/* -*- Mode: C; c-file-style: "gnu" -*-
   jniarray.c -- Java Native Interface array operations.
   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
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdlib.h>
#include <string.h> /* For strlen() on Alpha/Linux */

#include "jni.h"
#include "jniint.h"
#include "arrays.h"
#include "array-class.h"
#include "interp.h"
#include "qop.h"

#include <assert.h>

jsize
JNIFUNC(GetArrayLength)(JNIEnv *env,
			jarray array)
{
  jvalue length_value;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field = (*arr)->fields [ ARRAY_LENGTH_INDEX ];

  get_instance_field(array,
		     field,
		     &length_value);

  return length_value.i;
}

jarray
JNIFUNC(NewObjectArray)(JNIEnv *env,
			jsize length,
			jclass elementClass,
			jobject initialElement)
{
  ClazzFile *cf = jclass_to_clazzfile(env, elementClass);
  char *element_classname = getClassName(env, cf);
  japhar_obj array_reference;

  /* XXX use initialElement? */

  array_reference = create_array(env, length, element_classname);

  /* XXX Should it throw OutOfMemoryError if creation failed? */

  return array_reference;
}

jobject
JNIFUNC(GetObjectArrayElement)(JNIEnv *env,
			       jobjectArray array,
			       jsize index)
{
  jvalue body_value;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field = (*arr)->fields [ ARRAY_BODY_INDEX ];

  get_instance_field(array,
		     field,
		     &body_value);

  return ((jobject*)body_value.l)[ index ];
}

void
JNIFUNC(SetObjectArrayElement)(JNIEnv *env,
			       jobjectArray array,
			       jsize index,
			       jobject value)
{
  jvalue body_value;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field = (*arr)->fields [ ARRAY_BODY_INDEX ];

  get_instance_field(array,
		     field,
		     &body_value);

  ((jobject*)body_value.l)[ index ] = value;
}

jbooleanArray
JNIFUNC(NewBooleanArray)(JNIEnv *env,
			 jsize length)
{
  ClazzFile *boolean_array_type = createFakeArrayClass(env, "[Z");
  jobject array = new_array(env,length, boolean_array_type);

  return array;
}

jboolean*
JNIFUNC(GetBooleanArrayElements)(JNIEnv *env,
				 jbooleanArray array,
				 jboolean* isCopy)
{
  japhar_obj arr = (japhar_obj)array;
  jvalue body_value, length_value;
  jboolean *the_copy;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  the_copy = (jboolean*)malloc(sizeof(jboolean) * length_value.i);

  if (the_copy == NULL)
    {
      if (isCopy) *isCopy = JNI_FALSE;
      return (jboolean*)body_value.l;
    }
  else
    {
      memcpy(the_copy, body_value.l, sizeof(jboolean) * length_value.i);
      if (isCopy) *isCopy = JNI_TRUE;
      return the_copy;
    }
}

void
JNIFUNC(ReleaseBooleanArrayElements)(JNIEnv *env,
				     jbooleanArray array,
				     jboolean* elems,
				     jint mode)
{
  japhar_obj arr = (japhar_obj)array;
  jvalue body_value, length_value;
  jboolean can_free = JNI_FALSE;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ];
  get_instance_field(array,
		     field,
		     &length_value);

  if (body_value.l != elems)
    can_free = JNI_TRUE;

  switch (mode)
    {
    case 0: /* commit the changes and free elems. */
      memcpy(body_value.l, elems, sizeof(jboolean) * length_value.i);
      if (can_free) free(elems);
      break;
    case JNI_COMMIT: /* commit the changes but don't free elems. */
      memcpy(body_value.l, elems, sizeof(jboolean) * length_value.i);
      break;
    case JNI_ABORT:  /* don't commit the changes but free elems. */
      if (can_free) free(elems);
      break;
    }
}

void
JNIFUNC(GetBooleanArrayRegion)(JNIEnv *env,
			       jbooleanArray array,
			       jsize start,
			       jsize len,
			       jboolean* buf)
{
  jvalue body_value, length_value;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env, "java/lang/ArrayIndexOutOfBoundsException");
      (*env)->ThrowNew(env, exception, "In JNI GetBooleanArrayRegion");
      return;
    }

  memcpy(buf, ((jboolean*)body_value.l) + start, len * sizeof(jboolean));
}

