/* -*- Mode: C; c-file-style: "gnu" -*-
   jni.h -- Java Native Interface header file.
   Created: Chris Toshok <toshok@hungry.com>, 26-Jul-1997
 */
/*
  This file is part of Japhar, the GNU Virtual Machine for Java Bytecodes.
  Japhar is a project of The Hungry Programmers, GNU, and OryxSoft.

  Copyright (C) 1997, 1998, 1999 The Hungry Programmers

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#ifndef _hungry_jni_h
#define _hungry_jni_h

#include <stdio.h>
#include <sys/types.h>
#include <stdarg.h>

#include "jnitypes.h"

#ifdef __cplusplus
extern "C" {
#endif

#ifdef _WINDOWS
#define JNIEXPORT __declspec( dllexport )
#define JNICALL __cdecl
#else
#  define JNIEXPORT
#  define JNICALL
#endif

  /* new constants for jdk 1.2 */
#define JNI_VERSION_1_1		0x00010001
#define JNI_VERSION_1_2		0x00010002

  /* Error codes */
#define JNI_EDETACHED		(-2)		/* thread detached from the VM */
#define JNI_EVERSION		(-3)		/* JNI version error */
#define JNI_ENOMEM		(-4)		/* not enough memory */
#define JNI_EEXIST		(-5)		/* VM already created */
#define JNI_EINVAL		(-6)		/* invalid arguments */

#define JNI_FALSE 0
#define JNI_TRUE 1

  /* two constants used in Release<PrimitiveType>ArrayElements */
#define JNI_COMMIT 1
#define JNI_ABORT 2

  /* the type used to describe cardinal indices and sizes */
  typedef jint jsize;

  /* JNI Reference types */
  typedef jref jweak;
  typedef jref jobject;
  typedef jref jclass;
  typedef jobject jstring;
  typedef jobject jarray;
  typedef jarray jobjectArray;
  typedef jarray jbooleanArray;
  typedef jarray jbyteArray;
  typedef jarray jcharArray;
  typedef jarray jshortArray;
  typedef jarray jintArray;
  typedef jarray jlongArray;
  typedef jarray jfloatArray;
  typedef jarray jdoubleArray;
  typedef jobject jthrowable;

  /* JNI Field and Method ID's */
  typedef struct FieldStruct *jfieldID;
  typedef struct MethodStruct *jmethodID;

  /* JNI Value Type */

  typedef union jvalue {
    jboolean	z;
    jbyte		b;
    jchar		c;
    jshort	s;
    jint		i;
    jlong		j;
    jfloat	f;
    jdouble	d;
    jobject	l;
  } jvalue;

  /* Structure used when registering native methods. */
  typedef struct {
    char *name;
    char *signature;
    void *fnPtr;
  } JNINativeMethod;

#ifdef __cplusplus
  typedef struct JNIEnv JNIEnv;
  typedef struct JavaVM JavaVM;
#else
  typedef const struct JNINativeInterface *JNIEnv;
  typedef const struct JNIInvokeInterface *JavaVM;
