mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-29 03:44:37 +00:00
560 lines
14 KiB
C++
560 lines
14 KiB
C++
/*-
|
|
* See the file LICENSE for redistribution information.
|
|
*
|
|
* Copyright (c) 1997, 1998
|
|
* Sleepycat Software. All rights reserved.
|
|
*/
|
|
#include "config.h"
|
|
|
|
#ifndef lint
|
|
static const char sccsid[] = "@(#)java_util.cpp 10.7 (Sleepycat) 5/2/98";
|
|
#endif /* not lint */
|
|
|
|
#include "java_util.h"
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#ifdef WIN32
|
|
#define sys_errlist _sys_errlist
|
|
#define sys_nerr _sys_nerr
|
|
#endif
|
|
|
|
/****************************************************************
|
|
*
|
|
* Utility functions used by "glue" functions.
|
|
*
|
|
*/
|
|
|
|
/* Use our own malloc for any objects allocated via DB_DBT_MALLOC,
|
|
* since we must free them in the same library address space.
|
|
*/
|
|
extern "C"
|
|
void * java_db_malloc(size_t size)
|
|
{
|
|
return malloc(size);
|
|
}
|
|
|
|
/* Get the private data from a Db* object as a (64 bit) java long.
|
|
*/
|
|
jlong get_private_long_info(JNIEnv *jnienv, const char *classname,
|
|
jobject obj)
|
|
{
|
|
if (!obj)
|
|
return 0;
|
|
|
|
jclass dbClass = get_class(jnienv, classname);
|
|
jfieldID id = jnienv->GetFieldID(dbClass, "private_info_", "J");
|
|
return jnienv->GetLongField(obj, id);
|
|
}
|
|
|
|
/* Get the private data from a Db* object.
|
|
* The private data is stored in the object as a Java long (64 bits),
|
|
* which is long enough to store a pointer on current architectures.
|
|
*/
|
|
void *get_private_info(JNIEnv *jnienv, const char *classname,
|
|
jobject obj)
|
|
{
|
|
long_to_ptr lp;
|
|
if (!obj)
|
|
return 0;
|
|
lp.java_long = get_private_long_info(jnienv, classname, obj);
|
|
return lp.ptr;
|
|
}
|
|
|
|
/* Set the private data in a Db* object as a (64 bit) java long.
|
|
*/
|
|
void set_private_long_info(JNIEnv *jnienv, const char *classname,
|
|
jobject obj, jlong value)
|
|
{
|
|
jclass dbClass = get_class(jnienv, classname);
|
|
jfieldID id = jnienv->GetFieldID(dbClass, "private_info_", "J");
|
|
jnienv->SetLongField(obj, id, value);
|
|
}
|
|
|
|
/* Set the private data in a Db* object.
|
|
* The private data is stored in the object as a Java long (64 bits),
|
|
* which is long enough to store a pointer on current architectures.
|
|
*/
|
|
void set_private_info(JNIEnv *jnienv, const char *classname,
|
|
jobject obj, void *value)
|
|
{
|
|
long_to_ptr lp;
|
|
lp.java_long = 0;
|
|
lp.ptr = value;
|
|
set_private_long_info(jnienv, classname, obj, lp.java_long);
|
|
}
|
|
|
|
/*
|
|
* Given a non-qualified name (e.g. "foo"), get the class handl
|
|
* for the fully qualified name (e.g. "com.sleepycat.db.foo")
|
|
*/
|
|
jclass get_class(JNIEnv *jnienv, const char *classname)
|
|
{
|
|
// TODO: cache these (remember to use NewGlobalRef)
|
|
char fullname[128] = DB_PACKAGE_NAME;
|
|
strcat(fullname, classname);
|
|
return jnienv->FindClass(fullname);
|
|
}
|
|
|
|
/* Set an individual field in a Db* object.
|
|
* The field must be an object type.
|
|
*/
|
|
void set_object_field(JNIEnv *jnienv, jclass class_of_this,
|
|
jobject jthis, const char *object_classname,
|
|
const char *name_of_field, jobject obj)
|
|
{
|
|
char signature[512];
|
|
|
|
strcpy(signature, "L");
|
|
strcat(signature, DB_PACKAGE_NAME);
|
|
strcat(signature, object_classname);
|
|
strcat(signature, ";");
|
|
|
|
jfieldID id = jnienv->GetFieldID(class_of_this, name_of_field, signature);
|
|
jnienv->SetObjectField(jthis, id, obj);
|
|
}
|
|
|
|
|
|
/* Report an exception back to the java side.
|
|
*/
|
|
void report_exception(JNIEnv *jnienv, const char *text, int err)
|
|
{
|
|
jstring textString = get_java_string(jnienv, text);
|
|
jclass dbexcept = get_class(jnienv, name_DB_EXCEPTION);
|
|
jmethodID constructId = jnienv->GetMethodID(dbexcept, "<init>",
|
|
"(Ljava/lang/String;I)V");
|
|
jthrowable obj = (jthrowable)jnienv->AllocObject(dbexcept);
|
|
jnienv->CallVoidMethod(obj, constructId, textString, err);
|
|
jnienv->Throw(obj);
|
|
}
|
|
|
|
/* If the object is null, report an exception and return false (0),
|
|
* otherwise return true (1).
|
|
*/
|
|
int verify_non_null(JNIEnv *jnienv, void *obj)
|
|
{
|
|
if (obj == NULL) {
|
|
report_exception(jnienv, "null object", 0);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* If the error code is non-zero, report an exception and return false (0),
|
|
* otherwise return true (1).
|
|
*/
|
|
int verify_return(JNIEnv *jnienv, int err)
|
|
{
|
|
char *errstring;
|
|
|
|
if (err != 0) {
|
|
if (err > 0 && (errstring = strerror(err)) != NULL) {
|
|
report_exception(jnienv, errstring, err);
|
|
}
|
|
else {
|
|
char buffer[64];
|
|
sprintf(buffer, "error %d", err);
|
|
report_exception(jnienv, buffer, err);
|
|
}
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* Create an object of the given class, calling its default constructor.
|
|
*/
|
|
jobject create_default_object(JNIEnv *jnienv, const char *class_name)
|
|
{
|
|
jclass dbclass = get_class(jnienv, class_name);
|
|
jmethodID id = jnienv->GetMethodID(dbclass, "<init>", "()V");
|
|
jobject object = jnienv->NewObject(dbclass, id);
|
|
return object;
|
|
}
|
|
|
|
/* Convert an DB object to a Java encapsulation of that object.
|
|
* Note: This implementation creates a new Java object on each call,
|
|
* so it is generally useful when a new DB object has just been created.
|
|
*/
|
|
jobject convert_object(JNIEnv *jnienv, const char *class_name, void *dbobj)
|
|
{
|
|
if (!dbobj)
|
|
return 0;
|
|
|
|
jobject jo = create_default_object(jnienv, class_name);
|
|
set_private_info(jnienv, class_name, jo, dbobj);
|
|
return jo;
|
|
}
|
|
|
|
/* Create a copy of the string
|
|
*/
|
|
char *dup_string(const char *str)
|
|
{
|
|
char *retval = NEW_ARRAY(char, strlen(str)+1);
|
|
strcpy(retval, str);
|
|
return retval;
|
|
}
|
|
|
|
/* Create a java string from the given string
|
|
*/
|
|
jstring get_java_string(JNIEnv *jnienv, const char* string)
|
|
{
|
|
if (string == 0)
|
|
return 0;
|
|
return jnienv->NewStringUTF(string);
|
|
}
|
|
|
|
/* Convert a java object to the various C pointers they represent.
|
|
*/
|
|
DB *get_DB(JNIEnv *jnienv, jobject obj)
|
|
{
|
|
return (DB *)get_private_info(jnienv, name_DB, obj);
|
|
}
|
|
|
|
DB_BTREE_STAT *get_DB_BTREE_STAT(JNIEnv *jnienv, jobject obj)
|
|
{
|
|
return (DB_BTREE_STAT *)get_private_info(jnienv, name_DB_BTREE_STAT, obj);
|
|
}
|
|
|
|
DBC *get_DBC(JNIEnv *jnienv, jobject obj)
|
|
{
|
|
return (DBC *)get_private_info(jnienv, name_DBC, obj);
|
|
}
|
|
|
|
DB_ENV *get_DB_ENV(JNIEnv *jnienv, jobject obj)
|
|
{
|
|
return (DB_ENV *)get_private_info(jnienv, name_DB_ENV, obj);
|
|
}
|
|
|
|
DB_INFO *get_DB_INFO(JNIEnv *jnienv, jobject obj)
|
|
{
|
|
return (DB_INFO *)get_private_info(jnienv, name_DB_INFO, obj);
|
|
}
|
|
|
|
// A DB_LOCK is just a size_t, so no need for indirection.
|
|
DB_LOCK get_DB_LOCK(JNIEnv *jnienv, jobject obj)
|
|
{
|
|
return (DB_LOCK)get_private_long_info(jnienv, name_DB_LOCK, obj);
|
|
}
|
|
|
|
DB_LOCKTAB *get_DB_LOCKTAB(JNIEnv *jnienv, jobject obj)
|
|
{
|
|
return (DB_LOCKTAB *)get_private_info(jnienv, name_DB_LOCKTAB, obj);
|
|
}
|
|
|
|
DB_LOG *get_DB_LOG(JNIEnv *jnienv, jobject obj)
|
|
{
|
|
return (DB_LOG *)get_private_info(jnienv, name_DB_LOG, obj);
|
|
}
|
|
|
|
DB_LOG_STAT *get_DB_LOG_STAT(JNIEnv *jnienv, jobject obj)
|
|
{
|
|
return (DB_LOG_STAT *)get_private_info(jnienv, name_DB_LOG_STAT, obj);
|
|
}
|
|
|
|
DB_LSN *get_DB_LSN(JNIEnv *jnienv, jobject obj)
|
|
{
|
|
return (DB_LSN *)get_private_info(jnienv, name_DB_LSN, obj);
|
|
}
|
|
|
|
DB_MPOOL *get_DB_MPOOL(JNIEnv *jnienv, jobject obj)
|
|
{
|
|
return (DB_MPOOL *)get_private_info(jnienv, name_DB_MPOOL, obj);
|
|
}
|
|
|
|
DB_MPOOL_FSTAT *get_DB_MPOOL_FSTAT(JNIEnv *jnienv, jobject obj)
|
|
{
|
|
return (DB_MPOOL_FSTAT *)get_private_info(jnienv, name_DB_MPOOL_FSTAT, obj);
|
|
}
|
|
|
|
DB_MPOOL_STAT *get_DB_MPOOL_STAT(JNIEnv *jnienv, jobject obj)
|
|
{
|
|
return (DB_MPOOL_STAT *)get_private_info(jnienv, name_DB_MPOOL_STAT, obj);
|
|
}
|
|
|
|
DB_TXN *get_DB_TXN(JNIEnv *jnienv, jobject obj)
|
|
{
|
|
return (DB_TXN *)get_private_info(jnienv, name_DB_TXN, obj);
|
|
}
|
|
|
|
DB_TXNMGR *get_DB_TXNMGR(JNIEnv *jnienv, jobject obj)
|
|
{
|
|
return (DB_TXNMGR *)get_private_info(jnienv, name_DB_TXNMGR, obj);
|
|
}
|
|
|
|
DB_TXN_STAT *get_DB_TXN_STAT(JNIEnv *jnienv, jobject obj)
|
|
{
|
|
return (DB_TXN_STAT *)get_private_info(jnienv, name_DB_TXN_STAT, obj);
|
|
}
|
|
|
|
DBT_info *get_DBT(JNIEnv *jnienv, jobject obj)
|
|
{
|
|
return (DBT_info *)get_private_info(jnienv, name_DBT, obj);
|
|
}
|
|
|
|
|
|
/* Convert a C pointer to the various Java objects they represent.
|
|
*/
|
|
jobject get_DbBtreeStat(JNIEnv *jnienv, DB_BTREE_STAT *dbobj)
|
|
{
|
|
return convert_object(jnienv, name_DB_BTREE_STAT, dbobj);
|
|
}
|
|
|
|
jobject get_Dbc(JNIEnv *jnienv, DBC *dbobj)
|
|
{
|
|
return convert_object(jnienv, name_DBC, dbobj);
|
|
}
|
|
|
|
jobject get_DbLockTab(JNIEnv *jnienv, DB_LOCKTAB *dbobj)
|
|
{
|
|
return convert_object(jnienv, name_DB_LOCKTAB, dbobj);
|
|
}
|
|
|
|
jobject get_DbLog(JNIEnv *jnienv, DB_LOG *dbobj)
|
|
{
|
|
return convert_object(jnienv, name_DB_LOG, dbobj);
|
|
}
|
|
|
|
jobject get_DbLogStat(JNIEnv *jnienv, DB_LOG_STAT *dbobj)
|
|
{
|
|
return convert_object(jnienv, name_DB_LOG_STAT, dbobj);
|
|
}
|
|
|
|
// LSNs are different since they are really normally
|
|
// treated as by-value objects. We actually create
|
|
// a pointer to the LSN as store that, deleting it
|
|
// when the LSN is GC'd.
|
|
//
|
|
jobject get_DbLsn(JNIEnv *jnienv, DB_LSN dbobj)
|
|
{
|
|
DB_LSN *lsnp = NEW(DB_LSN);
|
|
*lsnp = dbobj;
|
|
return convert_object(jnienv, name_DB_LSN, lsnp);
|
|
}
|
|
|
|
jobject get_DbMpool(JNIEnv *jnienv, DB_MPOOL *dbobj)
|
|
{
|
|
return convert_object(jnienv, name_DB_MPOOL, dbobj);
|
|
}
|
|
|
|
jobject get_DbMpoolFStat(JNIEnv *jnienv, DB_MPOOL_FSTAT *dbobj)
|
|
{
|
|
return convert_object(jnienv, name_DB_MPOOL_FSTAT, dbobj);
|
|
}
|
|
|
|
jobject get_DbMpoolStat(JNIEnv *jnienv, DB_MPOOL_STAT *dbobj)
|
|
{
|
|
return convert_object(jnienv, name_DB_MPOOL_STAT, dbobj);
|
|
}
|
|
|
|
jobject get_DbTxn(JNIEnv *jnienv, DB_TXN *dbobj)
|
|
{
|
|
return convert_object(jnienv, name_DB_TXN, dbobj);
|
|
}
|
|
|
|
jobject get_DbTxnMgr(JNIEnv *jnienv, DB_TXNMGR *dbobj)
|
|
{
|
|
return convert_object(jnienv, name_DB_TXNMGR, dbobj);
|
|
}
|
|
|
|
jobject get_DbTxnStat(JNIEnv *jnienv, DB_TXN_STAT *dbobj)
|
|
{
|
|
return convert_object(jnienv, name_DB_TXN_STAT, dbobj);
|
|
}
|
|
|
|
/****************************************************************
|
|
*
|
|
* Implementation of class DBT_info
|
|
*
|
|
*/
|
|
DBT_info::DBT_info()
|
|
: array_(0)
|
|
, offset_(0)
|
|
{
|
|
memset((DBT*)this, 0, sizeof(DBT));
|
|
}
|
|
|
|
void DBT_info::release(JNIEnv *jnienv)
|
|
{
|
|
if (array_ != 0) {
|
|
jnienv->DeleteGlobalRef(array_);
|
|
}
|
|
}
|
|
|
|
DBT_info::~DBT_info()
|
|
{
|
|
}
|
|
|
|
/****************************************************************
|
|
*
|
|
* Implementation of class LockedDBT
|
|
*
|
|
*/
|
|
LockedDBT::LockedDBT(JNIEnv *jnienv, jobject obj, int is_retrieve_op)
|
|
: env_(jnienv)
|
|
, obj_(obj)
|
|
, has_error_(0)
|
|
, is_retrieve_op_(is_retrieve_op)
|
|
, java_array_len_(0)
|
|
, java_data_(0)
|
|
/* dbt initialized below */
|
|
{
|
|
dbt = (DBT_info *)get_private_info(jnienv, name_DBT, obj);
|
|
if (!verify_non_null(jnienv, dbt)) {
|
|
has_error_ = 1;
|
|
return;
|
|
}
|
|
|
|
if ((dbt->flags & DB_DBT_USERMEM) || !is_retrieve_op_) {
|
|
|
|
// If writing with DB_DBT_USERMEM or reading, then the data
|
|
// should point the java array.
|
|
//
|
|
if (!dbt->array_) {
|
|
report_exception(jnienv, "Dbt.data is null", 0);
|
|
has_error_ = 1;
|
|
return;
|
|
}
|
|
|
|
// Verify other parameters
|
|
//
|
|
java_array_len_ = jnienv->GetArrayLength(dbt->array_);
|
|
if (dbt->offset_ < 0 ) {
|
|
report_exception(jnienv, "Dbt.offset illegal", 0);
|
|
has_error_ = 1;
|
|
return;
|
|
}
|
|
if (dbt->ulen + dbt->offset_ > java_array_len_) {
|
|
report_exception(jnienv,
|
|
"Dbt.ulen + Dbt.offset greater than array length", 0);
|
|
has_error_ = 1;
|
|
return;
|
|
}
|
|
|
|
java_data_ = jnienv->GetByteArrayElements(dbt->array_, NULL);
|
|
dbt->data = java_data_ + dbt->offset_;
|
|
}
|
|
else {
|
|
|
|
// If writing with DB_DBT_MALLOC, then the data is
|
|
// allocated by DB.
|
|
//
|
|
dbt->data = 0;
|
|
}
|
|
}
|
|
|
|
LockedDBT::~LockedDBT()
|
|
{
|
|
// If there was an error in the constructor,
|
|
// everything is already cleaned up.
|
|
//
|
|
if (has_error_)
|
|
return;
|
|
|
|
if ((dbt->flags & DB_DBT_USERMEM) || !is_retrieve_op_) {
|
|
|
|
// If writing with DB_DBT_USERMEM or reading, then the data
|
|
// may be already in the java array, in which case,
|
|
// we just need to release it.
|
|
// If DB didn't put it in the array (indicated by the
|
|
// dbt->data changing), we need to do that
|
|
//
|
|
jbyte *data = (jbyte *)dbt->data;
|
|
data -= dbt->offset_;
|
|
if (data != java_data_) {
|
|
env_->SetByteArrayRegion(dbt->array_, dbt->offset_, dbt->ulen, data);
|
|
}
|
|
env_->ReleaseByteArrayElements(dbt->array_, java_data_, 0);
|
|
dbt->data = 0;
|
|
}
|
|
else {
|
|
|
|
// If writing with DB_DBT_MALLOC, then the data was allocated
|
|
// by DB. If dbt->data is zero, it means an error occurred
|
|
// (and should have been already reported).
|
|
//
|
|
if (dbt->data) {
|
|
|
|
// Release any old references.
|
|
//
|
|
dbt->release(env_);
|
|
|
|
dbt->array_ = (jbyteArray)
|
|
env_->NewGlobalRef(env_->NewByteArray(dbt->size));
|
|
dbt->offset_ = 0;
|
|
env_->SetByteArrayRegion(dbt->array_, 0, dbt->size, (jbyte *)dbt->data);
|
|
free(dbt->data);
|
|
dbt->data = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************************************************
|
|
*
|
|
* Implementation of class LockedString
|
|
*
|
|
*/
|
|
LockedString::LockedString(JNIEnv *jnienv, jstring jstr)
|
|
: env_(jnienv)
|
|
, jstr_(jstr)
|
|
{
|
|
if (jstr == 0)
|
|
string = 0;
|
|
else
|
|
string = jnienv->GetStringUTFChars(jstr, NULL);
|
|
}
|
|
|
|
LockedString::~LockedString()
|
|
{
|
|
if (jstr_)
|
|
env_->ReleaseStringUTFChars(jstr_, string);
|
|
}
|
|
|
|
|
|
/****************************************************************
|
|
*
|
|
* Implementation of class LockedStringArray
|
|
*
|
|
*/
|
|
LockedStringArray::LockedStringArray(JNIEnv *jnienv, jobjectArray arr)
|
|
: env_(jnienv)
|
|
, arr_(arr)
|
|
, string_array(0)
|
|
{
|
|
typedef const char *conststr;
|
|
|
|
if (arr != 0) {
|
|
int count = jnienv->GetArrayLength(arr);
|
|
string_array = NEW_ARRAY(conststr, count+1);
|
|
for (int i=0; i<count; i++) {
|
|
jstring jstr = (jstring)jnienv->GetObjectArrayElement(arr, i);
|
|
if (jstr == 0) {
|
|
//
|
|
// An embedded null in the string array is treated
|
|
// as an endpoint.
|
|
//
|
|
string_array[i] = 0;
|
|
break;
|
|
}
|
|
else {
|
|
string_array[i] = jnienv->GetStringUTFChars(jstr, NULL);
|
|
}
|
|
}
|
|
string_array[count] = 0;
|
|
}
|
|
}
|
|
|
|
LockedStringArray::~LockedStringArray()
|
|
{
|
|
if (arr_) {
|
|
int count = env_->GetArrayLength(arr_);
|
|
for (int i=0; i<count; i++) {
|
|
if (string_array[i] == 0)
|
|
break;
|
|
jstring jstr = (jstring)env_->GetObjectArrayElement(arr_, i);
|
|
env_->ReleaseStringUTFChars(jstr, string_array[i]);
|
|
}
|
|
DELETE(string_array);
|
|
}
|
|
}
|