void
JNIFUNC(SetBooleanArrayRegion)(JNIEnv *env,
			       jbooleanArray array,
			       jsize start,
			       jsize len,
			       jboolean* buf)
{
  jvalue body_value, length_value;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env, "java/lang/ArrayIndexOutOfBoundsException");
      (*env)->ThrowNew(env, exception, "In JNI GetBooleanArrayRegion");
      return;
    }

  memcpy(((jboolean*)body_value.l) + start, buf, len * sizeof(jboolean));
}

jbyteArray
JNIFUNC(NewByteArray)(JNIEnv *env,
		      jsize length)
{
  ClazzFile *byte_array_type = createFakeArrayClass(env, "[B");
  jobject array = new_array(env,length, byte_array_type);

  return array;
}

jbyte*
JNIFUNC(GetByteArrayElements)(JNIEnv *env,
			      jbyteArray array,
			      jboolean* isCopy)
{
  jvalue body_value, length_value;
  jbyte *the_copy;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  the_copy = (jbyte*)malloc(sizeof(jbyte) * length_value.i);

  if (the_copy == NULL)
    {
      if (isCopy) *isCopy = JNI_FALSE;
      return (jbyte*)body_value.l;
    }
  else
    {
      memcpy(the_copy, body_value.l, sizeof(jbyte) * length_value.i);
      if (isCopy) *isCopy = JNI_TRUE;
      return the_copy;
    }
}

void
JNIFUNC(ReleaseByteArrayElements)(JNIEnv *env,
				  jbyteArray array,
				  jbyte* elems,
				  jint mode)
{
  jvalue body_value, length_value;
  jboolean can_free = JNI_FALSE;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (body_value.l != elems)
    can_free = JNI_TRUE;

  switch (mode)
    {
    case 0: /* commit the changes and free elems. */
      memcpy(body_value.l, elems, sizeof(jbyte) * length_value.i);
      if (can_free) free(elems);
      break;
    case JNI_COMMIT: /* commit the changes but don't free elems. */
      memcpy(body_value.l, elems, sizeof(jbyte) * length_value.i);
      break;
    case JNI_ABORT:  /* don't commit the changes but free elems. */
      if (can_free) free(elems);
      break;
    }
}

void
JNIFUNC(GetByteArrayRegion)(JNIEnv *env,
			    jbyteArray array,
			    jsize start,
			    jsize len,
			    jbyte* buf)
{
  jvalue body_value, length_value;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env, "java/lang/ArrayIndexOutOfBoundsException");
      (*env)->ThrowNew(env, exception, "In JNI GetByteArrayRegion");
      return;
    }

  memcpy(buf, ((jbyte*)body_value.l) + start, len * sizeof(jbyte));
}

void
JNIFUNC(SetByteArrayRegion)(JNIEnv *env,
			    jbyteArray array,
			    jsize start,
			    jsize len,
			    jbyte* buf)
{
  jvalue body_value, length_value;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env, "java/lang/ArrayIndexOutOfBoundsException");
      (*env)->ThrowNew(env, exception, "In JNI GetByteArrayRegion");
      return;
    }

  memcpy(((jbyte*)body_value.l) + start, buf, len * sizeof(jbyte));
}

jcharArray
JNIFUNC(NewCharArray)(JNIEnv *env,
		      jsize length)
{
  jclass char_array_type = createFakeArrayClass(env, "[C");
  jobject array = new_array(env, length, char_array_type);
  japhar_object *jobj = NULL;

  if (NULL != array)
    {
      obj_to_object(array, jobj);
#if 0
      ENQUEUE((GC_obj*)jobj, henv->_local_refs);
#endif
    } /* new_array() has thrown if something went wrong */

  return array;
}