#endif

  struct JNINativeInterface {
    void *_sun0;
    void *_sun1;
    void *_sun2;
    void *_sun3;
    jint (*GetVersion)(JNIEnv *env);
  
    jclass (*DefineClass)(JNIEnv *env, jobject loader, const jbyte* buf, jsize bufLen);
    jclass (*FindClass)(JNIEnv *env, const char *name);

    void *_sun4;
    void *_sun5;
    void *_sun6;
    jclass (*GetSuperclass)(JNIEnv *env, jclass clazz);
    jboolean (*IsAssignableFrom)(JNIEnv *env, jclass clazz1, jclass clazz2);

    void *_sun7;

    jint (*Throw)(JNIEnv *env, jthrowable obj);
    jint (*ThrowNew)(JNIEnv *env, jclass clazz, const char *message);
    jthrowable (*ExceptionOccurred)(JNIEnv *env);
    void (*ExceptionDescribe)(JNIEnv *env);
    void (*ExceptionClear)(JNIEnv *env);
    void (*FatalError)(JNIEnv *env, const char *msg);
    void *_sun8;
    void *_sun9;

    jobject (*NewGlobalRef)(JNIEnv *env, jobject obj);
    void (*DeleteGlobalRef)(JNIEnv *env, jobject globalRef);
    void (*DeleteLocalRef)(JNIEnv *env, jobject localRef);

    jboolean (*IsSameObject)(JNIEnv *env, jobject ref, jobject ref2);
    void *_sun10;
    void *_sun11;
  
    jobject (*AllocObject)(JNIEnv *env, jclass clazz);
    jobject (*NewObject)(JNIEnv *env, jclass clazz,
			 jmethodID methodID, ...);
    jobject (*NewObjectV)(JNIEnv *env, jclass clazz,
			  jmethodID methodID, va_list args);
    jobject (*NewObjectA)(JNIEnv *env, jclass clazz,
			  jmethodID methodID, jvalue *args);

    jclass (*GetObjectClass)(JNIEnv *env, jobject obj);
    jboolean (*IsInstanceOf)(JNIEnv *env, jobject obj, jclass clazz);

    jmethodID (*GetMethodID)(JNIEnv *env, jclass clazz,
			     const char *name, const char *sig);

    jobject (*CallObjectMethod)(JNIEnv *env, jobject obj,
				jmethodID methodID, ...);
    jobject (*CallObjectMethodV)(JNIEnv *env, jobject obj,
				 jmethodID methodID, va_list args);
    jobject (*CallObjectMethodA)(JNIEnv *env, jobject obj,
				 jmethodID methodID, jvalue *args);
    jboolean (*CallBooleanMethod)(JNIEnv *env, jobject obj,
				  jmethodID methodID, ...);
    jboolean (*CallBooleanMethodV)(JNIEnv *env, jobject obj,
				   jmethodID methodID, va_list args);
    jboolean (*CallBooleanMethodA)(JNIEnv *env, jobject obj,
				   jmethodID methodID, jvalue *args);

    jbyte (*CallByteMethod)(JNIEnv *env, jobject obj,
			    jmethodID methodID, ...);
    jbyte (*CallByteMethodV)(JNIEnv *env, jobject obj,
			     jmethodID methodID, va_list args);
    jbyte (*CallByteMethodA)(JNIEnv *env, jobject obj,
			     jmethodID methodID, jvalue *args);

    jchar (*CallCharMethod)(JNIEnv *env, jobject obj,
			    jmethodID methodID, ...);
    jchar (*CallCharMethodV)(JNIEnv *env, jobject obj,
			     jmethodID methodID, va_list args);
    jchar (*CallCharMethodA)(JNIEnv *env, jobject obj,
			     jmethodID methodID, jvalue *args);

    jshort (*CallShortMethod)(JNIEnv *env, jobject obj,
			      jmethodID methodID, ...);
    jshort (*CallShortMethodV)(JNIEnv *env, jobject obj,
			       jmethodID methodID, va_list args);
    jshort (*CallShortMethodA)(JNIEnv *env, jobject obj,
			       jmethodID methodID, jvalue *args);

    jint (*CallIntMethod)(JNIEnv *env, jobject obj,
			  jmethodID methodID, ...);
    jint (*CallIntMethodV)(JNIEnv *env, jobject obj,
			   jmethodID methodID, va_list args);
    jint (*CallIntMethodA)(JNIEnv *env, jobject obj,
			   jmethodID methodID, jvalue *args);

    jlong (*CallLongMethod)(JNIEnv *env, jobject obj,
			    jmethodID methodID, ...);
    jlong (*CallLongMethodV)(JNIEnv *env, jobject obj,
			     jmethodID methodID, va_list args);
    jlong (*CallLongMethodA)(JNIEnv *env, jobject obj,
			     jmethodID methodID, jvalue *args);

    jfloat (*CallFloatMethod)(JNIEnv *env, jobject obj,
			      jmethodID methodID, ...);
    jfloat (*CallFloatMethodV)(JNIEnv *env, jobject obj,
			       jmethodID methodID, va_list args);
    jfloat (*CallFloatMethodA)(JNIEnv *env, jobject obj,
			       jmethodID methodID, jvalue *args);

    jdouble (*CallDoubleMethod)(JNIEnv *env, jobject obj,
				jmethodID methodID, ...);
    jdouble (*CallDoubleMethodV)(JNIEnv *env, jobject obj,
				 jmethodID methodID, va_list args);
    jdouble (*CallDoubleMethodA)(JNIEnv *env, jobject obj,
				 jmethodID methodID, jvalue *args);

    void (*CallVoidMethod)(JNIEnv *env, jobject obj,
			   jmethodID methodID, ...);
    void (*CallVoidMethodV)(JNIEnv *env, jobject obj,
			    jmethodID methodID, va_list args);
    void (*CallVoidMethodA)(JNIEnv *env, jobject obj,
			    jmethodID methodID, jvalue *args);


    jobject (*CallNonvirtualObjectMethod)(JNIEnv *env, jobject obj,
					  jmethodID methodID, ...);
    jobject (*CallNonvirtualObjectMethodV)(JNIEnv *env, jobject obj,
					   jmethodID methodID, va_list args);
    jobject (*CallNonvirtualObjectMethodA)(JNIEnv *env, jobject obj,
					   jmethodID methodID, jvalue *args);
    jboolean (*CallNonvirtualBooleanMethod)(JNIEnv *env, jobject obj,
					    jmethodID methodID, ...);
    jboolean (*CallNonvirtualBooleanMethodV)(JNIEnv *env, jobject obj,
					     jmethodID methodID, va_list args);
    jboolean (*CallNonvirtualBooleanMethodA)(JNIEnv *env, jobject obj,
					     jmethodID methodID, jvalue *args);
    jbyte (*CallNonvirtualByteMethod)(JNIEnv *env, jobject obj,
				      jmethodID methodID, ...);
    jbyte (*CallNonvirtualByteMethodV)(JNIEnv *env, jobject obj,
				       jmethodID methodID, va_list args);
    jbyte (*CallNonvirtualByteMethodA)(JNIEnv *env, jobject obj,
				       jmethodID methodID, jvalue *args);
    jchar (*CallNonvirtualCharMethod)(JNIEnv *env, jobject obj,
				      jmethodID methodID, ...);
    jchar (*CallNonvirtualCharMethodV)(JNIEnv *env, jobject obj,
				       jmethodID methodID, va_list args);
    jchar (*CallNonvirtualCharMethodA)(JNIEnv *env, jobject obj,
				       jmethodID methodID, jvalue *args);
    jshort (*CallNonvirtualShortMethod)(JNIEnv *env, jobject obj,
					jmethodID methodID, ...);
    jshort (*CallNonvirtualShortMethodV)(JNIEnv *env, jobject obj,
					 jmethodID methodID, va_list args);
    jshort (*CallNonvirtualShortMethodA)(JNIEnv *env, jobject obj,
					 jmethodID methodID, jvalue *args);
    jint (*CallNonvirtualIntMethod)(JNIEnv *env, jobject obj,
				    jmethodID methodID, ...);
    jint (*CallNonvirtualIntMethodV)(JNIEnv *env, jobject obj,
				     jmethodID methodID, va_list args);
    jint (*CallNonvirtualIntMethodA)(JNIEnv *env, jobject obj,
				     jmethodID methodID, jvalue *args);
    jlong (*CallNonvirtualLongMethod)(JNIEnv *env, jobject obj,
				      jmethodID methodID, ...);
    jlong (*CallNonvirtualLongMethodV)(JNIEnv *env, jobject obj,
				       jmethodID methodID, va_list args);
    jlong (*CallNonvirtualLongMethodA)(JNIEnv *env, jobject obj,
				       jmethodID methodID, jvalue *args);
    jfloat (*CallNonvirtualFloatMethod)(JNIEnv *env, jobject obj,
					jmethodID methodID, ...);
    jfloat (*CallNonvirtualFloatMethodV)(JNIEnv *env, jobject obj,
					 jmethodID methodID, va_list args);
    jfloat (*CallNonvirtualFloatMethodA)(JNIEnv *env, jobject obj,
					 jmethodID methodID, jvalue *args);
    jdouble (*CallNonvirtualDoubleMethod)(JNIEnv *env, jobject obj,
					  jmethodID methodID, ...);
    jdouble (*CallNonvirtualDoubleMethodV)(JNIEnv *env, jobject obj,
					   jmethodID methodID, va_list args);
    jdouble (*CallNonvirtualDoubleMethodA)(JNIEnv *env, jobject obj,
					   jmethodID methodID, jvalue *args);
    void (*CallNonvirtualVoidMethod)(JNIEnv *env, jobject obj,
				     jmethodID methodID, ...);
    void (*CallNonvirtualVoidMethodV)(JNIEnv *env, jobject obj,
				      jmethodID methodID, va_list args);
    void (*CallNonvirtualVoidMethodA)(JNIEnv *env, jobject obj,
				      jmethodID methodID, jvalue *args);

    jfieldID (*GetFieldID)(JNIEnv *env, jclass clazz,
			   const char *name, const char *sig);

    jobject (*GetObjectField)(JNIEnv *env, jobject obj,
			      jfieldID fieldID);

    jboolean (*GetBooleanField)(JNIEnv *env, jobject obj,
				jfieldID fieldID);
    jbyte (*GetByteField)(JNIEnv *env, jobject obj,
			  jfieldID fieldID);
    jchar (*GetCharField)(JNIEnv *env, jobject obj,
			  jfieldID fieldID);
    jshort (*GetShortField)(JNIEnv *env, jobject obj,
			    jfieldID fieldID);
    jint (*GetIntField)(JNIEnv *env, jobject obj,
			jfieldID fieldID);
    jlong (*GetLongField)(JNIEnv *env, jobject obj,
			  jfieldID fieldID);
    jfloat (*GetFloatField)(JNIEnv *env, jobject obj,
			    jfieldID fieldID);
    jdouble (*GetDoubleField)(JNIEnv *env, jobject obj,
			      jfieldID fieldID);
    void (*SetObjectField)(JNIEnv *env, jobject obj,
			   jfieldID fieldID, jobject value);

    void (*SetBooleanField)(JNIEnv *env, jobject obj,
			    jfieldID fieldID, jboolean value);
    void (*SetByteField)(JNIEnv *env, jobject obj,
			 jfieldID fieldID, jbyte value);
    void (*SetCharField)(JNIEnv *env, jobject obj,
			 jfieldID fieldID, jchar value);
    void (*SetShortField)(JNIEnv *env, jobject obj,
			  jfieldID fieldID, jshort value);
    void (*SetIntField)(JNIEnv *env, jobject obj,
			jfieldID fieldID, jint value);
    void (*SetLongField)(JNIEnv *env, jobject obj,
			 jfieldID fieldID, jlong value);
    void (*SetFloatField)(JNIEnv *env, jobject obj,
			  jfieldID fieldID, jfloat value);
    void (*SetDoubleField)(JNIEnv *env, jobject obj,
			   jfieldID fieldID, jdouble value);

    jmethodID (*GetStaticMethodID)(JNIEnv *env, jclass clazz,
				   const char *name, const char *sig);

    jobject (*CallStaticObjectMethod)(JNIEnv *env, jclass clazz,
				      jmethodID methodID, ...);
    jobject (*CallStaticObjectMethodV)(JNIEnv *env, jclass clazz,
				       jmethodID methodID, va_list args);
    jobject (*CallStaticObjectMethodA)(JNIEnv *env, jclass clazz,
				       jmethodID methodID, jvalue *args);

    jboolean (*CallStaticBooleanMethod)(JNIEnv *env, jclass clazz,
					jmethodID methodID, ...);
    jboolean (*CallStaticBooleanMethodV)(JNIEnv *env, jclass clazz,
					 jmethodID methodID, va_list args);
    jboolean (*CallStaticBooleanMethodA)(JNIEnv *env, jclass clazz,
					 jmethodID methodID, jvalue *args);
    jbyte (*CallStaticByteMethod)(JNIEnv *env, jclass clazz,
				  jmethodID methodID, ...);
    jbyte (*CallStaticByteMethodV)(JNIEnv *env, jclass clazz,
				   jmethodID methodID, va_list args);
    jbyte (*CallStaticByteMethodA)(JNIEnv *env, jclass clazz,
				   jmethodID methodID, jvalue *args);
    jchar (*CallStaticCharMethod)(JNIEnv *env, jclass clazz,
				  jmethodID methodID, ...);
    jchar (*CallStaticCharMethodV)(JNIEnv *env, jclass clazz,
				   jmethodID methodID, va_list args);
    jchar (*CallStaticCharMethodA)(JNIEnv *env, jclass clazz,
				   jmethodID methodID, jvalue *args);
    jshort (*CallStaticShortMethod)(JNIEnv *env, jclass clazz,
				    jmethodID methodID, ...);
    jshort (*CallStaticShortMethodV)(JNIEnv *env, jclass clazz,
				     jmethodID methodID, va_list args);
    jshort (*CallStaticShortMethodA)(JNIEnv *env, jclass clazz,
				     jmethodID methodID, jvalue *args);
    jint (*CallStaticIntMethod)(JNIEnv *env, jclass clazz,
				jmethodID methodID, ...);
    jint (*CallStaticIntMethodV)(JNIEnv *env, jclass clazz,
				 jmethodID methodID, va_list args);
    jint (*CallStaticIntMethodA)(JNIEnv *env, jclass clazz,
				 jmethodID methodID, jvalue *args);
    jlong (*CallStaticLongMethod)(JNIEnv *env, jclass clazz,
				  jmethodID methodID, ...);
    jlong (*CallStaticLongMethodV)(JNIEnv *env, jclass clazz,
				   jmethodID methodID, va_list args);
    jlong (*CallStaticLongMethodA)(JNIEnv *env, jclass clazz,
				   jmethodID methodID, jvalue *args);
    jfloat (*CallStaticFloatMethod)(JNIEnv *env, jclass clazz,
				    jmethodID methodID, ...);
    jfloat (*CallStaticFloatMethodV)(JNIEnv *env, jclass clazz,
				     jmethodID methodID, va_list args);
    jfloat (*CallStaticFloatMethodA)(JNIEnv *env, jclass clazz,
				     jmethodID methodID, jvalue *args);
    jdouble (*CallStaticDoubleMethod)(JNIEnv *env, jclass clazz,
				      jmethodID methodID, ...);
    jdouble (*CallStaticDoubleMethodV)(JNIEnv *env, jclass clazz,
				       jmethodID methodID, va_list args);
    jdouble (*CallStaticDoubleMethodA)(JNIEnv *env, jclass clazz,
				       jmethodID methodID, jvalue *args);
    void (*CallStaticVoidMethod)(JNIEnv *env, jclass clazz,
				 jmethodID methodID, ...);
    void (*CallStaticVoidMethodV)(JNIEnv *env, jclass clazz,
				  jmethodID methodID, va_list args);
    void (*CallStaticVoidMethodA)(JNIEnv *env, jclass clazz,
				  jmethodID methodID, jvalue *args);

    jfieldID (*GetStaticFieldID)(JNIEnv *env, jclass clazz,
				 const char *name, const char *sig);

    jobject (*GetStaticObjectField)(JNIEnv *env, jclass clazz,
				    jfieldID fieldID);
    jboolean (*GetStaticBooleanField)(JNIEnv *env, jclass clazz,
				      jfieldID fieldID);
    jbyte (*GetStaticByteField)(JNIEnv *env, jclass clazz,
				jfieldID fieldID);
    jchar (*GetStaticCharField)(JNIEnv *env, jclass clazz,
				jfieldID fieldID);
    jshort (*GetStaticShortField)(JNIEnv *env, jclass clazz,
				  jfieldID fieldID);
    jint (*GetStaticIntField)(JNIEnv *env, jclass clazz,
			      jfieldID fieldID);
    jlong (*GetStaticLongField)(JNIEnv *env, jclass clazz,
				jfieldID fieldID);
    jfloat (*GetStaticFloatField)(JNIEnv *env, jclass clazz,
				  jfieldID fieldID);
    jdouble (*GetStaticDoubleField)(JNIEnv *env, jclass clazz,
				    jfieldID fieldID);

    void (*SetStaticObjectField)(JNIEnv *env, jclass clazz,
				 jfieldID fieldID, jobject value);
    void (*SetStaticBooleanField)(JNIEnv *env, jclass clazz,
				  jfieldID fieldID, jboolean value);
    void (*SetStaticByteField)(JNIEnv *env, jclass clazz,
			       jfieldID fieldID, jbyte value);
    void (*SetStaticCharField)(JNIEnv *env, jclass clazz,
			       jfieldID fieldID, jchar value);
    void (*SetStaticShortField)(JNIEnv *env, jclass clazz,
				jfieldID fieldID, jshort value);
    void (*SetStaticIntField)(JNIEnv *env, jclass clazz,
			      jfieldID fieldID, jint value);
    void (*SetStaticLongField)(JNIEnv *env, jclass clazz,
			       jfieldID fieldID, jlong value);
    void (*SetStaticFloatField)(JNIEnv *env, jclass clazz,
				jfieldID fieldID, jfloat value);
    void (*SetStaticDoubleField)(JNIEnv *env, jclass clazz,
				 jfieldID fieldID, jdouble value);


    jstring (*NewString)(JNIEnv *env, const jchar *unicodeChars, jsize len);
    jsize (*GetStringLength)(JNIEnv *env, jstring string);
    jchar* (*GetStringChars)(JNIEnv *env, jstring string, jboolean *isCopy);
    void (*ReleaseStringChars)(JNIEnv *env, jstring string, const jchar *chars);

    jstring (*NewStringUTF)(JNIEnv *env, const char *bytes);
    jsize (*GetStringUTFLength)(JNIEnv *env, jstring string);
    const jbyte* (*GetStringUTFChars)(JNIEnv *env, jstring string, jboolean *isCopy);
    void (*ReleaseStringUTFChars)(JNIEnv *env, jstring string, const jbyte *utf);

    jsize (*GetArrayLength)(JNIEnv *env, jarray array);

    jarray (*NewObjectArray)(JNIEnv *env, jsize length,
			     jclass elementClass, jobject initialElement);
    jobject (*GetObjectArrayElement)(JNIEnv *env, jobjectArray array, jsize index);
    void (*SetObjectArrayElement)(JNIEnv *env, jobjectArray array,
				  jsize index, jobject value);

    jbooleanArray (*NewBooleanArray)(JNIEnv *env, jsize length);
    jbyteArray (*NewByteArray)(JNIEnv *env, jsize length);
    jcharArray (*NewCharArray)(JNIEnv *env, jsize length);
    jshortArray (*NewShortArray)(JNIEnv *env, jsize length);
    jintArray (*NewIntArray)(JNIEnv *env, jsize length);
    jlongArray (*NewLongArray)(JNIEnv *env, jsize length);
    jfloatArray (*NewFloatArray)(JNIEnv *env, jsize length);
    jdoubleArray (*NewDoubleArray)(JNIEnv *env, jsize length);

    jboolean* (*GetBooleanArrayElements)(JNIEnv *env, jbooleanArray array,
					 jboolean* isCopy);
    jbyte* (*GetByteArrayElements)(JNIEnv *env, jbyteArray array,
				   jboolean* isCopy);
    jchar* (*GetCharArrayElements)(JNIEnv *env, jcharArray array,
				   jboolean* isCopy);
    jshort* (*GetShortArrayElements)(JNIEnv *env, jshortArray array,
				     jboolean* isCopy);
    jint* (*GetIntArrayElements)(JNIEnv *env, jintArray array,
				 jboolean* isCopy);
    jlong* (*GetLongArrayElements)(JNIEnv *env, jlongArray array,
				   jboolean* isCopy);
    jfloat* (*GetFloatArrayElements)(JNIEnv *env, jfloatArray array,
				     jboolean* isCopy);
    jdouble* (*GetDoubleArrayElements)(JNIEnv *env, jdoubleArray array,
				       jboolean* isCopy);

    void (*ReleaseBooleanArrayElements)(JNIEnv *env, jbooleanArray array,
					jboolean* elems, jint mode);
    void (*ReleaseByteArrayElements)(JNIEnv *env, jbyteArray array,
				     jbyte* elems, jint mode);
    void (*ReleaseCharArrayElements)(JNIEnv *env, jcharArray array,
				     jchar* elems, jint mode);
    void (*ReleaseShortArrayElements)(JNIEnv *env, jshortArray array,
				      jshort* elems, jint mode);
    void (*ReleaseIntArrayElements)(JNIEnv *env, jintArray array,
				    jint* elems, jint mode);
    void (*ReleaseLongArrayElements)(JNIEnv *env, jlongArray array,
				     jlong* elems, jint mode);
    void (*ReleaseFloatArrayElements)(JNIEnv *env, jfloatArray array,
				      jfloat* elems, jint mode);
    void (*ReleaseDoubleArrayElements)(JNIEnv *env, jdoubleArray array,
				       jdouble* elems, jint mode);

    void (*GetBooleanArrayRegion)(JNIEnv *env, jbooleanArray array,
				  jsize start, jsize len, jboolean* buf);
    void (*GetByteArrayRegion)(JNIEnv *env, jbyteArray array,
			       jsize start, jsize len, jbyte* buf);
    void (*GetCharArrayRegion)(JNIEnv *env, jcharArray array,
			       jsize start, jsize len, jchar* buf);
    void (*GetShortArrayRegion)(JNIEnv *env, jshortArray array,
				jsize start, jsize len, jshort* buf);
    void (*GetIntArrayRegion)(JNIEnv *env, jintArray array,
			      jsize start, jsize len, jint* buf);
    void (*GetLongArrayRegion)(JNIEnv *env, jlongArray array,
			       jsize start, jsize len, jlong* buf);
    void (*GetFloatArrayRegion)(JNIEnv *env, jfloatArray array,
				jsize start, jsize len, jfloat* buf);
    void (*GetDoubleArrayRegion)(JNIEnv *env, jdoubleArray array,
				 jsize start, jsize len, jdouble* buf);

    void (*SetBooleanArrayRegion)(JNIEnv *env, jbooleanArray array,
				  jsize start, jsize len, jboolean* buf);
    void (*SetByteArrayRegion)(JNIEnv *env, jbyteArray array,
			       jsize start, jsize len, jbyte* buf);
    void (*SetCharArrayRegion)(JNIEnv *env, jcharArray array,
			       jsize start, jsize len, jchar* buf);
    void (*SetShortArrayRegion)(JNIEnv *env, jshortArray array,
				jsize start, jsize len, jshort* buf);
    void (*SetIntArrayRegion)(JNIEnv *env, jintArray array,
			      jsize start, jsize len, jint* buf);
    void (*SetLongArrayRegion)(JNIEnv *env, jlongArray array,
			       jsize start, jsize len, jlong* buf);
    void (*SetFloatArrayRegion)(JNIEnv *env, jfloatArray array,
				jsize start, jsize len, jfloat* buf);
    void (*SetDoubleArrayRegion)(JNIEnv *env, jdoubleArray array,
				 jsize start, jsize len, jdouble* buf);
  
    jint (*RegisterNatives)(JNIEnv *env, jclass clazz,
			    const JNINativeMethod *methods, jint nMethods);
    jint (*UnregisterNatives)(JNIEnv *env, jclass clazz);

    jint (*MonitorEnter)(JNIEnv *env, jobject obj);
    jint (*MonitorExit)(JNIEnv *env, jobject obj);

    jint (*GetJavaVM)(JNIEnv *env, JavaVM **vm);

    /* new for JDK 1.2 */

    /* local reference management */
    jint (*EnsureLocalCapacity)(JNIEnv *env, jint capacity);
    jint (*PushLocalFrame)(JNIEnv *env, jint capacity);
    jobject (*PopLocalFrame)(JNIEnv *env, jobject result);
    jobject (*NewLocalRef)(JNIEnv *env, jobject ref);

    /* weak global references */
    jweak (*NewWeakGlobalRef)(JNIEnv *env, jobject obj);
    void (*DeleteWeakGlobalRef)(JNIEnv *env, jweak obj);

    /* array operations */
    void* (*GetPrimitiveArrayCritical)(JNIEnv *env, jarray array, jboolean *isCopy);
    void (*ReleasePrimitiveArrayCritical)(JNIEnv *env, jarray array, void *carray, jint mode);

    /* string operations */
    void (*GetStringRegion)(JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf);
    void (*GetStringUTFRegion)(JNIEnv *env, jstring str, jsize start, jsize len, char *buf);

    const jchar* (*GetStringCritical)(JNIEnv *env, jstring string, jboolean *isCopy);
    void (*ReleaseStringCritical)(JNIEnv *env, jstring string, const jchar *carray);

    /* reflection support */
    jmethodID (*FromReflectedMethod)(JNIEnv *env, jobject method);
    jfieldID (*FromReflectedField)(JNIEnv *env, jobject field);
    jobject (*ToReflectedMethod)(JNIEnv *env, jclass cls, jmethodID methodID);
    jobject (*ToReflectedField)(JNIEnv *env, jclass cls, jfieldID fieldID);
  };

