mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2024-12-28 09:58:30 +01:00
1c4f0a47b7
it elsewhere in the set of possible directories. This should help ease the transition to there being a limited number of places where dicts can be, since games saved previously will still work after the dicts they reference have been moved. Also, clean up callbacks making their return values consistent: true means done.
886 lines
25 KiB
C
Executable file
886 lines
25 KiB
C
Executable file
/* -*-mode: C; fill-column: 78; c-basic-offset: 4;-*- */
|
|
/*
|
|
* Copyright 1997-2001 by Eric House (xwords@eehouse.org). All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#ifndef STUBBED_DICT
|
|
|
|
#include "stdafx.h"
|
|
#include <commdlg.h>
|
|
#include "dictnryp.h"
|
|
#include "strutils.h"
|
|
#include "cedict.h"
|
|
#include "debhacks.h"
|
|
|
|
typedef struct CEDictionaryCtxt {
|
|
DictionaryCtxt super;
|
|
HANDLE mappedFile;
|
|
void* mappedBase;
|
|
} CEDictionaryCtxt;
|
|
|
|
static void ce_dict_destroy( DictionaryCtxt* dict );
|
|
static XP_UCHAR* ce_dict_getShortName( DictionaryCtxt* dict );
|
|
static void ceLoadSpecialData( CEDictionaryCtxt* ctxt, XP_U8** ptrp );
|
|
static XP_U16 ceCountSpecials( CEDictionaryCtxt* ctxt );
|
|
static XP_Bitmap* ceMakeBitmap( CEDictionaryCtxt* ctxt, XP_U8** ptrp );
|
|
|
|
static XP_U32 n_ptr_tohl( XP_U8** in );
|
|
static XP_U16 n_ptr_tohs( XP_U8** in );
|
|
static XP_U8* openMappedFile( MPFORMAL const wchar_t* name,
|
|
HANDLE* mappedFileP, HANDLE* hFileP,
|
|
XP_U32* sizep );
|
|
static void closeMappedFile( MPFORMAL XP_U8* base, HANDLE mappedFile );
|
|
static XP_Bool checkIfDictAndLegal( MPFORMAL wchar_t* path, XP_U16 pathLen,
|
|
wchar_t* name );
|
|
static XP_Bool findAlternateDict( CEAppGlobals* globals, wchar_t* dictName );
|
|
|
|
#define ALIGN_COUNT 2
|
|
#define CE_MAXDICTS 0x7FFF
|
|
|
|
DictionaryCtxt*
|
|
ce_dictionary_make( CEAppGlobals* globals, XP_UCHAR* dictName )
|
|
{
|
|
CEDictionaryCtxt* ctxt = (CEDictionaryCtxt*)NULL;
|
|
HANDLE mappedFile = NULL;
|
|
|
|
wchar_t nameBuf[MAX_PATH+1];
|
|
HANDLE hFile;
|
|
XP_U8* ptr;
|
|
XP_U32 dictLength;
|
|
XP_UCHAR buf[CE_MAX_PATH_LEN+1]; /* in case we have to look */
|
|
|
|
XP_ASSERT( !!dictName );
|
|
XP_DEBUGF( "looking for dict %s", dictName );
|
|
|
|
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, dictName, -1,
|
|
nameBuf, sizeof(nameBuf)/sizeof(nameBuf[0]) );
|
|
|
|
ptr = openMappedFile( MPPARM(globals->mpool) nameBuf, &mappedFile,
|
|
&hFile, &dictLength );
|
|
if ( !ptr ) {
|
|
if ( findAlternateDict( globals, nameBuf ) ) {
|
|
(void)WideCharToMultiByte( CP_ACP, 0, nameBuf, -1,
|
|
buf, sizeof(buf), NULL, NULL );
|
|
ptr = openMappedFile( MPPARM(globals->mpool) nameBuf, &mappedFile,
|
|
&hFile, &dictLength );
|
|
if ( !!ptr ) {
|
|
dictName = buf;
|
|
}
|
|
}
|
|
}
|
|
|
|
while( !!ptr ) { /* lets us break.... */
|
|
XP_U32 offset;
|
|
XP_U16 numFaces;
|
|
XP_U16 i;
|
|
XP_U16 flags;
|
|
void* mappedBase = (void*)ptr;
|
|
XP_U8 nodeSize;
|
|
|
|
flags = n_ptr_tohs( &ptr );
|
|
XP_DEBUGF( "%s: flags=0x%x", __FUNCTION__, flags );
|
|
|
|
#ifdef NODE_CAN_4
|
|
if ( flags == 0x0002 ) {
|
|
nodeSize = 3;
|
|
} else if ( flags == 0x0003 ) {
|
|
nodeSize = 4;
|
|
} else {
|
|
break; /* we want to return NULL */
|
|
}
|
|
#else
|
|
if( flags != 0x0001 ) {
|
|
break;
|
|
}
|
|
#endif
|
|
ctxt = (CEDictionaryCtxt*)ce_dictionary_make_empty( globals );
|
|
|
|
ctxt->mappedFile = mappedFile;
|
|
ctxt->mappedBase = mappedBase;
|
|
ctxt->super.nodeSize = nodeSize;
|
|
ctxt->super.destructor = ce_dict_destroy;
|
|
ctxt->super.func_dict_getShortName = ce_dict_getShortName;
|
|
|
|
XP_DEBUGF( "ptr starting at 0x%lx", ptr );
|
|
|
|
numFaces = (XP_U16)(*ptr++);
|
|
ctxt->super.nFaces = (XP_U8)numFaces;
|
|
XP_DEBUGF( "read %d faces from dict", (short)numFaces );
|
|
ctxt->super.faces16 =
|
|
XP_MALLOC( globals->mpool,
|
|
numFaces * sizeof(ctxt->super.faces16[0]) );
|
|
|
|
#ifdef NODE_CAN_4
|
|
ctxt->super.is_4_byte = (ctxt->super.nodeSize == 4);
|
|
|
|
for ( i = 0; i < numFaces; ++i ) {
|
|
ctxt->super.faces16[i] = n_ptr_tohs(&ptr);
|
|
}
|
|
#else
|
|
for ( i = 0; i < numFaces; ++i ) {
|
|
ctxt->super.faces16[i] = (XP_CHAR16)*ptr++;
|
|
}
|
|
#endif
|
|
|
|
ctxt->super.countsAndValues =
|
|
(XP_U8*)XP_MALLOC(globals->mpool, numFaces*2);
|
|
|
|
ptr += 2; /* skip xloc header */
|
|
XP_DEBUGF( "pre values: ptr now 0x%lx", ptr );
|
|
for ( i = 0; i < numFaces*2; i += 2 ) {
|
|
ctxt->super.countsAndValues[i] = *ptr++;
|
|
ctxt->super.countsAndValues[i+1] = *ptr++;
|
|
}
|
|
XP_DEBUGF( "post values: ptr now 0x%lx", ptr );
|
|
|
|
ceLoadSpecialData( ctxt, &ptr );
|
|
|
|
dictLength -= ptr - (XP_U8*)ctxt->mappedBase;
|
|
if ( dictLength > sizeof(XP_U32) ) {
|
|
offset = n_ptr_tohl( &ptr );
|
|
dictLength -= sizeof(offset);
|
|
#ifdef NODE_CAN_4
|
|
XP_ASSERT( dictLength % ctxt->super.nodeSize == 0 );
|
|
# ifdef DEBUG
|
|
ctxt->super.numEdges = dictLength / ctxt->super.nodeSize;
|
|
# endif
|
|
#else
|
|
XP_ASSERT( dictLength % 3 == 0 );
|
|
# ifdef DEBUG
|
|
ctxt->super.numEdges = dictLength / 3;
|
|
# endif
|
|
#endif
|
|
}
|
|
|
|
if ( dictLength > 0 ) {
|
|
XP_DEBUGF( "setting topEdge; offset = %ld", offset );
|
|
ctxt->super.base = (array_edge*)ptr;
|
|
#ifdef NODE_CAN_4
|
|
ctxt->super.topEdge = ctxt->super.base
|
|
+ (offset * ctxt->super.nodeSize);
|
|
#else
|
|
ctxt->super.topEdge = ctxt->super.base + (offset * 3);
|
|
#endif
|
|
} else {
|
|
ctxt->super.topEdge = (array_edge*)NULL;
|
|
ctxt->super.base = (array_edge*)NULL;
|
|
}
|
|
|
|
setBlankTile( (DictionaryCtxt*)ctxt );
|
|
|
|
ctxt->super.name = copyString(MPPARM(globals->mpool) dictName);
|
|
break; /* exit phony while loop */
|
|
}
|
|
return (DictionaryCtxt*)ctxt;
|
|
} /* ce_dictionary_make */
|
|
|
|
DictionaryCtxt*
|
|
ce_dictionary_make_empty( CEAppGlobals* globals )
|
|
{
|
|
CEDictionaryCtxt* ctxt = (CEDictionaryCtxt*)XP_MALLOC(globals->mpool,
|
|
sizeof(*ctxt));
|
|
XP_MEMSET( ctxt, 0, sizeof(*ctxt) );
|
|
|
|
dict_super_init( (DictionaryCtxt*)ctxt );
|
|
MPASSIGN( ctxt->super.mpool, globals->mpool );
|
|
return (DictionaryCtxt*)ctxt;
|
|
} /* ce_dictionary_make_empty */
|
|
|
|
static void
|
|
ceLoadSpecialData( CEDictionaryCtxt* ctxt, XP_U8** ptrp )
|
|
{
|
|
XP_U16 nSpecials = ceCountSpecials( ctxt );
|
|
XP_U8* ptr = *ptrp;
|
|
Tile i;
|
|
XP_UCHAR** texts;
|
|
SpecialBitmaps* bitmaps;
|
|
|
|
XP_DEBUGF( "loadSpecialData: there are %d specials", nSpecials );
|
|
|
|
texts = (XP_UCHAR**)XP_MALLOC( ctxt->super.mpool,
|
|
nSpecials * sizeof(*texts) );
|
|
bitmaps = (SpecialBitmaps*)
|
|
XP_MALLOC( ctxt->super.mpool, nSpecials * sizeof(*bitmaps) );
|
|
|
|
for ( i = 0; i < ctxt->super.nFaces; ++i ) {
|
|
|
|
XP_CHAR16 face = ctxt->super.faces16[(short)i];
|
|
if ( IS_SPECIAL(face) ) {
|
|
|
|
/* get the string */
|
|
XP_U8 txtlen = *ptr++;
|
|
XP_UCHAR* text = (XP_UCHAR*)XP_MALLOC(ctxt->super.mpool, txtlen+1);
|
|
XP_MEMCPY( text, ptr, txtlen );
|
|
ptr += txtlen;
|
|
text[txtlen] = '\0';
|
|
XP_ASSERT( face < nSpecials );
|
|
texts[face] = text;
|
|
|
|
XP_DEBUGF( "making bitmaps for %s", texts[face] );
|
|
bitmaps[face].largeBM = ceMakeBitmap( ctxt, &ptr );
|
|
bitmaps[face].smallBM = ceMakeBitmap( ctxt, &ptr );
|
|
}
|
|
}
|
|
|
|
ctxt->super.chars = texts;
|
|
ctxt->super.bitmaps = bitmaps;
|
|
|
|
*ptrp = ptr;
|
|
} /* ceLoadSpecialData */
|
|
|
|
static XP_U16
|
|
ceCountSpecials( CEDictionaryCtxt* ctxt )
|
|
{
|
|
XP_U16 result = 0;
|
|
XP_U16 i;
|
|
|
|
for ( i = 0; i < ctxt->super.nFaces; ++i ) {
|
|
if ( IS_SPECIAL(ctxt->super.faces16[i] ) ) {
|
|
++result;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
} /* ceCountSpecials */
|
|
|
|
static void
|
|
printBitmapData1( XP_U16 nCols, XP_U16 nRows, XP_U8* data )
|
|
{
|
|
char strs[20];
|
|
XP_U16 rowBytes;
|
|
XP_U16 row, col;
|
|
|
|
rowBytes = (nCols + 7) / 8;
|
|
while ( (rowBytes % 2) != 0 ) {
|
|
++rowBytes;
|
|
}
|
|
|
|
XP_DEBUGF( " printBitmapData (%dx%d):", nCols, nRows );
|
|
|
|
for ( row = 0; row < nRows; ++row ) {
|
|
for ( col = 0; col < nCols; ++col ) {
|
|
XP_UCHAR byt = data[col / 8];
|
|
XP_Bool set = (byt & (0x80 >> (col % 8))) != 0;
|
|
|
|
strs[col] = set? '#': '.';
|
|
}
|
|
data += rowBytes;
|
|
|
|
strs[nCols] = '\0';
|
|
XP_DEBUGF( strs );
|
|
}
|
|
XP_DEBUGF( " printBitmapData done" );
|
|
} /* printBitmapData1 */
|
|
|
|
static void
|
|
printBitmapData2( XP_U16 nCols, XP_U16 nRows, XP_U8* data )
|
|
{
|
|
XP_DEBUGF( " printBitmapData (%dx%d):", nCols, nRows );
|
|
while ( nRows-- ) {
|
|
XP_UCHAR buf[100];
|
|
XP_UCHAR* ptr = buf;
|
|
XP_U16 rowBytes = (nCols + 7) / 8;
|
|
while ( (rowBytes % ALIGN_COUNT) != 0 ) {
|
|
++rowBytes;
|
|
}
|
|
|
|
while ( rowBytes-- ) {
|
|
ptr += XP_SNPRINTF( ptr, sizeof(buf), "0x%.2x ", *data++ );
|
|
}
|
|
XP_DEBUGF( buf );
|
|
}
|
|
XP_DEBUGF( " printBitmapData done" );
|
|
} /* printBitmapData2 */
|
|
|
|
#if 0
|
|
static void
|
|
longSwapData( XP_U8* destBase, XP_U16 nRows, XP_U16 rowBytes )
|
|
{
|
|
XP_U32* longBase = (XP_U32*)destBase;
|
|
rowBytes /= 4;
|
|
|
|
while ( nRows-- ) {
|
|
XP_U16 i;
|
|
for ( i = 0; i < rowBytes; ++i ) {
|
|
XP_U32 n = *longBase;
|
|
XP_U32 tmp = 0;
|
|
tmp |= (n >> 24) & 0x000000FF;
|
|
tmp |= (n >> 16) & 0x0000FF00;
|
|
tmp |= (n >> 8 ) & 0x00FF0000;
|
|
tmp |= (n >> 0 ) & 0xFF000000;
|
|
*longBase = tmp;
|
|
|
|
++longBase;
|
|
}
|
|
}
|
|
} /* longSwapData */
|
|
#endif
|
|
|
|
static XP_Bitmap*
|
|
ceMakeBitmap( CEDictionaryCtxt* ctxt, XP_U8** ptrp )
|
|
{
|
|
XP_U8* ptr = *ptrp;
|
|
XP_U8 nCols = *ptr++;
|
|
CEBitmapInfo* bitmap = (CEBitmapInfo*)NULL;
|
|
|
|
if ( nCols > 0 ) {
|
|
XP_U8* dest;
|
|
XP_U8* savedDest;
|
|
XP_U8 nRows = *ptr++;
|
|
XP_U16 rowBytes = (nCols+7) / 8;
|
|
XP_U8 srcByte = 0;
|
|
XP_U8 destByte = 0;
|
|
XP_U8 nBits;
|
|
XP_U16 i;
|
|
|
|
bitmap = (CEBitmapInfo*)XP_MALLOC( ctxt->super.mpool,
|
|
sizeof(bitmap) );
|
|
bitmap->nCols = nCols;
|
|
bitmap->nRows = nRows;
|
|
dest = XP_MALLOC( ctxt->super.mpool, rowBytes * nRows );
|
|
bitmap->bits = savedDest = dest;
|
|
|
|
nBits = nRows * nCols;
|
|
for ( i = 0; i < nBits; ++i ) {
|
|
XP_U8 srcBitIndex = i % 8;
|
|
XP_U8 destBitIndex = (i % nCols) % 8;
|
|
XP_U8 srcMask, bit;
|
|
|
|
if ( srcBitIndex == 0 ) {
|
|
srcByte = *ptr++;
|
|
}
|
|
|
|
srcMask = 1 << (7 - srcBitIndex);
|
|
bit = (srcByte & srcMask) != 0;
|
|
destByte |= bit << (7 - destBitIndex);
|
|
|
|
/* we need to put the byte if we've filled it or if we're done
|
|
with the row */
|
|
if ( (destBitIndex==7) || ((i%nCols) == (nCols-1)) ) {
|
|
*dest++ = destByte;
|
|
destByte = 0;
|
|
}
|
|
}
|
|
|
|
printBitmapData1( nCols, nRows, savedDest );
|
|
printBitmapData2( nCols, nRows, savedDest );
|
|
}
|
|
|
|
*ptrp = ptr;
|
|
return (XP_Bitmap*)bitmap;
|
|
} /* ceMakeBitmap */
|
|
|
|
static void
|
|
ce_dict_destroy( DictionaryCtxt* dict )
|
|
{
|
|
CEDictionaryCtxt* ctxt = (CEDictionaryCtxt*)dict;
|
|
XP_U16 nSpecials = ceCountSpecials( ctxt );
|
|
XP_U16 i;
|
|
|
|
if ( !!ctxt->super.chars ) {
|
|
for ( i = 0; i < nSpecials; ++i ) {
|
|
XP_UCHAR* text = ctxt->super.chars[i];
|
|
if ( !!text ) {
|
|
XP_FREE( ctxt->super.mpool, text );
|
|
}
|
|
}
|
|
XP_FREE( ctxt->super.mpool, ctxt->super.chars );
|
|
}
|
|
if ( !!ctxt->super.bitmaps ) {
|
|
for ( i = 0; i < nSpecials; ++i ) {
|
|
HBITMAP bitmap = (HBITMAP)ctxt->super.bitmaps[i].largeBM;
|
|
if ( !!bitmap ) {
|
|
DeleteObject( bitmap );
|
|
}
|
|
bitmap = (HBITMAP)ctxt->super.bitmaps[i].smallBM;
|
|
if ( !!bitmap ) {
|
|
DeleteObject( bitmap );
|
|
}
|
|
}
|
|
XP_FREE( ctxt->super.mpool, ctxt->super.bitmaps );
|
|
}
|
|
|
|
XP_FREE( ctxt->super.mpool, ctxt->super.faces16 );
|
|
|
|
closeMappedFile( MPPARM(ctxt->super.mpool) ctxt->mappedBase,
|
|
ctxt->mappedFile );
|
|
XP_FREE( ctxt->super.mpool, ctxt );
|
|
} // ce_dict_destroy
|
|
|
|
static XP_UCHAR*
|
|
ce_dict_getShortName( DictionaryCtxt* dict )
|
|
{
|
|
XP_UCHAR* name = dict_getName( dict );
|
|
return bname( name );
|
|
} /* ce_dict_getShortName */
|
|
|
|
static XP_U8*
|
|
openMappedFile( MPFORMAL const wchar_t* name, HANDLE* mappedFileP,
|
|
HANDLE* hFileP, XP_U32* sizep )
|
|
{
|
|
XP_U8* ptr = NULL;
|
|
HANDLE mappedFile = NULL;
|
|
HANDLE hFile;
|
|
|
|
#if defined TARGET_OS_WINCE
|
|
hFile = CreateFileForMapping( name,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ, /* (was 0: no sharing) */
|
|
NULL, /* security */
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_RANDOM_ACCESS,
|
|
NULL );
|
|
|
|
if ( hFile == INVALID_HANDLE_VALUE ) {
|
|
XP_DEBUGF( "open file failed: %ld", GetLastError() );
|
|
} else {
|
|
HANDLE mappedFile;
|
|
XP_DEBUGF( "open file succeeded!!!!" );
|
|
|
|
mappedFile = CreateFileMapping( hFile,
|
|
NULL,
|
|
PAGE_READONLY,
|
|
0,
|
|
0,
|
|
NULL );
|
|
|
|
|
|
if ( mappedFile != INVALID_HANDLE_VALUE ) {
|
|
void* mappedBase = MapViewOfFile( mappedFile,
|
|
FILE_MAP_READ,
|
|
0, 0, 0 );
|
|
ptr = (XP_U8*)mappedBase;
|
|
*mappedFileP = mappedFile;
|
|
*hFileP = hFile;
|
|
if ( sizep != NULL ) {
|
|
*sizep = GetFileSize( hFile, NULL );
|
|
}
|
|
}
|
|
}
|
|
#elif defined TARGET_OS_WIN32
|
|
hFile = CreateFile( name,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL, /* security */
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_RANDOM_ACCESS,
|
|
NULL );
|
|
if ( hFile != INVALID_HANDLE_VALUE ) {
|
|
|
|
DWORD size = GetFileSize( hFile, NULL );
|
|
XP_LOGF( "file size: %d", size );
|
|
|
|
ptr = XP_MALLOC( mpool, size );
|
|
if ( ptr != NULL ) {
|
|
DWORD nRead;
|
|
if ( ReadFile( hFile, ptr, size, &nRead, NULL ) ) {
|
|
XP_ASSERT( nRead == size );
|
|
} else {
|
|
XP_FREE( mpool, ptr );
|
|
ptr = NULL;
|
|
}
|
|
}
|
|
|
|
CloseHandle( hFile );
|
|
|
|
*hFileP = NULL; /* nothing to close later */
|
|
if ( sizep != NULL ) {
|
|
*sizep = size;
|
|
}
|
|
*mappedFileP = (HANDLE)ptr;
|
|
}
|
|
#endif
|
|
return ptr;
|
|
} /* openMappedFile */
|
|
|
|
static void
|
|
closeMappedFile( MPFORMAL XP_U8* base, HANDLE mappedFile )
|
|
{
|
|
#if defined TARGET_OS_WINCE
|
|
UnmapViewOfFile( base );
|
|
CloseHandle( mappedFile );
|
|
#elif defined TARGET_OS_WIN32
|
|
XP_FREE( mpool, base );
|
|
#endif
|
|
}
|
|
|
|
static XP_Bool
|
|
checkIfDictAndLegal( MPFORMAL wchar_t* path, XP_U16 pathLen,
|
|
wchar_t* name )
|
|
{
|
|
XP_Bool result = XP_FALSE;
|
|
XP_U16 len;
|
|
|
|
len = wcslen(name);
|
|
|
|
/* are the last four bytes ".xwd"? */
|
|
if ( 0 == lstrcmp( name + len - 4, L".xwd" ) ) {
|
|
XP_U16 flags;
|
|
HANDLE mappedFile, hFile;
|
|
XP_U8* base;
|
|
wchar_t pathBuf[CE_MAX_PATH_LEN+1];
|
|
|
|
wcscpy( pathBuf, path );
|
|
pathBuf[pathLen] = 0;
|
|
wcscat( pathBuf, name );
|
|
|
|
#ifdef DEBUG
|
|
{
|
|
char narrowName[CE_MAX_PATH_LEN+1];
|
|
int len = wcslen( pathBuf );
|
|
len = WideCharToMultiByte( CP_ACP, 0, pathBuf, len + 1,
|
|
narrowName, len + 1, NULL, NULL );
|
|
XP_LOGF( "%s ends in .xwd", narrowName );
|
|
}
|
|
#endif
|
|
|
|
base = openMappedFile( MPPARM(mpool) pathBuf, &mappedFile,
|
|
&hFile, NULL );
|
|
if ( !!base ) {
|
|
XP_U8* ptr = base;
|
|
|
|
flags = n_ptr_tohs( &ptr );
|
|
XP_LOGF( "checkIfDictAndLegal: flags=0x%x", flags );
|
|
closeMappedFile( MPPARM(mpool) base, mappedFile );
|
|
#ifdef NODE_CAN_4
|
|
/* are the flags what we expect */
|
|
result = flags == 0x0002 || flags == 0x0003;
|
|
#else
|
|
result = flags == 0x0001;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return result;
|
|
} /* checkIfDictAndLegal */
|
|
|
|
static XP_Bool
|
|
locateOneDir( MPFORMAL wchar_t* path, OnePathCB cb, void* ctxt, XP_U16 nSought,
|
|
XP_U16* nFoundP )
|
|
{
|
|
WIN32_FIND_DATA data;
|
|
HANDLE fileH;
|
|
XP_Bool done = XP_FALSE;
|
|
XP_U16 startLen;
|
|
|
|
lstrcat( path, L"\\" );
|
|
startLen = wcslen(path); /* record where we were so can back up */
|
|
lstrcat( path, L"*" );
|
|
|
|
XP_MEMSET( &data, 0, sizeof(data) );
|
|
|
|
/* Looks like I need to look at every file. If it's a directory I search
|
|
it recursively. If it's an .xwd file I check whether it's got the
|
|
right flags and if so I return its name. */
|
|
|
|
fileH = FindFirstFile( path, &data );
|
|
|
|
if ( fileH != INVALID_HANDLE_VALUE ) {
|
|
for ( ; ; ) {
|
|
|
|
if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0){
|
|
|
|
if ( ( data.cFileName[0] == '.' )
|
|
&& ( (data.cFileName[1] == '.')
|
|
|| (data.cFileName[1] == '\0' ) ) ) {
|
|
/* skip . and .. */
|
|
} else {
|
|
lstrcpy( path+startLen, data.cFileName );
|
|
done = locateOneDir( MPPARM(mpool) path, cb, ctxt,
|
|
nSought, nFoundP );
|
|
XP_ASSERT( done || *nFoundP < nSought );
|
|
if ( done ) {
|
|
break;
|
|
}
|
|
}
|
|
} else if ( checkIfDictAndLegal( MPPARM(mpool) path, startLen,
|
|
data.cFileName ) ) {
|
|
XP_U16 len;
|
|
XP_UCHAR buf[CE_MAX_PATH_LEN+1];
|
|
XP_ASSERT( *nFoundP < nSought );
|
|
|
|
lstrcpy( path+startLen, data.cFileName );
|
|
done = (*cb)( path, (*nFoundP)++, ctxt )
|
|
|| *nFoundP == nSought;
|
|
if ( done ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !FindNextFile( fileH, &data ) ) {
|
|
XP_ASSERT( GetLastError() == ERROR_NO_MORE_FILES );
|
|
break;
|
|
}
|
|
path[startLen] = 0;
|
|
}
|
|
|
|
(void)FindClose( fileH );
|
|
}
|
|
return done;
|
|
} /* locateOneDir */
|
|
|
|
#define USE_FOREACH /* FOREACH avoids code duplication, but may not be worth
|
|
the extra complexity. Size is the same. */
|
|
#ifdef USE_FOREACH
|
|
/* return true when done */
|
|
typedef XP_Bool (*ForEachCB)( wchar_t* dir, void* ctxt );
|
|
|
|
static void
|
|
forEachDictDir( HINSTANCE hInstance, ForEachCB cb, void* ctxt )
|
|
{
|
|
UINT id;
|
|
for ( id = IDS_DICTDIRS; ; ++id ) {
|
|
wchar_t pathBuf[CE_MAX_PATH_LEN+1];
|
|
if ( 0 >= LoadString( hInstance, id, pathBuf,
|
|
sizeof(pathBuf)/sizeof(pathBuf[0]) ) ) {
|
|
break;
|
|
}
|
|
|
|
if ( (*cb)( pathBuf, ctxt ) ) {
|
|
break;
|
|
}
|
|
}
|
|
} /* forEachDictDir */
|
|
|
|
typedef struct LocateOneData {
|
|
XP_U16 nFound;
|
|
XP_U16 nSought;
|
|
OnePathCB cb;
|
|
void* ctxt;
|
|
|
|
MPSLOT
|
|
} LocateOneData;
|
|
|
|
static XP_Bool
|
|
locateOneDirCB( wchar_t* dir, void* ctxt )
|
|
{
|
|
LocateOneData* datap = (LocateOneData*)ctxt;
|
|
|
|
return locateOneDir( MPPARM(datap->mpool) dir, datap->cb,
|
|
datap->ctxt, datap->nSought, &datap->nFound )
|
|
|| datap->nFound >= datap->nSought;
|
|
} /* locateOneDirCB */
|
|
|
|
XP_U16
|
|
ceLocateNDicts( MPFORMAL HINSTANCE hInstance, XP_U16 nSought,
|
|
OnePathCB cb, void* ctxt )
|
|
{
|
|
LocateOneData data;
|
|
|
|
data.nFound = 0;
|
|
data.nSought = nSought;
|
|
data.cb = cb;
|
|
data.ctxt = ctxt;
|
|
#ifdef MEM_DEBUG
|
|
data.mpool = mpool;
|
|
#endif
|
|
|
|
forEachDictDir( hInstance, locateOneDirCB, &data );
|
|
return data.nFound;
|
|
}
|
|
|
|
typedef struct FormatDirsData {
|
|
XWStreamCtxt* stream;
|
|
XP_Bool firstPassDone;
|
|
} FormatDirsData;
|
|
|
|
static XP_Bool
|
|
formatDirsCB( wchar_t* dir, void* ctxt )
|
|
{
|
|
FormatDirsData* datap = (FormatDirsData*)ctxt;
|
|
XP_UCHAR narrow[CE_MAX_PATH_LEN+1];
|
|
int len;
|
|
|
|
if ( datap->firstPassDone ) {
|
|
stream_putBytes( datap->stream, ", ", 2 );
|
|
} else {
|
|
datap->firstPassDone = XP_TRUE;
|
|
}
|
|
|
|
len = WideCharToMultiByte( CP_ACP, 0, dir, -1,
|
|
narrow, sizeof(narrow)/sizeof(narrow[0]),
|
|
NULL, NULL );
|
|
stream_putBytes( datap->stream, narrow, len-1 ); /* skip null */
|
|
return XP_FALSE;
|
|
} /* formatDirsCB */
|
|
|
|
void
|
|
ceFormatDictDirs( XWStreamCtxt* stream, HINSTANCE hInstance )
|
|
{
|
|
FormatDirsData data;
|
|
data.stream = stream;
|
|
data.firstPassDone = XP_FALSE;
|
|
|
|
forEachDictDir( hInstance, formatDirsCB, &data );
|
|
}
|
|
|
|
#else
|
|
|
|
XP_U16
|
|
ceLocateNDicts( MPFORMAL HINSTANCE hInstance, XP_U16 nSought,
|
|
OnePathCB cb, void* ctxt )
|
|
{
|
|
XP_U16 nFound = 0;
|
|
UINT id;
|
|
|
|
for ( id = IDS_DICTDIRS; ; ++id ) {
|
|
wchar_t pathBuf[CE_MAX_PATH_LEN+1];
|
|
if ( 0 >= LoadString( hInstance, id, pathBuf,
|
|
sizeof(pathBuf)/sizeof(pathBuf[0]) ) ) {
|
|
break;
|
|
}
|
|
|
|
locateOneDir( MPPARM(mpool) pathBuf, cb, ctxt, nSought, &nFound );
|
|
|
|
if ( nFound >= nSought ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return nFound;
|
|
} /* ceLocateNDicts */
|
|
|
|
void
|
|
ceFormatDictDirs( XWStreamCtxt* stream, HINSTANCE hInstance )
|
|
{
|
|
UINT id;
|
|
|
|
for ( id = IDS_DICTDIRS; ; ++id ) {
|
|
wchar_t wide[CE_MAX_PATH_LEN+1];
|
|
XP_UCHAR narrow[CE_MAX_PATH_LEN+1];
|
|
XP_U16 len;
|
|
|
|
if ( 0 >= LoadString( hInstance, id, wide,
|
|
sizeof(wide)/sizeof(wide[0]) ) ) {
|
|
break;
|
|
}
|
|
|
|
if ( id != IDS_DICTDIRS ) {
|
|
stream_putBytes( stream, ", ", 2 );
|
|
}
|
|
len = WideCharToMultiByte( CP_ACP, 0, wide, -1,
|
|
narrow, sizeof(narrow)/sizeof(narrow[0]),
|
|
NULL, NULL );
|
|
stream_putBytes( stream, narrow, len-1 ); /* skip null */
|
|
}
|
|
}
|
|
#endif /* USE_FOREACH */
|
|
|
|
typedef struct FindOneData {
|
|
wchar_t* result;
|
|
const wchar_t* sought;
|
|
XP_Bool found;
|
|
} FindOneData;
|
|
|
|
static XP_Bool
|
|
matchShortName( const wchar_t* wPath, XP_U16 index, void* ctxt )
|
|
{
|
|
FindOneData* datap = (FindOneData*)ctxt;
|
|
wchar_t buf[CE_MAX_PATH_LEN+1];
|
|
wchar_t* name;
|
|
|
|
LOG_FUNC();
|
|
|
|
XP_ASSERT( !datap->found );
|
|
|
|
name = wbname( buf, sizeof(buf), wPath );
|
|
if ( 0 == wcscmp( name, datap->sought ) ) {
|
|
wcscpy( datap->result, wPath );
|
|
datap->found = XP_TRUE;
|
|
}
|
|
return datap->found;
|
|
} /* matchShortName */
|
|
|
|
/* Users sometimes move dicts. Given a path to a dict that doesn't exist, See
|
|
* if another with the same short name exists somewhere else we're willing to
|
|
* look.
|
|
*/
|
|
static XP_Bool
|
|
findAlternateDict( CEAppGlobals* globals, wchar_t* path )
|
|
{
|
|
wchar_t shortPath[CE_MAX_PATH_LEN+1];
|
|
wchar_t* shortName;
|
|
XP_U16 nFound;
|
|
FindOneData data;
|
|
|
|
XP_MEMSET( &data, 0, sizeof(data) );
|
|
data.sought = wbname( shortPath, sizeof(shortPath), path );
|
|
data.result = path;
|
|
|
|
(void)ceLocateNDicts( MPPARM(globals->mpool) globals->hInst, CE_MAXDICTS,
|
|
matchShortName, &data );
|
|
return data.found;
|
|
} /* findAlternateDict */
|
|
|
|
static XP_U32
|
|
n_ptr_tohl( XP_U8** inp )
|
|
{
|
|
XP_U32 t;
|
|
XP_MEMCPY( &t, *inp, sizeof(t) );
|
|
|
|
*inp += sizeof(t);
|
|
|
|
return XP_NTOHL(t);
|
|
} /* n_ptr_tohl */
|
|
|
|
static XP_U16
|
|
n_ptr_tohs( XP_U8** inp )
|
|
{
|
|
XP_U16 t;
|
|
XP_MEMCPY( &t, *inp, sizeof(t) );
|
|
|
|
*inp += sizeof(t);
|
|
|
|
return XP_NTOHS(t);
|
|
} /* n_ptr_tohs */
|
|
|
|
XP_UCHAR*
|
|
bname( XP_UCHAR* in )
|
|
{
|
|
XP_U16 len = (XP_U16)XP_STRLEN(in);
|
|
XP_UCHAR* out = in + len - 1;
|
|
|
|
while ( *out != '\\' && out >= in ) {
|
|
--out;
|
|
}
|
|
return out + 1;
|
|
} /* bname */
|
|
|
|
wchar_t*
|
|
wbname( wchar_t* buf, XP_U16 buflen, const wchar_t* in )
|
|
{
|
|
int len;
|
|
wchar_t* result;
|
|
|
|
_snwprintf( buf, buflen, L"%s", in );
|
|
result = buf + wcslen( buf ) - 1;
|
|
|
|
/* wipe out extension */
|
|
while ( *result != '.' ) {
|
|
--result;
|
|
XP_ASSERT( result > buf );
|
|
}
|
|
*result = 0;
|
|
|
|
while ( result >= buf && *result != '\\' ) {
|
|
--result;
|
|
}
|
|
|
|
return result + 1;
|
|
} /* wbname */
|
|
|
|
#endif /* ifndef STUBBED_DICT */
|