[med-svn] [libsis-base-java] 01/05: Imported Upstream version 14.12.0

Olivier Sallou osallou at debian.org
Fri Aug 21 14:26:32 UTC 2015


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

osallou pushed a commit to branch master
in repository libsis-base-java.

commit b9ca42fce35e1577723f0ff50dcd49159424655f
Author: Olivier Sallou <osallou at debian.org>
Date:   Fri Aug 21 14:06:37 2015 +0000

    Imported Upstream version 14.12.0
---
 .classpath                                         |   13 +
 branch.sh                                          |   35 +
 build.gradle                                       |   98 ++
 dist/COPYING                                       |   15 +
 dist/COPYING_HDF                                   |   88 ++
 dist/LICENSE                                       |  203 ++++
 doc/tagged_array_def.txt                           |   43 +
 gradle/wrapper/gradle-wrapper.jar                  |  Bin 0 -> 50514 bytes
 gradle/wrapper/gradle-wrapper.properties           |    6 +
 gradlew                                            |  164 +++
 gradlew.bat                                        |   90 ++
 resource/dependency-structure.ddf                  |    6 +
 settings.gradle                                    |    1 +
 source/c/COPYING                                   |   88 ++
 source/c/compile_linux_amd64.sh                    |    6 +
 source/c/compile_linux_arm.sh                      |    6 +
 source/c/compile_linux_i386.sh                     |    6 +
 source/c/compile_macosx_i386.sh                    |    6 +
 source/c/compile_macosx_x86_64.sh                  |    6 +
 source/c/compile_solaris_amd64.sh                  |    6 +
 source/c/compile_solaris_sparc.sh                  |    6 +
 source/c/compile_solaris_sparcv9.sh                |    6 +
 source/c/compile_solaris_x86.sh                    |    6 +
 source/c/compile_windows_i386.mak                  |  181 ++++
 source/c/compile_windows_x64.mak                   |  182 ++++
 source/c/copyByteChar.c                            |   42 +
 source/c/copyByteDouble.c                          |   42 +
 source/c/copyByteFloat.c                           |   42 +
 source/c/copyByteInt.c                             |   42 +
 source/c/copyByteLong.c                            |   42 +
 source/c/copyByteShort.c                           |   42 +
 source/c/copyByteTarget.ctempl                     |  241 +++++
 source/c/copyCommon.c                              |  268 +++++
 source/c/unix.c                                    |  446 ++++++++
 .../cisd/base/BuildAndEnvironmentInfo.java         |   46 +
 .../systemsx/cisd/base/annotation/JsonObject.java  |   43 +
 .../cisd/base/convert/NativeArrayEncoding.java     |  184 ++++
 .../ch/systemsx/cisd/base/convert/NativeData.java  | 1086 ++++++++++++++++++++
 .../cisd/base/convert/NativeTaggedArray.java       |  672 ++++++++++++
 .../base/exceptions/CheckedExceptionTunnel.java    |  285 +++++
 .../cisd/base/exceptions/IErrorStrategy.java       |   56 +
 .../cisd/base/exceptions/IOExceptionUnchecked.java |   81 ++
 .../exceptions/InterruptedExceptionUnchecked.java  |   61 ++
 .../cisd/base/exceptions/StopException.java        |   29 +
 .../base/exceptions/TimeoutExceptionUnchecked.java |   52 +
 .../ch/systemsx/cisd/base/exceptions/package.html  |   13 +
 .../cisd/base/image/IImageTransformer.java         |   35 +
 .../cisd/base/image/IImageTransformerFactory.java  |   36 +
 .../base/image/IStreamingImageTransformer.java     |   53 +
 .../image/IStreamingImageTransformerFactory.java   |   36 +
 .../base/io/AdapterIInputStreamToInputStream.java  |  157 +++
 .../io/AdapterIOutputStreamToOutputStream.java     |  121 +++
 .../base/io/AdapterInputStreamToIInputStream.java  |  157 +++
 .../io/AdapterOutputStreamToIOutputStream.java     |  130 +++
 .../cisd/base/io/ByteBufferRandomAccessFile.java   |  455 ++++++++
 .../java/ch/systemsx/cisd/base/io/ICloseable.java  |   37 +
 .../ch/systemsx/cisd/base/io/IInputStream.java     |   74 ++
 .../ch/systemsx/cisd/base/io/IOutputStream.java    |   60 ++
 .../systemsx/cisd/base/io/IRandomAccessFile.java   |  278 +++++
 .../ch/systemsx/cisd/base/io/ISynchronizable.java  |   34 +
 .../cisd/base/io/RandomAccessFileImpl.java         |  648 ++++++++++++
 .../cisd/base/mdarray/MDAbstractArray.java         |  480 +++++++++
 .../ch/systemsx/cisd/base/mdarray/MDArray.java     |  352 +++++++
 .../ch/systemsx/cisd/base/mdarray/MDByteArray.java |  376 +++++++
 .../systemsx/cisd/base/mdarray/MDDoubleArray.java  |  376 +++++++
 .../systemsx/cisd/base/mdarray/MDFloatArray.java   |  376 +++++++
 .../ch/systemsx/cisd/base/mdarray/MDIntArray.java  |  376 +++++++
 .../ch/systemsx/cisd/base/mdarray/MDLongArray.java |  376 +++++++
 .../systemsx/cisd/base/mdarray/MDShortArray.java   |  376 +++++++
 .../ch/systemsx/cisd/base/mdarray/package.html     |   19 +
 .../base/namedthread/ICallableNameProvider.java    |   29 +
 .../base/namedthread/IRunnableNameProvider.java    |   28 +
 .../cisd/base/namedthread/NamedCallable.java       |   28 +
 .../cisd/base/namedthread/NamedFutureTask.java     |   72 ++
 .../cisd/base/namedthread/NamedRunnable.java       |   26 +
 .../cisd/base/namedthread/NamingThreadFactory.java |   88 ++
 .../base/namedthread/NamingThreadPoolExecutor.java |  329 ++++++
 .../cisd/base/namedthread/PoolNameThread.java      |   57 +
 .../ch/systemsx/cisd/base/namedthread/package.html |   14 +
 .../base/tests/AbstractFileSystemTestCase.java     |  145 +++
 .../java/ch/systemsx/cisd/base/tests/Retry10.java  |   50 +
 .../java/ch/systemsx/cisd/base/tests/Retry50.java  |   50 +
 .../ch/systemsx/cisd/base/unix/FileLinkType.java   |   37 +
 source/java/ch/systemsx/cisd/base/unix/Unix.java   |  901 ++++++++++++++++
 .../java/ch/systemsx/cisd/base/unix/package.html   |   12 +
 .../utilities/AbstractBuildAndEnvironmentInfo.java |  231 +++++
 .../base/utilities/NativeLibraryUtilities.java     |  154 +++
 .../systemsx/cisd/base/utilities/OSUtilities.java  |  257 +++++
 .../cisd/base/utilities/ResourceUtilities.java     |  101 ++
 .../ch/systemsx/cisd/base/utilities/package.html   |   12 +
 .../java/ch/systemsx/cisd/base/AllTests.java       |   59 ++
 .../cisd/base/convert/NativeDataTests.java         |  504 +++++++++
 .../cisd/base/convert/NativeTaggedArrayTests.java  |  470 +++++++++
 .../exceptions/CheckedExceptionTunnelTest.java     |   88 ++
 .../base/exceptions/IOExceptionUncheckedTests.java |  144 +++
 .../base/io/ByteBufferRandomAccessFileTests.java   |   94 ++
 .../cisd/base/io/IRandomAccessFileTests.java       |  196 ++++
 .../cisd/base/io/RandomAccessFileImplTests.java    |   97 ++
 .../systemsx/cisd/base/mdarray/MDArrayTests.java   |  332 ++++++
 .../namedthread/NamingThreadPoolExecutorTest.java  |  481 +++++++++
 .../java/ch/systemsx/cisd/base/unix/UnixTests.java |  351 +++++++
 sourceTest/java/tests.xml                          |   12 +
 tag.sh                                             |   24 +
 103 files changed, 15973 insertions(+)

diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..dbaf269
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="source/java"/>
+	<classpathentry kind="src" path="sourceTest/java"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="lib" path="/libraries/testng/testng-jdk15.jar" sourcepath="/libraries/testng/src.zip"/>
+	<classpathentry kind="lib" path="/libraries/restrictionchecker/restrictions.jar"/>
+	<classpathentry kind="lib" path="/libraries/commons-io/commons-io.jar" sourcepath="/libraries/commons-io/src.zip"/>
+	<classpathentry kind="lib" path="/libraries/commons-lang/commons-lang.jar" sourcepath="/libraries/commons-lang/src.zip"/>
+	<classpathentry kind="lib" path="/libraries/unix"/>
+	<classpathentry kind="lib" path="/libraries/nativedata"/>
+	<classpathentry kind="output" path="targets/classes"/>
+</classpath>
diff --git a/branch.sh b/branch.sh
new file mode 100755
index 0000000..57cf7ca
--- /dev/null
+++ b/branch.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+if [ `dirname $0` != "." ]
+then
+	echo "Please run from the same directory than the script source file is in"
+	exit 1
+fi
+
+if [ $# -ne 1 ]
+then
+  echo "Usage: ./branch.sh [branch]"
+  echo ""
+  echo "Example: ./branch.sh release/13.04.x"
+  exit 1
+fi
+
+svn info svn+ssh://svncisd.ethz.ch/repos/cisd/base/branches/$1 2>/dev/null
+if [ $? -eq 0 ]; then echo "Branch already exists!"; exit 1; fi
+
+CURRENT=`svn info|grep URL|cut -d" " -f2`
+
+svn copy $CURRENT svn+ssh://svncisd.ethz.ch/repos/cisd/base/branches/$1 -m "create branch $1"
+mkdir -p out
+rm -r out/temp_checkout
+svn checkout --depth=empty svn+ssh://svncisd.ethz.ch/repos/cisd/base/branches/$1 out/temp_checkout
+if [ $? -ne 0 ]; then echo "Checkout of new branch $1 failed!"; exit 1; fi
+
+cd out/temp_checkout
+svn update gradlew gradle build.gradle
+./gradlew dependencyReport
+cat out/reports/project/dependencies.txt|egrep ^.---|grep \>|sort|uniq|awk '{print $2 ":" $4}'|awk -F: '{print "s/" $1 ":" $2 ":" $3 "/" $1 ":" $2 ":" $4 "/g"}' > sed_commands
+sed -f sed_commands build.gradle > build.gradle.tmp
+mv build.gradle.tmp build.gradle
+svn commit build.gradle -m "fixed dependencies for branch $1"
+cd ../..
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..70bb26a
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,98 @@
+apply from: '../gradle/javaproject.gradle'
+
+group='sis'
+
+dependencies {
+    compile 'apache:commons-io:+',
+            'apache:commons-lang:+',
+            'testng:testng:+',
+            'rinn:restrictions:+'
+} 
+
+tasks.withType(Test) {
+    systemProperty "java.library.path", "libs/native/unix/amd64-Linux:libs/native/nativedata/amd64-Linux:libs/native/unix/x86_64-Mac OS X:libs/native/nativedata/x86_64-Mac OS X"
+}
+
+
+sourceSets {
+  test {
+    resources {
+      srcDir "libs"
+      include "**"
+    }
+  }
+}
+
+jar {
+    from fileTree("libs/")
+}
+
+task standaloneTestJar(type: Jar, dependsOn: [classes, testClasses]) {
+    archiveName "${project.group}-base-test.jar"
+    from files(sourceSets.main.output.classesDir)
+    from files(sourceSets.main.output.resourcesDir)
+    from files(sourceSets.test.output.classesDir)
+    from files("libs")
+ 
+    from {configurations.testRuntime.collect {zipTree(it)}}
+ 
+    manifest {
+        attributes 'Main-Class': 'ch.systemsx.cisd.base.AllTests'
+    }
+}
+
+task javadocZip(type: Zip, dependsOn: javadoc) {
+    archiveName "${project.group}-base-javadoc.zip"
+    from javadoc.destinationDir
+}
+
+task distributionZip(type: Zip, dependsOn: [jar, sourcesJar, javadocZip, standaloneTestJar]) {
+    baseName = "${project.group}-base"
+    from ('dist') {
+        into "${project.group}-base"
+    }
+
+    from ('doc') {
+        into "${project.group}-base/doc"
+    }
+
+    from (jar.archivePath) {
+        into "${project.group}-base/lib"
+        rename '(.*)', "${project.group}-base.jar"
+    }
+    
+    from (sourcesJar.archivePath) {
+        into "${project.group}-base/src"
+        rename '(.*)', "${project.group}-base-src.jar"
+    }
+    
+    from (standaloneTestJar.archivePath) {
+        into "${project.group}-base/lib"
+    }
+    
+    from (javadocZip.archivePath) {
+        into "${project.group}-base/doc"
+    }
+}
+
+build.dependsOn distributionZip
+
+publishing {
+    publications {
+        ivy(IvyPublication) {
+            module "${project.group}-base"
+            revision project.revisionForPublication
+            from components.java
+            artifact(sourcesJar) {
+                type = 'source'
+            }
+            descriptor {
+                withXml {
+                    for (org in ['testng', 'rinn']) {
+                      asNode().dependencies.dependency.find { it. at org == org }.replaceNode {}
+                    }
+                }
+            }
+        }
+  }
+}
\ No newline at end of file
diff --git a/dist/COPYING b/dist/COPYING
new file mode 100644
index 0000000..0bae472
--- /dev/null
+++ b/dist/COPYING
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2009 ETH Zuerich, CISD
+ *
+ * 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/dist/COPYING_HDF b/dist/COPYING_HDF
new file mode 100644
index 0000000..7ca6009
--- /dev/null
+++ b/dist/COPYING_HDF
@@ -0,0 +1,88 @@
+Copyright Notice and Statement for NCSA Hierarchical Data Format (HDF)
+Java Software Library and Utilities
+
+NCSA Hierarchical Data Format (HDF) Software Library and Utilities 
+Copyright 1988-2004, the Board of Trustees of the University of Illinois.
+Copyright 2007-2009, Center for Information Sciences and Databases, ETH Zurich, Switzerland.  
+All rights reserved.
+
+Contributors to the library: National Center for Supercomputing 
+Applications (NCSA) at the University of Illinois, Lawrence 
+Livermore Nationall Laboratory (LLNL), Sandia National Laboratories (SNL), 
+Los Alamos National Laboratory (LANL). Fortner Software, Unidata 
+Program Center (netCDF), The Independent JPEG Group (JPEG), 
+Jean-loup Gailly and Mark Adler (gzip), and Digital Equipment 
+Corporation (DEC). Macintosh support contributed by Gregory L. Guerin.
+Center for Information Sciences and Databases, ETH Zurich, Switzerland
+
+The package 'glguerin':
+Copyright 1998, 1999 by Gregory L. Guerin.
+Redistribute or reuse only as described below.
+These files are from the MacBinary Toolkit for Java:
+   <http://www.amug.org/~glguerin/sw/#macbinary>
+and are redistributed by NCSA with permission of the author.
+
+This work was supported in part by a Cooperative Agreement with 
+NASA under NASA grant NAG 5-2040 and NAG NCC5-599.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted for any purpose (including commercial purposes)
+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 materials provided with the distribution.
+
+3.  In addition, redistributions of modified forms of the source or binary
+    code must carry prominent notices stating that the original code was
+    changed and the date of the change.
+
+4.  All publications or advertising materials mentioning features or use of
+    this software must acknowledge that it was developed by the National
+    Center for Supercomputing Applications at the University of Illinois, and
+    credit the Contributors.
+
+5.  Neither the name of the University nor the names of the Contributors may
+    be used to endorse or promote products derived from this software without
+    specific prior written permission from the University or the Contributors.
+
+6.  THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND THE CONTRIBUTORS "AS IS"
+    WITH NO WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED.  In no event
+    shall the University or the Contributors be liable for any damages
+    suffered by the users arising out of the use of this software, even if
+    advised of the possibility of such damage.
+
+--------------------------------------------------------------------------
+Portions of HDF5 were developed with support from the University of 
+California, Lawrence Livermore National Laboratory (UC LLNL).
+The following statement applies to those portions of the product
+and must be retained in any redistribution of source code, binaries,
+documentation, and/or accompanying materials:
+
+    This work was partially produced at the University of California,
+    Lawrence Livermore National Laboratory (UC LLNL) under contract no.
+    W-7405-ENG-48 (Contract 48) between the U.S. Department of Energy 
+    (DOE) and The Regents of the University of California (University) 
+    for the operation of UC LLNL.
+
+    DISCLAIMER:
+    This work was prepared as an account of work sponsored by an agency 
+    of the United States Government.  Neither the United States 
+    Government nor the University of California nor any of their 
+    employees, makes any warranty, express or implied, or assumes any 
+    liability or responsibility for the accuracy, completeness, or 
+    usefulness of any information, apparatus, product, or process 
+    disclosed, or represents that its use would not infringe privately-
+    owned rights.  Reference herein to any specific commercial products, 
+    process, or service by trade name, trademark, manufacturer, or 
+    otherwise, does not necessarily constitute or imply its endorsement, 
+    recommendation, or favoring by the United States Government or the 
+    University of California.  The views and opinions of authors 
+    expressed herein do not necessarily state or reflect those of the 
+    United States Government or the University of California, and shall 
+    not be used for advertising or product endorsement purposes.
+--------------------------------------------------------------------------
+
diff --git a/dist/LICENSE b/dist/LICENSE
new file mode 100644
index 0000000..f820d4b
--- /dev/null
+++ b/dist/LICENSE
@@ -0,0 +1,203 @@
+/*
+ *                                 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/doc/tagged_array_def.txt b/doc/tagged_array_def.txt
new file mode 100644
index 0000000..4fe98e2
--- /dev/null
+++ b/doc/tagged_array_def.txt
@@ -0,0 +1,43 @@
+Tagged Array Definition:
+
+All indices and lengths are given in bytes.
+
+ID: number_type
+START INDEX: 0
+LENGTH: 1
+DESCRIPTION:
+    'F' : IEEE floating point numbers
+    'I' : Integer numbers
+ 
+ID: endiness
+START INDEX: 1
+LENGTH: 1
+DESCRIPTION:
+    'L' : Little Endian
+    'B' : Big Endian
+
+ID: element_size
+START INDEX: 2
+LENGTH: 1
+DESCRIPTION:
+    Size in Bytes (e.g. 4 for a 32bit number, or 8 for a 64bit number)
+    
+ID: rank
+START INDEX: 3
+LENGTH: 1
+DESCRIPTION:
+    Rank of the array (e.g. 2 for a matrix or 3 for a cube)
+
+ID: dimensions
+START INDEX: 4
+LENGTH: 4 * rank
+DESCRIPTION:
+    Dimensions of the array along each axis; each entry is a 32bit (4 byte) integer number in the specified endiness
+
+ID: data
+START INDEX: 4 + 4 * rank
+LENGTH: prod(dimensions)
+DESCRIPTION:
+    Number array with prod(dimensions) elements in C row-major order; 
+    each element is a number of the specified number_type, endiness and element_size
+    
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..667288a
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..e4d08ce
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Apr 23 11:31:33 CEST 2014
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://svncisd.ethz.ch/repos/cisd/ivy-repository/trunk/gradle/distribution/1.8/gradle-1.8-all.zip
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..91a7e26
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..aec9973
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,90 @@
+ at if "%DEBUG%" == "" @echo off
+ at rem ##########################################################################
+ at rem
+ at rem  Gradle startup script for Windows
+ at rem
+ at rem ##########################################################################
+
+ at rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+ at rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+ at rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+ at rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+ at rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+ at rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+ at rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+ at rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+ at rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/resource/dependency-structure.ddf b/resource/dependency-structure.ddf
new file mode 100644
index 0000000..b463616
--- /dev/null
+++ b/resource/dependency-structure.ddf
@@ -0,0 +1,6 @@
+{package} = ch.systemsx.cisd.base
+
+layer exceptions = ${package}.exceptions
+layer rest = ${package}.mdarray ${package}.namedthread ${package}.unix ${package}.utilities
+
+check layeringOf exceptions rest
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..8062ac2
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+// Don't delete it eventough it is empty!
diff --git a/source/c/COPYING b/source/c/COPYING
new file mode 100644
index 0000000..7ca6009
--- /dev/null
+++ b/source/c/COPYING
@@ -0,0 +1,88 @@
+Copyright Notice and Statement for NCSA Hierarchical Data Format (HDF)
+Java Software Library and Utilities
+
+NCSA Hierarchical Data Format (HDF) Software Library and Utilities 
+Copyright 1988-2004, the Board of Trustees of the University of Illinois.
+Copyright 2007-2009, Center for Information Sciences and Databases, ETH Zurich, Switzerland.  
+All rights reserved.
+
+Contributors to the library: National Center for Supercomputing 
+Applications (NCSA) at the University of Illinois, Lawrence 
+Livermore Nationall Laboratory (LLNL), Sandia National Laboratories (SNL), 
+Los Alamos National Laboratory (LANL). Fortner Software, Unidata 
+Program Center (netCDF), The Independent JPEG Group (JPEG), 
+Jean-loup Gailly and Mark Adler (gzip), and Digital Equipment 
+Corporation (DEC). Macintosh support contributed by Gregory L. Guerin.
+Center for Information Sciences and Databases, ETH Zurich, Switzerland
+
+The package 'glguerin':
+Copyright 1998, 1999 by Gregory L. Guerin.
+Redistribute or reuse only as described below.
+These files are from the MacBinary Toolkit for Java:
+   <http://www.amug.org/~glguerin/sw/#macbinary>
+and are redistributed by NCSA with permission of the author.
+
+This work was supported in part by a Cooperative Agreement with 
+NASA under NASA grant NAG 5-2040 and NAG NCC5-599.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted for any purpose (including commercial purposes)
+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 materials provided with the distribution.
+
+3.  In addition, redistributions of modified forms of the source or binary
+    code must carry prominent notices stating that the original code was
+    changed and the date of the change.
+
+4.  All publications or advertising materials mentioning features or use of
+    this software must acknowledge that it was developed by the National
+    Center for Supercomputing Applications at the University of Illinois, and
+    credit the Contributors.
+
+5.  Neither the name of the University nor the names of the Contributors may
+    be used to endorse or promote products derived from this software without
+    specific prior written permission from the University or the Contributors.
+
+6.  THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND THE CONTRIBUTORS "AS IS"
+    WITH NO WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED.  In no event
+    shall the University or the Contributors be liable for any damages
+    suffered by the users arising out of the use of this software, even if
+    advised of the possibility of such damage.
+
+--------------------------------------------------------------------------
+Portions of HDF5 were developed with support from the University of 
+California, Lawrence Livermore National Laboratory (UC LLNL).
+The following statement applies to those portions of the product
+and must be retained in any redistribution of source code, binaries,
+documentation, and/or accompanying materials:
+
+    This work was partially produced at the University of California,
+    Lawrence Livermore National Laboratory (UC LLNL) under contract no.
+    W-7405-ENG-48 (Contract 48) between the U.S. Department of Energy 
+    (DOE) and The Regents of the University of California (University) 
+    for the operation of UC LLNL.
+
+    DISCLAIMER:
+    This work was prepared as an account of work sponsored by an agency 
+    of the United States Government.  Neither the United States 
+    Government nor the University of California nor any of their 
+    employees, makes any warranty, express or implied, or assumes any 
+    liability or responsibility for the accuracy, completeness, or 
+    usefulness of any information, apparatus, product, or process 
+    disclosed, or represents that its use would not infringe privately-
+    owned rights.  Reference herein to any specific commercial products, 
+    process, or service by trade name, trademark, manufacturer, or 
+    otherwise, does not necessarily constitute or imply its endorsement, 
+    recommendation, or favoring by the United States Government or the 
+    University of California.  The views and opinions of authors 
+    expressed herein do not necessarily state or reflect those of the 
+    United States Government or the University of California, and shall 
+    not be used for advertising or product endorsement purposes.
+--------------------------------------------------------------------------
+
diff --git a/source/c/compile_linux_amd64.sh b/source/c/compile_linux_amd64.sh
new file mode 100755
index 0000000..038f83a
--- /dev/null
+++ b/source/c/compile_linux_amd64.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+gcc -shared -O3 -fPIC unix.c -I/usr/java/jdk1.6.0/include -I/usr/java/jdk1.6.0/include/linux -o libunix.so
+
+# MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
+gcc -shared -O3 -fPIC -DMACHINE_BYTE_ORDER=1 copy*.c  -I/usr/java/jdk1.6.0/include -I/usr/java/jdk1.6.0/include/linux -o libnativedata.so
diff --git a/source/c/compile_linux_arm.sh b/source/c/compile_linux_arm.sh
new file mode 100755
index 0000000..2b57024
--- /dev/null
+++ b/source/c/compile_linux_arm.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+gcc -shared -O3 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -I/usr/java/jdk1.7.0/include -I/usr/java/jdk1.7.0/include/linux unix.c -o libunix.so
+
+# MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
+gcc -shared -O3 -fPIC -DMACHINE_BYTE_ORDER=1 copy*.c  -I/usr/java/jdk1.7.0/include -I/usr/java/jdk1.7.0/include/linux -o libnativedata.so
diff --git a/source/c/compile_linux_i386.sh b/source/c/compile_linux_i386.sh
new file mode 100755
index 0000000..e9cb840
--- /dev/null
+++ b/source/c/compile_linux_i386.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+gcc -m32 -shared -O3 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -I/usr/java/jdk1.6.0/include -I/usr/java/jdk1.6.0/include/linux unix.c -o libunix.so
+
+# MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
+gcc -m32 -shared -O3 -fPIC -DMACHINE_BYTE_ORDER=1 copy*.c  -I/usr/java/jdk1.6.0/include -I/usr/java/jdk1.6.0/include/linux -o libnativedata.so
diff --git a/source/c/compile_macosx_i386.sh b/source/c/compile_macosx_i386.sh
new file mode 100755
index 0000000..e8f5345
--- /dev/null
+++ b/source/c/compile_macosx_i386.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+gcc -m32 -mmacosx-version-min=10.6 -bundle -O3 unix.c -I/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers -o libunix.jnilib
+
+# MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
+gcc -m32 -mmacosx-version-min=10.6 -bundle -O3 -DMACHINE_BYTE_ORDER=1 copy*.c -I/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers -o libnativedata.jnilib
diff --git a/source/c/compile_macosx_x86_64.sh b/source/c/compile_macosx_x86_64.sh
new file mode 100755
index 0000000..ec2d736
--- /dev/null
+++ b/source/c/compile_macosx_x86_64.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+gcc -m64 -mmacosx-version-min=10.6 -dynamiclib -D_DARWIN_USE_64_BIT_INODE -O3 unix.c -I/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers -o libunix.jnilib
+
+# MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
+gcc -m64 -mmacosx-version-min=10.6 -dynamiclib -O3 -DMACHINE_BYTE_ORDER=1 copy*.c -I/System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers -o libnativedata.jnilib
diff --git a/source/c/compile_solaris_amd64.sh b/source/c/compile_solaris_amd64.sh
new file mode 100755
index 0000000..16c3ac9
--- /dev/null
+++ b/source/c/compile_solaris_amd64.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+cc -G -KPIC -fast -m64 -I/usr/java/include -I/usr/java/include/solaris unix.c -o libunix.so
+
+# MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
+cc -G -KPIC -fast -m64 -DMACHINE_BYTE_ORDER=1 copy*.c  -I/usr/java/include -I/usr/java/include/solaris -o libnativedata.so
diff --git a/source/c/compile_solaris_sparc.sh b/source/c/compile_solaris_sparc.sh
new file mode 100755
index 0000000..99e2dd2
--- /dev/null
+++ b/source/c/compile_solaris_sparc.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+cc -G -KPIC -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -I/usr/java/include -I/usr/java/include/solaris unix.c -o libunix.so
+
+# MACHINE_BYTE_ORDER=2 corresponds to 'big endian'
+cc -G -KPIC -DMACHINE_BYTE_ORDER=2 copy*.c  -I/usr/java/include -I/usr/java/include/solaris -o libnativedata.so
diff --git a/source/c/compile_solaris_sparcv9.sh b/source/c/compile_solaris_sparcv9.sh
new file mode 100755
index 0000000..37852b4
--- /dev/null
+++ b/source/c/compile_solaris_sparcv9.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+cc -G -KPIC -fast -m64 -I/usr/java/include -I/usr/java/include/solaris unix.c -o libunix.so
+
+# MACHINE_BYTE_ORDER=2 corresponds to 'big endian'
+cc -G -KPIC -fast -m64 -DMACHINE_BYTE_ORDER=2 copy*.c  -I/usr/java/include -I/usr/java/include/solaris -o libnativedata.so
diff --git a/source/c/compile_solaris_x86.sh b/source/c/compile_solaris_x86.sh
new file mode 100755
index 0000000..588e192
--- /dev/null
+++ b/source/c/compile_solaris_x86.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+cc -G -KPIC -fast -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -I/usr/java/include -I/usr/java/include/solaris unix.c -o libunix.so
+
+# MACHINE_BYTE_ORDER=1 corresponds to 'little endian'
+cc -G -KPIC -fast -DMACHINE_BYTE_ORDER=1 copy*.c  -I/usr/java/include -I/usr/java/include/solaris -o libnativedata.so
diff --git a/source/c/compile_windows_i386.mak b/source/c/compile_windows_i386.mak
new file mode 100644
index 0000000..8ebb900
--- /dev/null
+++ b/source/c/compile_windows_i386.mak
@@ -0,0 +1,181 @@
+#============================================================================
+#
+#              Makefile to compile the 'nativedata' native library
+#              Usage: nmake /f compile_windows_i386.mak
+#
+#============================================================================
+
+# Visual C++ directory, for example
+VCPPDIR=C:\Program Files\Microsoft Visual Studio 9.0\VC
+
+# Directory where JDK is installed (We require JDK 1.6)
+JAVADIR=C:\Program Files\Java\jdk1.6.0_37
+
+# Common parent directory
+PARENTDIR=C:\nativeData
+
+# Directory of the HDF Java Products, for example
+SRCDIR=$(PARENTDIR)\c\
+
+#===========================================================================
+#   Do not make any change below this line unless you know what you do
+#===========================================================================
+PATH=$(PATH);$(VCPPDIR)\BIN
+SRCDIR=$(SRCDIR)
+
+VALID_PATH_SET=YES
+#-------------------------------------------------------
+# Test if all path is valid
+
+!IF EXISTS("$(VCPPDIR)")
+!ELSE
+!MESSAGE ERROR: Visual C++ directory $(VCPPDIR) does not exist
+VALID_PATH_SET=NO 
+!ENDIF
+
+!IF EXISTS("$(JAVADIR)")
+!ELSE
+!MESSAGE ERROR: JDK directory $(JAVADIR) does not exist
+VALID_PATH_SET=NO 
+!ENDIF
+
+!IF EXISTS("$(SRCDIR)")
+!ELSE
+!MESSAGE ERROR: C source directory $(SRCDIR) does not exist
+VALID_PATH_SET=NO 
+!ENDIF
+
+#-------------------------------------------------------
+
+
+!IF "$(VALID_PATH_SET)" == "YES"
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE 
+NULL=nul
+!ENDIF 
+
+INTDIR=.\nativedata\Release
+OUTDIR=$(SRCDIR)\lib\win
+
+INCLUDES =  \
+	"$(JAVADIR)\include\jni.h" \
+	"$(JAVADIR)\include\win32\jni_md.h"
+
+
+ALL : "$(OUTDIR)\nativedata.dll"
+
+"$(INTDIR)" :
+    if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /W3 /EHsc /O2 /I "$(JAVADIR)\include" /I "$(JAVADIR)\include\win32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "MACHINE_BYTE_ORDER=1" /Fp"$(INTDIR)\nativedata.pch" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c 
+
+.c{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.c{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 
+RSC=rc.exe
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(INTDIR)\nativedata.bsc" 
+BSC32_SBRS= \
+	
+LINK=link.exe
+LINK_FLAGS=/nologo /dll /nodefaultlib:msvcrt /incremental:no /pdb:"$(INTDIR)\nativedata.pdb" /machine:I386 /out:"$(OUTDIR)\nativedata.dll" /implib:"$(INTDIR)\nativedata.lib" 
+LINK_OBJS= \
+	"$(INTDIR)\copyCommon.obj" \
+	"$(INTDIR)\copyByteDouble.obj" \
+	"$(INTDIR)\copyByteFloat.obj" \
+	"$(INTDIR)\copyByteInt.obj" \
+	"$(INTDIR)\copyByteLong.obj" \
+	"$(INTDIR)\copyByteShort.obj" \
+	"$(INTDIR)\copyByteChar.obj"
+
+"$(OUTDIR)\nativedata.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK_OBJS)
+    $(LINK) @<<
+  $(LINK_FLAGS) $(LINK_OBJS)
+<<
+
+
+SOURCE=$(SRCDIR)\copyCommon.c
+
+"$(INTDIR)\copyCommon.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=$(SRCDIR)\copyByteDouble.c
+
+"$(INTDIR)\copyByteDouble.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=$(SRCDIR)\copyByteFloat.c
+
+"$(INTDIR)\copyByteFloat.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=$(SRCDIR)\copyByteInt.c
+
+"$(INTDIR)\copyByteInt.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=$(SRCDIR)\copyByteLong.c
+
+"$(INTDIR)\copyByteLong.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=$(SRCDIR)\copyByteShort.c
+
+"$(INTDIR)\copyByteShort.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=$(SRCDIR)\copyByteChar.c
+
+"$(INTDIR)\copyByteChar.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+CLEAN :
+	- at erase "$(INTDIR)\copyCommon.obj"
+	- at erase "$(INTDIR)\copyByteDouble.obj"
+	- at erase "$(INTDIR)\copyByteFloat.obj"
+	- at erase "$(INTDIR)\copyByteInt.obj"
+	- at erase "$(INTDIR)\copyByteLong.obj"
+	- at erase "$(INTDIR)\copyByteShort.obj"
+	- at erase "$(INTDIR)\copyByteChar.obj"
+	- at erase "$(INTDIR)\vc90.idb"
+	- at erase "$(INTDIR)\nativedata.exp"
+	- at erase "$(INTDIR)\nativedata.lib"
+	- at erase "$(OUTDIR)\nativedata.dll"
+
+!ENDIF
diff --git a/source/c/compile_windows_x64.mak b/source/c/compile_windows_x64.mak
new file mode 100644
index 0000000..52f71d7
--- /dev/null
+++ b/source/c/compile_windows_x64.mak
@@ -0,0 +1,182 @@
+#============================================================================
+#
+#              Makefile to compile the 'nativedata' native library
+#              Usage: nmake /f compile_windows_i386.mak
+#
+#============================================================================
+
+# Visual C++ directory, for example
+VCPPDIR=C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC
+
+# Directory where JDK is installed (We require JDK 1.6)
+JAVADIR=C:\Program Files\Java\jdk1.6.0_37
+
+# Common parent directory
+PARENTDIR=C:\nativeData
+
+# Directory of the HDF Java Products, for example
+SRCDIR=$(PARENTDIR)\c\
+
+#===========================================================================
+#   Do not make any change below this line unless you know what you do
+#===========================================================================
+PATH=$(PATH);$(VCPPDIR)\BIN
+SRCDIR=$(SRCDIR)
+
+VALID_PATH_SET=YES
+#-------------------------------------------------------
+# Test if all path is valid
+
+!IF EXISTS("$(VCPPDIR)")
+!ELSE
+!MESSAGE ERROR: Visual C++ directory $(VCPPDIR) does not exist
+VALID_PATH_SET=NO 
+!ENDIF
+
+!IF EXISTS("$(JAVADIR)")
+!ELSE
+!MESSAGE ERROR: JDK directory $(JAVADIR) does not exist
+VALID_PATH_SET=NO 
+!ENDIF
+
+!IF EXISTS("$(SRCDIR)")
+!ELSE
+!MESSAGE ERROR: C source directory $(SRCDIR) does not exist
+VALID_PATH_SET=NO 
+!ENDIF
+
+#-------------------------------------------------------
+
+
+!IF "$(VALID_PATH_SET)" == "YES"
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE 
+NULL=nul
+!ENDIF 
+
+INTDIR=.\nativedata\Release
+OUTDIR=$(SRCDIR)\lib\win
+
+INCLUDES =  \
+	"$(JAVADIR)\include\jni.h" \
+	"$(JAVADIR)\include\win32\jni_md.h"
+
+
+ALL : "$(OUTDIR)\nativedata.dll"
+
+"$(INTDIR)" :
+    if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /W3 /EHsc /O2 /I "$(JAVADIR)\include" /I "$(JAVADIR)\include\win32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "MACHINE_BYTE_ORDER=1" /Fp"$(INTDIR)\nativedata.pch" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c 
+
+.c{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.c{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 
+RSC=rc.exe
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(INTDIR)\nativedata.bsc" 
+BSC32_SBRS= \
+	
+LINK=link.exe
+LINK_FLAGS=/nologo /dll /nodefaultlib:msvcrt /incremental:no /pdb:"$(INTDIR)\nativedata.pdb" /machine:x64 /out:"$(OUTDIR)\nativedata.dll" /implib:"$(INTDIR)\nativedata.lib" 
+LINK_OBJS= \
+	"$(INTDIR)\copyCommon.obj" \
+	"$(INTDIR)\copyByteDouble.obj" \
+	"$(INTDIR)\copyByteFloat.obj" \
+	"$(INTDIR)\copyByteInt.obj" \
+	"$(INTDIR)\copyByteLong.obj" \
+	"$(INTDIR)\copyByteShort.obj" \
+	"$(INTDIR)\copyByteChar.obj"
+
+
+"$(OUTDIR)\nativedata.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK_OBJS)
+    $(LINK) @<<
+  $(LINK_FLAGS) $(LINK_OBJS)
+<<
+
+
+SOURCE=$(SRCDIR)\copyCommon.c
+
+"$(INTDIR)\copyCommon.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=$(SRCDIR)\copyByteDouble.c
+
+"$(INTDIR)\copyByteDouble.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=$(SRCDIR)\copyByteFloat.c
+
+"$(INTDIR)\copyByteFloat.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=$(SRCDIR)\copyByteInt.c
+
+"$(INTDIR)\copyByteInt.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=$(SRCDIR)\copyByteLong.c
+
+"$(INTDIR)\copyByteLong.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=$(SRCDIR)\copyByteShort.c
+
+"$(INTDIR)\copyByteShort.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+SOURCE=$(SRCDIR)\copyByteChar.c
+
+"$(INTDIR)\copyByteChar.obj" : $(SOURCE) $(INCLUDES) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+CLEAN :
+	- at erase "$(INTDIR)\copyCommon.obj"
+	- at erase "$(INTDIR)\copyByteDouble.obj"
+	- at erase "$(INTDIR)\copyByteFloat.obj"
+	- at erase "$(INTDIR)\copyByteInt.obj"
+	- at erase "$(INTDIR)\copyByteLong.obj"
+	- at erase "$(INTDIR)\copyByteShort.obj"
+	- at erase "$(INTDIR)\copyByteChar.obj"
+	- at erase "$(INTDIR)\vc90.idb"
+	- at erase "$(INTDIR)\nativedata.exp"
+	- at erase "$(INTDIR)\nativedata.lib"
+	- at erase "$(OUTDIR)\nativedata.dll"
+
+!ENDIF
diff --git a/source/c/copyByteChar.c b/source/c/copyByteChar.c
new file mode 100644
index 0000000..02b8a17
--- /dev/null
+++ b/source/c/copyByteChar.c
@@ -0,0 +1,42 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Computational Science Alliance                                  *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * Center for Information Sciences and Databases, ETH Zurich, Switzerland   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * COPYING file.                                                            *
+ *                                                                          *
+ ****************************************************************************/
+
+/*
+ *  This module contains the implementation of all the native methods
+ *  used for number conversion.  This is represented by the Java
+ *  class HDFNativeData.
+ *
+ *  These routines convert one dimensional arrays of bytes into
+ *  one-D arrays of other types (int, float, etc) and vice versa.
+ *
+ *  These routines are called from the Java parts of the Java-C
+ *  interface.
+ *
+ *  ***Important notes:
+ *
+ *     1.  These routines are designed to be portable--they use the
+ *         C compiler to do the required native data manipulation.
+ *     2.  These routines copy the data at least once -- a serious
+ *         but unavoidable performance hit.
+ */
+
+#define TARGET jchar
+#define TARGET_ARRAY jcharArray
+#define METHODNAMETB "copyCharToByte"
+#define FUNCTIONNAMETB Java_ch_systemsx_cisd_base_convert_NativeData_copyCharToByte___3CI_3BIII
+#define METHODNAMEBT "copyByteToChar"
+#define FUNCTIONNAMEBT Java_ch_systemsx_cisd_base_convert_NativeData_copyByteToChar___3BI_3CIII
+#define COPY_FUNC GetCharArrayRegion
+#define CHANGE_BYTE_ORDER CHANGE_BYTE_ORDER_2
+
+#include "copyByteTarget.ctempl"
diff --git a/source/c/copyByteDouble.c b/source/c/copyByteDouble.c
new file mode 100644
index 0000000..734d739
--- /dev/null
+++ b/source/c/copyByteDouble.c
@@ -0,0 +1,42 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Computational Science Alliance                                  *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * Center for Information Sciences and Databases, ETH Zurich, Switzerland   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * COPYING file.                                                            *
+ *                                                                          *
+ ****************************************************************************/
+
+/*
+ *  This module contains the implementation of all the native methods
+ *  used for number conversion.  This is represented by the Java
+ *  class HDFNativeData.
+ *
+ *  These routines convert one dimensional arrays of bytes into
+ *  one-D arrays of other types (int, double, etc) and vice versa.
+ *
+ *  These routines are called from the Java parts of the Java-C
+ *  interface.
+ *
+ *  ***Important notes:
+ *
+ *     1.  These routines are designed to be portable--they use the
+ *         C compiler to do the required native data manipulation.
+ *     2.  These routines copy the data at least once -- a serious
+ *         but unavoidable performance hit.
+ */
+
+#define TARGET jdouble
+#define TARGET_ARRAY jdoubleArray
+#define METHODNAMETB "copyDoubleToByte"
+#define FUNCTIONNAMETB Java_ch_systemsx_cisd_base_convert_NativeData_copyDoubleToByte___3DI_3BIII
+#define METHODNAMEBT "copyByteToDouble"
+#define FUNCTIONNAMEBT Java_ch_systemsx_cisd_base_convert_NativeData_copyByteToDouble___3BI_3DIII
+#define COPY_FUNC GetDoubleArrayRegion
+#define CHANGE_BYTE_ORDER CHANGE_BYTE_ORDER_8
+
+#include "copyByteTarget.ctempl"
diff --git a/source/c/copyByteFloat.c b/source/c/copyByteFloat.c
new file mode 100644
index 0000000..797a818
--- /dev/null
+++ b/source/c/copyByteFloat.c
@@ -0,0 +1,42 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Computational Science Alliance                                  *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * Center for Information Sciences and Databases, ETH Zurich, Switzerland   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * COPYING file.                                                            *
+ *                                                                          *
+ ****************************************************************************/
+
+/*
+ *  This module contains the implementation of all the native methods
+ *  used for number conversion.  This is represented by the Java
+ *  class HDFNativeData.
+ *
+ *  These routines convert one dimensional arrays of bytes into
+ *  one-D arrays of other types (int, float, etc) and vice versa.
+ *
+ *  These routines are called from the Java parts of the Java-C
+ *  interface.
+ *
+ *  ***Important notes:
+ *
+ *     1.  These routines are designed to be portable--they use the
+ *         C compiler to do the required native data manipulation.
+ *     2.  These routines copy the data at least once -- a serious
+ *         but unavoidable performance hit.
+ */
+
+#define TARGET jfloat
+#define TARGET_ARRAY jfloatArray
+#define METHODNAMETB "copyFloatToByte"
+#define FUNCTIONNAMETB Java_ch_systemsx_cisd_base_convert_NativeData_copyFloatToByte___3FI_3BIII
+#define METHODNAMEBT "copyByteToFloat"
+#define FUNCTIONNAMEBT Java_ch_systemsx_cisd_base_convert_NativeData_copyByteToFloat___3BI_3FIII
+#define COPY_FUNC GetFloatArrayRegion
+#define CHANGE_BYTE_ORDER CHANGE_BYTE_ORDER_4
+
+#include "copyByteTarget.ctempl"
diff --git a/source/c/copyByteInt.c b/source/c/copyByteInt.c
new file mode 100644
index 0000000..4227546
--- /dev/null
+++ b/source/c/copyByteInt.c
@@ -0,0 +1,42 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Computational Science Alliance                                  *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * Center for Information Sciences and Databases, ETH Zurich, Switzerland   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * COPYING file.                                                            *
+ *                                                                          *
+ ****************************************************************************/
+
+/*
+ *  This module contains the implementation of all the native methods
+ *  used for number conversion.  This is represented by the Java
+ *  class HDFNativeData.
+ *
+ *  These routines convert one dimensional arrays of bytes into
+ *  one-D arrays of other types (int, float, etc) and vice versa.
+ *
+ *  These routines are called from the Java parts of the Java-C
+ *  interface.
+ *
+ *  ***Important notes:
+ *
+ *     1.  These routines are designed to be portable--they use the
+ *         C compiler to do the required native data manipulation.
+ *     2.  These routines copy the data at least once -- a serious
+ *         but unavoidable performance hit.
+ */
+
+#define TARGET jint
+#define TARGET_ARRAY jintArray
+#define METHODNAMETB "copyIntToByte"
+#define FUNCTIONNAMETB Java_ch_systemsx_cisd_base_convert_NativeData_copyIntToByte___3II_3BIII
+#define METHODNAMEBT "copyByteToInt"
+#define FUNCTIONNAMEBT Java_ch_systemsx_cisd_base_convert_NativeData_copyByteToInt___3BI_3IIII
+#define COPY_FUNC GetIntArrayRegion
+#define CHANGE_BYTE_ORDER CHANGE_BYTE_ORDER_4
+
+#include "copyByteTarget.ctempl"
diff --git a/source/c/copyByteLong.c b/source/c/copyByteLong.c
new file mode 100644
index 0000000..c28352f
--- /dev/null
+++ b/source/c/copyByteLong.c
@@ -0,0 +1,42 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Computational Science Alliance                                  *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * Center for Information Sciences and Databases, ETH Zurich, Switzerland   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * COPYING file.                                                            *
+ *                                                                          *
+ ****************************************************************************/
+
+/*
+ *  This module contains the implementation of all the native methods
+ *  used for number conversion.  This is represented by the Java
+ *  class HDFNativeData.
+ *
+ *  These routines convert one dimensional arrays of bytes into
+ *  one-D arrays of other types (int, float, etc) and vice versa.
+ *
+ *  These routines are called from the Java parts of the Java-C
+ *  interface.
+ *
+ *  ***Important notes:
+ *
+ *     1.  These routines are designed to be portable--they use the
+ *         C compiler to do the required native data manipulation.
+ *     2.  These routines copy the data at least once -- a serious
+ *         but unavoidable performance hit.
+ */
+
+#define TARGET jlong
+#define TARGET_ARRAY jlongArray
+#define METHODNAMETB "copyLongToByte"
+#define FUNCTIONNAMETB Java_ch_systemsx_cisd_base_convert_NativeData_copyLongToByte___3JI_3BIII
+#define METHODNAMEBT "copyByteToLong"
+#define FUNCTIONNAMEBT Java_ch_systemsx_cisd_base_convert_NativeData_copyByteToLong___3BI_3JIII
+#define COPY_FUNC GetLongArrayRegion
+#define CHANGE_BYTE_ORDER CHANGE_BYTE_ORDER_8
+
+#include "copyByteTarget.ctempl"
diff --git a/source/c/copyByteShort.c b/source/c/copyByteShort.c
new file mode 100644
index 0000000..5081ab7
--- /dev/null
+++ b/source/c/copyByteShort.c
@@ -0,0 +1,42 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Computational Science Alliance                                  *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * Center for Information Sciences and Databases, ETH Zurich, Switzerland   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * COPYING file.                                                            *
+ *                                                                          *
+ ****************************************************************************/
+
+/*
+ *  This module contains the implementation of all the native methods
+ *  used for number conversion.  This is represented by the Java
+ *  class HDFNativeData.
+ *
+ *  These routines convert one dimensional arrays of bytes into
+ *  one-D arrays of other types (int, float, etc) and vice versa.
+ *
+ *  These routines are called from the Java parts of the Java-C
+ *  interface.
+ *
+ *  ***Important notes:
+ *
+ *     1.  These routines are designed to be portable--they use the
+ *         C compiler to do the required native data manipulation.
+ *     2.  These routines copy the data at least once -- a serious
+ *         but unavoidable performance hit.
+ */
+
+#define TARGET jshort
+#define TARGET_ARRAY jshortArray
+#define METHODNAMETB "copyShortToByte"
+#define FUNCTIONNAMETB Java_ch_systemsx_cisd_base_convert_NativeData_copyShortToByte___3SI_3BIII
+#define METHODNAMEBT "copyByteToShort"
+#define FUNCTIONNAMEBT Java_ch_systemsx_cisd_base_convert_NativeData_copyByteToShort___3BI_3SIII
+#define COPY_FUNC GetShortArrayRegion
+#define CHANGE_BYTE_ORDER CHANGE_BYTE_ORDER_2
+
+#include "copyByteTarget.ctempl"
diff --git a/source/c/copyByteTarget.ctempl b/source/c/copyByteTarget.ctempl
new file mode 100644
index 0000000..7d9b8d2
--- /dev/null
+++ b/source/c/copyByteTarget.ctempl
@@ -0,0 +1,241 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Computational Science Alliance                                  *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * Center for Information Sciences and Databases, ETH Zurich, Switzerland   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * COPYING file.                                                            *
+ *                                                                          *
+ ****************************************************************************/
+
+/*
+ *  This module contains the implementation of all the native methods
+ *  used for number conversion.  This is represented by the Java
+ *  class HDFNativeData.
+ *
+ *  These routines convert one dimensional arrays of bytes into
+ *  one-D arrays of other types (int, float, etc) and vice versa.
+ *
+ *  These routines are called from the Java parts of the Java-C
+ *  interface.
+ *
+ *  ***Important notes:
+ *
+ *     1.  These routines are designed to be portable--they use the
+ *         C compiler to do the required native data manipulation.
+ *     2.  These routines copy the data at least once -- a serious
+ *         but unavoidable performance hit.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <jni.h>
+
+extern jboolean h5JNIFatalError( JNIEnv *env, char *functName);
+extern jboolean h5nullArgument( JNIEnv *env, char *functName);
+extern jboolean h5badArgument( JNIEnv *env, char *functName);
+extern jboolean h5indexOutOfBounds( JNIEnv *env, char *functName);
+
+/* Change byte order for data type of length 2. */
+#define CHANGE_BYTE_ORDER_2(ARRAY) {jbyte _tmp; _tmp=ARRAY[0]; ARRAY[0]=ARRAY[1]; ARRAY[1]=_tmp;}
+/* Change byte order for data type of length 4. */
+#define CHANGE_BYTE_ORDER_4(ARRAY) {jbyte _tmp; _tmp=ARRAY[0]; ARRAY[0]=ARRAY[3]; ARRAY[3]=_tmp; _tmp=ARRAY[1]; ARRAY[1]=ARRAY[2]; ARRAY[2]=_tmp;}
+/* Change byte order for data type of length 8. */
+#define CHANGE_BYTE_ORDER_8(ARRAY) {jbyte _tmp; _tmp=ARRAY[0]; ARRAY[0]=ARRAY[7]; ARRAY[7]=_tmp; _tmp=ARRAY[1]; ARRAY[1]=ARRAY[6]; ARRAY[6]=_tmp; _tmp=ARRAY[2]; ARRAY[2]=ARRAY[5]; ARRAY[5]=_tmp; _tmp=ARRAY[3]; ARRAY[3]=ARRAY[4]; ARRAY[4]=_tmp;}
+
+#define INDATA_IS_NULL_ERR_TB METHODNAMETB ": inData is NULL"
+#define OUTDATA_IS_NULL_ERR_TB METHODNAMETB ": outData is NULL"
+#define OOB_IN_ERR_TB METHODNAMETB ": inStart or len is out of bounds"
+#define OOB_OUT_ERR_TB METHODNAMETB ": outStart or len is out of bounds"
+#define PINNING_OUT_ERR_TB METHODNAMETB ": pinning outArray failed"
+
+#define INDATA_IS_NULL_ERR_BT METHODNAMEBT ": inData is NULL"
+#define OUTDATA_IS_NULL_ERR_BT METHODNAMEBT ": outData is NULL"
+#define OOB_IN_ERR_BT METHODNAMEBT ": inStart or len is out of bounds"
+#define OOB_OUT_ERR_BT METHODNAMEBT ": outStart or len is out of bounds"
+#define PINNING_OUT_ERR_BT METHODNAMEBT ": pinning outArray failed"
+
+/*
+ *   public static native void copy<TARGET_CAPT>oByte(<TARGET>[] inData, int inStart, 
+ *                                byte[] outData, int outStart, int len, int byteOrder);
+ */
+JNIEXPORT void JNICALL FUNCTIONNAMETB
+(JNIEnv *env,
+  jclass clss,
+  TARGET_ARRAY inData, /* IN: array of TARGET */
+  jint inStart,
+  jbyteArray outData, /* OUT: array of byte */
+  jint outStart,
+  jint len,
+  jint byteOrder
+)  
+{
+    jsize inSize, outSize;
+    jint lenInBytes;
+    jbyte *outArray;
+    jboolean isCopy;
+
+    if (inData == NULL) {
+        h5nullArgument(env, INDATA_IS_NULL_ERR_BT);
+        return;
+    }
+
+    if (outData == NULL) {
+        h5nullArgument(env, OUTDATA_IS_NULL_ERR_TB);
+        return;
+    }
+
+    lenInBytes = len * sizeof(TARGET);
+
+#ifdef __cplusplus
+    inSize = env->GetArrayLength(inData);
+#else
+    inSize = (*env)->GetArrayLength(env, inData);
+#endif
+    if ((inStart < 0) || (inStart + len > inSize)) {
+        h5indexOutOfBounds(env, OOB_IN_ERR_TB);
+        return;
+    }
+
+#ifdef __cplusplus
+    outSize = env->GetArrayLength(outData);
+#else
+    outSize = (*env)->GetArrayLength(env, outData);
+#endif
+    if ((outStart < 0) || (outStart + lenInBytes > outSize)) {
+        h5indexOutOfBounds(env, OOB_OUT_ERR_TB);
+        return;
+    }
+
+#ifdef __cplusplus
+    outArray = env->GetPrimitiveArrayCritical(outData, &isCopy);
+#else
+    outArray = (*env)->GetPrimitiveArrayCritical(env, outData, &isCopy);
+#endif
+    if (outArray == NULL) {
+        h5JNIFatalError(env, PINNING_OUT_ERR_TB);
+        return;
+    }
+
+#ifdef __cplusplus
+    env->COPY_FUNC(inData, inStart, len, (TARGET*) (outArray + outStart));
+#else
+    (*env)->COPY_FUNC(env, inData, inStart, len, (TARGET*) (outArray + outStart));
+#endif
+
+    if (byteOrder > 0 && byteOrder != MACHINE_BYTE_ORDER)
+    {
+        jbyte *buf = outArray + outStart;
+        int nelmts;
+        for(nelmts = 0; nelmts < len; ++nelmts)
+        {
+            CHANGE_BYTE_ORDER(buf);
+            buf += sizeof(TARGET);
+        } 
+    }
+
+#ifdef __cplusplus
+    env->ReleasePrimitiveArrayCritical(outData, outArray, 0);
+#else
+    (*env)->ReleasePrimitiveArrayCritical(env, outData,outArray, 0);
+#endif
+
+    return;
+}
+
+/*
+ *   public static native void copyByteTo<TARGET_CAP>(byte[] inData, int inStart, 
+ *                                TARGET[] outData, int outStart, int len, int byteOrder);
+ */
+JNIEXPORT void JNICALL FUNCTIONNAMEBT
+(JNIEnv *env,
+  jclass clss,
+  jbyteArray inData, /* IN: array of byte */
+  jint inStart,
+  TARGET_ARRAY outData, /* OUT: array of TAGET */
+  jint outStart,
+  jint len,
+  jint byteOrder
+  )  
+{
+    jsize inSize, outSize;
+    jint lenInBytes;
+    TARGET *outArray;
+    jboolean isCopy;
+
+    if (inData == NULL) {
+        h5nullArgument(env, INDATA_IS_NULL_ERR_BT);
+        return;
+    }
+
+    if (outData == NULL) {
+        h5nullArgument(env, OUTDATA_IS_NULL_ERR_BT);
+        return;
+    }
+
+    lenInBytes = len * sizeof(TARGET);
+
+#ifdef __cplusplus
+    inSize = env->GetArrayLength(inData);
+#else
+    inSize = (*env)->GetArrayLength(env, inData);
+#endif
+    if ((inStart < 0) || (inStart + lenInBytes > inSize)) {
+        h5indexOutOfBounds(env, OOB_IN_ERR_BT);
+        return;
+    }
+
+#ifdef __cplusplus
+    outSize = env->GetArrayLength(outData);
+#else
+    outSize = (*env)->GetArrayLength(env, outData);
+#endif
+    if ((outStart < 0) || (outStart + len > outSize)) {
+        h5indexOutOfBounds(env, OOB_OUT_ERR_BT);
+        return;
+    }
+
+#ifdef __cplusplus
+    outArray = env->GetPrimitiveArrayCritical(outData, &isCopy);
+#else
+    outArray = (*env)->GetPrimitiveArrayCritical(env, outData, &isCopy);
+#endif
+    if (outArray == NULL) {
+        h5JNIFatalError(env, PINNING_OUT_ERR_BT);
+        return;
+    }
+
+#ifdef __cplusplus
+    env->GetByteArrayRegion(inData, inStart, lenInBytes, outArray + outStart);
+#else
+    (*env)->GetByteArrayRegion(env, inData, inStart, lenInBytes, (jbyte*) (outArray + outStart));
+#endif
+
+    if (byteOrder > 0 && byteOrder != MACHINE_BYTE_ORDER)
+    {
+        jbyte *buf = (jbyte*) outArray + outStart;
+        int nelmts;
+        for(nelmts = 0; nelmts < len; ++nelmts)
+        {
+            CHANGE_BYTE_ORDER(buf);
+            buf += sizeof(TARGET);
+        } 
+    }
+
+#ifdef __cplusplus
+    env->ReleasePrimitiveArrayCritical(outData, outArray, 0);
+#else
+    (*env)->ReleasePrimitiveArrayCritical(env, outData, outArray, 0);
+#endif
+
+    return;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/c/copyCommon.c b/source/c/copyCommon.c
new file mode 100755
index 0000000..40a0278
--- /dev/null
+++ b/source/c/copyCommon.c
@@ -0,0 +1,268 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Comptational Science Alliance                                   *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * COPYING file.                                                            *
+ *                                                                          *
+ ****************************************************************************/
+
+/*
+ *  This is a utility program used by native code to generate Java exceptions.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include "jni.h"
+
+/*
+ *   public static native boolean isLittleEndian();
+ */
+JNIEXPORT jboolean JNICALL Java_ch_systemsx_cisd_base_convert_NativeData_isLittleEndian
+(JNIEnv *env,
+  jclass clss
+  )  
+{
+    return MACHINE_BYTE_ORDER == 1;
+}
+
+/*
+ *  A fatal error in a JNI call
+ *  Create and throw an 'InternalError'
+ *
+ *  Note:  This routine never returns from the 'throw',
+ *  and the Java native method immediately raises the
+ *  exception.
+ */
+jboolean h5JNIFatalError( JNIEnv *env, char *functName)
+{
+    jmethodID jm;
+    jclass jc;
+    char * args[2];
+    jobject ex;
+    jstring str;
+    int rval;
+
+#ifdef __cplusplus
+    jc = env->FindClass("java/lang/InternalError");
+#else
+    jc = (*env)->FindClass(env, "java/lang/InternalError");
+#endif
+    if (jc == NULL) {
+        return JNI_FALSE;
+    }
+#ifdef __cplusplus
+    jm = env->GetMethodID(jc, "<init>", "(Ljava/lang/String;)V");
+#else
+    jm = (*env)->GetMethodID(env, jc, "<init>", "(Ljava/lang/String;)V");
+#endif
+    if (jm == NULL) {
+        return JNI_FALSE;
+    }
+
+#ifdef __cplusplus
+    str = env->NewStringUTF(functName);
+#else
+    str = (*env)->NewStringUTF(env,functName);
+#endif
+    args[0] = (char *)str;
+    args[1] = 0;
+#ifdef __cplusplus
+    ex = env->NewObjectA ( jc, jm, (jvalue *)args );
+
+    rval = env->Throw( (jthrowable) ex );
+#else
+    ex = (*env)->NewObjectA ( env, jc, jm, (jvalue *)args );
+
+    rval = (*env)->Throw(env, ex );
+#endif
+    if (rval < 0) {
+        fprintf(stderr, "FATAL ERROR:  JNIFatal: Throw failed\n");
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
+/*
+ *  A NULL argument in an HDF5 call
+ *  Create and throw an 'NullPointerException'
+ *
+ *  Note:  This routine never returns from the 'throw',
+ *  and the Java native method immediately raises the
+ *  exception.
+ */
+jboolean h5nullArgument( JNIEnv *env, char *functName)
+{
+    jmethodID jm;
+    jclass jc;
+    char * args[2];
+    jobject ex;
+    jstring str;
+    int rval;
+
+#ifdef __cplusplus
+    jc = env->FindClass("java/lang/NullPointerException");
+#else
+    jc = (*env)->FindClass(env, "java/lang/NullPointerException");
+#endif
+    if (jc == NULL) {
+        return JNI_FALSE;
+    }
+#ifdef __cplusplus
+    jm = env->GetMethodID(jc, "<init>", "(Ljava/lang/String;)V");
+#else
+    jm = (*env)->GetMethodID(env, jc, "<init>", "(Ljava/lang/String;)V");
+#endif
+    if (jm == NULL) {
+        return JNI_FALSE;
+    }
+
+#ifdef __cplusplus
+    str = env->NewStringUTF(functName);
+#else
+    str = (*env)->NewStringUTF(env,functName);
+#endif
+    args[0] = (char *)str;
+    args[1] = 0;
+#ifdef __cplusplus
+    ex = env->NewObjectA ( jc, jm, (jvalue *)args );
+
+    rval = env->Throw((jthrowable) ex );
+#else
+    ex = (*env)->NewObjectA ( env, jc, jm, (jvalue *)args );
+
+    rval = (*env)->Throw(env, ex );
+#endif
+
+    if (rval < 0) {
+        fprintf(stderr, "FATAL ERROR:  NullPointer: Throw failed\n");
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
+/*
+ *  A bad argument in an HDF5 call
+ *  Create and throw an 'IllegalArgumentException'
+ *
+ *  Note:  This routine never returns from the 'throw',
+ *  and the Java native method immediately raises the
+ *  exception.
+ */
+jboolean h5badArgument( JNIEnv *env, char *functName)
+{
+    jmethodID jm;
+    jclass jc;
+    char * args[2];
+    jobject ex;
+    jstring str;
+    int rval;
+
+#ifdef __cplusplus
+    jc = env->FindClass("java/lang/IllegalArgumentException");
+#else
+    jc = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
+#endif
+    if (jc == NULL) {
+        return JNI_FALSE;
+    }
+#ifdef __cplusplus
+    jm = env->GetMethodID(jc, "<init>", "(Ljava/lang/String;)V");
+#else
+    jm = (*env)->GetMethodID(env, jc, "<init>", "(Ljava/lang/String;)V");
+#endif
+    if (jm == NULL) {
+        return JNI_FALSE;
+    }
+
+#ifdef __cplusplus
+    str = env->NewStringUTF(functName);
+#else
+    str = (*env)->NewStringUTF(env,functName);
+#endif
+    args[0] = (char *)str;
+    args[1] = 0;
+#ifdef __cplusplus
+    ex = env->NewObjectA ( jc, jm, (jvalue *)args );
+
+    rval = env->Throw((jthrowable) ex );
+#else
+    ex = (*env)->NewObjectA ( env, jc, jm, (jvalue *)args );
+
+    rval = (*env)->Throw(env, ex );
+#endif
+    if (rval < 0) {
+        fprintf(stderr, "FATAL ERROR:  BadArgument: Throw failed\n");
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
+/*
+ *  An Index-out-of-bounds error argument in an HDF5 call
+ *  Create and throw an 'IllegalArgumentException'
+ *
+ *  Note:  This routine never returns from the 'throw',
+ *  and the Java native method immediately raises the
+ *  exception.
+ */
+jboolean h5indexOutOfBounds( JNIEnv *env, char *functName)
+{
+    jmethodID jm;
+    jclass jc;
+    char * args[2];
+    jobject ex;
+    jstring str;
+    int rval;
+
+#ifdef __cplusplus
+    jc = env->FindClass("java/lang/IndexOutOfBoundsException");
+#else
+    jc = (*env)->FindClass(env, "java/lang/IndexOutOfBoundsException");
+#endif
+    if (jc == NULL) {
+        return JNI_FALSE;
+    }
+#ifdef __cplusplus
+    jm = env->GetMethodID(jc, "<init>", "(Ljava/lang/String;)V");
+#else
+    jm = (*env)->GetMethodID(env, jc, "<init>", "(Ljava/lang/String;)V");
+#endif
+    if (jm == NULL) {
+        return JNI_FALSE;
+    }
+
+#ifdef __cplusplus
+    str = env->NewStringUTF(functName);
+#else
+    str = (*env)->NewStringUTF(env,functName);
+#endif
+    args[0] = (char *)str;
+    args[1] = 0;
+#ifdef __cplusplus
+    ex = env->NewObjectA ( jc, jm, (jvalue *)args );
+
+    rval = env->Throw((jthrowable) ex );
+#else
+    ex = (*env)->NewObjectA ( env, jc, jm, (jvalue *)args );
+
+    rval = (*env)->Throw(env, ex );
+#endif
+    if (rval < 0) {
+        fprintf(stderr, "FATAL ERROR:  BadArgument: Throw failed\n");
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/c/unix.c b/source/c/unix.c
new file mode 100644
index 0000000..1cfeef9
--- /dev/null
+++ b/source/c/unix.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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.
+ */
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <jni.h>
+
+/* Types of links. Keep in sync with Java enum. */
+#define REGULAR_FILE 0
+#define DIRECTORY 1
+#define SYMLINK 2
+#define OTHER 3
+
+#ifndef __STAT
+#define __STAT stat
+#endif
+
+#ifndef __LSTAT
+#define __LSTAT lstat
+#endif
+
+/* Global references. */
+jclass stringClass;
+jclass passwordClass;
+jmethodID passwordConstructorID;
+jclass groupClass;
+jmethodID groupConstructorID;
+jclass statClass;
+jmethodID statConstructorID;
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_init
+  (JNIEnv *env, jclass clss)
+{
+    stringClass = (*env)->FindClass(env, "java/lang/String");
+    if (stringClass == NULL) /* Really shouldn't happen, will throw NoClassDefFoundError. */
+    {
+        return -1;
+    }
+    stringClass = (*env)->NewGlobalRef(env, stringClass);
+    passwordClass = (*env)->FindClass(env, "ch/systemsx/cisd/base/unix/Unix$Password");
+    if (passwordClass == NULL) /* Really shouldn't happen, will throw NoClassDefFoundError. */
+    {
+        return -1;
+    }
+    passwordClass = (*env)->NewGlobalRef(env, passwordClass);
+    passwordConstructorID = (*env)->GetMethodID(env, passwordClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
+    if (passwordConstructorID == NULL) /* Really shouldn't happen, will throw NoSuchMethodError. */
+    {
+        return -1;
+    }
+    groupClass = (*env)->FindClass(env, "ch/systemsx/cisd/base/unix/Unix$Group");
+    if (groupClass == NULL) /* Really shouldn't happen, will throw NoClassDefFoundError. */
+    {
+        return -1;
+    }
+    groupClass = (*env)->NewGlobalRef(env, groupClass);
+    groupConstructorID = (*env)->GetMethodID(env, groupClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;I[Ljava/lang/String;)V");
+    if (groupConstructorID == NULL) /* Really shouldn't happen, will throw NoSuchMethodError. */
+    {
+        return -1;
+    }
+    statClass = (*env)->FindClass(env, "ch/systemsx/cisd/base/unix/Unix$Stat");
+    if (statClass == NULL) /* Really shouldn't happen, will throw NoClassDefFoundError. */
+    {
+        return -1;
+    }
+    statClass = (*env)->NewGlobalRef(env, statClass);
+    statConstructorID = (*env)->GetMethodID(env, statClass, "<init>", "(JJSBIIIJJJJJI)V");
+    if (groupConstructorID == NULL) /* Really shouldn't happen, will throw NoSuchMethodError. */
+    {
+        return -1;
+    }
+    return 0;
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_link
+  (JNIEnv *env, jclass clss, jstring filename, jstring linktarget)
+{
+    const char* pfilename;
+    const char* plinktarget;
+    int retval;
+
+    pfilename = (char *)(*env)->GetStringUTFChars(env, filename, NULL);
+    plinktarget = (char *)(*env)->GetStringUTFChars(env, linktarget, NULL);
+
+    retval = link(pfilename, plinktarget);
+    if (retval < 0)
+    {
+        retval = -errno;
+    }
+
+    (*env)->ReleaseStringUTFChars(env, filename, pfilename);
+    (*env)->ReleaseStringUTFChars(env, linktarget, plinktarget);
+
+   return retval;
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_symlink
+  (JNIEnv *env, jclass clss, jstring filename, jstring linktarget)
+{
+    const char* pfilename;
+    const char* plinktarget;
+    int retval;
+
+    pfilename = (char *)(*env)->GetStringUTFChars(env, filename, NULL);
+    plinktarget = (char *)(*env)->GetStringUTFChars(env, linktarget, NULL);
+
+    retval = symlink(pfilename, plinktarget);
+    if (retval < 0)    { 
+        retval = -errno; 
+    }
+
+    (*env)->ReleaseStringUTFChars(env, filename, pfilename);
+    (*env)->ReleaseStringUTFChars(env, linktarget, plinktarget);
+
+   return retval;
+}
+
+/* Function pointer for stat function calls. */
+typedef int (*stat_func_ptr)(const char *path, struct __STAT *buf);
+
+jobject call_stat(JNIEnv *env, jclass clss, jstring filename, stat_func_ptr statf)
+{
+    const char* pfilename;
+    struct __STAT s;
+    jobject result;
+    int retval;
+    jbyte type;
+
+    pfilename = (char *) (*env)->GetStringUTFChars(env, filename, NULL);
+    retval = statf(pfilename, &s);
+    (*env)->ReleaseStringUTFChars(env, filename, pfilename);
+    if (retval < 0)
+    {
+        return NULL;
+    } else
+    {
+        if (S_ISLNK(s.st_mode))
+        {
+            type = SYMLINK;
+        } else if (S_ISDIR(s.st_mode))
+        {
+            type = DIRECTORY;
+        } else if (S_ISREG(s.st_mode))
+        {
+            type = REGULAR_FILE;
+        } else
+        {
+            type = OTHER;
+        }
+        result = (*env)->NewObject(env, statClass, statConstructorID, (jlong) s.st_dev, (jlong) s.st_ino, 
+                   (jshort) (s.st_mode & 07777), (jbyte) type, (jint) s.st_nlink, 
+                   (jint) s.st_uid, (jint) s.st_gid, (jlong) s.st_atime, (jlong) s.st_mtime, 
+                   (jlong) s.st_ctime, (jlong) s.st_size, (jlong) s.st_blocks, (jint) s.st_blksize);
+        return result;
+    }
+}
+
+JNIEXPORT jobject JNICALL Java_ch_systemsx_cisd_base_unix_Unix_stat(JNIEnv *env, jclass clss, jstring filename)
+{
+    return call_stat(env, clss, filename, &__STAT);
+}
+
+JNIEXPORT jobject JNICALL Java_ch_systemsx_cisd_base_unix_Unix_lstat(JNIEnv *env, jclass clss, jstring filename)
+{
+    return call_stat(env, clss, filename, &__LSTAT);
+}
+
+JNIEXPORT jstring JNICALL Java_ch_systemsx_cisd_base_unix_Unix_readlink(JNIEnv *env, jclass clss, jstring linkname, jint linkvallen)
+{
+    const char* plinkname;
+    char plinkvalue[linkvallen + 1];
+    int retval;
+	
+    plinkname = (char *)(*env)->GetStringUTFChars(env, linkname, NULL);
+    retval = readlink(plinkname, plinkvalue, linkvallen);
+    (*env)->ReleaseStringUTFChars(env, linkname, plinkname);
+    if (retval < 0)
+    {
+		    return NULL;
+    } else
+    {
+        plinkvalue[linkvallen] = '\0';
+        return (*env)->NewStringUTF(env, plinkvalue);
+    }
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_chmod(JNIEnv *env, jclass clss, jstring linkname, jshort mode)
+{
+    const char* plinkname;
+    int retval;
+	
+    plinkname = (char *)(*env)->GetStringUTFChars(env, linkname, NULL);
+    retval = chmod(plinkname, mode);
+    (*env)->ReleaseStringUTFChars(env, linkname, plinkname);
+    if (retval < 0)
+    {
+		    return -errno;
+    } else
+    {
+        return 0;
+    }
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_chown(JNIEnv *env, jclass clss, jstring linkname, jint uid, jint gid)
+{
+    const char* plinkname;
+    int retval;
+	
+    plinkname = (char *)(*env)->GetStringUTFChars(env, linkname, NULL);
+    retval = chown(plinkname, uid, gid);
+    (*env)->ReleaseStringUTFChars(env, linkname, plinkname);
+    if (retval < 0)
+    {
+		    return -errno;
+    } else
+    {
+        return 0;
+    }
+}
+
+JNIEXPORT jstring JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getuser(JNIEnv *env, jclass clss, jint uid)
+{
+    struct passwd *pw;
+	
+    pw = getpwuid(uid);
+    if (pw == NULL)
+    {
+		    return NULL;
+    } else
+    {
+        return (*env)->NewStringUTF(env, pw->pw_name);
+    }
+}
+
+JNIEXPORT jstring JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getgroup(JNIEnv *env, jclass clss, jint gid)
+{
+    struct group *gp;
+	
+    gp = getgrgid(gid);
+    if (gp == NULL)
+    {
+		    return NULL;
+    } else
+    {
+        return (*env)->NewStringUTF(env, gp->gr_name);
+    }
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getuid__(JNIEnv *env, jclass clss)
+{
+    return getuid();
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_geteuid(JNIEnv *env, jclass clss)
+{
+    return geteuid();
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getuid__Ljava_lang_String_2(JNIEnv *env, jclass clss, jstring user)
+{
+    const char* puser;
+    struct passwd *pw;
+	
+    puser = (char *)(*env)->GetStringUTFChars(env, user, NULL);
+    pw = getpwnam(puser);
+    (*env)->ReleaseStringUTFChars(env, user, puser);
+    if (pw == NULL)
+    {
+		    return -errno;
+    } else
+    {
+        return pw->pw_uid;
+    }
+}
+
+JNIEXPORT jobject JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getpwnam(JNIEnv *env, jclass clss, jstring user)
+{
+    const char* puser;
+    struct passwd *pw;
+    jstring passwd;
+    jstring fullname;
+    jstring homedir;
+    jstring shell;
+    jobject result;
+	
+    puser = (char *)(*env)->GetStringUTFChars(env, user, NULL);
+    pw = getpwnam(puser);
+    (*env)->ReleaseStringUTFChars(env, user, puser);
+    if (pw == NULL)
+    {
+		    return NULL;
+    } else
+    {
+        passwd = (*env)->NewStringUTF(env, pw->pw_passwd);
+        fullname = (*env)->NewStringUTF(env, pw->pw_gecos);
+        homedir = (*env)->NewStringUTF(env, pw->pw_dir);
+        shell = (*env)->NewStringUTF(env, pw->pw_shell);
+        result = (*env)->NewObject(env, passwordClass, passwordConstructorID, user, passwd, pw->pw_uid, pw->pw_gid, fullname, homedir, shell);
+        return result;
+    }
+}
+
+JNIEXPORT jobject JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getpwuid(JNIEnv *env, jclass clss, jint uid)
+{
+    struct passwd *pw;
+    jstring user;
+    jstring passwd;
+    jstring fullname;
+    jstring homedir;
+    jstring shell;
+    jobject result;
+	
+    pw = getpwuid(uid);
+    if (pw == NULL)
+    {
+		    return NULL;
+    } else
+    {
+        user = (*env)->NewStringUTF(env, pw->pw_name);
+        passwd = (*env)->NewStringUTF(env, pw->pw_passwd);
+        fullname = (*env)->NewStringUTF(env, pw->pw_gecos);
+        homedir = (*env)->NewStringUTF(env, pw->pw_dir);
+        shell = (*env)->NewStringUTF(env, pw->pw_shell);
+        result = (*env)->NewObject(env, passwordClass, passwordConstructorID, user, passwd, pw->pw_uid, pw->pw_gid, fullname, homedir, shell);
+        return result;
+    }
+}
+
+JNIEXPORT jobjectArray JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getgrnam(JNIEnv *env, jclass clss, jstring group)
+{
+    const char* pgroup;
+    struct group *gr;
+    jstring grouppwd;
+    jobject result;
+    jobjectArray members;
+    int i;
+	
+    pgroup = (char *)(*env)->GetStringUTFChars(env, group, NULL);
+    gr = getgrnam(pgroup);
+    (*env)->ReleaseStringUTFChars(env, group, pgroup);
+    if (gr == NULL)
+    {
+		    return NULL;
+    } else
+    {
+        grouppwd = (*env)->NewStringUTF(env, gr->gr_passwd);
+        /* Count group members. */
+        for (i = 0; (gr->gr_mem)[i] != NULL; ++i);
+        members = (*env)->NewObjectArray(env, i, stringClass, NULL);
+        for (i = 0; (gr->gr_mem)[i] != NULL; ++i)
+        {
+            (*env)->SetObjectArrayElement(env, members, i, (*env)->NewStringUTF(env, (gr->gr_mem)[i]));
+        }
+        result = (*env)->NewObject(env, groupClass, groupConstructorID, group, grouppwd, gr->gr_gid, members); 
+        return result;
+    }
+}
+
+JNIEXPORT jobjectArray JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getgrgid(JNIEnv *env, jclass clss, jint gid)
+{
+    struct group *gr;
+    jstring group;
+    jstring grouppwd;
+    jobject result;
+    jobjectArray members;
+    int i;
+	
+    gr = getgrgid(gid);
+    if (gr == NULL)
+    {
+		    return NULL;
+    } else
+    {
+        group = (*env)->NewStringUTF(env, gr->gr_name);
+        grouppwd = (*env)->NewStringUTF(env, gr->gr_passwd);
+        /* Count group members. */
+        for (i = 0; (gr->gr_mem)[i] != NULL; ++i);
+        members = (*env)->NewObjectArray(env, i, stringClass, NULL);
+        for (i = 0; (gr->gr_mem)[i] != NULL; ++i)
+        {
+            (*env)->SetObjectArrayElement(env, members, i, (*env)->NewStringUTF(env, (gr->gr_mem)[i]));
+        }
+        result = (*env)->NewObject(env, groupClass, groupConstructorID, group, grouppwd, gr->gr_gid, members); 
+        return result;
+    }
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getgid__(JNIEnv *env, jclass clss)
+{
+    return getgid();
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getegid(JNIEnv *env, jclass clss)
+{
+    return getegid();
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getgid__Ljava_lang_String_2(JNIEnv *env, jclass clss, jstring group)
+{
+    const char* pgroup;
+    struct group *gr;
+	
+    pgroup = (char *)(*env)->GetStringUTFChars(env, group, NULL);
+    gr = getgrnam(pgroup);
+    (*env)->ReleaseStringUTFChars(env, group, pgroup);
+    if (gr == NULL)
+    {
+		    return -errno;
+    } else
+    {
+        return gr->gr_gid;
+    }
+}
+
+JNIEXPORT jint JNICALL Java_ch_systemsx_cisd_base_unix_Unix_getpid(JNIEnv *env, jclass clss)
+{
+    return getpid();
+}
+
+JNIEXPORT jstring JNICALL Java_ch_systemsx_cisd_base_unix_Unix_strerror__I(JNIEnv *env, jclass clss, jint errnum)
+{
+    return (*env)->NewStringUTF(env, strerror(errnum < 0 ? -errnum : errnum));
+}
+
+JNIEXPORT jstring JNICALL Java_ch_systemsx_cisd_base_unix_Unix_strerror__(JNIEnv *env, jclass clss)
+{
+    return (*env)->NewStringUTF(env, strerror(errno));
+}
diff --git a/source/java/ch/systemsx/cisd/base/BuildAndEnvironmentInfo.java b/source/java/ch/systemsx/cisd/base/BuildAndEnvironmentInfo.java
new file mode 100644
index 0000000..91a10b5
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/BuildAndEnvironmentInfo.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2009 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base;
+
+import ch.systemsx.cisd.base.utilities.AbstractBuildAndEnvironmentInfo;
+
+
+/**
+ * The build and environment information for cisd-base.
+ *
+ * @author Franz-Josef Elmer
+ */
+public class BuildAndEnvironmentInfo extends AbstractBuildAndEnvironmentInfo
+{
+    private final static String BASE = "base";
+    
+    public final static BuildAndEnvironmentInfo INSTANCE = new BuildAndEnvironmentInfo();
+    
+    private BuildAndEnvironmentInfo()
+    {
+        super(BASE);
+    }
+
+    /**
+     * Shows build and environment information on the console.
+     */
+    public static void main(String[] args)
+    {
+        System.out.println(INSTANCE);
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/annotation/JsonObject.java b/source/java/ch/systemsx/cisd/base/annotation/JsonObject.java
new file mode 100644
index 0000000..abf69e3
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/annotation/JsonObject.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation all JSON transfered classes should be marked with. It was originally created to
+ * replace @JsonTypeName annotation which was not visible in the documentation. With @JsonTypeName
+ * annotation it would be impossible for our users to find a logical type name of a class to be sent
+ * to JSON-RPC services.
+ * 
+ * @author pkupczyk
+ */
+ at Target(
+    { ElementType.TYPE })
+ at Retention(RetentionPolicy.RUNTIME)
+ at Documented
+public @interface JsonObject
+{
+    /**
+     * Logical type name for annotated type.
+     */
+    public String value();
+}
diff --git a/source/java/ch/systemsx/cisd/base/convert/NativeArrayEncoding.java b/source/java/ch/systemsx/cisd/base/convert/NativeArrayEncoding.java
new file mode 100644
index 0000000..e2bfa3d
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/convert/NativeArrayEncoding.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.convert;
+
+import ch.systemsx.cisd.base.convert.NativeData.ByteOrder;
+
+/**
+ * An enum for encoding array of numbers (integer or float) in native (host) format.
+ * 
+ * @author Bernd Rinn
+ */
+public enum NativeArrayEncoding
+{
+    INT8_NATIVE(false, (byte) 1, NativeData.ByteOrder.NATIVE),
+
+    INT16_LITTLE_ENDIAN(false, (byte) 2, NativeData.ByteOrder.LITTLE_ENDIAN),
+
+    INT32_LITTLE_ENDIAN(false, (byte) 4, NativeData.ByteOrder.LITTLE_ENDIAN),
+
+    INT64_LITTLE_ENDIAN(false, (byte) 8, NativeData.ByteOrder.LITTLE_ENDIAN),
+
+    INT16_BIG_ENDIAN(false, (byte) 2, NativeData.ByteOrder.BIG_ENDIAN),
+
+    INT32_BIG_ENDIAN(false, (byte) 4, NativeData.ByteOrder.BIG_ENDIAN),
+
+    INT64_BIG_ENDIAN(false, (byte) 8, NativeData.ByteOrder.BIG_ENDIAN),
+
+    FLOAT32_LITTLE_ENDIAN(true, (byte) 4, NativeData.ByteOrder.LITTLE_ENDIAN),
+
+    FLOAT64_LITTLE_ENDIAN(true, (byte) 8, NativeData.ByteOrder.LITTLE_ENDIAN),
+
+    FLOAT32_BIG_ENDIAN(true, (byte) 4, NativeData.ByteOrder.BIG_ENDIAN),
+
+    FLOAT64_BIG_ENDIAN(true, (byte) 8, NativeData.ByteOrder.BIG_ENDIAN),
+
+    ;
+
+    private static final int MIN_ENCODING_HEADER_SIZE = 8;
+
+    private static final int CHAR_N = 78;
+
+    private static final int CHAR_B = 66;
+
+    private static final int CHAR_L = 76;
+
+    private static final int CHAR_I = 73;
+
+    private static final int CHAR_F = 70;
+
+    private boolean floatingPoint;
+
+    private ByteOrder byteOrder;
+
+    private byte sizeInBytes;
+
+    private byte[] magic;
+
+    NativeArrayEncoding(boolean floatingPoint, byte sizeInBytes, NativeData.ByteOrder byteOrder)
+    {
+        this.floatingPoint = floatingPoint;
+        this.byteOrder = byteOrder;
+        this.sizeInBytes = sizeInBytes;
+        this.magic =
+                new byte[]
+                    {
+                            (byte) (floatingPoint ? CHAR_F : CHAR_I),
+                            (byte) ((byteOrder == ByteOrder.LITTLE_ENDIAN) ? CHAR_L
+                                    : (byteOrder == ByteOrder.BIG_ENDIAN) ? CHAR_B : CHAR_N),
+                            sizeInBytes };
+    }
+
+    /**
+     * Returns <code>true</code>, if the encoded array is a float array.
+     */
+    public boolean isFloatingPoint()
+    {
+        return floatingPoint;
+    }
+
+    /**
+     * Returns <code>true</code>, if the encoded array is an int array.
+     */
+    public boolean isInteger()
+    {
+        return floatingPoint == false;
+    }
+
+    /**
+     * Returns the byte order of the array.
+     */
+    public NativeData.ByteOrder getByteOrder()
+    {
+        return byteOrder;
+    }
+
+    /**
+     * Returns the size of one element in bytes.
+     */
+    public byte getSizeInBytes()
+    {
+        return sizeInBytes;
+    }
+
+    byte[] getMagic()
+    {
+        return magic;
+    }
+
+    static NativeArrayEncoding tryGetIntEncoding(ByteOrder byteOrder, byte sizeInBytes)
+    {
+        assert byteOrder != null;
+        if (sizeInBytes == 1 && byteOrder == ByteOrder.NATIVE)
+        {
+            return INT8_NATIVE;
+        } else if (sizeInBytes == 2)
+        {
+            return (byteOrder == ByteOrder.LITTLE_ENDIAN) ? INT16_LITTLE_ENDIAN : INT16_BIG_ENDIAN;
+        } else if (sizeInBytes == 4)
+        {
+            return (byteOrder == ByteOrder.LITTLE_ENDIAN) ? INT32_LITTLE_ENDIAN : INT32_BIG_ENDIAN;
+
+        } else if (sizeInBytes == 8)
+        {
+            return (byteOrder == ByteOrder.LITTLE_ENDIAN) ? INT64_LITTLE_ENDIAN : INT64_BIG_ENDIAN;
+        }
+        return null;
+    }
+
+    static NativeArrayEncoding tryGetFloatEncoding(ByteOrder byteOrder, byte sizeInBytes)
+    {
+        assert byteOrder != null;
+        if (sizeInBytes == 4)
+        {
+            return (byteOrder == ByteOrder.LITTLE_ENDIAN) ? FLOAT32_LITTLE_ENDIAN
+                    : FLOAT32_BIG_ENDIAN;
+        } else if (sizeInBytes == 8)
+        {
+            return (byteOrder == ByteOrder.LITTLE_ENDIAN) ? FLOAT64_LITTLE_ENDIAN
+                    : FLOAT64_BIG_ENDIAN;
+        }
+        return null;
+    }
+
+    /**
+     * Returns the encoding for the given <var>byteArr</var>, or <code>null</code>, if
+     * <var>byteArr</var> is not an encoded array.
+     */
+    public static NativeArrayEncoding tryGetEncoding(byte[] byteArr)
+    {
+        if (byteArr.length < MIN_ENCODING_HEADER_SIZE)
+        {
+            return null;
+        }
+        final ByteOrder byteOrder =
+                (byteArr[1] == CHAR_L) ? ByteOrder.LITTLE_ENDIAN
+                        : (byteArr[1] == CHAR_B) ? ByteOrder.BIG_ENDIAN : null;
+        if (byteOrder == null)
+        {
+            return null;
+        }
+        if (byteArr[0] == CHAR_F)
+        {
+            return tryGetFloatEncoding(byteOrder, byteArr[2]);
+        } else if (byteArr[0] == CHAR_I)
+        {
+            return tryGetIntEncoding(byteOrder, byteArr[2]);
+        }
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/source/java/ch/systemsx/cisd/base/convert/NativeData.java b/source/java/ch/systemsx/cisd/base/convert/NativeData.java
new file mode 100644
index 0000000..f962af5
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/convert/NativeData.java
@@ -0,0 +1,1086 @@
+/****************************************************************************
+ * NCSA HDF                                                                 *
+ * National Computational Science Alliance                                   *
+ * University of Illinois at Urbana-Champaign                               *
+ * 605 E. Springfield, Champaign IL 61820                                   *
+ *                                                                          *
+ * Center for Information Sciences and Databases, ETH Zurich, Switzerland   *
+ *                                                                          *
+ * For conditions of distribution and use, see the accompanying             *
+ * COPYING file.                                                            *
+ *                                                                          *
+ ****************************************************************************/
+
+package ch.systemsx.cisd.base.convert;
+
+import java.nio.ByteBuffer;
+
+import ch.systemsx.cisd.base.utilities.NativeLibraryUtilities;
+
+/**
+ * This class encapsulates native methods to deal with arrays of numbers, converting from numbers to
+ * bytes and bytes to numbers.
+ * <p>
+ * These routines are used by class <b>HDFArray</b> to pass data to and from the HDF5 library.
+ * <p>
+ * Methods copyXxxToByte() convert a Java array of primitive numbers (int, short, ...) to a Java
+ * array of bytes. Methods copyByteToXxx() convert from a Java array of bytes into a Java array of
+ * primitive numbers (int, short, ...)
+ * <p>
+ * Variant interfaces convert only a sub-array.
+ * <p>
+ * The class has optimized methods using jni-libraries for some common platforms and a pure-java
+ * implementation (called <i>javamode</i> if the jni-libraries are not available). If you want to
+ * enforce <i>javamode</i>, you need to pass the property <code>nativedata.javamode=true</code> to
+ * the JRE.
+ */
+public class NativeData
+{
+    private static final boolean useNativeLib;
+
+    static
+    {
+        if (Boolean.getBoolean("nativedata.javamode"))
+        {
+            useNativeLib = false;
+        } else
+        {
+            useNativeLib = NativeLibraryUtilities.loadNativeLibrary("nativedata");
+        }
+    }
+
+    /** Size of a <code>short</code> value in <code>byte</code>s. */
+    public final static int SHORT_SIZE = 2;
+
+    /** Size of a <code>char</code> value in <code>byte</code>s. */
+    public final static int CHAR_SIZE = 2;
+
+    /** Size of an <code>int</code> value in <code>byte</code>s. */
+    public final static int INT_SIZE = 4;
+
+    /** Size of a <code>long</code> value in <code>byte</code>s. */
+    public final static int LONG_SIZE = 8;
+
+    /** Size of a <code>float</code> value in <code>byte</code>s. */
+    public final static int FLOAT_SIZE = 4;
+
+    /** Size of a <code>double</code> value in <code>byte</code>s. */
+    public final static int DOUBLE_SIZE = 8;
+
+    /** Byte Order enumeration. */
+    // Implementation note: the ordinal of the entries needs to be understood by the native methods
+    public enum ByteOrder
+    {
+        /** <code>byte[]</code> is in native byte order (that is: don't change byte order) */
+        NATIVE(java.nio.ByteOrder.nativeOrder()),
+        /** <code>byte[]</code> is in little endian byte order */
+        LITTLE_ENDIAN(java.nio.ByteOrder.LITTLE_ENDIAN),
+        /** <code>byte[]</code> is in big endian byte order */
+        BIG_ENDIAN(java.nio.ByteOrder.BIG_ENDIAN);
+
+        private final java.nio.ByteOrder nioByteOrder;
+
+        ByteOrder(java.nio.ByteOrder nioByteOrder)
+        {
+            this.nioByteOrder = nioByteOrder;
+        }
+
+        java.nio.ByteOrder getNioByteOrder()
+        {
+            return nioByteOrder;
+        }
+
+        static ByteOrder getNativeByteOrder()
+        {
+            return NATIVE.nioByteOrder.equals(LITTLE_ENDIAN.nioByteOrder) ? LITTLE_ENDIAN
+                    : BIG_ENDIAN;
+        }
+    }
+
+    /**
+     * Returns <code>true</code> if this platform is a little-endian platform and <code>false</code>
+     * , if it is a big-endian platform.
+     */
+    private static native boolean isLittleEndian();
+
+    /**
+     * Copies a range from an array of <code>int</code> into an array of <code>byte</code>.
+     * 
+     * @param inData The input array of <code>int</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>int</code> to
+     *            start
+     * @param outData The output array of <code>byte</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+     *            start
+     * @param len The number of <code>int</code> to copy
+     * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+     *            <var>outData</var> should be in.
+     */
+    private static native void copyIntToByte(int[] inData, int inStart, byte[] outData,
+            int outStart, int len, int byteOrder);
+
+    /**
+     * Copies a range from an array of <code>byte</code> into an array of <code>int</code>.
+     * 
+     * @param inData The input array of <code>byte</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+     *            start
+     * @param outData The output array of <code>int</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>int</code> to
+     *            start
+     * @param len The number of <code>int</code> to copy
+     * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+     *            <var>outData</var> should be in.
+     */
+    private static native void copyByteToInt(byte[] inData, int inStart, int[] outData,
+            int outStart, int len, int byteOrder);
+
+    /**
+     * Copies a range from an array of <code>long</code> into an array of <code>byte</code>.
+     * 
+     * @param inData The input array of <code>long</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>long</code> to
+     *            start
+     * @param outData The output array of <code>byte</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+     *            start
+     * @param len The number of <code>long</code> to copy
+     * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+     *            <var>outData</var> should be in.
+     */
+    private static native void copyLongToByte(long[] inData, int inStart, byte[] outData,
+            int outStart, int len, int byteOrder);
+
+    /**
+     * Copies a range from an array of <code>byte</code> into an array of <code>long</code>.
+     * 
+     * @param inData The input array of <code>byte</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+     *            start
+     * @param outData The output array of <code>long</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>long</code> to
+     *            start
+     * @param len The number of <code>long</code> to copy
+     * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+     *            <var>outData</var> should be in.
+     */
+    private static native void copyByteToLong(byte[] inData, int inStart, long[] outData,
+            int outStart, int len, int byteOrder);
+
+    /**
+     * Copies a range from an array of <code>short</code> into an array of <code>byte</code>.
+     * 
+     * @param inData The input array of <code>short</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>short</code> to
+     *            start
+     * @param outData The output array of <code>byte</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+     *            start
+     * @param len The number of <code>short</code> to copy
+     * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+     *            <var>outData</var> should be in.
+     */
+    private static native void copyShortToByte(short[] inData, int inStart, byte[] outData,
+            int outStart, int len, int byteOrder);
+
+    /**
+     * Copies a range from an array of <code>byte</code> into an array of <code>short</code>.
+     * 
+     * @param inData The input array of <code>byte</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+     *            start
+     * @param outData The output array of <code>short</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>short</code> to
+     *            start
+     * @param len The number of <code>short</code> to copy
+     * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+     *            <var>outData</var> should be in.
+     */
+    private static native void copyByteToShort(byte[] inData, int inStart, short[] outData,
+            int outStart, int len, int byteOrder);
+
+    /**
+     * Copies a range from an array of <code>char</code> into an array of <code>byte</code>.
+     * 
+     * @param inData The input array of <code>char</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>char</code> to
+     *            start
+     * @param outData The output array of <code>byte</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+     *            start
+     * @param len The number of <code>char</code> to copy
+     * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+     *            <var>outData</var> should be in.
+     */
+    private static native void copyCharToByte(char[] inData, int inStart, byte[] outData,
+            int outStart, int len, int byteOrder);
+
+    /**
+     * Copies a range from an array of <code>byte</code> into an array of <code>char</code>.
+     * 
+     * @param inData The input array of <code>byte</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+     *            start
+     * @param outData The output array of <code>char</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>char</code> to
+     *            start
+     * @param len The number of <code>char</code> to copy
+     * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+     *            <var>outData</var> should be in.
+     */
+    private static native void copyByteToChar(byte[] inData, int inStart, char[] outData,
+            int outStart, int len, int byteOrder);
+
+    /**
+     * Copies a range from an array of <code>float</code> into an array of <code>byte</code>.
+     * 
+     * @param inData The input array of <code>float</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>float</code> to
+     *            start
+     * @param outData The output array of <code>byte</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+     *            start
+     * @param len The number of <code>float</code> to copy
+     * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+     *            <var>outData</var> should be in.
+     */
+    private static native void copyFloatToByte(float[] inData, int inStart, byte[] outData,
+            int outStart, int len, int byteOrder);
+
+    /**
+     * Copies a range from an array of <code>byte</code> into an array of <code>float</code>.
+     * 
+     * @param inData The input array of <code>byte</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+     *            start
+     * @param outData The output array of <code>float</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>float</code> to
+     *            start
+     * @param len The number of <code>float</code> to copy
+     * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+     *            <var>outData</var> should be in.
+     */
+    private static native void copyByteToFloat(byte[] inData, int inStart, float[] outData,
+            int outStart, int len, int byteOrder);
+
+    /**
+     * Copies a range from an array of <code>double</code> into an array of <code>byte</code>.
+     * 
+     * @param inData The input array of <code>double</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>double</code> to
+     *            start
+     * @param outData The output array of <code>byte</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+     *            start
+     * @param len The number of <code>double</code> to copy
+     * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+     *            <var>outData</var> should be in.
+     */
+    private static native void copyDoubleToByte(double[] inData, int inStart, byte[] outData,
+            int outStart, int len, int byteOrder);
+
+    /**
+     * Copies a range from an array of <code>byte</code> into an array of <code>double</code>.
+     * 
+     * @param inData The input array of <code>byte</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+     *            start
+     * @param outData The output array of <code>double</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>double</code> to
+     *            start
+     * @param len The number of <code>double</code> to copy
+     * @param byteOrder The ordinal of {@link ByteOrder}, encoding what byte order the
+     *            <var>outData</var> should be in.
+     */
+    private static native void copyByteToDouble(byte[] inData, int inStart, double[] outData,
+            int outStart, int len, int byteOrder);
+
+    //
+    // Public
+    //
+
+    /** Call to ensure that the native library is loaded. */
+    public static void ensureNativeLibIsLoaded()
+    {
+    }
+
+    /**
+     * Returns <code>true</code>, if this class uses the native library and <code>false</code>
+     * otherwise.
+     */
+    public static boolean isUseNativeLib()
+    {
+        return useNativeLib;
+    }
+
+    /**
+     * Returns the native byte order of the host running this JRE.
+     */
+    public static ByteOrder getNativeByteOrder()
+    {
+        return ByteOrder.getNativeByteOrder();
+    }
+
+    /**
+     * Changes the byte order of the bytes constituting <var>s</var>.
+     */
+    public static short changeByteOrder(short s)
+    {
+        return (short) ((s << 8) | ((s >> 8) & 0xff));
+    }
+
+    /**
+     * Changes the byte order of the bytes constituting <var>c</var>.
+     */
+    public static char changeByteOrder(char c)
+    {
+        return (char) ((c << 8) | ((c >> 8) & 0xff));
+    }
+
+    /**
+     * Changes the byte order of the bytes constituting <var>i</var>.
+     */
+    public static int changeByteOrder(int i)
+    {
+        return ((changeByteOrder((short) i) << 16) | (changeByteOrder((short) (i >> 16)) & 0xffff));
+    }
+
+    /**
+     * Changes the byte order of the bytes constituting <var>f</var>.
+     */
+    public static float changeByteOrder(float f)
+    {
+        return Float.intBitsToFloat(changeByteOrder(Float.floatToRawIntBits(f)));
+    }
+
+    /**
+     * Changes the byte order of the bytes constituting <var>l</var>.
+     */
+    public static long changeByteOrder(long l)
+    {
+        return (((long) changeByteOrder((int) (l)) << 32) | (changeByteOrder((int) (l >> 32)) & 0xffffffffL));
+    }
+
+    /**
+     * Changes the byte order of the bytes constituting <var>d</var>.
+     */
+    public static double changeByteOrder(double d)
+    {
+        return Double.longBitsToDouble(changeByteOrder(Double.doubleToRawLongBits(d)));
+    }
+
+    /**
+     * Copies a range from an array of <code>int</code> into an array of <code>byte</code>.
+     * 
+     * @param inData The input array of <code>int</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>int</code> to
+     *            start
+     * @param outData The output array of <code>byte</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+     *            start
+     * @param len The number of <code>int</code> to copy
+     * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+     *            should be in.
+     */
+    public static void copyIntToByte(int[] inData, int inStart, byte[] outData, int outStart,
+            int len, ByteOrder byteOrder)
+    {
+        if (useNativeLib)
+        {
+            copyIntToByte(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+        } else
+        {
+            final ByteBuffer bb = ByteBuffer.wrap(outData, outStart, len * INT_SIZE);
+            bb.order(byteOrder.getNioByteOrder());
+            bb.asIntBuffer().put(inData, inStart, len);
+        }
+    }
+
+    /**
+     * Copies a range from an array of <code>byte</code> into an array of <code>int</code>.
+     * 
+     * @param inData The input array of <code>byte</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+     *            start
+     * @param outData The output array of <code>int</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>int</code> to
+     *            start
+     * @param len The number of <code>int</code> to copy
+     * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+     *            should be in.
+     */
+    public static void copyByteToInt(byte[] inData, int inStart, int[] outData, int outStart,
+            int len, ByteOrder byteOrder)
+    {
+        if (useNativeLib)
+        {
+            copyByteToInt(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+        } else
+        {
+            final ByteBuffer bb = ByteBuffer.wrap(inData, inStart, len * INT_SIZE);
+            bb.order(byteOrder.getNioByteOrder());
+            bb.asIntBuffer().get(outData, outStart, len);
+        }
+    }
+
+    /**
+     * Copies a range from an array of <code>long</code> into an array of <code>byte</code>.
+     * 
+     * @param inData The input array of <code>long</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>long</code> to
+     *            start
+     * @param outData The output array of <code>byte</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+     *            start
+     * @param len The number of <code>long</code> to copy
+     * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+     *            should be in.
+     */
+    public static void copyLongToByte(long[] inData, int inStart, byte[] outData, int outStart,
+            int len, ByteOrder byteOrder)
+    {
+        if (useNativeLib)
+        {
+            copyLongToByte(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+        } else
+        {
+            final ByteBuffer bb = ByteBuffer.wrap(outData, outStart, len * LONG_SIZE);
+            bb.order(byteOrder.getNioByteOrder());
+            bb.asLongBuffer().put(inData, inStart, len);
+        }
+    }
+
+    /**
+     * Copies a range from an array of <code>byte</code> into an array of <code>long</code>.
+     * 
+     * @param inData The input array of <code>byte</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+     *            start
+     * @param outData The output array of <code>long</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>long</code> to
+     *            start
+     * @param len The number of <code>long</code> to copy
+     * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+     *            should be in.
+     */
+    public static void copyByteToLong(byte[] inData, int inStart, long[] outData, int outStart,
+            int len, ByteOrder byteOrder)
+    {
+        if (useNativeLib)
+        {
+            copyByteToLong(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+        } else
+        {
+            final ByteBuffer bb = ByteBuffer.wrap(inData, inStart, len * LONG_SIZE);
+            bb.order(byteOrder.getNioByteOrder());
+            bb.asLongBuffer().get(outData, outStart, len);
+        }
+    }
+
+    /**
+     * Copies a range from an array of <code>short</code> into an array of <code>byte</code>.
+     * 
+     * @param inData The input array of <code>short</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>short</code> to
+     *            start
+     * @param outData The output array of <code>byte</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+     *            start
+     * @param len The number of <code>short</code> to copy
+     * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+     *            should be in.
+     */
+    public static void copyShortToByte(short[] inData, int inStart, byte[] outData, int outStart,
+            int len, ByteOrder byteOrder)
+    {
+        if (useNativeLib)
+        {
+            copyShortToByte(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+        } else
+        {
+            final ByteBuffer bb = ByteBuffer.wrap(outData, outStart, len * SHORT_SIZE);
+            bb.order(byteOrder.getNioByteOrder());
+            bb.asShortBuffer().put(inData, inStart, len);
+        }
+    }
+
+    /**
+     * Copies a range from an array of <code>char</code> into an array of <code>byte</code>.
+     * 
+     * @param inData The input array of <code>char</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>char</code> to
+     *            start
+     * @param outData The output array of <code>byte</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+     *            start
+     * @param len The number of <code>char</code> to copy
+     * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+     *            should be in.
+     */
+    public static void copyCharToByte(char[] inData, int inStart, byte[] outData, int outStart,
+            int len, ByteOrder byteOrder)
+    {
+        if (useNativeLib)
+        {
+            copyCharToByte(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+        } else
+        {
+            final ByteBuffer bb = ByteBuffer.wrap(outData, outStart, len * SHORT_SIZE);
+            bb.order(byteOrder.getNioByteOrder());
+            bb.asCharBuffer().put(inData, inStart, len);
+        }
+    }
+
+    /**
+     * Copies a range from an array of <code>byte</code> into an array of <code>short</code>.
+     * 
+     * @param inData The input array of <code>byte</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+     *            start
+     * @param outData The output array of <code>short</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>short</code> to
+     *            start
+     * @param len The number of <code>short</code> to copy
+     * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+     *            should be in.
+     */
+    public static void copyByteToShort(byte[] inData, int inStart, short[] outData, int outStart,
+            int len, ByteOrder byteOrder)
+    {
+        if (useNativeLib)
+        {
+            copyByteToShort(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+        } else
+        {
+            final ByteBuffer bb = ByteBuffer.wrap(inData, inStart, len * SHORT_SIZE);
+            bb.order(byteOrder.getNioByteOrder());
+            bb.asShortBuffer().get(outData, outStart, len);
+        }
+    }
+
+    /**
+     * Copies a range from an array of <code>byte</code> into an array of <code>char</code>.
+     * 
+     * @param inData The input array of <code>byte</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+     *            start
+     * @param outData The output array of <code>short</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>short</code> to
+     *            start
+     * @param len The number of <code>short</code> to copy
+     * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+     *            should be in.
+     */
+    public static void copyByteToChar(byte[] inData, int inStart, char[] outData, int outStart,
+            int len, ByteOrder byteOrder)
+    {
+        if (useNativeLib)
+        {
+            copyByteToChar(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+        } else
+        {
+            final ByteBuffer bb = ByteBuffer.wrap(inData, inStart, len * CHAR_SIZE);
+            bb.order(byteOrder.getNioByteOrder());
+            bb.asCharBuffer().get(outData, outStart, len);
+        }
+    }
+
+    /**
+     * Copies a range from an array of <code>float</code> into an array of <code>byte</code>.
+     * 
+     * @param inData The input array of <code>float</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>float</code> to
+     *            start
+     * @param outData The output array of <code>byte</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+     *            start
+     * @param len The number of <code>float</code> to copy
+     * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+     *            should be in.
+     */
+    public static void copyFloatToByte(float[] inData, int inStart, byte[] outData, int outStart,
+            int len, ByteOrder byteOrder)
+    {
+        if (useNativeLib)
+        {
+            copyFloatToByte(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+        } else
+        {
+            final ByteBuffer bb = ByteBuffer.wrap(outData, outStart, len * FLOAT_SIZE);
+            bb.order(byteOrder.getNioByteOrder());
+            bb.asFloatBuffer().put(inData, inStart, len);
+        }
+    }
+
+    /**
+     * Copies a range from an array of <code>byte</code> into an array of <code>float</code>.
+     * 
+     * @param inData The input array of <code>byte</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+     *            start
+     * @param outData The output array of <code>float</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>float</code> to
+     *            start
+     * @param len The number of <code>float</code> to copy
+     * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+     *            should be in.
+     */
+    public static void copyByteToFloat(byte[] inData, int inStart, float[] outData, int outStart,
+            int len, ByteOrder byteOrder)
+    {
+        if (useNativeLib)
+        {
+            copyByteToFloat(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+        } else
+        {
+            final ByteBuffer bb = ByteBuffer.wrap(inData, inStart, len * FLOAT_SIZE);
+            bb.order(byteOrder.getNioByteOrder());
+            bb.asFloatBuffer().get(outData, outStart, len);
+        }
+    }
+
+    /**
+     * Copies a range from an array of <code>double</code> into an array of <code>byte</code>.
+     * 
+     * @param inData The input array of <code>double</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>double</code> to
+     *            start
+     * @param outData The output array of <code>byte</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>byte</code> to
+     *            start
+     * @param len The number of <code>double</code> to copy
+     * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+     *            should be in.
+     */
+    public static void copyDoubleToByte(double[] inData, int inStart, byte[] outData, int outStart,
+            int len, ByteOrder byteOrder)
+    {
+        if (useNativeLib)
+        {
+            copyDoubleToByte(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+        } else
+        {
+            final ByteBuffer bb = ByteBuffer.wrap(outData, outStart, len * DOUBLE_SIZE);
+            bb.order(byteOrder.getNioByteOrder());
+            bb.asDoubleBuffer().put(inData, inStart, len);
+        }
+    }
+
+    /**
+     * Copies a range from an array of <code>byte</code> into an array of <code>double</code>.
+     * 
+     * @param inData The input array of <code>byte</code> values.
+     * @param inStart The position in the input array <code>inData</code> of <code>byte</code> to
+     *            start
+     * @param outData The output array of <code>double</code> values.
+     * @param outStart The start in the output array <code>byteData</code> of <code>double</code> to
+     *            start
+     * @param len The number of <code>double</code> to copy
+     * @param byteOrder The {@link ByteOrder}, encoding what byte order the <var>outData</var>
+     *            should be in.
+     */
+    public static void copyByteToDouble(byte[] inData, int inStart, double[] outData, int outStart,
+            int len, ByteOrder byteOrder)
+    {
+        if (useNativeLib)
+        {
+            copyByteToDouble(inData, inStart, outData, outStart, len, byteOrder.ordinal());
+        } else
+        {
+            final ByteBuffer bb = ByteBuffer.wrap(inData, inStart, len * DOUBLE_SIZE);
+            bb.order(byteOrder.getNioByteOrder());
+            bb.asDoubleBuffer().get(outData, outStart, len);
+        }
+    }
+
+    /**
+     * Converts a <code>byte[]</code> array into a <code>char[]</code> array.
+     * 
+     * @param byteArr The <code>byte[]</code> to convert.
+     * @param byteOrder The byte order of <var>byteArr</var>.
+     * @param start The position in the <var>byteArr</var> to start the conversion.
+     * @param len The number of <code>short</code> values to convert.
+     * @return The <code>char[]</code> array.
+     */
+    public static char[] byteToChar(byte[] byteArr, ByteOrder byteOrder, int start, int len)
+    {
+        final char[] array = new char[len];
+        copyByteToChar(byteArr, start, array, 0, len, byteOrder);
+        return array;
+    }
+
+    /**
+     * Converts a <code>byte[]</code> array into a <code>char[]</code> array.
+     * 
+     * @param byteArr The <code>byte[]</code> to convert.
+     * @param byteOrder The byte order of <var>byteArr</var>.
+     * @return The <code>char[]</code> array.
+     */
+    public static char[] byteToChar(byte[] byteArr, ByteOrder byteOrder)
+    {
+        if (byteArr.length % CHAR_SIZE != 0)
+        {
+            throw new IllegalArgumentException("Length of byteArr does not match size of data type");
+        }
+        final int len = byteArr.length / SHORT_SIZE;
+        final char[] array = new char[len];
+        copyByteToChar(byteArr, 0, array, 0, len, byteOrder);
+        return array;
+    }
+
+    /**
+     * Converts a <code>byte[]</code> array into a <code>short[]</code> array.
+     * 
+     * @param byteArr The <code>byte[]</code> to convert.
+     * @param byteOrder The byte order of <var>byteArr</var>.
+     * @param start The position in the <var>byteArr</var> to start the conversion.
+     * @param len The number of <code>short</code> values to convert.
+     * @return The <code>short[]</code> array.
+     */
+    public static short[] byteToShort(byte[] byteArr, ByteOrder byteOrder, int start, int len)
+    {
+        final short[] array = new short[len];
+        copyByteToShort(byteArr, start, array, 0, len, byteOrder);
+        return array;
+    }
+
+    /**
+     * Converts a <code>byte[]</code> array into a <code>short[]</code> array.
+     * 
+     * @param byteArr The <code>byte[]</code> to convert.
+     * @param byteOrder The byte order of <var>byteArr</var>.
+     * @return The <code>short[]</code> array.
+     */
+    public static short[] byteToShort(byte[] byteArr, ByteOrder byteOrder)
+    {
+        if (byteArr.length % SHORT_SIZE != 0)
+        {
+            throw new IllegalArgumentException("Length of byteArr does not match size of data type");
+        }
+        final int len = byteArr.length / SHORT_SIZE;
+        final short[] array = new short[len];
+        copyByteToShort(byteArr, 0, array, 0, len, byteOrder);
+        return array;
+    }
+
+    /**
+     * Converts a <code>short[]</code> array to a <code>byte[]</code> array.
+     * 
+     * @param data The array to convert.
+     * @param byteOrder The byte order of the returned <code>byte[]</code>.
+     * @param start The position in <var>data</var> to start the conversion.
+     * @param len The number of <code>short</code> values to convert.
+     * @return The converted <code>byte[]</code> array.
+     */
+    public static byte[] shortToByte(short[] data, ByteOrder byteOrder, int start, int len)
+    {
+        final byte[] byteArr = new byte[SHORT_SIZE * len];
+        copyShortToByte(data, start, byteArr, 0, len, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Converts a <code>short[]</code> array to a <code>byte[]</code> array.
+     * 
+     * @param data The array to convert.
+     * @param byteOrder The byte order of the returned <code>byte[]</code>.
+     * @return The converted <code>byte[]</code> array.
+     */
+    public static byte[] shortToByte(short[] data, ByteOrder byteOrder)
+    {
+        final byte[] byteArr = new byte[SHORT_SIZE * data.length];
+        copyShortToByte(data, 0, byteArr, 0, data.length, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Converts a <code>char[]</code> array to a <code>byte[]</code> array.
+     * 
+     * @param data The array to convert.
+     * @param byteOrder The byte order of the returned <code>byte[]</code>.
+     * @param start The position in <var>data</var> to start the conversion.
+     * @param len The number of <code>char</code> values to convert.
+     * @return The converted <code>byte[]</code> array.
+     */
+    public static byte[] charToByte(char[] data, ByteOrder byteOrder, int start, int len)
+    {
+        final byte[] byteArr = new byte[CHAR_SIZE * len];
+        copyCharToByte(data, start, byteArr, 0, len, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Converts a <code>char[]</code> array to a <code>byte[]</code> array.
+     * 
+     * @param data The array to convert.
+     * @param byteOrder The byte order of the returned <code>byte[]</code>.
+     * @return The converted <code>byte[]</code> array.
+     */
+    public static byte[] charToByte(char[] data, ByteOrder byteOrder)
+    {
+        final byte[] byteArr = new byte[CHAR_SIZE * data.length];
+        copyCharToByte(data, 0, byteArr, 0, data.length, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Converts a <code>byte[]</code> array into an <code>int[]</code> array.
+     * 
+     * @param byteArr The <code>byte[]</code> to convert.
+     * @param byteOrder The byte order of <var>byteArr</var>.
+     * @param start The position in the <var>byteArr</var> to start the conversion.
+     * @param len The number of <code>int</code> values to convert.
+     * @return The <code>int[]</code> array.
+     */
+    public static int[] byteToInt(byte[] byteArr, ByteOrder byteOrder, int start, int len)
+    {
+        final int[] array = new int[len];
+        copyByteToInt(byteArr, start, array, 0, len, byteOrder);
+        return array;
+    }
+
+    /**
+     * Converts a <code>byte[]</code> array into an <code>int[]</code> array.
+     * 
+     * @param byteArr The <code>byte[]</code> to convert.
+     * @param byteOrder The byte order of <var>byteArr</var>.
+     * @return The <code>int[]</code> array.
+     */
+    public static int[] byteToInt(byte[] byteArr, ByteOrder byteOrder)
+    {
+        if (byteArr.length % INT_SIZE != 0)
+        {
+            throw new IllegalArgumentException("Length of byteArr does not match size of data type");
+        }
+        final int len = byteArr.length / INT_SIZE;
+        final int[] array = new int[len];
+        copyByteToInt(byteArr, 0, array, 0, len, byteOrder);
+        return array;
+    }
+
+    /**
+     * Converts a <code>int[]</code> array to a <code>byte[]</code> array.
+     * 
+     * @param data The array to convert.
+     * @param byteOrder The byte order of the returned <code>byte[]</code>.
+     * @param start The position in <var>data</var> to start the conversion.
+     * @param len The number of <code>int</code> values to convert.
+     * @return The converted <code>byte[]</code> array.
+     */
+    public static byte[] intToByte(int[] data, ByteOrder byteOrder, int start, int len)
+    {
+        final byte[] byteArr = new byte[INT_SIZE * len];
+        copyIntToByte(data, start, byteArr, 0, len, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Converts a <code>int[]</code> array to a <code>byte[]</code> array.
+     * 
+     * @param data The array to convert.
+     * @param byteOrder The byte order of the returned <code>byte[]</code>.
+     * @return The converted <code>byte[]</code> array.
+     */
+    public static byte[] intToByte(int[] data, ByteOrder byteOrder)
+    {
+        final byte[] byteArr = new byte[INT_SIZE * data.length];
+        copyIntToByte(data, 0, byteArr, 0, data.length, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Converts a <code>byte[]</code> array into a <code>long[]</code> array.
+     * 
+     * @param byteArr The <code>byte[]</code> to convert.
+     * @param byteOrder The byte order of <var>byteArr</var>.
+     * @param start The position in the <var>byteArr</var> to start the conversion.
+     * @param len The number of <code>long</code> values to convert.
+     * @return The <code>long[]</code> array.
+     */
+    public static long[] byteToLong(byte[] byteArr, ByteOrder byteOrder, int start, int len)
+    {
+        final long[] array = new long[len];
+        copyByteToLong(byteArr, start, array, 0, len, byteOrder);
+        return array;
+    }
+
+    /**
+     * Converts a <code>byte[]</code> array into a <code>long[]</code> array.
+     * 
+     * @param byteArr The <code>byte[]</code> to convert.
+     * @param byteOrder The byte order of <var>byteArr</var>.
+     * @return The <code>long[]</code> array.
+     */
+    public static long[] byteToLong(byte[] byteArr, ByteOrder byteOrder)
+    {
+        if (byteArr.length % LONG_SIZE != 0)
+        {
+            throw new IllegalArgumentException("Length of byteArr does not match size of data type");
+        }
+        final int len = byteArr.length / LONG_SIZE;
+        final long[] array = new long[len];
+        copyByteToLong(byteArr, 0, array, 0, len, byteOrder);
+        return array;
+    }
+
+    /**
+     * Converts a <code>long[]</code> array to a <code>byte[]</code> array.
+     * 
+     * @param data The array to convert.
+     * @param byteOrder The byte order of the returned <code>byte[]</code>.
+     * @param start The position in <var>data</var> to start the conversion.
+     * @param len The number of <code>long</code> values to convert.
+     * @return The converted <code>byte[]</code> array.
+     */
+    public static byte[] longToByte(long[] data, ByteOrder byteOrder, int start, int len)
+    {
+        final byte[] byteArr = new byte[LONG_SIZE * len];
+        copyLongToByte(data, start, byteArr, 0, len, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Converts a <code>long[]</code> array to a <code>byte[]</code> array.
+     * 
+     * @param data The array to convert.
+     * @param byteOrder The byte order of the returned <code>byte[]</code>.
+     * @return The converted <code>byte[]</code> array.
+     */
+    public static byte[] longToByte(long[] data, ByteOrder byteOrder)
+    {
+        final byte[] byteArr = new byte[LONG_SIZE * data.length];
+        copyLongToByte(data, 0, byteArr, 0, data.length, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Converts a <code>byte[]</code> array into a <code>float[]</code> array.
+     * 
+     * @param byteArr The <code>byte[]</code> to convert.
+     * @param byteOrder The byte order of <var>byteArr</var>.
+     * @param start The position in the <var>byteArr</var> to start the conversion.
+     * @param len The number of <code>float</code> values to convert.
+     * @return The <code>float[]</code> array.
+     */
+    public static float[] byteToFloat(byte[] byteArr, ByteOrder byteOrder, int start, int len)
+    {
+        final float[] array = new float[len];
+        copyByteToFloat(byteArr, start, array, 0, len, byteOrder);
+        return array;
+    }
+
+    /**
+     * Converts a <code>byte[]</code> array into a <code>float[]</code> array.
+     * 
+     * @param byteArr The <code>byte[]</code> to convert.
+     * @param byteOrder The byte order of <var>byteArr</var>.
+     * @return The <code>float[]</code> array.
+     */
+    public static float[] byteToFloat(byte[] byteArr, ByteOrder byteOrder)
+    {
+        if (byteArr.length % FLOAT_SIZE != 0)
+        {
+            throw new IllegalArgumentException("Length of byteArr does not match size of data type");
+        }
+        final int len = byteArr.length / FLOAT_SIZE;
+        final float[] array = new float[len];
+        copyByteToFloat(byteArr, 0, array, 0, len, byteOrder);
+        return array;
+    }
+
+    /**
+     * Converts a <code>float[]</code> array to a <code>byte[]</code> array.
+     * 
+     * @param data The array to convert.
+     * @param byteOrder The byte order of the returned <code>byte[]</code>.
+     * @param start The position in <var>data</var> to start the conversion.
+     * @param len The number of <code>float</code> values to convert.
+     * @return The converted <code>byte[]</code> array.
+     */
+    public static byte[] floatToByte(float[] data, ByteOrder byteOrder, int start, int len)
+    {
+        final byte[] byteArr = new byte[FLOAT_SIZE * len];
+        copyFloatToByte(data, start, byteArr, 0, len, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Converts a <code>float[]</code> array to a <code>byte[]</code> array.
+     * 
+     * @param data The array to convert.
+     * @param byteOrder The byte order of the returned <code>byte[]</code>.
+     * @return The converted <code>byte[]</code> array.
+     */
+    public static byte[] floatToByte(float[] data, ByteOrder byteOrder)
+    {
+        final byte[] byteArr = new byte[FLOAT_SIZE * data.length];
+        copyFloatToByte(data, 0, byteArr, 0, data.length, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Converts a <code>byte[]</code> array into a <code>double[]</code> array.
+     * 
+     * @param byteArr The <code>byte[]</code> to convert.
+     * @param byteOrder The byte order of <var>byteArr</var>.
+     * @param start The position in the <var>byteArr</var> to start the conversion.
+     * @param len The number of <code>double</code> values to convert.
+     * @return The <code>double[]</code> array.
+     */
+    public static double[] byteToDouble(byte[] byteArr, ByteOrder byteOrder, int start, int len)
+    {
+        final double[] array = new double[len];
+        copyByteToDouble(byteArr, start, array, 0, len, byteOrder);
+        return array;
+    }
+
+    /**
+     * Converts a <code>byte[]</code> array into a <code>double[]</code> array.
+     * 
+     * @param byteArr The <code>byte[]</code> to convert.
+     * @param byteOrder The byte order of <var>byteArr</var>.
+     * @return The <code>double[]</code> array.
+     */
+    public static double[] byteToDouble(byte[] byteArr, ByteOrder byteOrder)
+    {
+        if (byteArr.length % DOUBLE_SIZE != 0)
+        {
+            throw new IllegalArgumentException("Length of byteArr does not match size of data type");
+        }
+        final int len = byteArr.length / DOUBLE_SIZE;
+        final double[] array = new double[len];
+        copyByteToDouble(byteArr, 0, array, 0, len, byteOrder);
+        return array;
+    }
+
+    /**
+     * Converts a <code>double[]</code> array to a <code>byte[]</code> array.
+     * 
+     * @param data The array to convert.
+     * @param byteOrder The byte order of the returned <code>byte[]</code>.
+     * @param start The position in <var>data</var> to start the conversion.
+     * @param len The number of <code>double</code> values to convert.
+     * @return The converted <code>byte[]</code> array.
+     */
+    public static byte[] doubleToByte(double[] data, ByteOrder byteOrder, int start, int len)
+    {
+        final byte[] byteArr = new byte[DOUBLE_SIZE * len];
+        copyDoubleToByte(data, start, byteArr, 0, len, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Converts a <code>double[]</code> array to a <code>byte[]</code> array.
+     * 
+     * @param data The array to convert.
+     * @param byteOrder The byte order of the returned <code>byte[]</code>.
+     * @return The converted <code>byte[]</code> array.
+     */
+    public static byte[] doubleToByte(double[] data, ByteOrder byteOrder)
+    {
+        final byte[] byteArr = new byte[DOUBLE_SIZE * data.length];
+        copyDoubleToByte(data, 0, byteArr, 0, data.length, byteOrder);
+        return byteArr;
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/convert/NativeTaggedArray.java b/source/java/ch/systemsx/cisd/base/convert/NativeTaggedArray.java
new file mode 100644
index 0000000..da8c6b8
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/convert/NativeTaggedArray.java
@@ -0,0 +1,672 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.convert;
+
+import static ch.systemsx.cisd.base.convert.NativeData.DOUBLE_SIZE;
+import static ch.systemsx.cisd.base.convert.NativeData.FLOAT_SIZE;
+import static ch.systemsx.cisd.base.convert.NativeData.INT_SIZE;
+import static ch.systemsx.cisd.base.convert.NativeData.LONG_SIZE;
+import static ch.systemsx.cisd.base.convert.NativeData.SHORT_SIZE;
+
+import ch.systemsx.cisd.base.convert.NativeData.ByteOrder;
+import ch.systemsx.cisd.base.mdarray.MDAbstractArray;
+import ch.systemsx.cisd.base.mdarray.MDDoubleArray;
+import ch.systemsx.cisd.base.mdarray.MDFloatArray;
+import ch.systemsx.cisd.base.mdarray.MDIntArray;
+import ch.systemsx.cisd.base.mdarray.MDLongArray;
+import ch.systemsx.cisd.base.mdarray.MDShortArray;
+
+/**
+ * A utility class that supports encoding and decoding of arrays of primitive number types to byte
+ * arrays such that the characteristics of the number type (float or integer, byte order, element
+ * size) and the dimensions are known and can be checked for correctness when converted back to the
+ * number type.
+ * 
+ * @author Bernd Rinn
+ */
+public class NativeTaggedArray
+{
+
+    private final static NativeData.ByteOrder NATIVE_BYTE_ORDER = NativeData.getNativeByteOrder();
+
+    private static final int MAGIC_SIZE = 3;
+
+    private static final int RANK_SIZE = 1;
+
+    private static final int RANK_INDEX = 3;
+
+    private static final int LENGTH_SIZE = 4;
+
+    private static final int LENGTH_INDEX = 4;
+
+    private static final int RANK_1 = 1;
+
+    /**
+     * A class to return the array encoding and dimensions of a native tagged array.
+     */
+    public static class NativeArrayTag
+    {
+        private final NativeArrayEncoding encoding;
+
+        private final int[] dimensions;
+
+        NativeArrayTag(NativeArrayEncoding encoding, int[] dimensions)
+        {
+            this.encoding = encoding;
+            this.dimensions = dimensions;
+        }
+
+        /**
+         * Returns the {@link NativeArrayEncoding} of the array.
+         */
+        public NativeArrayEncoding getEncoding()
+        {
+            return encoding;
+        }
+
+        /**
+         * Resurns the dimensions of the array.
+         */
+        public int[] getDimensions()
+        {
+            return dimensions;
+        }
+    }
+
+    /**
+     * Returns the array tag of the native tagged array encoded in <var>data</var>, or
+     * <code>null</code>, if <var>data</var> does not encode a native tagged array.
+     */
+    public static NativeArrayTag tryGetArrayTag(byte[] data)
+    {
+        final NativeArrayEncoding encodingOrNull = NativeArrayEncoding.tryGetEncoding(data);
+        if (encodingOrNull == null)
+        {
+            return null;
+        }
+        final int rank = data[RANK_INDEX];
+        final int[] dimensions = new int[rank];
+        NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, rank,
+                encodingOrNull.getByteOrder());
+        return new NativeArrayTag(encodingOrNull, dimensions);
+    }
+
+    //
+    // Float
+    //
+
+    /**
+     * Converts <var>data</var> into a tagged array in native byte order.
+     */
+    public static byte[] toByteArray(float[] data)
+    {
+        return toByteArray(data, NATIVE_BYTE_ORDER);
+    }
+
+    /**
+     * Converts <var>data</var> into a tagged array in given byte order.
+     */
+    public static byte[] toByteArray(float[] data, ByteOrder byteOrder)
+    {
+        final byte[] magic =
+                NativeArrayEncoding.tryGetFloatEncoding(byteOrder, (byte) FLOAT_SIZE).getMagic();
+        assert magic.length == MAGIC_SIZE;
+        final int headerSize = MAGIC_SIZE + RANK_SIZE + 1 * LENGTH_SIZE;
+        final byte[] byteArr = new byte[headerSize + FLOAT_SIZE * data.length];
+        System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+        byteArr[RANK_INDEX] = RANK_1;
+        NativeData.copyIntToByte(new int[]
+            { data.length }, 0, byteArr, LENGTH_INDEX, 1, byteOrder);
+        NativeData.copyFloatToByte(data, 0, byteArr, headerSize, data.length, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Converts <var>data</var> into a tagged array in native byte order.
+     */
+    public static byte[] toByteArray(MDFloatArray data)
+    {
+        return toByteArray(data, NATIVE_BYTE_ORDER);
+    }
+
+    /**
+     * Converts <var>data</var> into a tagged array in given byte order.
+     */
+    public static byte[] toByteArray(MDFloatArray data, ByteOrder byteOrder)
+    {
+        final byte[] magic =
+                NativeArrayEncoding.tryGetFloatEncoding(byteOrder, (byte) FLOAT_SIZE).getMagic();
+        assert magic.length == MAGIC_SIZE;
+        final byte rank = (byte) data.rank();
+        final int headerSize = MAGIC_SIZE + RANK_SIZE + rank * LENGTH_SIZE;
+        final float[] flatDataArray = data.getAsFlatArray();
+        final byte[] byteArr = new byte[headerSize + FLOAT_SIZE * flatDataArray.length];
+        System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+        byteArr[RANK_INDEX] = rank;
+        NativeData.copyIntToByte(data.dimensions(), 0, byteArr, LENGTH_INDEX, rank, byteOrder);
+        NativeData.copyFloatToByte(flatDataArray, 0, byteArr, headerSize, flatDataArray.length,
+                byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Returns the tagged array <var>data</var> as a float array or <code>null</code>, if
+     * <var>data</var> is not a tagged 1D float array.
+     */
+    public static float[] tryToFloatArray1D(byte[] data)
+    {
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+        if (encoding == null || encoding.isInteger() || encoding.getSizeInBytes() != FLOAT_SIZE)
+        {
+            return null;
+        }
+        final int rank = data[RANK_INDEX];
+        if (rank != 1)
+        {
+            return null;
+        }
+        final int[] dimensions = new int[1];
+        NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, 1, encoding.getByteOrder());
+        if (dimensions[0] * FLOAT_SIZE + LENGTH_INDEX + LENGTH_SIZE != data.length)
+        {
+            return null;
+        }
+        final float[] floatData = new float[dimensions[0]];
+        NativeData.copyByteToFloat(data, LENGTH_INDEX + LENGTH_SIZE, floatData, 0,
+                floatData.length, encoding.getByteOrder());
+        return floatData;
+    }
+
+    /**
+     * Returns the tagged array <var>data</var> as a {@link MDFloatArray} or <code>null</code>, if
+     * <var>data</var> is not a tagged (multi-dimensional) float array.
+     */
+    public static MDFloatArray tryToFloatArray(byte[] data)
+    {
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+        if (encoding == null || encoding.isInteger() || encoding.getSizeInBytes() != FLOAT_SIZE)
+        {
+            return null;
+        }
+        final int rank = data[RANK_INDEX];
+        final int[] dimensions = new int[rank];
+        NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, rank, encoding.getByteOrder());
+        final int length = MDAbstractArray.getLength(dimensions);
+        final int headerSize = LENGTH_INDEX + rank * LENGTH_SIZE;
+        if (length * FLOAT_SIZE + headerSize != data.length)
+        {
+            return null;
+        }
+        final float[] intData = new float[length];
+        NativeData.copyByteToFloat(data, headerSize, intData, 0, intData.length,
+                encoding.getByteOrder());
+        return new MDFloatArray(intData, dimensions);
+    }
+
+    //
+    // Double
+    //
+
+    /**
+     * Converts <var>data</var> into a tagged array in native byte order.
+     */
+    public static byte[] toByteArray(double[] data)
+    {
+        return toByteArray(data, NATIVE_BYTE_ORDER);
+    }
+
+    /**
+     * Converts <var>data</var> into a tagged array in given byte order.
+     */
+    public static byte[] toByteArray(double[] data, ByteOrder byteOrder)
+    {
+        final byte[] magic =
+                NativeArrayEncoding.tryGetFloatEncoding(byteOrder, (byte) DOUBLE_SIZE).getMagic();
+        assert magic.length == MAGIC_SIZE;
+        final int headerSize = MAGIC_SIZE + RANK_SIZE + 1 * LENGTH_SIZE;
+        final byte[] byteArr = new byte[headerSize + DOUBLE_SIZE * data.length];
+        System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+        byteArr[RANK_INDEX] = RANK_1;
+        NativeData.copyIntToByte(new int[]
+            { data.length }, 0, byteArr, LENGTH_INDEX, 1, byteOrder);
+        NativeData.copyDoubleToByte(data, 0, byteArr, headerSize, data.length, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Converts <var>data</var> into a tagged array in native byte order.
+     */
+    public static byte[] toByteArray(MDDoubleArray data)
+    {
+        return toByteArray(data, NATIVE_BYTE_ORDER);
+    }
+
+    /**
+     * Converts <var>data</var> into a tagged array in given byte order.
+     */
+    public static byte[] toByteArray(MDDoubleArray data, ByteOrder byteOrder)
+    {
+        final byte[] magic =
+                NativeArrayEncoding.tryGetFloatEncoding(byteOrder, (byte) DOUBLE_SIZE).getMagic();
+        assert magic.length == MAGIC_SIZE;
+        final byte rank = (byte) data.rank();
+        final int headerSize = MAGIC_SIZE + RANK_SIZE + rank * LENGTH_SIZE;
+        final double[] flatDataArray = data.getAsFlatArray();
+        final byte[] byteArr = new byte[headerSize + DOUBLE_SIZE * flatDataArray.length];
+        System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+        byteArr[RANK_INDEX] = rank;
+        NativeData.copyIntToByte(data.dimensions(), 0, byteArr, LENGTH_INDEX, rank, byteOrder);
+        NativeData.copyDoubleToByte(flatDataArray, 0, byteArr, headerSize, flatDataArray.length,
+                byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Returns the tagged array <var>data</var> as a double array or <code>null</code>, if
+     * <var>data</var> is not a tagged 1D double array.
+     */
+    public static double[] tryToDoubleArray1D(byte[] data)
+    {
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+        if (encoding == null || encoding.isInteger() || encoding.getSizeInBytes() != DOUBLE_SIZE)
+        {
+            return null;
+        }
+        final int rank = data[RANK_INDEX];
+        if (rank != 1)
+        {
+            return null;
+        }
+        final int[] dimensions = new int[1];
+        NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, 1, encoding.getByteOrder());
+        if (dimensions[0] * DOUBLE_SIZE + LENGTH_INDEX + LENGTH_SIZE != data.length)
+        {
+            return null;
+        }
+        final double[] doubleData = new double[dimensions[0]];
+        NativeData.copyByteToDouble(data, LENGTH_INDEX + LENGTH_SIZE, doubleData, 0,
+                doubleData.length, encoding.getByteOrder());
+        return doubleData;
+    }
+
+    /**
+     * Returns the tagged array <var>data</var> as a {@link MDDoubleArray} or <code>null</code>, if
+     * <var>data</var> is not a tagged (multi-dimensional) double array.
+     */
+    public static MDDoubleArray tryToDoubleArray(byte[] data)
+    {
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+        if (encoding == null || encoding.isInteger() || encoding.getSizeInBytes() != DOUBLE_SIZE)
+        {
+            return null;
+        }
+        final int rank = data[RANK_INDEX];
+        final int[] dimensions = new int[rank];
+        NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, rank, encoding.getByteOrder());
+        final int length = MDAbstractArray.getLength(dimensions);
+        final int headerSize = LENGTH_INDEX + rank * LENGTH_SIZE;
+        if (length * DOUBLE_SIZE + headerSize != data.length)
+        {
+            return null;
+        }
+        final double[] intData = new double[length];
+        NativeData.copyByteToDouble(data, headerSize, intData, 0, intData.length,
+                encoding.getByteOrder());
+        return new MDDoubleArray(intData, dimensions);
+    }
+
+    //
+    // Short
+    //
+
+    /**
+     * Converts <var>data</var> into a tagged array in native byte order.
+     */
+    public static byte[] toByteArray(short[] data)
+    {
+        return toByteArray(data, NATIVE_BYTE_ORDER);
+    }
+
+    /**
+     * Converts <var>data</var> into a tagged array in given byte order.
+     */
+    public static byte[] toByteArray(short[] data, ByteOrder byteOrder)
+    {
+        final byte[] magic =
+                NativeArrayEncoding.tryGetIntEncoding(byteOrder, (byte) SHORT_SIZE).getMagic();
+        assert magic.length == MAGIC_SIZE;
+        final int headerSize = MAGIC_SIZE + RANK_SIZE + 1 * LENGTH_SIZE;
+        final byte[] byteArr = new byte[headerSize + SHORT_SIZE * data.length];
+        System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+        byteArr[RANK_INDEX] = RANK_1;
+        NativeData.copyIntToByte(new int[]
+            { data.length }, 0, byteArr, LENGTH_INDEX, 1, byteOrder);
+        NativeData.copyShortToByte(data, 0, byteArr, headerSize, data.length, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Converts <var>data</var> into a tagged array in native byte order.
+     */
+    public static byte[] toByteArray(MDShortArray data)
+    {
+        return toByteArray(data, NATIVE_BYTE_ORDER);
+    }
+
+    /**
+     * Converts <var>data</var> into a tagged array in given byte order.
+     */
+    public static byte[] toByteArray(MDShortArray data, ByteOrder byteOrder)
+    {
+        final byte[] magic =
+                NativeArrayEncoding.tryGetIntEncoding(byteOrder, (byte) SHORT_SIZE).getMagic();
+        assert magic.length == MAGIC_SIZE;
+        final byte rank = (byte) data.rank();
+        final int headerSize = MAGIC_SIZE + RANK_SIZE + rank * LENGTH_SIZE;
+        final short[] flatDataArray = data.getAsFlatArray();
+        final byte[] byteArr = new byte[headerSize + SHORT_SIZE * flatDataArray.length];
+        System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+        byteArr[RANK_INDEX] = rank;
+        NativeData.copyIntToByte(data.dimensions(), 0, byteArr, LENGTH_INDEX, rank, byteOrder);
+        NativeData.copyShortToByte(flatDataArray, 0, byteArr, headerSize, flatDataArray.length,
+                byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Returns the tagged array <var>data</var> as a short array or <code>null</code>, if
+     * <var>data</var> is not a tagged 1D short array.
+     */
+    public static short[] tryToShortArray1D(byte[] data)
+    {
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+        if (encoding == null || encoding.isFloatingPoint()
+                || encoding.getSizeInBytes() != SHORT_SIZE)
+        {
+            return null;
+        }
+        final int rank = data[RANK_INDEX];
+        if (rank != 1)
+        {
+            return null;
+        }
+        final int[] dimensions = new int[1];
+        NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, 1, encoding.getByteOrder());
+        if (dimensions[0] * SHORT_SIZE + LENGTH_INDEX + LENGTH_SIZE != data.length)
+        {
+            return null;
+        }
+        final short[] shortData = new short[dimensions[0]];
+        NativeData.copyByteToShort(data, LENGTH_INDEX + LENGTH_SIZE, shortData, 0,
+                shortData.length, encoding.getByteOrder());
+        return shortData;
+    }
+
+    /**
+     * Returns the tagged array <var>data</var> as a {@link MDShortArray} or <code>null</code>, if
+     * <var>data</var> is not a tagged (multi-dimensional) short array.
+     */
+    public static MDShortArray tryToShortArray(byte[] data)
+    {
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+        if (encoding == null || encoding.isFloatingPoint()
+                || encoding.getSizeInBytes() != SHORT_SIZE)
+        {
+            return null;
+        }
+        final int rank = data[RANK_INDEX];
+        final int[] dimensions = new int[rank];
+        NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, rank, encoding.getByteOrder());
+        final int length = MDAbstractArray.getLength(dimensions);
+        final int headerSize = LENGTH_INDEX + rank * LENGTH_SIZE;
+        if (length * SHORT_SIZE + headerSize != data.length)
+        {
+            return null;
+        }
+        final short[] intData = new short[length];
+        NativeData.copyByteToShort(data, headerSize, intData, 0, intData.length,
+                encoding.getByteOrder());
+        return new MDShortArray(intData, dimensions);
+    }
+
+    //
+    // Int
+    //
+
+    /**
+     * Converts <var>data</var> into a tagged array in native byte order.
+     */
+    public static byte[] toByteArray(int[] data)
+    {
+        return toByteArray(data, NATIVE_BYTE_ORDER);
+    }
+
+    /**
+     * Converts <var>data</var> into a tagged array in given byte order.
+     */
+    public static byte[] toByteArray(int[] data, ByteOrder byteOrder)
+    {
+        final byte[] magic =
+                NativeArrayEncoding.tryGetIntEncoding(byteOrder, (byte) INT_SIZE).getMagic();
+        assert magic.length == MAGIC_SIZE;
+        final int headerSize = MAGIC_SIZE + RANK_SIZE + 1 * LENGTH_SIZE;
+        final byte[] byteArr = new byte[headerSize + INT_SIZE * data.length];
+        System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+        byteArr[RANK_INDEX] = RANK_1;
+        NativeData.copyIntToByte(new int[]
+            { data.length }, 0, byteArr, LENGTH_INDEX, 1, byteOrder);
+        NativeData.copyIntToByte(data, 0, byteArr, headerSize, data.length, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Converts <var>data</var> into a tagged array in native byte order.
+     */
+    public static byte[] toByteArray(MDIntArray data)
+    {
+        return toByteArray(data, NATIVE_BYTE_ORDER);
+    }
+
+    /**
+     * Converts <var>data</var> into a tagged array in given byte order.
+     */
+    public static byte[] toByteArray(MDIntArray data, ByteOrder byteOrder)
+    {
+        final byte[] magic =
+                NativeArrayEncoding.tryGetIntEncoding(byteOrder, (byte) INT_SIZE).getMagic();
+        assert magic.length == MAGIC_SIZE;
+        final byte rank = (byte) data.rank();
+        final int headerSize = MAGIC_SIZE + RANK_SIZE + rank * LENGTH_SIZE;
+        final int[] flatDataArray = data.getAsFlatArray();
+        final byte[] byteArr = new byte[headerSize + INT_SIZE * flatDataArray.length];
+        System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+        byteArr[RANK_INDEX] = rank;
+        NativeData.copyIntToByte(data.dimensions(), 0, byteArr, LENGTH_INDEX, rank, byteOrder);
+        NativeData.copyIntToByte(flatDataArray, 0, byteArr, headerSize, flatDataArray.length,
+                byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Returns the tagged array <var>data</var> as an int array or <code>null</code>, if
+     * <var>data</var> is not a tagged 1D int array.
+     */
+    public static int[] tryToIntArray1D(byte[] data)
+    {
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+        if (encoding == null || encoding.isFloatingPoint() || encoding.getSizeInBytes() != INT_SIZE)
+        {
+            return null;
+        }
+        final int rank = data[RANK_INDEX];
+        if (rank != 1)
+        {
+            return null;
+        }
+        final int[] dimensions = new int[1];
+        NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, 1, encoding.getByteOrder());
+        if (dimensions[0] * INT_SIZE + LENGTH_INDEX + LENGTH_SIZE != data.length)
+        {
+            return null;
+        }
+        final int[] intData = new int[dimensions[0]];
+        NativeData.copyByteToInt(data, LENGTH_INDEX + LENGTH_SIZE, intData, 0, intData.length,
+                encoding.getByteOrder());
+        return intData;
+    }
+
+    /**
+     * Returns the tagged array <var>data</var> as a {@link MDIntArray} or <code>null</code>, if
+     * <var>data</var> is not a tagged (multi-dimensional) int array.
+     */
+    public static MDIntArray tryToIntArray(byte[] data)
+    {
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+        if (encoding == null || encoding.isFloatingPoint() || encoding.getSizeInBytes() != INT_SIZE)
+        {
+            return null;
+        }
+        final int rank = data[RANK_INDEX];
+        final int[] dimensions = new int[rank];
+        NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, rank, encoding.getByteOrder());
+        final int length = MDAbstractArray.getLength(dimensions);
+        final int headerSize = LENGTH_INDEX + rank * LENGTH_SIZE;
+        if (length * INT_SIZE + headerSize != data.length)
+        {
+            return null;
+        }
+        final int[] intData = new int[length];
+        NativeData.copyByteToInt(data, headerSize, intData, 0, intData.length,
+                encoding.getByteOrder());
+        return new MDIntArray(intData, dimensions);
+    }
+
+    //
+    // Long
+    //
+
+    /**
+     * Converts <var>data</var> into a tagged array in native byte order.
+     */
+    public static byte[] toByteArray(long[] data)
+    {
+        return toByteArray(data, NATIVE_BYTE_ORDER);
+    }
+
+    /**
+     * Converts <var>data</var> into a tagged array in given byte order.
+     */
+    public static byte[] toByteArray(long[] data, ByteOrder byteOrder)
+    {
+        final byte[] magic =
+                NativeArrayEncoding.tryGetIntEncoding(byteOrder, (byte) LONG_SIZE).getMagic();
+        assert magic.length == MAGIC_SIZE;
+        final int headerSize = MAGIC_SIZE + RANK_SIZE + 1 * LENGTH_SIZE;
+        final byte[] byteArr = new byte[headerSize + LONG_SIZE * data.length];
+        System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+        byteArr[RANK_INDEX] = RANK_1;
+        NativeData.copyIntToByte(new int[]
+            { data.length }, 0, byteArr, LENGTH_INDEX, 1, byteOrder);
+        NativeData.copyLongToByte(data, 0, byteArr, headerSize, data.length, byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Converts <var>data</var> into a tagged array in native byte order.
+     */
+    public static byte[] toByteArray(MDLongArray data)
+    {
+        return toByteArray(data, NATIVE_BYTE_ORDER);
+    }
+
+    /**
+     * Converts <var>data</var> into a tagged array in given byte order.
+     */
+    public static byte[] toByteArray(MDLongArray data, ByteOrder byteOrder)
+    {
+        final byte[] magic =
+                NativeArrayEncoding.tryGetIntEncoding(byteOrder, (byte) LONG_SIZE).getMagic();
+        assert magic.length == MAGIC_SIZE;
+        final byte rank = (byte) data.rank();
+        final int headerSize = MAGIC_SIZE + RANK_SIZE + rank * LENGTH_SIZE;
+        final long[] flatDataArray = data.getAsFlatArray();
+        final byte[] byteArr = new byte[headerSize + LONG_SIZE * flatDataArray.length];
+        System.arraycopy(magic, 0, byteArr, 0, MAGIC_SIZE);
+        byteArr[RANK_INDEX] = rank;
+        NativeData.copyIntToByte(data.dimensions(), 0, byteArr, LENGTH_INDEX, rank, byteOrder);
+        NativeData.copyLongToByte(flatDataArray, 0, byteArr, headerSize, flatDataArray.length,
+                byteOrder);
+        return byteArr;
+    }
+
+    /**
+     * Returns the tagged array <var>data</var> as a long array or <code>null</code>, if
+     * <var>data</var> is not a tagged 1D long array.
+     */
+    public static long[] tryToLongArray1D(byte[] data)
+    {
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+        if (encoding == null || encoding.isFloatingPoint()
+                || encoding.getSizeInBytes() != LONG_SIZE)
+        {
+            return null;
+        }
+        final int rank = data[RANK_INDEX];
+        if (rank != 1)
+        {
+            return null;
+        }
+        final int[] dimensions = new int[1];
+        NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, 1, encoding.getByteOrder());
+        if (dimensions[0] * LONG_SIZE + LENGTH_INDEX + 1 * LENGTH_SIZE != data.length)
+        {
+            return null;
+        }
+        final long[] longData = new long[dimensions[0]];
+        NativeData.copyByteToLong(data, LENGTH_INDEX + LENGTH_SIZE, longData, 0, longData.length,
+                encoding.getByteOrder());
+        return longData;
+    }
+
+    /**
+     * Returns the tagged array <var>data</var> as a {@link MDLongArray} or <code>null</code>, if
+     * <var>data</var> is not a tagged (multi-dimensional) long array.
+     */
+    public static MDLongArray tryToLongArray(byte[] data)
+    {
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(data);
+        if (encoding == null || encoding.isFloatingPoint()
+                || encoding.getSizeInBytes() != LONG_SIZE)
+        {
+            return null;
+        }
+        final int rank = data[RANK_INDEX];
+        final int[] dimensions = new int[rank];
+        NativeData.copyByteToInt(data, LENGTH_INDEX, dimensions, 0, rank, encoding.getByteOrder());
+        final int length = MDAbstractArray.getLength(dimensions);
+        final int headerSize = LENGTH_INDEX + rank * LENGTH_SIZE;
+        if (length * LONG_SIZE + headerSize != data.length)
+        {
+            return null;
+        }
+        final long[] longData = new long[length];
+        NativeData.copyByteToLong(data, headerSize, longData, 0, longData.length,
+                encoding.getByteOrder());
+        return new MDLongArray(longData, dimensions);
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/exceptions/CheckedExceptionTunnel.java b/source/java/ch/systemsx/cisd/base/exceptions/CheckedExceptionTunnel.java
new file mode 100644
index 0000000..c874c44
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/exceptions/CheckedExceptionTunnel.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2007 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.exceptions;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ * An exception for tunneling checked exception through code that doesn't expect it.
+ * 
+ * @author Bernd Rinn
+ */
+public class CheckedExceptionTunnel extends RuntimeException
+{
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Returns an unchecked exception from a <var>checkedException</var>.
+     * 
+     * @param checkedExceptionOrNull The checked exception to tunnel.
+     */
+    public CheckedExceptionTunnel(final Exception checkedExceptionOrNull)
+    {
+        super(checkedExceptionOrNull);
+
+        assert (checkedExceptionOrNull instanceof RuntimeException) == false;
+    }
+    
+    protected CheckedExceptionTunnel(final String msg)
+    {
+        super(msg);
+    }
+
+    protected CheckedExceptionTunnel()
+    {
+    }
+
+    @Override
+    public String getMessage()
+    {
+        if (getCause() != null && getCause().getMessage() != null)
+        {
+            return getCause().getMessage();
+        }
+        return super.getMessage();
+    }
+
+    @Override
+    public String toString()
+    {
+        if (getCause() != null)
+        {
+            return getCause().toString();
+        }
+        return super.toString();
+    }
+
+    @Override
+    public void printStackTrace(PrintStream s)
+    {
+        if (getCause() != null)
+        {
+            getCause().printStackTrace(s);
+        } else
+        {
+            super.printStackTrace(s);
+        }
+    }
+
+    @Override
+    public void printStackTrace(PrintWriter s)
+    {
+        if (getCause() != null)
+        {
+            getCause().printStackTrace(s);
+        } else
+        {
+            super.printStackTrace(s);
+        }
+    }
+
+    /**
+     * Like {@link #printStackTrace()}, but includes the tunnel's stacktrace as well.
+     */
+    public void printFullStackTrace()
+    {
+        printFullStackTrace(System.err);
+    }
+
+    /**
+     * Like {@link #printStackTrace(PrintStream)}, but includes the tunnel's stacktrace as well.
+     */
+    public void printFullStackTrace(PrintStream s)
+    {
+        synchronized (s) {
+            s.println(super.toString());
+            StackTraceElement[] trace = getStackTrace();
+            for (int i=0; i < trace.length; i++)
+                s.println("\tat " + trace[i]);
+
+            Throwable ourCause = getCause();
+            if (ourCause != null)
+            {
+                printStackTraceAsCause(ourCause, s, trace);
+            }
+        }
+    }
+
+    /**
+     * Print our stack trace as a cause for the specified stack trace.
+     */
+    private static void printStackTraceAsCause(Throwable cause, PrintStream s,
+                                        StackTraceElement[] causedTrace)
+    {
+        final StackTraceElement[] trace = cause.getStackTrace();
+        int m = trace.length-1, n = causedTrace.length-1;
+        while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) {
+            m--; n--;
+        }
+        final int framesInCommon = trace.length - 1 - m;
+
+        s.println("Caused by: " + cause);
+        for (int i=0; i <= m; i++)
+            s.println("\tat " + trace[i]);
+        if (framesInCommon != 0)
+            s.println("\t... " + framesInCommon + " more");
+
+        final Throwable ourCauseesCause = cause.getCause();
+        if (ourCauseesCause != null)
+        {
+            printStackTraceAsCause(ourCauseesCause, s, trace);
+        }
+    }
+
+    /**
+     * Like {@link #printStackTrace(PrintWriter)}, but includes the tunnel's stacktrace as well.
+     */
+    public void printFullStackTrace(PrintWriter s)
+    {
+        synchronized (s) {
+            s.println(super.toString());
+            StackTraceElement[] trace = getStackTrace();
+            for (int i=0; i < trace.length; i++)
+                s.println("\tat " + trace[i]);
+
+            Throwable ourCause = getCause();
+            if (ourCause != null)
+            {
+                printStackTraceAsCause(ourCause, s, trace);
+            }
+        }
+    }
+
+    /**
+     * Print our stack trace as a cause for the specified stack trace.
+     */
+    private static void printStackTraceAsCause(Throwable cause, PrintWriter s,
+                                        StackTraceElement[] causedTrace)
+    {
+        final StackTraceElement[] trace = cause.getStackTrace();
+        int m = trace.length-1, n = causedTrace.length-1;
+        while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) {
+            m--; n--;
+        }
+        final int framesInCommon = trace.length - 1 - m;
+
+        s.println("Caused by: " + cause);
+        for (int i=0; i <= m; i++)
+            s.println("\tat " + trace[i]);
+        if (framesInCommon != 0)
+            s.println("\t... " + framesInCommon + " more");
+
+        final Throwable ourCauseesCause = cause.getCause();
+        if (ourCauseesCause != null)
+        {
+            printStackTraceAsCause(ourCauseesCause, s, trace);
+        }
+    }
+
+    /**
+     * Convenience wrapper for {@link #wrapIfNecessary(Exception)}. If <var>throwable</var> is an
+     * {@link Error}, this method will not return but the error will be thrown.
+     * 
+     * @param throwable The exception to represent by the return value.
+     * @return A {@link RuntimeException} representing the <var>throwable</var>.
+     * @throws Error If <var>throwable</var> is an {@link Error} (except when it is a
+     *             {@link ThreadDeath}, which returns a {@link InterruptedExceptionUnchecked}).
+     */
+    public final static RuntimeException wrapIfNecessary(final Throwable throwable) throws Error
+    {
+        if (throwable instanceof Error)
+        {
+            if (throwable instanceof ThreadDeath)
+            {
+                return new InterruptedExceptionUnchecked();
+            } else
+            {
+                throw (Error) throwable;
+            }
+        }
+        return wrapIfNecessary((Exception) throwable);
+    }
+
+    /**
+     * Returns a {@link RuntimeException} from an <var>exception</var>. If <var>exception</var> is
+     * already a {@link RuntimeException}, itself is returned, otherwise an appropriate unchecked
+     * equivalent. If no unchecked equivalent exists, a {@link CheckedExceptionTunnel} is returned
+     * with <var>exception</var> as checked exception argument.
+     * 
+     * @param exception The exception to represent by the return value.
+     * @return A {@link RuntimeException} representing the <var>exception</var>.
+     */
+    public final static RuntimeException wrapIfNecessary(final Exception exception)
+    {
+        if (exception instanceof RuntimeException)
+        {
+            return (RuntimeException) exception;
+        }
+        if (exception instanceof IOException)
+        {
+            return new IOExceptionUnchecked((IOException) exception);
+        }
+        if (exception instanceof InterruptedException)
+        {
+            return new InterruptedExceptionUnchecked((InterruptedException) exception);
+        }
+        if (exception instanceof java.util.concurrent.TimeoutException)
+        {
+            return new TimeoutExceptionUnchecked((java.util.concurrent.TimeoutException) exception);
+        }
+        return new CheckedExceptionTunnel(exception);
+    }
+
+    /**
+     * Returns the original exception before being wrapped, if the exception has been wrapped, or
+     * <var>exception</var> otherwise.
+     */
+    public final static Exception unwrapIfNecessary(final Exception exception)
+    {
+        assert exception != null : "Exception not specified.";
+        if (exception instanceof CheckedExceptionTunnel)
+        {
+            // We are sure that the wrapped exception is an 'Exception'.
+            final Exception causeOrNull = (Exception) exception.getCause();
+            if (causeOrNull != null)
+            {
+                return causeOrNull;
+            }
+        }
+        return exception;
+    }
+
+    /**
+     * Returns the original throwable before being wrapped, if the throwable has been wrapped, or
+     * <var>exception</var> otherwise.
+     */
+    public final static Throwable unwrapIfNecessary(final Throwable throwable)
+    {
+        assert throwable != null : "Exception not specified.";
+        if (throwable instanceof Error)
+        {
+            return throwable;
+        } else
+        {
+            return unwrapIfNecessary((Exception) throwable);
+        }
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/exceptions/IErrorStrategy.java b/source/java/ch/systemsx/cisd/base/exceptions/IErrorStrategy.java
new file mode 100644
index 0000000..cfd17ee
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/exceptions/IErrorStrategy.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.exceptions;
+
+/**
+ * A strategy role for dealing with errors.
+ * 
+ * @author Bernd Rinn
+ */
+public interface IErrorStrategy
+{
+    /**
+     * The default error strategy, just re-throws the exception.
+     */
+    public static final IErrorStrategy DEFAULT_ERROR_STRATEGY = new IErrorStrategy()
+        {
+            @Override
+            public void dealWithError(Throwable th) throws RuntimeException, Error
+            {
+                throw CheckedExceptionTunnel.wrapIfNecessary(th);
+            }
+
+            @Override
+            public void warning(String message)
+            {
+                System.err.println(message);
+            }
+        };
+
+    /**
+     * Called when an exception <var>ex</var> has occurred. Can, but doesn't have to, abort the
+     * operation by re-throwing the exception.
+     * 
+     * @throws RuntimeException if the operation should be aborted.
+     */
+    public void dealWithError(final Throwable th) throws RuntimeException, Error;
+
+    /**
+     * Called to issue a warning message.
+     */
+    public void warning(String message);
+}
diff --git a/source/java/ch/systemsx/cisd/base/exceptions/IOExceptionUnchecked.java b/source/java/ch/systemsx/cisd/base/exceptions/IOExceptionUnchecked.java
new file mode 100644
index 0000000..caa7b39
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/exceptions/IOExceptionUnchecked.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.exceptions;
+
+import java.io.IOException;
+
+/**
+ * A {@link CheckedExceptionTunnel} for an {@link IOException}.
+ * 
+ * @author Bernd Rinn
+ */
+public class IOExceptionUnchecked extends CheckedExceptionTunnel
+{
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Returns an <code>IOExceptionUnchecked</code> from a <code>IOException</code>.
+     * 
+     * @param checkedException The checked exception to tunnel.
+     */
+    public IOExceptionUnchecked(final IOException checkedException)
+    {
+        super(checkedException);
+
+        assert checkedException != null;
+    }
+
+    /**
+     * Returns an <code>IOExceptionUnchecked</code> from a newly created <code>IOException</code>
+     * with given <var>msg</var>.
+     * 
+     * @param msg The checked exception to tunnel.
+     */
+    public IOExceptionUnchecked(final String msg)
+    {
+        this(new IOException(msg));
+    }
+
+    private static IOException createIOException(final Throwable throwable)
+    {
+        final IOException ioe =
+                new IOException(throwable.getClass().getSimpleName() + ": "
+                        + throwable.getMessage());
+        ioe.initCause(throwable);
+        return ioe;
+    }
+
+    /**
+     * Returns an <code>IOExceptionUnchecked</code> from newly created <code>IOException</code> with
+     * given <var>throwable</var> as its cause.
+     * 
+     * @param throwable The throwable to use the cause of the created <code>IOException</code>.
+     */
+    public IOExceptionUnchecked(final Throwable throwable)
+    {
+        super(createIOException(throwable));
+
+        assert throwable != null;
+    }
+
+    @Override
+    public IOException getCause()
+    {
+        return (IOException) super.getCause();
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/exceptions/InterruptedExceptionUnchecked.java b/source/java/ch/systemsx/cisd/base/exceptions/InterruptedExceptionUnchecked.java
new file mode 100644
index 0000000..d420052
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/exceptions/InterruptedExceptionUnchecked.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.exceptions;
+
+/**
+ * Exception that signals that whoever gets it should stop its current work. This is an unchecked
+ * equivalent to an {@link InterruptedException}.
+ * <p>
+ * This is usually triggered by interrupting the thread that the work package is processed in and
+ * regularly checking with {@link #check()}.
+ * </p>
+ * 
+ * @author Bernd Rinn
+ */
+public class InterruptedExceptionUnchecked extends CheckedExceptionTunnel
+{
+
+    private static final long serialVersionUID = 1L;
+
+    public InterruptedExceptionUnchecked()
+    {
+        super();
+    }
+
+    public InterruptedExceptionUnchecked(final InterruptedException cause)
+    {
+        super(cause);
+    }
+
+    /**
+     * Checks whether the current thread has been interrupted and, if it has, throw a
+     * {@link InterruptedExceptionUnchecked}.
+     */
+    public final static void check() throws InterruptedExceptionUnchecked
+    {
+        if (Thread.interrupted())
+        {
+            throw new InterruptedExceptionUnchecked();
+        }
+    }
+
+    @Override
+    public InterruptedException getCause()
+    {
+        return (InterruptedException) super.getCause();
+    }
+}
diff --git a/source/java/ch/systemsx/cisd/base/exceptions/StopException.java b/source/java/ch/systemsx/cisd/base/exceptions/StopException.java
new file mode 100644
index 0000000..47c4b5b
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/exceptions/StopException.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.exceptions;
+
+/**
+ * An exception that signals that <code>Thread.stop()</code> has been called on the current thread.
+ *
+ * @author Bernd Rinn
+ */
+public class StopException extends InterruptedExceptionUnchecked
+{
+
+    private static final long serialVersionUID = 1L;
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/exceptions/TimeoutExceptionUnchecked.java b/source/java/ch/systemsx/cisd/base/exceptions/TimeoutExceptionUnchecked.java
new file mode 100644
index 0000000..2768a8b
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/exceptions/TimeoutExceptionUnchecked.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.exceptions;
+
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Exception thrown when a blocking operation times out. This is an unchecked equivalent of
+ * {@link TimeoutException}, that is it is derived from {@link CheckedExceptionTunnel}.
+ * 
+ * @author Bernd Rinn
+ */
+public class TimeoutExceptionUnchecked extends CheckedExceptionTunnel
+{
+
+    private static final long serialVersionUID = 1L;
+
+    public TimeoutExceptionUnchecked()
+    {
+    }
+
+    public TimeoutExceptionUnchecked(String msg)
+    {
+        super(msg);
+    }
+
+    public TimeoutExceptionUnchecked(java.util.concurrent.TimeoutException cause)
+    {
+        super(cause);
+    }
+
+    @Override
+    public TimeoutException getCause()
+    {
+        return (TimeoutException) super.getCause();
+    }
+
+}
\ No newline at end of file
diff --git a/source/java/ch/systemsx/cisd/base/exceptions/package.html b/source/java/ch/systemsx/cisd/base/exceptions/package.html
new file mode 100644
index 0000000..b5b2cd1
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/exceptions/package.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+     "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Exceptions.</title>
+</head>
+<body>
+<p>
+This package provides basic exceptions thrown by CISD software. Note that all exceptions are 
+unchecked.
+</p>
+</body>
+</html> 
\ No newline at end of file
diff --git a/source/java/ch/systemsx/cisd/base/image/IImageTransformer.java b/source/java/ch/systemsx/cisd/base/image/IImageTransformer.java
new file mode 100644
index 0000000..bcc9599
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/image/IImageTransformer.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.image;
+
+import java.awt.image.BufferedImage;
+
+/**
+ * Interface for classes which can transform images. The transformation depends only on some
+ * parameters and an image as input.
+ * 
+ * @author Franz-Josef Elmer
+ */
+public interface IImageTransformer
+{
+    /**
+     * Transforms the specified image. The transformation must <i>not</i> change the input image.
+     * 
+     * @return The transformed image.
+     */
+    public BufferedImage transform(BufferedImage image);
+}
diff --git a/source/java/ch/systemsx/cisd/base/image/IImageTransformerFactory.java b/source/java/ch/systemsx/cisd/base/image/IImageTransformerFactory.java
new file mode 100644
index 0000000..c0c76a2
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/image/IImageTransformerFactory.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.image;
+
+import java.io.Serializable;
+
+import ch.systemsx.cisd.base.annotation.JsonObject;
+
+/**
+ * Factory creating an {@link IImageTransformer}. The parameters of the transformer should be
+ * stored as serializable attributes of concrete implementations of this interface.
+ *
+ * @author Franz-Josef Elmer
+ */
+ at JsonObject(value="IImageTransformerFactory")
+public interface IImageTransformerFactory extends Serializable
+{
+    /**
+     * Creates a transformer object based on the attributes of the factory.
+     */
+    public IImageTransformer createTransformer();
+}
diff --git a/source/java/ch/systemsx/cisd/base/image/IStreamingImageTransformer.java b/source/java/ch/systemsx/cisd/base/image/IStreamingImageTransformer.java
new file mode 100644
index 0000000..5520617
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/image/IStreamingImageTransformer.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.image;
+
+import java.awt.image.BufferedImage;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import ch.systemsx.cisd.base.image.IImageTransformer;
+
+/**
+ * Interface for classes which can transform images in a streaming mode. The transformation depends
+ * only on some parameters and an image as stream of bytes.
+ * 
+ * @author Bernd Rinn
+ */
+public interface IStreamingImageTransformer extends IImageTransformer
+{
+
+    /**
+     * Transforms the image provided as the <var>input</var> stream.
+     * 
+     * @return The transformed image.
+     */
+    public BufferedImage transform(InputStream input);
+
+    /**
+     * Transforms the image provided as the <var>input</var> stream.
+     * 
+     * @return The transformed image as a byte array that constitutes a PNG file.
+     */
+    public byte[] transformToPNG(InputStream input);
+
+    /**
+     * Transforms the image provided as the <var>input</var> stream. Writes the transformed PNG file
+     * to the <var>output</var> stream.
+     */
+    public void transformToPNGStream(InputStream input, OutputStream output);
+}
diff --git a/source/java/ch/systemsx/cisd/base/image/IStreamingImageTransformerFactory.java b/source/java/ch/systemsx/cisd/base/image/IStreamingImageTransformerFactory.java
new file mode 100644
index 0000000..6b4e06f
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/image/IStreamingImageTransformerFactory.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.image;
+
+import ch.systemsx.cisd.base.annotation.JsonObject;
+import ch.systemsx.cisd.base.image.IImageTransformerFactory;
+
+/**
+ * Factory creating an {@link IStreamingImageTransformer}. The parameters of the transformer should
+ * be stored as serializable attributes of concrete implementations of this interface.
+ * 
+ * @author Bernd Rinn
+ */
+ at JsonObject(value="IStreamingImageTransformerFactory")
+public interface IStreamingImageTransformerFactory extends IImageTransformerFactory
+{
+    /**
+     * Creates a transformer object based on the attributes of the factory.
+     */
+    @Override
+    public IStreamingImageTransformer createTransformer();
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/AdapterIInputStreamToInputStream.java b/source/java/ch/systemsx/cisd/base/io/AdapterIInputStreamToInputStream.java
new file mode 100644
index 0000000..0876766
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/AdapterIInputStreamToInputStream.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * An adapter for {@link IInputStream} that extends {@link java.io.InputStream}.
+ *
+ * @author Bernd Rinn
+ */
+public class AdapterIInputStreamToInputStream extends InputStream
+{
+
+    private final IInputStream delegate;
+    
+    public AdapterIInputStreamToInputStream(IInputStream delegate)
+    {
+        this.delegate = delegate;
+    }
+    
+    @Override
+    public int available() throws IOException
+    {
+        try
+        {
+            return delegate.available();
+        } catch (IOExceptionUnchecked ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    @Override
+    public void close() throws IOException
+    {
+        try
+        {
+            delegate.close();
+        } catch (IOExceptionUnchecked ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    @Override
+    public synchronized void mark(int readlimit)
+    {
+        delegate.mark(readlimit);
+    }
+
+    @Override
+    public boolean markSupported()
+    {
+        return delegate.markSupported();
+    }
+
+    @Override
+    public int read() throws IOException
+    {
+        try
+        {
+            return delegate.read();
+        } catch (IOExceptionUnchecked ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException
+    {
+        try
+        {
+            return delegate.read(b, off, len);
+        } catch (IOExceptionUnchecked ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    @Override
+    public int read(byte[] b) throws IOException
+    {
+        try
+        {
+            return delegate.read(b);
+        } catch (IOExceptionUnchecked ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    @Override
+    public synchronized void reset() throws IOException
+    {
+        try
+        {
+            delegate.reset();
+        } catch (IOExceptionUnchecked ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    @Override
+    public long skip(long n) throws IOException
+    {
+        try
+        {
+            return delegate.skip(n);
+        } catch (IOExceptionUnchecked ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    //
+    // Object
+    //
+    
+    @Override
+    public boolean equals(Object obj)
+    {
+        return delegate.equals(obj);
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return delegate.hashCode();
+    }
+
+    @Override
+    public String toString()
+    {
+        return delegate.toString();
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/AdapterIOutputStreamToOutputStream.java b/source/java/ch/systemsx/cisd/base/io/AdapterIOutputStreamToOutputStream.java
new file mode 100644
index 0000000..55b6e5f
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/AdapterIOutputStreamToOutputStream.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * An adapter for {@link IOutputStream} that extends {@link java.io.OutputStream}.
+ *
+ * @author Bernd Rinn
+ */
+public class AdapterIOutputStreamToOutputStream extends OutputStream
+{
+
+    private final IOutputStream delegate;
+    
+    public AdapterIOutputStreamToOutputStream(IOutputStream delegate)
+    {
+        this.delegate = delegate;
+    }
+    
+    @Override
+    public void write(int b) throws IOException
+    {
+        try
+        {
+            delegate.write(b);
+        } catch (IOExceptionUnchecked ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    @Override
+    public void close() throws IOException
+    {
+        try
+        {
+            delegate.close();
+        } catch (IOExceptionUnchecked ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    @Override
+    public void flush() throws IOException
+    {
+        try
+        {
+            delegate.flush();
+        } catch (IOExceptionUnchecked ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    @Override
+    public void write(byte[] b, int off, int len) throws IOException
+    {
+        try
+        {
+            delegate.write(b, off, len);
+        } catch (IOExceptionUnchecked ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    @Override
+    public void write(byte[] b) throws IOException
+    {
+        try
+        {
+            delegate.write(b);
+        } catch (IOExceptionUnchecked ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    //
+    // Object
+    //
+    
+    @Override
+    public boolean equals(Object obj)
+    {
+        return delegate.equals(obj);
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return delegate.hashCode();
+    }
+
+    @Override
+    public String toString()
+    {
+        return delegate.toString();
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/AdapterInputStreamToIInputStream.java b/source/java/ch/systemsx/cisd/base/io/AdapterInputStreamToIInputStream.java
new file mode 100644
index 0000000..c9e46a5
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/AdapterInputStreamToIInputStream.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.io;
+
+import java.io.IOException;
+
+import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * An adapter for {@link java.io.InputStream} that implements {@link IInputStream}.
+ *
+ * @author Bernd Rinn
+ */
+public class AdapterInputStreamToIInputStream implements IInputStream
+{
+    
+    private final java.io.InputStream delegate;
+    
+    public AdapterInputStreamToIInputStream(java.io.InputStream delegate)
+    {
+        this.delegate = delegate;
+    }
+
+    @Override
+    public int available() throws IOExceptionUnchecked
+    {
+        try
+        {
+            return delegate.available();
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public void close() throws IOExceptionUnchecked
+    {
+        try
+        {
+            delegate.close();
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public void mark(int readlimit)
+    {
+        delegate.mark(readlimit);
+    }
+
+    @Override
+    public boolean markSupported()
+    {
+        return delegate.markSupported();
+    }
+
+    @Override
+    public int read() throws IOExceptionUnchecked
+    {
+        try
+        {
+            return delegate.read();
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOExceptionUnchecked
+    {
+        try
+        {
+            return delegate.read(b, off, len);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public int read(byte[] b) throws IOExceptionUnchecked
+    {
+        try
+        {
+            return delegate.read(b);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public void reset() throws IOExceptionUnchecked
+    {
+        try
+        {
+            delegate.reset();
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public long skip(long n) throws IOExceptionUnchecked
+    {
+        try
+        {
+            return delegate.skip(n);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    //
+    // Object
+    //
+    
+    @Override
+    public String toString()
+    {
+        return delegate.toString();
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        return delegate.equals(obj);
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return delegate.hashCode();
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/AdapterOutputStreamToIOutputStream.java b/source/java/ch/systemsx/cisd/base/io/AdapterOutputStreamToIOutputStream.java
new file mode 100644
index 0000000..0720195
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/AdapterOutputStreamToIOutputStream.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.io;
+
+import java.io.IOException;
+
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * An adapter for {@link java.io.OutputStream} that implements {@link IOutputStream}.
+ *
+ * @author Bernd Rinn
+ */
+public class AdapterOutputStreamToIOutputStream implements IOutputStream
+{
+    
+    private final java.io.OutputStream delegate;
+
+    public AdapterOutputStreamToIOutputStream(java.io.OutputStream delegate)
+    {
+        this.delegate = delegate;
+    }
+
+    //
+    // IOutputStream
+    //
+    
+    @Override
+    public void write(byte[] b, int off, int len) throws IOExceptionUnchecked
+    {
+        try
+        {
+            delegate.write(b, off, len);
+        } catch (IOException ex)
+        {
+            throw new IOExceptionUnchecked(ex);
+        }
+    }
+
+    @Override
+    public void write(byte[] b) throws IOExceptionUnchecked
+    {
+        try
+        {
+            delegate.write(b);
+        } catch (IOException ex)
+        {
+            throw new IOExceptionUnchecked(ex);
+        }
+    }
+
+    @Override
+    public void write(int b) throws IOExceptionUnchecked
+    {
+        try
+        {
+            delegate.write(b);
+        } catch (IOException ex)
+        {
+            throw new IOExceptionUnchecked(ex);
+        }
+    }
+
+    @Override
+    public void close() throws IOExceptionUnchecked
+    {
+        try
+        {
+            delegate.close();
+        } catch (IOException ex)
+        {
+            throw new IOExceptionUnchecked(ex);
+        }
+    }
+
+    @Override
+    public void flush() throws IOExceptionUnchecked
+    {
+        try
+        {
+            delegate.flush();
+        } catch (IOException ex)
+        {
+            throw new IOExceptionUnchecked(ex);
+        }
+    }
+
+    @Override
+    public void synchronize() throws IOExceptionUnchecked
+    {
+        flush();
+    }
+
+    //
+    // Object
+    //
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        return delegate.equals(obj);
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return delegate.hashCode();
+    }
+
+    @Override
+    public String toString()
+    {
+        return delegate.toString();
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/ByteBufferRandomAccessFile.java b/source/java/ch/systemsx/cisd/base/io/ByteBufferRandomAccessFile.java
new file mode 100644
index 0000000..1055b8b
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/ByteBufferRandomAccessFile.java
@@ -0,0 +1,455 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.io;
+
+import java.io.EOFException;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import ch.systemsx.cisd.base.convert.NativeData;
+import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * An implementation of {@link IRandomAccessFile} based on a {@link ByteBuffer}.
+ * <p>
+ * Does <i>not</i> implement {@link IRandomAccessFile#readLine()}.
+ * 
+ * @author Bernd Rinn
+ */
+public class ByteBufferRandomAccessFile implements IRandomAccessFile
+{
+
+    private final ByteBuffer buf;
+
+    private void addToLength(int newItemLen)
+    {
+        final int rem = buf.remaining();
+        if (newItemLen > rem)
+        {
+            buf.limit(buf.limit() + (newItemLen - rem));
+        }
+    }
+
+    /**
+     * Creates a {@link IRandomAccessFile} wrapper for the given <var>buf</var>.
+     * 
+     * @param buf The buffer to wrap.
+     * @param initialLength The initially set length (corresponds to the {@link ByteBuffer#limit()}
+     *            ).
+     */
+    public ByteBufferRandomAccessFile(ByteBuffer buf, int initialLength)
+    {
+        this(buf);
+        setLength(initialLength);
+    }
+
+    /**
+     * Creates a {@link IRandomAccessFile} wrapper for the given <var>buf</var>. Does not change the
+     * {@link ByteBuffer#limit()} of <var>buf</var>.
+     * 
+     * @param buf The buffer to wrap.
+     */
+    public ByteBufferRandomAccessFile(ByteBuffer buf)
+    {
+        this.buf = buf;
+    }
+
+    /**
+     * Creates a {@link IRandomAccessFile} wrapper for the given <var>array</var>.
+     * 
+     * @param array The byte array to wrap.
+     * @param initialLength The initially set length.
+     */
+    public ByteBufferRandomAccessFile(byte[] array, int initialLength)
+    {
+        this(array);
+        setLength(initialLength);
+    }
+
+    /**
+     * Creates a {@link IRandomAccessFile} wrapper for the given <var>array</var>. The initial
+     * {@link ByteBuffer#limit()} will be <code>array.length</code>.
+     * 
+     * @param array The byte array to wrap.
+     */
+    public ByteBufferRandomAccessFile(byte[] array)
+    {
+        this(ByteBuffer.wrap(array));
+    }
+
+    /**
+     * Creates a {@link IRandomAccessFile} wrapper for a {@link ByteBuffer} with
+     * <var>capacity</var>. The initial {@link ByteBuffer#limit()} will be <code>0</code>.
+     * 
+     * @param capacity The maximal size of the {@link ByteBuffer}.
+     */
+    public ByteBufferRandomAccessFile(int capacity)
+    {
+        this(ByteBuffer.allocate(capacity));
+        setLength(0);
+    }
+
+    @Override
+    public ByteOrder getByteOrder()
+    {
+        return buf.order();
+    }
+
+    @Override
+    public void setByteOrder(ByteOrder byteOrder)
+    {
+        buf.order(byteOrder);
+    }
+
+    @Override
+    public void readFully(byte[] b) throws IOExceptionUnchecked
+    {
+        readFully(b, 0, b.length);
+    }
+
+    @Override
+    public void readFully(byte[] b, int off, int len) throws IOExceptionUnchecked
+    {
+        if (available0() == -1)
+        {
+            throw new IOExceptionUnchecked(new EOFException());
+        } else
+        {
+            buf.get(b, off, len);
+        }
+    }
+
+    @Override
+    public int skipBytes(int n) throws IOExceptionUnchecked
+    {
+        if (n <= 0)
+        {
+            return 0;
+        }
+        final int pos = buf.position();
+        final int len = buf.limit();
+        final int newpos = Math.min(len, pos + n);
+        buf.position(newpos);
+        return (newpos - pos);
+    }
+
+    @Override
+    public void close() throws IOExceptionUnchecked
+    {
+        // NOOP
+    }
+
+    @Override
+    public int read() throws IOExceptionUnchecked
+    {
+        return buf.get() & 0xff;
+    }
+
+    @Override
+    public int read(byte[] b) throws IOExceptionUnchecked
+    {
+        return read(b, 0, b.length);
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOExceptionUnchecked
+    {
+        final int bytesRead = Math.min(available0(), len);
+        if (bytesRead < 0)
+        {
+            return bytesRead;
+        }
+        buf.get(b, off, bytesRead);
+        return bytesRead;
+    }
+
+    @Override
+    public long skip(long n) throws IOExceptionUnchecked
+    {
+        if (n > Integer.MAX_VALUE)
+        {
+            throw new IndexOutOfBoundsException();
+        }
+        return skipBytes((int) n);
+    }
+    
+    private int available0() throws IOExceptionUnchecked
+    {
+        return (buf.remaining() == 0) ? -1 : buf.remaining();
+    }
+
+    @Override
+    public int available() throws IOExceptionUnchecked
+    {
+        return buf.remaining();
+    }
+
+    @Override
+    public void mark(int readlimit)
+    {
+        buf.mark();
+    }
+
+    @Override
+    public void reset() throws IOExceptionUnchecked
+    {
+        buf.reset();
+    }
+
+    @Override
+    public boolean markSupported()
+    {
+        return true;
+    }
+
+    @Override
+    public void flush() throws IOExceptionUnchecked
+    {
+        // NOOP
+    }
+
+    @Override
+    public void synchronize() throws IOExceptionUnchecked
+    {
+        // NOOP
+    }
+
+    @Override
+    public long getFilePointer() throws IOExceptionUnchecked
+    {
+        return buf.position();
+    }
+
+    @Override
+    public void seek(long pos) throws IOExceptionUnchecked
+    {
+        buf.position((int) pos);
+    }
+
+    @Override
+    public long length() throws IOExceptionUnchecked
+    {
+        return buf.limit();
+    }
+
+    @Override
+    public void setLength(long newLength) throws IOExceptionUnchecked
+    {
+        buf.limit((int) newLength);
+    }
+
+    @Override
+    public boolean readBoolean() throws IOExceptionUnchecked
+    {
+        return buf.get() != 0;
+    }
+
+    @Override
+    public byte readByte() throws IOExceptionUnchecked
+    {
+        return buf.get();
+    }
+
+    @Override
+    public int readUnsignedByte() throws IOExceptionUnchecked
+    {
+        return buf.get() & 0xff;
+    }
+
+    @Override
+    public short readShort() throws IOExceptionUnchecked
+    {
+        return buf.getShort();
+    }
+
+    @Override
+    public int readUnsignedShort() throws IOExceptionUnchecked
+    {
+        return buf.getShort() & 0xffff;
+    }
+
+    @Override
+    public char readChar() throws IOExceptionUnchecked
+    {
+        return buf.getChar();
+    }
+
+    @Override
+    public int readInt() throws IOExceptionUnchecked
+    {
+        return buf.getInt();
+    }
+
+    @Override
+    public long readLong() throws IOExceptionUnchecked
+    {
+        return buf.getLong();
+    }
+
+    @Override
+    public float readFloat() throws IOExceptionUnchecked
+    {
+        return buf.getFloat();
+    }
+
+    @Override
+    public double readDouble() throws IOExceptionUnchecked
+    {
+        return buf.getDouble();
+    }
+
+    /**
+     * @throws UnsupportedOperationException
+     */
+    @Override
+    public String readLine() throws UnsupportedOperationException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String readUTF()
+    {
+        try
+        {
+            final byte[] strBuf = new byte[readUnsignedShort()];
+            buf.get(strBuf);
+            return new String(strBuf, "UTF-8");
+        } catch (UnsupportedEncodingException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public void write(int b) throws IOExceptionUnchecked
+    {
+        addToLength(1);
+        buf.put((byte) b);
+    }
+
+    @Override
+    public void write(byte[] b) throws IOExceptionUnchecked
+    {
+        addToLength(b.length);
+        buf.put(b);
+    }
+
+    @Override
+    public void write(byte[] b, int off, int len) throws IOExceptionUnchecked
+    {
+        addToLength(len);
+        buf.put(b, off, len);
+    }
+
+    @Override
+    public void writeBoolean(boolean v) throws IOExceptionUnchecked
+    {
+        addToLength(1);
+        buf.put((byte) (v ? 1 : 0));
+    }
+
+    @Override
+    public void writeByte(int v) throws IOExceptionUnchecked
+    {
+        write((byte) v);
+    }
+
+    @Override
+    public void writeShort(int v) throws IOExceptionUnchecked
+    {
+        addToLength(NativeData.SHORT_SIZE);
+        buf.putShort((short) v);
+    }
+
+    @Override
+    public void writeChar(int v) throws IOExceptionUnchecked
+    {
+        addToLength(NativeData.CHAR_SIZE);
+        buf.putChar((char) v);
+    }
+
+    @Override
+    public void writeInt(int v) throws IOExceptionUnchecked
+    {
+        addToLength(NativeData.INT_SIZE);
+        buf.putInt(v);
+    }
+
+    @Override
+    public void writeLong(long v) throws IOExceptionUnchecked
+    {
+        addToLength(NativeData.LONG_SIZE);
+        buf.putLong(v);
+    }
+
+    @Override
+    public void writeFloat(float v) throws IOExceptionUnchecked
+    {
+        addToLength(NativeData.FLOAT_SIZE);
+        buf.putFloat(v);
+    }
+
+    @Override
+    public void writeDouble(double v) throws IOExceptionUnchecked
+    {
+        addToLength(NativeData.DOUBLE_SIZE);
+        buf.putDouble(v);
+    }
+
+    @Override
+    public void writeBytes(String s) throws IOExceptionUnchecked
+    {
+        final int len = s.length();
+        addToLength(len);
+        for (int i = 0; i < len; i++)
+        {
+            buf.put((byte) s.charAt(i));
+        }
+    }
+
+    @Override
+    public void writeChars(String s) throws IOExceptionUnchecked
+    {
+        final int len = s.length();
+        addToLength(NativeData.CHAR_SIZE * len);
+        for (int i = 0; i < len; i++)
+        {
+            final int v = s.charAt(i);
+            buf.put((byte) ((v >>> 8) & 0xFF));
+            buf.put((byte) ((v >>> 0) & 0xFF));
+        }
+    }
+
+    @Override
+    public void writeUTF(String str) throws UnsupportedOperationException
+    {
+        try
+        {
+            final byte[] strBuf = str.getBytes("UTF-8");
+            addToLength(NativeData.SHORT_SIZE + strBuf.length);
+            writeShort(strBuf.length);
+            write(strBuf);
+        } catch (UnsupportedEncodingException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/ICloseable.java b/source/java/ch/systemsx/cisd/base/io/ICloseable.java
new file mode 100644
index 0000000..1f3073e
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/ICloseable.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.io;
+
+import java.io.IOException;
+
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * A role that allows to close resource. Like {@link java.io.Closeable} but doesn't throw an
+ * {@link IOException} but a {@link IOExceptionUnchecked} instead.
+ * 
+ * @author Bernd Rinn
+ */
+public interface ICloseable
+{
+
+    /**
+     * Closes the resource.
+     */
+    public void close() throws IOExceptionUnchecked;
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/IInputStream.java b/source/java/ch/systemsx/cisd/base/io/IInputStream.java
new file mode 100644
index 0000000..c43e112
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/IInputStream.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.io;
+
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * An interface for {@link java.io.InputStream}.
+ *
+ * @author Bernd Rinn
+ */
+public interface IInputStream
+{
+
+    /**
+     * @see java.io.InputStream#read()
+     */
+    public int read() throws IOExceptionUnchecked;
+    
+    /**
+     * @see java.io.InputStream#read(byte[])
+     */
+    public int read(byte b[]) throws IOExceptionUnchecked;
+    
+    /**
+     * @see java.io.InputStream#read(byte[], int, int)
+     */
+    public int read(byte b[], int off, int len) throws IOExceptionUnchecked;
+    
+    /**
+     * @see java.io.InputStream#skip(long)
+     */
+    public long skip(long n) throws IOExceptionUnchecked;
+    
+    /**
+     * @see java.io.InputStream#available()
+     */
+    public int available() throws IOExceptionUnchecked;
+
+    /**
+     * @see java.io.InputStream#close()
+     */
+    public void close() throws IOExceptionUnchecked;
+    
+    /**
+     * @see java.io.InputStream#mark(int)
+     */
+    public void mark(int readlimit);
+    
+    /**
+     * @see java.io.InputStream#reset()
+     */
+    public void reset() throws IOExceptionUnchecked;
+
+    /**
+     * @see java.io.InputStream#markSupported()
+     */
+    public boolean markSupported();
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/IOutputStream.java b/source/java/ch/systemsx/cisd/base/io/IOutputStream.java
new file mode 100644
index 0000000..7445d49
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/IOutputStream.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.io;
+
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * An interface for {@link java.io.OutputStream}.
+ * 
+ * @author Bernd Rinn
+ */
+public interface IOutputStream extends ICloseable, ISynchronizable
+{
+    /**
+     * @see java.io.OutputStream#write(int)
+     */
+    public void write(int b) throws IOExceptionUnchecked;
+
+    /**
+     * @see java.io.OutputStream#write(byte[])
+     */
+    public void write(byte b[]) throws IOExceptionUnchecked;
+
+    /**
+     * @see java.io.OutputStream#write(byte[], int, int)
+     */
+    public void write(byte b[], int off, int len) throws IOExceptionUnchecked;
+
+    /**
+     * @see java.io.OutputStream#flush()
+     */
+    public void flush() throws IOExceptionUnchecked;
+
+    /**
+     * @see java.io.OutputStream#flush()
+     */
+    @Override
+    public void synchronize() throws IOExceptionUnchecked;
+
+    /**
+     * @see java.io.OutputStream#close()
+     */
+    @Override
+    public void close() throws IOExceptionUnchecked;
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/IRandomAccessFile.java b/source/java/ch/systemsx/cisd/base/io/IRandomAccessFile.java
new file mode 100644
index 0000000..8cd83ec
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/IRandomAccessFile.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.io;
+
+import java.io.Closeable;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.nio.ByteOrder;
+
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * The interface of {@link java.io.RandomAccessFile}.
+ * 
+ * @author Bernd Rinn
+ */
+public interface IRandomAccessFile extends DataInput, DataOutput, Closeable, IInputStream,
+        IOutputStream
+{
+    /**
+     * Gets the byte-order (endiness) of the random access file. Default is network-byte order
+     * (big-endian).
+     */
+    public ByteOrder getByteOrder();
+
+    /**
+     * Sets the byte-order (endiness) of the random access file.
+     */
+    public void setByteOrder(ByteOrder byteOrder);
+
+    //
+    // RandomAccessFile
+    //
+
+    /**
+     * Returns the current offset in this file.
+     * 
+     * @return the offset from the beginning of the file, in bytes, at which the next read or write
+     *         occurs.
+     * @exception IOExceptionUnchecked if an I/O error occurs.
+     */
+    public long getFilePointer() throws IOExceptionUnchecked;
+
+    /**
+     * Sets the file-pointer offset, measured from the beginning of this file, at which the next
+     * read or write occurs. The offset may be set beyond the end of the file. Setting the offset
+     * beyond the end of the file does not change the file length. The file length will change only
+     * by writing after the offset has been set beyond the end of the file.
+     * 
+     * @param pos the offset position, measured in bytes from the beginning of the file, at which to
+     *            set the file pointer.
+     * @exception IOExceptionUnchecked if <code>pos</code> is less than <code>0</code> or if an I/O
+     *                error occurs.
+     */
+    public void seek(long pos) throws IOExceptionUnchecked;
+
+    /**
+     * Returns the length of this file.
+     * 
+     * @return the length of this file, measured in bytes.
+     * @exception IOExceptionUnchecked if an I/O error occurs.
+     */
+    public long length() throws IOExceptionUnchecked;
+
+    /**
+     * Sets the length of this file.
+     * <p>
+     * If the present length of the file as returned by the <code>length</code> method is greater
+     * than the <code>newLength</code> argument then the file will be truncated. In this case, if
+     * the file offset as returned by the <code>getFilePointer</code> method is greater than
+     * <code>newLength</code> then after this method returns the offset will be equal to
+     * <code>newLength</code>.
+     * <p>
+     * If the present length of the file as returned by the <code>length</code> method is smaller
+     * than the <code>newLength</code> argument then the file will be extended. In this case, the
+     * contents of the extended portion of the file are not defined.
+     * 
+     * @param newLength The desired length of the file
+     * @exception IOExceptionUnchecked If an I/O error occurs
+     */
+    public void setLength(long newLength) throws IOExceptionUnchecked;
+
+    //
+    // DataInput
+    //
+
+    /**
+     * @see DataInput#readFully(byte[])
+     */
+    @Override
+    public void readFully(byte b[]) throws IOExceptionUnchecked;
+
+    /**
+     * @see DataInput#readFully(byte[], int, int)
+     */
+    @Override
+    public void readFully(byte b[], int off, int len) throws IOExceptionUnchecked;
+
+    /**
+     * @see DataInput#skipBytes(int)
+     */
+    @Override
+    public int skipBytes(int n) throws IOExceptionUnchecked;
+
+    /**
+     * @see DataInput#readBoolean()
+     */
+    @Override
+    public boolean readBoolean() throws IOExceptionUnchecked;
+
+    /**
+     * @see DataInput#readByte()
+     */
+    @Override
+    public byte readByte() throws IOExceptionUnchecked;
+
+    /**
+     * @see DataInput#readUnsignedByte()
+     */
+    @Override
+    public int readUnsignedByte() throws IOExceptionUnchecked;
+
+    /**
+     * @see DataInput#readShort()
+     */
+    @Override
+    public short readShort() throws IOExceptionUnchecked;
+
+    /**
+     * @see DataInput#readUnsignedShort()
+     */
+    @Override
+    public int readUnsignedShort() throws IOExceptionUnchecked;
+
+    /**
+     * @see DataInput#readChar()
+     */
+    @Override
+    public char readChar() throws IOExceptionUnchecked;
+
+    /**
+     * @see DataInput#readInt()
+     */
+    @Override
+    public int readInt() throws IOExceptionUnchecked;
+
+    /**
+     * @see DataInput#readLong()
+     */
+    @Override
+    public long readLong() throws IOExceptionUnchecked;
+
+    /**
+     * @see DataInput#readFloat()
+     */
+    @Override
+    public float readFloat() throws IOExceptionUnchecked;
+
+    /**
+     * @see DataInput#readDouble()
+     */
+    @Override
+    public double readDouble() throws IOExceptionUnchecked;
+
+    /**
+     * @see DataInput#readLine()
+     */
+    @Override
+    public String readLine() throws IOExceptionUnchecked;
+
+    /**
+     * @see DataInput#readUTF()
+     */
+    @Override
+    public String readUTF() throws IOExceptionUnchecked;
+
+    //
+    // DataOutput
+    //
+
+    /**
+     * @see DataOutput#write(int)
+     */
+    @Override
+    public void write(int b) throws IOExceptionUnchecked;
+
+    /**
+     * @see DataOutput#write(byte[])
+     */
+    @Override
+    public void write(byte b[]) throws IOExceptionUnchecked;
+
+    /**
+     * @see DataOutput#write(byte[], int, int)
+     */
+    @Override
+    public void write(byte b[], int off, int len) throws IOExceptionUnchecked;
+
+    /**
+     * @see DataOutput#writeBoolean(boolean)
+     */
+    @Override
+    public void writeBoolean(boolean v) throws IOExceptionUnchecked;
+
+    /**
+     * @see DataOutput#writeByte(int)
+     */
+    @Override
+    public void writeByte(int v) throws IOExceptionUnchecked;
+
+    /**
+     * @see DataOutput#writeShort(int)
+     */
+    @Override
+    public void writeShort(int v) throws IOExceptionUnchecked;
+
+    /**
+     * @see DataOutput#writeChar(int)
+     */
+    @Override
+    public void writeChar(int v) throws IOExceptionUnchecked;
+
+    /**
+     * @see DataOutput#writeInt(int)
+     */
+    @Override
+    public void writeInt(int v) throws IOExceptionUnchecked;
+
+    /**
+     * @see DataOutput#writeLong(long)
+     */
+    @Override
+    public void writeLong(long v) throws IOExceptionUnchecked;
+
+    /**
+     * @see DataOutput#writeFloat(float)
+     */
+    @Override
+    public void writeFloat(float v) throws IOExceptionUnchecked;
+
+    /**
+     * @see DataOutput#writeDouble(double)
+     */
+    @Override
+    public void writeDouble(double v) throws IOExceptionUnchecked;
+
+    /**
+     * @see DataOutput#writeBytes(String)
+     */
+    @Override
+    public void writeBytes(String s) throws IOExceptionUnchecked;
+
+    /**
+     * @see DataOutput#writeChars(String)
+     */
+    @Override
+    public void writeChars(String s) throws IOExceptionUnchecked;
+
+    /**
+     * @see DataOutput#writeUTF(String)
+     */
+    @Override
+    public void writeUTF(String str) throws IOExceptionUnchecked;
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/ISynchronizable.java b/source/java/ch/systemsx/cisd/base/io/ISynchronizable.java
new file mode 100644
index 0000000..67c1591
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/ISynchronizable.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.io;
+
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * A roles that allows to synchronize a resource with an underlying resource.
+ *
+ * @author Bernd Rinn
+ */
+public interface ISynchronizable
+{
+
+    /**
+     * Performs a synchronization of the resource.
+     */
+    public void synchronize() throws IOExceptionUnchecked;
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/io/RandomAccessFileImpl.java b/source/java/ch/systemsx/cisd/base/io/RandomAccessFileImpl.java
new file mode 100644
index 0000000..e5f1ce7
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/io/RandomAccessFileImpl.java
@@ -0,0 +1,648 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.io;
+
+import static ch.systemsx.cisd.base.convert.NativeData.changeByteOrder;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
+
+import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * The file implementation of {@link IRandomAccessFile}.
+ * 
+ * @author Bernd Rinn
+ */
+public class RandomAccessFileImpl implements IRandomAccessFile
+{
+
+    private final RandomAccessFile randomAccessFile;
+
+    private ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;
+
+    private boolean changeByteOrder = ByteOrder.LITTLE_ENDIAN.equals(byteOrder);
+
+    private long markedPosition = -1;
+
+    public RandomAccessFileImpl(RandomAccessFile randomAccessFile)
+    {
+        this.randomAccessFile = randomAccessFile;
+    }
+
+    public RandomAccessFileImpl(String name, String mode) throws IOExceptionUnchecked
+    {
+        try
+        {
+            this.randomAccessFile = new RandomAccessFile(name, mode);
+        } catch (FileNotFoundException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    public RandomAccessFileImpl(File file, String mode) throws IOExceptionUnchecked
+    {
+        try
+        {
+            this.randomAccessFile = new RandomAccessFile(file, mode);
+        } catch (FileNotFoundException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    public final FileDescriptor getFD() throws IOException
+    {
+        return randomAccessFile.getFD();
+    }
+
+    public final FileChannel getChannel()
+    {
+        return randomAccessFile.getChannel();
+    }
+
+    @Override
+    public ByteOrder getByteOrder()
+    {
+        return byteOrder;
+    }
+
+    @Override
+    public void setByteOrder(ByteOrder byteOrder)
+    {
+        this.byteOrder = byteOrder;
+        this.changeByteOrder = ByteOrder.LITTLE_ENDIAN.equals(byteOrder);
+    }
+
+    @Override
+    public int read() throws IOExceptionUnchecked
+    {
+        try
+        {
+            return randomAccessFile.read();
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOExceptionUnchecked
+    {
+        try
+        {
+            return randomAccessFile.read(b, off, len);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public int read(byte[] b) throws IOExceptionUnchecked
+    {
+        try
+        {
+            return randomAccessFile.read(b);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final void readFully(byte[] b) throws IOExceptionUnchecked
+    {
+        try
+        {
+            randomAccessFile.readFully(b);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final void readFully(byte[] b, int off, int len) throws IOExceptionUnchecked
+    {
+        try
+        {
+            randomAccessFile.readFully(b, off, len);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public int skipBytes(int n) throws IOExceptionUnchecked
+    {
+        try
+        {
+            return randomAccessFile.skipBytes(n);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public void write(int b) throws IOExceptionUnchecked
+    {
+        try
+        {
+            randomAccessFile.write(b);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public void write(byte[] b) throws IOExceptionUnchecked
+    {
+        try
+        {
+            randomAccessFile.write(b);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public void write(byte[] b, int off, int len) throws IOExceptionUnchecked
+    {
+        try
+        {
+            randomAccessFile.write(b, off, len);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public long getFilePointer() throws IOExceptionUnchecked
+    {
+        try
+        {
+            return randomAccessFile.getFilePointer();
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public void seek(long pos) throws IOExceptionUnchecked
+    {
+        try
+        {
+            randomAccessFile.seek(pos);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public long length() throws IOExceptionUnchecked
+    {
+        try
+        {
+            return randomAccessFile.length();
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public void setLength(long newLength) throws IOExceptionUnchecked
+    {
+        try
+        {
+            randomAccessFile.setLength(newLength);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public void close() throws IOExceptionUnchecked
+    {
+        try
+        {
+            randomAccessFile.close();
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final boolean readBoolean() throws IOExceptionUnchecked
+    {
+        try
+        {
+            return randomAccessFile.readBoolean();
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final byte readByte() throws IOExceptionUnchecked
+    {
+        try
+        {
+            return randomAccessFile.readByte();
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final int readUnsignedByte() throws IOExceptionUnchecked
+    {
+        try
+        {
+            return randomAccessFile.readUnsignedByte();
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final short readShort() throws IOExceptionUnchecked
+    {
+        try
+        {
+            final short s = randomAccessFile.readShort();
+            return changeByteOrder ? changeByteOrder(s) : s;
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final int readUnsignedShort() throws IOExceptionUnchecked
+    {
+        return readShort() & 0xffff;
+    }
+
+    @Override
+    public final char readChar() throws IOExceptionUnchecked
+    {
+        try
+        {
+            final char c = randomAccessFile.readChar(); 
+            return changeByteOrder ? changeByteOrder(c) : c;
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final int readInt() throws IOExceptionUnchecked
+    {
+        try
+        {
+            final int i = randomAccessFile.readInt();
+            return changeByteOrder ? changeByteOrder(i) : i;
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final long readLong() throws IOExceptionUnchecked
+    {
+        try
+        {
+            final long l = randomAccessFile.readLong();
+            return changeByteOrder ? changeByteOrder(l) : l;
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final float readFloat() throws IOExceptionUnchecked
+    {
+        try
+        {
+            final float f = randomAccessFile.readFloat();
+            return changeByteOrder ? changeByteOrder(f) : f;
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final double readDouble() throws IOExceptionUnchecked
+    {
+        try
+        {
+            final double d = randomAccessFile.readDouble();
+            return changeByteOrder ? changeByteOrder(d) : d;
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final String readLine() throws IOExceptionUnchecked
+    {
+        try
+        {
+            return randomAccessFile.readLine();
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final String readUTF() throws IOExceptionUnchecked
+    {
+        try
+        {
+            return randomAccessFile.readUTF();
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final void writeBoolean(boolean v) throws IOExceptionUnchecked
+    {
+        try
+        {
+            randomAccessFile.writeBoolean(v);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final void writeByte(int v) throws IOExceptionUnchecked
+    {
+        try
+        {
+            randomAccessFile.writeByte(v);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final void writeShort(int v) throws IOExceptionUnchecked
+    {
+        try
+        {
+            randomAccessFile.writeShort(changeByteOrder ? changeByteOrder(v) : v);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final void writeChar(int v) throws IOExceptionUnchecked
+    {
+        try
+        {
+            randomAccessFile.writeChar(changeByteOrder ? changeByteOrder(v) : v);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final void writeInt(int v) throws IOExceptionUnchecked
+    {
+        try
+        {
+            randomAccessFile.writeInt(changeByteOrder ? changeByteOrder(v) : v);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final void writeLong(long v) throws IOExceptionUnchecked
+    {
+        try
+        {
+            randomAccessFile.writeLong(changeByteOrder ? changeByteOrder(v) : v);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final void writeFloat(float v) throws IOExceptionUnchecked
+    {
+        try
+        {
+            randomAccessFile.writeFloat(changeByteOrder ? changeByteOrder(v) : v);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final void writeDouble(double v) throws IOExceptionUnchecked
+    {
+        try
+        {
+            randomAccessFile.writeDouble(changeByteOrder ? changeByteOrder(v) : v);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final void writeBytes(String s) throws IOExceptionUnchecked
+    {
+        try
+        {
+            randomAccessFile.writeBytes(s);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final void writeChars(String s) throws IOExceptionUnchecked
+    {
+        try
+        {
+            randomAccessFile.writeChars(s);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public final void writeUTF(String str) throws IOExceptionUnchecked
+    {
+        try
+        {
+            randomAccessFile.writeUTF(str);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public long skip(long n) throws IOExceptionUnchecked
+    {
+        if (n <= 0)
+        {
+            return 0;
+        }
+        try
+        {
+            final long pos = randomAccessFile.getFilePointer();
+            final long len = randomAccessFile.length();
+            final long newpos = Math.min(len, pos + n);
+            randomAccessFile.seek(newpos);
+            return (int) (newpos - pos);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public int available() throws IOExceptionUnchecked
+    {
+        try
+        {
+            return (int) Math.min(randomAccessFile.length() - randomAccessFile.getFilePointer(), Integer.MAX_VALUE);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public void mark(int readlimit)
+    {
+        try
+        {
+            markedPosition = randomAccessFile.getFilePointer();
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public void reset() throws IOExceptionUnchecked
+    {
+        if (markedPosition == -1)
+        {
+            throw new IOExceptionUnchecked(new IOException("mark() not called"));
+        }
+        try
+        {
+            randomAccessFile.seek(markedPosition);
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public boolean markSupported()
+    {
+        return true;
+    }
+
+    @Override
+    public void flush() throws IOExceptionUnchecked
+    {
+        // NOOP
+    }
+
+    @Override
+    public void synchronize() throws IOExceptionUnchecked
+    {
+        try
+        {
+            randomAccessFile.getFD().sync();
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    //
+    // Object
+    //
+
+    @Override
+    public int hashCode()
+    {
+        return randomAccessFile.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        return randomAccessFile.equals(obj);
+    }
+
+    @Override
+    public String toString()
+    {
+        return randomAccessFile.toString();
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/mdarray/MDAbstractArray.java b/source/java/ch/systemsx/cisd/base/mdarray/MDAbstractArray.java
new file mode 100644
index 0000000..d2dd838
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/mdarray/MDAbstractArray.java
@@ -0,0 +1,480 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.mdarray;
+
+import java.io.Serializable;
+import java.util.Iterator;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.ClassUtils;
+
+/**
+ * Base class of a multi-dimensional array. The <var>dimensions</var> of an array are provided
+ * separately from the data as a <code>int[]</code>.
+ * <p>
+ * The array can grow or shrink in the first dimension (<var>dimensions[0]</var>). Dimensions
+ * <code>1...n</code> are static. They are said to form a <i>hyper-row</i>.
+ * 
+ * @author Bernd Rinn
+ */
+public abstract class MDAbstractArray<T> implements Serializable,
+        Iterable<MDAbstractArray<T>.ArrayEntry>
+{
+    private static final long serialVersionUID = 1L;
+
+    protected final int[] dimensions;
+
+    protected int hyperRowLength;
+
+    protected int capacityHyperRows;
+
+    protected int size;
+
+    /**
+     * A class to represent an entry (index and value) of a {@link MDArray}, used for iteration.
+     */
+    public class ArrayEntry
+    {
+        private final int linearIndex;
+
+        ArrayEntry(int linearIndex)
+        {
+            this.linearIndex = linearIndex;
+        }
+
+        /**
+         * The multi-dimensional index of this entry.
+         */
+        public int[] getIndex()
+        {
+            return computeReverseIndex(linearIndex);
+        }
+
+        /**
+         * The linear index of this entry.
+         */
+        public int getLinearIndex()
+        {
+            return linearIndex;
+        }
+
+        /**
+         * The value of this entry.
+         */
+        public T getValue()
+        {
+            return getAsObject(linearIndex);
+        }
+    }
+
+    protected MDAbstractArray(int[] dimensions, int arrayLength, int capacityHyperRows)
+    {
+        assert dimensions != null;
+
+        this.dimensions = dimensions;
+        this.hyperRowLength = computeHyperRowLength(dimensions);
+        if (hyperRowLength == 0)
+        {
+            this.capacityHyperRows = 0;
+            this.size = 0;
+        } else
+        {
+            if (arrayLength % hyperRowLength != 0)
+            {
+                throw new IllegalArgumentException("Actual array length " + arrayLength
+                        + " does not match hyper-row length " + hyperRowLength + ".");
+            }
+            this.capacityHyperRows =
+                    (capacityHyperRows > 0) ? capacityHyperRows : Math.max(dimensions[0],
+                            arrayLength / hyperRowLength);
+            this.size = dimensions[0] * hyperRowLength;
+        }
+    }
+
+    protected int computeHyperRowLength(@SuppressWarnings("hiding")
+    int[] dimensions)
+    {
+        int hyperRowLen = 1;
+        for (int i = 1; i < dimensions.length; ++i)
+        {
+            hyperRowLen *= dimensions[i];
+        }
+        return hyperRowLen;
+    }
+
+    /**
+     * Returns the rank of the array.
+     */
+    public int rank()
+    {
+        return dimensions.length;
+    }
+
+    /**
+     * Returns the extent of the array along its <var>dim</var>-th axis.
+     */
+    public int size(int dim)
+    {
+        assert dim < dimensions.length;
+
+        return dimensions[dim];
+    }
+
+    /**
+     * Returns a copy of the dimensions of the multi-dimensional array.
+     */
+    public int[] dimensions()
+    {
+        return dimensions.clone();
+    }
+
+    /**
+     * Returns a copy of the dimensions of the multi-dimensional array as <code>long[]</code>.
+     */
+    public long[] longDimensions()
+    {
+        final long[] dimensionsCopy = new long[dimensions.length];
+        for (int i = 0; i < dimensionsCopy.length; ++i)
+        {
+            dimensionsCopy[i] = dimensions[i];
+        }
+        return dimensionsCopy;
+    }
+
+    /**
+     * Returns the number of elements in the array.
+     */
+    public int size()
+    {
+        return size;
+    }
+    
+    /**
+     * Returns the current number of hyper rows of of this array.
+     */
+    public int numberOfHyperRows()
+    {
+        return numberOfHyperRows();
+    }
+
+    /**
+     * Return an object which has the same value as the element of the array specified by
+     * <var>linearIndex</var>.
+     * 
+     * @param linearIndex The index in the linear array returned by {@link #getAsFlatArray()}.
+     * @return The value at the specified index.
+     */
+    public abstract T getAsObject(int linearIndex);
+
+    /**
+     * Return an object which has the same value as the element of the array specified by
+     * <var>indices</var>.
+     */
+    public abstract T getAsObject(int... indices);
+
+    /**
+     * Sets the element of the array specified by <var>indices</var> to the particular
+     * <var>value</var>.
+     */
+    public abstract void setToObject(T value, int... indices);
+
+    /**
+     * Sets the element of the array specified by <var>linearIndex</var> to the particular
+     * <var>value</var>.
+     * 
+     * @param value The new value to set.
+     * @param linearIndex The index in the linear array returned by {@link #getAsFlatArray()}.
+     */
+    public abstract void setToObject(T value, int linearIndex);
+
+    /**
+     * Returns the array in flattened form. Changes to the returned object will change the
+     * multi-dimensional array directly.
+     */
+    public abstract Object getAsFlatArray();
+
+    /**
+     * Returns a copy of the array in flattened form. Changes to the returned object will <i>not</i>
+     * change the multi-dimensional array directly.
+     */
+    public abstract Object getCopyAsFlatArray();
+
+    protected abstract void adaptCapacityHyperRows();
+
+    /**
+     * Returns the capacity of elements in the array.
+     */
+    public abstract int capacity();
+
+    /**
+     * Increase the number of hyper-rows by <var>count</var>. Doubles the capacity if needed.
+     * 
+     * @return The new number of rows.
+     */
+    public int incNumberOfHyperRows(int count)
+    {
+        dimensions[0] += count;
+        if (dimensions[0] > capacityHyperRows)
+        {
+            capacityHyperRows = Math.max(capacityHyperRows * 2, dimensions[0]);
+            adaptCapacityHyperRows();
+        }
+        size += count * hyperRowLength;
+        return dimensions[0];
+    }
+
+    /**
+     * Decrease the number of hyper-rows by <var>count</var>.
+     * 
+     * @return The new number of rows.
+     */
+    public int decNumberOfHyperRows(int count)
+    {
+        dimensions[0] -= count;
+        size -= count * hyperRowLength;
+        return dimensions[0];
+    }
+
+    /**
+     * Computes the linear index for the multi-dimensional <var>indices</var> provided.
+     */
+    public int computeIndex(int... indices)
+    {
+        assert indices != null;
+        assert indices.length == dimensions.length;
+
+        int index = indices[0];
+        for (int i = 1; i < indices.length; ++i)
+        {
+            index = index * dimensions[i] + indices[i];
+        }
+        return index;
+    }
+
+    /**
+     * Computes the multi-dimensional index from the <var>linearIndex</var>.
+     */
+    public int[] computeReverseIndex(int linearIndex)
+    {
+        final int[] index = new int[dimensions.length];
+        int workIndex = linearIndex;
+        int blockSize = size;
+        for (int i = 0; i < dimensions.length; ++i)
+        {
+            blockSize /= dimensions[i];
+            index[i] = workIndex / blockSize;
+            workIndex = workIndex - index[i] * blockSize;
+        }
+        return index;
+    }
+
+    /**
+     * Computes the linear index for the two-dimensional (<var>indexX, indexY</var>) provided.
+     */
+    public int computeIndex(int indexX, int indexY)
+    {
+        assert 2 == dimensions.length;
+
+        return dimensions[1] * indexX + indexY;
+    }
+
+    /**
+     * Computes the linear index for the three-dimensional (<var>indexX, indexY, indexZ</var>)
+     * provided.
+     */
+    public int computeIndex(int indexX, int indexY, int indexZ)
+    {
+        assert 3 == dimensions.length;
+
+        return dimensions[2] * (dimensions[1] * indexX + indexY) + indexZ;
+    }
+
+    /**
+     * Converts the <var>dimensions</var> from <code>long[]</code> to <code>int[]</code>.
+     */
+    public static int[] toInt(final long[] dimensions)
+    {
+        assert dimensions != null;
+
+        final int[] result = new int[dimensions.length];
+        for (int i = 0; i < result.length; ++i)
+        {
+            result[i] = (int) dimensions[i];
+            if (result[i] != dimensions[i])
+            {
+                throw new IllegalArgumentException("Dimension " + i + "  is too large ("
+                        + dimensions[i] + ")");
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Converts the <var>dimensions</var> from <code>int[]</code> to <code>long[]</code>.
+     */
+    public static long[] toLong(final int[] dimensions)
+    {
+        assert dimensions != null;
+
+        final long[] result = new long[dimensions.length];
+        for (int i = 0; i < result.length; ++i)
+        {
+            result[i] = dimensions[i];
+        }
+        return result;
+    }
+
+    /**
+     * Returns the one-dimensional length of the multi-dimensional array defined by
+     * <var>dimensions</var>.
+     * 
+     * @throws IllegalArgumentException If <var>dimensions</var> overflow the <code>int</code> type.
+     */
+    public static int getLength(final int[] dimensions)
+    {
+        return getLength(dimensions, 0);
+    }
+
+    /**
+     * Returns the one-dimensional length of the multi-dimensional array defined by
+     * <var>dimensions</var>. If <code>capacityHyperRows > dimensions[0]</code>, then it will
+     * replace <var>dimensions[0]</var> by <var>capacityHyperRows</var>
+     * 
+     * @throws IllegalArgumentException If <var>dimensions</var> overflow the <code>int</code> type.
+     */
+    public static int getLength(final int[] dimensions, int capacityHyperRows)
+    {
+        assert dimensions != null;
+
+        if (dimensions.length == 0)
+        {
+            return 0;
+        }
+        long length = Math.max(capacityHyperRows, dimensions[0]);
+        for (int i = 1; i < dimensions.length; ++i)
+        {
+            length *= dimensions[i];
+        }
+        int intLength = (int) length;
+        if (length != intLength)
+        {
+            throw new IllegalArgumentException("Length is too large (" + length + ")");
+        }
+        return intLength;
+    }
+
+    /**
+     * Returns the one-dimensional length of the multi-dimensional array defined by
+     * <var>dimensions</var>.
+     * 
+     * @throws IllegalArgumentException If <var>dimensions</var> overflow the <code>int</code> type.
+     */
+    public static int getLength(final long[] dimensions)
+    {
+        return getLength(dimensions, 0);
+    }
+
+    /**
+     * Returns the one-dimensional length of the multi-dimensional array defined by
+     * <var>dimensions</var>. If <code>capacityHyperRows > dimensions[0]</code>, then it will
+     * replace <var>dimensions[0]</var> by <var>capacityHyperRows</var>
+     * 
+     * @throws IllegalArgumentException If <var>dimensions</var> overflow the <code>int</code> type.
+     */
+    public static int getLength(final long[] dimensions, long capacityHyperRows)
+    {
+        assert dimensions != null;
+
+        if (dimensions.length == 0) // NULL data space needs to be treated differently
+        {
+            return 0;
+        }
+        long length = Math.max(capacityHyperRows, dimensions[0]);
+        for (int i = 1; i < dimensions.length; ++i)
+        {
+            length *= dimensions[i];
+        }
+        int intLength = (int) length;
+        if (length != intLength)
+        {
+            throw new IllegalArgumentException("Length is too large (" + length + ")");
+        }
+        return intLength;
+    }
+
+    //
+    // Iterable
+    //
+
+    @Override
+    public Iterator<ArrayEntry> iterator()
+    {
+        return new Iterator<ArrayEntry>()
+            {
+                int linearIndex = 0;
+
+                @Override
+                public boolean hasNext()
+                {
+                    return linearIndex < size;
+                }
+
+                @Override
+                public ArrayEntry next()
+                {
+                    final ArrayEntry next = new ArrayEntry(linearIndex);
+                    ++linearIndex;
+                    return next;
+                }
+
+                @Override
+                public void remove()
+                {
+                    throw new UnsupportedOperationException();
+                }
+
+            };
+    }
+
+    //
+    // Object
+    //
+
+    @Override
+    public String toString()
+    {
+        final int length = getLength(dimensions, 0);
+        final StringBuilder b = new StringBuilder();
+        b.append(ClassUtils.getShortCanonicalName(this.getClass()));
+        b.append('(');
+        b.append(ArrayUtils.toString(dimensions));
+        b.append(')');
+        if (length <= 100)
+        {
+            b.append(": ");
+            if (dimensions[0] < capacityHyperRows)
+            {
+                b.append(ArrayUtils.toString(getCopyAsFlatArray()));
+            } else
+            {
+                b.append(ArrayUtils.toString(getAsFlatArray()));
+            }
+        }
+        return b.toString();
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/mdarray/MDArray.java b/source/java/ch/systemsx/cisd/base/mdarray/MDArray.java
new file mode 100644
index 0000000..1a4a236
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/mdarray/MDArray.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.mdarray;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Arrays;
+
+import org.apache.commons.lang.ArrayUtils;
+
+/**
+ * A multi-dimensional array of generic type <code>T</code>.
+ * 
+ * @author Bernd Rinn
+ */
+public class MDArray<T> extends MDAbstractArray<T>
+{
+    private static final long serialVersionUID = 1L;
+
+    private T[] flattenedArray;
+
+    /**
+     * Creates an empty {@link MDArray} with the <var>dimensions</var>. Convenience method if
+     * <var>dimensions</var> are available as {@code long[]}.
+     */
+    public MDArray(Class<T> componentClass, long[] dimensions)
+    {
+        this(createArray(componentClass, getLength(dimensions, 0)), toInt(dimensions), false);
+    }
+
+    /**
+     * Creates an empty {@link MDArray} with the <var>dimensions</var>. If
+     * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+     * of <var>capacityHyperRows</var> hyper-rows. Convenience method if <var>dimensions</var> are
+     * available as {@code long[]}.
+     */
+    public MDArray(Class<T> componentClass, long[] dimensions, long capacityHyperRows)
+    {
+        this(createArray(componentClass, getLength(dimensions, capacityHyperRows)),
+                toInt(dimensions), false);
+    }
+
+    /**
+     * Creates a {@link MDArray} from the given {@code flattenedArray} and {@code dimensions}. It is
+     * checked that the arguments are compatible. Convenience method if <var>dimensions</var> are
+     * available as {@code long[]}.
+     */
+    public MDArray(T[] flattenedArray, long[] dimensions)
+    {
+        this(flattenedArray, toInt(dimensions), true);
+    }
+
+    /**
+     * Creates a {@link MDArray} from the given <var>flattenedArray</var> and <var>dimensions</var>.
+     * If <var>checkDimensions</var> is {@code true}, it is checked that the arguments are
+     * compatible. Convenience method if <var>dimensions</var> are available as {@code long[]}.
+     */
+    public MDArray(T[] flattenedArray, long[] dimensions, boolean checkdimensions)
+    {
+        this(flattenedArray, toInt(dimensions), checkdimensions);
+    }
+
+    /**
+     * Creates an empty {@link MDArray} with the <var>dimensions</var>.
+     */
+    public MDArray(Class<T> componentClass, int[] dimensions)
+    {
+        this(createArray(componentClass, getLength(dimensions, 0)), dimensions, false);
+    }
+
+    /**
+     * Creates an empty {@link MDArray} with the <var>dimensions</var>. If
+     * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+     * of <var>capacityHyperRows</var> hyper-rows.
+     */
+    public MDArray(Class<T> componentClass, int[] dimensions, int capacityHyperRows)
+    {
+        this(createArray(componentClass, getLength(dimensions, capacityHyperRows)), dimensions,
+                false);
+    }
+
+    /**
+     * Creates a {@link MDArray} from the given {@code flattenedArray} and {@code dimensions}. It is
+     * checked that the arguments are compatible.
+     */
+    public MDArray(T[] flattenedArray, int[] dimensions)
+    {
+        this(flattenedArray, dimensions, true);
+    }
+
+    /**
+     * Creates a {@link MDArray} from the given <var>flattenedArray</var> and <var>dimensions</var>.
+     * If <var>checkDimensions</var> is {@code true}, it is checked that the arguments are
+     * compatible.
+     */
+    public MDArray(T[] flattenedArray, int[] dimensions, boolean checkdimensions)
+    {
+        super(dimensions, flattenedArray.length, 0);
+        assert flattenedArray != null;
+
+        if (checkdimensions)
+        {
+            final int expectedLength = getLength(dimensions, 0);
+            if (flattenedArray.length != expectedLength)
+            {
+                throw new IllegalArgumentException("Actual array length " + flattenedArray.length
+                        + " does not match expected length " + expectedLength + ".");
+            }
+        }
+        this.flattenedArray = flattenedArray;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <V> V[] createArray(Class<V> componentClass, final int vectorLength)
+    {
+        final V[] value = (V[]) java.lang.reflect.Array.newInstance(componentClass, vectorLength);
+        return value;
+    }
+
+    @Override
+    public int capacity()
+    {
+        return flattenedArray.length;
+    }
+
+    @Override
+    public T getAsObject(int... indices)
+    {
+        return get(indices);
+    }
+
+    @Override
+    public void setToObject(T value, int... indices)
+    {
+        set(value, indices);
+    }
+
+    @Override
+    public T getAsObject(int linearIndex)
+    {
+        return get(linearIndex);
+    }
+
+    @Override
+    public void setToObject(T value, int linearIndex)
+    {
+        set(value, linearIndex);
+    }
+
+    @Override
+    public T[] getAsFlatArray()
+    {
+        return flattenedArray;
+    }
+
+    @Override
+    public T[] getCopyAsFlatArray()
+    {
+        return toTArray(ArrayUtils.subarray(flattenedArray, 0, dimensions[0] * hyperRowLength));
+    }
+
+    @Override
+    protected void adaptCapacityHyperRows()
+    {
+        final T[] oldArray = this.flattenedArray;
+        this.flattenedArray =
+                toTArray(createArray(oldArray.getClass().getComponentType(), capacityHyperRows
+                        * hyperRowLength));
+        System.arraycopy(oldArray, 0, flattenedArray, 0,
+                Math.min(oldArray.length, flattenedArray.length));
+    }
+
+    @SuppressWarnings("unchecked")
+    private T[] toTArray(Object obj)
+    {
+        return (T[]) obj;
+    }
+
+    /**
+     * Returns the value of array at the position defined by <var>indices</var>.
+     */
+    public T get(int... indices)
+    {
+        return flattenedArray[computeIndex(indices)];
+    }
+
+    /**
+     * Returns the value of a one-dimensional array at the position defined by <var>index</var>.
+     * <p>
+     * <b>Do not call for arrays other than one-dimensional!</b>
+     */
+    public T get(int index)
+    {
+        return flattenedArray[index];
+    }
+
+    /**
+     * Returns the value of a two-dimensional array at the position defined by <var>indexX</var> and
+     * <var>indexY</var>.
+     * <p>
+     * <b>Do not call for arrays other than two-dimensional!</b>
+     */
+    public T get(int indexX, int indexY)
+    {
+        return flattenedArray[computeIndex(indexX, indexY)];
+    }
+
+    /**
+     * Returns the value of a three-dimensional array at the position defined by <var>indexX</var>,
+     * <var>indexY</var> and <var>indexZ</var>.
+     * <p>
+     * <b>Do not call for arrays other than three-dimensional!</b>
+     */
+    public T get(int indexX, int indexY, int indexZ)
+    {
+        return flattenedArray[computeIndex(indexX, indexY, indexZ)];
+    }
+
+    /**
+     * Sets the <var>value</var> of array at the position defined by <var>indices</var>.
+     */
+    public void set(T value, int... indices)
+    {
+        flattenedArray[computeIndex(indices)] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a one-dimension array at the position defined by
+     * <var>index</var>.
+     * <p>
+     * <b>Do not call for arrays other than one-dimensional!</b>
+     */
+    public void set(T value, int index)
+    {
+        flattenedArray[index] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a two-dimensional array at the position defined by
+     * <var>indexX</var> and <var>indexY</var>.
+     * <p>
+     * <b>Do not call for arrays other than two-dimensional!</b>
+     */
+    public void set(T value, int indexX, int indexY)
+    {
+        flattenedArray[computeIndex(indexX, indexY)] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a three-dimensional array at the position defined by
+     * <var>indexX</var>, <var>indexY</var> and <var>indexZ</var>.
+     * <p>
+     * <b>Do not call for arrays other than three-dimensional!</b>
+     */
+    public void set(T value, int indexX, int indexY, int indexZ)
+    {
+        flattenedArray[computeIndex(indexX, indexY, indexZ)] = value;
+    }
+
+    /**
+     * Returns the component type of this array.
+     */
+    @SuppressWarnings("unchecked")
+    public Class<T> getComponentClass()
+    {
+        return (Class<T>) flattenedArray.getClass().getComponentType();
+    }
+
+    //
+    // Object
+    //
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(getValuesAsFlatArray());
+        result = prime * result + Arrays.hashCode(dimensions);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        final MDArray<T> other = toMDArray(obj);
+        if (Arrays.equals(getValuesAsFlatArray(), other.getValuesAsFlatArray()) == false)
+        {
+            return false;
+        }
+        if (Arrays.equals(dimensions, other.dimensions) == false)
+        {
+            return false;
+        }
+        return true;
+    }
+
+    private T[] getValuesAsFlatArray()
+    {
+        return (dimensions[0] < capacityHyperRows) ? getCopyAsFlatArray() : getAsFlatArray(); 
+    }
+    
+    @SuppressWarnings("unchecked")
+    private MDArray<T> toMDArray(Object obj)
+    {
+        return (MDArray<T>) obj;
+    }
+
+    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
+    {
+        stream.defaultReadObject();
+        if (hyperRowLength == 0)
+        {
+            this.hyperRowLength = computeHyperRowLength(dimensions);
+        }
+        if (capacityHyperRows == 0)
+        {
+            this.capacityHyperRows = dimensions[0];
+        }
+        if (size == 0)
+        {
+            this.size = hyperRowLength * dimensions[0];
+        }
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/mdarray/MDByteArray.java b/source/java/ch/systemsx/cisd/base/mdarray/MDByteArray.java
new file mode 100644
index 0000000..4bb36ad
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/mdarray/MDByteArray.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.mdarray;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Arrays;
+
+import org.apache.commons.lang.ArrayUtils;
+
+/**
+ * A multi-dimensional <code>byte</code> array.
+ * 
+ * @author Bernd Rinn
+ */
+public final class MDByteArray extends MDAbstractArray<Byte>
+{
+    private static final long serialVersionUID = 1L;
+
+    private byte[] flattenedArray;
+
+    /**
+     * Creates an empty {@link MDIntArray} with the <var>dimensions</var>. Convenience method if
+     * <var>dimensions</var> are available as {@code long[]}.
+     */
+    public MDByteArray(long[] dimensions)
+    {
+        this(new byte[getLength(dimensions, 0)], toInt(dimensions), false);
+    }
+
+    /**
+     * Creates an empty {@link MDByteArray} with the <var>dimensions</var>. If
+     * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+     * of <var>capacityHyperRows</var> hyper-rows. Convenience method if <var>dimensions</var> are
+     * available as {@code long[]}.
+     */
+    public MDByteArray(long[] dimensions, long capacityHyperRows)
+    {
+        this(new byte[getLength(dimensions, capacityHyperRows)], toInt(dimensions), false);
+    }
+
+    /**
+     * Creates a {@link MDByteArray} from the given {@code flattenedArray} and {@code dimensions}. It
+     * is checked that the arguments are compatible. Convenience method if <var>dimensions</var> are
+     * available as {@code long[]}.
+     */
+    public MDByteArray(byte[] flattenedArray, long[] dimensions)
+    {
+        this(flattenedArray, toInt(dimensions), true);
+    }
+
+    /**
+     * Creates a {@link MDByteArray} from the given <var>flattenedArray</var> and
+     * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+     * arguments are compatible. Convenience method if <var>dimensions</var> are available as
+     * {@code long[]}.
+     */
+    public MDByteArray(byte[] flattenedArray, long[] dimensions, boolean checkdimensions)
+    {
+        this(flattenedArray, toInt(dimensions), checkdimensions);
+    }
+
+    /**
+     * Creates an empty {@link MDByteArray} with the <var>dimensions</var>.
+     */
+    public MDByteArray(int[] dimensions)
+    {
+        this(new byte[getLength(dimensions, 0)], dimensions, false);
+    }
+
+    /**
+     * Creates an empty {@link MDByteArray} with the <var>dimensions</var>. If
+     * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+     * of <var>capacityHyperRows</var> hyper-rows.
+     */
+    public MDByteArray(int[] dimensions, int capacityHyperRows)
+    {
+        this(new byte[getLength(dimensions, capacityHyperRows)], dimensions, false);
+    }
+
+    /**
+     * Creates a {@link MDByteArray} from the given {@code flattenedArray} and {@code dimensions}. It
+     * is checked that the arguments are compatible.
+     */
+    public MDByteArray(byte[] flattenedArray, int[] dimensions)
+    {
+        this(flattenedArray, dimensions, true);
+    }
+
+    /**
+     * Creates a {@link MDByteArray} from the given <var>flattenedArray</var> and
+     * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+     * arguments are compatible.
+     */
+    public MDByteArray(byte[] flattenedArray, int[] dimensions, boolean checkdimensions)
+    {
+        super(dimensions, flattenedArray.length, 0);
+        assert flattenedArray != null;
+
+        if (checkdimensions)
+        {
+            final int expectedLength = getLength(dimensions, 0);
+            if (flattenedArray.length != expectedLength)
+            {
+                throw new IllegalArgumentException("Actual array length " + flattenedArray.length
+                        + " does not match expected length " + expectedLength + ".");
+            }
+        }
+        this.flattenedArray = flattenedArray;
+    }
+
+    /**
+     * Creates a {@link MDByteArray} from the given <var>matrix</var> of rank 2. Note that the values
+     * in <var>matrix</var> will be copied and thus the created {@link MDIntArray} will be
+     * independent from <var>matrix</var> after construction.
+     */
+    public MDByteArray(byte[][] matrix)
+    {
+        this(matrix, getDimensions(matrix));
+    }
+
+    /**
+     * Creates a {@link MDByteArray} from the given <var>matrix</var> of rank 2 and the
+     * <var>dimension</var> which need to be less or equal the dimensions of <var>matrix</var>. Note
+     * that the values in <var>matrix</var> will be copied and thus the created {@link MDIntArray}
+     * will be independent from <var>matrix</var> after construction.
+     */
+    public MDByteArray(byte[][] matrix, int[] dimensions)
+    {
+        super(dimensions, 0, matrix.length);
+
+        final int sizeX = dimensions[0];
+        final int sizeY = dimensions[1];
+        int length = getLength(dimensions, 0);
+        this.flattenedArray = new byte[length];
+        for (int i = 0; i < sizeX; ++i)
+        {
+            System.arraycopy(matrix[i], 0, flattenedArray, i * sizeY, sizeY);
+        }
+    }
+
+    private static int[] getDimensions(byte[][] matrix)
+    {
+        assert matrix != null;
+
+        return new int[]
+            { matrix.length, matrix.length == 0 ? 0 : matrix[0].length };
+    }
+
+    @Override
+    public int capacity()
+    {
+        return flattenedArray.length;
+    }
+
+    @Override
+    public Byte getAsObject(int... indices)
+    {
+        return get(indices);
+    }
+
+    @Override
+    public void setToObject(Byte value, int... indices)
+    {
+        set(value, indices);
+    }
+
+    @Override
+    public Byte getAsObject(int linearIndex)
+    {
+        return get(linearIndex);
+    }
+
+    @Override
+    public void setToObject(Byte value, int linearIndex)
+    {
+        set(value, linearIndex);
+    }
+
+    @Override
+    public byte[] getAsFlatArray()
+    {
+        return flattenedArray;
+    }
+
+    @Override
+    public byte[] getCopyAsFlatArray()
+    {
+        return ArrayUtils.subarray(flattenedArray, 0, dimensions[0] * hyperRowLength);
+    }
+
+    @Override
+    protected void adaptCapacityHyperRows()
+    {
+        final byte[] oldArray = this.flattenedArray;
+        this.flattenedArray = new byte[capacityHyperRows * hyperRowLength];
+        System.arraycopy(oldArray, 0, flattenedArray, 0,
+                Math.min(oldArray.length, flattenedArray.length));
+    }
+
+    /**
+     * Returns the value of array at the position defined by <var>indices</var>.
+     */
+    public byte get(int... indices)
+    {
+        return flattenedArray[computeIndex(indices)];
+    }
+
+    /**
+     * Returns the value of a one-dimensional array at the position defined by <var>index</var>.
+     * <p>
+     * <b>Do not call for arrays other than one-dimensional!</b>
+     */
+    public byte get(int index)
+    {
+        return flattenedArray[index];
+    }
+
+    /**
+     * Returns the value of a two-dimensional array at the position defined by <var>indexX</var> and
+     * <var>indexY</var>.
+     * <p>
+     * <b>Do not call for arrays other than two-dimensional!</b>
+     */
+    public byte get(int indexX, int indexY)
+    {
+        return flattenedArray[computeIndex(indexX, indexY)];
+    }
+
+    /**
+     * Returns the value of a three-dimensional array at the position defined by <var>indexX</var>,
+     * <var>indexY</var> and <var>indexZ</var>.
+     * <p>
+     * <b>Do not call for arrays other than three-dimensional!</b>
+     */
+    public byte get(int indexX, int indexY, int indexZ)
+    {
+        return flattenedArray[computeIndex(indexX, indexY, indexZ)];
+    }
+
+    /**
+     * Sets the <var>value</var> of array at the position defined by <var>indices</var>.
+     */
+    public void set(byte value, int... indices)
+    {
+        flattenedArray[computeIndex(indices)] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a one-dimension array at the position defined by
+     * <var>index</var>.
+     * <p>
+     * <b>Do not call for arrays other than one-dimensional!</b>
+     */
+    public void set(byte value, int index)
+    {
+        flattenedArray[index] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a two-dimensional array at the position defined by
+     * <var>indexX</var> and <var>indexY</var>.
+     * <p>
+     * <b>Do not call for arrays other than two-dimensional!</b>
+     */
+    public void set(byte value, int indexX, int indexY)
+    {
+        flattenedArray[computeIndex(indexX, indexY)] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a three-dimensional array at the position defined by
+     * <var>indexX</var>, <var>indexY</var> and <var>indexZ</var>.
+     * <p>
+     * <b>Do not call for arrays other than three-dimensional!</b>
+     */
+    public void set(byte value, int indexX, int indexY, int indexZ)
+    {
+        flattenedArray[computeIndex(indexX, indexY, indexZ)] = value;
+    }
+
+    /**
+     * Creates and returns a matrix from a two-dimensional array.
+     * <p>
+     * <b>Do not call for arrays other than two-dimensional!</b>
+     */
+    public byte[][] toMatrix()
+    {
+        final int sizeX = dimensions[0];
+        final int sizeY = dimensions[1];
+        final byte[][] result = new byte[sizeX][sizeY];
+        for (int i = 0; i < sizeX; ++i)
+        {
+            System.arraycopy(flattenedArray, i * sizeY, result[i], 0, sizeY);
+        }
+        return result;
+    }
+
+    //
+    // Object
+    //
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(getValuesAsFlatArray());
+        result = prime * result + Arrays.hashCode(dimensions);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        MDByteArray other = (MDByteArray) obj;
+        if (Arrays.equals(getValuesAsFlatArray(), other.getValuesAsFlatArray()) == false)
+        {
+            return false;
+        }
+        if (Arrays.equals(dimensions, other.dimensions) == false)
+        {
+            return false;
+        }
+        return true;
+    }
+
+    private byte[] getValuesAsFlatArray()
+    {
+        return (dimensions[0] < capacityHyperRows) ? getCopyAsFlatArray() : getAsFlatArray(); 
+    }
+    
+    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
+    {
+        stream.defaultReadObject();
+        if (hyperRowLength == 0)
+        {
+            this.hyperRowLength = computeHyperRowLength(dimensions);
+        }
+        if (capacityHyperRows == 0)
+        {
+            this.capacityHyperRows = dimensions[0];
+        }
+        if (size == 0)
+        {
+            this.size = hyperRowLength * dimensions[0];
+        }
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/mdarray/MDDoubleArray.java b/source/java/ch/systemsx/cisd/base/mdarray/MDDoubleArray.java
new file mode 100644
index 0000000..8a755f4
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/mdarray/MDDoubleArray.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.mdarray;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Arrays;
+
+import org.apache.commons.lang.ArrayUtils;
+
+/**
+ * A multi-dimensional <code>double</code> array.
+ * 
+ * @author Bernd Rinn
+ */
+public final class MDDoubleArray extends MDAbstractArray<Double>
+{
+    private static final long serialVersionUID = 1L;
+
+    private double[] flattenedArray;
+
+    /**
+     * Creates an empty {@link MDIntArray} with the <var>dimensions</var>. Convenience method if
+     * <var>dimensions</var> are available as {@code long[]}.
+     */
+    public MDDoubleArray(long[] dimensions)
+    {
+        this(new double[getLength(dimensions, 0)], toInt(dimensions), false);
+    }
+
+    /**
+     * Creates an empty {@link MDDoubleArray} with the <var>dimensions</var>. If
+     * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+     * of <var>capacityHyperRows</var> hyper-rows. Convenience method if <var>dimensions</var> are
+     * available as {@code long[]}.
+     */
+    public MDDoubleArray(long[] dimensions, long capacityHyperRows)
+    {
+        this(new double[getLength(dimensions, capacityHyperRows)], toInt(dimensions), false);
+    }
+
+    /**
+     * Creates a {@link MDDoubleArray} from the given {@code flattenedArray} and {@code dimensions}. It
+     * is checked that the arguments are compatible. Convenience method if <var>dimensions</var> are
+     * available as {@code long[]}.
+     */
+    public MDDoubleArray(double[] flattenedArray, long[] dimensions)
+    {
+        this(flattenedArray, toInt(dimensions), true);
+    }
+
+    /**
+     * Creates a {@link MDDoubleArray} from the given <var>flattenedArray</var> and
+     * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+     * arguments are compatible. Convenience method if <var>dimensions</var> are available as
+     * {@code long[]}.
+     */
+    public MDDoubleArray(double[] flattenedArray, long[] dimensions, boolean checkdimensions)
+    {
+        this(flattenedArray, toInt(dimensions), checkdimensions);
+    }
+
+    /**
+     * Creates an empty {@link MDDoubleArray} with the <var>dimensions</var>.
+     */
+    public MDDoubleArray(int[] dimensions)
+    {
+        this(new double[getLength(dimensions, 0)], dimensions, false);
+    }
+
+    /**
+     * Creates an empty {@link MDDoubleArray} with the <var>dimensions</var>. If
+     * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+     * of <var>capacityHyperRows</var> hyper-rows.
+     */
+    public MDDoubleArray(int[] dimensions, int capacityHyperRows)
+    {
+        this(new double[getLength(dimensions, capacityHyperRows)], dimensions, false);
+    }
+
+    /**
+     * Creates a {@link MDDoubleArray} from the given {@code flattenedArray} and {@code dimensions}. It
+     * is checked that the arguments are compatible.
+     */
+    public MDDoubleArray(double[] flattenedArray, int[] dimensions)
+    {
+        this(flattenedArray, dimensions, true);
+    }
+
+    /**
+     * Creates a {@link MDDoubleArray} from the given <var>flattenedArray</var> and
+     * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+     * arguments are compatible.
+     */
+    public MDDoubleArray(double[] flattenedArray, int[] dimensions, boolean checkdimensions)
+    {
+        super(dimensions, flattenedArray.length, 0);
+        assert flattenedArray != null;
+
+        if (checkdimensions)
+        {
+            final int expectedLength = getLength(dimensions, 0);
+            if (flattenedArray.length != expectedLength)
+            {
+                throw new IllegalArgumentException("Actual array length " + flattenedArray.length
+                        + " does not match expected length " + expectedLength + ".");
+            }
+        }
+        this.flattenedArray = flattenedArray;
+    }
+
+    /**
+     * Creates a {@link MDDoubleArray} from the given <var>matrix</var> of rank 2. Note that the values
+     * in <var>matrix</var> will be copied and thus the created {@link MDIntArray} will be
+     * independent from <var>matrix</var> after construction.
+     */
+    public MDDoubleArray(double[][] matrix)
+    {
+        this(matrix, getDimensions(matrix));
+    }
+
+    /**
+     * Creates a {@link MDDoubleArray} from the given <var>matrix</var> of rank 2 and the
+     * <var>dimension</var> which need to be less or equal the dimensions of <var>matrix</var>. Note
+     * that the values in <var>matrix</var> will be copied and thus the created {@link MDIntArray}
+     * will be independent from <var>matrix</var> after construction.
+     */
+    public MDDoubleArray(double[][] matrix, int[] dimensions)
+    {
+        super(dimensions, 0, matrix.length);
+
+        final int sizeX = dimensions[0];
+        final int sizeY = dimensions[1];
+        int length = getLength(dimensions, 0);
+        this.flattenedArray = new double[length];
+        for (int i = 0; i < sizeX; ++i)
+        {
+            System.arraycopy(matrix[i], 0, flattenedArray, i * sizeY, sizeY);
+        }
+    }
+
+    private static int[] getDimensions(double[][] matrix)
+    {
+        assert matrix != null;
+
+        return new int[]
+            { matrix.length, matrix.length == 0 ? 0 : matrix[0].length };
+    }
+
+    @Override
+    public int capacity()
+    {
+        return flattenedArray.length;
+    }
+
+    @Override
+    public Double getAsObject(int... indices)
+    {
+        return get(indices);
+    }
+
+    @Override
+    public void setToObject(Double value, int... indices)
+    {
+        set(value, indices);
+    }
+
+    @Override
+    public Double getAsObject(int linearIndex)
+    {
+        return get(linearIndex);
+    }
+
+    @Override
+    public void setToObject(Double value, int linearIndex)
+    {
+        set(value, linearIndex);
+    }
+
+    @Override
+    public double[] getAsFlatArray()
+    {
+        return flattenedArray;
+    }
+
+    @Override
+    public double[] getCopyAsFlatArray()
+    {
+        return ArrayUtils.subarray(flattenedArray, 0, dimensions[0] * hyperRowLength);
+    }
+
+    @Override
+    protected void adaptCapacityHyperRows()
+    {
+        final double[] oldArray = this.flattenedArray;
+        this.flattenedArray = new double[capacityHyperRows * hyperRowLength];
+        System.arraycopy(oldArray, 0, flattenedArray, 0,
+                Math.min(oldArray.length, flattenedArray.length));
+    }
+
+    /**
+     * Returns the value of array at the position defined by <var>indices</var>.
+     */
+    public double get(int... indices)
+    {
+        return flattenedArray[computeIndex(indices)];
+    }
+
+    /**
+     * Returns the value of a one-dimensional array at the position defined by <var>index</var>.
+     * <p>
+     * <b>Do not call for arrays other than one-dimensional!</b>
+     */
+    public double get(int index)
+    {
+        return flattenedArray[index];
+    }
+
+    /**
+     * Returns the value of a two-dimensional array at the position defined by <var>indexX</var> and
+     * <var>indexY</var>.
+     * <p>
+     * <b>Do not call for arrays other than two-dimensional!</b>
+     */
+    public double get(int indexX, int indexY)
+    {
+        return flattenedArray[computeIndex(indexX, indexY)];
+    }
+
+    /**
+     * Returns the value of a three-dimensional array at the position defined by <var>indexX</var>,
+     * <var>indexY</var> and <var>indexZ</var>.
+     * <p>
+     * <b>Do not call for arrays other than three-dimensional!</b>
+     */
+    public double get(int indexX, int indexY, int indexZ)
+    {
+        return flattenedArray[computeIndex(indexX, indexY, indexZ)];
+    }
+
+    /**
+     * Sets the <var>value</var> of array at the position defined by <var>indices</var>.
+     */
+    public void set(double value, int... indices)
+    {
+        flattenedArray[computeIndex(indices)] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a one-dimension array at the position defined by
+     * <var>index</var>.
+     * <p>
+     * <b>Do not call for arrays other than one-dimensional!</b>
+     */
+    public void set(double value, int index)
+    {
+        flattenedArray[index] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a two-dimensional array at the position defined by
+     * <var>indexX</var> and <var>indexY</var>.
+     * <p>
+     * <b>Do not call for arrays other than two-dimensional!</b>
+     */
+    public void set(double value, int indexX, int indexY)
+    {
+        flattenedArray[computeIndex(indexX, indexY)] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a three-dimensional array at the position defined by
+     * <var>indexX</var>, <var>indexY</var> and <var>indexZ</var>.
+     * <p>
+     * <b>Do not call for arrays other than three-dimensional!</b>
+     */
+    public void set(double value, int indexX, int indexY, int indexZ)
+    {
+        flattenedArray[computeIndex(indexX, indexY, indexZ)] = value;
+    }
+
+    /**
+     * Creates and returns a matrix from a two-dimensional array.
+     * <p>
+     * <b>Do not call for arrays other than two-dimensional!</b>
+     */
+    public double[][] toMatrix()
+    {
+        final int sizeX = dimensions[0];
+        final int sizeY = dimensions[1];
+        final double[][] result = new double[sizeX][sizeY];
+        for (int i = 0; i < sizeX; ++i)
+        {
+            System.arraycopy(flattenedArray, i * sizeY, result[i], 0, sizeY);
+        }
+        return result;
+    }
+
+    //
+    // Object
+    //
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(getValuesAsFlatArray());
+        result = prime * result + Arrays.hashCode(dimensions);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        MDDoubleArray other = (MDDoubleArray) obj;
+        if (Arrays.equals(getValuesAsFlatArray(), other.getValuesAsFlatArray()) == false)
+        {
+            return false;
+        }
+        if (Arrays.equals(dimensions, other.dimensions) == false)
+        {
+            return false;
+        }
+        return true;
+    }
+
+    private double[] getValuesAsFlatArray()
+    {
+        return (dimensions[0] < capacityHyperRows) ? getCopyAsFlatArray() : getAsFlatArray(); 
+    }
+    
+    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
+    {
+        stream.defaultReadObject();
+        if (hyperRowLength == 0)
+        {
+            this.hyperRowLength = computeHyperRowLength(dimensions);
+        }
+        if (capacityHyperRows == 0)
+        {
+            this.capacityHyperRows = dimensions[0];
+        }
+        if (size == 0)
+        {
+            this.size = hyperRowLength * dimensions[0];
+        }
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/mdarray/MDFloatArray.java b/source/java/ch/systemsx/cisd/base/mdarray/MDFloatArray.java
new file mode 100644
index 0000000..4b10fb8
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/mdarray/MDFloatArray.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.mdarray;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Arrays;
+
+import org.apache.commons.lang.ArrayUtils;
+
+/**
+ * A multi-dimensional <code>float</code> array.
+ * 
+ * @author Bernd Rinn
+ */
+public final class MDFloatArray extends MDAbstractArray<Float>
+{
+    private static final long serialVersionUID = 1L;
+
+    private float[] flattenedArray;
+
+    /**
+     * Creates an empty {@link MDIntArray} with the <var>dimensions</var>. Convenience method if
+     * <var>dimensions</var> are available as {@code long[]}.
+     */
+    public MDFloatArray(long[] dimensions)
+    {
+        this(new float[getLength(dimensions, 0)], toInt(dimensions), false);
+    }
+
+    /**
+     * Creates an empty {@link MDFloatArray} with the <var>dimensions</var>. If
+     * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+     * of <var>capacityHyperRows</var> hyper-rows. Convenience method if <var>dimensions</var> are
+     * available as {@code long[]}.
+     */
+    public MDFloatArray(long[] dimensions, long capacityHyperRows)
+    {
+        this(new float[getLength(dimensions, capacityHyperRows)], toInt(dimensions), false);
+    }
+
+    /**
+     * Creates a {@link MDFloatArray} from the given {@code flattenedArray} and {@code dimensions}. It
+     * is checked that the arguments are compatible. Convenience method if <var>dimensions</var> are
+     * available as {@code long[]}.
+     */
+    public MDFloatArray(float[] flattenedArray, long[] dimensions)
+    {
+        this(flattenedArray, toInt(dimensions), true);
+    }
+
+    /**
+     * Creates a {@link MDFloatArray} from the given <var>flattenedArray</var> and
+     * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+     * arguments are compatible. Convenience method if <var>dimensions</var> are available as
+     * {@code long[]}.
+     */
+    public MDFloatArray(float[] flattenedArray, long[] dimensions, boolean checkdimensions)
+    {
+        this(flattenedArray, toInt(dimensions), checkdimensions);
+    }
+
+    /**
+     * Creates an empty {@link MDFloatArray} with the <var>dimensions</var>.
+     */
+    public MDFloatArray(int[] dimensions)
+    {
+        this(new float[getLength(dimensions, 0)], dimensions, false);
+    }
+
+    /**
+     * Creates an empty {@link MDFloatArray} with the <var>dimensions</var>. If
+     * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+     * of <var>capacityHyperRows</var> hyper-rows.
+     */
+    public MDFloatArray(int[] dimensions, int capacityHyperRows)
+    {
+        this(new float[getLength(dimensions, capacityHyperRows)], dimensions, false);
+    }
+
+    /**
+     * Creates a {@link MDFloatArray} from the given {@code flattenedArray} and {@code dimensions}. It
+     * is checked that the arguments are compatible.
+     */
+    public MDFloatArray(float[] flattenedArray, int[] dimensions)
+    {
+        this(flattenedArray, dimensions, true);
+    }
+
+    /**
+     * Creates a {@link MDFloatArray} from the given <var>flattenedArray</var> and
+     * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+     * arguments are compatible.
+     */
+    public MDFloatArray(float[] flattenedArray, int[] dimensions, boolean checkdimensions)
+    {
+        super(dimensions, flattenedArray.length, 0);
+        assert flattenedArray != null;
+
+        if (checkdimensions)
+        {
+            final int expectedLength = getLength(dimensions, 0);
+            if (flattenedArray.length != expectedLength)
+            {
+                throw new IllegalArgumentException("Actual array length " + flattenedArray.length
+                        + " does not match expected length " + expectedLength + ".");
+            }
+        }
+        this.flattenedArray = flattenedArray;
+    }
+
+    /**
+     * Creates a {@link MDFloatArray} from the given <var>matrix</var> of rank 2. Note that the values
+     * in <var>matrix</var> will be copied and thus the created {@link MDIntArray} will be
+     * independent from <var>matrix</var> after construction.
+     */
+    public MDFloatArray(float[][] matrix)
+    {
+        this(matrix, getDimensions(matrix));
+    }
+
+    /**
+     * Creates a {@link MDFloatArray} from the given <var>matrix</var> of rank 2 and the
+     * <var>dimension</var> which need to be less or equal the dimensions of <var>matrix</var>. Note
+     * that the values in <var>matrix</var> will be copied and thus the created {@link MDIntArray}
+     * will be independent from <var>matrix</var> after construction.
+     */
+    public MDFloatArray(float[][] matrix, int[] dimensions)
+    {
+        super(dimensions, 0, matrix.length);
+
+        final int sizeX = dimensions[0];
+        final int sizeY = dimensions[1];
+        int length = getLength(dimensions, 0);
+        this.flattenedArray = new float[length];
+        for (int i = 0; i < sizeX; ++i)
+        {
+            System.arraycopy(matrix[i], 0, flattenedArray, i * sizeY, sizeY);
+        }
+    }
+
+    private static int[] getDimensions(float[][] matrix)
+    {
+        assert matrix != null;
+
+        return new int[]
+            { matrix.length, matrix.length == 0 ? 0 : matrix[0].length };
+    }
+
+    @Override
+    public int capacity()
+    {
+        return flattenedArray.length;
+    }
+
+    @Override
+    public Float getAsObject(int... indices)
+    {
+        return get(indices);
+    }
+
+    @Override
+    public void setToObject(Float value, int... indices)
+    {
+        set(value, indices);
+    }
+
+    @Override
+    public Float getAsObject(int linearIndex)
+    {
+        return get(linearIndex);
+    }
+
+    @Override
+    public void setToObject(Float value, int linearIndex)
+    {
+        set(value, linearIndex);
+    }
+
+    @Override
+    public float[] getAsFlatArray()
+    {
+        return flattenedArray;
+    }
+
+    @Override
+    public float[] getCopyAsFlatArray()
+    {
+        return ArrayUtils.subarray(flattenedArray, 0, dimensions[0] * hyperRowLength);
+    }
+
+    @Override
+    protected void adaptCapacityHyperRows()
+    {
+        final float[] oldArray = this.flattenedArray;
+        this.flattenedArray = new float[capacityHyperRows * hyperRowLength];
+        System.arraycopy(oldArray, 0, flattenedArray, 0,
+                Math.min(oldArray.length, flattenedArray.length));
+    }
+
+    /**
+     * Returns the value of array at the position defined by <var>indices</var>.
+     */
+    public float get(int... indices)
+    {
+        return flattenedArray[computeIndex(indices)];
+    }
+
+    /**
+     * Returns the value of a one-dimensional array at the position defined by <var>index</var>.
+     * <p>
+     * <b>Do not call for arrays other than one-dimensional!</b>
+     */
+    public float get(int index)
+    {
+        return flattenedArray[index];
+    }
+
+    /**
+     * Returns the value of a two-dimensional array at the position defined by <var>indexX</var> and
+     * <var>indexY</var>.
+     * <p>
+     * <b>Do not call for arrays other than two-dimensional!</b>
+     */
+    public float get(int indexX, int indexY)
+    {
+        return flattenedArray[computeIndex(indexX, indexY)];
+    }
+
+    /**
+     * Returns the value of a three-dimensional array at the position defined by <var>indexX</var>,
+     * <var>indexY</var> and <var>indexZ</var>.
+     * <p>
+     * <b>Do not call for arrays other than three-dimensional!</b>
+     */
+    public float get(int indexX, int indexY, int indexZ)
+    {
+        return flattenedArray[computeIndex(indexX, indexY, indexZ)];
+    }
+
+    /**
+     * Sets the <var>value</var> of array at the position defined by <var>indices</var>.
+     */
+    public void set(float value, int... indices)
+    {
+        flattenedArray[computeIndex(indices)] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a one-dimension array at the position defined by
+     * <var>index</var>.
+     * <p>
+     * <b>Do not call for arrays other than one-dimensional!</b>
+     */
+    public void set(float value, int index)
+    {
+        flattenedArray[index] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a two-dimensional array at the position defined by
+     * <var>indexX</var> and <var>indexY</var>.
+     * <p>
+     * <b>Do not call for arrays other than two-dimensional!</b>
+     */
+    public void set(float value, int indexX, int indexY)
+    {
+        flattenedArray[computeIndex(indexX, indexY)] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a three-dimensional array at the position defined by
+     * <var>indexX</var>, <var>indexY</var> and <var>indexZ</var>.
+     * <p>
+     * <b>Do not call for arrays other than three-dimensional!</b>
+     */
+    public void set(float value, int indexX, int indexY, int indexZ)
+    {
+        flattenedArray[computeIndex(indexX, indexY, indexZ)] = value;
+    }
+
+    /**
+     * Creates and returns a matrix from a two-dimensional array.
+     * <p>
+     * <b>Do not call for arrays other than two-dimensional!</b>
+     */
+    public float[][] toMatrix()
+    {
+        final int sizeX = dimensions[0];
+        final int sizeY = dimensions[1];
+        final float[][] result = new float[sizeX][sizeY];
+        for (int i = 0; i < sizeX; ++i)
+        {
+            System.arraycopy(flattenedArray, i * sizeY, result[i], 0, sizeY);
+        }
+        return result;
+    }
+
+    //
+    // Object
+    //
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(getValuesAsFlatArray());
+        result = prime * result + Arrays.hashCode(dimensions);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        MDFloatArray other = (MDFloatArray) obj;
+        if (Arrays.equals(getValuesAsFlatArray(), other.getValuesAsFlatArray()) == false)
+        {
+            return false;
+        }
+        if (Arrays.equals(dimensions, other.dimensions) == false)
+        {
+            return false;
+        }
+        return true;
+    }
+
+    private float[] getValuesAsFlatArray()
+    {
+        return (dimensions[0] < capacityHyperRows) ? getCopyAsFlatArray() : getAsFlatArray(); 
+    }
+    
+    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
+    {
+        stream.defaultReadObject();
+        if (hyperRowLength == 0)
+        {
+            this.hyperRowLength = computeHyperRowLength(dimensions);
+        }
+        if (capacityHyperRows == 0)
+        {
+            this.capacityHyperRows = dimensions[0];
+        }
+        if (size == 0)
+        {
+            this.size = hyperRowLength * dimensions[0];
+        }
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/mdarray/MDIntArray.java b/source/java/ch/systemsx/cisd/base/mdarray/MDIntArray.java
new file mode 100644
index 0000000..76cbcd1
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/mdarray/MDIntArray.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.mdarray;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Arrays;
+
+import org.apache.commons.lang.ArrayUtils;
+
+/**
+ * A multi-dimensional <code>int</code> array.
+ * 
+ * @author Bernd Rinn
+ */
+public final class MDIntArray extends MDAbstractArray<Integer>
+{
+    private static final long serialVersionUID = 1L;
+
+    private int[] flattenedArray;
+
+    /**
+     * Creates an empty {@link MDIntArray} with the <var>dimensions</var>. Convenience method if
+     * <var>dimensions</var> are available as {@code long[]}.
+     */
+    public MDIntArray(long[] dimensions)
+    {
+        this(new int[getLength(dimensions, 0)], toInt(dimensions), false);
+    }
+
+    /**
+     * Creates an empty {@link MDIntArray} with the <var>dimensions</var>. If
+     * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+     * of <var>capacityHyperRows</var> hyper-rows. Convenience method if <var>dimensions</var> are
+     * available as {@code long[]}.
+     */
+    public MDIntArray(long[] dimensions, long capacityHyperRows)
+    {
+        this(new int[getLength(dimensions, capacityHyperRows)], toInt(dimensions), false);
+    }
+
+    /**
+     * Creates a {@link MDIntArray} from the given {@code flattenedArray} and {@code dimensions}. It
+     * is checked that the arguments are compatible. Convenience method if <var>dimensions</var> are
+     * available as {@code long[]}.
+     */
+    public MDIntArray(int[] flattenedArray, long[] dimensions)
+    {
+        this(flattenedArray, toInt(dimensions), true);
+    }
+
+    /**
+     * Creates a {@link MDIntArray} from the given <var>flattenedArray</var> and
+     * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+     * arguments are compatible. Convenience method if <var>dimensions</var> are available as
+     * {@code long[]}.
+     */
+    public MDIntArray(int[] flattenedArray, long[] dimensions, boolean checkdimensions)
+    {
+        this(flattenedArray, toInt(dimensions), checkdimensions);
+    }
+
+    /**
+     * Creates an empty {@link MDIntArray} with the <var>dimensions</var>.
+     */
+    public MDIntArray(int[] dimensions)
+    {
+        this(new int[getLength(dimensions, 0)], dimensions, false);
+    }
+
+    /**
+     * Creates an empty {@link MDIntArray} with the <var>dimensions</var>. If
+     * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+     * of <var>capacityHyperRows</var> hyper-rows.
+     */
+    public MDIntArray(int[] dimensions, int capacityHyperRows)
+    {
+        this(new int[getLength(dimensions, capacityHyperRows)], dimensions, false);
+    }
+
+    /**
+     * Creates a {@link MDIntArray} from the given {@code flattenedArray} and {@code dimensions}. It
+     * is checked that the arguments are compatible.
+     */
+    public MDIntArray(int[] flattenedArray, int[] dimensions)
+    {
+        this(flattenedArray, dimensions, true);
+    }
+
+    /**
+     * Creates a {@link MDIntArray} from the given <var>flattenedArray</var> and
+     * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+     * arguments are compatible.
+     */
+    public MDIntArray(int[] flattenedArray, int[] dimensions, boolean checkdimensions)
+    {
+        super(dimensions, flattenedArray.length, 0);
+        assert flattenedArray != null;
+
+        if (checkdimensions)
+        {
+            final int expectedLength = getLength(dimensions, 0);
+            if (flattenedArray.length != expectedLength)
+            {
+                throw new IllegalArgumentException("Actual array length " + flattenedArray.length
+                        + " does not match expected length " + expectedLength + ".");
+            }
+        }
+        this.flattenedArray = flattenedArray;
+    }
+
+    /**
+     * Creates a {@link MDIntArray} from the given <var>matrix</var> of rank 2. Note that the values
+     * in <var>matrix</var> will be copied and thus the created {@link MDIntArray} will be
+     * independent from <var>matrix</var> after construction.
+     */
+    public MDIntArray(int[][] matrix)
+    {
+        this(matrix, getDimensions(matrix));
+    }
+
+    /**
+     * Creates a {@link MDIntArray} from the given <var>matrix</var> of rank 2 and the
+     * <var>dimension</var> which need to be less or equal the dimensions of <var>matrix</var>. Note
+     * that the values in <var>matrix</var> will be copied and thus the created {@link MDIntArray}
+     * will be independent from <var>matrix</var> after construction.
+     */
+    public MDIntArray(int[][] matrix, int[] dimensions)
+    {
+        super(dimensions, 0, matrix.length);
+
+        final int sizeX = dimensions[0];
+        final int sizeY = dimensions[1];
+        int length = getLength(dimensions, 0);
+        this.flattenedArray = new int[length];
+        for (int i = 0; i < sizeX; ++i)
+        {
+            System.arraycopy(matrix[i], 0, flattenedArray, i * sizeY, sizeY);
+        }
+    }
+
+    private static int[] getDimensions(int[][] matrix)
+    {
+        assert matrix != null;
+
+        return new int[]
+            { matrix.length, matrix.length == 0 ? 0 : matrix[0].length };
+    }
+
+    @Override
+    public int capacity()
+    {
+        return flattenedArray.length;
+    }
+
+    @Override
+    public Integer getAsObject(int... indices)
+    {
+        return get(indices);
+    }
+
+    @Override
+    public void setToObject(Integer value, int... indices)
+    {
+        set(value, indices);
+    }
+
+    @Override
+    public Integer getAsObject(int linearIndex)
+    {
+        return get(linearIndex);
+    }
+
+    @Override
+    public void setToObject(Integer value, int linearIndex)
+    {
+        set(value, linearIndex);
+    }
+
+    @Override
+    public int[] getAsFlatArray()
+    {
+        return flattenedArray;
+    }
+
+    @Override
+    public int[] getCopyAsFlatArray()
+    {
+        return ArrayUtils.subarray(flattenedArray, 0, dimensions[0] * hyperRowLength);
+    }
+
+    @Override
+    protected void adaptCapacityHyperRows()
+    {
+        final int[] oldArray = this.flattenedArray;
+        this.flattenedArray = new int[capacityHyperRows * hyperRowLength];
+        System.arraycopy(oldArray, 0, flattenedArray, 0,
+                Math.min(oldArray.length, flattenedArray.length));
+    }
+
+    /**
+     * Returns the value of array at the position defined by <var>indices</var>.
+     */
+    public int get(int... indices)
+    {
+        return flattenedArray[computeIndex(indices)];
+    }
+
+    /**
+     * Returns the value of a one-dimensional array at the position defined by <var>index</var>.
+     * <p>
+     * <b>Do not call for arrays other than one-dimensional!</b>
+     */
+    public int get(int index)
+    {
+        return flattenedArray[index];
+    }
+
+    /**
+     * Returns the value of a two-dimensional array at the position defined by <var>indexX</var> and
+     * <var>indexY</var>.
+     * <p>
+     * <b>Do not call for arrays other than two-dimensional!</b>
+     */
+    public int get(int indexX, int indexY)
+    {
+        return flattenedArray[computeIndex(indexX, indexY)];
+    }
+
+    /**
+     * Returns the value of a three-dimensional array at the position defined by <var>indexX</var>,
+     * <var>indexY</var> and <var>indexZ</var>.
+     * <p>
+     * <b>Do not call for arrays other than three-dimensional!</b>
+     */
+    public int get(int indexX, int indexY, int indexZ)
+    {
+        return flattenedArray[computeIndex(indexX, indexY, indexZ)];
+    }
+
+    /**
+     * Sets the <var>value</var> of array at the position defined by <var>indices</var>.
+     */
+    public void set(int value, int... indices)
+    {
+        flattenedArray[computeIndex(indices)] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a one-dimension array at the position defined by
+     * <var>index</var>.
+     * <p>
+     * <b>Do not call for arrays other than one-dimensional!</b>
+     */
+    public void set(int value, int index)
+    {
+        flattenedArray[index] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a two-dimensional array at the position defined by
+     * <var>indexX</var> and <var>indexY</var>.
+     * <p>
+     * <b>Do not call for arrays other than two-dimensional!</b>
+     */
+    public void set(int value, int indexX, int indexY)
+    {
+        flattenedArray[computeIndex(indexX, indexY)] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a three-dimensional array at the position defined by
+     * <var>indexX</var>, <var>indexY</var> and <var>indexZ</var>.
+     * <p>
+     * <b>Do not call for arrays other than three-dimensional!</b>
+     */
+    public void set(int value, int indexX, int indexY, int indexZ)
+    {
+        flattenedArray[computeIndex(indexX, indexY, indexZ)] = value;
+    }
+
+    /**
+     * Creates and returns a matrix from a two-dimensional array.
+     * <p>
+     * <b>Do not call for arrays other than two-dimensional!</b>
+     */
+    public int[][] toMatrix()
+    {
+        final int sizeX = dimensions[0];
+        final int sizeY = dimensions[1];
+        final int[][] result = new int[sizeX][sizeY];
+        for (int i = 0; i < sizeX; ++i)
+        {
+            System.arraycopy(flattenedArray, i * sizeY, result[i], 0, sizeY);
+        }
+        return result;
+    }
+
+    //
+    // Object
+    //
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(getValuesAsFlatArray());
+        result = prime * result + Arrays.hashCode(dimensions);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        MDIntArray other = (MDIntArray) obj;
+        if (Arrays.equals(getValuesAsFlatArray(), other.getValuesAsFlatArray()) == false)
+        {
+            return false;
+        }
+        if (Arrays.equals(dimensions, other.dimensions) == false)
+        {
+            return false;
+        }
+        return true;
+    }
+
+    private int[] getValuesAsFlatArray()
+    {
+        return (dimensions[0] < capacityHyperRows) ? getCopyAsFlatArray() : getAsFlatArray(); 
+    }
+    
+    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
+    {
+        stream.defaultReadObject();
+        if (hyperRowLength == 0)
+        {
+            this.hyperRowLength = computeHyperRowLength(dimensions);
+        }
+        if (capacityHyperRows == 0)
+        {
+            this.capacityHyperRows = dimensions[0];
+        }
+        if (size == 0)
+        {
+            this.size = hyperRowLength * dimensions[0];
+        }
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/mdarray/MDLongArray.java b/source/java/ch/systemsx/cisd/base/mdarray/MDLongArray.java
new file mode 100644
index 0000000..3b927b1
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/mdarray/MDLongArray.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.mdarray;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Arrays;
+
+import org.apache.commons.lang.ArrayUtils;
+
+/**
+ * A multi-dimensional <code>long</code> array.
+ * 
+ * @author Bernd Rinn
+ */
+public final class MDLongArray extends MDAbstractArray<Long>
+{
+    private static final long serialVersionUID = 1L;
+
+    private long[] flattenedArray;
+
+    /**
+     * Creates an empty {@link MDIntArray} with the <var>dimensions</var>. Convenience method if
+     * <var>dimensions</var> are available as {@code long[]}.
+     */
+    public MDLongArray(long[] dimensions)
+    {
+        this(new long[getLength(dimensions, 0)], toInt(dimensions), false);
+    }
+
+    /**
+     * Creates an empty {@link MDLongArray} with the <var>dimensions</var>. If
+     * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+     * of <var>capacityHyperRows</var> hyper-rows. Convenience method if <var>dimensions</var> are
+     * available as {@code long[]}.
+     */
+    public MDLongArray(long[] dimensions, long capacityHyperRows)
+    {
+        this(new long[getLength(dimensions, capacityHyperRows)], toInt(dimensions), false);
+    }
+
+    /**
+     * Creates a {@link MDLongArray} from the given {@code flattenedArray} and {@code dimensions}. It
+     * is checked that the arguments are compatible. Convenience method if <var>dimensions</var> are
+     * available as {@code long[]}.
+     */
+    public MDLongArray(long[] flattenedArray, long[] dimensions)
+    {
+        this(flattenedArray, toInt(dimensions), true);
+    }
+
+    /**
+     * Creates a {@link MDLongArray} from the given <var>flattenedArray</var> and
+     * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+     * arguments are compatible. Convenience method if <var>dimensions</var> are available as
+     * {@code long[]}.
+     */
+    public MDLongArray(long[] flattenedArray, long[] dimensions, boolean checkdimensions)
+    {
+        this(flattenedArray, toInt(dimensions), checkdimensions);
+    }
+
+    /**
+     * Creates an empty {@link MDLongArray} with the <var>dimensions</var>.
+     */
+    public MDLongArray(int[] dimensions)
+    {
+        this(new long[getLength(dimensions, 0)], dimensions, false);
+    }
+
+    /**
+     * Creates an empty {@link MDLongArray} with the <var>dimensions</var>. If
+     * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+     * of <var>capacityHyperRows</var> hyper-rows.
+     */
+    public MDLongArray(int[] dimensions, int capacityHyperRows)
+    {
+        this(new long[getLength(dimensions, capacityHyperRows)], dimensions, false);
+    }
+
+    /**
+     * Creates a {@link MDLongArray} from the given {@code flattenedArray} and {@code dimensions}. It
+     * is checked that the arguments are compatible.
+     */
+    public MDLongArray(long[] flattenedArray, int[] dimensions)
+    {
+        this(flattenedArray, dimensions, true);
+    }
+
+    /**
+     * Creates a {@link MDLongArray} from the given <var>flattenedArray</var> and
+     * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+     * arguments are compatible.
+     */
+    public MDLongArray(long[] flattenedArray, int[] dimensions, boolean checkdimensions)
+    {
+        super(dimensions, flattenedArray.length, 0);
+        assert flattenedArray != null;
+
+        if (checkdimensions)
+        {
+            final int expectedLength = getLength(dimensions, 0);
+            if (flattenedArray.length != expectedLength)
+            {
+                throw new IllegalArgumentException("Actual array length " + flattenedArray.length
+                        + " does not match expected length " + expectedLength + ".");
+            }
+        }
+        this.flattenedArray = flattenedArray;
+    }
+
+    /**
+     * Creates a {@link MDLongArray} from the given <var>matrix</var> of rank 2. Note that the values
+     * in <var>matrix</var> will be copied and thus the created {@link MDIntArray} will be
+     * independent from <var>matrix</var> after construction.
+     */
+    public MDLongArray(long[][] matrix)
+    {
+        this(matrix, getDimensions(matrix));
+    }
+
+    /**
+     * Creates a {@link MDLongArray} from the given <var>matrix</var> of rank 2 and the
+     * <var>dimension</var> which need to be less or equal the dimensions of <var>matrix</var>. Note
+     * that the values in <var>matrix</var> will be copied and thus the created {@link MDIntArray}
+     * will be independent from <var>matrix</var> after construction.
+     */
+    public MDLongArray(long[][] matrix, int[] dimensions)
+    {
+        super(dimensions, 0, matrix.length);
+
+        final int sizeX = dimensions[0];
+        final int sizeY = dimensions[1];
+        int length = getLength(dimensions, 0);
+        this.flattenedArray = new long[length];
+        for (int i = 0; i < sizeX; ++i)
+        {
+            System.arraycopy(matrix[i], 0, flattenedArray, i * sizeY, sizeY);
+        }
+    }
+
+    private static int[] getDimensions(long[][] matrix)
+    {
+        assert matrix != null;
+
+        return new int[]
+            { matrix.length, matrix.length == 0 ? 0 : matrix[0].length };
+    }
+
+    @Override
+    public int capacity()
+    {
+        return flattenedArray.length;
+    }
+
+    @Override
+    public Long getAsObject(int... indices)
+    {
+        return get(indices);
+    }
+
+    @Override
+    public void setToObject(Long value, int... indices)
+    {
+        set(value, indices);
+    }
+
+    @Override
+    public Long getAsObject(int linearIndex)
+    {
+        return get(linearIndex);
+    }
+
+    @Override
+    public void setToObject(Long value, int linearIndex)
+    {
+        set(value, linearIndex);
+    }
+
+    @Override
+    public long[] getAsFlatArray()
+    {
+        return flattenedArray;
+    }
+
+    @Override
+    public long[] getCopyAsFlatArray()
+    {
+        return ArrayUtils.subarray(flattenedArray, 0, dimensions[0] * hyperRowLength);
+    }
+
+    @Override
+    protected void adaptCapacityHyperRows()
+    {
+        final long[] oldArray = this.flattenedArray;
+        this.flattenedArray = new long[capacityHyperRows * hyperRowLength];
+        System.arraycopy(oldArray, 0, flattenedArray, 0,
+                Math.min(oldArray.length, flattenedArray.length));
+    }
+
+    /**
+     * Returns the value of array at the position defined by <var>indices</var>.
+     */
+    public long get(int... indices)
+    {
+        return flattenedArray[computeIndex(indices)];
+    }
+
+    /**
+     * Returns the value of a one-dimensional array at the position defined by <var>index</var>.
+     * <p>
+     * <b>Do not call for arrays other than one-dimensional!</b>
+     */
+    public long get(int index)
+    {
+        return flattenedArray[index];
+    }
+
+    /**
+     * Returns the value of a two-dimensional array at the position defined by <var>indexX</var> and
+     * <var>indexY</var>.
+     * <p>
+     * <b>Do not call for arrays other than two-dimensional!</b>
+     */
+    public long get(int indexX, int indexY)
+    {
+        return flattenedArray[computeIndex(indexX, indexY)];
+    }
+
+    /**
+     * Returns the value of a three-dimensional array at the position defined by <var>indexX</var>,
+     * <var>indexY</var> and <var>indexZ</var>.
+     * <p>
+     * <b>Do not call for arrays other than three-dimensional!</b>
+     */
+    public long get(int indexX, int indexY, int indexZ)
+    {
+        return flattenedArray[computeIndex(indexX, indexY, indexZ)];
+    }
+
+    /**
+     * Sets the <var>value</var> of array at the position defined by <var>indices</var>.
+     */
+    public void set(long value, int... indices)
+    {
+        flattenedArray[computeIndex(indices)] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a one-dimension array at the position defined by
+     * <var>index</var>.
+     * <p>
+     * <b>Do not call for arrays other than one-dimensional!</b>
+     */
+    public void set(long value, int index)
+    {
+        flattenedArray[index] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a two-dimensional array at the position defined by
+     * <var>indexX</var> and <var>indexY</var>.
+     * <p>
+     * <b>Do not call for arrays other than two-dimensional!</b>
+     */
+    public void set(long value, int indexX, int indexY)
+    {
+        flattenedArray[computeIndex(indexX, indexY)] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a three-dimensional array at the position defined by
+     * <var>indexX</var>, <var>indexY</var> and <var>indexZ</var>.
+     * <p>
+     * <b>Do not call for arrays other than three-dimensional!</b>
+     */
+    public void set(long value, int indexX, int indexY, int indexZ)
+    {
+        flattenedArray[computeIndex(indexX, indexY, indexZ)] = value;
+    }
+
+    /**
+     * Creates and returns a matrix from a two-dimensional array.
+     * <p>
+     * <b>Do not call for arrays other than two-dimensional!</b>
+     */
+    public long[][] toMatrix()
+    {
+        final int sizeX = dimensions[0];
+        final int sizeY = dimensions[1];
+        final long[][] result = new long[sizeX][sizeY];
+        for (int i = 0; i < sizeX; ++i)
+        {
+            System.arraycopy(flattenedArray, i * sizeY, result[i], 0, sizeY);
+        }
+        return result;
+    }
+
+    //
+    // Object
+    //
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(getValuesAsFlatArray());
+        result = prime * result + Arrays.hashCode(dimensions);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        MDLongArray other = (MDLongArray) obj;
+        if (Arrays.equals(getValuesAsFlatArray(), other.getValuesAsFlatArray()) == false)
+        {
+            return false;
+        }
+        if (Arrays.equals(dimensions, other.dimensions) == false)
+        {
+            return false;
+        }
+        return true;
+    }
+
+    private long[] getValuesAsFlatArray()
+    {
+        return (dimensions[0] < capacityHyperRows) ? getCopyAsFlatArray() : getAsFlatArray(); 
+    }
+    
+    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
+    {
+        stream.defaultReadObject();
+        if (hyperRowLength == 0)
+        {
+            this.hyperRowLength = computeHyperRowLength(dimensions);
+        }
+        if (capacityHyperRows == 0)
+        {
+            this.capacityHyperRows = dimensions[0];
+        }
+        if (size == 0)
+        {
+            this.size = hyperRowLength * dimensions[0];
+        }
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/mdarray/MDShortArray.java b/source/java/ch/systemsx/cisd/base/mdarray/MDShortArray.java
new file mode 100644
index 0000000..eefb0b8
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/mdarray/MDShortArray.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.mdarray;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Arrays;
+
+import org.apache.commons.lang.ArrayUtils;
+
+/**
+ * A multi-dimensional <code>short</code> array.
+ * 
+ * @author Bernd Rinn
+ */
+public final class MDShortArray extends MDAbstractArray<Short>
+{
+    private static final long serialVersionUID = 1L;
+
+    private short[] flattenedArray;
+
+    /**
+     * Creates an empty {@link MDIntArray} with the <var>dimensions</var>. Convenience method if
+     * <var>dimensions</var> are available as {@code long[]}.
+     */
+    public MDShortArray(long[] dimensions)
+    {
+        this(new short[getLength(dimensions, 0)], toInt(dimensions), false);
+    }
+
+    /**
+     * Creates an empty {@link MDShortArray} with the <var>dimensions</var>. If
+     * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+     * of <var>capacityHyperRows</var> hyper-rows. Convenience method if <var>dimensions</var> are
+     * available as {@code long[]}.
+     */
+    public MDShortArray(long[] dimensions, long capacityHyperRows)
+    {
+        this(new short[getLength(dimensions, capacityHyperRows)], toInt(dimensions), false);
+    }
+
+    /**
+     * Creates a {@link MDShortArray} from the given {@code flattenedArray} and {@code dimensions}. It
+     * is checked that the arguments are compatible. Convenience method if <var>dimensions</var> are
+     * available as {@code long[]}.
+     */
+    public MDShortArray(short[] flattenedArray, long[] dimensions)
+    {
+        this(flattenedArray, toInt(dimensions), true);
+    }
+
+    /**
+     * Creates a {@link MDShortArray} from the given <var>flattenedArray</var> and
+     * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+     * arguments are compatible. Convenience method if <var>dimensions</var> are available as
+     * {@code long[]}.
+     */
+    public MDShortArray(short[] flattenedArray, long[] dimensions, boolean checkdimensions)
+    {
+        this(flattenedArray, toInt(dimensions), checkdimensions);
+    }
+
+    /**
+     * Creates an empty {@link MDShortArray} with the <var>dimensions</var>.
+     */
+    public MDShortArray(int[] dimensions)
+    {
+        this(new short[getLength(dimensions, 0)], dimensions, false);
+    }
+
+    /**
+     * Creates an empty {@link MDShortArray} with the <var>dimensions</var>. If
+     * <code>capacityHyperRows > dimensions[0]</code>, then it will create an array with a capacity
+     * of <var>capacityHyperRows</var> hyper-rows.
+     */
+    public MDShortArray(int[] dimensions, int capacityHyperRows)
+    {
+        this(new short[getLength(dimensions, capacityHyperRows)], dimensions, false);
+    }
+
+    /**
+     * Creates a {@link MDShortArray} from the given {@code flattenedArray} and {@code dimensions}. It
+     * is checked that the arguments are compatible.
+     */
+    public MDShortArray(short[] flattenedArray, int[] dimensions)
+    {
+        this(flattenedArray, dimensions, true);
+    }
+
+    /**
+     * Creates a {@link MDShortArray} from the given <var>flattenedArray</var> and
+     * <var>dimensions</var>. If <var>checkDimensions</var> is {@code true}, it is checked that the
+     * arguments are compatible.
+     */
+    public MDShortArray(short[] flattenedArray, int[] dimensions, boolean checkdimensions)
+    {
+        super(dimensions, flattenedArray.length, 0);
+        assert flattenedArray != null;
+
+        if (checkdimensions)
+        {
+            final int expectedLength = getLength(dimensions, 0);
+            if (flattenedArray.length != expectedLength)
+            {
+                throw new IllegalArgumentException("Actual array length " + flattenedArray.length
+                        + " does not match expected length " + expectedLength + ".");
+            }
+        }
+        this.flattenedArray = flattenedArray;
+    }
+
+    /**
+     * Creates a {@link MDShortArray} from the given <var>matrix</var> of rank 2. Note that the values
+     * in <var>matrix</var> will be copied and thus the created {@link MDIntArray} will be
+     * independent from <var>matrix</var> after construction.
+     */
+    public MDShortArray(short[][] matrix)
+    {
+        this(matrix, getDimensions(matrix));
+    }
+
+    /**
+     * Creates a {@link MDShortArray} from the given <var>matrix</var> of rank 2 and the
+     * <var>dimension</var> which need to be less or equal the dimensions of <var>matrix</var>. Note
+     * that the values in <var>matrix</var> will be copied and thus the created {@link MDIntArray}
+     * will be independent from <var>matrix</var> after construction.
+     */
+    public MDShortArray(short[][] matrix, int[] dimensions)
+    {
+        super(dimensions, 0, matrix.length);
+
+        final int sizeX = dimensions[0];
+        final int sizeY = dimensions[1];
+        int length = getLength(dimensions, 0);
+        this.flattenedArray = new short[length];
+        for (int i = 0; i < sizeX; ++i)
+        {
+            System.arraycopy(matrix[i], 0, flattenedArray, i * sizeY, sizeY);
+        }
+    }
+
+    private static int[] getDimensions(short[][] matrix)
+    {
+        assert matrix != null;
+
+        return new int[]
+            { matrix.length, matrix.length == 0 ? 0 : matrix[0].length };
+    }
+
+    @Override
+    public int capacity()
+    {
+        return flattenedArray.length;
+    }
+
+    @Override
+    public Short getAsObject(int... indices)
+    {
+        return get(indices);
+    }
+
+    @Override
+    public void setToObject(Short value, int... indices)
+    {
+        set(value, indices);
+    }
+
+    @Override
+    public Short getAsObject(int linearIndex)
+    {
+        return get(linearIndex);
+    }
+
+    @Override
+    public void setToObject(Short value, int linearIndex)
+    {
+        set(value, linearIndex);
+    }
+
+    @Override
+    public short[] getAsFlatArray()
+    {
+        return flattenedArray;
+    }
+
+    @Override
+    public short[] getCopyAsFlatArray()
+    {
+        return ArrayUtils.subarray(flattenedArray, 0, dimensions[0] * hyperRowLength);
+    }
+
+    @Override
+    protected void adaptCapacityHyperRows()
+    {
+        final short[] oldArray = this.flattenedArray;
+        this.flattenedArray = new short[capacityHyperRows * hyperRowLength];
+        System.arraycopy(oldArray, 0, flattenedArray, 0,
+                Math.min(oldArray.length, flattenedArray.length));
+    }
+
+    /**
+     * Returns the value of array at the position defined by <var>indices</var>.
+     */
+    public short get(int... indices)
+    {
+        return flattenedArray[computeIndex(indices)];
+    }
+
+    /**
+     * Returns the value of a one-dimensional array at the position defined by <var>index</var>.
+     * <p>
+     * <b>Do not call for arrays other than one-dimensional!</b>
+     */
+    public short get(int index)
+    {
+        return flattenedArray[index];
+    }
+
+    /**
+     * Returns the value of a two-dimensional array at the position defined by <var>indexX</var> and
+     * <var>indexY</var>.
+     * <p>
+     * <b>Do not call for arrays other than two-dimensional!</b>
+     */
+    public short get(int indexX, int indexY)
+    {
+        return flattenedArray[computeIndex(indexX, indexY)];
+    }
+
+    /**
+     * Returns the value of a three-dimensional array at the position defined by <var>indexX</var>,
+     * <var>indexY</var> and <var>indexZ</var>.
+     * <p>
+     * <b>Do not call for arrays other than three-dimensional!</b>
+     */
+    public short get(int indexX, int indexY, int indexZ)
+    {
+        return flattenedArray[computeIndex(indexX, indexY, indexZ)];
+    }
+
+    /**
+     * Sets the <var>value</var> of array at the position defined by <var>indices</var>.
+     */
+    public void set(short value, int... indices)
+    {
+        flattenedArray[computeIndex(indices)] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a one-dimension array at the position defined by
+     * <var>index</var>.
+     * <p>
+     * <b>Do not call for arrays other than one-dimensional!</b>
+     */
+    public void set(short value, int index)
+    {
+        flattenedArray[index] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a two-dimensional array at the position defined by
+     * <var>indexX</var> and <var>indexY</var>.
+     * <p>
+     * <b>Do not call for arrays other than two-dimensional!</b>
+     */
+    public void set(short value, int indexX, int indexY)
+    {
+        flattenedArray[computeIndex(indexX, indexY)] = value;
+    }
+
+    /**
+     * Sets the <var>value</var> of a three-dimensional array at the position defined by
+     * <var>indexX</var>, <var>indexY</var> and <var>indexZ</var>.
+     * <p>
+     * <b>Do not call for arrays other than three-dimensional!</b>
+     */
+    public void set(short value, int indexX, int indexY, int indexZ)
+    {
+        flattenedArray[computeIndex(indexX, indexY, indexZ)] = value;
+    }
+
+    /**
+     * Creates and returns a matrix from a two-dimensional array.
+     * <p>
+     * <b>Do not call for arrays other than two-dimensional!</b>
+     */
+    public short[][] toMatrix()
+    {
+        final int sizeX = dimensions[0];
+        final int sizeY = dimensions[1];
+        final short[][] result = new short[sizeX][sizeY];
+        for (int i = 0; i < sizeX; ++i)
+        {
+            System.arraycopy(flattenedArray, i * sizeY, result[i], 0, sizeY);
+        }
+        return result;
+    }
+
+    //
+    // Object
+    //
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(getValuesAsFlatArray());
+        result = prime * result + Arrays.hashCode(dimensions);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        MDShortArray other = (MDShortArray) obj;
+        if (Arrays.equals(getValuesAsFlatArray(), other.getValuesAsFlatArray()) == false)
+        {
+            return false;
+        }
+        if (Arrays.equals(dimensions, other.dimensions) == false)
+        {
+            return false;
+        }
+        return true;
+    }
+
+    private short[] getValuesAsFlatArray()
+    {
+        return (dimensions[0] < capacityHyperRows) ? getCopyAsFlatArray() : getAsFlatArray(); 
+    }
+    
+    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
+    {
+        stream.defaultReadObject();
+        if (hyperRowLength == 0)
+        {
+            this.hyperRowLength = computeHyperRowLength(dimensions);
+        }
+        if (capacityHyperRows == 0)
+        {
+            this.capacityHyperRows = dimensions[0];
+        }
+        if (size == 0)
+        {
+            this.size = hyperRowLength * dimensions[0];
+        }
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/mdarray/package.html b/source/java/ch/systemsx/cisd/base/mdarray/package.html
new file mode 100644
index 0000000..1788c17
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/mdarray/package.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+     "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Multi-dimensional arrays.</title>
+</head>
+<body>
+<p>
+This package provides an implementation of multi-dimensional numerical arrays in Java. Contrary to 
+the <i>array of arrays</i> representation that is built into the Java language, the classes in this 
+package use one contiguous array and appropriate index operations to access the elements of the 
+array.    
+</p>
+<p>
+The number of indices (or axis') of an array is called the <i>rank</i> of the array, the set of 
+extends of the array along each of its axis' are called the <i>dimensions</i> of the array.
+</p>
+</body>
+</html> 
\ No newline at end of file
diff --git a/source/java/ch/systemsx/cisd/base/namedthread/ICallableNameProvider.java b/source/java/ch/systemsx/cisd/base/namedthread/ICallableNameProvider.java
new file mode 100644
index 0000000..061e213
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/namedthread/ICallableNameProvider.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.namedthread;
+
+/**
+ * A name provider for a {@link java.util.concurrent.Callable}.
+ *
+ * @author Bernd Rinn
+ */
+public interface ICallableNameProvider
+{
+    /** Returns the name to be used for the thread name. */
+    public String getCallableName();
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/namedthread/IRunnableNameProvider.java b/source/java/ch/systemsx/cisd/base/namedthread/IRunnableNameProvider.java
new file mode 100644
index 0000000..adf021b
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/namedthread/IRunnableNameProvider.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.namedthread;
+
+/**
+ * A name provider for a {@link Runnable}.
+ *
+ * @author Bernd Rinn
+ */
+public interface IRunnableNameProvider
+{
+    /** Returns the name to be used for the thread name. */
+    public String getRunnableName();
+}
diff --git a/source/java/ch/systemsx/cisd/base/namedthread/NamedCallable.java b/source/java/ch/systemsx/cisd/base/namedthread/NamedCallable.java
new file mode 100644
index 0000000..7bf3022
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/namedthread/NamedCallable.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.namedthread;
+
+import java.util.concurrent.Callable;
+
+/**
+ * A {@link Callable} with a name.
+ *
+ * @author Bernd Rinn
+ */
+public interface NamedCallable<T> extends Callable<T>, ICallableNameProvider
+{
+}
diff --git a/source/java/ch/systemsx/cisd/base/namedthread/NamedFutureTask.java b/source/java/ch/systemsx/cisd/base/namedthread/NamedFutureTask.java
new file mode 100644
index 0000000..7114e2a
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/namedthread/NamedFutureTask.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.namedthread;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.FutureTask;
+
+/**
+ * A {@link FutureTask} with a name.
+ * 
+ * @author Bernd Rinn
+ */
+class NamedFutureTask<V> extends FutureTask<V> implements NamedRunnable
+{
+    private final String name;
+    
+    private Thread thread;
+    
+    private String oldThreadName;
+
+    NamedFutureTask(Callable<V> callable)
+    {
+        super(callable);
+        this.name =
+                (callable instanceof ICallableNameProvider) ? ((ICallableNameProvider) callable)
+                        .getCallableName() : null;
+    }
+
+    NamedFutureTask(Runnable runnable, V result)
+    {
+        super(runnable, result);
+        this.name =
+                (runnable instanceof IRunnableNameProvider) ? ((IRunnableNameProvider) runnable)
+                        .getRunnableName() : null;
+    }
+
+    void restoreThreadName()
+    {
+        if (this.thread != null)
+        {
+            this.thread.setName(oldThreadName);
+            this.thread = null;
+        }
+    }
+
+    void setThread(Thread thread)
+    {
+        this.thread = thread;
+        this.oldThreadName = thread.getName();
+    }
+
+    @Override
+    public String getRunnableName()
+    {
+        return name;
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/namedthread/NamedRunnable.java b/source/java/ch/systemsx/cisd/base/namedthread/NamedRunnable.java
new file mode 100644
index 0000000..e4ceec0
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/namedthread/NamedRunnable.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.namedthread;
+
+/**
+ * A {@link Runnable} with a name.
+ *
+ * @author Bernd Rinn
+ */
+public interface NamedRunnable extends Runnable, IRunnableNameProvider
+{
+}
diff --git a/source/java/ch/systemsx/cisd/base/namedthread/NamingThreadFactory.java b/source/java/ch/systemsx/cisd/base/namedthread/NamingThreadFactory.java
new file mode 100644
index 0000000..f74e529
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/namedthread/NamingThreadFactory.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.namedthread;
+
+import java.util.concurrent.ThreadFactory;
+
+/**
+ * A {@link ThreadFactory} that gives (non-standard) names to new threads. If a name is a
+ * {@link IRunnableNameProvider}, the name provided by
+ * {@link IRunnableNameProvider#getRunnableName()} will be used, otherwise the
+ * <var>defaultName</var>. The thread count (number of already created threads in this factory) will
+ * always be appended.
+ * 
+ * @author Bernd Rinn
+ */
+public class NamingThreadFactory implements ThreadFactory
+{
+
+    private final String poolName;
+
+    private boolean createDaemonThreads;
+
+    private boolean addPoolName;
+
+    private int threadCount;
+
+    public NamingThreadFactory(String poolName)
+    {
+        this.poolName = poolName;
+        this.addPoolName = true;
+        this.createDaemonThreads = false;
+        this.threadCount = 0;
+    }
+
+    @Override
+    public Thread newThread(Runnable r)
+    {
+        ++threadCount;
+        final String completePoolName = poolName + "-T" + threadCount;
+        final Thread thread = new PoolNameThread(r, completePoolName, addPoolName);
+        thread.setDaemon(createDaemonThreads);
+        return thread;
+    }
+
+    String getPoolName()
+    {
+        return poolName;
+    }
+
+    public final boolean isCreateDaemonThreads()
+    {
+        return createDaemonThreads;
+    }
+
+    public final void setCreateDaemonThreads(boolean createDaemonThreads)
+    {
+        this.createDaemonThreads = createDaemonThreads;
+    }
+
+    public final int getThreadCount()
+    {
+        return threadCount;
+    }
+
+    public final boolean isAddPoolName()
+    {
+        return addPoolName;
+    }
+
+    public final void setAddPoolName(boolean addPoolName)
+    {
+        this.addPoolName = addPoolName;
+    }
+}
diff --git a/source/java/ch/systemsx/cisd/base/namedthread/NamingThreadPoolExecutor.java b/source/java/ch/systemsx/cisd/base/namedthread/NamingThreadPoolExecutor.java
new file mode 100644
index 0000000..1cd26ed
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/namedthread/NamingThreadPoolExecutor.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.namedthread;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A {@link ThreadPoolExecutor} that allows to attach names to the threads it manages. These names
+ * can come either from {@link IRunnableNameProvider}s or {@link ICallableNameProvider}s, or, if
+ * their standard counterparts are submitted, a default name is used.
+ * 
+ * @author Bernd Rinn
+ */
+public class NamingThreadPoolExecutor extends ThreadPoolExecutor
+{
+
+    /**
+     * The default time (in milli-seconds) to keep threads alive that are above the core pool size.
+     */
+    public final static long DEFAULT_KEEP_ALIVE_TIME_MILLIS = 10000L;
+
+    /**
+     * Creates a new (caching) <tt>NamingThreadPoolExecutor</tt> with the given initial parameters.
+     * This executor will create new threads as needed.
+     * 
+     * @param poolName the default name for new threads
+     */
+    public NamingThreadPoolExecutor(String poolName)
+    {
+        this(poolName, 0);
+    }
+
+    /**
+     * Creates a new (caching) <tt>NamingThreadPoolExecutor</tt> with the given initial parameters.
+     * This executor will create new threads as needed.
+     * 
+     * @param poolName The default name for new threads.
+     * @param workQueueSize The size of the work queue (0 for no queue).
+     * 
+     */
+    public NamingThreadPoolExecutor(String poolName, int workQueueSize)
+    {
+        super(1, Integer.MAX_VALUE, DEFAULT_KEEP_ALIVE_TIME_MILLIS, TimeUnit.MILLISECONDS,
+                workQueueSize == 0 ? new SynchronousQueue<Runnable>()
+                        : new LinkedBlockingQueue<Runnable>(workQueueSize),
+                new NamingThreadFactory(poolName));
+    }
+
+    /**
+     * Creates a new <tt>NamingThreadPoolExecutor</tt> with the given initial parameters.
+     * 
+     * @param poolName the default name for new threads
+     * @param corePoolSize the number of threads to keep in the pool, even if they are idle.
+     * @param maximumPoolSize the maximum number of threads to allow in the pool.
+     * @param keepAliveTime when the number of threads is greater than the core, this is the maximum
+     *            time that excess idle threads will wait for new tasks before terminating.
+     * @param unit the time unit for the keepAliveTime argument.
+     * @param workQueue the queue to use for holding tasks before they are executed. This queue will
+     *            hold only the <tt>Runnable</tt> tasks submitted by the <tt>execute</tt> method.
+     * @param handler the handler to use when execution is blocked because the thread bounds and
+     *            queue capacities are reached.
+     * @throws IllegalArgumentException if corePoolSize, or keepAliveTime less than zero, or if
+     *             maximumPoolSize less than or equal to zero, or if corePoolSize greater than
+     *             maximumPoolSize.
+     * @throws NullPointerException if <tt>workQueue</tt> or <tt>threadFactory</tt> or
+     *             <tt>handler</tt> are null.
+     */
+    public NamingThreadPoolExecutor(String poolName, int corePoolSize, int maximumPoolSize,
+            long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue,
+            RejectedExecutionHandler handler)
+    {
+        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
+                new NamingThreadFactory(poolName), handler);
+    }
+
+    /**
+     * Creates a new <tt>NamingThreadPoolExecutor</tt> with the given initial parameters.
+     * 
+     * @param poolName the default name for new threads
+     * @param corePoolSize the number of threads to keep in the pool, even if they are idle.
+     * @param maximumPoolSize the maximum number of threads to allow in the pool.
+     * @param keepAliveTime when the number of threads is greater than the core, this is the maximum
+     *            time that excess idle threads will wait for new tasks before terminating.
+     * @param unit the time unit for the keepAliveTime argument.
+     * @param workQueue the queue to use for holding tasks before they are executed. This queue will
+     *            hold only the <tt>Runnable</tt> tasks submitted by the <tt>execute</tt> method.
+     * @throws IllegalArgumentException if corePoolSize, or keepAliveTime less than zero, or if
+     *             maximumPoolSize less than or equal to zero, or if corePoolSize greater than
+     *             maximumPoolSize.
+     * @throws NullPointerException if <tt>workQueue</tt> or <tt>threadFactory</tt> are null.
+     */
+    public NamingThreadPoolExecutor(String poolName, int corePoolSize, int maximumPoolSize,
+            long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
+    {
+        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
+                new NamingThreadFactory(poolName));
+    }
+
+    /**
+     * Creates a new <tt>NamingThreadPoolExecutor</tt> with the given initial parameters.
+     * 
+     * @param corePoolSize the number of threads to keep in the pool, even if they are idle.
+     * @param maximumPoolSize the maximum number of threads to allow in the pool.
+     * @param keepAliveTime when the number of threads is greater than the core, this is the maximum
+     *            time that excess idle threads will wait for new tasks before terminating.
+     * @param unit the time unit for the keepAliveTime argument.
+     * @param workQueue the queue to use for holding tasks before they are executed. This queue will
+     *            hold only the <tt>Runnable</tt> tasks submitted by the <tt>execute</tt> method.
+     * @param threadFactory the factory to use when the executor creates a new thread.
+     * @param handler the handler to use when execution is blocked because the thread bounds and
+     *            queue capacities are reached.
+     * @throws IllegalArgumentException if corePoolSize, or keepAliveTime less than zero, or if
+     *             maximumPoolSize less than or equal to zero, or if corePoolSize greater than
+     *             maximumPoolSize.
+     * @throws NullPointerException if <tt>workQueue</tt> or <tt>threadFactory</tt> or
+     *             <tt>handler</tt> are null.
+     */
+    public NamingThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
+            TimeUnit unit, BlockingQueue<Runnable> workQueue, NamingThreadFactory threadFactory,
+            RejectedExecutionHandler handler)
+    {
+        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
+    }
+
+    /**
+     * Creates a new <tt>NamingThreadPoolExecutor</tt> with the given initial parameters.
+     * 
+     * @param corePoolSize the number of threads to keep in the pool, even if they are idle.
+     * @param maximumPoolSize the maximum number of threads to allow in the pool.
+     * @param keepAliveTime when the number of threads is greater than the core, this is the maximum
+     *            time that excess idle threads will wait for new tasks before terminating.
+     * @param unit the time unit for the keepAliveTime argument.
+     * @param workQueue the queue to use for holding tasks before they are executed. This queue will
+     *            hold only the <tt>Runnable</tt> tasks submitted by the <tt>execute</tt> method.
+     * @param threadFactory the factory to use when the executor creates a new thread.
+     * @throws IllegalArgumentException if corePoolSize, or keepAliveTime less than zero, or if
+     *             maximumPoolSize less than or equal to zero, or if corePoolSize greater than
+     *             maximumPoolSize.
+     * @throws NullPointerException if <tt>workQueue</tt> or <tt>threadFactory</tt> are null.
+     */
+    public NamingThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
+            TimeUnit unit, BlockingQueue<Runnable> workQueue, NamingThreadFactory threadFactory)
+    {
+        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
+    }
+
+    /**
+     * Sets the thread factory of this pool executor to daemon creation mode.
+     * <p>
+     * This method is supposed to be used in chaining mode, i.e.
+     * 
+     * <pre>
+     * final ExecutorService executor = new NamingThreadPoolExecutor("name").daemonize();
+     * </pre>
+     * 
+     * @return This class itself.
+     */
+    public NamingThreadPoolExecutor daemonize()
+    {
+        getThreadFactory().setCreateDaemonThreads(true);
+        return this;
+    }
+
+    /**
+     * Same as {@link #setCorePoolSize(int)}, but returns the object itself for chaining.
+     */
+    public NamingThreadPoolExecutor corePoolSize(int corePoolSize)
+    {
+        setCorePoolSize(corePoolSize);
+        return this;
+    }
+
+    /**
+     * Same as {@link #setMaximumPoolSize(int)}, but returns the object itself for chaining.
+     */
+    public NamingThreadPoolExecutor maximumPoolSize(int maximumPoolSize)
+    {
+        setMaximumPoolSize(maximumPoolSize);
+        return this;
+    }
+
+    /**
+     * Same as {@link #setKeepAliveTime(long, TimeUnit)}, but uses always
+     * {@link TimeUnit#MILLISECONDS} and returns the object itself for chaining.
+     */
+    public NamingThreadPoolExecutor keepAliveTime(long keepAliveTimeMillis)
+    {
+        setKeepAliveTime(keepAliveTimeMillis, TimeUnit.MILLISECONDS);
+        return this;
+    }
+
+    /**
+     * If <var>addPoolName</var> is <code>true</code>, the threads will contain the pool name as the
+     * first part of the thread names.
+     */
+    public NamingThreadPoolExecutor addPoolName(boolean addPoolName)
+    {
+        getThreadFactory().setAddPoolName(addPoolName);
+        return this;
+    }
+
+    @Override
+    public NamingThreadFactory getThreadFactory()
+    {
+        return (NamingThreadFactory) super.getThreadFactory();
+    }
+
+    /**
+     * Sets the thread factory of this pool executor.
+     */
+    public void setThreadFactory(NamingThreadFactory threadFactory)
+    {
+        super.setThreadFactory(threadFactory);
+    }
+
+    /**
+     * @deprecated Use {@link #setThreadFactory(NamingThreadFactory)} instead!
+     */
+    @Override
+    @Deprecated
+    public void setThreadFactory(ThreadFactory threadFactory)
+    {
+        if (threadFactory instanceof NamingThreadFactory == false)
+        {
+            throw new IllegalArgumentException("thread factory is of type '"
+                    + threadFactory.getClass().getCanonicalName() + ", but needs to be of type "
+                    + NamingThreadFactory.class.getCanonicalName());
+        }
+        super.setThreadFactory(threadFactory);
+    }
+
+    @Override
+    protected void beforeExecute(Thread t, Runnable r)
+    {
+        if (r instanceof IRunnableNameProvider == false)
+        {
+            return;
+        }
+        final String runnableName = ((IRunnableNameProvider) r).getRunnableName();
+        if (runnableName == null)
+        {
+            return;
+        }
+        if (r instanceof NamedFutureTask<?>)
+        {
+            ((NamedFutureTask<?>) r).setThread(t);
+        }
+        if (t instanceof PoolNameThread)
+        {
+            ((PoolNameThread) t).setRunnableName(runnableName);
+        } else
+        {
+            t.setName(runnableName);
+        }
+        super.beforeExecute(t, r);
+    }
+
+    @Override
+    protected void afterExecute(Runnable r, Throwable t)
+    {
+        if (r instanceof NamedFutureTask<?>)
+        {
+            ((NamedFutureTask<?>) r).restoreThreadName();
+        }
+        super.afterExecute(r, t);
+    }
+
+    @Override
+    public Future<?> submit(Runnable task)
+    {
+        if (task == null)
+        {
+            throw new NullPointerException();
+        }
+
+        final FutureTask<Object> ftask = new NamedFutureTask<Object>(task, null);
+        execute(ftask);
+        return ftask;
+    }
+
+    @Override
+    public <T> Future<T> submit(Runnable task, T result)
+    {
+        if (task == null)
+        {
+            throw new NullPointerException();
+        }
+
+        final FutureTask<T> ftask = new NamedFutureTask<T>(task, result);
+        execute(ftask);
+        return ftask;
+    }
+
+    @Override
+    public <T> Future<T> submit(Callable<T> task)
+    {
+        if (task == null)
+        {
+            throw new NullPointerException();
+        }
+        final FutureTask<T> ftask = new NamedFutureTask<T>(task);
+        execute(ftask);
+        return ftask;
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/namedthread/PoolNameThread.java b/source/java/ch/systemsx/cisd/base/namedthread/PoolNameThread.java
new file mode 100644
index 0000000..550efea
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/namedthread/PoolNameThread.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.namedthread;
+
+/**
+ * A {@link Thread} that knows its pool name.
+ * 
+ * @author Bernd Rinn
+ */
+public class PoolNameThread extends Thread
+{
+    private final String poolName;
+
+    private final boolean addPoolName;
+
+    public PoolNameThread(Runnable target, String poolName, boolean addPoolName)
+    {
+        super(target, poolName);
+        this.poolName = poolName;
+        this.addPoolName = addPoolName;
+    }
+
+    /**
+     * Sets the thread's name to the <var>runnableName</var>, possibly adding the pool name if
+     * <var>addPoolName</var> has been set to <code>true</code> in the constructor.
+     */
+    public void setRunnableName(String runnableName)
+    {
+        if (addPoolName)
+        {
+            setName(poolName + "::" + runnableName);
+        } else
+        {
+            setName(runnableName);
+        }
+    }
+
+    /** Clears the name of the runnable, setting the name of the thread to the pool name. */
+    public void clearRunnableName()
+    {
+        setName(poolName);
+    }
+}
diff --git a/source/java/ch/systemsx/cisd/base/namedthread/package.html b/source/java/ch/systemsx/cisd/base/namedthread/package.html
new file mode 100644
index 0000000..d2a54d4
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/namedthread/package.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+     "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Named pool threads.</title>
+</head>
+<body>
+<p>
+This package provides <i>named pool threads</i> when using an 
+{@code java.util.concurrent.ExecutorService}. This can be helpful in debugging and monitoring 
+multi-threaded Java applications. Start having a look at the {@code NamedThreadPoolExecutor}.
+</p>
+</body>
+</html> 
\ No newline at end of file
diff --git a/source/java/ch/systemsx/cisd/base/tests/AbstractFileSystemTestCase.java b/source/java/ch/systemsx/cisd/base/tests/AbstractFileSystemTestCase.java
new file mode 100644
index 0000000..b91323b
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/tests/AbstractFileSystemTestCase.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2007 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.tests;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.apache.commons.io.FileUtils;
+import org.testng.AssertJUnit;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeMethod;
+
+/**
+ * An <code>abstract</code> test case which accesses the file system.
+ * <p>
+ * It constructs an appropriate working directory which is test class specific.
+ * </p>
+ * 
+ * @author Christian Ribeaud
+ */
+public abstract class AbstractFileSystemTestCase extends AssertJUnit
+{
+    protected static final String UNIT_TEST_WORKING_DIRECTORY = "unit-test-wd";
+
+    protected static final String TARGETS_DIRECTORY = "targets";
+
+    protected static final File UNIT_TEST_ROOT_DIRECTORY = new File(TARGETS_DIRECTORY
+            + File.separator + UNIT_TEST_WORKING_DIRECTORY);
+
+    protected final File workingDirectory;
+
+    private final boolean cleanAfterMethod;
+
+    protected AbstractFileSystemTestCase()
+    {
+        this(true);
+    }
+
+    protected AbstractFileSystemTestCase(final boolean cleanAfterMethod)
+    {
+        workingDirectory = createWorkingDirectory();
+        this.cleanAfterMethod = cleanAfterMethod;
+    }
+
+    /**
+     * Creates a {@link File} with <var>name</var> in the working directory. Ensure it doesn't
+     * exist and is deleted on exit.
+     */
+    protected File create(String name)
+    {
+        final File file = new File(workingDirectory, name);
+        file.delete();
+        file.deleteOnExit();
+        return file;
+    }
+
+    /**
+     * Creates a directory in the unit test root directory "targets/unit-test-wd"
+     */
+    protected final File createDirectoryInUnitTestRoot(String dirName)
+    {
+        final File directory = new File(UNIT_TEST_ROOT_DIRECTORY, dirName);
+        directory.mkdirs();
+        directory.deleteOnExit();
+        return directory;
+    }
+
+    private final File createWorkingDirectory()
+    {
+        return createDirectoryInUnitTestRoot(getClass().getName());
+    }
+
+    @BeforeMethod
+    public void setUp() throws IOException
+    {
+        cleanUpDirectoryBeforeTheTest(workingDirectory);
+    }
+
+    /**
+     * Deletes, recreates and verifies that this is the empty directory
+     */
+    protected void cleanUpDirectoryBeforeTheTest(File directory)
+    {
+        deleteDirectory(directory);
+        directory.mkdirs();
+        assertEquals(true, directory.isDirectory());
+        File[] files = directory.listFiles();
+        if (files != null)
+        {
+            assertEquals("Unexpected files " + Arrays.asList(files), 0, files.length);
+        }
+    }
+
+    private void deleteDirectory(File dir)
+    {
+        try
+        {
+            FileUtils.deleteDirectory(dir);
+        } catch (IOException e)
+        {
+            System.err.println("Could not delete the directory " + dir.getPath() + " because: "
+                    + e.getMessage());
+            try
+            {
+                FileUtils.deleteDirectory(dir);
+            } catch (IOException e2)
+            {
+                System.err.println("Could not delete the directory " + dir.getPath()
+                        + " in second try because: " + e2.getMessage());
+            }
+        }
+    }
+
+    @AfterClass
+    public void afterClass() throws IOException
+    {
+        if (cleanAfterMethod == false)
+        {
+            return;
+        }
+        try
+        {
+            FileUtils.deleteDirectory(workingDirectory);
+        } catch (FileNotFoundException ex)
+        {
+            // Ignore
+        }
+    }
+}
diff --git a/source/java/ch/systemsx/cisd/base/tests/Retry10.java b/source/java/ch/systemsx/cisd/base/tests/Retry10.java
new file mode 100644
index 0000000..e3438e7
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/tests/Retry10.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.tests;
+
+import org.testng.IRetryAnalyzer;
+import org.testng.ITestResult;
+import org.testng.util.RetryAnalyzerCount;
+
+/**
+ * An {@link RetryAnalyzerCount} extension which sets the count to <code>10</code>.
+ * <p>
+ * This {@link IRetryAnalyzer} should only be applied to methods we know they should run
+ * successfully but do not for some reason. The retry analyzer exits as soon as it made a successful
+ * call.
+ * </p>
+ * 
+ * @author Christian Ribeaud
+ */
+public final class Retry10 extends RetryAnalyzerCount
+{
+    public Retry10()
+    {
+        setCount(10);
+    }
+
+    //
+    // RetryAnalyzerCount
+    //
+
+    @Override
+    public final boolean retryMethod(final ITestResult result)
+    {
+        return true;
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/tests/Retry50.java b/source/java/ch/systemsx/cisd/base/tests/Retry50.java
new file mode 100644
index 0000000..60df88e
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/tests/Retry50.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.tests;
+
+import org.testng.IRetryAnalyzer;
+import org.testng.ITestResult;
+import org.testng.util.RetryAnalyzerCount;
+
+/**
+ * An {@link RetryAnalyzerCount} extension which sets the count to <code>50</code>.
+ * <p>
+ * This {@link IRetryAnalyzer} should only be applied to methods we know they should run
+ * successfully but do not for some reason. The retry analyzer exits as soon as it made a successful
+ * call.
+ * </p>
+ * 
+ * @author Bernd Rinn
+ */
+public final class Retry50 extends RetryAnalyzerCount
+{
+    public Retry50()
+    {
+        setCount(50);
+    }
+
+    //
+    // RetryAnalyzerCount
+    //
+
+    @Override
+    public final boolean retryMethod(final ITestResult result)
+    {
+        return true;
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/unix/FileLinkType.java b/source/java/ch/systemsx/cisd/base/unix/FileLinkType.java
new file mode 100644
index 0000000..5a0f72e
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/unix/FileLinkType.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.unix;
+
+import java.io.Serializable;
+
+/**
+ * The type of a link in the file system.
+ * 
+ * @author Bernd Rinn
+ */
+public enum FileLinkType implements Serializable
+{
+    REGULAR_FILE, DIRECTORY, SYMLINK, OTHER;
+
+    /**
+     * Returns <code>true</code> if the <var>linkMode</var> corresponds to a symbolic link.
+     */
+    static boolean isSymLink(long linkMode)
+    {
+        return linkMode == SYMLINK.ordinal();
+    }
+}
\ No newline at end of file
diff --git a/source/java/ch/systemsx/cisd/base/unix/Unix.java b/source/java/ch/systemsx/cisd/base/unix/Unix.java
new file mode 100644
index 0000000..fc02834
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/unix/Unix.java
@@ -0,0 +1,901 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.unix;
+
+import java.io.File;
+import java.io.IOException;
+
+import ch.rinn.restrictions.Private;
+import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+import ch.systemsx.cisd.base.utilities.NativeLibraryUtilities;
+
+/**
+ * A utility class that provides access to common Unix system calls. Obviously, this will only work
+ * on Unix platforms and it requires a native library to be loaded.
+ * <p>
+ * <i>Check with {@link #isOperational()} if this class is operational and only call the other
+ * methods if <code>Unix.isOperational() == true</code>.</i>
+ * 
+ * @author Bernd Rinn
+ */
+public final class Unix
+{
+
+    private enum ProcessDetection
+    {
+        PROCFS, PS, NONE
+    }
+
+    private final static boolean operational;
+
+    private final static ProcessDetection processDetection;
+
+    static
+    {
+        operational = NativeLibraryUtilities.loadNativeLibrary("unix");
+        if (operational)
+        {
+            init();
+            final int myPid = getPid();
+            if (isProcessRunningProcFS(myPid))
+            {
+                processDetection = ProcessDetection.PROCFS;
+            } else if (isProcessRunningPS(myPid))
+            {
+                processDetection = ProcessDetection.PS;
+            } else
+            {
+                processDetection = ProcessDetection.NONE;
+            }
+        } else
+        {
+            processDetection = ProcessDetection.NONE;
+        }
+    }
+
+    /** set user ID on execution */
+    public static final short S_ISUID = 04000;
+
+    /** set group ID on execution */
+    public static final short S_ISGID = 02000;
+
+    /** sticky bit */
+    public static final short S_ISVTX = 01000;
+
+    /** read by owner */
+    public static final short S_IRUSR = 00400;
+
+    /** write by owner */
+    public static final short S_IWUSR = 00200;
+
+    /** execute/search by owner */
+    public static final short S_IXUSR = 00100;
+
+    /** read by group */
+    public static final short S_IRGRP = 00040;
+
+    /** write by group */
+    public static final short S_IWGRP = 00020;
+
+    /** execute/search by group */
+    public static final short S_IXGRP = 00010;
+
+    /** read by others */
+    public static final short S_IROTH = 00004;
+
+    /** write by others */
+    public static final short S_IWOTH = 00002;
+
+    /** execute/search by others */
+    public static final short S_IXOTH = 00001;
+
+    /**
+     * A class representing the Unix <code>stat</code> structure.
+     */
+    public static final class Stat
+    {
+        private final long deviceId;
+
+        private final long inode;
+
+        private final short permissions;
+
+        private final FileLinkType linkType;
+
+        private String symbolicLinkOrNull;
+
+        private final int numberOfHardLinks;
+
+        private final int uid;
+
+        private final int gid;
+
+        private final long lastAccess;
+
+        private final long lastModified;
+
+        private final long lastStatusChange;
+
+        private final long size;
+
+        private final long numberOfBlocks;
+
+        private final int blockSize;
+
+        Stat(long deviceId, long inode, short permissions, byte linkType, int numberOfHardLinks,
+                int uid, int gid, long lastAccess, long lastModified, long lastStatusChange,
+                long size, long numberOfBlocks, int blockSize)
+        {
+            this.deviceId = deviceId;
+            this.inode = inode;
+            this.permissions = permissions;
+            this.linkType = FileLinkType.values()[linkType];
+            this.numberOfHardLinks = numberOfHardLinks;
+            this.uid = uid;
+            this.gid = gid;
+            this.lastAccess = lastAccess;
+            this.lastModified = lastModified;
+            this.lastStatusChange = lastStatusChange;
+            this.size = size;
+            this.numberOfBlocks = numberOfBlocks;
+            this.blockSize = blockSize;
+        }
+
+        void setSymbolicLinkOrNull(String symbolicLinkOrNull)
+        {
+            this.symbolicLinkOrNull = symbolicLinkOrNull;
+        }
+
+        public String tryGetSymbolicLink()
+        {
+            return symbolicLinkOrNull;
+        }
+
+        public long getDeviceId()
+        {
+            return deviceId;
+        }
+
+        public long getInode()
+        {
+            return inode;
+        }
+
+        public short getPermissions()
+        {
+            return permissions;
+        }
+
+        public FileLinkType getLinkType()
+        {
+            return linkType;
+        }
+
+        /**
+         * Returns <code>true</code>, if this link is a symbolic link.
+         */
+        public final boolean isSymbolicLink()
+        {
+            return FileLinkType.SYMLINK == linkType;
+        }
+
+        public int getNumberOfHardLinks()
+        {
+            return numberOfHardLinks;
+        }
+
+        public int getUid()
+        {
+            return uid;
+        }
+
+        public int getGid()
+        {
+            return gid;
+        }
+
+        public long getLastAccess()
+        {
+            return lastAccess;
+        }
+
+        public long getLastModified()
+        {
+            return lastModified;
+        }
+
+        public long getLastStatusChange()
+        {
+            return lastStatusChange;
+        }
+
+        public long getSize()
+        {
+            return size;
+        }
+
+        public long getNumberOfBlocks()
+        {
+            return numberOfBlocks;
+        }
+
+        public int getBlockSize()
+        {
+            return blockSize;
+        }
+
+    }
+
+    /**
+     * A class representing the Unix <code>group</code> struct.
+     */
+    public static final class Group
+    {
+        private final String groupName;
+
+        private final String groupPasswordHash;
+
+        private final int gid;
+
+        private final String[] groupMembers;
+
+        Group(String groupName, String groupPasswordHash, int gid, String[] groupMembers)
+        {
+            this.groupName = groupName;
+            this.groupPasswordHash = groupPasswordHash;
+            this.gid = gid;
+            this.groupMembers = groupMembers;
+        }
+
+        public String getGroupName()
+        {
+            return groupName;
+        }
+
+        public String getGroupPasswordHash()
+        {
+            return groupPasswordHash;
+        }
+
+        public int getGid()
+        {
+            return gid;
+        }
+
+        public String[] getGroupMembers()
+        {
+            return groupMembers;
+        }
+    }
+
+    /**
+     * A class representing the Unix <code>passwd</code> struct.
+     */
+    public static final class Password
+    {
+        private final String userName;
+
+        private final String passwordHash;
+
+        private final int uid;
+
+        private final int gid;
+
+        private final String userFullName;
+
+        private final String homeDirectory;
+
+        private final String shell;
+
+        Password(String userName, String passwordHash, int uid, int gid, String userFullName,
+                String homeDirectory, String shell)
+        {
+            this.userName = userName;
+            this.passwordHash = passwordHash;
+            this.uid = uid;
+            this.gid = gid;
+            this.userFullName = userFullName;
+            this.homeDirectory = homeDirectory;
+            this.shell = shell;
+        }
+
+        public String getUserName()
+        {
+            return userName;
+        }
+
+        public String getPasswordHash()
+        {
+            return passwordHash;
+        }
+
+        public int getUid()
+        {
+            return uid;
+        }
+
+        public int getGid()
+        {
+            return gid;
+        }
+
+        public String getUserFullName()
+        {
+            return userFullName;
+        }
+
+        public String getHomeDirectory()
+        {
+            return homeDirectory;
+        }
+
+        public String getShell()
+        {
+            return shell;
+        }
+    }
+
+    private static void throwLinkCreationException(String type, String source, String target,
+            String errorMessage)
+    {
+        throw new IOExceptionUnchecked(new IOException(String.format(
+                "Creating %s link '%s' -> '%s': %s", type, target, source, errorMessage)));
+    }
+
+    private static void throwStatException(String filename, String errorMessage)
+    {
+        throw new IOExceptionUnchecked(new IOException(String.format(
+                "Cannot obtain inode info for file '%s': %s", filename, errorMessage)));
+    }
+
+    private static void throwFileException(String operation, String filename, String errorMessage)
+    {
+        throw new IOExceptionUnchecked(new IOException(String.format("Cannot %s of file '%s': %s",
+                operation, filename, errorMessage)));
+    }
+
+    private static native int init();
+
+    private static native int getpid();
+
+    private static native int getuid();
+
+    private static native int geteuid();
+
+    private static native int getgid();
+
+    private static native int getegid();
+
+    private static native int link(String filename, String linktarget);
+
+    private static native int symlink(String filename, String linktarget);
+
+    private static native Stat stat(String filename);
+
+    private static native Stat lstat(String filename);
+
+    private static native String readlink(String filename, int linkvallen);
+
+    private static native int chmod(String filename, short mode);
+
+    private static native int chown(String filename, int uid, int gid);
+
+    private static native String getuser(int uid);
+
+    private static native String getgroup(int gid);
+
+    private static native int getuid(String user);
+
+    private static native Password getpwnam(String user);
+
+    private static native Password getpwuid(int uid);
+
+    private static native int getgid(String group);
+
+    private static native Group getgrnam(String group);
+
+    private static native Group getgrgid(int gid);
+
+    private static native String strerror(int errnum);
+
+    private static native String strerror();
+
+    @Private
+    static boolean isProcessRunningProcFS(int pid)
+    {
+        return new File("/proc/" + pid).isDirectory();
+    }
+
+    @Private
+    static boolean isProcessRunningPS(int pid)
+    {
+        try
+        {
+            return Runtime.getRuntime().exec(new String[]
+                { "ps", "-p", Integer.toString(pid) }).waitFor() == 0;
+        } catch (IOException ex)
+        {
+            return false;
+        } catch (InterruptedException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    //
+    // Public
+    //
+
+    /**
+     * Returns <code>true</code>, if the native library has been loaded successfully and the link
+     * utilities are operational, <code>false</code> otherwise.
+     */
+    public static final boolean isOperational()
+    {
+        return operational;
+    }
+
+    /**
+     * Returns <code>true</code>, if process detection is available on this system.
+     */
+    public static boolean canDetectProcesses()
+    {
+        return processDetection != ProcessDetection.NONE;
+    }
+
+    /**
+     * Returns the last error that occurred in this class. Use this to find out what went wrong
+     * after {@link #tryGetLinkInfo(String)} or {@link #tryGetFileInfo(String)} returned
+     * <code>null</code>.
+     */
+    public static String getLastError()
+    {
+        return strerror();
+    }
+
+    //
+    // Process functions
+    //
+
+    /**
+     * Returns the process identifier of the current process.
+     */
+    public static int getPid()
+    {
+        return getpid();
+    }
+
+    /**
+     * Returns <code>true</code>, if the process with <var>pid</var> is currently running and
+     * <code>false</code>, if it is not running or if process detection is not available (
+     * {@link #canDetectProcesses()} <code>== false</code>).
+     */
+    public static boolean isProcessRunning(int pid)
+    {
+        switch (processDetection)
+        {
+            case PROCFS:
+                return isProcessRunningProcFS(pid);
+            case PS:
+                return isProcessRunningPS(pid);
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Returns the uid of the user that started this process.
+     */
+    public static final int getUid()
+    {
+        return getuid();
+    }
+
+    /**
+     * Returns the effective uid that determines the permissions of this process.
+     */
+    public static final int getEuid()
+    {
+        return geteuid();
+    }
+
+    /**
+     * Returns the gid of the user that started this process.
+     */
+    public static final int getGid()
+    {
+        return getgid();
+    }
+
+    /**
+     * Returns the effective gid that determines the permissions of this process.
+     */
+    public static final int getEgid()
+    {
+        return getegid();
+    }
+
+    //
+    // File functions
+    //
+
+    /**
+     * Creates a hard link <var>linkName</var> that points to <var>fileName</var>.
+     * 
+     * @throws IOExceptionUnchecked If the underlying system call fails, e.g. because
+     *             <var>linkName</var> already exists or <var>fileName</var> does not exist.
+     */
+    public static final void createHardLink(String fileName, String linkName)
+            throws IOExceptionUnchecked
+    {
+        if (fileName == null)
+        {
+            throw new NullPointerException("fileName");
+        }
+        if (linkName == null)
+        {
+            throw new NullPointerException("linkName");
+        }
+        final int result = link(fileName, linkName);
+        if (result < 0)
+        {
+            throwLinkCreationException("hard", fileName, linkName, strerror(result));
+        }
+    }
+
+    /**
+     * Creates a symbolic link <var>linkName</var> that points to <var>fileName</var>.
+     * 
+     * @throws IOExceptionUnchecked If the underlying system call fails, e.g. because
+     *             <var>linkName</var> already exists.
+     */
+    public static final void createSymbolicLink(String fileName, String linkName)
+            throws IOExceptionUnchecked
+    {
+        if (fileName == null)
+        {
+            throw new NullPointerException("fileName");
+        }
+        if (linkName == null)
+        {
+            throw new NullPointerException("linkName");
+        }
+        final int result = symlink(fileName, linkName);
+        if (result < 0)
+        {
+            throwLinkCreationException("symbolic", fileName, linkName, strerror(result));
+        }
+    }
+
+    private static Stat tryGetStat(String fileName) throws IOExceptionUnchecked
+    {
+        if (fileName == null)
+        {
+            throw new NullPointerException("fileName");
+        }
+        return stat(fileName);
+    }
+
+    private static Stat getStat(String fileName) throws IOExceptionUnchecked
+    {
+        if (fileName == null)
+        {
+            throw new NullPointerException("fileName");
+        }
+        final Stat result = stat(fileName);
+        if (result == null)
+        {
+            throwStatException(fileName, strerror());
+        }
+        return result;
+    }
+
+    private static Stat tryGetLStat(String linkName) throws IOExceptionUnchecked
+    {
+        if (linkName == null)
+        {
+            throw new NullPointerException("linkName");
+        }
+        return lstat(linkName);
+    }
+
+    private static Stat getLStat(String linkName) throws IOExceptionUnchecked
+    {
+        if (linkName == null)
+        {
+            throw new NullPointerException("linkName");
+        }
+        final Stat result = lstat(linkName);
+        if (result == null)
+        {
+            throwStatException(linkName, strerror());
+        }
+        return result;
+    }
+
+    /**
+     * Returns the inode for the <var>fileName</var>.
+     * 
+     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link
+     *             does not exist.
+     */
+    public static final long getInode(String fileName) throws IOExceptionUnchecked
+    {
+        return getLStat(fileName).getInode();
+    }
+
+    /**
+     * Returns the number of hard links for the <var>fileName</var>.
+     * 
+     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link
+     *             does not exist.
+     */
+    public static final int getNumberOfHardLinks(String fileName) throws IOExceptionUnchecked
+    {
+        return getLStat(fileName).getNumberOfHardLinks();
+    }
+
+    /**
+     * Returns <code>true</code> if <var>fileName</var> is a symbolic link and <code>false</code>
+     * otherwise.
+     * 
+     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link
+     *             does not exist.
+     */
+    public static final boolean isSymbolicLink(String fileName) throws IOExceptionUnchecked
+    {
+        return getLStat(fileName).isSymbolicLink();
+    }
+
+    /**
+     * Returns the value of the symbolik link <var>linkName</var>, or <code>null</code>, if
+     * <var>linkName</var> is not a symbolic link.
+     * 
+     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link
+     *             does not exist.
+     */
+    public static final String tryReadSymbolicLink(String linkName) throws IOExceptionUnchecked
+    {
+        final Stat stat = getLStat(linkName);
+        return stat.isSymbolicLink() ? readlink(linkName, (int) stat.getSize()) : null;
+    }
+
+    /**
+     * Returns the information about <var>fileName</var>.
+     * 
+     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the file
+     *             does not exist.
+     */
+    public static final Stat getFileInfo(String fileName) throws IOExceptionUnchecked
+    {
+        return getStat(fileName);
+    }
+
+    /**
+     * Returns the information about <var>fileName</var>, or {@link NullPointerException}, if the
+     * information could not be obtained, e.g. because the file does not exist (call
+     * {@link #getLastError()} to find out what went wrong).
+     */
+    public static final Stat tryGetFileInfo(String fileName) throws IOExceptionUnchecked
+    {
+        return tryGetStat(fileName);
+    }
+
+    /**
+     * Returns the information about <var>linkName</var>.
+     * 
+     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link
+     *             does not exist.
+     */
+    public static final Stat getLinkInfo(String linkName) throws IOExceptionUnchecked
+    {
+        return getLinkInfo(linkName, true);
+    }
+
+    /**
+     * Returns the information about <var>linkName</var>. If
+     * <code>readSymbolicLinkTarget == true</code>, then the symbolic link target is read when
+     * <var>linkName</var> is a symbolic link.
+     * 
+     * @throws IOExceptionUnchecked If the information could not be obtained, e.g. because the link
+     *             does not exist.
+     */
+    public static final Stat getLinkInfo(String linkName, boolean readSymbolicLinkTarget)
+            throws IOExceptionUnchecked
+    {
+        final Stat stat = getLStat(linkName);
+        final String symbolicLinkOrNull =
+                (readSymbolicLinkTarget && stat.isSymbolicLink()) ? readlink(linkName,
+                        (int) stat.getSize()) : null;
+        stat.setSymbolicLinkOrNull(symbolicLinkOrNull);
+        return stat;
+    }
+
+    /**
+     * Returns the information about <var>linkName</var>, or {@link NullPointerException}, if the
+     * information could not be obtained, e.g. because the link does not exist (call
+     * {@link #getLastError()} to find out what went wrong).
+     */
+    public static final Stat tryGetLinkInfo(String linkName) throws IOExceptionUnchecked
+    {
+        return tryGetLinkInfo(linkName, true);
+    }
+
+    /**
+     * Returns the information about <var>linkName</var>, or <code>null</code> if the information
+     * can not be obtained, e.g. because the link does not exist (call {@link #getLastError()} to
+     * find out what went wrong). If <code>readSymbolicLinkTarget == true</code>, then the symbolic
+     * link target is read when <var>linkName</var> is a symbolic link.
+     */
+    public static final Stat tryGetLinkInfo(String linkName, boolean readSymbolicLinkTarget)
+            throws IOExceptionUnchecked
+    {
+        final Stat stat = tryGetLStat(linkName);
+        if (stat == null)
+        {
+            return null;
+        }
+        final String symbolicLinkOrNull =
+                (readSymbolicLinkTarget && stat.isSymbolicLink()) ? readlink(linkName,
+                        (int) stat.getSize()) : null;
+        stat.setSymbolicLinkOrNull(symbolicLinkOrNull);
+        return stat;
+    }
+
+    /**
+     * Sets the access mode of <var>filename</var> to the specified <var>mode</var> value.
+     */
+    public static final void setAccessMode(String fileName, short mode) throws IOExceptionUnchecked
+    {
+        if (fileName == null)
+        {
+            throw new NullPointerException("fileName");
+        }
+        final int result = chmod(fileName, mode);
+        if (result < 0)
+        {
+            throwFileException("set mode", fileName, strerror(result));
+        }
+    }
+
+    /**
+     * Sets the owner of <var>filename</var> to the specified <var>uid</var> and <var>gid</var>
+     * values.
+     */
+    public static final void setOwner(String fileName, int uid, int gid)
+            throws IOExceptionUnchecked
+    {
+        if (fileName == null)
+        {
+            throw new NullPointerException("fileName");
+        }
+        final int result = chown(fileName, uid, gid);
+        if (result < 0)
+        {
+            throwFileException("set owner", fileName, strerror(result));
+        }
+    }
+
+    //
+    // User functions
+    //
+
+    /**
+     * Returns the name of the user identified by <var>uid</var>.
+     */
+    public static final String tryGetUserNameForUid(int uid)
+    {
+        return getuser(uid);
+    }
+
+    /**
+     * Returns the uid of the <var>userName</var>, or <code>-1</code>, if no user with this name
+     * exists.
+     */
+    public static final int getUidForUserName(String userName)
+    {
+        if (userName == null)
+        {
+            throw new NullPointerException("userName");
+        }
+        return getuid(userName);
+    }
+
+    /**
+     * Returns the {@link Password} for the given <var>userName</var>, or <code>null</code>, if no
+     * user with that name exists.
+     */
+    public static final Password tryGetUserByName(String userName)
+    {
+        if (userName == null)
+        {
+            throw new NullPointerException("userName");
+        }
+        return getpwnam(userName);
+    }
+
+    /**
+     * Returns the {@link Password} for the given <var>userName</var>, or <code>null</code>, if no
+     * user with that name exists.
+     */
+    public static final Password tryGetUserByUid(int uid)
+    {
+        return getpwuid(uid);
+    }
+
+    //
+    // Group functions
+    //
+
+    /**
+     * Returns the name of the group identified by <var>gid</var>, or <code>null</code>, if no group
+     * with that <var>gid</var> exists.
+     */
+    public static final String tryGetGroupNameForGid(int gid)
+    {
+        return getgroup(gid);
+    }
+
+    /**
+     * Returns the gid of the <var>groupName</var>, or <code>-1</code>, if no group with this name
+     * exists.
+     */
+    public static final int getGidForGroupName(String groupName)
+    {
+        if (groupName == null)
+        {
+            throw new NullPointerException("groupName");
+        }
+        return getgid(groupName);
+    }
+
+    /**
+     * Returns the {@link Group} for the given <var>groupName</var>, or <code>null</code>, if no
+     * group with that name exists.
+     */
+    public static final Group tryGetGroupByName(String groupName)
+    {
+        if (groupName == null)
+        {
+            throw new NullPointerException("groupName");
+        }
+        return getgrnam(groupName);
+    }
+
+    /**
+     * Returns the {@link Group} for the given <var>gid</var>, or <code>null</code>, if no group
+     * with that gid exists.
+     */
+    public static final Group tryGetGroupByGid(int gid)
+    {
+        return getgrgid(gid);
+    }
+
+    //
+    // Error
+    //
+
+    /**
+     * Returns the error string for the given <var>errnum</var>.
+     */
+    public static final String getErrorString(int errnum)
+    {
+        return strerror(errnum);
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/unix/package.html b/source/java/ch/systemsx/cisd/base/unix/package.html
new file mode 100644
index 0000000..f8a9751
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/unix/package.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+     "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Unix system calls.</title>
+</head>
+<body>
+<p>
+This package provides some basic (POSIX-compliant) Unix system calls.
+</p>
+</body>
+</html> 
\ No newline at end of file
diff --git a/source/java/ch/systemsx/cisd/base/utilities/AbstractBuildAndEnvironmentInfo.java b/source/java/ch/systemsx/cisd/base/utilities/AbstractBuildAndEnvironmentInfo.java
new file mode 100644
index 0000000..1a9dae6
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/utilities/AbstractBuildAndEnvironmentInfo.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2007 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.utilities;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+/**
+ * Abstract of all classes providing build and environment information.
+ * <p>
+ * Does <em>not</em> depend on any library jar files.
+ * </p>
+ * 
+ * @author Franz-Josef Elmer
+ */
+public abstract class AbstractBuildAndEnvironmentInfo
+{
+    private static final String UNKNOWN = "UNKNOWN";
+
+    private final String version;
+
+    private final String revision;
+
+    private final boolean cleanSources;
+
+    private final String applicationName;
+
+    protected AbstractBuildAndEnvironmentInfo(String applicationName)
+    {
+        this.applicationName = applicationName;
+        String extractedVersion = UNKNOWN;
+        String extractedRevision = UNKNOWN;
+        boolean extractedCleanFlag = false;
+        final InputStream stream =
+                AbstractBuildAndEnvironmentInfo.class.getResourceAsStream("/BUILD-" + applicationName
+                        + ".INFO");
+        if (stream != null)
+        {
+            BufferedReader reader = null;
+            try
+            {
+                reader = new BufferedReader(new InputStreamReader(stream));
+                final String line = reader.readLine();
+                if (line != null)
+                {
+                    final StringTokenizer tokenizer = new StringTokenizer(line, ":");
+                    extractedVersion = tokenizer.nextToken();
+                    extractedRevision = tokenizer.nextToken();
+                    extractedCleanFlag = "clean".equals(tokenizer.nextToken());
+                }
+            } catch (IOException ex)
+            {
+                // ignored
+            } finally
+            {
+                try
+                {
+                    if (reader != null)
+                    {
+                        reader.close();
+                    }
+                } catch (IOException ioe)
+                {
+                    // ignore
+                }
+            }
+        }
+        this.version = extractedVersion;
+        this.revision = extractedRevision;
+        this.cleanSources = extractedCleanFlag;
+    }
+
+    private final static String getProperty(final String property)
+    {
+        return System.getProperty(property, UNKNOWN);
+    }
+
+    private final static boolean isUnknown(final String property)
+    {
+        return property.equals(UNKNOWN);
+    }
+
+    /**
+     * @return Name of the CPU architecture.
+     */
+    public final String getCPUArchitecture()
+    {
+        return getProperty("os.arch");
+    }
+
+    /**
+     * @return Name and version of the operating system.
+     */
+    public final String getOS()
+    {
+        final String osName = getProperty("os.name");
+        final String osVersion = getProperty("os.version");
+        if (isUnknown(osName) || isUnknown(osVersion))
+        {
+            return osName;
+        }
+        return osName + " (v" + osVersion + ")";
+    }
+
+    /**
+     * @return Name and version of the Java Virtual Machine.
+     */
+    public final String getJavaVM()
+    {
+        final String vmName = getProperty("java.vm.name");
+        final String vmVersion = getProperty("java.vm.version");
+        if (isUnknown(vmName) || isUnknown(vmVersion))
+        {
+            return vmName;
+        }
+        return vmName + " (v" + vmVersion + ")";
+    }
+
+    /**
+     * @return The version of the software.
+     */
+    public final String getVersion()
+    {
+        return version;
+    }
+
+    /**
+     * @return <code>true</code> if the versioned entities of the working copy have been clean when
+     *         this build has been made, in other words, whether the revision given by
+     *         {@link #getRevision()} does really identify the source that is build has been
+     *         produced from.
+     */
+    public final boolean isCleanSources()
+    {
+        return cleanSources;
+    }
+
+    /**
+     * @return The revision number.
+     */
+    public final String getRevision()
+    {
+        return revision;
+    }
+
+    /**
+     * Returns the version accompanied by the build number of the software (if known).
+     */
+    public final String getFullVersion()
+    {
+        final StringBuilder builder = new StringBuilder();
+        final String rev = getRevision();
+        final boolean isDirty = isCleanSources() == false;
+        builder.append(getVersion());
+        if (isUnknown(rev) == false)
+        {
+            builder.append(" (r").append(rev);
+            if (isDirty)
+            {
+                builder.append("*");
+            }
+            builder.append(")");
+        } else
+        {
+            if (isDirty)
+            {
+                builder.append("*");
+            }
+        }
+        return builder.toString();
+    }
+
+    public String getApplicationName()
+    {
+        return applicationName;
+    }
+
+    /**
+     * Returns version, build number, Java VM, and OS as a {@link List} with four entries.
+     */
+    public final List<String> getEnvironmentInfo()
+    {
+        final List<String> environmentInfo = new ArrayList<String>();
+        environmentInfo.add("Application: " + getApplicationName());
+        environmentInfo.add("Version: " + getFullVersion());
+        environmentInfo.add("Java VM: " + getJavaVM());
+        environmentInfo.add("CPU Architecture: " + getCPUArchitecture());
+        environmentInfo.add("OS: " + getOS());
+        return environmentInfo;
+    }
+
+    /**
+     * Returns version, build number, Java VM, and OS in a four-liner as one {@link String}.
+     */
+    @Override
+    public final String toString()
+    {
+        final StringBuilder builder = new StringBuilder();
+        final List<String> environmentInfo = getEnvironmentInfo();
+        final int n = environmentInfo.size();
+        for (int i = 0; i < n; i++)
+        {
+            builder.append(environmentInfo.get(i));
+            if (i < n - 1)
+            {
+                builder.append(System.getProperty("line.separator"));
+            }
+        }
+        return builder.toString();
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/utilities/NativeLibraryUtilities.java b/source/java/ch/systemsx/cisd/base/utilities/NativeLibraryUtilities.java
new file mode 100644
index 0000000..785e662
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/utilities/NativeLibraryUtilities.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2009 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.utilities;
+
+import java.io.File;
+
+/**
+ * A library for loading native libraries.
+ * 
+ * @author Bernd Rinn
+ */
+public final class NativeLibraryUtilities
+{
+    private static final String JNI_LIB_PREFIX = getJNILibPrefixForSystem();
+
+    private static final String JNI_LIB_EXTENSION = getJNILibExtensionForSystem();
+
+    private static String getJNILibPrefixForSystem()
+    {
+        return OSUtilities.isWindows() ? "" : "lib";
+    }
+    
+    private static String getJNILibExtensionForSystem()
+    {
+        if (OSUtilities.isMacOS())
+        {
+            return "jnilib";
+        } else if (OSUtilities.isWindows())
+        {
+            return "dll";
+        } else
+        {
+            return "so";
+        }
+    }
+
+    /**
+     * Loads the native library <var>libraryName</var>. The native library will be searched for in
+     * this way:
+     * <ol>
+     * <li>Try to use {@link System#loadLibrary(String)}. If this fails, use the next method.</li>
+     * <li>The library path can either be provided as a Java property {@code
+     * native.libpath.<libraryName>}.</li>
+     * <li>Or a prefix on the filesystem can be provided by specifying the Java property {@code
+     * native.libpath} and then the library is expected to be in {@code
+     * <native.libpath>/<libraryName>/<platform_id>/<libraryName>.so}.</li>
+     * <li>Finally, the routine will try to find the library as a resource in the class path with
+     * resource name {@code /native/<libraryName>/<platform_id>/<libraryName>.so}.</li>
+     * </ol>
+     * 
+     * @return <code>true</code> if the library has been loaded successfully and <code>false</code>
+     *         otherwise.
+     */
+    public static boolean loadNativeLibrary(final String libraryName)
+    {
+        // Try specific path
+        String linkLibNameOrNull = System.getProperty("native.libpath." + libraryName);
+        if (linkLibNameOrNull != null)
+        {
+            return loadLib(linkLibNameOrNull);
+        }
+
+        // Try generic path
+        final String linkLibPathOrNull = System.getProperty("native.libpath");
+        if (linkLibPathOrNull != null)
+        {
+            linkLibNameOrNull = getLibPath(linkLibPathOrNull, libraryName);
+            return loadLib(linkLibNameOrNull);
+        }
+
+        // Try resource
+        linkLibNameOrNull = tryCopyNativeLibraryToTempFile(libraryName);
+        if (linkLibNameOrNull != null)
+        {
+            return loadLib(linkLibNameOrNull);
+        }
+        // Finally, try system dependent loading
+        return loadSystemLibrary(libraryName);
+    }
+
+    private static boolean loadLib(String libPath)
+    {
+        final File linkLib = new File(libPath);
+        if (linkLib.exists() && linkLib.canRead() && linkLib.isFile())
+        {
+            final String linkLibNameAbsolute = linkLib.getAbsolutePath();
+            try
+            {
+                System.load(linkLibNameAbsolute);
+                return true;
+            } catch (final Throwable err)
+            {
+                System.err.printf("Native library '%s' failed to load:\n", linkLibNameAbsolute);
+                err.printStackTrace();
+                return false;
+            }
+        } else
+        {
+            System.err.printf("Native library '%s' does not exist or is not readable.\n", linkLib
+                    .getAbsolutePath());
+            return false;
+        }
+    }
+
+    private static boolean loadSystemLibrary(String libName)
+    {
+        try
+        {
+            System.loadLibrary(libName);
+            return true;
+        } catch (Throwable th)
+        {
+            // Silence this - we return failure back as boolean value.
+            return false;
+        }
+    }
+
+    /**
+     * Tries to copy a native library which is available as a resource to a temporary file. It will
+     * use the following naming schema to locate the resource containing the native library:
+     * <p>
+     * {@code /native/<libraryName>/<platform_id>/<libraryName>.so}.
+     * 
+     * @param libraryName The name of the library.
+     * @return The name of the temporary file, or <code>null</code>, if the resource could not be
+     *         copied.
+     */
+    public static String tryCopyNativeLibraryToTempFile(final String libraryName)
+    {
+        return ResourceUtilities.tryCopyResourceToTempFile(getLibPath("/native", libraryName),
+                libraryName, ".so");
+    }
+
+    private static String getLibPath(final String prefix, final String libraryName)
+    {
+        return String.format("%s/%s/%s/%s%s.%s", prefix, libraryName, OSUtilities
+                .getCompatibleComputerPlatform(), JNI_LIB_PREFIX, libraryName, JNI_LIB_EXTENSION);
+    }
+    
+}
diff --git a/source/java/ch/systemsx/cisd/base/utilities/OSUtilities.java b/source/java/ch/systemsx/cisd/base/utilities/OSUtilities.java
new file mode 100644
index 0000000..11e8485
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/utilities/OSUtilities.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2007 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.utilities;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+/**
+ * Some useful methods related to the operating system.
+ * <p>
+ * Does <em>not</em> depend on any library jar files. But before using or extending this class and
+ * if you do not mind using <a href="http://jakarta.apache.org/commons/lang/">commons lang</a>, then
+ * have a look on <code>SystemUtils</code>.
+ * </p>
+ * 
+ * @author Bernd Rinn
+ */
+public class OSUtilities
+{
+
+    /** Platform specific line separator. */
+    public static final String LINE_SEPARATOR = System.getProperty("line.separator");
+
+    /**
+     * @return <code>true</code> if the operating system is UNIX like.
+     */
+    public static boolean isUnix()
+    {
+        return (File.separatorChar == '/');
+    }
+
+    /**
+     * @return <code>true</code> if the operating system is a MS Windows type.
+     */
+    public static boolean isWindows()
+    {
+        return (File.separatorChar == '\\');
+    }
+
+    /**
+     * @return <code>true</code> if the the operating system is a flavor of Mac OS X.
+     */
+    public static boolean isMacOS()
+    {
+        return "Mac OS X".equals(System.getProperty("os.name"));
+    }
+
+    /**
+     * @return The name of the computer platform that is compatible with respect to executables (CPU
+     *         architecture and OS name, both as precise as possible to be able to share libraries
+     *         and binaries).
+     */
+    public static String getCompatibleComputerPlatform()
+    {
+        String osName = System.getProperty("os.name");
+        if (osName.startsWith("Windows"))
+        {
+            osName = "Windows";
+        }
+        return System.getProperty("os.arch") + "-" + osName;
+    }
+
+    /**
+     * @return The name of the CPU architecture.
+     */
+    public static String getCPUArchitecture()
+    {
+        return System.getProperty("os.arch");
+    }
+
+    /**
+     * @return The name of the operating system.
+     */
+    public static String getOSName()
+    {
+        return System.getProperty("os.name");
+    }
+
+    /**
+     * @return The name of the computer platform (CPU architecture and OS name).
+     */
+    public static String getComputerPlatform()
+    {
+        return System.getProperty("os.arch") + "-" + System.getProperty("os.name");
+    }
+
+    /**
+     * @return The name of user that runs this program.
+     */
+    public static String getUsername()
+    {
+        return System.getProperty("user.name");
+    }
+
+    /**
+     * @return <code>true</code> if the user that runs this program is known to have root privileges
+     *         (based on his name).
+     */
+    public static boolean isRoot()
+    {
+        if (isUnix())
+        {
+            return "root".equals(getUsername());
+        } else
+        {
+            return "Administrator".equals(getUsername());
+        }
+    }
+
+    /**
+     * @return The <var>PATH</var> as provided by the operating system.
+     */
+    public static Set<String> getOSPath()
+    {
+        final String[] pathEntries =
+                System.getenv("PATH").split(Pattern.quote(System.getProperty("path.separator")));
+        return new LinkedHashSet<String>(Arrays.asList(pathEntries));
+    }
+
+    /**
+     * @param root Whether the path should be prepared for root or not.
+     * @return The path as provided by the operating system plus some path entries that should
+     *         always be available.
+     * @see #getOSPath()
+     */
+    public static Set<String> getSafeOSPath(boolean root)
+    {
+        final Set<String> pathEntries = getOSPath();
+        if (isUnix())
+        {
+            if (isMacOS())
+            {
+                pathEntries.add("/opt/local/bin"); // MacPorts
+                pathEntries.add("/sw/bin"); // Fink
+                if (root)
+                {
+                    pathEntries.add("/opt/local/sbin");
+                    pathEntries.add("/sw/sbin");
+                }
+            }
+            pathEntries.add("/usr/local/bin");
+            pathEntries.add("/usr/bin");
+            pathEntries.add("/bin");
+            if (root)
+            {
+                pathEntries.add("/usr/local/sbin");
+                pathEntries.add("/usr/sbin");
+                pathEntries.add("/sbin");
+            }
+        }
+        return pathEntries;
+    }
+
+    /**
+     * Convenience method for {@link #getSafeOSPath(boolean)} with <code>root=false</code>.
+     * 
+     * @return The path as provided by the operating system plus some path entries that should
+     *         always be available.
+     * @see #getSafeOSPath(boolean)
+     */
+    public static Set<String> getSafeOSPath()
+    {
+        return getSafeOSPath(false);
+    }
+
+    /**
+     * Search for the binary program with name <code>binaryName</code> in the operating system
+     * path..
+     * 
+     * @param executableName The name of the executable to search for. Under Windows, a name with
+     *            and without <code>.exe</code> appended will work, but the executable found needs
+     *            to have the .exe extension.
+     * @return The binary file that has been found in the path, or <code>null</code>, if no binary
+     *         file could be found.
+     */
+    public static File findExecutable(String executableName)
+    {
+        return OSUtilities.findExecutable(executableName, getSafeOSPath());
+    }
+
+    /**
+     * Search for the binary program with name <code>binaryName</code> in the set of paths denoted
+     * by <code>pathSet</code>.
+     * 
+     * @param executableName The name of the executable to search for. Under Windows, a name with
+     *            and without <code>.exe</code> appended will work, but the executable found needs
+     *            to have the .exe extension.
+     * @param pathSet The set of paths to search for. It is recommended to use an ordered set like
+     *            the {@link LinkedHashSet} here in order to get results that are independent of the
+     *            JRE implementation.
+     * @return The binary file that has been found in the path, or <code>null</code>, if no binary
+     *         file could be found.
+     */
+    public static File findExecutable(String executableName, Set<String> pathSet)
+    {
+        final String executableNameWithExtension =
+                addWindowsExecutableExtensionIfNecessary(executableName);
+        for (String dir : pathSet)
+        {
+            final File fileToCheck = new File(dir, executableNameWithExtension);
+            if (fileToCheck.exists())
+            {
+                return fileToCheck;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @return <code>true</code> if and only if an executable of name <var>executableName</var>
+     *         exists.
+     */
+    public static boolean executableExists(String executableName)
+    {
+        return (new File(OSUtilities.addWindowsExecutableExtensionIfNecessary(executableName)))
+                .exists();
+    }
+
+    /**
+     * @return <code>true</code> if and only if an executable of name <var>executableName</var>
+     *         exists.
+     */
+    public static boolean executableExists(File executable)
+    {
+        return (new File(OSUtilities.addWindowsExecutableExtensionIfNecessary(executable.getPath())))
+                .exists();
+    }
+
+    private static String addWindowsExecutableExtensionIfNecessary(String executableName)
+    {
+        if (isWindows() && executableName.indexOf('.') < 0)
+        {
+            return executableName + ".exe";
+        } else
+        {
+            return executableName;
+        }
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/utilities/ResourceUtilities.java b/source/java/ch/systemsx/cisd/base/utilities/ResourceUtilities.java
new file mode 100644
index 0000000..50b8c6e
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/utilities/ResourceUtilities.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2009 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.utilities;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.commons.io.IOUtils;
+
+import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * Utilities for handling Java resources.
+ * 
+ * @author Bernd Rinn
+ */
+public class ResourceUtilities
+{
+
+    /**
+     * Tries to copy the resource with the given name to a temporary file.
+     * 
+     * @param resource The name of the resource to copy.
+     * @param prefix The prefix to use for the temporary name.
+     * @param postfix The postfix to use for the temporary name.
+     * @return The name of the temporary file, or <code>null</code>, if the resource could not be
+     *         copied.
+     */
+    public static String tryCopyResourceToTempFile(final String resource, final String prefix,
+            final String postfix)
+    {
+        try
+        {
+            return copyResourceToTempFile(resource, prefix, postfix);
+        } catch (final Exception ex)
+        {
+            return null;
+        }
+    }
+
+    /**
+     * Copies the resource with the given name to a temporary file. The file will be deleted on
+     * program exit.
+     * 
+     * @param resource The name of the resource to copy.
+     * @param prefix The prefix to use for the temporary name.
+     * @param postfix The postfix to use for the temporary name.
+     * @return The name of the temporary file.
+     * @throws IllegalArgumentException If the resource cannot be found in the class path.
+     * @throws IOExceptionUnchecked If an {@link IOException} occurs.
+     */
+    public static String copyResourceToTempFile(final String resource, final String prefix,
+            final String postfix) throws IOExceptionUnchecked
+    {
+        final InputStream resourceStream = ResourceUtilities.class.getResourceAsStream(resource);
+        if (resourceStream == null)
+        {
+            throw new IllegalArgumentException("Resource '" + resource + "' not found.");
+        }
+        try
+        {
+            final File tempFile = File.createTempFile(prefix, postfix);
+            tempFile.deleteOnExit();
+            final OutputStream fileStream = new FileOutputStream(tempFile);
+            try
+            {
+                IOUtils.copy(resourceStream, fileStream);
+                fileStream.close();
+            } finally
+            {
+                IOUtils.closeQuietly(fileStream);
+            }
+            return tempFile.getAbsolutePath();
+        } catch (final IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        } finally
+        {
+            IOUtils.closeQuietly(resourceStream);
+        }
+    }
+
+}
diff --git a/source/java/ch/systemsx/cisd/base/utilities/package.html b/source/java/ch/systemsx/cisd/base/utilities/package.html
new file mode 100644
index 0000000..d7eda7f
--- /dev/null
+++ b/source/java/ch/systemsx/cisd/base/utilities/package.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+     "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Basic utilities.</title>
+</head>
+<body>
+<p>
+This package provides some basic utility classes. 
+</p>
+</body>
+</html> 
\ No newline at end of file
diff --git a/sourceTest/java/ch/systemsx/cisd/base/AllTests.java b/sourceTest/java/ch/systemsx/cisd/base/AllTests.java
new file mode 100644
index 0000000..3d6288f
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/AllTests.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base;
+
+import ch.systemsx.cisd.base.convert.NativeDataTests;
+import ch.systemsx.cisd.base.convert.NativeTaggedArrayTests;
+import ch.systemsx.cisd.base.exceptions.IOExceptionUncheckedTests;
+import ch.systemsx.cisd.base.io.ByteBufferRandomAccessFileTests;
+import ch.systemsx.cisd.base.io.RandomAccessFileImplTests;
+import ch.systemsx.cisd.base.mdarray.MDArrayTests;
+import ch.systemsx.cisd.base.namedthread.NamingThreadPoolExecutorTest;
+import ch.systemsx.cisd.base.unix.Unix;
+import ch.systemsx.cisd.base.unix.UnixTests;
+
+/**
+ * Run all unit tests.
+ *
+ * @author Bernd Rinn
+ */
+public class AllTests
+{
+
+    public static void main(String[] args) throws Throwable
+    {
+        NativeDataTests.main(args);
+        System.out.println();
+        NativeTaggedArrayTests.main(args);
+        System.out.println();
+        IOExceptionUncheckedTests.main(args);
+        System.out.println();
+        ByteBufferRandomAccessFileTests.main(args);
+        System.out.println();
+        RandomAccessFileImplTests.main(args);
+        System.out.println();
+        MDArrayTests.main(args);
+        System.out.println();
+        NamingThreadPoolExecutorTest.main(args);
+        System.out.println();
+        if (Unix.isOperational())
+        {
+            UnixTests.main(args);
+        }
+    }
+
+}
diff --git a/sourceTest/java/ch/systemsx/cisd/base/convert/NativeDataTests.java b/sourceTest/java/ch/systemsx/cisd/base/convert/NativeDataTests.java
new file mode 100644
index 0000000..d4a68e2
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/convert/NativeDataTests.java
@@ -0,0 +1,504 @@
+/*
+ * Copyright 2009 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.convert;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertTrue;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.base.BuildAndEnvironmentInfo;
+import ch.systemsx.cisd.base.convert.NativeData.ByteOrder;
+
+/**
+ * Test cases for {@link NativeData}.
+ * 
+ * @author Bernd Rinn
+ */
+public class NativeDataTests
+{
+
+    @DataProvider(name = "getOfs")
+    private Object[][] getOfs()
+    {
+        return new Object[][]
+            {
+                { 0, 0 },
+                { 0, 1 },
+                { 0, 2 },
+                { 0, 3 },
+                { 1, 0 },
+                { 1, 1 },
+                { 1, 2 },
+                { 1, 3 },
+                { 2, 0 },
+                { 2, 1 },
+                { 2, 2 },
+                { 2, 3 },
+                { 3, 0 },
+                { 3, 1 },
+                { 3, 2 },
+                { 3, 3 }, };
+    }
+
+    @Test(dataProvider = "getOfs")
+    public void testIntToByteToInt(int sourceOfs, int targetOfs)
+    {
+        final int sizeOfTarget = 4;
+        final int[] orignalArr = new int[]
+            { -1, 17, 100000, -1000000 };
+        final int[] iarr = new int[sourceOfs + orignalArr.length];
+        System.arraycopy(orignalArr, 0, iarr, sourceOfs, orignalArr.length);
+        final byte[] barr = new byte[iarr.length * sizeOfTarget + targetOfs];
+        NativeData.copyIntToByte(iarr, sourceOfs, barr, targetOfs, orignalArr.length,
+                NativeData.ByteOrder.NATIVE);
+        final int[] iarr2 = new int[(barr.length - targetOfs) / sizeOfTarget];
+        NativeData.copyByteToInt(barr, targetOfs, iarr2, sourceOfs, orignalArr.length,
+                NativeData.ByteOrder.NATIVE);
+        assertTrue(Arrays.equals(iarr, iarr2));
+    }
+
+    @Test
+    public void testIntChangeByteOrderAndBack()
+    {
+        assertEquals(0, NativeData.changeByteOrder(NativeData.changeByteOrder(0)));
+        assertEquals(1, NativeData.changeByteOrder(NativeData.changeByteOrder(1)));
+        assertEquals(-1, NativeData.changeByteOrder(NativeData.changeByteOrder(-1)));
+        assertEquals(Integer.MAX_VALUE,
+                NativeData.changeByteOrder(NativeData.changeByteOrder(Integer.MAX_VALUE)));
+        assertEquals(Integer.MIN_VALUE,
+                NativeData.changeByteOrder(NativeData.changeByteOrder(Integer.MIN_VALUE)));
+    }
+
+    @Test
+    public void testShortChangeByteOrderAndBack()
+    {
+        assertEquals((short) 0, NativeData.changeByteOrder(NativeData.changeByteOrder((short) 0)));
+        assertEquals((short) 1, NativeData.changeByteOrder(NativeData.changeByteOrder((short) 1)));
+        assertEquals((short) -1, NativeData.changeByteOrder(NativeData.changeByteOrder((short) -1)));
+        assertEquals(Short.MAX_VALUE,
+                NativeData.changeByteOrder(NativeData.changeByteOrder(Short.MAX_VALUE)));
+        assertEquals(Short.MIN_VALUE,
+                NativeData.changeByteOrder(NativeData.changeByteOrder(Short.MIN_VALUE)));
+    }
+
+    @Test
+    public void testCharChangeByteOrderAndBack()
+    {
+        assertEquals((char) 0, NativeData.changeByteOrder(NativeData.changeByteOrder((char) 0)));
+        assertEquals((char) 1, NativeData.changeByteOrder(NativeData.changeByteOrder((char) 1)));
+        assertEquals((char) -1, NativeData.changeByteOrder(NativeData.changeByteOrder((char) -1)));
+        assertEquals((char) Short.MAX_VALUE,
+                NativeData.changeByteOrder(NativeData.changeByteOrder((char) Short.MAX_VALUE)));
+        assertEquals((char) Short.MIN_VALUE,
+                NativeData.changeByteOrder(NativeData.changeByteOrder((char) Short.MIN_VALUE)));
+    }
+
+    @Test
+    public void testLongChangeByteOrderAndBack()
+    {
+        assertEquals(0, NativeData.changeByteOrder(NativeData.changeByteOrder(0L)));
+        assertEquals(1, NativeData.changeByteOrder(NativeData.changeByteOrder(1L)));
+        assertEquals(-1, NativeData.changeByteOrder(NativeData.changeByteOrder(-1L)));
+        assertEquals(Long.MAX_VALUE,
+                NativeData.changeByteOrder(NativeData.changeByteOrder(Long.MAX_VALUE)));
+        assertEquals(Long.MIN_VALUE,
+                NativeData.changeByteOrder(NativeData.changeByteOrder(Long.MIN_VALUE)));
+    }
+
+    @Test
+    public void testFloatChangeByteOrderAndBack()
+    {
+        assertEquals(0f, NativeData.changeByteOrder(NativeData.changeByteOrder(0f)));
+        assertEquals(1f, NativeData.changeByteOrder(NativeData.changeByteOrder(1f)));
+        assertEquals(-1f, NativeData.changeByteOrder(NativeData.changeByteOrder(-1f)));
+        assertEquals(Float.MAX_VALUE,
+                NativeData.changeByteOrder(NativeData.changeByteOrder(Float.MAX_VALUE)));
+        assertEquals(Float.MIN_VALUE,
+                NativeData.changeByteOrder(NativeData.changeByteOrder(Float.MIN_VALUE)));
+        assertEquals(-Float.MAX_VALUE,
+                NativeData.changeByteOrder(NativeData.changeByteOrder(-Float.MAX_VALUE)));
+        assertEquals(-Float.MIN_VALUE,
+                NativeData.changeByteOrder(NativeData.changeByteOrder(-Float.MIN_VALUE)));
+    }
+
+    @Test
+    public void testDoubleChangeByteOrderAndBack()
+    {
+        assertEquals(0., NativeData.changeByteOrder(NativeData.changeByteOrder(0.)));
+        assertEquals(1., NativeData.changeByteOrder(NativeData.changeByteOrder(1.)));
+        assertEquals(-1., NativeData.changeByteOrder(NativeData.changeByteOrder(-1.)));
+        assertEquals(Double.MAX_VALUE,
+                NativeData.changeByteOrder(NativeData.changeByteOrder(Double.MAX_VALUE)));
+        assertEquals(Double.MIN_VALUE,
+                NativeData.changeByteOrder(NativeData.changeByteOrder(Double.MIN_VALUE)));
+        assertEquals(-Double.MAX_VALUE,
+                NativeData.changeByteOrder(NativeData.changeByteOrder(-Double.MAX_VALUE)));
+        assertEquals(-Double.MIN_VALUE,
+                NativeData.changeByteOrder(NativeData.changeByteOrder(-Double.MIN_VALUE)));
+    }
+
+    @Test(dataProvider = "getOfs")
+    public void testLongToByteToLong(int sourceOfs, int targetOfs)
+    {
+        assertTrue(NativeData.isUseNativeLib());
+        final int sizeOfTarget = 8;
+        final long[] orignalArr = new long[]
+            { -1, 17, 100000, -1000000 };
+        final long[] iarr = new long[sourceOfs + orignalArr.length];
+        System.arraycopy(orignalArr, 0, iarr, sourceOfs, orignalArr.length);
+        final byte[] barr = new byte[iarr.length * sizeOfTarget + targetOfs];
+        NativeData.copyLongToByte(iarr, sourceOfs, barr, targetOfs, orignalArr.length,
+                NativeData.ByteOrder.NATIVE);
+        final long[] iarr2 = new long[(barr.length - targetOfs) / sizeOfTarget];
+        NativeData.copyByteToLong(barr, targetOfs, iarr2, sourceOfs, orignalArr.length,
+                NativeData.ByteOrder.NATIVE);
+        assertTrue(Arrays.equals(iarr, iarr2));
+    }
+
+    @Test(dataProvider = "getOfs")
+    public void testShortToByteToShort(int sourceOfs, int targetOfs)
+    {
+        assertTrue(NativeData.isUseNativeLib());
+        final int sizeOfTarget = 2;
+        final short[] orignalArr = new short[]
+            { -1, 17, 20000, (short) -50000 };
+        final short[] iarr = new short[sourceOfs + orignalArr.length];
+        System.arraycopy(orignalArr, 0, iarr, sourceOfs, orignalArr.length);
+        final byte[] barr = new byte[iarr.length * sizeOfTarget + targetOfs];
+        NativeData.copyShortToByte(iarr, sourceOfs, barr, targetOfs, orignalArr.length,
+                NativeData.ByteOrder.NATIVE);
+        final short[] iarr2 = new short[(barr.length - targetOfs) / sizeOfTarget];
+        NativeData.copyByteToShort(barr, targetOfs, iarr2, sourceOfs, orignalArr.length,
+                NativeData.ByteOrder.NATIVE);
+        assertTrue(Arrays.equals(iarr, iarr2));
+    }
+
+    @Test(dataProvider = "getOfs")
+    public void testCharToByteToChar(int sourceOfs, int targetOfs)
+    {
+        assertTrue(NativeData.isUseNativeLib());
+        final int sizeOfTarget = 2;
+        final char[] orignalArr = new char[]
+            { 'c', ';', '\u0222', '\u1000' };
+        final char[] iarr = new char[sourceOfs + orignalArr.length];
+        System.arraycopy(orignalArr, 0, iarr, sourceOfs, orignalArr.length);
+        final byte[] barr = new byte[iarr.length * sizeOfTarget + targetOfs];
+        NativeData.copyCharToByte(iarr, sourceOfs, barr, targetOfs, orignalArr.length,
+                NativeData.ByteOrder.NATIVE);
+        final char[] iarr2 = new char[(barr.length - targetOfs) / sizeOfTarget];
+        NativeData.copyByteToChar(barr, targetOfs, iarr2, sourceOfs, orignalArr.length,
+                NativeData.ByteOrder.NATIVE);
+        assertTrue(Arrays.equals(iarr, iarr2));
+    }
+
+    @Test(dataProvider = "getOfs")
+    public void testFloatToByteToFloat(int sourceOfs, int targetOfs)
+    {
+        assertTrue(NativeData.isUseNativeLib());
+        final int sizeOfTarget = 4;
+        final float[] orignalArr = new float[]
+            { -1, 17, 3.14159f, -1e6f };
+        final float[] iarr = new float[sourceOfs + orignalArr.length];
+        System.arraycopy(orignalArr, 0, iarr, sourceOfs, orignalArr.length);
+        final byte[] barr = new byte[iarr.length * sizeOfTarget + targetOfs];
+        NativeData.copyFloatToByte(iarr, sourceOfs, barr, targetOfs, orignalArr.length,
+                NativeData.ByteOrder.NATIVE);
+        final float[] iarr2 = new float[(barr.length - targetOfs) / sizeOfTarget];
+        NativeData.copyByteToFloat(barr, targetOfs, iarr2, sourceOfs, orignalArr.length,
+                NativeData.ByteOrder.NATIVE);
+        assertTrue(Arrays.equals(iarr, iarr2));
+    }
+
+    @Test(dataProvider = "getOfs")
+    public void testDoubleToByteToDouble(int sourceOfs, int targetOfs)
+    {
+        assertTrue(NativeData.isUseNativeLib());
+        final int sizeOfTarget = 8;
+        final double[] orignalArr = new double[]
+            { -1, 17, 3.14159, -1e42 };
+        final double[] iarr = new double[sourceOfs + orignalArr.length];
+        System.arraycopy(orignalArr, 0, iarr, sourceOfs, orignalArr.length);
+        final byte[] barr = new byte[iarr.length * sizeOfTarget + targetOfs];
+        NativeData.copyDoubleToByte(iarr, sourceOfs, barr, targetOfs, orignalArr.length,
+                NativeData.ByteOrder.NATIVE);
+        final double[] iarr2 = new double[(barr.length - targetOfs) / sizeOfTarget];
+        NativeData.copyByteToDouble(barr, targetOfs, iarr2, sourceOfs, orignalArr.length,
+                NativeData.ByteOrder.NATIVE);
+        assertTrue(Arrays.equals(iarr, iarr2));
+    }
+
+    @Test
+    public void testShortEndianConversion()
+    {
+        assertTrue(NativeData.isUseNativeLib());
+        final short[] values = new short[]
+            { 1, 2, 4, 8, 16, 256, 512 };
+        final short[] convertedValuesExpected = new short[]
+            { 1 << 8, 1 << 9, 1 << 10, 1 << 11, 1 << 12, 1, 2 };
+        final short[] convertedValuesFound =
+                NativeData.byteToShort(NativeData.shortToByte(values, ByteOrder.BIG_ENDIAN),
+                        ByteOrder.LITTLE_ENDIAN);
+        assertTrue(Arrays.equals(convertedValuesExpected, convertedValuesFound));
+    }
+
+    @Test
+    public void testIntEndianConversion()
+    {
+        assertTrue(NativeData.isUseNativeLib());
+        final int[] values = new int[]
+            { 1, 2, 4, 8, 16, 256, 1 << 16 };
+        final int[] convertedValuesExpected = new int[]
+            { 1 << 24, 1 << 25, 1 << 26, 1 << 27, 1 << 28, 1 << 16, 256 };
+        final int[] convertedValuesFound =
+                NativeData.byteToInt(NativeData.intToByte(values, ByteOrder.BIG_ENDIAN),
+                        ByteOrder.LITTLE_ENDIAN);
+        assertTrue(Arrays.equals(convertedValuesExpected, convertedValuesFound));
+    }
+
+    @Test
+    public void testLongEndianConversion()
+    {
+        assertTrue(NativeData.isUseNativeLib());
+        final long[] values = new long[]
+            { 1, 2, 4, 8, 16, 256, 1L << 16, 1L << 24 };
+        final long[] convertedValuesExpected = new long[]
+            { 1L << 56, 1L << 57, 1L << 58, 1L << 59, 1L << 60, 1L << 48, 1L << 40, 1L << 32 };
+        final long[] convertedValuesFound =
+                NativeData.byteToLong(NativeData.longToByte(values, ByteOrder.BIG_ENDIAN),
+                        ByteOrder.LITTLE_ENDIAN);
+        assertTrue(Arrays.equals(convertedValuesExpected, convertedValuesFound));
+    }
+
+    @Test
+    public void testFloatLittleEndianRoundtrip()
+    {
+        assertTrue(NativeData.isUseNativeLib());
+        final float[] values = new float[]
+            { 1.1f, 2.2f, 3.3f, 1e-25f, 1e25f };
+        final float[] convertedValuesFound =
+                NativeData.byteToFloat(NativeData.floatToByte(values, ByteOrder.LITTLE_ENDIAN),
+                        ByteOrder.LITTLE_ENDIAN);
+        assertTrue(Arrays.equals(values, convertedValuesFound));
+    }
+
+    @Test
+    public void testFloatBigEndianRoundtrip()
+    {
+        assertTrue(NativeData.isUseNativeLib());
+        final float[] values = new float[]
+            { 1.1f, 2.2f, 3.3f, 1e-25f, 1e25f };
+        final float[] convertedValuesFound =
+                NativeData.byteToFloat(NativeData.floatToByte(values, ByteOrder.BIG_ENDIAN),
+                        ByteOrder.BIG_ENDIAN);
+        assertTrue(Arrays.equals(values, convertedValuesFound));
+    }
+
+    @Test
+    public void testDoubleLittleEndianRoundtrip()
+    {
+        assertTrue(NativeData.isUseNativeLib());
+        final double[] values = new double[]
+            { 1.1f, 2.2f, 3.3f, 1e-25f, 1e25f };
+        final double[] convertedValuesFound =
+                NativeData.byteToDouble(NativeData.doubleToByte(values, ByteOrder.LITTLE_ENDIAN),
+                        ByteOrder.LITTLE_ENDIAN);
+        assertTrue(Arrays.equals(values, convertedValuesFound));
+    }
+
+    @Test
+    public void testDoubleBigEndianRoundtrip()
+    {
+        assertTrue(NativeData.isUseNativeLib());
+        final double[] values = new double[]
+            { 1.1, 2.2, 3.3, 1e-25, 1e25 };
+        final double[] convertedValuesFound =
+                NativeData.byteToDouble(NativeData.doubleToByte(values, ByteOrder.BIG_ENDIAN),
+                        ByteOrder.BIG_ENDIAN);
+        assertTrue(Arrays.equals(values, convertedValuesFound));
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testNPE()
+    {
+        assertTrue(NativeData.isUseNativeLib());
+        NativeData.copyByteToLong(null, 0, null, 0, 0, ByteOrder.NATIVE);
+    }
+
+    @Test(expectedExceptions = IndexOutOfBoundsException.class)
+    public void testIOOB()
+    {
+        assertTrue(NativeData.isUseNativeLib());
+        NativeData.copyByteToLong(new byte[] {}, -1, new long[] {}, 0, 0, ByteOrder.NATIVE);
+    }
+
+    @Test(expectedExceptions = IndexOutOfBoundsException.class)
+    public void testIOOB2()
+    {
+        assertTrue(NativeData.isUseNativeLib());
+        NativeData.copyByteToLong(new byte[] {}, 0, new long[] {}, 10, 0, ByteOrder.NATIVE);
+    }
+
+    @Test
+    public void testPlatformEndiness()
+    {
+        assertTrue(NativeData.isUseNativeLib());
+        final double[] values = new double[]
+            { 1.1, 2.2, 3.3, 1e-200, 1e200 };
+        final double[] valuesLE =
+                NativeData.byteToDouble(NativeData.doubleToByte(values, ByteOrder.LITTLE_ENDIAN),
+                        ByteOrder.NATIVE);
+        final double[] valuesBE =
+                NativeData.byteToDouble(NativeData.doubleToByte(values, ByteOrder.BIG_ENDIAN),
+                        ByteOrder.NATIVE);
+        if (Arrays.equals(values, valuesLE))
+        {
+            assertEquals(NativeData.ByteOrder.LITTLE_ENDIAN, NativeData.getNativeByteOrder());
+            assertFalse(Arrays.equals(values, valuesBE));
+        }
+        if (Arrays.equals(values, valuesBE))
+        {
+            assertEquals(NativeData.ByteOrder.BIG_ENDIAN, NativeData.getNativeByteOrder());
+            assertFalse(Arrays.equals(values, valuesLE));
+        }
+    }
+
+    @Test
+    public void testFloatToByteNonNativeByteOrderPartialOutputArray()
+    {
+        assertTrue(NativeData.isUseNativeLib());
+        final int sizeOfTarget = 4;
+        final ByteOrder nonNativeByteOrder =
+                (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+                        : ByteOrder.LITTLE_ENDIAN;
+        final float[] iarr = new float[]
+            { -1, 17, 3.14159f, -1e6f };
+        final byte[] headerArray = new byte[]
+            { 1, 2, 3, 4 };
+        final byte[] trailerArray = new byte[]
+            { 5, 6, 7, 8 };
+        final byte[] barr =
+                new byte[iarr.length * sizeOfTarget + headerArray.length + trailerArray.length];
+        System.arraycopy(headerArray, 0, barr, 0, headerArray.length);
+        System.arraycopy(trailerArray, 0, barr, headerArray.length + iarr.length * sizeOfTarget,
+                trailerArray.length);
+        NativeData.copyFloatToByte(iarr, 0, barr, headerArray.length, iarr.length,
+                nonNativeByteOrder);
+        final byte[] headerArray2 = ArrayUtils.subarray(barr, 0, headerArray.length);
+        final byte[] trailerArray2 =
+                ArrayUtils.subarray(barr, headerArray.length + iarr.length * sizeOfTarget,
+                        barr.length);
+        assertTrue(Arrays.equals(headerArray, headerArray2));
+        assertTrue(Arrays.equals(trailerArray, trailerArray2));
+    }
+
+    private void afterClass()
+    {
+    }
+
+    private void setUp()
+    {
+    }
+
+    public static void main(String[] args) throws Throwable
+    {
+        System.out.println(BuildAndEnvironmentInfo.INSTANCE);
+        System.out.println("Test class: " + NativeDataTests.class.getSimpleName());
+        System.out.println();
+        NativeData.ensureNativeLibIsLoaded();
+        final NativeDataTests test = new NativeDataTests();
+        try
+        {
+            for (Method m : NativeDataTests.class.getMethods())
+            {
+                final Test testAnnotation = m.getAnnotation(Test.class);
+                if (testAnnotation == null)
+                {
+                    continue;
+                }
+                if (m.getParameterTypes().length == 0)
+                {
+                    System.out.println("Running " + m.getName());
+                    test.setUp();
+                    try
+                    {
+                        m.invoke(test);
+                    } catch (InvocationTargetException wrapperThrowable)
+                    {
+                        final Throwable th = wrapperThrowable.getCause();
+                        boolean exceptionFound = false;
+                        for (Class<?> expectedExClazz : testAnnotation.expectedExceptions())
+                        {
+                            if (expectedExClazz == th.getClass())
+                            {
+                                exceptionFound = true;
+                                break;
+                            }
+                        }
+                        if (exceptionFound == false)
+                        {
+                            throw th;
+                        }
+                    }
+                }
+                if (m.getParameterTypes().length == 2
+                        && "getOfs".equals(testAnnotation.dataProvider()))
+                {
+                    System.out.println("Running " + m.getName());
+                    test.setUp();
+                    try
+                    {
+                        final Object[][] testArgs = test.getOfs();
+                        for (Object[] a : testArgs)
+                        {
+                            System.out.println(" Arguments: " + Arrays.toString(a));
+                            m.invoke(test, a);
+                        }
+                    } catch (InvocationTargetException wrapperThrowable)
+                    {
+                        final Throwable th = wrapperThrowable.getCause();
+                        boolean exceptionFound = false;
+                        for (Class<?> expectedExClazz : testAnnotation.expectedExceptions())
+                        {
+                            if (expectedExClazz == th.getClass())
+                            {
+                                exceptionFound = true;
+                                break;
+                            }
+                        }
+                        if (exceptionFound == false)
+                        {
+                            throw th;
+                        }
+                    }
+                }
+            }
+            System.out.println("Tests OK!");
+        } finally
+        {
+            test.afterClass();
+        }
+    }
+
+}
diff --git a/sourceTest/java/ch/systemsx/cisd/base/convert/NativeTaggedArrayTests.java b/sourceTest/java/ch/systemsx/cisd/base/convert/NativeTaggedArrayTests.java
new file mode 100644
index 0000000..13b0115
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/convert/NativeTaggedArrayTests.java
@@ -0,0 +1,470 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.convert;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.base.BuildAndEnvironmentInfo;
+import ch.systemsx.cisd.base.convert.NativeData.ByteOrder;
+import ch.systemsx.cisd.base.mdarray.MDDoubleArray;
+import ch.systemsx.cisd.base.mdarray.MDFloatArray;
+import ch.systemsx.cisd.base.mdarray.MDIntArray;
+import ch.systemsx.cisd.base.mdarray.MDLongArray;
+import ch.systemsx.cisd.base.mdarray.MDShortArray;
+
+import static org.testng.AssertJUnit.*;
+
+/**
+ * Test cases for {@link NativeTaggedArray}.
+ * 
+ * @author Bernd Rinn
+ */
+public class NativeTaggedArrayTests
+{
+
+    @Test
+    public static void testFloat1DArrayNativeByteOrder()
+    {
+        final float[] floatArr = new float[]
+            { 1.1f, -3.2f, 1001.5f };
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(floatArr);
+        assertEquals(3 * 4 + 4 + 4, taggedArr.length);
+        final float[] convertedFloatArr = NativeTaggedArray.tryToFloatArray1D(taggedArr);
+        final NativeTaggedArray.NativeArrayTag tag = NativeTaggedArray.tryGetArrayTag(taggedArr);
+        final NativeArrayEncoding encoding = tag.getEncoding();
+        assertNotNull(encoding);
+        assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+        assertEquals(4, encoding.getSizeInBytes());
+        assertTrue(encoding.isFloatingPoint());
+        assertFalse(encoding.isInteger());
+        assertEquals(1, tag.getDimensions().length);
+        assertEquals(3, tag.getDimensions()[0]);
+        assertTrue(Arrays.equals(floatArr, convertedFloatArr));
+    }
+
+    @Test
+    public static void testFloat1DArrayNonNativeByteOrder()
+    {
+        final float[] floatArr = new float[]
+            { 1.1f, -3.2f, 1001.5f };
+        final ByteOrder nonNativeByteOrder =
+                (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+                        : ByteOrder.LITTLE_ENDIAN;
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(floatArr, nonNativeByteOrder);
+        assertEquals(3 * 4 + 4 + 4, taggedArr.length);
+        final float[] convertedFloatArr = NativeTaggedArray.tryToFloatArray1D(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(nonNativeByteOrder, encoding.getByteOrder());
+        assertEquals(4, encoding.getSizeInBytes());
+        assertTrue(encoding.isFloatingPoint());
+        assertFalse(encoding.isInteger());
+        assertTrue(Arrays.equals(floatArr, convertedFloatArr));
+    }
+
+    @Test
+    public static void testFloat2DArrayNativeByteOrder()
+    {
+        final MDFloatArray floatArr = new MDFloatArray(new float[]
+            { 1, 2, 3, 4 }, new int[] { 2, 2 });
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(floatArr);
+        assertEquals(4 * 4 + 2 * 4 + 4, taggedArr.length);
+        final MDFloatArray convertedFloatArr = NativeTaggedArray.tryToFloatArray(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+        assertEquals(4, encoding.getSizeInBytes());
+        assertTrue(encoding.isFloatingPoint());
+        assertFalse(encoding.isInteger());
+        assertTrue(floatArr.equals(convertedFloatArr));
+    }
+
+    @Test
+    public static void testFloat2DArrayNonNativeByteOrder()
+    {
+        final MDFloatArray floatArr = new MDFloatArray(new float[]
+            { 1, 2, 3, 4 }, new int[] { 2, 2 });
+        final ByteOrder nonNativeByteOrder =
+            (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+                    : ByteOrder.LITTLE_ENDIAN;
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(floatArr, nonNativeByteOrder);
+        assertEquals(4 * 4 + 2 * 4 + 4, taggedArr.length);
+        final MDFloatArray convertedFloatArr = NativeTaggedArray.tryToFloatArray(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(nonNativeByteOrder, encoding.getByteOrder());
+        assertEquals(4, encoding.getSizeInBytes());
+        assertTrue(encoding.isFloatingPoint());
+        assertFalse(encoding.isInteger());
+        assertTrue(floatArr.equals(convertedFloatArr));
+    }
+
+    @Test
+    public static void testDouble1DArrayNativeByteOrder()
+    {
+        final double[] doubleArr = new double[]
+            { 1.1, -3.2, 1001.5 };
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(doubleArr);
+        assertEquals(3 * 8 + 4 + 4, taggedArr.length);
+        final double[] convertedDoubleArr = NativeTaggedArray.tryToDoubleArray1D(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+        assertEquals(8, encoding.getSizeInBytes());
+        assertTrue(encoding.isFloatingPoint());
+        assertFalse(encoding.isInteger());
+        assertTrue(Arrays.equals(doubleArr, convertedDoubleArr));
+    }
+
+    @Test
+    public static void testDouble1DArrayNonNativeByteOrder()
+    {
+        final double[] doubleArr = new double[]
+            { 1.1, -3.2, 1001.5 };
+        final ByteOrder nonNativeByteOrder =
+                (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+                        : ByteOrder.LITTLE_ENDIAN;
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(doubleArr, nonNativeByteOrder);
+        assertEquals(3 * 8 + 4 + 4, taggedArr.length);
+        final double[] convertedDoubleArr = NativeTaggedArray.tryToDoubleArray1D(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(nonNativeByteOrder, encoding.getByteOrder());
+        assertEquals(8, encoding.getSizeInBytes());
+        assertTrue(encoding.isFloatingPoint());
+        assertFalse(encoding.isInteger());
+        assertTrue(Arrays.equals(doubleArr, convertedDoubleArr));
+    }
+
+    @Test
+    public static void testDouble2DArrayNativeByteOrder()
+    {
+        final MDDoubleArray doubleArr = new MDDoubleArray(new double[]
+            { 1, 2, 3, 4 }, new int[] { 2, 2 });
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(doubleArr);
+        assertEquals(4 * 8 + 2 * 4 + 4, taggedArr.length);
+        final MDDoubleArray convertedDoubleArr = NativeTaggedArray.tryToDoubleArray(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+        assertEquals(8, encoding.getSizeInBytes());
+        assertTrue(encoding.isFloatingPoint());
+        assertFalse(encoding.isInteger());
+        assertTrue(doubleArr.equals(convertedDoubleArr));
+    }
+
+    @Test
+    public static void testDouble2DArrayNonNativeByteOrder()
+    {
+        final MDDoubleArray doubleArr = new MDDoubleArray(new double[]
+            { 1, 2, 3, 4 }, new int[] { 2, 2 });
+        final ByteOrder nonNativeByteOrder =
+            (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+                    : ByteOrder.LITTLE_ENDIAN;
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(doubleArr, nonNativeByteOrder);
+        assertEquals(4 * 8 + 2 * 4 + 4, taggedArr.length);
+        final MDDoubleArray convertedDoubleArr = NativeTaggedArray.tryToDoubleArray(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(nonNativeByteOrder, encoding.getByteOrder());
+        assertEquals(8, encoding.getSizeInBytes());
+        assertTrue(encoding.isFloatingPoint());
+        assertFalse(encoding.isInteger());
+        assertTrue(doubleArr.equals(convertedDoubleArr));
+    }
+
+    @Test
+    public static void testShort1DArrayNativeByteOrder()
+    {
+        final short[] shortArr = new short[]
+            { 1, -3, 1001 };
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(shortArr);
+        assertEquals(3 * 2 + 4 + 4, taggedArr.length);
+        final short[] convertedShortArr = NativeTaggedArray.tryToShortArray1D(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+        assertEquals(2, encoding.getSizeInBytes());
+        assertFalse(encoding.isFloatingPoint());
+        assertTrue(encoding.isInteger());
+        assertTrue(Arrays.equals(shortArr, convertedShortArr));
+    }
+
+    @Test
+    public static void testShort1DArrayNonNativeByteOrder()
+    {
+        final short[] shortArr = new short[]
+            { 1, -3, 1001 };
+        final ByteOrder nonNativeByteOrder =
+                (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+                        : ByteOrder.LITTLE_ENDIAN;
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(shortArr, nonNativeByteOrder);
+        assertEquals(3 * 2 + 4 + 4, taggedArr.length);
+        final short[] convertedShortArr = NativeTaggedArray.tryToShortArray1D(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(nonNativeByteOrder, encoding.getByteOrder());
+        assertEquals(2, encoding.getSizeInBytes());
+        assertFalse(encoding.isFloatingPoint());
+        assertTrue(encoding.isInteger());
+        assertTrue(Arrays.equals(shortArr, convertedShortArr));
+    }
+
+    @Test
+    public static void testShort2DArrayNativeByteOrder()
+    {
+        final MDShortArray shortArr = new MDShortArray(new short[]
+            { 1, 2, 3, 4 }, new int[] { 2, 2 });
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(shortArr);
+        assertEquals(4 * 2 + 2 * 4 + 4, taggedArr.length);
+        final MDShortArray convertedShortArr = NativeTaggedArray.tryToShortArray(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+        assertEquals(2, encoding.getSizeInBytes());
+        assertFalse(encoding.isFloatingPoint());
+        assertTrue(encoding.isInteger());
+        assertTrue(shortArr.equals(convertedShortArr));
+    }
+
+    @Test
+    public static void testShort2DArrayNonNativeByteOrder()
+    {
+        final MDShortArray shortArr = new MDShortArray(new short[]
+            { 1, 2, 3, 4 }, new int[] { 2, 2 });
+        final ByteOrder nonNativeByteOrder =
+            (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+                    : ByteOrder.LITTLE_ENDIAN;
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(shortArr, nonNativeByteOrder);
+        assertEquals(4 * 2 + 2 * 4 + 4, taggedArr.length);
+        final MDShortArray convertedShortArr = NativeTaggedArray.tryToShortArray(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(nonNativeByteOrder, encoding.getByteOrder());
+        assertEquals(2, encoding.getSizeInBytes());
+        assertFalse(encoding.isFloatingPoint());
+        assertTrue(encoding.isInteger());
+        assertTrue(shortArr.equals(convertedShortArr));
+    }
+
+    @Test
+    public static void testInt1DArrayNativeByteOrder()
+    {
+        final int[] intArr = new int[]
+            { 1, -3, 1001 };
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(intArr);
+        assertEquals(3 * 4 + 4 + 4, taggedArr.length);
+        final int[] convertedIntArr = NativeTaggedArray.tryToIntArray1D(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+        assertEquals(4, encoding.getSizeInBytes());
+        assertFalse(encoding.isFloatingPoint());
+        assertTrue(encoding.isInteger());
+        assertTrue(Arrays.equals(intArr, convertedIntArr));
+    }
+
+    @Test
+    public static void testInt1DArrayNonNativeByteOrder()
+    {
+        final int[] intArr = new int[]
+            { 1, -3, 1001 };
+        final ByteOrder nonNativeByteOrder =
+                (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+                        : ByteOrder.LITTLE_ENDIAN;
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(intArr, nonNativeByteOrder);
+        assertEquals(3 * 4 + 4 + 4, taggedArr.length);
+        final int[] convertedIntArr = NativeTaggedArray.tryToIntArray1D(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(nonNativeByteOrder, encoding.getByteOrder());
+        assertEquals(4, encoding.getSizeInBytes());
+        assertFalse(encoding.isFloatingPoint());
+        assertTrue(encoding.isInteger());
+        assertTrue(Arrays.equals(intArr, convertedIntArr));
+    }
+
+    @Test
+    public static void testInt2DArrayNativeByteOrder()
+    {
+        final MDIntArray intArr = new MDIntArray(new int[]
+            { 1, 2, 3, 4 }, new int[] { 2, 2 });
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(intArr);
+        assertEquals(4 * 4 + 2 * 4 + 4, taggedArr.length);
+        final MDIntArray convertedIntArr = NativeTaggedArray.tryToIntArray(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+        assertEquals(4, encoding.getSizeInBytes());
+        assertFalse(encoding.isFloatingPoint());
+        assertTrue(encoding.isInteger());
+        assertTrue(intArr.equals(convertedIntArr));
+    }
+
+    @Test
+    public static void testInt2DArrayNonNativeByteOrder()
+    {
+        final MDIntArray intArr = new MDIntArray(new int[]
+            { 1, 2, 3, 4 }, new int[] { 2, 2 });
+        final ByteOrder nonNativeByteOrder =
+            (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+                    : ByteOrder.LITTLE_ENDIAN;
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(intArr, nonNativeByteOrder);
+        assertEquals(4 * 4 + 2 * 4 + 4, taggedArr.length);
+        final MDIntArray convertedIntArr = NativeTaggedArray.tryToIntArray(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(nonNativeByteOrder, encoding.getByteOrder());
+        assertEquals(4, encoding.getSizeInBytes());
+        assertFalse(encoding.isFloatingPoint());
+        assertTrue(encoding.isInteger());
+        assertTrue(intArr.equals(convertedIntArr));
+    }
+
+    @Test
+    public static void testLong1DArrayNativeByteOrder()
+    {
+        final long[] longArr = new long[]
+            { 1, -3, 1001 };
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(longArr);
+        assertEquals(3 * 8 + 4 + 4, taggedArr.length);
+        final long[] convertedLongArr = NativeTaggedArray.tryToLongArray1D(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+        assertEquals(8, encoding.getSizeInBytes());
+        assertFalse(encoding.isFloatingPoint());
+        assertTrue(encoding.isInteger());
+        assertTrue(Arrays.equals(longArr, convertedLongArr));
+    }
+
+    @Test
+    public static void testLong1DArrayNonNativeByteOrder()
+    {
+        final long[] longArr = new long[]
+            { 1, -3, 1001 };
+        final ByteOrder nonNativeByteOrder =
+                (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+                        : ByteOrder.LITTLE_ENDIAN;
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(longArr, nonNativeByteOrder);
+        assertEquals(3 * 8 + 4 + 4, taggedArr.length);
+        final long[] convertedLongArr = NativeTaggedArray.tryToLongArray1D(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(nonNativeByteOrder, encoding.getByteOrder());
+        assertEquals(8, encoding.getSizeInBytes());
+        assertFalse(encoding.isFloatingPoint());
+        assertTrue(encoding.isInteger());
+        assertTrue(Arrays.equals(longArr, convertedLongArr));
+    }
+
+    @Test
+    public static void testLong2DArrayNativeByteOrder()
+    {
+        final MDLongArray longArr = new MDLongArray(new long[]
+            { 1, 2, 3, 4 }, new int[] { 2, 2 });
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(longArr);
+        assertEquals(4 * 8 + 2 * 4 + 4, taggedArr.length);
+        final MDLongArray convertedLongArr = NativeTaggedArray.tryToLongArray(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(NativeData.getNativeByteOrder(), encoding.getByteOrder());
+        assertEquals(8, encoding.getSizeInBytes());
+        assertFalse(encoding.isFloatingPoint());
+        assertTrue(encoding.isInteger());
+        assertTrue(longArr.equals(convertedLongArr));
+    }
+
+    @Test
+    public static void testLong2DArrayNonNativeByteOrder()
+    {
+        final MDLongArray longArr = new MDLongArray(new long[]
+            { 1, 2, 3, 4 }, new int[] { 2, 2 });
+        final ByteOrder nonNativeByteOrder =
+            (NativeData.getNativeByteOrder() == ByteOrder.LITTLE_ENDIAN) ? ByteOrder.BIG_ENDIAN
+                    : ByteOrder.LITTLE_ENDIAN;
+        final byte[] taggedArr = NativeTaggedArray.toByteArray(longArr, nonNativeByteOrder);
+        assertEquals(4 * 8 + 2 * 4 + 4, taggedArr.length);
+        final MDLongArray convertedLongArr = NativeTaggedArray.tryToLongArray(taggedArr);
+        final NativeArrayEncoding encoding = NativeArrayEncoding.tryGetEncoding(taggedArr);
+        assertNotNull(encoding);
+        assertEquals(nonNativeByteOrder, encoding.getByteOrder());
+        assertEquals(8, encoding.getSizeInBytes());
+        assertFalse(encoding.isFloatingPoint());
+        assertTrue(encoding.isInteger());
+        assertTrue(longArr.equals(convertedLongArr));
+    }
+
+    private void afterClass()
+    {
+    }
+
+    private void setUp()
+    {
+    }
+
+    public static void main(String[] args) throws Throwable
+    {
+        System.out.println(BuildAndEnvironmentInfo.INSTANCE);
+        System.out.println("Test class: " + NativeTaggedArrayTests.class.getSimpleName());
+        System.out.println();
+        NativeData.ensureNativeLibIsLoaded();
+        final NativeTaggedArrayTests test = new NativeTaggedArrayTests();
+        try
+        {
+            for (Method m : NativeTaggedArrayTests.class.getMethods())
+            {
+                final Test testAnnotation = m.getAnnotation(Test.class);
+                if (testAnnotation == null || m.getParameterTypes().length > 0)
+                {
+                    continue;
+                }
+                System.out.println("Running " + m.getName());
+                test.setUp();
+                try
+                {
+                    m.invoke(test);
+                } catch (InvocationTargetException wrapperThrowable)
+                {
+                    final Throwable th = wrapperThrowable.getCause();
+                    boolean exceptionFound = false;
+                    for (Class<?> expectedExClazz : testAnnotation.expectedExceptions())
+                    {
+                        if (expectedExClazz == th.getClass())
+                        {
+                            exceptionFound = true;
+                            break;
+                        }
+                    }
+                    if (exceptionFound == false)
+                    {
+                        throw th;
+                    }
+                }
+            }
+            System.out.println("Tests OK!");
+        } finally
+        {
+            test.afterClass();
+        }
+    }
+
+}
diff --git a/sourceTest/java/ch/systemsx/cisd/base/exceptions/CheckedExceptionTunnelTest.java b/sourceTest/java/ch/systemsx/cisd/base/exceptions/CheckedExceptionTunnelTest.java
new file mode 100644
index 0000000..04e34eb
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/exceptions/CheckedExceptionTunnelTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.exceptions;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.apache.commons.lang.StringUtils;
+import org.testng.annotations.Test;
+
+import static org.testng.AssertJUnit.*;
+
+/**
+ * Test cases for {@link CheckedExceptionTunnel}
+ * 
+ * @author Bernd Rinn
+ */
+public class CheckedExceptionTunnelTest
+{
+
+    @Test
+    public void testGetMessage()
+    {
+        final IOException ioe = new IOException("This is the message");
+        final RuntimeException re = CheckedExceptionTunnel.wrapIfNecessary(ioe);
+        assertEquals("This is the message", re.getMessage());
+    }
+
+    @Test
+    public void testToString()
+    {
+        final InterruptedException ioe = new InterruptedException("Somehow got interrupted");
+        final RuntimeException re = CheckedExceptionTunnel.wrapIfNecessary(ioe);
+        assertEquals("java.lang.InterruptedException: Somehow got interrupted", re.toString());
+    }
+
+    @Test
+    public void testPrintStackTrace()
+    {
+        final InterruptedException ie = new InterruptedException("Somehow got interrupted");
+        ie.fillInStackTrace();
+        final RuntimeException re = CheckedExceptionTunnel.wrapIfNecessary(ie);
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        re.printStackTrace(pw);
+        final String[] lines = StringUtils.split(sw.toString(), '\n');
+        assertEquals("java.lang.InterruptedException: Somehow got interrupted", lines[0]);
+        assertTrue(
+                lines[1],
+                lines[1].startsWith("\tat ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnelTest."
+                        + "testPrintStackTrace(CheckedExceptionTunnelTest.java"));
+    }
+
+    @Test
+    public void testPrintFullStackTrace()
+    {
+        final Exception e = new Exception("Some exceptional condition");
+        e.fillInStackTrace();
+        final CheckedExceptionTunnel re = new CheckedExceptionTunnel(e);
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        re.printFullStackTrace();
+        re.printFullStackTrace(pw);
+        final String[] lines = StringUtils.split(sw.toString(), '\n');
+        assertEquals(
+                "ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel: Some exceptional condition",
+                lines[0]);
+        assertTrue(
+                lines[1],
+                lines[1].startsWith("\tat ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnelTest."
+                        + "testPrintFullStackTrace(CheckedExceptionTunnelTest.java:"));
+    }
+}
diff --git a/sourceTest/java/ch/systemsx/cisd/base/exceptions/IOExceptionUncheckedTests.java b/sourceTest/java/ch/systemsx/cisd/base/exceptions/IOExceptionUncheckedTests.java
new file mode 100644
index 0000000..76db02d
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/exceptions/IOExceptionUncheckedTests.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.exceptions;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertNotNull;
+import static org.testng.AssertJUnit.assertNull;
+import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.AssertJUnit.fail;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.base.BuildAndEnvironmentInfo;
+import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
+import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked;
+
+/**
+ * Test cases for {@link IOExceptionUnchecked}.
+ *
+ * @author Bernd Rinn
+ */
+public class IOExceptionUncheckedTests
+{
+    private void generateFileNotFoundException() throws IOExceptionUnchecked
+    {
+        try
+        {
+            new FileInputStream(new File("doesnt.exist"));
+        } catch (IOException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+    
+    @Test
+    public void testWrapUnwrapIOException()
+    {
+        try
+        {
+            generateFileNotFoundException();
+            fail("No IOException thrown");
+        } catch (IOExceptionUnchecked e)
+        {
+            final Exception ex = CheckedExceptionTunnel.unwrapIfNecessary(e);
+            assertTrue(ex instanceof FileNotFoundException);
+            assertTrue(ex.getMessage().startsWith("doesnt.exist"));
+        }
+    }
+    
+    @Test
+    public void testWrapUnwrapNonIOException()
+    {
+        try
+        {
+            throw new IOExceptionUnchecked(new IllegalStateException("Don't like this state"));
+        } catch (CheckedExceptionTunnel e)
+        {
+            final Exception ex = CheckedExceptionTunnel.unwrapIfNecessary(e);
+            assertTrue(ex instanceof IOException);
+            assertEquals("IllegalStateException: Don't like this state", ex.getMessage());
+            assertNotNull(ex.getCause());
+            assertTrue(ex.getCause() instanceof IllegalStateException);
+            assertEquals("Don't like this state", ex.getCause().getMessage());
+        }
+    }
+
+    @Test
+    public void testWrapUnwrapIOExceptionGivingMsg()
+    {
+        try
+        {
+            throw new IOExceptionUnchecked("Some message");
+        } catch (CheckedExceptionTunnel e)
+        {
+            final Exception ex = CheckedExceptionTunnel.unwrapIfNecessary(e);
+            assertTrue(ex instanceof IOException);
+            assertEquals("Some message", ex.getMessage());
+            assertNull(ex.getCause());
+        }
+    }
+
+    public static void main(String[] args) throws Throwable
+    {
+        System.out.println(BuildAndEnvironmentInfo.INSTANCE);
+        System.out.println("Test class: " + IOExceptionUncheckedTests.class.getSimpleName());
+        System.out.println();
+        final IOExceptionUncheckedTests test = new IOExceptionUncheckedTests();
+        for (Method m : IOExceptionUncheckedTests.class.getMethods())
+        {
+            final Test testAnnotation = m.getAnnotation(Test.class);
+            if (testAnnotation == null)
+            {
+                continue;
+            }
+            if (m.getParameterTypes().length == 0)
+            {
+                System.out.println("Running " + m.getName());
+                try
+                {
+                    m.invoke(test);
+                } catch (InvocationTargetException wrapperThrowable)
+                {
+                    final Throwable th = wrapperThrowable.getCause();
+                    boolean exceptionFound = false;
+                    for (Class<?> expectedExClazz : testAnnotation.expectedExceptions())
+                    {
+                        if (expectedExClazz == th.getClass())
+                        {
+                            exceptionFound = true;
+                            break;
+                        }
+                    }
+                    if (exceptionFound == false)
+                    {
+                        throw th;
+                    }
+                }
+            }
+        }
+        System.out.println("Tests OK!");
+    }
+
+}
diff --git a/sourceTest/java/ch/systemsx/cisd/base/io/ByteBufferRandomAccessFileTests.java b/sourceTest/java/ch/systemsx/cisd/base/io/ByteBufferRandomAccessFileTests.java
new file mode 100644
index 0000000..0987c34
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/io/ByteBufferRandomAccessFileTests.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.io;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.base.BuildAndEnvironmentInfo;
+
+/**
+ * Test cases for {@link RandomAccessFileImpl}.
+ *
+ * @author Bernd Rinn
+ */
+public class ByteBufferRandomAccessFileTests extends IRandomAccessFileTests
+{
+
+    @Override
+    protected IRandomAccessFile createRandomAccessFile(String name)
+    {
+        return new ByteBufferRandomAccessFile(4096);
+    }
+
+    @Override
+    protected IRandomAccessFile createRandomAccessFile(String name, byte[] content)
+    {
+        return new ByteBufferRandomAccessFile(content);
+    }
+
+    public static void main(String[] args) throws Throwable
+    {
+        System.out.println(BuildAndEnvironmentInfo.INSTANCE);
+        System.out.println("Test class: " + ByteBufferRandomAccessFileTests.class.getSimpleName());
+        System.out.println();
+        final ByteBufferRandomAccessFileTests test = new ByteBufferRandomAccessFileTests();
+        try
+        {
+            for (Method m : ByteBufferRandomAccessFileTests.class.getMethods())
+            {
+                final Test testAnnotation = m.getAnnotation(Test.class);
+                if (testAnnotation == null)
+                {
+                    continue;
+                }
+                if (m.getParameterTypes().length == 0)
+                {
+                    System.out.println("Running " + m.getName());
+                    test.setUp();
+                    try
+                    {
+                        m.invoke(test);
+                    } catch (InvocationTargetException wrapperThrowable)
+                    {
+                        final Throwable th = wrapperThrowable.getCause();
+                        boolean exceptionFound = false;
+                        for (Class<?> expectedExClazz : testAnnotation.expectedExceptions())
+                        {
+                            if (expectedExClazz == th.getClass())
+                            {
+                                exceptionFound = true;
+                                break;
+                            }
+                        }
+                        if (exceptionFound == false)
+                        {
+                            throw th;
+                        }
+                    }
+                }
+            }
+            System.out.println("Tests OK!");
+        } finally
+        {
+            test.afterClass();
+        }
+    }
+
+}
diff --git a/sourceTest/java/ch/systemsx/cisd/base/io/IRandomAccessFileTests.java b/sourceTest/java/ch/systemsx/cisd/base/io/IRandomAccessFileTests.java
new file mode 100644
index 0000000..57ddec1
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/io/IRandomAccessFileTests.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.io;
+
+import java.io.IOException;
+import java.nio.ByteOrder;
+
+import org.apache.commons.io.IOUtils;
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.base.convert.NativeData;
+import ch.systemsx.cisd.base.tests.AbstractFileSystemTestCase;
+
+/**
+ * Test cases for {@link IRandomAccessFile} implementations.
+ * 
+ * @author Bernd Rinn
+ */
+public abstract class IRandomAccessFileTests extends AbstractFileSystemTestCase
+{
+
+    abstract protected IRandomAccessFile createRandomAccessFile(String name);
+
+    abstract protected IRandomAccessFile createRandomAccessFile(String name, byte[] content);
+
+    @Test
+    public void testSkip()
+    {
+        final IRandomAccessFile raf = createRandomAccessFile("testSkip");
+        final byte[] b = new byte[4096];
+        for (int i = 0; i < b.length; ++i)
+        {
+            b[i] = (byte) i;
+        }
+        raf.write(b);
+        raf.seek(0);
+        assertEquals(509, raf.skip(509));
+        assertEquals(509, raf.getFilePointer());
+        assertEquals(-3, raf.readByte());
+        assertEquals(4096 - 509 - 1, raf.skip(4096));
+        assertEquals(4096, raf.getFilePointer());
+        raf.close();
+    }
+
+    @Test
+    public void testLongByteOrder()
+    {
+        final IRandomAccessFile raf = createRandomAccessFile("testLongByteOrder");
+        raf.writeLong(1);
+        final byte[] buf = new byte[8];
+        raf.seek(0);
+        raf.read(buf);
+        // Default is big endian
+        assertEquals(0, buf[0]);
+        assertEquals(1, buf[7]);
+
+        raf.seek(0);
+        raf.setByteOrder(ByteOrder.LITTLE_ENDIAN);
+        raf.writeLong(1);
+        raf.seek(0);
+        raf.read(buf);
+        assertEquals(1, buf[0]);
+        assertEquals(0, buf[7]);
+        raf.close();
+    }
+
+    @Test
+    public void testMark()
+    {
+        final IRandomAccessFile raf = createRandomAccessFile("testMark");
+        final byte[] buf = new byte[128];
+        raf.write(buf);
+        raf.seek(0);
+        assertTrue(raf.markSupported());
+        raf.mark(0);
+        raf.read();
+        assertEquals(1, raf.getFilePointer());
+        raf.reset();
+        assertEquals(0, raf.getFilePointer());
+        raf.read();
+        raf.read();
+        raf.read();
+        raf.mark(0);
+        raf.read();
+        raf.read();
+        raf.read();
+        raf.reset();
+        assertEquals(3, raf.getFilePointer());
+        raf.close();
+    }
+
+    @Test
+    public void testWriteReadByte()
+    {
+        final IRandomAccessFile raf = createRandomAccessFile("testWriteReadByte");
+        raf.write(254);
+        raf.seek(0);
+        assertEquals(-2, raf.readByte());
+        raf.seek(0);
+        assertEquals(254, raf.read());
+        raf.seek(0);
+        assertEquals(254, raf.readUnsignedByte());
+        raf.close();
+    }
+
+    @Test
+    public void testWriteReadShort()
+    {
+        final IRandomAccessFile raf = createRandomAccessFile("testWriteReadShort");
+        raf.writeShort(65534);
+        raf.seek(0);
+        assertEquals(-2, raf.readShort());
+        raf.seek(0);
+        assertEquals(65534, raf.readUnsignedShort());
+        raf.close();
+    }
+
+    @Test
+    public void testAvailable()
+    {
+        final IRandomAccessFile raf = createRandomAccessFile("testAvailable");
+        assertEquals(0, raf.available());
+        raf.writeDouble(5.5);
+        raf.seek(0);
+        assertEquals(8, raf.available());
+        raf.close();
+    }
+
+    @Test
+    public void testWriteReadStringBytes()
+    {
+        final String s = "teststring";
+        final IRandomAccessFile raf = createRandomAccessFile("testWriteReadStringBytes");
+        raf.writeBytes(s);
+        raf.seek(0);
+        assertEquals(s.length(), raf.available());
+        final byte[] buf = new byte[raf.available()];
+        raf.read(buf);
+        assertEquals(s, new String(buf));
+        raf.close();
+    }
+
+    @Test
+    public void testWriteReadStringChars()
+    {
+        final String s = "teststring";
+        final IRandomAccessFile raf = createRandomAccessFile("testWriteReadStringChars");
+        raf.writeChars(s);
+        raf.seek(0);
+        assertEquals(2 * s.length(), raf.available());
+        final byte[] buf = new byte[raf.available()];
+        raf.read(buf);
+        assertEquals(
+                s,
+                new String(NativeData.byteToChar(buf,
+                        ch.systemsx.cisd.base.convert.NativeData.ByteOrder.BIG_ENDIAN)));
+        raf.close();
+    }
+
+    @Test
+    public void testReadLine() throws IOException
+    {
+        final byte[] bytes = "hello world".getBytes();
+        final IRandomAccessFile raf = createRandomAccessFile("testWriteReadStringChars", bytes);
+        final AdapterIInputStreamToInputStream is = new AdapterIInputStreamToInputStream(raf);
+
+        assertEquals("[hello world]", IOUtils.readLines(is).toString());
+        raf.close();
+    }
+
+    @Test
+    public void testToByteArray() throws IOException
+    {
+        final byte[] bytes = "hello world".getBytes();
+        final IRandomAccessFile raf = createRandomAccessFile("testWriteReadStringChars", bytes);
+        final AdapterIInputStreamToInputStream is = new AdapterIInputStreamToInputStream(raf);
+
+        assertEquals(bytes, IOUtils.toByteArray(is));
+        raf.close();
+    }
+
+}
diff --git a/sourceTest/java/ch/systemsx/cisd/base/io/RandomAccessFileImplTests.java b/sourceTest/java/ch/systemsx/cisd/base/io/RandomAccessFileImplTests.java
new file mode 100644
index 0000000..2bc200b
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/io/RandomAccessFileImplTests.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.io;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.base.BuildAndEnvironmentInfo;
+
+/**
+ * Test cases for {@link RandomAccessFileImpl}.
+ *
+ * @author Bernd Rinn
+ */
+public class RandomAccessFileImplTests extends IRandomAccessFileTests
+{
+
+    @Override
+    protected IRandomAccessFile createRandomAccessFile(String name)
+    {
+        return new RandomAccessFileImpl(create(name), "rw");
+    }
+
+    @Override
+    protected IRandomAccessFile createRandomAccessFile(String name, byte[] content)
+    {
+        final IRandomAccessFile f = new RandomAccessFileImpl(create(name), "rw");
+        f.write(content);
+        f.seek(0L);
+        return f;
+    }
+
+    public static void main(String[] args) throws Throwable
+    {
+        System.out.println(BuildAndEnvironmentInfo.INSTANCE);
+        System.out.println("Test class: " + RandomAccessFileImplTests.class.getSimpleName());
+        System.out.println();
+        final RandomAccessFileImplTests test = new RandomAccessFileImplTests();
+        try
+        {
+            for (Method m : RandomAccessFileImplTests.class.getMethods())
+            {
+                final Test testAnnotation = m.getAnnotation(Test.class);
+                if (testAnnotation == null)
+                {
+                    continue;
+                }
+                if (m.getParameterTypes().length == 0)
+                {
+                    System.out.println("Running " + m.getName());
+                    test.setUp();
+                    try
+                    {
+                        m.invoke(test);
+                    } catch (InvocationTargetException wrapperThrowable)
+                    {
+                        final Throwable th = wrapperThrowable.getCause();
+                        boolean exceptionFound = false;
+                        for (Class<?> expectedExClazz : testAnnotation.expectedExceptions())
+                        {
+                            if (expectedExClazz == th.getClass())
+                            {
+                                exceptionFound = true;
+                                break;
+                            }
+                        }
+                        if (exceptionFound == false)
+                        {
+                            throw th;
+                        }
+                    }
+                }
+            }
+            System.out.println("Tests OK!");
+        } finally
+        {
+            test.afterClass();
+        }
+    }
+
+}
diff --git a/sourceTest/java/ch/systemsx/cisd/base/mdarray/MDArrayTests.java b/sourceTest/java/ch/systemsx/cisd/base/mdarray/MDArrayTests.java
new file mode 100644
index 0000000..38a9182
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/mdarray/MDArrayTests.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.mdarray;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertTrue;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.base.BuildAndEnvironmentInfo;
+
+/**
+ * Test cases for {@link MDAbstractArray}.
+ * 
+ * @author Bernd Rinn
+ */
+public class MDArrayTests
+{
+    @Test
+    public void testGetLength()
+    {
+        assertEquals(0, MDAbstractArray.getLength(new int[]
+            { 0 }, 0));
+        assertEquals(1, MDAbstractArray.getLength(new int[]
+            { 1 }, 0));
+        assertEquals(2, MDAbstractArray.getLength(new int[]
+            { 1 }, 2));
+        assertEquals(15, MDAbstractArray.getLength(new int[]
+            { 5, 3 }, 0));
+        assertEquals(21, MDAbstractArray.getLength(new int[]
+            { 5, 3 }, 7));
+        assertEquals(15, MDAbstractArray.getLength(new int[]
+            { 5, 3 }, 3));
+        assertEquals(1, MDAbstractArray.getLength(new int[]
+            { 1, 1, 1 }, 0));
+        assertEquals(3, MDAbstractArray.getLength(new int[]
+            { 1, 1, 1 }, 3));
+        assertEquals(8, MDAbstractArray.getLength(new int[]
+            { 2, 2, 2 }, 0));
+        assertEquals(20, MDAbstractArray.getLength(new int[]
+            { 2, 2, 2 }, 5));
+        assertEquals(2, MDAbstractArray.getLength(new int[]
+            { 1, 1, 2 }, 0));
+        assertEquals(2, MDAbstractArray.getLength(new int[]
+            { 1, 2, 1 }, 0));
+        assertEquals(2, MDAbstractArray.getLength(new int[]
+            { 2, 1, 1 }, 0));
+        assertEquals(50, MDAbstractArray.getLength(new int[]
+            { 10, 1, 5 }, 0));
+        assertEquals(50, MDAbstractArray.getLength(new long[]
+            { 10, 1, 5 }, 0));
+    }
+
+    @Test
+    public void testToInt()
+    {
+        assertTrue(Arrays.equals(new int[]
+            { 1, 2, 3 }, MDAbstractArray.toInt(new long[]
+            { 1, 2, 3 })));
+        assertTrue(Arrays.equals(new int[] {}, MDAbstractArray.toInt(new long[] {})));
+    }
+
+    @Test
+    public void testComputeIndex()
+    {
+        MDArray<Object> array;
+        array = new MDArray<Object>(Object.class, new int[]
+            { 33 });
+        assertEquals(17, array.computeIndex(new int[]
+            { 17 }));
+        assertTrue(Arrays.toString(array.computeReverseIndex(17)), Arrays.equals(new int[]
+            { 17 }, array.computeReverseIndex(17)));
+        array = new MDArray<Object>(Object.class, new int[]
+            { 100, 10 });
+        assertEquals(10 * 42 + 8, array.computeIndex(new int[]
+            { 42, 8 }));
+        assertTrue(Arrays.toString(array.computeReverseIndex(10 * 42 + 8)),
+                Arrays.equals(new int[]
+                    { 42, 8 }, array.computeReverseIndex(10 * 42 + 8)));
+        array = new MDArray<Object>(Object.class, new int[]
+            { 2, 7, 3 });
+        assertEquals(3 * 7 * 1 + 3 * 3 + 2, array.computeIndex(new int[]
+            { 1, 3, 2 }));
+        assertTrue(Arrays.toString(array.computeReverseIndex(3 * 7 * 1 + 3 * 3 + 2)),
+                Arrays.equals(new int[]
+                    { 1, 3, 2 }, array.computeReverseIndex(3 * 7 * 1 + 3 * 3 + 2)));
+    }
+
+    @Test
+    public void testComputeIndex2D()
+    {
+        MDArray<Object> array;
+        array = new MDArray<Object>(Object.class, new int[]
+            { 100, 10 });
+        assertEquals(array.computeIndex(new int[]
+            { 5, 8, }), array.computeIndex(5, 8));
+        assertEquals(array.computeIndex(new int[]
+            { 9, 1, }), array.computeIndex(9, 1));
+        array = new MDArray<Object>(Object.class, new int[]
+            { 101, 11 });
+        assertEquals(array.computeIndex(new int[]
+            { 5, 8, }), array.computeIndex(5, 8));
+        assertEquals(array.computeIndex(new int[]
+            { 9, 1, }), array.computeIndex(9, 1));
+    }
+
+    @Test
+    public void testComputeIndex3()
+    {
+        MDArray<Object> array;
+        array = new MDArray<Object>(Object.class, new int[]
+            { 100, 10, 17 });
+        assertEquals(array.computeIndex(new int[]
+            { 5, 8, 16 }), array.computeIndex(5, 8, 16));
+        assertEquals(array.computeIndex(new int[]
+            { 9, 1, 5 }), array.computeIndex(9, 1, 5));
+        array = new MDArray<Object>(Object.class, new int[]
+            { 101, 11, 3 });
+        assertEquals(array.computeIndex(new int[]
+            { 5, 8, 0 }), array.computeIndex(5, 8, 0));
+        assertEquals(array.computeIndex(new int[]
+            { 9, 1, 2 }), array.computeIndex(9, 1, 2));
+    }
+
+    @Test
+    public void testEmptyMatrix()
+    {
+        final MDFloatArray arr = new MDFloatArray(new float[0][0]);
+        assertEquals(0, arr.dimensions()[0]);
+        assertEquals(0, arr.dimensions()[1]);
+    }
+
+    @Test
+    public void testChangeHyperRowCountIntArray()
+    {
+        final MDIntArray arr = new MDIntArray(new int[]
+            { 2, 2 }, 3);
+        assertEquals(2, arr.dimensions[0]);
+        assertEquals(2, arr.dimensions[1]);
+        arr.set(1, 0, 0);
+        arr.set(2, 0, 1);
+        arr.set(3, 1, 0);
+        arr.set(4, 1, 1);
+
+        final MDIntArray arr2 = new MDIntArray(arr.getCopyAsFlatArray(), arr.dimensions());
+        assertTrue(arr2.equals(arr));
+
+        arr.incNumberOfHyperRows(1);
+        assertEquals(3, arr.dimensions[0]);
+        assertEquals(1, arr.get(0, 0));
+        assertEquals(2, arr.get(0, 1));
+        assertEquals(3, arr.get(1, 0));
+        assertEquals(4, arr.get(1, 1));
+        arr.set(5, 2, 0);
+        arr.set(6, 2, 1);
+        arr.incNumberOfHyperRows(2);
+        assertEquals(5, arr.dimensions[0]);
+        assertEquals(1, arr.get(0, 0));
+        assertEquals(2, arr.get(0, 1));
+        assertEquals(3, arr.get(1, 0));
+        assertEquals(4, arr.get(1, 1));
+        assertEquals(5, arr.get(2, 0));
+        assertEquals(6, arr.get(2, 1));
+        arr.set(7, 3, 0);
+        arr.set(8, 3, 1);
+        arr.decNumberOfHyperRows(1);
+        assertEquals(4, arr.dimensions[0]);
+        assertEquals(1, arr.get(0, 0));
+        assertEquals(2, arr.get(0, 1));
+        assertEquals(3, arr.get(1, 0));
+        assertEquals(4, arr.get(1, 1));
+        assertEquals(5, arr.get(2, 0));
+        assertEquals(6, arr.get(2, 1));
+        assertEquals(7, arr.get(3, 0));
+        assertEquals(8, arr.get(3, 1));
+    }
+
+    @Test
+    public void testChangeHyperRowCountIntArrayFromZero()
+    {
+        final MDIntArray arr = new MDIntArray(new int[]
+            { 0 });
+        assertEquals(0, arr.size(0));
+        arr.incNumberOfHyperRows(1);
+        assertEquals(1, arr.size(0));
+        arr.set(17, 0);
+        assertEquals(17, arr.get(0));
+        arr.incNumberOfHyperRows(1);
+        arr.incNumberOfHyperRows(1);
+        assertEquals(3, arr.size());
+    }
+
+    @Test
+    public void testChangeHyperRowCountTArray()
+    {
+        final MDArray<Integer> arr = new MDArray<Integer>(Integer.class, new int[]
+            { 2, 2 }, 3);
+        assertEquals(2, arr.dimensions[0]);
+        assertEquals(2, arr.dimensions[1]);
+        arr.set(1, 0, 0);
+        arr.set(2, 0, 1);
+        arr.set(3, 1, 0);
+        arr.set(4, 1, 1);
+        arr.incNumberOfHyperRows(1);
+        assertEquals(3, arr.dimensions[0]);
+        assertEquals(1, (int) arr.get(0, 0));
+        assertEquals(2, (int) arr.get(0, 1));
+        assertEquals(3, (int) arr.get(1, 0));
+        assertEquals(4, (int) arr.get(1, 1));
+        arr.set(5, 2, 0);
+        arr.set(6, 2, 1);
+        arr.incNumberOfHyperRows(2);
+        assertEquals(5, arr.dimensions[0]);
+        assertEquals(1, (int) arr.get(0, 0));
+        assertEquals(2, (int) arr.get(0, 1));
+        assertEquals(3, (int) arr.get(1, 0));
+        assertEquals(4, (int) arr.get(1, 1));
+        assertEquals(5, (int) arr.get(2, 0));
+        assertEquals(6, (int) arr.get(2, 1));
+        arr.set(7, 3, 0);
+        arr.set(8, 3, 1);
+        arr.decNumberOfHyperRows(1);
+        assertEquals(4, arr.dimensions[0]);
+        assertEquals(1, (int) arr.get(0, 0));
+        assertEquals(2, (int) arr.get(0, 1));
+        assertEquals(3, (int) arr.get(1, 0));
+        assertEquals(4, (int) arr.get(1, 1));
+        assertEquals(5, (int) arr.get(2, 0));
+        assertEquals(6, (int) arr.get(2, 1));
+        assertEquals(7, (int) arr.get(3, 0));
+        assertEquals(8, (int) arr.get(3, 1));
+    }
+
+    @Test
+    public void testMDIntArrayIterator()
+    {
+        final int[] linArray = new int[120];
+        for (int i = 0; i < linArray.length; ++i)
+        {
+            linArray[i] = i;
+        }
+        final MDIntArray array = new MDIntArray(linArray, new int[]
+            { 2, 3, 4, 5 });
+        for (MDIntArray.ArrayEntry e : array)
+        {
+            assertEquals(e.getLinearIndex(), e.getValue().intValue());
+            assertEquals(e.getLinearIndex(), array.computeIndex(e.getIndex()));
+        }
+    }
+
+    @Test
+    public void testMDFloatArrayMatrix()
+    {
+        final float[][] matrix1 = new float[][]
+            {
+                { 1f, 2f, 3f, 4f },
+                { 5f, 6f, 7f, 8f },
+                { 9f, 10f, 11f, 12f } };
+        final MDFloatArray array = new MDFloatArray(matrix1);
+        assertEquals(2, array.rank());
+        assertEquals(12, array.size());
+        assertEquals(3, array.size(0));
+        assertEquals(4, array.size(1));
+        assertEquals(7f, array.get(1, 2));
+        final float[][] matrix2 = array.toMatrix();
+        assertEquals(matrix1.length, matrix2.length);
+        for (int i = 0; i < matrix1.length; ++i)
+        {
+            assertTrue(Arrays.equals(matrix1[i], matrix2[i]));
+        }
+    }
+
+    public static void main(String[] args) throws Throwable
+    {
+        System.out.println(BuildAndEnvironmentInfo.INSTANCE);
+        System.out.println("Test class: " + MDArrayTests.class.getSimpleName());
+        System.out.println();
+        final MDArrayTests test = new MDArrayTests();
+        for (Method m : MDArrayTests.class.getMethods())
+        {
+            final Test testAnnotation = m.getAnnotation(Test.class);
+            if (testAnnotation == null)
+            {
+                continue;
+            }
+            if (m.getParameterTypes().length == 0)
+            {
+                System.out.println("Running " + m.getName());
+                try
+                {
+                    m.invoke(test);
+                } catch (InvocationTargetException wrapperThrowable)
+                {
+                    final Throwable th = wrapperThrowable.getCause();
+                    boolean exceptionFound = false;
+                    for (Class<?> expectedExClazz : testAnnotation.expectedExceptions())
+                    {
+                        if (expectedExClazz == th.getClass())
+                        {
+                            exceptionFound = true;
+                            break;
+                        }
+                    }
+                    if (exceptionFound == false)
+                    {
+                        throw th;
+                    }
+                }
+            }
+        }
+        System.out.println("Tests OK!");
+    }
+
+}
diff --git a/sourceTest/java/ch/systemsx/cisd/base/namedthread/NamingThreadPoolExecutorTest.java b/sourceTest/java/ch/systemsx/cisd/base/namedthread/NamingThreadPoolExecutorTest.java
new file mode 100644
index 0000000..582a02a
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/namedthread/NamingThreadPoolExecutorTest.java
@@ -0,0 +1,481 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.namedthread;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.AssertJUnit.fail;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.base.BuildAndEnvironmentInfo;
+import ch.systemsx.cisd.base.tests.Retry10;
+
+/**
+ * Test cases for the {@link NamingThreadPoolExecutor}.
+ * 
+ * @author Bernd Rinn
+ */
+public class NamingThreadPoolExecutorTest
+{
+
+    private final static String name = "This is the pool name";
+
+    @Test
+    public void testNamedPool() throws Throwable
+    {
+        final ThreadPoolExecutor eservice =
+                new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(2).daemonize();
+        assertEquals(1, eservice.getCorePoolSize());
+        assertEquals(2, eservice.getMaximumPoolSize());
+        final Future<?> future = eservice.submit(new Runnable()
+            {
+                @Override
+                public void run()
+                {
+                    assertEquals(name + "-T1", Thread.currentThread().getName());
+                }
+            });
+        try
+        {
+            future.get(200L, TimeUnit.MILLISECONDS);
+        } catch (ExecutionException ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    @Test
+    public void testDaemonize()
+    {
+        final NamingThreadPoolExecutor eservice =
+                new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(2);
+        assertFalse(eservice.getThreadFactory().isCreateDaemonThreads());
+        eservice.daemonize();
+        assertTrue(eservice.getThreadFactory().isCreateDaemonThreads());
+    }
+
+    @Test
+    public void testSetNamedThreadFactory()
+    {
+        final NamingThreadPoolExecutor eservice =
+                new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(2).daemonize();
+        final NamingThreadFactory factory = new NamingThreadFactory("name");
+        eservice.setThreadFactory(factory);
+        assertEquals(factory, eservice.getThreadFactory());
+    }
+
+    @Test
+    public void testSetThreadFactory()
+    {
+        final ThreadPoolExecutor eservice =
+                new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(2).daemonize();
+        final ThreadFactory factory = new NamingThreadFactory("name");
+        eservice.setThreadFactory(factory);
+        assertEquals(factory, eservice.getThreadFactory());
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testSetThreadFactoryFailed()
+    {
+        final ThreadPoolExecutor eservice =
+                new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(2).daemonize();
+        final ThreadFactory factory = new ThreadFactory()
+            {
+                @Override
+                public Thread newThread(Runnable r)
+                {
+                    return null; // Doesn't matter, never used
+                }
+            };
+        // It needs to be NamingThreadFactory, thus it will throw an IllegalArgumentException.
+        eservice.setThreadFactory(factory);
+    }
+
+    @Test(groups = "slow")
+    public void testThreadDefaultNames() throws Throwable
+    {
+        final int max = 10;
+        final ThreadPoolExecutor eservice =
+                new NamingThreadPoolExecutor(name).corePoolSize(max).maximumPoolSize(max).daemonize();
+        assertEquals(max, eservice.getCorePoolSize());
+        assertEquals(max, eservice.getMaximumPoolSize());
+        final Set<String> expectedThreadNameSet = new HashSet<String>();
+        for (int i = 1; i <= max; ++i)
+        {
+            expectedThreadNameSet.add(name + "-T" + i);
+        }
+        final Set<String> threadNameSet = Collections.synchronizedSet(new HashSet<String>());
+        final Set<Future<?>> futureSet = new HashSet<Future<?>>();
+        for (int i = 0; i < max; ++i)
+        {
+            futureSet.add(eservice.submit(new Runnable()
+                {
+                    @Override
+                    public void run()
+                    {
+                        threadNameSet.add(Thread.currentThread().getName());
+                        try
+                        {
+                            Thread.sleep(20L);
+                        } catch (InterruptedException ex)
+                        {
+                            fail("We got interrupted.");
+                        }
+                    }
+                }));
+        }
+        for (Future<?> future : futureSet)
+        {
+            try
+            {
+                future.get(400L, TimeUnit.MILLISECONDS);
+            } catch (ExecutionException ex)
+            {
+                throw ex.getCause();
+            }
+        }
+        assertEquals(expectedThreadNameSet, threadNameSet);
+    }
+
+    @Test(groups = "slow")
+    public void testSubmitNamedRunnable() throws Throwable
+    {
+        final String runnableName = "This is the special runnable name";
+        final ThreadPoolExecutor eservice =
+                new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(1).daemonize();
+        assertEquals(1, eservice.getCorePoolSize());
+        assertEquals(1, eservice.getMaximumPoolSize());
+        final Future<?> future = eservice.submit(new NamedRunnable()
+            {
+                @Override
+                public void run()
+                {
+                    assertEquals(name + "-T1::" + runnableName, Thread.currentThread().getName());
+                }
+
+                @Override
+                public String getRunnableName()
+                {
+                    return runnableName;
+                }
+            });
+        try
+        {
+            future.get(200L, TimeUnit.MILLISECONDS);
+        } catch (ExecutionException ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    @Test(groups = "slow")
+    public void testExecuteNamedRunnable() throws Throwable
+    {
+        final String runnableName = "This is the special runnable name";
+        final ThreadPoolExecutor eservice =
+                new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(1).daemonize();
+        assertEquals(1, eservice.getCorePoolSize());
+        assertEquals(1, eservice.getMaximumPoolSize());
+        final Semaphore sem = new Semaphore(0);
+        eservice.execute(new NamedRunnable()
+            {
+                @Override
+                public void run()
+                {
+                    assertEquals(name + "-T1::" + runnableName, Thread.currentThread().getName());
+                    sem.release();
+                }
+
+                @Override
+                public String getRunnableName()
+                {
+                    return runnableName;
+                }
+            });
+        assertTrue(sem.tryAcquire(200L, TimeUnit.MILLISECONDS));
+    }
+
+    interface MyRunnable extends Runnable, IRunnableNameProvider
+    {
+    }
+    
+    @Test(groups = "slow")
+    public void testExecuteNamedMyRunnable() throws Throwable
+    {
+        final String runnableName = "This is the special runnable name";
+        final ThreadPoolExecutor eservice =
+                new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(1).daemonize();
+        assertEquals(1, eservice.getCorePoolSize());
+        assertEquals(1, eservice.getMaximumPoolSize());
+        final Semaphore sem = new Semaphore(0);
+        eservice.execute(new MyRunnable()
+            {
+                @Override
+                public void run()
+                {
+                    assertEquals(name + "-T1::" + runnableName, Thread.currentThread().getName());
+                    sem.release();
+                }
+
+                @Override
+                public String getRunnableName()
+                {
+                    return runnableName;
+                }
+            });
+        assertTrue(sem.tryAcquire(200L, TimeUnit.MILLISECONDS));
+    }
+
+    @Test(groups = "slow")
+    public void testSubmitNamedCallable() throws Throwable
+    {
+        final String callableName = "This is the special callable name";
+        final ThreadPoolExecutor eservice =
+                new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(1).daemonize();
+        assertEquals(1, eservice.getCorePoolSize());
+        assertEquals(1, eservice.getMaximumPoolSize());
+        final Future<?> future = eservice.submit(new NamedCallable<Object>()
+            {
+                @Override
+                public Object call() throws Exception
+                {
+                    assertEquals(name + "-T1::" + callableName, Thread.currentThread().getName());
+                    return null;
+                }
+
+                @Override
+                public String getCallableName()
+                {
+                    return callableName;
+                }
+            });
+        try
+        {
+            future.get(200L, TimeUnit.MILLISECONDS);
+        } catch (ExecutionException ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    interface MyCallable extends Callable<Object>, ICallableNameProvider
+    {
+    }
+    
+    @Test(groups = "slow")
+    public void testSubmitMyNamedCallable() throws Throwable
+    {
+        final String callableName = "This is the special callable name";
+        final ThreadPoolExecutor eservice =
+                new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(1).daemonize();
+        assertEquals(1, eservice.getCorePoolSize());
+        assertEquals(1, eservice.getMaximumPoolSize());
+        final Future<?> future = eservice.submit(new MyCallable()
+            {
+                @Override
+                public Object call() throws Exception
+                {
+                    assertEquals(name + "-T1::" + callableName, Thread.currentThread().getName());
+                    return null;
+                }
+
+                @Override
+                public String getCallableName()
+                {
+                    return callableName;
+                }
+            });
+        try
+        {
+            future.get(200L, TimeUnit.MILLISECONDS);
+        } catch (ExecutionException ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    @Test(groups = "slow", retryAnalyzer = Retry10.class)
+    public void testSubmitNamedCallables() throws Throwable
+    {
+        final String callableName1 = "This is the first special callable name";
+        final ThreadPoolExecutor eservice =
+                new NamingThreadPoolExecutor(name).corePoolSize(1).maximumPoolSize(1).daemonize();
+        assertEquals(1, eservice.getCorePoolSize());
+        assertEquals(1, eservice.getMaximumPoolSize());
+        final Future<?> future1 = eservice.submit(new NamedCallable<Object>()
+            {
+                @Override
+                public Object call() throws Exception
+                {
+                    assertEquals(name + "-T1::" + callableName1, Thread.currentThread().getName());
+                    return null;
+                }
+
+                @Override
+                public String getCallableName()
+                {
+                    return callableName1;
+                }
+            });
+        try
+        {
+            future1.get(200L, TimeUnit.MILLISECONDS);
+        } catch (ExecutionException ex)
+        {
+            throw ex.getCause();
+        }
+        // On Linux x64, Java 1.6 we get a RejectedExecutionException if we continue immediately.
+        Thread.sleep(200L);
+        final String callableName2 = "This is the second special callable name";
+        final Future<?> future2 = eservice.submit(new NamedCallable<Object>()
+            {
+                @Override
+                public Object call() throws Exception
+                {
+                    assertEquals(name + "-T1::" + callableName2, Thread.currentThread().getName());
+                    return null;
+                }
+
+                @Override
+                public String getCallableName()
+                {
+                    return callableName2;
+                }
+            });
+        try
+        {
+            future2.get(200L, TimeUnit.MILLISECONDS);
+        } catch (ExecutionException ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+
+    @Test(groups = "slow", retryAnalyzer = Retry10.class)
+    public void testSubmitQueuedNamedCallables() throws Throwable
+    {
+        final String callableName1 = "This is the first special callable name";
+        final ThreadPoolExecutor eservice =
+                new NamingThreadPoolExecutor(name, 1).corePoolSize(1).maximumPoolSize(1).daemonize();
+        assertEquals(1, eservice.getCorePoolSize());
+        assertEquals(1, eservice.getMaximumPoolSize());
+        final Future<?> future1 = eservice.submit(new NamedCallable<Object>()
+            {
+                @Override
+                public Object call() throws Exception
+                {
+                    assertEquals(name + "-T1::" + callableName1, Thread.currentThread().getName());
+                    Thread.sleep(100L);
+                    return null;
+                }
+
+                @Override
+                public String getCallableName()
+                {
+                    return callableName1;
+                }
+            });
+        final Future<?> future2 = eservice.submit(new NamedCallable<Object>()
+                {
+                    @Override
+                    public Object call() throws Exception
+                    {
+                        assertEquals(name + "-T1::" + callableName1, Thread.currentThread().getName());
+                        Thread.sleep(100L);
+                        return null;
+                    }
+
+                    @Override
+                    public String getCallableName()
+                    {
+                        return callableName1;
+                    }
+                });
+        try
+        {
+            future1.get(200L, TimeUnit.MILLISECONDS);
+        } catch (ExecutionException ex)
+        {
+            throw ex.getCause();
+        }
+        try
+        {
+            future2.get(200L, TimeUnit.MILLISECONDS);
+        } catch (ExecutionException ex)
+        {
+            throw ex.getCause();
+        }
+    }
+
+    public static void main(String[] args) throws Throwable
+    {
+        System.out.println(BuildAndEnvironmentInfo.INSTANCE);
+        System.out.println("Test class: " + NamingThreadPoolExecutorTest.class.getSimpleName());
+        System.out.println();
+        final NamingThreadPoolExecutorTest test = new NamingThreadPoolExecutorTest();
+        for (Method m : NamingThreadPoolExecutorTest.class.getMethods())
+        {
+            final Test testAnnotation = m.getAnnotation(Test.class);
+            if (testAnnotation == null)
+            {
+                continue;
+            }
+            if (m.getParameterTypes().length == 0)
+            {
+                System.out.println("Running " + m.getName());
+                try
+                {
+                    m.invoke(test);
+                } catch (InvocationTargetException wrapperThrowable)
+                {
+                    final Throwable th = wrapperThrowable.getCause();
+                    boolean exceptionFound = false;
+                    for (Class<?> expectedExClazz : testAnnotation.expectedExceptions())
+                    {
+                        if (expectedExClazz == th.getClass())
+                        {
+                            exceptionFound = true;
+                            break;
+                        }
+                    }
+                    if (exceptionFound == false)
+                    {
+                        throw th;
+                    }
+                }
+            }
+        }
+        System.out.println("Tests OK!");
+    }
+
+}
diff --git a/sourceTest/java/ch/systemsx/cisd/base/unix/UnixTests.java b/sourceTest/java/ch/systemsx/cisd/base/unix/UnixTests.java
new file mode 100644
index 0000000..3371488
--- /dev/null
+++ b/sourceTest/java/ch/systemsx/cisd/base/unix/UnixTests.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright 2008 ETH Zuerich, CISD
+ *
+ * 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 ch.systemsx.cisd.base.unix;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.commons.io.FileUtils;
+import org.testng.annotations.Test;
+
+import ch.rinn.restrictions.Friend;
+import ch.systemsx.cisd.base.BuildAndEnvironmentInfo;
+import ch.systemsx.cisd.base.tests.AbstractFileSystemTestCase;
+import ch.systemsx.cisd.base.unix.Unix.Group;
+import ch.systemsx.cisd.base.unix.Unix.Password;
+import ch.systemsx.cisd.base.unix.Unix.Stat;
+
+/**
+ * Test cases for the {@link Unix} system calls.
+ * 
+ * @author Bernd Rinn
+ */
+ at Friend(toClasses = Unix.class)
+public class UnixTests extends AbstractFileSystemTestCase
+{
+
+    @Test(groups =
+        { "requires_unix" })
+    public void testGetLinkInfoRegularFile() throws IOException
+    {
+        final short accessMode = (short) 0777;
+        final String content = "someText\n";
+        final File f = new File(workingDirectory, "someFile");
+        FileUtils.writeStringToFile(f, content);
+        Unix.setAccessMode(f.getAbsolutePath(), accessMode);
+        final Stat info = Unix.getLinkInfo(f.getAbsolutePath());
+        Unix.setOwner(f.getAbsolutePath(), info.getUid(), info.getGid());
+        assertEquals(1, info.getNumberOfHardLinks());
+        assertEquals(content.length(), info.getSize());
+        assertEquals(accessMode, info.getPermissions());
+        assertEquals("root", Unix.tryGetUserNameForUid(0));
+        assertEquals(FileLinkType.REGULAR_FILE, info.getLinkType());
+        assertFalse(info.isSymbolicLink());
+        assertEquals(f.lastModified(), 1000 * info.getLastModified());
+    }
+
+    @Test(groups =
+        { "requires_unix" }, expectedExceptions = NullPointerException.class)
+    public void testGetLinkNull() throws IOException
+    {
+        Unix.getLinkInfo(null);
+    }
+
+    @Test(groups =
+        { "requires_unix" })
+    public void testGetLinkInfoDirectory() throws IOException
+    {
+        final File d = new File(workingDirectory, "someDir");
+        d.mkdir();
+        final Stat info = Unix.getLinkInfo(d.getAbsolutePath());
+        assertEquals(2, info.getNumberOfHardLinks());
+        assertEquals(FileLinkType.DIRECTORY, info.getLinkType());
+        assertFalse(info.isSymbolicLink());
+    }
+
+    @Test(groups =
+        { "requires_unix" })
+    public void testGetLinkInfoSymLink() throws IOException
+    {
+        final File f = new File(workingDirectory, "someOtherFile");
+        final String content = "someMoreText\n";
+        FileUtils.writeStringToFile(f, content);
+        final File s = new File(workingDirectory, "someLink");
+        Unix.createSymbolicLink(f.getAbsolutePath(), s.getAbsolutePath());
+        final Stat info = Unix.getLinkInfo(s.getAbsolutePath());
+        assertEquals(1, info.getNumberOfHardLinks());
+        assertEquals(FileLinkType.SYMLINK, info.getLinkType());
+        assertTrue(info.isSymbolicLink());
+        assertEquals(f.getAbsolutePath(), info.tryGetSymbolicLink());
+        assertEquals(f.getAbsolutePath(), Unix.tryReadSymbolicLink(s.getAbsolutePath()));
+        assertNull(Unix.getLinkInfo(s.getAbsolutePath(), false).tryGetSymbolicLink());
+
+        final Stat info2 = Unix.getFileInfo(s.getAbsolutePath());
+        assertEquals(1, info2.getNumberOfHardLinks());
+        assertEquals(content.length(), info2.getSize());
+        assertEquals(FileLinkType.REGULAR_FILE, info2.getLinkType());
+        assertFalse(info2.isSymbolicLink());
+        assertNull(info2.tryGetSymbolicLink());
+    }
+
+    @Test(groups =
+        { "requires_unix" })
+    public void testGetLinkInfoSymLinkDanglingLink() throws IOException
+    {
+        final File s = new File(workingDirectory, "someDanglingLink");
+        Unix.createSymbolicLink("link_to_nowhere", s.getAbsolutePath());
+        final Stat info = Unix.tryGetLinkInfo(s.getAbsolutePath());
+        assertNotNull(info);
+        assertEquals(1, info.getNumberOfHardLinks());
+        assertEquals(FileLinkType.SYMLINK, info.getLinkType());
+        assertTrue(info.isSymbolicLink());
+        final Stat info2 = Unix.tryGetFileInfo(s.getAbsolutePath());
+        assertNull(info2);
+        assertEquals("No such file or directory", Unix.getLastError());
+    }
+
+    @Test(groups =
+        { "requires_unix" })
+    public void testGetLinkInfoNonExistent() throws IOException
+    {
+        final File s = new File(workingDirectory, "nonExistent");
+        final Stat info = Unix.tryGetLinkInfo(s.getAbsolutePath());
+        assertNull(info);
+        assertEquals("No such file or directory", Unix.getLastError());
+        final Stat info2 = Unix.tryGetFileInfo(s.getAbsolutePath());
+        assertNull(info2);
+        assertEquals("No such file or directory", Unix.getLastError());
+    }
+
+    @Test(groups =
+        { "requires_unix" }, expectedExceptions = NullPointerException.class)
+    public void testCreateSymbolicLinkNull() throws IOException
+    {
+        Unix.createSymbolicLink(null, null);
+    }
+
+    @Test(groups =
+        { "requires_unix" }, expectedExceptions = NullPointerException.class)
+    public void testCreateHardLinkNull() throws IOException
+    {
+        Unix.createHardLink(null, null);
+    }
+
+    @Test(groups =
+        { "requires_unix" })
+    public void testGetLinkInfoHardLink() throws IOException
+    {
+        final File f = new File(workingDirectory, "someOtherFile");
+        f.createNewFile();
+        final File s = new File(workingDirectory, "someLink");
+        Unix.createHardLink(f.getAbsolutePath(), s.getAbsolutePath());
+        final Stat info = Unix.getLinkInfo(s.getAbsolutePath());
+        assertEquals(2, info.getNumberOfHardLinks());
+        assertEquals(FileLinkType.REGULAR_FILE, info.getLinkType());
+        assertFalse(info.isSymbolicLink());
+        assertNull(info.tryGetSymbolicLink());
+    }
+
+    @Test(groups =
+        { "requires_unix" })
+    public void testGetUid()
+    {
+        assertTrue(Unix.getUid() > 0);
+    }
+
+    @Test(groups =
+        { "requires_unix" })
+    public void testGetEuid()
+    {
+        assertTrue(Unix.getEuid() > 0);
+        assertEquals(Unix.getUid(), Unix.getEuid());
+    }
+
+    @Test(groups =
+        { "requires_unix" })
+    public void testGetGid()
+    {
+        assertTrue(Unix.getGid() > 0);
+    }
+
+    @Test(groups =
+        { "requires_unix" })
+    public void testGetEgid()
+    {
+        assertTrue(Unix.getEgid() > 0);
+        assertEquals(Unix.getGid(), Unix.getEgid());
+    }
+
+    @Test(groups =
+        { "requires_unix" })
+    public void testGetUidForUserName()
+    {
+        assertEquals(0, Unix.getUidForUserName("root"));
+    }
+
+    @Test(groups =
+        { "requires_unix" }, expectedExceptions = NullPointerException.class)
+    public void testGetUidForUserNameNull() throws IOException
+    {
+        Unix.getUidForUserName(null);
+    }
+
+    @Test(groups =
+        { "requires_unix" })
+    public void testGetGidForGroupName()
+    {
+        final String rootGroup = Unix.tryGetGroupNameForGid(0);
+        assertTrue(rootGroup, "root".equals(rootGroup) || "wheel".equals(rootGroup));
+        assertEquals(0, Unix.getGidForGroupName(rootGroup));
+    }
+
+    @Test(groups =
+        { "requires_unix" }, expectedExceptions = NullPointerException.class)
+    public void testGetGidForGroupNameNull() throws IOException
+    {
+        Unix.getGidForGroupName(null);
+    }
+
+    @Test(groups =
+        { "requires_unix" })
+    public void testTryGetGroupByName()
+    {
+        final String rootGroup = Unix.tryGetGroupNameForGid(0);
+        final Group group = Unix.tryGetGroupByName(rootGroup);
+        assertNotNull(group);
+        assertEquals(rootGroup, group.getGroupName());
+        assertEquals(0, group.getGid());
+        assertNotNull(group.getGroupMembers());
+    }
+
+    @Test(groups =
+        { "requires_unix" }, expectedExceptions = NullPointerException.class)
+    public void testTryGetGroupByNameNull() throws IOException
+    {
+        Unix.tryGetGroupByName(null);
+    }
+
+    @Test(groups =
+        { "requires_unix" })
+    public void testTryGetGroupByGid()
+    {
+        final Group group = Unix.tryGetGroupByGid(0);
+        assertNotNull(group);
+        final String rootGroup = group.getGroupName();
+        assertTrue(rootGroup, "root".equals(rootGroup) || "wheel".equals(rootGroup));
+        assertEquals(0, group.getGid());
+        assertNotNull(group.getGroupMembers());
+    }
+
+    @Test(groups =
+        { "requires_unix" })
+    public void testTryGetUserByName()
+    {
+        final Password user = Unix.tryGetUserByName("root");
+        assertNotNull(user);
+        assertEquals("root", user.getUserName());
+        assertEquals(0, user.getUid());
+        assertEquals(0, user.getGid());
+        assertNotNull(user.getUserFullName());
+        assertNotNull(user.getHomeDirectory());
+        assertNotNull(user.getShell());
+        assertTrue(user.getShell().startsWith("/"));
+    }
+
+    @Test(groups =
+        { "requires_unix" }, expectedExceptions = NullPointerException.class)
+    public void testTryGetUserByNameNull() throws IOException
+    {
+        Unix.tryGetUserByName(null);
+    }
+
+    @Test(groups =
+        { "requires_unix" })
+    public void testTryGetUserByUid()
+    {
+        final Password user = Unix.tryGetUserByUid(0);
+        assertNotNull(user);
+        assertEquals("root", user.getUserName());
+        assertEquals(0, user.getUid());
+        assertEquals(0, user.getGid());
+        assertNotNull(user.getUserFullName());
+        assertNotNull(user.getHomeDirectory());
+        assertNotNull(user.getShell());
+        assertTrue(user.getShell().startsWith("/"));
+    }
+
+    @Test(groups =
+        { "requires_unix" })
+    public void testDetectProcess()
+    {
+        assertTrue(Unix.canDetectProcesses());
+        assertTrue(Unix.isProcessRunningPS(Unix.getPid()));
+    }
+
+    public static void main(String[] args) throws Throwable
+    {
+        System.out.println(BuildAndEnvironmentInfo.INSTANCE);
+        System.out.println("Test class: " + UnixTests.class.getSimpleName());
+        System.out.println();
+        if (Unix.isOperational() == false)
+        {
+            System.err.println("No unix library found.");
+            System.exit(1);
+        }
+        final UnixTests test = new UnixTests();
+        try
+        {
+            for (Method m : UnixTests.class.getMethods())
+            {
+                final Test testAnnotation = m.getAnnotation(Test.class);
+                if (testAnnotation == null)
+                {
+                    continue;
+                }
+                System.out.println("Running " + m.getName());
+                test.setUp();
+                try
+                {
+                    m.invoke(test);
+                } catch (InvocationTargetException wrapperThrowable)
+                {
+                    final Throwable th = wrapperThrowable.getCause();
+                    boolean exceptionFound = false;
+                    for (Class<?> expectedExClazz : testAnnotation.expectedExceptions())
+                    {
+                        if (expectedExClazz == th.getClass())
+                        {
+                            exceptionFound = true;
+                            break;
+                        }
+                    }
+                    if (exceptionFound == false)
+                    {
+                        throw th;
+                    }
+                }
+            }
+            System.out.println("Tests OK!");
+        } finally
+        {
+            test.afterClass();
+        }
+    }
+
+}
diff --git a/sourceTest/java/tests.xml b/sourceTest/java/tests.xml
new file mode 100644
index 0000000..0a6ff5b
--- /dev/null
+++ b/sourceTest/java/tests.xml
@@ -0,0 +1,12 @@
+<suite name="All" verbose="1">
+    <test name="All">
+        <groups>
+            <run>
+                <exclude name="broken" />
+            </run>
+        </groups>
+        <packages>
+            <package name="ch.systemsx.cisd.base.*" />
+        </packages>
+    </test>
+</suite>
diff --git a/tag.sh b/tag.sh
new file mode 100755
index 0000000..a4f1cce
--- /dev/null
+++ b/tag.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+if [ `dirname $0` != "." ]
+then
+	echo "Please run from the same directory than the script source file is in"
+	exit 1
+fi
+
+if [ $# -ne 2 ]
+then
+  echo "Usage: ./tag.sh [branch] [tag]"
+  echo ""
+  echo "Example: ./tag.sh release/13.04.x 13.04.1"
+  exit 1
+fi
+
+svn info svn+ssh://svncisd.ethz.ch/repos/cisd/base/branches/$1 2>/dev/null
+if [ $? -ne 0 ]; then echo "Branch does not exist!"; exit 1; fi
+
+svn info svn+ssh://svncisd.ethz.ch/repos/cisd/base/tags/$1/$2 2>/dev/null
+if [ $? -eq 0 ]; then echo "Tag already exists!"; exit 1; fi
+
+svn mkdir --parents svn+ssh://svncisd.ethz.ch/repos/cisd/base/tags/$1 -m "create tag folders $1/$2"
+svn copy svn+ssh://svncisd.ethz.ch/repos/cisd/base/branches/$1 svn+ssh://svncisd.ethz.ch/repos/cisd/base/tags/$1/$2 -m "create tag $1/$2"

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/libsis-base-java.git



More information about the debian-med-commit mailing list