xwords/xwords4/wince/ceresstr.c
ehouse a6ecdd0f9e merge revisions 2443 2446 2447 2450 2451 2452 2454 2456 2469 2498 2499
2509 2513 2514 2515 2516 2517 2518 2519 2521 2522 2523 2524 2525 2526
2527 2528 2529 2530 2531 2532 2534 2535 2536 2537 2538 2539 2540 2541
2542 2543 and 2544 from trunk with the goal of adding localization
support to this branch so that it can be released before all the
networking stuff on trunk is debugged.
2009-05-09 16:01:44 +00:00

341 lines
10 KiB
C

/* -*- compile-command: "make -j3 TARGET_OS=wince DEBUG=TRUE RELAY_NAME_DEFAULT=localhost" -*- */
/*
* Copyright 2009 by Eric House (xwords@eehouse.org). All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "ceresstr.h"
#include "ceutil.h"
#include "cedebug.h"
HINSTANCE
ceLoadResFile( const XP_UCHAR* file )
{
HINSTANCE hinst = NULL;
wchar_t widebuf[128];
XP_U16 len = MultiByteToWideChar( CP_ACP, 0, file, -1, widebuf, VSIZE(widebuf) );
widebuf[len] = 0;
hinst = LoadLibrary( widebuf );
return hinst;
}
void
ceCloseResFile( HINSTANCE inst )
{
XP_ASSERT( !!inst );
FreeLibrary( inst );
}
#ifdef LOADSTRING_BROKEN
typedef struct _ResStrEntry {
union {
XP_UCHAR nstr[1];
wchar_t wstr[1];
} u;
} ResStrEntry;
typedef struct _ResStrStorage {
ResStrEntry* entries[CE_LAST_RES_ID - CE_FIRST_RES_ID + 1];
} ResStrStorage;
static const ResStrEntry*
getEntry( CEAppGlobals* globals, XP_U16 resID, XP_Bool isWide )
{
ResStrStorage* storage = (ResStrStorage*)globals->resStrStorage;
ResStrEntry* entry;
XP_U16 index;
XP_ASSERT( resID >= CE_FIRST_RES_ID && resID <= CE_LAST_RES_ID );
index = CE_LAST_RES_ID - resID;
XP_ASSERT( index < VSIZE(storage->entries) );
if ( !storage ) {
storage = XP_MALLOC( globals->mpool, sizeof( *storage ) );
XP_MEMSET( storage, 0, sizeof(*storage) );
globals->resStrStorage = storage;
}
entry = storage->entries[index];
if ( !entry ) {
wchar_t wbuf[265];
XP_U16 len;
LoadString( globals->locInst, resID, wbuf, VSIZE(wbuf) );
if ( isWide ) {
len = wcslen( wbuf );
entry = (ResStrEntry*)XP_MALLOC( globals->mpool,
(len*sizeof(wchar_t))
+ sizeof(*entry) );
wcscpy( entry->u.wstr, wbuf );
} else {
XP_UCHAR nbuf[265];
(void)WideCharToMultiByte( CP_ACP, 0, wbuf, -1,
nbuf, VSIZE(nbuf), NULL, NULL );
len = XP_STRLEN( nbuf );
entry = (ResStrEntry*)XP_MALLOC( globals->mpool,
len + sizeof(*entry) );
XP_STRNCPY( entry->u.nstr, nbuf, len + 1 );
}
storage->entries[index] = entry;
}
return entry;
} /* getEntry */
#endif
const XP_UCHAR*
ceGetResString( CEAppGlobals* globals, XP_U16 resID )
{
#ifdef LOADSTRING_BROKEN
const ResStrEntry* entry = getEntry( globals, resID, XP_FALSE );
return entry->u.nstr;
#else
/* Docs say that you can call LoadString with 0 as the length and it'll
return a read-only ptr to the text within the resource, but I'm getting
a ptr to wide chars back the resource text being multibyte. I swear
I've seen it work, though, so might be a res file formatting thing or a
param to the res compiler. Need to investigate. Until I do, the above
caches local multibyte copies of the resources so the API can stay the
same. */
const XP_UCHAR* str = NULL;
LoadString( globals->locInst, resID, (LPSTR)&str, 0 );
return str;
#endif
}
const wchar_t*
ceGetResStringL( CEAppGlobals* globals, XP_U16 resID )
{
#ifdef LOADSTRING_BROKEN
const ResStrEntry* entry = getEntry( globals, resID, XP_TRUE );
return entry->u.wstr;
#else
/* Docs say that you can call LoadString with 0 as the length and it'll
return a read-only ptr to the text within the resource, but I'm getting
a ptr to wide chars back the resource text being multibyte. I swear
I've seen it work, though, so might be a res file formatting thing or a
param to the res compiler. Need to investigate. Until I do, the above
caches local multibyte copies of the resources so the API can stay the
same. */
const XP_UCHAR* str = NULL;
LoadString( globals->locInst, resID, (LPSTR)&str, 0 );
return str;
#endif
}
#ifdef LOADSTRING_BROKEN
void
ceFreeResStrings( CEAppGlobals* globals )
{
ResStrStorage* storage = (ResStrStorage*)globals->resStrStorage;
if ( !!storage ) {
XP_U16 ii;
for ( ii = 0; ii < VSIZE(storage->entries); ++ii ) {
ResStrEntry* entry = storage->entries[ii];
if ( !!entry ) {
XP_FREE( globals->mpool, entry );
}
}
XP_FREE( globals->mpool, storage );
globals->resStrStorage = NULL;
}
}
#endif
typedef struct _DllSelState {
CeDlgHdr dlgHdr;
wchar_t wbuf[MAX_PATH];
wchar_t* names[8];
wchar_t* files[8];
XP_U16 nItems;
XP_U16 dllListID;
XP_Bool inited;
XP_Bool cancelled;
} DllSelState;
static void
copyWideStr( CEAppGlobals* globals, const wchar_t* str, wchar_t** loc )
{
XP_U16 len = 1 + wcslen( str );
*loc = XP_MALLOC( globals->mpool, len * sizeof(**loc) );
wcscpy( *loc, str );
}
/* Iterate through .dll files listing the name of any that has one. Pair with
* file from which it came since that's what we'll return.
*/
static void
listDlls( DllSelState* state )
{
LOG_FUNC();
HANDLE fileH;
HWND hDlg = state->dlgHdr.hDlg;
WIN32_FIND_DATA data;
CEAppGlobals* globals = state->dlgHdr.globals;
XP_U16 nItems = 0;
wchar_t name[64];
LoadString( globals->hInst, IDS_LANGUAGE_NAME, name, VSIZE(name) );
copyWideStr( globals, name, &state->names[nItems++] );
(void)SendDlgItemMessage( hDlg, state->dllListID, ADDSTRING(globals),
0, (LPARAM)name );
wchar_t path[MAX_PATH];
ceGetExeDir( path, VSIZE(path) );
wcscat( path, L"\\xwords4*.dll" );
XP_MEMSET( &data, 0, sizeof(data) );
fileH = FindFirstFile( path, &data );
while ( fileH != INVALID_HANDLE_VALUE ) {
HINSTANCE hinst = LoadLibrary( data.cFileName );
if ( !!hinst ) {
if ( LoadString( hinst, IDS_LANGUAGE_NAME,
name, VSIZE(name) ) ) {
(void)SendDlgItemMessage( hDlg, state->dllListID, ADDSTRING(globals),
0, (LPARAM)name );
copyWideStr( globals, name, &state->names[nItems] );
copyWideStr( globals, data.cFileName, &state->files[nItems] );
++nItems;
} else {
XP_LOGF( "IDS_LANGUAGE_NAME not found in %ls", data.cFileName );
}
FreeLibrary( hinst );
} else {
logLastError("LoadLibrary");
XP_LOGF( "Unable to open" );
}
if ( nItems >= VSIZE(state->names) ) {
break;
} else if ( !FindNextFile( fileH, &data ) ) {
XP_ASSERT( GetLastError() == ERROR_NO_MORE_FILES );
break;
}
}
SendDlgItemMessage( hDlg, state->dllListID, SETCURSEL(globals), 0, 0 );
state->nItems = nItems;
LOG_RETURN_VOID();
} /* listDlls */
static void
unlistDlls( DllSelState* state )
{
XP_U16 ii;
CEAppGlobals* globals = state->dlgHdr.globals;
for ( ii = 0; ii < state->nItems; ++ii ) {
XP_ASSERT( ii == 0 || !!state->files[ii] );
if ( ii > 0 ) {
XP_FREE( globals->mpool, state->files[ii] );
}
XP_FREE( globals->mpool, state->names[ii] );
}
}
static XP_Bool
getSelText( DllSelState* state )
{
XP_Bool gotIt = XP_FALSE;
HWND hDlg = state->dlgHdr.hDlg;
CEAppGlobals* globals = state->dlgHdr.globals;
XP_S16 sel = SendDlgItemMessage( hDlg, state->dllListID,
GETCURSEL(globals), 0, 0 );
if ( sel >= 0 ) {
gotIt = XP_TRUE;
if ( sel > 0 ) {
wcscpy( state->wbuf, state->files[sel] );
}
}
return gotIt;
} /* getSelText */
LRESULT CALLBACK
DllSelDlg( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
DllSelState* state;
BOOL result = FALSE;
if ( message == WM_INITDIALOG ) {
SetWindowLongPtr( hDlg, GWL_USERDATA, lParam );
state = (DllSelState*)lParam;
state->cancelled = XP_TRUE;
state->dllListID = LB_IF_PPC( state->dlgHdr.globals, LOCALES_COMBO );
ceDlgSetup( &state->dlgHdr, hDlg, DLG_STATE_NONE );
ceDlgComboShowHide( &state->dlgHdr, LOCALES_COMBO );
result = TRUE;
} else {
state = (DllSelState*)GetWindowLongPtr( hDlg, GWL_USERDATA );
if ( !!state ) {
if ( !state->inited ) {
state->inited = XP_TRUE;
listDlls( state );
}
if ( ceDoDlgHandle( &state->dlgHdr, message, wParam, lParam) ) {
result = TRUE;
} else if ( (WM_COMMAND == message)
&& (BN_CLICKED == HIWORD(wParam)) ) {
switch( LOWORD(wParam) ) {
case IDOK:
state->cancelled = XP_FALSE;
getSelText( state );
/* fallthrough */
case IDCANCEL:
unlistDlls( state );
EndDialog( hDlg, LOWORD(wParam) );
result = TRUE;
break;
}
}
}
}
return result;
} /* DllSelDlg */
/* ceChooseResFile: List all the available .rc files and return if user
* chooses one.
*/
XP_Bool
ceChooseResFile( CEAppGlobals* globals, XP_UCHAR* buf, XP_U16 bufLen )
{
DllSelState state;
XP_MEMSET( &state, 0, sizeof(state) );
state.dlgHdr.globals = globals;
(void)DialogBoxParam( globals->locInst, (LPCTSTR)IDD_LOCALESDLG, globals->hWnd,
(DLGPROC)DllSelDlg, (long)&state );
if ( !state.cancelled ) {
(void)WideCharToMultiByte( CP_ACP, 0, state.wbuf, -1,
buf, bufLen, NULL, NULL );
}
LOG_RETURNF( "%s", buf );
return !state.cancelled;
}