/*
** Command & Conquer Generals Zero Hour(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 .
*/
/****************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
****************************************************************************
* *
* Project Name : Setup *
* *
* File Name : UTILS.C *
* *
* Programmers: Maria del Mar McCready Legg *
* *
* Start Date : December 12, 1992 *
* *
* Last Update : March 16, 1998 [MML] *
* *
*--------------------------------------------------------------------------*
* Functions: *
* *
* Clip_Line_To_Rect -- Clips a line (two points) against a *
* rectangle, using CS algorithm. *
* Compute_Code -- computes line clipping bit code for *
* point & rectangle. *
* Copy_File -- Copies a file from one dir to another. *
* Convert_Hex_To_Version -- Converts a hex num obtained from the *
* Registry, into a string *
* representation of a version *
* number ( XX.XX ). *
* Convert_Version_To_Hex -- Converts a string to an unsigned long. *
* Convert_To_Version_Format -- Converts version string's "," to "."s *
* Dialog_Box -- draws a dialog background box *
* Draw_Box -- Displays a highlighted box. *
* Fatal -- General purpose fatal error handler. *
* Get_Version -- Retrieves a version string from a file. *
* Get_String -- Returns a pointer to the undipped text. *
* Is_File_Available -- Use both FindFirst to check that CD is *
* in drive & if File_Exists() to *
* determine if file is really there. *
* Pad_With_Zeros -- Adds zeros to the beginning of string. *
* String_Width -- Calculate with of the string. *
* Strip_Newlines -- Remove '\r' from string passed in. *
* TextPtr -- Returns a pointer to the undipped text. *
* Path_Name_Valid -- Validate that the path has the correct *
* number of chars between '\' in the *
* path. *
* Path_Get_Next_Directory -- Return the next dir path from string. *
* Path_Add_Back_Slash -- Add a "\\" to the end of the string. *
* Path_Remove_Back_Slash -- Remove a '\\' at the end of the string. *
* Path_Trim_Blanks -- Trim lead/trail white spaces off string *
* Pad_With_Zeros -- Adds zeros to the beginning of string. *
* Remove_Ending_Spaces -- Remove any blank spaces at end of string*
* Remove_Spaces -- Remove spaces from string passed in. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
#include
#include "args.h"
#include "assert.h"
#include "locale_api.h"
#include "resource.h"
#include "utils.h"
#include "winfix.h"
#include "wnd_file.h"
#include
#include
//#include "resources.h"
//----------------------------------------------------------------------------
//
// Function: Fix_Single_Ampersands()
//
// Purpose: To replace each "&" with "&&" for display in a dialog.
// Some dialogs mistake a single "&" for an accelerator key.
//
// Input: pszString - any NULL terminated string.
//
// Returns: VOID (returns nothing)
//
// Comments: Modifies the characters in pszString.
//
//---------------------------------------------------------------------------
void Fix_Single_Ampersands ( LPSTR pszString, bool upper_case )
{
char pszTemp[ MAX_PATH ]; // variable to hold the string passed
char pszOld[ MAX_PATH ]; // variable to hold the string passed
char * letter;
int i = 0;
lstrcpy((LPSTR)pszOld, (LPSTR)pszString );
letter = pszOld;
memset ( pszTemp, '\0', MAX_PATH );
//----------------------------------------------------------------------
// While our ptr has not passed the end of the string...
//----------------------------------------------------------------------
while (*letter != '\0') {
if (*letter == '&') {
pszTemp[i++] = '&';
pszTemp[i++] = '&';
letter++;
} else {
if ( upper_case ) {
pszTemp[i++] = (char) toupper( *( letter++ ));
} else {
pszTemp[i++] = *(letter++);
}
}
}
strcpy((LPSTR)pszString, (LPSTR)pszTemp );
}
void Fix_Single_Ampersands ( wchar_t *pszString, bool upper_case )
{
wchar_t pszTemp[ MAX_PATH ]; // variable to hold the string passed
wchar_t pszOld[ MAX_PATH ]; // variable to hold the string passed
wchar_t *letter;
int i = 0;
wcscpy( pszOld, pszString );
letter = pszOld;
memset ( pszTemp, '\0', MAX_PATH );
//----------------------------------------------------------------------
// While our ptr has not passed the end of the string...
//----------------------------------------------------------------------
while (*letter != '\0') {
if (*letter == '&') {
pszTemp[i++] = '&';
pszTemp[i++] = '&';
letter++;
} else {
if ( upper_case ) {
pszTemp[i++] = (char) toupper( *( letter++ ));
} else {
pszTemp[i++] = *(letter++);
}
}
}
wcscpy( pszString, pszTemp );
}
////////////////UnicodeString Fix_Single_Ampersands( UnicodeString string, bool upper_case)
////////////////{
//////////////// UnicodeString retval;
////////////////
//////////////// Int i = 0;
//////////////// while (i < string.getLength()) {
//////////////// if (upper_case) {
//////////////// retval.concat(toupper(string.getCharAt(i)));
//////////////// } else {
//////////////// retval.concat(string.getCharAt(i));
//////////////// }
//////////////// if (string.getCharAt(i) == L'&') {
//////////////// retval.concat(string.getCharAt(i));
//////////////// }
//////////////// ++i;
//////////////// }
////////////////
//////////////// return retval;
////////////////}
//----------------------------------------------------------------------------
//
// Function: Fix_Double_Ampersands()
//
// Purpose: To replace each "&&" with "&" for display in a dialog.
// Some dialogs mistake a single "&" for an accelerator key.
//
// Input: pszString - any NULL terminated string.
//
// Returns: VOID (returns nothing)
//
// Comments: Modifies the characters in pszString.
//
//---------------------------------------------------------------------------
void Fix_Double_Ampersands ( LPSTR pszString, bool upper_case )
{
char pszTemp[ MAX_PATH ]; // variable to hold the string passed
char pszOld[ MAX_PATH ]; // variable to hold the string passed
char *letter;
int i = 0;
lstrcpy( (LPSTR)pszOld, (LPSTR)pszString );
letter = pszOld;
memset ( pszTemp, '\0', MAX_PATH );
//----------------------------------------------------------------------
// While our ptr has not passed the end of the string...
//----------------------------------------------------------------------
while (*letter != '\0') {
if ((*letter == '&') && (*( letter+1 ) == '&')) {
pszTemp[i++] = '&';
letter = letter + 2;
} else {
if ( upper_case ) {
pszTemp[i++] = (char) toupper( *( letter++ ));
} else {
pszTemp[i++] = *(letter++);
}
}
}
strcpy((LPSTR)pszString, (LPSTR)pszTemp );
}
/******************************************************************************
* Load_Alloc_Data -- 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_Alloc_Data( char *filename, long *filesize )
{
int size, bytes_read;
void *ptr = NULL;
StandardFileClass file;
//-------------------------------------------------------------------------
// Open file in READ ONLY mode. If fails, exit.
//-------------------------------------------------------------------------
file.Open( filename, MODE_READ_ONLY );
if ( !file.Query_Open()) {
return( NULL );
}
//-------------------------------------------------------------------------
// Get filesize and create a buffer.
//-------------------------------------------------------------------------
size = file.Query_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 );
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 );
}
/****************************************************************************
* MIXFILECLASS::LOAD_FILE -- Returns a buffer loaded with file desired. *
* *
* INPUT: none. * *
* *
* OUTPUT: none. *
* *
* WARNINGS: Searches MixFile first, then local directory. *
* Use free() to release buffer. * *
* *
* HISTORY: *
* 04/13/1998 ML/MG : Created. *
*==========================================================================*/
void *Load_File ( char *filename, long *filesize )
{
void *ptr = NULL;
if ( filename == NULL || filename[0] == '\0' ) {
return( NULL );
}
//-------------------------------------------------------------------------
// Try loading from local directory.
//-------------------------------------------------------------------------
ptr = Load_Alloc_Data( filename, filesize );
return( ptr );
}
/****************************************************************************
* MAKE_CURRENT_PATH_TO -- Returns a buffer to path desired. *
* *
* INPUT: none. * *
* *
* OUTPUT: none. *
* *
* WARNINGS: * *
* *
* HISTORY: *
* 10/08/2001 MML : Created. *
*==========================================================================*/
char *Make_Current_Path_To ( char *filename, char *path )
{
char szPath [ _MAX_PATH ];
char drive [ _MAX_DRIVE];
char dir [ _MAX_DIR ];
strcpy( szPath, Args->Get_argv(0));
_splitpath( szPath, drive, dir, NULL, NULL );
_makepath( szPath, drive, dir, NULL, NULL );
Path_Add_Back_Slash( szPath );
strcat( szPath, filename );
if( path != NULL ) {
strcpy( path, szPath );
}
return( path );
}
wchar_t *Make_Current_Path_To ( wchar_t *filename, wchar_t *path )
{
wchar_t szPath [ _MAX_PATH ];
wchar_t drive [ _MAX_DRIVE];
wchar_t dir [ _MAX_DIR ];
wcscpy( szPath, (wchar_t *)Args->Get_argv(0));
_wsplitpath( szPath, drive, dir, NULL, NULL );
_wmakepath( szPath, drive, dir, NULL, NULL );
Path_Add_Back_Slash( szPath );
wcscat( szPath, filename );
if( path != NULL ) {
wcscpy( path, szPath );
}
return( path );
}
/******************************************************************************
* Path_Add_Back_Slash -- Add a '\\' to the end of the path.
*
* INPUT: char * path -- Pointer to the string to be modified.
*
* OUTPUT: char * path
*
* WARNINGS: none
*
* HISTORY:
* 08/14/1998 MML : Created.
*============================================================================*/
char *Path_Add_Back_Slash ( char *path )
{
if ( path != NULL && *path != '\0' ) {
if ( path[ strlen( path )-1 ] != '\\' ) {
strcat( path, "\\" );
}
}
return( path );
}
wchar_t *Path_Add_Back_Slash ( wchar_t *path )
{
if ( path != NULL && *path != '\0' ) {
if ( path[ wcslen( path )-1 ] != '\\' ) {
wcscat( path, L"\\" );
}
}
return( path );
}
/******************************************************************************
* Path_Remove_Back_Slash -- Remove a '\\' from the end of the path.
*
* INPUT: char * path -- Pointer to the string to be modified.
*
* OUTPUT: char * path
*
* WARNINGS: none
*
* HISTORY:
* 08/14/1998 MML : Created.
*============================================================================*/
char *Path_Remove_Back_Slash ( char *path )
{
if ( path != NULL && *path != '\0' ) {
if ( path[ strlen( path )-1 ] == '\\' ) {
path[ strlen( path )-1 ] = '\0';
}
}
return( path );
}
wchar_t *Path_Remove_Back_Slash ( wchar_t *path )
{
if ( path != NULL && *path != '\0' ) {
if ( path[ wcslen( path )-1 ] == L'\\' ) {
path[ wcslen( path )-1 ] = L'\0';
}
}
return( path );
}
/*--------------------------------------------------------------------------*/
/* Function: PlugInProductName */
/* */
/* Descrip: The function plugs the product name defined in */
/* SdProductName() into %P found in the static message. */
/* It will search for the first nMax controls only. */
/* Misc: */
/* */
/*--------------------------------------------------------------------------*/
void PlugInProductName ( char *szString, char *szName )
{
int nCount, nMsgLength;
char szTextBuf[ MAX_PATH ];
char szOut[ MAX_PATH ];
char szProduct[ MAX_PATH ];
char * temp = NULL;
char * next = NULL;
if ( szName == NULL || szName[0] == '\0' ) {
return;
}
//--------------------------------------------------------------------------
// Find the first appearance of "%P".
//--------------------------------------------------------------------------
strcpy( szProduct, szName );
strcpy( szTextBuf, szString );
nMsgLength = strlen( szTextBuf );
nCount = 0;
temp = strstr( szTextBuf, "%s" );
//-------------------------------------------------------------
// Substitute each "%P" with "%s". nStrReturn is the index
// into the buffer where "%P" was found.
//-------------------------------------------------------------
while ( temp != NULL && nCount < 6) {
next = temp+1;
nCount = nCount + 1;
temp = strstr( next, "%s" );
}
//-------------------------------------------------------------
// Only support up to 5 product name per message.
// Do the substitution of the product name and store in szOut.
//-------------------------------------------------------------
switch( nCount ) {
case 1:
sprintf( szOut, szTextBuf, szProduct );
break;
case 2:
sprintf( szOut, szTextBuf, szProduct, szProduct );
break;
case 3:
sprintf( szOut, szTextBuf, szProduct, szProduct, szProduct );
break;
case 4:
sprintf( szOut, szTextBuf, szProduct, szProduct, szProduct, szProduct );
break;
case 5:
sprintf( szOut, szTextBuf, szProduct, szProduct, szProduct, szProduct, szProduct, szProduct );
break;
}
//-------------------------------------------------------------
// Replace szTextBuf with szOut.
//-------------------------------------------------------------
if ( nCount >= 1 ) {
strcpy( szString, szOut );
}
}
/*--------------------------------------------------------------------------*/
/* Function: PlugInProductName */
/* */
/* Descrip: The function plugs the product name defined in */
/* SdProductName() into %P found in the static message. */
/* It will search for the first nMax controls only. */
/* Misc: */
/* */
/*--------------------------------------------------------------------------*/
void PlugInProductName( char *szString, int nName )
{
/*
int nCount, nMsgLength;
char szTextBuf[ MAX_PATH ];
char szOut[ MAX_PATH ];
char szProduct[ MAX_PATH ];
char * temp = NULL;
char * next = NULL;
if ( nName <= STRNONE ) {
nName = STRNONE;
}
//--------------------------------------------------------------------------
// Find the first appearance of "%P".
//-------------------------------------------------------------
// LoadString( Main::hInstance, nName, szProduct, MAX_PATH );
Locale_GetString( nName, szProduct );
strcpy( szTextBuf, szString );
nMsgLength = strlen( szTextBuf );
nCount = 0;
temp = strstr( szTextBuf, "%s" );
//-------------------------------------------------------------
// Substitute each "%P" with "%s". nStrReturn is the index
// into the buffer where "%P" was found.
//-------------------------------------------------------------
while ( temp != NULL && nCount < 6) {
next = temp+1;
nCount = nCount + 1;
temp = strstr( next, "%s" );
}
//-------------------------------------------------------------
// Only support up to 5 product name per message.
// Do the substitution of the product name and store in szOut.
//-------------------------------------------------------------
switch( nCount ) {
case 1:
sprintf( szOut, szTextBuf, szProduct );
break;
case 2:
sprintf( szOut, szTextBuf, szProduct, szProduct );
break;
case 3:
sprintf( szOut, szTextBuf, szProduct, szProduct, szProduct );
break;
case 4:
sprintf( szOut, szTextBuf, szProduct, szProduct, szProduct, szProduct );
break;
case 5:
sprintf( szOut, szTextBuf, szProduct, szProduct, szProduct, szProduct, szProduct, szProduct );
break;
}
//-------------------------------------------------------------
// Replace szTextBuf with szOut.
//-------------------------------------------------------------
if ( nCount >= 1 ) {
strcpy( szString, szOut );
}
*/
}
/*--------------------------------------------------------------------------*/
/* Function: PlugInProductName */
/* */
/* Descrip: The function plugs the product name defined in */
/* SdProductName() into %P found in the static message. */
/* It will search for the first nMax controls only. */
/* Misc: */
/* */
/*--------------------------------------------------------------------------*/
void PlugInProductName ( wchar_t *szString, const wchar_t *szName )
{
int nCount, nMsgLength;
wchar_t szTextBuf[ MAX_PATH ];
wchar_t szOut[ MAX_PATH ];
wchar_t szProduct[ MAX_PATH ];
wchar_t *temp = NULL;
wchar_t *next = NULL;
if ( szName == NULL || szName[0] == '\0' ) {
return;
}
//--------------------------------------------------------------------------
// Find the first appearance of "%P".
//--------------------------------------------------------------------------
wcscpy( szProduct, szName );
wcscpy( szTextBuf, szString );
nMsgLength = wcslen( szTextBuf );
nCount = 0;
temp = wcsstr( szTextBuf, L"%s" );
//-------------------------------------------------------------
// Substitute each "%P" with "%s". nStrReturn is the index
// into the buffer where "%P" was found.
//-------------------------------------------------------------
while ( temp != NULL && nCount < 6) {
next = temp+1;
nCount = nCount + 1;
temp = wcsstr( next, L"%s" );
}
//-------------------------------------------------------------
// Only support up to 5 product name per message.
// Do the substitution of the product name and store in szOut.
//-------------------------------------------------------------
switch( nCount ) {
case 1:
swprintf( szOut, szTextBuf, szProduct );
break;
case 2:
swprintf( szOut, szTextBuf, szProduct, szProduct );
break;
case 3:
swprintf( szOut, szTextBuf, szProduct, szProduct, szProduct );
break;
case 4:
swprintf( szOut, szTextBuf, szProduct, szProduct, szProduct, szProduct );
break;
case 5:
swprintf( szOut, szTextBuf, szProduct, szProduct, szProduct, szProduct, szProduct, szProduct );
break;
}
//-------------------------------------------------------------
// Replace szTextBuf with szOut.
//-------------------------------------------------------------
if ( nCount >= 1 ) {
wcscpy( szString, szOut );
}
}