jchar*
JNIFUNC(GetCharArrayElements)(JNIEnv *env,
			      jcharArray array,
			      jboolean* isCopy)
{
  jvalue body_value, length_value;
  jchar *the_copy = NULL;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (0 < length_value.i)
    the_copy = (jchar*)malloc(sizeof(jchar) * length_value.i);

  if (the_copy == NULL)
    {
      if (isCopy) *isCopy = JNI_FALSE;
      return (jchar*)body_value.l;
    }
  else
    {
      memcpy(the_copy, body_value.l, sizeof(jchar) * length_value.i);
      if (isCopy) *isCopy = JNI_TRUE;
      return the_copy;
    }
}

void
JNIFUNC(ReleaseCharArrayElements)(JNIEnv *env,
				  jcharArray array,
				  jchar* elems,
				  jint mode)
{
  jvalue body_value, length_value;
  jboolean can_free = JNI_FALSE;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (body_value.l != elems)
    can_free = JNI_TRUE;

  switch (mode)
    {
    case 0: /* commit the changes and free elems. */
      memcpy(body_value.l, elems, sizeof(jchar) * length_value.i);
      if (can_free) free(elems);
      break;
    case JNI_COMMIT: /* commit the changes but don't free elems. */
      memcpy(body_value.l, elems, sizeof(jchar) * length_value.i);
      break;
    case JNI_ABORT:  /* don't commit the changes but free elems. */
      if (can_free) free(elems);
      break;
    }
}

void
JNIFUNC(GetCharArrayRegion)(JNIEnv *env,
			    jcharArray array,
			    jsize start,
			    jsize len,
			    jchar* buf)
{
  jvalue body_value, length_value;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env, "java/lang/ArrayIndexOutOfBoundsException");
      (*env)->ThrowNew(env, exception, "In JNI GetCharArrayRegion");
      return;
    }

  memcpy(buf, ((jchar*)body_value.l) + start, len * sizeof(jchar));
}

void
JNIFUNC(SetCharArrayRegion)(JNIEnv *env,
			    jcharArray array,
			    jsize start,
			    jsize len,
			    jchar* buf)
{
  jvalue body_value, length_value;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env, "java/lang/ArrayIndexOutOfBoundsException");
      (*env)->ThrowNew(env, exception, "In JNI GetCharArrayRegion");
      return;
    }

  memcpy(((jchar*)body_value.l) + start, buf, len * sizeof(jchar));
}

jshortArray
JNIFUNC(NewShortArray)(JNIEnv *env,
		       jsize length)
{
  ClazzFile *short_array_type = createFakeArrayClass(env, "[S");
  jobject array = new_array(env,length, short_array_type);

  return array;
}

jshort*
JNIFUNC(GetShortArrayElements)(JNIEnv *env,
			       jshortArray array,
			       jboolean* isCopy)
{
  jvalue body_value, length_value;
  jshort *the_copy;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  the_copy = (jshort*)malloc(sizeof(jshort) * length_value.i);

  if (the_copy == NULL)
    {
      if (isCopy) *isCopy = JNI_FALSE;
      return (jshort*)body_value.l;
    }
  else
    {
      memcpy(the_copy, body_value.l, sizeof(jshort) * length_value.i);
      if (isCopy) *isCopy = JNI_TRUE;
      return the_copy;
    }
}

void
JNIFUNC(ReleaseShortArrayElements)(JNIEnv *env,
				   jshortArray array,
				   jshort* elems,
				   jint mode)
{
  jvalue body_value, length_value;
  jboolean can_free = JNI_FALSE;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (body_value.l != elems)
    can_free = JNI_TRUE;

  switch (mode)
    {
    case 0: /* commit the changes and free elems. */
      memcpy(body_value.l, elems, sizeof(jshort) * length_value.i);
      if (can_free) free(elems);
      break;
    case JNI_COMMIT: /* commit the changes but don't free elems. */
      memcpy(body_value.l, elems, sizeof(jshort) * length_value.i);
      break;
    case JNI_ABORT:  /* don't commit the changes but free elems. */
      if (can_free) free(elems);
      break;
    }
}

void
JNIFUNC(GetShortArrayRegion)(JNIEnv *env,
			     jshortArray array,
			     jsize start,
			     jsize len,
			     jshort* buf)
{
  jvalue body_value, length_value;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env, "java/lang/ArrayIndexOutOfBoundsException");
      (*env)->ThrowNew(env, exception, "In JNI GetShortArrayRegion");
      return;
    }

  memcpy(buf, ((jshort*)body_value.l) + start, len * sizeof(jshort));
}

