From 0229a3acf359ccc1b8ee597a1f92541ba38cbcbe Mon Sep 17 00:00:00 2001
From: Jesper Smith <jsmith@ihmc.us>
Date: Thu, 27 Jul 2017 17:42:01 -0500
Subject: [PATCH 1/2] Added supported for custom IO Systems in Java.
 Implemented ClassLoader IO System

---
 port/jassimp/jassimp-native/src/jassimp.cpp   | 258 +++++++++++++++++-
 port/jassimp/jassimp-native/src/jassimp.h     |   2 +-
 .../src/jassimp/AiClassLoaderIOSystem.java    | 130 +++++++++
 .../jassimp/src/jassimp/AiIOStream.java       |  55 ++++
 .../jassimp/src/jassimp/AiIOSystem.java       |  54 ++++
 .../src/jassimp/AiInputStreamIOStream.java    | 102 +++++++
 port/jassimp/jassimp/src/jassimp/Jassimp.java |  36 ++-
 7 files changed, 619 insertions(+), 18 deletions(-)
 create mode 100644 port/jassimp/jassimp/src/jassimp/AiClassLoaderIOSystem.java
 create mode 100644 port/jassimp/jassimp/src/jassimp/AiIOStream.java
 create mode 100644 port/jassimp/jassimp/src/jassimp/AiIOSystem.java
 create mode 100644 port/jassimp/jassimp/src/jassimp/AiInputStreamIOStream.java

diff --git a/port/jassimp/jassimp-native/src/jassimp.cpp b/port/jassimp/jassimp-native/src/jassimp.cpp
index 226e416aa..475f6c5a0 100644
--- a/port/jassimp/jassimp-native/src/jassimp.cpp
+++ b/port/jassimp/jassimp-native/src/jassimp.cpp
@@ -1,7 +1,9 @@
 #include "jassimp.h"
 
-#include <assimp/cimport.h>
+#include <assimp/Importer.hpp>
 #include <assimp/scene.h>
+#include <assimp/IOStream.hpp>
+#include <assimp/IOSystem.hpp>
 
 
 #ifdef JNI_LOG
@@ -12,9 +14,11 @@
 #define lprintf(...) printf (__VA_ARGS__)
 #endif /* ANDROID */
 #else
-#define lprintf
+#define lprintf 
 #endif
 