#ifdef __cplusplus
  extern struct JNINativeInterface _hungryJNIInterface;

  struct JNIEnv {
    JNINativeInterface *_vtable;

    JNIEnv() {
      _vtable = &_hungryJNIInterface;
    }

    jint GetVersion() {
      return _vtable->GetVersion(this);
    };

    jclass DefineClass(jobject loader, const jbyte* buf, jsize bufLen) {
      return _vtable->DefineClass(this, loader, buf, bufLen);
    }

    jclass FindClass(const char *name) {
      return _vtable->FindClass(this, name);
    }

    jclass GetSuperclass(jclass clazz) {
      return _vtable->GetSuperclass(this, clazz);
    }

    jboolean IsAssignableFrom(jclass clazz1, jclass clazz2) {
      return _vtable->IsAssignableFrom(this, clazz1, clazz2);
    }

    jint Throw(jthrowable obj) {
      return _vtable->Throw(this, obj);
    }

    jint ThrowNew(jclass clazz, const char *message) {
      return _vtable->ThrowNew(this, clazz, message);
    }

    jthrowable ExceptionOccurred() {
      return _vtable->ExceptionOccurred(this);
    }

    void ExceptionDescribe() {
      _vtable->ExceptionDescribe(this);
    }

    void ExceptionClear() {
      _vtable->ExceptionClear(this);
    }

    jobject NewGlobalRef(jobject obj) {
      return _vtable->NewGlobalRef(this, obj);
    }

    void DeleteGlobalRef(jobject globalRef) {
      _vtable->DeleteGlobalRef(this, globalRef);
    }

    void DeleteLocalRef(jobject localRef) {
      _vtable->DeleteLocalRef(this, localRef);
    }

    jboolean IsSameObject(jobject ref, jobject ref2) {
      return _vtable->IsSameObject(this, ref, ref2);
    }

    jobject AllocObject(jclass clazz) {
      return _vtable->AllocObject(this, clazz);
    }

    jobject NewObject(jclass clazz, jmethodID methodID, ...) {
      va_list varargs;
      jobject object = _vtable->AllocObject(this, clazz);

      if (object == NULL) return NULL;

      va_start(varargs, methodID);
      _vtable->CallNonvirtualVoidMethodV(this, object, methodID, varargs);
      va_end(varargs);

      return object;
    }

    jobject NewObjectV(jclass clazz, jmethodID methodID, va_list args) {
      return _vtable->NewObjectV(this, clazz, methodID, args);
    }

    jobject NewObjectA(jclass clazz, jmethodID methodID, jvalue *args) {
      return _vtable->NewObjectA(this, clazz, methodID, args);
    }

    jclass GetObjectClass(jobject obj) {
      return _vtable->GetObjectClass(this, obj);
    }

    jboolean IsInstanceOf(jobject obj, jclass clazz) {
      return _vtable->IsInstanceOf(this, obj, clazz);
    }

    jmethodID GetMethodID(jclass clazz, const char *name, const char *sig) {
      return _vtable->GetMethodID(this, clazz, name, sig);
    }

    jobject CallObjectMethod(jobject obj, jmethodID methodID, ...) {
      va_list varargs;
      jobject result;
    
      va_start(varargs, methodID);
      result = _vtable->CallObjectMethodV(this, obj, methodID, varargs);
      va_end(varargs);
    
      return result;
    }

    jobject CallObjectMethodV(jobject obj, jmethodID methodID, va_list args) {
      return _vtable->CallObjectMethodV(this, obj, methodID, args);
    }

    jobject CallObjectMethodA(jobject obj, jmethodID methodID, jvalue *args) {
      return _vtable->CallObjectMethodA(this, obj, methodID, args);
    }

    jboolean CallBooleanMethod(jobject obj, jmethodID methodID, ...) {
      va_list varargs;
      jboolean result;
    
      va_start(varargs, methodID);
      result = _vtable->CallBooleanMethodV(this, obj, methodID, varargs);
      va_end(varargs);
    
      return result;
    }

    jboolean CallBooleanMethodV(jobject obj, jmethodID methodID, va_list args) {
      return _vtable->CallBooleanMethodV(this, obj, methodID, args);
    }

    jboolean CallBooleanMethodA(jobject obj, jmethodID methodID, jvalue *args) {
      return _vtable->CallBooleanMethodA(this, obj, methodID, args);
    }

    jbyte CallByteMethod(jobject obj, jmethodID methodID, ...) {
      va_list varargs;
      jbyte result;
    
      va_start(varargs, methodID);
      result = _vtable->CallByteMethodV(this, obj, methodID, varargs);
      va_end(varargs);
    
      return result;
    }

    jbyte CallByteMethodV(jobject obj, jmethodID methodID, va_list args) {
      return _vtable->CallByteMethodV(this, obj, methodID, args);
    }

    jbyte CallByteMethodA(jobject obj, jmethodID methodID, jvalue *args) {
      return _vtable->CallByteMethodA(this, obj, methodID, args);
    }

    jchar CallCharMethod(jobject obj, jmethodID methodID, ...) {
      va_list varargs;
      jchar result;
    
      va_start(varargs, methodID);
      result = _vtable->CallCharMethodV(this, obj, methodID, varargs);
      va_end(varargs);
    
      return result;
    }

    jchar CallCharMethodV(jobject obj, jmethodID methodID, va_list args) {
      return _vtable->CallCharMethodV(this, obj, methodID, args);
    }

    jchar CallCharMethodA(jobject obj, jmethodID methodID, jvalue *args) {
      return _vtable->CallCharMethodA(this, obj, methodID, args);
    }

    jshort CallShortMethod(jobject obj, jmethodID methodID, ...) {
      va_list varargs;
      jshort result;
    
      va_start(varargs, methodID);
      result = _vtable->CallShortMethodV(this, obj, methodID, varargs);
      va_end(varargs);
    
      return result;
    }

    jshort CallShortMethodV(jobject obj, jmethodID methodID, va_list args) {
      return _vtable->CallShortMethodV(this, obj, methodID, args);
    }

    jshort CallShortMethodA(jobject obj, jmethodID methodID, jvalue *args) {
      return _vtable->CallShortMethodA(this, obj, methodID, args);
    }

    jint CallIntMethod(jobject obj, jmethodID methodID, ...) {
      va_list varargs;
      jint result;
    
      va_start(varargs, methodID);
      result = _vtable->CallIntMethodV(this, obj, methodID, varargs);
      va_end(varargs);
    
      return result;
    }

    jint CallIntMethodV(jobject obj, jmethodID methodID, va_list args) {
      return _vtable->CallIntMethodV(this, obj, methodID, args);
    }

    jint CallIntMethodA(jobject obj, jmethodID methodID, jvalue *args) {
      return _vtable->CallIntMethodA(this, obj, methodID, args);
    }

    jlong CallLongMethod(jobject obj, jmethodID methodID, ...) {
      va_list varargs;
      jlong result;
    
      va_start(varargs, methodID);
      result = _vtable->CallLongMethodV(this, obj, methodID, varargs);
      va_end(varargs);
    
      return result;
    }

    jlong CallLongMethodV(jobject obj, jmethodID methodID, va_list args) {
      return _vtable->CallLongMethodV(this, obj, methodID, args);
    }

    jlong CallLongMethodA(jobject obj, jmethodID methodID, jvalue *args) {
      return _vtable->CallLongMethodA(this, obj, methodID, args);
    }

    jfloat CallFloatMethod(jobject obj, jmethodID methodID, ...) {
      va_list varargs;
      jfloat result;
    
      va_start(varargs, methodID);
      result = _vtable->CallFloatMethodV(this, obj, methodID, varargs);
      va_end(varargs);
    
      return result;
    }

    jfloat CallFloatMethodV(jobject obj, jmethodID methodID, va_list args) {
      return _vtable->CallFloatMethodV(this, obj, methodID, args);
    }

    jfloat CallFloatMethodA(jobject obj, jmethodID methodID, jvalue *args) {
      return _vtable->CallFloatMethodA(this, obj, methodID, args);
    }

    jdouble CallDoubleMethod(jobject obj, jmethodID methodID, ...) {
      va_list varargs;
      jdouble result;
    
      va_start(varargs, methodID);
      result = _vtable->CallDoubleMethodV(this, obj, methodID, varargs);
      va_end(varargs);
    
      return result;
    }

    jdouble CallDoubleMethodV(jobject obj, jmethodID methodID, va_list args) {
      return _vtable->CallDoubleMethodV(this, obj, methodID, args);
    }

    jdouble CallDoubleMethodA(jobject obj, jmethodID methodID, jvalue *args) {
      return _vtable->CallDoubleMethodA(this, obj, methodID, args);
    }

    void CallVoidMethod(jobject obj, jmethodID methodID, ...) {
      va_list varargs;
    
      va_start(varargs, methodID);
      _vtable->CallVoidMethodV(this, obj, methodID, varargs);
      va_end(varargs);
    }

    void CallVoidMethodV(jobject obj, jmethodID methodID, va_list args) {
      _vtable->CallVoidMethodV(this, obj, methodID, args);
    }

    void CallVoidMethodA(jobject obj, jmethodID methodID, jvalue *args) {
      _vtable->CallVoidMethodA(this, obj, methodID, args);
    }

    jobject CallNonvirtualObjectMethod(jobject obj, jmethodID methodID, ...) {
      va_list varargs;
      jobject result;
    
      va_start(varargs, methodID);
      result = _vtable->CallNonvirtualObjectMethodV(this, obj, methodID, varargs);
      va_end(varargs);
    
      return result;
    }

    jobject CallNonvirtualObjectMethodV(jobject obj, jmethodID methodID, va_list args) {
      return _vtable->CallNonvirtualObjectMethodV(this, obj, methodID, args);
    }

    jobject CallNonvirtualObjectMethodA(jobject obj, jmethodID methodID, jvalue *args) {
      return _vtable->CallNonvirtualObjectMethodA(this, obj, methodID, args);
    }

    jboolean CallNonvirtualBooleanMethod(jobject obj, jmethodID methodID, ...) {
      va_list varargs;
      jboolean result;
    
      va_start(varargs, methodID);
      result = _vtable->CallNonvirtualBooleanMethodV(this, obj, methodID, varargs);
      va_end(varargs);
    
      return result;
    }

    jboolean CallNonvirtualBooleanMethodV(jobject obj, jmethodID methodID, va_list args) {
      return _vtable->CallNonvirtualBooleanMethodV(this, obj, methodID, args);
    }

    jboolean CallNonvirtualBooleanMethodA(jobject obj, jmethodID methodID, jvalue *args) {
      return _vtable->CallNonvirtualBooleanMethodA(this, obj, methodID, args);
    }

    jbyte CallNonvirtualByteMethod(jobject obj, jmethodID methodID, ...) {
      va_list varargs;
      jbyte result;
    
      va_start(varargs, methodID);
      result = _vtable->CallNonvirtualByteMethodV(this, obj, methodID, varargs);
      va_end(varargs);
    
      return result;
    }

    jbyte CallNonvirtualByteMethodV(jobject obj, jmethodID methodID, va_list args) {
      return _vtable->CallNonvirtualByteMethodV(this, obj, methodID, args);
    }

    jbyte CallNonvirtualByteMethodA(jobject obj, jmethodID methodID, jvalue *args) {
      return _vtable->CallNonvirtualByteMethodA(this, obj, methodID, args);
    }

    jchar CallNonvirtualCharMethod(jobject obj, jmethodID methodID, ...) {
      va_list varargs;
      jchar result;
    
      va_start(varargs, methodID);
      result = _vtable->CallNonvirtualCharMethodV(this, obj, methodID, varargs);
      va_end(varargs);
    
      return result;
    }

    jchar CallNonvirtualCharMethodV(jobject obj, jmethodID methodID, va_list args) {
      return _vtable->CallNonvirtualCharMethodV(this, obj, methodID, args);
    }

    jchar CallNonvirtualCharMethodA(jobject obj, jmethodID methodID, jvalue *args) {
      return _vtable->CallNonvirtualCharMethodA(this, obj, methodID, args);
    }

    jshort CallNonvirtualShortMethod(jobject obj, jmethodID methodID, ...) {
      va_list varargs;
      jshort result;
    
      va_start(varargs, methodID);
      result = _vtable->CallNonvirtualShortMethodV(this, obj, methodID, varargs);
      va_end(varargs);
    
      return result;
    }

    jshort CallNonvirtualShortMethodV(jobject obj, jmethodID methodID, va_list args) {
      return _vtable->CallNonvirtualShortMethodV(this, obj, methodID, args);
    }

    jshort CallNonvirtualShortMethodA(jobject obj, jmethodID methodID, jvalue *args) {
      return _vtable->CallNonvirtualShortMethodA(this, obj, methodID, args);
    }

    jint CallNonvirtualIntMethod(jobject obj, jmethodID methodID, ...) {
      va_list varargs;
      jint result;
    
      va_start(varargs, methodID);
      result = _vtable->CallNonvirtualIntMethodV(this, obj, methodID, varargs);
      va_end(varargs);
    
      return result;
    }

    jint CallNonvirtualIntMethodV(jobject obj, jmethodID methodID, va_list args) {
      return _vtable->CallNonvirtualIntMethodV(this, obj, methodID, args);
    }

    jint CallNonvirtualIntMethodA(jobject obj, jmethodID methodID, jvalue *args) {
      return _vtable->CallNonvirtualIntMethodA(this, obj, methodID, args);
    }

    jlong CallNonvirtualLongMethod(jobject obj, jmethodID methodID, ...) {
      va_list varargs;
      jlong result;
    
      va_start(varargs, methodID);
      result = _vtable->CallNonvirtualLongMethodV(this, obj, methodID, varargs);
      va_end(varargs);
    
      return result;
    }

    jlong CallNonvirtualLongMethodV(jobject obj, jmethodID methodID, va_list args) {
      return _vtable->CallNonvirtualLongMethodV(this, obj, methodID, args);
    }

    jlong CallNonvirtualLongMethodA(jobject obj, jmethodID methodID, jvalue *args) {
      return _vtable->CallNonvirtualLongMethodA(this, obj, methodID, args);
    }

    jfloat CallNonvirtualFloatMethod(jobject obj, jmethodID methodID, ...) {
      va_list varargs;
      jfloat result;
    
      va_start(varargs, methodID);
      result = _vtable->CallNonvirtualFloatMethodV(this, obj, methodID, varargs);
      va_end(varargs);
    
      return result;
    }

    jfloat CallNonvirtualFloatMethodV(jobject obj, jmethodID methodID, va_list args) {
      return _vtable->CallNonvirtualFloatMethodV(this, obj, methodID, args);
    }

    jfloat CallNonvirtualFloatMethodA(jobject obj, jmethodID methodID, jvalue *args) {
      return _vtable->CallNonvirtualFloatMethodA(this, obj, methodID, args);
    }

    jdouble CallNonvirtualDoubleMethod(jobject obj, jmethodID methodID, ...) {
      va_list varargs;
      jdouble result;
    
      va_start(varargs, methodID);
      result = _vtable->CallNonvirtualDoubleMethodV(this, obj, methodID, varargs);
      va_end(varargs);
    
      return result;
    }

    jdouble CallNonvirtualDoubleMethodV(jobject obj, jmethodID methodID, va_list args) {
      return _vtable->CallNonvirtualDoubleMethodV(this, obj, methodID, args);
    }

    jdouble CallNonvirtualDoubleMethodA(jobject obj, jmethodID methodID, jvalue *args) {
      return _vtable->CallNonvirtualDoubleMethodA(this, obj, methodID, args);
    }

    void CallNonvirtualVoidMethod(jobject obj, jmethodID methodID, ...) {
      va_list varargs;
    
      va_start(varargs, methodID);
      _vtable->CallNonvirtualVoidMethodV(this, obj, methodID, varargs);
      va_end(varargs);
    }

    void CallNonvirtualVoidMethodV(jobject obj, jmethodID methodID, va_list args) {
      _vtable->CallNonvirtualVoidMethodV(this, obj, methodID, args);
    }

    void CallNonvirtualVoidMethodA(jobject obj, jmethodID methodID, jvalue *args) {
      _vtable->CallNonvirtualVoidMethodA(this, obj, methodID, args);
    }

    jfieldID GetFieldID(jclass clazz, const char *name, const char *sig) {
      return _vtable->GetFieldID(this, clazz, name, sig);
    }

    jobject GetObjectField(jobject obj, jfieldID fieldID) {
      return _vtable->GetObjectField(this, obj, fieldID);
    }

    jboolean GetBooleanField(jobject obj, jfieldID fieldID) {
      return _vtable->GetBooleanField(this, obj, fieldID);
    }

    jbyte GetByteField(jobject obj, jfieldID fieldID) {
      return _vtable->GetByteField(this, obj, fieldID);
    }

    jchar GetCharField(jobject obj, jfieldID fieldID) {
      return _vtable->GetCharField(this, obj, fieldID);
    }

    jshort GetShortField(jobject obj, jfieldID fieldID) {
      return _vtable->GetShortField(this, obj, fieldID);
    }

    jint GetIntField(jobject obj, jfieldID fieldID) {
      return _vtable->GetIntField(this, obj, fieldID);
    }

    jlong GetLongField(jobject obj, jfieldID fieldID) {
      return _vtable->GetLongField(this, obj, fieldID);
    }

    jfloat GetFloatField(jobject obj, jfieldID fieldID) {
      return _vtable->GetFloatField(this, obj, fieldID);
    }

    jdouble GetDoubleField(jobject obj, jfieldID fieldID) {
      return _vtable->GetDoubleField(this, obj, fieldID);
    }

    void SetObjectField(jobject obj, jfieldID fieldID, jobject value) {
      _vtable->SetObjectField(this, obj, fieldID, value);
    }

    void SetBooleanField(jobject obj, jfieldID fieldID, jboolean value) {
      _vtable->SetBooleanField(this, obj, fieldID, value);
    }

    void SetByteField(jobject obj, jfieldID fieldID, jbyte value) {
      _vtable->SetByteField(this, obj, fieldID, value);
    }

    void SetCharField(jobject obj, jfieldID fieldID, jchar value) {
      _vtable->SetCharField(this, obj, fieldID, value);
    }

    void SetShortField(jobject obj, jfieldID fieldID, jshort value) {
      _vtable->SetShortField(this, obj, fieldID, value);
    }

    void SetIntField(jobject obj, jfieldID fieldID, jint value) {
      _vtable->SetIntField(this, obj, fieldID, value);
    }

    void SetLongField(jobject obj, jfieldID fieldID, jlong value) {
      _vtable->SetLongField(this, obj, fieldID, value);
    }

    void SetFloatField(jobject obj, jfieldID fieldID, jfloat value) {
      _vtable->SetFloatField(this, obj, fieldID, value);
    }

    void SetDoubleField(jobject obj, jfieldID fieldID, jdouble value) {
      _vtable->SetDoubleField(this, obj, fieldID, value);
    }

    jmethodID GetStaticMethodID(jclass clazz, const char *name, const char *sig) {
      return _vtable->GetStaticMethodID(this, clazz, name, sig);
    }

    jobject CallStaticObjectMethod(jclass clazz, jmethodID methodID, ...) {
      va_list varargs;
      jobject result;

      va_start(varargs, methodID);
      result = _vtable->CallStaticObjectMethodV(this, clazz, methodID, varargs);
      va_end(varargs);

      return result;
    }
  
    jobject CallStaticObjectMethodV(jclass clazz, jmethodID methodID, va_list args) {
      return _vtable->CallStaticObjectMethodV(this, clazz, methodID, args);
    }

    jobject CallStaticObjectMethodA(jclass clazz, jmethodID methodID, jvalue *args) {
      return _vtable->CallStaticObjectMethodA(this, clazz, methodID, args);
    }

    jboolean CallStaticBooleanMethod(jclass clazz, jmethodID methodID, ...) {
      va_list varargs;
      jboolean result;
    
      va_start(varargs, methodID);
      result = _vtable->CallStaticBooleanMethodV(this, clazz, methodID, varargs);
      va_end(varargs);

      return result;
    }

    jboolean CallStaticBooleanMethodV(jclass clazz, jmethodID methodID, va_list args) {
      return _vtable->CallStaticBooleanMethodV(this, clazz, methodID, args);
    }


    jboolean CallStaticBooleanMethodA(jclass clazz, jmethodID methodID, jvalue *args) {
      return _vtable->CallStaticBooleanMethodA(this, clazz, methodID, args);
    }

    jbyte CallStaticByteMethod(jclass clazz, jmethodID methodID, ...) {
      va_list varargs;
      jbyte result;
    
      va_start(varargs, methodID);
      result = _vtable->CallStaticByteMethodV(this, clazz, methodID, varargs);
      va_end(varargs);

      return result;
    }

    jbyte CallStaticByteMethodV(jclass clazz, jmethodID methodID, va_list args) {
      return _vtable->CallStaticByteMethodV(this, clazz, methodID, args);
    }

    jbyte CallStaticByteMethodA(jclass clazz, jmethodID methodID, jvalue *args) {
      return _vtable->CallStaticByteMethodA(this, clazz, methodID, args);
    }

    jchar CallStaticCharMethod(jclass clazz, jmethodID methodID, ...) {
      va_list varargs;
      jchar result;
    
      va_start(varargs, methodID);
      result = _vtable->CallStaticCharMethodV(this, clazz, methodID, varargs);
      va_end(varargs);

      return result;
    }

    jchar CallStaticCharMethodV(jclass clazz, jmethodID methodID, va_list args) {
      return _vtable->CallStaticCharMethodV(this, clazz, methodID, args);
    }

    jchar CallStaticCharMethodA(jclass clazz, jmethodID methodID, jvalue *args) {
      return _vtable->CallStaticCharMethodA(this, clazz, methodID, args);
    }

    jshort CallStaticShortMethod(jclass clazz, jmethodID methodID, ...) {
      va_list varargs;
      jshort result;
    
      va_start(varargs, methodID);
      result = _vtable->CallStaticShortMethodV(this, clazz, methodID, varargs);
      va_end(varargs);

      return result;
    }

    jshort CallStaticShortMethodV(jclass clazz, jmethodID methodID, va_list args) {
      return _vtable->CallStaticShortMethodV(this, clazz, methodID, args);
    }

    jshort CallStaticShortMethodA(jclass clazz, jmethodID methodID, jvalue *args) {
      return _vtable->CallStaticShortMethodA(this, clazz, methodID, args);
    }

    jint CallStaticIntMethod(jclass clazz, jmethodID methodID, ...) {
      va_list varargs;
      jint result;
    
      va_start(varargs, methodID);
      result = _vtable->CallStaticIntMethodV(this, clazz, methodID, varargs);
      va_end(varargs);

      return result;
    }

    jint CallStaticIntMethodV(jclass clazz, jmethodID methodID, va_list args) {
      return _vtable->CallStaticIntMethodV(this, clazz, methodID, args);
    }

    jint CallStaticIntMethodA(jclass clazz, jmethodID methodID, jvalue *args) {
      return _vtable->CallStaticIntMethodA(this, clazz, methodID, args);
    }

    jlong CallStaticLongMethod(jclass clazz, jmethodID methodID, ...) {
      va_list varargs;
      jlong result;
    
      va_start(varargs, methodID);
      result = _vtable->CallStaticLongMethodV(this, clazz, methodID, varargs);
      va_end(varargs);

      return result;
    }

    jlong CallStaticLongMethodV(jclass clazz, jmethodID methodID, va_list args) {
      return _vtable->CallStaticLongMethodV(this, clazz, methodID, args);
    }
  
    jlong CallStaticLongMethodA(jclass clazz, jmethodID methodID, jvalue *args) {
      return _vtable->CallStaticLongMethodA(this, clazz, methodID, args);
    }
  
    jfloat CallStaticFloatMethod(jclass clazz, jmethodID methodID, ...) {
      va_list varargs;
      jfloat result;
    
      va_start(varargs, methodID);
      result = _vtable->CallStaticFloatMethodV(this, clazz, methodID, varargs);
      va_end(varargs);

      return result;
    }
  
    jfloat CallStaticFloatMethodV(jclass clazz, jmethodID methodID, va_list args) {
      return _vtable->CallStaticFloatMethodV(this, clazz, methodID, args);
    }
  
    jfloat CallStaticFloatMethodA(jclass clazz, jmethodID methodID, jvalue *args) {
      return _vtable->CallStaticFloatMethodA(this, clazz, methodID, args);
    }
  
    jdouble CallStaticDoubleMethod(jclass clazz,  jmethodID methodID, ...) {
      va_list varargs;
      jdouble result;
    
      va_start(varargs, methodID);
      result = _vtable->CallStaticDoubleMethodV(this, clazz, methodID, varargs);
      va_end(varargs);

      return result;
    }
  
    jdouble CallStaticDoubleMethodV(jclass clazz, jmethodID methodID, va_list args) {
      return _vtable->CallStaticDoubleMethodV(this, clazz, methodID, args);
    }
  
    jdouble CallStaticDoubleMethodA(jclass clazz, jmethodID methodID, jvalue *args) {
      return _vtable->CallStaticDoubleMethodA(this, clazz, methodID, args);
    }
  
    void CallStaticVoidMethod(jclass clazz, jmethodID methodID, ...) {
      va_list varargs;
    
      va_start(varargs, methodID);
      _vtable->CallStaticVoidMethodV(this, clazz, methodID, varargs);
      va_end(varargs);
    }
  
    void CallStaticVoidMethodV(jclass clazz, jmethodID methodID, va_list args) {
      _vtable->CallStaticVoidMethodV(this, clazz, methodID, args);
    }
  
    void CallStaticVoidMethodA(jclass clazz, jmethodID methodID, jvalue *args) {
      _vtable->CallStaticVoidMethodA(this, clazz, methodID, args);
    }
  
  
    jfieldID GetStaticFieldID(jclass clazz, const char *name, const char *sig) {
      return _vtable->GetStaticFieldID(this, clazz, name, sig);
    }


    jobject GetStaticObjectField(jclass clazz, jfieldID fieldID) {
      return _vtable->GetStaticObjectField(this, clazz, fieldID);
    }

    jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID) {
      return _vtable->GetStaticBooleanField(this, clazz, fieldID);
    }

    jbyte GetStaticByteField(jclass clazz, jfieldID fieldID) {
      return _vtable->GetStaticByteField(this, clazz, fieldID);
    }

    jchar GetStaticCharField(jclass clazz, jfieldID fieldID) {
      return _vtable->GetStaticCharField(this, clazz, fieldID);
    }

    jshort GetStaticShortField(jclass clazz, jfieldID fieldID) {
      return _vtable->GetStaticShortField(this, clazz, fieldID);
    }

    jint GetStaticIntField(jclass clazz, jfieldID fieldID) {
      return _vtable->GetStaticIntField(this, clazz, fieldID);
    }

    jlong GetStaticLongField(jclass clazz, jfieldID fieldID) {
      return _vtable->GetStaticLongField(this, clazz, fieldID);
    }

    jfloat GetStaticFloatField(jclass clazz, jfieldID fieldID) {
      return _vtable->GetStaticFloatField(this, clazz, fieldID);
    }

    jdouble GetStaticDoubleField(jclass clazz, jfieldID fieldID) {
      return _vtable->GetStaticDoubleField(this, clazz, fieldID);
    }

    void SetStaticObjectField(jclass clazz, jfieldID fieldID, jobject value) {
      _vtable->SetStaticObjectField(this, clazz, fieldID, value);
    }

    void SetStaticBooleanField(jclass clazz, jfieldID fieldID, jboolean value) {
      _vtable->SetStaticBooleanField(this, clazz, fieldID, value);
    }

    void SetStaticByteField(jclass clazz, jfieldID fieldID, jbyte value) {
      _vtable->SetStaticByteField(this, clazz, fieldID, value);
    }

    void SetStaticCharField(jclass clazz, jfieldID fieldID, jchar value) {
      _vtable->SetStaticCharField(this, clazz, fieldID, value);
    }

    void SetStaticShortField(jclass clazz, jfieldID fieldID, jshort value) {
      _vtable->SetStaticShortField(this, clazz, fieldID, value);
    }

    void SetStaticIntField(jclass clazz, jfieldID fieldID, jint value) {
      _vtable->SetStaticIntField(this, clazz, fieldID, value);
    }
  
    void SetStaticLongField(jclass clazz, jfieldID fieldID, jlong value) {
      _vtable->SetStaticLongField(this, clazz, fieldID, value);
    }

    void SetStaticFloatField(jclass clazz, jfieldID fieldID, jfloat value) {
      _vtable->SetStaticFloatField(this, clazz, fieldID, value);
    }

    void SetStaticDoubleField(jclass clazz, jfieldID fieldID, jdouble value) {
      _vtable->SetStaticDoubleField(this, clazz, fieldID, value);
    }

    jstring NewString(const jchar *unicodeChars, jsize len) {
      return _vtable->NewString(this, unicodeChars, len);
    }

    jsize GetStringLength(jstring string) {
      return _vtable->GetStringLength(this,string);
    }

    jchar* GetStringChars(jstring string, jboolean *isCopy) {
      return _vtable->GetStringChars(this, string, isCopy);
    }

    void ReleaseStringChars(jstring string, const jchar *chars) {
      _vtable->ReleaseStringChars(this, string, chars);
    }

    jstring NewStringUTF(const char *bytes) {
      return _vtable->NewStringUTF(this, bytes);
    }

    jsize GetStringUTFLength(jstring string) {
      return _vtable->GetStringUTFLength(this, string);
    }

    const jbyte* GetStringUTFChars(jstring string, jboolean *isCopy) {
      return _vtable->GetStringUTFChars(this, string, isCopy);
    }

    void ReleaseStringUTFChars(jstring string, const jbyte *utf) {
      _vtable->ReleaseStringUTFChars(this, string, utf);
    }

    jsize GetArrayLength(jarray array) {
      return _vtable->GetArrayLength(this, array);
    }
  
    jarray NewObjectArray(jsize length, jclass elementClass, jobject initialElement) {
      return _vtable->NewObjectArray(this, length, elementClass, initialElement);
    }

    jobject GetObjectArrayElement(jobjectArray array, jsize index) {
      return _vtable->GetObjectArrayElement(this, array, index);
    }

    void SetObjectArrayElement(jobjectArray array, jsize index, jobject value) {
      _vtable->SetObjectArrayElement(this, array, index, value);
    }

    jbooleanArray NewBooleanArray(jsize length) {
      return _vtable->NewBooleanArray(this, length);
    }

    jbyteArray NewByteArray(jsize length) {
      return _vtable->NewByteArray(this, length);
    }

    jcharArray NewCharArray(jsize length) {
      return _vtable->NewCharArray(this, length);
    }

    jshortArray NewShortArray(jsize length) {
      return _vtable->NewShortArray(this, length);
    }

    jintArray NewIntArray(jsize length) {
      return _vtable->NewIntArray(this, length);
    }

    jlongArray NewLongArray(jsize length) {
      return _vtable->NewLongArray(this, length);
    }

    jfloatArray NewFloatArray(jsize length) {
      return _vtable->NewFloatArray(this, length);
    }

    jdoubleArray NewDoubleArray(jsize length) {
      return _vtable->NewDoubleArray(this, length);
    }


    jboolean* GetBooleanArrayElements(jbooleanArray array, jboolean* isCopy) {
      return _vtable->GetBooleanArrayElements(this, array, isCopy);
    }

    jbyte* GetByteArrayElements(jbyteArray array, jboolean* isCopy) {
      return _vtable->GetByteArrayElements(this, array, isCopy);
    }

    jchar* GetCharArrayElements(jcharArray array, jboolean* isCopy) {
      return _vtable->GetCharArrayElements(this, array, isCopy);
    }

    jshort* GetShortArrayElements(jshortArray array, jboolean* isCopy) {
      return _vtable->GetShortArrayElements(this, array, isCopy);
    }

    jint* GetIntArrayElements(jintArray array, jboolean* isCopy) {
      return _vtable->GetIntArrayElements(this, array, isCopy);
    }

    jlong* GetLongArrayElements(jlongArray array, jboolean* isCopy) {
      return _vtable->GetLongArrayElements(this, array, isCopy);
    }

    jfloat* GetFloatArrayElements(jfloatArray array, jboolean* isCopy) {
      return _vtable->GetFloatArrayElements(this, array, isCopy);
    }

    jdouble* GetDoubleArrayElements(jdoubleArray array, jboolean* isCopy) {
      return _vtable->GetDoubleArrayElements(this, array, isCopy);
    }

    void ReleaseBooleanArrayElements(jbooleanArray array, jboolean* elems, jint mode) {
      _vtable->ReleaseBooleanArrayElements(this, array, elems, mode);
    }
  
    void ReleaseByteArrayElements(jbyteArray array, jbyte* elems, jint mode) {
      _vtable->ReleaseByteArrayElements(this, array, elems, mode);
    }

    void ReleaseCharArrayElements(jcharArray array, jchar* elems, jint mode) {
      _vtable->ReleaseCharArrayElements(this, array, elems, mode);
    }

    void ReleaseShortArrayElements(jshortArray array, jshort* elems, jint mode) {
      _vtable->ReleaseShortArrayElements(this, array, elems, mode);
    }

    void ReleaseIntArrayElements(jintArray array, jint* elems, jint mode) {
      _vtable->ReleaseIntArrayElements(this, array, elems, mode);
    }

    void ReleaseLongArrayElements(jlongArray array, jlong* elems, jint mode) {
      _vtable->ReleaseLongArrayElements(this, array, elems, mode);
    }

    void ReleaseFloatArrayElements(jfloatArray array, jfloat* elems, jint mode) {
      _vtable->ReleaseFloatArrayElements(this, array, elems, mode);
    }

    void ReleaseDoubleArrayElements(jdoubleArray array, jdouble* elems, jint mode) {
      _vtable->ReleaseDoubleArrayElements(this, array, elems, mode);
    }

    void GetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, jboolean* buf) {
      _vtable->GetBooleanArrayRegion(this, array, start, len, buf);
    }

    void GetByteArrayRegion(jbyteArray array, jsize start, jsize len, jbyte* buf) {
      _vtable->GetByteArrayRegion(this, array, start, len, buf);
    }

    void GetCharArrayRegion(jcharArray array, jsize start, jsize len, jchar* buf) {
      _vtable->GetCharArrayRegion(this, array, start, len, buf);
    }

    void GetShortArrayRegion(jshortArray array, jsize start, jsize len, jshort* buf) {
      _vtable->GetShortArrayRegion(this, array, start, len, buf);
    }

    void GetIntArrayRegion(jintArray array, jsize start, jsize len, jint* buf) {
      _vtable->GetIntArrayRegion(this, array, start, len, buf);
    }
  
    void GetLongArrayRegion(jlongArray array, jsize start, jsize len, jlong* buf) {
      _vtable->GetLongArrayRegion(this, array, start, len, buf);
    }

    void GetFloatArrayRegion(jfloatArray array, jsize start, jsize len, jfloat* buf) {
      _vtable->GetFloatArrayRegion(this, array, start, len, buf);
    }

    void GetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, jdouble* buf) {
      _vtable->GetDoubleArrayRegion(this, array, start, len, buf);
    }

    void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, jboolean* buf) {
      _vtable->SetBooleanArrayRegion(this, array, start, len, buf);
    }

    void SetByteArrayRegion(jbyteArray array, jsize start, jsize len, jbyte* buf) {
      _vtable->SetByteArrayRegion(this, array, start, len, buf);
    }

    void SetCharArrayRegion(jcharArray array, jsize start, jsize len, jchar* buf) {
      _vtable->SetCharArrayRegion(this, array, start, len, buf);
    }

    void SetShortArrayRegion(jshortArray array, jsize start, jsize len, jshort* buf) {
      _vtable->SetShortArrayRegion(this, array, start, len, buf);
    }

    void SetIntArrayRegion(jintArray array, jsize start, jsize len, jint* buf) {
      _vtable->SetIntArrayRegion(this, array, start, len, buf);
    }

    void SetLongArrayRegion(jlongArray array, jsize start, jsize len, jlong* buf) {
      _vtable->SetLongArrayRegion(this, array, start, len, buf);
    }

    void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len, jfloat* buf) {
      _vtable->SetFloatArrayRegion(this, array, start, len, buf);
    }

    void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, jdouble* buf) {
      _vtable->SetDoubleArrayRegion(this, array, start, len, buf);
    }

    jint RegisterNatives(jclass clazz, const JNINativeMethod *methods, jint nMethods) {
      return _vtable->RegisterNatives(this, clazz, methods, nMethods);
    }

    jint UnregisterNatives(jclass clazz) {
      return _vtable->UnregisterNatives(this, clazz);
    }

    jint MonitorEnter(jobject obj) {
      return _vtable->MonitorEnter(this, obj);
    }
  
    jint MonitorExit(jobject obj) {
      return _vtable->MonitorExit(this, obj);
    }
  
    jint GetJavaVM(JavaVM **vm) {
      return _vtable->GetJavaVM(this, vm);
    }

    /* new for JDK 1.2 */

    /* local reference management */
    jint EnsureLocalCapacity(jint capacity) {
      return _vtable->EnsureLocalCapacity(this, capacity);
    }

    jint PushLocalFrame(jint capacity) {
      return _vtable->PushLocalFrame(this, capacity);
    }

    jobject PopLocalFrame(jobject result) {
      return _vtable->PopLocalFrame(this, result);
    }

    jobject NewLocalRef(jobject ref) {
      return _vtable->NewLocalRef(this, ref);
    }

    /* weak global references */
    jweak NewWeakGlobalRef(jobject obj) {
      return _vtable->NewWeakGlobalRef(this, obj);
    }

    void DeleteWeakGlobalRef(jweak obj) {
      _vtable->DeleteWeakGlobalRef(this, obj);
    }

    /* array operations */
    void* GetPrimitiveArrayCritical(jarray array, jboolean *isCopy) {
      return _vtable->GetPrimitiveArrayCritical(this, array, isCopy);
    }

    void ReleasePrimitiveArrayCritical(jarray array, void *carray, jint mode) {
      _vtable->ReleasePrimitiveArrayCritical(this, array, carray, mode);
    }

    /* string operations */
    void GetStringRegion(jstring str, jsize start, jsize len, jchar *buf) {
      _vtable->GetStringRegion(this, str, start, len, buf);
    }

    void GetStringUTFRegion(jstring str, jsize start, jsize len, char *buf) {
      _vtable->GetStringUTFRegion(this, str, start, len, buf);
    }

    const jchar* GetStringCritical(jstring string, jboolean *isCopy) {
      return _vtable->GetStringCritical(this, string, isCopy);
    }

    void ReleaseStringCritical(jstring string, const jchar *carray) {
      _vtable->ReleaseStringCritical(this, string, carray);
    }

    /* reflection support */
    jmethodID FromReflectedMethod(jobject method) {
      return _vtable->FromReflectedMethod(this, method);
    }

    jfieldID FromReflectedField(jobject field) {
      return _vtable->FromReflectedField(this, field);
    }

    jobject ToReflectedMethod(jclass cls, jmethodID methodID) {
      return _vtable->ToReflectedMethod(this, cls, methodID);
    }

    jobject ToReflectedField(jclass cls, jfieldID fieldID) {
      return _vtable->ToReflectedField(this, cls, fieldID);
    }
  };