void
JNIFUNC(SetShortArrayRegion)(JNIEnv *env,
			     jshortArray array,
			     jsize start,
			     jsize len,
			     jshort* buf)
{
  jvalue body_value, length_value;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env, "java/lang/ArrayIndexOutOfBoundsException");
      (*env)->ThrowNew(env, exception, "In JNI GetShortArrayRegion");
      return;
    }

  memcpy(((jshort*)body_value.l) + start, buf, len * sizeof(jshort));
}

jintArray
JNIFUNC(NewIntArray)(JNIEnv *env,
		     jsize length)
{
  ClazzFile *int_array_type = createFakeArrayClass(env, "[I");
  jobject array = new_array(env,length, int_array_type);

  return array;
}

jint*
JNIFUNC(GetIntArrayElements)(JNIEnv *env,
			     jintArray array,
			     jboolean* isCopy)
{
  jvalue body_value, length_value;
  jint *the_copy;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  the_copy = (jint*)malloc(sizeof(jint) * length_value.i);

  if (the_copy == NULL)
    {
      if (isCopy) *isCopy = JNI_FALSE;
      return (jint*)body_value.l;
    }
  else
    {
      memcpy(the_copy, body_value.l, sizeof(jint) * length_value.i);
      if (isCopy) *isCopy = JNI_TRUE;
      return the_copy;
    }
}

void
JNIFUNC(ReleaseIntArrayElements)(JNIEnv *env,
				 jintArray array,
				 jint* elems,
				 jint mode)
{
  jvalue body_value, length_value;
  jboolean can_free = JNI_FALSE;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (body_value.l != elems)
    can_free = JNI_TRUE;

  switch (mode)
    {
    case 0: /* commit the changes and free elems. */
      memcpy(body_value.l, elems, sizeof(jint) * length_value.i);
      if (can_free) free(elems);
      break;
    case JNI_COMMIT: /* commit the changes but don't free elems. */
      memcpy(body_value.l, elems, sizeof(jint) * length_value.i);
      break;
    case JNI_ABORT:  /* don't commit the changes but free elems. */
      if (can_free) free(elems);
      break;
    }
}

void
JNIFUNC(GetIntArrayRegion)(JNIEnv *env,
			   jintArray array,
			   jsize start,
			   jsize len,
			   jint* buf)
{
  jvalue body_value, length_value;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env, "java/lang/ArrayIndexOutOfBoundsException");
      (*env)->ThrowNew(env, exception, "In JNI GetIntArrayRegion");
      return;
    }

  memcpy(buf, ((jint*)body_value.l) + start, len * sizeof(jint));
}

void
JNIFUNC(SetIntArrayRegion)(JNIEnv *env,
			   jintArray array,
			   jsize start,
			   jsize len,
			   jint* buf)
{
  jvalue body_value, length_value;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env, "java/lang/ArrayIndexOutOfBoundsException");
      (*env)->ThrowNew(env, exception, "In JNI GetIntArrayRegion");
      return;
    }

  memcpy(((jint*)body_value.l) + start, buf, len * sizeof(jint));
}

jlongArray
JNIFUNC(NewLongArray)(JNIEnv *env,
		      jsize length)
{
  ClazzFile *long_array_type = createFakeArrayClass(env, "[J");
  jobject array = new_array(env,length, long_array_type);

  return array;
}

jlong*
JNIFUNC(GetLongArrayElements)(JNIEnv *env,
			      jlongArray array,
			      jboolean* isCopy)
{
  jvalue body_value, length_value;
  jlong *the_copy;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  the_copy = (jlong*)malloc(sizeof(jlong) * length_value.i);

  if (the_copy == NULL)
    {
      if (isCopy) *isCopy = JNI_FALSE;
      return (jlong*)body_value.l;
    }
  else
    {
      memcpy(the_copy, body_value.l, sizeof(jlong) * length_value.i);
      if (isCopy) *isCopy = JNI_TRUE;
      return the_copy;
    }
}

