swigutil_java.c

来自「linux subdivision ying gai ke yi le ba」· C语言 代码 · 共 1,257 行 · 第 1/3 页

C
1,257
字号
/*
 * swigutil_java.c: utility functions for the SWIG Java bindings
 *
 * ====================================================================
 * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.  The terms
 * are also available at http://subversion.tigris.org/license-1.html.
 * If newer versions of this license are posted there, you may use a
 * newer version instead, at your option.
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://subversion.tigris.org/.
 * ====================================================================
 */


#include <jni.h>

#include <apr_pools.h>
#include <apr_hash.h>


#include "svn_client.h"

#include "svn_string.h"
#include "svn_delta.h"

#define SVN_SWIG_JAVA_DEFINE_CACHE
#include "swigutil_java.h"

/* FIXME: Need java.swg for the JCALL macros.  The following was taken
   from javahead.swg (which is included by java.swg). */
#ifndef JCALL0
#ifdef __cplusplus
#   define JCALL0(func, jenv) jenv->func()
#   define JCALL1(func, jenv, ar1) jenv->func(ar1)
#   define JCALL2(func, jenv, ar1, ar2) jenv->func(ar1, ar2)
#   define JCALL3(func, jenv, ar1, ar2, ar3) jenv->func(ar1, ar2, ar3)
#   define JCALL4(func, jenv, ar1, ar2, ar3, ar4) \
                      jenv->func(ar1, ar2, ar3, ar4)
#   define JCALL7(func, jenv, ar1, ar2, ar3, ar4, ar5, ar6, ar7) \
                      jenv->func(ar1, ar2, ar3, ar4, ar5, ar6, ar7)
#else
#   define JCALL0(func, jenv) (*jenv)->func(jenv)
#   define JCALL1(func, jenv, ar1) (*jenv)->func(jenv, ar1)
#   define JCALL2(func, jenv, ar1, ar2) (*jenv)->func(jenv, ar1, ar2)
#   define JCALL3(func, jenv, ar1, ar2, ar3) (*jenv)->func(jenv, ar1, ar2, ar3)
#   define JCALL4(func, jenv, ar1, ar2, ar3, ar4) \
                      (*jenv)->func(jenv, ar1, ar2, ar3, ar4)
#   define JCALL7(func, jenv, ar1, ar2, ar3, ar4, ar5, ar6, ar7) \
                      (*jenv)->func(jenv, ar1, ar2, ar3, ar4, ar5, ar6, ar7)
#endif
#endif

/* Convert an svn_error_t into a SubversionException */
static jthrowable convert_error(JNIEnv *jenv, svn_error_t *error)
{
  jthrowable cause;
  jthrowable exc;
  jstring msg;
  jstring file;

  /* Is it wise to use recursion in an error handler? */
  cause = (error->child) ? convert_error(jenv, error->child) : NULL;

  /* ### need more error checking */
  msg = JCALL1(NewStringUTF, jenv, error->message);
  file = error->file ? JCALL1(NewStringUTF, jenv, error->file) : NULL;

  exc = JCALL7(NewObject, jenv, 
               svn_swig_java_cls_subversionexception, 
               svn_swig_java_mid_subversionexception_init, 
               msg, cause, 
               (jlong) error->apr_err, file, (jlong) error->line);
  return exc;
}

/* Convert an svn_error_t into a SubversionException 
   After conversion, the error will be cleared */
jthrowable svn_swig_java_convert_error(JNIEnv *jenv, svn_error_t *error)
{
  jthrowable exc;

  exc = convert_error(jenv, error);
  svn_error_clear(error);
  return exc;
}

/* this baton is used for the editor, directory, and file batons. */
typedef struct {
  jobject editor;       /* the editor handling the callbacks */
  jobject baton;        /* the dir/file baton (or NULL for edit baton) */
  apr_pool_t *pool;     /* pool to use for errors */
  JNIEnv *jenv;         /* Java native interface structure */
} item_baton;

typedef struct {
  jobject handler;      /* the window handler (a callable) */
  apr_pool_t *pool;     /* a pool for constructing errors */
  JNIEnv *jenv;         /* Java native interface structure */
} handler_baton;

static jobject make_pointer(JNIEnv* env, void *ptr)
{
  /* Return a Long object contining the C pointer to the object
     (SWIG/Java knows nothing of SWIG_NewPointerObj) */
  jclass cls = JCALL1(FindClass, env, "java/lang/Long");
  return JCALL3(NewObject, env, cls,
                JCALL3(GetMethodID, env, cls, "<init>", "(J)V"), (jlong) ptr);
}