+static std::string gLastErrorString;
+
 // Automatically deletes a local ref when it goes out of scope
 class SmartLocalRef {
 private:
@@ -270,6 +274,81 @@ static bool callv(JNIEnv *env, jobject object, const char* typeName,
 	return true;
 }
 
+static jobject callo(JNIEnv *env, jobject object, const char* typeName, const char* methodName, 
+	const char* signature,/* const*/ jvalue* params)
+{
+	jclass clazz = env->FindClass(typeName);
+	SmartLocalRef clazzRef(env, clazz);
+
+	if (NULL == clazz)
+	{
+		lprintf("could not find class %s\n", typeName);
+		return NULL;
+	}
+
+	jmethodID mid = env->GetMethodID(clazz, methodName, signature);
+
+	if (NULL == mid)
+	{
+		lprintf("could not find method %s with signature %s in type %s\n", methodName, signature, typeName);
+		return NULL;
+	}
+
+	jobject jReturnValue = env->CallObjectMethodA(object, mid, params);
+
+	return jReturnValue;
+}
+
+static int calli(JNIEnv *env, jobject object, const char* typeName, const char* methodName, 
+	const char* signature)
+{
+	jclass clazz = env->FindClass(typeName);
+	SmartLocalRef clazzRef(env, clazz);
+
+	if (NULL == clazz)
+	{
+		lprintf("could not find class %s\n", typeName);
+		return false;
+	}
+
+	jmethodID mid = env->GetMethodID(clazz, methodName, signature);
+
+	if (NULL == mid)
+	{
+		lprintf("could not find method %s with signature %s in type %s\n", methodName, signature, typeName);
+		return false;
+	}
+
+	jint jReturnValue = env->CallIntMethod(object, mid);
+
+	return (int) jReturnValue;
+}
+
+static int callc(JNIEnv *env, jobject object, const char* typeName, const char* methodName, 
+	const char* signature)
+{
+	jclass clazz = env->FindClass(typeName);
+	SmartLocalRef clazzRef(env, clazz);
+
+	if (NULL == clazz)
+	{
+		lprintf("could not find class %s\n", typeName);
+		return false;
+	}
+
+	jmethodID mid = env->GetMethodID(clazz, methodName, signature);
+
+	if (NULL == mid)
+	{
+		lprintf("could not find method %s with signature %s in type %s\n", methodName, signature, typeName);
+		return false;
+	}
+
+	jint jReturnValue = env->CallCharMethod(object, mid);
+
+	return (int) jReturnValue;
+}
+
 
 static bool callStaticObject(JNIEnv *env, const char* typeName, const char* methodName, 
 	const char* signature,/* const*/ jvalue* params, jobject& returnValue)
@@ -359,6 +438,155 @@ static bool copyBufferArray(JNIEnv *env, jobject jMesh, const char* jBufferName,
 	return true;
 }
 
+class JavaIOStream : public Assimp::IOStream
+{
+private:	
+	size_t pos;
+	size_t size;
+	char* buffer;
+	jobject jIOStream;
+
+	
+public:
+	JavaIOStream(size_t size, char* buffer, jobject jIOStream) :
+	pos(0),
+	size(size),
+	buffer(buffer),
+	jIOStream(jIOStream)
+	{};
+	
+	
+    ~JavaIOStream(void) 
+    {
+    	free(buffer);
+    }; 
+
+    size_t Read(void* pvBuffer, size_t pSize, size_t pCount)
+    {
+    	const size_t cnt = std::min(pCount,(size - pos)/pSize);
+		const size_t ofs = pSize*cnt;
+	
+	    memcpy(pvBuffer, buffer + pos, ofs);
+	    pos += ofs;
+	
+	    return cnt;
+    };
+    size_t Write(const void* pvBuffer, size_t pSize, size_t pCount) {};
+    
+    aiReturn Seek(size_t pOffset, aiOrigin pOrigin)
+    {
+	    if (aiOrigin_SET == pOrigin) {
+	        if (pOffset >= size) {
+	            return AI_FAILURE;
+	        }
+	        pos = pOffset;
+	    }
+	    else if (aiOrigin_END == pOrigin) {
+	        if (pOffset >= size) {
+	            return AI_FAILURE;
+	        }
+	        pos = size-pOffset;
+	    }
+	    else {
+	        if (pOffset + pos >= size) {
+	            return AI_FAILURE;
+	        }
+	        pos += pOffset;
+	    }
+	    return AI_SUCCESS;
+    };
+    
+    size_t Tell(void) const
+    {
+    	return pos;
+    };
+    
+    size_t FileSize() const
+    {
+    	return size;
+    };
+    
+    void Flush() {};
+    
+    
+    jobject javaObject()
+    {
+    	return jIOStream;
+    };
+    
+    
+};
+ 
+
+class JavaIOSystem : public Assimp::IOSystem {
+	private:
+    JNIEnv* mJniEnv;
+	jobject& mJavaIOSystem;
+	
+	public:
+	JavaIOSystem(JNIEnv* env, jobject& javaIOSystem) :
+		mJniEnv(env),
+		mJavaIOSystem(javaIOSystem)
+	{};
+	
+    bool Exists( const char* pFile) const
+    {
+    	jvalue params[1];
+		params[0].l = mJniEnv->NewStringUTF(pFile);
+	    return call(mJniEnv, mJavaIOSystem, "jassimp/AiIOSystem", "exists", "(Ljava/lang/String;)Z", params);
+
+    };
+    char getOsSeparator() const
+    {
+	    return (char) callc(mJniEnv, mJavaIOSystem, "jassimp/AiIOSystem", "getOsSeparator", "()C");
+    };
+    
+    Assimp::IOStream* Open(const char* pFile,const char* pMode = "rb")
+    {
+        jvalue params[2];
+		params[0].l = mJniEnv->NewStringUTF(pFile);
+		params[1].l = mJniEnv->NewStringUTF(pMode);
+		
+		
+	    jobject jStream = callo(mJniEnv, mJavaIOSystem, "jassimp/AiIOSystem", "open", "(Ljava/lang/String;Ljava/lang/String;)Ljassimp/AiIOStream;", params);
+	    if(NULL == jStream)
+	    {
+	    	lprintf("NULL object from AiIOSystem.open\n");
+	    	return NULL;
+	    }
+	    
+	    size_t size = calli(mJniEnv, jStream, "jassimp/AiIOStream", "getFileSize", "()I");
+	    lprintf("Model file size is %d\n", size);
+	    
+	    char* buffer = (char*)malloc(size);
+	    jobject javaBuffer = mJniEnv->NewDirectByteBuffer(buffer, size);
+	    
+	    jvalue readParams[1];
+	    readParams[0].l = javaBuffer;
+	    if(call(mJniEnv, jStream, "jassimp/AiIOStream", "read", "(Ljava/nio/ByteBuffer;)Z", readParams))
+	    {
+	    	return new JavaIOStream(size, buffer, jStream);
+		}
+		else
+		{
+			lprintf("Read failure on AiIOStream.read");
+			free(buffer);
+			return NULL;
+		}
+
+    };
+    void Close( Assimp::IOStream* pFile)
+    {
+    	
+		jvalue params[1];
+		params[0].l = ((JavaIOStream*) pFile)->javaObject();
+		callv(mJniEnv, mJavaIOSystem, "jassimp/AiIOSystem", "close", "(Ljassimp/AiIOStream;)V", params);
+    	delete pFile;
+    };
+    
+
+	
+};
 
 
 static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene)
