xwords/xwords4/wince/ceresstr.c

343 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;
XP_LOGF( "%s: created entry for %d", __func__, resID );
}
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, DLLS_COMBO );
ceDlgSetup( &state->dlgHdr, hDlg, DLG_STATE_NONE );
ceDlgComboShowHide( &state->dlgHdr, DLLS_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;
}