static jobject convert_hash(JNIEnv* jenv, apr_hash_t *hash,
                            jobject (*converter_func)(JNIEnv* env,
                                                      void *value,
                                                      void *ctx),
                            void *ctx)
{
  apr_hash_index_t *hi;
  jclass cls = JCALL1(FindClass, jenv, "java/util/HashMap");
  jobject dict = JCALL3(NewObject, jenv, cls,
                        JCALL3(GetMethodID, jenv, cls, "<init>", "(I)V"),
                        (jint) apr_hash_count(hash));
  jmethodID put = JCALL3(GetMethodID, jenv, cls, "put",
                         "(Ljava/lang/Object;Ljava/lang/Object;)"
                         "Ljava/lang/Object;");

  if (dict == NULL)
    return NULL;

  for (hi = apr_hash_first(NULL, hash); hi; hi = apr_hash_next(hi))
    {
      const void *key;
      void *val;
      jobject value;

      apr_hash_this(hi, &key, NULL, &val);
      value = (*converter_func)(jenv, val, ctx);
      JCALL4(CallObjectMethod, jenv, dict, put,
              JCALL1(NewStringUTF, jenv, key), value);
      JCALL1(DeleteLocalRef, jenv, value);
    }

  return dict;
}

void svn_swig_java_add_to_list(JNIEnv* jenv, apr_array_header_t *array,
                               jobject list)
{
  /* TODO: This impl will be much like svn_swig_java_add_to_map */
}

void svn_swig_java_add_to_map(JNIEnv* jenv, apr_hash_t *hash, jobject map)
{
  apr_hash_index_t *hi;
  jclass cls = JCALL1(FindClass, jenv, "java/util/Map");
  jmethodID put = JCALL3(GetMethodID, jenv, cls, "put",
                         "(Ljava/lang/Object;Ljava/lang/Object;)"
                         "Ljava/lang/Object;");

  for (hi = apr_hash_first(NULL, hash); hi; hi = apr_hash_next(hi))
    {
      const void *key;
      void *val;
      jobject keyname, value, oldvalue;

      apr_hash_this(hi, &key, NULL, &val);
      keyname = JCALL1(NewStringUTF, jenv, key);
      value = make_pointer(jenv, val);

      oldvalue = JCALL4(CallObjectMethod, jenv, map, put, keyname, value);
  
      JCALL1(DeleteLocalRef, jenv, value);
      JCALL1(DeleteLocalRef, jenv, oldvalue);
      JCALL1(DeleteLocalRef, jenv, keyname);

      if (JCALL0(ExceptionOccurred, jenv))
        return;
    }
}

static jobject convert_to_swigtype(JNIEnv* jenv, void *value, void *ctx)
{
  return make_pointer(jenv, value);
}

static jobject convert_svn_string_t(JNIEnv* jenv, void *value, void *ctx)
{
  const svn_string_t *s = value;

  /* This will copy the data */
  return JCALL1(NewStringUTF, jenv, s->data);
}

jobject svn_swig_java_prophash_to_dict(JNIEnv *jenv, apr_hash_t *hash)
{
  return convert_hash(jenv, hash, convert_svn_string_t, jenv);
}

jobject svn_swig_java_convert_hash(JNIEnv *jenv, apr_hash_t *hash)
{
  return convert_hash(jenv, hash, convert_to_swigtype, NULL);
}

jobject svn_swig_java_c_strings_to_list(JNIEnv *jenv, char **strings)
{
  jclass cls = JCALL1(FindClass, jenv, "java/util/ArrayList");
  jobject list = JCALL2(NewObject, jenv, cls,
                        JCALL3(GetMethodID, jenv, cls, "<init>", "()V"));
  jmethodID add = JCALL3(GetMethodID, jenv, cls, "add", 
                         "(Ljava/lang/Object;)Z");
  char *s;
  jobject obj;
  while ((s = *strings++) != NULL)
    {
      obj = JCALL1(NewStringUTF, jenv, s);

      if (obj == NULL)
          goto error;

      JCALL3(CallBooleanMethod, jenv, list, add, obj);

      JCALL1(DeleteLocalRef, jenv, obj);
    }

  return list;

 error:
  JCALL1(DeleteLocalRef, jenv, list);
  return NULL;
}

jobject svn_swig_java_array_to_list(JNIEnv *jenv,
                                    const apr_array_header_t *strings)
{
  jclass cls = JCALL1(FindClass, jenv, "java/util/ArrayList");
  jobject list = JCALL3(NewObject, jenv, cls,
                        JCALL3(GetMethodID, jenv, cls, "<init>", "(I)V"),
                        strings->nelts);
  int i;
  jobject obj;

  jmethodID add;
  if (strings->nelts > 0)
    add = JCALL3(GetMethodID, jenv, cls, "add", "(i, Ljava/lang/Object;)Z");

  for (i = 0; i < strings->nelts; ++i)
    {
      const char *s;

      s = APR_ARRAY_IDX(strings, i, const char *);
      obj = JCALL1(NewStringUTF, jenv, s);
      if (obj == NULL)
        goto error;
      /* ### HELP: The format specifier might be 'I' instead of 'i' */
      JCALL4(CallObjectMethod, jenv, list, add, i, obj);
      JCALL1(DeleteLocalRef, jenv, obj);
    }

  return list;

 error:
  JCALL1(DeleteLocalRef, jenv, list);
  return NULL;
}