@@ -1474,7 +1702,7 @@ JNIEXPORT jint JNICALL Java_jassimp_Jassimp_getlongsize
 JNIEXPORT jstring JNICALL Java_jassimp_Jassimp_getErrorString
   (JNIEnv *env, jclass jClazz)
 {
-	const char *err = aiGetErrorString();
+	const char *err = gLastErrorString.c_str();
 
 	if (NULL == err)
 	{
@@ -1486,18 +1714,26 @@ JNIEXPORT jstring JNICALL Java_jassimp_Jassimp_getErrorString
 
 
 JNIEXPORT jobject JNICALL Java_jassimp_Jassimp_aiImportFile
-  (JNIEnv *env, jclass jClazz, jstring jFilename, jlong postProcess)
+  (JNIEnv *env, jclass jClazz, jstring jFilename, jlong postProcess, jobject ioSystem)
 {
 	jobject jScene = NULL; 
 
 	/* convert params */
 	const char* cFilename = env->GetStringUTFChars(jFilename, NULL);
+	
+    Assimp::Importer imp;
 
-
+	
+	if(ioSystem != NULL)
+	{
+		imp.SetIOHandler(new JavaIOSystem(env, ioSystem));		
+		lprintf("Created aiFileIO\n");
+	}
+	
 	lprintf("opening file: %s\n", cFilename);
 
 	/* do import */
-	const aiScene *cScene = aiImportFile(cFilename, (unsigned int) postProcess);
+	const aiScene *cScene = imp.ReadFile(cFilename, (unsigned int) postProcess);
 
 	if (!cScene)
 	{
@@ -1552,19 +1788,13 @@ error:
 		/* thats really a problem because we cannot throw in this case */
 		env->FatalError("could not throw java.io.IOException");
 	}
-
-	env->ThrowNew(exception, aiGetErrorString());
+	gLastErrorString = imp.GetErrorString();
+	env->ThrowNew(exception, gLastErrorString.c_str());
 
 	lprintf("problem detected\n");
 	}
 
 end:
-	/* 
-	 * NOTE: this releases all memory used in the native domain.
-	 * Ensure all data has been passed to java before!
-	 */
-	aiReleaseImport(cScene);
-
 
 	/* free params */
 	env->ReleaseStringUTFChars(jFilename, cFilename);
diff --git a/port/jassimp/jassimp-native/src/jassimp.h b/port/jassimp/jassimp-native/src/jassimp.h
index f448dc2c2..7d4b66e29 100644
--- a/port/jassimp/jassimp-native/src/jassimp.h
+++ b/port/jassimp/jassimp-native/src/jassimp.h
@@ -39,7 +39,7 @@ JNIEXPORT jstring JNICALL Java_jassimp_Jassimp_getErrorString
  * Signature: (Ljava/lang/String;J)Ljassimp/AiScene;
  */
 JNIEXPORT jobject JNICALL Java_jassimp_Jassimp_aiImportFile
-  (JNIEnv *, jclass, jstring, jlong);
+  (JNIEnv *, jclass, jstring, jlong, jobject);
 
 #ifdef __cplusplus
 }
diff --git a/port/jassimp/jassimp/src/jassimp/AiClassLoaderIOSystem.java b/port/jassimp/jassimp/src/jassimp/AiClassLoaderIOSystem.java
new file mode 100644
index 000000000..04d638610
--- /dev/null
+++ b/port/jassimp/jassimp/src/jassimp/AiClassLoaderIOSystem.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2017 Florida Institute for Human and Machine Cognition (IHMC)
+ * 
+ * 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 jassimp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+/**
+ * IOSystem based on the Java classloader.<p>
+ * 
+ * This IOSystem allows loading models directly from the 
+ * classpath. No extraction to the file system is 
+ * necessary.
+ * 
+ * @author Jesper Smith
+ *
+ */
+public class AiClassLoaderIOSystem implements AiIOSystem<AiInputStreamIOStream>
+{
+   private final Class<?> clazz;
+   private final ClassLoader classLoader;
+  
+   /**
+    * Construct a new AiClassLoaderIOSystem.<p>
+    * 
+    * This constructor uses a ClassLoader to resolve
+    * resources.
+    * 
+    * @param classLoader classLoader to resolve resources.
+    */
+   public AiClassLoaderIOSystem(ClassLoader classLoader) {
+      this.clazz = null;
+      this.classLoader = classLoader;
+   }
+
+   /**
+    * Construct a new AiClassLoaderIOSystem.<p>
+    * 
+    * This constructor uses a Class to resolve
+    * resources.
+    * 
+    * @param class<?> class to resolve resources.
+    */
+   public AiClassLoaderIOSystem(Class<?> clazz) {
+      this.clazz = clazz;
+      this.classLoader = null;
+   }
+   
+
+   @Override
+   public AiInputStreamIOStream open(String filename, String ioMode) {
+      try {
+         
+         InputStream is;
+         
+         if(clazz != null) {
+            is = clazz.getResourceAsStream(filename);
+         }
+         else if (classLoader != null) {
+            is = classLoader.getResourceAsStream(filename);
+         }
+         else {
+            System.err.println("[" + getClass().getSimpleName() + 
+                "] No class or classLoader provided to resolve " + filename);
+            return null;
+         }
+         
+         if(is != null) {
+            return new AiInputStreamIOStream(is);
+         }
+         else {
+            System.err.println("[" + getClass().getSimpleName() + 
+                               "] Cannot find " + filename);
+            return null;
+         }
+      }
+      catch (IOException e) {
+         e.printStackTrace();
+         return null;
+      }
+   }
+
+   @Override
+   public void close(AiInputStreamIOStream file) {
+   }
+
+   @Override
+   public boolean exists(String path)
+   {
+      URL url = null;
+      if(clazz != null) {
+         url = clazz.getResource(path);
+      }
+      else if (classLoader != null) {
+         url = classLoader.getResource(path);
+      }
+
+      
+      if(url == null)
+      {
+         return false;
+      }
+      else
+      {
+         return true;
+      }
+      
+   }
+
+   @Override
+   public char getOsSeparator()
+   {
+      return '/';
+   }
+
+}
diff --git a/port/jassimp/jassimp/src/jassimp/AiIOStream.java b/port/jassimp/jassimp/src/jassimp/AiIOStream.java
new file mode 100644
index 000000000..5378da5f8
--- /dev/null
+++ b/port/jassimp/jassimp/src/jassimp/AiIOStream.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2017 Florida Institute for Human and Machine Cognition (IHMC)
+ * 
+ * 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 jassimp;
+
+import java.nio.ByteBuffer;
+
+
+/**
+ * Interface to allow custom resource loaders for jassimp.<p>
+ *
+ * The design is based on passing the file wholly in memory, 
+ * because Java inputstreams do not have to support seek. <p>
+ * 
+ * Writing files from Java is unsupported.
+ * 
+ * 
+ * @author Jesper Smith
+ *
+ */
+public interface AiIOStream
+{
+
+   /**
+    * Read all data into buffer. <p>
+    * 
+    * The whole stream should be read into the buffer. 
+    * No support is provided for partial reads. 
+    * 
+    * @param buffer Target buffer for the model data
+    * 
+    * @return true if successful, false if an error occurred.
+    */
+   boolean read(ByteBuffer buffer);
+
+   /**
+    * The total size of this stream. <p>
+    *  
+    * @return total size of this stream
+    */
+   int getFileSize();
+
+}
diff --git a/port/jassimp/jassimp/src/jassimp/AiIOSystem.java b/port/jassimp/jassimp/src/jassimp/AiIOSystem.java
new file mode 100644
index 000000000..d2c741529
--- /dev/null
+++ b/port/jassimp/jassimp/src/jassimp/AiIOSystem.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2017 Florida Institute for Human and Machine Cognition (IHMC)
+ * 
+ * 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 jassimp;
+
+public interface AiIOSystem <T extends AiIOStream>
+{
+   /**
+    * 
+    * Open a new file with a given path.
+    * When the access to the file is finished, call close() to release all associated resources
+    * 
+    * @param path Path to the file
+    * @param ioMode file I/O mode. Required are: "wb", "w", "wt", "rb", "r", "rt".
+    * 
+    * @return AiIOStream or null if an error occurred
+    */
+   public T open(String path, String ioMode);
+   
+   
+   /**
+    * Tests for the existence of a file at the given path.
+    *  
+    * @param path path to the file
+    * @return true if there is a file with this path, else false.
+    */
+   public boolean exists(String path);
+
+   /**
+    * Returns the system specific directory separator.<p>
+    * 
+    * @return System specific directory separator
+    */
+   public char getOsSeparator();
+   
+   /**
+    * Closes the given file and releases all resources associated with it.
+    * 
+    * @param file The file instance previously created by Open().
+    */
+   public void close(T file);
+}
diff --git a/port/jassimp/jassimp/src/jassimp/AiInputStreamIOStream.java b/port/jassimp/jassimp/src/jassimp/AiInputStreamIOStream.java
new file mode 100644
index 000000000..998401b68
--- /dev/null
+++ b/port/jassimp/jassimp/src/jassimp/AiInputStreamIOStream.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2017 Florida Institute for Human and Machine Cognition (IHMC)
+ * 
+ * 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 jassimp;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URL;
+import java.nio.ByteBuffer;
+
+
+/**
+ * Implementation of AiIOStream reading from a InputStream
+ * 
+ * @author Jesper Smith
+ *
+ */
+public class AiInputStreamIOStream implements AiIOStream
+{
+   private final ByteArrayOutputStream os = new ByteArrayOutputStream(); 
+   
+   
+   public AiInputStreamIOStream(URI uri) throws IOException {
+      this(uri.toURL());
+   }
+   
+   public AiInputStreamIOStream(URL url) throws IOException {
+      this(url.openStream());
+   }
+   
+   public AiInputStreamIOStream(InputStream is) throws IOException {
+      int read;
+      byte[] data = new byte[1024];
+      while((read = is.read(data, 0, data.length)) != -1) {
+         os.write(data, 0, read);
+      }
+      os.flush();
+      
+      is.close();
+   }
+   
+   @Override
+   public int getFileSize() {
+      return os.size();
+   }
+   
+   @Override
+   public boolean read(ByteBuffer buffer) {
+     ByteBufferOutputStream bos = new ByteBufferOutputStream(buffer);
+     try
+     {
+        os.writeTo(bos);
+     }
+     catch (IOException e)
+     {
+        e.printStackTrace();
+        return false;
+     }
+     return true;
+   }
+   
+   /**
+    * Internal helper class to copy the contents of an OutputStream
+    * into a ByteBuffer. This avoids a copy.
+    *
+    */
+   private static class ByteBufferOutputStream extends OutputStream {
+
+      private final ByteBuffer buffer;
+      
+      public ByteBufferOutputStream(ByteBuffer buffer) {
+         this.buffer = buffer;
+      }
+      
+      @Override
+      public void write(int b) throws IOException
+      {
+         buffer.put((byte) b);
+      }
+    
+      @Override
+      public void write(byte b[], int off, int len) throws IOException {
+         buffer.put(b, off, len);
+      }
+   }
+}
+
diff --git a/port/jassimp/jassimp/src/jassimp/Jassimp.java b/port/jassimp/jassimp/src/jassimp/Jassimp.java
index 92f4864c7..d1b4aae4e 100644
--- a/port/jassimp/jassimp/src/jassimp/Jassimp.java
+++ b/port/jassimp/jassimp/src/jassimp/Jassimp.java
@@ -79,6 +79,20 @@ public final class Jassimp {
         return importFile(filename, EnumSet.noneOf(AiPostProcessSteps.class));
     }
     
+    /**
+     * Imports a file via assimp without post processing.
+     * 
+     * @param filename the file to import
+     * @param ioSystem ioSystem to load files, or null for default
+     * @return the loaded scene
+     * @throws IOException if an error occurs
+     */
+    public static AiScene importFile(String filename, AiIOSystem<?> ioSystem) 
+          throws IOException {
+       
+       return importFile(filename, EnumSet.noneOf(AiPostProcessSteps.class), ioSystem);
+    }
+    
     
     /**
      * Imports a file via assimp.
@@ -89,12 +103,28 @@ public final class Jassimp {
      * @throws IOException if an error occurs
      */
     public static AiScene importFile(String filename, 
-            Set<AiPostProcessSteps> postProcessing) throws IOException {
+                                     Set<AiPostProcessSteps> postProcessing) 
+                                           throws IOException {
+        return importFile(filename, postProcessing, null);
+    }
+    
+    /**
+     * Imports a file via assimp.
+     * 
+     * @param filename the file to import
+     * @param postProcessing post processing flags
+     * @param ioSystem ioSystem to load files, or null for default
+     * @return the loaded scene, or null if an error occurred
+     * @throws IOException if an error occurs
+     */
+    public static AiScene importFile(String filename, 
+            Set<AiPostProcessSteps> postProcessing, AiIOSystem<?> ioSystem) 
+                  throws IOException {
         
        loadLibrary();
        
         return aiImportFile(filename, AiPostProcessSteps.toRawValue(
-                postProcessing));
+                postProcessing), ioSystem);
     }
     
     