void
JNIFUNC(ReleaseLongArrayElements)(JNIEnv *env,
				  jlongArray array,
				  jlong* elems,
				  jint mode)
{
  jvalue body_value, length_value;
  jboolean can_free = JNI_FALSE;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (body_value.l != elems)
    can_free = JNI_TRUE;

  switch (mode)
    {
    case 0: /* commit the changes and free elems. */
      memcpy(body_value.l, elems, sizeof(jlong) * length_value.i);
      if (can_free) free(elems);
      break;
    case JNI_COMMIT: /* commit the changes but don't free elems. */
      memcpy(body_value.l, elems, sizeof(jlong) * length_value.i);
      break;
    case JNI_ABORT:  /* don't commit the changes but free elems. */
      if (can_free) free(elems);
      break;
    }
}

void
JNIFUNC(GetLongArrayRegion)(JNIEnv *env,
			    jlongArray array,
			    jsize start,
			    jsize len,
			    jlong* buf)
{
  jvalue body_value, length_value;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env, "java/lang/ArrayIndexOutOfBoundsException");
      (*env)->ThrowNew(env, exception, "In JNI GetLongArrayRegion");
      return;
    }

  memcpy(buf, ((jlong*)body_value.l) + start, len * sizeof(jlong));
}

void
JNIFUNC(SetLongArrayRegion)(JNIEnv *env,
			    jlongArray array,
			    jsize start,
			    jsize len,
			    jlong* buf)
{
  jvalue body_value, length_value;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env, "java/lang/ArrayIndexOutOfBoundsException");
      (*env)->ThrowNew(env, exception, "In JNI GetLongArrayRegion");
      return;
    }

  memcpy(((jlong*)body_value.l) + start, buf, len * sizeof(jlong));
}

jfloatArray
JNIFUNC(NewFloatArray)(JNIEnv *env,
		       jsize length)
{
  ClazzFile *float_array_type = createFakeArrayClass(env, "[F");
  jobject array = new_array(env,length, float_array_type);

  return array;
}

jfloat*
JNIFUNC(GetFloatArrayElements)(JNIEnv *env,
			       jfloatArray array,
			       jboolean* isCopy)
{
  jvalue body_value, length_value;
  jfloat *the_copy;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  the_copy = (jfloat*)malloc(sizeof(jfloat) * length_value.i);

  if (the_copy == NULL)
    {
      if (isCopy) *isCopy = JNI_FALSE;
      return (jfloat*)body_value.l;
    }
  else
    {
      memcpy(the_copy, body_value.l, sizeof(jfloat) * length_value.i);
      if (isCopy) *isCopy = JNI_TRUE;
      return the_copy;
    }
}

void
JNIFUNC(ReleaseFloatArrayElements)(JNIEnv *env,
				   jfloatArray array,
				   jfloat* elems,
				   jint mode)
{
  jvalue body_value, length_value;
  jboolean can_free = JNI_FALSE;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (body_value.l != elems)
    can_free = JNI_TRUE;

  switch (mode)
    {
    case 0: /* commit the changes and free elems. */
      memcpy(body_value.l, elems, sizeof(jfloat) * length_value.i);
      if (can_free) free(elems);
      break;
    case JNI_COMMIT: /* commit the changes but don't free elems. */
      memcpy(body_value.l, elems, sizeof(jfloat) * length_value.i);
      break;
    case JNI_ABORT:  /* don't commit the changes but free elems. */
      if (can_free) free(elems);
      break;
    }
}

void
JNIFUNC(GetFloatArrayRegion)(JNIEnv *env,
			     jfloatArray array,
			     jsize start,
			     jsize len,
			     jfloat* buf)
{
  jvalue body_value, length_value;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env, "java/lang/ArrayIndexOutOfBoundsException");
      (*env)->ThrowNew(env, exception, "In JNI GetFloatArrayRegion");
      return;
    }

  memcpy(buf, ((jfloat*)body_value.l) + start, len * sizeof(jfloat));
}

