/* -*- fill-column: 77; compile-command: "make TARGET_OS=wince DEBUG=TRUE" -*- */ /* * Copyright 1997-2008 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 /* _snwprintf */ #include /* _snwprintf */ #include "stdafx.h" /* #include */ #include #include "dictnryp.h" #include "strutils.h" #include "cedict.h" #include "debhacks.h" #include "cedebug.h" #include "ceutil.h" typedef struct CEDictionaryCtxt { DictionaryCtxt super; HANDLE mappedFile; void* mappedBase; } CEDictionaryCtxt; static void ce_dict_destroy( DictionaryCtxt* dict ); static const XP_UCHAR* ce_dict_getShortName( const 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 DictionaryCtxt* ce_dictionary_make( CEAppGlobals* globals, const char* dictName ) { CEDictionaryCtxt* ctxt = (CEDictionaryCtxt*)NULL; HANDLE mappedFile = NULL; wchar_t nameBuf[MAX_PATH+1]; HANDLE hFile; XP_U8* ptr = NULL; XP_U32 dictLength; XP_UCHAR buf[CE_MAX_PATH_LEN+1]; /* in case we have to look */ UINT codePages[] = { CP_ACP, CP_UTF8 }; XP_U16 ii; XP_ASSERT( !!dictName ); /* Try both old-iso and UTF-8 to convert file name */ for ( ii = 0; ii < VSIZE(codePages); ++ii ) { if ( 0 != MultiByteToWideChar( codePages[ii], 0, dictName, -1, nameBuf, VSIZE(nameBuf) ) ) { ptr = openMappedFile( MPPARM(globals->mpool) nameBuf, &mappedFile, &hFile, &dictLength ); break; } } 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, numFaceBytes = 0; XP_U16 i; XP_U16 flags; void* mappedBase = (void*)ptr; XP_U8 nodeSize; XP_Bool isUTF8 = XP_FALSE; flags = n_ptr_tohs( &ptr ); #ifdef NODE_CAN_4 if ( flags == 0x0002 ) { nodeSize = 3; } else if ( flags == 0x0003 ) { nodeSize = 4; } else if ( flags == 0x0004 ) { isUTF8 = XP_TRUE; nodeSize = 3; } else if ( flags == 0x0005 ) { isUTF8 = XP_TRUE; nodeSize = 4; } else { break; /* we want to return NULL */ } #else if( flags != 0x0001 ) { break; } #endif if ( isUTF8 ) { numFaceBytes = (XP_U16)(*ptr++); } numFaces = (XP_U16)(*ptr++); if ( numFaces > 64 ) { break; } 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; if ( !isUTF8 ) { numFaceBytes = numFaces * 2; } ctxt->super.nFaces = (XP_U8)numFaces; ctxt->super.isUTF8 = isUTF8; if ( isUTF8 ) { dict_splitFaces( &ctxt->super, ptr, numFaceBytes, numFaces ); ptr += numFaceBytes; } else { XP_U8 tmp[numFaces*4]; /* should be enough... */ XP_U16 nBytes = 0; XP_U16 ii; /* Need to translate from iso-8859-n to utf8 */ for ( ii = 0; ii < numFaces; ++ii ) { XP_UCHAR ch = ptr[1]; wchar_t wch; ptr += 2; MultiByteToWideChar( CP_ACP, 0, &ch, 1, &wch, 1 ); XP_UCHAR utfs[8]; int len = WideCharToMultiByte( CP_UTF8, 0, &wch, 1, utfs, VSIZE(utfs), NULL, NULL ); XP_MEMCPY( &tmp[nBytes], utfs, len ); nBytes += len; } dict_splitFaces( &ctxt->super, tmp, nBytes, numFaces ); } ctxt->super.is_4_byte = (ctxt->super.nodeSize == 4); ctxt->super.countsAndValues = (XP_U8*)XP_MALLOC(globals->mpool, numFaces*2); ptr += 2; /* skip xloc header */ for ( i = 0; i < numFaces*2; i += 2 ) { ctxt->super.countsAndValues[i] = *ptr++; ctxt->super.countsAndValues[i+1] = *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 } else { offset = 0; } if ( dictLength > 0 ) { 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( &ctxt->super ); ctxt->super.name = copyString(globals->mpool, dictName); break; /* exit phony while loop */ } return (DictionaryCtxt*)ctxt; } /* ce_dictionary_make */ DictionaryCtxt* ce_dictionary_make_empty( CEAppGlobals* XP_UNUSED_DBG(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 */ void dict_splitFaces( DictionaryCtxt* dict, const XP_U8* utf8, XP_U16 nBytes, XP_U16 nFaces ) { XP_UCHAR* faces = XP_MALLOC( dict->mpool, nBytes + nFaces ); XP_UCHAR** ptrs = XP_MALLOC( dict->mpool, nFaces * sizeof(ptrs[0])); XP_U16 ii; XP_UCHAR* next = faces; wchar_t widebuf[nFaces]; int nRead = MultiByteToWideChar( CP_UTF8, 0, (char*)utf8, nBytes, widebuf, VSIZE(widebuf) ); if ( 0 == nRead ) { logLastError( "MultiByteToWideChar" ); } XP_ASSERT( nRead == nFaces ); /* now split */ for ( ii = 0; ii < nFaces; ++ii ) { ptrs[ii] = next; int nWritten = WideCharToMultiByte( CP_UTF8, 0, &widebuf[ii], 1, next, 100, NULL, NULL ); next += nWritten; *next++ = 0; } XP_ASSERT( next == faces + nFaces + nBytes ); XP_ASSERT( !dict->faces ); dict->faces = faces; XP_ASSERT( !dict->facePtrs ); dict->facePtrs = ptrs; } /* dict_splitFaces */ static void ceLoadSpecialData( CEDictionaryCtxt* ctxt, XP_U8** ptrp ) { XP_U16 nSpecials = ceCountSpecials( ctxt ); XP_U8* ptr = *ptrp; Tile ii; XP_UCHAR** texts; SpecialBitmaps* bitmaps; texts = (XP_UCHAR**)XP_MALLOC( ctxt->super.mpool, nSpecials * sizeof(*texts) ); bitmaps = (SpecialBitmaps*) XP_MALLOC( ctxt->super.mpool, nSpecials * sizeof(*bitmaps) ); for ( ii = 0; ii < ctxt->super.nFaces; ++ii ) { const XP_UCHAR* facep = ctxt->super.facePtrs[(short)ii]; if ( IS_SPECIAL(*facep) ) { /* 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( *facep < nSpecials ); texts[(int)*facep] = text; bitmaps[(int)*facep].largeBM = ceMakeBitmap( ctxt, &ptr ); bitmaps[(int)*facep].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 ii; for ( ii = 0; ii < ctxt->super.nFaces; ++ii ) { if ( IS_SPECIAL( ctxt->super.facePtrs[ii][0] ) ) { ++result; } } return result; } /* ceCountSpecials */ #if 0 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; } 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 ); } } /* printBitmapData1 */ static void printBitmapData2( XP_U16 nCols, XP_U16 nRows, XP_U8* data ) { 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 ); } } /* printBitmapData2 */ 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* XP_UNUSED_DBG(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 ceDeleteBitmap( const CEDictionaryCtxt* XP_UNUSED_DBG(ctxt), XP_Bitmap* bitmap ) { if ( !!bitmap ) { CEBitmapInfo* bmi = (CEBitmapInfo*)bitmap; XP_FREE( ctxt->super.mpool, bmi->bits ); XP_FREE( ctxt->super.mpool, bmi ); } } 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 ) { ceDeleteBitmap( ctxt, ctxt->super.bitmaps[i].largeBM ); ceDeleteBitmap( ctxt, ctxt->super.bitmaps[i].smallBM ); } XP_FREE( ctxt->super.mpool, ctxt->super.bitmaps ); } XP_FREE( ctxt->super.mpool, ctxt->super.faces ); XP_FREE( ctxt->super.mpool, ctxt->super.facePtrs ); XP_FREE( ctxt->super.mpool, ctxt->super.countsAndValues ); XP_FREE( ctxt->super.mpool, ctxt->super.name ); closeMappedFile( MPPARM(ctxt->super.mpool) ctxt->mappedBase, ctxt->mappedFile ); XP_FREE( ctxt->super.mpool, ctxt ); } // ce_dict_destroy static const XP_UCHAR* ce_dict_getShortName( const DictionaryCtxt* dict ) { const 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 hFile; #if defined _WIN32_WCE 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 ) { logLastError( "CreateFileForMapping" ); } else { HANDLE mappedFile; 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 ); } } } #else 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 ); 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 XP_UNUSED_32(mappedFile) ) { #ifdef _WIN32_WCE UnmapViewOfFile( base ); CloseHandle( mappedFile ); #else 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_UTF8, 0, pathBuf, len + 1, narrowName, len + 1, NULL, NULL ); } #endif base = openMappedFile( MPPARM(mpool) pathBuf, &mappedFile, &hFile, NULL ); if ( !!base ) { XP_U8* ptr = base; flags = n_ptr_tohs( &ptr ); closeMappedFile( MPPARM(mpool) base, mappedFile ); #ifdef NODE_CAN_4 /* are the flags what we expect */ result = flags >= 0x0002 && flags <= 0x0005; #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_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 */ XP_U16 ceLocateNDicts( CEAppGlobals* globals, XP_U16 nSought, OnePathCB cb, void* ctxt ) { XP_U16 nFound = 0; wchar_t path[CE_MAX_PATH_LEN+1]; if ( ceGetExeDir( path, VSIZE(path) ) ) { locateOneDir( MPPARM(globals->mpool) path, cb, ctxt, nSought, &nFound ); } if ( nFound < nSought ) { ceGetPath( globals, PROGFILES_PATH, path, VSIZE(path) ); locateOneDir( MPPARM(globals->mpool) path, cb, ctxt, nSought, &nFound ); } if ( nFound < nSought ) { WIN32_FIND_DATA data; HANDLE fileH; XP_MEMSET( &data, 0, sizeof(data) ); fileH = FindFirstFile( L"\\*", &data ); while ( fileH != INVALID_HANDLE_VALUE ) { if ( ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) && (((data.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) != 0) ) ) { wsprintf( path, L"\\%s\\Crosswords", data.cFileName ); XP_LOGW( "looking in:", path ); locateOneDir( MPPARM(globals->mpool) path, cb, ctxt, nSought, &nFound ); } if ( nFound >= nSought ) { break; } if ( !FindNextFile( fileH, &data ) ) { break; } } } return nFound; } /* ceLocateNDicts */ typedef struct FindOneData { wchar_t* result; const wchar_t* sought; XP_Bool found; } FindOneData; static XP_Bool matchShortName( const wchar_t* wPath, XP_U16 XP_UNUSED(index), void* ctxt ) { FindOneData* datap = (FindOneData*)ctxt; wchar_t buf[CE_MAX_PATH_LEN+1]; wchar_t* name; XP_ASSERT( !datap->found ); name = wbname( buf, VSIZE(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]; FindOneData data; XP_MEMSET( &data, 0, sizeof(data) ); data.sought = wbname( shortPath, VSIZE(shortPath), path ); data.result = path; (void)ceLocateNDicts( globals, 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 */ const XP_UCHAR* bname( const XP_UCHAR* in ) { XP_U16 len = (XP_U16)XP_STRLEN(in); const 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 ) { const wchar_t* slash = wcsrchr( in, L'\\' ); if ( !!slash ) { ++slash; } else { slash = in; } const wchar_t* dot = wcsrchr( slash, L'.' ); if ( !dot ) { dot = slash + wcslen( slash ); } _snwprintf( buf, buflen, L"%s", slash ); XP_ASSERT( dot >= slash ); buf[dot-slash] = 0; return buf; } /* wbname */ #endif /* ifndef STUBBED_DICT */