#endif

  /* Types needed for the JNI Invocation API */
  typedef struct JDK_1_1InitArgs {
    jint version;

    char **properties; 		/* system properties */
    jint checkSource; 		/* check if .java files are newer than .class files. */
    jint nativeStackSize;		/* max native stack size of java created threads. */
    jint javaStackSize; 		/* max java stack size */
    jint minHeapSize;		/* initial heap size */
    jint maxHeapSize;		/* max heap size */
    jint verifyMode;		/* 0 = none.  1 = remotely loaded code.  2 = all code */
    const char *classpath; 	/* local directory path for class loading */
    /* a hook for a function that redirects all VM messages. */
    jint (*vfprintf)(FILE *fp, const char *format, va_list args);
    void (*exit)(jint code);	/* a VM exit hook. */
    void (*abort)(void);		/* a VM abort hook. */
    jint enableClassGC;		/* whether to enable class GC */
    jint enableVerboseGC;		/* whether GC messages will appear */
    jint disableAsyncGC;		/* whether asynchronous GC is allowed.*/

    /* Three reserved fields. */
    jint reserved0;
    jint reserved1;
    /* XXX hungry added field... */
    jboolean enableVerboseClassLoading;
    /*  jint reserved2;*/
  } JDK1_1InitArgs;

  typedef struct JavaVMOption {
    char *optionString;
    void *extraInfo;
  } JavaVMOption;

  typedef struct JavaVMInitArgs {
    jint version;

    jint nOptions;
    JavaVMOption *options;
    jboolean ignoreUnrecognized;
  } JavaVMInitArgs;

  typedef struct JavaVMAttachArgs {
    jint version;		/* must be JNI_VERSION_1_2 */
    char *name;		/* the name of the thread, or NULL */
    jobject group;	/* global ref of a ThreadGroup object, or NULL */
  } JavaVMAttachArgs;

  struct JNIInvokeInterface {
    void *_sun1;
    void *_sun2;
    void *_sun3;
    jint (*DestroyJavaVM)(JavaVM *vm);
    jint (*AttachCurrentThread)(JavaVM *vm, JNIEnv **p_env, void *thr_args);
    jint (*DetachCurrentThread)(JavaVM *vm);

    /* new for jdk 1.2 */
    jint (*GetEnv)(JavaVM *vm, void **env, jint version);
  };

#ifdef __cplusplus
  extern struct JNIInvokeInterface _hungryJNIInvokeInterface;
  
  struct JavaVM {
    JNIInvokeInterface *_vtable;
  
    JavaVM() {
      _vtable = &_hungryJNIInvokeInterface;
    }
  
    jint DestroyJavaVM() {
      return _vtable->DestroyJavaVM(this);
    }
    jint AttachCurrentThread(JNIEnv **p_env, void *thr_args) {
      return _vtable->AttachCurrentThread(this, p_env, thr_args);
    }
    jint DetachCurrentThread() {
      return _vtable->DetachCurrentThread(this);
    }

    /* new for jdk 1.2 */
    jint GetEnv(void **env, jint version) {
      return _vtable->GetEnv(this, env, version);
    }
  };
#endif

  JNIEXPORT jint JNICALL JNI_GetDefaultJavaVMInitArgs(void *vm_args);
  JNIEXPORT jint JNICALL JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen,
					       jsize *nVMs);
  JNIEXPORT jint JNICALL JNI_CreateJavaVM(JavaVM **pMvm, JNIEnv **p_env,
					  void *vm_args);

#ifdef __cplusplus
};
#endif

#endif /* _hungry_jni_h */