void
JNIFUNC(SetFloatArrayRegion)(JNIEnv *env,
			     jfloatArray array,
			     jsize start,
			     jsize len,
			     jfloat* buf)
{
  jvalue body_value, length_value;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env, "java/lang/ArrayIndexOutOfBoundsException");
      (*env)->ThrowNew(env, exception, "In JNI GetFloatArrayRegion");
      return;
    }

  memcpy(((jfloat*)body_value.l) + start, buf, len * sizeof(jfloat));
}

jdoubleArray
JNIFUNC(NewDoubleArray)(JNIEnv *env,
			jsize length)
{
  ClazzFile *double_array_type = createFakeArrayClass(env, "[D");
  jobject array = new_array(env,length, double_array_type);

  return array;
}

jdouble*
JNIFUNC(GetDoubleArrayElements)(JNIEnv *env,
				jdoubleArray array,
				jboolean* isCopy)
{
  jvalue body_value, length_value;
  jdouble *the_copy;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  the_copy = (jdouble*)malloc(sizeof(jdouble) * length_value.i);

  if (the_copy == NULL)
    {
      if (isCopy) *isCopy = JNI_FALSE;
      return (jdouble*)body_value.l;
    }
  else
    {
      memcpy(the_copy, body_value.l, sizeof(jdouble) * length_value.i);
      if (isCopy) *isCopy = JNI_TRUE;
      return the_copy;
    }
}

void
JNIFUNC(ReleaseDoubleArrayElements)(JNIEnv *env,
				    jdoubleArray array,
				    jdouble* elems,
				    jint mode)
{
  jvalue body_value, length_value;
  jboolean can_free = JNI_FALSE;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (body_value.l != elems)
    can_free = JNI_TRUE;

  switch (mode)
    {
    case 0: /* commit the changes and free elems. */
      memcpy(body_value.l, elems, sizeof(jdouble) * length_value.i);
      if (can_free) free(elems);
      break;
    case JNI_COMMIT: /* commit the changes but don't free elems. */
      memcpy(body_value.l, elems, sizeof(jdouble) * length_value.i);
      break;
    case JNI_ABORT:  /* don't commit the changes but free elems. */
      if (can_free) free(elems);
      break;
    }
}

void
JNIFUNC(GetDoubleArrayRegion)(JNIEnv *env,
			      jdoubleArray array,
			      jsize start,
			      jsize len,
			      jdouble* buf)
{
  jvalue body_value, length_value;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env, "java/lang/ArrayIndexOutOfBoundsException");
      (*env)->ThrowNew(env, exception, "In JNI GetDoubleArrayRegion");
      return;
    }

  memcpy(buf, ((jdouble*)body_value.l) + start, len * sizeof(jdouble));
}

void
JNIFUNC(SetDoubleArrayRegion)(JNIEnv *env,
			      jdoubleArray array,
			      jsize start,
			      jsize len,
			      jdouble* buf)
{
  jvalue body_value, length_value;
  japhar_obj arr = (japhar_obj)array;
  FieldStruct *field;

  field = (*arr)->fields [ ARRAY_BODY_INDEX ];
  get_instance_field(array,
		     field,
		     &body_value);

  field = (*arr)->fields [ ARRAY_LENGTH_INDEX ],
    get_instance_field(array,
		       field,
		       &length_value);

  if (start < 0 || start + len >= length_value.i)
    {
      jclass exception = (*env)->FindClass(env, "java/lang/ArrayIndexOutOfBoundsException");
      (*env)->ThrowNew(env, exception, "In JNI GetDoubleArrayRegion");
      return;
    }

  memcpy(((jdouble*)body_value.l) + start, buf, len * sizeof(jdouble));
}


/* new for JDK 1.2 */

void*
JNIFUNC(GetPrimitiveArrayCritical)(JNIEnv *env, jarray array,
				   jboolean *isCopy)
{
  (*env)->FatalError(env, "JNI GetPrimitiveArrayCritical not implemented yet.\n");

  return NULL;
}

void
JNIFUNC(ReleasePrimitiveArrayCritical)(JNIEnv *env,
				       jarray array,
				       void *carray,
				       jint mode)
{
  (*env)->FatalError(env, "JNI ReleasePrimitiveArrayCritical not implemented yet.\n");
}
