[gluegen2] 02/10: Imported Upstream version 2.3.1

Tony Mancill tmancill at moszumanska.debian.org
Fri Oct 9 03:22:42 UTC 2015


This is an automated email from the git hooks/post-receive script.

tmancill pushed a commit to branch master
in repository gluegen2.

commit 1124bee67f5bb3e508db94089a590bc8dff3ace2
Author: tony mancill <tmancill at debian.org>
Date:   Tue Jul 14 21:58:30 2015 -0700

    Imported Upstream version 2.3.1
---
 .classpath                                         |    2 +
 .gitmodules                                        |    3 +
 LICENSE.txt                                        |   51 +-
 doc/HowToBuild.html                                |  269 +++
 doc/licenses/Apache.LICENSE-2.0                    |  202 ++
 jcpp/.gitignore                                    |    4 +
 jcpp/LICENSE                                       |  201 ++
 jcpp/README.md                                     |   31 +
 .../java/com/jogamp/gluegen/jcpp/Argument.java     |   75 +
 .../com/jogamp/gluegen/jcpp/ChrootFileSystem.java  |   84 +
 .../java/com/jogamp/gluegen/jcpp/CppReader.java    |  149 ++
 .../main/java/com/jogamp/gluegen/jcpp/CppTask.java |  215 ++
 .../gluegen/jcpp/DefaultPreprocessorListener.java  |   99 +
 .../main/java/com/jogamp/gluegen/jcpp/Feature.java |   42 +
 .../com/jogamp/gluegen/jcpp/FileLexerSource.java   |   89 +
 .../com/jogamp/gluegen/jcpp/FixedTokenSource.java  |   59 +
 .../com/jogamp/gluegen/jcpp/InputLexerSource.java  |   64 +
 .../com/jogamp/gluegen/jcpp/InternalException.java |   31 +
 .../main/java/com/jogamp/gluegen/jcpp/JCPP.java    |  189 ++
 .../com/jogamp/gluegen/jcpp/JavaFileSystem.java    |   84 +
 .../java/com/jogamp/gluegen/jcpp/JoinReader.java   |  218 ++
 .../com/jogamp/gluegen/jcpp/LexerException.java    |   33 +
 .../java/com/jogamp/gluegen/jcpp/LexerSource.java  |  987 ++++++++
 .../main/java/com/jogamp/gluegen/jcpp/Macro.java   |  212 ++
 .../com/jogamp/gluegen/jcpp/MacroTokenSource.java  |  209 ++
 .../java/com/jogamp/gluegen/jcpp/NumericValue.java |  215 ++
 .../java/com/jogamp/gluegen/jcpp/Preprocessor.java | 2177 +++++++++++++++++
 .../jogamp/gluegen/jcpp/PreprocessorCommand.java   |   44 +
 .../jogamp/gluegen/jcpp/PreprocessorListener.java  |   59 +
 .../jogamp/gluegen/jcpp/ResourceFileSystem.java    |   81 +
 .../main/java/com/jogamp/gluegen/jcpp/Source.java  |  298 +++
 .../com/jogamp/gluegen/jcpp/SourceIterator.java    |   88 +
 .../main/java/com/jogamp/gluegen/jcpp/State.java   |   68 +
 .../com/jogamp/gluegen/jcpp/StringLexerSource.java |   53 +
 .../main/java/com/jogamp/gluegen/jcpp/Token.java   |  193 ++
 .../jogamp/gluegen/jcpp/TokenSnifferSource.java    |   46 +
 .../java/com/jogamp/gluegen/jcpp/TokenType.java    |  130 +
 .../java/com/jogamp/gluegen/jcpp/VirtualFile.java  |   45 +
 .../com/jogamp/gluegen/jcpp/VirtualFileSystem.java |   31 +
 .../main/java/com/jogamp/gluegen/jcpp/Warning.java |   32 +
 .../com/jogamp/gluegen/jcpp/CppReaderTest.java     |   77 +
 .../java/com/jogamp/gluegen/jcpp/ErrorTest.java    |   72 +
 .../jogamp/gluegen/jcpp/IncludeAbsoluteTest.java   |   55 +
 .../jogamp/gluegen/jcpp/JavaFileSystemTest.java    |   46 +
 .../com/jogamp/gluegen/jcpp/JoinReaderTest.java    |   48 +
 .../com/jogamp/gluegen/jcpp/LexerSourceTest.java   |  147 ++
 .../com/jogamp/gluegen/jcpp/NumericValueTest.java  |  102 +
 .../com/jogamp/gluegen/jcpp/PreprocessorTest.java  |  376 +++
 .../gluegen/jcpp/TokenPastingWhitespaceTest.java   |   59 +
 jcpp/src/test/resources/absolute.h                 |    1 +
 jcpp/src/test/resources/once.c                     |    2 +
 jcpp/src/test/resources/once.h                     |    2 +
 jcpp/src/test/resources/test0.c                    |   61 +
 jcpp/src/test/resources/test0.h                    |    7 +
 jcpp/src/test/resources/test1.c                    |    2 +
 jcpp/src/test/resources/test1.h                    |    7 +
 jcpp/src/test/resources/trigraph.c                 |    1 +
 jcpp/src/test/resources/varargs.c                  |    8 +
 make/build-test.xml                                |   30 +-
 make/build.xml                                     |   27 +-
 make/elf-header.cfg                                |   56 +-
 make/gluegen-cpptasks-base.xml                     |   78 +-
 make/jogamp-androidtasks.xml                       |   65 +-
 make/jogamp-env.xml                                |   31 +-
 make/scripts/adb-install-all-aarch64.sh            |    2 +
 make/scripts/adb-install-all-armv6.sh              |    2 +-
 make/scripts/adb-install-all-armv7.sh              |    2 -
 ...l-all-armv7.sh => adb-reinstall-all-aarch64.sh} |    2 +-
 make/scripts/crosstest-junit-android-armv7-rel.sh  |   69 -
 make/scripts/java-win32.bat                        |   17 +-
 make/scripts/java-win64.bat                        |   19 +-
 .../make.gluegen.all.android-aarch64-cross.sh      |   62 +
 .../make.gluegen.all.android-armv6-cross.sh        |   59 +-
 .../make.gluegen.all.android-armv7-cross.sh        |  101 -
 ...x-java7.sh => make.gluegen.all.macosx-java6.sh} |   13 +-
 make/scripts/make.gluegen.all.macosx.sh            |    5 +-
 make/scripts/make.gluegen.all.win32.bat            |    4 +-
 make/scripts/make.gluegen.all.win64.bat            |    4 +-
 make/scripts/runtest-x32.bat                       |   11 +-
 make/scripts/runtest-x64.bat                       |   19 +-
 make/scripts/runtest.sh                            |   45 +-
 make/scripts/setenv-android-tools.sh               |   79 +
 make/scripts/setenv-build-jogl-x86_64.sh           |    7 -
 make/scripts/test-win32-smb_share.bat              |    6 +-
 make/stub_includes/gluegen/stdio.h                 |    7 +
 make/stub_includes/jni/jawt.h                      |  106 +
 make/stub_includes/jni/jni.h                       | 1934 +++++++++++++++
 make/stub_includes/jni/macosx/jawt_md.h            |    7 +-
 make/stub_includes/jni/macosx/jni_md.h             |   29 +-
 .../jni/{macosx/jni_md.h => win32/jawt_md.h}       |   43 +-
 make/stub_includes/jni/{macosx => win32}/jni_md.h  |   31 +-
 .../jni/{macosx/jni_md.h => x11/jawt_md.h}         |   45 +-
 make/stub_includes/jni/{macosx => x11}/jni_md.h    |   21 +-
 make/stub_includes/os/elf_header.h                 |    5 +-
 make/stub_includes/platform/glibc-compat-symbols.h |    8 +-
 make/stub_includes/platform/gluegen_stddef.h       |    2 +-
 make/stub_includes/platform/gluegen_stdint.h       |    2 +-
 src/antlr/com/jogamp/gluegen/cgram/GnuCParser.g    |    3 +-
 src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g  |  531 +++--
 src/antlr/com/jogamp/gluegen/cgram/StdCParser.g    |   15 +-
 src/antlr/com/jogamp/gluegen/jgram/JavaParser.g    | 1509 ++++++------
 src/java/com/jogamp/common/ExceptionUtils.java     |   78 +
 .../com/jogamp/common/jvm/JNILibLoaderBase.java    |   36 +-
 .../com/jogamp/common/net/AssetURLContext.java     |    2 +-
 src/java/com/jogamp/common/net/Uri.java            | 2516 ++++++++++++++++++++
 .../net/{URIQueryProps.java => UriQueryProps.java} |   31 +-
 src/java/com/jogamp/common/nio/Buffers.java        |   40 +-
 .../jogamp/common/nio/ByteBufferInputStream.java   |  186 ++
 .../common/nio/MappedByteBufferInputStream.java    |  958 ++++++++
 .../common/nio/MappedByteBufferOutputStream.java   |  351 +++
 src/java/com/jogamp/common/nio/StructAccessor.java |   23 +
 src/java/com/jogamp/common/os/AndroidVersion.java  |   82 +-
 .../com/jogamp/common/os/DynamicLibraryBundle.java |   61 +-
 src/java/com/jogamp/common/os/DynamicLinker.java   |   17 +-
 .../com/jogamp/common/os/DynamicLookupHelper.java  |   15 +-
 ...achineDescription.java => MachineDataInfo.java} |  208 +-
 src/java/com/jogamp/common/os/NativeLibrary.java   |  122 +-
 src/java/com/jogamp/common/os/Platform.java        |  312 ++-
 src/java/com/jogamp/common/util/Bitstream.java     |  555 +++--
 src/java/com/jogamp/common/util/IOUtil.java        |  482 ++--
 src/java/com/jogamp/common/util/JarUtil.java       |  301 +--
 .../com/jogamp/common/util/ReflectionUtil.java     |    3 +-
 src/java/com/jogamp/common/util/VersionUtil.java   |   12 +-
 .../common/util/bin/exe-windows-i586-268b.bin      |  Bin 0 -> 268 bytes
 .../jogamp/common/util/cache/TempFileCache.java    |    5 +-
 .../com/jogamp/common/util/cache/TempJarCache.java |  160 +-
 src/java/com/jogamp/gluegen/ASTLocusTag.java       |   99 +
 .../com/jogamp/gluegen/CMethodBindingEmitter.java  |  261 +-
 .../com/jogamp/gluegen/ConstantDefinition.java     |  295 ++-
 src/java/com/jogamp/gluegen/DebugEmitter.java      |   25 +-
 src/java/com/jogamp/gluegen/FunctionEmitter.java   |   40 +-
 ...unctionAddressResolver.java => GenericCPP.java} |   40 +-
 src/java/com/jogamp/gluegen/GlueEmitter.java       |    7 +-
 src/java/com/jogamp/gluegen/GlueGen.java           |  205 +-
 src/java/com/jogamp/gluegen/GlueGenException.java  |   92 +
 src/java/com/jogamp/gluegen/JavaConfiguration.java |  647 +++--
 src/java/com/jogamp/gluegen/JavaEmitter.java       |  962 +++++---
 .../jogamp/gluegen/JavaMethodBindingEmitter.java   |  128 +-
 src/java/com/jogamp/gluegen/JavaType.java          |   79 +-
 src/java/com/jogamp/gluegen/Logging.java           |  349 ++-
 src/java/com/jogamp/gluegen/MethodBinding.java     |   98 +-
 src/java/com/jogamp/gluegen/ReferencedStructs.java |   56 +-
 ...unctionAddressResolver.java => TypeConfig.java} |   31 +-
 src/java/com/jogamp/gluegen/TypeInfo.java          |    2 +-
 src/java/com/jogamp/gluegen/ant/GlueGenTask.java   |   23 +-
 src/java/com/jogamp/gluegen/cgram/Define.java      |   16 +-
 src/java/com/jogamp/gluegen/cgram/TNode.java       |   24 +-
 .../jogamp/gluegen/cgram/types/AliasedSymbol.java  |  185 ++
 .../com/jogamp/gluegen/cgram/types/ArrayType.java  |   86 +-
 .../com/jogamp/gluegen/cgram/types/BitType.java    |   65 +-
 .../jogamp/gluegen/cgram/types/CompoundType.java   |  161 +-
 .../com/jogamp/gluegen/cgram/types/DoubleType.java |   39 +-
 .../com/jogamp/gluegen/cgram/types/EnumType.java   |  130 +-
 src/java/com/jogamp/gluegen/cgram/types/Field.java |   39 +-
 .../com/jogamp/gluegen/cgram/types/FloatType.java  |   39 +-
 .../jogamp/gluegen/cgram/types/FunctionSymbol.java |   82 +-
 .../jogamp/gluegen/cgram/types/FunctionType.java   |   89 +-
 .../com/jogamp/gluegen/cgram/types/IntType.java    |  111 +-
 .../gluegen/cgram/types/MemoryLayoutType.java      |   14 +-
 .../jogamp/gluegen/cgram/types/PointerType.java    |  130 +-
 .../jogamp/gluegen/cgram/types/PrimitiveType.java  |   10 +-
 .../com/jogamp/gluegen/cgram/types/SizeThunk.java  |  232 +-
 .../jogamp/gluegen/cgram/types/StructLayout.java   |    6 +-
 .../com/jogamp/gluegen/cgram/types/StructType.java |   25 +-
 src/java/com/jogamp/gluegen/cgram/types/Type.java  |  510 ++--
 .../jogamp/gluegen/cgram/types/TypeComparator.java |  143 ++
 .../jogamp/gluegen/cgram/types/TypeDictionary.java |   35 +
 .../jogamp/gluegen/cgram/types/TypeVisitor.java    |    6 +
 .../com/jogamp/gluegen/cgram/types/UnionType.java  |   25 +-
 .../com/jogamp/gluegen/cgram/types/VoidType.java   |   38 +-
 src/java/com/jogamp/gluegen/package.html           |   18 +-
 src/java/com/jogamp/gluegen/pcpp/PCPP.java         |  158 +-
 .../ProcAddressCMethodBindingEmitter.java          |   90 +-
 .../procaddress/ProcAddressConfiguration.java      |   51 +-
 .../gluegen/procaddress/ProcAddressEmitter.java    |  121 +-
 .../ProcAddressJavaMethodBindingEmitter.java       |   13 +-
 .../gluegen/runtime/FunctionAddressResolver.java   |   10 +-
 .../jogamp/gluegen/runtime/ProcAddressTable.java   |   23 +-
 .../structgen/CStructAnnotationProcessor.java      |    9 +-
 .../jogamp/android/launcher/ClassLoaderUtil.java   |   48 +
 ...Impl.java => BionicDynamicLinker32bitImpl.java} |   26 +-
 ...Impl.java => BionicDynamicLinker64BitImpl.java} |   30 +-
 src/java/jogamp/common/os/DynamicLinkerImpl.java   |  182 +-
 .../jogamp/common/os/MacOSXDynamicLinkerImpl.java  |   12 +-
 ...ionRuntime.java => MachineDataInfoRuntime.java} |  151 +-
 src/java/jogamp/common/os/PlatformPropsImpl.java   |  476 ++--
 .../jogamp/common/os/PosixDynamicLinkerImpl.java   |   12 +-
 .../jogamp/common/os/UnixDynamicLinkerImpl.java    |   41 +-
 .../jogamp/common/os/WindowsDynamicLinkerImpl.java |   47 +-
 src/java/jogamp/common/os/elf/Ehdr.java            |  175 --
 src/java/jogamp/common/os/elf/Ehdr_p1.java         |  118 +
 src/java/jogamp/common/os/elf/Ehdr_p2.java         |  176 ++
 .../os/elf/{ElfHeader.java => ElfHeaderPart1.java} |  414 ++--
 src/java/jogamp/common/os/elf/ElfHeaderPart2.java  |  375 +++
 src/java/jogamp/common/os/elf/IOUtils.java         |   10 +-
 .../jogamp/common/os/elf/SectionArmAttributes.java |   45 +-
 src/java/jogamp/common/os/elf/SectionHeader.java   |   40 +-
 src/java/jogamp/common/os/elf/Shdr.java            |  145 +-
 .../jogamp/common/net/AssetURLConnectionBase.java  |   10 +-
 .../net/AssetURLConnectionRegisteredTest.java      |    9 +-
 .../net/AssetURLConnectionUnregisteredTest.java    |    7 +-
 src/junit/com/jogamp/common/net/TestUri01.java     |  433 ++++
 .../TestUri02Composing.java}                       |   58 +-
 .../com/jogamp/common/net/TestUri03Resolving.java  |  430 ++++
 ...> TestUri99LaunchOnReservedCharPathBug908.java} |   32 +-
 ...stURIQueryProps.java => TestUriQueryProps.java} |   23 +-
 .../common/net/TestUrisWithAssetHandler.java       |    4 +-
 src/junit/com/jogamp/common/net/URIDumpUtil.java   |   53 +
 src/junit/com/jogamp/common/nio/BuffersTest.java   |    4 +-
 .../jogamp/common/nio/CachedBufferFactoryTest.java |    4 +-
 .../nio/TestBuffersFloatDoubleConversion.java      |    4 +-
 .../common/nio/TestByteBufferCopyStream.java       |  244 ++
 .../common/nio/TestByteBufferInputStream.java      |  363 +++
 .../common/nio/TestByteBufferOutputStream.java     |  298 +++
 .../jogamp/common/nio/TestPointerBufferEndian.java |    6 +-
 .../common/nio/TestStructAccessorEndian.java       |    8 +-
 .../com/jogamp/common/os/TestElfReader01.java      |   76 +-
 .../com/jogamp/common/util/IntIntHashMapTest.java  |    6 +-
 .../jogamp/common/util/IntObjectHashMapTest.java   |    6 +-
 .../com/jogamp/common/util/LongIntHashMapTest.java |    4 +-
 .../com/jogamp/common/util/TestArrayHashSet01.java |    4 +-
 .../com/jogamp/common/util/TestBitstream00.java    |  136 +-
 .../com/jogamp/common/util/TestBitstream01.java    |  168 +-
 .../com/jogamp/common/util/TestBitstream02.java    |   18 +-
 .../com/jogamp/common/util/TestBitstream03.java    |   25 +-
 .../com/jogamp/common/util/TestBitstream04.java    |   24 +-
 .../com/jogamp/common/util/TestFloatStack01.java   |    4 +-
 src/junit/com/jogamp/common/util/TestIOUtil01.java |   45 +-
 .../jogamp/common/util/TestIOUtilURIHandling.java  |  393 ---
 .../jogamp/common/util/TestIteratorIndexCORE.java  |    4 +-
 src/junit/com/jogamp/common/util/TestJarUtil.java  |   44 +-
 .../com/jogamp/common/util/TestPlatform01.java     |   10 +-
 .../com/jogamp/common/util/TestRunnableTask01.java |    4 +-
 .../jogamp/common/util/TestSystemPropsAndEnvs.java |    4 +-
 .../com/jogamp/common/util/TestTempJarCache.java   |   35 +-
 .../com/jogamp/common/util/TestVersionInfo.java    |    4 +-
 .../com/jogamp/common/util/TestVersionNumber.java  |    4 +-
 .../jogamp/common/util/TestVersionSemantics.java   |   45 +-
 .../common/util/locks/TestRecursiveLock01.java     |    4 +-
 .../util/locks/TestRecursiveThreadGroupLock01.java |    4 +-
 .../util/locks/TestSingletonServerSocket00.java    |   22 +-
 .../util/locks/TestSingletonServerSocket01.java    |   11 +-
 .../util/locks/TestSingletonServerSocket02.java    |   29 +-
 .../gluegen/test/junit/generation/BaseClass.java   |  202 +-
 .../gluegen/test/junit/generation/PCPPTest.java    |    4 +-
 .../test/junit/generation/test1-CustomJavaCode.cfg |    7 +
 .../gluegen/test/junit/generation/test1-common.cfg |   17 +
 .../jogamp/gluegen/test/junit/generation/test1.c   |   57 +
 .../jogamp/gluegen/test/junit/generation/test1.h   |  120 +-
 .../test/junit/generation/test1p1-gluegen.cfg      |    2 +
 .../test/junit/generation/test1p2-gluegen.cfg      |    2 +
 .../gluegen/test/junit/internals/TestType.java     |   85 +
 .../test/junit/structgen/TestStructGen01.java      |    4 +-
 .../test/junit/structgen/TestStructGen02.java      |    4 +-
 src/junit/com/jogamp/junit/sec/Applet01.java       |  108 +-
 .../com/jogamp/junit/sec/TestSecIOUtil01.java      |  106 +-
 src/junit/com/jogamp/junit/util/JunitTracer.java   |   28 +-
 .../com/jogamp/junit/util/SingletonJunitCase.java  |   79 +
 .../jogamp/junit/util/VersionSemanticsUtil.java    |    9 +-
 src/native/common/JVMUtil.c                        |    5 +
 ...scriptionRuntime.c => MachineDataInfoRuntime.c} |   36 +-
 src/native/tinype-corkami/consts.inc               |  675 ++++++
 src/native/tinype-corkami/make.bat                 |   13 +
 src/native/tinype-corkami/readme.txt               |   25 +
 src/native/tinype-corkami/tiny-simple.asm          |  102 +
 src/native/tinype-corkami/tiny.asm                 |  117 +
 src/native/unix/UnixDynamicLinkerImpl_JNI.c        |   78 +-
 src/native/windows/WindowsDynamicLinkerImpl_JNI.c  |    8 +-
 268 files changed, 27424 insertions(+), 6191 deletions(-)

diff --git a/.classpath b/.classpath
index bf36344..92580a8 100644
--- a/.classpath
+++ b/.classpath
@@ -21,6 +21,8 @@
 		</attributes>
 	</classpathentry>
 	<classpathentry kind="src" path="test/junit"/>
+	<classpathentry kind="src" path="jcpp/src/main/java"/>
+	<classpathentry kind="src" path="jcpp/src/test/java"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/Ant"/>
 	<classpathentry kind="lib" path="make/lib/antlr.jar"/>
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..c3f990a
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "jcpp"]
+	path = jcpp
+	url = ../jcpp
diff --git a/LICENSE.txt b/LICENSE.txt
index 8be18df..1b21c36 100755
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,7 +1,13 @@
-
 The GlueGen source code is mostly licensed under the New BSD 2-clause license,
 however it contains other licensed material as well.
 
+Other licensed material is compatible with the 'New BSD 2-Clause License',
+if not stated otherwise.
+
+'New BSD 2-Clause License' incompatible materials are optional, they are:
+
+    NONE
+
 Below you find a detailed list of licenses used in this project.
 
 +++
@@ -131,3 +137,46 @@ L.3) The GlueGen source tree contains CGRAM http://www.antlr.org/grammar/cgram/,
     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     POSSIBILITY OF SUCH DAMAGE.
 
+A.1) The GlueGen source tree contains code from The Apache Software Foundation
+     which is covered by the Apache License Version 2.0
+
+   Apache Harmony - Open Source Java SE
+   =====================================
+
+   <http://harmony.apache.org/>
+
+   Author: The Apache Software Foundation (http://www.apache.org/).
+
+   Copyright 2006, 2010 The Apache Software Foundation.
+
+   Apache License Version 2.0, January 2004
+   http://www.apache.org/licenses/LICENSE-2.0
+   Or within this repository: doc/licenses/Apache.LICENSE-2.0
+
+   Files:
+    - src/java/com/jogamp/common/net/Uri.java 
+      (derived from java.net.URI.Helper and heavily modified)
+
+A.2) The GlueGen source tree contains code from Ben Mankin, a.k.a 'Shevek',
+     which is covered by the Apache License Version 2.0
+
+   JCPP - A Java C Preprocessor
+   =============================
+
+   <http://www.anarres.org/projects/jcpp/>
+   <https://github.com/shevek/jcpp>
+
+   Author: Ben Mankin, a.k.a 'Shevek' (http://www.anarres.org/about/).
+
+   Copyright (c) 2007-2008, Shevek
+
+   Apache License Version 2.0, January 2004
+   http://www.apache.org/licenses/LICENSE-2.0
+   Or within this repository: doc/licenses/Apache.LICENSE-2.0
+
+   Files:
+    The complete git submodule 'jcpp',
+    which is a patched version of the original mentioned above.
+
+   Used for the compile-time module gluegen.jar only.
+
diff --git a/doc/HowToBuild.html b/doc/HowToBuild.html
new file mode 100644
index 0000000..dcfe3ba
--- /dev/null
+++ b/doc/HowToBuild.html
@@ -0,0 +1,269 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+        <link href="../../style.css" rel="stylesheet" type="text/css"/>
+        <title>How to build JOGL</title>
+    </head>
+    <body>
+        <div id="container">
+            <div id="header">
+                <div id="slogan">How to build GlueGen</div>
+                <div id="logo"><a href="http://jogamp.org/">How to build GlueGen</a></div>
+            </div>
+            <div id="menu">
+                <ul>
+                    <li><a href="http://jogamp.org/">Home</a></li>
+                    <li><a href="../../gluegen/www/">Gluegen</a></li>
+                    <li><a href="../../joal/www/">JOAL</a></li>
+                    <li><a href="../../jocl/www/">JOCL</a></li>
+                    <li><a href="../../jogl/www/">JOGL</a></li>
+                    <li><a href="../../demos/www/">Demos</a></li>
+                    <li><a href="../../wiki/">Wiki</a></li>
+                    <li><a href="../../deployment/jogl-next/javadoc_public/">JavaDoc</a></li>
+                    <li><a href="../../blog/">Blogs</a></li>
+                    <li><a href="../../forum.html">Forums</a></li>
+                </ul>
+            </div>
+            <div id="main">
+                <div id="text" class="fill">
+
+                    <h2>Platform and Component Requirements</h2>
+                    <hr/>
+                    Here is a list of platforms and components, we were able to build GlueGen on,<br/>
+                    if not stated otherwise.<br/>
+
+                    <ul>
+                        <li> <b>Java</b><br/>
+                            A Java 1.6 compliant SDK.
+                        </li>
+                        <li> <b><a href="http://ant.apache.org/">Ant</a></b> 1.9.0 or later</li>
+                        <li> <b><a href="http://www.kernel.org/pub/software/scm/git/docs/">Git</a></b> 1.6.0 or later<br/>
+                            <ul>
+                                <li> Use your Unix distribution's version, if available, or</li>
+                                <li> <a href="http://www.kernel.org/pub/software/scm/git/">Source Code for GNU/Linux, MacOSX, ..</a>, or</li>
+                                <li> Git on Windows
+                                    <ul>
+                                        <li> <a href="https://cygwin.com">cygwin</a></li>
+                                        <li> <a href="http://code.google.com/p/msysgit/">msysgit</a></li>
+                                    </ul>
+                                </li>
+                                <li> <a href="http://code.google.com/p/git-osx-installer/">git-osx-installer</a> </li>
+                            </ul>
+                        </li>
+
+                        <li> <b>GNU Linux</b> x86, 32- and 64-bit<br/>
+                            You may have to install a few developer packages ...
+                            <ul>
+                                <li> <b>Debian</b> 5.00 or later
+                                    <ul>
+                                        <li>openjdk-7-jre</li>
+                                        <li>openjdk-7-jdk</li>
+                                        <li>ant</li>
+                                        <li>git</li>
+                                        <li>p7zip-full</li>
+                                        <li>gcc</li>
+                                    </ul>
+                                    One liner install command:
+                                    <pre>
+apt-get install openjdk-7-jre openjdk-7-jdk ant git-all p7zip-full gcc
+                                    </pre>
+                                    Optional: Add <i>kernel</i> build utilities:
+                                    <pre>
+apt-get install kernel-package build-essential 
+                                    </pre>
+                                    Optional: Add <i>multiarch</i> i386 next to amd64 
+                                    <ul>
+                                      <li><b>Debian</b> 7.00
+                                        <pre>
+dpkg --add-architecture i386
+apt-get update
+apt-get install ia32-libs ia32-libs-gtk gcc-multilib lib32gcc1 lib32gomp1 lib32itm1 lib32quadmath0 libc6-i386 ibc6-dev-i386 g++-multilib lib32stdc++6 openjdk-7-jre:i386 openjdk-7-jdk:i386
+                                        </pre></li>
+
+                                      <li><b>Debian</b> 8.00
+                                        <pre>
+dpkg --add-architecture i386
+apt-get update
+apt-get install lib32z1 lib32ncurses5 lib32bz2-1.0 gcc-multilib lib32gcc1 lib32gomp1 lib32itm1 lib32quadmath0 libc6-i386 libc6-dev-i386 g++-multilib lib32stdc++6 openjdk-7-jre:i386 openjdk-7-jdk:i386
+                                        </pre></li>
+                                    </ul>
+                                </li>
+                                <li> <b>OpenSuSE</b> 10.2 or later
+                                    <ul>
+                                        <li>openjdk-7-jre</li>
+                                        <li>openjdk-7-jdk</li>
+                                        <li>ant</li>
+                                        <li>git</li>
+                                        <li>p7zip-full</li>
+                                        <li>gcc</li>
+                                    </ul>
+                                </li>
+                                <li> <b>CentOS / Red Hat Enterprise Linux</b> 5.4 or later<br/>
+                                    <ul>
+                                        <li>openjdk-7-jre</li>
+                                        <li>openjdk-7-jdk</li>
+                                        <li>ant</li>
+                                        <li>git</li>
+                                        <li>p7zip-full</li>
+                                        <li>gcc</li>
+                                    </ul>
+                                </li>
+                            </ul>
+                        </li>
+                        <li> <b>OpenSolaris</b> SPARC and x86, 32- and 64-bit
+                            <ul>
+                                <li> <a href="http://opensolaris.org/">OpenSolaris 2009.06 or later</a></li>
+                            </ul>
+                        </li>
+                        <li> <b>MacOSX</b> Intel
+                            <ul>
+                                <li> git, see above </li>
+                                <li> <a href="http://www.apple.com/macosx/">Mac OS X</a> 10.3 (note: will not work with earlier releases) </li>
+                                <li> <a href="http://developer.apple.com/technologies/xcode.html">Xcode</a> for gcc, etc (included in OSX)</li>
+                            </ul>
+                        </li>
+                        <li> <b>Windows</b>/x86 (32 bit)
+                            <ul>
+                                <li>Windows XP or later </li>
+                                <li>git, see above</li>
+                                <li> <a href="http://mingw-w64.sourceforge.net/">MinGW64</a>
+                                  <ul>
+                                    <li> <a href="http://sourceforge.net/projects/mingwbuilds/files/mingw-builds-install/mingw-builds-install.exe/download">Installer</a>
+                                      <ul>
+                                        <li>mingw-build-install</li>
+                                        <li>version: 4.8.1</li>
+                                        <li>host: x32</li>
+                                        <li>threading: win32</li>
+                                        <li>exceptions: SJLJ</li>
+                                        <li>revision: 5</li>
+                                      </ul></li>
+                                    <li> or <a href="http://sourceforge.net/projects/mingwbuilds/files/host-windows/releases/">manual</a> 
+                                         via  <a href="http://sourceforge.net/projects/mingwbuilds/files/host-windows/releases/4.8.1/32-bit/threads-win32/sjlj/">7z archive file</a></li>
+                                  </ul></li>
+                            </ul>
+                        </li>
+                        <li> <b>Windows</b>/x86_64 (64-bit)
+                            <ul>
+                                <li>Windows XP or later </li>
+                                <li>git, see above</li>
+                                <li> <a href="http://mingw-w64.sourceforge.net/">MinGW64</a>
+                                  <ul>
+                                    <li> <a href="http://sourceforge.net/projects/mingwbuilds/files/mingw-builds-install/mingw-builds-install.exe/download">Installer</a>
+                                      <ul>
+                                        <li>mingw-build-install</li>
+                                        <li>version: 4.8.1</li>
+                                        <li>host: x64</li>
+                                        <li>threading: win32</li>
+                                        <li>exceptions: SJLJ</li>
+                                        <li>revision: 5</li>
+                                      </ul></li>
+                                    <li> or <a href="http://sourceforge.net/projects/mingwbuilds/files/host-windows/releases/">manual</a> 
+                                         via  <a href="http://sourceforge.net/projects/mingwbuilds/files/host-windows/releases/4.8.1/64-bit/threads-win32/sjlj/">7z archive file</a></li>
+                                  </ul></li>
+                            </ul>
+                        </li>
+                    </ul>
+
+                    <p>
+                        Additional platforms such as FreeBSD and HP/UX are handled by the
+                        build system, but are not officially supported.
+                    </p>
+
+                    <h2>Build Steps</h2>
+                    <hr/>
+                    <p>
+                        Here are the steps that are required in order to build JOGL.
+                    </p>
+
+                    <ol>
+                        <li><b>Optain the source code</b> using git:
+                            <ul>
+                                <li><a href="http://jogamp.org/git/?p=gluegen.git">Gluegen Dev GIT Repo</a></li>
+                            </ul><br/>
+                            It is crucial that you checkout the source code under a common root directory:
+                            <pre>
+    /home/dude/projects/jogamp> git clone --recurse-submodules git://jogamp.org/srv/scm/gluegen.git gluegen
+                            </pre>
+                            Now you should have following directory structure:
+                            <pre>
+    /home/dude/projects/jogamp
+    /home/dude/projects/jogamp/gluegen
+                            </pre>
+                            <p>
+                            Note-1: The GlueGen source must be fetched using <i>-recurse-submodules</i>,
+                                    which imports <i>JCPP</i>, now used as the default C preprocessor. 
+                            </p>
+                        </li>
+
+                        <li> <b>Unset your CLASSPATH environment variable:</b> <br/>
+                            The Ant build requires that the JOGL jars not be visible on the classpath. On Unix, type
+                            <code> unsetenv CLASSPATH </code> into a csh or tcsh shell, or <code> unset CLASSPATH </code>
+                            into a Bourne shell. On Windows, type <code> set CLASSPATH= </code> into a command prompt.
+                        </li>
+
+                        <li> <b>Optional</b>  <i>Copy and edit <b>gluegen.properties</b>:</i> <br/>
+                            To specify different basic options for components and compilers,<br/>
+                            copy <b>gluegen/make/gluegen.properties</b> into your home directory (pointed to by the Java system property <b>user.home</b>). <br/></li>
+
+                        <li> <b>Build the source tree:</b> <br/>
+                            Open a command shell in the "gluegen/make" directory of the source tree and type <code>"ant"</code>.
+                        </li>
+
+                        <li> <b>Test your build:</b> <br/> Stay in your command shell in the "gluegen/make" directory of the source tree and type <code>"ant junit.run"</code>.</li>
+
+                        <li> <b>Build Javadoc:</b> <br/> Stay in your command shell in the "gluegen/make" directory of the source tree and type "<code>ant javadoc"</code>.
+                            This will produce the end-user documentation for JOGL along with some auxiliary utility packages.
+                        </li>
+                    </ol>
+
+                    Note that there might be a few warnings produced by ANTLR about the
+                    C grammar and our modifications to some of the signatures of the
+                    productions; the C grammar warnings have been documented by the
+                    author of the grammar as having been investigated completely and
+                    harmless, and the warnings about our modifications are also
+                    harmless.
+
+                    <h2> Common build problems </h2>
+
+                    <ol>
+
+                        <li>
+                            <b>Your CLASSPATH environment variable appears to be set (some GlueGen classes are currently visible to the build.)</b>, and $CLASSPATH isn't set.
+                            An older version of GlueGen was installed into the extension directory of the JDK you're using to build the
+                            current GlueGen. On Windows and Linux, delete any ANTLR jars from jre/lib/ext, and on Mac OS X, delete them from
+                            /Library/Java/Extensions. It is generally not a good idea to drop GlueGen directly into the extensions directory,
+                            as this can interfere with upgrades via Java Web Start.
+                        </li>
+
+                        <li>
+                            <b>CharScanner; panic: ClassNotFoundException: com.sun.gluegen.cgram.CToken</b>
+
+                            This occurs because ANTLR was dropped into the Extensions
+                            directory of the JRE/JDK. On Windows and Linux, delete any ANTLR jars from jre/lib/ext,
+                            and on Mac OS X, delete them from /Library/Java/Extensions. Use the antlr.jar property in the build.xml
+                            to point to a JRE-external location of this jar file.
+                        </li>
+
+                    </ol>
+
+                    <br/>
+                    <p>
+                        <i>- Christopher Kline and Kenneth Russell, June 2003 (revised November 2006)</i><br/>
+                        <i>- Sven Gothel and Michael Bien, May 2010</i><br/>
+                        <i>- Sven Gothel, March 2010 (Extracted version from JOGL)</i><br/>
+                    </p>
+
+                </div>
+            </div>
+            <div id="footer">
+                <div id="footer_left">
+                    <span>JogAmp.org</span>
+                    by <a href="http://jogamp.org">http://jogamp.org</a>
+                    is licensed under a <br/>
+                    <a href="http://creativecommons.org/licenses/by/3.0/us/">Creative Commons Attribution 3.0 License</a>.
+                </div>
+            </div>
+        </div>
+    </body>
+</html>
diff --git a/doc/licenses/Apache.LICENSE-2.0 b/doc/licenses/Apache.LICENSE-2.0
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/doc/licenses/Apache.LICENSE-2.0
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/jcpp/.gitignore b/jcpp/.gitignore
new file mode 100644
index 0000000..9d7ac43
--- /dev/null
+++ b/jcpp/.gitignore
@@ -0,0 +1,4 @@
+build
+.*.swp
+.gradle
+.nb-gradle
diff --git a/jcpp/LICENSE b/jcpp/LICENSE
new file mode 100644
index 0000000..11069ed
--- /dev/null
+++ b/jcpp/LICENSE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/jcpp/README.md b/jcpp/README.md
new file mode 100644
index 0000000..fe891e4
--- /dev/null
+++ b/jcpp/README.md
@@ -0,0 +1,31 @@
+# Introduction
+
+The C Preprocessor is an interesting standard. It appears to be
+derived from the de-facto behaviour of the first preprocessors, and
+has evolved over the years. Implementation is therefore difficult.
+
+JCPP is a complete, compliant, standalone, pure Java implementation
+of the C preprocessor. It is intended to be of use to people writing
+C-style compilers in Java using tools like sablecc, antlr, JLex,
+CUP and so forth (although if you aren't using sablecc, you need your
+head examined).
+
+This project has has been used to successfully preprocess much of
+the source code of the GNU C library. As of version 1.2.5, it can
+also preprocess the Apple Objective C library.
+
+# JogAmp Branch
+
+This branch is modified for JogAmp 
+to supply [GlueGen](http://jogamp.org/gluegen/www/) with JCPP.
+
+This branch is only intended as a submodule for GlueGen
+and hence must be [build from within GlueGen](http://jogamp.org/gluegen/doc/HowToBuild.html).
+
+# Original JCPP Version
+* [Homepage](http://www.anarres.org/projects/jcpp/)
+* [GitHub](https://github.com/shevek/jcpp.git)
+
+# Documentation
+
+* [JavaDoc API](http://jogamp.org/deployment/jogamp-next/javadoc/gluegen/javadoc/)
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Argument.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Argument.java
new file mode 100644
index 0000000..bccddcb
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Argument.java
@@ -0,0 +1,75 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.annotation.Nonnull;
+
+/**
+ * A macro argument.
+ *
+ * This encapsulates a raw and preprocessed token stream.
+ */
+/* pp */ class Argument extends ArrayList<Token> {
+
+    private List<Token> expansion;
+
+    public Argument() {
+        this.expansion = null;
+    }
+
+    public void addToken(@Nonnull Token tok) {
+        add(tok);
+    }
+
+    /* pp */ void expand(@Nonnull Preprocessor p)
+            throws IOException,
+            LexerException {
+        /* Cache expansion. */
+        if (expansion == null) {
+            this.expansion = p.expand(this);
+            // System.out.println("Expanded arg " + this);
+        }
+    }
+
+    @Nonnull
+    public Iterator<Token> expansion() {
+        return expansion.iterator();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder();
+        buf.append("Argument(");
+        // buf.append(super.toString());
+        buf.append("raw=[ ");
+        for (int i = 0; i < size(); i++)
+            buf.append(get(i).getText());
+        buf.append(" ];expansion=[ ");
+        if (expansion == null)
+            buf.append("null");
+        else
+            for (Token token : expansion)
+                buf.append(token.getText());
+        buf.append(" ])");
+        return buf.toString();
+    }
+
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/ChrootFileSystem.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/ChrootFileSystem.java
new file mode 100644
index 0000000..f3806fa
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/ChrootFileSystem.java
@@ -0,0 +1,84 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * A virtual filesystem implementation using java.io in a virtual
+ * chroot.
+ */
+public class ChrootFileSystem implements VirtualFileSystem {
+
+    private File root;
+
+    public ChrootFileSystem(File root) {
+        this.root = root;
+    }
+
+    @Override
+    public VirtualFile getFile(String path) {
+        return new ChrootFile(path);
+    }
+
+    @Override
+    public VirtualFile getFile(String dir, String name) {
+        return new ChrootFile(dir, name);
+    }
+
+    private class ChrootFile extends File implements VirtualFile {
+
+        private File rfile;
+
+        public ChrootFile(String path) {
+            super(path);
+        }
+
+        public ChrootFile(String dir, String name) {
+            super(dir, name);
+        }
+
+        /* private */
+        public ChrootFile(File dir, String name) {
+            super(dir, name);
+        }
+
+        @Override
+        public ChrootFile getParentFile() {
+            return new ChrootFile(getParent());
+        }
+
+        @Override
+        public ChrootFile getChildFile(String name) {
+            return new ChrootFile(this, name);
+        }
+
+        @Override
+        public boolean isFile() {
+            File real = new File(root, getPath());
+            return real.isFile();
+        }
+
+        @Override
+        public Source getSource() throws IOException {
+            return new FileLexerSource(new File(root, getPath()),
+                    getPath());
+        }
+    }
+
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/CppReader.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/CppReader.java
new file mode 100644
index 0000000..82ef2fe
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/CppReader.java
@@ -0,0 +1,149 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.Reader;
+
+import javax.annotation.Nonnull;
+
+import static com.jogamp.gluegen.jcpp.Token.CCOMMENT;
+import static com.jogamp.gluegen.jcpp.Token.CPPCOMMENT;
+import static com.jogamp.gluegen.jcpp.Token.EOF;
+
+/**
+ * A Reader wrapper around the Preprocessor.
+ *
+ * This is a utility class to provide a transparent {@link Reader}
+ * which preprocesses the input text.
+ *
+ * @see Preprocessor
+ * @see Reader
+ */
+public class CppReader extends Reader implements Closeable {
+
+    private final Preprocessor cpp;
+    private String token;
+    private int idx;
+
+    public CppReader(@Nonnull final Reader r) {
+        cpp = new Preprocessor(new LexerSource(r, true) {
+            @Override
+            public String getName() {
+                return "<CppReader Input@"
+                        + System.identityHashCode(r) + ">";
+            }
+        });
+        token = "";
+        idx = 0;
+    }
+
+    public CppReader(@Nonnull Preprocessor p) {
+        cpp = p;
+        token = "";
+        idx = 0;
+    }
+
+    /**
+     * Returns the Preprocessor used by this CppReader.
+     */
+    @Nonnull
+    public Preprocessor getPreprocessor() {
+        return cpp;
+    }
+
+    /**
+     * Defines the given name as a macro.
+     *
+     * This is a convnience method.
+     */
+    public void addMacro(@Nonnull String name)
+            throws LexerException {
+        cpp.addMacro(name);
+    }
+
+    /**
+     * Defines the given name as a macro.
+     *
+     * This is a convnience method.
+     */
+    public void addMacro(@Nonnull String name, @Nonnull String value)
+            throws LexerException {
+        cpp.addMacro(name, value);
+    }
+
+    private boolean refill()
+            throws IOException {
+        try {
+            assert cpp != null : "cpp is null : was it closed?";
+            if (token == null)
+                return false;
+            while (idx >= token.length()) {
+                Token tok = cpp.token();
+                switch (tok.getType()) {
+                    case EOF:
+                        token = null;
+                        return false;
+                    case CCOMMENT:
+                    case CPPCOMMENT:
+                        if (!cpp.getFeature(Feature.KEEPCOMMENTS)) {
+                            token = " ";
+                            break;
+                        }
+                    default:
+                        token = tok.getText();
+                        break;
+                }
+                idx = 0;
+            }
+            return true;
+        } catch (LexerException e) {
+            throw new IOException(String.valueOf(e), e);
+        }
+    }
+
+    @Override
+    public int read()
+            throws IOException {
+        if (!refill())
+            return -1;
+        return token.charAt(idx++);
+    }
+
+    /* XXX Very slow and inefficient. */
+    public int read(char cbuf[], int off, int len)
+            throws IOException {
+        if (token == null)
+            return -1;
+        for (int i = 0; i < len; i++) {
+            int ch = read();
+            if (ch == -1)
+                return i;
+            cbuf[off + i] = (char) ch;
+        }
+        return len;
+    }
+
+    @Override
+    public void close()
+            throws IOException {
+        cpp.close();
+        token = null;
+    }
+
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/CppTask.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/CppTask.java
new file mode 100644
index 0000000..e3be324
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/CppTask.java
@@ -0,0 +1,215 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.List;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Copy;
+import org.apache.tools.ant.types.FilterSet;
+import org.apache.tools.ant.types.FilterSetCollection;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * An ant task for jcpp.
+ */
+public class CppTask extends Copy {
+
+    private class Listener extends DefaultPreprocessorListener {
+
+        @Override
+        protected void print(String msg) {
+            log(msg);
+        }
+    }
+
+    public static class Macro {
+
+        private String name;
+        private String value;
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setValue(String value) {
+            this.value = value;
+        }
+
+        public String getValue() {
+            return value;
+        }
+    }
+
+    private final Listener listener = new Listener();
+    private final List<Macro> macros = new ArrayList<Macro>();
+    private Path systemincludepath;
+    private Path localincludepath;
+
+    public void addMacro(Macro macro) {
+        macros.add(macro);
+    }
+
+    public void addSystemincludepath(Path path) {
+        if (systemincludepath == null)
+            systemincludepath = new Path(getProject());
+        systemincludepath.add(path);
+    }
+
+    public void addLocalincludepath(Path path) {
+        if (localincludepath == null)
+            localincludepath = new Path(getProject());
+        localincludepath.add(path);
+    }
+
+    /*
+     public void execute() {
+     FileWriter writer = null;
+     try {
+     if (input == null)
+     throw new BuildException("Input not specified");
+     if (output == null)
+     throw new BuildException("Output not specified");
+     cpp.addInput(this.input);
+     writer = new FileWriter(this.output);
+     for (;;) {
+     Token	tok = cpp.token();
+     if (tok != null && tok.getType() == Token.EOF)
+     break;
+     writer.write(tok.getText());
+     }
+     }
+     catch (Exception e) {
+     throw new BuildException(e);
+     }
+     finally {
+     if (writer != null) {
+     try {
+     writer.close();
+     }
+     catch (IOException e) {
+     }
+     }
+     }
+     }
+     */
+    private void preprocess(File input, File output) throws Exception {
+        Preprocessor cpp = new Preprocessor();
+        cpp.setListener(listener);
+        for (Macro macro : macros)
+            cpp.addMacro(macro.getName(), macro.getValue());
+        if (systemincludepath != null)
+            cpp.setSystemIncludePath(Arrays.asList(systemincludepath.list()));
+        if (localincludepath != null)
+            cpp.setQuoteIncludePath(Arrays.asList(localincludepath.list()));
+
+        File dir = output.getParentFile();
+        if (!dir.exists()) {
+            if (!dir.mkdirs())
+                throw new BuildException("Failed to make parent directory " + dir);
+        } else if (!dir.isDirectory()) {
+            throw new BuildException("Parent directory of output file " + output + " exists, but is not a directory.");
+        }
+        FileWriter writer = null;
+        try {
+            if (input == null)
+                throw new BuildException("Input not specified");
+            if (output == null)
+                throw new BuildException("Output not specified");
+            cpp.addInput(input);
+            writer = new FileWriter(output);
+            for (;;) {
+                Token tok = cpp.token();
+                if (tok == null)
+                    break;
+                if (tok.getType() == Token.EOF)
+                    break;
+                writer.write(tok.getText());
+            }
+        } finally {
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void doFileOperations() {
+        if (fileCopyMap.size() > 0) {
+            log("Copying " + fileCopyMap.size()
+                    + " file" + (fileCopyMap.size() == 1 ? "" : "s")
+                    + " to " + destDir.getAbsolutePath());
+
+            Enumeration<String> e = fileCopyMap.keys();
+
+            while (e.hasMoreElements()) {
+                String fromFile = e.nextElement();
+                String[] toFiles = (String[]) fileCopyMap.get(fromFile);
+
+                for (String toFile : toFiles) {
+                    if (fromFile.equals(toFile)) {
+                        log("Skipping self-copy of " + fromFile, verbosity);
+                        continue;
+                    }
+
+                    try {
+                        log("Copying " + fromFile + " to " + toFile, verbosity);
+
+                        FilterSetCollection executionFilters
+                                = new FilterSetCollection();
+                        if (filtering) {
+                            executionFilters
+                                    .addFilterSet(getProject().getGlobalFilterSet());
+                        }
+                        for (Enumeration filterEnum = getFilterSets().elements();
+                                filterEnum.hasMoreElements();) {
+                            executionFilters
+                                    .addFilterSet((FilterSet) filterEnum.nextElement());
+                        }
+
+                        File srcFile = new File(fromFile);
+                        File dstFile = new File(toFile);
+                        preprocess(srcFile, dstFile);
+                    } catch (Exception ioe) {
+                        // ioe.printStackTrace();
+                        String msg = "Failed to copy " + fromFile + " to " + toFile
+                                + " due to " + ioe.getMessage();
+                        File targetFile = new File(toFile);
+                        if (targetFile.exists() && !targetFile.delete()) {
+                            msg += " and I couldn't delete the corrupt " + toFile;
+                        }
+                        throw new BuildException(msg, ioe, getLocation());
+                    }
+                }
+            }
+        }
+
+    }
+
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/DefaultPreprocessorListener.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/DefaultPreprocessorListener.java
new file mode 100644
index 0000000..aeff3c8
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/DefaultPreprocessorListener.java
@@ -0,0 +1,99 @@
+package com.jogamp.gluegen.jcpp;
+
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+
+import com.jogamp.gluegen.Logging;
+import com.jogamp.gluegen.Logging.LoggerIf;
+
+/**
+ * A handler for preprocessor events, primarily errors and warnings.
+ *
+ * If no PreprocessorListener is installed in a Preprocessor, all
+ * error and warning events will throw an exception. Installing a
+ * listener allows more intelligent handling of these events.
+ */
+public class DefaultPreprocessorListener implements PreprocessorListener {
+
+    private final LoggerIf LOG;
+
+    private int errors;
+    private int warnings;
+
+    public DefaultPreprocessorListener() {
+        LOG = Logging.getLogger(DefaultPreprocessorListener.class);
+        clear();
+    }
+
+    public void clear() {
+        errors = 0;
+        warnings = 0;
+    }
+
+    @Nonnegative
+    public int getErrors() {
+        return errors;
+    }
+
+    @Nonnegative
+    public int getWarnings() {
+        return warnings;
+    }
+
+    protected void print(@Nonnull final String msg) {
+        LOG.info(msg);
+    }
+
+    /**
+     * Handles a warning.
+     *
+     * The behaviour of this method is defined by the
+     * implementation. It may simply record the error message, or
+     * it may throw an exception.
+     */
+    @Override
+    public void handleWarning(final Source source, final int line, final int column,
+            final String msg)
+            throws LexerException {
+        warnings++;
+        print(source.getName() + ":" + line + ":" + column
+                + ": warning: " + msg);
+    }
+
+    /**
+     * Handles an error.
+     *
+     * The behaviour of this method is defined by the
+     * implementation. It may simply record the error message, or
+     * it may throw an exception.
+     */
+    @Override
+    public void handleError(final Source source, final int line, final int column,
+            final String msg)
+            throws LexerException {
+        errors++;
+        print(source.getName() + ":" + line + ":" + column
+                + ": error: " + msg);
+    }
+
+    @Override
+    public void handleSourceChange(final Source source, final SourceChangeEvent event) {
+    }
+
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Feature.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Feature.java
new file mode 100644
index 0000000..e2feefc
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Feature.java
@@ -0,0 +1,42 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+/**
+ * Features of the Preprocessor, which may be enabled or disabled.
+ */
+public enum Feature {
+
+    /** Supports ANSI digraphs. */
+    DIGRAPHS,
+    /** Supports ANSI trigraphs. */
+    TRIGRAPHS,
+    /** Outputs linemarker tokens. */
+    LINEMARKERS,
+    /** Reports tokens of type INVALID as errors. */
+    CSYNTAX,
+    /** Preserves comments in the lexed output. */
+    KEEPCOMMENTS,
+    /** Preserves comments in the lexed output, even when inactive. */
+    KEEPALLCOMMENTS,
+    DEBUG,
+    /** Supports lexing of objective-C. */
+    OBJCSYNTAX,
+    INCLUDENEXT,
+    /** Random extensions. */
+    PRAGMA_ONCE
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/FileLexerSource.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/FileLexerSource.java
new file mode 100644
index 0000000..6d7e4c5
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/FileLexerSource.java
@@ -0,0 +1,89 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import javax.annotation.Nonnull;
+
+/**
+ * A {@link Source} which lexes a file.
+ *
+ * The input is buffered.
+ *
+ * @see Source
+ */
+public class FileLexerSource extends LexerSource {
+
+    private final String path;
+    private final File file;
+
+    /**
+     * Creates a new Source for lexing the given File.
+     *
+     * Preprocessor directives are honoured within the file.
+     */
+    public FileLexerSource(@Nonnull File file, String path)
+            throws IOException {
+        super(
+                new BufferedReader(
+                        new FileReader(
+                                file
+                        )
+                ),
+                true
+        );
+
+        this.file = file;
+        this.path = path;
+    }
+
+    public FileLexerSource(@Nonnull File file)
+            throws IOException {
+        this(file, file.getPath());
+    }
+
+    public FileLexerSource(@Nonnull String path)
+            throws IOException {
+        this(new File(path), path);
+    }
+
+    @Nonnull
+    public File getFile() {
+        return file;
+    }
+
+    /**
+     * This is not necessarily the same as getFile().getPath() in case we are in a chroot.
+     */
+    @Override
+    public String getPath() {
+        return path;
+    }
+
+    @Override
+    public String getName() {
+        return getPath();
+    }
+
+    @Override
+    public String toString() {
+        return "file " + getPath();
+    }
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/FixedTokenSource.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/FixedTokenSource.java
new file mode 100644
index 0000000..d084932
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/FixedTokenSource.java
@@ -0,0 +1,59 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+/* pp */ class FixedTokenSource extends Source {
+
+    private static final Token EOF
+            = new Token(Token.EOF, "<ts-eof>");
+
+    private final List<Token> tokens;
+    private int idx;
+
+    /* pp */ FixedTokenSource(Token... tokens) {
+        this.tokens = Arrays.asList(tokens);
+        this.idx = 0;
+    }
+
+    /* pp */ FixedTokenSource(List<Token> tokens) {
+        this.tokens = tokens;
+        this.idx = 0;
+    }
+
+    @Override
+    public Token token()
+            throws IOException,
+            LexerException {
+        if (idx >= tokens.size())
+            return EOF;
+        return tokens.get(idx++);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder();
+        buf.append("constant token stream ").append(tokens);
+        Source parent = getParent();
+        if (parent != null)
+            buf.append(" in ").append(String.valueOf(parent));
+        return buf.toString();
+    }
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/InputLexerSource.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/InputLexerSource.java
new file mode 100644
index 0000000..00cb01a
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/InputLexerSource.java
@@ -0,0 +1,64 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+/**
+ * A {@link Source} which lexes a file.
+ *
+ * The input is buffered.
+ *
+ * @see Source
+ */
+public class InputLexerSource extends LexerSource {
+
+    /**
+     * Creates a new Source for lexing the given Reader.
+     *
+     * Preprocessor directives are honoured within the file.
+     */
+    public InputLexerSource(InputStream input)
+            throws IOException {
+        super(
+                new BufferedReader(
+                        new InputStreamReader(
+                                input
+                        )
+                ),
+                true
+        );
+    }
+
+    @Override
+    public String getPath() {
+        return "<standard-input>";
+    }
+
+    @Override
+    public String getName() {
+        return "standard input";
+    }
+
+    @Override
+    public String toString() {
+        return String.valueOf(getPath());
+    }
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/InternalException.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/InternalException.java
new file mode 100644
index 0000000..72abaf9
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/InternalException.java
@@ -0,0 +1,31 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+/**
+ * An internal exception.
+ *
+ * This exception is thrown when an internal state violation is
+ * encountered. This should never happen. If it ever happens, please
+ * report it as a bug.
+ */
+public class InternalException extends RuntimeException {
+
+    public InternalException(String msg) {
+        super(msg);
+    }
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/JCPP.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/JCPP.java
new file mode 100644
index 0000000..658306a
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/JCPP.java
@@ -0,0 +1,189 @@
+/**
+ * Copyright 2015 JogAmp Community. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.io.File;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+
+import com.jogamp.gluegen.ASTLocusTag;
+import com.jogamp.gluegen.ConstantDefinition;
+import com.jogamp.gluegen.GenericCPP;
+import com.jogamp.gluegen.GlueGen;
+import com.jogamp.gluegen.GlueGenException;
+import com.jogamp.gluegen.Logging;
+import com.jogamp.gluegen.Logging.LoggerIf;
+
+public class JCPP implements GenericCPP {
+    private final LoggerIf LOG;
+
+    public final Preprocessor cpp;
+    private OutputStream out;
+    private final List<String> includePaths;
+    private final boolean enableCopyOutput2Stderr;
+
+    public JCPP(final List<String> includePaths, final boolean debug, final boolean copyOutput2Stderr) {
+        LOG = Logging.getLogger(JCPP.class);
+        setOut(System.out);
+        this.includePaths = includePaths;
+        this.enableCopyOutput2Stderr = copyOutput2Stderr;
+
+        cpp = new Preprocessor();
+        cpp.addFeature(Feature.DIGRAPHS);
+        cpp.addFeature(Feature.TRIGRAPHS);
+        cpp.addFeature(Feature.LINEMARKERS);
+        cpp.addFeature(Feature.CSYNTAX);
+        cpp.addFeature(Feature.KEEPCOMMENTS);
+        cpp.addWarning(Warning.IMPORT);
+        cpp.setListener(new DefaultPreprocessorListener() {
+            @Override
+            public void handleError(final Source source, final int line, final int column,
+                                    final String msg) throws LexerException {
+                super.handleError(source, line, column, msg);
+                throw new GlueGenException(msg, new ASTLocusTag(source.getPath(), line, column, null));
+            }
+        });
+        if (debug) {
+            cpp.addFeature(Feature.DEBUG);
+        }
+        cpp.setSystemIncludePath(includePaths);
+        cpp.setQuoteIncludePath(includePaths);
+
+        if (cpp.getFeature(Feature.DEBUG)) {
+            LOG.info("#" + "include \"...\" search starts here:");
+            for (final String dir : cpp.getQuoteIncludePath())
+                LOG.info("  " + dir);
+            LOG.info("#" + "include <...> search starts here:");
+            for (final String dir : cpp.getSystemIncludePath())
+                LOG.info("  " + dir);
+            LOG.info("End of search list.");
+        }
+    }
+
+    @Override
+    public void addDefine(final String name, final String value) throws LexerException {
+        cpp.addMacro(name, value);
+    }
+
+    @Override
+    public List<ConstantDefinition> getConstantDefinitions() throws GlueGenException {
+        final List<ConstantDefinition> constants = new ArrayList<ConstantDefinition>();
+        final List<Macro> macros;
+        try {
+            macros = cpp.getMacros(true);
+        } catch (final Throwable t) {
+            throw new GlueGenException(t);
+        }
+        final int count = macros.size();
+        for(int i=0; i<count; i++) {
+            final Macro macro = macros.get(i);
+            final String name = macro.getName();
+            if( !GlueGen.__GLUEGEN__.equals(name) ) {
+                if( !macro.isFunctionLike() ) {
+                    final String value = macro.getText();
+                    if ( ConstantDefinition.isConstantExpression(value) ) {
+                        final Source source = macro.getSource();
+                        final ASTLocusTag locus = new ASTLocusTag(
+                                                    null != source ? source.getPath() : "<programmatic>",
+                                                    null != source ? source.getLine() : -1,
+                                                    null != source ? source.getColumn() : -1,
+                                                    macro.toString());
+                        final ConstantDefinition c = new ConstantDefinition(macro.getName(), value, locus);
+                        constants.add(c);
+                    }
+                }
+            }
+        }
+        return constants;
+    }
+
+    @Override
+    public String findFile(final String filename) {
+        final String sep = File.separator;
+        for (final String inclPath : includePaths) {
+            final String fullPath = inclPath + sep + filename;
+            final File file = new File(fullPath);
+            if (file.exists()) {
+                return fullPath;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public OutputStream out() {
+        return out;
+    }
+    @Override
+    public void setOut(final OutputStream out) {
+        this.out = out;
+    }
+
+    @Override
+    public void run(final Reader reader, final String filename) throws GlueGenException {
+        final PrintWriter writer = new PrintWriter(out);
+        cpp.addInput(new LexerSource(reader, true) {
+                        @Override
+                        public String getPath() { return filename; }
+                        @Override
+                        public String getName() { return filename; }
+                        @Override
+                        public String toString() { return "file " + filename; }
+                   } );
+        try {
+            for (;;) {
+                final Token tok = cpp.token();
+                if (tok == null)
+                    break;
+                if (tok.getType() == Token.EOF)
+                    break;
+                final String s = tok.getText();
+                writer.print(s);
+                if (enableCopyOutput2Stderr) {
+                    System.err.print(s);
+                    System.err.flush();
+                }
+            }
+            writer.flush();
+        } catch (final Exception e) {
+            final StringBuilder buf = new StringBuilder("Preprocessor failed:\n");
+            Source s = cpp.getSource();
+            while (s != null) {
+                buf.append(" -> ").append(s).append("\n");
+                s = s.getParent();
+            }
+            buf.append(" : {0}\n");
+            LOG.log(Level.SEVERE, buf.toString(), e);
+            if( e instanceof GlueGenException ) {
+                throw (GlueGenException)e;
+            } else {
+                throw new GlueGenException("Preprocessor failed",
+                                           new ASTLocusTag(null != s ? s.getPath() : "n/a",
+                                                           null != s ? s.getLine() : -1,
+                                                           null != s ? s.getColumn() : -1, null), e);
+            }
+        }
+    }
+
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/JavaFileSystem.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/JavaFileSystem.java
new file mode 100644
index 0000000..f62ba53
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/JavaFileSystem.java
@@ -0,0 +1,84 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * A virtual filesystem implementation using java.io.
+ */
+public class JavaFileSystem implements VirtualFileSystem {
+
+    @Override
+    public VirtualFile getFile(String path) {
+        return new JavaFile(path);
+    }
+
+    @Override
+    public VirtualFile getFile(String dir, String name) {
+        return new JavaFile(dir, name);
+    }
+
+    private class JavaFile extends File implements VirtualFile {
+
+        public JavaFile(String path) {
+            super(path);
+        }
+
+        public JavaFile(String dir, String name) {
+            super(dir, name);
+        }
+
+        /* private */
+        public JavaFile(File dir, String name) {
+            super(dir, name);
+        }
+
+        /*
+         @Override
+         public String getPath() {
+         return getCanonicalPath();
+         }
+         */
+        @Override
+        public JavaFile getParentFile() {
+            String parent = getParent();
+            if (parent != null)
+                return new JavaFile(parent);
+            File absolute = getAbsoluteFile();
+            parent = absolute.getParent();
+            /*
+             if (parent == null)
+             return null;
+             */
+            return new JavaFile(parent);
+        }
+
+        @Override
+        public JavaFile getChildFile(String name) {
+            return new JavaFile(this, name);
+        }
+
+        @Override
+        public Source getSource() throws IOException {
+            return new FileLexerSource(this);
+        }
+
+    }
+
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/JoinReader.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/JoinReader.java
new file mode 100644
index 0000000..e44a7e6
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/JoinReader.java
@@ -0,0 +1,218 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.Reader;
+
+/* pp */ class JoinReader /* extends Reader */ implements Closeable {
+
+    private final Reader in;
+
+    private PreprocessorListener listener;
+    private LexerSource source;
+    private boolean trigraphs;
+    private boolean warnings;
+
+    private int newlines;
+    private boolean flushnl;
+    private int[] unget;
+    private int uptr;
+
+    public JoinReader(Reader in, boolean trigraphs) {
+        this.in = in;
+        this.trigraphs = trigraphs;
+        this.newlines = 0;
+        this.flushnl = false;
+        this.unget = new int[2];
+        this.uptr = 0;
+    }
+
+    public JoinReader(Reader in) {
+        this(in, false);
+    }
+
+    public void setTrigraphs(boolean enable, boolean warnings) {
+        this.trigraphs = enable;
+        this.warnings = warnings;
+    }
+
+    /* pp */ void init(Preprocessor pp, LexerSource s) {
+        this.listener = pp.getListener();
+        this.source = s;
+        setTrigraphs(pp.getFeature(Feature.TRIGRAPHS),
+                pp.getWarning(Warning.TRIGRAPHS));
+    }
+
+    private int __read() throws IOException {
+        if (uptr > 0)
+            return unget[--uptr];
+        return in.read();
+    }
+
+    private void _unread(int c) {
+        if (c != -1)
+            unget[uptr++] = c;
+        assert uptr <= unget.length :
+                "JoinReader ungets too many characters";
+    }
+
+    protected void warning(String msg)
+            throws LexerException {
+        if (source != null)
+            source.warning(msg);
+        else
+            throw new LexerException(msg);
+    }
+
+    private char trigraph(char raw, char repl)
+            throws IOException, LexerException {
+        if (trigraphs) {
+            if (warnings)
+                warning("trigraph ??" + raw + " converted to " + repl);
+            return repl;
+        } else {
+            if (warnings)
+                warning("trigraph ??" + raw + " ignored");
+            _unread(raw);
+            _unread('?');
+            return '?';
+        }
+    }
+
+    private int _read()
+            throws IOException, LexerException {
+        int c = __read();
+        if (c == '?' && (trigraphs || warnings)) {
+            int d = __read();
+            if (d == '?') {
+                int e = __read();
+                switch (e) {
+                    case '(':
+                        return trigraph('(', '[');
+                    case ')':
+                        return trigraph(')', ']');
+                    case '<':
+                        return trigraph('<', '{');
+                    case '>':
+                        return trigraph('>', '}');
+                    case '=':
+                        return trigraph('=', '#');
+                    case '/':
+                        return trigraph('/', '\\');
+                    case '\'':
+                        return trigraph('\'', '^');
+                    case '!':
+                        return trigraph('!', '|');
+                    case '-':
+                        return trigraph('-', '~');
+                }
+                _unread(e);
+            }
+            _unread(d);
+        }
+        return c;
+    }
+
+    public int read()
+            throws IOException, LexerException {
+        if (flushnl) {
+            if (newlines > 0) {
+                newlines--;
+                return '\n';
+            }
+            flushnl = false;
+        }
+
+        for (;;) {
+            int c = _read();
+            switch (c) {
+                case '\\':
+                    int d = _read();
+                    switch (d) {
+                        case '\n':
+                            newlines++;
+                            continue;
+                        case '\r':
+                            newlines++;
+                            int e = _read();
+                            if (e != '\n')
+                                _unread(e);
+                            continue;
+                        default:
+                            _unread(d);
+                            return c;
+                    }
+                case '\r':
+                case '\n':
+                case '\u2028':
+                case '\u2029':
+                case '\u000B':
+                case '\u000C':
+                case '\u0085':
+                    flushnl = true;
+                    return c;
+                case -1:
+                    if (newlines > 0) {
+                        newlines--;
+                        return '\n';
+                    }
+                default:
+                    return c;
+            }
+        }
+    }
+
+    public int read(char cbuf[], int off, int len)
+            throws IOException, LexerException {
+        for (int i = 0; i < len; i++) {
+            int ch = read();
+            if (ch == -1)
+                return i;
+            cbuf[off + i] = (char) ch;
+        }
+        return len;
+    }
+
+    @Override
+    public void close()
+            throws IOException {
+        in.close();
+    }
+
+    @Override
+    public String toString() {
+        return "JoinReader(nl=" + newlines + ")";
+    }
+
+    /*
+     public static void main(String[] args) throws IOException {
+     FileReader		f = new FileReader(new File(args[0]));
+     BufferedReader	b = new BufferedReader(f);
+     JoinReader		r = new JoinReader(b);
+     BufferedWriter	w = new BufferedWriter(
+     new java.io.OutputStreamWriter(System.out)
+     );
+     int				c;
+     while ((c = r.read()) != -1) {
+     w.write((char)c);
+     }
+     w.close();
+     }
+     */
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/LexerException.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/LexerException.java
new file mode 100644
index 0000000..6a9bf5b
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/LexerException.java
@@ -0,0 +1,33 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+/**
+ * A preprocessor exception.
+ *
+ * Note to users: I don't really like the name of this class. S.
+ */
+public class LexerException extends Exception {
+
+    public LexerException(String msg) {
+        super(msg);
+    }
+
+    public LexerException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/LexerSource.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/LexerSource.java
new file mode 100644
index 0000000..798e0a9
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/LexerSource.java
@@ -0,0 +1,987 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import javax.annotation.Nonnull;
+
+import static com.jogamp.gluegen.jcpp.Token.*;
+
+/** Does not handle digraphs. */
+public class LexerSource extends Source {
+
+    private static final boolean DEBUG = false;
+
+    private JoinReader reader;
+    private final boolean ppvalid;
+    private boolean bol;
+    private boolean include;
+
+    private boolean digraphs;
+
+    /* Unread. */
+    private int u0, u1;
+    private int ucount;
+
+    private int line;
+    private int column;
+    private int lastcolumn;
+    private boolean cr;
+
+    /* ppvalid is:
+     * false in StringLexerSource,
+     * true in FileLexerSource */
+    public LexerSource(Reader r, boolean ppvalid) {
+        this.reader = new JoinReader(r);
+        this.ppvalid = ppvalid;
+        this.bol = true;
+        this.include = false;
+
+        this.digraphs = true;
+
+        this.ucount = 0;
+
+        this.line = 1;
+        this.column = 0;
+        this.lastcolumn = -1;
+        this.cr = false;
+    }
+
+    @Override
+    /* pp */ void init(Preprocessor pp) {
+        super.init(pp);
+        this.digraphs = pp.getFeature(Feature.DIGRAPHS);
+        this.reader.init(pp, this);
+    }
+
+    @Override
+    public int getLine() {
+        return line;
+    }
+
+    @Override
+    public int getColumn() {
+        return column;
+    }
+
+    @Override
+    /* pp */ boolean isNumbered() {
+        return true;
+    }
+
+    /* Error handling. */
+    private void _error(String msg, boolean error)
+            throws LexerException {
+        int _l = line;
+        int _c = column;
+        if (_c == 0) {
+            _c = lastcolumn;
+            _l--;
+        } else {
+            _c--;
+        }
+        if (error)
+            super.error(_l, _c, msg);
+        else
+            super.warning(_l, _c, msg);
+    }
+
+    /* Allow JoinReader to call this. */
+    /* pp */ final void error(String msg)
+            throws LexerException {
+        _error(msg, true);
+    }
+
+    /* Allow JoinReader to call this. */
+    /* pp */ final void warning(String msg)
+            throws LexerException {
+        _error(msg, false);
+    }
+
+    /* A flag for string handling. */
+
+    /* pp */ void setInclude(boolean b) {
+        this.include = b;
+    }
+
+    /*
+     * private boolean _isLineSeparator(int c) {
+     * return Character.getType(c) == Character.LINE_SEPARATOR
+     * || c == -1;
+     * }
+     */
+
+    /* XXX Move to JoinReader and canonicalise newlines. */
+    private static boolean isLineSeparator(int c) {
+        switch ((char) c) {
+            case '\r':
+            case '\n':
+            case '\u2028':
+            case '\u2029':
+            case '\u000B':
+            case '\u000C':
+            case '\u0085':
+                return true;
+            default:
+                return (c == -1);
+        }
+    }
+
+    private int read()
+            throws IOException,
+            LexerException {
+        int c;
+        assert ucount <= 2 : "Illegal ucount: " + ucount;
+        switch (ucount) {
+            case 2:
+                ucount = 1;
+                c = u1;
+                break;
+            case 1:
+                ucount = 0;
+                c = u0;
+                break;
+            default:
+                if (reader == null)
+                    c = -1;
+                else
+                    c = reader.read();
+                break;
+        }
+
+        switch (c) {
+            case '\r':
+                cr = true;
+                line++;
+                lastcolumn = column;
+                column = 0;
+                break;
+            case '\n':
+                if (cr) {
+                    cr = false;
+                    break;
+                }
+            /* fallthrough */
+            case '\u2028':
+            case '\u2029':
+            case '\u000B':
+            case '\u000C':
+            case '\u0085':
+                cr = false;
+                line++;
+                lastcolumn = column;
+                column = 0;
+                break;
+            case -1:
+                cr = false;
+                break;
+            default:
+                cr = false;
+                column++;
+                break;
+        }
+
+        /*
+         * if (isLineSeparator(c)) {
+         * line++;
+         * lastcolumn = column;
+         * column = 0;
+         * }
+         * else {
+         * column++;
+         * }
+         */
+        return c;
+    }
+
+    /* You can unget AT MOST one newline. */
+    private void unread(int c)
+            throws IOException {
+        /* XXX Must unread newlines. */
+        if (c != -1) {
+            if (isLineSeparator(c)) {
+                line--;
+                column = lastcolumn;
+                cr = false;
+            } else {
+                column--;
+            }
+            switch (ucount) {
+                case 0:
+                    u0 = c;
+                    ucount = 1;
+                    break;
+                case 1:
+                    u1 = c;
+                    ucount = 2;
+                    break;
+                default:
+                    throw new IllegalStateException(
+                            "Cannot unget another character!"
+                    );
+            }
+            // reader.unread(c);
+        }
+    }
+
+    /* Consumes the rest of the current line into an invalid. */
+    @Nonnull
+    private Token invalid(StringBuilder text, String reason)
+            throws IOException,
+            LexerException {
+        int d = read();
+        while (!isLineSeparator(d)) {
+            text.append((char) d);
+            d = read();
+        }
+        unread(d);
+        return new Token(INVALID, text.toString(), reason);
+    }
+
+    @Nonnull
+    private Token ccomment()
+            throws IOException,
+            LexerException {
+        StringBuilder text = new StringBuilder("/*");
+        int d;
+        do {
+            do {
+                d = read();
+                if (d == -1)
+                    return new Token(INVALID, text.toString(),
+                            "Unterminated comment");
+                text.append((char) d);
+            } while (d != '*');
+            do {
+                d = read();
+                if (d == -1)
+                    return new Token(INVALID, text.toString(),
+                            "Unterminated comment");
+                text.append((char) d);
+            } while (d == '*');
+        } while (d != '/');
+        return new Token(CCOMMENT, text.toString());
+    }
+
+    @Nonnull
+    private Token cppcomment()
+            throws IOException,
+            LexerException {
+        StringBuilder text = new StringBuilder("//");
+        int d = read();
+        while (!isLineSeparator(d)) {
+            text.append((char) d);
+            d = read();
+        }
+        unread(d);
+        return new Token(CPPCOMMENT, text.toString());
+    }
+
+    private int escape(StringBuilder text)
+            throws IOException,
+            LexerException {
+        int d = read();
+        switch (d) {
+            case 'a':
+                text.append('a');
+                return 0x07;
+            case 'b':
+                text.append('b');
+                return '\b';
+            case 'f':
+                text.append('f');
+                return '\f';
+            case 'n':
+                text.append('n');
+                return '\n';
+            case 'r':
+                text.append('r');
+                return '\r';
+            case 't':
+                text.append('t');
+                return '\t';
+            case 'v':
+                text.append('v');
+                return 0x0b;
+            case '\\':
+                text.append('\\');
+                return '\\';
+
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+                int len = 0;
+                int val = 0;
+                do {
+                    val = (val << 3) + Character.digit(d, 8);
+                    text.append((char) d);
+                    d = read();
+                } while (++len < 3 && Character.digit(d, 8) != -1);
+                unread(d);
+                return val;
+
+            case 'x':
+                text.append((char) d);
+                len = 0;
+                val = 0;
+                while (len++ < 2) {
+                    d = read();
+                    if (Character.digit(d, 16) == -1) {
+                        unread(d);
+                        break;
+                    }
+                    val = (val << 4) + Character.digit(d, 16);
+                    text.append((char) d);
+                }
+                return val;
+
+            /* Exclude two cases from the warning. */
+            case '"':
+                text.append('"');
+                return '"';
+            case '\'':
+                text.append('\'');
+                return '\'';
+
+            default:
+                warning("Unnecessary escape character " + (char) d);
+                text.append((char) d);
+                return d;
+        }
+    }
+
+    @Nonnull
+    private Token character()
+            throws IOException,
+            LexerException {
+        StringBuilder text = new StringBuilder("'");
+        int d = read();
+        if (d == '\\') {
+            text.append('\\');
+            d = escape(text);
+        } else if (isLineSeparator(d)) {
+            unread(d);
+            return new Token(INVALID, text.toString(),
+                    "Unterminated character literal");
+        } else if (d == '\'') {
+            text.append('\'');
+            return new Token(INVALID, text.toString(),
+                    "Empty character literal");
+        } else if (!Character.isDefined(d)) {
+            text.append('?');
+            return invalid(text, "Illegal unicode character literal");
+        } else {
+            text.append((char) d);
+        }
+
+        int e = read();
+        if (e != '\'') {
+            // error("Illegal character constant");
+			/* We consume up to the next ' or the rest of the line. */
+            for (;;) {
+                if (isLineSeparator(e)) {
+                    unread(e);
+                    break;
+                }
+                text.append((char) e);
+                if (e == '\'')
+                    break;
+                e = read();
+            }
+            return new Token(INVALID, text.toString(),
+                    "Illegal character constant " + text);
+        }
+        text.append('\'');
+        /* XXX It this a bad cast? */
+        return new Token(CHARACTER,
+                text.toString(), Character.valueOf((char) d));
+    }
+
+    @Nonnull
+    private Token string(char open, char close)
+            throws IOException,
+            LexerException {
+        StringBuilder text = new StringBuilder();
+        text.append(open);
+
+        StringBuilder buf = new StringBuilder();
+
+        for (;;) {
+            int c = read();
+            if (c == close) {
+                break;
+            } else if (c == '\\') {
+                text.append('\\');
+                if (!include) {
+                    char d = (char) escape(text);
+                    buf.append(d);
+                }
+            } else if (c == -1) {
+                unread(c);
+                // error("End of file in string literal after " + buf);
+                return new Token(INVALID, text.toString(),
+                        "End of file in string literal after " + buf);
+            } else if (isLineSeparator(c)) {
+                unread(c);
+                // error("Unterminated string literal after " + buf);
+                return new Token(INVALID, text.toString(),
+                        "Unterminated string literal after " + buf);
+            } else {
+                text.append((char) c);
+                buf.append((char) c);
+            }
+        }
+        text.append(close);
+        switch (close) {
+            case '"':
+                return new Token(STRING,
+                        text.toString(), buf.toString());
+            case '>':
+                return new Token(HEADER,
+                        text.toString(), buf.toString());
+            case '\'':
+                if (buf.length() == 1)
+                    return new Token(CHARACTER,
+                            text.toString(), buf.toString());
+                return new Token(SQSTRING,
+                        text.toString(), buf.toString());
+            default:
+                throw new IllegalStateException(
+                        "Unknown closing character " + String.valueOf(close));
+        }
+    }
+
+    @Nonnull
+    private Token _number_suffix(StringBuilder text, NumericValue value, int d)
+            throws IOException,
+            LexerException {
+        int flags = 0;	// U, I, L, LL, F, D, MSB
+        for (;;) {
+            if (d == 'U' || d == 'u') {
+                if ((flags & NumericValue.F_UNSIGNED) != 0)
+                    warning("Duplicate unsigned suffix " + d);
+                flags |= NumericValue.F_UNSIGNED;
+                text.append((char) d);
+                d = read();
+            } else if (d == 'L' || d == 'l') {
+                if ((flags & NumericValue.FF_SIZE) != 0)
+                    warning("Multiple length suffixes after " + text);
+                text.append((char) d);
+                int e = read();
+                if (e == d) {	// Case must match. Ll is Welsh.
+                    flags |= NumericValue.F_LONGLONG;
+                    text.append((char) e);
+                    d = read();
+                } else {
+                    flags |= NumericValue.F_LONG;
+                    d = e;
+                }
+            } else if (d == 'I' || d == 'i') {
+                if ((flags & NumericValue.FF_SIZE) != 0)
+                    warning("Multiple length suffixes after " + text);
+                flags |= NumericValue.F_INT;
+                text.append((char) d);
+                d = read();
+            } else if (d == 'F' || d == 'f') {
+                if ((flags & NumericValue.FF_SIZE) != 0)
+                    warning("Multiple length suffixes after " + text);
+                flags |= NumericValue.F_FLOAT;
+                text.append((char) d);
+                d = read();
+            } else if (d == 'D' || d == 'd') {
+                if ((flags & NumericValue.FF_SIZE) != 0)
+                    warning("Multiple length suffixes after " + text);
+                flags |= NumericValue.F_DOUBLE;
+                text.append((char) d);
+                d = read();
+            }
+            else if (Character.isUnicodeIdentifierPart(d)) {
+                String reason = "Invalid suffix \"" + (char) d + "\" on numeric constant";
+                // We've encountered something initially identified as a number.
+                // Read in the rest of this token as an identifer but return it as an invalid.
+                while (Character.isUnicodeIdentifierPart(d)) {
+                    text.append((char) d);
+                    d = read();
+                }
+                unread(d);
+                return new Token(INVALID, text.toString(), reason);
+            } else {
+                unread(d);
+                value.setFlags(flags);
+                return new Token(NUMBER,
+                        text.toString(), value);
+            }
+        }
+    }
+
+    /* Either a decimal part, or a hex exponent. */
+    @Nonnull
+    private String _number_part(StringBuilder text, int base, boolean sign)
+            throws IOException,
+            LexerException {
+        StringBuilder part = new StringBuilder();
+        int d = read();
+        if (sign && d == '-') {
+            text.append((char) d);
+            part.append((char) d);
+            d = read();
+        }
+        while (Character.digit(d, base) != -1) {
+            text.append((char) d);
+            part.append((char) d);
+            d = read();
+        }
+        unread(d);
+        return part.toString();
+    }
+
+    /* We do not know whether know the first digit is valid. */
+    @Nonnull
+    private Token number_hex(char x)
+            throws IOException,
+            LexerException {
+        StringBuilder text = new StringBuilder("0");
+        text.append(x);
+        String integer = _number_part(text, 16, false);
+        NumericValue value = new NumericValue(16, integer);
+        int d = read();
+        if (d == '.') {
+            text.append((char) d);
+            String fraction = _number_part(text, 16, false);
+            value.setFractionalPart(fraction);
+            d = read();
+        }
+        if (d == 'P' || d == 'p') {
+            text.append((char) d);
+            String exponent = _number_part(text, 10, true);
+            value.setExponent(2, exponent);
+            d = read();
+        }
+        // XXX Make sure it's got enough parts
+        return _number_suffix(text, value, d);
+    }
+
+    private static boolean is_octal(@Nonnull String text) {
+        if (!text.startsWith("0"))
+            return false;
+        for (int i = 0; i < text.length(); i++)
+            if (Character.digit(text.charAt(i), 8) == -1)
+                return false;
+        return true;
+    }
+
+    /* We know we have at least one valid digit, but empty is not
+     * fine. */
+    @Nonnull
+    private Token number_decimal()
+            throws IOException,
+            LexerException {
+        StringBuilder text = new StringBuilder();
+        String integer = _number_part(text, 10, false);
+        String fraction = null;
+        String exponent = null;
+        int d = read();
+        if (d == '.') {
+            text.append((char) d);
+            fraction = _number_part(text, 10, false);
+            d = read();
+        }
+        if (d == 'E' || d == 'e') {
+            text.append((char) d);
+            exponent = _number_part(text, 10, true);
+            d = read();
+        }
+        int base = 10;
+        if (fraction == null && exponent == null && integer.startsWith("0")) {
+            if (!is_octal(integer))
+                warning("Decimal constant starts with 0, but not octal: " + integer);
+            else
+                base = 8;
+        }
+        NumericValue value = new NumericValue(base, integer);
+        if (fraction != null)
+            value.setFractionalPart(fraction);
+        if (exponent != null)
+            value.setExponent(10, exponent);
+        // XXX Make sure it's got enough parts
+        return _number_suffix(text, value, d);
+    }
+
+    /**
+     * Section 6.4.4.1 of C99
+     * 
+     * (Not pasted here, but says that the initial negation is a separate token.)
+     * 
+     * Section 6.4.4.2 of C99
+     *
+     * A floating constant has a significand part that may be followed
+     * by an exponent part and a suffix that specifies its type. The
+     * components of the significand part may include a digit sequence
+     * representing the whole-number part, followed by a period (.),
+     * followed by a digit sequence representing the fraction part.
+     *
+     * The components of the exponent part are an e, E, p, or P
+     * followed by an exponent consisting of an optionally signed digit
+     * sequence. Either the whole-number part or the fraction part has to
+     * be present; for decimal floating constants, either the period or
+     * the exponent part has to be present.
+     *
+     * The significand part is interpreted as a (decimal or hexadecimal)
+     * rational number; the digit sequence in the exponent part is
+     * interpreted as a decimal integer. For decimal floating constants,
+     * the exponent indicates the power of 10 by which the significand
+     * part is to be scaled. For hexadecimal floating constants, the
+     * exponent indicates the power of 2 by which the significand part is
+     * to be scaled.
+     *
+     * For decimal floating constants, and also for hexadecimal
+     * floating constants when FLT_RADIX is not a power of 2, the result
+     * is either the nearest representable value, or the larger or smaller
+     * representable value immediately adjacent to the nearest representable
+     * value, chosen in an implementation-defined manner. For hexadecimal
+     * floating constants when FLT_RADIX is a power of 2, the result is
+     * correctly rounded.
+     */
+    @Nonnull
+    private Token number()
+            throws IOException,
+            LexerException {
+        Token tok;
+        int c = read();
+        if (c == '0') {
+            int d = read();
+            if (d == 'x' || d == 'X') {
+                tok = number_hex((char) d);
+            } else {
+                unread(d);
+                unread(c);
+                tok = number_decimal();
+            }
+        } else if (Character.isDigit(c) || c == '.') {
+            unread(c);
+            tok = number_decimal();
+        } else {
+            throw new LexerException("Asked to parse something as a number which isn't: " + (char) c);
+        }
+        return tok;
+    }
+
+    @Nonnull
+    private Token identifier(int c)
+            throws IOException,
+            LexerException {
+        StringBuilder text = new StringBuilder();
+        int d;
+        text.append((char) c);
+        for (;;) {
+            d = read();
+            if (Character.isIdentifierIgnorable(d))
+				; else if (Character.isJavaIdentifierPart(d))
+                text.append((char) d);
+            else
+                break;
+        }
+        unread(d);
+        return new Token(IDENTIFIER, text.toString());
+    }
+
+    @Nonnull
+    private Token whitespace(int c)
+            throws IOException,
+            LexerException {
+        StringBuilder text = new StringBuilder();
+        int d;
+        text.append((char) c);
+        for (;;) {
+            d = read();
+            if (ppvalid && isLineSeparator(d))	/* XXX Ugly. */
+
+                break;
+            if (Character.isWhitespace(d))
+                text.append((char) d);
+            else
+                break;
+        }
+        unread(d);
+        return new Token(WHITESPACE, text.toString());
+    }
+
+    /* No token processed by cond() contains a newline. */
+    @Nonnull
+    private Token cond(char c, int yes, int no)
+            throws IOException,
+            LexerException {
+        int d = read();
+        if (c == d)
+            return new Token(yes);
+        unread(d);
+        return new Token(no);
+    }
+
+    @Override
+    public Token token()
+            throws IOException,
+            LexerException {
+        Token tok = null;
+
+        int _l = line;
+        int _c = column;
+
+        int c = read();
+        int d;
+
+        switch (c) {
+            case '\n':
+                if (ppvalid) {
+                    bol = true;
+                    if (include) {
+                        tok = new Token(NL, _l, _c, "\n");
+                    } else {
+                        int nls = 0;
+                        do {
+                            nls++;
+                            d = read();
+                        } while (d == '\n');
+                        unread(d);
+                        char[] text = new char[nls];
+                        for (int i = 0; i < text.length; i++)
+                            text[i] = '\n';
+                        // Skip the bol = false below.
+                        tok = new Token(NL, _l, _c, new String(text));
+                    }
+                    if (DEBUG)
+                        System.out.println("lx: Returning NL: " + tok);
+                    return tok;
+                }
+                /* Let it be handled as whitespace. */
+                break;
+
+            case '!':
+                tok = cond('=', NE, '!');
+                break;
+
+            case '#':
+                if (bol)
+                    tok = new Token(HASH);
+                else
+                    tok = cond('#', PASTE, '#');
+                break;
+
+            case '+':
+                d = read();
+                if (d == '+')
+                    tok = new Token(INC);
+                else if (d == '=')
+                    tok = new Token(PLUS_EQ);
+                else
+                    unread(d);
+                break;
+            case '-':
+                d = read();
+                if (d == '-')
+                    tok = new Token(DEC);
+                else if (d == '=')
+                    tok = new Token(SUB_EQ);
+                else if (d == '>')
+                    tok = new Token(ARROW);
+                else
+                    unread(d);
+                break;
+
+            case '*':
+                tok = cond('=', MULT_EQ, '*');
+                break;
+            case '/':
+                d = read();
+                if (d == '*')
+                    tok = ccomment();
+                else if (d == '/')
+                    tok = cppcomment();
+                else if (d == '=')
+                    tok = new Token(DIV_EQ);
+                else
+                    unread(d);
+                break;
+
+            case '%':
+                d = read();
+                if (d == '=')
+                    tok = new Token(MOD_EQ);
+                else if (digraphs && d == '>')
+                    tok = new Token('}');	// digraph
+                else if (digraphs && d == ':')
+                    PASTE:
+                    {
+                        d = read();
+                        if (d != '%') {
+                            unread(d);
+                            tok = new Token('#');	// digraph
+                            break PASTE;
+                        }
+                        d = read();
+                        if (d != ':') {
+                            unread(d);	// Unread 2 chars here.
+                            unread('%');
+                            tok = new Token('#');	// digraph
+                            break PASTE;
+                        }
+                        tok = new Token(PASTE);	// digraph
+                    }
+                else
+                    unread(d);
+                break;
+
+            case ':':
+                /* :: */
+                d = read();
+                if (digraphs && d == '>')
+                    tok = new Token(']');	// digraph
+                else
+                    unread(d);
+                break;
+
+            case '<':
+                if (include) {
+                    tok = string('<', '>');
+                } else {
+                    d = read();
+                    if (d == '=')
+                        tok = new Token(LE);
+                    else if (d == '<')
+                        tok = cond('=', LSH_EQ, LSH);
+                    else if (digraphs && d == ':')
+                        tok = new Token('[');	// digraph
+                    else if (digraphs && d == '%')
+                        tok = new Token('{');	// digraph
+                    else
+                        unread(d);
+                }
+                break;
+
+            case '=':
+                tok = cond('=', EQ, '=');
+                break;
+
+            case '>':
+                d = read();
+                if (d == '=')
+                    tok = new Token(GE);
+                else if (d == '>')
+                    tok = cond('=', RSH_EQ, RSH);
+                else
+                    unread(d);
+                break;
+
+            case '^':
+                tok = cond('=', XOR_EQ, '^');
+                break;
+
+            case '|':
+                d = read();
+                if (d == '=')
+                    tok = new Token(OR_EQ);
+                else if (d == '|')
+                    tok = cond('=', LOR_EQ, LOR);
+                else
+                    unread(d);
+                break;
+            case '&':
+                d = read();
+                if (d == '&')
+                    tok = cond('=', LAND_EQ, LAND);
+                else if (d == '=')
+                    tok = new Token(AND_EQ);
+                else
+                    unread(d);
+                break;
+
+            case '.':
+                d = read();
+                if (d == '.')
+                    tok = cond('.', ELLIPSIS, RANGE);
+                else
+                    unread(d);
+                if (Character.isDigit(d)) {
+                    unread('.');
+                    tok = number();
+                }
+                /* XXX decimal fraction */
+                break;
+
+            case '\'':
+                tok = string('\'', '\'');
+                break;
+
+            case '"':
+                tok = string('"', '"');
+                break;
+
+            case -1:
+                close();
+                tok = new Token(EOF, _l, _c, "<eof>");
+                break;
+        }
+
+        if (tok == null) {
+            if (Character.isWhitespace(c)) {
+                tok = whitespace(c);
+            } else if (Character.isDigit(c)) {
+                unread(c);
+                tok = number();
+            } else if (Character.isJavaIdentifierStart(c)) {
+                tok = identifier(c);
+            } else {
+                tok = new Token(c);
+            }
+        }
+
+        if (bol) {
+            switch (tok.getType()) {
+                case WHITESPACE:
+                case CCOMMENT:
+                    break;
+                default:
+                    bol = false;
+                    break;
+            }
+        }
+
+        tok.setLocation(_l, _c);
+        if (DEBUG)
+            System.out.println("lx: Returning " + tok);
+        // (new Exception("here")).printStackTrace(System.out);
+        return tok;
+    }
+
+    @Override
+    public void close()
+            throws IOException {
+        if (reader != null) {
+            reader.close();
+            reader = null;
+        }
+        super.close();
+    }
+
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Macro.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Macro.java
new file mode 100644
index 0000000..3029252
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Macro.java
@@ -0,0 +1,212 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A macro object.
+ *
+ * This encapsulates a name, an argument count, and a token stream
+ * for replacement. The replacement token stream may contain the
+ * extra tokens {@link Token#M_ARG} and {@link Token#M_STRING}.
+ */
+public class Macro {
+
+    private final Source source;
+    private final String name;
+    /* It's an explicit decision to keep these around here. We don't
+     * need to; the argument token type is M_ARG and the value
+     * is the index. The strings themselves are only used in
+     * stringification of the macro, for debugging. */
+    private List<String> args;
+    private boolean variadic;
+    private boolean hasPaste;
+    private List<Token> tokens;
+
+    public Macro(final Source source, final String name) {
+        this.source = source;
+        this.name = name;
+        this.args = null;
+        this.variadic = false;
+        this.hasPaste = false;
+        this.tokens = new ArrayList<Token>();
+    }
+    public Macro(final Macro o) {
+        this(o, o.tokens, true);
+    }
+    public Macro(final Macro o, final List<Token> tokens) {
+        this(o, tokens, false);
+    }
+    private Macro(final Macro o, final List<Token> tokens, final boolean copyTokens) {
+        this.source = o.source;
+        this.name = o.name;
+        if(null != o.args) {
+            this.args = new ArrayList<String>(o.args);
+        } else {
+            this.args = null;
+        }
+        this.variadic = o.variadic;
+        this.hasPaste = o.hasPaste;
+        if(null != tokens) {
+            this.tokens = copyTokens ? new ArrayList<Token>(tokens) : tokens;
+        } else {
+            this.tokens = new ArrayList<Token>();
+        }
+    }
+
+    public Macro(final String name) {
+        this(null, name);
+    }
+
+    /**
+     * Returns the Source from which this macro was parsed.
+     *
+     * This method may return null if the macro was not parsed
+     * from a regular file.
+     */
+    public Source getSource() {
+        return source;
+    }
+
+    /**
+     * Returns the name of this macro.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets the arguments to this macro.
+     */
+    /* pp */ void setArgs(final List<String> args) {
+        this.args = args;
+    }
+
+    /**
+     * Returns true if this is a function-like macro.
+     */
+    public boolean isFunctionLike() {
+        return args != null;
+    }
+
+    /**
+     * Returns the number of arguments to this macro.
+     */
+    public int getArgs() {
+        return args.size();
+    }
+
+    /**
+     * Sets the variadic flag on this Macro.
+     */
+    public void setVariadic(final boolean b) {
+        this.variadic = b;
+    }
+
+    /**
+     * Returns true if this is a variadic function-like macro.
+     */
+    public boolean isVariadic() {
+        return variadic;
+    }
+
+    /**
+     * Returns true if this macro contains a "paste" operator.
+     */
+    public boolean hasPaste() {
+        return hasPaste;
+    }
+
+    /**
+     * Adds a token to the expansion of this macro.
+     */
+    public void addToken(final Token tok) {
+        this.tokens.add(tok);
+    }
+
+    /**
+     * Adds a "paste" operator to the expansion of this macro.
+     *
+     * A paste operator causes the next token added to be pasted
+     * to the previous token when the macro is expanded.
+     * It is an error for a macro to end with a paste token.
+     */
+    public void addPaste(final Token tok) {
+        /*
+         * Given: tok0 ## tok1
+         * We generate: M_PASTE, tok0, tok1
+         * This extends as per a stack language:
+         * tok0 ## tok1 ## tok2 ->
+         *   M_PASTE, tok0, M_PASTE, tok1, tok2
+         */
+        this.tokens.add(tokens.size() - 1, tok);
+        this.hasPaste = true;
+    }
+
+    /* pp */ List<Token> getTokens() {
+        return tokens;
+    }
+
+    /* Paste tokens are inserted before the first of the two pasted
+     * tokens, so it's a kind of bytecode notation. This method
+     * swaps them around again. We know that there will never be two
+     * sequential paste tokens, so a boolean is sufficient. */
+    public String getText() {
+        final StringBuilder buf = new StringBuilder();
+        boolean paste = false;
+        for (final Token tok : tokens) {
+            if (tok.getType() == Token.M_PASTE) {
+                assert paste == false : "Two sequential pastes.";
+                paste = true;
+                continue;
+            } else {
+                buf.append(tok.getText());
+            }
+            if (paste) {
+                buf.append(" #" + "# ");
+                paste = false;
+            }
+            // buf.append(tokens.get(i));
+        }
+        return buf.toString();
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder buf = new StringBuilder(name);
+        if (args != null) {
+            buf.append('(');
+            final Iterator<String> it = args.iterator();
+            while (it.hasNext()) {
+                buf.append(it.next());
+                if (it.hasNext())
+                    buf.append(", ");
+                else if (isVariadic())
+                    buf.append("...");
+            }
+            buf.append(')');
+        }
+        if (!tokens.isEmpty()) {
+            buf.append(" => ").append(getText());
+        }
+        return buf.toString();
+    }
+
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/MacroTokenSource.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/MacroTokenSource.java
new file mode 100644
index 0000000..fbb2428
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/MacroTokenSource.java
@@ -0,0 +1,209 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import static com.jogamp.gluegen.jcpp.Token.*;
+
+/* This source should always be active, since we don't expand macros
+ * in any inactive context. */
+/* pp */ class MacroTokenSource extends Source {
+
+    private final Macro macro;
+    private final Iterator<Token> tokens;	/* Pointer into the macro.  */
+
+    private final List<Argument> args;	/* { unexpanded, expanded } */
+
+    private Iterator<Token> arg;	/* "current expansion" */
+
+    /* pp */ MacroTokenSource(@Nonnull Macro m, @Nonnull List<Argument> args) {
+        this.macro = m;
+        this.tokens = m.getTokens().iterator();
+        this.args = args;
+        this.arg = null;
+    }
+
+    @Override
+    /* pp */ boolean isExpanding(@Nonnull Macro m) {
+        /* When we are expanding an arg, 'this' macro is not
+         * being expanded, and thus we may re-expand it. */
+        if (/* XXX this.arg == null && */this.macro == m)
+            return true;
+        return super.isExpanding(m);
+    }
+
+    /* XXX Called from Preprocessor [ugly]. */
+    /* pp */ static void escape(@Nonnull StringBuilder buf, @Nonnull CharSequence cs) {
+        if (buf == null)
+            throw new NullPointerException("Buffer was null.");
+        if (cs == null)
+            throw new NullPointerException("CharSequence was null.");
+        for (int i = 0; i < cs.length(); i++) {
+            char c = cs.charAt(i);
+            switch (c) {
+                case '\\':
+                    buf.append("\\\\");
+                    break;
+                case '"':
+                    buf.append("\\\"");
+                    break;
+                case '\n':
+                    buf.append("\\n");
+                    break;
+                case '\r':
+                    buf.append("\\r");
+                    break;
+                default:
+                    buf.append(c);
+            }
+        }
+    }
+
+    private void concat(@Nonnull StringBuilder buf, @Nonnull Argument arg) {
+        for (Token tok : arg) {
+            buf.append(tok.getText());
+        }
+    }
+
+    @Nonnull
+    private Token stringify(@Nonnull Token pos, @Nonnull Argument arg) {
+        StringBuilder buf = new StringBuilder();
+        concat(buf, arg);
+        // System.out.println("Concat: " + arg + " -> " + buf);
+        StringBuilder str = new StringBuilder("\"");
+        escape(str, buf);
+        str.append("\"");
+        // System.out.println("Escape: " + buf + " -> " + str);
+        return new Token(STRING,
+                pos.getLine(), pos.getColumn(),
+                str.toString(), buf.toString());
+    }
+
+
+    /* At this point, we have consumed the first M_PASTE.
+     * @see Macro#addPaste(Token) */
+    private void paste(@Nonnull Token ptok)
+            throws IOException,
+            LexerException {
+        StringBuilder buf = new StringBuilder();
+        // Token err = null;
+        /* We know here that arg is null or expired,
+         * since we cannot paste an expanded arg. */
+
+        int count = 2;
+        for (int i = 0; i < count; i++) {
+            if (!tokens.hasNext()) {
+                /* XXX This one really should throw. */
+                error(ptok.getLine(), ptok.getColumn(),
+                        "Paste at end of expansion");
+                buf.append(' ').append(ptok.getText());
+                break;
+            }
+            Token tok = tokens.next();
+            // System.out.println("Paste " + tok);
+            switch (tok.getType()) {
+                case M_PASTE:
+                    /* One extra to paste, plus one because the
+                     * paste token didn't count. */
+                    count += 2;
+                    ptok = tok;
+                    break;
+                case M_ARG:
+                    int idx = ((Integer) tok.getValue()).intValue();
+                    concat(buf, args.get(idx));
+                    break;
+                /* XXX Test this. */
+                case CCOMMENT:
+                case CPPCOMMENT:
+                    break;
+                default:
+                    buf.append(tok.getText());
+                    break;
+            }
+        }
+
+        /* Push and re-lex. */
+        /*
+         StringBuilder		src = new StringBuilder();
+         escape(src, buf);
+         StringLexerSource	sl = new StringLexerSource(src.toString());
+         */
+        StringLexerSource sl = new StringLexerSource(buf.toString());
+
+        /* XXX Check that concatenation produces a valid token. */
+        arg = new SourceIterator(sl);
+    }
+
+    @Override
+    public Token token()
+            throws IOException,
+            LexerException {
+        for (;;) {
+            /* Deal with lexed tokens first. */
+
+            if (arg != null) {
+                if (arg.hasNext()) {
+                    Token tok = arg.next();
+                    /* XXX PASTE -> INVALID. */
+                    assert tok.getType() != M_PASTE :
+                            "Unexpected paste token";
+                    return tok;
+                }
+                arg = null;
+            }
+
+            if (!tokens.hasNext())
+                return new Token(EOF, -1, -1, "");	/* End of macro. */
+
+            Token tok = tokens.next();
+            int idx;
+            switch (tok.getType()) {
+                case M_STRING:
+                    /* Use the nonexpanded arg. */
+                    idx = ((Integer) tok.getValue()).intValue();
+                    return stringify(tok, args.get(idx));
+                case M_ARG:
+                    /* Expand the arg. */
+                    idx = ((Integer) tok.getValue()).intValue();
+                    // System.out.println("Pushing arg " + args.get(idx));
+                    arg = args.get(idx).expansion();
+                    break;
+                case M_PASTE:
+                    paste(tok);
+                    break;
+                default:
+                    return tok;
+            }
+        } /* for */
+
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder();
+        buf.append("expansion of ").append(macro.getName());
+        Source parent = getParent();
+        if (parent != null)
+            buf.append(" in ").append(String.valueOf(parent));
+        return buf.toString();
+    }
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/NumericValue.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/NumericValue.java
new file mode 100644
index 0000000..8e79fd3
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/NumericValue.java
@@ -0,0 +1,215 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import javax.annotation.CheckForNull;
+import javax.annotation.CheckForSigned;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+
+public class NumericValue extends Number {
+
+    public static final int F_UNSIGNED = 1;
+    public static final int F_INT = 2;
+    public static final int F_LONG = 4;
+    public static final int F_LONGLONG = 8;
+    public static final int F_FLOAT = 16;
+    public static final int F_DOUBLE = 32;
+
+    public static final int FF_SIZE = F_INT | F_LONG | F_LONGLONG | F_FLOAT | F_DOUBLE;
+
+    private final int base;
+    private final String integer;
+    private String fraction;
+    private int expbase = 0;
+    private String exponent;
+    private int flags;
+
+    public NumericValue(int base, String integer) {
+        this.base = base;
+        this.integer = integer;
+    }
+
+    @Nonnegative
+    public int getBase() {
+        return base;
+    }
+
+    @Nonnull
+    public String getIntegerPart() {
+        return integer;
+    }
+
+    @CheckForNull
+    public String getFractionalPart() {
+        return fraction;
+    }
+
+    /* pp */ void setFractionalPart(String fraction) {
+        this.fraction = fraction;
+    }
+
+    @CheckForSigned
+    public int getExponentBase() {
+        return expbase;
+    }
+
+    @CheckForNull
+    public String getExponent() {
+        return exponent;
+    }
+
+    /* pp */ void setExponent(int expbase, String exponent) {
+        this.expbase = expbase;
+        this.exponent = exponent;
+    }
+
+    public int getFlags() {
+        return flags;
+    }
+
+    /* pp */ void setFlags(int flags) {
+        this.flags = flags;
+    }
+
+    /**
+     * So, it turns out that parsing arbitrary bases into arbitrary
+     * precision numbers is nontrivial, and this routine gets it wrong
+     * in many important cases.
+     */
+    @Nonnull
+    public BigDecimal toBigDecimal() {
+        int scale = 0;
+        String text = getIntegerPart();
+        String t_fraction = getFractionalPart();
+        if (t_fraction != null) {
+            text += getFractionalPart();
+            // XXX Wrong for anything but base 10.
+            scale += t_fraction.length();
+        }
+        String t_exponent = getExponent();
+        if (t_exponent != null)
+            scale -= Integer.parseInt(t_exponent);
+        BigInteger unscaled = new BigInteger(text, getBase());
+        return new BigDecimal(unscaled, scale);
+    }
+
+    @Nonnull
+    public Number toJavaLangNumber() {
+        int flags = getFlags();
+        if ((flags & F_DOUBLE) != 0)
+            return doubleValue();
+        else if ((flags & F_FLOAT) != 0)
+            return floatValue();
+        else if ((flags & (F_LONG | F_LONGLONG)) != 0)
+            return longValue();
+        else if ((flags & F_INT) != 0)
+            return intValue();
+        else if (getFractionalPart() != null)
+            return doubleValue();	// .1 is a double in Java.
+        else if (getExponent() != null)
+            return doubleValue();
+        else
+            return intValue();
+    }
+
+    private int exponentValue() {
+        return Integer.parseInt(exponent, 10);
+    }
+
+    @Override
+    public int intValue() {
+        int v = integer.isEmpty() ? 0 : Integer.parseInt(integer, base);
+        if (expbase == 2)
+            v = v << exponentValue();
+        else if (expbase != 0)
+            v = (int) (v * Math.pow(expbase, exponentValue()));
+        return v;
+    }
+
+    @Override
+    public long longValue() {
+        long v = integer.isEmpty() ? 0 : Long.parseLong(integer, base);
+        if (expbase == 2)
+            v = v << exponentValue();
+        else if (expbase != 0)
+            v = (long) (v * Math.pow(expbase, exponentValue()));
+        return v;
+    }
+
+    @Override
+    public float floatValue() {
+        if (getBase() != 10)
+            return longValue();
+        return Float.parseFloat(toString());
+    }
+
+    @Override
+    public double doubleValue() {
+        if (getBase() != 10)
+            return longValue();
+        return Double.parseDouble(toString());
+    }
+
+    private boolean appendFlags(StringBuilder buf, String suffix, int flag) {
+        if ((getFlags() & flag) != flag)
+            return false;
+        buf.append(suffix);
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder();
+        switch (base) {
+            case 8:
+                buf.append('0');
+                break;
+            case 10:
+                break;
+            case 16:
+                buf.append("0x");
+                break;
+            case 2:
+                buf.append('b');
+                break;
+            default:
+                buf.append("[base-").append(base).append("]");
+                break;
+        }
+        buf.append(getIntegerPart());
+        if (getFractionalPart() != null)
+            buf.append('.').append(getFractionalPart());
+        if (getExponent() != null) {
+            buf.append(base > 10 ? 'p' : 'e');
+            buf.append(getExponent());
+        }
+        /*
+         if (appendFlags(buf, "ui", F_UNSIGNED | F_INT));
+         else if (appendFlags(buf, "ul", F_UNSIGNED | F_LONG));
+         else if (appendFlags(buf, "ull", F_UNSIGNED | F_LONGLONG));
+         else if (appendFlags(buf, "i", F_INT));
+         else if (appendFlags(buf, "l", F_LONG));
+         else if (appendFlags(buf, "ll", F_LONGLONG));
+         else if (appendFlags(buf, "f", F_FLOAT));
+         else if (appendFlags(buf, "d", F_DOUBLE));
+         */
+        return buf.toString();
+    }
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Preprocessor.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Preprocessor.java
new file mode 100644
index 0000000..3208b0e
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Preprocessor.java
@@ -0,0 +1,2177 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+import java.util.TreeMap;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+import static com.jogamp.gluegen.jcpp.PreprocessorCommand.*;
+import static com.jogamp.gluegen.jcpp.Token.*;
+
+import com.jogamp.gluegen.Logging;
+import com.jogamp.gluegen.Logging.LoggerIf;
+import com.jogamp.gluegen.jcpp.PreprocessorListener.SourceChangeEvent;
+
+/**
+ * A C Preprocessor.
+ * The Preprocessor outputs a token stream which does not need
+ * re-lexing for C or C++. Alternatively, the output text may be
+ * reconstructed by concatenating the {@link Token#getText() text}
+ * values of the returned {@link Token Tokens}. (See
+ * {@link CppReader}, which does this.)
+ */
+/*
+ * Source file name and line number information is conveyed by lines of the form
+ *
+ * # linenum filename flags
+ *
+ * These are called linemarkers. They are inserted as needed into
+ * the output (but never within a string or character constant). They
+ * mean that the following line originated in file filename at line
+ * linenum. filename will never contain any non-printing characters;
+ * they are replaced with octal escape sequences.
+ *
+ * After the file name comes zero or more flags, which are `1', `2',
+ * `3', or `4'. If there are multiple flags, spaces separate them. Here
+ * is what the flags mean:
+ *
+ * `1'
+ * This indicates the start of a new file.
+ * `2'
+ * This indicates returning to a file (after having included another
+ * file).
+ * `3'
+ * This indicates that the following text comes from a system header
+ * file, so certain warnings should be suppressed.
+ * `4'
+ * This indicates that the following text should be treated as being
+ * wrapped in an implicit extern "C" block.
+ */
+public class Preprocessor implements Closeable {
+
+    private final LoggerIf LOG;
+
+    private static final Source INTERNAL = new Source() {
+        @Override
+        public Token token()
+                throws IOException,
+                LexerException {
+            throw new LexerException("Cannot read from " + getName());
+        }
+
+        @Override
+        public String getPath() {
+            return "<internal-data>";
+        }
+
+        @Override
+        public String getName() {
+            return "internal data";
+        }
+    };
+    private static final Macro __LINE__ = new Macro(INTERNAL, "__LINE__");
+    private static final Macro __FILE__ = new Macro(INTERNAL, "__FILE__");
+    private static final Macro __COUNTER__ = new Macro(INTERNAL, "__COUNTER__");
+
+    private final List<Source> inputs;
+
+    /* The fundamental engine. */
+    private final Map<String, Macro> macros;
+    private final Stack<State> states;
+    private Source source;
+
+    /* Miscellaneous support. */
+    private int counter;
+    private final Set<String> onceseenpaths = new HashSet<String>();
+    private final List<VirtualFile> includes = new ArrayList<VirtualFile>();
+
+    /* Support junk to make it work like cpp */
+    private List<String> quoteincludepath;	/* -iquote */
+
+    private List<String> sysincludepath;		/* -I */
+
+    private List<String> frameworkspath;
+    private final Set<Feature> features;
+    private final Set<Warning> warnings;
+    private VirtualFileSystem filesystem;
+    private PreprocessorListener listener;
+
+    public Preprocessor() {
+        LOG = Logging.getLogger(Preprocessor.class);
+        this.inputs = new ArrayList<Source>();
+
+        this.macros = new HashMap<String, Macro>();
+        macros.put(__LINE__.getName(), __LINE__);
+        macros.put(__FILE__.getName(), __FILE__);
+        macros.put(__COUNTER__.getName(), __COUNTER__);
+        this.states = new Stack<State>();
+        states.push(new State());
+        this.source = null;
+
+        this.counter = 0;
+
+        this.quoteincludepath = new ArrayList<String>();
+        this.sysincludepath = new ArrayList<String>();
+        this.frameworkspath = new ArrayList<String>();
+        this.features = EnumSet.noneOf(Feature.class);
+        this.warnings = EnumSet.noneOf(Warning.class);
+        this.filesystem = new JavaFileSystem();
+        this.listener = null;
+    }
+
+    public Preprocessor(@Nonnull final Source initial) {
+        this();
+        addInput(initial);
+    }
+
+    /** Equivalent to
+     * 'new Preprocessor(new {@link FileLexerSource}(file))'
+     */
+    public Preprocessor(@Nonnull final File file)
+            throws IOException {
+        this(new FileLexerSource(file));
+    }
+
+    /**
+     * Sets the VirtualFileSystem used by this Preprocessor.
+     */
+    public void setFileSystem(@Nonnull final VirtualFileSystem filesystem) {
+        this.filesystem = filesystem;
+    }
+
+    /**
+     * Returns the VirtualFileSystem used by this Preprocessor.
+     */
+    @Nonnull
+    public VirtualFileSystem getFileSystem() {
+        return filesystem;
+    }
+
+    /**
+     * Sets the PreprocessorListener which handles events for
+     * this Preprocessor.
+     *
+     * The listener is notified of warnings, errors and source
+     * changes, amongst other things.
+     */
+    public void setListener(@Nonnull final PreprocessorListener listener) {
+        this.listener = listener;
+        Source s = source;
+        while (s != null) {
+            // s.setListener(listener);
+            s.init(this);
+            s = s.getParent();
+        }
+    }
+
+    /**
+     * Returns the PreprocessorListener which handles events for
+     * this Preprocessor.
+     */
+    @Nonnull
+    public PreprocessorListener getListener() {
+        return listener;
+    }
+
+    /**
+     * Returns the feature-set for this Preprocessor.
+     *
+     * This set may be freely modified by user code.
+     */
+    @Nonnull
+    public Set<Feature> getFeatures() {
+        return features;
+    }
+
+    /**
+     * Adds a feature to the feature-set of this Preprocessor.
+     */
+    public void addFeature(@Nonnull final Feature f) {
+        features.add(f);
+    }
+
+    /**
+     * Adds features to the feature-set of this Preprocessor.
+     */
+    public void addFeatures(@Nonnull final Collection<Feature> f) {
+        features.addAll(f);
+    }
+
+    /**
+     * Adds features to the feature-set of this Preprocessor.
+     */
+    public void addFeatures(final Feature... f) {
+        addFeatures(Arrays.asList(f));
+    }
+
+    /**
+     * Returns true if the given feature is in
+     * the feature-set of this Preprocessor.
+     */
+    public boolean getFeature(@Nonnull final Feature f) {
+        return features.contains(f);
+    }
+
+    /**
+     * Returns the warning-set for this Preprocessor.
+     *
+     * This set may be freely modified by user code.
+     */
+    @Nonnull
+    public Set<Warning> getWarnings() {
+        return warnings;
+    }
+
+    /**
+     * Adds a warning to the warning-set of this Preprocessor.
+     */
+    public void addWarning(@Nonnull final Warning w) {
+        warnings.add(w);
+    }
+
+    /**
+     * Adds warnings to the warning-set of this Preprocessor.
+     */
+    public void addWarnings(@Nonnull final Collection<Warning> w) {
+        warnings.addAll(w);
+    }
+
+    /**
+     * Returns true if the given warning is in
+     * the warning-set of this Preprocessor.
+     */
+    public boolean getWarning(@Nonnull final Warning w) {
+        return warnings.contains(w);
+    }
+
+    /**
+     * Adds input for the Preprocessor.
+     *
+     * Inputs are processed in the order in which they are added.
+     */
+    public void addInput(@Nonnull final Source source) {
+        source.init(this);
+        inputs.add(source);
+    }
+
+    /**
+     * Adds input for the Preprocessor.
+     *
+     * @see #addInput(Source)
+     */
+    public void addInput(@Nonnull final File file)
+            throws IOException {
+        addInput(new FileLexerSource(file));
+    }
+
+    /**
+     * Handles an error.
+     *
+     * If a PreprocessorListener is installed, it receives the
+     * error. Otherwise, an exception is thrown.
+     */
+    protected void error(final int line, final int column, @Nonnull final String msg)
+            throws LexerException {
+        if (listener != null)
+            listener.handleError(source, line, column, msg);
+        else
+            throw new LexerException("Error at " + line + ":" + column + ": " + msg);
+    }
+
+    /**
+     * Handles an error.
+     *
+     * If a PreprocessorListener is installed, it receives the
+     * error. Otherwise, an exception is thrown.
+     *
+     * @see #error(int, int, String)
+     */
+    protected void error(@Nonnull final Token tok, @Nonnull final String msg)
+            throws LexerException {
+        error(tok.getLine(), tok.getColumn(), msg);
+    }
+
+    /**
+     * Handles a warning.
+     *
+     * If a PreprocessorListener is installed, it receives the
+     * warning. Otherwise, an exception is thrown.
+     */
+    protected void warning(final int line, final int column, @Nonnull final String msg)
+            throws LexerException {
+        if (warnings.contains(Warning.ERROR))
+            error(line, column, msg);
+        else if (listener != null)
+            listener.handleWarning(source, line, column, msg);
+        else
+            throw new LexerException("Warning at " + line + ":" + column + ": " + msg);
+    }
+
+    /**
+     * Handles a warning.
+     *
+     * If a PreprocessorListener is installed, it receives the
+     * warning. Otherwise, an exception is thrown.
+     *
+     * @see #warning(int, int, String)
+     */
+    protected void warning(@Nonnull final Token tok, @Nonnull final String msg)
+            throws LexerException {
+        warning(tok.getLine(), tok.getColumn(), msg);
+    }
+
+    /**
+     * Adds a Macro to this Preprocessor.
+     *
+     * The given {@link Macro} object encapsulates both the name
+     * and the expansion.
+     * @throws IOException
+     */
+    public void addMacro(@Nonnull final Macro m) throws LexerException, IOException {
+        // System.out.println("Macro " + m);
+        final String name = m.getName();
+        /* Already handled as a source error in macro(). */
+        if ("defined".equals(name)) {
+            throw new LexerException("Cannot redefine name 'defined'");
+        }
+        macros.put(m.getName(), m);
+    }
+
+    /**
+     * Defines the given name as a macro.
+     *
+     * The String value is lexed into a token stream, which is
+     * used as the macro expansion.
+     */
+    public void addMacro(@Nonnull final String name, @Nonnull final String value)
+            throws LexerException {
+        try {
+            final Macro m = new Macro(name);
+            final StringLexerSource s = new StringLexerSource(value);
+            try {
+                for (;;) {
+                    final Token tok = s.token();
+                    if (tok.getType() == EOF)
+                        break;
+                    m.addToken(tok);
+                }
+            } finally {
+                s.close();
+            }
+            addMacro(m);
+        } catch (final IOException e) {
+            throw new LexerException(e);
+        }
+    }
+
+    /**
+     * Defines the given name as a macro, with the value <code>1</code>.
+     *
+     * This is a convnience method, and is equivalent to
+     * <code>addMacro(name, "1")</code>.
+     */
+    public void addMacro(@Nonnull final String name)
+            throws LexerException {
+        addMacro(name, "1");
+    }
+
+    /**
+     * Sets the user include path used by this Preprocessor.
+     */
+    /* Note for future: Create an IncludeHandler? */
+    public void setQuoteIncludePath(@Nonnull final List<String> path) {
+        this.quoteincludepath = path;
+    }
+
+    /**
+     * Returns the user include-path of this Preprocessor.
+     *
+     * This list may be freely modified by user code.
+     */
+    @Nonnull
+    public List<String> getQuoteIncludePath() {
+        return quoteincludepath;
+    }
+
+    /**
+     * Sets the system include path used by this Preprocessor.
+     */
+    /* Note for future: Create an IncludeHandler? */
+    public void setSystemIncludePath(@Nonnull final List<String> path) {
+        this.sysincludepath = path;
+    }
+
+    /**
+     * Returns the system include-path of this Preprocessor.
+     *
+     * This list may be freely modified by user code.
+     */
+    @Nonnull
+    public List<String> getSystemIncludePath() {
+        return sysincludepath;
+    }
+
+    /**
+     * Sets the Objective-C frameworks path used by this Preprocessor.
+     */
+    /* Note for future: Create an IncludeHandler? */
+    public void setFrameworksPath(@Nonnull final List<String> path) {
+        this.frameworkspath = path;
+    }
+
+    /**
+     * Returns the Objective-C frameworks path used by this
+     * Preprocessor.
+     *
+     * This list may be freely modified by user code.
+     */
+    @Nonnull
+    public List<String> getFrameworksPath() {
+        return frameworkspath;
+    }
+
+    /**
+     * Returns the Map of Macros parsed during the run of this
+     * Preprocessor.
+     */
+    @Nonnull
+    public Map<String, Macro> getMacros() {
+        return macros;
+    }
+
+    /**
+     * Returns a list of {@link Macro}s.
+     * <p>
+     * Implementation returns a new list of copy-ctor {@link Macro}s.
+     * </p>
+     * @param expand if {@code true} and if macro is not {@link Macro#isFunctionLike() function-like},
+     *               i.e. a constant, the returned macro will be expanded.
+     * @throws IOException
+     * @throws LexerException
+     */
+    public List<Macro> getMacros(final boolean expand) throws IOException, LexerException {
+        final List<Macro> res = new ArrayList<Macro>();
+        final Collection<Macro> macroList = macros.values();
+        for(final Macro m : macroList) {
+            if( expand && !m.isFunctionLike() ) {
+                res.add( new Macro( m, expand( m.getTokens() ) ) );
+            } else {
+                res.add( new Macro( m ) );
+            }
+        }
+        return res;
+    }
+
+    /**
+     * Returns the named macro.
+     *
+     * While you can modify the returned object, unexpected things
+     * might happen if you do.
+     */
+    @CheckForNull
+    public Macro getMacro(final String name) {
+        return macros.get(name);
+    }
+
+    /**
+     * Returns the list of {@link VirtualFile VirtualFiles} which have been
+     * included by this Preprocessor.
+     *
+     * This does not include any {@link Source} provided to the constructor
+     * or {@link #addInput(java.io.File)} or {@link #addInput(Source)}.
+     */
+    @Nonnull
+    public List<? extends VirtualFile> getIncludes() {
+        return includes;
+    }
+
+    /* States */
+    private void push_state() {
+        final State top = states.peek();
+        states.push(new State(top));
+    }
+
+    private void pop_state()
+            throws LexerException {
+        final State s = states.pop();
+        if (states.isEmpty()) {
+            error(0, 0, "#" + "endif without #" + "if");
+            states.push(s);
+        }
+    }
+
+    private boolean isActive() {
+        final State state = states.peek();
+        return state.isParentActive() && state.isActive();
+    }
+
+
+    /* Sources */
+    /**
+     * Returns the top Source on the input stack.
+     *
+     * @see Source
+     * @see #push_source(Source,boolean)
+     * @see #pop_source()
+     */
+    // @CheckForNull
+    public Source getSource() {
+        return source;
+    }
+
+    /**
+     * Pushes a Source onto the input stack.
+     *
+     * @see #getSource()
+     * @see #pop_source()
+     */
+    protected void push_source(@Nonnull final Source source, final boolean autopop) {
+        source.init(this);
+        source.setParent(this.source, autopop);
+        // source.setListener(listener);
+        if (listener != null)
+            listener.handleSourceChange(this.source, SourceChangeEvent.SUSPEND);
+        this.source = source;
+        if (listener != null)
+            listener.handleSourceChange(this.source, SourceChangeEvent.PUSH);
+    }
+
+    /**
+     * Pops a Source from the input stack.
+     *
+     * @see #getSource()
+     * @see #push_source(Source,boolean)
+     */
+    @CheckForNull
+    protected Token pop_source(final boolean linemarker)
+            throws IOException {
+        if (listener != null)
+            listener.handleSourceChange(this.source, SourceChangeEvent.POP);
+        final Source s = this.source;
+        this.source = s.getParent();
+        /* Always a noop unless called externally. */
+        s.close();
+        if (listener != null && this.source != null)
+            listener.handleSourceChange(this.source, SourceChangeEvent.RESUME);
+
+        final Source t = getSource();
+        if (getFeature(Feature.LINEMARKERS)
+                && s.isNumbered()
+                && t != null) {
+            /* We actually want 'did the nested source
+             * contain a newline token', which isNumbered()
+             * approximates. This is not perfect, but works.
+             * FIXME: Removed the '+ 1', since all lines were off by one.
+             * This solves this case, but I don't know _why_ this was here in the first place.
+             */
+            return line_token(t.getLine() /* SEE ABOVE: + 1 */, t.getName(), " 2");
+        }
+
+        return null;
+    }
+
+    protected void pop_source()
+            throws IOException {
+        pop_source(false);
+    }
+
+    @Nonnull
+    private Token next_source() {
+        if (inputs.isEmpty())
+            return new Token(EOF);
+        final Source s = inputs.remove(0);
+        push_source(s, true);
+        return line_token(s.getLine(), s.getName(), " 1");
+    }
+
+    /* Source tokens */
+    private Token source_token;
+
+    /* XXX Make this include the NL, and make all cpp directives eat
+     * their own NL. */
+    @Nonnull
+    private Token line_token(final int line, @CheckForNull final String name, @Nonnull final String extra) {
+        final StringBuilder buf = new StringBuilder();
+        buf.append("#line ").append(line)
+                .append(" \"");
+        /* XXX This call to escape(name) is correct but ugly. */
+        if (name == null)
+            buf.append("<no file>");
+        else
+            MacroTokenSource.escape(buf, name);
+        buf.append("\"").append(extra).append("\n");
+        return new Token(P_LINE, line, 0, buf.toString(), null);
+    }
+
+    @Nonnull
+    private Token source_token()
+            throws IOException,
+            LexerException {
+        if (source_token != null) {
+            final Token tok = source_token;
+            source_token = null;
+            if (getFeature(Feature.DEBUG))
+                LOG.debug("Returning unget token " + tok);
+            return tok;
+        }
+
+        for (;;) {
+            final Source s = getSource();
+            if (s == null) {
+                final Token t = next_source();
+                if (t.getType() == P_LINE && !getFeature(Feature.LINEMARKERS))
+                    continue;
+                return t;
+            }
+            final Token tok = s.token();
+            /* XXX Refactor with skipline() */
+            if (tok.getType() == EOF && s.isAutopop()) {
+                // System.out.println("Autopop " + s);
+                final Token mark = pop_source(true);
+                if (mark != null)
+                    return mark;
+                continue;
+            }
+            if (getFeature(Feature.DEBUG))
+                LOG.debug("Returning fresh token " + tok);
+            return tok;
+        }
+    }
+
+    private void source_untoken(final Token tok) {
+        if (this.source_token != null)
+            throw new IllegalStateException("Cannot return two tokens");
+        this.source_token = tok;
+    }
+
+    private boolean isWhite(final Token tok) {
+        final int type = tok.getType();
+        return (type == WHITESPACE)
+                || (type == CCOMMENT)
+                || (type == CPPCOMMENT);
+    }
+
+    private Token source_token_nonwhite()
+            throws IOException,
+            LexerException {
+        Token tok;
+        do {
+            tok = source_token();
+        } while (isWhite(tok));
+        return tok;
+    }
+
+    /**
+     * Returns an NL or an EOF token.
+     *
+     * The metadata on the token will be correct, which is better
+     * than generating a new one.
+     *
+     * This method can, as of recent patches, return a P_LINE token.
+     */
+    private Token source_skipline(final boolean white)
+            throws IOException,
+            LexerException {
+        // (new Exception("skipping line")).printStackTrace(System.out);
+        final Source s = getSource();
+        final Token tok = s.skipline(white);
+        /* XXX Refactor with source_token() */
+        if (tok.getType() == EOF && s.isAutopop()) {
+            // System.out.println("Autopop " + s);
+            final Token mark = pop_source(true);
+            if (mark != null)
+                return mark;
+        }
+        return tok;
+    }
+
+    /* processes and expands a macro. */
+    private boolean macro(final Macro m, final Token orig)
+            throws IOException,
+            LexerException {
+        Token tok;
+        List<Argument> args;
+
+        // System.out.println("pp: expanding " + m);
+        if (m.isFunctionLike()) {
+            OPEN:
+            for (;;) {
+                tok = source_token();
+                // System.out.println("pp: open: token is " + tok);
+                switch (tok.getType()) {
+                    case WHITESPACE:	/* XXX Really? */
+
+                    case CCOMMENT:
+                    case CPPCOMMENT:
+                    case NL:
+                        break;	/* continue */
+
+                    case '(':
+                        break OPEN;
+                    default:
+                        source_untoken(tok);
+                        return false;
+                }
+            }
+
+            // tok = expanded_token_nonwhite();
+            tok = source_token_nonwhite();
+
+            /* We either have, or we should have args.
+             * This deals elegantly with the case that we have
+             * one empty arg. */
+            if (tok.getType() != ')' || m.getArgs() > 0) {
+                args = new ArrayList<Argument>();
+
+                Argument arg = new Argument();
+                int depth = 0;
+                boolean space = false;
+
+                ARGS:
+                for (;;) {
+                    // System.out.println("pp: arg: token is " + tok);
+                    switch (tok.getType()) {
+                        case EOF:
+                            error(tok, "EOF in macro args");
+                            return false;
+
+                        case ',':
+                            if (depth == 0) {
+                                if (m.isVariadic()
+                                        && /* We are building the last arg. */ args.size() == m.getArgs() - 1) {
+                                    /* Just add the comma. */
+                                    arg.addToken(tok);
+                                } else {
+                                    args.add(arg);
+                                    arg = new Argument();
+                                }
+                            } else {
+                                arg.addToken(tok);
+                            }
+                            space = false;
+                            break;
+                        case ')':
+                            if (depth == 0) {
+                                args.add(arg);
+                                break ARGS;
+                            } else {
+                                depth--;
+                                arg.addToken(tok);
+                            }
+                            space = false;
+                            break;
+                        case '(':
+                            depth++;
+                            arg.addToken(tok);
+                            space = false;
+                            break;
+
+                        case WHITESPACE:
+                        case CCOMMENT:
+                        case CPPCOMMENT:
+                        case NL:
+                            /* Avoid duplicating spaces. */
+                            space = true;
+                            break;
+
+                        default:
+                            /* Do not put space on the beginning of
+                             * an argument token. */
+                            if (space && !arg.isEmpty())
+                                arg.addToken(Token.space);
+                            arg.addToken(tok);
+                            space = false;
+                            break;
+
+                    }
+                    // tok = expanded_token();
+                    tok = source_token();
+                }
+                /* space may still be true here, thus trailing space
+                 * is stripped from arguments. */
+
+                if (args.size() != m.getArgs()) {
+                    if (m.isVariadic()) {
+                        if (args.size() == m.getArgs() - 1) {
+                            args.add(new Argument());
+                        } else {
+                            error(tok,
+                                    "variadic macro " + m.getName()
+                                    + " has at least " + (m.getArgs() - 1) + " parameters "
+                                    + "but given " + args.size() + " args");
+                            return false;
+                        }
+                    } else {
+                        error(tok,
+                                "macro " + m.getName()
+                                + " has " + m.getArgs() + " parameters "
+                                + "but given " + args.size() + " args");
+                        /* We could replay the arg tokens, but I
+                         * note that GNU cpp does exactly what we do,
+                         * i.e. output the macro name and chew the args.
+                         */
+                        return false;
+                    }
+                }
+
+                for (final Argument a : args) {
+                    a.expand(this);
+                }
+
+                // System.out.println("Macro " + m + " args " + args);
+            } else {
+                /* nargs == 0 and we (correctly) got () */
+                args = null;
+            }
+
+        } else {
+            /* Macro without args. */
+            args = null;
+        }
+
+        if (m == __LINE__) {
+            push_source(new FixedTokenSource(
+                    new Token[]{new Token(NUMBER,
+                                orig.getLine(), orig.getColumn(),
+                                Integer.toString(orig.getLine()),
+                                new NumericValue(10, Integer.toString(orig.getLine())))}
+            ), true);
+        } else if (m == __FILE__) {
+            final StringBuilder buf = new StringBuilder("\"");
+            String name = getSource().getName();
+            if (name == null)
+                name = "<no file>";
+            for (int i = 0; i < name.length(); i++) {
+                final char c = name.charAt(i);
+                switch (c) {
+                    case '\\':
+                        buf.append("\\\\");
+                        break;
+                    case '"':
+                        buf.append("\\\"");
+                        break;
+                    default:
+                        buf.append(c);
+                        break;
+                }
+            }
+            buf.append("\"");
+            final String text = buf.toString();
+            push_source(new FixedTokenSource(
+                    new Token[]{new Token(STRING,
+                                orig.getLine(), orig.getColumn(),
+                                text, text)}
+            ), true);
+        } else if (m == __COUNTER__) {
+            /* This could equivalently have been done by adding
+             * a special Macro subclass which overrides getTokens(). */
+            final int value = this.counter++;
+            push_source(new FixedTokenSource(
+                    new Token[]{new Token(NUMBER,
+                                orig.getLine(), orig.getColumn(),
+                                Integer.toString(value),
+                                new NumericValue(10, Integer.toString(value)))}
+            ), true);
+        } else {
+            push_source(new MacroTokenSource(m, args), true);
+        }
+
+        return true;
+    }
+
+    /**
+     * Expands an argument.
+     */
+    /* I'd rather this were done lazily, but doing so breaks spec. */
+    @Nonnull
+    /* pp */ List<Token> expand(@Nonnull final List<Token> arg)
+            throws IOException,
+            LexerException {
+        final List<Token> expansion = new ArrayList<Token>();
+        boolean space = false;
+
+        push_source(new FixedTokenSource(arg), false);
+
+        EXPANSION:
+        for (;;) {
+            final Token tok = expanded_token();
+            switch (tok.getType()) {
+                case EOF:
+                    break EXPANSION;
+
+                case WHITESPACE:
+                case CCOMMENT:
+                case CPPCOMMENT:
+                    space = true;
+                    break;
+
+                default:
+                    if (space && !expansion.isEmpty())
+                        expansion.add(Token.space);
+                    expansion.add(tok);
+                    space = false;
+                    break;
+            }
+        }
+
+        // Always returns null.
+        pop_source(false);
+
+        return expansion;
+    }
+
+    /* processes a #define directive */
+    private Token define()
+            throws IOException,
+            LexerException {
+        Token tok = source_token_nonwhite();
+        if (tok.getType() != IDENTIFIER) {
+            error(tok, "Expected identifier");
+            return source_skipline(false);
+        }
+        /* if predefined */
+        final String name = tok.getText();
+        if ("defined".equals(name)) {
+            error(tok, "Cannot redefine name 'defined'");
+            return source_skipline(false);
+        }
+
+        final Macro m = new Macro(getSource(), name);
+        List<String> args;
+
+        tok = source_token();
+        if (tok.getType() == '(') {
+            tok = source_token_nonwhite();
+            if (tok.getType() != ')') {
+                args = new ArrayList<String>();
+                ARGS:
+                for (;;) {
+                    switch (tok.getType()) {
+                        case IDENTIFIER:
+                            args.add(tok.getText());
+                            break;
+                        case ELLIPSIS:
+                            // Unnamed Variadic macro
+                            args.add("__VA_ARGS__");
+                            // We just named the ellipsis, but we unget the token
+                            // to allow the ELLIPSIS handling below to process it.
+                            source_untoken(tok);
+                            break;
+                        case NL:
+                        case EOF:
+                            error(tok,
+                                    "Unterminated macro parameter list");
+                            return tok;
+                        default:
+                            error(tok,
+                                    "error in macro parameters: "
+                                    + tok.getText());
+                            return source_skipline(false);
+                    }
+                    tok = source_token_nonwhite();
+                    switch (tok.getType()) {
+                        case ',':
+                            break;
+                        case ELLIPSIS:
+                            tok = source_token_nonwhite();
+                            if (tok.getType() != ')')
+                                error(tok,
+                                        "ellipsis must be on last argument");
+                            m.setVariadic(true);
+                            break ARGS;
+                        case ')':
+                            break ARGS;
+
+                        case NL:
+                        case EOF:
+                            /* Do not skip line. */
+                            error(tok,
+                                    "Unterminated macro parameters");
+                            return tok;
+                        default:
+                            error(tok,
+                                    "Bad token in macro parameters: "
+                                    + tok.getText());
+                            return source_skipline(false);
+                    }
+                    tok = source_token_nonwhite();
+                }
+            } else {
+                assert tok.getType() == ')' : "Expected ')'";
+                args = Collections.emptyList();
+            }
+
+            m.setArgs(args);
+        } else {
+            /* For searching. */
+            args = Collections.emptyList();
+            source_untoken(tok);
+        }
+
+        /* Get an expansion for the macro, using indexOf. */
+        boolean space = false;
+        boolean paste = false;
+        int idx;
+
+        /* Ensure no space at start. */
+        tok = source_token_nonwhite();
+        EXPANSION:
+        for (;;) {
+            switch (tok.getType()) {
+                case EOF:
+                    break EXPANSION;
+                case NL:
+                    break EXPANSION;
+
+                case CCOMMENT:
+                case CPPCOMMENT:
+                /* XXX This is where we implement GNU's cpp -CC. */
+                // break;
+                case WHITESPACE:
+                    if (!paste)
+                        space = true;
+                    break;
+
+                /* Paste. */
+                case PASTE:
+                    space = false;
+                    paste = true;
+                    m.addPaste(new Token(M_PASTE,
+                            tok.getLine(), tok.getColumn(),
+                            "#" + "#", null));
+                    break;
+
+                /* Stringify. */
+                case '#':
+                    if (space)
+                        m.addToken(Token.space);
+                    space = false;
+                    final Token la = source_token_nonwhite();
+                    if (la.getType() == IDENTIFIER
+                            && ((idx = args.indexOf(la.getText())) != -1)) {
+                        m.addToken(new Token(M_STRING,
+                                la.getLine(), la.getColumn(),
+                                "#" + la.getText(),
+                                Integer.valueOf(idx)));
+                    } else {
+                        m.addToken(tok);
+                        /* Allow for special processing. */
+                        source_untoken(la);
+                    }
+                    break;
+
+                case IDENTIFIER:
+                    if (space)
+                        m.addToken(Token.space);
+                    space = false;
+                    paste = false;
+                    idx = args.indexOf(tok.getText());
+                    if (idx == -1)
+                        m.addToken(tok);
+                    else
+                        m.addToken(new Token(M_ARG,
+                                tok.getLine(), tok.getColumn(),
+                                tok.getText(),
+                                Integer.valueOf(idx)));
+                    break;
+
+                default:
+                    if (space)
+                        m.addToken(Token.space);
+                    space = false;
+                    paste = false;
+                    m.addToken(tok);
+                    break;
+            }
+            tok = source_token();
+        }
+
+        if (getFeature(Feature.DEBUG)) {
+            LOG.debug("Defined macro " + m);
+        }
+        addMacro(m);
+
+        return tok;	/* NL or EOF. */
+    }
+
+    @Nonnull
+    private Token undef()
+            throws IOException,
+            LexerException {
+        final Token tok = source_token_nonwhite();
+        if (tok.getType() != IDENTIFIER) {
+            error(tok,
+                    "Expected identifier, not " + tok.getText());
+            if (tok.getType() == NL || tok.getType() == EOF)
+                return tok;
+        } else {
+            final Macro m = getMacro(tok.getText());
+            if (m != null) {
+                /* XXX error if predefined */
+                macros.remove(m.getName());
+            }
+        }
+        return source_skipline(true);
+    }
+
+    /**
+     * Attempts to include the given file.
+     *
+     * User code may override this method to implement a virtual
+     * file system.
+     */
+    protected boolean include(@Nonnull final VirtualFile file)
+            throws IOException,
+            LexerException {
+        // System.out.println("Try to include " + ((File)file).getAbsolutePath());
+        if (!file.isFile())
+            return false;
+        if (getFeature(Feature.DEBUG))
+            LOG.debug("pp: including " + file);
+        includes.add(file);
+        push_source(file.getSource(), true);
+        return true;
+    }
+
+    /**
+     * Includes a file from an include path, by name.
+     */
+    protected boolean include(@Nonnull final Iterable<String> path, @Nonnull final String name)
+            throws IOException,
+            LexerException {
+        for (final String dir : path) {
+            final VirtualFile file = getFileSystem().getFile(dir, name);
+            if (include(file))
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Handles an include directive.
+     */
+    private void include(
+            @CheckForNull final String parent, final int line,
+            @Nonnull final String name, final boolean quoted, final boolean next)
+            throws IOException,
+            LexerException {
+        if (name.startsWith("/")) {
+            final VirtualFile file = filesystem.getFile(name);
+            if (include(file))
+                return;
+            final StringBuilder buf = new StringBuilder();
+            buf.append("File not found: ").append(name);
+            error(line, 0, buf.toString());
+            return;
+        }
+
+        VirtualFile pdir = null;
+        if (quoted) {
+            if (parent != null) {
+                final VirtualFile pfile = filesystem.getFile(parent);
+                pdir = pfile.getParentFile();
+            }
+            if (pdir != null) {
+                final VirtualFile ifile = pdir.getChildFile(name);
+                if (include(ifile))
+                    return;
+            }
+            if (include(quoteincludepath, name))
+                return;
+        } else {
+            final int idx = name.indexOf('/');
+            if (idx != -1) {
+                final String frameworkName = name.substring(0, idx);
+                final String headerName = name.substring(idx + 1);
+                final String headerPath = frameworkName + ".framework/Headers/" + headerName;
+                if (include(frameworkspath, headerPath))
+                    return;
+            }
+        }
+
+        if (include(sysincludepath, name))
+            return;
+
+        final StringBuilder buf = new StringBuilder();
+        buf.append("File not found: ").append(name);
+        buf.append(" in");
+        if (quoted) {
+            buf.append(" .").append('(').append(pdir).append(')');
+            for (final String dir : quoteincludepath)
+                buf.append(" ").append(dir);
+        }
+        for (final String dir : sysincludepath)
+            buf.append(" ").append(dir);
+        error(line, 0, buf.toString());
+    }
+
+    @Nonnull
+    private Token include(final boolean next)
+            throws IOException,
+            LexerException {
+        final LexerSource lexer = (LexerSource) source;
+        try {
+            lexer.setInclude(true);
+            Token tok = token_nonwhite();
+
+            String name;
+            boolean quoted;
+
+            if (tok.getType() == STRING) {
+                /* XXX Use the original text, not the value.
+                 * Backslashes must not be treated as escapes here. */
+                final StringBuilder buf = new StringBuilder((String) tok.getValue());
+                HEADER:
+                for (;;) {
+                    tok = token_nonwhite();
+                    switch (tok.getType()) {
+                        case STRING:
+                            buf.append((String) tok.getValue());
+                            break;
+                        case NL:
+                        case EOF:
+                            break HEADER;
+                        default:
+                            warning(tok,
+                                    "Unexpected token on #" + "include line");
+                            return source_skipline(false);
+                    }
+                }
+                name = buf.toString();
+                quoted = true;
+            } else if (tok.getType() == HEADER) {
+                name = (String) tok.getValue();
+                quoted = false;
+                tok = source_skipline(true);
+            } else {
+                error(tok,
+                        "Expected string or header, not " + tok.getText());
+                switch (tok.getType()) {
+                    case NL:
+                    case EOF:
+                        return tok;
+                    default:
+                        /* Only if not a NL or EOF already. */
+                        return source_skipline(false);
+                }
+            }
+
+            /* Do the inclusion. */
+            include(source.getPath(), tok.getLine(), name, quoted, next);
+
+            /* 'tok' is the 'nl' after the include. We use it after the
+             * #line directive. */
+            if (getFeature(Feature.LINEMARKERS))
+                return line_token(1, source.getName(), " 1");
+            return tok;
+        } finally {
+            lexer.setInclude(false);
+        }
+    }
+
+    protected void pragma_once(@Nonnull final Token name)
+            throws IOException, LexerException {
+        final Source s = this.source;
+        if (!onceseenpaths.add(s.getPath())) {
+            final Token mark = pop_source(true);
+            // FixedTokenSource should never generate a linemarker on exit.
+            if (mark != null)
+                push_source(new FixedTokenSource(Arrays.asList(mark)), true);
+        }
+    }
+
+    protected void pragma(@Nonnull final Token name, @Nonnull final List<Token> value)
+            throws IOException,
+            LexerException {
+        if (getFeature(Feature.PRAGMA_ONCE)) {
+            if ("once".equals(name.getText())) {
+                pragma_once(name);
+                return;
+            }
+        }
+        warning(name, "Unknown #" + "pragma: " + name.getText());
+    }
+
+    @Nonnull
+    private Token pragma()
+            throws IOException,
+            LexerException {
+        Token name;
+
+        NAME:
+        for (;;) {
+            final Token tok = token();
+            switch (tok.getType()) {
+                case EOF:
+                    /* There ought to be a newline before EOF.
+                     * At least, in any skipline context. */
+                    /* XXX Are we sure about this? */
+                    warning(tok,
+                            "End of file in #" + "pragma");
+                    return tok;
+                case NL:
+                    /* This may contain one or more newlines. */
+                    warning(tok,
+                            "Empty #" + "pragma");
+                    return tok;
+                case CCOMMENT:
+                case CPPCOMMENT:
+                case WHITESPACE:
+                    continue NAME;
+                case IDENTIFIER:
+                    name = tok;
+                    break NAME;
+                default:
+                    return source_skipline(false);
+            }
+        }
+
+        Token tok;
+        final List<Token> value = new ArrayList<Token>();
+        VALUE:
+        for (;;) {
+            tok = token();
+            switch (tok.getType()) {
+                case EOF:
+                    /* There ought to be a newline before EOF.
+                     * At least, in any skipline context. */
+                    /* XXX Are we sure about this? */
+                    warning(tok,
+                            "End of file in #" + "pragma");
+                    break VALUE;
+                case NL:
+                    /* This may contain one or more newlines. */
+                    break VALUE;
+                case CCOMMENT:
+                case CPPCOMMENT:
+                    break;
+                case WHITESPACE:
+                    value.add(tok);
+                    break;
+                default:
+                    value.add(tok);
+                    break;
+            }
+        }
+
+        pragma(name, value);
+
+        return tok;	/* The NL. */
+
+    }
+
+    /* For #error and #warning. */
+    private void error(@Nonnull final Token pptok, final boolean is_error)
+            throws IOException,
+            LexerException {
+        final StringBuilder buf = new StringBuilder();
+        buf.append('#').append(pptok.getText()).append(' ');
+        /* Peculiar construction to ditch first whitespace. */
+        Token tok = source_token_nonwhite();
+        ERROR:
+        for (;;) {
+            switch (tok.getType()) {
+                case NL:
+                case EOF:
+                    break ERROR;
+                default:
+                    buf.append(tok.getText());
+                    break;
+            }
+            tok = source_token();
+        }
+        if (is_error)
+            error(pptok, buf.toString());
+        else
+            warning(pptok, buf.toString());
+    }
+
+    /* This bypasses token() for #elif expressions.
+     * If we don't do this, then isActive() == false
+     * causes token() to simply chew the entire input line. */
+    @Nonnull
+    private Token expanded_token()
+            throws IOException,
+            LexerException {
+        for (;;) {
+            final Token tok = source_token();
+            // System.out.println("Source token is " + tok);
+            if (tok.getType() == IDENTIFIER) {
+                final Macro m = getMacro(tok.getText());
+                if (m == null)
+                    return tok;
+                if (source.isExpanding(m))
+                    return tok;
+                if (macro(m, tok))
+                    continue;
+            }
+            return tok;
+        }
+    }
+
+    @Nonnull
+    private Token expanded_token_nonwhite()
+            throws IOException,
+            LexerException {
+        Token tok;
+        do {
+            tok = expanded_token();
+            // System.out.println("expanded token is " + tok);
+        } while (isWhite(tok));
+        return tok;
+    }
+
+    @CheckForNull
+    private Token expr_token = null;
+
+    @Nonnull
+    private Token expr_token()
+            throws IOException,
+            LexerException {
+        Token tok = expr_token;
+
+        if (tok != null) {
+            // System.out.println("ungetting");
+            expr_token = null;
+        } else {
+            tok = expanded_token_nonwhite();
+            // System.out.println("expt is " + tok);
+
+            if (tok.getType() == IDENTIFIER
+                    && tok.getText().equals("defined")) {
+                Token la = source_token_nonwhite();
+                boolean paren = false;
+                if (la.getType() == '(') {
+                    paren = true;
+                    la = source_token_nonwhite();
+                }
+
+                // System.out.println("Core token is " + la);
+                if (la.getType() != IDENTIFIER) {
+                    error(la,
+                            "defined() needs identifier, not "
+                            + la.getText());
+                    tok = new Token(NUMBER,
+                            la.getLine(), la.getColumn(),
+                            "0", new NumericValue(10, "0"));
+                } else if (macros.containsKey(la.getText())) {
+                    // System.out.println("Found macro");
+                    tok = new Token(NUMBER,
+                            la.getLine(), la.getColumn(),
+                            "1", new NumericValue(10, "1"));
+                } else {
+                    // System.out.println("Not found macro");
+                    tok = new Token(NUMBER,
+                            la.getLine(), la.getColumn(),
+                            "0", new NumericValue(10, "0"));
+                }
+
+                if (paren) {
+                    la = source_token_nonwhite();
+                    if (la.getType() != ')') {
+                        expr_untoken(la);
+                        error(la, "Missing ) in defined(). Got " + la.getText());
+                    }
+                }
+            }
+        }
+
+        // System.out.println("expr_token returns " + tok);
+        return tok;
+    }
+
+    private void expr_untoken(@Nonnull final Token tok)
+            throws LexerException {
+        if (expr_token != null)
+            throw new InternalException(
+                    "Cannot unget two expression tokens."
+            );
+        expr_token = tok;
+    }
+
+    private int expr_priority(@Nonnull final Token op) {
+        switch (op.getType()) {
+            case '/':
+                return 11;
+            case '%':
+                return 11;
+            case '*':
+                return 11;
+            case '+':
+                return 10;
+            case '-':
+                return 10;
+            case LSH:
+                return 9;
+            case RSH:
+                return 9;
+            case '<':
+                return 8;
+            case '>':
+                return 8;
+            case LE:
+                return 8;
+            case GE:
+                return 8;
+            case EQ:
+                return 7;
+            case NE:
+                return 7;
+            case '&':
+                return 6;
+            case '^':
+                return 5;
+            case '|':
+                return 4;
+            case LAND:
+                return 3;
+            case LOR:
+                return 2;
+            case '?':
+                return 1;
+            default:
+                // System.out.println("Unrecognised operator " + op);
+                return 0;
+        }
+    }
+
+    private long expr(final int priority)
+            throws IOException,
+            LexerException {
+        /*
+         * (new Exception("expr(" + priority + ") called")).printStackTrace();
+         */
+
+        Token tok = expr_token();
+        long lhs, rhs;
+
+        // System.out.println("Expr lhs token is " + tok);
+        switch (tok.getType()) {
+            case '(':
+                lhs = expr(0);
+                tok = expr_token();
+                if (tok.getType() != ')') {
+                    expr_untoken(tok);
+                    error(tok, "Missing ) in expression. Got " + tok.getText());
+                    return 0;
+                }
+                break;
+
+            case '~':
+                lhs = ~expr(11);
+                break;
+            case '!':
+                lhs = expr(11) == 0 ? 1 : 0;
+                break;
+            case '-':
+                lhs = -expr(11);
+                break;
+            case NUMBER:
+                final NumericValue value = (NumericValue) tok.getValue();
+                lhs = value.longValue();
+                break;
+            case CHARACTER:
+                lhs = ((Character) tok.getValue()).charValue();
+                break;
+            case IDENTIFIER:
+                if (warnings.contains(Warning.UNDEF))
+                    warning(tok, "Undefined token '" + tok.getText()
+                            + "' encountered in conditional.");
+                lhs = 0;
+                break;
+
+            default:
+                expr_untoken(tok);
+                error(tok,
+                        "Bad token in expression: " + tok.getText());
+                return 0;
+        }
+
+        EXPR:
+        for (;;) {
+            // System.out.println("expr: lhs is " + lhs + ", pri = " + priority);
+            final Token op = expr_token();
+            final int pri = expr_priority(op);	/* 0 if not a binop. */
+
+            if (pri == 0 || priority >= pri) {
+                expr_untoken(op);
+                break EXPR;
+            }
+            rhs = expr(pri);
+            // System.out.println("rhs token is " + rhs);
+            switch (op.getType()) {
+                case '/':
+                    if (rhs == 0) {
+                        error(op, "Division by zero");
+                        lhs = 0;
+                    } else {
+                        lhs = lhs / rhs;
+                    }
+                    break;
+                case '%':
+                    if (rhs == 0) {
+                        error(op, "Modulus by zero");
+                        lhs = 0;
+                    } else {
+                        lhs = lhs % rhs;
+                    }
+                    break;
+                case '*':
+                    lhs = lhs * rhs;
+                    break;
+                case '+':
+                    lhs = lhs + rhs;
+                    break;
+                case '-':
+                    lhs = lhs - rhs;
+                    break;
+                case '<':
+                    lhs = lhs < rhs ? 1 : 0;
+                    break;
+                case '>':
+                    lhs = lhs > rhs ? 1 : 0;
+                    break;
+                case '&':
+                    lhs = lhs & rhs;
+                    break;
+                case '^':
+                    lhs = lhs ^ rhs;
+                    break;
+                case '|':
+                    lhs = lhs | rhs;
+                    break;
+
+                case LSH:
+                    lhs = lhs << rhs;
+                    break;
+                case RSH:
+                    lhs = lhs >> rhs;
+                    break;
+                case LE:
+                    lhs = lhs <= rhs ? 1 : 0;
+                    break;
+                case GE:
+                    lhs = lhs >= rhs ? 1 : 0;
+                    break;
+                case EQ:
+                    lhs = lhs == rhs ? 1 : 0;
+                    break;
+                case NE:
+                    lhs = lhs != rhs ? 1 : 0;
+                    break;
+                case LAND:
+                    lhs = (lhs != 0) && (rhs != 0) ? 1 : 0;
+                    break;
+                case LOR:
+                    lhs = (lhs != 0) || (rhs != 0) ? 1 : 0;
+                    break;
+
+                case '?': {
+                    tok = expr_token();
+                    if (tok.getType() != ':') {
+                        expr_untoken(tok);
+                        error(tok, "Missing : in conditional expression. Got " + tok.getText());
+                        return 0;
+                    }
+                    final long falseResult = expr(0);
+                    lhs = (lhs != 0) ? rhs : falseResult;
+                }
+                break;
+
+                default:
+                    error(op,
+                            "Unexpected operator " + op.getText());
+                    return 0;
+
+            }
+        }
+
+        /*
+         * (new Exception("expr returning " + lhs)).printStackTrace();
+         */
+        // System.out.println("expr returning " + lhs);
+        return lhs;
+    }
+
+    @Nonnull
+    private Token toWhitespace(@Nonnull final Token tok) {
+        final String text = tok.getText();
+        final int len = text.length();
+        boolean cr = false;
+        int nls = 0;
+
+        for (int i = 0; i < len; i++) {
+            final char c = text.charAt(i);
+
+            switch (c) {
+                case '\r':
+                    cr = true;
+                    nls++;
+                    break;
+                case '\n':
+                    if (cr) {
+                        cr = false;
+                        break;
+                    }
+                /* fallthrough */
+                case '\u2028':
+                case '\u2029':
+                case '\u000B':
+                case '\u000C':
+                case '\u0085':
+                    cr = false;
+                    nls++;
+                    break;
+            }
+        }
+
+        final char[] cbuf = new char[nls];
+        Arrays.fill(cbuf, '\n');
+        return new Token(WHITESPACE,
+                tok.getLine(), tok.getColumn(),
+                new String(cbuf));
+    }
+
+    @Nonnull
+    private Token _token()
+            throws IOException,
+            LexerException {
+
+        for (;;) {
+            Token tok;
+            if (!isActive()) {
+                final Source s = getSource();
+                if (s == null) {
+                    final Token t = next_source();
+                    if (t.getType() == P_LINE && !getFeature(Feature.LINEMARKERS))
+                        continue;
+                    return t;
+                }
+
+                try {
+                    /* XXX Tell lexer to ignore warnings. */
+                    s.setActive(false);
+                    tok = source_token();
+                } finally {
+                    /* XXX Tell lexer to stop ignoring warnings. */
+                    s.setActive(true);
+                }
+                switch (tok.getType()) {
+                    case HASH:
+                    case NL:
+                    case EOF:
+                        /* The preprocessor has to take action here. */
+                        break;
+                    case WHITESPACE:
+                        return tok;
+                    case CCOMMENT:
+                    case CPPCOMMENT:
+                        // Patch up to preserve whitespace.
+                        if (getFeature(Feature.KEEPALLCOMMENTS))
+                            return tok;
+                        if (!isActive())
+                            return toWhitespace(tok);
+                        if (getFeature(Feature.KEEPCOMMENTS))
+                            return tok;
+                        return toWhitespace(tok);
+                    default:
+                        // Return NL to preserve whitespace.
+						/* XXX This might lose a comment. */
+                        return source_skipline(false);
+                }
+            } else {
+                tok = source_token();
+            }
+
+            LEX:
+            switch (tok.getType()) {
+                case EOF:
+                    /* Pop the stacks. */
+                    return tok;
+
+                case WHITESPACE:
+                case NL:
+                    return tok;
+
+                case CCOMMENT:
+                case CPPCOMMENT:
+                    return tok;
+
+                case '!':
+                case '%':
+                case '&':
+                case '(':
+                case ')':
+                case '*':
+                case '+':
+                case ',':
+                case '-':
+                case '/':
+                case ':':
+                case ';':
+                case '<':
+                case '=':
+                case '>':
+                case '?':
+                case '[':
+                case ']':
+                case '^':
+                case '{':
+                case '|':
+                case '}':
+                case '~':
+                case '.':
+
+                /* From Olivier Chafik for Objective C? */
+                case '@':
+                /* The one remaining ASCII, might as well. */
+                case '`':
+
+                // case '#':
+                case AND_EQ:
+                case ARROW:
+                case CHARACTER:
+                case DEC:
+                case DIV_EQ:
+                case ELLIPSIS:
+                case EQ:
+                case GE:
+                case HEADER:	/* Should only arise from include() */
+
+                case INC:
+                case LAND:
+                case LE:
+                case LOR:
+                case LSH:
+                case LSH_EQ:
+                case SUB_EQ:
+                case MOD_EQ:
+                case MULT_EQ:
+                case NE:
+                case OR_EQ:
+                case PLUS_EQ:
+                case RANGE:
+                case RSH:
+                case RSH_EQ:
+                case STRING:
+                case SQSTRING:
+                case XOR_EQ:
+                    return tok;
+
+                case NUMBER:
+                    return tok;
+
+                case IDENTIFIER:
+                    final Macro m = getMacro(tok.getText());
+                    if (m == null)
+                        return tok;
+                    if (source.isExpanding(m))
+                        return tok;
+                    if (macro(m, tok))
+                        break;
+                    return tok;
+
+                case P_LINE:
+                    if (getFeature(Feature.LINEMARKERS))
+                        return tok;
+                    break;
+
+                case INVALID:
+                    if (getFeature(Feature.CSYNTAX))
+                        error(tok, String.valueOf(tok.getValue()));
+                    return tok;
+
+                default:
+                    throw new InternalException("Bad token " + tok);
+                // break;
+
+                case HASH:
+                    tok = source_token_nonwhite();
+                    // (new Exception("here")).printStackTrace();
+                    switch (tok.getType()) {
+                        case NL:
+                            break LEX;	/* Some code has #\n */
+
+                        case IDENTIFIER:
+                            break;
+                        default:
+                            error(tok,
+                                    "Preprocessor directive not a word "
+                                    + tok.getText());
+                            return source_skipline(false);
+                    }
+                    final PreprocessorCommand ppcmd = PreprocessorCommand.forText(tok.getText());
+                    if (ppcmd == null) {
+                        error(tok,
+                                "Unknown preprocessor directive "
+                                + tok.getText());
+                        return source_skipline(false);
+                    }
+
+                    PP:
+                    switch (ppcmd) {
+
+                        case PP_DEFINE:
+                            if (!isActive())
+                                return source_skipline(false);
+                            else
+                                return define();
+                        // break;
+
+                        case PP_UNDEF:
+                            if (!isActive())
+                                return source_skipline(false);
+                            else
+                                return undef();
+                        // break;
+
+                        case PP_INCLUDE:
+                            if (!isActive())
+                                return source_skipline(false);
+                            else
+                                return include(false);
+                        // break;
+                        case PP_INCLUDE_NEXT:
+                            if (!isActive())
+                                return source_skipline(false);
+                            if (!getFeature(Feature.INCLUDENEXT)) {
+                                error(tok,
+                                        "Directive include_next not enabled"
+                                );
+                                return source_skipline(false);
+                            }
+                            return include(true);
+                        // break;
+
+                        case PP_WARNING:
+                        case PP_ERROR:
+                            if (!isActive())
+                                return source_skipline(false);
+                            else
+                                error(tok, ppcmd == PP_ERROR);
+                            break;
+
+                        case PP_IF:
+                            push_state();
+                            if (!isActive()) {
+                                return source_skipline(false);
+                            }
+                            expr_token = null;
+                            states.peek().setActive(expr(0) != 0);
+                            tok = expr_token();	/* unget */
+
+                            if (tok.getType() == NL)
+                                return tok;
+                            return source_skipline(true);
+                        // break;
+
+                        case PP_ELIF:
+                            State state = states.peek();
+                            if (false) {
+                                /* Check for 'if' */;
+                            } else if (state.sawElse()) {
+                                error(tok,
+                                        "#elif after #" + "else");
+                                return source_skipline(false);
+                            } else if (!state.isParentActive()) {
+                                /* Nested in skipped 'if' */
+                                return source_skipline(false);
+                            } else if (state.isActive()) {
+                                /* The 'if' part got executed. */
+                                state.setParentActive(false);
+                                /* This is like # else # if but with
+                                 * only one # end. */
+                                state.setActive(false);
+                                return source_skipline(false);
+                            } else {
+                                expr_token = null;
+                                state.setActive(expr(0) != 0);
+                                tok = expr_token();	/* unget */
+
+                                if (tok.getType() == NL)
+                                    return tok;
+                                return source_skipline(true);
+                            }
+                        // break;
+
+                        case PP_ELSE:
+                            state = states.peek();
+                            if (false)
+								/* Check for 'if' */ ; else if (state.sawElse()) {
+                                error(tok,
+                                        "#" + "else after #" + "else");
+                                return source_skipline(false);
+                            } else {
+                                state.setSawElse();
+                                state.setActive(!state.isActive());
+                                return source_skipline(warnings.contains(Warning.ENDIF_LABELS));
+                            }
+                        // break;
+
+                        case PP_IFDEF:
+                            push_state();
+                            if (!isActive()) {
+                                return source_skipline(false);
+                            } else {
+                                tok = source_token_nonwhite();
+                                // System.out.println("ifdef " + tok);
+                                if (tok.getType() != IDENTIFIER) {
+                                    error(tok,
+                                            "Expected identifier, not "
+                                            + tok.getText());
+                                    return source_skipline(false);
+                                } else {
+                                    final String text = tok.getText();
+                                    final boolean exists
+                                            = macros.containsKey(text);
+                                    states.peek().setActive(exists);
+                                    return source_skipline(true);
+                                }
+                            }
+                        // break;
+
+                        case PP_IFNDEF:
+                            push_state();
+                            if (!isActive()) {
+                                return source_skipline(false);
+                            } else {
+                                tok = source_token_nonwhite();
+                                if (tok.getType() != IDENTIFIER) {
+                                    error(tok,
+                                            "Expected identifier, not "
+                                            + tok.getText());
+                                    return source_skipline(false);
+                                } else {
+                                    final String text = tok.getText();
+                                    final boolean exists
+                                            = macros.containsKey(text);
+                                    states.peek().setActive(!exists);
+                                    return source_skipline(true);
+                                }
+                            }
+                        // break;
+
+                        case PP_ENDIF:
+                            pop_state();
+                            return source_skipline(warnings.contains(Warning.ENDIF_LABELS));
+                        // break;
+
+                        case PP_LINE:
+                            return source_skipline(false);
+                        // break;
+
+                        case PP_PRAGMA:
+                            if (!isActive())
+                                return source_skipline(false);
+                            return pragma();
+                        // break;
+
+                        default:
+                            /* Actual unknown directives are
+                             * processed above. If we get here,
+                             * we succeeded the map lookup but
+                             * failed to handle it. Therefore,
+                             * this is (unconditionally?) fatal. */
+                            // if (isActive()) /* XXX Could be warning. */
+                            throw new InternalException(
+                                    "Internal error: Unknown directive "
+                                    + tok);
+                        // return source_skipline(false);
+                    }
+
+            }
+        }
+    }
+
+    @Nonnull
+    private Token token_nonwhite()
+            throws IOException,
+            LexerException {
+        Token tok;
+        do {
+            tok = _token();
+        } while (isWhite(tok));
+        return tok;
+    }
+
+    /**
+     * Returns the next preprocessor token.
+     *
+     * @see Token
+     * @throws LexerException if a preprocessing error occurs.
+     * @throws InternalException if an unexpected error condition arises.
+     */
+    @Nonnull
+    public Token token()
+            throws IOException,
+            LexerException {
+        final Token tok = _token();
+        if (getFeature(Feature.DEBUG))
+            LOG.debug("pp: Returning " + tok);
+        return tok;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder buf = new StringBuilder();
+
+        Source s = getSource();
+        while (s != null) {
+            buf.append(" -> ").append(String.valueOf(s)).append("\n");
+            s = s.getParent();
+        }
+
+        final Map<String, Macro> macros = new TreeMap<String, Macro>(getMacros());
+        for (final Macro macro : macros.values()) {
+            buf.append("#").append("macro ").append(macro).append("\n");
+        }
+
+        return buf.toString();
+    }
+
+    @Override
+    public void close()
+            throws IOException {
+        {
+            Source s = source;
+            while (s != null) {
+                s.close();
+                s = s.getParent();
+            }
+        }
+        for (final Source s : inputs) {
+            s.close();
+        }
+    }
+
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/PreprocessorCommand.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/PreprocessorCommand.java
new file mode 100644
index 0000000..a01a04b
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/PreprocessorCommand.java
@@ -0,0 +1,44 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ *
+ * @author shevek
+ */
+public enum PreprocessorCommand {
+
+    PP_DEFINE("define"),
+    PP_ELIF("elif"),
+    PP_ELSE("else"),
+    PP_ENDIF("endif"),
+    PP_ERROR("error"),
+    PP_IF("if"),
+    PP_IFDEF("ifdef"),
+    PP_IFNDEF("ifndef"),
+    PP_INCLUDE("include"),
+    PP_LINE("line"),
+    PP_PRAGMA("pragma"),
+    PP_UNDEF("undef"),
+    PP_WARNING("warning"),
+    PP_INCLUDE_NEXT("include_next"),
+    PP_IMPORT("import");
+    private final String text;
+    /* pp */ PreprocessorCommand(String text) {
+        this.text = text;
+    }
+
+    @CheckForNull
+    public static PreprocessorCommand forText(@Nonnull String text) {
+        for (PreprocessorCommand ppcmd : PreprocessorCommand.values())
+            if (ppcmd.text.equals(text))
+                return ppcmd;
+        return null;
+    }
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/PreprocessorListener.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/PreprocessorListener.java
new file mode 100644
index 0000000..1152a58
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/PreprocessorListener.java
@@ -0,0 +1,59 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A handler for preprocessor events, primarily errors and warnings.
+ *
+ * If no PreprocessorListener is installed in a Preprocessor, all
+ * error and warning events will throw an exception. Installing a
+ * listener allows more intelligent handling of these events.
+ */
+public interface PreprocessorListener {
+
+    /**
+     * Handles a warning.
+     *
+     * The behaviour of this method is defined by the
+     * implementation. It may simply record the error message, or
+     * it may throw an exception.
+     */
+    public void handleWarning(@Nonnull Source source, int line, int column,
+            @Nonnull String msg)
+            throws LexerException;
+
+    /**
+     * Handles an error.
+     *
+     * The behaviour of this method is defined by the
+     * implementation. It may simply record the error message, or
+     * it may throw an exception.
+     */
+    public void handleError(@Nonnull Source source, int line, int column,
+            @Nonnull String msg)
+            throws LexerException;
+
+    public enum SourceChangeEvent {
+
+        SUSPEND, PUSH, POP, RESUME;
+    }
+
+    public void handleSourceChange(@Nonnull Source source, @Nonnull SourceChangeEvent event);
+
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/ResourceFileSystem.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/ResourceFileSystem.java
new file mode 100644
index 0000000..438d9c1
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/ResourceFileSystem.java
@@ -0,0 +1,81 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import javax.annotation.Nonnull;
+
+/**
+ *
+ * @author shevek
+ */
+public class ResourceFileSystem implements VirtualFileSystem {
+
+    private final ClassLoader loader;
+
+    public ResourceFileSystem(@Nonnull ClassLoader loader) {
+        this.loader = loader;
+    }
+
+    @Override
+    public VirtualFile getFile(String path) {
+        return new ResourceFile(loader, path);
+    }
+
+    @Override
+    public VirtualFile getFile(String dir, String name) {
+        return getFile(dir + "/" + name);
+    }
+
+    private class ResourceFile implements VirtualFile {
+
+        private final ClassLoader loader;
+        private final String path;
+
+        public ResourceFile(ClassLoader loader, String path) {
+            this.loader = loader;
+            this.path = path;
+        }
+
+        @Override
+        public boolean isFile() {
+            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+        }
+
+        @Override
+        public String getPath() {
+            return path;
+        }
+
+        @Override
+        public String getName() {
+            return path.substring(path.lastIndexOf('/') + 1);
+        }
+
+        @Override
+        public ResourceFile getParentFile() {
+            int idx = path.lastIndexOf('/');
+            if (idx < 1)
+                return null;
+            return new ResourceFile(loader, path.substring(0, idx));
+        }
+
+        @Override
+        public ResourceFile getChildFile(String name) {
+            return new ResourceFile(loader, path + "/" + name);
+        }
+
+        @Override
+        public Source getSource() throws IOException {
+            InputStream stream = loader.getResourceAsStream(path);
+            BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
+            return new LexerSource(reader, true);
+        }
+    }
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Source.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Source.java
new file mode 100644
index 0000000..d56b5d7
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Source.java
@@ -0,0 +1,298 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Iterator;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+
+import static com.jogamp.gluegen.jcpp.Token.CCOMMENT;
+import static com.jogamp.gluegen.jcpp.Token.CPPCOMMENT;
+import static com.jogamp.gluegen.jcpp.Token.EOF;
+import static com.jogamp.gluegen.jcpp.Token.NL;
+import static com.jogamp.gluegen.jcpp.Token.WHITESPACE;
+
+/**
+ * An input to the Preprocessor.
+ *
+ * Inputs may come from Files, Strings or other sources. The
+ * preprocessor maintains a stack of Sources. Operations such as
+ * file inclusion or token pasting will push a new source onto
+ * the Preprocessor stack. Sources pop from the stack when they
+ * are exhausted; this may be transparent or explicit.
+ *
+ * BUG: Error messages are not handled properly.
+ */
+public abstract class Source implements Iterable<Token>, Closeable {
+
+    private Source parent;
+    private boolean autopop;
+    private PreprocessorListener listener;
+    private boolean active;
+    private boolean werror;
+
+    /* LineNumberReader */
+
+    /*
+     // We can't do this, since we would lose the LexerException
+     private class Itr implements Iterator {
+     private Token	next = null;
+     private void advance() {
+     try {
+     if (next != null)
+     next = token();
+     }
+     catch (IOException e) {
+     throw new UnsupportedOperationException(
+     "Failed to advance token iterator: " +
+     e.getMessage()
+     );
+     }
+     }
+     public boolean hasNext() {
+     return next.getType() != EOF;
+     }
+     public Token next() {
+     advance();
+     Token	t = next;
+     next = null;
+     return t;
+     }
+     public void remove() {
+     throw new UnsupportedOperationException(
+     "Cannot remove tokens from a Source."
+     );
+     }
+     }
+     */
+    public Source() {
+        this.parent = null;
+        this.autopop = false;
+        this.listener = null;
+        this.active = true;
+        this.werror = false;
+    }
+
+    /**
+     * Sets the parent source of this source.
+     *
+     * Sources form a singly linked list.
+     */
+    /* pp */ void setParent(final Source parent, final boolean autopop) {
+        this.parent = parent;
+        this.autopop = autopop;
+    }
+
+    /**
+     * Returns the parent source of this source.
+     *
+     * Sources form a singly linked list.
+     */
+    public final Source getParent() {
+        return parent;
+    }
+
+
+    // @OverrideMustInvoke
+	/* pp */ void init(final Preprocessor pp) {
+        setListener(pp.getListener());
+        this.werror = pp.getWarnings().contains(Warning.ERROR);
+    }
+
+    /**
+     * Sets the listener for this Source.
+     *
+     * Normally this is set by the Preprocessor when a Source is
+     * used, but if you are using a Source as a standalone object,
+     * you may wish to call this.
+     */
+    public void setListener(final PreprocessorListener pl) {
+        this.listener = pl;
+    }
+
+    /**
+     * Returns the File currently being lexed.
+     *
+     * If this Source is not a {@link FileLexerSource}, then
+     * it will ask the parent Source, and so forth recursively.
+     * If no Source on the stack is a FileLexerSource, returns null.
+     */
+    @CheckForNull
+    public String getPath() {
+        final Source parent = getParent();
+        if (parent != null)
+            return parent.getPath();
+        return null;
+    }
+
+    /**
+     * Returns the human-readable name of the current Source.
+     */
+    @CheckForNull
+    public String getName() {
+        final Source parent = getParent();
+        if (parent != null)
+            return parent.getName();
+        return null;
+    }
+
+    /**
+     * Returns the current line number within this Source.
+     */
+    @Nonnegative
+    public int getLine() {
+        final Source parent = getParent();
+        if (parent == null)
+            return 0;
+        return parent.getLine();
+    }
+
+    /**
+     * Returns the current column number within this Source.
+     */
+    public int getColumn() {
+        final Source parent = getParent();
+        if (parent == null)
+            return 0;
+        return parent.getColumn();
+    }
+
+    /**
+     * Returns true if this Source is expanding the given macro.
+     *
+     * This is used to prevent macro recursion.
+     */
+    /* pp */ boolean isExpanding(@Nonnull final Macro m) {
+        final Source parent = getParent();
+        if (parent != null)
+            return parent.isExpanding(m);
+        return false;
+    }
+
+    /**
+     * Returns true if this Source should be transparently popped
+     * from the input stack.
+     *
+     * Examples of such sources are macro expansions.
+     */
+    /* pp */ boolean isAutopop() {
+        return autopop;
+    }
+
+    /**
+     * Returns true if this source has line numbers.
+     */
+    /* pp */ boolean isNumbered() {
+        return false;
+    }
+
+    /* This is an incredibly lazy way of disabling warnings when
+     * the source is not active. */
+    /* pp */ void setActive(final boolean b) {
+        this.active = b;
+    }
+
+    /* pp */ boolean isActive() {
+        return active;
+    }
+
+    /**
+     * Returns the next Token parsed from this input stream.
+     *
+     * @see Token
+     */
+    @Nonnull
+    public abstract Token token()
+            throws IOException,
+            LexerException;
+
+    /**
+     * Returns a token iterator for this Source.
+     */
+    @Override
+    public Iterator<Token> iterator() {
+        return new SourceIterator(this);
+    }
+
+    /**
+     * Skips tokens until the end of line.
+     *
+     * @param white true if only whitespace is permitted on the
+     *	remainder of the line.
+     * @return the NL token.
+     */
+    @Nonnull
+    public Token skipline(final boolean white)
+            throws IOException,
+            LexerException {
+        for (;;) {
+            final Token tok = token();
+            switch (tok.getType()) {
+                case EOF:
+                    /* There ought to be a newline before EOF.
+                     * At least, in any skipline context. */
+                    /* XXX Are we sure about this? */
+                    warning(tok.getLine(), tok.getColumn(),
+                            "No newline before end of file");
+                    return new Token(NL,
+                            tok.getLine(), tok.getColumn(),
+                            "\n");
+                // return tok;
+                case NL:
+                    /* This may contain one or more newlines. */
+                    return tok;
+                case CCOMMENT:
+                case CPPCOMMENT:
+                case WHITESPACE:
+                    break;
+                default:
+                    /* XXX Check white, if required. */
+                    if (white)
+                        warning(tok.getLine(), tok.getColumn(),
+                                "Unexpected nonwhite token");
+                    break;
+            }
+        }
+    }
+
+    protected void error(final int line, final int column, final String msg)
+            throws LexerException {
+        if (listener != null)
+            listener.handleError(this, line, column, msg);
+        else
+            throw new LexerException("Error at " + line + ":" + column + ": " + msg);
+    }
+
+    protected void warning(final int line, final int column, final String msg)
+            throws LexerException {
+        if (werror)
+            error(line, column, msg);
+        else if (listener != null)
+            listener.handleWarning(this, line, column, msg);
+        else
+            throw new LexerException("Warning at " + line + ":" + column + ": " + msg);
+    }
+
+    public void close()
+            throws IOException {
+    }
+
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/SourceIterator.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/SourceIterator.java
new file mode 100644
index 0000000..4990512
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/SourceIterator.java
@@ -0,0 +1,88 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import static com.jogamp.gluegen.jcpp.Token.EOF;
+
+/**
+ * An Iterator for {@link Source Sources},
+ * returning {@link Token Tokens}.
+ */
+public class SourceIterator implements Iterator<Token> {
+
+    private final Source source;
+    private Token tok;
+
+    public SourceIterator(Source s) {
+        this.source = s;
+        this.tok = null;
+    }
+
+    /**
+     * Rethrows IOException inside IllegalStateException.
+     */
+    private void advance() {
+        try {
+            if (tok == null)
+                tok = source.token();
+        } catch (LexerException e) {
+            throw new IllegalStateException(e);
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    /**
+     * Returns true if the enclosed Source has more tokens.
+     *
+     * The EOF token is never returned by the iterator.
+     * @throws IllegalStateException if the Source
+     *		throws a LexerException or IOException
+     */
+    public boolean hasNext() {
+        advance();
+        return tok.getType() != EOF;
+    }
+
+    /**
+     * Returns the next token from the enclosed Source.
+     *
+     * The EOF token is never returned by the iterator.
+     * @throws IllegalStateException if the Source
+     *		throws a LexerException or IOException
+     */
+    public Token next() {
+        if (!hasNext())
+            throw new NoSuchElementException();
+        Token t = this.tok;
+        this.tok = null;
+        return t;
+    }
+
+    /**
+     * Not supported.
+     *
+     * @throws UnsupportedOperationException.
+     */
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/State.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/State.java
new file mode 100644
index 0000000..4d7f886
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/State.java
@@ -0,0 +1,68 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+/* pp */ class State {
+
+    boolean parent;
+    boolean active;
+    boolean sawElse;
+
+    /* pp */ State() {
+        this.parent = true;
+        this.active = true;
+        this.sawElse = false;
+    }
+
+    /* pp */ State(State parent) {
+        this.parent = parent.isParentActive() && parent.isActive();
+        this.active = true;
+        this.sawElse = false;
+    }
+
+    /* Required for #elif */
+    /* pp */ void setParentActive(boolean b) {
+        this.parent = b;
+    }
+
+    /* pp */ boolean isParentActive() {
+        return parent;
+    }
+
+    /* pp */ void setActive(boolean b) {
+        this.active = b;
+    }
+
+    /* pp */ boolean isActive() {
+        return active;
+    }
+
+    /* pp */ void setSawElse() {
+        sawElse = true;
+    }
+
+    /* pp */ boolean sawElse() {
+        return sawElse;
+    }
+
+    @Override
+    public String toString() {
+        return "parent=" + parent
+                + ", active=" + active
+                + ", sawelse=" + sawElse;
+    }
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/StringLexerSource.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/StringLexerSource.java
new file mode 100644
index 0000000..568bdca
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/StringLexerSource.java
@@ -0,0 +1,53 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.io.StringReader;
+
+/**
+ * A Source for lexing a String.
+ *
+ * This class is used by token pasting, but can be used by user
+ * code.
+ */
+public class StringLexerSource extends LexerSource {
+
+    /**
+     * Creates a new Source for lexing the given String.
+     *
+     * @param ppvalid true if preprocessor directives are to be
+     *	honoured within the string.
+     */
+    public StringLexerSource(String string, boolean ppvalid) {
+        super(new StringReader(string), ppvalid);
+    }
+
+    /**
+     * Creates a new Source for lexing the given String.
+     *
+     * By default, preprocessor directives are not honoured within
+     * the string.
+     */
+    public StringLexerSource(String string) {
+        this(string, false);
+    }
+
+    @Override
+    public String toString() {
+        return "string literal";
+    }
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Token.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Token.java
new file mode 100644
index 0000000..9c1794b
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Token.java
@@ -0,0 +1,193 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+/**
+ * A Preprocessor token.
+ *
+ * @see Preprocessor
+ */
+public final class Token {
+
+    // public static final int	EOF        = -1;
+    private final int type;
+    private int line;
+    private int column;
+    private final Object value;
+    private final String text;
+
+    public Token(int type, int line, int column,
+            String text, Object value) {
+        this.type = type;
+        this.line = line;
+        this.column = column;
+        this.text = text;
+        this.value = value;
+    }
+
+    public Token(int type, int line, int column, String text) {
+        this(type, line, column, text, null);
+    }
+
+    /* pp */ Token(int type, String text, Object value) {
+        this(type, -1, -1, text, value);
+    }
+
+    /* pp */ Token(int type, String text) {
+        this(type, text, null);
+    }
+
+    /* pp */ Token(int type) {
+        this(type, TokenType.getTokenText(type));
+    }
+
+    /**
+     * Returns the semantic type of this token.
+     */
+    public int getType() {
+        return type;
+    }
+
+    /* pp */ void setLocation(int line, int column) {
+        this.line = line;
+        this.column = column;
+    }
+
+    /**
+     * Returns the line at which this token started.
+     *
+     * Lines are numbered from zero.
+     */
+    public int getLine() {
+        return line;
+    }
+
+    /**
+     * Returns the column at which this token started.
+     *
+     * Columns are numbered from zero.
+     */
+    public int getColumn() {
+        return column;
+    }
+
+    /**
+     * Returns the original or generated text of this token.
+     *
+     * This is distinct from the semantic value of the token.
+     *
+     * @see #getValue()
+     */
+    public String getText() {
+        return text;
+    }
+
+    /**
+     * Returns the semantic value of this token.
+     *
+     * For strings, this is the parsed String.
+     * For integers, this is an Integer object.
+     * For other token types, as appropriate.
+     *
+     * @see #getText()
+     */
+    public Object getValue() {
+        return value;
+    }
+
+    /**
+     * Returns a description of this token, for debugging purposes.
+     */
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder();
+
+        buf.append('[').append(getTokenName(type));
+        if (line != -1) {
+            buf.append('@').append(line);
+            if (column != -1)
+                buf.append(',').append(column);
+        }
+        buf.append("]:");
+        if (text != null)
+            buf.append('"').append(text).append('"');
+        else if (type > 3 && type < 256)
+            buf.append((char) type);
+        else
+            buf.append('<').append(type).append('>');
+        if (value != null)
+            buf.append('=').append(value);
+        return buf.toString();
+    }
+
+    /**
+     * Returns the descriptive name of the given token type.
+     *
+     * This is mostly used for stringification and debugging.
+     */
+    public static String getTokenName(int type) {
+        return TokenType.getTokenName(type);
+    }
+
+    public static final int AND_EQ = 257;
+    public static final int ARROW = 258;
+    public static final int CHARACTER = 259;
+    public static final int CCOMMENT = 260;
+    public static final int CPPCOMMENT = 261;
+    public static final int DEC = 262;
+    public static final int DIV_EQ = 263;
+    public static final int ELLIPSIS = 264;
+    public static final int EOF = 265;
+    public static final int EQ = 266;
+    public static final int GE = 267;
+    public static final int HASH = 268;
+    public static final int HEADER = 269;
+    public static final int IDENTIFIER = 270;
+    public static final int INC = 271;
+    public static final int NUMBER = 272;
+    public static final int LAND = 273;
+    public static final int LAND_EQ = 274;
+    public static final int LE = 275;
+    public static final int LITERAL = 276;
+    public static final int LOR = 277;
+    public static final int LOR_EQ = 278;
+    public static final int LSH = 279;
+    public static final int LSH_EQ = 280;
+    public static final int MOD_EQ = 281;
+    public static final int MULT_EQ = 282;
+    public static final int NE = 283;
+    public static final int NL = 284;
+    public static final int OR_EQ = 285;
+    public static final int PASTE = 286;
+    public static final int PLUS_EQ = 287;
+    public static final int RANGE = 288;
+    public static final int RSH = 289;
+    public static final int RSH_EQ = 290;
+    public static final int SQSTRING = 291;
+    public static final int STRING = 292;
+    public static final int SUB_EQ = 293;
+    public static final int WHITESPACE = 294;
+    public static final int XOR_EQ = 295;
+    public static final int M_ARG = 296;
+    public static final int M_PASTE = 297;
+    public static final int M_STRING = 298;
+    public static final int P_LINE = 299;
+    public static final int INVALID = 300;
+
+    /** The position-less space token. */
+    /* pp */ static final Token space = new Token(WHITESPACE, -1, -1, " ");
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/TokenSnifferSource.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/TokenSnifferSource.java
new file mode 100644
index 0000000..cc60698
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/TokenSnifferSource.java
@@ -0,0 +1,46 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.io.IOException;
+import java.util.List;
+
+import static com.jogamp.gluegen.jcpp.Token.EOF;
+
+ at Deprecated
+/* pp */ class TokenSnifferSource extends Source {
+
+    private final List<Token> target;
+
+    /* pp */ TokenSnifferSource(List<Token> target) {
+        this.target = target;
+    }
+
+    public Token token()
+            throws IOException,
+            LexerException {
+        Token tok = getParent().token();
+        if (tok.getType() != EOF)
+            target.add(tok);
+        return tok;
+    }
+
+    @Override
+    public String toString() {
+        return getParent().toString();
+    }
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/TokenType.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/TokenType.java
new file mode 100644
index 0000000..e481bab
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/TokenType.java
@@ -0,0 +1,130 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+
+import static com.jogamp.gluegen.jcpp.Token.*;
+
+/**
+ *
+ * @author shevek
+ */
+/* pp */ class TokenType {
+
+    private static final List<TokenType> TYPES = new ArrayList<TokenType>();
+
+    private static void addTokenType(@Nonnegative int type, @Nonnull String name, @CheckForNull String text) {
+        while (TYPES.size() <= type)
+            TYPES.add(null);
+        TYPES.set(type, new TokenType(name, text));
+    }
+
+    private static void addTokenType(@Nonnegative int type, @Nonnull String name) {
+        addTokenType(type, name, null);
+    }
+
+    @CheckForNull
+    public static TokenType getTokenType(@Nonnegative int type) {
+        try {
+            return TYPES.get(type);
+        } catch (IndexOutOfBoundsException e) {
+            return null;
+        }
+    }
+
+    @Nonnull
+    public static String getTokenName(@Nonnegative int type) {
+        if (type < 0)
+            return "Invalid" + type;
+        TokenType tokenType = getTokenType(type);
+        if (tokenType == null)
+            return "Unknown" + type;
+        return tokenType.getName();
+    }
+
+    @CheckForNull
+    public static String getTokenText(@Nonnegative int type) {
+        TokenType tokenType = getTokenType(type);
+        if (tokenType == null)
+            return null;
+        return tokenType.getText();
+    }
+
+    static {
+        for (int i = 0; i < 255; i++) {
+            String text = String.valueOf((char) i);
+            addTokenType(i, text, text);
+        }
+        addTokenType(AND_EQ, "AND_EQ", "&=");
+        addTokenType(ARROW, "ARROW", "->");
+        addTokenType(CHARACTER, "CHARACTER");
+        addTokenType(CCOMMENT, "CCOMMENT");
+        addTokenType(CPPCOMMENT, "CPPCOMMENT");
+        addTokenType(DEC, "DEC", "--");
+        addTokenType(DIV_EQ, "DIV_EQ", "/=");
+        addTokenType(ELLIPSIS, "ELLIPSIS", "...");
+        addTokenType(EOF, "EOF");
+        addTokenType(EQ, "EQ", "==");
+        addTokenType(GE, "GE", ">=");
+        addTokenType(HASH, "HASH", "#");
+        addTokenType(HEADER, "HEADER");
+        addTokenType(IDENTIFIER, "IDENTIFIER");
+        addTokenType(INC, "INC", "++");
+        addTokenType(NUMBER, "NUMBER");
+        addTokenType(LAND, "LAND", "&&");
+        addTokenType(LAND_EQ, "LAND_EQ", "&&=");
+        addTokenType(LE, "LE", "<=");
+        addTokenType(LITERAL, "LITERAL");
+        addTokenType(LOR, "LOR", "||");
+        addTokenType(LOR_EQ, "LOR_EQ", "||=");
+        addTokenType(LSH, "LSH", "<<");
+        addTokenType(LSH_EQ, "LSH_EQ", "<<=");
+        addTokenType(MOD_EQ, "MOD_EQ", "%=");
+        addTokenType(MULT_EQ, "MULT_EQ", "*=");
+        addTokenType(NE, "NE", "!=");
+        addTokenType(NL, "NL");
+        addTokenType(OR_EQ, "OR_EQ", "|=");
+        addTokenType(PASTE, "PASTE", "##");
+        addTokenType(PLUS_EQ, "PLUS_EQ", "+=");
+        addTokenType(RANGE, "RANGE", "..");
+        addTokenType(RSH, "RSH", ">>");
+        addTokenType(RSH_EQ, "RSH_EQ", ">>=");
+        addTokenType(SQSTRING, "SQSTRING");
+        addTokenType(STRING, "STRING");
+        addTokenType(SUB_EQ, "SUB_EQ", "-=");
+        addTokenType(WHITESPACE, "WHITESPACE");
+        addTokenType(XOR_EQ, "XOR_EQ", "^=");
+        addTokenType(M_ARG, "M_ARG");
+        addTokenType(M_PASTE, "M_PASTE");
+        addTokenType(M_STRING, "M_STRING");
+        addTokenType(P_LINE, "P_LINE");
+        addTokenType(INVALID, "INVALID");
+    }
+
+    private final String name;
+    private final String text;
+
+    /* pp */ TokenType(@Nonnull String name, @CheckForNull String text) {
+        this.name = name;
+        this.text = text;
+    }
+
+    @Nonnull
+    public String getName() {
+        return name;
+    }
+
+    @CheckForNull
+    public String getText() {
+        return text;
+    }
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/VirtualFile.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/VirtualFile.java
new file mode 100644
index 0000000..26bbbcb
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/VirtualFile.java
@@ -0,0 +1,45 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import java.io.IOException;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * An extremely lightweight virtual file interface.
+ */
+public interface VirtualFile {
+
+    // public String getParent();
+    public boolean isFile();
+
+    @Nonnull
+    public String getPath();
+
+    @Nonnull
+    public String getName();
+
+    @CheckForNull
+    public VirtualFile getParentFile();
+
+    @Nonnull
+    public VirtualFile getChildFile(String name);
+
+    @Nonnull
+    public Source getSource() throws IOException;
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/VirtualFileSystem.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/VirtualFileSystem.java
new file mode 100644
index 0000000..3f72f0c
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/VirtualFileSystem.java
@@ -0,0 +1,31 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+import javax.annotation.Nonnull;
+
+/**
+ * An extremely lightweight virtual file system interface.
+ */
+public interface VirtualFileSystem {
+
+    @Nonnull
+    public VirtualFile getFile(@Nonnull String path);
+
+    @Nonnull
+    public VirtualFile getFile(@Nonnull String dir, @Nonnull String name);
+}
diff --git a/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Warning.java b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Warning.java
new file mode 100644
index 0000000..89388f4
--- /dev/null
+++ b/jcpp/src/main/java/com/jogamp/gluegen/jcpp/Warning.java
@@ -0,0 +1,32 @@
+/*
+ * Anarres C Preprocessor
+ * Copyright (c) 2007-2008, Shevek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied.  See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.jogamp.gluegen.jcpp;
+
+/**
+ * Warning classes which may optionally be emitted by the Preprocessor.
+ */
+public enum Warning {
+
+    TRIGRAPHS,
+    // TRADITIONAL,
+    IMPORT,
+    UNDEF,
+    UNUSED_MACROS,
+    ENDIF_LABELS,
+    ERROR,
+    // SYSTEM_HEADERS
+}
diff --git a/jcpp/src/test/java/com/jogamp/gluegen/jcpp/CppReaderTest.java b/jcpp/src/test/java/com/jogamp/gluegen/jcpp/CppReaderTest.java
new file mode 100644
index 0000000..870663d
--- /dev/null
+++ b/jcpp/src/test/java/com/jogamp/gluegen/jcpp/CppReaderTest.java
@@ -0,0 +1,77 @@
+package com.jogamp.gluegen.jcpp;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Collections;
+
+import javax.annotation.Nonnull;
+
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+import com.jogamp.gluegen.test.junit.generation.BuildEnvironment;
+import com.jogamp.junit.util.SingletonJunitCase;
+
+import static org.junit.Assert.assertEquals;
+
+ at FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class CppReaderTest extends SingletonJunitCase {
+
+    public static String testCppReader(@Nonnull final String in, final Feature... f) throws Exception {
+        final String inclpath = BuildEnvironment.gluegenRoot + "/jcpp/src/test/resources" ;
+
+        System.out.println("Testing " + in);
+        final StringReader r = new StringReader(in);
+        final CppReader p = new CppReader(r);
+        p.getPreprocessor().setSystemIncludePath(
+                Collections.singletonList(inclpath)
+        );
+        p.getPreprocessor().addFeatures(f);
+        final BufferedReader b = new BufferedReader(p);
+
+        final StringBuilder out = new StringBuilder();
+        String line;
+        while ((line = b.readLine()) != null) {
+            System.out.println(" >> " + line);
+            out.append(line).append("\n");
+        }
+
+        return out.toString();
+    }
+
+    @Test
+    public void testCppReader()
+            throws Exception {
+        testCppReader("#include <test0.h>\n", Feature.LINEMARKERS);
+    }
+
+    @Test
+    public void testVarargs()
+            throws Exception {
+        // The newlines are irrelevant, We want exactly one "foo"
+        testCppReader("#include <varargs.c>\n");
+    }
+
+    @Test
+    public void testPragmaOnce()
+            throws Exception {
+        // The newlines are irrelevant, We want exactly one "foo"
+        final String out = testCppReader("#include <once.c>\n", Feature.PRAGMA_ONCE);
+        assertEquals("foo", out.trim());
+    }
+
+    @Test
+    public void testPragmaOnceWithMarkers()
+            throws Exception {
+        // The newlines are irrelevant, We want exactly one "foo"
+        testCppReader("#include <once.c>\n", Feature.PRAGMA_ONCE, Feature.LINEMARKERS);
+    }
+
+    public static void main(final String args[]) throws IOException {
+        final String tstname = CppReaderTest.class.getName();
+        org.junit.runner.JUnitCore.main(tstname);
+    }
+
+}
diff --git a/jcpp/src/test/java/com/jogamp/gluegen/jcpp/ErrorTest.java b/jcpp/src/test/java/com/jogamp/gluegen/jcpp/ErrorTest.java
new file mode 100644
index 0000000..ad6a1b4
--- /dev/null
+++ b/jcpp/src/test/java/com/jogamp/gluegen/jcpp/ErrorTest.java
@@ -0,0 +1,72 @@
+package com.jogamp.gluegen.jcpp;
+
+import java.io.IOException;
+
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+import com.jogamp.junit.util.SingletonJunitCase;
+
+import static com.jogamp.gluegen.jcpp.Token.*;
+import static org.junit.Assert.*;
+
+ at FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class ErrorTest extends SingletonJunitCase {
+
+    private boolean testError(final Preprocessor p)
+            throws LexerException,
+            IOException {
+        for (;;) {
+            final Token tok = p.token();
+            if (tok.getType() == EOF)
+                break;
+            if (tok.getType() == INVALID)
+                return true;
+        }
+        return false;
+    }
+
+    private void testError(final String input) throws Exception {
+        StringLexerSource sl;
+        DefaultPreprocessorListener pl;
+        Preprocessor p;
+
+        /* Without a PreprocessorListener, throws an exception. */
+        sl = new StringLexerSource(input, true);
+        p = new Preprocessor();
+        p.addFeature(Feature.CSYNTAX);
+        p.addInput(sl);
+        try {
+            assertTrue(testError(p));
+            fail("Lexing unexpectedly succeeded without listener.");
+        } catch (final LexerException e) {
+            /* required */
+        }
+
+        /* With a PreprocessorListener, records the error. */
+        sl = new StringLexerSource(input, true);
+        p = new Preprocessor();
+        p.addFeature(Feature.CSYNTAX);
+        p.addInput(sl);
+        pl = new DefaultPreprocessorListener();
+        p.setListener(pl);
+        assertNotNull("CPP has listener", p.getListener());
+        assertTrue(testError(p));
+        assertTrue("Listener has errors", pl.getErrors() > 0);
+
+        /* Without CSYNTAX, works happily. */
+        sl = new StringLexerSource(input, true);
+        p = new Preprocessor();
+        p.addInput(sl);
+        assertTrue(testError(p));
+    }
+
+    @Test
+    public void testErrors() throws Exception {
+        testError("\"");
+        testError("'");
+        // testError("''");
+    }
+
+}
diff --git a/jcpp/src/test/java/com/jogamp/gluegen/jcpp/IncludeAbsoluteTest.java b/jcpp/src/test/java/com/jogamp/gluegen/jcpp/IncludeAbsoluteTest.java
new file mode 100644
index 0000000..9008ebe
--- /dev/null
+++ b/jcpp/src/test/java/com/jogamp/gluegen/jcpp/IncludeAbsoluteTest.java
@@ -0,0 +1,55 @@
+package com.jogamp.gluegen.jcpp;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Reader;
+
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+import com.jogamp.common.util.IOUtil;
+import com.jogamp.gluegen.Logging;
+import com.jogamp.gluegen.Logging.LoggerIf;
+import com.jogamp.gluegen.test.junit.generation.BuildEnvironment;
+import com.jogamp.junit.util.SingletonJunitCase;
+
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author shevek
+ */
+ at FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class IncludeAbsoluteTest extends SingletonJunitCase {
+
+    private static final LoggerIf LOG = Logging.getLogger(IncludeAbsoluteTest.class);
+
+    @Test
+    public void testAbsoluteInclude() throws Exception {
+        final String filepath = BuildEnvironment.gluegenRoot + "/jcpp/src/test/resources/absolute.h" ;
+        LOG.info("filepath: " + filepath);
+
+        final File file = new File(filepath);
+        assertTrue(file.exists());
+        final String slashifiedFilePath = IOUtil.slashify(file.getAbsolutePath(), true, false);
+        LOG.info("slashifiedFilePath: " + slashifiedFilePath);
+
+        // Expects something like:
+        //   WINDOWS: "/C:/projects/jogamp/gluegen/jcpp/src/test/resources/absolute.h"
+        //   UNIX:    "/projects/jogamp/gluegen/jcpp/src/test/resources/absolute.h"
+        final String input = "#include <" + slashifiedFilePath + ">\n";
+        LOG.info("Input: " + input);
+        final Preprocessor pp = new Preprocessor();
+        pp.addInput(new StringLexerSource(input, true));
+        final Reader r = new CppReader(pp);
+        final String output = IOUtil.appendCharStream(new StringBuilder(), r).toString();
+        r.close();
+        LOG.info("Output: " + output);
+        assertTrue(output.contains("absolute-result"));
+    }
+    public static void main(final String args[]) throws IOException {
+        final String tstname = IncludeAbsoluteTest.class.getName();
+        org.junit.runner.JUnitCore.main(tstname);
+    }
+}
diff --git a/jcpp/src/test/java/com/jogamp/gluegen/jcpp/JavaFileSystemTest.java b/jcpp/src/test/java/com/jogamp/gluegen/jcpp/JavaFileSystemTest.java
new file mode 100644
index 0000000..3477d97
--- /dev/null
+++ b/jcpp/src/test/java/com/jogamp/gluegen/jcpp/JavaFileSystemTest.java
@@ -0,0 +1,46 @@
+package com.jogamp.gluegen.jcpp;
+
+import java.io.FileNotFoundException;
+
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+import com.jogamp.junit.util.SingletonJunitCase;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+ at FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class JavaFileSystemTest extends SingletonJunitCase {
+
+    @Test
+    public void testJavaFileSystem() throws Exception {
+        final JavaFileSystem fs = new JavaFileSystem();
+        VirtualFile f;
+
+        /* Anyone who has this file on their Unix box is messed up. */
+        f = fs.getFile("/foo/bar baz");
+        try {
+            f.getSource();	/* drop on floor */
+
+            assertTrue("Got a source for a non-file", f.isFile());
+        } catch (final FileNotFoundException e) {
+            assertFalse("Got no source for a file", f.isFile());
+        }
+
+        /* We hope we have this. */
+        f = fs.getFile("/usr/include/stdio.h");
+        try {
+            f.getSource();	/* drop on floor */
+
+            System.out.println("Opened stdio.h");
+            assertTrue("Got a source for a non-file", f.isFile());
+        } catch (final FileNotFoundException e) {
+            System.out.println("Failed to open stdio.h");
+            assertFalse("Got no source for a file", f.isFile());
+        }
+
+    }
+
+}
diff --git a/jcpp/src/test/java/com/jogamp/gluegen/jcpp/JoinReaderTest.java b/jcpp/src/test/java/com/jogamp/gluegen/jcpp/JoinReaderTest.java
new file mode 100644
index 0000000..4193f3f
--- /dev/null
+++ b/jcpp/src/test/java/com/jogamp/gluegen/jcpp/JoinReaderTest.java
@@ -0,0 +1,48 @@
+package com.jogamp.gluegen.jcpp;
+
+import java.io.StringReader;
+
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+import com.jogamp.junit.util.SingletonJunitCase;
+
+import static org.junit.Assert.assertEquals;
+
+ at FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class JoinReaderTest extends SingletonJunitCase {
+
+    private void testJoinReader(final String in, final String out, final boolean tg)
+            throws Exception {
+        System.out.println("Testing " + in + " => " + out);
+        final StringReader r = new StringReader(in);
+        final JoinReader j = new JoinReader(r, tg);
+
+        for (int i = 0; i < out.length(); i++) {
+            final int c = j.read();
+            System.out.println("At offset " + i + ": " + (char) c);
+            assertEquals(out.charAt(i), c);
+        }
+        assertEquals(-1, j.read());
+        assertEquals(-1, j.read());
+    }
+
+    private void testJoinReader(final String in, final String out)
+            throws Exception {
+        testJoinReader(in, out, true);
+        testJoinReader(in, out, false);
+    }
+
+    @Test
+    public void testJoinReader()
+            throws Exception {
+        testJoinReader("ab", "ab");
+        testJoinReader("a\\b", "a\\b");
+        testJoinReader("a\nb", "a\nb");
+        testJoinReader("a\\\nb", "ab\n");
+        testJoinReader("foo??(bar", "foo[bar", true);
+        testJoinReader("foo??/\nbar", "foobar\n", true);
+    }
+
+}
diff --git a/jcpp/src/test/java/com/jogamp/gluegen/jcpp/LexerSourceTest.java b/jcpp/src/test/java/com/jogamp/gluegen/jcpp/LexerSourceTest.java
new file mode 100644
index 0000000..99324ff
--- /dev/null
+++ b/jcpp/src/test/java/com/jogamp/gluegen/jcpp/LexerSourceTest.java
@@ -0,0 +1,147 @@
+package com.jogamp.gluegen.jcpp;
+
+import java.util.Arrays;
+
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+import com.jogamp.gluegen.Logging;
+import com.jogamp.gluegen.Logging.LoggerIf;
+import com.jogamp.junit.util.SingletonJunitCase;
+
+import static com.jogamp.gluegen.jcpp.PreprocessorTest.assertType;
+import static com.jogamp.gluegen.jcpp.Token.*;
+import static org.junit.Assert.*;
+
+ at FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class LexerSourceTest extends SingletonJunitCase {
+
+    private static final LoggerIf LOG = Logging.getLogger(LexerSourceTest.class);
+
+    public static void testLexerSource(final String in, final boolean textmatch, final int... out)
+            throws Exception {
+        LOG.info("Testing '" + in + "' => "
+                + Arrays.toString(out));
+        final StringLexerSource s = new StringLexerSource(in);
+
+        final StringBuilder buf = new StringBuilder();
+        for (int i = 0; i < out.length; i++) {
+            final Token tok = s.token();
+            LOG.info("Token is " + tok);
+            assertType(out[i], tok);
+            // assertEquals(col, tok.getColumn());
+            buf.append(tok.getText());
+        }
+
+        final Token tok = s.token();
+        LOG.info("Token is " + tok);
+        assertType(EOF, tok);
+
+        if (textmatch)
+            assertEquals(in, buf.toString());
+    }
+
+    @Test
+    public void testLexerSource()
+            throws Exception {
+
+        testLexerSource("int a = 5;", true,
+                IDENTIFIER, WHITESPACE, IDENTIFIER, WHITESPACE,
+                '=', WHITESPACE, NUMBER, ';'
+        );
+
+        // \n is WHITESPACE because ppvalid = false
+        testLexerSource("# #   \r\n\n\r \rfoo", true,
+                HASH, WHITESPACE, '#', WHITESPACE, IDENTIFIER
+        );
+
+        // No match - trigraphs
+        testLexerSource("%:%:", false, PASTE);
+        testLexerSource("%:?", false, '#', '?');
+        testLexerSource("%:%=", false, '#', MOD_EQ);
+
+        testLexerSource("0x1234ffdUL 0765I", true,
+                NUMBER, WHITESPACE, NUMBER);
+
+        testLexerSource("+= -= *= /= %= <= >= >>= <<= &= |= ^= x", true,
+                PLUS_EQ, WHITESPACE,
+                SUB_EQ, WHITESPACE,
+                MULT_EQ, WHITESPACE,
+                DIV_EQ, WHITESPACE,
+                MOD_EQ, WHITESPACE,
+                LE, WHITESPACE,
+                GE, WHITESPACE,
+                RSH_EQ, WHITESPACE,
+                LSH_EQ, WHITESPACE,
+                AND_EQ, WHITESPACE,
+                OR_EQ, WHITESPACE,
+                XOR_EQ, WHITESPACE,
+                IDENTIFIER);
+
+        testLexerSource("/**/", true, CCOMMENT);
+        testLexerSource("/* /**/ */", true, CCOMMENT, WHITESPACE, '*', '/');
+        testLexerSource("/** ** **/", true, CCOMMENT);
+        testLexerSource("//* ** **/", true, CPPCOMMENT);
+        testLexerSource("'\\r' '\\xf' '\\xff' 'x' 'aa' ''", true,
+                CHARACTER, WHITESPACE,
+                CHARACTER, WHITESPACE,
+                CHARACTER, WHITESPACE,
+                CHARACTER, WHITESPACE,
+                SQSTRING, WHITESPACE,
+                SQSTRING);
+
+        if (false)  // Actually, I think this is illegal.
+            testLexerSource("1i1I1l1L1ui1ul", true,
+                    NUMBER, NUMBER,
+                    NUMBER, NUMBER,
+                    NUMBER, NUMBER);
+
+        testLexerSource("'' 'x' 'xx'", true,
+                SQSTRING, WHITESPACE, CHARACTER, WHITESPACE, SQSTRING);
+    }
+
+    @Test
+    public void testNumbers() throws Exception {
+        testLexerSource("0", true, NUMBER);
+        testLexerSource("045", true, NUMBER);
+        testLexerSource("45", true, NUMBER);
+        testLexerSource("0.45", true, NUMBER);
+        testLexerSource("1.45", true, NUMBER);
+        testLexerSource("1e6", true, NUMBER);
+        testLexerSource("1.45e6", true, NUMBER);
+        testLexerSource(".45e6", true, NUMBER);
+        testLexerSource("-6", true, '-', NUMBER);
+    }
+
+    @Test
+    public void testNumbersSuffix() throws Exception {
+        testLexerSource("6f", true, NUMBER);
+        testLexerSource("6d", true, NUMBER);
+        testLexerSource("6l", true, NUMBER);
+        testLexerSource("6ll", true, NUMBER);
+        testLexerSource("6ul", true, NUMBER);
+        testLexerSource("6ull", true, NUMBER);
+        testLexerSource("6e3f", true, NUMBER);
+        testLexerSource("6e3d", true, NUMBER);
+        testLexerSource("6e3l", true, NUMBER);
+        testLexerSource("6e3ll", true, NUMBER);
+        testLexerSource("6e3ul", true, NUMBER);
+        testLexerSource("6e3ull", true, NUMBER);
+    }
+
+    @Test
+    public void testNumbersInvalid() throws Exception {
+        // testLexerSource("0x foo", true, INVALID, WHITESPACE, IDENTIFIER);   // FAIL
+        testLexerSource("6x foo", true, INVALID, WHITESPACE, IDENTIFIER);
+        testLexerSource("6g foo", true, INVALID, WHITESPACE, IDENTIFIER);
+        testLexerSource("6xsd foo", true, INVALID, WHITESPACE, IDENTIFIER);
+        testLexerSource("6gsd foo", true, INVALID, WHITESPACE, IDENTIFIER);
+    }
+
+    @Test
+    public void testUnterminatedComment() throws Exception {
+        testLexerSource("5 /*", false, NUMBER, WHITESPACE, INVALID);    // Bug #15
+        testLexerSource("5 //", false, NUMBER, WHITESPACE, CPPCOMMENT);
+    }
+}
diff --git a/jcpp/src/test/java/com/jogamp/gluegen/jcpp/NumericValueTest.java b/jcpp/src/test/java/com/jogamp/gluegen/jcpp/NumericValueTest.java
new file mode 100644
index 0000000..84a0ff1
--- /dev/null
+++ b/jcpp/src/test/java/com/jogamp/gluegen/jcpp/NumericValueTest.java
@@ -0,0 +1,102 @@
+package com.jogamp.gluegen.jcpp;
+
+import java.io.IOException;
+
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+import com.jogamp.junit.util.SingletonJunitCase;
+
+import static com.jogamp.gluegen.jcpp.Token.*;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author shevek
+ */
+ at FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class NumericValueTest extends SingletonJunitCase {
+
+    private Token testNumericValue(final String in) throws IOException, LexerException {
+        final StringLexerSource s = new StringLexerSource(in);
+
+        final Token tok = s.token();
+        System.out.println("Token is " + tok);
+        assertEquals(NUMBER, tok.getType());
+
+        final Token eof = s.token();
+        assertEquals("Didn't get EOF, but " + tok, EOF, eof.getType());
+
+        return tok;
+    }
+
+    private void testNumericValue(final String in, final double out) throws IOException, LexerException {
+        System.out.println("Testing '" + in + "' -> " + out);
+        final Token tok = testNumericValue(in);
+        assertEquals(in, tok.getText());
+        final NumericValue value = (NumericValue) tok.getValue();
+        assertEquals("Double mismatch", out, value.doubleValue(), 0.01d);
+        assertEquals("Float mismatch", (float) out, value.floatValue(), 0.01f);
+        assertEquals("Long mismatch", (long) out, value.longValue());
+        assertEquals("Integer mismatch", (int) out, value.intValue());
+    }
+
+    @Test
+    public void testNumericValue() throws Exception {
+
+        // Zero
+        testNumericValue("0", 0);
+
+        // Decimal
+        testNumericValue("1", 1);
+        testNumericValue("1L", 1);
+        testNumericValue("12", 12);
+        testNumericValue("12L", 12);
+
+        // Hex
+        testNumericValue("0xf", 0xf);
+        testNumericValue("0xfL", 0xf);
+        testNumericValue("0x12", 0x12);
+        testNumericValue("0x12L", 0x12);
+
+        // Negative
+        // testNumericValue("-0", 0);
+        // testNumericValue("-1", -1);
+        // Negative hex
+        // testNumericValue("-0x56", -0x56);
+        // testNumericValue("-0x102", -0x102);
+        // Octal and negative octal
+        testNumericValue("0673", Integer.parseInt("673", 8));
+        // testNumericValue("-0673", Integer.parseInt("-673", 8));
+
+        // Floating point
+        testNumericValue(".0", 0);
+        testNumericValue(".00", 0);
+        testNumericValue("0.", 0);
+        testNumericValue("0.0", 0);
+        testNumericValue("00.0", 0);
+        testNumericValue("00.", 0);
+
+        // Sign on exponents
+        testNumericValue("1e1", 1e1);
+        // testNumericValue("-1e1", -1e1);
+        testNumericValue("1e-1", 1e-1);
+
+        // Hex numbers with decimal exponents
+        testNumericValue("0x12e3", 0x12e3);
+        testNumericValue("0x12p3", 0x12p3);
+
+        // Octal numbers with decimal exponents
+        testNumericValue("012e3", 012e3);    // Fails
+        testNumericValue("067e4", 067e4);    // Fails
+
+        // Issues a warning.
+        try {
+            testNumericValue("097", 97);
+            fail("No warning.");
+        } catch (final LexerException e) {
+        }
+
+    }
+}
diff --git a/jcpp/src/test/java/com/jogamp/gluegen/jcpp/PreprocessorTest.java b/jcpp/src/test/java/com/jogamp/gluegen/jcpp/PreprocessorTest.java
new file mode 100644
index 0000000..c4a4b06
--- /dev/null
+++ b/jcpp/src/test/java/com/jogamp/gluegen/jcpp/PreprocessorTest.java
@@ -0,0 +1,376 @@
+package com.jogamp.gluegen.jcpp;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.util.List;
+import java.util.logging.Level;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+import com.jogamp.gluegen.Logging;
+import com.jogamp.gluegen.Logging.LoggerIf;
+import com.jogamp.junit.util.SingletonJunitCase;
+
+import static com.jogamp.gluegen.jcpp.Token.*;
+import static org.junit.Assert.*;
+
+ at FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class PreprocessorTest extends SingletonJunitCase {
+
+    private static final LoggerIf LOG = Logging.getLogger(PreprocessorTest.class);
+
+    private OutputStreamWriter writer;
+    private Preprocessor p;
+
+    @Before
+    public void setUp() throws Exception {
+        LOG.setLevel(Level.INFO);
+        final PipedOutputStream po = new PipedOutputStream();
+        writer = new OutputStreamWriter(po);
+
+        p = new Preprocessor();
+        // p.addFeature(Feature.DEBUG);
+        p.addInput(
+                new LexerSource(
+                        new InputStreamReader(
+                                new PipedInputStream(po)
+                        ),
+                        true
+                )
+        );
+    }
+
+    private static class I {
+        private final String t;
+
+        public I(final String t) {
+            this.t = t;
+        }
+
+        public String getText() {
+            return t;
+        }
+
+        @Override
+        public String toString() {
+            return getText();
+        }
+    }
+    private static I I(final String t) {
+        return new I(t);
+    }
+    private static class N {
+        private final String t;
+
+        public N(final String t) {
+            this.t = t;
+        }
+
+        public String getText() {
+            return t;
+        }
+
+        @Override
+        public String toString() {
+            return getText();
+        }
+    }
+    private static N N(final String t) {
+        return new N(t);
+    }
+
+    /*
+     * When writing tests in this file, remember the preprocessor
+     * stashes NLs, so you won't see an immediate NL at the end of any
+     * input line. You will see it right before the next nonblank on
+     * the following input line.
+     */
+    @Test
+    public void test01Preprocessor() throws Exception {
+        /* Magic macros */
+        testInput("line = __LINE__\n",
+                I("line"), WHITESPACE, '=', WHITESPACE, NUMBER
+        /*, NL - all nls deferred so as not to block the reader */
+        );
+        testInput("file = __FILE__\n", NL, /* from before, etc */
+                I("file"), WHITESPACE, '=', WHITESPACE, STRING
+        );
+
+        /* Simple definitions */
+        testInput("#define A a /* a defined */\n", NL);
+        testInput("A /* a */\n", NL, I("a"), WHITESPACE, CCOMMENT);
+        testConstMacro("A", true, I("a"));
+        testInput("#define B b /* b defined */\n", NL);
+        testInput("B /* b */\n", NL, I("b"), WHITESPACE, CCOMMENT);
+        testConstMacro("B", false, I("b"));
+        testInput("#define C c /* c defined */\n", NL);
+
+        /* Expansion of arguments */
+        testInput("#define EXPAND(x) x\n", NL);
+        testInput("EXPAND(a)\n", NL, I("a"));
+        testInput("EXPAND(A)\n", NL, I("a"));
+
+        /* Stringification */
+        testInput("#define _STRINGIFY(x) #x\n", NL);
+        testInput("_STRINGIFY(A)\n", NL, "A");
+        testInput("#define STRINGIFY(x) _STRINGIFY(x)\n", NL);
+        testInput("STRINGIFY(b)\n", NL, "b");
+        testInput("STRINGIFY(A)\n", NL, "a");
+
+        /* Concatenation */
+        testInput("#define _CONCAT(x, y) x ## y\n", NL);
+        testInput("_CONCAT(A, B)\n", NL, I("AB"));
+        testInput("#define A_CONCAT done_a_concat\n", NL);
+        testInput("_CONCAT(A, _CONCAT(B, C))\n", NL,
+                I("done_a_concat"), '(', I("b"), ',', WHITESPACE, I("c"), ')'
+        );
+        testInput("#define CONCAT(x, y) _CONCAT(x, y)\n", NL);
+        testInput("CONCAT(A, CONCAT(B, C))\n", NL, I("abc"));
+        testInput("#define _CONCAT3(x, y, z) x ## y ## z\n", NL);
+        testInput("_CONCAT3(a, b, c)\n", NL, I("abc"));
+        testInput("_CONCAT3(A, B, C)\n", NL, I("ABC"));
+        testInput("_CONCAT(test_, inline)\n", NL, I("test_inline"));
+        testInput("_CONCAT(test_, \nnewline)\n", NL, I("test_newline"));
+
+        /* Redefinitions, undefinitions. */
+        testInput("#define two three\n", NL);
+        testInput("two /* three */\n", NL, I("three"), WHITESPACE, CCOMMENT);
+        testInput("one /* one */\n", NL, I("one"), WHITESPACE, CCOMMENT);
+        testConstMacro("two", false, I("three"));
+        testConstMacro("two", true, I("three"));
+
+        testInput("#define one two\n", NL);
+        testInput("one /* three */\n", NL, I("three"), WHITESPACE, CCOMMENT);
+        testConstMacro("one", false, I("two"));
+        testConstMacro("one", true, I("three"));
+
+        testInput("#undef two\n", NL);
+        testInput("one /* two */\n", NL, I("two"), WHITESPACE, CCOMMENT);
+        testConstMacro("one", false, I("two"));
+        testConstMacro("one", true, I("two"));
+
+        testInput("#define two five\n", NL);
+        testInput("one /* five */\n", NL, I("five"), WHITESPACE, CCOMMENT);
+        testConstMacro("one", false, I("two"));
+        testConstMacro("one", true, I("five"));
+
+        testInput("#undef two\n", NL);
+        testInput("one /* two */\n", NL, I("two"), WHITESPACE, CCOMMENT);
+        testConstMacro("one", false, I("two"));
+        testConstMacro("one", true, I("two"));
+
+        testInput("#undef one\n", NL);
+        testInput("#define one four\n", NL);
+        testInput("one /* four */\n", NL, I("four"), WHITESPACE, CCOMMENT);
+        testConstMacro("one", false, I("four"));
+        testConstMacro("one", true, I("four"));
+
+        testInput("#undef one\n", NL);
+        testInput("#define one one\n", NL);
+        testInput("one /* one */\n", NL, I("one"), WHITESPACE, CCOMMENT);
+        testConstMacro("one", false, I("one"));
+        testConstMacro("one", true, I("one"));
+
+        testInput("#define NUM1 1\n", NL);
+        testInput("#define NUM4 ( 1 << ( NUM1 + NUM1 ) )\n", NL);
+        testInput("NUM4 /* ( 1 << ( 1 + 1 ) ) */\n", NL,
+                '(', WHITESPACE, N("1"), WHITESPACE, LSH, WHITESPACE,
+                '(', WHITESPACE, N("1"), WHITESPACE, '+', WHITESPACE, N("1"), WHITESPACE, ')', WHITESPACE, ')',
+                WHITESPACE, CCOMMENT);
+        testConstMacro("NUM4", false, '(', WHITESPACE, N("1"), WHITESPACE, LSH, WHITESPACE,
+                                      '(', WHITESPACE, I("NUM1"), WHITESPACE, '+', WHITESPACE, I("NUM1"), WHITESPACE, ')',
+                                      WHITESPACE, ')');
+        testConstMacro("NUM4", true, '(', WHITESPACE, N("1"), WHITESPACE, LSH, WHITESPACE,
+                                     '(', WHITESPACE, N("1"), WHITESPACE, '+', WHITESPACE, N("1"), WHITESPACE, ')', WHITESPACE, ')');
+
+        /* Variadic macros. */
+        testInput("#define var(x...) a x __VA_ARGS__ b\n", NL);
+        testInput("var(e, f, g)\n", NL,
+                I("a"), WHITESPACE,
+                I("e"), ',', WHITESPACE,
+                I("f"), ',', WHITESPACE,
+                I("g"), WHITESPACE,
+                I("__VA_ARGS__"), WHITESPACE, // __VA_ARGS__ is not expanded in this case.
+                I("b")
+        );
+        /* Missing arguments are fine. */
+        testInput("var()\n", NL,
+                I("a"), WHITESPACE,
+                /* No expansion for 'x'. */ WHITESPACE,
+                I("__VA_ARGS__"), WHITESPACE,
+                I("b")
+        );
+
+        /* Variadic macros with anonymous args. */
+        testInput("#define var2(x, ...) a x __VA_ARGS__ e\n", NL);
+        testInput("var2(b, c, d)\n", NL,
+                I("a"), WHITESPACE,
+                I("b"), WHITESPACE,
+                I("c"), ',', WHITESPACE,
+                I("d"), WHITESPACE,
+                I("e")
+        );
+        /* Missing arguments are fine. */
+        testInput("var2(b)\n", NL,
+                I("a"), WHITESPACE,
+                I("b"), WHITESPACE,
+                /* No expansion for '__VA_ARGS__'. */ WHITESPACE,
+                I("e")
+        );
+
+        testInput("#define var3(...) a __VA_ARGS__ d\n", NL);
+        testInput("var3(b, c)\n", NL,
+                I("a"), WHITESPACE,
+                I("b"), ',', WHITESPACE,
+                I("c"), WHITESPACE,
+                I("d")
+        );
+        testInput("var3()\n", NL,
+                I("a"), WHITESPACE,
+                /* No expansion for '__VA_ARGS__'. */ WHITESPACE,
+                I("d")
+        );
+
+        testInput("#define _Widen(x) L ## x\n", NL);
+        testInput("#define Widen(x) _Widen(x)\n", NL);
+        testInput("#define LStr(x) _Widen(#x)\n", NL);
+        testInput("LStr(x);\n", NL, I("L"), "x", ';');
+
+        testInput("'foo'\n", NL, SQSTRING);
+        testInput("#if 1 ? 2 : 0\nTEXT\n#endif\n", NL, NL, I("TEXT"), NL);
+        testInput("#if 1 ? 0 : 2\nTEXT\n#endif\n", NL, NL, NL);
+        testInput("#if 0 ? 0 : 2\nTEXT\n#endif\n", NL, NL, I("TEXT"), NL);
+        testInput("#if 0 ? 2 : 0\nTEXT\n#endif\n", NL, NL, NL);
+
+        writer.close();
+
+        Token t;
+        do {
+            t = p.token();
+            LOG.warning("Remaining token " + t);
+        } while (t.getType() != EOF);
+    }
+
+    @Test
+    public void test02PreprocessorUnterminated() throws Exception {
+        testInput("#ifndef X\na\n#else\nb\n");   // Bug #16
+
+        writer.close();
+
+        Token t;
+        do {
+            t = p.token();
+            LOG.warning("Remaining token " + t);
+        } while (t.getType() != EOF);
+    }
+
+    public static void assertType(final int type, final Token t) {
+        final String typeExpect = TokenType.getTokenName(type);
+        final String typeActual = TokenType.getTokenName(t.getType());
+        assertEquals("Expected " + typeExpect + " but got " + typeActual, type, t.getType());
+    }
+
+    private void testInput(final String in, final Object... out)
+            throws Exception {
+        LOG.info("Input: " + in);
+        writer.write(in);
+        writer.flush();
+        for (final Object v : out) {
+            final Token t = p.token();
+            LOG.info("READ: "+String.valueOf(t));
+            if (v instanceof String) {
+                if (t.getType() != STRING)
+                    fail("Expected STRING, but got " + t);
+                assertEquals(v, t.getValue());
+            } else if (v instanceof I) {
+                if (t.getType() != IDENTIFIER) {
+                    fail("Expected IDENTIFIER " + v + ", but got " + t);
+                }
+                assertEquals(((I) v).getText(), t.getText());
+            } else if (v instanceof N) {
+                if (t.getType() != NUMBER) {
+                    fail("Expected NUMBER " + v + ", but got " + t);
+                }
+                assertEquals(((N) v).getText(), t.getText());
+            } else if (v instanceof Character) {
+                assertType(((Character) v).charValue(), t);
+            } else if (v instanceof Integer) {
+                assertType(((Number) v).intValue(), t);
+            } else {
+                fail("Bad object " + v.getClass());
+            }
+        }
+    }
+    // slow ..
+    private Macro findMacro(final List<Macro> macros, final String macroName) {
+        final int count = macros.size();
+        for(int i=0; i<count; i++) {
+            final Macro m = macros.get(i);
+            if( m.getName().equals(macroName) ) {
+                return m;
+            }
+        }
+        return null;
+    }
+    private void dumpMacros(final List<Macro> macros) {
+        final int count = macros.size();
+        System.err.println("Macro count: "+count);
+        for(int i=0; i<count; i++) {
+            final Macro m = macros.get(i);
+            System.err.println(" ["+i+"]: "+m);
+        }
+    }
+    private void testConstMacro(final String macroName, final boolean expandMacro, final Object... out)
+            throws Exception {
+        final List<Macro> macros = p.getMacros(expandMacro);
+        final Macro m = findMacro(macros, macroName);
+        if( null == m ) {
+            dumpMacros(macros);
+        }
+        Assert.assertNotNull("Macro <"+macroName+"> is missing!", m);
+        Assert.assertFalse(m.isFunctionLike());
+
+        final Source s = new MacroTokenSource(m, null);
+        try {
+            for (final Object v : out) {
+                final Token t = s.token();
+                LOG.info("READ: "+String.valueOf(t));
+                if (v instanceof String) {
+                    if (t.getType() != STRING) {
+                        fail("Expected STRING, but got " + t);
+                    }
+                    assertEquals(v, t.getValue());
+                } else if (v instanceof I) {
+                    if (t.getType() != IDENTIFIER) {
+                        fail("Expected IDENTIFIER " + v + ", but got " + t);
+                    }
+                    assertEquals(((I) v).getText(), t.getText());
+                } else if (v instanceof N) {
+                    if (t.getType() != NUMBER) {
+                        fail("Expected NUMBER " + v + ", but got " + t);
+                    }
+                    assertEquals(((N) v).getText(), t.getText());
+                } else if (v instanceof Character) {
+                    assertType(((Character) v).charValue(), t);
+                } else if (v instanceof Integer) {
+                    assertType(((Number) v).intValue(), t);
+                } else {
+                    fail("Bad object " + v.getClass());
+                }
+            }
+        } finally {
+            s.close();
+        }
+    }
+    public static void main(final String args[]) throws IOException {
+        final String tstname = PreprocessorTest.class.getName();
+        org.junit.runner.JUnitCore.main(tstname);
+    }
+}
diff --git a/jcpp/src/test/java/com/jogamp/gluegen/jcpp/TokenPastingWhitespaceTest.java b/jcpp/src/test/java/com/jogamp/gluegen/jcpp/TokenPastingWhitespaceTest.java
new file mode 100644
index 0000000..ff556ad
--- /dev/null
+++ b/jcpp/src/test/java/com/jogamp/gluegen/jcpp/TokenPastingWhitespaceTest.java
@@ -0,0 +1,59 @@
+package com.jogamp.gluegen.jcpp;
+
+import com.jogamp.common.util.IOUtil;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+import com.jogamp.gluegen.Logging;
+import com.jogamp.gluegen.Logging.LoggerIf;
+import com.jogamp.junit.util.SingletonJunitCase;
+
+import static org.junit.Assert.*;
+
+/**
+ * https://github.com/shevek/jcpp/issues/25
+ *
+ * @author shevek
+ */
+ at FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class TokenPastingWhitespaceTest extends SingletonJunitCase {
+
+    private static final LoggerIf LOG = Logging.getLogger(TokenPastingWhitespaceTest.class);
+
+    @Test
+    public void test01WhitespacePasting() throws IOException {
+        final Preprocessor pp = new Preprocessor();
+        testWhitespacePastingImpl(pp);
+    }
+    void testWhitespacePastingImpl(final Preprocessor pp) throws IOException {
+        pp.addInput(new StringLexerSource(
+                "#define ONE(arg) one_##arg\n"
+                + "#define TWO(arg) ONE(two_##arg)\n"
+                + "\n"
+                + "TWO(good)\n"
+                + "TWO(     /* evil newline */\n"
+                + "    bad)\n"
+                + "\n"
+                + "ONE(good)\n"
+                + "ONE(     /* evil newline */\n"
+                + "    bad)\n", true));
+        final Reader r = new CppReader(pp);
+        final String text = IOUtil.appendCharStream(new StringBuilder(), r).toString().trim();
+        LOG.info("Output is:\n" + text);
+        assertEquals("one_two_good\n"
+                + "one_two_bad\n"
+                + "\n"
+                + "one_good\n"
+                + "one_bad", text);
+    }
+
+    public static void main(final String args[]) throws IOException {
+        final String tstname = TokenPastingWhitespaceTest.class.getName();
+        org.junit.runner.JUnitCore.main(tstname);
+    }
+}
diff --git a/jcpp/src/test/resources/absolute.h b/jcpp/src/test/resources/absolute.h
new file mode 100644
index 0000000..82c5a66
--- /dev/null
+++ b/jcpp/src/test/resources/absolute.h
@@ -0,0 +1 @@
+absolute-result
diff --git a/jcpp/src/test/resources/once.c b/jcpp/src/test/resources/once.c
new file mode 100644
index 0000000..fd50d46
--- /dev/null
+++ b/jcpp/src/test/resources/once.c
@@ -0,0 +1,2 @@
+#include "once.h"
+#include "once.h"
diff --git a/jcpp/src/test/resources/once.h b/jcpp/src/test/resources/once.h
new file mode 100644
index 0000000..b6a482e
--- /dev/null
+++ b/jcpp/src/test/resources/once.h
@@ -0,0 +1,2 @@
+#pragma once
+foo
diff --git a/jcpp/src/test/resources/test0.c b/jcpp/src/test/resources/test0.c
new file mode 100644
index 0000000..7e91637
--- /dev/null
+++ b/jcpp/src/test/resources/test0.c
@@ -0,0 +1,61 @@
+line = __LINE__
+file = __FILE__
+
+#define A a	/* a defined */
+#define B b	/* b defined */
+#define C c	/* c defined */
+
+#define EXPAND(x) x
+EXPAND(a) -> a
+EXPAND(A) -> a
+
+#define _STRINGIFY(x) #x
+_STRINGIFY(A) -> "A"
+
+#define STRINGIFY(x) _STRINGIFY(x)
+STRINGIFY(b) -> "b"
+STRINGIFY(A) -> "a"
+
+#define _CONCAT(x, y) x ## y
+_CONCAT(A, B) -> AB
+
+#define A_CONCAT done_a_concat
+_CONCAT(A, _CONCAT(B, C)) -> done_a_concat(b, c)
+
+#define CONCAT(x, y) _CONCAT(x, y)
+CONCAT(A, CONCAT(B, C)) -> abc
+
+#define _CONCAT3(x, y, z) x ## y ## z
+_CONCAT3(a, b, c) -> abc
+_CONCAT3(A, B, C) -> ABC
+_CONCAT3(A, EXPAND(B), C) -> AEXPAND(b)C
+
+Line is __LINE__
+File is __FILE__
+
+#define two three
+one /* one */
+#define one two
+one /* three */
+#undef two
+#define two five
+one /* five */
+#undef two
+one /* two */
+#undef one
+#define one four
+one /* four */
+#undef one
+#define one one
+one /* one */
+
+/* warning line 57 column 0 */
+#warning arse
+
+#define foo(x) foo(x, b)
+foo(1) -> _foo(1, b) without the _
+foo(foo(2)) -> _foo(_foo(2, b), b) without the _
+// foo(y, z)
+
+#define var(x...) a x b
+var(e, f, g) -> a e, f, g b
diff --git a/jcpp/src/test/resources/test0.h b/jcpp/src/test/resources/test0.h
new file mode 100644
index 0000000..b6697c6
--- /dev/null
+++ b/jcpp/src/test/resources/test0.h
@@ -0,0 +1,7 @@
+
+test0start_2
+
+#include "test1.h"
+
+test0end___6
+
diff --git a/jcpp/src/test/resources/test1.c b/jcpp/src/test/resources/test1.c
new file mode 100644
index 0000000..3e6fbda
--- /dev/null
+++ b/jcpp/src/test/resources/test1.c
@@ -0,0 +1,2 @@
+#include "./test0.h"
+#include <test1.h>
diff --git a/jcpp/src/test/resources/test1.h b/jcpp/src/test/resources/test1.h
new file mode 100644
index 0000000..0b690f7
--- /dev/null
+++ b/jcpp/src/test/resources/test1.h
@@ -0,0 +1,7 @@
+
+test1start_2
+
+test1mid___4
+
+test1end___6
+
diff --git a/jcpp/src/test/resources/trigraph.c b/jcpp/src/test/resources/trigraph.c
new file mode 100644
index 0000000..89615fe
--- /dev/null
+++ b/jcpp/src/test/resources/trigraph.c
@@ -0,0 +1 @@
+??/
diff --git a/jcpp/src/test/resources/varargs.c b/jcpp/src/test/resources/varargs.c
new file mode 100644
index 0000000..5eac2fa
--- /dev/null
+++ b/jcpp/src/test/resources/varargs.c
@@ -0,0 +1,8 @@
+#define var(x...) a x __VA_ARGS__ b
+var(b, c, d)
+
+#define var2(x, ...) a x __VA_ARGS__ b
+var2(b, c, d)
+
+#define var3(...) a x __VA_ARGS__ b
+var3(b, c, d)
diff --git a/make/build-test.xml b/make/build-test.xml
index f9092d0..68f674f 100644
--- a/make/build-test.xml
+++ b/make/build-test.xml
@@ -36,6 +36,9 @@
         <property name="test.junit.generation.rel" value="${test.junit.rel}/gluegen/test/junit/generation" />
         <property name="test.junit.generation.dir" value="${test.base.dir}/${test.junit.generation.rel}" />
 
+        <property name="test.jcpp.base.dir" value="${project.root}/jcpp/src/test/java" />
+
+        <property name="tempdir"      value="${project.root}/build-temp" />
         <property name="build"        location="${project.root}/${rootrel.build}" />
         <property name="test.dir"     value="${gluegen.root}/${rootrel.build}/test"/>
         <property name="results"      value="${test.dir}/results" />
@@ -50,6 +53,7 @@
 
         <property name="build_t.gen.rootrel" value="${rootrel.build}/test/build/gensrc"/>
 
+        <mkdir dir="${tempdir}" />
         <mkdir dir="${test.dir}"/>
         <mkdir dir="${results}"/>
         <mkdir dir="${build_t}"/>
@@ -148,7 +152,7 @@
                debug="${javacdebug}" debuglevel="${javacdebuglevel}">
             <classpath refid="junit.compile.classpath"/>
             <compilerarg value="-proc:only"/>
-            <compilerarg value="-J-Djogamp.gluegen.structgen.debug"/>
+            <!-- compilerarg value="-J-Djogamp.gluegen.structgen.debug"/ -->
             <compilerarg value="-J-Djogamp.gluegen.structgen.output=${build_t.gen}/classes"/>
             <src path="${test.base.dir}/com/jogamp/gluegen/test/junit/structgen"/>
             <src path="${build_t.gen}/classes/com/jogamp/gluegen/test/junit/structgen" />
@@ -167,6 +171,7 @@
             <classpath refid="junit.compile.classpath"/>
             <compilerarg value="-proc:none"/>
             <src path="${test.base.dir}"/>
+            <src path="${test.jcpp.base.dir}"/>
             <src path="${build_t.gen}" />
         </javac>
 
@@ -264,9 +269,10 @@
 
     <target name="junit.compile.check" depends="init">
       <uptodate property="junit.compile.skip">
-        <srcfiles dir= "."                 includes="*.xml"/>
-        <srcfiles dir= "${test.base.dir}"  includes="**"/>
-        <srcfiles                          file="${gluegen.jar}" />
+        <srcfiles dir= "."                      includes="*.xml"/>
+        <srcfiles dir= "${test.base.dir}"       includes="**"/>
+        <srcfiles dir= "${test.jcpp.base.dir}"  includes="**"/>
+        <srcfiles                               file="${gluegen.jar}" />
         <mapper type="merge" to="${gluegen-test.jar}"/>
       </uptodate>
     </target>
@@ -516,6 +522,12 @@ chmod 644 ${results}/* \${line.separator}
       </antcall>
     </target>
 
+    <target name="java.generate.copy2temp">
+        <copy todir="${tempdir}">
+            <fileset dir="${build_t}"
+                     includes="gensrc/classes/**" />
+        </copy>
+    </target>
 
     <!-- 
 
@@ -542,9 +554,11 @@ chmod 644 ${results}/* \${line.separator}
                  includeRefid="stub.includes.fileset.test"
                  emitter="com.jogamp.gluegen.JavaEmitter"
                  dumpCPP="false"
-                 debug="false">
+                 debug="false"
+                 logLevel="WARNING">
             <classpath refid="gluegen.classpath" />
         </gluegen>
+        <antcall target="java.generate.copy2temp" inheritRefs="true" />
 
         <gluegen src="${test.junit.generation.dir}/test1-gluegen.c"
                  outputRootDir="${build_t.gen}"
@@ -553,7 +567,8 @@ chmod 644 ${results}/* \${line.separator}
                  includeRefid="stub.includes.fileset.test"
                  emitter="com.jogamp.gluegen.JavaEmitter"
                  dumpCPP="false"
-                 debug="false">
+                 debug="false"
+                 logLevel="WARNING">
             <classpath refid="gluegen.classpath" />
         </gluegen>
 
@@ -564,7 +579,8 @@ chmod 644 ${results}/* \${line.separator}
                  includeRefid="stub.includes.fileset.test"
                  emitter="com.jogamp.gluegen.procaddress.ProcAddressEmitter"
                  dumpCPP="false"
-                 debug="false">
+                 debug="false"
+                 logLevel="INFO">
             <classpath refid="gluegen.classpath" />
         </gluegen>
     </target>
diff --git a/make/build.xml b/make/build.xml
index 534f122..e92da5b 100644
--- a/make/build.xml
+++ b/make/build.xml
@@ -31,6 +31,7 @@
          This requires the user-defined "antlr.jar" property. -->
     <path id="cc_gluegen.classpath">
       <pathelement location="${antlr.jar}" />
+      <pathelement location="${semver.jar}" />
     </path>
   </target>
 
@@ -59,6 +60,8 @@
     <property name="project.root"  value=".." />
     <property name="src.java" value="${project.root}/src/java" />
     <property name="src.antlr" value="${project.root}/src/antlr" />
+    <property name="src.jcpp" value="${project.root}/jcpp/src/main/java" />
+
     <property name="build"    location="${project.root}/${rootrel.build}" />
     <property name="javadoc.root.path"    location="${build}/javadoc" />
     <property name="javadoc.gluegen.path" location="${javadoc.root.path}/gluegen/javadoc" />
@@ -138,8 +141,10 @@
 
     <!-- property name="java.part.awt" value="com/jogamp/common/util/awt/** jogamp/common/awt/**"/-->
     <property name="java.part.awt" value="com/jogamp/common/util/awt/**"/>
+    <property name="java.part.nonjava" value="com/jogamp/common/util/bin/*" />
     <property name="gluegen-rt.classes" value="com/jogamp/gluegen/runtime/**"/>
     <property name="jogamp.common.classes" value="com/jogamp/common/** jogamp/common/**"/>
+    <property name="java.part.jcpp" value="com/jogamp/gluegen/jcpp/**"/>
 
     <property name="gluegen.excludes.all" value="${gluegen.excludes.nsig} ${jogamp-android-launcher.classes}" />
   </target>
@@ -426,7 +431,7 @@
       <fail message="Requires '${compiler.cfg.id}'"      unless="compiler.cfg.id"/>
       <fail message="Requires '${linker.cfg.id}'"        unless="linker.cfg.id"/>
 
-      <javah destdir="${src.generated.c}"         classpath="${classes}" class="com.jogamp.common.os.Platform, com.jogamp.common.nio.PointerBuffer, jogamp.common.jvm.JVMUtil, com.jogamp.common.util.JarUtil, jogamp.common.os.MachineDescriptionRuntime" />
+      <javah destdir="${src.generated.c}"         classpath="${classes}" class="com.jogamp.common.os.Platform, com.jogamp.common.nio.PointerBuffer, jogamp.common.jvm.JVMUtil, com.jogamp.common.util.JarUtil, jogamp.common.os.MachineDataInfoRuntime" />
       <javah destdir="${src.generated.c}/Unix"    classpath="${classes}" class="jogamp.common.os.UnixDynamicLinkerImpl" />
       <javah destdir="${src.generated.c}/Windows" classpath="${classes}" class="jogamp.common.os.WindowsDynamicLinkerImpl"/>
 
@@ -602,6 +607,7 @@
       <uptodate property="gluegen.build.skip.java1">
         <srcfiles dir= "."            includes="*.xml"/>
         <srcfiles dir= "${src.java}"  includes="**"/>
+        <srcfiles dir= "${src.jcpp}"  includes="**"/>
         <srcfiles dir= "${c.grammar}" includes="*.g"/>
         <srcfiles dir= "${j.grammar}" includes="*.g"/>
         <mapper type="merge" to="${build}/gluegen.jar"/>
@@ -609,6 +615,7 @@
       <uptodate property="gluegen.build.skip.java2">
         <srcfiles dir= "."            includes="*.xml"/>
         <srcfiles dir= "${src.java}"  includes="**"/>
+        <srcfiles dir= "${src.jcpp}"  includes="**"/>
         <srcfiles dir= "${c.grammar}" includes="*.g"/>
         <srcfiles dir= "${j.grammar}" includes="*.g"/>
         <mapper type="merge" to="${build}/gluegen-rt.jar"/>
@@ -718,6 +725,13 @@
       <classpath refid="cc_gluegen.classpath" />
     </javac>
 
+    <!-- make non-java code available in classpath -->
+    <copy todir="${classes}">
+        <fileset dir="${src.java}"
+                 includes="${java.part.nonjava}"
+                 excludes="**/*.java"/>
+    </copy>
+
     <!-- Compile gluegen (compile time).
 
          Uses host.rt.jar, since we require 'com.sun.tools.doclets.Taglet',
@@ -730,10 +744,11 @@
            excludes="${gluegen.excludes.all} ${gluegen-rt.classes} ${java.part.android}"
            memoryMaximumSize="${javac.memorymax}"
            encoding="UTF-8"
-           source="${target.sourcelevel}" 
+           source="${target.sourcelevel}"
            target="${target.targetlevel}" 
            bootclasspath="${host.rt.jar}"
            debug="${javacdebug}" debuglevel="${javacdebuglevel}">
+      <src path="${src.jcpp}" />
       <src path="${src.java}" />
       <src path="${src.generated.java}" />
       <classpath refid="cc_gluegen.classpath" />
@@ -813,6 +828,7 @@
         <include name="jogamp/common/**" />
         <exclude name="${jogamp-android-launcher.classes}" />
         <exclude name="${java.part.android}" />
+        <exclude name="${java.part.jcpp}" />
       </fileset>
       <fileset dir="resources/assets">
         <include name="**" />
@@ -827,6 +843,7 @@
         <include name="jogamp/common/**" />
         <exclude name="${jogamp-android-launcher.classes}" />
         <exclude name="${java.part.android}" />
+        <exclude name="${java.part.jcpp}" />
       </fileset>
       <fileset dir="resources/assets">
         <include name="**" />
@@ -966,7 +983,7 @@
         <srcfiles dir= "."                includes="*.xml"/>
         <srcfiles dir= "${src.java}"      includes="**"/>
         <srcfiles dir= "${src.generated}" includes="**"/>
-        <mapper type="merge" to="${build}/gluegen-rt-android-${android.abi}.apk"/>
+        <mapper type="merge" to="${build}/gluegen-rt-${os.and.arch}.apk"/>
       </uptodate>
   </target>
 
@@ -1024,7 +1041,7 @@
     <delete dir="${javadoc.gluegen.path}" includeEmptyDirs="true" quiet="true" failonerror="false" />
     <mkdir dir="${javadoc.gluegen.path}" />
     <javadoc packagenames="com.jogamp.*"
-             sourcepath="${src.java};${src.generated.java}"
+             sourcepath="${src.java};${src.jcpp};${src.generated.java}"
              destdir="${javadoc.gluegen.path}" windowtitle="GlueGen Runtime Documentation"
              overview="../src/java/com/jogamp/gluegen/package.html"
              encoding="UTF-8"
@@ -1033,6 +1050,7 @@
              stylesheetfile="doc/javadoc/stylesheet.css">
         <classpath path="${classes}"/>
         <link offline="true" href="${javadoc.link}" packagelistLoc="142-packages" />
+        <arg value="${javadoc.xarg1}"/>
     </javadoc>
     <copy todir="${javadoc.gluegen.path}/resources" overwrite="true">
         <fileset dir="doc/javadoc/resources" includes="*" />
@@ -1055,6 +1073,7 @@
         <zip destfile="${build}/gluegen-java-src.zip" level="0">
             <fileset dir="${src.java}"/>
             <fileset dir="${build}/gensrc/java"/>
+            <fileset dir="${src.jcpp}"/>
         </zip>
     </target>
 
diff --git a/make/elf-header.cfg b/make/elf-header.cfg
index 05c7d79..c9c8be4 100644
--- a/make/elf-header.cfg
+++ b/make/elf-header.cfg
@@ -6,7 +6,61 @@ HierarchicalNativeOutput false
 #Implements Sym32 Sym
 #Implements Sym64 Sym
 
-EmitStruct Ehdr
+# ELF-1 (part-1) is independent of CPUType/ABI
+# hence can use an arbitrary MachineDataInfo index
+# for reading the struct Ehdr_p1 !
+StructMachineDataInfoIndex Ehdr_p1 private static final int mdIdx = 0;
+
+# The following sub structures shall use an mdIdx
+# defined by ELF-1 header code, set w/ ctor!
+StructMachineDataInfoIndex Ehdr_p2 private final int mdIdx;
+StructMachineDataInfoIndex Shdr private final int mdIdx;
+
+ManuallyImplement Ehdr_p2.size
+ManuallyImplement Ehdr_p2.create
+ManuallyImplement Ehdr_p2.Ehdr_p2
+ManuallyImplement Shdr.size
+ManuallyImplement Shdr.create
+ManuallyImplement Shdr.Shdr
+
+CustomJavaCode Ehdr_p2  public static int size(final int mdIdx) {
+CustomJavaCode Ehdr_p2      return Ehdr_p2_size[mdIdx];
+CustomJavaCode Ehdr_p2  }
+CustomJavaCode Ehdr_p2
+CustomJavaCode Ehdr_p2  public static Ehdr_p2 create(final int mdIdx) {
+CustomJavaCode Ehdr_p2      return create(mdIdx, Buffers.newDirectByteBuffer(size(mdIdx)));
+CustomJavaCode Ehdr_p2  }
+CustomJavaCode Ehdr_p2
+CustomJavaCode Ehdr_p2  public static Ehdr_p2 create(final int mdIdx, final java.nio.ByteBuffer buf) {
+CustomJavaCode Ehdr_p2      return new Ehdr_p2(mdIdx, buf);
+CustomJavaCode Ehdr_p2  }
+CustomJavaCode Ehdr_p2
+CustomJavaCode Ehdr_p2  Ehdr_p2(final int mdIdx, final java.nio.ByteBuffer buf) {
+CustomJavaCode Ehdr_p2      this.mdIdx = mdIdx;
+CustomJavaCode Ehdr_p2      this.md = MachineDataInfo.StaticConfig.values()[mdIdx].md;
+CustomJavaCode Ehdr_p2      this.accessor = new StructAccessor(buf);
+CustomJavaCode Ehdr_p2  }
+
+CustomJavaCode Shdr  public static int size(final int mdIdx) {
+CustomJavaCode Shdr      return Shdr_size[mdIdx];
+CustomJavaCode Shdr  }
+CustomJavaCode Shdr
+CustomJavaCode Shdr  public static Shdr create(final int mdIdx) {
+CustomJavaCode Shdr      return create(mdIdx, Buffers.newDirectByteBuffer(size(mdIdx)));
+CustomJavaCode Shdr  }
+CustomJavaCode Shdr
+CustomJavaCode Shdr  public static Shdr create(final int mdIdx, final java.nio.ByteBuffer buf) {
+CustomJavaCode Shdr      return new Shdr(mdIdx, buf);
+CustomJavaCode Shdr  }
+CustomJavaCode Shdr
+CustomJavaCode Shdr  Shdr(final int mdIdx, final java.nio.ByteBuffer buf) {
+CustomJavaCode Shdr      this.mdIdx = mdIdx;
+CustomJavaCode Shdr      this.md = MachineDataInfo.StaticConfig.values()[mdIdx].md;
+CustomJavaCode Shdr      this.accessor = new StructAccessor(buf);
+CustomJavaCode Shdr  }
+
+EmitStruct Ehdr_p1
+EmitStruct Ehdr_p2
 EmitStruct Shdr
 #EmitStruct Sym32
 #EmitStruct Sym64
diff --git a/make/gluegen-cpptasks-base.xml b/make/gluegen-cpptasks-base.xml
index 222cad7..426bfae 100755
--- a/make/gluegen-cpptasks-base.xml
+++ b/make/gluegen-cpptasks-base.xml
@@ -21,7 +21,7 @@
    -   isI386
    -   isAMD64
    -   is64Bit
-   -   isAbiEabiGnuArmel (implicit if isAndroidARMv6 or isLinuxARMv6)
+   -   isAbiEabiGnuArmel (implicit if isAndroidARMv6 or isAndroidARM64)
    -   isAbiEabiGnuArmhf (shall be declared explicit)
    -   isUnix
    -   isX11
@@ -32,6 +32,7 @@
    -   isIA64
    -   isAndroid
    -   isAndroidARMv6
+   -   isAndroidARM64
    -   isAndroidARMv6Armel (set in gluegen.cpptasks.detected.os.2)
    -   isAndroidARMv6Armhf (set in gluegen.cpptasks.detected.os.2)
    -   isLinux
@@ -39,6 +40,7 @@
    -   isLinuxIA64
    -   isLinuxX86
    -   isLinuxARMv6
+   -   isLinuxARM64
    -   isLinuxARMv6Armel   (set in gluegen.cpptasks.detected.os.2)
    -   isLinuxARMv6Armhf   (set in gluegen.cpptasks.detected.os.2)
    -   isLinuxAlpha
@@ -125,6 +127,7 @@
    -   compiler.cfg.linux.x86
    -   compiler.cfg.linux.amd64
    -   compiler.cfg.linux.armv6
+   -   compiler.cfg.linux.aarch64
    -   compiler.cfg.linux.alpha
    -   compiler.cfg.linux.hppa
    -   compiler.cfg.linux.mips
@@ -146,6 +149,7 @@
    -   linker.cfg.linux.x86
    -   linker.cfg.linux.amd64
    -   linker.cfg.linux.armv6
+   -   linker.cfg.linux.aarch64
    -   linker.cfg.linux.alpha
    -   linker.cfg.linux.hppa
    -   linker.cfg.linux.mips
@@ -255,6 +259,8 @@
         <istrue value="${isAMD64}" />
         <os arch="IA64" />
         <os arch="sparcv9" />
+        <os arch="armv8a" />
+        <os arch="aarch64" />
       </or>
     </condition>
 
@@ -324,6 +330,15 @@
         </or>
       </and>
     </condition>
+    <condition property="isAndroidARM64">
+      <and>
+        <istrue value="${isAndroid}" />
+        <or>
+            <os arch="armv8a" />
+            <os arch="aarch64" />
+        </or>
+      </and>
+    </condition>
     <condition property="isLinuxARMv6">
       <and>
         <istrue value="${isLinux}" />
@@ -334,12 +349,23 @@
         </or>
       </and>
     </condition>
+    <condition property="isLinuxARM64">
+      <and>
+        <istrue value="${isLinux}" />
+        <or>
+            <os arch="armv8a" />
+            <os arch="aarch64" />
+        </or>
+      </and>
+    </condition>
     <condition property="isAbiEabiGnuArmel">
       <and>
         <isfalse value="${isAbiEabiGnuArmhf}" />
         <or>
             <istrue value="${isAndroidARMv6}" />
+            <istrue value="${isAndroidARM64}" />
             <istrue value="${isLinuxARMv6}" />
+            <istrue value="${isLinuxARM64}" />
         </or>
       </and>
     </condition>
@@ -559,6 +585,7 @@
     <echo message="IA64=${isIA64}" />
     <echo message="Android=${isAndroid}" />
     <echo message="AndroidARMv6=${isAndroidARMv6}" />
+    <echo message="AndroidARM64=${isAndroidARM64}" />
     <echo message="AndroidARMv6Armel=${isAndroidARMv6Armel}" />
     <echo message="AndroidARMv6Armhf=${isAndroidARMv6Armhf}" />
     <echo message="Linux=${isLinux}" />
@@ -566,6 +593,7 @@
     <echo message="LinuxIA64=${isLinuxIA64}" />
     <echo message="LinuxX86=${isLinuxX86}" />
     <echo message="LinuxARMv6=${isLinuxARMv6}" />
+    <echo message="LinuxARM64=${isLinuxARM64}" />
     <echo message="LinuxARMv6Armel=${isLinuxARMv6Armel}" />
     <echo message="LinuxARMv6Armhf=${isLinuxARMv6Armhf}" />
     <echo message="LinuxAlpha=${isLinuxAlpha}" />
@@ -595,6 +623,8 @@
     <echo message="arch=${os.arch}" /> 
  </target>
 
+ <!-- Consult jogamp.common.os.PlatformPropsImpl.getOSAndArch(..) to complete/sync mapping! -->
+
   <target name="gluegen.cpptasks.detect.os.freebsd.x86" unless="gluegen.cpptasks.detected.os.2" if="isFreeBSDX86">
     <property name="os.and.arch" value="freebsd-i586" />
   </target>
@@ -629,6 +659,10 @@
     <property name="os.and.arch" value="linux-armv6hf" />
   </target>
 
+  <target name="gluegen.cpptasks.detect.os.linux.aarch64" unless="gluegen.cpptasks.detected.os.2" if="isLinuxARM64">
+    <property name="os.and.arch" value="linux-aarch64" />
+  </target>
+
   <target name="gluegen.cpptasks.detect.os.linux.alpha" unless="gluegen.cpptasks.detected.os.2" if="isLinuxAlpha">
     <property name="os.and.arch" value="linux-alpha" />
   </target>
@@ -669,7 +703,11 @@
     <property name="os.and.arch" value="android-armv6hf" />
   </target>
 
-  <target name="gluegen.cpptasks.detect.os.linux" depends="gluegen.cpptasks.detect.os.linux.amd64,gluegen.cpptasks.detect.os.linux.ia64,gluegen.cpptasks.detect.os.linux.x86,gluegen.cpptasks.detect.os.linux.armv6.armel,gluegen.cpptasks.detect.os.linux.armv6.armhf,gluegen.cpptasks.detect.os.android.armv6.armel,gluegen.cpptasks.detect.os.android.armv6.armhf,gluegen.cpptasks.detect.os.linux.alpha,gluegen.cpptasks.detect.os.linux.hppa,gluegen.cpptasks.detect.os.linux.mips,gluegen.cpptasks.det [...]
+  <target name="gluegen.cpptasks.detect.os.android.aarch64" unless="gluegen.cpptasks.detected.os.2" if="isAndroidARM64">
+    <property name="os.and.arch" value="android-aarch64" />
+  </target>
+
+  <target name="gluegen.cpptasks.detect.os.linux" depends="gluegen.cpptasks.detect.os.linux.amd64,gluegen.cpptasks.detect.os.linux.ia64,gluegen.cpptasks.detect.os.linux.x86,gluegen.cpptasks.detect.os.linux.armv6.armel,gluegen.cpptasks.detect.os.linux.armv6.armhf,gluegen.cpptasks.detect.os.android.armv6.armel,gluegen.cpptasks.detect.os.linux.aarch64,gluegen.cpptasks.detect.os.android.armv6.armhf,gluegen.cpptasks.detect.os.android.aarch64,gluegen.cpptasks.detect.os.linux.alpha,gluegen.cppt [...]
 
   <target name="gluegen.cpptasks.detect.os.osx" unless="gluegen.cpptasks.detected.os.2" if="isOSX">
     <property name="native.library.suffix"     value="*lib" />
@@ -950,6 +988,8 @@
       <compilerarg value="-fPIC"/>
       <compilerarg value="-m64"/>
       <defineset>
+        <define name="__LP64__" />     <!-- default pre-defined macro for 64bit unix -->
+
         <define name="__unix__"/>
         <define name="__X11__"  if="isX11"/>
         <define name="_DEBUG"   if="c.compiler.use-debug"/>        
@@ -977,6 +1017,22 @@
       <compilerarg value="${gluegen.root.abs-path}/make/stub_includes/platform/glibc-compat-symbols.h" />
     </compiler>
 
+    <compiler id="compiler.cfg.linux.aarch64" name="${gcc.compat.compiler}">
+      <defineset>
+        <define name="__LP64__" />     <!-- default pre-defined macro for 64bit unix -->
+        <define name="__aarch64__" />  <!-- default pre-defined macro for armv8-a, 64bit -->
+
+        <define name="__unix__"/>
+        <define name="__X11__"  if="isX11"/>
+        <define name="_DEBUG"   if="c.compiler.use-debug"/>        
+        <define name="DEBUG"    if="c.compiler.use-debug"/>        
+        <define name="NDEBUG"   unless="c.compiler.use-debug"/>        
+      </defineset>
+      <compilerarg value="-fpic" /> 
+      <compilerarg value="-include"/>
+      <compilerarg value="${gluegen.root.abs-path}/make/stub_includes/platform/glibc-compat-symbols.h" />
+    </compiler>
+
     <compiler id="compiler.cfg.android" name="${gcc.compat.compiler}">
         <!-- shall be defined in custom ${gluegen-cpptasks.file} ! -->
     </compiler>
@@ -1055,6 +1111,8 @@
       <!-- compilerarg value="-xarch=amd64" / --> 
       <!-- compilerarg value="-xcache=64/64/2:1024/64/16" / --> 
       <defineset> 
+        <define name="__LP64__" />     <!-- default pre-defined macro for 64bit unix -->
+
         <define name="__unix__"/>
         <define name="__X11__"  if="isX11"/>
         <define name="_DEBUG"   if="c.compiler.use-debug"/>
@@ -1188,6 +1246,13 @@
       <linkerarg value="-static-libgcc" if="isGCC"/>
     </linker>
 
+    <linker id="linker.cfg.linux.aarch64" name="${gcc.compat.compiler}">
+      <linkerarg value="-fpic" /> 
+      <linkerarg value="-nostdlib" />
+      <linkerarg value="-Bdynamic" />
+      <linkerarg value="-static-libgcc" if="isGCC"/>
+    </linker>
+
     <linker id="linker.cfg.linux.alpha" name="${gcc.compat.compiler}">
     </linker>
 
@@ -1390,6 +1455,13 @@
       <property name="java.lib.dir.platform"         value="${java.home.dir}/jre/lib/arm" />
     </target>
 
+    <target name="gluegen.cpptasks.declare.compiler.linux.aarch64" if="isLinuxARM64">
+      <echo message="Linux.aarch64" />
+      <property name="compiler.cfg.id.base"          value="compiler.cfg.linux.aarch64" /> 
+      <property name="linker.cfg.id.base"            value="linker.cfg.linux.aarch64" /> 
+      <property name="java.lib.dir.platform"         value="${java.home.dir}/jre/lib/arm" />
+    </target>
+
     <target name="gluegen.cpptasks.declare.compiler.linux.ia64" if="isLinuxIA64">
       <echo message="Linux.IA64" />
       <property name="compiler.cfg.id.base"          value="compiler.cfg.linux" /> 
@@ -1446,7 +1518,7 @@
       <property name="java.lib.dir.platform"         value="${java.home.dir}/jre/lib/sparc" />
     </target>
 
-    <target name="gluegen.cpptasks.declare.compiler.linux" depends="gluegen.cpptasks.declare.compiler.linux.x86,gluegen.cpptasks.declare.compiler.linux.amd64,gluegen.cpptasks.declare.compiler.linux.ia64,gluegen.cpptasks.declare.compiler.linux.armv6,gluegen.cpptasks.declare.compiler.linux.alpha,gluegen.cpptasks.declare.compiler.linux.hppa,gluegen.cpptasks.declare.compiler.linux.mips,gluegen.cpptasks.declare.compiler.linux.mipsel,gluegen.cpptasks.declare.compiler.linux.ppc,gluegen.cpptasks [...]
+    <target name="gluegen.cpptasks.declare.compiler.linux" depends="gluegen.cpptasks.declare.compiler.linux.x86,gluegen.cpptasks.declare.compiler.linux.amd64,gluegen.cpptasks.declare.compiler.linux.ia64,gluegen.cpptasks.declare.compiler.linux.armv6,gluegen.cpptasks.declare.compiler.linux.aarch64,gluegen.cpptasks.declare.compiler.linux.alpha,gluegen.cpptasks.declare.compiler.linux.hppa,gluegen.cpptasks.declare.compiler.linux.mips,gluegen.cpptasks.declare.compiler.linux.mipsel,gluegen.cppt [...]
         <property name="java.includes.dir.platform" value="${java.includes.dir}/linux" />
     </target>
 
diff --git a/make/jogamp-androidtasks.xml b/make/jogamp-androidtasks.xml
index 30d8dc0..24aea10 100644
--- a/make/jogamp-androidtasks.xml
+++ b/make/jogamp-androidtasks.xml
@@ -7,6 +7,22 @@
       </classpath>
     </taskdef>
 
+    <target name="test.regexp1" >
+        <property name="jarbasename" value="gluegen-rt-android" />
+        <propertyregex property="m.aapt.apkbasename0"
+              input="${jarbasename}"
+              regexp="(.*)(-android$)"
+              select="\1"
+              casesensitive="true" />
+        <condition property="m.aapt.apkbasename1" value="${m.aapt.apkbasename0}" else="${jarbasename}">
+            <not>
+                <equals arg1="${m.aapt.apkbasename0}" arg2="$${m.aapt.apkbasename0}" casesensitive="true" />
+            </not>
+        </condition>
+        <echo>val: ${jarbasename}</echo>
+        <echo>___: ${m.aapt.apkbasename0}</echo>
+        <echo>res: ${m.aapt.apkbasename1}</echo>
+    </target>
     <!---
         <aapt.signed 
             jarbuilddir="${build}"   // jar build location
@@ -51,27 +67,46 @@
       <attribute name="keystore.keypass" default="${android.keystore.keypass}" />
 
       <sequential>
-        <var name="m.aapt.android.abi.extstr" unset="true"/>
+        <var name="m.aapt.apkbasename0" unset="true"/>
+        <var name="m.aapt.apkbasename1" unset="true"/>
+        <var name="m.aapt.apkbasename" unset="true"/>
         <var name="m.aapt.build.apk" unset="true"/>
         <var name="m.aapt.dex.file" unset="true"/>
         <var name="m.aapt.unsigned.package.file.name" unset="true"/>
         <var name="m.aapt.signed.file.name" unset="true"/>
         <var name="m.aapt.release.file.name" unset="true"/>
         <var name="m.aapt.keystore.file" unset="true"/>
-
         <var name="m.aapt.java.encoding" unset="true"/>
 
-        <condition property="m.aapt.android.abi.extstr" value="-@{android.abi}" else="">
+        <!-- ${m.aapt.apkbasename}: 
+             if ( @{android.abi} != 'generic' ) {
+                ${m.aapt.apkbasename} := ( @{jarbasename} - ( optional postfix '-android' ) ) + ${os.and.arch} ;
+             } else {
+                ${m.aapt.apkbasename} := @{jarbasename} ;
+             }
+              regexp="(.*((\Q\-android\E){0}))(\Q\-android\E)?"
+          -->
+        <propertyregex property="m.aapt.apkbasename0"
+              input="@{jarbasename}"
+              regexp="(.*)(-android$)"
+              select="\1"
+              casesensitive="true" />
+        <condition property="m.aapt.apkbasename1" value="${m.aapt.apkbasename0}" else="@{jarbasename}">
+            <not>
+                <equals arg1="${m.aapt.apkbasename0}" arg2="$${m.aapt.apkbasename0}" casesensitive="true" />
+            </not>
+        </condition>
+        <condition property="m.aapt.apkbasename" value="${m.aapt.apkbasename1}-${os.and.arch}" else="@{jarbasename}">
             <not>
                 <equals arg1="@{android.abi}" arg2="generic" casesensitive="true" />
             </not>
         </condition>
 
-        <property name="m.aapt.build.apk" value="@{jarbuilddir}/@{jarbasename}${m.aapt.android.abi.extstr}.apk.d" />
+        <property name="m.aapt.build.apk" value="@{jarbuilddir}/${m.aapt.apkbasename}.apk.d" />
         <property name="m.aapt.dex.file" location="${m.aapt.build.apk}/image/classes.dex" />
-        <property name="m.aapt.unsigned.package.file.name" value="@{jarbuilddir}/@{jarbasename}${m.aapt.android.abi.extstr}-unsigned.apk" />
-        <property name="m.aapt.signed.file.name" value="${m.aapt.build.apk}/@{jarbasename}${m.aapt.android.abi.extstr}-signed-raw.apk" />
-        <property name="m.aapt.release.file.name" value="@{jarbuilddir}/@{jarbasename}${m.aapt.android.abi.extstr}.apk" />
+        <property name="m.aapt.unsigned.package.file.name" value="@{jarbuilddir}/${m.aapt.apkbasename}-unsigned.apk" />
+        <property name="m.aapt.signed.file.name" value="${m.aapt.build.apk}/${m.aapt.apkbasename}-signed-raw.apk" />
+        <property name="m.aapt.release.file.name" value="@{jarbuilddir}/${m.aapt.apkbasename}.apk" />
 
         <property name="m.aapt.java.encoding" value="UTF-8" />
 
@@ -105,7 +140,7 @@
         <copy file="@{androidmanifest.path}" tofile="${m.aapt.build.apk}/image/AndroidManifest.xml"/>
         <copy file="@{jarmanifest.path}" failonerror="false" tofile="${m.aapt.build.apk}/image/META-INF/MANIFEST.MF"/>
 
-        <echo>aapt.signed @{jarbasename}: generating Android R.java from the resources...</echo>
+        <echo>aapt.signed ${m.aapt.apkbasename}: generating Android R.java from the resources...</echo>
         <exec dir="." executable="aapt" logError="true" failonerror="true" failifexecutionfails="true">
             <arg line="package"/>
             <!-- arg line="-v"/ -->
@@ -121,7 +156,7 @@
             <arg line="${m.aapt.build.apk}/temp/src"/>
         </exec>
 
-        <echo>aapt.signed @{jarbasename}: compiling R.java...</echo>
+        <echo>aapt.signed ${m.aapt.apkbasename}: compiling R.java...</echo>
         <javac encoding="${m.aapt.java.encoding}"
             source="${target.sourcelevel}" 
             target="${target.targetlevel}" 
@@ -137,7 +172,7 @@
             </classpath>
         </javac>
 
-        <echo>aapt.signed @{jarbasename}: dex'ing</echo>
+        <echo>aapt.signed ${m.aapt.apkbasename}: dex'ing</echo>
         <exec dir="." executable="dx" logError="true" failonerror="true" failifexecutionfails="true">
             <arg line="--dex"/>
             <arg line="--output=${m.aapt.dex.file}"/>
@@ -153,7 +188,7 @@
             <pathelement path="${env.ANDROID_HOME}/tools/lib/jarutils.jar" />
         </path>
 
-        <echo>aapt.signed @{jarbasename}: packaging</echo>
+        <echo>aapt.signed ${m.aapt.apkbasename}: packaging</echo>
         <exec dir="." executable="aapt" logError="true" failonerror="true" failifexecutionfails="true">
             <arg line="package"/>
             <!--arg line="-v"/-->
@@ -182,7 +217,7 @@
             <arg line="${m.aapt.build.apk}/image/"/>
         </exec>
         
-        <echo>aapt.signed @{jarbasename}: gen temp keystore @{keystore.alias} @ ${m.aapt.build.apk}/debug.keystore</echo>
+        <echo>aapt.signed ${m.aapt.apkbasename}: gen temp keystore @{keystore.alias} @ ${m.aapt.build.apk}/debug.keystore</echo>
         <exec dir="." executable="keytool" failonerror="true">
             <arg value="-genkey"/>
 
@@ -211,7 +246,7 @@
         </exec>
 
         <!-- Be Java6 keytool/jarsigner compatible, and hence Android compatible -->
-        <echo>aapt.signed @{jarbasename}: signing w/ key @{keystore.alias} @ ${m.aapt.keystore.file}</echo>
+        <echo>aapt.signed ${m.aapt.apkbasename}: signing w/ key @{keystore.alias} @ ${m.aapt.keystore.file}</echo>
         <!-- signjar
               sigalg="MD5withRSA"
               digestalg="SHA1"
@@ -246,8 +281,8 @@
             <arg value="@{keystore.alias}" />
         </exec>
 
-        <echo>aapt.signed @{jarbasename}: zip aligning</echo>
-        <exec dir="." executable="${env.ANDROID_HOME}/tools/zipalign" failonerror="true">
+        <echo>aapt.signed ${m.aapt.apkbasename}: zip aligning</echo>
+        <exec dir="." executable="${env.ANDROID_HOME}/build-tools/${env.ANDROID_BUILD_TOOLS_VERSION}/zipalign" failonerror="true">
             <arg line="-v" />
             <arg value="-f" />
             <arg value="4" />
diff --git a/make/jogamp-env.xml b/make/jogamp-env.xml
index 80bf5ae..42bd1eb 100755
--- a/make/jogamp-env.xml
+++ b/make/jogamp-env.xml
@@ -49,11 +49,12 @@
         <condition>
             <not>
                 <or>
-                    <contains string="${ant.java.version}" substring="1.6" casesensitive="false" />
-                    <contains string="${ant.java.version}" substring="1.7" casesensitive="false" />
-                    <contains string="${ant.java.version}" substring="1.8" casesensitive="false" />
-                    <contains string="${ant.java.version}" substring="1.9" casesensitive="false" />
-                    <contains string="${ant.java.version}" substring="2.0" casesensitive="false" />
+                    <equals arg1="${ant.java.version}" arg2="1.6"/>
+                    <equals arg1="${ant.java.version}" arg2="1.7"/>
+                    <equals arg1="${ant.java.version}" arg2="1.8"/>
+                    <equals arg1="${ant.java.version}" arg2="1.9"/>
+                    <equals arg1="${ant.java.version}" arg2="2.0"/>
+                    <equals arg1="${ant.java.version}" arg2="2.1"/>
                 </or>
             </not>
         </condition>
@@ -68,6 +69,16 @@
         <format property="version.timestamp" pattern="yyyyMMdd"/>
     </tstamp>
 
+    <condition property="javadoc.xarg1" value="-Xdoclint:none" else="-J-Ddummy=val">
+        <or>
+            <equals arg1="${ant.java.version}" arg2="1.8"/>
+            <equals arg1="${ant.java.version}" arg2="1.9"/>
+            <equals arg1="${ant.java.version}" arg2="2.0"/>
+            <equals arg1="${ant.java.version}" arg2="2.1"/>
+        </or>
+    </condition>
+    <echo message="javadoc.xarg1              ${javadoc.xarg1}"/>
+
     <condition property="jogamp.jar.codebase" value="${env.JOGAMP_JAR_CODEBASE}">
         <not>
          <equals arg1="${env.JOGAMP_JAR_CODEBASE}" arg2="$${env.JOGAMP_JAR_CODEBASE}" casesensitive="true" />
@@ -77,8 +88,8 @@
     <echo message="jogamp.jar.codebase        ${jogamp.jar.codebase}"/>
 
     <property name="jogamp.version.major" value="2"/>
-    <property name="jogamp.version.minor" value="2"/>
-    <property name="jogamp.version.submi" value="4"/>
+    <property name="jogamp.version.minor" value="3"/>
+    <property name="jogamp.version.submi" value="1"/>
     <!-- property name="jogamp.version.devel" value="-rc-${version.timestamp}"/ --> <!-- Devel RC Tag -->
     <property name="jogamp.version.devel" value=""/> <!-- Release tag -->
     <property name="jogamp.version.base"  value="${jogamp.version.major}.${jogamp.version.minor}"/>
@@ -225,6 +236,9 @@
                     <contains string="${target.sourcelevel}" substring="1.6" casesensitive="false" />
                     <contains string="${target.sourcelevel}" substring="1.7" casesensitive="false" />
                     <contains string="${target.sourcelevel}" substring="1.8" casesensitive="false" />
+                    <contains string="${target.sourcelevel}" substring="1.9" casesensitive="false" />
+                    <contains string="${target.sourcelevel}" substring="2.0" casesensitive="false" />
+                    <contains string="${target.sourcelevel}" substring="2.1" casesensitive="false" />
                 </or>
             </not>
         </condition>
@@ -236,6 +250,9 @@
                     <contains string="${target.targetlevel}" substring="1.6" casesensitive="false" />
                     <contains string="${target.targetlevel}" substring="1.7" casesensitive="false" />
                     <contains string="${target.targetlevel}" substring="1.8" casesensitive="false" />
+                    <contains string="${target.targetlevel}" substring="1.9" casesensitive="false" />
+                    <contains string="${target.targetlevel}" substring="2.0" casesensitive="false" />
+                    <contains string="${target.targetlevel}" substring="2.1" casesensitive="false" />
                 </or>
             </not>
         </condition>
diff --git a/make/scripts/adb-install-all-aarch64.sh b/make/scripts/adb-install-all-aarch64.sh
new file mode 100755
index 0000000..7f1de25
--- /dev/null
+++ b/make/scripts/adb-install-all-aarch64.sh
@@ -0,0 +1,2 @@
+adb $* install ../build-android-aarch64/jogamp-android-launcher.apk
+adb $* install ../build-android-aarch64/gluegen-rt-android-aarch64.apk
diff --git a/make/scripts/adb-install-all-armv6.sh b/make/scripts/adb-install-all-armv6.sh
index 866881c..e2754c2 100755
--- a/make/scripts/adb-install-all-armv6.sh
+++ b/make/scripts/adb-install-all-armv6.sh
@@ -1,2 +1,2 @@
 adb $* install ../build-android-armv6/jogamp-android-launcher.apk
-adb $* install ../build-android-armv6/gluegen-rt-android-armeabi.apk
+adb $* install ../build-android-armv6/gluegen-rt-android-armv6.apk
diff --git a/make/scripts/adb-install-all-armv7.sh b/make/scripts/adb-install-all-armv7.sh
deleted file mode 100755
index 9a0e4f7..0000000
--- a/make/scripts/adb-install-all-armv7.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-adb $* install ../build-android-armv7/jogamp-android-launcher.apk
-adb $* install ../build-android-armv7/gluegen-rt-android-armeabi-v7a.apk
diff --git a/make/scripts/adb-reinstall-all-armv7.sh b/make/scripts/adb-reinstall-all-aarch64.sh
similarity index 58%
rename from make/scripts/adb-reinstall-all-armv7.sh
rename to make/scripts/adb-reinstall-all-aarch64.sh
index 2cb7713..e27a1e9 100755
--- a/make/scripts/adb-reinstall-all-armv7.sh
+++ b/make/scripts/adb-reinstall-all-aarch64.sh
@@ -1,5 +1,5 @@
 sdir=`dirname $0`
 
 $sdir/adb-uninstall-all.sh $*
-$sdir/adb-install-all-armv7.sh $*
+$sdir/adb-install-all-aarch64.sh $*
 
diff --git a/make/scripts/crosstest-junit-android-armv7-rel.sh b/make/scripts/crosstest-junit-android-armv7-rel.sh
deleted file mode 100644
index 3d5ada1..0000000
--- a/make/scripts/crosstest-junit-android-armv7-rel.sh
+++ /dev/null
@@ -1,69 +0,0 @@
-#! /bin/bash
-
-export HOST_UID=sven
-export HOST_IP=192.168.0.52
-export HOST_RSYNC_ROOT=PROJECTS/JOGL
-
-export TARGET_UID=jogamp
-export TARGET_IP=beagle02
-export TARGET_ROOT=/projects
-
-export BUILD_DIR=../build-android-armv7
-
-if [ -e /opt-linux-x86/android-sdk-linux_x86 ] ; then
-    export ANDROID_HOME=/opt-linux-x86/android-sdk-linux_x86
-    export PATH=$ANDROID_HOME/platform-tools:$PATH
-fi 
-
-#
-# orig android:
-#   export LD_LIBRARY_PATH /system/lib
-#   export BOOTCLASSPATH /system/framework/core.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/core-junit.jar
-#
-
-#TSTCLASS=com.jogamp.gluegen.test.junit.generation.Test1p1JavaEmitter
-TSTCLASS=com.jogamp.gluegen.test.junit.generation.Test1p2ProcAddressEmitter
-
-LOGFILE=`basename $0 .sh`.log
-
-#  -Djava.class.path=lib/junit.jar:/usr/share/ant/lib/ant.jar:/usr/share/ant/lib/ant-junit.jar:$BUILD_DIR/gluegen.jar:$BUILD_DIR/test/build/gluegen-test.jar \
-#  -Djava.class.path=lib/ant-junit-all.apk:$BUILD_DIR/gluegen-rt.apk \
-#  -Djava.library.path=/system/lib:$TARGET_ROOT/gluegen/make/$BUILD_DIR/obj:$BUILD_DIR/test/build/natives \
-
-RSYNC_EXCLUDES="--exclude 'build-x86*/' --exclude 'build-linux*/' --exclude 'build-win*/' --exclude 'build-mac*/' \
-                --exclude 'classes/' --exclude 'src/' --exclude '.git/' --exclude 'gluegen-java-src.zip' \
-                --delete-excluded"
-
-echo "#! /system/bin/sh" > $BUILD_DIR/targetcommand.sh
-
-echo "\
-rsync -av --delete --delete-after $RSYNC_EXCLUDES $HOST_UID@$HOST_IP::$HOST_RSYNC_ROOT/gluegen $TARGET_ROOT ; \
-cd $TARGET_ROOT/gluegen/make ; \
-export LD_LIBRARY_PATH=/system/lib:$TARGET_ROOT/gluegen/make/$BUILD_DIR/obj:$TARGET_ROOT/gluegen/make/$BUILD_DIR/test/build/natives ; \
-export BOOTCLASSPATH=/system/framework/core.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar ; \
-dalvikvm \
-  -Xjnigreflimit:2000 \
-  -cp ../make/lib/ant-junit-all.apk:../build-android-armv7/gluegen.apk:../build-android-armv7/test/build/gluegen-test.apk \
-  -Djogamp.debug.JNILibLoader=true \
-  -Djogamp.debug.NativeLibrary=true \
-  -Djogamp.debug.NativeLibrary.Lookup=true \
-  -Djogamp.debug.ProcAddressHelper=true \
-  com.android.internal.util.WithFramework \
-  org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner \
-  $TSTCLASS \
-  filtertrace=true \
-  haltOnError=false \
-  haltOnFailure=false \
-  showoutput=true \
-  outputtoformatters=true \
-  logfailedtests=true \
-  logtestlistenerevents=true \
-  formatter=org.apache.tools.ant.taskdefs.optional.junit.PlainJUnitResultFormatter \
-  formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,./TEST-result.xml \
-" >> $BUILD_DIR/targetcommand.sh
-
-chmod ugo+x $BUILD_DIR/targetcommand.sh
-adb push $BUILD_DIR/targetcommand.sh $TARGET_ROOT/targetcommand.sh
-adb shell $TARGET_ROOT/targetcommand.sh 2>&1 | tee $LOGFILE
-adb pull $TARGET_ROOT/gluegen/make/TEST-result.xml TEST-result.xml
-
diff --git a/make/scripts/java-win32.bat b/make/scripts/java-win32.bat
index 4cae57e..5d85976 100755
--- a/make/scripts/java-win32.bat
+++ b/make/scripts/java-win32.bat
@@ -1,21 +1,24 @@
 
 set BLD_SUB=build-win32
-set J2RE_HOME=c:\jre1.7.0_67_x32
-set JAVA_HOME=c:\jdk1.7.0_67_x32
+set J2RE_HOME=c:\jre1.8.0_25_x32
+set JAVA_HOME=c:\jdk1.8.0_25_x32
 set ANT_PATH=C:\apache-ant-1.9.4
 
 set BLD_DIR=..\%BLD_SUB%
 REM set LIB_DIR=..\%BLD_SUB%\obj;..\%BLD_SUB%\test\build\natives
-set LIB_DIR=..\%BLD_SUB%\test\build\natives
+REM set LIB_DIR=..\%BLD_SUB%\test\build\natives
 
-set PATH=%JAVA_HOME%\bin;%ANT_PATH%\bin;c:\mingw\bin;%LIB_DIR%;%PATH%
+REM set PATH=%JAVA_HOME%\bin;%ANT_PATH%\bin;c:\mingw\bin;%LIB_DIR%;%PATH%
+set PATH=%JAVA_HOME%\bin;%ANT_PATH%\bin;c:\mingw\bin;%PATH%
 
 set CP_ALL=.;lib\junit.jar;%ANT_PATH%\lib\ant.jar;%ANT_PATH%\lib\ant-junit.jar;lib/semantic-versioning/semver.jar;%BLD_DIR%\gluegen-rt.jar;%BLD_DIR%\gluegen.jar;%BLD_DIR%\gluegen-test-util.jar;%BLD_DIR%\test\build\gluegen-test.jar
 
 echo CP_ALL %CP_ALL%
 
-set D_ARGS="-Djogamp.debug.Platform" "-Djogamp.debug.NativeLibrary"
+set X_ARGS="-Drootrel.build=%BLD_SUB%" "-Dgluegen.root=.."
+REM set D_ARGS="-Djogamp.debug.Platform" "-Djogamp.debug.NativeLibrary"
 REM set D_ARGS="-Djogamp.debug.IOUtil"
-REM set D_ARGS="-Djogamp.debug=all"
+set D_ARGS="-Djogamp.debug=all"
 
-%J2RE_HOME%\bin\java -classpath %CP_ALL% %D_ARGS% "-Djava.library.path=%LIB_DIR%" "-Dsun.java2d.noddraw=true" "-Dsun.awt.noerasebackground=true" %1 %2 %3 %4 %5 %6 %7 %8 %9 > java-win32.log 2>&1
+REM %J2RE_HOME%\bin\java -classpath %CP_ALL% %X_ARGS% %D_ARGS% "-Djava.library.path=%LIB_DIR%" "-Dsun.java2d.noddraw=true" "-Dsun.awt.noerasebackground=true" %1 %2 %3 %4 %5 %6 %7 %8 %9 > java-win32.log 2>&1
+%J2RE_HOME%\bin\java -classpath %CP_ALL% %X_ARGS% %D_ARGS% "-Dsun.java2d.noddraw=true" "-Dsun.awt.noerasebackground=true" %1 %2 %3 %4 %5 %6 %7 %8 %9 > java-win32.log 2>&1
diff --git a/make/scripts/java-win64.bat b/make/scripts/java-win64.bat
index 27dff84..f5e6bb1 100755
--- a/make/scripts/java-win64.bat
+++ b/make/scripts/java-win64.bat
@@ -1,23 +1,26 @@
 
 set BLD_SUB=build-win64
-set J2RE_HOME=c:\jre1.7.0_67_x64
-set JAVA_HOME=c:\jdk1.7.0_67_x64
+set J2RE_HOME=c:\jre1.8.0_25_x64
+set JAVA_HOME=c:\jdk1.8.0_25_x64
 set ANT_PATH=C:\apache-ant-1.9.4
 
 set BLD_DIR=..\%BLD_SUB%
 REM set LIB_DIR=..\%BLD_SUB%\obj;..\%BLD_SUB%\test\build\natives
-set LIB_DIR=..\%BLD_SUB%\test\build\natives
+REM set LIB_DIR=..\%BLD_SUB%\test\build\natives
 
-set PATH=%JAVA_HOME%\bin;%ANT_PATH%\bin;c:\mingw\bin;%LIB_DIR%;%PATH%
+REM set PATH=%JAVA_HOME%\bin;%ANT_PATH%\bin;c:\mingw\bin;%LIB_DIR%;%PATH%
+set PATH=%JAVA_HOME%\bin;%ANT_PATH%\bin;c:\mingw\bin;%PATH%
 
-set CP_ALL=.;lib\junit.jar;%ANT_PATH%\lib\ant.jar;%ANT_PATH%\lib\ant-junit.jar;lib/semantic-versioning/semver.jar;%BLD_DIR%\gluegen-rt.jar;%BLD_DIR%\gluegen.jar;%BLD_DIR%\gluegen-test-util.jar;%BLD_DIR%\test\build\gluegen-test.jar
+set CP_ALL=.;lib\junit.jar;%ANT_PATH%\lib\ant.jar;%ANT_PATH%\lib\ant-junit.jar;lib/semantic-versioning/semver.jar;lib\TestJarsInJar.jar;%BLD_DIR%\gluegen-rt.jar;%BLD_DIR%\gluegen.jar;%BLD_DIR%\gluegen-test-util.jar;%BLD_DIR%\test\build\gluegen-test.jar
 
 echo CP_ALL %CP_ALL%
 
-set D_ARGS="-Djogamp.debug.IOUtil" "-Djogamp.debug.JNILibLoader" "-Djogamp.debug.TempFileCache" "-Djogamp.debug.JarUtil" "-Djogamp.debug.TempJarCache"
+set X_ARGS="-Drootrel.build=%BLD_SUB%" "-Dgluegen.root=.."
+REM set D_ARGS="-Djogamp.debug.IOUtil" "-Djogamp.debug.JNILibLoader" "-Djogamp.debug.TempFileCache" "-Djogamp.debug.JarUtil" "-Djogamp.debug.TempJarCache"
 REM set D_ARGS="-Djogamp.debug.Platform" "-Djogamp.debug.NativeLibrary" "-Djogamp.debug.IOUtil"
 REM set D_ARGS="-Djogamp.debug.IOUtil"
-REM set D_ARGS="-Djogamp.debug=all"
+set D_ARGS="-Djogamp.debug=all"
 
-%J2RE_HOME%\bin\java -classpath %CP_ALL% %D_ARGS% "-Djava.library.path=%LIB_DIR%" "-Dsun.java2d.noddraw=true" "-Dsun.awt.noerasebackground=true" %1 %2 %3 %4 %5 %6 %7 %8 %9 > java-win64.log 2>&1
+REM %J2RE_HOME%\bin\java -classpath %CP_ALL% %X_ARGS% %D_ARGS% "-Djava.library.path=%LIB_DIR%" "-Dsun.java2d.noddraw=true" "-Dsun.awt.noerasebackground=true" %1 %2 %3 %4 %5 %6 %7 %8 %9 > java-win64.log 2>&1
+%J2RE_HOME%\bin\java -classpath %CP_ALL% %X_ARGS% %D_ARGS% "-Dsun.java2d.noddraw=true" "-Dsun.awt.noerasebackground=true" %1 %2 %3 %4 %5 %6 %7 %8 %9 > java-win64.log 2>&1
 
diff --git a/make/scripts/make.gluegen.all.android-aarch64-cross.sh b/make/scripts/make.gluegen.all.android-aarch64-cross.sh
new file mode 100755
index 0000000..6d46779
--- /dev/null
+++ b/make/scripts/make.gluegen.all.android-aarch64-cross.sh
@@ -0,0 +1,62 @@
+#! /bin/sh
+
+SDIR=`dirname $0` 
+
+if [ -e $SDIR/setenv-build-jogl-x86_64.sh ] ; then
+    . $SDIR/setenv-build-jogl-x86_64.sh
+fi
+
+if [ -e $SDIR/setenv-android-tools.sh ] ; then
+    . $SDIR/setenv-android-tools.sh
+fi
+
+export NODE_LABEL=.
+
+export HOST_UID=jogamp
+# jogamp02 - 10.1.0.122
+export HOST_IP=10.1.0.122
+export HOST_RSYNC_ROOT=PROJECTS/JOGL
+
+export TARGET_UID=jogamp
+export TARGET_IP=panda02
+#export TARGET_IP=jautab03
+#export TARGET_IP=jauphone04
+export TARGET_ADB_PORT=5555
+# needs executable bit (probably su)
+export TARGET_ROOT=/data/projects
+export TARGET_ANT_HOME=/usr/share/ant
+
+export ANDROID_VERSION=21
+export SOURCE_LEVEL=1.6
+export TARGET_LEVEL=1.6
+export TARGET_RT_JAR=/opt-share/jre1.6.0_30/lib/rt.jar
+
+#export GCC_VERSION=4.4.3
+export GCC_VERSION=4.9
+HOST_ARCH=linux-x86_64
+export TARGET_TRIPLE=aarch64-linux-android
+
+export NDK_TOOLCHAIN_ROOT=$NDK_ROOT/toolchains/${TARGET_TRIPLE}-${GCC_VERSION}/prebuilt/${HOST_ARCH}
+export TARGET_PLATFORM_ROOT=${NDK_ROOT}/platforms/android-${ANDROID_VERSION}/arch-arm64
+
+# Need to add toolchain bins to the PATH. 
+# May need to create symbolic links within $NDK_TOOLCHAIN_ROOT/$TARGET_TRIPLE/bin
+#   cd $NDK_TOOLCHAIN_ROOT/$TARGET_TRIPLE/bin
+#   ln -s ../../bin/aarch64-linux-android-gcc gcc
+export PATH="$NDK_TOOLCHAIN_ROOT/$TARGET_TRIPLE/bin:$ANDROID_HOME/platform-tools:$ANDROID_HOME/build-tools/$ANDROID_BUILD_TOOLS_VERSION:$PATH"
+
+export GLUEGEN_CPPTASKS_FILE="lib/gluegen-cpptasks-android-aarch64.xml"
+
+#export JUNIT_DISABLED="true"
+#export JUNIT_RUN_ARG0="-Dnewt.test.Screen.disableScreenMode"
+
+echo PATH $PATH 2>&1 | tee make.gluegen.all.android-aarch64-cross.log
+echo gcc `which gcc` 2>&1 | tee -a make.gluegen.all.android-aarch64-cross.log
+
+#export JOGAMP_JAR_CODEBASE="Codebase: *.jogamp.org"
+export JOGAMP_JAR_CODEBASE="Codebase: *.goethel.localnet"
+
+#BUILD_ARCHIVE=true \
+ant \
+    -Drootrel.build=build-android-aarch64 \
+    $* 2>&1 | tee -a make.gluegen.all.android-aarch64-cross.log
diff --git a/make/scripts/make.gluegen.all.android-armv6-cross.sh b/make/scripts/make.gluegen.all.android-armv6-cross.sh
index 8c9f0f4..7c3043f 100755
--- a/make/scripts/make.gluegen.all.android-armv6-cross.sh
+++ b/make/scripts/make.gluegen.all.android-armv6-cross.sh
@@ -6,6 +6,10 @@ if [ -e $SDIR/setenv-build-jogl-x86_64.sh ] ; then
     . $SDIR/setenv-build-jogl-x86_64.sh
 fi
 
+if [ -e $SDIR/setenv-android-tools.sh ] ; then
+    . $SDIR/setenv-android-tools.sh
+fi
+
 export NODE_LABEL=.
 
 export HOST_UID=jogamp
@@ -22,70 +26,21 @@ export TARGET_ADB_PORT=5555
 export TARGET_ROOT=/data/projects
 export TARGET_ANT_HOME=/usr/share/ant
 
-echo ANDROID_HOME $ANDROID_HOME
-echo NDK_ROOT $NDK_ROOT
-
-if [ -z "$NDK_ROOT" ] ; then
-    #
-    # Generic android-ndk
-    #
-    if [ -e /usr/local/android-ndk ] ; then
-        NDK_ROOT=/usr/local/android-ndk
-    elif [ -e /opt-linux-x86/android-ndk ] ; then
-        NDK_ROOT=/opt-linux-x86/android-ndk
-    elif [ -e /opt/android-ndk ] ; then
-        NDK_ROOT=/opt/android-ndk
-    #
-    # Specific android-ndk-r8d
-    #
-    elif [ -e /usr/local/android-ndk-r8d ] ; then
-        NDK_ROOT=/usr/local/android-ndk-r8d
-    elif [ -e /opt-linux-x86/android-ndk-r8d ] ; then
-        NDK_ROOT=/opt-linux-x86/android-ndk-r8d
-    elif [ -e /opt/android-ndk-r8d ] ; then
-        NDK_ROOT=/opt/android-ndk-r8d
-    else 
-        echo NDK_ROOT is not specified and does not exist in default locations
-        exit 1
-    fi
-elif [ ! -e $NDK_ROOT ] ; then
-    echo NDK_ROOT $NDK_ROOT does not exist
-    exit 1
-fi
-export NDK_ROOT
-
-if [ -z "$ANDROID_HOME" ] ; then
-    if [ -e /usr/local/android-sdk-linux_x86 ] ; then
-        ANDROID_HOME=/usr/local/android-sdk-linux_x86
-    elif [ -e /opt-linux-x86/android-sdk-linux_x86 ] ; then
-        ANDROID_HOME=/opt-linux-x86/android-sdk-linux_x86
-    elif [ -e /opt/android-sdk-linux_x86 ] ; then
-        ANDROID_HOME=/opt/android-sdk-linux_x86
-    else 
-        echo ANDROID_HOME is not specified and does not exist in default locations
-        exit 1
-    fi
-elif [ ! -e $ANDROID_HOME ] ; then
-    echo ANDROID_HOME $ANDROID_HOME does not exist
-    exit 1
-fi
-export ANDROID_HOME
-
 export ANDROID_VERSION=9
 export SOURCE_LEVEL=1.6
 export TARGET_LEVEL=1.6
 export TARGET_RT_JAR=/opt-share/jre1.6.0_30/lib/rt.jar
 
 #export GCC_VERSION=4.4.3
-export GCC_VERSION=4.7
-HOST_ARCH=linux-x86
+export GCC_VERSION=4.8
+HOST_ARCH=linux-x86_64
 export TARGET_TRIPLE=arm-linux-androideabi
 
 export NDK_TOOLCHAIN_ROOT=$NDK_ROOT/toolchains/${TARGET_TRIPLE}-${GCC_VERSION}/prebuilt/${HOST_ARCH}
 export TARGET_PLATFORM_ROOT=${NDK_ROOT}/platforms/android-${ANDROID_VERSION}/arch-arm
 
 # Need to add toolchain bins to the PATH. 
-export PATH="$NDK_TOOLCHAIN_ROOT/$TARGET_TRIPLE/bin:$ANDROID_HOME/platform-tools:$ANDROID_HOME/build-tools/17.0.0:$PATH"
+export PATH="$NDK_TOOLCHAIN_ROOT/$TARGET_TRIPLE/bin:$ANDROID_HOME/platform-tools:$ANDROID_HOME/build-tools/$ANDROID_BUILD_TOOLS_VERSION:$PATH"
 
 export GLUEGEN_CPPTASKS_FILE="lib/gluegen-cpptasks-android-armv6.xml"
 
diff --git a/make/scripts/make.gluegen.all.android-armv7-cross.sh b/make/scripts/make.gluegen.all.android-armv7-cross.sh
deleted file mode 100755
index f79b904..0000000
--- a/make/scripts/make.gluegen.all.android-armv7-cross.sh
+++ /dev/null
@@ -1,101 +0,0 @@
-#! /bin/sh
-
-if [ -e $SDIR/setenv-build-jogl-x86_64.sh ] ; then
-    . $SDIR/setenv-build-jogl-x86_64.sh
-fi
-
-export NODE_LABEL=.
-
-export HOST_UID=jogamp
-# jogamp02 - 10.1.0.122
-export HOST_IP=10.1.0.122
-export HOST_RSYNC_ROOT=PROJECTS/JOGL
-
-export TARGET_UID=jogamp
-export TARGET_IP=panda02
-#export TARGET_IP=jautab03
-#export TARGET_IP=jauphone04
-export TARGET_ADB_PORT=5555
-# needs executable bit (probably su)
-export TARGET_ROOT=/data/projects
-export TARGET_ANT_HOME=/usr/share/ant
-
-echo ANDROID_HOME $ANDROID_HOME
-echo NDK_ROOT $NDK_ROOT
-
-if [ -z "$NDK_ROOT" ] ; then
-    #
-    # Generic android-ndk
-    #
-    if [ -e /usr/local/android-ndk ] ; then
-        NDK_ROOT=/usr/local/android-ndk
-    elif [ -e /opt-linux-x86/android-ndk ] ; then
-        NDK_ROOT=/opt-linux-x86/android-ndk
-    elif [ -e /opt/android-ndk ] ; then
-        NDK_ROOT=/opt/android-ndk
-    #
-    # Specific android-ndk-r8d
-    #
-    elif [ -e /usr/local/android-ndk-r8d ] ; then
-        NDK_ROOT=/usr/local/android-ndk-r8d
-    elif [ -e /opt-linux-x86/android-ndk-r8d ] ; then
-        NDK_ROOT=/opt-linux-x86/android-ndk-r8d
-    elif [ -e /opt/android-ndk-r8d ] ; then
-        NDK_ROOT=/opt/android-ndk-r8d
-    else 
-        echo NDK_ROOT is not specified and does not exist in default locations
-        exit 1
-    fi
-elif [ ! -e $NDK_ROOT ] ; then
-    echo NDK_ROOT $NDK_ROOT does not exist
-    exit 1
-fi
-export NDK_ROOT
-
-if [ -z "$ANDROID_HOME" ] ; then
-    if [ -e /usr/local/android-sdk-linux_x86 ] ; then
-        ANDROID_HOME=/usr/local/android-sdk-linux_x86
-    elif [ -e /opt-linux-x86/android-sdk-linux_x86 ] ; then
-        ANDROID_HOME=/opt-linux-x86/android-sdk-linux_x86
-    elif [ -e /opt/android-sdk-linux_x86 ] ; then
-        ANDROID_HOME=/opt/android-sdk-linux_x86
-    else 
-        echo ANDROID_HOME is not specified and does not exist in default locations
-        exit 1
-    fi
-elif [ ! -e $ANDROID_HOME ] ; then
-    echo ANDROID_HOME $ANDROID_HOME does not exist
-    exit 1
-fi
-export ANDROID_HOME
-
-export ANDROID_VERSION=9
-export SOURCE_LEVEL=1.6
-export TARGET_LEVEL=1.6
-export TARGET_RT_JAR=/opt-share/jre1.6.0_30/lib/rt.jar
-
-#export GCC_VERSION=4.4.3
-export GCC_VERSION=4.7
-HOST_ARCH=linux-x86
-export TARGET_TRIPLE=arm-linux-androideabi
-
-export NDK_TOOLCHAIN_ROOT=$NDK_ROOT/toolchains/${TARGET_TRIPLE}-${GCC_VERSION}/prebuilt/${HOST_ARCH}
-export TARGET_PLATFORM_ROOT=${NDK_ROOT}/platforms/android-${ANDROID_VERSION}/arch-arm
-
-# Need to add toolchain bins to the PATH. 
-export PATH="$NDK_TOOLCHAIN_ROOT/$TARGET_TRIPLE/bin:$ANDROID_HOME/platform-tools:$PATH"
-
-export GLUEGEN_CPPTASKS_FILE="lib/gluegen-cpptasks-android-armv7.xml"
-
-#export JUNIT_DISABLED="true"
-#export JUNIT_RUN_ARG0="-Dnewt.test.Screen.disableScreenMode"
-
-which gcc 2>&1 | tee make.gluegen.all.android-armv7-cross.log
-
-#export JOGAMP_JAR_CODEBASE="Codebase: *.jogamp.org"
-export JOGAMP_JAR_CODEBASE="Codebase: *.goethel.localnet"
-
-#BUILD_ARCHIVE=true \
-ant \
-    -Drootrel.build=build-android-armv7 \
-    $* 2>&1 | tee -a make.gluegen.all.android-armv7-cross.log
diff --git a/make/scripts/make.gluegen.all.macosx-java7.sh b/make/scripts/make.gluegen.all.macosx-java6.sh
similarity index 58%
rename from make/scripts/make.gluegen.all.macosx-java7.sh
rename to make/scripts/make.gluegen.all.macosx-java6.sh
index 3ea0cc3..0a5a8f2 100755
--- a/make/scripts/make.gluegen.all.macosx-java7.sh
+++ b/make/scripts/make.gluegen.all.macosx-java6.sh
@@ -10,13 +10,20 @@ fi
 #    -Dtarget.targetlevel=1.6 \
 #    -Dtarget.rt.jar=/opt-share/jre1.6.0_30/lib/rt.jar \
 
-JAVA_HOME=`/usr/libexec/java_home -version 1.7`
+# Force OSX SDK 10.6, if desired
+# export SDKROOT=macosx10.6
+
+JAVA_HOME=`/usr/libexec/java_home -version 1.6`
 PATH=$JAVA_HOME/bin:$PATH
 export JAVA_HOME PATH
 
+export SOURCE_LEVEL=1.6
+export TARGET_LEVEL=1.6
+export TARGET_RT_JAR=/opt-share/jre1.6.0_30/lib/rt.jar
+
 #export JOGAMP_JAR_CODEBASE="Codebase: *.jogamp.org"
 export JOGAMP_JAR_CODEBASE="Codebase: *.goethel.localnet"
 
 ant \
-    -Drootrel.build=build-macosx-java7 \
-    $* 2>&1 | tee make.gluegen.all.macosx-java7.log
+    -Drootrel.build=build-macosx \
+    $* 2>&1 | tee make.gluegen.all.macosx.log
diff --git a/make/scripts/make.gluegen.all.macosx.sh b/make/scripts/make.gluegen.all.macosx.sh
index aa81ee9..808afac 100755
--- a/make/scripts/make.gluegen.all.macosx.sh
+++ b/make/scripts/make.gluegen.all.macosx.sh
@@ -10,7 +10,10 @@ fi
 #    -Dtarget.targetlevel=1.6 \
 #    -Dtarget.rt.jar=/opt-share/jre1.6.0_30/lib/rt.jar \
 
-JAVA_HOME=`/usr/libexec/java_home -version 1.7`
+# Force OSX SDK 10.6, if desired
+# export SDKROOT=macosx10.6
+
+JAVA_HOME=`/usr/libexec/java_home -version 1.8`
 PATH=$JAVA_HOME/bin:$PATH
 export JAVA_HOME PATH
 
diff --git a/make/scripts/make.gluegen.all.win32.bat b/make/scripts/make.gluegen.all.win32.bat
index a1f0bac..b421d4c 100755
--- a/make/scripts/make.gluegen.all.win32.bat
+++ b/make/scripts/make.gluegen.all.win32.bat
@@ -1,7 +1,7 @@
 set THISDIR="C:\JOGL"
 
-set J2RE_HOME=c:\jre1.8.0_20_x32
-set JAVA_HOME=c:\jdk1.8.0_20_x32
+set J2RE_HOME=c:\jre1.8.0_25_x32
+set JAVA_HOME=c:\jdk1.8.0_25_x32
 set ANT_PATH=C:\apache-ant-1.9.4
 
 set PATH=%JAVA_HOME%\bin;%ANT_PATH%\bin;c:\mingw\bin;%PATH%
diff --git a/make/scripts/make.gluegen.all.win64.bat b/make/scripts/make.gluegen.all.win64.bat
index cfd2d16..faba4c3 100755
--- a/make/scripts/make.gluegen.all.win64.bat
+++ b/make/scripts/make.gluegen.all.win64.bat
@@ -1,7 +1,7 @@
 set THISDIR="C:\JOGL"
 
-set J2RE_HOME=c:\jre1.8.0_20_x64
-set JAVA_HOME=c:\jdk1.8.0_20_x64
+set J2RE_HOME=c:\jre1.8.0_25_x64
+set JAVA_HOME=c:\jdk1.8.0_25_x64
 set ANT_PATH=C:\apache-ant-1.9.4
 
 set PATH=%JAVA_HOME%\bin;%ANT_PATH%\bin;c:\mingw64\bin;c:\mingw\bin;%PATH%
diff --git a/make/scripts/runtest-x32.bat b/make/scripts/runtest-x32.bat
index 5a2739c..9297d9a 100755
--- a/make/scripts/runtest-x32.bat
+++ b/make/scripts/runtest-x32.bat
@@ -1,8 +1,15 @@
-REM scripts\java-win32.bat com.jogamp.common.GlueGenVersion 
+REM set TEMP=C:\Documents and Settings\jogamp\temp-exec
+REM set TMP=C:\Documents and Settings\jogamp\temp-exec
+REM set TEMP=C:\Users\jogamp\temp-exec
+REM set TMP=C:\Users\jogamp\temp-exec
+
+scripts\java-win32.bat com.jogamp.common.GlueGenVersion 
 REM scripts\java-win32.bat com.jogamp.common.util.TestVersionInfo
 REM scripts\java-win32.bat com.jogamp.gluegen.test.junit.generation.Test1p1JavaEmitter
 REM scripts\java-win32.bat com.jogamp.gluegen.test.junit.generation.Test1p2ProcAddressEmitter
-scripts\java-win32.bat com.jogamp.common.util.TestTempJarCache
+REM scripts\java-win32.bat com.jogamp.common.util.TestTempJarCache
 REM scripts\java-win32.bat com.jogamp.common.os.TestElfReader01
 REM scripts\java-win32.bat com.jogamp.common.util.TestIOUtilURIHandling
+REM scripts\java-win32.bat com.jogamp.common.nio.TestByteBufferInputStream
+REM scripts\java-win32.bat com.jogamp.common.nio.TestByteBufferOutputStream
 
diff --git a/make/scripts/runtest-x64.bat b/make/scripts/runtest-x64.bat
index 6a5d79c..1dfff6f 100755
--- a/make/scripts/runtest-x64.bat
+++ b/make/scripts/runtest-x64.bat
@@ -1,15 +1,26 @@
+REM set TEMP=C:\Documents and Settings\jogamp\temp-exec
+REM set TMP=C:\Documents and Settings\jogamp\temp-exec
+REM set TEMP=C:\Users\jogamp\temp-exec
+REM set TMP=C:\Users\jogamp\temp-exec
+
 REM scripts\java-win64.bat com.jogamp.common.GlueGenVersion 
 REM scripts\java-win64.bat com.jogamp.common.util.TestVersionInfo
+
+scripts\java-win64.bat com.jogamp.gluegen.jcpp.IncludeAbsoluteTest
+
 REM scripts\java-win64.bat com.jogamp.gluegen.test.junit.generation.Test1p1JavaEmitter
 REM scripts\java-win64.bat com.jogamp.gluegen.test.junit.generation.Test1p2ProcAddressEmitter
 REM scripts\java-win64.bat com.jogamp.common.util.TestTempJarCache
 REM scripts\java-win64.bat com.jogamp.common.os.TestElfReader01
 
 REM scripts\java-win64.bat com.jogamp.common.util.TestIOUtil01
-REM scripts\java-win64.bat com.jogamp.common.util.TestIOUtilURICompose
-REM scripts\java-win64.bat com.jogamp.common.util.TestIOUtilURIHandling
+REM scripts\java-win64.bat com.jogamp.common.util.TestJarUtil
 REM scripts\java-win64.bat com.jogamp.common.net.TestUrisWithAssetHandler
 REM scripts\java-win64.bat com.jogamp.common.net.TestURIQueryProps
-scripts\java-win64.bat com.jogamp.common.net.TestNetIOURIReservedCharsBug908
-REM scripts\java-win64.bat com.jogamp.common.util.TestIOUtilURIHandling
+REM scripts\java-win64.bat com.jogamp.common.net.TestUri01
+REM scripts\java-win64.bat com.jogamp.common.net.TestUri02Composing
+REM scripts\java-win64.bat com.jogamp.common.net.TestUri03Resolving
+REM scripts\java-win64.bat com.jogamp.common.net.TestUri99LaunchOnReservedCharPathBug908
 
+REM scripts\java-win64.bat com.jogamp.common.nio.TestByteBufferInputStream
+REM scripts\java-win64.bat com.jogamp.common.nio.TestByteBufferOutputStream
diff --git a/make/scripts/runtest.sh b/make/scripts/runtest.sh
index 4bec5e7..b93eef1 100755
--- a/make/scripts/runtest.sh
+++ b/make/scripts/runtest.sh
@@ -39,6 +39,10 @@ ANT_JARS=$ANT_PATH/lib/ant.jar:$ANT_PATH/lib/ant-junit.jar:$ANT_PATH/lib/ant-lau
 LOG=runtest.log
 rm -f $LOG
 
+GLUEGEN_ROOT=`dirname $builddir`
+ROOTREL_BUILD=`basename $builddir`
+
+X_ARGS="-Drootrel.build=$ROOTREL_BUILD -Dgluegen.root=$GLUEGEN_ROOT"
 #D_ARGS="-Djogamp.debug.ProcAddressHelper -Djogamp.debug.NativeLibrary -Djogamp.debug.NativeLibrary.Lookup"
 #D_ARGS="-Djogamp.debug.TraceLock"
 #D_ARGS="-Djogamp.debug.Platform -Djogamp.debug.NativeLibrary"
@@ -46,7 +50,9 @@ rm -f $LOG
 #D_ARGS="-Djogamp.debug.TempJarCache"
 #D_ARGS="-Djogamp.debug.TempFileCache"
 #D_ARGS="-Djogamp.debug.IOUtil -Djogamp.debug.JNILibLoader -Djogamp.debug.TempFileCache -Djogamp.debug.JarUtil -Djava.io.tmpdir=/run/tmp"
-D_ARGS="-Djogamp.debug.IOUtil -Djogamp.debug.JNILibLoader -Djogamp.debug.TempFileCache -Djogamp.debug.JarUtil -Djogamp.debug.TempJarCache"
+#D_ARGS="-Djogamp.debug.IOUtil -Djogamp.debug.JNILibLoader -Djogamp.debug.TempFileCache -Djogamp.debug.JarUtil -Djogamp.debug.TempJarCache"
+#D_ARGS="-Djogamp.debug.IOUtil -Djogamp.debug.JarUtil -Djogamp.debug.TempJarCache -Djogamp.debug.Uri -Djogamp.debug.Uri.ShowFix"
+#D_ARGS="-Djogamp.debug.Uri -Djogamp.debug.Uri.ShowFix"
 #D_ARGS="-Djogamp.debug.JNILibLoader -Djogamp.gluegen.UseTempJarCache=false"
 #D_ARGS="-Djogamp.debug.JNILibLoader -Djogamp.debug.TempJarCache"
 #D_ARGS="-Djogamp.debug.JNILibLoader"
@@ -54,8 +60,10 @@ D_ARGS="-Djogamp.debug.IOUtil -Djogamp.debug.JNILibLoader -Djogamp.debug.TempFil
 #D_ARGS="-Djogamp.debug.Lock -Djogamp.debug.Lock.TraceLock"
 #D_ARGS="-Djogamp.debug.Lock.TraceLock"
 #D_ARGS="-Djogamp.debug.IOUtil"
+#D_ARGS="-Djogamp.debug.ByteBufferInputStream"
 #D_ARGS="-Djogamp.debug.Bitstream"
 #D_ARGS="-Djogamp.debug=all"
+#D_ARGS="-Djogamp.debug.Logging"
 
 function onetest() {
     #USE_CLASSPATH=lib/junit.jar:$ANT_JARS:lib/semantic-versioning/semver.jar:"$builddir"/../make/lib/TestJarsInJar.jar:"$builddir"/gluegen-rt.jar:"$builddir"/gluegen.jar:"$builddir"/gluegen-test-util.jar:"$builddir"/test/build/gluegen-test.jar
@@ -70,11 +78,11 @@ function onetest() {
     echo LD_LIBRARY_PATH $LD_LIBRARY_PATH
     echo USE_CLASSPATH $USE_CLASSPATH
     which java
-    #echo java -cp $USE_CLASSPATH $D_ARGS -Djava.library.path=$libspath $*
-    #java -cp $USE_CLASSPATH $D_ARGS -Djava.library.path="$libspath" $*
-    echo java -cp "$USE_CLASSPATH" $D_ARGS $*
-    java -cp "$USE_CLASSPATH" $D_ARGS $*
-    #j3 -cp "$USE_CLASSPATH" $D_ARGS $*
+    #echo java -cp $USE_CLASSPATH $X_ARGS $D_ARGS -Djava.library.path=$libspath $*
+    #java -cp $USE_CLASSPATH $X_ARGS $D_ARGS -Djava.library.path="$libspath" $*
+    echo java -cp "$USE_CLASSPATH" $X_ARGS $D_ARGS $*
+    java -cp "$USE_CLASSPATH" $X_ARGS $D_ARGS $*
+    #j3 -cp "$USE_CLASSPATH" $X_ARGS $D_ARGS $*
     echo
 }
 #
@@ -82,7 +90,7 @@ function onetest() {
 #onetest com.jogamp.common.util.TestSystemPropsAndEnvs 2>&1 | tee -a $LOG
 #onetest com.jogamp.common.util.TestVersionInfo 2>&1 | tee -a $LOG
 #onetest com.jogamp.common.util.TestVersionNumber 2>&1 | tee -a $LOG
-#onetest com.jogamp.common.util.TestVersionSemantics 2>&1 | tee -a $LOG
+onetest com.jogamp.common.util.TestVersionSemantics 2>&1 | tee -a $LOG
 #onetest com.jogamp.common.util.TestIteratorIndexCORE 2>&1 | tee -a $LOG
 #onetest com.jogamp.common.util.locks.TestRecursiveLock01 2>&1 | tee -a $LOG
 #onetest com.jogamp.common.util.locks.TestRecursiveThreadGroupLock01 2>&1 | tee -a $LOG
@@ -98,8 +106,6 @@ function onetest() {
 #onetest com.jogamp.common.util.TestPlatform01 2>&1 | tee -a $LOG
 #onetest com.jogamp.common.util.TestRunnableTask01 2>&1 | tee -a $LOG
 #onetest com.jogamp.common.util.TestIOUtil01 2>&1 | tee -a $LOG
-#onetest com.jogamp.common.util.TestIOUtilURICompose 2>&1 | tee -a $LOG
-#onetest com.jogamp.common.util.TestIOUtilURIHandling 2>&1 | tee -a $LOG
 #onetest com.jogamp.common.util.TestTempJarCache 2>&1 | tee -a $LOG
 #onetest com.jogamp.common.util.TestJarUtil 2>&1 | tee -a $LOG
 #onetest com.jogamp.common.util.TestValueConversion 2>&1 | tee -a $LOG
@@ -111,16 +117,29 @@ function onetest() {
 #onetest com.jogamp.common.util.TestBitstream03 2>&1 | tee -a $LOG
 #onetest com.jogamp.common.util.TestBitstream04 2>&1 | tee -a $LOG
 #onetest com.jogamp.common.net.TestUrisWithAssetHandler 2>&1 | tee -a $LOG
-#onetest com.jogamp.common.net.TestURIQueryProps 2>&1 | tee -a $LOG
+#onetest com.jogamp.common.net.TestUriQueryProps 2>&1 | tee -a $LOG
+#onetest com.jogamp.common.net.TestUri01 2>&1 | tee -a $LOG
+#onetest com.jogamp.common.net.TestUri02Composing 2>&1 | tee -a $LOG
+#onetest com.jogamp.common.net.TestUri03Resolving 2>&1 | tee -a $LOG
+#onetest com.jogamp.common.net.TestUri99LaunchOnReservedCharPathBug908 2>&1 | tee -a $LOG
 #onetest com.jogamp.common.net.AssetURLConnectionUnregisteredTest 2>&1 | tee -a $LOG
 #onetest com.jogamp.common.net.AssetURLConnectionRegisteredTest 2>&1 | tee -a $LOG
-onetest com.jogamp.common.net.TestNetIOURIReservedCharsBug908 2>&1 | tee -a $LOG
 #onetest com.jogamp.junit.sec.TestSecIOUtil01 2>&1 | tee -a $LOG
 #onetest com.jogamp.common.nio.TestBuffersFloatDoubleConversion 2>&1 | tee -a $LOG
 #onetest com.jogamp.common.nio.TestPointerBufferEndian 2>&1 | tee -a $LOG
 #onetest com.jogamp.common.nio.TestStructAccessorEndian 2>&1 | tee -a $LOG
-#onetest com.jogamp.common.os.TestElfReader01 2>&1 | tee -a $LOG
-#onetest com.jogamp.gluegen.PCPPTest 2>&1 | tee -a $LOG
+#onetest com.jogamp.common.nio.TestByteBufferInputStream 2>&1 | tee -a $LOG
+#onetest com.jogamp.common.nio.TestByteBufferOutputStream 2>&1 | tee -a $LOG
+#onetest com.jogamp.common.nio.TestByteBufferCopyStream 2>&1 | tee -a $LOG
+#onetest com.jogamp.common.os.TestElfReader01 $* 2>&1 | tee -a $LOG
+#onetest com.jogamp.gluegen.test.junit.internals.TestType 2>&1 | tee -a $LOG
+
+#onetest com.jogamp.gluegen.test.junit.generation.PCPPTest 2>&1 | tee -a $LOG
+#onetest com.jogamp.gluegen.jcpp.IncludeAbsoluteTest 2>&1 | tee -a $LOG
+#onetest com.jogamp.gluegen.jcpp.CppReaderTest 2>&1 | tee -a $LOG
+#onetest com.jogamp.gluegen.jcpp.TokenPastingWhitespaceTest 2>&1 | tee -a $LOG
+#onetest com.jogamp.gluegen.jcpp.PreprocessorTest 2>&1 | tee -a $LOG
+
 #onetest com.jogamp.gluegen.test.junit.generation.Test1p1JavaEmitter 2>&1 | tee -a $LOG
 #onetest com.jogamp.gluegen.test.junit.generation.Test1p2ProcAddressEmitter 2>&1 | tee -a $LOG
 #onetest com.jogamp.gluegen.test.junit.generation.Test1p2LoadJNIAndImplLib 2>&1 | tee -a $LOG
diff --git a/make/scripts/setenv-android-tools.sh b/make/scripts/setenv-android-tools.sh
new file mode 100644
index 0000000..c178e4e
--- /dev/null
+++ b/make/scripts/setenv-android-tools.sh
@@ -0,0 +1,79 @@
+#! /bin/sh
+
+echo $0
+
+echo Presets
+echo   NDK_ROOT $NDK_ROOT
+echo   ANDROID_HOME $ANDROID_HOME
+echo   ANDROID_BUILD_TOOLS_VERSION $ANDROID_BUILD_TOOLS_VERSION
+
+if [ -z "$NDK_ROOT" ] ; then
+    #
+    # Generic android-ndk
+    #
+    if [ -e /usr/local/android-ndk ] ; then
+        NDK_ROOT=/usr/local/android-ndk
+    elif [ -e /opt-linux-x86_64/android-ndk ] ; then
+        NDK_ROOT=/opt-linux-x86_64/android-ndk
+    elif [ -e /opt-linux-x86/android-ndk ] ; then
+        NDK_ROOT=/opt-linux-x86/android-ndk
+    elif [ -e /opt/android-ndk ] ; then
+        NDK_ROOT=/opt/android-ndk
+    #
+    # Specific android-ndk-r10d
+    #
+    elif [ -e /usr/local/android-ndk-r10d ] ; then
+        NDK_ROOT=/usr/local/android-ndk-r10d
+    elif [ -e /opt-linux-x86_64/android-ndk-r10d ] ; then
+        NDK_ROOT=/opt-linux-x86_64/android-ndk-r10d
+    elif [ -e /opt-linux-x86/android-ndk-r10d ] ; then
+        NDK_ROOT=/opt-linux-x86/android-ndk-r10d
+    elif [ -e /opt/android-ndk-r10d ] ; then
+        NDK_ROOT=/opt/android-ndk-r10d
+    else 
+        echo NDK_ROOT is not specified and does not exist in default locations
+        exit 1
+    fi
+elif [ ! -e $NDK_ROOT ] ; then
+    echo NDK_ROOT $NDK_ROOT does not exist
+    exit 1
+fi
+export NDK_ROOT
+
+if [ -z "$ANDROID_HOME" ] ; then
+    if [ -e /usr/local/android-sdk-linux_x86 ] ; then
+        ANDROID_HOME=/usr/local/android-sdk-linux_x86
+    elif [ -e /opt-linux-x86/android-sdk-linux_x86 ] ; then
+        ANDROID_HOME=/opt-linux-x86/android-sdk-linux_x86
+    elif [ -e /opt/android-sdk-linux_x86 ] ; then
+        ANDROID_HOME=/opt/android-sdk-linux_x86
+    else 
+        echo ANDROID_HOME is not specified and does not exist in default locations
+        exit 1
+    fi
+elif [ ! -e $ANDROID_HOME ] ; then
+    echo ANDROID_HOME $ANDROID_HOME does not exist
+    exit 1
+fi
+export ANDROID_HOME
+
+if [ -z "$ANDROID_BUILD_TOOLS_VERSION" ] ; then
+    if [ -e $ANDROID_HOME/build-tools/21.1.2/zipalign ] ; then
+        ANDROID_BUILD_TOOLS_VERSION=21.1.2
+    elif [ -e $ANDROID_HOME/build-tools/20.0.0/zipalign ] ; then
+        ANDROID_BUILD_TOOLS_VERSION=20.0.0
+    else 
+        echo ANDROID_BUILD_TOOLS_VERSION $ANDROID_HOME/build-tools/ANDROID_BUILD_TOOLS_VERSION/zipalign does not exist in default locations
+        exit 1
+    fi
+elif [ ! -e $ANDROID_HOME/build-tools/$ANDROID_BUILD_TOOLS_VERSION/zipalign ] ; then
+    echo ANDROID_BUILD_TOOLS_VERSION $ANDROID_HOME/build-tools/$ANDROID_BUILD_TOOLS_VERSION/zipalign does not exist
+    exit 1
+fi
+export ANDROID_BUILD_TOOLS_VERSION
+
+echo Set
+echo   NDK_ROOT $NDK_ROOT
+echo   ANDROID_HOME $ANDROID_HOME
+echo   ANDROID_BUILD_TOOLS_VERSION $ANDROID_BUILD_TOOLS_VERSION
+
diff --git a/make/scripts/setenv-build-jogl-x86_64.sh b/make/scripts/setenv-build-jogl-x86_64.sh
index 2d01d19..6a009c5 100644
--- a/make/scripts/setenv-build-jogl-x86_64.sh
+++ b/make/scripts/setenv-build-jogl-x86_64.sh
@@ -15,13 +15,6 @@ if [ -z "$ANT_PATH" ] ; then
     fi
 fi
 if [ -z "$ANT_PATH" ] ; then
-    if [ -e /usr/share/ant/bin/ant -a -e /usr/share/ant/lib/ant.jar ] ; then
-        ANT_PATH=/usr/share/ant
-        export ANT_PATH
-        echo autosetting ANT_PATH to $ANT_PATH
-    fi
-fi
-if [ -z "$ANT_PATH" ] ; then
     echo ANT_PATH does not exist, set it
     exit
 fi
diff --git a/make/scripts/test-win32-smb_share.bat b/make/scripts/test-win32-smb_share.bat
index 5f55583..a6d3cc1 100755
--- a/make/scripts/test-win32-smb_share.bat
+++ b/make/scripts/test-win32-smb_share.bat
@@ -2,9 +2,9 @@
 set SMB_ROOT=\\risa.goethel.localnet\deployment\test\jogamp
 
 set BLD_SUB=build-win32
-set J2RE_HOME=c:\jre1.7.0_45_x32
-set JAVA_HOME=c:\jdk1.7.0_45_x32
-set ANT_PATH=C:\apache-ant-1.8.2
+set J2RE_HOME=c:\jre1.8.0_25_x32
+set JAVA_HOME=c:\jdk1.8.0_25_x32
+set ANT_PATH=C:\apache-ant-1.9.4
 
 set PROJECT_ROOT=%SMB_ROOT%\gluegen
 set BLD_DIR=%PROJECT_ROOT%\%BLD_SUB%
diff --git a/make/stub_includes/gluegen/stdio.h b/make/stub_includes/gluegen/stdio.h
new file mode 100644
index 0000000..13d941e
--- /dev/null
+++ b/make/stub_includes/gluegen/stdio.h
@@ -0,0 +1,7 @@
+#ifndef __stdio_h
+#define __stdio_h
+
+#include <gluegen_types.h>
+
+#endif /* __stdio_h */
+
diff --git a/make/stub_includes/jni/jawt.h b/make/stub_includes/jni/jawt.h
new file mode 100644
index 0000000..3867d54
--- /dev/null
+++ b/make/stub_includes/jni/jawt.h
@@ -0,0 +1,106 @@
+/*
+ * @(#)jawt.h	1.11 05/11/17
+ *
+ * This C header file is derived from Sun Microsystem's Java SDK provided C header file
+ * with the following copyright notice:
+ *
+ *   Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ *   SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ * This version has complex comments removed and does not contain inlined algorithms etc, if any existed.
+ * 
+ * The original C header file was included to JOGL on Sat Jun 21 02:10:30 2008
+ * (commit cbc45e816f4ee81031bffce19a99550681462a24) by Sun Microsystem's staff and were approved. 
+ *
+ * This C header file is included due to ensure compatibility with - and invocation of the JAWT protocol.
+ * They are processed by GlueGen to create a Java binding for JAWT invocation only.
+ * 
+ * http://ftp.resource.org/courts.gov/c/F3/387/387.F3d.522.03-5400.html (36)
+ * "Atari Games Corp. v. Nintendo of Am., Inc., Nos. 88-4805 & 89-0027, 1993 WL 207548, at *1 (N.D.Cal. May 18, 1993) ("Atari III") 
+ * ("Program code that is strictly necessary to achieve current compatibility presents a merger problem, almost by definition, 
+ * and is thus excluded from the scope of any copyright.")."
+ *
+ * http://eur-lex.europa.eu/LexUriServ/LexUriServ.do?uri=OJ:L:2009:111:0016:0022:EN:PDF
+ * L 111/17 (10) and (15)
+ */
+
+#ifndef _JAVASOFT_JAWT_H_
+#define _JAVASOFT_JAWT_H_
+
+#include "jni.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * AWT native interface (new in JDK 1.3)
+ */
+
+typedef struct jawt_Rectangle {
+    jint x;
+    jint y;
+    jint width;
+    jint height;
+} JAWT_Rectangle;
+
+struct jawt_DrawingSurface;
+
+typedef struct jawt_DrawingSurfaceInfo {
+    void* platformInfo;
+    struct jawt_DrawingSurface* ds;
+    JAWT_Rectangle bounds;
+    jint clipSize;
+    JAWT_Rectangle* clip;
+} JAWT_DrawingSurfaceInfo;
+
+#define JAWT_LOCK_ERROR                 0x00000001
+#define JAWT_LOCK_CLIP_CHANGED          0x00000002
+#define JAWT_LOCK_BOUNDS_CHANGED        0x00000004
+#define JAWT_LOCK_SURFACE_CHANGED       0x00000008
+
+typedef struct jawt_DrawingSurface {
+    JNIEnv* env;
+    jobject target;
+    jint (JNICALL *Lock)
+        (struct jawt_DrawingSurface* ds);
+    JAWT_DrawingSurfaceInfo* (JNICALL *GetDrawingSurfaceInfo)
+        (struct jawt_DrawingSurface* ds);
+    void (JNICALL *FreeDrawingSurfaceInfo)
+        (JAWT_DrawingSurfaceInfo* dsi);
+    void (JNICALL *Unlock)
+        (struct jawt_DrawingSurface* ds);
+} JAWT_DrawingSurface;
+
+typedef struct jawt {
+    jint version;
+    JAWT_DrawingSurface* (JNICALL *GetDrawingSurface)
+        (JNIEnv* env, jobject target);
+    void (JNICALL *FreeDrawingSurface)
+        (JAWT_DrawingSurface* ds);
+    /*
+     * Since 1.4
+     */
+    void (JNICALL *Lock)(JNIEnv* env);
+    /*
+     * Since 1.4
+     */
+    void (JNICALL *Unlock)(JNIEnv* env);
+    /*
+     * Since 1.4
+     */
+    jobject (JNICALL *GetComponent)(JNIEnv* env, void* platformInfo);
+
+} JAWT;
+
+_JNI_IMPORT_OR_EXPORT_
+jboolean JNICALL JAWT_GetAWT(JNIEnv* env, JAWT* awt);
+
+#define JAWT_VERSION_1_3 0x00010003
+#define JAWT_VERSION_1_4 0x00010004
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* !_JAVASOFT_JAWT_H_ */
diff --git a/make/stub_includes/jni/jni.h b/make/stub_includes/jni/jni.h
new file mode 100644
index 0000000..b4c6c1d
--- /dev/null
+++ b/make/stub_includes/jni/jni.h
@@ -0,0 +1,1934 @@
+/*
+ * @(#)jni.h	1.62 06/02/02
+ *
+ * This C header file is derived from Sun Microsystem's Java SDK provided C header file
+ * with the following copyright notice:
+ *
+ *   Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ *   SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ * This version has complex comments removed and does not contain inlined algorithms etc, if any existed.
+ * 
+ * The original C header file was included to JOGL on Sat Jun 21 02:10:30 2008
+ * (commit cbc45e816f4ee81031bffce19a99550681462a24) by Sun Microsystem's staff and were approved. 
+ *
+ * This C header file is included due to ensure compatibility with - and invocation of the JAWT protocol.
+ * They are processed by GlueGen to create a Java binding for JAWT invocation only.
+ * 
+ * http://ftp.resource.org/courts.gov/c/F3/387/387.F3d.522.03-5400.html (36)
+ * "Atari Games Corp. v. Nintendo of Am., Inc., Nos. 88-4805 & 89-0027, 1993 WL 207548, at *1 (N.D.Cal. May 18, 1993) ("Atari III") 
+ * ("Program code that is strictly necessary to achieve current compatibility presents a merger problem, almost by definition, 
+ * and is thus excluded from the scope of any copyright.")."
+ *
+ * http://eur-lex.europa.eu/LexUriServ/LexUriServ.do?uri=OJ:L:2009:111:0016:0022:EN:PDF
+ * L 111/17 (10) and (15)
+ */
+
+/*
+ * We used part of Netscape's Java Runtime Interface (JRI) as the starting
+ * point of our design and implementation.
+ */
+
+/******************************************************************************
+ * Java Runtime Interface
+ * Copyright (c) 1996 Netscape Communications Corporation. All rights reserved.
+ *****************************************************************************/
+
+#ifndef _JAVASOFT_JNI_H_
+#define _JAVASOFT_JNI_H_
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <gluegen_stdint.h>
+
+#include "jni_md.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H
+
+typedef uint8_t  jboolean;
+typedef uint16_t jchar;
+typedef int16_t  jshort;
+typedef float    jfloat;
+typedef double   jdouble;
+
+typedef jint     jsize;
+
+#ifdef __cplusplus
+
+class _jobject {};
+class _jclass : public _jobject {};
+class _jthrowable : public _jobject {};
+class _jstring : public _jobject {};
+class _jarray : public _jobject {};
+class _jbooleanArray : public _jarray {};
+class _jbyteArray : public _jarray {};
+class _jcharArray : public _jarray {};
+class _jshortArray : public _jarray {};
+class _jintArray : public _jarray {};
+class _jlongArray : public _jarray {};
+class _jfloatArray : public _jarray {};
+class _jdoubleArray : public _jarray {};
+class _jobjectArray : public _jarray {};
+
+typedef _jobject *jobject;
+typedef _jclass *jclass;
+typedef _jthrowable *jthrowable;
+typedef _jstring *jstring;
+typedef _jarray *jarray;
+typedef _jbooleanArray *jbooleanArray;
+typedef _jbyteArray *jbyteArray;
+typedef _jcharArray *jcharArray;
+typedef _jshortArray *jshortArray;
+typedef _jintArray *jintArray;
+typedef _jlongArray *jlongArray;
+typedef _jfloatArray *jfloatArray;
+typedef _jdoubleArray *jdoubleArray;
+typedef _jobjectArray *jobjectArray;
+
+#else
+
+struct _jobject;
+
+typedef struct _jobject *jobject;
+typedef jobject jclass;
+typedef jobject jthrowable;
+typedef jobject jstring;
+typedef jobject jarray;
+typedef jarray jbooleanArray;
+typedef jarray jbyteArray;
+typedef jarray jcharArray;
+typedef jarray jshortArray;
+typedef jarray jintArray;
+typedef jarray jlongArray;
+typedef jarray jfloatArray;
+typedef jarray jdoubleArray;
+typedef jarray jobjectArray;
+
+#endif
+
+typedef jobject jweak;
+
+typedef union jvalue {
+    jboolean z;
+    jbyte    b;
+    jchar    c;
+    jshort   s;
+    jint     i;
+    jlong    j;
+    jfloat   f;
+    jdouble  d;
+    jobject  l;
+} jvalue;
+
+struct _jfieldID;
+typedef struct _jfieldID *jfieldID;
+
+struct _jmethodID;
+typedef struct _jmethodID *jmethodID;
+
+typedef enum _jobjectType {
+     JNIInvalidRefType    = 0,
+     JNILocalRefType      = 1,
+     JNIGlobalRefType     = 2,
+     JNIWeakGlobalRefType = 3 
+} jobjectRefType;
+
+
+#endif /* JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H */
+
+#define JNI_FALSE 0
+#define JNI_TRUE 1
+
+#define JNI_OK           0                 /* success */
+#define JNI_ERR          (-1)              /* unknown error */
+#define JNI_EDETACHED    (-2)              /* thread detached from the VM */
+#define JNI_EVERSION     (-3)              /* JNI version error */
+#define JNI_ENOMEM       (-4)              /* not enough memory */
+#define JNI_EEXIST       (-5)              /* VM already created */
+#define JNI_EINVAL       (-6)              /* invalid arguments */
+
+#define JNI_COMMIT 1
+#define JNI_ABORT 2
+
+#ifdef __GLUEGEN__
+
+// GlueGen 'shortcut': We don't want to create bindings for JNI invocations!
+// Hence dropping the JNI details, use-case: jawt.h
+
+/** Special opaque GlueGen handling of JNIEnv */
+typedef long JNIEnv;
+
+#define JDK1_2
+#define JDK1_4
+
+#define _JNI_IMPORT_OR_EXPORT_ JNIIMPORT
+
+#define JNI_VERSION_1_1 0x00010001
+#define JNI_VERSION_1_2 0x00010002
+#define JNI_VERSION_1_4 0x00010004
+#define JNI_VERSION_1_6 0x00010006
+
+#else /*  __GLUEGEN__ */
+
+typedef struct {
+    char *name;
+    char *signature;
+    void *fnPtr;
+} JNINativeMethod;
+
+struct JNINativeInterface_;
+
+struct JNIEnv_;
+
+#ifdef __cplusplus
+typedef JNIEnv_ JNIEnv;
+#else
+typedef const struct JNINativeInterface_ *JNIEnv;
+#endif
+
+struct JNIInvokeInterface_;
+
+struct JavaVM_;
+
+#ifdef __cplusplus
+typedef JavaVM_ JavaVM;
+#else
+typedef const struct JNIInvokeInterface_ *JavaVM;
+#endif
+
+struct JNINativeInterface_ {
+    void *reserved0;
+    void *reserved1;
+    void *reserved2;
+
+    void *reserved3;
+    jint (JNICALL *GetVersion)(JNIEnv *env);
+
+    jclass (JNICALL *DefineClass)
+      (JNIEnv *env, const char *name, jobject loader, const jbyte *buf,
+       jsize len);
+    jclass (JNICALL *FindClass)
+      (JNIEnv *env, const char *name);
+
+    jmethodID (JNICALL *FromReflectedMethod)
+      (JNIEnv *env, jobject method);
+    jfieldID (JNICALL *FromReflectedField)
+      (JNIEnv *env, jobject field);
+
+    jobject (JNICALL *ToReflectedMethod)
+      (JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic);
+
+    jclass (JNICALL *GetSuperclass)
+      (JNIEnv *env, jclass sub);
+    jboolean (JNICALL *IsAssignableFrom)
+      (JNIEnv *env, jclass sub, jclass sup);
+
+    jobject (JNICALL *ToReflectedField)
+      (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic);
+
+    jint (JNICALL *Throw)
+      (JNIEnv *env, jthrowable obj);
+    jint (JNICALL *ThrowNew)
+      (JNIEnv *env, jclass clazz, const char *msg);
+    jthrowable (JNICALL *ExceptionOccurred)
+      (JNIEnv *env);
+    void (JNICALL *ExceptionDescribe)
+      (JNIEnv *env);
+    void (JNICALL *ExceptionClear)
+      (JNIEnv *env);
+    void (JNICALL *FatalError)
+      (JNIEnv *env, const char *msg);
+
+    jint (JNICALL *PushLocalFrame)
+      (JNIEnv *env, jint capacity);
+    jobject (JNICALL *PopLocalFrame)
+      (JNIEnv *env, jobject result);
+
+    jobject (JNICALL *NewGlobalRef)
+      (JNIEnv *env, jobject lobj);
+    void (JNICALL *DeleteGlobalRef)
+      (JNIEnv *env, jobject gref);
+    void (JNICALL *DeleteLocalRef)
+      (JNIEnv *env, jobject obj);
+    jboolean (JNICALL *IsSameObject)
+      (JNIEnv *env, jobject obj1, jobject obj2);
+    jobject (JNICALL *NewLocalRef)
+      (JNIEnv *env, jobject ref);
+    jint (JNICALL *EnsureLocalCapacity)
+      (JNIEnv *env, jint capacity);
+
+    jobject (JNICALL *AllocObject)
+      (JNIEnv *env, jclass clazz);
+    jobject (JNICALL *NewObject)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jobject (JNICALL *NewObjectV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jobject (JNICALL *NewObjectA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+    jclass (JNICALL *GetObjectClass)
+      (JNIEnv *env, jobject obj);
+    jboolean (JNICALL *IsInstanceOf)
+      (JNIEnv *env, jobject obj, jclass clazz);
+
+    jmethodID (JNICALL *GetMethodID)
+      (JNIEnv *env, jclass clazz, const char *name, const char *sig);
+
+    jobject (JNICALL *CallObjectMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jobject (JNICALL *CallObjectMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jobject (JNICALL *CallObjectMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args);
+
+    jboolean (JNICALL *CallBooleanMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jboolean (JNICALL *CallBooleanMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jboolean (JNICALL *CallBooleanMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args);
+
+    jbyte (JNICALL *CallByteMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jbyte (JNICALL *CallByteMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jbyte (JNICALL *CallByteMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+    jchar (JNICALL *CallCharMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jchar (JNICALL *CallCharMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jchar (JNICALL *CallCharMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+    jshort (JNICALL *CallShortMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jshort (JNICALL *CallShortMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jshort (JNICALL *CallShortMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+    jint (JNICALL *CallIntMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jint (JNICALL *CallIntMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jint (JNICALL *CallIntMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+    jlong (JNICALL *CallLongMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jlong (JNICALL *CallLongMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jlong (JNICALL *CallLongMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+    jfloat (JNICALL *CallFloatMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jfloat (JNICALL *CallFloatMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jfloat (JNICALL *CallFloatMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+    jdouble (JNICALL *CallDoubleMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jdouble (JNICALL *CallDoubleMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jdouble (JNICALL *CallDoubleMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args);
+
+    void (JNICALL *CallVoidMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    void (JNICALL *CallVoidMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    void (JNICALL *CallVoidMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, const jvalue * args);
+
+    jobject (JNICALL *CallNonvirtualObjectMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jobject (JNICALL *CallNonvirtualObjectMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jobject (JNICALL *CallNonvirtualObjectMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       const jvalue * args);
+
+    jboolean (JNICALL *CallNonvirtualBooleanMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jboolean (JNICALL *CallNonvirtualBooleanMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jboolean (JNICALL *CallNonvirtualBooleanMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       const jvalue * args);
+
+    jbyte (JNICALL *CallNonvirtualByteMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jbyte (JNICALL *CallNonvirtualByteMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jbyte (JNICALL *CallNonvirtualByteMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       const jvalue *args);
+
+    jchar (JNICALL *CallNonvirtualCharMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jchar (JNICALL *CallNonvirtualCharMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jchar (JNICALL *CallNonvirtualCharMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       const jvalue *args);
+
+    jshort (JNICALL *CallNonvirtualShortMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jshort (JNICALL *CallNonvirtualShortMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jshort (JNICALL *CallNonvirtualShortMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       const jvalue *args);
+
+    jint (JNICALL *CallNonvirtualIntMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jint (JNICALL *CallNonvirtualIntMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jint (JNICALL *CallNonvirtualIntMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       const jvalue *args);
+
+    jlong (JNICALL *CallNonvirtualLongMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jlong (JNICALL *CallNonvirtualLongMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jlong (JNICALL *CallNonvirtualLongMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       const jvalue *args);
+
+    jfloat (JNICALL *CallNonvirtualFloatMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jfloat (JNICALL *CallNonvirtualFloatMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jfloat (JNICALL *CallNonvirtualFloatMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       const jvalue *args);
+
+    jdouble (JNICALL *CallNonvirtualDoubleMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jdouble (JNICALL *CallNonvirtualDoubleMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jdouble (JNICALL *CallNonvirtualDoubleMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       const jvalue *args);
+
+    void (JNICALL *CallNonvirtualVoidMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    void (JNICALL *CallNonvirtualVoidMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    void (JNICALL *CallNonvirtualVoidMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       const jvalue * args);
+
+    jfieldID (JNICALL *GetFieldID)
+      (JNIEnv *env, jclass clazz, const char *name, const char *sig);
+
+    jobject (JNICALL *GetObjectField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jboolean (JNICALL *GetBooleanField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jbyte (JNICALL *GetByteField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jchar (JNICALL *GetCharField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jshort (JNICALL *GetShortField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jint (JNICALL *GetIntField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jlong (JNICALL *GetLongField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jfloat (JNICALL *GetFloatField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jdouble (JNICALL *GetDoubleField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+
+    void (JNICALL *SetObjectField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jobject val);
+    void (JNICALL *SetBooleanField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jboolean val);
+    void (JNICALL *SetByteField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jbyte val);
+    void (JNICALL *SetCharField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jchar val);
+    void (JNICALL *SetShortField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jshort val);
+    void (JNICALL *SetIntField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jint val);
+    void (JNICALL *SetLongField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jlong val);
+    void (JNICALL *SetFloatField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jfloat val);
+    void (JNICALL *SetDoubleField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jdouble val);
+
+    jmethodID (JNICALL *GetStaticMethodID)
+      (JNIEnv *env, jclass clazz, const char *name, const char *sig);
+
+    jobject (JNICALL *CallStaticObjectMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jobject (JNICALL *CallStaticObjectMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jobject (JNICALL *CallStaticObjectMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+    jboolean (JNICALL *CallStaticBooleanMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jboolean (JNICALL *CallStaticBooleanMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jboolean (JNICALL *CallStaticBooleanMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+    jbyte (JNICALL *CallStaticByteMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jbyte (JNICALL *CallStaticByteMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jbyte (JNICALL *CallStaticByteMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+    jchar (JNICALL *CallStaticCharMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jchar (JNICALL *CallStaticCharMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jchar (JNICALL *CallStaticCharMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+    jshort (JNICALL *CallStaticShortMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jshort (JNICALL *CallStaticShortMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jshort (JNICALL *CallStaticShortMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+    jint (JNICALL *CallStaticIntMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jint (JNICALL *CallStaticIntMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jint (JNICALL *CallStaticIntMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+    jlong (JNICALL *CallStaticLongMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jlong (JNICALL *CallStaticLongMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jlong (JNICALL *CallStaticLongMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+    jfloat (JNICALL *CallStaticFloatMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jfloat (JNICALL *CallStaticFloatMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jfloat (JNICALL *CallStaticFloatMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+    jdouble (JNICALL *CallStaticDoubleMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jdouble (JNICALL *CallStaticDoubleMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jdouble (JNICALL *CallStaticDoubleMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
+
+    void (JNICALL *CallStaticVoidMethod)
+      (JNIEnv *env, jclass cls, jmethodID methodID, ...);
+    void (JNICALL *CallStaticVoidMethodV)
+      (JNIEnv *env, jclass cls, jmethodID methodID, va_list args);
+    void (JNICALL *CallStaticVoidMethodA)
+      (JNIEnv *env, jclass cls, jmethodID methodID, const jvalue * args);
+
+    jfieldID (JNICALL *GetStaticFieldID)
+      (JNIEnv *env, jclass clazz, const char *name, const char *sig);
+    jobject (JNICALL *GetStaticObjectField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jboolean (JNICALL *GetStaticBooleanField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jbyte (JNICALL *GetStaticByteField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jchar (JNICALL *GetStaticCharField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jshort (JNICALL *GetStaticShortField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jint (JNICALL *GetStaticIntField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jlong (JNICALL *GetStaticLongField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jfloat (JNICALL *GetStaticFloatField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jdouble (JNICALL *GetStaticDoubleField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+
+    void (JNICALL *SetStaticObjectField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value);
+    void (JNICALL *SetStaticBooleanField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean value);
+    void (JNICALL *SetStaticByteField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte value);
+    void (JNICALL *SetStaticCharField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jchar value);
+    void (JNICALL *SetStaticShortField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jshort value);
+    void (JNICALL *SetStaticIntField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jint value);
+    void (JNICALL *SetStaticLongField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jlong value);
+    void (JNICALL *SetStaticFloatField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat value);
+    void (JNICALL *SetStaticDoubleField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble value);
+
+    jstring (JNICALL *NewString)
+      (JNIEnv *env, const jchar *unicode, jsize len);
+    jsize (JNICALL *GetStringLength)
+      (JNIEnv *env, jstring str);
+    const jchar *(JNICALL *GetStringChars)
+      (JNIEnv *env, jstring str, jboolean *isCopy);
+    void (JNICALL *ReleaseStringChars)
+      (JNIEnv *env, jstring str, const jchar *chars);
+
+    jstring (JNICALL *NewStringUTF)
+      (JNIEnv *env, const char *utf);
+    jsize (JNICALL *GetStringUTFLength)
+      (JNIEnv *env, jstring str);
+    const char* (JNICALL *GetStringUTFChars)
+      (JNIEnv *env, jstring str, jboolean *isCopy);
+    void (JNICALL *ReleaseStringUTFChars)
+      (JNIEnv *env, jstring str, const char* chars);
+
+
+    jsize (JNICALL *GetArrayLength)
+      (JNIEnv *env, jarray array);
+
+    jobjectArray (JNICALL *NewObjectArray)
+      (JNIEnv *env, jsize len, jclass clazz, jobject init);
+    jobject (JNICALL *GetObjectArrayElement)
+      (JNIEnv *env, jobjectArray array, jsize index);
+    void (JNICALL *SetObjectArrayElement)
+      (JNIEnv *env, jobjectArray array, jsize index, jobject val);
+
+    jbooleanArray (JNICALL *NewBooleanArray)
+      (JNIEnv *env, jsize len);
+    jbyteArray (JNICALL *NewByteArray)
+      (JNIEnv *env, jsize len);
+    jcharArray (JNICALL *NewCharArray)
+      (JNIEnv *env, jsize len);
+    jshortArray (JNICALL *NewShortArray)
+      (JNIEnv *env, jsize len);
+    jintArray (JNICALL *NewIntArray)
+      (JNIEnv *env, jsize len);
+    jlongArray (JNICALL *NewLongArray)
+      (JNIEnv *env, jsize len);
+    jfloatArray (JNICALL *NewFloatArray)
+      (JNIEnv *env, jsize len);
+    jdoubleArray (JNICALL *NewDoubleArray)
+      (JNIEnv *env, jsize len);
+
+    jboolean * (JNICALL *GetBooleanArrayElements)
+      (JNIEnv *env, jbooleanArray array, jboolean *isCopy);
+    jbyte * (JNICALL *GetByteArrayElements)
+      (JNIEnv *env, jbyteArray array, jboolean *isCopy);
+    jchar * (JNICALL *GetCharArrayElements)
+      (JNIEnv *env, jcharArray array, jboolean *isCopy);
+    jshort * (JNICALL *GetShortArrayElements)
+      (JNIEnv *env, jshortArray array, jboolean *isCopy);
+    jint * (JNICALL *GetIntArrayElements)
+      (JNIEnv *env, jintArray array, jboolean *isCopy);
+    jlong * (JNICALL *GetLongArrayElements)
+      (JNIEnv *env, jlongArray array, jboolean *isCopy);
+    jfloat * (JNICALL *GetFloatArrayElements)
+      (JNIEnv *env, jfloatArray array, jboolean *isCopy);
+    jdouble * (JNICALL *GetDoubleArrayElements)
+      (JNIEnv *env, jdoubleArray array, jboolean *isCopy);
+
+    void (JNICALL *ReleaseBooleanArrayElements)
+      (JNIEnv *env, jbooleanArray array, jboolean *elems, jint mode);
+    void (JNICALL *ReleaseByteArrayElements)
+      (JNIEnv *env, jbyteArray array, jbyte *elems, jint mode);
+    void (JNICALL *ReleaseCharArrayElements)
+      (JNIEnv *env, jcharArray array, jchar *elems, jint mode);
+    void (JNICALL *ReleaseShortArrayElements)
+      (JNIEnv *env, jshortArray array, jshort *elems, jint mode);
+    void (JNICALL *ReleaseIntArrayElements)
+      (JNIEnv *env, jintArray array, jint *elems, jint mode);
+    void (JNICALL *ReleaseLongArrayElements)
+      (JNIEnv *env, jlongArray array, jlong *elems, jint mode);
+    void (JNICALL *ReleaseFloatArrayElements)
+      (JNIEnv *env, jfloatArray array, jfloat *elems, jint mode);
+    void (JNICALL *ReleaseDoubleArrayElements)
+      (JNIEnv *env, jdoubleArray array, jdouble *elems, jint mode);
+
+    void (JNICALL *GetBooleanArrayRegion)
+      (JNIEnv *env, jbooleanArray array, jsize start, jsize l, jboolean *buf);
+    void (JNICALL *GetByteArrayRegion)
+      (JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf);
+    void (JNICALL *GetCharArrayRegion)
+      (JNIEnv *env, jcharArray array, jsize start, jsize len, jchar *buf);
+    void (JNICALL *GetShortArrayRegion)
+      (JNIEnv *env, jshortArray array, jsize start, jsize len, jshort *buf);
+    void (JNICALL *GetIntArrayRegion)
+      (JNIEnv *env, jintArray array, jsize start, jsize len, jint *buf);
+    void (JNICALL *GetLongArrayRegion)
+      (JNIEnv *env, jlongArray array, jsize start, jsize len, jlong *buf);
+    void (JNICALL *GetFloatArrayRegion)
+      (JNIEnv *env, jfloatArray array, jsize start, jsize len, jfloat *buf);
+    void (JNICALL *GetDoubleArrayRegion)
+      (JNIEnv *env, jdoubleArray array, jsize start, jsize len, jdouble *buf);
+
+    void (JNICALL *SetBooleanArrayRegion)
+      (JNIEnv *env, jbooleanArray array, jsize start, jsize l, const jboolean *buf);
+    void (JNICALL *SetByteArrayRegion)
+      (JNIEnv *env, jbyteArray array, jsize start, jsize len, const jbyte *buf);
+    void (JNICALL *SetCharArrayRegion)
+      (JNIEnv *env, jcharArray array, jsize start, jsize len, const jchar *buf);
+    void (JNICALL *SetShortArrayRegion)
+      (JNIEnv *env, jshortArray array, jsize start, jsize len, const jshort *buf);
+    void (JNICALL *SetIntArrayRegion)
+      (JNIEnv *env, jintArray array, jsize start, jsize len, const jint *buf);
+    void (JNICALL *SetLongArrayRegion)
+      (JNIEnv *env, jlongArray array, jsize start, jsize len, const jlong *buf);
+    void (JNICALL *SetFloatArrayRegion)
+      (JNIEnv *env, jfloatArray array, jsize start, jsize len, const jfloat *buf);
+    void (JNICALL *SetDoubleArrayRegion)
+      (JNIEnv *env, jdoubleArray array, jsize start, jsize len, const jdouble *buf);
+
+    jint (JNICALL *RegisterNatives)
+      (JNIEnv *env, jclass clazz, const JNINativeMethod *methods,
+       jint nMethods);
+    jint (JNICALL *UnregisterNatives)
+      (JNIEnv *env, jclass clazz);
+
+    jint (JNICALL *MonitorEnter)
+      (JNIEnv *env, jobject obj);
+    jint (JNICALL *MonitorExit)
+      (JNIEnv *env, jobject obj);
+
+    jint (JNICALL *GetJavaVM)
+      (JNIEnv *env, JavaVM **vm);
+
+    void (JNICALL *GetStringRegion)
+      (JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf);
+    void (JNICALL *GetStringUTFRegion)
+      (JNIEnv *env, jstring str, jsize start, jsize len, char *buf);
+
+    void * (JNICALL *GetPrimitiveArrayCritical)
+      (JNIEnv *env, jarray array, jboolean *isCopy);
+    void (JNICALL *ReleasePrimitiveArrayCritical)
+      (JNIEnv *env, jarray array, void *carray, jint mode);
+
+    const jchar * (JNICALL *GetStringCritical)
+      (JNIEnv *env, jstring string, jboolean *isCopy);
+    void (JNICALL *ReleaseStringCritical)
+      (JNIEnv *env, jstring string, const jchar *cstring);
+
+    jweak (JNICALL *NewWeakGlobalRef)
+       (JNIEnv *env, jobject obj);
+    void (JNICALL *DeleteWeakGlobalRef)
+       (JNIEnv *env, jweak ref);
+
+    jboolean (JNICALL *ExceptionCheck)
+       (JNIEnv *env);
+
+    jobject (JNICALL *NewDirectByteBuffer)
+       (JNIEnv* env, void* address, jlong capacity);
+    void* (JNICALL *GetDirectBufferAddress)
+       (JNIEnv* env, jobject buf);
+    jlong (JNICALL *GetDirectBufferCapacity)
+       (JNIEnv* env, jobject buf);
+
+    /* New JNI 1.6 Features */
+
+    jobjectRefType (JNICALL *GetObjectRefType)
+        (JNIEnv* env, jobject obj);
+};
+
+struct JNIEnv_ {
+    const struct JNINativeInterface_ *functions;
+#ifdef __cplusplus
+
+    jint GetVersion() {
+        return functions->GetVersion(this);
+    }
+    jclass DefineClass(const char *name, jobject loader, const jbyte *buf,
+		       jsize len) {
+        return functions->DefineClass(this, name, loader, buf, len);
+    }
+    jclass FindClass(const char *name) {
+        return functions->FindClass(this, name);
+    }
+    jmethodID FromReflectedMethod(jobject method) {
+        return functions->FromReflectedMethod(this,method);
+    }
+    jfieldID FromReflectedField(jobject field) {
+        return functions->FromReflectedField(this,field);
+    }
+
+    jobject ToReflectedMethod(jclass cls, jmethodID methodID, jboolean isStatic) {
+        return functions->ToReflectedMethod(this, cls, methodID, isStatic);
+    }
+
+    jclass GetSuperclass(jclass sub) {
+        return functions->GetSuperclass(this, sub);
+    }
+    jboolean IsAssignableFrom(jclass sub, jclass sup) {
+        return functions->IsAssignableFrom(this, sub, sup);
+    }
+
+    jobject ToReflectedField(jclass cls, jfieldID fieldID, jboolean isStatic) {
+        return functions->ToReflectedField(this,cls,fieldID,isStatic);
+    }
+
+    jint Throw(jthrowable obj) {
+        return functions->Throw(this, obj);
+    }
+    jint ThrowNew(jclass clazz, const char *msg) {
+        return functions->ThrowNew(this, clazz, msg);
+    }
+    jthrowable ExceptionOccurred() {
+        return functions->ExceptionOccurred(this);
+    }
+    void ExceptionDescribe() {
+        functions->ExceptionDescribe(this);
+    }
+    void ExceptionClear() {
+        functions->ExceptionClear(this);
+    }
+    void FatalError(const char *msg) {
+        functions->FatalError(this, msg);
+    }
+
+    jint PushLocalFrame(jint capacity) {
+        return functions->PushLocalFrame(this,capacity);
+    }
+    jobject PopLocalFrame(jobject result) {
+        return functions->PopLocalFrame(this,result);
+    }
+
+    jobject NewGlobalRef(jobject lobj) {
+        return functions->NewGlobalRef(this,lobj);
+    }
+    void DeleteGlobalRef(jobject gref) {
+        functions->DeleteGlobalRef(this,gref);
+    }
+    void DeleteLocalRef(jobject obj) {
+        functions->DeleteLocalRef(this, obj);
+    }
+
+    jboolean IsSameObject(jobject obj1, jobject obj2) {
+        return functions->IsSameObject(this,obj1,obj2);
+    }
+
+    jobject NewLocalRef(jobject ref) {
+        return functions->NewLocalRef(this,ref);
+    }
+    jint EnsureLocalCapacity(jint capacity) {
+        return functions->EnsureLocalCapacity(this,capacity);
+    }
+
+    jobject AllocObject(jclass clazz) {
+        return functions->AllocObject(this,clazz);
+    }
+    jobject NewObject(jclass clazz, jmethodID methodID, ...) {
+        va_list args;
+	jobject result;
+	va_start(args, methodID);
+        result = functions->NewObjectV(this,clazz,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jobject NewObjectV(jclass clazz, jmethodID methodID,
+		       va_list args) {
+        return functions->NewObjectV(this,clazz,methodID,args);
+    }
+    jobject NewObjectA(jclass clazz, jmethodID methodID,
+		       const jvalue *args) {
+        return functions->NewObjectA(this,clazz,methodID,args);
+    }
+
+    jclass GetObjectClass(jobject obj) {
+        return functions->GetObjectClass(this,obj);
+    }
+    jboolean IsInstanceOf(jobject obj, jclass clazz) {
+        return functions->IsInstanceOf(this,obj,clazz);
+    }
+
+    jmethodID GetMethodID(jclass clazz, const char *name,
+			  const char *sig) {
+        return functions->GetMethodID(this,clazz,name,sig);
+    }
+
+    jobject CallObjectMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+	jobject result;
+	va_start(args,methodID);
+	result = functions->CallObjectMethodV(this,obj,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jobject CallObjectMethodV(jobject obj, jmethodID methodID,
+			va_list args) {
+        return functions->CallObjectMethodV(this,obj,methodID,args);
+    }
+    jobject CallObjectMethodA(jobject obj, jmethodID methodID,
+			const jvalue * args) {
+        return functions->CallObjectMethodA(this,obj,methodID,args);
+    }
+
+    jboolean CallBooleanMethod(jobject obj,
+			       jmethodID methodID, ...) {
+        va_list args;
+	jboolean result;
+	va_start(args,methodID);
+	result = functions->CallBooleanMethodV(this,obj,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jboolean CallBooleanMethodV(jobject obj, jmethodID methodID,
+				va_list args) {
+        return functions->CallBooleanMethodV(this,obj,methodID,args);
+    }
+    jboolean CallBooleanMethodA(jobject obj, jmethodID methodID,
+				const jvalue * args) {
+        return functions->CallBooleanMethodA(this,obj,methodID, args);
+    }
+
+    jbyte CallByteMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+	jbyte result;
+	va_start(args,methodID);
+	result = functions->CallByteMethodV(this,obj,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jbyte CallByteMethodV(jobject obj, jmethodID methodID,
+			  va_list args) {
+        return functions->CallByteMethodV(this,obj,methodID,args);
+    }
+    jbyte CallByteMethodA(jobject obj, jmethodID methodID,
+			  const jvalue * args) {
+        return functions->CallByteMethodA(this,obj,methodID,args);
+    }
+
+    jchar CallCharMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+	jchar result;
+	va_start(args,methodID);
+	result = functions->CallCharMethodV(this,obj,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jchar CallCharMethodV(jobject obj, jmethodID methodID,
+			  va_list args) {
+        return functions->CallCharMethodV(this,obj,methodID,args);
+    }
+    jchar CallCharMethodA(jobject obj, jmethodID methodID,
+			  const jvalue * args) {
+        return functions->CallCharMethodA(this,obj,methodID,args);
+    }
+
+    jshort CallShortMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+	jshort result;
+	va_start(args,methodID);
+	result = functions->CallShortMethodV(this,obj,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jshort CallShortMethodV(jobject obj, jmethodID methodID,
+			    va_list args) {
+        return functions->CallShortMethodV(this,obj,methodID,args);
+    }
+    jshort CallShortMethodA(jobject obj, jmethodID methodID,
+			    const jvalue * args) {
+        return functions->CallShortMethodA(this,obj,methodID,args);
+    }
+
+    jint CallIntMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+	jint result;
+	va_start(args,methodID);
+	result = functions->CallIntMethodV(this,obj,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jint CallIntMethodV(jobject obj, jmethodID methodID,
+			va_list args) {
+        return functions->CallIntMethodV(this,obj,methodID,args);
+    }
+    jint CallIntMethodA(jobject obj, jmethodID methodID,
+			const jvalue * args) {
+        return functions->CallIntMethodA(this,obj,methodID,args);
+    }
+
+    jlong CallLongMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+	jlong result;
+	va_start(args,methodID);
+	result = functions->CallLongMethodV(this,obj,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jlong CallLongMethodV(jobject obj, jmethodID methodID,
+			  va_list args) {
+        return functions->CallLongMethodV(this,obj,methodID,args);
+    }
+    jlong CallLongMethodA(jobject obj, jmethodID methodID,
+			  const jvalue * args) {
+        return functions->CallLongMethodA(this,obj,methodID,args);
+    }
+
+    jfloat CallFloatMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+	jfloat result;
+	va_start(args,methodID);
+	result = functions->CallFloatMethodV(this,obj,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jfloat CallFloatMethodV(jobject obj, jmethodID methodID,
+			    va_list args) {
+        return functions->CallFloatMethodV(this,obj,methodID,args);
+    }
+    jfloat CallFloatMethodA(jobject obj, jmethodID methodID,
+			    const jvalue * args) {
+        return functions->CallFloatMethodA(this,obj,methodID,args);
+    }
+
+    jdouble CallDoubleMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+	jdouble result;
+	va_start(args,methodID);
+	result = functions->CallDoubleMethodV(this,obj,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jdouble CallDoubleMethodV(jobject obj, jmethodID methodID,
+			va_list args) {
+        return functions->CallDoubleMethodV(this,obj,methodID,args);
+    }
+    jdouble CallDoubleMethodA(jobject obj, jmethodID methodID,
+			const jvalue * args) {
+        return functions->CallDoubleMethodA(this,obj,methodID,args);
+    }
+
+    void CallVoidMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+	va_start(args,methodID);
+	functions->CallVoidMethodV(this,obj,methodID,args);
+	va_end(args);
+    }
+    void CallVoidMethodV(jobject obj, jmethodID methodID,
+			 va_list args) {
+        functions->CallVoidMethodV(this,obj,methodID,args);
+    }
+    void CallVoidMethodA(jobject obj, jmethodID methodID,
+			 const jvalue * args) {
+        functions->CallVoidMethodA(this,obj,methodID,args);
+    }
+
+    jobject CallNonvirtualObjectMethod(jobject obj, jclass clazz,
+				       jmethodID methodID, ...) {
+        va_list args;
+	jobject result;
+	va_start(args,methodID);
+	result = functions->CallNonvirtualObjectMethodV(this,obj,clazz,
+							methodID,args);
+	va_end(args);
+	return result;
+    }
+    jobject CallNonvirtualObjectMethodV(jobject obj, jclass clazz,
+					jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualObjectMethodV(this,obj,clazz,
+						      methodID,args);
+    }
+    jobject CallNonvirtualObjectMethodA(jobject obj, jclass clazz,
+					jmethodID methodID, const jvalue * args) {
+        return functions->CallNonvirtualObjectMethodA(this,obj,clazz,
+						      methodID,args);
+    }
+
+    jboolean CallNonvirtualBooleanMethod(jobject obj, jclass clazz,
+					 jmethodID methodID, ...) {
+        va_list args;
+	jboolean result;
+	va_start(args,methodID);
+	result = functions->CallNonvirtualBooleanMethodV(this,obj,clazz,
+							 methodID,args);
+	va_end(args);
+	return result;
+    }
+    jboolean CallNonvirtualBooleanMethodV(jobject obj, jclass clazz,
+					  jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualBooleanMethodV(this,obj,clazz,
+						       methodID,args);
+    }
+    jboolean CallNonvirtualBooleanMethodA(jobject obj, jclass clazz,
+					  jmethodID methodID, const jvalue * args) {
+        return functions->CallNonvirtualBooleanMethodA(this,obj,clazz,
+						       methodID, args);
+    }
+
+    jbyte CallNonvirtualByteMethod(jobject obj, jclass clazz,
+				   jmethodID methodID, ...) {
+        va_list args;
+	jbyte result;
+	va_start(args,methodID);
+	result = functions->CallNonvirtualByteMethodV(this,obj,clazz,
+						      methodID,args);
+	va_end(args);
+	return result;
+    }
+    jbyte CallNonvirtualByteMethodV(jobject obj, jclass clazz,
+				    jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualByteMethodV(this,obj,clazz,
+						    methodID,args);
+    }
+    jbyte CallNonvirtualByteMethodA(jobject obj, jclass clazz,
+				    jmethodID methodID, const jvalue * args) {
+        return functions->CallNonvirtualByteMethodA(this,obj,clazz,
+						    methodID,args);
+    }
+
+    jchar CallNonvirtualCharMethod(jobject obj, jclass clazz,
+				   jmethodID methodID, ...) {
+        va_list args;
+	jchar result;
+	va_start(args,methodID);
+	result = functions->CallNonvirtualCharMethodV(this,obj,clazz,
+						      methodID,args);
+	va_end(args);
+	return result;
+    }
+    jchar CallNonvirtualCharMethodV(jobject obj, jclass clazz,
+				    jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualCharMethodV(this,obj,clazz,
+						    methodID,args);
+    }
+    jchar CallNonvirtualCharMethodA(jobject obj, jclass clazz,
+				    jmethodID methodID, const jvalue * args) {
+        return functions->CallNonvirtualCharMethodA(this,obj,clazz,
+						    methodID,args);
+    }
+
+    jshort CallNonvirtualShortMethod(jobject obj, jclass clazz,
+				     jmethodID methodID, ...) {
+        va_list args;
+	jshort result;
+	va_start(args,methodID);
+	result = functions->CallNonvirtualShortMethodV(this,obj,clazz,
+						       methodID,args);
+	va_end(args);
+	return result;
+    }
+    jshort CallNonvirtualShortMethodV(jobject obj, jclass clazz,
+				      jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualShortMethodV(this,obj,clazz,
+						     methodID,args);
+    }
+    jshort CallNonvirtualShortMethodA(jobject obj, jclass clazz,
+				      jmethodID methodID, const jvalue * args) {
+        return functions->CallNonvirtualShortMethodA(this,obj,clazz,
+						     methodID,args);
+    }
+
+    jint CallNonvirtualIntMethod(jobject obj, jclass clazz,
+				 jmethodID methodID, ...) {
+        va_list args;
+	jint result;
+	va_start(args,methodID);
+	result = functions->CallNonvirtualIntMethodV(this,obj,clazz,
+						     methodID,args);
+	va_end(args);
+	return result;
+    }
+    jint CallNonvirtualIntMethodV(jobject obj, jclass clazz,
+				  jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualIntMethodV(this,obj,clazz,
+						   methodID,args);
+    }
+    jint CallNonvirtualIntMethodA(jobject obj, jclass clazz,
+				  jmethodID methodID, const jvalue * args) {
+        return functions->CallNonvirtualIntMethodA(this,obj,clazz,
+						   methodID,args);
+    }
+
+    jlong CallNonvirtualLongMethod(jobject obj, jclass clazz,
+				   jmethodID methodID, ...) {
+        va_list args;
+	jlong result;
+	va_start(args,methodID);
+	result = functions->CallNonvirtualLongMethodV(this,obj,clazz,
+						      methodID,args);
+	va_end(args);
+	return result;
+    }
+    jlong CallNonvirtualLongMethodV(jobject obj, jclass clazz,
+				    jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualLongMethodV(this,obj,clazz,
+						    methodID,args);
+    }
+    jlong CallNonvirtualLongMethodA(jobject obj, jclass clazz,
+				    jmethodID methodID, const jvalue * args) {
+        return functions->CallNonvirtualLongMethodA(this,obj,clazz,
+						    methodID,args);
+    }
+
+    jfloat CallNonvirtualFloatMethod(jobject obj, jclass clazz,
+				     jmethodID methodID, ...) {
+        va_list args;
+	jfloat result;
+	va_start(args,methodID);
+	result = functions->CallNonvirtualFloatMethodV(this,obj,clazz,
+						       methodID,args);
+	va_end(args);
+	return result;
+    }
+    jfloat CallNonvirtualFloatMethodV(jobject obj, jclass clazz,
+				      jmethodID methodID,
+				      va_list args) {
+        return functions->CallNonvirtualFloatMethodV(this,obj,clazz,
+						     methodID,args);
+    }
+    jfloat CallNonvirtualFloatMethodA(jobject obj, jclass clazz,
+				      jmethodID methodID,
+				      const jvalue * args) {
+        return functions->CallNonvirtualFloatMethodA(this,obj,clazz,
+						     methodID,args);
+    }
+
+    jdouble CallNonvirtualDoubleMethod(jobject obj, jclass clazz,
+				       jmethodID methodID, ...) {
+        va_list args;
+	jdouble result;
+	va_start(args,methodID);
+	result = functions->CallNonvirtualDoubleMethodV(this,obj,clazz,
+							methodID,args);
+	va_end(args);
+	return result;
+    }
+    jdouble CallNonvirtualDoubleMethodV(jobject obj, jclass clazz,
+					jmethodID methodID,
+					va_list args) {
+        return functions->CallNonvirtualDoubleMethodV(this,obj,clazz,
+						      methodID,args);
+    }
+    jdouble CallNonvirtualDoubleMethodA(jobject obj, jclass clazz,
+					jmethodID methodID,
+					const jvalue * args) {
+        return functions->CallNonvirtualDoubleMethodA(this,obj,clazz,
+						      methodID,args);
+    }
+
+    void CallNonvirtualVoidMethod(jobject obj, jclass clazz,
+				  jmethodID methodID, ...) {
+        va_list args;
+	va_start(args,methodID);
+	functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args);
+	va_end(args);
+    }
+    void CallNonvirtualVoidMethodV(jobject obj, jclass clazz,
+				   jmethodID methodID,
+				   va_list args) {
+        functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args);
+    }
+    void CallNonvirtualVoidMethodA(jobject obj, jclass clazz,
+				   jmethodID methodID,
+				   const jvalue * args) {
+        functions->CallNonvirtualVoidMethodA(this,obj,clazz,methodID,args);
+    }
+
+    jfieldID GetFieldID(jclass clazz, const char *name,
+			const char *sig) {
+        return functions->GetFieldID(this,clazz,name,sig);
+    }
+
+    jobject GetObjectField(jobject obj, jfieldID fieldID) {
+        return functions->GetObjectField(this,obj,fieldID);
+    }
+    jboolean GetBooleanField(jobject obj, jfieldID fieldID) {
+        return functions->GetBooleanField(this,obj,fieldID);
+    }
+    jbyte GetByteField(jobject obj, jfieldID fieldID) {
+        return functions->GetByteField(this,obj,fieldID);
+    }
+    jchar GetCharField(jobject obj, jfieldID fieldID) {
+        return functions->GetCharField(this,obj,fieldID);
+    }
+    jshort GetShortField(jobject obj, jfieldID fieldID) {
+        return functions->GetShortField(this,obj,fieldID);
+    }
+    jint GetIntField(jobject obj, jfieldID fieldID) {
+        return functions->GetIntField(this,obj,fieldID);
+    }
+    jlong GetLongField(jobject obj, jfieldID fieldID) {
+        return functions->GetLongField(this,obj,fieldID);
+    }
+    jfloat GetFloatField(jobject obj, jfieldID fieldID) {
+        return functions->GetFloatField(this,obj,fieldID);
+    }
+    jdouble GetDoubleField(jobject obj, jfieldID fieldID) {
+        return functions->GetDoubleField(this,obj,fieldID);
+    }
+
+    void SetObjectField(jobject obj, jfieldID fieldID, jobject val) {
+        functions->SetObjectField(this,obj,fieldID,val);
+    }
+    void SetBooleanField(jobject obj, jfieldID fieldID,
+			 jboolean val) {
+        functions->SetBooleanField(this,obj,fieldID,val);
+    }
+    void SetByteField(jobject obj, jfieldID fieldID,
+		      jbyte val) {
+        functions->SetByteField(this,obj,fieldID,val);
+    }
+    void SetCharField(jobject obj, jfieldID fieldID,
+		      jchar val) {
+        functions->SetCharField(this,obj,fieldID,val);
+    }
+    void SetShortField(jobject obj, jfieldID fieldID,
+		       jshort val) {
+        functions->SetShortField(this,obj,fieldID,val);
+    }
+    void SetIntField(jobject obj, jfieldID fieldID,
+		     jint val) {
+        functions->SetIntField(this,obj,fieldID,val);
+    }
+    void SetLongField(jobject obj, jfieldID fieldID,
+		      jlong val) {
+        functions->SetLongField(this,obj,fieldID,val);
+    }
+    void SetFloatField(jobject obj, jfieldID fieldID,
+		       jfloat val) {
+        functions->SetFloatField(this,obj,fieldID,val);
+    }
+    void SetDoubleField(jobject obj, jfieldID fieldID,
+			jdouble val) {
+        functions->SetDoubleField(this,obj,fieldID,val);
+    }
+
+    jmethodID GetStaticMethodID(jclass clazz, const char *name,
+				const char *sig) {
+        return functions->GetStaticMethodID(this,clazz,name,sig);
+    }
+
+    jobject CallStaticObjectMethod(jclass clazz, jmethodID methodID,
+			     ...) {
+        va_list args;
+	jobject result;
+	va_start(args,methodID);
+	result = functions->CallStaticObjectMethodV(this,clazz,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jobject CallStaticObjectMethodV(jclass clazz, jmethodID methodID,
+			      va_list args) {
+        return functions->CallStaticObjectMethodV(this,clazz,methodID,args);
+    }
+    jobject CallStaticObjectMethodA(jclass clazz, jmethodID methodID,
+			      const jvalue *args) {
+        return functions->CallStaticObjectMethodA(this,clazz,methodID,args);
+    }
+
+    jboolean CallStaticBooleanMethod(jclass clazz,
+				     jmethodID methodID, ...) {
+        va_list args;
+	jboolean result;
+	va_start(args,methodID);
+	result = functions->CallStaticBooleanMethodV(this,clazz,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jboolean CallStaticBooleanMethodV(jclass clazz,
+				      jmethodID methodID, va_list args) {
+        return functions->CallStaticBooleanMethodV(this,clazz,methodID,args);
+    }
+    jboolean CallStaticBooleanMethodA(jclass clazz,
+				      jmethodID methodID, const jvalue *args) {
+        return functions->CallStaticBooleanMethodA(this,clazz,methodID,args);
+    }
+
+    jbyte CallStaticByteMethod(jclass clazz,
+			       jmethodID methodID, ...) {
+        va_list args;
+	jbyte result;
+	va_start(args,methodID);
+	result = functions->CallStaticByteMethodV(this,clazz,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jbyte CallStaticByteMethodV(jclass clazz,
+				jmethodID methodID, va_list args) {
+        return functions->CallStaticByteMethodV(this,clazz,methodID,args);
+    }
+    jbyte CallStaticByteMethodA(jclass clazz,
+				jmethodID methodID, const jvalue *args) {
+        return functions->CallStaticByteMethodA(this,clazz,methodID,args);
+    }
+
+    jchar CallStaticCharMethod(jclass clazz,
+			       jmethodID methodID, ...) {
+        va_list args;
+	jchar result;
+	va_start(args,methodID);
+	result = functions->CallStaticCharMethodV(this,clazz,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jchar CallStaticCharMethodV(jclass clazz,
+				jmethodID methodID, va_list args) {
+        return functions->CallStaticCharMethodV(this,clazz,methodID,args);
+    }
+    jchar CallStaticCharMethodA(jclass clazz,
+				jmethodID methodID, const jvalue *args) {
+        return functions->CallStaticCharMethodA(this,clazz,methodID,args);
+    }
+
+    jshort CallStaticShortMethod(jclass clazz,
+				 jmethodID methodID, ...) {
+        va_list args;
+	jshort result;
+	va_start(args,methodID);
+	result = functions->CallStaticShortMethodV(this,clazz,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jshort CallStaticShortMethodV(jclass clazz,
+				  jmethodID methodID, va_list args) {
+        return functions->CallStaticShortMethodV(this,clazz,methodID,args);
+    }
+    jshort CallStaticShortMethodA(jclass clazz,
+				  jmethodID methodID, const jvalue *args) {
+        return functions->CallStaticShortMethodA(this,clazz,methodID,args);
+    }
+
+    jint CallStaticIntMethod(jclass clazz,
+			     jmethodID methodID, ...) {
+        va_list args;
+	jint result;
+	va_start(args,methodID);
+	result = functions->CallStaticIntMethodV(this,clazz,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jint CallStaticIntMethodV(jclass clazz,
+			      jmethodID methodID, va_list args) {
+        return functions->CallStaticIntMethodV(this,clazz,methodID,args);
+    }
+    jint CallStaticIntMethodA(jclass clazz,
+			      jmethodID methodID, const jvalue *args) {
+        return functions->CallStaticIntMethodA(this,clazz,methodID,args);
+    }
+
+    jlong CallStaticLongMethod(jclass clazz,
+			       jmethodID methodID, ...) {
+        va_list args;
+	jlong result;
+	va_start(args,methodID);
+	result = functions->CallStaticLongMethodV(this,clazz,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jlong CallStaticLongMethodV(jclass clazz,
+				jmethodID methodID, va_list args) {
+        return functions->CallStaticLongMethodV(this,clazz,methodID,args);
+    }
+    jlong CallStaticLongMethodA(jclass clazz,
+				jmethodID methodID, const jvalue *args) {
+        return functions->CallStaticLongMethodA(this,clazz,methodID,args);
+    }
+
+    jfloat CallStaticFloatMethod(jclass clazz,
+				 jmethodID methodID, ...) {
+        va_list args;
+	jfloat result;
+	va_start(args,methodID);
+	result = functions->CallStaticFloatMethodV(this,clazz,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jfloat CallStaticFloatMethodV(jclass clazz,
+				  jmethodID methodID, va_list args) {
+        return functions->CallStaticFloatMethodV(this,clazz,methodID,args);
+    }
+    jfloat CallStaticFloatMethodA(jclass clazz,
+				  jmethodID methodID, const jvalue *args) {
+        return functions->CallStaticFloatMethodA(this,clazz,methodID,args);
+    }
+
+    jdouble CallStaticDoubleMethod(jclass clazz,
+				   jmethodID methodID, ...) {
+        va_list args;
+	jdouble result;
+	va_start(args,methodID);
+	result = functions->CallStaticDoubleMethodV(this,clazz,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jdouble CallStaticDoubleMethodV(jclass clazz,
+				    jmethodID methodID, va_list args) {
+        return functions->CallStaticDoubleMethodV(this,clazz,methodID,args);
+    }
+    jdouble CallStaticDoubleMethodA(jclass clazz,
+				    jmethodID methodID, const jvalue *args) {
+        return functions->CallStaticDoubleMethodA(this,clazz,methodID,args);
+    }
+
+    void CallStaticVoidMethod(jclass cls, jmethodID methodID, ...) {
+        va_list args;
+	va_start(args,methodID);
+	functions->CallStaticVoidMethodV(this,cls,methodID,args);
+	va_end(args);
+    }
+    void CallStaticVoidMethodV(jclass cls, jmethodID methodID,
+			       va_list args) {
+        functions->CallStaticVoidMethodV(this,cls,methodID,args);
+    }
+    void CallStaticVoidMethodA(jclass cls, jmethodID methodID,
+			       const jvalue * args) {
+        functions->CallStaticVoidMethodA(this,cls,methodID,args);
+    }
+
+    jfieldID GetStaticFieldID(jclass clazz, const char *name,
+			      const char *sig) {
+        return functions->GetStaticFieldID(this,clazz,name,sig);
+    }
+    jobject GetStaticObjectField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticObjectField(this,clazz,fieldID);
+    }
+    jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticBooleanField(this,clazz,fieldID);
+    }
+    jbyte GetStaticByteField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticByteField(this,clazz,fieldID);
+    }
+    jchar GetStaticCharField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticCharField(this,clazz,fieldID);
+    }
+    jshort GetStaticShortField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticShortField(this,clazz,fieldID);
+    }
+    jint GetStaticIntField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticIntField(this,clazz,fieldID);
+    }
+    jlong GetStaticLongField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticLongField(this,clazz,fieldID);
+    }
+    jfloat GetStaticFloatField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticFloatField(this,clazz,fieldID);
+    }
+    jdouble GetStaticDoubleField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticDoubleField(this,clazz,fieldID);
+    }
+
+    void SetStaticObjectField(jclass clazz, jfieldID fieldID,
+			jobject value) {
+      functions->SetStaticObjectField(this,clazz,fieldID,value);
+    }
+    void SetStaticBooleanField(jclass clazz, jfieldID fieldID,
+			jboolean value) {
+      functions->SetStaticBooleanField(this,clazz,fieldID,value);
+    }
+    void SetStaticByteField(jclass clazz, jfieldID fieldID,
+			jbyte value) {
+      functions->SetStaticByteField(this,clazz,fieldID,value);
+    }
+    void SetStaticCharField(jclass clazz, jfieldID fieldID,
+			jchar value) {
+      functions->SetStaticCharField(this,clazz,fieldID,value);
+    }
+    void SetStaticShortField(jclass clazz, jfieldID fieldID,
+			jshort value) {
+      functions->SetStaticShortField(this,clazz,fieldID,value);
+    }
+    void SetStaticIntField(jclass clazz, jfieldID fieldID,
+			jint value) {
+      functions->SetStaticIntField(this,clazz,fieldID,value);
+    }
+    void SetStaticLongField(jclass clazz, jfieldID fieldID,
+			jlong value) {
+      functions->SetStaticLongField(this,clazz,fieldID,value);
+    }
+    void SetStaticFloatField(jclass clazz, jfieldID fieldID,
+			jfloat value) {
+      functions->SetStaticFloatField(this,clazz,fieldID,value);
+    }
+    void SetStaticDoubleField(jclass clazz, jfieldID fieldID,
+			jdouble value) {
+      functions->SetStaticDoubleField(this,clazz,fieldID,value);
+    }
+
+    jstring NewString(const jchar *unicode, jsize len) {
+        return functions->NewString(this,unicode,len);
+    }
+    jsize GetStringLength(jstring str) {
+        return functions->GetStringLength(this,str);
+    }
+    const jchar *GetStringChars(jstring str, jboolean *isCopy) {
+        return functions->GetStringChars(this,str,isCopy);
+    }
+    void ReleaseStringChars(jstring str, const jchar *chars) {
+        functions->ReleaseStringChars(this,str,chars);
+    }
+
+    jstring NewStringUTF(const char *utf) {
+        return functions->NewStringUTF(this,utf);
+    }
+    jsize GetStringUTFLength(jstring str) {
+        return functions->GetStringUTFLength(this,str);
+    }
+    const char* GetStringUTFChars(jstring str, jboolean *isCopy) {
+        return functions->GetStringUTFChars(this,str,isCopy);
+    }
+    void ReleaseStringUTFChars(jstring str, const char* chars) {
+        functions->ReleaseStringUTFChars(this,str,chars);
+    }
+
+    jsize GetArrayLength(jarray array) {
+        return functions->GetArrayLength(this,array);
+    }
+
+    jobjectArray NewObjectArray(jsize len, jclass clazz,
+				jobject init) {
+        return functions->NewObjectArray(this,len,clazz,init);
+    }
+    jobject GetObjectArrayElement(jobjectArray array, jsize index) {
+        return functions->GetObjectArrayElement(this,array,index);
+    }
+    void SetObjectArrayElement(jobjectArray array, jsize index,
+			       jobject val) {
+        functions->SetObjectArrayElement(this,array,index,val);
+    }
+
+    jbooleanArray NewBooleanArray(jsize len) {
+        return functions->NewBooleanArray(this,len);
+    }
+    jbyteArray NewByteArray(jsize len) {
+        return functions->NewByteArray(this,len);
+    }
+    jcharArray NewCharArray(jsize len) {
+        return functions->NewCharArray(this,len);
+    }
+    jshortArray NewShortArray(jsize len) {
+        return functions->NewShortArray(this,len);
+    }
+    jintArray NewIntArray(jsize len) {
+        return functions->NewIntArray(this,len);
+    }
+    jlongArray NewLongArray(jsize len) {
+        return functions->NewLongArray(this,len);
+    }
+    jfloatArray NewFloatArray(jsize len) {
+        return functions->NewFloatArray(this,len);
+    }
+    jdoubleArray NewDoubleArray(jsize len) {
+        return functions->NewDoubleArray(this,len);
+    }
+
+    jboolean * GetBooleanArrayElements(jbooleanArray array, jboolean *isCopy) {
+        return functions->GetBooleanArrayElements(this,array,isCopy);
+    }
+    jbyte * GetByteArrayElements(jbyteArray array, jboolean *isCopy) {
+        return functions->GetByteArrayElements(this,array,isCopy);
+    }
+    jchar * GetCharArrayElements(jcharArray array, jboolean *isCopy) {
+        return functions->GetCharArrayElements(this,array,isCopy);
+    }
+    jshort * GetShortArrayElements(jshortArray array, jboolean *isCopy) {
+        return functions->GetShortArrayElements(this,array,isCopy);
+    }
+    jint * GetIntArrayElements(jintArray array, jboolean *isCopy) {
+        return functions->GetIntArrayElements(this,array,isCopy);
+    }
+    jlong * GetLongArrayElements(jlongArray array, jboolean *isCopy) {
+        return functions->GetLongArrayElements(this,array,isCopy);
+    }
+    jfloat * GetFloatArrayElements(jfloatArray array, jboolean *isCopy) {
+        return functions->GetFloatArrayElements(this,array,isCopy);
+    }
+    jdouble * GetDoubleArrayElements(jdoubleArray array, jboolean *isCopy) {
+        return functions->GetDoubleArrayElements(this,array,isCopy);
+    }
+
+    void ReleaseBooleanArrayElements(jbooleanArray array,
+				     jboolean *elems,
+				     jint mode) {
+        functions->ReleaseBooleanArrayElements(this,array,elems,mode);
+    }
+    void ReleaseByteArrayElements(jbyteArray array,
+				  jbyte *elems,
+				  jint mode) {
+        functions->ReleaseByteArrayElements(this,array,elems,mode);
+    }
+    void ReleaseCharArrayElements(jcharArray array,
+				  jchar *elems,
+				  jint mode) {
+        functions->ReleaseCharArrayElements(this,array,elems,mode);
+    }
+    void ReleaseShortArrayElements(jshortArray array,
+				   jshort *elems,
+				   jint mode) {
+        functions->ReleaseShortArrayElements(this,array,elems,mode);
+    }
+    void ReleaseIntArrayElements(jintArray array,
+				 jint *elems,
+				 jint mode) {
+        functions->ReleaseIntArrayElements(this,array,elems,mode);
+    }
+    void ReleaseLongArrayElements(jlongArray array,
+				  jlong *elems,
+				  jint mode) {
+        functions->ReleaseLongArrayElements(this,array,elems,mode);
+    }
+    void ReleaseFloatArrayElements(jfloatArray array,
+				   jfloat *elems,
+				   jint mode) {
+        functions->ReleaseFloatArrayElements(this,array,elems,mode);
+    }
+    void ReleaseDoubleArrayElements(jdoubleArray array,
+				    jdouble *elems,
+				    jint mode) {
+        functions->ReleaseDoubleArrayElements(this,array,elems,mode);
+    }
+
+    void GetBooleanArrayRegion(jbooleanArray array,
+			       jsize start, jsize len, jboolean *buf) {
+        functions->GetBooleanArrayRegion(this,array,start,len,buf);
+    }
+    void GetByteArrayRegion(jbyteArray array,
+			    jsize start, jsize len, jbyte *buf) {
+        functions->GetByteArrayRegion(this,array,start,len,buf);
+    }
+    void GetCharArrayRegion(jcharArray array,
+			    jsize start, jsize len, jchar *buf) {
+        functions->GetCharArrayRegion(this,array,start,len,buf);
+    }
+    void GetShortArrayRegion(jshortArray array,
+			     jsize start, jsize len, jshort *buf) {
+        functions->GetShortArrayRegion(this,array,start,len,buf);
+    }
+    void GetIntArrayRegion(jintArray array,
+			   jsize start, jsize len, jint *buf) {
+        functions->GetIntArrayRegion(this,array,start,len,buf);
+    }
+    void GetLongArrayRegion(jlongArray array,
+			    jsize start, jsize len, jlong *buf) {
+        functions->GetLongArrayRegion(this,array,start,len,buf);
+    }
+    void GetFloatArrayRegion(jfloatArray array,
+			     jsize start, jsize len, jfloat *buf) {
+        functions->GetFloatArrayRegion(this,array,start,len,buf);
+    }
+    void GetDoubleArrayRegion(jdoubleArray array,
+			      jsize start, jsize len, jdouble *buf) {
+        functions->GetDoubleArrayRegion(this,array,start,len,buf);
+    }
+
+    void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len,
+			       const jboolean *buf) {
+        functions->SetBooleanArrayRegion(this,array,start,len,buf);
+    }
+    void SetByteArrayRegion(jbyteArray array, jsize start, jsize len,
+			    const jbyte *buf) {
+        functions->SetByteArrayRegion(this,array,start,len,buf);
+    }
+    void SetCharArrayRegion(jcharArray array, jsize start, jsize len,
+			    const jchar *buf) {
+        functions->SetCharArrayRegion(this,array,start,len,buf);
+    }
+    void SetShortArrayRegion(jshortArray array, jsize start, jsize len,
+			     const jshort *buf) {
+        functions->SetShortArrayRegion(this,array,start,len,buf);
+    }
+    void SetIntArrayRegion(jintArray array, jsize start, jsize len,
+			   const jint *buf) {
+        functions->SetIntArrayRegion(this,array,start,len,buf);
+    }
+    void SetLongArrayRegion(jlongArray array, jsize start, jsize len,
+			    const jlong *buf) {
+        functions->SetLongArrayRegion(this,array,start,len,buf);
+    }
+    void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len,
+			     const jfloat *buf) {
+        functions->SetFloatArrayRegion(this,array,start,len,buf);
+    }
+    void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len,
+			      const jdouble *buf) {
+        functions->SetDoubleArrayRegion(this,array,start,len,buf);
+    }
+
+    jint RegisterNatives(jclass clazz, const JNINativeMethod *methods,
+			 jint nMethods) {
+        return functions->RegisterNatives(this,clazz,methods,nMethods);
+    }
+    jint UnregisterNatives(jclass clazz) {
+        return functions->UnregisterNatives(this,clazz);
+    }
+
+    jint MonitorEnter(jobject obj) {
+        return functions->MonitorEnter(this,obj);
+    }
+    jint MonitorExit(jobject obj) {
+        return functions->MonitorExit(this,obj);
+    }
+
+    jint GetJavaVM(JavaVM **vm) {
+        return functions->GetJavaVM(this,vm);
+    }
+
+    void GetStringRegion(jstring str, jsize start, jsize len, jchar *buf) {
+        functions->GetStringRegion(this,str,start,len,buf);
+    }
+    void GetStringUTFRegion(jstring str, jsize start, jsize len, char *buf) {
+        functions->GetStringUTFRegion(this,str,start,len,buf);
+    }
+
+    void * GetPrimitiveArrayCritical(jarray array, jboolean *isCopy) {
+        return functions->GetPrimitiveArrayCritical(this,array,isCopy);
+    }
+    void ReleasePrimitiveArrayCritical(jarray array, void *carray, jint mode) {
+        functions->ReleasePrimitiveArrayCritical(this,array,carray,mode);
+    }
+
+    const jchar * GetStringCritical(jstring string, jboolean *isCopy) {
+        return functions->GetStringCritical(this,string,isCopy);
+    }
+    void ReleaseStringCritical(jstring string, const jchar *cstring) {
+        functions->ReleaseStringCritical(this,string,cstring);
+    }
+
+    jweak NewWeakGlobalRef(jobject obj) {
+        return functions->NewWeakGlobalRef(this,obj);
+    }
+    void DeleteWeakGlobalRef(jweak ref) {
+        functions->DeleteWeakGlobalRef(this,ref);
+    }
+
+    jboolean ExceptionCheck() {
+	return functions->ExceptionCheck(this);
+    }
+
+    jobject NewDirectByteBuffer(void* address, jlong capacity) {
+        return functions->NewDirectByteBuffer(this, address, capacity);
+    }
+    void* GetDirectBufferAddress(jobject buf) {
+        return functions->GetDirectBufferAddress(this, buf);
+    }
+    jlong GetDirectBufferCapacity(jobject buf) {
+        return functions->GetDirectBufferCapacity(this, buf);
+    }
+    jobjectRefType GetObjectRefType(jobject obj) {
+        return functions->GetObjectRefType(this, obj);
+    }
+
+#endif /* __cplusplus */
+};
+
+typedef struct JavaVMOption {
+    char *optionString;
+    void *extraInfo;
+} JavaVMOption;
+
+typedef struct JavaVMInitArgs {
+    jint version;
+
+    jint nOptions;
+    JavaVMOption *options;
+    jboolean ignoreUnrecognized;
+} JavaVMInitArgs;
+
+typedef struct JavaVMAttachArgs {
+    jint version;
+
+    char *name;
+    jobject group;
+} JavaVMAttachArgs;
+
+#define JDK1_2
+#define JDK1_4
+
+struct JNIInvokeInterface_ {
+    void *reserved0;
+    void *reserved1;
+    void *reserved2;
+
+    jint (JNICALL *DestroyJavaVM)(JavaVM *vm);
+
+    jint (JNICALL *AttachCurrentThread)(JavaVM *vm, void **penv, void *args);
+
+    jint (JNICALL *DetachCurrentThread)(JavaVM *vm);
+
+    jint (JNICALL *GetEnv)(JavaVM *vm, void **penv, jint version);
+
+    jint (JNICALL *AttachCurrentThreadAsDaemon)(JavaVM *vm, void **penv, void *args);
+};
+
+struct JavaVM_ {
+    const struct JNIInvokeInterface_ *functions;
+#ifdef __cplusplus
+
+    jint DestroyJavaVM() {
+        return functions->DestroyJavaVM(this);
+    }
+    jint AttachCurrentThread(void **penv, void *args) {
+        return functions->AttachCurrentThread(this, penv, args);
+    }
+    jint DetachCurrentThread() {
+        return functions->DetachCurrentThread(this);
+    }
+
+    jint GetEnv(void **penv, jint version) {
+        return functions->GetEnv(this, penv, version);
+    }
+    jint AttachCurrentThreadAsDaemon(void **penv, void *args) {
+        return functions->AttachCurrentThreadAsDaemon(this, penv, args);
+    }
+#endif
+};
+
+#ifdef _JNI_IMPLEMENTATION_
+#define _JNI_IMPORT_OR_EXPORT_ JNIEXPORT
+#else
+#define _JNI_IMPORT_OR_EXPORT_ JNIIMPORT
+#endif
+_JNI_IMPORT_OR_EXPORT_ jint JNICALL
+JNI_GetDefaultJavaVMInitArgs(void *args);
+
+_JNI_IMPORT_OR_EXPORT_ jint JNICALL
+JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args);
+
+_JNI_IMPORT_OR_EXPORT_ jint JNICALL
+JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *);
+
+JNIEXPORT jint JNICALL
+JNI_OnLoad(JavaVM *vm, void *reserved);
+
+JNIEXPORT void JNICALL
+JNI_OnUnload(JavaVM *vm, void *reserved);
+
+#define JNI_VERSION_1_1 0x00010001
+#define JNI_VERSION_1_2 0x00010002
+#define JNI_VERSION_1_4 0x00010004
+#define JNI_VERSION_1_6 0x00010006
+
+#endif /*  __GLUEGEN__ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* !_JAVASOFT_JNI_H_ */
+
diff --git a/make/stub_includes/jni/macosx/jawt_md.h b/make/stub_includes/jni/macosx/jawt_md.h
index 3b019dd..519a513 100644
--- a/make/stub_includes/jni/macosx/jawt_md.h
+++ b/make/stub_includes/jni/macosx/jawt_md.h
@@ -1,9 +1,4 @@
 /**
- * Temporary workaround!
- * 
- * Provided darwin/jawt_md.h from Oracle for OSX / Java7
- * has X11 dependencies and does not define JAWT_SurfaceLayers. 
- *
  * This C header file is derived from Apple's Java SDK provided C header file
  * with the following copyright notice:
  *
@@ -59,7 +54,7 @@ JAWT_MacOSXDrawingSurfaceInfo;
     @property (readonly) CALayer *windowLayer;
     @end
 
-#endif /* __GLUEGEN__ */
+#endif __GLUEGEN__
 
 #ifdef __cplusplus
 }
diff --git a/make/stub_includes/jni/macosx/jni_md.h b/make/stub_includes/jni/macosx/jni_md.h
index 7f52704..f64bda4 100644
--- a/make/stub_includes/jni/macosx/jni_md.h
+++ b/make/stub_includes/jni/macosx/jni_md.h
@@ -1,9 +1,4 @@
 /*
- * Temporary workaround!
- * 
- * Provided darwin/jawt_md.h from Oracle for OSX / Java7
- * has X11 dependencies and does not define JAWT_SurfaceLayers. 
- *
  * @(#)jni_md.h	1.18 03/12/19
  *
  * This C header file is derived from Sun Microsystem's Java SDK provided C header file
@@ -32,16 +27,20 @@
 #ifndef _JAVASOFT_JNI_MD_H_
 #define _JAVASOFT_JNI_MD_H_
 
-#define JNIEXPORT __attribute__((visibility("default")))
-#define JNIIMPORT
-#define JNICALL
+#include <gluegen_stdint.h>
+
+#ifdef __GLUEGEN__
+    #define JNIEXPORT
+    #define JNIIMPORT
+    #define JNICALL
+#else /* __GLUEGEN__ */
+    #define JNIEXPORT __attribute__((visibility("default")))
+    #define JNIIMPORT __attribute__((visibility("default")))
+    #define JNICALL
+#endif /* __GLUEGEN__ */
 
-#if __LP64__
-typedef int jint;
-#else
-typedef long jint;
-#endif
-typedef long long jlong;
-typedef signed char jbyte;
+typedef int8_t  jbyte;
+typedef int32_t jint;
+typedef int64_t jlong;
 
 #endif /* !_JAVASOFT_JNI_MD_H_ */
diff --git a/make/stub_includes/jni/macosx/jni_md.h b/make/stub_includes/jni/win32/jawt_md.h
similarity index 73%
copy from make/stub_includes/jni/macosx/jni_md.h
copy to make/stub_includes/jni/win32/jawt_md.h
index 7f52704..23be13c 100644
--- a/make/stub_includes/jni/macosx/jni_md.h
+++ b/make/stub_includes/jni/win32/jawt_md.h
@@ -1,10 +1,5 @@
 /*
- * Temporary workaround!
- * 
- * Provided darwin/jawt_md.h from Oracle for OSX / Java7
- * has X11 dependencies and does not define JAWT_SurfaceLayers. 
- *
- * @(#)jni_md.h	1.18 03/12/19
+ * @(#)jawt_md.h	1.8 05/11/17
  *
  * This C header file is derived from Sun Microsystem's Java SDK provided C header file
  * with the following copyright notice:
@@ -29,19 +24,31 @@
  * L 111/17 (10) and (15)
  */
 
-#ifndef _JAVASOFT_JNI_MD_H_
-#define _JAVASOFT_JNI_MD_H_
+#ifndef _JAVASOFT_JAWT_MD_H_
+#define _JAVASOFT_JAWT_MD_H_
+
+#include <windows.h>
+#include "jawt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct jawt_Win32DrawingSurfaceInfo {
+    /**
+    union {
+        HWND hwnd;
+        HBITMAP hbitmap;
+        void* pbits;
+    }; */
+    HWND handle;
 
-#define JNIEXPORT __attribute__((visibility("default")))
-#define JNIIMPORT
-#define JNICALL
+    HDC hdc;
+    HPALETTE hpalette;
+} JAWT_Win32DrawingSurfaceInfo;
 
-#if __LP64__
-typedef int jint;
-#else
-typedef long jint;
+#ifdef __cplusplus
+}
 #endif
-typedef long long jlong;
-typedef signed char jbyte;
 
-#endif /* !_JAVASOFT_JNI_MD_H_ */
+#endif /* !_JAVASOFT_JAWT_MD_H_ */
diff --git a/make/stub_includes/jni/macosx/jni_md.h b/make/stub_includes/jni/win32/jni_md.h
similarity index 77%
copy from make/stub_includes/jni/macosx/jni_md.h
copy to make/stub_includes/jni/win32/jni_md.h
index 7f52704..34282c8 100644
--- a/make/stub_includes/jni/macosx/jni_md.h
+++ b/make/stub_includes/jni/win32/jni_md.h
@@ -1,10 +1,5 @@
 /*
- * Temporary workaround!
- * 
- * Provided darwin/jawt_md.h from Oracle for OSX / Java7
- * has X11 dependencies and does not define JAWT_SurfaceLayers. 
- *
- * @(#)jni_md.h	1.18 03/12/19
+ * @(#)jni_md.h	1.15 05/11/17
  *
  * This C header file is derived from Sun Microsystem's Java SDK provided C header file
  * with the following copyright notice:
@@ -32,16 +27,20 @@
 #ifndef _JAVASOFT_JNI_MD_H_
 #define _JAVASOFT_JNI_MD_H_
 
-#define JNIEXPORT __attribute__((visibility("default")))
-#define JNIIMPORT
-#define JNICALL
+#include <gluegen_stdint.h>
+
+#ifdef __GLUEGEN__
+    #define JNIEXPORT
+    #define JNIIMPORT
+    #define JNICALL
+#else /* __GLUEGEN__ */
+    #define JNIEXPORT __declspec(dllexport)
+    #define JNIIMPORT __declspec(dllimport)
+    #define JNICALL __stdcall
+#endif /* __GLUEGEN__ */
 
-#if __LP64__
-typedef int jint;
-#else
-typedef long jint;
-#endif
-typedef long long jlong;
-typedef signed char jbyte;
+typedef int8_t  jbyte;
+typedef int32_t jint;
+typedef int64_t jlong;
 
 #endif /* !_JAVASOFT_JNI_MD_H_ */
diff --git a/make/stub_includes/jni/macosx/jni_md.h b/make/stub_includes/jni/x11/jawt_md.h
similarity index 69%
copy from make/stub_includes/jni/macosx/jni_md.h
copy to make/stub_includes/jni/x11/jawt_md.h
index 7f52704..0879de8 100644
--- a/make/stub_includes/jni/macosx/jni_md.h
+++ b/make/stub_includes/jni/x11/jawt_md.h
@@ -1,10 +1,5 @@
 /*
- * Temporary workaround!
- * 
- * Provided darwin/jawt_md.h from Oracle for OSX / Java7
- * has X11 dependencies and does not define JAWT_SurfaceLayers. 
- *
- * @(#)jni_md.h	1.18 03/12/19
+ * @(#)jawt_md.h	1.12 05/11/17
  *
  * This C header file is derived from Sun Microsystem's Java SDK provided C header file
  * with the following copyright notice:
@@ -29,19 +24,33 @@
  * L 111/17 (10) and (15)
  */
 
-#ifndef _JAVASOFT_JNI_MD_H_
-#define _JAVASOFT_JNI_MD_H_
+#ifndef _JAVASOFT_JAWT_MD_H_
+#define _JAVASOFT_JAWT_MD_H_
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Intrinsic.h>
+#include "jawt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
 
-#define JNIEXPORT __attribute__((visibility("default")))
-#define JNIIMPORT
-#define JNICALL
+typedef struct jawt_X11DrawingSurfaceInfo {
+    Drawable drawable;
+    Display* display;
+    VisualID visualID;
+    Colormap colormapID;
+    int depth;
+    /*
+     * Since 1.4
+     */
+    int (JNICALL *GetAWTColor)(JAWT_DrawingSurface* ds,
+        int r, int g, int b);
+} JAWT_X11DrawingSurfaceInfo;
 
-#if __LP64__
-typedef int jint;
-#else
-typedef long jint;
+#ifdef __cplusplus
+}
 #endif
-typedef long long jlong;
-typedef signed char jbyte;
 
-#endif /* !_JAVASOFT_JNI_MD_H_ */
+#endif /* !_JAVASOFT_JAWT_MD_H_ */
diff --git a/make/stub_includes/jni/macosx/jni_md.h b/make/stub_includes/jni/x11/jni_md.h
similarity index 79%
copy from make/stub_includes/jni/macosx/jni_md.h
copy to make/stub_includes/jni/x11/jni_md.h
index 7f52704..39d3abf 100644
--- a/make/stub_includes/jni/macosx/jni_md.h
+++ b/make/stub_includes/jni/x11/jni_md.h
@@ -1,10 +1,5 @@
 /*
- * Temporary workaround!
- * 
- * Provided darwin/jawt_md.h from Oracle for OSX / Java7
- * has X11 dependencies and does not define JAWT_SurfaceLayers. 
- *
- * @(#)jni_md.h	1.18 03/12/19
+ * @(#)jni_md.h	1.19 05/11/17
  *
  * This C header file is derived from Sun Microsystem's Java SDK provided C header file
  * with the following copyright notice:
@@ -32,16 +27,14 @@
 #ifndef _JAVASOFT_JNI_MD_H_
 #define _JAVASOFT_JNI_MD_H_
 
-#define JNIEXPORT __attribute__((visibility("default")))
+#include <gluegen_stdint.h>
+
+#define JNIEXPORT 
 #define JNIIMPORT
 #define JNICALL
 
-#if __LP64__
-typedef int jint;
-#else
-typedef long jint;
-#endif
-typedef long long jlong;
-typedef signed char jbyte;
+typedef int8_t  jbyte;
+typedef int32_t jint;
+typedef int64_t jlong;
 
 #endif /* !_JAVASOFT_JNI_MD_H_ */
diff --git a/make/stub_includes/os/elf_header.h b/make/stub_includes/os/elf_header.h
index 7d608f0..b303029 100644
--- a/make/stub_includes/os/elf_header.h
+++ b/make/stub_includes/os/elf_header.h
@@ -15,6 +15,9 @@ typedef struct {
     uint16_t        e_type;
     uint16_t        e_machine;
     uint32_t        e_version;
+} Ehdr_p1;
+
+typedef struct {
     ElfN_Addr       e_entry;
     ElfN_Off        e_phoff;
     ElfN_Off        e_shoff;
@@ -25,7 +28,7 @@ typedef struct {
     uint16_t        e_shentsize;
     uint16_t        e_shnum;
     uint16_t        e_shstrndx;
-} Ehdr;
+} Ehdr_p2;
 
 typedef struct {
     uint32_t        sh_name;     
diff --git a/make/stub_includes/platform/glibc-compat-symbols.h b/make/stub_includes/platform/glibc-compat-symbols.h
index 3599b82..1163c78 100644
--- a/make/stub_includes/platform/glibc-compat-symbols.h
+++ b/make/stub_includes/platform/glibc-compat-symbols.h
@@ -17,7 +17,9 @@
  */
 #if defined(__linux__) /* Actually we like to test whether we link against GLIBC .. */
     #if defined(__GNUC__)
-        #if defined(__arm__)
+        #if defined(__aarch64__)
+           #define GLIBC_COMPAT_SYMBOL(FFF) __asm__(".symver " #FFF "," #FFF "@GLIBC_2.4");
+        #elif defined(__arm__)
            #define GLIBC_COMPAT_SYMBOL(FFF) __asm__(".symver " #FFF "," #FFF "@GLIBC_2.4");
         #elif defined(__amd64__)
            #define GLIBC_COMPAT_SYMBOL(FFF) __asm__(".symver " #FFF "," #FFF "@GLIBC_2.2.5");
@@ -25,7 +27,9 @@
            #define GLIBC_COMPAT_SYMBOL(FFF) __asm__(".symver " #FFF "," #FFF "@GLIBC_2.0");
         #endif /*__amd64__*/
     #elif defined(__clang__)
-        #if defined(__arm__)
+        #if defined(__aarch64__)
+           #define GLIBC_COMPAT_SYMBOL(FFF) asm(".symver " #FFF "," #FFF "@GLIBC_2.4");
+        #elif defined(__arm__)
            #define GLIBC_COMPAT_SYMBOL(FFF) asm(".symver " #FFF "," #FFF "@GLIBC_2.4");
         #elif defined(__amd64__)
            #define GLIBC_COMPAT_SYMBOL(FFF) asm(".symver " #FFF "," #FFF "@GLIBC_2.2.5");
diff --git a/make/stub_includes/platform/gluegen_stddef.h b/make/stub_includes/platform/gluegen_stddef.h
index 6272bd1..1500684 100644
--- a/make/stub_includes/platform/gluegen_stddef.h
+++ b/make/stub_includes/platform/gluegen_stddef.h
@@ -15,7 +15,7 @@
 #elif defined(_WIN32)
     typedef          __int32 ptrdiff_t;
     typedef unsigned __int32 size_t;
-#elif defined(__ia64__) || defined(__x86_64__)
+#elif defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) || defined(__aarch64__)
     typedef             long ptrdiff_t;
     typedef unsigned    long size_t;
 #else
diff --git a/make/stub_includes/platform/gluegen_stdint.h b/make/stub_includes/platform/gluegen_stdint.h
index 8b1dbe3..b277817 100644
--- a/make/stub_includes/platform/gluegen_stdint.h
+++ b/make/stub_includes/platform/gluegen_stdint.h
@@ -33,7 +33,7 @@
 
     typedef            __int32  intptr_t;
     typedef unsigned   __int32 uintptr_t;
-#elif defined(__ia64__) || defined(__x86_64__)
+#elif defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) || defined(__aarch64__)
     typedef signed        char   int8_t;
     typedef unsigned      char  uint8_t;
     typedef signed       short  int16_t;
diff --git a/src/antlr/com/jogamp/gluegen/cgram/GnuCParser.g b/src/antlr/com/jogamp/gluegen/cgram/GnuCParser.g
index e8ca8c5..bf01b12 100644
--- a/src/antlr/com/jogamp/gluegen/cgram/GnuCParser.g
+++ b/src/antlr/com/jogamp/gluegen/cgram/GnuCParser.g
@@ -23,6 +23,7 @@ header {
 
         import antlr.CommonAST;
         import antlr.DumpASTVisitor;
+        import com.jogamp.gluegen.ASTLocusTag;
 }
 
            
@@ -715,7 +716,7 @@ tokens {
   
   public void addDefine(String name, String value)
   {
-    defines.add(new Define(name, value));
+    defines.add(new Define(name, value, new ASTLocusTag(lineObject.getSource(), lineObject.getLine()+deferredLineCount, -1, name)));
   }
 
   /** Returns a list of Define objects corresponding to the
diff --git a/src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g b/src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g
index 01f10c3..4bcb052 100644
--- a/src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g
+++ b/src/antlr/com/jogamp/gluegen/cgram/HeaderParser.g
@@ -45,6 +45,9 @@ header {
         import java.util.*;
 
         import antlr.CommonAST;
+        import com.jogamp.gluegen.ASTLocusTag;
+        import com.jogamp.gluegen.GlueGenException;
+        import com.jogamp.gluegen.JavaConfiguration;
         import com.jogamp.gluegen.cgram.types.*;
 }
 
@@ -67,6 +70,12 @@ options {
         this.debug = debug;
     }
 
+    /** Set the configuration for this
+        HeaderParser. Must be done before parsing. */
+    public void setJavaConfiguration(JavaConfiguration cfg) {
+        this.cfg = cfg;
+    }
+
     /** Set the dictionary mapping typedef names to types for this
         HeaderParser. Must be done before parsing. */
     public void setTypedefDictionary(TypeDictionary dict) {
@@ -105,7 +114,7 @@ options {
         // the enumerates from each EnumType, and fill in the enumHash
         // so that each enumerate maps to the enumType to which it
         // belongs.
-                throw new RuntimeException("setEnums is Unimplemented!");
+        throw new RuntimeException("setEnums is Unimplemented!");
     }
 
     /** Returns the EnumTypes this HeaderParser processed. */
@@ -125,22 +134,25 @@ options {
         return functions;
     }
 
-    private CompoundType lookupInStructDictionary(String typeName,
+    private CompoundType lookupInStructDictionary(String structName,
                                                   CompoundTypeKind kind,
-                                                  int cvAttrs) {
-        CompoundType t = (CompoundType) structDictionary.get(typeName);
+                                                  int cvAttrs, final ASTLocusTag locusTag) 
+    {
+        CompoundType t = (CompoundType) structDictionary.get(structName);
         if (t == null) {
-            t = CompoundType.create(null, null, kind, cvAttrs);
-            t.setStructName(typeName);
-            structDictionary.put(typeName, t);
+            t = CompoundType.create(structName, null, kind, cvAttrs, locusTag);
+            structDictionary.put(structName, t);
+            debugPrintln("Adding compound mapping: [" + structName + "] -> "+getDebugTypeString(t)+" @ "+locusTag);
+            debugPrintln(t.getStructString());
         }
         return t;
     }
 
-    private Type lookupInTypedefDictionary(String typeName) {
+    private Type lookupInTypedefDictionary(final AST _t, String typeName) {
         Type t = typedefDictionary.get(typeName);
         if (t == null) {
-            throw new RuntimeException("Undefined reference to typedef name " + typeName);
+            throwGlueGenException(_t,
+                 "Undefined reference to typedef name " + typeName);
         }
         return t;
     }
@@ -153,8 +165,10 @@ options {
             this.id = id;
             this.type = type;
         }
-        String id()             { return id; }
-        Type   type()           { return type; }
+        String id()              { return id; }
+        Type   type()            { return type; }
+        void setType(final Type t) { type = t; }
+        public String toString() { return "ParamDecl["+id+": "+type.getDebugString()+"]"; }
     }
 
     // A box for a Type. Allows type to be passed down to be modified by recursive rules.
@@ -207,22 +221,27 @@ options {
             }
     }
 
+    private String getDebugTypeString(Type t) {
+      if(debug) {
+        return getTypeString(t);
+      } else {
+        return null;
+      }
+    }
     private String getTypeString(Type t) {
       StringBuilder sb = new StringBuilder();
       sb.append("[");
-      sb.append(t);
-      sb.append(", size: ");
       if(null!=t) {
-        SizeThunk st = t.getSize();
-        if(null!=st) {
-          sb.append(st.getClass().getName());
-        } else {
-          sb.append("undef");
-        }
+        sb.append(t.getDebugString());
+        sb.append(", opaque ").append(isOpaque(t)).append("]");
+      } else {
+        sb.append("nil]");
       }
-      sb.append("]");
       return sb.toString();
     }
+    private boolean isOpaque(final Type type) {
+      return (cfg.typeInfo(type) != null);
+    }
 
     private void debugPrintln(String msg) {
         if(debug) {
@@ -236,14 +255,13 @@ options {
         }
     }
 
-    private boolean doDeclaration;   // Used to only process function typedefs
-    private String  declId;
-    private List    parameters;
+    private JavaConfiguration cfg;
     private TypeDictionary typedefDictionary;
     private TypeDictionary structDictionary;
     private List<FunctionSymbol> functions = new ArrayList<FunctionSymbol>();
     // hash from name of an enumerated value to the EnumType to which it belongs
     private HashMap<String, EnumType> enumHash = new HashMap<String, EnumType>();
+    private HashMap<String, EnumType> enumMap = new HashMap<String, EnumType>();
 
     // Storage class specifiers
     private static final int AUTO     = 1 << 0;
@@ -259,25 +277,41 @@ options {
     private static final int SIGNED   = 1 << 8;
     private static final int UNSIGNED = 1 << 9;
 
-    private void initDeclaration() {
-        doDeclaration = false;
-        declId = null;
-    }
+    private boolean isFuncDeclaration;   // Used to only process function typedefs
+    private String  funcDeclName;
+    private List<ParameterDeclaration> funcDeclParams;
+    private ASTLocusTag funcLocusTag;
 
-    private void doDeclaration() {
-        doDeclaration = true;
+    private void resetFuncDeclaration() {
+        isFuncDeclaration = false;
+        funcDeclName = null;
+        funcDeclParams = null;
+        funcLocusTag = null;
+    }
+    private void setFuncDeclaration(final String name, final List<ParameterDeclaration> p, final ASTLocusTag locusTag) {
+        isFuncDeclaration = true;
+        funcDeclName = name;
+        funcDeclParams = p;
+        funcLocusTag = locusTag;
     }
 
     private void processDeclaration(Type returnType) {
-        if (doDeclaration) {
-            FunctionSymbol sym = new FunctionSymbol(declId, new FunctionType(null, null, returnType, 0));
-                if (parameters != null) { // handle funcs w/ empty parameter lists (e.g., "foo()")
-                for (Iterator iter = parameters.iterator(); iter.hasNext(); ) {
-                    ParameterDeclaration pd = (ParameterDeclaration) iter.next();
+        if (isFuncDeclaration) {
+            final FunctionSymbol sym = new FunctionSymbol(funcDeclName, 
+                                                          new FunctionType(null, null, returnType, 0, funcLocusTag),
+                                                          funcLocusTag);
+            debugPrintln("Function ... "+sym.toString()+" @ "+funcLocusTag);
+            if (funcDeclParams != null) { // handle funcs w/ empty parameter lists (e.g., "foo()")
+                for (Iterator<ParameterDeclaration> iter = funcDeclParams.iterator(); iter.hasNext(); ) {
+                    ParameterDeclaration pd = iter.next();
+                    pd.setType(pd.type());
+                    debugPrintln(" add "+pd.toString());
                     sym.addArgument(pd.type(), pd.id());
                 }
-                }
+            }
+            debugPrintln("Function Added "+sym.toString());
             functions.add(sym);
+            resetFuncDeclaration();
         }
     }
 
@@ -294,19 +328,18 @@ options {
 
     /** Helper routine which handles creating a pointer or array type
         for [] expressions */
-    private void handleArrayExpr(TypeBox tb, AST t) {
+    private void handleArrayExpr(TypeBox tb, AST t, ASTLocusTag locusTag) {
         if (t != null) {
             try {
                 final int len = parseIntConstExpr(t);
-                tb.setType(canonicalize(new ArrayType(tb.type(), SizeThunk.mul(SizeThunk.constant(len), tb.type().getSize()), len, 0)));
+                tb.setType(canonicalize(new ArrayType(tb.type(), SizeThunk.mul(SizeThunk.constant(len), tb.type().getSize()), len, 0, locusTag)));
                 return;
             } catch (RecognitionException e) {
                 // Fall through
             }
         }
         tb.setType(canonicalize(new PointerType(SizeThunk.POINTER,
-                                                tb.type(),
-                                                0)));
+                                                tb.type(), 0, locusTag)));
     }
 
     private int parseIntConstExpr(AST t) throws RecognitionException {
@@ -315,49 +348,104 @@ options {
 
   /** Utility function: creates a new EnumType with the given name, or
           returns an existing one if it has already been created. */
-  private EnumType getEnumType(String enumTypeName) {
+    private EnumType getEnumType(String enumTypeName, ASTLocusTag locusTag) {
         EnumType enumType = null;
         Iterator<EnumType> it = enumHash.values().iterator(); 
         while (it.hasNext()) {
           EnumType potentialMatch = it.next();
           if (potentialMatch.getName().equals(enumTypeName)) {
-                enumType = potentialMatch;
-                break;        
+              enumType = potentialMatch;
+              break;        
           }
         }
         
         if (enumType == null) {
-      // This isn't quite correct. In theory the enum should expand to
-      // the size of the largest element, so if there were a long long
-      // entry the enum should expand to e.g. int64. However, using
-      // "long" here (which is what used to be the case) was 
-      // definitely incorrect and caused problems.
-          enumType = new EnumType(enumTypeName, SizeThunk.INT32);
+          // This isn't quite correct. In theory the enum should expand to
+          // the size of the largest element, so if there were a long long
+          // entry the enum should expand to e.g. int64. However, using
+          // "long" here (which is what used to be the case) was 
+          // definitely incorrect and caused problems.
+          enumType = new EnumType(enumTypeName, SizeThunk.INT32, locusTag);
         }  
         
         return enumType;
-  }        
+    }        
   
   // Map used to canonicalize types. For example, we may typedef
   // struct foo { ... } *pfoo; subsequent references to struct foo* should
   // point to the same PointerType object that had its name set to "pfoo".
-  private Map canonMap = new HashMap();
+  // Opaque canonical types are excluded.
+  private Map<Type, Type> canonMap = new HashMap<Type, Type>();
   private Type canonicalize(Type t) {
     Type res = (Type) canonMap.get(t);
     if (res != null) {
       return res;
+    } else {
+      canonMap.put(t, t);
+      return t;
+    }
+  }
+
+  private void throwGlueGenException(final AST t, final String message) throws GlueGenException {
+    // dumpASTTree("XXX", t);
+    throw new GlueGenException(message, findASTLocusTag(t));
+  }
+  private void throwGlueGenException(final ASTLocusTag locusTag, final String message) throws GlueGenException {
+    // dumpASTTree("XXX", t);
+    throw new GlueGenException(message, locusTag);
+  }
+
+  /**
+   * Return ASTLocusTag in tree, or null if not found.
+   */
+  private ASTLocusTag findASTLocusTag(final AST astIn) {
+    AST ast = astIn;
+    while(null != ast) {
+        if( ast instanceof TNode ) {
+            final TNode tn = (TNode) ast;
+            final ASTLocusTag tag = tn.getASTLocusTag();
+            if( null != tag ) {
+                return tag;
+            }
+        }
+        ast = ast.getFirstChild();
+    }
+    return null;
+  }
+  private void dumpASTTree(final String pre, final AST t) {
+    int i=0;
+    AST it = t;
+    while( null != it ) {
+        it = dumpAST(pre+"."+i, it);
+        i++;
+    }
+  }
+  private AST dumpAST(final String pre, final AST ast) {
+    if( null == ast ) {
+        System.err.println(pre+".0: AST NULL");
+        return null;
+    } else {
+        System.err.println(pre+".0: AST Type: "+ast.getClass().getName());
+        System.err.println(pre+".1: line:col "+ast.getLine()+":"+ast.getColumn()+" -> "+ast.getText());
+        if( ast instanceof TNode ) {
+            final TNode tn = (TNode) ast;
+            final ASTLocusTag tag = tn.getASTLocusTag();
+            System.err.println(pre+".TN.1: "+tag);
+            final Hashtable<String, Object> attributes = tn.getAttributesTable();
+            System.err.println(pre+".TN.2: "+attributes);
+        }
+        return ast.getFirstChild();
     }
-    canonMap.put(t, t);
-    return t;
   }
 }
 
 declarator[TypeBox tb] returns [String s] {
-    initDeclaration();
+    resetFuncDeclaration();
     s = null;
-    List params = null;
+    List<ParameterDeclaration> params = null;
     String funcPointerName = null;
     TypeBox dummyTypeBox = null;
+    final ASTLocusTag locusTag = findASTLocusTag(declarator_AST_in);
 }
         :   #( NDeclarator
                 ( pointerGroup[tb] )?
@@ -374,32 +462,29 @@ declarator[TypeBox tb] returns [String s] {
                       RPAREN
                     )  {
                            if (id != null) {
-                               declId = id.getText();
-                               parameters = params; // FIXME: Ken, why are we setting this class member here? 
-                               doDeclaration();
+                               setFuncDeclaration(id.getText(), params, locusTag);
                            } else if ( funcPointerName != null ) {
                                /* TypeBox becomes function pointer in this case */
-                               FunctionType ft = new FunctionType(null, null, tb.type(), 0);
+                               final FunctionType ft = new FunctionType(null, null, tb.type(), 0, locusTag);
                                if (params == null) {
-                                                     // If the function pointer has no declared parameters, it's a 
-                                               // void function. I'm not sure if the parameter name is 
-                                               // ever referenced anywhere when the type is VoidType, so
+                                   // If the function pointer has no declared parameters, it's a 
+                                   // void function. I'm not sure if the parameter name is 
+                                   // ever referenced anywhere when the type is VoidType, so
                                    // just in case I'll set it to a comment string so it will
-                                               // still compile if written out to code anywhere.
-                                                     ft.addArgument(new VoidType(0), "/*unnamed-void*/");
-                                           } else {
-                                                     for (Iterator iter = params.iterator(); iter.hasNext(); ) {
-                                     ParameterDeclaration pd = (ParameterDeclaration) iter.next();
-                                     ft.addArgument(pd.type(), pd.id());
-                                                   }
+                                   // still compile if written out to code anywhere.
+                                   ft.addArgument(new VoidType(0, locusTag), "/*unnamed-void*/");
+                               } else {
+                                   for (Iterator iter = params.iterator(); iter.hasNext(); ) {
+                                       ParameterDeclaration pd = (ParameterDeclaration) iter.next();
+                                       ft.addArgument(pd.type(), pd.id());
+                                   }
                                }
                                tb.setType(canonicalize(new PointerType(SizeThunk.POINTER,
-                                                                       ft,
-                                                                       0)));
+                                                                       ft, 0, locusTag)));
                                s = funcPointerName;
                            }
                        }
-                 | LBRACKET ( e:expr )? RBRACKET { handleArrayExpr(tb, e); }
+                 | LBRACKET ( e:expr )? RBRACKET { handleArrayExpr(tb, e, locusTag); }
                 )*
              )
         ;
@@ -422,8 +507,8 @@ declaration {
                 ) { processDeclaration(tb.type()); }
         ;
 
-parameterTypeList returns [List l] { l = new ArrayList(); ParameterDeclaration decl = null; }
-        :       ( decl = parameterDeclaration { if (decl != null) l.add(decl); } ( COMMA | SEMI )? )+ ( VARARGS )?
+parameterTypeList returns [List<ParameterDeclaration> l] { l = new ArrayList<ParameterDeclaration>(); ParameterDeclaration decl = null; }
+        :       ( decl = parameterDeclaration { if (decl != null) { l.add(decl); } } ( COMMA | SEMI )? )+ ( VARARGS )?
         ;
 
 parameterDeclaration returns [ParameterDeclaration pd] {
@@ -435,7 +520,13 @@ parameterDeclaration returns [ParameterDeclaration pd] {
         :       #( NParameterDeclaration
                 tb    = declSpecifiers
                 (decl = declarator[tb] | nonemptyAbstractDeclarator[tb])?
-                ) { pd = new ParameterDeclaration(decl, tb.type()); }
+                ) { 
+                  if( null == tb ) {
+                    throwGlueGenException(parameterDeclaration_AST_in,
+                        String.format("Undefined type for declaration '%s'", decl));
+                  }
+                  pd = new ParameterDeclaration(decl, tb.type()); 
+                }
         ;
 
 functionDef {
@@ -462,7 +553,10 @@ declSpecifiers returns [TypeBox tb] {
 {
             if (t == null &&
                 (x & (SIGNED | UNSIGNED)) != 0) {
-                t = new IntType("int", SizeThunk.INTxx, ((x & UNSIGNED) != 0), attrs2CVAttrs(x));
+                t = new IntType("int", SizeThunk.INTxx, 
+                                ((x & UNSIGNED) != 0), 
+                                attrs2CVAttrs(x),
+                                findASTLocusTag(declSpecifiers_AST_in));
             }
             tb = new TypeBox(t, ((x & TYPEDEF) != 0));
 }
@@ -493,30 +587,35 @@ typeQualifier returns [int x] { x = 0; }
 typeSpecifier[int attributes] returns [Type t] {
     t = null;
     int cvAttrs = attrs2CVAttrs(attributes);
-    boolean unsigned = ((attributes & UNSIGNED) != 0);
+    boolean unsig = ((attributes & UNSIGNED) != 0);
+    final ASTLocusTag locusTag = findASTLocusTag(typeSpecifier_AST_in);
 }
-        :       "void"      { t = new VoidType(cvAttrs); }
-        |       "char"      { t = new IntType("char" , SizeThunk.INT8,  unsigned, cvAttrs); }
-        |       "short"     { t = new IntType("short", SizeThunk.INT16, unsigned, cvAttrs); }
-        |       "int"       { t = new IntType("int"  , SizeThunk.INTxx, unsigned, cvAttrs); }
-        |       "long"      { t = new IntType("long" , SizeThunk.LONG,  unsigned, cvAttrs); }
-        |       "float"     { t = new FloatType("float", SizeThunk.FLOAT, cvAttrs); }
-        |       "double"    { t = new DoubleType("double", SizeThunk.DOUBLE, cvAttrs); }
-        |       "__int32"   { t = new IntType("__int32", SizeThunk.INT32, unsigned, cvAttrs); }
-        |       "__int64"   { t = new IntType("__int64", SizeThunk.INT64, unsigned, cvAttrs); }
-        |       "int8_t"    { t = new IntType("int8_t", SizeThunk.INT8, false, cvAttrs); /* TS: always signed */ }
-        |       "uint8_t"   { t = new IntType("uint8_t", SizeThunk.INT8, true, cvAttrs); /* TS: always unsigned */ }
-        |       "int16_t"   { t = new IntType("int16_t", SizeThunk.INT16, false, cvAttrs); /* TS: always signed */ }
-        |       "uint16_t"  { t = new IntType("uint16_t", SizeThunk.INT16, true, cvAttrs); /* TS: always unsigned */ }
-        |       "int32_t"   { t = new IntType("int32_t", SizeThunk.INT32, false, cvAttrs); /* TS: always signed */ }
-        |       "wchar_t"   { t = new IntType("wchar_t", SizeThunk.INT32, false, cvAttrs); /* TS: always signed */ }
-        |       "uint32_t"  { t = new IntType("uint32_t", SizeThunk.INT32, true, cvAttrs, true); /* TS: always unsigned */ }
-        |       "int64_t"   { t = new IntType("int64_t", SizeThunk.INT64, false, cvAttrs); /* TS: always signed */ }
-        |       "uint64_t"  { t = new IntType("uint64_t", SizeThunk.INT64, true, cvAttrs, true); /* TS: always unsigned */ }
-        |       "ptrdiff_t" { t = new IntType("ptrdiff_t", SizeThunk.POINTER, false, cvAttrs); /* TS: always signed */ }
-        |       "intptr_t"  { t = new IntType("intptr_t", SizeThunk.POINTER, false, cvAttrs); /* TS: always signed */ }
-        |       "size_t"    { t = new IntType("size_t", SizeThunk.POINTER, true, cvAttrs, true); /* TS: always unsigned */ }
-        |       "uintptr_t" { t = new IntType("uintptr_t", SizeThunk.POINTER, true, cvAttrs, true); /* TS: always unsigned */ }
+        //                                                                                    TYPEDEF
+        //                                                                                    |      TYPEDEF-UNSIGNED
+        //                                                                    UNSIGNED        |      |
+        //      TOKEN                 TYPE    NAME         SIZE               |      ATTRIBS  |      |      LOCUS
+        :       "void"      { t = new VoidType(                                      cvAttrs,               locusTag); }
+        |       "char"      { t = new IntType("char" ,     SizeThunk.INT8,    unsig, cvAttrs, false, false, locusTag); }
+        |       "short"     { t = new IntType("short",     SizeThunk.INT16,   unsig, cvAttrs, false, false, locusTag); }
+        |       "int"       { t = new IntType("int"  ,     SizeThunk.INTxx,   unsig, cvAttrs, false, false, locusTag); }
+        |       "long"      { t = new IntType("long" ,     SizeThunk.LONG,    unsig, cvAttrs, false, false, locusTag); }
+        |       "float"     { t = new FloatType("float",   SizeThunk.FLOAT,          cvAttrs,               locusTag); }
+        |       "double"    { t = new DoubleType("double", SizeThunk.DOUBLE,         cvAttrs,               locusTag); }
+        |       "__int32"   { t = new IntType("__int32",   SizeThunk.INT32,   unsig, cvAttrs, true,  false, locusTag); }  /* TD: signed   */
+        |       "__int64"   { t = new IntType("__int64",   SizeThunk.INT64,   unsig, cvAttrs, true,  false, locusTag); }  /* TD: signed   */
+        |       "int8_t"    { t = new IntType("int8_t",    SizeThunk.INT8,    unsig, cvAttrs, true,  false, locusTag); }  /* TD: signed   */
+        |       "uint8_t"   { t = new IntType("uint8_t",   SizeThunk.INT8,    unsig, cvAttrs, true,  true,  locusTag); }  /* TD: unsigned */
+        |       "int16_t"   { t = new IntType("int16_t",   SizeThunk.INT16,   unsig, cvAttrs, true,  false, locusTag); }  /* TD: signed   */
+        |       "uint16_t"  { t = new IntType("uint16_t",  SizeThunk.INT16,   unsig, cvAttrs, true,  true,  locusTag); }  /* TD: unsigned */
+        |       "int32_t"   { t = new IntType("int32_t",   SizeThunk.INT32,   unsig, cvAttrs, true,  false, locusTag); }  /* TD: signed   */
+        |       "wchar_t"   { t = new IntType("wchar_t",   SizeThunk.INT32,   unsig, cvAttrs, true,  false, locusTag); }  /* TD: signed   */
+        |       "uint32_t"  { t = new IntType("uint32_t",  SizeThunk.INT32,   unsig, cvAttrs, true,  true,  locusTag); }  /* TS: unsigned */
+        |       "int64_t"   { t = new IntType("int64_t",   SizeThunk.INT64,   unsig, cvAttrs, true,  false, locusTag); }  /* TD: signed   */
+        |       "uint64_t"  { t = new IntType("uint64_t",  SizeThunk.INT64,   unsig, cvAttrs, true,  true,  locusTag); }  /* TD: unsigned */
+        |       "ptrdiff_t" { t = new IntType("ptrdiff_t", SizeThunk.POINTER, unsig, cvAttrs, true,  false, locusTag); }  /* TD: signed   */
+        |       "intptr_t"  { t = new IntType("intptr_t",  SizeThunk.POINTER, unsig, cvAttrs, true,  false, locusTag); }  /* TD: signed   */
+        |       "size_t"    { t = new IntType("size_t",    SizeThunk.POINTER, unsig, cvAttrs, true,  true,  locusTag); }  /* TD: unsigned */
+        |       "uintptr_t" { t = new IntType("uintptr_t", SizeThunk.POINTER, unsig, cvAttrs, true,  true,  locusTag); }  /* TD: unsigned */
         |       t = structSpecifier[cvAttrs] ( attributeDecl )*
         |       t = unionSpecifier [cvAttrs] ( attributeDecl )*
         |       t = enumSpecifier  [cvAttrs] 
@@ -533,9 +632,12 @@ typeSpecifier[int attributes] returns [Type t] {
 typedefName[int cvAttrs] returns [Type t] { t = null; }
         :       #(NTypedefName id : ID)
             {
-              Type tdict = lookupInTypedefDictionary(id.getText());
-              t = canonicalize(tdict.getCVVariant(cvAttrs));
-              debugPrintln("Adding typedef canon : [" + id.getText() + "] -> [" + tdict + "] -> "+getTypeString(t));
+              final Type t0 = lookupInTypedefDictionary(typedefName_AST_in, id.getText());
+              debugPrint("Adding typedef lookup: [" + id.getText() + "] -> "+getDebugTypeString(t0));
+              final Type t1 = t0.newCVVariant(cvAttrs);
+              debugPrintln(" - cvvar -> "+getDebugTypeString(t1));
+              t = canonicalize(t1);
+              debugPrintln(" - canon -> "+getDebugTypeString(t));
             }
         ;
 
@@ -549,31 +651,50 @@ unionSpecifier[int cvAttrs] returns [Type t] { t = null; }
    
 structOrUnionBody[CompoundTypeKind kind, int cvAttrs] returns [CompoundType t] {
     t = null;
+    boolean addedAny = false;
+    final ASTLocusTag locusTag = findASTLocusTag(structOrUnionBody_AST_in);
 }
         :       ( (ID LCURLY) => id:ID LCURLY {
-                    t = (CompoundType) canonicalize(lookupInStructDictionary(id.getText(), kind, cvAttrs));
-                  } ( structDeclarationList[t] )?
+                    // fully declared struct, i.e. not anonymous
+                    t = (CompoundType) canonicalize(lookupInStructDictionary(id.getText(), kind, cvAttrs, locusTag));
+                  } ( addedAny = structDeclarationList[t] )?
                     RCURLY { t.setBodyParsed(); }
-                |   LCURLY { t = CompoundType.create(null, null, kind, cvAttrs); }
-                    ( structDeclarationList[t] )?
+                |   LCURLY { 
+                      // anonymous declared struct
+                      t = CompoundType.create(null, null, kind, cvAttrs, locusTag); 
+                    } ( structDeclarationList[t] )?
                     RCURLY { t.setBodyParsed(); }
-                | id2:ID { t = (CompoundType) canonicalize(lookupInStructDictionary(id2.getText(), kind, cvAttrs)); }
-                )
+                | id2:ID { 
+                      // anonymous struct
+                      t = (CompoundType) canonicalize(lookupInStructDictionary(id2.getText(), kind, cvAttrs, locusTag)); 
+                    }
+                ) {
+                    debugPrintln("Adding compound body: [" + t.getName() + "] -> "+getDebugTypeString(t)+" @ "+locusTag);
+                    debugPrintln(t.getStructString());
+                }
         ;
 
-structDeclarationList[CompoundType t]
-        :       ( structDeclaration[t] )+
+structDeclarationList[CompoundType t] returns [boolean addedAny] {
+    addedAny = false;
+    boolean addedOne = false;
+}
+        :       ( addedOne = structDeclaration[t] { addedAny |= addedOne; } )+
         ;
 
-structDeclaration[CompoundType containingType] {
+structDeclaration[CompoundType containingType] returns [boolean addedAny] {
+    addedAny = false;
     Type t = null;
-    boolean addedAny = false;
 }
         :       t = specifierQualifierList addedAny = structDeclaratorList[containingType, t] {
                     if (!addedAny) {
                         if (t != null) {
                             CompoundType ct = t.asCompound();
-                            if (ct.isUnion()) {
+                            if( null == ct ) {
+                                throwGlueGenException(structDeclaration_AST_in,
+                                    String.format("Anonymous compound, w/ NULL type:%n  containing '%s'",
+                                        getTypeString(containingType)));
+                            }
+                            if ( ct.isUnion() ) {
                                 // Anonymous union
                                 containingType.addField(new Field(null, t, null));
                             }
@@ -591,7 +712,8 @@ specifierQualifierList returns [Type t] {
                 )+ {
             if (t == null &&
                 (x & (SIGNED | UNSIGNED)) != 0) {
-                t = new IntType("int", SizeThunk.INTxx, ((x & UNSIGNED) != 0), attrs2CVAttrs(x));
+                t = new IntType("int", SizeThunk.INTxx, ((x & UNSIGNED) != 0), attrs2CVAttrs(x), 
+                                findASTLocusTag(specifierQualifierList_AST_in));
             }
 }
         ;
@@ -629,13 +751,30 @@ structDeclarator[CompoundType containingType, Type t] returns [boolean addedAny]
 // "enumName" *before* executing the enumList rule.
 enumSpecifier [int cvAttrs] returns [Type t] { 
         t = null; 
+        EnumType e = null;
+        ASTLocusTag locusTag = findASTLocusTag(enumSpecifier_AST_in);
 }
         :       #( "enum"
-                   ( ( ID LCURLY )=> i:ID LCURLY enumList[(EnumType)(t = getEnumType(i.getText()))] RCURLY 
-                     | LCURLY enumList[(EnumType)(t = getEnumType(ANONYMOUS_ENUM_NAME))] RCURLY 
-                     | ID { t = getEnumType(i.getText()); }
-                    )
-                  )
+                   ( ( ID LCURLY )=> i:ID LCURLY enumList[(EnumType)(e = getEnumType(i.getText(), locusTag))] RCURLY 
+                     | LCURLY enumList[(EnumType)(e = getEnumType(ANONYMOUS_ENUM_NAME, locusTag))] RCURLY 
+                     | ID { e = getEnumType(i.getText(), locusTag); }
+                   ) {
+                     debugPrintln("Adding enum mapping: "+getDebugTypeString(e));
+                     if( null != e ) {
+                        final String eName = e.getName();
+                        if( null != eName && !eName.equals(ANONYMOUS_ENUM_NAME) ) { // validate only non-anonymous enum
+                            final EnumType dupE = enumMap.get(eName);
+                            if( null != dupE && !dupE.equalSemantics(e) ) {
+                                throwGlueGenException(enumSpecifier_AST_in,
+                                    String.format("Duplicate enum w/ incompatible type:%n  this '%s',%n  have '%s',%n  %s: previous definition is here",
+                                        getTypeString(e), getTypeString(dupE), dupE.getASTLocusTag().toString(new StringBuilder(), "note", true)));
+                            }
+                            enumMap.put(eName, (EnumType)e.clone(locusTag));
+                        }
+                     }
+                     t = e; // return val
+                   }
+                 )
         ;
 
 enumList[EnumType enumeration] {
@@ -648,42 +787,43 @@ enumerator[EnumType enumeration, long defaultValue] returns [long newDefaultValu
         newDefaultValue = defaultValue;
 }
         :       eName:ID ( ASSIGN eVal:expr )? {
-                    long value = 0;
+                    final long newValue;
                     if (eVal != null) {
                       String vTxt = eVal.getAllChildrenText();
                       if (enumHash.containsKey(vTxt)) {
                         EnumType oldEnumType = enumHash.get(vTxt);
-                        value = oldEnumType.getEnumValue(vTxt);
+                        newValue = oldEnumType.getEnumValue(vTxt);
                       } else {
                         try {
-                          value = Long.decode(vTxt).longValue();
+                          newValue = Long.decode(vTxt).longValue();
                         } catch (NumberFormatException e) {
                           System.err.println("NumberFormatException: ID[" + eName.getText() + "], VALUE=[" + vTxt + "]");
                           throw e;
                         }
                       }
                     } else {
-                      value = defaultValue;
+                      newValue = defaultValue;
                     }
 
-                                        newDefaultValue = value+1;
-                                          String eTxt = eName.getText();
-                                          if (enumHash.containsKey(eTxt)) {
-                                                EnumType oldEnumType = enumHash.get(eTxt);
-                                                long oldValue = oldEnumType.getEnumValue(eTxt);
-                                                  System.err.println("WARNING: redefinition of enumerated value '" + eTxt + "';" +
-                                                     " existing definition is in enumeration '" + oldEnumType.getName() +
-                                                     "' with value " + oldValue + " and new definition is in enumeration '" +
-                                                     enumeration.getName() + "' with value " + value);
-                                                // remove old definition
-                                                oldEnumType.removeEnumerate(eTxt);
-                                          }
-                                          // insert new definition
-                                          enumeration.addEnum(eTxt, value);
-                                          enumHash.put(eTxt, enumeration);
-                                        debugPrintln("ENUM [" + enumeration.getName() + "]: " + eTxt + " = " + enumeration.getEnumValue(eTxt) +
-                                                     " (new default = " + newDefaultValue + ")");
-                                }
+                    newDefaultValue = newValue+1;
+                    String eTxt = eName.getText();
+                    if (enumHash.containsKey(eTxt)) {
+                        EnumType oldEnumType = enumHash.get(eTxt);
+                        final long oldValue = oldEnumType.getEnumValue(eTxt);
+                        if( oldValue != newValue ) {
+                            throwGlueGenException(enumerator_AST_in,
+                                 String.format("Duplicate enum value '%s.%s' w/ diff value:%n  this %d,%n  have %d",
+                                     oldEnumType.getName(), eTxt, newValue, oldValue));
+                        }
+                        // remove old definition
+                        oldEnumType.removeEnumerate(eTxt);
+                    }
+                    // insert new definition
+                    enumeration.addEnum(eTxt, newValue);
+                    enumHash.put(eTxt, enumeration);
+                    debugPrintln("ENUM [" + enumeration.getName() + "]: " + eTxt + " = " + enumeration.getEnumValue(eTxt) +
+                                 " (new default = " + newDefaultValue + ")");
+                }
             ;
 
 initDeclList[TypeBox tb]
@@ -692,6 +832,7 @@ initDeclList[TypeBox tb]
 
 initDecl[TypeBox tb] {
     String declName = null;
+    final ASTLocusTag locusTag = findASTLocusTag(initDecl_AST_in);
 }
         :       #( NInitDecl
                 declName = declarator[tb] { 
@@ -705,23 +846,98 @@ initDecl[TypeBox tb] {
 {
     if ((declName != null) && (tb != null) && tb.isTypedef()) {
         Type t = tb.type();
-        debugPrint("Adding typedef mapping: [" + declName + "] -> "+getTypeString(t));
-        if (!t.hasTypedefName()) {
-            t.setName(declName);
-            debugPrint(" - declName -> "+getTypeString(t));
+        debugPrintln("Adding typedef mapping: [" + declName + "] -> "+getDebugTypeString(t));
+        final Type tg;
+        if( t.isPointer() ) {
+            tg = t.getTargetType();
+            debugPrintln("  - has target: "+getDebugTypeString(tg));
         } else {
-            // copy type to preserve declName !
-            t = (Type) t.clone();
-            t.setName(declName);
-            debugPrint(" - copy -> "+getTypeString(t));
+            tg = null;
+        }
+        // NOTE: Struct Name Resolution (JavaEmitter, HeaderParser)
+        // Also see NOTE below.
+        if (!t.isTypedef()) {
+            if( t.isCompound() ) {
+                // This aliases '_a' -> 'A' for 'typedef struct _a { } A;' in-place
+                t.setTypedefName(declName);
+                debugPrintln(" - alias.11 -> "+getDebugTypeString(t));
+            } else {
+                // Use new typedef, using a copy to preserve canonicalized base type
+                t = t.clone(locusTag);
+                t.setTypedefName(declName);
+                debugPrintln(" - newdefine.12 -> "+getDebugTypeString(t));
+            }
+        } else {
+            // Adds typeInfo alias w/ t's typeInfo, if exists
+            cfg.addTypeInfo(declName, t);
+            final Type alias;
+            if( t.isCompound() ) {
+                // This aliases 'D' -> 'A' for 'typedef struct _a { } A, D;' in-place
+                debugPrintln(" - alias.21 -> "+getDebugTypeString(t));
+            } else {
+                // copy to preserve canonicalized base type
+                t = t.clone(locusTag);
+                t.setTypedefName(declName);
+                debugPrintln(" - copy.22 -> "+getDebugTypeString(t));
+            }
+        }
+        final Type dupT = typedefDictionary.get(declName);
+        if( null != dupT && !dupT.equalSemantics(t) ) {
+            throwGlueGenException(locusTag,
+                  String.format("Duplicate typedef w/ incompatible type:%n  this '%s',%n  have '%s',%n  %s: previous definition is here",
+                     getTypeString(t), getTypeString(dupT), dupT.getASTLocusTag().toString(new StringBuilder(), "note", true)));
         }
         t = canonicalize(t);
-        debugPrintln(" - canon -> "+getTypeString(t));
+        debugPrintln(" - canon -> "+getDebugTypeString(t));
         typedefDictionary.put(declName, t);
         // Clear out PointerGroup effects in case another typedef variant follows
         tb.reset();
     }
 }
+    /*
+        // Below just shows a different handling using copying
+        // and enforcing aliased names, which is not desired.
+        // Keeping it in here for documentation.
+        // NOTE: Struct Name Resolution (JavaEmitter, HeaderParser)
+        if ( !t.isTypedef() ) {
+            if( t.isCompound() ) {
+                // This aliases '_a' -> 'A' for 'typedef struct _a { } A;'
+                t.setTypedefName(declName);
+                debugPrintln(" - alias.10 -> "+getDebugTypeString(t));
+            } else if( null != tg && tg.isCompound() ) {
+                if( !tg.isTypedef() ) {
+                    // This aliases '_a *' -> 'A*' for 'typedef struct _a { } *A;'
+                    t.setTypedefName(declName);
+                    debugPrintln(" - alias.11 -> "+getDebugTypeString(t));
+                } else {
+                    // This aliases 'B' -> 'A*' for 'typedef struct _a { } A, *B;' and 'typedef A * B;'
+                    t = new PointerType(SizeThunk.POINTER, tg, 0, locusTag); // name: 'A*'
+                    t.setTypedefName(t.getName()); // make typedef
+                    debugPrintln(" - alias.12 -> "+getDebugTypeString(t));
+                }
+            } else {
+                // Use new typedef, using a copy to preserve canonicalized base type
+                t = t.clone(locusTag);
+                t.setTypedefName(declName);
+                debugPrintln(" - newdefine.13 -> "+getDebugTypeString(t));
+            }
+        } else {
+            // Adds typeInfo alias w/ t's typeInfo, if exists
+            cfg.addTypeInfo(declName, t);
+            if( t.isCompound() ) {
+                // This aliases 'D' -> 'A' for 'typedef struct _a { } A, D;'
+                debugPrintln(" - alias.20 -> "+getDebugTypeString(t));
+            } else if( null != tg && tg.isCompound() ) {
+                // This aliases 'B' -> 'A' for 'typedef A B;', where A is pointer to compound
+                debugPrintln(" - alias.21 -> "+getDebugTypeString(t));
+            } else {
+                // copy to preserve canonicalized base type
+                t = t.clone(locusTag);
+                t.setTypedefName(declName);
+                debugPrintln(" - copy.22 -> "+getDebugTypeString(t));
+            }
+        }
+*/
         ;
 
 pointerGroup[TypeBox tb] { int x = 0; int y = 0; }
@@ -731,7 +947,8 @@ pointerGroup[TypeBox tb] { int x = 0; int y = 0; }
                                         if (tb != null) {
                                             tb.setType(canonicalize(new PointerType(SizeThunk.POINTER,
                                                                                     tb.type(),
-                                                                                    attrs2CVAttrs(x))));
+                                                                                    attrs2CVAttrs(x), 
+                                                                                    findASTLocusTag(pointerGroup_AST_in))));
                                         }
                                     }
                                  )+ )
@@ -756,7 +973,9 @@ typeName {
 /* FIXME: the handling of types in this rule has not been well thought
    out and is known to be incomplete. Currently it is only used to handle
    pointerGroups for unnamed parameters. */
-nonemptyAbstractDeclarator[TypeBox tb]
+nonemptyAbstractDeclarator[TypeBox tb] {
+    final ASTLocusTag locusTag = findASTLocusTag(nonemptyAbstractDeclarator_AST_in);
+}
         :   #( NNonemptyAbstractDeclarator
             (   pointerGroup[tb]
                 (   (LPAREN  
@@ -764,7 +983,7 @@ nonemptyAbstractDeclarator[TypeBox tb]
                         | parameterTypeList
                     )?
                     RPAREN)
-                | (LBRACKET (e1:expr)? RBRACKET) { handleArrayExpr(tb, e1); }
+                | (LBRACKET (e1:expr)? RBRACKET) { handleArrayExpr(tb, e1, locusTag); }
                 )*
 
             |  (   (LPAREN  
@@ -772,7 +991,7 @@ nonemptyAbstractDeclarator[TypeBox tb]
                         | parameterTypeList
                     )?
                     RPAREN)
-                | (LBRACKET (e2:expr)? RBRACKET) { handleArrayExpr(tb, e2); }
+                | (LBRACKET (e2:expr)? RBRACKET) { handleArrayExpr(tb, e2, locusTag); }
                 )+
             )
             )
@@ -786,12 +1005,14 @@ intConstExpr returns [int i] { i = -1; }
             final String enumName = e.getText();
             final EnumType enumType = enumHash.get(enumName);
             if( null == enumType ) {
-               throw new IllegalArgumentException("Error: intConstExpr ID "+enumName+" recognized, but no containing enum-type found");
+               throwGlueGenException(intConstExpr_AST_in,
+                     "Error: intConstExpr ID "+enumName+" recognized, but no containing enum-type found");
             }
             final long enumValue = enumType.getEnumValue(enumName);
             System.err.println("INFO: intConstExpr: enum[Type "+enumType.getName()+", name "+enumName+", value "+enumValue+"]");
             if( (long)Integer.MIN_VALUE > enumValue || (long)Integer.MAX_VALUE < enumValue ) {
-               throw new IndexOutOfBoundsException("Error: intConstExpr ID "+enumName+" enum-value "+enumValue+" out of int range");
+               throwGlueGenException(intConstExpr_AST_in,
+                     "Error: intConstExpr ID "+enumName+" enum-value "+enumValue+" out of int range");
             }
             return (int)enumValue;
           }
diff --git a/src/antlr/com/jogamp/gluegen/cgram/StdCParser.g b/src/antlr/com/jogamp/gluegen/cgram/StdCParser.g
index 7b34656..26da996 100644
--- a/src/antlr/com/jogamp/gluegen/cgram/StdCParser.g
+++ b/src/antlr/com/jogamp/gluegen/cgram/StdCParser.g
@@ -1131,11 +1131,12 @@ options {
             nw:NonWhitespace
             ("\r\n" | "\r" | "\n") )               {
                                                      if (n != null) {
-                                                       //System.out.println("addDefine: #define " + i.getText() + " " +  n.getText());
+                                                       // System.out.println("addDefine: #define " + i.getText() + " " +  n.getText()+" @ "+lineObject.getSource()+":"+(lineObject.line+deferredLineCount));
                                                        addDefine(i.getText(), n.getText());
                                                      } else {
                                                        setPreprocessingDirective("#define " + i.getText() + " " + nw.getText());
                                                      }
+                                                     deferredNewline();
                                                    }
         | (~'\n')*                                 { setPreprocessingDirective(getText()); }
         )
@@ -1165,15 +1166,19 @@ protected LineDirective
 }
 :
                 {
-                        lineObject = new LineObject();
-                        deferredLineCount = 0;
+                    lineObject = new LineObject();
+                    deferredLineCount = 0;
                 }
         ("line")?  //this would be for if the directive started "#line", but not there for GNU directives
         (Space)+
-        n:Number { lineObject.setLine(Integer.parseInt(n.getText())); } 
+        n:Number { 
+                    lineObject.setLine(Integer.parseInt(n.getText()));
+                 } 
         (Space)+
         (       fn:StringLiteral {  try { 
-                                          lineObject.setSource(fn.getText().substring(1,fn.getText().length()-1)); 
+                                          final String newSource = fn.getText().substring(1,fn.getText().length()-1);
+                                          // System.out.println("line: "+lineObject.getSource()+" -> "+newSource+", line "+(lineObject.line+deferredLineCount));
+                                          lineObject.setSource(newSource);
                                     } 
                                     catch (StringIndexOutOfBoundsException e) { /*not possible*/ } 
                                  }
diff --git a/src/antlr/com/jogamp/gluegen/jgram/JavaParser.g b/src/antlr/com/jogamp/gluegen/jgram/JavaParser.g
index f67579e..1c06bfd 100644
--- a/src/antlr/com/jogamp/gluegen/jgram/JavaParser.g
+++ b/src/antlr/com/jogamp/gluegen/jgram/JavaParser.g
@@ -8,105 +8,105 @@
  * Run 'java Main <directory full of java files>'
  *
  * Contributing authors:
- *		John Mitchell		johnm at non.net
- *		Terence Parr		parrt at magelang.com
- *		John Lilley			jlilley at empathy.com
- *		Scott Stanchfield	thetick at magelang.com
- *		Markus Mohnen       mohnen at informatik.rwth-aachen.de
+ *        John Mitchell        johnm at non.net
+ *        Terence Parr        parrt at magelang.com
+ *        John Lilley            jlilley at empathy.com
+ *        Scott Stanchfield    thetick at magelang.com
+ *        Markus Mohnen       mohnen at informatik.rwth-aachen.de
  *      Peter Williams      pete.williams at sun.com
  *      Allan Jacobs        Allan.Jacobs at eng.sun.com
  *      Steve Messick       messick at redhills.com
- *      John Pybus			john at pybus.org
+ *      John Pybus            john at pybus.org
  *
  * Version 1.00 December 9, 1997 -- initial release
  * Version 1.01 December 10, 1997
- *		fixed bug in octal def (0..7 not 0..8)
+ *        fixed bug in octal def (0..7 not 0..8)
  * Version 1.10 August 1998 (parrt)
- *		added tree construction
- *		fixed definition of WS,comments for mac,pc,unix newlines
- *		added unary plus
+ *        added tree construction
+ *        fixed definition of WS,comments for mac,pc,unix newlines
+ *        added unary plus
  * Version 1.11 (Nov 20, 1998)
- *		Added "shutup" option to turn off last ambig warning.
- *		Fixed inner class def to allow named class defs as statements
- *		synchronized requires compound not simple statement
- *		add [] after builtInType DOT class in primaryExpression
- *		"const" is reserved but not valid..removed from modifiers
+ *        Added "shutup" option to turn off last ambig warning.
+ *        Fixed inner class def to allow named class defs as statements
+ *        synchronized requires compound not simple statement
+ *        add [] after builtInType DOT class in primaryExpression
+ *        "const" is reserved but not valid..removed from modifiers
  * Version 1.12 (Feb 2, 1999)
- *		Changed LITERAL_xxx to xxx in tree grammar.
- *		Updated java.g to use tokens {...} now for 2.6.0 (new feature).
+ *        Changed LITERAL_xxx to xxx in tree grammar.
+ *        Updated java.g to use tokens {...} now for 2.6.0 (new feature).
  *
  * Version 1.13 (Apr 23, 1999)
- *		Didn't have (stat)? for else clause in tree parser.
- *		Didn't gen ASTs for interface extends.  Updated tree parser too.
- *		Updated to 2.6.0.
+ *        Didn't have (stat)? for else clause in tree parser.
+ *        Didn't gen ASTs for interface extends.  Updated tree parser too.
+ *        Updated to 2.6.0.
  * Version 1.14 (Jun 20, 1999)
- *		Allowed final/abstract on local classes.
- *		Removed local interfaces from methods
- *		Put instanceof precedence where it belongs...in relationalExpr
- *			It also had expr not type as arg; fixed it.
- *		Missing ! on SEMI in classBlock
- *		fixed: (expr) + "string" was parsed incorrectly (+ as unary plus).
- *		fixed: didn't like Object[].class in parser or tree parser
+ *        Allowed final/abstract on local classes.
+ *        Removed local interfaces from methods
+ *        Put instanceof precedence where it belongs...in relationalExpr
+ *            It also had expr not type as arg; fixed it.
+ *        Missing ! on SEMI in classBlock
+ *        fixed: (expr) + "string" was parsed incorrectly (+ as unary plus).
+ *        fixed: didn't like Object[].class in parser or tree parser
  * Version 1.15 (Jun 26, 1999)
- *		Screwed up rule with instanceof in it. :(  Fixed.
- *		Tree parser didn't like (expr).something; fixed.
- *		Allowed multiple inheritance in tree grammar. oops.
+ *        Screwed up rule with instanceof in it. :(  Fixed.
+ *        Tree parser didn't like (expr).something; fixed.
+ *        Allowed multiple inheritance in tree grammar. oops.
  * Version 1.16 (August 22, 1999)
- *		Extending an interface built a wacky tree: had extra EXTENDS.
- *		Tree grammar didn't allow multiple superinterfaces.
- *		Tree grammar didn't allow empty var initializer: {}
+ *        Extending an interface built a wacky tree: had extra EXTENDS.
+ *        Tree grammar didn't allow multiple superinterfaces.
+ *        Tree grammar didn't allow empty var initializer: {}
  * Version 1.17 (October 12, 1999)
- *		ESC lexer rule allowed 399 max not 377 max.
- *		java.tree.g didn't handle the expression of synchronized
- *		statements.
+ *        ESC lexer rule allowed 399 max not 377 max.
+ *        java.tree.g didn't handle the expression of synchronized
+ *        statements.
  * Version 1.18 (August 12, 2001)
- *      	Terence updated to Java 2 Version 1.3 by
- *		observing/combining work of Allan Jacobs and Steve
- *		Messick.  Handles 1.3 src.  Summary:
- *		o  primary didn't include boolean.class kind of thing
- *      	o  constructor calls parsed explicitly now:
- * 		   see explicitConstructorInvocation
- *		o  add strictfp modifier
- *      	o  missing objBlock after new expression in tree grammar
- *		o  merged local class definition alternatives, moved after declaration
- *		o  fixed problem with ClassName.super.field
- *      	o  reordered some alternatives to make things more efficient
- *		o  long and double constants were not differentiated from int/float
- *		o  whitespace rule was inefficient: matched only one char
- *		o  add an examples directory with some nasty 1.3 cases
- *		o  made Main.java use buffered IO and a Reader for Unicode support
- *		o  supports UNICODE?
- *		   Using Unicode charVocabulay makes code file big, but only
- *		   in the bitsets at the end. I need to make ANTLR generate
- *		   unicode bitsets more efficiently.
+ *          Terence updated to Java 2 Version 1.3 by
+ *        observing/combining work of Allan Jacobs and Steve
+ *        Messick.  Handles 1.3 src.  Summary:
+ *        o  primary didn't include boolean.class kind of thing
+ *          o  constructor calls parsed explicitly now:
+ *            see explicitConstructorInvocation
+ *        o  add strictfp modifier
+ *          o  missing objBlock after new expression in tree grammar
+ *        o  merged local class definition alternatives, moved after declaration
+ *        o  fixed problem with ClassName.super.field
+ *          o  reordered some alternatives to make things more efficient
+ *        o  long and double constants were not differentiated from int/float
+ *        o  whitespace rule was inefficient: matched only one char
+ *        o  add an examples directory with some nasty 1.3 cases
+ *        o  made Main.java use buffered IO and a Reader for Unicode support
+ *        o  supports UNICODE?
+ *           Using Unicode charVocabulay makes code file big, but only
+ *           in the bitsets at the end. I need to make ANTLR generate
+ *           unicode bitsets more efficiently.
  * Version 1.19 (April 25, 2002)
- *		Terence added in nice fixes by John Pybus concerning floating
- *		constants and problems with super() calls.  John did a nice
- *		reorg of the primary/postfix expression stuff to read better
- *		and makes f.g.super() parse properly (it was METHOD_CALL not
- *		a SUPER_CTOR_CALL).  Also:
+ *        Terence added in nice fixes by John Pybus concerning floating
+ *        constants and problems with super() calls.  John did a nice
+ *        reorg of the primary/postfix expression stuff to read better
+ *        and makes f.g.super() parse properly (it was METHOD_CALL not
+ *        a SUPER_CTOR_CALL).  Also:
  *
- *		o  "finally" clause was a root...made it a child of "try"
- *		o  Added stuff for asserts too for Java 1.4, but *commented out*
- *		   as it is not backward compatible.
+ *        o  "finally" clause was a root...made it a child of "try"
+ *        o  Added stuff for asserts too for Java 1.4, but *commented out*
+ *           as it is not backward compatible.
  *
  * Version 1.20 (October 27, 2002)
  *
  *      Terence ended up reorging John Pybus' stuff to
  *      remove some nondeterminisms and some syntactic predicates.
  *      Note that the grammar is stricter now; e.g., this(...) must
- *	be the first statement.
+ *    be the first statement.
  *
  *      Trinary ?: operator wasn't working as array name:
  *          (isBig ? bigDigits : digits)[i];
  *
  *      Checked parser/tree parser on source for
  *          Resin-2.0.5, jive-2.1.1, jdk 1.3.1, Lucene, antlr 2.7.2a4,
- *	    and the 110k-line jGuru server source.
+ *        and the 110k-line jGuru server source.
  *
  * Version 1.21 (October 17, 2003)
- *	Fixed lots of problems including:
- *	Ray Waldin: add typeDefinition to interfaceBlock in java.tree.g
+ *    Fixed lots of problems including:
+ *    Ray Waldin: add typeDefinition to interfaceBlock in java.tree.g
  *  He found a problem/fix with floating point that start with 0
  *  Ray also fixed problem that (int.class) was not recognized.
  *  Thorsten van Ellen noticed that \n are allowed incorrectly in strings.
@@ -129,24 +129,24 @@ header {
 class JavaParser extends Parser;
 
 options {
-	k = 2;                           // two token lookahead
-	exportVocab=Java;                // Call its vocabulary "Java"
-	codeGenMakeSwitchThreshold = 2;  // Some optimizations
-	codeGenBitsetTestThreshold = 3;
-	defaultErrorHandler = false;     // Don't generate parser error handlers
-	buildAST = true;
-	//buildAST = false;
+    k = 2;                           // two token lookahead
+    exportVocab=Java;                // Call its vocabulary "Java"
+    codeGenMakeSwitchThreshold = 2;  // Some optimizations
+    codeGenBitsetTestThreshold = 3;
+    defaultErrorHandler = false;     // Don't generate parser error handlers
+    buildAST = true;
+    //buildAST = false;
 }
 
 tokens {
-	BLOCK; MODIFIERS; OBJBLOCK; SLIST; CTOR_DEF; METHOD_DEF; VARIABLE_DEF;
-	INSTANCE_INIT; STATIC_INIT; TYPE; CLASS_DEF; INTERFACE_DEF;
-	PACKAGE_DEF; ARRAY_DECLARATOR; EXTENDS_CLAUSE; IMPLEMENTS_CLAUSE;
-	PARAMETERS; PARAMETER_DEF; LABELED_STAT; TYPECAST; INDEX_OP;
-	POST_INC; POST_DEC; METHOD_CALL; EXPR; ARRAY_INIT;
-	IMPORT; UNARY_MINUS; UNARY_PLUS; CASE_GROUP; ELIST; FOR_INIT; FOR_CONDITION;
-	FOR_ITERATOR; EMPTY_STAT; FINAL="final"; ABSTRACT="abstract";
-	STRICTFP="strictfp"; SUPER_CTOR_CALL; CTOR_CALL;
+    BLOCK; MODIFIERS; OBJBLOCK; SLIST; CTOR_DEF; METHOD_DEF; VARIABLE_DEF;
+    INSTANCE_INIT; STATIC_INIT; TYPE; CLASS_DEF; INTERFACE_DEF;
+    PACKAGE_DEF; ARRAY_DECLARATOR; EXTENDS_CLAUSE; IMPLEMENTS_CLAUSE;
+    PARAMETERS; PARAMETER_DEF; LABELED_STAT; TYPECAST; INDEX_OP;
+    POST_INC; POST_DEC; METHOD_CALL; EXPR; ARRAY_INIT;
+    IMPORT; UNARY_MINUS; UNARY_PLUS; CASE_GROUP; ELIST; FOR_INIT; FOR_CONDITION;
+    FOR_ITERATOR; EMPTY_STAT; FINAL="final"; ABSTRACT="abstract";
+    STRICTFP="strictfp"; SUPER_CTOR_CALL; CTOR_CALL;
 }
 
 {
@@ -181,250 +181,250 @@ tokens {
 // Compilation Unit: In Java, this is a single file.  This is the start
 //   rule for this parser
 compilationUnit
-	:	// A compilation unit starts with an optional package definition
-		(	packageDefinition
-		|	/* nothing */
-		)
+    :    // A compilation unit starts with an optional package definition
+        (    packageDefinition
+        |    /* nothing */
+        )
 
-		// Next we have a series of zero or more import statements
-		( importDefinition )*
+        // Next we have a series of zero or more import statements
+        ( importDefinition )*
 
-		// Wrapping things up with any number of class or interface
-		//    definitions
-		( typeDefinition )*
+        // Wrapping things up with any number of class or interface
+        //    definitions
+        ( typeDefinition )*
 
-		EOF!
-	;
+        EOF!
+    ;
 
 
 // Package statement: "package" followed by an identifier.
 packageDefinition
-	options {defaultErrorHandler = true;} // let ANTLR handle errors
-	:	p:"package"^ {#p.setType(PACKAGE_DEF);} identifier SEMI!
-	;
+    options {defaultErrorHandler = true;} // let ANTLR handle errors
+    :    p:"package"^ {#p.setType(PACKAGE_DEF);} identifier SEMI!
+    ;
 
 
 // Import statement: import followed by a package or class name
 importDefinition
-	options {defaultErrorHandler = true;}
-	:	i:"import"^ {#i.setType(IMPORT);} identifierStar SEMI!
-	;
+    options {defaultErrorHandler = true;}
+    :    i:"import"^ {#i.setType(IMPORT);} identifierStar SEMI!
+    ;
 
 // A type definition in a file is either a class or interface definition.
 typeDefinition
-	options {defaultErrorHandler = true;}
-	:	m:modifiers!
-		( classDefinition[#m]
-		| interfaceDefinition[#m]
-		)
-	|	SEMI!
-	;
+    options {defaultErrorHandler = true;}
+    :    m:modifiers!
+        ( classDefinition[#m]
+        | interfaceDefinition[#m]
+        )
+    |    SEMI!
+    ;
 
 /** A declaration is the creation of a reference or primitive-type variable
  *  Create a separate Type/Var tree for each var in the var list.
  */
 declaration!
-	:	m:modifiers t:typeSpec[false] v:variableDefinitions[#m,#t]
-		{#declaration = #v;}
-	;
+    :    m:modifiers t:typeSpec[false] v:variableDefinitions[#m,#t]
+        {#declaration = #v;}
+    ;
 
 // A type specification is a type name with possible brackets afterwards
 //   (which would make it an array type).
 typeSpec[boolean addImagNode]
-	: classTypeSpec[addImagNode]
-	| builtInTypeSpec[addImagNode]
-	;
+    : classTypeSpec[addImagNode]
+    | builtInTypeSpec[addImagNode]
+    ;
 
 // A class type specification is a class type with possible brackets afterwards
 //   (which would make it an array type).
 classTypeSpec[boolean addImagNode]
-	:	identifier (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
-		{
-			if ( addImagNode ) {
-				#classTypeSpec = #(#[TYPE,"TYPE"], #classTypeSpec);
-			}
-		}
-	;
+    :    identifier (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+        {
+            if ( addImagNode ) {
+                #classTypeSpec = #(#[TYPE,"TYPE"], #classTypeSpec);
+            }
+        }
+    ;
 
 // A builtin type specification is a builtin type with possible brackets
 // afterwards (which would make it an array type).
 builtInTypeSpec[boolean addImagNode]
-	:	builtInType (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
-		{
-			if ( addImagNode ) {
-				#builtInTypeSpec = #(#[TYPE,"TYPE"], #builtInTypeSpec);
-			}
-		}
-	;
+    :    builtInType (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+        {
+            if ( addImagNode ) {
+                #builtInTypeSpec = #(#[TYPE,"TYPE"], #builtInTypeSpec);
+            }
+        }
+    ;
 
 // A type name. which is either a (possibly qualified) class name or
 //   a primitive (builtin) type
 type
-	:	identifier
-	|	builtInType
-	;
+    :    identifier
+    |    builtInType
+    ;
 
 // The primitive types.
 builtInType
-	:	"void"
-	|	"boolean"
-	|	"byte"
-	|	"char"
-	|	"short"
-	|	"int"
-	|	"float"
-	|	"long"
-	|	"double"
-	;
+    :    "void"
+    |    "boolean"
+    |    "byte"
+    |    "char"
+    |    "short"
+    |    "int"
+    |    "float"
+    |    "long"
+    |    "double"
+    ;
 
 // A (possibly-qualified) java identifier.  We start with the first IDENT
 //   and expand its name by adding dots and following IDENTS
 identifier
-	:	IDENT  ( DOT^ IDENT )*
-	;
+    :    IDENT  ( DOT^ IDENT )*
+    ;
 
 identifierStar
-	:	IDENT
-		( DOT^ IDENT )*
-		( DOT^ STAR  )?
-	;
+    :    IDENT
+        ( DOT^ IDENT )*
+        ( DOT^ STAR  )?
+    ;
 
 // A list of zero or more modifiers.  We could have used (modifier)* in
 //   place of a call to modifiers, but I thought it was a good idea to keep
 //   this rule separate so they can easily be collected in a Vector if
 //   someone so desires
 modifiers
-	:	( modifier )*
-		{#modifiers = #([MODIFIERS, "MODIFIERS"], #modifiers);}
-	;
+    :    ( modifier )*
+        {#modifiers = #([MODIFIERS, "MODIFIERS"], #modifiers);}
+    ;
 
 // modifiers for Java classes, interfaces, class/instance vars and methods
 modifier
-	:	"private"
-	|	"public"
-	|	"protected"
-	|	"static"
-	|	"transient"
-	|	"final"
-	|	"abstract"
-	|	"native"
-	|	"threadsafe"
-	|	"synchronized"
-//	|	"const"			// reserved word, but not valid
-	|	"volatile"
-	|	"strictfp"
-	;
+    :    "private"
+    |    "public"
+    |    "protected"
+    |    "static"
+    |    "transient"
+    |    "final"
+    |    "abstract"
+    |    "native"
+    |    "threadsafe"
+    |    "synchronized"
+//    |    "const"            // reserved word, but not valid
+    |    "volatile"
+    |    "strictfp"
+    ;
 
 // Definition of a Java class
 classDefinition![AST modifiers]
-	:	"class" IDENT
-		// it _might_ have a superclass...
-		sc:superClassClause
-		// it might implement some interfaces...
-		ic:implementsClause
-		// now parse the body of the class
-		cb:classBlock
-		{#classDefinition = #(#[CLASS_DEF,"CLASS_DEF"],
-							   modifiers,IDENT,sc,ic,cb);}
-	;
+    :    "class" IDENT
+        // it _might_ have a superclass...
+        sc:superClassClause
+        // it might implement some interfaces...
+        ic:implementsClause
+        // now parse the body of the class
+        cb:classBlock
+        {#classDefinition = #(#[CLASS_DEF,"CLASS_DEF"],
+                               modifiers,IDENT,sc,ic,cb);}
+    ;
 
 superClassClause!
-	:	( "extends" id:identifier )?
-		{#superClassClause = #(#[EXTENDS_CLAUSE,"EXTENDS_CLAUSE"],id);}
-	;
+    :    ( "extends" id:identifier )?
+        {#superClassClause = #(#[EXTENDS_CLAUSE,"EXTENDS_CLAUSE"],id);}
+    ;
 
 // Definition of a Java Interface
 interfaceDefinition![AST modifiers]
-	:	"interface" IDENT
-		// it might extend some other interfaces
-		ie:interfaceExtends
-		// now parse the body of the interface (looks like a class...)
-		cb:classBlock
-		{#interfaceDefinition = #(#[INTERFACE_DEF,"INTERFACE_DEF"],
-									modifiers,IDENT,ie,cb);}
-	;
+    :    "interface" IDENT
+        // it might extend some other interfaces
+        ie:interfaceExtends
+        // now parse the body of the interface (looks like a class...)
+        cb:classBlock
+        {#interfaceDefinition = #(#[INTERFACE_DEF,"INTERFACE_DEF"],
+                                    modifiers,IDENT,ie,cb);}
+    ;
 
 
 // This is the body of a class.  You can have fields and extra semicolons,
 // That's about it (until you see what a field is...)
 classBlock
-	:	LCURLY! { blockDepth++; }
-			( field | SEMI! )*
-		RCURLY! { blockDepth--; }
-		{#classBlock = #([OBJBLOCK, "OBJBLOCK"], #classBlock);}
-	;
+    :    LCURLY! { blockDepth++; }
+            ( field | SEMI! )*
+        RCURLY! { blockDepth--; }
+        {#classBlock = #([OBJBLOCK, "OBJBLOCK"], #classBlock);}
+    ;
 
 // An interface can extend several other interfaces...
 interfaceExtends
-	:	(
-		e:"extends"!
-		identifier ( COMMA! identifier )*
-		)?
-		{#interfaceExtends = #(#[EXTENDS_CLAUSE,"EXTENDS_CLAUSE"],
-							#interfaceExtends);}
-	;
+    :    (
+        e:"extends"!
+        identifier ( COMMA! identifier )*
+        )?
+        {#interfaceExtends = #(#[EXTENDS_CLAUSE,"EXTENDS_CLAUSE"],
+                            #interfaceExtends);}
+    ;
 
 // A class can implement several interfaces...
 implementsClause
-	:	(
-			i:"implements"! identifier ( COMMA! identifier )*
-		)?
-		{#implementsClause = #(#[IMPLEMENTS_CLAUSE,"IMPLEMENTS_CLAUSE"],
-								 #implementsClause);}
-	;
+    :    (
+            i:"implements"! identifier ( COMMA! identifier )*
+        )?
+        {#implementsClause = #(#[IMPLEMENTS_CLAUSE,"IMPLEMENTS_CLAUSE"],
+                                 #implementsClause);}
+    ;
 
 // Now the various things that can be defined inside a class or interface...
 // Note that not all of these are really valid in an interface (constructors,
 //   for example), and if this grammar were used for a compiler there would
 //   need to be some semantic checks to make sure we're doing the right thing...
 field!
-	:	// method, constructor, or variable declaration
-		mods:modifiers
-		(	h:ctorHead s:constructorBody // constructor
-			{#field = #(#[CTOR_DEF,"CTOR_DEF"], mods, h, s);}
+    :    // method, constructor, or variable declaration
+        mods:modifiers
+        (    h:ctorHead s:constructorBody // constructor
+            {#field = #(#[CTOR_DEF,"CTOR_DEF"], mods, h, s);}
 
-		|	cd:classDefinition[#mods]       // inner class
-			{#field = #cd;}
+        |    cd:classDefinition[#mods]       // inner class
+            {#field = #cd;}
 
-		|	id:interfaceDefinition[#mods]   // inner interface
-			{#field = #id;}
+        |    id:interfaceDefinition[#mods]   // inner interface
+            {#field = #id;}
 
-		|	t:typeSpec[false]  // method or variable declaration(s)
-			(	fn:IDENT  // the name of the method
+        |    t:typeSpec[false]  // method or variable declaration(s)
+            (    fn:IDENT  // the name of the method
 
-				// parse the formal parameter declarations.
-				LPAREN! param:parameterDeclarationList RPAREN!
+                // parse the formal parameter declarations.
+                LPAREN! param:parameterDeclarationList RPAREN!
 
-				rt:declaratorBrackets[#t]
+                rt:declaratorBrackets[#t]
 
-				// get the list of exceptions that this method is
-				// declared to throw
-				(tc:throwsClause)?
+                // get the list of exceptions that this method is
+                // declared to throw
+                (tc:throwsClause)?
 
-				( s2:compoundStatement | SEMI )
-				{#field = #(#[METHOD_DEF,"METHOD_DEF"],
-						     mods,
-							 #(#[TYPE,"TYPE"],rt),
-							 fn,
-							 param,
-							 tc,
-							 s2);
+                ( s2:compoundStatement | SEMI )
+                {#field = #(#[METHOD_DEF,"METHOD_DEF"],
+                             mods,
+                             #(#[TYPE,"TYPE"],rt),
+                             fn,
+                             param,
+                             tc,
+                             s2);
                   if(blockDepth==1) {
                     functionNames.add(fn.getText()); } }
-			|	v:variableDefinitions[#mods,#t] SEMI
-//				{#field = #(#[VARIABLE_DEF,"VARIABLE_DEF"], v);}
-				{#field = #v;}
-			)
-		)
+            |    v:variableDefinitions[#mods,#t] SEMI
+//                {#field = #(#[VARIABLE_DEF,"VARIABLE_DEF"], v);}
+                {#field = #v;}
+            )
+        )
 
     // "static { ... }" class initializer
-	|	"static" s3:compoundStatement
-		{#field = #(#[STATIC_INIT,"STATIC_INIT"], s3);}
+    |    "static" s3:compoundStatement
+        {#field = #(#[STATIC_INIT,"STATIC_INIT"], s3);}
 
     // "{ ... }" instance initializer
-	|	s4:compoundStatement
-		{#field = #(#[INSTANCE_INIT,"INSTANCE_INIT"], s4);}
-	;
+    |    s4:compoundStatement
+        {#field = #(#[INSTANCE_INIT,"INSTANCE_INIT"], s4);}
+    ;
 
 constructorBody
     :   lc:LCURLY^ {#lc.setType(SLIST); blockDepth++; }
@@ -436,108 +436,108 @@ constructorBody
 /** Catch obvious constructor calls, but not the expr.super(...) calls */
 explicitConstructorInvocation
     :   "this"! lp1:LPAREN^ argList RPAREN! SEMI!
-		{#lp1.setType(CTOR_CALL);}
+        {#lp1.setType(CTOR_CALL);}
     |   "super"! lp2:LPAREN^ argList RPAREN! SEMI!
-		{#lp2.setType(SUPER_CTOR_CALL);}
+        {#lp2.setType(SUPER_CTOR_CALL);}
     ;
 
 variableDefinitions[AST mods, AST t]
-	:	variableDeclarator[getASTFactory().dupTree(mods),
-						   getASTFactory().dupTree(t)]
-		(	COMMA!
-			variableDeclarator[getASTFactory().dupTree(mods),
-							   getASTFactory().dupTree(t)]
-		)*
-	;
+    :    variableDeclarator[getASTFactory().dupTree(mods),
+                           getASTFactory().dupTree(t)]
+        (    COMMA!
+            variableDeclarator[getASTFactory().dupTree(mods),
+                               getASTFactory().dupTree(t)]
+        )*
+    ;
 
 /** Declaration of a variable.  This can be a class/instance variable,
  *   or a local variable in a method
  * It can also include possible initialization.
  */
 variableDeclarator![AST mods, AST t]
-	:	id:IDENT d:declaratorBrackets[t] v:varInitializer
-		{#variableDeclarator = #(#[VARIABLE_DEF,"VARIABLE_DEF"], mods, #(#[TYPE,"TYPE"],d), id, v);
+    :    id:IDENT d:declaratorBrackets[t] v:varInitializer
+        {#variableDeclarator = #(#[VARIABLE_DEF,"VARIABLE_DEF"], mods, #(#[TYPE,"TYPE"],d), id, v);
          if(blockDepth==1) { 
             enumNames.add(id.getText()); 
          }
         }
-	;
+    ;
 
 declaratorBrackets[AST typ]
-	:	{#declaratorBrackets=typ;}
-		(lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
-	;
+    :    {#declaratorBrackets=typ;}
+        (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+    ;
 
 varInitializer
-	:	( ASSIGN^ initializer )?
-	;
+    :    ( ASSIGN^ initializer )?
+    ;
 
 // This is an initializer used to set up an array.
 arrayInitializer
-	:	lc:LCURLY^ {#lc.setType(ARRAY_INIT); blockDepth++; }
-			(	initializer
-				(
-					// CONFLICT: does a COMMA after an initializer start a new
-					//           initializer or start the option ',' at end?
-					//           ANTLR generates proper code by matching
-					//			 the comma as soon as possible.
-					options {
-						warnWhenFollowAmbig = false;
-					}
-				:
-					COMMA! initializer
-				)*
-				(COMMA!)?
-			)?
-		RCURLY! { blockDepth--; }
-	;
+    :    lc:LCURLY^ {#lc.setType(ARRAY_INIT); blockDepth++; }
+            (    initializer
+                (
+                    // CONFLICT: does a COMMA after an initializer start a new
+                    //           initializer or start the option ',' at end?
+                    //           ANTLR generates proper code by matching
+                    //             the comma as soon as possible.
+                    options {
+                        warnWhenFollowAmbig = false;
+                    }
+                :
+                    COMMA! initializer
+                )*
+                (COMMA!)?
+            )?
+        RCURLY! { blockDepth--; }
+    ;
 
 
 // The two "things" that can initialize an array element are an expression
 //   and another (nested) array initializer.
 initializer
-	:	expression
-	|	arrayInitializer
-	;
+    :    expression
+    |    arrayInitializer
+    ;
 
 // This is the header of a method.  It includes the name and parameters
 //   for the method.
 //   This also watches for a list of exception classes in a "throws" clause.
 ctorHead
-	:	IDENT  // the name of the method
+    :    IDENT  // the name of the method
 
-		// parse the formal parameter declarations.
-		LPAREN! parameterDeclarationList RPAREN!
+        // parse the formal parameter declarations.
+        LPAREN! parameterDeclarationList RPAREN!
 
-		// get the list of exceptions that this method is declared to throw
-		(throwsClause)?
-	;
+        // get the list of exceptions that this method is declared to throw
+        (throwsClause)?
+    ;
 
 // This is a list of exception classes that the method is declared to throw
 throwsClause
-	:	"throws"^ identifier ( COMMA! identifier )*
-	;
+    :    "throws"^ identifier ( COMMA! identifier )*
+    ;
 
 
 // A list of formal parameters
 parameterDeclarationList
-	:	( parameterDeclaration ( COMMA! parameterDeclaration )* )?
-		{#parameterDeclarationList = #(#[PARAMETERS,"PARAMETERS"],
-									#parameterDeclarationList);}
-	;
+    :    ( parameterDeclaration ( COMMA! parameterDeclaration )* )?
+        {#parameterDeclarationList = #(#[PARAMETERS,"PARAMETERS"],
+                                    #parameterDeclarationList);}
+    ;
 
 // A formal parameter.
 parameterDeclaration!
-	:	pm:parameterModifier t:typeSpec[false] id:IDENT
-		pd:declaratorBrackets[#t]
-		{#parameterDeclaration = #(#[PARAMETER_DEF,"PARAMETER_DEF"],
-									pm, #([TYPE,"TYPE"],pd), id);}
-	;
+    :    pm:parameterModifier t:typeSpec[false] id:IDENT
+        pd:declaratorBrackets[#t]
+        {#parameterDeclaration = #(#[PARAMETER_DEF,"PARAMETER_DEF"],
+                                    pm, #([TYPE,"TYPE"],pd), id);}
+    ;
 
 parameterModifier
-	:	(f:"final")?
-		{#parameterModifier = #(#[MODIFIERS,"MODIFIERS"], f);}
-	;
+    :    (f:"final")?
+        {#parameterModifier = #(#[MODIFIERS,"MODIFIERS"], f);}
+    ;
 
 // Compound statement.  This is used in many contexts:
 //   Inside a class definition prefixed with "static":
@@ -549,151 +549,151 @@ parameterModifier
 //      it starts a new scope for variable definitions
 
 compoundStatement
-	:	lc:LCURLY^ {#lc.setType(SLIST); blockDepth++; }
-			// include the (possibly-empty) list of statements
-			(statement)*
-		RCURLY! { blockDepth--; }
-	;
+    :    lc:LCURLY^ {#lc.setType(SLIST); blockDepth++; }
+            // include the (possibly-empty) list of statements
+            (statement)*
+        RCURLY! { blockDepth--; }
+    ;
 
 
 statement
-	// A list of statements in curly braces -- start a new scope!
-	:	compoundStatement
-
-	// declarations are ambiguous with "ID DOT" relative to expression
-	// statements.  Must backtrack to be sure.  Could use a semantic
-	// predicate to test symbol table to see what the type was coming
-	// up, but that's pretty hard without a symbol table ;)
-	|	(declaration)=> declaration SEMI!
-
-	// An expression statement.  This could be a method call,
-	// assignment statement, or any other expression evaluated for
-	// side-effects.
-	|	expression SEMI!
-
-	// class definition
-	|	m:modifiers! classDefinition[#m]
-
-	// Attach a label to the front of a statement
-	|	IDENT c:COLON^ {#c.setType(LABELED_STAT);} statement
-
-	// If-else statement
-	|	"if"^ LPAREN! expression RPAREN! statement
-		(
-			// CONFLICT: the old "dangling-else" problem...
-			//           ANTLR generates proper code matching
-			//			 as soon as possible.  Hush warning.
-			options {
-				warnWhenFollowAmbig = false;
-			}
-		:
-			"else"! statement
-		)?
-
-	// For statement
-	|	"for"^
-			LPAREN!
-				forInit SEMI!   // initializer
-				forCond	SEMI!   // condition test
-				forIter         // updater
-			RPAREN!
-			statement                     // statement to loop over
-
-	// While statement
-	|	"while"^ LPAREN! expression RPAREN! statement
-
-	// do-while statement
-	|	"do"^ statement "while"! LPAREN! expression RPAREN! SEMI!
-
-	// get out of a loop (or switch)
-	|	"break"^ (IDENT)? SEMI!
-
-	// do next iteration of a loop
-	|	"continue"^ (IDENT)? SEMI!
-
-	// Return an expression
-	|	"return"^ (expression)? SEMI!
-
-	// switch/case statement
-	|	"switch"^ LPAREN! expression RPAREN! LCURLY! { blockDepth++; }
-			( casesGroup )*
-		RCURLY! { blockDepth--; }
-
-	// exception try-catch block
-	|	tryBlock
-
-	// throw an exception
-	|	"throw"^ expression SEMI!
-
-	// synchronize a statement
-	|	"synchronized"^ LPAREN! expression RPAREN! compoundStatement
-
-	// asserts (uncomment if you want 1.4 compatibility)
-	// |	"assert"^ expression ( COLON! expression )? SEMI!
-
-	// empty statement
-	|	s:SEMI {#s.setType(EMPTY_STAT);}
-	;
+    // A list of statements in curly braces -- start a new scope!
+    :    compoundStatement
+
+    // declarations are ambiguous with "ID DOT" relative to expression
+    // statements.  Must backtrack to be sure.  Could use a semantic
+    // predicate to test symbol table to see what the type was coming
+    // up, but that's pretty hard without a symbol table ;)
+    |    (declaration)=> declaration SEMI!
+
+    // An expression statement.  This could be a method call,
+    // assignment statement, or any other expression evaluated for
+    // side-effects.
+    |    expression SEMI!
+
+    // class definition
+    |    m:modifiers! classDefinition[#m]
+
+    // Attach a label to the front of a statement
+    |    IDENT c:COLON^ {#c.setType(LABELED_STAT);} statement
+
+    // If-else statement
+    |    "if"^ LPAREN! expression RPAREN! statement
+        (
+            // CONFLICT: the old "dangling-else" problem...
+            //           ANTLR generates proper code matching
+            //             as soon as possible.  Hush warning.
+            options {
+                warnWhenFollowAmbig = false;
+            }
+        :
+            "else"! statement
+        )?
+
+    // For statement
+    |    "for"^
+            LPAREN!
+                forInit SEMI!   // initializer
+                forCond    SEMI!   // condition test
+                forIter         // updater
+            RPAREN!
+            statement                     // statement to loop over
+
+    // While statement
+    |    "while"^ LPAREN! expression RPAREN! statement
+
+    // do-while statement
+    |    "do"^ statement "while"! LPAREN! expression RPAREN! SEMI!
+
+    // get out of a loop (or switch)
+    |    "break"^ (IDENT)? SEMI!
+
+    // do next iteration of a loop
+    |    "continue"^ (IDENT)? SEMI!
+
+    // Return an expression
+    |    "return"^ (expression)? SEMI!
+
+    // switch/case statement
+    |    "switch"^ LPAREN! expression RPAREN! LCURLY! { blockDepth++; }
+            ( casesGroup )*
+        RCURLY! { blockDepth--; }
+
+    // exception try-catch block
+    |    tryBlock
+
+    // throw an exception
+    |    "throw"^ expression SEMI!
+
+    // synchronize a statement
+    |    "synchronized"^ LPAREN! expression RPAREN! compoundStatement
+
+    // asserts (uncomment if you want 1.4 compatibility)
+    // |    "assert"^ expression ( COLON! expression )? SEMI!
+
+    // empty statement
+    |    s:SEMI {#s.setType(EMPTY_STAT);}
+    ;
 
 casesGroup
-	:	(	// CONFLICT: to which case group do the statements bind?
-			//           ANTLR generates proper code: it groups the
-			//           many "case"/"default" labels together then
-			//           follows them with the statements
-			options {
-				greedy = true;
-			}
-			:
-			aCase
-		)+
-		caseSList
-		{#casesGroup = #([CASE_GROUP, "CASE_GROUP"], #casesGroup);}
-	;
+    :    (    // CONFLICT: to which case group do the statements bind?
+            //           ANTLR generates proper code: it groups the
+            //           many "case"/"default" labels together then
+            //           follows them with the statements
+            options {
+                greedy = true;
+            }
+            :
+            aCase
+        )+
+        caseSList
+        {#casesGroup = #([CASE_GROUP, "CASE_GROUP"], #casesGroup);}
+    ;
 
 aCase
-	:	("case"^ expression | "default") COLON!
-	;
+    :    ("case"^ expression | "default") COLON!
+    ;
 
 caseSList
-	:	(statement)*
-		{#caseSList = #(#[SLIST,"SLIST"],#caseSList);}
-	;
+    :    (statement)*
+        {#caseSList = #(#[SLIST,"SLIST"],#caseSList);}
+    ;
 
 // The initializer for a for loop
 forInit
-		// if it looks like a declaration, it is
-	:	(	(declaration)=> declaration
-		// otherwise it could be an expression list...
-		|	expressionList
-		)?
-		{#forInit = #(#[FOR_INIT,"FOR_INIT"],#forInit);}
-	;
+        // if it looks like a declaration, it is
+    :    (    (declaration)=> declaration
+        // otherwise it could be an expression list...
+        |    expressionList
+        )?
+        {#forInit = #(#[FOR_INIT,"FOR_INIT"],#forInit);}
+    ;
 
 forCond
-	:	(expression)?
-		{#forCond = #(#[FOR_CONDITION,"FOR_CONDITION"],#forCond);}
-	;
+    :    (expression)?
+        {#forCond = #(#[FOR_CONDITION,"FOR_CONDITION"],#forCond);}
+    ;
 
 forIter
-	:	(expressionList)?
-		{#forIter = #(#[FOR_ITERATOR,"FOR_ITERATOR"],#forIter);}
-	;
+    :    (expressionList)?
+        {#forIter = #(#[FOR_ITERATOR,"FOR_ITERATOR"],#forIter);}
+    ;
 
 // an exception handler try/catch block
 tryBlock
-	:	"try"^ compoundStatement
-		(handler)*
-		( finallyClause )?
-	;
+    :    "try"^ compoundStatement
+        (handler)*
+        ( finallyClause )?
+    ;
 
 finallyClause
-	:	"finally"^ compoundStatement
-	;
+    :    "finally"^ compoundStatement
+    ;
 
 // an exception handler
 handler
-	:	"catch"^ LPAREN! parameterDeclaration RPAREN! compoundStatement
-	;
+    :    "catch"^ LPAREN! parameterDeclaration RPAREN! compoundStatement
+    ;
 
 
 // expressions
@@ -732,22 +732,22 @@ handler
 
 // the mother of all expressions
 expression
-	:	assignmentExpression
-		{#expression = #(#[EXPR,"EXPR"],#expression);}
-	;
+    :    assignmentExpression
+        {#expression = #(#[EXPR,"EXPR"],#expression);}
+    ;
 
 
 // This is a list of expressions.
 expressionList
-	:	expression (COMMA! expression)*
-		{#expressionList = #(#[ELIST,"ELIST"], expressionList);}
-	;
+    :    expression (COMMA! expression)*
+        {#expressionList = #(#[ELIST,"ELIST"], expressionList);}
+    ;
 
 
 // assignment expression (level 13)
 assignmentExpression
-	:	conditionalExpression
-		(	(	ASSIGN^
+    :    conditionalExpression
+        (    (    ASSIGN^
             |   PLUS_ASSIGN^
             |   MINUS_ASSIGN^
             |   STAR_ASSIGN^
@@ -760,99 +760,99 @@ assignmentExpression
             |   BXOR_ASSIGN^
             |   BOR_ASSIGN^
             )
-			assignmentExpression
-		)?
-	;
+            assignmentExpression
+        )?
+    ;
 
 
 // conditional test (level 12)
 conditionalExpression
-	:	logicalOrExpression
-		( QUESTION^ assignmentExpression COLON! conditionalExpression )?
-	;
+    :    logicalOrExpression
+        ( QUESTION^ assignmentExpression COLON! conditionalExpression )?
+    ;
 
 
 // logical or (||)  (level 11)
 logicalOrExpression
-	:	logicalAndExpression (LOR^ logicalAndExpression)*
-	;
+    :    logicalAndExpression (LOR^ logicalAndExpression)*
+    ;
 
 
 // logical and (&&)  (level 10)
 logicalAndExpression
-	:	inclusiveOrExpression (LAND^ inclusiveOrExpression)*
-	;
+    :    inclusiveOrExpression (LAND^ inclusiveOrExpression)*
+    ;
 
 
 // bitwise or non-short-circuiting or (|)  (level 9)
 inclusiveOrExpression
-	:	exclusiveOrExpression (BOR^ exclusiveOrExpression)*
-	;
+    :    exclusiveOrExpression (BOR^ exclusiveOrExpression)*
+    ;
 
 
 // exclusive or (^)  (level 8)
 exclusiveOrExpression
-	:	andExpression (BXOR^ andExpression)*
-	;
+    :    andExpression (BXOR^ andExpression)*
+    ;
 
 
 // bitwise or non-short-circuiting and (&)  (level 7)
 andExpression
-	:	equalityExpression (BAND^ equalityExpression)*
-	;
+    :    equalityExpression (BAND^ equalityExpression)*
+    ;
 
 
 // equality/inequality (==/!=) (level 6)
 equalityExpression
-	:	relationalExpression ((NOT_EQUAL^ | EQUAL^) relationalExpression)*
-	;
+    :    relationalExpression ((NOT_EQUAL^ | EQUAL^) relationalExpression)*
+    ;
 
 
 // boolean relational expressions (level 5)
 relationalExpression
-	:	shiftExpression
-		(	(	(	LT^
-				|	GT^
-				|	LE^
-				|	GE^
-				)
-				shiftExpression
-			)*
-		|	"instanceof"^ typeSpec[true]
-		)
-	;
+    :    shiftExpression
+        (    (    (    LT^
+                |    GT^
+                |    LE^
+                |    GE^
+                )
+                shiftExpression
+            )*
+        |    "instanceof"^ typeSpec[true]
+        )
+    ;
 
 
 // bit shift expressions (level 4)
 shiftExpression
-	:	additiveExpression ((SL^ | SR^ | BSR^) additiveExpression)*
-	;
+    :    additiveExpression ((SL^ | SR^ | BSR^) additiveExpression)*
+    ;
 
 
 // binary addition/subtraction (level 3)
 additiveExpression
-	:	multiplicativeExpression ((PLUS^ | MINUS^) multiplicativeExpression)*
-	;
+    :    multiplicativeExpression ((PLUS^ | MINUS^) multiplicativeExpression)*
+    ;
 
 
 // multiplication/division/modulo (level 2)
 multiplicativeExpression
-	:	unaryExpression ((STAR^ | DIV^ | MOD^ ) unaryExpression)*
-	;
+    :    unaryExpression ((STAR^ | DIV^ | MOD^ ) unaryExpression)*
+    ;
 
 unaryExpression
-	:	INC^ unaryExpression
-	|	DEC^ unaryExpression
-	|	MINUS^ {#MINUS.setType(UNARY_MINUS);} unaryExpression
-	|	PLUS^  {#PLUS.setType(UNARY_PLUS);} unaryExpression
-	|	unaryExpressionNotPlusMinus
-	;
+    :    INC^ unaryExpression
+    |    DEC^ unaryExpression
+    |    MINUS^ {#MINUS.setType(UNARY_MINUS);} unaryExpression
+    |    PLUS^  {#PLUS.setType(UNARY_PLUS);} unaryExpression
+    |    unaryExpressionNotPlusMinus
+    ;
 
 unaryExpressionNotPlusMinus
-	:	BNOT^ unaryExpression
-	|	LNOT^ unaryExpression
+    :    BNOT^ unaryExpression
+    |    LNOT^ unaryExpression
 
-		// use predicate to skip cases like: (int.class)
+        // use predicate to skip cases like: (int.class)
     |   (LPAREN builtInTypeSpec[true] RPAREN) =>
         lpb:LPAREN^ {#lpb.setType(TYPECAST);} builtInTypeSpec[true] RPAREN!
         unaryExpression
@@ -860,108 +860,108 @@ unaryExpressionNotPlusMinus
         // Have to backtrack to see if operator follows.  If no operator
         // follows, it's a typecast.  No semantic checking needed to parse.
         // if it _looks_ like a cast, it _is_ a cast; else it's a "(expr)"
-    |	(LPAREN classTypeSpec[true] RPAREN unaryExpressionNotPlusMinus)=>
+    |    (LPAREN classTypeSpec[true] RPAREN unaryExpressionNotPlusMinus)=>
         lp:LPAREN^ {#lp.setType(TYPECAST);} classTypeSpec[true] RPAREN!
         unaryExpressionNotPlusMinus
 
-    |	postfixExpression
-	;
+    |    postfixExpression
+    ;
 
 // qualified names, array expressions, method invocation, post inc/dec
 postfixExpression
-	:
+    :
     /*
     "this"! lp1:LPAREN^ argList RPAREN!
-		{#lp1.setType(CTOR_CALL);}
+        {#lp1.setType(CTOR_CALL);}
 
     |   "super"! lp2:LPAREN^ argList RPAREN!
-		{#lp2.setType(SUPER_CTOR_CALL);}
+        {#lp2.setType(SUPER_CTOR_CALL);}
     |
     */
         primaryExpression
 
-		(
+        (
             /*
             options {
-				// the use of postfixExpression in SUPER_CTOR_CALL adds DOT
-				// to the lookahead set, and gives loads of false non-det
-				// warnings.
-				// shut them off.
-				generateAmbigWarnings=false;
-			}
-		:	*/
+                // the use of postfixExpression in SUPER_CTOR_CALL adds DOT
+                // to the lookahead set, and gives loads of false non-det
+                // warnings.
+                // shut them off.
+                generateAmbigWarnings=false;
+            }
+        :    */
             DOT^ IDENT
-			(	lp:LPAREN^ {#lp.setType(METHOD_CALL);}
-				argList
-				RPAREN!
-			)?
-		|	DOT^ "this"
+            (    lp:LPAREN^ {#lp.setType(METHOD_CALL);}
+                argList
+                RPAREN!
+            )?
+        |    DOT^ "this"
 
-		|	DOT^ "super"
+        |    DOT^ "super"
             (   // (new Outer()).super()  (create enclosing instance)
                 lp3:LPAREN^ argList RPAREN!
                 {#lp3.setType(SUPER_CTOR_CALL);}
-			|   DOT^ IDENT
-                (	lps:LPAREN^ {#lps.setType(METHOD_CALL);}
+            |   DOT^ IDENT
+                (    lps:LPAREN^ {#lps.setType(METHOD_CALL);}
                     argList
                     RPAREN!
                 )?
             )
-		|	DOT^ newExpression
-		|	lb:LBRACK^ {#lb.setType(INDEX_OP);} expression RBRACK!
-		)*
+        |    DOT^ newExpression
+        |    lb:LBRACK^ {#lb.setType(INDEX_OP);} expression RBRACK!
+        )*
 
-		(   // possibly add on a post-increment or post-decrement.
+        (   // possibly add on a post-increment or post-decrement.
             // allows INC/DEC on too much, but semantics can check
-			in:INC^ {#in.setType(POST_INC);}
-	 	|	de:DEC^ {#de.setType(POST_DEC);}
-		)?
- 	;
+            in:INC^ {#in.setType(POST_INC);}
+         |    de:DEC^ {#de.setType(POST_DEC);}
+        )?
+     ;
 
 // the basic element of an expression
 primaryExpression
-	:	identPrimary ( options {greedy=true;} : DOT^ "class" )?
+    :    identPrimary ( options {greedy=true;} : DOT^ "class" )?
     |   constant
-	|	"true"
-	|	"false"
-	|	"null"
+    |    "true"
+    |    "false"
+    |    "null"
     |   newExpression
-	|	"this"
-	|	"super"
-	|	LPAREN! assignmentExpression RPAREN!
-		// look for int.class and int[].class
-	|	builtInType
-		( lbt:LBRACK^ {#lbt.setType(ARRAY_DECLARATOR);} RBRACK! )*
-		DOT^ "class"
-	;
+    |    "this"
+    |    "super"
+    |    LPAREN! assignmentExpression RPAREN!
+        // look for int.class and int[].class
+    |    builtInType
+        ( lbt:LBRACK^ {#lbt.setType(ARRAY_DECLARATOR);} RBRACK! )*
+        DOT^ "class"
+    ;
 
 /** Match a, a.b.c refs, a.b.c(...) refs, a.b.c[], a.b.c[].class,
  *  and a.b.c.class refs.  Also this(...) and super(...).  Match
  *  this or super.
  */
 identPrimary
-	:	IDENT
-		(
+    :    IDENT
+        (
             options {
-				// .ident could match here or in postfixExpression.
-				// We do want to match here.  Turn off warning.
-				greedy=true;
-			}
-		:	DOT^ IDENT
-		)*
-		(
+                // .ident could match here or in postfixExpression.
+                // We do want to match here.  Turn off warning.
+                greedy=true;
+            }
+        :    DOT^ IDENT
+        )*
+        (
             options {
-				// ARRAY_DECLARATOR here conflicts with INDEX_OP in
-				// postfixExpression on LBRACK RBRACK.
-				// We want to match [] here, so greedy.  This overcomes
+                // ARRAY_DECLARATOR here conflicts with INDEX_OP in
+                // postfixExpression on LBRACK RBRACK.
+                // We want to match [] here, so greedy.  This overcomes
                 // limitation of linear approximate lookahead.
-				greedy=true;
-		    }
-		:   ( lp:LPAREN^ {#lp.setType(METHOD_CALL);} argList RPAREN! )
-		|	( options {greedy=true;} :
+                greedy=true;
+            }
+        :   ( lp:LPAREN^ {#lp.setType(METHOD_CALL);} argList RPAREN! )
+        |    ( options {greedy=true;} :
               lbc:LBRACK^ {#lbc.setType(ARRAY_DECLARATOR);} RBRACK!
             )+
-		)?
+        )?
     ;
 
 /** object instantiation.
@@ -1014,53 +1014,53 @@ identPrimary
  *
  */
 newExpression
-	:	"new"^ type
-		(	LPAREN! argList RPAREN! (classBlock)?
-
-			//java 1.1
-			// Note: This will allow bad constructs like
-			//    new int[4][][3] {exp,exp}.
-			//    There needs to be a semantic check here...
-			// to make sure:
-			//   a) [ expr ] and [ ] are not mixed
-			//   b) [ expr ] and an init are not used together
-
-		|	newArrayDeclarator (arrayInitializer)?
-		)
-	;
+    :    "new"^ type
+        (    LPAREN! argList RPAREN! (classBlock)?
+
+            //java 1.1
+            // Note: This will allow bad constructs like
+            //    new int[4][][3] {exp,exp}.
+            //    There needs to be a semantic check here...
+            // to make sure:
+            //   a) [ expr ] and [ ] are not mixed
+            //   b) [ expr ] and an init are not used together
+
+        |    newArrayDeclarator (arrayInitializer)?
+        )
+    ;
 
 argList
-	:	(	expressionList
-		|	/*nothing*/
-			{#argList = #[ELIST,"ELIST"];}
-		)
-	;
+    :    (    expressionList
+        |    /*nothing*/
+            {#argList = #[ELIST,"ELIST"];}
+        )
+    ;
 
 newArrayDeclarator
-	:	(
-			// CONFLICT:
-			// newExpression is a primaryExpression which can be
-			// followed by an array index reference.  This is ok,
-			// as the generated code will stay in this loop as
-			// long as it sees an LBRACK (proper behavior)
-			options {
-				warnWhenFollowAmbig = false;
-			}
-		:
-			lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);}
-				(expression)?
-			RBRACK!
-		)+
-	;
+    :    (
+            // CONFLICT:
+            // newExpression is a primaryExpression which can be
+            // followed by an array index reference.  This is ok,
+            // as the generated code will stay in this loop as
+            // long as it sees an LBRACK (proper behavior)
+            options {
+                warnWhenFollowAmbig = false;
+            }
+        :
+            lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);}
+                (expression)?
+            RBRACK!
+        )+
+    ;
 
 constant
-	:	NUM_INT
-	|	CHAR_LITERAL
-	|	STRING_LITERAL
-	|	NUM_FLOAT
-	|	NUM_LONG
-	|	NUM_DOUBLE
-	;
+    :    NUM_INT
+    |    CHAR_LITERAL
+    |    STRING_LITERAL
+    |    NUM_FLOAT
+    |    NUM_LONG
+    |    NUM_DOUBLE
+    ;
 
 //----------------------------------------------------------------------------
 // The Java scanner
@@ -1068,121 +1068,121 @@ constant
 class JavaLexer extends Lexer;
 
 options {
-	exportVocab=Java;      // call the vocabulary "Java"
-	testLiterals=false;    // don't automatically test for literals
-	k=4;                   // four characters of lookahead
-	charVocabulary='\u0003'..'\u7FFE';
-	// without inlining some bitset tests, couldn't do unicode;
-	// I need to make ANTLR generate smaller bitsets; see
-	// bottom of JavaLexer.java
-	codeGenBitsetTestThreshold=20;
+    exportVocab=Java;      // call the vocabulary "Java"
+    testLiterals=false;    // don't automatically test for literals
+    k=4;                   // four characters of lookahead
+    charVocabulary='\u0003'..'\u7FFE';
+    // without inlining some bitset tests, couldn't do unicode;
+    // I need to make ANTLR generate smaller bitsets; see
+    // bottom of JavaLexer.java
+    codeGenBitsetTestThreshold=20;
 }
 
 // OPERATORS
-QUESTION		:	'?'		;
-LPAREN			:	'('		;
-RPAREN			:	')'		;
-LBRACK			:	'['		;
-RBRACK			:	']'		;
-LCURLY			:	'{'		;
-RCURLY			:	'}'		;
-COLON			:	':'		;
-COMMA			:	','		;
-//DOT			:	'.'		;
-ASSIGN			:	'='		;
-EQUAL			:	"=="	;
-LNOT			:	'!'		;
-BNOT			:	'~'		;
-NOT_EQUAL		:	"!="	;
-DIV				:	'/'		;
-DIV_ASSIGN		:	"/="	;
-PLUS			:	'+'		;
-PLUS_ASSIGN		:	"+="	;
-INC				:	"++"	;
-MINUS			:	'-'		;
-MINUS_ASSIGN	:	"-="	;
-DEC				:	"--"	;
-STAR			:	'*'		;
-STAR_ASSIGN		:	"*="	;
-MOD				:	'%'		;
-MOD_ASSIGN		:	"%="	;
-SR				:	">>"	;
-SR_ASSIGN		:	">>="	;
-BSR				:	">>>"	;
-BSR_ASSIGN		:	">>>="	;
-GE				:	">="	;
-GT				:	">"		;
-SL				:	"<<"	;
-SL_ASSIGN		:	"<<="	;
-LE				:	"<="	;
-LT				:	'<'		;
-BXOR			:	'^'		;
-BXOR_ASSIGN		:	"^="	;
-BOR				:	'|'		;
-BOR_ASSIGN		:	"|="	;
-LOR				:	"||"	;
-BAND			:	'&'		;
-BAND_ASSIGN		:	"&="	;
-LAND			:	"&&"	;
-SEMI			:	';'		;
+QUESTION        :    '?'        ;
+LPAREN            :    '('        ;
+RPAREN            :    ')'        ;
+LBRACK            :    '['        ;
+RBRACK            :    ']'        ;
+LCURLY            :    '{'        ;
+RCURLY            :    '}'        ;
+COLON            :    ':'        ;
+COMMA            :    ','        ;
+//DOT            :    '.'        ;
+ASSIGN            :    '='        ;
+EQUAL            :    "=="    ;
+LNOT            :    '!'        ;
+BNOT            :    '~'        ;
+NOT_EQUAL        :    "!="    ;
+DIV                :    '/'        ;
+DIV_ASSIGN        :    "/="    ;
+PLUS            :    '+'        ;
+PLUS_ASSIGN        :    "+="    ;
+INC                :    "++"    ;
+MINUS            :    '-'        ;
+MINUS_ASSIGN    :    "-="    ;
+DEC                :    "--"    ;
+STAR            :    '*'        ;
+STAR_ASSIGN        :    "*="    ;
+MOD                :    '%'        ;
+MOD_ASSIGN        :    "%="    ;
+SR                :    ">>"    ;
+SR_ASSIGN        :    ">>="    ;
+BSR                :    ">>>"    ;
+BSR_ASSIGN        :    ">>>="    ;
+GE                :    ">="    ;
+GT                :    ">"        ;
+SL                :    "<<"    ;
+SL_ASSIGN        :    "<<="    ;
+LE                :    "<="    ;
+LT                :    '<'        ;
+BXOR            :    '^'        ;
+BXOR_ASSIGN        :    "^="    ;
+BOR                :    '|'        ;
+BOR_ASSIGN        :    "|="    ;
+LOR                :    "||"    ;
+BAND            :    '&'        ;
+BAND_ASSIGN        :    "&="    ;
+LAND            :    "&&"    ;
+SEMI            :    ';'        ;
 
 
 // Whitespace -- ignored
-WS	:	(	' '
-		|	'\t'
-		|	'\f'
-			// handle newlines
-		|	(	options {generateAmbigWarnings=false;}
-			:	"\r\n"  // Evil DOS
-			|	'\r'    // Macintosh
-			|	'\n'    // Unix (the right way)
-			)
-			{ newline(); }
-		)+
-		{ _ttype = Token.SKIP; }
-	;
+WS    :    (    ' '
+        |    '\t'
+        |    '\f'
+            // handle newlines
+        |    (    options {generateAmbigWarnings=false;}
+            :    "\r\n"  // Evil DOS
+            |    '\r'    // Macintosh
+            |    '\n'    // Unix (the right way)
+            )
+            { newline(); }
+        )+
+        { _ttype = Token.SKIP; }
+    ;
 
 // Single-line comments
 SL_COMMENT
-	:	"//"
-		(~('\n'|'\r'))* ('\n'|'\r'('\n')?)?
-		{$setType(Token.SKIP); newline();}
-	;
+    :    "//"
+        (~('\n'|'\r'))* ('\n'|'\r'('\n')?)?
+        {$setType(Token.SKIP); newline();}
+    ;
 
 // multiple-line comments
 ML_COMMENT
-	:	"/*"
-		(	/*	'\r' '\n' can be matched in one alternative or by matching
-				'\r' in one iteration and '\n' in another.  I am trying to
-				handle any flavor of newline that comes in, but the language
-				that allows both "\r\n" and "\r" and "\n" to all be valid
-				newline is ambiguous.  Consequently, the resulting grammar
-				must be ambiguous.  I'm shutting this warning off.
-			 */
-			options {
-				generateAmbigWarnings=false;
-			}
-		:
-			{ LA(2)!='/' }? '*'
-		|	'\r' '\n'		{newline();}
-		|	'\r'			{newline();}
-		|	'\n'			{newline();}
-		|	~('*'|'\n'|'\r')
-		)*
-		"*/"
-		{$setType(Token.SKIP);}
-	;
+    :    "/*"
+        (    /*    '\r' '\n' can be matched in one alternative or by matching
+                '\r' in one iteration and '\n' in another.  I am trying to
+                handle any flavor of newline that comes in, but the language
+                that allows both "\r\n" and "\r" and "\n" to all be valid
+                newline is ambiguous.  Consequently, the resulting grammar
+                must be ambiguous.  I'm shutting this warning off.
+             */
+            options {
+                generateAmbigWarnings=false;
+            }
+        :
+            { LA(2)!='/' }? '*'
+        |    '\r' '\n'        {newline();}
+        |    '\r'            {newline();}
+        |    '\n'            {newline();}
+        |    ~('*'|'\n'|'\r')
+        )*
+        "*/"
+        {$setType(Token.SKIP);}
+    ;
 
 
 // character literals
 CHAR_LITERAL
-	:	'\'' ( ESC | ~('\''|'\n'|'\r'|'\\') ) '\''
-	;
+    :    '\'' ( ESC | ~('\''|'\n'|'\r'|'\\') ) '\''
+    ;
 
 // string literals
 STRING_LITERAL
-	:	'"' (ESC|~('"'|'\\'|'\n'|'\r'))* '"'
-	;
+    :    '"' (ESC|~('"'|'\\'|'\n'|'\r'))* '"'
+    ;
 
 
 // escape sequence -- note that this is protected; it can only be called
@@ -1195,121 +1195,132 @@ STRING_LITERAL
 // the FOLLOW ambig warnings.
 protected
 ESC
-	:	'\\'
-		(	'n'
-		|	'r'
-		|	't'
-		|	'b'
-		|	'f'
-		|	'"'
-		|	'\''
-		|	'\\'
-		|	('u')+ HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
-		|	'0'..'3'
-			(
-				options {
-					warnWhenFollowAmbig = false;
-				}
-			:	'0'..'7'
-				(
-					options {
-						warnWhenFollowAmbig = false;
-					}
-				:	'0'..'7'
-				)?
-			)?
-		|	'4'..'7'
-			(
-				options {
-					warnWhenFollowAmbig = false;
-				}
-			:	'0'..'7'
-			)?
-		)
-	;
+    :    '\\'
+        (    'n'
+        |    'r'
+        |    't'
+        |    'b'
+        |    'f'
+        |    '"'
+        |    '\''
+        |    '\\'
+        |    ('u')+ HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
+        |    '0'..'3'
+            (
+                options {
+                    warnWhenFollowAmbig = false;
+                }
+            :    '0'..'7'
+                (
+                    options {
+                        warnWhenFollowAmbig = false;
+                    }
+                :    '0'..'7'
+                )?
+            )?
+        |    '4'..'7'
+            (
+                options {
+                    warnWhenFollowAmbig = false;
+                }
+            :    '0'..'7'
+            )?
+        )
+    ;
 
 
 // hexadecimal digit (again, note it's protected!)
 protected
 HEX_DIGIT
-	:	('0'..'9'|'A'..'F'|'a'..'f')
-	;
+    :    ('0'..'9'|'A'..'F'|'a'..'f')
+    ;
 
 
 // an identifier.  Note that testLiterals is set to true!  This means
 // that after we match the rule, we look in the literals table to see
 // if it's a literal or really an identifer
 IDENT
-	options {testLiterals=true;}
-	:	('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|'$')*
-	;
+    options {testLiterals=true;}
+    :    ('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|'$')*
+    ;
 
 
 // a numeric literal
 NUM_INT
-	{boolean isDecimal=false; Token t=null;}
+    {boolean isDecimal=false, isHexadecimal=false; Token t=null;}
     :   '.' {_ttype = DOT;}
-            (	('0'..'9')+ (EXPONENT)? (f1:FLOAT_SUFFIX {t=f1;})?
+            (    ('0'..'9')+ (EXPONENT)? (f1:FLOAT_SUFFIX {t=f1;})?
                 {
-				if (t != null && t.getText().toUpperCase().indexOf('F')>=0) {
-                	_ttype = NUM_FLOAT;
-				}
-				else {
-                	_ttype = NUM_DOUBLE; // assume double
-				}
-				}
+                if (t != null && t.getText().toUpperCase().indexOf('F')>=0) {
+                    _ttype = NUM_FLOAT;
+                }
+                else {
+                    _ttype = NUM_DOUBLE; // assume double
+                }
+                }
             )?
 
-	|	(	'0' {isDecimal = true;} // special case for just '0'
-			(	('x'|'X')
-				(											// hex
-					// the 'e'|'E' and float suffix stuff look
-					// like hex digits, hence the (...)+ doesn't
-					// know when to stop: ambig.  ANTLR resolves
-					// it correctly by matching immediately.  It
-					// is therefor ok to hush warning.
-					options {
-						warnWhenFollowAmbig=false;
-					}
-				:	HEX_DIGIT
-				)+
-
-			|	//float or double with leading zero
-				(('0'..'9')+ ('.'|EXPONENT|FLOAT_SUFFIX)) => ('0'..'9')+
-
-			|	('0'..'7')+									// octal
-			)?
-		|	('1'..'9') ('0'..'9')*  {isDecimal=true;}		// non-zero decimal
-		)
-		(	('l'|'L') { _ttype = NUM_LONG; }
-
-		// only check to see if it's a float if looks like decimal so far
-		|	{isDecimal}?
-            (   '.' ('0'..'9')* (EXPONENT)? (f2:FLOAT_SUFFIX {t=f2;})?
-            |   EXPONENT (f3:FLOAT_SUFFIX {t=f3;})?
-            |   f4:FLOAT_SUFFIX {t=f4;}
-            )
-            {
-			if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0) {
-                _ttype = NUM_FLOAT;
-			}
-            else {
-	           	_ttype = NUM_DOUBLE; // assume double
-			}
-			}
+    |    (  '0' {isDecimal = true;} // special case for just '0'
+            (    ('x'|'X') { isHexadecimal=true; }           // hex
+                (
+                    // the 'e'|'E' and float suffix stuff look
+                    // like hex digits, hence the (...)+ doesn't
+                    // know when to stop: ambig.  ANTLR resolves
+                    // it correctly by matching immediately.  It
+                    // is therefor ok to hush warning.
+                    options {
+                        warnWhenFollowAmbig=false;
+                    }
+                :    HEX_DIGIT
+                )+
+
+            |    //float or double with leading zero
+                (('0'..'9')+ ('.'|EXPONENT|FLOAT_SUFFIX)) => ('0'..'9')+
+
+            |    ('0'..'7')+                                    // octal
+            )?
+        |   ('1'..'9') ('0'..'9')* {isDecimal=true;}            // non-zero decimal
+        )
+        (
+            ('l'|'L') { _ttype = NUM_LONG; }
+
+            // check to see if it's a hexadecimal w/ binary exponent float if looks like hexadecimal so far
+        |   {isHexadecimal}?
+                ( '.' ( options { warnWhenFollowAmbig=false; } : HEX_DIGIT )* )?
+                ('p'|'P') ('+'|'-')? ('0'..'9')+ (f5:FLOAT_SUFFIX {t=f5;})?
+                {
+                    if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0) {
+                        _ttype = NUM_FLOAT;
+                    } else {
+                        _ttype = NUM_DOUBLE; // assume double
+                    }
+                }
+            // check to see if it's a float if looks like decimal so far
+        |   {isDecimal}?
+                (   '.' ('0'..'9')* (EXPONENT)? (f2:FLOAT_SUFFIX {t=f2;})?
+                |   EXPONENT (f3:FLOAT_SUFFIX {t=f3;})?
+                |   f4:FLOAT_SUFFIX {t=f4;}
+                )
+                {
+                    if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0) {
+                        _ttype = NUM_FLOAT;
+                    } else {
+                        _ttype = NUM_DOUBLE; // assume double
+                    }
+                }
         )?
-	;
+    ;
 
 
 // a couple protected methods to assist in matching floating point numbers
 protected
 EXPONENT
-	:	('e'|'E') ('+'|'-')? ('0'..'9')+
-	;
+    :    ('e'|'E') (PLUS|MINUS)? ('0'..'9')+
+    ;
 
 
 protected
 FLOAT_SUFFIX
-	:	'f'|'F'|'d'|'D'
-	;
+    :    'f'|'F'|'d'|'D'
+    ;
 
diff --git a/src/java/com/jogamp/common/ExceptionUtils.java b/src/java/com/jogamp/common/ExceptionUtils.java
new file mode 100644
index 0000000..c848a99
--- /dev/null
+++ b/src/java/com/jogamp/common/ExceptionUtils.java
@@ -0,0 +1,78 @@
+/**
+ * Copyright 2014 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.common;
+
+import java.io.PrintStream;
+
+/**
+ * @since 2.3.0
+ */
+public class ExceptionUtils {
+    public static void dumpStack(final PrintStream out) {
+        dumpStack(out, 1, -1);
+    }
+    public static void dumpStack(final PrintStream out, final int skip, final int depth) {
+        dumpStack(out, new Exception(""), skip+1, depth);
+    }
+    public static void dumpStack(final PrintStream out, final Throwable t, final int skip, final int depth) {
+        dumpStack(out, t.getStackTrace(), skip, depth);
+    }
+    public static void dumpStack(final PrintStream out, final StackTraceElement[] stack, final int skip, final int depth) {
+        if( null == stack ) {
+            return;
+        }
+        final int maxDepth;
+        if( 0 > depth ) {
+            maxDepth = stack.length;
+        } else {
+            maxDepth = Math.min(depth+skip, stack.length);
+        }
+        for(int i=skip; i<maxDepth; i++) {
+            out.println("    ["+i+"]: "+stack[i]);
+        }
+    }
+
+    /**
+     * Dumps a {@link Throwable} in a decorating message including the current thread name,
+     * and its {@link #dumpStack(PrintStream, StackTraceElement[], int, int) stack trace}.
+     * <p>
+     * Implementation will iterate through all {@link Throwable#getCause() causes}.
+     * </p>
+     */
+    public static void dumpThrowable(final String additionalDescr, final Throwable t) {
+        System.err.println("Caught "+additionalDescr+" "+t.getClass().getSimpleName()+": "+t.getMessage()+" on thread "+Thread.currentThread().getName());
+        dumpStack(System.err, t.getStackTrace(), 0, -1);
+        int causeDepth = 1;
+        for( Throwable cause = t.getCause(); null != cause; cause = cause.getCause() ) {
+            System.err.println("Caused["+causeDepth+"] by "+cause.getClass().getSimpleName()+": "+cause.getMessage()+" on thread "+Thread.currentThread().getName());
+            dumpStack(System.err, cause.getStackTrace(), 0, -1);
+            causeDepth++;
+        }
+    }
+
+}
diff --git a/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java b/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java
index 4bb68d3..9b1865f 100644
--- a/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java
+++ b/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java
@@ -42,7 +42,6 @@ package com.jogamp.common.jvm;
 import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.security.AccessController;
@@ -52,8 +51,8 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 
+import com.jogamp.common.net.Uri;
 import com.jogamp.common.os.NativeLibrary;
-import com.jogamp.common.util.IOUtil;
 import com.jogamp.common.util.JarUtil;
 import com.jogamp.common.util.PropertyAccess;
 import com.jogamp.common.util.cache.TempJarCache;
@@ -155,7 +154,7 @@ public class JNILibLoaderBase {
   /**
    *
    * @param classFromJavaJar
-   * @param classJarURI
+   * @param classJarUri
    * @param jarBasename jar basename w/ suffix
    * @param nativeJarBasename native jar basename w/ suffix
    * @return
@@ -163,15 +162,15 @@ public class JNILibLoaderBase {
    * @throws SecurityException
    * @throws URISyntaxException
    */
-  private static final boolean addNativeJarLibsImpl(final Class<?> classFromJavaJar, final URI classJarURI,
-                                                    final String jarBasename, final String nativeJarBasename)
+  private static final boolean addNativeJarLibsImpl(final Class<?> classFromJavaJar, final Uri classJarUri,
+                                                    final Uri.Encoded jarBasename, final Uri.Encoded nativeJarBasename)
     throws IOException, SecurityException, URISyntaxException
   {
     if (DEBUG) {
         final StringBuilder msg = new StringBuilder();
         msg.append("JNILibLoaderBase: addNativeJarLibsImpl(").append(PlatformPropsImpl.NEWLINE);
         msg.append("  classFromJavaJar  = ").append(classFromJavaJar).append(PlatformPropsImpl.NEWLINE);
-        msg.append("  classJarURI       = ").append(classJarURI).append(PlatformPropsImpl.NEWLINE);
+        msg.append("  classJarURI       = ").append(classJarUri).append(PlatformPropsImpl.NEWLINE);
         msg.append("  jarBasename       = ").append(jarBasename).append(PlatformPropsImpl.NEWLINE);
         msg.append("  os.and.arch       = ").append(PlatformPropsImpl.os_and_arch).append(PlatformPropsImpl.NEWLINE);
         msg.append("  nativeJarBasename = ").append(nativeJarBasename).append(PlatformPropsImpl.NEWLINE);
@@ -181,15 +180,15 @@ public class JNILibLoaderBase {
 
     boolean ok = false;
 
-    final URI jarSubURI = JarUtil.getJarSubURI( classJarURI );
+    final Uri jarSubURI = classJarUri.getContainedUri();
     if (null == jarSubURI) {
-        throw new IllegalArgumentException("JarSubURI is null of: "+classJarURI);
+        throw new IllegalArgumentException("JarSubURI is null of: "+classJarUri);
     }
 
-    final String jarUriRoot_s = IOUtil.getURIDirname( jarSubURI.toString() );
+    final Uri jarSubUriRoot = jarSubURI.getDirectory();
 
     if (DEBUG) {
-        System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: initial: %s -> %s%n", jarSubURI, jarUriRoot_s);
+        System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: initial: %s -> %s%n", jarSubURI, jarSubUriRoot);
     }
 
     final String nativeLibraryPath = String.format("natives/%s/", PlatformPropsImpl.os_and_arch);
@@ -201,7 +200,7 @@ public class JNILibLoaderBase {
     if (null != nativeLibraryURI) {
         // We probably have one big-fat jar file, containing java classes
         // and all native platform libraries under 'natives/os.and.arch'!
-        final URI nativeJarURI = JarUtil.getJarFileURI(jarUriRoot_s+jarBasename);
+        final Uri nativeJarURI = JarUtil.getJarFileUri( jarSubUriRoot.getEncoded().concat(jarBasename) );
         try {
             if( TempJarCache.addNativeLibs(classFromJavaJar, nativeJarURI, nativeLibraryPath) ) {
                 ok = true;
@@ -218,7 +217,7 @@ public class JNILibLoaderBase {
     }
     if (!ok) {
         // We assume one slim native jar file per 'os.and.arch'!
-        final URI nativeJarURI = JarUtil.getJarFileURI(jarUriRoot_s+nativeJarBasename);
+        final Uri nativeJarURI = JarUtil.getJarFileUri( jarSubUriRoot.getEncoded().concat(nativeJarBasename) );
 
         if (DEBUG) {
             System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: module: %s -> %s%n", nativeJarBasename, nativeJarURI);
@@ -247,13 +246,13 @@ public class JNILibLoaderBase {
             }
         }
         final String os_and_arch_dot = PlatformPropsImpl.os_and_arch.replace('-', '.');
-        final String nativeJarTagClassName = nativeJarTagPackage + "." + moduleName + "." + os_and_arch_dot + ".TAG" ; // TODO: sync with gluegen-cpptasks-base.xml
+        final String nativeJarTagClassName = nativeJarTagPackage + "." + moduleName + "." + os_and_arch_dot + ".TAG"; // TODO: sync with gluegen-cpptasks-base.xml
         try {
             if(DEBUG) {
                 System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: ClassLoader/TAG: Locating module %s, os.and.arch %s: %s%n",
                         moduleName, os_and_arch_dot, nativeJarTagClassName);
             }
-            final URI nativeJarTagClassJarURI = JarUtil.getJarURI(nativeJarTagClassName, cl);
+            final Uri nativeJarTagClassJarURI = JarUtil.getJarUri(nativeJarTagClassName, cl);
             if (DEBUG) {
                 System.err.printf("JNILibLoaderBase: addNativeJarLibsImpl: ClassLoader/TAG: %s -> %s%n", nativeJarTagClassName, nativeJarTagClassJarURI);
             }
@@ -399,14 +398,14 @@ public class JNILibLoaderBase {
               }
 
               final ClassLoader cl = c.getClassLoader();
-              final URI classJarURI = JarUtil.getJarURI(c.getName(), cl);
-              final String jarName = JarUtil.getJarBasename(classJarURI);
+              final Uri classJarURI = JarUtil.getJarUri(c.getName(), cl);
+              final Uri.Encoded jarName = JarUtil.getJarBasename(classJarURI);
 
               if (jarName == null) {
                   continue;
               }
 
-              final String jarBasename = jarName.substring(0, jarName.indexOf(".jar"));
+              final Uri.Encoded jarBasename = jarName.substring(0, jarName.indexOf(".jar"));
 
               if(DEBUG) {
                   System.err.printf("JNILibLoaderBase: jarBasename: %s%n", jarBasename);
@@ -423,7 +422,8 @@ public class JNILibLoaderBase {
                   }
               }
 
-              final String nativeJarBasename = String.format("%s-natives-%s.jar", jarBasename, PlatformPropsImpl.os_and_arch);
+              final Uri.Encoded nativeJarBasename =
+                      Uri.Encoded.cast( String.format("%s-natives-%s.jar", jarBasename.get(), PlatformPropsImpl.os_and_arch) );
 
               ok = JNILibLoaderBase.addNativeJarLibsImpl(c, classJarURI, jarName, nativeJarBasename);
               if (ok) {
diff --git a/src/java/com/jogamp/common/net/AssetURLContext.java b/src/java/com/jogamp/common/net/AssetURLContext.java
index 2ada3c6..af90c01 100644
--- a/src/java/com/jogamp/common/net/AssetURLContext.java
+++ b/src/java/com/jogamp/common/net/AssetURLContext.java
@@ -185,7 +185,7 @@ public abstract class AssetURLContext implements PiggybackURLContext {
             try {
                 final File file = new File(path);
                 if(file.exists()) {
-                    url = IOUtil.toURISimple(file).toURL();
+                    url = Uri.valueOf(file).toURL();
                     conn = open(url);
                     type = null != conn ? 3 : -1;
                 }
diff --git a/src/java/com/jogamp/common/net/Uri.java b/src/java/com/jogamp/common/net/Uri.java
new file mode 100644
index 0000000..6bafba2
--- /dev/null
+++ b/src/java/com/jogamp/common/net/Uri.java
@@ -0,0 +1,2516 @@
+/**
+ * Copyright 2014 JogAmp Community. All rights reserved.
+ * Copyright 2006, 2010 The Apache Software Foundation.
+ *
+ * This code is derived from the Apache Harmony project's {@code class java.net.URI.Helper},
+ * and has been heavily modified for GlueGen/JogAmp.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the LICENSE.txt file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jogamp.common.net;
+
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.util.StringTokenizer;
+import java.util.regex.Pattern;
+
+import jogamp.common.Debug;
+
+import com.jogamp.common.util.IOUtil;
+import com.jogamp.common.util.PropertyAccess;
+
+/**
+ * This class implements an immutable Uri as defined by <a href="https://tools.ietf.org/html/rfc2396">RFC 2396</a>.
+ * <p>
+ * Character encoding is employed as defined by <a href="https://tools.ietf.org/html/rfc3986">RFC 3986</a>,
+ * see <a href="https://tools.ietf.org/html/rfc3986#section-2.1">RFC 3986 section 2.1</a>,
+ * while multibyte unicode characters are preserved in encoded parts.
+ * </p>
+ *
+ * <pre>
+     1 [scheme:]scheme-specific-part[#fragment]
+     2 [scheme:][//authority]path[?query][#fragment]
+     3 [scheme:][//[user-info@]host[:port]]path[?query][#fragment]
+
+        scheme-specific-part: [//authority]path[?query]
+        authority:            [user-info@]host[:port]
+ * </pre>
+ * <p>
+ * <a href="https://tools.ietf.org/html/rfc3986#section-2.2">RFC 3986 section 2.2</a> <i>Reserved Characters</i> (January 2005)
+ * <table border="1">
+    <tr>
+    <td><code>!</code></td>
+    <td><code>*</code></td>
+    <td><code>'</code></td>
+    <td><code>(</code></td>
+    <td><code>)</code></td>
+    <td><code>;</code></td>
+    <td><code>:</code></td>
+    <td><code>@</code></td>
+    <td><code>&</code></td>
+    <td><code>=</code></td>
+    <td><code>+</code></td>
+    <td><code>$</code></td>
+    <td><code>,</code></td>
+    <td><code>/</code></td>
+    <td><code>?</code></td>
+    <td><code>#</code></td>
+    <td><code>[</code></td>
+    <td><code>]</code></td>
+    </tr>
+ * </table>
+ * </p>
+ * <p>
+ * <a href="https://tools.ietf.org/html/rfc3986#section-2.3">RFC 3986 section 2.3</a> <i>Unreserved Characters</i> (January 2005)
+ * <table border="1">
+    <tr>
+    <td><code>A</code></td>
+    <td><code>B</code></td>
+    <td><code>C</code></td>
+    <td><code>D</code></td>
+    <td><code>E</code></td>
+    <td><code>F</code></td>
+    <td><code>G</code></td>
+    <td><code>H</code></td>
+    <td><code>I</code></td>
+    <td><code>J</code></td>
+    <td><code>K</code></td>
+    <td><code>L</code></td>
+    <td><code>M</code></td>
+    <td><code>N</code></td>
+    <td><code>O</code></td>
+    <td><code>P</code></td>
+    <td><code>Q</code></td>
+    <td><code>R</code></td>
+    <td><code>S</code></td>
+    <td><code>T</code></td>
+    <td><code>U</code></td>
+    <td><code>V</code></td>
+    <td><code>W</code></td>
+    <td><code>X</code></td>
+    <td><code>Y</code></td>
+    <td><code>Z</code></td>
+    </tr>
+    <tr>
+    <td><code>a</code></td>
+    <td><code>b</code></td>
+    <td><code>c</code></td>
+    <td><code>d</code></td>
+    <td><code>e</code></td>
+    <td><code>f</code></td>
+    <td><code>g</code></td>
+    <td><code>h</code></td>
+    <td><code>i</code></td>
+    <td><code>j</code></td>
+    <td><code>k</code></td>
+    <td><code>l</code></td>
+    <td><code>m</code></td>
+    <td><code>n</code></td>
+    <td><code>o</code></td>
+    <td><code>p</code></td>
+    <td><code>q</code></td>
+    <td><code>r</code></td>
+    <td><code>s</code></td>
+    <td><code>t</code></td>
+    <td><code>u</code></td>
+    <td><code>v</code></td>
+    <td><code>w</code></td>
+    <td><code>x</code></td>
+    <td><code>y</code></td>
+    <td><code>z</code></td>
+    </tr>
+    <tr>
+    <td><code>0</code></td>
+    <td><code>1</code></td>
+    <td><code>2</code></td>
+    <td><code>3</code></td>
+    <td><code>4</code></td>
+    <td><code>5</code></td>
+    <td><code>6</code></td>
+    <td><code>7</code></td>
+    <td><code>8</code></td>
+    <td><code>9</code></td>
+    <td><code>-</code></td>
+    <td><code>_</code></td>
+    <td><code>.</code></td>
+    <td><code>~</code></td>
+    </tr>
+ * </table>
+ * </p>
+ * <p>
+ * Other characters in a Uri must be percent encoded.
+ * </p>
+ * @since 2.2.1
+ */
+public class Uri {
+    private static final boolean DEBUG;
+    private static final boolean DEBUG_SHOWFIX;
+
+    static {
+        Debug.initSingleton();
+        DEBUG = IOUtil.DEBUG || Debug.debug("Uri");
+        DEBUG_SHOWFIX = PropertyAccess.isPropertyDefined("jogamp.debug.Uri.ShowFix", true);
+    }
+
+    /**
+     * Usually used to fix a path from a previously contained and opaque Uri,
+     * i.e. {@link #getContainedUri()}.
+     * <p>
+     * Such an opaque Uri w/ erroneous encoding may have been injected via
+     * {@link #valueOf(URI)} and {@link #valueOf(URL)} where the given URL or URI was opaque!
+     * </p>
+     * <p>
+     * This remedies issues when dealing w/ java URI/URL opaque sources,
+     * which do not comply to the spec, i.e. containe un-encoded chars, e.g. ':', '$', ..
+     * </p>
+     */
+    private static final int PARSE_HINT_FIX_PATH = 1 << 0;
+
+    private static final String DIGITS = "0123456789ABCDEF";
+
+    private static final String ENCODING = "UTF8";
+    private static final String MSG_ENCODING_NA = "Charset UTF8 not available";
+    private static final Pattern patternSingleFS = Pattern.compile("/{1}");
+
+    /**
+     * RFC 3986 section 2.3 Unreserved Characters (January 2005)
+     * <p>
+     * {@value} + {@code alphanum}
+     * </p>
+     */
+    public static final String UNRESERVED = "_-.~";
+    // Harmony: _ - ! . ~ ' ( ) *
+
+    private static final String punct = ",;:$&+=";
+    // Harmony: , ; : $ & + =
+
+    /**
+     * RFC 3986 section 2.2 Reserved Characters (January 2005)
+     * <p>
+     * {@value} + {@code alphanum}
+     * </p>
+     */
+    public static final String RESERVED = punct + "!*\'()@/?#[]";
+    // Harmony: , ; : $ & + = ? / [ ] @
+
+    public static final String RESERVED_2 = punct + "!*\'()@/?[]";
+    // Harmony: , ; : $ & + = ? / [ ] @
+
+    // Bug 908, issues w/ windows file path char: $ ^ ~ # [ ]
+    // Windows invalid File characters: * ? " < > |
+
+    /**
+     * Valid charset for RFC 2396 {@code authority}'s {@code user-info},
+     * additional to legal {@code alphanum} characters.
+     * <p>
+     * {@value} + {@code alphanum}
+     * </p>
+     */
+    public static final String USERINFO_LEGAL = UNRESERVED + punct;
+    // Harmony: someLegal = unreserved + punct -> _ - ! . ~ ' ( ) * , ; : $ & + =
+
+    /**
+     * Valid charset for RFC 2396 {@code authority},
+     * additional to legal {@code alphanum} characters.
+     * <p>
+     * {@value} + {@code alphanum}
+     * </p>
+     */
+    public static final String AUTHORITY_LEGAL = "@[]" + USERINFO_LEGAL;
+
+    /**
+     * Valid charset for RFC 2396 {@code path},
+     * additional to legal {@code alphanum} characters.
+     * <p>
+     * {@value} + {@code alphanum}
+     * </p>
+     */
+    public static final String PATH_LEGAL = "/!" + UNRESERVED; // no RESERVED chars but '!',  to allow JAR Uris;
+    // Harmony: "/@" + unreserved + punct -> / @ _ - ! . ~ \ ' ( ) * , ; : $ & + =
+
+    /**
+     * Valid charset for RFC 2396 {@code query},
+     * additional to legal {@code alphanum} characters.
+     * <p>
+     * {@value} + {@code alphanum}
+     * </p>
+     */
+    public static final String QUERY_LEGAL = UNRESERVED + RESERVED_2 + "\\\"";
+    // Harmony: unreserved + reserved + "\\\""
+
+    /**
+     * Valid charset for RFC 2396 {@code scheme-specific-part},
+     * additional to legal {@code alphanum} characters.
+     * <p>
+     * {@value} + {@code alphanum}
+     * </p>
+     */
+    public static final String SSP_LEGAL = QUERY_LEGAL;
+    // Harmony: unreserved + reserved
+
+    /**
+     * Valid charset for RFC 2396 {@code fragment},
+     * additional to legal {@code alphanum} characters.
+     * <p>
+     * {@value} + {@code alphanum}
+     * </p>
+     */
+    public static final String FRAG_LEGAL = UNRESERVED + RESERVED;
+    // Harmony: unreserved + reserved
+
+    /** {@value} */
+    public static final char SCHEME_SEPARATOR = ':';
+    /** {@value} */
+    public static final char QUERY_SEPARATOR = '?';
+    /** {@value} */
+    public static final char FRAGMENT_SEPARATOR = '#';
+    /** {@value} */
+    public static final String FILE_SCHEME = "file";
+    /** {@value} */
+    public static final String HTTP_SCHEME = "http";
+    /** {@value} */
+    public static final String HTTPS_SCHEME = "https";
+    /** {@value} */
+    public static final String JAR_SCHEME = "jar";
+    /** A JAR sub-protocol is separated from the JAR entry w/ this separator {@value}. Even if no class is specified '!/' must follow!. */
+    public static final char JAR_SCHEME_SEPARATOR = '!';
+
+    /**
+     * Immutable RFC3986 encoded string.
+     */
+    public static class Encoded implements Comparable<Encoded>, CharSequence {
+        private final String s;
+
+        /**
+         * Casts the given encoded String by creating a new Encoded instance.
+         * <p>
+         * No encoding will be performed, use with care.
+         * </p>
+         */
+        public static Encoded cast(final String encoded) {
+            return new Encoded(encoded);
+        }
+
+        Encoded(final String encodedString) {
+            this.s = encodedString;
+        }
+
+        /**
+         * Encodes all characters into their hexadecimal value prepended by '%', except:
+         * <ol>
+         *   <li>letters ('a'..'z', 'A'..'Z')</li>
+         *   <li>numbers ('0'..'9')</li>
+         *   <li>characters in the legal-set parameter</li>
+         *   <li> others (unicode characters that are not in
+         *        US-ASCII set, and are not ISO Control or are not ISO Space characters)</li>
+         * </ol>
+         * <p>
+         * Uses {@link Uri#encode(String, String)} for implementation..
+         * </p>
+         *
+         * @param vanilla the string to be encoded
+         * @param legal extended character set, allowed to be preserved in the vanilla string
+         */
+        public Encoded(final String vanilla, final String legal) {
+            this.s = encode(vanilla, legal);
+        }
+
+        public boolean isASCII() { return false; }
+
+        /** Returns the encoded String */
+        public final String get() { return s; }
+
+        /**
+         * Decodes the string argument which is assumed to be encoded in the {@code
+         * x-www-form-urlencoded} MIME content type using the UTF-8 encoding scheme.
+         * <p>
+         *'%' and two following hex digit characters are converted to the
+         * equivalent byte value. All other characters are passed through
+         * unmodified.
+         * </p>
+         * <p>
+         * e.g. "A%20B%20C %24%25" -> "A B C $%"
+         * </p>
+         * <p>
+         * Uses {@link Uri#decode(String)} for implementation..
+         * </p>
+         */
+        public final String decode() { return Uri.decode(s); }
+
+        //
+        // Basic Object / Identity
+        //
+
+        /**
+         * {@inheritDoc}
+         * <p>
+         * Returns the encoded String, same as {@link #get()}.
+         * </p>
+         */
+        @Override
+        public final String toString() { return s; }
+
+        @Override
+        public final int hashCode() { return s.hashCode(); }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @param  o The comparison argument, either a {@link Encoded} or a {@link String}
+         *
+         * @return {@code true} if the given object is equivalent to this instance,
+         *         otherwise {@code false}.
+         *
+         * @see  #compareTo(Encoded)
+         * @see  #equalsIgnoreCase(Encoded)
+         */
+        @Override
+        public final boolean equals(final Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o instanceof Encoded) {
+                return s.equals(((Encoded)o).s);
+            }
+            return s.equals(o);
+        }
+
+        //
+        // CharSequence
+        //
+
+        @Override
+        public final int length() { return s.length(); }
+
+        @Override
+        public final char charAt(final int index) { return s.charAt(index); }
+
+        @Override
+        public final CharSequence subSequence(final int start, final int end) { return s.subSequence(start, end); }
+
+        @Override
+        public final int compareTo(final Encoded o) { return s.compareTo(o.s); }
+
+        //
+        // String derived ..
+        //
+        /** See {@link String#concat(String)}. */
+        public Encoded concat(final Encoded encoded) { return new Encoded(s.concat(encoded.s)); }
+
+        /** See {@link String#substring(int)}. */
+        public final Encoded substring(final int start) { return new Encoded(s.substring(start)); }
+        /** See {@link String#substring(int, int)}. */
+        public final Encoded substring(final int start, final int end) { return new Encoded(s.substring(start, end)); }
+
+        /** See {@link String#indexOf(int)}. */
+        public final int indexOf(final int ch) { return s.indexOf(ch); }
+        /** See {@link String#indexOf(int, int)}. */
+        public final int indexOf(final int ch, final int fromIndex) { return s.indexOf(ch, fromIndex); }
+        /** See {@link String#indexOf(String)}. */
+        public final int indexOf(final String str) { return s.indexOf(str); }
+        /** See {@link String#indexOf(String, int)}. */
+        public final int indexOf(final String str, final int fromIndex) { return s.indexOf(str, fromIndex); }
+
+        /** See {@link String#lastIndexOf(int)}. */
+        public final int lastIndexOf(final int ch) { return s.lastIndexOf(ch); }
+        /** See {@link String#lastIndexOf(int, int)}. */
+        public int lastIndexOf(final int ch, final int fromIndex) { return s.lastIndexOf(ch, fromIndex); }
+        /** See {@link String#lastIndexOf(String)}. */
+        public int lastIndexOf(final String str) { return s.lastIndexOf(str); }
+        /** See {@link String#lastIndexOf(String, int)}. */
+        public int lastIndexOf(final String str, final int fromIndex) { return s.lastIndexOf(str, fromIndex); }
+
+        /** See {@link String#startsWith(String)} */
+        public boolean startsWith(final String prefix) { return s.startsWith(prefix); }
+        /** See {@link String#startsWith(String, int)} */
+        public boolean startsWith(final String prefix, final int toffset) { return s.startsWith(prefix, toffset); }
+        /** See {@link String#endsWith(String)} */
+        public boolean endsWith(final String suffix) { return s.endsWith(suffix); }
+
+        /** See {@link String#equalsIgnoreCase(String)}. */
+        public final boolean equalsIgnoreCase(final Encoded anotherEncoded) { return s.equalsIgnoreCase(anotherEncoded.s); }
+    }
+
+    public static class ASCIIEncoded extends Encoded {
+        /**
+         * Casts the given encoded String by creating a new ASCIIEncoded instance.
+         * <p>
+         * No encoding will be performed, use with care.
+         * </p>
+         */
+        public static ASCIIEncoded cast(final String encoded) {
+            return new ASCIIEncoded(encoded, null);
+        }
+        private ASCIIEncoded(final String encoded, final Object unused) {
+            super(encoded);
+        }
+
+        /**
+         * Other characters, which are Unicode chars that are not US-ASCII, and are
+         * not ISO Control or are not ISO Space chars are not preserved
+         * and encoded into their hexidecimal value prepended by '%'.
+         * <p>
+         * For example: Euro currency symbol -> "%E2%82%AC".
+         * </p>
+         * <p>
+         * Uses {@link Uri#encodeToASCIIString(String)} for implementation.
+         * </p>
+         * @param unicode unencoded input
+         */
+        public ASCIIEncoded(final String unicode) {
+            super(encodeToASCIIString(unicode));
+        }
+        public boolean isASCII() { return true; }
+    }
+
+    private static void encodeChar2UTF8(final StringBuilder buf, final char ch) {
+        final byte[] bytes;
+        try {
+            bytes = new String(new char[] { ch }).getBytes(ENCODING);
+        } catch (final UnsupportedEncodingException e) {
+            throw new RuntimeException(MSG_ENCODING_NA, e);
+        }
+        // FIXME: UTF-8 produces more than one byte ? Optimization might be possible.
+        for (int j = 0; j < bytes.length; j++) {
+            final byte b = bytes[j];
+            buf.append('%');
+            buf.append(DIGITS.charAt( ( b & 0xf0 ) >> 4 ));
+            buf.append(DIGITS.charAt(   b & 0xf         ));
+        }
+    }
+
+    /**
+     * All characters are encoded into their hexadecimal value prepended by '%', except:
+     * <ol>
+     *   <li>letters ('a'..'z', 'A'..'Z')</li>
+     *   <li>numbers ('0'..'9')</li>
+     *   <li>characters in the legal-set parameter</li>
+     *   <li> others (unicode characters that are not in
+     *        US-ASCII set, and are not ISO Control or are not ISO Space characters)</li>
+     * </ol>
+     * <p>
+     * Use {@link #encodeToASCIIString(String)} for US-ASCII encoding.
+     * </p>
+     * <p>
+     * Consider using {@link Encoded#Encoded(String, String)} in APIs
+     * to distinguish encoded from unencoded data by type.
+     * </p>
+     *
+     * @param vanilla the string to be encoded
+     * @param legal extended character set, allowed to be preserved in the vanilla string
+     * @return java.lang.String the converted string
+     */
+    public static String encode(final String vanilla, final String legal) {
+        if( null == vanilla ) {
+            return null;
+        }
+        final StringBuilder buf = new StringBuilder();
+        for (int i = 0; i < vanilla.length(); i++) {
+            final char ch = vanilla.charAt(i);
+            if ( (ch >= 'a' && ch <= 'z') ||
+                 (ch >= 'A' && ch <= 'Z')  ||
+                 (ch >= '0' && ch <= '9')  ||
+                 legal.indexOf(ch) > -1 ||
+                 ( ch > 127 && !Character.isSpaceChar(ch) && !Character.isISOControl(ch) )
+               ) {
+                buf.append(ch);
+            } else {
+                encodeChar2UTF8(buf, ch);
+            }
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Other characters, which are Unicode chars that are not US-ASCII, and are
+     * not ISO Control or are not ISO Space chars are not preserved
+     * and encoded into their hexidecimal value prepended by '%'.
+     * <p>
+     * For example: Euro currency symbol -> "%E2%82%AC".
+     * </p>
+     * <p>
+     * Consider using {@link ASCIIEncoded#ASCIIEncoded(String)} in APIs
+     * to distinguish encoded from unencoded data by type.
+     * </p>
+     * @param unicode string to be converted
+     * @return java.lang.String the converted string
+     */
+    public static String encodeToASCIIString(final String unicode) {
+        final StringBuilder buf = new StringBuilder();
+        for (int i = 0; i < unicode.length(); i++) {
+            final char ch = unicode.charAt(i);
+            if (ch <= 127) {
+                buf.append(ch);
+            } else {
+                encodeChar2UTF8(buf, ch);
+            }
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Safe {@link Encoded#decode()} call on optional {@code encoded} instance.
+     * @param encoded {@link Encoded} instance to be decoded, may be {@code null}.
+     * @return the {@link Encoded#decode() decoded} String or {@code null} if {@code encoded} was {@code null}.
+     */
+    public static String decode(final Encoded encoded) {
+        return null != encoded ? encoded.decode() : null;
+    }
+
+    /**
+     * Decodes the string argument which is assumed to be encoded in the {@code
+     * x-www-form-urlencoded} MIME content type using the UTF-8 encoding scheme.
+     * <p>
+     *'%' and two following hex digit characters are converted to the
+     * equivalent byte value. All other characters are passed through
+     * unmodified.
+     * </p>
+     * <p>
+     * e.g. "A%20B%20C %24%25" -> "A B C $%"
+     * </p>
+     *
+     * @param encoded The encoded string.
+     * @return java.lang.String The decoded version.
+     */
+    public static String decode(final String encoded) {
+        if( null == encoded ) {
+            return null;
+        }
+        final StringBuilder result = new StringBuilder();
+        final byte[] buf = new byte[32];
+        int bufI = 0;
+        for (int i = 0; i < encoded.length();) {
+            final char c = encoded.charAt(i);
+            if (c == '%') {
+                bufI = 0;
+                do {
+                    if (i + 2 >= encoded.length()) {
+                        throw new IllegalArgumentException("missing '%' hex-digits at index "+i);
+                    }
+                    final int d1 = Character.digit(encoded.charAt(i + 1), 16);
+                    final int d2 = Character.digit(encoded.charAt(i + 2), 16);
+                    if (d1 == -1 || d2 == -1) {
+                        throw new IllegalArgumentException("invalid hex-digits at index "+i+": "+encoded.substring(i, i + 3));
+                    }
+                    buf[bufI++] = (byte) ((d1 << 4) + d2);
+                    if( 32 == bufI ) {
+                        appendUTF8(result, buf, bufI);
+                        bufI = 0;
+                    }
+                    i += 3;
+                } while (i < encoded.length() && encoded.charAt(i) == '%');
+                if( 0 < bufI ) {
+                    appendUTF8(result, buf, bufI);
+                }
+            } else {
+                result.append(c);
+                i++;
+            }
+        }
+        return result.toString();
+    }
+    private static void appendUTF8(final StringBuilder sb, final byte[] buf, final int count) {
+        try {
+            sb.append(new String(buf, 0, count, ENCODING));
+        } catch (final UnsupportedEncodingException e) {
+            throw new RuntimeException(MSG_ENCODING_NA, e);
+        }
+    }
+
+    /**
+     * Creates a new Uri instance using the given unencoded arguments.
+     * <p>
+     * This constructor first creates a temporary Uri string from the given unencoded components. This
+     * string will be parsed later on to create the Uri instance.
+     * </p>
+     * <p>
+     * {@code [scheme:]scheme-specific-part[#fragment]}
+     * </p>
+     * <p>
+     * {@code host} and {@code port} <i>may</i> be undefined or invalid within {@code scheme-specific-part}.
+     * </p>
+     *
+     * @param scheme the unencoded scheme part of the Uri.
+     * @param ssp the unencoded scheme-specific-part of the Uri.
+     * @param fragment the unencoded fragment part of the Uri.
+     * @throws URISyntaxException
+     *             if the temporary created string doesn't fit to the
+     *             specification RFC2396 or could not be parsed correctly.
+     */
+    public static Uri create(final String scheme, final String ssp, final String fragment) throws URISyntaxException {
+        if ( emptyString(scheme) && emptyString(ssp) && emptyString(fragment) ) {
+            throw new URISyntaxException("", "all empty parts");
+        }
+        final StringBuilder uri = new StringBuilder();
+        if ( !emptyString(scheme) ) {
+            uri.append(scheme);
+            uri.append(SCHEME_SEPARATOR);
+        }
+        if ( !emptyString(ssp) ) {
+            // QUOTE ILLEGAL CHARACTERS
+            uri.append(encode(ssp, SSP_LEGAL));
+        }
+        if ( !emptyString(fragment) ) {
+            uri.append(FRAGMENT_SEPARATOR);
+            // QUOTE ILLEGAL CHARACTERS
+            uri.append(encode(fragment, FRAG_LEGAL));
+        }
+        return new Uri(new Encoded(uri.toString()), false, 0);
+    }
+
+    /**
+     * Creates a new Uri instance using the given encoded arguments.
+     * <p>
+     * This constructor first creates a temporary Uri string from the given encoded components. This
+     * string will be parsed later on to create the Uri instance.
+     * </p>
+     * <p>
+     * The given encoded components are taken as-is, i.e. no re-encoding will be performed!
+     * However, Uri parsing will re-evaluate encoding of the resulting components.
+     * </p>
+     * <p>
+     * {@code [scheme:]scheme-specific-part[#fragment]}
+     * </p>
+     * <p>
+     * {@code host} and {@code port} <i>may</i> be undefined or invalid within {@code scheme-specific-part}.
+     * </p>
+     *
+     * @param scheme the encoded scheme part of the Uri.
+     * @param ssp the encoded scheme-specific-part of the Uri.
+     * @param fragment the encoded fragment part of the Uri.
+     * @throws URISyntaxException
+     *             if the temporary created string doesn't fit to the
+     *             specification RFC2396 or could not be parsed correctly.
+     */
+    public static Uri create(final Encoded scheme, final Encoded ssp, final Encoded fragment) throws URISyntaxException {
+        if ( emptyString(scheme) && emptyString(ssp) && emptyString(fragment) ) {
+            throw new URISyntaxException("", "all empty parts");
+        }
+        final StringBuilder uri = new StringBuilder();
+        if ( !emptyString(scheme) ) {
+            uri.append(scheme);
+            uri.append(SCHEME_SEPARATOR);
+        }
+        if ( !emptyString(ssp) ) {
+            uri.append(ssp.get());
+        }
+        if ( !emptyString(fragment) ) {
+            uri.append(FRAGMENT_SEPARATOR);
+            uri.append(fragment.get());
+        }
+        return new Uri(new Encoded(uri.toString()), false, 0);
+    }
+
+    /**
+     * Creates a new Uri instance using the given unencoded arguments.
+     * <p>
+     * This constructor first creates a temporary Uri string from the given unencoded components. This
+     * string will be parsed later on to create the Uri instance.
+     * </p>
+     * <p>
+     * {@code [scheme:][user-info@]host[:port][path][?query][#fragment]}
+     * </p>
+     * <p>
+     * {@code host} and {@code port} <i>must</i> be defined and valid, if any {@code authority} components are defined,
+     * i.e. {@code user-info}, {@code host} or {@code port}.
+     * </p>
+     *
+     * @param scheme the unencoded scheme part of the Uri.
+     * @param userinfo the unencoded user information of the Uri for authentication and authorization, {@code null} for undefined.
+     * @param host the unencoded host name of the Uri, {@code null} for undefined.
+     * @param port the port number of the Uri, -1 for undefined.
+     * @param path the unencoded path to the resource on the host.
+     * @param query the unencoded query part of the Uri to specify parameters for the resource.
+     * @param fragment the unencoded fragment part of the Uri.
+     * @throws URISyntaxException
+     *             if the temporary created string doesn't fit to the
+     *             specification RFC2396 or could not be parsed correctly.
+     */
+    public static Uri create (final String scheme, final String userinfo, String host, final int port,
+                              final String path, final String query, final String fragment) throws URISyntaxException {
+        if ( emptyString(scheme) && emptyString(userinfo) && emptyString(host) && emptyString(path) &&
+             emptyString(query)  && emptyString(fragment) ) {
+            throw new URISyntaxException("", "all empty parts");
+        }
+
+        if ( !emptyString(scheme) && !emptyString(path) && path.length() > 0 && path.charAt(0) != '/') {
+            throw new URISyntaxException(path, "path doesn't start with '/'");
+        }
+
+        final StringBuilder uri = new StringBuilder();
+        if ( !emptyString(scheme) ) {
+            uri.append(scheme);
+            uri.append(SCHEME_SEPARATOR);
+        }
+
+        if ( !emptyString(userinfo) || !emptyString(host) || port != -1) {
+            uri.append("//");
+        }
+
+        if ( !emptyString(userinfo) ) {
+            // QUOTE ILLEGAL CHARACTERS in userinfo
+            uri.append(encode(userinfo, USERINFO_LEGAL));
+            uri.append('@');
+        }
+
+        if ( !emptyString(host) ) {
+            // check for ipv6 addresses that hasn't been enclosed
+            // in square brackets
+            if (host.indexOf(SCHEME_SEPARATOR) != -1 && host.indexOf(']') == -1
+                    && host.indexOf('[') == -1) {
+                host = "[" + host + "]";
+            }
+            uri.append(host);
+        }
+
+        if ( port != -1 ) {
+            uri.append(SCHEME_SEPARATOR);
+            uri.append(port);
+        }
+
+        if ( !emptyString(path) ) {
+            // QUOTE ILLEGAL CHARS
+            uri.append(encode(path, PATH_LEGAL));
+        }
+
+        if ( !emptyString(query) ) {
+            uri.append(QUERY_SEPARATOR);
+            // QUOTE ILLEGAL CHARS
+            uri.append(encode(query, QUERY_LEGAL));
+        }
+
+        if ( !emptyString(fragment) ) {
+            // QUOTE ILLEGAL CHARS
+            uri.append(FRAGMENT_SEPARATOR);
+            uri.append(encode(fragment, FRAG_LEGAL));
+        }
+        return new Uri(new Encoded(uri.toString()), true, 0);
+    }
+
+    /**
+     * Creates a new Uri instance using the given encoded arguments.
+     * <p>
+     * This constructor first creates a temporary Uri string from the given encoded components. This
+     * string will be parsed later on to create the Uri instance.
+     * </p>
+     * <p>
+     * The given encoded components are taken as-is, i.e. no re-encoding will be performed!
+     * However, Uri parsing will re-evaluate encoding of the resulting components.
+     * </p>
+     * <p>
+     * {@code [scheme:][user-info@]host[:port][path][?query][#fragment]}
+     * </p>
+     * <p>
+     * {@code host} and {@code port} <i>must</i> be defined and valid, if any {@code authority} components are defined,
+     * i.e. {@code user-info}, {@code host} or {@code port}.
+     * </p>
+     *
+     * @param scheme the encoded scheme part of the Uri.
+     * @param userinfo the encoded user information of the Uri for authentication and authorization, {@code null} for undefined.
+     * @param host the encoded host name of the Uri, {@code null} for undefined.
+     * @param port the port number of the Uri, -1 for undefined.
+     * @param path the encoded path to the resource on the host.
+     * @param query the encoded query part of the Uri to specify parameters for the resource.
+     * @param fragment the encoded fragment part of the Uri.
+     * @throws URISyntaxException
+     *             if the temporary created string doesn't fit to the
+     *             specification RFC2396 or could not be parsed correctly.
+     */
+    public static Uri create (final Encoded scheme, final Encoded userinfo, final Encoded host, final int port,
+                              final Encoded path, final Encoded query, final Encoded fragment) throws URISyntaxException {
+        if ( emptyString(scheme) && emptyString(userinfo) && emptyString(host) && emptyString(path) &&
+             emptyString(query)  && emptyString(fragment) ) {
+            throw new URISyntaxException("", "all empty parts");
+        }
+
+        if ( !emptyString(scheme) && !emptyString(path) && path.length() > 0 && path.charAt(0) != '/') {
+            throw new URISyntaxException(path.get(), "path doesn't start with '/'");
+        }
+
+        final StringBuilder uri = new StringBuilder();
+        if ( !emptyString(scheme) ) {
+            uri.append(scheme);
+            uri.append(SCHEME_SEPARATOR);
+        }
+
+        if ( !emptyString(userinfo) || !emptyString(host) || port != -1) {
+            uri.append("//");
+        }
+
+        if ( !emptyString(userinfo) ) {
+            uri.append(userinfo.get());
+            uri.append('@');
+        }
+
+        if ( !emptyString(host) ) {
+            uri.append(host.get());
+        }
+
+        if ( port != -1 ) {
+            uri.append(SCHEME_SEPARATOR);
+            uri.append(port);
+        }
+
+        if ( !emptyString(path) ) {
+            uri.append(path.get());
+        }
+
+        if ( !emptyString(query) ) {
+            uri.append(QUERY_SEPARATOR);
+            uri.append(query.get());
+        }
+
+        if ( !emptyString(fragment) ) {
+            uri.append(FRAGMENT_SEPARATOR);
+            uri.append(fragment.get());
+        }
+        return new Uri(new Encoded(uri.toString()), true, 0);
+    }
+
+    /**
+     * Creates a new Uri instance using the given unencoded arguments.
+     * <p>
+     * This constructor first creates a temporary Uri string from the given unencoded components. This
+     * string will be parsed later on to create the Uri instance.
+     * </p>
+     * <p>
+     * {@code [scheme:]host[path][#fragment]}
+     * </p>
+     * <p>
+     * {@code host} <i>must</i> be valid, if defined.
+     * </p>
+     *
+     * @param scheme the unencoded scheme part of the Uri.
+     * @param host the unencoded host name of the Uri.
+     * @param path the unencoded path to the resource on the host.
+     * @param fragment the unencoded fragment part of the Uri.
+     * @throws URISyntaxException
+     *             if the temporary created string doesn't fit to the
+     *             specification RFC2396 or could not be parsed correctly.
+     */
+    public static Uri create(final String scheme, final String host, final String path, final String fragment) throws URISyntaxException {
+        return create(scheme, null, host, -1, path, null, fragment);
+    }
+
+    /**
+     * Creates a new Uri instance using the given encoded arguments.
+     * <p>
+     * This constructor first creates a temporary Uri string from the given encoded components. This
+     * string will be parsed later on to create the Uri instance.
+     * </p>
+     * <p>
+     * The given encoded components are taken as-is, i.e. no re-encoding will be performed!
+     * However, Uri parsing will re-evaluate encoding of the resulting components.
+     * </p>
+     * <p>
+     * {@code [scheme:]host[path][#fragment]}
+     * </p>
+     * <p>
+     * {@code host} <i>must</i> be valid, if defined.
+     * </p>
+     *
+     * @param scheme the encoded scheme part of the Uri.
+     * @param host the encoded host name of the Uri.
+     * @param path the encoded path to the resource on the host.
+     * @param fragment the encoded fragment part of the Uri.
+     * @throws URISyntaxException
+     *             if the temporary created string doesn't fit to the
+     *             specification RFC2396 or could not be parsed correctly.
+     */
+    public static Uri create(final Encoded scheme, final Encoded host, final Encoded path, final Encoded fragment) throws URISyntaxException {
+        return create(scheme, null, host, -1, path, null, fragment);
+    }
+
+    /**
+     * Creates a new Uri instance using the given unencoded arguments.
+     * <p>
+     * This constructor first creates a temporary Uri string from the given unencoded components. This
+     * string will be parsed later on to create the Uri instance.
+     * </p>
+     * <p>
+     * {@code [scheme:][//authority][path][?query][#fragment]}
+     * </p>
+     * <p>
+     * {@code host} and {@code port} <i>may</i> be undefined or invalid, in the optional {@code authority}.
+     * </p>
+     *
+     * @param scheme the unencoded scheme part of the Uri.
+     * @param authority the unencoded authority part of the Uri.
+     * @param path the unencoded path to the resource on the host.
+     * @param query the unencoded query part of the Uri to specify parameters for the resource.
+     * @param fragment the unencoded fragment part of the Uri.
+     *
+     * @throws URISyntaxException
+     *             if the temporary created string doesn't fit to the
+     *             specification RFC2396 or could not be parsed correctly.
+     */
+    public static Uri create(final String scheme, final String authority, final String path, final String query, final String fragment) throws URISyntaxException {
+        if ( emptyString(scheme) && emptyString(authority) && emptyString(path) &&
+             emptyString(query)  && emptyString(fragment) ) {
+            throw new URISyntaxException("", "all empty parts");
+        }
+        if ( !emptyString(scheme) && !emptyString(path) && path.length() > 0 && path.charAt(0) != '/') {
+            throw new URISyntaxException(path, "path doesn't start with '/'");
+        }
+
+        final StringBuilder uri = new StringBuilder();
+        if ( !emptyString(scheme) ) {
+            uri.append(scheme);
+            uri.append(SCHEME_SEPARATOR);
+        }
+        if ( !emptyString(authority) ) {
+            uri.append("//");
+            // QUOTE ILLEGAL CHARS
+            uri.append(encode(authority, AUTHORITY_LEGAL));
+        }
+
+        if ( !emptyString(path) ) {
+            // QUOTE ILLEGAL CHARS
+            uri.append(encode(path, PATH_LEGAL));
+        }
+        if ( !emptyString(query) ) {
+            // QUOTE ILLEGAL CHARS
+            uri.append(QUERY_SEPARATOR);
+            uri.append(encode(query, QUERY_LEGAL));
+        }
+        if ( !emptyString(fragment) ) {
+            // QUOTE ILLEGAL CHARS
+            uri.append(FRAGMENT_SEPARATOR);
+            uri.append(encode(fragment, FRAG_LEGAL));
+        }
+        return new Uri(new Encoded(uri.toString()), false, 0);
+    }
+
+    /**
+     * Creates a new Uri instance using the given encoded arguments.
+     * <p>
+     * This constructor first creates a temporary Uri string from the given encoded encoded components. This
+     * string will be parsed later on to create the Uri instance.
+     * </p>
+     * <p>
+     * The given encoded components are taken as-is, i.e. no re-encoding will be performed!
+     * However, Uri parsing will re-evaluate encoding of the resulting components.
+     * </p>
+     * <p>
+     * {@code [scheme:][//authority][path][?query][#fragment]}
+     * </p>
+     * <p>
+     * {@code host} and {@code port} <i>may</i> be undefined or invalid, in the optional {@code authority}.
+     * </p>
+     *
+     * @param scheme the encoded scheme part of the Uri.
+     * @param authority the encoded authority part of the Uri.
+     * @param path the encoded path to the resource on the host.
+     * @param query the encoded query part of the Uri to specify parameters for the resource.
+     * @param fragment the encoded fragment part of the Uri.
+     *
+     * @throws URISyntaxException
+     *             if the temporary created string doesn't fit to the
+     *             specification RFC2396 or could not be parsed correctly.
+     */
+    public static Uri create(final Encoded scheme, final Encoded authority, final Encoded path, final Encoded query, final Encoded fragment) throws URISyntaxException {
+        if ( emptyString(scheme) && emptyString(authority) && emptyString(path) &&
+             emptyString(query)  && emptyString(fragment) ) {
+            throw new URISyntaxException("", "all empty parts");
+        }
+        if ( !emptyString(scheme) && !emptyString(path) && path.length() > 0 && path.charAt(0) != '/') {
+            throw new URISyntaxException(path.get(), "path doesn't start with '/'");
+        }
+
+        final StringBuilder uri = new StringBuilder();
+        if ( !emptyString(scheme) ) {
+            uri.append(scheme);
+            uri.append(SCHEME_SEPARATOR);
+        }
+        if ( !emptyString(authority) ) {
+            uri.append("//");
+            uri.append(authority.get());
+        }
+
+        if ( !emptyString(path) ) {
+            uri.append(path.get());
+        }
+        if ( !emptyString(query) ) {
+            uri.append(QUERY_SEPARATOR);
+            uri.append(query.get());
+        }
+        if ( !emptyString(fragment) ) {
+            uri.append(FRAGMENT_SEPARATOR);
+            uri.append(fragment.get());
+        }
+        return new Uri(new Encoded(uri.toString()), false, 0);
+    }
+
+    /**
+     * Casts the given encoded String to a {@link Encoded#cast(String) new Encoded instance}
+     * used to create the resulting Uri instance via {@link #Uri(Encoded)}.
+     * <p>
+     * No encoding will be performed on the given {@code encodedUri}, use with care.
+     * </p>
+     * @throws URISyntaxException
+     */
+    public static Uri cast(final String encodedUri) throws URISyntaxException {
+        return new Uri(Encoded.cast(encodedUri));
+    }
+
+    /**
+     * Creates a new Uri instance using the given file-path argument.
+     * <p>
+     * This constructor first creates a temporary Uri string from the given components. This
+     * string will be parsed later on to create the Uri instance.
+     * </p>
+     * <p>
+     * {@code file:path}
+     * </p>
+     *
+     * @param path the unencoded path of the {@code file} {@code schema}.
+     * @throws URISyntaxException
+     *             if the temporary created string doesn't fit to the
+     *             specification RFC2396 or could not be parsed correctly.
+     */
+    public static Uri valueOfFilepath(final String path) throws URISyntaxException {
+        if ( emptyString(path) ) {
+            throw new URISyntaxException("", "empty path");
+        }
+        if ( path.charAt(0) != '/' ) {
+            throw new URISyntaxException(path, "path doesn't start with '/'");
+        }
+
+        final StringBuilder uri = new StringBuilder();
+        uri.append(FILE_SCHEME);
+        uri.append(SCHEME_SEPARATOR);
+
+        // QUOTE ILLEGAL CHARS
+        uri.append(encode(path, PATH_LEGAL));
+
+        return new Uri(new Encoded(uri.toString()), false, 0);
+    }
+
+    /**
+     * Creates a new Uri instance using the given File instance.
+     * <p>
+     * This constructor first creates a temporary Uri string from the given components. This
+     * string will be parsed later on to create the Uri instance.
+     * </p>
+     * <p>
+     * {@code file:path}
+     * </p>
+     *
+     * @param file using {@link IOUtil#slashify(String, boolean, boolean) slashified} {@link File#getAbsolutePath() absolute-path}
+     *             for the path of the {@code file} {@code schema}, utilizing {@link #valueOfFilepath(String)}.
+     * @throws URISyntaxException
+     *             if the temporary created string doesn't fit to the
+     *             specification RFC2396 or could not be parsed correctly.
+     */
+    public static Uri valueOf(final File file) throws URISyntaxException {
+        return Uri.valueOfFilepath(IOUtil.slashify(file.getAbsolutePath(), true, file.isDirectory()));
+    }
+
+    /**
+     * Creates a new Uri instance using the given URI instance.
+     * <p>
+     * Re-encoding will be performed if the given URI is {@link URI#isOpaque() not opaque}.
+     * </p>
+     * <p>
+     * See {@link #PARSE_HINT_FIX_PATH} for issues of injecting opaque URLs.
+     * </p>
+     *
+     * @param uri A given URI instance
+     * @throws URISyntaxException
+     *             if the temporary created string doesn't fit to the
+     *             specification RFC2396 or could not be parsed correctly.
+     */
+    public static Uri valueOf(final java.net.URI uri) throws URISyntaxException {
+        if( uri.isOpaque()) {
+            // opaque, without host validation.
+            // Note: This may induce encoding errors of authority and path, see {@link #PARSE_HINT_FIX_PATH}
+            return new Uri(new Encoded( uri.toString() ), false, 0);
+        } else {
+            // with host validation if authority is defined
+            return Uri.create(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(),
+                              uri.getPath(), uri.getQuery(), uri.getFragment());
+        }
+    }
+
+    /**
+     * Creates a new Uri instance using the given URL instance,
+     * convenient wrapper for {@link #valueOf(URI)} and {@link URL#toURI()}.
+     * <p>
+     * Re-encoding will be performed if the given URL is {@link URI#isOpaque() not opaque}, see {@link #valueOf(URI)}.
+     * </p>
+     * <p>
+     * See {@link #PARSE_HINT_FIX_PATH} for issues of injecting opaque URLs.
+     * </p>
+     *
+     * @param url A given URL instance
+     *
+     * @throws URISyntaxException
+     *             if the temporary created string doesn't fit to the
+     *             specification RFC2396 or could not be parsed correctly.
+     */
+    public static Uri valueOf(final java.net.URL url) throws URISyntaxException {
+        return valueOf(url.toURI());
+    }
+
+    //
+    // All string fields are encoded!
+    //
+
+    /** Encoded input string used at construction, never {@code null}. */
+    public final Encoded input;
+
+    private final Object lazyLock = new Object();
+
+    /** Encoded input string used at construction, in US-ASCII encoding. */
+    private ASCIIEncoded inputASCII;
+
+    private int hash;
+
+    /** Encoded {@code scheme}, {@code null} if undefined. */
+    public final Encoded scheme;
+
+    /** Encoded {@code scheme-specific-part}, never {@code null}. */
+    public final Encoded schemeSpecificPart;
+    /** Encoded {@code path} part of {@code scheme-specific-part}, never {@code null}. */
+    public final Encoded path;
+
+    /** Indicating whether {@code authority} part is defined or not. */
+    public final boolean hasAuthority;
+    /** Encoded {@code authority} part of {@code scheme-specific-part}, {@code null} if undefined. */
+    public final Encoded authority;
+    /** Encoded {@code userinfo} part of {@code authority} and {@code scheme-specific-part}, {@code null} if undefined. */
+    public final Encoded userInfo; // part of authority
+    /** Encoded {@code host} part of {@code authority} and {@code scheme-specific-part}, {@code null} if undefined. */
+    public final Encoded host;     // part of authority
+    /** Encoded {@code port} part of {@code authority} and {@code scheme-specific-part}, {@code -1} if undefined. */
+    public final int port;        // part of authority
+
+    /** Encoded {@code query} part of {@code scheme-specific-part}, {@code null} if undefined. */
+    public final Encoded query;
+
+    /** Encoded {@code fragment}, {@code null} if undefined. */
+    public final Encoded fragment;
+
+    /** Indicating whether this Uri is absolute, i.e. has a {@code scheme} and hence an absolute {@code scheme-specific-part}. */
+    public final boolean absolute;
+
+    /**
+     * Indicating whether this Uri is opaque, i.e. non-hierarchical {@code scheme-specific-part}.
+     * <p>
+     * An opaque Uri has no {@code scheme-specific-part} being parsed,
+     * i.e. {@code path}, {@code query} and {@code authority} are {@code null}.
+     * </p>
+     */
+    public final boolean opaque;
+
+    /**
+     * Creates a new Uri instance according to the given encoded string {@code uri}.
+     *
+     * @param uri the RFC3986 encoded RFC2396 Uri representation to be parsed into a Uri object
+     * @throws URISyntaxException
+     *             if the given string {@code uri} doesn't fit to the
+     *             specification RFC2396 and RFC3986 or could not be parsed correctly.
+     */
+    public Uri(final Encoded uri) throws URISyntaxException {
+        this(uri, false, 0);
+    }
+
+    /** Returns true, if this instance is a {@code file} {@code scheme}, otherwise false. */
+    public final boolean isFileScheme() {
+        return FILE_SCHEME.equals( scheme.get() );
+    }
+
+    /**
+     * Returns the encoded {@link #input}, never {@code null}.
+     */
+    public final Encoded getEncoded() {
+        return input;
+    }
+
+    /**
+     * Returns the encoded {@link #input} as String, never {@code null}, same as {@link #getEncoded()}.
+     */
+    @Override
+    public final String toString() {
+        return input.get();
+    }
+
+    /**
+     * Returns the encoded {@link #input} encoded in US-ASCII.
+     */
+    public ASCIIEncoded toASCIIString() {
+        synchronized( lazyLock ) {
+            if( null == inputASCII ) {
+                inputASCII = new ASCIIEncoded(input.get());
+            }
+            return inputASCII;
+        }
+    }
+
+    /**
+     * Returns a new {@link URI} instance using the encoded {@link #input} string, {@code new URI(uri.input)},
+     * i.e. no re-encoding will be performed.
+     * @see #toURIReencoded(boolean)
+     * @see #valueOf(URI)
+     */
+    public final java.net.URI toURI() {
+        try {
+            return new java.net.URI(input.get());
+        } catch (final URISyntaxException e) {
+            throw new Error(e); // Can't happen
+        }
+    }
+
+    /**
+     * Returns a new {@link URI} instance based upon this instance.
+     * <p>
+     * All Uri parts of this instance will be decoded
+     * and encoded by the URI constructor, i.e. re-encoding will be performed.
+     * </p>
+     *
+     * @throws URISyntaxException
+     *             if the given string {@code uri} doesn't fit to the
+     *             specification RFC2396 or could not be parsed correctly.
+     * @see #toURI()
+     * @see #valueOf(URI)
+     */
+    public final java.net.URI toURIReencoded() throws URISyntaxException {
+        final java.net.URI recomposedURI;
+        if( opaque ) {
+            // opaque, without host validation
+            recomposedURI = new java.net.URI(decode(scheme), decode(schemeSpecificPart), decode(fragment));
+        } else if( null != host ) {
+            // with host validation
+            recomposedURI = new java.net.URI(decode(scheme), decode(userInfo), decode(host), port,
+                                             decode(path), decode(query), decode(fragment));
+        } else {
+            // without host validation
+            recomposedURI = new java.net.URI(decode(scheme), decode(authority),
+                                             decode(path), decode(query), decode(fragment));
+        }
+        return recomposedURI;
+    }
+
+
+    /**
+     * Returns a new {@link URL} instance using the encoded {@link #input} string, {@code new URL(uri.input)},
+     * i.e. no re-encoding will be performed.
+     * @throws MalformedURLException
+     *             if an error occurs while creating the URL or no protocol
+     *             handler could be found.
+     */
+    public final java.net.URL toURL() throws MalformedURLException {
+        if (!absolute) {
+            throw new IllegalArgumentException("Cannot convert relative Uri: "+input);
+        }
+        return new java.net.URL(input.get());
+    }
+
+    /**
+     * If this instance {@link #isFileScheme() is a file scheme},
+     * implementation decodes <i>[ "//"+{@link #authority} ] + {@link #path}</i>,<br>
+     * then it processes the result if {@link File#separatorChar} <code> == '\\'</code>
+     * as follows:
+     * <ul>
+     *   <li>slash -> backslash</li>
+     *   <li>drop a starting single backslash, preserving windows UNC</li>
+     * </ul>
+     * and returns the resulting new {@link File} instance.
+     * <p>
+     * Otherwise implementation returns {@code null}.
+     * </p>
+     */
+    public final File toFile() {
+        if( isFileScheme() && !emptyString(path) ) {
+            final String authorityS;
+            if( null == authority ) {
+                authorityS = "";
+            } else {
+                authorityS = "//"+authority.decode();
+            }
+            final String path = authorityS+this.path.decode();
+            if( File.separator.equals("\\") ) {
+                final String r = patternSingleFS.matcher(path).replaceAll("\\\\");
+                if( r.startsWith("\\") && !r.startsWith("\\\\") ) { // '\\\\' denotes UNC hostname, which shall not be cut-off
+                    return new File(r.substring(1));
+                } else {
+                    return new File(r);
+                }
+            }
+            return new File(path);
+        }
+        return null;
+    }
+
+    /**
+     * If this instance's {@link #schemeSpecificPart} contains a Uri itself, a sub-Uri,
+     * return {@link #schemeSpecificPart} + {@code #} {@link #fragment} via it's own new Uri instance.
+     * <p>
+     * In case this Uri is a {@code jar-scheme}, the {@code query} is omitted,
+     * since it shall be invalid for {@code jar-schemes} anyway.
+     * </p>
+     * <p>
+     * Otherwise method returns {@code null}.
+     * </p>
+     * <pre>
+     * Example 1:
+     *     This instance: <code>jar:<i>scheme2</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
+     *     Returned Uri:  <code><i>scheme2</i>:/some/path/gluegen-rt.jar</code>
+     *
+     * Example 2:
+     *     This instance: <code>jar:<i>scheme2</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class?lala=01#fragment</code>
+     *     Returned Uri:  <code><i>scheme2</i>:/some/path/gluegen-rt.jar#fragment</code>
+     *
+     * Example 3:
+     *     This instance: <code>scheme1:<i>scheme2</i>:/some/path/gluegen-rt.jar!/?lala=01#fragment</code>
+     *     Returned Uri:  <code><i>scheme2</i>:/some/path/gluegen-rt.jar?lala=01#fragment</code>
+     * </pre>
+     * @throws URISyntaxException if this Uri is a container Uri and does not comply with the container spec, i.e. a JAR Uri
+     */
+    public final Uri getContainedUri() throws URISyntaxException {
+        if( !emptyString(schemeSpecificPart) ) {
+            final StringBuilder sb = new StringBuilder();
+
+            if( scheme.equals(JAR_SCHEME) ) {
+                final int idx = schemeSpecificPart.lastIndexOf(JAR_SCHEME_SEPARATOR);
+                if (0 > idx) {
+                    throw new URISyntaxException(input.get(), "missing jar separator");
+                }
+                sb.append( schemeSpecificPart.get().substring(0, idx) ); // exclude '!/'
+            } else {
+                sb.append( schemeSpecificPart.get() );
+            }
+            if ( !emptyString(fragment) ) {
+                sb.append(FRAGMENT_SEPARATOR);
+                sb.append(fragment);
+            }
+            try {
+                final int parseHints = opaque ? PARSE_HINT_FIX_PATH : 0;
+                final Uri res = new Uri(new Encoded(sb.toString()), false, parseHints);
+                if( null != res.scheme ) {
+                    return res;
+                }
+            } catch(final URISyntaxException e) {
+                // OK, does not contain uri
+                if( DEBUG ) {
+                    System.err.println("Caught "+e.getClass().getSimpleName()+": "+e.getMessage());
+                    e.printStackTrace();
+                }
+            }
+        }
+        return null;
+    }
+
+    private static final boolean cutoffLastPathSegementImpl(final StringBuilder pathBuf,
+                                                            final boolean cutoffFile,
+                                                            final boolean cutoffDir,
+                                                            final Encoded appendPath) throws URISyntaxException {
+        final boolean cleaned;
+        {// clean-up existing path
+            final String pathS = pathBuf.toString();
+            if( 0 > pathS.indexOf("/") && emptyString(appendPath) ) {
+                return false; // nothing to cut-off
+            }
+            pathBuf.setLength(0);
+            pathBuf.append( IOUtil.cleanPathString( pathS ) );
+            cleaned = pathBuf.length() != pathS.length();
+        }
+
+        {// cut-off file or last dir-segment
+            final String pathS = pathBuf.toString();
+            final int jarSepIdx = pathS.lastIndexOf(JAR_SCHEME_SEPARATOR);
+            final int e = pathS.lastIndexOf("/");
+            if( 0 > jarSepIdx || e - 1 > jarSepIdx ) { // stop at jar-separator '!/', if exist
+                if( cutoffFile && e < pathS.length() - 1 ) {
+                    // cut-off file
+                    pathBuf.setLength(0);
+                    pathBuf.append( pathS.substring(0, e+1) );
+                } else if( cutoffDir ) {
+                    // cut-off dir-segment
+                    final int p = pathS.lastIndexOf("/", e-1);
+                    if( p >= 0 ) {
+                        pathBuf.setLength(0);
+                        pathBuf.append( pathS.substring(0, p+1) );
+                    } // else keep
+                } // else keep
+            }
+            final boolean cutoff = pathBuf.length() != pathS.length();
+            if( !cutoff && ( cutoffDir || !cleaned ) && emptyString(appendPath) ) {
+                return false; // no modifications!
+            }
+        }
+        if( !emptyString(appendPath) ) {
+            pathBuf.append(appendPath.get());
+            // 2nd round of cleaning!
+            final String pathS = pathBuf.toString();
+            pathBuf.setLength(0);
+            pathBuf.append( IOUtil.cleanPathString( pathS ) );
+        }
+        return true; // continue processing w/ buffer
+    }
+    private final Uri cutoffLastPathSegementImpl(final boolean cutoffFile, final boolean cutoffDir, final Encoded appendPath) throws URISyntaxException {
+        if( opaque ) {
+            if( emptyString(schemeSpecificPart) ) {
+                 // nothing to cut-off
+                if( !emptyString(appendPath) )  {
+                    return Uri.create(scheme, appendPath, fragment);
+                } else {
+                    return null;
+                }
+            }
+            final StringBuilder sspBuf = new StringBuilder(); // without path!
+
+            // save optional query in scheme-specific-part
+            final Encoded queryTemp;
+            final int queryI = schemeSpecificPart.lastIndexOf(QUERY_SEPARATOR);
+            if( queryI >= 0 ) {
+                queryTemp = schemeSpecificPart.substring(queryI+1);
+                sspBuf.append( schemeSpecificPart.substring(0, queryI).get() );
+            } else {
+                queryTemp = null;
+                sspBuf.append( schemeSpecificPart.get() );
+            }
+
+            if( !cutoffLastPathSegementImpl(sspBuf, cutoffFile, cutoffDir, appendPath) ) {
+                return null; // no modifications
+            }
+
+            if ( !emptyString(queryTemp)  ) {
+                sspBuf.append(QUERY_SEPARATOR);
+                sspBuf.append( queryTemp.get() );
+            }
+
+            // without host validation if authority is defined
+            return Uri.create(scheme, new Encoded(sspBuf.toString()), fragment);
+        } else {
+            if( emptyString(path) ) {
+                return null; // nothing to cut-off
+            }
+            final StringBuilder pathBuf = new StringBuilder();
+            pathBuf.append( path.get() );
+
+            if( !cutoffLastPathSegementImpl(pathBuf, cutoffFile, cutoffDir, appendPath) ) {
+                return null; // no modifications
+            }
+
+            // with host validation if authority is defined
+            return Uri.create(scheme, userInfo, host, port, new Encoded(pathBuf.toString()), query, fragment);
+        }
+    }
+
+    /**
+     * {@link IOUtil#cleanPathString(String) Normalizes} this Uri's path and return the
+     * {@link IOUtil#cleanPathString(String) normalized} form if it differs, otherwise {@code this} instance.
+     * <p>
+     * <pre>
+     * Example-1:
+     *     This instance  : <code>jar:http://some/path/../gluegen-rt.jar!/com/Test.class?arg=1#frag</code>
+     *     Normalized     : <code>jar:http://some/gluegen-rt.jar!/com/Test.class?arg=1#frag</code>
+     *
+     * Example-2:
+     *     This instance  : <code>http://some/path/../gluegen-rt.jar?arg=1#frag</code>
+     *     Normalized     : <code>http://some/gluegen-rt.jar?arg=1#frag</code>
+     * </pre>
+     * </p>
+     */
+    public final Uri getNormalized() {
+        try {
+            final Uri res = cutoffLastPathSegementImpl(false, false, null);
+            return null != res ? res : this;
+        } catch (final URISyntaxException e) {
+            if( DEBUG ) {
+                System.err.println("Caught "+e.getClass().getSimpleName()+": "+e.getMessage());
+                e.printStackTrace();
+            }
+            return this;
+        }
+    }
+
+    /**
+     * Returns this Uri's directory Uri.
+     * <p>
+     * This Uri path will be {@link IOUtil#cleanPathString(String) normalized} before returning the directory.
+     * </p>
+     * <p>
+     * If this Uri's directory cannot be found, or already denotes a directory, method returns {@code this} instance.
+     * </p>
+     * <p>
+     * <pre>
+     * Example-1:
+     *     this-uri: http:/some/path/gluegen-rt.jar?arg=1#frag
+     *     result:   http:/some/path/?arg=1#frag
+     *
+     * Example-2:
+     *     this-uri: file:/some/path/
+     *     result:   file:/some/path/
+     *
+     * Example-3:
+     *     this-uri: file:/some/path/lala/lili/../../hello.txt
+     *     result:   file:/some/path/
+     * </pre>
+     * </p>
+     * @throws URISyntaxException if the new string {@code uri} doesn't fit to the
+     *                            specification RFC2396 and RFC3986 or could not be parsed correctly.
+     */
+    public Uri getDirectory() {
+        try {
+            final Uri res = cutoffLastPathSegementImpl(true, false, null);
+            return null != res ? res : this;
+        } catch (final URISyntaxException e) {
+            if( DEBUG ) {
+                System.err.println("Caught "+e.getClass().getSimpleName()+": "+e.getMessage());
+                e.printStackTrace();
+            }
+            return this;
+        }
+    }
+
+    /**
+     * Returns this Uri's parent directory Uri..
+     * <p>
+     * This Uri path will be {@link IOUtil#cleanPathString(String) normalized} before traversing up one directory.
+     * </p>
+     * <p>
+     * If a parent folder cannot be found, method returns {@code null}.
+     * </p>
+     * <p>
+     * <pre>
+     * Example-1:
+     *     This instance  : <code>jar:http://some/path/gluegen-rt.jar!/com/Test.class?arg=1#frag</code>
+     *     Returned Uri #1: <code>jar:http://some/path/gluegen-rt.jar!/com/?arg=1#frag</code>
+     *     Returned Uri #2: <code>jar:http://some/path/gluegen-rt.jar!/?arg=1#frag</code>
+     *     Returned Uri #3: <code>null</code>
+     *
+     * Example-2:
+     *     This instance  : <code>http://some/path/gluegen-rt.jar?arg=1#frag</code>
+     *     Returned Uri #1: <code>http://some/path/?arg=1#frag</code>
+     *     Returned Uri #2: <code>http://some/?arg=1#frag</code>
+     *     Returned Uri #2: <code>null</code>
+     *
+     * Example-3:
+     *     This instance  : <code>http://some/path/../gluegen-rt.jar?arg=1#frag</code>
+     *     Returned Uri #1: <code>http://some/?arg=1#frag</code>
+     *     Returned Uri #2: <code>null</code>
+     * </pre>
+     * </p>
+     */
+    public final Uri getParent() {
+        try {
+            return cutoffLastPathSegementImpl(true, true, null);
+        } catch (final URISyntaxException e) {
+            if( DEBUG ) {
+                System.err.println("Caught "+e.getClass().getSimpleName()+": "+e.getMessage());
+                e.printStackTrace();
+            }
+            return null;
+        }
+    }
+
+    /**
+     * Returns a new Uri appending the given {@code appendPath}
+     * to this instance's {@link #getDirectory() directory}.
+     * <p>
+     * If {@code appendPath} is empty, method behaves like {@link #getNormalized()}.
+     * </p>
+     * <p>
+     * This resulting path will be {@link IOUtil#cleanPathString(String) normalized}.
+     * </p>
+     * <p>
+     * <pre>
+     * Example-1:
+     *     append: null
+     *     this-uri: http:/some/path/gluegen-rt.jar
+     *     result:   http:/some/path/gluegen-rt.jar
+     *
+     * Example-2:
+     *     append: test.txt
+     *     this-uri: file:/some/path/gluegen-rt.jar
+     *     result:   file:/some/path/test.txt
+     *
+     * Example-3:
+     *     append: test.txt
+     *     this-uri: file:/some/path/lala/lili/../../hello.txt
+     *     result:   file:/some/path/test.txt
+     * </pre>
+     * </p>
+     *
+     * @param appendPath denotes a relative path to be appended to this Uri's directory
+     * @throws URISyntaxException
+     *             if the resulting {@code uri} doesn't fit to the
+     *             specification RFC2396 and RFC3986 or could not be parsed correctly.
+     */
+    public Uri getRelativeOf(final Encoded appendPath) throws URISyntaxException {
+        if( emptyString(appendPath) ) {
+            return getNormalized();
+        } else {
+            return cutoffLastPathSegementImpl(true, false, appendPath);
+        }
+    }
+
+    /**
+     * Concatenates the given encoded string to the {@link #getEncoded() encoded uri}
+     * of this instance and returns {@link #Uri(Encoded) a new Uri instance} with the result.
+     *
+     * @throws URISyntaxException
+     *             if the concatenated string {@code uri} doesn't fit to the
+     *             specification RFC2396 and RFC3986 or could not be parsed correctly.
+     */
+    public final Uri concat(final Encoded suffix) throws URISyntaxException {
+        if( null == suffix ) {
+            return this;
+        } else {
+            return new Uri( input.concat(suffix) );
+        }
+    }
+
+    /**
+     * Returns a new Uri instance w/ the given new query {@code newQuery}.
+     *
+     * @throws URISyntaxException if this Uri is {@link #opaque}
+     *             or if the new string {@code uri} doesn't fit to the
+     *             specification RFC2396 and RFC3986 or could not be parsed correctly.
+     */
+    public final Uri getNewQuery(final Encoded newQuery) throws URISyntaxException {
+        if( opaque ) {
+            throw new URISyntaxException(input.decode(), "Opaque Uri cannot permute by query");
+        } else {
+            // with host validation if authority is defined
+            return Uri.create(scheme, userInfo, host, port, path, newQuery, fragment);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Compares this Uri instance with the given argument {@code o} and
+     * determines if both are equal. Two Uri instances are equal if all single
+     * parts are identical in their meaning.
+     * </p>
+     *
+     * @param o
+     *            the Uri this instance has to be compared with.
+     * @return {@code true} if both Uri instances point to the same resource,
+     *         {@code false} otherwise.
+     */
+    @Override
+    public final boolean equals(final Object o) {
+        if (!(o instanceof Uri)) {
+            return false;
+        }
+        final Uri uri = (Uri) o;
+
+        if (uri.fragment == null && fragment != null || uri.fragment != null && fragment == null) {
+            return false;
+        } else if (uri.fragment != null && fragment != null) {
+            if (!equalsHexCaseInsensitive(uri.fragment, fragment)) {
+                return false;
+            }
+        }
+
+        if (uri.scheme == null && scheme != null || uri.scheme != null && scheme == null) {
+            return false;
+        } else if (uri.scheme != null && scheme != null) {
+            if (!uri.scheme.equalsIgnoreCase(scheme)) {
+                return false;
+            }
+        }
+
+        if (uri.opaque && opaque) {
+            return equalsHexCaseInsensitive(uri.schemeSpecificPart, schemeSpecificPart);
+        } else if (!uri.opaque && !opaque) {
+            if (!equalsHexCaseInsensitive(path, uri.path)) {
+                return false;
+            }
+
+            if (uri.query != null && query == null || uri.query == null && query != null) {
+                return false;
+            } else if (uri.query != null && query != null) {
+                if (!equalsHexCaseInsensitive(uri.query, query)) {
+                    return false;
+                }
+            }
+
+            if (uri.authority != null && authority == null || uri.authority == null && authority != null) {
+                return false;
+            } else if (uri.authority != null && authority != null) {
+                if (uri.host != null && host == null || uri.host == null && host != null) {
+                    return false;
+                } else if (uri.host == null && host == null) {
+                    // both are registry based, so compare the whole authority
+                    return equalsHexCaseInsensitive(uri.authority, authority);
+                } else { // uri.host != null && host != null, so server-based
+                    if (!host.equalsIgnoreCase(uri.host)) {
+                        return false;
+                    }
+
+                    if (port != uri.port) {
+                        return false;
+                    }
+
+                    if ( uri.userInfo != null && userInfo == null ||
+                         uri.userInfo == null && userInfo != null
+                       ) {
+                        return false;
+                    } else if (uri.userInfo != null && userInfo != null) {
+                        return equalsHexCaseInsensitive(userInfo, uri.userInfo);
+                    } else {
+                        return true;
+                    }
+                }
+            } else {
+                // no authority
+                return true;
+            }
+
+        } else {
+            // one is opaque, the other hierarchical
+            return false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Gets the hashcode value of this Uri instance.
+     * </p>
+     */
+    @Override
+    public final int hashCode() {
+        synchronized( lazyLock ) {
+            if (hash == -1) {
+                hash = getHashString().hashCode();
+            }
+            return hash;
+        }
+    }
+
+    /*
+     * Takes a string that may contain hex sequences like %F1 or %2b and
+     * converts the hex values following the '%' to lowercase
+     */
+    private String convertHexToLowerCase(final String s) {
+        if (s.indexOf('%') == -1) {
+            return s;
+        }
+        final StringBuilder result = new StringBuilder("");
+        int index = 0, previndex = 0;
+        while ((index = s.indexOf('%', previndex)) != -1) {
+            result.append(s.substring(previndex, index + 1));
+            result.append(s.substring(index + 1, index + 3).toLowerCase());
+            index += 3;
+            previndex = index;
+        }
+        return result.toString();
+    }
+
+    /*
+     * Takes two strings that may contain hex sequences like %F1 or %2b and
+     * compares them, ignoring case for the hex values. Hex values must always
+     * occur in pairs as above
+     */
+    private boolean equalsHexCaseInsensitive(final Encoded first, final Encoded second) {
+        if (first.indexOf('%') != second.indexOf('%')) {
+            return first.equals(second);
+        }
+
+        int index = 0, previndex = 0;
+        while ( ( index = first.indexOf('%', previndex) ) != -1 &&
+                second.indexOf('%', previndex) == index
+              ) {
+            if( !first.get().substring(previndex, index).equals( second.get().substring(previndex, index) ) ) {
+                return false;
+            }
+            if( !first.get().substring(index + 1, index + 3).equalsIgnoreCase( second.get().substring(index + 1, index + 3) ) ) {
+                return false;
+            }
+            index += 3;
+            previndex = index;
+        }
+        return first.get().substring(previndex).equals( second.get().substring(previndex) );
+    }
+
+    /*
+     * Form a string from the components of this Uri, similarly to the
+     * toString() method. But this method converts scheme and host to lowercase,
+     * and converts escaped octets to lowercase.
+     */
+    private String getHashString() {
+        final StringBuilder result = new StringBuilder();
+        if (scheme != null) {
+            result.append(scheme.get().toLowerCase());
+            result.append(SCHEME_SEPARATOR);
+        }
+        if (opaque) {
+            result.append(schemeSpecificPart.get());
+        } else {
+            if (authority != null) {
+                result.append("//");
+                if (host == null) {
+                    result.append(authority.get());
+                } else {
+                    if (userInfo != null) {
+                        result.append(userInfo.get() + "@");
+                    }
+                    result.append(host.get().toLowerCase());
+                    if (port != -1) {
+                        result.append(SCHEME_SEPARATOR + port);
+                    }
+                }
+            }
+
+            if (path != null) {
+                result.append(path.get());
+            }
+
+            if (query != null) {
+                result.append(QUERY_SEPARATOR);
+                result.append(query.get());
+            }
+        }
+
+        if (fragment != null) {
+            result.append(FRAGMENT_SEPARATOR);
+            result.append(fragment.get());
+        }
+        return convertHexToLowerCase(result.toString());
+    }
+
+    /**
+     *
+     * @param input
+     * @param expectServer
+     * @param parseHints TODO
+     * @throws URISyntaxException
+     */
+    private Uri(final Encoded input, final boolean expectServer, final int parseHints) throws URISyntaxException {
+        if( emptyString(input) ) {
+            throw new URISyntaxException(input.get(), "empty input");
+        }
+        String temp = input.get();
+        int index;
+        // parse into Fragment, Scheme, and SchemeSpecificPart
+        // then parse SchemeSpecificPart if necessary
+
+        // Fragment
+        index = temp.indexOf(FRAGMENT_SEPARATOR);
+        if (index != -1) {
+            // remove the fragment from the end
+            fragment = new Encoded( temp.substring(index + 1) );
+            validateFragment(input, fragment, index + 1);
+            temp = temp.substring(0, index);
+        } else {
+            fragment = null;
+        }
+
+        String inputTemp = input.get(); // may get modified due to error correction
+
+        // Scheme and SchemeSpecificPart
+        final int indexSchemeSep = temp.indexOf(SCHEME_SEPARATOR);
+        index = indexSchemeSep;
+        final int indexSSP = temp.indexOf('/');
+        final int indexQuerySep = temp.indexOf(QUERY_SEPARATOR);
+
+        String sspTemp; // may get modified due to error correction
+
+        // if a '/' or '?' occurs before the first ':' the uri has no
+        // specified scheme, and is therefore not absolute
+        if ( indexSchemeSep != -1 &&
+             ( indexSSP >= indexSchemeSep || indexSSP == -1 ) &&
+             ( indexQuerySep >= indexSchemeSep || indexQuerySep == -1 )
+           ) {
+            // the characters up to the first ':' comprise the scheme
+            absolute = true;
+            scheme = new Encoded( temp.substring(0, indexSchemeSep) );
+            if (scheme.length() == 0) {
+                failExpecting(input, "scheme", indexSchemeSep);
+            }
+            validateScheme(input, scheme, 0);
+            sspTemp = temp.substring(indexSchemeSep + 1);
+            if (sspTemp.length() == 0) {
+                failExpecting(input, "scheme-specific-part", indexSchemeSep);
+            }
+        } else {
+            absolute = false;
+            scheme = null;
+            sspTemp = temp;
+        }
+
+        if ( scheme == null ||  sspTemp.length() > 0 && sspTemp.charAt(0) == '/' ) {
+            // Uri is hierarchical, not opaque
+            opaque = false;
+
+            // Query
+            temp = sspTemp;
+            index = temp.indexOf(QUERY_SEPARATOR);
+            if (index != -1) {
+                query = new Encoded( temp.substring(index + 1) );
+                temp = temp.substring(0, index);
+                validateQuery(input, query, indexSSP + 1 + index);
+            } else {
+                query = null;
+            }
+
+            String pathTemp; // may get modified due to error correction
+            final int indexPathInSSP;
+
+            // Authority and Path
+            if (temp.startsWith("//")) {
+                index = temp.indexOf('/', 2);
+                final String authorityS;
+                if (index != -1) {
+                    authorityS = temp.substring(2, index);
+                    pathTemp = temp.substring(index);
+                    indexPathInSSP = index;
+                } else {
+                    authorityS = temp.substring(2);
+                    if (authorityS.length() == 0 && query == null && fragment == null) {
+                        failExpecting(input, "authority, path [, query, fragment]", index);
+                    }
+                    pathTemp = "";
+                    indexPathInSSP = -1;
+                    // nothing left, so path is empty
+                    // (not null, path should never be null if hierarchical/non-opaque)
+                }
+                if ( emptyString(authorityS) ) {
+                    authority = null;
+                } else {
+                    authority = new Encoded( authorityS );
+                    validateAuthority(input, authority, indexSchemeSep + 3);
+                }
+            } else { // no authority specified
+                pathTemp = temp;
+                indexPathInSSP = 0;
+                authority = null;
+            }
+
+            int indexPath = 0; // in input
+            if (indexSSP > -1) {
+                indexPath += indexSSP;
+            }
+            if (indexPathInSSP > -1) {
+                indexPath += indexPathInSSP;
+            }
+
+            final int pathErrIdx = validateEncoded(pathTemp, PATH_LEGAL);
+            if( 0 <= pathErrIdx ) {
+                // Perform error correction on PATH if requested!
+                if( 0 != ( parseHints & PARSE_HINT_FIX_PATH ) ) {
+                    if( DEBUG_SHOWFIX ) {
+                        System.err.println("Uri FIX_FILEPATH: input at index "+(indexPath+pathErrIdx)+": "+inputTemp);
+                        System.err.println("Uri FIX_FILEPATH: ssp at index   "+(indexPathInSSP+pathErrIdx)+": "+sspTemp);
+                        System.err.println("Uri FIX_FILEPATH: path  at index "+pathErrIdx+": "+pathTemp);
+                    }
+                    final int pathTempOldLen = pathTemp.length();
+                    pathTemp = encode( decode( pathTemp ), PATH_LEGAL); // re-encode, and hope for the best!
+                    validatePath(input, pathTemp, indexPath); // re-validate!
+                    {
+                        // Patch SSP + INPUT !
+                        final StringBuilder sb = new StringBuilder();
+                        if( indexPathInSSP > 0 ) {
+                            sb.append( sspTemp.substring(0, indexPathInSSP) );
+                        }
+                        sb.append( pathTemp ).append( sspTemp.substring( indexPathInSSP + pathTempOldLen ) );
+                        sspTemp = sb.toString(); // update
+
+                        sb.setLength(0);
+                        if( indexPath > 0 ) {
+                            sb.append( inputTemp.substring(0, indexPath) );
+                        }
+                        sb.append( pathTemp ).append( inputTemp.substring( indexPath + pathTempOldLen ) );
+                        inputTemp = sb.toString(); // update
+                    }
+                    if( DEBUG_SHOWFIX ) {
+                        System.err.println("Uri FIX_FILEPATH: result          : "+pathTemp);
+                        System.err.println("Uri FIX_FILEPATH: ssp after       : "+sspTemp);
+                        System.err.println("Uri FIX_FILEPATH: input after     : "+inputTemp);
+                    }
+                } else {
+                    fail(input, "invalid path", indexPath+pathErrIdx);
+                }
+            }
+            path = new Encoded( pathTemp );
+        } else {
+            // Uri is not hierarchical, Uri is opaque
+            opaque = true;
+            query = null;
+            path = null;
+            authority = null;
+            validateSsp(input, sspTemp, indexSchemeSep + 1);
+        }
+        schemeSpecificPart = new Encoded( sspTemp );
+        this.input = inputTemp == input.get() ? input : new Encoded( inputTemp );
+
+        /**
+         * determine the host, port and userinfo if the authority parses
+         * successfully to a server based authority
+         *
+         * Behavior in error cases: if forceServer is true, throw
+         * URISyntaxException with the proper diagnostic messages. if
+         * forceServer is false assume this is a registry based uri, and just
+         * return leaving the host, port and userinfo fields undefined.
+         *
+         * and there are some error cases where URISyntaxException is thrown
+         * regardless of the forceServer parameter e.g. malformed ipv6 address
+         */
+        Encoded tempUserinfo = null, tempHost = null;
+        int tempPort = -1;
+        boolean authorityComplete;
+
+        if ( null != authority ) {
+            authorityComplete = true; // set to false later
+            int hostindex = 0;
+
+            temp = authority.get();
+            index = temp.indexOf('@');
+            if (index != -1) {
+                // remove user info
+                tempUserinfo = new Encoded( temp.substring(0, index) );
+                validateUserinfo(authority, tempUserinfo, 0);
+                temp = temp.substring(index + 1); // host[:port] is left
+                hostindex = index + 1;
+            }
+
+            index = temp.lastIndexOf(SCHEME_SEPARATOR);
+            final int endindex = temp.indexOf(']');
+
+            if (index != -1 && endindex < index) {
+                // determine port and host
+                tempHost = new Encoded( temp.substring(0, index) );
+
+                if (index < (temp.length() - 1)) { // port part is not empty
+                    try {
+                        tempPort = Integer.parseInt(temp.substring(index + 1));
+                        if (tempPort < 0) {
+                            if (expectServer) {
+                                fail(authority, "invalid port <"+authority+">", hostindex + index + 1);
+                            }
+                            authorityComplete = false;
+                        }
+                    } catch (final NumberFormatException e) {
+                        if (expectServer) {
+                            fail(authority, "invalid port <"+authority+">, "+e.getMessage(), hostindex + index + 1);
+                        }
+                        authorityComplete = false;
+                    }
+                }
+            } else {
+                tempHost = new Encoded( temp );
+            }
+
+            if( authorityComplete ) {
+                if ( emptyString(tempHost) ) {
+                    if (expectServer) {
+                        fail(authority, "empty host <"+authority+">", hostindex);
+                    }
+                    authorityComplete = false;
+                } else if (!isValidHost(expectServer, tempHost)) {
+                    if (expectServer) {
+                        fail(authority, "invalid host <"+tempHost+">", hostindex);
+                    }
+                    authorityComplete = false;
+                }
+            }
+        } else {
+            authorityComplete = false;
+        }
+
+        if( authorityComplete ) {
+            // this is a server based uri,
+            // fill in the userinfo, host and port fields
+            userInfo = tempUserinfo;
+            host = tempHost;
+            port = tempPort;
+            hasAuthority = true;
+        } else {
+            userInfo = null;
+            host = null;
+            port = -1;
+            hasAuthority = false;
+        }
+    }
+
+    private static void validateScheme(final Encoded uri, final Encoded scheme, final int index) throws URISyntaxException {
+        // first char needs to be an alpha char
+        final char ch = scheme.charAt(0);
+        if ( !((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) ) {
+            fail(uri, "invalid scheme", index);
+        }
+        final int errIdx = validateAlphaNum(scheme.get(), "+-.");
+        if( 0 <= errIdx ) {
+            fail(uri, "invalid scheme", index+errIdx);
+        }
+    }
+
+    private static void validateSsp(final Encoded uri, final String ssp, final int index) throws URISyntaxException {
+        final int errIdx = validateEncoded(ssp, SSP_LEGAL);
+        if( 0 <= errIdx ) {
+            fail(uri, "invalid scheme-specific-part", index+errIdx);
+        }
+    }
+
+    private static void validateAuthority(final Encoded uri, final Encoded authority, final int index) throws URISyntaxException {
+        final int errIdx = validateEncoded(authority.get(), AUTHORITY_LEGAL);
+        if( 0 <= errIdx ) {
+            fail(uri, "invalid authority", index+errIdx);
+        }
+    }
+
+    private static void validatePath(final Encoded uri, final String path, final int index) throws URISyntaxException {
+        final int errIdx = validateEncoded(path, PATH_LEGAL);
+        if( 0 <= errIdx ) {
+            fail(uri, "invalid path", index+errIdx);
+        }
+    }
+
+    private static void validateQuery(final Encoded uri, final Encoded query, final int index) throws URISyntaxException {
+        final int errIdx = validateEncoded(query.get(), QUERY_LEGAL);
+        if( 0 <= errIdx ) {
+            fail(uri, "invalid query", index+errIdx);
+        }
+    }
+
+    private static void validateFragment(final Encoded uri, final Encoded fragment, final int index) throws URISyntaxException {
+        final int errIdx = validateEncoded(fragment.get(), FRAG_LEGAL);
+        if( 0 <= errIdx ) {
+            fail(uri, "invalid fragment", index+errIdx);
+        }
+    }
+
+    private static void validateUserinfo(final Encoded uri, final Encoded userinfo, final int index) throws URISyntaxException {
+        for (int i = 0; i < userinfo.length(); i++) {
+            final char ch = userinfo.charAt(i);
+            if (ch == ']' || ch == '[') {
+                fail(uri, "invalid userinfo", index+i);
+            }
+        }
+    }
+
+    /**
+     * distinguish between IPv4, IPv6, domain name and validate it based on
+     * its type
+     */
+    private boolean isValidHost(final boolean expectServer, final Encoded host) throws URISyntaxException {
+        if (host.charAt(0) == '[') {
+            // ipv6 address
+            if (host.charAt(host.length() - 1) != ']') {
+                fail(input, "invalid host, missing closing ipv6: "+host, 0);
+            }
+            if (!isValidIP6Address(host.get())) {
+                fail(input, "invalid ipv6: "+host, 0);
+            }
+            return true;
+        }
+
+        // '[' and ']' can only be the first char and last char
+        // of the host name
+        if (host.indexOf('[') != -1 || host.indexOf(']') != -1) {
+            fail(input, "invalid host: "+host, 0);
+        }
+
+        final int index = host.lastIndexOf('.');
+        if ( index < 0 || index == host.length() - 1 ||
+             !Character.isDigit(host.charAt(index + 1)) )
+        {
+            // domain name
+            if (isValidDomainName(host)) {
+                return true;
+            }
+            if (expectServer) {
+                fail(input, "invalid host, invalid domain-name or ipv4: "+host, 0);
+            }
+            return false;
+        }
+
+        // IPv4 address
+        if (isValidIPv4Address(host.get())) {
+            return true;
+        }
+        if (expectServer) {
+            fail(input, "invalid host, invalid ipv4: "+host, 0);
+        }
+        return false;
+    }
+
+    private static boolean isValidDomainName(final Encoded host) {
+        final String hostS = host.get();
+        if( 0 <= validateAlphaNum(hostS, "-.") ) {
+            return false;
+        }
+        String label = null;
+        final StringTokenizer st = new StringTokenizer(hostS, ".");
+        while (st.hasMoreTokens()) {
+            label = st.nextToken();
+            if (label.startsWith("-") || label.endsWith("-")) {
+                return false;
+            }
+        }
+
+        if (!label.equals(hostS)) {
+            final char ch = label.charAt(0);
+            if (ch >= '0' && ch <= '9') {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static boolean isValidIPv4Address(final String ipv4Address) {
+        int index;
+        int index2;
+        try {
+            int num;
+            index = ipv4Address.indexOf('.');
+            num = Integer.parseInt(ipv4Address.substring(0, index));
+            if (num < 0 || num > 255) {
+                return false;
+            }
+            index2 = ipv4Address.indexOf('.', index + 1);
+            num = Integer.parseInt(ipv4Address.substring(index + 1, index2));
+            if (num < 0 || num > 255) {
+                return false;
+            }
+            index = ipv4Address.indexOf('.', index2 + 1);
+            num = Integer.parseInt(ipv4Address.substring(index2 + 1, index));
+            if (num < 0 || num > 255) {
+                return false;
+            }
+            num = Integer.parseInt(ipv4Address.substring(index + 1));
+            if (num < 0 || num > 255) {
+                return false;
+            }
+        } catch (final Exception e) {
+            return false;
+        }
+        return true;
+    }
+
+    private static boolean isValidIP6Address(final String ipv6Address) {
+        final int length = ipv6Address.length();
+        boolean doubleColon = false;
+        int numberOfColons = 0;
+        int numberOfPeriods = 0;
+        String word = "";
+        char c = 0;
+        char prevChar = 0;
+        int offset = 0; // offset for [] ip addresses
+
+        if (length < 2) {
+            return false;
+        }
+
+        for (int i = 0; i < length; i++) {
+            prevChar = c;
+            c = ipv6Address.charAt(i);
+            switch (c) {
+
+                // case for an open bracket [x:x:x:...x]
+                case '[':
+                    if (i != 0) {
+                        return false; // must be first character
+                    }
+                    if (ipv6Address.charAt(length - 1) != ']') {
+                        return false; // must have a close ]
+                    }
+                    if ((ipv6Address.charAt(1) == SCHEME_SEPARATOR)
+                            && (ipv6Address.charAt(2) != SCHEME_SEPARATOR)) {
+                        return false;
+                    }
+                    offset = 1;
+                    if (length < 4) {
+                        return false;
+                    }
+                    break;
+
+                // case for a closed bracket at end of IP [x:x:x:...x]
+                case ']':
+                    if (i != length - 1) {
+                        return false; // must be last character
+                    }
+                    if (ipv6Address.charAt(0) != '[') {
+                        return false; // must have a open [
+                    }
+                    break;
+
+                // case for the last 32-bits represented as IPv4
+                // x:x:x:x:x:x:d.d.d.d
+                case '.':
+                    numberOfPeriods++;
+                    if (numberOfPeriods > 3) {
+                        return false;
+                    }
+                    if (!isValidIP4Word(word)) {
+                        return false;
+                    }
+                    if (numberOfColons != 6 && !doubleColon) {
+                        return false;
+                    }
+                    // a special case ::1:2:3:4:5:d.d.d.d allows 7 colons
+                    // with
+                    // an IPv4 ending, otherwise 7 :'s is bad
+                    if (numberOfColons == 7
+                            && ipv6Address.charAt(0 + offset) != SCHEME_SEPARATOR
+                            && ipv6Address.charAt(1 + offset) != SCHEME_SEPARATOR) {
+                        return false;
+                    }
+                    word = "";
+                    break;
+
+                case SCHEME_SEPARATOR:
+                    numberOfColons++;
+                    if (numberOfColons > 7) {
+                        return false;
+                    }
+                    if (numberOfPeriods > 0) {
+                        return false;
+                    }
+                    if (prevChar == SCHEME_SEPARATOR) {
+                        if (doubleColon) {
+                            return false;
+                        }
+                        doubleColon = true;
+                    }
+                    word = "";
+                    break;
+
+                default:
+                    if (word.length() > 3) {
+                        return false;
+                    }
+                    if (!isValidHexChar(c)) {
+                        return false;
+                    }
+                    word += c;
+            }
+        }
+
+        // Check if we have an IPv4 ending
+        if (numberOfPeriods > 0) {
+            if (numberOfPeriods != 3 || !isValidIP4Word(word)) {
+                return false;
+            }
+        } else {
+            // If we're at then end and we haven't had 7 colons then there
+            // is a problem unless we encountered a doubleColon
+            if (numberOfColons != 7 && !doubleColon) {
+                return false;
+            }
+
+            // If we have an empty word at the end, it means we ended in
+            // either a : or a .
+            // If we did not end in :: then this is invalid
+            if (word == "" && ipv6Address.charAt(length - 1 - offset) != SCHEME_SEPARATOR
+                    && ipv6Address.charAt(length - 2 - offset) != SCHEME_SEPARATOR) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private static boolean isValidIP4Word(final String word) {
+        char c;
+        if (word.length() < 1 || word.length() > 3) {
+            return false;
+        }
+        for (int i = 0; i < word.length(); i++) {
+            c = word.charAt(i);
+            if (!(c >= '0' && c <= '9')) {
+                return false;
+            }
+        }
+        if (Integer.parseInt(word) > 255) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Validate a string by checking if it contains any characters other than:
+     * <ol>
+     *   <li>letters ('a'..'z', 'A'..'Z')</li>
+     *   <li>numbers ('0'..'9')</li>
+     *   <li>characters in the legal-set parameter</li>
+     *   <li> others (unicode characters that are not in
+     *        US-ASCII set, and are not ISO Control or are not ISO Space characters)</li>
+     * </ol>
+     *
+     * @param encoded
+     *            {@code java.lang.String} the string to be validated
+     * @param legal
+     *            {@code java.lang.String} the characters allowed in the String
+     *            s
+     */
+    private static int validateEncoded(final String encoded, final String legal) {
+        for (int i = 0; i < encoded.length();) {
+            final char ch = encoded.charAt(i);
+            if (ch == '%') {
+                do {
+                    if (i + 2 >= encoded.length()) {
+                        throw new IllegalArgumentException("missing '%' hex-digits at index "+i);
+                    }
+                    final int d1 = Character.digit(encoded.charAt(i + 1), 16);
+                    final int d2 = Character.digit(encoded.charAt(i + 2), 16);
+                    if (d1 == -1 || d2 == -1) {
+                        throw new IllegalArgumentException("invalid hex-digits at index "+i+": "+encoded.substring(i, i + 3));
+                    }
+                    i += 3;
+                } while (i < encoded.length() && encoded.charAt(i) == '%');
+                continue;
+            }
+            if ( !( (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
+                    (ch >= '0' && ch <= '9') || legal.indexOf(ch) > -1 ||
+                    (ch > 127 && !Character.isSpaceChar(ch) && !Character.isISOControl(ch))
+                  )
+               ) {
+                return i;
+            }
+            i++;
+        }
+        return -1;
+    }
+    private static int validateAlphaNum(final String s, final String legal) {
+        for (int i = 0; i < s.length();) {
+            final char ch = s.charAt(i);
+            if ( !( (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
+                    (ch >= '0' && ch <= '9') || legal.indexOf(ch) > -1
+                  )
+               ) {
+                return i;
+            }
+            i++;
+        }
+        return -1;
+    }
+
+    private static boolean isValidHexChar(final char c) {
+        return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
+    }
+    private static boolean emptyString(final Encoded s) {
+        return null == s || 0 == s.length();
+    }
+    private static boolean emptyString(final String s) {
+        return null == s || 0 == s.length();
+    }
+
+    private static void fail(final Encoded input, final String reason, final int p) throws URISyntaxException {
+        throw new URISyntaxException(input.get(), reason, p);
+    }
+    private static void failExpecting(final Encoded input, final String expected, final int p) throws URISyntaxException {
+        fail(input, "Expecting " + expected, p);
+    }
+}
\ No newline at end of file
diff --git a/src/java/com/jogamp/common/net/URIQueryProps.java b/src/java/com/jogamp/common/net/UriQueryProps.java
similarity index 85%
rename from src/java/com/jogamp/common/net/URIQueryProps.java
rename to src/java/com/jogamp/common/net/UriQueryProps.java
index 138ff9b..a93a1eb 100644
--- a/src/java/com/jogamp/common/net/URIQueryProps.java
+++ b/src/java/com/jogamp/common/net/UriQueryProps.java
@@ -27,7 +27,6 @@
  */
 package com.jogamp.common.net;
 
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -44,8 +43,12 @@ import java.util.Map.Entry;
  *  w/ authority: [user-info@]host[:port]
  *  Note: 'path' starts w/ fwd slash
  * </pre>
+ * <p>
+ * Since 2.3.0 renamed from {@code URIQueryProps} to {@code UriQueryProps},
+ * and using {@link Uri} instead of {@link java.net.URI}.
+ * </p>
  */
-public class URIQueryProps {
+public class UriQueryProps {
    private static final String QMARK = "?";
    private static final char ASSIG = '=';
    private static final String EMPTY = "";
@@ -53,21 +56,21 @@ public class URIQueryProps {
 
    private final HashMap<String, String> properties = new HashMap<String, String>();
 
-   private URIQueryProps(final char querySeparator) {
+   private UriQueryProps(final char querySeparator) {
        query_separator = String.valueOf(querySeparator);
    }
 
    public final Map<String, String> getProperties() { return properties; }
    public final char getQuerySeparator() { return query_separator.charAt(0); }
 
-   public final String appendQuery(String baseQuery) {
+   public final Uri.Encoded appendQuery(Uri.Encoded baseQuery) {
        boolean needsSep = false;
        final StringBuilder sb = new StringBuilder();
        if ( null != baseQuery ) {
-           if( !baseQuery.startsWith(QMARK) ) {
-               baseQuery = baseQuery.substring(1);
+           if( baseQuery.startsWith(QMARK) ) {
+               baseQuery = baseQuery.substring(1); // cut off '?'
            }
-           sb.append(baseQuery);
+           sb.append(baseQuery.get());
            if( !baseQuery.endsWith(query_separator) ) {
                needsSep = true;
            }
@@ -84,13 +87,11 @@ public class URIQueryProps {
            }
            needsSep = true;
        }
-       return sb.toString();
+       return new Uri.Encoded(sb.toString(), Uri.QUERY_LEGAL);
    }
 
-   public final URI appendQuery(final URI base) throws URISyntaxException {
-       return new URI(base.getScheme(),
-                      base.getRawUserInfo(), base.getHost(), base.getPort(),
-                      base.getRawPath(), appendQuery(base.getRawQuery()), base.getRawFragment());
+   public final Uri appendQuery(final Uri base) throws URISyntaxException {
+       return base.getNewQuery( appendQuery( base.query ) );
    }
 
    /**
@@ -100,12 +101,12 @@ public class URIQueryProps {
     * @return
     * @throws IllegalArgumentException if <code>querySeparator</code> is illegal, i.e. neither <i>;</i> nor <i>&</i>
     */
-   public static final URIQueryProps create(final URI uri, final char querySeparator) throws IllegalArgumentException {
+   public static final UriQueryProps create(final Uri uri, final char querySeparator) throws IllegalArgumentException {
        if( ';' != querySeparator && '&' != querySeparator ) {
            throw new IllegalArgumentException("querySeparator is invalid: "+querySeparator);
        }
-       final URIQueryProps data = new URIQueryProps(querySeparator);
-       final String q = uri.getQuery();
+       final UriQueryProps data = new UriQueryProps(querySeparator);
+       final String q = Uri.decode(uri.query);
        final int q_l = null != q ? q.length() : -1;
        int q_e = -1;
        while(q_e < q_l) {
diff --git a/src/java/com/jogamp/common/nio/Buffers.java b/src/java/com/jogamp/common/nio/Buffers.java
index 8fff30e..aae2be8 100644
--- a/src/java/com/jogamp/common/nio/Buffers.java
+++ b/src/java/com/jogamp/common/nio/Buffers.java
@@ -39,9 +39,15 @@
  */
 package com.jogamp.common.nio;
 
-import java.nio.*;
-
-import jogamp.common.os.PlatformPropsImpl;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.LongBuffer;
+import java.nio.ShortBuffer;
 
 import com.jogamp.common.util.ValueConv;
 
@@ -445,30 +451,10 @@ public class Buffers {
         if (buf == null) {
             return true;
         }
-        if ( PlatformPropsImpl.JAVA_6 ) {
-            if (buf instanceof Buffer) {
-                return ((Buffer) buf).isDirect();
-            } else if (buf instanceof PointerBuffer) {
-                return ((PointerBuffer) buf).isDirect();
-            }
-        } else {
-            if (buf instanceof ByteBuffer) {
-                return ((ByteBuffer) buf).isDirect();
-            } else if (buf instanceof IntBuffer) {
-                return ((IntBuffer) buf).isDirect();
-            } else if (buf instanceof ShortBuffer) {
-                return ((ShortBuffer) buf).isDirect();
-            } else if (buf instanceof FloatBuffer) {
-                return ((FloatBuffer) buf).isDirect();
-            } else if (buf instanceof DoubleBuffer) {
-                return ((DoubleBuffer) buf).isDirect();
-            } else if (buf instanceof LongBuffer) {
-                return ((LongBuffer) buf).isDirect();
-            } else if (buf instanceof CharBuffer) {
-                return ((CharBuffer) buf).isDirect();
-            } else if (buf instanceof PointerBuffer) {
-                return ((PointerBuffer) buf).isDirect();
-            }
+        if (buf instanceof Buffer) {
+            return ((Buffer) buf).isDirect();
+        } else if (buf instanceof PointerBuffer) {
+            return ((PointerBuffer) buf).isDirect();
         }
         throw new IllegalArgumentException("Unexpected buffer type " + buf.getClass().getName());
     }
diff --git a/src/java/com/jogamp/common/nio/ByteBufferInputStream.java b/src/java/com/jogamp/common/nio/ByteBufferInputStream.java
new file mode 100644
index 0000000..b74360f
--- /dev/null
+++ b/src/java/com/jogamp/common/nio/ByteBufferInputStream.java
@@ -0,0 +1,186 @@
+/**
+ * Copyright 2014 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.common.nio;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileChannel.MapMode;
+
+/**
+ * An {@link InputStream} implementation based on an underlying {@link ByteBuffer}
+ * supporting {@link #markSupported() mark}.
+ * <p>
+ * May be utilized as well with a {@link MappedByteBuffer memory-mapped} {@link FileChannel#map(MapMode, long, long) FileChannel}
+ * using a size ≤ {@link Integer#MAX_VALUE}.<br>
+ * This becomes efficient with files ≥ 10 MiB, depending on the platform
+ * and whether the traditional method uses a {@link BufferedInputStream} supporting {@code mark} incl. it's buffer size.<br>
+ * See test case {@code com.jogamp.common.nio.TestByteBufferInputStream}.
+ * </p>
+ * @since 2.3.0
+ */
+public class ByteBufferInputStream extends InputStream {
+    private final ByteBuffer buf;
+    private int mark;
+
+    /**
+     * Creates a new byte-buffer input stream.
+     *
+     * @param buf the underlying byte buffer.
+     */
+    public ByteBufferInputStream(final ByteBuffer buf) {
+        this.buf = buf;
+        this.mark = -1;
+    }
+
+    @Override
+    public final int available() {
+        return buf.remaining();
+    }
+
+    /**
+     * <i>This implementation supports {@code mark}.</i>
+     * <p>
+     * {@inheritDoc}
+     * </p>
+     */
+    @Override
+    public final boolean markSupported() {
+        return true;
+    }
+
+    /**
+     * <i>This implementation supports {@code mark}.</i>
+     * <p>
+     * {@inheritDoc}
+     * </p>
+     * @see #markSupported()
+     */
+    @Override
+    public final synchronized void mark(final int unused) {
+        mark = buf.position();
+    }
+
+    /**
+     * <i>This implementation supports {@code mark}.</i>
+     * <p>
+     * {@inheritDoc}
+     * </p>
+     * @see #markSupported()
+     */
+    @Override
+    public final synchronized void reset() throws IOException {
+        if ( mark == -1 ) {
+            throw new IOException();
+        }
+        buf.position(mark);
+    }
+
+    @Override
+    public final long skip(final long n) throws IOException {
+        if( 0 > n ) {
+            return 0;
+        }
+        final int s = (int) Math.min( buf.remaining(), n );
+        buf.position(buf.position() + s);
+        return s;
+    }
+
+    @Override
+    public final int read() {
+        if ( ! buf.hasRemaining() ) {
+            return -1;
+        }
+        return buf.get() & 0xFF;
+    }
+
+    @Override
+    public final int read(final byte[] b, final int off, final int len) {
+        if (b == null) {
+            throw new NullPointerException();
+        } else if( off < 0 ||
+                   len < 0 ||
+                   off > b.length ||
+                   off + len > b.length ||
+                   off + len < 0
+                 ) {
+            throw new IndexOutOfBoundsException("offset "+off+", length "+len+", b.length "+b.length);
+        } else if ( 0 == len ) {
+            return 0;
+        }
+        final int totalRem = buf.remaining();
+        if ( 0 == totalRem ) {
+            return -1;
+        }
+        final int maxLen = Math.min(totalRem, len);
+        if( buf.hasArray() ) {
+            System.arraycopy(buf.array(), buf.arrayOffset() + buf.position(), b, off, maxLen);
+            buf.position( buf.position() + maxLen );
+        } else {
+            buf.get(b, off, maxLen);
+        }
+        return maxLen;
+    }
+
+    // @Override
+    public final int read(final ByteBuffer b, final int len) {
+        if (b == null) {
+            throw new NullPointerException();
+        } else if (len < 0 || len > b.remaining()) {
+            throw new IndexOutOfBoundsException("length "+len+", b "+b);
+        } else if ( 0 == len ) {
+            return 0;
+        }
+        final int remaining = buf.remaining();
+        if ( 0 == remaining ) {
+            return -1;
+        }
+        final int maxLen = Math.min(remaining, len);
+        if( buf.hasArray() && b.hasArray() ) {
+            System.arraycopy(buf.array(), buf.arrayOffset() + buf.position(), b.array(), b.arrayOffset() + b.position(), maxLen);
+            buf.position( buf.position() + maxLen );
+            b.position( b.position() + maxLen );
+        } else if( maxLen == remaining ) {
+            b.put(buf);
+        } else {
+            final int _limit = buf.limit();
+            buf.limit(maxLen);
+            try {
+                b.put(buf);
+            } finally {
+                buf.limit(_limit);
+            }
+        }
+        return maxLen;
+    }
+
+    public final ByteBuffer getBuffer() { return buf; }
+}
diff --git a/src/java/com/jogamp/common/nio/MappedByteBufferInputStream.java b/src/java/com/jogamp/common/nio/MappedByteBufferInputStream.java
new file mode 100644
index 0000000..f8d5857
--- /dev/null
+++ b/src/java/com/jogamp/common/nio/MappedByteBufferInputStream.java
@@ -0,0 +1,958 @@
+/**
+ * Copyright 2014 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.common.nio;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.RandomAccessFile;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileChannel.MapMode;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import jogamp.common.Debug;
+
+import com.jogamp.common.os.Platform;
+
+/**
+ * An {@link InputStream} implementation based on an underlying {@link FileChannel}'s memory mapped {@link ByteBuffer},
+ * {@link #markSupported() supporting} {@link #mark(int) mark} and {@link #reset()}.
+ * <p>
+ * Implementation allows full memory mapped {@link ByteBuffer} coverage via {@link FileChannel#map(MapMode, long, long) FileChannel}
+ * beyond its size limitation of {@link Integer#MAX_VALUE} utilizing an array of {@link ByteBuffer} slices.<br>
+ * </p>
+ * <p>
+ * Implementation further allows full random access via {@link #position()} and {@link #position(long)}
+ * and accessing the memory mapped {@link ByteBuffer} slices directly via {@link #currentSlice()} and {@link #nextSlice()}.
+ * </p>
+ * @since 2.3.0
+ */
+public class MappedByteBufferInputStream extends InputStream {
+    public static enum CacheMode {
+        /**
+         * Keep all previous lazily cached buffer slices alive, useful for hopping readers,
+         * i.e. random access via {@link MappedByteBufferInputStream#position(long) position(p)}
+         * or {@link MappedByteBufferInputStream#reset() reset()}.
+         * <p>
+         * Note that without flushing, the platform may fail memory mapping
+         * due to virtual address space exhaustion.<br>
+         * In such case an {@link OutOfMemoryError} may be thrown directly,
+         * or encapsulated as the {@link IOException#getCause() the cause}
+         * of a thrown {@link IOException}.
+         * </p>
+         */
+        FLUSH_NONE,
+        /**
+         * Soft flush the previous lazily cached buffer slice when caching the next buffer slice,
+         * useful for sequential forward readers, as well as for hopping readers like {@link #FLUSH_NONE}
+         * in case of relatively short periods between hopping across slices.
+         * <p>
+         * Implementation clears the buffer slice reference
+         * while preserving a {@link WeakReference} to allow its resurrection if not yet
+         * {@link System#gc() garbage collected}.
+         * </p>
+         */
+        FLUSH_PRE_SOFT,
+        /**
+         * Hard flush the previous lazily cached buffer slice when caching the next buffer slice,
+         * useful for sequential forward readers.
+         * <p>
+         * Besides clearing the buffer slice reference,
+         * implementation attempts to hard flush the mapped buffer
+         * using a {@code sun.misc.Cleaner} by reflection.
+         * In case such method does not exist nor works, implementation falls back to {@link #FLUSH_PRE_SOFT}.
+         * </p>
+         * <p>
+         * This is the default.
+         * </p>
+         */
+        FLUSH_PRE_HARD
+    };
+
+    /**
+     * File resize interface allowing a file to change its size,
+     * e.g. via {@link RandomAccessFile#setLength(long)}.
+     */
+    public static interface FileResizeOp {
+        /**
+         * @param newSize the new file size
+         * @throws IOException if file size change is not supported or any other I/O error occurs
+         */
+        void setLength(final long newSize) throws IOException;
+    }
+    private static final FileResizeOp NoFileResize = new FileResizeOp() {
+        @Override
+        public void setLength(final long newSize) throws IOException {
+            throw new IOException("file size change not supported");
+        }
+    };
+
+    /**
+     * Default slice shift, i.e. 1L << shift, denoting slice size in MiB:
+     * <ul>
+     *   <li>{@link Platform#is64Bit() 64bit machines} -> 30 = 1024 MiB</li>
+     *   <li>{@link Platform#is32Bit() 32bit machines} -> 29 = 512 MiB</li>
+     * </ul>
+     * <p>
+     * In case the default is too much of-used up address-space, one may choose other values:
+     * <ul>
+     *   <li>29 ->  512 MiB</li>
+     *   <li>28 ->  256 MiB</li>
+     *   <li>27 ->  128 MiB</li>
+     *   <li>26 ->   64 MiB</li>
+     * </ul>
+     * </p>
+     */
+    public static final int DEFAULT_SLICE_SHIFT;
+
+    static final boolean DEBUG;
+
+    static {
+        Platform.initSingleton();
+        if( Platform.is32Bit() ) {
+            DEFAULT_SLICE_SHIFT = 29;
+        } else {
+            DEFAULT_SLICE_SHIFT = 30;
+        }
+
+        DEBUG = Debug.debug("ByteBufferInputStream");
+    }
+
+    private final int sliceShift;
+    private final FileChannel fc;
+    private final FileChannel.MapMode mmode;
+    private FileResizeOp fileResizeOp = NoFileResize;
+
+    private int sliceCount;
+    private ByteBuffer[] slices;
+    private WeakReference<ByteBuffer>[] slices2GC;
+    private long totalSize;
+    private int slicesEntries, slices2GCEntries;
+    private boolean synchronous;
+
+    private int refCount;
+
+    private Method mbbCleaner;
+    private Method cClean;
+    private boolean cleanerInit;
+    private boolean hasCleaner;
+    private CacheMode cmode;
+
+    private int sliceIdx;
+    private long mark;
+
+    final void dbgDump(final String prefix, final PrintStream out) {
+        int _slicesEntries = 0;
+        for(int i=0; i<sliceCount; i++) {
+            if( null != slices[i] ) {
+                _slicesEntries++;
+            }
+        }
+        int _slices2GCEntries = 0;
+        int _slices2GCAliveEntries = 0;
+        for(int i=0; i<sliceCount; i++) {
+            final WeakReference<ByteBuffer> ref = slices2GC[i];
+            if( null != ref ) {
+                _slices2GCEntries++;
+                if( null != ref.get() ) {
+                    _slices2GCAliveEntries++;
+                }
+            }
+        }
+        long fcSz = 0, pos = 0, rem = 0;
+        try {
+            fcSz = fc.size();
+        } catch (final IOException e) {
+            e.printStackTrace();
+        }
+        if( 0 < refCount ) {
+            try {
+                pos = position();
+                rem = totalSize - pos;
+            } catch (final IOException e) {
+                e.printStackTrace();
+            }
+        }
+        final int sliceCount2 = null != slices ? slices.length : 0;
+        out.println(prefix+" refCount "+refCount+", fcSize "+fcSz+", totalSize "+totalSize);
+        out.println(prefix+" position "+pos+", remaining "+rem);
+        out.println(prefix+" mmode "+mmode+", cmode "+cmode+", fileResizeOp "+fileResizeOp);
+        out.println(prefix+" slice "+sliceIdx+" / "+sliceCount+" ("+sliceCount2+"), synchronous "+synchronous);
+        out.println(prefix+"   mapped   "+slicesEntries+" / "+_slicesEntries);
+        out.println(prefix+"   GC-queue "+slices2GCEntries+" / "+_slices2GCEntries+" (alive "+_slices2GCAliveEntries+")");
+        out.println(prefix+" sliceShift "+sliceShift+" -> "+(1L << sliceShift));
+    }
+
+    MappedByteBufferInputStream(final FileChannel fc, final FileChannel.MapMode mmode, final CacheMode cmode,
+                                final int sliceShift, final long totalSize, final int currSliceIdx) throws IOException {
+        this.sliceShift = sliceShift;
+        this.fc = fc;
+        this.mmode = mmode;
+
+        if( 0 > totalSize ) {
+            throw new IllegalArgumentException("Negative size "+totalSize);
+        }
+        // trigger notifyLengthChange
+        this.totalSize = -1;
+        this.sliceCount = 0;
+        notifyLengthChange( totalSize );
+
+        this.refCount = 1;
+        this.cleanerInit = false;
+        this.hasCleaner = false;
+        this.cmode = cmode;
+
+        this.sliceIdx = currSliceIdx;
+        this.mark = -1;
+
+        currentSlice().position(0);
+    }
+
+    /**
+     * Creates a new instance using the given {@link FileChannel}.
+     * <p>
+     * The {@link ByteBuffer} slices will be mapped lazily at first usage.
+     * </p>
+     * @param fileChannel the file channel to be mapped lazily.
+     * @param mmode the map mode, default is {@link FileChannel.MapMode#READ_ONLY}.
+     * @param cmode the caching mode, default is {@link CacheMode#FLUSH_PRE_HARD}.
+     * @param sliceShift the pow2 slice size, default is {@link #DEFAULT_SLICE_SHIFT}.
+     * @throws IOException
+     */
+    public MappedByteBufferInputStream(final FileChannel fileChannel,
+                                       final FileChannel.MapMode mmode,
+                                       final CacheMode cmode,
+                                       final int sliceShift) throws IOException {
+        this(fileChannel, mmode, cmode, sliceShift, fileChannel.size(), 0);
+    }
+
+    /**
+     * Creates a new instance using the given {@link FileChannel},
+     * given mapping-mode, given cache-mode and the {@link #DEFAULT_SLICE_SHIFT}.
+     * <p>
+     * The {@link ByteBuffer} slices will be mapped lazily at first usage.
+     * </p>
+     * @param fileChannel the file channel to be used.
+     * @param mmode the map mode, default is {@link FileChannel.MapMode#READ_ONLY}.
+     * @param cmode the caching mode, default is {@link CacheMode#FLUSH_PRE_HARD}.
+     * @throws IOException
+     */
+    public MappedByteBufferInputStream(final FileChannel fileChannel, final FileChannel.MapMode mmode, final CacheMode cmode) throws IOException {
+        this(fileChannel, mmode, cmode, DEFAULT_SLICE_SHIFT);
+    }
+
+    /**
+     * Creates a new instance using the given {@link FileChannel},
+     * {@link FileChannel.MapMode#READ_ONLY read-only} mapping mode, {@link CacheMode#FLUSH_PRE_HARD}
+     * and the {@link #DEFAULT_SLICE_SHIFT}.
+     * <p>
+     * The {@link ByteBuffer} slices will be mapped {@link FileChannel.MapMode#READ_ONLY} lazily at first usage.
+     * </p>
+     * @param fileChannel the file channel to be used.
+     * @throws IOException
+     */
+    public MappedByteBufferInputStream(final FileChannel fileChannel) throws IOException {
+        this(fileChannel, FileChannel.MapMode.READ_ONLY, CacheMode.FLUSH_PRE_HARD, DEFAULT_SLICE_SHIFT);
+    }
+
+    /**
+     * Enable or disable synchronous mode.
+     * <p>
+     * If synchronous mode is enabled, mapped buffers will be {@link #flush(boolean) flushed}
+     * if {@link #notifyLengthChange(long) resized}, <i>written to</i> or {@link #close() closing}  in {@link FileChannel.MapMode#READ_WRITE read-write} mapping mode.
+     * </p>
+     * <p>
+     * If synchronous mode is enabled, {@link FileChannel#force(boolean)} is issued
+     * if {@link #setLength(long) resizing} or {@link #close() closing} and not in {@link FileChannel.MapMode#READ_ONLY read-only} mapping mode.
+     * </p>
+     * @param s {@code true} to enable synchronous mode
+     */
+    public final synchronized void setSynchronous(final boolean s) {
+        synchronous = s;
+    }
+    /**
+     * Return {@link #setSynchronous(boolean) synchronous mode}.
+     */
+    public final synchronized boolean getSynchronous() {
+        return synchronous ;
+    }
+
+    final synchronized void checkOpen() throws IOException {
+        if( 0 == refCount ) {
+            throw new IOException("stream closed");
+        }
+    }
+
+    @Override
+    public final synchronized void close() throws IOException {
+        if( 0 < refCount ) {
+            refCount--;
+            if( 0 == refCount ) {
+                try {
+                    cleanAllSlices( true /* syncBuffer */ );
+                } finally {
+                    flushImpl(true /* metaData */, false /* syncBuffer */);
+                    fc.close();
+                    mark = -1;
+                    sliceIdx = -1;
+                    super.close();
+                }
+            }
+        }
+    }
+
+    final FileChannel.MapMode getMapMode() { return mmode; }
+
+    /**
+     * @param fileResizeOp the new {@link FileResizeOp}.
+     * @throws IllegalStateException if attempting to set the {@link FileResizeOp} to a different value than before
+     */
+    public final synchronized void setFileResizeOp(final FileResizeOp fileResizeOp) throws IllegalStateException {
+        if( NoFileResize != this.fileResizeOp && this.fileResizeOp != fileResizeOp ) {
+            throw new IllegalStateException("FileResizeOp already set, this value differs");
+        }
+        this.fileResizeOp = null != fileResizeOp ? fileResizeOp : NoFileResize;
+    }
+
+    /**
+     * Resize the underlying {@link FileChannel}'s size and adjusting this instance
+     * via {@link #notifyLengthChange(long) accordingly}.
+     * <p>
+     * User must have a {@link FileResizeOp} {@link #setFileResizeOp(FileResizeOp) registered} before.
+     * </p>
+     * <p>
+     * Implementation calls {@link #notifyLengthChange(long)} after {@link FileResizeOp#setLength(long)}.
+     * </p>
+     * @param newTotalSize the new total size
+     * @throws IOException if no {@link FileResizeOp} has been {@link #setFileResizeOp(FileResizeOp) registered}
+     *                     or if a buffer slice operation failed
+     */
+    public final synchronized void setLength(final long newTotalSize) throws IOException {
+        final long currentPosition;
+        if( 0 != newTotalSize &&  totalSize != newTotalSize ) {
+            currentPosition = position();
+        } else {
+            currentPosition = -1L;
+        }
+        if( fc.size() != newTotalSize ) {
+            if( Platform.OSType.WINDOWS == Platform.getOSType() ) {
+                // On Windows, we have to close all mapped slices.
+                // Otherwise we will receive:
+                // java.io.IOException: The requested operation cannot be performed on a file with a user-mapped section open
+                //      at java.io.RandomAccessFile.setLength(Native Method)
+                cleanAllSlices( synchronous );
+            }
+            fileResizeOp.setLength(newTotalSize);
+            if( synchronous ) {
+                // buffers will be synchronized in notifyLengthChangeImpl(..)
+                flushImpl( true /* metaData */, false /* syncBuffer */);
+            }
+        }
+        notifyLengthChangeImpl(newTotalSize, currentPosition);
+    }
+
+    /**
+     * Notify this instance that the underlying {@link FileChannel}'s size has been changed
+     * and adjusting this instances buffer slices and states accordingly.
+     * <p>
+     * Should be called by user API when aware of such event.
+     * </p>
+     * @param newTotalSize the new total size
+     * @throws IOException if a buffer slice operation failed
+     */
+    public final synchronized void notifyLengthChange(final long newTotalSize) throws IOException {
+        notifyLengthChangeImpl(newTotalSize, -1L);
+    }
+    private final synchronized void notifyLengthChangeImpl(final long newTotalSize, final long currentPosition) throws IOException {
+        /* if( DEBUG ) {
+            System.err.println("notifyLengthChange.0: "+totalSize+" -> "+newTotalSize);
+            dbgDump("notifyLengthChange.0:", System.err);
+        } */
+        if( totalSize == newTotalSize ) {
+            // NOP
+            return;
+        } else if( 0 == newTotalSize ) {
+            // ZERO - ensure one entry avoiding NULL checks
+            cleanAllSlices( synchronous );
+            @SuppressWarnings("unchecked")
+            final WeakReference<ByteBuffer>[] newSlices2GC = new WeakReference[ 1 ];
+            slices2GC = newSlices2GC;
+            slices = new ByteBuffer[1];
+            slices[0] = ByteBuffer.allocate(0);
+            sliceCount = 0;
+            totalSize = 0;
+            mark = -1;
+            sliceIdx = 0;
+        } else {
+            final long prePosition = 0 <= currentPosition ? currentPosition : position();
+
+            final long sliceSize = 1L << sliceShift;
+            final int newSliceCount = (int)( ( newTotalSize + ( sliceSize - 1 ) ) / sliceSize );
+            @SuppressWarnings("unchecked")
+            final WeakReference<ByteBuffer>[] newSlices2GC = new WeakReference[ newSliceCount ];
+            final ByteBuffer[] newSlices = new ByteBuffer[ newSliceCount ];
+            final int copySliceCount = Math.min(newSliceCount, sliceCount-1); // drop last (resize)
+            if( 0 <= copySliceCount ) {
+                if( 0 < copySliceCount ) {
+                    System.arraycopy(slices2GC, 0, newSlices2GC, 0, copySliceCount);
+                    System.arraycopy(slices,    0, newSlices,    0, copySliceCount);
+                }
+                for(int i=copySliceCount; i<sliceCount; i++) { // clip shrunken slices + 1 (last), incl. slices2GC!
+                    cleanSlice(i, synchronous);
+                }
+            }
+            slices2GC = newSlices2GC;
+            slices = newSlices;
+            sliceCount = newSliceCount;
+            totalSize = newTotalSize;
+            if( newTotalSize < mark ) {
+                mark = -1;
+            }
+            position2( Math.min(prePosition, newTotalSize) ); // -> clipped position (set currSlice and re-map/-pos buffer)
+        }
+        /* if( DEBUG ) {
+            System.err.println("notifyLengthChange.X: "+slices[currSlice]);
+            dbgDump("notifyLengthChange.X:", System.err);
+        } */
+    }
+
+    /**
+     * Similar to {@link OutputStream#flush()}, synchronizes all mapped buffers
+     * from local storage via {@link MappedByteBuffer#force()}
+     * as well as the {@link FileChannel#force(boolean)} w/o {@code metaData}.
+     * @param metaData TODO
+     * @throws IOException if this stream has been {@link #close() closed}.
+     */
+    public final synchronized void flush(final boolean metaData) throws IOException {
+        checkOpen();
+        flushImpl(metaData, true);
+    }
+    private final synchronized void flushImpl(final boolean metaData, final boolean syncBuffer) throws IOException {
+        if( FileChannel.MapMode.READ_ONLY != mmode ) {
+            if( syncBuffer && FileChannel.MapMode.READ_WRITE == mmode ) {
+                for(int i=0; i<sliceCount; i++) {
+                    syncSlice(slices[i], true);
+                }
+                for(int i=0; i<sliceCount; i++) {
+                    final WeakReference<ByteBuffer> ref = slices2GC[i];
+                    if( null != ref ) {
+                        syncSlice(ref.get(), true);
+                    }
+                }
+            }
+            fc.force(metaData);
+        }
+    }
+
+
+    /**
+     * Returns a new MappedByteBufferOutputStream instance sharing
+     * all resources of this input stream, including all buffer slices.
+     *
+     * @throws IllegalStateException if attempting to set the {@link FileResizeOp} to a different value than before
+     * @throws IOException if this instance was opened w/ {@link FileChannel.MapMode#READ_ONLY}
+     *                     or if this stream has been {@link #close() closed}.
+     */
+    public final synchronized MappedByteBufferOutputStream getOutputStream(final FileResizeOp fileResizeOp)
+            throws IllegalStateException, IOException
+    {
+        checkOpen();
+        final MappedByteBufferOutputStream res = new MappedByteBufferOutputStream(this, fileResizeOp);
+        refCount++;
+        return res;
+    }
+
+    /**
+     * Return the mapped {@link ByteBuffer} slice at the current {@link #position()}.
+     * <p>
+     * Due to the nature of using sliced buffers mapping the whole region,
+     * user has to determine whether the returned buffer covers the desired region
+     * and may fetch the {@link #nextSlice()} until satisfied.<br>
+     * It is also possible to repeat this operation after reposition the stream via {@link #position(long)}
+     * or {@link #skip(long)} to a position within the next block, similar to {@link #nextSlice()}.
+     * </p>
+     * @throws IOException if a buffer slice operation failed.
+     */
+    public final synchronized ByteBuffer currentSlice() throws IOException {
+        final ByteBuffer s0 = slices[sliceIdx];
+        if ( null != s0 ) {
+            return s0;
+        } else {
+            if( CacheMode.FLUSH_PRE_SOFT == cmode ) {
+                final WeakReference<ByteBuffer> ref = slices2GC[sliceIdx];
+                if( null != ref ) {
+                    final ByteBuffer mbb = ref.get();
+                    slices2GC[sliceIdx] = null;
+                    slices2GCEntries--;
+                    if( null != mbb ) {
+                        slices[sliceIdx] = mbb;
+                        slicesEntries++;
+                        return mbb;
+                    }
+                }
+            }
+            final long pos = (long)sliceIdx << sliceShift;
+            final MappedByteBuffer s1 = fc.map(mmode, pos, Math.min(1L << sliceShift, totalSize - pos));
+            slices[sliceIdx] = s1;
+            slicesEntries++;
+            return s1;
+        }
+    }
+
+    /**
+     * Return the <i>next</i> mapped {@link ByteBuffer} slice from the current {@link #position()},
+     * implicitly setting {@link #position(long)} to the start of the returned <i>next</i> slice,
+     * see {@link #currentSlice()}.
+     * <p>
+     * If no subsequent slice is available, {@code null} is being returned.
+     * </p>
+     * @throws IOException if a buffer slice operation failed.
+     */
+    public final synchronized ByteBuffer nextSlice() throws IOException {
+        if ( sliceIdx < sliceCount - 1 ) {
+            flushSlice(sliceIdx, synchronous);
+            sliceIdx++;
+            final ByteBuffer slice = currentSlice();
+            slice.position( 0 );
+            return slice;
+        } else {
+            return null;
+        }
+    }
+
+    synchronized void syncSlice(final ByteBuffer s) throws IOException {
+        syncSlice(s, synchronous);
+    }
+    synchronized void syncSlice(final ByteBuffer s, final boolean syncBuffer) throws IOException {
+        if( syncBuffer && null != s && FileChannel.MapMode.READ_WRITE == mmode ) {
+            try {
+                ((MappedByteBuffer)s).force();
+            } catch( final Throwable t ) {
+                // On Windows .. this may happen, like:
+                // java.io.IOException: The process cannot access the file because another process has locked a portion of the file
+                //   at java.nio.MappedByteBuffer.force0(Native Method)
+                //   at java.nio.MappedByteBuffer.force(MappedByteBuffer.java:203)
+                if( DEBUG ) {
+                    System.err.println("Caught "+t.getMessage());
+                    t.printStackTrace();
+                }
+            }
+        }
+    }
+    private synchronized void flushSlice(final int i, final boolean syncBuffer) throws IOException {
+        final ByteBuffer s = slices[i];
+        if ( null != s ) {
+            if( CacheMode.FLUSH_NONE != cmode ) {
+                slices[i] = null; // trigger slice GC
+                slicesEntries--;
+                if( CacheMode.FLUSH_PRE_HARD == cmode ) {
+                    if( !cleanBuffer(s, syncBuffer) ) {
+                        // buffer already synced in cleanBuffer(..) if requested
+                        slices2GC[i] = new WeakReference<ByteBuffer>(s);
+                        slices2GCEntries++;
+                    }
+                } else {
+                    syncSlice(s, syncBuffer);
+                    slices2GC[i] = new WeakReference<ByteBuffer>(s);
+                    slices2GCEntries++;
+                }
+            } else {
+                syncSlice(s, syncBuffer);
+            }
+        }
+    }
+    private synchronized void cleanAllSlices(final boolean syncBuffers) throws IOException {
+        if( null != slices ) {
+            for(int i=0; i<sliceCount; i++) {
+                cleanSlice(i, syncBuffers);
+            }
+            if( 0 != slicesEntries || 0 != slices2GCEntries ) { // FIXME
+                final String err = "mappedSliceCount "+slicesEntries+", slices2GCEntries "+slices2GCEntries;
+                dbgDump(err+": ", System.err);
+                throw new InternalError(err);
+            }
+        }
+    }
+
+    private synchronized void cleanSlice(final int i, final boolean syncBuffer) throws IOException {
+        final ByteBuffer s1 = slices[i];
+        final ByteBuffer s2;
+        {
+            final WeakReference<ByteBuffer> ref = slices2GC[i];
+            slices2GC[i] = null;
+            if( null != ref ) {
+                slices2GCEntries--;
+                s2 = ref.get();
+            } else {
+                s2 = null;
+            }
+        }
+        if( null != s1 ) {
+            slices[i] = null;
+            slicesEntries--;
+            cleanBuffer(s1, syncBuffer);
+            if( null != s2 ) {
+                throw new InternalError("XXX");
+            }
+        } else if( null != s2 ) {
+            cleanBuffer(s2, syncBuffer);
+        }
+    }
+    private synchronized boolean cleanBuffer(final ByteBuffer mbb, final boolean syncBuffer) throws IOException {
+        if( !cleanerInit ) {
+            initCleaner(mbb);
+        }
+        syncSlice(mbb, syncBuffer);
+        if( !mbb.isDirect() ) {
+            return false;
+        }
+        boolean res = false;
+        if ( hasCleaner ) {
+            try {
+                cClean.invoke(mbbCleaner.invoke(mbb));
+                res = true;
+            } catch(final Throwable t) {
+                hasCleaner = false;
+                if( DEBUG ) {
+                    System.err.println("Caught "+t.getMessage());
+                    t.printStackTrace();
+                }
+            }
+        }
+        if( !res && CacheMode.FLUSH_PRE_HARD == cmode ) {
+            cmode = CacheMode.FLUSH_PRE_SOFT;
+        }
+        return res;
+    }
+    private synchronized void initCleaner(final ByteBuffer bb) {
+        final Method[] _mbbCleaner = { null };
+        final Method[] _cClean = { null };
+        AccessController.doPrivileged(new PrivilegedAction<Object>() {
+            @Override
+            public Object run() {
+                try {
+                    _mbbCleaner[0] = bb.getClass().getMethod("cleaner");
+                    _mbbCleaner[0].setAccessible(true);
+                    _cClean[0] = Class.forName("sun.misc.Cleaner").getMethod("clean");
+                    _cClean[0].setAccessible(true);
+                } catch(final Throwable t) {
+                    if( DEBUG ) {
+                        System.err.println("Caught "+t.getMessage());
+                        t.printStackTrace();
+                    }
+                }
+                return null;
+            } } );
+        mbbCleaner = _mbbCleaner[0];
+        cClean = _cClean[0];
+        final boolean res = null != mbbCleaner && null != cClean;
+        if( DEBUG ) {
+            System.err.println("initCleaner: Has cleaner: "+res+", mbbCleaner "+mbbCleaner+", cClean "+cClean);
+        }
+        hasCleaner = res;
+        cleanerInit = true;
+    }
+
+    /**
+     * Return the used {@link CacheMode}.
+     * <p>
+     * If a desired {@link CacheMode} is not available, it may fall back to an available one at runtime,
+     * see {@link CacheMode#FLUSH_PRE_HARD}.<br>
+     * This evaluation only happens if the {@link CacheMode} != {@link CacheMode#FLUSH_NONE}
+     * and while attempting to flush an unused buffer slice.
+     * </p>
+     */
+    public final synchronized CacheMode getCacheMode() { return cmode; }
+
+    /**
+     * Returns the total size in bytes of the {@link InputStream}
+     * <pre>
+     *   <code>0 <= {@link #position()} <= {@link #length()}</code>
+     * </pre>
+     */
+    // @Override
+    public final synchronized long length() {
+        return totalSize;
+    }
+
+    /**
+     * Returns the number of remaining available bytes of the {@link InputStream},
+     * i.e. <code>{@link #length()} - {@link #position()}</code>.
+     * <pre>
+     *   <code>0 <= {@link #position()} <= {@link #length()}</code>
+     * </pre>
+     * <p>
+     * In contrast to {@link InputStream}'s {@link #available()} method,
+     * this method returns the proper return type {@code long}.
+     * </p>
+     * @throws IOException if a buffer slice operation failed.
+     */
+    public final synchronized long remaining() throws IOException {
+        return 0 < refCount ? totalSize - position() : 0;
+    }
+
+    /**
+     * <i>See {@link #remaining()} for an accurate variant.</i>
+     * <p>
+     * {@inheritDoc}
+     * </p>
+     * @throws IOException if a buffer slice operation failed.
+     */
+    @Override
+    public final synchronized int available() throws IOException {
+        final long available = remaining();
+        return available <= Integer.MAX_VALUE ? (int)available : Integer.MAX_VALUE;
+    }
+
+    /**
+     * Returns the absolute position of the {@link InputStream}.
+     * <pre>
+     *   <code>0 <= {@link #position()} <= {@link #length()}</code>
+     * </pre>
+     * @throws IOException if a buffer slice operation failed.
+     */
+    // @Override
+    public final synchronized long position() throws IOException {
+        if( 0 < refCount ) {
+            return ( (long)sliceIdx << sliceShift ) + currentSlice().position();
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Sets the absolute position of the {@link InputStream} to {@code newPosition}.
+     * <pre>
+     *   <code>0 <= {@link #position()} <= {@link #length()}</code>
+     * </pre>
+     * @param newPosition The new position, which must be non-negative and ≤ {@link #length()}.
+     * @return this instance
+     * @throws IOException if a buffer slice operation failed or stream is {@link #close() closed}.
+     */
+    // @Override
+    public final synchronized MappedByteBufferInputStream position( final long newPosition ) throws IOException {
+        checkOpen();
+        if ( totalSize < newPosition || 0 > newPosition ) {
+            throw new IllegalArgumentException("new position "+newPosition+" not within [0.."+totalSize+"]");
+        }
+        final int preSlice = sliceIdx;
+
+        if ( totalSize == newPosition ) {
+            // EOF, pos == maxPos + 1
+            sliceIdx = Math.max(0, sliceCount - 1); // handle zero size
+            if( preSlice != sliceIdx ) {
+                flushSlice(preSlice, synchronous);
+            }
+            final ByteBuffer s = currentSlice();
+            s.position( s.capacity() );
+        } else {
+            sliceIdx = (int)( newPosition >>> sliceShift );
+            if( preSlice != sliceIdx ) {
+                flushSlice(preSlice, synchronous);
+            }
+            currentSlice().position( (int)( newPosition - ( (long)sliceIdx << sliceShift ) ) );
+        }
+        return this;
+    }
+    private final synchronized void position2( final long newPosition ) throws IOException {
+        if ( totalSize == newPosition ) {
+            // EOF, pos == maxPos + 1
+            sliceIdx = Math.max(0, sliceCount - 1); // handle zero size
+            final ByteBuffer s = currentSlice();
+            s.position( s.capacity() );
+        } else {
+            sliceIdx = (int)( newPosition >>> sliceShift );
+            currentSlice().position( (int)( newPosition - ( (long)sliceIdx << sliceShift ) ) );
+        }
+    }
+
+    @Override
+    public final boolean markSupported() {
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * <i>Parameter {@code readLimit} is not used in this implementation,
+     * since the whole file is memory mapped and no read limitation occurs.</i>
+     * </p>
+     */
+    @Override
+    public final synchronized void mark( final int readlimit ) {
+        if( 0 < refCount ) {
+            try {
+                mark = position();
+            } catch (final IOException e) {
+                throw new RuntimeException(e); // FIXME: oops
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws IOException if this stream has not been marked,
+     *                     a buffer slice operation failed or stream has been {@link #close() closed}.
+     */
+    @Override
+    public final synchronized void reset() throws IOException {
+        checkOpen();
+        if ( mark == -1 ) {
+            throw new IOException("mark not set");
+        }
+        position( mark );
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws IOException if a buffer slice operation failed or stream is {@link #close() closed}.
+     */
+    @Override
+    public final synchronized long skip( final long n ) throws IOException {
+        checkOpen();
+        if( 0 > n ) {
+            return 0;
+        }
+        final long pos = position();
+        final long rem = totalSize - pos; // remaining
+        final long s = Math.min( rem, n );
+        position( pos + s );
+        return s;
+    }
+
+    @Override
+    public final synchronized int read() throws IOException {
+        checkOpen();
+        ByteBuffer slice = currentSlice();
+        if ( !slice.hasRemaining() ) {
+            if ( null == ( slice = nextSlice() ) ) {
+                return -1;
+            }
+        }
+        return slice.get() & 0xFF;
+    }
+
+    @Override
+    public final synchronized int read( final byte[] b, final int off, final int len ) throws IOException {
+        checkOpen();
+        if (b == null) {
+            throw new NullPointerException();
+        } else if( off < 0 ||
+                   len < 0 ||
+                   off > b.length ||
+                   off + len > b.length ||
+                   off + len < 0
+                 ) {
+            throw new IndexOutOfBoundsException("offset "+off+", length "+len+", b.length "+b.length);
+        } else if ( 0 == len ) {
+            return 0;
+        }
+        final long totalRem = remaining();
+        if ( 0 == totalRem ) {
+            return -1;
+        }
+        final int maxLen = (int)Math.min( totalRem, len );
+        int read = 0;
+        while( read < maxLen ) {
+            ByteBuffer slice = currentSlice();
+            int currRem = slice.remaining();
+            if ( 0 == currRem ) {
+                if ( null == ( slice = nextSlice() ) ) {
+                    throw new InternalError("Unexpected EOT");
+                }
+                currRem = slice.remaining();
+            }
+            final int currLen = Math.min( maxLen - read, currRem );
+            slice.get( b, off + read, currLen );
+            read += currLen;
+        }
+        return maxLen;
+    }
+
+    /**
+     * Perform similar to {@link #read(byte[], int, int)}
+     * with {@link ByteBuffer} instead of byte array.
+     * @param b the {@link ByteBuffer} sink, data is written at current {@link ByteBuffer#position()}
+     * @param len the number of bytes to read
+     * @return the number of bytes read, -1 for EOS
+     * @throws IOException if a buffer slice operation failed or stream has been {@link #close() closed}.
+     */
+    // @Override
+    public final synchronized int read(final ByteBuffer b, final int len) throws IOException {
+        checkOpen();
+        if (b == null) {
+            throw new NullPointerException();
+        } else if (len < 0 || len > b.remaining()) {
+            throw new IndexOutOfBoundsException("length "+len+", b "+b);
+        } else if ( 0 == len ) {
+            return 0;
+        }
+        final long totalRem = remaining();
+        if ( 0 == totalRem ) {
+            return -1;
+        }
+        final int maxLen = (int)Math.min( totalRem, len );
+        int read = 0;
+        while( read < maxLen ) {
+            ByteBuffer slice = currentSlice();
+            int currRem = slice.remaining();
+            if ( 0 == currRem ) {
+                if ( null == ( slice = nextSlice() ) ) {
+                    throw new InternalError("Unexpected EOT");
+                }
+                currRem = slice.remaining();
+            }
+            final int currLen = Math.min( maxLen - read, currRem );
+            if( slice.hasArray() && b.hasArray() ) {
+                System.arraycopy(slice.array(), slice.arrayOffset() + slice.position(),
+                                 b.array(), b.arrayOffset() + b.position(),
+                                 currLen);
+                slice.position( slice.position() + currLen );
+                b.position( b.position() + currLen );
+            } else if( currLen == currRem ) {
+                b.put(slice);
+            } else {
+                final int _limit = slice.limit();
+                slice.limit(currLen);
+                try {
+                    b.put(slice);
+                } finally {
+                    slice.limit(_limit);
+                }
+            }
+            read += currLen;
+        }
+        return maxLen;
+    }
+}
diff --git a/src/java/com/jogamp/common/nio/MappedByteBufferOutputStream.java b/src/java/com/jogamp/common/nio/MappedByteBufferOutputStream.java
new file mode 100644
index 0000000..8adf0e4
--- /dev/null
+++ b/src/java/com/jogamp/common/nio/MappedByteBufferOutputStream.java
@@ -0,0 +1,351 @@
+/**
+ * Copyright 2014 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.common.nio;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileChannel.MapMode;
+
+import com.jogamp.common.nio.MappedByteBufferInputStream.CacheMode;
+import com.jogamp.common.nio.MappedByteBufferInputStream.FileResizeOp;
+
+/**
+ * An {@link OutputStream} implementation based on an underlying {@link FileChannel}'s memory mapped {@link ByteBuffer}.
+ * <p>
+ * Implementation is based on {@link MappedByteBufferInputStream}, using it as its parent instance.
+ * </p>
+ * <p>
+ * An instance maybe created via its parent {@link MappedByteBufferInputStream#getOutputStream(FileResizeOp)}
+ * or directly {@link #MappedByteBufferOutputStream(FileChannel, MapMode, CacheMode, int, FileResizeOp)}.
+ * </p>
+ * @since 2.3.0
+ */
+public class MappedByteBufferOutputStream extends OutputStream {
+    private final MappedByteBufferInputStream parent;
+
+    MappedByteBufferOutputStream(final MappedByteBufferInputStream parent,
+                                 final FileResizeOp fileResizeOp) throws IOException {
+        if( FileChannel.MapMode.READ_ONLY == parent.getMapMode() ) {
+            throw new IOException("FileChannel map-mode is read-only");
+        }
+        this.parent = parent;
+        this.parent.setFileResizeOp(fileResizeOp);
+    }
+
+    /**
+     * Creates a new instance using the given {@link FileChannel}.
+     * <p>
+     * The {@link ByteBuffer} slices will be mapped lazily at first usage.
+     * </p>
+     * @param fileChannel the file channel to be mapped lazily.
+     * @param mmode the map mode, default is {@link FileChannel.MapMode#READ_WRITE}.
+     * @param cmode the caching mode, default is {@link MappedByteBufferInputStream.CacheMode#FLUSH_PRE_SOFT}.
+     * @param sliceShift the pow2 slice size, default is {@link MappedByteBufferInputStream#DEFAULT_SLICE_SHIFT}.
+     * @param fileResizeOp {@link MappedByteBufferInputStream.FileResizeOp} as described on {@link MappedByteBufferInputStream#setFileResizeOp(FileResizeOp)}.
+     * @throws IOException
+     */
+    public MappedByteBufferOutputStream(final FileChannel fileChannel,
+                                        final FileChannel.MapMode mmode,
+                                        final CacheMode cmode,
+                                        final int sliceShift, final FileResizeOp fileResizeOp) throws IOException {
+        this(new MappedByteBufferInputStream(fileChannel, mmode, cmode, sliceShift, fileChannel.size(), 0), fileResizeOp);
+    }
+
+    /**
+     * See {@link MappedByteBufferInputStream#setSynchronous(boolean)}.
+     */
+    public final synchronized void setSynchronous(final boolean s) {
+        parent.setSynchronous(s);
+    }
+    /**
+     * See {@link MappedByteBufferInputStream#getSynchronous()}.
+     */
+    public final synchronized boolean getSynchronous() {
+        return parent.getSynchronous();
+    }
+
+    /**
+     * See {@link MappedByteBufferInputStream#setLength(long)}.
+     */
+    public final synchronized void setLength(final long newTotalSize) throws IOException {
+        parent.setLength(newTotalSize);
+    }
+
+    /**
+     * See {@link MappedByteBufferInputStream#notifyLengthChange(long)}.
+     */
+    public final synchronized void notifyLengthChange(final long newTotalSize) throws IOException {
+        parent.notifyLengthChange(newTotalSize);
+    }
+
+    /**
+     * See {@link MappedByteBufferInputStream#length()}.
+     */
+    public final synchronized long length() {
+        return parent.length();
+    }
+
+    /**
+     * See {@link MappedByteBufferInputStream#remaining()}.
+     */
+    public final synchronized long remaining() throws IOException {
+        return parent.remaining();
+    }
+
+    /**
+     * See {@link MappedByteBufferInputStream#position()}.
+     */
+    public final synchronized long position() throws IOException {
+        return parent.position();
+    }
+
+    /**
+     * See {@link MappedByteBufferInputStream#position(long)}.
+     */
+    public final synchronized MappedByteBufferInputStream position( final long newPosition ) throws IOException {
+        return parent.position(newPosition);
+    }
+
+    /**
+     * See {@link MappedByteBufferInputStream#skip(long)}.
+     */
+    public final synchronized long skip( final long n ) throws IOException {
+        return parent.skip(n);
+    }
+
+    @Override
+    public final synchronized void flush() throws IOException {
+        parent.flush( true /* metaData */);
+    }
+
+    /**
+     * See {@link MappedByteBufferInputStream#flush(boolean)}.
+     */
+    // @Override
+    public final synchronized void flush(final boolean metaData) throws IOException {
+        parent.flush(metaData);
+    }
+
+    @Override
+    public final synchronized void close() throws IOException {
+        parent.close();
+    }
+
+    @Override
+    public final synchronized void write(final int b) throws IOException {
+        parent.checkOpen();
+        final long totalRem = parent.remaining();
+        if ( totalRem < 1 ) { // grow if required
+            parent.setLength( parent.length() + 1 );
+        }
+        ByteBuffer slice = parent.currentSlice();
+        final int currRem = slice.remaining();
+        if ( 0 == currRem ) {
+            if ( null == ( slice = parent.nextSlice() ) ) {
+                if( MappedByteBufferInputStream.DEBUG ) {
+                    System.err.println("EOT write: "+parent.currentSlice());
+                    parent.dbgDump("EOT write:", System.err);
+                }
+                throw new IOException("EOT"); // 'end-of-tape'
+            }
+        }
+        slice.put( (byte)(b & 0xFF) );
+
+        // sync last buffer (happens only in synchronous mode)
+        if( null != slice ) {
+            parent.syncSlice(slice);
+        }
+    }
+
+    @Override
+    public final synchronized void write(final byte b[], final int off, final int len) throws IOException {
+        parent.checkOpen();
+        if (b == null) {
+            throw new NullPointerException();
+        } else if( off < 0 ||
+                   len < 0 ||
+                   off > b.length ||
+                   off + len > b.length ||
+                   off + len < 0
+                 ) {
+            throw new IndexOutOfBoundsException("offset "+off+", length "+len+", b.length "+b.length);
+        } else if( 0 == len ) {
+            return;
+        }
+        final long totalRem = parent.remaining();
+        if ( totalRem < len ) { // grow if required
+            parent.setLength( parent.length() + len - totalRem );
+        }
+        int written = 0;
+        ByteBuffer slice = null;
+        while( written < len ) {
+            slice = parent.currentSlice();
+            int currRem = slice.remaining();
+            if ( 0 == currRem ) {
+                if ( null == ( slice = parent.nextSlice() ) ) {
+                    if( MappedByteBufferInputStream.DEBUG ) {
+                        System.err.println("EOT write: offset "+off+", length "+len+", b.length "+b.length);
+                        System.err.println("EOT write: written "+written+" / "+len+", currRem "+currRem);
+                        System.err.println("EOT write: "+parent.currentSlice());
+                        parent.dbgDump("EOT write:", System.err);
+                    }
+                    throw new InternalError("EOT"); // 'end-of-tape'
+                }
+                currRem = slice.remaining();
+            }
+            final int currLen = Math.min( len - written, currRem );
+            slice.put( b, off + written, currLen );
+            written += currLen;
+        }
+        // sync last buffer (happens only in synchronous mode)
+        if( null != slice ) {
+            parent.syncSlice(slice);
+        }
+    }
+
+    /**
+     * Perform similar to {@link #write(byte[], int, int)}
+     * with {@link ByteBuffer} instead of byte array.
+     * @param b the {@link ByteBuffer} source, data is read from current {@link ByteBuffer#position()}
+     * @param len the number of bytes to write
+     * @throws IOException if a buffer slice operation failed or stream has been {@link #close() closed}.
+     */
+    // @Override
+    public final synchronized void write(final ByteBuffer b, final int len) throws IOException {
+        parent.checkOpen();
+        if (b == null) {
+            throw new NullPointerException();
+        } else if (len < 0 || len > b.remaining()) {
+            throw new IndexOutOfBoundsException("length "+len+", b "+b);
+        } else if( 0 == len ) {
+            return;
+        }
+        final long totalRem = parent.remaining();
+        if ( totalRem < len ) { // grow if required
+            parent.setLength( parent.length() + len - totalRem );
+        }
+        int written = 0;
+        ByteBuffer slice = null;
+        while( written < len ) {
+            slice = parent.currentSlice();
+            int currRem = slice.remaining();
+            if ( 0 == currRem ) {
+                if ( null == ( slice = parent.nextSlice() ) ) {
+                    if( MappedByteBufferInputStream.DEBUG ) {
+                        System.err.println("EOT write: length "+len+", b "+b);
+                        System.err.println("EOT write: written "+written+" / "+len+", currRem "+currRem);
+                        System.err.println("EOT write: "+parent.currentSlice());
+                        parent.dbgDump("EOT write:", System.err);
+                    }
+                    throw new InternalError("EOT"); // 'end-of-tape'
+                }
+                currRem = slice.remaining();
+            }
+            final int currLen = Math.min( len - written, currRem );
+
+            if( slice.hasArray() && b.hasArray() ) {
+                System.arraycopy(b.array(), b.arrayOffset() + b.position(),
+                                 slice.array(), slice.arrayOffset() + slice.position(),
+                                 currLen);
+                b.position( b.position() + currLen );
+                slice.position( slice.position() + currLen );
+            } else if( currLen == currRem ) {
+                slice.put(b);
+            } else {
+                final int _limit = b.limit();
+                b.limit(currLen);
+                try {
+                    slice.put(b);
+                } finally {
+                    b.limit(_limit);
+                }
+            }
+            written += currLen;
+        }
+        // sync last buffer (happens only in synchronous mode)
+        if( null != slice ) {
+            parent.syncSlice(slice);
+        }
+    }
+
+    /**
+     * Perform similar to {@link #write(ByteBuffer, int)}
+     * with {@link MappedByteBufferInputStream} instead of byte array.
+     * <p>
+     * Method directly copies memory mapped {@link ByteBuffer}'ed data
+     * from the given input stream to this stream without extra data copy.
+     * </p>
+     * @param b the {@link ByteBuffer} source, data is read from current {@link MappedByteBufferInputStream#position()}
+     * @param len the number of bytes to write
+     * @throws IOException if a buffer slice operation failed or stream has been {@link #close() closed}.
+     */
+    // @Override
+    public final synchronized void write(final MappedByteBufferInputStream b, final long len) throws IOException {
+        parent.checkOpen();
+        if (b == null) {
+            throw new NullPointerException();
+        } else if (len < 0 || len > b.remaining()) {
+            throw new IndexOutOfBoundsException("length "+len+", b "+b);
+        } else if( 0 == len ) {
+            return;
+        }
+        final long totalRem = parent.remaining();
+        if ( totalRem < len ) { // grow if required
+            parent.setLength( parent.length() + len - totalRem );
+        }
+        long written = 0;
+        ByteBuffer slice = null;
+        while( written < len ) {
+            slice = parent.currentSlice();
+            int currRem = slice.remaining();
+            if ( 0 == currRem ) {
+                if ( null == ( slice = parent.nextSlice() ) ) {
+                    if( MappedByteBufferInputStream.DEBUG ) {
+                        System.err.println("EOT write: length "+len+", b "+b);
+                        System.err.println("EOT write: written "+written+" / "+len+", currRem "+currRem);
+                        System.err.println("EOT write: "+parent.currentSlice());
+                        parent.dbgDump("EOT write:", System.err);
+                    }
+                    throw new InternalError("EOT"); // 'end-of-tape'
+                }
+                currRem = slice.remaining();
+            }
+            final int currLen = b.read(slice, (int)Math.min( len - written, currRem ));
+            if( 0 > currLen ) {
+                throw new InternalError("Unexpected InputStream EOT"); // 'end-of-tape'
+            }
+            written += currLen;
+        }
+        // sync last buffer (happens only in synchronous mode)
+        if( null != slice ) {
+            parent.syncSlice(slice);
+        }
+    }
+}
diff --git a/src/java/com/jogamp/common/nio/StructAccessor.java b/src/java/com/jogamp/common/nio/StructAccessor.java
index af7b6d1..8ae0c29 100644
--- a/src/java/com/jogamp/common/nio/StructAccessor.java
+++ b/src/java/com/jogamp/common/nio/StructAccessor.java
@@ -83,6 +83,16 @@ public class StructAccessor {
         bb.put(byteOffset, v);
     }
 
+    /** Retrieves the boolean at the specified byteOffset. */
+    public final boolean getBooleanAt(final int byteOffset) {
+        return (byte)0 != bb.get(byteOffset);
+    }
+
+    /** Puts a boolean at the specified byteOffset. */
+    public final void setBooleanAt(final int byteOffset, final boolean v) {
+        bb.put(byteOffset, v?(byte)1:(byte)0);
+    }
+
     /** Retrieves the char at the specified byteOffset. */
     public final char getCharAt(final int byteOffset) {
         return bb.getChar(byteOffset);
@@ -213,6 +223,19 @@ public class StructAccessor {
         return v;
     }
 
+    public final void setBooleansAt(int byteOffset, final boolean[] v) {
+        for (int i = 0; i < v.length; i++) {
+            bb.put(byteOffset++, v[i]?(byte)1:(byte)0);
+        }
+    }
+
+    public final boolean[] getBooleansAt(int byteOffset, final boolean[] v) {
+        for (int i = 0; i < v.length; i++) {
+            v[i] = (byte)0 != bb.get(byteOffset++);
+        }
+        return v;
+    }
+
     public final void setCharsAt(int byteOffset, final char[] v) {
         for (int i = 0; i < v.length; i++, byteOffset+=2) {
             bb.putChar(byteOffset, v[i]);
diff --git a/src/java/com/jogamp/common/os/AndroidVersion.java b/src/java/com/jogamp/common/os/AndroidVersion.java
index adfb1ef..840933f 100644
--- a/src/java/com/jogamp/common/os/AndroidVersion.java
+++ b/src/java/com/jogamp/common/os/AndroidVersion.java
@@ -30,7 +30,6 @@ package com.jogamp.common.os;
 import java.lang.reflect.Field;
 
 import com.jogamp.common.os.Platform.ABIType;
-import com.jogamp.common.os.Platform.CPUFamily;
 import com.jogamp.common.os.Platform.CPUType;
 import com.jogamp.common.util.IntObjectHashMap;
 import com.jogamp.common.util.ReflectionUtil;
@@ -67,46 +66,6 @@ public class AndroidVersion {
     private static final String androidBuildVersion = "android.os.Build$VERSION";
     private static final String androidBuildVersionCodes = "android.os.Build$VERSION_CODES";
 
-    /**
-     * Returns {@link CPUType} for matching <code>cpuABI<code>,
-     * i.e. {@link #CPU_ABI} or {@link #CPU_ABI2},
-     * or <code>null</code> for no match.
-     * <p>
-     * FIXME: Where is a comprehensive list of known 'android.os.Build.CPU_ABI' and 'android.os.Build.CPU_ABI2' strings ?<br/>
-     * Fount this one: <code>http://www.kandroid.org/ndk/docs/CPU-ARCH-ABIS.html</code>
-     * <pre>
-     *  lib/armeabi/libfoo.so
-     *  lib/armeabi-v7a/libfoo.so
-     *  lib/x86/libfoo.so
-     *  lib/mips/libfoo.so
-     * </pre>
-     * </p>
-     */
-    private static final CPUType getCPUTypeImpl(final String cpuABI) {
-        if( null == cpuABI ) {
-            return null;
-        } else if( cpuABI.equals("armeabi-v7a") ) {
-            return CPUType.ARMv7;
-        } else if( cpuABI.equals("armeabi") ||
-                   cpuABI.startsWith("arm") ) { // last chance ..
-            return CPUType.ARM;
-        } else if( cpuABI.equals("x86") ) {
-            return CPUType.X86_32;
-        } else if( cpuABI.equals("mips") ) {    // no 32bit vs 64bit identifier ?
-            return CPUType.MIPS_32;
-        } else {
-            return null;
-        }
-    }
-    private static final ABIType getABITypeImpl(final CPUType cpuType, final String cpuABI) {
-        if( null == cpuType || null == cpuABI ) {
-            return null;
-        } else if( CPUFamily.ARM  != cpuType.family ) {
-            return ABIType.GENERIC_ABI;
-        }
-        return ABIType.EABI_GNU_ARMEL; // FIXME: How will they name ABIType.EABI_GNU_ARMHF
-    }
-
     static {
         final ClassLoader cl = AndroidVersion.class.getClassLoader();
         Class<?> abClass = null;
@@ -123,7 +82,7 @@ public class AndroidVersion {
             abvcClass = ReflectionUtil.getClass(androidBuildVersionCodes, true, cl);
             abvcObject = abvcClass.newInstance();
         } catch (final Exception e) { /* n/a */ }
-        isAvailable = null != abObject && null != abvObject && null != abvcObject;
+        isAvailable = null != abObject && null != abvObject;
         if(isAvailable) {
             CPU_ABI = getString(abClass, abObject, "CPU_ABI", true);
             CPU_ABI2 = getString(abClass, abObject, "CPU_ABI2", true);
@@ -131,9 +90,36 @@ public class AndroidVersion {
             INCREMENTAL = getString(abvClass, abvObject, "INCREMENTAL", false);
             RELEASE = getString(abvClass, abvObject, "RELEASE", false);
             SDK_INT = getInt(abvClass, abvObject, "SDK_INT");
-            final IntObjectHashMap version_codes = getVersionCodes(abvcClass, abvcObject);
-            final String sdk_name = (String) version_codes.get(SDK_INT);
+            final String sdk_name;
+            if( null != abvcObject ) {
+                final IntObjectHashMap version_codes = getVersionCodes(abvcClass, abvcObject);
+                sdk_name = (String) version_codes.get(SDK_INT);
+            } else {
+                sdk_name = null;
+            }
             SDK_NAME = ( null != sdk_name ) ? sdk_name : "SDK_"+SDK_INT ;
+
+            /**
+             * <p>
+             * FIXME: Where is a comprehensive list of known 'android.os.Build.CPU_ABI' and 'android.os.Build.CPU_ABI2' strings ?<br/>
+             * Fount this one: <code>http://www.kandroid.org/ndk/docs/CPU-ARCH-ABIS.html</code>
+             * <pre>
+             *  lib/armeabi/libfoo.so
+             *  lib/armeabi-v7a/libfoo.so
+             *  lib/x86/libfoo.so
+             *  lib/mips/libfoo.so
+             * </pre>
+             * </p>
+             */
+            CPU_TYPE = Platform.CPUType.query(CPU_ABI);
+            ABI_TYPE = Platform.ABIType.query(CPU_TYPE, CPU_ABI);
+            if( null != CPU_ABI2 && CPU_ABI2.length() > 0 ) {
+                CPU_TYPE2 = Platform.CPUType.query(CPU_ABI2);
+                ABI_TYPE2 = Platform.ABIType.query(CPU_TYPE2, CPU_ABI2);
+            } else {
+                CPU_TYPE2 = null;
+                ABI_TYPE2 = null;
+            }
         } else {
             CPU_ABI = null;
             CPU_ABI2 = null;
@@ -142,11 +128,11 @@ public class AndroidVersion {
             RELEASE = null;
             SDK_INT = -1;
             SDK_NAME = null;
+            CPU_TYPE = null;
+            ABI_TYPE = null;
+            CPU_TYPE2 = null;
+            ABI_TYPE2 = null;
         }
-        CPU_TYPE = getCPUTypeImpl(CPU_ABI);
-        ABI_TYPE = getABITypeImpl(CPU_TYPE, CPU_ABI);
-        CPU_TYPE2 = getCPUTypeImpl(CPU_ABI2);
-        ABI_TYPE2 = getABITypeImpl(CPU_TYPE2, CPU_ABI2);
     }
 
     private static final IntObjectHashMap getVersionCodes(final Class<?> cls, final Object obj) {
diff --git a/src/java/com/jogamp/common/os/DynamicLibraryBundle.java b/src/java/com/jogamp/common/os/DynamicLibraryBundle.java
index 0f5ea8f..2f51e2e 100644
--- a/src/java/com/jogamp/common/os/DynamicLibraryBundle.java
+++ b/src/java/com/jogamp/common/os/DynamicLibraryBundle.java
@@ -62,6 +62,7 @@ public class DynamicLibraryBundle implements DynamicLookupHelper {
     private final DynamicLibraryBundleInfo info;
 
     protected final List<NativeLibrary> nativeLibraries;
+    private final DynamicLinker dynLinkGlobal;
     private final List<List<String>> toolLibNames;
     private final List<String> glueLibNames;
     private final boolean[] toolLibLoaded;
@@ -118,11 +119,15 @@ public class DynamicLibraryBundle implements DynamicLookupHelper {
             glueLibLoaded[i] = false;
         }
 
-        info.getLibLoaderExecutor().invoke(true, new Runnable() {
-                @Override
-                public void run() {
-                    loadLibraries();
-                } } ) ;
+        {
+            final DynamicLinker[] _dynLinkGlobal = { null };
+            info.getLibLoaderExecutor().invoke(true, new Runnable() {
+                    @Override
+                    public void run() {
+                        _dynLinkGlobal[0] = loadLibraries();
+                    } } ) ;
+            dynLinkGlobal = _dynLinkGlobal[0];
+        }
 
         toolGetProcAddressFuncNameList = info.getToolGetProcAddressFuncNameList();
         if( null != toolGetProcAddressFuncNameList ) {
@@ -184,7 +189,10 @@ public class DynamicLibraryBundle implements DynamicLookupHelper {
      * @see DynamicLibraryBundleInfo#getToolLibNames()
      */
     public final boolean isToolLibComplete() {
-        return toolGetProcAddressComplete && getToolLibNumber() == getToolLibLoadedNumber();
+        final int toolLibNumber = getToolLibNumber();
+        return toolGetProcAddressComplete &&
+               ( 0 == toolLibNumber || null != dynLinkGlobal ) &&
+               toolLibNumber == getToolLibLoadedNumber();
     }
 
     public final boolean isToolLibLoaded() {
@@ -226,7 +234,7 @@ public class DynamicLibraryBundle implements DynamicLookupHelper {
 
     public final DynamicLibraryBundleInfo getBundleInfo() { return info; }
 
-    protected final long getToolGetProcAddressHandle() {
+    protected final long getToolGetProcAddressHandle() throws SecurityException {
         if(!isToolLibLoaded()) {
             return 0;
         }
@@ -241,7 +249,7 @@ public class DynamicLibraryBundle implements DynamicLookupHelper {
         return aptr;
     }
 
-    protected final NativeLibrary loadFirstAvailable(final List<String> libNames, final ClassLoader loader, final boolean global) {
+    protected static final NativeLibrary loadFirstAvailable(final List<String> libNames, final ClassLoader loader, final boolean global) throws SecurityException {
         for (int i=0; i < libNames.size(); i++) {
             final NativeLibrary lib = NativeLibrary.open(libNames.get(i), loader, global);
             if (lib != null) {
@@ -251,11 +259,12 @@ public class DynamicLibraryBundle implements DynamicLookupHelper {
         return null;
     }
 
-    final void loadLibraries() {
+    final DynamicLinker loadLibraries() throws SecurityException {
         int i;
         toolLibLoadedNumber = 0;
         final ClassLoader cl = info.getClass().getClassLoader();
         NativeLibrary lib = null;
+        DynamicLinker dynLinkGlobal = null;
 
         for (i=0; i < toolLibNames.size(); i++) {
             final List<String> libNames = toolLibNames.get(i);
@@ -266,6 +275,9 @@ public class DynamicLibraryBundle implements DynamicLookupHelper {
                         System.err.println("Unable to load any Tool library of: "+libNames);
                     }
                 } else {
+                    if( null == dynLinkGlobal ) {
+                        dynLinkGlobal = lib.getDynamicLinker();
+                    }
                     nativeLibraries.add(lib);
                     toolLibLoaded[i]=true;
                     toolLibLoadedNumber++;
@@ -279,7 +291,7 @@ public class DynamicLibraryBundle implements DynamicLookupHelper {
             if(DEBUG) {
                 System.err.println("No Tool libraries loaded");
             }
-            return;
+            return dynLinkGlobal;
         }
 
         glueLibLoadedNumber = 0;
@@ -304,9 +316,16 @@ public class DynamicLibraryBundle implements DynamicLookupHelper {
                 glueLibLoadedNumber++;
             }
         }
+
+        return dynLinkGlobal;
     }
 
-    private final long dynamicLookupFunctionOnLibs(final String funcName) {
+    /**
+     * @param funcName
+     * @return
+     * @throws SecurityException if user is not granted access for the library set.
+     */
+    private final long dynamicLookupFunctionOnLibs(final String funcName) throws SecurityException {
         if(!isToolLibLoaded() || null==funcName) {
             if(DEBUG_LOOKUP && !isToolLibLoaded()) {
                 System.err.println("Lookup-Native: <" + funcName + "> ** FAILED ** Tool native library not loaded");
@@ -318,7 +337,8 @@ public class DynamicLibraryBundle implements DynamicLookupHelper {
 
         if( info.shallLookupGlobal() ) {
             // Try a global symbol lookup first ..
-            addr = NativeLibrary.dynamicLookupFunctionGlobal(funcName);
+            // addr = NativeLibrary.dynamicLookupFunctionGlobal(funcName);
+            addr = dynLinkGlobal.lookupSymbolGlobal(funcName);
         }
         // Look up this function name in all known libraries
         for (int i=0; 0==addr && i < nativeLibraries.size(); i++) {
@@ -350,7 +370,20 @@ public class DynamicLibraryBundle implements DynamicLookupHelper {
     }
 
     @Override
-    public final long dynamicLookupFunction(final String funcName) {
+    public final void claimAllLinkPermission() throws SecurityException {
+        for (int i=0; i < nativeLibraries.size(); i++) {
+            nativeLibraries.get(i).claimAllLinkPermission();
+        }
+    }
+    @Override
+    public final void releaseAllLinkPermission() throws SecurityException {
+        for (int i=0; i < nativeLibraries.size(); i++) {
+            nativeLibraries.get(i).releaseAllLinkPermission();
+        }
+    }
+
+    @Override
+    public final long dynamicLookupFunction(final String funcName) throws SecurityException {
         if(!isToolLibLoaded() || null==funcName) {
             if(DEBUG_LOOKUP && !isToolLibLoaded()) {
                 System.err.println("Lookup: <" + funcName + "> ** FAILED ** Tool native library not loaded");
@@ -378,7 +411,7 @@ public class DynamicLibraryBundle implements DynamicLookupHelper {
     }
 
     @Override
-    public final boolean isFunctionAvailable(final String funcName) {
+    public final boolean isFunctionAvailable(final String funcName) throws SecurityException {
         return 0 != dynamicLookupFunction(funcName);
     }
 
diff --git a/src/java/com/jogamp/common/os/DynamicLinker.java b/src/java/com/jogamp/common/os/DynamicLinker.java
index 3b1ec3f..4019c77 100644
--- a/src/java/com/jogamp/common/os/DynamicLinker.java
+++ b/src/java/com/jogamp/common/os/DynamicLinker.java
@@ -34,6 +34,16 @@ public interface DynamicLinker {
   public static final boolean DEBUG_LOOKUP = NativeLibrary.DEBUG_LOOKUP;
 
   /**
+   * @throws SecurityException if user is not granted global access
+   */
+  public void claimAllLinkPermission() throws SecurityException;
+
+  /**
+   * @throws SecurityException if user is not granted global access
+   */
+  public void releaseAllLinkPermission() throws SecurityException;
+
+  /**
    * If a {@link SecurityManager} is installed, user needs link permissions
    * for the named library.
    * <p>
@@ -80,8 +90,9 @@ public interface DynamicLinker {
    * @param symbolName global symbol name to lookup up system wide.
    * @return the library handle, maybe 0 if not found.
    * @throws IllegalArgumentException in case case <code>libraryHandle</code> is unknown.
+   * @throws SecurityException if user is not granted access for the given library handle
    */
-  public long lookupSymbol(long libraryHandle, String symbolName) throws IllegalArgumentException;
+  public long lookupSymbol(long libraryHandle, String symbolName) throws SecurityException, IllegalArgumentException;
 
   /**
    * Security checks are implicit by previous call of
@@ -89,9 +100,11 @@ public interface DynamicLinker {
    * retrieving the <code>librarHandle</code>.
    *
    * @param libraryHandle a library handle previously retrieved via {@link #openLibraryLocal(String, boolean)} or {@link #openLibraryGlobal(String, boolean)}.
+   * @param debug set to true to enable debugging
    * @throws IllegalArgumentException in case case <code>libraryHandle</code> is unknown.
+   * @throws SecurityException if user is not granted access for the given library handle
    */
-  public void closeLibrary(long libraryHandle) throws IllegalArgumentException;
+  public void closeLibrary(long libraryHandle, boolean debug) throws SecurityException, IllegalArgumentException;
 
   /**
    * Returns a string containing the last error.
diff --git a/src/java/com/jogamp/common/os/DynamicLookupHelper.java b/src/java/com/jogamp/common/os/DynamicLookupHelper.java
index 0f87351..7997d57 100644
--- a/src/java/com/jogamp/common/os/DynamicLookupHelper.java
+++ b/src/java/com/jogamp/common/os/DynamicLookupHelper.java
@@ -51,12 +51,23 @@ public interface DynamicLookupHelper {
   public static final boolean DEBUG_LOOKUP = Debug.debug("NativeLibrary.Lookup");
 
   /**
+   * @throws SecurityException if user is not granted access for the library set.
+   */
+  public void claimAllLinkPermission() throws SecurityException;
+  /**
+   * @throws SecurityException if user is not granted access for the library set.
+   */
+  public void releaseAllLinkPermission() throws SecurityException;
+
+  /**
    * Returns the function handle for function 'funcName'.
+   * @throws SecurityException if user is not granted access for the library set.
    */
-  public long dynamicLookupFunction(String funcName);
+  public long dynamicLookupFunction(String funcName) throws SecurityException;
 
   /**
    * Queries whether function 'funcName' is available.
+   * @throws SecurityException if user is not granted access for the library set.
    */
-  public boolean isFunctionAvailable(String funcName);
+  public boolean isFunctionAvailable(String funcName) throws SecurityException;
 }
diff --git a/src/java/com/jogamp/common/os/MachineDescription.java b/src/java/com/jogamp/common/os/MachineDataInfo.java
similarity index 70%
rename from src/java/com/jogamp/common/os/MachineDescription.java
rename to src/java/com/jogamp/common/os/MachineDataInfo.java
index ca9819a..0192cd8 100644
--- a/src/java/com/jogamp/common/os/MachineDescription.java
+++ b/src/java/com/jogamp/common/os/MachineDataInfo.java
@@ -43,73 +43,80 @@ package com.jogamp.common.os;
 import jogamp.common.os.PlatformPropsImpl;
 
 /**
- * For alignment and size see {@link com.jogamp.gluegen}
+ * Machine data description for alignment and size onle, see {@link com.jogamp.gluegen}.
+ * <p>
+ * {@code little-endian} / {@code big/endian} description is left,
+ * allowing re-using instances in {@link MachineDataInfo.StaticConfig StaticConfig}.
+ * Use {@link {@link PlatformPropsImpl#LITTLE_ENDIAN}.
+ * </p>
+ * <p>
+ * Further more, the value {@ MachineDataInfo#pageSizeInBytes} shall be ignored
+ * in {@link MachineDataInfo.StaticConfig StaticConfig}, see {@link MachineDataInfo#compatible(MachineDataInfo)}.
+ * </p>
  */
-public class MachineDescription {
-  public enum ID {
-      /** {@link Platform.CPUType#ARM} EABI Little Endian */
-      ARMle_EABI(Platform.CPUType.ARM),
-      /** {@link Platform.CPUType#X86_32} Little Endian Unix */
-      X86_32_UNIX(Platform.CPUType.X86_32),
-      /** {@link Platform.CPUType#X86_64} Little Endian Unix */
-      X86_64_UNIX(Platform.CPUType.X86_64),
-      /** {@link Platform.CPUType#X86_32} Little Endian MacOS (Special case gcc4/OSX) */
-      X86_32_MACOS(Platform.CPUType.X86_32),
-      /** {@link Platform.CPUType#X86_64} Little Endian MacOS */
-      X86_32_WINDOWS(Platform.CPUType.X86_32),
-      /** {@link Platform.CPUType#X86_64} Little Endian Windows */
-      X86_64_WINDOWS(Platform.CPUType.X86_64),
-      /** {@link Platform.CPUType#SPARC_32} Big Endian Solaris */
-      SPARC_32_SUNOS(Platform.CPUType.SPARC_32);
-
-      public final Platform.CPUType cpu;
-
-      ID(final Platform.CPUType cpu){
-          this.cpu = cpu;
-      }
-  }
-
+public class MachineDataInfo {
   /*                              arch   os          int, long, float, doubl, ldoubl,  ptr,   page */
-  private final static int[] size_armeabi         =  { 4,    4,     4,     8,      8,    4,   4096 };
+  private final static int[] size_arm_mips_32     =  { 4,    4,     4,     8,      8,    4,   4096 };
   private final static int[] size_x86_32_unix     =  { 4,    4,     4,     8,     12,    4,   4096 };
   private final static int[] size_x86_32_macos    =  { 4,    4,     4,     8,     16,    4,   4096 };
+  private final static int[] size_ppc_32_unix     =  { 4,    4,     4,     8,     16,    4,   4096 };
+  private final static int[] size_sparc_32_sunos  =  { 4,    4,     4,     8,     16,    4,   8192 };
   private final static int[] size_x86_32_windows  =  { 4,    4,     4,     8,     12,    4,   4096 };
-  private final static int[] size_x86_64_unix     =  { 4,    8,     4,     8,     16,    8,   4096 };
+  private final static int[] size_lp64_unix       =  { 4,    8,     4,     8,     16,    8,   4096 };
   private final static int[] size_x86_64_windows  =  { 4,    4,     4,     8,     16,    8,   4096 };
-  private final static int[] size_sparc_32_sunos  =  { 4,    4,     4,     8,     16,    4,   8192 };
 
   /*                               arch   os          i8, i16, i32, i64, int, long, float, doubl, ldoubl, ptr */
-  private final static int[] align_armeabi        =  { 1,   2,   4,   8,   4,    4,     4,     8,      8,   4 };
+  private final static int[] align_arm_mips_32    =  { 1,   2,   4,   8,   4,    4,     4,     8,      8,   4 };
   private final static int[] align_x86_32_unix    =  { 1,   2,   4,   4,   4,    4,     4,     4,      4,   4 };
   private final static int[] align_x86_32_macos   =  { 1,   2,   4,   4,   4,    4,     4,     4,     16,   4 };
+  private final static int[] align_ppc_32_unix    =  { 1,   2,   4,   8,   4,    4,     4,     8,     16,   4 };
+  private final static int[] align_sparc_32_sunos =  { 1,   2,   4,   8,   4,    4,     4,     8,      8,   4 };
   private final static int[] align_x86_32_windows =  { 1,   2,   4,   8,   4,    4,     4,     8,      4,   4 };
-  private final static int[] align_x86_64_unix    =  { 1,   2,   4,   8,   4,    8,     4,     8,     16,   8 };
+  private final static int[] align_lp64_unix      =  { 1,   2,   4,   8,   4,    8,     4,     8,     16,   8 };
   private final static int[] align_x86_64_windows =  { 1,   2,   4,   8,   4,    4,     4,     8,     16,   8 };
-  private final static int[] align_sparc_32_sunos =  { 1,   2,   4,   8,   4,    4,     4,     8,      8,   4 };
 
+  /**
+   * Static enumeration of {@link MachineDataInfo} instances
+   * used for high performance data size and alignment lookups,
+   * e.g. for generated structures.
+   * <p>
+   * The value {@link MachineDataInfo#pageSizeInBytes} shall be ignored
+   * for static instances!
+   * </p>
+   * <p>
+   * If changing this table, you need to:
+   * <ul>
+   *   <li>Rebuild GlueGen.</li>
+   *   <li>Run ant {@code build.xml} target {@code generate.os.sources}.</li>
+   *   <li>Rebuild everything.</li>
+   * </ul>
+   * .. b/c the generated code for glued structures must reflect this change!
+   * </p>
+   */
   public enum StaticConfig {
-      /** {@link MachineDescription.ID#ARMle_EABI } */
-      ARMle_EABI(ID.ARMle_EABI,         true,  size_armeabi,        align_armeabi),
-      /** {@link MachineDescription.ID#X86_32_UNIX } */
-      X86_32_UNIX(ID.X86_32_UNIX,       true,  size_x86_32_unix,    align_x86_32_unix),
-      /** {@link MachineDescription.ID#X86_64_UNIX } */
-      X86_64_UNIX(ID.X86_64_UNIX,       true,  size_x86_64_unix,    align_x86_64_unix),
-      /** {@link MachineDescription.ID#X86_32_MACOS } */
-      X86_32_MACOS(ID.X86_32_MACOS,     true,  size_x86_32_macos,   align_x86_32_macos),
-      /** {@link MachineDescription.ID#X86_32_WINDOWS } */
-      X86_32_WINDOWS(ID.X86_32_WINDOWS, true,  size_x86_32_windows, align_x86_32_windows),
-      /** {@link MachineDescription.ID#X86_64_WINDOWS } */
-      X86_64_WINDOWS(ID.X86_64_WINDOWS, true,  size_x86_64_windows, align_x86_64_windows),
-      /** {@link MachineDescription.ID#SPARC_32_SUNOS } */
-      SPARC_32_SUNOS(ID.SPARC_32_SUNOS, false, size_sparc_32_sunos, align_sparc_32_sunos);
-
-      public final ID id;
-      public final MachineDescription md;
-
-      StaticConfig(final ID id, final boolean littleEndian, final int[] sizes, final int[] alignments) {
-          this.id = id;
+      /** {@link Platform.CPUType#ARM} or {@link Platform.CPUType#MIPS_32} */
+      ARM_MIPS_32(     size_arm_mips_32,   align_arm_mips_32),
+      /** {@link Platform.CPUType#X86_32} Unix */
+      X86_32_UNIX(    size_x86_32_unix,    align_x86_32_unix),
+      /** {@link Platform.CPUType#X86_32} MacOS (Special case gcc4/OSX) */
+      X86_32_MACOS(   size_x86_32_macos,   align_x86_32_macos),
+      /** {@link Platform.CPUType#PPC} Unix */
+      PPC_32_UNIX(    size_ppc_32_unix,   align_ppc_32_unix),
+      /** {@link Platform.CPUType#SPARC_32} Solaris */
+      SPARC_32_SUNOS( size_sparc_32_sunos, align_sparc_32_sunos),
+      /** {@link Platform.CPUType#X86_32} Windows */
+      X86_32_WINDOWS( size_x86_32_windows, align_x86_32_windows),
+      /** LP64 Unix, e.g.: {@link Platform.CPUType#X86_64} Unix, {@link Platform.CPUType#ARM64} EABI, {@link Platform.CPUType#PPC64} Unix, .. */
+      LP64_UNIX(      size_lp64_unix,    align_lp64_unix),
+      /** {@link Platform.CPUType#X86_64} Windows */
+      X86_64_WINDOWS( size_x86_64_windows, align_x86_64_windows);
+      // 8
+
+      public final MachineDataInfo md;
+
+      StaticConfig(final int[] sizes, final int[] alignments) {
           int i=0, j=0;
-          this.md = new MachineDescription(false, littleEndian,
+          this.md = new MachineDataInfo(false,
                                            sizes[i++],
                                            sizes[i++],
                                            sizes[i++],
@@ -129,26 +136,59 @@ public class MachineDescription {
                                            alignments[j++]);
       }
 
-      public StringBuilder toString(StringBuilder sb) {
+      public final StringBuilder toString(StringBuilder sb) {
         if(null==sb) {
             sb = new StringBuilder();
         }
-        sb.append("MachineDescriptionStatic: ").append(this.name()).append("(").append(this.ordinal()).append("): ");
+        sb.append("MachineDataInfoStatic: ").append(this.name()).append("(").append(this.ordinal()).append("): ");
         md.toString(sb);
         return sb;
       }
-
+      public final String toShortString() {
+          return this.name()+"("+this.ordinal()+")";
+      }
       @Override
       public String toString() {
         return toString(null).toString();
       }
-  }
 
+      /**
+       * Static's {@link MachineDataInfo} shall be unique by the
+       * {@link MachineDataInfo#compatible(MachineDataInfo) compatible} criteria.
+       */
+      public static final void validateUniqueMachineDataInfo() {
+          final StaticConfig[] scs = StaticConfig.values();
+          for(int i=scs.length-1; i>=0; i--) {
+              final StaticConfig a = scs[i];
+              for(int j=scs.length-1; j>=0; j--) {
+                  if( i != j ) {
+                      final StaticConfig b = scs[j];
+                      if( a.md.compatible(b.md) ) {
+                          // oops
+                          final String msg = "Duplicate/Compatible MachineDataInfo in StaticConfigs: Elements ["+i+": "+a.toShortString()+"] and ["+j+": "+b.toShortString()+"]";
+                          System.err.println(msg);
+                          System.err.println(a);
+                          System.err.println(b);
+                          throw new InternalError(msg);
+                      }
+                  }
+              }
+          }
+      }
+      public static final StaticConfig findCompatible(final MachineDataInfo md) {
+          final StaticConfig[] scs = StaticConfig.values();
+          for(int i=scs.length-1; i>=0; i--) {
+              final StaticConfig a = scs[i];
+              if( a.md.compatible(md) ) {
+                  return a;
+              }
+          }
+          return null;
+      }
+  }
 
   final private boolean runtimeValidated;
 
-  final private boolean littleEndian;
-
   final private int int8SizeInBytes = 1;
   final private int int16SizeInBytes = 2;
   final private int int32SizeInBytes = 4;
@@ -161,7 +201,6 @@ public class MachineDescription {
   final private int ldoubleSizeInBytes;
   final private int pointerSizeInBytes;
   final private int pageSizeInBytes;
-  final private boolean is32Bit;
 
   final private int int8AlignmentInBytes;
   final private int int16AlignmentInBytes;
@@ -174,8 +213,7 @@ public class MachineDescription {
   final private int ldoubleAlignmentInBytes;
   final private int pointerAlignmentInBytes;
 
-  public MachineDescription(final boolean runtimeValidated,
-                            final boolean littleEndian,
+  public MachineDataInfo(final boolean runtimeValidated,
 
                             final int intSizeInBytes,
                             final int longSizeInBytes,
@@ -196,7 +234,6 @@ public class MachineDescription {
                             final int ldoubleAlignmentInBytes,
                             final int pointerAlignmentInBytes) {
     this.runtimeValidated = runtimeValidated;
-    this.littleEndian = littleEndian;
 
     this.intSizeInBytes     = intSizeInBytes;
     this.longSizeInBytes    = longSizeInBytes;
@@ -205,7 +242,6 @@ public class MachineDescription {
     this.ldoubleSizeInBytes = ldoubleSizeInBytes;
     this.pointerSizeInBytes = pointerSizeInBytes;
     this.pageSizeInBytes    = pageSizeInBytes;
-    this.is32Bit            = 4 == pointerSizeInBytes;
 
     this.int8AlignmentInBytes    = int8AlignmentInBytes;
     this.int16AlignmentInBytes   = int16AlignmentInBytes;
@@ -226,27 +262,6 @@ public class MachineDescription {
       return runtimeValidated;
   }
 
-  /**
-   * Returns true only if this system uses little endian byte ordering.
-   */
-  public final boolean isLittleEndian() {
-      return littleEndian;
-  }
-
-  /**
-   * Returns true if this JVM/ARCH is 32bit.
-   */
-  public final boolean is32Bit() {
-    return is32Bit;
-  }
-
-  /**
-   * Returns true if this JVM/ARCH is 64bit.
-   */
-  public final  boolean is64Bit() {
-    return !is32Bit;
-  }
-
   public final int intSizeInBytes()     { return intSizeInBytes;    }
   public final int longSizeInBytes()    { return longSizeInBytes;   }
   public final int int8SizeInBytes()    { return int8SizeInBytes;  }
@@ -286,38 +301,37 @@ public class MachineDescription {
 
   /**
    * Checks whether two size objects are equal. Two instances
-   * of <code>MachineDescription</code> are considered equal if all components
+   * of <code>MachineDataInfo</code> are considered equal if all components
    * match but {@link #runtimeValidated},  {@link #isRuntimeValidated()}.
-   * @return  <code>true</code> if the two MachineDescription are equal;
+   * @return  <code>true</code> if the two MachineDataInfo are equal;
    *          otherwise <code>false</code>.
    */
   @Override
   public final boolean equals(final Object obj) {
       if (this == obj) { return true; }
-      if ( !(obj instanceof MachineDescription) ) { return false; }
-      final MachineDescription md = (MachineDescription) obj;
+      if ( !(obj instanceof MachineDataInfo) ) { return false; }
+      final MachineDataInfo md = (MachineDataInfo) obj;
 
       return pageSizeInBytes == md.pageSizeInBytes &&
              compatible(md);
   }
 
   /**
-   * Checks whether two size objects are equal. Two instances
-   * of <code>MachineDescription</code> are considered equal if all components
+   * Checks whether two {@link MachineDataInfo} objects are equal.
+   * <p>
+   * Two {@link MachineDataInfo} instances are considered equal if all components
    * match but {@link #isRuntimeValidated()} and {@link #pageSizeInBytes()}.
-   * @return  <code>true</code> if the two MachineDescription are equal;
+   * </p>
+   * @return  <code>true</code> if the two {@link MachineDataInfo} are equal;
    *          otherwise <code>false</code>.
    */
-  public final boolean compatible(final MachineDescription md) {
-      return littleEndian == md.littleEndian &&
-
-             intSizeInBytes == md.intSizeInBytes &&
+  public final boolean compatible(final MachineDataInfo md) {
+      return intSizeInBytes == md.intSizeInBytes &&
              longSizeInBytes == md.longSizeInBytes &&
              floatSizeInBytes == md.floatSizeInBytes &&
              doubleSizeInBytes == md.doubleSizeInBytes &&
              ldoubleSizeInBytes == md.ldoubleSizeInBytes &&
              pointerSizeInBytes == md.pointerSizeInBytes &&
-             is32Bit == md.is32Bit &&
 
              int8AlignmentInBytes == md.int8AlignmentInBytes &&
              int16AlignmentInBytes == md.int16AlignmentInBytes &&
@@ -335,7 +349,7 @@ public class MachineDescription {
     if(null==sb) {
         sb = new StringBuilder();
     }
-    sb.append("MachineDescription: runtimeValidated ").append(isRuntimeValidated()).append(", littleEndian ").append(isLittleEndian()).append(", 32Bit ").append(is32Bit()).append(", primitive size / alignment:").append(PlatformPropsImpl.NEWLINE);
+    sb.append("MachineDataInfo: runtimeValidated ").append(isRuntimeValidated()).append(", 32Bit ").append(4 == pointerAlignmentInBytes).append(", primitive size / alignment:").append(PlatformPropsImpl.NEWLINE);
     sb.append("  int8    ").append(int8SizeInBytes)   .append(" / ").append(int8AlignmentInBytes);
     sb.append(", int16   ").append(int16SizeInBytes)  .append(" / ").append(int16AlignmentInBytes).append(Platform.getNewline());
     sb.append("  int     ").append(intSizeInBytes)    .append(" / ").append(intAlignmentInBytes);
diff --git a/src/java/com/jogamp/common/os/NativeLibrary.java b/src/java/com/jogamp/common/os/NativeLibrary.java
index e54f5e6..747f92d 100644
--- a/src/java/com/jogamp/common/os/NativeLibrary.java
+++ b/src/java/com/jogamp/common/os/NativeLibrary.java
@@ -50,12 +50,14 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.StringTokenizer;
 
-import jogamp.common.os.BionicDynamicLinkerImpl;
+import jogamp.common.os.BionicDynamicLinker32bitImpl;
+import jogamp.common.os.BionicDynamicLinker64BitImpl;
 import jogamp.common.os.MacOSXDynamicLinkerImpl;
 import jogamp.common.os.PlatformPropsImpl;
 import jogamp.common.os.PosixDynamicLinkerImpl;
 import jogamp.common.os.WindowsDynamicLinkerImpl;
 
+import com.jogamp.common.ExceptionUtils;
 import com.jogamp.common.util.IOUtil;
 import com.jogamp.common.util.cache.TempJarCache;
 
@@ -73,45 +75,42 @@ import com.jogamp.common.util.cache.TempJarCache;
     supporting code needed in the generated library. */
 
 public final class NativeLibrary implements DynamicLookupHelper {
-  private static final DynamicLinker dynLink;
   private static final String[] prefixes;
   private static final String[] suffixes;
+  private static final boolean isOSX;
 
   static {
     // Instantiate dynamic linker implementation
     switch (PlatformPropsImpl.OS_TYPE) {
       case WINDOWS:
-        dynLink = new WindowsDynamicLinkerImpl();
         prefixes = new String[] { "" };
         suffixes = new String[] { ".dll" };
+        isOSX = false;
         break;
 
       case MACOS:
-        dynLink = new MacOSXDynamicLinkerImpl();
         prefixes = new String[] { "lib" };
         suffixes = new String[] { ".dylib", ".jnilib" };
-        break;
-
-      case ANDROID:
-        dynLink = new BionicDynamicLinkerImpl();
-        prefixes = new String[] { "lib" };
-        suffixes = new String[] { ".so" };
+        isOSX = true;
         break;
 
       /*
+      case ANDROID:
       case FREEBSD:
       case SUNOS:
       case HPUX:
       case OPENKODE:
       case LINUX: */
       default:
-        dynLink = new PosixDynamicLinkerImpl();
         prefixes = new String[] { "lib" };
         suffixes = new String[] { ".so" };
+        isOSX = false;
         break;
     }
   }
 
+  private final DynamicLinker dynLink;
+
   // Platform-specific representation for the handle to the open
   // library. This is an HMODULE on Windows and a void* (the result of
   // a dlopen() call) on Unix and Mac OS X platforms.
@@ -123,7 +122,8 @@ public final class NativeLibrary implements DynamicLookupHelper {
   private final boolean global;
 
   // Private constructor to prevent arbitrary instances from floating around
-  private NativeLibrary(final long libraryHandle, final String libraryPath, final boolean global) {
+  private NativeLibrary(final DynamicLinker dynLink, final long libraryHandle, final String libraryPath, final boolean global) {
+    this.dynLink = dynLink;
     this.libraryHandle = libraryHandle;
     this.libraryPath   = libraryPath;
     this.global        = global;
@@ -134,22 +134,26 @@ public final class NativeLibrary implements DynamicLookupHelper {
 
   @Override
   public final String toString() {
-    return "NativeLibrary[" + libraryPath + ", 0x" + Long.toHexString(libraryHandle) + ", global " + global + "]";
+    return "NativeLibrary[" + dynLink.getClass().getSimpleName() + ", " + libraryPath + ", 0x" + Long.toHexString(libraryHandle) + ", global " + global + "]";
   }
 
   /** Opens the given native library, assuming it has the same base
       name on all platforms, looking first in the system's search
       path, and in the context of the specified ClassLoader, which is
-      used to help find the library in the case of e.g. Java Web Start. */
-  public static final NativeLibrary open(final String libName, final ClassLoader loader) {
+      used to help find the library in the case of e.g. Java Web Start.
+   * @throws SecurityException if user is not granted access for the named library.
+   */
+  public static final NativeLibrary open(final String libName, final ClassLoader loader) throws SecurityException {
     return open(libName, libName, libName, true, loader, true);
   }
 
   /** Opens the given native library, assuming it has the same base
       name on all platforms, looking first in the system's search
       path, and in the context of the specified ClassLoader, which is
-      used to help find the library in the case of e.g. Java Web Start. */
-  public static final NativeLibrary open(final String libName, final ClassLoader loader, final boolean global) {
+      used to help find the library in the case of e.g. Java Web Start.
+   * @throws SecurityException if user is not granted access for the named library.
+   */
+  public static final NativeLibrary open(final String libName, final ClassLoader loader, final boolean global) throws SecurityException {
     return open(libName, libName, libName, true, loader, global);
   }
 
@@ -167,26 +171,54 @@ public final class NativeLibrary implements DynamicLookupHelper {
       ending in .so, for example .so.0), and in general if this
       dynamic loading facility is used correctly the version number
       will be irrelevant.
-  */
+   * @throws SecurityException if user is not granted access for the named library.
+   */
   public static final NativeLibrary open(final String windowsLibName,
                                          final String unixLibName,
                                          final String macOSXLibName,
                                          final boolean searchSystemPathFirst,
-                                         final ClassLoader loader) {
+                                         final ClassLoader loader) throws SecurityException {
     return open(windowsLibName, unixLibName, macOSXLibName, searchSystemPathFirst, loader, true);
   }
 
+  /**
+   * @throws SecurityException if user is not granted access for the named library.
+   */
   public static final NativeLibrary open(final String windowsLibName,
                                          final String unixLibName,
                                          final String macOSXLibName,
                                          final boolean searchSystemPathFirst,
-                                         final ClassLoader loader, final boolean global) {
+                                         final ClassLoader loader, final boolean global) throws SecurityException {
     final List<String> possiblePaths = enumerateLibraryPaths(windowsLibName,
                                                        unixLibName,
                                                        macOSXLibName,
                                                        searchSystemPathFirst,
                                                        loader);
     Platform.initSingleton(); // loads native gluegen-rt library
+
+    final DynamicLinker dynLink;
+    switch (PlatformPropsImpl.OS_TYPE) {
+      case WINDOWS:
+        dynLink = new WindowsDynamicLinkerImpl();
+        break;
+
+      case MACOS:
+        dynLink = new MacOSXDynamicLinkerImpl();
+        break;
+
+      case ANDROID:
+        if( PlatformPropsImpl.CPU_ARCH.is32Bit ) {
+            dynLink = new BionicDynamicLinker32bitImpl();
+        } else {
+            dynLink = new BionicDynamicLinker64BitImpl();
+        }
+        break;
+
+      default:
+        dynLink = new PosixDynamicLinkerImpl();
+        break;
+    }
+
     // Iterate down these and see which one if any we can actually find.
     for (final Iterator<String> iter = possiblePaths.iterator(); iter.hasNext(); ) {
         final String path = iter.next();
@@ -206,7 +238,7 @@ public final class NativeLibrary implements DynamicLookupHelper {
             res = 0;
         }
         if ( 0 != res ) {
-            return new NativeLibrary(res, path, global);
+            return new NativeLibrary(dynLink, res, path, global);
         } else if( DEBUG ) {
             if( null != t ) {
                 System.err.println("NativeLibrary.open: Caught "+t.getClass().getSimpleName()+": "+t.getMessage());
@@ -233,7 +265,16 @@ public final class NativeLibrary implements DynamicLookupHelper {
   }
 
   @Override
-  public final long dynamicLookupFunction(final String funcName) {
+  public final void claimAllLinkPermission() throws SecurityException {
+      dynLink.claimAllLinkPermission();
+  }
+  @Override
+  public final void releaseAllLinkPermission() throws SecurityException {
+      dynLink.releaseAllLinkPermission();
+  }
+
+  @Override
+  public final long dynamicLookupFunction(final String funcName) throws SecurityException {
     if ( 0 == libraryHandle ) {
       throw new RuntimeException("Library is not open");
     }
@@ -241,22 +282,21 @@ public final class NativeLibrary implements DynamicLookupHelper {
   }
 
   @Override
-  public final boolean isFunctionAvailable(final String funcName) {
+  public final boolean isFunctionAvailable(final String funcName) throws SecurityException {
     if ( 0 == libraryHandle ) {
       throw new RuntimeException("Library is not open");
     }
     return 0 != dynLink.lookupSymbol(libraryHandle, funcName);
   }
 
-  /** Looks up the given function name in all loaded libraries. */
-  public static final long dynamicLookupFunctionGlobal(final String funcName) {
+  /** Looks up the given function name in all loaded libraries.
+   * @throws SecurityException if user is not granted access for the named library.
+   */
+  public final long dynamicLookupFunctionGlobal(final String funcName) throws SecurityException {
     return dynLink.lookupSymbolGlobal(funcName);
   }
 
-  /** Looks up the given function name in all loaded libraries. */
-  public static final boolean isFunctionAvailableGlobal(final String funcName) {
-    return 0 != dynLink.lookupSymbolGlobal(funcName);
-  }
+  /* pp */ final DynamicLinker getDynamicLinker() { return dynLink; }
 
   /** Retrieves the low-level library handle from this NativeLibrary
       object. On the Windows platform this is an HMODULE, and on Unix
@@ -271,8 +311,10 @@ public final class NativeLibrary implements DynamicLookupHelper {
   }
 
   /** Closes this native library. Further lookup operations are not
-      allowed after calling this method. */
-  public final void close() {
+      allowed after calling this method.
+   * @throws SecurityException if user is not granted access for the named library.
+   */
+  public final void close() throws SecurityException {
     if (DEBUG) {
       System.err.println("NativeLibrary.close(): closing " + this);
     }
@@ -281,10 +323,10 @@ public final class NativeLibrary implements DynamicLookupHelper {
     }
     final long handle = libraryHandle;
     libraryHandle = 0;
-    dynLink.closeLibrary(handle);
+    dynLink.closeLibrary(handle, DEBUG);
     if (DEBUG) {
       System.err.println("NativeLibrary.close(): Successfully closed " + this);
-      Thread.dumpStack();
+      ExceptionUtils.dumpStack(System.err);
     }
   }
 
@@ -419,7 +461,7 @@ public final class NativeLibrary implements DynamicLookupHelper {
     }
 
     // Add probable Mac OS X-specific paths
-    if (PlatformPropsImpl.OS_TYPE == Platform.OSType.MACOS) {
+    if ( isOSX ) {
       // Add historical location
       addPaths("/Library/Frameworks/" + libName + ".Framework", baseNames, paths);
       // Add current location
@@ -440,13 +482,6 @@ public final class NativeLibrary implements DynamicLookupHelper {
       case MACOS:
         return macOSXLibName;
 
-      /*
-      case FREEBSD:
-      case DALVIK:
-      case SUNOS:
-      case HPUX:
-      case OPENKODE:
-      case LINUX: */
       default:
         return unixLibName;
     }
@@ -497,15 +532,14 @@ public final class NativeLibrary implements DynamicLookupHelper {
           }
       }
 
-      final String[] res = new String[prefixes.length * suffixes.length +
-                                ( PlatformPropsImpl.OS_TYPE == Platform.OSType.MACOS ? 1 : 0 )];
+      final String[] res = new String[prefixes.length * suffixes.length + ( isOSX ? 1 : 0 )];
       int idx = 0;
       for (int i = 0; i < prefixes.length; i++) {
           for (int j = 0; j < suffixes.length; j++) {
               res[idx++] = prefixes[i] + libName + suffixes[j];
           }
       }
-      if (PlatformPropsImpl.OS_TYPE == Platform.OSType.MACOS) {
+      if ( isOSX ) {
           // Plain library-base-name in Framework folder
           res[idx++] = libName;
       }
diff --git a/src/java/com/jogamp/common/os/Platform.java b/src/java/com/jogamp/common/os/Platform.java
index 12122a2..2e63550 100644
--- a/src/java/com/jogamp/common/os/Platform.java
+++ b/src/java/com/jogamp/common/os/Platform.java
@@ -28,12 +28,12 @@
 
 package com.jogamp.common.os;
 
-import java.net.URI;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.concurrent.TimeUnit;
 
 import com.jogamp.common.jvm.JNILibLoaderBase;
+import com.jogamp.common.net.Uri;
 import com.jogamp.common.util.JarUtil;
 import com.jogamp.common.util.PropertyAccess;
 import com.jogamp.common.util.ReflectionUtil;
@@ -41,7 +41,7 @@ import com.jogamp.common.util.VersionNumber;
 import com.jogamp.common.util.cache.TempJarCache;
 
 import jogamp.common.jvm.JVMUtil;
-import jogamp.common.os.MachineDescriptionRuntime;
+import jogamp.common.os.MachineDataInfoRuntime;
 import jogamp.common.os.PlatformPropsImpl;
 
 /**
@@ -50,7 +50,7 @@ import jogamp.common.os.PlatformPropsImpl;
  * Some field declarations and it's static initialization has been delegated
  * to it's super class {@link PlatformPropsImpl} to solve
  * static initialization interdependencies w/ the GlueGen native library loading
- * and it's derived information {@link #getMachineDescription()}, {@link #is32Bit()}, ..<br>
+ * and it's derived information {@link #getMachineDataInfo()}, {@link #is32Bit()}, ..<br>
  * This mechanism is preferred in this case to avoid synchronization and locking
  * and allow better performance accessing the mentioned fields/methods.
  * </p>
@@ -58,89 +58,199 @@ import jogamp.common.os.PlatformPropsImpl;
 public class Platform extends PlatformPropsImpl {
 
     public enum OSType {
-        LINUX(0), FREEBSD(1), ANDROID(2), MACOS(3), SUNOS(4), HPUX(5), WINDOWS(6), OPENKODE(7);
-
-        public final int id;
-
-        OSType(final int id){
-            this.id = id;
-        }
+        LINUX, FREEBSD, ANDROID, MACOS, SUNOS, HPUX, WINDOWS, OPENKODE;
     }
 
     public enum CPUFamily {
         /** AMD/Intel */
-        X86(    0x00000000),
+        X86,
         /** ARM */
-        ARM(    0x00010000),
+        ARM,
         /** Power PC */
-        PPC(    0x00020000),
+        PPC,
         /** SPARC */
-        SPARC(  0x00030000),
+        SPARC,
         /** Mips */
-        MIPS(   0x00040000),
+        MIPS,
         /** PA RISC */
-        PA_RISC(0xFFFF0000),
+        PA_RISC,
         /** Itanium */
-        IA64(   0xFFFF1000);
-
-        public final int id;
-
-        CPUFamily(final int id){
-            this.id = id;
-        }
+        IA64,
+        /** Hitachi SuperH */
+        SuperH;
     }
 
     public enum CPUType {
-        /** X86 32bit */
-        X86_32(    CPUFamily.X86,     0x0001),
-        /** X86 64bit */
-        X86_64(    CPUFamily.X86,     0x0002),
-        /** ARM default */
-        ARM(       CPUFamily.ARM,     0x0000),
-        /** ARM7EJ, ARM9E, ARM10E, XScale */
-        ARMv5(     CPUFamily.ARM,     0x0001),
-        /** ARM11 */
-        ARMv6(     CPUFamily.ARM,     0x0002),
-        /** ARM Cortex */
-        ARMv7(     CPUFamily.ARM,     0x0004),
-        /** PPC default */
-        PPC(       CPUFamily.PPC,     0x0000),
-        /** SPARC 32bit */
-        SPARC_32(  CPUFamily.SPARC,   0x0001),
-        /** SPARC 64bit */
-        SPARCV9_64(CPUFamily.SPARC,   0x0002),
-        /** MIPS 32bit */
-        MIPS_32(  CPUFamily.MIPS,     0x0001),
-        /** MIPS 64bit */
-        MIPS_64(  CPUFamily.MIPS,     0x0002),
-        /** Itanium default */
-        IA64(      CPUFamily.IA64,    0x0000),
-        /** PA_RISC2_0 */
-        PA_RISC2_0(CPUFamily.PA_RISC, 0x0001);
+        /** ARM 32bit default, usually little endian */
+        ARM(       CPUFamily.ARM,     true),
+        /** ARM7EJ, ARM9E, ARM10E, XScale, usually little endian */
+        ARMv5(     CPUFamily.ARM,     true),
+        /** ARM11, usually little endian */
+        ARMv6(     CPUFamily.ARM,     true),
+        /** ARM Cortex, usually little endian */
+        ARMv7(     CPUFamily.ARM,     true),
+        // 4
+
+        /** X86 32bit, little endian */
+        X86_32(    CPUFamily.X86,     true),
+        /** PPC 32bit default, usually big endian */
+        PPC(       CPUFamily.PPC,     true),
+        /** MIPS 32bit, big endian (mips) or little endian (mipsel) */
+        MIPS_32(   CPUFamily.MIPS,    true),
+        /** Hitachi SuperH 32bit default, ??? endian */
+        SuperH(    CPUFamily.SuperH,  true),
+        /** SPARC 32bit, big endian */
+        SPARC_32(  CPUFamily.SPARC,   true),
+        // 9
+
+        /** ARM64 default (64bit), usually little endian */
+        ARM64(     CPUFamily.ARM,     false),
+        /** ARM AArch64 (64bit), usually little endian */
+        ARMv8_A(   CPUFamily.ARM,     false),
+        /** X86 64bit, little endian */
+        X86_64(    CPUFamily.X86,     false),
+        /** PPC 64bit default, usually big endian */
+        PPC64(     CPUFamily.PPC,     false),
+        /** MIPS 64bit, big endian (mips64) or little endian (mipsel64) ? */
+        MIPS_64(   CPUFamily.MIPS,    false),
+        /** Itanium 64bit default, little endian */
+        IA64(      CPUFamily.IA64,    false),
+        /** SPARC 64bit, big endian */
+        SPARCV9_64(CPUFamily.SPARC,   false),
+        /** PA_RISC2_0 64bit, ??? endian */
+        PA_RISC2_0(CPUFamily.PA_RISC, false);
+        // 17
 
-        public final int id;
         public final CPUFamily family;
+        public final boolean is32Bit;
 
-        CPUType(final CPUFamily type, final int id){
+        CPUType(final CPUFamily type, final boolean is32Bit){
             this.family = type;
-            this.id = id;
+            this.is32Bit = is32Bit;
+        }
+
+        /**
+         * Returns {@code true} if the given {@link CPUType} is compatible
+         * w/ this one, i.e. at least {@link #family} and {@link #is32Bit} is equal.
+         */
+        public final boolean isCompatible(final CPUType other) {
+            if( null == other ) {
+                return false;
+            } else if( other == this ) {
+                return true;
+            } else {
+                return this.family == other.family &&
+                       this.is32Bit == other.is32Bit;
+            }
         }
 
-        public CPUFamily getFamily() { return family; }
+        public static final CPUType query(final String cpuABILower) {
+            if( null == cpuABILower ) {
+                throw new IllegalArgumentException("Null cpuABILower arg");
+            }
+            if(        cpuABILower.equals("x86")  ||
+                       cpuABILower.equals("i386") ||
+                       cpuABILower.equals("i486") ||
+                       cpuABILower.equals("i586") ||
+                       cpuABILower.equals("i686") ) {
+                return X86_32;
+            } else if( cpuABILower.equals("x86_64") ||
+                       cpuABILower.equals("amd64")  ) {
+                return X86_64;
+            } else if( cpuABILower.equals("ia64") ) {
+                return IA64;
+            } else if( cpuABILower.equals("aarch64") ) {
+                return ARM64;
+            } else if( cpuABILower.startsWith("arm") ) {
+                if(        cpuABILower.equals("armv8-a")   ||
+                           cpuABILower.equals("arm-v8-a") ||
+                           cpuABILower.equals("arm-8-a") ||
+                           cpuABILower.equals("arm64-v8a") ) {
+                    return ARMv8_A;
+                } else if( cpuABILower.startsWith("arm64") ) {
+                    return ARM64;
+                } else if( cpuABILower.startsWith("armv7") ||
+                           cpuABILower.startsWith("arm-v7") ||
+                           cpuABILower.startsWith("arm-7") ||
+                           cpuABILower.startsWith("armeabi-v7") ) {
+                    return ARMv7;
+                } else if( cpuABILower.startsWith("armv5") ||
+                           cpuABILower.startsWith("arm-v5") ||
+                           cpuABILower.startsWith("arm-5") ) {
+                    return ARMv5;
+                } else if( cpuABILower.startsWith("armv6") ||
+                           cpuABILower.startsWith("arm-v6") ||
+                           cpuABILower.startsWith("arm-6") ) {
+                    return ARMv6;
+                } else {
+                    return ARM;
+                }
+            } else if( cpuABILower.equals("sparcv9") ) {
+                return SPARCV9_64;
+            } else if( cpuABILower.equals("sparc") ) {
+                return SPARC_32;
+            } else if( cpuABILower.equals("pa_risc2.0") ) {
+                return PA_RISC2_0;
+            } else if( cpuABILower.startsWith("ppc64") ) {
+                return PPC64;
+            } else if( cpuABILower.startsWith("ppc") ) {
+                return PPC;
+            } else if( cpuABILower.startsWith("mips64") ) {
+                return MIPS_64;
+            } else if( cpuABILower.startsWith("mips") ) {
+                return MIPS_32;
+            } else if( cpuABILower.startsWith("superh") ) {
+                return SuperH;
+            } else {
+                throw new RuntimeException("Please port CPUType detection to your platform (CPU_ABI string '" + cpuABILower + "')");
+            }
+        }
     }
 
     public enum ABIType {
-        GENERIC_ABI    ( 0x0000 ),
+        GENERIC_ABI       ( 0x00 ),
         /** ARM GNU-EABI ARMEL -mfloat-abi=softfp */
-        EABI_GNU_ARMEL ( 0x0001 ),
+        EABI_GNU_ARMEL    ( 0x01 ),
         /** ARM GNU-EABI ARMHF -mfloat-abi=hard */
-        EABI_GNU_ARMHF ( 0x0002 );
+        EABI_GNU_ARMHF    ( 0x02 ),
+        /** ARM EABI AARCH64 (64bit) */
+        EABI_AARCH64      ( 0x03 );
 
         public final int id;
 
         ABIType(final int id){
             this.id = id;
         }
+
+        /**
+         * Returns {@code true} if the given {@link ABIType} is compatible
+         * w/ this one, i.e. they are equal.
+         */
+        public final boolean isCompatible(final ABIType other) {
+            if( null == other ) {
+                return false;
+            } else {
+                return other == this;
+            }
+        }
+
+        public static final ABIType query(final CPUType cpuType, final String cpuABILower) {
+            if( null == cpuType ) {
+                throw new IllegalArgumentException("Null cpuType");
+            } else if( null == cpuABILower ) {
+                throw new IllegalArgumentException("Null cpuABILower");
+            } else if( CPUFamily.ARM == cpuType.family ) {
+                if( !cpuType.is32Bit ) {
+                    return EABI_AARCH64;
+                } else if( cpuABILower.equals("armeabi-v7a-hard") ) {
+                    return EABI_GNU_ARMHF;
+                } else {
+                    return EABI_GNU_ARMEL;
+                }
+            } else {
+                return GENERIC_ABI;
+            }
+        }
     }
 
     private static final String useTempJarCachePropName = "jogamp.gluegen.UseTempJarCache";
@@ -162,9 +272,7 @@ public class Platform extends PlatformPropsImpl {
     // post loading native lib:
     //
 
-    private static final MachineDescription machineDescription;
-
-    private static final boolean is32Bit;
+    private static final MachineDataInfo machineDescription;
 
     /** <code>true</code> if AWT is available and not in headless mode, otherwise <code>false</code>. */
     public static final boolean AWT_AVAILABLE;
@@ -184,11 +292,11 @@ public class Platform extends PlatformPropsImpl {
 
                 final ClassLoader cl = Platform.class.getClassLoader();
 
-                final URI platformClassJarURI;
+                final Uri platformClassJarURI;
                 {
-                    URI _platformClassJarURI = null;
+                    Uri _platformClassJarURI = null;
                     try {
-                        _platformClassJarURI = JarUtil.getJarURI(Platform.class.getName(), cl);
+                        _platformClassJarURI = JarUtil.getJarUri(Platform.class.getName(), cl);
                     } catch (final Exception e) { }
                     platformClassJarURI = _platformClassJarURI;
                 }
@@ -225,21 +333,11 @@ public class Platform extends PlatformPropsImpl {
         USE_TEMP_JAR_CACHE = _USE_TEMP_JAR_CACHE[0];
         AWT_AVAILABLE = _AWT_AVAILABLE[0];
 
-        MachineDescription md = MachineDescriptionRuntime.getRuntime();
-        if(null == md) {
-            final MachineDescription.StaticConfig smd = MachineDescriptionRuntime.getStatic();
-            md = smd.md;
-            System.err.println("Warning: Using static MachineDescription: "+smd);
-        } else {
-            final MachineDescription.StaticConfig smd = MachineDescriptionRuntime.getStatic();
-            if(!md.compatible(smd.md)) {
-                throw new RuntimeException("Incompatible MachineDescriptions:"+PlatformPropsImpl.NEWLINE+
-                                           " Static "+smd+PlatformPropsImpl.NEWLINE+
-                                           " Runtime "+md);
-            }
-        }
-        machineDescription = md;
-        is32Bit = machineDescription.is32Bit();
+        //
+        // Validate and setup MachineDataInfo.StaticConfig
+        //
+        MachineDataInfoRuntime.initialize();
+        machineDescription = MachineDataInfoRuntime.getRuntime();
     }
 
     private Platform() {}
@@ -257,26 +355,6 @@ public class Platform extends PlatformPropsImpl {
     public static void initSingleton() { }
 
     /**
-     * Returns true only if having {@link java.nio.LongBuffer} and {@link java.nio.DoubleBuffer} available.
-     */
-    public static boolean isJavaSE() {
-        return JAVA_SE;
-    }
-
-    /**
-     * Returns true only if being compatible w/ language level 6, e.g. JRE 1.6.
-     * <p>
-     * Implies {@link #isJavaSE()}.
-     * </p>
-     * <p>
-     * <i>Note</i>: We claim Android is compatible.
-     * </p>
-     */
-    public static boolean isJava6() {
-        return JAVA_6;
-    }
-
-    /**
      * Returns true if this machine is little endian, otherwise false.
      */
     public static boolean isLittleEndian() {
@@ -324,7 +402,7 @@ public class Platform extends PlatformPropsImpl {
      * Returns the CPU family.
      */
     public static CPUFamily getCPUFamily() {
-        return CPU_ARCH.getFamily();
+        return CPU_ARCH.family;
     }
 
     /**
@@ -335,6 +413,22 @@ public class Platform extends PlatformPropsImpl {
     }
 
     /**
+     * Returns true if this JVM/ARCH is 32bit.
+     * <p>Shortcut to {@link #getCPUType()}.{@link CPUType#is32Bit is32Bit}</p>
+     */
+    public static boolean is32Bit() {
+        return CPU_ARCH.is32Bit; // used very often
+    }
+
+    /**
+     * Returns true if this JVM/ARCH is 64bit.
+     * <p>Shortcut to !{@link #getCPUType()}.{@link CPUType#is32Bit is32Bit}</p>
+     */
+    public static boolean is64Bit() {
+        return !CPU_ARCH.is32Bit; // used very often
+    }
+
+    /**
      * Returns the ABI type.
      * <p>
      * In case of {@link CPUFamily#ARM}, the value is determined by parsing the <i>Elf Headers</i> of the running VM.
@@ -407,27 +501,9 @@ public class Platform extends PlatformPropsImpl {
     }
 
     /**
-     * Returns true if this JVM/ARCH is 32bit.
-     * <p>Shortcut to {@link #getMachineDescription()}.{@link MachineDescription#is32Bit() is32Bit()}</p>
-     */
-    public static boolean is32Bit() {
-        // return Platform.machineDescription.is32Bit();
-        return Platform.is32Bit; // used very often
-    }
-
-    /**
-     * Returns true if this JVM/ARCH is 64bit.
-     * <p>Shortcut to {@link #getMachineDescription()}.{@link MachineDescription#is32Bit() is64Bit()}</p>
-     */
-    public static boolean is64Bit() {
-        // return Platform.machineDescription.is64Bit();
-        return !Platform.is32Bit; // used very often
-    }
-
-    /**
-     * Returns the MachineDescription of the running machine.
+     * Returns the MachineDataInfo of the running machine.
      */
-    public static MachineDescription getMachineDescription() {
+    public static MachineDataInfo getMachineDataInfo() {
         return machineDescription;
     }
 
diff --git a/src/java/com/jogamp/common/util/Bitstream.java b/src/java/com/jogamp/common/util/Bitstream.java
index a242faf..e75d820 100644
--- a/src/java/com/jogamp/common/util/Bitstream.java
+++ b/src/java/com/jogamp/common/util/Bitstream.java
@@ -91,6 +91,28 @@ public class Bitstream<T> {
         long position();
 
         /**
+         * Sets this stream's position.
+         * <p>
+         * A set mark is cleared if > new position.
+         * </p>
+         * <p>
+         * Returns {@link Bitstream#EOS} is end-of-stream is reached,
+         * otherwise the new position.
+         * </p>
+         * <p>
+         * Known supporting implementation is {@link ByteBufferStream} and {@link ByteArrayStream}.
+         * </p>
+         *
+         * @param newPosition The new positive position.
+         *
+         * @return The new set position or {@link Bitstream#EOS} if end-of-stream is reached.
+         *
+         * @throws UnsupportedOperationException if not supported, i.e. {@link ByteInputStream} or {@link ByteOutputStream}
+         * @throws IllegalArgumentException If the {@code newPosition} is negative
+         */
+        long position(long newPosition) throws UnsupportedOperationException, IllegalArgumentException;
+
+        /**
          * It is implementation dependent, whether backward skip giving a negative number is supported or not.
          * @param n number of bytes to skip
          * @return actual skipped bytes
@@ -99,9 +121,9 @@ public class Bitstream<T> {
         long skip(final long n) throws IOException;
 
         /**
-         * Set <i>markpos</i> to current position, allowing the stream to be {@link #reset()}.
-         * @param readLimit
-         * @throws UnsupportedOperationException is not supported, i.e. if stream is not an {@link #canInput() input stream}.
+         * Set {@code markpos} to current position, allowing the stream to be {@link #reset()}.
+         * @param readlimit maximum number of bytes able to read before invalidating the {@code markpos}.
+         * @throws UnsupportedOperationException if not supported, i.e. if stream is not an {@link #canInput() input stream}.
          */
         void mark(final int readLimit) throws UnsupportedOperationException;
 
@@ -110,7 +132,7 @@ public class Bitstream<T> {
          * <p>
          * <i>markpos</i> is kept, hence {@link #reset()} can be called multiple times.
          * </p>
-         * @throws UnsupportedOperationException is not supported, i.e. if stream is not an {@link #canInput() input stream}.
+         * @throws UnsupportedOperationException if not supported, i.e. if stream is not an {@link #canInput() input stream}.
          * @throws IllegalStateException if <i>markpos</i> has not been set via {@link #mark(int)} or reset operation failed.
          * @throws IOException if reset operation failed.
          */
@@ -123,7 +145,7 @@ public class Bitstream<T> {
          * otherwise the resulting value.
          * </p>
          * @throws IOException
-         * @throws UnsupportedOperationException is not supported, i.e. if stream is not an {@link #canInput() input stream}.
+         * @throws UnsupportedOperationException if not supported, i.e. if stream is not an {@link #canInput() input stream}.
          */
         int read() throws UnsupportedOperationException, IOException;
 
@@ -134,7 +156,7 @@ public class Bitstream<T> {
          * otherwise the written value.
          * </p>
          * @throws IOException
-         * @throws UnsupportedOperationException is not supported, i.e. if stream is not an {@link #canOutput() output stream}.
+         * @throws UnsupportedOperationException if not supported, i.e. if stream is not an {@link #canOutput() output stream}.
          */
         int write(final byte val) throws UnsupportedOperationException, IOException;
     }
@@ -183,6 +205,18 @@ public class Bitstream<T> {
         public long position() { return pos; }
 
         @Override
+        public long position(final long newPosition) throws UnsupportedOperationException, IllegalArgumentException {
+            if( newPosition >= media.length ) {
+                return Bitstream.EOS;
+            }
+            pos = (int)newPosition;
+            if( posMark > pos ) {
+                posMark = -1;
+            }
+            return pos;
+        }
+
+        @Override
         public long skip(final long n) {
             final long skip;
             if( n >= 0 ) {
@@ -220,7 +254,7 @@ public class Bitstream<T> {
             }
             if( DEBUG ) {
                 if( EOS != r ) {
-                    System.err.println("u8["+(pos-1)+"] -> "+toHexBinString(r, 8));
+                    System.err.println("u8["+(pos-1)+"] -> "+toHexBinString(true, r, 8));
                 } else {
                     System.err.println("u8["+(pos-0)+"] -> EOS");
                 }
@@ -239,7 +273,7 @@ public class Bitstream<T> {
             }
             if( DEBUG ) {
                 if( EOS != r ) {
-                    System.err.println("u8["+(pos-1)+"] <- "+toHexBinString(r, 8));
+                    System.err.println("u8["+(pos-1)+"] <- "+toHexBinString(true, r, 8));
                 } else {
                     System.err.println("u8["+(pos-0)+"] <- EOS");
                 }
@@ -292,6 +326,19 @@ public class Bitstream<T> {
         public long position() { return pos; }
 
         @Override
+        public long position(final long newPosition) throws UnsupportedOperationException, IllegalArgumentException {
+            if( newPosition >= media.limit() ) {
+                return Bitstream.EOS;
+            }
+            media.position((int)newPosition);
+            pos = (int)newPosition;
+            if( posMark > pos ) {
+                posMark = -1;
+            }
+            return pos;
+        }
+
+        @Override
         public long skip(final long n) {
             final long skip;
             if( n >= 0 ) {
@@ -330,7 +377,7 @@ public class Bitstream<T> {
             }
             if( DEBUG ) {
                 if( EOS != r ) {
-                    System.err.println("u8["+(pos-1)+"] -> "+toHexBinString(r, 8));
+                    System.err.println("u8["+(pos-1)+"] -> "+toHexBinString(true, r, 8));
                 } else {
                     System.err.println("u8["+(pos-0)+"] -> EOS");
                 }
@@ -349,7 +396,7 @@ public class Bitstream<T> {
             }
             if( DEBUG ) {
                 if( EOS != r ) {
-                    System.err.println("u8["+(pos-1)+"] <- "+toHexBinString(r, 8));
+                    System.err.println("u8["+(pos-1)+"] <- "+toHexBinString(true, r, 8));
                 } else {
                     System.err.println("u8["+(pos-0)+"] <- EOS");
                 }
@@ -411,6 +458,11 @@ public class Bitstream<T> {
         public long position() { return pos; }
 
         @Override
+        public long position(final long newPosition) throws UnsupportedOperationException, IllegalArgumentException {
+            throw new UnsupportedOperationException("N/a for "+getClass().getCanonicalName());
+        }
+
+        @Override
         public long skip(final long n) throws IOException {
             final long skip = media.skip(n);
             pos += skip;
@@ -438,7 +490,7 @@ public class Bitstream<T> {
             final int r = media.read();
             if(DEBUG) {
                 if( EOS != r ) {
-                    System.err.println("u8["+pos+"] -> "+toHexBinString(r, 8));
+                    System.err.println("u8["+pos+"] -> "+toHexBinString(true, r, 8));
                 } else {
                     System.err.println("u8["+pos+"] -> EOS");
                 }
@@ -505,6 +557,11 @@ public class Bitstream<T> {
         public long position() { return pos; }
 
         @Override
+        public long position(final long newPosition) throws UnsupportedOperationException, IllegalArgumentException {
+            throw new UnsupportedOperationException("N/a for "+getClass().getCanonicalName());
+        }
+
+        @Override
         public long skip(final long n) throws IOException {
             long i = n;
             while(i > 0) {
@@ -539,7 +596,7 @@ public class Bitstream<T> {
             final int r = 0xff & val;
             media.write(r);
             if(DEBUG) {
-                System.err.println("u8["+pos+"] <- "+toHexBinString(r, 8));
+                System.err.println("u8["+pos+"] <- "+toHexBinString(true, r, 8));
             }
             pos++;
             return r;
@@ -685,8 +742,8 @@ public class Bitstream<T> {
     public final boolean canOutput() { return null != bytes ? bytes.canOutput() : false; }
 
     /**
-     * Set <i>markpos</i> to current position, allowing the stream to be {@link #reset()}.
-     * @param readLimit
+     * Set {@code markpos} to current position, allowing the stream to be {@link #reset()}.
+     * @param readlimit maximum number of bytes able to read before invalidating the {@code markpos}.
      * @throws IllegalStateException if not in input mode or stream closed
      */
     public final void mark(final int readLimit) throws IllegalStateException {
@@ -779,46 +836,68 @@ public class Bitstream<T> {
     }
 
     /**
+     * Sets this stream's bit position.
+     * <p>
+     * A set mark is cleared.
+     * </p>
+     * <p>
+     * Returns {@link Bitstream#EOS} is end-of-stream is reached,
+     * otherwise the new position.
+     * </p>
+     * <p>
+     * Known supporting implementation is {@link ByteBufferStream} and {@link ByteArrayStream}.
+     * </p>
+     *
+     * @param newPosition The new positive position.
+     *
+     * @return The new set position or {@link Bitstream#EOS} if end-of-stream is reached.
+     *
+     * @throws UnsupportedOperationException if not supported, i.e. {@link ByteInputStream} or {@link ByteOutputStream}
+     * @throws IllegalArgumentException If the {@code newPosition} is negative
+     * @throws IOException if read error occurs or EOS is reached and {@link #setThrowIOExceptionOnEOF(boolean)} is set to true.
+     * @throws IllegalStateException
+     */
+    public final long position(final long newPosition) throws UnsupportedOperationException, IllegalArgumentException, IllegalStateException, IOException {
+        if( 0 > newPosition ) {
+            throw new IllegalArgumentException("new position not positive: "+newPosition);
+        }
+        bytes.position(0); // throws UnsupportedOperationException
+        resetLocal();
+        if( newPosition > skip(newPosition) ) {
+            return EOS;
+        }
+        return newPosition;
+    }
+
+    /**
      * @param msbFirst if true incoming stream bit order is MSB to LSB, otherwise LSB to MSB.
      * @return the read bit or {@link #EOS} if end-of-stream is reached.
      * @throws IOException
      * @throws IllegalStateException if not in input mode or stream closed
      */
-    public final int readBit(final boolean msbFirst) throws IllegalStateException, IOException {
+    public final int readBit(final boolean msbFirst) throws UnsupportedOperationException, IllegalStateException, IOException {
         if( outputMode || null == bytes ) {
             throw new IllegalStateException("not in input-mode: "+this);
         }
-        if( msbFirst ) {
-            // MSB
-            if ( 0 < bitCount ) {
-                bitCount--;
+        if ( 0 < bitCount ) {
+            bitCount--;
+            if( msbFirst ) {
                 return  ( bitBuffer >>> bitCount ) & 0x01;
             } else {
-                bitBuffer = bytes.read();
-                if( EOS == bitBuffer ) {
-                    if( throwIOExceptionOnEOF ) {
-                        throw new IOException("EOS "+this);
-                    }
-                    return EOS;
-                } else {
-                    bitCount=7;
-                    return bitBuffer >>> 7;
-                }
+                return  ( bitBuffer >>> ( 7 - bitCount ) ) & 0x01;
             }
         } else {
-            // LSB
-            if ( 0 < bitCount ) {
-                bitCount--;
-                return  ( bitBuffer >>> ( 7 - bitCount ) ) & 0x01;
+            bitBuffer = bytes.read();
+            if( EOS == bitBuffer ) {
+                if( throwIOExceptionOnEOF ) {
+                    throw new IOException("EOS "+this);
+                }
+                return EOS;
             } else {
-                bitBuffer = bytes.read();
-                if( EOS == bitBuffer ) {
-                    if( throwIOExceptionOnEOF ) {
-                        throw new IOException("EOS "+this);
-                    }
-                    return EOS;
+                bitCount=7;
+                if( msbFirst ) {
+                    return bitBuffer >>> 7;
                 } else {
-                    bitCount=7;
                     return bitBuffer & 0x01;
                 }
             }
@@ -836,36 +915,25 @@ public class Bitstream<T> {
         if( !outputMode || null == bytes ) {
             throw new IllegalStateException("not in output-mode: "+this);
         }
-        if( msbFirst ) {
-            // MSB
-            if ( 0 < bitCount ) {
-                bitCount--;
+        if ( 0 < bitCount ) {
+            bitCount--;
+            if( msbFirst ) {
                 bitBuffer |= ( 0x01 & bit ) << bitCount;
-                if( 0 == bitCount ) {
-                    final int r = bytes.write((byte)bitBuffer);
-                    if( throwIOExceptionOnEOF && EOS == r ) {
-                        throw new IOException("EOS "+this);
-                    }
-                    return r;
-                }
             } else {
-                bitCount = 7;
-                bitBuffer = ( 0x01 & bit ) << 7;
-            }
-        } else {
-            // LSB
-            if ( 0 < bitCount ) {
-                bitCount--;
                 bitBuffer |= ( 0x01 & bit ) << ( 7 - bitCount );
-                if( 0 == bitCount ) {
-                    final int r = bytes.write((byte)bitBuffer);
-                    if( throwIOExceptionOnEOF && EOS == r ) {
-                        throw new IOException("EOS "+this);
-                    }
-                    return r;
+            }
+            if( 0 == bitCount ) {
+                final int r = bytes.write((byte)bitBuffer);
+                if( throwIOExceptionOnEOF && EOS == r ) {
+                    throw new IOException("EOS "+this);
                 }
+                return r;
+            }
+        } else {
+            bitCount = 7;
+            if( msbFirst ) {
+                bitBuffer = ( 0x01 & bit ) << 7;
             } else {
-                bitCount = 7;
                 bitBuffer = 0x01 & bit;
             }
         }
@@ -877,7 +945,7 @@ public class Bitstream<T> {
      *
      * @param n number of bits to skip
      * @return actual skipped bits
-     * @throws IOException
+     * @throws IOException if read error occurs or EOS is reached and {@link #setThrowIOExceptionOnEOF(boolean)} is set to true.
      * @throws IllegalStateException if closed
      */
     public long skip(final long n) throws IllegalStateException, IOException {
@@ -939,85 +1007,96 @@ public class Bitstream<T> {
                 return nX - notReadBits;
             }
         } else {
-            // FIXME: Backward skip
+            // Zero skip or backward skip
+            // FIXME: Backward skip n < 0
             return 0;
         }
     }
 
+    private static final boolean useFastPathStream = true;
+    private static final boolean useFastPathTypes = true;
+
     /**
-     * Return incoming bits as read via {@link #readBit(boolean)}.
+     * Return incoming bits as read via {@link #readBit(boolean)} LSB-first as little-endian.
      * <p>
-     * The incoming bits are stored in MSB-first order, i.e. first on highest position and last bit on lowest position.
-     * Hence reading w/ <i>lsbFirst</i>, the bit order will be reversed!
+     * The incoming bit order is from low- to most-significant-bit, maintaining bit LSB-first order.
      * </p>
-     * @param msbFirst if true incoming stream bit order is MSB to LSB, otherwise LSB to MSB.
      * @param n number of bits, maximum 31 bits
      * @return the read bits from 0-n in the given order or {@link #EOS}.
      * @throws IllegalStateException if not in input mode or stream closed
      * @throws IllegalArgumentException if n > 31
      * @throws IOException
      */
-    public int readBits31(final boolean msbFirst, final int n) throws IllegalArgumentException, IOException {
+    public int readBits31(final int n) throws IllegalArgumentException, IOException {
         if( 31 < n ) {
             throw new IllegalArgumentException("n > 31: "+n);
         }
         if( outputMode || null == bytes ) {
             throw new IllegalStateException("not in input-mode: "+this);
         }
-        if( !msbFirst || 0 == n ) {
-            // Slow path
-            int r = 0;
-            int c = n;
-            while(--c >= 0) {
-                final int b = readBit(msbFirst);
-                if( EOS == b ) {
-                    return EOS;
-                }
-                r |= b << c;
-            }
-            return r;
+        if( 0 == n ) {
+            return 0;
         } else {
-            // fast path: MSB
-            int c = n;
-            final int n1 = Math.min(c, bitCount); // remaining portion
-            int r;
-            if( 0 < n1 ) {
-                final int m1 = ( 1 << n1 ) - 1;
-                bitCount -= n1;
-                c -= n1;
-                r = ( m1 & ( bitBuffer >>> bitCount ) ) << c;
-                if( 0 == c ) {
-                    return r;
+            if( !useFastPathStream ) {
+                // Slow path
+                int r = 0;
+                for(int i=0; i < n; i++) {
+                    final int b = readBit(false /* msbFirst */);
+                    if( EOS == b ) {
+                        if( throwIOExceptionOnEOF ) {
+                            throw new IOException("EOS "+this);
+                        }
+                        return EOS;
+                    }
+                    r |= b << i;
                 }
+                return r;
             } else {
-                r = 0;
-            }
-            assert( 0 == bitCount );
-            do {
-                bitBuffer = bytes.read();
-                if( EOS == bitBuffer ) {
-                    if( throwIOExceptionOnEOF ) {
-                        throw new IOException("EOS "+this);
+                // fast path
+                int c = n;
+                final int n1 = Math.min(n, bitCount); // remaining portion
+                int r;
+                if( 0 < n1 ) {
+                    final int m1 = ( 1 << n1 ) - 1;
+                    final int s1 = 7 - bitCount + 1; // LSBfirst: right-shift to new bits
+                    bitCount -= n1;
+                    c -= n1;
+                    // MSBfirst: r = ( m1 & ( bitBuffer >>> bitCount ) ) << c;
+                    r = ( m1 & ( bitBuffer >>> s1 ) ); // LSBfirst
+                    if( 0 == c ) {
+                        return r;
                     }
-                    return EOS;
+                } else {
+                    r = 0;
                 }
-                final int n2 = Math.min(c, 8); // full portion
-                final int m2 = ( 1 << n2 ) - 1;
-                bitCount = 8 - n2;
-                c -= n2;
-                r |= ( m2 & ( bitBuffer >>> bitCount ) ) << c;
-            } while ( 0 < c );
-            return r;
+                assert( 0 == bitCount );
+                int s = n1; // LSBfirst: left shift for additional elements
+                do {
+                    bitBuffer = bytes.read();
+                    if( EOS == bitBuffer ) {
+                        if( throwIOExceptionOnEOF ) {
+                            throw new IOException("EOS "+this);
+                        }
+                        return EOS;
+                    }
+                    final int n2 = Math.min(c, 8); // full portion
+                    final int m2 = ( 1 << n2 ) - 1;
+                    bitCount = 8 - n2;
+                    c -= n2;
+                    // MSBfirst: r |= ( m2 & ( bitBuffer >>> bitCount ) ) << c;
+                    r |= ( m2 & bitBuffer ) << s; // LSBfirst on new bits
+                    s += n2;
+                } while ( 0 < c );
+                return r;
+            }
         }
     }
 
     /**
-     * Write the given bits via {@link #writeBit(boolean, int)}.
+     * Write the given bits via {@link #writeBit(boolean, int)} LSB-first as little-endian.
      * <p>
-     * The given bits are scanned from LSB-first order.
-     * Hence reading w/ <i>msbFirst</i>, the bit order will be reversed!
+     * The outgoing bit order is from low- to most-significant-bit, maintaining bit LSB-first order.
      * </p>
-     * @param msbFirst if true incoming stream bit order is MSB to LSB, otherwise LSB to MSB.
      * @param n number of bits, maximum 31 bits
      * @param bits the bits to write
      * @return the written bits or {@link #EOS}.
@@ -1025,76 +1104,81 @@ public class Bitstream<T> {
      * @throws IllegalArgumentException if n > 31
      * @throws IOException
      */
-    public int writeBits31(final boolean msbFirst, final int n, final int bits) throws IllegalStateException, IllegalArgumentException, IOException {
+    public int writeBits31(final int n, final int bits) throws IllegalStateException, IllegalArgumentException, IOException {
         if( 31 < n ) {
             throw new IllegalArgumentException("n > 31: "+n);
         }
         if( !outputMode || null == bytes ) {
             throw new IllegalStateException("not in output-mode: "+this);
         }
-        if( !msbFirst || 0 == n ) {
-            // Slow path
-            int c = n;
-            while(--c >= 0) {
-                final int b = writeBit(msbFirst, ( bits >>> c ) & 0x1);
-                if( EOS == b ) {
-                    return EOS;
-                }
-            }
-        } else {
-            // fast path: MSB
-            int c = n;
-            final int n1 = Math.min(c, bitCount); // remaining portion
-            if( 0 < n1 ) {
-                final int m1 = ( 1 << n1 ) - 1;
-                bitCount -= n1;
-                c -= n1;
-                bitBuffer |= ( m1 & ( bits >> c ) ) << bitCount;
-                if( 0 == bitCount ) {
-                    if( EOS == bytes.write((byte)bitBuffer) ) {
-                        if( throwIOExceptionOnEOF ) {
-                            throw new IOException("EOS "+this);
-                        }
+        if( 0 < n ) {
+            if( !useFastPathStream ) {
+                // Slow path
+                for(int i=0; i < n; i++) {
+                    final int b = writeBit(false /* msbFirst */, ( bits >>> i ) & 0x1);
+                    if( EOS == b ) {
                         return EOS;
                     }
                 }
-                if( 0 == c ) {
-                    return bits;
-                }
-            }
-            assert( 0 == bitCount );
-            do {
-                final int n2 = Math.min(c, 8); // full portion
-                final int m2 = ( 1 << n2 ) - 1;
-                bitCount = 8 - n2;
-                c -= n2;
-                bitBuffer = ( m2 & ( bits >> c ) ) << bitCount;
-                if( 0 == bitCount ) {
-                    if( EOS == bytes.write((byte)bitBuffer) ) {
-                        if( throwIOExceptionOnEOF ) {
-                            throw new IOException("EOS "+this);
+            } else {
+                // fast path
+                int c = n;
+                final int n1 = Math.min(n, bitCount); // remaining portion
+                if( 0 < n1 ) {
+                    final int m1 = ( 1 << n1 ) - 1;
+                    final int s1 = 7 - bitCount + 1; // LSBfirst: left-shift to free bit-pos
+                    bitCount -= n1;
+                    c -= n1;
+                    // MSBfirst: bitBuffer |= ( m1 & ( bits >>> c ) ) << bitCount;
+                    bitBuffer |= ( m1 & bits ) << s1 ; // LSBfirst
+                    if( 0 == bitCount ) {
+                        if( EOS == bytes.write((byte)bitBuffer) ) {
+                            if( throwIOExceptionOnEOF ) {
+                                throw new IOException("EOS "+this);
+                            }
+                            return EOS;
                         }
-                        return EOS;
+                    }
+                    if( 0 == c ) {
+                        return bits;
                     }
                 }
-            } while ( 0 < c );
+                assert( 0 == bitCount );
+                int s = n1; // LSBfirst: left shift for additional elements
+                do {
+                    final int n2 = Math.min(c, 8); // full portion
+                    final int m2 = ( 1 << n2 ) - 1;
+                    bitCount = 8 - n2;
+                    c -= n2;
+                    // MSBfirst: bitBuffer = ( m2 & ( bits >>> c ) ) << bitCount;
+                    bitBuffer = ( m2 & ( bits >>> s ) ); // LSBfirst
+                    s += n2;
+                    if( 0 == bitCount ) {
+                        if( EOS == bytes.write((byte)bitBuffer) ) {
+                            if( throwIOExceptionOnEOF ) {
+                                throw new IOException("EOS "+this);
+                            }
+                            return EOS;
+                        }
+                    }
+                } while ( 0 < c );
+            }
         }
         return bits;
     }
 
     /**
-     * Return incoming <code>uint8_t</code> as read via {@link #readBits31(boolean, int)}.
+     * Return incoming <code>uint8_t</code> as read via {@link #readBits31(int)}.
      * <p>
      * In case of a <code>int8_t</code> 2-complement signed value, simply cast the result to <code>byte</code>
      * after checking for {@link #EOS}.
      * </p>
-     * @param msbFirst if true incoming stream bit order is MSB to LSB, otherwise LSB to MSB.
      * @return {@link #EOS} or the 8bit unsigned value within the lower bits.
      * @throws IllegalStateException if not in input mode or stream closed
      * @throws IOException
      */
-    public final int readUInt8(final boolean msbFirst) throws IllegalStateException, IOException {
-        if( 0 == bitCount && msbFirst ) {
+    public final int readUInt8() throws IllegalStateException, IOException {
+        if( 0 == bitCount && useFastPathTypes ) {
             // fast path
             if( outputMode || null == bytes ) {
                 throw new IllegalStateException("not in input-mode: "+this);
@@ -1105,19 +1189,18 @@ public class Bitstream<T> {
             }
             return r;
         } else {
-            return readBits31(msbFirst, 8);
+            return readBits31(8);
         }
     }
 
     /**
-     * Write the given 8 bits via {@link #writeBits31(boolean, int, int)}.
-     * @param msbFirst if true incoming stream bit order is MSB to LSB, otherwise LSB to MSB.
+     * Write the given 8 bits via {@link #writeBits31(int, int)}.
      * @return {@link #EOS} or the written 8bit value.
      * @throws IllegalStateException if not in output mode or stream closed
      * @throws IOException
      */
-    public final int writeInt8(final boolean msbFirst, final byte int8) throws IllegalStateException, IOException {
-        if( 0 == bitCount && msbFirst ) {
+    public final int writeInt8(final byte int8) throws IllegalStateException, IOException {
+        if( 0 == bitCount && useFastPathTypes  ) {
             // fast path
             if( !outputMode || null == bytes ) {
                 throw new IllegalStateException("not in output-mode: "+this);
@@ -1128,25 +1211,24 @@ public class Bitstream<T> {
             }
             return r;
         } else {
-            return this.writeBits31(msbFirst, 8, int8);
+            return this.writeBits31(8, int8);
         }
     }
 
     /**
-     * Return incoming <code>uint16_t</code> as read via {@link #readBits31(boolean, int)}
-     * and swap bytes if !bigEndian.
+     * Return incoming <code>uint16_t</code> as read via {@link #readBits31(int)} LSB-first as little-endian,
+     * hence bytes are swapped if bigEndian.
      * <p>
      * In case of a <code>int16_t</code> 2-complement signed value, simply cast the result to <code>short</code>
      * after checking for {@link #EOS}.
      * </p>
-     * @param msbFirst if true incoming stream bit order is MSB to LSB, otherwise LSB to MSB.
-     * @param bigEndian if false, swap incoming bytes to little-endian, otherwise leave them as big-endian.
+     * @param bigEndian if true, swap incoming bytes to little-endian, otherwise leave them as little-endian.
      * @return {@link #EOS} or the 16bit unsigned value within the lower bits.
      * @throws IllegalStateException if not in input mode or stream closed
      * @throws IOException
      */
-    public final int readUInt16(final boolean msbFirst, final boolean bigEndian) throws IllegalStateException, IOException {
-        if( 0 == bitCount && msbFirst ) {
+    public final int readUInt16(final boolean bigEndian) throws IllegalStateException, IOException {
+        if( 0 == bitCount && useFastPathTypes ) {
             // fast path
             if( outputMode || null == bytes ) {
                 throw new IllegalStateException("not in input-mode: "+this);
@@ -1164,21 +1246,21 @@ public class Bitstream<T> {
                 return b2 << 8 | b1;
             }
         } else {
-            final int i16 = readBits31(msbFirst, 16);
+            final int i16 = readBits31(16);
             if( EOS == i16 ) {
                 return EOS;
             } else if( bigEndian ) {
-                return i16;
-            } else {
                 final int b1 = 0xff & ( i16 >>> 8 );
                 final int b2 = 0xff &   i16;
                 return b2 << 8 | b1;
+            } else {
+                return i16;
             }
         }
     }
 
     /**
-     * Return incoming <code>uint16_t</code> value and swap bytes if !bigEndian.
+     * Return incoming <code>uint16_t</code> value and swap bytes according to bigEndian.
      * <p>
      * In case of a <code>int16_t</code> 2-complement signed value, simply cast the result to <code>short</code>.
      * </p>
@@ -1199,16 +1281,15 @@ public class Bitstream<T> {
     }
 
     /**
-     * Write the given 16 bits via {@link #writeBits31(boolean, int, int)},
-     * while swapping bytes if !bigEndian beforehand.
-     * @param msbFirst if true incoming stream bit order is MSB to LSB, otherwise LSB to MSB.
-     * @param bigEndian if false, swap given bytes to little-endian, otherwise leave them as big-endian.
+     * Write the given 16 bits via {@link #writeBits31(int, int)} LSB-first as little-endian,
+     * hence bytes are swapped if bigEndian.
+     * @param bigEndian if true, swap given bytes to little-endian, otherwise leave them as little-endian.
      * @return {@link #EOS} or the written 16bit value.
      * @throws IllegalStateException if not in output mode or stream closed
      * @throws IOException
      */
-    public final int writeInt16(final boolean msbFirst, final boolean bigEndian, final short int16) throws IllegalStateException, IOException {
-        if( 0 == bitCount && msbFirst ) {
+    public final int writeInt16(final boolean bigEndian, final short int16) throws IllegalStateException, IOException {
+        if( 0 == bitCount && useFastPathTypes ) {
             // fast path
             if( !outputMode || null == bytes ) {
                 throw new IllegalStateException("not in output-mode: "+this);
@@ -1233,29 +1314,28 @@ public class Bitstream<T> {
             }
             return EOS;
         } else if( bigEndian ) {
-            return writeBits31(msbFirst, 16, int16);
-        } else {
             final int b1 = 0xff & ( int16 >>> 8 );
             final int b2 = 0xff &   int16;
-            return writeBits31(msbFirst, 16, b2 << 8 | b1);
+            return writeBits31(16, b2 << 8 | b1);
+        } else {
+            return writeBits31(16, int16);
         }
     }
 
     /**
-     * Return incoming <code>uint32_t</code> as read via {@link #readBits31(boolean, int)}
-     * and swap bytes if !bigEndian.
+     * Return incoming <code>uint32_t</code> as read via {@link #readBits31(int)} LSB-first as little-endian,
+     * hence bytes are swapped if bigEndian.
      * <p>
      * In case of a <code>int32_t</code> 2-complement signed value, simply cast the result to <code>int</code>
      * after checking for {@link #EOS}.
      * </p>
-     * @param msbFirst if true incoming stream bit order is MSB to LSB, otherwise LSB to MSB.
-     * @param bigEndian if false, swap incoming bytes to little-endian, otherwise leave them as big-endian.
+     * @param bigEndian if true, swap incoming bytes to little-endian, otherwise leave them as little-endian.
      * @return {@link #EOS} or the 32bit unsigned value within the lower bits.
      * @throws IllegalStateException if not in input mode or stream closed
      * @throws IOException
      */
-    public final long readUInt32(final boolean msbFirst, final boolean bigEndian) throws IllegalStateException, IOException {
-        if( 0 == bitCount && msbFirst ) {
+    public final long readUInt32(final boolean bigEndian) throws IllegalStateException, IOException {
+        if( 0 == bitCount && useFastPathTypes ) {
             // fast path
             if( outputMode || null == bytes ) {
                 throw new IllegalStateException("not in input-mode: "+this);
@@ -1275,24 +1355,24 @@ public class Bitstream<T> {
                 return 0xffffffffL & ( b4 << 24 | b3 << 16 | b2 << 8 | b1 );
             }
         } else {
-            final int i16a = readBits31(msbFirst, 16);
-            final int i16b = EOS != i16a ? readBits31(msbFirst, 16) : EOS;
+            final int i16a = readBits31(16);
+            final int i16b = EOS != i16a ? readBits31(16) : EOS;
             if( EOS == i16b ) {
                 return EOS;
             } else if( bigEndian ) {
-                return 0xffffffffL & ( i16a << 16 | i16b );
-            } else {
-                final int b1 = 0xff & ( i16a >>> 8 );
-                final int b2 = 0xff &   i16a;
-                final int b3 = 0xff & ( i16b >>> 8 );
-                final int b4 = 0xff &   i16b;
+                final int b1 = 0xff & ( i16b >>> 8 );
+                final int b2 = 0xff &   i16b;
+                final int b3 = 0xff & ( i16a >>> 8 );
+                final int b4 = 0xff &   i16a;
                 return 0xffffffffL & ( b4 << 24 | b3 << 16 | b2 << 8 | b1 );
+            } else {
+                return 0xffffffffL & ( i16b << 16 | i16a );
             }
         }
     }
 
     /**
-     * Return incoming <code>uint32_t</code> and swap bytes if !bigEndian.
+     * Return incoming <code>uint32_t</code> and swap bytes according to bigEndian.
      * <p>
      * In case of a <code>int32_t</code> 2-complement signed value, simply cast the result to <code>int</code>.
      * </p>
@@ -1314,16 +1394,15 @@ public class Bitstream<T> {
     }
 
     /**
-     * Write the given 32 bits via {@link #writeBits31(boolean, int, int)},
-     * while swapping bytes if !bigEndian beforehand.
-     * @param msbFirst if true incoming stream bit order is MSB to LSB, otherwise LSB to MSB.
-     * @param bigEndian if false, swap given bytes to little-endian, otherwise leave them as little-endian.
+     * Write the given 32 bits via {@link #writeBits31(int, int)} LSB-first as little-endian,
+     * hence bytes are swapped if bigEndian.
+     * @param bigEndian if true, swap given bytes to little-endian, otherwise leave them as little-endian.
      * @return {@link #EOS} or the written 32bit value.
      * @throws IllegalStateException if not in output mode or stream closed
      * @throws IOException
      */
-    public final int writeInt32(final boolean msbFirst, final boolean bigEndian, final int int32) throws IllegalStateException, IOException {
-        if( 0 == bitCount && msbFirst ) {
+    public final int writeInt32(final boolean bigEndian, final int int32) throws IllegalStateException, IOException {
+        if( 0 == bitCount && useFastPathTypes ) {
             // fast path
             if( !outputMode || null == bytes ) {
                 throw new IllegalStateException("not in output-mode: "+this);
@@ -1358,21 +1437,21 @@ public class Bitstream<T> {
             }
             return EOS;
         } else if( bigEndian ) {
-            final int hi = 0x0000ffff & ( int32 >>> 16 );
-            final int lo = 0x0000ffff &   int32 ;
-            if( EOS != writeBits31(msbFirst, 16, hi) ) {
-                if( EOS != writeBits31(msbFirst, 16, lo) ) {
+            final int p1 = 0xff & ( int32 >>> 24 );
+            final int p2 = 0xff & ( int32 >>> 16 );
+            final int p3 = 0xff & ( int32 >>>  8 );
+            final int p4 = 0xff &   int32         ;
+            if( EOS != writeBits31(16, p2 << 8 | p1) ) {
+                if( EOS != writeBits31(16, p4 << 8 | p3) ) {
                     return int32;
                 }
             }
             return EOS;
         } else {
-            final int p1 = 0xff & ( int32 >>> 24 );
-            final int p2 = 0xff & ( int32 >>> 16 );
-            final int p3 = 0xff & ( int32 >>>  8 );
-            final int p4 = 0xff &   int32         ;
-            if( EOS != writeBits31(msbFirst, 16, p4 << 8 | p3) ) {
-                if( EOS != writeBits31(msbFirst, 16, p2 << 8 | p1) ) {
+            final int hi = 0x0000ffff & ( int32 >>> 16 );
+            final int lo = 0x0000ffff &   int32 ;
+            if( EOS != writeBits31(16, lo) ) {
+                if( EOS != writeBits31(16, hi) ) {
                     return int32;
                 }
             }
@@ -1429,22 +1508,52 @@ public class Bitstream<T> {
             bpos = bytes.position();
         }
         return String.format("%s, pos %d [byteP %d, bitCnt %d], bitbuf %s",
-                mode, position(), bpos, bitCount, toHexBinString(bitBuffer, 8));
+                mode, position(), bpos, bitCount, toHexBinString(true, bitBuffer, 8));
     }
 
     private static final String strZeroPadding= "0000000000000000000000000000000000000000000000000000000000000000"; // 64
-    public static String toBinString(final int v, final int bitCount) {
+    public static String toBinString(final boolean msbFirst, final int v, final int bitCount) {
         if( 0 == bitCount ) {
             return "";
         }
-        final int mask = (int) ( ( 1L << bitCount ) - 1L );
-        final String s0 = Integer.toBinaryString( mask & v );
-        return strZeroPadding.substring(0, bitCount-s0.length())+s0;
+        if( msbFirst ) {
+            final int mask = (int) ( ( 1L << bitCount ) - 1L );
+            final String s0 = Integer.toBinaryString( mask & v );
+            return strZeroPadding.substring(0, bitCount-s0.length())+s0;
+        } else {
+            final char[] c = new char[32];
+            for(int i=0; i<bitCount; i++) {
+                c[i] = 0 != ( v & ( 1 << i ) ) ? '1' : '0';
+            }
+            final String s0 = new String(c, 0, bitCount);
+            return s0+strZeroPadding.substring(0, bitCount-s0.length());
+        }
     }
-    public static String toHexBinString(final int v, final int bitCount) {
+    public static String toHexBinString(final boolean msbFirst, final int v, final int bitCount) {
         final int nibbles = 0 == bitCount ? 2 : ( bitCount + 3 ) / 4;
-        return String.format("[%0"+nibbles+"X, %s]", v, toBinString(v, bitCount));
+        return String.format("[0x%0"+nibbles+"X, msbFirst %b, %s]", v, msbFirst, toBinString(msbFirst, v, bitCount));
+    }
+    public static final String toHexBinString(final boolean msbFirst, final byte[] data, final int offset, final int len) {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("[");
+        for(int i=0; i<len; i++) {
+            final int v = 0xFF & data[offset+i];
+            sb.append(toHexBinString(msbFirst, v, 8)).append(", ");
+        }
+        sb.append("]");
+        return sb.toString();
     }
+    public static final String toHexBinString(final boolean msbFirst, final ByteBuffer data, final int offset, final int len) {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("[");
+        for(int i=0; i<len; i++) {
+            final int v = 0xFF & data.get(offset+i);
+            sb.append(toHexBinString(msbFirst, v, 8)).append(", ");
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
     public static void checkBounds(final byte[] sb, final int offset, final int remaining) throws IndexOutOfBoundsException {
         if( offset + remaining > sb.length ) {
             throw new IndexOutOfBoundsException("Buffer of size "+sb.length+" cannot hold offset "+offset+" + remaining "+remaining);
diff --git a/src/java/com/jogamp/common/util/IOUtil.java b/src/java/com/jogamp/common/util/IOUtil.java
index d5a9544..88542c4 100644
--- a/src/java/com/jogamp/common/util/IOUtil.java
+++ b/src/java/com/jogamp/common/util/IOUtil.java
@@ -39,8 +39,9 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.PrintStream;
+import java.io.Reader;
+import java.lang.ref.WeakReference;
 import java.lang.reflect.Constructor;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLConnection;
@@ -52,26 +53,14 @@ import jogamp.common.os.AndroidUtils;
 import jogamp.common.os.PlatformPropsImpl;
 
 import com.jogamp.common.net.AssetURLContext;
+import com.jogamp.common.net.Uri;
 import com.jogamp.common.nio.Buffers;
-import com.jogamp.common.os.MachineDescription;
+import com.jogamp.common.os.MachineDataInfo;
 import com.jogamp.common.os.Platform;
 
 public class IOUtil {
     public static final boolean DEBUG = Debug.debug("IOUtil");
 
-    /** {@value} */
-    public static final String SCHEME_SEPARATOR = ":";
-    /** {@value} */
-    public static final String FILE_SCHEME = "file";
-    /** {@value} */
-    public static final String HTTP_SCHEME = "http";
-    /** {@value} */
-    public static final String HTTPS_SCHEME = "https";
-    /** {@value} */
-    public static final String JAR_SCHEME = "jar";
-    /** A JAR subprotocol is separeted from the JAR entry w/ this separator {@value}. Even if no class is specified '!/' must follow!. */
-    public static final char JAR_SCHEME_SEPARATOR = '!';
-
     /** Std. temporary directory property key <code>java.io.tmpdir</code>. */
     private static final String java_io_tmpdir_propkey = "java.io.tmpdir";
     private static final String user_home_propkey = "user.home";
@@ -121,7 +110,7 @@ public class IOUtil {
 
     /**
      * Copy the specified URL resource to the specified output file. The total
-     * number of bytes written is returned. Both streams are closed upon completion.
+     * number of bytes written is returned.
      *
      * @param conn the open URLConnection
      * @param outFile the destination
@@ -143,7 +132,7 @@ public class IOUtil {
 
     /**
      * Copy the specified input stream to the specified output file. The total
-     * number of bytes written is returned. Both streams are closed upon completion.
+     * number of bytes written is returned.
      *
      * @param in the source
      * @param outFile the destination
@@ -172,14 +161,14 @@ public class IOUtil {
      * @throws IOException
      */
     public static int copyStream2Stream(final InputStream in, final OutputStream out, final int totalNumBytes) throws IOException {
-        return copyStream2Stream(Platform.getMachineDescription().pageSizeInBytes(), in, out, totalNumBytes);
+        return copyStream2Stream(Platform.getMachineDataInfo().pageSizeInBytes(), in, out, totalNumBytes);
     }
 
     /**
      * Copy the specified input stream to the specified output stream. The total
      * number of bytes written is returned.
      *
-     * @param bufferSize the intermediate buffer size, should be {@link MachineDescription#pageSizeInBytes()} for best performance.
+     * @param bufferSize the intermediate buffer size, should be {@link MachineDataInfo#pageSizeInBytes()} for best performance.
      * @param in the source
      * @param out the destination
      * @param totalNumBytes informal number of expected bytes, maybe used for user feedback while processing. -1 if unknown
@@ -200,6 +189,15 @@ public class IOUtil {
         return numBytes;
     }
 
+    public static StringBuilder appendCharStream(final StringBuilder sb, final Reader r) throws IOException {
+        final char[] cbuf = new char[1024];
+        int count;
+        while( 0 < ( count = r.read(cbuf) ) ) {
+            sb.append(cbuf, 0, count);
+        }
+        return sb;
+    }
+
     /**
      * Copy the specified input stream to a byte array, which is being returned.
      */
@@ -258,7 +256,7 @@ public class IOUtil {
         if( initialCapacity < avail ) {
             initialCapacity = avail;
         }
-        final MachineDescription machine = Platform.getMachineDescription();
+        final MachineDataInfo machine = Platform.getMachineDataInfo();
         ByteBuffer data = Buffers.newDirectByteBuffer( machine.pageAlignedSize( initialCapacity ) );
         final byte[] chunk = new byte[machine.pageSizeInBytes()];
         int chunk2Read = Math.min(machine.pageSizeInBytes(), avail);
@@ -289,6 +287,8 @@ public class IOUtil {
      *
      */
 
+    private static final Pattern patternSingleBS = Pattern.compile("\\\\{1}");
+
     /**
      *
      * @param path
@@ -298,7 +298,7 @@ public class IOUtil {
      * @throws URISyntaxException if path is empty or has no parent directory available while resolving <code>../</code>
      */
     public static String slashify(final String path, final boolean startWithSlash, final boolean endWithSlash) throws URISyntaxException {
-        String p = path.replace('\\', '/'); // unify file separator
+        String p = patternSingleBS.matcher(path).replaceAll("/");
         if (startWithSlash && !p.startsWith("/")) {
             p = "/" + p;
         }
@@ -309,24 +309,6 @@ public class IOUtil {
     }
 
     /**
-     * Using the simple conversion via File -> URI, assuming proper characters.
-     * @throws URISyntaxException if path is empty or has no parent directory available while resolving <code>../</code>
-     * @throws URISyntaxException if the resulting string does not comply w/ an RFC 2396 URI
-     */
-    public static URI toURISimple(final File file) throws URISyntaxException {
-        return new URI(FILE_SCHEME, null, slashify(file.getAbsolutePath(), true /* startWithSlash */, file.isDirectory() /* endWithSlash */), null);
-    }
-
-    /**
-     * Using the simple conversion via File -> URI, assuming proper characters.
-     * @throws URISyntaxException if path is empty or has no parent directory available while resolving <code>../</code>
-     * @throws URISyntaxException if the resulting string does not comply w/ an RFC 2396 URI
-     */
-    public static URI toURISimple(final String protocol, final String path, final boolean isDirectory) throws URISyntaxException {
-        return new URI(protocol, null, slashify(new File(path).getAbsolutePath(), true /* startWithSlash */, isDirectory /* endWithSlash */), null);
-    }
-
-    /**
      * Returns the lowercase suffix of the given file name (the text
      * after the last '.' in the file name). Returns null if the file
      * name has no suffix. Only operates on the given file name;
@@ -434,79 +416,6 @@ public class IOUtil {
         return fname;
     }
 
-    /**
-     * The URI's <code><i>protocol</i>:/some/path/gluegen-rt.jar</code>
-     * parent dirname URI <code><i>protocol</i>:/some/path/</code> will be returned.
-     * <p>
-     * <i>protocol</i> may be "file", "http", etc..
-     * </p>
-     *
-     * @param uri "<i>protocol</i>:/some/path/gluegen-rt.jar"
-     * @return "<i>protocol</i>:/some/path/"
-     * @throws IllegalArgumentException if the URI doesn't match the expected formatting, or is null
-     * @throws URISyntaxException
-     */
-    public static URI getURIDirname(final URI uri) throws IllegalArgumentException, URISyntaxException {
-        if(null == uri) {
-            throw new IllegalArgumentException("URI is null");
-        }
-        final String uriS = uri.toString();
-        if( DEBUG ) {
-            System.err.println("getURIDirname "+uri+", extForm: "+uriS);
-        }
-        return new URI( getURIDirname(uriS) );
-    }
-
-    /**
-     * The URI's <code><i>protocol</i>:/some/path/gluegen-rt.jar</code>
-     * parent dirname URI <code><i>protocol</i>:/some/path/</code> will be returned.
-     * <p>
-     * <i>protocol</i> may be "file", "http", etc..
-     * </p>
-     *
-     * @param uri "<i>protocol</i>:/some/path/gluegen-rt.jar" (URI encoded)
-     * @return "<i>protocol</i>:/some/path/"
-     * @throws IllegalArgumentException if the URI doesn't match the expected formatting, or is null
-     * @throws URISyntaxException
-     */
-    public static String getURIDirname(String uriS) throws IllegalArgumentException, URISyntaxException {
-        if(null == uriS) {
-            throw new IllegalArgumentException("uriS is null");
-        }
-        // from
-        //   file:/some/path/gluegen-rt.jar  _or_ rsrc:gluegen-rt.jar
-        // to
-        //   file:/some/path/                _or_ rsrc:
-        int idx = uriS.lastIndexOf('/');
-        if(0 > idx) {
-            // no abs-path, check for protocol terminator ':'
-            idx = uriS.lastIndexOf(':');
-            if(0 > idx) {
-                throw new IllegalArgumentException("URI does not contain protocol terminator ':', in <"+uriS+">");
-            }
-        }
-        uriS = uriS.substring(0, idx+1); // exclude jar name, include terminal '/' or ':'
-
-        if( DEBUG ) {
-            System.err.println("getJarURIDirname res: "+uriS);
-        }
-        return uriS;
-    }
-
-    /**
-     * Simply returns {@link URI#toURL()}.
-     * @param uri
-     * @return
-     * @throws IOException
-     * @throws IllegalArgumentException
-     * @throws URISyntaxException
-     *
-     * @deprecated Useless
-     */
-    public static URL toURL(final URI uri) throws IOException, IllegalArgumentException, URISyntaxException {
-        return uri.toURL();
-    }
-
     /***
      *
      * RESOURCE LOCATION STUFF
@@ -705,218 +614,21 @@ public class IOUtil {
         return path;
     }
 
-    /**
-     * Generates a URI for the <i>relativePath</i> relative to the <i>baseURI</i>,
-     * hence the result is a absolute location.
-     * <p>
-     * Impl. operates on the <i>scheme-specific-part</i>, and hence is sub-protocol savvy.
-     * </p>
-     * <p>
-     * In case <i>baseURI</i> is not a path ending w/ '/', it's a assumed to be a file and it's parent is being used.
-     * </p>
-     *
-     * @param baseURI denotes a URI to a directory ending w/ '/', or a file. In the latter case the file's directory is being used.
-     * @param relativePath denotes a relative file to the baseLocation's parent directory (URI encoded)
-     * @throws URISyntaxException if path is empty or has no parent directory available while resolving <code>../</code>
-     */
-    public static URI getRelativeOf(final URI baseURI, final String relativePath) throws URISyntaxException {
-        return compose(baseURI.getScheme(), baseURI.getRawSchemeSpecificPart(), relativePath, baseURI.getRawFragment());
-    }
-
-    /**
-     * Wraps {@link #getRelativeOf(URI, String)} for convenience.
-     * @param relativePath denotes a relative file to the baseLocation's parent directory (URI encoded)
-     * @throws IOException
-     */
-    public static URL getRelativeOf(final URL baseURL, final String relativePath) throws IOException {
-        try {
-            return getRelativeOf(baseURL.toURI(), relativePath).toURL();
-        } catch (final URISyntaxException e) {
-            throw new IOException(e);
-        }
-    }
-
-    /**
-     * Generates a URI for the <i>relativePath</i> relative to the <i>schemeSpecificPart</i>,
-     * hence the result is a absolute location.
-     * <p>
-     * <i>schemeSpecificPart</i>'s query, if exist is split to <i>path</i> and <i>query</i>.
-     * </p>
-     * <p>
-     * In case <i>path</i> is not a path ending w/ '/', it's a assumed to be a file and it's parent is being used.
-     * </p>
-     *
-     * @param scheme scheme of the resulting URI
-     * @param schemeSpecificPart may include a query, which is separated while processing (URI encoded)
-     * @param relativePath denotes a relative file to the baseLocation's parent directory (URI encoded)
-     * @param fragment the URI fragment (URI encoded)
-     * @throws URISyntaxException if path is empty or has no parent directory available while resolving <code>../</code>
-     * @see #encodeToURI(String)
-     */
-    public static URI compose(final String scheme, String schemeSpecificPart, final String relativePath, final String fragment) throws URISyntaxException {
-        // cut off optional query in scheme-specific-part
-        final String query;
-        final int queryI = schemeSpecificPart.lastIndexOf('?');
-        if( queryI >= 0 ) {
-            query = schemeSpecificPart.substring(queryI+1);
-            schemeSpecificPart = schemeSpecificPart.substring(0, queryI);
-        } else {
-            query = null;
-        }
-        if( null != relativePath ) {
-            if( !schemeSpecificPart.endsWith("/") ) {
-                schemeSpecificPart = getParentOf(schemeSpecificPart);
-            }
-            schemeSpecificPart = schemeSpecificPart + relativePath;
-        }
-        schemeSpecificPart = cleanPathString( schemeSpecificPart );
-        final StringBuilder uri = new StringBuilder();
-        uri.append(scheme);
-        uri.append(':');
-        uri.append(schemeSpecificPart);
-        if ( null != query ) {
-            uri.append('?');
-            uri.append(query);
-        }
-        if ( null != fragment ) {
-            uri.append('#');
-            uri.append(fragment);
-        }
-        return new URI(uri.toString());
-    }
-
-    private static final Pattern patternSpaceRaw = Pattern.compile(" ");
-    private static final Pattern patternSpaceEnc = Pattern.compile("%20");
-
-    /**
-     * Escapes characters not complying w/ RFC 2396 and the {@link URI#URI(String)} ctor.
-     * <ul>
-     *   <li>SPACE -> %20</li>
-     * </ul>
-     * @deprecated Useless
-     */
-    public static String encodeToURI(final String vanilla) {
-        return patternSpaceRaw.matcher(vanilla).replaceAll("%20"); // Uri TODO: Uri.encode(vanilla, Uri.PATH_MIN_LEGAL);
-    }
-
-    /**
-     * Reverses escaping of characters as performed via {@link #encodeToURI(String)}.
-     * <ul>
-     *   <li>%20 -> SPACE</li>
-     * </ul>
-     * @deprecated Use {@link #decodeURIIfFilePath(URI)}
-     */
-    public static String decodeFromURI(final String encodedUri) {
-        return patternSpaceEnc.matcher(encodedUri).replaceAll(" "); // Uri TODO: Uri.decode(encoded);
-    }
-
-    private static final Pattern patternSingleBS = Pattern.compile("\\\\{1}");
-    private static final Pattern patternSingleFS = Pattern.compile("/{1}");
-
-    /**
-     * Encodes file path characters not complying w/ RFC 2396 and the {@link URI#URI(String)} ctor.
-     * <p>
-     * Implementation processes the <code>filePath</code> if {@link File#separatorChar} <code> == '\\'</code>
-     * as follows:
-     * <ul>
-     *   <li>backslash -> slash</li>
-     *   <li>ensure starting with slash</li>
-     * </ul>
-     * </p>
-     * <p>
-     * Note that this method does not perform <i>space</i> encoding,
-     * which can be utilized via {@link #encodeToURI(String)}.
-     * </p>
-     * <p>
-     * Even though Oracle's JarURLStreamHandler can handle backslashes and
-     * erroneous URIs w/ e.g. Windows file 'syntax', other may not (Netbeans).<br>
-     * See Bug 857 - http://jogamp.org/bugzilla/show_bug.cgi?id=857
-     * </p>
-     * @see #encodeToURI(String)
-     * @deprecated Useless
-     */
-    public static String encodeFilePathToURI(final String filePath) {
-        if( File.separator.equals("\\") ) {
-            final String r = patternSingleBS.matcher(filePath).replaceAll("/");
-            if( !r.startsWith("/") ) {
-                return "/" + r;
-            } else {
-                return r;
-            }
-        }
-        return filePath;
-    }
-
-    /**
-     * Completes decoding uri-file path characters complying w/ RFC 2396 to native file-path.
-     * <p>
-     * Implementation decodes the space-encoding <code>path={@link #decodeFromURI(String) decodeFromURI}(uriPath)</code>.
-     * </p>
-     * <p>
-     * Then it processes the <code>path</code> if {@link File#separatorChar} <code> == '\\'</code>
-     * as follows:
-     * <ul>
-     *   <li>slash -> backslash</li>
-     *   <li>drop a starting single backslash, preserving windows UNC</li>
-     * </ul>
-     * </p>
-     * @param encodedUriPath URI encoded path
-     * @see #decodeFromURI(String)
-     * @deprecated Use {@link #decodeURIIfFilePath(URI)}
-     */
-    public static String decodeURIToFilePath(final String encodedUriPath) {
-        final String path = patternSpaceEnc.matcher(encodedUriPath).replaceAll(" "); // Uri TODO: Uri.decode(encoded);
-        if( File.separator.equals("\\") ) {
-            final String r = patternSingleFS.matcher(path).replaceAll("\\\\");
-            if( r.startsWith("\\") && !r.startsWith("\\\\") ) { // '\\\\' denotes UNC hostname, which shall not be cut-off
-                return r.substring(1);
-            } else {
-                return r;
-            }
-        }
-        return path;
-    }
+    public static final Pattern patternSpaceEnc = Pattern.compile("%20");
 
     /**
-     * If <code>uri</code> is a <i>file scheme</i>,
-     * implementation completes space-decoding <i>[ "//"+{@link URI#getAuthority()} ] + {@link URI#getPath()}</i>.<br>
-     * Then it processes the <code>path</code> if {@link File#separatorChar} <code> == '\\'</code>
-     * as follows:
-     * <ul>
-     *   <li>slash -> backslash</li>
-     *   <li>drop a starting single backslash, preserving windows UNC</li>
-     * </ul>
-     * </p>
+     * If <code>uri</code> is a <i>file scheme</i>
+     * implementation returns {@link Uri#toFile()}.{@link File#getPath()}.
      * <p>
      * Otherwise it returns the {@link URI#toASCIIString()} encoded URI.
      * </p>
-     *
-     * @see #decodeFromURI(String)
-     * @see #decodeURIToFilePath(String)
      */
-    public static String decodeURIIfFilePath(final URI uri) {
-        if( IOUtil.FILE_SCHEME.equals( uri.getScheme() ) ) {
-            final String authorityS;
-            {
-                final String authority = uri.getAuthority();
-                if( null == authority ) {
-                    authorityS = "";
-                } else {
-                    authorityS = "//"+authority;
-                }
-                final String path = patternSpaceEnc.matcher(authorityS+uri.getPath()).replaceAll(" "); // Uri TODO: Uri.decode(encoded);
-                if( File.separator.equals("\\") ) {
-                    final String r = patternSingleFS.matcher(path).replaceAll("\\\\");
-                    if( r.startsWith("\\") && !r.startsWith("\\\\") ) { // '\\\\' denotes UNC hostname, which shall not be cut-off
-                        return r.substring(1);
-                    } else {
-                        return r;
-                    }
-                }
-                return path;
-            }
+    public static String getUriFilePathOrASCII(final Uri uri) {
+        if( uri.isFileScheme() ) {
+            return uri.toFile().getPath();
+        } else {
+            return uri.toASCIIString().get();
         }
-        return uri.toASCIIString();
     }
 
     /**
@@ -951,15 +663,19 @@ public class IOUtil {
         return null;
     }
 
-    private static String getShellSuffix() {
+    private static String getExeTestFileSuffix() {
         switch(PlatformPropsImpl.OS_TYPE) {
             case WINDOWS:
-              return ".bat";
+              if( Platform.CPUFamily.X86 == PlatformPropsImpl.CPU_ARCH.family ) {
+                  return ".exe";
+              } else {
+                  return ".bat";
+              }
             default:
               return ".sh";
         }
     }
-    private static String getShellCode() {
+    private static String getExeTestShellCode() {
         switch(PlatformPropsImpl.OS_TYPE) {
             case WINDOWS:
               return "echo off"+PlatformPropsImpl.NEWLINE;
@@ -967,7 +683,71 @@ public class IOUtil {
               return null;
         }
     }
-
+    private static String[] getExeTestCommandArgs(final String scriptFile) {
+        switch(PlatformPropsImpl.OS_TYPE) {
+            case WINDOWS:
+            //   return new String[] { "cmd", "/c", scriptFile };
+            default:
+              return new String[] { scriptFile };
+        }
+    }
+    private static final byte[] getBytesFromRelFile(final byte[] res, final String fname, final int size) throws IOException {
+        final URLConnection con = IOUtil.getResource(IOUtil.class, fname);
+        final InputStream in = con.getInputStream();
+        int numBytes = 0;
+        try {
+            while (true) {
+                final int remBytes = size - numBytes;
+                int count;
+                if ( 0 >= remBytes || (count = in.read(res, numBytes, remBytes)) == -1 ) {
+                    break;
+                }
+                numBytes += count;
+            }
+        } finally {
+            in.close();
+        }
+        if( size != numBytes ) {
+            throw new IOException("Got "+numBytes+" bytes != expected "+size);
+        }
+        return res;
+    }
+    private static final Object exeTestBytesLock = new Object();
+    private static WeakReference<byte[]> exeTestBytesRef = null;
+
+    private static void fillExeTestFile(final File exefile) throws IOException {
+        if( Platform.OSType.WINDOWS == PlatformPropsImpl.OS_TYPE &&
+            Platform.CPUFamily.X86 == PlatformPropsImpl.CPU_ARCH.family
+          ) {
+            final int codeSize = 268;
+            final byte[] code;
+            synchronized ( exeTestBytesLock ) {
+                byte[] _code;
+                if( null == exeTestBytesRef || null == ( _code = exeTestBytesRef.get() ) ) {
+                    code = getBytesFromRelFile(new byte[512], "bin/exe-windows-i586-268b.bin", codeSize);
+                    exeTestBytesRef = new WeakReference<byte[]>(code);
+                } else {
+                    code = _code;
+                }
+            }
+            final OutputStream out = new FileOutputStream(exefile);
+            try {
+                out.write(code, 0, codeSize);
+            } finally {
+                out.close();
+            }
+        } else {
+            final String shellCode = getExeTestShellCode();
+            if( isStringSet(shellCode) ) {
+                final FileWriter fout = new FileWriter(exefile);
+                try {
+                    fout.write(shellCode);
+                } finally {
+                    fout.close();
+                }
+            }
+        }
+    }
     private static boolean getOSHasNoexecFS() {
         switch(PlatformPropsImpl.OS_TYPE) {
             case OPENKODE:
@@ -1099,9 +879,9 @@ public class IOUtil {
         }
 
         final long t0 = DEBUG ? System.currentTimeMillis() : 0;
-        File exetst;
+        final File exeTestFile;
         try {
-            exetst = File.createTempFile("jogamp_exe_tst", getShellSuffix(), dir);
+            exeTestFile = File.createTempFile("jogamp_exe_tst", getExeTestFileSuffix(), dir);
         } catch (final SecurityException se) {
             throw se; // fwd Security exception
         } catch (final IOException e) {
@@ -1112,17 +892,13 @@ public class IOUtil {
         }
         final long t1 = DEBUG ? System.currentTimeMillis() : 0;
         int res = -1;
-        if(exetst.setExecutable(true /* exec */, true /* ownerOnly */)) {
-            final String shellCode = getShellCode();
+        if(exeTestFile.setExecutable(true /* exec */, true /* ownerOnly */)) {
             try {
-                if( isStringSet(shellCode) ) {
-                    final FileWriter fout = new FileWriter(exetst);
-                    fout.write(shellCode);
-                    fout.close();
-                }
+                fillExeTestFile(exeTestFile);
+
                 // Using 'Process.exec(String[])' avoids StringTokenizer of 'Process.exec(String)'
                 // and hence splitting up command by spaces!
-                final Process pr = Runtime.getRuntime().exec(new String[] { exetst.getCanonicalPath() } );
+                final Process pr = Runtime.getRuntime().exec( getExeTestCommandArgs( exeTestFile.getCanonicalPath() ) );
                 /**
                  * Disable StreamMonitor, which throttles exec-test performance a lot!
                  *
@@ -1137,18 +913,19 @@ public class IOUtil {
             } catch (final Throwable t) {
                 res = -2;
                 if(DEBUG) {
-                    System.err.println("IOUtil.testDirExec: <"+exetst.getAbsolutePath()+">: Caught "+t.getClass().getSimpleName()+": "+t.getMessage());
-                    // t.printStackTrace();
+                    System.err.println("IOUtil.testDirExec: <"+exeTestFile.getAbsolutePath()+">: Caught "+t.getClass().getSimpleName()+": "+t.getMessage());
+                    t.printStackTrace();
                 }
             }
         }
+        final boolean ok = 0 == res;
         final long t2 = DEBUG ? System.currentTimeMillis() : 0;
-        exetst.delete();
+        exeTestFile.delete();
         if( DEBUG) {
-            System.err.println("IOUtil.testDirExec(): <"+dir.getAbsolutePath()+">: res "+res);
+            System.err.println("IOUtil.testDirExec(): <"+dir.getAbsolutePath()+">: res "+res+" -> "+ok);
             System.err.println("IOUtil.testDirExec(): total "+(t2-t0)+"ms, create "+(t1-t0)+"ms, execute "+(t2-t1)+"ms");
         }
-        return 0 == res;
+        return ok;
     }
 
     private static File testDirImpl(final File dir, final boolean create, final boolean executable, final String dbgMsg)
@@ -1256,14 +1033,14 @@ public class IOUtil {
      * a dot is being prepended to {@link #tmpSubDir}, i.e.: {@code /home/user/.jogamp_0000/}.
      * </p>
      * @param executable true if the user intents to launch executables from the temporary directory, otherwise false.
-     * @throws RuntimeException if no temporary directory could be determined
+     * @throws IOException if no temporary directory could be determined
      * @throws SecurityException if access to <code>java.io.tmpdir</code> is not allowed within the current security context
      *
      * @see PropertyAccess#getProperty(String, boolean)
      * @see Context#getDir(String, int)
      */
     public static File getTempDir(final boolean executable)
-        throws SecurityException, RuntimeException
+        throws SecurityException, IOException
     {
         if(!tempRootSet) { // volatile: ok
             synchronized(IOUtil.class) {
@@ -1388,7 +1165,7 @@ public class IOUtil {
         final File r = executable ? tempRootExec : tempRootNoexec ;
         if(null == r) {
             final String exe_s = executable ? "executable " : "";
-            throw new RuntimeException("Could not determine a temporary "+exe_s+"directory");
+            throw new IOException("Could not determine a temporary "+exe_s+"directory");
         }
         final FilePermission fp = new FilePermission(r.getAbsolutePath(), "read,write,delete");
         SecurityUtil.checkPermission(fp);
@@ -1412,7 +1189,7 @@ public class IOUtil {
      * @param executable true if the temporary root folder needs to hold executable files, otherwise false.
      * @return
      * @throws IllegalArgumentException
-     * @throws IOException
+     * @throws IOException if no temporary directory could be determined or temp file could not be created
      * @throws SecurityException
      */
     public static File createTempFile(final String prefix, final String suffix, final boolean executable)
@@ -1435,4 +1212,29 @@ public class IOUtil {
             }
         }
     }
+
+    /**
+     * Helper to simplify closing {@link Closeable}s.
+     *
+     * @param stream the {@link Closeable} instance to close
+     * @param saveOneIfFree cache for one {@link IOException} to store, if not already used (excess)
+     * @param dumpExcess dump the excess {@link IOException} on this {@link PrintStream}
+     * @return the excess {@link IOException} or {@code null}.
+     */
+    public static IOException close(final Closeable stream, final IOException[] saveOneIfFree, final PrintStream dumpExcess) {
+        try {
+            stream.close();
+        } catch(final IOException e) {
+            if( null == saveOneIfFree[0] ) {
+                saveOneIfFree[0] = e;
+            } else {
+                if( null != dumpExcess ) {
+                    dumpExcess.println("Caught "+e.getClass().getSimpleName()+": "+e.getMessage());
+                    e.printStackTrace(dumpExcess);
+                }
+                return e;
+            }
+        }
+        return null;
+    }
 }
diff --git a/src/java/com/jogamp/common/util/JarUtil.java b/src/java/com/jogamp/common/util/JarUtil.java
index 3fe03bf..745dd12 100644
--- a/src/java/com/jogamp/common/util/JarUtil.java
+++ b/src/java/com/jogamp/common/util/JarUtil.java
@@ -35,7 +35,6 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.JarURLConnection;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLConnection;
@@ -46,6 +45,7 @@ import java.util.Map;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 
+import com.jogamp.common.net.Uri;
 import com.jogamp.common.os.NativeLibrary;
 import com.jogamp.common.os.Platform;
 
@@ -111,18 +111,18 @@ public class JarUtil {
      * @param clazzBinName "com.jogamp.common.GlueGenVersion"
      * @param cl
      * @return true if the class is loaded from a Jar file, otherwise false.
-     * @see {@link #getJarURI(String, ClassLoader)}
+     * @see {@link #getJarUri(String, ClassLoader)}
      */
-    public static boolean hasJarURI(final String clazzBinName, final ClassLoader cl) {
+    public static boolean hasJarUri(final String clazzBinName, final ClassLoader cl) {
         try {
-            return null != getJarURI(clazzBinName, cl);
+            return null != getJarUri(clazzBinName, cl);
         } catch (final Exception e) { /* ignore */ }
         return false;
     }
 
     /**
      * The Class's <code>"com.jogamp.common.GlueGenVersion"</code>
-     * URI <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class"</code>
+     * Uri <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class"</code>
      * will be returned.
      * <p>
      * <i>sub_protocol</i> may be "file", "http", etc..
@@ -131,108 +131,107 @@ public class JarUtil {
      * @param clazzBinName "com.jogamp.common.GlueGenVersion"
      * @param cl ClassLoader to locate the JarFile
      * @return "jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class"
-     * @throws IllegalArgumentException if the URI doesn't match the expected formatting or null arguments
+     * @throws IllegalArgumentException if the Uri doesn't match the expected formatting or null arguments
      * @throws IOException if the class's Jar file could not been found by the ClassLoader
-     * @throws URISyntaxException if the URI could not be translated into a RFC 2396 URI
+     * @throws URISyntaxException if the Uri could not be translated into a RFC 2396 Uri
      * @see {@link IOUtil#getClassURL(String, ClassLoader)}
      */
-    public static URI getJarURI(final String clazzBinName, final ClassLoader cl) throws IllegalArgumentException, IOException, URISyntaxException {
+    public static Uri getJarUri(final String clazzBinName, final ClassLoader cl) throws IllegalArgumentException, IOException, URISyntaxException {
         if(null == clazzBinName || null == cl) {
             throw new IllegalArgumentException("null arguments: clazzBinName "+clazzBinName+", cl "+cl);
         }
-        final URI uri;
+        final Uri uri;
         final URL url;
         {
             url = IOUtil.getClassURL(clazzBinName, cl);
             final String scheme = url.getProtocol();
             if( null != resolver &&
-                !scheme.equals( IOUtil.JAR_SCHEME ) &&
-                !scheme.equals( IOUtil.FILE_SCHEME ) &&
-                !scheme.equals( IOUtil.HTTP_SCHEME ) &&
-                !scheme.equals( IOUtil.HTTPS_SCHEME ) )
+                !scheme.equals( Uri.JAR_SCHEME ) &&
+                !scheme.equals( Uri.FILE_SCHEME ) &&
+                !scheme.equals( Uri.HTTP_SCHEME ) &&
+                !scheme.equals( Uri.HTTPS_SCHEME ) )
             {
                 final URL _url = resolver.resolve( url );
-                uri = _url.toURI();
+                uri = Uri.valueOf(_url);
                 if(DEBUG) {
-                    System.err.println("getJarURI Resolver: "+url+"\n\t-> "+_url+"\n\t-> "+uri);
+                    System.err.println("getJarUri Resolver: "+url+"\n\t-> "+_url+"\n\t-> "+uri);
                 }
             } else {
-                uri = url.toURI();
+                uri = Uri.valueOf(url);
                 if(DEBUG) {
-                    System.err.println("getJarURI Default "+url+"\n\t-> "+uri);
+                    System.err.println("getJarUri Default "+url+"\n\t-> "+uri);
                 }
             }
         }
-        // test name ..
-        if( !uri.getScheme().equals( IOUtil.JAR_SCHEME ) ) {
-            throw new IllegalArgumentException("URI is not using scheme "+IOUtil.JAR_SCHEME+": <"+uri+">");
+        if( !uri.scheme.equals( Uri.JAR_SCHEME ) ) {
+            throw new IllegalArgumentException("Uri is not using scheme "+Uri.JAR_SCHEME+": <"+uri+">");
         }
         if(DEBUG) {
-            System.err.println("getJarURI res: "+clazzBinName+" -> "+url+" -> "+uri);
+            System.err.println("getJarUri res: "+clazzBinName+" -> "+url+" -> "+uri);
         }
         return uri;
     }
 
 
     /**
-     * The Class's Jar URI <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
+     * The Class's Jar Uri <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
      * Jar basename <code>gluegen-rt.jar</code> will be returned.
      * <p>
      * <i>sub_protocol</i> may be "file", "http", etc..
      * </p>
      *
-     * @param classJarURI as retrieved w/ {@link #getJarURI(String, ClassLoader) getJarURI("com.jogamp.common.GlueGenVersion", cl).toURI()},
+     * @param classJarUri as retrieved w/ {@link #getJarUri(String, ClassLoader) getJarUri("com.jogamp.common.GlueGenVersion", cl)},
      *                    i.e. <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
      * @return <code>gluegen-rt.jar</code>
-     * @throws IllegalArgumentException if the URI doesn't match the expected formatting or is null
+     * @throws IllegalArgumentException if the Uri doesn't match the expected formatting or is null
      * @see {@link IOUtil#getClassURL(String, ClassLoader)}
      */
-    public static String getJarBasename(final URI classJarURI) throws IllegalArgumentException {
-        if(null == classJarURI) {
-            throw new IllegalArgumentException("URI is null");
+    public static Uri.Encoded getJarBasename(final Uri classJarUri) throws IllegalArgumentException {
+        if(null == classJarUri) {
+            throw new IllegalArgumentException("Uri is null");
         }
-        if( !classJarURI.getScheme().equals(IOUtil.JAR_SCHEME) ) {
-            throw new IllegalArgumentException("URI is not using scheme "+IOUtil.JAR_SCHEME+": <"+classJarURI+">");
+        if( !classJarUri.scheme.equals(Uri.JAR_SCHEME) ) {
+            throw new IllegalArgumentException("Uri is not using scheme "+Uri.JAR_SCHEME+": <"+classJarUri+">");
         }
-        String uriS = classJarURI.getSchemeSpecificPart();
+        Uri.Encoded ssp = classJarUri.schemeSpecificPart;
 
         // from
         //   file:/some/path/gluegen-rt.jar!/com/jogamp/common/util/cache/TempJarCache.class
         // to
         //   file:/some/path/gluegen-rt.jar
-        int idx = uriS.lastIndexOf(IOUtil.JAR_SCHEME_SEPARATOR);
+        int idx = ssp.lastIndexOf(Uri.JAR_SCHEME_SEPARATOR);
         if (0 <= idx) {
-            uriS = uriS.substring(0, idx); // exclude '!/'
+            ssp = ssp.substring(0, idx); // exclude '!/'
         } else {
-            throw new IllegalArgumentException("URI does not contain jar uri terminator '!', in <"+classJarURI+">");
+            throw new IllegalArgumentException("Uri does not contain jar uri terminator '!', in <"+classJarUri+">");
         }
 
         // from
         //   file:/some/path/gluegen-rt.jar
         // to
         //   gluegen-rt.jar
-        idx = uriS.lastIndexOf('/');
+        idx = ssp.lastIndexOf('/');
         if(0 > idx) {
             // no abs-path, check for protocol terminator ':'
-            idx = uriS.lastIndexOf(':');
+            idx = ssp.lastIndexOf(':');
             if(0 > idx) {
-                throw new IllegalArgumentException("URI does not contain protocol terminator ':', in <"+classJarURI+">");
+                throw new IllegalArgumentException("Uri does not contain protocol terminator ':', in <"+classJarUri+">");
             }
         }
-        uriS = uriS.substring(idx+1); // just the jar name
+        ssp = ssp.substring(idx+1); // just the jar name
 
-        if(0 >= uriS.lastIndexOf(".jar")) {
-            throw new IllegalArgumentException("No Jar name in <"+classJarURI+">");
+        if(0 >= ssp.lastIndexOf(".jar")) {
+            throw new IllegalArgumentException("No Jar name in <"+classJarUri+">");
         }
         if(DEBUG) {
-            System.err.println("getJarName res: "+uriS);
+            System.err.println("getJarName res: "+ssp);
         }
-        return uriS;
+        return ssp;
     }
 
     /**
      * The Class's <code>com.jogamp.common.GlueGenVersion</code>
-     * URI <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
+     * Uri <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
      * Jar basename <code>gluegen-rt.jar</code> will be returned.
      * <p>
      * <i>sub_protocol</i> may be "file", "http", etc..
@@ -241,119 +240,54 @@ public class JarUtil {
      * @param clazzBinName <code>com.jogamp.common.GlueGenVersion</code>
      * @param cl
      * @return <code>gluegen-rt.jar</code>
-     * @throws IllegalArgumentException if the URI doesn't match the expected formatting
+     * @throws IllegalArgumentException if the Uri doesn't match the expected formatting
      * @throws IOException if the class's Jar file could not been found by the ClassLoader.
-     * @throws URISyntaxException if the URI could not be translated into a RFC 2396 URI
+     * @throws URISyntaxException if the Uri could not be translated into a RFC 2396 Uri
      * @see {@link IOUtil#getClassURL(String, ClassLoader)}
      */
-    public static String getJarBasename(final String clazzBinName, final ClassLoader cl) throws IllegalArgumentException, IOException, URISyntaxException {
-        return getJarBasename( getJarURI(clazzBinName, cl) );
+    public static Uri.Encoded getJarBasename(final String clazzBinName, final ClassLoader cl) throws IllegalArgumentException, IOException, URISyntaxException {
+        return getJarBasename( getJarUri(clazzBinName, cl) );
     }
 
     /**
-     * The Class's Jar URI <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
-     * Jar file's sub URI <code><i>sub_protocol</i>:/some/path/gluegen-rt.jar</code> will be returned.
-     * <p>
-     * <i>sub_protocol</i> may be "file", "http", etc..
-     * </p>
-     *
-     * @param classJarURI as retrieved w/ {@link #getJarURI(String, ClassLoader) getJarURI("com.jogamp.common.GlueGenVersion", cl).toURI()},
-     *                    i.e. <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
-     * @return <code><i>sub_protocol</i>:/some/path/gluegen-rt.jar</code>
-     * @throws IllegalArgumentException if the URI doesn't match the expected formatting or is null
-     * @throws URISyntaxException if the URI could not be translated into a RFC 2396 URI
-     * @see {@link IOUtil#getClassURL(String, ClassLoader)}
-     */
-    public static URI getJarSubURI(final URI classJarURI) throws IllegalArgumentException, URISyntaxException {
-        if(null == classJarURI) {
-            throw new IllegalArgumentException("URI is null");
-        }
-        if( !classJarURI.getScheme().equals(IOUtil.JAR_SCHEME) ) {
-            throw new IllegalArgumentException("URI is not a using scheme "+IOUtil.JAR_SCHEME+": <"+classJarURI+">");
-        }
-
-        // from
-        //   file:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class
-        // to
-        //   file:/some/path/gluegen-rt.jar
-        final String uriSSP = classJarURI.getRawSchemeSpecificPart();
-        final int idx = uriSSP.lastIndexOf(IOUtil.JAR_SCHEME_SEPARATOR);
-        final String uriSSPJar;
-        if (0 <= idx) {
-            uriSSPJar = uriSSP.substring(0, idx); // exclude '!/'
-        } else {
-            throw new IllegalArgumentException("JAR URI does not contain jar uri terminator '!', uri <"+classJarURI+">");
-        }
-        if(0 >= uriSSPJar.lastIndexOf(".jar")) {
-            throw new IllegalArgumentException("No Jar name in <"+classJarURI+">");
-        }
-        if(DEBUG) {
-            System.err.println("getJarSubURI res: "+classJarURI+" -> "+uriSSP+" -> "+uriSSPJar);
-        }
-        return new URI(uriSSPJar);
-    }
-
-    /**
-     * The Class's Jar URI <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
+     * The Class's Jar Uri <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
      * Jar file's entry <code>/com/jogamp/common/GlueGenVersion.class</code> will be returned.
      *
-     * @param classJarURI as retrieved w/ {@link #getJarURI(String, ClassLoader) getJarURI("com.jogamp.common.GlueGenVersion", cl).toURI()},
+     * @param classJarUri as retrieved w/ {@link #getJarUri(String, ClassLoader) getJarUri("com.jogamp.common.GlueGenVersion", cl)},
      *                    i.e. <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
      * @return <code>/com/jogamp/common/GlueGenVersion.class</code>
      * @see {@link IOUtil#getClassURL(String, ClassLoader)}
-     * @deprecated Useless
      */
-    public static String getJarEntry(final URI classJarURI) {
-        if(null == classJarURI) {
-            throw new IllegalArgumentException("URI is null");
+    public static Uri.Encoded getJarEntry(final Uri classJarUri) {
+        if(null == classJarUri) {
+            throw new IllegalArgumentException("Uri is null");
         }
-        if( !classJarURI.getScheme().equals(IOUtil.JAR_SCHEME) ) {
-            throw new IllegalArgumentException("URI is not a using scheme "+IOUtil.JAR_SCHEME+": <"+classJarURI+">");
+        if( !classJarUri.scheme.equals(Uri.JAR_SCHEME) ) {
+            throw new IllegalArgumentException("Uri is not a using scheme "+Uri.JAR_SCHEME+": <"+classJarUri+">");
         }
-        final String uriSSP = classJarURI.getSchemeSpecificPart();
-        // Uri TODO ? final String uriSSP = classJarURI.getRawSchemeSpecificPart();
+        final Uri.Encoded uriSSP = classJarUri.schemeSpecificPart;
 
         // from
         //   file:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class
         // to
         //   /com/jogamp/common/GlueGenVersion.class
-        final int idx = uriSSP.lastIndexOf(IOUtil.JAR_SCHEME_SEPARATOR);
+        final int idx = uriSSP.lastIndexOf(Uri.JAR_SCHEME_SEPARATOR);
         if (0 <= idx) {
-            final String res = uriSSP.substring(idx+1); // right of '!'
+            final Uri.Encoded res = uriSSP.substring(idx+1); // right of '!'
             // Uri TODO ? final String res = Uri.decode(uriSSP.substring(idx+1)); // right of '!'
             if(DEBUG) {
-                System.err.println("getJarEntry res: "+classJarURI+" -> "+uriSSP+" -> "+idx+" -> "+res);
+                System.err.println("getJarEntry res: "+classJarUri+" -> "+uriSSP+" -> "+idx+" -> "+res);
             }
             return res;
         } else {
-            throw new IllegalArgumentException("JAR URI does not contain jar uri terminator '!', uri <"+classJarURI+">");
+            throw new IllegalArgumentException("JAR Uri does not contain jar uri terminator '!', uri <"+classJarUri+">");
         }
     }
 
     /**
-     * The Class's <code>com.jogamp.common.GlueGenVersion</code>
-     * URI <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class</code>
-     * Jar file's sub URI <code><i>sub_protocol</i>:/some/path/gluegen-rt.jar</code> will be returned.
-     * <p>
-     * <i>sub_protocol</i> may be "file", "http", etc..
-     * </p>
-     *
-     * @param clazzBinName <code>com.jogamp.common.GlueGenVersion</code>
-     * @param cl
-     * @return <code><i>sub_protocol</i>:/some/path/gluegen-rt.jar</code>
-     * @throws IllegalArgumentException if the URI doesn't match the expected formatting
-     * @throws IOException if the class's Jar file could not been found by the ClassLoader
-     * @throws URISyntaxException if the URI could not be translated into a RFC 2396 URI
-     * @see {@link IOUtil#getClassURL(String, ClassLoader)}
-     */
-    public static URI getJarSubURI(final String clazzBinName, final ClassLoader cl) throws IllegalArgumentException, IOException, URISyntaxException {
-        return getJarSubURI( getJarURI(clazzBinName, cl) );
-    }
-
-    /**
      * The Class's <code>"com.jogamp.common.GlueGenVersion"</code>
-     * URI <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class"</code>
-     * Jar file URI <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/</code> will be returned.
+     * Uri <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class"</code>
+     * Jar file Uri <code>jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/</code> will be returned.
      * <p>
      * <i>sub_protocol</i> may be "file", "http", etc..
      * </p>
@@ -361,34 +295,35 @@ public class JarUtil {
      * @param clazzBinName "com.jogamp.common.GlueGenVersion"
      * @param cl
      * @return "jar:<i>sub_protocol</i>:/some/path/gluegen-rt.jar!/"
-     * @throws IllegalArgumentException if the URI doesn't match the expected formatting or null arguments
+     * @throws IllegalArgumentException if the Uri doesn't match the expected formatting or null arguments
      * @throws IOException if the class's Jar file could not been found by the ClassLoader
-     * @throws URISyntaxException if the URI could not be translated into a RFC 2396 URI
+     * @throws URISyntaxException if the Uri could not be translated into a RFC 2396 Uri
      * @see {@link IOUtil#getClassURL(String, ClassLoader)}
      */
-    public static URI getJarFileURI(final String clazzBinName, final ClassLoader cl) throws IllegalArgumentException, IOException, URISyntaxException {
+    public static Uri getJarFileUri(final String clazzBinName, final ClassLoader cl) throws IllegalArgumentException, IOException, URISyntaxException {
         if(null == clazzBinName || null == cl) {
             throw new IllegalArgumentException("null arguments: clazzBinName "+clazzBinName+", cl "+cl);
         }
-        final URI uri = new URI(IOUtil.JAR_SCHEME+IOUtil.SCHEME_SEPARATOR+getJarSubURI(clazzBinName, cl).toString()+"!/");
+        final Uri jarSubUri = getJarUri(clazzBinName, cl).getContainedUri();
+        final Uri uri = Uri.cast(Uri.JAR_SCHEME+Uri.SCHEME_SEPARATOR+jarSubUri.toString()+"!/");
         if(DEBUG) {
-            System.err.println("getJarFileURI res: "+uri);
+            System.err.println("getJarFileUri res: "+uri);
         }
         return uri;
     }
 
     /**
      * @param baseUri file:/some/path/
-     * @param jarFileName gluegen-rt.jar (URI encoded)
+     * @param jarFileName gluegen-rt.jar (Uri encoded)
      * @return jar:file:/some/path/gluegen-rt.jar!/
      * @throws URISyntaxException
      * @throws IllegalArgumentException null arguments
      */
-    public static URI getJarFileURI(final URI baseUri, final String jarFileName) throws IllegalArgumentException, URISyntaxException {
+    public static Uri getJarFileUri(final Uri baseUri, final Uri.Encoded jarFileName) throws IllegalArgumentException, URISyntaxException {
         if(null == baseUri || null == jarFileName) {
-            throw new IllegalArgumentException("null arguments: baseURI "+baseUri+", jarFileName "+jarFileName);
+            throw new IllegalArgumentException("null arguments: baseUri "+baseUri+", jarFileName "+jarFileName);
         }
-        return new URI(IOUtil.JAR_SCHEME+IOUtil.SCHEME_SEPARATOR+baseUri.toString()+jarFileName+"!/");
+        return Uri.cast(Uri.JAR_SCHEME+Uri.SCHEME_SEPARATOR+baseUri.toString()+jarFileName+"!/");
     }
 
     /**
@@ -397,38 +332,38 @@ public class JarUtil {
      * @throws IllegalArgumentException null arguments
      * @throws URISyntaxException
      */
-    public static URI getJarFileURI(final URI jarSubUri) throws IllegalArgumentException, URISyntaxException {
+    public static Uri getJarFileUri(final Uri jarSubUri) throws IllegalArgumentException, URISyntaxException {
         if(null == jarSubUri) {
-            throw new IllegalArgumentException("jarSubURI is null");
+            throw new IllegalArgumentException("jarSubUri is null");
         }
-        return new URI(IOUtil.JAR_SCHEME+IOUtil.SCHEME_SEPARATOR+jarSubUri.toString()+"!/");
+        return Uri.cast(Uri.JAR_SCHEME+Uri.SCHEME_SEPARATOR+jarSubUri.toString()+"!/");
     }
 
     /**
-     * @param jarSubUriS file:/some/path/gluegen-rt.jar (URI encoded)
+     * @param jarSubUriS file:/some/path/gluegen-rt.jar (Uri encoded)
      * @return jar:file:/some/path/gluegen-rt.jar!/
      * @throws IllegalArgumentException null arguments
      * @throws URISyntaxException
      */
-    public static URI getJarFileURI(final String jarSubUriS) throws IllegalArgumentException, URISyntaxException {
+    public static Uri getJarFileUri(final Uri.Encoded jarSubUriS) throws IllegalArgumentException, URISyntaxException {
         if(null == jarSubUriS) {
-            throw new IllegalArgumentException("jarSubURIS is null");
+            throw new IllegalArgumentException("jarSubUriS is null");
         }
-        return new URI(IOUtil.JAR_SCHEME+IOUtil.SCHEME_SEPARATOR+jarSubUriS+"!/");
+        return Uri.cast(Uri.JAR_SCHEME+Uri.SCHEME_SEPARATOR+jarSubUriS+"!/");
     }
 
     /**
-     * @param jarFileURI jar:file:/some/path/gluegen-rt.jar!/
+     * @param jarFileUri jar:file:/some/path/gluegen-rt.jar!/
      * @param jarEntry com/jogamp/common/GlueGenVersion.class
      * @return jar:file:/some/path/gluegen-rt.jar!/com/jogamp/common/GlueGenVersion.class
      * @throws IllegalArgumentException null arguments
      * @throws URISyntaxException
      */
-    public static URI getJarEntryURI(final URI jarFileURI, final String jarEntry) throws IllegalArgumentException, URISyntaxException {
+    public static Uri getJarEntryUri(final Uri jarFileUri, final Uri.Encoded jarEntry) throws IllegalArgumentException, URISyntaxException {
         if(null == jarEntry) {
             throw new IllegalArgumentException("jarEntry is null");
         }
-        return new URI(jarFileURI.toString()+jarEntry);
+        return Uri.cast(jarFileUri.toString()+jarEntry);
     }
 
     /**
@@ -437,28 +372,28 @@ public class JarUtil {
      * @return JarFile containing the named class within the given ClassLoader
      * @throws IOException if the class's Jar file could not been found by the ClassLoader
      * @throws IllegalArgumentException null arguments
-     * @throws URISyntaxException if the URI could not be translated into a RFC 2396 URI
-     * @see {@link #getJarFileURI(String, ClassLoader)}
+     * @throws URISyntaxException if the Uri could not be translated into a RFC 2396 Uri
+     * @see {@link #getJarFileUri(String, ClassLoader)}
      */
     public static JarFile getJarFile(final String clazzBinName, final ClassLoader cl) throws IOException, IllegalArgumentException, URISyntaxException {
-        return getJarFile( getJarFileURI(clazzBinName, cl) );
+        return getJarFile( getJarFileUri(clazzBinName, cl) );
     }
 
     /**
-     * @param jarFileURI jar:file:/some/path/gluegen-rt.jar!/
-     * @return JarFile as named by URI within the given ClassLoader
+     * @param jarFileUri jar:file:/some/path/gluegen-rt.jar!/
+     * @return JarFile as named by Uri within the given ClassLoader
      * @throws IllegalArgumentException null arguments
      * @throws IOException if the Jar file could not been found
      * @throws URISyntaxException
      */
-    public static JarFile getJarFile(final URI jarFileURI) throws IOException, IllegalArgumentException, URISyntaxException {
-        if(null == jarFileURI) {
-            throw new IllegalArgumentException("null jarFileURI");
+    public static JarFile getJarFile(final Uri jarFileUri) throws IOException, IllegalArgumentException, URISyntaxException {
+        if(null == jarFileUri) {
+            throw new IllegalArgumentException("null jarFileUri");
         }
         if(DEBUG) {
-            System.err.println("getJarFile.0: "+jarFileURI.toString());
+            System.err.println("getJarFile.0: "+jarFileUri.toString());
         }
-        final URL jarFileURL = jarFileURI.toURL();
+        final URL jarFileURL = jarFileUri.toURL();
         if(DEBUG) {
             System.err.println("getJarFile.1: "+jarFileURL.toString());
         }
@@ -478,8 +413,22 @@ public class JarUtil {
     }
 
     /**
-     * Locates the {@link JarUtil#getJarFileURI(URI) Jar file URI} of a given resource
-     * relative to a given class's Jar's URI.
+     * See {@link #getRelativeOf(Class, com.jogamp.common.net.Uri.Encoded, com.jogamp.common.net.Uri.Encoded)}.
+     * @param classFromJavaJar URI encoded!
+     * @param cutOffInclSubDir URI encoded!
+     * @param relResPath URI encoded!
+     * @return
+     * @throws IllegalArgumentException
+     * @throws IOException
+     * @throws URISyntaxException
+     * @deprecated Use {@link #getRelativeOf(Class, com.jogamp.common.net.Uri.Encoded, com.jogamp.common.net.Uri.Encoded)}.
+     */
+    public static java.net.URI getRelativeOf(final Class<?> classFromJavaJar, final String cutOffInclSubDir, final String relResPath) throws IllegalArgumentException, IOException, URISyntaxException {
+        return getRelativeOf(classFromJavaJar, Uri.Encoded.cast(cutOffInclSubDir), Uri.Encoded.cast(relResPath)).toURI();
+    }
+    /**
+     * Locates the {@link JarUtil#getJarFileUri(Uri) Jar file Uri} of a given resource
+     * relative to a given class's Jar's Uri.
      * <pre>
      *   class's jar url path + cutOffInclSubDir + relResPath,
      * </pre>
@@ -500,47 +449,47 @@ public class JarUtil {
      *
      * TODO: Enhance documentation!
      *
-     * @param classFromJavaJar Used to get the root URI for the class's Jar URI.
+     * @param classFromJavaJar Used to get the root Uri for the class's Jar Uri.
      * @param cutOffInclSubDir The <i>cut off</i> included sub-directory prepending the relative resource path.
-     *                         If the root URI includes cutOffInclSubDir, it is no more added to the result.
-     * @param relResPath The relative resource path. (URI encoded)
-     * @return The resulting resource URI, which is not tested.
+     *                         If the root Uri includes cutOffInclSubDir, it is no more added to the result.
+     * @param relResPath The relative resource path. (Uri encoded)
+     * @return The resulting resource Uri, which is not tested.
      * @throws IllegalArgumentException
      * @throws IOException
      * @throws URISyntaxException
      */
-    public static URI getRelativeOf(final Class<?> classFromJavaJar, final String cutOffInclSubDir, final String relResPath) throws IllegalArgumentException, IOException, URISyntaxException {
+    public static Uri getRelativeOf(final Class<?> classFromJavaJar, final Uri.Encoded cutOffInclSubDir, final Uri.Encoded relResPath) throws IllegalArgumentException, IOException, URISyntaxException {
         final ClassLoader cl = classFromJavaJar.getClassLoader();
-        final URI classJarURI = JarUtil.getJarURI(classFromJavaJar.getName(), cl);
+        final Uri classJarUri = JarUtil.getJarUri(classFromJavaJar.getName(), cl);
         if( DEBUG ) {
-            System.err.println("JarUtil.getRelativeOf: "+"(classFromJavaJar "+classFromJavaJar+", classJarURI "+classJarURI+
+            System.err.println("JarUtil.getRelativeOf: "+"(classFromJavaJar "+classFromJavaJar+", classJarUri "+classJarUri+
                     ", cutOffInclSubDir "+cutOffInclSubDir+", relResPath "+relResPath+"): ");
         }
 
-        final URI jarSubURI = JarUtil.getJarSubURI( classJarURI );
-        if(null == jarSubURI) {
-            throw new IllegalArgumentException("JarSubURI is null of: "+classJarURI);
+        final Uri jarSubUri = classJarUri.getContainedUri();
+        if(null == jarSubUri) {
+            throw new IllegalArgumentException("JarSubUri is null of: "+classJarUri);
         }
-        final String jarUriRoot_s = IOUtil.getURIDirname( jarSubURI.toString() );
+        final Uri.Encoded jarUriRoot = jarSubUri.getDirectory().getEncoded();
         if( DEBUG ) {
-            System.err.println("JarUtil.getRelativeOf: "+"uri "+jarSubURI.toString()+" -> "+jarUriRoot_s);
+            System.err.println("JarUtil.getRelativeOf: "+"uri "+jarSubUri.toString()+" -> "+jarUriRoot);
         }
 
-        final String resUri_s;
-        if( jarUriRoot_s.endsWith(cutOffInclSubDir) ) {
-            resUri_s = jarUriRoot_s+relResPath;
+        final Uri.Encoded resUri;
+        if( jarUriRoot.endsWith(cutOffInclSubDir.get()) ) {
+            resUri = jarUriRoot.concat(relResPath);
         } else {
-            resUri_s = jarUriRoot_s+cutOffInclSubDir+relResPath;
+            resUri = jarUriRoot.concat(cutOffInclSubDir).concat(relResPath);
         }
         if( DEBUG ) {
-            System.err.println("JarUtil.getRelativeOf: "+"...  -> "+resUri_s);
+            System.err.println("JarUtil.getRelativeOf: "+"...  -> "+resUri);
         }
 
-        final URI resURI = JarUtil.getJarFileURI(resUri_s);
+        final Uri resJarUri = JarUtil.getJarFileUri(resUri);
         if( DEBUG ) {
-            System.err.println("JarUtil.getRelativeOf: "+"fin "+resURI);
+            System.err.println("JarUtil.getRelativeOf: "+"fin "+resJarUri);
         }
-        return resURI;
+        return resJarUri;
     }
 
     /**
diff --git a/src/java/com/jogamp/common/util/ReflectionUtil.java b/src/java/com/jogamp/common/util/ReflectionUtil.java
index 9e716b8..7e8ae63 100644
--- a/src/java/com/jogamp/common/util/ReflectionUtil.java
+++ b/src/java/com/jogamp/common/util/ReflectionUtil.java
@@ -48,6 +48,7 @@ import java.util.Set;
 
 import jogamp.common.Debug;
 
+import com.jogamp.common.ExceptionUtils;
 import com.jogamp.common.JogampRuntimeException;
 
 public final class ReflectionUtil {
@@ -140,7 +141,7 @@ public final class ReflectionUtil {
                 System.err.printf("ReflectionUtil.getClassImpl.%03d: %8.3f ms, init %b, [%s]@ Thread %s%n",
                         forNameCount, nanoCosts/1e6, initializeClazz, cnl.toString(), Thread.currentThread().getName());
                 if(DEBUG) {
-                    Thread.dumpStack();
+                    ExceptionUtils.dumpStack(System.err);
                 }
             }
             return res;
diff --git a/src/java/com/jogamp/common/util/VersionUtil.java b/src/java/com/jogamp/common/util/VersionUtil.java
index 6949d62..6fec8fa 100644
--- a/src/java/com/jogamp/common/util/VersionUtil.java
+++ b/src/java/com/jogamp/common/util/VersionUtil.java
@@ -58,23 +58,23 @@ public class VersionUtil {
 
         // environment
         sb.append("Platform: ").append(Platform.getOSType()).append(" / ").append(Platform.getOSName()).append(' ').append(Platform.getOSVersion()).append(" (").append(Platform.getOSVersionNumber()).append("), ");
-        sb.append(Platform.getArchName()).append(" (arch), ").append(Platform.getABIType()).append(", ");
-        sb.append(Runtime.getRuntime().availableProcessors()).append(" cores");
+        sb.append(Platform.getArchName()).append(" (").append(Platform.getCPUType()).append(", ").append(Platform.getABIType()).append("), ");
+        sb.append(Runtime.getRuntime().availableProcessors()).append(" cores, ").append("littleEndian ").append(PlatformPropsImpl.LITTLE_ENDIAN);
         sb.append(Platform.getNewline());
-        if( AndroidVersion.isAvailable) {
+        if( Platform.OSType.ANDROID == PlatformPropsImpl.OS_TYPE ) {
             sb.append("Platform: Android Version: ").append(AndroidVersion.CODENAME).append(", ");
             sb.append(AndroidVersion.RELEASE).append(" [").append(AndroidVersion.RELEASE).append("], SDK: ").append(AndroidVersion.SDK_INT).append(", ").append(AndroidVersion.SDK_NAME);
             sb.append(Platform.getNewline());
         }
 
-        Platform.getMachineDescription().toString(sb).append(Platform.getNewline());
+        Platform.getMachineDataInfo().toString(sb).append(Platform.getNewline());
 
         // JVM/JRE
         sb.append("Platform: Java Version: ").append(Platform.getJavaVersion()).append(" (").append(Platform.getJavaVersionNumber()).append("u").append(PlatformPropsImpl.JAVA_VERSION_UPDATE).append("), VM: ").append(Platform.getJavaVMName());
         sb.append(", Runtime: ").append(Platform.getJavaRuntimeName()).append(Platform.getNewline());
         sb.append("Platform: Java Vendor: ").append(Platform.getJavaVendor()).append(", ").append(Platform.getJavaVendorURL());
-        sb.append(", JavaSE: ").append(Platform.isJavaSE());
-        sb.append(", Java6: ").append(Platform.isJava6());
+        sb.append(", JavaSE: ").append(PlatformPropsImpl.JAVA_SE);
+        sb.append(", Java6: ").append(PlatformPropsImpl.JAVA_6);
         sb.append(", AWT enabled: ").append(Platform.AWT_AVAILABLE);
         sb.append(Platform.getNewline()).append(SEPERATOR);
 
diff --git a/src/java/com/jogamp/common/util/bin/exe-windows-i586-268b.bin b/src/java/com/jogamp/common/util/bin/exe-windows-i586-268b.bin
new file mode 100644
index 0000000..b0d5f63
Binary files /dev/null and b/src/java/com/jogamp/common/util/bin/exe-windows-i586-268b.bin differ
diff --git a/src/java/com/jogamp/common/util/cache/TempFileCache.java b/src/java/com/jogamp/common/util/cache/TempFileCache.java
index b58ea28..24f0237 100644
--- a/src/java/com/jogamp/common/util/cache/TempFileCache.java
+++ b/src/java/com/jogamp/common/util/cache/TempFileCache.java
@@ -87,8 +87,11 @@ public class TempFileCache {
             tmpBaseDir = _tmpBaseDir;
 
             if (DEBUG) {
+                final String tmpBaseDirAbsPath = null != tmpBaseDir ? tmpBaseDir.getAbsolutePath() : null;
                 System.err.println("TempFileCache: Static Initialization ---------------------------------------------- OK: "+(!staticInitError));
-                System.err.println("TempFileCache: Thread: "+Thread.currentThread().getName()+", CL 0x"+Integer.toHexString(TempFileCache.class.getClassLoader().hashCode())+", tempBaseDir "+tmpBaseDir.getAbsolutePath());
+                System.err.println("TempFileCache: Thread: "+Thread.currentThread().getName()+
+                        ", CL 0x"+Integer.toHexString(TempFileCache.class.getClassLoader().hashCode())+
+                        ", tempBaseDir "+tmpBaseDirAbsPath);
             }
 
             if(!staticInitError) {
diff --git a/src/java/com/jogamp/common/util/cache/TempJarCache.java b/src/java/com/jogamp/common/util/cache/TempJarCache.java
index 1b322d7..ed69ddc 100644
--- a/src/java/com/jogamp/common/util/cache/TempJarCache.java
+++ b/src/java/com/jogamp/common/util/cache/TempJarCache.java
@@ -29,7 +29,6 @@ package com.jogamp.common.util.cache;
 
 import java.io.File;
 import java.io.IOException;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.security.cert.Certificate;
 import java.util.HashMap;
@@ -38,8 +37,8 @@ import java.util.jar.JarFile;
 
 import jogamp.common.Debug;
 
+import com.jogamp.common.net.Uri;
 import com.jogamp.common.os.NativeLibrary;
-import com.jogamp.common.util.IOUtil;
 import com.jogamp.common.util.JarUtil;
 import com.jogamp.common.util.SecurityUtil;
 
@@ -68,9 +67,9 @@ public class TempJarCache {
     }
 
     // Set of jar files added
-    private static Map<URI, LoadState> nativeLibJars;
-    private static Map<URI, LoadState> classFileJars;
-    private static Map<URI, LoadState> resourceFileJars;
+    private static Map<Uri, LoadState> nativeLibJars;
+    private static Map<Uri, LoadState> classFileJars;
+    private static Map<Uri, LoadState> resourceFileJars;
 
     private static TempFileCache tmpFileCache;
 
@@ -96,12 +95,14 @@ public class TempJarCache {
                     if(!staticInitError) {
                         // Initialize the collections of resources
                         nativeLibMap = new HashMap<String, String>();
-                        nativeLibJars = new HashMap<URI, LoadState>();
-                        classFileJars = new HashMap<URI, LoadState>();
-                        resourceFileJars = new HashMap<URI, LoadState>();
+                        nativeLibJars = new HashMap<Uri, LoadState>();
+                        classFileJars = new HashMap<Uri, LoadState>();
+                        resourceFileJars = new HashMap<Uri, LoadState>();
                     }
                     if(DEBUG) {
-                        System.err.println("TempJarCache.initSingleton(): ok "+(false==staticInitError)+", "+ tmpFileCache.getTempDir());
+                        final File tempDir = null != tmpFileCache ? tmpFileCache.getTempDir() : null;
+                        final String tempDirAbsPath = null != tempDir ? tempDir.getAbsolutePath() : null;
+                        System.err.println("TempJarCache.initSingleton(): ok "+(false==staticInitError)+", "+ tempDirAbsPath);
                     }
                     isInit = true;
                 }
@@ -182,62 +183,62 @@ public class TempJarCache {
         return tmpFileCache;
     }
 
-    public synchronized static boolean checkNativeLibs(final URI jarURI, final LoadState exp) throws IOException {
+    public synchronized static boolean checkNativeLibs(final Uri jarUri, final LoadState exp) throws IOException {
         checkInitialized();
-        if(null == jarURI) {
-            throw new IllegalArgumentException("jarURI is null");
+        if(null == jarUri) {
+            throw new IllegalArgumentException("jarUri is null");
         }
-        return testLoadState(nativeLibJars.get(jarURI), exp);
+        return testLoadState(nativeLibJars.get(jarUri), exp);
     }
 
-    public synchronized static boolean checkClasses(final URI jarURI, final LoadState exp) throws IOException {
+    public synchronized static boolean checkClasses(final Uri jarUri, final LoadState exp) throws IOException {
         checkInitialized();
-        if(null == jarURI) {
-            throw new IllegalArgumentException("jarURI is null");
+        if(null == jarUri) {
+            throw new IllegalArgumentException("jarUri is null");
         }
-        return testLoadState(classFileJars.get(jarURI), exp);
+        return testLoadState(classFileJars.get(jarUri), exp);
     }
 
-    public synchronized static boolean checkResources(final URI jarURI, final LoadState exp) throws IOException {
+    public synchronized static boolean checkResources(final Uri jarUri, final LoadState exp) throws IOException {
         checkInitialized();
-        if(null == jarURI) {
-            throw new IllegalArgumentException("jarURI is null");
+        if(null == jarUri) {
+            throw new IllegalArgumentException("jarUri is null");
         }
-        return testLoadState(resourceFileJars.get(jarURI), exp);
+        return testLoadState(resourceFileJars.get(jarUri), exp);
     }
 
     /**
      * Adds native libraries, if not yet added.
      *
      * @param certClass if class is certified, the JarFile entries needs to have the same certificate
-     * @param jarURI
+     * @param jarUri
      * @param nativeLibraryPath if not null, only extracts native libraries within this path.
-     * @return true if native libraries were added or previously loaded from given jarURI, otherwise false
-     * @throws IOException if the <code>jarURI</code> could not be loaded or a previous load attempt failed
+     * @return true if native libraries were added or previously loaded from given jarUri, otherwise false
+     * @throws IOException if the <code>jarUri</code> could not be loaded or a previous load attempt failed
      * @throws SecurityException
      * @throws URISyntaxException
      * @throws IllegalArgumentException
      */
-    public synchronized static final boolean addNativeLibs(final Class<?> certClass, final URI jarURI, final String nativeLibraryPath) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException {
+    public synchronized static final boolean addNativeLibs(final Class<?> certClass, final Uri jarUri, final String nativeLibraryPath) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException {
         checkInitialized();
-        final LoadState nativeLibJarsLS = nativeLibJars.get(jarURI);
+        final LoadState nativeLibJarsLS = nativeLibJars.get(jarUri);
         if( !testLoadState(nativeLibJarsLS, LoadState.LOOKED_UP) ) {
-            nativeLibJars.put(jarURI, LoadState.LOOKED_UP);
-            final JarFile jarFile = JarUtil.getJarFile(jarURI);
+            nativeLibJars.put(jarUri, LoadState.LOOKED_UP);
+            final JarFile jarFile = JarUtil.getJarFile(jarUri);
             if(DEBUG) {
-                System.err.println("TempJarCache: addNativeLibs: "+jarURI+": nativeJar "+jarFile.getName()+" (NEW)");
+                System.err.println("TempJarCache: addNativeLibs: "+jarUri+": nativeJar "+jarFile.getName()+" (NEW)");
             }
             validateCertificates(certClass, jarFile);
             final int num = JarUtil.extract(tmpFileCache.getTempDir(), nativeLibMap, jarFile, nativeLibraryPath, true, false, false);
-            nativeLibJars.put(jarURI, LoadState.LOADED);
+            nativeLibJars.put(jarUri, LoadState.LOADED);
             return num > 0;
         } else if( testLoadState(nativeLibJarsLS, LoadState.LOADED) ) {
             if(DEBUG) {
-                System.err.println("TempJarCache: addNativeLibs: "+jarURI+": nativeJar "+jarURI+" (REUSE)");
+                System.err.println("TempJarCache: addNativeLibs: "+jarUri+": nativeJar "+jarUri+" (REUSE)");
             }
             return true;
         }
-        throw new IOException("TempJarCache: addNativeLibs: "+jarURI+", previous load attempt failed");
+        throw new IOException("TempJarCache: addNativeLibs: "+jarUri+", previous load attempt failed");
     }
 
     /**
@@ -247,56 +248,69 @@ public class TempJarCache {
      * needs Classloader.defineClass(..) access, ie. own derivation - will do when needed ..
      *
      * @param certClass if class is certified, the JarFile entries needs to have the same certificate
-     * @param jarURI
-     * @throws IOException if the <code>jarURI</code> could not be loaded or a previous load attempt failed
+     * @param jarUri
+     * @throws IOException if the <code>jarUri</code> could not be loaded or a previous load attempt failed
      * @throws SecurityException
      * @throws URISyntaxException
      * @throws IllegalArgumentException
      */
-    public synchronized static final void addClasses(final Class<?> certClass, final URI jarURI) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException {
+    public synchronized static final void addClasses(final Class<?> certClass, final Uri jarUri) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException {
         checkInitialized();
-        final LoadState classFileJarsLS = classFileJars.get(jarURI);
+        final LoadState classFileJarsLS = classFileJars.get(jarUri);
         if( !testLoadState(classFileJarsLS, LoadState.LOOKED_UP) ) {
-            classFileJars.put(jarURI, LoadState.LOOKED_UP);
-            final JarFile jarFile = JarUtil.getJarFile(jarURI);
+            classFileJars.put(jarUri, LoadState.LOOKED_UP);
+            final JarFile jarFile = JarUtil.getJarFile(jarUri);
             if(DEBUG) {
-                System.err.println("TempJarCache: addClasses: "+jarURI+": nativeJar "+jarFile.getName());
+                System.err.println("TempJarCache: addClasses: "+jarUri+": nativeJar "+jarFile.getName());
             }
             validateCertificates(certClass, jarFile);
             JarUtil.extract(tmpFileCache.getTempDir(), null, jarFile,
                             null /* nativeLibraryPath */, false, true, false);
-            classFileJars.put(jarURI, LoadState.LOADED);
+            classFileJars.put(jarUri, LoadState.LOADED);
         } else if( !testLoadState(classFileJarsLS, LoadState.LOADED) ) {
-            throw new IOException("TempJarCache: addClasses: "+jarURI+", previous load attempt failed");
+            throw new IOException("TempJarCache: addClasses: "+jarUri+", previous load attempt failed");
         }
     }
 
     /**
+     * See {@link #addResources(Class, Uri)}
+     * @param certClass
+     * @param jarURI
+     * @throws IOException
+     * @throws SecurityException
+     * @throws IllegalArgumentException
+     * @throws URISyntaxException
+     * @deprecated Use {@link #addResources(Class, Uri)}
+     */
+    public synchronized static final void addResources(final Class<?> certClass, final java.net.URI jarURI) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException {
+        addResources(certClass, Uri.valueOf(jarURI));
+    }
+    /**
      * Adds native resources, if not yet added.
      *
      * @param certClass if class is certified, the JarFile entries needs to have the same certificate
-     * @param jarURI
+     * @param jarUri
      * @return
-     * @throws IOException if the <code>jarURI</code> could not be loaded or a previous load attempt failed
+     * @throws IOException if the <code>jarUri</code> could not be loaded or a previous load attempt failed
      * @throws SecurityException
      * @throws URISyntaxException
      * @throws IllegalArgumentException
      */
-    public synchronized static final void addResources(final Class<?> certClass, final URI jarURI) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException {
+    public synchronized static final void addResources(final Class<?> certClass, final Uri jarUri) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException {
         checkInitialized();
-        final LoadState resourceFileJarsLS = resourceFileJars.get(jarURI);
+        final LoadState resourceFileJarsLS = resourceFileJars.get(jarUri);
         if( !testLoadState(resourceFileJarsLS, LoadState.LOOKED_UP) ) {
-            resourceFileJars.put(jarURI, LoadState.LOOKED_UP);
-            final JarFile jarFile = JarUtil.getJarFile(jarURI);
+            resourceFileJars.put(jarUri, LoadState.LOOKED_UP);
+            final JarFile jarFile = JarUtil.getJarFile(jarUri);
             if(DEBUG) {
-                System.err.println("TempJarCache: addResources: "+jarURI+": nativeJar "+jarFile.getName());
+                System.err.println("TempJarCache: addResources: "+jarUri+": nativeJar "+jarFile.getName());
             }
             validateCertificates(certClass, jarFile);
             JarUtil.extract(tmpFileCache.getTempDir(), null, jarFile,
                             null /* nativeLibraryPath */, false, false, true);
-            resourceFileJars.put(jarURI, LoadState.LOADED);
+            resourceFileJars.put(jarUri, LoadState.LOADED);
         } else if( !testLoadState(resourceFileJarsLS, LoadState.LOADED) ) {
-            throw new IOException("TempJarCache: addResources: "+jarURI+", previous load attempt failed");
+            throw new IOException("TempJarCache: addResources: "+jarUri+", previous load attempt failed");
         }
     }
 
@@ -308,20 +322,20 @@ public class TempJarCache {
      * needs Classloader.defineClass(..) access, ie. own derivation - will do when needed ..
      *
      * @param certClass if class is certified, the JarFile entries needs to have the same certificate
-     * @param jarURI
-     * @throws IOException if the <code>jarURI</code> could not be loaded or a previous load attempt failed
+     * @param jarUri
+     * @throws IOException if the <code>jarUri</code> could not be loaded or a previous load attempt failed
      * @throws SecurityException
      * @throws URISyntaxException
      * @throws IllegalArgumentException
      */
-    public synchronized static final void addAll(final Class<?> certClass, final URI jarURI) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException {
+    public synchronized static final void addAll(final Class<?> certClass, final Uri jarUri) throws IOException, SecurityException, IllegalArgumentException, URISyntaxException {
         checkInitialized();
-        if(null == jarURI) {
-            throw new IllegalArgumentException("jarURI is null");
+        if(null == jarUri) {
+            throw new IllegalArgumentException("jarUri is null");
         }
-        final LoadState nativeLibJarsLS = nativeLibJars.get(jarURI);
-        final LoadState classFileJarsLS = classFileJars.get(jarURI);
-        final LoadState resourceFileJarsLS = resourceFileJars.get(jarURI);
+        final LoadState nativeLibJarsLS = nativeLibJars.get(jarUri);
+        final LoadState classFileJarsLS = classFileJars.get(jarUri);
+        final LoadState resourceFileJarsLS = resourceFileJars.get(jarUri);
         if( !testLoadState(nativeLibJarsLS, LoadState.LOOKED_UP) ||
             !testLoadState(classFileJarsLS, LoadState.LOOKED_UP) ||
             !testLoadState(resourceFileJarsLS, LoadState.LOOKED_UP) ) {
@@ -332,18 +346,18 @@ public class TempJarCache {
 
             // mark looked-up (those who are not loaded)
             if(extractNativeLibraries) {
-                nativeLibJars.put(jarURI, LoadState.LOOKED_UP);
+                nativeLibJars.put(jarUri, LoadState.LOOKED_UP);
             }
             if(extractClassFiles) {
-                classFileJars.put(jarURI, LoadState.LOOKED_UP);
+                classFileJars.put(jarUri, LoadState.LOOKED_UP);
             }
             if(extractOtherFiles) {
-                resourceFileJars.put(jarURI, LoadState.LOOKED_UP);
+                resourceFileJars.put(jarUri, LoadState.LOOKED_UP);
             }
 
-            final JarFile jarFile = JarUtil.getJarFile(jarURI);
+            final JarFile jarFile = JarUtil.getJarFile(jarUri);
             if(DEBUG) {
-                System.err.println("TempJarCache: addAll: "+jarURI+": nativeJar "+jarFile.getName());
+                System.err.println("TempJarCache: addAll: "+jarUri+": nativeJar "+jarFile.getName());
             }
             validateCertificates(certClass, jarFile);
             JarUtil.extract(tmpFileCache.getTempDir(), nativeLibMap, jarFile,
@@ -351,18 +365,18 @@ public class TempJarCache {
 
             // mark loaded (those were just loaded)
             if(extractNativeLibraries) {
-                nativeLibJars.put(jarURI, LoadState.LOADED);
+                nativeLibJars.put(jarUri, LoadState.LOADED);
             }
             if(extractClassFiles) {
-                classFileJars.put(jarURI, LoadState.LOADED);
+                classFileJars.put(jarUri, LoadState.LOADED);
             }
             if(extractOtherFiles) {
-                resourceFileJars.put(jarURI, LoadState.LOADED);
+                resourceFileJars.put(jarUri, LoadState.LOADED);
             }
         } else if( !testLoadState(nativeLibJarsLS, LoadState.LOADED) ||
                    !testLoadState(classFileJarsLS, LoadState.LOADED) ||
                    !testLoadState(resourceFileJarsLS, LoadState.LOADED) ) {
-            throw new IOException("TempJarCache: addAll: "+jarURI+", previous load attempt failed");
+            throw new IOException("TempJarCache: addAll: "+jarUri+", previous load attempt failed");
         }
     }
 
@@ -407,12 +421,20 @@ public class TempJarCache {
         return null;
     }
 
+    /**
+     * See {@link #getResourceUri(String)}
+     * @deprecated Use {@link #getResourceUri(String)}
+     */
+    public synchronized static final java.net.URI getResource(final String name) throws URISyntaxException {
+        return getResourceUri(name).toURI();
+    }
+
     /** Similar to {@link ClassLoader#getResource(String)}. */
-    public synchronized static final URI getResource(final String name) throws URISyntaxException {
+    public synchronized static final Uri getResourceUri(final String name) throws URISyntaxException {
         checkInitialized();
         final File f = new File(tmpFileCache.getTempDir(), name);
         if(f.exists()) {
-            return IOUtil.toURISimple(f);
+            return Uri.valueOf(f);
         }
         return null;
     }
diff --git a/src/java/com/jogamp/gluegen/ASTLocusTag.java b/src/java/com/jogamp/gluegen/ASTLocusTag.java
new file mode 100644
index 0000000..aea7699
--- /dev/null
+++ b/src/java/com/jogamp/gluegen/ASTLocusTag.java
@@ -0,0 +1,99 @@
+/**
+ * Copyright 2015 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.gluegen;
+
+/**
+ * An AST location tag.
+ */
+public class ASTLocusTag {
+    /** Source object, might be {@link String}. */
+    public final Object source;
+    /** Line number, {@code -1} if undefined */
+    public final int line;
+    /** Column number, {@code -1} if undefined */
+    public final int column;
+    /** Source text reflecting current location, {@code null} if undefined */
+    public final String text;
+
+    public ASTLocusTag(final Object source, final int line, final int column, final String text) {
+        this.source = source;
+        this.line = line;
+        this.column = column;
+        this.text = text;
+    }
+
+    public String toString() {
+        return toString(new StringBuilder(), null, true).toString();
+    }
+    public StringBuilder toString(final StringBuilder sb, final String level, final boolean inclText) {
+        boolean preCol = false;
+        if (source != null) {
+            sb.append(source);
+            preCol = true;
+        }
+        if (line != -1) {
+            if( preCol ) {
+                sb.append(":");
+            } else {
+                sb.append("line ");
+            }
+            sb.append(line);
+            if (column != -1) {
+                sb.append(":" + column);
+            }
+            preCol = true;
+        }
+        if( null != level && level.length()>0 ) {
+            if( preCol ) {
+                sb.append(": ");
+            }
+            sb.append(level);
+            preCol = true;
+        }
+        if( inclText && null != text && text.length()>0 ) {
+            if( preCol ) {
+                sb.append(": ");
+            } else {
+                sb.append("text ");
+            }
+            sb.append("'").append(text).append("'");
+        }
+        return sb;
+    }
+
+    /**
+     * Interface tag for {@link ASTLocusTag} provider.
+     */
+    public static interface ASTLocusTagProvider {
+        /**
+         * Returns this instance's {@link ASTLocusTag}, if available,
+         * otherwise returns {@code null}.
+         */
+        ASTLocusTag getASTLocusTag();
+    }
+}
diff --git a/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java
index 5673aac..7c88c37 100644
--- a/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java
+++ b/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java
@@ -43,21 +43,21 @@ import java.util.*;
 import java.io.*;
 import java.text.MessageFormat;
 
-import com.jogamp.common.os.MachineDescription;
+import com.jogamp.common.os.MachineDataInfo;
+import com.jogamp.gluegen.Logging.LoggerIf;
 import com.jogamp.gluegen.cgram.types.*;
 
-import java.util.logging.Logger;
-
 /** Emits the C-side component of the Java<->C JNI binding. */
 public class CMethodBindingEmitter extends FunctionEmitter {
 
-  protected static final Logger LOG = Logger.getLogger(CMethodBindingEmitter.class.getPackage().getName());
   protected static final CommentEmitter defaultCommentEmitter = new DefaultCommentEmitter();
 
   protected static final String arrayResLength = "_array_res_length";
   protected static final String arrayRes       = "_array_res";
   protected static final String arrayIdx       = "_array_idx";
 
+  protected final LoggerIf LOG;
+
   protected MethodBinding binding;
 
   /** Name of the package in which the corresponding Java method resides.*/
@@ -109,7 +109,7 @@ public class CMethodBindingEmitter extends FunctionEmitter {
   protected static final String STRING_CHARS_PREFIX = "_strchars_";
 
   // We need this in order to compute sizes of certain types
-  protected MachineDescription machDesc;
+  protected MachineDataInfo machDesc;
 
   /**
    * Constructs an emitter for the specified binding, and sets a default
@@ -124,9 +124,11 @@ public class CMethodBindingEmitter extends FunctionEmitter {
                                final boolean isJavaMethodStatic,
                                final boolean forImplementingMethodCall,
                                final boolean forIndirectBufferAndArrayImplementation,
-                               final MachineDescription machDesc)
+                               final MachineDataInfo machDesc,
+                               final JavaConfiguration configuration)
   {
-    super(output, false);
+    super(output, false, configuration);
+    LOG = Logging.getLogger(CMethodBindingEmitter.class.getPackage().getName(), CMethodBindingEmitter.class.getSimpleName());
 
     assert(binding != null);
     assert(javaClassName != null);
@@ -148,8 +150,21 @@ public class CMethodBindingEmitter extends FunctionEmitter {
   public final MethodBinding getBinding() { return binding; }
 
   @Override
-  public String getName() {
-    return binding.getName();
+  public String getInterfaceName() {
+    return binding.getInterfaceName();
+  }
+  @Override
+  public String getImplName() {
+    return binding.getImplName();
+  }
+  @Override
+  public String getNativeName() {
+    return binding.getNativeName();
+  }
+
+  @Override
+  public FunctionSymbol getCSymbol() {
+      return binding.getCSymbol();
   }
 
   /**
@@ -289,7 +304,7 @@ public class CMethodBindingEmitter extends FunctionEmitter {
   /**
    * Used for certain internal type size computations
    */
-  public final MachineDescription getMachineDescription() { return machDesc; }
+  public final MachineDataInfo getMachineDataInfo() { return machDesc; }
 
 
   @Override
@@ -306,12 +321,8 @@ public class CMethodBindingEmitter extends FunctionEmitter {
     writer.print("_");
     if (isOverloadedBinding)    {
       writer.print(jniMangle(binding));
-      //System.err.println("OVERLOADED MANGLING FOR " + getName() +
-      //                   " = " + jniMangle(binding));
     } else {
-      writer.print(JavaEmitter.jniMangle(getName()));
-      //System.err.println("    NORMAL MANGLING FOR " + binding.getName() +
-      //                   " = " + jniMangle(getName()));
+      writer.print(JavaEmitter.jniMangle(getImplName()));
     }
   }
 
@@ -450,8 +461,10 @@ public class CMethodBindingEmitter extends FunctionEmitter {
     final JavaType javaReturnType = binding.getJavaReturnType();
     if (!cReturnType.isVoid()) {
       writer.print("  ");
-      // Note we must respect const/volatile for return argument
-      writer.print(binding.getCSymbol().getReturnType().getName(true));
+      // Note we respect const/volatile in the function return type.
+      // However, we cannot have it 'const' for our local variable.
+      // See cast in emitBodyCallCFunction(..)!
+      writer.print(binding.getCSymbol().getReturnType().getCName(false));
       writer.println(" _res;");
       if (javaReturnType.isNIOByteBufferArray() ||
           javaReturnType.isArrayOfCompoundTypeWrappers()) {
@@ -569,7 +582,7 @@ public class CMethodBindingEmitter extends FunctionEmitter {
         writer.println("  if ( NULL != " + javaArgName + " ) {");
 
         final Type cArgType = binding.getCArgumentType(i);
-        String cArgTypeName = cArgType.getName();
+        String cArgTypeName = cArgType.getCName();
 
         final String convName = pointerConversionArgumentName(javaArgName);
 
@@ -595,14 +608,14 @@ public class CMethodBindingEmitter extends FunctionEmitter {
           //
           // Note that we properly handle only the case of an array of
           // compound type wrappers in emitBodyVariablePostCallCleanup below
-          if (!isBaseTypeConst(cArgType) &&
+          if (!cArgType.isBaseTypeConst() &&
               !javaArgType.isArrayOfCompoundTypeWrappers()) {
             // FIXME: if the arg type is non-const, the sematics might be that
             // the function modifies the argument -- we don't yet support
             // this.
-            throw new RuntimeException(
-              "Cannot copy data for ptr-to-ptr arg type \"" + cArgType +
-              "\": support for non-const ptr-to-ptr types not implemented.");
+            throw new GlueGenException(
+              "Cannot copy data for ptr-to-ptr arg type \"" + cArgType.getDebugString() +
+              "\": support for non-const ptr-to-ptr types not implemented: "+binding, binding.getCSymbol().getASTLocusTag());
           }
 
           writer.println();
@@ -646,16 +659,17 @@ public class CMethodBindingEmitter extends FunctionEmitter {
                   error = 100;
               }
               if( 0 < error ) {
-                throw new RuntimeException(
-                  "Could not copy data for type \"" + cArgType +
-                  "\"; currently only pointer- and array-types are supported. (error "+error+")");
+                throw new GlueGenException(
+                  "Could not copy data for type \"" + cArgType.getDebugString() +
+                  "\"; currently only pointer- and array-types are supported. (error "+error+"): "+binding,
+                  binding.getCSymbol().getASTLocusTag());
               }
           }
           emitMalloc(
             writer,
             convName+"_copy",
-            cArgElementType.getName(),
-            isBaseTypeConst(cArgType),
+            cArgElementType.getCName(),
+            cArgType.isBaseTypeConst(),
             arrayLenName,
             "Could not allocate buffer for copying data in argument \\\""+javaArgName+"\\\"");
 
@@ -692,7 +706,7 @@ public class CMethodBindingEmitter extends FunctionEmitter {
                in the method binding. */
             emitGetDirectBufferAddress(writer,
                                        "_tmpObj",
-                                       cArgElementType.getName(),
+                                       cArgElementType.getCName(),
                                        convName + "_copy[_copyIndex]",
                                        true,
                                        "_offsetHandle[_copyIndex]", true);
@@ -702,13 +716,14 @@ public class CMethodBindingEmitter extends FunctionEmitter {
             // offset argument
             emitGetDirectBufferAddress(writer,
                                        "_tmpObj",
-                                       cArgElementType.getName(),
+                                       cArgElementType.getCName(),
                                        "("+convName + "_copy + _copyIndex)",
                                        false /* !receivingIsPtrPtr -> linear layout -> use memcpy */,
                                        null, true);
           } else {
             if( null == cArgElementType2 ) {
-                throw new RuntimeException("XXX: Type "+cArgType+" not properly handled as ptr-to-ptr");
+                throw new GlueGenException("XXX: Type "+cArgType.getDebugString()+" not properly handled as ptr-to-ptr: "+binding,
+                                           binding.getCSymbol().getASTLocusTag());
             }
             // Question: do we always need to copy the sub-arrays, or just
             // GetPrimitiveArrayCritical on each jobjectarray element and
@@ -719,14 +734,15 @@ public class CMethodBindingEmitter extends FunctionEmitter {
             emitMalloc(
                        writer,
                        convName+"_copy[_copyIndex]",
-                       cArgElementType2.getName(), // assumes cArgPtrType is ptr-to-ptr-to-primitive !!
-                       isBaseTypeConst(cArgType),
+                       cArgElementType2.getCName(), // assumes cArgPtrType is ptr-to-ptr-to-primitive !!
+                       cArgType.isBaseTypeConst(),
                        "(*env)->GetArrayLength(env, _tmpObj)",
                        "Could not allocate buffer during copying of data in argument \\\""+javaArgName+"\\\"");
             // FIXME: copy the data (use matched Get/ReleasePrimitiveArrayCritical() calls)
             if (true) {
-                throw new RuntimeException("Cannot yet handle type \"" + cArgType.getName() +
-                              "\"; need to add support for copying ptr-to-ptr-to-primitiveType subarrays");
+                throw new GlueGenException("Cannot yet handle type \"" + cArgType.getDebugString() +
+                                           "\"; need to add support for copying ptr-to-ptr-to-primitiveType subarrays: "+binding,
+                                           binding.getCSymbol().getASTLocusTag());
             }
 
           }
@@ -781,7 +797,7 @@ public class CMethodBindingEmitter extends FunctionEmitter {
           writer.println("  if ( JNI_FALSE == " + isNIOArgName(i) + " && NULL != " + javaArgName + " ) {");
 
           // Release array
-          final String modeFlag = isBaseTypeConst(cArgType) ? "JNI_ABORT" : "0" ;
+          final String modeFlag = cArgType.isBaseTypeConst() ? "JNI_ABORT" : "0" ;
           writer.print("    (*env)->ReleasePrimitiveArrayCritical(env, " + javaArgName + ", " + convName + ", "+modeFlag+");");
         } else {
           writer.println("  if ( NULL != " + javaArgName + " ) {");
@@ -792,7 +808,7 @@ public class CMethodBindingEmitter extends FunctionEmitter {
           //
           // FIXME: should factor out this whole block of code into a separate
           // method for clarity and maintenance purposes
-          if (!isBaseTypeConst(cArgType)) {
+          if (!cArgType.isBaseTypeConst()) {
             // FIXME: handle any cleanup from treatment of non-const args,
             // assuming they were treated differently in
             // emitBodyVariablePreCallSetup() (see the similar section in that
@@ -804,15 +820,16 @@ public class CMethodBindingEmitter extends FunctionEmitter {
               writer.println("      _tmpObj = (*env)->GetObjectArrayElement(env, " + javaArgName + ", _copyIndex);");
               emitReturnDirectBufferAddress(writer,
                                           "_tmpObj",
-                                          cArgType.asArray().getBaseElementType().getName(),
+                                          cArgType.asArray().getBaseElementType().getCName(),
                                           "("+convName + "_copy + _copyIndex)",
                                           false /* receivingIsPtrPtr */,
                                           null);
               writer.println("    }");
             } else {
-              throw new RuntimeException(
-                "Cannot clean up copied data for ptr-to-ptr arg type \"" + cArgType +
-                "\": support for cleaning up most non-const ptr-to-ptr types not implemented.");
+              throw new GlueGenException(
+                "Cannot clean up copied data for ptr-to-ptr arg type \"" + cArgType.getDebugString() +
+                "\": support for cleaning up most non-const ptr-to-ptr types not implemented.",
+                binding.getCSymbol().getASTLocusTag());
             }
           }
 
@@ -833,9 +850,10 @@ public class CMethodBindingEmitter extends FunctionEmitter {
             // free each element
             final PointerType cArgPtrType = cArgType.asPointer();
             if (cArgPtrType == null) {
-              throw new RuntimeException(
-                "Could not copy data for type \"" + cArgType +
-                "\"; currently only pointer types supported.");
+              throw new GlueGenException(
+                "Could not copy data for type \"" + cArgType.getDebugString() +
+                "\"; currently only pointer types supported.",
+                binding.getCSymbol().getASTLocusTag());
             }
 
             // process each element in the array
@@ -854,9 +872,10 @@ public class CMethodBindingEmitter extends FunctionEmitter {
               writer.print(convName+"_copy[_copyIndex]");
               writer.println(");");
             } else {
-              if (true) throw new RuntimeException(
-                "Cannot yet handle type \"" + cArgType.getName() +
-                "\"; need to add support for cleaning up copied ptr-to-ptr-to-primitiveType subarrays");
+              throw new GlueGenException(
+                "Cannot yet handle type \"" + cArgType.getDebugString() +
+                "\"; need to add support for cleaning up copied ptr-to-ptr-to-primitiveType subarrays",
+                binding.getCSymbol().getASTLocusTag());
             }
             writer.println("    }");
           }
@@ -915,20 +934,9 @@ public class CMethodBindingEmitter extends FunctionEmitter {
                                      javaArgType.isArray() ||
                                      javaArgType.isArrayOfCompoundTypeWrappers() ||
                                      ( javaArgType.isNIOBuffer() && forIndirectBufferAndArrayImplementation ) );
-        if (isBaseTypeConst(cArgType)) {
-            writer.print("const ");
-        }
-
-        // if this is a pointer to an unsigned type, add unsigned to the name to avoid compiler warnings
-        if(cArgType.isPointer()) {
-          final Type baseType = cArgType.getBaseElementType();
-          if(baseType.isInt() && (((IntType)baseType).isPrimitiveUnsigned())) {
-            writer.print("unsigned ");
-          }
-        }
-
-        writer.print(cArgType.getName());
+        writer.print(cArgType.getCName(true));
         writer.print(") ");
+
         if (cArgType.isPointer() && javaArgType.isPrimitive()) {
           writer.print("(intptr_t) ");
         }
@@ -975,13 +983,18 @@ public class CMethodBindingEmitter extends FunctionEmitter {
     final Type cReturnType = binding.getCReturnType();
 
     if (!cReturnType.isVoid()) {
-      writer.print("_res = ");
+      // Note we respect const/volatile in the function return type.
+      // However, we cannot have it 'const' for our local variable.
+      // See return type in emitBodyVariableDeclarations(..)!
+      writer.print("_res = (");
+      writer.print(cReturnType.getCName(false));
+      writer.print(") ");
     }
     if ( isCStructFunctionPointer && binding.hasContainingType() ) {
       // Call through function pointer
       writer.print(CMethodBindingEmitter.cThisArgumentName() + "->");
     }
-    writer.print(binding.getCSymbol().getName());
+    writer.print(getNativeName());
     writer.print("(");
     emitBodyPassCArguments(writer);
     writer.println(");");
@@ -1020,7 +1033,7 @@ public class CMethodBindingEmitter extends FunctionEmitter {
         if (returnValueCapacityExpression != null) {
             returnSizeOf = returnValueCapacityExpression.format(argumentNameArray());
         } else {
-            returnSizeOf = "sizeof(" + cReturnType.getName() + ")";
+            returnSizeOf = "sizeof(" + cReturnType.getCName() + ")";
         }
         writer.println("  return JVMUtil_NewDirectByteBufferCopy(env, &_res, "+returnSizeOf+");");
       } else if (javaReturnType.isNIOBuffer() || javaReturnType.isCompoundTypeWrapper()) {
@@ -1029,36 +1042,76 @@ public class CMethodBindingEmitter extends FunctionEmitter {
 
         // See whether capacity has been specified
         if (returnValueCapacityExpression != null) {
-          writer.print( returnValueCapacityExpression.format( argumentNameArray() ) );
+          writer.println( returnValueCapacityExpression.format( argumentNameArray() ) + ");");
         } else {
-          if (cReturnType.isPointer() &&
-              cReturnType.asPointer().getTargetType().isCompound()) {
-            if (cReturnType.asPointer().getTargetType().getSize() == null) {
-              throw new RuntimeException(
-                "Error emitting code for compound return type "+
-                "for function \"" + binding + "\": " +
-                "Structs to be emitted should have been laid out by this point " +
-                "(type " + cReturnType.asPointer().getTargetType().getName() + " / " +
-                cReturnType.asPointer().getTargetType() + " was not) for "+binding
-              );
+          final Type cReturnTargetType = cReturnType.isPointer() ? cReturnType.getTargetType() : null;
+          int mode = 0;
+          if ( 1 == cReturnType.pointerDepth() && null != cReturnTargetType ) {
+            if( cReturnTargetType.isCompound() ) {
+                if( !cReturnTargetType.isAnon() &&
+                    cReturnTargetType.asCompound().getNumFields() > 0 )
+                {
+                    // fully declared non-anonymous struct pointer: pass content
+                    if ( cReturnTargetType.getSize() == null ) {
+                      throw new GlueGenException(
+                        "Error emitting code for compound return type "+
+                        "for function \"" + binding + "\": " +
+                        "Structs to be emitted should have been laid out by this point " +
+                        "(type " + cReturnTargetType.getCName() + " / " +
+                        cReturnTargetType.getDebugString() + " was not) for "+binding.getCSymbol(),
+                        binding.getCSymbol().getASTLocusTag()
+                      );
+                    }
+                    writer.println("sizeof(" + cReturnTargetType.getCName() + ") );");
+                    mode = 10;
+                } else if( cReturnTargetType.asCompound().getNumFields() == 0 ) {
+                    // anonymous struct pointer: pass pointer
+                    writer.println("sizeof(" + cReturnType.getCName() + ") );");
+                    mode = 11;
+                }
+            }
+            if( 0 == mode ) {
+                if( cReturnTargetType.isPrimitive() ) {
+                    // primitive pointer: pass primitive
+                    writer.println("sizeof(" + cReturnTargetType.getCName() + ") );");
+                    mode = 20;
+                } else if( cReturnTargetType.isVoid() ) {
+                    // void pointer: pass pointer
+                    writer.println("sizeof(" + cReturnType.getCName() + ") );");
+                    mode = 21;
+                }
+            }
+          }
+          if( 0 == mode ) {
+            if( null != cfg.typeInfo(cReturnType) ) { // javaReturnType.isOpaqued() covered above via isPrimitive()
+                // Opaque
+                writer.println("sizeof(" + cReturnType.getCName()  + ") );");
+                mode = 88;
+            } else {
+                final String wmsg = "Assumed return size of equivalent C return type";
+                writer.println("sizeof(" + cReturnType.getCName()  + ") ); // WARNING: "+wmsg);
+                mode = 99;
+                LOG.warning(binding.getCSymbol().getASTLocusTag(),
+                  "No capacity specified for java.nio.Buffer return " +
+                  "value for function \"" + binding.getName() + "\". " + wmsg + " (sizeof(" + cReturnType.getCName() + ")): " + binding);
             }
           }
-          writer.print("sizeof(" + cReturnType.getName() + ")");
-          LOG.warning(
-            "No capacity specified for java.nio.Buffer return " +
-            "value for function \"" + binding.getName() + "\"" +
-            " assuming size of equivalent C return type (sizeof(" + cReturnType.getName() + ")): " + binding);
+          writer.println("  /** ");
+          writer.println("   * mode: "+mode);
+          writer.println("   * cReturnType: "+cReturnType.getDebugString());
+          writer.println("   * cReturnTargetType: "+cReturnTargetType.getDebugString());
+          writer.println("   * javaReturnType: "+javaReturnType.getDebugString());
+          writer.println("   */");
         }
-        writer.println(");");
       } else if (javaReturnType.isString()) {
         writer.println("  if (NULL == _res) return NULL;");
-        writer.println("  return (*env)->NewStringUTF(env, _res);");
+        writer.println("  return (*env)->NewStringUTF(env, (const char *)_res);");
       } else if (javaReturnType.isArrayOfCompoundTypeWrappers() ||
                  (javaReturnType.isArray() && javaReturnType.isNIOByteBufferArray())) {
         writer.println("  if (NULL == _res) return NULL;");
         if (returnValueLengthExpression == null) {
-          throw new RuntimeException("Error while generating C code: no length specified for array returned from function " +
-                                     binding);
+          throw new GlueGenException("Error while generating C code: no length specified for array returned from function " +
+                                      binding, binding.getCSymbol().getASTLocusTag());
         }
         writer.println("  " + arrayResLength + " = " + returnValueLengthExpression.format(argumentNameArray()) + ";");
         writer.println("  " + arrayRes + " = (*env)->NewObjectArray(env, " + arrayResLength + ", (*env)->FindClass(env, \"java/nio/ByteBuffer\"), NULL);");
@@ -1071,7 +1124,7 @@ public class CMethodBindingEmitter extends FunctionEmitter {
           pointerType = retType.asArray().getBaseElementType();
         }
         writer.println("    (*env)->SetObjectArrayElement(env, " + arrayRes + ", " + arrayIdx +
-                       ", (*env)->NewDirectByteBuffer(env, (void *)_res[" + arrayIdx + "], sizeof(" + pointerType.getName() + ")));");
+                       ", (*env)->NewDirectByteBuffer(env, (void *)_res[" + arrayIdx + "], sizeof(" + pointerType.getCName() + ")));");
         writer.println("  }");
         writer.println("  return " + arrayRes + ";");
       } else if (javaReturnType.isArray()) {
@@ -1080,9 +1133,10 @@ public class CMethodBindingEmitter extends FunctionEmitter {
         // expression which computes the array size (already present
         // as ReturnValueCapacity, not yet implemented / tested here)
 
-        throw new RuntimeException(
+        throw new GlueGenException(
                                    "Could not emit native code for function \"" + binding +
-                                   "\": array return values for non-char types not implemented yet, for "+binding);
+                                   "\": array return values for non-char types not implemented yet, for "+binding,
+                                   binding.getCSymbol().getASTLocusTag());
 
         // FIXME: This is approximately what will be required here
         //
@@ -1104,8 +1158,8 @@ public class CMethodBindingEmitter extends FunctionEmitter {
         //writer.print(arrayRes);
         //writer.println(";");
       } else {
-        System.err.print("Unhandled return type: "+javaReturnType.getDebugString());
-        throw new RuntimeException("Unhandled return type: "+javaReturnType.getDebugString()+" for "+binding);
+        throw new GlueGenException("Unhandled return type: "+javaReturnType.getDebugString()+" for "+binding,
+                                   binding.getCSymbol().getReturnType().getASTLocusTag());
       }
     }
   }
@@ -1116,7 +1170,7 @@ public class CMethodBindingEmitter extends FunctionEmitter {
 
   protected String jniMangle(final MethodBinding binding) {
     final StringBuilder buf = new StringBuilder();
-    buf.append(JavaEmitter.jniMangle(getName()));
+    buf.append(JavaEmitter.jniMangle(getImplName()));
     buf.append(getImplSuffix());
     buf.append("__");
     if (binding.hasContainingType()) {
@@ -1132,7 +1186,8 @@ public class CMethodBindingEmitter extends FunctionEmitter {
         // We should only see "void" as the first argument of a 1-argument function
         // FIXME: should normalize this in the parser
         if ((i != 0) || (binding.getNumArguments() > 1)) {
-          throw new RuntimeException("Saw illegal \"void\" argument while emitting \"" + getName() + "\"");
+          throw new GlueGenException("Saw illegal \"void\" argument while emitting arg "+i+" of "+binding,
+                                     binding.getCArgumentType(i).getASTLocusTag());
         }
       } else {
         Class<?> c = type.getJavaClass();
@@ -1164,7 +1219,8 @@ public class CMethodBindingEmitter extends FunctionEmitter {
           // These are not exposed at the Java level
         } else {
           // FIXME: add support for char* -> String conversion
-          throw new RuntimeException("Unknown kind of JavaType: name="+type.getName());
+          throw new GlueGenException("Unknown kind of JavaType: arg "+i+", name="+type.getName()+" of "+binding,
+                                     binding.getCArgumentType(i).getASTLocusTag());
         }
       }
     }
@@ -1225,7 +1281,7 @@ public class CMethodBindingEmitter extends FunctionEmitter {
     writer.println("      (*env)->ThrowNew(env, (*env)->FindClass(env, \"java/lang/OutOfMemoryError\"),");
     writer.print("                       \"" + errorMessage);
     writer.print(" in native dispatcher for \\\"");
-    writer.print(getName());
+    writer.print(getInterfaceName());
     writer.println("\\\"\");");
     writer.print("      return");
     if (!binding.getJavaReturnType().isVoid()) {
@@ -1386,33 +1442,34 @@ public class CMethodBindingEmitter extends FunctionEmitter {
     // Note that we don't need to obey const/volatile for outgoing arguments
     //
     if (javaType.isNIOBuffer()) {
-      ptrTypeString = cType.getName();
+      // primitive NIO object
+      ptrTypeString = cType.getCName();
     } else if (javaType.isArray() || javaType.isArrayOfCompoundTypeWrappers()) {
       needsDataCopy = javaArgTypeNeedsDataCopy(javaType);
       if (javaType.isPrimitiveArray() ||
           javaType.isNIOBufferArray() ||
           javaType.isArrayOfCompoundTypeWrappers()) {
-        ptrTypeString = cType.getName();
+        ptrTypeString = cType.getCName();
       } else if (!javaType.isStringArray()) {
         final Class<?> elementType = javaType.getJavaClass().getComponentType();
         if (elementType.isArray()) {
           final Class<?> subElementType = elementType.getComponentType();
           if (subElementType.isPrimitive()) {
             // type is pointer to pointer to primitive
-            ptrTypeString = cType.getName();
+            ptrTypeString = cType.getCName();
           } else {
             // type is pointer to pointer of some type we don't support (maybe
             // it's an array of pointers to structs?)
-            throw new RuntimeException("Unsupported pointer type: \"" + cType.getName() + "\"");
+            throw new GlueGenException("Unsupported pointer type: \"" + cType.getDebugString() + "\"", cType.getASTLocusTag());
           }
         } else {
           // type is pointer to pointer of some type we don't support (maybe
           // it's an array of pointers to structs?)
-          throw new RuntimeException("Unsupported pointer type: \"" + cType.getName() + "\"");
+          throw new GlueGenException("Unsupported pointer type: \"" + cType.getDebugString() + "\"", cType.getASTLocusTag());
         }
       }
     } else {
-      ptrTypeString = cType.getName();
+      ptrTypeString = cType.getCName();
     }
 
     writer.print("  ");
@@ -1434,14 +1491,14 @@ public class CMethodBindingEmitter extends FunctionEmitter {
         String cElementTypeName = "char *";
         final PointerType cPtrType = cType.asPointer();
         if (cPtrType != null) {
-            cElementTypeName = cPtrType.getTargetType().asPointer().getName();
+            cElementTypeName = cPtrType.getTargetType().asPointer().getCName();
         }
-        if (isBaseTypeConst(cType)) {
+        if (cType.isBaseTypeConst()) {
             writer.print("const ");
         }
         writer.print(cElementTypeName+" *");
       } else {
-        if (isBaseTypeConst(cType)) {
+        if (cType.isBaseTypeConst()) {
             writer.print("const ");
         }
         writer.print(ptrTypeString);
@@ -1470,9 +1527,9 @@ public class CMethodBindingEmitter extends FunctionEmitter {
 
     final String cVariableType;
     if( !cType.isPointer() && type.isCompoundTypeWrapper() ) { // FIXME: Compound call-by-value
-        cVariableType = cType.getName()+" *";
+        cVariableType = cType.getCName()+" *";
     } else {
-        cVariableType = cType.getName();
+        cVariableType = cType.getCName();
     }
     emitGetDirectBufferAddress(writer,
                                incomingArgumentName,
diff --git a/src/java/com/jogamp/gluegen/ConstantDefinition.java b/src/java/com/jogamp/gluegen/ConstantDefinition.java
index ca67001..f8f4973 100644
--- a/src/java/com/jogamp/gluegen/ConstantDefinition.java
+++ b/src/java/com/jogamp/gluegen/ConstantDefinition.java
@@ -33,39 +33,135 @@
 
 package com.jogamp.gluegen;
 
-import java.util.*;
+import java.util.regex.Pattern;
+
+import com.jogamp.gluegen.ASTLocusTag.ASTLocusTagProvider;
+import com.jogamp.gluegen.cgram.types.AliasedSymbol.AliasedSymbolImpl;
+import com.jogamp.gluegen.cgram.types.TypeComparator.AliasedSemanticSymbol;
+import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp;
 
 /** Represents the definition of a constant which was provided either
     via a #define statement or through an enum definition. */
-public class ConstantDefinition {
-
-    private final String origName;
-    private final HashSet<String> aliasedNames;
-    private String name;
-    private final String value;
+public class ConstantDefinition extends AliasedSymbolImpl implements AliasedSemanticSymbol, ASTLocusTagProvider {
+    private final boolean relaxedEqSem;
+    private final String sValue;
+    private final long iValue;
+    private final boolean hasIntValue;
     private final boolean isEnum;
     private final String enumName;
-    private Set<String> aliases;
+    private final ASTLocusTag astLocus;
 
+    /** Covering enums  */
     public ConstantDefinition(final String name,
-                              final String value,
-                              final boolean isEnum,
-                              final String enumName) {
-        this.origName = name;
-        this.name = name;
-        this.value = value;
-        this.isEnum = isEnum;
+                              final long value,
+                              final String enumName,
+                              final ASTLocusTag astLocus) {
+        super(name);
+        this.relaxedEqSem = TypeConfig.relaxedEqualSemanticsTest();
+        this.sValue = String.valueOf(value);
+        this.iValue = value;
+        this.hasIntValue = true;
+        this.isEnum = true;
         this.enumName = enumName;
-        this.aliasedNames=new HashSet<String>();
+        this.astLocus = astLocus;
+    }
+
+    /** Covering defines */
+    public ConstantDefinition(final String name,
+                              final String value,
+                              final ASTLocusTag astLocus) {
+        super(name);
+        this.relaxedEqSem = TypeConfig.relaxedEqualSemanticsTest();
+        this.sValue = value;
+        {
+            // Attempt to parse define string as number
+            long v;
+            boolean b;
+            try {
+                v = Long.decode(value).longValue();
+                b = true;
+            } catch (final NumberFormatException e) {
+                v = 0;
+                b = false;
+            }
+            this.iValue = v;
+            this.hasIntValue = b;
+        }
+        this.isEnum = false;
+        this.enumName = null;
+        this.astLocus = astLocus;
+    }
+
+    @Override
+    public ASTLocusTag getASTLocusTag() { return astLocus; }
+
+    /**
+     * Hash by its given {@link #getName() name}.
+     */
+    @Override
+    public final int hashCode() {
+        return getName().hashCode();
+    }
+
+    /**
+     * Equality test by its given {@link #getName() name}.
+     */
+    @Override
+    public final boolean equals(final Object arg) {
+        if (arg == this) {
+            return true;
+        } else  if ( !(arg instanceof ConstantDefinition) ) {
+            return false;
+        } else {
+            final ConstantDefinition t = (ConstantDefinition)arg;
+            return equals(getName(), t.getName());
+        }
     }
 
-    public boolean equals(final ConstantDefinition other) {
-        return (equals(name, other.name) &&
-                equals(value, other.value) &&
-                equals(enumName, other.enumName));
+    @Override
+    public final int hashCodeSemantics() {
+        // 31 * x == (x << 5) - x
+        int hash = 31 + ( null != getName() ? getName().hashCode() : 0 );
+        hash = ((hash << 5) - hash) + ( null != sValue ? sValue.hashCode() : 0 );
+        return ((hash << 5) - hash) + ( null != enumName ? enumName.hashCode() : 0 );
     }
 
-    private boolean equals(final String s1, final String s2) {
+    @Override
+    public final boolean equalSemantics(final SemanticEqualityOp arg) {
+        if (arg == this) {
+            return true;
+        } else  if ( !(arg instanceof ConstantDefinition) ) {
+            return false;
+        } else {
+            final ConstantDefinition t = (ConstantDefinition) arg;
+            if( !equals(getName(), t.getName()) ||
+                !equals(enumName, t.enumName) ) {
+                return false;
+            }
+            if( hasIntValue ) {
+                return iValue == t.iValue;
+            } else {
+                // define's string value may be semantical equal .. but formatted differently!
+                return relaxedEqSem || equals(sValue, t.sValue);
+            }
+        }
+    }
+
+    public String getValue()    { return sValue;    }
+    /** Returns null if this definition was not part of an
+        enumeration, or if the enum was anonymous. */
+    public String getEnumName() { return enumName; }
+
+    public boolean isEnum() { return isEnum; }
+
+    @Override
+    public String toString() {
+        return "ConstantDefinition [name " + getName()
+                + ", value " + sValue + " (isInt " + hasIntValue
+                + "), enumName " + enumName + ", isEnum " + isEnum + "]";
+    }
+
+    private static boolean equals(final String s1, final String s2) {
         if (s1 == null || s2 == null) {
             if (s1 == null && s2 == null) {
                 return true;
@@ -76,57 +172,140 @@ public class ConstantDefinition {
         return s1.equals(s2);
     }
 
-    @Override
-    public int hashCode() {
-        return name.hashCode();
+    public static boolean isConstantExpression(final String value) {
+        if( null != value && value.length() > 0 ) {
+            // Single numeric value
+            if ( isNumber(value) ) {
+                return true;
+            }
+            // Find constant expressions like (1 << 3)
+            // if found just pass them through, they will most likely work in java too
+            // expressions containing identifiers are currently ignored (casts too)
+            final String[] values = value.split("[\\s\\(\\)]"); // [ whitespace '(' ')' ]
+            int numberCount = 0;
+            for (final String s : values) {
+                if( s.length() > 0 ) {
+                    if( isCPPOperand(s) ) {
+                        // OK
+                    } else if ( isNumber(s) ) {
+                        // OK
+                        numberCount++;
+                    } else {
+                        return false;
+                    }
+                }
+            }
+            final boolean res = numberCount > 0;
+            return res;
+        }
+        return false;
     }
 
-    /** Supports renaming in Java binding. */
-    public void rename(final String name) {
-      if(null!=name) {
-          this.name = name;
-          aliasedNames.add(origName);
-      }
+    public static boolean isIdentifier(final String value) {
+        boolean identifier = false;
+
+        final char[] chars = value.toCharArray();
+
+        for (int i = 0; i < chars.length; i++) {
+            final char c = chars[i];
+            if (i == 0) {
+                if (Character.isJavaIdentifierStart(c)) {
+                    identifier = true;
+                }
+            } else {
+                if (!Character.isJavaIdentifierPart(c)) {
+                    identifier = false;
+                    break;
+                }
+            }
+        }
+        return identifier;
     }
 
-    public void addAliasedName(final String name) {
-        aliasedNames.add(name);
+    public static boolean isNumber(final String s) {
+        if( isHexNumber(s) ) {
+            return true;
+        } else {
+            return isDecimalNumber(s);
+        }
     }
-    public Collection<String> getAliasedNames() {
-        return aliasedNames;
+    public static boolean isHexNumber(final String s) {
+        return patternHexNumber.matcher(s).matches();
     }
+    public static Pattern patternHexNumber = Pattern.compile("0[xX][0-9a-fA-F]+[lLfFuU]?");
 
-    public String getOrigName() {
-        return origName;
-    }
+    /**
+     * Complete pattern for <code>floating point</code> number,
+     * compatible and described in {@link Double#valueOf(String)}.
+     */
+    public static Pattern patternDecimalNumber;
+    private static String fpRegex;
+    static {
+        final String Digits = "(\\p{Digit}+)";
+        final String HexDigits = "(\\p{XDigit}+)";
+        // an exponent is 'e' or 'E' followed by an optionally
+        // signed decimal integer.
+        final String Exp = "[eE][+-]?"+Digits;
+        fpRegex =
+            ("[\\x00-\\x20]*"+  // Optional leading "whitespace"
+             "[+-]?" + // Optional sign character
+             "("+
+                 "NaN|" +       // "NaN" string
+                 "Infinity|" +  // "Infinity" string
 
-    public String getName() {
-        return name;
-    }
+                 // A decimal floating-point string representing a finite positive
+                 // number without a leading sign has at most five basic pieces:
+                 // Digits . Digits ExponentPart FloatTypeSuffix
+                 //
+                 // Since this method allows integer-only strings as input
+                 // in addition to strings of floating-point literals, the
+                 // two sub-patterns below are simplifications of the grammar
+                 // productions from the Java Language Specification, 2nd
+                 // edition, section 3.10.2.
 
-    public String getValue()    { return value;    }
-    /** Returns null if this definition was not part of an
-        enumeration, or if the enum was anonymous. */
-    public String getEnumName() { return enumName; }
+                 "("+
+                     "("+
+                         // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
+                         "("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+
 
-    public boolean isEnum() { return isEnum; }
+                         // . Digits ExponentPart_opt FloatTypeSuffix_opt
+                         "(\\.("+Digits+")("+Exp+")?)|"+
 
-    public Set<String> getAliases() {
-        return aliases;
-    }
+                         // Hexadecimal w/ binary exponent
+                         "(" +
+                             "(" +
+                                 // Hexadecimal strings
+                                 // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
+                                 "(0[xX]" + HexDigits + "(\\.)?)|" +
 
-    public void addAlias(final String alias) {
-        if (aliases == null) {
-            aliases = new LinkedHashSet<String>();
-        }
-        aliases.add(alias);
+                                 // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
+                                 "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +
+                             ")" +
+
+                           // binary exponent
+                           "[pP][+-]?" + Digits +
+                         ")" +
+                     ")" +
+                     "[fFdD]?"+
+                 ")"+
+             ")" +
+             "[\\x00-\\x20]*"// Optional trailing "whitespace"
+            );
+        patternDecimalNumber = Pattern.compile(fpRegex);
+    }
+    public static boolean isDecimalNumber(final String s) {
+        return patternDecimalNumber.matcher(s).matches();
     }
 
-    @Override
-    public String toString() {
-        return "ConstantDefinition [name " + name + " origName " + origName + " value " + value
-                + " aliasedNames " + aliasedNames + " aliases " + aliases
-                + " enumName " + enumName + " isEnum " + isEnum + "]";
+    public static boolean isCPPOperand(final String s) {
+        return patternCPPOperand.matcher(s).matches();
     }
+    /**
+     * One of: {@code +} {@code -} {@code *} {@code /} {@code |} {@code &} {@code (} {@code )} {@code <<} {@code >>}
+     * <p>
+     * Expression excludes {@link #patternDecimalNumber}.
+     * </p>
+     */
+    public static Pattern patternCPPOperand = Pattern.compile("(?!"+fpRegex+")[\\+\\-\\*\\/\\|\\&\\(\\)]|(\\<\\<)|(\\>\\>)");
 
 }
diff --git a/src/java/com/jogamp/gluegen/DebugEmitter.java b/src/java/com/jogamp/gluegen/DebugEmitter.java
index 6381c8c..582a1d7 100644
--- a/src/java/com/jogamp/gluegen/DebugEmitter.java
+++ b/src/java/com/jogamp/gluegen/DebugEmitter.java
@@ -39,6 +39,7 @@
 
 package com.jogamp.gluegen;
 
+import java.io.IOException;
 import java.util.*;
 
 import com.jogamp.gluegen.cgram.types.*;
@@ -46,9 +47,16 @@ import com.jogamp.gluegen.cgram.types.*;
 /** Debug emitter which prints the parsing results to standard output. */
 
 public class DebugEmitter implements GlueEmitter {
+  protected JavaConfiguration cfg;
 
   @Override
-  public void readConfigurationFile(final String filename) {}
+  public void readConfigurationFile(final String filename) throws IOException {
+      cfg = createConfig();
+      cfg.read(filename);
+  }
+
+  @Override
+  public JavaConfiguration getConfiguration() { return cfg; }
 
   @Override
   public void beginEmission(final GlueEmitterControls controls) {
@@ -110,10 +118,10 @@ public class DebugEmitter implements GlueEmitter {
   }
 
   @Override
-  public void emitStruct(final CompoundType t, final String alternateName) {
+  public void emitStruct(final CompoundType t, final Type typedefType) {
     String name = t.getName();
-    if (name == null && alternateName != null) {
-      name = alternateName;
+    if (name == null && typedefType != null) {
+      name = typedefType.getName();
     }
 
     System.out.println("Referenced type \"" + name + "\"");
@@ -121,4 +129,13 @@ public class DebugEmitter implements GlueEmitter {
 
   @Override
   public void endStructs() {}
+
+  /**
+   * Create the object that will read and store configuration information for
+   * this JavaEmitter.
+   */
+  protected JavaConfiguration createConfig() {
+    return new JavaConfiguration();
+  }
+
 }
diff --git a/src/java/com/jogamp/gluegen/FunctionEmitter.java b/src/java/com/jogamp/gluegen/FunctionEmitter.java
index 8e9d306..bfbb73b 100644
--- a/src/java/com/jogamp/gluegen/FunctionEmitter.java
+++ b/src/java/com/jogamp/gluegen/FunctionEmitter.java
@@ -42,57 +42,43 @@ package com.jogamp.gluegen;
 import java.util.*;
 import java.io.*;
 
+import com.jogamp.gluegen.cgram.types.FunctionSymbol;
 import com.jogamp.gluegen.cgram.types.Type;
 
 public abstract class FunctionEmitter {
 
   public static final EmissionModifier STATIC = new EmissionModifier("static");
 
-  private final boolean isInterfaceVal;
+  private final boolean isInterface;
   private final ArrayList<EmissionModifier> modifiers;
   private CommentEmitter commentEmitter = null;
   private final PrintWriter defaultOutput;
+  // Only present to provide more clear comments
+  protected final JavaConfiguration cfg;
 
   /**
    * Constructs the FunctionEmitter with a CommentEmitter that emits nothing.
    */
-  public FunctionEmitter(final PrintWriter defaultOutput, final boolean isInterface)  {
+  public FunctionEmitter(final PrintWriter defaultOutput, final boolean isInterface, final JavaConfiguration configuration)  {
     assert(defaultOutput != null);
+    this.isInterface = isInterface;
     this.modifiers = new ArrayList<EmissionModifier>();
     this.defaultOutput = defaultOutput;
-    this.isInterfaceVal = isInterface;
+    this.cfg = configuration;
   }
 
   /**
    * Makes this FunctionEmitter a copy of the passed one.
    */
   public FunctionEmitter(final FunctionEmitter arg) {
+    isInterface = arg.isInterface;
     modifiers      = new ArrayList<EmissionModifier>(arg.modifiers);
     commentEmitter = arg.commentEmitter;
     defaultOutput  = arg.defaultOutput;
-    isInterfaceVal = arg.isInterfaceVal;
+    cfg            = arg.cfg;
   }
 
-  public boolean isInterface() { return isInterfaceVal; }
-
-  /**
-   * Checks the base type of pointer-to-pointer, pointer, array or plain for const-ness.
-   * <p>
-   * Note: Implementation walks down to the base type and returns it's const-ness.
-   * Intermediate 'const' qualifier are not considered, e.g. const pointer.
-   * </p>
-   */
-  protected final boolean isBaseTypeConst(final Type type) {
-    if ( 2 == type.pointerDepth() ) {
-      return type.asPointer().getTargetType().asPointer().getTargetType().isConst();
-    } else if ( 1 == type.pointerDepth() ) {
-      return type.asPointer().getTargetType().isConst();
-    } else if( type.isArray() ) {
-      return type.asArray().getBaseElementType().isConst();
-    } else {
-      return type.isConst();
-    }
-  }
+  public boolean isInterface() { return isInterface; }
 
   public PrintWriter getDefaultOutput() { return defaultOutput; }
 
@@ -111,7 +97,11 @@ public abstract class FunctionEmitter {
 
   public Iterator<EmissionModifier> getModifiers() { return modifiers.iterator(); }
 
-  public abstract String getName();
+  public abstract String getInterfaceName();
+  public abstract String getImplName();
+  public abstract String getNativeName();
+
+  public abstract FunctionSymbol getCSymbol();
 
   /**
    * Emit the function to the specified output (instead of the default
diff --git a/src/java/com/jogamp/gluegen/runtime/FunctionAddressResolver.java b/src/java/com/jogamp/gluegen/GenericCPP.java
similarity index 61%
copy from src/java/com/jogamp/gluegen/runtime/FunctionAddressResolver.java
copy to src/java/com/jogamp/gluegen/GenericCPP.java
index 4fc40a4..db414d9 100644
--- a/src/java/com/jogamp/gluegen/runtime/FunctionAddressResolver.java
+++ b/src/java/com/jogamp/gluegen/GenericCPP.java
@@ -1,5 +1,5 @@
 /**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2015 JogAmp Community. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
  * permitted provided that the following conditions are met:
@@ -25,23 +25,39 @@
  * authors and should not be interpreted as representing official policies, either expressed
  * or implied, of JogAmp Community.
  */
+package com.jogamp.gluegen;
 
-/*
- * Created on Saturday, April 24 2010 16:30
- */
-package com.jogamp.gluegen.runtime;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.util.List;
 
-import com.jogamp.common.os.DynamicLookupHelper;
+import com.jogamp.gluegen.jcpp.LexerException;
 
 /**
- *
- * @author Michael Bien
+ * Generic C preprocessor interface for GlueGen
  */
-public interface FunctionAddressResolver {
+public interface GenericCPP {
+
+    public void addDefine(String name, String value) throws LexerException;
+
+    public String findFile(String filename);
+
+    public OutputStream out();
+    public void setOut(OutputStream out);
+
+    public void run(Reader reader, String filename) throws GlueGenException;
 
     /**
-     * Resolves the name of the function bound to the method and returns the address.
+     * Returns a list of {@link ConstantDefinition}, i.e.
+     * <i>non-function-like</i> and <i>non-empty</i> macros w/ <i>constant-value</i>,
+     * as derived during parsing.
+     * <p>
+     * May return an empty list, in case this preprocessor does not
+     * store {@link ConstantDefinition}s.
+     * </p>
+     * @throws GlueGenException
      */
-    public long resolve(String name, DynamicLookupHelper lookup);
+    public List<ConstantDefinition> getConstantDefinitions() throws GlueGenException;
+
 
-}
+}
\ No newline at end of file
diff --git a/src/java/com/jogamp/gluegen/GlueEmitter.java b/src/java/com/jogamp/gluegen/GlueEmitter.java
index bb46cf5..0e8d61f 100644
--- a/src/java/com/jogamp/gluegen/GlueEmitter.java
+++ b/src/java/com/jogamp/gluegen/GlueEmitter.java
@@ -50,6 +50,7 @@ import com.jogamp.gluegen.cgram.types.*;
 public interface GlueEmitter {
 
   public void readConfigurationFile(String filename) throws Exception;
+  public JavaConfiguration getConfiguration();
 
   /**
    * Begin the emission of glue code. This might include opening files,
@@ -91,11 +92,11 @@ public interface GlueEmitter {
   public void beginStructs(TypeDictionary typedefDictionary,
                            TypeDictionary structDictionary,
                            Map<Type, Type> canonMap) throws Exception;
-  /** Emit glue code for the given CompoundType. alternateName is
+  /** Emit glue code for the given CompoundType. typedefType is
       provided when the CompoundType (e.g. "struct foo_t") has not
       been typedefed to anything but the type of "pointer to struct
       foo_t" has (e.g. "typedef struct foo_t {} *Foo"); in this case
-      alternateName would be set to Foo. */
-  public void emitStruct(CompoundType t, String alternateName) throws Exception;
+      typedefType would be set to pointer type Foo. */
+  public void emitStruct(CompoundType t, Type typedefType) throws Exception;
   public void endStructs() throws Exception;
 }
diff --git a/src/java/com/jogamp/gluegen/GlueGen.java b/src/java/com/jogamp/gluegen/GlueGen.java
index e123910..d0ce9ed 100644
--- a/src/java/com/jogamp/gluegen/GlueGen.java
+++ b/src/java/com/jogamp/gluegen/GlueGen.java
@@ -43,11 +43,13 @@ import com.jogamp.common.GlueGenVersion;
 
 import java.io.*;
 import java.util.*;
+import java.util.logging.Level;
 
 import antlr.*;
+
 import com.jogamp.gluegen.cgram.*;
 import com.jogamp.gluegen.cgram.types.*;
-import com.jogamp.gluegen.pcpp.*;
+import com.jogamp.gluegen.jcpp.JCPP;
 
 import static java.lang.System.*;
 
@@ -61,14 +63,18 @@ public class GlueGen implements GlueEmitterControls {
     }
 
     private final List<String> forcedStructNames = new ArrayList<String>();
-    private PCPP preprocessor;
+    private GenericCPP preprocessor;
 
     // State for SymbolFilters
-    private List<ConstantDefinition> constants;
-    private List<FunctionSymbol> functions;
+    private List<ConstantDefinition> allConstants;
+    private List<FunctionSymbol> allFunctions;
 
     private static boolean debug = false;
 
+    private static Level logLevel = null;
+
+    public static void setDebug(final boolean v) { debug=v; }
+    public static void setLogLevel(final Level l) { logLevel=l; }
     public static boolean debug() { return debug; }
 
     @Override
@@ -83,38 +89,66 @@ public class GlueGen implements GlueEmitterControls {
 
     @Override
     public void runSymbolFilter(final SymbolFilter filter) {
-        filter.filterSymbols(constants, functions);
+        filter.filterSymbols(allConstants, allFunctions);
         final List<ConstantDefinition> newConstants = filter.getConstants();
         final List<FunctionSymbol> newFunctions = filter.getFunctions();
         if (newConstants != null) {
-            constants = newConstants;
+            allConstants = newConstants;
         }
         if (newFunctions != null) {
-            functions = newFunctions;
+            allFunctions = newFunctions;
         }
     }
 
+    /** GlueGen's build in macro name {@value}, when compiling w/ GlueGen. */
+    public static final String __GLUEGEN__ = "__GLUEGEN__";
 
     @SuppressWarnings("unchecked")
-    public void run(final Reader reader, final String filename, final Class<?> emitterClass, final List<String> includePaths, final List<String> cfgFiles, final String outputRootDir, final boolean copyPCPPOutput2Stderr) {
+    public void run(final Reader reader, final String filename, final Class<?> emitterClass, final List<String> includePaths, final List<String> cfgFiles, final String outputRootDir, final boolean copyCPPOutput2Stderr) {
 
         try {
-            final File out = File.createTempFile("PCPPTemp", ".pcpp");
+            if(debug) {
+                Logging.getLogger().setLevel(Level.ALL);
+            } else if( null != logLevel ) {
+                Logging.getLogger().setLevel(logLevel);
+            }
+            final GlueEmitter emit;
+            if (emitterClass == null) {
+                emit = new JavaEmitter();
+            } else {
+                try {
+                    emit = (GlueEmitter) emitterClass.newInstance();
+                } catch (final Exception e) {
+                    throw new RuntimeException("Exception occurred while instantiating emitter class.", e);
+                }
+            }
+
+            for (final String config : cfgFiles) {
+                emit.readConfigurationFile(config);
+            }
+            final JavaConfiguration cfg = emit.getConfiguration();
+
+            final File out = File.createTempFile("CPPTemp", ".cpp");
             final FileOutputStream outStream = new FileOutputStream(out);
 
+            // preprocessor = new PCPP(includePaths, debug, copyCPPOutput2Stderr);
+            preprocessor = new JCPP(includePaths, debug, copyCPPOutput2Stderr);
+            final String cppName = preprocessor.getClass().getSimpleName();
             if(debug) {
-                System.err.println("PCPP output at (persistent): " + out.getAbsolutePath());
+                System.err.println("CPP <"+cppName+"> output at (persistent): " + out.getAbsolutePath());
             } else {
                 out.deleteOnExit();
             }
 
-            preprocessor = new PCPP(includePaths, debug, copyPCPPOutput2Stderr);
-            preprocessor.addDefine("__GLUEGEN__", "2");
+            preprocessor.addDefine(__GLUEGEN__, "2");
             preprocessor.setOut(outStream);
 
             preprocessor.run(reader, filename);
             outStream.flush();
             outStream.close();
+            if(debug) {
+                System.err.println("CPP <"+cppName+"> done");
+            }
 
             final FileInputStream inStream = new FileInputStream(out);
             final DataInputStream dis = new DataInputStream(inStream);
@@ -140,6 +174,7 @@ public class GlueGen implements GlueEmitterControls {
 
             final HeaderParser headerParser = new HeaderParser();
             headerParser.setDebug(debug);
+            headerParser.setJavaConfiguration(cfg);
             final TypeDictionary td = new TypeDictionary();
             headerParser.setTypedefDictionary(td);
             final TypeDictionary sd = new TypeDictionary();
@@ -162,21 +197,6 @@ public class GlueGen implements GlueEmitterControls {
             // generate glue code: the #defines to constants, the set of
             // typedefs, and the set of functions.
 
-            GlueEmitter emit = null;
-            if (emitterClass == null) {
-                emit = new JavaEmitter();
-            } else {
-                try {
-                    emit = (GlueEmitter) emitterClass.newInstance();
-                } catch (final Exception e) {
-                    throw new RuntimeException("Exception occurred while instantiating emitter class.", e);
-                }
-            }
-
-            for (final String config : cfgFiles) {
-                emit.readConfigurationFile(config);
-            }
-
             if (null != outputRootDir && outputRootDir.trim().length() > 0) {
                 if (emit instanceof JavaEmitter) {
                     // FIXME: hack to interfere with the *Configuration setting via commandlines
@@ -189,7 +209,7 @@ public class GlueGen implements GlueEmitterControls {
 
             // Repackage the enum and #define statements from the parser into a common format
             // so that SymbolFilters can operate upon both identically
-            constants = new ArrayList<ConstantDefinition>();
+            allConstants = new ArrayList<ConstantDefinition>();
             for (final EnumType enumeration : headerParser.getEnums()) {
                 String enumName = enumeration.getName();
                 if (enumName.equals("<anonymous>")) {
@@ -198,62 +218,89 @@ public class GlueGen implements GlueEmitterControls {
                 // iterate over all values in the enumeration
                 for (int i = 0; i < enumeration.getNumEnumerates(); ++i) {
                     final String enumElementName = enumeration.getEnumName(i);
-                    final String value = String.valueOf(enumeration.getEnumValue(i));
-                    constants.add(new ConstantDefinition(enumElementName, value, true, enumName));
+                    allConstants.add(new ConstantDefinition(enumElementName, enumeration.getEnumValue(i),
+                                                            enumName, enumeration.getASTLocusTag()));
                 }
             }
             for (final Object elem : lexer.getDefines()) {
                 final Define def = (Define) elem;
-                constants.add(new ConstantDefinition(def.getName(), def.getValue(), false, null));
+                allConstants.add(new ConstantDefinition(def.getName(), def.getValue(), def.getASTLocusTag()));
             }
+            allConstants.addAll(preprocessor.getConstantDefinitions());
 
-            functions = headerParser.getParsedFunctions();
+            allFunctions = headerParser.getParsedFunctions();
 
-            // begin emission of glue code
+            // begin emission of glue code,
+            // incl. firing up 'runSymbolFilter(SymbolFilter)' calls, which:
+            //    - filters all ConstantDefinition
+            //    - filters all FunctionSymbol
             emit.beginEmission(this);
 
-            emit.beginDefines();
-            final Set<String> emittedDefines = new HashSet<String>(100);
-            // emit java equivalent of enum { ... } statements
-            final StringBuilder comment = new StringBuilder();
-            for (final ConstantDefinition def : constants) {
-                if (!emittedDefines.contains(def.getName())) {
-                    emittedDefines.add(def.getName());
-                    final Set<String> aliases = def.getAliases();
-                    if (aliases != null) {
-                        comment.append("Alias for: <code>");
-                        for (final String alias : aliases) {
-                            comment.append(" ").append(alias);
-                        }
-                        comment.append("</code>");
+            if( debug() ) {
+                int i=0;
+                System.err.println("Filtered Constants: "+allConstants.size());
+                for (final ConstantDefinition def : allConstants) {
+                    if( debug() ) {
+                        System.err.println("Filtered ["+i+"]: "+def.getAliasedString());
+                        i++;
                     }
-                    if (def.getEnumName() != null) {
-                        if (comment.length() > 0)
-                            comment.append("<br>\n");
+                }
+                i=0;
+                System.err.println("Filtered Functions: "+allFunctions.size());
+                for (final FunctionSymbol cFunc : allFunctions) {
+                    System.err.println("Filtered ["+i+"]: "+cFunc.getAliasedString());
+                    i++;
+                }
+            }
 
-                        comment.append("Defined as part of enum type \"");
-                        comment.append(def.getEnumName());
-                        comment.append("\"");
-                    }
-                    if (comment.length() > 0) {
-                        emit.emitDefine(def, comment.toString());
-                        comment.setLength(0);
-                    }
-                    else {
-                        emit.emitDefine(def, null);
+            if ( !cfg.structsOnly() ) {
+                emit.beginDefines();
+                final Set<String> emittedDefines = new HashSet<String>(100);
+                // emit java equivalent of enum { ... } statements
+                final StringBuilder comment = new StringBuilder();
+                for (final ConstantDefinition def : allConstants) {
+                    if (!emittedDefines.contains(def.getName())) {
+                        emittedDefines.add(def.getName());
+                        final Set<String> aliases = cfg.getAliasedDocNames(def);
+                        if (aliases != null && aliases.size() > 0 ) {
+                            int i=0;
+                            comment.append("Alias for: <code>");
+                            for (final String alias : aliases) {
+                                if(0 < i) {
+                                    comment.append("</code>, <code>");
+                                }
+                                comment.append(alias);
+                                i++;
+                            }
+                            comment.append("</code>");
+                        }
+                        if (def.getEnumName() != null) {
+                            if (comment.length() > 0)
+                                comment.append("<br>\n");
+
+                            comment.append("Defined as part of enum type \"");
+                            comment.append(def.getEnumName());
+                            comment.append("\"");
+                        }
+                        if (comment.length() > 0) {
+                            emit.emitDefine(def, comment.toString());
+                            comment.setLength(0);
+                        }
+                        else {
+                            emit.emitDefine(def, null);
+                        }
                     }
                 }
+                emit.endDefines();
             }
-            emit.endDefines();
 
             // Iterate through the functions finding structs that are referenced in
             // the function signatures; these will be remembered for later emission
             final ReferencedStructs referencedStructs = new ReferencedStructs();
-            for (final FunctionSymbol sym : functions) {
+            for (final FunctionSymbol sym : allFunctions) {
                 // FIXME: this doesn't take into account the possibility that some of
                 // the functions we send to emitMethodBindings() might not actually be
-                // emitted (e.g., if an Ignore directive in the JavaEmitter causes it
-                // to be skipped).
+                // emitted (e.g., if an Ignore directive in the JavaEmitter causes it to be skipped).
                 sym.getType().visit(referencedStructs);
             }
 
@@ -273,13 +320,9 @@ public class GlueGen implements GlueEmitterControls {
 
             // Lay out structs
             emit.beginStructLayout();
-            for (final Iterator<Type> iter = referencedStructs.results(); iter.hasNext();) {
-                final Type t = iter.next();
-                if (t.isCompound()) {
-                    emit.layoutStruct(t.asCompound());
-                } else if (t.isPointer()) {
-                    final PointerType p = t.asPointer();
-                    final CompoundType c = p.getTargetType().asCompound();
+            for (final Iterator<CompoundType> iter = referencedStructs.layouts(); iter.hasNext();) {
+                final CompoundType c = iter.next();
+                if( !c.isLayouted() ) {
                     emit.layoutStruct(c);
                 }
             }
@@ -290,20 +333,23 @@ public class GlueGen implements GlueEmitterControls {
             for (final Iterator<Type> iter = referencedStructs.results(); iter.hasNext();) {
                 final Type t = iter.next();
                 if (t.isCompound()) {
+                    assert t.isTypedef() && t.getName() == null : "ReferencedStructs incorrectly recorded compound type " + t;
                     emit.emitStruct(t.asCompound(), null);
                 } else if (t.isPointer()) {
                     final PointerType p = t.asPointer();
                     final CompoundType c = p.getTargetType().asCompound();
-                    assert p.hasTypedefedName() && c.getName() == null : "ReferencedStructs incorrectly recorded pointer type " + p;
-                    emit.emitStruct(c, p.getName());
+                    assert p.isTypedef() && c.getName() == null : "ReferencedStructs incorrectly recorded pointer type " + p;
+                    emit.emitStruct(c, p);
                 }
             }
             emit.endStructs();
 
-            // emit java and C code to interface with the native functions
-            emit.beginFunctions(td, sd, headerParser.getCanonMap());
-            emit.emitFunctions(functions);
-            emit.endFunctions();
+            if ( !cfg.structsOnly() ) {
+                // emit java and C code to interface with the native functions
+                emit.beginFunctions(td, sd, headerParser.getCanonMap());
+                emit.emitFunctions(allFunctions);
+                emit.endFunctions();
+            }
 
             // end emission of glue code
             emit.endEmission();
@@ -340,6 +386,9 @@ public class GlueGen implements GlueEmitterControls {
                     emitterFQN = arg.substring(2);
                 } else if (arg.startsWith("-C")) {
                     cfgFiles.add(arg.substring(2));
+                } else if (arg.equals("--logLevel")) {
+                    i++;
+                    logLevel = Level.parse(args[i]);
                 } else if (arg.equals("--debug")) {
                     debug=true;
                 } else if (arg.equals("--dumpCPP")) {
@@ -392,7 +441,7 @@ public class GlueGen implements GlueEmitterControls {
         out.println("file or files can be specified with -C option; e.g,");
         out.println("-Cjava-emitter.cfg.");
         out.println("  --debug enables debug mode");
-        out.println("  --dumpCPP directs PCPP to dump all output to stderr as well");
+        out.println("  --dumpCPP directs CPP to dump all output to stderr as well");
         exit(1);
     }
 }
diff --git a/src/java/com/jogamp/gluegen/GlueGenException.java b/src/java/com/jogamp/gluegen/GlueGenException.java
new file mode 100644
index 0000000..b6713e1
--- /dev/null
+++ b/src/java/com/jogamp/gluegen/GlueGenException.java
@@ -0,0 +1,92 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.gluegen;
+
+import com.jogamp.common.JogampRuntimeException;
+
+/** A generic exception for Jogamp errors used throughout the binding
+    as a substitute for {@link RuntimeException}. */
+
+ at SuppressWarnings("serial")
+public class GlueGenException extends JogampRuntimeException {
+  final ASTLocusTag locus;
+
+  public ASTLocusTag getASTLocusTag() { return locus; }
+
+  /** Constructs a GlueGenException object. */
+  public GlueGenException() {
+    super();
+    locus = null;
+  }
+
+  /** Constructs a GlueGenException object with the specified detail
+      message. */
+  public GlueGenException(final String message) {
+    super(message);
+    locus = null;
+  }
+
+  /** Constructs a GlueGenException object with the specified detail
+      message and root cause. */
+  public GlueGenException(final String message, final Throwable cause) {
+    super(message, cause);
+    locus = null;
+  }
+
+  /** Constructs a GlueGenException object with the specified root
+      cause. */
+  public GlueGenException(final Throwable cause) {
+    super(cause);
+    locus = null;
+  }
+
+  /** Constructs a GlueGenException object with the specified detail
+      message and root cause. */
+  public GlueGenException(final String message, final ASTLocusTag locusTag) {
+    super(message);
+    this.locus = locusTag;
+  }
+
+  /** Constructs a GlueGenException object with the specified detail
+      message and root cause. */
+  public GlueGenException(final String message, final ASTLocusTag locusTag, final Throwable cause) {
+    super(message, cause);
+    this.locus = locusTag;
+  }
+
+  public String toString() {
+      final StringBuilder sb = new StringBuilder(256);
+      if (null != locus) {
+          locus.toString(sb, "error", true).append(": ");
+      }
+      sb.append(getClass().getSimpleName()).append(": ").append(getLocalizedMessage());
+      return sb.toString();
+  }
+
+}
diff --git a/src/java/com/jogamp/gluegen/JavaConfiguration.java b/src/java/com/jogamp/gluegen/JavaConfiguration.java
index 53af4fc..019ca2d 100644
--- a/src/java/com/jogamp/gluegen/JavaConfiguration.java
+++ b/src/java/com/jogamp/gluegen/JavaConfiguration.java
@@ -40,19 +40,19 @@
 
 package com.jogamp.gluegen;
 
+import com.jogamp.gluegen.ASTLocusTag.ASTLocusTagProvider;
 import com.jogamp.gluegen.JavaEmitter.EmissionStyle;
 import com.jogamp.gluegen.JavaEmitter.MethodAccess;
+import com.jogamp.gluegen.Logging.LoggerIf;
+
 import java.io.*;
 import java.lang.reflect.Array;
 import java.util.*;
-import java.util.Map.Entry;
 import java.util.regex.*;
 
 import com.jogamp.gluegen.jgram.*;
 import com.jogamp.gluegen.cgram.types.*;
 
-import java.util.logging.Logger;
-
 import static java.util.logging.Level.*;
 import static com.jogamp.gluegen.JavaEmitter.MethodAccess.*;
 import static com.jogamp.gluegen.JavaEmitter.EmissionStyle.*;
@@ -61,17 +61,13 @@ import static com.jogamp.gluegen.JavaEmitter.EmissionStyle.*;
     JavaEmitter. */
 
 public class JavaConfiguration {
-
-    public static final boolean DEBUG_IGNORES = GlueGen.debug() || false;
-    public static final boolean DEBUG_RENAMES = GlueGen.debug() || false;
-
     private int nestedReads;
     private String packageName;
     private String implPackageName;
     private String className;
     private String implClassName;
 
-    protected static final Logger LOG = Logger.getLogger(JavaConfiguration.class.getPackage().getName());
+    protected final LoggerIf LOG;
 
     public static String NEWLINE = System.getProperty("line.separator");
 
@@ -106,6 +102,13 @@ public class JavaConfiguration {
     private boolean tagNativeBinding;
 
     /**
+     * If true, {@link TypeConfig.SemanticEqualityOp#equalSemantics(TypeConfig.SemanticEqualityOp)}
+     * will attempt to perform a relaxed semantic equality test, e.g. skip the {@code const} and {@code volatile} qualifiers.
+     * Otherwise a full semantic equality test will be performed.
+     */
+    private boolean relaxedEqualSemanticsTest;
+
+    /**
      * Style of code emission. Can emit everything into one class
      * (AllStatic), separate interface and implementing classes
      * (InterfaceAndImpl), only the interface (InterfaceOnly), or only
@@ -135,6 +138,7 @@ public class JavaConfiguration {
     private final Map<String, MethodAccess> accessControl = new HashMap<String, MethodAccess>();
     private final Map<String, TypeInfo> typeInfoMap = new HashMap<String, TypeInfo>();
     private final Set<String> returnsString = new HashSet<String>();
+    private final Map<String, JavaType> returnsOpaqueJType = new HashMap<String, JavaType>();
     private final Map<String, String> returnedArrayLengths = new HashMap<String, String>();
 
     /**
@@ -156,6 +160,7 @@ public class JavaConfiguration {
     private boolean forceUseNIODirectOnly4All = false;
     private final Set<String> useNIODirectOnly = new HashSet<String>();
     private final Set<String> manuallyImplement = new HashSet<String>();
+    private final Map<String, String> delegatedImplementation = new HashMap<String, String>();
     private final Set<String> manualStaticInitCall = new HashSet<String>();
     private final Set<String> forceStaticInitCode = new HashSet<String>();
     private final Map<String, List<String>> customJavaCode = new HashMap<String, List<String>>();
@@ -164,6 +169,7 @@ public class JavaConfiguration {
     private final Map<String, String> structPackages = new HashMap<String, String>();
     private final List<String> customCCode = new ArrayList<String>();
     private final List<String> forcedStructs = new ArrayList<String>();
+    private final Map<String, String> structMachineDataInfoIndex = new HashMap<String, String>();
     private final Map<String, String> returnValueCapacities = new HashMap<String, String>();
     private final Map<String, String> returnValueLengths = new HashMap<String, String>();
     private final Map<String, List<String>> temporaryCVariableDeclarations = new HashMap<String, List<String>>();
@@ -177,6 +183,10 @@ public class JavaConfiguration {
     private final Map<String, List<String>> javaPrologues = new HashMap<String, List<String>>();
     private final Map<String, List<String>> javaEpilogues = new HashMap<String, List<String>>();
 
+    public JavaConfiguration() {
+        LOG = Logging.getLogger(JavaConfiguration.class.getPackage().getName(), JavaConfiguration.class.getSimpleName());
+    }
+
   /** Reads the configuration file.
       @param filename path to file that should be read
   */
@@ -314,20 +324,32 @@ public class JavaConfiguration {
         return tagNativeBinding;
     }
 
+    /**
+     * Returns whether {@link TypeConfig.SemanticEqualityOp#equalSemantics(TypeConfig.SemanticEqualityOp)}
+     * shall attempt to perform a relaxed semantic equality test, e.g. skip the {@code const} and {@code volatile} qualifier
+     * - or not.
+     */
+    public boolean relaxedEqualSemanticsTest() {
+        return relaxedEqualSemanticsTest;
+    }
+
     /** Returns the code emission style (constants in JavaEmitter) parsed from the configuration file. */
     public EmissionStyle emissionStyle() {
         return emissionStyle;
     }
 
-    /** Returns the access control for the emitted Java method. Returns one of JavaEmitter.ACC_PUBLIC, JavaEmitter.ACC_PROTECTED, JavaEmitter.ACC_PRIVATE, or JavaEmitter.ACC_PACKAGE_PRIVATE. */
-    public MethodAccess accessControl(final String methodName) {
-        final MethodAccess ret = accessControl.get(methodName);
+    /**
+     * Returns the access control for the given method-name
+     * or fully qualified class-name.
+     */
+    public MethodAccess accessControl(final String name) {
+        final MethodAccess ret = accessControl.get(name);
         if (ret != null) {
             return ret;
         }
         // Default access control is public
         return PUBLIC;
-  }
+    }
 
     /** Returns the package in which the generated glue code expects to
     find its run-time helper classes (Buffers, Platform,
@@ -352,15 +374,31 @@ public class JavaConfiguration {
     }
 
   private static final boolean DEBUG_TYPE_INFO = false;
+
+  /**
+   * If the given {@code canonicalName} should be considered opaque,
+   * returns the TypeInfo describing the replacement type.
+   * <p>
+   * Returns null if this type should not be considered opaque.
+   * </p>
+   * <p>
+   * If symbol references a struct fields, see {@link #canonicalStructFieldSymbol(String, String)},
+   * it describes field's array-length or element-count referenced by a pointer.
+   * </p>
+   */
+  public TypeInfo canonicalNameOpaque(final String canonicalName) {
+    return typeInfoMap.get(canonicalName);
+  }
+
   /** If this type should be considered opaque, returns the TypeInfo
       describing the replacement type. Returns null if this type
       should not be considered opaque. */
-  public TypeInfo typeInfo(Type type, final TypeDictionary typedefDictionary) {
+  public TypeInfo typeInfo(Type type) {
     // Because typedefs of pointer types can show up at any point,
     // walk the pointer chain looking for a typedef name that is in
     // the TypeInfo map.
     if (DEBUG_TYPE_INFO)
-      System.err.println("Incoming type = " + type);
+      System.err.println("Incoming type = " + type + ", " + type.getDebugString());
     final int pointerDepth = type.pointerDepth();
     for (int i = 0; i <= pointerDepth; i++) {
       String name = type.getName();
@@ -371,12 +409,13 @@ public class JavaConfiguration {
       if (name != null) {
         final TypeInfo info = closestTypeInfo(name, i + type.pointerDepth());
         if (info != null) {
+          final TypeInfo res = promoteTypeInfo(info, i);
           if (DEBUG_TYPE_INFO) {
-            System.err.println(" info.name=" + info.name() + ", name=" + name +
+            System.err.println(" [1] info.name=" + info.name() + ", name=" + name +
                                ", info.pointerDepth=" + info.pointerDepth() +
-                               ", type.pointerDepth=" + type.pointerDepth());
+                               ", type.pointerDepth=" + type.pointerDepth() + " -> "+res);
           }
-          return promoteTypeInfo(info, i);
+          return res;
         }
       }
 
@@ -386,33 +425,13 @@ public class JavaConfiguration {
         if (name != null) {
           final TypeInfo info = closestTypeInfo(name, i + type.pointerDepth());
           if (info != null) {
+            final TypeInfo res = promoteTypeInfo(info, i);
             if (DEBUG_TYPE_INFO) {
-              System.err.println(" info.name=" + info.name() + ", name=" + name +
-                                 ", info.pointerDepth=" + info.pointerDepth() +
-                                 ", type.pointerDepth=" + type.pointerDepth());
-            }
-            return promoteTypeInfo(info, i);
-          }
-        }
-      }
-
-      // Try all typedef names that map to this type
-      final Set<Entry<String, Type>> entrySet = typedefDictionary.entrySet();
-      for (final Map.Entry<String, Type> entry : entrySet) {
-        // "eq" equality is OK to use here since all types have been canonicalized
-        if (entry.getValue() == type) {
-          name = entry.getKey();
-          if (DEBUG_TYPE_INFO) {
-            System.err.println("Looking under typedef name " + name);
-          }
-          final TypeInfo info = closestTypeInfo(name, i + type.pointerDepth());
-          if (info != null) {
-            if (DEBUG_TYPE_INFO) {
-              System.err.println(" info.name=" + info.name() + ", name=" + name +
+              System.err.println(" [2] info.name=" + info.name() + ", name=" + name +
                                  ", info.pointerDepth=" + info.pointerDepth() +
-                                 ", type.pointerDepth=" + type.pointerDepth());
+                                 ", type.pointerDepth=" + type.pointerDepth() + " -> "+res);
             }
-            return promoteTypeInfo(info, i);
+            return res;
           }
         }
       }
@@ -421,7 +440,9 @@ public class JavaConfiguration {
         type = type.asPointer().getTargetType();
       }
     }
-
+    if (DEBUG_TYPE_INFO) {
+      System.err.println(" [X] NULL");
+    }
     return null;
   }
 
@@ -491,6 +512,13 @@ public class JavaConfiguration {
   public boolean returnsString(final String functionName) {
     return returnsString.contains(functionName);
   }
+  /** Indicates whether the given function (which returns a
+      <code>char*</code> in C) should be translated as returning a
+      <code>java.lang.String</code>. */
+  public boolean returnsString(final AliasedSymbol symbol) {
+      return returnsString.contains( symbol.getName() ) ||
+             oneInSet(returnsString, symbol.getAliasedNames());
+  }
 
   /**
    * Returns a MessageFormat string of the Java expression calculating
@@ -543,12 +571,6 @@ public class JavaConfiguration {
     return forceUseNIODirectOnly4All || useNIODirectOnly.contains(functionName);
   }
 
-  /** Returns true if the glue code for the given function will be
-      manually implemented by the end user. */
-  public boolean manuallyImplement(final String functionName) {
-    return manuallyImplement.contains(functionName);
-  }
-
   /**
    * Returns true if the static initialization java code calling <code>initializeImpl()</code>
    * for the given class will be manually implemented by the end user
@@ -634,6 +656,20 @@ public class JavaConfiguration {
   }
 
   /**
+   * Returns a MessageFormat string of the Java code defining {@code mdIdx},
+   * i.e. the index of the static MachineDescriptor index for structs.
+   * <p>
+   * If undefined, code generation uses the default expression:
+   * <pre>
+   *     private static final int mdIdx = MachineDataInfoRuntime.getStatic().ordinal();
+   * </pre>
+   * </p>
+   */
+  public String returnStructMachineDataInfoIndex(final String structName) {
+    return structMachineDataInfoIndex.get(structName);
+  }
+
+  /**
    * Returns a MessageFormat string of the C expression calculating
    * the capacity of the java.nio.ByteBuffer being returned from a
    * native method, or null if no expression has been specified.
@@ -702,52 +738,94 @@ public class JavaConfiguration {
     return parentClass.get(className);
   }
 
-  public void dumpIgnoresOnce() {
-    if(!dumpedIgnores) {
-        dumpedIgnores = true;
-        dumpIgnores();
+  public void logIgnoresOnce() {
+    if(!loggedIgnores) {
+        loggedIgnores = true;
+        logIgnores();
     }
   }
-  private static boolean dumpedIgnores = false;
+  private static boolean loggedIgnores = false;
 
-  public void dumpIgnores() {
-    System.err.println("Extended Intf: ");
+  public void logIgnores() {
+    LOG.log(INFO, "Extended Intf: {0}", extendedIntfSymbolsIgnore.size());
     for (final String str : extendedIntfSymbolsIgnore) {
-        System.err.println("\t"+str);
+        LOG.log(INFO, "\t{0}", str);
     }
-    System.err.println("Extended Impl: ");
+    LOG.log(INFO, "Extended Impl: {0}", extendedImplSymbolsIgnore.size());
     for (final String str : extendedImplSymbolsIgnore) {
-        System.err.println("\t"+str);
+        LOG.log(INFO, "\t{0}", str);
     }
-    System.err.println("Ignores (All): ");
+    LOG.log(INFO, "Ignores (All): {0}", ignores.size());
     for (final Pattern pattern : ignores) {
-        System.err.println("\t"+pattern);
+        LOG.log(INFO, "\t{0}", pattern);
     }
   }
 
-  public void dumpRenamesOnce() {
-    if(!dumpedRenames) {
-        dumpedRenames = true;
-        dumpRenames();
+  public void logRenamesOnce() {
+    if(!loggedRenames) {
+        loggedRenames = true;
+        logRenames();
     }
   }
-  private static boolean dumpedRenames = false;
+  private static boolean loggedRenames = false;
 
-  public void dumpRenames() {
-    System.err.println("Symbol Renames: ");
+  public void logRenames() {
+    LOG.log(INFO, "Symbol Renames: {0}", javaSymbolRenames.size());
     for (final String key : javaSymbolRenames.keySet()) {
-        System.err.println("\t"+key+" -> "+javaSymbolRenames.get(key));
+        LOG.log(INFO, "\t{0} -> {1}", key, javaSymbolRenames.get(key));
     }
 
-    System.err.println("Symbol Aliasing (through renaming): ");
+    LOG.log(INFO, "Symbol Aliasing (through renaming): {0}", javaSymbolRenames.size());
     for(final String newName : javaSymbolRenames.values()) {
         final Set<String> origNames = javaRenamedSymbols.get(newName);
         if(null!=origNames) {
-            System.err.println("\t"+newName+" <- "+origNames);
+            LOG.log(INFO, "\t{0} <- {1}", newName, origNames);
         }
     }
   }
 
+  public static <K,V> V oneInMap(final Map<K, V> map, final Set<K> symbols) {
+      if( null != map && map.size() > 0 &&
+          null != symbols && symbols.size() > 0 ) {
+          for(final K sym : symbols) {
+              final V v = map.get(sym);
+              if( null != v ) {
+                  return v;
+              }
+          }
+      }
+      return null;
+  }
+  public static <K> boolean oneInSet(final Set<K> set1, final Set<K> set2) {
+      if( null != set1 && set1.size() > 0 &&
+          null != set2 && set2.size() > 0 ) {
+          for(final K sym : set2) {
+              if( set1.contains( sym ) ) {
+                  return true;
+              }
+          }
+      }
+      return false;
+  }
+  private static boolean onePatternMatch(final Pattern ignoreRegexp, final Set<String> set) {
+      if( null != ignoreRegexp && null != set && set.size() > 0 ) {
+          for(final String sym : set) {
+              final Matcher matcher = ignoreRegexp.matcher(sym);
+              if (matcher.matches()) {
+                  return true;
+              }
+          }
+      }
+      return false;
+  }
+  protected static ASTLocusTag getASTLocusTag(final AliasedSymbol s) {
+      if( s instanceof ASTLocusTagProvider ) {
+          return ((ASTLocusTagProvider)s).getASTLocusTag();
+      } else {
+          return null;
+      }
+  }
+
   /**
    * Returns the canonical configuration name for a struct field name,
    * i.e. 'struct-name'.'field-name'
@@ -757,136 +835,286 @@ public class JavaConfiguration {
   }
 
   /**
-   * Returns true if this #define, function, struct, or field within
-   * a struct should be ignored during glue code generation of interfaces and implementation.
+   * Variant of {@link #manuallyImplement(AliasedSymbol)},
+   * where this method only considers the {@link AliasedSymbol#getName() current-name}
+   * of the given symbol, not the {@link #getJavaSymbolRename(String) renamed-symbol}.
+   */
+  public boolean manuallyImplement(final String functionName) {
+      if( manuallyImplement.contains(functionName) ) {
+          LOG.log(INFO, "ManuallyImplement: \"{0}\"", functionName);
+          return true;
+      } else {
+          return false;
+      }
+  }
+
+  /**
+   * Returns true if the glue code for the given aliased function will be
+   * manually implemented by the end user.
+   * <p>
+   * Both, the {@link AliasedSymbol#getName() current-name}
+   * and all {@link AliasedSymbol#getAliasedNames() aliases} shall be considered.
+   * </p>
+   * <p>
+   * If symbol references a struct field or method, see {@link #canonicalStructFieldSymbol(String, String)},
+   * it describes field's array-length or element-count referenced by a pointer.
+   * </p>
+   * @see #manuallyImplement(String)
+   */
+  public boolean manuallyImplement(final AliasedSymbol symbol) {
+      final String name = symbol.getName();
+      final Set<String> aliases = symbol.getAliasedNames();
+
+      if ( manuallyImplement.contains( name ) ||
+           oneInSet(manuallyImplement, aliases)
+         )
+      {
+          LOG.log(INFO, getASTLocusTag(symbol), "ManuallyImplement: {0}", symbol);
+          return true;
+      } else {
+          return false;
+      }
+  }
+
+  /**
+   * Variant of {@link #getDelegatedImplementation(AliasedSymbol)},
+   * where this method only considers the {@link AliasedSymbol#getName() current-name}
+   * of the given symbol, not the {@link #getJavaSymbolRename(String) renamed-symbol}.
+   */
+  public String getDelegatedImplementation(final String functionName) {
+      final String res = delegatedImplementation.get(functionName);
+      if( null == res ) {
+          return null;
+      }
+      LOG.log(INFO, "DelegatedImplementation: {0} -> {1}", functionName, res);
+      return res;
+  }
+
+  /**
+   * Returns the {@code RENAMED-IMPL-SYMBOL} if the implementation of the glue code
+   * of the given function shall be manually delegated by the end user.
+   * <p>
+   * {@code DelegateImplementation <ORIG-SYMBOL> <RENAMED-IMPL-SYMBOL>}
+   * </p>
+   * <p>
+   * The interface is emitted unchanged.
+   * </p>
    * <p>
-   * For struct fields see {@link #canonicalStructFieldSymbol(String, String)}.
+   * The Java and native-code implementation is renamed to {@code RENAMED-IMPL-SYMBOL}.
+   * The user's manual implementation of {@code ORIG-SYMBOL}
+   * may delegate to {@code RENAMED-IMPL-SYMBOL}.
+   * </p>
+   * <p>
+   * If symbol references a struct field or method, see {@link #canonicalStructFieldSymbol(String, String)},
+   * it describes field's array-length or element-count referenced by a pointer.
    * </p>
    */
-  public boolean shouldIgnoreInInterface(final String symbol) {
-    if(DEBUG_IGNORES) {
-        dumpIgnoresOnce();
-    }
-    // Simple case-1; the entire symbol (orig or renamed) is in the interface ignore table
-    final String renamedSymbol = getJavaSymbolRename(symbol);
-    if ( extendedIntfSymbolsIgnore.contains( symbol ) ||
-         extendedIntfSymbolsIgnore.contains( renamedSymbol ) ) {
-      if(DEBUG_IGNORES) {
-          System.err.println("Ignore Intf ignore : "+symbol);
+  public String getDelegatedImplementation(final AliasedSymbol symbol) {
+      final String name = symbol.getName();
+      final Set<String> aliases = symbol.getAliasedNames();
+
+      String res = delegatedImplementation.get(name);
+      if( null == res ) {
+          res = oneInMap(delegatedImplementation, aliases);
+          if( null == res ) {
+              return null;
+          }
       }
-      return true;
-    }
-    // Simple case-2; the entire symbol (orig or renamed) is _not_ in the not-empty interface only table
-    if ( !extendedIntfSymbolsOnly.isEmpty() &&
-         !extendedIntfSymbolsOnly.contains( symbol ) &&
-         !extendedIntfSymbolsOnly.contains( renamedSymbol ) ) {
-          if(DEBUG_IGNORES) {
-              System.err.println("Ignore Intf !extended: " + symbol);
+      LOG.log(INFO, getASTLocusTag(symbol), "DelegatedImplementation: {0} -> {1}", symbol, res);
+      return res;
+  }
+
+  /**
+   * Variant of {@link #getOpaqueReturnType(AliasedSymbol)},
+   * where this method only considers the {@link AliasedSymbol#getName() current-name}
+   * of the given symbol, not the {@link #getJavaSymbolRename(String) renamed-symbol}.
+   */
+  public JavaType getOpaqueReturnType(final String functionName) {
+      final JavaType res = returnsOpaqueJType.get(functionName);
+      if( null == res ) {
+          return null;
+      }
+      LOG.log(INFO, "ReturnsOpaque: {0} -> {1}", functionName, res);
+      return res;
+  }
+
+  /**
+   * Returns the opaque {@link JavaType} for the given function {@link AliasedSymbol}
+   * or {@code null} if not opaque.
+   * <p>
+   * {@code ReturnsOpaque <Primitive Java Type> <Function Name>}
+   * </p>
+   */
+  public JavaType getOpaqueReturnType(final AliasedSymbol symbol) {
+      final String name = symbol.getName();
+      final Set<String> aliases = symbol.getAliasedNames();
+      JavaType res = returnsOpaqueJType.get(name);
+      if( null == res ) {
+          res = oneInMap(returnsOpaqueJType, aliases);
+          if( null == res ) {
+              return null;
           }
+      }
+      LOG.log(INFO, getASTLocusTag(symbol), "ReturnsOpaque: {0} -> {1}", symbol, res);
+      return res;
+  }
+
+  /**
+   * Variant of {@link #shouldIgnoreInInterface(AliasedSymbol)},
+   * where this method only considers the {@link AliasedSymbol#getName() current-name}
+   * of the given symbol, not the {@link #getJavaSymbolRename(String) renamed-symbol}.
+   */
+  public final boolean shouldIgnoreInInterface(final String symbol) {
+      return shouldIgnoreInInterface( new AliasedSymbol.NoneAliasedSymbol(symbol) );
+  }
+  /**
+   * Returns true if this aliased symbol should be ignored
+   * during glue code generation of interfaces and implementation.
+   * <p>
+   * Both, the {@link AliasedSymbol#getName() current-name}
+   * and all {@link AliasedSymbol#getAliasedNames() aliases} shall be considered.
+   * </p>
+   * <p>
+   * Implementation calls {@link #shouldIgnoreInInterface_Int(AliasedSymbol)}
+   * and overriding implementations shall ensure its being called as well!
+   * </p>
+   * @param symbol the symbolic aliased name to check for exclusion
+   */
+  public boolean shouldIgnoreInInterface(final AliasedSymbol symbol) {
+      return shouldIgnoreInInterface_Int(symbol);
+  }
+
+  protected final boolean shouldIgnoreInInterface_Int(final AliasedSymbol symbol) {
+      if( GlueGen.debug() ) {
+          logIgnoresOnce();
+      }
+      final String name = symbol.getName();
+      final Set<String> aliases = symbol.getAliasedNames();
+
+      // Simple case-1; the symbol (orig or renamed) is in the interface ignore table
+      if ( extendedIntfSymbolsIgnore.contains( name ) ||
+           oneInSet(extendedIntfSymbolsIgnore, aliases)
+         )
+      {
+          LOG.log(INFO, getASTLocusTag(symbol), "Ignore Intf ignore (one): {0}", symbol);
           return true;
-    }
-    return shouldIgnoreInImpl_Int(symbol);
+      }
+      // Simple case-2; the entire symbol (orig and renamed) is _not_ in the not-empty interface only table
+      if ( !extendedIntfSymbolsOnly.isEmpty() &&
+           !extendedIntfSymbolsOnly.contains( name ) &&
+           !oneInSet(extendedIntfSymbolsOnly, aliases) ) {
+          LOG.log(INFO, getASTLocusTag(symbol), "Ignore Intf !extended (all): {0}", symbol);
+          return true;
+      }
+      return shouldIgnoreInImpl_Int(symbol);
   }
 
   /**
-   * Returns true if this #define, function, struct, or field within
-   * a struct should be ignored during glue code generation of implementation only.
+   * Returns true if this aliased symbol should be ignored
+   * during glue code generation of implementation only.
+   * <p>
+   * Both, the {@link AliasedSymbol#getName() current-name}
+   * and all {@link AliasedSymbol#getAliasedNames() aliases} shall be considered.
+   * </p>
    * <p>
-   * For struct fields see {@link #canonicalStructFieldSymbol(String, String)}.
+   * Implementation calls {@link #shouldIgnoreInImpl_Int(AliasedSymbol)}
+   * and overriding implementations shall ensure its being called as well!
    * </p>
+   * @param symbol the symbolic aliased name to check for exclusion
    */
-  public boolean shouldIgnoreInImpl(final String symbol) {
+  public boolean shouldIgnoreInImpl(final AliasedSymbol symbol) {
     return shouldIgnoreInImpl_Int(symbol);
   }
 
-  private boolean shouldIgnoreInImpl_Int(final String symbol) {
+  protected final boolean shouldIgnoreInImpl_Int(final AliasedSymbol symbol) {
+      final String name = symbol.getName();
+      final Set<String> aliases = symbol.getAliasedNames();
 
-    if(DEBUG_IGNORES) {
-      dumpIgnoresOnce();
-    }
-
-    // Simple case-1; the entire symbol (orig or renamed) is in the implementation ignore table
-    final String renamedSymbol = getJavaSymbolRename(symbol);
-    if ( extendedImplSymbolsIgnore.contains( symbol ) ||
-         extendedImplSymbolsIgnore.contains( renamedSymbol ) ) {
-      if(DEBUG_IGNORES) {
-          System.err.println("Ignore Impl ignore : "+symbol);
+      // Simple case-1; the symbol (orig or renamed) is in the interface ignore table
+      if ( extendedImplSymbolsIgnore.contains( name ) ||
+           oneInSet(extendedImplSymbolsIgnore, aliases)
+         )
+      {
+          LOG.log(INFO, getASTLocusTag(symbol), "Ignore Impl ignore (one): {0}", symbol);
+          return true;
       }
-      return true;
-    }
-    // Simple case-2; the entire symbol (orig or renamed) is _not_ in the not-empty implementation only table
-    if ( !extendedImplSymbolsOnly.isEmpty() &&
-         !extendedImplSymbolsOnly.contains( symbol ) &&
-         !extendedImplSymbolsOnly.contains( renamedSymbol ) ) {
-          if(DEBUG_IGNORES) {
-              System.err.println("Ignore Impl !extended: " + symbol);
-          }
+      // Simple case-2; the entire symbol (orig and renamed) is _not_ in the not-empty interface only table
+      if ( !extendedImplSymbolsOnly.isEmpty() &&
+           !extendedImplSymbolsOnly.contains( name ) &&
+           !oneInSet(extendedImplSymbolsOnly, aliases) ) {
+          LOG.log(INFO, getASTLocusTag(symbol), "Ignore Impl !extended (all): {0}", symbol);
           return true;
-    }
-
-    // Ok, the slow case. We need to check the entire table, in case the table
-    // contains an regular expression that matches the symbol.
-    for (final Pattern regexp : ignores) {
-      final Matcher matcher = regexp.matcher(symbol);
-      if (matcher.matches()) {
-        if(DEBUG_IGNORES) {
-            System.err.println("Ignore Impl RegEx: "+symbol);
-        }
-        return true;
       }
-    }
 
-    // Check negated ignore table if not empty
-    if (ignoreNots.size() > 0) {
       // Ok, the slow case. We need to check the entire table, in case the table
       // contains an regular expression that matches the symbol.
-      for (final Pattern regexp : ignoreNots) {
-        final Matcher matcher = regexp.matcher(symbol);
-        if (!matcher.matches()) {
-          // Special case as this is most often likely to be the case.
-          // Unignores are not used very often.
-          if(unignores.isEmpty()) {
-            if(DEBUG_IGNORES) {
-                System.err.println("Ignore Impl unignores==0: "+symbol);
-            }
-            return true;
+      for (final Pattern ignoreRegexp : ignores) {
+          final Matcher matcher = ignoreRegexp.matcher(name);
+          if ( matcher.matches() || onePatternMatch(ignoreRegexp, aliases) ) {
+              LOG.log(INFO, getASTLocusTag(symbol), "Ignore Impl RegEx: {0}", symbol);
+              return true;
           }
+      }
 
-          boolean unignoreFound = false;
-          for (final Pattern unignoreRegexp : unignores) {
-            final Matcher unignoreMatcher = unignoreRegexp.matcher(symbol);
-            if (unignoreMatcher.matches()) {
-              unignoreFound = true;
-              break;
-            }
+      // Check negated ignore table if not empty
+      if (ignoreNots.size() > 0) {
+          // Ok, the slow case. We need to check the entire table, in case the table
+          // contains an regular expression that matches the symbol.
+          for (final Pattern ignoreNotRegexp : ignoreNots) {
+              final Matcher matcher = ignoreNotRegexp.matcher(name);
+              if ( !matcher.matches() && !onePatternMatch(ignoreNotRegexp, aliases) ) {
+                  // Special case as this is most often likely to be the case.
+                  // Unignores are not used very often.
+                  if(unignores.isEmpty()) {
+                      LOG.log(INFO, getASTLocusTag(symbol), "Ignore Impl unignores==0: {0} -> {1}", symbol, name);
+                      return true;
+                  }
+                  boolean unignoreFound = false;
+                  for (final Pattern unignoreRegexp : unignores) {
+                      final Matcher unignoreMatcher = unignoreRegexp.matcher(name);
+                      if ( unignoreMatcher.matches() || onePatternMatch(unignoreRegexp, aliases) ) {
+                          unignoreFound = true;
+                          break;
+                      }
+                  }
+
+                  if (!unignoreFound) {
+                      LOG.log(INFO, getASTLocusTag(symbol), "Ignore Impl !unignore: {0} -> {1}", symbol, name);
+                      return true;
+                  }
+              }
           }
-
-          if (!unignoreFound)
-            if(DEBUG_IGNORES) {
-                System.err.println("Ignore Impl !unignore: "+symbol);
-            }
-            return true;
-        }
       }
-    }
-
-    return false;
+      return false;
   }
 
   /** Returns true if this function should be given a body which
       throws a run-time exception with an "unimplemented" message
       during glue code generation. */
-  public boolean isUnimplemented(final String symbol) {
-    // Ok, the slow case. We need to check the entire table, in case the table
-    // contains an regular expression that matches the symbol.
-    for (final Pattern regexp : unimplemented) {
-      final Matcher matcher = regexp.matcher(symbol);
-      if (matcher.matches()) {
-        return true;
+  public boolean isUnimplemented(final AliasedSymbol symbol) {
+      // Ok, the slow case. We need to check the entire table, in case the table
+      // contains an regular expression that matches the symbol.
+      for (final Pattern unimplRegexp : unimplemented) {
+          final Matcher matcher = unimplRegexp.matcher(symbol.getName());
+          if ( matcher.matches() || onePatternMatch(unimplRegexp, symbol.getAliasedNames()) ) {
+              return true;
+          }
       }
-    }
+      return false;
+  }
+
 
-    return false;
+  /**
+   * Return a set of aliased-name for comment in docs.
+   * <p>
+   * This is usually {@link AliasedSymbol#addAliasedName(String)},
+   * however an implementation may choose otherwise.
+   * </p>
+   * @param symbol the aliased symbol to retrieve the aliases
+   * @return set of aliased-names or {@code null}.
+   */
+  public Set<String> getAliasedDocNames(final AliasedSymbol symbol) {
+      return symbol.getAliasedNames();
   }
 
   /** Returns a replacement name for this type, which should be the
@@ -907,8 +1135,8 @@ public class JavaConfiguration {
       function under the hood. Returns null if this symbol has not
       been explicitly renamed. */
   public String getJavaSymbolRename(final String origName) {
-    if(DEBUG_RENAMES) {
-        dumpRenamesOnce();
+    if( LOG.isLoggable(INFO) ) {
+        logRenamesOnce();
     }
     return javaSymbolRenames.get(origName);
   }
@@ -920,18 +1148,12 @@ public class JavaConfiguration {
 
   /** Programmatically adds a rename directive for the given symbol. */
   public void addJavaSymbolRename(final String origName, final String newName) {
-    if(DEBUG_RENAMES) {
-        System.err.print("\tRename "+origName+" -> "+newName);
-    }
+    LOG.log(INFO, "\tRename {0} -> {1}", origName, newName);
     final String prevValue = javaSymbolRenames.put(origName, newName);
     if(null != prevValue && !prevValue.equals(newName)) {
         throw new RuntimeException("Rename-Override Attampt: "+origName+" -> "+newName+
                                    ", but "+origName+" -> "+prevValue+" already exist. Run in 'debug' mode to analyze!");
     }
-    if(DEBUG_RENAMES) {
-        System.err.println();
-    }
-
     Set<String> origNames = javaRenamedSymbols.get(newName);
     if(null == origNames) {
         origNames = new HashSet<String>();
@@ -940,6 +1162,16 @@ public class JavaConfiguration {
     origNames.add(origName);
   }
 
+  /** Programmatically adds a delegate implementation directive for the given symbol. */
+  public void addDelegateImplementation(final String origName, final String renamedImpl) {
+    LOG.log(INFO, "\tDelegateImplementation {0} -> {1}", origName, renamedImpl);
+    final String prevValue = delegatedImplementation.put(origName, renamedImpl);
+    if(null != prevValue && !prevValue.equals(renamedImpl)) {
+        throw new RuntimeException("Rename-Override Attampt: "+origName+" -> "+renamedImpl+
+                                   ", but "+origName+" -> "+prevValue+" already exist. Run in 'debug' mode to analyze!");
+    }
+  }
+
   /** Returns true if the emission style is AllStatic. */
   public boolean allStatic() {
     return emissionStyle == AllStatic;
@@ -1008,11 +1240,14 @@ public class JavaConfiguration {
       nativeOutputUsesJavaHierarchy = Boolean.valueOf(tmp).booleanValue();
     } else if (cmd.equalsIgnoreCase("TagNativeBinding")) {
       tagNativeBinding = readBoolean("TagNativeBinding", tok, filename, lineNo).booleanValue();
+    } else if (cmd.equalsIgnoreCase("RelaxedEqualSemanticsTest")) {
+      relaxedEqualSemanticsTest = readBoolean("RelaxedEqualSemanticsTest", tok, filename, lineNo).booleanValue();
+      TypeConfig.setRelaxedEqualSemanticsTest(relaxedEqualSemanticsTest); // propagate ..
     } else if (cmd.equalsIgnoreCase("Style")) {
         try{
           emissionStyle = EmissionStyle.valueOf(readString("Style", tok, filename, lineNo));
         }catch(final IllegalArgumentException ex) {
-            LOG.log(WARNING, "Error parsing \"style\" command at line {0} in file \"{1}\"", new Object[]{lineNo, filename});
+            LOG.log(WARNING, "Error parsing \"style\" command at line {0} in file \"{1}\"", lineNo, filename);
         }
     } else if (cmd.equalsIgnoreCase("AccessControl")) {
       readAccessControl(tok, filename, lineNo);
@@ -1022,6 +1257,8 @@ public class JavaConfiguration {
       readOpaque(tok, filename, lineNo);
     } else if (cmd.equalsIgnoreCase("ReturnsString")) {
       readReturnsString(tok, filename, lineNo);
+    } else if (cmd.equalsIgnoreCase("ReturnsOpaque")) {
+      readReturnsOpaque(tok, filename, lineNo);
     } else if (cmd.equalsIgnoreCase("ReturnedArrayLength")) {
       readReturnedArrayLength(tok, filename, lineNo);
       // Warning: make sure delimiters are reset at the top of this loop
@@ -1098,6 +1335,10 @@ public class JavaConfiguration {
       readTemporaryCVariableAssignment(tok, filename, lineNo);
       // Warning: make sure delimiters are reset at the top of this loop
       // because TemporaryCVariableAssignment changes them.
+    } else if (cmd.equalsIgnoreCase("StructMachineDataInfoIndex")) {
+      readStructMachineDataInfoIndex(tok, filename, lineNo);
+      // Warning: make sure delimiters are reset at the top of this loop
+      // because StructMachineDescriptorIndex changes them.
     } else if (cmd.equalsIgnoreCase("ReturnValueCapacity")) {
       readReturnValueCapacity(tok, filename, lineNo);
       // Warning: make sure delimiters are reset at the top of this loop
@@ -1118,10 +1359,10 @@ public class JavaConfiguration {
       readParentClass(tok, filename, lineNo);
     } else if (cmd.equalsIgnoreCase("RenameJavaType")) {
       readRenameJavaType(tok, filename, lineNo);
-    } else if (cmd.equalsIgnoreCase("RenameJavaSymbol") ||
-               // Backward compatibility
-               cmd.equalsIgnoreCase("RenameJavaMethod")) {
+    } else if (cmd.equalsIgnoreCase("RenameJavaSymbol")) {
       readRenameJavaSymbol(tok, filename, lineNo);
+    } else if (cmd.equalsIgnoreCase("DelegateImplementation")) {
+      readDelegateImplementation(tok, filename, lineNo);
     } else if (cmd.equalsIgnoreCase("RuntimeExceptionType")) {
       runtimeExceptionType = readString("RuntimeExceptionType", tok, filename, lineNo);
     } else if (cmd.equalsIgnoreCase("UnsupportedExceptionType")) {
@@ -1193,7 +1434,7 @@ public class JavaConfiguration {
 
   protected void readOpaque(final StringTokenizer tok, final String filename, final int lineNo) {
     try {
-      final JavaType javaType = JavaType.createForClass(stringToPrimitiveType(tok.nextToken()));
+      final JavaType javaType = JavaType.createForOpaqueClass(stringToPrimitiveType(tok.nextToken()));
       String cType = null;
       while (tok.hasMoreTokens()) {
         if (cType == null) {
@@ -1214,6 +1455,17 @@ public class JavaConfiguration {
     }
   }
 
+  protected void readReturnsOpaque(final StringTokenizer tok, final String filename, final int lineNo) {
+    try {
+      final JavaType javaType = JavaType.createForOpaqueClass(stringToPrimitiveType(tok.nextToken()));
+      final String funcName = tok.nextToken();
+      returnsOpaqueJType.put(funcName, javaType);
+    } catch (final Exception e) {
+      throw new RuntimeException("Error parsing \"ReturnsOpaque\" command at line " + lineNo +
+        " in file \"" + filename + "\"", e);
+    }
+  }
+
   protected void readReturnsString(final StringTokenizer tok, final String filename, final int lineNo) {
     try {
       final String name = tok.nextToken();
@@ -1496,6 +1748,18 @@ public class JavaConfiguration {
     }
   }
 
+  protected void readStructMachineDataInfoIndex(final StringTokenizer tok, final String filename, final int lineNo) {
+    try {
+      final String structName = tok.nextToken();
+      String restOfLine = tok.nextToken("\n\r\f");
+      restOfLine = restOfLine.trim();
+      structMachineDataInfoIndex.put(structName, restOfLine);
+    } catch (final NoSuchElementException e) {
+      throw new RuntimeException("Error parsing \"StructMachineDataInfoIndex\" command at line " + lineNo +
+        " in file \"" + filename + "\"", e);
+    }
+  }
+
   protected void readReturnValueCapacity(final StringTokenizer tok, final String filename, final int lineNo) {
     try {
       final String functionName = tok.nextToken();
@@ -1643,6 +1907,17 @@ public class JavaConfiguration {
     }
   }
 
+  public void readDelegateImplementation(final StringTokenizer tok, final String filename, final int lineNo) {
+    try {
+      final String fromName = tok.nextToken();
+      final String toName   = tok.nextToken();
+      addDelegateImplementation(fromName, toName);
+    } catch (final NoSuchElementException e) {
+      throw new RuntimeException("Error parsing \"DelegateImplementation\" command at line " + lineNo +
+        " in file \"" + filename + "\": missing expected parameter", e);
+    }
+  }
+
   protected void readJavaPrologueOrEpilogue(final StringTokenizer tok, final String filename, final int lineNo, final boolean prologue) {
     try {
       String methodName = tok.nextToken();
@@ -1714,6 +1989,16 @@ public class JavaConfiguration {
     return new TypeInfo(typeName, pointerDepth, javaType);
   }
 
+  public TypeInfo addTypeInfo(final String alias, final Type superType) {
+      final TypeInfo superInfo = typeInfo(superType);
+      if( null != superInfo ) {
+          final TypeInfo res = new TypeInfo(alias, superInfo.pointerDepth(), superInfo.javaType());
+          addTypeInfo(res);
+          return res;
+      } else {
+          return null;
+      }
+  }
   protected void addTypeInfo(final TypeInfo info) {
     TypeInfo tmp = typeInfoMap.get(info.name());
     if (tmp == null) {
diff --git a/src/java/com/jogamp/gluegen/JavaEmitter.java b/src/java/com/jogamp/gluegen/JavaEmitter.java
index f9dd13b..15dc401 100644
--- a/src/java/com/jogamp/gluegen/JavaEmitter.java
+++ b/src/java/com/jogamp/gluegen/JavaEmitter.java
@@ -42,18 +42,20 @@ package com.jogamp.gluegen;
 
 import com.jogamp.common.nio.Buffers;
 import com.jogamp.common.os.DynamicLookupHelper;
-import com.jogamp.common.os.MachineDescription;
+import com.jogamp.common.os.MachineDataInfo;
 
 import java.io.*;
 import java.util.*;
 import java.text.MessageFormat;
 
+import com.jogamp.gluegen.ASTLocusTag.ASTLocusTagProvider;
+import com.jogamp.gluegen.Logging.LoggerIf;
 import com.jogamp.gluegen.cgram.types.*;
+import com.jogamp.gluegen.cgram.types.TypeComparator.AliasedSemanticSymbol;
 
 import java.nio.Buffer;
-import java.util.logging.Logger;
 
-import jogamp.common.os.MachineDescriptionRuntime;
+import jogamp.common.os.MachineDataInfoRuntime;
 import static java.util.logging.Level.*;
 import static com.jogamp.gluegen.JavaEmitter.MethodAccess.*;
 
@@ -70,7 +72,6 @@ import static com.jogamp.gluegen.JavaEmitter.MethodAccess.*;
 public class JavaEmitter implements GlueEmitter {
 
   private StructLayout layout;
-  private TypeDictionary typedefDictionary;
   private Map<Type, Type> canonMap;
   protected JavaConfiguration cfg;
   private boolean requiresStaticInitialization = false;
@@ -97,13 +98,19 @@ public class JavaEmitter implements GlueEmitter {
       private final String javaName;
   }
 
-  private PrintWriter javaWriter; // Emits either interface or, in AllStatic mode, everything
+  private String javaFileName;        // of  javaWriter or javaImplWriter
+  private PrintWriter javaWriter;     // Emits either interface or, in AllStatic mode, everything
   private PrintWriter javaImplWriter; // Only used in non-AllStatic modes for impl class
+  private String cFileName;           // of cWriter
   private PrintWriter cWriter;
-  private final MachineDescription machDescJava = MachineDescription.StaticConfig.X86_64_UNIX.md;
-  private final MachineDescription.StaticConfig[] machDescTargetConfigs = MachineDescription.StaticConfig.values();
+  private final MachineDataInfo machDescJava = MachineDataInfo.StaticConfig.LP64_UNIX.md;
+  private final MachineDataInfo.StaticConfig[] machDescTargetConfigs = MachineDataInfo.StaticConfig.values();
 
-  protected final static Logger LOG = Logger.getLogger(JavaEmitter.class.getPackage().getName());
+  protected final LoggerIf LOG;
+
+  public JavaEmitter() {
+      LOG = Logging.getLogger(JavaEmitter.class.getPackage().getName(), JavaEmitter.class.getSimpleName());
+  }
 
   @Override
   public void readConfigurationFile(final String filename) throws Exception {
@@ -111,61 +118,124 @@ public class JavaEmitter implements GlueEmitter {
     cfg.read(filename);
   }
 
-  class ConstantRenamer implements SymbolFilter {
+  @Override
+  public JavaConfiguration getConfiguration() { return cfg; }
 
+  class ConstFuncRenamer implements SymbolFilter {
     private List<ConstantDefinition> constants;
-
-    @Override
-    public void filterSymbols(final List<ConstantDefinition> constants, final List<FunctionSymbol> functions) {
-      this.constants = constants;
-      doWork();
-    }
+    private List<FunctionSymbol> functions;
 
     @Override
     public List<ConstantDefinition> getConstants() {
       return constants;
     }
-
     @Override
     public List<FunctionSymbol> getFunctions() {
-      return null;
+      return functions;
+    }
+
+    private <T extends AliasedSemanticSymbol> List<T> filterSymbolsInt(final List<T> inList, final List<T> outList) {
+        final JavaConfiguration cfg = getConfig();
+        final HashMap<String, T> symMap = new HashMap<String, T>(100);
+        for (final T sym : inList) {
+            final String origName = sym.getName();
+            final String newName = cfg.getJavaSymbolRename(origName);
+            final T dupSym;
+            if( null != newName ) {
+                // Alias Name
+                dupSym = symMap.get(newName);
+                if( null != dupSym ) {
+                    // only rename to allow 'equalSemantics' to not care ..
+                    sym.rename(newName);
+                }
+            } else {
+                // Original Name
+                dupSym = symMap.get(origName);
+            }
+            if( null != dupSym ) {
+                // Duplicate alias .. check
+                if( !dupSym.equalSemantics(sym) ) {
+                    final ASTLocusTag loc;
+                    final String preLoc;
+                    if( sym instanceof ASTLocusTagProvider ) {
+                        loc = ((ASTLocusTagProvider)sym).getASTLocusTag();
+                    } else {
+                        loc = null;
+                    }
+                    if( dupSym instanceof ASTLocusTagProvider ) {
+                        preLoc = String.format(",%n  %s: previous definition is here",
+                                ((ASTLocusTagProvider)dupSym).getASTLocusTag().toString(new StringBuilder(), "note", true));
+                    } else {
+                        preLoc = "";
+                    }
+                    final String mode = null != newName ? "alias" : "orig";
+                    final String message =
+                            String.format("Duplicate Name (%s) w/ incompatible value:%n  this '%s',%n  have '%s'%s",
+                                    mode, sym.getAliasedString(), dupSym.getAliasedString(), preLoc);
+                    throw new GlueGenException(message, loc);
+                }
+            }
+            if( null != newName ) {
+                // Alias Name
+                if( null != dupSym ) {
+                    // Duplicate alias .. add aliased name
+                    dupSym.addAliasedName(origName);
+                } else {
+                    // No duplicate .. rename and add
+                    sym.rename(newName);
+                    symMap.put(newName, sym);
+                }
+            } else {
+                // Original Name
+                if( null != dupSym ) {
+                    // Duplicate orig .. drop
+                } else {
+                    // No duplicate orig .. add
+                    symMap.put(origName, sym);
+                }
+            }
+        }
+        outList.addAll(symMap.values());
+        // sort constants to make them easier to find in native code
+        Collections.sort(outList, new Comparator<T>() {
+            @Override
+            public int compare(final T o1, final T o2) {
+                return o1.getName().compareTo(o2.getName());
+            }
+        });
+        return outList;
     }
 
-    private void doWork() {
-      final List<ConstantDefinition> newConstants = new ArrayList<ConstantDefinition>();
-      final JavaConfiguration cfg = getConfig();
-      for (final ConstantDefinition def : constants) {
-        def.rename(cfg.getJavaSymbolRename(def.getName()));
-        newConstants.add(def);
-      }
-      constants = newConstants;
+    @Override
+    public void filterSymbols(final List<ConstantDefinition> inConstList, final List<FunctionSymbol> inFuncList) {
+        constants = filterSymbolsInt(inConstList, new ArrayList<ConstantDefinition>(100));
+        functions = filterSymbolsInt(inFuncList, new ArrayList<FunctionSymbol>(100));
     }
   }
 
     @Override
     public void beginEmission(final GlueEmitterControls controls) throws IOException {
+        // Handle renaming of constants and functions
+        controls.runSymbolFilter(new ConstFuncRenamer());
 
         // Request emission of any structs requested
         for (final String structs : cfg.forcedStructs()) {
             controls.forceStructEmission(structs);
         }
 
-        if (!cfg.structsOnly()) {
+        if ( !cfg.structsOnly() ) {
             try {
                 openWriters();
             } catch (final Exception e) {
                 throw new RuntimeException("Unable to open files for writing", e);
             }
             emitAllFileHeaders();
-
-            // Handle renaming of constants
-            controls.runSymbolFilter(new ConstantRenamer());
         }
     }
 
     @Override
     public void endEmission() {
-        if (!cfg.structsOnly()) {
+        if ( !cfg.structsOnly() ) {
             emitAllFileFooters();
 
             try {
@@ -178,7 +248,7 @@ public class JavaEmitter implements GlueEmitter {
 
   @Override
   public void beginDefines() throws Exception {
-    if ((cfg.allStatic() || cfg.emitInterface()) && !cfg.structsOnly()) {
+    if ( ( cfg.allStatic() || cfg.emitInterface() ) && !cfg.structsOnly() ) {
       javaWriter().println();
     }
   }
@@ -231,8 +301,7 @@ public class JavaEmitter implements GlueEmitter {
     // "calculates" the result type of a simple expression
     // example: (2+3)-(2.0f-3.0) -> Double
     // example: (1 << 2) -> Integer
-
-    final Scanner scanner = new Scanner(value).useDelimiter("[+-/*/></(/)]");
+    final Scanner scanner = new Scanner(value).useDelimiter(ConstantDefinition.patternCPPOperand);
 
     Object resultType = null;
 
@@ -315,7 +384,7 @@ public class JavaEmitter implements GlueEmitter {
         final double dVal = Double.parseDouble(value);
         final double absVal = Math.abs(dVal);
         // if constant is small enough, store it as a float instead of a double
-        if (absVal < Float.MIN_VALUE || absVal > Float.MAX_VALUE) {
+        if (absVal < Float.MIN_VALUE || absVal > Float.MAX_VALUE || lastChar == 'd' || lastChar == 'D' ) {
             return new Double(dVal);
         }
         return new Float((float) dVal);
@@ -360,8 +429,7 @@ public class JavaEmitter implements GlueEmitter {
 
   @Override
   public void emitDefine(final ConstantDefinition def, final String optionalComment) throws Exception  {
-
-    if (cfg.allStatic() || cfg.emitInterface()) {
+    if ( ( cfg.allStatic() || cfg.emitInterface() ) && !cfg.structsOnly() ) {
       // TODO: Some defines (e.g., GL_DOUBLE_EXT in gl.h) are defined in terms
       // of other defines -- should we emit them as references to the original
       // define (not even sure if the lexer supports this)? Right now they're
@@ -374,20 +442,20 @@ public class JavaEmitter implements GlueEmitter {
       final String name = def.getName();
       String value = def.getValue();
 
-      if (!cfg.shouldIgnoreInInterface(name)) {
+      if ( !cfg.shouldIgnoreInInterface(def) ) {
         final String type = getJavaType(name, value);
         if (optionalComment != null && optionalComment.length() != 0) {
           javaWriter().println("  /** " + optionalComment + " */");
         }
         String suffix = "";
-        if(!value.endsWith(")")) {
-            if (type.equals("float") && !value.endsWith("f")) {
+        final char lastChar = value.charAt(value.length()-1);
+        if( lastChar != ')' ) {
+            if (type.equals("float") && lastChar != 'f' && lastChar != 'F' ) {
                 suffix = "f";
-            }else if(value.endsWith("u") || value.endsWith("U")) {
+            }else if( lastChar == 'u' || lastChar == 'U' ) {
                 value = value.substring(0, value.length()-1);
             }
         }
-
         javaWriter().println("  public static final " + type + " " + name + " = " + value + suffix + ";");
       }
     }
@@ -402,67 +470,51 @@ public class JavaEmitter implements GlueEmitter {
                              final TypeDictionary structDictionary,
                              final Map<Type, Type> canonMap) throws Exception {
 
-    this.typedefDictionary = typedefDictionary;
+    // this.typedefDictionary = typedefDictionary;
     this.canonMap          = canonMap;
     this.requiresStaticInitialization = false; // reset
 
-    if ((cfg.allStatic() || cfg.emitInterface()) && !cfg.structsOnly()) {
+    if ( ( cfg.allStatic() || cfg.emitInterface() ) && !cfg.structsOnly() ) {
       javaWriter().println();
     }
   }
 
   @Override
-  public Iterator<FunctionSymbol> emitFunctions(final List<FunctionSymbol> originalCFunctions) throws Exception {
-
-    // Sometimes headers will have the same function prototype twice, once
-    // with the argument names and once without. We'll remember the signatures
-    // we've already processed we don't generate duplicate bindings.
-    //
-    // Note: this code assumes that on the equals() method in FunctionSymbol
-    // only considers function name and argument types (i.e., it does not
-    // consider argument *names*) when comparing FunctionSymbols for equality
-    final Set<FunctionSymbol> funcsToBindSet = new HashSet<FunctionSymbol>(100);
-    for (final FunctionSymbol cFunc : originalCFunctions) {
-      if (!funcsToBindSet.contains(cFunc)) {
-        funcsToBindSet.add(cFunc);
-      }
-    }
-
-    //    validateFunctionsToBind(funcsToBindSet);
+  public Iterator<FunctionSymbol> emitFunctions(final List<FunctionSymbol> funcsToBind) throws Exception {
+    if ( !cfg.structsOnly() ) {
+        // Bind all the C funcs to Java methods
+        final ArrayList<FunctionEmitter> methodBindingEmitters = new ArrayList<FunctionEmitter>(2*funcsToBind.size());
+        {
+            int i=0;
+            for (final FunctionSymbol cFunc : funcsToBind) {
+              // Check to see whether this function should be ignored
+              if ( !cfg.shouldIgnoreInImpl(cFunc) ) {
+                  methodBindingEmitters.addAll(generateMethodBindingEmitters(cFunc));
+                  LOG.log(INFO, cFunc.getASTLocusTag(), "Non-Ignored Impl[{0}]: {1}", i++, cFunc);
+              }
 
-    final ArrayList<FunctionSymbol> funcsToBind = new ArrayList<FunctionSymbol>(funcsToBindSet);
-    // sort functions to make them easier to find in native code
-    Collections.sort(funcsToBind, new Comparator<FunctionSymbol>() {
-            @Override
-            public int compare(final FunctionSymbol o1, final FunctionSymbol o2) {
-                return o1.getName().compareTo(o2.getName());
             }
-        });
-
-    // Bind all the C funcs to Java methods
-    final HashSet<MethodBinding> methodBindingSet = new HashSet<MethodBinding>();
-    final ArrayList<FunctionEmitter> methodBindingEmitters = new ArrayList<FunctionEmitter>(2*funcsToBind.size());
-    for (final FunctionSymbol cFunc : funcsToBind) {
-      // Check to see whether this function should be ignored
-      if (!cfg.shouldIgnoreInImpl(cFunc.getName())) {
-          methodBindingEmitters.addAll(generateMethodBindingEmitters(methodBindingSet, cFunc));
-      }
-
-    }
+        }
 
-    // Emit all the methods
-    for (final FunctionEmitter emitter : methodBindingEmitters) {
-      try {
-        if (!emitter.isInterface() || !cfg.shouldIgnoreInInterface(emitter.getName())) {
-            emitter.emit();
-            emitter.getDefaultOutput().println(); // put newline after method body
+        // Emit all the methods
+        {
+            int i=0;
+            for (final FunctionEmitter emitter : methodBindingEmitters) {
+              try {
+                final FunctionSymbol cFunc = emitter.getCSymbol();
+                if ( !emitter.isInterface() || !cfg.shouldIgnoreInInterface(cFunc) ) {
+                    emitter.emit();
+                    emitter.getDefaultOutput().println(); // put newline after method body
+                    LOG.log(INFO, cFunc.getASTLocusTag(), "Non-Ignored Intf[{0}]: {1}", i++, cFunc);
+                }
+              } catch (final Exception e) {
+                throw new GlueGenException(
+                    "Error while emitting binding for \"" + emitter.getCSymbol().getAliasedString() + "\"",
+                    emitter.getCSymbol().getASTLocusTag(), e);
+              }
+            }
         }
-      } catch (final Exception e) {
-        throw new RuntimeException(
-            "Error while emitting binding for \"" + emitter.getName() + "\"", e);
-      }
     }
-
     // Return the list of FunctionSymbols that we generated gluecode for
     return funcsToBind.iterator();
   }
@@ -506,25 +558,33 @@ public class JavaEmitter implements GlueEmitter {
    * native code because it doesn't need any processing of the
    * outgoing arguments).
    */
-  protected void generatePublicEmitters(final MethodBinding binding, final List<FunctionEmitter> allEmitters, final boolean signatureOnly) {
-      if (cfg.manuallyImplement(binding.getName()) && !signatureOnly) {
+  protected void generatePublicEmitters(final MethodBinding binding, final List<FunctionEmitter> allEmitters,
+                                        final boolean signatureOnly) {
+      final FunctionSymbol cSymbol = binding.getCSymbol();
+      if ( !signatureOnly && cfg.manuallyImplement(cSymbol) ) {
           // We only generate signatures for manually-implemented methods;
           // user provides the implementation
           return;
       }
 
-      final MethodAccess accessControl = cfg.accessControl(binding.getName());
+      final MethodAccess accessControl;
+
+      if ( !signatureOnly && null != binding.getDelegationImplName() ) {
+          // private access for delegation implementation methods
+          accessControl = PRIVATE;
+      } else {
+          accessControl = cfg.accessControl(binding.getName());
+      }
+
       // We should not emit anything except public APIs into interfaces
-      if (signatureOnly && (accessControl != PUBLIC)) {
+      if ( signatureOnly && PUBLIC != accessControl ) {
           return;
       }
 
-      final PrintWriter writer = ((signatureOnly || cfg.allStatic()) ? javaWriter() : javaImplWriter());
-
       // It's possible we may not need a body even if signatureOnly is
       // set to false; for example, if the routine doesn't take any
       // arrays or buffers as arguments
-      final boolean isUnimplemented = cfg.isUnimplemented(binding.getName());
+      final boolean isUnimplemented = cfg.isUnimplemented(cSymbol);
       final List<String> prologue = cfg.javaPrologueForMethod(binding, false, false);
       final List<String> epilogue = cfg.javaEpilogueForMethod(binding, false, false);
       final boolean needsBody = isUnimplemented ||
@@ -536,25 +596,31 @@ public class JavaEmitter implements GlueEmitter {
       if( !requiresStaticInitialization ) {
           requiresStaticInitialization = binding.signatureRequiresStaticInitialization();
           if( requiresStaticInitialization ) {
-              LOG.log(INFO, "StaticInit Trigger.1 \"{0}\"", binding);
+              LOG.log(INFO, cSymbol.getASTLocusTag(), "StaticInit Trigger.1 \"{0}\"", binding);
           }
       }
 
+      final boolean emitBody = !signatureOnly && needsBody;
+      final boolean isNativeMethod = !isUnimplemented && !needsBody && !signatureOnly;
+
+      final PrintWriter writer = ((signatureOnly || cfg.allStatic()) ? javaWriter() : javaImplWriter());
+
       final JavaMethodBindingEmitter emitter =
               new JavaMethodBindingEmitter(binding,
                       writer,
                       cfg.runtimeExceptionType(),
                       cfg.unsupportedExceptionType(),
-                      !signatureOnly && needsBody,
+                      emitBody,        // emitBody
                       cfg.tagNativeBinding(),
-                      false, // eraseBufferAndArrayTypes
+                      false,           // eraseBufferAndArrayTypes
                       cfg.useNIOOnly(binding.getName()),
                       cfg.useNIODirectOnly(binding.getName()),
-                      false,
-                      false,
-                      false,
-                      isUnimplemented,
-                      signatureOnly,
+                      false,           // forDirectBufferImplementation
+                      false,           // forIndirectBufferAndArrayImplementation
+                      isUnimplemented, // isUnimplemented
+                      signatureOnly,   // isInterface
+                      isNativeMethod,  // isNativeMethod
+                      false,           // isPrivateNativeMethod
                       cfg);
       switch (accessControl) {
           case PUBLIC:     emitter.addModifier(JavaMethodBindingEmitter.PUBLIC); break;
@@ -565,7 +631,7 @@ public class JavaEmitter implements GlueEmitter {
       if (cfg.allStatic()) {
           emitter.addModifier(FunctionEmitter.STATIC);
       }
-      if (!isUnimplemented && !needsBody && !signatureOnly) {
+      if (isNativeMethod) {
           emitter.addModifier(JavaMethodBindingEmitter.NATIVE);
       }
       emitter.setReturnedArrayLengthExpression(cfg.returnedArrayLength(binding.getName()));
@@ -585,7 +651,8 @@ public class JavaEmitter implements GlueEmitter {
    */
   protected void generatePrivateEmitters(final MethodBinding binding,
                                          final List<FunctionEmitter> allEmitters) {
-      if (cfg.manuallyImplement(binding.getName())) {
+      final FunctionSymbol cSymbol = binding.getCSymbol();
+      if (cfg.manuallyImplement(cSymbol)) {
           // Don't produce emitters for the implementation class
           return;
       }
@@ -594,11 +661,11 @@ public class JavaEmitter implements GlueEmitter {
               cfg.javaPrologueForMethod(binding, false, false) != null ||
               cfg.javaEpilogueForMethod(binding, false, false) != null ;
 
-      if ( !cfg.isUnimplemented( binding.getName() ) ) {
+      if ( !cfg.isUnimplemented( cSymbol ) ) {
           if( !requiresStaticInitialization ) {
               requiresStaticInitialization = binding.signatureRequiresStaticInitialization();
               if( requiresStaticInitialization ) {
-                  LOG.log(INFO, "StaticInit Trigger.2 \"{0}\"", binding);
+                  LOG.log(INFO, cSymbol.getASTLocusTag(), "StaticInit Trigger.2 \"{0}\"", binding);
               }
           }
 
@@ -621,16 +688,17 @@ public class JavaEmitter implements GlueEmitter {
                               writer,
                               cfg.runtimeExceptionType(),
                               cfg.unsupportedExceptionType(),
-                              false,
+                              false, // emitBody
                               cfg.tagNativeBinding(),
-                              true, // eraseBufferAndArrayTypes
+                              true,  // eraseBufferAndArrayTypes
                               cfg.useNIOOnly(binding.getName()),
                               cfg.useNIODirectOnly(binding.getName()),
-                              true,
-                              true,
-                              false,
-                              false,
-                              false,
+                              true,  // forDirectBufferImplementation
+                              false, // forIndirectBufferAndArrayImplementation
+                              false, // isUnimplemented
+                              false, // isInterface
+                              true,  // isNativeMethod
+                              true,  // isPrivateNativeMethod
                               cfg);
               emitter.addModifier(JavaMethodBindingEmitter.PRIVATE);
               if (cfg.allStatic()) {
@@ -658,7 +726,7 @@ public class JavaEmitter implements GlueEmitter {
                               cfg.allStatic(),
                               (binding.needsNIOWrappingOrUnwrapping() || hasPrologueOrEpilogue),
                               !cfg.useNIODirectOnly(binding.getName()),
-                              machDescJava);
+                              machDescJava, getConfiguration());
               prepCEmitter(binding.getName(), binding.getJavaReturnType(), cEmitter);
               allEmitters.add(cEmitter);
           }
@@ -700,18 +768,34 @@ public class JavaEmitter implements GlueEmitter {
    * Generate all appropriate Java bindings for the specified C function
    * symbols.
    */
-  protected List<? extends FunctionEmitter> generateMethodBindingEmitters(final Set<MethodBinding> methodBindingSet, final FunctionSymbol sym) throws Exception {
-
+  protected List<? extends FunctionEmitter> generateMethodBindingEmitters(final FunctionSymbol sym) throws Exception {
     final ArrayList<FunctionEmitter> allEmitters = new ArrayList<FunctionEmitter>();
-
     try {
+        if( cfg.emitInterface() ) {
+            generateMethodBindingEmittersImpl(allEmitters, sym, true);
+        }
+        if( cfg.emitImpl() ) {
+            generateMethodBindingEmittersImpl(allEmitters, sym, false);
+        }
+    } catch (final Exception e) {
+      throw new GlueGenException("Error while generating bindings for \"" + sym + "\"", sym.getASTLocusTag(), e);
+    }
+
+    return allEmitters;
+  }
+  private void generateMethodBindingEmittersImpl(final ArrayList<FunctionEmitter> allEmitters,
+                                                 final FunctionSymbol sym,
+                                                 final boolean forInterface) throws Exception
+  {
       // Get Java binding for the function
-      final MethodBinding mb = bindFunction(sym, null, null, machDescJava);
+      final MethodBinding mb = bindFunction(sym, forInterface, machDescJava, null, null);
 
       // JavaTypes representing C pointers in the initial
       // MethodBinding have not been lowered yet to concrete types
       final List<MethodBinding> bindings = expandMethodBinding(mb);
 
+      final HashSet<MethodBinding> methodBindingSet = new HashSet<MethodBinding>();
+
       for (final MethodBinding binding : bindings) {
 
         if(!methodBindingSet.add(binding)) {
@@ -772,25 +856,19 @@ public class JavaEmitter implements GlueEmitter {
         // Note in particular that the public entry point taking an
         // array is merely a special case of the indirect buffer case.
 
-        if (cfg.emitInterface()) {
+        if ( forInterface ) {
           generatePublicEmitters(binding, allEmitters, true);
-        }
-        if (cfg.emitImpl()) {
+        } else {
           generatePublicEmitters(binding, allEmitters, false);
           generatePrivateEmitters(binding, allEmitters);
         }
       } // end iteration over expanded bindings
-    } catch (final Exception e) {
-      throw new RuntimeException("Error while generating bindings for \"" + sym + "\"", e);
     }
 
-    return allEmitters;
-  }
-
 
   @Override
   public void endFunctions() throws Exception {
-    if (!cfg.structsOnly()) {
+    if ( !cfg.structsOnly() ) {
         if (cfg.allStatic() || cfg.emitInterface()) {
             emitCustomJavaCode(javaWriter(), cfg.className());
         }
@@ -821,44 +899,93 @@ public class JavaEmitter implements GlueEmitter {
   public void beginStructs(final TypeDictionary typedefDictionary,
                            final TypeDictionary structDictionary,
                            final Map<Type, Type> canonMap) throws Exception {
-    this.typedefDictionary = typedefDictionary;
+    // this.typedefDictionary = typedefDictionary;
     this.canonMap          = canonMap;
   }
 
   @Override
-  public void emitStruct(final CompoundType structCType, final String alternateName) throws Exception {
-    final String structCTypeName;
+  public void emitStruct(final CompoundType structCType, final Type structCTypedefPtr) throws Exception {
+    final String structCTypeName, typedefedName;
     {
-        String _name = structCType.getName();
-        if (_name == null && alternateName != null) {
-          _name = alternateName;
+        final String _name = structCType.getName();
+        if ( null != structCTypedefPtr && null != structCTypedefPtr.getName() ) {
+            // always use typedef'ed name if available
+            typedefedName = structCTypedefPtr.getName();
+            structCTypeName = typedefedName;
+        } else {
+            // fall back to actual struct type name
+            typedefedName = null;
+            structCTypeName = _name;
         }
-        structCTypeName = _name;
-    }
-
-    if (structCTypeName == null) {
-        final String structName = structCType.getStructName();
-        if ( null != structName && cfg.shouldIgnoreInInterface(structName) ) {
+        LOG.log(INFO, structCType.getASTLocusTag(), "Struct emission of structCType {0}", structCType);
+        LOG.log(INFO, structCType.getASTLocusTag(),"              structCTypedefPtr {0}", structCTypedefPtr);
+        LOG.log(INFO, structCType.getASTLocusTag(),"   : structCTypeName \"{0}\" -> typedefedName \"{1}\" -> \"{2}\"",
+                                                                   _name, typedefedName, structCTypeName);
+        if ( null == structCTypeName ) {
+            LOG.log(INFO, structCType.getASTLocusTag(),
+                    "skipping emission of unnamed struct {0} w/o typedef",  structCType);
+            return;
+        }
+        final AliasedSymbol.AliasedSymbolImpl aliases = new AliasedSymbol.AliasedSymbolImpl(structCTypeName);
+        aliases.addAliasedName(_name);
+        aliases.addAliasedName(typedefedName);
+        if ( cfg.shouldIgnoreInInterface(aliases) ) {
+            LOG.log(INFO, structCType.getASTLocusTag(),
+                    "skipping emission of ignored \"{0}\": {1}", aliases, structCType);
             return;
         }
-        LOG.log(WARNING, "skipping emission of unnamed struct \"{0}\"", structCType);
-        return;
     }
 
-    if (cfg.shouldIgnoreInInterface(structCTypeName)) {
-      return;
+    if( null != structCTypedefPtr && isOpaque(structCTypedefPtr) ) {
+        LOG.log(INFO, structCType.getASTLocusTag(),
+                "skipping emission of opaque typedef {0}", structCTypedefPtr);
+        return;
+    }
+    if( isOpaque(structCType) ) {
+        LOG.log(INFO, structCType.getASTLocusTag(),
+                "skipping emission of opaque c-struct {0}", structCType);
+        return;
     }
 
-    final Type containingCType = canonicalize(new PointerType(SizeThunk.POINTER, structCType, 0));
+    final Type containingCType;
+    {
+        // NOTE: Struct Name Resolution (JavaEmitter, HeaderParser)
+        final Type aptr;
+        int mode;
+        if( null != typedefedName ) {
+            aptr = structCTypedefPtr;
+            mode = 1;
+        } else {
+            aptr = new PointerType(SizeThunk.POINTER, structCType, 0);
+            aptr.setTypedefName(typedefedName);
+            mode = 2;
+        }
+        containingCType = canonicalize(aptr);
+        LOG.log(INFO, structCType.getASTLocusTag(), "containingCType[{0}]: {1} -canon-> {2}", mode, aptr, containingCType);
+    }
     final JavaType containingJType = typeToJavaType(containingCType, null);
-    if (!containingJType.isCompoundTypeWrapper()) {
-      return;
+    if( containingJType.isOpaqued() ) {
+        LOG.log(INFO, structCType.getASTLocusTag(),
+                "skipping emission of opaque {0}, {1}", containingJType, structCType);
+        return;
+    }
+    if( !containingJType.isCompoundTypeWrapper() ) {
+        LOG.log(WARNING, structCType.getASTLocusTag(),
+                "skipping emission of non-compound {0}, {1}", containingJType, structCType);
+        return;
     }
     final String containingJTypeName = containingJType.getName();
+    LOG.log(INFO, structCType.getASTLocusTag(),
+            "perform emission of \"{0}\" -> \"{1}\": {2}", structCTypeName, containingJTypeName, structCType);
+
+    if( 0 == structCType.getNumFields() ) {
+        LOG.log(INFO, structCType.getASTLocusTag(),
+                "emission of \"{0}\" with zero fields {1}", containingJTypeName, structCType);
+    }
 
     this.requiresStaticInitialization = false; // reset
 
-    // machDescJava global MachineDescription is the one used to determine
+    // machDescJava global MachineDataInfo is the one used to determine
     // the sizes of the primitive types seen in the public API in Java.
     // For example, if a C long is an element of a struct, it is the size
     // of a Java int on a 32-bit machine but the size of a Java long
@@ -868,11 +995,11 @@ public class JavaEmitter implements GlueEmitter {
     // implementation on a 32-bit platform must downcast this to an
     // int and set only an int's worth of data in the struct.
     //
-    // The machDescTarget MachineDescription is the one used to determine how
+    // The machDescTarget MachineDataInfo is the one used to determine how
     // much data to set in or get from the struct and exactly from
     // where it comes.
     //
-    // Note that machDescJava MachineDescription is always 64bit unix,
+    // Note that machDescJava MachineDataInfo is always 64bit unix,
     // which complies w/ Java types.
 
     boolean needsNativeCode = false;
@@ -884,13 +1011,13 @@ public class JavaEmitter implements GlueEmitter {
       final Field field = structCType.getField(i);
       final Type fieldType = field.getType();
 
-      final String cfgFieldName0 = JavaConfiguration.canonicalStructFieldSymbol(structCTypeName, field.getName());
+      final String cfgFieldName0 = JavaConfiguration.canonicalStructFieldSymbol(containingJTypeName, field.getName());
 
       if (!cfg.shouldIgnoreInInterface(cfgFieldName0)) {
 
         final String renamed = cfg.getJavaSymbolRename(cfgFieldName0);
         final String fieldName = renamed==null ? field.getName() : renamed;
-        final String cfgFieldName1 = JavaConfiguration.canonicalStructFieldSymbol(structCTypeName, fieldName);
+        final String cfgFieldName1 = JavaConfiguration.canonicalStructFieldSymbol(containingJTypeName, fieldName);
 
         if ( fieldType.isFunctionPointer() || fieldType.isPointer() || requiresGetCStringLength(fieldType, cfgFieldName1) ) {
             needsNativeCode = true;
@@ -935,7 +1062,7 @@ public class JavaEmitter implements GlueEmitter {
     javaWriter.println("import " + cfg.gluegenRuntimePackage() + ".*;");
     javaWriter.println("import " + DynamicLookupHelper.class.getPackage().getName() + ".*;");
     javaWriter.println("import " + Buffers.class.getPackage().getName() + ".*;");
-    javaWriter.println("import " + MachineDescriptionRuntime.class.getName() + ";");
+    javaWriter.println("import " + MachineDataInfoRuntime.class.getName() + ";");
     javaWriter.println();
     final List<String> imports = cfg.imports();
     for (final String str : imports) {
@@ -963,7 +1090,10 @@ public class JavaEmitter implements GlueEmitter {
     javaWriter.println();
     javaWriter.println("  StructAccessor accessor;");
     javaWriter.println();
-    javaWriter.println("  private static final int mdIdx = MachineDescriptionRuntime.getStatic().ordinal();");
+    final String cfgMachDescrIdxCode = cfg.returnStructMachineDataInfoIndex(containingJTypeName);
+    final String machDescrIdxCode = null != cfgMachDescrIdxCode ? cfgMachDescrIdxCode : "private static final int mdIdx = MachineDataInfoRuntime.getStatic().ordinal();";
+    javaWriter.println("  "+machDescrIdxCode);
+    javaWriter.println("  private final MachineDataInfo md;");
     javaWriter.println();
     // generate all offset and size arrays
     generateOffsetAndSizeArrays(javaWriter, "  ", containingJTypeName, structCType, null, null); /* w/o offset */
@@ -975,11 +1105,11 @@ public class JavaEmitter implements GlueEmitter {
     for (int i = 0; i < structCType.getNumFields(); i++) {
       final Field field = structCType.getField(i);
       final Type fieldType = field.getType();
-      final String cfgFieldName0 = JavaConfiguration.canonicalStructFieldSymbol(structCTypeName, field.getName());
+      final String cfgFieldName0 = JavaConfiguration.canonicalStructFieldSymbol(containingJTypeName, field.getName());
       if ( !cfg.shouldIgnoreInInterface(cfgFieldName0) ) {
         final String renamed = cfg.getJavaSymbolRename(cfgFieldName0);
         final String fieldName = null==renamed ? field.getName() : renamed;
-        final String cfgFieldName1 = JavaConfiguration.canonicalStructFieldSymbol(structCTypeName, fieldName);
+        final String cfgFieldName1 = JavaConfiguration.canonicalStructFieldSymbol(containingJTypeName, fieldName);
         if (fieldType.isFunctionPointer()) {
           // no offset/size for function pointer ..
           if( GlueGen.debug() ) {
@@ -990,8 +1120,8 @@ public class JavaEmitter implements GlueEmitter {
           // handle the union in jawt_Win32DrawingSurfaceInfo (fabricate
           // a name?)
           if (fieldType.getName() == null) {
-            throw new RuntimeException("Anonymous structs as fields not supported yet, field \"" +
-                                       cfgFieldName1 + "\", "+fieldType.getDebugString());
+            throw new GlueGenException("Anonymous structs as fields not supported yet, field \"" +
+                                       cfgFieldName1 + "\", "+fieldType.getDebugString(), fieldType.getASTLocusTag());
           }
           if( GlueGen.debug() ) {
             System.err.printf("SE.os.%02d: %s / %s, %s (%s)%n", (i+1), field, cfgFieldName1, fieldType.getDebugString(), "compound");
@@ -1009,11 +1139,11 @@ public class JavaEmitter implements GlueEmitter {
           try {
             externalJavaType = typeToJavaType(fieldType, machDescJava);
           } catch (final Exception e) {
-            throw new RuntimeException("Error occurred while creating accessor for field \"" +
-                                       cfgFieldName1 + "\", "+fieldType.getDebugString(), e);
+            throw new GlueGenException("Error occurred while creating accessor for field \"" +
+                                       cfgFieldName1 + "\", "+fieldType.getDebugString(), fieldType.getASTLocusTag(), e);
           }
           if( GlueGen.debug() ) {
-              System.err.printf("SE.os.%02d: %s / %s, %s (%s)%n", (i+1), field, fieldName, fieldType.getDebugString(), "MISC");
+              System.err.printf("SE.os.%02d: %s / %s, %s (%s)%n", (i+1), field, cfgFieldName1, fieldType.getDebugString(), "MISC");
               System.err.printf("SE.os.%02d: javaType %s%n", (i+1), externalJavaType.getDebugString());
           }
           if (externalJavaType.isPrimitive()) {
@@ -1037,22 +1167,30 @@ public class JavaEmitter implements GlueEmitter {
       }
     }
     javaWriter.println();
-    javaWriter.println("  public static int size() {");
-    javaWriter.println("    return "+containingJTypeName+"_size[mdIdx];");
-    javaWriter.println("  }");
-    javaWriter.println();
-    javaWriter.println("  public static " + containingJTypeName + " create() {");
-    javaWriter.println("    return create(Buffers.newDirectByteBuffer(size()));");
-    javaWriter.println("  }");
-    javaWriter.println();
-    javaWriter.println("  public static " + containingJTypeName + " create(java.nio.ByteBuffer buf) {");
-    javaWriter.println("      return new " + containingJTypeName + "(buf);");
-    javaWriter.println("  }");
-    javaWriter.println();
-    javaWriter.println("  " + containingJTypeName + "(java.nio.ByteBuffer buf) {");
-    javaWriter.println("    accessor = new StructAccessor(buf);");
-    javaWriter.println("  }");
-    javaWriter.println();
+    // getDelegatedImplementation
+    if( !cfg.manuallyImplement(JavaConfiguration.canonicalStructFieldSymbol(containingJTypeName, "size")) ) {
+        javaWriter.println("  public static int size() {");
+        javaWriter.println("    return "+containingJTypeName+"_size[mdIdx];");
+        javaWriter.println("  }");
+        javaWriter.println();
+    }
+    if( !cfg.manuallyImplement(JavaConfiguration.canonicalStructFieldSymbol(containingJTypeName, "create")) ) {
+        javaWriter.println("  public static " + containingJTypeName + " create() {");
+        javaWriter.println("    return create(Buffers.newDirectByteBuffer(size()));");
+        javaWriter.println("  }");
+        javaWriter.println();
+        javaWriter.println("  public static " + containingJTypeName + " create(java.nio.ByteBuffer buf) {");
+        javaWriter.println("      return new " + containingJTypeName + "(buf);");
+        javaWriter.println("  }");
+        javaWriter.println();
+    }
+    if( !cfg.manuallyImplement(JavaConfiguration.canonicalStructFieldSymbol(containingJTypeName, containingJTypeName)) ) {
+        javaWriter.println("  " + containingJTypeName + "(java.nio.ByteBuffer buf) {");
+        javaWriter.println("    md = MachineDataInfo.StaticConfig.values()[mdIdx].md;");
+        javaWriter.println("    accessor = new StructAccessor(buf);");
+        javaWriter.println("  }");
+        javaWriter.println();
+    }
     javaWriter.println("  public java.nio.ByteBuffer getBuffer() {");
     javaWriter.println("    return accessor.getBuffer();");
     javaWriter.println("  }");
@@ -1063,52 +1201,62 @@ public class JavaEmitter implements GlueEmitter {
       final Field field = structCType.getField(i);
       final Type fieldType = field.getType();
 
-      final String cfgFieldName0 = JavaConfiguration.canonicalStructFieldSymbol(structCTypeName, field.getName());
+      final String cfgFieldName0 = JavaConfiguration.canonicalStructFieldSymbol(containingJTypeName, field.getName());
       if (!cfg.shouldIgnoreInInterface(cfgFieldName0)) {
         final String renamed = cfg.getJavaSymbolRename(cfgFieldName0);
         final String fieldName = renamed==null ? field.getName() : renamed;
-        final String cfgFieldName1 = JavaConfiguration.canonicalStructFieldSymbol(structCTypeName, fieldName);
+        final String cfgFieldName1 = JavaConfiguration.canonicalStructFieldSymbol(containingJTypeName, fieldName);
+        final TypeInfo opaqueFieldType = cfg.typeInfo(fieldType);
+        final boolean isOpaqueFieldType = null != opaqueFieldType;
+        final TypeInfo opaqueField = cfg.canonicalNameOpaque(cfgFieldName1);
+        final boolean isOpaqueField = null != opaqueField;
 
         if( GlueGen.debug() ) {
-          System.err.printf("SE.ac.%02d: %s / %s, %s%n", (i+1), field, cfgFieldName1, fieldType.getDebugString());
+          System.err.printf("SE.ac.%02d: %s / %s (opaque %b), %s (opaque %b)%n", (i+1),
+                  (i+1), field, cfgFieldName1, isOpaqueField, fieldType.getDebugString(), isOpaqueFieldType);
         }
-        if (fieldType.isFunctionPointer()) {
+        if ( fieldType.isFunctionPointer() && !isOpaqueField ) {
+            final FunctionSymbol func = new FunctionSymbol(field.getName(), fieldType.asPointer().getTargetType().asFunction());
+            func.rename(renamed); // null is OK
             generateFunctionPointerCode(methodBindingSet, javaWriter, jniWriter, structCTypeName, structClassPkgName,
                                         containingCType, containingJType, i,
-                                        new FunctionSymbol(fieldName, fieldType.asPointer().getTargetType().asFunction()), cfgFieldName1);
-        } else if (fieldType.isCompound()) {
+                                        func, cfgFieldName1);
+        } else if ( fieldType.isCompound() && !isOpaqueField ) {
           // FIXME: will need to support this at least in order to
           // handle the union in jawt_Win32DrawingSurfaceInfo (fabricate a name?)
           if (fieldType.getName() == null) {
-            throw new RuntimeException("Anonymous structs as fields not supported yet (field \"" +
-                                       field + "\" in type \"" + structCTypeName + "\")");
+            throw new GlueGenException("Anonymous structs as fields not supported yet (field \"" +
+                                       field + "\" in type \"" + structCTypeName + "\")",
+                                       fieldType.getASTLocusTag());
           }
           javaWriter.println();
-          generateGetterSignature(javaWriter, fieldType, false, fieldType.getName(), capitalizeString(fieldName), null, null);
+          generateGetterSignature(javaWriter, fieldType, false, false, fieldType.getName(), fieldName, capitalizeString(fieldName), null, null);
           javaWriter.println(" {");
           javaWriter.println("    return " + fieldType.getName() + ".create( accessor.slice( " +
                            fieldName+"_offset[mdIdx], "+fieldName+"_size[mdIdx] ) );");
           javaWriter.println(" }");
 
-        } else if ( fieldType.isArray() || fieldType.isPointer() ) {
-            generateArrayGetterSetterCode(methodBindingSet, javaWriter, jniWriter, structCTypeName, structClassPkgName,
-                                          containingCType, containingJType,
-                                          i, field, fieldName, cfgFieldName1);
+        } else if ( ( fieldType.isArray() || fieldType.isPointer() ) && !isOpaqueField ) {
+            generateArrayGetterSetterCode(methodBindingSet, javaWriter, jniWriter, structCType, structCTypeName,
+                                          structClassPkgName, containingCType,
+                                          containingJType, i, field, fieldName, cfgFieldName1);
         } else {
           final JavaType javaType;
           try {
             javaType = typeToJavaType(fieldType, machDescJava);
           } catch (final Exception e) {
-            System.err.println("Error occurred while creating accessor for field \"" +
-                               field.getName() + "\", "+fieldType.getDebugString());
-            throw(e);
+            throw new GlueGenException("Error occurred while creating accessor for field \"" +
+                                       field.getName() + "\", "+fieldType.getDebugString(), fieldType.getASTLocusTag(), e);
           }
-          if (javaType.isPrimitive()) {
+          if ( isOpaqueFieldType || isOpaqueField || javaType.isPrimitive()) {
             // Primitive type
             final boolean fieldTypeNativeSizeFixed = fieldType.getSize().hasFixedNativeSize();
             final String javaTypeName;
-            if ( isOpaque(fieldType) ) {
-              javaTypeName = compatiblePrimitiveJavaTypeName(fieldType, javaType, machDescJava);
+            if ( isOpaqueFieldType ) {
+              javaTypeName = opaqueFieldType.javaType().getName();
+            } else if ( isOpaqueField ) {
+              javaTypeName = opaqueField.javaType().getName();
+              // javaTypeName = compatiblePrimitiveJavaTypeName(fieldType, javaType, machDescJava);
             } else {
               javaTypeName = javaType.getName();
             }
@@ -1116,20 +1264,19 @@ public class JavaEmitter implements GlueEmitter {
             final String capFieldName = capitalizeString(fieldName);
             final String sizeDenominator = fieldType.isPointer() ? "pointer" : javaTypeName ;
 
-            if(GlueGen.debug()) {
-                System.err.println("Java.StructEmitter.Primitive: "+field.getName()+", "+fieldType.getDebugString()+", "+javaTypeName+", "+
-                                   ", fixedSize "+fieldTypeNativeSizeFixed+", opaque "+isOpaque(fieldType)+", sizeDenominator "+sizeDenominator);
-            }
+            LOG.log(FINE, structCType.getASTLocusTag(),
+                    "Java.StructEmitter.Primitive: "+field.getName()+", "+fieldType+", "+javaTypeName+", "+
+                    ", fixedSize "+fieldTypeNativeSizeFixed+", opaque[t "+isOpaqueFieldType+", f "+isOpaqueField+"], sizeDenominator "+sizeDenominator);
 
             if( !fieldType.isConst() ) {
                 // Setter
                 javaWriter.println();
-                generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, capFieldName, null, javaTypeName, null, null);
+                generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, fieldName, capFieldName, null, javaTypeName, null, null);
                 javaWriter.println(" {");
                 if( fieldTypeNativeSizeFixed ) {
                     javaWriter.println("    accessor.set" + capJavaTypeName + "At(" + fieldName+"_offset[mdIdx], val);");
                 } else {
-                    javaWriter.println("    accessor.set" + capJavaTypeName + "At(" + fieldName+"_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md."+sizeDenominator+"SizeInBytes());");
+                    javaWriter.println("    accessor.set" + capJavaTypeName + "At(" + fieldName+"_offset[mdIdx], val, md."+sizeDenominator+"SizeInBytes());");
                 }
                 javaWriter.println("    return this;");
                 javaWriter.println("  }");
@@ -1137,13 +1284,13 @@ public class JavaEmitter implements GlueEmitter {
 
             // Getter
             javaWriter.println();
-            generateGetterSignature(javaWriter, fieldType, false, javaTypeName, capFieldName, null, null);
+            generateGetterSignature(javaWriter, fieldType, false, false, javaTypeName, fieldName, capFieldName, null, null);
             javaWriter.println(" {");
             javaWriter.print  ("    return ");
             if( fieldTypeNativeSizeFixed ) {
                 javaWriter.println("accessor.get" + capJavaTypeName + "At(" + fieldName+"_offset[mdIdx]);");
             } else {
-                javaWriter.println("accessor.get" + capJavaTypeName + "At(" + fieldName+"_offset[mdIdx], MachineDescriptionRuntime.getStatic().md."+sizeDenominator+"SizeInBytes());");
+                javaWriter.println("accessor.get" + capJavaTypeName + "At(" + fieldName+"_offset[mdIdx], md."+sizeDenominator+"SizeInBytes());");
             }
             javaWriter.println("  }");
           } else {
@@ -1204,15 +1351,16 @@ public class JavaEmitter implements GlueEmitter {
   // Internals only below this point
   //
 
-  private void generateGetterSignature(final PrintWriter writer, final Type origFieldType, final boolean abstractMethod,
-                                       final String returnTypeName, final String capitalizedFieldName,
-                                       final String customArgs, final String arrayLengthExpr) {
-      writer.print("  /** Getter for native field: "+origFieldType.getDebugString());
+  private void generateGetterSignature(final PrintWriter writer, final Type origFieldType,
+                                       final boolean staticMethod, final boolean abstractMethod,
+                                       final String returnTypeName, final String fieldName,
+                                       final String capitalizedFieldName, final String customArgs, final String arrayLengthExpr) {
+      writer.print("  /** Getter for native field <code>"+fieldName+"</code>: "+origFieldType.getDebugString());
       if( null != arrayLengthExpr ) {
           writer.print(", with array length of <code>"+arrayLengthExpr+"</code>");
       }
       writer.println(" */");
-      writer.print("  public " + (abstractMethod ? "abstract " : "") + returnTypeName + " get" + capitalizedFieldName + "(");
+      writer.print("  public " + (staticMethod ? "static " : "") + (abstractMethod ? "abstract " : "") + returnTypeName + " get" + capitalizedFieldName + "(");
       if( null != customArgs ) {
           writer.print(customArgs);
       }
@@ -1220,10 +1368,10 @@ public class JavaEmitter implements GlueEmitter {
   }
 
   private void generateSetterSignature(final PrintWriter writer, final Type origFieldType, final boolean abstractMethod,
-                                       final String returnTypeName, final String capitalizedFieldName,
-                                       final String customArgsPre, final String paramTypeName, final String customArgsPost,
-                                       final String arrayLengthExpr) {
-      writer.print("  /** Setter for native field: "+origFieldType.getDebugString());
+                                       final String returnTypeName, final String fieldName,
+                                       final String capitalizedFieldName, final String customArgsPre, final String paramTypeName,
+                                       final String customArgsPost, final String arrayLengthExpr) {
+      writer.print("  /** Setter for native field <code>"+fieldName+"</code>: "+origFieldType.getDebugString());
       if( null != arrayLengthExpr ) {
           writer.print(", with array length of <code>"+arrayLengthExpr+"</code>");
       }
@@ -1239,7 +1387,9 @@ public class JavaEmitter implements GlueEmitter {
       writer.print(")");
   }
 
-  private void generateOffsetAndSizeArrays(final PrintWriter writer, final String prefix, final String fieldName, final Type fieldType, final Field field, final String postfix) {
+  private void generateOffsetAndSizeArrays(final PrintWriter writer, final String prefix,
+                                           final String fieldName, final Type fieldType,
+                                           final Field field, final String postfix) {
       if(null != field) {
           writer.print(prefix+"private static final int[] "+fieldName+"_offset = new int[] { ");
           for( int i=0; i < machDescTargetConfigs.length; i++ ) {
@@ -1275,7 +1425,7 @@ public class JavaEmitter implements GlueEmitter {
           final Type containingCType, final JavaType containingJType,
           final int i, final FunctionSymbol funcSym, final String returnSizeLookupName) {
       // Emit method call and associated native code
-      final MethodBinding  mb = bindFunction(funcSym, containingJType, containingCType, machDescJava);
+      final MethodBinding  mb = bindFunction(funcSym, true  /* forInterface */, machDescJava, containingJType, containingCType);
       mb.findThisPointer(); // FIXME: need to provide option to disable this on per-function basis
 
       // JavaTypes representing C pointers in the initial
@@ -1297,16 +1447,17 @@ public class JavaEmitter implements GlueEmitter {
                           javaWriter,
                           cfg.runtimeExceptionType(),
                           cfg.unsupportedExceptionType(),
-                          true,
+                          true,  // emitBody
                           cfg.tagNativeBinding(),
                           false, // eraseBufferAndArrayTypes
                           useNIOOnly,
                           useNIODirectOnly,
-                          false,
-                          false, // FIXME: should unify this with the general emission code
+                          false, // forDirectBufferImplementation
                           false, // forIndirectBufferAndArrayImplementation
-                          false, // FIXME: should unify this with the general emission code
-                          false,
+                          false, // isUnimplemented
+                          false, // isInterface
+                          false, // isNativeMethod
+                          false, // isPrivateNativeMethod
                           cfg);
           emitter.addModifier(JavaMethodBindingEmitter.PUBLIC);
           emitter.emit();
@@ -1317,17 +1468,17 @@ public class JavaEmitter implements GlueEmitter {
                           javaWriter,
                           cfg.runtimeExceptionType(),
                           cfg.unsupportedExceptionType(),
-                          false,
+                          false, // emitBody
                           cfg.tagNativeBinding(),
-                          true, // eraseBufferAndArrayTypes
+                          true,  // eraseBufferAndArrayTypes
                           useNIOOnly,
                           useNIODirectOnly,
-                          true,
-                          true, // FIXME: should unify this with the general emission code
+                          true,  // forDirectBufferImplementation
                           false, // forIndirectBufferAndArrayImplementation
-                          false, // FIXME: should unify this with the general emission code
-                          false,
-                          cfg);
+                          false, // isUnimplemented
+                          false, // isInterface
+                          false,  // isNativeMethod
+                          true, cfg);
           emitter.addModifier(JavaMethodBindingEmitter.PRIVATE);
           emitter.addModifier(JavaMethodBindingEmitter.NATIVE);
           emitter.emit();
@@ -1342,7 +1493,7 @@ public class JavaEmitter implements GlueEmitter {
                           false,
                           true,
                           false, // forIndirectBufferAndArrayImplementation
-                          machDescJava);
+                          machDescJava, getConfiguration());
           cEmitter.setIsCStructFunctionPointer(true);
           prepCEmitter(returnSizeLookupName, binding.getJavaReturnType(), cEmitter);
           cEmitter.emit();
@@ -1356,7 +1507,7 @@ public class JavaEmitter implements GlueEmitter {
           final int i, final FunctionSymbol funcSym,
           final String returnSizeLookupName, final String docArrayLenExpr, final String nativeArrayLenExpr) {
       // Emit method call and associated native code
-      final MethodBinding  mb = bindFunction(funcSym, containingJType, containingCType, machDescJava);
+      final MethodBinding  mb = bindFunction(funcSym, true /* forInterface */, machDescJava, containingJType, containingCType);
       mb.findThisPointer(); // FIXME: need to provide option to disable this on per-function basis
 
       // JavaTypes representing C pointers in the initial
@@ -1379,16 +1530,17 @@ public class JavaEmitter implements GlueEmitter {
                           javaWriter,
                           cfg.runtimeExceptionType(),
                           cfg.unsupportedExceptionType(),
-                          false,
-                          cfg.tagNativeBinding(),
-                          true, // eraseBufferAndArrayTypes
+                          false,                  // emitBody
+                          cfg.tagNativeBinding(), // tagNativeBinding
+                          true,                   // eraseBufferAndArrayTypes
                           useNIOOnly,
                           useNIODirectOnly,
-                          true,
-                          true, // FIXME: should unify this with the general emission code
-                          false, // forIndirectBufferAndArrayImplementation
-                          false, // FIXME: should unify this with the general emission code
-                          false,
+                          false,                  // forDirectBufferImplementation
+                          false,                  // forIndirectBufferAndArrayImplementation
+                          false,                  // isUnimplemented
+                          true,                   // isInterface
+                          true,                   // isNativeMethod
+                          true,                   // isPrivateNativeMethod
                           cfg);
           if( null != docArrayLenExpr ) {
               emitter.setReturnedArrayLengthExpression(docArrayLenExpr, true);
@@ -1407,7 +1559,7 @@ public class JavaEmitter implements GlueEmitter {
                           false,
                           true,
                           false, // forIndirectBufferAndArrayImplementation
-                          machDescJava);
+                          machDescJava, getConfiguration());
           cEmitter.setIsCStructFunctionPointer(false);
           final String lenExprSet;
           if( null != nativeArrayLenExpr ) {
@@ -1457,14 +1609,16 @@ public class JavaEmitter implements GlueEmitter {
       final String cfgVal = cfg.returnedArrayLength(returnSizeLookupName);
       if( null != cfgVal ) {
           if( hasFixedTypeLen[0] ) {
-              System.err.println("WARNING: struct array field '"+returnSizeLookupName+"' of '"+type+"' length '"+Arrays.toString(length)+"' overwritten by cfg-expression: "+cfgVal);
+              LOG.log(WARNING, type.getASTLocusTag(),
+                      "struct array field '"+returnSizeLookupName+"' of '"+type+"' length '"+Arrays.toString(length)+"' overwritten by cfg-expression: "+cfgVal);
           }
           return cfgVal;
       }
       if( hasFixedTypeLen[0] ) {
           return lengthExpr.toString();
       } else {
-          System.err.println("WARNING: struct array field '"+returnSizeLookupName+"' length '"+Arrays.toString(length)+"' without fixed- nor configured-size: "+type.getDebugString());
+          LOG.log(WARNING, type.getASTLocusTag(),
+                  "struct array field '"+returnSizeLookupName+"' length '"+Arrays.toString(length)+"' without fixed- nor configured-size: {0}", type);
           return null;
       }
   }
@@ -1497,16 +1651,18 @@ public class JavaEmitter implements GlueEmitter {
 
   private void generateArrayGetterSetterCode(final Set<MethodBinding> methodBindingSet,
                                              final PrintWriter javaWriter, final PrintWriter jniWriter,
+                                             final CompoundType structCType,
                                              final String structCTypeName, final String structClassPkgName,
                                              final Type containingCType, final JavaType containingJType,
-                                             final int i, final Field field, final String fieldName, final String returnSizeLookupName) throws Exception {
+                                             final int i, final Field field, final String fieldName,
+                                             final String returnSizeLookupName) throws Exception {
       final Type fieldType = field.getType();
       final JavaType javaType;
       try {
         javaType = typeToJavaType(fieldType, machDescJava);
       } catch (final Exception e) {
-        throw new RuntimeException("Error occurred while creating array/pointer accessor for field \"" +
-                                   returnSizeLookupName + "\", "+fieldType.getDebugString(), e);
+        throw new GlueGenException("Error occurred while creating array/pointer accessor for field \"" +
+                                   returnSizeLookupName + "\", "+fieldType.getDebugString(), fieldType.getASTLocusTag(), e);
       }
       if( GlueGen.debug() ) {
           System.err.printf("SE.ac.%02d: javaType  %s%n", (i+1), javaType.getDebugString());
@@ -1520,6 +1676,7 @@ public class JavaEmitter implements GlueEmitter {
       final boolean isString = cfg.returnsString(returnSizeLookupName); // FIXME: Allow custom Charset ? US-ASCII, UTF-8 or UTF-16 ?
       final boolean useGetCStringLength;
       final String arrayLengthExpr;
+      final boolean arrayLengthExprIsConst;
       final int[] arrayLengths;
       final boolean useFixedTypeLen[] = { false };
       final boolean isPointer;
@@ -1538,11 +1695,13 @@ public class JavaEmitter implements GlueEmitter {
           final Type baseCElemType;
           final ArrayType arrayType = fieldType.asArray();
           String _arrayLengthExpr = null;
+          boolean _arrayLengthExprIsConst = false;
           if( isOpaque || javaType.isPrimitive() ) {
               // Overridden by JavaConfiguration.typeInfo(..), i.e. Opaque!
               // Emulating array w/ 1 element
               isPrimitive = true;
               _arrayLengthExpr = nativeArrayLengthONE;
+              _arrayLengthExprIsConst = true;
               arrayLengths = new int[] { 1 };
               baseCElemType = null;
               isPointer = false;
@@ -1555,12 +1714,14 @@ public class JavaEmitter implements GlueEmitter {
               if( null != arrayType ) {
                   final int[][] lengthRes = new int[1][];
                   _arrayLengthExpr = getArrayArrayLengthExpr(arrayType, returnSizeLookupName, useFixedTypeLen, lengthRes);
+                  _arrayLengthExprIsConst = true;
                   arrayLengths = lengthRes[0];
                   baseCElemType = arrayType.getBaseElementType();
                   isPointer = false;
               } else {
                   final PointerType pointerType = fieldType.asPointer();
                   _arrayLengthExpr = getPointerArrayLengthExpr(pointerType, returnSizeLookupName);
+                  _arrayLengthExprIsConst = false;
                   arrayLengths = null;
                   baseCElemType = pointerType.getBaseElementType();
                   isPointer = true;
@@ -1568,7 +1729,7 @@ public class JavaEmitter implements GlueEmitter {
                       javaWriter.println();
                       final String msg = "SKIP ptr-ptr (depth "+pointerType.pointerDepth()+"): "+returnSizeLookupName +": "+fieldType;
                       javaWriter.println("  // "+msg);
-                      System.err.println("WARNING: "+msg);
+                      LOG.log(WARNING, structCType.getASTLocusTag(), msg);
                       return;
                   }
               }
@@ -1580,8 +1741,9 @@ public class JavaEmitter implements GlueEmitter {
               try {
                   baseJElemType = typeToJavaType(baseCElemType, machDescJava);
               } catch (final Exception e ) {
-                  throw new RuntimeException("Error occurred while creating array/pointer accessor for field \"" +
-                                              returnSizeLookupName + "\", baseType "+baseCElemType.getDebugString()+", topType "+fieldType.getDebugString(), e);
+                  throw new GlueGenException("Error occurred while creating array/pointer accessor for field \"" +
+                                              returnSizeLookupName + "\", baseType "+baseCElemType.getDebugString()+", topType "+fieldType.getDebugString(),
+                                              fieldType.getASTLocusTag(), e);
               }
               baseJElemTypeName = baseJElemType.getName();
               baseCElemNativeSizeFixed = baseCElemType.isPrimitive() ? baseCElemType.getSize().hasFixedNativeSize() : true;
@@ -1591,7 +1753,7 @@ public class JavaEmitter implements GlueEmitter {
                   javaWriter.println();
                   final String msg = "SKIP primitive w/ platform dependent sized type in struct: "+returnSizeLookupName+": "+fieldType.getDebugString();
                   javaWriter.println("  // "+msg);
-                  System.err.println("WARNING: "+msg);
+                  LOG.log(WARNING, structCType.getASTLocusTag(), msg);
                   return;
               }
           }
@@ -1605,17 +1767,19 @@ public class JavaEmitter implements GlueEmitter {
           if( null == _arrayLengthExpr && isString && isPointer ) {
               useGetCStringLength = true;
               _arrayLengthExpr = "getCStringLengthImpl(pString)+1";
+              _arrayLengthExprIsConst = false;
               this.requiresStaticInitialization = true;
-              LOG.log(INFO, "StaticInit Trigger.3 \"{0}\"", returnSizeLookupName);
+              LOG.log(INFO, structCType.getASTLocusTag(), "StaticInit Trigger.3 \"{0}\"", returnSizeLookupName);
           } else {
               useGetCStringLength = false;
           }
           arrayLengthExpr = _arrayLengthExpr;
+          arrayLengthExprIsConst = _arrayLengthExprIsConst;
           if( null == arrayLengthExpr ) {
               javaWriter.println();
               final String msg = "SKIP unsized array in struct: "+returnSizeLookupName+": "+fieldType.getDebugString();
               javaWriter.println("  // "+msg);
-              System.err.println("WARNING: "+msg);
+              LOG.log(WARNING, structCType.getASTLocusTag(), msg);
               return;
           }
           boolean _hasSingleElement=false;
@@ -1626,8 +1790,8 @@ public class JavaEmitter implements GlueEmitter {
       }
       if( GlueGen.debug() ) {
           System.err.printf("SE.ac.%02d: baseJElemTypeName %s, array-lengths %s%n", (i+1), baseJElemTypeName, Arrays.toString(arrayLengths));
-          System.err.printf("SE.ac.%02d: arrayLengthExpr: %s, hasSingleElement %b, isByteBuffer %b, isString %b, isPointer %b, isPrimitive %b, isOpaque %b, baseCElemNativeSizeFixed %b, baseCElemSizeDenominator %s, isConst %b, useGetCStringLength %b%n",
-                  (i+1), arrayLengthExpr, hasSingleElement, isByteBuffer, isString, isPointer, isPrimitive, isOpaque,
+          System.err.printf("SE.ac.%02d: arrayLengthExpr: %s (const %b), hasSingleElement %b, isByteBuffer %b, isString %b, isPointer %b, isPrimitive %b, isOpaque %b, baseCElemNativeSizeFixed %b, baseCElemSizeDenominator %s, isConst %b, useGetCStringLength %b%n",
+                  (i+1), arrayLengthExpr, arrayLengthExprIsConst, hasSingleElement, isByteBuffer, isString, isPointer, isPrimitive, isOpaque,
                   baseCElemNativeSizeFixed, baseCElemSizeDenominator,
                   isConst, useGetCStringLength);
       }
@@ -1637,7 +1801,7 @@ public class JavaEmitter implements GlueEmitter {
       //
       if( !hasSingleElement && useFixedTypeLen[0] ) {
           javaWriter.println();
-          generateGetterSignature(javaWriter, fieldType, false, "final int", capitalFieldName+"ArrayLength", null, arrayLengthExpr);
+          generateGetterSignature(javaWriter, fieldType, arrayLengthExprIsConst, false, "final int", fieldName, capitalFieldName+"ArrayLength", null, arrayLengthExpr);
           javaWriter.println(" {");
           javaWriter.println("    return "+arrayLengthExpr+";");
           javaWriter.println("  }");
@@ -1651,21 +1815,21 @@ public class JavaEmitter implements GlueEmitter {
                   // Setter Primitive Pointer
                   final String msg = "SKIP setter for primitive-pointer type in struct: "+returnSizeLookupName+": "+fieldType.getDebugString();
                   javaWriter.println("  // "+msg);
-                  System.err.println("INFO: "+msg);
+                  LOG.log(INFO, structCType.getASTLocusTag(), msg);
               } else {
                   // Setter Primitive Array
                   if( hasSingleElement ) {
-                      generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, capitalFieldName, null, baseJElemTypeName, null, arrayLengthExpr);
+                      generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, fieldName, capitalFieldName, null, baseJElemTypeName, null, arrayLengthExpr);
                       javaWriter.println(" {");
                       if( baseCElemNativeSizeFixed ) {
                           javaWriter.println("    accessor.set" + baseJElemTypeNameC + "At(" + fieldName+"_offset[mdIdx], val);");
                       } else {
-                          javaWriter.println("    accessor.set" + baseJElemTypeNameC + "At(" + fieldName+"_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md."+baseCElemSizeDenominator+"SizeInBytes());");
+                          javaWriter.println("    accessor.set" + baseJElemTypeNameC + "At(" + fieldName+"_offset[mdIdx], val, md."+baseCElemSizeDenominator+"SizeInBytes());");
                       }
                       javaWriter.println("    return this;");
                       javaWriter.println("  }");
                   } else {
-                      generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, capitalFieldName, "final int offset", baseJElemTypeName+"[]", null, arrayLengthExpr);
+                      generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, fieldName, capitalFieldName, "final int offset", baseJElemTypeName+"[]", null, arrayLengthExpr);
                       javaWriter.println(" {");
                       javaWriter.println("    final int arrayLength = "+arrayLengthExpr+";");
                       javaWriter.println("    if( offset + val.length > arrayLength ) { throw new IndexOutOfBoundsException(\"offset \"+offset+\" + val.length \"+val.length+\" > array-length \"+arrayLength); };");
@@ -1688,11 +1852,11 @@ public class JavaEmitter implements GlueEmitter {
                   // Setter Struct Pointer
                   final String msg = "SKIP setter for complex-pointer type in struct: "+returnSizeLookupName+": "+fieldType.getDebugString();
                   javaWriter.println("  // "+msg);
-                  System.err.println("INFO: "+msg);
+                  LOG.log(INFO, structCType.getASTLocusTag(), msg);
               } else {
                   // Setter Struct Array
                   if( hasSingleElement ) {
-                      generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, capitalFieldName, null, baseJElemTypeName, null, arrayLengthExpr);
+                      generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, fieldName, capitalFieldName, null, baseJElemTypeName, null, arrayLengthExpr);
                       javaWriter.println(" {");
                       javaWriter.println("    final int elemSize = "+baseJElemTypeName+".size();");
                       javaWriter.println("    final ByteBuffer destB = getBuffer();");
@@ -1708,7 +1872,7 @@ public class JavaEmitter implements GlueEmitter {
                       javaWriter.println("    return this;");
                       javaWriter.println("  }");
                   } else {
-                      generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, capitalFieldName, "final int offset", baseJElemTypeName+"[]", null, arrayLengthExpr);
+                      generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, fieldName, capitalFieldName, "final int offset", baseJElemTypeName+"[]", null, arrayLengthExpr);
                       javaWriter.println(" {");
                       javaWriter.println("    final int arrayLength = "+arrayLengthExpr+";");
                       javaWriter.println("    if( offset + val.length > arrayLength ) { throw new IndexOutOfBoundsException(\"offset \"+offset+\" + val.length \"+val.length+\" > array-length \"+arrayLength); };");
@@ -1730,7 +1894,7 @@ public class JavaEmitter implements GlueEmitter {
                       javaWriter.println("    return this;");
                       javaWriter.println("  }");
                       javaWriter.println();
-                      generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, capitalFieldName, "final int index", baseJElemTypeName, null, arrayLengthExpr);
+                      generateSetterSignature(javaWriter, fieldType, false, containingJTypeName, fieldName, capitalFieldName, "final int index", baseJElemTypeName, null, arrayLengthExpr);
                       javaWriter.println(" {");
                       javaWriter.println("    final int arrayLength = "+arrayLengthExpr+";");
                       javaWriter.println("    final int elemSize = "+baseJElemTypeName+".size();");
@@ -1759,12 +1923,12 @@ public class JavaEmitter implements GlueEmitter {
           if( isPointer ) {
               // Getter Primitive Pointer
               final FunctionType ft = new FunctionType(dummyFuncTypeName, SizeThunk.POINTER, fieldType, 0);
-              ft.addArgument(containingCType.getCVVariant(containingCType.getCVAttributes() | CVAttributes.CONST),
+              ft.addArgument(containingCType.newCVVariant(containingCType.getCVAttributes() | CVAttributes.CONST),
                              CMethodBindingEmitter.cThisArgumentName());
               ft.addArgument(int32Type, nativeArrayLengthArg);
               final FunctionSymbol fs = new FunctionSymbol("get"+capitalFieldName, ft);
               jniWriter.println();
-              jniWriter.print("static "+fs.toString());
+              jniWriter.print("static "+fs.toString(false));
               jniWriter.println("{");
               jniWriter.println("  return "+CMethodBindingEmitter.cThisArgumentName()+"->"+field.getName()+";");
               jniWriter.println("}");
@@ -1772,7 +1936,7 @@ public class JavaEmitter implements GlueEmitter {
               generateArrayPointerCode(methodBindingSet, javaWriter, jniWriter, structCTypeName, structClassPkgName,
                                        containingCType, containingJType, i, fs, returnSizeLookupName, arrayLengthExpr, nativeArrayLengthArg);
               javaWriter.println();
-              generateGetterSignature(javaWriter, fieldType, false, baseJElemTypeNameC+"Buffer", capitalFieldName, null, arrayLengthExpr);
+              generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeNameC+"Buffer", fieldName, capitalFieldName, null, arrayLengthExpr);
               javaWriter.println(" {");
               if( useGetCStringLength ) {
                   javaWriter.println("    final int arrayLength = get"+capitalFieldName+"ArrayLength();");
@@ -1789,7 +1953,7 @@ public class JavaEmitter implements GlueEmitter {
               javaWriter.println("  }");
               if( isString && isByteBuffer ) {
                   javaWriter.println();
-                  generateGetterSignature(javaWriter, fieldType, false, "String", capitalFieldName+"AsString", null, arrayLengthExpr);
+                  generateGetterSignature(javaWriter, fieldType, false, false, "String", fieldName, capitalFieldName+"AsString", null, arrayLengthExpr);
                   javaWriter.println(" {");
                   if( useGetCStringLength ) {
                       javaWriter.println("    final int arrayLength = get"+capitalFieldName+"ArrayLength();");
@@ -1809,7 +1973,7 @@ public class JavaEmitter implements GlueEmitter {
               }
               if( useGetCStringLength ) {
                   javaWriter.println();
-                  generateGetterSignature(javaWriter, fieldType, false, "final int", capitalFieldName+"ArrayLength", null, arrayLengthExpr);
+                  generateGetterSignature(javaWriter, fieldType, false, false, "final int", fieldName, capitalFieldName+"ArrayLength", null, arrayLengthExpr);
                   javaWriter.println(" {");
                   javaWriter.println("    final long pString = PointerBuffer.wrap( accessor.slice(" + fieldName+"_offset[mdIdx],  PointerBuffer.ELEMENT_SIZE) ).get(0);");
                   javaWriter.println("    return "+arrayLengthExpr+";");
@@ -1818,17 +1982,17 @@ public class JavaEmitter implements GlueEmitter {
           } else {
               // Getter Primitive Array
               if( hasSingleElement ) {
-                  generateGetterSignature(javaWriter, fieldType, false, baseJElemTypeName, capitalFieldName, null, arrayLengthExpr);
+                  generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeName, fieldName, capitalFieldName, null, arrayLengthExpr);
                   javaWriter.println(" {");
                   if( baseCElemNativeSizeFixed ) {
                       javaWriter.println("    return accessor.get" + baseJElemTypeNameC + "At(" + fieldName+"_offset[mdIdx]);");
                   } else {
-                      javaWriter.println("    return accessor.get" + baseJElemTypeNameC + "At(" + fieldName+"_offset[mdIdx], MachineDescriptionRuntime.getStatic().md."+baseCElemSizeDenominator+"SizeInBytes());");
+                      javaWriter.println("    return accessor.get" + baseJElemTypeNameC + "At(" + fieldName+"_offset[mdIdx], md."+baseCElemSizeDenominator+"SizeInBytes());");
                   }
                   javaWriter.println("  }");
                   javaWriter.println();
               } else {
-                  generateGetterSignature(javaWriter, fieldType, false, baseJElemTypeNameC+"Buffer", capitalFieldName, null, arrayLengthExpr);
+                  generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeNameC+"Buffer", fieldName, capitalFieldName, null, arrayLengthExpr);
                   javaWriter.println(" {");
                   javaWriter.print("    return accessor.slice(" + fieldName+"_offset[mdIdx],  Buffers.SIZEOF_"+baseJElemTypeNameU+" * "+arrayLengthExpr+")");
                   if( !isByteBuffer ) {
@@ -1838,7 +2002,7 @@ public class JavaEmitter implements GlueEmitter {
                   javaWriter.println("  }");
                   javaWriter.println();
                   if( isString && isByteBuffer ) {
-                      generateGetterSignature(javaWriter, fieldType, false, "String", capitalFieldName+"AsString", null, arrayLengthExpr);
+                      generateGetterSignature(javaWriter, fieldType, false, false, "String", fieldName, capitalFieldName+"AsString", null, arrayLengthExpr);
                       javaWriter.println(" {");
                       javaWriter.println("    final int offset = " + fieldName+"_offset[mdIdx];");
                       javaWriter.println("    final int arrayLength = "+arrayLengthExpr+";");
@@ -1852,7 +2016,7 @@ public class JavaEmitter implements GlueEmitter {
                       javaWriter.println("    return new String(ba, 0, i);");
                       javaWriter.println("  }");
                   } else {
-                      generateGetterSignature(javaWriter, fieldType, false, baseJElemTypeName+"[]", capitalFieldName, "final int offset, "+baseJElemTypeName+" result[]", arrayLengthExpr);
+                      generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeName+"[]", fieldName, capitalFieldName, "final int offset, "+baseJElemTypeName+" result[]", arrayLengthExpr);
                       javaWriter.println(" {");
                       javaWriter.println("    final int arrayLength = "+arrayLengthExpr+";");
                       javaWriter.println("    if( offset + result.length > arrayLength ) { throw new IndexOutOfBoundsException(\"offset \"+offset+\" + result.length \"+result.length+\" > array-length \"+arrayLength); };");
@@ -1867,12 +2031,12 @@ public class JavaEmitter implements GlueEmitter {
           if( isPointer ) {
               // Getter Struct Pointer
               final FunctionType ft = new FunctionType(dummyFuncTypeName, SizeThunk.POINTER, fieldType, 0);
-              ft.addArgument(containingCType.getCVVariant(containingCType.getCVAttributes() | CVAttributes.CONST),
+              ft.addArgument(containingCType.newCVVariant(containingCType.getCVAttributes() | CVAttributes.CONST),
                              CMethodBindingEmitter.cThisArgumentName());
               ft.addArgument(int32Type, nativeArrayElemOffsetArg);
               final FunctionSymbol fs = new FunctionSymbol("get"+capitalFieldName, ft);
               jniWriter.println();
-              jniWriter.print("static "+fs.toString());
+              jniWriter.print("static "+fs.toString(false));
               jniWriter.println("{");
               jniWriter.println("  return "+CMethodBindingEmitter.cThisArgumentName()+"->"+field.getName()+"+"+nativeArrayElemOffsetArg+";");
               jniWriter.println("}");
@@ -1881,7 +2045,7 @@ public class JavaEmitter implements GlueEmitter {
                                        containingCType, containingJType, i, fs, returnSizeLookupName, arrayLengthExpr, nativeArrayLengthONE);
               javaWriter.println();
               if( hasSingleElement ) {
-                  generateGetterSignature(javaWriter, fieldType, false, baseJElemTypeName, capitalFieldName, null, arrayLengthExpr);
+                  generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeName, fieldName, capitalFieldName, null, arrayLengthExpr);
                   javaWriter.println(" {");
                   javaWriter.println("    final ByteBuffer source = getBuffer();");
                   javaWriter.println("    final ByteBuffer _res = get"+capitalFieldName+"0(source, 0);");
@@ -1889,7 +2053,7 @@ public class JavaEmitter implements GlueEmitter {
                   javaWriter.println("    return "+baseJElemTypeName+".create(_res);");
                   javaWriter.println("  }");
               } else {
-                  generateGetterSignature(javaWriter, fieldType, false, baseJElemTypeName+"[]", capitalFieldName, "final int offset, "+baseJElemTypeName+" result[]", arrayLengthExpr);
+                  generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeName+"[]", fieldName, capitalFieldName, "final int offset, "+baseJElemTypeName+" result[]", arrayLengthExpr);
                   javaWriter.println(" {");
                   javaWriter.println("    final int arrayLength = "+arrayLengthExpr+";");
                   javaWriter.println("    if( offset + result.length > arrayLength ) { throw new IndexOutOfBoundsException(\"offset \"+offset+\" + result.length \"+result.length+\" > array-length \"+arrayLength); };");
@@ -1905,12 +2069,12 @@ public class JavaEmitter implements GlueEmitter {
           } else {
               // Getter Struct Array
               if( hasSingleElement ) {
-                  generateGetterSignature(javaWriter, fieldType, false, baseJElemTypeName, capitalFieldName, null, arrayLengthExpr);
+                  generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeName, fieldName, capitalFieldName, null, arrayLengthExpr);
                   javaWriter.println(" {");
                   javaWriter.println("    return "+baseJElemTypeName+".create(accessor.slice("+fieldName+"_offset[mdIdx], "+baseJElemTypeName+".size()));");
                   javaWriter.println("  }");
               } else {
-                  generateGetterSignature(javaWriter, fieldType, false, baseJElemTypeName+"[]", capitalFieldName, "final int offset, "+baseJElemTypeName+" result[]", arrayLengthExpr);
+                  generateGetterSignature(javaWriter, fieldType, false, false, baseJElemTypeName+"[]", fieldName, capitalFieldName, "final int offset, "+baseJElemTypeName+" result[]", arrayLengthExpr);
                   javaWriter.println(" {");
                   javaWriter.println("    final int arrayLength = "+arrayLengthExpr+";");
                   javaWriter.println("    if( offset + result.length > arrayLength ) { throw new IndexOutOfBoundsException(\"offset \"+offset+\" + result.length \"+result.length+\" > array-length \"+arrayLength); };");
@@ -1927,12 +2091,9 @@ public class JavaEmitter implements GlueEmitter {
       }
   }
 
-  private static final boolean DEBUG_TYPEC2JAVA = false;
-  private JavaType typeToJavaType(final Type cType, final MachineDescription curMachDesc) {
+  private JavaType typeToJavaType(final Type cType, final MachineDataInfo curMachDesc) {
       final JavaType jt = typeToJavaTypeImpl(cType, curMachDesc);
-      if( DEBUG_TYPEC2JAVA ) {
-          System.err.println("typeToJavaType: "+cType.getDebugString()+" -> "+jt.getDebugString());
-      }
+      LOG.log(FINE, cType.getASTLocusTag(), "typeToJavaType: {0} -> {1}", cType, jt);
       return jt;
   }
   private boolean isJNIEnvPointer(final Type cType) {
@@ -1941,14 +2102,14 @@ public class JavaEmitter implements GlueEmitter {
            (opt.getTargetType().getName() != null) &&
            (opt.getTargetType().getName().equals("JNIEnv"));
   }
-  private JavaType typeToJavaTypeImpl(final Type cType, final MachineDescription curMachDesc) {
+  private JavaType typeToJavaTypeImpl(final Type cType, final MachineDataInfo curMachDesc) {
     // Recognize JNIEnv* case up front
     if( isJNIEnvPointer(cType) ) {
         return JavaType.createForJNIEnv();
     }
     // Opaque specifications override automatic conversions
     // in case the identity is being used .. not if ptr-ptr
-    final TypeInfo info = cfg.typeInfo(cType, typedefDictionary);
+    final TypeInfo info = cfg.typeInfo(cType);
     if (info != null) {
       boolean isPointerPointer = false;
       if (cType.pointerDepth() > 0 || cType.arrayDimension() > 0) {
@@ -1966,16 +2127,16 @@ public class JavaEmitter implements GlueEmitter {
           // target type)
           if (targetType.isPointer()) {
             isPointerPointer = true;
-
-            // t is<type>**, targetType is <type>*, we need to get <type>
-            final Type bottomType = targetType.asPointer().getTargetType();
             if( GlueGen.debug() ) {
-                LOG.log(INFO, "Opaque Type: {0}, targetType: {1}, bottomType: {2} is ptr-ptr", new Object[]{cType.getDebugString(), targetType, bottomType});
+                // t is<type>**, targetType is <type>*, we need to get <type>
+                final Type bottomType = targetType.asPointer().getTargetType();
+                LOG.log(INFO, cType.getASTLocusTag(), "Opaque Type: {0}, targetType: {1}, bottomType: {2} is ptr-ptr",
+                        cType, targetType, bottomType);
             }
           }
         }
       }
-      if(!isPointerPointer) {
+      if( !isPointerPointer ) {
           return info.javaType();
       }
     }
@@ -1986,8 +2147,9 @@ public class JavaEmitter implements GlueEmitter {
        case 2:  return javaType(Short.TYPE);
        case 4:  return javaType(Integer.TYPE);
        case 8:  return javaType(Long.TYPE);
-       default: throw new RuntimeException("Unknown integer type of size " +
-                                           cType.getSize(curMachDesc) + " and name " + cType.getName());
+       default: throw new GlueGenException("Unknown integer type of size " +
+                                           cType.getSize(curMachDesc) + " and name " + cType.getName(),
+                                           cType.getASTLocusTag());
       }
     } else if (cType.isFloat()) {
       return javaType(Float.TYPE);
@@ -2022,8 +2184,9 @@ public class JavaEmitter implements GlueEmitter {
               case 2:  return JavaType.createForCShortPointer();
               case 4:  return JavaType.createForCInt32Pointer();
               case 8:  return JavaType.createForCInt64Pointer();
-              default: throw new RuntimeException("Unknown integer array type of size " +
-                                                  cType.getSize(curMachDesc) + " and name " + cType.getName()+", "+cType.getDebugString());
+              default: throw new GlueGenException("Unknown integer array type of size " +
+                                                  cType.getSize(curMachDesc) + " and name " + cType.getName()+", "+cType.getDebugString(),
+                                                  cType.getASTLocusTag());
             }
           } else if (targetType.isFloat()) {
             return JavaType.createForCFloatPointer();
@@ -2038,19 +2201,28 @@ public class JavaEmitter implements GlueEmitter {
                 cType.getName().equals("jobject")) {
               return javaType(java.lang.Object.class);
             }
-            String name = targetType.getName();
-            if (name == null) {
-              // Try containing pointer type for any typedefs
-              name = cType.getName();
-              if (name == null) {
-                throw new RuntimeException("Couldn't find a proper type name for pointer type " + cType.getDebugString());
-              }
+            // NOTE: Struct Name Resolution (JavaEmitter, HeaderParser)
+            String name;
+            if( !targetType.isTypedef() && cType.isTypedef() ) {
+                // If compound is not a typedef _and_ containing pointer is typedef, use the latter.
+                name = cType.getName();
+            } else {
+                // .. otherwise try compound name
+                name = targetType.getName();
+                if( null == name ) {
+                  // .. fall back to pointer type name
+                  name = cType.getName();
+                  if (name == null) {
+                    throw new GlueGenException("Couldn't find a proper type name for pointer type " + cType.getDebugString(),
+                                                cType.getASTLocusTag());
+                  }
+                }
             }
-
             return JavaType.createForCStruct(cfg.renameJavaType(name));
           } else {
-            throw new RuntimeException("Don't know how to convert pointer/array type \"" +
-                                       cType.getDebugString() + "\"");
+            throw new GlueGenException("Don't know how to convert pointer/array type \"" +
+                                       cType.getDebugString() + "\"",
+                                       cType.getASTLocusTag());
           }
         }
         // Handle Types of form pointer-to-pointer-to-type or
@@ -2064,19 +2236,22 @@ public class JavaEmitter implements GlueEmitter {
             // t is<type>**, targetType is <type>*, we need to get <type>
             bottomType = targetType.asPointer().getTargetType();
             if( GlueGen.debug() ) {
-                LOG.log(INFO, "typeToJavaType(ptr-ptr): {0}, targetType: {1}, bottomType: {2}", new Object[]{cType.getDebugString(), targetType, bottomType});
+                LOG.log(INFO, cType.getASTLocusTag(), "typeToJavaType(ptr-ptr): {0}, targetType: {1}, bottomType: {2}",
+                        cType.getDebugString(), targetType, bottomType);
             }
             return JavaType.forNIOPointerBufferClass();
           } else if(targetType.isArray()) {
             // t is<type>[][], targetType is <type>[], we need to get <type>
             bottomType = targetType.asArray().getBaseElementType();
             if( GlueGen.debug() ) {
-                LOG.log(INFO, "typeToJavaType(ptr-ptr.array): {0}, targetType: {1}, bottomType: {2}", new Object[]{cType.getDebugString(), targetType, bottomType});
+                LOG.log(INFO, cType.getASTLocusTag(), "typeToJavaType(ptr-ptr.array): {0}, targetType: {1}, bottomType: {2}",
+                        cType.getDebugString(), targetType, bottomType);
             }
           } else {
             bottomType = targetType;
             if( GlueGen.debug() ) {
-                LOG.log(INFO, "typeToJavaType(ptr-ptr.primitive): {0}, targetType: {1}, bottomType: {2}", new Object[]{cType.getDebugString(), targetType, bottomType});
+                LOG.log(INFO, cType.getASTLocusTag(), "typeToJavaType(ptr-ptr.primitive): {0}, targetType: {1}, bottomType: {2}",
+                        cType.getDebugString(), targetType, bottomType);
             }
           }
 
@@ -2090,16 +2265,17 @@ public class JavaEmitter implements GlueEmitter {
                 case 2: return javaType(ArrayTypes.shortBufferArrayClass);
                 case 4: return javaType(ArrayTypes.intBufferArrayClass);
                 case 8: return javaType(ArrayTypes.longBufferArrayClass);
-                default: throw new RuntimeException("Unknown two-dimensional integer array type of element size " +
-                                                    bottomType.getSize(curMachDesc) + " and name " + bottomType.getName()+", "+bottomType.getDebugString());
+                default: throw new GlueGenException("Unknown two-dimensional integer array type of element size " +
+                                                    bottomType.getSize(curMachDesc) + " and name " + bottomType.getName()+", "+bottomType.getDebugString(),
+                                                    bottomType.getASTLocusTag());
               }
             } else if (bottomType.isFloat()) {
               return javaType(ArrayTypes.floatBufferArrayClass);
             } else if (bottomType.isDouble()) {
               return javaType(ArrayTypes.doubleBufferArrayClass);
             } else {
-              throw new RuntimeException("Unexpected primitive type " + bottomType.getDebugString() +
-                                         " in two-dimensional array");
+              throw new GlueGenException("Unexpected primitive type " + bottomType.getDebugString() +
+                                         " in two-dimensional array", bottomType.getASTLocusTag());
             }
           } else if (bottomType.isVoid()) {
             return javaType(ArrayTypes.bufferArrayClass);
@@ -2108,32 +2284,38 @@ public class JavaEmitter implements GlueEmitter {
             // Array of pointers; convert as array of StructAccessors
             return JavaType.createForCArray(bottomType);
           } else {
-            throw new RuntimeException(
+            throw new GlueGenException(
               "Could not convert C type \"" + cType.getDebugString() + "\" " +
               "to appropriate Java type; need to add more support for " +
               "depth=2 pointer/array types [debug info: targetType=\"" +
-              targetType + "\"]");
+              targetType + "\"]", cType.getASTLocusTag());
           }
         } else {
           // can't handle this type of pointer/array argument
-          throw new RuntimeException(
+          throw new GlueGenException(
             "Could not convert C pointer/array \"" + cType.getDebugString() + "\" to " +
             "appropriate Java type; types with pointer/array depth " +
             "greater than 2 are not yet supported [debug info: " +
             "pointerDepth=" + cType.pointerDepth() + " arrayDimension=" +
-            cType.arrayDimension() + " targetType=\"" + targetType + "\"]");
+            cType.arrayDimension() + " targetType=\"" + targetType + "\"]",
+            cType.getASTLocusTag());
         }
 
-    } else if(cType.isCompound() ) { // FIXME: Compound and Compound-Arrays
-        final String name = cType.getName();
+    } else if( cType.isCompound() ) { // FIXME: Compound and Compound-Arrays
+        String name = cType.getName();
         if (name == null) {
-          throw new RuntimeException("Couldn't find a proper type name for pointer type " + cType.getDebugString());
+          name = cType.asCompound().getStructName();
+          if (name == null) {
+              throw new GlueGenException("Couldn't find a proper type name for pointer type " + cType.getDebugString(),
+                                         cType.getASTLocusTag());
+          }
         }
         return JavaType.createForCStruct(cfg.renameJavaType(name));
     } else {
-        throw new RuntimeException(
+        throw new GlueGenException(
           "Could not convert C type \"" + cType.getDebugString() + "\" (class " +
-          cType.getClass().getName() + ") to appropriate Java type");
+          cType.getClass().getName() + ") to appropriate Java type",
+          cType.getASTLocusTag());
     }
   }
 
@@ -2169,23 +2351,25 @@ public class JavaEmitter implements GlueEmitter {
   }
 
   private boolean isOpaque(final Type type) {
-    return (cfg.typeInfo(type, typedefDictionary) != null);
+    return null != cfg.typeInfo(type);
   }
 
   private String compatiblePrimitiveJavaTypeName(final Type fieldType,
                                                  final JavaType javaType,
-                                                 final MachineDescription curMachDesc) {
+                                                 final MachineDataInfo curMachDesc) {
     final Class<?> c = javaType.getJavaClass();
     if (!isIntegerType(c)) {
       // FIXME
-      throw new RuntimeException("Can't yet handle opaque definitions of structs' fields to non-integer types (byte, short, int, long, etc.): type: "+fieldType+", javaType "+javaType+", javaClass "+c);
+      throw new GlueGenException("Can't yet handle opaque definitions of structs' fields to non-integer types (byte, short, int, long, etc.): type: "+fieldType+", javaType "+javaType+", javaClass "+c,
+                                 fieldType.getASTLocusTag());
     }
     switch ((int) fieldType.getSize(curMachDesc)) {
       case 1:  return "byte";
       case 2:  return "short";
       case 4:  return "int";
       case 8:  return "long";
-      default: throw new RuntimeException("Can't handle opaque definitions if the starting type isn't compatible with integral types");
+      default: throw new GlueGenException("Can't handle opaque definitions if the starting type isn't compatible with integral types",
+                                          fieldType.getASTLocusTag());
     }
   }
 
@@ -2209,13 +2393,16 @@ public class JavaEmitter implements GlueEmitter {
     }
 
     if (cfg.allStatic() || cfg.emitInterface()) {
-      javaWriter = openFile(jRoot + File.separator + cfg.className() + ".java", cfg.className());
+      javaFileName = jRoot + File.separator + cfg.className() + ".java";
+      javaWriter = openFile(javaFileName, cfg.className());
     }
     if (!cfg.allStatic() && cfg.emitImpl()) {
-      javaImplWriter = openFile(jImplRoot + File.separator + cfg.implClassName() + ".java", cfg.implClassName());
+      javaFileName = jImplRoot + File.separator + cfg.implClassName() + ".java";
+      javaImplWriter = openFile(javaFileName, cfg.implClassName());
     }
     if (cfg.emitImpl()) {
-      cWriter = openFile(nRoot + File.separator + cfg.implClassName() + "_JNI.c", cfg.implClassName());
+      cFileName = nRoot + File.separator + cfg.implClassName() + "_JNI.c";
+      cWriter = openFile(cFileName, cfg.implClassName());
     }
 
     if (javaWriter != null) {
@@ -2229,6 +2416,9 @@ public class JavaEmitter implements GlueEmitter {
     }
   }
 
+  /** For {@link #javaWriter} or {@link #javaImplWriter} */
+  protected String javaFileName() { return javaFileName; }
+
   protected PrintWriter javaWriter() {
     if (!cfg.allStatic() && !cfg.emitInterface()) {
       throw new InternalError("Should not call this");
@@ -2243,6 +2433,9 @@ public class JavaEmitter implements GlueEmitter {
     return javaImplWriter;
   }
 
+  /** For {@link #cImplWriter} */
+  protected String cFileName() { return cFileName; }
+
   protected PrintWriter cWriter() {
     if (!cfg.emitImpl()) {
       throw new InternalError("Should not call this");
@@ -2311,6 +2504,23 @@ public class JavaEmitter implements GlueEmitter {
     writer.println("  // ---- End CustomJavaCode .cfg declarations");
   }
 
+  public String[] getClassAccessModifiers(final String classFQName) {
+      String[] accessModifiers;
+      final MethodAccess acc = cfg.accessControl(classFQName);
+      if( PUBLIC_ABSTRACT == acc ) {
+          accessModifiers = new String[] { PUBLIC.getJavaName(), PUBLIC_ABSTRACT.getJavaName() };
+      } else if( PACKAGE_PRIVATE == acc ) {
+          accessModifiers = new String[] { PACKAGE_PRIVATE.getJavaName() };
+      } else if( PRIVATE == acc ) {
+          throw new IllegalArgumentException("Class access "+classFQName+" cannot be private");
+      } else if( PROTECTED == acc ) {
+          accessModifiers = new String[] { PROTECTED.getJavaName() };
+      } else { // default PUBLIC
+          accessModifiers = new String[] { PUBLIC.getJavaName() };
+      }
+      return accessModifiers;
+  }
+
   /**
    * Write out any header information for the output files (class declaration
    * and opening brace, import statements, etc).
@@ -2346,13 +2556,7 @@ public class JavaEmitter implements GlueEmitter {
             }
           };
 
-        String[] accessModifiers = null;
-        if(cfg.accessControl(cfg.className()) == PUBLIC_ABSTRACT) {
-            accessModifiers = new String[] { "public", "abstract" };
-        } else {
-            accessModifiers = new String[] { "public" };
-        }
-
+        final String[] accessModifiers = getClassAccessModifiers(cfg.className());
         CodeGenUtils.emitJavaHeaders(
           javaWriter,
           cfg.packageName(),
@@ -2390,13 +2594,7 @@ public class JavaEmitter implements GlueEmitter {
           interfaces[userSpecifiedInterfaces.size()] = cfg.className();
         }
 
-        String[] accessModifiers = null;
-        if(cfg.accessControl(cfg.implClassName()) == PUBLIC_ABSTRACT) {
-            accessModifiers = new String[] { "public", "abstract" };
-        } else {
-            accessModifiers = new String[] { "public" };
-        }
-
+        final String[] accessModifiers = getClassAccessModifiers(cfg.implClassName());
         CodeGenUtils.emitJavaHeaders(
           javaImplWriter,
           cfg.implPackageName(),
@@ -2555,36 +2753,46 @@ public class JavaEmitter implements GlueEmitter {
       potentially representing C pointers rather than true Java types)
       and must be lowered to concrete Java types before creating
       emitters for them. */
-  private MethodBinding bindFunction(final FunctionSymbol sym,
-                                     final JavaType containingType,
-                                     final Type containingCType,
-                                     final MachineDescription curMachDesc) {
-
-    final MethodBinding binding = new MethodBinding(sym, containingType, containingCType);
-
-    binding.renameMethodName(cfg.getJavaSymbolRename(sym.getName()));
-
-    // System.out.println("bindFunction(0) "+sym.getReturnType());
-
-    if (cfg.returnsString(binding.getName())) {
+  private MethodBinding bindFunction(FunctionSymbol sym,
+                                     final boolean forInterface,
+                                     final MachineDataInfo curMachDesc,
+                                     final JavaType containingType, final Type containingCType) {
+
+    final String delegationImplName = null == containingType && null == containingCType ?
+                                      cfg.getDelegatedImplementation(sym) : null;
+    if( !forInterface && null != delegationImplName ) {
+        // We need to reflect the 'delegationImplName' for implementations
+        // to allow all subsequent type/cfg checks to hit on AliasedSymbol!
+        sym = FunctionSymbol.cloneWithDeepAliases(sym);
+        sym.addAliasedName(delegationImplName);
+    }
+    final String name = sym.getName();
+    final JavaType javaReturnType;
+
+    if (cfg.returnsString(sym)) {
       final PointerType prt = sym.getReturnType().asPointer();
       if (prt == null ||
           prt.getTargetType().asInt() == null ||
           prt.getTargetType().getSize(curMachDesc) != 1) {
-        throw new RuntimeException(
+        throw new GlueGenException(
           "Cannot apply ReturnsString configuration directive to \"" + sym +
-          "\". ReturnsString requires native method to have return type \"char *\"");
+          "\". ReturnsString requires native method to have return type \"char *\"",
+          sym.getASTLocusTag());
       }
-      binding.setJavaReturnType(javaType(java.lang.String.class));
+      javaReturnType = javaType(java.lang.String.class);
     } else {
-      binding.setJavaReturnType(typeToJavaType(sym.getReturnType(), curMachDesc));
+      final JavaType r = cfg.getOpaqueReturnType(sym);
+      if( null != r ) {
+          javaReturnType = r;
+      } else {
+          javaReturnType = typeToJavaType(sym.getReturnType(), curMachDesc);
+      }
     }
 
-    // System.out.println("bindFunction(1) "+binding.getJavaReturnType());
-
     // List of the indices of the arguments in this function that should be
     // converted from byte[] or short[] to String
-    final List<Integer> stringArgIndices = cfg.stringArguments(binding.getName());
+    final List<JavaType> javaArgumentTypes = new ArrayList<JavaType>();
+    final List<Integer> stringArgIndices = cfg.stringArguments(name);
 
     for (int i = 0; i < sym.getNumArguments(); i++) {
       final Type cArgType = sym.getArgumentType(i);
@@ -2612,20 +2820,21 @@ public class JavaEmitter implements GlueEmitter {
           }
         }
         else {
-        throw new RuntimeException(
+        throw new GlueGenException(
           "Cannot apply ArgumentIsString configuration directive to " +
           "argument " + i + " of \"" + sym + "\": argument type is not " +
-          "a \"void*\", \"char *\", \"short *\", \"char**\", or \"short**\" equivalent");
+          "a \"void*\", \"char *\", \"short *\", \"char**\", or \"short**\" equivalent",
+          sym.getASTLocusTag());
         }
       }
-      binding.addJavaArgumentType(mappedType);
+      javaArgumentTypes.add(mappedType);
       //System.out.println("During binding of [" + sym + "], added mapping from C type: " + cArgType + " to Java type: " + mappedType);
     }
-
-    // System.out.println("---> " + binding);
-    // System.out.println("    ---> " + binding.getCSymbol());
-    // System.out.println("bindFunction(3) "+binding);
-    return binding;
+    final MethodBinding mb = new MethodBinding(sym, delegationImplName,
+                                               javaReturnType, javaArgumentTypes,
+                                               containingType, containingCType);
+    mangleBinding(mb);
+    return mb;
   }
 
   private MethodBinding lowerMethodBindingPointerTypes(final MethodBinding inputBinding,
@@ -2685,7 +2894,7 @@ public class JavaEmitter implements GlueEmitter {
             result = result.replaceJavaArgumentType(i, JavaType.forNIODoubleBufferClass());
           }
         } else {
-          throw new RuntimeException("Unknown C pointer type " + t);
+          throw new GlueGenException("Unknown C pointer type " + t);
         }
       }
     }
@@ -2710,7 +2919,7 @@ public class JavaEmitter implements GlueEmitter {
       } else if (t.isCDoublePointerType()) {
         result = result.replaceJavaArgumentType(-1, JavaType.forNIODoubleBufferClass());
       } else {
-        throw new RuntimeException("Unknown C pointer type " + t);
+        throw new GlueGenException("Unknown C pointer type " + t, result.getCReturnType().getASTLocusTag());
       }
     }
 
@@ -2723,6 +2932,14 @@ public class JavaEmitter implements GlueEmitter {
     return result;
   }
 
+  /**
+   * Allow specializations to modify the given {@link MethodBinding}
+   * before {@link #expandMethodBinding(MethodBinding) expanding} and emission.
+   */
+  protected void mangleBinding(final MethodBinding binding) {
+      // NOP
+  }
+
   // Expands a MethodBinding containing C primitive pointer types into
   // multiple variants taking Java primitive arrays and NIO buffers, subject
   // to the per-function "NIO only" rule in the configuration file
@@ -2754,10 +2971,11 @@ public class JavaEmitter implements GlueEmitter {
   private Type canonicalize(final Type t) {
     final Type res = canonMap.get(t);
     if (res != null) {
-      return res;
+        return res;
+    } else {
+        canonMap.put(t, t);
+        return t;
     }
-    canonMap.put(t, t);
-    return t;
   }
 
   /**
diff --git a/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java
index 6966315..c145ff5 100644
--- a/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java
+++ b/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java
@@ -40,14 +40,17 @@
 package com.jogamp.gluegen;
 
 import com.jogamp.gluegen.cgram.HeaderParser;
+import com.jogamp.gluegen.cgram.types.AliasedSymbol;
 import com.jogamp.gluegen.cgram.types.ArrayType;
 import com.jogamp.gluegen.cgram.types.EnumType;
+import com.jogamp.gluegen.cgram.types.FunctionSymbol;
 import com.jogamp.gluegen.cgram.types.Type;
 
 import java.io.PrintWriter;
 import java.text.MessageFormat;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
 /**
  * An emitter that emits only the interface for a Java<->C JNI binding.
@@ -64,22 +67,22 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
 
   protected final CommentEmitter defaultJavaCommentEmitter = new DefaultCommentEmitter();
   protected final CommentEmitter defaultInterfaceCommentEmitter = new InterfaceCommentEmitter();
+  protected final boolean tagNativeBinding;
+  protected final boolean useNIODirectOnly;
+  protected final MethodBinding binding;
 
   // Exception type raised in the generated code if runtime checks fail
   private final String runtimeExceptionType;
   private final String unsupportedExceptionType;
+  private final boolean useNIOOnly;
+  private final boolean isNativeMethod;
+  private final boolean isUnimplemented;
 
-  protected boolean emitBody;
-  protected boolean eraseBufferAndArrayTypes;
-  protected boolean useNIOOnly;
-  protected boolean useNIODirectOnly;
-  protected boolean forImplementingMethodCall;
-  protected boolean forDirectBufferImplementation;
-  protected boolean forIndirectBufferAndArrayImplementation;
-  protected boolean isUnimplemented;
-  protected boolean tagNativeBinding;
-
-  protected MethodBinding binding;
+  private boolean emitBody;
+  private boolean eraseBufferAndArrayTypes;
+  private boolean isPrivateNativeMethod;
+  private boolean forDirectBufferImplementation;
+  private boolean forIndirectBufferAndArrayImplementation;
 
   // Manually-specified prologue and epilogue code
   protected List<String> prologue;
@@ -97,9 +100,6 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
   // represent an array of compound type wrappers
   private static final String COMPOUND_ARRAY_SUFFIX = "_buf_array_copy";
 
-  // Only present to provide more clear comments
-  private final JavaConfiguration cfg;
-
   public JavaMethodBindingEmitter(final MethodBinding binding,
                                   final PrintWriter output,
                                   final String runtimeExceptionType,
@@ -109,13 +109,13 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
                                   final boolean eraseBufferAndArrayTypes,
                                   final boolean useNIOOnly,
                                   final boolean useNIODirectOnly,
-                                  final boolean forImplementingMethodCall,
                                   final boolean forDirectBufferImplementation,
                                   final boolean forIndirectBufferAndArrayImplementation,
                                   final boolean isUnimplemented,
                                   final boolean isInterface,
-                                  final JavaConfiguration configuration) {
-    super(output, isInterface);
+                                  final boolean isNativeMethod,
+                                  final boolean isPrivateNativeMethod, final JavaConfiguration configuration) {
+    super(output, isInterface, configuration);
     this.binding = binding;
     this.runtimeExceptionType = runtimeExceptionType;
     this.unsupportedExceptionType = unsupportedExceptionType;
@@ -124,16 +124,17 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
     this.eraseBufferAndArrayTypes = eraseBufferAndArrayTypes;
     this.useNIOOnly = useNIOOnly;
     this.useNIODirectOnly = useNIODirectOnly;
-    this.forImplementingMethodCall = forImplementingMethodCall;
     this.forDirectBufferImplementation = forDirectBufferImplementation;
     this.forIndirectBufferAndArrayImplementation = forIndirectBufferAndArrayImplementation;
     this.isUnimplemented = isUnimplemented;
-    if (forImplementingMethodCall) {
+    this.isNativeMethod = isNativeMethod;
+    this.isPrivateNativeMethod = isPrivateNativeMethod;
+    if (isPrivateNativeMethod) {
       setCommentEmitter(defaultJavaCommentEmitter);
     } else {
       setCommentEmitter(defaultInterfaceCommentEmitter);
     }
-    cfg = configuration;
+    // !forImplementingMethodCall && !isInterface
   }
 
   public JavaMethodBindingEmitter(final JavaMethodBindingEmitter arg) {
@@ -146,7 +147,8 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
     eraseBufferAndArrayTypes      = arg.eraseBufferAndArrayTypes;
     useNIOOnly                    = arg.useNIOOnly;
     useNIODirectOnly              = arg.useNIODirectOnly;
-    forImplementingMethodCall     = arg.forImplementingMethodCall;
+    isNativeMethod                = arg.isNativeMethod;
+    isPrivateNativeMethod         = arg.isPrivateNativeMethod;
     forDirectBufferImplementation = arg.forDirectBufferImplementation;
     forIndirectBufferAndArrayImplementation = arg.forIndirectBufferAndArrayImplementation;
     isUnimplemented               = arg.isUnimplemented;
@@ -154,18 +156,31 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
     epilogue                      = arg.epilogue;
     returnedArrayLengthExpression = arg.returnedArrayLengthExpression;
     returnedArrayLengthExpressionOnlyForComments = arg.returnedArrayLengthExpressionOnlyForComments;
-    cfg                           = arg.cfg;
   }
 
   public final MethodBinding getBinding() { return binding; }
 
-  public boolean isForImplementingMethodCall() { return forImplementingMethodCall; }
+  public boolean isNativeMethod() { return isNativeMethod; }
+  public boolean isPrivateNativeMethod() { return isPrivateNativeMethod; }
   public boolean isForDirectBufferImplementation() { return forDirectBufferImplementation; }
   public boolean isForIndirectBufferAndArrayImplementation() { return forIndirectBufferAndArrayImplementation; }
 
   @Override
-  public String getName() {
-    return binding.getName();
+  public String getInterfaceName() {
+    return binding.getInterfaceName();
+  }
+  @Override
+  public String getImplName() {
+    return binding.getImplName();
+  }
+  @Override
+  public String getNativeName() {
+    return binding.getNativeName();
+  }
+
+  @Override
+  public FunctionSymbol getCSymbol() {
+      return binding.getCSymbol();
   }
 
   protected String getArgumentName(final int i) {
@@ -233,8 +248,8 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
   }
 
   /** Accessor for subclasses. */
-  public void setForImplementingMethodCall(final boolean impl) {
-    this.forImplementingMethodCall = impl;
+  public void setPrivateNativeMethod(final boolean v) {
+    this.isPrivateNativeMethod = v;
   }
 
   /** Accessor for subclasses. */
@@ -322,10 +337,12 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
 
   @Override
   protected void emitName(final PrintWriter writer)  {
-    if (forImplementingMethodCall) {
-      writer.print(getImplMethodName());
+    if (isPrivateNativeMethod) {
+      writer.print(getNativeImplMethodName());
+    } else if( isInterface()) {
+      writer.print(getInterfaceName());
     } else {
-      writer.print(getName());
+      writer.print(getImplName());
     }
   }
 
@@ -334,7 +351,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
     boolean needComma = false;
     int numEmitted = 0;
 
-    if (forImplementingMethodCall  && binding.hasContainingType()) {
+    if (isPrivateNativeMethod  && binding.hasContainingType()) {
       // Always emit outgoing "this" argument
       writer.print("ByteBuffer ");
       writer.print(javaThisArgumentName());
@@ -395,8 +412,8 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
   }
 
 
-  protected String getImplMethodName() {
-    return binding.getName() + ( useNIODirectOnly ? "0" : "1" );
+  protected String getNativeImplMethodName() {
+    return binding.getImplName() + ( useNIODirectOnly ? "0" : "1" );
   }
 
   protected String byteOffsetArgName(final int i) {
@@ -544,7 +561,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
   }
 
   protected void emitCall(final MethodBinding binding, final PrintWriter writer) {
-    writer.print(getImplMethodName());
+    writer.print(getNativeImplMethodName());
     writer.print("(");
     emitCallArguments(binding, writer);
     writer.print(");");
@@ -675,9 +692,10 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
         } else if(type.isIntArray()) {
           writer.print(", Buffers.SIZEOF_INT * ");
         } else {
-          throw new RuntimeException("Unsupported type for calculating array offset argument for " +
+          throw new GlueGenException("Unsupported type for calculating array offset argument for " +
                                      getArgumentName(i) +
-                                     " -- error occurred while processing Java glue code for " + getName());
+                                     " -- error occurred while processing Java glue code for " + getCSymbol().getAliasedString(),
+                                     getCSymbol().getASTLocusTag());
         }
         writer.print(offsetArgName(i));
       }
@@ -688,7 +706,8 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
         }
       } else if (type.isPrimitiveArray()) {
         if (useNIOOnly) {
-            throw new RuntimeException("NIO[Direct]Only "+binding+" is set, but "+getArgumentName(i)+" is a primitive array");
+            throw new GlueGenException("NIO[Direct]Only "+binding+" is set, but "+getArgumentName(i)+" is a primitive array",
+                                       getCSymbol().getASTLocusTag());
         }
         writer.print( ", false");
       }
@@ -706,7 +725,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
       // ByteBuffers back into the wrapper types
       for (int i = 0; i < binding.getNumArguments(); i++) {
         final JavaType javaArgType = binding.getJavaArgumentType(i);
-        if ( javaArgType.isArrayOfCompoundTypeWrappers() && !isBaseTypeConst(javaArgType.getElementCType()) ) {
+        if ( javaArgType.isArrayOfCompoundTypeWrappers() && !javaArgType.getElementCType().isBaseTypeConst() ) {
           final String argName = binding.getArgumentName(i);
           writer.println("    for (int _ctr = 0; _ctr < " + argName + ".length; _ctr++) {");
           writer.println("      if ((" + argName + "[_ctr] == null && " + argName + COMPOUND_ARRAY_SUFFIX + "[_ctr] == null) ||");
@@ -743,8 +762,9 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
           } else if (returnType.isNIOLongBuffer()) {
               writer.println("    return _res.asLongBuffer();");
           } else {
-            throw new RuntimeException("While emitting glue code for " + getName() +
-                                       ": can not legally make pointers opaque to anything but PointerBuffer or LongBuffer/long");
+            throw new GlueGenException("While emitting glue code for " + getCSymbol().getAliasedString() +
+                                       ": can not legally make pointers opaque to anything but PointerBuffer or LongBuffer/long",
+                                       getCSymbol().getASTLocusTag());
           }
         } else if (getBinding().getCReturnType().pointerDepth() == 1 && returnType.isNIOLongBuffer()) {
           writer.println("    return _res.asLongBuffer();");
@@ -812,6 +832,26 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
    * emitter java method.
    */
   protected class DefaultCommentEmitter implements CommentEmitter {
+    protected void emitAliasedDocNamesComment(final AliasedSymbol sym, final PrintWriter writer) {
+        writer.print(emitAliasedDocNamesComment(sym, new StringBuilder()).toString());
+    }
+    protected StringBuilder emitAliasedDocNamesComment(final AliasedSymbol sym, final StringBuilder sb) {
+      final Set<String> aliases = cfg.getAliasedDocNames(sym);
+      if (aliases != null && aliases.size() > 0 ) {
+          int i=0;
+          sb.append("Alias for: <code>");
+          for (final String alias : aliases) {
+              if(0 < i) {
+                  sb.append("</code>, <code>");
+              }
+              sb.append(alias);
+              i++;
+          }
+          sb.append("</code>");
+      }
+      return sb;
+    }
+
     @Override
     public void emit(final FunctionEmitter emitter, final PrintWriter writer) {
       emitBeginning(emitter, writer);
@@ -826,9 +866,11 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
       writer.print("Entry point to C language function: ");
     }
     protected void emitBindingCSignature(final MethodBinding binding, final PrintWriter writer) {
-      writer.print("<code> ");
-      writer.print(binding.getCSymbol().toString(tagNativeBinding));
-      writer.print(" </code> ");
+      final FunctionSymbol funcSym = binding.getCSymbol();
+      writer.print("<code>");
+      writer.print(funcSym.toString(tagNativeBinding));
+      writer.print("</code><br>");
+      emitAliasedDocNamesComment(funcSym, writer);
     }
     protected void emitEnding(final FunctionEmitter emitter, final PrintWriter writer) {
       // If argument type is a named enum, then emit a comment detailing the
diff --git a/src/java/com/jogamp/gluegen/JavaType.java b/src/java/com/jogamp/gluegen/JavaType.java
index 87804bd..9bcd663 100644
--- a/src/java/com/jogamp/gluegen/JavaType.java
+++ b/src/java/com/jogamp/gluegen/JavaType.java
@@ -63,6 +63,7 @@ public class JavaType {
   private final String structName;  // Types we're generating glue code for (i.e., C structs)
   private final Type   elementType; // Element type if this JavaType represents a C array
   private final C_PTR  primitivePointerType;
+  private final boolean opaqued;
 
   private static JavaType nioBufferType;
   private static JavaType nioByteBufferType;
@@ -107,12 +108,20 @@ public class JavaType {
        return elementType;
   }
 
+  /** Creates a JavaType corresponding to the given opaque Java type. This
+      can be used to represent arrays of primitive values or Strings;
+      the emitters understand how to perform proper conversion from
+      the corresponding C type. */
+  public static JavaType createForOpaqueClass(final Class<?> clazz) {
+    return new JavaType(clazz, true);
+  }
+
   /** Creates a JavaType corresponding to the given Java type. This
       can be used to represent arrays of primitive values or Strings;
       the emitters understand how to perform proper conversion from
       the corresponding C type. */
   public static JavaType createForClass(final Class<?> clazz) {
-    return new JavaType(clazz);
+    return new JavaType(clazz, false);
   }
 
   /** Creates a JavaType corresponding to the specified C CompoundType
@@ -336,6 +345,8 @@ public class JavaType {
     return "jobject";
   }
 
+  public boolean isOpaqued() { return opaqued; }
+
   public boolean isNIOBuffer() {
     return clazz != null && ( java.nio.Buffer.class.isAssignableFrom(clazz) ||
                               com.jogamp.common.nio.NativeBuffer.class.isAssignableFrom(clazz)) ;
@@ -528,34 +539,39 @@ public class JavaType {
         append(sb, "primitivePointerType = "+primitivePointerType, prepComma); prepComma=true;
     }
     append(sb, "is[", prepComma); prepComma=false;
-    if( isArray() ) {
-        append(sb, "array", prepComma); prepComma=true;
-    }
-    if( isArrayOfCompoundTypeWrappers() ) {
-        append(sb, "compoundArray", prepComma); prepComma=true;
-    }
-    if( isCompoundTypeWrapper() ) {
-        append(sb, "compound", prepComma); prepComma=true;
-    }
-    if( isArray() ) {
-        append(sb, "array", prepComma); prepComma=true;
-    }
-    if( isPrimitive() ) {
-        append(sb, "primitive", prepComma); prepComma=true;
-    }
-    if( isPrimitiveArray() ) {
-        append(sb, "primitiveArray", prepComma); prepComma=true;
-    }
-    if( isNIOBuffer() ) {
-        append(sb, "nioBuffer", prepComma); prepComma=true;
-    }
-    if( isNIOBufferArray() ) {
-        append(sb, "nioBufferArray", prepComma); prepComma=true;
-    }
-    if( isCPrimitivePointerType() ) {
-        append(sb, "C-Primitive-Pointer", prepComma); prepComma=true;
+    {
+        if( isOpaqued() ) {
+            append(sb, "opaque", prepComma); prepComma=true;
+        }
+        if( isArray() ) {
+            append(sb, "array", prepComma); prepComma=true;
+        }
+        if( isArrayOfCompoundTypeWrappers() ) {
+            append(sb, "compoundArray", prepComma); prepComma=true;
+        }
+        if( isCompoundTypeWrapper() ) {
+            append(sb, "compound", prepComma); prepComma=true;
+        }
+        if( isArray() ) {
+            append(sb, "array", prepComma); prepComma=true;
+        }
+        if( isPrimitive() ) {
+            append(sb, "primitive", prepComma); prepComma=true;
+        }
+        if( isPrimitiveArray() ) {
+            append(sb, "primitiveArray", prepComma); prepComma=true;
+        }
+        if( isNIOBuffer() ) {
+            append(sb, "nioBuffer", prepComma); prepComma=true;
+        }
+        if( isNIOBufferArray() ) {
+            append(sb, "nioBufferArray", prepComma); prepComma=true;
+        }
+        if( isCPrimitivePointerType() ) {
+            append(sb, "C-Primitive-Pointer", prepComma); prepComma=true;
+        }
     }
-    append(sb, "descriptor '"+getDescriptor()+"'", prepComma); prepComma=true;
+    append(sb, "], descriptor '"+getDescriptor()+"']", prepComma); prepComma=true;
     return sb.toString();
   }
 
@@ -563,11 +579,12 @@ public class JavaType {
    * Constructs a representation for a type corresponding to the given Class
    * argument.
    */
-  private JavaType(final Class<?> clazz) {
+  private JavaType(final Class<?> clazz, final boolean opaqued) {
     this.primitivePointerType = null;
     this.clazz = clazz;
     this.structName = null;
     this.elementType = null;
+    this.opaqued = opaqued;
   }
 
   /** Constructs a type representing a named C struct. */
@@ -576,6 +593,7 @@ public class JavaType {
     this.clazz = null;
     this.structName = structName;
     this.elementType = null;
+    this.opaqued = false;
   }
 
   /** Constructs a type representing a pointer to a C primitive
@@ -585,6 +603,7 @@ public class JavaType {
     this.clazz = null;
     this.structName = null;
     this.elementType = null;
+    this.opaqued = false;
   }
 
   /** Constructs a type representing an array of C pointers. */
@@ -593,6 +612,7 @@ public class JavaType {
     this.clazz = null;
     this.structName = null;
     this.elementType = elementType;
+    this.opaqued = false;
   }
 
   /** clone only */
@@ -601,6 +621,7 @@ public class JavaType {
     this.clazz = clazz;
     this.structName = name;
     this.elementType = elementType;
+    this.opaqued = false;
   }
 
   private String arrayName(Class<?> clazz) {
diff --git a/src/java/com/jogamp/gluegen/Logging.java b/src/java/com/jogamp/gluegen/Logging.java
index 40eadcb..c057db4 100644
--- a/src/java/com/jogamp/gluegen/Logging.java
+++ b/src/java/com/jogamp/gluegen/Logging.java
@@ -31,57 +31,352 @@
  */
 package com.jogamp.gluegen;
 
+import java.util.HashMap;
+import java.util.Map;
 import java.util.logging.ConsoleHandler;
 import java.util.logging.Formatter;
+import java.util.logging.Handler;
 import java.util.logging.Level;
 import java.util.logging.LogRecord;
 import java.util.logging.Logger;
 
+import jogamp.common.Debug;
+
 import com.jogamp.common.util.PropertyAccess;
+import com.jogamp.gluegen.cgram.types.AliasedSymbol;
+import com.jogamp.gluegen.cgram.types.Type;
 
 /**
  *
- * @author Michael Bien
+ * @author Michael Bien, et.al.
  */
 public class Logging {
+    public static final boolean DEBUG = Debug.debug("Logging");
+
+    /**
+     * An interface for {@link Logger}.
+     */
+    public static interface LoggerIf {
+        /**
+         * See {@link Logger#info(String)}
+         */
+        void info(final String msg);
+        /**
+         * See {@link Logger#info(String)}
+         */
+        void info(final ASTLocusTag loc, final String msg);
+
+        /**
+         * See {@link Logger#warning(String)}
+         */
+        void warning(final String msg);
+        /**
+         * See {@link Logger#warning(String)}
+         */
+        void warning(final ASTLocusTag loc, final String msg);
+
+        /**
+         * Calls {@link #log(Level, String)} w/ {@link Level#FINE}.
+         */
+        void debug(final String msg);
+        /**
+         * Calls {@link #log(Level, ASTLocusTag, String)} w/ {@link Level#FINE}.
+         */
+        void debug(final ASTLocusTag loc, final String msg);
+
+        /**
+         * See {@link Logger#log(Level, String)}
+         */
+        void log(final Level level, final String msg);
+        /**
+         * See {@link Logger#log(Level, String, Object)}
+         */
+        void log(final Level level, final String msg, final Object param);
+        /**
+         * See {@link Logger#log(Level, String, Object[])}
+         */
+        void log(final Level level, final String msg, final Object ... params);
+
+        /**
+         * See {@link Logger#log(Level, String)}
+         */
+        void log(final Level level, final ASTLocusTag loc, final String msg);
+        /**
+         * See {@link Logger#log(Level, String, Object)}
+         */
+        void log(final Level level, final ASTLocusTag loc, final String msg, final Object param);
+        /**
+         * See {@link Logger#log(Level, String, Object[])}
+         */
+        void log(final Level level, final ASTLocusTag loc, final String msg, final Object ... params);
+
+        /**
+         * See {@link Logger#setLevel(Level)}
+         */
+        void setLevel(final Level newLevel) throws SecurityException;
+        /**
+         * See {@link Handler#setLevel(Level)}
+         */
+        void setLevelOfAllHandler(final Level newLevel) throws SecurityException;
+        /**
+         * See {@link Logger#getLevel()}
+         */
+        Level getLevel();
+        /**
+         * See {@link Logger#isLoggable(Level)}
+         */
+        boolean isLoggable(Level level);
+        /**
+         * See {@link Logger#getName()}
+         */
+        String getName();
+        /**
+         * See {@link Logger#getHandlers()}
+         */
+        Handler[] getHandlers();
+        /**
+         * See {@link LogRecord#getSourceClassName()}
+         */
+        String getSourceClassName();
+    }
+    /* pp */ static class FQNLogger implements LoggerIf {
+        public final Logger impl;
+        public final PlainLogConsoleHandler handler;
+        /* pp */ FQNLogger(final String fqnClassName, final String simpleClassName, final Level level) {
+            this.impl = Logger.getLogger(fqnClassName);
+            this.handler = new PlainLogConsoleHandler(new PlainLogFormatter(simpleClassName), Level.ALL);
+            this.impl.setUseParentHandlers(false);
+            this.impl.setLevel(level);
+            this.impl.addHandler(this.handler);
+            this.impl.log(Level.INFO, "Logging.new: "+impl.getName()+": level "+level+
+                                      ": obj 0x"+Integer.toHexString(impl.hashCode()));
+        }
+        @Override
+        public void info(final String msg) {
+            impl.info(msg);
+        }
+        @Override
+        public void info(final ASTLocusTag loc, final String msg) {
+            handler.plf.setASTLocusTag(loc);
+            try {
+                impl.info(msg);
+            } finally {
+                handler.plf.setASTLocusTag(null);
+            }
+        }
+
+        @Override
+        public void warning(final String msg) {
+            impl.warning(msg);
+        }
+        @Override
+        public void warning(final ASTLocusTag loc, final String msg) {
+            handler.plf.setASTLocusTag(loc);
+            try {
+                impl.warning(msg);
+            } finally {
+                handler.plf.setASTLocusTag(null);
+            }
+        }
+
+        @Override
+        public void debug(final String msg) {
+            log(Level.FINE, msg);
+        }
+        @Override
+        public void debug(final ASTLocusTag loc, final String msg) {
+            log(Level.FINE, loc, msg);
+        }
+
+        @Override
+        public void log(final Level level, final String msg) {
+            impl.log(level, msg);
+        }
+        @Override
+        public void log(final Level level, final String msg, final Object param) {
+            impl.log(level, msg, param);
+        }
+        @Override
+        public void log(final Level level, final String msg, final Object ... params) {
+            impl.log(level, msg, params);
+        }
 
-    static void init() {
+        @Override
+        public void log(final Level level, final ASTLocusTag loc, final String msg) {
+            handler.plf.setASTLocusTag(loc);
+            try {
+                impl.log(level, msg);
+            } finally {
+                handler.plf.setASTLocusTag(null);
+            }
+        }
+        @Override
+        public void log(final Level level, final ASTLocusTag loc, final String msg, final Object param) {
+            handler.plf.setASTLocusTag(loc);
+            try {
+                impl.log(level, msg, param);
+            } finally {
+                handler.plf.setASTLocusTag(null);
+            }
+        }
+        @Override
+        public void log(final Level level, final ASTLocusTag loc, final String msg, final Object ... params) {
+            handler.plf.setASTLocusTag(loc);
+            try {
+                impl.log(level, msg, params);
+            } finally {
+                handler.plf.setASTLocusTag(null);
+            }
+        }
+
+        @Override
+        public void setLevel(final Level newLevel) throws SecurityException {
+            impl.setLevel(newLevel);
+        }
+        @Override
+        public void setLevelOfAllHandler(final Level newLevel) throws SecurityException {
+            final Handler[] hs = getHandlers();
+            for(final Handler h:hs) {
+                h.setLevel(newLevel);
+            }
+        }
+        @Override
+        public Level getLevel() {
+            return impl.getLevel();
+        }
+        @Override
+        public boolean isLoggable(final Level level) {
+            return impl.isLoggable(level);
+        }
+        @Override
+        public String getName() {
+            return impl.getName();
+        }
+        @Override
+        public synchronized Handler[] getHandlers() {
+            return impl.getHandlers();
+        }
+        @Override
+        public String getSourceClassName() {
+            return handler.plf.simpleClassName;
+        }
+    }
+    static class PlainLogConsoleHandler extends ConsoleHandler {
+        final PlainLogFormatter plf;
+        PlainLogConsoleHandler(final PlainLogFormatter plf, final Level level) {
+            this.plf = plf;
+            setFormatter(plf);
+            setLevel(level);
+        }
+        @Override
+        public java.util.logging.Formatter getFormatter() {
+            return plf;
+        }
+    }
+    static class PlainLogFormatter extends Formatter {
+        final String simpleClassName;
+        ASTLocusTag astLocus;
+        PlainLogFormatter(final String simpleClassName) {
+            this.simpleClassName = simpleClassName;
+        }
+        public void setASTLocusTag(final ASTLocusTag loc) { astLocus = loc; }
+        @Override
+        public String format(final LogRecord record) {
+            // Replace [Type, JavaType] -> its debug string!
+            final Object[] params = record.getParameters();
+            if( null != params ) {
+                for(int i=params.length-1; 0<=i; i--) {
+                    final Object o = params[i];
+                    if( o instanceof Type ) {
+                        params[i] = ((Type)o).getDebugString();
+                    } else if( o instanceof JavaType ) {
+                        params[i] = ((JavaType)o).getDebugString();
+                    } else if( o instanceof AliasedSymbol ) {
+                        params[i] = ((AliasedSymbol)o).getAliasedString();
+                    }
+                }
+            }
+            final StringBuilder sb = new StringBuilder(256);
+            if( null != astLocus ) {
+                astLocus.toString(sb, getCanonicalName(record.getLevel()), GlueGen.debug()).append(": ");
+            }
+            if( GlueGen.debug() ) {
+                sb.append(simpleClassName).append(": ");
+            }
+            sb.append(formatMessage(record)).append("\n");
+            return sb.toString();
+        }
+    }
+
+    private final static Map<String, LoggerIf> loggers;
+    private final static FQNLogger rootPackageLogger;
+    static {
+        loggers = new HashMap<String, LoggerIf>();
         final String packageName = Logging.class.getPackage().getName();
         final String property = PropertyAccess.getProperty(packageName+".level", true);
         Level level;
         if(property != null) {
             level = Level.parse(property);
         } else {
-            level = Level.WARNING;
+            if( DEBUG || GlueGen.debug() ) {
+                level = Level.ALL;
+            } else {
+                level = Level.WARNING;
+            }
         }
+        final String simpleClassName = Logging.class.getSimpleName();
+        final String fqnClassName = packageName+"."+simpleClassName;
+        rootPackageLogger = new FQNLogger(fqnClassName, simpleClassName, level);
+        loggers.put(fqnClassName, rootPackageLogger);
+    }
 
-        final ConsoleHandler handler = new ConsoleHandler() {
-            @Override
-            public java.util.logging.Formatter getFormatter() {
-                return new PlainLogFormatter();
-            }
-        };
-        handler.setFormatter(new PlainLogFormatter());
-        handler.setLevel(level);
-
-        final Logger rootPackageLogger = Logger.getLogger(packageName);
-        rootPackageLogger.setUseParentHandlers(false);
-        rootPackageLogger.setLevel(level);
-        rootPackageLogger.addHandler(handler);
+    /** provokes static initialization */
+    static void init() { }
+
+    public static String getCanonicalName(final Level level) {
+        if( Level.CONFIG == level ) {
+            return "config";
+        } else if( Level.FINER == level ) {
+            return "verbose";
+        } else if( Level.FINE == level ) {
+            return "debug";
+        } else if( Level.INFO == level ) {
+            return "info";
+        } else if( Level.WARNING == level ) {
+            return "warning";
+        } else if( Level.SEVERE == level ) {
+            return "error";
+        } else {
+            return level.getName().toLowerCase();
+        }
     }
 
-    /**
-     * This log formatter needs usually one line per log record.
-     * @author Michael Bien
-     */
-    private static class PlainLogFormatter extends Formatter {
+    /** Returns the <i>root package logger</i>. */
+    public static LoggerIf getLogger() {
+        return rootPackageLogger;
+    }
+    /** Returns the demanded logger, while aligning its log-level to the root logger's level. */
+    public static synchronized LoggerIf getLogger(final Class<?> clazz) {
+        return getLogger(clazz.getPackage().getName(), clazz.getSimpleName());
+    }
 
-        @Override
-        public String format(final LogRecord record) {
-            final StringBuilder sb = new StringBuilder(128);
-            sb.append("[").append(record.getLevel()).append(' ').append(record.getSourceClassName()).append("]: ");
-            sb.append(formatMessage(record)).append("\n");
-            return sb.toString();
+    /** Returns the demanded logger, while aligning its log-level to the root logger's level. */
+    public static synchronized LoggerIf getLogger(final String packageName, final String simpleClassName) {
+        final String fqnClassName = packageName+"."+simpleClassName;
+        LoggerIf res = loggers.get(fqnClassName);
+        if( null == res ) {
+            res = new FQNLogger(fqnClassName, simpleClassName, rootPackageLogger.getLevel());
+            loggers.put(fqnClassName, res);
         }
+        return res;
+    }
+    /** Align log-level of given logger to the root logger's level. */
+    public static void alignLevel(final LoggerIf l) {
+        alignLevel(l, rootPackageLogger.getLevel());
+    }
+    /** Align log-level of given logger and all its handlers to the given level. */
+    public static void alignLevel(final LoggerIf l, final Level level) {
+        l.setLevel(level);
+        l.setLevelOfAllHandler(level);
     }
 }
diff --git a/src/java/com/jogamp/gluegen/MethodBinding.java b/src/java/com/jogamp/gluegen/MethodBinding.java
index 93c55d5..95a10c6 100644
--- a/src/java/com/jogamp/gluegen/MethodBinding.java
+++ b/src/java/com/jogamp/gluegen/MethodBinding.java
@@ -43,8 +43,6 @@ import com.jogamp.gluegen.cgram.types.FunctionSymbol;
 import com.jogamp.gluegen.cgram.types.Type;
 
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
 import java.util.List;
 
 /** Represents the binding of a C function to a Java method. Also used
@@ -54,8 +52,10 @@ import java.util.List;
 public class MethodBinding {
 
   private final FunctionSymbol sym;
-  private String         renamedMethodName;
-  private final HashSet<String> aliasedNames;
+  private final String   delegationImplName;
+  private final JavaType containingType;
+  private final Type     containingCType;
+  private String         nativeName;
   private JavaType       javaReturnType;
   private List<JavaType> javaArgumentTypes;
   private boolean        computedSignatureProperties;
@@ -69,8 +69,6 @@ public class MethodBinding {
   private boolean        signatureUsesCArrays;
   private boolean        signatureUsesJavaPrimitiveArrays;
   private boolean        signatureRequiresStaticInitialization;
-  private JavaType       containingType;
-  private Type           containingCType;
   private int            thisPointerIndex = -1;
 
   /**
@@ -79,12 +77,12 @@ public class MethodBinding {
    * types. It's safe to modify this binding after construction.
    */
   public MethodBinding(final MethodBinding bindingToCopy) {
-    this.sym = bindingToCopy.sym;
-
-    this.renamedMethodName                = bindingToCopy.renamedMethodName;
-    this.aliasedNames                     = new HashSet<String>(bindingToCopy.aliasedNames);
+    this.sym                              = bindingToCopy.sym;
+    this.delegationImplName               = bindingToCopy.delegationImplName;
     this.containingType                   = bindingToCopy.containingType;
     this.containingCType                  = bindingToCopy.containingCType;
+
+    this.nativeName                       = bindingToCopy.nativeName;
     this.javaReturnType                   = bindingToCopy.javaReturnType;
     this.javaArgumentTypes                = ( null != bindingToCopy.javaArgumentTypes ) ? new ArrayList<JavaType>(bindingToCopy.javaArgumentTypes) : null;
     this.computedSignatureProperties      = bindingToCopy.computedSignatureProperties;
@@ -101,19 +99,27 @@ public class MethodBinding {
     this.thisPointerIndex                 = bindingToCopy.thisPointerIndex;
   }
 
-  /** Constructor for calling a C function. */
-  public MethodBinding(final FunctionSymbol sym) {
-    this.sym = sym;
-    this.aliasedNames = new HashSet<String>();
-  }
-
-  /** Constructor for calling a function pointer contained in a
-      struct. */
-  public MethodBinding(final FunctionSymbol sym, final JavaType containingType, final Type containingCType) {
+  /**
+   * Constructor for calling a C function or a function pointer contained in a struct.
+   * <p>
+   * In case of the latter, a struct function pointer,
+   * the arguments {@code containingType} and {@code containingCType} must not be {@code null}!
+   * </p>
+   */
+  public MethodBinding(final FunctionSymbol sym,
+                       final String delegationImplName,
+                       final JavaType javaReturnType,
+                       final List<JavaType> javaArgumentTypes,
+                       final JavaType containingType,
+                       final Type containingCType) {
     this.sym = sym;
+    this.delegationImplName = delegationImplName;
     this.containingType = containingType;
     this.containingCType = containingCType;
-    this.aliasedNames = new HashSet<String>();
+
+    this.nativeName = null;
+    this.javaReturnType = javaReturnType;
+    this.javaArgumentTypes = javaArgumentTypes;
   }
 
     public void setJavaReturnType(final JavaType type) {
@@ -149,6 +155,7 @@ public class MethodBinding {
         return sym.getArgumentType(i);
     }
 
+    /** Returns the {@link FunctionSymbol}. */
     public FunctionSymbol getCSymbol() {
         return sym;
     }
@@ -166,33 +173,42 @@ public class MethodBinding {
         return "arg" + i;
     }
 
-    public String getOrigName() {
-        return sym.getName();
-    }
-
+    /** Returns the {@link FunctionSymbol}'s current {@link FunctionSymbol#getName() aliased} API name. */
     public String getName() {
-        // Defaults to same as C symbol unless renamed
-        if (renamedMethodName != null) {
-            return renamedMethodName;
-        }
         return sym.getName();
     }
-
-    /** Supports renaming C function in Java binding. */
-    public void renameMethodName(final String name) {
-        if (null != name) {
-            renamedMethodName = name;
-            aliasedNames.add(sym.getName());
-        }
-    }
-
-    public void addAliasedName(final String name) {
-        aliasedNames.add(name);
+    /**
+     * The
+     * {@link JavaConfiguration#getDelegatedImplementation(com.jogamp.gluegen.cgram.types.AliasedSymbol) implementation delegation}
+     * name, or {@code null} for no delegation.
+     * @see #getImplName()
+     */
+    public String getDelegationImplName() {
+        return delegationImplName;
     }
 
-    public Collection<String> getAliasedNames() {
-        return aliasedNames;
+    /** Returns the {@link FunctionSymbol}'s current {@link FunctionSymbol#getName() aliased} API name for the interface. */
+    public String getInterfaceName() {
+        return sym.getName();
     }
+    /**
+     * Returns the {@link FunctionSymbol}'s name for the implementation,
+     * which is the current {@link FunctionSymbol#getName() aliased} API name per default,
+     * or the {@link #getDelegationImplName() delegation} name.
+     * @see #getDelegationImplName()
+     */
+    public String getImplName() {
+        return null != delegationImplName ? delegationImplName : sym.getName();
+    }
+    /**
+     * Returns the {@link FunctionSymbol}'s name for the native function
+     * which is the {@link FunctionSymbol#getOrigName() original} C API name per default,
+     * but may be overridden via {@link #setNativeName(String)}.
+     */
+    public String getNativeName() {
+        return null != nativeName ? nativeName : sym.getOrigName();
+    }
+    public void setNativeName(final String s) { nativeName = s; }
 
   /** Creates a new MethodBinding replacing the specified Java
       argument type with a new argument type. If argumentNumber is
diff --git a/src/java/com/jogamp/gluegen/ReferencedStructs.java b/src/java/com/jogamp/gluegen/ReferencedStructs.java
index d06d47f..26deb3a 100644
--- a/src/java/com/jogamp/gluegen/ReferencedStructs.java
+++ b/src/java/com/jogamp/gluegen/ReferencedStructs.java
@@ -44,31 +44,43 @@ import com.jogamp.gluegen.cgram.types.*;
 
 public class ReferencedStructs implements TypeVisitor {
 
-  private final Set<Type> results = new HashSet<Type>();
+    private final Map<String, Type> resultMap = new HashMap<String, Type>();
+    private final Set<CompoundType> layoutSet = new HashSet<CompoundType>();
+    private final Set<Type> skip = new HashSet<Type>();
 
-  public void clear() {
-    results.clear();
-  }
+    public void clear() {
+        resultMap.clear();
+    }
 
-  public Iterator<Type> results() {
-    return results.iterator();
-  }
+    public Iterator<Type> results() {
+        return resultMap.values().iterator();
+    }
+    public Iterator<CompoundType> layouts() {
+        return layoutSet.iterator();
+    }
 
-  @Override
-  public void visitType(final Type t) {
-    if (t.isPointer()) {
-      final PointerType p = t.asPointer();
-      if (p.hasTypedefedName()) {
-        final CompoundType c = p.getTargetType().asCompound();
-        if (c != null && c.getName() == null) {
-          // This otherwise-unnamed CompoundType is referred to by a
-          // PointerType that has a typedef name. Assume that it is
-          // referred to in the glue code and emit it.
-          results.add(p);
+    @Override
+    public void visitType(final Type t) {
+        if( skip.contains(t) ) {
+            return;
+        }
+        if ( t.isPointer() ) {
+            final PointerType p = t.asPointer();
+            final CompoundType c = p.getTargetType().asCompound();
+            if( p.isTypedef() && null != c ) {
+                // If containing pointer is typedef, use it (preferred)
+                skip.add(c); // earmark to skip the compound!
+                resultMap.put(c.getName(), p);
+                layoutSet.add(c);
+            } else {
+                // .. otherwise skip pointer and use followup compound
+            }
+        } else if( t.isCompound() ) {
+            // Use compound if not yet mapped, e.g. by typedef'ed (preferred)
+            if( !resultMap.containsKey(t.getName()) ) {
+                resultMap.put(t.getName(), t);
+            }
+            layoutSet.add(t.asCompound()); // always: could be const/volatile variants ..
         }
-      }
-    } else if (t.isCompound()) {
-      results.add(t);
     }
-  }
 }
diff --git a/src/java/com/jogamp/gluegen/runtime/FunctionAddressResolver.java b/src/java/com/jogamp/gluegen/TypeConfig.java
similarity index 63%
copy from src/java/com/jogamp/gluegen/runtime/FunctionAddressResolver.java
copy to src/java/com/jogamp/gluegen/TypeConfig.java
index 4fc40a4..5f389f4 100644
--- a/src/java/com/jogamp/gluegen/runtime/FunctionAddressResolver.java
+++ b/src/java/com/jogamp/gluegen/TypeConfig.java
@@ -1,5 +1,5 @@
 /**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2015 JogAmp Community. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
  * permitted provided that the following conditions are met:
@@ -25,23 +25,28 @@
  * authors and should not be interpreted as representing official policies, either expressed
  * or implied, of JogAmp Community.
  */
+package com.jogamp.gluegen;
 
-/*
- * Created on Saturday, April 24 2010 16:30
- */
-package com.jogamp.gluegen.runtime;
-
-import com.jogamp.common.os.DynamicLookupHelper;
+import com.jogamp.gluegen.cgram.types.SizeThunk;
+import com.jogamp.gluegen.cgram.types.Type;
 
 /**
- *
- * @author Michael Bien
+ * Static {@link Type} config helper
+ * binding {@link JavaConfiguration#relaxedEqualSemanticsTest()} system wide.
  */
-public interface FunctionAddressResolver {
+public class TypeConfig {
+    private static boolean relaxedEqualSemanticsTest = false;
 
     /**
-     * Resolves the name of the function bound to the method and returns the address.
+     * Returns whether {@link TypeConfig.SemanticEqualityOp#equalSemantics(TypeConfig.SemanticEqualityOp)}
+     * shall attempt to perform a relaxed semantic equality test, e.g. skip the {@code const} and {@code volatile} qualifier
+     * - or not.
      */
-    public long resolve(String name, DynamicLookupHelper lookup);
-
+    public static boolean relaxedEqualSemanticsTest() {
+        return relaxedEqualSemanticsTest;
+    }
+    /* pp */ static void setRelaxedEqualSemanticsTest(final boolean v) {
+        relaxedEqualSemanticsTest = v;
+        SizeThunk.setRelaxedEqualSemanticsTest(v);
+    }
 }
diff --git a/src/java/com/jogamp/gluegen/TypeInfo.java b/src/java/com/jogamp/gluegen/TypeInfo.java
index d89ac79..52fdc04 100644
--- a/src/java/com/jogamp/gluegen/TypeInfo.java
+++ b/src/java/com/jogamp/gluegen/TypeInfo.java
@@ -66,7 +66,7 @@ public class TypeInfo {
     buf.append(name);
     buf.append(" pointerDepth ");
     buf.append(pointerDepth);
-    buf.append(" JavaType " + javaType);
+    buf.append(" JavaType " + javaType.getDebugString());
     return buf.toString();
   }
 }
diff --git a/src/java/com/jogamp/gluegen/ant/GlueGenTask.java b/src/java/com/jogamp/gluegen/ant/GlueGenTask.java
index dd57365..2b11d3f 100644
--- a/src/java/com/jogamp/gluegen/ant/GlueGenTask.java
+++ b/src/java/com/jogamp/gluegen/ant/GlueGenTask.java
@@ -73,7 +73,8 @@ import org.apache.tools.ant.util.JavaEnvUtils;
                 emitter="[emitter class name]"
                 config="[configuration file]"
                 dumpCPP="[optional boolean]"
-                debug="[optional boolean]" />
+                debug="[optional boolean]"
+                logLevel="[optional string]" />
  * </pre>
  *
  * @author Rob Grzywinski <a href="mailto:rgrzywinski at realityinteractive.com">rgrzywinski at yahoo.com</a>
@@ -101,6 +102,11 @@ public class GlueGenTask extends Task
     private boolean debug=false;
 
     /**
+     * <p>The optional logLevel.</p>
+     */
+    private String logLevel = null;
+
+    /**
      * <p>The optional dumpCPP flag.</p>
      */
     private boolean dumpCPP=false;
@@ -182,6 +188,15 @@ public class GlueGenTask extends Task
     }
 
     /**
+     * <p>Set the logLevel (optional).  This is called by ANT.</p>
+     */
+    public void setLogLevel(final String logLevel)
+    {
+        log( ("Setting logLevel: " + logLevel), Project.MSG_VERBOSE);
+        this.logLevel=logLevel;
+    }
+
+    /**
      * <p>Set the dumpCPP flag (optional).  This is called by ANT.</p>
      */
     public void setDumpCPP(final boolean dumpCPP)
@@ -456,6 +471,12 @@ public void setIncludeRefid(final Reference reference) {
             gluegenCommandline.createArgument().setValue("--debug");
         }
 
+        // add the logLevel if enabled
+        if(null != logLevel) {
+            gluegenCommandline.createArgument().setValue("--logLevel");
+            gluegenCommandline.createArgument().setValue(logLevel);
+        }
+
         // add the debug flag if enabled
         if(dumpCPP) {
             gluegenCommandline.createArgument().setValue("--dumpCPP");
diff --git a/src/java/com/jogamp/gluegen/cgram/Define.java b/src/java/com/jogamp/gluegen/cgram/Define.java
index 797cf6f..23caabd 100644
--- a/src/java/com/jogamp/gluegen/cgram/Define.java
+++ b/src/java/com/jogamp/gluegen/cgram/Define.java
@@ -39,18 +39,32 @@
 
 package com.jogamp.gluegen.cgram;
 
+import com.jogamp.gluegen.ASTLocusTag;
+import com.jogamp.gluegen.ASTLocusTag.ASTLocusTagProvider;
+
 /** Represents a #define of a literal to a value (a number represented
     in string form.) */
 
-public class Define {
+public class Define implements ASTLocusTagProvider {
   private final String name;
   private final String value;
+  private final ASTLocusTag astLocus;
 
   public Define(final String name, final String value) {
     this.name = name;
     this.value = value;
+    this.astLocus = null;
+  }
+
+  public Define(final String name, final String value, final ASTLocusTag astLocus) {
+    this.name = name;
+    this.value = value;
+    this.astLocus = astLocus;
   }
 
   public String getName()  { return name; }
   public String getValue() { return value; }
+
+  @Override
+  public ASTLocusTag getASTLocusTag() { return astLocus; }
 }
diff --git a/src/java/com/jogamp/gluegen/cgram/TNode.java b/src/java/com/jogamp/gluegen/cgram/TNode.java
index a564c54..70dc2c4 100644
--- a/src/java/com/jogamp/gluegen/cgram/TNode.java
+++ b/src/java/com/jogamp/gluegen/cgram/TNode.java
@@ -3,10 +3,14 @@ package com.jogamp.gluegen.cgram;
 import antlr.collections.AST;
 import antlr.CommonAST;
 import antlr.Token;
+
 import java.lang.reflect.*;
 import java.util.Hashtable;
 import java.util.Enumeration;
 
+import com.jogamp.gluegen.ASTLocusTag;
+import com.jogamp.gluegen.ASTLocusTag.ASTLocusTagProvider;
+
 /**
   Class TNode is an implementation of the AST interface
   and adds many useful features:
@@ -29,7 +33,8 @@ import java.util.Enumeration;
 
 
  */
-public class TNode extends CommonAST {
+ at SuppressWarnings("serial")
+public class TNode extends CommonAST implements ASTLocusTagProvider {
   protected int ttype;
   protected String text;
   protected int lineNum = 0;
@@ -40,7 +45,22 @@ public class TNode extends CommonAST {
   protected Hashtable<String, Object> attributes = null;
   static String tokenVocabulary;
 
-
+  /**
+   * {@inheritDoc}
+   * <p>
+   * If <i>source</i> is not available,
+   * implementation returns {@code null}.
+   * </p>
+   */
+  @Override
+  public ASTLocusTag getASTLocusTag() {
+      final Object s = getAttribute("source");
+      if( null != s ) {
+          return new ASTLocusTag(s, getLineNum(), -1, getText());
+      } else {
+          return null;
+      }
+  }
 
 
   /** Set the token vocabulary to a tokentypes class
diff --git a/src/java/com/jogamp/gluegen/cgram/types/AliasedSymbol.java b/src/java/com/jogamp/gluegen/cgram/types/AliasedSymbol.java
new file mode 100644
index 0000000..869c658
--- /dev/null
+++ b/src/java/com/jogamp/gluegen/cgram/types/AliasedSymbol.java
@@ -0,0 +1,185 @@
+/**
+ * Copyright 2015 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.gluegen.cgram.types;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Supports symbol aliasing, i.e. renaming,
+ * while preserving all its original names, i.e. aliases.
+ */
+public interface AliasedSymbol {
+    /**
+     * Rename this symbol with the given {@code newName} if not equal {@link #getName() current-name}.
+     * <p>
+     * Before renaming the {@link #getName() current-name} will be added
+     * to the list of {@link #getAliasedNames() aliases}.
+     * while the given {@code newName} will be removed.
+     * </p>
+     * <p>
+     * Operation will be ignored if {@code newName} is {@code null}.
+     * </p>
+     * @param newName the new {@link #getName() current-name}, maybe {@code null}
+     */
+    void rename(final String newName);
+    /**
+     * Add the given {@code origName} to the list of {@link #getAliasedNames() aliases}
+     * if not equal {@link #getName() current-name}.
+     * <p>
+     * Operation will be ignored if {@code newName} is {@code null}.
+     * </p>
+     * @param origName the new alias to be added, maybe {@code null}
+     */
+    void addAliasedName(final String origName);
+    /**
+     *
+     * Returns {@code true} if this symbol has aliases, i.e. either being {@link #rename(String) renamed}
+     * or {@link #addAliasedName(String) aliases-added}.
+     * <p>
+     * Otherwise {@code false} is being returned.
+     * </p>
+     */
+    boolean hasAliases();
+    /**
+     * Return all aliases for this symbol, i.e. original names, for this symbol.
+     * <p>
+     * Inclusive {@link #getOrigName() original-name}, if {@link #rename(String) renamed},
+     * </p>
+     * <p>
+     * Exclusive {@link #getName() current-name}.
+     * </p>
+     * <p>
+     * May return {@code null} or a zero sized {@link Set} for no aliases.
+     * </p>
+     */
+    Set<String> getAliasedNames();
+    /**
+     * Return the original-name as set at creation.
+     */
+    String getOrigName();
+    /**
+     * Return the current-name, which is the last {@link #rename(String) renamed-name} if issued,
+     * or the {@link #getOrigName() original-name}.
+     */
+    String getName();
+    /**
+     * Return this object's {@link #toString()} wrapped w/ the {@link #getName() current-name}
+     * and all {@link #getAliasedNames() aliases}.
+     */
+    String getAliasedString();
+
+    public static class AliasedSymbolImpl implements AliasedSymbol {
+        private final String origName;
+        private final HashSet<String> aliasedNames;
+        private String name;
+
+        public AliasedSymbolImpl(final String origName) {
+            if( null == origName ) {
+                throw new IllegalArgumentException("Null origName not allowed");
+            }
+            this.origName = origName;
+            this.aliasedNames=new HashSet<String>();
+            this.name = origName;
+        }
+        public AliasedSymbolImpl(final AliasedSymbolImpl o) {
+            this.origName = o.origName;
+            this.aliasedNames = new HashSet<String>(o.aliasedNames);
+            this.name = o.name;
+        }
+        @Override
+        public void rename(final String newName) {
+            if( null != newName && !name.equals(newName) ) {
+                aliasedNames.add(name);
+                aliasedNames.remove(newName);
+                name = newName;
+            }
+        }
+        @Override
+        public void addAliasedName(final String origName) {
+            if( null != origName && !name.equals(origName) ) {
+                aliasedNames.add(origName);
+            }
+        }
+        @Override
+        public boolean hasAliases() {
+            return aliasedNames.size() > 0;
+        }
+        @Override
+        public Set<String> getAliasedNames() {
+            return aliasedNames;
+        }
+        @Override
+        public String getOrigName() {
+            return origName;
+        }
+        @Override
+        public String getName() {
+            return name;
+        }
+        @Override
+        public String getAliasedString() {
+            return "["+name+", aliases "+aliasedNames.toString()+", "+toString()+"]";
+        }
+    }
+    public static class NoneAliasedSymbol implements AliasedSymbol {
+        private final String name;
+
+        public NoneAliasedSymbol(final String origName) {
+            this.name = origName;
+        }
+        @Override
+        public void rename(final String newName) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public void addAliasedName(final String origName) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public boolean hasAliases() {
+            return false;
+        }
+        @Override
+        public Set<String> getAliasedNames() {
+            return null;
+        }
+        @Override
+        public String getOrigName() {
+            return name;
+        }
+        @Override
+        public String getName() {
+            return name;
+        }
+        @Override
+        public String getAliasedString() {
+            return toString();
+        }
+    }
+}
diff --git a/src/java/com/jogamp/gluegen/cgram/types/ArrayType.java b/src/java/com/jogamp/gluegen/cgram/types/ArrayType.java
index d867b40..ada34f7 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/ArrayType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/ArrayType.java
@@ -40,6 +40,8 @@
 
 package com.jogamp.gluegen.cgram.types;
 
+import com.jogamp.gluegen.ASTLocusTag;
+
 /** Represents an array type. This differs from a pointer type in C
     syntax by the use of "[]" rather than "*". The length may or may
     not be known; if the length is unknown then a negative number
@@ -48,50 +50,79 @@ package com.jogamp.gluegen.cgram.types;
 public class ArrayType extends MemoryLayoutType implements Cloneable {
   private final Type elementType;
   private final int length;
-  private String computedName;
 
-  public ArrayType(final Type elementType, final SizeThunk sizeInBytes, final int length, final int cvAttributes) {
-    super(elementType.getName() + " *", sizeInBytes, cvAttributes);
+  public ArrayType(final Type elementType, final SizeThunk sizeInBytes, final int length,
+                   final int cvAttributes) {
+    this(elementType, sizeInBytes, length, cvAttributes, null);
+  }
+  public ArrayType(final Type elementType, final SizeThunk sizeInBytes, final int length,
+                   final int cvAttributes, final ASTLocusTag astLocus) {
+    super(elementType.getName() + " *", sizeInBytes, cvAttributes, astLocus);
     this.elementType = elementType;
     this.length      = length;
   }
+  private ArrayType(final ArrayType o, final int cvAttributes, final ASTLocusTag astLocus) {
+    super(o, cvAttributes, astLocus);
+    elementType = o.elementType;
+    length      = o.length;
+  }
 
   @Override
-  public boolean equals(final Object arg) {
-    if (arg == this) return true;
-    if (arg == null || (!(arg instanceof ArrayType))) {
-      return false;
-    }
+  Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+    return new ArrayType(this, cvAttributes, astLocus);
+  }
+
+  @Override
+  protected int hashCodeImpl() {
+    // 31 * x == (x << 5) - x
+    final int hash = elementType.hashCode();
+    return ((hash << 5) - hash) + length;
+  }
+
+  @Override
+  protected boolean equalsImpl(final Type arg) {
     final ArrayType t = (ArrayType) arg;
-    return (super.equals(arg) && elementType.equals(t.elementType) && (length == t.length));
+    return elementType.equals(t.elementType) &&
+           length == t.length;
   }
 
   @Override
+  protected int hashCodeSemanticsImpl() {
+    // 31 * x == (x << 5) - x
+    final int hash = elementType.hashCodeSemantics();
+    return ((hash << 5) - hash) + length;
+  }
+
+  @Override
+  protected boolean equalSemanticsImpl(final Type arg) {
+    final ArrayType t = (ArrayType) arg;
+    return elementType.equalSemantics(t.elementType) &&
+           length == t.length;
+  }
+
+  @Override
+  public boolean isAnon() { return elementType.isAnon(); }
+
+  @Override
   public String getName(final boolean includeCVAttrs) {
-    // Lazy computation of name due to lazy setting of compound type
-    // names during parsing
-    // Note: don't think cvAttributes can be set for array types (unlike pointer types)
-    if (computedName == null) {
-      computedName = (elementType.getName() + " *").intern();
-    }
-    return computedName;
+    return elementType.getName() + " *";
   }
 
   @Override
-  public ArrayType asArray()      { return this; }
+  public final ArrayType asArray()      { return this; }
 
   public Type    getElementType() { return elementType; }
   public int     getLength()      { return length;      }
   public boolean hasLength()      { return length >= 0; }
 
   @Override
-  public Type getBaseElementType() {
-    ArrayType t = this;
-    while (t.getElementType().isArray()) {
-      t = t.getElementType().asArray();
-    }
-    return t.getElementType();
-    // return elementType.getBaseElementType();
+  public final Type getBaseElementType() {
+    return elementType.getBaseElementType();
+  }
+
+  @Override
+  public final int arrayDimension() {
+    return 1 + elementType.arrayDimension();
   }
 
   /** Recompute the size of this array if necessary. This needs to be
@@ -114,7 +145,7 @@ public class ArrayType extends MemoryLayoutType implements Cloneable {
     if(elementType.isConst()) {
         buf.append("const ");
     }
-    buf.append(elementType.getName());
+    buf.append(elementType.getCName());
     if (variableName != null) {
       buf.append(" ");
       buf.append(variableName);
@@ -130,9 +161,4 @@ public class ArrayType extends MemoryLayoutType implements Cloneable {
     super.visit(arg);
     elementType.visit(arg);
   }
-
-  @Override
-  Type newCVVariant(final int cvAttributes) {
-    return new ArrayType(elementType, getSize(), length, cvAttributes);
-  }
 }
diff --git a/src/java/com/jogamp/gluegen/cgram/types/BitType.java b/src/java/com/jogamp/gluegen/cgram/types/BitType.java
index 2644551..834ff95 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/BitType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/BitType.java
@@ -40,6 +40,8 @@
 
 package com.jogamp.gluegen.cgram.types;
 
+import com.jogamp.gluegen.ASTLocusTag;
+
 /** Represents a bitfield in a struct. */
 
 public class BitType extends IntType implements Cloneable {
@@ -47,22 +49,60 @@ public class BitType extends IntType implements Cloneable {
   private final int sizeInBits;
   private final int offset;
 
-  public BitType(final IntType underlyingType, final int sizeInBits, final int lsbOffset, final int cvAttributes) {
-    super(underlyingType.getName(), underlyingType.getSize(), underlyingType.isUnsigned(), cvAttributes);
+  public BitType(final IntType underlyingType, final int sizeInBits, final int lsbOffset,
+                 final int cvAttributes, final ASTLocusTag astLocus) {
+    super(underlyingType.getName(), underlyingType.getSize(), underlyingType.isUnsigned(), cvAttributes, astLocus);
     this.underlyingType = underlyingType;
     this.sizeInBits = sizeInBits;
     this.offset = lsbOffset;
   }
 
+  private BitType(final BitType o, final int cvAttributes, final ASTLocusTag astLocus) {
+      super(o, cvAttributes, astLocus);
+      underlyingType = o.underlyingType;
+      sizeInBits = o.sizeInBits;
+      offset = o.offset;
+  }
+
+  @Override
+  Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+    return new BitType(this, cvAttributes, astLocus);
+  }
+
+  @Override
+  protected int hashCodeImpl() {
+      // 31 * x == (x << 5) - x
+      int hash = super.hashCodeImpl();
+      hash = ((hash << 5) - hash) + underlyingType.hashCode();
+      hash = ((hash << 5) - hash) + sizeInBits;
+      return ((hash << 5) - hash) + offset;
+  }
+
   @Override
-  public boolean equals(final Object arg) {
-    if (arg == this) return true;
-    if (arg == null || (!(arg instanceof BitType))) {
-      return false;
-    }
-    final BitType t = (BitType) arg;
-    return (super.equals(arg) && underlyingType.equals(t.underlyingType) &&
-            (sizeInBits == t.sizeInBits) && (offset == t.offset));
+  protected boolean equalsImpl(final Type arg) {
+      final BitType t = (BitType) arg;
+      return super.equalsImpl(arg) &&
+             underlyingType.equals(t.underlyingType) &&
+             sizeInBits == t.sizeInBits &&
+             offset == t.offset;
+  }
+
+  @Override
+  protected int hashCodeSemanticsImpl() {
+      // 31 * x == (x << 5) - x
+      int hash = super.hashCodeSemanticsImpl();
+      hash = ((hash << 5) - hash) + underlyingType.hashCodeSemantics();
+      hash = ((hash << 5) - hash) + sizeInBits;
+      return ((hash << 5) - hash) + offset;
+  }
+
+  @Override
+  protected boolean equalSemanticsImpl(final Type arg) {
+      final BitType t = (BitType) arg;
+      return super.equalSemanticsImpl(arg) &&
+             underlyingType.equalSemantics(t.underlyingType) &&
+             sizeInBits == t.sizeInBits &&
+             offset == t.offset;
   }
 
   @Override
@@ -84,9 +124,4 @@ public class BitType extends IntType implements Cloneable {
     super.visit(arg);
     underlyingType.visit(arg);
   }
-
-  @Override
-  Type newCVVariant(final int cvAttributes) {
-    return new BitType(underlyingType, sizeInBits, offset, cvAttributes);
-  }
 }
diff --git a/src/java/com/jogamp/gluegen/cgram/types/CompoundType.java b/src/java/com/jogamp/gluegen/cgram/types/CompoundType.java
index 9716f54..56bcdda 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/CompoundType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/CompoundType.java
@@ -42,73 +42,110 @@ package com.jogamp.gluegen.cgram.types;
 
 import java.util.*;
 
+import com.jogamp.gluegen.ASTLocusTag;
+
 /** Models all compound types, i.e., those containing fields: structs
     and unions. The boolean type accessors indicate how the type is
     really defined. */
 
-public abstract class CompoundType extends MemoryLayoutType implements Cloneable {
+public abstract class CompoundType extends MemoryLayoutType implements Cloneable, AliasedSymbol {
   // The name "foo" in the construct "struct foo { ... }";
-  private String structName;
+  private final String structName;
   private ArrayList<Field> fields;
   private boolean visiting;
   private boolean bodyParsed;
-  private boolean computedHashcode;
-  private int     hashcode;
 
-  CompoundType(final String name, final SizeThunk size, final int cvAttributes, final String structName) {
-    super(name, size, cvAttributes);
-    this.structName = structName;
+  @Override
+  public void rename(final String newName) {
+      throw new UnsupportedOperationException();
   }
-
-  public static CompoundType create(final String name, final SizeThunk size, final CompoundTypeKind kind, final int cvAttributes) {
+  @Override
+  public void addAliasedName(final String origName) {
+      throw new UnsupportedOperationException();
+  }
+  @Override
+  public boolean hasAliases() {
+      return false;
+  }
+  @Override
+  public Set<String> getAliasedNames() {
+      return null;
+  }
+  @Override
+  public String getAliasedString() {
+      return toString();
+  }
+  @Override
+  public String getOrigName() {
+      return getName();
+  }
+  /**
+   * @param structName struct name of this CompoundType, i.e. the "foo" in the
+                       construct {@code struct foo { int a, ... };} or {@code struct foo;} <i>even</i> for anonymous structs.
+   * @param size
+   * @param kind
+   * @param cvAttributes
+   * @return
+   */
+  public static CompoundType create(final String structName, final SizeThunk size,
+                                    final CompoundTypeKind kind, final int cvAttributes,
+                                    final ASTLocusTag astLocus)
+  {
+    final CompoundType res;
     switch (kind) {
       case STRUCT:
-          return new StructType(name, size, cvAttributes);
+          res = new StructType(null, size, cvAttributes, structName, astLocus);
+          break;
       case UNION:
-          return new UnionType(name, size, cvAttributes);
+          res = new UnionType(null, size, cvAttributes, structName, astLocus);
+          break;
       default:
           throw new RuntimeException("OO relation "+kind+" / Compount not yet supported");
     }
+    return res;
   }
 
-  @Override
-  public Object clone() {
-    final CompoundType n = (CompoundType) super.clone();
-    if(null!=this.fields) {
-        n.fields = new ArrayList<Field>(this.fields);
+  CompoundType(final String name, final SizeThunk size, final int cvAttributes,
+               final String structName, final ASTLocusTag astLocus) {
+    super(null == name ? structName : name, size, cvAttributes, astLocus);
+    this.structName = structName;
+  }
+
+  CompoundType(final CompoundType o, final int cvAttributes, final ASTLocusTag astLocus) {
+    super(o, cvAttributes, astLocus);
+    this.structName = o.structName;
+    if(null != o.fields) {
+        fields = new ArrayList<Field>(o.fields);
     }
-    return n;
+    bodyParsed = o.bodyParsed;
   }
 
   @Override
-  public int hashCode() {
-    if (computedHashcode) {
-      return hashcode;
-    }
+  protected int hashCodeImpl() {
+      // 31 * x == (x << 5) - x
+      final int hash = 31 + ( null != structName ? structName.hashCode() : 0 );
+      return ((hash << 5) - hash) + TypeComparator.listsHashCode(fields);
+  }
 
-    if (structName != null) {
-      hashcode = structName.hashCode();
-    } else if (getName() != null) {
-      hashcode = getName().hashCode();
-    } else {
-      hashcode = 0;
-    }
+  @Override
+  protected boolean equalsImpl(final Type arg) {
+    final CompoundType ct = (CompoundType) arg;
+    return ( (structName == null ? ct.structName == null : structName.equals(ct.structName)) ||
+             (structName != null && structName.equals(ct.structName))
+           ) &&
+           TypeComparator.listsEqual(fields, ct.fields);
+  }
 
-    computedHashcode = true;
-    return hashcode;
+  @Override
+  protected int hashCodeSemanticsImpl() {
+      // 31 * x == (x << 5) - x
+      return TypeComparator.listsHashCodeSemantics(fields);
   }
 
   @Override
-  public boolean equals(final Object arg) {
-    if (arg == this) return true;
-    if (arg == null || !(arg instanceof CompoundType)) {
-      return false;
-    }
-    final CompoundType t = (CompoundType) arg;
-    return super.equals(arg) &&
-        ((structName == null ? t.structName == null : structName.equals(t.structName)) ||
-         (structName != null && structName.equals(t.structName))) &&
-        listsEqual(fields, t.fields);
+  protected boolean equalSemanticsImpl(final Type arg) {
+    final CompoundType ct = (CompoundType) arg;
+    return TypeComparator.listsEqualSemantics(fields, ct.fields);
   }
 
   /** Returns the struct name of this CompoundType, i.e. the "foo" in
@@ -117,22 +154,20 @@ public abstract class CompoundType extends MemoryLayoutType implements Cloneable
     return structName;
   }
 
-  /** Sets the struct name of this CompoundType, i.e. the "foo" in the
-      construct "struct foo { ... };". */
-  public void setStructName(final String structName) {
-    this.structName = structName;
-  }
-
   @Override
-  public void setSize(final SizeThunk size) {
-    super.setSize(size);
-  }
+  public CompoundType asCompound() { return this; }
 
   @Override
-  public CompoundType asCompound() { return this; }
+  public String getCName(final boolean includeCVAttrs) {
+      if( isTypedef() ) {
+          return getName(includeCVAttrs);
+      } else {
+          return (isStruct() ? "struct " : "union ")+getName(includeCVAttrs);
+      }
+  }
 
   ArrayList<Field> getFields() { return fields; }
-  void setFields(final ArrayList<Field> fields) { this.fields = fields; }
+  void setFields(final ArrayList<Field> fields) { this.fields = fields; clearCache(); }
 
   /** Returns the number of fields in this type. */
   public int   getNumFields() {
@@ -147,17 +182,24 @@ public abstract class CompoundType extends MemoryLayoutType implements Cloneable
   /** Adds a field to this type. */
   public void addField(final Field f) {
     if (bodyParsed) {
-      throw new RuntimeException("Body of this CompoundType has already been parsed; should not be adding more fields");
+      throw new IllegalStateException("Body of this CompoundType has been already closed");
     }
     if (fields == null) {
       fields = new ArrayList<Field>();
     }
     fields.add(f);
+    clearCache();
   }
 
-  /** Indicates to this CompoundType that its body has been parsed and
-      that no more {@link #addField} operations will be made. */
-  public void setBodyParsed() {
+  /**
+   * Indicates to this CompoundType that its body has been parsed and
+   * that no more {@link #addField} operations will be made.
+   * @throws IllegalStateException If called twice.
+   */
+  public void setBodyParsed() throws IllegalStateException {
+    if (bodyParsed) {
+        throw new IllegalStateException("Body of this CompoundType has been already closed");
+    }
     bodyParsed = true;
   }
 
@@ -169,8 +211,9 @@ public abstract class CompoundType extends MemoryLayoutType implements Cloneable
   @Override
   public String toString() {
     final String cvAttributesString = getCVAttributesString();
-    if (getName() != null) {
-      return cvAttributesString + getName();
+    final String cname = getCName();
+    if ( null != cname ) {
+      return cvAttributesString + cname;
     } else if (getStructName() != null) {
       return cvAttributesString + "struct " + getStructName();
     } else {
@@ -188,12 +231,12 @@ public abstract class CompoundType extends MemoryLayoutType implements Cloneable
       super.visit(arg);
       final int n = getNumFields();
       for (int i = 0; i < n; i++) {
-        final Field f = getField(i);
-        f.getType().visit(arg);
+        getField(i).getType().visit(arg);
       }
     } finally {
       visiting = false;
     }
+    return;
   }
 
   public String getStructString() {
diff --git a/src/java/com/jogamp/gluegen/cgram/types/DoubleType.java b/src/java/com/jogamp/gluegen/cgram/types/DoubleType.java
index de42522..133a322 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/DoubleType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/DoubleType.java
@@ -39,22 +39,22 @@
  */
 package com.jogamp.gluegen.cgram.types;
 
+import com.jogamp.gluegen.ASTLocusTag;
+
 /** Represents a double-word floating-point type (C type "double".) */
 public class DoubleType extends PrimitiveType implements Cloneable {
 
-    public DoubleType(final String name, final SizeThunk size, final int cvAttributes) {
-        super(name, size, cvAttributes);
+    public DoubleType(final String name, final SizeThunk size, final int cvAttributes, final ASTLocusTag astLocus) {
+        super(name, size, cvAttributes, astLocus);
+    }
+
+    private DoubleType(final DoubleType o, final int cvAttributes, final ASTLocusTag astLocus) {
+        super(o, cvAttributes, astLocus);
     }
 
     @Override
-    public boolean equals(final Object arg) {
-        if (arg == this) {
-            return true;
-        }
-        if (arg == null || (!(arg instanceof DoubleType))) {
-            return false;
-        }
-        return super.equals(arg);
+    Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+        return new DoubleType(this, cvAttributes, astLocus);
     }
 
     @Override
@@ -63,7 +63,22 @@ public class DoubleType extends PrimitiveType implements Cloneable {
     }
 
     @Override
-    Type newCVVariant(final int cvAttributes) {
-        return new DoubleType(getName(), getSize(), cvAttributes);
+    protected int hashCodeImpl() {
+        return 0;
+    }
+
+    @Override
+    protected boolean equalsImpl(final Type t) {
+        return true;
+    }
+
+    @Override
+    protected int hashCodeSemanticsImpl() {
+        return 0;
+    }
+
+    @Override
+    protected boolean equalSemanticsImpl(final Type t) {
+        return true;
     }
 }
diff --git a/src/java/com/jogamp/gluegen/cgram/types/EnumType.java b/src/java/com/jogamp/gluegen/cgram/types/EnumType.java
index 0b1193b..f49c2ec 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/EnumType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/EnumType.java
@@ -42,17 +42,17 @@ package com.jogamp.gluegen.cgram.types;
 import java.util.ArrayList;
 import java.util.NoSuchElementException;
 
+import com.jogamp.gluegen.ASTLocusTag;
+import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp;
+
 
 /** Describes enumerated types. Enumerations are like ints except that
 they have a set of named values. */
 public class EnumType extends IntType implements Cloneable {
 
-    private IntType underlyingType;
-
-    private static class Enum {
-
-        String name;
-        long value;
+    private static class Enum implements TypeComparator.SemanticEqualityOp {
+        final String name;
+        final long value;
 
         Enum(final String name, final long value) {
             this.name = name;
@@ -66,8 +66,40 @@ public class EnumType extends IntType implements Cloneable {
         long getValue() {
             return value;
         }
+
+        @Override
+        public int hashCode() {
+            // 31 * x == (x << 5) - x
+            final int hash = name.hashCode();
+            return ((hash << 5) - hash) + (int)(value ^ (value >>> 32));
+        }
+
+        @Override
+        public boolean equals(final Object arg) {
+            if (arg == this) {
+                return true;
+            } else if ( !(arg instanceof Enum) ) {
+                return false;
+            }
+            final Enum t = (Enum) arg;
+            return name.equals(t.name) &&
+                   value == t.value;
+        }
+
+        @Override
+        public int hashCodeSemantics() {
+            return hashCode();
+        }
+
+        @Override
+        public boolean equalSemantics(final SemanticEqualityOp arg) {
+            return equals(arg);
+        }
+
+        public String toString() { return name+" = "+value; }
     }
 
+    private final IntType underlyingType;
     private ArrayList<Enum> enums;
 
     public EnumType(final String name) {
@@ -75,40 +107,54 @@ public class EnumType extends IntType implements Cloneable {
         this.underlyingType = new IntType(name, SizeThunk.LONG, false, CVAttributes.CONST);
     }
 
-    public EnumType(final String name, final SizeThunk enumSizeInBytes) {
-        super(name, enumSizeInBytes, false, CVAttributes.CONST);
-        this.underlyingType = new IntType(name, enumSizeInBytes, false, CVAttributes.CONST);
+    public EnumType(final String name, final SizeThunk enumSizeInBytes, final ASTLocusTag astLocus) {
+        super(name, enumSizeInBytes, false, CVAttributes.CONST, astLocus);
+        this.underlyingType = new IntType(name, enumSizeInBytes, false, CVAttributes.CONST, astLocus);
     }
 
-    protected EnumType(final String name, final IntType underlyingType, final int cvAttributes) {
-        super(name, underlyingType.getSize(), underlyingType.isUnsigned(), cvAttributes);
-        this.underlyingType = underlyingType;
+    private EnumType(final EnumType o, final int cvAttributes, final ASTLocusTag astLocus) {
+        super(o, cvAttributes, astLocus);
+        underlyingType = o.underlyingType;
+        if(null != o.enums) {
+            enums = new ArrayList<Enum>(o.enums);
+        }
     }
 
     @Override
-    public Object clone() {
-        final EnumType n = (EnumType) super.clone();
-        if(null!=this.underlyingType) {
-            n.underlyingType = (IntType) this.underlyingType.clone();
-        }
-        if(null!=this.enums) {
-            n.enums = new ArrayList<Enum>(this.enums);
-        }
-        return n;
+    Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+        return new EnumType(this, cvAttributes, astLocus);
     }
 
     @Override
-    public boolean equals(final Object arg) {
-        if (arg == this) {
-            return true;
-        }
-        if (arg == null || (!(arg instanceof EnumType))) {
-            return false;
-        }
+    protected int hashCodeImpl() {
+      // 31 * x == (x << 5) - x
+      int hash = super.hashCodeImpl();
+      hash = ((hash << 5) - hash) + underlyingType.hashCode();
+      return ((hash << 5) - hash) + TypeComparator.listsHashCode(enums);
+    }
+
+    @Override
+    protected boolean equalsImpl(final Type arg) {
+        final EnumType t = (EnumType) arg;
+        return super.equalsImpl(arg) &&
+                underlyingType.equals(t.underlyingType) &&
+               TypeComparator.listsEqual(enums, t.enums);
+    }
+
+    @Override
+    protected int hashCodeSemanticsImpl() {
+      // 31 * x == (x << 5) - x
+      int hash = super.hashCodeSemanticsImpl();
+      hash = ((hash << 5) - hash) + underlyingType.hashCodeSemantics();
+      return ((hash << 5) - hash) + TypeComparator.listsHashCodeSemantics(enums);
+    }
+
+    @Override
+    protected boolean equalSemanticsImpl(final Type arg) {
         final EnumType t = (EnumType) arg;
-        return (super.equals(arg)
-                && underlyingType.equals(t.underlyingType)
-                && listsEqual(enums, t.enums));
+        return super.equalSemanticsImpl(arg) &&
+                underlyingType.equalSemantics(t.underlyingType) &&
+               TypeComparator.listsEqualSemantics(enums, t.enums);
     }
 
     @Override
@@ -116,11 +162,14 @@ public class EnumType extends IntType implements Cloneable {
         return this;
     }
 
+    public Type getUnderlyingType() { return this.underlyingType; }
+
     public void addEnum(final String name, final long val) {
         if (enums == null) {
             enums = new ArrayList<Enum>();
         }
         enums.add(new Enum(name, val));
+        clearCache();
     }
 
     /** Number of enumerates defined in this enum. */
@@ -169,22 +218,27 @@ public class EnumType extends IntType implements Cloneable {
             final Enum e = enums.get(i);
             if (e.getName().equals(name)) {
                 enums.remove(e);
+                clearCache();
                 return true;
             }
         }
         return false;
     }
 
+    public StringBuilder appendEnums(final StringBuilder sb, final boolean cr) {
+        for(int i=0; i<enums.size(); i++) {
+            sb.append(enums.get(i)).append(", ");
+            if( cr ) {
+                sb.append(String.format("%n"));
+            }
+        }
+        sb.append("}");
+        return sb;
+    }
+
     @Override
     public void visit(final TypeVisitor arg) {
         super.visit(arg);
         underlyingType.visit(arg);
     }
-
-    @Override
-    Type newCVVariant(final int cvAttributes) {
-        final EnumType t = new EnumType(getName(), underlyingType, cvAttributes);
-        t.enums = enums;
-        return t;
-    }
 }
diff --git a/src/java/com/jogamp/gluegen/cgram/types/Field.java b/src/java/com/jogamp/gluegen/cgram/types/Field.java
index afaeade..a8fc599 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/Field.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/Field.java
@@ -39,11 +39,12 @@
 
 package com.jogamp.gluegen.cgram.types;
 
-import com.jogamp.common.os.MachineDescription;
+import com.jogamp.common.os.MachineDataInfo;
+import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp;
 
 /** Represents a field in a struct or union. */
 
-public class Field {
+public class Field implements SemanticEqualityOp {
   private final String    name;
   private final Type      type;
   private SizeThunk offset;
@@ -56,21 +57,41 @@ public class Field {
 
   @Override
   public int hashCode() {
-    return name.hashCode();
+    // 31 * x == (x << 5) - x
+    final int hash = 31 + ( null != name ? name.hashCode() : 0 );
+    return ((hash << 5) - hash) + type.hashCode();
   }
 
   @Override
   public boolean equals(final Object arg) {
-    if (arg == null || (!(arg instanceof Field))) {
+    if ( !(arg instanceof Field) ) {
       return false;
     }
 
     final Field f = (Field) arg;
     // Note: don't know how to examine offset any more since it's
     // implemented in terms of code and they're not canonicalized
-    return (((name != null && name.equals(f.name)) ||
-             (name == null && f.name == null)) &&
-            type.equals(f.type));
+    return ( ( name != null && name.equals(f.name) ) ||
+             ( name == null && f.name == null )
+           ) &&
+           type.equals(f.type);
+  }
+
+  @Override
+  public int hashCodeSemantics() {
+    return type.hashCodeSemantics();
+  }
+
+  @Override
+  public boolean equalSemantics(final SemanticEqualityOp arg) {
+    if ( !(arg instanceof Field) ) {
+      return false;
+    }
+
+    final Field f = (Field) arg;
+    // Note: don't know how to examine offset any more since it's
+    // implemented in terms of code and they're not canonicalized
+    return type.equalSemantics(f.type);
   }
 
   /** Name of this field in the containing data structure. */
@@ -83,8 +104,8 @@ public class Field {
   public SizeThunk getOffset() { return offset; }
 
   /** Offset, in bytes, of this field in the containing data structure
-      given the specified MachineDescription. */
-  public long    getOffset(final MachineDescription machDesc) { return offset.computeSize(machDesc); }
+      given the specified MachineDataInfo. */
+  public long    getOffset(final MachineDataInfo machDesc) { return offset.computeSize(machDesc); }
 
   /** Sets the offset of this field in the containing data structure. */
   public void    setOffset(final SizeThunk offset) { this.offset = offset; }
diff --git a/src/java/com/jogamp/gluegen/cgram/types/FloatType.java b/src/java/com/jogamp/gluegen/cgram/types/FloatType.java
index d8b0b13..2e7a2cf 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/FloatType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/FloatType.java
@@ -40,29 +40,44 @@
 
 package com.jogamp.gluegen.cgram.types;
 
+import com.jogamp.gluegen.ASTLocusTag;
+
 /** Represents a single-word floating-point type (C type "float".) */
 
 public class FloatType extends PrimitiveType implements Cloneable {
-  public FloatType(final String name, final SizeThunk size, final int cvAttributes) {
-    super(name, size, cvAttributes);
+  public FloatType(final String name, final SizeThunk size, final int cvAttributes, final ASTLocusTag astLocus) {
+    super(name, size, cvAttributes, astLocus);
+  }
+
+  private FloatType(final FloatType o, final int cvAttributes, final ASTLocusTag astLocus) {
+      super(o, cvAttributes, astLocus);
   }
 
   @Override
-  public boolean equals(final Object arg) {
-    if (arg == this) {
-      return true;
-    }
-    if (arg == null || (!(arg instanceof FloatType))) {
-      return false;
-    }
-    return super.equals(arg);
+  Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+    return new FloatType(this, cvAttributes, astLocus);
   }
 
   @Override
   public FloatType asFloat() { return this; }
 
   @Override
-  Type newCVVariant(final int cvAttributes) {
-    return new FloatType(getName(), getSize(), cvAttributes);
+  protected int hashCodeImpl() {
+      return 0;
+  }
+
+  @Override
+  protected boolean equalsImpl(final Type t) {
+      return true;
+  }
+
+  @Override
+  protected int hashCodeSemanticsImpl() {
+      return 0;
+  }
+
+  @Override
+  protected boolean equalSemanticsImpl(final Type t) {
+      return true;
   }
 }
diff --git a/src/java/com/jogamp/gluegen/cgram/types/FunctionSymbol.java b/src/java/com/jogamp/gluegen/cgram/types/FunctionSymbol.java
index d41f2fd..91a0a5a 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/FunctionSymbol.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/FunctionSymbol.java
@@ -38,6 +38,14 @@
  */
 package com.jogamp.gluegen.cgram.types;
 
+import java.util.List;
+
+import com.jogamp.gluegen.ASTLocusTag;
+import com.jogamp.gluegen.ASTLocusTag.ASTLocusTagProvider;
+import com.jogamp.gluegen.cgram.types.AliasedSymbol.AliasedSymbolImpl;
+import com.jogamp.gluegen.cgram.types.TypeComparator.AliasedSemanticSymbol;
+import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp;
+
 
 /**
  * Describes a function symbol, which includes the name and
@@ -51,20 +59,37 @@ package com.jogamp.gluegen.cgram.types;
  * Deep comparison can be performed via {@link #isCompletelyEqual(Object o)};
  * </p>
  **/
-public class FunctionSymbol {
+public class FunctionSymbol extends AliasedSymbolImpl implements AliasedSemanticSymbol, ASTLocusTagProvider {
 
-    private final String name;
     private final FunctionType type;
+    private final ASTLocusTag astLocus;
 
     public FunctionSymbol(final String name, final FunctionType type) {
-        this.name = name;
+        super(name);
+        this.type = type;
+        this.astLocus = null;
+    }
+
+    public FunctionSymbol(final String name, final FunctionType type, final ASTLocusTag locus) {
+        super(name);
         this.type = type;
+        this.astLocus = locus;
     }
 
-    public String getName() {
-        return name;
+    /** Shallow'ish copy, only aliased names are re-created. */
+    public static FunctionSymbol cloneWithDeepAliases(final FunctionSymbol o) {
+        return new FunctionSymbol(o);
+    }
+    /** Warning: Shallow'ish copy, only aliased names are re-created. */
+    private FunctionSymbol(final FunctionSymbol o) {
+        super(o);
+        this.type = o.type;
+        this.astLocus = o.astLocus;
     }
 
+    @Override
+    public ASTLocusTag getASTLocusTag() { return astLocus; }
+
     /** Returns the type of this function. Do not add arguments to it
     directly; use addArgument instead. */
     public FunctionType getType() {
@@ -99,7 +124,7 @@ public class FunctionSymbol {
 
     @Override
     public String toString() {
-        return getType().toString(getName());
+        return getType().toString(getName(), false);
     }
 
     /** Helper routine for emitting native javadoc tags */
@@ -109,10 +134,10 @@ public class FunctionSymbol {
 
     @Override
     public int hashCode() {
-        if (name == null) {
+        if (getName() == null) {
             return 0;
         }
-        return name.hashCode();
+        return getName().hashCode();
     }
 
     @Override
@@ -120,25 +145,54 @@ public class FunctionSymbol {
         if (arg == this) {
             return true;
         }
-
-        if (arg == null || (!(arg instanceof FunctionSymbol))) {
+        if ( !(arg instanceof FunctionSymbol) ) {
             return false;
         }
-
         final FunctionSymbol other = (FunctionSymbol) arg;
-
         if (getName() == null && other.getName() != null) {
             return false;
         }
-
         return getName().equals(other.getName());
     }
 
+    @Override
+    public int hashCodeSemantics() {
+        return type.hashCodeSemantics();
+    }
+    @Override
+    public final boolean equalSemantics(final SemanticEqualityOp arg) {
+        if (arg == this) {
+            return true;
+        }
+        if ( !(arg instanceof FunctionSymbol) ) {
+            return false;
+        }
+        final FunctionSymbol other = (FunctionSymbol) arg;
+        return type.equalSemantics(other.type);
+    }
+
+
+    public static boolean containsExactly(final List<FunctionSymbol> l, final FunctionSymbol s) {
+        return exactIndexOf(l, s) >= 0;
+    }
+
+    public static int exactIndexOf(final List<FunctionSymbol> l, final FunctionSymbol s) {
+        final int size = l.size();
+        for (int i = 0; i < size; i++) {
+            final FunctionSymbol e = l.get(i);
+            if( null == s && null == e ||
+                s.equals( e ) && s.type.equals(e.type) ) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
     /**
      * Compares the function type as well, since {@link #equals(Object)}
      * and {@link #hashCode()} won't.
      */
-    public boolean isCompletelyEqual(final Object arg) {
+    public boolean exactlyEqual(final Object arg) {
         if( !this.equals(arg) ) {
             return false;
         }
diff --git a/src/java/com/jogamp/gluegen/cgram/types/FunctionType.java b/src/java/com/jogamp/gluegen/cgram/types/FunctionType.java
index 4b39a34..2b9dec7 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/FunctionType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/FunctionType.java
@@ -41,6 +41,8 @@ package com.jogamp.gluegen.cgram.types;
 
 import java.util.*;
 
+import com.jogamp.gluegen.ASTLocusTag;
+
 /** Describes a function type, used to model both function
 declarations and (via PointerType) function pointers. */
 public class FunctionType extends Type implements Cloneable {
@@ -49,35 +51,63 @@ public class FunctionType extends Type implements Cloneable {
     private ArrayList<Type> argumentTypes;
     private ArrayList<String> argumentNames;
 
-    public FunctionType(final String name, final SizeThunk size, final Type returnType, final int cvAttributes) {
-        super(name, size, cvAttributes);
+    public FunctionType(final String name, final SizeThunk size, final Type returnType,
+                        final int cvAttributes) {
+        this(name, size, returnType, cvAttributes, null);
+    }
+    public FunctionType(final String name, final SizeThunk size, final Type returnType,
+                        final int cvAttributes, final ASTLocusTag astLocus) {
+        super(name, size, cvAttributes, astLocus);
         this.returnType = returnType;
     }
 
-    @Override
-    public Object clone() {
-        final FunctionType n = (FunctionType) super.clone();
-        if(null!=this.argumentTypes) {
-            n.argumentTypes = new ArrayList<Type>(this.argumentTypes);
+    private FunctionType(final FunctionType o, final ASTLocusTag astLocus) {
+        super(o, o.getCVAttributes(), astLocus);
+        returnType = o.returnType;
+        if(null != o.argumentTypes) {
+            argumentTypes = new ArrayList<Type>(o.argumentTypes);
         }
-        if(null!=this.argumentNames) {
-            n.argumentNames = new ArrayList<String>(this.argumentNames);
+        if(null != o.argumentNames) {
+            argumentNames = new ArrayList<String>(o.argumentNames);
         }
-        return n;
     }
 
     @Override
-    public boolean equals(final Object arg) {
-        if (arg == this) {
-            return true;
-        }
-        if (arg == null || (!(arg instanceof FunctionType))) {
-            return false;
+    Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+        if( newCVVariant ) {
+            // Functions don't have const/volatile attributes
+            return this;
+        } else {
+            return new FunctionType(this, astLocus);
         }
+    }
+
+    @Override
+    protected int hashCodeImpl() {
+        // 31 * x == (x << 5) - x
+        final int hash = returnType.hashCode();
+        return ((hash << 5) - hash) + TypeComparator.listsHashCode(argumentTypes);
+    }
+
+    @Override
+    protected boolean equalsImpl(final Type arg) {
         final FunctionType t = (FunctionType) arg;
-        return (super.equals(arg)
-                && returnType.equals(t.returnType)
-                && listsEqual(argumentTypes, t.argumentTypes));
+        return returnType.equals(t.returnType) &&
+               TypeComparator.listsEqual(argumentTypes, t.argumentTypes);
+    }
+
+    @Override
+    protected int hashCodeSemanticsImpl() {
+        // 31 * x == (x << 5) - x
+        final int hash = returnType.hashCodeSemantics();
+        return ((hash << 5) - hash) + TypeComparator.listsHashCodeSemantics(argumentTypes);
+    }
+
+    @Override
+    protected boolean equalSemanticsImpl(final Type arg) {
+        final FunctionType t = (FunctionType) arg;
+        return returnType.equalSemantics(t.returnType) &&
+               TypeComparator.listsEqualSemantics(argumentTypes, t.argumentTypes);
     }
 
     @Override
@@ -115,28 +145,27 @@ public class FunctionType extends Type implements Cloneable {
         }
         argumentTypes.add(argumentType);
         argumentNames.add(argumentName);
+        clearCache();
     }
 
     public void setArgumentName(final int i, final String name) {
         argumentNames.set(i, name);
+        clearCache();
     }
 
     @Override
     public String toString() {
-        return toString(null);
-    }
-
-    public String toString(final String functionName) {
-        return toString(functionName, false);
+        return toString(null, false);
     }
 
     public String toString(final String functionName, final boolean emitNativeTag) {
         return toString(functionName, null, emitNativeTag, false);
     }
 
-    String toString(final String functionName, final String callingConvention, final boolean emitNativeTag, final boolean isPointer) {
+    String toString(final String functionName, final String callingConvention,
+                    final boolean emitNativeTag, final boolean isPointer) {
         final StringBuilder res = new StringBuilder();
-        res.append(getReturnType());
+        res.append(getReturnType().getCName(true));
         res.append(" ");
         if (isPointer) {
             res.append("(");
@@ -169,7 +198,7 @@ public class FunctionType extends Type implements Cloneable {
             } else if (t.isArray()) {
                 res.append(t.asArray().toString(getArgumentName(i)));
             } else {
-                res.append(t);
+                res.append(t.getCName(true));
                 final String argumentName = getArgumentName(i);
                 if (argumentName != null) {
                     res.append(" ");
@@ -193,10 +222,4 @@ public class FunctionType extends Type implements Cloneable {
             getArgumentType(i).visit(arg);
         }
     }
-
-    @Override
-    Type newCVVariant(final int cvAttributes) {
-        // Functions don't have const/volatile attributes
-        return this;
-    }
 }
diff --git a/src/java/com/jogamp/gluegen/cgram/types/IntType.java b/src/java/com/jogamp/gluegen/cgram/types/IntType.java
index 3f8dddc..2433fc6 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/IntType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/IntType.java
@@ -39,37 +39,95 @@
  */
 package com.jogamp.gluegen.cgram.types;
 
+import com.jogamp.gluegen.ASTLocusTag;
+
 public class IntType extends PrimitiveType implements Cloneable {
 
     private final boolean unsigned;
-    private boolean typedefedUnsigned;
+    private boolean typedefUnsigned;
 
     public IntType(final String name, final SizeThunk size, final boolean unsigned, final int cvAttributes) {
-        this(name, size, unsigned, cvAttributes, false);
+        this(name, size, unsigned, cvAttributes, null);
     }
 
-    public IntType(final String name, final SizeThunk size, final boolean unsigned, final int cvAttributes, final boolean typedefedUnsigned) {
-        super(name, size, cvAttributes);
+    public IntType(final String name, final SizeThunk size,
+                   final boolean unsigned, final int cvAttributes,
+                   final ASTLocusTag astLocus) {
+        super(name, size, cvAttributes, astLocus);
         this.unsigned = unsigned;
-        this.typedefedUnsigned = typedefedUnsigned;
+        this.typedefUnsigned = false;
     }
 
-    @Override
-    public boolean equals(final Object arg) {
-        if (arg == this) {
-            return true;
-        }
-        if (arg == null || (!(arg instanceof IntType))) {
-            return false;
+    /**
+     * Only for HeaderParser!
+     *
+     * @param name  the name
+     * @param size  the size
+     * @param unsigned true if this instance is unsigned, not the <i>typedef</i>!
+     * @param cvAttributes the cvAttributes for this instance, not for the <i>typedef</i>!
+     * @param isTypedef true if this instance is a <i>typedef</i> variant
+     * @param typedefUnsigned true if the <i>typedef</i> itself is unsigned
+     * @param astLocus the location in source code
+     */
+    public IntType(final String name, final SizeThunk size,
+                   final boolean unsigned, final int cvAttributes,
+                   final boolean isTypedef, final boolean typedefUnsigned,
+                   final ASTLocusTag astLocus) {
+        super(name, size, cvAttributes, astLocus);
+        this.unsigned = unsigned;
+        if( isTypedef ) {
+            // the 'cvAttributes' are intended for this instance, not the 'typedef cvAttributes'!
+            setTypedef(0);
+            this.typedefUnsigned = typedefUnsigned;
+        } else {
+            this.typedefUnsigned = false;
         }
+    }
+
+    IntType(final IntType o, final int cvAttributes, final ASTLocusTag astLocus) {
+        super(o, cvAttributes, astLocus);
+        this.unsigned = o.unsigned;
+        this.typedefUnsigned = o.typedefUnsigned;
+    }
+
+    @Override
+    Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+        return new IntType(this, cvAttributes, astLocus);
+    }
+
+    @Override
+    protected int hashCodeImpl() {
+      // 31 * x == (x << 5) - x
+      int hash = 1;
+      hash = ((hash << 5) - hash) + ( unsigned ? 1 : 0 );
+      return ((hash << 5) - hash) + ( typedefUnsigned ? 1 : 0 );
+    }
+
+    @Override
+    protected boolean equalsImpl(final Type arg) {
         final IntType t = (IntType) arg;
-        return (super.equals(arg) && (unsigned == t.unsigned));
+        return unsigned == t.unsigned &&
+               typedefUnsigned == t.typedefUnsigned;
     }
 
     @Override
-    public void setName(final String name) {
-        super.setName(name);
-        typedefedUnsigned = unsigned;
+    protected int hashCodeSemanticsImpl() {
+      // 31 * x == (x << 5) - x
+      int hash = 1;
+      if( !relaxedEqSem ) {
+        hash = ((hash << 5) - hash) + ( unsigned ? 1 : 0 );
+        hash = ((hash << 5) - hash) + ( typedefUnsigned ? 1 : 0 );
+      }
+      return hash;
+    }
+
+    @Override
+    protected boolean equalSemanticsImpl(final Type arg) {
+        final IntType t = (IntType) arg;
+        return relaxedEqSem ||
+               ( unsigned == t.unsigned &&
+                 typedefUnsigned == t.typedefUnsigned
+               );
     }
 
     @Override
@@ -82,18 +140,27 @@ public class IntType extends PrimitiveType implements Cloneable {
         return unsigned;
     }
 
-    /** Indicates whether this type is an unsigned primitive type, as opposed to a typedef type that's unsigned. */
-    public boolean isPrimitiveUnsigned() {
-        return unsigned && !typedefedUnsigned;
+    @Override
+    public String getCName(final boolean includeCVAttrs) {
+        if ( !unsigned || typedefUnsigned ) {
+            return super.getCName(includeCVAttrs);
+        } else {
+            return "unsigned "+super.getCName(includeCVAttrs);
+        }
     }
 
     @Override
     public String toString() {
-        return getCVAttributesString() + ((isUnsigned() & (!typedefedUnsigned)) ? "unsigned " : "") + getName();
+        return getCVAttributesString() + ( unsigned && !typedefUnsigned ? "unsigned " : "") + getCName();
     }
 
     @Override
-    Type newCVVariant(final int cvAttributes) {
-        return new IntType(getName(), getSize(), isUnsigned(), cvAttributes, typedefedUnsigned);
+    public boolean setTypedefName(final String name) {
+        if( super.setTypedefName(name) ) {
+            typedefUnsigned = unsigned;
+            return true;
+        } else {
+            return false;
+        }
     }
 }
diff --git a/src/java/com/jogamp/gluegen/cgram/types/MemoryLayoutType.java b/src/java/com/jogamp/gluegen/cgram/types/MemoryLayoutType.java
index 25d2d1d..8b06a7e 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/MemoryLayoutType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/MemoryLayoutType.java
@@ -27,15 +27,23 @@
  */
 package com.jogamp.gluegen.cgram.types;
 
+import com.jogamp.gluegen.ASTLocusTag;
+
 public abstract class MemoryLayoutType extends Type {
   private boolean isLayouted;
 
-  protected MemoryLayoutType(final String name, final SizeThunk size, final int cvAttributes) {
-      super(name, size, cvAttributes);
+  protected MemoryLayoutType(final String name, final SizeThunk size, final int cvAttributes, final ASTLocusTag astLocus) {
+      super(name, size, cvAttributes, astLocus);
       isLayouted = false;
   }
+  MemoryLayoutType(final MemoryLayoutType o, final int cvAttributes, final ASTLocusTag astLocus) {
+      super(o, cvAttributes, astLocus);
+      isLayouted = o.isLayouted;
+  }
 
   public boolean isLayouted() { return isLayouted; }
-  public void setLayouted() { isLayouted = true; }
+  public void setLayouted() {
+      isLayouted = true;
+  }
 
 }
diff --git a/src/java/com/jogamp/gluegen/cgram/types/PointerType.java b/src/java/com/jogamp/gluegen/cgram/types/PointerType.java
index d1dfb17..5707b5c 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/PointerType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/PointerType.java
@@ -39,111 +39,124 @@
  */
 package com.jogamp.gluegen.cgram.types;
 
+import com.jogamp.gluegen.ASTLocusTag;
+
 public class PointerType extends Type implements Cloneable {
 
     private final Type targetType;
-    private String computedName;
-    private boolean hasTypedefedName;
 
     public PointerType(final SizeThunk size, final Type targetType, final int cvAttributes) {
+        this(size, targetType, cvAttributes, null);
+    }
+    public PointerType(final SizeThunk size, final Type targetType, final int cvAttributes, final ASTLocusTag astLocus) {
         // can pass null for the final name parameter because the PointerType's getName()
         // completely replaces superclass behavior
-        this(size, targetType, cvAttributes, false, null);
+        super(targetType.getName() + " *", size, cvAttributes, astLocus);
+        this.targetType = targetType;
     }
 
-    private PointerType(final SizeThunk size, final Type targetType, final int cvAttributes, final boolean hasTypedefedName, final String typedefedName) {
-        super(targetType.getName() + " *", size, cvAttributes);
-        this.hasTypedefedName = false;
-        this.targetType = targetType;
-        if (hasTypedefedName) {
-            setName(typedefedName);
-        }
+    private PointerType(final PointerType o, final int cvAttributes, final ASTLocusTag astLocus) {
+        super(o, cvAttributes, astLocus);
+        targetType = o.targetType;
     }
 
     @Override
-    public int hashCode() {
-        return targetType.hashCode();
+    Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+        return new PointerType(this, cvAttributes, astLocus);
     }
 
     @Override
-    public boolean equals(final Object arg) {
-        if (arg == this) {
-            return true;
-        }
-        if (arg == null || (!(arg instanceof PointerType))) {
-            return false;
-        }
+    protected int hashCodeImpl() {
+      return targetType.hashCode();
+    }
+
+    @Override
+    protected boolean equalsImpl(final Type arg) {
         final PointerType t = (PointerType) arg;
-        // Note we ignore the name of this type (which might be a typedef
-        // name) for comparison purposes because this is what allows
-        // e.g. a newly-fabricated type "PIXELFORMATDESCRIPTOR *" to be
-        // canonicalized to e.g. "LPPIXELFORMATDESCRIPTOR"
-        return ((getSize() == t.getSize())
-                && (getCVAttributes() == t.getCVAttributes())
-                && targetType.equals(t.targetType));
+        return targetType.equals(t.targetType);
+    }
+
+    @Override
+    protected int hashCodeSemanticsImpl() {
+      return targetType.hashCodeSemantics();
     }
 
     @Override
-    public void setName(final String name) {
-        super.setName(name);
-        hasTypedefedName = true;
+    protected boolean equalSemanticsImpl(final Type arg) {
+        final PointerType pt = (PointerType) arg;
+        return targetType.equalSemantics(pt.targetType);
+    }
+
+    @Override
+    public boolean isAnon() {
+        if ( isTypedef() ) {
+            return super.isAnon();
+        } else {
+            return targetType.isAnon();
+        }
     }
 
     @Override
     public String getName(final boolean includeCVAttrs) {
-        if (hasTypedefedName) {
+        if ( isTypedef() ) {
             return super.getName(includeCVAttrs);
+        } else if (!includeCVAttrs) {
+            return targetType.getName(includeCVAttrs) + " *";
         } else {
-            // Lazy computation of name due to lazy setting of compound type
-            // names during parsing
-            if (computedName == null) {
-                computedName = (targetType.getName(includeCVAttrs) + " *").intern();
-            }
-            if (!includeCVAttrs) {
-                return computedName;
-            }
             return targetType.getName(includeCVAttrs) + " * " + getCVAttributesString();
         }
     }
 
-    public boolean hasTypedefedName() {
-        return hasTypedefedName;
+    @Override
+    public String getCName(final boolean includeCVAttrs) {
+        if ( isTypedef() ) {
+            return super.getCName(includeCVAttrs);
+        } else if (!includeCVAttrs) {
+            return targetType.getCName(includeCVAttrs) + " *";
+        } else {
+            return targetType.getCName(includeCVAttrs) + " * " + getCVAttributesString();
+        }
     }
 
     @Override
-    public PointerType asPointer() {
+    public final PointerType asPointer() {
         return this;
     }
 
-    public Type getTargetType() {
+    @Override
+    public final Type getTargetType() {
         return targetType;
     }
 
     @Override
-    public Type getBaseElementType() {
-        /**
-        if(targetType.isPointer()) {
-            return ((PointerType)targetType).getBaseElementType();
-        } else {
-            return targetType;
-        } */
+    public final Type getBaseElementType() {
         return targetType.getBaseElementType();
     }
 
     @Override
-    public boolean isFunctionPointer() {
+    public final boolean isFunctionPointer() {
         return targetType.isFunction();
     }
 
     @Override
+    public final int pointerDepth() {
+        return 1 + targetType.pointerDepth();
+    }
+
+    @Override
     public String toString() {
-        if (hasTypedefedName) {
-            return super.getName(true);
+        if ( isTypedef() ) {
+            return super.getCName(true);
+        } else {
+            return toStringInt();
+        }
+    }
+    private String toStringInt() {
+        if (!targetType.isFunction()) {
+            return targetType.getCName(true) + " * " + getCVAttributesString();
         } else {
-            if (!targetType.isFunction()) {
-                return targetType.toString() + " * " + getCVAttributesString();
-            }
-            return toString(null, null); // this is a pointer to an unnamed function
+            // return toString(null, null); // this is a pointer to an unnamed function
+            return ((FunctionType) targetType).toString(null /* functionName */, null /* callingConvention */, false, true);
         }
     }
 
@@ -162,9 +175,4 @@ public class PointerType extends Type implements Cloneable {
         super.visit(arg);
         targetType.visit(arg);
     }
-
-    @Override
-    Type newCVVariant(final int cvAttributes) {
-        return new PointerType(getSize(), targetType, cvAttributes, hasTypedefedName, (hasTypedefedName ? getName() : null));
-    }
 }
diff --git a/src/java/com/jogamp/gluegen/cgram/types/PrimitiveType.java b/src/java/com/jogamp/gluegen/cgram/types/PrimitiveType.java
index 8a86337..76f3ff1 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/PrimitiveType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/PrimitiveType.java
@@ -39,10 +39,16 @@
  */
 package com.jogamp.gluegen.cgram.types;
 
+import com.jogamp.gluegen.ASTLocusTag;
+
 public abstract class PrimitiveType extends Type implements Cloneable {
 
-    protected PrimitiveType(final String name, final SizeThunk size, final int cvAttributes) {
-        super(name, size, cvAttributes);
+    protected PrimitiveType(final String name, final SizeThunk size, final int cvAttributes, final ASTLocusTag astLocus) {
+        super(name, size, cvAttributes, astLocus);
+    }
+
+    PrimitiveType(final PrimitiveType o, final int cvAttributes, final ASTLocusTag astLocus) {
+        super(o, cvAttributes, astLocus);
     }
 
     @Override
diff --git a/src/java/com/jogamp/gluegen/cgram/types/SizeThunk.java b/src/java/com/jogamp/gluegen/cgram/types/SizeThunk.java
index c13e5d5..7a9c62a 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/SizeThunk.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/SizeThunk.java
@@ -40,18 +40,26 @@
 
 package com.jogamp.gluegen.cgram.types;
 
-import com.jogamp.common.os.MachineDescription;
+import com.jogamp.common.os.MachineDataInfo;
+import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp;
 
 /** Provides a level of indirection between the definition of a type's
     size and the absolute value of this size. Necessary when
     generating glue code for two different CPU architectures (e.g.,
     32-bit and 64-bit) from the same internal representation of the
     various types involved. */
-public abstract class SizeThunk implements Cloneable {
+public abstract class SizeThunk implements Cloneable, SemanticEqualityOp {
+  /* pp */ static boolean relaxedEqSem = false;
   private final boolean fixedNativeSize;
 
+  public static void setRelaxedEqualSemanticsTest(final boolean v) {
+      relaxedEqSem = v;
+  }
+
   // Private constructor because there are only a few of these
-  private SizeThunk(final boolean fixedNativeSize) { this.fixedNativeSize = fixedNativeSize; }
+  private SizeThunk(final boolean fixedNativeSize) {
+      this.fixedNativeSize = fixedNativeSize;
+  }
 
   @Override
   public Object clone() {
@@ -64,106 +72,191 @@ public abstract class SizeThunk implements Cloneable {
 
   public final boolean hasFixedNativeSize() { return fixedNativeSize; }
 
-  public abstract long computeSize(MachineDescription machDesc);
-  public abstract long computeAlignment(MachineDescription machDesc);
+  public abstract long computeSize(MachineDataInfo machDesc);
+  public abstract long computeAlignment(MachineDataInfo machDesc);
+
+  @Override
+  public final int hashCode() {
+      final int hash = 0x02DEAD6F; // magic hash start
+      return ((hash << 5) - hash) + hashCodeImpl();
+  }
+  /* pp */ abstract int hashCodeImpl();
+
+  @Override
+  public final boolean equals(final Object arg) {
+    if (arg == this) {
+        return true;
+    } else  if ( !(arg instanceof SizeThunk) ) {
+        return false;
+    } else {
+        final SizeThunk t = (SizeThunk) arg;
+        return hashCodeImpl() == t.hashCodeImpl();
+    }
+  }
+
+  @Override
+  public final int hashCodeSemantics() {
+      final int hash = 0x01DEAD5F; // magic hash start
+      return ((hash << 5) - hash) + hashCodeSemanticsImpl();
+  }
+  /* pp */ abstract int hashCodeSemanticsImpl();
+
+  @Override
+  public final boolean equalSemantics(final SemanticEqualityOp arg) {
+    if (arg == this) {
+        return true;
+    } else  if ( !(arg instanceof SizeThunk) ) {
+        return false;
+    } else {
+        final SizeThunk t = (SizeThunk) arg;
+        return hashCodeSemanticsImpl() == t.hashCodeSemanticsImpl();
+    }
+  }
+
+  static final int magic_int08   = 0x00000010;
+  static final int magic_int16   = 0x00000012;
+  static final int magic_int32   = 0x00000014;
+  static final int magic_intxx   = 0x00000016;
+  static final int magic_long64  = 0x00000020;
+  static final int magic_longxx  = 0x00000022;
+  static final int magic_float32 = 0x00000030;
+  static final int magic_float64 = 0x00000032;
+  static final int magic_aptr64  = 0x00000040;
+  static final int magic_ops     = 0x00010000;
 
   public static final SizeThunk INT8 = new SizeThunk(true) {
       @Override
-      public long computeSize(final MachineDescription machDesc) {
+      public long computeSize(final MachineDataInfo machDesc) {
         return machDesc.int8SizeInBytes();
       }
       @Override
-      public long computeAlignment(final MachineDescription machDesc) {
+      public long computeAlignment(final MachineDataInfo machDesc) {
         return machDesc.int8AlignmentInBytes();
       }
+      @Override
+      protected int hashCodeImpl() { return 1; }
+      @Override
+      protected int hashCodeSemanticsImpl() { return relaxedEqSem ? magic_int32 : magic_int08; }
     };
 
   public static final SizeThunk INT16 = new SizeThunk(true) {
       @Override
-      public long computeSize(final MachineDescription machDesc) {
+      public long computeSize(final MachineDataInfo machDesc) {
         return machDesc.int16SizeInBytes();
       }
       @Override
-      public long computeAlignment(final MachineDescription machDesc) {
+      public long computeAlignment(final MachineDataInfo machDesc) {
         return machDesc.int16AlignmentInBytes();
       }
+      @Override
+      protected int hashCodeImpl() { return 2; }
+      @Override
+      protected int hashCodeSemanticsImpl() { return relaxedEqSem ? magic_int32 : magic_int16; }
     };
 
   public static final SizeThunk INT32 = new SizeThunk(true) {
       @Override
-      public long computeSize(final MachineDescription machDesc) {
+      public long computeSize(final MachineDataInfo machDesc) {
         return machDesc.int32SizeInBytes();
       }
       @Override
-      public long computeAlignment(final MachineDescription machDesc) {
+      public long computeAlignment(final MachineDataInfo machDesc) {
         return machDesc.int32AlignmentInBytes();
       }
+      @Override
+      protected int hashCodeImpl() { return 3; }
+      @Override
+      protected int hashCodeSemanticsImpl() { return magic_int32; }
     };
 
   public static final SizeThunk INTxx = new SizeThunk(false) {
       @Override
-      public long computeSize(final MachineDescription machDesc) {
+      public long computeSize(final MachineDataInfo machDesc) {
         return machDesc.intSizeInBytes();
       }
       @Override
-      public long computeAlignment(final MachineDescription machDesc) {
+      public long computeAlignment(final MachineDataInfo machDesc) {
         return machDesc.intAlignmentInBytes();
       }
+      @Override
+      protected int hashCodeImpl() { return 4; }
+      @Override
+      protected int hashCodeSemanticsImpl() { return relaxedEqSem ? magic_int32 : magic_intxx; }
     };
 
   public static final SizeThunk LONG = new SizeThunk(false) {
       @Override
-      public long computeSize(final MachineDescription machDesc) {
+      public long computeSize(final MachineDataInfo machDesc) {
         return machDesc.longSizeInBytes();
       }
       @Override
-      public long computeAlignment(final MachineDescription machDesc) {
+      public long computeAlignment(final MachineDataInfo machDesc) {
         return machDesc.longAlignmentInBytes();
       }
+      @Override
+      protected int hashCodeImpl() { return 5; }
+      @Override
+      protected int hashCodeSemanticsImpl() { return relaxedEqSem ? magic_long64 : magic_longxx; }
     };
 
   public static final SizeThunk INT64 = new SizeThunk(true) {
       @Override
-      public long computeSize(final MachineDescription machDesc) {
+      public long computeSize(final MachineDataInfo machDesc) {
         return machDesc.int64SizeInBytes();
       }
       @Override
-      public long computeAlignment(final MachineDescription machDesc) {
+      public long computeAlignment(final MachineDataInfo machDesc) {
         return machDesc.int64AlignmentInBytes();
       }
+      @Override
+      protected int hashCodeImpl() { return 6; }
+      @Override
+      protected int hashCodeSemanticsImpl() { return magic_long64; }
     };
 
   public static final SizeThunk FLOAT = new SizeThunk(true) {
       @Override
-      public long computeSize(final MachineDescription machDesc) {
+      public long computeSize(final MachineDataInfo machDesc) {
         return machDesc.floatSizeInBytes();
       }
       @Override
-      public long computeAlignment(final MachineDescription machDesc) {
+      public long computeAlignment(final MachineDataInfo machDesc) {
         return machDesc.floatAlignmentInBytes();
       }
+      @Override
+      protected int hashCodeImpl() { return 7; }
+      @Override
+      protected int hashCodeSemanticsImpl() { return magic_float32; }
     };
 
   public static final SizeThunk DOUBLE = new SizeThunk(true) {
       @Override
-      public long computeSize(final MachineDescription machDesc) {
+      public long computeSize(final MachineDataInfo machDesc) {
         return machDesc.doubleSizeInBytes();
       }
       @Override
-      public long computeAlignment(final MachineDescription machDesc) {
+      public long computeAlignment(final MachineDataInfo machDesc) {
         return machDesc.doubleAlignmentInBytes();
       }
+      @Override
+      protected int hashCodeImpl() { return 8; }
+      @Override
+      protected int hashCodeSemanticsImpl() { return magic_float64; }
     };
 
   public static final SizeThunk POINTER = new SizeThunk(false) {
       @Override
-      public long computeSize(final MachineDescription machDesc) {
+      public long computeSize(final MachineDataInfo machDesc) {
         return machDesc.pointerSizeInBytes();
       }
       @Override
-      public long computeAlignment(final MachineDescription machDesc) {
+      public long computeAlignment(final MachineDataInfo machDesc) {
         return machDesc.pointerAlignmentInBytes();
       }
+      @Override
+      protected int hashCodeImpl() { return 9; }
+      @Override
+      protected int hashCodeSemanticsImpl() { return magic_aptr64; }
     };
 
   // Factory methods for performing certain limited kinds of
@@ -172,15 +265,24 @@ public abstract class SizeThunk implements Cloneable {
                               final SizeThunk thunk2) {
     return new SizeThunk(false) {
         @Override
-        public long computeSize(final MachineDescription machDesc) {
+        public long computeSize(final MachineDataInfo machDesc) {
           return thunk1.computeSize(machDesc) + thunk2.computeSize(machDesc);
         }
         @Override
-        public long computeAlignment(final MachineDescription machDesc) {
+        public long computeAlignment(final MachineDataInfo machDesc) {
           final long thunk1A = thunk1.computeAlignment(machDesc);
           final long thunk2A = thunk2.computeAlignment(machDesc);
           return ( thunk1A > thunk2A ) ? thunk1A : thunk2A ;
         }
+        @Override
+        protected int hashCodeImpl() {
+            // 31 * x == (x << 5) - x
+            int hash = 31 + 10;
+            hash = ((hash << 5) - hash) + ( null != thunk1 ? thunk1.hashCode() : 0 );
+            return ((hash << 5) - hash) + ( null != thunk2 ? thunk2.hashCode() : 0 );
+        }
+        @Override
+        protected int hashCodeSemanticsImpl() { return magic_ops + 1; }
       };
   }
 
@@ -188,15 +290,24 @@ public abstract class SizeThunk implements Cloneable {
                               final SizeThunk thunk2) {
     return new SizeThunk(false) {
         @Override
-        public long computeSize(final MachineDescription machDesc) {
+        public long computeSize(final MachineDataInfo machDesc) {
           return thunk1.computeSize(machDesc) * thunk2.computeSize(machDesc);
         }
         @Override
-        public long computeAlignment(final MachineDescription machDesc) {
+        public long computeAlignment(final MachineDataInfo machDesc) {
           final long thunk1A = thunk1.computeAlignment(machDesc);
           final long thunk2A = thunk2.computeAlignment(machDesc);
           return ( thunk1A > thunk2A ) ? thunk1A : thunk2A ;
         }
+        @Override
+        protected int hashCodeImpl() {
+            // 31 * x == (x << 5) - x
+            int hash = 31 + 11;
+            hash = ((hash << 5) - hash) + ( null != thunk1 ? thunk1.hashCode() : 0 );
+            return ((hash << 5) - hash) + ( null != thunk2 ? thunk2.hashCode() : 0 );
+        }
+        @Override
+        protected int hashCodeSemanticsImpl() { return magic_ops + 2; }
       };
   }
 
@@ -204,26 +315,50 @@ public abstract class SizeThunk implements Cloneable {
                                 final SizeThunk alignmentThunk) {
     return new SizeThunk(false) {
         @Override
-        public long computeSize(final MachineDescription machDesc) {
-          // x % 2n == x & (2n - 1)
-          // remainder = net_size & ( alignment - 1 )
-          // padding = alignment - remainder ;
-          // aligned_size = net_size + padding ;
+        public long computeSize(final MachineDataInfo machDesc) {
+          /**
+           * padding = ( alignment - ( net_size % alignment ) ) % alignment ;
+           * aligned_size = net_size + padding ;
+           *
+           * With x % 2n == x & (2n - 1)
+           *
+           * Either:
+           *   remainder = net_size & ( alignment - 1 )
+           *   padding = ( remainder > 0 ) ? alignment - remainder ;
+           *   aligned_size = net_size + padding ;
+           *
+           * Or:
+           *   padding = ( alignment - ( net_size & ( alignment - 1 ) ) ) & ( alignment - 1 );
+           *   aligned_size = net_size + padding ;
+           *
+           */
 
-          final long size = offsetThunk.computeSize(machDesc);
+          final long net_size = offsetThunk.computeSize(machDesc);
           final long alignment = alignmentThunk.computeAlignment(machDesc);
 
-          final long remainder = size & ( alignment - 1 ) ;
+          /**
+          final long remainder = net_size & ( alignment - 1 ) ;
           final long padding = (remainder > 0) ? alignment - remainder : 0;
-          return size + padding;
+           */
+          final long padding = ( alignment - ( net_size & ( alignment - 1 ) ) ) & ( alignment - 1 );
+          return net_size + padding;
         }
 
         @Override
-        public long computeAlignment(final MachineDescription machDesc) {
+        public long computeAlignment(final MachineDataInfo machDesc) {
           final long thunk1A = offsetThunk.computeAlignment(machDesc);
           final long thunk2A = alignmentThunk.computeAlignment(machDesc);
           return ( thunk1A > thunk2A ) ? thunk1A : thunk2A ;
         }
+        @Override
+        protected int hashCodeImpl() {
+            // 31 * x == (x << 5) - x
+            int hash = 31 + 12;
+            hash = ((hash << 5) - hash) + ( null != offsetThunk ? offsetThunk.hashCode() : 0 );
+            return ((hash << 5) - hash) + ( null != alignmentThunk ? alignmentThunk.hashCode() : 0 );
+        }
+        @Override
+        protected int hashCodeSemanticsImpl() { return magic_ops + 3; }
       };
   }
 
@@ -231,28 +366,45 @@ public abstract class SizeThunk implements Cloneable {
                               final SizeThunk thunk2) {
     return new SizeThunk(false) {
         @Override
-        public long computeSize(final MachineDescription machDesc) {
+        public long computeSize(final MachineDataInfo machDesc) {
           return Math.max(thunk1.computeSize(machDesc), thunk2.computeSize(machDesc));
         }
         @Override
-        public long computeAlignment(final MachineDescription machDesc) {
+        public long computeAlignment(final MachineDataInfo machDesc) {
           final long thunk1A = thunk1.computeAlignment(machDesc);
           final long thunk2A = thunk2.computeAlignment(machDesc);
           return ( thunk1A > thunk2A ) ? thunk1A : thunk2A ;
         }
+        @Override
+        protected int hashCodeImpl() {
+            // 31 * x == (x << 5) - x
+            int hash = 31 + 13;
+            hash = ((hash << 5) - hash) + ( null != thunk1 ? thunk1.hashCode() : 0 );
+            return ((hash << 5) - hash) + ( null != thunk2 ? thunk2.hashCode() : 0 );
+        }
+        @Override
+        protected int hashCodeSemanticsImpl() { return magic_ops + 4; }
       };
   }
 
   public static SizeThunk constant(final int constant) {
     return new SizeThunk(false) {
         @Override
-        public long computeSize(final MachineDescription machDesc) {
+        public long computeSize(final MachineDataInfo machDesc) {
           return constant;
         }
         @Override
-        public long computeAlignment(final MachineDescription machDesc) {
+        public long computeAlignment(final MachineDataInfo machDesc) {
           return 1; // no alignment for constants
         }
+        @Override
+        protected int hashCodeImpl() {
+            // 31 * x == (x << 5) - x
+            final int hash = 31 + 14;
+            return ((hash << 5) - hash) + constant;
+        }
+        @Override
+        protected int hashCodeSemanticsImpl() { return magic_ops + 5; }
       };
   }
 }
diff --git a/src/java/com/jogamp/gluegen/cgram/types/StructLayout.java b/src/java/com/jogamp/gluegen/cgram/types/StructLayout.java
index e3ed7c2..86f1ae1 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/StructLayout.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/StructLayout.java
@@ -40,7 +40,7 @@
 
 package com.jogamp.gluegen.cgram.types;
 
-import com.jogamp.common.os.MachineDescription;
+import com.jogamp.common.os.MachineDataInfo;
 import com.jogamp.gluegen.GlueGen;
 
 /** Encapsulates algorithm for laying out data structures. Note that
@@ -67,9 +67,9 @@ public class StructLayout {
     SizeThunk curOffset = SizeThunk.constant(baseOffset);
     SizeThunk maxSize   = SizeThunk.constant(0);
 
-    final MachineDescription dbgMD;
+    final MachineDataInfo dbgMD;
     if( GlueGen.debug() ) {
-        dbgMD = MachineDescription.StaticConfig.X86_64_UNIX.md;
+        dbgMD = MachineDataInfo.StaticConfig.LP64_UNIX.md;
         System.err.printf("SL.__: o %03d, s %03d, t %s{%d}%n", curOffset.computeSize(dbgMD), 0, t, t.getNumFields());
     } else {
         dbgMD = null;
diff --git a/src/java/com/jogamp/gluegen/cgram/types/StructType.java b/src/java/com/jogamp/gluegen/cgram/types/StructType.java
index 27099e9..fa78006 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/StructType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/StructType.java
@@ -27,34 +27,25 @@
  */
 package com.jogamp.gluegen.cgram.types;
 
+import com.jogamp.gluegen.ASTLocusTag;
+
 public class StructType extends CompoundType {
 
-  public StructType(final String name, final SizeThunk size, final int cvAttributes) {
-      this(name, size, cvAttributes, null);
+  StructType(final String name, final SizeThunk size, final int cvAttributes, final String structName, final ASTLocusTag astLocus) {
+    super (name, size, cvAttributes, structName, astLocus);
   }
 
-  StructType(final String name, final SizeThunk size, final int cvAttributes, final String structName) {
-    super (name, size, cvAttributes, structName);
+  private StructType(final StructType o, final int cvAttributes, final ASTLocusTag astLocus) {
+    super(o, cvAttributes, astLocus);
   }
 
   @Override
-  public boolean equals(final Object arg) {
-    if (arg == null || !(arg instanceof StructType)) {
-      return false;
-    }
-    return super.equals(arg);
+  Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+    return new StructType(this, cvAttributes, astLocus);
   }
 
   @Override
   public final boolean isStruct() { return true; }
   @Override
   public final boolean isUnion()  { return false; }
-
-  @Override
-  Type newCVVariant(final int cvAttributes) {
-    final StructType t = new StructType(getName(), getSize(), cvAttributes, getStructName());
-    t.setFields(getFields());
-    return t;
-  }
-
 }
diff --git a/src/java/com/jogamp/gluegen/cgram/types/Type.java b/src/java/com/jogamp/gluegen/cgram/types/Type.java
index 32f48a6..04c46af 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/Type.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/Type.java
@@ -40,46 +40,110 @@
 
 package com.jogamp.gluegen.cgram.types;
 
-import java.util.List;
-
-import com.jogamp.common.os.MachineDescription;
+import com.jogamp.common.os.MachineDataInfo;
+import com.jogamp.gluegen.ASTLocusTag.ASTLocusTagProvider;
+import com.jogamp.gluegen.ASTLocusTag;
+import com.jogamp.gluegen.GlueGen;
+import com.jogamp.gluegen.TypeConfig;
+import com.jogamp.gluegen.cgram.types.TypeComparator.SemanticEqualityOp;
 
 /** Models a C type. Primitive types include int, float, and
     double. All types have an associated name. Structs and unions are
     modeled as "compound" types -- composed of fields of primitive or
     other types. */
-public abstract class Type implements Cloneable {
-
+public abstract class Type implements SemanticEqualityOp, ASTLocusTagProvider {
+  public final boolean relaxedEqSem;
+  private final int cvAttributes;
+  final ASTLocusTag astLocus;
   private String name;
   private SizeThunk size;
-  private final int cvAttributes;
-  private int typedefedCVAttributes;
-  private boolean hasTypedefName;
-
-  protected Type(final String name, final SizeThunk size, final int cvAttributes) {
-    setName(name);
+  private int typedefCVAttributes;
+  private boolean isTypedef;
+  private boolean hasCachedHash;
+  private int cachedHash;
+  private boolean hasCachedSemanticHash;
+  private int cachedSemanticHash;
+
+  protected Type(final String name, final SizeThunk size, final int cvAttributes, final ASTLocusTag astLocus) {
+    setName(name); // -> clearCache()
+    this.relaxedEqSem = TypeConfig.relaxedEqualSemanticsTest();
+    this.cvAttributes = cvAttributes;
+    this.astLocus = astLocus;
     this.size = size;
+    this.typedefCVAttributes = 0;
+    this.isTypedef = false;
+  }
+  Type(final Type o, final int cvAttributes, final ASTLocusTag astLocus) {
+    this.relaxedEqSem = o.relaxedEqSem;
     this.cvAttributes = cvAttributes;
-    hasTypedefName = false;
+    this.astLocus = astLocus;
+    this.name = o.name;
+    this.size = o.size;
+    this.typedefCVAttributes = o.typedefCVAttributes;
+    this.isTypedef = o.isTypedef;
+    clearCache();
   }
 
-  @Override
-  public Object clone() {
-    try {
-        return super.clone();
-    } catch (final CloneNotSupportedException ex) {
-        throw new InternalError();
+  protected final void clearCache() {
+    hasCachedHash = false;
+    cachedHash = 0;
+    hasCachedSemanticHash = false;
+    cachedSemanticHash = 0;
+  }
+
+  /**
+   * Return a variant of this type matching the given const/volatile
+   * attributes. May return this object if the attributes match.
+   */
+  public final Type newCVVariant(final int cvAttributes) {
+    if (this.cvAttributes == cvAttributes) {
+        return this;
+    } else {
+        return newVariantImpl(true, cvAttributes, astLocus);
     }
   }
 
+  /**
+   * Clones this instance using a new {@link ASTLocusTag}.
+   */
+  public Type clone(final ASTLocusTag newLoc) {
+    return newVariantImpl(true, cvAttributes, newLoc);
+  }
+
+  /**
+   * Create a new variant of this type matching the given parameter
+   * <p>
+   * Implementation <i>must</i> use {@link Type}'s copy-ctor: {@link #Type(Type, int, ASTLocusTag)}!
+   * </p>
+   * @param newCVVariant true if new variant is intended to have new <i>cvAttributes</i>
+   * @param cvAttributes the <i>cvAttributes</i> to be used
+   * @param astLocus the {@link ASTLocusTag} to be used
+   */
+  abstract Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus);
+
+  @Override
+  public final ASTLocusTag getASTLocusTag() { return astLocus; }
+
+  public boolean isAnon() { return null == name; }
+
   /** Returns the name of this type. The returned string is suitable
-      for use as a type specifier. Does not include any const/volatile
+      for use as a type specifier for native C. Does not include any const/volatile
+      attributes. */
+  public final String getCName() { return getCName(false); }
+
+  /** Returns the name of this type, optionally including
+      const/volatile attributes. The returned string is suitable for
+      use as a type specifier for native C. */
+  public String getCName(final boolean includeCVAttrs) { return getName(includeCVAttrs); }
+
+  /** Returns the name of this type. The returned string is suitable
+      for use as a type specifier for Java. Does not include any const/volatile
       attributes. */
   public final String getName() { return getName(false); }
 
   /** Returns the name of this type, optionally including
       const/volatile attributes. The returned string is suitable for
-      use as a type specifier. */
+      use as a type specifier for Java. */
   public String getName(final boolean includeCVAttrs) {
     if (!includeCVAttrs) {
       return name;
@@ -87,32 +151,59 @@ public abstract class Type implements Cloneable {
     return getCVAttributesString() + name;
   }
 
-  private void append(final StringBuilder sb, final String val, final boolean prepComma) {
+  /**
+   * Returns a string representation of this type.
+   * The returned string is suitable for use as a type specifier for native C.
+   * It does contain an expanded description of structs/unions,
+   * hence may not be suitable for type declarations.
+   */
+  @Override
+  public String toString() {
+    return getCName(true);
+  }
+
+
+  private static StringBuilder append(final StringBuilder sb, final String val, final boolean prepComma) {
       if( prepComma ) {
           sb.append(", ");
       }
       sb.append(val);
+      return sb;
   }
   // For debugging
-  public String getDebugString() {
+  public final String getDebugString() {
     final StringBuilder sb = new StringBuilder();
     boolean prepComma = false;
     sb.append("CType[");
+    sb.append("(").append(getClass().getSimpleName()).append(") ");
+    if( isTypedef() ) {
+        sb.append("typedef ");
+    }
     if( null != name ) {
-        append(sb, "'"+name+"'", prepComma); prepComma=true;
+        sb.append("'").append(name).append("'");
     } else {
-        append(sb, "ANON", prepComma); prepComma=true;
+        sb.append("ANON");
+    }
+    final Type targetType = getTargetType();
+    if( null != targetType && this != targetType ) {
+        sb.append(" -> ");
+        if (!targetType.isFunction()) {
+            sb.append("(" + targetType.toString() + ") * " + getCVAttributesString());
+        } else {
+            sb.append(((FunctionType) targetType).toString(null /* functionName */, null /* callingConvention */, false, true));
+        }
     }
-    if( hasTypedefName() ) {
-        sb.append(" (typedef)");
+    if( GlueGen.debug() ) {
+        sb.append(", o=0x"+Integer.toHexString(objHash()));
     }
-    append(sb, "size ", prepComma); prepComma=true;
+    sb.append(", size ");
+    prepComma=true;
     if( null != size ) {
         final long mdSize;
         {
             long _mdSize = -1;
             try {
-                _mdSize = size.computeSize(MachineDescription.StaticConfig.X86_64_UNIX.md);
+                _mdSize = size.computeSize(MachineDataInfo.StaticConfig.LP64_UNIX.md);
             } catch (final Exception e) {}
             mdSize = _mdSize;
         }
@@ -121,67 +212,135 @@ public abstract class Type implements Cloneable {
         sb.append(" ZERO");
     }
     append(sb, "[", prepComma); prepComma=false;
-    if( isConst() ) {
-        append(sb, "const ", false);
-    }
-    if( isVolatile() ) {
-        append(sb, "volatile ", false);
-    }
-    if( isPointer() ) {
-        append(sb, "pointer*"+pointerDepth(), prepComma); prepComma=true;
-    }
-    if( isArray() ) {
-        append(sb, "array*"+arrayDimension(), prepComma); prepComma=true;
-    }
-    if( isBit() ) {
-        append(sb, "bit", prepComma); prepComma=true;
-    }
-    if( isCompound() ) {
-        sb.append("struct{").append(asCompound().getNumFields());
-        append(sb, "}", prepComma); prepComma=true;
-    }
-    if( isDouble() ) {
-        append(sb, "double", prepComma); prepComma=true;
-    }
-    if( isEnum() ) {
-        append(sb, "enum", prepComma); prepComma=true;
-    }
-    if( isFloat() ) {
-        append(sb, "float", prepComma); prepComma=true;
-    }
-    if( isFunction() ) {
-        append(sb, "function", prepComma); prepComma=true;
-    }
-    if( isFunctionPointer() ) {
-        append(sb, "funcPointer", prepComma); prepComma=true;
-    }
-    if( isInt() ) {
-        append(sb, "int", prepComma); prepComma=true;
-    }
-    if( isVoid() ) {
-        append(sb, "void", prepComma); prepComma=true;
+    {
+        append(sb, "const[", prepComma); prepComma=false;
+        {
+            if( isConstTypedef() ) {
+                append(sb, "type ", prepComma);  prepComma=true;
+            }
+            if( isConstRaw() ) {
+                append(sb, "inst -> ", prepComma);  prepComma=false;
+            }
+            if( isConst() ) {
+                append(sb, "true]", prepComma);
+            } else {
+                append(sb, "false]", prepComma);
+            }
+            prepComma=true;
+        }
+        if( isVolatile() ) {
+            append(sb, "volatile ", prepComma);  prepComma=true;
+        }
+        if( isPointer() ) {
+            append(sb, "pointer*"+pointerDepth(), prepComma); prepComma=true;
+        }
+        if( isArray() ) {
+            append(sb, "array*"+arrayDimension(), prepComma); prepComma=true;
+        }
+        if( isBit() ) {
+            append(sb, "bit", prepComma); prepComma=true;
+        }
+        if( isCompound() ) {
+            append(sb, "struct{", prepComma).append(asCompound().getStructName()).append(": ").append(asCompound().getNumFields());
+            append(sb, "}", prepComma); prepComma=true;
+        }
+        if( isDouble() ) {
+            append(sb, "double", prepComma); prepComma=true;
+        }
+        if( isEnum() ) {
+            final EnumType eT = asEnum();
+            append(sb, "enum ", prepComma).append(" [").append(eT.getUnderlyingType()).append("] {").append(eT.getNumEnumerates()).append(": ");
+            eT.appendEnums(sb, false);
+            prepComma=true;
+        }
+        if( isFloat() ) {
+            append(sb, "float", prepComma); prepComma=true;
+        }
+        if( isFunction() ) {
+            append(sb, "function", prepComma); prepComma=true;
+        }
+        if( isFunctionPointer() ) {
+            append(sb, "funcPointer", prepComma); prepComma=true;
+        }
+        if( isInt() ) {
+            append(sb, "int", prepComma); prepComma=true;
+        }
+        if( isVoid() ) {
+            append(sb, "void", prepComma); prepComma=true;
+        }
+        sb.append("]");
     }
-    sb.append("]]");
+    sb.append("]");
     return sb.toString();
   }
+  private final int objHash() { return super.hashCode(); }
+
 
-  /** Set the name of this type; used for handling typedefs. */
-  public void         setName(final String name) {
-    if (name == null) {
+  /**
+   * Returns {@code true} if given {@code name} is not {@code null}
+   * and has a length > 0. In this case this instance's names will
+   * be set to the internalized version.
+   * <p>
+   * Otherwise method returns {@code false}
+   * and this instance's name will be set to {@code null}.
+   * </p>
+   * <p>
+   * Method issues {@link #clearCache()}, to force re-evaluation
+   * of hashes.
+   * </p>
+   */
+  private final boolean setName(final String name) {
+    clearCache();
+    if( null == name || 0 == name.length() ) {
       this.name = name;
+      return false;
     } else {
       this.name = name.intern();
+      return true;
+    }
+  }
+
+  /**
+   * Set the typedef name of this type and renders this type a typedef,
+   * if given {@code name} has a length.
+   * <p>
+   * Method issues {@link #clearCache()}, to force re-evaluation
+   * of hashes.
+   * </p>
+   */
+  public boolean setTypedefName(final String name) {
+    if( setName(name) ) {
+        // Capture the const/volatile attributes at the time of typedef so
+        // we don't redundantly repeat them in the CV attributes string
+        typedefCVAttributes = cvAttributes;
+        isTypedef = true;
+        return true;
+    } else {
+        return false;
     }
-    // Capture the const/volatile attributes at the time of typedef so
-    // we don't redundantly repeat them in the CV attributes string
-    typedefedCVAttributes = cvAttributes;
-    hasTypedefName = true;
+  }
+  final void setTypedef(final int typedefedCVAttributes) {
+    this.name = this.name.intern(); // just make sure ..
+    this.typedefCVAttributes = typedefedCVAttributes;
+    this.isTypedef = true;
+    clearCache();
+  }
+  final int getTypedefCVAttributes() {
+    return typedefCVAttributes;
+  }
+
+  /**
+   * Indicates whether this type is a typedef type,
+   * i.e. declared via {@link #setTypedefName(String)}.
+   */
+  public final boolean isTypedef() {
+    return isTypedef;
   }
 
   /** SizeThunk which computes size of this type in bytes. */
-  public SizeThunk    getSize()    { return size; }
-  /** Size of this type in bytes according to the given MachineDescription. */
-  public long         getSize(final MachineDescription machDesc) {
+  public final SizeThunk getSize()    { return size; }
+  /** Size of this type in bytes according to the given MachineDataInfo. */
+  public final long getSize(final MachineDataInfo machDesc) {
     final SizeThunk thunk = getSize();
     if (thunk == null) {
       throw new RuntimeException("No size set for type \"" + getName() + "\"");
@@ -189,7 +348,10 @@ public abstract class Type implements Cloneable {
     return thunk.computeSize(machDesc);
   }
   /** Set the size of this type; only available for CompoundTypes. */
-  void                setSize(final SizeThunk size) { this.size = size; }
+  final void setSize(final SizeThunk size) {
+      this.size = size;
+      clearCache();
+  }
 
   /** Casts this to a BitType or returns null if not a BitType. */
   public BitType      asBit()      { return null; }
@@ -213,82 +375,153 @@ public abstract class Type implements Cloneable {
   public VoidType     asVoid()     { return null; }
 
   /** Indicates whether this is a BitType. */
-  public boolean      isBit()      { return (asBit()      != null); }
+  public final boolean      isBit()      { return (asBit()      != null); }
   /** Indicates whether this is an IntType. */
-  public boolean      isInt()      { return (asInt()      != null); }
+  public final boolean      isInt()      { return (asInt()      != null); }
   /** Indicates whether this is an EnumType. */
-  public boolean      isEnum()     { return (asEnum()     != null); }
+  public final boolean      isEnum()     { return (asEnum()     != null); }
   /** Indicates whether this is a FloatType. */
-  public boolean      isFloat()    { return (asFloat()    != null); }
+  public final boolean      isFloat()    { return (asFloat()    != null); }
   /** Indicates whether this is a DoubleType. */
-  public boolean      isDouble()   { return (asDouble()   != null); }
+  public final boolean      isDouble()   { return (asDouble()   != null); }
   /** Indicates whether this is a PointerType. */
-  public boolean      isPointer()  { return (asPointer()  != null); }
+  public final boolean      isPointer()  { return (asPointer()  != null); }
   /** Indicates whether this is an ArrayType. */
-  public boolean      isArray()    { return (asArray()    != null); }
+  public final boolean      isArray()    { return (asArray()    != null); }
   /** Indicates whether this is a CompoundType. */
-  public boolean      isCompound() { return (asCompound() != null); }
+  public final boolean      isCompound() { return (asCompound() != null); }
   /** Indicates whether this is a FunctionType. */
-  public boolean      isFunction() { return (asFunction() != null); }
+  public final boolean      isFunction() { return (asFunction() != null); }
   /** Indicates whether this is a VoidType. */
-  public boolean      isVoid()     { return (asVoid()     != null); }
+  public final boolean      isVoid()     { return (asVoid()     != null); }
 
-  /** Indicates whether this type is const. */
-  public boolean      isConst()    { return (((cvAttributes & ~typedefedCVAttributes) & CVAttributes.CONST) != 0); }
   /** Indicates whether this type is volatile. */
-  public boolean      isVolatile() { return (((cvAttributes & ~typedefedCVAttributes) & CVAttributes.VOLATILE) != 0); }
+  public final boolean      isVolatile() { return 0 != ( ( cvAttributes & ~typedefCVAttributes ) & CVAttributes.VOLATILE );  }
+  /** Indicates whether this type is const. */
+  public final boolean      isConst()    { return 0 != ( ( cvAttributes & ~typedefCVAttributes ) & CVAttributes.CONST );  }
+
+  private final boolean isConstTypedef() { return 0 !=                   ( typedefCVAttributes   & CVAttributes.CONST ); }
+  private final boolean isConstRaw()     { return 0 !=   ( cvAttributes                          & CVAttributes.CONST ); }
 
   /** Indicates whether this type is a primitive type. */
-  public boolean      isPrimitive(){ return false; }
+  public boolean isPrimitive(){ return false; }
 
   /** Convenience routine indicating whether this Type is a pointer to
       a function. */
   public boolean isFunctionPointer() {
-    return (isPointer() && asPointer().getTargetType().isFunction());
+    return false;
+  }
+
+  /**
+   * Checks the base type of pointer-to-pointer, pointer, array or plain for const-ness.
+   * <p>
+   * Note: Intermediate 'const' qualifier are not considered, e.g. const pointer.
+   * </p>
+   */
+  public final boolean isBaseTypeConst() {
+    return getBaseElementType().isConst();
   }
 
   /** Hashcode for Types. */
   @Override
-  public int hashCode() {
-    if (name == null) {
-      return 0;
-    }
-
-    if (cvAttributes != 0)  {
-      final String nameWithAttribs = name + cvAttributes;
-      return nameWithAttribs.hashCode();
+  public final int hashCode() {
+    if( !hasCachedHash ) {
+        // 31 * x == (x << 5) - x
+        int hash = 31 + ( isTypedef ? 1 : 0 );
+        hash = ((hash << 5) - hash) + ( null != size ? size.hashCode() : 0 );
+        hash = ((hash << 5) - hash) + cvAttributes;
+        hash = ((hash << 5) - hash) + typedefCVAttributes;
+        hash = ((hash << 5) - hash) + ( null != name ? name.hashCode() : 0 );
+        if( !isTypedef ) {
+            hash = ((hash << 5) - hash) + hashCodeImpl();
+        }
+        cachedHash = hash;
+        hasCachedHash = true;
     }
-    return name.hashCode();
+    return cachedHash;
   }
+  protected abstract int hashCodeImpl();
 
   /**
-   * Equality test for Types.
+   * Equality test for Types inclusive its given {@link #getName() name}.
    */
   @Override
-  public boolean equals(final Object arg) {
+  public final boolean equals(final Object arg) {
     if (arg == this) {
-      return true;
+        return true;
+    } else  if ( !getClass().isInstance(arg) ) { // implies null == arg || !(arg instanceof Type)
+        return false;
+    } else {
+        final Type t = (Type)arg;
+        if( isTypedef == t.isTypedef &&
+            ( ( null != size && size.equals(t.size) ) ||
+              ( null == size && null == t.size )
+            ) &&
+            cvAttributes == t.cvAttributes &&
+            typedefCVAttributes == t.typedefCVAttributes &&
+            ( null == name ? null == t.name : name.equals(t.name) )
+          )
+        {
+            if( !isTypedef ) {
+                return equalsImpl(t);
+            } else {
+                return true;
+            }
+        } else {
+            return false;
+        }
     }
+  }
+  protected abstract boolean equalsImpl(final Type t);
 
-    if ( !(arg instanceof Type) ) {
-      return false;
+  @Override
+  public final int hashCodeSemantics() {
+    if( !hasCachedSemanticHash ) {
+        // 31 * x == (x << 5) - x
+        int hash = 31 + ( null != size ? size.hashCodeSemantics() : 0 );
+        if( !relaxedEqSem ) {
+            hash = ((hash << 5) - hash) + cvAttributes;
+            hash = ((hash << 5) - hash) + typedefCVAttributes;
+        }
+        hash = ((hash << 5) - hash) + hashCodeSemanticsImpl();
+        cachedSemanticHash = hash;
+        hasCachedSemanticHash = true;
     }
-
-    final Type t = (Type)arg;
-    return size == t.size && cvAttributes == t.cvAttributes &&
-           ( null == name ? null == t.name : name.equals(t.name) ) ;
+    return cachedSemanticHash;
   }
+  protected abstract int hashCodeSemanticsImpl();
 
-  /** Returns a string representation of this type. This string is not
-      necessarily suitable for use as a type specifier; for example,
-      it will contain an expanded description of structs/unions. */
   @Override
-  public String toString() {
-    return getName(true);
+  public final boolean equalSemantics(final SemanticEqualityOp arg) {
+    if (arg == this) {
+        return true;
+    } else  if ( !(arg instanceof Type) ||
+                 !getClass().isInstance(arg) ) { // implies null == arg
+        return false;
+    } else {
+        final Type t = (Type) arg;
+        if( ( ( null != size && size.equalSemantics(t.size) ) ||
+              ( null == size && null == t.size )
+            ) &&
+            ( relaxedEqSem ||
+              ( cvAttributes == t.cvAttributes &&
+                typedefCVAttributes == t.typedefCVAttributes
+              )
+            )
+          )
+        {
+            return equalSemanticsImpl(t);
+        } else {
+            return false;
+        }
+    }
   }
+  protected abstract boolean equalSemanticsImpl(final Type t);
 
-  /** Visit this type and all of the component types of this one; for
-      example, the return type and argument types of a FunctionType. */
+  /**
+   * Traverse this {@link Type} and all of its component types; for
+   * example, the return type and argument types of a FunctionType.
+   */
   public void visit(final TypeVisitor visitor) {
     visitor.visitType(this);
   }
@@ -306,45 +539,18 @@ public abstract class Type implements Cloneable {
     return "";
   }
 
-  /** Return a variant of this type matching the given const/volatile
-      attributes. May return this object if the attributes match. */
-  public final Type getCVVariant(final int cvAttributes) {
-    if (this.cvAttributes == cvAttributes) {
-      return this;
-    }
-    return newCVVariant(cvAttributes);
-  }
-
-  /** Create a new variant of this type matching the given
-      const/volatile attributes. */
-  abstract Type newCVVariant(int cvAttributes);
-
-  /** Indicates whether setName() has been called on this type,
-      indicating that it already has a typedef name. */
-  public boolean hasTypedefName() {
-    return hasTypedefName;
-  }
-
   /** Helper method for determining how many pointer indirections this
       type represents (i.e., "void **" returns 2). Returns 0 if this
       type is not a pointer type. */
   public int pointerDepth() {
-    final PointerType pt = asPointer();
-    if (pt == null) {
-      return 0;
-    }
-    return 1 + pt.getTargetType().pointerDepth();
+    return 0;
   }
 
   /** Helper method for determining how many array dimentions this
       type represents (i.e., "char[][]" returns 2). Returns 0 if this
       type is not an array type. */
   public int arrayDimension() {
-    final ArrayType arrayType = asArray();
-    if (arrayType == null) {
-      return 0;
-    }
-    return 1 + arrayType.getElementType().arrayDimension();
+    return 0;
   }
 
   /**
@@ -358,8 +564,10 @@ public abstract class Type implements Cloneable {
       return this;
   }
 
-  /** Helper routine for list equality comparison */
-  static <C> boolean listsEqual(final List<C> a, final List<C> b) {
-    return ((a == null && b == null) || (a != null && b != null && a.equals(b)));
+  /**
+   * Helper method to returns the target type of this type, in case another type is being referenced.
+   */
+  public Type getTargetType() {
+      return this;
   }
 }
diff --git a/src/java/com/jogamp/gluegen/cgram/types/TypeComparator.java b/src/java/com/jogamp/gluegen/cgram/types/TypeComparator.java
new file mode 100644
index 0000000..850d953
--- /dev/null
+++ b/src/java/com/jogamp/gluegen/cgram/types/TypeComparator.java
@@ -0,0 +1,143 @@
+/**
+ * Copyright 2015 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.gluegen.cgram.types;
+
+import java.util.List;
+
+public class TypeComparator {
+    /**
+     * Supports semantic equality and hash functions for types.
+     */
+    public static interface SemanticEqualityOp {
+        /**
+         * Semantic hashcode for Types exclusive its given {@link #getName() name}.
+         * @see #equalSemantics(SemanticEqualityOp)
+         */
+        int hashCodeSemantics();
+
+        /**
+         * Semantic equality test for Types exclusive its given {@link #getName() name}.
+         * @see #hashCodeSemantics()
+         */
+        boolean equalSemantics(final SemanticEqualityOp arg);
+    }
+    /**
+     * Supports common interface for {@link SemanticEqualityOp} and {@link AliasedSymbol}.
+     */
+    public static interface AliasedSemanticSymbol extends AliasedSymbol, SemanticEqualityOp { };
+
+    /** Helper routine for list equality comparison*/
+    static <C> boolean listsEqual(final List<C> a, final List<C> b) {
+        if( a == null ) {
+            if( null != b ) {
+                return false;
+            } else {
+                return true; // elements equal, i.e. both null
+            }
+        }
+        if( b != null && a.size() == b.size() ) {
+            final int count = a.size();
+            for(int i=0; i<count; i++) {
+                final C ac = a.get(i);
+                final C bc = b.get(i);
+                if( null == ac ) {
+                    if( null != bc ) {
+                        return false;
+                    } else {
+                        continue; // elements equal, i.e. both null
+                    }
+                }
+                if( !ac.equals(bc) ) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /** Helper routine for list hashCode */
+    static <C extends SemanticEqualityOp> int listsHashCode(final List<C> a) {
+        if( a == null ) {
+            return 0;
+        } else {
+            final int count = a.size();
+            int hash = 31;
+            for(int i=0; i<count; i++) {
+                final C ac = a.get(i);
+                hash = ((hash << 5) - hash) + ( null != ac ? ac.hashCode() : 0 );
+            }
+            return hash;
+        }
+    }
+
+    /** Helper routine for list semantic equality comparison*/
+    static <C extends SemanticEqualityOp> boolean listsEqualSemantics(final List<C> a, final List<C> b) {
+        if( a == null ) {
+            if( null != b ) {
+                return false;
+            } else {
+                return true; // elements equal, i.e. both null
+            }
+        }
+        if( b != null && a.size() == b.size() ) {
+            final int count = a.size();
+            for(int i=0; i<count; i++) {
+                final C ac = a.get(i);
+                final C bc = b.get(i);
+                if( null == ac ) {
+                    if( null != bc ) {
+                        return false;
+                    } else {
+                        continue; // elements equal, i.e. both null
+                    }
+                }
+                if( !ac.equalSemantics(bc) ) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /** Helper routine for list hashCode */
+    static <C extends SemanticEqualityOp> int listsHashCodeSemantics(final List<C> a) {
+        if( a == null ) {
+            return 0;
+        } else {
+            final int count = a.size();
+            int hash = 31;
+            for(int i=0; i<count; i++) {
+                final C ac = a.get(i);
+                hash = ((hash << 5) - hash) + ( null != ac ? ac.hashCodeSemantics() : 0 );
+            }
+            return hash;
+        }
+    }
+}
diff --git a/src/java/com/jogamp/gluegen/cgram/types/TypeDictionary.java b/src/java/com/jogamp/gluegen/cgram/types/TypeDictionary.java
index cd03388..c1cfcdf 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/TypeDictionary.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/TypeDictionary.java
@@ -41,6 +41,9 @@ package com.jogamp.gluegen.cgram.types;
 
 import java.util.*;
 
+import com.jogamp.gluegen.GlueGen;
+import com.jogamp.gluegen.JavaConfiguration;
+
 
 /** Utility class for recording names of typedefs and structs. */
 
@@ -63,6 +66,38 @@ public class TypeDictionary {
     return map.get(name);
   }
 
+  public List<Type> getEqualSemantics(final Type s, final JavaConfiguration cfg, final boolean skipOpaque) {
+      final List<Type> res = new ArrayList<Type>();
+      if( !skipOpaque || null == cfg.typeInfo(s) ) {
+          final Set<Map.Entry<String, Type>> entries = entrySet();
+          for(final Iterator<Map.Entry<String, Type>> iter = entries.iterator(); iter.hasNext(); ) {
+              final Map.Entry<String, Type> entry = iter.next();
+              final Type t = entry.getValue();
+              if( s.equalSemantics(t) ) {
+                  if( !skipOpaque || null == cfg.typeInfo(t) ) {
+                      if( GlueGen.debug() ) {
+                          System.err.println(" tls["+res.size()+"]: -> "+entry.getKey()+" -> "+t.getDebugString());
+                      }
+                      res.add(t);
+                  }
+              }
+          }
+      }
+      return res;
+  }
+  public Type getEqualSemantics1(final Type s, final JavaConfiguration cfg, final boolean skipOpaque) {
+      final List<Type> tls = getEqualSemantics(s, cfg, skipOpaque);
+      if( tls.size() > 0 ) {
+          final Type res = tls.get(0);
+          if( GlueGen.debug() ) {
+              System.err.println(" tls.0: "+res.getDebugString());
+          }
+          return res;
+      } else {
+          return null;
+      }
+  }
+
   //this method is broken
   /**
    * Get the names that correspond to the given type. There will be more than
diff --git a/src/java/com/jogamp/gluegen/cgram/types/TypeVisitor.java b/src/java/com/jogamp/gluegen/cgram/types/TypeVisitor.java
index 89c014b..ed5cfa9 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/TypeVisitor.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/TypeVisitor.java
@@ -39,6 +39,12 @@
 
 package com.jogamp.gluegen.cgram.types;
 
+/**
+ * A visitor for {@link Type}'s visitor model.
+ */
 public interface TypeVisitor {
+  /**
+   * Visiting the given {@link Type}.
+   */
   public void visitType(Type t);
 }
diff --git a/src/java/com/jogamp/gluegen/cgram/types/UnionType.java b/src/java/com/jogamp/gluegen/cgram/types/UnionType.java
index 99d2fed..8c6d9dd 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/UnionType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/UnionType.java
@@ -27,34 +27,25 @@
  */
 package com.jogamp.gluegen.cgram.types;
 
+import com.jogamp.gluegen.ASTLocusTag;
+
 public class UnionType extends CompoundType {
 
-  public UnionType(final String name, final SizeThunk size, final int cvAttributes) {
-      this(name, size, cvAttributes, null);
+  UnionType(final String name, final SizeThunk size, final int cvAttributes, final String structName, final ASTLocusTag astLocus) {
+    super (name, size, cvAttributes, structName, astLocus);
   }
 
-  UnionType(final String name, final SizeThunk size, final int cvAttributes, final String structName) {
-    super (name, size, cvAttributes, structName);
+  private UnionType(final UnionType o, final int cvAttributes, final ASTLocusTag astLocus) {
+    super(o, cvAttributes, astLocus);
   }
 
   @Override
-  public boolean equals(final Object arg) {
-    if (arg == null || !(arg instanceof UnionType)) {
-      return false;
-    }
-    return super.equals(arg);
+  Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+    return new UnionType(this, cvAttributes, astLocus);
   }
 
   @Override
   public final boolean isStruct() { return false; }
   @Override
   public final boolean isUnion()  { return true; }
-
-  @Override
-  Type newCVVariant(final int cvAttributes) {
-    final UnionType t = new UnionType(getName(), getSize(), cvAttributes, getStructName());
-    t.setFields(getFields());
-    return t;
-  }
-
 }
diff --git a/src/java/com/jogamp/gluegen/cgram/types/VoidType.java b/src/java/com/jogamp/gluegen/cgram/types/VoidType.java
index 2e1f069..bf51523 100644
--- a/src/java/com/jogamp/gluegen/cgram/types/VoidType.java
+++ b/src/java/com/jogamp/gluegen/cgram/types/VoidType.java
@@ -39,14 +39,25 @@
  */
 package com.jogamp.gluegen.cgram.types;
 
+import com.jogamp.gluegen.ASTLocusTag;
+
 public class VoidType extends Type implements Cloneable {
 
-    public VoidType(final int cvAttributes) {
-        this("void", cvAttributes);
+    public VoidType(final int cvAttributes, final ASTLocusTag astLocus) {
+        this("void", cvAttributes, astLocus);
+    }
+
+    private VoidType(final String name, final int cvAttributes, final ASTLocusTag astLocus) {
+        super(name, null, cvAttributes, astLocus);
+    }
+
+    private VoidType(final VoidType o, final int cvAttributes, final ASTLocusTag astLocus) {
+        super(o, cvAttributes, astLocus);
     }
 
-    private VoidType(final String name, final int cvAttributes) {
-        super(name, null, cvAttributes);
+    @Override
+    Type newVariantImpl(final boolean newCVVariant, final int cvAttributes, final ASTLocusTag astLocus) {
+        return new VoidType(this, cvAttributes, astLocus);
     }
 
     @Override
@@ -55,7 +66,22 @@ public class VoidType extends Type implements Cloneable {
     }
 
     @Override
-    Type newCVVariant(final int cvAttributes) {
-        return new VoidType(getName(), cvAttributes);
+    protected int hashCodeImpl() {
+        return 0;
+    }
+
+    @Override
+    protected boolean equalsImpl(final Type t) {
+        return true;
+    }
+
+    @Override
+    protected int hashCodeSemanticsImpl() {
+        return 0;
+    }
+
+    @Override
+    protected boolean equalSemanticsImpl(final Type t) {
+        return true;
     }
 }
diff --git a/src/java/com/jogamp/gluegen/package.html b/src/java/com/jogamp/gluegen/package.html
index 2b4f1fa..689fa05 100644
--- a/src/java/com/jogamp/gluegen/package.html
+++ b/src/java/com/jogamp/gluegen/package.html
@@ -60,13 +60,23 @@
   </ul>
   
   <h5>Simple alignment arithmetic</h5>
-  <blockquote>remainder = offset % alignment</blockquote>
-  since alignment is a multiple of 2 <code>-> x % 2n == x & (2n - 1)</code><br>   
-  <blockquote>remainder = offset & ( alignment - 1 )</blockquote>
+  Modulo operation, where the 2nd handles the case offset == alignment:
   <blockquote>
-   padding = (remainder > 0) ? alignment - remainder : 0 ;<br>
+    padding = ( alignment - ( offset % alignment ) ) % alignment ; <br>
+    aligned_offset = offset + padding ;
+  </blockquote>
+  Optimization utilizing alignment as a multiple of 2 <code>-> x % 2n == x & ( 2n - 1 )</code><br>
+  <blockquote>
+   remainder = offset & ( alignment - 1 ) ; <br>
+   padding = ( remainder > 0 ) ? alignment - remainder : 0 ;<br>
+   aligned_offset = offset + padding ;   
+  </blockquote>
+  Without branching, using the 2nd modulo operation for the case offset == alignment:
+  <blockquote>
+   padding = ( alignment - ( offset & ( alignment - 1 ) ) ) & ( alignment - 1 ) ;<br>
    aligned_offset = offset + padding ;   
   </blockquote>
+  See <code>com.jogamp.gluegen.cgram.types.SizeThunk.align(..)</code>.
   
   <h5>Type Size & Alignment for x86, x86_64, armv6l-32bit-eabi and Window(mingw/mingw64)</h5>
   Runtime query is implemented as follows: 
diff --git a/src/java/com/jogamp/gluegen/pcpp/PCPP.java b/src/java/com/jogamp/gluegen/pcpp/PCPP.java
index aca7b14..c766634 100644
--- a/src/java/com/jogamp/gluegen/pcpp/PCPP.java
+++ b/src/java/com/jogamp/gluegen/pcpp/PCPP.java
@@ -56,16 +56,24 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.logging.Logger;
+import java.util.logging.Level;
+
+import com.jogamp.gluegen.ASTLocusTag;
+import com.jogamp.gluegen.ConstantDefinition;
+import com.jogamp.gluegen.GenericCPP;
+import com.jogamp.gluegen.GlueGenException;
+import com.jogamp.gluegen.Logging;
+import com.jogamp.gluegen.Logging.LoggerIf;
+
 import static java.util.logging.Level.*;
 
 /** A minimal pseudo-C-preprocessor designed in particular to preserve
     #define statements defining constants so they can be observed by a
     glue code generator. */
 
-public class PCPP {
+public class PCPP implements GenericCPP {
 
-    private static final Logger LOG = Logger.getLogger(PCPP.class.getPackage().getName());
+    private final LoggerIf LOG;
 
     /** Map containing the results of #define statements. We must
         evaluate certain very simple definitions (to properly handle
@@ -86,13 +94,15 @@ public class PCPP {
     private final boolean enableCopyOutput2Stderr;
 
     public PCPP(final List<String> includePaths, final boolean debug, final boolean copyOutput2Stderr) {
+        LOG = Logging.getLogger(PCPP.class.getPackage().getName(), PCPP.class.getSimpleName());
         this.includePaths = includePaths;
         setOut(System.out);
         enableDebugPrint = debug;
         enableCopyOutput2Stderr = copyOutput2Stderr;
     }
 
-    public void run(final Reader reader, final String filename) throws IOException {
+    @Override
+    public void run(final Reader reader, final String filename) throws GlueGenException {
         StreamTokenizer tok = null;
         BufferedReader bufReader = null;
         if (reader instanceof BufferedReader) {
@@ -108,13 +118,29 @@ public class PCPP {
         final ParseState oldState = state;
         state = curState;
         lineDirective();
-        parse();
+        try {
+            parse();
+        } catch (final Exception e) {
+            final StringBuilder buf = new StringBuilder("Preprocessor failed");
+            LOG.log(Level.SEVERE, buf.toString(), e);
+            if( e instanceof GlueGenException ) {
+                throw (GlueGenException)e;
+            } else {
+                throw new GlueGenException("Preprocessor failed",
+                                           new ASTLocusTag(filename(), lineNumber(), -1, null), e);
+            }
+        }
         state = oldState;
         if (state != null) {
             lineDirective();
         }
     }
 
+    @Override
+    public List<ConstantDefinition> getConstantDefinitions() throws GlueGenException {
+        return new ArrayList<ConstantDefinition>(); // NOP
+    }
+
     private void initTokenizer(final StreamTokenizer tok) {
         tok.resetSyntax();
         tok.wordChars('a', 'z');
@@ -131,6 +157,7 @@ public class PCPP {
         tok.slashStarComments(true);
     }
 
+    @Override
     public String findFile(final String filename) {
         final String sep = File.separator;
         for (final String inclPath : includePaths) {
@@ -143,10 +170,12 @@ public class PCPP {
         return null;
     }
 
+    @Override
     public OutputStream out() {
         return out;
     }
 
+    @Override
     public void setOut(final OutputStream out) {
         this.out = out;
         writer = new PrintWriter(out);
@@ -375,7 +404,7 @@ public class PCPP {
                             }
                         }
 
-                        if(isIdentifier(value)) {
+                        if(ConstantDefinition.isIdentifier(value)) {
                             newS +=" ";
                         }
 
@@ -459,28 +488,30 @@ public class PCPP {
         if (enabled()) {
             final String oldDef = defineMap.remove(name);
             if (oldDef == null) {
-                LOG.log(WARNING, "ignoring redundant \"#undef {0}\", at \"{1}\" line {2}: \"{3}\" was not previously defined",
-                        new Object[]{name, filename(), lineNumber(), name});
+                LOG.log(WARNING, new ASTLocusTag(filename(), lineNumber(), -1, name),
+                        "ignoring redundant \"#undef {0}\" - was not previously defined",
+                        name);
             } else {
                 // System.err.println("UNDEFINED: '" + name + "'  (line " + lineNumber() + " file " + filename() + ")");
             }
             nonConstantDefines.remove(name);
         } else {
-            LOG.log(WARNING, "FAILED TO UNDEFINE: ''{0}''  (line {1} file {2})", new Object[]{name, lineNumber(), filename()});
+            LOG.log(INFO, new ASTLocusTag(filename(), lineNumber(), -1, name),
+                    "DISABLED UNDEFINE: ''{0}''", name);
         }
     }
 
     private void handleWarning() throws IOException {
         final String msg = nextWordOrString();
         if (enabled()) {
-            LOG.log(WARNING, "#warning {0} at \"{1}\" line \"{2}\"", new Object[]{msg, filename(), lineNumber()});
+            LOG.log(WARNING, new ASTLocusTag(filename(), lineNumber(), -1, null), msg);
         }
     }
 
-    private void handleError() throws IOException {
+    private void handleError() throws IOException, GlueGenException {
         final String msg = nextWordOrString();
         if (enabled()) {
-            throw new RuntimeException("#error "+msg+" at \""+filename()+"\" line "+lineNumber());
+            throw new GlueGenException(msg, new ASTLocusTag(filename(), lineNumber(), -1, null));
         }
     }
 
@@ -520,6 +551,7 @@ public class PCPP {
         addDefine(name, macroDefinition, values);
     }
 
+    @Override
     public void addDefine(final String name, final String value) {
         final List<String> values = new ArrayList<String>();
         values.add(value);
@@ -541,7 +573,8 @@ public class PCPP {
                 final String value = "";
                 final String oldDef = defineMap.put(name, value);
                 if (oldDef != null && !oldDef.equals(value)) {
-                    LOG.log(WARNING, "\"{0}\" redefined from \"{1}\" to \"\"", new Object[]{name, oldDef});
+                    LOG.log(WARNING, new ASTLocusTag(filename(), lineNumber(), -1, null),
+                            "\"{0}\" redefined from \"{1}\" to \"\"", name, oldDef);
                 }
                 // We don't want to emit the define, because it would serve no purpose
                 // and cause GlueGen errors (confuse the GnuCParser)
@@ -551,12 +584,13 @@ public class PCPP {
                 // See whether the value is a constant
                 final String value = values.get(0);
 
-                if (isConstant(value)) {
+                if (ConstantDefinition.isNumber(value)) {
                     // Value is numeric constant like "#define FOO 5".
                     // Put it in the #define map
                     final String oldDef = defineMap.put(name, value);
                     if (oldDef != null && !oldDef.equals(value)) {
-                        LOG.log(WARNING, "\"{0}\" redefined from \"{1}\" to \"{2}\"", new Object[]{name, oldDef, value});
+                        LOG.log(WARNING, new ASTLocusTag(filename(), lineNumber(), -1, null),
+                                "\"{0}\" redefined from \"{1}\" to \"{2}\"", name, oldDef, value);
                     }
                     debugPrint(true, "DEFINE " + name + " ["+oldDef+" ] -> "+value + " CONST");
                     //System.err.println("//---DEFINED: " + name + " to \"" + value + "\"");
@@ -606,7 +640,8 @@ public class PCPP {
                 final Macro macro = new Macro(params, values);
                 final Macro oldDef = macroMap.put(name, macro);
                 if (oldDef != null) {
-                    LOG.log(WARNING, "\"{0}\" redefined from \"{1}\" to \"{2}\"", new Object[]{name, oldDef, macro});
+                    LOG.log(WARNING, new ASTLocusTag(filename(), lineNumber(), -1, null),
+                            "\"{0}\" redefined from \"{1}\" to \"{2}\"", name, oldDef, macro);
                 }
                 emitDefine = false;
 
@@ -618,7 +653,7 @@ public class PCPP {
 
                 boolean containsIdentifier = false;
                 for (final String value : values) {
-                    if(isIdentifier(value)) {
+                    if(ConstantDefinition.isIdentifier(value)) {
                         containsIdentifier = true;
                         break;
                     }
@@ -657,7 +692,8 @@ public class PCPP {
 
                     final String oldDef = defineMap.put(name, value);
                     if (oldDef != null && !oldDef.equals(value)) {
-                        LOG.log(WARNING, "\"{0}\" redefined from \"{1}\" to \"{2}\"", new Object[]{name, oldDef, value});
+                        LOG.log(WARNING, new ASTLocusTag(filename(), lineNumber(), -1, null),
+                                "\"{0}\" redefined from \"{1}\" to \"{2}\"", name, oldDef, value);
                     }
                     debugPrint(true, "DEFINE " + name + " ["+oldDef+" ] -> "+value + " CONST");
 //                    System.err.println("#define " + name +" "+value + " CONST EXPRESSION");
@@ -681,68 +717,6 @@ public class PCPP {
         //System.err.println("OUT HANDLE_DEFINE: " + name);
     }
 
-    private boolean isIdentifier(final String value) {
-
-        boolean identifier = false;
-
-        final char[] chars = value.toCharArray();
-
-        for (int i = 0; i < chars.length; i++) {
-            final char c = chars[i];
-            if (i == 0) {
-                if (Character.isJavaIdentifierStart(c)) {
-                    identifier = true;
-                }
-            } else {
-                if (!Character.isJavaIdentifierPart(c)) {
-                    identifier = false;
-                    break;
-                }
-            }
-        }
-        return identifier;
-    }
-
-    private boolean isConstant(final String s) {
-        if (s.startsWith("0x") || s.startsWith("0X")) {
-            return checkHex(s);
-        } else {
-            return checkDecimal(s);
-        }
-    }
-
-    private boolean checkHex(final String s) {
-        char c='\0';
-        int i;
-        for (i = 2; i < s.length(); i++) {
-            c = s.charAt(i);
-            if (!((c >= '0' && c <= '9') ||
-                  (c >= 'a' && c <= 'f') ||
-                  (c >= 'A' && c <= 'F'))) {
-                break;
-            }
-        }
-        if(i==s.length()) {
-            return true;
-        } else if(i==s.length()-1) {
-            // Const qualifier ..
-            return c == 'l' || c == 'L' ||
-                   c == 'f' || c == 'F' ||
-                   c == 'u' || c == 'U' ;
-        }
-        return false;
-    }
-
-    private boolean checkDecimal(final String s) {
-        try {
-            Float.valueOf(s);
-        } catch (final NumberFormatException e) {
-            // not parsable as a number
-            return false;
-        }
-        return true;
-    }
-
     private String resolveDefine(final String word, final boolean returnNullIfNotFound) {
         String lastWord = defineMap.get(word);
         if (lastWord == null) {
@@ -920,6 +894,27 @@ public class PCPP {
                         ifValue = false;
                     }
                     break;
+                case '*':
+                    {
+                        // NOTE: we don't handle expressions like this properly
+                        final boolean rhs = handleIfRecursive(false);
+                        ifValue = false;
+                    }
+                    break;
+                case '+':
+                    {
+                        // NOTE: we don't handle expressions like this properly
+                        final boolean rhs = handleIfRecursive(false);
+                        ifValue = false;
+                    }
+                    break;
+                case '-':
+                    {
+                        // NOTE: we don't handle expressions like this properly
+                        final boolean rhs = handleIfRecursive(false);
+                        ifValue = false;
+                    }
+                    break;
                 case '=':
                     {
                         // NOTE: we don't handle expressions like this properly
@@ -1008,7 +1003,8 @@ public class PCPP {
                 buf.append(curTokenAsString());
             }
             if (t == StreamTokenizer.TT_EOF) {
-                LOG.warning("unexpected EOF while processing #include directive");
+                LOG.warning(new ASTLocusTag(filename(), lineNumber(), -1, null),
+                            "unexpected EOF while processing #include directive");
             }
             filename = buf.toString();
         }
diff --git a/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java
index 351e0cd..37a39e1 100644
--- a/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java
+++ b/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java
@@ -42,30 +42,35 @@ package com.jogamp.gluegen.procaddress;
 import com.jogamp.gluegen.CMethodBindingEmitter;
 import com.jogamp.gluegen.MethodBinding;
 import com.jogamp.gluegen.JavaType;
+
 import java.io.*;
+
 import com.jogamp.gluegen.cgram.types.*;
 
 public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter {
 
   private boolean callThroughProcAddress;
-  private boolean needsLocalTypedef;
+  private boolean hasProcAddrTypedef;
 
   private String localTypedefCallingConvention;
 
   private static final String procAddressJavaTypeName = JavaType.createForClass(Long.TYPE).jniTypeName();
   private ProcAddressEmitter emitter;
 
-  public ProcAddressCMethodBindingEmitter(final CMethodBindingEmitter methodToWrap, final boolean callThroughProcAddress,
-                          final boolean needsLocalTypedef, final String localTypedefCallingConvention, final ProcAddressEmitter emitter) {
+  public ProcAddressCMethodBindingEmitter(final CMethodBindingEmitter methodToWrap,
+                                          final boolean callThroughProcAddress,
+                                          final boolean hasProcAddrTypedef,
+                                          final String localTypedefCallingConvention,
+                                          final ProcAddressEmitter emitter) {
 
         super(
                 new MethodBinding(methodToWrap.getBinding()) {
                     @Override
-                    public String getName() {
+                    public String getImplName() {
                         if (callThroughProcAddress) {
-                            return ProcAddressEmitter.WRAP_PREFIX + super.getName();
+                            return ProcAddressEmitter.WRAP_PREFIX + super.getImplName();
                         } else {
-                            return super.getName();
+                            return super.getImplName();
                         }
                     }
                 },
@@ -76,9 +81,9 @@ public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter {
                 methodToWrap.getIsJavaMethodStatic(),
                 true,
                 methodToWrap.forIndirectBufferAndArrayImplementation(),
-                methodToWrap.getMachineDescription()
+                methodToWrap.getMachineDataInfo(),
+                emitter.getConfiguration()
         );
-
         if (methodToWrap.getReturnValueCapacityExpression() != null) {
             setReturnValueCapacityExpression(methodToWrap.getReturnValueCapacityExpression());
         }
@@ -91,7 +96,7 @@ public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter {
         setCommentEmitter(defaultCommentEmitter);
 
         this.callThroughProcAddress = callThroughProcAddress;
-        this.needsLocalTypedef = needsLocalTypedef;
+        this.hasProcAddrTypedef = hasProcAddrTypedef;
         this.localTypedefCallingConvention = localTypedefCallingConvention;
         this.emitter = emitter;
     }
@@ -116,28 +121,31 @@ public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter {
         if (callThroughProcAddress) {
             // create variable for the function pointer with the right type, and set
             // it to the value of the passed-in proc address
-            final FunctionSymbol cSym = getBinding().getCSymbol();
-            String funcPointerTypedefName =
-                    emitter.getFunctionPointerTypedefName(cSym);
-
-            if (needsLocalTypedef) {
-                // We (probably) didn't get a typedef for this function
-                // pointer type in the header file; the user requested that we
-                // forcibly generate one. Here we force the emission of one.
-                final PointerType funcPtrType = new PointerType(null, cSym.getType(), 0);
-                // Just for safety, emit this name slightly differently than
-                // the mangling would otherwise produce
-                funcPointerTypedefName = "_local_" + funcPointerTypedefName;
-
-                writer.print("  typedef ");
-                writer.print(funcPtrType.toString(funcPointerTypedefName, localTypedefCallingConvention));
-                writer.println(";");
+            final FunctionSymbol cSym = binding.getCSymbol();
+
+            // Always emit the local typedef, based on our parsing results.
+            // In case we do have the public typedef from the original header,
+            // we use it for the local var and assign our proc-handle to it,
+            // cast to the local typedef.
+            // This allows the native C compiler to validate our types!
+            final String funcPointerTypedefBaseName = emitter.getFunctionPointerTypedefName(cSym);
+            final String funcPointerTypedefLocalName = "_local_" + funcPointerTypedefBaseName;
+            final String funcPointerTypedefName;
+            if (hasProcAddrTypedef) {
+                funcPointerTypedefName = funcPointerTypedefBaseName;
+            } else {
+                funcPointerTypedefName = funcPointerTypedefLocalName;
             }
+            final PointerType funcPtrType = new PointerType(null, cSym.getType(), 0);
+
+            writer.print("  typedef ");
+            writer.print(funcPtrType.toString(funcPointerTypedefLocalName, localTypedefCallingConvention));
+            writer.println(";");
 
             writer.print("  ");
-            writer.print(funcPointerTypedefName);
+            writer.print(funcPointerTypedefName); // Uses public typedef if available!
             writer.print(" ptr_");
-            writer.print(cSym.getName());
+            writer.print(getNativeName());
             writer.println(";");
         }
 
@@ -150,18 +158,25 @@ public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter {
 
         if (callThroughProcAddress) {
             // set the function pointer to the value of the passed-in procAddress
-            final FunctionSymbol cSym = getBinding().getCSymbol();
-            String funcPointerTypedefName = emitter.getFunctionPointerTypedefName(cSym);
-            if (needsLocalTypedef) {
-                funcPointerTypedefName = "_local_" + funcPointerTypedefName;
+            // See above notes in emitBodyVariableDeclarations(..)!
+            final String funcPointerTypedefBaseName = emitter.getFunctionPointerTypedefName(binding.getCSymbol());
+            final String funcPointerTypedefLocalName = "_local_" + funcPointerTypedefBaseName;
+            final String funcPointerTypedefName;
+            if (hasProcAddrTypedef) {
+                funcPointerTypedefName = funcPointerTypedefBaseName;
+            } else {
+                funcPointerTypedefName = funcPointerTypedefLocalName;
             }
 
-            final String ptrVarName = "ptr_" + cSym.getName();
+            final String ptrVarName = "ptr_" + getNativeName();
 
+            if (hasProcAddrTypedef) {
+                writer.println("  // implicit type validation of "+funcPointerTypedefLocalName+" -> "+funcPointerTypedefName);
+            }
             writer.print("  ");
             writer.print(ptrVarName);
             writer.print(" = (");
-            writer.print(funcPointerTypedefName);
+            writer.print(funcPointerTypedefLocalName);
             writer.println(") (intptr_t) procAddress;");
 
             writer.println("  assert(" + ptrVarName + " != NULL);");
@@ -181,7 +196,12 @@ public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter {
             final Type cReturnType = binding.getCReturnType();
 
             if (!cReturnType.isVoid()) {
-                writer.print("_res = ");
+                // Note we respect const/volatile in the function return type.
+                // However, we cannot have it 'const' for our local variable.
+                // See return type in CMethodBindingEmitter.emitBodyVariableDeclarations(..)!
+                writer.print("_res = (");
+                writer.print(cReturnType.getCName(false));
+                writer.print(") ");
             }
             final MethodBinding mBinding = getBinding();
             if (mBinding.hasContainingType()) {
@@ -192,7 +212,7 @@ public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter {
 
             // call throught the run-time function pointer
             writer.print("(* ptr_");
-            writer.print(mBinding.getCSymbol().getName());
+            writer.print(getNativeName());
             writer.print(") ");
             writer.print("(");
             emitBodyPassCArguments(writer);
diff --git a/src/java/com/jogamp/gluegen/procaddress/ProcAddressConfiguration.java b/src/java/com/jogamp/gluegen/procaddress/ProcAddressConfiguration.java
index 7fc720c..36d433a 100644
--- a/src/java/com/jogamp/gluegen/procaddress/ProcAddressConfiguration.java
+++ b/src/java/com/jogamp/gluegen/procaddress/ProcAddressConfiguration.java
@@ -38,7 +38,12 @@
  */
 package com.jogamp.gluegen.procaddress;
 
+import static java.util.logging.Level.INFO;
+
 import com.jogamp.gluegen.JavaConfiguration;
+import com.jogamp.gluegen.cgram.types.AliasedSymbol;
+import com.jogamp.gluegen.cgram.types.FunctionSymbol;
+
 import java.io.*;
 import java.text.*;
 import java.util.*;
@@ -82,7 +87,7 @@ public class ProcAddressConfiguration extends JavaConfiguration {
                 addForceProcAddressGen(funcName);
             }
         } else if (cmd.equalsIgnoreCase("GetProcAddressTableExpr")) {
-            getProcAddressTableExpr = readGetProcAddressTableExpr(tok, filename, lineNo);
+            setProcAddressTableExpr( readGetProcAddressTableExpr(tok, filename, lineNo) );
         } else if (cmd.equalsIgnoreCase("ProcAddressNameExpr")) {
             readProcAddressNameExpr(tok, filename, lineNo);
         } else if (cmd.equalsIgnoreCase("LocalProcAddressCallingConvention")) {
@@ -269,8 +274,15 @@ public class ProcAddressConfiguration extends JavaConfiguration {
         return tableClassName;
     }
 
-    public boolean skipProcAddressGen(final String name) {
-        return skipProcAddressGen.contains(name);
+    public boolean skipProcAddressGen(final FunctionSymbol symbol) {
+      if ( skipProcAddressGen.contains( symbol.getName() ) ||
+           oneInSet(skipProcAddressGen, symbol.getAliasedNames())
+         )
+      {
+          LOG.log(INFO, symbol.getASTLocusTag(), "Skip ProcAddress: {0}", symbol);
+          return true;
+      }
+      return false;
     }
 
     public boolean isForceProcAddressGen4All() {
@@ -287,6 +299,9 @@ public class ProcAddressConfiguration extends JavaConfiguration {
         }
         return getProcAddressTableExpr;
     }
+    protected void setProcAddressTableExpr(final String s) {
+        getProcAddressTableExpr = s;
+    }
 
     public String convertToFunctionPointerName(final String funcName) {
         if (procAddressNameConverter == null) {
@@ -295,9 +310,25 @@ public class ProcAddressConfiguration extends JavaConfiguration {
         return procAddressNameConverter.convert(funcName);
     }
 
-    public boolean forceProcAddressGen(final String funcName) {
-        return forceProcAddressGen4All || forceProcAddressGenSet.contains(funcName);
+    public boolean forceProcAddressGen(final FunctionSymbol symbol) {
+        if( forceProcAddressGen4All ) {
+            if(!forceProcAddressGen4AllOnce) {
+                forceProcAddressGen4AllOnce = true;
+                LOG.log(INFO, symbol.getASTLocusTag(), "Force ALL ProcAddress");
+            }
+            return true;
+        }
+
+        if ( forceProcAddressGenSet.contains( symbol.getName() ) ||
+             oneInSet(forceProcAddressGenSet, symbol.getAliasedNames())
+           )
+        {
+            LOG.log(INFO, symbol.getASTLocusTag(), "Force ProcAddress: {0}", symbol);
+            return true;
+        }
+        return false;
     }
+    private static boolean forceProcAddressGen4AllOnce = false;
 
     public void addForceProcAddressGen(final String funcName) {
         forceProcAddressGen.add(funcName);
@@ -308,11 +339,15 @@ public class ProcAddressConfiguration extends JavaConfiguration {
         localProcAddressCallingConventionMap.put(funcName, callingConvention);
     }
 
-    public String getLocalProcAddressCallingConvention(final String funcName) {
-        if (isLocalProcAddressCallingConvention4All()) {
+    public String getLocalProcAddressCallingConvention(final FunctionSymbol symbol) {
+        if ( isLocalProcAddressCallingConvention4All() ) {
             return getLocalProcAddressCallingConvention4All();
         }
-        return localProcAddressCallingConventionMap.get(funcName);
+        final String res = localProcAddressCallingConventionMap.get(symbol.getName());
+        if( null != res ) {
+            return res;
+        }
+        return oneInMap(localProcAddressCallingConventionMap, symbol.getAliasedNames());
     }
 
     public boolean isLocalProcAddressCallingConvention4All() {
diff --git a/src/java/com/jogamp/gluegen/procaddress/ProcAddressEmitter.java b/src/java/com/jogamp/gluegen/procaddress/ProcAddressEmitter.java
index a0adbd0..ec29b08 100644
--- a/src/java/com/jogamp/gluegen/procaddress/ProcAddressEmitter.java
+++ b/src/java/com/jogamp/gluegen/procaddress/ProcAddressEmitter.java
@@ -47,6 +47,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.logging.Level;
 
 import com.jogamp.gluegen.CMethodBindingEmitter;
 import com.jogamp.gluegen.CodeGenUtils;
@@ -54,7 +55,6 @@ import com.jogamp.gluegen.FunctionEmitter;
 import com.jogamp.gluegen.JavaConfiguration;
 import com.jogamp.gluegen.JavaEmitter;
 import com.jogamp.gluegen.JavaMethodBindingEmitter;
-import com.jogamp.gluegen.MethodBinding;
 import com.jogamp.gluegen.cgram.types.FunctionSymbol;
 import com.jogamp.gluegen.cgram.types.Type;
 import com.jogamp.gluegen.cgram.types.TypeDictionary;
@@ -114,40 +114,45 @@ public class ProcAddressEmitter extends JavaEmitter {
     }
 
     @Override
-    protected List<? extends FunctionEmitter> generateMethodBindingEmitters(final Set<MethodBinding> methodBindingSet, final FunctionSymbol sym) throws Exception {
-        return generateMethodBindingEmittersImpl(methodBindingSet, sym);
+    protected List<? extends FunctionEmitter> generateMethodBindingEmitters(final FunctionSymbol sym) throws Exception {
+        return generateMethodBindingEmittersImpl(sym);
     }
 
     protected boolean needsModifiedEmitters(final FunctionSymbol sym) {
-        if (!needsProcAddressWrapper(sym) || getConfig().isUnimplemented(getAliasedSymName(sym))) {
+        if ( !callThroughProcAddress(sym) || getConfig().isUnimplemented(sym) ) {
             return false;
+        } else {
+            return true;
         }
-
-        return true;
     }
 
-    private List<? extends FunctionEmitter> generateMethodBindingEmittersImpl(final Set<MethodBinding> methodBindingSet, final FunctionSymbol sym) throws Exception {
-        final List<? extends FunctionEmitter> defaultEmitters = super.generateMethodBindingEmitters(methodBindingSet, sym);
+    private List<? extends FunctionEmitter> generateMethodBindingEmittersImpl(final FunctionSymbol sym) throws Exception {
+        final List<? extends FunctionEmitter> defaultEmitters = super.generateMethodBindingEmitters(sym);
 
         // if the superclass didn't generate any bindings for the symbol, let's
         // honor that (for example, the superclass might have caught an Ignore
         // direction that matched the symbol's name).
         if (defaultEmitters.isEmpty()) {
+            LOG.log(Level.INFO, sym.getASTLocusTag(), "genModProcAddrEmitter: SKIP, empty binding set: {0}", sym);
             return defaultEmitters;
         }
 
-        // Don't do anything special if this symbol doesn't require
-        // modifications
-        if (!needsModifiedEmitters(sym)) {
+        final boolean callThroughProcAddress = callThroughProcAddress(sym);
+        final boolean isUnimplemented = getConfig().isUnimplemented(sym);
+
+        // Don't do anything special if this symbol doesn't require modifications
+        if( !callThroughProcAddress || isUnimplemented ) {
+            LOG.log(Level.INFO, sym.getASTLocusTag(), "genModProcAddrEmitter: SKIP, not needed: callThrough {0}, isUnimplemented {1}: {2}",
+                    callThroughProcAddress, isUnimplemented, sym);
             return defaultEmitters;
         }
 
         final ArrayList<FunctionEmitter> modifiedEmitters = new ArrayList<FunctionEmitter>(defaultEmitters.size());
 
-        if (needsProcAddressWrapper(sym)) {
+        if ( callThroughProcAddress ) {
             if (getProcAddressConfig().emitProcAddressTable()) {
                 // emit an entry in the GL proc address table for this method.
-                emitProcAddressTableEntryForString(getAliasedSymName(sym));
+                emitProcAddressTableEntryForString(sym.getName());
             }
         }
         for (final FunctionEmitter emitter : defaultEmitters) {
@@ -172,7 +177,7 @@ public class ProcAddressEmitter extends JavaEmitter {
      * whether or not the typedef is actually defined.
      */
     protected String getFunctionPointerTypedefName(final FunctionSymbol sym) {
-        return getProcAddressConfig().convertToFunctionPointerName(sym.getName());
+        return getProcAddressConfig().convertToFunctionPointerName(sym.getOrigName());
     }
 
     //----------------------------------------------------------------------
@@ -194,20 +199,14 @@ public class ProcAddressEmitter extends JavaEmitter {
 
   protected void generateModifiedEmitters(final JavaMethodBindingEmitter baseJavaEmitter, final List<FunctionEmitter> emitters) {
         // See whether we need a proc address entry for this one
-        final boolean callThroughProcAddress = needsProcAddressWrapper(baseJavaEmitter.getBinding().getCSymbol());
+        final boolean callThroughProcAddress = callThroughProcAddress(baseJavaEmitter.getBinding().getCSymbol());
 
         // If this emitter doesn't have a body (i.e., is a direct native
         // call with no intervening argument processing), we need to force
-        // it to emit a body, and produce another one to act as the entry
-        // point
-        // FIXME: the negative test against the PRIVATE modifier is a
-        // nasty hack to prevent the ProcAddressJavaMethodBindingEmitter
-        // from incorrectly introducing method bodies to the private
-        // native implementing methods; want this to work at least for
-        // public and package-private methods
+        // it to emit a body, and produce another one to act as the entry point
         final boolean needsJavaWrapper = baseJavaEmitter.signatureOnly() &&
-                                        !baseJavaEmitter.hasModifier(JavaMethodBindingEmitter.PRIVATE) &&
-                                         baseJavaEmitter.hasModifier(JavaMethodBindingEmitter.NATIVE) &&
+                                         baseJavaEmitter.isNativeMethod() &&
+                                         !baseJavaEmitter.isPrivateNativeMethod() &&
                                          callThroughProcAddress;
 
 
@@ -215,7 +214,7 @@ public class ProcAddressEmitter extends JavaEmitter {
             final ProcAddressJavaMethodBindingEmitter emitter = new ProcAddressJavaMethodBindingEmitter(baseJavaEmitter,
                     callThroughProcAddress,
                     getProcAddressConfig().getProcAddressTableExpr(),
-                    baseJavaEmitter.isForImplementingMethodCall(),
+                    baseJavaEmitter.isPrivateNativeMethod(),
                     this);
             if( needsJavaWrapper ) {
                 emitter.setEmitBody(true);
@@ -232,7 +231,7 @@ public class ProcAddressEmitter extends JavaEmitter {
                     getProcAddressConfig().getProcAddressTableExpr(),
                     true,
                     this);
-            emitter.setForImplementingMethodCall(true);
+            emitter.setPrivateNativeMethod(true);
             fixSecurityModifiers(emitter);
             emitters.add(emitter);
         }
@@ -243,13 +242,13 @@ public class ProcAddressEmitter extends JavaEmitter {
         final FunctionSymbol cSymbol = baseCEmitter.getBinding().getCSymbol();
 
         // See whether we need a proc address entry for this one
-        final boolean callThroughProcAddress = needsProcAddressWrapper(cSymbol);
-        final boolean forceProcAddress = getProcAddressConfig().forceProcAddressGen(cSymbol.getName());
+        final boolean hasProcAddrTypedef = hasFunctionPointerTypedef(cSymbol);
+        final boolean callThroughProcAddress = hasProcAddrTypedef || callThroughProcAddress(cSymbol);
+        final String localProcCallingConvention = getProcAddressConfig().getLocalProcAddressCallingConvention(cSymbol);
+
+        LOG.log(Level.INFO, cSymbol.getASTLocusTag(), "genModProcAddrEmitter: callThrough {0}, hasTypedef {1}, localCallConv {2}: {3}",
+                callThroughProcAddress, hasProcAddrTypedef, localProcCallingConvention, cSymbol);
 
-        String forcedCallingConvention = null;
-        if (forceProcAddress) {
-            forcedCallingConvention = getProcAddressConfig().getLocalProcAddressCallingConvention(cSymbol.getName());
-        }
         // Note that we don't care much about the naming of the C argument
         // variables so to keep things simple we ignore the buffer object
         // property for the binding
@@ -258,7 +257,7 @@ public class ProcAddressEmitter extends JavaEmitter {
         // extra final argument, which is the address (the OpenGL procedure
         // address) of the function it needs to call
         final ProcAddressCMethodBindingEmitter res = new ProcAddressCMethodBindingEmitter(
-                baseCEmitter, callThroughProcAddress, forceProcAddress, forcedCallingConvention, this);
+                baseCEmitter, callThroughProcAddress, hasProcAddrTypedef, localProcCallingConvention, this);
 
         final MessageFormat exp = baseCEmitter.getReturnValueCapacityExpression();
         if (exp != null) {
@@ -267,34 +266,30 @@ public class ProcAddressEmitter extends JavaEmitter {
         emitters.add(res);
     }
 
-    private String getAliasedSymName(final FunctionSymbol sym) {
-        String symName = getConfig().getJavaSymbolRename(sym.getName());
-        if (null == symName) {
-            symName = sym.getName();
+    protected boolean callThroughProcAddress(final FunctionSymbol sym) {
+        final ProcAddressConfiguration cfg = getProcAddressConfig();
+        boolean res = false;
+        int mode = 0;
+        if (cfg.forceProcAddressGen(sym)) {
+            res = true;
+            mode = 1;
+        } else {
+            if (cfg.skipProcAddressGen(sym)) {
+                res = false;
+                mode = 2;
+            } else {
+                res = hasFunctionPointerTypedef(sym);
+                mode = 3;
+            }
         }
-        return symName;
+        LOG.log(Level.INFO, sym.getASTLocusTag(), "callThroughProcAddress: {0} [m {1}]: {2}", res, mode, sym);
+        return res;
     }
-
-    protected boolean needsProcAddressWrapper(final FunctionSymbol sym) {
-        final String symName = getAliasedSymName(sym);
-
-        final ProcAddressConfiguration config = getProcAddressConfig();
-
-        // We should only generate code to call through a function pointer
-        // if the symbol has an associated function pointer typedef.
+    protected boolean hasFunctionPointerTypedef(final FunctionSymbol sym) {
         final String funcPointerTypedefName = getFunctionPointerTypedefName(sym);
-        boolean shouldWrap = typedefDictionary.containsKey(funcPointerTypedefName);
-        //System.err.println(funcPointerTypedefName + " defined: " + shouldWrap);
-
-        if (config.skipProcAddressGen(symName)) {
-            shouldWrap = false;
-        }
-
-        if (config.forceProcAddressGen(symName)) {
-            shouldWrap = true;
-        }
-
-        return shouldWrap;
+        final boolean res = typedefDictionary.containsKey(funcPointerTypedefName);
+        LOG.log(Level.INFO, sym.getASTLocusTag(), "hasFunctionPointerTypedef: {0}: {1}", res, sym);
+        return res;
     }
 
     protected void beginProcAddressTable() throws Exception {
@@ -307,8 +302,8 @@ public class ProcAddressEmitter extends JavaEmitter {
         if (implPackageName == null) {
             implPackageName = getImplPackageName();
         }
-        final String fullTableClassName = implPackageName + "." + tableClassName;
-        final MethodAccess tableClassAccess = cfg.accessControl(fullTableClassName);
+        final String tableClassFQN = implPackageName + "." + tableClassName;
+        final String[] accessModifiers = getClassAccessModifiers(tableClassFQN);
 
         final String jImplRoot = getJavaOutputDir() + File.separator + CodeGenUtils.packageAsPath(implPackageName);
 
@@ -330,7 +325,11 @@ public class ProcAddressEmitter extends JavaEmitter {
         tableWriter.println(" * This table is a cache of pointers to the dynamically-linkable C library.");
         tableWriter.println(" * @see " + ProcAddressTable.class.getSimpleName());
         tableWriter.println(" */");
-        tableWriter.println(tableClassAccess.getJavaName() + " final class " + tableClassName + " extends "+ ProcAddressTable.class.getSimpleName() + " {");
+        for (int i = 0; accessModifiers != null && i < accessModifiers.length; ++i) {
+            tableWriter.print(accessModifiers[i]);
+            tableWriter.print(' ');
+        }
+        tableWriter.println("final class " + tableClassName + " extends "+ ProcAddressTable.class.getSimpleName() + " {");
         tableWriter.println();
 
         for (final String string : getProcAddressConfig().getForceProcAddressGen()) {
diff --git a/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java
index a70c18d..5298a8d 100644
--- a/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java
+++ b/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java
@@ -41,6 +41,7 @@ package com.jogamp.gluegen.procaddress;
 import com.jogamp.gluegen.MethodBinding;
 import com.jogamp.gluegen.FunctionEmitter;
 import com.jogamp.gluegen.JavaMethodBindingEmitter;
+
 import java.io.*;
 
 /** A specialization of JavaMethodBindingEmitter with knowledge of how
@@ -76,12 +77,12 @@ public class ProcAddressJavaMethodBindingEmitter extends JavaMethodBindingEmitte
 
     public ProcAddressJavaMethodBindingEmitter(final ProcAddressJavaMethodBindingEmitter methodToWrap) {
         this(methodToWrap, methodToWrap.callThroughProcAddress, methodToWrap.getProcAddressTableExpr,
-                methodToWrap.changeNameAndArguments, methodToWrap.emitter);
+             methodToWrap.changeNameAndArguments, methodToWrap.emitter);
     }
 
     @Override
-    public String getName() {
-        final String res = super.getName();
+    public String getImplName() {
+        final String res = super.getImplName();
         if (changeNameAndArguments) {
             return ProcAddressEmitter.WRAP_PREFIX + res;
         }
@@ -106,8 +107,8 @@ public class ProcAddressJavaMethodBindingEmitter extends JavaMethodBindingEmitte
     }
 
     @Override
-    protected String getImplMethodName() {
-        final String name = super.getImplMethodName();
+    protected String getNativeImplMethodName() {
+        final String name = super.getNativeImplMethodName();
         if (callThroughProcAddress) {
             return ProcAddressEmitter.WRAP_PREFIX + name;
         }
@@ -119,7 +120,7 @@ public class ProcAddressJavaMethodBindingEmitter extends JavaMethodBindingEmitte
         super.emitPreCallSetup(binding, writer);
 
         if (callThroughProcAddress) {
-            final String procAddressVariable = ProcAddressEmitter.PROCADDRESS_VAR_PREFIX + binding.getName();
+            final String procAddressVariable = ProcAddressEmitter.PROCADDRESS_VAR_PREFIX + binding.getNativeName();
             writer.println("    final long __addr_ = " + getProcAddressTableExpr + "." + procAddressVariable + ";");
             writer.println("    if (__addr_ == 0) {");
             writer.format("      throw new %s(String.format(\"Method \\\"%%s\\\" not available\", \"%s\"));%n",
diff --git a/src/java/com/jogamp/gluegen/runtime/FunctionAddressResolver.java b/src/java/com/jogamp/gluegen/runtime/FunctionAddressResolver.java
index 4fc40a4..ea7cfa2 100644
--- a/src/java/com/jogamp/gluegen/runtime/FunctionAddressResolver.java
+++ b/src/java/com/jogamp/gluegen/runtime/FunctionAddressResolver.java
@@ -32,16 +32,20 @@
 package com.jogamp.gluegen.runtime;
 
 import com.jogamp.common.os.DynamicLookupHelper;
+import com.jogamp.common.util.SecurityUtil;
 
 /**
- *
- * @author Michael Bien
+ * @author Michael Bien, et.al.
  */
 public interface FunctionAddressResolver {
 
     /**
      * Resolves the name of the function bound to the method and returns the address.
+     * <p>
+     * Implementation shall ensure {@link SecurityUtil#checkLinkPermission(String)} is performed.
+     * </p>
+     * @throws SecurityException if user is not granted access for the library set.
      */
-    public long resolve(String name, DynamicLookupHelper lookup);
+    public long resolve(String name, DynamicLookupHelper lookup) throws SecurityException;
 
 }
diff --git a/src/java/com/jogamp/gluegen/runtime/ProcAddressTable.java b/src/java/com/jogamp/gluegen/runtime/ProcAddressTable.java
index a0988cd..03ed5c1 100644
--- a/src/java/com/jogamp/gluegen/runtime/ProcAddressTable.java
+++ b/src/java/com/jogamp/gluegen/runtime/ProcAddressTable.java
@@ -119,8 +119,6 @@ public abstract class ProcAddressTable {
      * @throws SecurityException if user is not granted access for all libraries.
      */
     public void reset(final DynamicLookupHelper lookup) throws SecurityException, RuntimeException {
-        SecurityUtil.checkAllLinkPermission();
-
         if(null==lookup) {
             throw new RuntimeException("Passed null DynamicLookupHelper");
         }
@@ -137,13 +135,17 @@ public abstract class ProcAddressTable {
 
         // All at once - performance.
         AccessibleObject.setAccessible(fields, true);
-
-        for (int i = 0; i < fields.length; ++i) {
-            final String fieldName = fields[i].getName();
-            if ( isAddressField(fieldName) ) {
-                final String funcName = fieldToFunctionName(fieldName);
-                setEntry(fields[i], funcName, lookup);
+        lookup.claimAllLinkPermission();
+        try {
+            for (int i = 0; i < fields.length; ++i) {
+                final String fieldName = fields[i].getName();
+                if ( isAddressField(fieldName) ) {
+                    final String funcName = fieldToFunctionName(fieldName);
+                    setEntry(fields[i], funcName, lookup);
+                }
             }
+        } finally {
+            lookup.releaseAllLinkPermission();
         }
 
         if (DEBUG) {
@@ -165,7 +167,6 @@ public abstract class ProcAddressTable {
      * @throws SecurityException if user is not granted access for all libraries.
      */
     public void initEntry(final String name, final DynamicLookupHelper lookup) throws SecurityException, IllegalArgumentException {
-        SecurityUtil.checkAllLinkPermission();
         final Field addressField = fieldForFunction(name);
         addressField.setAccessible(true);
         setEntry(addressField, name, lookup);
@@ -174,7 +175,7 @@ public abstract class ProcAddressTable {
     private final void setEntry(final Field addressField, final String funcName, final DynamicLookupHelper lookup) throws SecurityException {
         try {
             assert (addressField.getType() == Long.TYPE);
-            final long newProcAddress = resolver.resolve(funcName, lookup);
+            final long newProcAddress = resolver.resolve(funcName, lookup); // issues SecurityUtil.checkLinkPermission(String)
             addressField.setLong(this, newProcAddress);
             if (DEBUG) {
                 getDebugOutStream().println("  " + addressField.getName() + " -> 0x" + Long.toHexString(newProcAddress));
@@ -343,7 +344,7 @@ public abstract class ProcAddressTable {
 
     private static class One2OneResolver implements FunctionAddressResolver {
         @Override
-        public long resolve(final String name, final DynamicLookupHelper lookup) {
+        public long resolve(final String name, final DynamicLookupHelper lookup) throws SecurityException {
             return lookup.dynamicLookupFunction(name);
         }
     }
diff --git a/src/java/com/jogamp/gluegen/structgen/CStructAnnotationProcessor.java b/src/java/com/jogamp/gluegen/structgen/CStructAnnotationProcessor.java
index c4dedb7..7ccfd1b 100644
--- a/src/java/com/jogamp/gluegen/structgen/CStructAnnotationProcessor.java
+++ b/src/java/com/jogamp/gluegen/structgen/CStructAnnotationProcessor.java
@@ -131,7 +131,11 @@ public class CStructAnnotationProcessor extends AbstractProcessor {
             if( f.exists() ) {
                 return f;
             }
-        } catch (final IOException e) { if(DEBUG) { System.err.println("Caught "+e.getClass().getSimpleName()+": "+e.getMessage()); /* e.printStackTrace(); */ } }
+        } catch (final IOException e) {
+            if(DEBUG) {
+                System.err.println("Caught "+e.getClass().getSimpleName()+": "+e.getMessage()); /* e.printStackTrace(); */
+            }
+        }
         return null;
     }
 
@@ -263,6 +267,9 @@ public class CStructAnnotationProcessor extends AbstractProcessor {
         } catch (final FileNotFoundException ex) {
             throw new RuntimeException("input file not found", ex);
         }
+        if( DEBUG  ) {
+            GlueGen.setDebug(true);
+        }
         new GlueGen().run(reader, filename, AnnotationProcessorJavaStructEmitter.class,
                           includePaths, cfgFiles, outputPath1, false /* copyCPPOutput2Stderr */);
 
diff --git a/src/java/jogamp/android/launcher/ClassLoaderUtil.java b/src/java/jogamp/android/launcher/ClassLoaderUtil.java
index 5238fd4..8db6d0a 100644
--- a/src/java/jogamp/android/launcher/ClassLoaderUtil.java
+++ b/src/java/jogamp/android/launcher/ClassLoaderUtil.java
@@ -28,7 +28,14 @@
 
 package jogamp.android.launcher;
 
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -46,6 +53,7 @@ public class ClassLoaderUtil {
    // location where optimized dex files will be written
    private static final String dexPathName= "jogampDex";
    private static File dexPath = null;
+   private static boolean needsAPKCopy;
 
    private static LauncherTempFileCache tmpFileCache = null;
 
@@ -64,6 +72,9 @@ public class ClassLoaderUtil {
            dexPath = new File(tmpFileCache.getTempDir(), dexPathName);
            Log.d(TAG, "jogamp dexPath: " + dexPath.getAbsolutePath());
            dexPath.mkdir();
+
+           needsAPKCopy = android.os.Build.VERSION.SDK_INT >= 21; // >= LOLLIPOP
+           Log.d(TAG, "jogamp Android SDK "+android.os.Build.VERSION.SDK_INT+", needsAPKCopy "+needsAPKCopy);
        }
    }
 
@@ -151,6 +162,18 @@ public class ClassLoaderUtil {
                            libs.append(ELEM_SEP);
                        }
                    }
+                   if( needsAPKCopy ) {
+                       final File src = new File(userAPK);
+                       userAPK = dexPath + "/" + lastUserPackageName + "-1.apk";
+                       final File dst = new File(userAPK);
+                       try {
+                           copyFile(src, dst);
+                       } catch (final IOException e) {
+                           Log.d(TAG, "error copying <"+src+"> -> <"+dst+">: "+e, e);
+                           return null;
+                       }
+                       Log.d(TAG, "APK["+apkCount+"] copied: <"+src+"> -> <"+dst+">");
+                   }
                    apks.append(userAPK);
                    Log.d(TAG, "APK["+apkCount+"] found: <"+lastUserPackageName+"> -> <"+userAPK+">");
                    Log.d(TAG, "APK["+apkCount+"] apks: <"+apks.toString()+">");
@@ -194,6 +217,31 @@ public class ClassLoaderUtil {
        return new AssetDexClassLoader(apks.toString(), dexPath.getAbsolutePath(), libs.toString(), parent);
    }
 
+   private static int copyFile(final File src, final File dst) throws IOException {
+       int totalBytes = 0;
+       final InputStream in = new BufferedInputStream(new FileInputStream(src));
+       try {
+           final OutputStream out = new BufferedOutputStream(new FileOutputStream(dst));
+           try {
+               final byte[] buf = new byte[bufferSize];
+               while (true) {
+                   int count;
+                   if ((count = in.read(buf)) == -1) {
+                       break;
+                   }
+                   out.write(buf, 0, count);
+                   totalBytes += count;
+               }
+           } finally {
+               out.close();
+           }
+       } finally {
+           in.close();
+       }
+       return totalBytes;
+   }
+   private static final int bufferSize = 4096;
+
    /***
     *
    public boolean setAPKClassLoader(String activityPackageName, ClassLoader classLoader)
diff --git a/src/java/jogamp/common/os/BionicDynamicLinkerImpl.java b/src/java/jogamp/common/os/BionicDynamicLinker32bitImpl.java
similarity index 76%
copy from src/java/jogamp/common/os/BionicDynamicLinkerImpl.java
copy to src/java/jogamp/common/os/BionicDynamicLinker32bitImpl.java
index b293776..e51ae69 100644
--- a/src/java/jogamp/common/os/BionicDynamicLinkerImpl.java
+++ b/src/java/jogamp/common/os/BionicDynamicLinker32bitImpl.java
@@ -28,34 +28,36 @@
 package jogamp.common.os;
 
 /**
- * Bionic specialization of {@link UnixDynamicLinkerImpl}
+ * Bionic 32bit specialization of {@link UnixDynamicLinkerImpl}
  * utilizing Bionic's non POSIX flags and mode values.
  * <p>
  * Bionic is used on Android.
  * </p>
  */
-public final class BionicDynamicLinkerImpl extends UnixDynamicLinkerImpl {
-  private static final long RTLD_DEFAULT = 0xffffffffL;
-  //      static final long RTLD_NEXT    = 0xfffffffeL;
+public final class BionicDynamicLinker32bitImpl extends UnixDynamicLinkerImpl {
 
-  private static final int RTLD_LAZY     = 0x00001;
   //      static final int RTLD_NOW      = 0x00000;
+  private static final int RTLD_LAZY     = 0x00001;
+
   private static final int RTLD_LOCAL    = 0x00000;
   private static final int RTLD_GLOBAL   = 0x00002;
+  //      static final int RTLD_NOLOAD   = 0x00004;
+
+  private static final long RTLD_DEFAULT = 0xffffffffL;
+  //      static final long RTLD_NEXT    = 0xfffffffeL;
 
   @Override
-  public final long openLibraryLocal(final String pathname, final boolean debug) throws SecurityException {
-    return this.openLibraryImpl(pathname, RTLD_LAZY | RTLD_LOCAL, debug);
+  protected final long openLibraryLocalImpl(final String pathname) throws SecurityException {
+    return dlopen(pathname, RTLD_LAZY | RTLD_LOCAL);
   }
 
   @Override
-  public final long openLibraryGlobal(final String pathname, final boolean debug) throws SecurityException {
-    return this.openLibraryImpl(pathname, RTLD_LAZY | RTLD_GLOBAL, debug);
+  protected final long openLibraryGlobalImpl(final String pathname) throws SecurityException {
+    return dlopen(pathname, RTLD_LAZY | RTLD_GLOBAL);
   }
 
   @Override
-  public final long lookupSymbolGlobal(final String symbolName) throws SecurityException {
-    return this.lookupSymbolGlobalImpl(RTLD_DEFAULT, symbolName);
+  protected final long lookupSymbolGlobalImpl(final String symbolName) throws SecurityException {
+    return dlsym(RTLD_DEFAULT, symbolName);
   }
-
 }
diff --git a/src/java/jogamp/common/os/BionicDynamicLinkerImpl.java b/src/java/jogamp/common/os/BionicDynamicLinker64BitImpl.java
similarity index 66%
rename from src/java/jogamp/common/os/BionicDynamicLinkerImpl.java
rename to src/java/jogamp/common/os/BionicDynamicLinker64BitImpl.java
index b293776..d8d3134 100644
--- a/src/java/jogamp/common/os/BionicDynamicLinkerImpl.java
+++ b/src/java/jogamp/common/os/BionicDynamicLinker64BitImpl.java
@@ -1,5 +1,5 @@
 /**
- * Copyright 2013 JogAmp Community. All rights reserved.
+ * Copyright 2015 JogAmp Community. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without modification, are
  * permitted provided that the following conditions are met:
@@ -28,34 +28,36 @@
 package jogamp.common.os;
 
 /**
- * Bionic specialization of {@link UnixDynamicLinkerImpl}
+ * Bionic 64bit specialization of {@link UnixDynamicLinkerImpl}
  * utilizing Bionic's non POSIX flags and mode values.
  * <p>
  * Bionic is used on Android.
  * </p>
  */
-public final class BionicDynamicLinkerImpl extends UnixDynamicLinkerImpl {
-  private static final long RTLD_DEFAULT = 0xffffffffL;
-  //      static final long RTLD_NEXT    = 0xfffffffeL;
-
+public final class BionicDynamicLinker64BitImpl extends UnixDynamicLinkerImpl {
+  //      static final int RTLD_NOW      = 0x00002;
   private static final int RTLD_LAZY     = 0x00001;
-  //      static final int RTLD_NOW      = 0x00000;
+
   private static final int RTLD_LOCAL    = 0x00000;
-  private static final int RTLD_GLOBAL   = 0x00002;
+  private static final int RTLD_GLOBAL   = 0x00100;
+  //      static final int RTLD_NOLOAD   = 0x00004;
+
+  private static final long RTLD_DEFAULT = 0x00000000L;
+  //      static final long RTLD_NEXT    = -1L;
 
   @Override
-  public final long openLibraryLocal(final String pathname, final boolean debug) throws SecurityException {
-    return this.openLibraryImpl(pathname, RTLD_LAZY | RTLD_LOCAL, debug);
+  protected final long openLibraryLocalImpl(final String pathname) throws SecurityException {
+    return dlopen(pathname, RTLD_LAZY | RTLD_LOCAL);
   }
 
   @Override
-  public final long openLibraryGlobal(final String pathname, final boolean debug) throws SecurityException {
-    return this.openLibraryImpl(pathname, RTLD_LAZY | RTLD_GLOBAL, debug);
+  protected final long openLibraryGlobalImpl(final String pathname) throws SecurityException {
+    return dlopen(pathname, RTLD_LAZY | RTLD_GLOBAL);
   }
 
   @Override
-  public final long lookupSymbolGlobal(final String symbolName) throws SecurityException {
-    return this.lookupSymbolGlobalImpl(RTLD_DEFAULT, symbolName);
+  protected final long lookupSymbolGlobalImpl(final String symbolName) throws SecurityException {
+    return dlsym(RTLD_DEFAULT, symbolName);
   }
 
 }
diff --git a/src/java/jogamp/common/os/DynamicLinkerImpl.java b/src/java/jogamp/common/os/DynamicLinkerImpl.java
index 392d906..56a909e 100644
--- a/src/java/jogamp/common/os/DynamicLinkerImpl.java
+++ b/src/java/jogamp/common/os/DynamicLinkerImpl.java
@@ -29,6 +29,7 @@ package jogamp.common.os;
 
 import com.jogamp.common.os.DynamicLinker;
 import com.jogamp.common.util.LongObjectHashMap;
+import com.jogamp.common.util.SecurityUtil;
 
 /* pp */ abstract class DynamicLinkerImpl implements DynamicLinker {
 
@@ -38,18 +39,134 @@ import com.jogamp.common.util.LongObjectHashMap;
   // ensuring no abuse via subclassing.
   //
 
-  private final LongObjectHashMap libHandle2Name = new LongObjectHashMap( 16 /* initialCapacity */ );
+  private final Object secSync = new Object();
+  private boolean allLinkPermissionGranted = false;
 
-  protected static final class LibRef {
-      public LibRef(final String name) {
+  /**
+   * @throws SecurityException if user is not granted global access
+   */
+  public final void claimAllLinkPermission() throws SecurityException {
+      synchronized( secSync ) {
+          allLinkPermissionGranted = true;
+      }
+  }
+
+  /**
+   * @throws SecurityException if user is not granted global access
+   */
+  public final void releaseAllLinkPermission() throws SecurityException {
+      synchronized( secSync ) {
+          allLinkPermissionGranted = false;
+      }
+  }
+
+  private final void checkLinkPermission(final String pathname) throws SecurityException {
+      synchronized( secSync ) {
+          if( !allLinkPermissionGranted ) {
+              SecurityUtil.checkLinkPermission(pathname);
+          }
+      }
+  }
+  private final void checkLinkPermission(final long libraryHandle) throws SecurityException {
+      synchronized( secSync ) {
+          if( !allLinkPermissionGranted ) {
+              final LibRef libRef = getLibRef( libraryHandle );
+              if( null == libRef ) {
+                  throw new IllegalArgumentException("Library handle 0x"+Long.toHexString(libraryHandle)+" unknown.");
+              }
+              SecurityUtil.checkLinkPermission(libRef.getName());
+          }
+      }
+  }
+
+  private final void checkAllLinkPermission() throws SecurityException {
+      synchronized( secSync ) {
+          if( !allLinkPermissionGranted ) {
+              SecurityUtil.checkAllLinkPermission();
+          }
+      }
+  }
+
+  @Override
+  public final long openLibraryGlobal(final String pathname, final boolean debug) throws SecurityException {
+    checkLinkPermission(pathname);
+    final long handle = openLibraryGlobalImpl(pathname);
+    if( 0 != handle ) {
+        final LibRef libRef = incrLibRefCount(handle, pathname);
+        if( DEBUG || debug ) {
+            System.err.println("DynamicLinkerImpl.openLibraryGlobal \""+pathname+"\": 0x"+Long.toHexString(handle)+" -> "+libRef+")");
+        }
+    } else if ( DEBUG || debug ) {
+        System.err.println("DynamicLinkerImpl.openLibraryGlobal \""+pathname+"\" failed, error: "+getLastError());
+    }
+    return handle;
+  }
+  protected abstract long openLibraryGlobalImpl(final String pathname) throws SecurityException;
+
+  @Override
+  public final long openLibraryLocal(final String pathname, final boolean debug) throws SecurityException {
+    checkLinkPermission(pathname);
+    final long handle = openLibraryLocalImpl(pathname);
+    if( 0 != handle ) {
+        final LibRef libRef = incrLibRefCount(handle, pathname);
+        if( DEBUG || debug ) {
+            System.err.println("DynamicLinkerImpl.openLibraryLocal \""+pathname+"\": 0x"+Long.toHexString(handle)+" -> "+libRef+")");
+        }
+    } else if ( DEBUG || debug ) {
+        System.err.println("DynamicLinkerImpl.openLibraryLocal \""+pathname+"\" failed, error: "+getLastError());
+    }
+    return handle;
+  }
+  protected abstract long openLibraryLocalImpl(final String pathname) throws SecurityException;
+
+  @Override
+  public final long lookupSymbolGlobal(final String symbolName) throws SecurityException {
+    checkAllLinkPermission();
+    final long addr = lookupSymbolGlobalImpl(symbolName);
+    if(DEBUG_LOOKUP) {
+        System.err.println("DynamicLinkerImpl.lookupSymbolGlobal("+symbolName+") -> 0x"+Long.toHexString(addr));
+    }
+    return addr;
+  }
+  protected abstract long lookupSymbolGlobalImpl(final String symbolName) throws SecurityException;
+
+  @Override
+  public final long lookupSymbol(final long libraryHandle, final String symbolName) throws SecurityException, IllegalArgumentException {
+    checkLinkPermission(libraryHandle);
+    final long addr = lookupSymbolLocalImpl(libraryHandle, symbolName);
+    if(DEBUG_LOOKUP) {
+        System.err.println("DynamicLinkerImpl.lookupSymbol(0x"+Long.toHexString(libraryHandle)+", "+symbolName+") -> 0x"+Long.toHexString(addr));
+    }
+    return addr;
+  }
+  protected abstract long lookupSymbolLocalImpl(final long libraryHandle, final String symbolName) throws SecurityException;
+
+  @Override
+  public final void closeLibrary(final long libraryHandle, final boolean debug) throws SecurityException, IllegalArgumentException {
+    final LibRef libRef = decrLibRefCount( libraryHandle );
+    if( null == libRef ) {
+        throw new IllegalArgumentException("Library handle 0x"+Long.toHexString(libraryHandle)+" unknown.");
+    }
+    checkLinkPermission(libRef.getName());
+    if( DEBUG || debug ) {
+        System.err.println("DynamicLinkerImpl.closeLibrary(0x"+Long.toHexString(libraryHandle)+" -> "+libRef+")");
+    }
+    closeLibraryImpl(libraryHandle);
+  }
+  protected abstract void closeLibraryImpl(final long libraryHandle) throws SecurityException;
+
+  private static final LongObjectHashMap libHandle2Name = new LongObjectHashMap( 16 /* initialCapacity */ );
+
+  static final class LibRef {
+      LibRef(final String name) {
           this.name = name;
           this.refCount = 1;
       }
-      public final int incrRefCount() { return ++refCount; }
-      public final int decrRefCount() { return --refCount; }
-      public final int getRefCount() { return refCount; }
+      final int incrRefCount() { return ++refCount; }
+      final int decrRefCount() { return --refCount; }
+      final int getRefCount() { return refCount; }
 
-      public final String getName() { return name; }
+      final String getName() { return name; }
       @Override
       public final String toString() { return "LibRef["+name+", refCount "+refCount+"]"; }
 
@@ -57,35 +174,40 @@ import com.jogamp.common.util.LongObjectHashMap;
       private int refCount;
   }
 
-  protected final synchronized LibRef getLibRef(final long handle) {
-      return (LibRef) libHandle2Name.get(handle);
+  private final LibRef getLibRef(final long handle) {
+      synchronized( libHandle2Name ) {
+          return (LibRef) libHandle2Name.get(handle);
+      }
   }
 
-  protected final synchronized LibRef incrLibRefCount(final long handle, final String libName) {
-      LibRef libRef = getLibRef(handle);
-      if( null == libRef ) {
-          libRef = new LibRef(libName);
-          libHandle2Name.put(handle, libRef);
-      } else {
-          libRef.incrRefCount();
-      }
-      if(DEBUG) {
-          System.err.println("DynamicLinkerImpl.incrLibRefCount 0x"+Long.toHexString(handle)+ " -> "+libRef+", libs loaded "+libHandle2Name.size());
+  private final LibRef incrLibRefCount(final long handle, final String libName) {
+      synchronized( libHandle2Name ) {
+          LibRef libRef = getLibRef(handle);
+          if( null == libRef ) {
+              libRef = new LibRef(libName);
+              libHandle2Name.put(handle, libRef);
+          } else {
+              libRef.incrRefCount();
+          }
+          if(DEBUG) {
+              System.err.println("DynamicLinkerImpl.incrLibRefCount 0x"+Long.toHexString(handle)+ " -> "+libRef+", libs loaded "+libHandle2Name.size());
+          }
+          return libRef;
       }
-      return libRef;
   }
 
-  protected final synchronized LibRef decrLibRefCount(final long handle) {
-      final LibRef libRef = getLibRef(handle);
-      if( null != libRef ) {
-          if( 0 == libRef.decrRefCount() ) {
-              libHandle2Name.remove(handle);
+  private final LibRef decrLibRefCount(final long handle) {
+      synchronized( libHandle2Name ) {
+          final LibRef libRef = getLibRef(handle);
+          if( null != libRef ) {
+              if( 0 == libRef.decrRefCount() ) {
+                  libHandle2Name.remove(handle);
+              }
           }
+          if(DEBUG) {
+              System.err.println("DynamicLinkerImpl.decrLibRefCount 0x"+Long.toHexString(handle)+ " -> "+libRef+", libs loaded "+libHandle2Name.size());
+          }
+          return libRef;
       }
-      if(DEBUG) {
-          System.err.println("DynamicLinkerImpl.decrLibRefCount 0x"+Long.toHexString(handle)+ " -> "+libRef+", libs loaded "+libHandle2Name.size());
-      }
-      return libRef;
   }
-
 }
diff --git a/src/java/jogamp/common/os/MacOSXDynamicLinkerImpl.java b/src/java/jogamp/common/os/MacOSXDynamicLinkerImpl.java
index 0fdfc8b..d724f9a 100644
--- a/src/java/jogamp/common/os/MacOSXDynamicLinkerImpl.java
+++ b/src/java/jogamp/common/os/MacOSXDynamicLinkerImpl.java
@@ -42,18 +42,18 @@ public final class MacOSXDynamicLinkerImpl extends UnixDynamicLinkerImpl {
   private static final int RTLD_GLOBAL   = 0x00008;
 
   @Override
-  public final long openLibraryLocal(final String pathname, final boolean debug) throws SecurityException {
-    return this.openLibraryImpl(pathname, RTLD_LAZY | RTLD_LOCAL, debug);
+  protected final long openLibraryLocalImpl(final String pathname) throws SecurityException {
+    return dlopen(pathname, RTLD_LAZY | RTLD_LOCAL);
   }
 
   @Override
-  public final long openLibraryGlobal(final String pathname, final boolean debug) throws SecurityException {
-    return this.openLibraryImpl(pathname, RTLD_LAZY | RTLD_GLOBAL, debug);
+  protected final long openLibraryGlobalImpl(final String pathname) throws SecurityException {
+    return dlopen(pathname, RTLD_LAZY | RTLD_GLOBAL);
   }
 
   @Override
-  public final long lookupSymbolGlobal(final String symbolName) throws SecurityException {
-    return this.lookupSymbolGlobalImpl(RTLD_DEFAULT, symbolName);
+  protected final long lookupSymbolGlobalImpl(final String symbolName) throws SecurityException {
+    return dlsym(RTLD_DEFAULT, symbolName);
   }
 
 }
diff --git a/src/java/jogamp/common/os/MachineDescriptionRuntime.java b/src/java/jogamp/common/os/MachineDataInfoRuntime.java
similarity index 55%
rename from src/java/jogamp/common/os/MachineDescriptionRuntime.java
rename to src/java/jogamp/common/os/MachineDataInfoRuntime.java
index e62c914..af90cc5 100644
--- a/src/java/jogamp/common/os/MachineDescriptionRuntime.java
+++ b/src/java/jogamp/common/os/MachineDataInfoRuntime.java
@@ -28,107 +28,98 @@
 
 package jogamp.common.os;
 
-import com.jogamp.common.os.MachineDescription;
+import com.jogamp.common.os.MachineDataInfo;
 import com.jogamp.common.os.Platform;
-import com.jogamp.common.os.MachineDescription.StaticConfig;
+import com.jogamp.common.os.MachineDataInfo.StaticConfig;
 
 /**
- * Runtime MachineDescription
+ * Runtime operations of {@link MachineDataInfo}.
  */
-public class MachineDescriptionRuntime {
-
-  static volatile boolean smdHardQueried = false;
-  static MachineDescription.StaticConfig smdHard = null;
-
-  static volatile boolean smdSoftQueried = false;
-  static MachineDescription.StaticConfig smdSoft = null;
-
-  static volatile boolean smdHardEnabled = false;
-
-  /* pp */ static void notifyPropsInitialized() { smdHardEnabled = true; }
-
-  public static MachineDescription.StaticConfig getStatic() {
-      if(!smdHardEnabled) {
-          if(!smdSoftQueried) {
-              synchronized(MachineDescription.class) { // volatile dbl-checked-locking OK
-                  if(!smdSoftQueried) {
-                      smdSoft = get(PlatformPropsImpl.OS_TYPE, PlatformPropsImpl.sCpuType, PlatformPropsImpl.LITTLE_ENDIAN);
-                      smdSoftQueried=true;
+public class MachineDataInfoRuntime {
+
+  static volatile boolean initialized = false;
+  static volatile MachineDataInfo runtimeMD = null;
+  static volatile MachineDataInfo.StaticConfig staticMD = null;
+
+  public static void initialize() {
+      if( !initialized ) {
+          synchronized(MachineDataInfo.class) { // volatile dbl-checked-locking OK
+              if( !initialized ) {
+                  MachineDataInfo.StaticConfig.validateUniqueMachineDataInfo();
+
+                  final MachineDataInfo runtimeMD = getRuntimeImpl();
+                  final MachineDataInfo.StaticConfig staticMD = MachineDataInfo.StaticConfig.findCompatible(runtimeMD);
+                  if( null == staticMD ) {
+                      throw new RuntimeException("No compatible MachineDataInfo.StaticConfig for runtime:"+PlatformPropsImpl.NEWLINE+runtimeMD);
                   }
+                  if( !staticMD.md.compatible(runtimeMD) ) {
+                      throw new RuntimeException("Incompatible MachineDataInfo:"+PlatformPropsImpl.NEWLINE+
+                                                 " Static "+staticMD+PlatformPropsImpl.NEWLINE+
+                                                 " Runtime "+runtimeMD);
+                  }
+                  MachineDataInfoRuntime.runtimeMD = runtimeMD;
+                  MachineDataInfoRuntime.staticMD = staticMD;
+                  initialized=true;
+                  if( PlatformPropsImpl.DEBUG ) {
+                      System.err.println("MachineDataInfoRuntime.initialize():"+PlatformPropsImpl.NEWLINE+
+                                         " Static "+staticMD+PlatformPropsImpl.NEWLINE+
+                                         " Runtime "+runtimeMD);
+                  }
+                  return;
               }
           }
-          return smdSoft;
-      } else {
-          if(!smdHardQueried) {
-              synchronized(MachineDescription.class) { // volatile dbl-checked-locking OK
-                  if(!smdHardQueried) {
-                      smdHard = get(PlatformPropsImpl.OS_TYPE, PlatformPropsImpl.CPU_ARCH, PlatformPropsImpl.LITTLE_ENDIAN);
-                      smdHardQueried=true;
-                  }
+      }
+      throw new InternalError("Already initialized");
+  }
+  public static MachineDataInfo.StaticConfig getStatic() {
+      if(!initialized) {
+          synchronized(MachineDataInfo.class) { // volatile dbl-checked-locking OK
+              if(!initialized) {
+                  throw new InternalError("Not set");
               }
           }
-          return smdHard;
       }
+      return staticMD;
   }
-
-  private static boolean isCPUArch32Bit(final Platform.CPUType cpuType) throws RuntimeException {
-    switch( cpuType ) {
-        case X86_32:
-        case ARM:
-        case ARMv5:
-        case ARMv6:
-        case ARMv7:
-        case SPARC_32:
-        case PPC:
-            return true;
-        case X86_64:
-        case IA64:
-        case SPARCV9_64:
-        case PA_RISC2_0:
-            return false;
-        default:
-            throw new RuntimeException("Please port CPU detection (32/64 bit) to your platform (" + PlatformPropsImpl.OS_lower + "/" + PlatformPropsImpl.ARCH_lower + "("+PlatformPropsImpl.CPU_ARCH+"))");
-    }
+  public static MachineDataInfo getRuntime() {
+      if(!initialized) {
+          synchronized(MachineDataInfo.class) { // volatile dbl-checked-locking OK
+              if(!initialized) {
+                  throw new InternalError("Not set");
+              }
+          }
+      }
+      return runtimeMD;
   }
 
-  private static MachineDescription.StaticConfig get(final Platform.OSType osType, final Platform.CPUType cpuType, final boolean littleEndian) {
-      if( isCPUArch32Bit(cpuType) ) {
-          if( cpuType.getFamily() == Platform.CPUFamily.ARM && littleEndian) {
-              return StaticConfig.ARMle_EABI;
-          } else if( osType == Platform.OSType.WINDOWS ) {
+  public static MachineDataInfo.StaticConfig guessStaticMachineDataInfo(final Platform.OSType osType, final Platform.CPUType cpuType) {
+      if( cpuType.is32Bit ) {
+          if( Platform.CPUFamily.ARM == cpuType.family ||
+              Platform.CPUType.MIPS_32 == cpuType ) {
+              return StaticConfig.ARM_MIPS_32;
+          } else if( Platform.OSType.WINDOWS == osType ) {
               return StaticConfig.X86_32_WINDOWS;
-          } else if( osType == Platform.OSType.MACOS ) {
+          } else if( Platform.OSType.MACOS == osType ) {
               return StaticConfig.X86_32_MACOS;
-          } else if ( osType == Platform.OSType.SUNOS ) {
-              if ( cpuType == Platform.CPUType.SPARC_32 ) {
-                  return StaticConfig.SPARC_32_SUNOS;
-              }
-              // TODO SPARCv9 description is missing
+          } else if ( Platform.OSType.SUNOS == osType &&
+                      Platform.CPUType.SPARC_32 == cpuType ) {
+              return StaticConfig.SPARC_32_SUNOS;
+          } else if ( Platform.CPUType.PPC == cpuType ) {
+              return StaticConfig.PPC_32_UNIX;
+          } else {
+              return StaticConfig.X86_32_UNIX;
           }
-          return StaticConfig.X86_32_UNIX;
       } else {
           if( osType == Platform.OSType.WINDOWS ) {
               return StaticConfig.X86_64_WINDOWS;
+          } else {
+              // for all 64bit unix types (x86_64, aarch64, sparcv9, ..)
+              return StaticConfig.LP64_UNIX;
           }
-          return StaticConfig.X86_64_UNIX;
       }
   }
 
-  static volatile boolean rmdQueried = false;
-  static MachineDescription rmd = null;
-
-  public static MachineDescription getRuntime() {
-        if(!rmdQueried) {
-            synchronized(MachineDescription.class) { // volatile dbl-checked-locking OK
-                if(!rmdQueried) {
-                    rmd = getRuntimeImpl();
-                    rmdQueried=true;
-                }
-            }
-        }
-        return rmd;
-  }
-  private static MachineDescription getRuntimeImpl() {
+  private static MachineDataInfo getRuntimeImpl() {
         try {
             Platform.initSingleton(); // loads native gluegen-rt library
         } catch (final UnsatisfiedLinkError err) {
@@ -151,8 +142,8 @@ public class MachineDescriptionRuntime {
 
         // size:      int, long, float, double, pointer, pageSize
         // alignment: int8, int16, int32, int64, int, long, float, double, pointer
-        return new MachineDescription(
-            true /* runtime validated */, PlatformPropsImpl.LITTLE_ENDIAN,
+        return new MachineDataInfo(
+            true /* runtime validated */,
 
             getSizeOfIntImpl(), getSizeOfLongImpl(),
             getSizeOfFloatImpl(), getSizeOfDoubleImpl(), getSizeOfLongDoubleImpl(),
diff --git a/src/java/jogamp/common/os/PlatformPropsImpl.java b/src/java/jogamp/common/os/PlatformPropsImpl.java
index d5ea012..0d0063c 100644
--- a/src/java/jogamp/common/os/PlatformPropsImpl.java
+++ b/src/java/jogamp/common/os/PlatformPropsImpl.java
@@ -11,9 +11,9 @@ import java.security.PrivilegedAction;
 import java.util.List;
 
 import jogamp.common.Debug;
-import jogamp.common.os.elf.ElfHeader;
+import jogamp.common.os.elf.ElfHeaderPart1;
+import jogamp.common.os.elf.ElfHeaderPart2;
 import jogamp.common.os.elf.SectionArmAttributes;
-import jogamp.common.os.elf.SectionHeader;
 
 import com.jogamp.common.nio.Buffers;
 import com.jogamp.common.os.AndroidVersion;
@@ -48,6 +48,13 @@ public abstract class PlatformPropsImpl {
         public static final VersionNumber Mavericks = new VersionNumber(10,9,0);
     }
 
+    /**
+     * Returns {@code true} if the given {@link CPUType}s and {@link ABIType}s are compatible.
+     */
+    public static final boolean isCompatible(final CPUType cpu1, final ABIType abi1, final CPUType cpu2, final ABIType abi2) {
+        return cpu1.isCompatible(cpu2) && abi1.isCompatible(abi2);
+    }
+
     //
     // static initialization order:
     //
@@ -72,14 +79,20 @@ public abstract class PlatformPropsImpl {
     public static final String JAVA_RUNTIME_NAME;
     /** True if having {@link java.nio.LongBuffer} and {@link java.nio.DoubleBuffer} available. */
     public static final boolean JAVA_SE;
-    /** True if being compatible w/ language level 6, e.g. JRE 1.6. Implies {@link #JAVA_SE}. <i>Note</i>: We claim Android is compatible. */
+    /**
+     * True only if being compatible w/ language level 6, e.g. JRE 1.6.
+     * <p>
+     * Implies {@link #isJavaSE()}.
+     * </p>
+     * <p>
+     * <i>Note</i>: We claim Android is compatible.
+     * </p>
+     */
     public static final boolean JAVA_6;
 
     public static final String NEWLINE;
     public static final boolean LITTLE_ENDIAN;
 
-    /* pp */ static final CPUType sCpuType;
-
     public static final CPUType CPU_ARCH;
     public static final ABIType ABI_TYPE;
     public static final OSType OS_TYPE;
@@ -126,107 +139,183 @@ public abstract class PlatformPropsImpl {
         OS_VERSION_NUMBER = new VersionNumber(OS_VERSION);
         OS_TYPE = getOSTypeImpl(OS_lower, isAndroid);
 
-        LITTLE_ENDIAN = queryIsLittleEndianImpl();
-
-        // Soft values, i.e. w/o probing binaries
-        final String sARCH = System.getProperty("os.arch");
-        final String sARCH_lower = sARCH.toLowerCase();
-        sCpuType = getCPUTypeImpl(sARCH_lower);
-        if( DEBUG ) {
-            System.err.println("Platform.Soft: str "+sARCH+", cpuType "+sCpuType);
-        }
-
         // Hard values, i.e. w/ probing binaries
-        //
-        // FIXME / HACK:
-        //   We use sCPUType for MachineDescriptionRuntime.getStatic()
-        //   until we have determined the final CPU_TYPE, etc.
-        //   MachineDescriptionRuntime gets notified via MachineDescriptionRuntime.notifyPropsInitialized() below.
-        //
-        //   We could use Elf Ehdr's machine value to determine the bit-size
-        //   used for it's offset table!
-        //   However, 'os.arch' should be a good guess for this task.
-        final CPUType ehCpuType;
-        final ABIType ehAbiType;
-        final boolean ehValid;
+        final String elfCpuName;
+        final CPUType elfCpuType;
+        final ABIType elfABIType;
+        final int elfLittleEndian;
+        final boolean elfValid;
         {
-            final CPUType[] _ehCpuType = { null };
-            final ABIType[] _ehAbiType = { null };
-            final ElfHeader eh = queryABITypeImpl(OS_TYPE, _ehCpuType, _ehAbiType);
-            if( null != eh && null != _ehCpuType[0] && null != _ehAbiType[0] ) {
-                ehCpuType = _ehCpuType[0];
-                ehAbiType = _ehAbiType[0];
-                if( isAndroid ) {
-                    if( DEBUG ) {
-                        System.err.println("Android: CPU_ABI1 str "+AndroidVersion.CPU_ABI+", cpu "+AndroidVersion.CPU_TYPE+", abi "+AndroidVersion.ABI_TYPE);
-                        System.err.println("Android: CPU_ABI2 str "+AndroidVersion.CPU_ABI2+", cpu "+AndroidVersion.CPU_TYPE2+", abi "+AndroidVersion.ABI_TYPE2);
-                    }
-                    final CPUFamily aCpuFamily1 = null != AndroidVersion.CPU_TYPE ? AndroidVersion.CPU_TYPE.family : null;
-                    final CPUFamily aCpuFamily2 = null != AndroidVersion.CPU_TYPE2 ? AndroidVersion.CPU_TYPE2.family : null;
-                    if( ehCpuType.family != aCpuFamily1 && ehCpuType.family != aCpuFamily2 ) {
-                        // Ooops !
-                        ehValid = false;
-                    } else {
-                        ehValid = true;
-                    }
-                } else {
-                    if( ehCpuType.family != sCpuType.family ) {
-                        // Ooops !
-                        ehValid = false;
-                    } else {
-                        ehValid = true;
+            final String[] _elfCpuName = { null };
+            final CPUType[] _elfCpuType = { null };
+            final ABIType[] _elfAbiType = { null };
+            final int[] _elfLittleEndian = { 0 }; // 1 - little, 2 - big
+            final boolean[] _elfValid = { false };
+            AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                @Override
+                public Object run() {
+                    RandomAccessFile in = null;
+                    try {
+                        final File file = queryElfFile(OS_TYPE);
+                        if(DEBUG) {
+                            System.err.println("ELF-1: Using "+file);
+                        }
+                        in = new RandomAccessFile(file, "r");
+                        final ElfHeaderPart1 eh1 = readElfHeaderPart1(OS_TYPE, in);
+                        if(DEBUG) {
+                            System.err.println("ELF-1: Got "+eh1);
+                        }
+                        if( null != eh1 ) {
+                            final ElfHeaderPart2 eh2 = readElfHeaderPart2(eh1, in);
+                            if(DEBUG) {
+                                System.err.println("ELF-2: Got "+eh2);
+                            }
+                            if( null != eh2 ) {
+                                _elfCpuName[0] = eh2.cpuName;
+                                _elfCpuType[0] = eh2.cpuType;
+                                _elfAbiType[0] = eh2.abiType;
+                                if( eh1.isLittleEndian() ) {
+                                    _elfLittleEndian[0] = 1;
+                                } else if( eh1.isBigEndian() ) {
+                                    _elfLittleEndian[0] = 2;
+                                }
+                                _elfValid[0] = true;
+                            }
+                        }
+                    } catch (final Throwable t) {
+                        if(DEBUG) {
+                            t.printStackTrace();
+                        }
+                    } finally {
+                        if(null != in) {
+                            try {
+                                in.close();
+                            } catch (final IOException e) { }
+                        }
                     }
-                }
-                if( DEBUG ) {
-                    System.err.println("Platform.Elf: cpuType "+ehCpuType+", abiType "+ehAbiType+", valid "+ehValid);
-                }
-            } else {
-                ehCpuType = null;
-                ehAbiType = null;
-                ehValid = false;
-                if( DEBUG ) {
-                    System.err.println("Platform.Elf: n/a");
-                }
+                    return null;
+                } });
+            elfCpuName = _elfCpuName[0];
+            elfCpuType = _elfCpuType[0];
+            elfABIType = _elfAbiType[0];
+            elfLittleEndian = _elfLittleEndian[0];
+            elfValid = _elfValid[0];
+            if( DEBUG ) {
+                System.err.println("Platform.Elf: valid "+elfValid+", elfCpuName "+elfCpuName+", cpuType "+elfCpuType+", abiType "+elfABIType+", elfLittleEndian "+elfLittleEndian);
+            }
+        }
+
+        // Determine endianess, favor ELF value
+        final boolean littleEndian = queryIsLittleEndianImpl();
+        if( elfValid ) {
+            switch( elfLittleEndian ) {
+                case 1:
+                    LITTLE_ENDIAN = true;
+                    break;
+                case 2:
+                    LITTLE_ENDIAN = false;
+                    break;
+                default:
+                    LITTLE_ENDIAN = littleEndian;
+                    break;
             }
+        } else {
+            LITTLE_ENDIAN = littleEndian;
+        }
+        if( DEBUG ) {
+            System.err.println("Platform.Endian: test-little "+littleEndian+", elf[valid "+elfValid+", val "+elfLittleEndian+"] -> LITTLE_ENDIAN "+LITTLE_ENDIAN);
         }
+
+        // Property values for comparison
+        // We might take the property values even if ELF values are available,
+        // since the latter only reflect the CPU/ABI version of the binary files!
+        final String propARCH = System.getProperty("os.arch");
+        final String propARCH_lower = propARCH.toLowerCase();
+        final CPUType propCpuType = CPUType.query(propARCH_lower);
+        final ABIType propABIType = ABIType.query(propCpuType, propARCH_lower);
+        if( DEBUG ) {
+            System.err.println("Platform.Property: ARCH "+propARCH+", CpuType "+propCpuType+", ABIType "+propABIType);
+        }
+
+        final int strategy;
         if( isAndroid ) {
-            if( ehValid ) {
-                if( ehCpuType.family == AndroidVersion.CPU_TYPE.family ) {
+            if( DEBUG ) {
+                System.err.println("Android: CPU_ABI1 str "+AndroidVersion.CPU_ABI+", CPU_TYPE "+AndroidVersion.CPU_TYPE+", ABI_TYPE "+AndroidVersion.ABI_TYPE);
+                System.err.println("Android: CPU_ABI2 str "+AndroidVersion.CPU_ABI2+", CPU_TYPE2 "+AndroidVersion.CPU_TYPE2+", ABI_TYPE2 "+AndroidVersion.ABI_TYPE2);
+            }
+            if( elfValid ) {
+                if( null != AndroidVersion.CPU_TYPE &&
+                    isCompatible(elfCpuType, elfABIType, AndroidVersion.CPU_TYPE, AndroidVersion.ABI_TYPE) )
+                {
+                    // ELF matches Android-1
                     ARCH = AndroidVersion.CPU_ABI;
+                    ARCH_lower = ARCH;
                     CPU_ARCH = AndroidVersion.CPU_TYPE;
-                } else {
+                    strategy = 110;
+                } else if( null != AndroidVersion.CPU_TYPE2 &&
+                           isCompatible(elfCpuType, elfABIType, AndroidVersion.CPU_TYPE2, AndroidVersion.ABI_TYPE2) )
+                {
+                    // ELF matches Android-2
                     ARCH = AndroidVersion.CPU_ABI2;
+                    ARCH_lower = ARCH;
                     CPU_ARCH = AndroidVersion.CPU_TYPE2;
+                    strategy = 111;
+                } else {
+                    // We assume our ELF data beats AndroidVersion info (correctness)
+                    ARCH = elfCpuType.toString();
+                    ARCH_lower = ARCH.toLowerCase();
+                    CPU_ARCH = elfCpuType;
+                    strategy = 112;
                 }
-                ABI_TYPE = ehAbiType;
+                ABI_TYPE = elfABIType;
             } else {
-                // default
-                if( AndroidVersion.CPU_TYPE.family == CPUFamily.ARM || null == AndroidVersion.CPU_TYPE2 ) {
+                if( AndroidVersion.CPU_TYPE.family == CPUFamily.ARM ||
+                    null == AndroidVersion.CPU_TYPE2 ) {
+                    // Favor Android-1: Either b/c ARM Family, or no Android-2
                     ARCH = AndroidVersion.CPU_ABI;
+                    ARCH_lower = ARCH;
                     CPU_ARCH = AndroidVersion.CPU_TYPE;
                     ABI_TYPE = AndroidVersion.ABI_TYPE;
+                    strategy = 120;
                 } else {
+                    // Last resort Android-2
                     ARCH = AndroidVersion.CPU_ABI2;
+                    ARCH_lower = ARCH;
                     CPU_ARCH = AndroidVersion.CPU_TYPE2;
                     ABI_TYPE = AndroidVersion.ABI_TYPE2;
+                    strategy = 121;
                 }
             }
-            ARCH_lower  = ARCH;
         } else {
-            ARCH = sARCH;
-            ARCH_lower = sARCH_lower;
-            if( ehValid && CPUFamily.ARM == ehCpuType.family ) {
-                // Use Elf for ARM
-                CPU_ARCH = ehCpuType;
-                ABI_TYPE = ehAbiType;
+            if( elfValid ) {
+                if( isCompatible(elfCpuType, elfABIType, propCpuType, propABIType) ) {
+                    // Use property ARCH, compatible w/ ELF
+                    ARCH = propARCH;
+                    ARCH_lower = propARCH_lower;
+                    CPU_ARCH = propCpuType;
+                    ABI_TYPE = propABIType;
+                    strategy = 210;
+                } else {
+                    // use ELF ARCH
+                    ARCH = elfCpuName;
+                    ARCH_lower = elfCpuName;
+                    CPU_ARCH = elfCpuType;
+                    ABI_TYPE = elfABIType;
+                    strategy = 211;
+                }
             } else {
-                // Otherwise trust detailed os.arch (?)
-                CPU_ARCH = sCpuType;
-                ABI_TYPE = ABIType.GENERIC_ABI;
+                // Last resort: properties
+                ARCH = propARCH;
+                ARCH_lower = propARCH_lower;
+                CPU_ARCH = propCpuType;
+                ABI_TYPE = propABIType;
+                strategy = 220;
             }
         }
-        MachineDescriptionRuntime.notifyPropsInitialized();
-        os_and_arch = getOSAndArch(OS_TYPE, CPU_ARCH, ABI_TYPE);
+        if( DEBUG ) {
+            System.err.println("Platform.Hard: ARCH "+ARCH+", CPU_ARCH "+CPU_ARCH+", ABI_TYPE "+ABI_TYPE+" - strategy "+strategy+"(isAndroid "+isAndroid+", elfValid "+elfValid+")");
+        }
+        os_and_arch = getOSAndArch(OS_TYPE, CPU_ARCH, ABI_TYPE, LITTLE_ENDIAN);
     }
 
     protected PlatformPropsImpl() {}
@@ -266,43 +355,6 @@ public abstract class PlatformPropsImpl {
         return 0x0C0D == tst_s.get(0);
     }
 
-    private static final CPUType getCPUTypeImpl(final String archLower) {
-        if(        archLower.equals("x86")  ||         // jvm + android
-                   archLower.equals("i386") ||
-                   archLower.equals("i486") ||
-                   archLower.equals("i586") ||
-                   archLower.equals("i686") ) {
-            return CPUType.X86_32;
-        } else if( archLower.equals("x86_64") ||
-                   archLower.equals("amd64")  ) {
-            return CPUType.X86_64;
-        } else if( archLower.equals("ia64") ) {
-            return CPUType.IA64;
-        } else if( archLower.equals("arm") ) {
-            return CPUType.ARM;
-        } else if( archLower.equals("armv5l") ) {
-            return CPUType.ARMv5;
-        } else if( archLower.equals("armv6l") ) {
-            return CPUType.ARMv6;
-        } else if( archLower.equals("armv7l") ||
-                   archLower.equals("armeabi") ||      // android
-                   archLower.equals("armeabi-v7a") ) { // android
-            return CPUType.ARMv7;
-        } else if( archLower.equals("sparc") ) {
-            return CPUType.SPARC_32;
-        } else if( archLower.equals("sparcv9") ) {
-            return CPUType.SPARCV9_64;
-        } else if( archLower.equals("pa_risc2.0") ) {
-            return CPUType.PA_RISC2_0;
-        } else if( archLower.equals("ppc") ) {
-            return CPUType.PPC;
-        } else if( archLower.equals("mips") ) {        // android
-            return CPUType.MIPS_32;
-        } else {
-            throw new RuntimeException("Please port CPU detection to your platform (" + OS_lower + "/" + archLower + ")");
-        }
-    }
-
     @SuppressWarnings("unused")
     private static final boolean contains(final String data, final String[] search) {
         if(null != data && null != search) {
@@ -330,98 +382,53 @@ public abstract class PlatformPropsImpl {
      * Elf ARM Tags are read using {@link ElfHeader}, .. and {@link SectionArmAttributes#abiVFPArgsAcceptsVFPVariant(byte)}.
      * </p>
      */
-    private static final ElfHeader queryABITypeImpl(final OSType osType, final CPUType[] cpuType, final ABIType[] abiType) {
-        return AccessController.doPrivileged(new PrivilegedAction<ElfHeader>() {
-            @Override
-            public ElfHeader run() {
-                ElfHeader res = null;
-                try {
-                    File file = null;
-                    if( OSType.ANDROID == osType ) {
-                        file = new File(NativeLibrary.findLibrary("gluegen-rt", PlatformPropsImpl.class.getClassLoader()));
-                    } else {
-                        if( OSType.LINUX == osType ) {
-                            file = new File("/proc/self/exe");
-                            if( !checkFileReadAccess(file) ) {
-                                file = null;
-                            }
-                        }
-                        if( null == file ) {
-                            file = findSysLib("java");
-                        }
-                        if( null == file ) {
-                            file = findSysLib("jvm");
-                        }
-                    }
-                    if( null != file ) {
-                        res = queryABITypeImpl(file, cpuType, abiType);
-                    }
-                } catch(final Throwable t) {
-                    if(DEBUG) {
-                        t.printStackTrace();
-                    }
-                }
-                return res;
-            } } );
-    }
-    private static final ElfHeader queryABITypeImpl(final File file, final CPUType[] cpuType, final ABIType[] abiType) {
-        ElfHeader res = null;
-        RandomAccessFile in = null;
+    private static final File queryElfFile(final OSType osType) {
+        File file = null;
         try {
-            in = new RandomAccessFile(file, "r");
-            final ElfHeader eh = ElfHeader.read(in);
-            if(DEBUG) {
-                System.err.println("ELF: Got HDR "+file+": "+eh);
-            }
-            if( eh.isArm() ) {
-                boolean abiVFPArgsAcceptsVFPVariant = false;
-                final SectionHeader sh = eh.getSectionHeader(SectionHeader.SHT_ARM_ATTRIBUTES);
-                if( null != sh ) {
-                    if(DEBUG) {
-                        System.err.println("ELF: Got ARM Attribs Section Header: "+sh);
-                    }
-                    final SectionArmAttributes sArmAttrs = (SectionArmAttributes) sh.readSection(in);
-                    if(DEBUG) {
-                        System.err.println("ELF: Got ARM Attribs Section Block : "+sArmAttrs);
-                    }
-                    final SectionArmAttributes.Attribute abiVFPArgsAttr = sArmAttrs.get(SectionArmAttributes.Tag.ABI_VFP_args);
-                    if( null != abiVFPArgsAttr ) {
-                        abiVFPArgsAcceptsVFPVariant = SectionArmAttributes.abiVFPArgsAcceptsVFPVariant(abiVFPArgsAttr.getULEB128());
+            if( OSType.ANDROID == osType ) {
+                file = new File(NativeLibrary.findLibrary("gluegen-rt", PlatformPropsImpl.class.getClassLoader()));
+            } else {
+                if( OSType.LINUX == osType ) {
+                    file = new File("/proc/self/exe");
+                    if( !checkFileReadAccess(file) ) {
+                        file = null;
                     }
                 }
-                cpuType[0] = CPUType.ARM; // lowest denominator, ok for us
-                abiType[0] = abiVFPArgsAcceptsVFPVariant ? ABIType.EABI_GNU_ARMHF : ABIType.EABI_GNU_ARMEL;
-                if(DEBUG) {
-                    System.err.println("ELF: abiARM, abiVFPArgsAcceptsVFPVariant "+abiVFPArgsAcceptsVFPVariant);
+                if( null == file ) {
+                    file = findSysLib("java");
+                }
+                if( null == file ) {
+                    file = findSysLib("jvm");
                 }
-            } else if ( eh.isX86_64() ) {
-                cpuType[0] = CPUType.X86_64;
-                abiType[0] = ABIType.GENERIC_ABI;
-            } else if ( eh.isX86_32() ) {
-                cpuType[0] = CPUType.X86_32;
-                abiType[0] = ABIType.GENERIC_ABI;
-            } else if ( eh.isIA64() ) {
-                cpuType[0] = CPUType.IA64;
-                abiType[0] = ABIType.GENERIC_ABI;
-            } else if ( eh.isMips() ) {
-                cpuType[0] = CPUType.MIPS_32; // FIXME
-                abiType[0] = ABIType.GENERIC_ABI;
             }
-            res = eh;
         } catch(final Throwable t) {
             if(DEBUG) {
-                System.err.println("Caught: "+t.getMessage());
                 t.printStackTrace();
             }
-        } finally {
-            if(null != in) {
-                try {
-                    in.close();
-                } catch (final IOException e) { }
+        }
+        return file;
+    }
+    private static final ElfHeaderPart1 readElfHeaderPart1(final OSType osType, final RandomAccessFile in) {
+        ElfHeaderPart1 res = null;
+        try {
+            res = ElfHeaderPart1.read(osType, in);
+        } catch(final Throwable t) {
+            if(DEBUG) {
+                System.err.println("Caught: "+t.getMessage());
+                t.printStackTrace();
             }
         }
-        if(DEBUG) {
-            System.err.println("ELF: res "+res+", cpuType "+cpuType[0]+", abiType "+abiType[0]);
+        return res;
+    }
+    private static final ElfHeaderPart2 readElfHeaderPart2(final ElfHeaderPart1 eh1, final RandomAccessFile in) {
+        ElfHeaderPart2 res = null;
+        try {
+            res = ElfHeaderPart2.read(eh1, in);
+        } catch(final Throwable t) {
+            if(DEBUG) {
+                System.err.println("Caught: "+t.getMessage());
+                t.printStackTrace();
+            }
         }
         return res;
     }
@@ -488,20 +495,34 @@ public abstract class PlatformPropsImpl {
     public static void initSingleton() { }
 
     /**
-     * Returns the GlueGen common name for the given OSType and CPUType
-     * as implemented in the build system in 'gluegen-cpptasks-base.xml'.<br>
+     * Returns the GlueGen common name for the given
+     * {@link OSType}, {@link CPUType}, {@link ABIType} and {@code littleEndian}.
+     * <p>
+     * Consult 'gluegen/make/gluegen-cpptasks-base.xml' to complete/sync mapping!
+     * </p>
      *
-     * A list of currently supported <code>os.and.arch</code> strings:
+     * An excerpt of supported <code>os.and.arch</code> strings:
      * <ul>
+     *   <li>android-armv6</li>
+     *   <li>android-aarch64</li>
+     *   <li>linux-armv6</li>
+     *   <li>linux-armv6hf</li>
+     *   <li>linux-i586</li>
+     *   <li>linux-ppc</li>
+     *   <li>linux-mips</li>
+     *   <li>linux-mipsel</li>
+     *   <li>linux-superh</li>
+     *   <li>linux-sparc</li>
+     *   <li>linux-aarch64</li>
+     *   <li>linux-amd64</li>
+     *   <li>linux-ppc64</li>
+     *   <li>linux-mips64</li>
+     *   <li>linux-ia64</li>
+     *   <li>linux-sparcv9</li>
+     *   <li>linux-risc2.0</li>
      *   <li>freebsd-i586</li>
      *   <li>freebsd-amd64</li>
      *   <li>hpux-hppa</li>
-     *   <li>linux-amd64</li>
-     *   <li>linux-ia64</li>
-     *   <li>linux-i586</li>
-     *   <li>linux-armv6</li>
-     *   <li>linux-armv6hf</li>
-     *   <li>android-armv6</li>
      *   <li>macosx-universal</li>
      *   <li>solaris-sparc</li>
      *   <li>solaris-sparcv9</li>
@@ -512,33 +533,50 @@ public abstract class PlatformPropsImpl {
      * </ul>
      * @return The <i>os.and.arch</i> value.
      */
-    public static final String getOSAndArch(final OSType osType, final CPUType cpuType, final ABIType abiType) {
+    public static final String getOSAndArch(final OSType osType, final CPUType cpuType, final ABIType abiType, final boolean littleEndian) {
         final String os_;
         final String _and_arch_tmp, _and_arch_final;
 
         switch( cpuType ) {
-            case X86_32:
-                _and_arch_tmp = "i586";
-                break;
             case ARM:
             case ARMv5:
             case ARMv6:
             case ARMv7:
                 if( ABIType.EABI_GNU_ARMHF == abiType ) {
-                    _and_arch_tmp = "armv6hf" ; // TODO: sync with gluegen-cpptasks-base.xml
+                    _and_arch_tmp = "armv6hf";
                 } else {
-                    _and_arch_tmp = "armv6";    // TODO: sync with gluegen-cpptasks-base.xml
+                    _and_arch_tmp = "armv6";
                 }
                 break;
+            case X86_32:
+                _and_arch_tmp = "i586";
+                break;
+            case PPC:
+                _and_arch_tmp = "ppc";
+                break;
+            case MIPS_32:
+                _and_arch_tmp = littleEndian ? "mipsel" : "mips";
+                break;
+            case SuperH:
+                _and_arch_tmp = "superh";
+                break;
             case SPARC_32:
                 _and_arch_tmp = "sparc";
                 break;
-            case PPC:
-                _and_arch_tmp = "ppc";          // TODO: sync with gluegen-cpptasks-base.xml
+
+            case ARM64:
+            case ARMv8_A:
+                _and_arch_tmp = "aarch64";
                 break;
             case X86_64:
                 _and_arch_tmp = "amd64";
                 break;
+            case PPC64:
+                _and_arch_tmp = "ppc64";
+                break;
+            case MIPS_64:
+                _and_arch_tmp = "mips64";
+                break;
             case IA64:
                 _and_arch_tmp = "ia64";
                 break;
@@ -546,10 +584,10 @@ public abstract class PlatformPropsImpl {
                 _and_arch_tmp = "sparcv9";
                 break;
             case PA_RISC2_0:
-                _and_arch_tmp = "risc2.0";      // TODO: sync with gluegen-cpptasks-base.xml
+                _and_arch_tmp = "risc2.0";
                 break;
             default:
-                throw new InternalError("Complete case block");
+                throw new InternalError("Unhandled CPUType: "+cpuType);
         }
 
         switch( osType ) {
@@ -586,7 +624,7 @@ public abstract class PlatformPropsImpl {
               _and_arch_final = "hppa";     // TODO: really only hppa ?
               break;
             default:
-              throw new InternalError("Complete case block");
+              throw new InternalError("Unhandled OSType: "+osType);
         }
         return os_ + "-" + _and_arch_final;
     }
diff --git a/src/java/jogamp/common/os/PosixDynamicLinkerImpl.java b/src/java/jogamp/common/os/PosixDynamicLinkerImpl.java
index f929e03..a022f01 100644
--- a/src/java/jogamp/common/os/PosixDynamicLinkerImpl.java
+++ b/src/java/jogamp/common/os/PosixDynamicLinkerImpl.java
@@ -38,17 +38,17 @@ public final class PosixDynamicLinkerImpl extends UnixDynamicLinkerImpl {
   private static final int RTLD_GLOBAL   = 0x00100;
 
   @Override
-  public final long openLibraryLocal(final String pathname, final boolean debug) throws SecurityException {
-    return this.openLibraryImpl(pathname, RTLD_LAZY | RTLD_LOCAL, debug);
+  protected final long openLibraryLocalImpl(final String pathname) throws SecurityException {
+    return dlopen(pathname, RTLD_LAZY | RTLD_LOCAL);
   }
 
   @Override
-  public final long openLibraryGlobal(final String pathname, final boolean debug) throws SecurityException {
-    return this.openLibraryImpl(pathname, RTLD_LAZY | RTLD_GLOBAL, debug);
+  protected final long openLibraryGlobalImpl(final String pathname) throws SecurityException {
+    return dlopen(pathname, RTLD_LAZY | RTLD_GLOBAL);
   }
 
   @Override
-  public final long lookupSymbolGlobal(final String symbolName) throws SecurityException {
-    return this.lookupSymbolGlobalImpl(RTLD_DEFAULT, symbolName);
+  protected final long lookupSymbolGlobalImpl(final String symbolName) throws SecurityException {
+    return dlsym(RTLD_DEFAULT, symbolName);
   }
 }
diff --git a/src/java/jogamp/common/os/UnixDynamicLinkerImpl.java b/src/java/jogamp/common/os/UnixDynamicLinkerImpl.java
index 59be76c..5e8ba9d 100644
--- a/src/java/jogamp/common/os/UnixDynamicLinkerImpl.java
+++ b/src/java/jogamp/common/os/UnixDynamicLinkerImpl.java
@@ -27,8 +27,6 @@
  */
 package jogamp.common.os;
 
-import com.jogamp.common.util.SecurityUtil;
-
 /* pp */ abstract class UnixDynamicLinkerImpl extends DynamicLinkerImpl {
 
   //
@@ -49,46 +47,17 @@ import com.jogamp.common.util.SecurityUtil;
   /** Interface to C language function: <br> <code> void *  dlsym(void * , const char * ); </code>    */
   protected static native long dlsym(long arg0, java.lang.String arg1);
 
-  protected final long openLibraryImpl(final String pathname, final int dlSymFlags, final boolean debug) throws SecurityException {
-    SecurityUtil.checkLinkPermission(pathname);
-    final long handle = dlopen(pathname, dlSymFlags);
-    if( 0 != handle ) {
-        incrLibRefCount(handle, pathname);
-    } else if ( DEBUG || debug ) {
-        System.err.println("dlopen \""+pathname+"\" failed, error: "+dlerror());
-    }
-    return handle;
-  }
-
-  protected final long lookupSymbolGlobalImpl(final long dlSymGlobalFlag, final String symbolName) throws SecurityException {
-    SecurityUtil.checkAllLinkPermission();
-    final long addr = dlsym(dlSymGlobalFlag, symbolName);
-    if(DEBUG_LOOKUP) {
-        System.err.println("DynamicLinkerImpl.lookupSymbolGlobal("+symbolName+") -> 0x"+Long.toHexString(addr));
-    }
-    return addr;
-  }
-
   @Override
-  public final long lookupSymbol(final long libraryHandle, final String symbolName) throws IllegalArgumentException {
-    if( null == getLibRef( libraryHandle ) ) {
-        throw new IllegalArgumentException("Library handle 0x"+Long.toHexString(libraryHandle)+" unknown.");
-    }
-    final long addr = dlsym(libraryHandle, symbolName);
-    if(DEBUG_LOOKUP) {
-        System.err.println("DynamicLinkerImpl.lookupSymbol(0x"+Long.toHexString(libraryHandle)+", "+symbolName+") -> 0x"+Long.toHexString(addr));
-    }
-    return addr;
+  protected final long lookupSymbolLocalImpl(final long libraryHandle, final String symbolName) throws SecurityException {
+      return dlsym(libraryHandle, symbolName);
   }
 
   @Override
-  public final void closeLibrary(final long libraryHandle) throws IllegalArgumentException {
-    if( null == decrLibRefCount( libraryHandle ) ) {
-        throw new IllegalArgumentException("Library handle 0x"+Long.toHexString(libraryHandle)+" unknown.");
-    }
-    dlclose(libraryHandle);
+  protected final void closeLibraryImpl(final long libraryHandle) throws SecurityException {
+      dlclose(libraryHandle);
   }
 
+
   @Override
   public final String getLastError() {
       return dlerror();
diff --git a/src/java/jogamp/common/os/WindowsDynamicLinkerImpl.java b/src/java/jogamp/common/os/WindowsDynamicLinkerImpl.java
index de69d0c..04f13fb 100644
--- a/src/java/jogamp/common/os/WindowsDynamicLinkerImpl.java
+++ b/src/java/jogamp/common/os/WindowsDynamicLinkerImpl.java
@@ -27,8 +27,6 @@
  */
 package jogamp.common.os;
 
-import com.jogamp.common.util.SecurityUtil;
-
 public final class WindowsDynamicLinkerImpl extends DynamicLinkerImpl {
 
   /** Interface to C language function: <br> <code> BOOL FreeLibrary(HANDLE hLibModule); </code>    */
@@ -44,28 +42,19 @@ public final class WindowsDynamicLinkerImpl extends DynamicLinkerImpl {
   private static native long LoadLibraryW(java.lang.String lpLibFileName);
 
   @Override
-  public final long openLibraryLocal(final String libraryName, final boolean debug) throws SecurityException {
+  protected final long openLibraryLocalImpl(final String libraryName) throws SecurityException {
     // How does that work under Windows ?
-    // Don't know .. so it's an alias for the time being
-    return openLibraryGlobal(libraryName, debug);
+    // Don't know .. so it's an alias to global, for the time being
+    return LoadLibraryW(libraryName);
   }
 
   @Override
-  public final long openLibraryGlobal(final String libraryName, final boolean debug) throws SecurityException {
-    SecurityUtil.checkLinkPermission(libraryName);
-    final long handle = LoadLibraryW(libraryName);
-    if( 0 != handle ) {
-        incrLibRefCount(handle, libraryName);
-    } else if ( DEBUG || debug ) {
-        final int err = GetLastError();
-        System.err.println("LoadLibraryW \""+libraryName+"\" failed, error code: 0x"+Integer.toHexString(err)+", "+err);
-    }
-    return handle;
+  protected final long openLibraryGlobalImpl(final String libraryName) throws SecurityException {
+    return LoadLibraryW(libraryName);
   }
 
   @Override
-  public final long lookupSymbolGlobal(final String symbolName) throws SecurityException {
-    SecurityUtil.checkAllLinkPermission();
+  protected final long lookupSymbolGlobalImpl(final String symbolName) throws SecurityException {
     if(DEBUG_LOOKUP) {
         System.err.println("lookupSymbolGlobal: Not supported on Windows");
     }
@@ -73,34 +62,26 @@ public final class WindowsDynamicLinkerImpl extends DynamicLinkerImpl {
     return 0;
   }
 
+  private static final int symbolArgAlignment=4;  // 4 byte alignment of each argument
+  private static final int symbolMaxArguments=12; // experience ..
+
   @Override
-  public final long lookupSymbol(final long libraryHandle, final String symbolName) throws IllegalArgumentException {
-    if( null == getLibRef( libraryHandle ) ) {
-        throw new IllegalArgumentException("Library handle 0x"+Long.toHexString(libraryHandle)+" unknown.");
-    }
+  protected final long lookupSymbolLocalImpl(final long libraryHandle, final String symbolName) throws IllegalArgumentException {
     String _symbolName = symbolName;
     long addr = GetProcAddressA(libraryHandle, _symbolName);
-    if(0==addr) {
+    if( 0 == addr ) {
         // __stdcall hack: try some @nn decorations,
         //                 the leading '_' must not be added (same with cdecl)
-        final int argAlignment=4;  // 4 byte alignment of each argument
-        final int maxArguments=12; // experience ..
-        for(int arg=0; 0==addr && arg<=maxArguments; arg++) {
-            _symbolName = symbolName+"@"+(arg*argAlignment);
+        for(int arg=0; 0==addr && arg<=symbolMaxArguments; arg++) {
+            _symbolName = symbolName+"@"+(arg*symbolArgAlignment);
             addr = GetProcAddressA(libraryHandle, _symbolName);
         }
     }
-    if(DEBUG_LOOKUP) {
-        System.err.println("DynamicLinkerImpl.lookupSymbol(0x"+Long.toHexString(libraryHandle)+", "+symbolName+") -> "+_symbolName+", 0x"+Long.toHexString(addr));
-    }
     return addr;
   }
 
   @Override
-  public final void closeLibrary(final long libraryHandle) throws IllegalArgumentException {
-    if( null == decrLibRefCount( libraryHandle ) ) {
-        throw new IllegalArgumentException("Library handle 0x"+Long.toHexString(libraryHandle)+" unknown.");
-    }
+  protected final void closeLibraryImpl(final long libraryHandle) throws IllegalArgumentException {
     FreeLibrary(libraryHandle);
   }
 
diff --git a/src/java/jogamp/common/os/elf/Ehdr.java b/src/java/jogamp/common/os/elf/Ehdr.java
deleted file mode 100644
index e12ef4f..0000000
--- a/src/java/jogamp/common/os/elf/Ehdr.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/* !---- DO NOT EDIT: This file autogenerated by com/jogamp/gluegen/JavaEmitter.java on Thu Feb 07 17:54:18 CET 2013 ----! */
-
-
-package jogamp.common.os.elf;
-
-import com.jogamp.common.nio.*;
-import jogamp.common.os.MachineDescriptionRuntime;
-
-
-public class Ehdr {
-
-  StructAccessor accessor;
-
-  private static final int mdIdx = MachineDescriptionRuntime.getStatic().ordinal();
-
-  private static final int[] Ehdr_size = new int[] { 52 /* ARMle_EABI */, 52 /* X86_32_UNIX */, 64 /* X86_64_UNIX */, 52 /* X86_32_MACOS */, 52 /* X86_32_WINDOWS */, 64 /* X86_64_WINDOWS */  };
-  private static final int[] e_ident_offset = new int[] { 0 /* ARMle_EABI */, 0 /* X86_32_UNIX */, 0 /* X86_64_UNIX */, 0 /* X86_32_MACOS */, 0 /* X86_32_WINDOWS */, 0 /* X86_64_WINDOWS */ };
-  private static final int[] e_type_offset = new int[] { 16 /* ARMle_EABI */, 16 /* X86_32_UNIX */, 16 /* X86_64_UNIX */, 16 /* X86_32_MACOS */, 16 /* X86_32_WINDOWS */, 16 /* X86_64_WINDOWS */ };
-  private static final int[] e_machine_offset = new int[] { 18 /* ARMle_EABI */, 18 /* X86_32_UNIX */, 18 /* X86_64_UNIX */, 18 /* X86_32_MACOS */, 18 /* X86_32_WINDOWS */, 18 /* X86_64_WINDOWS */ };
-  private static final int[] e_version_offset = new int[] { 20 /* ARMle_EABI */, 20 /* X86_32_UNIX */, 20 /* X86_64_UNIX */, 20 /* X86_32_MACOS */, 20 /* X86_32_WINDOWS */, 20 /* X86_64_WINDOWS */ };
-  private static final int[] e_entry_offset = new int[] { 24 /* ARMle_EABI */, 24 /* X86_32_UNIX */, 24 /* X86_64_UNIX */, 24 /* X86_32_MACOS */, 24 /* X86_32_WINDOWS */, 24 /* X86_64_WINDOWS */ };
-  private static final int[] e_phoff_offset = new int[] { 28 /* ARMle_EABI */, 28 /* X86_32_UNIX */, 32 /* X86_64_UNIX */, 28 /* X86_32_MACOS */, 28 /* X86_32_WINDOWS */, 32 /* X86_64_WINDOWS */ };
-  private static final int[] e_shoff_offset = new int[] { 32 /* ARMle_EABI */, 32 /* X86_32_UNIX */, 40 /* X86_64_UNIX */, 32 /* X86_32_MACOS */, 32 /* X86_32_WINDOWS */, 40 /* X86_64_WINDOWS */ };
-  private static final int[] e_flags_offset = new int[] { 36 /* ARMle_EABI */, 36 /* X86_32_UNIX */, 48 /* X86_64_UNIX */, 36 /* X86_32_MACOS */, 36 /* X86_32_WINDOWS */, 48 /* X86_64_WINDOWS */ };
-  private static final int[] e_ehsize_offset = new int[] { 40 /* ARMle_EABI */, 40 /* X86_32_UNIX */, 52 /* X86_64_UNIX */, 40 /* X86_32_MACOS */, 40 /* X86_32_WINDOWS */, 52 /* X86_64_WINDOWS */ };
-  private static final int[] e_phentsize_offset = new int[] { 42 /* ARMle_EABI */, 42 /* X86_32_UNIX */, 54 /* X86_64_UNIX */, 42 /* X86_32_MACOS */, 42 /* X86_32_WINDOWS */, 54 /* X86_64_WINDOWS */ };
-  private static final int[] e_phnum_offset = new int[] { 44 /* ARMle_EABI */, 44 /* X86_32_UNIX */, 56 /* X86_64_UNIX */, 44 /* X86_32_MACOS */, 44 /* X86_32_WINDOWS */, 56 /* X86_64_WINDOWS */ };
-  private static final int[] e_shentsize_offset = new int[] { 46 /* ARMle_EABI */, 46 /* X86_32_UNIX */, 58 /* X86_64_UNIX */, 46 /* X86_32_MACOS */, 46 /* X86_32_WINDOWS */, 58 /* X86_64_WINDOWS */ };
-  private static final int[] e_shnum_offset = new int[] { 48 /* ARMle_EABI */, 48 /* X86_32_UNIX */, 60 /* X86_64_UNIX */, 48 /* X86_32_MACOS */, 48 /* X86_32_WINDOWS */, 60 /* X86_64_WINDOWS */ };
-  private static final int[] e_shstrndx_offset = new int[] { 50 /* ARMle_EABI */, 50 /* X86_32_UNIX */, 62 /* X86_64_UNIX */, 50 /* X86_32_MACOS */, 50 /* X86_32_WINDOWS */, 62 /* X86_64_WINDOWS */ };
-
-  public static int size() {
-    return Ehdr_size[mdIdx];
-  }
-
-  public static Ehdr create() {
-    return create(Buffers.newDirectByteBuffer(size()));
-  }
-
-  public static Ehdr create(final java.nio.ByteBuffer buf) {
-      return new Ehdr(buf);
-  }
-
-  Ehdr(final java.nio.ByteBuffer buf) {
-    accessor = new StructAccessor(buf);
-  }
-
-  public java.nio.ByteBuffer getBuffer() {
-    return accessor.getBuffer();
-  }
-
-  public Ehdr setE_ident(final byte[] val) {
-    accessor.setBytesAt(e_ident_offset[mdIdx], val);    return this;
-  }
-
-  public byte[] getE_ident() {
-    return accessor.getBytesAt(e_ident_offset[mdIdx], new byte[16]); }
-
-  public Ehdr setE_type(final short val) {
-    accessor.setShortAt(e_type_offset[mdIdx], val);
-    return this;
-  }
-
-  public short getE_type() {
-    return accessor.getShortAt(e_type_offset[mdIdx]);
-  }
-
-  public Ehdr setE_machine(final short val) {
-    accessor.setShortAt(e_machine_offset[mdIdx], val);
-    return this;
-  }
-
-  public short getE_machine() {
-    return accessor.getShortAt(e_machine_offset[mdIdx]);
-  }
-
-  public Ehdr setE_version(final int val) {
-    accessor.setIntAt(e_version_offset[mdIdx], val);
-    return this;
-  }
-
-  public int getE_version() {
-    return accessor.getIntAt(e_version_offset[mdIdx]);
-  }
-
-  public Ehdr setE_entry(final long val) {
-    accessor.setLongAt(e_entry_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md.longSizeInBytes());
-    return this;
-  }
-
-  public long getE_entry() {
-    return accessor.getLongAt(e_entry_offset[mdIdx], MachineDescriptionRuntime.getStatic().md.longSizeInBytes());
-  }
-
-  public Ehdr setE_phoff(final long val) {
-    accessor.setLongAt(e_phoff_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md.longSizeInBytes());
-    return this;
-  }
-
-  public long getE_phoff() {
-    return accessor.getLongAt(e_phoff_offset[mdIdx], MachineDescriptionRuntime.getStatic().md.longSizeInBytes());
-  }
-
-  public Ehdr setE_shoff(final long val) {
-    accessor.setLongAt(e_shoff_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md.longSizeInBytes());
-    return this;
-  }
-
-  public long getE_shoff() {
-    return accessor.getLongAt(e_shoff_offset[mdIdx], MachineDescriptionRuntime.getStatic().md.longSizeInBytes());
-  }
-
-  public Ehdr setE_flags(final int val) {
-    accessor.setIntAt(e_flags_offset[mdIdx], val);
-    return this;
-  }
-
-  public int getE_flags() {
-    return accessor.getIntAt(e_flags_offset[mdIdx]);
-  }
-
-  public Ehdr setE_ehsize(final short val) {
-    accessor.setShortAt(e_ehsize_offset[mdIdx], val);
-    return this;
-  }
-
-  public short getE_ehsize() {
-    return accessor.getShortAt(e_ehsize_offset[mdIdx]);
-  }
-
-  public Ehdr setE_phentsize(final short val) {
-    accessor.setShortAt(e_phentsize_offset[mdIdx], val);
-    return this;
-  }
-
-  public short getE_phentsize() {
-    return accessor.getShortAt(e_phentsize_offset[mdIdx]);
-  }
-
-  public Ehdr setE_phnum(final short val) {
-    accessor.setShortAt(e_phnum_offset[mdIdx], val);
-    return this;
-  }
-
-  public short getE_phnum() {
-    return accessor.getShortAt(e_phnum_offset[mdIdx]);
-  }
-
-  public Ehdr setE_shentsize(final short val) {
-    accessor.setShortAt(e_shentsize_offset[mdIdx], val);
-    return this;
-  }
-
-  public short getE_shentsize() {
-    return accessor.getShortAt(e_shentsize_offset[mdIdx]);
-  }
-
-  public Ehdr setE_shnum(final short val) {
-    accessor.setShortAt(e_shnum_offset[mdIdx], val);
-    return this;
-  }
-
-  public short getE_shnum() {
-    return accessor.getShortAt(e_shnum_offset[mdIdx]);
-  }
-
-  public Ehdr setE_shstrndx(final short val) {
-    accessor.setShortAt(e_shstrndx_offset[mdIdx], val);
-    return this;
-  }
-
-  public short getE_shstrndx() {
-    return accessor.getShortAt(e_shstrndx_offset[mdIdx]);
-  }
-}
diff --git a/src/java/jogamp/common/os/elf/Ehdr_p1.java b/src/java/jogamp/common/os/elf/Ehdr_p1.java
new file mode 100644
index 0000000..8953776
--- /dev/null
+++ b/src/java/jogamp/common/os/elf/Ehdr_p1.java
@@ -0,0 +1,118 @@
+/* !---- DO NOT EDIT: This file autogenerated by com/jogamp/gluegen/JavaEmitter.java on Sun Feb 01 23:28:47 CET 2015 ----! */
+
+
+package jogamp.common.os.elf;
+
+import java.nio.*;
+
+import com.jogamp.gluegen.runtime.*;
+import com.jogamp.common.os.*;
+import com.jogamp.common.nio.*;
+import jogamp.common.os.MachineDataInfoRuntime;
+
+
+public class Ehdr_p1 {
+
+  StructAccessor accessor;
+
+  private static final int mdIdx = 0;
+  private final MachineDataInfo md;
+
+  private static final int[] Ehdr_p1_size = new int[] { 24 /* ARM_MIPS_32 */, 24 /* X86_32_UNIX */, 24 /* X86_32_MACOS */, 24 /* PPC_32_UNIX */, 24 /* SPARC_32_SUNOS */, 24 /* X86_32_WINDOWS */, 24 /* LP64_UNIX */, 24 /* X86_64_WINDOWS */  };
+  private static final int[] e_ident_offset = new int[] { 0 /* ARM_MIPS_32 */, 0 /* X86_32_UNIX */, 0 /* X86_32_MACOS */, 0 /* PPC_32_UNIX */, 0 /* SPARC_32_SUNOS */, 0 /* X86_32_WINDOWS */, 0 /* LP64_UNIX */, 0 /* X86_64_WINDOWS */ };
+  private static final int[] e_ident_size = new int[] { 16 /* ARM_MIPS_32 */, 16 /* X86_32_UNIX */, 16 /* X86_32_MACOS */, 16 /* PPC_32_UNIX */, 16 /* SPARC_32_SUNOS */, 16 /* X86_32_WINDOWS */, 16 /* LP64_UNIX */, 16 /* X86_64_WINDOWS */  };
+  private static final int[] e_type_offset = new int[] { 16 /* ARM_MIPS_32 */, 16 /* X86_32_UNIX */, 16 /* X86_32_MACOS */, 16 /* PPC_32_UNIX */, 16 /* SPARC_32_SUNOS */, 16 /* X86_32_WINDOWS */, 16 /* LP64_UNIX */, 16 /* X86_64_WINDOWS */ };
+//private static final int[] e_type_size = new int[] { 2 /* ARM_MIPS_32 */, 2 /* X86_32_UNIX */, 2 /* X86_32_MACOS */, 2 /* PPC_32_UNIX */, 2 /* SPARC_32_SUNOS */, 2 /* X86_32_WINDOWS */, 2 /* LP64_UNIX */, 2 /* X86_64_WINDOWS */  };
+  private static final int[] e_machine_offset = new int[] { 18 /* ARM_MIPS_32 */, 18 /* X86_32_UNIX */, 18 /* X86_32_MACOS */, 18 /* PPC_32_UNIX */, 18 /* SPARC_32_SUNOS */, 18 /* X86_32_WINDOWS */, 18 /* LP64_UNIX */, 18 /* X86_64_WINDOWS */ };
+//private static final int[] e_machine_size = new int[] { 2 /* ARM_MIPS_32 */, 2 /* X86_32_UNIX */, 2 /* X86_32_MACOS */, 2 /* PPC_32_UNIX */, 2 /* SPARC_32_SUNOS */, 2 /* X86_32_WINDOWS */, 2 /* LP64_UNIX */, 2 /* X86_64_WINDOWS */  };
+  private static final int[] e_version_offset = new int[] { 20 /* ARM_MIPS_32 */, 20 /* X86_32_UNIX */, 20 /* X86_32_MACOS */, 20 /* PPC_32_UNIX */, 20 /* SPARC_32_SUNOS */, 20 /* X86_32_WINDOWS */, 20 /* LP64_UNIX */, 20 /* X86_64_WINDOWS */ };
+//private static final int[] e_version_size = new int[] { 4 /* ARM_MIPS_32 */, 4 /* X86_32_UNIX */, 4 /* X86_32_MACOS */, 4 /* PPC_32_UNIX */, 4 /* SPARC_32_SUNOS */, 4 /* X86_32_WINDOWS */, 4 /* LP64_UNIX */, 4 /* X86_64_WINDOWS */  };
+
+  public static int size() {
+    return Ehdr_p1_size[mdIdx];
+  }
+
+  public static Ehdr_p1 create() {
+    return create(Buffers.newDirectByteBuffer(size()));
+  }
+
+  public static Ehdr_p1 create(java.nio.ByteBuffer buf) {
+      return new Ehdr_p1(buf);
+  }
+
+  Ehdr_p1(java.nio.ByteBuffer buf) {
+    md = MachineDataInfo.StaticConfig.values()[mdIdx].md;
+    accessor = new StructAccessor(buf);
+  }
+
+  public java.nio.ByteBuffer getBuffer() {
+    return accessor.getBuffer();
+  }
+
+  /** Getter for native field: CType['char *', size [fixed false, lnx64 16], [array*1]], with array length of <code>16</code> */
+  public static final int getE_identArrayLength() {
+    return 16;
+  }
+
+  /** Setter for native field: CType['char *', size [fixed false, lnx64 16], [array*1]], with array length of <code>16</code> */
+  public Ehdr_p1 setE_ident(final int offset, byte[] val) {
+    final int arrayLength = 16;
+    if( offset + val.length > arrayLength ) { throw new IndexOutOfBoundsException("offset "+offset+" + val.length "+val.length+" > array-length "+arrayLength); };
+    final int elemSize = Buffers.SIZEOF_BYTE;
+    final ByteBuffer destB = getBuffer();
+    final int bTotal = arrayLength * elemSize;
+    if( bTotal > e_ident_size[mdIdx] ) { throw new IndexOutOfBoundsException("bTotal "+bTotal+" > size "+e_ident_size[mdIdx]+", elemSize "+elemSize+" * "+arrayLength); };
+    int bOffset = e_ident_offset[mdIdx];
+    final int bLimes = bOffset + bTotal;
+    if( bLimes > destB.limit() ) { throw new IndexOutOfBoundsException("bLimes "+bLimes+" > buffer.limit "+destB.limit()+", elemOff "+bOffset+", elemSize "+elemSize+" * "+arrayLength); };
+    bOffset += elemSize * offset;
+    accessor.setBytesAt(bOffset, val);
+    return this;
+  }
+
+  /** Getter for native field: CType['char *', size [fixed false, lnx64 16], [array*1]], with array length of <code>16</code> */
+  public ByteBuffer getE_ident() {
+    return accessor.slice(e_ident_offset[mdIdx],  Buffers.SIZEOF_BYTE * 16);
+  }
+
+  /** Getter for native field: CType['char *', size [fixed false, lnx64 16], [array*1]], with array length of <code>16</code> */
+  public byte[] getE_ident(final int offset, byte result[]) {
+    final int arrayLength = 16;
+    if( offset + result.length > arrayLength ) { throw new IndexOutOfBoundsException("offset "+offset+" + result.length "+result.length+" > array-length "+arrayLength); };
+    return accessor.getBytesAt(e_ident_offset[mdIdx] + (Buffers.SIZEOF_BYTE * offset), result);
+  }
+
+
+  /** Setter for native field: CType['uint16_t', size [fixed true, lnx64 2], [int]] */
+  public Ehdr_p1 setE_type(short val) {
+    accessor.setShortAt(e_type_offset[mdIdx], val);
+    return this;
+  }
+
+  /** Getter for native field: CType['uint16_t', size [fixed true, lnx64 2], [int]] */
+  public short getE_type() {
+    return accessor.getShortAt(e_type_offset[mdIdx]);
+  }
+
+  /** Setter for native field: CType['uint16_t', size [fixed true, lnx64 2], [int]] */
+  public Ehdr_p1 setE_machine(short val) {
+    accessor.setShortAt(e_machine_offset[mdIdx], val);
+    return this;
+  }
+
+  /** Getter for native field: CType['uint16_t', size [fixed true, lnx64 2], [int]] */
+  public short getE_machine() {
+    return accessor.getShortAt(e_machine_offset[mdIdx]);
+  }
+
+  /** Setter for native field: CType['uint32_t', size [fixed true, lnx64 4], [int]] */
+  public Ehdr_p1 setE_version(int val) {
+    accessor.setIntAt(e_version_offset[mdIdx], val);
+    return this;
+  }
+
+  /** Getter for native field: CType['uint32_t', size [fixed true, lnx64 4], [int]] */
+  public int getE_version() {
+    return accessor.getIntAt(e_version_offset[mdIdx]);
+  }
+}
diff --git a/src/java/jogamp/common/os/elf/Ehdr_p2.java b/src/java/jogamp/common/os/elf/Ehdr_p2.java
new file mode 100644
index 0000000..0842e15
--- /dev/null
+++ b/src/java/jogamp/common/os/elf/Ehdr_p2.java
@@ -0,0 +1,176 @@
+/* !---- DO NOT EDIT: This file autogenerated by com/jogamp/gluegen/JavaEmitter.java on Sun Feb 01 23:28:47 CET 2015 ----! */
+
+
+package jogamp.common.os.elf;
+
+import java.nio.*;
+
+import com.jogamp.gluegen.runtime.*;
+import com.jogamp.common.os.*;
+import com.jogamp.common.nio.*;
+import jogamp.common.os.MachineDataInfoRuntime;
+
+
+public class Ehdr_p2 {
+
+  StructAccessor accessor;
+
+  private final int mdIdx;
+  private final MachineDataInfo md;
+
+  private static final int[] Ehdr_p2_size = new int[] { 28 /* ARM_MIPS_32 */, 28 /* X86_32_UNIX */, 28 /* X86_32_MACOS */, 28 /* PPC_32_UNIX */, 28 /* SPARC_32_SUNOS */, 28 /* X86_32_WINDOWS */, 40 /* LP64_UNIX */, 40 /* X86_64_WINDOWS */  };
+  private static final int[] e_entry_offset = new int[] { 0 /* ARM_MIPS_32 */, 0 /* X86_32_UNIX */, 0 /* X86_32_MACOS */, 0 /* PPC_32_UNIX */, 0 /* SPARC_32_SUNOS */, 0 /* X86_32_WINDOWS */, 0 /* LP64_UNIX */, 0 /* X86_64_WINDOWS */ };
+//private static final int[] e_entry_size = new int[] { 4 /* ARM_MIPS_32 */, 4 /* X86_32_UNIX */, 4 /* X86_32_MACOS */, 4 /* PPC_32_UNIX */, 4 /* SPARC_32_SUNOS */, 4 /* X86_32_WINDOWS */, 8 /* LP64_UNIX */, 8 /* X86_64_WINDOWS */  };
+  private static final int[] e_phoff_offset = new int[] { 4 /* ARM_MIPS_32 */, 4 /* X86_32_UNIX */, 4 /* X86_32_MACOS */, 4 /* PPC_32_UNIX */, 4 /* SPARC_32_SUNOS */, 4 /* X86_32_WINDOWS */, 8 /* LP64_UNIX */, 8 /* X86_64_WINDOWS */ };
+//private static final int[] e_phoff_size = new int[] { 4 /* ARM_MIPS_32 */, 4 /* X86_32_UNIX */, 4 /* X86_32_MACOS */, 4 /* PPC_32_UNIX */, 4 /* SPARC_32_SUNOS */, 4 /* X86_32_WINDOWS */, 8 /* LP64_UNIX */, 8 /* X86_64_WINDOWS */  };
+  private static final int[] e_shoff_offset = new int[] { 8 /* ARM_MIPS_32 */, 8 /* X86_32_UNIX */, 8 /* X86_32_MACOS */, 8 /* PPC_32_UNIX */, 8 /* SPARC_32_SUNOS */, 8 /* X86_32_WINDOWS */, 16 /* LP64_UNIX */, 16 /* X86_64_WINDOWS */ };
+//private static final int[] e_shoff_size = new int[] { 4 /* ARM_MIPS_32 */, 4 /* X86_32_UNIX */, 4 /* X86_32_MACOS */, 4 /* PPC_32_UNIX */, 4 /* SPARC_32_SUNOS */, 4 /* X86_32_WINDOWS */, 8 /* LP64_UNIX */, 8 /* X86_64_WINDOWS */  };
+  private static final int[] e_flags_offset = new int[] { 12 /* ARM_MIPS_32 */, 12 /* X86_32_UNIX */, 12 /* X86_32_MACOS */, 12 /* PPC_32_UNIX */, 12 /* SPARC_32_SUNOS */, 12 /* X86_32_WINDOWS */, 24 /* LP64_UNIX */, 24 /* X86_64_WINDOWS */ };
+//private static final int[] e_flags_size = new int[] { 4 /* ARM_MIPS_32 */, 4 /* X86_32_UNIX */, 4 /* X86_32_MACOS */, 4 /* PPC_32_UNIX */, 4 /* SPARC_32_SUNOS */, 4 /* X86_32_WINDOWS */, 4 /* LP64_UNIX */, 4 /* X86_64_WINDOWS */  };
+  private static final int[] e_ehsize_offset = new int[] { 16 /* ARM_MIPS_32 */, 16 /* X86_32_UNIX */, 16 /* X86_32_MACOS */, 16 /* PPC_32_UNIX */, 16 /* SPARC_32_SUNOS */, 16 /* X86_32_WINDOWS */, 28 /* LP64_UNIX */, 28 /* X86_64_WINDOWS */ };
+//private static final int[] e_ehsize_size = new int[] { 2 /* ARM_MIPS_32 */, 2 /* X86_32_UNIX */, 2 /* X86_32_MACOS */, 2 /* PPC_32_UNIX */, 2 /* SPARC_32_SUNOS */, 2 /* X86_32_WINDOWS */, 2 /* LP64_UNIX */, 2 /* X86_64_WINDOWS */  };
+  private static final int[] e_phentsize_offset = new int[] { 18 /* ARM_MIPS_32 */, 18 /* X86_32_UNIX */, 18 /* X86_32_MACOS */, 18 /* PPC_32_UNIX */, 18 /* SPARC_32_SUNOS */, 18 /* X86_32_WINDOWS */, 30 /* LP64_UNIX */, 30 /* X86_64_WINDOWS */ };
+//private static final int[] e_phentsize_size = new int[] { 2 /* ARM_MIPS_32 */, 2 /* X86_32_UNIX */, 2 /* X86_32_MACOS */, 2 /* PPC_32_UNIX */, 2 /* SPARC_32_SUNOS */, 2 /* X86_32_WINDOWS */, 2 /* LP64_UNIX */, 2 /* X86_64_WINDOWS */  };
+  private static final int[] e_phnum_offset = new int[] { 20 /* ARM_MIPS_32 */, 20 /* X86_32_UNIX */, 20 /* X86_32_MACOS */, 20 /* PPC_32_UNIX */, 20 /* SPARC_32_SUNOS */, 20 /* X86_32_WINDOWS */, 32 /* LP64_UNIX */, 32 /* X86_64_WINDOWS */ };
+//private static final int[] e_phnum_size = new int[] { 2 /* ARM_MIPS_32 */, 2 /* X86_32_UNIX */, 2 /* X86_32_MACOS */, 2 /* PPC_32_UNIX */, 2 /* SPARC_32_SUNOS */, 2 /* X86_32_WINDOWS */, 2 /* LP64_UNIX */, 2 /* X86_64_WINDOWS */  };
+  private static final int[] e_shentsize_offset = new int[] { 22 /* ARM_MIPS_32 */, 22 /* X86_32_UNIX */, 22 /* X86_32_MACOS */, 22 /* PPC_32_UNIX */, 22 /* SPARC_32_SUNOS */, 22 /* X86_32_WINDOWS */, 34 /* LP64_UNIX */, 34 /* X86_64_WINDOWS */ };
+//private static final int[] e_shentsize_size = new int[] { 2 /* ARM_MIPS_32 */, 2 /* X86_32_UNIX */, 2 /* X86_32_MACOS */, 2 /* PPC_32_UNIX */, 2 /* SPARC_32_SUNOS */, 2 /* X86_32_WINDOWS */, 2 /* LP64_UNIX */, 2 /* X86_64_WINDOWS */  };
+  private static final int[] e_shnum_offset = new int[] { 24 /* ARM_MIPS_32 */, 24 /* X86_32_UNIX */, 24 /* X86_32_MACOS */, 24 /* PPC_32_UNIX */, 24 /* SPARC_32_SUNOS */, 24 /* X86_32_WINDOWS */, 36 /* LP64_UNIX */, 36 /* X86_64_WINDOWS */ };
+//private static final int[] e_shnum_size = new int[] { 2 /* ARM_MIPS_32 */, 2 /* X86_32_UNIX */, 2 /* X86_32_MACOS */, 2 /* PPC_32_UNIX */, 2 /* SPARC_32_SUNOS */, 2 /* X86_32_WINDOWS */, 2 /* LP64_UNIX */, 2 /* X86_64_WINDOWS */  };
+  private static final int[] e_shstrndx_offset = new int[] { 26 /* ARM_MIPS_32 */, 26 /* X86_32_UNIX */, 26 /* X86_32_MACOS */, 26 /* PPC_32_UNIX */, 26 /* SPARC_32_SUNOS */, 26 /* X86_32_WINDOWS */, 38 /* LP64_UNIX */, 38 /* X86_64_WINDOWS */ };
+//private static final int[] e_shstrndx_size = new int[] { 2 /* ARM_MIPS_32 */, 2 /* X86_32_UNIX */, 2 /* X86_32_MACOS */, 2 /* PPC_32_UNIX */, 2 /* SPARC_32_SUNOS */, 2 /* X86_32_WINDOWS */, 2 /* LP64_UNIX */, 2 /* X86_64_WINDOWS */  };
+
+  public java.nio.ByteBuffer getBuffer() {
+    return accessor.getBuffer();
+  }
+
+  /** Setter for native field: CType['ElfN_Addr' (typedef), size [fixed false, lnx64 8], [int]] */
+  public Ehdr_p2 setE_entry(long val) {
+    accessor.setLongAt(e_entry_offset[mdIdx], val, md.longSizeInBytes());
+    return this;
+  }
+
+  /** Getter for native field: CType['ElfN_Addr' (typedef), size [fixed false, lnx64 8], [int]] */
+  public long getE_entry() {
+    return accessor.getLongAt(e_entry_offset[mdIdx], md.longSizeInBytes());
+  }
+
+  /** Setter for native field: CType['ElfN_Off' (typedef), size [fixed false, lnx64 8], [int]] */
+  public Ehdr_p2 setE_phoff(long val) {
+    accessor.setLongAt(e_phoff_offset[mdIdx], val, md.longSizeInBytes());
+    return this;
+  }
+
+  /** Getter for native field: CType['ElfN_Off' (typedef), size [fixed false, lnx64 8], [int]] */
+  public long getE_phoff() {
+    return accessor.getLongAt(e_phoff_offset[mdIdx], md.longSizeInBytes());
+  }
+
+  /** Setter for native field: CType['ElfN_Off' (typedef), size [fixed false, lnx64 8], [int]] */
+  public Ehdr_p2 setE_shoff(long val) {
+    accessor.setLongAt(e_shoff_offset[mdIdx], val, md.longSizeInBytes());
+    return this;
+  }
+
+  /** Getter for native field: CType['ElfN_Off' (typedef), size [fixed false, lnx64 8], [int]] */
+  public long getE_shoff() {
+    return accessor.getLongAt(e_shoff_offset[mdIdx], md.longSizeInBytes());
+  }
+
+  /** Setter for native field: CType['uint32_t', size [fixed true, lnx64 4], [int]] */
+  public Ehdr_p2 setE_flags(int val) {
+    accessor.setIntAt(e_flags_offset[mdIdx], val);
+    return this;
+  }
+
+  /** Getter for native field: CType['uint32_t', size [fixed true, lnx64 4], [int]] */
+  public int getE_flags() {
+    return accessor.getIntAt(e_flags_offset[mdIdx]);
+  }
+
+  /** Setter for native field: CType['uint16_t', size [fixed true, lnx64 2], [int]] */
+  public Ehdr_p2 setE_ehsize(short val) {
+    accessor.setShortAt(e_ehsize_offset[mdIdx], val);
+    return this;
+  }
+
+  /** Getter for native field: CType['uint16_t', size [fixed true, lnx64 2], [int]] */
+  public short getE_ehsize() {
+    return accessor.getShortAt(e_ehsize_offset[mdIdx]);
+  }
+
+  /** Setter for native field: CType['uint16_t', size [fixed true, lnx64 2], [int]] */
+  public Ehdr_p2 setE_phentsize(short val) {
+    accessor.setShortAt(e_phentsize_offset[mdIdx], val);
+    return this;
+  }
+
+  /** Getter for native field: CType['uint16_t', size [fixed true, lnx64 2], [int]] */
+  public short getE_phentsize() {
+    return accessor.getShortAt(e_phentsize_offset[mdIdx]);
+  }
+
+  /** Setter for native field: CType['uint16_t', size [fixed true, lnx64 2], [int]] */
+  public Ehdr_p2 setE_phnum(short val) {
+    accessor.setShortAt(e_phnum_offset[mdIdx], val);
+    return this;
+  }
+
+  /** Getter for native field: CType['uint16_t', size [fixed true, lnx64 2], [int]] */
+  public short getE_phnum() {
+    return accessor.getShortAt(e_phnum_offset[mdIdx]);
+  }
+
+  /** Setter for native field: CType['uint16_t', size [fixed true, lnx64 2], [int]] */
+  public Ehdr_p2 setE_shentsize(short val) {
+    accessor.setShortAt(e_shentsize_offset[mdIdx], val);
+    return this;
+  }
+
+  /** Getter for native field: CType['uint16_t', size [fixed true, lnx64 2], [int]] */
+  public short getE_shentsize() {
+    return accessor.getShortAt(e_shentsize_offset[mdIdx]);
+  }
+
+  /** Setter for native field: CType['uint16_t', size [fixed true, lnx64 2], [int]] */
+  public Ehdr_p2 setE_shnum(short val) {
+    accessor.setShortAt(e_shnum_offset[mdIdx], val);
+    return this;
+  }
+
+  /** Getter for native field: CType['uint16_t', size [fixed true, lnx64 2], [int]] */
+  public short getE_shnum() {
+    return accessor.getShortAt(e_shnum_offset[mdIdx]);
+  }
+
+  /** Setter for native field: CType['uint16_t', size [fixed true, lnx64 2], [int]] */
+  public Ehdr_p2 setE_shstrndx(short val) {
+    accessor.setShortAt(e_shstrndx_offset[mdIdx], val);
+    return this;
+  }
+
+  /** Getter for native field: CType['uint16_t', size [fixed true, lnx64 2], [int]] */
+  public short getE_shstrndx() {
+    return accessor.getShortAt(e_shstrndx_offset[mdIdx]);
+  }
+
+  // --- Begin CustomJavaCode .cfg declarations
+  public static int size(final int mdIdx) {
+      return Ehdr_p2_size[mdIdx];
+  }
+
+  public static Ehdr_p2 create(final int mdIdx) {
+      return create(mdIdx, Buffers.newDirectByteBuffer(size(mdIdx)));
+  }
+
+  public static Ehdr_p2 create(final int mdIdx, final java.nio.ByteBuffer buf) {
+      return new Ehdr_p2(mdIdx, buf);
+  }
+
+  Ehdr_p2(final int mdIdx, final java.nio.ByteBuffer buf) {
+      this.mdIdx = mdIdx;
+      this.md = MachineDataInfo.StaticConfig.values()[mdIdx].md;
+      this.accessor = new StructAccessor(buf);
+  }
+  // ---- End CustomJavaCode .cfg declarations
+}
diff --git a/src/java/jogamp/common/os/elf/ElfHeader.java b/src/java/jogamp/common/os/elf/ElfHeaderPart1.java
similarity index 60%
rename from src/java/jogamp/common/os/elf/ElfHeader.java
rename to src/java/jogamp/common/os/elf/ElfHeaderPart1.java
index 3447107..4f5b135 100644
--- a/src/java/jogamp/common/os/elf/ElfHeader.java
+++ b/src/java/jogamp/common/os/elf/ElfHeaderPart1.java
@@ -31,26 +31,38 @@ import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.nio.ByteBuffer;
 
+import jogamp.common.Debug;
+import jogamp.common.os.MachineDataInfoRuntime;
+
+import com.jogamp.common.os.MachineDataInfo;
+import com.jogamp.common.os.Platform.ABIType;
+import com.jogamp.common.os.Platform.CPUType;
+import com.jogamp.common.os.Platform.OSType;
+
 import static jogamp.common.os.elf.IOUtils.readBytes;
-import static jogamp.common.os.elf.IOUtils.seek;
-import static jogamp.common.os.elf.IOUtils.shortToInt;
-import static jogamp.common.os.elf.IOUtils.toHexString;
 
 /**
- * ELF ABI Header
+ * ELF ABI Header Part-1
+ * <p>
+ * Part-1 can be read w/o knowledge of CPUType!
+ * </p>
  * <p>
  * References:
  * <ul>
- *   <li>http://linux.die.net/man/5/elf</li>
  *   <li>http://www.sco.com/developers/gabi/latest/contents.html</li>
+ *   <li>https://en.wikipedia.org/wiki/Executable_and_Linkable_Format</li>
+ *   <li>http://linux.die.net/man/5/elf</li>
  *   <li>http://infocenter.arm.com/
  *   <ul>
  *      <li>ARM IHI 0044E, current through ABI release 2.09</li>
+ *      <li>ARM IHI 0056B: Elf for ARM 64-bit Architecture</li>
  *   </ul></li>
  * </ul>
  * </p>
  */
-public class ElfHeader {
+public class ElfHeaderPart1 {
+    static final boolean DEBUG = Debug.debug("Platform");
+
     /** Size of e_ident array - {@value} */
     public static int EI_NIDENT = 16;
 
@@ -137,64 +149,6 @@ public class ElfHeader {
      */
     public static final int EI_PAD = 9;
 
-    /**
-     * This masks an 8-bit version number, the version of the ABI to which this
-     * ELF file conforms. This ABI is version 5. A value of 0 denotes unknown conformance.
-     * {@value}
-     */
-    public static final int EF_ARM_ABIMASK  = 0xFF000000;
-    public static final int EF_ARM_ABISHIFT  = 24;
-
-    /**
-     * ARM ABI version 5.
-     * {@value}
-     */
-    public static final int EF_ARM_ABI5  = 0x05000000;
-
-    /**
-     * The ELF file contains BE-8 code, suitable for execution on an ARM
-     * Architecture v6 processor. This flag must only be set on an executable file.
-     * {@value}
-     */
-    public static final int EF_ARM_BE8      = 0x00800000;
-
-    /**
-     * Legacy code (ABI version 4 and earlier) generated by gcc-arm-xxx might
-     * use these bits.
-     * {@value}
-     */
-    public static final int EF_ARM_GCCMASK  = 0x00400FFF;
-
-    /**
-     * Set in executable file headers (e_type = ET_EXEC or ET_DYN) to note that
-     * the executable file was built to conform to the hardware floating-point
-     * procedure-call standard.
-     * <p>
-     * Compatible with legacy (pre version 5) gcc use as EF_ARM_VFP_FLOAT.
-     * </p>
-     * <p>
-     * Note: This is not used (anymore)
-     * </p>
-     * {@value}
-     */
-    public static final int EF_ARM_ABI_FLOAT_HARD  = 0x00000400;
-
-    /**
-     * Set in executable file headers (e_type = ET_EXEC or ET_DYN) to note
-     * explicitly that the executable file was built to conform to the software
-     * floating-point procedure-call standard (the base standard). If both
-     * {@link #EF_ARM_ABI_FLOAT_HARD} and {@link #EF_ARM_ABI_FLOAT_SOFT} are clear,
-     * conformance to the base procedure-call standard is implied.
-     * <p>
-     * Compatible with legacy (pre version 5) gcc use as EF_ARM_SOFT_FLOAT.
-     * </p>
-     * <p>
-     * Note: This is not used (anymore)
-     * </p>
-     * {@value}
-     */
-    public static final int EF_ARM_ABI_FLOAT_SOFT  = 0x00000200;
-
     /** An unknown type - {@value} */
     public static final short ET_NONE   = 0;
     /** A relocatable file - {@value} */
@@ -349,8 +303,8 @@ public class ElfHeader {
     public static final short EM_L1OM = 180;
     public static final short EM_INTEL181 = 181;
     public static final short EM_INTEL182 = 182;
-    public static final short EM_res183 = 183;
-    public static final short EM_res184 = 184;
+    public static final short EM_AARCH64 = 183;
+    public static final short EM_ARM184 = 184;
     public static final short EM_AVR32 = 185;
     public static final short EM_STM8 = 186;
     public static final short EM_TILE64 = 187;
@@ -365,45 +319,112 @@ public class ElfHeader {
                ELFMAG3 == ident[3] ;
     }
 
-    /** Public access to the raw elf header */
-    public final Ehdr d;
+    /** Public access to the raw elf header part-1 (CPU/ABI independent read) */
+    public final Ehdr_p1 raw;
+    private final byte[] E_ident;
 
-    /** Public access to the {@link SectionHeader} */
-    public final SectionHeader[] sht;
+    /** Lower case CPUType name */
+    public final String cpuName;
+    public final CPUType cpuType;
+    public final ABIType abiType;
 
-    private final String string;
+    public final MachineDataInfo.StaticConfig machDesc;
 
     /**
      * Note: The input stream shall stay untouch to be able to read sections!
-     *
+     * @param osType TODO
      * @param in input stream of a binary file at position zero
+     *
      * @return
      * @throws IOException if reading from the given input stream fails or less then ELF Header size bytes
      * @throws IllegalArgumentException if the given input stream does not represent an ELF Header
      */
-    public static ElfHeader read(final RandomAccessFile in) throws IOException, IllegalArgumentException {
-        final int eh_sz = Ehdr.size();
-        final byte[] buf = new byte[eh_sz];
-        readBytes (in, buf, 0, eh_sz);
-        final ElfHeader eh = new ElfHeader(ByteBuffer.wrap(buf, 0, buf.length), in);
-        return eh;
+    public static ElfHeaderPart1 read(final OSType osType, final RandomAccessFile in) throws IOException, IllegalArgumentException {
+        return new ElfHeaderPart1(osType, in);
     }
 
     /**
+     * @param osType TODO
      * @param buf ELF Header bytes
      * @throws IllegalArgumentException if the given buffer does not represent an ELF Header
      * @throws IOException
      */
-    ElfHeader(final java.nio.ByteBuffer buf, final RandomAccessFile in) throws IllegalArgumentException, IOException {
-        d = Ehdr.create(buf);
-        if( !isIdentityValid(d.getE_ident()) ) {
+    ElfHeaderPart1(final OSType osType, final RandomAccessFile in) throws IllegalArgumentException, IOException {
+        {
+            final byte[] buf = new byte[Ehdr_p1.size()];
+            readBytes (in, buf, 0, buf.length);
+            final ByteBuffer eh1Bytes = ByteBuffer.wrap(buf, 0, buf.length);
+            raw = Ehdr_p1.create(eh1Bytes);
+        }
+        E_ident = raw.getE_ident(0, new byte[Ehdr_p1.getE_identArrayLength()]);
+        if( !isIdentityValid(E_ident) ) {
             throw new IllegalArgumentException("Buffer is not an ELF Header");
         }
-        sht = readSectionHeaderTable(in);
-        string = toStringImpl();
-    }
 
-    public final short getSize() { return d.getE_ehsize(); }
+        final short machine = getMachine();
+        switch ( machine ) {
+            case EM_ARM:
+                cpuName = "arm"; // lowest 32bit denominator, ok for now
+                abiType = ABIType.GENERIC_ABI;
+                break;
+            case EM_AARCH64:
+                cpuName = "aarch64";
+                abiType = ABIType.EABI_AARCH64;
+                break;
+            case EM_X86_64:
+                cpuName = "x86_64";
+                abiType = ABIType.GENERIC_ABI;
+                break;
+            case EM_386:
+                cpuName = "i386";
+                abiType = ABIType.GENERIC_ABI;
+                break;
+            case EM_486:
+                cpuName = "i486";
+                abiType = ABIType.GENERIC_ABI;
+                break;
+            case EM_IA_64:
+                cpuName = "ia64";
+                abiType = ABIType.GENERIC_ABI;
+                break;
+            case EM_MIPS:
+                 // Can be little-endian or big-endian and 32 or 64 bits
+                if( 64 == getArchClassBits() ) {
+                    cpuName = isLittleEndian() ? "mips64le" : "mips64";
+                } else {
+                    cpuName = isLittleEndian() ? "mipsle" : "mips";
+                }
+                abiType = ABIType.GENERIC_ABI;
+                break;
+            case EM_MIPS_RS3_LE:
+                cpuName = "mipsle-rs3";  // FIXME: Only little-endian?
+                abiType = ABIType.GENERIC_ABI;
+                break;
+            case EM_MIPS_X:
+                cpuName = isLittleEndian() ? "mipsle-x" : "mips-x"; // Can be little-endian
+                abiType = ABIType.GENERIC_ABI;
+                break;
+            case EM_PPC:
+                cpuName = "ppc";
+                abiType = ABIType.GENERIC_ABI;
+                break;
+            case EM_PPC64:
+                cpuName = "ppc64";
+                abiType = ABIType.GENERIC_ABI;
+                break;
+            case EM_SH:
+                cpuName = "superh";
+                abiType = ABIType.GENERIC_ABI;
+                break;
+            default:
+                throw new IllegalArgumentException("CPUType and ABIType could not be determined");
+        }
+        cpuType = CPUType.query(cpuName.toLowerCase());
+        machDesc = MachineDataInfoRuntime.guessStaticMachineDataInfo(osType, cpuType);
+        if(DEBUG) {
+            System.err.println("ELF-1: cpuName "+cpuName+" -> "+cpuType+", "+abiType+", machDesc "+machDesc.toShortString());
+        }
+    }
 
     /**
      * Returns the architecture class in bits,
@@ -411,7 +432,7 @@ public class ElfHeader {
      * and 0 for {@link #ELFCLASSNONE}.
      */
     public final int getArchClassBits() {
-        switch( d.getE_ident()[EI_CLASS] ) {
+        switch( E_ident[EI_CLASS] ) {
             case ELFCLASS32: return 32;
             case ELFCLASS64: return 64;
             default: return 0;
@@ -423,223 +444,66 @@ public class ElfHeader {
      * {@link #ELFDATA2LSB}, {@link #ELFDATA2MSB} or {@link #ELFDATANONE};
      */
     public final byte getDataEncodingMode() {
-        return d.getE_ident()[EI_DATA];
+        return E_ident[EI_DATA];
     }
 
+    /**
+     * Returns whether the processor's {@link #getDataEncodingMode() data encoding} is {@link #ELFDATA2LSB}.
+     */
+    public final boolean isLittleEndian() { return ELFDATA2LSB == E_ident[EI_DATA]; }
+    /**
+     * Returns whether the processor's {@link #getDataEncodingMode() data encoding} is {@link #ELFDATA2MSB}.
+     */
+    public final boolean isBigEndian() { return ELFDATA2MSB == E_ident[EI_DATA]; }
+    /**
+     * Returns whether the processor's {@link #getDataEncodingMode() data encoding} is {@link #ELFDATANONE}.
+     */
+    public final boolean isNoneEndian() { return ELFDATANONE == E_ident[EI_DATA]; }
+
     /** Returns the ELF file version, should be {@link #EV_CURRENT}. */
     public final byte getVersion() {
-        return d.getE_ident()[EI_VERSION];
+        return E_ident[EI_VERSION];
     }
 
     /** Returns the operating system and ABI for this file, 3 == Linux. Note: Often not used. */
     public final byte getOSABI() {
-        return d.getE_ident()[EI_OSABI];
+        return E_ident[EI_OSABI];
     }
 
     /** Returns the version of the {@link #getOSABI() OSABI} for this file. */
     public final byte getOSABIVersion() {
-        return d.getE_ident()[EI_ABIVERSION];
+        return E_ident[EI_ABIVERSION];
     }
 
     /** Returns the object file type, e.g. {@link #ET_EXEC}, .. */
     public final short getType() {
-        return d.getE_type();
+        return raw.getE_type();
     }
 
     /** Returns the required architecture for the file, e.g. {@link #EM_386}, .. */
     public final short getMachine() {
-        return d.getE_machine();
-    }
-
-    /**
-     * Returns true if {@link #getMachine() machine} is a 32 or 64 bit ARM CPU
-     * of type {@link #EM_ARM}. */
-    public final boolean isArm() {
-        return getMachine() == EM_ARM;
-    }
-
-    /**
-     * Returns true if {@link #getMachine() machine} is a 32 or 64 bit Intel CPU
-     * of type {@link #EM_386}, {@link #EM_486} or {@link #EM_X86_64}. */
-    public final boolean isX86_32() {
-        final short m = getMachine();
-        return EM_386 == m ||
-               EM_486 == m ||
-               EM_X86_64 == m;
-    }
-
-    /**
-     * Returns true if {@link #getMachine() machine} is a 64 bit AMD/Intel x86_64 CPU
-     * of type {@link #EM_X86_64}. */
-    public final boolean isX86_64() {
-        return getMachine() == EM_X86_64;
-    }
-
-    /**
-     * Returns true if {@link #getMachine() machine} is a 64 bit Intel Itanium CPU
-     * of type {@link #EM_IA_64}. */
-    public final boolean isIA64() {
-        return getMachine() == EM_IA_64;
-    }
-
-    /**
-     * Returns true if {@link #getMachine() machine} is a 32 or 64 bit MIPS CPU
-     * of type {@link #EM_MIPS}, {@link #EM_MIPS_X} or {@link #EM_MIPS_RS3_LE}. */
-    public final boolean isMips() {
-        final short m = getMachine();
-        return EM_MIPS == m ||
-               EM_MIPS_X == m ||
-               EM_MIPS_RS3_LE == m;
-    }
-
-    /** Returns the processor-specific flags associated with the file. */
-    public final int getFlags() {
-        return d.getE_flags();
-    }
-
-    /** Returns the ARM EABI version from {@link #getFlags() flags}, maybe 0 if not an ARM EABI. */
-    public byte getArmABI() {
-        return (byte) ( ( ( EF_ARM_ABIMASK & d.getE_flags() ) >> EF_ARM_ABISHIFT ) & 0xff );
-    }
-
-    /** Returns the ARM EABI legacy GCC {@link #getFlags() flags}, maybe 0 if not an ARM EABI or not having legacy GCC flags. */
-    public int getArmLegacyGCCFlags() {
-        final int f = d.getE_flags();
-        return 0 != ( EF_ARM_ABIMASK & f ) ? ( EF_ARM_GCCMASK & f ) : 0;
-    }
-
-    /**
-     * Returns the ARM EABI float mode from {@link #getFlags() flags},
-     * i.e. 1 for {@link #EF_ARM_ABI_FLOAT_SOFT}, 2 for {@link #EF_ARM_ABI_FLOAT_HARD}
-     * or 0 for none.
-     * <p>
-     * Note: This is not used (anymore)
-     * </p>
-     */
-    public byte getArmFloatMode() {
-        final int f = d.getE_flags();
-        if( 0 != ( EF_ARM_ABIMASK & f ) ) {
-            if( ( EF_ARM_ABI_FLOAT_HARD & f ) != 0 ) {
-                return 2;
-            }
-            if( ( EF_ARM_ABI_FLOAT_SOFT & f ) != 0 ) {
-                return 1;
-            }
-        }
-        return 0;
-    }
-
-    /** Returns the 1st occurence of matching SectionHeader {@link SectionHeader#getType() type}, or null if not exists. */
-    public final SectionHeader getSectionHeader(final int type) {
-        for(int i=0; i<sht.length; i++) {
-            final SectionHeader sh = sht[i];
-            if( sh.getType() == type ) {
-                return sh;
-            }
-        }
-        return null;
-    }
-
-    /** Returns the 1st occurence of matching SectionHeader {@link SectionHeader#getName() name}, or null if not exists. */
-    public final SectionHeader getSectionHeader(final String name) {
-        for(int i=0; i<sht.length; i++) {
-            final SectionHeader sh = sht[i];
-            if( sh.getName().equals(name) ) {
-                return sh;
-            }
-        }
-        return null;
+        return raw.getE_machine();
     }
 
     @Override
     public final String toString() {
-        return string;
-    }
-
-    private final String toStringImpl() {
-        final String machineS;
-        if( isArm() ) {
-            machineS=", arm";
-        } else if( isX86_64() ) {
-            machineS=", x86_64";
-        } else if( isX86_32() ) {
-            machineS=", x86_32";
-        } else if( isIA64() ) {
-            machineS=", itanium";
-        } else if( isMips() ) {
-            machineS=", mips";
-        } else {
-            machineS="";
-        }
         final int enc = getDataEncodingMode();
         final String encS;
         switch(enc) {
-            case 1:  encS = "LSB"; break;
-            case 2:  encS = "MSB"; break;
-            default: encS = "NON"; break;
+            case ELFDATA2LSB: encS = "LSB"; break;
+            case ELFDATA2MSB: encS = "MSB"; break;
+            default:          encS = "NON"; break; /* ELFDATANONE */
         }
-        final int armABI = getArmABI();
-        final String armFlagsS;
-        if( 0 != armABI ) {
-            armFlagsS=", arm[abi "+armABI+", lGCC "+getArmLegacyGCCFlags()+", float "+getArmFloatMode()+"]";
-        } else {
-            armFlagsS="";
+        final int type = getType();
+        final String typeS;
+        switch(type) {
+            case ET_REL:  typeS = "reloc"; break;
+            case ET_EXEC: typeS = "exec"; break;
+            case ET_DYN:  typeS = "shared"; break;
+            case ET_CORE: typeS = "core"; break;
+            default:      typeS = "none"; break; /* ET_NONE */
         }
-        return "ElfHeader[vers "+getVersion()+", machine["+getMachine()+machineS+"], bits "+getArchClassBits()+", enc "+encS+
-               ", abi[os "+getOSABI()+", vers "+getOSABIVersion()+"], flags["+toHexString(getFlags())+armFlagsS+"], type "+getType()+", sh-num "+sht.length+"]";
-    }
-
-    final SectionHeader[] readSectionHeaderTable(final RandomAccessFile in) throws IOException, IllegalArgumentException {
-        // positioning
-        {
-            final long off = d.getE_shoff(); // absolute offset
-            if( 0 == off ) {
-                return new SectionHeader[0];
-            }
-            seek(in, off);
-        }
-        final SectionHeader[] sht;
-        final int strndx = d.getE_shstrndx();
-        final int size = d.getE_shentsize();
-        final int num;
-        int i;
-        if( 0 == d.getE_shnum() ) {
-            // Read 1st table 1st and use it's sh_size
-            final byte[] buf0 = new byte[size];
-            readBytes(in, buf0, 0, size);
-            final SectionHeader sh0 = new SectionHeader(buf0, 0, size, 0);
-            num = (int) sh0.d.getSh_size();
-            if( 0 >= num ) {
-                throw new IllegalArgumentException("EHdr sh_num == 0 and 1st SHdr size == 0");
-            }
-            sht = new SectionHeader[num];
-            sht[0] = sh0;
-            i=1;
-        } else {
-            num = d.getE_shnum();
-            sht = new SectionHeader[num];
-            i=0;
-        }
-        for(; i<num; i++) {
-            final byte[] buf = new byte[size];
-            readBytes(in, buf, 0, size);
-            sht[i] = new SectionHeader(buf, 0, size, i);
-        }
-        if( SectionHeader.SHN_UNDEF != strndx ) {
-            // has section name string table
-            if( shortToInt(SectionHeader.SHN_LORESERVE) <= strndx ) {
-                throw new InternalError("TODO strndx: "+SectionHeader.SHN_LORESERVE+" < "+strndx);
-            }
-            final SectionHeader strShdr = sht[strndx];
-            if( SectionHeader.SHT_STRTAB != strShdr.getType() ) {
-                throw new IllegalArgumentException("Ref. string Shdr["+strndx+"] is of type "+strShdr.d.getSh_type());
-            }
-            final Section strS = strShdr.readSection(in);
-            for(i=0; i<num; i++) {
-                sht[i].initName(strS, sht[i].d.getSh_name());
-            }
-        }
-
-        return sht;
+        return "ELF-1[vers "+getVersion()+", machine["+getMachine()+", "+cpuType+", "+abiType+", machDesc "+machDesc.toShortString()+"], bits "+getArchClassBits()+", enc "+encS+
+               ", abi[os "+getOSABI()+", vers "+getOSABIVersion()+"], type "+typeS+"]";
     }
 }
diff --git a/src/java/jogamp/common/os/elf/ElfHeaderPart2.java b/src/java/jogamp/common/os/elf/ElfHeaderPart2.java
new file mode 100644
index 0000000..e019b05
--- /dev/null
+++ b/src/java/jogamp/common/os/elf/ElfHeaderPart2.java
@@ -0,0 +1,375 @@
+/**
+ * Copyright 2013 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package jogamp.common.os.elf;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+
+import com.jogamp.common.os.Platform.ABIType;
+import com.jogamp.common.os.Platform.CPUFamily;
+import com.jogamp.common.os.Platform.CPUType;
+
+import static jogamp.common.os.elf.IOUtils.readBytes;
+import static jogamp.common.os.elf.IOUtils.seek;
+import static jogamp.common.os.elf.IOUtils.shortToInt;
+import static jogamp.common.os.elf.IOUtils.toHexString;
+
+/**
+ * ELF ABI Header Part-2
+ * <p>
+ * Part-2 can only be read w/ knowledge of CPUType!
+ * </p>
+ * <p>
+ * References:
+ * <ul>
+ *   <li>http://www.sco.com/developers/gabi/latest/contents.html</li>
+ *   <li>https://en.wikipedia.org/wiki/Executable_and_Linkable_Format</li>
+ *   <li>http://linux.die.net/man/5/elf</li>
+ *   <li>http://infocenter.arm.com/
+ *   <ul>
+ *      <li>ARM IHI 0044E, current through ABI release 2.09</li>
+ *      <li>ARM IHI 0056B: Elf for ARM 64-bit Architecture</li>
+ *   </ul></li>
+ * </ul>
+ * </p>
+ */
+public class ElfHeaderPart2 {
+    /**
+     * This masks an 8-bit version number, the version of the ABI to which this
+     * ELF file conforms. This ABI is version 5. A value of 0 denotes unknown conformance.
+     * {@value}
+     */
+    public static final int EF_ARM_ABIMASK  = 0xFF000000;
+    public static final int EF_ARM_ABISHIFT  = 24;
+
+    /**
+     * ARM ABI version 5.
+     * {@value}
+     */
+    public static final int EF_ARM_ABI5  = 0x05000000;
+
+    /**
+     * The ELF file contains BE-8 code, suitable for execution on an ARM
+     * Architecture v6 processor. This flag must only be set on an executable file.
+     * {@value}
+     */
+    public static final int EF_ARM_BE8      = 0x00800000;
+
+    /**
+     * Legacy code (ABI version 4 and earlier) generated by gcc-arm-xxx might
+     * use these bits.
+     * {@value}
+     */
+    public static final int EF_ARM_GCCMASK  = 0x00400FFF;
+
+    /**
+     * Set in executable file headers (e_type = ET_EXEC or ET_DYN) to note that
+     * the executable file was built to conform to the hardware floating-point
+     * procedure-call standard.
+     * <p>
+     * Compatible with legacy (pre version 5) gcc use as EF_ARM_VFP_FLOAT.
+     * </p>
+     * <p>
+     * Note: This is not used (anymore)
+     * </p>
+     * {@value}
+     */
+    public static final int EF_ARM_ABI_FLOAT_HARD  = 0x00000400;
+
+    /**
+     * Set in executable file headers (e_type = ET_EXEC or ET_DYN) to note
+     * explicitly that the executable file was built to conform to the software
+     * floating-point procedure-call standard (the base standard). If both
+     * {@link #EF_ARM_ABI_FLOAT_HARD} and {@link #EF_ARM_ABI_FLOAT_SOFT} are clear,
+     * conformance to the base procedure-call standard is implied.
+     * <p>
+     * Compatible with legacy (pre version 5) gcc use as EF_ARM_SOFT_FLOAT.
+     * </p>
+     * <p>
+     * Note: This is not used (anymore)
+     * </p>
+     * {@value}
+     */
+    public static final int EF_ARM_ABI_FLOAT_SOFT  = 0x00000200;
+
+    /** Public access to the elf header part-1 (CPU/ABI independent read) */
+    public final ElfHeaderPart1 eh1;
+
+    /** Public access to the raw elf header part-2 (CPU/ABI dependent read) */
+    public final Ehdr_p2 raw;
+
+    /** Lower case CPUType name */
+    public final String cpuName;
+    public final CPUType cpuType;
+    public final ABIType abiType;
+
+    /** Public access to the {@link SectionHeader} */
+    public final SectionHeader[] sht;
+
+    /**
+     * Note: The input stream shall stay untouch to be able to read sections!
+     *
+     * @param in input stream of a binary file at position zero
+     * @return
+     * @throws IOException if reading from the given input stream fails or less then ELF Header size bytes
+     * @throws IllegalArgumentException if the given input stream does not represent an ELF Header
+     */
+    public static ElfHeaderPart2 read(final ElfHeaderPart1 eh1, final RandomAccessFile in) throws IOException, IllegalArgumentException {
+        return new ElfHeaderPart2(eh1, in);
+    }
+
+    /**
+     * @param buf ELF Header bytes
+     * @throws IllegalArgumentException if the given buffer does not represent an ELF Header
+     * @throws IOException
+     */
+    ElfHeaderPart2(final ElfHeaderPart1 eh1, final RandomAccessFile in) throws IllegalArgumentException, IOException {
+        this.eh1 = eh1;
+        //
+        // Part-2
+        //
+        {
+            final byte[] buf = new byte[Ehdr_p2.size(eh1.machDesc.ordinal())];
+            readBytes (in, buf, 0, buf.length);
+            final ByteBuffer eh2Bytes = ByteBuffer.wrap(buf, 0, buf.length);
+            raw = Ehdr_p2.create(eh1.machDesc.ordinal(), eh2Bytes);
+        }
+        sht = readSectionHeaderTable(in);
+
+        if( CPUFamily.ARM == eh1.cpuType.family && eh1.cpuType.is32Bit ) {
+            // AArch64, has no SHT_ARM_ATTRIBUTES or SHT_AARCH64_ATTRIBUTES SectionHeader defined in our builds!
+            String armCpuName = null;
+            String armCpuRawName = null;
+            boolean abiVFPArgsAcceptsVFPVariant = false;
+            final SectionHeader sh = getSectionHeader(SectionHeader.SHT_ARM_ATTRIBUTES);
+            if(ElfHeaderPart1.DEBUG) {
+                System.err.println("ELF-2: Got ARM Attribs Section Header: "+sh);
+            }
+            if( null != sh ) {
+                final SectionArmAttributes sArmAttrs = (SectionArmAttributes) sh.readSection(in);
+                if(ElfHeaderPart1.DEBUG) {
+                    System.err.println("ELF-2: Got ARM Attribs Section Block : "+sArmAttrs);
+                }
+                final SectionArmAttributes.Attribute cpuNameArgsAttr = sArmAttrs.get(SectionArmAttributes.Tag.CPU_name);
+                if( null != cpuNameArgsAttr && cpuNameArgsAttr.isNTBS() ) {
+                    armCpuName = cpuNameArgsAttr.getNTBS();
+                }
+                final SectionArmAttributes.Attribute cpuRawNameArgsAttr = sArmAttrs.get(SectionArmAttributes.Tag.CPU_raw_name);
+                if( null != cpuRawNameArgsAttr && cpuRawNameArgsAttr.isNTBS() ) {
+                    armCpuRawName = cpuRawNameArgsAttr.getNTBS();
+                }
+                final SectionArmAttributes.Attribute abiVFPArgsAttr = sArmAttrs.get(SectionArmAttributes.Tag.ABI_VFP_args);
+                if( null != abiVFPArgsAttr ) {
+                    abiVFPArgsAcceptsVFPVariant = SectionArmAttributes.abiVFPArgsAcceptsVFPVariant(abiVFPArgsAttr.getULEB128());
+                }
+            }
+            {
+                String _cpuName;
+                if( null != armCpuName && armCpuName.length() > 0 ) {
+                    _cpuName = armCpuName.toLowerCase().replace(' ', '-');
+                } else if( null != armCpuRawName && armCpuRawName.length() > 0 ) {
+                    _cpuName = armCpuRawName.toLowerCase().replace(' ', '-');
+                } else {
+                    _cpuName = eh1.cpuName;
+                }
+
+                // 1st-try: native name
+                CPUType _cpuType = queryCPUTypeSafe(_cpuName);
+                if( null == _cpuType ) {
+                    // 2nd-try: "arm-" + native name
+                    _cpuName = "arm-"+_cpuName;
+                    _cpuType = queryCPUTypeSafe(_cpuName);
+                    if( null == _cpuType ) {
+                        // finally: Use ELF-1
+                        _cpuName = eh1.cpuName;
+                        _cpuType = queryCPUTypeSafe(_cpuName);
+                        if( null == _cpuType ) {
+                            throw new InternalError("XXX: "+_cpuName+", "+eh1); // shall not happen
+                        }
+                    }
+                }
+                cpuName = _cpuName;
+                cpuType = _cpuType;
+                if(ElfHeaderPart1.DEBUG) {
+                    System.err.println("ELF-2: abiARM cpuName "+_cpuName+"[armCpuName "+armCpuName+", armCpuRawName "+armCpuRawName+"] -> "+cpuName+" -> "+cpuType+", abiVFPArgsAcceptsVFPVariant "+abiVFPArgsAcceptsVFPVariant);
+                }
+            }
+            if( cpuType.is32Bit ) { // always true, see above!
+                abiType = abiVFPArgsAcceptsVFPVariant ? ABIType.EABI_GNU_ARMHF : ABIType.EABI_GNU_ARMEL;
+            } else {
+                abiType = eh1.abiType;
+            }
+        } else {
+            cpuName = eh1.cpuName;
+            cpuType = eh1.cpuType;
+            abiType = eh1.abiType;
+        }
+        if(ElfHeaderPart1.DEBUG) {
+            System.err.println("ELF-2: cpuName "+cpuName+" -> "+cpuType+", "+abiType);
+        }
+    }
+    private static CPUType queryCPUTypeSafe(final String cpuName) {
+        CPUType res = null;
+        try {
+            res = CPUType.query(cpuName);
+        } catch (final Throwable t) {
+            if(ElfHeaderPart1.DEBUG) {
+                System.err.println("ELF-2: queryCPUTypeSafe("+cpuName+"): "+t.getMessage());
+            }
+        }
+        return res;
+    }
+
+    public final short getSize() { return raw.getE_ehsize(); }
+
+    /** Returns the processor-specific flags associated with the file. */
+    public final int getFlags() {
+        return raw.getE_flags();
+    }
+
+    /** Returns the ARM EABI version from {@link #getFlags() flags}, maybe 0 if not an ARM EABI. */
+    public byte getArmABI() {
+        return (byte) ( ( ( EF_ARM_ABIMASK & raw.getE_flags() ) >> EF_ARM_ABISHIFT ) & 0xff );
+    }
+
+    /** Returns the ARM EABI legacy GCC {@link #getFlags() flags}, maybe 0 if not an ARM EABI or not having legacy GCC flags. */
+    public int getArmLegacyGCCFlags() {
+        final int f = raw.getE_flags();
+        return 0 != ( EF_ARM_ABIMASK & f ) ? ( EF_ARM_GCCMASK & f ) : 0;
+    }
+
+    /**
+     * Returns the ARM EABI float mode from {@link #getFlags() flags},
+     * i.e. 1 for {@link #EF_ARM_ABI_FLOAT_SOFT}, 2 for {@link #EF_ARM_ABI_FLOAT_HARD}
+     * or 0 for none.
+     * <p>
+     * Note: This is not used (anymore)
+     * </p>
+     */
+    public byte getArmFloatMode() {
+        final int f = raw.getE_flags();
+        if( 0 != ( EF_ARM_ABIMASK & f ) ) {
+            if( ( EF_ARM_ABI_FLOAT_HARD & f ) != 0 ) {
+                return 2;
+            }
+            if( ( EF_ARM_ABI_FLOAT_SOFT & f ) != 0 ) {
+                return 1;
+            }
+        }
+        return 0;
+    }
+
+    /** Returns the 1st occurence of matching SectionHeader {@link SectionHeader#getType() type}, or null if not exists. */
+    public final SectionHeader getSectionHeader(final int type) {
+        for(int i=0; i<sht.length; i++) {
+            final SectionHeader sh = sht[i];
+            if( sh.getType() == type ) {
+                return sh;
+            }
+        }
+        return null;
+    }
+
+    /** Returns the 1st occurence of matching SectionHeader {@link SectionHeader#getName() name}, or null if not exists. */
+    public final SectionHeader getSectionHeader(final String name) {
+        for(int i=0; i<sht.length; i++) {
+            final SectionHeader sh = sht[i];
+            if( sh.getName().equals(name) ) {
+                return sh;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public final String toString() {
+        final int armABI = getArmABI();
+        final String armFlagsS;
+        if( 0 != armABI ) {
+            armFlagsS=", arm[abi "+armABI+", lGCC "+getArmLegacyGCCFlags()+", float "+getArmFloatMode()+"]";
+        } else {
+            armFlagsS="";
+        }
+        return "ELF-2["+cpuType+", "+abiType+", flags["+toHexString(getFlags())+armFlagsS+"], sh-num "+sht.length+"]";
+    }
+
+    final SectionHeader[] readSectionHeaderTable(final RandomAccessFile in) throws IOException, IllegalArgumentException {
+        // positioning
+        {
+            final long off = raw.getE_shoff(); // absolute offset
+            if( 0 == off ) {
+                return new SectionHeader[0];
+            }
+            seek(in, off);
+        }
+        final SectionHeader[] sht;
+        final int strndx = raw.getE_shstrndx();
+        final int size = raw.getE_shentsize();
+        final int num;
+        int i;
+        if( 0 == raw.getE_shnum() ) {
+            // Read 1st table 1st and use it's sh_size
+            final byte[] buf0 = new byte[size];
+            readBytes(in, buf0, 0, size);
+            final SectionHeader sh0 = new SectionHeader(this, buf0, 0, size, 0);
+            num = (int) sh0.raw.getSh_size();
+            if( 0 >= num ) {
+                throw new IllegalArgumentException("EHdr sh_num == 0 and 1st SHdr size == 0");
+            }
+            sht = new SectionHeader[num];
+            sht[0] = sh0;
+            i=1;
+        } else {
+            num = raw.getE_shnum();
+            sht = new SectionHeader[num];
+            i=0;
+        }
+        for(; i<num; i++) {
+            final byte[] buf = new byte[size];
+            readBytes(in, buf, 0, size);
+            sht[i] = new SectionHeader(this, buf, 0, size, i);
+        }
+        if( SectionHeader.SHN_UNDEF != strndx ) {
+            // has section name string table
+            if( shortToInt(SectionHeader.SHN_LORESERVE) <= strndx ) {
+                throw new InternalError("TODO strndx: "+SectionHeader.SHN_LORESERVE+" < "+strndx);
+            }
+            final SectionHeader strShdr = sht[strndx];
+            if( SectionHeader.SHT_STRTAB != strShdr.getType() ) {
+                throw new IllegalArgumentException("Ref. string Shdr["+strndx+"] is of type "+strShdr.raw.getSh_type());
+            }
+            final Section strS = strShdr.readSection(in);
+            for(i=0; i<num; i++) {
+                sht[i].initName(strS, sht[i].raw.getSh_name());
+            }
+        }
+
+        return sht;
+    }
+}
diff --git a/src/java/jogamp/common/os/elf/IOUtils.java b/src/java/jogamp/common/os/elf/IOUtils.java
index 62b47db..454a325 100644
--- a/src/java/jogamp/common/os/elf/IOUtils.java
+++ b/src/java/jogamp/common/os/elf/IOUtils.java
@@ -30,7 +30,6 @@ package jogamp.common.os.elf;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 
-import com.jogamp.common.os.Platform;
 import com.jogamp.common.util.Bitstream;
 
 class IOUtils {
@@ -61,17 +60,12 @@ class IOUtils {
         in.seek(newPos);
     }
 
-    static int readUInt32(final byte[] in, final int offset) {
-        final int v = Bitstream.uint32LongToInt(Bitstream.readUInt32(!Platform.isLittleEndian(), in, offset));
+    static int readUInt32(final boolean isBigEndian, final byte[] in, final int offset) {
+        final int v = Bitstream.uint32LongToInt(Bitstream.readUInt32(isBigEndian, in, offset));
         if( 0 > v ) {
             throw new IllegalArgumentException("Read uint32 value "+toHexString(v)+" > int32-max "+toHexString(MAX_INT_VALUE));
         }
         return v;
-        /** Need to fix endian for below path ..
-        checkBounds(in, offset, 4);
-        final byte[] uint = new byte[] { 0, 0, 0, 0, in[offset+0],  in[offset+1],  in[offset+2],  in[offset+3] };
-        final ByteBuffer b = ByteBuffer.wrap(uint, 0, 8).order(ByteOrder.nativeOrder());
-        return b.asLongBuffer().get(0); */
     }
 
     /**
diff --git a/src/java/jogamp/common/os/elf/SectionArmAttributes.java b/src/java/jogamp/common/os/elf/SectionArmAttributes.java
index 91e8c31..e6d9257 100644
--- a/src/java/jogamp/common/os/elf/SectionArmAttributes.java
+++ b/src/java/jogamp/common/os/elf/SectionArmAttributes.java
@@ -1,3 +1,30 @@
+/**
+ * Copyright 2013 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
 package jogamp.common.os.elf;
 
 import static jogamp.common.os.elf.IOUtils.toHexString;
@@ -172,7 +199,7 @@ public class SectionArmAttributes extends Section {
 
     SectionArmAttributes(final SectionHeader sh, final byte[] data, final int offset, final int length) throws IndexOutOfBoundsException, IllegalArgumentException {
         super(sh, data, offset, length);
-        this.vendorAttributesList = parse(data, offset, length);
+        this.vendorAttributesList = parse(sh, data, offset, length);
     }
 
     @Override
@@ -208,6 +235,7 @@ public class SectionArmAttributes extends Section {
     }
 
     /**
+     * @param sh TODO
      * @param in byte source buffer to parse
      * @param offset offset within byte source buffer to start parsing
      * @param remaining remaining numbers of bytes to parse beginning w/ <code>sb_off</code>,
@@ -215,7 +243,7 @@ public class SectionArmAttributes extends Section {
      * @throws IndexOutOfBoundsException if <code>offset + remaining > sb.length</code>.
      * @throws IllegalArgumentException if section parsing failed, i.e. incompatible version or data.
      */
-    static List<VendorAttributes> parse(final byte[] in, final int offset, final int remaining) throws IndexOutOfBoundsException, IllegalArgumentException {
+    static List<VendorAttributes> parse(final SectionHeader sh, final byte[] in, final int offset, final int remaining) throws IndexOutOfBoundsException, IllegalArgumentException {
         Bitstream.checkBounds(in, offset, remaining);
         int i = offset;
         if( FORMAT_VERSION_A != in[ i ] ) {
@@ -224,10 +252,11 @@ public class SectionArmAttributes extends Section {
         i++;
 
         final List<VendorAttributes> vendorAttributesList = new ArrayList<VendorAttributes>();
+        final boolean isBigEndian = sh.eh2.eh1.isBigEndian();
 
         while(i < remaining) {
             final int i_pre = i;
-            final int secLen = readUInt32(in, i); /* total section size: 4 + string + content, i.e. offset to next section */
+            final int secLen = readUInt32(isBigEndian, in, i); /* total section size: 4 + string + content, i.e. offset to next section */
             i+=4;
 
             final String vendor;
@@ -241,7 +270,7 @@ public class SectionArmAttributes extends Section {
 
             while(i < secLen) {
                 final int[] i_post = new int[] { 0 };
-                parseSub(in, i, secLen - i, i_post, attributes);
+                parseSub(isBigEndian, in, i, secLen - i, i_post, attributes);
                 i = i_post[0];
             }
 
@@ -261,6 +290,7 @@ public class SectionArmAttributes extends Section {
     }
 
     /**
+     * @param isBigEndian TODO
      * @param in byte source buffer to parse
      * @param offset offset within byte source buffer to start parsing
      * @param remaining remaining numbers of bytes to parse beginning w/ <code>sb_off</code>,
@@ -268,7 +298,10 @@ public class SectionArmAttributes extends Section {
      * @throws IndexOutOfBoundsException if <code>offset + remaining > sb.length</code>.
      * @throws IllegalArgumentException if section parsing failed, i.e. incompatible version or data.
      */
-    static void parseSub(final byte[] in, final int offset, final int remaining, final int[] offset_post, final List<Attribute> attributes) throws IndexOutOfBoundsException, IllegalArgumentException {
+    private static void parseSub(final boolean isBigEndian, final byte[] in, final int offset, final int remaining,
+                                 final int[] offset_post, final List<Attribute> attributes)
+            throws IndexOutOfBoundsException, IllegalArgumentException
+    {
         Bitstream.checkBounds(in, offset, remaining);
 
         // Starts w/ sub-section Tag
@@ -283,7 +316,7 @@ public class SectionArmAttributes extends Section {
             case File:
             case Section:
             case Symbol:
-                subSecLen = readUInt32(in, i);
+                subSecLen = readUInt32(isBigEndian, in, i);
                 i+=4;
                 break;
             default:
diff --git a/src/java/jogamp/common/os/elf/SectionHeader.java b/src/java/jogamp/common/os/elf/SectionHeader.java
index 20a40a5..533c04b 100644
--- a/src/java/jogamp/common/os/elf/SectionHeader.java
+++ b/src/java/jogamp/common/os/elf/SectionHeader.java
@@ -133,6 +133,12 @@ public class SectionHeader {
      * {@value}
      */
     public static final int SHT_ARM_ATTRIBUTES     = 0x70000003;
+
+    /**
+     * {@value}. FIXME: Same as {@link #SHT_ARM_ATTRIBUTES}, ok?
+     */
+    public static final int SHT_AARCH64_ATTRIBUTES = 0x70000003;
+
     /**
      * {@value}
      */
@@ -171,24 +177,28 @@ public class SectionHeader {
      */
     public static final short SHN_HIRESERVE = (short)0xffff;
 
+    /** Public access to the elf header */
+    public final ElfHeaderPart2 eh2;
+
     /** Public access to the raw elf section header */
-    public final Shdr d;
+    public final Shdr raw;
 
     private final int idx;
     private String name;
 
-    SectionHeader(final byte[] buf, final int offset, final int length, final int sectionIdx) {
-        this( ByteBuffer.wrap(buf, 0, buf.length), sectionIdx );
+    SectionHeader(final ElfHeaderPart2 eh, final byte[] buf, final int offset, final int length, final int sectionIdx) {
+        this( eh, ByteBuffer.wrap(buf, 0, buf.length), sectionIdx );
     }
-    SectionHeader(final java.nio.ByteBuffer buf, final int idx) {
-        d = Shdr.create(buf);
+    SectionHeader(final ElfHeaderPart2 eh, final java.nio.ByteBuffer buf, final int idx) {
+        this.eh2 = eh;
+        this.raw = Shdr.create(eh.eh1.machDesc.ordinal(), buf);
         this.idx = idx;
-        name = null;
+        this.name = null;
     }
 
     @Override
     public String toString() {
-        return "SectionHeader[idx "+idx+", name "+name+", type "+toHexString(getType())+", link "+d.getSh_link()+", info "+toHexString(d.getSh_info())+", flags "+toHexString(getFlags())+"]";
+        return "SectionHeader[idx "+idx+", name "+name+", type "+toHexString(getType())+", link "+raw.getSh_link()+", info "+toHexString(raw.getSh_info())+", flags "+toHexString(getFlags())+"]";
     }
 
     /**
@@ -206,17 +216,17 @@ public class SectionHeader {
 
     /** Returns the type of this section. */
     public int getType() {
-        return d.getSh_type();
+        return raw.getSh_type();
     }
 
     /** Returns the flags of this section. */
     public long getFlags() {
-        return d.getSh_flags();
+        return raw.getSh_flags();
     }
 
     /** Returns the size of this section. */
     public long getSize() {
-        return d.getSh_size();
+        return raw.getSh_size();
     }
 
     /** Returns this section name, maybe <code>null</code> if not read. */
@@ -232,9 +242,9 @@ public class SectionHeader {
      * @throws IllegalArgumentException if section offset or size mismatch including size > {@link Integer#MAX_VALUE}
      */
     public Section readSection(final RandomAccessFile in) throws IOException, IllegalArgumentException {
-        final int s_size = long2Int(d.getSh_size());
+        final int s_size = long2Int(raw.getSh_size());
         if( 0 == s_size || 0 > s_size ) {
-            throw new IllegalArgumentException("Shdr["+idx+"] has invalid int size: "+d.getSh_size()+" -> "+s_size);
+            throw new IllegalArgumentException("Shdr["+idx+"] has invalid int size: "+raw.getSh_size()+" -> "+s_size);
         }
         final byte[] s_buf = new byte[s_size];
         return readSectionImpl(in, s_buf, 0, s_size);
@@ -252,9 +262,9 @@ public class SectionHeader {
      * @throws IllegalArgumentException if requested read length is > section size
      */
     public Section readSection(final RandomAccessFile in, final byte[] b, final int b_off, final int r_len) throws IOException, IllegalArgumentException {
-        final int s_size = long2Int(d.getSh_size());
+        final int s_size = long2Int(raw.getSh_size());
         if( 0 == s_size || 0 > s_size ) {
-            throw new IllegalArgumentException("Shdr["+idx+"] has invalid int size: "+d.getSh_size()+" -> "+s_size);
+            throw new IllegalArgumentException("Shdr["+idx+"] has invalid int size: "+raw.getSh_size()+" -> "+s_size);
         }
         if( r_len > s_size ) {
             throw new IllegalArgumentException("Shdr["+idx+"] has only "+s_size+" bytes, while read request is of "+r_len+" bytes");
@@ -263,7 +273,7 @@ public class SectionHeader {
     }
 
     Section readSectionImpl(final RandomAccessFile in, final byte[] b, final int b_off, final int r_len) throws IOException, IllegalArgumentException {
-        final long s_off = d.getSh_offset();
+        final long s_off = raw.getSh_offset();
         seek(in, s_off);
         readBytes(in, b, b_off, r_len);
         if( SectionHeader.SHT_ARM_ATTRIBUTES == getType() ) {
diff --git a/src/java/jogamp/common/os/elf/Shdr.java b/src/java/jogamp/common/os/elf/Shdr.java
index d31aec2..18f50b2 100644
--- a/src/java/jogamp/common/os/elf/Shdr.java
+++ b/src/java/jogamp/common/os/elf/Shdr.java
@@ -1,137 +1,176 @@
-/* !---- DO NOT EDIT: This file autogenerated by com/jogamp/gluegen/JavaEmitter.java on Thu Feb 07 17:54:18 CET 2013 ----! */
+/* !---- DO NOT EDIT: This file autogenerated by com/jogamp/gluegen/JavaEmitter.java on Sun Feb 01 23:28:47 CET 2015 ----! */
 
 
 package jogamp.common.os.elf;
 
+import java.nio.*;
+
+import com.jogamp.gluegen.runtime.*;
+import com.jogamp.common.os.*;
 import com.jogamp.common.nio.*;
-import jogamp.common.os.MachineDescriptionRuntime;
+import jogamp.common.os.MachineDataInfoRuntime;
 
 
 public class Shdr {
 
   StructAccessor accessor;
 
-  private static final int mdIdx = MachineDescriptionRuntime.getStatic().ordinal();
-
-  private static final int[] Shdr_size = new int[] { 40 /* ARMle_EABI */, 40 /* X86_32_UNIX */, 64 /* X86_64_UNIX */, 40 /* X86_32_MACOS */, 40 /* X86_32_WINDOWS */, 64 /* X86_64_WINDOWS */  };
-  private static final int[] sh_name_offset = new int[] { 0 /* ARMle_EABI */, 0 /* X86_32_UNIX */, 0 /* X86_64_UNIX */, 0 /* X86_32_MACOS */, 0 /* X86_32_WINDOWS */, 0 /* X86_64_WINDOWS */ };
-  private static final int[] sh_type_offset = new int[] { 4 /* ARMle_EABI */, 4 /* X86_32_UNIX */, 4 /* X86_64_UNIX */, 4 /* X86_32_MACOS */, 4 /* X86_32_WINDOWS */, 4 /* X86_64_WINDOWS */ };
-  private static final int[] sh_flags_offset = new int[] { 8 /* ARMle_EABI */, 8 /* X86_32_UNIX */, 8 /* X86_64_UNIX */, 8 /* X86_32_MACOS */, 8 /* X86_32_WINDOWS */, 8 /* X86_64_WINDOWS */ };
-  private static final int[] sh_addr_offset = new int[] { 12 /* ARMle_EABI */, 12 /* X86_32_UNIX */, 16 /* X86_64_UNIX */, 12 /* X86_32_MACOS */, 12 /* X86_32_WINDOWS */, 16 /* X86_64_WINDOWS */ };
-  private static final int[] sh_offset_offset = new int[] { 16 /* ARMle_EABI */, 16 /* X86_32_UNIX */, 24 /* X86_64_UNIX */, 16 /* X86_32_MACOS */, 16 /* X86_32_WINDOWS */, 24 /* X86_64_WINDOWS */ };
-  private static final int[] sh_size_offset = new int[] { 20 /* ARMle_EABI */, 20 /* X86_32_UNIX */, 32 /* X86_64_UNIX */, 20 /* X86_32_MACOS */, 20 /* X86_32_WINDOWS */, 32 /* X86_64_WINDOWS */ };
-  private static final int[] sh_link_offset = new int[] { 24 /* ARMle_EABI */, 24 /* X86_32_UNIX */, 40 /* X86_64_UNIX */, 24 /* X86_32_MACOS */, 24 /* X86_32_WINDOWS */, 40 /* X86_64_WINDOWS */ };
-  private static final int[] sh_info_offset = new int[] { 28 /* ARMle_EABI */, 28 /* X86_32_UNIX */, 44 /* X86_64_UNIX */, 28 /* X86_32_MACOS */, 28 /* X86_32_WINDOWS */, 44 /* X86_64_WINDOWS */ };
-  private static final int[] sh_addralign_offset = new int[] { 32 /* ARMle_EABI */, 32 /* X86_32_UNIX */, 48 /* X86_64_UNIX */, 32 /* X86_32_MACOS */, 32 /* X86_32_WINDOWS */, 48 /* X86_64_WINDOWS */ };
-  private static final int[] sh_entsize_offset = new int[] { 36 /* ARMle_EABI */, 36 /* X86_32_UNIX */, 56 /* X86_64_UNIX */, 36 /* X86_32_MACOS */, 36 /* X86_32_WINDOWS */, 56 /* X86_64_WINDOWS */ };
-
-  public static int size() {
-    return Shdr_size[mdIdx];
-  }
-
-  public static Shdr create() {
-    return create(Buffers.newDirectByteBuffer(size()));
-  }
-
-  public static Shdr create(final java.nio.ByteBuffer buf) {
-      return new Shdr(buf);
-  }
-
-  Shdr(final java.nio.ByteBuffer buf) {
-    accessor = new StructAccessor(buf);
-  }
+  private final int mdIdx;
+  private final MachineDataInfo md;
+
+  private static final int[] Shdr_size = new int[] { 40 /* ARM_MIPS_32 */, 40 /* X86_32_UNIX */, 40 /* X86_32_MACOS */, 40 /* PPC_32_UNIX */, 40 /* SPARC_32_SUNOS */, 40 /* X86_32_WINDOWS */, 64 /* LP64_UNIX */, 64 /* X86_64_WINDOWS */  };
+  private static final int[] sh_name_offset = new int[] { 0 /* ARM_MIPS_32 */, 0 /* X86_32_UNIX */, 0 /* X86_32_MACOS */, 0 /* PPC_32_UNIX */, 0 /* SPARC_32_SUNOS */, 0 /* X86_32_WINDOWS */, 0 /* LP64_UNIX */, 0 /* X86_64_WINDOWS */ };
+//private static final int[] sh_name_size = new int[] { 4 /* ARM_MIPS_32 */, 4 /* X86_32_UNIX */, 4 /* X86_32_MACOS */, 4 /* PPC_32_UNIX */, 4 /* SPARC_32_SUNOS */, 4 /* X86_32_WINDOWS */, 4 /* LP64_UNIX */, 4 /* X86_64_WINDOWS */  };
+  private static final int[] sh_type_offset = new int[] { 4 /* ARM_MIPS_32 */, 4 /* X86_32_UNIX */, 4 /* X86_32_MACOS */, 4 /* PPC_32_UNIX */, 4 /* SPARC_32_SUNOS */, 4 /* X86_32_WINDOWS */, 4 /* LP64_UNIX */, 4 /* X86_64_WINDOWS */ };
+//private static final int[] sh_type_size = new int[] { 4 /* ARM_MIPS_32 */, 4 /* X86_32_UNIX */, 4 /* X86_32_MACOS */, 4 /* PPC_32_UNIX */, 4 /* SPARC_32_SUNOS */, 4 /* X86_32_WINDOWS */, 4 /* LP64_UNIX */, 4 /* X86_64_WINDOWS */  };
+  private static final int[] sh_flags_offset = new int[] { 8 /* ARM_MIPS_32 */, 8 /* X86_32_UNIX */, 8 /* X86_32_MACOS */, 8 /* PPC_32_UNIX */, 8 /* SPARC_32_SUNOS */, 8 /* X86_32_WINDOWS */, 8 /* LP64_UNIX */, 8 /* X86_64_WINDOWS */ };
+//private static final int[] sh_flags_size = new int[] { 4 /* ARM_MIPS_32 */, 4 /* X86_32_UNIX */, 4 /* X86_32_MACOS */, 4 /* PPC_32_UNIX */, 4 /* SPARC_32_SUNOS */, 4 /* X86_32_WINDOWS */, 8 /* LP64_UNIX */, 8 /* X86_64_WINDOWS */  };
+  private static final int[] sh_addr_offset = new int[] { 12 /* ARM_MIPS_32 */, 12 /* X86_32_UNIX */, 12 /* X86_32_MACOS */, 12 /* PPC_32_UNIX */, 12 /* SPARC_32_SUNOS */, 12 /* X86_32_WINDOWS */, 16 /* LP64_UNIX */, 16 /* X86_64_WINDOWS */ };
+//private static final int[] sh_addr_size = new int[] { 4 /* ARM_MIPS_32 */, 4 /* X86_32_UNIX */, 4 /* X86_32_MACOS */, 4 /* PPC_32_UNIX */, 4 /* SPARC_32_SUNOS */, 4 /* X86_32_WINDOWS */, 8 /* LP64_UNIX */, 8 /* X86_64_WINDOWS */  };
+  private static final int[] sh_offset_offset = new int[] { 16 /* ARM_MIPS_32 */, 16 /* X86_32_UNIX */, 16 /* X86_32_MACOS */, 16 /* PPC_32_UNIX */, 16 /* SPARC_32_SUNOS */, 16 /* X86_32_WINDOWS */, 24 /* LP64_UNIX */, 24 /* X86_64_WINDOWS */ };
+//private static final int[] sh_offset_size = new int[] { 4 /* ARM_MIPS_32 */, 4 /* X86_32_UNIX */, 4 /* X86_32_MACOS */, 4 /* PPC_32_UNIX */, 4 /* SPARC_32_SUNOS */, 4 /* X86_32_WINDOWS */, 8 /* LP64_UNIX */, 8 /* X86_64_WINDOWS */  };
+  private static final int[] sh_size_offset = new int[] { 20 /* ARM_MIPS_32 */, 20 /* X86_32_UNIX */, 20 /* X86_32_MACOS */, 20 /* PPC_32_UNIX */, 20 /* SPARC_32_SUNOS */, 20 /* X86_32_WINDOWS */, 32 /* LP64_UNIX */, 32 /* X86_64_WINDOWS */ };
+//private static final int[] sh_size_size = new int[] { 4 /* ARM_MIPS_32 */, 4 /* X86_32_UNIX */, 4 /* X86_32_MACOS */, 4 /* PPC_32_UNIX */, 4 /* SPARC_32_SUNOS */, 4 /* X86_32_WINDOWS */, 8 /* LP64_UNIX */, 8 /* X86_64_WINDOWS */  };
+  private static final int[] sh_link_offset = new int[] { 24 /* ARM_MIPS_32 */, 24 /* X86_32_UNIX */, 24 /* X86_32_MACOS */, 24 /* PPC_32_UNIX */, 24 /* SPARC_32_SUNOS */, 24 /* X86_32_WINDOWS */, 40 /* LP64_UNIX */, 40 /* X86_64_WINDOWS */ };
+//private static final int[] sh_link_size = new int[] { 4 /* ARM_MIPS_32 */, 4 /* X86_32_UNIX */, 4 /* X86_32_MACOS */, 4 /* PPC_32_UNIX */, 4 /* SPARC_32_SUNOS */, 4 /* X86_32_WINDOWS */, 4 /* LP64_UNIX */, 4 /* X86_64_WINDOWS */  };
+  private static final int[] sh_info_offset = new int[] { 28 /* ARM_MIPS_32 */, 28 /* X86_32_UNIX */, 28 /* X86_32_MACOS */, 28 /* PPC_32_UNIX */, 28 /* SPARC_32_SUNOS */, 28 /* X86_32_WINDOWS */, 44 /* LP64_UNIX */, 44 /* X86_64_WINDOWS */ };
+//private static final int[] sh_info_size = new int[] { 4 /* ARM_MIPS_32 */, 4 /* X86_32_UNIX */, 4 /* X86_32_MACOS */, 4 /* PPC_32_UNIX */, 4 /* SPARC_32_SUNOS */, 4 /* X86_32_WINDOWS */, 4 /* LP64_UNIX */, 4 /* X86_64_WINDOWS */  };
+  private static final int[] sh_addralign_offset = new int[] { 32 /* ARM_MIPS_32 */, 32 /* X86_32_UNIX */, 32 /* X86_32_MACOS */, 32 /* PPC_32_UNIX */, 32 /* SPARC_32_SUNOS */, 32 /* X86_32_WINDOWS */, 48 /* LP64_UNIX */, 48 /* X86_64_WINDOWS */ };
+//private static final int[] sh_addralign_size = new int[] { 4 /* ARM_MIPS_32 */, 4 /* X86_32_UNIX */, 4 /* X86_32_MACOS */, 4 /* PPC_32_UNIX */, 4 /* SPARC_32_SUNOS */, 4 /* X86_32_WINDOWS */, 8 /* LP64_UNIX */, 8 /* X86_64_WINDOWS */  };
+  private static final int[] sh_entsize_offset = new int[] { 36 /* ARM_MIPS_32 */, 36 /* X86_32_UNIX */, 36 /* X86_32_MACOS */, 36 /* PPC_32_UNIX */, 36 /* SPARC_32_SUNOS */, 36 /* X86_32_WINDOWS */, 56 /* LP64_UNIX */, 56 /* X86_64_WINDOWS */ };
+//private static final int[] sh_entsize_size = new int[] { 4 /* ARM_MIPS_32 */, 4 /* X86_32_UNIX */, 4 /* X86_32_MACOS */, 4 /* PPC_32_UNIX */, 4 /* SPARC_32_SUNOS */, 4 /* X86_32_WINDOWS */, 8 /* LP64_UNIX */, 8 /* X86_64_WINDOWS */  };
 
   public java.nio.ByteBuffer getBuffer() {
     return accessor.getBuffer();
   }
 
-  public Shdr setSh_name(final int val) {
+  /** Setter for native field: CType['uint32_t', size [fixed true, lnx64 4], [int]] */
+  public Shdr setSh_name(int val) {
     accessor.setIntAt(sh_name_offset[mdIdx], val);
     return this;
   }
 
+  /** Getter for native field: CType['uint32_t', size [fixed true, lnx64 4], [int]] */
   public int getSh_name() {
     return accessor.getIntAt(sh_name_offset[mdIdx]);
   }
 
-  public Shdr setSh_type(final int val) {
+  /** Setter for native field: CType['uint32_t', size [fixed true, lnx64 4], [int]] */
+  public Shdr setSh_type(int val) {
     accessor.setIntAt(sh_type_offset[mdIdx], val);
     return this;
   }
 
+  /** Getter for native field: CType['uint32_t', size [fixed true, lnx64 4], [int]] */
   public int getSh_type() {
     return accessor.getIntAt(sh_type_offset[mdIdx]);
   }
 
-  public Shdr setSh_flags(final long val) {
-    accessor.setLongAt(sh_flags_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md.longSizeInBytes());
+  /** Setter for native field: CType['ElfN_size' (typedef), size [fixed false, lnx64 8], [int]] */
+  public Shdr setSh_flags(long val) {
+    accessor.setLongAt(sh_flags_offset[mdIdx], val, md.longSizeInBytes());
     return this;
   }
 
+  /** Getter for native field: CType['ElfN_size' (typedef), size [fixed false, lnx64 8], [int]] */
   public long getSh_flags() {
-    return accessor.getLongAt(sh_flags_offset[mdIdx], MachineDescriptionRuntime.getStatic().md.longSizeInBytes());
+    return accessor.getLongAt(sh_flags_offset[mdIdx], md.longSizeInBytes());
   }
 
-  public Shdr setSh_addr(final long val) {
-    accessor.setLongAt(sh_addr_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md.longSizeInBytes());
+  /** Setter for native field: CType['ElfN_Addr' (typedef), size [fixed false, lnx64 8], [int]] */
+  public Shdr setSh_addr(long val) {
+    accessor.setLongAt(sh_addr_offset[mdIdx], val, md.longSizeInBytes());
     return this;
   }
 
+  /** Getter for native field: CType['ElfN_Addr' (typedef), size [fixed false, lnx64 8], [int]] */
   public long getSh_addr() {
-    return accessor.getLongAt(sh_addr_offset[mdIdx], MachineDescriptionRuntime.getStatic().md.longSizeInBytes());
+    return accessor.getLongAt(sh_addr_offset[mdIdx], md.longSizeInBytes());
   }
 
-  public Shdr setSh_offset(final long val) {
-    accessor.setLongAt(sh_offset_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md.longSizeInBytes());
+  /** Setter for native field: CType['ElfN_Off' (typedef), size [fixed false, lnx64 8], [int]] */
+  public Shdr setSh_offset(long val) {
+    accessor.setLongAt(sh_offset_offset[mdIdx], val, md.longSizeInBytes());
     return this;
   }
 
+  /** Getter for native field: CType['ElfN_Off' (typedef), size [fixed false, lnx64 8], [int]] */
   public long getSh_offset() {
-    return accessor.getLongAt(sh_offset_offset[mdIdx], MachineDescriptionRuntime.getStatic().md.longSizeInBytes());
+    return accessor.getLongAt(sh_offset_offset[mdIdx], md.longSizeInBytes());
   }
 
-  public Shdr setSh_size(final long val) {
-    accessor.setLongAt(sh_size_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md.longSizeInBytes());
+  /** Setter for native field: CType['ElfN_size' (typedef), size [fixed false, lnx64 8], [int]] */
+  public Shdr setSh_size(long val) {
+    accessor.setLongAt(sh_size_offset[mdIdx], val, md.longSizeInBytes());
     return this;
   }
 
+  /** Getter for native field: CType['ElfN_size' (typedef), size [fixed false, lnx64 8], [int]] */
   public long getSh_size() {
-    return accessor.getLongAt(sh_size_offset[mdIdx], MachineDescriptionRuntime.getStatic().md.longSizeInBytes());
+    return accessor.getLongAt(sh_size_offset[mdIdx], md.longSizeInBytes());
   }
 
-  public Shdr setSh_link(final int val) {
+  /** Setter for native field: CType['uint32_t', size [fixed true, lnx64 4], [int]] */
+  public Shdr setSh_link(int val) {
     accessor.setIntAt(sh_link_offset[mdIdx], val);
     return this;
   }
 
+  /** Getter for native field: CType['uint32_t', size [fixed true, lnx64 4], [int]] */
   public int getSh_link() {
     return accessor.getIntAt(sh_link_offset[mdIdx]);
   }
 
-  public Shdr setSh_info(final int val) {
+  /** Setter for native field: CType['uint32_t', size [fixed true, lnx64 4], [int]] */
+  public Shdr setSh_info(int val) {
     accessor.setIntAt(sh_info_offset[mdIdx], val);
     return this;
   }
 
+  /** Getter for native field: CType['uint32_t', size [fixed true, lnx64 4], [int]] */
   public int getSh_info() {
     return accessor.getIntAt(sh_info_offset[mdIdx]);
   }
 
-  public Shdr setSh_addralign(final long val) {
-    accessor.setLongAt(sh_addralign_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md.longSizeInBytes());
+  /** Setter for native field: CType['ElfN_size' (typedef), size [fixed false, lnx64 8], [int]] */
+  public Shdr setSh_addralign(long val) {
+    accessor.setLongAt(sh_addralign_offset[mdIdx], val, md.longSizeInBytes());
     return this;
   }
 
+  /** Getter for native field: CType['ElfN_size' (typedef), size [fixed false, lnx64 8], [int]] */
   public long getSh_addralign() {
-    return accessor.getLongAt(sh_addralign_offset[mdIdx], MachineDescriptionRuntime.getStatic().md.longSizeInBytes());
+    return accessor.getLongAt(sh_addralign_offset[mdIdx], md.longSizeInBytes());
   }
 
-  public Shdr setSh_entsize(final long val) {
-    accessor.setLongAt(sh_entsize_offset[mdIdx], val, MachineDescriptionRuntime.getStatic().md.longSizeInBytes());
+  /** Setter for native field: CType['ElfN_size' (typedef), size [fixed false, lnx64 8], [int]] */
+  public Shdr setSh_entsize(long val) {
+    accessor.setLongAt(sh_entsize_offset[mdIdx], val, md.longSizeInBytes());
     return this;
   }
 
+  /** Getter for native field: CType['ElfN_size' (typedef), size [fixed false, lnx64 8], [int]] */
   public long getSh_entsize() {
-    return accessor.getLongAt(sh_entsize_offset[mdIdx], MachineDescriptionRuntime.getStatic().md.longSizeInBytes());
+    return accessor.getLongAt(sh_entsize_offset[mdIdx], md.longSizeInBytes());
+  }
+
+  // --- Begin CustomJavaCode .cfg declarations
+  public static int size(final int mdIdx) {
+      return Shdr_size[mdIdx];
+  }
+
+  public static Shdr create(final int mdIdx) {
+      return create(mdIdx, Buffers.newDirectByteBuffer(size(mdIdx)));
+  }
+
+  public static Shdr create(final int mdIdx, final java.nio.ByteBuffer buf) {
+      return new Shdr(mdIdx, buf);
+  }
+
+  Shdr(final int mdIdx, final java.nio.ByteBuffer buf) {
+      this.mdIdx = mdIdx;
+      this.md = MachineDataInfo.StaticConfig.values()[mdIdx].md;
+      this.accessor = new StructAccessor(buf);
   }
+  // ---- End CustomJavaCode .cfg declarations
 }
diff --git a/src/junit/com/jogamp/common/net/AssetURLConnectionBase.java b/src/junit/com/jogamp/common/net/AssetURLConnectionBase.java
index e16003f..e4ff717 100644
--- a/src/junit/com/jogamp/common/net/AssetURLConnectionBase.java
+++ b/src/junit/com/jogamp/common/net/AssetURLConnectionBase.java
@@ -10,9 +10,9 @@ import org.junit.Assert;
 
 import com.jogamp.common.os.AndroidVersion;
 import com.jogamp.common.util.IOUtil;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
-public abstract class AssetURLConnectionBase extends JunitTracer {
+public abstract class AssetURLConnectionBase extends SingletonJunitCase {
 
     /** In gluegen-rt.jar */
     protected static final String test_asset_rt_url      = "asset:gluegen/info.txt";
@@ -23,15 +23,15 @@ public abstract class AssetURLConnectionBase extends JunitTracer {
     /** In gluegen.test.jar */
     protected static final String test_asset_test1_url   = "asset:gluegen-test/info.txt";
     protected static final String test_asset_test1_entry = "gluegen-test/info.txt";
-    protected static final String test_asset_test2_rel   = "data/AssetURLConnectionTest.txt";
+    protected static final Uri.Encoded test_asset_test2_rel   = Uri.Encoded.cast("data/AssetURLConnectionTest.txt");
     protected static final String test_asset_test2a_url  = "asset:com/jogamp/common/net/data/AssetURLConnectionTest.txt";
     protected static final String test_asset_test2b_url  = "asset:/com/jogamp/common/net/data/AssetURLConnectionTest.txt";
     protected static final String test_asset_test2_entry = "com/jogamp/common/net/data/AssetURLConnectionTest.txt";
-    protected static final String test_asset_test3_rel   = "RelativeData.txt";
+    protected static final Uri.Encoded test_asset_test3_rel   = Uri.Encoded.cast("RelativeData.txt");
     protected static final String test_asset_test3a_url  = "asset:com/jogamp/common/net/data/RelativeData.txt";
     protected static final String test_asset_test3b_url  = "asset:/com/jogamp/common/net/data/RelativeData.txt";
     protected static final String test_asset_test3_entry = "com/jogamp/common/net/data/RelativeData.txt";
-    protected static final String test_asset_test4_rel   = "../data2/RelativeData2.txt";
+    protected static final Uri.Encoded test_asset_test4_rel   = Uri.Encoded.cast("../data2/RelativeData2.txt");
     protected static final String test_asset_test4a_url  = "asset:com/jogamp/common/net/data2/RelativeData2.txt";
     protected static final String test_asset_test4b_url  = "asset:/com/jogamp/common/net/data2/RelativeData2.txt";
     protected static final String test_asset_test4_entry = "com/jogamp/common/net/data2/RelativeData2.txt";
diff --git a/src/junit/com/jogamp/common/net/AssetURLConnectionRegisteredTest.java b/src/junit/com/jogamp/common/net/AssetURLConnectionRegisteredTest.java
index 7648990..cb6200d 100644
--- a/src/junit/com/jogamp/common/net/AssetURLConnectionRegisteredTest.java
+++ b/src/junit/com/jogamp/common/net/AssetURLConnectionRegisteredTest.java
@@ -1,7 +1,6 @@
 package com.jogamp.common.net;
 
 import java.io.IOException;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLConnection;
@@ -48,12 +47,12 @@ public class AssetURLConnectionRegisteredTest extends AssetURLConnectionBase {
         Assert.assertEquals(test_asset_test2a_url, urlConn0.getURL().toExternalForm());
         testAssetConnection(urlConn0, test_asset_test2_entry);
 
-        final URI uri1 = IOUtil.getRelativeOf(urlConn0.getURL().toURI(), test_asset_test3_rel);
+        final Uri uri1 = Uri.valueOf(urlConn0.getURL()).getRelativeOf(test_asset_test3_rel);
         Assert.assertNotNull(uri1);
         Assert.assertEquals(test_asset_test3a_url, uri1.toString());
         testAssetConnection(uri1.toURL().openConnection(), test_asset_test3_entry);
 
-        final URI uri2 = IOUtil.getRelativeOf(urlConn0.getURL().toURI(), test_asset_test4_rel);
+        final Uri uri2 = Uri.valueOf(urlConn0.getURL()).getRelativeOf(test_asset_test4_rel);
         Assert.assertNotNull(uri2);
         Assert.assertEquals(test_asset_test4a_url, uri2.toString());
         testAssetConnection(uri2.toURL().openConnection(), test_asset_test4_entry);
@@ -66,12 +65,12 @@ public class AssetURLConnectionRegisteredTest extends AssetURLConnectionBase {
         Assert.assertEquals(test_asset_test2b_url, urlConn0.getURL().toExternalForm());
         testAssetConnection(urlConn0, test_asset_test2_entry);
 
-        final URI uri1 = IOUtil.getRelativeOf(urlConn0.getURL().toURI(), test_asset_test3_rel);
+        final Uri uri1 = Uri.valueOf(urlConn0.getURL()).getRelativeOf(test_asset_test3_rel);
         Assert.assertNotNull(uri1);
         Assert.assertEquals(test_asset_test3b_url, uri1.toString());
         testAssetConnection(uri1.toURL().openConnection(), test_asset_test3_entry);
 
-        final URI uri2 = IOUtil.getRelativeOf(urlConn0.getURL().toURI(), test_asset_test4_rel);
+        final Uri uri2 = Uri.valueOf(urlConn0.getURL()).getRelativeOf(test_asset_test4_rel);
         Assert.assertNotNull(uri2);
         Assert.assertEquals(test_asset_test4b_url, uri2.toString());
         testAssetConnection(uri2.toURL().openConnection(), test_asset_test4_entry);
diff --git a/src/junit/com/jogamp/common/net/AssetURLConnectionUnregisteredTest.java b/src/junit/com/jogamp/common/net/AssetURLConnectionUnregisteredTest.java
index 5fbde49..5167abb 100644
--- a/src/junit/com/jogamp/common/net/AssetURLConnectionUnregisteredTest.java
+++ b/src/junit/com/jogamp/common/net/AssetURLConnectionUnregisteredTest.java
@@ -1,7 +1,6 @@
 package com.jogamp.common.net;
 
 import java.io.IOException;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLConnection;
@@ -39,14 +38,14 @@ public class AssetURLConnectionUnregisteredTest extends AssetURLConnectionBase {
 
     @Test
     public void assetUnregisteredIOUtilGetResourceRel0_RT() throws IOException, URISyntaxException {
-        final URLConnection urlConn0 = IOUtil.getResource(this.getClass(), test_asset_test2_rel);
+        final URLConnection urlConn0 = IOUtil.getResource(this.getClass(), test_asset_test2_rel.get());
         testAssetConnection(urlConn0, test_asset_test2_entry);
 
-        final URI uri1 = IOUtil.getRelativeOf(urlConn0.getURL().toURI(), test_asset_test3_rel);
+        final Uri uri1 = Uri.valueOf(urlConn0.getURL()).getRelativeOf(test_asset_test3_rel);
         Assert.assertNotNull(uri1); // JARFile URL ..
         testAssetConnection(uri1.toURL().openConnection(), test_asset_test3_entry);
 
-        final URI uri2 = IOUtil.getRelativeOf(urlConn0.getURL().toURI(), test_asset_test4_rel);
+        final Uri uri2 = Uri.valueOf(urlConn0.getURL()).getRelativeOf(test_asset_test4_rel);
         Assert.assertNotNull(uri2);
         testAssetConnection(uri2.toURL().openConnection(), test_asset_test4_entry);
     }
diff --git a/src/junit/com/jogamp/common/net/TestUri01.java b/src/junit/com/jogamp/common/net/TestUri01.java
new file mode 100644
index 0000000..1173610
--- /dev/null
+++ b/src/junit/com/jogamp/common/net/TestUri01.java
@@ -0,0 +1,433 @@
+package com.jogamp.common.net;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.jogamp.common.net.URIDumpUtil;
+import com.jogamp.common.util.IOUtil;
+import com.jogamp.junit.util.SingletonJunitCase;
+
+import org.junit.FixMethodOrder;
+import org.junit.runners.MethodSorters;
+
+ at FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class TestUri01 extends SingletonJunitCase {
+
+    @Test
+    public void test00BasicCoding() throws IOException, URISyntaxException {
+        final String string = "Hallo Welt öä";
+        System.err.println("sp1 "+string);
+        final File file = new File(string);
+        System.err.println("file "+file);
+        System.err.println("file.path.dec "+file.getPath());
+        System.err.println("file.path.abs "+file.getAbsolutePath());
+        System.err.println("file.path.can "+file.getCanonicalPath());
+        final Uri uri0 = Uri.valueOf(file);
+        URIDumpUtil.showUri(uri0);
+        URIDumpUtil.showReencodedURIOfUri(uri0);
+
+        boolean ok = true;
+        {
+            final String s2 = IOUtil.slashify(file.getAbsolutePath(), true /* startWithSlash */, file.isDirectory() /* endWithSlash */);
+            System.err.println("uri2.slashify: "+s2);
+            final Uri uri1 = Uri.create(Uri.FILE_SCHEME, null, s2, null);
+            final boolean equalEncoded= uri0.getEncoded().equals(uri1.getEncoded());
+            final boolean equalPath = uri0.path.decode().equals(uri1.path.decode());
+            final boolean equalASCII= uri0.toASCIIString().equals(uri1.toASCIIString().get());
+            System.err.println("uri2.enc   : "+uri1.getEncoded()+" - "+(equalEncoded?"OK":"ERROR"));
+            System.err.println("uri2.pathD : "+uri1.path.decode()+" - "+(equalPath?"OK":"ERROR"));
+            System.err.println("uri2.asciiE: "+uri1.toASCIIString()+" - "+(equalASCII?"OK":"ERROR"));
+            ok = equalEncoded && equalPath && equalASCII && ok;
+        }
+        {
+            final String s2 = "/"+string;
+            System.err.println("uri3.orig: "+s2);
+            final Uri uri1 = Uri.create(Uri.FILE_SCHEME, s2, null);
+            final String rString = "file:/Hallo%20Welt%20öä";
+            final String rPath = s2;
+            final String rASCII = "file:/Hallo%20Welt%20%C3%B6%C3%A4";
+            final boolean equalEncoded = rString.equals(uri1.toString());
+            final boolean equalPath = rPath.equals(uri1.path.decode());
+            final boolean equalASCII= rASCII.equals(uri1.toASCIIString().get());
+            System.err.println("uri3.enc   : "+uri1.toString()+" - "+(equalEncoded?"OK":"ERROR"));
+            System.err.println("uri3.pathD : "+uri1.path.decode()+" - "+(equalPath?"OK":"ERROR"));
+            System.err.println("uri3.asciiE: "+uri1.toASCIIString()+" - "+(equalASCII?"OK":"ERROR"));
+            ok = equalEncoded && equalPath && equalASCII && ok;
+        }
+        {
+            final String s2 = "//lala.org/"+string;
+            System.err.println("uri4.orig: "+s2);
+            final Uri uri1 = Uri.create(Uri.HTTP_SCHEME, s2, null);
+            final String rString = "http://lala.org/Hallo%20Welt%20öä";
+            final String rPath = "/"+string;
+            final String rASCII = "http://lala.org/Hallo%20Welt%20%C3%B6%C3%A4";
+            final boolean equalString= rString.equals(uri1.toString());
+            final boolean equalPath = rPath.equals(uri1.path.decode());
+            final boolean equalASCII= rASCII.equals(uri1.toASCIIString().get());
+            System.err.println("uri4.enc   : "+uri1.toString()+" - "+(equalString?"OK":"ERROR"));
+            System.err.println("uri4.pathD : "+uri1.path.decode()+" - "+(equalPath?"OK":"ERROR"));
+            System.err.println("uri4.asciiE: "+uri1.toASCIIString()+" - "+(equalASCII?"OK":"ERROR"));
+            ok = equalString && equalPath && equalASCII && ok;
+        }
+        Assert.assertTrue("One or more errors occured see stderr above", ok);
+    }
+
+    @Test
+    public void test02URIEscapeSpecialChars() throws IOException, URISyntaxException {
+        {
+            final String vanilla = "XXX ! # $ & ' ( ) * + , / : ; = ? @ [ ]";
+            final Uri.Encoded escaped = Uri.Encoded.cast("XXX%20!%20%23%20%24%20%26%20%27%20%28%20%29%20%2A%20%2B%20%2C%20/%20%3A%20%3B%20%3D%20%3F%20%40%20%5B%20%5D");
+            System.err.println("vanilla "+vanilla);
+            final Uri.Encoded esc1 = new Uri.Encoded(vanilla, Uri.PATH_LEGAL);
+            System.err.println("esc1 "+esc1);
+            Assert.assertEquals(escaped, esc1);
+
+            final String invEsc1 = esc1.decode();
+            System.err.println("inv(esc1) "+invEsc1);
+            Assert.assertEquals(vanilla, invEsc1);
+        }
+        {
+            final String vanilla = "/XXX R!# R$&'()*+,/:;=?z at y[x]";
+            final Uri.Encoded escaped = Uri.Encoded.cast("/XXX%20R!%23%20R%24%26%27%28%29%2A%2B%2C/%3A%3B%3D%3Fz%40y%5Bx%5D");
+            System.err.println("vanilla "+vanilla);
+            final Uri.Encoded esc1 = new Uri.Encoded(vanilla, Uri.PATH_LEGAL);
+            System.err.println("esc1 "+esc1);
+            Assert.assertEquals(escaped, esc1);
+
+            final String invEsc1 = esc1.decode();
+            System.err.println("inv(esc1) "+invEsc1);
+            Assert.assertEquals(vanilla, invEsc1);
+        }
+        {
+            // Bug 908:    $ ^ ~ # [ ]
+            final String vanilla = "/XXX $ ^ ~ # [ ]";
+            showDump0x(vanilla);
+        }
+        {
+            // Windows invalid File characters: * ? " < > |
+            final String vanilla = "/XXX ! & ' ( ) + , / ; = @ [ ]";
+            showDump0x(vanilla);
+        }
+    }
+    @Test
+    public void test03URIEscapeCommonChars() throws IOException, URISyntaxException {
+        {
+            final String vanilla = "/XXX \"%-.<>\\^_`{|}~";
+            final Uri.Encoded escaped = Uri.Encoded.cast("/XXX%20%22%25-.%3C%3E%5C%5E_%60%7B%7C%7D~");
+            System.err.println("vanilla "+vanilla);
+            final Uri.Encoded esc1 = new Uri.Encoded(vanilla, Uri.PATH_LEGAL);
+            System.err.println("esc1 "+esc1);
+            Assert.assertEquals(escaped, esc1);
+
+            final String invEsc1 = esc1.decode();
+            System.err.println("inv(esc1) "+invEsc1);
+            Assert.assertEquals(vanilla, invEsc1);
+            showDump0x(vanilla);
+        }
+    }
+    private static void showDump0x(final String string) throws IOException, URISyntaxException {
+        final File file = new File(string);
+        System.err.println("file "+file);
+        System.err.println("file.path.dec "+file.getPath());
+        System.err.println("file.path.abs "+file.getAbsolutePath());
+        System.err.println("file.path.can "+file.getCanonicalPath());
+
+        System.err.println("File-path -> Uri:");
+        final Uri uri0 = Uri.valueOfFilepath(string);
+        URIDumpUtil.showUri(uri0);
+
+        System.err.println("Uri -> File:");
+        final Uri uri2 = Uri.valueOf(file);
+        URIDumpUtil.showUri(uri2);
+
+        System.err.println("Uri -> URI:");
+        final URI uri3 = uri2.toURI();
+        URIDumpUtil.showURI(uri3);
+
+        System.err.println("URI -> Uri (keep encoding):");
+        final Uri uri4 = Uri.valueOf(uri3);
+        URIDumpUtil.showUri(uri4);
+
+        System.err.println("URI -> Uri (re-encode):");
+        final Uri uri5 = Uri.valueOf(uri3);
+        URIDumpUtil.showUri(uri5);
+    }
+
+    @Test
+    public void test04EqualsAndHashCode() throws IOException, URISyntaxException {
+        {
+            final Uri uri0 = Uri.cast("http://localhost/test01.html#tag01");
+            final Uri uri1 = Uri.create("http", null, "localhost", -1, "/test01.html", null, "tag01");
+            final Uri uri2 = Uri.create("http", "localhost", "/test01.html", "tag01");
+
+            Assert.assertEquals(uri0, uri1);
+            Assert.assertEquals(uri0.hashCode(), uri1.hashCode());
+
+            Assert.assertEquals(uri0, uri2);
+            Assert.assertEquals(uri0.hashCode(), uri2.hashCode());
+
+            Assert.assertEquals(uri1, uri2);
+            Assert.assertEquals(uri1.hashCode(), uri2.hashCode());
+
+            final Uri uriA = Uri.create("http", null, "localhost", -1, "/test02.html", null, "tag01");
+            final Uri uriB = Uri.create("http", null, "localhost", -1, "/test01.html", null, "tag02");
+            final Uri uriC = Uri.create("http", null, "lalalhost", -1, "/test01.html", null, "tag01");
+            final Uri uriD = Uri.create("sftp", null, "localhost", -1, "/test01.html", null, "tag01");
+
+            Assert.assertNotEquals(uri1, uriA);
+            Assert.assertNotEquals(uri1, uriB);
+            Assert.assertNotEquals(uri1, uriC);
+            Assert.assertNotEquals(uri1, uriD);
+        }
+        {   // 3 [scheme:][//[user-info@]host[:port]]path[?query][#fragment]
+            final Uri uri0 = Uri.cast("http://user@localhost:80/test01.html?test=01&test=02#tag01");
+            final Uri uri1 = Uri.create("http", "user", "localhost", 80, "/test01.html", "test=01&test=02", "tag01");
+
+            Assert.assertEquals(uri0, uri1);
+            Assert.assertEquals(uri0.hashCode(), uri1.hashCode());
+
+            final Uri uriA = Uri.cast("http://user@localhost:80/test01.html?test=01&test=02#tag02");
+            final Uri uriB = Uri.cast("http://user@localhost:80/test01.html?test=01&test=03#tag01");
+            final Uri uriC = Uri.cast("http://user@localhost:80/test04.html?test=01&test=02#tag01");
+            final Uri uriD = Uri.cast("http://user@localhost:88/test01.html?test=01&test=02#tag01");
+            final Uri uriE = Uri.cast("http://user@lalalhost:80/test01.html?test=01&test=02#tag01");
+            final Uri uriF = Uri.cast("http://test@localhost:80/test01.html?test=01&test=02#tag01");
+            final Uri uriG = Uri.cast("sftp://user@localhost:80/test01.html?test=01&test=02#tag01");
+
+            Assert.assertNotEquals(uri1, uriA);
+            Assert.assertNotEquals(uri1, uriB);
+            Assert.assertNotEquals(uri1, uriC);
+            Assert.assertNotEquals(uri1, uriD);
+            Assert.assertNotEquals(uri1, uriE);
+            Assert.assertNotEquals(uri1, uriF);
+            Assert.assertNotEquals(uri1, uriG);
+        }
+    }
+
+    @Test
+    public void test05Contained() throws IOException, URISyntaxException {
+        {
+            final Uri input = Uri.cast("http://localhost/test01.html#tag01");
+            final Uri contained = input.getContainedUri();
+            Assert.assertNull(contained);
+        }
+        {
+            final Uri input     = Uri.cast("jar:http://localhost/test01.jar!/com/jogamp/Lala.class#tag01");
+            final Uri expected  = Uri.cast("http://localhost/test01.jar#tag01");
+            final Uri contained = input.getContainedUri();
+            URIDumpUtil.showUri(input);
+            URIDumpUtil.showUri(contained);
+            Assert.assertEquals(expected, contained);
+            Assert.assertEquals(expected.hashCode(), contained.hashCode());
+        }
+        {
+            final Uri input     = Uri.cast("jar:file://localhost/test01.jar!/");
+            final Uri expected  = Uri.cast("file://localhost/test01.jar");
+            final Uri contained = input.getContainedUri();
+            URIDumpUtil.showUri(input);
+            URIDumpUtil.showUri(contained);
+            Assert.assertEquals(expected, contained);
+            Assert.assertEquals(expected.hashCode(), contained.hashCode());
+        }
+        {
+            final Uri input     = Uri.cast("sftp:http://localhost/test01.jar?lala=01#tag01");
+            final Uri expected  = Uri.cast("http://localhost/test01.jar?lala=01#tag01");
+            final Uri contained = input.getContainedUri();
+            URIDumpUtil.showUri(input);
+            URIDumpUtil.showUri(contained);
+            Assert.assertEquals(expected, contained);
+            Assert.assertEquals(expected.hashCode(), contained.hashCode());
+        }
+    }
+
+    @Test
+    public void test08NormalizedHierarchy() throws IOException, URISyntaxException {
+        {
+            final Uri input    = Uri.cast("http://localhost/dummy/../");
+            final Uri expected = Uri.cast("http://localhost/");
+            URIDumpUtil.showUri(input);
+            final Uri normal = input.getNormalized();
+            Assert.assertEquals(expected, normal);
+        }
+        {
+            final Uri input    = Uri.cast("http://localhost/test/dummy/../text.txt");
+            final Uri expected = Uri.cast("http://localhost/test/text.txt");
+            URIDumpUtil.showUri(input);
+            final Uri normal = input.getNormalized();
+            Assert.assertEquals(expected, normal);
+        }
+        {
+            final Uri input    = Uri.cast("http://localhost/test/dummy/../text.txt?lala=01&lili=02#frag01");
+            final Uri expected = Uri.cast("http://localhost/test/text.txt?lala=01&lili=02#frag01");
+            URIDumpUtil.showUri(input);
+            final Uri normal = input.getNormalized();
+            Assert.assertEquals(expected, normal);
+        }
+    }
+
+    @Test
+    public void test09NormalizedOpaque() throws IOException, URISyntaxException {
+        {
+            final Uri input    = Uri.cast("jar:http://localhost/dummy/../abc.jar!/");
+            final Uri expected = Uri.cast("jar:http://localhost/abc.jar!/");
+            URIDumpUtil.showUri(input);
+            final Uri normal = input.getNormalized();
+            Assert.assertEquals(expected, normal);
+        }
+        {
+            final Uri input    = Uri.cast("jar:http://localhost/test/dummy/../abc.jar!/");
+            final Uri expected = Uri.cast("jar:http://localhost/test/abc.jar!/");
+            URIDumpUtil.showUri(input);
+            final Uri normal = input.getNormalized();
+            Assert.assertEquals(expected, normal);
+        }
+        {
+            final Uri input    = Uri.cast("jar:http://localhost/test/dummy/../abc.jar!/a/b/C.class");
+            final Uri expected = Uri.cast("jar:http://localhost/test/abc.jar!/a/b/C.class");
+            URIDumpUtil.showUri(input);
+            final Uri normal = input.getNormalized();
+            Assert.assertEquals(expected, normal);
+        }
+        {
+            final Uri input    = Uri.cast("jar:http://localhost/test/dummy/../abc.jar!/a/b/C.class?lala=01&lili=02#frag01");
+            final Uri expected = Uri.cast("jar:http://localhost/test/abc.jar!/a/b/C.class?lala=01&lili=02#frag01");
+            URIDumpUtil.showUri(input);
+            final Uri normal = input.getNormalized();
+            Assert.assertEquals(expected, normal);
+        }
+    }
+
+    @Test
+    public void test10ParentAndDirHierarchy() throws IOException, URISyntaxException {
+        {
+            final Uri input = Uri.cast("http://localhost/");
+            URIDumpUtil.showUri(input);
+            final Uri directory = input.getDirectory();
+            Assert.assertEquals(input, directory);
+            final Uri parent = input.getParent();
+            Assert.assertNull(parent);
+        }
+        {
+            final Uri input    = Uri.cast("http://localhost/dummy/../test/");
+            final Uri expectedD = Uri.cast("http://localhost/test/");
+            final Uri expectedP = Uri.cast("http://localhost/");
+            URIDumpUtil.showUri(input);
+            final Uri directory = input.getDirectory();
+            Assert.assertEquals(expectedD, directory);
+            final Uri parent = input.getParent();
+            Assert.assertEquals(expectedP, parent);
+        }
+        {
+            final Uri input    = Uri.cast("http://localhost/dummy/../test/dummy/../");
+            final Uri expectedD = Uri.cast("http://localhost/test/");
+            final Uri expectedP = Uri.cast("http://localhost/");
+            URIDumpUtil.showUri(input);
+            final Uri directory = input.getDirectory();
+            Assert.assertEquals(expectedD, directory);
+            final Uri parent = input.getParent();
+            Assert.assertEquals(expectedP, parent);
+        }
+        {
+            final Uri input     = Uri.cast("http://localhost/dir/test01.jar?lala=01#frag01");
+            final Uri expParen1 = Uri.cast("http://localhost/dir/?lala=01#frag01");
+            final Uri expFolde1 = expParen1;
+            final Uri expParen2 = Uri.cast("http://localhost/?lala=01#frag01");
+            final Uri expFolde2 = expParen1; // is folder already
+            final Uri expParen3 = null;
+            final Uri expFolde3 = expParen2;
+            Assert.assertNotEquals(input, expParen1);
+            Assert.assertNotEquals(expParen1, expParen2);
+            Assert.assertNotEquals(expParen1, expParen3);
+            URIDumpUtil.showUri(input);
+
+            final Uri parent1 = input.getParent();
+            Assert.assertEquals(expParen1, parent1);
+            Assert.assertEquals(expParen1.hashCode(), parent1.hashCode());
+            final Uri folder1 = input.getDirectory();
+            Assert.assertEquals(expFolde1, folder1);
+
+            final Uri parent2 = parent1.getParent();
+            Assert.assertEquals(expParen2, parent2);
+            Assert.assertEquals(expParen2.hashCode(), parent2.hashCode());
+            final Uri folder2 = parent1.getDirectory();
+            Assert.assertEquals(expFolde2, folder2);
+
+            final Uri parent3 = parent2.getParent();
+            Assert.assertEquals(expParen3, parent3); // NULL!
+            final Uri folder3 = parent2.getDirectory();
+            Assert.assertEquals(expFolde3, folder3); // NULL!
+        }
+    }
+
+    @Test
+    public void test11ParentAndDirOpaque() throws IOException, URISyntaxException {
+        {
+            final Uri input = Uri.cast("jar:http://localhost/test.jar!/");
+            URIDumpUtil.showUri(input);
+            final Uri directory = input.getDirectory();
+            Assert.assertEquals(input, directory);
+            final Uri parent = input.getParent();
+            Assert.assertNull(parent);
+        }
+        {
+            final Uri input    = Uri.cast("jar:http://localhost/dummy/../test/test.jar!/");
+            final Uri expectedD = Uri.cast("jar:http://localhost/test/test.jar!/");
+            final Uri expectedP = null;
+            URIDumpUtil.showUri(input);
+            final Uri directory = input.getDirectory();
+            Assert.assertEquals(expectedD, directory);
+            final Uri parent = input.getParent();
+            Assert.assertEquals(expectedP, parent);
+        }
+        {
+            final Uri input    = Uri.cast("jar:http://localhost/dummy/../test/dummy/../test.jar!/a/b/C.class");
+            final Uri expectedD = Uri.cast("jar:http://localhost/test/test.jar!/a/b/");
+            final Uri expectedP = Uri.cast("jar:http://localhost/test/test.jar!/a/b/");
+            URIDumpUtil.showUri(input);
+            final Uri directory = input.getDirectory();
+            Assert.assertEquals(expectedD, directory);
+            final Uri parent = input.getParent();
+            Assert.assertEquals(expectedP, parent);
+        }
+        {
+            final Uri input     = Uri.cast("jar:http://localhost/test01.jar!/com/Lala.class?lala=01#frag01");
+            final Uri expParen1 = Uri.cast("jar:http://localhost/test01.jar!/com/?lala=01#frag01");
+            final Uri expFolde1 = expParen1;
+            final Uri expParen2 = Uri.cast("jar:http://localhost/test01.jar!/?lala=01#frag01");
+            final Uri expFolde2 = expParen1; // is folder already
+            final Uri expParen3 = null;
+            final Uri expFolde3 = expParen2; // is folder already
+            Assert.assertNotEquals(input, expParen1);
+            Assert.assertNotEquals(expParen1, expParen2);
+            Assert.assertNotEquals(expParen1, expParen3);
+            URIDumpUtil.showUri(input);
+
+            final Uri parent1 = input.getParent();
+            Assert.assertEquals(expParen1, parent1);
+            Assert.assertEquals(expParen1.hashCode(), parent1.hashCode());
+            final Uri folder1 = input.getDirectory();
+            Assert.assertEquals(expFolde1, folder1);
+
+            final Uri parent2 = parent1.getParent();
+            Assert.assertEquals(expParen2, parent2);
+            Assert.assertEquals(expParen2.hashCode(), parent2.hashCode());
+            final Uri folder2 = parent1.getDirectory();
+            Assert.assertEquals(expFolde2, folder2);
+
+            final Uri parent3 = parent2.getParent();
+            Assert.assertEquals(expParen3, parent3); // NULL
+            final Uri folder3 = parent2.getDirectory();
+            Assert.assertEquals(expFolde3, folder3);
+        }
+    }
+
+    public static void main(final String args[]) throws IOException {
+        final String tstname = TestUri01.class.getName();
+        org.junit.runner.JUnitCore.main(tstname);
+    }
+}
diff --git a/src/junit/com/jogamp/common/util/TestIOUtilURICompose.java b/src/junit/com/jogamp/common/net/TestUri02Composing.java
similarity index 58%
rename from src/junit/com/jogamp/common/util/TestIOUtilURICompose.java
rename to src/junit/com/jogamp/common/net/TestUri02Composing.java
index 3369afd..51a5cc6 100644
--- a/src/junit/com/jogamp/common/util/TestIOUtilURICompose.java
+++ b/src/junit/com/jogamp/common/net/TestUri02Composing.java
@@ -1,22 +1,34 @@
-package com.jogamp.common.util;
+package com.jogamp.common.net;
 
 import java.io.IOException;
 import java.net.MalformedURLException;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 
 import org.junit.Assert;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
-import com.jogamp.common.util.IOUtil;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestIOUtilURICompose extends JunitTracer {
+public class TestUri02Composing extends SingletonJunitCase {
+
+    @BeforeClass
+    public static void assetRegistration() throws Exception {
+        try {
+            System.err.println("******* Asset URL Stream Handler Registration: PRE");
+            Assert.assertTrue("GenericURLStreamHandlerFactory.register() failed", AssetURLContext.registerHandler(AssetURLConnectionRegisteredTest.class.getClassLoader()));
+            Assert.assertNotNull(AssetURLContext.getRegisteredHandler());
+            System.err.println("******* Asset URL Stream Handler Registration: POST");
+        } catch (final Exception e) {
+            setTestSupported(false);
+            throw e;
+        }
+    }
 
     @Test
     public void test01URLCompositioning() throws IOException, URISyntaxException {
@@ -28,10 +40,10 @@ public class TestIOUtilURICompose extends JunitTracer {
         testURNCompositioning("http://domain.com/web1/index.html?lala=23&lili=24#anchor");
         testURNCompositioning("http://domain.com:1234/web1/index.html?lala=23&lili=24#anchor");
 
-        final URI file1URI = new URI("asset:jar:file:/web1/file1.jar!/rootDir/file1.txt");
+        final Uri file1URI = Uri.cast("asset:jar:file:/web1/file1.jar!/rootDir/file1.txt");
         testURICompositioning(file1URI);
-        testURICompositioning(file1URI, new URI("asset:jar:file:/web1/file1.jar!/rootDir/./file1.txt"));
-        testURICompositioning(file1URI, new URI("asset:jar:file:/web1/file1.jar!/rootDir/dummyParent/../file1.txt"));
+        testUriCompositioning(file1URI, Uri.cast("asset:jar:file:/web1/file1.jar!/rootDir/./file1.txt"));
+        testUriCompositioning(file1URI, Uri.cast("asset:jar:file:/web1/file1.jar!/rootDir/dummyParent/../file1.txt"));
 
         final URL file1URL = new URL("asset:jar:file:/web1/file1.jar!/rootDir/file1.txt");
         testURLCompositioning(file1URL);
@@ -40,20 +52,16 @@ public class TestIOUtilURICompose extends JunitTracer {
     }
 
     static void testURNCompositioning(final String urn) throws MalformedURLException, URISyntaxException {
-        testURICompositioning( new URI(urn) );
+        testURICompositioning( Uri.cast(urn) );
         testURLCompositioning( new URL(urn) );
     }
 
-    static void testURICompositioning(final URI uri) throws MalformedURLException, URISyntaxException {
-        testURICompositioning(uri, uri);
+    static void testURICompositioning(final Uri uri) throws MalformedURLException, URISyntaxException {
+        testUriCompositioning(uri, uri);
     }
-    static void testURICompositioning(final URI refURI, final URI uri1) throws MalformedURLException, URISyntaxException {
-        final String scheme = uri1.getScheme();
-        final String ssp = uri1.getRawSchemeSpecificPart();
-        final String fragment = uri1.getRawFragment();
-
-        System.err.println("scheme <"+scheme+">, ssp <"+ssp+">, fragment <"+fragment+">");
-        final URI uri2 = IOUtil.compose(scheme, ssp, null, fragment);
+    static void testUriCompositioning(final Uri refURI, final Uri uri1) throws MalformedURLException, URISyntaxException {
+        System.err.println("scheme <"+uri1.scheme+">, ssp <"+uri1.schemeSpecificPart+">, fragment <"+uri1.fragment+">");
+        final Uri uri2 = uri1.getRelativeOf(null);
 
         System.err.println("URL-equals: "+refURI.equals(uri2));
         System.err.println("URL-ref   : <"+refURI+">");
@@ -66,13 +74,9 @@ public class TestIOUtilURICompose extends JunitTracer {
         testURLCompositioning(url, url);
     }
     static void testURLCompositioning(final URL refURL, final URL url1) throws MalformedURLException, URISyntaxException {
-        final URI uri1 = url1.toURI();
-        final String scheme = uri1.getScheme();
-        final String ssp = uri1.getRawSchemeSpecificPart();
-        final String fragment = uri1.getRawFragment();
-
-        System.err.println("scheme <"+scheme+">, ssp <"+ssp+">, fragment <"+fragment+">");
-        final URI uri2 = IOUtil.compose(scheme, ssp, null, fragment);
+        final Uri uri1 = Uri.valueOf(url1);
+        System.err.println("scheme <"+uri1.scheme+">, ssp <"+uri1.schemeSpecificPart+">, fragment <"+uri1.fragment+">");
+        final Uri uri2 = uri1.getRelativeOf(null);
 
         System.err.println("URL-equals(1): "+refURL.toURI().equals(uri2));
         System.err.println("URL-equals(2): "+refURL.equals(uri2.toURL()));
@@ -80,13 +84,13 @@ public class TestIOUtilURICompose extends JunitTracer {
         System.err.println("URL-ref   : <"+refURL+">");
         System.err.println("URL-orig  : <"+url1+">");
         System.err.println("URL-comp  : <"+uri2+">");
-        Assert.assertEquals(refURL.toURI(), uri2);
+        Assert.assertEquals(Uri.valueOf(refURL), uri2);
         Assert.assertEquals(refURL, uri2.toURL());
         Assert.assertTrue(refURL.sameFile(uri2.toURL()));
     }
 
     public static void main(final String args[]) throws IOException {
-        final String tstname = TestIOUtilURICompose.class.getName();
+        final String tstname = TestUri02Composing.class.getName();
         org.junit.runner.JUnitCore.main(tstname);
     }
 }
diff --git a/src/junit/com/jogamp/common/net/TestUri03Resolving.java b/src/junit/com/jogamp/common/net/TestUri03Resolving.java
new file mode 100644
index 0000000..1b0c839
--- /dev/null
+++ b/src/junit/com/jogamp/common/net/TestUri03Resolving.java
@@ -0,0 +1,430 @@
+package com.jogamp.common.net;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+
+import jogamp.common.os.PlatformPropsImpl;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.jogamp.common.net.Uri;
+import com.jogamp.common.os.Platform;
+import com.jogamp.junit.util.SingletonJunitCase;
+
+import org.junit.FixMethodOrder;
+import org.junit.runners.MethodSorters;
+
+ at FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class TestUri03Resolving extends SingletonJunitCase {
+
+    // Bug 908, issues w/ windows file path char: $ ^ ~ # [ ]
+
+    private static final String[][] uriHttpSArray = new String[][] {
+        new String[] {"http://localhost/gluegen/build-x86_64/gluegen-rt.jar"},
+
+        new String[] {"http://localhost/gluegen/"+'\u0394'+"/gluegen-rt.jar"},
+
+        new String[] {"http://localhost/gluegen/build-x86_64%20lala/gluegen-rt.jar"},
+
+        new String[] {"http://localhost/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar"},
+
+        new String[] {"jar:http://localhost/gluegen/build-x86_64/gluegen-rt.jar!/"},
+
+        new String[] {"jar:http://localhost/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/"},
+
+        new String[] {"jar:http://localhost/gluegen/build-x86_64/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
+
+        new String[] {"jar:http://localhost/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
+
+        new String[] {"jar:http://localhost/gluegen/R%23/gluegen-rt.jar!/"},
+
+        new String[] {"jar:http://localhost/gluegen/A%24/B%5E/C~/D%23/E%5B/F%5D/gluegen-rt.jar!/"},
+
+        new String[] {"jar:http://localhost/gluegen/%24/%5E/~/%23/%5B/%5D/gluegen-rt.jar!/"},
+
+        new String[] {"jar:http://localhost/gluegen/"+'\u0394'+"/gluegen-rt.jar!/"},
+    };
+
+    private static final String[][] uriFileSArrayUnix = new String[][] {
+        new String[] {"file:/gluegen/build-x86_64/gluegen-rt.jar"},
+
+        new String[] {"file:/gluegen/"+'\u0394'+"/gluegen-rt.jar"},
+
+        new String[] {"file:/gluegen/build-x86_64%20lala/gluegen-rt.jar"},
+
+        new String[] {"file:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar"},
+
+        new String[] {"jar:file:/gluegen/build-x86_64/gluegen-rt.jar!/"},
+
+        new String[] {"jar:file:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/"},
+
+        new String[] {"jar:file:/gluegen/build-x86_64/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
+
+        new String[] {"jar:file:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
+
+        new String[] {"jar:file://filehost/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
+
+        new String[] {"jar:file:/gluegen/R%23/gluegen-rt.jar!/"},
+
+        new String[] {"jar:file:/gluegen/A%24/B%5E/C~/D%23/E%5B/F%5D/gluegen-rt.jar!/"},
+
+        new String[] {"jar:file:/gluegen/%24/%5E/~/%23/%5B/%5D/gluegen-rt.jar!/"},
+
+        new String[] {"jar:file:/gluegen/"+'\u0394'+"/gluegen-rt.jar!/"},
+    };
+
+    private static final String[][] uriFileSArrayWindows = new String[][] {
+        new String[] {"file:/C%3A/gluegen/build-x86_64/gluegen-rt.jar"},
+
+        new String[] {"file:/C%3A/gluegen/"+'\u0394'+"/gluegen-rt.jar"},
+
+        new String[] {"file:/C%3A/gluegen/build-x86_64%20lala/gluegen-rt.jar"},
+
+        new String[] {"file:/C%3A/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar"},
+
+        new String[] {"jar:file:/C%3A/gluegen/build-x86_64/gluegen-rt.jar!/"},
+
+        new String[] {"jar:file:/C%3A/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/"},
+
+        new String[] {"jar:file:/C%3A/gluegen/build-x86_64/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
+
+        new String[] {"jar:file:/C%3A/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
+
+        new String[] {"jar:file:///C%3A/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
+
+        new String[] {"jar:file://filehost/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
+
+        new String[] {"jar:file:/C%3A/gluegen/R%23/gluegen-rt.jar!/"},
+
+        new String[] {"jar:file:/C%3A/gluegen/A%24/B%5E/C~/D%23/E%5B/F%5D/gluegen-rt.jar!/"},
+
+        new String[] {"jar:file:/C%3A/gluegen/%24/%5E/~/%23/%5B/%5D/gluegen-rt.jar!/"},
+
+        new String[] {"jar:file:/C%3A/gluegen/"+'\u0394'+"/gluegen-rt.jar!/"},
+    };
+
+    private static final String[][] urlFileSArrayWindows = new String[][] {
+        new String[] {"file:/C:/gluegen/build-x86_64/gluegen-rt.jar"},
+
+        new String[] {"file:/C:/gluegen/"+'\u0394'+"/gluegen-rt.jar"},
+
+        new String[] {"file:/C:/gluegen/build-x86_64%20lala/gluegen-rt.jar"},
+
+        new String[] {"file:/C:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar"},
+
+        new String[] {"jar:file:/C:/gluegen/build-x86_64/gluegen-rt.jar!/"},
+
+        new String[] {"jar:file:/C:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/"},
+
+        new String[] {"jar:file:/C:/gluegen/build-x86_64/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
+
+        new String[] {"jar:file:/C:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
+
+        new String[] {"jar:file:///C:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
+
+        new String[] {"jar:file://filehost/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
+
+        new String[] {"jar:file:/C:/gluegen/R%23/gluegen-rt.jar!/"},
+
+        new String[] {"jar:file:/C:/gluegen/A%24/B%5E/C~/D%23/E%5B/F%5D/gluegen-rt.jar!/"},
+
+        new String[] {"jar:file:/C:/gluegen/%24/%5E/~/%23/%5B/%5D/gluegen-rt.jar!/"},
+
+        new String[] {"jar:file:/C:/gluegen/"+'\u0394'+"/gluegen-rt.jar!/"},
+    };
+
+    public static final String[][] fileSArrayUnix = new String[][] {
+        new String[] {"/gluegen/build-x86_64/gluegen-rt.jar",
+                      "file:/gluegen/build-x86_64/gluegen-rt.jar",
+                      "/gluegen/build-x86_64/gluegen-rt.jar"},
+
+        new String[] {"/gluegen/"+'\u0394'+"/gluegen-rt.jar",
+                      "file:/gluegen/"+'\u0394'+"/gluegen-rt.jar",
+                      "/gluegen/"+'\u0394'+"/gluegen-rt.jar"},
+
+        new String[] {"/gluegen/build-x86_64 lala/gluegen-rt.jar",
+                      "file:/gluegen/build-x86_64%20lala/gluegen-rt.jar",
+                      "/gluegen/build-x86_64 lala/gluegen-rt.jar"},
+
+        new String[] {"/gluegen/build-x86_64 öä lala/gluegen-rt.jar",
+                      "file:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar",
+                      "/gluegen/build-x86_64 öä lala/gluegen-rt.jar"},
+
+        new String[] {"/gluegen/A$/B^/C~/D#/E[/F]/gluegen-rt.jar",
+                      "file:/gluegen/A%24/B%5E/C~/D%23/E%5B/F%5D/gluegen-rt.jar",
+                      "/gluegen/A$/B^/C~/D#/E[/F]/gluegen-rt.jar" },
+
+        new String[] {"/gluegen/$/^/~/#/[/]/gluegen-rt.jar",
+                      "file:/gluegen/%24/%5E/~/%23/%5B/%5D/gluegen-rt.jar",
+                      "/gluegen/$/^/~/#/[/]/gluegen-rt.jar" },
+    };
+
+    public static final String[][] fileSArrayWindows = new String[][] {
+        new String[] {"C:/gluegen/build-x86_64/gluegen-rt.jar",
+                      "file:/C%3A/gluegen/build-x86_64/gluegen-rt.jar",
+                      "C:\\gluegen\\build-x86_64\\gluegen-rt.jar"},
+
+        new String[] {"C:/gluegen/"+'\u0394'+"/gluegen-rt.jar",
+                      "file:/C%3A/gluegen/"+'\u0394'+"/gluegen-rt.jar",
+                      "C:\\gluegen\\"+'\u0394'+"\\gluegen-rt.jar"},
+
+        new String[] {"C:/gluegen/build-x86_64 lala/gluegen-rt.jar",
+                      "file:/C%3A/gluegen/build-x86_64%20lala/gluegen-rt.jar",
+                      "C:\\gluegen\\build-x86_64 lala\\gluegen-rt.jar"},
+
+        new String[] {"C:/gluegen/build-x86_64 öä lala/gluegen-rt.jar",
+                      "file:/C%3A/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar",
+                      "C:\\gluegen\\build-x86_64 öä lala\\gluegen-rt.jar"},
+
+        new String[] {"C:\\gluegen\\build-x86_64 öä lala\\gluegen-rt.jar",
+                      "file:/C%3A/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar",
+                      "C:\\gluegen\\build-x86_64 öä lala\\gluegen-rt.jar"},
+
+        new String[] {"\\\\filehost\\gluegen\\build-x86_64 öä lala\\gluegen-rt.jar",
+                      "file://filehost/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar",
+                      "\\\\filehost\\gluegen\\build-x86_64 öä lala\\gluegen-rt.jar"},
+
+        new String[] {"C:/gluegen/A$/B^/C~/D#/E[/F]/gluegen-rt.jar",
+                      "file:/C%3A/gluegen/A%24/B%5E/C~/D%23/E%5B/F%5D/gluegen-rt.jar",
+                      "C:\\gluegen\\A$\\B^\\C~\\D#\\E[\\F]\\gluegen-rt.jar" },
+
+        new String[] {"C:/gluegen/$/^/~/#/[/]/gluegen-rt.jar",
+                      "file:/C%3A/gluegen/%24/%5E/~/%23/%5B/%5D/gluegen-rt.jar",
+                      "C:\\gluegen\\$\\^\\~\\#\\[\\]\\gluegen-rt.jar" },
+    };
+
+    @Test
+    public void test01HttpUri2URL() throws IOException, URISyntaxException {
+        testUri2URL(getSimpleTestName("."), uriHttpSArray);
+    }
+
+    @Test
+    public void test02FileUnixUri2URL() throws IOException, URISyntaxException {
+        testUri2URL(getSimpleTestName("."), uriFileSArrayUnix);
+    }
+
+    @Test
+    public void test03FileWindowsUri2URL() throws IOException, URISyntaxException {
+        testUri2URL(getSimpleTestName("."), uriFileSArrayWindows);
+    }
+
+    @Test
+    public void test11HttpURL2Uri() throws IOException, URISyntaxException {
+        testURL2Uri(getSimpleTestName("."), uriHttpSArray);
+    }
+
+    @Test
+    public void test12FileUnixURL2Uri() throws IOException, URISyntaxException {
+        testURL2Uri(getSimpleTestName("."), uriFileSArrayUnix);
+    }
+
+    @Test
+    public void test13FileWindowsURL2Uri() throws IOException, URISyntaxException {
+        testURL2Uri(getSimpleTestName("."), urlFileSArrayWindows);
+    }
+
+    @Test
+    public void test24FileUnixURI2URL() throws IOException, URISyntaxException {
+        if( Platform.OSType.WINDOWS != PlatformPropsImpl.OS_TYPE ) {
+            testFile2Uri(getSimpleTestName("."), fileSArrayUnix);
+        }
+    }
+
+    @Test
+    public void test25FileWindowsURI2URL() throws IOException, URISyntaxException {
+        if( Platform.OSType.WINDOWS == PlatformPropsImpl.OS_TYPE ) {
+            testFile2Uri(getSimpleTestName("."), fileSArrayWindows);
+        }
+    }
+
+    static void testUri2URL(final String testname, final String[][] uriSArray) throws IOException, URISyntaxException {
+        boolean ok = true;
+        for(int i=0; i<uriSArray.length; i++) {
+            final String[] uriSPair = uriSArray[i];
+            final String uriSource = uriSPair[0];
+            System.err.println("SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS "+testname+": "+(i+1)+"/"+uriSArray.length);
+            ok = testUri2URL(Uri.Encoded.cast(uriSource)) && ok;
+            System.err.println("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE "+testname+": "+(i+1)+"/"+uriSArray.length);
+        }
+        Assert.assertTrue("One or more errors occured see stderr above", ok);
+    }
+
+    static boolean testUri2URL(final Uri.Encoded uriSource) throws IOException, URISyntaxException {
+        System.err.println("uriSource   : "+uriSource);
+        final Uri uri0 = new Uri(uriSource);
+        URIDumpUtil.showUri(uri0);
+
+        final URI actualURI = uri0.toURI();
+        URIDumpUtil.showURI(actualURI);
+        final Uri.Encoded actualURIStr = Uri.Encoded.cast(actualURI.toString());
+
+        final URL actualURL = uri0.toURL();
+        URIDumpUtil.showURL(actualURL);
+        final Uri.Encoded actualURLStr = Uri.Encoded.cast(actualURL.toExternalForm());
+
+        System.err.println("expected_URX: "+uriSource);
+
+        final boolean equalsURI = uriSource.equals(actualURIStr);
+        System.err.println("actual   URI: "+actualURIStr+" - "+(equalsURI?"OK":"ERROR"));
+        final boolean equalsURL = uriSource.equals(actualURLStr);
+        System.err.println("actual   URL: "+actualURLStr+" - "+(equalsURL?"OK":"ERROR"));
+        URIDumpUtil.showReencodedURIOfUri(uri0);
+        URIDumpUtil.showReencodedUriOfURI(actualURI);
+
+        boolean ok = equalsURL && equalsURI;
+
+        // now test open ..
+        Throwable t = null;
+        URLConnection con = null;
+        try {
+            con = actualURL.openConnection();
+        } catch (final Throwable _t) {
+            t = _t;
+        }
+        if( null != t ) {
+            System.err.println("XXX: "+t.getClass().getName()+": "+t.getMessage());
+            t.printStackTrace();
+        } else {
+            System.err.println("XXX: No openConnection() failure");
+            System.err.println("XXX: "+con);
+        }
+
+        if( uri0.scheme.equals(Uri.JAR_SCHEME) ) {
+            // Extended tests on JAR Uri
+            final Uri uriSub0 = uri0.getContainedUri();
+            Assert.assertNotNull(uriSub0);
+            System.err.println("EXT JAR contained:");
+            URIDumpUtil.showUri(uriSub0);
+            final Uri uriSubDir0 = uriSub0.getDirectory();
+            final Uri uriSubParent0 = uriSub0.getParent();
+            System.err.println("EXT JAR contained Dir:");
+            URIDumpUtil.showUri(uriSubDir0);
+            System.err.println("EXT JAR contained Parent:");
+            URIDumpUtil.showUri(uriSubParent0);
+            ok = uriSubDir0.equals(uriSubParent0) && ok;
+        }
+        return ok;
+    }
+
+    static void testURL2Uri(final String testname, final String[][] urlSArray) throws IOException, URISyntaxException {
+        boolean ok = true;
+        for(int i=0; i<urlSArray.length; i++) {
+            final String[] uriSPair = urlSArray[i];
+            final String uriSource = uriSPair[0];
+            System.err.println("SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS "+testname+": "+(i+1)+"/"+urlSArray.length);
+            ok = testURL2Uri(new URL(uriSource)) && ok;
+            System.err.println("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE "+testname+": "+(i+1)+"/"+urlSArray.length);
+        }
+        Assert.assertTrue("One or more errors occured see stderr above", ok);
+    }
+
+    static boolean testURL2Uri(final URL urlSource) throws IOException, URISyntaxException {
+        System.err.println("URL Source   : "+urlSource);
+        URIDumpUtil.showURL(urlSource);
+
+        final URI uriSource = urlSource.toURI();
+        URIDumpUtil.showURI(uriSource);
+
+        final Uri uri0 = Uri.valueOf(urlSource);
+        URIDumpUtil.showUri(uri0);
+
+        final URL uriToURL = uri0.toURL();
+        URIDumpUtil.showURL(uriToURL);
+
+        // now test open ..
+        Throwable t = null;
+        URLConnection con = null;
+        try {
+            con = uriToURL.openConnection();
+        } catch (final Throwable _t) {
+            t = _t;
+        }
+        if( null != t ) {
+            System.err.println("XXX: "+t.getClass().getName()+": "+t.getMessage());
+            t.printStackTrace();
+        } else {
+            System.err.println("XXX: No openConnection() failure");
+            System.err.println("XXX: "+con);
+        }
+
+        boolean ok = true;
+
+        if( uri0.scheme.equals(Uri.JAR_SCHEME) ) {
+            // Extended tests on JAR Uri
+            final Uri uriSub0 = uri0.getContainedUri();
+            Assert.assertNotNull(uriSub0);
+            System.err.println("EXT JAR contained:");
+            URIDumpUtil.showUri(uriSub0);
+            final Uri uriSubDir0 = uriSub0.getDirectory();
+            final Uri uriSubParent0 = uriSub0.getParent();
+            System.err.println("EXT JAR contained Dir:");
+            URIDumpUtil.showUri(uriSubDir0);
+            System.err.println("EXT JAR contained Parent:");
+            URIDumpUtil.showUri(uriSubParent0);
+            ok = uriSubDir0.equals(uriSubParent0) && ok;
+        }
+        return ok;
+    }
+
+    static void testFile2Uri(final String testname, final String[][] uriSArray) throws IOException, URISyntaxException {
+        boolean ok = true;
+        for(int i=0; i<uriSArray.length; i++) {
+            final String[] uriSPair = uriSArray[i];
+            final String uriSource = uriSPair[0];
+            final String uriEncExpected= uriSPair[1];
+            final String fileExpected= uriSPair[2];
+            System.err.println("SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS "+testname+": "+(i+1)+"/"+uriSArray.length);
+            ok = testFile2Uri(uriSource, Uri.Encoded.cast(uriEncExpected), fileExpected) && ok;
+            System.err.println("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE "+testname+": "+(i+1)+"/"+uriSArray.length);
+        }
+        Assert.assertTrue("One or more errors occured see stderr above", ok);
+    }
+
+    static boolean testFile2Uri(final String fileSource, final Uri.Encoded uriEncExpected, final String fileExpected) throws IOException, URISyntaxException {
+        System.err.println("fileSource:         "+fileSource);
+        final File file = new File(fileSource);
+        System.err.println("file:               "+file.getAbsolutePath());
+
+        final Uri uri0 = Uri.valueOf(file);
+        URIDumpUtil.showReencodedURIOfUri(uri0);
+
+        final URL actualUrl = uri0.toURL();
+        final File actualFile = uri0.toFile();
+        final boolean equalsFilePath = fileExpected.equals(actualFile.getPath());
+        System.err.println("expected_path:      "+fileExpected);
+        System.err.println("actual___file-path: "+actualFile+" - "+(equalsFilePath?"OK":"ERROR"));
+        final boolean equalsEncUri = uriEncExpected.equals(uri0.getEncoded());
+        System.err.println("expected__encUri:   "+uriEncExpected);
+        System.err.println("actual_______Uri:   "+uri0.getEncoded()+" - "+(equalsEncUri?"OK":"ERROR"));
+        final boolean ok = equalsEncUri && equalsFilePath;
+
+        System.err.println("actual_______URL:   "+actualUrl.toExternalForm());
+
+        // now test open ..
+        Throwable t = null;
+        URLConnection con = null;
+        try {
+            con = actualUrl.openConnection();
+        } catch (final Throwable _t) {
+            t = _t;
+        }
+        if( null != t ) {
+            System.err.println("XXX: "+t.getClass().getName()+": "+t.getMessage());
+            t.printStackTrace();
+        } else {
+            System.err.println("XXX: No openConnection() failure");
+            System.err.println("XXX: "+con);
+        }
+        return ok;
+    }
+
+    public static void main(final String args[]) throws IOException {
+        final String tstname = TestUri03Resolving.class.getName();
+        org.junit.runner.JUnitCore.main(tstname);
+    }
+}
diff --git a/src/junit/com/jogamp/common/net/TestNetIOURIReservedCharsBug908.java b/src/junit/com/jogamp/common/net/TestUri99LaunchOnReservedCharPathBug908.java
similarity index 86%
rename from src/junit/com/jogamp/common/net/TestNetIOURIReservedCharsBug908.java
rename to src/junit/com/jogamp/common/net/TestUri99LaunchOnReservedCharPathBug908.java
index 904fca5..3b3cc6f 100644
--- a/src/junit/com/jogamp/common/net/TestNetIOURIReservedCharsBug908.java
+++ b/src/junit/com/jogamp/common/net/TestUri99LaunchOnReservedCharPathBug908.java
@@ -42,10 +42,9 @@ import org.junit.runners.MethodSorters;
 
 import com.jogamp.common.os.AndroidVersion;
 import com.jogamp.common.os.Platform;
-import com.jogamp.common.util.IOUtil;
 import com.jogamp.common.util.JarUtil;
 import com.jogamp.common.util.ReflectionUtil;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 import com.jogamp.junit.util.MiscUtils;
 
 /**
@@ -71,7 +70,7 @@ import com.jogamp.junit.util.MiscUtils;
  * </p>
  */
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestNetIOURIReservedCharsBug908 extends JunitTracer {
+public class TestUri99LaunchOnReservedCharPathBug908 extends SingletonJunitCase {
     static class TestClassLoader extends URLClassLoader {
         public TestClassLoader(final URL[] urls) {
             super(urls);
@@ -84,16 +83,16 @@ public class TestNetIOURIReservedCharsBug908 extends JunitTracer {
 
     @Test
     public void test00TempJarCacheSimplePath() throws IOException, IllegalArgumentException, URISyntaxException {
-        testTempJarCacheOddJarPathImpl("simpletons/", "simpletons/");
+        testTempJarCacheOddJarPathImpl("simpletons/");
     }
 
     @Test
     public void test01TempJarCacheOddPath() throws IOException, IllegalArgumentException, URISyntaxException {
         // Bug 908, issues w/ windows file path char: $ ^ ~ # [ ]
-        testTempJarCacheOddJarPathImpl("A$-B^-C~-D#-E]-F[-öä/",
+        testTempJarCacheOddJarPathImpl("A$-B^-C~-D#-E]-F[-öä/");
                                     // "A$-B%5E-C~-D#-E]-F[-%C3%B6%C3%A4/");    <- Firefox URI encoding! '#' -> [1]
                                     //   "A$-B%5E-C~-D%23-E]-F[-%C3%B6%C3%A4/"); <- '[' ']' -> [2]
-                                    "A$-B%5E-C~-D%23-E%5D-F%5B-%C3%B6%C3%A4/");
+                                    // "A$-B%5E-C~-D%23-E%5D-F%5B-%C3%B6%C3%A4/");
         /**
          * [1] '#'
             java.lang.IllegalArgumentException: URI has a fragment component
@@ -111,34 +110,35 @@ public class TestNetIOURIReservedCharsBug908 extends JunitTracer {
          */
 
     }
-    private void testTempJarCacheOddJarPathImpl(final String subPathUTF, final String subPathEncoded) throws IOException, IllegalArgumentException, URISyntaxException {
+    private void testTempJarCacheOddJarPathImpl(final String subPathUTF) throws IOException, IllegalArgumentException, URISyntaxException {
         if(AndroidVersion.isAvailable) { System.err.println("n/a on Android"); return; }
 
+        final Uri.Encoded subPathEncoded = new Uri.Encoded(subPathUTF, Uri.PATH_LEGAL);
         final String reservedCharPathUnencoded = "test/build/"+getClass().getSimpleName()+"/"+getTestMethodName()+"/"+subPathUTF;
-        final String reservedCharPathEncoded = "test/build/"+getClass().getSimpleName()+"/"+getTestMethodName()+"/"+subPathEncoded;
+        final Uri.Encoded reservedCharPathEncoded = Uri.Encoded.cast("test/build/"+getClass().getSimpleName()+"/"+getTestMethodName()+"/").concat(subPathEncoded);
 
         System.err.println("0 Unencoded:             "+reservedCharPathUnencoded);
         System.err.println("0 Encoded:               "+reservedCharPathEncoded);
 
         // jar:file:/dir1/dir2/gluegen-rt.jar!/
-        final URI jarFileURI = JarUtil.getJarFileURI(Platform.class.getName(), getClass().getClassLoader());
+        final Uri jarFileURI = JarUtil.getJarFileUri(Platform.class.getName(), getClass().getClassLoader());
         System.err.println("1 jarFileURI:            "+jarFileURI.toString());
         // gluegen-rt.jar
-        final String jarBasename = JarUtil.getJarBasename(jarFileURI);
+        final Uri.Encoded jarBasename = JarUtil.getJarBasename(jarFileURI);
         System.err.println("2 jarBasename:           "+jarBasename);
 
         // file:/dir1/build/gluegen-rt.jar
-        final URI fileURI = JarUtil.getJarSubURI(jarFileURI);
+        final Uri fileURI = jarFileURI.getContainedUri();
         System.err.println("3 fileURI:               "+fileURI.toString());
         // file:/dir1/build/
-        final URI fileFolderURI = new URI(IOUtil.getParentOf(fileURI.toString()));
+        final Uri fileFolderURI = fileURI.getParent();
         System.err.println("4 fileFolderURI:         "+fileFolderURI.toString());
         // file:/dir1/build/test/build/A$-B^-C~-D#-E]-F[/
-        final URI fileNewFolderURI = new URI(fileFolderURI.toString()+reservedCharPathEncoded);
+        final Uri fileNewFolderURI = fileFolderURI.concat(reservedCharPathEncoded);
         System.err.println("5 fileNewFolderURI:      "+fileNewFolderURI.toString());
 
-        final File srcFolder = new File(fileFolderURI);
-        final File dstFolder = new File(fileNewFolderURI);
+        final File srcFolder = fileFolderURI.toFile();
+        final File dstFolder = fileNewFolderURI.toFile();
         System.err.println("6 srcFolder:             "+srcFolder.toString());
         System.err.println("7 dstFolder:             "+dstFolder.toString());
         try {
@@ -163,7 +163,7 @@ public class TestNetIOURIReservedCharsBug908 extends JunitTracer {
     }
 
     public static void main(final String args[]) throws IOException {
-        final String tstname = TestNetIOURIReservedCharsBug908.class.getName();
+        final String tstname = TestUri99LaunchOnReservedCharPathBug908.class.getName();
         org.junit.runner.JUnitCore.main(tstname);
     }
 
diff --git a/src/junit/com/jogamp/common/net/TestURIQueryProps.java b/src/junit/com/jogamp/common/net/TestUriQueryProps.java
similarity index 66%
rename from src/junit/com/jogamp/common/net/TestURIQueryProps.java
rename to src/junit/com/jogamp/common/net/TestUriQueryProps.java
index 4f4435a..27a4bb7 100644
--- a/src/junit/com/jogamp/common/net/TestURIQueryProps.java
+++ b/src/junit/com/jogamp/common/net/TestUriQueryProps.java
@@ -1,21 +1,20 @@
 package com.jogamp.common.net;
 
-import static com.jogamp.common.net.URIDumpUtil.showURI;
+import static com.jogamp.common.net.URIDumpUtil.showUri;
 
 import java.io.IOException;
-import java.net.URI;
 import java.net.URISyntaxException;
 
 import org.junit.Assert;
 import org.junit.Test;
 
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestURIQueryProps extends JunitTracer {
+public class TestUriQueryProps extends SingletonJunitCase {
 
     @Test
     public void test() throws IOException, URISyntaxException {
@@ -29,22 +28,22 @@ public class TestURIQueryProps extends JunitTracer {
        for(int i=0; i<args.length-1; i+=2) {
            final String uri_s0 = args[i];
            final String uri_s1 = args[i+1];
-           final URI uri0 = new URI(uri_s0);
-           final URI uri1 = new URI(uri_s1);
-           showURI(uri0);
-           showURI(uri1);
-           final URIQueryProps data = URIQueryProps.create(uri1, ';');
+           final Uri uri0 = Uri.cast(uri_s0);
+           final Uri uri1 = Uri.cast(uri_s1);
+           showUri(uri0);
+           showUri(uri1);
+           final UriQueryProps data = UriQueryProps.create(uri1, ';');
            if(null == data) {
                System.err.println("Error: NULL: <"+uri_s1+"> -> "+uri1+" -> NULL");
            } else {
-               final URI uri1T = data.appendQuery(uri0);
-               showURI(uri1T);
+               final Uri uri1T = data.appendQuery(uri0);
+               showUri(uri1T);
                Assert.assertEquals(uri1, uri1T);
            }
        }
     }
     public static void main(final String args[]) throws IOException {
-        final String tstname = TestURIQueryProps.class.getName();
+        final String tstname = TestUriQueryProps.class.getName();
         org.junit.runner.JUnitCore.main(tstname);
     }
 }
diff --git a/src/junit/com/jogamp/common/net/TestUrisWithAssetHandler.java b/src/junit/com/jogamp/common/net/TestUrisWithAssetHandler.java
index d2bfaf7..1db0888 100644
--- a/src/junit/com/jogamp/common/net/TestUrisWithAssetHandler.java
+++ b/src/junit/com/jogamp/common/net/TestUrisWithAssetHandler.java
@@ -11,10 +11,10 @@ import org.junit.FixMethodOrder;
 import org.junit.Test;
 import org.junit.runners.MethodSorters;
 
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestUrisWithAssetHandler extends JunitTracer {
+public class TestUrisWithAssetHandler extends SingletonJunitCase {
 
     @BeforeClass
     public static void assetRegistration() throws Exception {
diff --git a/src/junit/com/jogamp/common/net/URIDumpUtil.java b/src/junit/com/jogamp/common/net/URIDumpUtil.java
index 1a74742..c5ba51f 100644
--- a/src/junit/com/jogamp/common/net/URIDumpUtil.java
+++ b/src/junit/com/jogamp/common/net/URIDumpUtil.java
@@ -42,4 +42,57 @@ public class URIDumpUtil {
         System.err.println("2.3.0 query:       "+uri.getRawQuery()+" (raw), "+uri.getQuery()+" (dec)");
         System.err.println("3.0.0 fragment:    "+uri.getRawFragment()+" (raw), "+uri.getFragment()+" (dec)");
     }
+
+    public static void showUri(final Uri uri) throws URISyntaxException {
+        showUri("ZZZZZZ Uri "+uri+", isOpaque "+uri.opaque+", isAbs "+uri.absolute+", hasAuth "+uri.hasAuthority, uri);
+    }
+
+    public static void showUri(final String message, final Uri uri) throws URISyntaxException {
+        System.err.println(message);
+
+        System.err.println("0.0.0 string:      "+uri.toString());
+        System.err.println("0.0.0 ascii :      "+uri.toASCIIString());
+        System.err.println("0.0.0 native-file: "+uri.toFile());
+        System.err.println("0.0.0 contained:   "+uri.getContainedUri());
+
+        System.err.println("1.0.0 scheme:      "+uri.scheme);
+        System.err.println("2.0.0 scheme-part: "+uri.schemeSpecificPart+" (raw), "+Uri.decode(uri.schemeSpecificPart)+" (dec)");
+        System.err.println("2.1.0 auth:        "+uri.authority+" (raw), "+Uri.decode(uri.authority)+" (dec)");
+        System.err.println("2.1.1 user-info:   "+uri.userInfo+" (raw), "+Uri.decode(uri.userInfo)+" (dec)");
+        System.err.println("2.1.1 host:        "+uri.host);
+        System.err.println("2.1.1 port:        "+uri.port);
+        System.err.println("2.2.0 path:        "+uri.path+" (raw), "+Uri.decode(uri.path)+" (dec)");
+        System.err.println("2.3.0 query:       "+uri.query+" (raw), "+Uri.decode(uri.query)+" (dec)");
+        System.err.println("3.0.0 fragment:    "+uri.fragment+" (raw), "+Uri.decode(uri.fragment)+" (dec)");
+    }
+
+    /**
+     * Just showing different encoding of Uri -> URI
+     *
+     * @param uri
+     * @throws URISyntaxException
+     */
+    public static void showReencodedURIOfUri(final Uri uri) throws URISyntaxException {
+        final URI recomposedURI = uri.toURIReencoded();
+        showURI("YYYYYY Recomposed URI "+recomposedURI+", isOpaque "+recomposedURI.isOpaque()+", isAbs "+recomposedURI.isAbsolute(), recomposedURI);
+        final String recomposedURIStr = recomposedURI.toString();
+        final boolean equalsRecompURI = uri.input.equals(recomposedURIStr);
+        System.err.println("source   Uri: "+uri.input);
+        System.err.println("recomp   URI: "+recomposedURIStr+" - "+(equalsRecompURI?"EQUAL":"UNEQUAL"));
+    }
+
+   /**
+     * Just showing different encoding of URI -> Uri
+     *
+     * @param uri
+     * @throws URISyntaxException
+     */
+    public static void showReencodedUriOfURI(final URI uri) throws URISyntaxException {
+        final Uri recomposedUri = Uri.valueOf(uri);
+        showUri("ZZZZZZ Recomposed Uri "+recomposedUri+", isOpaque "+recomposedUri.opaque+", isAbs "+recomposedUri.absolute+", hasAuth "+recomposedUri.hasAuthority, recomposedUri);
+        final String recomposedUriStr = recomposedUri.toString();
+        final boolean equalsRecompUri = uri.toString().equals(recomposedUriStr);
+        System.err.println("source   URI: "+uri.toString());
+        System.err.println("recomp   Uri: "+recomposedUriStr+" - "+(equalsRecompUri?"EQUAL":"UNEQUAL"));
+     }
 }
diff --git a/src/junit/com/jogamp/common/nio/BuffersTest.java b/src/junit/com/jogamp/common/nio/BuffersTest.java
index 68bd71f..c6a89f1 100644
--- a/src/junit/com/jogamp/common/nio/BuffersTest.java
+++ b/src/junit/com/jogamp/common/nio/BuffersTest.java
@@ -34,7 +34,7 @@ package com.jogamp.common.nio;
 import java.nio.IntBuffer;
 import org.junit.Test;
 
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import static org.junit.Assert.*;
 
@@ -45,7 +45,7 @@ import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class BuffersTest extends JunitTracer {
+public class BuffersTest extends SingletonJunitCase {
 
     @Test
     public void slice() {
diff --git a/src/junit/com/jogamp/common/nio/CachedBufferFactoryTest.java b/src/junit/com/jogamp/common/nio/CachedBufferFactoryTest.java
index b0f3cfb..6b9409f 100644
--- a/src/junit/com/jogamp/common/nio/CachedBufferFactoryTest.java
+++ b/src/junit/com/jogamp/common/nio/CachedBufferFactoryTest.java
@@ -42,7 +42,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import static java.lang.System.*;
 import static org.junit.Assert.*;
@@ -55,7 +55,7 @@ import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class CachedBufferFactoryTest extends JunitTracer {
+public class CachedBufferFactoryTest extends SingletonJunitCase {
 
     private final int BUFFERCOUNT = 120;
 
diff --git a/src/junit/com/jogamp/common/nio/TestBuffersFloatDoubleConversion.java b/src/junit/com/jogamp/common/nio/TestBuffersFloatDoubleConversion.java
index 61bbafa..7ee85fc 100644
--- a/src/junit/com/jogamp/common/nio/TestBuffersFloatDoubleConversion.java
+++ b/src/junit/com/jogamp/common/nio/TestBuffersFloatDoubleConversion.java
@@ -33,13 +33,13 @@ import org.junit.Assert;
 
 import org.junit.Test;
 
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestBuffersFloatDoubleConversion extends JunitTracer {
+public class TestBuffersFloatDoubleConversion extends SingletonJunitCase {
 
     public static boolean cmpFloatArray(final float[] d1, final int d1_offset, final float[] d2, final int d2_offset, final int len) {
         if( d1.length - d1_offset < len) {
diff --git a/src/junit/com/jogamp/common/nio/TestByteBufferCopyStream.java b/src/junit/com/jogamp/common/nio/TestByteBufferCopyStream.java
new file mode 100644
index 0000000..9524e91
--- /dev/null
+++ b/src/junit/com/jogamp/common/nio/TestByteBufferCopyStream.java
@@ -0,0 +1,244 @@
+/**
+ * Copyright 2014 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.common.nio;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.jogamp.common.os.Platform;
+import com.jogamp.junit.util.SingletonJunitCase;
+
+import org.junit.FixMethodOrder;
+import org.junit.runners.MethodSorters;
+
+/**
+ * Testing {@link MappedByteBufferInputStream} and {@link MappedByteBufferOutputStream}
+ * direct stream to stream copy via mapped buffers.
+ */
+ at FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class TestByteBufferCopyStream extends SingletonJunitCase {
+
+    static void testImpl(final String srcFileName, final long size,
+                         final MappedByteBufferInputStream.CacheMode srcCacheMode, final int srcSliceShift,
+                         final String dstFileName,
+                         final MappedByteBufferInputStream.CacheMode dstCacheMode, final int dstSliceShift ) throws IOException {
+        final Runtime runtime = Runtime.getRuntime();
+        final long[] usedMem0 = { 0 };
+        final long[] freeMem0 = { 0 };
+        final long[] usedMem1 = { 0 };
+        final long[] freeMem1 = { 0 };
+        final String prefix = "test "+String.format(TestByteBufferInputStream.PrintPrecision+" MiB", size/TestByteBufferInputStream.MIB);
+        TestByteBufferInputStream.dumpMem(prefix+" before", runtime, -1, -1, usedMem0, freeMem0 );
+
+        final File srcFile = new File(srcFileName);
+        srcFile.delete();
+        srcFile.createNewFile();
+        srcFile.deleteOnExit();
+
+        final RandomAccessFile input;
+        {
+            final RandomAccessFile _input = new RandomAccessFile(srcFile, "rw");
+            _input.setLength(size);
+            _input.close();
+            input = new RandomAccessFile(srcFile, "r");
+        }
+        final MappedByteBufferInputStream mis = new MappedByteBufferInputStream(input.getChannel(),
+                                                                                FileChannel.MapMode.READ_ONLY,
+                                                                                srcCacheMode,
+                                                                                srcSliceShift);
+        Assert.assertEquals(size, input.length());
+        Assert.assertEquals(size, mis.length());
+        Assert.assertEquals(0, mis.position());
+        Assert.assertEquals(size, mis.remaining());
+
+        final File dstFile = new File(dstFileName);
+        dstFile.delete();
+        dstFile.createNewFile();
+        dstFile.deleteOnExit();
+        final RandomAccessFile output = new RandomAccessFile(dstFile, "rw");
+        final MappedByteBufferInputStream.FileResizeOp szOp = new MappedByteBufferInputStream.FileResizeOp() {
+            @Override
+            public void setLength(final long newSize) throws IOException {
+                output.setLength(newSize);
+            }
+        };
+        final MappedByteBufferOutputStream mos = new MappedByteBufferOutputStream(output.getChannel(),
+                                                                                  FileChannel.MapMode.READ_WRITE,
+                                                                                  dstCacheMode,
+                                                                                  srcSliceShift, szOp);
+        Assert.assertEquals(0, output.length());
+        Assert.assertEquals(0, mos.length());
+        Assert.assertEquals(0, mos.position());
+        Assert.assertEquals(0, mos.remaining());
+
+        OutOfMemoryError oome = null;
+        IOException ioe = null;
+
+        try {
+            mos.write(mis, mis.remaining());
+
+            Assert.assertEquals(size, input.length());
+            Assert.assertEquals(size, output.length());
+            Assert.assertEquals(size, mis.length());
+            Assert.assertEquals(size, mos.length());
+            Assert.assertEquals(size, mis.position());
+            Assert.assertEquals(size, mos.position());
+            Assert.assertEquals(0, mis.remaining());
+            Assert.assertEquals(0, mos.remaining());
+
+        } catch (final IOException e) {
+            if( e.getCause() instanceof OutOfMemoryError ) {
+                oome = (OutOfMemoryError) e.getCause(); // oops
+            } else {
+                ioe = e;
+            }
+        } catch (final OutOfMemoryError m) {
+            oome = m; // oops
+        } finally {
+            mos.close();
+            mis.close();
+            input.close();
+            output.close();
+            srcFile.delete();
+            dstFile.delete();
+            TestByteBufferInputStream.dumpMem(prefix+" after ", runtime, usedMem0[0], freeMem0[0], usedMem1, freeMem1 );
+            System.gc();
+            try {
+                Thread.sleep(500);
+            } catch (final InterruptedException e) { }
+            TestByteBufferInputStream.dumpMem(prefix+" gc'ed ", runtime, usedMem0[0], freeMem0[0], usedMem1, freeMem1 );
+        }
+        if( null != ioe || null != oome ) {
+            if( null != oome ) {
+                System.err.printf("%s: OutOfMemoryError.2 %s%n", prefix, oome.getMessage());
+                oome.printStackTrace();
+            } else {
+                Assert.assertNull(ioe);
+            }
+        }
+    }
+
+    /** {@value} */
+    static final long halfMiB = 1L << 19;
+    /** {@value} */
+    static final long quaterGiB = 1L << 28;
+    /** {@value} */
+    static final long quaterPlusGiB = quaterGiB + halfMiB;
+    /** {@value} */
+    static final long halfGiB = 1L << 29;
+    /** {@value} */
+    static final long halfPlusGiB = halfGiB + halfMiB;
+    /** {@value} */
+    static final long oneGiB = 1L << 30;
+    /** {@value} */
+    static final long onePlusGiB = oneGiB + halfMiB;
+    /** {@value} */
+    static final long twoGiB = ( 2L << 30 );
+    /** {@value} */
+    static final long twoPlusGiB = twoGiB + halfMiB;
+
+    /** {@value} */
+    static final long lala = ( 1L << 27 );
+
+    @Test
+    public void test00() throws IOException {
+        final long size;
+        if( !manualTest && Platform.OSType.MACOS == Platform.getOSType() ) {
+            size = quaterGiB;
+        } else {
+            size = twoPlusGiB;
+        }
+        final int srcSliceShift = MappedByteBufferInputStream.DEFAULT_SLICE_SHIFT;
+        final int dstSliceShift = MappedByteBufferInputStream.DEFAULT_SLICE_SHIFT;
+        testImpl(getSimpleTestName(".")+"_In.bin", size, MappedByteBufferInputStream.CacheMode.FLUSH_PRE_HARD, srcSliceShift,
+                getSimpleTestName(".")+"_Out.bin", MappedByteBufferInputStream.CacheMode.FLUSH_PRE_HARD, dstSliceShift );
+    }
+
+    @Test
+    public void test01() throws IOException {
+        final long size;
+        if( !manualTest && Platform.OSType.MACOS == Platform.getOSType() ) {
+            size = quaterGiB;
+        } else {
+            size = twoPlusGiB;
+        }
+        final int srcSliceShift = MappedByteBufferInputStream.DEFAULT_SLICE_SHIFT;
+        final int dstSliceShift = MappedByteBufferInputStream.DEFAULT_SLICE_SHIFT;
+        testImpl(getSimpleTestName(".")+"_In.bin", size, MappedByteBufferInputStream.CacheMode.FLUSH_PRE_SOFT, srcSliceShift,
+                 getSimpleTestName(".")+"_Out.bin", MappedByteBufferInputStream.CacheMode.FLUSH_PRE_SOFT, dstSliceShift );
+    }
+
+    @Test
+    public void test02() throws IOException {
+        final long size;
+        if( !manualTest && Platform.OSType.MACOS == Platform.getOSType() ) {
+            size = quaterPlusGiB;
+        } else {
+            size = halfPlusGiB;
+        }
+        final int srcSliceShift = 27; // 125M bytes per slice
+        final int dstSliceShift = 27; // 125M bytes per slice
+        testImpl(getSimpleTestName(".")+"_In.bin", size, MappedByteBufferInputStream.CacheMode.FLUSH_PRE_SOFT, srcSliceShift,
+                 getSimpleTestName(".")+"_Out.bin", MappedByteBufferInputStream.CacheMode.FLUSH_PRE_SOFT, dstSliceShift );
+    }
+
+    @Test
+    public void test11() throws IOException {
+        final int srcSliceShift = 26; //  64M bytes per slice
+        final int dstSliceShift = 25; //  32M bytes per slice
+        final long size = quaterPlusGiB;
+        testImpl(getSimpleTestName(".")+"_In.bin", size, MappedByteBufferInputStream.CacheMode.FLUSH_PRE_SOFT, srcSliceShift,
+                 getSimpleTestName(".")+"_Out.bin", MappedByteBufferInputStream.CacheMode.FLUSH_PRE_SOFT, dstSliceShift );
+    }
+
+    @Test
+    public void test12() throws IOException {
+        final int srcSliceShift = 25; //  32M bytes per slice
+        final int dstSliceShift = 26; //  64M bytes per slice
+        final long size = quaterPlusGiB;
+        testImpl(getSimpleTestName(".")+"_In.bin", size, MappedByteBufferInputStream.CacheMode.FLUSH_PRE_SOFT, srcSliceShift,
+                 getSimpleTestName(".")+"_Out.bin", MappedByteBufferInputStream.CacheMode.FLUSH_PRE_SOFT, dstSliceShift );
+    }
+
+    static boolean manualTest = false;
+
+    public static void main(final String args[]) throws IOException {
+        for(int i=0; i<args.length; i++) {
+            if(args[i].equals("-manual")) {
+                manualTest = true;
+            }
+        }
+        final String tstname = TestByteBufferCopyStream.class.getName();
+        org.junit.runner.JUnitCore.main(tstname);
+    }
+}
diff --git a/src/junit/com/jogamp/common/nio/TestByteBufferInputStream.java b/src/junit/com/jogamp/common/nio/TestByteBufferInputStream.java
new file mode 100644
index 0000000..90a954b
--- /dev/null
+++ b/src/junit/com/jogamp/common/nio/TestByteBufferInputStream.java
@@ -0,0 +1,363 @@
+/**
+ * Copyright 2014 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.common.nio;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.jogamp.common.os.Platform;
+import com.jogamp.common.util.IOUtil;
+import com.jogamp.junit.util.SingletonJunitCase;
+
+import org.junit.FixMethodOrder;
+import org.junit.runners.MethodSorters;
+
+/**
+ * Testing serial read of {@link ByteBufferInputStream} and {@link MappedByteBufferInputStream},
+ * i.e. basic functionality only.
+ * <p>
+ * Focusing on comparison with {@link BufferedInputStream} regarding
+ * performance, used memory heap and used virtual memory.
+ * </p>
+ */
+ at FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class TestByteBufferInputStream extends SingletonJunitCase {
+    /** {@value} */
+    static final int buffer__8KiB = 1 << 13;
+
+    /** {@value} */
+    static final int halfMiB = 1 << 19;
+    /** {@value} */
+    static final int oneMiB = 1 << 20;
+    /** {@value} */
+    static final int tenMiB = 1 << 24;
+    /** {@value} */
+    static final int hunMiB = 1 << 27;
+    /** {@value} */
+    static final int halfGiB = 1 << 29;
+    /** {@value} */
+    static final int oneGiB = 1 << 30;
+    /** {@value} */
+    static final long twoPlusGiB = ( 2L << 30 ) + halfMiB;
+
+    static final String fileHalfMiB = "./testHalfMiB.bin" ;
+    static final String fileOneMiB = "./testOneMiB.bin" ;
+    static final String fileTenMiB = "./testTenMiB.bin" ;
+    static final String fileHunMiB = "./testHunMiB.bin" ;
+    static final String fileHalfGiB = "./testHalfGiB.bin" ;
+    static final String fileOneGiB = "./testOneGiB.bin" ;
+    static final String fileTwoPlusGiB = "./testTwoPlusGiB.bin" ;
+    static final String fileOut = "./testOut.bin" ;
+
+    public static final String PrintPrecision = "%8.3f";
+    public static final double MIB = 1024.0*1024.0;
+
+
+    @BeforeClass
+    public static void setup() throws IOException {
+        final Runtime runtime = Runtime.getRuntime();
+        System.err.printf("Total Memory : "+PrintPrecision+" MiB%n", runtime.totalMemory() / MIB);
+        System.err.printf("Max Memory   : "+PrintPrecision+" MiB%n", runtime.maxMemory() / MIB);
+
+        setup(fileHalfMiB, halfMiB);
+        setup(fileOneMiB, oneMiB);
+        setup(fileTenMiB, tenMiB);
+        setup(fileHunMiB, hunMiB);
+        setup(fileHalfGiB, halfGiB);
+        setup(fileOneGiB, oneGiB);
+        setup(fileTwoPlusGiB, twoPlusGiB);
+    }
+    static void setup(final String fname, final long size) throws IOException {
+        final File file = new File(fname);
+        final RandomAccessFile out = new RandomAccessFile(file, "rws");
+        out.setLength(size);
+        out.close();
+    }
+
+    @AfterClass
+    public static void cleanup() {
+        cleanup(fileHalfMiB);
+        cleanup(fileOneMiB);
+        cleanup(fileTenMiB);
+        cleanup(fileHunMiB);
+        cleanup(fileHalfGiB);
+        cleanup(fileOneGiB);
+        cleanup(fileTwoPlusGiB);
+        cleanup(fileOut);
+    }
+    static void cleanup(final String fname) {
+        final File file = new File(fname);
+        file.delete();
+    }
+
+    @Test
+    public void test01MixedIntSize() throws IOException {
+        // testCopyIntSize1Impl(fileHalfMiB, halfMiB);
+
+        // testCopyIntSize1Impl(fileOneMiB, oneMiB);
+
+        testCopyIntSize1Impl(fileTenMiB, tenMiB);
+
+        testCopyIntSize1Impl(fileHunMiB, hunMiB);
+
+        testCopyIntSize1Impl(fileHalfGiB, halfGiB);
+
+        // testCopyIntSize1Impl(fileOneGiB, oneGiB);
+    }
+
+    static enum SrcType { COPY, MMAP1, MMAP2_NONE, MMAP2_SOFT, MMAP2_HARD };
+
+    @Test
+    public void test11MMap1GiBFlushNone() throws IOException {
+        if( !manualTest && Platform.OSType.MACOS == Platform.getOSType() ) {
+            testCopyIntSize1Impl2(0, SrcType.MMAP2_NONE, 0, fileOneMiB, oneMiB);
+        } else {
+            testCopyIntSize1Impl2(0, SrcType.MMAP2_NONE, 0, fileOneGiB, oneGiB);
+            // testCopyIntSize1Impl2(0, SrcType.MMAP2_NONE, 0, fileTwoPlusGiB, twoPlusGiB);
+        }
+    }
+
+    @Test
+    public void test12MMap1GiBFlushSoft() throws IOException {
+        if( !manualTest && Platform.OSType.MACOS == Platform.getOSType() ) {
+            testCopyIntSize1Impl2(0, SrcType.MMAP2_SOFT, 0, fileOneMiB, oneMiB);
+        } else {
+            testCopyIntSize1Impl2(0, SrcType.MMAP2_SOFT, 0, fileOneGiB, oneGiB);
+            // testCopyIntSize1Impl2(0, SrcType.MMAP2_SOFT, 0, fileTwoPlusGiB, twoPlusGiB);
+        }
+    }
+
+    @Test
+    public void test13MMap2GiBFlushHard() throws IOException {
+        if( !manualTest && Platform.OSType.MACOS == Platform.getOSType() ) {
+            testCopyIntSize1Impl2(0, SrcType.MMAP2_HARD, 0, fileOneMiB, oneMiB);
+        } else {
+            // testCopyIntSize1Impl2(0, SrcType.MMAP2_HARD, 0, fileOneGiB, oneGiB);
+            testCopyIntSize1Impl2(0, SrcType.MMAP2_HARD, 0, fileTwoPlusGiB, twoPlusGiB);
+        }
+    }
+
+    void testCopyIntSize1Impl(final String testFileName, final long expSize) throws IOException {
+        testCopyIntSize1Impl2(0, SrcType.COPY, buffer__8KiB, testFileName, expSize);
+        testCopyIntSize1Impl2(0, SrcType.COPY,       hunMiB, testFileName, expSize);
+        testCopyIntSize1Impl2(0, SrcType.MMAP1,           0, testFileName, expSize);
+        testCopyIntSize1Impl2(0, SrcType.MMAP2_SOFT,           0, testFileName, expSize);
+        System.err.println();
+    }
+    boolean testCopyIntSize1Impl2(final int iter, final SrcType srcType, final int reqBufferSize, final String testFileName, final long expSize) throws IOException {
+        final int expSizeI = (int) ( expSize <= Integer.MAX_VALUE ? expSize : Integer.MAX_VALUE );
+        final int bufferSize = reqBufferSize < expSizeI ? reqBufferSize : expSizeI;
+        final File testFile = new File(testFileName);
+        final long hasSize1 = testFile.length();
+        final long t0 = System.currentTimeMillis();
+        Assert.assertEquals(expSize, hasSize1);
+
+        final Runtime runtime = Runtime.getRuntime();
+        final long[] usedMem0 = { 0 };
+        final long[] freeMem0 = { 0 };
+        final long[] usedMem1 = { 0 };
+        final long[] freeMem1 = { 0 };
+
+        final String prefix = "test #"+iter+" "+String.format(PrintPrecision+" MiB", expSize/MIB);
+        System.err.printf("%s: mode %-5s, bufferSize %9d: BEGIN%n", prefix, srcType.toString(), bufferSize);
+        dumpMem(prefix+" before", runtime, -1, -1, usedMem0, freeMem0 );
+
+        final IOException[] ioe = { null };
+        OutOfMemoryError oome = null;
+        InputStream bis = null;
+        FileInputStream fis = null;
+        FileChannel fic = null;
+        boolean isMappedByteBufferInputStream = false;
+        try {
+            fis = new FileInputStream(testFile);
+            if( SrcType.COPY == srcType ) {
+                if( hasSize1 > Integer.MAX_VALUE ) {
+                    fis.close();
+                    throw new IllegalArgumentException("file size > MAX_INT for "+srcType+": "+hasSize1+" of "+testFile);
+                }
+                bis = new BufferedInputStream(fis, bufferSize);
+            } else if( SrcType.MMAP1 == srcType ) {
+                if( hasSize1 > Integer.MAX_VALUE ) {
+                    fis.close();
+                    throw new IllegalArgumentException("file size > MAX_INT for "+srcType+": "+hasSize1+" of "+testFile);
+                }
+                fic = fis.getChannel();
+                final MappedByteBuffer fmap = fic.map(FileChannel.MapMode.READ_ONLY, 0, hasSize1); // survives channel/stream closing until GC'ed!
+                bis = new ByteBufferInputStream(fmap);
+            } else {
+                isMappedByteBufferInputStream = true;
+                MappedByteBufferInputStream.CacheMode cmode;
+                switch(srcType) {
+                    case MMAP2_NONE: cmode = MappedByteBufferInputStream.CacheMode.FLUSH_NONE;
+                                     break;
+                    case MMAP2_SOFT: cmode = MappedByteBufferInputStream.CacheMode.FLUSH_PRE_SOFT;
+                                     break;
+                    case MMAP2_HARD: cmode = MappedByteBufferInputStream.CacheMode.FLUSH_PRE_HARD;
+                                     break;
+                    default:         fis.close();
+                                     throw new InternalError("XX: "+srcType);
+                }
+                final MappedByteBufferInputStream mis = new MappedByteBufferInputStream(fis.getChannel(), FileChannel.MapMode.READ_ONLY, cmode);
+                Assert.assertEquals(expSize, mis.remaining());
+                Assert.assertEquals(expSize, mis.length());
+                Assert.assertEquals(0, mis.position());
+                bis = mis;
+            }
+        } catch (final IOException e) {
+            if( e.getCause() instanceof OutOfMemoryError ) {
+                oome = (OutOfMemoryError) e.getCause(); // oops
+            } else {
+                ioe[0] = e;
+            }
+        } catch (final OutOfMemoryError m) {
+            oome = m; // oops
+        }
+        IOException ioe2 = null;
+        try {
+            if( null != ioe[0] || null != oome ) {
+                if( null != oome ) {
+                    System.err.printf("%s: mode %-5s, bufferSize %9d: OutOfMemoryError.1 %s%n",
+                                      prefix, srcType.toString(), bufferSize, oome.getMessage());
+                    oome.printStackTrace();
+                } else {
+                    Assert.assertNull(ioe[0]);
+                }
+                return false;
+            }
+            Assert.assertEquals(expSizeI, bis.available());
+
+            final long t1 = System.currentTimeMillis();
+
+            final File out = new File(fileOut);
+            IOUtil.copyStream2File(bis, out, -1);
+            final long t2 = System.currentTimeMillis();
+
+            final String suffix;
+            if( isMappedByteBufferInputStream ) {
+                suffix = ", cacheMode "+((MappedByteBufferInputStream)bis).getCacheMode();
+            } else {
+                suffix = "";
+            }
+            System.err.printf("%s: mode %-5s, bufferSize %9d: total %5d, setup %5d, copy %5d ms%s%n",
+                              prefix, srcType.toString(), bufferSize, t2-t0, t1-t0, t2-t1, suffix);
+
+            Assert.assertEquals(expSize, out.length());
+            out.delete();
+
+            Assert.assertEquals(0, bis.available());
+            if( isMappedByteBufferInputStream ) {
+                final MappedByteBufferInputStream mis = (MappedByteBufferInputStream)bis;
+                Assert.assertEquals(0, mis.remaining());
+                Assert.assertEquals(expSize, mis.length());
+                Assert.assertEquals(expSize, mis.position());
+            }
+            dumpMem(prefix+" after ", runtime, usedMem0[0], freeMem0[0], usedMem1, freeMem1 );
+            System.gc();
+            try {
+                Thread.sleep(500);
+            } catch (final InterruptedException e) { }
+            dumpMem(prefix+" gc'ed ", runtime, usedMem0[0], freeMem0[0], usedMem1, freeMem1 );
+        } catch( final IOException e ) {
+            if( e.getCause() instanceof OutOfMemoryError ) {
+                oome = (OutOfMemoryError) e.getCause(); // oops
+            } else {
+                ioe2 = e;
+            }
+        } catch (final OutOfMemoryError m) {
+            oome = m; // oops
+        } finally {
+            if( null != fic ) {
+                fic.close();
+            }
+            if( null != fis ) {
+                fis.close();
+            }
+            if( null != bis ) {
+                bis.close();
+            }
+            System.err.printf("%s: mode %-5s, bufferSize %9d: END%n", prefix, srcType.toString(), bufferSize);
+            System.err.println();
+        }
+        if( null != ioe2 || null != oome ) {
+            if( null != oome ) {
+                System.err.printf("%s: mode %-5s, bufferSize %9d: OutOfMemoryError.2 %s%n",
+                        prefix, srcType.toString(), bufferSize, oome.getMessage());
+                oome.printStackTrace();
+            } else {
+                Assert.assertNull(ioe2);
+            }
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    public static void dumpMem(final String pre,
+                               final Runtime runtime, final long usedMem0,
+                               final long freeMem0, final long[] usedMemN,
+                               final long[] freeMemN )
+    {
+        usedMemN[0] = runtime.totalMemory() - runtime.freeMemory();
+        freeMemN[0] = runtime.freeMemory();
+
+        System.err.printf("%s Used Memory  : "+PrintPrecision, pre, usedMemN[0] / MIB);
+        if( 0 < usedMem0 ) {
+            System.err.printf(", delta "+PrintPrecision, (usedMemN[0]-usedMem0) / MIB);
+        }
+        System.err.println(" MiB");
+        /**
+        System.err.printf("%s Free Memory  : "+printPrecision, pre, freeMemN[0] / mib);
+        if( 0 < freeMem0 ) {
+            System.err.printf(", delta "+printPrecision, (freeMemN[0]-freeMem0) / mib);
+        }
+        System.err.println(" MiB"); */
+    }
+
+    static boolean manualTest = false;
+
+    public static void main(final String args[]) throws IOException {
+        for(int i=0; i<args.length; i++) {
+            if(args[i].equals("-manual")) {
+                manualTest = true;
+            }
+        }
+        final String tstname = TestByteBufferInputStream.class.getName();
+        org.junit.runner.JUnitCore.main(tstname);
+    }
+}
diff --git a/src/junit/com/jogamp/common/nio/TestByteBufferOutputStream.java b/src/junit/com/jogamp/common/nio/TestByteBufferOutputStream.java
new file mode 100644
index 0000000..b0d7baf
--- /dev/null
+++ b/src/junit/com/jogamp/common/nio/TestByteBufferOutputStream.java
@@ -0,0 +1,298 @@
+/**
+ * Copyright 2014 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.common.nio;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.jogamp.junit.util.SingletonJunitCase;
+
+import org.junit.FixMethodOrder;
+import org.junit.runners.MethodSorters;
+
+/**
+ * Testing {@link MappedByteBufferInputStream} and {@link MappedByteBufferOutputStream} editing functionality.
+ */
+ at FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class TestByteBufferOutputStream extends SingletonJunitCase {
+
+    static void testImpl(final String fname,
+                         final byte[] payLoad, final long payLoadOffset, final long postPayLoadFiller,
+                         final byte[] endBytes,
+                         final int sliceShift)
+            throws IOException
+    {
+        testImpl(fname, payLoad, payLoadOffset, postPayLoadFiller, endBytes, sliceShift, false);
+        testImpl(fname, payLoad, payLoadOffset, postPayLoadFiller, endBytes, sliceShift, true);
+    }
+    static void testImpl(final String fname,
+                         final byte[] payLoad, final long payLoadOffset, final long postPayLoadFiller,
+                         final byte[] endBytes,
+                         final int sliceShift, final boolean synchronous)
+            throws IOException
+    {
+        final File file = new File(fname);
+        file.delete();
+        file.createNewFile();
+        file.deleteOnExit();
+
+        try {
+            final RandomAccessFile out = new RandomAccessFile(file, "rw");
+            final MappedByteBufferInputStream.FileResizeOp szOp = new MappedByteBufferInputStream.FileResizeOp() {
+                @Override
+                public void setLength(final long newSize) throws IOException {
+                    out.setLength(newSize);
+                }
+            };
+            final MappedByteBufferInputStream mis = new MappedByteBufferInputStream(out.getChannel(),
+                                                                                    FileChannel.MapMode.READ_WRITE,
+                                                                                    MappedByteBufferInputStream.CacheMode.FLUSH_PRE_SOFT,
+                                                                                    sliceShift);
+            final MappedByteBufferOutputStream mos = mis.getOutputStream(szOp);
+            mos.setSynchronous(synchronous);
+
+            try {
+                // resize to payLoad start and position to it
+                mos.setLength(payLoadOffset);
+                Assert.assertEquals(payLoadOffset, out.length());
+                Assert.assertEquals(payLoadOffset, mos.length());
+                Assert.assertEquals(0, mos.position()); // no change
+                mos.position(payLoadOffset);
+                Assert.assertEquals(payLoadOffset, mos.position());
+
+                // mark, write-expand payLoad
+                mis.mark(1);
+                mos.write(payLoad);
+                Assert.assertEquals(payLoadOffset+payLoad.length, out.length());
+                Assert.assertEquals(payLoadOffset+payLoad.length, mos.length());
+                Assert.assertEquals(payLoadOffset+payLoad.length, mos.position());
+
+                // expand + 1
+                mos.setLength(payLoadOffset+payLoad.length+1);
+                Assert.assertEquals(payLoadOffset+payLoad.length+1, out.length());
+                Assert.assertEquals(payLoadOffset+payLoad.length+1, mos.length());
+                Assert.assertEquals(payLoadOffset+payLoad.length, mos.position()); // no change
+
+                // expand up-to very end, ahead of write - position to endBytes start
+                mos.setLength(payLoadOffset+payLoad.length+postPayLoadFiller+endBytes.length);
+                Assert.assertEquals(payLoadOffset+payLoad.length+postPayLoadFiller+endBytes.length, out.length());
+                Assert.assertEquals(payLoadOffset+payLoad.length+postPayLoadFiller+endBytes.length, mos.length());
+                Assert.assertEquals(payLoadOffset+payLoad.length, mos.position()); // no change
+                mos.skip(postPayLoadFiller);
+                Assert.assertEquals(payLoadOffset+payLoad.length+postPayLoadFiller, mos.position());
+
+                // write endBytes (no resize)
+                mos.write(endBytes);
+                Assert.assertEquals(payLoadOffset+payLoad.length+postPayLoadFiller+endBytes.length, mos.position());
+
+                // Reset to payLoad, read it and verify
+                mis.reset();
+                Assert.assertEquals(payLoadOffset, mos.position());
+                Assert.assertEquals(payLoadOffset, mis.position());
+                final byte[] tmp = new byte[payLoad.length];
+                Assert.assertEquals(payLoad.length, mis.read(tmp));
+                Assert.assertEquals(payLoadOffset+payLoad.length, mos.position());
+                Assert.assertEquals(payLoadOffset+payLoad.length, mis.position());
+                Assert.assertArrayEquals(payLoad, tmp);
+
+                // Shrink to end of payLoad, mark, read >= 0, reset .. redo
+                Assert.assertEquals(payLoadOffset+payLoad.length+postPayLoadFiller+endBytes.length, out.length());
+                Assert.assertEquals(payLoadOffset+payLoad.length+postPayLoadFiller+endBytes.length, mos.length());
+                mos.setLength(payLoadOffset+payLoad.length+1);
+                Assert.assertEquals(payLoadOffset+payLoad.length+1, out.length());
+                Assert.assertEquals(payLoadOffset+payLoad.length+1, mos.length());
+                Assert.assertEquals(payLoadOffset+payLoad.length, mos.position());
+                mis.mark(1);
+                Assert.assertTrue(mis.read()>=0);
+                Assert.assertEquals(payLoadOffset+payLoad.length+1, mos.position());
+                mis.reset();
+                Assert.assertEquals(payLoadOffset+payLoad.length, mos.position());
+                Assert.assertTrue(mis.read()>=0);
+                Assert.assertEquals(payLoadOffset+payLoad.length+1, mos.position());
+
+                // Shrink -1, read EOS
+                mos.setLength(payLoadOffset+payLoad.length);
+                Assert.assertEquals(payLoadOffset+payLoad.length, out.length());
+                Assert.assertEquals(payLoadOffset+payLoad.length, mos.length());
+                Assert.assertEquals(payLoadOffset+payLoad.length, mos.position());
+                Assert.assertEquals(-1, mis.read());
+
+                // Expand + 1, mark, read >= 0, reset .. redo
+                mos.setLength(payLoadOffset+payLoad.length+1);
+                Assert.assertEquals(payLoadOffset+payLoad.length+1, out.length());
+                Assert.assertEquals(payLoadOffset+payLoad.length+1, mos.length());
+                Assert.assertEquals(payLoadOffset+payLoad.length, mos.position());
+                mis.mark(1);
+                Assert.assertTrue(mis.read()>=0);
+                Assert.assertEquals(payLoadOffset+payLoad.length+1, mos.position());
+                mis.reset();
+                Assert.assertEquals(payLoadOffset+payLoad.length, mos.position());
+                Assert.assertTrue(mis.read()>=0);
+                Assert.assertEquals(payLoadOffset+payLoad.length+1, mos.position());
+
+                // Shrink -1, read EOS, write-expand, reset and verify
+                mos.setLength(payLoadOffset+payLoad.length);
+                Assert.assertEquals(payLoadOffset+payLoad.length, out.length());
+                Assert.assertEquals(payLoadOffset+payLoad.length, mos.length());
+                Assert.assertEquals(payLoadOffset+payLoad.length, mos.position());
+                Assert.assertEquals(-1, mis.read());
+                mos.write('Z'); // expand while writing ..
+                Assert.assertEquals(payLoadOffset+payLoad.length+1, out.length());
+                Assert.assertEquals(payLoadOffset+payLoad.length+1, mos.length());
+                Assert.assertEquals(payLoadOffset+payLoad.length+1, mos.position());
+                mis.reset();
+                Assert.assertEquals(payLoadOffset+payLoad.length, mos.position());
+                Assert.assertEquals(payLoadOffset+payLoad.length, mis.position());
+                Assert.assertEquals('Z', mis.read());
+                Assert.assertEquals(payLoadOffset+payLoad.length+1, mos.position());
+                Assert.assertEquals(payLoadOffset+payLoad.length+1, mis.position());
+
+                // Shrink -2, shall clear mark, test reset failure
+                mos.setLength(payLoadOffset+payLoad.length-1);
+                Assert.assertEquals(payLoadOffset+payLoad.length-1, out.length());
+                Assert.assertEquals(payLoadOffset+payLoad.length-1, mos.length());
+                Assert.assertEquals(payLoadOffset+payLoad.length-1, mos.position());
+                try {
+                    mis.reset();
+                    Assert.assertTrue(false); // shall not reach
+                } catch( final IOException ioe ) {
+                    Assert.assertNotNull(ioe);
+                }
+                mis.mark(1);
+
+                // ZERO file, test reset failure, read EOS, write-expand
+                mos.setLength(0);
+                Assert.assertEquals(0, out.length());
+                Assert.assertEquals(0, mos.length());
+                Assert.assertEquals(0, mos.position());
+                try {
+                    mis.reset();
+                    Assert.assertTrue(false); // shall not reach
+                } catch( final IOException ioe ) {
+                    Assert.assertNotNull(ioe);
+                }
+                Assert.assertEquals(-1, mis.read());
+                mos.write('Z'); // expand while writing ..
+                Assert.assertEquals(1, out.length());
+                Assert.assertEquals(1, mos.length());
+                Assert.assertEquals(1, mos.position());
+                mis.position(0);
+                Assert.assertEquals(0, mos.position());
+                Assert.assertEquals(0, mis.position());
+                Assert.assertEquals('Z', mis.read());
+            } finally {
+                mos.close();
+                mis.close();
+                out.close();
+            }
+        } finally {
+            file.delete();
+        }
+    }
+
+    @Test
+    public void test00() throws IOException {
+        final int sliceShift = 13; // 8192 bytes per slice
+        testImpl(getSimpleTestName(".")+".bin", "123456789AB".getBytes(), 0L, 0L, "EOF".getBytes(), sliceShift);
+    }
+
+    @Test
+    public void test01() throws IOException {
+        final int sliceShift = 13; // 8192 bytes per slice
+        testImpl(getSimpleTestName(".")+".bin", "123456789AB".getBytes(), 9000L, 100L, "EOF".getBytes(), sliceShift);
+    }
+
+    @Test
+    public void test02() throws IOException {
+        final int sliceShift = 13; // 8192 bytes per slice
+        testImpl(getSimpleTestName(".")+".bin", "123456789AB".getBytes(), 8189L, 9001L, "EOF".getBytes(), sliceShift);
+    }
+
+    @Test
+    public void test03() throws IOException {
+        final int sliceShift = 13; // 8192 bytes per slice
+        testImpl(getSimpleTestName(".")+".bin", "123456789AB".getBytes(), 58189L, 109001L, "EOF".getBytes(), sliceShift);
+    }
+
+    @Test
+    public void test10() throws IOException {
+        final int sliceShift = 10; // 1024 bytes per slice
+        final byte[] payLoad = new byte[4096];
+        for(int i=0; i<payLoad.length; i++) {
+            payLoad[i] = (byte)('A' + i%26);
+        }
+        testImpl(getSimpleTestName(".")+".bin", payLoad, 0L, 0L, "EOF".getBytes(), sliceShift);
+    }
+
+    @Test
+    public void test11() throws IOException {
+        final int sliceShift = 10; // 1024 bytes per slice
+        final byte[] payLoad = new byte[4096];
+        for(int i=0; i<payLoad.length; i++) {
+            payLoad[i] = (byte)('A' + i%26);
+        }
+        testImpl(getSimpleTestName(".")+".bin", payLoad, 1030L, 99L, "EOF".getBytes(), sliceShift);
+    }
+
+    @Test
+    public void test12() throws IOException {
+        final int sliceShift = 10; // 1024 bytes per slice
+        final byte[] payLoad = new byte[4096];
+        for(int i=0; i<payLoad.length; i++) {
+            payLoad[i] = (byte)('A' + i%26);
+        }
+        testImpl(getSimpleTestName(".")+".bin", payLoad, 1021L, 1301L, "EOF".getBytes(), sliceShift);
+    }
+
+    @Test
+    public void test13() throws IOException {
+        final int sliceShift = 10; // 1024 bytes per slice
+        final byte[] payLoad = new byte[4096];
+        for(int i=0; i<payLoad.length; i++) {
+            payLoad[i] = (byte)('A' + i%26);
+        }
+        testImpl(getSimpleTestName(".")+".bin", payLoad, 3021L, 6301L, "EOF".getBytes(), sliceShift);
+    }
+
+    static boolean manualTest = false;
+
+    public static void main(final String args[]) throws IOException {
+        for(int i=0; i<args.length; i++) {
+            if(args[i].equals("-manual")) {
+                manualTest = true;
+            }
+        }
+        final String tstname = TestByteBufferOutputStream.class.getName();
+        org.junit.runner.JUnitCore.main(tstname);
+    }
+}
diff --git a/src/junit/com/jogamp/common/nio/TestPointerBufferEndian.java b/src/junit/com/jogamp/common/nio/TestPointerBufferEndian.java
index 49a470f..d97e98c 100644
--- a/src/junit/com/jogamp/common/nio/TestPointerBufferEndian.java
+++ b/src/junit/com/jogamp/common/nio/TestPointerBufferEndian.java
@@ -6,7 +6,7 @@ import java.io.IOException;
 import jogamp.common.os.PlatformPropsImpl;
 
 import com.jogamp.common.os.*;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.Assert;
 import org.junit.Test;
@@ -17,10 +17,10 @@ import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestPointerBufferEndian extends JunitTracer {
+public class TestPointerBufferEndian extends SingletonJunitCase {
 
     protected void testImpl (final boolean direct) {
-        final MachineDescription machine = Platform.getMachineDescription();
+        final MachineDataInfo machine = Platform.getMachineDataInfo();
         final int bitsPtr = machine.pointerSizeInBytes() * 8;
         final String bitsProp = System.getProperty("sun.arch.data.model");
         out.println("OS: <"+PlatformPropsImpl.OS+"> CPU: <"+PlatformPropsImpl.ARCH+"> Bits: <"+bitsPtr+"/"+bitsProp+">");
diff --git a/src/junit/com/jogamp/common/nio/TestStructAccessorEndian.java b/src/junit/com/jogamp/common/nio/TestStructAccessorEndian.java
index 967122e..a569b54 100644
--- a/src/junit/com/jogamp/common/nio/TestStructAccessorEndian.java
+++ b/src/junit/com/jogamp/common/nio/TestStructAccessorEndian.java
@@ -10,19 +10,19 @@ import jogamp.common.os.PlatformPropsImpl;
 import org.junit.Assert;
 import org.junit.Test;
 
-import com.jogamp.common.os.MachineDescription;
+import com.jogamp.common.os.MachineDataInfo;
 import com.jogamp.common.os.Platform;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestStructAccessorEndian extends JunitTracer {
+public class TestStructAccessorEndian extends SingletonJunitCase {
 
     @Test
     public void testStructAccessorEndian1 () {
-        final MachineDescription machine = Platform.getMachineDescription();
+        final MachineDataInfo machine = Platform.getMachineDataInfo();
         final int bitsPtr = machine.pointerSizeInBytes() * 8;
         final String bitsProp = System.getProperty("sun.arch.data.model");
         out.println("OS: <"+PlatformPropsImpl.OS+"> CPU: <"+PlatformPropsImpl.ARCH+"> Bits: <"+bitsPtr+"/"+bitsProp+">");
diff --git a/src/junit/com/jogamp/common/os/TestElfReader01.java b/src/junit/com/jogamp/common/os/TestElfReader01.java
index bc6aef1..980a17a 100644
--- a/src/junit/com/jogamp/common/os/TestElfReader01.java
+++ b/src/junit/com/jogamp/common/os/TestElfReader01.java
@@ -8,7 +8,9 @@ import java.io.OutputStream;
 import java.io.RandomAccessFile;
 import java.util.List;
 
-import jogamp.common.os.elf.ElfHeader;
+import jogamp.common.os.PlatformPropsImpl;
+import jogamp.common.os.elf.ElfHeaderPart1;
+import jogamp.common.os.elf.ElfHeaderPart2;
 import jogamp.common.os.elf.Section;
 import jogamp.common.os.elf.SectionArmAttributes;
 import jogamp.common.os.elf.SectionHeader;
@@ -16,16 +18,17 @@ import jogamp.common.os.elf.SectionHeader;
 import org.junit.Test;
 
 import com.jogamp.common.os.Platform.OSType;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestElfReader01 extends JunitTracer {
+public class TestElfReader01 extends SingletonJunitCase {
     public static String GNU_LINUX_SELF_EXE = "/proc/self/exe";
     public static String ARM_HF_EXE = "tst-exe-armhf";
     public static String ARM_SF_EXE = "tst-exe-arm";
+    static File userFile = null;
 
     private static boolean checkFileReadAccess(final File file) {
         try {
@@ -49,49 +52,64 @@ public class TestElfReader01 extends JunitTracer {
     }
 
     @Test
-    public void testGNULinuxSelfExe () throws IOException {
-        if( OSType.LINUX == Platform.getOSType() ) {
-            final File f = new File(GNU_LINUX_SELF_EXE);
-            if( checkFileReadAccess(f) ) {
-                testElfHeaderImpl(f, false);
+    public void test01GNULinuxSelfExe () throws IOException {
+        if( null == userFile ) {
+            if( OSType.LINUX == Platform.getOSType() ) {
+                final File f = new File(GNU_LINUX_SELF_EXE);
+                if( checkFileReadAccess(f) ) {
+                    testElfHeaderImpl(f, false);
+                }
             }
         }
     }
 
     @Test
-    public void testJavaLib () throws IOException {
-        File jvmLib = findJVMLib("java");
-        if( null == jvmLib ) {
-            jvmLib = findJVMLib("jvm");
+    public void test02JavaLib () throws IOException {
+        if( null == userFile ) {
+            File jvmLib = findJVMLib("java");
+            if( null == jvmLib ) {
+                jvmLib = findJVMLib("jvm");
+            }
+            if( null != jvmLib ) {
+                testElfHeaderImpl(jvmLib, false);
+            }
         }
-        if( null != jvmLib ) {
-            testElfHeaderImpl(jvmLib, false);
+    }
+
+    @Test
+    public void test99UserFile() throws IOException {
+        if( null != userFile ) {
+            testElfHeaderImpl(userFile, false);
         }
     }
 
     void testElfHeaderImpl(final File file, final boolean fileOutSections) throws IOException {
+        Platform.initSingleton();
         System.err.println("Test file "+file.getAbsolutePath());
         final RandomAccessFile in = new RandomAccessFile(file, "r");
         try {
-            final ElfHeader eh;
+            final ElfHeaderPart1 eh1;
+            final ElfHeaderPart2 eh2;
             try {
-                eh = ElfHeader.read(in);
+                eh1 = ElfHeaderPart1.read(PlatformPropsImpl.OS_TYPE, in);
+                eh2 = ElfHeaderPart2.read(eh1, in);
             } catch (final Exception e) {
                 System.err.println("Probably not an ELF file - or not in current format: (caught) "+e.getMessage());
                 e.printStackTrace();
                 return;
             }
             int i=0;
-            System.err.println(eh);
-            System.err.println("SH entsz     "+eh.d.getE_shentsize());
-            System.err.println("SH off       "+toHexString(eh.d.getE_shoff()));
-            System.err.println("SH strndx    "+eh.d.getE_shstrndx());
-            System.err.println("SH num "+eh.sht.length);
-            if( 0 < eh.sht.length ) {
-                System.err.println("SH size "+eh.sht[0].d.getBuffer().limit());
+            System.err.println(eh1);
+            System.err.println(eh2);
+            System.err.println("SH entsz     "+eh2.raw.getE_shentsize());
+            System.err.println("SH off       "+toHexString(eh2.raw.getE_shoff()));
+            System.err.println("SH strndx    "+eh2.raw.getE_shstrndx());
+            System.err.println("SH num "+eh2.sht.length);
+            if( 0 < eh2.sht.length ) {
+                System.err.println("SH size "+eh2.sht[0].raw.getBuffer().limit());
             }
             {
-                final SectionHeader sh = eh.getSectionHeader(SectionHeader.SHT_ARM_ATTRIBUTES);
+                final SectionHeader sh = eh2.getSectionHeader(SectionHeader.SHT_ARM_ATTRIBUTES);
                 boolean abiVFPArgsAcceptsVFPVariant = false;
                 if( null != sh ) {
                     final SectionArmAttributes sArmAttrs = (SectionArmAttributes) sh.readSection(in);
@@ -102,8 +120,8 @@ public class TestElfReader01 extends JunitTracer {
                 }
                 System.err.println("abiVFPArgsAcceptsVFPVariant "+abiVFPArgsAcceptsVFPVariant);
             }
-            for(i=0; i<eh.sht.length; i++) {
-                final SectionHeader sh = eh.sht[i];
+            for(i=0; i<eh2.sht.length; i++) {
+                final SectionHeader sh = eh2.sht[i];
                 System.err.println(sh);
                 final int type = sh.getType();
                 if( SectionHeader.SHT_STRTAB == type ) {
@@ -132,6 +150,12 @@ public class TestElfReader01 extends JunitTracer {
     }
 
     public static void main(final String args[]) throws IOException {
+        for(int i=0; i<args.length; i++) {
+            if(args[i].equals("-file")) {
+                i++;
+                userFile = new File(args[i]);
+            }
+        }
         final String tstname = TestElfReader01.class.getName();
         org.junit.runner.JUnitCore.main(tstname);
     }
diff --git a/src/junit/com/jogamp/common/util/IntIntHashMapTest.java b/src/junit/com/jogamp/common/util/IntIntHashMapTest.java
index 75524ac..dc523f0 100644
--- a/src/junit/com/jogamp/common/util/IntIntHashMapTest.java
+++ b/src/junit/com/jogamp/common/util/IntIntHashMapTest.java
@@ -40,7 +40,7 @@ import org.junit.BeforeClass;
 import org.junit.Test;
 
 import com.jogamp.common.os.Platform;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import static org.junit.Assert.*;
 import static java.lang.System.*;
@@ -54,14 +54,14 @@ import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class IntIntHashMapTest extends JunitTracer {
+public class IntIntHashMapTest extends SingletonJunitCase {
 
     private static int iterations;
     private static IntIntUniqueRndValues pairs;
 
     @BeforeClass
     public static void init() {
-        iterations = ( Platform.getCPUType().getFamily() == Platform.CPUFamily.ARM ) ? 20 : 10000;
+        iterations = ( Platform.getCPUType().family == Platform.CPUFamily.ARM ) ? 20 : 10000;
         pairs = new IntIntUniqueRndValues(iterations);
     }
 
diff --git a/src/junit/com/jogamp/common/util/IntObjectHashMapTest.java b/src/junit/com/jogamp/common/util/IntObjectHashMapTest.java
index 3207683..5573c1a 100644
--- a/src/junit/com/jogamp/common/util/IntObjectHashMapTest.java
+++ b/src/junit/com/jogamp/common/util/IntObjectHashMapTest.java
@@ -40,7 +40,7 @@ import org.junit.BeforeClass;
 import org.junit.Test;
 
 import com.jogamp.common.os.Platform;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import static org.junit.Assert.*;
 
@@ -53,14 +53,14 @@ import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class IntObjectHashMapTest extends JunitTracer {
+public class IntObjectHashMapTest extends SingletonJunitCase {
 
     private static int iterations;
     private static IntIntObjUniqueRndValues pairs;
 
     @BeforeClass
     public static void init() {
-        iterations = ( Platform.getCPUType().getFamily() == Platform.CPUFamily.ARM ) ? 20 : 10000;
+        iterations = ( Platform.getCPUType().family == Platform.CPUFamily.ARM ) ? 20 : 10000;
         pairs = new IntIntObjUniqueRndValues(iterations);
     }
 
diff --git a/src/junit/com/jogamp/common/util/LongIntHashMapTest.java b/src/junit/com/jogamp/common/util/LongIntHashMapTest.java
index 90e54b9..9ea4206 100644
--- a/src/junit/com/jogamp/common/util/LongIntHashMapTest.java
+++ b/src/junit/com/jogamp/common/util/LongIntHashMapTest.java
@@ -40,7 +40,7 @@ import org.junit.BeforeClass;
 import org.junit.Test;
 
 import com.jogamp.common.os.Platform;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import static org.junit.Assert.*;
 import static java.lang.System.*;
@@ -54,7 +54,7 @@ import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class LongIntHashMapTest extends JunitTracer {
+public class LongIntHashMapTest extends SingletonJunitCase {
 
     private static int iterations;
     private static LongIntUniqueRndValues pairs;
diff --git a/src/junit/com/jogamp/common/util/TestArrayHashSet01.java b/src/junit/com/jogamp/common/util/TestArrayHashSet01.java
index 4f63fbe..51db2c7 100644
--- a/src/junit/com/jogamp/common/util/TestArrayHashSet01.java
+++ b/src/junit/com/jogamp/common/util/TestArrayHashSet01.java
@@ -34,13 +34,13 @@ import java.io.IOException;
 import org.junit.Assert;
 import org.junit.Test;
 
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestArrayHashSet01 extends JunitTracer {
+public class TestArrayHashSet01 extends SingletonJunitCase {
 
     public static class Dummy {
         int i1, i2, i3;
diff --git a/src/junit/com/jogamp/common/util/TestBitstream00.java b/src/junit/com/jogamp/common/util/TestBitstream00.java
index 7bf4167..920363b 100644
--- a/src/junit/com/jogamp/common/util/TestBitstream00.java
+++ b/src/junit/com/jogamp/common/util/TestBitstream00.java
@@ -42,7 +42,7 @@ import com.jogamp.common.os.Platform;
 
 import static com.jogamp.common.util.BitstreamData.*;
 
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
@@ -51,7 +51,7 @@ import org.junit.runners.MethodSorters;
  * Test basic bit operations for {@link Bitstream}
  */
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestBitstream00 extends JunitTracer {
+public class TestBitstream00 extends SingletonJunitCase {
 
     @Test
     public void test00ShowByteOrder() {
@@ -129,6 +129,138 @@ public class TestBitstream00 extends JunitTracer {
         }
     }
 
+    @Test
+    public void test10ReadWrite_13() throws UnsupportedOperationException, IllegalStateException, IOException {
+        // H->L    : 00000011 00000010 00000001   000000110000001000000001
+        // H->L rev: 10000000 01000000 11000000   100000000100000011000000
+        //
+        // L->H    : 00000001 00000010 00000011   000000010000001000000011
+        // L->H rev: 11000000 01000000 10000000   110000000100000010000000
+        test10ReadWrite1_31Impl(8, 8, 8, 0x030201, "000000110000001000000001");
+
+        // H->L: 00011 000010 00001  0001100001000001
+        // L->H: 10000 010000 11000  1000001000011000
+        test10ReadWrite1_31Impl(5, 6, 5, 0x1841, "0001100001000001");
+    }
+    void test10ReadWrite1_31Impl(final int c1, final int c2, final int c3, final int v, final String vStrHigh2LowExp)
+                        throws UnsupportedOperationException, IllegalStateException, IOException
+    {
+        // final Bitstream<ByteBuffer> source = new Bitstream<ByteBuffer>();
+        final int bitCount = c1+c2+c3;
+        final int byteCount = ( bitCount + 7 ) / 8;
+        final String vStrHigh2Low0 = Bitstream.toBinString(true, v, bitCount);
+        System.err.printf("test10ReadWrite31 bits %d:%d:%d = %d = %d bytes%n",
+                c1, c2, c3, bitCount, byteCount);
+        System.err.printf("test10ReadWrite31 %s%n", Bitstream.toHexBinString(true, v, bitCount));
+        System.err.printf("test10ReadWrite31 %s%n", Bitstream.toHexBinString(false, v, bitCount));
+        Assert.assertEquals(vStrHigh2LowExp, vStrHigh2Low0);
+
+        final ByteBuffer bbRead = ByteBuffer.allocate(byteCount);
+        for(int i=0; i<byteCount; i++) {
+            final int b = ( v >>> 8*i ) & 0xff;
+            bbRead.put(i, (byte) b);
+            System.err.printf("testBytes[%d]: %s%n", i, Bitstream.toHexBinString(true, b, 8));
+        }
+        final Bitstream.ByteBufferStream bbsRead = new Bitstream.ByteBufferStream(bbRead);
+        final Bitstream<ByteBuffer> bsRead = new Bitstream<ByteBuffer>(bbsRead, false /* outputMode */);
+
+        String vStrHigh2Low1C1 = "";
+        String vStrHigh2Low1C2 = "";
+        String vStrHigh2Low1C3 = "";
+        String vStrHigh2Low1 = "";
+        {
+            bsRead.mark(byteCount);
+            System.err.println("readBit    (msbFirst false): ");
+            int b;
+            int i=0;
+            String vStrHigh2Low1T = ""; // OK for LSB, MSB segmented
+            while( Bitstream.EOS != ( b = bsRead.readBit(false /* msbFirst */) ) ) {
+                vStrHigh2Low1T = b + vStrHigh2Low1T;
+                if(i < c1) {
+                    vStrHigh2Low1C1 = b + vStrHigh2Low1C1;
+                } else if(i < c1+c2) {
+                    vStrHigh2Low1C2 = b + vStrHigh2Low1C2;
+                } else {
+                    vStrHigh2Low1C3 = b + vStrHigh2Low1C3;
+                }
+                i++;
+            }
+            vStrHigh2Low1 = vStrHigh2Low1C3 + vStrHigh2Low1C2 + vStrHigh2Low1C1;
+            System.err.printf("readBit.1 %s, 0x%s%n", vStrHigh2Low1C1, Integer.toHexString(Integer.valueOf(vStrHigh2Low1C1, 2)));
+            System.err.printf("readBit.2 %s, 0x%s%n", vStrHigh2Low1C2, Integer.toHexString(Integer.valueOf(vStrHigh2Low1C2, 2)));
+            System.err.printf("readBit.3 %s, 0x%s%n", vStrHigh2Low1C3, Integer.toHexString(Integer.valueOf(vStrHigh2Low1C3, 2)));
+            System.err.printf("readBit.T %s, ok %b%n%n", vStrHigh2Low1T, vStrHigh2LowExp.equals(vStrHigh2Low1T));
+            System.err.printf("readBit.X %s, ok %b%n%n", vStrHigh2Low1, vStrHigh2LowExp.equals(vStrHigh2Low1));
+            bsRead.reset();
+        }
+
+        {
+            String vStrHigh2Low3T = ""; // OK for LSB, MSB segmented
+            System.err.println("readBits32: ");
+            final int b = bsRead.readBits31(bitCount);
+            vStrHigh2Low3T = Bitstream.toBinString(true, b, bitCount);
+            System.err.printf("readBits31.T %s, ok %b, %s%n%n", vStrHigh2Low3T, vStrHigh2LowExp.equals(vStrHigh2Low3T), Bitstream.toHexBinString(true, b, bitCount));
+            bsRead.reset();
+        }
+
+        String vStrHigh2Low2 = "";
+        {
+            System.err.println("readBits32: ");
+            final int bC1 = bsRead.readBits31(c1);
+            System.err.printf("readBits31.1 %s%n", Bitstream.toHexBinString(true, bC1, c1));
+            final int bC2 = bsRead.readBits31(c2);
+            System.err.printf("readBits31.2 %s%n", Bitstream.toHexBinString(true, bC2, c2));
+            final int bC3 = bsRead.readBits31(c3);
+            System.err.printf("readBits31.3 %s%n", Bitstream.toHexBinString(true, bC3, c3));
+            final int b = bC3 << (c1+c2) | bC2 << c1 | bC1;
+            vStrHigh2Low2 = Bitstream.toBinString(true, b, bitCount);
+            System.err.printf("readBits31.X %s, ok %b, %s%n%n", vStrHigh2Low2, vStrHigh2LowExp.equals(vStrHigh2Low2), Bitstream.toHexBinString(true, b, bitCount));
+            bsRead.reset();
+        }
+
+        Assert.assertEquals(vStrHigh2LowExp, vStrHigh2Low1);
+        Assert.assertEquals(vStrHigh2LowExp, vStrHigh2Low2);
+
+        boolean ok = true;
+        {
+            final ByteBuffer bbWrite = ByteBuffer.allocate(byteCount);
+            final Bitstream.ByteBufferStream bbsWrite = new Bitstream.ByteBufferStream(bbWrite);
+            final Bitstream<ByteBuffer> bsWrite = new Bitstream<ByteBuffer>(bbsWrite, true /* outputMode */);
+            {
+                int b;
+                while( Bitstream.EOS != ( b = bsRead.readBit(false)) ) {
+                    bsWrite.writeBit(false, b);
+                }
+            }
+            bsRead.reset();
+            for(int i=0; i<byteCount; i++) {
+                final int bR = bbWrite.get(i);
+                final int bW = bbWrite.get(i);
+                System.err.printf("readWriteBit   [%d]: read %s, write %s, ok %b%n",
+                        i, Bitstream.toHexBinString(true, bR, 8), Bitstream.toHexBinString(true, bW, 8), bR==bW);
+                ok = ok && bR==bW;
+            }
+            Assert.assertTrue(ok);
+        }
+        {
+            final ByteBuffer bbWrite = ByteBuffer.allocate(byteCount);
+            final Bitstream.ByteBufferStream bbsWrite = new Bitstream.ByteBufferStream(bbWrite);
+            final Bitstream<ByteBuffer> bsWrite = new Bitstream<ByteBuffer>(bbsWrite, true /* outputMode */);
+            {
+                bsWrite.writeBits31(bitCount, bsRead.readBits31(bitCount));
+            }
+            bsRead.reset();
+            for(int i=0; i<byteCount; i++) {
+                final int bR = bbWrite.get(i);
+                final int bW = bbWrite.get(i);
+                System.err.printf("readWriteBits31[%d]: read %s, write %s, ok %b%n",
+                        i, Bitstream.toHexBinString(true, bR, 8), Bitstream.toHexBinString(true, bW, 8), bR==bW);
+                ok = ok && bR==bW;
+            }
+            Assert.assertTrue(ok);
+        }
+    }
+
     public static void main(final String args[]) throws IOException {
         final String tstname = TestBitstream00.class.getName();
         org.junit.runner.JUnitCore.main(tstname);
diff --git a/src/junit/com/jogamp/common/util/TestBitstream01.java b/src/junit/com/jogamp/common/util/TestBitstream01.java
index f0415bc..49931a3 100644
--- a/src/junit/com/jogamp/common/util/TestBitstream01.java
+++ b/src/junit/com/jogamp/common/util/TestBitstream01.java
@@ -34,7 +34,7 @@ import java.nio.ByteBuffer;
 import org.junit.Assert;
 import org.junit.Test;
 
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 import static com.jogamp.common.util.BitstreamData.*;
 
 import org.junit.FixMethodOrder;
@@ -48,44 +48,67 @@ import org.junit.runners.MethodSorters;
  *  <li>{@link Bitstream#mark(int)}</li>
  *  <li>{@link Bitstream#reset()}</li>
  *  <li>{@link Bitstream#flush()}</li>
- *  <li>{@link Bitstream#readBits31(boolean, int)}</li>
- *  <li>{@link Bitstream#writeBits31(boolean, int, int)}</li>
+ *  <li>{@link Bitstream#readBits31(int)}</li>
+ *  <li>{@link Bitstream#writeBits31(int, int)}</li>
  * </ul>
  */
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestBitstream01 extends JunitTracer {
+public class TestBitstream01 extends SingletonJunitCase {
 
-    Bitstream<ByteBuffer> getTestStream(final boolean msbFirst, final int preBits, final int skipBits, final int postBits) throws IOException {
-        final int byteCount = ( preBits + skipBits + postBits + 7 ) / 8;
+    Bitstream<ByteBuffer> getTestStream(final boolean msbFirstData, final boolean msbFirstWrite,
+                                        final int preBits, final int skipBits, final int postBits) throws IOException {
+        final int bitCount = preBits+skipBits+postBits;
+        final int byteCount = ( bitCount + 7 ) / 8;
         final ByteBuffer bbTest = ByteBuffer.allocate(byteCount);
         final Bitstream.ByteBufferStream bbsTest = new Bitstream.ByteBufferStream(bbTest);
         final Bitstream<ByteBuffer> bsTest = new Bitstream<ByteBuffer>(bbsTest, true /* outputMode */);
         final String sTest0;
-        if( msbFirst ) {
+        if( msbFirstData ) {
             sTest0 = testStringMSB.substring(0, preBits+skipBits+postBits);
         } else {
             sTest0 = testStringLSB.substring(0, preBits+skipBits+postBits);
         }
-        for(int i=0; i<preBits+skipBits+postBits; i++) {
-            final int bit = Integer.valueOf(sTest0.substring(i, i+1));
-            bsTest.writeBit(msbFirst, bit);
+        if( msbFirstData == msbFirstWrite ) {
+            for(int i=0; i<bitCount; i++) {
+                final int bit = Integer.valueOf(sTest0.substring(i, i+1));
+                bsTest.writeBit(msbFirstWrite, bit);
+            }
+        } else {
+            for(int i=bitCount-1; i >= 0; i--) {
+                final int bit = Integer.valueOf(sTest0.substring(i, i+1));
+                bsTest.writeBit(msbFirstWrite, bit);
+            }
         }
+        System.err.printf("TestData: msbFirst[data %b, write %b], bits[pre %d, skip %d, post %d = %d]: <%s>%n",
+                msbFirstData, msbFirstWrite, preBits, skipBits, postBits, bitCount, sTest0);
         Assert.assertEquals(preBits+skipBits+postBits, bsTest.position());
         bsTest.setStream(bsTest.getSubStream(), false /* outputMode */); // switch to input-mode, implies flush()
+        dumpData("TestData: ", bsTest.getSubStream(), 0, bsTest.getSubStream().limit());
         return bsTest;
     }
 
-    String getTestStreamResultAsString(final boolean msbFirst, final int preBits, final int skipBits, final int postBits) {
+    String getTestStreamResultAsString(final boolean msbFirstData, final boolean msbFirstAssemble,
+                                       final int preBits, final int skipBits, final int postBits) {
         final String pre, post;
-        if( msbFirst ) {
-            pre = testStringMSB.substring(0, preBits);
-            post = testStringMSB.substring(preBits+skipBits, preBits+skipBits+postBits);
+        if( msbFirstData ) {
+            if( msbFirstAssemble ) {
+                pre = testStringMSB.substring(0, preBits);
+                post = testStringMSB.substring(preBits+skipBits, preBits+skipBits+postBits);
+            } else {
+                pre = testStringMSB.substring(postBits+skipBits, preBits+skipBits+postBits);
+                post = testStringMSB.substring(0, postBits);
+            }
         } else {
-            pre = testStringLSB.substring(0, preBits);
-            post = testStringLSB.substring(preBits+skipBits, preBits+skipBits+postBits);
+            if( msbFirstAssemble ) {
+                pre = testStringLSB.substring(0, preBits);
+                post = testStringLSB.substring(preBits+skipBits, preBits+skipBits+postBits);
+            } else {
+                pre = testStringMSB.substring(postBits+skipBits, preBits+skipBits+postBits);
+                post = testStringMSB.substring(0, postBits);
+            }
         }
-        final String r = pre + post;
-        System.err.println("Test: <"+pre+"> + <"+post+"> = <"+r+">");
+        final String r = msbFirstAssemble ? pre + post : post + pre;
+        System.err.println("ResultExp: <"+pre+"> + <"+post+"> = <"+r+">");
         return r;
     }
 
@@ -155,9 +178,8 @@ public class TestBitstream01 extends JunitTracer {
 
         // prepare bitstream
         System.err.println("Prepare bitstream");
-        final Bitstream<ByteBuffer> bsTest = getTestStream(msbFirst, preBits, skipBits, postBits);
-        dumpData("Test", bsTest.getSubStream(), 0, bsTest.getSubStream().limit());
-        final String sTest = getTestStreamResultAsString(msbFirst, preBits, skipBits, postBits);
+        final Bitstream<ByteBuffer> bsTest = getTestStream(msbFirst, msbFirst, preBits, skipBits, postBits);
+        final String sTest = getTestStreamResultAsString(msbFirst, true, preBits, skipBits, postBits);
 
         // init copy-bitstream
         final int byteCount = ( totalBits + 7 ) / 8;
@@ -219,50 +241,48 @@ public class TestBitstream01 extends JunitTracer {
     }
 
     @Test
-    public void test03BulkBitsMSBFirst() throws IOException {
-        testBulkBitsImpl(true);
-    }
-    @Test
-    public void test04BulkBitsLSBFirst() throws IOException {
-        testBulkBitsImpl(false);
-    }
-    void testBulkBitsImpl(final boolean msbFirst) throws IOException {
-        testBulkBitsImpl(msbFirst,  0,  0,  1);
-        testBulkBitsImpl(msbFirst,  0,  0,  3);
-        testBulkBitsImpl(msbFirst,  0,  0,  8);
-        testBulkBitsImpl(msbFirst,  0,  0, 10);
-        testBulkBitsImpl(msbFirst,  0,  0, 30);
-        testBulkBitsImpl(msbFirst,  0,  0, 31);
-
-        testBulkBitsImpl(msbFirst,  3,  0,  3);
-        testBulkBitsImpl(msbFirst,  8,  0,  3);
-        testBulkBitsImpl(msbFirst,  9,  0,  3);
-
-        testBulkBitsImpl(msbFirst,  0,  1,  1);
-        testBulkBitsImpl(msbFirst,  0,  1,  3);
-        testBulkBitsImpl(msbFirst,  0,  2,  8);
-        testBulkBitsImpl(msbFirst,  0,  8, 10);
-        testBulkBitsImpl(msbFirst,  0, 12, 20);
-        testBulkBitsImpl(msbFirst,  0, 23,  9);
-        testBulkBitsImpl(msbFirst,  0,  1, 31);
-
-        testBulkBitsImpl(msbFirst,  1,  1,  1);
-        testBulkBitsImpl(msbFirst,  2,  1,  3);
-        testBulkBitsImpl(msbFirst,  7,  2,  8);
-        testBulkBitsImpl(msbFirst,  8,  8,  8);
-        testBulkBitsImpl(msbFirst, 15, 12,  5);
-        testBulkBitsImpl(msbFirst, 16, 11,  5);
+    public void test03BulkBits() throws IOException {
+        testBulkBitsImpl(0,  0,  1);
+        testBulkBitsImpl(0,  0,  3);
+        testBulkBitsImpl(0,  0,  8);
+        testBulkBitsImpl(0,  0,  10);
+        testBulkBitsImpl(0,  0,  30);
+        testBulkBitsImpl(0,  0,  31);
+
+        testBulkBitsImpl(3,  0,  3);
+        testBulkBitsImpl(8,  0,  3);
+        testBulkBitsImpl(9,  0,  3);
+        testBulkBitsImpl(5,  0,  6);
+        testBulkBitsImpl(5,  0,  8);
+
+        testBulkBitsImpl(0,  1,  1);
+        testBulkBitsImpl(3,  6,  4);
+
+        testBulkBitsImpl(0,  1,  3);
+        testBulkBitsImpl(0,  2,  8);
+        testBulkBitsImpl(0,  8,  10);
+        testBulkBitsImpl(0,  12, 20);
+        testBulkBitsImpl(0,  23, 9);
+        testBulkBitsImpl(0,  1,  31);
+
+        testBulkBitsImpl(1,  1,  1);
+        testBulkBitsImpl(2,  1,  3);
+        testBulkBitsImpl(7,  2,  8);
+        testBulkBitsImpl(8,  8,  8);
+        testBulkBitsImpl(15, 12, 5);
+        testBulkBitsImpl(16, 11, 5);
+        testBulkBitsImpl(5,  6,  5);
+        testBulkBitsImpl(5,  6,  8);
     }
 
-    void testBulkBitsImpl(final boolean msbFirst, final int preBits, final int skipBits, final int postBits) throws IOException {
+    void testBulkBitsImpl(final int preBits, final int skipBits, final int postBits) throws IOException {
         final int totalBits = preBits+skipBits+postBits;
-        System.err.println("XXX TestBulkBits: msbFirst "+msbFirst+", preBits "+preBits+", skipBits "+skipBits+", postBits "+postBits+", totalBits "+totalBits);
+        System.err.println("XXX TestBulkBits: preBits "+preBits+", skipBits "+skipBits+", postBits "+postBits+", totalBits "+totalBits);
 
         // prepare bitstream
         System.err.println("Prepare bitstream");
-        final Bitstream<ByteBuffer> bsTest = getTestStream(msbFirst, preBits, skipBits, postBits);
-        dumpData("Test", bsTest.getSubStream(), 0, bsTest.getSubStream().limit());
-        final String sTest = getTestStreamResultAsString(msbFirst, preBits, skipBits, postBits);
+        final Bitstream<ByteBuffer> bsTest = getTestStream(true, false, preBits, skipBits, postBits);
+        final String sTest = getTestStreamResultAsString(true, false, preBits, skipBits, postBits);
 
         // init copy-bitstream
         final int byteCount = ( totalBits + 7 ) / 8;
@@ -273,18 +293,18 @@ public class TestBitstream01 extends JunitTracer {
         // read-bitstream .. and copy bits while reading
         System.err.println("Reading bitstream: "+bsTest);
         {
-            final int readBitsPre = bsTest.readBits31(msbFirst, preBits);
-            Assert.assertEquals(readBitsPre, bsCopy.writeBits31(msbFirst, preBits, readBitsPre));
+            final int readBitsPre = bsTest.readBits31(preBits);
+            Assert.assertEquals(readBitsPre, bsCopy.writeBits31(preBits, readBitsPre));
 
             final int skippedReadBits = (int) bsTest.skip(skipBits);
             final int skippedBitsCopy = (int) bsCopy.skip(skipBits);
 
-            final int readBitsPost = bsTest.readBits31(msbFirst, postBits);
-            Assert.assertEquals(readBitsPost, bsCopy.writeBits31(msbFirst, postBits, readBitsPost));
-            final String sReadPre = toBinaryString(readBitsPre, preBits);
-            final String sReadPost = toBinaryString(readBitsPost, postBits);
-            final String sRead = sReadPre + sReadPost;
-            System.err.println("Read.Test: <"+sReadPre+"> + <"+sReadPost+"> = <"+sRead+">");
+            final int readBitsPost = bsTest.readBits31(postBits);
+            Assert.assertEquals(readBitsPost, bsCopy.writeBits31(postBits, readBitsPost));
+            final String sReadPreLo = toBinaryString(readBitsPre, preBits);
+            final String sReadPostHi = toBinaryString(readBitsPost, postBits);
+            final String sRead = sReadPostHi + sReadPreLo;
+            System.err.println("Read.Test: <"+sReadPreLo+"> + <"+sReadPostHi+"> = <"+sRead+">");
 
             Assert.assertEquals(skipBits, skippedReadBits);
             Assert.assertEquals(sTest, sRead);
@@ -298,15 +318,15 @@ public class TestBitstream01 extends JunitTracer {
         System.err.println("Reading copy-bitstream: "+bsCopy);
         Assert.assertEquals(0, bsCopy.position());
         {
-            final int copyBitsPre = bsCopy.readBits31(msbFirst, preBits);
+            final int copyBitsPre = bsCopy.readBits31(preBits);
 
             final int skippedCopyBits = (int) bsCopy.skip(skipBits);
 
-            final int copyBitsPost = bsCopy.readBits31(msbFirst, postBits);
-            final String sCopyPre = toBinaryString(copyBitsPre, preBits);
-            final String sCopyPost = toBinaryString(copyBitsPost, postBits);
-            final String sCopy = sCopyPre + sCopyPost;
-            System.err.println("Copy.Test: <"+sCopyPre+"> + <"+sCopyPost+"> = <"+sCopy+">");
+            final int copyBitsPost = bsCopy.readBits31(postBits);
+            final String sCopyPreLo = toBinaryString(copyBitsPre, preBits);
+            final String sCopyPostHi = toBinaryString(copyBitsPost, postBits);
+            final String sCopy = sCopyPostHi + sCopyPreLo;
+            System.err.println("Copy.Test: <"+sCopyPreLo+"> + <"+sCopyPostHi+"> = <"+sCopy+">");
 
             Assert.assertEquals(skipBits, skippedCopyBits);
             Assert.assertEquals(sTest, sCopy);
@@ -317,7 +337,7 @@ public class TestBitstream01 extends JunitTracer {
     @Test
     public void test05ErrorHandling() throws IOException {
         // prepare bitstream
-        final Bitstream<ByteBuffer> bsTest = getTestStream(false, 0, 0, 0);
+        final Bitstream<ByteBuffer> bsTest = getTestStream(false, false, 0, 0, 0);
         System.err.println("01a: "+bsTest);
         bsTest.close();
         System.err.println("01b: "+bsTest);
diff --git a/src/junit/com/jogamp/common/util/TestBitstream02.java b/src/junit/com/jogamp/common/util/TestBitstream02.java
index e1a9eb0..16904a2 100644
--- a/src/junit/com/jogamp/common/util/TestBitstream02.java
+++ b/src/junit/com/jogamp/common/util/TestBitstream02.java
@@ -35,7 +35,7 @@ import org.junit.Assert;
 import org.junit.Test;
 
 import com.jogamp.common.nio.Buffers;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import static com.jogamp.common.util.BitstreamData.*;
 
@@ -51,7 +51,7 @@ import org.junit.runners.MethodSorters;
  * </ul>
  */
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestBitstream02 extends JunitTracer {
+public class TestBitstream02 extends SingletonJunitCase {
 
     @Test
     public void test01Int8BitsAligned() throws IOException {
@@ -71,17 +71,17 @@ public class TestBitstream02 extends JunitTracer {
         final Bitstream.ByteBufferStream bbs = new Bitstream.ByteBufferStream(bb);
         final Bitstream<ByteBuffer> bs = new Bitstream<ByteBuffer>(bbs, false /* outputMode */);
         {
-            final byte r8 = (byte) bs.readUInt8(true /* msbFirst */);
+            final byte r8 = (byte) bs.readUInt8();
             System.err.println("Read8.1 "+r8+", "+toHexBinaryString(r8, 8));
             Assert.assertEquals(val8, r8);
         }
 
         // Test with written bitstream value
         bs.setStream(bs.getSubStream(), true /* outputMode */);
-        bs.writeInt8(true /* msbFirst */, val8);
+        bs.writeInt8(val8);
         bs.setStream(bs.getSubStream(), false /* outputMode */); // switch to input-mode, implies flush()
         {
-            final byte r8 = (byte) bs.readUInt8(true /* msbFirst */);
+            final byte r8 = (byte) bs.readUInt8();
             System.err.println("Read8.2 "+r8+", "+toHexBinaryString(r8, 8));
             Assert.assertEquals(val8, r8);
         }
@@ -114,12 +114,12 @@ public class TestBitstream02 extends JunitTracer {
         // Test with written bitstream value
         final Bitstream.ByteBufferStream bbs = new Bitstream.ByteBufferStream(bb);
         final Bitstream<ByteBuffer> bs = new Bitstream<ByteBuffer>(bbs, true /* outputMode */);
-        bs.writeBits31(true /* msbFirst */, preBits, 0);
-        bs.writeInt8(true /* msbFirst */, val8);
+        bs.writeBits31(preBits, 0);
+        bs.writeInt8(val8);
         bs.setStream(bs.getSubStream(), false /* outputMode */); // switch to input-mode, implies flush()
 
-        final int rPre = (short) bs.readBits31(true /* msbFirst */, preBits);
-        final byte r8 = (byte) bs.readUInt8(true /* msbFirst */);
+        final int rPre = (short) bs.readBits31(preBits);
+        final byte r8 = (byte) bs.readUInt8();
         System.err.println("ReadPre "+rPre+", "+toBinaryString(rPre, preBits));
         System.err.println("Read8 "+r8+", "+toHexBinaryString(r8, 8));
         Assert.assertEquals(val8, r8);
diff --git a/src/junit/com/jogamp/common/util/TestBitstream03.java b/src/junit/com/jogamp/common/util/TestBitstream03.java
index 29debc8..a6129d8 100644
--- a/src/junit/com/jogamp/common/util/TestBitstream03.java
+++ b/src/junit/com/jogamp/common/util/TestBitstream03.java
@@ -36,7 +36,7 @@ import org.junit.Assert;
 import org.junit.Test;
 
 import com.jogamp.common.nio.Buffers;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import static com.jogamp.common.util.BitstreamData.*;
 
@@ -47,12 +47,12 @@ import org.junit.runners.MethodSorters;
  * Test {@link Bitstream} w/ int16 read/write access w/ semantics
  * as well as with aligned and unaligned access.
  * <ul>
- *  <li>{@link Bitstream#readUInt16(boolean, boolean)}</li>
- *  <li>{@link Bitstream#writeInt16(boolean, boolean, short)}</li>
+ *  <li>{@link Bitstream#readUInt16(boolean)}</li>
+ *  <li>{@link Bitstream#writeInt16(boolean, short)}</li>
  * </ul>
  */
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestBitstream03 extends JunitTracer {
+public class TestBitstream03 extends SingletonJunitCase {
 
     @Test
     public void test01Int16BitsAligned() throws IOException {
@@ -78,21 +78,23 @@ public class TestBitstream03 extends JunitTracer {
         final boolean bigEndian = ByteOrder.BIG_ENDIAN == bb.order();
         System.err.println("XXX Test01Int16BitsAligned: byteOrder "+byteOrder+" (bigEndian "+bigEndian+"), value "+val16+", "+toHexBinaryString(val16, 16));
         bb.putShort(0, val16);
+        dumpData("TestData.1: ", bb, 0, 2);
 
         final Bitstream.ByteBufferStream bbs = new Bitstream.ByteBufferStream(bb);
         final Bitstream<ByteBuffer> bs = new Bitstream<ByteBuffer>(bbs, false /* outputMode */);
         {
-            final short r16 = (short) bs.readUInt16(true /* msbFirst */, bigEndian);
+            final short r16 = (short) bs.readUInt16(bigEndian);
             System.err.println("Read16.1 "+r16+", "+toHexBinaryString(r16, 16));
             Assert.assertEquals(val16, r16);
         }
 
         // Test with written bitstream value
         bs.setStream(bs.getSubStream(), true /* outputMode */);
-        bs.writeInt16(true /* msbFirst */, bigEndian, val16);
+        bs.writeInt16(bigEndian, val16);
         bs.setStream(bs.getSubStream(), false /* outputMode */); // switch to input-mode, implies flush()
+        dumpData("TestData.2: ", bb, 0, 2);
         {
-            final short r16 = (short) bs.readUInt16(true /* msbFirst */, bigEndian);
+            final short r16 = (short) bs.readUInt16(bigEndian);
             System.err.println("Read16.2 "+r16+", "+toHexBinaryString(r16, 16));
             Assert.assertEquals(val16, r16);
         }
@@ -135,12 +137,13 @@ public class TestBitstream03 extends JunitTracer {
         // Test with written bitstream value
         final Bitstream.ByteBufferStream bbs = new Bitstream.ByteBufferStream(bb);
         final Bitstream<ByteBuffer> bs = new Bitstream<ByteBuffer>(bbs, true /* outputMode */);
-        bs.writeBits31(true /* msbFirst */, preBits, 0);
-        bs.writeInt16(true /* msbFirst */, bigEndian, val16);
+        bs.writeBits31(preBits, 0);
+        bs.writeInt16(bigEndian, val16);
         bs.setStream(bs.getSubStream(), false /* outputMode */); // switch to input-mode, implies flush()
+        dumpData("TestData.1: ", bb, 0, byteCount);
 
-        final int rPre = (short) bs.readBits31(true /* msbFirst */, preBits);
-        final short r16 = (short) bs.readUInt16(true /* msbFirst */, bigEndian);
+        final int rPre = (short) bs.readBits31(preBits);
+        final short r16 = (short) bs.readUInt16(bigEndian);
         System.err.println("ReadPre "+rPre+", "+toBinaryString(rPre, preBits));
         System.err.println("Read16 "+r16+", "+toHexBinaryString(r16, 16));
         Assert.assertEquals(val16, r16);
diff --git a/src/junit/com/jogamp/common/util/TestBitstream04.java b/src/junit/com/jogamp/common/util/TestBitstream04.java
index f61ebea..47be38d 100644
--- a/src/junit/com/jogamp/common/util/TestBitstream04.java
+++ b/src/junit/com/jogamp/common/util/TestBitstream04.java
@@ -36,7 +36,7 @@ import org.junit.Assert;
 import org.junit.Test;
 
 import com.jogamp.common.nio.Buffers;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import static com.jogamp.common.util.BitstreamData.*;
 
@@ -47,12 +47,12 @@ import org.junit.runners.MethodSorters;
  * Test {@link Bitstream} w/ int32 read/write access w/ semantics
  * as well as with aligned and unaligned access.
  * <ul>
- *  <li>{@link Bitstream#readUInt32(boolean, boolean)}</li>
- *  <li>{@link Bitstream#writeInt32(boolean, boolean, int)}</li>
+ *  <li>{@link Bitstream#readUInt32(boolean)}</li>
+ *  <li>{@link Bitstream#writeInt32(boolean, int)}</li>
  * </ul>
  */
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestBitstream04 extends JunitTracer {
+public class TestBitstream04 extends SingletonJunitCase {
 
     @Test
     public void test01Int32BitsAligned() throws IOException {
@@ -82,11 +82,12 @@ public class TestBitstream04 extends JunitTracer {
         System.err.println("XXX Test01Int32BitsAligned: "+val32+", "+val32_hs);
 
         bb.putInt(0, val32);
+        dumpData("TestData.1: ", bb, 0, 4);
 
         final Bitstream.ByteBufferStream bbs = new Bitstream.ByteBufferStream(bb);
         final Bitstream<ByteBuffer> bs = new Bitstream<ByteBuffer>(bbs, false /* outputMode */);
         {
-            final long uint32_l = bs.readUInt32(true /* msbFirst */, bigEndian);
+            final long uint32_l = bs.readUInt32(bigEndian);
             final int int32_l = (int)uint32_l;
             final String uint32_l_hs = toHexString(uint32_l);
             final int uint32_i = Bitstream.uint32LongToInt(uint32_l);
@@ -99,10 +100,11 @@ public class TestBitstream04 extends JunitTracer {
 
         // Test with written bitstream value
         bs.setStream(bs.getSubStream(), true /* outputMode */);
-        bs.writeInt32(true /* msbFirst */, bigEndian, val32);
+        bs.writeInt32(bigEndian, val32);
         bs.setStream(bs.getSubStream(), false /* outputMode */); // switch to input-mode, implies flush()
+        dumpData("TestData.2: ", bb, 0, 4);
         {
-            final long uint32_l = bs.readUInt32(true /* msbFirst */, bigEndian);
+            final long uint32_l = bs.readUInt32(bigEndian);
             final int int32_l = (int)uint32_l;
             final String uint32_l_hs = toHexString(uint32_l);
             final int uint32_i = Bitstream.uint32LongToInt(uint32_l);
@@ -154,12 +156,12 @@ public class TestBitstream04 extends JunitTracer {
         // Test with written bitstream value
         final Bitstream.ByteBufferStream bbs = new Bitstream.ByteBufferStream(bb);
         final Bitstream<ByteBuffer> bs = new Bitstream<ByteBuffer>(bbs, true /* outputMode */);
-        bs.writeBits31(true /* msbFirst */, preBits, 0);
-        bs.writeInt32(true /* msbFirst */, bigEndian, val32);
+        bs.writeBits31(preBits, 0);
+        bs.writeInt32(bigEndian, val32);
         bs.setStream(bs.getSubStream(), false /* outputMode */); // switch to input-mode, implies flush()
 
-        final int rPre = bs.readBits31(true /* msbFirst */, preBits);
-        final long uint32_l = bs.readUInt32(true /* msbFirst */, bigEndian);
+        final int rPre = bs.readBits31(preBits);
+        final long uint32_l = bs.readUInt32(bigEndian);
         final int int32_l = (int)uint32_l;
         final String uint32_l_hs = toHexString(uint32_l);
         final int uint32_i = Bitstream.uint32LongToInt(uint32_l);
diff --git a/src/junit/com/jogamp/common/util/TestFloatStack01.java b/src/junit/com/jogamp/common/util/TestFloatStack01.java
index c0c1a2f..7a22a44 100644
--- a/src/junit/com/jogamp/common/util/TestFloatStack01.java
+++ b/src/junit/com/jogamp/common/util/TestFloatStack01.java
@@ -35,13 +35,13 @@ import java.util.Arrays;
 import org.junit.Assert;
 import org.junit.Test;
 
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class /*testname*/TestFloatStack01/*testname*/ extends JunitTracer {
+public class /*testname*/TestFloatStack01/*testname*/ extends SingletonJunitCase {
 
     static final boolean equals(final /*value*/float/*value*/[] b, final int bOffset,
                                 final /*value*/float/*value*/[] stack, final int stackOffset, final int length) {
diff --git a/src/junit/com/jogamp/common/util/TestIOUtil01.java b/src/junit/com/jogamp/common/util/TestIOUtil01.java
index 2a9c857..e85aa37 100644
--- a/src/junit/com/jogamp/common/util/TestIOUtil01.java
+++ b/src/junit/com/jogamp/common/util/TestIOUtil01.java
@@ -38,21 +38,22 @@ import java.io.OutputStream;
 import java.net.URLConnection;
 import java.nio.ByteBuffer;
 
+import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import com.jogamp.common.os.MachineDescription;
+import com.jogamp.common.os.MachineDataInfo;
 import com.jogamp.common.os.Platform;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestIOUtil01 extends JunitTracer {
+public class TestIOUtil01 extends SingletonJunitCase {
 
-    static final MachineDescription machine = Platform.getMachineDescription();
+    static final MachineDataInfo machine = Platform.getMachineDataInfo();
     static final int tsz = machine.pageSizeInBytes() + machine.pageSizeInBytes() / 2 ;
     static final byte[] orig = new byte[tsz];
     static final String tfilename = "./test.bin" ;
@@ -60,6 +61,7 @@ public class TestIOUtil01 extends JunitTracer {
     @BeforeClass
     public static void setup() throws IOException {
         final File tfile = new File(tfilename);
+        tfile.deleteOnExit();
         final OutputStream tout = new BufferedOutputStream(new FileOutputStream(tfile));
         for(int i=0; i<tsz; i++) {
             final byte b = (byte) (i%256);
@@ -69,6 +71,12 @@ public class TestIOUtil01 extends JunitTracer {
         tout.close();
     }
 
+    @AfterClass
+    public static void cleanup() {
+        final File tfile = new File(tfilename);
+        tfile.delete();
+    }
+
     @Test
     public void testCopyStream01Array() throws IOException {
         final URLConnection urlConn = IOUtil.getResource(this.getClass(), tfilename);
@@ -109,21 +117,26 @@ public class TestIOUtil01 extends JunitTracer {
         Assert.assertNotNull(urlConn1);
 
         final File file2 = new File(tfilename2);
-        IOUtil.copyURLConn2File(urlConn1, file2);
-        final URLConnection urlConn2 = IOUtil.getResource(this.getClass(), tfilename2);
-        Assert.assertNotNull(urlConn2);
-
-        final BufferedInputStream bis = new BufferedInputStream( urlConn2.getInputStream() );
-        final ByteBuffer bb;
+        file2.deleteOnExit();
         try {
-            bb = IOUtil.copyStream2ByteBuffer( bis );
+            IOUtil.copyURLConn2File(urlConn1, file2);
+            final URLConnection urlConn2 = IOUtil.getResource(this.getClass(), tfilename2);
+            Assert.assertNotNull(urlConn2);
+
+            final BufferedInputStream bis = new BufferedInputStream( urlConn2.getInputStream() );
+            final ByteBuffer bb;
+            try {
+                bb = IOUtil.copyStream2ByteBuffer( bis );
+            } finally {
+                IOUtil.close(bis, false);
+            }
+            Assert.assertEquals("Byte number not equal orig vs buffer", orig.length, bb.limit());
+            int i;
+            for(i=tsz-1; i>=0 && orig[i]==bb.get(i); i--) ;
+            Assert.assertTrue("Bytes not equal orig vs array", 0>i);
         } finally {
-            IOUtil.close(bis, false);
+            file2.delete();
         }
-        Assert.assertEquals("Byte number not equal orig vs buffer", orig.length, bb.limit());
-        int i;
-        for(i=tsz-1; i>=0 && orig[i]==bb.get(i); i--) ;
-        Assert.assertTrue("Bytes not equal orig vs array", 0>i);
     }
 
     public static void main(final String args[]) throws IOException {
diff --git a/src/junit/com/jogamp/common/util/TestIOUtilURIHandling.java b/src/junit/com/jogamp/common/util/TestIOUtilURIHandling.java
deleted file mode 100644
index 66dbacf..0000000
--- a/src/junit/com/jogamp/common/util/TestIOUtilURIHandling.java
+++ /dev/null
@@ -1,393 +0,0 @@
-package com.jogamp.common.util;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.net.URLConnection;
-
-import jogamp.common.os.PlatformPropsImpl;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-import com.jogamp.common.net.URIDumpUtil;
-import com.jogamp.common.os.Platform;
-import com.jogamp.common.util.IOUtil;
-import com.jogamp.junit.util.JunitTracer;
-
-import org.junit.FixMethodOrder;
-import org.junit.runners.MethodSorters;
-
- at FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestIOUtilURIHandling extends JunitTracer {
-
-    // Bug 908, issues w/ windows file path char: $ ^ ~ # [ ]
-
-    public static final String[][] uriHttpSArray = new String[][] {
-        new String[] {"http://localhost/gluegen/build-x86_64/gluegen-rt.jar"},
-
-        new String[] {"http://localhost/gluegen/"+'\u0394'+"/gluegen-rt.jar"},
-
-        new String[] {"http://localhost/gluegen/build-x86_64%20lala/gluegen-rt.jar"},
-
-        new String[] {"http://localhost/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar"},
-
-        new String[] {"jar:http://localhost/gluegen/build-x86_64/gluegen-rt.jar!/"},
-
-        new String[] {"jar:http://localhost/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/"},
-
-        new String[] {"jar:http://localhost/gluegen/build-x86_64/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
-
-        new String[] {"jar:http://localhost/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
-
-        new String[] {"jar:http://localhost/gluegen/R%23/gluegen-rt.jar!/"},
-
-        new String[] {"jar:http://localhost/gluegen/"+'\u0394'+"/gluegen-rt.jar!/"},
-    };
-
-    public static final String[][] uriFileSArrayUnix = new String[][] {
-        new String[] {"file:/gluegen/build-x86_64/gluegen-rt.jar"},
-
-        new String[] {"file:/gluegen/"+'\u0394'+"/gluegen-rt.jar"},
-
-        new String[] {"file:/gluegen/build-x86_64%20lala/gluegen-rt.jar"},
-
-        new String[] {"file:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar"},
-
-        new String[] {"jar:file:/gluegen/build-x86_64/gluegen-rt.jar!/"},
-
-        new String[] {"jar:file:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/"},
-
-        new String[] {"jar:file:/gluegen/build-x86_64/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
-
-        new String[] {"jar:file:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
-
-        new String[] {"jar:file://filehost/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
-
-        new String[] {"jar:file:/gluegen/R%23/gluegen-rt.jar!/"},
-
-        new String[] {"jar:file:/gluegen/"+'\u0394'+"/gluegen-rt.jar!/"},
-    };
-
-    public static final String[][] uriFileSArrayWindows = new String[][] {
-        new String[] {"file:/C:/gluegen/build-x86_64/gluegen-rt.jar"},
-        new String[] {"file:/C%3A/gluegen/build-x86_64/gluegen-rt.jar"},
-
-        new String[] {"file:/C:/gluegen/"+'\u0394'+"/gluegen-rt.jar"},
-
-        new String[] {"file:/C:/gluegen/build-x86_64%20lala/gluegen-rt.jar"},
-
-        new String[] {"file:/C:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar"},
-
-        new String[] {"jar:file:/C:/gluegen/build-x86_64/gluegen-rt.jar!/"},
-
-        new String[] {"jar:file:/C:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/"},
-
-        new String[] {"jar:file:/C:/gluegen/build-x86_64/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
-
-        new String[] {"jar:file:/C:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
-        new String[] {"jar:file:/C%3A/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
-
-        new String[] {"jar:file:///C:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
-
-        new String[] {"jar:file://filehost/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar!/com/jogamp/common/os/Platform.class"},
-
-        new String[] {"jar:file:/C:/gluegen/R%23/gluegen-rt.jar!/"},
-
-        new String[] {"jar:file:/C:/gluegen/"+'\u0394'+"/gluegen-rt.jar!/"},
-    };
-
-    public static final String[][] fileSArrayUnix = new String[][] {
-        new String[] {"/gluegen/build-x86_64/gluegen-rt.jar",
-                      "file:/gluegen/build-x86_64/gluegen-rt.jar",
-                      "/gluegen/build-x86_64/gluegen-rt.jar"},
-
-        new String[] {"/gluegen/"+'\u0394'+"/gluegen-rt.jar",
-                      "file:/gluegen/"+'\u0394'+"/gluegen-rt.jar",
-                      "/gluegen/"+'\u0394'+"/gluegen-rt.jar"},
-
-        new String[] {"/gluegen/build-x86_64 lala/gluegen-rt.jar",
-                      "file:/gluegen/build-x86_64%20lala/gluegen-rt.jar",
-                      "/gluegen/build-x86_64 lala/gluegen-rt.jar"},
-
-        new String[] {"/gluegen/build-x86_64 öä lala/gluegen-rt.jar",
-                      "file:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar",
-                      "/gluegen/build-x86_64 öä lala/gluegen-rt.jar"},
-
-        new String[] {"/gluegen/A$/B^/C~/D#/E[/F]/gluegen-rt.jar",
-                      // "file:/gluegen/A%24/B%5E/C%7E/D%23/E%5B/F%5D/gluegen-rt.jar", // goal w/ new Uri class
-                         "file:/gluegen/A$/B%5E/C~/D%23/E%5B/F%5D/gluegen-rt.jar",     // current Java URI/URL decoding
-                      "/gluegen/A$/B^/C~/D#/E[/F]/gluegen-rt.jar" },                // goal w/ new Uri class
-
-        new String[] {"/gluegen/$/^/~/#/[/]/gluegen-rt.jar",
-                      // "file:/gluegen/%24/%5E/%7E/%23/%5B/%5D/gluegen-rt.jar",
-                         "file:/gluegen/$/%5E/~/%23/%5B/%5D/gluegen-rt.jar",           // current Java URI/URL decoding
-                      "/gluegen/$/^/~/#/[/]/gluegen-rt.jar" },
-    };
-
-    public static final String[][] fileSArrayWindows = new String[][] {
-        new String[] {"C:/gluegen/build-x86_64/gluegen-rt.jar",
-                      // "file:/C%3A/gluegen/build-x86_64/gluegen-rt.jar",
-                         "file:/C:/gluegen/build-x86_64/gluegen-rt.jar",
-                      "C:\\gluegen\\build-x86_64\\gluegen-rt.jar"},
-
-        new String[] {"C:/gluegen/"+'\u0394'+"/gluegen-rt.jar",
-                      // "file:/C%3A/gluegen/"+'\u0394'+"/gluegen-rt.jar",
-                         "file:/C:/gluegen/"+'\u0394'+"/gluegen-rt.jar",
-                      "C:\\gluegen\\"+'\u0394'+"\\gluegen-rt.jar"},
-
-        new String[] {"C:/gluegen/build-x86_64 lala/gluegen-rt.jar",
-                      // "file:/C%3A/gluegen/build-x86_64%20lala/gluegen-rt.jar",
-                         "file:/C:/gluegen/build-x86_64%20lala/gluegen-rt.jar",
-                      "C:\\gluegen\\build-x86_64 lala\\gluegen-rt.jar"},
-
-        new String[] {"C:/gluegen/build-x86_64 öä lala/gluegen-rt.jar",
-                      // "file:/C%3A/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar",
-                         "file:/C:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar",
-                      "C:\\gluegen\\build-x86_64 öä lala\\gluegen-rt.jar"},
-
-        new String[] {"C:\\gluegen\\build-x86_64 öä lala\\gluegen-rt.jar",
-                      // "file:/C%3A/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar",
-                      "file:/C:/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar",
-                      "C:\\gluegen\\build-x86_64 öä lala\\gluegen-rt.jar"},
-
-        new String[] {"\\\\filehost\\gluegen\\build-x86_64 öä lala\\gluegen-rt.jar",
-                      "file:////filehost/gluegen/build-x86_64%20öä%20lala/gluegen-rt.jar",
-                      "\\\\filehost\\gluegen\\build-x86_64 öä lala\\gluegen-rt.jar"},
-
-        new String[] {"C:/gluegen/A$/B^/C~/D#/E[/F]/gluegen-rt.jar",
-                      // "file:/C%3A/gluegen/A%24/B%5E/C%7E/D%23/E%5B/F%5D/gluegen-rt.jar",
-                         "file:/C:/gluegen/A$/B%5E/C~/D%23/E%5B/F%5D/gluegen-rt.jar",
-                      "C:\\gluegen\\A$\\B^\\C~\\D#\\E[\\F]\\gluegen-rt.jar" },
-
-        new String[] {"C:/gluegen/$/^/~/#/[/]/gluegen-rt.jar",
-                      // "file:/C%3A/gluegen/%24/%5E/%7E/%23/%5B/%5D/gluegen-rt.jar",
-                         "file:/C:/gluegen/$/%5E/~/%23/%5B/%5D/gluegen-rt.jar",        // current Java URI/URL decoding
-                      "C:\\gluegen\\$\\^\\~\\#\\[\\]\\gluegen-rt.jar" },
-    };
-
-    @Test
-    public void test00BasicCoding() throws IOException, URISyntaxException {
-        final String string = "Hallo Welt öä";
-        System.err.println("sp1 "+string);
-        final File file = new File(string);
-        System.err.println("file "+file);
-        System.err.println("file.path.dec "+file.getPath());
-        System.err.println("file.path.abs "+file.getAbsolutePath());
-        System.err.println("file.path.can "+file.getCanonicalPath());
-        final URI uri0 = file.toURI();
-        System.err.println("uri0.string: "+uri0.toString());
-        System.err.println("uri0.path  : "+uri0.getPath());
-        System.err.println("uri0.ascii : "+uri0.toASCIIString());
-        boolean ok = true;
-        {
-            final URI uri1 = IOUtil.toURISimple(file);
-            final boolean equalString= uri0.toString().equals(uri1.toString());
-            final boolean equalPath = uri0.getPath().equals(uri1.getPath());
-            final boolean equalASCII= uri0.toASCIIString().equals(uri1.toASCIIString());
-            System.err.println("uri1.string: "+uri1.toString()+" - "+(equalString?"OK":"ERROR"));
-            System.err.println("uri1.path  : "+uri1.getPath()+" - "+(equalPath?"OK":"ERROR"));
-            System.err.println("uri1.ascii : "+uri1.toASCIIString()+" - "+(equalASCII?"OK":"ERROR"));
-            ok = equalString && equalPath && equalASCII && ok;
-        }
-        {
-            final String s2 = IOUtil.slashify(file.getAbsolutePath(), true /* startWithSlash */, file.isDirectory() /* endWithSlash */);
-            System.err.println("uri2.slashify: "+s2);
-            {
-                // Expected !equals due to double-escaping of space %20 -> %25%20
-                // Double escaping is due to IOUtil.encodeToURI(s2).
-                @SuppressWarnings("deprecation")
-                final String s3 = IOUtil.encodeToURI(s2);
-                System.err.println("uri2.encoded: "+s3);
-                final URI uri1 = new URI(IOUtil.FILE_SCHEME, null, s3, null);
-                final boolean equalString= uri0.toString().equals(uri1.toString());
-                final boolean equalPath = uri0.getPath().equals(uri1.getPath());
-                final boolean equalASCII= uri0.toASCIIString().equals(uri1.toASCIIString());
-                System.err.println("uri2.string: "+uri1.toString()+" - "+(equalString?"ERROR EQUAL":"OK NOT_EQUAL"));
-                System.err.println("uri2.path  : "+uri1.getPath()+" - "+(equalPath?"ERROR EQUAL":"OK NOT_EQUAL"));
-                System.err.println("uri2.ascii : "+uri1.toASCIIString()+" - "+(equalASCII?"ERROR EQUAL":"OK NOT_EQUAL"));
-                ok = !equalString && !equalPath && !equalASCII && ok;
-            }
-            final URI uri1 = new URI(IOUtil.FILE_SCHEME, null, s2, null);
-            final boolean equalString= uri0.toString().equals(uri1.toString());
-            final boolean equalPath = uri0.getPath().equals(uri1.getPath());
-            final boolean equalASCII= uri0.toASCIIString().equals(uri1.toASCIIString());
-            System.err.println("uri2.string: "+uri1.toString()+" - "+(equalString?"OK":"ERROR"));
-            System.err.println("uri2.path  : "+uri1.getPath()+" - "+(equalPath?"OK":"ERROR"));
-            System.err.println("uri2.ascii : "+uri1.toASCIIString()+" - "+(equalASCII?"OK":"ERROR"));
-            ok = equalString && equalPath && equalASCII && ok;
-        }
-        {
-            final String s2 = "/"+string;
-            System.err.println("uri3.orig: "+s2);
-            final URI uri1 = new URI(IOUtil.FILE_SCHEME, s2, null);
-            final String rString = "file:/Hallo%20Welt%20öä";
-            final String rPath = s2;
-            final String rASCII = "file:/Hallo%20Welt%20%C3%B6%C3%A4";
-            final boolean equalString= rString.equals(uri1.toString());
-            final boolean equalPath = rPath.equals(uri1.getPath());
-            final boolean equalASCII= rASCII.equals(uri1.toASCIIString());
-            System.err.println("uri3.string: "+uri1.toString()+" - "+(equalString?"OK":"ERROR"));
-            System.err.println("uri3.path  : "+uri1.getPath()+" - "+(equalPath?"OK":"ERROR"));
-            System.err.println("uri3.ascii : "+uri1.toASCIIString()+" - "+(equalASCII?"OK":"ERROR"));
-            ok = equalString && equalPath && equalASCII && ok;
-        }
-        {
-            final String s2 = "//lala.org/"+string;
-            System.err.println("uri4.orig: "+s2);
-            final URI uri1 = new URI(IOUtil.HTTP_SCHEME, s2, null);
-            final String rString = "http://lala.org/Hallo%20Welt%20öä";
-            final String rPath = "/"+string;
-            final String rASCII = "http://lala.org/Hallo%20Welt%20%C3%B6%C3%A4";
-            final boolean equalString= rString.equals(uri1.toString());
-            final boolean equalPath = rPath.equals(uri1.getPath());
-            final boolean equalASCII= rASCII.equals(uri1.toASCIIString());
-            System.err.println("uri4.string: "+uri1.toString()+" - "+(equalString?"OK":"ERROR"));
-            System.err.println("uri4.path  : "+uri1.getPath()+" - "+(equalPath?"OK":"ERROR"));
-            System.err.println("uri4.ascii : "+uri1.toASCIIString()+" - "+(equalASCII?"OK":"ERROR"));
-            ok = equalString && equalPath && equalASCII && ok;
-        }
-        Assert.assertTrue("One or more errors occured see stderr above", ok);
-    }
-
-    @Test
-    public void test01HttpURI2URL() throws IOException, URISyntaxException {
-        testURI2URL(getSimpleTestName("."), uriHttpSArray);
-    }
-
-    @Test
-    public void test02FileUnixURI2URL() throws IOException, URISyntaxException {
-        testURI2URL(getSimpleTestName("."), uriFileSArrayUnix);
-    }
-
-    @Test
-    public void test03FileWindowsURI2URL() throws IOException, URISyntaxException {
-        testURI2URL(getSimpleTestName("."), uriFileSArrayWindows);
-    }
-
-    @Test
-    public void test04FileUnixURI2URL() throws IOException, URISyntaxException {
-        if( Platform.OSType.WINDOWS != PlatformPropsImpl.OS_TYPE ) {
-            testFile2URI(getSimpleTestName("."), fileSArrayUnix);
-        }
-    }
-
-    @Test
-    public void test05FileWindowsURI2URL() throws IOException, URISyntaxException {
-        if( Platform.OSType.WINDOWS == PlatformPropsImpl.OS_TYPE ) {
-            testFile2URI(getSimpleTestName("."), fileSArrayWindows);
-        }
-    }
-
-    static void testURI2URL(final String testname, final String[][] uriSArray) throws IOException, URISyntaxException {
-        boolean ok = true;
-        for(int i=0; i<uriSArray.length; i++) {
-            final String[] uriSPair = uriSArray[i];
-            final String uriSource = uriSPair[0];
-            System.err.println("SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS "+testname+": "+(i+1)+"/"+uriSArray.length);
-            ok = testURI2URL(uriSource) && ok;
-            System.err.println("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE "+testname+": "+(i+1)+"/"+uriSArray.length);
-        }
-        Assert.assertTrue("One or more errors occured see stderr above", ok);
-    }
-
-    static boolean testURI2URL(final String uriSource) throws IOException, URISyntaxException {
-        final URI uri0 = new URI(uriSource);
-        URIDumpUtil.showURI(uri0);
-
-        final String expected1 = uriSource.toString();
-        final String expected2 = expected1.replaceFirst("///", "/");
-        System.err.println("expected__s0: "+uriSource);
-        System.err.println("expected__d1: "+expected1);
-        System.err.println("expected__d2: "+expected2);
-
-        final URL actualURL = uri0.toURL();
-        final String actualURLStr = actualURL.toString();
-        final boolean equalsURLSrc = uriSource.equals(actualURLStr);
-        final boolean equalsURLDec1 = expected1.equals(actualURLStr);
-        final boolean equalsURLDec2 = expected2.equals(actualURLStr);
-        final boolean equalsURL = equalsURLSrc || equalsURLDec1 || equalsURLDec2;
-        System.err.println("actual      : "+actualURLStr+" - "+(equalsURL?"OK":"ERROR")+
-                " - equalSrc "+equalsURLSrc+", equalDec1 "+equalsURLDec1+", equalDec2 "+equalsURLDec2);
-
-        final boolean ok = equalsURL;
-
-        // now test open ..
-        Throwable t = null;
-        URLConnection con = null;
-        try {
-            con = actualURL.openConnection();
-        } catch (final Throwable _t) {
-            t = _t;
-        }
-        if( null != t ) {
-            System.err.println("XXX: "+t.getClass().getName()+": "+t.getMessage());
-            t.printStackTrace();
-        } else {
-            System.err.println("XXX: No openConnection() failure");
-            System.err.println("XXX: "+con);
-        }
-        return ok;
-    }
-
-    static void testFile2URI(final String testname, final String[][] uriSArray) throws IOException, URISyntaxException {
-        boolean ok = true;
-        for(int i=0; i<uriSArray.length; i++) {
-            final String[] uriSPair = uriSArray[i];
-            final String uriSource = uriSPair[0];
-            final String uriEncExpected= uriSPair[1];
-            final String fileExpected= uriSPair[2];
-            System.err.println("SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS "+testname+": "+(i+1)+"/"+uriSArray.length);
-            ok = testFile2URI(uriSource, uriEncExpected, fileExpected) && ok;
-            System.err.println("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE "+testname+": "+(i+1)+"/"+uriSArray.length);
-        }
-        Assert.assertTrue("One or more errors occured see stderr above", ok);
-    }
-
-    static boolean testFile2URI(final String fileSource, final String uriEncExpected, final String fileExpected) throws IOException, URISyntaxException {
-        System.err.println("fileSource:         "+fileSource);
-        final File file = new File(fileSource);
-        System.err.println("file:               "+file.getAbsolutePath());
-
-        final URI uri0 = IOUtil.toURISimple(file);
-        final URI uri1 = file.toURI();
-        URIDumpUtil.showURI(uri0);
-        URIDumpUtil.showURI(uri1);
-
-        final URL actualUrl = uri1.toURL();
-        final String actualFileS = IOUtil.decodeURIIfFilePath(uri1);
-        final boolean equalsFilePath = fileExpected.equals(actualFileS);
-        System.err.println("expected_path:      "+fileExpected);
-        System.err.println("actual___file-path: "+actualFileS+" - "+(equalsFilePath?"OK":"ERROR"));
-        final boolean equalsEncUri = uriEncExpected.equals(uri1.toString());
-        System.err.println("expected__encUri:   "+uriEncExpected);
-        System.err.println("actual_______Uri:   "+uri1.toString()+" - "+(equalsEncUri?"OK":"ERROR"));
-        final boolean ok = equalsEncUri && equalsFilePath;
-
-        System.err.println("actual_______URL:   "+actualUrl.toExternalForm());
-
-        // now test open ..
-        Throwable t = null;
-        URLConnection con = null;
-        try {
-            con = actualUrl.openConnection();
-        } catch (final Throwable _t) {
-            t = _t;
-        }
-        if( null != t ) {
-            System.err.println("XXX: "+t.getClass().getName()+": "+t.getMessage());
-            t.printStackTrace();
-        } else {
-            System.err.println("XXX: No openConnection() failure");
-            System.err.println("XXX: "+con);
-        }
-        return ok;
-    }
-
-    public static void main(final String args[]) throws IOException {
-        final String tstname = TestIOUtilURIHandling.class.getName();
-        org.junit.runner.JUnitCore.main(tstname);
-    }
-}
diff --git a/src/junit/com/jogamp/common/util/TestIteratorIndexCORE.java b/src/junit/com/jogamp/common/util/TestIteratorIndexCORE.java
index 110d1cd..8289587 100644
--- a/src/junit/com/jogamp/common/util/TestIteratorIndexCORE.java
+++ b/src/junit/com/jogamp/common/util/TestIteratorIndexCORE.java
@@ -34,13 +34,13 @@ import java.io.IOException;
 import org.junit.Test;
 
 import com.jogamp.common.os.Platform;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestIteratorIndexCORE extends JunitTracer {
+public class TestIteratorIndexCORE extends SingletonJunitCase {
 
     static int elems = 10;
     static int loop = ( Platform.getCPUFamily() == Platform.CPUFamily.ARM ) ? 20 : 9999999;
diff --git a/src/junit/com/jogamp/common/util/TestJarUtil.java b/src/junit/com/jogamp/common/util/TestJarUtil.java
index db5c268..747da8f 100644
--- a/src/junit/com/jogamp/common/util/TestJarUtil.java
+++ b/src/junit/com/jogamp/common/util/TestJarUtil.java
@@ -30,7 +30,6 @@ package com.jogamp.common.util;
 
 import java.io.IOException;
 import java.net.MalformedURLException;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLClassLoader;
@@ -46,17 +45,19 @@ import org.junit.BeforeClass;
 import org.junit.Test;
 
 import com.jogamp.common.GlueGenVersion;
+import com.jogamp.common.net.URIDumpUtil;
+import com.jogamp.common.net.Uri;
 import com.jogamp.common.os.AndroidVersion;
 import com.jogamp.common.util.cache.TempCacheReg;
 import com.jogamp.common.util.cache.TempFileCache;
 import com.jogamp.common.util.cache.TempJarCache;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestJarUtil extends JunitTracer {
+public class TestJarUtil extends SingletonJunitCase {
     static TempFileCache fileCache;
 
     @BeforeClass
@@ -97,7 +98,7 @@ public class TestJarUtil extends JunitTracer {
         }
     }
 
-    void validateJarFileURL(final URI jarFileURI) throws IllegalArgumentException, IOException, URISyntaxException {
+    void validateJarFileURL(final Uri jarFileURI) throws IllegalArgumentException, IOException, URISyntaxException {
         Assert.assertNotNull(jarFileURI);
         final URL jarFileURL = jarFileURI.toURL();
         final URLConnection aURLc = jarFileURL.openConnection();
@@ -110,18 +111,27 @@ public class TestJarUtil extends JunitTracer {
     }
 
     void validateJarUtil(final String expJarName, final String clazzBinName, final ClassLoader cl) throws IllegalArgumentException, IOException, URISyntaxException {
-        final String jarName= JarUtil.getJarBasename(clazzBinName, cl);
+        final Uri.Encoded expJarNameE = Uri.Encoded.cast(expJarName);
+        final Uri.Encoded jarName= JarUtil.getJarBasename(clazzBinName, cl);
         Assert.assertNotNull(jarName);
-        Assert.assertEquals(expJarName, jarName);
+        Assert.assertEquals(expJarNameE, jarName);
 
-        final URI jarSubURI = JarUtil.getJarSubURI(clazzBinName, cl);
-        Assert.assertNotNull(jarSubURI);
-        final URL jarSubURL= jarSubURI.toURL();
+        final Uri jarUri = JarUtil.getJarUri(clazzBinName, cl);
+        Assert.assertNotNull(jarUri);
+        System.err.println("1 - jarUri:");
+        URIDumpUtil.showUri(jarUri);
+
+        final Uri jarSubUri = jarUri.getContainedUri();
+        Assert.assertNotNull(jarSubUri);
+        System.err.println("2 - jarSubUri:");
+        URIDumpUtil.showUri(jarSubUri);
+
+        final URL jarSubURL= jarSubUri.toURL();
         final URLConnection urlConn = jarSubURL.openConnection();
         Assert.assertTrue("jarSubURL has zero content: "+jarSubURL, urlConn.getContentLength()>0);
         System.err.println("URLConnection of jarSubURL: "+urlConn);
 
-        final URI jarFileURL = JarUtil.getJarFileURI(clazzBinName, cl);
+        final Uri jarFileURL = JarUtil.getJarFileUri(clazzBinName, cl);
         validateJarFileURL(jarFileURL);
 
         final JarFile jarFile = JarUtil.getJarFile(clazzBinName, cl);
@@ -146,10 +156,10 @@ public class TestJarUtil extends JunitTracer {
         final ClassLoader rootCL = this.getClass().getClassLoader();
 
         // Get containing JAR file "TestJarsInJar.jar" and add it to the TempJarCache
-        TempJarCache.addAll(GlueGenVersion.class, JarUtil.getJarFileURI("ClassInJar0", rootCL));
+        TempJarCache.addAll(GlueGenVersion.class, JarUtil.getJarFileUri("ClassInJar0", rootCL));
 
         // Fetch and load the contained "ClassInJar1.jar"
-        final URL ClassInJar1_jarFileURL = JarUtil.getJarFileURI(TempJarCache.getResource("ClassInJar1.jar")).toURL();
+        final URL ClassInJar1_jarFileURL = JarUtil.getJarFileUri(TempJarCache.getResourceUri("ClassInJar1.jar")).toURL();
         final ClassLoader cl = new URLClassLoader(new URL[] { ClassInJar1_jarFileURL }, rootCL);
         Assert.assertNotNull(cl);
         validateJarUtil("ClassInJar1.jar", "ClassInJar1", cl);
@@ -167,10 +177,10 @@ public class TestJarUtil extends JunitTracer {
         final ClassLoader rootCL = this.getClass().getClassLoader();
 
         // Get containing JAR file "TestJarsInJar.jar" and add it to the TempJarCache
-        TempJarCache.addAll(GlueGenVersion.class, JarUtil.getJarFileURI("ClassInJar0", rootCL));
+        TempJarCache.addAll(GlueGenVersion.class, JarUtil.getJarFileUri("ClassInJar0", rootCL));
 
         // Fetch and load the contained "ClassInJar1.jar"
-        final URL ClassInJar2_jarFileURL = JarUtil.getJarFileURI(TempJarCache.getResource("sub/ClassInJar2.jar")).toURL();
+        final URL ClassInJar2_jarFileURL = JarUtil.getJarFileUri(TempJarCache.getResourceUri("sub/ClassInJar2.jar")).toURL();
         final ClassLoader cl = new URLClassLoader(new URL[] { ClassInJar2_jarFileURL }, rootCL);
         Assert.assertNotNull(cl);
         validateJarUtil("ClassInJar2.jar", "ClassInJar2", cl);
@@ -231,7 +241,7 @@ public class TestJarUtil extends JunitTracer {
             public URL resolve( final URL url ) {
                 if( url.getProtocol().equals("bundleresource") ) {
                     try {
-                        return new URL( IOUtil.JAR_SCHEME, "", url.getFile() );
+                        return new URL( Uri.JAR_SCHEME, "", url.getFile() );
                     } catch(final MalformedURLException e) {
                         return url;
                     }
@@ -244,10 +254,10 @@ public class TestJarUtil extends JunitTracer {
         final ClassLoader rootCL = new CustomClassLoader();
 
         // Get containing JAR file "TestJarsInJar.jar" and add it to the TempJarCache
-        TempJarCache.addAll(GlueGenVersion.class, JarUtil.getJarFileURI("ClassInJar0", rootCL));
+        TempJarCache.addAll(GlueGenVersion.class, JarUtil.getJarFileUri("ClassInJar0", rootCL));
 
         // Fetch and load the contained "ClassInJar1.jar"
-        final URL ClassInJar2_jarFileURL = JarUtil.getJarFileURI(TempJarCache.getResource("sub/ClassInJar2.jar")).toURL();
+        final URL ClassInJar2_jarFileURL = JarUtil.getJarFileUri(TempJarCache.getResourceUri("sub/ClassInJar2.jar")).toURL();
         final ClassLoader cl = new URLClassLoader(new URL[] { ClassInJar2_jarFileURL }, rootCL);
         Assert.assertNotNull(cl);
         validateJarUtil("ClassInJar2.jar", "ClassInJar2", cl);
diff --git a/src/junit/com/jogamp/common/util/TestPlatform01.java b/src/junit/com/jogamp/common/util/TestPlatform01.java
index ebdfe19..6f1fe0e 100644
--- a/src/junit/com/jogamp/common/util/TestPlatform01.java
+++ b/src/junit/com/jogamp/common/util/TestPlatform01.java
@@ -31,15 +31,15 @@ package com.jogamp.common.util;
 import org.junit.Assert;
 import org.junit.Test;
 
-import com.jogamp.common.os.MachineDescription;
+import com.jogamp.common.os.MachineDataInfo;
 import com.jogamp.common.os.Platform;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestPlatform01 extends JunitTracer {
+public class TestPlatform01 extends SingletonJunitCase {
 
     @Test
     public void testInfo00()  {
@@ -55,14 +55,14 @@ public class TestPlatform01 extends JunitTracer {
         System.err.println("Java vendor[name/url]: "+Platform.getJavaVendor()+"/"+Platform.getJavaVendorURL());
         System.err.println("Java version, vm: "+Platform.getJavaVersion()+", "+Platform.getJavaVMName());
         System.err.println();
-        System.err.println("MD: "+Platform.getMachineDescription());
+        System.err.println("MD: "+Platform.getMachineDataInfo());
         System.err.println();
         System.err.println();
     }
 
     @Test
     public void testPageSize01()  {
-        final MachineDescription machine = Platform.getMachineDescription();
+        final MachineDataInfo machine = Platform.getMachineDataInfo();
         final int ps = machine.pageSizeInBytes();
         System.err.println("PageSize: "+ps);
         Assert.assertTrue("PageSize is 0", 0 < ps );
diff --git a/src/junit/com/jogamp/common/util/TestRunnableTask01.java b/src/junit/com/jogamp/common/util/TestRunnableTask01.java
index feb0468..76c2d2a 100644
--- a/src/junit/com/jogamp/common/util/TestRunnableTask01.java
+++ b/src/junit/com/jogamp/common/util/TestRunnableTask01.java
@@ -34,13 +34,13 @@ import java.lang.reflect.InvocationTargetException;
 import org.junit.Assert;
 import org.junit.Test;
 
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestRunnableTask01 extends JunitTracer {
+public class TestRunnableTask01 extends SingletonJunitCase {
 
     @Test
     public void testInvokeAndWait00() throws IOException, InterruptedException, InvocationTargetException {
diff --git a/src/junit/com/jogamp/common/util/TestSystemPropsAndEnvs.java b/src/junit/com/jogamp/common/util/TestSystemPropsAndEnvs.java
index a78957a..ec71494 100644
--- a/src/junit/com/jogamp/common/util/TestSystemPropsAndEnvs.java
+++ b/src/junit/com/jogamp/common/util/TestSystemPropsAndEnvs.java
@@ -35,13 +35,13 @@ import java.util.Properties;
 
 import org.junit.Test;
 
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestSystemPropsAndEnvs extends JunitTracer {
+public class TestSystemPropsAndEnvs extends SingletonJunitCase {
 
     @Test
     public void dumpProperties() {
diff --git a/src/junit/com/jogamp/common/util/TestTempJarCache.java b/src/junit/com/jogamp/common/util/TestTempJarCache.java
index ce06e9a..9cc855f 100644
--- a/src/junit/com/jogamp/common/util/TestTempJarCache.java
+++ b/src/junit/com/jogamp/common/util/TestTempJarCache.java
@@ -29,10 +29,8 @@
 package com.jogamp.common.util;
 
 import java.io.File;
-
 import java.io.IOException;
 import java.lang.reflect.Method;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLClassLoader;
@@ -45,17 +43,18 @@ import org.junit.Test;
 import org.junit.runners.MethodSorters;
 
 import com.jogamp.common.GlueGenVersion;
-import com.jogamp.common.jvm.JNILibLoaderBase;
+import com.jogamp.common.net.URIDumpUtil;
+import com.jogamp.common.net.Uri;
 import com.jogamp.common.os.AndroidVersion;
 import com.jogamp.common.os.NativeLibrary;
 import com.jogamp.common.os.Platform;
 import com.jogamp.common.util.cache.TempCacheReg;
 import com.jogamp.common.util.cache.TempFileCache;
 import com.jogamp.common.util.cache.TempJarCache;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestTempJarCache extends JunitTracer {
+public class TestTempJarCache extends SingletonJunitCase {
     static TempFileCache fileCache;
 
     static class TestClassLoader extends URLClassLoader {
@@ -177,7 +176,7 @@ public class TestTempJarCache extends JunitTracer {
         if(AndroidVersion.isAvailable) { System.err.println("n/a on Android"); return; }
 
         final ClassLoader cl = getClass().getClassLoader();
-        TempJarCache.addAll(GlueGenVersion.class, JarUtil.getJarFileURI(GlueGenVersion.class.getName(), cl));
+        TempJarCache.addAll(GlueGenVersion.class, JarUtil.getJarFileUri(GlueGenVersion.class.getName(), cl));
 
         File f0 = new File(TempJarCache.getTempFileCache().getTempDir(), "META-INF/MANIFEST.MF");
         Assert.assertTrue(f0.exists());
@@ -197,14 +196,28 @@ public class TestTempJarCache extends JunitTracer {
     @Test
     public void testTempJarCache02AddNativeLibs() throws IOException, IllegalArgumentException, URISyntaxException {
         if(AndroidVersion.isAvailable) { System.err.println("n/a on Android"); return; }
-        final String nativeJarName = "gluegen-rt-natives-"+Platform.getOSAndArch()+".jar";
+        final Uri.Encoded nativeJarName = Uri.Encoded.cast("gluegen-rt-natives-"+Platform.getOSAndArch()+".jar");
         final String libBaseName = "gluegen-rt";
         final ClassLoader cl = getClass().getClassLoader();
 
-        URI jarUriRoot = JarUtil.getJarSubURI(TempJarCache.class.getName(), cl);
-        jarUriRoot = IOUtil.getURIDirname(jarUriRoot);
+        final Uri jarUri = JarUtil.getJarUri(TempJarCache.class.getName(), cl);
+        Assert.assertNotNull(jarUri);
+        System.err.println("1 - jarUri:");
+        URIDumpUtil.showUri(jarUri);
+
+        final Uri jarFileUri = jarUri.getContainedUri();
+        Assert.assertNotNull(jarFileUri);
+        System.err.println("2 - jarFileUri:");
+        URIDumpUtil.showUri(jarFileUri);
+
+        final Uri jarFileDir = jarFileUri.getParent();
+        Assert.assertNotNull(jarFileDir);
+        System.err.println("3 - jarFileDir:");
+        URIDumpUtil.showUri(jarFileDir);
 
-        final URI nativeJarURI = JarUtil.getJarFileURI(jarUriRoot, nativeJarName);
+        final Uri nativeJarURI = JarUtil.getJarFileUri(jarFileDir, nativeJarName);
+        System.err.println("4 - nativeJarURI:");
+        URIDumpUtil.showUri(nativeJarURI);
 
         TempJarCache.addNativeLibs(TempJarCache.class, nativeJarURI, null /* nativeLibraryPath */);
         final String libFullPath = TempJarCache.findLibrary(libBaseName);
@@ -227,7 +240,7 @@ public class TestTempJarCache extends JunitTracer {
     @Test
     public void testTempJarCache04bDiffClassLoader() throws IOException, IllegalArgumentException, URISyntaxException {
         if(AndroidVersion.isAvailable) { System.err.println("n/a on Android"); return; }
-        final URL[] urls = new URL[] { JarUtil.getJarFileURI(TempJarCache.class.getName(), getClass().getClassLoader()).toURL() };
+        final URL[] urls = new URL[] { JarUtil.getJarFileUri(TempJarCache.class.getName(), getClass().getClassLoader()).toURL() };
         System.err.println("url: "+urls[0]);
         final ClassLoader cl2 = new TestClassLoader(urls, null);
         final ClassLoader cl3 = new TestClassLoader(urls, null);
diff --git a/src/junit/com/jogamp/common/util/TestVersionInfo.java b/src/junit/com/jogamp/common/util/TestVersionInfo.java
index 7466d0d..2a9dfa1 100644
--- a/src/junit/com/jogamp/common/util/TestVersionInfo.java
+++ b/src/junit/com/jogamp/common/util/TestVersionInfo.java
@@ -32,13 +32,13 @@ import java.io.IOException;
 import org.junit.Test;
 
 import com.jogamp.common.GlueGenVersion;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestVersionInfo extends JunitTracer {
+public class TestVersionInfo extends SingletonJunitCase {
 
     @Test
     public void testInfo01() {
diff --git a/src/junit/com/jogamp/common/util/TestVersionNumber.java b/src/junit/com/jogamp/common/util/TestVersionNumber.java
index 2b4f6d2..9b86376 100644
--- a/src/junit/com/jogamp/common/util/TestVersionNumber.java
+++ b/src/junit/com/jogamp/common/util/TestVersionNumber.java
@@ -33,13 +33,13 @@ import java.io.IOException;
 import org.junit.Assert;
 import org.junit.Test;
 
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestVersionNumber extends JunitTracer {
+public class TestVersionNumber extends SingletonJunitCase {
 
     @Test
     public void test01() {
diff --git a/src/junit/com/jogamp/common/util/TestVersionSemantics.java b/src/junit/com/jogamp/common/util/TestVersionSemantics.java
index 77d3b72..4fe4bcd 100644
--- a/src/junit/com/jogamp/common/util/TestVersionSemantics.java
+++ b/src/junit/com/jogamp/common/util/TestVersionSemantics.java
@@ -42,7 +42,7 @@ import org.semver.Delta;
 
 import com.jogamp.common.GlueGenVersion;
 import com.jogamp.common.util.VersionNumberString;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 import com.jogamp.junit.util.VersionSemanticsUtil;
 
 /**
@@ -64,11 +64,8 @@ import com.jogamp.junit.util.VersionSemanticsUtil;
  * @throws URISyntaxException
  */
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestVersionSemantics extends JunitTracer {
+public class TestVersionSemantics extends SingletonJunitCase {
     static final String jarFile = "gluegen-rt.jar";
-    static final VersionNumberString preVersionNumber = new VersionNumberString("2.2.0");
-    // static final Delta.CompatibilityType expectedCompatibilityType = Delta.CompatibilityType.NON_BACKWARD_COMPATIBLE;
-    static final Delta.CompatibilityType expectedCompatibilityType = Delta.CompatibilityType.BACKWARD_COMPATIBLE_USER;
 
     static final DiffCriteria diffCriteria = new SimpleDiffCriteria();
     // static final DiffCriteria diffCriteria = new PublicDiffCriteria();
@@ -76,22 +73,50 @@ public class TestVersionSemantics extends JunitTracer {
     static final JogampVersion curVersion = GlueGenVersion.getInstance();
     static final VersionNumberString curVersionNumber = new VersionNumberString(curVersion.getImplementationVersion());
 
-    static final Set<String> excludes;
+    static final Set<String> excludesDefault;
     static {
-        excludes = new HashSet<String>();
-        excludes.add("^\\Qjogamp/\\E.*$");
+        excludesDefault = new HashSet<String>();
+        excludesDefault.add("^\\Qjogamp/\\E.*$");
     }
 
     @Test
-    public void testVersionLatest() throws IllegalArgumentException, IOException, URISyntaxException {
+    public void testVersionV220V221() throws IllegalArgumentException, IOException, URISyntaxException {
+        testVersions(diffCriteria, Delta.CompatibilityType.BACKWARD_COMPATIBLE_USER, "2.2.0", "2.2.1", excludesDefault);
+    }
+
+    @Test
+    public void testVersionV221V230() throws IllegalArgumentException, IOException, URISyntaxException {
+        testVersions(diffCriteria, Delta.CompatibilityType.NON_BACKWARD_COMPATIBLE, "2.2.1", "2.3.0", excludesDefault);
+    }
+
+    void testVersions(final DiffCriteria diffCriteria, final Delta.CompatibilityType expectedCompatibilityType,
+                      final String v1, final String v2, final Set<String> excludes)
+                              throws IllegalArgumentException, IOException, URISyntaxException {
+        final VersionNumberString preVersionNumber = new VersionNumberString(v1);
+        final File previousJar = new File("lib/v"+v1+"/"+jarFile);
+
+        final VersionNumberString curVersionNumber = new VersionNumberString(v2);
+        final File currentJar = new File("lib/v"+v2+"/"+jarFile);
+
+        VersionSemanticsUtil.testVersion(diffCriteria, expectedCompatibilityType,
+                                         previousJar, preVersionNumber,
+                                         currentJar, curVersionNumber,
+                                         excludes);
+    }
+
+    @Test
+    public void testVersionV230V23x() throws IllegalArgumentException, IOException, URISyntaxException {
+        // final Delta.CompatibilityType expectedCompatibilityType = Delta.CompatibilityType.NON_BACKWARD_COMPATIBLE;
+        final Delta.CompatibilityType expectedCompatibilityType = Delta.CompatibilityType.BACKWARD_COMPATIBLE_USER;
 
+        final VersionNumberString preVersionNumber = new VersionNumberString("2.3.0");
         final File previousJar = new File("lib/v"+preVersionNumber.getVersionString()+"/"+jarFile);
 
         final ClassLoader currentCL = TestVersionSemantics.class.getClassLoader();
 
         VersionSemanticsUtil.testVersion(diffCriteria, expectedCompatibilityType,
                                          previousJar, preVersionNumber,
-                                         curVersion.getClass(), currentCL, curVersionNumber, excludes);
+                                         curVersion.getClass(), currentCL, curVersionNumber, excludesDefault);
     }
 
     public static void main(final String args[]) throws IOException {
diff --git a/src/junit/com/jogamp/common/util/locks/TestRecursiveLock01.java b/src/junit/com/jogamp/common/util/locks/TestRecursiveLock01.java
index 26677c0..4508f94 100644
--- a/src/junit/com/jogamp/common/util/locks/TestRecursiveLock01.java
+++ b/src/junit/com/jogamp/common/util/locks/TestRecursiveLock01.java
@@ -38,13 +38,13 @@ import org.junit.Assert;
 import org.junit.Test;
 
 import com.jogamp.common.os.Platform;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestRecursiveLock01 extends JunitTracer {
+public class TestRecursiveLock01 extends SingletonJunitCase {
 
     public enum YieldMode {
         NONE(0), YIELD(1), SLEEP(2);
diff --git a/src/junit/com/jogamp/common/util/locks/TestRecursiveThreadGroupLock01.java b/src/junit/com/jogamp/common/util/locks/TestRecursiveThreadGroupLock01.java
index b361463..e35d146 100644
--- a/src/junit/com/jogamp/common/util/locks/TestRecursiveThreadGroupLock01.java
+++ b/src/junit/com/jogamp/common/util/locks/TestRecursiveThreadGroupLock01.java
@@ -34,13 +34,13 @@ import org.junit.Assert;
 import org.junit.Test;
 
 import com.jogamp.common.os.Platform;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestRecursiveThreadGroupLock01 extends JunitTracer {
+public class TestRecursiveThreadGroupLock01 extends SingletonJunitCase {
 
     public enum YieldMode {
         NONE(0), YIELD(1), SLEEP(2);
diff --git a/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket00.java b/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket00.java
index 775d46f..b018a79 100644
--- a/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket00.java
+++ b/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket00.java
@@ -32,35 +32,37 @@ import java.io.IOException;
 import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
-
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
+import com.jogamp.junit.util.SingletonJunitCase;
+
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 public class TestSingletonServerSocket00 {
-    // public static final String SINGLE_INSTANCE_LOCK_FILE = "UITestCase.lock";
-    public static final int SINGLE_INSTANCE_LOCK_PORT = 59999;
-    public static final long SINGLE_INSTANCE_LOCK_TO   = 3*60*1000; // wait up to 3 min
-    public static final long SINGLE_INSTANCE_LOCK_POLL =       100; // poll every 100ms
+    public static final long SINGLE_INSTANCE_LOCK_TO   = SingletonJunitCase.SINGLE_INSTANCE_LOCK_TO;
+
+    public static final long SINGLE_INSTANCE_LOCK_POLL = 100; // poll every 100ms
+
     private static volatile SingletonInstance singletonInstance;
 
     @BeforeClass
     public static void oneTimeSetUp() {
         // one-time initialization code
-        singletonInstance = SingletonInstance.createServerSocket(SINGLE_INSTANCE_LOCK_POLL, SINGLE_INSTANCE_LOCK_PORT);
+        singletonInstance = SingletonInstance.createServerSocket(SINGLE_INSTANCE_LOCK_POLL,
+                                                                 SingletonJunitCase.SINGLE_INSTANCE_LOCK_PORT);
     }
 
     @Test
-    public void testLockUnlock() {
+    public void test01_LockUnlock() {
         Assert.assertTrue("Could not lock single instance: "+singletonInstance.getName(), singletonInstance.tryLock(SINGLE_INSTANCE_LOCK_TO));
         System.gc(); // force cleanup
         singletonInstance.unlock();
     }
 
     @Test
-    public void test2ndInstanceLockTimeout() {
+    public void test02_2ndInstanceLockTimeout() {
         Assert.assertTrue("Could not lock single instance: "+singletonInstance.getName(), singletonInstance.tryLock(SINGLE_INSTANCE_LOCK_TO));
-        final SingletonInstance instanceTwo = SingletonInstance.createServerSocket(SINGLE_INSTANCE_LOCK_POLL, SINGLE_INSTANCE_LOCK_PORT);
+        final SingletonInstance instanceTwo = SingletonInstance.createServerSocket(SINGLE_INSTANCE_LOCK_POLL, SingletonJunitCase.SINGLE_INSTANCE_LOCK_PORT);
         Assert.assertFalse("Could lock 2nd instance: "+instanceTwo.getName(), instanceTwo.tryLock(1000)); // 10x
         System.gc(); // force cleanup
         singletonInstance.unlock();
@@ -69,7 +71,7 @@ public class TestSingletonServerSocket00 {
     private Thread startLockUnlockOffThread(final int i) {
         final Thread t = new Thread(new Runnable() {
             public void run() {
-                final SingletonInstance myLock = SingletonInstance.createServerSocket(10, SINGLE_INSTANCE_LOCK_PORT);
+                final SingletonInstance myLock = SingletonInstance.createServerSocket(10, SingletonJunitCase.SINGLE_INSTANCE_LOCK_PORT);
                 System.err.println(Thread.currentThread().getName()+" LOCK try ..");
                 Assert.assertTrue(Thread.currentThread().getName()+" - Could not lock instance: "+myLock.getName(), myLock.tryLock(1000));
                 System.err.println(Thread.currentThread().getName()+" LOCK ON");
diff --git a/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket01.java b/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket01.java
index 82ca89b..b37e600 100644
--- a/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket01.java
+++ b/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket01.java
@@ -32,27 +32,24 @@ import java.io.IOException;
 import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
-
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
+import com.jogamp.junit.util.SingletonJunitCase;
+
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 public class TestSingletonServerSocket01 {
-    // public static final String SINGLE_INSTANCE_LOCK_FILE = "UITestCase.lock";
-    public static final int SINGLE_INSTANCE_LOCK_PORT = 59999;
-    public static final long SINGLE_INSTANCE_LOCK_TO   = 3*60*1000; // wait up to 3 min
-    public static final long SINGLE_INSTANCE_LOCK_POLL =      1000; // poll every 1s
     private static volatile SingletonInstance singletonInstance;
 
     @BeforeClass
     public static void oneTimeSetUp() {
         // one-time initialization code
-        singletonInstance = SingletonInstance.createServerSocket(SINGLE_INSTANCE_LOCK_POLL, SINGLE_INSTANCE_LOCK_PORT);
+        singletonInstance = SingletonInstance.createServerSocket(SingletonJunitCase.SINGLE_INSTANCE_LOCK_POLL, SingletonJunitCase.SINGLE_INSTANCE_LOCK_PORT);
     }
 
     @Test
     public void testJVMShutdown() {
-        Assert.assertTrue("Could not lock single instance: "+singletonInstance.getName(), singletonInstance.tryLock(SINGLE_INSTANCE_LOCK_TO));
+        Assert.assertTrue("Could not lock single instance: "+singletonInstance.getName(), singletonInstance.tryLock(SingletonJunitCase.SINGLE_INSTANCE_LOCK_TO));
         singletonInstance.unlock();
     }
 
diff --git a/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket02.java b/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket02.java
index 50eebd6..b96f1b4 100644
--- a/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket02.java
+++ b/src/junit/com/jogamp/common/util/locks/TestSingletonServerSocket02.java
@@ -29,35 +29,14 @@ package com.jogamp.common.util.locks;
 
 import java.io.IOException;
 
-import org.junit.Assert;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
 import org.junit.Test;
-
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
- at FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestSingletonServerSocket02 {
-    // public static final String SINGLE_INSTANCE_LOCK_FILE = "UITestCase.lock";
-    public static final int SINGLE_INSTANCE_LOCK_PORT = 59999;
-    public static final long SINGLE_INSTANCE_LOCK_TO   = 3*60*1000; // wait up to 3 min
-    public static final long SINGLE_INSTANCE_LOCK_POLL =      1000; // poll every 1s
-    private static volatile SingletonInstance singletonInstance;
-
-    @BeforeClass
-    public static void oneTimeSetUp() {
-        // one-time initialization code
-        singletonInstance = SingletonInstance.createServerSocket(SINGLE_INSTANCE_LOCK_POLL, SINGLE_INSTANCE_LOCK_PORT);
-        Assert.assertTrue("Could not lock single instance: "+singletonInstance.getName(), singletonInstance.tryLock(SINGLE_INSTANCE_LOCK_TO));
-    }
-
-    @AfterClass
-    public static void oneTimeTearDown() {
-        System.gc(); // force cleanup
-        singletonInstance.unlock();
-    }
+import com.jogamp.junit.util.SingletonJunitCase;
 
+ at FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class TestSingletonServerSocket02 extends SingletonJunitCase {
     @Test
     public void dummy() throws InterruptedException {
         // make junit happy
@@ -65,7 +44,7 @@ public class TestSingletonServerSocket02 {
 
     // @Test(timeout=10) // Only enable manually to test timeout behavior
     public void testTimeout() throws InterruptedException {
-        Thread.sleep(3000);
+        Thread.sleep(SingletonJunitCase.SINGLE_INSTANCE_LOCK_TO+3000);
     }
 
     public static void main(final String args[]) throws IOException, InterruptedException {
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/BaseClass.java b/src/junit/com/jogamp/gluegen/test/junit/generation/BaseClass.java
index b90eeb0..b5f4f2c 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/BaseClass.java
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/BaseClass.java
@@ -30,9 +30,9 @@ package com.jogamp.gluegen.test.junit.generation;
 
 import com.jogamp.common.nio.Buffers;
 import com.jogamp.common.nio.PointerBuffer;
-import com.jogamp.common.os.MachineDescription;
+import com.jogamp.common.os.MachineDataInfo;
 import com.jogamp.common.os.Platform;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
@@ -41,7 +41,7 @@ import java.nio.IntBuffer;
 import java.nio.LongBuffer;
 import java.util.Arrays;
 
-import jogamp.common.os.MachineDescriptionRuntime;
+import jogamp.common.os.MachineDataInfoRuntime;
 
 import org.junit.Assert;
 
@@ -50,7 +50,7 @@ import org.junit.Assert;
  * @author Michael Bien
  * @author Sven Gothel
  */
-public class BaseClass extends JunitTracer {
+public class BaseClass extends SingletonJunitCase {
 
     /**
      * Verifies the existence and creation of the generated class.
@@ -65,21 +65,25 @@ public class BaseClass extends JunitTracer {
         Assert.assertNotNull(ifName+" does not exist", clazzIf);
         Assert.assertNotNull(implName+" does not exist", clazzImpl);
 
-        Assert.assertEquals(1,  clazzIf.getDeclaredField("CONSTANT_ONE").get(null));
+        Assert.assertNotNull(clazzImpl.getDeclaredMethod("nopTest"));
 
         final Object obj = clazzImpl.newInstance();
         Assert.assertTrue("Not of type "+ifName, clazzIf.isAssignableFrom(obj.getClass()));
-        Assert.assertTrue("Not of type com.jogamp.gluegen.test.junit.generation.Bindingtest1", (obj instanceof com.jogamp.gluegen.test.junit.generation.Bindingtest1));
+        Assert.assertTrue("Not of type com.jogamp.gluegen.test.junit.generation.Bindingtest1",
+                (obj instanceof com.jogamp.gluegen.test.junit.generation.Bindingtest1));
     }
 
+    public static final float EPSILON = 1.1920929E-7f; // Float.MIN_VALUE == 1.4e-45f ; double EPSILON 2.220446049250313E-16d
+
     /**
      * Verifies if all generated method signatures are completed,
      * ie a compilation only coverage test without functional tests.
      */
     public void chapter__TestCoverageSignature(final Bindingtest1 binding) throws Exception {
-          int i;
+          int i = 0;
           final long context = 0;
           LongBuffer lb=null;
+          ByteBuffer bb=null;
           final IntBuffer ib=null;
           final long[] larray = null;
           final int larray_offset = 0;
@@ -89,10 +93,99 @@ public class BaseClass extends JunitTracer {
           final int iarray_offset = 0;
           long result = 0;
           long l = result;
+          ShortBlob sb = null;
+          Int32Struct i32s = null;
+          AnonBlob ab = null;
+          PointerBuffer pb=null;
 
+          // Test constants values: binding and value!
           {
-              final ByteBuffer bb = binding.createAPtrBlob();
-              PointerBuffer pb = safeByteBuffer2PointerBuffer(bb, 1);
+              // Plain vanilla CPP constants
+              Assert.assertEquals(   1, Bindingtest1.CONSTANT_ONE);
+              Assert.assertEquals(   8, Bindingtest1.ARRAY_SIZE);
+              Assert.assertEquals(1234, Bindingtest1.DEFINE_01);
+
+              // Enums
+              Assert.assertEquals(   1, Bindingtest1.LI);
+              Assert.assertEquals(   3, Bindingtest1.LO);
+              Assert.assertEquals(   2, Bindingtest1.LU);
+              Assert.assertEquals(   1, Bindingtest1.MI);
+              Assert.assertEquals(   3, Bindingtest1.MO);
+              Assert.assertEquals(   2, Bindingtest1.MU);
+              Assert.assertEquals(   0, Bindingtest1.ZERO);
+              Assert.assertEquals(   1, Bindingtest1.ONE);
+              Assert.assertEquals(   2, Bindingtest1.TWO);
+              Assert.assertEquals(   3, Bindingtest1.THREE);
+
+              // CPP Macro Expansion!
+              Assert.assertEquals(   1, Bindingtest1.NUMBER_ONE);
+              Assert.assertEquals(   2, Bindingtest1.NUMBER_TWO);
+              Assert.assertEquals(   4, Bindingtest1.NUMBER_FOUR);
+              Assert.assertEquals(   8, Bindingtest1.NUMBER_EIGHT);
+              Assert.assertEquals(   9, Bindingtest1.NUMBER_NINE);
+              Assert.assertEquals(  10, Bindingtest1.NUMBER_TEN);
+
+
+              // Floating point hexadecimals
+              final float CL_FLT_A0 = Bindingtest1.CL_FLT_A0;
+              final float CL_FLT_A1 = Bindingtest1.CL_FLT_A1;
+              final float CL_FLT_A2 = Bindingtest1.CL_FLT_A2;
+              Assert.assertEquals(  0x1.p127f,  CL_FLT_A0, EPSILON);
+              Assert.assertEquals(  0x1.p+127F, CL_FLT_A1, EPSILON);
+              Assert.assertEquals(  0x1.p-127f, CL_FLT_A2, EPSILON);
+
+              final float CL_FLT_EPSILON = Bindingtest1.CL_FLT_EPSILON;
+              final double CL_FLT_MAX= Bindingtest1.CL_FLT_MAX;
+              final double CL_FLT_MIN = Bindingtest1.CL_FLT_MIN;
+              Assert.assertEquals(  0x1.0p-23f, CL_FLT_EPSILON, EPSILON);
+              Assert.assertEquals(  0x1.fffffep127f, CL_FLT_MAX, EPSILON);
+              Assert.assertEquals(  0x1.0p-126f, CL_FLT_MIN, EPSILON);
+
+              final double CL_DBL_B0 = Bindingtest1.CL_DBL_B0;
+              final double CL_DBL_B1 = Bindingtest1.CL_DBL_B1;
+              final double CL_DBL_B2 = Bindingtest1.CL_DBL_B2;
+              Assert.assertEquals(  0x1.p127d,  CL_DBL_B0, EPSILON);
+              Assert.assertEquals(  0x1.p+127D, CL_DBL_B1, EPSILON);
+              Assert.assertEquals(  0x1.p-127d, CL_DBL_B2, EPSILON);
+
+              final float CL_DBL_EPSILON = Bindingtest1.CL_DBL_EPSILON;
+              final double CL_DBL_MAX= Bindingtest1.CL_DBL_MAX;
+              final double CL_DBL_MIN = Bindingtest1.CL_DBL_MIN;
+              Assert.assertEquals(  0x1.0p-52f, CL_DBL_EPSILON, EPSILON);
+              Assert.assertEquals(  0x1.fffffffffffffp1023, CL_DBL_MAX, EPSILON);
+              Assert.assertEquals(  0x1.0p-1022, CL_DBL_MIN, EPSILON);
+          }
+          {
+              l = binding.testXID(l);
+              l = binding.testXID_2(l);
+
+              bb = binding.testAnonBuffer(bb);
+
+              sb = binding.testShortBlob(sb);
+              sb = binding.testLPShortBlob0(sb);
+              sb = binding.testLPShortBlob1(sb);
+              sb = binding.testLPShortBlob2(sb);
+              sb = binding.testLPShortBlob3(sb);
+              sb = binding.testShortBlobL1(sb);
+              sb = binding.testShortBlobL2(sb);
+
+              i32s = binding.testInt32Struct(i32s);
+
+              ab = binding.testCreateAnonBlob();
+              binding.testDestroyAnonBlob(ab);
+
+              l = binding.testCreateAnonBlob2();
+              binding.testDestroyAnonBlob2(l);
+
+              lb = binding.testFooPtr(larray, 0);
+              lb = binding.testFooPtr(lb);
+
+              i = binding.testDelegate(i);
+          }
+
+          {
+              bb = binding.createAPtrBlob();
+              pb = safeByteBuffer2PointerBuffer(bb, 1);
               long bb2A = binding.getAPtrAddress(bb);
               bb2A = bb2A - 0; // avoid warning
 
@@ -119,9 +212,6 @@ public class BaseClass extends JunitTracer {
               binding.releaseAPtrBlob(bb);
           }
 
-          final ByteBuffer bb=null;
-          PointerBuffer pb=null;
-
           result = binding.arrayTestInt32(context, ib);
           result = binding.arrayTestInt32(context, iarray, iarray_offset);
 
@@ -629,6 +719,66 @@ public class BaseClass extends JunitTracer {
                   Assert.assertTrue("Wrong result: 0x"+Long.toHexString(pb.get(i))+"+1 != 0x"+Long.toHexString(pb2.get(i)), (pb.get(i)+1)==pb2.get(i));
               }
           }
+
+          {
+              final long l0 = 0xAAFFEE;
+              final long l1 = binding.testXID(l0);
+              final long l2 = binding.testXID_2(l0);
+              Assert.assertEquals(l0, l1);
+              Assert.assertEquals(l0, l2);
+
+              final ByteBuffer bb = Buffers.newDirectByteBuffer(PointerBuffer.ELEMENT_SIZE);
+              for(int j=0; j<bb.limit(); j++) {
+                  bb.put(j, (byte)(0xAA+j));
+              }
+              final ByteBuffer bbOut = binding.testAnonBuffer(bb);
+              Assert.assertEquals(bb, bbOut);
+
+              final ShortBlob sb = ShortBlob.create();
+              sb.setB1((byte)0xAA);
+              sb.setB2((byte)0xEE);
+              final ShortBlob sb_ = binding.testShortBlob(sb);
+              final ShortBlob sb0 = binding.testLPShortBlob0(sb);
+              final ShortBlob sb1 = binding.testLPShortBlob1(sb);
+              final ShortBlob sb2 = binding.testLPShortBlob2(sb);
+              final ShortBlob sb3 = binding.testLPShortBlob3(sb);
+              final ShortBlob sb4 = binding.testShortBlobL1(sb);
+              final ShortBlob sb5 = binding.testShortBlobL2(sb);
+              Assert.assertEquals(sb.getBuffer(), sb_.getBuffer());
+              Assert.assertEquals(sb.getBuffer(), sb0.getBuffer());
+              Assert.assertEquals(sb.getBuffer(), sb1.getBuffer());
+              Assert.assertEquals(sb.getBuffer(), sb2.getBuffer());
+              Assert.assertEquals(sb.getBuffer(), sb3.getBuffer());
+              Assert.assertEquals(sb.getBuffer(), sb4.getBuffer());
+              Assert.assertEquals(sb.getBuffer(), sb5.getBuffer());
+
+              final Int32Struct i32s = Int32Struct.create();
+              i32s.setB1((byte)0x02);
+              i32s.setB2((byte)0x12);
+              i32s.setB3((byte)0x22);
+              i32s.setB4((byte)0x32);
+              final Int32Struct i32s0 = binding.testInt32Struct(i32s);
+              Assert.assertEquals(i32s.getBuffer(), i32s0.getBuffer());
+
+              final AnonBlob ab = binding.testCreateAnonBlob();
+              binding.testDestroyAnonBlob(ab);
+
+              final long ab2 = binding.testCreateAnonBlob2();
+              binding.testDestroyAnonBlob2(ab2);
+
+              final long[] foo = new long[] { 0x1122334455667788L };
+              final LongBuffer fooLB = Buffers.newDirectLongBuffer(foo);
+              final LongBuffer foo1Out = binding.testFooPtr(fooLB);
+              Assert.assertEquals(fooLB, foo1Out);
+              final LongBuffer foo2Out = binding.testFooPtr(foo, 0);
+              Assert.assertEquals(fooLB, foo2Out);
+          }
+
+          {
+              i=41;
+              final int iRes = binding.testDelegate(i);
+              Assert.assertEquals(i+1, iRes);
+          }
     }
 
     public void chapter04TestPointerBuffer(final Bindingtest1 binding) throws Exception {
@@ -824,8 +974,8 @@ public class BaseClass extends JunitTracer {
 
     public void chapter09TestCompoundAlignment(final Bindingtest1 binding) throws Exception {
 
-        final MachineDescription.StaticConfig smd = MachineDescriptionRuntime.getStatic();
-        final MachineDescription md = MachineDescriptionRuntime.getRuntime();
+        final MachineDataInfo.StaticConfig smd = MachineDataInfoRuntime.getStatic();
+        final MachineDataInfo md = MachineDataInfoRuntime.getRuntime();
 
         System.err.println("static  md: "+smd);
         System.err.println("runtime md: "+md);
@@ -1115,22 +1265,20 @@ public class BaseClass extends JunitTracer {
         }
     }
 
-    public static final float EPSILON = 1.1920929E-7f; // Float.MIN_VALUE == 1.4e-45f ; double EPSILON 2.220446049250313E-16d
-
     /** Test array and pointer bindings of structs  */
     public void chapter12TestStructArrayModelConst(final Bindingtest1 binding) throws Exception {
         final TK_ModelConst model = binding.createModelConst();
 
         Assert.assertEquals(3, model.getIntxxPointerCustomLenVal());
         Assert.assertEquals(3, model.getInt32PointerCustomLenVal());
-        Assert.assertEquals(3, model.getInt32ArrayFixedLenArrayLength());
-        Assert.assertEquals(3, model.getStructArrayFixedLenArrayLength());
+        Assert.assertEquals(3, TK_ModelConst.getInt32ArrayFixedLenArrayLength());
+        Assert.assertEquals(3, TK_ModelConst.getStructArrayFixedLenArrayLength());
         Assert.assertEquals(3, model.getStructPointerCustomLenVal());
 
         // field: int32ArrayFixedLen
         //        CType['int32_t *', size [fixed false, lnx64 12], [array*1]], with array length of 3
         {
-            final int size = model.getInt32ArrayFixedLenArrayLength();
+            final int size = TK_ModelConst.getInt32ArrayFixedLenArrayLength();
             final int[] all = model.getInt32ArrayFixedLen(0, new int[size]);
             final IntBuffer allB = model.getInt32ArrayFixedLen();
             Assert.assertEquals(size, allB.limit());
@@ -1170,7 +1318,7 @@ public class BaseClass extends JunitTracer {
         // field: mat4x4
         //        CType['float * *', size [fixed false, lnx64 64], [array*2]], with array length of <code>4*4</code> */
         {
-            Assert.assertEquals(4*4, model.getMat4x4ArrayLength());
+            Assert.assertEquals(4*4, TK_ModelConst.getMat4x4ArrayLength());
             final FloatBuffer mat4x4 = model.getMat4x4();
             Assert.assertEquals(4*4, mat4x4.limit());
             for(int i=0; i<4; i++) {
@@ -1185,7 +1333,7 @@ public class BaseClass extends JunitTracer {
         // field: structArrayFixedLen
         //        field: CType['TK_Dimension *', size [fixed false, lnx64 48], [array*1]], with array length of 3
         {
-            final int size = model.getStructArrayFixedLenArrayLength();
+            final int size = TK_ModelConst.getStructArrayFixedLenArrayLength();
             final TK_Dimension[] all = model.getStructArrayFixedLen(0, new TK_Dimension[size]);
             for(int i=0; i<size; i++) {
                 Assert.assertEquals(51 + i * 10, all[i].getX());
@@ -1236,7 +1384,7 @@ public class BaseClass extends JunitTracer {
         assertAPTR(surfaceContext, model.getCtx());
 
         {
-            Assert.assertEquals(12, model.getModelNameArrayFixedLenArrayLength());
+            Assert.assertEquals(12, TK_ModelConst.getModelNameArrayFixedLenArrayLength());
 
             final ByteBuffer bb = model.getModelNameArrayFixedLen();
             Assert.assertEquals(12, bb.limit());
@@ -1296,14 +1444,14 @@ public class BaseClass extends JunitTracer {
 
         Assert.assertEquals(3, model.getIntxxPointerCustomLenVal());
         Assert.assertEquals(3, model.getInt32PointerCustomLenVal());
-        Assert.assertEquals(3, model.getInt32ArrayFixedLenArrayLength());
-        Assert.assertEquals(3, model.getStructArrayFixedLenArrayLength());
+        Assert.assertEquals(3, TK_ModelMutable.getInt32ArrayFixedLenArrayLength());
+        Assert.assertEquals(3, TK_ModelMutable.getStructArrayFixedLenArrayLength());
         Assert.assertEquals(3, model.getStructPointerCustomLenVal());
 
         // field: int32ArrayFixedLen
         //        CType['int32_t *', size [fixed false, lnx64 12], [array*1]], with array length of 3
         {
-            final int size = model.getInt32ArrayFixedLenArrayLength();
+            final int size = TK_ModelMutable.getInt32ArrayFixedLenArrayLength();
             {
                 final int[] values = new int[] { 1, 2, 3 };
                 model.setInt32ArrayFixedLen(0, values);
@@ -1385,7 +1533,7 @@ public class BaseClass extends JunitTracer {
             model.setMat4x4(2*4, new float[] { 31, 32, 33, 34 } );
             model.setMat4x4(3*4, new float[] { 41, 42, 43, 44 } );
 
-            Assert.assertEquals(4*4, model.getMat4x4ArrayLength());
+            Assert.assertEquals(4*4, TK_ModelMutable.getMat4x4ArrayLength());
             final FloatBuffer mat4x4 = model.getMat4x4();
             Assert.assertEquals(4*4, mat4x4.limit());
             for(int i=0; i<4; i++) {
@@ -1400,7 +1548,7 @@ public class BaseClass extends JunitTracer {
         // field: structArrayFixedLen
         //        field: CType['TK_Dimension *', size [fixed false, lnx64 48], [array*1]], with array length of 3
         {
-            final int size = model.getStructArrayFixedLenArrayLength();
+            final int size = TK_ModelMutable.getStructArrayFixedLenArrayLength();
             {
                 for(int i=0; i<size; i++) {
                     final TK_Dimension d = TK_Dimension.create();
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/PCPPTest.java b/src/junit/com/jogamp/gluegen/test/junit/generation/PCPPTest.java
index f45297f..608a17f 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/PCPPTest.java
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/PCPPTest.java
@@ -30,7 +30,7 @@ package com.jogamp.gluegen.test.junit.generation;
 
 import com.jogamp.common.os.AndroidVersion;
 import com.jogamp.gluegen.pcpp.PCPP;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import java.io.BufferedReader;
 import java.io.ByteArrayOutputStream;
@@ -51,7 +51,7 @@ import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class PCPPTest extends JunitTracer {
+public class PCPPTest extends SingletonJunitCase {
 
     @BeforeClass
     public static void init() {
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test1-CustomJavaCode.cfg b/src/junit/com/jogamp/gluegen/test/junit/generation/test1-CustomJavaCode.cfg
new file mode 100644
index 0000000..8d8f650
--- /dev/null
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test1-CustomJavaCode.cfg
@@ -0,0 +1,7 @@
+
+ at Override
+public int testDelegate(int v) {
+    return testDelegateOrigImpl(v) + 1;
+}
+
+
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test1-common.cfg b/src/junit/com/jogamp/gluegen/test/junit/generation/test1-common.cfg
index 8e41aae..6c516c2 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/test1-common.cfg
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test1-common.cfg
@@ -32,10 +32,24 @@ ReturnValueCapacity typeTestAnonPointer ARRAY_SIZE * sizeof(MYAPIConfig)
 Opaque long MYAPIConfig
 Opaque boolean Bool
 
+Opaque long XID
+# For 'struct _AnonBlob2*', we need to drop 'struct'
+Opaque long _AnonBlob2*
+
+Opaque long _Crazy*;
+Opaque long ShortBlob.Cool
+
 CustomCCode #include "test1.h"
 
 Opaque long TK_Context
 
+RenameJavaSymbol DEFINE_01_EXT DEFINE_01
+RenameJavaSymbol testXID_EXT testXID
+
+DelegateImplementation testDelegate testDelegateOrigImpl
+IncludeAs CustomJavaCode Bindingtest1p1Impl test1-CustomJavaCode.cfg
+IncludeAs CustomJavaCode Bindingtest1p2Impl test1-CustomJavaCode.cfg
+
 StructPackage TK_Dimension com.jogamp.gluegen.test.junit.generation
 EmitStruct TK_Dimension
 StructPackage TK_DimensionPair com.jogamp.gluegen.test.junit.generation
@@ -96,6 +110,9 @@ Import java.nio.*
 Import java.util.*
 Import com.jogamp.common.os.*
 Import com.jogamp.common.nio.*
+Import com.jogamp.gluegen.test.junit.generation.ShortBlob
+Import com.jogamp.gluegen.test.junit.generation.Int32Struct
+Import com.jogamp.gluegen.test.junit.generation.AnonBlob
 Import com.jogamp.gluegen.test.junit.generation.TK_Surface
 Import com.jogamp.gluegen.test.junit.generation.TK_Dimension
 Import com.jogamp.gluegen.test.junit.generation.TK_DimensionPair
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test1.c b/src/junit/com/jogamp/gluegen/test/junit/generation/test1.c
index 9999274..0683600 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/test1.c
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test1.c
@@ -8,10 +8,67 @@
 
 #define DEBUG 1
 
+MYAPI XID MYAPIENTRY testXID(XID v) {
+    return v;
+}
+MYAPI XID_2 MYAPIENTRY testXID_2(XID_2 v) {
+    return v;
+}
+MYAPI AnonBuffer MYAPIENTRY testAnonBuffer(AnonBuffer v) {
+    return v;
+}
+
+MYAPI const ShortBlob * MYAPIENTRY testShortBlob(const ShortBlob *v) {
+    return v;
+}
+MYAPI const LPShortBlob0 MYAPIENTRY testLPShortBlob0(const LPShortBlob0 v) {
+    return v;
+}
+MYAPI LPShortBlob1 MYAPIENTRY testLPShortBlob1(LPShortBlob1 v) {
+    return v;
+}
+MYAPI const LPShortBlob2 MYAPIENTRY testLPShortBlob2(const LPShortBlob2 v) {
+    return v;
+}
+MYAPI LPShortBlob3 MYAPIENTRY testLPShortBlob3(LPShortBlob3 v) {
+    return v;
+}
+MYAPI const ShortBlobL1 * MYAPIENTRY testShortBlobL1(const ShortBlobL1 * v) {
+    return v;
+}
+MYAPI ShortBlobL2 * MYAPIENTRY testShortBlobL2(ShortBlobL2 * v) {
+    return v;
+}
+MYAPI struct Int32Struct * MYAPIENTRY testInt32Struct(struct Int32Struct * v) {
+    return v;
+}
+
+MYAPI AnonBlob MYAPIENTRY testCreateAnonBlob() {
+    return (AnonBlob) calloc(1, sizeof(char));
+}
+MYAPI void MYAPIENTRY testDestroyAnonBlob(AnonBlob v) {
+    free(v);
+}
+
+MYAPI struct _AnonBlob2 * MYAPIENTRY testCreateAnonBlob2() {
+    return (struct _AnonBlob2 *) calloc(1, sizeof(char));
+}
+MYAPI void MYAPIENTRY testDestroyAnonBlob2(struct _AnonBlob2 * v) {
+    free(v);
+}
+
+MYAPI foo_ptr MYAPIENTRY testFooPtr(foo_ptr v) {
+    return v;
+}
+
 MYAPI foo MYAPIENTRY nopTest() {
     return 42;
 }
 
+MYAPI int32_t MYAPIENTRY testDelegate(int32_t v) {
+   return v; 
+}
+
 /**
  * new blob sizeof(void*) filled w/ 0xDEADBEEF
  */
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test1.h b/src/junit/com/jogamp/gluegen/test/junit/generation/test1.h
index 67a8050..4e60114 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/test1.h
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test1.h
@@ -28,12 +28,114 @@
 
 typedef int Bool;
 typedef uint64_t foo;
+typedef foo * foo_ptr;
 typedef void * APtr1Type;
 typedef intptr_t APtr2Type;
 
+typedef void * XID;        // Opaque
+typedef XID    XID_2;      // Opaque, due to XID
+typedef void * AnonBuffer; // Non Opaque
+
+// typedef XID    XID_2;              // Duplicate w/ compatible type (ignored) - OpenSolaris: Native gcc error
+// typedef int    XID_2;              // Duplicate w/ incompatible type ERROR
+
+#define CL_FLT_A0           0x1p127
+#define CL_FLT_A1           0x1p+127F
+#define CL_FLT_A2           0x1p-127f
+
+#define CL_DBL_B0           0x1.p127d
+#define CL_DBL_B1           0x1.p+127D
+#define CL_DBL_B2           0x1.p-127d
+
+#define CL_FLT_MAX          0x1.fffffep127f
+#define CL_FLT_MIN          0x1.0p-126f
+#define CL_FLT_EPSILON      0x1.0p-23f
+
+#define CL_DBL_MAX          0x1.fffffffffffffp1023
+#define CL_DBL_MIN          0x1.0p-1022
+#define CL_DBL_EPSILON      0x1.0p-52
+
+#define DEFINE_01 1234
+#define DEFINE_01 1234                // Duplicate w/ same value (ignored)
+// #define DEFINE_01 1235             // Duplicate w/ diff value ERROR
+#define DEFINE_01_EXT 1234            // Renamed Duplicate w/ same value (ignored)
+// #define DEFINE_01_EXT 1235         // Renamed Duplicate w/ diff value ERROR
+// #define DEFINE_01 1235             // Duplicate w/ diff value ERROR
+
+#define DEFINE_02 ( (int ) 3 )
+// #define DEFINE_02 ( (int ) 3 )     // Duplicate w/ same value ERROR (PCPP redefine)
+// #define DEFINE_02 ( (int) 3 )      // Duplicate w/ diff value ERROR (PCPP redefine, then GlueGen)
+
+#define NUMBER_ONE      CONSTANT_ONE
+#define NUMBER_TWO      ( NUMBER_ONE + NUMBER_ONE )
+#define NUMBER_FOUR     ( NUMBER_ONE << NUMBER_TWO )
+#define NUMBER_EIGHT    ( NUMBER_TWO * NUMBER_TWO + ( NUMBER_ONE << NUMBER_TWO ) )
+#define NUMBER_NINE     ( 2 * 2 + ( 1 << 2 ) + 1 )
+#define NUMBER_TEN      ( NUMBER_EIGHT | NUMBER_TWO )
+
+enum Lala { LI=1, LU, LO };            
+// enum Lala { LI=1, LU, LO };        // Duplicate w/ same value (ignored, ERROR in native compilation)
+// enum Lala { LI=1, LU=3, LO };      // Duplicate w/ diff value ERROR
+// enum Lala { LI=1, LU, LO, LERROR }; // Duplicate w/ diff value ERROR
+
+typedef enum { MI=1, MU, MO } Momo;
+// typedef enum { MI=1, MU, MO } Momo; // Duplicate w/ same value (ignored, ERROR in native compilation)
+// typedef enum { MI=1, MU=3, MO } Momo; // Duplicate w/ diff value ERROR
+// typedef enum { MI=1, MU, MO, MERR } Momo; // Duplicate w/ diff value ERROR
+
+struct _Crazy;
+
+typedef struct _ShortBlob {
+    uint8_t b1;
+    uint8_t b2;
+    struct _Crazy * Cool;  // Opaque field!
+} ShortBlob, ShortBlob2, *LPShortBlob0; // Aliased to 'ShortBlob'
+typedef ShortBlob  * LPShortBlob1; // Aliased to 'ShortBlob'
+typedef ShortBlob2 * LPShortBlob2; // Aliased to 'ShortBlob'
+typedef LPShortBlob1 LPShortBlob3; // Aliased to 'ShortBlob'
+typedef ShortBlob    ShortBlobL1;  // Aliased to 'ShortBlob'
+typedef ShortBlob2   ShortBlobL2;  // Aliased to 'ShortBlob'
+
+struct Int32Struct {
+    uint8_t b1;
+    uint8_t b2;
+    uint8_t b3;
+    uint8_t b4;
+};
+
+typedef struct _AnonBlob * AnonBlob; // Anonymous-Struct, Non Opaque
+
+struct _AnonBlob2; // opaque: struct _AnonBlob2*
+
+MYAPI XID MYAPIENTRY testXID(XID v);
+MYAPI XID MYAPIENTRY testXID(XID_2 v);      // duplicate: shall be dropped
+// MYAPI XID MYAPIENTRY testXID(int v);     // duplicate w/ diff value ERROR
+MYAPI XID MYAPIENTRY testXID_EXT(XID v);    // renamed duplicate w/ compat value: shall be dropped
+// MYAPI XID MYAPIENTRY testXID_EXT(int v); // renamed duplicate w/ diff value ERROR
+MYAPI XID_2 MYAPIENTRY testXID_2(XID_2 v);
+MYAPI AnonBuffer MYAPIENTRY testAnonBuffer(AnonBuffer v);
+MYAPI const ShortBlob * MYAPIENTRY testShortBlob(const ShortBlob *v);
+MYAPI const LPShortBlob0 MYAPIENTRY testLPShortBlob0(const LPShortBlob0 v);
+MYAPI LPShortBlob1 MYAPIENTRY testLPShortBlob1(LPShortBlob1 v);
+MYAPI const LPShortBlob2 MYAPIENTRY testLPShortBlob2(const LPShortBlob2 v);
+MYAPI LPShortBlob3 MYAPIENTRY testLPShortBlob3(LPShortBlob3 v);
+MYAPI const ShortBlobL1 * MYAPIENTRY testShortBlobL1(const ShortBlobL1 *v);
+MYAPI ShortBlobL2 * MYAPIENTRY testShortBlobL2(ShortBlobL2 *v);
+MYAPI struct Int32Struct * MYAPIENTRY testInt32Struct(struct Int32Struct * v);
+
+MYAPI AnonBlob MYAPIENTRY testCreateAnonBlob();
+MYAPI void MYAPIENTRY testDestroyAnonBlob(AnonBlob v);
+
+MYAPI struct _AnonBlob2 * MYAPIENTRY testCreateAnonBlob2();
+MYAPI void MYAPIENTRY testDestroyAnonBlob2(struct _AnonBlob2 * v);
+
+MYAPI foo_ptr MYAPIENTRY testFooPtr(foo_ptr v);
+
 /** Returns 42 */
 MYAPI foo MYAPIENTRY nopTest();
 
+MYAPI int32_t MYAPIENTRY testDelegate(int32_t v);
+
 //
 // Different pointer type tests ..
 //
@@ -131,7 +233,7 @@ MYAPI int MYAPIENTRY intArrayCopy(int * dest, const int * src, int num);
 /** Increases the elements by 1, and returns the sum 
 MYAPI int MYAPIENTRY intArrayWrite(int *  *  ints, int num); */
 
-typedef struct __MYAPIConfig * MYAPIConfig;
+typedef struct __MYAPIConfig * MYAPIConfig; // anonymous-struct opaque
 
 /** Returns the passed MYAPIConfig incremented by 1 */
 MYAPI MYAPIConfig  MYAPIENTRY typeTestAnonSingle(const MYAPIConfig a);
@@ -172,7 +274,7 @@ typedef struct {
     int32_t height;
 } TK_Dimension;
 
-typedef struct _TK_Context * TK_Context; // anonymous
+typedef struct _TK_Context * TK_Context; // anonymous-struct opaque
 
 typedef struct {
     TK_Context ctx;
@@ -246,9 +348,12 @@ typedef struct {
     int32_t i2;
 } TK_DimensionPair;
 
+// some implicity _local_ typedef -> public typedef checks
+typedef TK_Surface *  (MYAPIENTRY* PFNCREATESURFACEPROC)();
+typedef void (MYAPIENTRY* PFNDESTROYSURFACEPROC)(TK_Surface *  surface);
+
 MYAPI TK_Surface * MYAPIENTRY createSurface();
 MYAPI void MYAPIENTRY destroySurface(TK_Surface * surface);
-
 MYAPI TK_ComplicatedSuperSet * MYAPIENTRY createComplicatedSuperSet();
 MYAPI Bool MYAPIENTRY hasInitValues(TK_ComplicatedSuperSet * s);
 MYAPI void MYAPIENTRY destroyComplicatedSuperSet(TK_ComplicatedSuperSet * s);
@@ -266,6 +371,13 @@ MYAPI TK_Dimension MYAPIENTRY addDimensions(const TK_Dimension s[TWO]);
 MYAPI TK_Dimension MYAPIENTRY addDimensionPair(const TK_DimensionPair s);
 MYAPI void MYAPIENTRY zeroDimensions(TK_Dimension s[2]);
 
+
+// some implicity _local_ typedef -> public typedef checks
+typedef void (MYAPIENTRY* PFNCOPYPRIMTODIMENSIONSPROC)(const int pos[2], const int size[2], TK_Dimension dest[1]);
+typedef int (MYAPIENTRY* PFNRGBATOINTPROC)(const char rgba[4]);
+typedef void (MYAPIENTRY* PFNINTTORGBAPROC)(int irgba, char rgbaSink[4]);
+typedef void (MYAPIENTRY* PFNADDBYTEPROC)(const char summands[2], char result[1]);
+
 MYAPI void MYAPIENTRY copyPrimToDimensions(const int pos[2], const int size[2], TK_Dimension dest[1]);
 MYAPI void MYAPIENTRY copyDimensionsToPrim(TK_Dimension dim, int dpos[2], int dsize[2]);
 MYAPI int MYAPIENTRY rgbaToInt(const char rgba[4]);
@@ -296,7 +408,7 @@ typedef struct {
     const int32_t structPointerCustomLenVal;
     const TK_Dimension * structPointerOneElem;
 
-    const TK_Context ctx;
+    TK_Context ctx;
 
     const char modelNameArrayFixedLen[12]; /* 'Hello Array' len=11+1 */
     const char * modelNamePointerCString;    /* 'Hello CString' len=13+1 */
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test1p1-gluegen.cfg b/src/junit/com/jogamp/gluegen/test/junit/generation/test1p1-gluegen.cfg
index 6ef171b..b8582a8 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/test1p1-gluegen.cfg
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test1p1-gluegen.cfg
@@ -6,6 +6,8 @@ NativeOutputDir native
 
 Extends Bindingtest1p1 Bindingtest1
 
+ExtendedInterfaceSymbolsIgnore ../build-temp/gensrc/classes/com/jogamp/gluegen/test/junit/generation/Bindingtest1.java
+
 Include test1-common.cfg
 
 Import com.jogamp.gluegen.test.junit.generation.Bindingtest1
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test1p2-gluegen.cfg b/src/junit/com/jogamp/gluegen/test/junit/generation/test1p2-gluegen.cfg
index 708bd26..eb9fdcf 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/test1p2-gluegen.cfg
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test1p2-gluegen.cfg
@@ -6,6 +6,8 @@ NativeOutputDir native
 
 Extends Bindingtest1p2 Bindingtest1
 
+ExtendedInterfaceSymbolsIgnore ../build-temp/gensrc/classes/com/jogamp/gluegen/test/junit/generation/Bindingtest1.java
+
 # Use a ProcAddressTable so we dynamically look up the routines
 EmitProcAddressTable true
 ProcAddressTableClassName Bindingtest1p2ProcAddressTable
diff --git a/src/junit/com/jogamp/gluegen/test/junit/internals/TestType.java b/src/junit/com/jogamp/gluegen/test/junit/internals/TestType.java
new file mode 100644
index 0000000..84fc463
--- /dev/null
+++ b/src/junit/com/jogamp/gluegen/test/junit/internals/TestType.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.gluegen.test.junit.internals;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.jogamp.gluegen.cgram.types.FloatType;
+import com.jogamp.gluegen.cgram.types.IntType;
+import com.jogamp.junit.util.SingletonJunitCase;
+
+import org.junit.FixMethodOrder;
+import org.junit.runners.MethodSorters;
+
+ at FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class TestType extends SingletonJunitCase {
+
+    @Test
+    public void test01Equals() {
+        final FloatType f1 = new FloatType("GLfloat", null, 0, null);
+        final FloatType f2 = new FloatType("float", null, 0, null);
+        final IntType i1 = new IntType("GLint", null, false, 0, null);
+        final IntType i2 = new IntType("int", null, false, 0, null);
+        final int f1H = f1.hashCode();
+        final int f2H = f2.hashCode();
+        final int i1H = i1.hashCode();
+        final int i2H = i2.hashCode();
+
+        final int f1HS = f1.hashCodeSemantics();
+        final int f2HS = f2.hashCodeSemantics();
+        final int i1HS = i1.hashCodeSemantics();
+        final int i2HS = i2.hashCodeSemantics();
+
+        Assert.assertFalse(f1.getClass().isInstance(null));
+        Assert.assertTrue(f1.getClass().isInstance(f2));
+        Assert.assertTrue(i1.getClass().isInstance(i2));
+        Assert.assertFalse(f1.getClass().isInstance(i2));
+
+        Assert.assertFalse(f1.equals(f2));
+        Assert.assertFalse(i1.equals(i2));
+        Assert.assertFalse(f1.equals(i2));
+        Assert.assertNotEquals(f1H, f2H);
+        Assert.assertNotEquals(i1H, i2H);
+        Assert.assertNotEquals(f1H, i2H);
+
+        Assert.assertTrue(f1.equalSemantics(f2));
+        Assert.assertTrue(i1.equalSemantics(i2));
+        Assert.assertFalse(f1.equalSemantics(i2));
+        Assert.assertEquals(f1HS, f2HS);
+        Assert.assertEquals(i1HS, i2HS);
+        Assert.assertNotEquals(f1HS, i2HS);
+    }
+
+    public static void main(final String args[]) {
+        final String tstname = TestType.class.getName();
+        org.junit.runner.JUnitCore.main(tstname);
+    }
+
+}
diff --git a/src/junit/com/jogamp/gluegen/test/junit/structgen/TestStructGen01.java b/src/junit/com/jogamp/gluegen/test/junit/structgen/TestStructGen01.java
index 89a9a68..4ecc776 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/structgen/TestStructGen01.java
+++ b/src/junit/com/jogamp/gluegen/test/junit/structgen/TestStructGen01.java
@@ -1,6 +1,6 @@
 package com.jogamp.gluegen.test.junit.structgen;
 
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.Assert;
 import org.junit.BeforeClass;
@@ -9,7 +9,7 @@ import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestStructGen01 extends JunitTracer {
+public class TestStructGen01 extends SingletonJunitCase {
 
     @BeforeClass
     public static void init() {
diff --git a/src/junit/com/jogamp/gluegen/test/junit/structgen/TestStructGen02.java b/src/junit/com/jogamp/gluegen/test/junit/structgen/TestStructGen02.java
index cf0fadc..f3368e0 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/structgen/TestStructGen02.java
+++ b/src/junit/com/jogamp/gluegen/test/junit/structgen/TestStructGen02.java
@@ -1,6 +1,6 @@
 package com.jogamp.gluegen.test.junit.structgen;
 
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.Assert;
 import org.junit.BeforeClass;
@@ -9,7 +9,7 @@ import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestStructGen02 extends JunitTracer {
+public class TestStructGen02 extends SingletonJunitCase {
 
     @BeforeClass
     public static void init() {
diff --git a/src/junit/com/jogamp/junit/sec/Applet01.java b/src/junit/com/jogamp/junit/sec/Applet01.java
index a335efe..f028d7c 100644
--- a/src/junit/com/jogamp/junit/sec/Applet01.java
+++ b/src/junit/com/jogamp/junit/sec/Applet01.java
@@ -34,14 +34,13 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.net.URISyntaxException;
-import java.net.URL;
 import java.security.AccessControlException;
 
-import com.jogamp.common.os.MachineDescription;
+import com.jogamp.common.net.Uri;
+import com.jogamp.common.os.MachineDataInfo;
 import com.jogamp.common.os.NativeLibrary;
 import com.jogamp.common.os.Platform;
 import com.jogamp.common.util.IOUtil;
-import com.jogamp.common.util.JarUtil;
 
 /**
  * Applet: Provoke AccessControlException while writing to file!
@@ -53,7 +52,7 @@ public class Applet01 extends Applet {
     static final String os_name_propkey = "os.name";
 
     static final String tfilename = "test.bin" ;
-    static final MachineDescription machine = Platform.getMachineDescription();
+    static final MachineDataInfo machine = Platform.getMachineDataInfo();
     static final int tsz = machine.pageSizeInBytes();
 
     static final boolean usesSecurityManager;
@@ -112,6 +111,17 @@ public class Applet01 extends Applet {
                 System.err.println("Unexpected exception for secure temp dir");
                 se0.printStackTrace();
             }
+        } catch (final SecurityException e) {
+            se0 = e;
+            if( !isSecure ) {
+                System.err.println("Expected exception for insecure temp dir (2)");
+                System.err.println("Message: "+se0.getMessage());
+            } else {
+                System.err.println("Unexpected exception for secure temp dir (2)");
+                se0.printStackTrace();
+            }
+        } catch (final IOException e) {
+            throw new RuntimeException(e); // oops
         }
         if( isSecure ) {
             if( null != se0 ) {
@@ -156,64 +166,64 @@ public class Applet01 extends Applet {
         }
     }
 
-    private void testOpenLibrary(final boolean global) {
+    private void testOpenLibrary(final boolean global) throws URISyntaxException {
         final ClassLoader cl = getClass().getClassLoader();
         System.err.println("CL "+cl);
 
         String libBaseName = null;
         final Class<?> clazz = this.getClass();
-        URL libURL = clazz.getResource("/libtest1.so");
-        if( null != libURL ) {
+        Uri libUri = null;
+        try {
+            libUri = Uri.valueOf(clazz.getResource("/libtest1.so"));
+        } catch (final URISyntaxException e2) {
+            // not found .. OK
+        }
+        if( null != libUri ) {
             libBaseName = "libtest1.so";
         } else {
-            libURL = clazz.getResource("/test1.dll");
-            if( null != libURL ) {
-                libBaseName = "test1.dll";
+            try {
+                libUri = Uri.valueOf(clazz.getResource("/test1.dll"));
+                if( null != libUri ) {
+                    libBaseName = "test1.dll";
+                }
+            } catch (final URISyntaxException e) {
+                // not found
             }
         }
-        System.err.println("Untrusted Library (URL): "+libURL);
+        System.err.println("Untrusted Library (URL): "+libUri);
 
-        String libDir1 = null;
-        if( null != libURL ) {
+        if( null != libUri ) {
+            Uri libDir1 = libUri.getContainedUri();
+            System.err.println("libDir1.1: "+libDir1);
+            libDir1= libDir1.getParent();
+            System.err.println("libDir1.2: "+libDir1);
+            System.err.println("Untrusted Library Dir1 (abs): "+libDir1);
+            final Uri absLib = libDir1.concat(Uri.Encoded.cast("natives/" + libBaseName));
+            Exception sec01 = null;
             try {
-                libDir1 = JarUtil.getJarSubURI(libURL.toURI()).getPath();
-            } catch (final Exception e) {
-                e.printStackTrace();
-            }
-            if( null != libDir1 ) {
-                System.err.println("libDir1.1: "+libDir1);
-                try {
-                    libDir1= IOUtil.getParentOf(libDir1);
-                } catch (final URISyntaxException e) {
-                    e.printStackTrace();
+                final NativeLibrary nlib = NativeLibrary.open(absLib.toFile().getPath(), cl);
+                System.err.println("NativeLibrary: "+nlib);
+            } catch (final SecurityException e) {
+                sec01 = e;
+                if( usesSecurityManager ) {
+                    System.err.println("Expected exception for loading native library");
+                    System.err.println("Message: "+sec01.getMessage());
+                } else {
+                    System.err.println("Unexpected exception for loading native library");
+                    sec01.printStackTrace();
                 }
-                System.err.println("libDir1.2: "+libDir1);
             }
-        }
-        System.err.println("Untrusted Library Dir1 (abs): "+libDir1);
-        final String absLib = libDir1 + "natives/" + libBaseName;
-        Exception sec01 = null;
-        try {
-            final NativeLibrary nlib = NativeLibrary.open(absLib, cl);
-            System.err.println("NativeLibrary: "+nlib);
-        } catch (final SecurityException e) {
-            sec01 = e;
-            if( usesSecurityManager ) {
-                System.err.println("Expected exception for loading native library");
-                System.err.println("Message: "+sec01.getMessage());
+            if( !usesSecurityManager ) {
+                if( null != sec01 ) {
+                    throw new Error("SecurityException thrown on loading native library", sec01);
+                }
             } else {
-                System.err.println("Unexpected exception for loading native library");
-                sec01.printStackTrace();
-            }
-        }
-        if( !usesSecurityManager ) {
-            if( null != sec01 ) {
-                throw new Error("SecurityException thrown on loading native library", sec01);
+                if( null == sec01 ) {
+                    throw new Error("SecurityException not thrown on loading native library");
+                }
             }
         } else {
-            if( null == sec01 ) {
-                throw new Error("SecurityException not thrown on loading native library");
-            }
+            System.err.println("No library found");
         }
     }
 
@@ -244,7 +254,11 @@ public class Applet01 extends Applet {
         testWriteFile();
         System.err.println("writeFile: OK");
 
-        testOpenLibrary(true);
+        try {
+            testOpenLibrary(true);
+        } catch (final URISyntaxException e) {
+            e.printStackTrace();
+        }
         System.err.println("lib0: OK");
     }
 
diff --git a/src/junit/com/jogamp/junit/sec/TestSecIOUtil01.java b/src/junit/com/jogamp/junit/sec/TestSecIOUtil01.java
index e4e1b34..b3a1877 100644
--- a/src/junit/com/jogamp/junit/sec/TestSecIOUtil01.java
+++ b/src/junit/com/jogamp/junit/sec/TestSecIOUtil01.java
@@ -29,7 +29,6 @@
 package com.jogamp.junit.sec;
 
 import java.net.URISyntaxException;
-import java.net.URL;
 import java.security.AccessControlException;
 import java.io.File;
 import java.io.IOException;
@@ -38,17 +37,17 @@ import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
+import com.jogamp.common.net.Uri;
 import com.jogamp.common.os.NativeLibrary;
 import com.jogamp.common.os.Platform;
 import com.jogamp.common.util.IOUtil;
-import com.jogamp.common.util.JarUtil;
-import com.jogamp.junit.util.JunitTracer;
+import com.jogamp.junit.util.SingletonJunitCase;
 
 import org.junit.FixMethodOrder;
 import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestSecIOUtil01 extends JunitTracer {
+public class TestSecIOUtil01 extends SingletonJunitCase {
     static final String java_io_tmpdir_propkey = "java.io.tmpdir";
     static final String java_home_propkey = "java.home";
     static final String os_name_propkey = "os.name";
@@ -124,6 +123,17 @@ public class TestSecIOUtil01 extends JunitTracer {
                 System.err.println("Unexpected exception for secure temp dir");
                 se0.printStackTrace();
             }
+        } catch (final SecurityException e) {
+            se0 = e;
+            if( !isSecure ) {
+                System.err.println("Expected exception for insecure temp dir (2)");
+                System.err.println("Message: "+se0.getMessage());
+            } else {
+                System.err.println("Unexpected exception for secure temp dir (2)");
+                se0.printStackTrace();
+            }
+        } catch (final IOException e) {
+            throw new RuntimeException(e); // oops
         }
         if( isSecure ) {
             Assert.assertNull("AccessControlException thrown on secure temp dir", se0);
@@ -137,73 +147,75 @@ public class TestSecIOUtil01 extends JunitTracer {
         testTempDirImpl(false);
     }
 
-    private NativeLibrary openLibraryImpl(final boolean global) {
+    private NativeLibrary openLibraryImpl(final boolean global) throws URISyntaxException {
         final ClassLoader cl = getClass().getClassLoader();
         System.err.println("CL "+cl);
 
         String libBaseName = null;
         final Class<?> clazz = this.getClass();
-        URL libURL = clazz.getResource("/libtest1.so");
-        if( null != libURL ) {
+        Uri libUri = null;
+        try {
+            libUri = Uri.valueOf(clazz.getResource("/libtest1.so"));
+        } catch (final URISyntaxException e2) {
+            // not found .. OK
+        }
+        if( null != libUri ) {
             libBaseName = "libtest1.so";
         } else {
-            libURL = clazz.getResource("/test1.dll");
-            if( null != libURL ) {
-                libBaseName = "test1.dll";
+            try {
+                libUri = Uri.valueOf(clazz.getResource("/test1.dll"));
+                if( null != libUri ) {
+                    libBaseName = "test1.dll";
+                }
+            } catch (final URISyntaxException e) {
+                // not found
             }
         }
-        System.err.println("Untrusted Library (URL): "+libURL);
-
-        String libDir1 = null;
-        if( null != libURL ) {
+        System.err.println("Untrusted Library (URL): "+libUri);
+
+        if( null != libUri ) {
+            Uri libDir1 = libUri.getContainedUri();
+            System.err.println("libDir1.1: "+libDir1);
+            libDir1= libDir1.getParent();
+            System.err.println("libDir1.2: "+libDir1);
+            System.err.println("Untrusted Library Dir1 (abs): "+libDir1);
+            final Uri absLib = libDir1.concat(Uri.Encoded.cast("natives/" + libBaseName));
+            Exception se0 = null;
+            NativeLibrary nlib = null;
             try {
-                libDir1 = JarUtil.getJarSubURI(libURL.toURI()).getPath();
-            } catch (final Exception e) {
-                e.printStackTrace();
-            }
-            if( null != libDir1 ) {
-                System.err.println("libDir1.1: "+libDir1);
-                try {
-                    libDir1= IOUtil.getParentOf(libDir1);
-                } catch (final URISyntaxException e) {
-                    e.printStackTrace();
+                nlib = NativeLibrary.open(absLib.toFile().getPath(), cl);
+                System.err.println("NativeLibrary: "+nlib);
+            } catch (final SecurityException e) {
+                se0 = e;
+                if( usesSecurityManager ) {
+                    System.err.println("Expected exception for loading native library");
+                    System.err.println("Message: "+se0.getMessage());
+                } else {
+                    System.err.println("Unexpected exception for loading native library");
+                    se0.printStackTrace();
                 }
-                System.err.println("libDir1.2: "+libDir1);
             }
-        }
-        System.err.println("Untrusted Library Dir1 (abs): "+libDir1);
-        final String absLib = libDir1 + "natives/" + libBaseName;
-        Exception se0 = null;
-        NativeLibrary nlib = null;
-        try {
-            nlib = NativeLibrary.open(absLib, cl);
-            System.err.println("NativeLibrary: "+nlib);
-        } catch (final SecurityException e) {
-            se0 = e;
-            if( usesSecurityManager ) {
-                System.err.println("Expected exception for loading native library");
-                System.err.println("Message: "+se0.getMessage());
+            if( !usesSecurityManager ) {
+                Assert.assertNull("SecurityException thrown on loading native library", se0);
             } else {
-                System.err.println("Unexpected exception for loading native library");
-                se0.printStackTrace();
+                Assert.assertNotNull("SecurityException not thrown on loading native library", se0);
             }
-        }
-        if( !usesSecurityManager ) {
-            Assert.assertNull("SecurityException thrown on loading native library", se0);
+            return nlib;
         } else {
-            Assert.assertNotNull("SecurityException not thrown on loading native library", se0);
+            System.err.println("No library found");
+            return null;
         }
-        return nlib;
+
     }
 
-    public void testOpenLibrary() {
+    public void testOpenLibrary() throws URISyntaxException {
         final NativeLibrary nlib = openLibraryImpl(true);
         if( null != nlib ) {
             nlib.close();
         }
     }
 
-    public static void main(final String args[]) throws IOException {
+    public static void main(final String args[]) throws IOException, URISyntaxException {
         TestSecIOUtil01.setup();
 
         final TestSecIOUtil01 aa = new TestSecIOUtil01();
diff --git a/src/junit/com/jogamp/junit/util/JunitTracer.java b/src/junit/com/jogamp/junit/util/JunitTracer.java
index 0575532..f6cb953 100644
--- a/src/junit/com/jogamp/junit/util/JunitTracer.java
+++ b/src/junit/com/jogamp/junit/util/JunitTracer.java
@@ -28,6 +28,10 @@
 
 package com.jogamp.junit.util;
 
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
 import org.junit.Assume;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -41,11 +45,15 @@ import org.junit.runners.MethodSorters;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 public abstract class JunitTracer {
-    @Rule public TestName _unitTestName = new TestName();
+    @Rule public final TestName _unitTestName = new TestName();
 
     static volatile boolean testSupported = true;
 
-    public static void setTestSupported(final boolean v) {
+    public static final boolean isTestSupported() {
+        return testSupported;
+    }
+
+    public static final void setTestSupported(final boolean v) {
         System.err.println("setTestSupported: "+v);
         testSupported = v;
     }
@@ -63,18 +71,18 @@ public abstract class JunitTracer {
     }
 
     @BeforeClass
-    public static void oneTimeSetUp() {
+    public static final void oneTimeSetUpBase() {
         // one-time initialization code
     }
 
     @AfterClass
-    public static void oneTimeTearDown() {
+    public static final void oneTimeTearDownBase() {
         // one-time cleanup code
         System.gc(); // force cleanup
     }
 
     @Before
-    public void setUp() {
+    public final void setUpBase() {
         System.err.print("++++ TestCase.setUp: "+getFullTestName(" - "));
         if(!testSupported) {
             System.err.println(" - "+unsupportedTestMsg);
@@ -84,10 +92,18 @@ public abstract class JunitTracer {
     }
 
     @After
-    public void tearDown() {
+    public final void tearDownBase() {
         System.err.println("++++ TestCase.tearDown: "+getFullTestName(" - "));
     }
 
     static final String unsupportedTestMsg = "Test not supported on this platform.";
+
+    public static final void waitForKey(final String preMessage) {
+        final BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
+        System.err.println(preMessage+"> Press enter to continue");
+        try {
+            System.err.println(stdin.readLine());
+        } catch (final IOException e) { e.printStackTrace(); }
+    }
 }
 
diff --git a/src/junit/com/jogamp/junit/util/SingletonJunitCase.java b/src/junit/com/jogamp/junit/util/SingletonJunitCase.java
new file mode 100644
index 0000000..7fb5fea
--- /dev/null
+++ b/src/junit/com/jogamp/junit/util/SingletonJunitCase.java
@@ -0,0 +1,79 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ *
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.junit.util;
+
+import com.jogamp.common.util.locks.SingletonInstance;
+
+import org.junit.BeforeClass;
+import org.junit.AfterClass;
+import org.junit.FixMethodOrder;
+import org.junit.runners.MethodSorters;
+
+ at FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public abstract class SingletonJunitCase extends JunitTracer {
+    public static final String SINGLE_INSTANCE_LOCK_FILE = "SingletonTestCase.lock";
+    public static final int SINGLE_INSTANCE_LOCK_PORT = 59999;
+
+    public static final long SINGLE_INSTANCE_LOCK_TO   = 15*60*1000; // wait up to 15 mins
+    public static final long SINGLE_INSTANCE_LOCK_POLL =        500; // poll every 500 ms
+
+    private static SingletonInstance singletonInstance = null; // system wide lock via port locking
+    private static final Object singletonSync = new Object();  // classloader wide lock
+
+    @BeforeClass
+    public static final void oneTimeSetUpSingleton() {
+        // one-time initialization code
+        synchronized( singletonSync ) {
+            if( null == singletonInstance )  {
+                System.err.println("++++ Test Singleton.ctor()");
+                // singletonInstance = SingletonInstance.createFileLock(SINGLE_INSTANCE_LOCK_POLL, SINGLE_INSTANCE_LOCK_FILE);
+                singletonInstance = SingletonInstance.createServerSocket(SINGLE_INSTANCE_LOCK_POLL, SINGLE_INSTANCE_LOCK_PORT);
+            }
+            System.err.println("++++ Test Singleton.lock()");
+            if(!singletonInstance.tryLock(SINGLE_INSTANCE_LOCK_TO)) {
+                throw new RuntimeException("Fatal: Could not lock single instance: "+singletonInstance.getName());
+            }
+        }
+    }
+
+    @AfterClass
+    public static final void oneTimeTearDownSingleton() {
+        // one-time cleanup code
+        synchronized( singletonSync ) {
+            System.gc(); // force cleanup
+            System.err.println("++++ Test Singleton.unlock()");
+            singletonInstance.unlock();
+            try {
+                // allowing other JVM instances to pick-up socket
+                Thread.sleep( SINGLE_INSTANCE_LOCK_POLL );
+            } catch (final InterruptedException e) { }
+        }
+    }
+}
+
diff --git a/src/junit/com/jogamp/junit/util/VersionSemanticsUtil.java b/src/junit/com/jogamp/junit/util/VersionSemanticsUtil.java
index 953c795..78f4460 100644
--- a/src/junit/com/jogamp/junit/util/VersionSemanticsUtil.java
+++ b/src/junit/com/jogamp/junit/util/VersionSemanticsUtil.java
@@ -29,7 +29,6 @@ package com.jogamp.junit.util;
 
 import java.io.File;
 import java.io.IOException;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.HashSet;
 import java.util.Set;
@@ -40,7 +39,7 @@ import org.semver.Comparer;
 import org.semver.Delta;
 import org.semver.Dumper;
 
-import com.jogamp.common.util.IOUtil;
+import com.jogamp.common.net.Uri;
 import com.jogamp.common.util.JarUtil;
 import com.jogamp.common.util.VersionNumberString;
 
@@ -54,12 +53,10 @@ public class VersionSemanticsUtil {
                                        throws IllegalArgumentException, IOException, URISyntaxException
     {
         // Get containing JAR file "TestJarsInJar.jar" and add it to the TempJarCache
-        final URI currentJarURI = JarUtil.getJarSubURI(currentJarClazz.getName(), currentJarCL);
-        final String currentJarLocS = IOUtil.decodeURIIfFilePath(currentJarURI);
-        final File currentJar = new File(currentJarLocS);
+        final Uri currentJarUri = JarUtil.getJarUri(currentJarClazz.getName(), currentJarCL).getContainedUri();
         testVersion(diffCriteria, expectedCompatibilityType,
                     previousJar, preVersionNumber,
-                    currentJar, curVersionNumber,
+                    currentJarUri.toFile(), curVersionNumber,
                     excludesRegExp);
     }
 
diff --git a/src/native/common/JVMUtil.c b/src/native/common/JVMUtil.c
index 6df2aff..e9b399f 100644
--- a/src/native/common/JVMUtil.c
+++ b/src/native/common/JVMUtil.c
@@ -43,6 +43,11 @@
 
 #include "jogamp_common_jvm_JVMUtil.h"
 
+/*
+ * Class:     jogamp_common_jvm_JVMUtil
+ * Method:    initialize
+ * Signature: (Ljava/nio/ByteBuffer;)Z
+ */
 JNIEXPORT jboolean JNICALL
 Java_jogamp_common_jvm_JVMUtil_initialize(JNIEnv *env, jclass _unused, jobject nioBuffer) {
   void * ptr = NULL;
diff --git a/src/native/common/MachineDescriptionRuntime.c b/src/native/common/MachineDataInfoRuntime.c
similarity index 68%
rename from src/native/common/MachineDescriptionRuntime.c
rename to src/native/common/MachineDataInfoRuntime.c
index a8a69ee..4c6c9e3 100644
--- a/src/native/common/MachineDescriptionRuntime.c
+++ b/src/native/common/MachineDataInfoRuntime.c
@@ -3,7 +3,7 @@
 
 #include <assert.h>
 
-#include "jogamp_common_os_MachineDescriptionRuntime.h"
+#include "jogamp_common_os_MachineDataInfoRuntime.h"
 
 #if defined(_WIN32)
     #include <windows.h>
@@ -14,12 +14,12 @@
 #include <gluegen_stdint.h>
 
 JNIEXPORT jint JNICALL 
-Java_jogamp_common_os_MachineDescriptionRuntime_getPointerSizeInBytesImpl(JNIEnv *env, jclass _unused) {
+Java_jogamp_common_os_MachineDataInfoRuntime_getPointerSizeInBytesImpl(JNIEnv *env, jclass _unused) {
     return sizeof(void *);
 }
 
 JNIEXPORT jlong JNICALL 
-Java_jogamp_common_os_MachineDescriptionRuntime_getPageSizeInBytesImpl(JNIEnv *env, jclass _unused) {
+Java_jogamp_common_os_MachineDataInfoRuntime_getPageSizeInBytesImpl(JNIEnv *env, jclass _unused) {
 #if defined(_WIN32)
     SYSTEM_INFO si;
     GetSystemInfo(&si);
@@ -84,77 +84,77 @@ typedef struct {
 #define ALIGNMENT(a, b) ( (a) - (b) )
 
 JNIEXPORT jint JNICALL 
-Java_jogamp_common_os_MachineDescriptionRuntime_getAlignmentInt8Impl(JNIEnv *env, jclass _unused) {
+Java_jogamp_common_os_MachineDataInfoRuntime_getAlignmentInt8Impl(JNIEnv *env, jclass _unused) {
     return ALIGNMENT(sizeof( struct_alignment_int8 ), sizeof(int8_t));
 }
 
 JNIEXPORT jint JNICALL 
-Java_jogamp_common_os_MachineDescriptionRuntime_getAlignmentInt16Impl(JNIEnv *env, jclass _unused) {
+Java_jogamp_common_os_MachineDataInfoRuntime_getAlignmentInt16Impl(JNIEnv *env, jclass _unused) {
     return ALIGNMENT(sizeof( struct_alignment_int16 ), sizeof(int16_t));
 }
 
 JNIEXPORT jint JNICALL 
-Java_jogamp_common_os_MachineDescriptionRuntime_getAlignmentInt32Impl(JNIEnv *env, jclass _unused) {
+Java_jogamp_common_os_MachineDataInfoRuntime_getAlignmentInt32Impl(JNIEnv *env, jclass _unused) {
     return ALIGNMENT(sizeof( struct_alignment_int32 ), sizeof(int32_t));
 }
 
 JNIEXPORT jint JNICALL 
-Java_jogamp_common_os_MachineDescriptionRuntime_getAlignmentInt64Impl(JNIEnv *env, jclass _unused) {
+Java_jogamp_common_os_MachineDataInfoRuntime_getAlignmentInt64Impl(JNIEnv *env, jclass _unused) {
     return ALIGNMENT(sizeof( struct_alignment_int64 ), sizeof(int64_t));
 }
 
 JNIEXPORT jint JNICALL 
-Java_jogamp_common_os_MachineDescriptionRuntime_getAlignmentIntImpl(JNIEnv *env, jclass _unused) {
+Java_jogamp_common_os_MachineDataInfoRuntime_getAlignmentIntImpl(JNIEnv *env, jclass _unused) {
     return ALIGNMENT(sizeof( struct_alignment_int ), sizeof(int));
 }
 
 JNIEXPORT jint JNICALL 
-Java_jogamp_common_os_MachineDescriptionRuntime_getAlignmentLongImpl(JNIEnv *env, jclass _unused) {
+Java_jogamp_common_os_MachineDataInfoRuntime_getAlignmentLongImpl(JNIEnv *env, jclass _unused) {
     return ALIGNMENT(sizeof( struct_alignment_long ), sizeof(long));
 }
 
 JNIEXPORT jint JNICALL 
-Java_jogamp_common_os_MachineDescriptionRuntime_getAlignmentPointerImpl(JNIEnv *env, jclass _unused) {
+Java_jogamp_common_os_MachineDataInfoRuntime_getAlignmentPointerImpl(JNIEnv *env, jclass _unused) {
     return ALIGNMENT(sizeof( struct_alignment_pointer ), sizeof(void *));
 }
 
 JNIEXPORT jint JNICALL 
-Java_jogamp_common_os_MachineDescriptionRuntime_getAlignmentFloatImpl(JNIEnv *env, jclass _unused) {
+Java_jogamp_common_os_MachineDataInfoRuntime_getAlignmentFloatImpl(JNIEnv *env, jclass _unused) {
     return ALIGNMENT(sizeof( struct_alignment_float ), sizeof(float));
 }
 
 JNIEXPORT jint JNICALL 
-Java_jogamp_common_os_MachineDescriptionRuntime_getAlignmentDoubleImpl(JNIEnv *env, jclass _unused) {
+Java_jogamp_common_os_MachineDataInfoRuntime_getAlignmentDoubleImpl(JNIEnv *env, jclass _unused) {
     return ALIGNMENT(sizeof( struct_alignment_double ), sizeof(double));
 }
 
 JNIEXPORT jint JNICALL 
-Java_jogamp_common_os_MachineDescriptionRuntime_getAlignmentLongDoubleImpl(JNIEnv *env, jclass _unused) {
+Java_jogamp_common_os_MachineDataInfoRuntime_getAlignmentLongDoubleImpl(JNIEnv *env, jclass _unused) {
     return ALIGNMENT(sizeof( struct_alignment_ldouble ), sizeof(long double));
 }
 
 JNIEXPORT jint JNICALL 
-Java_jogamp_common_os_MachineDescriptionRuntime_getSizeOfIntImpl(JNIEnv *env, jclass _unused) {
+Java_jogamp_common_os_MachineDataInfoRuntime_getSizeOfIntImpl(JNIEnv *env, jclass _unused) {
     return sizeof(int);
 }
 
 JNIEXPORT jint JNICALL 
-Java_jogamp_common_os_MachineDescriptionRuntime_getSizeOfLongImpl(JNIEnv *env, jclass _unused) {
+Java_jogamp_common_os_MachineDataInfoRuntime_getSizeOfLongImpl(JNIEnv *env, jclass _unused) {
     return sizeof(long);
 }
 
 JNIEXPORT jint JNICALL 
-Java_jogamp_common_os_MachineDescriptionRuntime_getSizeOfFloatImpl(JNIEnv *env, jclass _unused) {
+Java_jogamp_common_os_MachineDataInfoRuntime_getSizeOfFloatImpl(JNIEnv *env, jclass _unused) {
     return sizeof(float);
 }
 
 JNIEXPORT jint JNICALL 
-Java_jogamp_common_os_MachineDescriptionRuntime_getSizeOfDoubleImpl(JNIEnv *env, jclass _unused) {
+Java_jogamp_common_os_MachineDataInfoRuntime_getSizeOfDoubleImpl(JNIEnv *env, jclass _unused) {
     return sizeof(double);
 }
 
 JNIEXPORT jint JNICALL 
-Java_jogamp_common_os_MachineDescriptionRuntime_getSizeOfLongDoubleImpl(JNIEnv *env, jclass _unused) {
+Java_jogamp_common_os_MachineDataInfoRuntime_getSizeOfLongDoubleImpl(JNIEnv *env, jclass _unused) {
     return sizeof(long double);
 }
 
diff --git a/src/native/tinype-corkami/consts.inc b/src/native/tinype-corkami/consts.inc
new file mode 100644
index 0000000..8005ffc
--- /dev/null
+++ b/src/native/tinype-corkami/consts.inc
@@ -0,0 +1,675 @@
+%define PREFIX_OPERANDSIZE db 66h
+
+IMAGE_RESOURCE_DATA_IS_DIRECTORY equ 80000000h
+PAGE_READWRITE equ 4
+ExceptionContinueExecution equ 0
+
+DLL_PROCESS_ATTACH equ 1
+DLL_PROCESS_DETACH equ 0
+
+IMAGE_SCN_CNT_CODE               equ 000000020h
+IMAGE_SCN_CNT_INITIALIZED_DATA   equ 000000040h
+IMAGE_SCN_MEM_SHARED             equ 010000000h
+IMAGE_SCN_MEM_EXECUTE            equ 020000000h
+IMAGE_SCN_MEM_READ               equ 040000000h
+IMAGE_SCN_MEM_WRITE              equ 080000000h
+
+MEM_COMMIT equ 1000h
+
+BREAKPOINT equ 080000003h
+SINGLE_STEP equ 80000004h
+ACCESS_VIOLATION equ 0c0000005h
+INVALID_HANDLE equ 0C0000008h
+INVALID_LOCK_SEQUENCE equ 0C000001eh
+INTEGER_DIVIDE_BY_ZERO equ 0C0000094h
+INTEGER_OVERFLOW equ 0C0000095h
+PRIVILEGED_INSTRUCTION equ 0C0000096h
+
+struc exceptionHandler
+    .pException resd 1          ; EXCEPTION_RECORD
+    .pRegistrationRecord resd 1 ; EXCEPTION_REGISTRATION_RECORD
+    .pContext resd 1            ; CONTEXT
+endstruc
+
+SIZE_OF_80387_REGISTERS equ 80
+MAXIMUM_SUPPORTED_EXTENSION equ 512
+
+struc CONTEXT
+    .ContextFlags  resd 1
+    ;CONTEXT_DEBUG_REGISTERS
+    .iDr0          resd 1
+    .iDr1          resd 1
+    .iDr2          resd 1
+    .iDr3          resd 1
+    .iDr6          resd 1
+    .iDr7          resd 1
+    ;CONTEXT_FLOATING_POINT
+    .ControlWord   resd 1
+    .StatusWord    resd 1
+    .TagWord       resd 1
+    .ErrorOffset   resd 1
+    .ErrorSelector resd 1
+    .DataOffset    resd 1
+    .DataSelector  resd 1
+    .RegisterArea  resb SIZE_OF_80387_REGISTERS
+    .Cr0NpxState   resd 1
+    ;CONTEXT_SEGMENTS
+    .regGs   resd 1
+    .regFs   resd 1
+    .regEs   resd 1
+    .regDs   resd 1
+    ;CONTEXT_INTEGER
+    .regEdi  resd 1
+    .regEsi  resd 1
+    .regEbx  resd 1
+    .regEdx  resd 1
+    .regEcx  resd 1
+    .regEax  resd 1
+    ;CONTEXT_CONTROL
+    .regEbp  resd 1
+    .regEip  resd 1
+    .regCs   resd 1
+    .regFlag resd 1
+    .regEsp  resd 1
+    .regSs   resd 1
+    ;CONTEXT_EXTENDED_REGISTERS
+    .ExtendedRegisters resb MAXIMUM_SUPPORTED_EXTENSION
+endstruc
+
+IMAGE_SIZEOF_SHORT_NAME equ 8
+
+struc IMAGE_DOS_HEADER
+  .e_magic      resw 1
+  .e_cblp       resw 1
+  .e_cp         resw 1
+  .e_crlc       resw 1
+  .e_cparhdr    resw 1
+  .e_minalloc   resw 1
+  .e_maxalloc   resw 1
+  .e_ss         resw 1
+  .e_sp         resw 1
+  .e_csum       resw 1
+  .e_ip         resw 1
+  .e_cs         resw 1
+  .e_lfarlc     resw 1
+  .e_ovno       resw 1
+  .e_res        resw 4
+  .e_oemid      resw 1
+  .e_oeminfo    resw 1
+  .e_res2       resw 10
+  .e_lfanew     resd 1
+endstruc
+
+struc IMAGE_NT_HEADERS
+  .Signature         resd 1
+;  .FileHeader        resb IMAGE_FILE_HEADER_size
+;  .OptionalHeader    resb IMAGE_OPTIONAL_HEADER32_size
+endstruc
+
+struc IMAGE_FILE_HEADER
+  .Machine              resw 1
+  .NumberOfSections     resw 1
+  .TimeDateStamp        resd 1
+  .PointerToSymbolTable resd 1
+  .NumberOfSymbols      resd 1
+  .SizeOfOptionalHeader resw 1
+  .Characteristics      resw 1
+endstruc
+
+IMAGE_FILE_MACHINE_I386         equ 014ch
+IMAGE_FILE_DLL equ 02000h
+IMAGE_NT_OPTIONAL_HDR32_MAGIC equ 010bh
+
+struc IMAGE_OPTIONAL_HEADER32
+  .Magic                        resw 1
+  .MajorLinkerVersion           resb 1
+  .MinorLinkerVersion           resb 1
+  .SizeOfCode                   resd 1
+  .SizeOfInitializedData        resd 1
+  .SizeOfUninitializedData      resd 1
+  .AddressOfEntryPoint          resd 1
+  .BaseOfCode                   resd 1
+  .BaseOfData                   resd 1
+  .ImageBase                    resd 1
+  .SectionAlignment             resd 1
+  .FileAlignment                resd 1
+  .MajorOperatingSystemVersion  resw 1
+  .MinorOperatingSystemVersion  resw 1
+  .MajorImageVersion            resw 1
+  .MinorImageVersion            resw 1
+  .MajorSubsystemVersion        resw 1
+  .MinorSubsystemVersion        resw 1
+  .Win32VersionValue            resd 1
+  .SizeOfImage                  resd 1
+  .SizeOfHeaders                resd 1
+  .CheckSum                     resd 1
+  .Subsystem                    resw 1
+  .DllCharacteristics           resw 1
+  .SizeOfStackReserve           resd 1
+  .SizeOfStackCommit            resd 1
+  .SizeOfHeapReserve            resd 1
+  .SizeOfHeapCommit             resd 1
+  .LoaderFlags                  resd 1
+  .NumberOfRvaAndSizes          resd 1
+  .DataDirectory                resb 0
+endstruc
+
+struc IMAGE_DATA_DIRECTORY
+  VirtualAddress    resd 1
+  isize             resd 1
+endstruc
+
+struc IMAGE_DATA_DIRECTORY_16
+    .ExportsVA        resd 1
+    .ExportsSize      resd 1
+    .ImportsVA        resd 1
+    .ImportsSize      resd 1
+    .ResourceVA       resd 1
+    .ResourceSize     resd 1
+    .Exception        resd 2
+    .Security         resd 2
+    .FixupsVA         resd 1
+    .FixupsSize       resd 1
+    .DebugVA          resd 1
+    .DebugSize        resd 1
+    .Description      resd 2
+    .MIPS             resd 2
+    .TLSVA            resd 1
+    .TLSSize          resd 1
+    .Load             resd 2
+    .BoundImportsVA   resd 1
+    .BoundImportsSize resd 1
+    .IATVA            resd 1
+    .IATSize          resd 1
+    .DelayImportsVA   resd 1
+    .DelayImportsSize resd 1
+    .COM              resd 2
+    .reserved         resd 2
+endstruc
+
+struc IMAGE_SECTION_HEADER
+    .Name                    resb IMAGE_SIZEOF_SHORT_NAME
+    .VirtualSize             resd 1
+    .VirtualAddress          resd 1
+    .SizeOfRawData           resd 1
+    .PointerToRawData        resd 1
+    .PointerToRelocations    resd 1
+    .PointerToLinenumbers    resd 1
+    .NumberOfRelocations     resw 1
+    .NumberOfLinenumbers     resw 1
+    .Characteristics         resd 1
+endstruc
+
+
+IMAGE_SUBSYSTEM_WINDOWS_CUI    equ 3
+IMAGE_SUBSYSTEM_WINDOWS_GUI    equ 2
+IMAGE_FILE_RELOCS_STRIPPED         equ 00001h
+IMAGE_FILE_EXECUTABLE_IMAGE        equ 00002h
+IMAGE_FILE_LINE_NUMS_STRIPPED      equ 00004h
+IMAGE_FILE_LOCAL_SYMS_STRIPPED     equ 00008h
+IMAGE_FILE_32BIT_MACHINE           equ 00100h
+
+%macro _ 0
+    nop
+%endmacro
+
+%macro _c 0
+    int3
+    align 4, int3
+%endmacro
+
+%macro _d 0
+    db 0
+    align 16, db 0
+%endmacro
+
+
+%macro setSEH 1
+    push  %1
+    push dword [fs:0]
+    mov [fs:0], esp
+%endmacro
+
+%macro clearSEH 0
+    pop dword [fs:0]
+    add esp, 4
+%endmacro
+
+struc IMAGE_OPTIONAL_HEADER64
+  .Magic                        resw 1
+  .MajorLinkerVersion           resb 1
+  .MinorLinkerVersion           resb 1
+  .SizeOfCode                   resd 1
+  .SizeOfInitializedData        resd 1
+  .SizeOfUninitializedData      resd 1
+  .AddressOfEntryPoint          resd 1
+  .BaseOfCode                   resd 1
+  .ImageBase                    resq 1
+  .SectionAlignment             resd 1
+  .FileAlignment                resd 1
+  .MajorOperatingSystemVersion  resw 1
+  .MinorOperatingSystemVersion  resw 1
+  .MajorImageVersion            resw 1
+  .MinorImageVersion            resw 1
+  .MajorSubsystemVersion        resw 1
+  .MinorSubsystemVersion        resw 1
+  .Win32VersionValue            resd 1
+  .SizeOfImage                  resd 1
+  .SizeOfHeaders                resd 1
+  .CheckSum                     resd 1
+  .Subsystem                    resw 1
+  .DllCharacteristics           resw 1
+  .SizeOfStackReserve           resq 1
+  .SizeOfStackCommit            resq 1
+  .SizeOfHeapReserve            resq 1
+  .SizeOfHeapCommit             resq 1
+  .LoaderFlags                  resd 1
+  .NumberOfRvaAndSizes          resd 1
+  .DataDirectory                resb 0
+endstruc
+
+IMAGE_FILE_MACHINE_AMD64        equ 8664h
+IMAGE_NT_OPTIONAL_HDR64_MAGIC   equ 020bh
+
+IMAGE_REL_BASED_ABSOLUTE       equ 0 ; used for padding
+IMAGE_REL_BASED_HIGH           equ 1
+IMAGE_REL_BASED_LOW            equ 2 ; does nothing
+IMAGE_REL_BASED_HIGHLOW        equ 3 ;
+IMAGE_REL_BASED_HIGHADJ        equ 4 ; takes an argument but actually does nothing
+IMAGE_REL_BASED_MIPS_JMPADDR   equ 5 ; until W7 only
+IMAGE_REL_BASED_SECTION        equ 6 ; until W7 only ; does nothing anyway
+IMAGE_REL_BASED_REL32          equ 7 ; until W7 only ; does nothing anyway
+; 8 is always rejected, historically
+IMAGE_REL_BASED_MIPS_JMPADDR16 equ 9
+IMAGE_REL_BASED_IA64_IMM64     equ 9
+IMAGE_REL_BASED_DIR64          equ 10
+IMAGE_REL_BASED_HIGH3ADJ       equ 11 ; Win2k only
+
+CR equ 0dh
+EOF equ 1ah
+LF equ 0ah
+
+struc IMAGE_RESOURCE_DIRECTORY
+ .Characteristics         resd 1
+ .TimeDateStamp           resd 1
+ .MajorVersion            resw 1
+ .MinorVersion            resw 1
+ .NumberOfNamedEntries    resw 1
+ .NumberOfIdEntries       resw 1
+endstruc
+
+struc IMAGE_RESOURCE_DIRECTORY_ENTRY
+    .NameID resd 1
+    .OffsetToData resd 1
+endstruc
+
+struc IMAGE_RESOURCE_DATA_ENTRY
+    .OffsetToData resd 1
+    .Size1        resd 1
+    .CodePage     resd 1
+    .Reserved     resd 1
+endstruc
+
+struc _IMAGE_DELAY_IMPORT_DESCRIPTOR
+    .grAttrs       resd 1  ; attributes
+    .rvaDLLName    resd 1  ; RVA to dll name
+    .rvaHmod       resd 1  ; RVA of module handle
+    .rvaIAT        resd 1  ; RVA of the IAT
+    .rvaINT        resd 1  ; RVA of the INT
+    .rvaBoundIAT   resd 1  ; RVA of the optional bound IAT
+    .rvaUnloadIAT  resd 1  ; RVA of optional copy of original IAT
+    .dwTimeStamp   resd 1  ; 0 if not bound
+endstruc
+
+struc TRUNC_OPTIONAL_HEADER32
+  .Magic                        resw 1
+  .MajorLinkerVersion           resb 1
+  .MinorLinkerVersion           resb 1
+  .SizeOfCode                   resd 1
+  .SizeOfInitializedData        resd 1
+  .SizeOfUninitializedData      resd 1
+  .AddressOfEntryPoint          resd 1
+  .BaseOfCode                   resd 1
+  .BaseOfData                   resd 1
+  .ImageBase                    resd 1
+  .SectionAlignment             resd 1
+  .FileAlignment                resd 1
+  .MajorOperatingSystemVersion  resw 1
+  .MinorOperatingSystemVersion  resw 1
+  .MajorImageVersion            resw 1
+  .MinorImageVersion            resw 1
+  .MajorSubsystemVersion        resw 1
+  .MinorSubsystemVersion        resw 1
+  .Win32VersionValue            resd 1
+  .SizeOfImage                  resd 1
+  .SizeOfHeaders                resd 1
+  .CheckSum                     resd 1
+  .Subsystem                    resb 1  ; truncated as a byte
+  ; no more data
+endstruc
+
+struc VS_FIXEDFILEINFO
+  .dwSignature           resd 1
+  .dwStrucVersion        resd 1
+  .dwFileVersionMS       resd 1
+  .dwFileVersionLS       resd 1
+  .dwProductVersionMS    resd 1
+  .dwProductVersionLS    resd 1
+  .dwFileFlagsMask       resd 1
+  .dwFileFlags           resd 1
+  .dwFileOS              resd 1
+  .dwFileType            resd 1
+  .dwFileSubtype         resd 1
+  .dwFileDateMS          resd 1
+  .dwFileDateLS          resd 1
+endstruc
+
+CREATEPROCESS_MANIFEST_RESOURCE_ID EQU 1
+ISOLATIONAWARE_MANIFEST_RESOURCE_ID EQU 2
+ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID EQU 3
+
+
+struc ACTCTX                       ; typedef struct tagACTCTX {
+.cbSize resd 1                     ;   ULONG   cbSize;
+.dwFlags resd 1                    ;   DWORD   dwFlags;
+.lpSource resd 1                   ;   LPCWSTR lpSource;
+.wProcessorArchitecture resw 1     ;   USHORT  wProcessorArchitecture;
+.wLangId resw 1                    ;   LANGID  wLangId;
+.lpAssemblyDirectory resd 1        ;   LPCTSTR lpAssemblyDirectory;
+.lpResourceName resd 1             ;   LPCTSTR lpResourceName;
+.lpApplicationName resd 1          ;   LPCTSTR lpApplicationName;
+.hModule resd 1                    ;   HMODULE hModule;
+endstruc                           ; } ACTCTX, *PACTCTX;
+
+ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID equ 1
+ACTCTX_FLAG_LANGID_VALID equ 2
+ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID equ 4
+ACTCTX_FLAG_RESOURCE_NAME_VALID equ 8
+ACTCTX_FLAG_SET_PROCESS_DEFAULT equ 16
+ACTCTX_FLAG_APPLICATION_NAME_VALID equ 32
+ACTCTX_FLAG_HMODULE_VALID equ 128
+
+; widechar string macro
+%macro WIDE 1
+%assign %%__i 1
+%strlen %%__len %1
+%rep %%__len
+	%substr %%__c %1 %%__i
+		db %%__c
+		db 0
+	%assign %%__i %%__i + 1
+%endrep
+	db 0, 0
+%endmacro
+
+%macro _widestr_no0 1
+%assign %%__i 1
+%strlen %%__len %1
+%rep %%__len
+	%substr %%__c %1 %%__i
+		db %%__c
+		db 0
+	%assign %%__i %%__i + 1
+%endrep
+%endmacro
+
+%macro __string 2
+%%string:
+dw %%SLEN
+dw %%VALLEN / 2 ; dammit !
+dw 1 ; text type
+WIDE %1
+	align 4, db 0
+%%val:
+	WIDE %2
+	%%VALLEN equ $ - %%val
+	align 4, db 0
+%%SLEN equ $ - %%string
+%endmacro
+
+
+struc RUNTIME_FUNCTION
+    .FunctionStart resd 1
+    .FunctionEnd   resd 1
+    .UnwindInfo    resd 1
+endstruc
+
+struc UNWIND_INFO
+    .Ver3_Flags     resb 1 ; versions and flags
+    .PrologSize     resb 1
+    .CntUnwindCodes resb 1
+    .FrReg_FrRegOff resb 1 ; frame register and offsets
+    ; dd ExceptionHandler or FunctionEntry
+    ; ExceptionData
+endstruc
+
+struc UNWIND_CODE
+    .PrologOff     resb 1
+    .OpCode_OpInfo resb 1 ; operation code and info
+endstruc
+
+UNW_FLAG_EHANDLER equ 1
+
+struc IMAGE_DEBUG_DIRECTORY
+    .Characteristics  resd 1
+    .TimeDateStamp    resd 1
+    .MajorVersion     resw 1
+    .MinorVersion     resw 1
+    .Type             resd 1
+    .SizeOfData       resd 1
+    .AddressOfRawData resd 1
+    .PointerToRawData resd 1
+endstruc
+
+IMAGE_DEBUG_TYPE_COFF equ 1
+IMAGE_DEBUG_TYPE_CODEVIEW equ 2
+IMAGE_DEBUG_TYPE_MISC equ 4
+
+SYMOPT_DEBUG equ 080000000h
+
+struc IMAGE_EXPORT_DIRECTORY
+    .Characteristics       resd 1
+    .TimeDateStamp         resd 1
+    .MajorVersion          resw 1
+    .MinorVersion          resw 1
+    .nName                 resd 1
+    .nBase                 resd 1
+    .NumberOfFunctions     resd 1
+    .NumberOfNames         resd 1
+    .AddressOfFunctions    resd 1
+    .AddressOfNames        resd 1
+    .AddressOfNameOrdinals resd 1
+endstruc
+
+struc IMAGE_IMPORT_DESCRIPTOR
+    .OriginalFirstThunk resd 1 ; Characteristics
+    .TimeDateStamp      resd 1
+    .ForwarderChain     resd 1
+    .Name1              resd 1
+    .FirstThunk         resd 1
+endstruc
+
+%macro _import_descriptor 1
+istruc IMAGE_IMPORT_DESCRIPTOR
+    at IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk, dd %1_hintnames - IMAGEBASE
+    at IMAGE_IMPORT_DESCRIPTOR.Name1             , dd %1 - IMAGEBASE
+    at IMAGE_IMPORT_DESCRIPTOR.FirstThunk        , dd %1_iat - IMAGEBASE
+iend
+%endmacro
+
+struc IMAGE_LOAD_CONFIG_DIRECTORY32
+    .Size                           resd 1
+    .TimeDateStamp                  resd 1
+    .MajorVersion                   resw 1
+    .MinorVersion                   resw 1
+    .GlobalFlagsClear               resd 1
+    .GlobalFlagsSet                 resd 1
+    .CriticalSectionDefaultTimeout  resd 1
+    .DeCommitFreeBlockThreshold     resd 1
+    .DeCommitTotalFreeThreshold     resd 1
+    .LockPrefixTable                resd 1 ; VA
+    .MaximumAllocationSize          resd 1
+    .VirtualMemoryThreshold         resd 1
+    .ProcessHeapFlags               resd 1
+    .ProcessAffinityMask            resd 1
+    .CSDVersion                     resw 1
+    .Reserved1                      resw 1
+    .EditList                       resd 1 ; VA
+    .SecurityCookie                 resd 1 ; VA
+    .SEHandlerTable                 resd 1 ; VA
+    .SEHandlerCount                 resd 1
+    .GuardCFCheckFunctionPointer    resd 1 ; VA
+    .Reserved2                      resd 1
+    .GuardCFFunctionTable           resd 1 ; VA
+    .GuardCFFunctionCount           resd 1
+    .GuardFlags                     resd 1
+endstruc
+
+struc IMAGE_LOAD_CONFIG_DIRECTORY64
+    .Size                           resd 1
+    .TimeDateStamp                  resd 1
+    .MajorVersion                   resw 1
+    .MinorVersion                   resw 1
+    .GlobalFlagsClear               resd 1
+    .GlobalFlagsSet                 resd 1
+    .CriticalSectionDefaultTimeout  resd 1
+    .DeCommitFreeBlockThreshold     resq 1
+    .DeCommitTotalFreeThreshold     resq 1
+    .LockPrefixTable                resq 1 ; VA
+    .MaximumAllocationSize          resq 1
+    .VirtualMemoryThreshold         resq 1
+    .ProcessAffinityMask            resq 1
+    .ProcessHeapFlags               resd 1
+    .CSDVersion                     resw 1
+    .Reserved1                      resw 1
+    .EditList                       resq 1 ; VA
+    .SecurityCookie                 resq 1 ; VA
+    .SEHandlerTable                 resq 1 ; VA
+    .SEHandlerCount                 resq 1
+    .GuardCFCheckFunctionPointer    resq 1 ; VA
+    .Reserved2                      resq 1
+    .GuardCFFunctionTable           resq 1 ; VA
+    .GuardCFFunctionCount           resq 1
+    .GuardFlags                     resd 1
+endstruc
+
+RT_ICON       equ  3
+RT_STRING     equ  6
+RT_GROUP_ICON equ 14
+RT_VERSION    equ 16
+RT_MANIFEST   equ 24
+
+struc GRPICONDIR
+    .idReserved resw 1 ; always 0 - enforced
+    .idType     resw 1 ; always 1 for icons
+    .idCount    resw 1
+endstruc
+
+struc GRPICONDIRENTRY
+    .bWidth       resb 1
+    .bHeight      resb 1
+    .bColorCount  resb 1
+    .bReserved    resb 1
+    .wPlanes      resw 1
+    .wBitCount    resw 1
+    .dwBytesInRes resd 1
+    .nId          resw 1
+endstruc
+
+%macro _resourceDirectoryEntry 2
+istruc IMAGE_RESOURCE_DIRECTORY_ENTRY
+    at IMAGE_RESOURCE_DIRECTORY_ENTRY.NameID, dd %1
+    at IMAGE_RESOURCE_DIRECTORY_ENTRY.OffsetToData, dd IMAGE_RESOURCE_DATA_IS_DIRECTORY | (%2 - Directory_Entry_Resource)
+iend
+%endmacro
+
+%macro _resource_tree 3 ; ID, Offset, Size
+istruc IMAGE_RESOURCE_DIRECTORY
+    at IMAGE_RESOURCE_DIRECTORY.NumberOfIdEntries, dw 1
+iend
+istruc IMAGE_RESOURCE_DIRECTORY_ENTRY
+    at IMAGE_RESOURCE_DIRECTORY_ENTRY.NameID, dd %1
+    at IMAGE_RESOURCE_DIRECTORY_ENTRY.OffsetToData, dd IMAGE_RESOURCE_DATA_IS_DIRECTORY | (%%language - Directory_Entry_Resource)
+iend
+
+%%language:
+istruc IMAGE_RESOURCE_DIRECTORY
+    at IMAGE_RESOURCE_DIRECTORY.NumberOfIdEntries, dw 1
+iend
+istruc IMAGE_RESOURCE_DIRECTORY_ENTRY
+    ; language doesn't matter
+    at IMAGE_RESOURCE_DIRECTORY_ENTRY.OffsetToData, dd %%entry - Directory_Entry_Resource
+iend
+
+%%entry:
+istruc IMAGE_RESOURCE_DATA_ENTRY
+    at IMAGE_RESOURCE_DATA_ENTRY.OffsetToData, dd %2 - IMAGEBASE
+    at IMAGE_RESOURCE_DATA_ENTRY.Size1, dd %3
+iend
+%endmacro
+
+RichKey EQU 092033d19h
+
+struc IMAGE_TLS_DIRECTORY32
+    .StartAddressOfRawData resd 1
+    .EndAddressOfRawData   resd 1
+    .AddressOfIndex        resd 1
+    .AddressOfCallBacks    resd 1
+    .SizeOfZeroFill        resd 1
+    .Characteristics       resd 1
+endstruc
+
+struc IMAGE_TLS_DIRECTORY64
+    .StartAddressOfRawData resq 1
+    .EndAddressOfRawData   resq 1
+    .AddressOfIndex        resq 1
+    .AddressOfCallBacks    resq 1
+    .SizeOfZeroFill        resd 1
+    .Characteristics       resd 1
+endstruc
+
+struc IMAGE_BOUND_IMPORT_DESCRIPTOR
+    .TimeDateStamp                resd 1
+    .OffsetModuleName             resw 1
+    .NumberOfModulesForwarderRefs resw 1
+endstruc
+
+struc WIN_CERTIFICATE
+    .dwLength         resd 1
+    .wRevision        resw 1
+    .wCertificateType resw 1
+    .bCertificate     resb 0
+endstruc
+
+struc IMAGE_BASE_RELOCATION
+    .VirtualAddress resd 1
+    .SizeOfBlock    resd 1
+endstruc
+
+; can't make a struct of that one with Yasm :(
+%macro _IMAGE_IMPORT_BY_NAME 1
+    .Hint   dw 0
+    .Name   db %1, 0
+%endmacro
+
+IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE    equ 0040h
+IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY equ 0080h
+IMAGE_DLLCHARACTERISTICS_NX_COMPAT       equ 0100h
+IMAGE_DLLCHARACTERISTICS_NO_SEH          equ 0400h
+IMAGE_DLLCHARACTERISTICS_APPCONTAINER    equ 1000h ; W8
+IMAGE_DLLCHARACTERISTICS_GUARD_CF        equ 4000h ; W8.1
+
+FLG_SHOW_LDR_SNAPS equ 2
+
+MB_OK           equ 00000000h
+MB_ICONASTERISK equ 00000040h
+MB_APPLMODAL    equ 00000000h
+
+LOAD_LIBRARY_AS_DATAFILE equ 000000002h
+
+IMAGE_GUARD_CF_INSTRUMENTED           equ 000000100h ;Module performs control flow integrity checks using system-supplied support
+IMAGE_GUARD_CFW_INSTRUMENTED          equ 000000200h ;Module performs control flow and write integrity checks
+IMAGE_GUARD_CF_FUNCTION_TABLE_PRESENT equ 000000400h ;Module contains valid control flow target metadata
+IMAGE_GUARD_SECURITY_COOKIE_UNUSED    equ 000000800h ;Module does not make use of the /GS security cookie
+
+COOKIE_DEFAULT equ 0bb40e64eh
diff --git a/src/native/tinype-corkami/make.bat b/src/native/tinype-corkami/make.bat
new file mode 100755
index 0000000..7a231ec
--- /dev/null
+++ b/src/native/tinype-corkami/make.bat
@@ -0,0 +1,13 @@
+REM
+REM Using yasm 1.2.0 win64 or win32
+REM    http://yasm.tortall.net/
+REM
+REM TinyPE XP-W8 Compatible - x86 32bit and 64bit - 268 bytes
+REM    https://code.google.com/p/corkami/wiki/PE
+REM    https://code.google.com/p/corkami/source/browse/trunk/src/PE/tiny.asm
+REM
+REM See also:
+REM    http://www.phreedom.org/research/tinype/
+REM
+c:\yasm\yasm.exe -f bin -o tiny-simple.exe tiny-simple.asm
+REM c:\yasm\yasm.exe -f bin -o tiny.exe tiny.asm
diff --git a/src/native/tinype-corkami/readme.txt b/src/native/tinype-corkami/readme.txt
new file mode 100644
index 0000000..1ca48c7
--- /dev/null
+++ b/src/native/tinype-corkami/readme.txt
@@ -0,0 +1,25 @@
+TinyPE XP-W8 Compatible - x86 32bit and 64bit - 268 bytes
+
+https://code.google.com/p/corkami/wiki/PE
+https://code.google.com/p/corkami/source/browse/trunk/src/PE/tiny.asm
+
+by Ange Albertini, BSD Licence, 2010-2013
+
+tiny-simple.asm (diff to tiny.asm):
+  - remove printf, and msvcrt.dll import
+  - just return 0
+
++++
+
+See also:
+
+Tiny PE
+http://www.phreedom.org/research/tinype/
+by Alexander Sotirov
+
++++
+
+Compiled w/ yasm 1.2.0 for win64 or win32.
+http://yasm.tortall.net/
+
++++
diff --git a/src/native/tinype-corkami/tiny-simple.asm b/src/native/tinype-corkami/tiny-simple.asm
new file mode 100644
index 0000000..53677f1
--- /dev/null
+++ b/src/native/tinype-corkami/tiny-simple.asm
@@ -0,0 +1,102 @@
+; a 268-byte PE (as small as possible), XP-W8x64 compatible
+
+; similar with the w7 x64 PE, but larger sizeofimage and IAT required. XP compat also requires Debug Size and TLS VA to be null
+; a few extra tricks required for Windows 8 compatibility
+
+;Ange Albertini, BSD Licence, 2010-2013
+
+%include 'consts.inc'
+
+IMAGEBASE equ 400000h
+
+org IMAGEBASE
+
+DOS_HEADER:
+.e_magic dw 'MZ'
+
+align 4, db 0
+
+istruc IMAGE_NT_HEADERS
+    at IMAGE_NT_HEADERS.Signature, db 'PE',0,0
+iend
+istruc IMAGE_FILE_HEADER
+    at IMAGE_FILE_HEADER.Machine,               dw IMAGE_FILE_MACHINE_I386
+    at IMAGE_FILE_HEADER.TimeDateStamp
+    at IMAGE_FILE_HEADER.Characteristics,       dw IMAGE_FILE_EXECUTABLE_IMAGE ; | IMAGE_FILE_32BIT_MACHINE
+
+iend
+
+istruc IMAGE_OPTIONAL_HEADER32
+        at IMAGE_OPTIONAL_HEADER32.Magic,                     dw IMAGE_NT_OPTIONAL_HDR32_MAGIC
+bits 32
+
+realEntryPoint:
+    push byte 0
+    pop eax
+    ret
+        at IMAGE_OPTIONAL_HEADER32.AddressOfEntryPoint,       dd EntryPoint - IMAGEBASE
+        at IMAGE_OPTIONAL_HEADER32.BaseOfCode, dd 0 ; must be valid for W7
+        at IMAGE_OPTIONAL_HEADER32.ImageBase,        dd IMAGEBASE
+        at IMAGE_OPTIONAL_HEADER32.SectionAlignment, dd 4      ; also sets e_lfanew
+        at IMAGE_OPTIONAL_HEADER32.FileAlignment,    dd 4
+
+ImportsAddressTable:
+    dd 0
+IMPORTSADDRESSTABLESIZE equ $ - ImportsAddressTable
+
+        at IMAGE_OPTIONAL_HEADER32.MajorSubsystemVersion, dw 4
+        at IMAGE_OPTIONAL_HEADER32.SizeOfImage,           dd SIZEOFIMAGE
+        at IMAGE_OPTIONAL_HEADER32.SizeOfHeaders,         dd SIZEOFIMAGE - 5 ; W8 enforce SizeOfHeaders <= EntryPoint
+        at IMAGE_OPTIONAL_HEADER32.Subsystem,             db IMAGE_SUBSYSTEM_WINDOWS_CUI
+
+db 0 ; one byte delta to avoid setting DllCharacteristics to AppContainer
+
+        at IMAGE_OPTIONAL_HEADER32.NumberOfRvaAndSizes, dd 13
+iend
+
+istruc IMAGE_DATA_DIRECTORY_13
+
+    at IMAGE_DATA_DIRECTORY_13.ImportsVA,     dd Import_Descriptor - IMAGEBASE
+
+Import_Descriptor:
+istruc IMAGE_IMPORT_DESCRIPTOR
+iend
+        at IMAGE_DATA_DIRECTORY_13.DebugSize, dd 0 ; required for safety under XP
+
+        at IMAGE_DATA_DIRECTORY_13.TLSVA,     dd 0 ; required for safety under XP
+
+        at IMAGE_DATA_DIRECTORY_13.IATVA,     dd ImportsAddressTable - IMAGEBASE ; required under XP
+        at IMAGE_DATA_DIRECTORY_13.IATSize,   dd IMPORTSADDRESSTABLESIZE    ; required under XP
+iend
+
+message db "JogAmp Windows TinyPE Universal", 0ah, 0
+
+times 268 - 266 db 0
+EntryPoint:
+    jmp realEntryPoint
+
+SIZEOFIMAGE equ 268
+
+struc IMAGE_DATA_DIRECTORY_13
+    .ExportsVA        resd 1
+    .ExportsSize      resd 1
+    .ImportsVA        resd 1
+    .ImportsSize      resd 1
+    .ResourceVA       resd 1
+    .ResourceSize     resd 1
+    .Exception        resd 2
+    .Security         resd 2
+    .FixupsVA         resd 1
+    .FixupsSize       resd 1
+    .DebugVA          resd 1
+    .DebugSize        resd 1
+    .Description      resd 2
+    .MIPS             resd 2
+    .TLSVA            resd 1
+    .TLSSize          resd 1
+    .Load             resd 2
+    .BoundImportsVA   resd 1
+    .BoundImportsSize resd 1
+    .IATVA            resd 1
+    .IATSize          resd 1
+endstruc
diff --git a/src/native/tinype-corkami/tiny.asm b/src/native/tinype-corkami/tiny.asm
new file mode 100644
index 0000000..abbb945
--- /dev/null
+++ b/src/native/tinype-corkami/tiny.asm
@@ -0,0 +1,117 @@
+; a 268-byte PE (as small as possible), XP-W8x64 compatible
+
+; similar with the w7 x64 PE, but larger sizeofimage and IAT required. XP compat also requires Debug Size and TLS VA to be null
+; a few extra tricks required for Windows 8 compatibility
+
+;Ange Albertini, BSD Licence, 2010-2013
+
+%include 'consts.inc'
+
+IMAGEBASE equ 400000h
+
+org IMAGEBASE
+
+DOS_HEADER:
+.e_magic dw 'MZ'
+
+align 4, db 0
+
+istruc IMAGE_NT_HEADERS
+    at IMAGE_NT_HEADERS.Signature, db 'PE',0,0
+iend
+istruc IMAGE_FILE_HEADER
+    at IMAGE_FILE_HEADER.Machine,               dw IMAGE_FILE_MACHINE_I386
+    at IMAGE_FILE_HEADER.TimeDateStamp
+msvcrt db 'msvcrt.dll', 0 ; keeping the extension in case it'd work under W2K
+    at IMAGE_FILE_HEADER.Characteristics,       dw IMAGE_FILE_EXECUTABLE_IMAGE ; | IMAGE_FILE_32BIT_MACHINE
+
+iend
+
+istruc IMAGE_OPTIONAL_HEADER32
+        at IMAGE_OPTIONAL_HEADER32.Magic,                     dw IMAGE_NT_OPTIONAL_HDR32_MAGIC
+bits 32
+
+realEntryPoint:
+    push message
+    call [__imp__printf]
+    jmp _2
+        at IMAGE_OPTIONAL_HEADER32.AddressOfEntryPoint,       dd EntryPoint - IMAGEBASE
+        at IMAGE_OPTIONAL_HEADER32.BaseOfCode, dd 0 ; must be valid for W7
+_2:
+    add esp, 1 * 4
+    retn
+        at IMAGE_OPTIONAL_HEADER32.ImageBase,        dd IMAGEBASE
+        at IMAGE_OPTIONAL_HEADER32.SectionAlignment, dd 4      ; also sets e_lfanew
+        at IMAGE_OPTIONAL_HEADER32.FileAlignment,    dd 4
+
+ImportsAddressTable:
+msvcrt_iat:
+__imp__printf:
+    dd hnprintf - IMAGEBASE
+    dd 0
+IMPORTSADDRESSTABLESIZE equ $ - ImportsAddressTable
+
+        at IMAGE_OPTIONAL_HEADER32.MajorSubsystemVersion, dw 4
+        at IMAGE_OPTIONAL_HEADER32.SizeOfImage,           dd SIZEOFIMAGE
+        at IMAGE_OPTIONAL_HEADER32.SizeOfHeaders,         dd SIZEOFIMAGE - 5 ; W8 enforce SizeOfHeaders <= EntryPoint
+        at IMAGE_OPTIONAL_HEADER32.Subsystem,             db IMAGE_SUBSYSTEM_WINDOWS_CUI
+
+db 0 ; one byte delta to avoid setting DllCharacteristics to AppContainer
+
+hnprintf:
+    dw 0
+    db 'printf', 0
+
+        at IMAGE_OPTIONAL_HEADER32.NumberOfRvaAndSizes, dd 13
+iend
+
+istruc IMAGE_DATA_DIRECTORY_13
+
+    at IMAGE_DATA_DIRECTORY_13.ImportsVA,     dd Import_Descriptor - IMAGEBASE
+
+Import_Descriptor:
+istruc IMAGE_IMPORT_DESCRIPTOR
+    at IMAGE_IMPORT_DESCRIPTOR.Name1     , dd msvcrt - IMAGEBASE
+    at IMAGE_IMPORT_DESCRIPTOR.FirstThunk, dd msvcrt_iat - IMAGEBASE
+iend
+istruc IMAGE_IMPORT_DESCRIPTOR
+iend
+        at IMAGE_DATA_DIRECTORY_13.DebugSize, dd 0 ; required for safety under XP
+
+        at IMAGE_DATA_DIRECTORY_13.TLSVA,     dd 0 ; required for safety under XP
+
+        at IMAGE_DATA_DIRECTORY_13.IATVA,     dd ImportsAddressTable - IMAGEBASE ; required under XP
+        at IMAGE_DATA_DIRECTORY_13.IATSize,   dd IMPORTSADDRESSTABLESIZE    ; required under XP
+iend
+
+message db " * 268b universal tiny PE", 0ah, 0
+
+times 268 - 260 db 0
+EntryPoint:
+    jmp realEntryPoint
+
+SIZEOFIMAGE equ 268
+
+struc IMAGE_DATA_DIRECTORY_13
+    .ExportsVA        resd 1
+    .ExportsSize      resd 1
+    .ImportsVA        resd 1
+    .ImportsSize      resd 1
+    .ResourceVA       resd 1
+    .ResourceSize     resd 1
+    .Exception        resd 2
+    .Security         resd 2
+    .FixupsVA         resd 1
+    .FixupsSize       resd 1
+    .DebugVA          resd 1
+    .DebugSize        resd 1
+    .Description      resd 2
+    .MIPS             resd 2
+    .TLSVA            resd 1
+    .TLSSize          resd 1
+    .Load             resd 2
+    .BoundImportsVA   resd 1
+    .BoundImportsSize resd 1
+    .IATVA            resd 1
+    .IATSize          resd 1
+endstruc
\ No newline at end of file
diff --git a/src/native/unix/UnixDynamicLinkerImpl_JNI.c b/src/native/unix/UnixDynamicLinkerImpl_JNI.c
index c23c9ef..d818b3e 100644
--- a/src/native/unix/UnixDynamicLinkerImpl_JNI.c
+++ b/src/native/unix/UnixDynamicLinkerImpl_JNI.c
@@ -13,49 +13,63 @@
     #define RTLD_DEFAULT   ((void *) 0)
 #endif
 
-/*   Java->C glue code:
- *   Java package: jogamp.common.os.UnixDynamicLinkerImpl
- *    Java method: int dlclose(long arg0)
- *     C function: int dlclose(void * );
+// #define DEBUG_DLOPEN 1
+
+#ifdef DEBUG_DLOPEN
+    typedef void *(*DLOPEN_FPTR_TYPE)(const char *filename, int flag); 
+    #define VERBOSE_ON 1
+#endif
+
+// #define VERBOSE_ON 1
+
+#ifdef VERBOSE_ON
+    #ifdef ANDROID
+        #include <android/log.h>
+        #define  DBG_PRINT(...)  __android_log_print(ANDROID_LOG_DEBUG, "JogAmp", __VA_ARGS__)
+    #else
+        #define  DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr)
+    #endif
+#else
+        #define  DBG_PRINT(...)
+#endif
+
+/*
+ * Class:     jogamp_common_os_UnixDynamicLinkerImpl
+ * Method:    dlclose
+ * Signature: (J)I
  */
 JNIEXPORT jint JNICALL 
-Java_jogamp_common_os_UnixDynamicLinkerImpl_dlclose__J(JNIEnv *env, jclass _unused, jlong arg0) {
+Java_jogamp_common_os_UnixDynamicLinkerImpl_dlclose(JNIEnv *env, jclass _unused, jlong arg0) {
   int _res;
   _res = dlclose((void *) (intptr_t) arg0);
   return _res;
 }
 
 
-/*   Java->C glue code:
- *   Java package: jogamp.common.os.UnixDynamicLinkerImpl
- *    Java method: java.lang.String dlerror()
- *     C function: char *  dlerror(void);
+/*
+ * Class:     jogamp_common_os_UnixDynamicLinkerImpl
+ * Method:    dlerror
+ * Signature: ()Ljava/lang/String;
  */
 JNIEXPORT jstring JNICALL 
-Java_jogamp_common_os_UnixDynamicLinkerImpl_dlerror__(JNIEnv *env, jclass _unused) {
+Java_jogamp_common_os_UnixDynamicLinkerImpl_dlerror(JNIEnv *env, jclass _unused) {
   char *  _res;
   _res = dlerror();
   if (_res == NULL) return NULL;  return (*env)->NewStringUTF(env, _res);
 }
 
-// #define DEBUG_DLOPEN 1
-
-#ifdef DEBUG_DLOPEN
-    typedef void *(*DLOPEN_FPTR_TYPE)(const char *filename, int flag); 
-#endif
-
-/*   Java->C glue code:
- *   Java package: jogamp.common.os.UnixDynamicLinkerImpl
- *    Java method: long dlopen(java.lang.String arg0, int arg1)
- *     C function: void *  dlopen(const char * , int);
+/*
+ * Class:     jogamp_common_os_UnixDynamicLinkerImpl
+ * Method:    dlopen
+ * Signature: (Ljava/lang/String;I)J
  */
 JNIEXPORT jlong JNICALL 
-Java_jogamp_common_os_UnixDynamicLinkerImpl_dlopen__Ljava_lang_String_2I(JNIEnv *env, jclass _unused, jstring arg0, jint arg1) {
+Java_jogamp_common_os_UnixDynamicLinkerImpl_dlopen(JNIEnv *env, jclass _unused, jstring arg0, jint arg1) {
   const char* _UTF8arg0 = NULL;
   void *  _res;
 #ifdef DEBUG_DLOPEN
   DLOPEN_FPTR_TYPE dlopenFunc = NULL;
-  fprintf(stderr, "XXX dlopen.0\n");
+  DBG_PRINT("XXX dlopen.0\n");
 #endif
 
   if (arg0 != NULL) {
@@ -70,9 +84,9 @@ Java_jogamp_common_os_UnixDynamicLinkerImpl_dlopen__Ljava_lang_String_2I(JNIEnv
   }
 #ifdef DEBUG_DLOPEN
   dlopenFunc = (DLOPEN_FPTR_TYPE) dlsym(RTLD_DEFAULT, "dlopen");
-  fprintf(stderr, "XXX dlopen.1: lib %s, dlopen-fptr %p %p (%d)\n", _UTF8arg0, dlopen, dlopenFunc, dlopen==dlopenFunc); fflush(stderr);
+  DBG_PRINT("XXX dlopen.1: lib %s, dlopen-fptr %p %p (%d)\n", _UTF8arg0, dlopen, dlopenFunc, dlopen==dlopenFunc);
   _res = dlopen((char *) _UTF8arg0, (int) arg1);
-  fprintf(stderr, "XXX dlopen.2: %p\n", _res); fflush(stderr);
+  DBG_PRINT("XXX dlopen.2: %p\n", _res);
 #else
   _res = dlopen((char *) _UTF8arg0, (int) arg1);
 #endif
@@ -80,19 +94,18 @@ Java_jogamp_common_os_UnixDynamicLinkerImpl_dlopen__Ljava_lang_String_2I(JNIEnv
     (*env)->ReleaseStringUTFChars(env, arg0, _UTF8arg0);
   }
 #ifdef DEBUG_DLOPEN
-  fprintf(stderr, "XXX dlopen.X\n"); fflush(stderr);
+  DBG_PRINT("XXX dlopen.X\n");
 #endif
   return (jlong) (intptr_t) _res;
 }
 
-
-/*   Java->C glue code:
- *   Java package: jogamp.common.os.UnixDynamicLinkerImpl
- *    Java method: long dlsym(long arg0, java.lang.String arg1)
- *     C function: void *  dlsym(void * , const char * );
+/*
+ * Class:     jogamp_common_os_UnixDynamicLinkerImpl
+ * Method:    dlsym
+ * Signature: (JLjava/lang/String;)J
  */
 JNIEXPORT jlong JNICALL 
-Java_jogamp_common_os_UnixDynamicLinkerImpl_dlsym__JLjava_lang_String_2(JNIEnv *env, jclass _unused, jlong arg0, jstring arg1) {
+Java_jogamp_common_os_UnixDynamicLinkerImpl_dlsym(JNIEnv *env, jclass _unused, jlong arg0, jstring arg1) {
   const char* _UTF8arg1 = NULL;
   void *  _res;
   if (arg1 != NULL) {
@@ -106,10 +119,11 @@ Java_jogamp_common_os_UnixDynamicLinkerImpl_dlsym__JLjava_lang_String_2(JNIEnv *
     }
   }
   _res = dlsym((void *) (intptr_t) arg0, (char *) _UTF8arg1);
+  DBG_PRINT("XXX dlsym: handle %p, symbol %s -> %p\n", (void *) (intptr_t) arg0, _UTF8arg1, _res);
+
   if (arg1 != NULL) {
     (*env)->ReleaseStringUTFChars(env, arg1, _UTF8arg1);
   }
   return (jlong) (intptr_t) _res;
 }
 
-
diff --git a/src/native/windows/WindowsDynamicLinkerImpl_JNI.c b/src/native/windows/WindowsDynamicLinkerImpl_JNI.c
index 9ddb9d0..ef94bb0 100644
--- a/src/native/windows/WindowsDynamicLinkerImpl_JNI.c
+++ b/src/native/windows/WindowsDynamicLinkerImpl_JNI.c
@@ -24,7 +24,7 @@
  *     C function: BOOL FreeLibrary(HANDLE hLibModule);
  */
 JNIEXPORT jint JNICALL 
-Java_jogamp_common_os_WindowsDynamicLinkerImpl_FreeLibrary__J(JNIEnv *env, jclass _unused, jlong hLibModule) {
+Java_jogamp_common_os_WindowsDynamicLinkerImpl_FreeLibrary(JNIEnv *env, jclass _unused, jlong hLibModule) {
   BOOL _res;
   _res = FreeLibrary((HANDLE) (intptr_t) hLibModule);
   return _res;
@@ -37,7 +37,7 @@ Java_jogamp_common_os_WindowsDynamicLinkerImpl_FreeLibrary__J(JNIEnv *env, jclas
  *     C function: DWORD GetLastError(void);
  */
 JNIEXPORT jint JNICALL 
-Java_jogamp_common_os_WindowsDynamicLinkerImpl_GetLastError__(JNIEnv *env, jclass _unused) {
+Java_jogamp_common_os_WindowsDynamicLinkerImpl_GetLastError(JNIEnv *env, jclass _unused) {
   DWORD _res;
   _res = GetLastError();
   return _res;
@@ -50,7 +50,7 @@ Java_jogamp_common_os_WindowsDynamicLinkerImpl_GetLastError__(JNIEnv *env, jclas
  *     C function: PROC GetProcAddressA(HANDLE hModule, LPCSTR lpProcName);
  */
 JNIEXPORT jlong JNICALL 
-Java_jogamp_common_os_WindowsDynamicLinkerImpl_GetProcAddressA__JLjava_lang_String_2(JNIEnv *env, jclass _unused, jlong hModule, jstring lpProcName) {
+Java_jogamp_common_os_WindowsDynamicLinkerImpl_GetProcAddressA(JNIEnv *env, jclass _unused, jlong hModule, jstring lpProcName) {
   const char* _strchars_lpProcName = NULL;
   PROC _res;
   if (lpProcName != NULL) {
@@ -75,7 +75,7 @@ Java_jogamp_common_os_WindowsDynamicLinkerImpl_GetProcAddressA__JLjava_lang_Stri
  *     C function: HANDLE LoadLibraryW(LPCWSTR lpLibFileName);
  */
 JNIEXPORT jlong JNICALL 
-Java_jogamp_common_os_WindowsDynamicLinkerImpl_LoadLibraryW__Ljava_lang_String_2(JNIEnv *env, jclass _unused, jstring lpLibFileName) {
+Java_jogamp_common_os_WindowsDynamicLinkerImpl_LoadLibraryW(JNIEnv *env, jclass _unused, jstring lpLibFileName) {
   jchar* _strchars_lpLibFileName = NULL;
   HANDLE _res;
   if (lpLibFileName != NULL) {

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/gluegen2.git



More information about the pkg-java-commits mailing list