mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-04 23:02:02 +01:00
519 lines
15 KiB
C
519 lines
15 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 <sys/time.h>
|
|
#include <time.h>
|
|
|
|
#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 );
|
|
}
|
|
|
|
XP_UCHAR*
|
|
getStringCopy( MPFORMAL JNIEnv* env, jstring jstr )
|
|
{
|
|
XP_UCHAR* result = NULL;
|
|
if ( NULL != jstr ) {
|
|
jsize len = 1 + (*env)->GetStringUTFLength( env, jstr );
|
|
const char* chars = (*env)->GetStringUTFChars( env, jstr, NULL );
|
|
result = XP_MALLOC( mpool, len );
|
|
XP_MEMCPY( result, chars, len );
|
|
(*env)->ReleaseStringUTFChars( env, jstr, chars );
|
|
}
|
|
return result;
|
|
}
|
|
|
|
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 );
|
|
}
|
|
|
|
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 );
|
|
setBool( env, jaddr, "ip_relay_seeksPublicRoom",
|
|
addr->u.ip_relay.seeksPublicRoom );
|
|
setBool( env, jaddr, "ip_relay_advertiseRoom",
|
|
addr->u.ip_relay.advertiseRoom );
|
|
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) );
|
|
addr->u.ip_relay.seeksPublicRoom =
|
|
getBool( env, jaddr, "ip_relay_seeksPublicRoom" );
|
|
addr->u.ip_relay.advertiseRoom =
|
|
getBool( env, jaddr, "ip_relay_advertiseRoom" );
|
|
|
|
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
|
|
void
|
|
android_debugf( const char* format, ... )
|
|
{
|
|
char buf[1024];
|
|
va_list ap;
|
|
int len;
|
|
struct tm* timp;
|
|
struct timeval tv;
|
|
struct timezone tz;
|
|
|
|
gettimeofday( &tv, &tz );
|
|
timp = localtime( &tv.tv_sec );
|
|
|
|
len = snprintf( buf, sizeof(buf), "%.2d:%.2d:%.2d: ",
|
|
timp->tm_hour, timp->tm_min, timp->tm_sec );
|
|
if ( len < sizeof(buf) ) {
|
|
va_start(ap, format);
|
|
vsnprintf( buf + len, sizeof(buf)-len, format, ap );
|
|
va_end(ap);
|
|
}
|
|
|
|
(void)__android_log_write( ANDROID_LOG_DEBUG, "xw4", buf );
|
|
}
|
|
#endif
|
|
|
|
|
|
/* #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 */
|
|
|
|
#ifndef MEM_DEBUG
|
|
void
|
|
and_freep( void** ptrp )
|
|
{
|
|
if ( !!*ptrp ) {
|
|
free( *ptrp );
|
|
*ptrp = NULL;
|
|
}
|
|
}
|
|
#endif
|