/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode:nil -*-
   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 JNI_H
#define JNI_H

#include "nspr.h"
#include <stdarg.h>

PR_BEGIN_EXTERN_C

#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

/* primitive types */
typedef PRInt8 jbyte;
typedef PRUint8 jboolean;
typedef PRInt16 jshort;
typedef PRUint16 jchar;
typedef PRInt32 jint;
typedef PRInt64 jlong;
typedef float jfloat;
typedef PRFloat64 jdouble;
typedef void* jref;

/* 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
#ifdef JNI_IMPL
typedef struct JNINativeInterface *JNIEnv;
typedef struct JNIInvokeInterface *JavaVM;
#else
typedef const struct JNINativeInterface *JNIEnv;
typedef const struct JNIInvokeInterface *JavaVM;
#endif
#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 char* (*GetStringUTFChars)(JNIEnv *env, jstring string,
                                   jboolean *isCopy);
  void (*ReleaseStringUTFChars)(JNIEnv *env, jstring string,
                                const char *chars);

  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;

  void *_sun1;
  void *_sun2[6];
  
  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);
  }

  void FatalError(const char *msg) {
    _vtable->FatalError(this, msg);
  }

  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 char* GetStringUTFChars(jstring string, jboolean *isCopy) {
    return _vtable->GetStringUTFChars(this, string, isCopy);
  }

  void ReleaseStringUTFChars(jstring string, const char *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;
  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;

  void *_sun1;
  void *_sun2;
  void *_sun3;

  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);

PR_END_EXTERN_C

#endif /* JNI_H */

