xwords/xwords4/android/XWords4/jni/andutils.c
Andy2 51d759569a call srand with current time (attempting to fix what may be duplicate
seeds on relay, possible if rand() always starts with same sequence on
different devices in new process); add commented-out logging util_rand
implementation.
2010-07-29 06:53:06 -07:00

456 lines
13 KiB
C

/* -*-mode: C; compile-command: "../../scripts/ndkbuild.sh"; -*- */
/*
* Copyright © 2009-2010 by Eric House (xwords@eehouse.org). All
* rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "andutils.h"
#include "comtypes.h"
#include "xwstream.h"
void
and_assert( const char* test, int line, const char* file, const char* func )
{
XP_LOGF( "assertion \"%s\" failed: line %d in %s() in %s",
test, line, file, func );
__android_log_assert( test, "ASSERT", "line %d in %s() in %s",
line, file, func );
}
#ifdef __LITTLE_ENDIAN
XP_U32
and_ntohl(XP_U32 ll)
{
XP_U32 result = 0L;
int ii;
for ( ii = 0; ii < 4; ++ii ) {
result <<= 8;
result |= ll & 0x000000FF;
ll >>= 8;
}
return result;
}
XP_U16
and_ntohs( XP_U16 ss )
{
XP_U16 result;
result = ss << 8;
result |= ss >> 8;
return result;
}
XP_U32
and_htonl( XP_U32 ll )
{
return and_ntohl( ll );
}
XP_U16
and_htons( XP_U16 ss )
{
return and_ntohs( ss );
}
#else
error error error
#endif
int
getInt( JNIEnv* env, jobject obj, const char* name )
{
jclass cls = (*env)->GetObjectClass( env, obj );
XP_ASSERT( !!cls );
jfieldID fid = (*env)->GetFieldID( env, cls, name, "I");
XP_ASSERT( !!fid );
int result = (*env)->GetIntField( env, obj, fid );
(*env)->DeleteLocalRef( env, cls );
return result;
}
void
setInt( JNIEnv* env, jobject obj, const char* name, int value )
{
jclass cls = (*env)->GetObjectClass( env, obj );
XP_ASSERT( !!cls );
jfieldID fid = (*env)->GetFieldID( env, cls, name, "I");
XP_ASSERT( !!fid );
(*env)->SetIntField( env, obj, fid, value );
(*env)->DeleteLocalRef( env, cls );
}
bool
setBool( JNIEnv* env, jobject obj, const char* name, bool value )
{
bool success = false;
jclass cls = (*env)->GetObjectClass( env, obj );
jfieldID fid = (*env)->GetFieldID( env, cls, name, "Z");
if ( 0 != fid ) {
(*env)->SetBooleanField( env, obj, fid, value );
success = true;
}
(*env)->DeleteLocalRef( env, cls );
return success;
}
bool
setString( JNIEnv* env, jobject obj, const char* name, const XP_UCHAR* value )
{
bool success = false;
jclass cls = (*env)->GetObjectClass( env, obj );
jfieldID fid = (*env)->GetFieldID( env, cls, name, "Ljava/lang/String;" );
(*env)->DeleteLocalRef( env, cls );
if ( 0 != fid ) {
jstring str = (*env)->NewStringUTF( env, value );
(*env)->SetObjectField( env, obj, fid, str );
success = true;
(*env)->DeleteLocalRef( env, str );
}
return success;
}
void
getString( JNIEnv* env, jobject obj, const char* name, XP_UCHAR* buf,
int bufLen )
{
jclass cls = (*env)->GetObjectClass( env, obj );
XP_ASSERT( !!cls );
jfieldID fid = (*env)->GetFieldID( env, cls, name, "Ljava/lang/String;" );
XP_ASSERT( !!fid );
jstring jstr = (*env)->GetObjectField( env, obj, fid );
jsize len = 0;
if ( !!jstr ) { /* might be null */
len = (*env)->GetStringUTFLength( env, jstr );
XP_ASSERT( len < bufLen );
const char* chars = (*env)->GetStringUTFChars( env, jstr, NULL );
XP_MEMCPY( buf, chars, len );
(*env)->ReleaseStringUTFChars( env, jstr, chars );
(*env)->DeleteLocalRef( env, jstr );
}
buf[len] = '\0';
(*env)->DeleteLocalRef( env, cls );
}
bool
getObject( JNIEnv* env, jobject obj, const char* name, const char* sig,
jobject* ret )
{
jclass cls = (*env)->GetObjectClass( env, obj );
XP_ASSERT( !!cls );
jfieldID fid = (*env)->GetFieldID( env, cls, name, sig );
XP_ASSERT( !!fid );
*ret = (*env)->GetObjectField( env, obj, fid );
XP_ASSERT( !!*ret );
(*env)->DeleteLocalRef( env, cls );
return true;
}
void
setObject( JNIEnv* env, jobject obj, const char* name, const char* sig,
jobject val )
{
jclass cls = (*env)->GetObjectClass( env, obj );
XP_ASSERT( !!cls );
jfieldID fid = (*env)->GetFieldID( env, cls, name, sig );
XP_ASSERT( !!fid );
(*env)->SetObjectField( env, obj, fid, val );
(*env)->DeleteLocalRef( env, cls );
}
/* return false on failure, e.g. exception raised */
bool
getBool( JNIEnv* env, jobject obj, const char* name )
{
bool result;
jclass cls = (*env)->GetObjectClass( env, obj );
XP_ASSERT( !!cls );
jfieldID fid = (*env)->GetFieldID( env, cls, name, "Z");
XP_ASSERT( !!fid );
result = (*env)->GetBooleanField( env, obj, fid );
(*env)->DeleteLocalRef( env, cls );
return result;
}
jintArray
makeIntArray( JNIEnv *env, int siz, const jint* vals )
{
jintArray array = (*env)->NewIntArray( env, siz );
XP_ASSERT( !!array );
if ( !!vals ) {
jint* elems = (*env)->GetIntArrayElements( env, array, NULL );
XP_ASSERT( !!elems );
XP_MEMCPY( elems, vals, siz * sizeof(*elems) );
(*env)->ReleaseIntArrayElements( env, array, elems, 0 );
}
return array;
}
jbyteArray
makeByteArray( JNIEnv *env, int siz, const jbyte* vals )
{
jbyteArray array = (*env)->NewByteArray( env, siz );
XP_ASSERT( !!array );
if ( !!vals ) {
jbyte* elems = (*env)->GetByteArrayElements( env, array, NULL );
XP_ASSERT( !!elems );
XP_MEMCPY( elems, vals, siz * sizeof(*elems) );
(*env)->ReleaseByteArrayElements( env, array, elems, 0 );
}
return array;
}
void
setBoolArray( JNIEnv* env, jbooleanArray jarr, int count,
const jboolean* vals )
{
jboolean* elems = (*env)->GetBooleanArrayElements( env, jarr, NULL );
XP_ASSERT( !!elems );
XP_MEMCPY( elems, vals, count * sizeof(*elems) );
(*env)->ReleaseBooleanArrayElements( env, jarr, elems, 0 );
}
jbooleanArray
makeBooleanArray( JNIEnv *env, int siz, const jboolean* vals )
{
jbooleanArray array = (*env)->NewBooleanArray( env, siz );
XP_ASSERT( !!array );
if ( !!vals ) {
setBoolArray( env, array, siz, vals );
}
return array;
}
int
getIntFromArray( JNIEnv* env, jintArray arr, bool del )
{
jint* ints = (*env)->GetIntArrayElements(env, arr, 0);
int result = ints[0];
(*env)->ReleaseIntArrayElements( env, arr, ints, 0);
if ( del ) {
(*env)->DeleteLocalRef( env, arr );
}
return result;
}
jobjectArray
makeStringArray( JNIEnv *env, int siz, const XP_UCHAR** vals )
{
jclass clas = (*env)->FindClass(env, "java/lang/String");
jstring empty = (*env)->NewStringUTF( env, "" );
jobjectArray jarray = (*env)->NewObjectArray( env, siz, clas, empty );
(*env)->DeleteLocalRef( env, clas );
(*env)->DeleteLocalRef( env, empty );
int ii;
for ( ii = 0; ii < siz; ++ii ) {
jstring jstr = (*env)->NewStringUTF( env, vals[ii] );
(*env)->SetObjectArrayElement( env, jarray, ii, jstr );
(*env)->DeleteLocalRef( env, jstr );
}
return jarray;
}
jstring
streamToJString( MPFORMAL JNIEnv *env, XWStreamCtxt* stream )
{
int len = stream_getSize( stream );
XP_UCHAR* buf = XP_MALLOC( mpool, 1 + len );
stream_getBytes( stream, buf, len );
buf[len] = '\0';
jstring jstr = (*env)->NewStringUTF( env, buf );
XP_FREE( mpool, buf );
return jstr;
}
jmethodID
getMethodID( JNIEnv* env, jobject obj, const char* proc, const char* sig )
{
XP_ASSERT( !!env );
jclass cls = (*env)->GetObjectClass( env, obj );
XP_ASSERT( !!cls );
jmethodID mid = (*env)->GetMethodID( env, cls, proc, sig );
XP_ASSERT( !!mid );
(*env)->DeleteLocalRef( env, cls );
return mid;
}
void
setJAddrRec( JNIEnv* env, jobject jaddr, const CommsAddrRec* addr )
{
XP_ASSERT( !!addr );
intToJenumField( env, jaddr, addr->conType, "conType",
"org/eehouse/android/xw4/jni/CommsAddrRec$CommsConnType" );
switch ( addr->conType ) {
case COMMS_CONN_NONE:
break;
case COMMS_CONN_RELAY:
setInt( env, jaddr, "ip_relay_port", addr->u.ip_relay.port );
setString( env, jaddr, "ip_relay_hostName", addr->u.ip_relay.hostName );
setString( env, jaddr, "ip_relay_invite", addr->u.ip_relay.invite );
break;
case COMMS_CONN_SMS:
setString( env, jaddr, "sms_phone", addr->u.sms.phone );
XP_LOGF( "%s: got SMS; phone=%s", __func__, addr->u.sms.phone );
setInt( env, jaddr, "sms_port", addr->u.sms.port );
break;
case COMMS_CONN_BT:
default:
XP_ASSERT(0);
}
}
void
getJAddrRec( JNIEnv* env, CommsAddrRec* addr, jobject jaddr )
{
addr->conType = jenumFieldToInt( env, jaddr, "conType",
"org/eehouse/android/xw4/jni/"
"CommsAddrRec$CommsConnType" );
switch ( addr->conType ) {
case COMMS_CONN_NONE:
break;
case COMMS_CONN_RELAY:
addr->u.ip_relay.port = getInt( env, jaddr, "ip_relay_port" );
getString( env, jaddr, "ip_relay_hostName", addr->u.ip_relay.hostName,
VSIZE(addr->u.ip_relay.hostName) );
getString( env, jaddr, "ip_relay_invite", addr->u.ip_relay.invite,
VSIZE(addr->u.ip_relay.invite) );
break;
case COMMS_CONN_SMS:
getString( env, jaddr, "sms_phone", addr->u.sms.phone,
VSIZE(addr->u.sms.phone) );
XP_LOGF( "%s: got SMS; phone=%s", __func__, addr->u.sms.phone );
addr->u.sms.port = getInt( env, jaddr, "sms_port" );
break;
case COMMS_CONN_BT:
default:
XP_ASSERT(0);
}
}
jint
jenumFieldToInt( JNIEnv* env, jobject j_gi, const char* field,
const char* fieldSig )
{
jclass clazz = (*env)->GetObjectClass( env, j_gi );
XP_ASSERT( !!clazz );
char sig[128];
snprintf( sig, sizeof(sig), "L%s;", fieldSig );
jfieldID fid = (*env)->GetFieldID( env, clazz, field, sig );
XP_ASSERT( !!fid );
jobject jenum = (*env)->GetObjectField( env, j_gi, fid );
XP_ASSERT( !!jenum );
jint result = jEnumToInt( env, jenum );
(*env)->DeleteLocalRef( env, clazz );
(*env)->DeleteLocalRef( env, jenum );
return result;
}
void
intToJenumField( JNIEnv* env, jobject jobj, int val, const char* field,
const char* fieldSig )
{
jclass clazz = (*env)->GetObjectClass( env, jobj );
XP_ASSERT( !!clazz );
char buf[128];
snprintf( buf, sizeof(buf), "L%s;", fieldSig );
jfieldID fid = (*env)->GetFieldID( env, clazz, field, buf );
XP_ASSERT( !!fid ); /* failed */
(*env)->DeleteLocalRef( env, clazz );
jobject jenum = (*env)->GetObjectField( env, jobj, fid );
if ( !jenum ) { /* won't exist in new object */
jclass clazz = (*env)->FindClass( env, fieldSig );
XP_ASSERT( !!clazz );
jmethodID mid = getMethodID( env, clazz, "<init>", "()V" );
XP_ASSERT( !!mid );
jenum = (*env)->NewObject( env, clazz, mid );
XP_ASSERT( !!jenum );
(*env)->SetObjectField( env, jobj, fid, jenum );
(*env)->DeleteLocalRef( env, clazz );
}
jobject jval = intToJEnum( env, val, fieldSig );
XP_ASSERT( !!jval );
(*env)->SetObjectField( env, jobj, fid, jval );
(*env)->DeleteLocalRef( env, jval );
} /* intToJenumField */
/* Cons up a new enum instance and set its value */
jobject
intToJEnum( JNIEnv* env, int val, const char* enumSig )
{
jobject jenum = NULL;
jclass clazz = (*env)->FindClass( env, enumSig );
XP_ASSERT( !!clazz );
char buf[128];
snprintf( buf, sizeof(buf), "()[L%s;", enumSig );
jmethodID mid = (*env)->GetStaticMethodID( env, clazz, "values", buf );
XP_ASSERT( !!mid );
jobject jvalues = (*env)->CallStaticObjectMethod( env, clazz, mid );
XP_ASSERT( !!jvalues );
XP_ASSERT( val < (*env)->GetArrayLength( env, jvalues ) );
/* get the value we want */
jenum = (*env)->GetObjectArrayElement( env, jvalues, val );
XP_ASSERT( !!jenum );
(*env)->DeleteLocalRef( env, jvalues );
(*env)->DeleteLocalRef( env, clazz );
return jenum;
} /* intToJEnum */
jint
jEnumToInt( JNIEnv* env, jobject jenum )
{
jmethodID mid = getMethodID( env, jenum, "ordinal", "()I" );
XP_ASSERT( !!mid );
return (*env)->CallIntMethod( env, jenum, mid );
}
XWStreamCtxt*
and_empty_stream( MPFORMAL AndGlobals* globals )
{
XWStreamCtxt* stream = mem_stream_make( MPPARM(mpool) globals->vtMgr,
globals, 0, NULL );
return stream;
}
/* #ifdef DEBUG */
/* XP_U32 */
/* andy_rand( const char* caller ) */
/* { */
/* XP_U32 result = rand(); */
/* XP_LOGF( "%s: returning 0x%lx to %s", __func__, result, caller ); */
/* LOG_RETURNF( "%lx", result ); */
/* return result; */
/* } */
/* #endif */