515 lines
16 KiB
C++
515 lines
16 KiB
C++
|
/*
|
||
|
** Command & Conquer Renegade(tm)
|
||
|
** Copyright 2025 Electronic Arts Inc.
|
||
|
**
|
||
|
** 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 3 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, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
/*****************************************************************************
|
||
|
* C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S *
|
||
|
******************************************************************************
|
||
|
*
|
||
|
* FILE
|
||
|
* $Archive: /Commando/Code/Tools/WWConfig/Locale_API.cpp $
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
*
|
||
|
* PROGRAMMER
|
||
|
* $Author: Ian_l $
|
||
|
*
|
||
|
* VERSION INFO
|
||
|
* $Modtime: 1/09/02 11:02a $
|
||
|
* $Revision: 2 $
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#include <Windows.h>
|
||
|
#include <wtypes.h>
|
||
|
#include "locale.h"
|
||
|
#include "locale_api.h"
|
||
|
#include "rawfile.h"
|
||
|
#include "wwconfig_ids.h"
|
||
|
|
||
|
|
||
|
/****************************************************************************/
|
||
|
/* DEFINES */
|
||
|
/****************************************************************************/
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
// NOTE: if USE_MULTI_FILE_FORMAT is "true", then a .lOC file must be in
|
||
|
// the same directory as this file.
|
||
|
//----------------------------------------------------------------------------
|
||
|
#define USE_MULTI_FILE_FORMAT FALSE
|
||
|
|
||
|
#define LANGUAGE_IS_DBCS(l) (((l)==IDL_JAPANESE)||((l)==IDL_KOREAN)||((l)==IDL_CHINESE)) // [OYO]
|
||
|
#define CODEPAGE_IS_DBCS(C) ((C==932)||(C==949)||(C==950)) // [OYO]
|
||
|
|
||
|
|
||
|
/****************************************************************************/
|
||
|
/* GLOBAL VARIABLES */
|
||
|
/****************************************************************************/
|
||
|
CHAR LanguageFile[ _MAX_PATH ];
|
||
|
void * LocaleFile = NULL;
|
||
|
int CodePage = GetACP();
|
||
|
int LanguageID = 0;
|
||
|
|
||
|
/****************************************************************************/
|
||
|
/* LOCALE API */
|
||
|
/****************************************************************************/
|
||
|
WCHAR * Remove_Quotes_Around_String ( WCHAR *old_string );
|
||
|
void * Load_File ( const CHAR *filename, long *filesize );
|
||
|
|
||
|
//=============================================================================
|
||
|
// These are wrapper functions around the LOCALE_ functions. I made these to
|
||
|
// make using the single vs. multi language files more transparent to the program.
|
||
|
//=============================================================================
|
||
|
|
||
|
bool Locale_Use_Multi_Language_Files ( void )
|
||
|
{
|
||
|
#if( USE_MULTI_FILE_FORMAT )
|
||
|
return true;
|
||
|
#else
|
||
|
return false;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************/
|
||
|
/* initialization */
|
||
|
/****************************************************************************/
|
||
|
|
||
|
int Locale_Init ( int language, char *file )
|
||
|
{
|
||
|
int result = 0;
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
// Check for a file passed in.
|
||
|
//-------------------------------------------------------------------------
|
||
|
if( file == NULL || file[0] == '/0' ) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
// Initialize settings.
|
||
|
//-------------------------------------------------------------------------
|
||
|
strcpy( LanguageFile, file );
|
||
|
LanguageID = language;
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
// If language == -1, then set based on CodePage.
|
||
|
//-------------------------------------------------------------------------
|
||
|
if( LanguageID == -1 ) {
|
||
|
|
||
|
switch( CodePage ) {
|
||
|
|
||
|
// Japanese
|
||
|
case 932:
|
||
|
LanguageID = IDL_JAPANESE;
|
||
|
break;
|
||
|
|
||
|
// Korean
|
||
|
case 949:
|
||
|
LanguageID = IDL_KOREAN;
|
||
|
break;
|
||
|
|
||
|
// Chinese
|
||
|
case 950:
|
||
|
LanguageID = IDL_CHINESE;
|
||
|
break;
|
||
|
|
||
|
// English, French, and German
|
||
|
case 1252:
|
||
|
{
|
||
|
LANGID langid = GetSystemDefaultLangID();
|
||
|
WORD plangid = PRIMARYLANGID( langid );
|
||
|
|
||
|
switch( plangid ) {
|
||
|
|
||
|
// German
|
||
|
case 0x07:
|
||
|
LanguageID = IDL_GERMAN;
|
||
|
break;
|
||
|
|
||
|
// French
|
||
|
case 0x0c:
|
||
|
LanguageID = IDL_FRENCH;
|
||
|
break;
|
||
|
|
||
|
// English
|
||
|
case 0x09:
|
||
|
default:
|
||
|
LanguageID = IDL_ENGLISH;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
LanguageID = IDL_ENGLISH;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
// Check for valid LanguageID range.
|
||
|
//-------------------------------------------------------------------------
|
||
|
if( LanguageID < 0 || LanguageID >= LOCALE_LANGUAGE_COUNT ) {
|
||
|
LanguageID = 0;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
// Use English in the situation where Chinese, Korean, or Japanese was
|
||
|
// requested but not available.
|
||
|
//-------------------------------------------------------------------------
|
||
|
if( LANGUAGE_IS_DBCS( LanguageID ) && !CODEPAGE_IS_DBCS( CodePage )) {
|
||
|
LanguageID = IDL_ENGLISH;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
// Initialize the lx object.
|
||
|
//-------------------------------------------------------------------------
|
||
|
LOCALE_init();
|
||
|
|
||
|
#if( USE_MULTI_FILE_FORMAT )
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
// Set bank to use and load the appropriate table.
|
||
|
//---------------------------------------------------------------------
|
||
|
LOCALE_setbank(0);
|
||
|
result = LOCALE_loadtable( LanguageFile, LanguageID );
|
||
|
|
||
|
#else
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
// Create a file buffer that holds all the strings in the file.
|
||
|
//---------------------------------------------------------------------
|
||
|
long filesize;
|
||
|
HRSRC hRsrc;
|
||
|
HGLOBAL hGlobal;
|
||
|
int PrimaryLanguage = LANG_NEUTRAL;
|
||
|
int SubLanguage = SUBLANG_DEFAULT;
|
||
|
HMODULE module = GetModuleHandle( NULL );
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
// Find the string file in this program's resources.
|
||
|
//-------------------------------------------------------------------------
|
||
|
switch( LanguageID ) {
|
||
|
|
||
|
// Japanese
|
||
|
case IDL_JAPANESE:
|
||
|
PrimaryLanguage = LANG_JAPANESE;
|
||
|
SubLanguage = SUBLANG_DEFAULT;
|
||
|
break;
|
||
|
|
||
|
// Korean
|
||
|
case IDL_KOREAN:
|
||
|
PrimaryLanguage = LANG_KOREAN;
|
||
|
SubLanguage = SUBLANG_DEFAULT;
|
||
|
break;
|
||
|
|
||
|
// Chinese
|
||
|
case IDL_CHINESE:
|
||
|
PrimaryLanguage = LANG_CHINESE;
|
||
|
SubLanguage = SUBLANG_DEFAULT;
|
||
|
break;
|
||
|
|
||
|
// German
|
||
|
case IDL_GERMAN:
|
||
|
PrimaryLanguage = LANG_GERMAN;
|
||
|
SubLanguage = SUBLANG_GERMAN;
|
||
|
break;
|
||
|
|
||
|
// French
|
||
|
case IDL_FRENCH:
|
||
|
PrimaryLanguage = LANG_FRENCH;
|
||
|
SubLanguage = SUBLANG_FRENCH;
|
||
|
break;
|
||
|
|
||
|
// English
|
||
|
case IDL_ENGLISH:
|
||
|
PrimaryLanguage = LANG_ENGLISH;
|
||
|
SubLanguage = SUBLANG_ENGLISH_US;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
PrimaryLanguage = LANG_ENGLISH;
|
||
|
SubLanguage = SUBLANG_ENGLISH_US;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
hRsrc = FindResourceEx( module, RT_RCDATA, "STRINGS", MAKELANGID( PrimaryLanguage, SubLanguage ));
|
||
|
if ( hRsrc == NULL ) {
|
||
|
hRsrc = FindResourceEx( module, RT_RCDATA, "STRINGS", MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ));
|
||
|
}
|
||
|
if ( hRsrc ) {
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
// Load the resource, lock the memory, grab a DC.
|
||
|
//---------------------------------------------------------------------
|
||
|
hGlobal = LoadResource( module, hRsrc );
|
||
|
filesize = SizeofResource( module, hRsrc );
|
||
|
|
||
|
LocaleFile = (void*)malloc( filesize + 1 );
|
||
|
memset( LocaleFile, '\0', filesize + 1 );
|
||
|
memcpy( LocaleFile, (const void *)hGlobal, filesize );
|
||
|
|
||
|
//---------------------------------------------------------------------
|
||
|
// Free DS and memory used.
|
||
|
//---------------------------------------------------------------------
|
||
|
UnlockResource( hGlobal );
|
||
|
FreeResource( hGlobal );
|
||
|
}
|
||
|
|
||
|
if( LocaleFile == NULL ) {
|
||
|
LocaleFile = Load_File( LanguageFile, &filesize );
|
||
|
}
|
||
|
|
||
|
if( LocaleFile != NULL ) {
|
||
|
result = 1;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/************************************************************************/
|
||
|
/* restore */
|
||
|
/************************************************************************/
|
||
|
|
||
|
void Locale_Restore ( void )
|
||
|
{
|
||
|
#if( USE_MULTI_FILE_FORMAT )
|
||
|
LOCALE_freetable();
|
||
|
LOCALE_restore();
|
||
|
#else
|
||
|
if( LocaleFile ) {
|
||
|
free( LocaleFile );
|
||
|
LocaleFile = NULL;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
/********************************************************************************
|
||
|
* Load_File -- Allocates a buffer and loads the file into it. *
|
||
|
* *
|
||
|
* Get a string usine Resource ID and a buffer. *
|
||
|
* *
|
||
|
* INPUT: int StringID -- The resource number of the string. *
|
||
|
* CHAR *String -- The buffer to place the text in. *
|
||
|
* *
|
||
|
* OUTPUT: Returns with a pointer to the buffer. *
|
||
|
* *
|
||
|
* WARNINGS: none *
|
||
|
* *
|
||
|
* HISTORY: *
|
||
|
* 12/10/2001 MML : Created. *
|
||
|
*==============================================================================*/
|
||
|
|
||
|
const CHAR* Locale_GetString( int StringID, CHAR *String )
|
||
|
{
|
||
|
static CHAR buffer[ _MAX_PATH ];
|
||
|
static WCHAR wide_buffer[ _MAX_PATH ];
|
||
|
|
||
|
memset( buffer, '\0', _MAX_PATH );
|
||
|
memset( wide_buffer, '\0', _MAX_PATH );
|
||
|
|
||
|
#if( USE_MULTI_FILE_FORMAT )
|
||
|
wcscpy( wide_buffer, (WCHAR *)LOCALE_getstring( StringID ));
|
||
|
#else
|
||
|
wcscpy( wide_buffer, (WCHAR *)LOCALE_getstr( LocaleFile, StringID ));
|
||
|
#endif
|
||
|
|
||
|
Remove_Quotes_Around_String( wide_buffer );
|
||
|
WideCharToMultiByte( CodePage, 0, wide_buffer, _MAX_PATH, buffer, _MAX_PATH, NULL, NULL );
|
||
|
|
||
|
if( String != NULL ) {
|
||
|
strncpy( String, buffer, _MAX_PATH );
|
||
|
}
|
||
|
return buffer;
|
||
|
}
|
||
|
|
||
|
/********************************************************************************
|
||
|
* Load_File -- Allocates a buffer and loads the file into it. *
|
||
|
* *
|
||
|
* Get a string usine Resource ID and a buffer. *
|
||
|
* *
|
||
|
* INPUT: int StringID -- The resource number of the string. *
|
||
|
* WCHAR *String -- The buffer to place the text in. *
|
||
|
* *
|
||
|
* OUTPUT: Returns with a pointer to the buffer. *
|
||
|
* *
|
||
|
* WARNINGS: none *
|
||
|
* *
|
||
|
* HISTORY: *
|
||
|
* 12/10/2001 MML : Created. *
|
||
|
*==============================================================================*/
|
||
|
|
||
|
const WCHAR* Locale_GetString( int StringID, WCHAR *String )
|
||
|
{
|
||
|
static WCHAR wide_buffer[ _MAX_PATH ];
|
||
|
|
||
|
memset( wide_buffer, '\0', _MAX_PATH );
|
||
|
|
||
|
#if( USE_MULTI_FILE_FORMAT )
|
||
|
wcscpy( wide_buffer, (WCHAR *)LOCALE_getstring( StringID ));
|
||
|
#else
|
||
|
wcscpy( wide_buffer, (WCHAR *)LOCALE_getstr( LocaleFile, StringID ));
|
||
|
#endif
|
||
|
|
||
|
Remove_Quotes_Around_String( wide_buffer );
|
||
|
|
||
|
if( String != NULL ) {
|
||
|
wcsncpy( String, wide_buffer, _MAX_PATH );
|
||
|
}
|
||
|
return wide_buffer;
|
||
|
}
|
||
|
|
||
|
/********************************************************************************
|
||
|
* Load_File -- Allocates a buffer and loads the file into it. *
|
||
|
* *
|
||
|
* Get a string usine Resource ID and a buffer. *
|
||
|
* *
|
||
|
* INPUT: int StringID -- The resource number of the string. *
|
||
|
* *
|
||
|
* OUTPUT: Returns with a pointer to the buffer. *
|
||
|
* *
|
||
|
* WARNINGS: none *
|
||
|
* *
|
||
|
* HISTORY: *
|
||
|
* 12/10/2001 MML : Created. *
|
||
|
*==============================================================================*/
|
||
|
|
||
|
const WCHAR* Locale_GetString( int StringID )
|
||
|
{
|
||
|
static WCHAR wide_buffer[ _MAX_PATH ];
|
||
|
|
||
|
memset( wide_buffer, '\0', _MAX_PATH );
|
||
|
|
||
|
#if( USE_MULTI_FILE_FORMAT )
|
||
|
wcscpy( wide_buffer, (WCHAR *)LOCALE_getstring( StringID ));
|
||
|
#else
|
||
|
wcscpy( wide_buffer, (WCHAR *)LOCALE_getstr( LocaleFile, StringID ));
|
||
|
#endif
|
||
|
|
||
|
Remove_Quotes_Around_String( wide_buffer );
|
||
|
|
||
|
return wide_buffer;
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************/
|
||
|
/* formating strings */
|
||
|
/****************************************************************************/
|
||
|
|
||
|
WCHAR *Remove_Quotes_Around_String ( WCHAR *old_string )
|
||
|
{
|
||
|
WCHAR wide_buffer[ _MAX_PATH * 3 ];
|
||
|
WCHAR * letter = old_string;
|
||
|
int length;
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
// If string is not NULL...
|
||
|
//----------------------------------------------------------------------
|
||
|
if ( *letter == '"' ) {
|
||
|
|
||
|
letter++;
|
||
|
wcscpy( wide_buffer, letter );
|
||
|
|
||
|
length = wcslen( wide_buffer );
|
||
|
|
||
|
if ( wide_buffer[ wcslen( wide_buffer )-1 ] == '"' ) {
|
||
|
wide_buffer[ wcslen( wide_buffer )-1 ] = '\0';
|
||
|
}
|
||
|
wcscpy( old_string, wide_buffer );
|
||
|
}
|
||
|
|
||
|
return( old_string );
|
||
|
}
|
||
|
|
||
|
|
||
|
/********************************************************************************
|
||
|
* Load_File -- Allocates a buffer and loads the file into it. *
|
||
|
* *
|
||
|
* This is the C++ replacement for the Load_Alloc_Data function. It will *
|
||
|
* allocate the memory big enough to hold the file & read the file into it. *
|
||
|
* *
|
||
|
* INPUT: file -- The file to read. *
|
||
|
* mem -- The memory system to use for allocation. *
|
||
|
* *
|
||
|
* OUTPUT: Returns with a pointer to the allocated and filled memory block. *
|
||
|
* *
|
||
|
* WARNINGS: none *
|
||
|
* *
|
||
|
* HISTORY: *
|
||
|
* 10/17/1994 JLB : Created. *
|
||
|
*==============================================================================*/
|
||
|
|
||
|
void * Load_File ( const char *filename, long *filesize )
|
||
|
{
|
||
|
int size, bytes_read;
|
||
|
void *ptr = NULL;
|
||
|
// StandardFileClass file;
|
||
|
RawFileClass file;
|
||
|
|
||
|
if ( filename == NULL || filename[0] == '\0' ) {
|
||
|
return( NULL );
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
// Open file in READ ONLY mode. If fails, exit.
|
||
|
//-------------------------------------------------------------------------
|
||
|
// file.Open( filename, MODE_READ_ONLY );
|
||
|
file.Open( filename, FileClass::READ );
|
||
|
// if( !file.Query_Open()) {
|
||
|
if( !file.Is_Open()) {
|
||
|
return( NULL );
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
// Get filesize and create a buffer.
|
||
|
//-------------------------------------------------------------------------
|
||
|
// size = file.Query_Size();
|
||
|
size = file.Size();
|
||
|
ptr = (void*)malloc(size + 1);
|
||
|
if ( !ptr ) {
|
||
|
return( NULL );
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
// Read data into the buffer, close the file.
|
||
|
//-------------------------------------------------------------------------
|
||
|
memset( ptr, '\0', size + 1 );
|
||
|
// bytes_read = file.Read( ptr, size );
|
||
|
bytes_read = file.Read( ptr, size );
|
||
|
// file.Close();
|
||
|
file.Close();
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
// Check return bytes. It should match the file size.
|
||
|
//-------------------------------------------------------------------------
|
||
|
assert( bytes_read == size );
|
||
|
if ( bytes_read != size ) {
|
||
|
free(ptr);
|
||
|
return( NULL );
|
||
|
}
|
||
|
|
||
|
if ( filesize != NULL ) {
|
||
|
*filesize = (long)size;
|
||
|
}
|
||
|
return( ptr );
|
||
|
}
|
||
|
|