From 8fbc9ca3438892d47b700396beed4ca5b5f43edd Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sun, 9 Sep 2012 09:22:00 -0700
Subject: [PATCH 01/44] fix to compile in release mode
---
xwords4/linux/linuxdict.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xwords4/linux/linuxdict.c b/xwords4/linux/linuxdict.c
index 76788be50..068c09372 100644
--- a/xwords4/linux/linuxdict.c
+++ b/xwords4/linux/linuxdict.c
@@ -84,7 +84,7 @@ linux_dictionary_make( MPFORMAL const char* dictFileName, XP_Bool useMMap )
} /* gtk_dictionary_make */
static XP_UCHAR*
-getNullTermParam( LinuxDictionaryCtxt* dctx, const XP_U8** ptr,
+getNullTermParam( LinuxDictionaryCtxt* XP_UNUSED_DBG(dctx), const XP_U8** ptr,
XP_U16* headerLen )
{
XP_U16 len = 1 + XP_STRLEN( (XP_UCHAR*)*ptr );
From 9340db36c1b45704010b6bfc7c5ff766fd4e86e0 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sun, 9 Sep 2012 15:48:57 -0700
Subject: [PATCH 02/44] disallow opening android DBs when not configured
correctly.
---
xwords4/linux/linuxmain.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/xwords4/linux/linuxmain.c b/xwords4/linux/linuxmain.c
index 6eafff375..4543c1bc8 100644
--- a/xwords4/linux/linuxmain.c
+++ b/xwords4/linux/linuxmain.c
@@ -1517,6 +1517,12 @@ main( int argc, char** argv )
break;
#ifdef USE_SQLITE
case CMD_GAMEDB_FILE:
+ /* Android isn't using XWFEATURE_SEARCHLIMIT, and it writes to
+ stream, so to read an android DB is to invite mayhem. */
+# ifdef XWFEATURE_SEARCHLIMIT
+ usage( argv[0], "Don't open android DBs without "
+ "disabling XWFEATURE_SEARCHLIMIT" );
+# endif
mainParams.dbFileName = optarg;
case CMD_GAMEDB_ID:
mainParams.dbFileID = atoi(optarg);
From 1608f0a8f9935605ba6a7144d508c9400af55afb Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sun, 9 Sep 2012 15:49:17 -0700
Subject: [PATCH 03/44] handle missing error messages
---
xwords4/linux/gtkmain.c | 2 ++
xwords4/linux/linuxutl.c | 10 ++++++++++
2 files changed, 12 insertions(+)
diff --git a/xwords4/linux/gtkmain.c b/xwords4/linux/gtkmain.c
index f55298352..733884631 100644
--- a/xwords4/linux/gtkmain.c
+++ b/xwords4/linux/gtkmain.c
@@ -378,6 +378,8 @@ relay_error_gtk( void* closure, XWREASON relayErr )
"relay says another device deleted game.",
GTK_BUTTONS_OK, 1000 );
break;
+ case XWRELAY_ERROR_DEADGAME:
+ break;
default:
assert(0);
break;
diff --git a/xwords4/linux/linuxutl.c b/xwords4/linux/linuxutl.c
index 1b4f9e51c..65db504ec 100644
--- a/xwords4/linux/linuxutl.c
+++ b/xwords4/linux/linuxutl.c
@@ -475,6 +475,16 @@ linux_getErrString( UtilErrID id, XP_Bool* silent )
message = "You tried to supply more players than the host expected.";
break;
+ case ERR_RELAY_BASE + XWRELAY_ERROR_DELETED:
+ message = "Game deleted .";
+ break;
+ case ERR_RELAY_BASE + XWRELAY_ERROR_NORECONN:
+ message = "Cannot reconnect.";
+ break;
+ case ERR_RELAY_BASE + XWRELAY_ERROR_DEADGAME:
+ message = "Game is listed as dead on relay.";
+ break;
+
default:
XP_LOGF( "no code for error: %d", id );
message = "";
From 45de62818b4042fcd2f384a481a5aae4fb7b77db Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sun, 9 Sep 2012 15:49:55 -0700
Subject: [PATCH 04/44] format to 80 columns -- no code change.
---
xwords4/relay/crefmgr.h | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/xwords4/relay/crefmgr.h b/xwords4/relay/crefmgr.h
index cc19b0663..138d76a8e 100644
--- a/xwords4/relay/crefmgr.h
+++ b/xwords4/relay/crefmgr.h
@@ -186,7 +186,8 @@ class SafeCref {
/* SafeCref( CookieRef* cref ); */
~SafeCref();
- bool Forward( HostID src, in_addr& addr, HostID dest, unsigned char* buf, int buflen ) {
+ bool Forward( HostID src, in_addr& addr, HostID dest, unsigned char* buf,
+ int buflen ) {
if ( IsValid() ) {
CookieRef* cref = m_cinfo->GetRef();
assert( 0 != cref->GetCid() );
@@ -206,11 +207,13 @@ class SafeCref {
}
}
- bool Connect( int socket, int nPlayersH, int nPlayersS, int seed, in_addr& addr ) {
+ bool Connect( int socket, int nPlayersH, int nPlayersS, int seed,
+ in_addr& addr ) {
if ( IsValid() ) {
CookieRef* cref = m_cinfo->GetRef();
assert( 0 != cref->GetCid() );
- return cref->_Connect( socket, m_clientVersion, nPlayersH, nPlayersS, seed,
+ return cref->_Connect( socket, m_clientVersion, nPlayersH,
+ nPlayersS, seed,
m_seenSeed, addr );
} else {
return false;
@@ -226,8 +229,9 @@ class SafeCref {
if ( m_dead ) {
*errp = XWRELAY_ERROR_DEADGAME;
} else {
- success = cref->_Reconnect( socket, m_clientVersion, srcID, nPlayersH,
- nPlayersS, seed, addr, m_dead );
+ success = cref->_Reconnect( socket, m_clientVersion, srcID,
+ nPlayersH, nPlayersS, seed, addr,
+ m_dead );
}
}
return success;
From 0ccc2331b5f55af855b9ceab3d788d41d724f4c8 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 10 Sep 2012 07:31:45 -0700
Subject: [PATCH 05/44] address bug where message was getting ACK'd by a device
that failed to save what it had ACK'd leaving the game permanently broken.
Do that by adding a new method game_saveSucceeded() called after the client
claims to have committed bytes returned by game_writeToStream() to disk. In
that method comms updates the value it'll use in subseqent ACKs.
---
xwords4/android/XWords4/jni/xwjni.c | 14 ++++++-
.../eehouse/android/xw4/jni/JNIThread.java | 3 +-
.../org/eehouse/android/xw4/jni/XwJNI.java | 1 +
xwords4/common/comms.c | 42 +++++++++++++++----
xwords4/common/comms.h | 4 +-
xwords4/common/game.c | 13 +++++-
xwords4/common/game.h | 3 +-
xwords4/linux/cursesmain.c | 17 +-------
xwords4/linux/gtkmain.c | 17 ++------
xwords4/linux/linuxmain.c | 23 ++++++++++
xwords4/linux/linuxmain.h | 1 +
xwords4/linux/main.h | 2 +
12 files changed, 97 insertions(+), 43 deletions(-)
diff --git a/xwords4/android/XWords4/jni/xwjni.c b/xwords4/android/XWords4/jni/xwjni.c
index 1135634e9..3447c3f57 100644
--- a/xwords4/android/XWords4/jni/xwjni.c
+++ b/xwords4/android/XWords4/jni/xwjni.c
@@ -211,7 +211,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_gi_1to_1stream
XWStreamCtxt* stream = mem_stream_make( MPPARM(mpool) vtMgr,
NULL, 0, NULL );
- game_saveToStream( NULL, gi, stream );
+ game_saveToStream( NULL, gi, stream, 0 );
destroyGI( MPPARM(mpool) &gi );
int nBytes = stream_getSize( stream );
@@ -344,6 +344,7 @@ typedef struct _JNIState {
XWGame game;
JNIEnv* env;
AndGlobals globals;
+ XP_U16 curSaveCount;
#ifdef DEBUG
const char* envSetterFunc;
#endif
@@ -536,7 +537,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1saveToStream
XWStreamCtxt* stream = mem_stream_make( MPPARM(mpool) globals->vtMgr,
NULL, 0, NULL );
- game_saveToStream( &state->game, gi, stream );
+ game_saveToStream( &state->game, gi, stream, ++state->curSaveCount );
if ( NULL != jgi ) {
destroyGI( MPPARM(mpool) &gi );
@@ -553,6 +554,15 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1saveToStream
return result;
}
+JNIEXPORT void JNICALL
+Java_org_eehouse_android_xw4_jni_XwJNI_game_1saveSucceeded
+( JNIEnv* env, jclass C, jint gamePtr )
+{
+ XWJNI_START();
+ game_saveSucceeded( &state->game, state->curSaveCount );
+ XWJNI_END();
+}
+
JNIEXPORT void JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_board_1invalAll
( JNIEnv *env, jclass C, jint gamePtr )
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java
index a39c9404a..87a6b4f9a 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java
@@ -277,6 +277,8 @@ public class JNIThread extends Thread {
byte[] state = XwJNI.game_saveToStream( m_jniGamePtr, null );
GameUtils.saveGame( m_context, state, m_lock, false );
DBUtils.saveSummary( m_context, m_lock, summary );
+ // There'd better be no way for saveGame above to fail!
+ XwJNI.game_saveSucceeded( m_jniGamePtr );
}
@SuppressWarnings("fallthrough")
@@ -357,7 +359,6 @@ public class JNIThread extends Thread {
(byte[])args[0],
(CommsAddrRec)args[1]);
handle( JNICmd.CMD_DO );
- handle( JNICmd.CMD_ACKANY );
if ( draw ) {
handle( JNICmd.CMD_SAVE );
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/XwJNI.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/XwJNI.java
index 9d687bf5e..52795f0b1 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/XwJNI.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/XwJNI.java
@@ -127,6 +127,7 @@ public class XwJNI {
public static native void game_summarize( int gamePtr, GameSummary summary );
public static native byte[] game_saveToStream( int gamePtr,
CurGameInfo gi );
+ public static native void game_saveSucceeded( int gamePtr );
public static native void game_getGi( int gamePtr, CurGameInfo gi );
public static native void game_getState( int gamePtr,
JNIThread.GameStateInfo gsi );
diff --git a/xwords4/common/comms.c b/xwords4/common/comms.c
index 7a73b64f1..2408053d0 100644
--- a/xwords4/common/comms.c
+++ b/xwords4/common/comms.c
@@ -66,8 +66,15 @@ typedef struct AddressRecord {
struct AddressRecord* next;
CommsAddrRec addr;
MsgID nextMsgID; /* on a per-channel basis */
- MsgID lastMsgRcd; /* on a per-channel basis */
MsgID lastMsgAckd; /* on a per-channel basis */
+
+ /* lastMsgRcd is the numerically highest MsgID we've seen. Because once
+ * it's sent in message as an ACK the other side will delete messages
+ * based on it, we don't send a number higher than has actually been
+ * written out successfully. lastMsgSaved is that number.
+ */
+ MsgID lastMsgRcd;
+ MsgID lastMsgSaved;
/* only used if COMMS_HEARTBEAT set except for serialization (to_stream) */
XP_PlayerAddr channelNo;
struct {
@@ -109,6 +116,7 @@ struct CommsCtxt {
XP_Bool hbTimerPending;
XP_Bool reconTimerPending;
#endif
+ XP_U16 lastSaveToken;
/* The following fields, down to isServer, are only used if
XWFEATURE_RELAY is defined, but I'm leaving them in here so apps built
@@ -575,7 +583,7 @@ comms_makeFromStream( MPFORMAL XWStreamCtxt* stream, XW_UtilCtxt* util,
addrFromStream( &rec->addr, stream );
rec->nextMsgID = stream_getU16( stream );
- rec->lastMsgRcd = stream_getU16( stream );
+ rec->lastMsgSaved = rec->lastMsgRcd = stream_getU16( stream );
if ( version >= STREAM_VERS_BLUETOOTH2 ) {
rec->lastMsgAckd = stream_getU16( stream );
}
@@ -713,7 +721,8 @@ addrToStream( XWStreamCtxt* stream, const CommsAddrRec* addrP )
} /* addrToStream */
void
-comms_writeToStream( const CommsCtxt* comms, XWStreamCtxt* stream )
+comms_writeToStream( CommsCtxt* comms, XWStreamCtxt* stream,
+ XP_U16 saveToken )
{
XP_U16 nAddrRecs;
AddressRecord* rec;
@@ -762,8 +771,26 @@ comms_writeToStream( const CommsCtxt* comms, XWStreamCtxt* stream )
stream_putBytes( stream, msg->msg, msg->len );
}
+ comms->lastSaveToken = saveToken;
} /* comms_writeToStream */
+void
+comms_saveSucceeded( CommsCtxt* comms, XP_U16 saveToken )
+{
+ XP_LOGF( "%s(saveToken=%d)", __func__, saveToken );
+ XP_ASSERT( !!comms );
+ if ( saveToken == comms->lastSaveToken ) {
+ XP_LOGF( "%s: lastSave matches", __func__ );
+ AddressRecord* rec;
+ for ( rec = comms->recs; !!rec; rec = rec->next ) {
+ rec->lastMsgSaved = rec->lastMsgRcd;
+ }
+#ifdef XWFEATURE_COMMSACK
+ comms_ackAny( comms ); /* might not want this for all transports */
+#endif
+ }
+}
+
void
comms_getAddr( const CommsCtxt* comms, CommsAddrRec* addr )
{
@@ -902,7 +929,7 @@ makeElemWithID( CommsCtxt* comms, MsgID msgID, AddressRecord* rec,
{
XP_U16 headerLen;
XP_U16 streamSize = NULL == stream? 0 : stream_getSize( stream );
- MsgID lastMsgRcd = (!!rec)? rec->lastMsgRcd : 0;
+ MsgID lastMsgSaved = (!!rec)? rec->lastMsgSaved : 0;
MsgQueueElem* newMsgElem;
XWStreamCtxt* msgStream;
@@ -924,10 +951,10 @@ makeElemWithID( CommsCtxt* comms, MsgID msgID, AddressRecord* rec,
stream_putU16( msgStream, channelNo );
stream_putU32( msgStream, msgID );
- XP_LOGF( "put lastMsgRcd: %ld", lastMsgRcd );
- stream_putU32( msgStream, lastMsgRcd );
+ XP_LOGF( "put lastMsgSaved: %ld", lastMsgSaved );
+ stream_putU32( msgStream, lastMsgSaved );
if ( !!rec ) {
- rec->lastMsgAckd = lastMsgRcd;
+ rec->lastMsgAckd = lastMsgSaved;
}
headerLen = stream_getSize( msgStream );
@@ -1734,6 +1761,7 @@ comms_checkIncomingStream( CommsCtxt* comms, XWStreamCtxt* stream,
XP_LOGF( "%s: got channelNo=%d;msgID=%ld;len=%d", __func__,
channelNo & CHANNEL_MASK, msgID, payloadSize );
rec->lastMsgRcd = msgID;
+ comms->lastSaveToken = 0; /* lastMsgRcd no longer valid */
stream_setAddress( stream, channelNo );
messageValid = payloadSize > 0;
}
diff --git a/xwords4/common/comms.h b/xwords4/common/comms.h
index 78aa361a2..7907be490 100644
--- a/xwords4/common/comms.h
+++ b/xwords4/common/comms.h
@@ -198,7 +198,9 @@ CommsCtxt* comms_makeFromStream( MPFORMAL XWStreamCtxt* stream,
XW_UtilCtxt* util,
const TransportProcs* procs );
void comms_start( CommsCtxt* comms );
-void comms_writeToStream( const CommsCtxt* comms, XWStreamCtxt* stream );
+void comms_writeToStream( CommsCtxt* comms, XWStreamCtxt* stream,
+ XP_U16 saveToken );
+void comms_saveSucceeded( CommsCtxt* comms, XP_U16 saveToken );
XP_S16 comms_send( CommsCtxt* comms, XWStreamCtxt* stream );
XP_Bool comms_resendAll( CommsCtxt* comms );
diff --git a/xwords4/common/game.c b/xwords4/common/game.c
index b4f1db0cf..4310ebd9e 100644
--- a/xwords4/common/game.c
+++ b/xwords4/common/game.c
@@ -259,8 +259,9 @@ game_makeFromStream( MPFORMAL XWStreamCtxt* stream, XWGame* game,
void
game_saveToStream( const XWGame* game, const CurGameInfo* gi,
- XWStreamCtxt* stream )
+ XWStreamCtxt* stream, XP_U16 saveToken )
{
+ XP_ASSERT( 0 != saveToken );
stream_putU8( stream, CUR_STREAM_VERS );
stream_setVersion( stream, CUR_STREAM_VERS );
@@ -272,7 +273,7 @@ game_saveToStream( const XWGame* game, const CurGameInfo* gi,
XP_ASSERT( !game->comms );
#endif
if ( !!game->comms ) {
- comms_writeToStream( game->comms, stream );
+ comms_writeToStream( game->comms, stream, saveToken );
}
model_writeToStream( game->model, stream );
@@ -281,6 +282,14 @@ game_saveToStream( const XWGame* game, const CurGameInfo* gi,
}
} /* game_saveToStream */
+void
+game_saveSucceeded( const XWGame* game, XP_U16 saveToken )
+{
+ if ( !!game->comms ) {
+ comms_saveSucceeded( game->comms, saveToken );
+ }
+}
+
void
game_getState( const XWGame* game, GameStateInfo* gsi )
{
diff --git a/xwords4/common/game.h b/xwords4/common/game.h
index c1bc42c3a..3ac1c7286 100644
--- a/xwords4/common/game.h
+++ b/xwords4/common/game.h
@@ -103,7 +103,8 @@ XP_Bool game_makeFromStream( MPFORMAL XWStreamCtxt* stream, XWGame* game,
const TransportProcs* procs );
void game_saveToStream( const XWGame* game, const CurGameInfo* gi,
- XWStreamCtxt* stream );
+ XWStreamCtxt* stream, XP_U16 saveToken );
+void game_saveSucceeded( const XWGame* game, XP_U16 saveToken );
void game_dispose( XWGame* game );
void game_getState( const XWGame* game, GameStateInfo* gsi );
diff --git a/xwords4/linux/cursesmain.c b/xwords4/linux/cursesmain.c
index 457caeb34..3380d5fc6 100644
--- a/xwords4/linux/cursesmain.c
+++ b/xwords4/linux/cursesmain.c
@@ -1893,22 +1893,7 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
}
#endif
}
- if ( !!g_globals.cGlobals.params->fileName ) {
- XWStreamCtxt* outStream;
-
- outStream =
- mem_stream_make( MPPARM(g_globals.cGlobals.params->util->mpool)
- g_globals.cGlobals.params->vtMgr,
- &g_globals.cGlobals, 0, writeToFile );
- stream_open( outStream );
-
- game_saveToStream( &g_globals.cGlobals.game,
- &g_globals.cGlobals.params->gi,
- outStream );
-
- stream_destroy( outStream );
- sync();
- }
+ saveGame( &g_globals.cGlobals );
game_dispose( &g_globals.cGlobals.game ); /* takes care of the dict */
gi_disposePlayerInfo( MEMPOOL &g_globals.cGlobals.params->gi );
diff --git a/xwords4/linux/gtkmain.c b/xwords4/linux/gtkmain.c
index 733884631..fe50008f2 100644
--- a/xwords4/linux/gtkmain.c
+++ b/xwords4/linux/gtkmain.c
@@ -680,19 +680,7 @@ quit( void )
static void
cleanup( GtkAppGlobals* globals )
{
- if ( !!globals->cGlobals.params->fileName ) {
- XWStreamCtxt* outStream;
-
- outStream = mem_stream_make( MEMPOOL globals->cGlobals.params->vtMgr,
- globals, 0, writeToFile );
- stream_open( outStream );
-
- game_saveToStream( &globals->cGlobals.game,
- &globals->cGlobals.params->gi,
- outStream );
-
- stream_destroy( outStream );
- }
+ saveGame( &globals->cGlobals );
game_dispose( &globals->cGlobals.game ); /* takes care of the dict */
gi_disposePlayerInfo( MEMPOOL &globals->cGlobals.params->gi );
@@ -2088,6 +2076,9 @@ newConnectionInput( GIOChannel *source,
redraw =
server_receiveMessage(globals->cGlobals.game.server,
inboundS );
+ if ( redraw ) {
+ saveGame( &globals->cGlobals );
+ }
}
stream_destroy( inboundS );
}
diff --git a/xwords4/linux/linuxmain.c b/xwords4/linux/linuxmain.c
index 4543c1bc8..02d8c4c12 100644
--- a/xwords4/linux/linuxmain.c
+++ b/xwords4/linux/linuxmain.c
@@ -175,6 +175,8 @@ writeToFile( XWStreamCtxt* stream, void* closure )
}
free( buf );
+
+ game_saveSucceeded( &cGlobals->game, cGlobals->curSaveToken );
} /* writeToFile */
void
@@ -233,6 +235,27 @@ strFromStream( XWStreamCtxt* stream )
return buf;
} /* strFromStream */
+void
+saveGame( CommonGlobals* cGlobals )
+{
+ if ( !!cGlobals->params->fileName ) {
+ XWStreamCtxt* outStream;
+
+ outStream = mem_stream_make( cGlobals->params->util->mpool,
+ cGlobals->params->vtMgr,
+ cGlobals, 0, writeToFile );
+ stream_open( outStream );
+
+ game_saveToStream( &cGlobals->game,
+ &cGlobals->params->gi,
+ outStream, ++cGlobals->curSaveToken );
+
+ stream_destroy( outStream );
+
+ game_saveSucceeded( &cGlobals->game, cGlobals->curSaveToken );
+ }
+}
+
static void
handle_messages_from( CommonGlobals* cGlobals, const TransportProcs* procs,
int fdin )
diff --git a/xwords4/linux/linuxmain.h b/xwords4/linux/linuxmain.h
index 212c10e6b..876329e37 100644
--- a/xwords4/linux/linuxmain.h
+++ b/xwords4/linux/linuxmain.h
@@ -66,6 +66,7 @@ XWStreamCtxt* streamFromFile( CommonGlobals* cGlobals, char* name,
void* closure );
XWStreamCtxt* streamFromDB( CommonGlobals* cGlobals, void* closure );
void writeToFile( XWStreamCtxt* stream, void* closure );
+void saveGame( CommonGlobals* cGlobals );
int blocking_read( int fd, unsigned char* buf, int len );
diff --git a/xwords4/linux/main.h b/xwords4/linux/main.h
index b2410b727..140b40fae 100644
--- a/xwords4/linux/main.h
+++ b/xwords4/linux/main.h
@@ -193,6 +193,8 @@ struct CommonGlobals {
#endif
TimerInfo timerInfo[NUM_TIMERS_PLUS_ONE];
+
+ XP_U16 curSaveToken;
};
#endif
From ad4231289ff4fc788be4cac9687f22b4302a7364 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 11 Sep 2012 07:24:51 -0700
Subject: [PATCH 06/44] fix --max-devs and resigns begin allowed when only one
game
---
xwords4/linux/scripts/discon_ok2.sh | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/xwords4/linux/scripts/discon_ok2.sh b/xwords4/linux/scripts/discon_ok2.sh
index a49809e12..7489cf55b 100755
--- a/xwords4/linux/scripts/discon_ok2.sh
+++ b/xwords4/linux/scripts/discon_ok2.sh
@@ -74,9 +74,9 @@ print_cmdline() {
function pick_ndevs() {
local NDEVS=2
local RNUM=$((RANDOM % 100))
- if [ $RNUM -gt 90 ]; then
+ if [ $RNUM -gt 90 -a $MAXDEVS -ge 4 ]; then
NDEVS=4
- elif [ $RNUM -gt 75 ]; then
+ elif [ $RNUM -gt 75 -a $MAXDEVS -ge 3 ]; then
NDEVS=3
fi
echo $NDEVS
@@ -563,7 +563,7 @@ done
[ -z "$PORT" ] && PORT=10997
[ -z "$TIMEOUT" ] && TIMEOUT=$((NGAMES*60+500))
[ -z "$SAVE_GOOD" ] && SAVE_GOOD=YES
-[ -z "$RESIGN_RATIO" ] && RESIGN_RATIO=1000
+[ -z "$RESIGN_RATIO" -a "$NGAMES" -gt 1 ] && RESIGN_RATIO=1000 || RESIGN_RATIO=0
[ -z "$DROP_N" ] && DROP_N=0
[ -z "$USE_GTK" ] && USE_GTK=FALSE
[ -z "$UPGRADE_ODDS" ] && UPGRADE_ODDS=10
From 75474e1891899080b496c948468f2066577ed229 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 11 Sep 2012 07:26:17 -0700
Subject: [PATCH 07/44] Add option to pretend save failed a random pct of time.
Point it to test fix for problem on Android, but right now turning this on
breaks networking.
---
xwords4/linux/linuxmain.c | 41 +++++++++++++++++++++++++++------------
xwords4/linux/main.h | 1 +
2 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/xwords4/linux/linuxmain.c b/xwords4/linux/linuxmain.c
index 02d8c4c12..037b881a9 100644
--- a/xwords4/linux/linuxmain.c
+++ b/xwords4/linux/linuxmain.c
@@ -175,8 +175,6 @@ writeToFile( XWStreamCtxt* stream, void* closure )
}
free( buf );
-
- game_saveSucceeded( &cGlobals->game, cGlobals->curSaveToken );
} /* writeToFile */
void
@@ -239,20 +237,33 @@ void
saveGame( CommonGlobals* cGlobals )
{
if ( !!cGlobals->params->fileName ) {
- XWStreamCtxt* outStream;
+ XP_Bool doSave = XP_TRUE;
+ if ( 0 < cGlobals->params->saveFailPct
+ /* don't fail to save first time! */
+ && file_exists( cGlobals->params->fileName ) ) {
+ XP_U16 pct = XP_RANDOM() % 100;
+ doSave = pct >= cGlobals->params->saveFailPct;
+ }
- outStream = mem_stream_make( cGlobals->params->util->mpool,
- cGlobals->params->vtMgr,
- cGlobals, 0, writeToFile );
- stream_open( outStream );
+ if ( doSave ) {
+ XWStreamCtxt* outStream;
- game_saveToStream( &cGlobals->game,
- &cGlobals->params->gi,
- outStream, ++cGlobals->curSaveToken );
+ outStream = mem_stream_make( cGlobals->params->util->mpool,
+ cGlobals->params->vtMgr,
+ cGlobals, 0, writeToFile );
+ stream_open( outStream );
- stream_destroy( outStream );
+ game_saveToStream( &cGlobals->game,
+ &cGlobals->params->gi,
+ outStream, ++cGlobals->curSaveToken );
- game_saveSucceeded( &cGlobals->game, cGlobals->curSaveToken );
+ stream_destroy( outStream );
+
+ game_saveSucceeded( &cGlobals->game, cGlobals->curSaveToken );
+ XP_LOGF( "%s: saved", __func__ );
+ } else {
+ XP_LOGF( "%s: simulating save failure", __func__ );
+ }
}
}
@@ -481,6 +492,7 @@ typedef enum {
,CMD_SEED
,CMD_GAMESEED
,CMD_GAMEFILE
+ ,CMD_SAVEFAIL_PCT
#ifdef USE_SQLITE
,CMD_GAMEDB_FILE
,CMD_GAMEDB_ID
@@ -572,6 +584,7 @@ static CmdInfoRec CmdInfoRecs[] = {
,{ CMD_SEED, true, "seed", "random seed" }
,{ CMD_GAMESEED, true, "game-seed", "game seed (for relay play)" }
,{ CMD_GAMEFILE, true, "file", "file to save to/read from" }
+ ,{ CMD_SAVEFAIL_PCT, true, "savefail-pct", "How often, at random, does save fail?" }
#ifdef USE_SQLITE
,{ CMD_GAMEDB_FILE, true, "game-db-file",
"sqlite3 file, android format, holding game" }
@@ -1538,6 +1551,10 @@ main( int argc, char** argv )
case CMD_GAMEFILE:
mainParams.fileName = optarg;
break;
+ case CMD_SAVEFAIL_PCT:
+ mainParams.saveFailPct = atoi( optarg );
+ break;
+
#ifdef USE_SQLITE
case CMD_GAMEDB_FILE:
/* Android isn't using XWFEATURE_SEARCHLIMIT, and it writes to
diff --git a/xwords4/linux/main.h b/xwords4/linux/main.h
index 140b40fae..f8558b02f 100644
--- a/xwords4/linux/main.h
+++ b/xwords4/linux/main.h
@@ -49,6 +49,7 @@ typedef struct LaunchParams {
CurGameInfo gi;
PlayerDicts dicts;
char* fileName;
+ XP_U16 saveFailPct;
const XP_UCHAR* playerDictNames[MAX_NUM_PLAYERS];
#ifdef USE_SQLITE
char* dbFileName;
From 5c683f173ab6a54df9b05a5f6f01fcc350fd6092 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 11 Sep 2012 19:06:27 -0700
Subject: [PATCH 08/44] add mem_stream_make_sized, meant to make saving games
more efficient
---
xwords4/common/memstream.c | 17 ++++++++++++++---
xwords4/common/memstream.h | 5 +++++
2 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/xwords4/common/memstream.c b/xwords4/common/memstream.c
index 095e52845..f3c627491 100644
--- a/xwords4/common/memstream.c
+++ b/xwords4/common/memstream.c
@@ -70,10 +70,8 @@ mem_stream_make( MPFORMAL VTableMgr* vtmgr, void* closure,
XP_PlayerAddr channelNo, MemStreamCloseCallback onClose )
{
StreamCtxVTable* vtable;
- MemStreamCtxt* result = (MemStreamCtxt*)XP_MALLOC( mpool,
+ MemStreamCtxt* result = (MemStreamCtxt*)XP_CALLOC( mpool,
sizeof(*result) );
- XP_MEMSET( result, 0, sizeof(*result) );
-
MPASSIGN(result->mpool, mpool);
vtable = (StreamCtxVTable*)vtmgr_getVTable( vtmgr, VTABLE_MEM_STREAM );
@@ -92,6 +90,19 @@ mem_stream_make( MPFORMAL VTableMgr* vtmgr, void* closure,
return (XWStreamCtxt*)result;
} /* make_mem_stream */
+XWStreamCtxt*
+mem_stream_make_sized( MPFORMAL VTableMgr* vtmgr, XP_U16 startSize,
+ void* closure, XP_PlayerAddr channelNo,
+ MemStreamCloseCallback onClose )
+{
+ MemStreamCtxt* result =
+ (MemStreamCtxt*)mem_stream_make( MPPARM(mpool) vtmgr, closure,
+ channelNo, onClose );
+ result->buf = (XP_U8*)XP_MALLOC( mpool, startSize );
+ result->nBytesAllocated = startSize;
+ return (XWStreamCtxt*)result;
+}
+
static void
mem_stream_getBytes( XWStreamCtxt* p_sctx, void* where, XP_U16 count )
{
diff --git a/xwords4/common/memstream.h b/xwords4/common/memstream.h
index ea9c1245a..5091088f2 100644
--- a/xwords4/common/memstream.h
+++ b/xwords4/common/memstream.h
@@ -38,6 +38,11 @@ XWStreamCtxt* mem_stream_make( MPFORMAL VTableMgr* vtmgr,
subclass */
MemStreamCloseCallback onCloseWritten );
+XWStreamCtxt* mem_stream_make_sized( MPFORMAL VTableMgr* vtmgr,
+ XP_U16 initialSize,
+ void* closure, XP_PlayerAddr addr,
+ MemStreamCloseCallback onCloseWritten );
+
#ifdef CPLUS
}
From 761f93dd7ea736039c674a1239206e9d1cc8b8ee Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 11 Sep 2012 19:07:00 -0700
Subject: [PATCH 09/44] use new mem_stream_make_sized
---
xwords4/linux/linuxmain.c | 9 +++++----
xwords4/linux/main.h | 1 +
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/xwords4/linux/linuxmain.c b/xwords4/linux/linuxmain.c
index 037b881a9..4ae698aa0 100644
--- a/xwords4/linux/linuxmain.c
+++ b/xwords4/linux/linuxmain.c
@@ -248,15 +248,16 @@ saveGame( CommonGlobals* cGlobals )
if ( doSave ) {
XWStreamCtxt* outStream;
- outStream = mem_stream_make( cGlobals->params->util->mpool,
- cGlobals->params->vtMgr,
- cGlobals, 0, writeToFile );
+ outStream = mem_stream_make_sized( cGlobals->params->util->mpool,
+ cGlobals->params->vtMgr,
+ cGlobals->lastStreamSize,
+ cGlobals, 0, writeToFile );
stream_open( outStream );
game_saveToStream( &cGlobals->game,
&cGlobals->params->gi,
outStream, ++cGlobals->curSaveToken );
-
+ cGlobals->lastStreamSize = stream_getSize( outStream );
stream_destroy( outStream );
game_saveSucceeded( &cGlobals->game, cGlobals->curSaveToken );
diff --git a/xwords4/linux/main.h b/xwords4/linux/main.h
index f8558b02f..06432cec0 100644
--- a/xwords4/linux/main.h
+++ b/xwords4/linux/main.h
@@ -163,6 +163,7 @@ struct CommonGlobals {
XWGame game;
XP_U16 lastNTilesToUse;
+ XP_U16 lastStreamSize;
SocketChangedFunc socketChanged;
void* socketChangedClosure;
From a0b564c7e8ec4a79fa84592a77c6e637fb6f41b1 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 11 Sep 2012 19:07:16 -0700
Subject: [PATCH 10/44] show related messages as well
---
xwords4/relay/scripts/showinplay.sh | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/xwords4/relay/scripts/showinplay.sh b/xwords4/relay/scripts/showinplay.sh
index 8da72c800..b570a4456 100755
--- a/xwords4/relay/scripts/showinplay.sh
+++ b/xwords4/relay/scripts/showinplay.sh
@@ -30,3 +30,8 @@ echo "SELECT dead,connname,cid,room,lang,clntVers,ntotal,nperdevice,seeds,ack,ns
"FROM games $QUERY ORDER BY NOT dead, connname LIMIT $LIMIT;" \
| psql xwgames
+echo "SELECT id, connname, hid, msglen "\
+ "FROM msgs where connname in (SELECT connname from games where not games.dead group by connname)" \
+ "order by connname, id;" \
+ | psql xwgames
+
From 4f18f01cb8bde84fec2c3e7dc3848d6829514923 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 11 Sep 2012 19:17:10 -0700
Subject: [PATCH 11/44] don't malloc(0)
---
xwords4/common/memstream.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/xwords4/common/memstream.c b/xwords4/common/memstream.c
index f3c627491..f255a3d9b 100644
--- a/xwords4/common/memstream.c
+++ b/xwords4/common/memstream.c
@@ -98,8 +98,10 @@ mem_stream_make_sized( MPFORMAL VTableMgr* vtmgr, XP_U16 startSize,
MemStreamCtxt* result =
(MemStreamCtxt*)mem_stream_make( MPPARM(mpool) vtmgr, closure,
channelNo, onClose );
- result->buf = (XP_U8*)XP_MALLOC( mpool, startSize );
- result->nBytesAllocated = startSize;
+ if ( 0 < startSize ) {
+ result->buf = (XP_U8*)XP_CALLOC( mpool, startSize );
+ result->nBytesAllocated = startSize;
+ }
return (XWStreamCtxt*)result;
}
From ae2b6205bd16f1e711ca012eedb83b261c4e138e Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 11 Sep 2012 19:17:27 -0700
Subject: [PATCH 12/44] use mem_stream_make_sized
---
xwords4/android/XWords4/jni/xwjni.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/xwords4/android/XWords4/jni/xwjni.c b/xwords4/android/XWords4/jni/xwjni.c
index 3447c3f57..d7d7998d3 100644
--- a/xwords4/android/XWords4/jni/xwjni.c
+++ b/xwords4/android/XWords4/jni/xwjni.c
@@ -185,9 +185,9 @@ loadCommonPrefs( JNIEnv* env, CommonPrefs* cp, jobject j_cp )
static XWStreamCtxt*
streamFromJStream( MPFORMAL JNIEnv* env, VTableMgr* vtMgr, jbyteArray jstream )
{
- XWStreamCtxt* stream = mem_stream_make( MPPARM(mpool) vtMgr,
- NULL, 0, NULL );
int len = (*env)->GetArrayLength( env, jstream );
+ XWStreamCtxt* stream = mem_stream_make_sized( MPPARM(mpool) vtMgr,
+ len, NULL, 0, NULL );
jbyte* jelems = (*env)->GetByteArrayElements( env, jstream, NULL );
stream_putBytes( stream, jelems, len );
(*env)->ReleaseByteArrayElements( env, jstream, jelems, 0 );
@@ -345,6 +345,7 @@ typedef struct _JNIState {
JNIEnv* env;
AndGlobals globals;
XP_U16 curSaveCount;
+ XP_U16 lastSavedSize;
#ifdef DEBUG
const char* envSetterFunc;
#endif
@@ -534,8 +535,9 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1saveToStream
ours should -- changes like remote players being added. */
CurGameInfo* gi =
(NULL == jgi) ? globals->gi : makeGI( MPPARM(mpool) env, jgi );
- XWStreamCtxt* stream = mem_stream_make( MPPARM(mpool) globals->vtMgr,
- NULL, 0, NULL );
+ XWStreamCtxt* stream = mem_stream_make_sized( MPPARM(mpool) globals->vtMgr,
+ state->lastSavedSize,
+ NULL, 0, NULL );
game_saveToStream( &state->game, gi, stream, ++state->curSaveCount );
@@ -549,6 +551,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1saveToStream
stream_getBytes( stream, jelems, nBytes );
(*env)->ReleaseByteArrayElements( env, result, jelems, 0 );
stream_destroy( stream );
+ state->lastSavedSize = nBytes;
XWJNI_END();
return result;
From 72b4b02c20018ed6772462335591d6595c9a1c71 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 11 Sep 2012 20:44:07 -0700
Subject: [PATCH 13/44] improve messages display
---
xwords4/relay/scripts/showinplay.sh | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/xwords4/relay/scripts/showinplay.sh b/xwords4/relay/scripts/showinplay.sh
index b570a4456..9085a54ec 100755
--- a/xwords4/relay/scripts/showinplay.sh
+++ b/xwords4/relay/scripts/showinplay.sh
@@ -30,8 +30,8 @@ echo "SELECT dead,connname,cid,room,lang,clntVers,ntotal,nperdevice,seeds,ack,ns
"FROM games $QUERY ORDER BY NOT dead, connname LIMIT $LIMIT;" \
| psql xwgames
-echo "SELECT id, connname, hid, msglen "\
+echo "SELECT connname, hid, count(*), sum(msglen) "\
"FROM msgs where connname in (SELECT connname from games where not games.dead group by connname)" \
- "order by connname, id;" \
+ "GROUP BY connname, hid ORDER BY connname;" \
| psql xwgames
From a6bed2706d989e72848227768331874211dca16b Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 11 Sep 2012 20:45:03 -0700
Subject: [PATCH 14/44] include, commented out, the parameter that makes things
fall apart. I think the protocol needs work to survive devices failing to
save state. Better to work on making sure they always save.
---
xwords4/linux/scripts/discon_ok2.sh | 1 +
1 file changed, 1 insertion(+)
diff --git a/xwords4/linux/scripts/discon_ok2.sh b/xwords4/linux/scripts/discon_ok2.sh
index 7489cf55b..f6ebeda33 100755
--- a/xwords4/linux/scripts/discon_ok2.sh
+++ b/xwords4/linux/scripts/discon_ok2.sh
@@ -185,6 +185,7 @@ build_cmds() {
PARAMS="$PARAMS --game-dict $DICT --port $PORT --host $HOST "
PARAMS="$PARAMS --file $FILE --slow-robot 1:3 --skip-confirm"
PARAMS="$PARAMS --drop-nth-packet $DROP_N $PLAT_PARMS"
+ # PARAMS="$PARAMS --savefail-pct 10"
[ -n "$SEED" ] && PARAMS="$PARAMS --seed $RANDOM"
PARAMS="$PARAMS $PUBLIC"
ARGS[$COUNTER]=$PARAMS
From ce6356fb92917e2479b479ce5739549cbcd30856 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Wed, 12 Sep 2012 07:44:58 -0700
Subject: [PATCH 15/44] add new db table for tracking dict-releated stuff. Use
it to save state in wordlist browser so can return to same place as left for
each dict. Eventually the new table should replace DictLangCache.
---
.../src/org/eehouse/android/xw4/DBHelper.java | 35 +++++-
.../src/org/eehouse/android/xw4/DBUtils.java | 87 +++++++++++++++
.../android/xw4/DictBrowseActivity.java | 103 +++++++++++++-----
3 files changed, 194 insertions(+), 31 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java
index a369f9a45..fcdbff254 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java
@@ -28,8 +28,9 @@ public class DBHelper extends SQLiteOpenHelper {
public static final String TABLE_NAME_SUM = "summaries";
public static final String TABLE_NAME_OBITS = "obits";
+ public static final String TABLE_NAME_DICTS = "dicts";
private static final String DB_NAME = "xwdb";
- private static final int DB_VERSION = 12;
+ private static final int DB_VERSION = 13;
public static final String GAME_NAME = "GAME_NAME";
public static final String NUM_MOVES = "NUM_MOVES";
@@ -60,6 +61,19 @@ public class DBHelper extends SQLiteOpenHelper {
public static final String RELAYID = "RELAYID";
public static final String SEED = "SEED";
public static final String SMSPHONE = "SMSPHONE";
+
+ public static final String DICTNAME = "DICTNAME";
+ public static final String MD5SUM = "MD5SUM";
+ public static final String WORDCOUNT = "WORDCOUNT";
+ public static final String WORDCOUNTS = "WORDCOUNTS";
+ public static final String LANGCODE = "LANGCODE";
+ public static final String LOC = "LOC";
+ public static final String ITERMIN = "ITERMIN";
+ public static final String ITERMAX = "ITERMAX";
+ public static final String ITERPOS = "ITERPOS";
+ public static final String ITERTOP = "ITERTOP";
+ public static final String ITERPREFIX = "ITERPREFIX";
+
// not used yet
public static final String CREATE_TIME = "CREATE_TIME";
// not used yet
@@ -122,11 +136,29 @@ public class DBHelper extends SQLiteOpenHelper {
+ ");" );
}
+ private void onCreateDictsDB( SQLiteDatabase db )
+ {
+ db.execSQL( "CREATE TABLE " + TABLE_NAME_DICTS + " ("
+ + DICTNAME + " TEXT,"
+ + MD5SUM + " TEXT(32),"
+ + WORDCOUNT + " INTEGER,"
+ + WORDCOUNTS + " TEXT,"
+ + LANGCODE + " INTEGER,"
+ + LOC + " INTEGER(2),"
+ + ITERMIN + " INTEGER(4),"
+ + ITERMAX + " INTEGER(4),"
+ + ITERPOS + " INTEGER,"
+ + ITERTOP + " INTEGER,"
+ + ITERPREFIX + " TEXT"
+ + ");" );
+ }
+
@Override
public void onCreate( SQLiteDatabase db )
{
onCreateSum( db );
onCreateObits( db );
+ onCreateDictsDB( db );
}
@Override
@@ -154,6 +186,7 @@ public class DBHelper extends SQLiteOpenHelper {
case 11:
addColumn( db, REMOTEDEVS, "TEXT" );
case 12:
+ onCreateDictsDB( db );
// nothing yet
break;
default:
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
index f12e70906..367f758f2 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
@@ -54,6 +54,7 @@ public class DBUtils {
private static final String ROW_ID = "rowid";
private static final String ROW_ID_FMT = "rowid=%d";
+ private static final String NAME_FMT = "%s='%s'";
private static long s_cachedRowID = -1;
private static byte[] s_cachedBytes = null;
@@ -84,6 +85,15 @@ public class DBUtils {
boolean sourceLocal;
}
+ public static class DictBrowseState {
+ public int m_minShown;
+ public int m_maxShown;
+ public int m_pos;
+ public int m_top;
+ public int[] m_counts;
+ public int m_count;
+ }
+
public static GameSummary getSummary( Context context, long rowid,
long maxMillis )
{
@@ -938,6 +948,83 @@ public class DBUtils {
return success;
}
+ /////////////////////////////////////////////////////////////////
+ // DictsDB stuff
+ /////////////////////////////////////////////////////////////////
+ public static DictBrowseState dictsGetOffset( Context context,
+ String name )
+ {
+ DictBrowseState result = null;
+ initDB( context );
+ synchronized( s_dbHelper ) {
+ SQLiteDatabase db = s_dbHelper.getReadableDatabase();
+ String[] columns = { DBHelper.ITERPOS, DBHelper.ITERTOP,
+ DBHelper.ITERMIN, DBHelper.ITERMAX,
+ DBHelper.WORDCOUNTS, DBHelper.WORDCOUNT };
+ String selection = String.format( NAME_FMT, DBHelper.DICTNAME, name );
+ Cursor cursor = db.query( DBHelper.TABLE_NAME_DICTS, columns,
+ selection, null, null, null, null );
+ if ( 1 == cursor.getCount() && cursor.moveToFirst() ) {
+ result = new DictBrowseState();
+ result.m_pos = cursor.getInt( cursor
+ .getColumnIndex(DBHelper.ITERPOS));
+ result.m_top = cursor.getInt( cursor
+ .getColumnIndex(DBHelper.ITERTOP));
+ result.m_minShown =
+ cursor.getInt( cursor
+ .getColumnIndex(DBHelper.ITERMIN));
+ result.m_maxShown =
+ cursor.getInt( cursor
+ .getColumnIndex(DBHelper.ITERMAX));
+ result.m_count =
+ cursor.getInt( cursor.getColumnIndex(DBHelper.WORDCOUNT));
+ String counts =
+ cursor.getString( cursor.getColumnIndex(DBHelper.WORDCOUNTS));
+ if ( null != counts ) {
+ String[] nums = TextUtils.split( counts, ":" );
+ int[] ints = new int[nums.length];
+ for ( int ii = 0; ii < nums.length; ++ii ) {
+ ints[ii] = Integer.parseInt( nums[ii] );
+ }
+ result.m_counts = ints;
+ }
+ }
+ cursor.close();
+ db.close();
+ }
+ return result;
+ }
+
+ public static void dictsSetOffset( Context context, String name,
+ DictBrowseState state )
+ {
+ initDB( context );
+ synchronized( s_dbHelper ) {
+ SQLiteDatabase db = s_dbHelper.getWritableDatabase();
+ String selection = String.format( NAME_FMT, DBHelper.DICTNAME, name );
+ ContentValues values = new ContentValues();
+ values.put( DBHelper.ITERPOS, state.m_pos );
+ values.put( DBHelper.ITERTOP, state.m_top );
+ values.put( DBHelper.ITERMIN, state.m_minShown );
+ values.put( DBHelper.ITERMAX, state.m_maxShown );
+ values.put( DBHelper.WORDCOUNT, state.m_count );
+ if ( null != state.m_counts ) {
+ String[] nums = new String[state.m_counts.length];
+ for ( int ii = 0; ii < nums.length; ++ii ) {
+ nums[ii] = String.format( "%d", state.m_counts[ii] );
+ }
+ values.put( DBHelper.WORDCOUNTS, TextUtils.join( ":", nums ) );
+ }
+ int result = db.update( DBHelper.TABLE_NAME_DICTS,
+ values, selection, null );
+ if ( 0 == result ) {
+ values.put( DBHelper.DICTNAME, name );
+ db.insert( DBHelper.TABLE_NAME_DICTS, null, values );
+ }
+ db.close();
+ }
+ }
+
private static void copyGameDB( Context context, boolean toSDCard )
{
String name = DBHelper.getDBName();
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java
index 98ba37e95..7f19aaece 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java
@@ -32,6 +32,7 @@ import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListAdapter;
+import android.widget.ListView;
import android.widget.SectionIndexer;
import android.widget.Spinner;
import android.widget.TextView;
@@ -48,9 +49,6 @@ public class DictBrowseActivity extends XWListActivity
implements View.OnClickListener, OnItemSelectedListener {
public static final String DICT_NAME = "DICT_NAME";
- public static final String DICT_MIN = "DICT_MIN";
- public static final String DICT_MAX = "DICT_MAX";
- public static final String DICT_COUNTS = "DICT_COUNTS";
private static final int MIN_LEN = 2;
private static final int FINISH_ACTION = 1;
@@ -60,11 +58,9 @@ public class DictBrowseActivity extends XWListActivity
private String m_name;
private Spinner m_minSpinner;
private Spinner m_maxSpinner;
- private int m_minShown;
- private int m_maxShown;
+ private DBUtils.DictBrowseState m_browseState;
private int m_minAvail;
private int m_maxAvail;
- private int[] m_counts;
// - Steps to reproduce the problem:
@@ -84,13 +80,15 @@ public class DictBrowseActivity extends XWListActivity
{
super();
- XwJNI.dict_iter_setMinMax( m_dictClosure, m_minShown, m_maxShown );
+ XwJNI.dict_iter_setMinMax( m_dictClosure, m_browseState.m_minShown,
+ m_browseState.m_maxShown );
m_nWords = XwJNI.dict_iter_wordCount( m_dictClosure );
- int format = m_minShown == m_maxShown ?
+ int format = m_browseState.m_minShown == m_browseState.m_maxShown ?
R.string.dict_browse_title1f : R.string.dict_browse_titlef;
setTitle( Utils.format( DictBrowseActivity.this, format,
- m_name, m_nWords, m_minShown, m_maxShown ));
+ m_name, m_nWords, m_browseState.m_minShown,
+ m_browseState.m_maxShown ));
String desc = XwJNI.dict_iter_getDesc( m_dictClosure );
if ( null != desc ) {
@@ -170,11 +168,21 @@ public class DictBrowseActivity extends XWListActivity
pairs.m_paths[0],
JNIUtilsImpl.get() );
- m_counts = intent.getIntArrayExtra( DICT_COUNTS );
- if ( null == m_counts ) {
- m_counts = XwJNI.dict_iter_getCounts( m_dictClosure );
+ m_browseState = DBUtils.dictsGetOffset( this, name );
+ boolean newState = null == m_browseState;
+ if ( newState ) {
+ m_browseState = new DBUtils.DictBrowseState();
+ m_browseState.m_pos = 0;
+ m_browseState.m_top = 0;
+ m_browseState.m_count =
+ XwJNI.dict_iter_wordCount( m_dictClosure );
}
- if ( null == m_counts ) {
+ if ( null == m_browseState.m_counts ) {
+ m_browseState.m_counts =
+ XwJNI.dict_iter_getCounts( m_dictClosure );
+ }
+
+ if ( null == m_browseState.m_counts ) {
// empty dict? Just close down for now. Later if
// this is extended to include tile info -- it should
// be -- then use an empty list elem and disable
@@ -183,7 +191,11 @@ public class DictBrowseActivity extends XWListActivity
name );
showOKOnlyDialogThen( msg, FINISH_ACTION );
} else {
- figureMinMax();
+ figureMinMax( m_browseState.m_counts );
+ if ( newState ) {
+ m_browseState.m_minShown = m_minAvail;
+ m_browseState.m_maxShown = m_maxAvail;
+ }
setContentView( R.layout.dict_browser );
@@ -195,14 +207,38 @@ public class DictBrowseActivity extends XWListActivity
}
} );
- m_minShown = intent.getIntExtra( DICT_MIN, m_minAvail );
- m_maxShown = intent.getIntExtra( DICT_MAX, m_maxAvail );
setUpSpinners();
setListAdapter( new DictListAdapter() );
getListView().setFastScrollEnabled( true );
+ getListView().setSelectionFromTop( m_browseState.m_pos,
+ m_browseState.m_top );
}
}
+ } // onCreate
+
+ @Override
+ protected void onPause()
+ {
+ if ( null != m_browseState ) { // already saved?
+ ListView list = getListView();
+ m_browseState.m_pos = list.getFirstVisiblePosition();
+ View view = list.getChildAt( 0 );
+ m_browseState.m_top = (view == null) ? 0 : view.getTop();
+ DBUtils.dictsSetOffset( this, m_name, m_browseState );
+ m_browseState = null;
+ }
+
+ super.onPause();
+ }
+
+ @Override
+ protected void onResume()
+ {
+ super.onResume();
+ if ( null == m_browseState ) {
+ m_browseState = DBUtils.dictsGetOffset( this, m_name );
+ }
}
@Override
@@ -247,9 +283,9 @@ public class DictBrowseActivity extends XWListActivity
TextView text = (TextView)view;
int newval = Integer.parseInt( text.getText().toString() );
if ( parent == m_minSpinner ) {
- setMinMax( newval, m_maxShown );
+ setMinMax( newval, m_browseState.m_maxShown );
} else if ( parent == m_maxSpinner ) {
- setMinMax( m_minShown, newval );
+ setMinMax( m_browseState.m_minShown, newval );
}
}
@@ -289,26 +325,31 @@ public class DictBrowseActivity extends XWListActivity
// adapter/making it recognized a changed dataset. So, as a
// workaround, relaunch the activity with different
// parameters.
- if ( m_minShown != min || m_maxShown != max ) {
- Intent intent = getIntent();
- intent.putExtra( DICT_MIN, min );
- intent.putExtra( DICT_MAX, max );
- intent.putExtra( DICT_COUNTS, m_counts );
- startActivity( intent );
+ if ( m_browseState.m_minShown != min ||
+ m_browseState.m_maxShown != max ) {
+
+ m_browseState.m_pos = 0;
+ m_browseState.m_top = 0;
+ m_browseState.m_minShown = min;
+ m_browseState.m_maxShown = max;
+ DBUtils.dictsSetOffset( this, m_name, m_browseState );
+ m_browseState = null;
+
+ startActivity( getIntent() );
finish();
}
}
- private void figureMinMax()
+ private void figureMinMax( int[] counts )
{
- Assert.assertTrue( m_counts.length == XwJNI.MAX_COLS_DICT + 1 );
+ Assert.assertTrue( counts.length == XwJNI.MAX_COLS_DICT + 1 );
m_minAvail = 0;
- while ( 0 == m_counts[m_minAvail] ) {
+ while ( 0 == counts[m_minAvail] ) {
++m_minAvail;
}
m_maxAvail = XwJNI.MAX_COLS_DICT;
- while ( 0 == m_counts[m_maxAvail] ) { //
+ while ( 0 == counts[m_maxAvail] ) { //
--m_maxAvail;
}
}
@@ -342,11 +383,13 @@ public class DictBrowseActivity extends XWListActivity
// current max the largest min allowed, and the current
// min the smallest max allowed.
m_minSpinner = (Spinner)findViewById( R.id.wordlen_min );
- makeAdapter( m_minSpinner, m_minAvail, m_maxShown, m_minShown );
+ makeAdapter( m_minSpinner, m_minAvail, m_browseState.m_maxShown,
+ m_browseState.m_minShown );
m_minSpinner.setOnItemSelectedListener( this );
m_maxSpinner = (Spinner)findViewById( R.id.wordlen_max );
- makeAdapter( m_maxSpinner, m_minShown, m_maxAvail, m_maxShown );
+ makeAdapter( m_maxSpinner, m_browseState.m_minShown,
+ m_maxAvail, m_browseState.m_maxShown );
m_maxSpinner.setOnItemSelectedListener( this );
}
From 67b0d44f2619c5d73b78541d1c9529e4393f5a9e Mon Sep 17 00:00:00 2001
From: Eric House
Date: Wed, 12 Sep 2012 07:55:41 -0700
Subject: [PATCH 16/44] save search prefix too
---
.../src/org/eehouse/android/xw4/DBUtils.java | 10 ++++++++--
.../eehouse/android/xw4/DictBrowseActivity.java | 15 +++++++++++++++
2 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
index 367f758f2..a23db96d8 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
@@ -90,8 +90,9 @@ public class DBUtils {
public int m_maxShown;
public int m_pos;
public int m_top;
- public int[] m_counts;
+ public String m_prefix;
public int m_count;
+ public int[] m_counts;
}
public static GameSummary getSummary( Context context, long rowid,
@@ -960,7 +961,8 @@ public class DBUtils {
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
String[] columns = { DBHelper.ITERPOS, DBHelper.ITERTOP,
DBHelper.ITERMIN, DBHelper.ITERMAX,
- DBHelper.WORDCOUNTS, DBHelper.WORDCOUNT };
+ DBHelper.WORDCOUNTS, DBHelper.WORDCOUNT,
+ DBHelper.ITERPREFIX };
String selection = String.format( NAME_FMT, DBHelper.DICTNAME, name );
Cursor cursor = db.query( DBHelper.TABLE_NAME_DICTS, columns,
selection, null, null, null, null );
@@ -976,6 +978,9 @@ public class DBUtils {
result.m_maxShown =
cursor.getInt( cursor
.getColumnIndex(DBHelper.ITERMAX));
+ result.m_prefix =
+ cursor.getString( cursor
+ .getColumnIndex(DBHelper.ITERPREFIX));
result.m_count =
cursor.getInt( cursor.getColumnIndex(DBHelper.WORDCOUNT));
String counts =
@@ -1007,6 +1012,7 @@ public class DBUtils {
values.put( DBHelper.ITERTOP, state.m_top );
values.put( DBHelper.ITERMIN, state.m_minShown );
values.put( DBHelper.ITERMAX, state.m_maxShown );
+ values.put( DBHelper.ITERPREFIX, state.m_prefix );
values.put( DBHelper.WORDCOUNT, state.m_count );
if ( null != state.m_counts ) {
String[] nums = new String[state.m_counts.length];
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java
index 7f19aaece..47b08a19e 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java
@@ -239,6 +239,7 @@ public class DictBrowseActivity extends XWListActivity
if ( null == m_browseState ) {
m_browseState = DBUtils.dictsGetOffset( this, m_name );
}
+ showPrefix( true );
}
@Override
@@ -308,6 +309,20 @@ public class DictBrowseActivity extends XWListActivity
EditText edit = (EditText)findViewById( R.id.word_edit );
String text = edit.getText().toString();
if ( null != text && 0 < text.length() ) {
+ m_browseState.m_prefix = text;
+ showPrefix( false );
+ }
+ }
+
+ private void showPrefix( boolean fillField )
+ {
+ String text = m_browseState.m_prefix;
+ if ( null != text && 0 < text.length() ) {
+ if ( fillField ) {
+ EditText edit = (EditText)findViewById( R.id.word_edit );
+ edit.setText( text );
+ }
+
int pos = XwJNI.dict_iter_getStartsWith( m_dictClosure, text );
if ( 0 <= pos ) {
getListView().setSelection( pos );
From 13507e6fc2e198f626762265502d3916afc6c9a0 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Wed, 12 Sep 2012 19:50:03 -0700
Subject: [PATCH 17/44] break dict info table in two, one browse state and one
for what's been stored in static data in DictLangCache up to now -- and
remove that static data in favor of the new table.
---
.../src/org/eehouse/android/xw4/DBHelper.java | 14 +++-
.../src/org/eehouse/android/xw4/DBUtils.java | 73 ++++++++++++++++++-
.../eehouse/android/xw4/DictLangCache.java | 30 ++------
3 files changed, 86 insertions(+), 31 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java
index fcdbff254..26e570c4d 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java
@@ -28,7 +28,8 @@ public class DBHelper extends SQLiteOpenHelper {
public static final String TABLE_NAME_SUM = "summaries";
public static final String TABLE_NAME_OBITS = "obits";
- public static final String TABLE_NAME_DICTS = "dicts";
+ public static final String TABLE_NAME_DICTBROWSE = "dictbrowse";
+ public static final String TABLE_NAME_DICTINFO = "dictinfo";
private static final String DB_NAME = "xwdb";
private static final int DB_VERSION = 13;
@@ -138,13 +139,18 @@ public class DBHelper extends SQLiteOpenHelper {
private void onCreateDictsDB( SQLiteDatabase db )
{
- db.execSQL( "CREATE TABLE " + TABLE_NAME_DICTS + " ("
+ db.execSQL( "CREATE TABLE " + TABLE_NAME_DICTINFO + " ("
+ DICTNAME + " TEXT,"
+ MD5SUM + " TEXT(32),"
+ WORDCOUNT + " INTEGER,"
- + WORDCOUNTS + " TEXT,"
+ LANGCODE + " INTEGER,"
- + LOC + " INTEGER(2),"
+ + LOC + " INTEGER(2)"
+ + ");" );
+
+ db.execSQL( "CREATE TABLE " + TABLE_NAME_DICTBROWSE + " ("
+ + DICTNAME + " TEXT,"
+ + WORDCOUNT + " INTEGER,"
+ + WORDCOUNTS + " TEXT,"
+ ITERMIN + " INTEGER(4),"
+ ITERMAX + " INTEGER(4),"
+ ITERPOS + " INTEGER,"
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
index a23db96d8..d732e94dc 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
@@ -964,7 +964,7 @@ public class DBUtils {
DBHelper.WORDCOUNTS, DBHelper.WORDCOUNT,
DBHelper.ITERPREFIX };
String selection = String.format( NAME_FMT, DBHelper.DICTNAME, name );
- Cursor cursor = db.query( DBHelper.TABLE_NAME_DICTS, columns,
+ Cursor cursor = db.query( DBHelper.TABLE_NAME_DICTBROWSE, columns,
selection, null, null, null, null );
if ( 1 == cursor.getCount() && cursor.moveToFirst() ) {
result = new DictBrowseState();
@@ -1021,16 +1021,83 @@ public class DBUtils {
}
values.put( DBHelper.WORDCOUNTS, TextUtils.join( ":", nums ) );
}
- int result = db.update( DBHelper.TABLE_NAME_DICTS,
+ int result = db.update( DBHelper.TABLE_NAME_DICTBROWSE,
values, selection, null );
if ( 0 == result ) {
values.put( DBHelper.DICTNAME, name );
- db.insert( DBHelper.TABLE_NAME_DICTS, null, values );
+ db.insert( DBHelper.TABLE_NAME_DICTBROWSE, null, values );
}
db.close();
}
}
+ public static DictInfo dictsGetInfo( Context context, String name )
+ {
+ DictInfo result = null;
+ initDB( context );
+ synchronized( s_dbHelper ) {
+ SQLiteDatabase db = s_dbHelper.getReadableDatabase();
+ String[] columns = { DBHelper.LANGCODE,
+ DBHelper.WORDCOUNT,
+ DBHelper.MD5SUM,
+ DBHelper.LOC };
+ String selection = String.format( NAME_FMT, DBHelper.DICTNAME, name );
+ Cursor cursor = db.query( DBHelper.TABLE_NAME_DICTINFO, columns,
+ selection, null, null, null, null );
+ if ( 1 == cursor.getCount() && cursor.moveToFirst() ) {
+ result = new DictInfo();
+ result.name = name;
+ result.langCode =
+ cursor.getInt( cursor.getColumnIndex(DBHelper.LANGCODE));
+ result.wordCount =
+ cursor.getInt( cursor.getColumnIndex(DBHelper.WORDCOUNT));
+ result.md5Sum =
+ cursor.getString( cursor.getColumnIndex(DBHelper.MD5SUM));
+ }
+ cursor.close();
+ db.close();
+ }
+ return result;
+ }
+
+ public static void dictsSetInfo( Context context, DictUtils.DictAndLoc dal,
+ DictInfo info )
+ {
+ initDB( context );
+ synchronized( s_dbHelper ) {
+ SQLiteDatabase db = s_dbHelper.getWritableDatabase();
+ String selection =
+ String.format( NAME_FMT, DBHelper.DICTNAME, dal.name );
+ ContentValues values = new ContentValues();
+
+ values.put( DBHelper.LANGCODE, info.langCode );
+ values.put( DBHelper.WORDCOUNT, info.wordCount );
+ values.put( DBHelper.MD5SUM, info.md5Sum );
+ values.put( DBHelper.LOC, dal.loc.ordinal() );
+
+ int result = db.update( DBHelper.TABLE_NAME_DICTINFO,
+ values, selection, null );
+ if ( 0 == result ) {
+ values.put( DBHelper.DICTNAME, dal.name );
+ db.insert( DBHelper.TABLE_NAME_DICTINFO, null, values );
+ }
+ db.close();
+ }
+ }
+
+ public static void dictsRemoveInfo( Context context,
+ DictUtils.DictAndLoc dal )
+ {
+ initDB( context );
+ synchronized( s_dbHelper ) {
+ SQLiteDatabase db = s_dbHelper.getWritableDatabase();
+ String selection =
+ String.format( NAME_FMT, DBHelper.DICTNAME, dal.name );
+ db.delete( DBHelper.TABLE_NAME_DICTINFO, selection, null );
+ db.close();
+ }
+ }
+
private static void copyGameDB( Context context, boolean toSDCard )
{
String name = DBHelper.getDBName();
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictLangCache.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictLangCache.java
index d07fa8b83..c6ecddf96 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictLangCache.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictLangCache.java
@@ -39,8 +39,6 @@ import org.eehouse.android.xw4.jni.DictInfo;
import org.eehouse.android.xw4.jni.CommonPrefs;
public class DictLangCache {
- private static final HashMap s_nameToLang =
- new HashMap();
private static String[] s_langNames;
private static int m_adaptedLang = -1;
@@ -230,7 +228,8 @@ public class DictLangCache {
DictUtils.DictLoc loc, boolean added )
{
DictAndLoc dal = new DictAndLoc( name, loc );
- s_nameToLang.remove( dal );
+ DBUtils.dictsRemoveInfo( context, dal );
+
if ( added ) {
getInfo( context, dal );
}
@@ -352,15 +351,7 @@ public class DictLangCache {
private static DictInfo getInfo( Context context, String name )
{
- DictInfo result = null;
- Set keys = s_nameToLang.keySet();
- for ( DictAndLoc key : keys ) {
- if ( key.name.equals(name) ) {
- result = s_nameToLang.get( key );
- break;
- }
- }
-
+ DictInfo result = DBUtils.dictsGetInfo( context, name );
if ( null == result ) {
DictUtils.DictLoc loc = DictUtils.getDictLoc( context, name );
result = getInfo( context, new DictAndLoc( name, loc ) );
@@ -370,28 +361,19 @@ public class DictLangCache {
private static DictInfo getInfo( Context context, DictAndLoc dal )
{
- DictInfo info;
- if ( s_nameToLang.containsKey( dal ) ) {
- info = s_nameToLang.get( dal );
- } else {
+ DictInfo info = DBUtils.dictsGetInfo( context, dal.name );
+ if ( null == info ) {
String[] names = { dal.name };
DictUtils.DictPairs pairs = DictUtils.openDicts( context, names );
info = new DictInfo();
-
- // It should not be possible for dict_getInfo to fail
- // unless DictUtils.dictList() isn't doing its job and
- // puts unchecked dicts on the list. Should probably
- // assert that this returns true. Open question: do I
- // always trust dicts in the BUILTIN and INTERNAL
- // locations? Files can get damaged....
if ( XwJNI.dict_getInfo( pairs.m_bytes[0], pairs.m_paths[0],
JNIUtilsImpl.get(),
DictUtils.DictLoc.DOWNLOAD == dal.loc,
info ) ) {
info.name = dal.name;
- s_nameToLang.put( dal, info );
+ DBUtils.dictsSetInfo( context, dal, info );
} else {
info = null;
DbgUtils.logf( "getInfo(): unable to open dict %s", dal.name );
From 3e4384c2a88a6be8647ce9e65053173bd9989583 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Thu, 13 Sep 2012 05:39:44 -0700
Subject: [PATCH 18/44] when dict doesn't have built-in md5sum, or when in
DEBUG code, call back into java to get a sum. It's very slow for large
dicts, but will eventually be in a DB so only done once per dict that doesn't
have it.
---
xwords4/android/XWords4/jni/anddict.c | 17 +++++++++++
xwords4/android/XWords4/jni/jniutlswrapper.c | 26 +++++++++++-----
xwords4/android/XWords4/jni/jniutlswrapper.h | 2 ++
.../org/eehouse/android/xw4/DictUtils.java | 13 +-------
.../src/org/eehouse/android/xw4/Utils.java | 17 +++++++++++
.../org/eehouse/android/xw4/jni/JNIUtils.java | 1 +
.../eehouse/android/xw4/jni/JNIUtilsImpl.java | 30 +++++++++++++++++--
7 files changed, 83 insertions(+), 23 deletions(-)
diff --git a/xwords4/android/XWords4/jni/anddict.c b/xwords4/android/XWords4/jni/anddict.c
index 4bddb2990..1c86f7018 100644
--- a/xwords4/android/XWords4/jni/anddict.c
+++ b/xwords4/android/XWords4/jni/anddict.c
@@ -340,6 +340,23 @@ parseDict( AndDictionaryCtxt* ctxt, XP_U8 const* ptr, XP_U32 dictLength,
goto error;
}
+ if ( NULL == ctxt->super.md5Sum
+#ifdef DEBUG
+ || XP_TRUE
+#endif
+ ) {
+ JNIEnv* env = ctxt->env;
+ jstring jsum = and_util_figureMD5Sum( ctxt->jniutil, ptr, end - ptr );
+ XP_UCHAR* md5Sum = getStringCopy( MPPARM(ctxt->super.mpool) env, jsum );
+ (*env)->DeleteLocalRef( env, jsum );
+ if ( NULL == ctxt->super.md5Sum ) {
+ ctxt->super.md5Sum = md5Sum;
+ } else {
+ XP_ASSERT( 0 == XP_STRCMP( ctxt->super.md5Sum, md5Sum ) );
+ XP_FREE( ctxt->super.mpool, md5Sum );
+ }
+ }
+
ctxt->super.nodeSize = nodeSize;
if ( !isUTF8 ) {
diff --git a/xwords4/android/XWords4/jni/jniutlswrapper.c b/xwords4/android/XWords4/jni/jniutlswrapper.c
index 94b52265c..e5d5b5d91 100644
--- a/xwords4/android/XWords4/jni/jniutlswrapper.c
+++ b/xwords4/android/XWords4/jni/jniutlswrapper.c
@@ -84,14 +84,24 @@ and_util_splitFaces( JNIUtilCtxt* jniutil, const XP_U8* bytes, jsize len,
= getMethodID( env, jniutil->jjniutil, "splitFaces",
"([BZ)[Ljava/lang/String;" );
- jbyteArray jbytes = (*env)->NewByteArray( env, len );
-
- jbyte* jp = (*env)->GetByteArrayElements( env, jbytes, NULL );
- XP_MEMCPY( jp, bytes, len );
- (*env)->ReleaseByteArrayElements( env, jbytes, jp, 0 );
-
- strarray = (*env)->CallObjectMethod( env, jniutil->jjniutil, mid, jbytes,
- isUTF8 );
+ jbyteArray jbytes = makeByteArray( env, len, (jbyte*)bytes );
+ strarray =
+ (*env)->CallObjectMethod( env, jniutil->jjniutil, mid, jbytes, isUTF8 );
(*env)->DeleteLocalRef( env, jbytes );
+
return strarray;
}
+
+jstring
+and_util_figureMD5Sum( JNIUtilCtxt* jniutil, const XP_U8* bytes, jsize len )
+{
+ JNIEnv* env = *jniutil->envp;
+ jmethodID mid = getMethodID( env, jniutil->jjniutil, "figureMD5Sum",
+ "([B)Ljava/lang/String;" );
+ jbyteArray jbytes = makeByteArray( env, len, (jbyte*)bytes );
+ jstring sum =
+ (*env)->CallObjectMethod( env, jniutil->jjniutil, mid, jbytes );
+ (*env)->DeleteLocalRef( env, jbytes );
+
+ return sum;
+}
diff --git a/xwords4/android/XWords4/jni/jniutlswrapper.h b/xwords4/android/XWords4/jni/jniutlswrapper.h
index 4e0dfea9a..0cc6c53dc 100644
--- a/xwords4/android/XWords4/jni/jniutlswrapper.h
+++ b/xwords4/android/XWords4/jni/jniutlswrapper.h
@@ -35,5 +35,7 @@ jobject and_util_makeJBitmap( JNIUtilCtxt* jniu, int nCols, int nRows,
const jboolean* colors );
jobject and_util_splitFaces( JNIUtilCtxt* jniu, const XP_U8* bytes, int len,
XP_Bool isUTF8 );
+jstring and_util_figureMD5Sum( JNIUtilCtxt* jniutil, const XP_U8* bytes,
+ jsize len );
#endif
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java
index 2f19e2ff2..d37f13083 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java
@@ -555,18 +555,7 @@ public class DictUtils {
DbgUtils.loge( ioe );
}
- if ( null != digest ) {
- final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9',
- 'a','b','c','d','e','f'};
- char[] chars = new char[digest.length * 2];
- for ( int ii = 0; ii < digest.length; ii++ ) {
- int byt = digest[ii] & 0xFF;
- chars[ii * 2] = hexArray[byt >> 4];
- chars[ii * 2 + 1] = hexArray[byt & 0x0F];
- }
- result = new String(chars);
- }
- return result;
+ return Utils.digestToString( digest );
} // figureMD5Sum
public static String getMD5SumFor( Context context, DictAndLoc dandl )
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java
index 5c08356ae..8715901de 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/Utils.java
@@ -345,6 +345,23 @@ public class Utils {
return context.getString( id, args );
}
+ public static String digestToString( byte[] digest )
+ {
+ String result = null;
+ if ( null != digest ) {
+ final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9',
+ 'a','b','c','d','e','f'};
+ char[] chars = new char[digest.length * 2];
+ for ( int ii = 0; ii < digest.length; ii++ ) {
+ int byt = digest[ii] & 0xFF;
+ chars[ii * 2] = hexArray[byt >> 4];
+ chars[ii * 2 + 1] = hexArray[byt & 0x0F];
+ }
+ result = new String(chars);
+ }
+ return result;
+ }
+
private static void setFirstBootStatics( Context context )
{
int thisVersion = 0;
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtils.java
index 03bbe39cb..ce9dff290 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtils.java
@@ -26,4 +26,5 @@ public interface JNIUtils {
// Stuff I can't do in C....
String[] splitFaces( byte[] chars, boolean isUTF8 );
+ String figureMD5Sum( byte[] bytes );
}
\ No newline at end of file
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java
index c64c391b1..fc450e1ab 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java
@@ -20,11 +20,12 @@
package org.eehouse.android.xw4.jni;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.Bitmap;
-import java.util.ArrayList;
+import android.graphics.drawable.BitmapDrawable;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
+import java.security.MessageDigest;
+import java.util.ArrayList;
import org.eehouse.android.xw4.*;
@@ -86,4 +87,27 @@ public class JNIUtilsImpl implements JNIUtils {
String[] result = al.toArray( new String[al.size()] );
return result;
}
-}
\ No newline at end of file
+
+ public String figureMD5Sum( byte[] bytes )
+ {
+ byte[] digest = null;
+ try {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ byte[] buf = new byte[128];
+ int nLeft = bytes.length;
+ int offset = 0;
+ while ( 0 < nLeft ) {
+ int len = Math.min( buf.length, nLeft );
+ System.arraycopy( bytes, offset, buf, 0, len );
+ md.update( buf, 0, len );
+ nLeft -= len;
+ offset += len;
+ }
+ digest = md.digest();
+ } catch ( java.security.NoSuchAlgorithmException nsae ) {
+ DbgUtils.loge( nsae );
+ }
+
+ return Utils.digestToString( digest );
+ }
+}
From aa974be5675a58783a8c2560c1db14c186cd808f Mon Sep 17 00:00:00 2001
From: Eric House
Date: Thu, 13 Sep 2012 07:38:08 -0700
Subject: [PATCH 19/44] Before figuring md5sum (via java callback added
recently), use new callback to see if there's already one in the DB.
Required passing context into jniutils getter, and passing name into jni dict
constructors that previously didn't need it.
---
xwords4/android/XWords4/jni/anddict.c | 5 +++-
xwords4/android/XWords4/jni/jniutlswrapper.c | 13 +++++++++
xwords4/android/XWords4/jni/jniutlswrapper.h | 1 +
xwords4/android/XWords4/jni/xwjni.c | 9 ++++---
.../eehouse/android/xw4/BoardActivity.java | 2 +-
.../src/org/eehouse/android/xw4/DBUtils.java | 27 +++++++++++++++++++
.../android/xw4/DictBrowseActivity.java | 6 ++---
.../eehouse/android/xw4/DictLangCache.java | 5 ++--
.../org/eehouse/android/xw4/DictUtils.java | 20 +++++++-------
.../org/eehouse/android/xw4/GameUtils.java | 13 ++++-----
.../org/eehouse/android/xw4/jni/JNIUtils.java | 1 +
.../eehouse/android/xw4/jni/JNIUtilsImpl.java | 12 +++++++--
.../org/eehouse/android/xw4/jni/XwJNI.java | 10 +++----
13 files changed, 90 insertions(+), 34 deletions(-)
diff --git a/xwords4/android/XWords4/jni/anddict.c b/xwords4/android/XWords4/jni/anddict.c
index 1c86f7018..70cfd6649 100644
--- a/xwords4/android/XWords4/jni/anddict.c
+++ b/xwords4/android/XWords4/jni/anddict.c
@@ -346,7 +346,10 @@ parseDict( AndDictionaryCtxt* ctxt, XP_U8 const* ptr, XP_U32 dictLength,
#endif
) {
JNIEnv* env = ctxt->env;
- jstring jsum = and_util_figureMD5Sum( ctxt->jniutil, ptr, end - ptr );
+ jstring jsum = and_util_getMD5SumFor( ctxt->jniutil, ctxt->super.name );
+ if ( NULL == jsum ) {
+ jsum = and_util_figureMD5Sum( ctxt->jniutil, ptr, end - ptr );
+ }
XP_UCHAR* md5Sum = getStringCopy( MPPARM(ctxt->super.mpool) env, jsum );
(*env)->DeleteLocalRef( env, jsum );
if ( NULL == ctxt->super.md5Sum ) {
diff --git a/xwords4/android/XWords4/jni/jniutlswrapper.c b/xwords4/android/XWords4/jni/jniutlswrapper.c
index e5d5b5d91..70bfc5e45 100644
--- a/xwords4/android/XWords4/jni/jniutlswrapper.c
+++ b/xwords4/android/XWords4/jni/jniutlswrapper.c
@@ -92,6 +92,19 @@ and_util_splitFaces( JNIUtilCtxt* jniutil, const XP_U8* bytes, jsize len,
return strarray;
}
+jstring
+and_util_getMD5SumFor( JNIUtilCtxt* jniutil, const XP_UCHAR* name )
+{
+ JNIEnv* env = *jniutil->envp;
+ jmethodID mid = getMethodID( env, jniutil->jjniutil, "getMD5SumFor",
+ "(Ljava/lang/String;)Ljava/lang/String;" );
+ jstring jname = (*env)->NewStringUTF( env, name );
+ jstring result =
+ (*env)->CallObjectMethod( env, jniutil->jjniutil, mid, jname );
+ (*env)->DeleteLocalRef( env, jname );
+ return result;
+}
+
jstring
and_util_figureMD5Sum( JNIUtilCtxt* jniutil, const XP_U8* bytes, jsize len )
{
diff --git a/xwords4/android/XWords4/jni/jniutlswrapper.h b/xwords4/android/XWords4/jni/jniutlswrapper.h
index 0cc6c53dc..389c1462d 100644
--- a/xwords4/android/XWords4/jni/jniutlswrapper.h
+++ b/xwords4/android/XWords4/jni/jniutlswrapper.h
@@ -35,6 +35,7 @@ jobject and_util_makeJBitmap( JNIUtilCtxt* jniu, int nCols, int nRows,
const jboolean* colors );
jobject and_util_splitFaces( JNIUtilCtxt* jniu, const XP_U8* bytes, int len,
XP_Bool isUTF8 );
+jstring and_util_getMD5SumFor( JNIUtilCtxt* jniutil, const XP_UCHAR* name );
jstring and_util_figureMD5Sum( JNIUtilCtxt* jniutil, const XP_U8* bytes,
jsize len );
diff --git a/xwords4/android/XWords4/jni/xwjni.c b/xwords4/android/XWords4/jni/xwjni.c
index d7d7998d3..0433e41b1 100644
--- a/xwords4/android/XWords4/jni/xwjni.c
+++ b/xwords4/android/XWords4/jni/xwjni.c
@@ -285,7 +285,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_comms_1getUUID
JNIEXPORT jboolean JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getInfo
-( JNIEnv* env, jclass C, jbyteArray jDictBytes, jstring jpath,
+( JNIEnv* env, jclass C, jbyteArray jDictBytes, jstring jname, jstring jpath,
jobject jniu, jboolean check, jobject jinfo )
{
jboolean result = false;
@@ -293,7 +293,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1getInfo
MemPoolCtx* mpool = mpool_make();
#endif
JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(mpool) &env, jniu );
- DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, jniutil, NULL,
+ DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, jniutil, jname,
jDictBytes, jpath, NULL, check );
if ( NULL != dict ) {
if ( NULL != jinfo ) {
@@ -1382,7 +1382,8 @@ typedef struct _DictIterData {
JNIEXPORT jint JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1init
-(JNIEnv* env, jclass C, jbyteArray jDictBytes, jstring jpath, jobject jniu )
+( JNIEnv* env, jclass C, jbyteArray jDictBytes, jstring jname,
+ jstring jpath, jobject jniu )
{
jint closure = 0;
#ifdef MEM_DEBUG
@@ -1391,7 +1392,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1init
DictIterData* data = XP_CALLOC( mpool, sizeof(*data) );
data->env = env;
JNIUtilCtxt* jniutil = makeJNIUtil( MPPARM(mpool) &data->env, jniu );
- DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, jniutil, NULL,
+ DictionaryCtxt* dict = makeDict( MPPARM(mpool) env, jniutil, jname,
jDictBytes, jpath, NULL, false );
if ( !!dict ) {
data->vtMgr = make_vtablemgr( MPPARM_NOCOMMA(mpool) );
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
index e9d14ce29..d5ce62292 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java
@@ -448,7 +448,7 @@ public class BoardActivity extends XWActivity
}
m_utils = new BoardUtilCtxt();
- m_jniu = JNIUtilsImpl.get();
+ m_jniu = JNIUtilsImpl.get( this );
setContentView( R.layout.board );
m_timers = new TimerRunnable[4]; // needs to be in sync with
// XWTimerReason
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
index d732e94dc..52a024977 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
@@ -1031,6 +1031,31 @@ public class DBUtils {
}
}
+ public static String dictsGetMD5Sum( Context context, String name )
+ {
+ DictInfo info = dictsGetInfo( context, name );
+ String result = null == info? null : info.md5Sum;
+ return result;
+ }
+
+ public static void dictsSetMD5Sum( Context context, String name, String sum )
+ {
+ initDB( context );
+ synchronized( s_dbHelper ) {
+ SQLiteDatabase db = s_dbHelper.getWritableDatabase();
+ String selection = String.format( NAME_FMT, DBHelper.DICTNAME, name );
+ ContentValues values = new ContentValues();
+ values.put( DBHelper.MD5SUM, sum );
+ int result = db.update( DBHelper.TABLE_NAME_DICTINFO,
+ values, selection, null );
+ if ( 0 == result ) {
+ values.put( DBHelper.DICTNAME, name );
+ db.insert( DBHelper.TABLE_NAME_DICTINFO, null, values );
+ }
+ db.close();
+ }
+ }
+
public static DictInfo dictsGetInfo( Context context, String name )
{
DictInfo result = null;
@@ -1147,6 +1172,8 @@ public class DBUtils {
{
if ( null == s_dbHelper ) {
s_dbHelper = new DBHelper( context );
+ // force any upgrade
+ s_dbHelper.getWritableDatabase().close();
}
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java
index 47b08a19e..116283703 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java
@@ -164,9 +164,9 @@ public class DictBrowseActivity extends XWListActivity
String[] names = { name };
DictUtils.DictPairs pairs = DictUtils.openDicts( this, names );
- m_dictClosure = XwJNI.dict_iter_init( pairs.m_bytes[0],
- pairs.m_paths[0],
- JNIUtilsImpl.get() );
+ m_dictClosure = XwJNI.dict_iter_init( pairs.m_bytes[0],
+ name, pairs.m_paths[0],
+ JNIUtilsImpl.get(this) );
m_browseState = DBUtils.dictsGetOffset( this, name );
boolean newState = null == m_browseState;
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictLangCache.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictLangCache.java
index c6ecddf96..6bdca3580 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictLangCache.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictLangCache.java
@@ -367,8 +367,9 @@ public class DictLangCache {
DictUtils.DictPairs pairs = DictUtils.openDicts( context, names );
info = new DictInfo();
- if ( XwJNI.dict_getInfo( pairs.m_bytes[0], pairs.m_paths[0],
- JNIUtilsImpl.get(),
+ if ( XwJNI.dict_getInfo( pairs.m_bytes[0], dal.name,
+ pairs.m_paths[0],
+ JNIUtilsImpl.get( context ),
DictUtils.DictLoc.DOWNLOAD == dal.loc,
info ) ) {
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java
index d37f13083..02a519bdc 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java
@@ -114,14 +114,14 @@ public class DictUtils {
// changes?
}
- private static void tryDir( File dir, boolean strict, DictLoc loc,
- ArrayList al )
+ private static void tryDir( Context context, File dir, boolean strict,
+ DictLoc loc, ArrayList al )
{
if ( null != dir ) {
String[] list = dir.list();
if ( null != list ) {
for ( String file : list ) {
- if ( isDict( file, strict? dir : null ) ) {
+ if ( isDict( context, file, strict? dir : null ) ) {
al.add( new DictAndLoc( removeDictExtn( file ), loc ) );
}
}
@@ -135,21 +135,21 @@ public class DictUtils {
ArrayList al = new ArrayList();
for ( String file : getAssets( context ) ) {
- if ( isDict( file, null ) ) {
+ if ( isDict( context, file, null ) ) {
al.add( new DictAndLoc( removeDictExtn( file ),
DictLoc.BUILT_IN ) );
}
}
for ( String file : context.fileList() ) {
- if ( isDict( file, null ) ) {
+ if ( isDict( context, file, null ) ) {
al.add( new DictAndLoc( removeDictExtn( file ),
DictLoc.INTERNAL ) );
}
}
- tryDir( getSDDir( context ), false, DictLoc.EXTERNAL, al );
- tryDir( getDownloadDir(), true, DictLoc.DOWNLOAD, al );
+ tryDir( context, getSDDir( context ), false, DictLoc.EXTERNAL, al );
+ tryDir( context, getDownloadDir(), true, DictLoc.DOWNLOAD, al );
s_dictListCache =
al.toArray( new DictUtils.DictAndLoc[al.size()] );
@@ -480,13 +480,13 @@ public class DictUtils {
return file.endsWith( XWConstants.GAME_EXTN );
}
- private static boolean isDict( String file, File dir )
+ private static boolean isDict( Context context, String file, File dir )
{
boolean ok = file.endsWith( XWConstants.DICT_EXTN );
if ( ok && null != dir ) {
String fullPath = new File( dir, file ).getPath();
- ok = XwJNI.dict_getInfo( null, fullPath, JNIUtilsImpl.get(),
- true, null );
+ ok = XwJNI.dict_getInfo( null, removeDictExtn( file ), fullPath,
+ JNIUtilsImpl.get(context), true, null );
}
return ok;
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
index 4c3f99231..25ac8f8bb 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
@@ -220,7 +220,7 @@ public class GameUtils {
XwJNI.game_dispose( gamePtr );
gamePtr = XwJNI.initJNI();
- XwJNI.game_makeNewGame( gamePtr, gi, JNIUtilsImpl.get(),
+ XwJNI.game_makeNewGame( gamePtr, gi, JNIUtilsImpl.get( context ),
CommonPrefs.get( context ), dictNames,
pairs.m_bytes, pairs.m_paths, gi.langName() );
@@ -360,11 +360,11 @@ public class GameUtils {
XwJNI.game_makeFromStream( gamePtr, stream, gi,
dictNames, pairs.m_bytes,
pairs.m_paths, langName,
- util, JNIUtilsImpl.get(),
+ util, JNIUtilsImpl.get( context ),
CommonPrefs.get(context),
tp);
if ( !madeGame ) {
- XwJNI.game_makeNewGame( gamePtr, gi, JNIUtilsImpl.get(),
+ XwJNI.game_makeNewGame( gamePtr, gi, JNIUtilsImpl.get(context),
CommonPrefs.get(context), dictNames,
pairs.m_bytes, pairs.m_paths,
langName );
@@ -773,7 +773,7 @@ public class GameUtils {
int gamePtr = XwJNI.initJNI();
XwJNI.game_makeFromStream( gamePtr, stream, gi, dictNames,
pairs.m_bytes, pairs.m_paths,
- gi.langName(), JNIUtilsImpl.get(),
+ gi.langName(), JNIUtilsImpl.get(context),
CommonPrefs.get( context ) );
// second time required as game_makeFromStream can overwrite
gi.replaceDicts( newDict );
@@ -816,11 +816,12 @@ public class GameUtils {
new CurGameInfo(context),
dictNames, pairs.m_bytes,
pairs.m_paths, langName,
- JNIUtilsImpl.get(), cp );
+ JNIUtilsImpl.get(context),
+ cp );
}
if ( forceNew || !madeGame ) {
- XwJNI.game_makeNewGame( gamePtr, gi, JNIUtilsImpl.get(),
+ XwJNI.game_makeNewGame( gamePtr, gi, JNIUtilsImpl.get(context),
cp, dictNames, pairs.m_bytes,
pairs.m_paths, langName );
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtils.java
index ce9dff290..d1fff71a6 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtils.java
@@ -26,5 +26,6 @@ public interface JNIUtils {
// Stuff I can't do in C....
String[] splitFaces( byte[] chars, boolean isUTF8 );
+ String getMD5SumFor( String dictName );
String figureMD5Sum( byte[] bytes );
}
\ No newline at end of file
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java
index fc450e1ab..27b832446 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java
@@ -20,6 +20,7 @@
package org.eehouse.android.xw4.jni;
+import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import java.io.ByteArrayInputStream;
@@ -31,15 +32,17 @@ import org.eehouse.android.xw4.*;
public class JNIUtilsImpl implements JNIUtils {
- private static JNIUtils s_impl = null;
+ private static JNIUtilsImpl s_impl = null;
+ private Context m_context;
private JNIUtilsImpl(){}
- public static JNIUtils get()
+ public static JNIUtils get( Context context )
{
if ( null == s_impl ) {
s_impl = new JNIUtilsImpl();
}
+ s_impl.m_context = context;
return s_impl;
}
@@ -88,6 +91,11 @@ public class JNIUtilsImpl implements JNIUtils {
return result;
}
+ public String getMD5SumFor( String dictName )
+ {
+ return DBUtils.dictsGetMD5Sum( m_context, dictName );
+ }
+
public String figureMD5Sum( byte[] bytes )
{
byte[] digest = null;
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/XwJNI.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/XwJNI.java
index 52795f0b1..e13d9df23 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/XwJNI.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/XwJNI.java
@@ -239,15 +239,15 @@ public class XwJNI {
// Dicts
public static native boolean dict_tilesAreSame( int dictPtr1, int dictPtr2 );
public static native String[] dict_getChars( int dictPtr );
- public static native boolean dict_getInfo( byte[] dict, String path,
- JNIUtils jniu, boolean check,
- DictInfo info );
+ public static native boolean dict_getInfo( byte[] dict, String name,
+ String path, JNIUtils jniu,
+ boolean check, DictInfo info );
public static native int dict_getTileValue( int dictPtr, int tile );
// Dict iterator
public final static int MAX_COLS_DICT = 15; // from dictiter.h
- public static native int dict_iter_init( byte[] dict, String path,
- JNIUtils jniu );
+ public static native int dict_iter_init( byte[] dict, String name,
+ String path, JNIUtils jniu );
public static native void dict_iter_setMinMax( int closure,
int min, int max );
public static native void dict_iter_destroy( int closure );
From 50e90405a777272a33fda554487790990d1e5574 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Thu, 13 Sep 2012 08:00:37 -0700
Subject: [PATCH 20/44] add new Catalan word lookup URL
---
xwords4/android/XWords4/res/values/common_rsrc.xml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/xwords4/android/XWords4/res/values/common_rsrc.xml b/xwords4/android/XWords4/res/values/common_rsrc.xml
index 5e4d424ee..aea01b1d5 100644
--- a/xwords4/android/XWords4/res/values/common_rsrc.xml
+++ b/xwords4/android/XWords4/res/values/common_rsrc.xml
@@ -241,6 +241,10 @@
- :ca:
- http://ca.wiktionary.org/w/index.php?search=%2$s
+ - DISC lookup
+ - :ca:
+ - http://escrable.montane.cat/diccionari/cercador/?mot=%2$s
+
- Google
- http://www.google.com/search?nl=%1$s\u0026q=%2$s
From a85ab865cb0c3112b81ded87adcae42ab92e43a7 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Thu, 13 Sep 2012 19:05:09 -0700
Subject: [PATCH 21/44] up note for new version of DISC
---
xwords4/dawg/Catalan/Makefile.DISC2 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xwords4/dawg/Catalan/Makefile.DISC2 b/xwords4/dawg/Catalan/Makefile.DISC2
index 28bf19bca..0fd8df01b 100644
--- a/xwords4/dawg/Catalan/Makefile.DISC2
+++ b/xwords4/dawg/Catalan/Makefile.DISC2
@@ -20,7 +20,7 @@ LANGCODE=ca_ES
TARGET_TYPE ?= WINCE
ENC = UTF-8
-DICTNOTE = "Built from DISC 2.0.5.\nSee http://escrable.montane.cat/diccionari for more information."
+DICTNOTE = "Built from DISC 2.0.6.\nSee http://escrable.montane.cat/diccionari for more information."
ifeq ($(TARGET_TYPE),PALM)
From 20afa9fd56e3b1b0eb8955967366f9d11807186c Mon Sep 17 00:00:00 2001
From: Eric House
Date: Thu, 13 Sep 2012 19:06:46 -0700
Subject: [PATCH 22/44] rename: file's obsolete now
---
xwords4/dawg/Catalan/{Makefile => Makefile.DANOSC} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename xwords4/dawg/Catalan/{Makefile => Makefile.DANOSC} (100%)
diff --git a/xwords4/dawg/Catalan/Makefile b/xwords4/dawg/Catalan/Makefile.DANOSC
similarity index 100%
rename from xwords4/dawg/Catalan/Makefile
rename to xwords4/dawg/Catalan/Makefile.DANOSC
From aaa12a291e87caf7d42dc275cef89d8867610a0b Mon Sep 17 00:00:00 2001
From: Eric House
Date: Thu, 13 Sep 2012 19:07:37 -0700
Subject: [PATCH 23/44] use unpack to correctly pull wordcount, note and
checksum
---
xwords4/dawg/dawg2dict.pl | 14 +++-----------
1 file changed, 3 insertions(+), 11 deletions(-)
diff --git a/xwords4/dawg/dawg2dict.pl b/xwords4/dawg/dawg2dict.pl
index 629131270..e09d3a1ff 100755
--- a/xwords4/dawg/dawg2dict.pl
+++ b/xwords4/dawg/dawg2dict.pl
@@ -169,17 +169,9 @@ sub readNodesToEnd($) {
sub printHeader($$) {
my ( $buf, $len ) = @_;
printf STDERR "skipped %d bytes of header:\n", $len + 2;
- my $asStr = Encode::decode_utf8($buf);
- my @strs = split( '\0', $asStr );
- # There are variable numbers of strings showing up in this thing.
- # Need to figure out the right way to unpack the thing.
- $gDesc = $strs[1];
- $gSum = $strs[2];
- foreach my $str (@strs) {
- if ( 0 < length($str) ) {
- print STDERR 'Got: ', $str, "\n";
- }
- }
+ my $count;
+ ($count, $gDesc, $gSum) = unpack( 'N Z* Z*', $buf );
+ printf STDERR "has %d words\n", $count;
}
sub nodeSizeFromFlags($$) {
From bcc8c0c249591a81407499fea46b35d1c9b2bde2 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Thu, 13 Sep 2012 19:33:17 -0700
Subject: [PATCH 24/44] remove code figuring md5sum on full dict file; the sum
on data is all we're using now.
---
.../org/eehouse/android/xw4/DictUtils.java | 43 -------------------
.../android/xw4/UpdateCheckReceiver.java | 2 +-
2 files changed, 1 insertion(+), 44 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java
index 02a519bdc..1a3f5767e 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java
@@ -527,49 +527,6 @@ public class DictUtils {
// want this later? Environment.MEDIA_MOUNTED_READ_ONLY
}
- private static String figureMD5Sum( Context context, DictAndLoc dandl )
- {
- byte[] digest = null;
- String result = null;
- String name = dandl.name;
- File path = getDictFile( context, addDictExtn( name ), dandl.loc );
- try {
- InputStream fis = new FileInputStream( path );
- byte[] buffer = new byte[1024];
- MessageDigest md = MessageDigest.getInstance("MD5");
- for ( ; ; ) {
- int nRead = fis.read( buffer );
- if ( 0 > nRead ) {
- break;
- }
- md.update( buffer, 0, nRead );
- }
- fis.close();
-
- digest = md.digest();
- } catch ( java.io.FileNotFoundException fnfe ) {
- DbgUtils.loge( fnfe );
- } catch( java.security.NoSuchAlgorithmException nsae ) {
- DbgUtils.loge( nsae );
- } catch( java.io.IOException ioe ) {
- DbgUtils.loge( ioe );
- }
-
- return Utils.digestToString( digest );
- } // figureMD5Sum
-
- public static String getMD5SumFor( Context context, DictAndLoc dandl )
- {
- String sum = null; // DBUtils.getDictMD5Sum( context, dandl.name,
- // dandl.loc.ordinal() );
- if ( null == sum ) {
- sum = figureMD5Sum( context, dandl );
- // DBUtils.setDictMD5Sum( context, dandl.name,
- // dandl.loc.ordinal(), sum );
- }
- return sum;
- }
-
private static File getSDDir( Context context )
{
File result = null;
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/UpdateCheckReceiver.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/UpdateCheckReceiver.java
index 36c14d98f..bda133c38 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/UpdateCheckReceiver.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/UpdateCheckReceiver.java
@@ -253,7 +253,7 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
JSONObject params = new JSONObject();
int lang = DictLangCache.getDictLangCode( context, dal );
String langStr = DictLangCache.getLangName( context, lang );
- String sum = DictUtils.getMD5SumFor( context, dal );
+ String sum = DictLangCache.getDictMD5Sum( context, dal.name );
try {
params.put( k_NAME, dal.name );
params.put( k_LANG, langStr );
From c815d739cd4ff4cd0db5239d664a18820caefa68 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Thu, 13 Sep 2012 20:54:35 -0700
Subject: [PATCH 25/44] generate md5sum for old .xwd files that don't have it
internally. And for those that do, verify that stored and generated values
match.
---
xwords4/dawg/dawg2dict.pl | 82 ++++++++++++++++++++++++++-------------
1 file changed, 56 insertions(+), 26 deletions(-)
diff --git a/xwords4/dawg/dawg2dict.pl b/xwords4/dawg/dawg2dict.pl
index e09d3a1ff..bca528a45 100755
--- a/xwords4/dawg/dawg2dict.pl
+++ b/xwords4/dawg/dawg2dict.pl
@@ -24,10 +24,11 @@ use strict;
use Fcntl;
use Encode 'from_to';
use Encode;
+use Digest::MD5;
my $gInFile;
my $gSumOnly = 0;
-my $gSum;
+my $gSum = '';
my $gDescOnly = 0;
my $gDesc;
my $gDoRaw = 0;
@@ -95,24 +96,37 @@ sub readXWDFaces($$$) {
$nChars = unpack( 'c', $buf );
printf STDERR "nChars of faces: %d\n", $nChars;
- binmode( $fh, ":encoding(utf8)" ) or die "binmode(:utf-8) failed\n";
- sysread( $fh, $buf, $nChars );
- length($buf) == $nChars or die "didn't read expected number of bytes\n";
- binmode( $fh ) or die "binmode failed\n";
+ # At this point $fh is pointing at the start of data
+ if ( $gSumOnly ) {
+ my $sum = sumRestOfFile( $fh );
+ if ( $sum eq $gSum ) {
+ print STDERR "got: $sum, $gSum twice!!!\n";
+ } elsif ( !$gSum ) {
+ $gSum = $sum;
+ } else {
+ print STDERR "disagreement: $sum vs $gSum\n";
+ exit( -1 );
+ }
+ } else {
+ binmode( $fh, ":encoding(utf8)" ) or die "binmode(:utf-8) failed\n";
+ sysread( $fh, $buf, $nChars );
+ length($buf) == $nChars or die "didn't read expected number of bytes\n";
+ binmode( $fh ) or die "binmode failed\n";
- print STDERR "string now: $buf\n";
- my @faces;
- for ( my $ii = 0; $ii < $nChars; ++$ii ) {
- my $chr = substr( $buf, $ii, 1 );
- print STDERR "pushing $chr \n";
- push( @faces, $chr );
+ print STDERR "string now: $buf\n";
+ my @faces;
+ for ( my $ii = 0; $ii < $nChars; ++$ii ) {
+ my $chr = substr( $buf, $ii, 1 );
+ print STDERR "pushing $chr \n";
+ push( @faces, $chr );
+ }
+
+ printf STDERR "at 0x%x after reading faces\n", systell($fh);
+
+ ${$nSpecials} = countSpecials( \@faces );
+ @{$facRef} = @faces;
+ printf STDERR "readXWDFaces=>%d\n", $nChars;
}
-
- printf STDERR "at 0x%x after reading faces\n", systell($fh);
-
- ${$nSpecials} = countSpecials( \@faces );
- @{$facRef} = @faces;
- printf STDERR "readXWDFaces=>%d\n", $nChars;
return $nChars;
} # readXWDFaces
@@ -170,7 +184,12 @@ sub printHeader($$) {
my ( $buf, $len ) = @_;
printf STDERR "skipped %d bytes of header:\n", $len + 2;
my $count;
- ($count, $gDesc, $gSum) = unpack( 'N Z* Z*', $buf );
+ if ( $len == 4 ) {
+ ($count) = unpack( 'N', $buf );
+ } else {
+ print STDERR 'unpacking...\n';
+ ($count, $gDesc, $gSum) = unpack( 'N Z* Z*', $buf );
+ }
printf STDERR "has %d words\n", $count;
}
@@ -190,7 +209,7 @@ sub nodeSizeFromFlags($$) {
if ( $flags == 2 || $ flags == 4 ) {
return 3;
- } elsif ( $flags == 5 ) {
+ } elsif ( $flags == 3 || $flags == 5 ) {
return 4;
} else {
die "invalid dict flags $flags";
@@ -208,6 +227,21 @@ sub mergeSpecials($$) {
}
}
+sub sumRestOfFile($) {
+ my ( $fh ) = @_;
+ my $buf;
+ my $count = 0;
+ my $md5 = Digest::MD5->new;
+ for ( ; ; ) {
+ my $nRead = sysread( $fh, $buf, 128 );
+ 0 == $nRead && last;
+ $count += $nRead;
+ $md5->add( $buf );
+ }
+ # print STDERR "read $count bytes\n";
+ return $md5->hexdigest();
+}
+
sub prepXWD($$$$) {
my ( $fh, $facRef, $nodesRef, $startRef ) = @_;
my $done = 1;
@@ -219,18 +253,14 @@ sub prepXWD($$$$) {
$gNodeSize = nodeSizeFromFlags( $fh, $flags );
+ my $nSpecials;
+ my $faceCount = readXWDFaces( $fh, $facRef, \$nSpecials ); # does checksum
+
if ( $gSumOnly ) {
print STDOUT $gSum, "\n";
} elsif( $gDescOnly ) {
print STDOUT $gDesc, "\n";
} else {
- $done = 0;
- }
-
- if ( !$done ) {
- my $nSpecials;
- my $faceCount = readXWDFaces( $fh, $facRef, \$nSpecials );
-
printf STDERR "at 0x%x before header read\n", systell($fh);
# skip xloc header
$nRead = sysread( $fh, $buf, 2 );
From 5d45d8d35f2144451586e0aa52345237fcd32db9 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sat, 15 Sep 2012 09:03:52 -0700
Subject: [PATCH 26/44] remove param that doesn't work when called from
mod_python
---
xwords4/dawg/dawg2dict.pl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xwords4/dawg/dawg2dict.pl b/xwords4/dawg/dawg2dict.pl
index bca528a45..f800e8ca3 100755
--- a/xwords4/dawg/dawg2dict.pl
+++ b/xwords4/dawg/dawg2dict.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -CS
+#!/usr/bin/perl -C
#
# Copyright 2004 - 2009 by Eric House (xwords@eehouse.org)
#
From 571300c0f832d2e86c34c8acde2c555e3ad04a20 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sat, 15 Sep 2012 09:34:27 -0700
Subject: [PATCH 27/44] work with two checksums per wordlist, the old that's on
the whole file, and the new that's on the wordlist data only.
---
xwords4/android/scripts/info.py | 74 +++++++++++++++++++++++----------
1 file changed, 53 insertions(+), 21 deletions(-)
diff --git a/xwords4/android/scripts/info.py b/xwords4/android/scripts/info.py
index a42fd2536..89ac4eacc 100755
--- a/xwords4/android/scripts/info.py
+++ b/xwords4/android/scripts/info.py
@@ -1,6 +1,7 @@
+#!/usr/bin/python
# Script meant to be installed on eehouse.org.
-import logging, shelve, hashlib, sys, json
+import logging, shelve, hashlib, sys, json, subprocess
try:
from mod_python import apache
apacheAvailable = True
@@ -18,6 +19,7 @@ k_DICTS = 'dicts'
k_LANG = 'lang'
k_MD5SUM = 'md5sum'
k_INDEX = 'index'
+k_ISUM = 'isum'
k_SUCCESS = 'success'
k_URL = 'url'
@@ -26,7 +28,7 @@ k_COUNT = 'count'
k_suffix = '.xwd'
k_filebase = "/var/www/"
-k_shelfFile = k_filebase + 'xw4/info_shelf'
+k_shelfFile = k_filebase + 'xw4/info_shelf_2'
k_urlbase = "http://eehouse.org/"
k_versions = { 'org.eehouse.android.xw4': {
'version' : 43,
@@ -49,8 +51,8 @@ k_versions_dbg = { 'org.eehouse.android.xw4': {
'org.eehouse.android.xw4sms' : {
'version' : 43,
k_AVERS : 43,
- k_GVERS : 'android_beta_51',
- k_URL : 'xw4/android/sms/XWords4-release_android_beta_51.apk',
+ k_GVERS : 'android_beta_51-50-g0ccc233',
+ k_URL : 'xw4/android/sms/XWords4-release_android_beta_51-50-g0ccc233.apk',
},
}
s_shelf = None
@@ -63,24 +65,43 @@ logging.basicConfig(level=logging.DEBUG
# ,filemode='w')
# This seems to be required to prime the pump somehow.
-logging.debug( "loaded...." )
+# logging.debug( "loaded...." )
-def md5Checksum(sums, filePath):
+def getInternalSum( filePath ):
+ filePath = k_filebase + "and_wordlists/" + filePath
+ proc = subprocess.Popen(['/usr/bin/perl',
+ '--',
+ '/var/www/xw4/dawg2dict.pl',
+ '-get-sum',
+ '-dict', filePath ],
+ stdout = subprocess.PIPE,
+ stderr = subprocess.PIPE)
+ return proc.communicate()[0].strip()
+
+def md5Checksums( sums, filePath ):
if not filePath.endswith(k_suffix): filePath += k_suffix
if not filePath in sums:
+ logging.debug( "opening %s" % (k_filebase + "and_wordlists/" + filePath))
file = open( k_filebase + "and_wordlists/" + filePath, 'rb' )
md5 = hashlib.md5()
while True:
buffer = file.read(128)
if not buffer: break
md5.update( buffer )
- sums[filePath] = md5.hexdigest()
+
+ sums[filePath] = [ md5.hexdigest(), getInternalSum( filePath ) ]
logging.debug( "figured sum for %s" % filePath )
return sums[filePath]
def getDictSums():
global s_shelf
- s_shelf = shelve.open(k_shelfFile)
+ # shelve will fail if permissions are wrong. That's ok for some
+ # testing: just make a fake shelf and test before saving it later.
+ try:
+ s_shelf = shelve.open(k_shelfFile)
+ except:
+ s_shelf = {}
+
if not k_SUMS in s_shelf: s_shelf[k_SUMS] = {}
if not k_COUNT in s_shelf: s_shelf[k_COUNT] = 0
s_shelf[k_COUNT] += 1
@@ -115,16 +136,16 @@ def dictVersion( req, name, lang, md5sum ):
dictSums = getDictSums()
path = lang + "/" + name
if not path in dictSums:
- sum = md5Checksum( dictSums, path )
- if sum:
- dictSums[path] = sum
+ sums = md5Checksums( dictSums, path )
+ if sums:
+ dictSums[path] = sums
s_shelf[k_SUMS] = dictSums
if path in dictSums:
- if dictSums[path] != md5sum:
+ if not md5sum in dictSums[path]:
result[k_URL] = k_urlbase + "and_wordlists/" + path
else:
logging.debug( path + " not known" )
- s_shelf.close()
+ if 'close' in s_shelf: s_shelf.close()
return json.dumps( result )
def getApp( params ):
@@ -137,6 +158,7 @@ def getApp( params ):
gvers = params[k_GVERS]
if k_INSTALLER in params: installer = params[k_INSTALLER]
else: installer = ''
+
logging.debug( "name: %s; avers: %s; installer: %s; gvers: %s"
% (name, avers, installer, gvers) )
if k_DEVOK in params and params[k_DEVOK]: versions = k_versions_dbg
@@ -166,18 +188,19 @@ def getDicts( params ):
if not name.endswith(k_suffix): name += k_suffix
path = lang + "/" + name
if not path in dictSums:
- sum = md5Checksum( dictSums, path )
- if sum:
- dictSums[path] = sum
+ sums = md5Checksums( dictSums, path )
+ if sums:
+ dictSums[path] = sums
s_shelf[k_SUMS] = dictSums
if path in dictSums:
- if dictSums[path] != md5sum:
+ if not md5sum in dictSums[path]:
cur = { k_URL : k_urlbase + "and_wordlists/" + path,
- k_INDEX : index }
+ k_INDEX : index, k_ISUM: dictSums[path][1] }
result.append( cur )
else:
logging.debug( path + " not known" )
+ if 'close' in s_shelf: s_shelf.close()
if 0 == len(result): result = None
return result
@@ -201,7 +224,8 @@ def clearShelf():
def usage():
print "usage:", sys.argv[0], '--get-sums [lang/dict]*'
- print " | --test-get-app app avers gvers"
+ print ' | --test-get-app app avers gvers'
+ print ' | --test-get-dicts name lang curSum'
print ' | --clear-shelf'
sys.exit(-1)
@@ -213,9 +237,9 @@ def main():
elif arg == '--get-sums':
dictSums = getDictSums()
for arg in sys.argv[2:]:
- print arg, md5Checksum(dictSums, arg)
+ print arg, md5Checksums(dictSums, arg)
s_shelf[k_SUMS] = dictSums
- s_shelf.close()
+ if 'close' in s_shelf: s_shelf.close()
elif arg == '--test-get-app':
if not 5 == len(sys.argv): usage()
params = { k_NAME: sys.argv[2],
@@ -223,6 +247,14 @@ def main():
k_GVERS: sys.argv[4],
}
print getApp( params )
+ elif arg == '--test-get-dicts':
+ if not 5 == len(sys.argv): usage()
+ params = { k_NAME: sys.argv[2],
+ k_LANG : sys.argv[3],
+ k_MD5SUM : sys.argv[4],
+ k_INDEX : 0,
+ }
+ print getDicts( [params] )
else:
usage()
From ad67f31573f91bcbe3113b72bc1342e6af395492 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sat, 15 Sep 2012 15:19:23 -0700
Subject: [PATCH 28/44] saveToken can be 0 when only gi is being saved
---
xwords4/common/game.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xwords4/common/game.c b/xwords4/common/game.c
index 4310ebd9e..839fd0166 100644
--- a/xwords4/common/game.c
+++ b/xwords4/common/game.c
@@ -261,13 +261,13 @@ void
game_saveToStream( const XWGame* game, const CurGameInfo* gi,
XWStreamCtxt* stream, XP_U16 saveToken )
{
- XP_ASSERT( 0 != saveToken );
stream_putU8( stream, CUR_STREAM_VERS );
stream_setVersion( stream, CUR_STREAM_VERS );
gi_writeToStream( stream, gi );
if ( !!game ) {
+ XP_ASSERT( 0 != saveToken );
stream_putU8( stream, (XP_U8)!!game->comms );
#ifdef XWFEATURE_STANDALONE_ONLY
XP_ASSERT( !game->comms );
From 937bde6378f9bcd785665264ee18eb532697f4d9 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sat, 15 Sep 2012 15:21:31 -0700
Subject: [PATCH 29/44] combine two jniutils methods into one
---
xwords4/android/XWords4/jni/anddict.c | 6 ++-
xwords4/android/XWords4/jni/jniutlswrapper.c | 26 ++++------
xwords4/android/XWords4/jni/jniutlswrapper.h | 5 +-
.../org/eehouse/android/xw4/jni/JNIUtils.java | 3 +-
.../eehouse/android/xw4/jni/JNIUtilsImpl.java | 50 ++++++++++---------
5 files changed, 43 insertions(+), 47 deletions(-)
diff --git a/xwords4/android/XWords4/jni/anddict.c b/xwords4/android/XWords4/jni/anddict.c
index 70cfd6649..ee33595c3 100644
--- a/xwords4/android/XWords4/jni/anddict.c
+++ b/xwords4/android/XWords4/jni/anddict.c
@@ -346,9 +346,11 @@ parseDict( AndDictionaryCtxt* ctxt, XP_U8 const* ptr, XP_U32 dictLength,
#endif
) {
JNIEnv* env = ctxt->env;
- jstring jsum = and_util_getMD5SumFor( ctxt->jniutil, ctxt->super.name );
+ jstring jsum = and_util_getMD5SumFor( ctxt->jniutil, ctxt->super.name,
+ NULL, 0 );
if ( NULL == jsum ) {
- jsum = and_util_figureMD5Sum( ctxt->jniutil, ptr, end - ptr );
+ jsum = and_util_getMD5SumFor( ctxt->jniutil, ctxt->super.name,
+ ptr, end - ptr );
}
XP_UCHAR* md5Sum = getStringCopy( MPPARM(ctxt->super.mpool) env, jsum );
(*env)->DeleteLocalRef( env, jsum );
diff --git a/xwords4/android/XWords4/jni/jniutlswrapper.c b/xwords4/android/XWords4/jni/jniutlswrapper.c
index 70bfc5e45..bac160648 100644
--- a/xwords4/android/XWords4/jni/jniutlswrapper.c
+++ b/xwords4/android/XWords4/jni/jniutlswrapper.c
@@ -93,28 +93,20 @@ and_util_splitFaces( JNIUtilCtxt* jniutil, const XP_U8* bytes, jsize len,
}
jstring
-and_util_getMD5SumFor( JNIUtilCtxt* jniutil, const XP_UCHAR* name )
+and_util_getMD5SumFor( JNIUtilCtxt* jniutil, const XP_UCHAR* name,
+ const XP_U8* bytes, jsize len )
{
JNIEnv* env = *jniutil->envp;
jmethodID mid = getMethodID( env, jniutil->jjniutil, "getMD5SumFor",
- "(Ljava/lang/String;)Ljava/lang/String;" );
+ "(Ljava/lang/String;[B)Ljava/lang/String;" );
jstring jname = (*env)->NewStringUTF( env, name );
+ jbyteArray jbytes = NULL == bytes? NULL
+ : makeByteArray( env, len, (jbyte*)bytes );
jstring result =
- (*env)->CallObjectMethod( env, jniutil->jjniutil, mid, jname );
+ (*env)->CallObjectMethod( env, jniutil->jjniutil, mid, jname, jbytes );
(*env)->DeleteLocalRef( env, jname );
+ if ( NULL != jbytes ) {
+ (*env)->DeleteLocalRef( env, jbytes );
+ }
return result;
}
-
-jstring
-and_util_figureMD5Sum( JNIUtilCtxt* jniutil, const XP_U8* bytes, jsize len )
-{
- JNIEnv* env = *jniutil->envp;
- jmethodID mid = getMethodID( env, jniutil->jjniutil, "figureMD5Sum",
- "([B)Ljava/lang/String;" );
- jbyteArray jbytes = makeByteArray( env, len, (jbyte*)bytes );
- jstring sum =
- (*env)->CallObjectMethod( env, jniutil->jjniutil, mid, jbytes );
- (*env)->DeleteLocalRef( env, jbytes );
-
- return sum;
-}
diff --git a/xwords4/android/XWords4/jni/jniutlswrapper.h b/xwords4/android/XWords4/jni/jniutlswrapper.h
index 389c1462d..dc75abe67 100644
--- a/xwords4/android/XWords4/jni/jniutlswrapper.h
+++ b/xwords4/android/XWords4/jni/jniutlswrapper.h
@@ -35,8 +35,7 @@ jobject and_util_makeJBitmap( JNIUtilCtxt* jniu, int nCols, int nRows,
const jboolean* colors );
jobject and_util_splitFaces( JNIUtilCtxt* jniu, const XP_U8* bytes, int len,
XP_Bool isUTF8 );
-jstring and_util_getMD5SumFor( JNIUtilCtxt* jniutil, const XP_UCHAR* name );
-jstring and_util_figureMD5Sum( JNIUtilCtxt* jniutil, const XP_U8* bytes,
- jsize len );
+jstring and_util_getMD5SumFor( JNIUtilCtxt* jniutil, const XP_UCHAR* name,
+ const XP_U8* bytes, jsize len );
#endif
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtils.java
index d1fff71a6..3172b5099 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtils.java
@@ -26,6 +26,5 @@ public interface JNIUtils {
// Stuff I can't do in C....
String[] splitFaces( byte[] chars, boolean isUTF8 );
- String getMD5SumFor( String dictName );
- String figureMD5Sum( byte[] bytes );
+ String getMD5SumFor( String dictName, byte[] bytes );
}
\ No newline at end of file
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java
index 27b832446..6720079f3 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java
@@ -91,31 +91,35 @@ public class JNIUtilsImpl implements JNIUtils {
return result;
}
- public String getMD5SumFor( String dictName )
+ public String getMD5SumFor( String dictName, byte[] bytes )
{
- return DBUtils.dictsGetMD5Sum( m_context, dictName );
- }
-
- public String figureMD5Sum( byte[] bytes )
- {
- byte[] digest = null;
- try {
- MessageDigest md = MessageDigest.getInstance("MD5");
- byte[] buf = new byte[128];
- int nLeft = bytes.length;
- int offset = 0;
- while ( 0 < nLeft ) {
- int len = Math.min( buf.length, nLeft );
- System.arraycopy( bytes, offset, buf, 0, len );
- md.update( buf, 0, len );
- nLeft -= len;
- offset += len;
+ DbgUtils.logf( "dictName(%H)", bytes );
+ String result = null;
+ if ( null == bytes ) {
+ result = DBUtils.dictsGetMD5Sum( m_context, dictName );
+ } else {
+ byte[] digest = null;
+ try {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ byte[] buf = new byte[128];
+ int nLeft = bytes.length;
+ int offset = 0;
+ while ( 0 < nLeft ) {
+ int len = Math.min( buf.length, nLeft );
+ System.arraycopy( bytes, offset, buf, 0, len );
+ md.update( buf, 0, len );
+ nLeft -= len;
+ offset += len;
+ }
+ digest = md.digest();
+ } catch ( java.security.NoSuchAlgorithmException nsae ) {
+ DbgUtils.loge( nsae );
}
- digest = md.digest();
- } catch ( java.security.NoSuchAlgorithmException nsae ) {
- DbgUtils.loge( nsae );
- }
+ result = Utils.digestToString( digest );
- return Utils.digestToString( digest );
+ // Is this needed? Caller might be doing it anyway.
+ DBUtils.dictsSetMD5Sum( m_context, dictName, result );
+ }
+ return result;
}
}
From b2d47d70be800936d51df601dabe82a9b9824ac2 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sat, 15 Sep 2012 15:19:23 -0700
Subject: [PATCH 30/44] saveToken can be 0 when only gi is being saved
---
xwords4/common/game.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xwords4/common/game.c b/xwords4/common/game.c
index 4310ebd9e..839fd0166 100644
--- a/xwords4/common/game.c
+++ b/xwords4/common/game.c
@@ -261,13 +261,13 @@ void
game_saveToStream( const XWGame* game, const CurGameInfo* gi,
XWStreamCtxt* stream, XP_U16 saveToken )
{
- XP_ASSERT( 0 != saveToken );
stream_putU8( stream, CUR_STREAM_VERS );
stream_setVersion( stream, CUR_STREAM_VERS );
gi_writeToStream( stream, gi );
if ( !!game ) {
+ XP_ASSERT( 0 != saveToken );
stream_putU8( stream, (XP_U8)!!game->comms );
#ifdef XWFEATURE_STANDALONE_ONLY
XP_ASSERT( !game->comms );
From ee1df7eeb7e5dc5aa4245c2562dffb469bff17c0 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sat, 15 Sep 2012 15:57:38 -0700
Subject: [PATCH 31/44] replace DeleteLocalRef calls with version that checks
for NULL
---
xwords4/android/XWords4/jni/anddict.c | 15 ++---
xwords4/android/XWords4/jni/andutils.c | 63 +++++++++++++-------
xwords4/android/XWords4/jni/andutils.h | 4 ++
xwords4/android/XWords4/jni/drawwrapper.c | 38 +++++-------
xwords4/android/XWords4/jni/jniutlswrapper.c | 6 +-
xwords4/android/XWords4/jni/utilwrapper.c | 33 ++++------
xwords4/android/XWords4/jni/xportwrapper.c | 17 ++----
xwords4/android/XWords4/jni/xwjni.c | 18 +++---
8 files changed, 96 insertions(+), 98 deletions(-)
diff --git a/xwords4/android/XWords4/jni/anddict.c b/xwords4/android/XWords4/jni/anddict.c
index 1c86f7018..5893e0285 100644
--- a/xwords4/android/XWords4/jni/anddict.c
+++ b/xwords4/android/XWords4/jni/anddict.c
@@ -141,7 +141,7 @@ andMakeBitmap( AndDictionaryCtxt* ctxt, XP_U8 const** ptrp,
JNIEnv* env = ctxt->env;
jobject tmp = and_util_makeJBitmap( ctxt->jniutil, nCols, nRows, colors );
bitmap = (*env)->NewGlobalRef( env, tmp );
- (*env)->DeleteLocalRef( env, tmp );
+ deleteLocalRef( env, tmp );
XP_FREE( ctxt->super.mpool, colors );
#endif
}
@@ -242,13 +242,13 @@ splitFaces_via_java( JNIEnv* env, AndDictionaryCtxt* ctxt, const XP_U8* ptr,
XP_MEMCPY( &facesBuf[indx], bytes, nBytes );
}
(*env)->ReleaseStringUTFChars( env, jstr, bytes );
- (*env)->DeleteLocalRef( env, jstr );
+ deleteLocalRef( env, jstr );
indx += nBytes;
facesBuf[indx++] = '\0';
XP_ASSERT( indx < VSIZE(facesBuf) );
}
- (*env)->DeleteLocalRef( env, jstrarr );
+ deleteLocalRef( env, jstrarr );
XP_UCHAR* faces = (XP_UCHAR*)XP_CALLOC( ctxt->super.mpool, indx );
const XP_UCHAR** ptrs = (const XP_UCHAR**)
@@ -348,7 +348,7 @@ parseDict( AndDictionaryCtxt* ctxt, XP_U8 const* ptr, XP_U32 dictLength,
JNIEnv* env = ctxt->env;
jstring jsum = and_util_figureMD5Sum( ctxt->jniutil, ptr, end - ptr );
XP_UCHAR* md5Sum = getStringCopy( MPPARM(ctxt->super.mpool) env, jsum );
- (*env)->DeleteLocalRef( env, jsum );
+ deleteLocalRef( env, jsum );
if ( NULL == ctxt->super.md5Sum ) {
ctxt->super.md5Sum = md5Sum;
} else {
@@ -534,12 +534,9 @@ makeDicts( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil,
dict = makeDict( MPPARM(mpool) env, jniutil, jname, jdict,
jpath, jlang, false );
XP_ASSERT( !!dict );
- (*env)->DeleteLocalRef( env, jdict );
- (*env)->DeleteLocalRef( env, jname );
- }
- if ( NULL != jpath) {
- (*env)->DeleteLocalRef( env, jpath );
+ deleteLocalRefs( env, jdict, jname, DELETE_NO_REF );
}
+ deleteLocalRef( env, jpath );
}
if ( 0 == ii ) {
*dictp = dict;
diff --git a/xwords4/android/XWords4/jni/andutils.c b/xwords4/android/XWords4/jni/andutils.c
index ecba9dd28..5259a7c55 100644
--- a/xwords4/android/XWords4/jni/andutils.c
+++ b/xwords4/android/XWords4/jni/andutils.c
@@ -84,7 +84,7 @@ getInt( JNIEnv* env, jobject obj, const char* name )
jfieldID fid = (*env)->GetFieldID( env, cls, name, "I");
XP_ASSERT( !!fid );
int result = (*env)->GetIntField( env, obj, fid );
- (*env)->DeleteLocalRef( env, cls );
+ deleteLocalRef( env, cls );
return result;
}
@@ -96,7 +96,7 @@ setInt( JNIEnv* env, jobject obj, const char* name, int value )
jfieldID fid = (*env)->GetFieldID( env, cls, name, "I");
XP_ASSERT( !!fid );
(*env)->SetIntField( env, obj, fid, value );
- (*env)->DeleteLocalRef( env, cls );
+ deleteLocalRef( env, cls );
}
bool
@@ -109,7 +109,7 @@ setBool( JNIEnv* env, jobject obj, const char* name, bool value )
(*env)->SetBooleanField( env, obj, fid, value );
success = true;
}
- (*env)->DeleteLocalRef( env, cls );
+ deleteLocalRef( env, cls );
return success;
}
@@ -120,13 +120,13 @@ 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 );
+ deleteLocalRef( env, cls );
if ( 0 != fid ) {
jstring str = (*env)->NewStringUTF( env, value );
(*env)->SetObjectField( env, obj, fid, str );
success = true;
- (*env)->DeleteLocalRef( env, str );
+ deleteLocalRef( env, str );
}
return success;
@@ -148,11 +148,11 @@ getString( JNIEnv* env, jobject obj, const char* name, XP_UCHAR* buf,
const char* chars = (*env)->GetStringUTFChars( env, jstr, NULL );
XP_MEMCPY( buf, chars, len );
(*env)->ReleaseStringUTFChars( env, jstr, chars );
- (*env)->DeleteLocalRef( env, jstr );
+ deleteLocalRef( env, jstr );
}
buf[len] = '\0';
- (*env)->DeleteLocalRef( env, cls );
+ deleteLocalRef( env, cls );
}
XP_UCHAR*
@@ -180,7 +180,7 @@ getObject( JNIEnv* env, jobject obj, const char* name, const char* sig,
*ret = (*env)->GetObjectField( env, obj, fid );
XP_ASSERT( !!*ret );
- (*env)->DeleteLocalRef( env, cls );
+ deleteLocalRef( env, cls );
return true;
}
@@ -194,7 +194,7 @@ setObject( JNIEnv* env, jobject obj, const char* name, const char* sig,
XP_ASSERT( !!fid );
(*env)->SetObjectField( env, obj, fid, val );
- (*env)->DeleteLocalRef( env, cls );
+ deleteLocalRef( env, cls );
}
bool
@@ -206,7 +206,7 @@ getBool( JNIEnv* env, jobject obj, const char* name )
jfieldID fid = (*env)->GetFieldID( env, cls, name, "Z");
XP_ASSERT( !!fid );
result = (*env)->GetBooleanField( env, obj, fid );
- (*env)->DeleteLocalRef( env, cls );
+ deleteLocalRef( env, cls );
return result;
}
@@ -266,7 +266,7 @@ getIntFromArray( JNIEnv* env, jintArray arr, bool del )
int result = ints[0];
(*env)->ReleaseIntArrayElements( env, arr, ints, 0);
if ( del ) {
- (*env)->DeleteLocalRef( env, arr );
+ deleteLocalRef( env, arr );
}
return result;
}
@@ -277,14 +277,13 @@ 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 );
+ deleteLocalRefs( env, clas, empty, DELETE_NO_REF );
int ii;
for ( ii = 0; !!vals && ii < siz; ++ii ) {
jstring jstr = (*env)->NewStringUTF( env, vals[ii] );
(*env)->SetObjectArrayElement( env, jarray, ii, jstr );
- (*env)->DeleteLocalRef( env, jstr );
+ deleteLocalRef( env, jstr );
}
return jarray;
@@ -311,7 +310,7 @@ getMethodID( JNIEnv* env, jobject obj, const char* proc, const char* sig )
XP_ASSERT( !!cls );
jmethodID mid = (*env)->GetMethodID( env, cls, proc, sig );
XP_ASSERT( !!mid );
- (*env)->DeleteLocalRef( env, cls );
+ deleteLocalRef( env, cls );
return mid;
}
@@ -400,8 +399,7 @@ jenumFieldToInt( JNIEnv* env, jobject j_gi, const char* field,
XP_ASSERT( !!jenum );
jint result = jEnumToInt( env, jenum );
- (*env)->DeleteLocalRef( env, clazz );
- (*env)->DeleteLocalRef( env, jenum );
+ deleteLocalRefs( env, clazz, jenum, DELETE_NO_REF );
return result;
}
@@ -415,7 +413,7 @@ intToJenumField( JNIEnv* env, jobject jobj, int val, const char* field,
snprintf( buf, sizeof(buf), "L%s;", fieldSig );
jfieldID fid = (*env)->GetFieldID( env, clazz, field, buf );
XP_ASSERT( !!fid ); /* failed */
- (*env)->DeleteLocalRef( env, clazz );
+ deleteLocalRef( env, clazz );
jobject jenum = (*env)->GetObjectField( env, jobj, fid );
if ( !jenum ) { /* won't exist in new object */
@@ -426,13 +424,13 @@ intToJenumField( JNIEnv* env, jobject jobj, int val, const char* field,
jenum = (*env)->NewObject( env, clazz, mid );
XP_ASSERT( !!jenum );
(*env)->SetObjectField( env, jobj, fid, jenum );
- (*env)->DeleteLocalRef( env, clazz );
+ deleteLocalRef( env, clazz );
}
jobject jval = intToJEnum( env, val, fieldSig );
XP_ASSERT( !!jval );
(*env)->SetObjectField( env, jobj, fid, jval );
- (*env)->DeleteLocalRef( env, jval );
+ deleteLocalRef( env, jval );
} /* intToJenumField */
/* Cons up a new enum instance and set its value */
@@ -455,8 +453,7 @@ intToJEnum( JNIEnv* env, int val, const char* enumSig )
jenum = (*env)->GetObjectArrayElement( env, jvalues, val );
XP_ASSERT( !!jenum );
- (*env)->DeleteLocalRef( env, jvalues );
- (*env)->DeleteLocalRef( env, clazz );
+ deleteLocalRefs( env, jvalues, clazz, DELETE_NO_REF );
return jenum;
} /* intToJEnum */
@@ -476,6 +473,28 @@ and_empty_stream( MPFORMAL AndGlobals* globals )
return stream;
}
+void deleteLocalRef( JNIEnv* env, jobject jobj )
+{
+ if ( NULL != jobj ) {
+ (*env)->DeleteLocalRef( env, jobj );
+ }
+}
+
+void
+deleteLocalRefs( JNIEnv* env, jobject jobj, ... )
+{
+ va_list ap;
+ va_start( ap, jobj );
+ for ( ; ; ) {
+ jobject jnext = va_arg( ap, jobject );
+ if ( DELETE_NO_REF == jnext ) {
+ break;
+ }
+ deleteLocalRef( env, jnext );
+ }
+ va_end( ap );
+}
+
#ifdef DEBUG
void
android_debugf( const char* format, ... )
diff --git a/xwords4/android/XWords4/jni/andutils.h b/xwords4/android/XWords4/jni/andutils.h
index 20215b8d6..029f7cf31 100644
--- a/xwords4/android/XWords4/jni/andutils.h
+++ b/xwords4/android/XWords4/jni/andutils.h
@@ -70,4 +70,8 @@ void intToJenumField( JNIEnv* env, jobject jobj, int val, const char* field,
const char* fieldSig );
jobject intToJEnum( JNIEnv* env, int val, const char* enumSig );
jint jEnumToInt( JNIEnv* env, jobject jenum );
+
+void deleteLocalRef( JNIEnv* env, jobject jobj );
+void deleteLocalRefs( JNIEnv* env, jobject jobj, ... );
+# define DELETE_NO_REF ((jobject)-1) /* terminates above varargs list */
#endif
diff --git a/xwords4/android/XWords4/jni/drawwrapper.c b/xwords4/android/XWords4/jni/drawwrapper.c
index f05b04ee1..e78e3e34b 100644
--- a/xwords4/android/XWords4/jni/drawwrapper.c
+++ b/xwords4/android/XWords4/jni/drawwrapper.c
@@ -59,10 +59,8 @@ makeJRect( AndDraw* draw, int indx, const XP_Rect* rect )
robj = (*env)->NewObject( env, rclass, initId, rect->left, rect->top,
right, bottom );
- (*env)->DeleteLocalRef( env, rclass );
-
draw->jCache[indx] = (*env)->NewGlobalRef( env, robj );
- (*env)->DeleteLocalRef( env, robj );
+ deleteLocalRefs( env, robj, rclass, DELETE_NO_REF );
robj = draw->jCache[indx];
} else {
setInt( env, robj, "left", rect->left );
@@ -94,7 +92,6 @@ makeJRects( AndDraw* draw, int indx, XP_U16 nPlayers, const XP_Rect rects[] )
jclass rclass = (*env)->FindClass( env, "android/graphics/Rect");
jrects = (*env)->NewObjectArray( env, nPlayers, rclass, NULL );
draw->jCache[indx] = (*env)->NewGlobalRef( env, jrects );
- (*env)->DeleteLocalRef( env, jrects );
jrects = draw->jCache[indx];
jmethodID initId = (*env)->GetMethodID( env, rclass, "",
@@ -103,10 +100,10 @@ makeJRects( AndDraw* draw, int indx, XP_U16 nPlayers, const XP_Rect rects[] )
for ( ii = 0; ii < nPlayers; ++ii ) {
jobject jrect = (*env)->NewObject( env, rclass, initId );
(*env)->SetObjectArrayElement( env, jrects, ii, jrect );
- (*env)->DeleteLocalRef( env, jrect );
+ deleteLocalRef( env, jrect );
}
- (*env)->DeleteLocalRef( env, rclass );
+ deleteLocalRefs( env, rclass, jrects, DELETE_NO_REF );
}
if ( NULL != rects ) {
@@ -131,17 +128,17 @@ makeDSIs( AndDraw* draw, int indx, XP_U16 nPlayers, const DrawScoreInfo dsis[] )
jclass clas = (*env)->FindClass( env, PKG_PATH("jni/DrawScoreInfo") );
dsiobjs = (*env)->NewObjectArray( env, nPlayers, clas, NULL );
draw->jCache[indx] = (*env)->NewGlobalRef( env, dsiobjs );
- (*env)->DeleteLocalRef( env, dsiobjs );
+ deleteLocalRef( env, dsiobjs );
dsiobjs = draw->jCache[indx];
jmethodID initId = (*env)->GetMethodID( env, clas, "", "()V" );
for ( ii = 0; ii < nPlayers; ++ii ) {
jobject dsiobj = (*env)->NewObject( env, clas, initId );
(*env)->SetObjectArrayElement( env, dsiobjs, ii, dsiobj );
- (*env)->DeleteLocalRef( env, dsiobj );
+ deleteLocalRef( env, dsiobj );
}
- (*env)->DeleteLocalRef( env, clas );
+ deleteLocalRef( env, clas );
}
for ( ii = 0; ii < nPlayers; ++ii ) {
@@ -173,10 +170,9 @@ makeDSI( AndDraw* draw, int indx, const DrawScoreInfo* dsi )
jclass rclass = (*env)->FindClass( env, PKG_PATH("jni/DrawScoreInfo") );
jmethodID initId = (*env)->GetMethodID( env, rclass, "", "()V" );
dsiobj = (*env)->NewObject( env, rclass, initId );
- (*env)->DeleteLocalRef( env, rclass );
draw->jCache[indx] = (*env)->NewGlobalRef( env, dsiobj );
- (*env)->DeleteLocalRef( env, dsiobj );
+ deleteLocalRefs( env, rclass, dsiobj, DELETE_NO_REF );
dsiobj = draw->jCache[indx];
}
@@ -219,7 +215,7 @@ and_draw_scoreBegin( DrawCtx* dctx, const XP_Rect* rect,
result = (*env)->CallBooleanMethod( env, draw->jdraw, mid,
jrect, numPlayers, jscores, remCount );
- (*env)->DeleteLocalRef( env, jscores );
+ deleteLocalRef( env, jscores );
return result;
}
@@ -389,9 +385,7 @@ and_draw_drawCell( DrawCtx* dctx, const XP_Rect* rect, const XP_UCHAR* text,
jrect, jtext, tile, value,
owner, bonus, hintAtts,
flags );
- if ( !!jtext ) {
- (*env)->DeleteLocalRef( env, jtext );
- }
+ deleteLocalRef( env, jtext );
return result;
}
@@ -444,9 +438,7 @@ and_draw_drawTile( DrawCtx* dctx, const XP_Rect* rect, const XP_UCHAR* text,
(*env)->CallVoidMethod( env, draw->jdraw, mid,
jrect, jtext, val, flags );
- if ( !!jtext ) {
- (*env)->DeleteLocalRef( env, jtext );
- }
+ deleteLocalRef( env, jtext );
}
static void
@@ -466,9 +458,7 @@ and_draw_drawTileMidDrag( DrawCtx* dctx, const XP_Rect* rect,
(*env)->CallVoidMethod( env, draw->jdraw, mid,
jrect, jtext, val, owner, flags );
- if ( !!jtext ) {
- (*env)->DeleteLocalRef( env, jtext );
- }
+ deleteLocalRef( env, jtext );
}
static void
@@ -550,7 +540,7 @@ and_draw_getMiniWText( DrawCtx* dctx, XWMiniTextType textHint )
const char* str = (*env)->GetStringUTFChars( env, jstr, NULL );
snprintf( draw->miniTextBuf, VSIZE(draw->miniTextBuf), "%s", str );
(*env)->ReleaseStringUTFChars( env, jstr, str );
- (*env)->DeleteLocalRef( env, jstr );
+ deleteLocalRef( env, jstr );
return draw->miniTextBuf;
}
@@ -567,7 +557,7 @@ and_draw_measureMiniWText( DrawCtx* dctx, const XP_UCHAR* textP,
(*env)->CallVoidMethod( env, draw->jdraw, mid,
jstr, widthArray, heightArray );
- (*env)->DeleteLocalRef( env, jstr );
+ deleteLocalRef( env, jstr );
*width = getIntFromArray( env, widthArray, true );
*height = getIntFromArray( env, heightArray, true );
}
@@ -585,7 +575,7 @@ and_draw_drawMiniWindow( DrawCtx* dctx, const XP_UCHAR* text,
(*env)->CallVoidMethod( env, draw->jdraw, mid,
jstr, jrect );
- (*env)->DeleteLocalRef( env, jstr );
+ deleteLocalRef( env, jstr );
}
#endif
diff --git a/xwords4/android/XWords4/jni/jniutlswrapper.c b/xwords4/android/XWords4/jni/jniutlswrapper.c
index e5d5b5d91..d7d37959e 100644
--- a/xwords4/android/XWords4/jni/jniutlswrapper.c
+++ b/xwords4/android/XWords4/jni/jniutlswrapper.c
@@ -68,7 +68,7 @@ and_util_makeJBitmap( JNIUtilCtxt* jniutil, int nCols, int nRows,
bitmap = (*env)->CallObjectMethod( env, jniutil->jjniutil, mid,
nCols, nRows, jcolors );
- (*env)->DeleteLocalRef( env, jcolors );
+ deleteLocalRef( env, jcolors );
return bitmap;
}
@@ -87,7 +87,7 @@ and_util_splitFaces( JNIUtilCtxt* jniutil, const XP_U8* bytes, jsize len,
jbyteArray jbytes = makeByteArray( env, len, (jbyte*)bytes );
strarray =
(*env)->CallObjectMethod( env, jniutil->jjniutil, mid, jbytes, isUTF8 );
- (*env)->DeleteLocalRef( env, jbytes );
+ deleteLocalRef( env, jbytes );
return strarray;
}
@@ -101,7 +101,7 @@ and_util_figureMD5Sum( JNIUtilCtxt* jniutil, const XP_U8* bytes, jsize len )
jbyteArray jbytes = makeByteArray( env, len, (jbyte*)bytes );
jstring sum =
(*env)->CallObjectMethod( env, jniutil->jjniutil, mid, jbytes );
- (*env)->DeleteLocalRef( env, jbytes );
+ deleteLocalRef( env, jbytes );
return sum;
}
diff --git a/xwords4/android/XWords4/jni/utilwrapper.c b/xwords4/android/XWords4/jni/utilwrapper.c
index 2671f9065..4d9e29364 100644
--- a/xwords4/android/XWords4/jni/utilwrapper.c
+++ b/xwords4/android/XWords4/jni/utilwrapper.c
@@ -129,9 +129,7 @@ and_util_userQuery( XW_UtilCtxt* uc, UtilQueryID id, XWStreamCtxt* stream )
jstr = streamToJString( env, stream );
}
result = (*env)->CallBooleanMethod( env, util->jutil, mid, id, jstr );
- if ( NULL != jstr ) {
- (*env)->DeleteLocalRef( env, jstr );
- }
+ deleteLocalRef( env, jstr );
UTIL_CBK_TAIL();
return result;
}
@@ -143,7 +141,7 @@ and_util_confirmTrade( XW_UtilCtxt* uc, const XP_UCHAR** tiles, XP_U16 nTiles )
UTIL_CBK_HEADER("confirmTrade", "([Ljava/lang/String;)Z" );
jobjectArray jtiles = makeStringArray( env, nTiles, tiles );
result = (*env)->CallBooleanMethod( env, util->jutil, mid, jtiles );
- (*env)->DeleteLocalRef( env, jtiles );
+ deleteLocalRef( env, jtiles );
UTIL_CBK_TAIL();
return result;
}
@@ -160,7 +158,7 @@ and_util_userPickTileBlank( XW_UtilCtxt* uc, XP_U16 playerNum,
result = (*env)->CallIntMethod( env, util->jutil, mid,
playerNum, jtexts );
- (*env)->DeleteLocalRef( env, jtexts );
+ deleteLocalRef( env, jtexts );
UTIL_CBK_TAIL();
return result;
}
@@ -178,8 +176,7 @@ and_util_userPickTileTray( XW_UtilCtxt* uc, const PickInfo* pi,
result = (*env)->CallIntMethod( env, util->jutil, mid,
playerNum, jtexts, jcurtiles,
pi->thisPick );
- (*env)->DeleteLocalRef( env, jtexts );
- (*env)->DeleteLocalRef( env, jcurtiles );
+ deleteLocalRefs( env, jtexts, jcurtiles, DELETE_NO_REF );
UTIL_CBK_TAIL();
return result;
@@ -195,7 +192,7 @@ and_util_askPassword( XW_UtilCtxt* uc, const XP_UCHAR* name,
jstring jname = (*env)->NewStringUTF( env, name );
jstring jstr = (*env)->CallObjectMethod( env, util->jutil, mid,
jname );
- (*env)->DeleteLocalRef( env, jname );
+ deleteLocalRef( env, jname );
if ( NULL != jstr ) { /* null means user cancelled */
jsize jsiz = (*env)->GetStringUTFLength( env, jstr );
@@ -207,7 +204,7 @@ and_util_askPassword( XW_UtilCtxt* uc, const XP_UCHAR* name,
*len = jsiz;
result = XP_TRUE;
}
- (*env)->DeleteLocalRef( env, jstr );
+ deleteLocalRef( env, jstr );
}
UTIL_CBK_TAIL();
@@ -253,10 +250,7 @@ and_util_informMove( XW_UtilCtxt* uc, XWStreamCtxt* expl, XWStreamCtxt* words )
jstring jexpl = streamToJString( env, expl );
jstring jwords = !!words ? streamToJString( env, words ) : NULL;
(*env)->CallVoidMethod( env, util->jutil, mid, jexpl, jwords );
- (*env)->DeleteLocalRef( env, jexpl );
- if ( !!jwords ) {
- (*env)->DeleteLocalRef( env, jwords );
- }
+ deleteLocalRefs( env, jexpl, jwords, DELETE_NO_REF );
UTIL_CBK_TAIL();
}
@@ -391,7 +385,7 @@ and_util_getUserString( XW_UtilCtxt* uc, XP_U16 stringCode )
XP_MEMCPY( buf, jchars, len );
buf[len] = '\0';
(*env)->ReleaseStringUTFChars( env, jresult, jchars );
- (*env)->DeleteLocalRef( env, jresult );
+ deleteLocalRef( env, jresult );
util->userStrings[index] = buf;
}
@@ -413,7 +407,7 @@ and_util_warnIllegalWord( XW_UtilCtxt* uc, BadWordInfo* bwi,
(const XP_UCHAR**)bwi->words );
result = (*env)->CallBooleanMethod( env, util->jutil, mid,
jwords, turn, turnLost );
- (*env)->DeleteLocalRef( env, jwords );
+ deleteLocalRef( env, jwords );
}
UTIL_CBK_TAIL();
return result;
@@ -425,7 +419,7 @@ and_util_showChat( XW_UtilCtxt* uc, const XP_UCHAR const* msg )
UTIL_CBK_HEADER("showChat", "(Ljava/lang/String;)V" );
jstring jmsg = (*env)->NewStringUTF( env, msg );
(*env)->CallVoidMethod( env, util->jutil, mid, jmsg );
- (*env)->DeleteLocalRef( env, jmsg );
+ deleteLocalRef( env, jmsg );
UTIL_CBK_TAIL();
}
@@ -467,8 +461,7 @@ and_util_phoneNumbersSame( XW_UtilCtxt* uc, const XP_UCHAR* p1,
jstring js1 = (*env)->NewStringUTF( env, p1 );
jstring js2 = (*env)->NewStringUTF( env, p2 );
same = (*env)->CallBooleanMethod( env, util->jutil, mid, js1, js2 );
- (*env)->DeleteLocalRef( env, js1 );
- (*env)->DeleteLocalRef( env, js2 );
+ deleteLocalRefs( env, js1, js2, DELETE_NO_REF );
UTIL_CBK_TAIL();
}
return same;
@@ -483,7 +476,7 @@ and_util_cellSquareHeld( XW_UtilCtxt* uc, XWStreamCtxt* words )
UTIL_CBK_HEADER( "cellSquareHeld", "(Ljava/lang/String;)V" );
jstring jwords = streamToJString( env, words );
(*env)->CallVoidMethod( env, util->jutil, mid, jwords );
- (*env)->DeleteLocalRef( env, jwords );
+ deleteLocalRef( env, jwords );
UTIL_CBK_TAIL();
}
}
@@ -500,7 +493,7 @@ and_util_informMissing(XW_UtilCtxt* uc, XP_Bool isServer,
jobject jtyp = intToJEnum( env, connType,
PKG_PATH("jni/CommsAddrRec$CommsConnType") );
(*env)->CallVoidMethod( env, util->jutil, mid, isServer, jtyp, nMissing );
- (*env)->DeleteLocalRef( env, jtyp );
+ deleteLocalRef( env, jtyp );
UTIL_CBK_TAIL();
}
diff --git a/xwords4/android/XWords4/jni/xportwrapper.c b/xwords4/android/XWords4/jni/xportwrapper.c
index 76d7fa451..d18f04492 100644
--- a/xwords4/android/XWords4/jni/xportwrapper.c
+++ b/xwords4/android/XWords4/jni/xportwrapper.c
@@ -45,7 +45,7 @@ makeJAddr( JNIEnv* env, const CommsAddrRec* addr )
setJAddrRec( env, jaddr, addr );
- (*env)->DeleteLocalRef( env, clazz );
+ deleteLocalRef( env, clazz );
}
return jaddr;
}
@@ -82,11 +82,7 @@ and_xport_send( const XP_U8* buf, XP_U16 len, const CommsAddrRec* addr,
result = (*env)->CallIntMethod( env, aprocs->jxport, mid,
jbytes, jaddr, gameID );
-
- if ( NULL != jaddr ) {
- (*env)->DeleteLocalRef( env, jaddr );
- }
- (*env)->DeleteLocalRef( env, jbytes );
+ deleteLocalRefs( env, jaddr, jbytes, DELETE_NO_REF );
}
LOG_RETURNF( "%d", result );
return result;
@@ -105,7 +101,7 @@ and_xport_relayStatus( void* closure, CommsRelayState newState )
jobject jenum = intToJEnum( env, newState,
PKG_PATH("jni/TransportProcs$CommsRelayState") );
(*env)->CallVoidMethod( env, aprocs->jxport, mid, jenum );
- (*env)->DeleteLocalRef( env, jenum );
+ deleteLocalRef( env, jenum );
}
}
@@ -122,7 +118,7 @@ and_xport_relayConnd( void* closure, XP_UCHAR* const room, XP_Bool reconnect,
jstring str = (*env)->NewStringUTF( env, room );
(*env)->CallVoidMethod( env, aprocs->jxport, mid,
str, devOrder, allHere, nMissing );
- (*env)->DeleteLocalRef( env, str );
+ deleteLocalRef( env, str );
}
}
@@ -142,8 +138,7 @@ and_xport_sendNoConn( const XP_U8* buf, XP_U16 len,
jstring str = (*env)->NewStringUTF( env, relayID );
result = (*env)->CallBooleanMethod( env, aprocs->jxport, mid,
jbytes, str );
- (*env)->DeleteLocalRef( env, jbytes );
- (*env)->DeleteLocalRef( env, str );
+ deleteLocalRefs( env, jbytes, str, DELETE_NO_REF );
}
return result;
}
@@ -163,7 +158,7 @@ and_xport_relayError( void* closure, XWREASON relayErr )
PKG_PATH("jni/TransportProcs$XWRELAY_ERROR") );
(*env)->CallVoidMethod( env, aprocs->jxport, mid, jenum );
- (*env)->DeleteLocalRef( env, jenum );
+ deleteLocalRef( env, jenum );
}
}
diff --git a/xwords4/android/XWords4/jni/xwjni.c b/xwords4/android/XWords4/jni/xwjni.c
index d7d7998d3..0159f4c6f 100644
--- a/xwords4/android/XWords4/jni/xwjni.c
+++ b/xwords4/android/XWords4/jni/xwjni.c
@@ -100,9 +100,9 @@ makeGI( MPFORMAL JNIEnv* env, jobject j_gi )
lp->secondsUsed = 0;
- (*env)->DeleteLocalRef( env, jlp );
+ deleteLocalRef( env, jlp );
}
- (*env)->DeleteLocalRef( env, jplayers );
+ deleteLocalRef( env, jplayers );
} else {
XP_ASSERT(0);
}
@@ -147,9 +147,9 @@ setJGI( JNIEnv* env, jobject jgi, const CurGameInfo* gi )
setString( env, jlp, "dictName", lp->dictName );
setInt( env, jlp, "secondsUsed", lp->secondsUsed );
- (*env)->DeleteLocalRef( env, jlp );
+ deleteLocalRef( env, jlp );
}
- (*env)->DeleteLocalRef( env, jplayers );
+ deleteLocalRef( env, jplayers );
} else {
XP_ASSERT(0);
}
@@ -1052,9 +1052,9 @@ Java_org_eehouse_android_xw4_jni_XwJNI_comms_1getAddrs
jobject jaddr = (*env)->NewObject( env, clas, initId );
setJAddrRec( env, jaddr, &addrs[ii] );
(*env)->SetObjectArrayElement( env, result, ii, jaddr );
- (*env)->DeleteLocalRef( env, jaddr );
+ deleteLocalRef( env, jaddr );
}
- (*env)->DeleteLocalRef( env, clas );
+ deleteLocalRef( env, clas );
XWJNI_END();
return result;
@@ -1162,7 +1162,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1summarize
jobjectArray jaddrs = makeStringArray( env, count, addrps );
setObject( env, jsummary, "remoteDevs", "[Ljava/lang/String;",
jaddrs );
- (*env)->DeleteLocalRef( env, jaddrs );
+ deleteLocalRef( env, jaddrs );
#endif
}
}
@@ -1183,7 +1183,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1summarize
}
jintArray jarr = makeIntArray( env, nPlayers, jvals );
setObject( env, jsummary, "scores", "[I", jarr );
- (*env)->DeleteLocalRef( env, jarr );
+ deleteLocalRef( env, jarr );
XWJNI_END();
}
@@ -1538,7 +1538,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_dict_1iter_1getPrefixes
depth, buf, VSIZE(buf) );
jstring jstr = (*env)->NewStringUTF( env, buf );
(*env)->SetObjectArrayElement( env, result, ii, jstr );
- (*env)->DeleteLocalRef( env, jstr );
+ deleteLocalRef( env, jstr );
}
}
return result;
From a939c9ec4b4b109779adf8f45fdd49de964ac8a3 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sat, 15 Sep 2012 17:11:45 -0700
Subject: [PATCH 32/44] cleanup
---
.../XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java | 1 -
1 file changed, 1 deletion(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java
index 6720079f3..fc9ab2444 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIUtilsImpl.java
@@ -93,7 +93,6 @@ public class JNIUtilsImpl implements JNIUtils {
public String getMD5SumFor( String dictName, byte[] bytes )
{
- DbgUtils.logf( "dictName(%H)", bytes );
String result = null;
if ( null == bytes ) {
result = DBUtils.dictsGetMD5Sum( m_context, dictName );
From 33772ff0b9bfef77ea75ea4d1e46abfd61dafb22 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Sat, 15 Sep 2012 17:11:59 -0700
Subject: [PATCH 33/44] remove redundant DB field and variable
---
.../android/XWords4/src/org/eehouse/android/xw4/DBHelper.java | 1 -
.../android/XWords4/src/org/eehouse/android/xw4/DBUtils.java | 4 ----
.../src/org/eehouse/android/xw4/DictBrowseActivity.java | 2 --
3 files changed, 7 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java
index 26e570c4d..05e50ab2e 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java
@@ -149,7 +149,6 @@ public class DBHelper extends SQLiteOpenHelper {
db.execSQL( "CREATE TABLE " + TABLE_NAME_DICTBROWSE + " ("
+ DICTNAME + " TEXT,"
- + WORDCOUNT + " INTEGER,"
+ WORDCOUNTS + " TEXT,"
+ ITERMIN + " INTEGER(4),"
+ ITERMAX + " INTEGER(4),"
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
index 52a024977..64c2b0d39 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
@@ -91,7 +91,6 @@ public class DBUtils {
public int m_pos;
public int m_top;
public String m_prefix;
- public int m_count;
public int[] m_counts;
}
@@ -981,8 +980,6 @@ public class DBUtils {
result.m_prefix =
cursor.getString( cursor
.getColumnIndex(DBHelper.ITERPREFIX));
- result.m_count =
- cursor.getInt( cursor.getColumnIndex(DBHelper.WORDCOUNT));
String counts =
cursor.getString( cursor.getColumnIndex(DBHelper.WORDCOUNTS));
if ( null != counts ) {
@@ -1013,7 +1010,6 @@ public class DBUtils {
values.put( DBHelper.ITERMIN, state.m_minShown );
values.put( DBHelper.ITERMAX, state.m_maxShown );
values.put( DBHelper.ITERPREFIX, state.m_prefix );
- values.put( DBHelper.WORDCOUNT, state.m_count );
if ( null != state.m_counts ) {
String[] nums = new String[state.m_counts.length];
for ( int ii = 0; ii < nums.length; ++ii ) {
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java
index 116283703..77612120c 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java
@@ -174,8 +174,6 @@ public class DictBrowseActivity extends XWListActivity
m_browseState = new DBUtils.DictBrowseState();
m_browseState.m_pos = 0;
m_browseState.m_top = 0;
- m_browseState.m_count =
- XwJNI.dict_iter_wordCount( m_dictClosure );
}
if ( null == m_browseState.m_counts ) {
m_browseState.m_counts =
From 168b69112e4eead51bb13206f73bcdecd37d1275 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 17 Sep 2012 06:36:58 -0700
Subject: [PATCH 34/44] up version strings for pending new release
---
xwords4/android/XWords4/AndroidManifest.xml | 2 +-
xwords4/android/XWords4/res/raw/changes | 11 +++++++++--
xwords4/android/XWords4/res/values/app_name.xml | 2 +-
3 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/xwords4/android/XWords4/AndroidManifest.xml b/xwords4/android/XWords4/AndroidManifest.xml
index 6af4889bd..b1fa22df3 100644
--- a/xwords4/android/XWords4/AndroidManifest.xml
+++ b/xwords4/android/XWords4/AndroidManifest.xml
@@ -22,7 +22,7 @@
to come from a domain that you own or have control over. -->
diff --git a/xwords4/android/XWords4/res/raw/changes b/xwords4/android/XWords4/res/raw/changes
index 5ae3061ee..92eec84f5 100644
--- a/xwords4/android/XWords4/res/raw/changes
+++ b/xwords4/android/XWords4/res/raw/changes
@@ -5,9 +5,16 @@
-Crosswords 4.4 beta 51 release
+Crosswords 4.4 beta 52 release
- - Add auto-update for wordlists and the app itself (when side-loaded)
+ - Remember wordlist browser position, word size, etc.
+
+ - Fix wordlist browser bugs for languages with more than one
+ letter on a tile
+
+ - New word lookup URLs for Catalan language lists
+
+ - Display wordlist comment if present
Please remember that this is beta software. Please let me know (at
diff --git a/xwords4/android/XWords4/res/values/app_name.xml b/xwords4/android/XWords4/res/values/app_name.xml
index caffa71f3..660145822 100644
--- a/xwords4/android/XWords4/res/values/app_name.xml
+++ b/xwords4/android/XWords4/res/values/app_name.xml
@@ -1,5 +1,5 @@
- 4.4 beta 51
+ 4.4 beta 52
From 4fa5c61e143ebd20731084d7ed31c5f02840f4d3 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 17 Sep 2012 06:48:53 -0700
Subject: [PATCH 35/44] add option to build in a separate directory, for e.g.
case where source files are on ro filesystem.
---
xwords4/common/config.mk | 4 ++--
xwords4/linux/Makefile | 6 ++++--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/xwords4/common/config.mk b/xwords4/common/config.mk
index e4bf1cdd7..5c8ee2105 100644
--- a/xwords4/common/config.mk
+++ b/xwords4/common/config.mk
@@ -16,11 +16,11 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-COMMON_INCS = -I ./$(PLATFORM) -I../common -I../relay
+COMMON_INCS = -I ../common -I../relay
INCLUDES += $(COMMON_INCS) -I./
COMMONDIR ?= ../common
-COMMONOBJDIR = ../common/$(PLATFORM)
+COMMONOBJDIR = $(PLATFORM)/common
COMMONSRC = \
$(COMMONDIR)/board.c \
diff --git a/xwords4/linux/Makefile b/xwords4/linux/Makefile
index 848914b3b..1e3772ef0 100644
--- a/xwords4/linux/Makefile
+++ b/xwords4/linux/Makefile
@@ -16,15 +16,17 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+BUILD_DIR ?= .
+
ifeq ($(MEMDEBUG),TRUE)
DEFINES = -DMEM_DEBUG -DDEBUG -DENABLE_LOGGING -DNUMBER_KEY_AS_INDEX
DEFINES += -DCOMMS_CHECKSUM
CFLAGS += -g $(GPROFFLAG) -Wall -Wunused-parameter -Wcast-align -Werror -O0
CFLAGS += -DDEBUG_TS -rdynamic
-PLATFORM = obj_linux_memdbg
+PLATFORM = $(BUILD_DIR)/obj_linux_memdbg
else
DEFINES =
-PLATFORM = obj_linux_rel
+PLATFORM = $(BUILD_DIR)/obj_linux_rel
# Not shipping this! Always build with symbols etc
CFLAGS += -g $(GPROFFLAG) -Wall -Wunused-parameter -Wcast-align -Werror -O0
#CFLAGS += -Os -Werror -Wunused
From fcecd1db3cf7fc547db68840cfb4c7cc35c13702 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 18 Sep 2012 06:38:22 -0700
Subject: [PATCH 36/44] don't ask for column no longer there
---
.../android/XWords4/src/org/eehouse/android/xw4/DBUtils.java | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
index 64c2b0d39..340e8a684 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
@@ -960,8 +960,7 @@ public class DBUtils {
SQLiteDatabase db = s_dbHelper.getReadableDatabase();
String[] columns = { DBHelper.ITERPOS, DBHelper.ITERTOP,
DBHelper.ITERMIN, DBHelper.ITERMAX,
- DBHelper.WORDCOUNTS, DBHelper.WORDCOUNT,
- DBHelper.ITERPREFIX };
+ DBHelper.WORDCOUNTS, DBHelper.ITERPREFIX };
String selection = String.format( NAME_FMT, DBHelper.DICTNAME, name );
Cursor cursor = db.query( DBHelper.TABLE_NAME_DICTBROWSE, columns,
selection, null, null, null, null );
From 210913d4d42498dc9fdbe8b095060187946f0617 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 18 Sep 2012 07:36:54 -0700
Subject: [PATCH 37/44] track dictbrowse info for multiple copies of same dict
if that's what's installed.
---
.../src/org/eehouse/android/xw4/DBHelper.java | 19 +++++----
.../src/org/eehouse/android/xw4/DBUtils.java | 42 +++++++++++++++----
.../android/xw4/DictBrowseActivity.java | 24 ++++++++---
.../eehouse/android/xw4/DictsActivity.java | 6 ++-
4 files changed, 68 insertions(+), 23 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java
index 05e50ab2e..4a296872f 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBHelper.java
@@ -133,29 +133,30 @@ public class DBHelper extends SQLiteOpenHelper {
{
db.execSQL( "CREATE TABLE " + TABLE_NAME_OBITS + " ("
+ RELAYID + " TEXT,"
- + SEED + " INTEGER"
- + ");" );
+ + SEED + " INTEGER);"
+ );
}
private void onCreateDictsDB( SQLiteDatabase db )
{
- db.execSQL( "CREATE TABLE " + TABLE_NAME_DICTINFO + " ("
+ db.execSQL( "CREATE TABLE " + TABLE_NAME_DICTINFO + "("
+ DICTNAME + " TEXT,"
+ + LOC + " UNSIGNED INTEGER(1),"
+ MD5SUM + " TEXT(32),"
+ WORDCOUNT + " INTEGER,"
- + LANGCODE + " INTEGER,"
- + LOC + " INTEGER(2)"
- + ");" );
+ + LANGCODE + " INTEGER);"
+ );
- db.execSQL( "CREATE TABLE " + TABLE_NAME_DICTBROWSE + " ("
+ db.execSQL( "CREATE TABLE " + TABLE_NAME_DICTBROWSE + "("
+ DICTNAME + " TEXT,"
+ + LOC + " UNSIGNED INTEGER(1),"
+ WORDCOUNTS + " TEXT,"
+ ITERMIN + " INTEGER(4),"
+ ITERMAX + " INTEGER(4),"
+ ITERPOS + " INTEGER,"
+ ITERTOP + " INTEGER,"
- + ITERPREFIX + " TEXT"
- + ");" );
+ + ITERPREFIX + " TEXT);"
+ );
}
@Override
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
index 340e8a684..477a679ab 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
@@ -45,6 +45,7 @@ import java.util.StringTokenizer;
import junit.framework.Assert;
import org.eehouse.android.xw4.jni.*;
+import org.eehouse.android.xw4.DictUtils.DictLoc;
public class DBUtils {
@@ -55,6 +56,7 @@ public class DBUtils {
private static final String ROW_ID = "rowid";
private static final String ROW_ID_FMT = "rowid=%d";
private static final String NAME_FMT = "%s='%s'";
+ private static final String NAMELOC_FMT = "%s='%s' AND %s=%d";
private static long s_cachedRowID = -1;
private static byte[] s_cachedBytes = null;
@@ -951,9 +953,10 @@ public class DBUtils {
/////////////////////////////////////////////////////////////////
// DictsDB stuff
/////////////////////////////////////////////////////////////////
- public static DictBrowseState dictsGetOffset( Context context,
- String name )
+ public static DictBrowseState dictsGetOffset( Context context, String name,
+ DictLoc loc )
{
+ Assert.assertTrue( DictLoc.UNKNOWN != loc );
DictBrowseState result = null;
initDB( context );
synchronized( s_dbHelper ) {
@@ -961,10 +964,12 @@ public class DBUtils {
String[] columns = { DBHelper.ITERPOS, DBHelper.ITERTOP,
DBHelper.ITERMIN, DBHelper.ITERMAX,
DBHelper.WORDCOUNTS, DBHelper.ITERPREFIX };
- String selection = String.format( NAME_FMT, DBHelper.DICTNAME, name );
+ String selection =
+ String.format( NAMELOC_FMT, DBHelper.DICTNAME,
+ name, DBHelper.LOC, loc.ordinal() );
Cursor cursor = db.query( DBHelper.TABLE_NAME_DICTBROWSE, columns,
selection, null, null, null, null );
- if ( 1 == cursor.getCount() && cursor.moveToFirst() ) {
+ if ( 1 >= cursor.getCount() && cursor.moveToFirst() ) {
result = new DictBrowseState();
result.m_pos = cursor.getInt( cursor
.getColumnIndex(DBHelper.ITERPOS));
@@ -997,12 +1002,15 @@ public class DBUtils {
}
public static void dictsSetOffset( Context context, String name,
- DictBrowseState state )
+ DictLoc loc, DictBrowseState state )
{
+ Assert.assertTrue( DictLoc.UNKNOWN != loc );
initDB( context );
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getWritableDatabase();
- String selection = String.format( NAME_FMT, DBHelper.DICTNAME, name );
+ String selection =
+ String.format( NAMELOC_FMT, DBHelper.DICTNAME,
+ name, DBHelper.LOC, loc.ordinal() );
ContentValues values = new ContentValues();
values.put( DBHelper.ITERPOS, state.m_pos );
values.put( DBHelper.ITERTOP, state.m_top );
@@ -1020,6 +1028,7 @@ public class DBUtils {
values, selection, null );
if ( 0 == result ) {
values.put( DBHelper.DICTNAME, name );
+ values.put( DBHelper.LOC, loc.ordinal() );
db.insert( DBHelper.TABLE_NAME_DICTBROWSE, null, values );
}
db.close();
@@ -1105,6 +1114,23 @@ public class DBUtils {
}
}
+ public static void dictsMoveInfo( Context context, String name,
+ DictLoc fromLoc, DictLoc toLoc )
+ {
+ initDB( context );
+ synchronized( s_dbHelper ) {
+ SQLiteDatabase db = s_dbHelper.getWritableDatabase();
+ String selection =
+ String.format( NAMELOC_FMT, DBHelper.DICTNAME,
+ name, DBHelper.LOC, fromLoc.ordinal() );
+ ContentValues values = new ContentValues();
+ values.put( DBHelper.LOC, toLoc.ordinal() );
+ db.update( DBHelper.TABLE_NAME_DICTINFO, values, selection, null );
+ db.update( DBHelper.TABLE_NAME_DICTBROWSE, values, selection, null);
+ db.close();
+ }
+ }
+
public static void dictsRemoveInfo( Context context,
DictUtils.DictAndLoc dal )
{
@@ -1112,8 +1138,10 @@ public class DBUtils {
synchronized( s_dbHelper ) {
SQLiteDatabase db = s_dbHelper.getWritableDatabase();
String selection =
- String.format( NAME_FMT, DBHelper.DICTNAME, dal.name );
+ String.format( NAMELOC_FMT, DBHelper.DICTNAME,
+ dal.name, DBHelper.LOC, dal.loc.ordinal() );
db.delete( DBHelper.TABLE_NAME_DICTINFO, selection, null );
+ db.delete( DBHelper.TABLE_NAME_DICTBROWSE, selection, null );
db.close();
}
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java
index 77612120c..e81121f71 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java
@@ -48,7 +48,8 @@ import org.eehouse.android.xw4.jni.XwJNI;
public class DictBrowseActivity extends XWListActivity
implements View.OnClickListener, OnItemSelectedListener {
- public static final String DICT_NAME = "DICT_NAME";
+ private static final String DICT_NAME = "DICT_NAME";
+ private static final String DICT_LOC = "DICT_LOC";
private static final int MIN_LEN = 2;
private static final int FINISH_ACTION = 1;
@@ -56,6 +57,7 @@ public class DictBrowseActivity extends XWListActivity
private int m_dictClosure = 0;
private int m_lang;
private String m_name;
+ private DictUtils.DictLoc m_loc;
private Spinner m_minSpinner;
private Spinner m_maxSpinner;
private DBUtils.DictBrowseState m_browseState;
@@ -160,6 +162,8 @@ public class DictBrowseActivity extends XWListActivity
finish();
} else {
m_name = name;
+ m_loc =
+ DictUtils.DictLoc.values()[intent.getIntExtra( DICT_LOC, 0 )];
m_lang = DictLangCache.getDictLangCode( this, name );
String[] names = { name };
@@ -168,7 +172,7 @@ public class DictBrowseActivity extends XWListActivity
name, pairs.m_paths[0],
JNIUtilsImpl.get(this) );
- m_browseState = DBUtils.dictsGetOffset( this, name );
+ m_browseState = DBUtils.dictsGetOffset( this, name, m_loc );
boolean newState = null == m_browseState;
if ( newState ) {
m_browseState = new DBUtils.DictBrowseState();
@@ -223,7 +227,7 @@ public class DictBrowseActivity extends XWListActivity
m_browseState.m_pos = list.getFirstVisiblePosition();
View view = list.getChildAt( 0 );
m_browseState.m_top = (view == null) ? 0 : view.getTop();
- DBUtils.dictsSetOffset( this, m_name, m_browseState );
+ DBUtils.dictsSetOffset( this, m_name, m_loc, m_browseState );
m_browseState = null;
}
@@ -235,7 +239,7 @@ public class DictBrowseActivity extends XWListActivity
{
super.onResume();
if ( null == m_browseState ) {
- m_browseState = DBUtils.dictsGetOffset( this, m_name );
+ m_browseState = DBUtils.dictsGetOffset( this, m_name, m_loc );
}
showPrefix( true );
}
@@ -345,7 +349,7 @@ public class DictBrowseActivity extends XWListActivity
m_browseState.m_top = 0;
m_browseState.m_minShown = min;
m_browseState.m_maxShown = max;
- DBUtils.dictsSetOffset( this, m_name, m_browseState );
+ DBUtils.dictsSetOffset( this, m_name, m_loc, m_browseState );
m_browseState = null;
startActivity( getIntent() );
@@ -407,10 +411,18 @@ public class DictBrowseActivity extends XWListActivity
}
- public static void launch( Context caller, String name )
+ public static void launch( Context caller, String name,
+ DictUtils.DictLoc loc )
{
Intent intent = new Intent( caller, DictBrowseActivity.class );
intent.putExtra( DICT_NAME, name );
+ intent.putExtra( DICT_LOC, loc.ordinal() );
caller.startActivity( intent );
}
+
+ public static void launch( Context caller, String name )
+ {
+ DictUtils.DictLoc loc = DictUtils.getDictLoc( caller, name );
+ launch( caller, name, loc );
+ }
}
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java
index 9680b8737..f5a3f0f7c 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java
@@ -306,6 +306,9 @@ public class DictsActivity extends ExpandableListActivity
rowView.setComment( m_locNames[toLoc.ordinal()] );
rowView.cache( toLoc );
rowView.invalidate();
+ DBUtils.dictsMoveInfo( DictsActivity.this,
+ rowView.getText(),
+ m_moveFromLoc, toLoc );
} else {
DbgUtils.logf( "moveDict(%s) failed",
rowView.getText() );
@@ -473,7 +476,8 @@ public class DictsActivity extends ExpandableListActivity
askStartDownload( 0, null );
} else {
XWListItem item = (XWListItem)view;
- DictBrowseActivity.launch( this, item.getText() );
+ DictBrowseActivity.launch( this, item.getText(),
+ (DictUtils.DictLoc)item.getCached() );
}
}
From a601d0818ee7e0e4bf7f894d6c48aed75c885dd5 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Tue, 18 Sep 2012 07:51:50 -0700
Subject: [PATCH 38/44] save and restore search prefix even when find button
not clicked, and display last scroll position when different from what prefix
finds.
---
.../android/xw4/DictBrowseActivity.java | 28 ++++++++++++-------
1 file changed, 18 insertions(+), 10 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java
index e81121f71..8ede3dbd3 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictBrowseActivity.java
@@ -227,6 +227,7 @@ public class DictBrowseActivity extends XWListActivity
m_browseState.m_pos = list.getFirstVisiblePosition();
View view = list.getChildAt( 0 );
m_browseState.m_top = (view == null) ? 0 : view.getTop();
+ m_browseState.m_prefix = getFindText();
DBUtils.dictsSetOffset( this, m_name, m_loc, m_browseState );
m_browseState = null;
}
@@ -241,7 +242,7 @@ public class DictBrowseActivity extends XWListActivity
if ( null == m_browseState ) {
m_browseState = DBUtils.dictsGetOffset( this, m_name, m_loc );
}
- showPrefix( true );
+ setFindText( m_browseState.m_prefix );
}
@Override
@@ -308,23 +309,29 @@ public class DictBrowseActivity extends XWListActivity
private void findButtonClicked()
{
- EditText edit = (EditText)findViewById( R.id.word_edit );
- String text = edit.getText().toString();
+ String text = getFindText();
if ( null != text && 0 < text.length() ) {
m_browseState.m_prefix = text;
- showPrefix( false );
+ showPrefix();
}
}
- private void showPrefix( boolean fillField )
+ private String getFindText()
+ {
+ EditText edit = (EditText)findViewById( R.id.word_edit );
+ return edit.getText().toString();
+ }
+
+ private void setFindText( String text )
+ {
+ EditText edit = (EditText)findViewById( R.id.word_edit );
+ edit.setText( text );
+ }
+
+ private void showPrefix()
{
String text = m_browseState.m_prefix;
if ( null != text && 0 < text.length() ) {
- if ( fillField ) {
- EditText edit = (EditText)findViewById( R.id.word_edit );
- edit.setText( text );
- }
-
int pos = XwJNI.dict_iter_getStartsWith( m_dictClosure, text );
if ( 0 <= pos ) {
getListView().setSelection( pos );
@@ -349,6 +356,7 @@ public class DictBrowseActivity extends XWListActivity
m_browseState.m_top = 0;
m_browseState.m_minShown = min;
m_browseState.m_maxShown = max;
+ m_browseState.m_prefix = getFindText();
DBUtils.dictsSetOffset( this, m_name, m_loc, m_browseState );
m_browseState = null;
From 81d3f7d15f2e65045e7c9ef318c4d87a1680824a Mon Sep 17 00:00:00 2001
From: Eric House
Date: Wed, 19 Sep 2012 07:20:43 -0700
Subject: [PATCH 39/44] up version strings for SMS version too
---
xwords4/android/XWords4-sms/AndroidManifest.xml | 2 +-
xwords4/android/XWords4-sms/res/raw/changes | 9 ++++++++-
xwords4/android/XWords4-sms/res/values/app_name.xml | 2 +-
3 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/xwords4/android/XWords4-sms/AndroidManifest.xml b/xwords4/android/XWords4-sms/AndroidManifest.xml
index 790f67808..de71c5fe2 100644
--- a/xwords4/android/XWords4-sms/AndroidManifest.xml
+++ b/xwords4/android/XWords4-sms/AndroidManifest.xml
@@ -22,7 +22,7 @@
to come from a domain that you own or have control over. -->
diff --git a/xwords4/android/XWords4-sms/res/raw/changes b/xwords4/android/XWords4-sms/res/raw/changes
index 51915056b..654ab005d 100644
--- a/xwords4/android/XWords4-sms/res/raw/changes
+++ b/xwords4/android/XWords4-sms/res/raw/changes
@@ -13,7 +13,14 @@ ability to play via SMS
Other changes
- - Add auto-update for wordlists and the app itself (when side-loaded)
+ - Remember wordlist browser position, word size, etc.
+
+ - Fix wordlist browser bugs for languages with more than one
+ letter on a tile
+
+ - New word lookup URLs for Catalan language lists
+
+ - Display wordlist comment if present
diff --git a/xwords4/android/XWords4-sms/res/values/app_name.xml b/xwords4/android/XWords4-sms/res/values/app_name.xml
index caffa71f3..660145822 100644
--- a/xwords4/android/XWords4-sms/res/values/app_name.xml
+++ b/xwords4/android/XWords4-sms/res/values/app_name.xml
@@ -1,5 +1,5 @@
- 4.4 beta 51
+ 4.4 beta 52
From 598a15469343a6f7b490a2cc69b424a1bf30d8f6 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Wed, 19 Sep 2012 08:09:27 -0700
Subject: [PATCH 40/44] factor common code into function
---
xwords4/android/XWords4/jni/andutils.c | 11 +++++++++++
xwords4/android/XWords4/jni/andutils.h | 1 +
xwords4/android/XWords4/jni/xwjni.c | 19 ++++---------------
3 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/xwords4/android/XWords4/jni/andutils.c b/xwords4/android/XWords4/jni/andutils.c
index 5259a7c55..f0f3283d5 100644
--- a/xwords4/android/XWords4/jni/andutils.c
+++ b/xwords4/android/XWords4/jni/andutils.c
@@ -238,6 +238,17 @@ makeByteArray( JNIEnv *env, int siz, const jbyte* vals )
return array;
}
+jbyteArray
+streamToBArray( JNIEnv *env, XWStreamCtxt* stream )
+{
+ int nBytes = stream_getSize( stream );
+ jbyteArray result = (*env)->NewByteArray( env, nBytes );
+ jbyte* jelems = (*env)->GetByteArrayElements( env, result, NULL );
+ stream_getBytes( stream, jelems, nBytes );
+ (*env)->ReleaseByteArrayElements( env, result, jelems, 0 );
+ return result;
+}
+
void
setBoolArray( JNIEnv* env, jbooleanArray jarr, int count,
const jboolean* vals )
diff --git a/xwords4/android/XWords4/jni/andutils.h b/xwords4/android/XWords4/jni/andutils.h
index 029f7cf31..bda6aa314 100644
--- a/xwords4/android/XWords4/jni/andutils.h
+++ b/xwords4/android/XWords4/jni/andutils.h
@@ -57,6 +57,7 @@ void setBoolArray( JNIEnv* env, jbooleanArray jarr, int count,
jobjectArray makeStringArray( JNIEnv *env, int size, const XP_UCHAR** vals );
jstring streamToJString( JNIEnv* env, XWStreamCtxt* stream );
+jbyteArray streamToBArray( JNIEnv *env, XWStreamCtxt* stream );
/* Note: jmethodID can be cached. Should not look up more than once. */
jmethodID getMethodID( JNIEnv* env, jobject obj, const char* proc,
diff --git a/xwords4/android/XWords4/jni/xwjni.c b/xwords4/android/XWords4/jni/xwjni.c
index 2ff200356..8903e8d44 100644
--- a/xwords4/android/XWords4/jni/xwjni.c
+++ b/xwords4/android/XWords4/jni/xwjni.c
@@ -214,11 +214,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_gi_1to_1stream
game_saveToStream( NULL, gi, stream, 0 );
destroyGI( MPPARM(mpool) &gi );
- int nBytes = stream_getSize( stream );
- result = (*env)->NewByteArray( env, nBytes );
- jbyte* jelems = (*env)->GetByteArrayElements( env, result, NULL );
- stream_getBytes( stream, jelems, nBytes );
- (*env)->ReleaseByteArrayElements( env, result, jelems, 0 );
+ result = streamToBArray( env, stream );
stream_destroy( stream );
vtmgr_destroy( MPPARM(mpool) vtMgr );
@@ -545,13 +541,9 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1saveToStream
destroyGI( MPPARM(mpool) &gi );
}
- int nBytes = stream_getSize( stream );
- result = (*env)->NewByteArray( env, nBytes );
- jbyte* jelems = (*env)->GetByteArrayElements( env, result, NULL );
- stream_getBytes( stream, jelems, nBytes );
- (*env)->ReleaseByteArrayElements( env, result, jelems, 0 );
+ state->lastSavedSize = stream_getSize( stream );
+ result = streamToBArray( env, stream );
stream_destroy( stream );
- state->lastSavedSize = nBytes;
XWJNI_END();
return result;
@@ -1636,10 +1628,7 @@ Java_org_eehouse_android_xw4_jni_XwJNI_base64Decode
XP_U8 out[inlen];
XP_U16 outlen = VSIZE(out);
if ( smsToBin( out, &outlen, instr, inlen ) ) {
- result = (*env)->NewByteArray( env, outlen );
- jbyte* jelems = (*env)->GetByteArrayElements( env, result, NULL );
- XP_MEMCPY( jelems, out, outlen );
- (*env)->ReleaseByteArrayElements( env, result, jelems, 0 );
+ result = makeByteArray( env, outlen, (jbyte*)out );
} else {
XP_ASSERT(0);
}
From 96e277c7ba7aae0cb216be5d5ec210ba7523b073 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Thu, 20 Sep 2012 07:29:00 -0700
Subject: [PATCH 41/44] don't offer to copy DB from sdcard when there is none.
---
.../XWords4/src/org/eehouse/android/xw4/DBUtils.java | 8 ++++++++
.../XWords4/src/org/eehouse/android/xw4/GamesList.java | 6 ++++++
2 files changed, 14 insertions(+)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
index 477a679ab..a036cc9e4 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DBUtils.java
@@ -1146,6 +1146,14 @@ public class DBUtils {
}
}
+ public static boolean gameDBExists( Context context )
+ {
+ String name = DBHelper.getDBName();
+ File sdcardDB = new File( Environment.getExternalStorageDirectory(),
+ name );
+ return sdcardDB.exists();
+ }
+
private static void copyGameDB( Context context, boolean toSDCard )
{
String name = DBHelper.getDBName();
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
index 2d8f3b2ec..93eca3af1 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java
@@ -545,6 +545,12 @@ public class GamesList extends XWListActivity
MenuItem item = menu.findItem( id );
item.setVisible( visible );
}
+
+ if ( visible && !DBUtils.gameDBExists( this ) ) {
+ MenuItem item = menu.findItem( R.id.gamel_menu_loaddb );
+ item.setVisible( false );
+ }
+
return super.onPrepareOptionsMenu( menu );
}
From c76c5f5868335953c2bdc01507e72b3a53bb468b Mon Sep 17 00:00:00 2001
From: Eric House
Date: Thu, 20 Sep 2012 07:45:04 -0700
Subject: [PATCH 42/44] don't create obits for apps that don't have relayIDs
(and presumably never connected.)
---
.../XWords4/src/org/eehouse/android/xw4/GameUtils.java | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
index 25ac8f8bb..15866b626 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java
@@ -887,9 +887,11 @@ public class GameUtils {
private static void tellRelayDied( Context context, GameSummary summary,
boolean informNow )
{
- DBUtils.addDeceased( context, summary.relayID, summary.seed );
- if ( informNow ) {
- NetUtils.informOfDeaths( context );
+ if ( null != summary.relayID ) {
+ DBUtils.addDeceased( context, summary.relayID, summary.seed );
+ if ( informNow ) {
+ NetUtils.informOfDeaths( context );
+ }
}
}
From d24f9a28f63cbb8d33dcbde82fd037653ed04751 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 24 Sep 2012 07:00:18 -0700
Subject: [PATCH 43/44] up release number
---
xwords4/android/XWords4-sms/res/raw/changes | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/xwords4/android/XWords4-sms/res/raw/changes b/xwords4/android/XWords4-sms/res/raw/changes
index 654ab005d..3a7181f47 100644
--- a/xwords4/android/XWords4-sms/res/raw/changes
+++ b/xwords4/android/XWords4-sms/res/raw/changes
@@ -6,7 +6,7 @@
-CrossW-SMS 4.4 beta 51 release
+CrossW-SMS 4.4 beta 52 release
This is first release of this variant of Crosswords featuring the
ability to play via SMS
@@ -21,7 +21,6 @@ ability to play via SMS
New word lookup URLs for Catalan language lists
Display wordlist comment if present
-
Please remember that this is beta software. Please let me know (at
From 4909dde6221ffe52a4146b55c3731737b95dd5d8 Mon Sep 17 00:00:00 2001
From: Eric House
Date: Mon, 24 Sep 2012 07:35:14 -0700
Subject: [PATCH 44/44] call a script rather than an html file so file doesn't
have to be updated with every release.
---
.../android/XWords4/src/org/eehouse/android/xw4/SMSService.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java
index 3e8a2e3ee..8a9e1c854 100644
--- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java
+++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java
@@ -53,7 +53,7 @@ import org.eehouse.android.xw4.jni.XwJNI;
public class SMSService extends Service {
- private static final String INSTALL_URL = "http://eehouse.org/_/aa.htm ";
+ private static final String INSTALL_URL = "http://eehouse.org/_/a.py/a ";
private static final int MAX_SMS_LEN = 140; // ??? differs by network
private static final String MSG_SENT = "MSG_SENT";