diff --git a/xwords4/common/memstream.c b/xwords4/common/memstream.c index a6f07d04b..2413ed4eb 100644 --- a/xwords4/common/memstream.c +++ b/xwords4/common/memstream.c @@ -212,6 +212,20 @@ mem_stream_getBits( XWStreamCtxt* p_sctx, XP_U16 nBits ) return result; } /* stream_getBits */ +static XP_U32 +mem_stream_getU32VL( XWStreamCtxt* p_sctx ) +{ + XP_U32 result = 0; + for ( int ii = 0; ; ++ii ) { + XP_U8 byt = mem_stream_getBits( p_sctx, 8 * sizeof(byt) ); + result |= (byt & 0x7F) << (7 * ii); + if ( 0 == (byt & 0x80) ) { + break; + } + } + return result; +} /* mem_stream_getU32VL */ + #if defined DEBUG static void mem_stream_copyBits( const XWStreamCtxt* p_sctx, XWStreamPos endPos, @@ -235,7 +249,6 @@ mem_stream_putBytes( XWStreamCtxt* p_sctx, const void* whence, XP_U16 count ) { MemStreamCtxt* stream = (MemStreamCtxt*)p_sctx; - XP_U32 newSize; if ( !stream->buf ) { XP_ASSERT( stream->nBytesAllocated == 0 ); @@ -255,7 +268,7 @@ mem_stream_putBytes( XWStreamCtxt* p_sctx, const void* whence, the new size is bigger than what we have, and if so expand to hold it plus something. */ - newSize = stream->nBytesWritten + count; + XP_U32 newSize = stream->nBytesWritten + count; if ( stream->curWritePos < stream->nBytesWritten ) { newSize -= stream->nBytesWritten - stream->curWritePos; } @@ -352,6 +365,25 @@ mem_stream_putBits( XWStreamCtxt* p_sctx, XP_U16 nBits, XP_U32 data XP_ASSERT( data == 0 ); /* otherwise nBits was too small */ } /* mem_stream_putBits */ +/* Variable-length format: each 7 bits goes in a byte, with the 8th bit + * reserved for signaling whether there's another byte to come. */ +static void +mem_stream_putU32VL( XWStreamCtxt* p_sctx, XP_U32 data ) +{ + for ( ; ; ) { + XP_U8 byt = data & 0x7F; + data >>= 7; + XP_Bool haveMore = 0 != data; + if ( haveMore ) { + byt |= 0x80; + } + stream_putBits( p_sctx, 8 * sizeof(byt), byt ); + if ( !haveMore ) { + break; + } + } +} /* mem_stream_putU32VL */ + static void mem_stream_getFromStream( XWStreamCtxt* p_sctx, XWStreamCtxt* src, XP_U16 nBytes ) @@ -544,6 +576,7 @@ make_vtable( MemStreamCtxt* stream ) SET_VTABLE_ENTRY( vtable, stream_getBytes, mem ); SET_VTABLE_ENTRY( vtable, stream_getU16, mem ); SET_VTABLE_ENTRY( vtable, stream_getU32, mem ); + SET_VTABLE_ENTRY( vtable, stream_getU32VL, mem ); SET_VTABLE_ENTRY( vtable, stream_getBits, mem ); #if defined DEBUG SET_VTABLE_ENTRY( vtable, stream_copyBits, mem ); @@ -554,6 +587,7 @@ make_vtable( MemStreamCtxt* stream ) SET_VTABLE_ENTRY( vtable, stream_catString, mem ); SET_VTABLE_ENTRY( vtable, stream_putU16, mem ); SET_VTABLE_ENTRY( vtable, stream_putU32, mem ); + SET_VTABLE_ENTRY( vtable, stream_putU32VL, mem ); SET_VTABLE_ENTRY( vtable, stream_putBits, mem ); SET_VTABLE_ENTRY( vtable, stream_getFromStream, mem ); diff --git a/xwords4/common/xwstream.h b/xwords4/common/xwstream.h index be86cb954..054e33561 100644 --- a/xwords4/common/xwstream.h +++ b/xwords4/common/xwstream.h @@ -65,6 +65,7 @@ typedef struct StreamCtxVTable { XP_U16 count ); XP_U16 (*m_stream_getU16)( DBG_PROC_FORMAL XWStreamCtxt* dctx ); XP_U32 (*m_stream_getU32)( DBG_PROC_FORMAL XWStreamCtxt* dctx ); + XP_U32 (*m_stream_getU32VL)( XWStreamCtxt* dctx ); XP_U32 (*m_stream_getBits)( XWStreamCtxt* dctx, XP_U16 nBits ); #if defined DEBUG void (*m_stream_copyBits)( const XWStreamCtxt* dctx, XWStreamPos endPos, @@ -77,6 +78,7 @@ typedef struct StreamCtxVTable { void (*m_stream_catString)( XWStreamCtxt* dctx, const char* whence ); void (*m_stream_putU16)( XWStreamCtxt* dctx, XP_U16 data ); void (*m_stream_putU32)( XWStreamCtxt* dctx, XP_U32 data ); + void (*m_stream_putU32VL)( XWStreamCtxt* dctx, XP_U32 data ); void (*m_stream_putBits)( XWStreamCtxt* dctx, XP_U16 nBits, XP_U32 bits DBG_LINE_FILE_FORMAL ); @@ -133,6 +135,9 @@ struct XWStreamCtxt { #define stream_getU32(sc) \ (sc)->vtable->m_stream_getU32(DBG_PROC sc) +#define stream_getU32VL(sc) \ + (sc)->vtable->m_stream_getU32VL(sc) + #define stream_getBits(sc, n) \ (sc)->vtable->m_stream_getBits((sc), (n)) @@ -156,6 +161,9 @@ struct XWStreamCtxt { #define stream_putU32(sc, d) \ (sc)->vtable->m_stream_putU32((sc), (d)) +#define stream_putU32VL(sc, d) \ + (sc)->vtable->m_stream_putU32VL((sc), (d)) + #define stream_putBits(sc, n, b) \ (sc)->vtable->m_stream_putBits((sc), (n), (b) DBG_LINE_FILE_PARM ) diff --git a/xwords4/linux/linuxmain.c b/xwords4/linux/linuxmain.c index 9c175e461..d9009df7d 100644 --- a/xwords4/linux/linuxmain.c +++ b/xwords4/linux/linuxmain.c @@ -2561,6 +2561,36 @@ initParams( LaunchParams* params ) params->dutil = linux_dutils_init( MPPARM(params->mpool) params->vtMgr, params ); } +static void +testStreams( LaunchParams* params ) +{ + XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(params->dutil->mpool) + params->vtMgr ); + + XP_U32 nums[] = { 1, 4, 8, 200, + makeRandomInt(), + makeRandomInt(), + makeRandomInt(), + makeRandomInt(), + makeRandomInt(), + makeRandomInt(), + }; + + for ( int ii = 0; ii < VSIZE(nums); ++ii ) { + stream_putU32VL( stream, nums[ii] ); + XP_LOGFF( "put num[%d]: %d", ii, nums[ii] ); + } + + for ( int ii = 0; ii < VSIZE(nums); ++ii ) { + XP_U32 num = stream_getU32VL( stream ); + XP_LOGFF( "compariing num[%d]: %d with %d", ii, nums[ii], num ); + XP_ASSERT( num == nums[ii] ); + } + + stream_destroy( stream, NULL ); + XP_LOGFF( "OK!!" ); +} + static void freeParams( LaunchParams* params ) { @@ -2672,6 +2702,7 @@ main( int argc, char** argv ) #endif initParams( &mainParams ); + testStreams( &mainParams ); /* defaults */ for ( int ii = 0; ii < VSIZE(mainParams.connInfo.inviteeCounts); ++ii ) {