@@ -310,7 +340,7 @@ public final class Jassimp {
      * @throws IOException if an error occurs
      */
     private static native AiScene aiImportFile(String filename, 
-            long postProcessing) throws IOException;
+            long postProcessing, AiIOSystem<?> ioSystem) throws IOException;
     
     
     /**

From a7c1dde56e3ae4af5eaef801e938ee9e2265ecfb Mon Sep 17 00:00:00 2001
From: Jesper Smith <jsmith@ihmc.us>
Date: Fri, 28 Jul 2017 15:08:59 -0500
Subject: [PATCH 2/2] Added return statement to Write

---
 port/jassimp/jassimp-native/src/jassimp.cpp | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/port/jassimp/jassimp-native/src/jassimp.cpp b/port/jassimp/jassimp-native/src/jassimp.cpp
index 475f6c5a0..75b1bc510 100644
--- a/port/jassimp/jassimp-native/src/jassimp.cpp
+++ b/port/jassimp/jassimp-native/src/jassimp.cpp
@@ -471,7 +471,10 @@ public:
 	
 	    return cnt;
     };
-    size_t Write(const void* pvBuffer, size_t pSize, size_t pCount) {};
+    size_t Write(const void* pvBuffer, size_t pSize, size_t pCount) 
+    {
+        return 0;
+    };
     
     aiReturn Seek(size_t pOffset, aiOrigin pOrigin)
     {