const apr_array_header_t *svn_swig_java_strings_to_array(JNIEnv *jenv,
                                                         jobject source,
                                                         apr_pool_t *pool)
{
  int targlen;
  apr_array_header_t *temp;

  jclass cls = JCALL1(FindClass, jenv, "java/util/List");
  jmethodID size = JCALL3(GetMethodID, jenv, cls, "size", "()I");
  jmethodID get = JCALL3(GetMethodID, jenv, cls, "get",
                         "(I)Ljava/lang/Object;");

  jclass illegalArgCls = JCALL1(FindClass, jenv,
                                "java/lang/IllegalArgumentException");

  if (!JCALL2(IsInstanceOf, jenv, source, cls))
    {
      if (JCALL2(ThrowNew, jenv, illegalArgCls, "Not a List") != JNI_OK)
          return NULL;
    }

  targlen = JCALL2(CallIntMethod, jenv, source, size);
  temp = apr_array_make(pool, targlen, sizeof(const char *));
  while (targlen--)
    {
      jobject o = JCALL3(CallObjectMethod, jenv, source, get, targlen);
      const char * c_string;
      if (o == NULL)
          return NULL;
      else if (!JCALL2(IsInstanceOf, jenv, o,
                       JCALL1(FindClass, jenv, "java/lang/String")))
        {
          JCALL1(DeleteLocalRef, jenv, o);
          if (JCALL2(ThrowNew, jenv, illegalArgCls, "Not a String") != JNI_OK)
            {
              return NULL;
            }
        }
      c_string = (*jenv)->GetStringUTFChars(jenv, o, 0);
      APR_ARRAY_IDX(temp, targlen, const char *) = apr_pstrdup(pool, c_string);
      (*jenv)->ReleaseStringUTFChars(jenv, o, c_string);
      JCALL1(DeleteLocalRef, jenv, o);

    }
  return temp;
}

/* Convert a Java exception into a svn_error_t.
   This function may only be called if there is
   a pending exception. */
static svn_error_t * convert_exception(JNIEnv *jenv, apr_pool_t *pool)
{
  svn_error_t *result;
  apr_status_t status;
  char *msg;
  jthrowable exc;

  /* Fetch the exception */
  exc = JCALL0(ExceptionOccurred, jenv);

#ifdef SVN_DEBUG
  /* Print the pending exception to stderr */
  JCALL0(ExceptionDescribe, jenv);
#endif

  /* Clear the exception */
  JCALL0(ExceptionClear, jenv);

  /* Interpret the exception:
     java.lang.OutOfMemoryError -> APR_ENOMEM
     other -> APR_EGENERAL */
  /* ### Add other exceptions; use a table? */
  if (JCALL2(IsInstanceOf, jenv, exc, svn_swig_java_cls_outofmemoryerror))
    {
      status = APR_ENOMEM;
      msg = "JVM raised OutOfMemoryError";
    }
  else
    {
      status = APR_EGENERAL;
      msg = "The Java callback raised an exception";
    }
  result = svn_error_create(status, NULL, msg);

  /* Free the local reference */
  JCALL1(DeleteLocalRef, jenv, exc);
  return result;
}

static item_baton * make_baton(JNIEnv *jenv, apr_pool_t *pool,
                               jobject editor, jobject baton)
{
  item_baton *newb = apr_palloc(pool, sizeof(*newb));

  /* one more reference to the editor. */
  JCALL1(NewGlobalRef, jenv, editor);
  JCALL1(NewGlobalRef, jenv, baton);

  /* note: we take the caller's reference to 'baton' */

  newb->editor = JCALL1(NewGlobalRef, jenv, editor);
  newb->baton = baton;
  newb->pool = pool;
  newb->jenv = jenv;

  return newb;
}

static svn_error_t * close_baton(void *baton, const char *method)
{
  item_baton *ib = baton;
  jobject result;
  JNIEnv *jenv = ib->jenv;
  jclass cls = JCALL1(GetObjectClass, jenv, ib->editor);
  jmethodID methodID;

  /* If there is no baton object, then it is an edit_baton, and we should
     not bother to pass an object. Note that we still shove a NULL onto
     the stack, but the format specified just won't reference it.  */

  if (ib->baton)
    {
      methodID = JCALL3(GetMethodID, jenv, cls, method,
                       "(Ljava/lang/Object;)Ljava/lang/Object;");
      result = JCALL3(CallObjectMethod, jenv, ib->editor, methodID, ib->baton);
    }
  else
    {
      methodID = JCALL3(GetMethodID, jenv, cls, method,
                        "()Ljava/lang/Object;");
      result = JCALL2(CallObjectMethod, jenv, ib->editor, methodID);
    }

  if (result == NULL)
      return convert_exception(ib->jenv, ib->pool);

  /* there is no return value, so just toss this object */
  JCALL1(DeleteGlobalRef, ib->jenv, result);

  /* We're now done with the baton. Since there isn't really a free, all
     we need to do is note that its objects are no longer referenced by
     the baton.  */
  JCALL1(DeleteGlobalRef, ib->jenv, ib->editor);
  JCALL1(DeleteGlobalRef, ib->jenv, ib->baton);

#ifdef SVN_DEBUG
  ib->editor = ib->baton = NULL;
#endif

  return SVN_NO_ERROR;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?