Initial commit of Command & Conquer Red Alert source code.
This commit is contained in:
213
LAUNCHER/256BMP.C
Normal file
213
LAUNCHER/256BMP.C
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <alloc.h>
|
||||
|
||||
DWORD GetDibInfoHeaderSize (BYTE huge *);
|
||||
WORD GetDibWidth (BYTE huge *);
|
||||
WORD GetDibHeight (BYTE huge *);
|
||||
BYTE huge * GetDibBitsAddr (BYTE huge *);
|
||||
BYTE huge * ReadDib(char *);
|
||||
|
||||
//-------------------------------------------------------------//
|
||||
|
||||
DWORD GetDibInfoHeaderSize (BYTE huge * lpDib)
|
||||
{
|
||||
return ((BITMAPINFOHEADER huge *) lpDib)->biSize ;
|
||||
}
|
||||
|
||||
WORD GetDibWidth (BYTE huge * lpDib)
|
||||
{
|
||||
if (GetDibInfoHeaderSize (lpDib) == sizeof (BITMAPCOREHEADER))
|
||||
return (WORD) (((BITMAPCOREHEADER huge *) lpDib)->bcWidth) ;
|
||||
else
|
||||
return (WORD) (((BITMAPINFOHEADER huge *) lpDib)->biWidth) ;
|
||||
}
|
||||
|
||||
WORD GetDibHeight (BYTE huge * lpDib)
|
||||
{
|
||||
if (GetDibInfoHeaderSize (lpDib) == sizeof (BITMAPCOREHEADER))
|
||||
return (WORD) (((BITMAPCOREHEADER huge *) lpDib)->bcHeight) ;
|
||||
else
|
||||
return (WORD) (((BITMAPINFOHEADER huge *) lpDib)->biHeight) ;
|
||||
}
|
||||
|
||||
BYTE huge * GetDibBitsAddr (BYTE huge * lpDib)
|
||||
{
|
||||
DWORD dwNumColors, dwColorTableSize ;
|
||||
WORD wBitCount ;
|
||||
|
||||
if (GetDibInfoHeaderSize (lpDib) == sizeof (BITMAPCOREHEADER))
|
||||
{
|
||||
wBitCount = ((BITMAPCOREHEADER huge *) lpDib)->bcBitCount ;
|
||||
|
||||
if (wBitCount != 24)
|
||||
dwNumColors = 1L << wBitCount ;
|
||||
else
|
||||
dwNumColors = 0 ;
|
||||
|
||||
dwColorTableSize = dwNumColors * sizeof (RGBTRIPLE) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
wBitCount = ((BITMAPINFOHEADER huge *) lpDib)->biBitCount ;
|
||||
|
||||
if (GetDibInfoHeaderSize (lpDib) >= 36)
|
||||
dwNumColors = ((BITMAPINFOHEADER huge *) lpDib)->biClrUsed ;
|
||||
else
|
||||
dwNumColors = 0 ;
|
||||
|
||||
if (dwNumColors == 0)
|
||||
{
|
||||
if (wBitCount != 24)
|
||||
dwNumColors = 1L << wBitCount ;
|
||||
else
|
||||
dwNumColors = 0 ;
|
||||
}
|
||||
|
||||
dwColorTableSize = dwNumColors * sizeof (RGBQUAD) ;
|
||||
}
|
||||
|
||||
return lpDib + GetDibInfoHeaderSize (lpDib) + dwColorTableSize ;
|
||||
}
|
||||
|
||||
// Read a DIB from a file into memory
|
||||
BYTE huge * ReadDib (char * szFileName)
|
||||
{
|
||||
BITMAPFILEHEADER bmfh ;
|
||||
BYTE huge * lpDib ;
|
||||
DWORD dwDibSize, dwOffset, dwHeaderSize ;
|
||||
int hFile ;
|
||||
WORD wDibRead ;
|
||||
|
||||
if (-1 == (hFile = _lopen (szFileName, OF_READ | OF_SHARE_DENY_WRITE)))
|
||||
return NULL ;
|
||||
|
||||
if (_lread (hFile, (LPSTR) &bmfh, sizeof (BITMAPFILEHEADER)) !=
|
||||
sizeof (BITMAPFILEHEADER))
|
||||
{
|
||||
_lclose (hFile) ;
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
if (bmfh.bfType != * (WORD *) "BM")
|
||||
{
|
||||
_lclose (hFile) ;
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
dwDibSize = bmfh.bfSize - sizeof (BITMAPFILEHEADER) ;
|
||||
|
||||
lpDib = (BYTE huge * ) GlobalAllocPtr (GMEM_MOVEABLE, dwDibSize) ;
|
||||
|
||||
if (lpDib == NULL)
|
||||
{
|
||||
_lclose (hFile) ;
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
dwOffset = 0 ;
|
||||
|
||||
while (dwDibSize > 0)
|
||||
{
|
||||
wDibRead = (WORD) min (32768ul, dwDibSize) ;
|
||||
|
||||
if (wDibRead != _lread (hFile, (LPSTR) (lpDib + dwOffset), wDibRead))
|
||||
{
|
||||
_lclose (hFile) ;
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
dwDibSize -= wDibRead ;
|
||||
dwOffset += wDibRead ;
|
||||
}
|
||||
|
||||
_lclose (hFile) ;
|
||||
|
||||
dwHeaderSize = GetDibInfoHeaderSize (lpDib) ;
|
||||
|
||||
if (dwHeaderSize < 12 || (dwHeaderSize > 12 && dwHeaderSize < 16))
|
||||
return NULL ;
|
||||
return lpDib ;
|
||||
}
|
||||
|
||||
long FAR PASCAL _export MainWndProc(HWND hWnd,UINT message,UINT wParam,LONG lParam)
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc;
|
||||
RECT rect;
|
||||
unsigned char r,g,b,x;
|
||||
FILE *fi;
|
||||
int i;
|
||||
|
||||
static BYTE huge *lpDib;
|
||||
static BYTE huge *lpDibBits;
|
||||
static int cxDib, cyDib;
|
||||
static LPLOGPALETTE LogPal;
|
||||
static HPALETTE hLogPal;
|
||||
|
||||
switch(message)
|
||||
{
|
||||
case WM_CREATE:
|
||||
fi=fopen("somefile.bmp","r");
|
||||
if(fi==NULL)
|
||||
return 0;
|
||||
|
||||
LogPal=(LPLOGPALETTE)farmalloc(sizeof(LOGPALETTE)+sizeof(PALETTEENTRY)*256);
|
||||
LogPal->palVersion=0x300;
|
||||
LogPal->palNumEntries=256;
|
||||
|
||||
fseek(fi,54L,0);
|
||||
for(i=0;i<256;i++)
|
||||
{
|
||||
fscanf(fi,"%c%c%c%c",&b,&g,&r,&x);
|
||||
LogPal->palPalEntry[i].peRed=r;
|
||||
LogPal->palPalEntry[i].peGreen=g;
|
||||
LogPal->palPalEntry[i].peBlue=b;
|
||||
LogPal->palPalEntry[i].peFlags=x;
|
||||
}
|
||||
fclose(fi);
|
||||
hLogPal=CreatePalette(LogPal);
|
||||
return 0;
|
||||
case WM_PAINT:
|
||||
hdc=BeginPaint(hWnd,&ps);
|
||||
GetClientRect(hWnd,&rect);
|
||||
SelectPalette(hdc,hLogPal,0);
|
||||
RealizePalette(hdc);
|
||||
|
||||
SetStretchBltMode(hdc,COLORONCOLOR);
|
||||
lpDib=ReadDib(bmp_fname);
|
||||
lpDibBits=GetDibBitsAddr(lpDib);
|
||||
cxDib=GetDibWidth(lpDib);
|
||||
cyDib=GetDibHeight(lpDib);
|
||||
StretchDIBits(hdc,0,0,rect.right,rect.bottom,0,0,cxDib,cyDib,(LPSTR)lpDibBits,
|
||||
(LPBITMAPINFO)lpDib,DIB_RGB_COLORS,SRCCOPY);
|
||||
EndPaint(hWnd,&ps);
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
farfree(LogPal);
|
||||
DeleteObject(hLogPal);
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
default:
|
||||
return (DefWindowProc(hWnd,message,wParam,lParam));
|
||||
}
|
||||
return (DefWindowProc(hWnd,message,wParam,lParam));
|
||||
}
|
18
LAUNCHER/BITMAP.CPP
Normal file
18
LAUNCHER/BITMAP.CPP
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
165
LAUNCHER/CONFIGFILE.CPP
Normal file
165
LAUNCHER/CONFIGFILE.CPP
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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 S T U D I O S *
|
||||
******************************************************************************
|
||||
Project Name: Carpenter (The RedAlert ladder creator)
|
||||
File Name : configfile.cpp
|
||||
Author : Neal Kettler
|
||||
Start Date : June 9, 1997
|
||||
Last Update : June 17, 1997
|
||||
|
||||
|
||||
This class will read in a config file and store the key value pairs for
|
||||
later access. This is a fairly simple class, the config file is assumed
|
||||
to be of the form:
|
||||
|
||||
#comment
|
||||
key = value
|
||||
|
||||
The value can then be retrieved as a string or an integer. The key on
|
||||
the left is used for retrieval and it must be specified in uppercase
|
||||
for the 'get' functions. E.g. getString("KEY",valWstring);
|
||||
\***************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "configfile.h"
|
||||
|
||||
static uint32 Wstring_Hash(Wstring &string);
|
||||
static char *Eat_Spaces(char *string);
|
||||
|
||||
ConfigFile::ConfigFile() : dictionary(Wstring_Hash)
|
||||
{ }
|
||||
|
||||
ConfigFile::~ConfigFile()
|
||||
{ }
|
||||
|
||||
// Read and parse the config file. The key value pairs will be stored
|
||||
// for later access by the getString/getInt functions.
|
||||
bit8 ConfigFile::readFile(FILE *in)
|
||||
{
|
||||
char string[256];
|
||||
Wstring key;
|
||||
Wstring value;
|
||||
char *cptr;
|
||||
|
||||
memset(string,0,256);
|
||||
while (fgets(string,256,in))
|
||||
{
|
||||
cptr=Eat_Spaces(string);
|
||||
if ((*cptr==0)||(*cptr=='#')) // '#' signals a comment
|
||||
continue;
|
||||
if (strchr(cptr,'=')==NULL) // All config entries must have a '='
|
||||
continue;
|
||||
key=cptr;
|
||||
key.truncate('=');
|
||||
key.removeSpaces(); // No spaces allowed in the key
|
||||
key.toUpper(); // make key all caps
|
||||
cptr=Eat_Spaces(strchr(cptr,'=')+1); // Jump to after the '='
|
||||
value=cptr;
|
||||
value.truncate('\r');
|
||||
value.truncate('\n');
|
||||
dictionary.add(key,value);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
// Get a config entry as a string
|
||||
bit8 ConfigFile::getString(Wstring &key,Wstring &value)
|
||||
{
|
||||
return(dictionary.getValue(key,value));
|
||||
}
|
||||
|
||||
// Get a config entry as a string
|
||||
bit8 ConfigFile::getString(char *key,Wstring &value)
|
||||
{
|
||||
Wstring sKey;
|
||||
sKey.set(key);
|
||||
return(getString(sKey,value));
|
||||
}
|
||||
|
||||
// Get a config entry as an integer
|
||||
bit8 ConfigFile::getInt(Wstring &key,sint32 &value)
|
||||
{
|
||||
Wstring svalue;
|
||||
bit8 retval=dictionary.getValue(key,svalue);
|
||||
if (retval==FALSE)
|
||||
return(FALSE);
|
||||
value=atol(svalue.get());
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
// Get a config entry as an integer
|
||||
bit8 ConfigFile::getInt(char *key,sint32 &value)
|
||||
{
|
||||
Wstring sKey;
|
||||
sKey.set(key);
|
||||
return(getInt(sKey,value));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Get a config entry as an integer
|
||||
bit8 ConfigFile::getInt(Wstring &key,sint16 &value)
|
||||
{
|
||||
Wstring svalue;
|
||||
bit8 retval=dictionary.getValue(key,svalue);
|
||||
if (retval==FALSE)
|
||||
return(FALSE);
|
||||
value=atoi(svalue.get());
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
// Get a config entry as an integer
|
||||
bit8 ConfigFile::getInt(char *key,sint16 &value)
|
||||
{
|
||||
Wstring sKey;
|
||||
sKey.set(key);
|
||||
return(getInt(sKey,value));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/************* Static functions below **************/
|
||||
|
||||
// Given a Wstring, return a 32 bit integer that has a good numeric
|
||||
// distributation for the purposes of indexing into a hash table.
|
||||
static uint32 Wstring_Hash(Wstring &string)
|
||||
{
|
||||
uint32 retval=0;
|
||||
retval=string.length();
|
||||
for (uint32 i=0; i<string.length(); i++)
|
||||
{
|
||||
retval+=*(string.get()+i);
|
||||
retval+=i;
|
||||
retval=(retval<<8)^(retval>>24); // ROL 8
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
|
||||
static char *Eat_Spaces(char *string)
|
||||
{
|
||||
char *retval=string;
|
||||
while (isspace(*retval))
|
||||
retval++;
|
||||
return(retval);
|
||||
}
|
55
LAUNCHER/CONFIGFILE.H
Normal file
55
LAUNCHER/CONFIGFILE.H
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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 S T U D I O S *
|
||||
******************************************************************************
|
||||
Project Name: Carpenter (The RedAlert ladder creator)
|
||||
File Name : configfile.h
|
||||
Author : Neal Kettler
|
||||
Start Date : June 9, 1997
|
||||
Last Update : June 17, 1997
|
||||
\***************************************************************************/
|
||||
|
||||
#ifndef CONFIGFILE_HEADER
|
||||
#define CONFIGFILE_HEADER
|
||||
|
||||
#include "dictionary.h"
|
||||
#include "wstring.h"
|
||||
|
||||
class ConfigFile
|
||||
{
|
||||
public:
|
||||
ConfigFile();
|
||||
~ConfigFile();
|
||||
bit8 readFile(IN FILE *config);
|
||||
bit8 getString(IN Wstring &key,OUT Wstring &value);
|
||||
bit8 getString(IN char *key,OUT Wstring &value);
|
||||
|
||||
bit8 getInt(IN Wstring &key,OUT sint32 &value);
|
||||
bit8 getInt(IN char *key,OUT sint32 &value);
|
||||
|
||||
bit8 getInt(IN Wstring &key,OUT sint16 &value);
|
||||
bit8 getInt(IN char *key,OUT sint16 &value);
|
||||
|
||||
private:
|
||||
Dictionary<Wstring,Wstring> dictionary; // stores the mappings from keys
|
||||
// to value strings
|
||||
};
|
||||
|
||||
#endif
|
80
LAUNCHER/DIALOG.CPP
Normal file
80
LAUNCHER/DIALOG.CPP
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
//
|
||||
// Create the dialog used during the patching process.
|
||||
//
|
||||
#include"winblows.h"
|
||||
#include"resource.h"
|
||||
#include"loadbmp.h"
|
||||
#include<commctrl.h>
|
||||
|
||||
HWND PatchDialog;
|
||||
BOOL CALLBACK Patch_Window_Proc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
HWND Create_Patch_Dialog(void)
|
||||
{
|
||||
PatchDialog=CreateDialog(Global_instance, MAKEINTRESOURCE(IDD_DIALOG1),
|
||||
NULL, (DLGPROC)Patch_Window_Proc);
|
||||
|
||||
ShowWindow(PatchDialog, SW_NORMAL);
|
||||
SetForegroundWindow(PatchDialog);
|
||||
return(PatchDialog);
|
||||
}
|
||||
|
||||
BOOL CALLBACK Patch_Window_Proc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
|
||||
static LoadBmp bmpLoader;
|
||||
|
||||
switch(iMsg) {
|
||||
case WM_INITDIALOG:
|
||||
// progress bar
|
||||
SendMessage(GetDlgItem(hwnd,IDC_PROGRESS2),PBM_SETRANGE,
|
||||
0,MAKELPARAM(0,100));
|
||||
SendMessage(GetDlgItem(hwnd,IDC_PROGRESS2),PBM_SETPOS,0,0);
|
||||
SendMessage(GetDlgItem(hwnd,IDC_PROGRESS2),PBM_SETSTEP,10,0);
|
||||
|
||||
bmpLoader.init("launcher.bmp",GetDlgItem(hwnd,IDC_SPLASH));
|
||||
return(TRUE); // True means windows handles focus issues
|
||||
break;
|
||||
case WM_PAINT:
|
||||
bmpLoader.drawBmp();
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
/* May want to add cancel later
|
||||
switch(wParam) {
|
||||
case IDCANCEL:
|
||||
{
|
||||
// do some stuff
|
||||
return(TRUE);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
*************/
|
||||
break;
|
||||
case WM_CLOSE:
|
||||
DestroyWindow(hwnd);
|
||||
PostQuitMessage(0);
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
return(FALSE);
|
||||
}
|
28
LAUNCHER/DIALOG.H
Normal file
28
LAUNCHER/DIALOG.H
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#ifndef DIALOG_HEADER
|
||||
#define DIALOG_HEADER
|
||||
|
||||
#include"winblows.h"
|
||||
#include<commctrl.h>
|
||||
HWND Create_Patch_Dialog(void);
|
||||
|
||||
extern HWND PatchDialog;
|
||||
|
||||
#endif
|
586
LAUNCHER/DICTIONARY.H
Normal file
586
LAUNCHER/DICTIONARY.H
Normal file
@@ -0,0 +1,586 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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 S T U D I O S *
|
||||
******************************************************************************
|
||||
Project Name: Carpenter (The RedAlert ladder creator)
|
||||
File Name : dictionary.h
|
||||
Author : Neal Kettler
|
||||
Start Date : June 1, 1997
|
||||
Last Update : June 17, 1997
|
||||
|
||||
This template file implements a hash dictionary. A hash dictionary is
|
||||
used to quickly match a value with a key. This works well for very
|
||||
large sets of data. A table is constructed that has some power of two
|
||||
number of pointers in it. Any value to be put in the table has a hashing
|
||||
function applied to the key. That key/value pair is then put in the
|
||||
linked list at the slot the hashing function specifies. If everything
|
||||
is working well, this is much faster than a linked list, but only if
|
||||
your hashing function is good.
|
||||
\****************************************************************************/
|
||||
|
||||
#ifndef DICTIONARY_HEADER
|
||||
#define DICTIONARY_HEADER
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "wstypes.h"
|
||||
#include "wdebug.h"
|
||||
|
||||
// Every entry in the hash dictionary must be an instance of the DNode
|
||||
// template. 'K' and 'V' denote Key and Value.
|
||||
template <class K,class V>
|
||||
class DNode
|
||||
{
|
||||
public:
|
||||
K key;
|
||||
V value;
|
||||
DNode<K,V> *hashNext;
|
||||
};
|
||||
|
||||
template <class K,class V>
|
||||
class Dictionary
|
||||
{
|
||||
public:
|
||||
Dictionary(uint32 (* hashFn)(K &key));
|
||||
~Dictionary();
|
||||
|
||||
void clear(void);
|
||||
bit8 add(IN K &key,IN V &value);
|
||||
bit8 getValue(IN K &key, OUT V &value);
|
||||
void print(IN FILE *out) const;
|
||||
uint32 getSize(void) const;
|
||||
uint32 getEntries(void) const;
|
||||
bit8 contains(IN K &key);
|
||||
bit8 updateValue(IN K &key,IN V &value);
|
||||
bit8 remove(IN K &key,OUT V &value);
|
||||
bit8 remove(IN K &key);
|
||||
bit8 removeAny(OUT K &key,OUT V &value);
|
||||
bit8 iterate(INOUT int &index,INOUT int &offset, OUT V &value) const;
|
||||
|
||||
private:
|
||||
void shrink(void); // halve the number of slots
|
||||
void expand(void); // double the number of slots
|
||||
|
||||
|
||||
DNode<K,V> **table; // This stores the lists at each slot
|
||||
|
||||
uint32 entries; // number of entries
|
||||
uint32 size; // size of table
|
||||
uint32 tableBits; // table is 2^tableBits big
|
||||
uint32 log2Size; // Junk variable
|
||||
bit8 keepSize; // If true don't shrink or expand
|
||||
|
||||
uint32 (* hashFunc)(K &key); // User provided hash function
|
||||
uint32 keyHash(IN K &key); // This will reduce to correct range
|
||||
|
||||
|
||||
// See initilizer list of constructor for values
|
||||
const double SHRINK_THRESHOLD; // When table is this % full shrink it
|
||||
const double EXPAND_THRESHOLD; // When table is this % full grow it
|
||||
const int MIN_TABLE_SIZE; // must be a power of 2
|
||||
};
|
||||
|
||||
|
||||
//Create the empty hash dictionary
|
||||
template <class K,class V>
|
||||
Dictionary<K,V>::Dictionary(uint32 (* hashFn)(K &key)) :
|
||||
SHRINK_THRESHOLD(0.20), // When table is only 20% full shrink it
|
||||
EXPAND_THRESHOLD(0.80), // When table is 80% full grow it
|
||||
MIN_TABLE_SIZE(32) // must be a power of 2
|
||||
{
|
||||
log2Size=MIN_TABLE_SIZE;
|
||||
size=MIN_TABLE_SIZE;
|
||||
assert(size>=4);
|
||||
tableBits=0;
|
||||
while(log2Size) { tableBits++; log2Size>>=1; }
|
||||
tableBits--;
|
||||
size=1<<tableBits; //Just in case MIN_TABLE_SIZE wasn't a power of 2
|
||||
entries=0;
|
||||
keepSize=FALSE;
|
||||
|
||||
//Table is a pointer to a list of pointers (the hash table)
|
||||
table=(DNode<K,V> **)new DNode<K,V>* [size];
|
||||
assert(table!=NULL);
|
||||
|
||||
memset((void *)table,0,size*sizeof(void *));
|
||||
hashFunc=hashFn;
|
||||
}
|
||||
|
||||
//Free all the memory...
|
||||
template <class K,class V>
|
||||
Dictionary<K,V>::~Dictionary()
|
||||
{
|
||||
clear(); // Remove the entries
|
||||
delete[](table); // And the table as well
|
||||
}
|
||||
|
||||
// Remove all the entries and free the memory
|
||||
template <class K,class V>
|
||||
void Dictionary<K,V>::clear()
|
||||
{
|
||||
DNode<K,V> *temp,*del;
|
||||
uint32 i;
|
||||
//free all the data
|
||||
for (i=0; i<size; i++)
|
||||
{
|
||||
temp=table[i];
|
||||
while(temp!=NULL)
|
||||
{
|
||||
del=temp;
|
||||
temp=temp->hashNext;
|
||||
delete(del);
|
||||
}
|
||||
table[i]=NULL;
|
||||
}
|
||||
entries=0;
|
||||
|
||||
while ((getSize()>(uint32)MIN_TABLE_SIZE)&&(keepSize==FALSE))
|
||||
shrink();
|
||||
}
|
||||
|
||||
template <class K,class V>
|
||||
uint32 Dictionary<K,V>::keyHash(IN K &key)
|
||||
{
|
||||
uint32 retval=hashFunc(key);
|
||||
retval &= ((1<<tableBits)-1);
|
||||
assert(retval<getSize());
|
||||
return(retval);
|
||||
}
|
||||
|
||||
|
||||
template <class K,class V>
|
||||
void Dictionary<K,V>::print(IN FILE *out) const
|
||||
{
|
||||
DNode<K,V> *temp;
|
||||
uint32 i;
|
||||
|
||||
fprintf(out,"--------------------\n");
|
||||
for (i=0; i<getSize(); i++)
|
||||
{
|
||||
temp=table[i];
|
||||
|
||||
fprintf(out," |\n");
|
||||
fprintf(out,"[ ]");
|
||||
|
||||
while (temp!=NULL)
|
||||
{
|
||||
fprintf(out,"--[ ]");
|
||||
temp=temp->hashNext;
|
||||
}
|
||||
fprintf(out,"\n");
|
||||
}
|
||||
fprintf(out,"--------------------\n");
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Iterate through all the records. Index is for the table, offset specifies the
|
||||
// element in the linked list. Set both to 0 and continue calling till false
|
||||
// is returned.
|
||||
template <class K,class V>
|
||||
bit8 Dictionary<K,V>::iterate(INOUT int &index,INOUT int &offset,
|
||||
OUT V &value) const
|
||||
{
|
||||
DNode<K,V> *temp;
|
||||
|
||||
// index out of range
|
||||
if ((index<0)||(index >= getSize()))
|
||||
return(FALSE);
|
||||
|
||||
temp=table[index];
|
||||
while ((temp==NULL)&&((++index) < getSize()))
|
||||
{
|
||||
temp=table[index];
|
||||
offset=0;
|
||||
}
|
||||
|
||||
if (temp==NULL) // no more slots with data
|
||||
return(FALSE);
|
||||
|
||||
uint32 i=0;
|
||||
while ((temp!=NULL) && (i < offset))
|
||||
{
|
||||
temp=temp->hashNext;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (temp==NULL) // should never happen
|
||||
return(FALSE);
|
||||
|
||||
value=temp->value;
|
||||
if (temp->hashNext==NULL)
|
||||
{
|
||||
index++;
|
||||
offset=0;
|
||||
}
|
||||
else
|
||||
offset++;
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Return the current size of the hash table
|
||||
template <class K,class V>
|
||||
uint32 Dictionary<K,V>::getSize(void) const
|
||||
{ return(size); }
|
||||
|
||||
|
||||
// Return the current number of entries in the table
|
||||
template <class K,class V>
|
||||
uint32 Dictionary<K,V>::getEntries(void) const
|
||||
{ return(entries); }
|
||||
|
||||
|
||||
// Does the Dictionary contain the key?
|
||||
template <class K,class V>
|
||||
bit8 Dictionary<K,V>::contains(IN K &key)
|
||||
{
|
||||
int offset;
|
||||
DNode<K,V> *node;
|
||||
|
||||
offset=keyHash(key);
|
||||
|
||||
node=table[offset];
|
||||
|
||||
if (node==NULL)
|
||||
{ return(FALSE); } // can't find it
|
||||
|
||||
while(node!=NULL)
|
||||
{
|
||||
if ((node->key)==key)
|
||||
{ return(TRUE); }
|
||||
node=node->hashNext;
|
||||
}
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
|
||||
// Try and update the value of an already existing object
|
||||
template <class K,class V>
|
||||
bit8 Dictionary<K,V>::updateValue(IN K &key,IN V &value)
|
||||
{
|
||||
sint32 retval;
|
||||
|
||||
retval=remove(key);
|
||||
if (retval==FALSE)
|
||||
return(FALSE);
|
||||
|
||||
add(key,value);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// Add to the dictionary (if key exists, value is updated with the new V)
|
||||
template <class K, class V>
|
||||
bit8 Dictionary<K,V>::add(IN K &key,IN V &value)
|
||||
{
|
||||
int offset;
|
||||
DNode<K,V> *node,*item,*temp;
|
||||
float percent;
|
||||
|
||||
item=(DNode<K,V> *)new DNode<K,V>;
|
||||
assert(item!=NULL);
|
||||
|
||||
#ifdef KEY_MEM_OPS
|
||||
memcpy(&(item->key),&key,sizeof(K));
|
||||
#else
|
||||
item->key=key;
|
||||
#endif
|
||||
|
||||
#ifdef VALUE_MEM_OPS
|
||||
memcpy(&(item->value),&value,sizeof(V));
|
||||
#else
|
||||
item->value=value;
|
||||
#endif
|
||||
|
||||
item->hashNext=NULL;
|
||||
|
||||
//If key already exists, it will be overwritten
|
||||
remove(key);
|
||||
|
||||
offset=keyHash(key);
|
||||
|
||||
node=table[offset];
|
||||
|
||||
if (node==NULL)
|
||||
{ table[offset]=item; }
|
||||
else
|
||||
{
|
||||
temp=table[offset];
|
||||
table[offset]=item;
|
||||
item->hashNext=temp;
|
||||
}
|
||||
|
||||
entries++;
|
||||
percent=(float)entries;
|
||||
percent/=(float)getSize();
|
||||
if (percent>= EXPAND_THRESHOLD ) expand();
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
// Remove an item from the dictionary
|
||||
template <class K,class V>
|
||||
bit8 Dictionary<K,V>::remove(IN K &key,OUT V &value)
|
||||
{
|
||||
int offset;
|
||||
DNode<K,V> *node,*last,*temp;
|
||||
float percent;
|
||||
|
||||
if (entries==0)
|
||||
return(FALSE);
|
||||
|
||||
percent=(float)(entries-1);
|
||||
percent/=(float)getSize();
|
||||
|
||||
offset=keyHash(key);
|
||||
node=table[offset];
|
||||
|
||||
last=node;
|
||||
if (node==NULL) return(FALSE);
|
||||
|
||||
//special case table points to thing to delete
|
||||
|
||||
#ifdef KEY_MEM_OPS
|
||||
if (0==memcmp(&(node->key),&key,sizeof(K)))
|
||||
#else
|
||||
if ((node->key)==key)
|
||||
#endif
|
||||
{
|
||||
#ifdef VALUE_MEM_OPS
|
||||
memcpy(&value,&(node->value),sizeof(V));
|
||||
#else
|
||||
value=node->value;
|
||||
#endif
|
||||
temp=table[offset]->hashNext;
|
||||
delete(table[offset]);
|
||||
table[offset]=temp;
|
||||
entries--;
|
||||
if (percent <= SHRINK_THRESHOLD)
|
||||
shrink();
|
||||
return(TRUE);
|
||||
}
|
||||
node=node->hashNext;
|
||||
|
||||
//Now the case if the thing to delete is not the first
|
||||
while (node!=NULL)
|
||||
{
|
||||
#ifdef KEY_MEM_OPS
|
||||
if (0==memcmp(&(node->key),&key,sizeof(K)))
|
||||
#else
|
||||
if (node->key==key)
|
||||
#endif
|
||||
{
|
||||
#ifdef VALUE_MEM_OPS
|
||||
memcpy(&value,&(node->value),sizeof(V));
|
||||
#else
|
||||
value=node->value;
|
||||
#endif
|
||||
last->hashNext=node->hashNext;
|
||||
entries--;
|
||||
delete(node);
|
||||
break;
|
||||
}
|
||||
last=node;
|
||||
node=node->hashNext;
|
||||
}
|
||||
|
||||
if (percent <= SHRINK_THRESHOLD)
|
||||
shrink();
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
template <class K,class V>
|
||||
bit8 Dictionary<K,V>::remove(IN K &key)
|
||||
{
|
||||
V temp;
|
||||
return(remove(key,temp));
|
||||
}
|
||||
|
||||
|
||||
// Remove some random K/V pair that's in the Dictionary
|
||||
template <class K,class V>
|
||||
bit8 Dictionary<K,V>::removeAny(OUT K &key,OUT V &value)
|
||||
{
|
||||
int offset;
|
||||
DNode<K,V> *node,*last,*temp;
|
||||
float percent;
|
||||
|
||||
if (entries==0)
|
||||
return(FALSE);
|
||||
|
||||
percent=(entries-1);
|
||||
percent/=(float)getSize();
|
||||
|
||||
int i;
|
||||
offset=-1;
|
||||
for (i=0; i<(int)getSize(); i++)
|
||||
if (table[i]!=NULL)
|
||||
{
|
||||
offset=i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (offset==-1) // Nothing there
|
||||
return(FALSE);
|
||||
|
||||
node=table[offset];
|
||||
last=node;
|
||||
|
||||
#ifdef KEY_MEM_OPS
|
||||
memcpy(&key,&(node->key),sizeof(K));
|
||||
#else
|
||||
key=node->key;
|
||||
#endif
|
||||
#ifdef VALUE_MEM_OPS
|
||||
memcpy(&value,&(node->value),sizeof(V));
|
||||
#else
|
||||
value=node->value;
|
||||
#endif
|
||||
|
||||
temp=table[offset]->hashNext;
|
||||
delete(table[offset]);
|
||||
table[offset]=temp;
|
||||
entries--;
|
||||
if (percent <= SHRINK_THRESHOLD)
|
||||
shrink();
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
template <class K,class V>
|
||||
bit8 Dictionary<K,V>::getValue(IN K &key,OUT V &value)
|
||||
{
|
||||
int offset;
|
||||
DNode<K,V> *node;
|
||||
|
||||
offset=keyHash(key);
|
||||
|
||||
node=table[offset];
|
||||
|
||||
if (node==NULL) return(FALSE);
|
||||
|
||||
#ifdef KEY_MEM_OPS
|
||||
while ((node!=NULL)&&(memcmp(&(node->key),&key,sizeof(K))))
|
||||
#else
|
||||
while ((node!=NULL)&&( ! ((node->key)==key)) ) // odd syntax so you don't
|
||||
#endif // have to do oper !=
|
||||
{ node=node->hashNext; }
|
||||
|
||||
if (node==NULL)
|
||||
{ return(FALSE); }
|
||||
|
||||
#ifdef VALUE_MEM_OPS
|
||||
memcpy(&value,&(node->value),sizeof(V));
|
||||
#else
|
||||
value=(node->value);
|
||||
#endif
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
//A note about Shrink and Expand: They are never necessary, they are
|
||||
//only here to improve performance of the hash table by reducing
|
||||
//the length of the linked list at each table entry.
|
||||
|
||||
// Shrink the hash table by a factor of 2 (and relocate entries)
|
||||
template <class K,class V>
|
||||
void Dictionary<K,V>::shrink(void)
|
||||
{
|
||||
int i;
|
||||
int oldsize;
|
||||
uint32 offset;
|
||||
DNode<K,V> **oldtable,*temp,*first,*next;
|
||||
|
||||
if ((size<=(uint32)MIN_TABLE_SIZE)||(keepSize==TRUE))
|
||||
return;
|
||||
|
||||
//fprintf(stderr,"Shrinking....\n");
|
||||
|
||||
oldtable=table;
|
||||
oldsize=size;
|
||||
size/=2;
|
||||
tableBits--;
|
||||
|
||||
table=(DNode<K,V> **)new DNode<K,V>*[size];
|
||||
assert(table!=NULL);
|
||||
memset((void *)table,0,size*sizeof(void *));
|
||||
|
||||
for (i=0; i<oldsize; i++)
|
||||
{
|
||||
temp=oldtable[i];
|
||||
while (temp!=NULL)
|
||||
{
|
||||
offset=keyHash(temp->key);
|
||||
first=table[offset];
|
||||
table[offset]=temp;
|
||||
next=temp->hashNext;
|
||||
temp->hashNext=first;
|
||||
temp=next;
|
||||
}
|
||||
}
|
||||
delete[](oldtable);
|
||||
}
|
||||
|
||||
|
||||
template <class K,class V>
|
||||
void Dictionary<K,V>::expand(void)
|
||||
{
|
||||
int i;
|
||||
int oldsize;
|
||||
uint32 offset;
|
||||
DNode<K,V> **oldtable,*temp,*first,*next;
|
||||
|
||||
if (keepSize==TRUE)
|
||||
return;
|
||||
|
||||
//fprintf(stderr,"Expanding...\n");
|
||||
|
||||
oldtable=table;
|
||||
oldsize=size;
|
||||
size*=2;
|
||||
tableBits++;
|
||||
|
||||
table=(DNode<K,V> **)new DNode<K,V>* [size];
|
||||
assert(table!=NULL);
|
||||
memset((void *)table,0,size*sizeof(void *));
|
||||
|
||||
for (i=0; i<oldsize; i++)
|
||||
{
|
||||
temp=oldtable[i];
|
||||
while (temp!=NULL)
|
||||
{
|
||||
offset=keyHash(temp->key);
|
||||
first=table[offset];
|
||||
table[offset]=temp;
|
||||
next=temp->hashNext;
|
||||
temp->hashNext=first;
|
||||
temp=next;
|
||||
}
|
||||
}
|
||||
delete[](oldtable);
|
||||
}
|
||||
|
||||
#endif
|
51
LAUNCHER/FILED.H
Normal file
51
LAUNCHER/FILED.H
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#ifndef FILED_HEADER
|
||||
#define FILED_HEADER
|
||||
|
||||
#include "odevice.h"
|
||||
|
||||
class FileD : public OutputDevice
|
||||
{
|
||||
public:
|
||||
FileD(char *filename)
|
||||
{
|
||||
out=fopen(filename,"w");
|
||||
if (out==NULL)
|
||||
out=fopen("FileDev.out","w");
|
||||
}
|
||||
|
||||
virtual ~FileD()
|
||||
{ fclose(out); }
|
||||
|
||||
virtual int print(const char *str,int len)
|
||||
{
|
||||
char *string=new char[len+1];
|
||||
memset(string,0,len+1);
|
||||
memcpy(string,str,len);
|
||||
fprintf(out,"%s",string);
|
||||
delete[](string);
|
||||
fflush(out);
|
||||
return(len);
|
||||
}
|
||||
|
||||
FILE *out;
|
||||
};
|
||||
|
||||
#endif
|
203
LAUNCHER/FINDPATCH.CPP
Normal file
203
LAUNCHER/FINDPATCH.CPP
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#include "findpatch.h"
|
||||
|
||||
//
|
||||
// Locate a patch file
|
||||
// If a patch can be found then TRUE is returned and the name is filled in,
|
||||
// otherwise FALSE is returned.
|
||||
//
|
||||
// Patch Types:
|
||||
// - *.rtp = RTPatch file that can be applied right now
|
||||
// - *.exe = Executable that should be put in the RunOnce registry entry & reboot
|
||||
// - *.exn = Executable that should be run right now
|
||||
// - *.web = Link to a web page that will have the patch
|
||||
// - else = File is ignored, possibly a resource file for one of the other types
|
||||
//
|
||||
int Find_Patch(OUT char *filename,int maxlen, ConfigFile &config)
|
||||
{
|
||||
WIN32_FIND_DATA findData;
|
||||
char string[128];
|
||||
HANDLE hFile;
|
||||
char *extensions[]={"web","exe","exn","rtp",NULL};
|
||||
int i;
|
||||
int skuIndex=0;
|
||||
Wstring key;
|
||||
Wstring path;
|
||||
Wstring sku;
|
||||
char gamePath[MAX_PATH];
|
||||
bit8 ok;
|
||||
|
||||
|
||||
while(1)
|
||||
{
|
||||
//
|
||||
// Loop through the apps we're responsible for
|
||||
//
|
||||
skuIndex++;
|
||||
ok=Get_App_Dir(gamePath,MAX_PATH,config,skuIndex);
|
||||
if (ok==FALSE)
|
||||
break;
|
||||
|
||||
i=0;
|
||||
while(extensions[i++])
|
||||
{
|
||||
_chdir(gamePath); // goto the directory with the game
|
||||
|
||||
// should probably get the registry entry for the wchat install path
|
||||
sprintf(string,"patches\\*.%s",extensions[i]);
|
||||
hFile=FindFirstFile(string,&findData);
|
||||
if (hFile!=INVALID_HANDLE_VALUE)
|
||||
{
|
||||
_getcwd(filename,MAX_PATH);
|
||||
strcat(filename,"\\patches\\");
|
||||
strcat(filename,findData.cFileName);
|
||||
FindClose(hFile);
|
||||
return(skuIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Get the directory for the N'th application in the config file
|
||||
//
|
||||
// Returns FALSE if not in the config file or invalid for some reason.
|
||||
//
|
||||
bit8 Get_App_Dir(OUT char *filename,int maxlen, ConfigFile &config,int index)
|
||||
{
|
||||
char string[128];
|
||||
Wstring key;
|
||||
Wstring path;
|
||||
Wstring sku;
|
||||
int temp;
|
||||
char gamePath[MAX_PATH];
|
||||
|
||||
|
||||
sprintf(string,"SKU%d",index);
|
||||
|
||||
// Can't find this product
|
||||
if (config.getString(string,key)==FALSE)
|
||||
return(FALSE);
|
||||
|
||||
|
||||
DBGMSG("KEY = "<<key.get());
|
||||
// Get the InstallPath from the specified registry key
|
||||
temp=0;
|
||||
temp=key.getToken(temp," ",sku);
|
||||
path=key;
|
||||
path.remove(0,temp);
|
||||
while((*(path.get()))==' ') // remove leading spaces
|
||||
path.remove(0,1);
|
||||
|
||||
|
||||
DBGMSG("CONFIG: SKU = "<<sku.get()<<" PATH = '"<<path.get()<<"'");
|
||||
HKEY regKey;
|
||||
LONG regRetval;
|
||||
/////////////DWORD regPrevious;
|
||||
regRetval=RegOpenKeyEx(HKEY_LOCAL_MACHINE,path.get(),0,KEY_READ,®Key);
|
||||
if (regRetval!=ERROR_SUCCESS)
|
||||
{
|
||||
DBGMSG("RegOpenKey failed");
|
||||
return(FALSE);
|
||||
}
|
||||
DWORD type;
|
||||
DWORD length=MAX_PATH;
|
||||
regRetval=RegQueryValueEx(regKey,"InstallPath",NULL,&type,(uint8 *)gamePath,
|
||||
&length);
|
||||
DBGMSG("GAME PATH = "<<gamePath);
|
||||
if ((regRetval!=ERROR_SUCCESS)||(type!=REG_SZ))
|
||||
{
|
||||
DBGMSG("Reg failure");
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
// Find the last '\\' in a string and put a 0 after it
|
||||
// If you only put a directory in the InstallPath key instead of a full
|
||||
// path to a file, you better end the directory with a trailing '\\'!!!
|
||||
char *cptr=gamePath;
|
||||
char *tempPtr;
|
||||
while( (tempPtr=strchr(cptr,'\\')) !=NULL)
|
||||
cptr=tempPtr+1;
|
||||
if (cptr)
|
||||
*cptr=0;
|
||||
|
||||
DBGMSG("Game path = "<<gamePath);
|
||||
strncpy(filename,gamePath,maxlen);
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Delete any patch files
|
||||
//
|
||||
void Delete_Patches(ConfigFile &config)
|
||||
{
|
||||
char dir[MAX_PATH];
|
||||
int i=1;
|
||||
WIN32_FIND_DATA findData;
|
||||
HANDLE hFile;
|
||||
|
||||
DBGMSG("IN DELPATCH");
|
||||
|
||||
//
|
||||
// Loop through all the application directories in the config file
|
||||
//
|
||||
while (Get_App_Dir(dir,MAX_PATH,config,i++)==TRUE)
|
||||
{
|
||||
// Make sure path is at least 3 for "c:\". I really hope nobody's
|
||||
// dumb enough to install a game to the root directory. (It's OK though
|
||||
// since only the '\patches' folder is cleared out.
|
||||
if (strlen(dir)<3)
|
||||
continue;
|
||||
|
||||
//
|
||||
// Delete everything in case a .exe patch had some data files it used.
|
||||
//
|
||||
strcat(dir,"patches\\*.*");
|
||||
|
||||
DBGMSG("DELPATCH: "<<dir);
|
||||
|
||||
hFile=FindFirstFile(dir,&findData);
|
||||
if (hFile!=INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (findData.cFileName[0]!='.')
|
||||
{
|
||||
//_unlink(findData.cFileName);
|
||||
DBGMSG("UNLINK: "<<findData.cFileName);
|
||||
}
|
||||
while(FindNextFile(hFile,&findData))
|
||||
{
|
||||
if (findData.cFileName[0]!='.')
|
||||
{
|
||||
//_unlink(findData.cFileName);
|
||||
DBGMSG("UNLINK: "<<findData.cFileName);
|
||||
}
|
||||
}
|
||||
} // If there's at least one file
|
||||
FindClose(hFile);
|
||||
} // while there's apps in config
|
||||
return;
|
||||
}
|
33
LAUNCHER/FINDPATCH.H
Normal file
33
LAUNCHER/FINDPATCH.H
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#ifndef FINDPATCH_HEADER
|
||||
#define FINDPATCH_HEADER
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <direct.h>
|
||||
#include "wstypes.h"
|
||||
#include "configfile.h"
|
||||
|
||||
int Find_Patch(OUT char *file,int maxlen, ConfigFile &config);
|
||||
bit8 Get_App_Dir(OUT char *file,int maxlen, ConfigFile &config, int index);
|
||||
void Delete_Patches(ConfigFile &config);
|
||||
|
||||
#endif
|
219
LAUNCHER/LAUNCHER.DSP
Normal file
219
LAUNCHER/LAUNCHER.DSP
Normal file
@@ -0,0 +1,219 @@
|
||||
# Microsoft Developer Studio Project File - Name="launcher" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Application" 0x0101
|
||||
|
||||
CFG=launcher - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "launcher.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "launcher.mak" CFG="launcher - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "launcher - Win32 Release" (based on "Win32 (x86) Application")
|
||||
!MESSAGE "launcher - Win32 Debug" (based on "Win32 (x86) Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
MTL=midl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "launcher - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
|
||||
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /map /machine:I386
|
||||
|
||||
!ELSEIF "$(CFG)" == "launcher - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
|
||||
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "DEBUG" /YX /FD /c
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib patchw32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept /libpath:"."
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "launcher - Win32 Release"
|
||||
# Name "launcher - Win32 Debug"
|
||||
# Begin Group "dbglib"
|
||||
|
||||
# PROP Default_Filter ".cpp,.h"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\configfile.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\configfile.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\dictionary.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\filed.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\monod.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\monod.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\odevice.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\streamer.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\streamer.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wdebug.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wdebug.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wstring.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wstring.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "util"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\dialog.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\dialog.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\findpatch.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\findpatch.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\launcher1.rc
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\loadbmp.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\loadbmp.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\main.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\patch.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\patch.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\process.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\process.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Redalert.ico
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\resource.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\winblows.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\winblows.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wstypes.h
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
29
LAUNCHER/LAUNCHER.DSW
Normal file
29
LAUNCHER/LAUNCHER.DSW
Normal file
@@ -0,0 +1,29 @@
|
||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "launcher"=.\launcher.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
150
LAUNCHER/LAUNCHER1.RC
Normal file
150
LAUNCHER/LAUNCHER1.RC
Normal file
@@ -0,0 +1,150 @@
|
||||
//Microsoft Developer Studio generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "afxres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 243, 126
|
||||
STYLE DS_MODALFRAME | DS_SETFOREGROUND | WS_MINIMIZEBOX | WS_POPUP |
|
||||
WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Patching"
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
CONTROL "",IDC_SPLASH,"Static",SS_GRAYRECT | SS_SUNKEN,7,7,229,
|
||||
70
|
||||
GROUPBOX "File",IDC_CAPTION,7,78,229,22
|
||||
CONTROL "Progress1",IDC_PROGRESS2,"msctls_progress32",WS_BORDER,
|
||||
7,105,229,13
|
||||
CONTROL "",IDC_FILENAME,"Static",SS_LEFTNOWORDWRAP |
|
||||
SS_CENTERIMAGE | WS_GROUP,13,85,217,13
|
||||
END
|
||||
|
||||
IDD_CHANGELOG DIALOG DISCARDABLE 0, 0, 332, 204
|
||||
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Update Information"
|
||||
FONT 10, "Lucida Console"
|
||||
BEGIN
|
||||
EDITTEXT IDC_TEXT,5,5,322,178,ES_MULTILINE | ES_AUTOHSCROLL |
|
||||
ES_READONLY | WS_VSCROLL | WS_HSCROLL
|
||||
PUSHBUTTON "OK",IDOK,128,185,76,14
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESIGNINFO
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
GUIDELINES DESIGNINFO DISCARDABLE
|
||||
BEGIN
|
||||
IDD_DIALOG1, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 236
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 119
|
||||
END
|
||||
|
||||
IDD_CHANGELOG, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 5
|
||||
RIGHTMARGIN, 327
|
||||
TOPMARGIN, 5
|
||||
BOTTOMMARGIN, 199
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"#include ""afxres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE DISCARDABLE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDI_ICON2 ICON DISCARDABLE "redalert.ico"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// String Table
|
||||
//
|
||||
|
||||
STRINGTABLE DISCARDABLE
|
||||
BEGIN
|
||||
IDS_SYS_RESTART "Your computer needs to be restarted to continue the patch. Press OK to continue."
|
||||
IDS_SYS_RESTART_TITLE "About to restart"
|
||||
IDS_WEBPATCH "You need to download a patch from our website.\rWhen you press OK, your browser will automatically open to the download page."
|
||||
IDS_WEBPATCH_TITLE "Web Patch"
|
||||
IDS_FILE_X_OF_Y "File (%d of %d)"
|
||||
IDS_MUST_RESTART "You must restart your computer now."
|
||||
IDS_RUNONCE_ERR "Could not set the patch to run on system reboot!\rYou must exit the game and run %s to complete the patch."
|
||||
IDS_ERROR "Error"
|
||||
IDS_ERR_MISSING_FILE "Error: Couldn't find file: %s"
|
||||
IDS_BAD_LIBRARY "A required DLL is corrupt."
|
||||
END
|
||||
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
214
LAUNCHER/LOADBMP.CPP
Normal file
214
LAUNCHER/LOADBMP.CPP
Normal file
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#include"loadbmp.h"
|
||||
|
||||
|
||||
LoadBmp::LoadBmp()
|
||||
{
|
||||
BitmapHandle_=NULL;
|
||||
PalHandle_=NULL;
|
||||
}
|
||||
|
||||
LoadBmp::~LoadBmp()
|
||||
{
|
||||
// free resources
|
||||
DeleteObject(BitmapHandle_);
|
||||
DeleteObject(PalHandle_);
|
||||
}
|
||||
|
||||
//
|
||||
// Load a specified bitmap for later display on a window
|
||||
//
|
||||
bit8 LoadBmp::init(char *filename,HWND hwnd)
|
||||
{
|
||||
int i;
|
||||
char string[128];
|
||||
HANDLE hBitmapFile;
|
||||
DWORD dwRead;
|
||||
BITMAPFILEHEADER bitmapHeader;
|
||||
BITMAPINFOHEADER bitmapInfoHeader;
|
||||
LPLOGPALETTE lpLogPalette;
|
||||
char *palData;
|
||||
HGLOBAL hmem2;
|
||||
LPVOID lpvBits;
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc;
|
||||
HPALETTE select;
|
||||
UINT realize;
|
||||
RECT rect;
|
||||
|
||||
|
||||
// Set the member for future reference
|
||||
WindowHandle_=hwnd;
|
||||
|
||||
// Retrieve a handle identifying the file.
|
||||
hBitmapFile = CreateFile(
|
||||
filename,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
(LPSECURITY_ATTRIBUTES) NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_READONLY,
|
||||
(HANDLE) NULL);
|
||||
|
||||
if (hBitmapFile==NULL)
|
||||
return(FALSE);
|
||||
|
||||
// Retrieve the BITMAPFILEHEADER structure.
|
||||
ReadFile(hBitmapFile, &bitmapHeader, sizeof(BITMAPFILEHEADER), &dwRead,
|
||||
(LPOVERLAPPED)NULL);
|
||||
|
||||
|
||||
// Retrieve the BITMAPFILEHEADER structure.
|
||||
ReadFile(hBitmapFile, &bitmapInfoHeader, sizeof(BITMAPINFOHEADER),
|
||||
&dwRead, (LPOVERLAPPED)NULL);
|
||||
|
||||
|
||||
// Allocate memory for the BITMAPINFO structure.
|
||||
HGLOBAL infoHeaderMem = GlobalAlloc(GHND, sizeof(BITMAPINFOHEADER) +
|
||||
((1<<bitmapInfoHeader.biBitCount) * sizeof(RGBQUAD)));
|
||||
|
||||
LPBITMAPINFO lpHeaderMem = (LPBITMAPINFO)GlobalLock(infoHeaderMem);
|
||||
|
||||
// Load BITMAPINFOHEADER into the BITMAPINFO structure.
|
||||
lpHeaderMem->bmiHeader.biSize = bitmapInfoHeader.biSize;
|
||||
lpHeaderMem->bmiHeader.biWidth = bitmapInfoHeader.biWidth;
|
||||
lpHeaderMem->bmiHeader.biHeight = bitmapInfoHeader.biHeight;
|
||||
lpHeaderMem->bmiHeader.biPlanes = bitmapInfoHeader.biPlanes;
|
||||
lpHeaderMem->bmiHeader.biBitCount = bitmapInfoHeader.biBitCount;
|
||||
lpHeaderMem->bmiHeader.biCompression = bitmapInfoHeader.biCompression;
|
||||
lpHeaderMem->bmiHeader.biSizeImage = bitmapInfoHeader.biSizeImage;
|
||||
lpHeaderMem->bmiHeader.biXPelsPerMeter = bitmapInfoHeader.biXPelsPerMeter;
|
||||
lpHeaderMem->bmiHeader.biYPelsPerMeter = bitmapInfoHeader.biYPelsPerMeter;
|
||||
lpHeaderMem->bmiHeader.biClrUsed = bitmapInfoHeader.biClrUsed;
|
||||
lpHeaderMem->bmiHeader.biClrImportant = bitmapInfoHeader.biClrImportant;
|
||||
|
||||
|
||||
// Retrieve the color table.
|
||||
// 1 << bitmapInfoHeader.biBitCount == 2 ^ bitmapInfoHeader.biBitCount
|
||||
ReadFile(hBitmapFile, lpHeaderMem->bmiColors,
|
||||
((1<<bitmapInfoHeader.biBitCount) * sizeof(RGBQUAD)),
|
||||
&dwRead, (LPOVERLAPPED) NULL);
|
||||
|
||||
|
||||
lpLogPalette=(LPLOGPALETTE)new char[(sizeof(LOGPALETTE)+
|
||||
sizeof(PALETTEENTRY)*256)];
|
||||
lpLogPalette->palVersion=0x300;
|
||||
lpLogPalette->palNumEntries=256;
|
||||
|
||||
palData=(char *)lpHeaderMem->bmiColors;
|
||||
|
||||
for (i=0; i<256; i++)
|
||||
{
|
||||
lpLogPalette->palPalEntry[i].peRed=*palData++;
|
||||
lpLogPalette->palPalEntry[i].peGreen=*palData++;
|
||||
lpLogPalette->palPalEntry[i].peBlue=*palData++;
|
||||
lpLogPalette->palPalEntry[i].peFlags=*palData++;
|
||||
}
|
||||
PalHandle_=CreatePalette(lpLogPalette);
|
||||
delete(lpLogPalette);
|
||||
|
||||
|
||||
// Allocate memory for the required number of bytes.
|
||||
hmem2 = GlobalAlloc(GHND, (bitmapHeader.bfSize - bitmapHeader.bfOffBits));
|
||||
|
||||
lpvBits = GlobalLock(hmem2);
|
||||
|
||||
// Retrieve the bitmap data.
|
||||
ReadFile(hBitmapFile, lpvBits, (bitmapHeader.bfSize - bitmapHeader.bfOffBits),
|
||||
&dwRead, (LPOVERLAPPED) NULL);
|
||||
|
||||
|
||||
// Create a bitmap from the data stored in the .BMP file.
|
||||
hdc=GetDC(hwnd);
|
||||
select=SelectPalette(hdc,PalHandle_,0);
|
||||
if (select==NULL)
|
||||
return(FALSE);
|
||||
realize=RealizePalette(hdc);
|
||||
if (realize==GDI_ERROR)
|
||||
return(FALSE);
|
||||
BitmapHandle_=CreateDIBitmap(hdc, &bitmapInfoHeader, CBM_INIT, lpvBits, lpHeaderMem, DIB_RGB_COLORS);
|
||||
ReleaseDC(hwnd,hdc);
|
||||
|
||||
|
||||
if (BitmapHandle_==NULL)
|
||||
return(FALSE);
|
||||
|
||||
// Unlock the global memory objects and close the .BMP file.
|
||||
GlobalUnlock(infoHeaderMem);
|
||||
GlobalUnlock(hmem2);
|
||||
CloseHandle(hBitmapFile);
|
||||
|
||||
if (BitmapHandle_==NULL)
|
||||
return(FALSE);
|
||||
|
||||
// Inform windows the window needs to be repainted
|
||||
GetClientRect(hwnd, &rect);
|
||||
InvalidateRect(hwnd, &rect, TRUE);
|
||||
UpdateWindow(hwnd);
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
bit8 LoadBmp::drawBmp(void)
|
||||
{
|
||||
// Paint the window (and draw the bitmap).
|
||||
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc;
|
||||
char string[128];
|
||||
|
||||
InvalidateRect(WindowHandle_,NULL,FALSE); // keep windows from screwing up the
|
||||
// redrawing (as much).
|
||||
hdc=BeginPaint(WindowHandle_,&ps);
|
||||
|
||||
//Do palette stuff
|
||||
HPALETTE select=SelectPalette(ps.hdc,PalHandle_,0);
|
||||
if (select==NULL)
|
||||
{
|
||||
sprintf(string,"Select Pal Fail: %d",GetLastError());
|
||||
MessageBox(NULL,string,"OK",MB_OK);
|
||||
}
|
||||
UINT realize=RealizePalette(ps.hdc);
|
||||
if (realize==GDI_ERROR)
|
||||
{
|
||||
sprintf(string,"Realize Pal Fail: %d",GetLastError());
|
||||
MessageBox(NULL,string,"OK",MB_OK);
|
||||
}
|
||||
|
||||
HDC hdcMem = CreateCompatibleDC(ps.hdc);
|
||||
SelectObject(hdcMem, BitmapHandle_);
|
||||
BITMAP bm;
|
||||
GetObject(BitmapHandle_, sizeof(BITMAP), (LPSTR) &bm);
|
||||
|
||||
/// for non-stretching version
|
||||
///////BitBlt(ps.hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
|
||||
|
||||
RECT clientRect;
|
||||
GetClientRect(WindowHandle_,&clientRect);
|
||||
SetStretchBltMode(ps.hdc,COLORONCOLOR);
|
||||
StretchBlt(ps.hdc,0,0,clientRect.right,clientRect.bottom,hdcMem,0,0,bm.bmWidth,
|
||||
bm.bmHeight,SRCCOPY);
|
||||
|
||||
|
||||
DeleteDC(hdcMem);
|
||||
EndPaint(WindowHandle_,&ps);
|
||||
return(TRUE);
|
||||
}
|
46
LAUNCHER/LOADBMP.H
Normal file
46
LAUNCHER/LOADBMP.H
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#ifndef LOADBMP_HEADER
|
||||
#define LOADBMP_HEADER
|
||||
|
||||
#include<stdlib.h>
|
||||
#include<stdio.h>
|
||||
#include "wstypes.h"
|
||||
#include "winblows.h"
|
||||
|
||||
|
||||
//
|
||||
// Functions and data assocated with a loaded bitmap on a single window.
|
||||
//
|
||||
class LoadBmp
|
||||
{
|
||||
public:
|
||||
LoadBmp();
|
||||
~LoadBmp();
|
||||
bit8 init(char *filename,HWND hwnd); // must call before the drawBmp
|
||||
bit8 drawBmp(void); // call this from your WM_PAINT message
|
||||
|
||||
private:
|
||||
HBITMAP BitmapHandle_;
|
||||
HPALETTE PalHandle_;
|
||||
HWND WindowHandle_;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
270
LAUNCHER/MAIN.CPP
Normal file
270
LAUNCHER/MAIN.CPP
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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 S T U D I O S
|
||||
*******************************************************************************
|
||||
File: main.cpp
|
||||
Programmer: Neal Kettler
|
||||
|
||||
StartDate: Feb 6, 1998
|
||||
LastUpdate: Feb 10, 1998
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Launcher application for games/apps using the chat API. This should be
|
||||
run by the user and it will start the actual game executable. If a patch
|
||||
file has been downloaded the patch will be applied before starting the game.
|
||||
|
||||
This does not download patches or do version checks, the game/app is responsible
|
||||
for that. This just applies patches that are in the correct location for the
|
||||
game. All patches should be in the "Patches" folder of the app.
|
||||
|
||||
The launcher should have a config file (launcher.cfg) so it knows which apps
|
||||
should be checked for patches. The file should look like this:
|
||||
|
||||
# comment
|
||||
# RUN = the game to launch
|
||||
RUN = . notepad.exe # directory and app name
|
||||
#
|
||||
# Sku's to check for patches
|
||||
#
|
||||
SKU1 = 1100 SOFTWARE\Westwood\WOnline # skus and registry keys
|
||||
SKU2 = 1234 SOFTWARE\Westwood\FakeGame
|
||||
|
||||
\*****************************************************************************/
|
||||
|
||||
|
||||
#include "dialog.h"
|
||||
#include "patch.h"
|
||||
#include "findpatch.h"
|
||||
#include "process.h"
|
||||
|
||||
#include "wdebug.h"
|
||||
#include "monod.h"
|
||||
#include "filed.h"
|
||||
#include "configfile.h"
|
||||
#include <windows.h>
|
||||
|
||||
#define UPDATE_RETVAL 123456789 // if a program returns this it means it wants to check for patches
|
||||
|
||||
void CreatePrimaryWin(char *prefix);
|
||||
void myChdir(char *path);
|
||||
|
||||
|
||||
//
|
||||
// Called by WinMain
|
||||
//
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char patchFile[MAX_PATH];
|
||||
bit8 ok;
|
||||
int skuIndex=0;
|
||||
char cwd[MAX_PATH]; // save current directory before game start
|
||||
_getcwd(cwd,MAX_PATH);
|
||||
|
||||
InitCommonControls();
|
||||
|
||||
#ifdef DEBUG
|
||||
///MonoD outputDevice;
|
||||
FileD outputDevice("launcher.out");
|
||||
MsgManager::setAllStreams(&outputDevice);
|
||||
DBGMSG("Launcher initialized");
|
||||
#endif
|
||||
|
||||
|
||||
// Goto the folder where launcher is installed
|
||||
myChdir(argv[0]);
|
||||
|
||||
// extract the program name from argv[0]. Change the extension to
|
||||
// .lcf (Launcher ConFig). This is the name of our config file.
|
||||
char configName[MAX_PATH+3];
|
||||
strcpy(configName,argv[0]);
|
||||
char *extension=configName;
|
||||
char *tempptr;
|
||||
while((tempptr=strchr(extension+1,'.')))
|
||||
extension=tempptr;
|
||||
if (*extension=='.')
|
||||
*extension=0;
|
||||
strcat(configName,".lcf");
|
||||
|
||||
DBGMSG("Config Name: "<<configName);
|
||||
|
||||
ConfigFile config;
|
||||
FILE *in=fopen(configName,"r");
|
||||
if (in==NULL)
|
||||
{
|
||||
MessageBox(NULL,"You must run the game from its install directory.",
|
||||
"Launcher config file missing",MB_OK);
|
||||
exit(-1);
|
||||
}
|
||||
ok=config.readFile(in);
|
||||
fclose(in);
|
||||
if(ok==FALSE)
|
||||
{
|
||||
MessageBox(NULL,"File 'launcher.cfg' is corrupt","Error",MB_OK);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
// Load process info
|
||||
Process proc;
|
||||
Read_Process_Info(config,proc);
|
||||
|
||||
DBGMSG("Read process info");
|
||||
|
||||
// Create the main window
|
||||
///CreatePrimaryWin(proc.command);
|
||||
|
||||
while((skuIndex=Find_Patch(patchFile,MAX_PATH,config))!=0)
|
||||
Apply_Patch(patchFile,config,skuIndex);
|
||||
|
||||
Delete_Patches(config); // delete all patches
|
||||
|
||||
for (int i=1; i<argc; i++)
|
||||
{
|
||||
strcat(proc.args," ");
|
||||
strcat(proc.args,argv[i]);
|
||||
}
|
||||
DBGMSG("ARGS: "<<proc.args);
|
||||
|
||||
while(1)
|
||||
{
|
||||
myChdir(argv[0]);
|
||||
Create_Process(proc);
|
||||
Wait_Process(proc);
|
||||
|
||||
if((skuIndex=Find_Patch(patchFile,MAX_PATH,config))!=0)
|
||||
{
|
||||
do
|
||||
{
|
||||
Apply_Patch(patchFile,config,skuIndex);
|
||||
} while((skuIndex=Find_Patch(patchFile,MAX_PATH,config))!=0);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
myChdir(cwd);
|
||||
|
||||
// Exit normally
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Create a primary window
|
||||
//
|
||||
void CreatePrimaryWin(char *prefix)
|
||||
{
|
||||
HWND hwnd;
|
||||
WNDCLASS wc;
|
||||
char name[256];
|
||||
|
||||
sprintf(name,"launcher_%s",prefix);
|
||||
|
||||
DBGMSG("CreatePrimary: "<<name);
|
||||
|
||||
/*
|
||||
** set up and register window class
|
||||
*/
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wc.lpfnWndProc = DefWindowProc;
|
||||
wc.cbClsExtra = 0; // Don't need any extra class data
|
||||
wc.cbWndExtra = 0; // No extra win data
|
||||
wc.hInstance = Global_instance;
|
||||
wc.hIcon=LoadIcon(Global_instance, MAKEINTRESOURCE(IDI_ICON));
|
||||
wc.hCursor = NULL; /////////LoadCursor( NULL, IDC_ARROW );
|
||||
wc.hbrBackground = NULL;
|
||||
wc.lpszMenuName = name;
|
||||
wc.lpszClassName = name;
|
||||
RegisterClass( &wc );
|
||||
|
||||
/*
|
||||
** create a window
|
||||
*/
|
||||
hwnd = CreateWindowEx(
|
||||
WS_EX_TOPMOST,
|
||||
name,
|
||||
name,
|
||||
WS_POPUP,
|
||||
0, 0,
|
||||
GetSystemMetrics( SM_CXSCREEN ),
|
||||
GetSystemMetrics( SM_CYSCREEN ),
|
||||
NULL,
|
||||
NULL,
|
||||
Global_instance,
|
||||
NULL );
|
||||
|
||||
if( !hwnd )
|
||||
{
|
||||
DBGMSG("Couldn't make window!");
|
||||
}
|
||||
else
|
||||
{
|
||||
DBGMSG("Window created!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//void DestroyPrimaryWin(void)
|
||||
//{
|
||||
// DestroyWindow(PrimaryWin);
|
||||
// UnregisterClass(classname);
|
||||
//}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// If given a file, it'll goto it's directory. If on a diff drive,
|
||||
// it'll go there.
|
||||
//
|
||||
void myChdir(char *path)
|
||||
{
|
||||
char drive[10];
|
||||
char dir[255];
|
||||
char file[255];
|
||||
char ext[64];
|
||||
char filepath[513];
|
||||
int abc;
|
||||
|
||||
_splitpath( path, drive, dir, file, ext );
|
||||
_makepath ( filepath, drive, dir, NULL, NULL );
|
||||
|
||||
if ( filepath[ strlen( filepath ) - 1 ] == '\\' )
|
||||
{
|
||||
filepath[ strlen( filepath ) - 1 ] = '\0';
|
||||
}
|
||||
abc = (unsigned)( toupper( filepath[0] ) - 'A' + 1 );
|
||||
if ( !_chdrive( abc ))
|
||||
{
|
||||
abc = chdir( filepath ); // Will fail with ending '\\'
|
||||
}
|
||||
// should be in proper folder now....
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
57
LAUNCHER/MONOD.CPP
Normal file
57
LAUNCHER/MONOD.CPP
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#include "monod.h"
|
||||
|
||||
MonoD::MonoD(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
unsigned long retval;
|
||||
handle = CreateFile("\\\\.\\MONO", GENERIC_READ|GENERIC_WRITE, 0, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DeviceIoControl(handle, (DWORD)IOCTL_MONO_CLEAR_SCREEN, NULL, 0, NULL, 0,
|
||||
&retval,0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
MonoD::~MonoD()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
CloseHandle(handle);
|
||||
handle=NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
int MonoD::print(const char *str, int len)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
unsigned long retval;
|
||||
WriteFile(handle, str, len, &retval, NULL);
|
||||
//DeviceIoControl(handle, (DWORD)IOCTL_MONO_PRINT_RAW, (void *)str, len, NULL, 0,
|
||||
// &retval,0);
|
||||
return(len);
|
||||
#else
|
||||
for (int i=0; i<len; i++)
|
||||
fprintf(stderr,"%c",str[i]);
|
||||
return(len);
|
||||
#endif
|
||||
}
|
74
LAUNCHER/MONOD.H
Normal file
74
LAUNCHER/MONOD.H
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#ifndef MONOD_HEADER
|
||||
#define MONOD_HEADER
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "odevice.h"
|
||||
|
||||
///////////////////////// WIN32 ONLY ///////////////////////////////////
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
|
||||
/*
|
||||
** This is the identifier for the Monochrome Display Driver
|
||||
*/
|
||||
#define FILE_DEVICE_MONO 0x00008000
|
||||
|
||||
/*
|
||||
** These are the IOCTL commands supported by the Monochrome Display Driver.
|
||||
*/
|
||||
#define IOCTL_MONO_HELP_SCREEN CTL_CODE(FILE_DEVICE_MONO, 0x800, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_CLEAR_SCREEN CTL_CODE(FILE_DEVICE_MONO, 0x801, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_PRINT_RAW CTL_CODE(FILE_DEVICE_MONO, 0x802, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_SET_CURSOR CTL_CODE(FILE_DEVICE_MONO, 0x803, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_SCROLL CTL_CODE(FILE_DEVICE_MONO, 0x804, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_BRING_TO_TOP CTL_CODE(FILE_DEVICE_MONO, 0x805, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_SET_ATTRIBUTE CTL_CODE(FILE_DEVICE_MONO, 0x806, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_PAN CTL_CODE(FILE_DEVICE_MONO, 0x807, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_LOCK CTL_CODE(FILE_DEVICE_MONO, 0x808, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_UNLOCK CTL_CODE(FILE_DEVICE_MONO, 0x809, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_SET_WINDOW CTL_CODE(FILE_DEVICE_MONO, 0x80A, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_RESET_WINDOW CTL_CODE(FILE_DEVICE_MONO, 0x80B, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_SET_FLAG CTL_CODE(FILE_DEVICE_MONO, 0x80C, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_CLEAR_FLAG CTL_CODE(FILE_DEVICE_MONO, 0x80D, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_FILL_ATTRIB CTL_CODE(FILE_DEVICE_MONO, 0x80E, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
|
||||
#endif // ifdef _WIN32
|
||||
|
||||
class MonoD : public OutputDevice
|
||||
{
|
||||
public:
|
||||
MonoD();
|
||||
~MonoD();
|
||||
|
||||
virtual int print(const char *str,int len);
|
||||
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
HANDLE handle;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
32
LAUNCHER/ODEVICE.H
Normal file
32
LAUNCHER/ODEVICE.H
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#ifndef ODEVICE_HEADER
|
||||
#define ODEVICE_HEADER
|
||||
|
||||
// This virtual base class provides an interface for output devices
|
||||
// that can be used for the debugging package.
|
||||
class OutputDevice
|
||||
{
|
||||
public:
|
||||
OutputDevice() {}
|
||||
virtual ~OutputDevice() {};
|
||||
virtual int print(const char *s,int len)=0;
|
||||
};
|
||||
|
||||
#endif
|
548
LAUNCHER/PATCH.CPP
Normal file
548
LAUNCHER/PATCH.CPP
Normal file
@@ -0,0 +1,548 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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 S T U D I O S
|
||||
*******************************************************************************
|
||||
File: patch.cpp
|
||||
Programmer: Neal Kettler
|
||||
|
||||
StartDate: Feb 6, 1998
|
||||
LastUpdate: Feb 10, 1998
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
This is where all the code is for applying various types of patches.
|
||||
|
||||
\*****************************************************************************/
|
||||
|
||||
|
||||
#include "patch.h"
|
||||
#include <shellapi.h>
|
||||
#include <direct.h>
|
||||
|
||||
|
||||
//
|
||||
// For the text box showing patch info
|
||||
//
|
||||
BOOL CALLBACK Update_Info_Proc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
|
||||
static int unselectText=0;
|
||||
|
||||
switch(iMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
FILE *in = fopen("launcher.txt","r");
|
||||
if (in==NULL)
|
||||
{
|
||||
EndDialog(hwnd,-1);
|
||||
return(1);
|
||||
}
|
||||
|
||||
char line[270];
|
||||
int lastsel=0;
|
||||
char *cptr=NULL;
|
||||
while(fgets(line,255,in))
|
||||
{
|
||||
//Get rid of any trailing junk
|
||||
while(1)
|
||||
{
|
||||
if (strlen(line)<1)
|
||||
break;
|
||||
cptr=line+(strlen(line))-1;
|
||||
if ((*cptr=='\r')||(*cptr=='\n'))
|
||||
*cptr=0;
|
||||
else
|
||||
break;
|
||||
}
|
||||
// ...and add back the gunk that windows likes
|
||||
strcat(line,"\r\r\n");
|
||||
|
||||
SendDlgItemMessage(hwnd, IDC_TEXT, EM_SETSEL, (WPARAM)lastsel, (LPARAM)lastsel );
|
||||
SendDlgItemMessage(hwnd, IDC_TEXT, EM_REPLACESEL, 0, (LPARAM)(line) );
|
||||
SendDlgItemMessage(hwnd, IDC_TEXT, EM_GETSEL, (WPARAM)NULL, (LPARAM)&lastsel );
|
||||
}
|
||||
unselectText=1;
|
||||
fclose(in);
|
||||
|
||||
return(1); // 1 means windows handles focus issues
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_PAINT:
|
||||
if (unselectText)
|
||||
SendDlgItemMessage(hwnd, IDC_TEXT, EM_SETSEL, -1, 0);
|
||||
unselectText=0;
|
||||
return(0);
|
||||
break;
|
||||
|
||||
|
||||
case WM_COMMAND:
|
||||
switch(wParam) {
|
||||
case IDOK:
|
||||
{
|
||||
EndDialog(hwnd,0);
|
||||
return(1);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
case WM_CLOSE:
|
||||
EndDialog(hwnd,0);
|
||||
return(1);
|
||||
break;
|
||||
}
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Restart the computer for certain types of patches
|
||||
void Shutdown_Computer_Now(void);
|
||||
|
||||
|
||||
LPVOID CALLBACK __export PatchCallBack(UINT ID, LPVOID Param);
|
||||
|
||||
typedef LPVOID (CALLBACK* PATCHCALLBACK)(UINT, LPVOID);
|
||||
typedef UINT (CALLBACK *PATCHFUNC)( LPSTR, PATCHCALLBACK, BOOL);
|
||||
|
||||
//
|
||||
// Apply any type of patch. Filename in patchfile. Product base registry
|
||||
// (eg: "SOFTWARE\Westwood\Red Alert") should be in the config file as
|
||||
// SKUX SKU base reg dir where X = index
|
||||
//
|
||||
void Apply_Patch(char *patchfile,ConfigFile &config,int skuIndex)
|
||||
{
|
||||
DBGMSG("PATCHFILE : "<<patchfile);
|
||||
char cwdbuf[256];
|
||||
_getcwd(cwdbuf,255);
|
||||
DBGMSG("CWD : "<<cwdbuf);
|
||||
|
||||
//
|
||||
// If patch is a .exe type patch
|
||||
//
|
||||
if (strcasecmp(patchfile+strlen(patchfile)-strlen(".exe"),".exe")==0)
|
||||
{
|
||||
// Set this as a run once service thing
|
||||
HKEY regKey;
|
||||
LONG regRetval;
|
||||
DWORD regPrevious;
|
||||
regRetval=RegCreateKeyEx(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce",
|
||||
0,
|
||||
"",
|
||||
REG_OPTION_NON_VOLATILE,
|
||||
KEY_ALL_ACCESS,
|
||||
NULL,
|
||||
®Key,
|
||||
®Previous);
|
||||
|
||||
if (regRetval==ERROR_SUCCESS)
|
||||
{
|
||||
RegSetValueEx(regKey,"EXEPatch",0,REG_SZ,(const uint8*)patchfile,strlen(patchfile)+1);
|
||||
|
||||
char message[256];
|
||||
LoadString(NULL,IDS_SYS_RESTART,message,256);
|
||||
char title[128];
|
||||
LoadString(NULL,IDS_SYS_RESTART_TITLE,title,128);
|
||||
|
||||
MessageBox(NULL,message,title,MB_OK);
|
||||
|
||||
Shutdown_Computer_Now();
|
||||
}
|
||||
else
|
||||
{
|
||||
char message[256];
|
||||
LoadString(NULL,IDS_RUNONCE_ERR,message,256);
|
||||
char string[256];
|
||||
sprintf(string,message,patchfile);
|
||||
MessageBox(NULL,string,"ERROR",MB_OK);
|
||||
}
|
||||
}
|
||||
//
|
||||
// RTPatch type patch
|
||||
//
|
||||
else if (strcasecmp(patchfile+strlen(patchfile)-strlen(".rtp"),".rtp")==0)
|
||||
{
|
||||
MSG msg;
|
||||
HWND dialog=Create_Patch_Dialog();
|
||||
while(PeekMessage(&msg,NULL,0,0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
HINSTANCE hInst=LoadLibrary("patchw32.dll");
|
||||
if (hInst==NULL)
|
||||
{
|
||||
char message[256];
|
||||
LoadString(NULL,IDS_ERR_MISSING_FILE,message,256);
|
||||
char string[256];
|
||||
sprintf(string,message,"patchw32.dll");
|
||||
char title[128];
|
||||
LoadString(NULL,IDS_ERROR,title,128);
|
||||
MessageBox(NULL,string,title,MB_OK);
|
||||
return;
|
||||
}
|
||||
|
||||
DBGMSG("Patch SKU = "<<skuIndex);
|
||||
|
||||
|
||||
PATCHFUNC patchFunc;
|
||||
patchFunc=(PATCHFUNC)GetProcAddress(hInst,"RTPatchApply32@12");
|
||||
if (patchFunc==NULL)
|
||||
{
|
||||
char message[256];
|
||||
LoadString(NULL,IDS_BAD_LIBRARY,message,256);
|
||||
char title[128];
|
||||
LoadString(NULL,IDS_ERROR,title,128);
|
||||
MessageBox(NULL,message,title,MB_OK);
|
||||
return;
|
||||
}
|
||||
|
||||
char patchArgs[200];
|
||||
sprintf(patchArgs,"\"%s\" .",patchfile);
|
||||
int rtpErrCode=patchFunc(patchArgs,PatchCallBack,TRUE);
|
||||
FreeLibrary(hInst); // unload the DLL
|
||||
_unlink(patchfile); // delete the patch
|
||||
|
||||
DestroyWindow(dialog); // get rid of the dialog
|
||||
|
||||
// Now we have to update the registry so the version is correct
|
||||
// The version is the first integer in the filename
|
||||
// Eg: 22456_patch.rtp means version 22456 goes into the registry
|
||||
|
||||
// The version# starts after the last '\' char
|
||||
char *cptr=patchfile;
|
||||
char *tempPtr;
|
||||
DWORD version;
|
||||
while( (tempPtr=strchr(cptr,'\\')) !=NULL)
|
||||
cptr=tempPtr+1;
|
||||
if (cptr)
|
||||
version=atol(cptr);
|
||||
DBGMSG("VERSION TO = "<<version);
|
||||
|
||||
|
||||
char string[256];
|
||||
Wstring key;
|
||||
// Get the InstallPath from the specified registry key
|
||||
sprintf(string,"SKU%d",skuIndex);
|
||||
if (config.getString(string,key)==FALSE)
|
||||
{
|
||||
ERRMSGX("SKU is missing from config file!", "D:\\dev\\launcher\\patch.cpp"); //ERRMSG("SKU is missing from config file!");
|
||||
return;
|
||||
}
|
||||
|
||||
int temp=0;
|
||||
Wstring sku;
|
||||
Wstring path;
|
||||
temp=key.getToken(temp," ",sku);
|
||||
path=key;
|
||||
path.remove(0,temp);
|
||||
while((*(path.get()))==' ') // remove leading spaces
|
||||
path.remove(0,1);
|
||||
// Open the registry key for modifying now...
|
||||
HKEY regKey;
|
||||
LONG regRetval;
|
||||
regRetval=RegOpenKeyEx(HKEY_LOCAL_MACHINE,path.get(),0,
|
||||
KEY_ALL_ACCESS,®Key);
|
||||
if (regRetval!=ERROR_SUCCESS)
|
||||
DBGMSG("Can't open reg key for writing");
|
||||
regRetval=RegSetValueEx(regKey,"Version",0,REG_DWORD,(uint8 *)&version,
|
||||
sizeof(version));
|
||||
|
||||
|
||||
// Create blocking DLG for update info
|
||||
DialogBox(Global_instance,MAKEINTRESOURCE(IDD_CHANGELOG),NULL,(DLGPROC)Update_Info_Proc);
|
||||
}
|
||||
//
|
||||
// Execute now (without rebooting) type patch
|
||||
//
|
||||
else if (strcasecmp(patchfile+strlen(patchfile)-strlen(".exn"),".exn")==0)
|
||||
{
|
||||
Process proc;
|
||||
strcpy(proc.directory,".");
|
||||
strcpy(proc.command,patchfile);
|
||||
Create_Process(proc);
|
||||
Wait_Process(proc);
|
||||
_unlink(patchfile);
|
||||
}
|
||||
//
|
||||
// Web link type patch
|
||||
//
|
||||
// Im about 99.44% sure that this is completely useless.
|
||||
//
|
||||
else if (strcasecmp(patchfile+strlen(patchfile)-strlen(".web"),".web")==0)
|
||||
{
|
||||
char message[256];
|
||||
LoadString(NULL,IDS_WEBPATCH,message,256);
|
||||
char title[128];
|
||||
LoadString(NULL,IDS_WEBPATCH_TITLE,title,128);
|
||||
MessageBox(NULL,message,title,MB_OK);
|
||||
|
||||
FILE *in=fopen(patchfile,"r");
|
||||
if (in!=NULL)
|
||||
{
|
||||
char URL[256];
|
||||
fgets(URL,255,in);
|
||||
fclose(in);
|
||||
ShellExecute(NULL,NULL,URL,NULL,".",SW_SHOW);
|
||||
_unlink(patchfile);
|
||||
//// This is somewhat skanky, but we can't wait
|
||||
//// for the viewer to exit (I tried).
|
||||
exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox(NULL,patchfile,"Patchfile vanished?",MB_OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Shutdown_Computer_Now(void)
|
||||
{
|
||||
HANDLE hToken;
|
||||
TOKEN_PRIVILEGES tkp;
|
||||
|
||||
// Get a token for this process.
|
||||
if (!OpenProcessToken(GetCurrentProcess(),
|
||||
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
|
||||
{
|
||||
//error("OpenProcessToken");
|
||||
}
|
||||
|
||||
// Get the LUID for the shutdown privilege.
|
||||
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
|
||||
&tkp.Privileges[0].Luid);
|
||||
|
||||
tkp.PrivilegeCount = 1; // one privilege to set
|
||||
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
|
||||
// Get the shutdown privilege for this process.
|
||||
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
|
||||
(PTOKEN_PRIVILEGES)NULL, 0);
|
||||
|
||||
// Cannot test the return value of AdjustTokenPrivileges.
|
||||
if (GetLastError() != ERROR_SUCCESS)
|
||||
{
|
||||
//error("AdjustTokenPrivileges");
|
||||
}
|
||||
|
||||
// Shut down the system and force all applications to close.
|
||||
if (!ExitWindowsEx(EWX_REBOOT, 0))
|
||||
{
|
||||
// Should never happen
|
||||
char restart[128];
|
||||
LoadString(NULL,IDS_MUST_RESTART,restart,128);
|
||||
MessageBox(NULL,restart,"OK",MB_OK);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, NULL, 0, 0))
|
||||
{
|
||||
TranslateMessage( &msg );
|
||||
DispatchMessage( &msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Callback during the patching process
|
||||
//
|
||||
LPVOID CALLBACK __export PatchCallBack(UINT Id, LPVOID Param)
|
||||
{
|
||||
char string[128];
|
||||
static int fileCount=0; // number of files to be patched
|
||||
static int currFile=0;
|
||||
|
||||
// Make sure our windows get updated
|
||||
MSG msg;
|
||||
int counter=0;
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE ))
|
||||
{
|
||||
TranslateMessage( &msg );
|
||||
DispatchMessage( &msg );
|
||||
counter++;
|
||||
if (counter==100) // just in case...
|
||||
break;
|
||||
}
|
||||
|
||||
LPVOID RetVal="";
|
||||
bit8 Abort=FALSE;
|
||||
|
||||
//// using the global Dialog pointer, set the current "error" code
|
||||
//g_DlgPtr->SetRTPErrCode(Id);
|
||||
|
||||
int percent;
|
||||
|
||||
switch( Id )
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
// Warning message header/text
|
||||
DBGMSG("P_MSG: "<<((char *)Param));
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// Error message header
|
||||
DBGMSG("P_MSG: "<<((char *)Param));
|
||||
break;
|
||||
|
||||
case 4:
|
||||
// Error message header/text
|
||||
///////*g_LogFile << (char *)Parm << endl;
|
||||
MessageBox(NULL,(char *)Param,"ERROR",MB_OK);
|
||||
{
|
||||
FILE *out=fopen("patch.err","a");
|
||||
time_t timet=time(NULL);
|
||||
fprintf(out,"\n\nPatch Erorr: %s\n",ctime(&timet));
|
||||
fprintf(out,"%s\n",(char *)Param);
|
||||
fclose(out);
|
||||
}
|
||||
break;
|
||||
|
||||
case 9:
|
||||
// progress message
|
||||
break;
|
||||
|
||||
case 0xa:
|
||||
// help message
|
||||
break;
|
||||
|
||||
case 0xb:
|
||||
// patch file comment
|
||||
break;
|
||||
|
||||
case 0xc:
|
||||
// copyright message
|
||||
break; // these just display text
|
||||
|
||||
case 5:
|
||||
// % completed
|
||||
// so adjust the progress bar using the global Dialog pointer
|
||||
/////////g_DlgPtr->SetProgressBar((int)((float)(*(UINT *)Parm)/(float)0x8000*(float)100));
|
||||
percent=((*(UINT *)Param)*100)/0x8000;
|
||||
SendMessage(GetDlgItem(PatchDialog,IDC_PROGRESS2),PBM_SETPOS,percent,0);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
// Number of patch files
|
||||
DBGMSG("6: "<<*((uint32 *)Param));
|
||||
fileCount=*((uint32 *)Param);
|
||||
currFile=0;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
//// begin patch
|
||||
//LoadString(g_AppInstance, IDS_PROCESSING, lpcBuf, 256);
|
||||
//strcpy(buf,lpcBuf);
|
||||
//strcat(buf,(char *)Parm);
|
||||
//g_DlgPtr->SetProgressText(buf);
|
||||
//*g_LogFile << buf << " : ";
|
||||
//fileModified = true;
|
||||
|
||||
DBGMSG("7: "<<(char *)Param);
|
||||
SetWindowText(GetDlgItem(PatchDialog,IDC_FILENAME),(char *)Param);
|
||||
percent=0;
|
||||
SendMessage(GetDlgItem(PatchDialog,IDC_PROGRESS2),PBM_SETPOS,percent,0);
|
||||
|
||||
currFile++;
|
||||
char xofy[64];
|
||||
LoadString(NULL,IDS_FILE_X_OF_Y,xofy,64);
|
||||
sprintf(string,xofy,currFile,fileCount);
|
||||
SetWindowText(GetDlgItem(PatchDialog,IDC_CAPTION),string);
|
||||
|
||||
break;
|
||||
|
||||
case 8:
|
||||
//// end patch
|
||||
//LoadString(g_AppInstance, IDS_PROCCOMPLETE, lpcBuf, 256);
|
||||
//g_DlgPtr->SetProgressText(lpcBuf);
|
||||
//*g_LogFile << " complete" << endl;
|
||||
percent=100;
|
||||
SendMessage(GetDlgItem(PatchDialog,IDC_PROGRESS2),PBM_SETPOS,percent,0);
|
||||
DBGMSG("P_DONE");
|
||||
break;
|
||||
|
||||
case 0xd:
|
||||
//// this one shouldn't happen (only occurs if the command line
|
||||
//// doesn't have a patch file in it, and we insure that it does).
|
||||
//Abort = TRUE;
|
||||
//*g_LogFile << "Incorrect (or none) patch file specified in command line." << endl;
|
||||
break;
|
||||
|
||||
case 0xe:
|
||||
//// this one shouldn't happen either (same reason)
|
||||
//Abort = TRUE;
|
||||
//*g_LogFile << "Incorrect (or none) path specified in command line." << endl;
|
||||
break;
|
||||
|
||||
case 0xf:
|
||||
//// Password Dialog
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
//// Invalid Password Alert
|
||||
break;
|
||||
|
||||
case 0x11:
|
||||
//// Disk Change Dialog
|
||||
break;
|
||||
|
||||
case 0x12:
|
||||
//// Disk Change Alert
|
||||
break;
|
||||
|
||||
case 0x13:
|
||||
//// Confirmation Dialog
|
||||
break;
|
||||
|
||||
case 0x14:
|
||||
//// Location Dialog
|
||||
//Abort = TRUE;
|
||||
//*g_LogFile << "Specified path is incorrect." << endl;
|
||||
break;
|
||||
|
||||
case 0x16:
|
||||
//// Searching Call-back
|
||||
break;
|
||||
|
||||
case 0x15:
|
||||
//// Idle...
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(Abort)
|
||||
return (NULL);
|
||||
else
|
||||
return (RetVal);
|
||||
}
|
41
LAUNCHER/PATCH.H
Normal file
41
LAUNCHER/PATCH.H
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#ifndef PATCH_HEADER
|
||||
#define PATCH_HEADER
|
||||
|
||||
#include "winblows.h"
|
||||
#include "dialog.h"
|
||||
#include "resource.h"
|
||||
#include "wdebug.h"
|
||||
#include "process.h"
|
||||
|
||||
void Apply_Patch(char *patchfile,ConfigFile &config,int skuIndex);
|
||||
|
||||
// Print an error message
|
||||
#define ERRMSGX(X,F)\
|
||||
{\
|
||||
char timebuf[40]; \
|
||||
time_t clock=time(NULL); \
|
||||
strcpy(timebuf,ctime(&clock)); \
|
||||
if (MsgManager::errorStream()) \
|
||||
(*(MsgManager::errorStream())) << "ERR " << timebuf << " [" << \
|
||||
F << " " << __LINE__ << "] " << X << endl; \
|
||||
}
|
||||
|
||||
#endif
|
138
LAUNCHER/PROCESS.CPP
Normal file
138
LAUNCHER/PROCESS.CPP
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#include "process.h"
|
||||
|
||||
Process::Process()
|
||||
{
|
||||
directory[0]=0;
|
||||
command[0]=0;
|
||||
args[0]=0;
|
||||
hProcess=NULL;
|
||||
hThread=NULL;
|
||||
}
|
||||
|
||||
// Create a process
|
||||
bit8 Create_Process(Process &process)
|
||||
{
|
||||
int retval;
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION piProcess;
|
||||
ZeroMemory(&si,sizeof(si));
|
||||
si.cb=sizeof(si);
|
||||
|
||||
char cmdargs[513];
|
||||
memset(cmdargs,0,513);
|
||||
strcpy(cmdargs,process.command);
|
||||
strcat(cmdargs,process.args);
|
||||
|
||||
retval=CreateProcess(NULL,cmdargs,NULL,NULL,FALSE, 0 ,NULL, NULL/*process.directory*/,&si,&piProcess);
|
||||
|
||||
process.hProcess=piProcess.hProcess;
|
||||
process.hThread=piProcess.hThread;
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
bit8 Wait_Process(Process &process)
|
||||
{
|
||||
DWORD retval;
|
||||
retval=WaitForSingleObject(process.hProcess,INFINITE);
|
||||
if (retval==WAIT_OBJECT_0) // process exited
|
||||
return(TRUE);
|
||||
else // can this happen?
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Get the process to run from the config object
|
||||
//
|
||||
bit8 Read_Process_Info(ConfigFile &config,OUT Process &info)
|
||||
{
|
||||
|
||||
Wstring procinfo;
|
||||
if (config.getString("RUN",procinfo)==FALSE)
|
||||
{
|
||||
DBGMSG("Couldn't read the RUN line");
|
||||
return(FALSE);
|
||||
}
|
||||
int offset=0;
|
||||
Wstring dir;
|
||||
Wstring executable;
|
||||
Wstring args;
|
||||
offset=procinfo.getToken(offset," ",dir);
|
||||
offset=procinfo.getToken(offset," ",executable);
|
||||
args=procinfo;
|
||||
args.remove(0,offset);
|
||||
|
||||
///
|
||||
///
|
||||
DBGMSG("RUN: EXE = "<<executable.get()<<" DIR = "<<dir.get()<<
|
||||
" ARGS = "<<args.get());
|
||||
strcpy(info.command,executable.get());
|
||||
strcpy(info.directory,dir.get());
|
||||
strcpy(info.args,args.get());
|
||||
return(TRUE);
|
||||
|
||||
|
||||
/*********************************************************
|
||||
FILE *in;
|
||||
char string[256];
|
||||
bit8 found_space;
|
||||
int i;
|
||||
|
||||
if ((in=fopen(config,"r"))==NULL)
|
||||
return(FALSE);
|
||||
|
||||
while(fgets(string,256,in))
|
||||
{
|
||||
i=0;
|
||||
while ((isspace(string[i]))&&(i<int(strlen(string))))
|
||||
i++;
|
||||
|
||||
// do nothing with empty line or commented line
|
||||
if ((string[i]=='#')||(i==int(strlen(string)-1)))
|
||||
continue;
|
||||
|
||||
strcpy(info.directory,string);
|
||||
found_space=FALSE;
|
||||
for (; i<int(strlen(string)); i++)
|
||||
{
|
||||
if (isspace(info.directory[i]))
|
||||
{
|
||||
info.directory[i]=0;
|
||||
found_space=TRUE;
|
||||
}
|
||||
else if (found_space)
|
||||
break;
|
||||
}
|
||||
|
||||
strcpy(info.command,string+i);
|
||||
for (i=0; i<int(strlen(info.command)); i++)
|
||||
if ((info.command[i]=='\n')||(info.command[i]=='\r'))
|
||||
info.command[i]=0;
|
||||
|
||||
//printf("DIR = '%s' CMD = '%s'\n",info.directory,info.command);
|
||||
|
||||
// We only have 1 process for this
|
||||
break;
|
||||
}
|
||||
fclose(in);
|
||||
return(TRUE);
|
||||
**********************************************/
|
||||
}
|
44
LAUNCHER/PROCESS.H
Normal file
44
LAUNCHER/PROCESS.H
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#ifndef PROCESS_HEADER
|
||||
#define PROCESS_HEADER
|
||||
|
||||
#include <windows.h>
|
||||
#include "wstypes.h"
|
||||
#include "wdebug.h"
|
||||
#include "configfile.h"
|
||||
|
||||
class Process
|
||||
{
|
||||
public:
|
||||
Process();
|
||||
|
||||
char directory[256];
|
||||
char command[256];
|
||||
char args[256];
|
||||
HANDLE hProcess;
|
||||
HANDLE hThread;
|
||||
};
|
||||
|
||||
bit8 Read_Process_Info(ConfigFile &config,OUT Process &info);
|
||||
bit8 Create_Process(Process &process);
|
||||
bit8 Wait_Process(Process &process);
|
||||
|
||||
|
||||
#endif
|
BIN
LAUNCHER/REDALERT.ICO
Normal file
BIN
LAUNCHER/REDALERT.ICO
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
54
LAUNCHER/RESOURCE.H
Normal file
54
LAUNCHER/RESOURCE.H
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Developer Studio generated include file.
|
||||
// Used by launcher1.rc
|
||||
//
|
||||
#define IDS_SYS_RESTART 1
|
||||
#define IDS_SYS_RESTART_TITLE 2
|
||||
#define IDS_WEBPATCH 3
|
||||
#define IDS_WEBPATCH_TITLE 4
|
||||
#define IDS_FILE_X_OF_Y 5
|
||||
#define IDS_MUST_RESTART 6
|
||||
#define IDS_RUNONCE_ERR 7
|
||||
#define IDS_ERROR 8
|
||||
#define IDS_ERR_MISSING_FILE 9
|
||||
#define IDS_BAD_LIBRARY 10
|
||||
#define IDD_DIALOG1 101
|
||||
#define IDI_ICON1 102
|
||||
#define IDD_CHANGELOG 103
|
||||
#define IDI_ICON 108
|
||||
#define IDI_ICON2 112
|
||||
#define IDI_ICON3 117
|
||||
#define IDC_PROGRESS2 1001
|
||||
#define IDC_SPLASH 1004
|
||||
#define IDC_FILENAME 1009
|
||||
#define IDC_CAPTION 1010
|
||||
#define IDC_TEXT 1011
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 118
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1013
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
142
LAUNCHER/STREAMER.CPP
Normal file
142
LAUNCHER/STREAMER.CPP
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "streamer.h"
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
Streamer::Streamer() : streambuf()
|
||||
{
|
||||
int state=unbuffered();
|
||||
unbuffered(0); // 0 = buffered, 1 = unbuffered
|
||||
}
|
||||
|
||||
Streamer::~Streamer()
|
||||
{
|
||||
sync();
|
||||
delete[](base());
|
||||
}
|
||||
|
||||
int Streamer::setOutputDevice(OutputDevice *device)
|
||||
{
|
||||
Output_Device=device;
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
// put n chars from string into buffer
|
||||
int Streamer::xsputn(const char* buf, int size) //implementation of sputn
|
||||
{
|
||||
|
||||
if (size<=0) // Nothing to do
|
||||
return(0);
|
||||
|
||||
const unsigned char *ptr=(const unsigned char *)buf;
|
||||
for (int i=0; i<size; i++, ptr++)
|
||||
{
|
||||
if(*ptr=='\n')
|
||||
{
|
||||
if (overflow(*ptr)==EOF)
|
||||
return(i);
|
||||
}
|
||||
else if (sputc(*ptr)==EOF)
|
||||
return(i);
|
||||
}
|
||||
return(size);
|
||||
}
|
||||
|
||||
// Flush the buffer and make more room if needed
|
||||
int Streamer::overflow(int c)
|
||||
{
|
||||
|
||||
if (c==EOF)
|
||||
return(sync());
|
||||
if ((pbase()==0) && (doallocate()==0))
|
||||
return(EOF);
|
||||
if((pptr() >= epptr()) && (sync()==EOF))
|
||||
return(EOF);
|
||||
else {
|
||||
sputc(c);
|
||||
if ((unbuffered() && c=='\n' || pptr() >= epptr())
|
||||
&& sync()==EOF) {
|
||||
return(EOF);
|
||||
}
|
||||
return(c);
|
||||
}
|
||||
}
|
||||
|
||||
// This is a write only stream, this should never happen
|
||||
int Streamer::underflow(void)
|
||||
{
|
||||
return(EOF);
|
||||
}
|
||||
|
||||
int Streamer::doallocate()
|
||||
{
|
||||
|
||||
if (base()==NULL)
|
||||
{
|
||||
char *buf=new char[(2*STREAMER_BUFSIZ)]; // deleted by destructor
|
||||
memset(buf,0,2*STREAMER_BUFSIZ);
|
||||
|
||||
// Buffer
|
||||
setb(
|
||||
buf, // base pointer
|
||||
buf+STREAMER_BUFSIZ, // ebuf pointer (end of buffer);
|
||||
0); // 0 = manual deletion of buff
|
||||
|
||||
// Get area
|
||||
setg(
|
||||
buf, // eback
|
||||
buf, // gptr
|
||||
buf); // egptr
|
||||
|
||||
buf+=STREAMER_BUFSIZ;
|
||||
// Put area
|
||||
setp(buf,buf+STREAMER_BUFSIZ);
|
||||
return(1);
|
||||
}
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int Streamer::sync()
|
||||
{
|
||||
if (pptr()<=pbase()) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
int wlen=pptr()-pbase();
|
||||
|
||||
if (Output_Device)
|
||||
{
|
||||
Output_Device->print(pbase(),wlen);
|
||||
}
|
||||
|
||||
if (unbuffered()) {
|
||||
setp(pbase(),pbase());
|
||||
}
|
||||
else {
|
||||
setp(pbase(),pbase()+STREAMER_BUFSIZ);
|
||||
}
|
||||
return(0);
|
||||
}
|
60
LAUNCHER/STREAMER.H
Normal file
60
LAUNCHER/STREAMER.H
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#ifndef STREAMER_HEADER
|
||||
#define STREAMER_HEADER
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <iostream.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "odevice.h"
|
||||
|
||||
#ifndef STREAMER_BUFSIZ
|
||||
// This limits the number of characters that can be sent to a single 'print'
|
||||
// call. If your debug message is bigger than this, it will get split over
|
||||
// multiple 'print' calls. That's usually not a problem.
|
||||
#define STREAMER_BUFSIZ 2048
|
||||
#endif
|
||||
|
||||
|
||||
// Provide a streambuf interface for a class that can 'print'
|
||||
class Streamer : public streambuf
|
||||
{
|
||||
public:
|
||||
Streamer();
|
||||
virtual ~Streamer();
|
||||
|
||||
int setOutputDevice(OutputDevice *output_device);
|
||||
|
||||
protected:
|
||||
// Virtual methods from streambuf
|
||||
int xsputn(const char* s, int n); // buffer some characters
|
||||
int overflow(int = EOF); // flush buffer and make more room
|
||||
int underflow(void); // Does nothing
|
||||
int sync();
|
||||
|
||||
int doallocate(); // allocate a buffer
|
||||
|
||||
|
||||
OutputDevice *Output_Device;
|
||||
};
|
||||
|
||||
#endif
|
51
LAUNCHER/UTIL/FILED.H
Normal file
51
LAUNCHER/UTIL/FILED.H
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#ifndef FILED_HEADER
|
||||
#define FILED_HEADER
|
||||
|
||||
#include "odevice.h"
|
||||
|
||||
class FileD : public OutputDevice
|
||||
{
|
||||
public:
|
||||
FileD(char *filename)
|
||||
{
|
||||
out=fopen(filename,"w");
|
||||
if (out==NULL)
|
||||
out=fopen("FileDev.out","w");
|
||||
}
|
||||
|
||||
virtual ~FileD()
|
||||
{ fclose(out); }
|
||||
|
||||
virtual int print(const char *str,int len)
|
||||
{
|
||||
char *string=new char[len+1];
|
||||
memset(string,0,len+1);
|
||||
memcpy(string,str,len);
|
||||
fprintf(out,"%s",string);
|
||||
delete[](string);
|
||||
fflush(out);
|
||||
return(len);
|
||||
}
|
||||
|
||||
FILE *out;
|
||||
};
|
||||
|
||||
#endif
|
40
LAUNCHER/UTIL/MBOXD.H
Normal file
40
LAUNCHER/UTIL/MBOXD.H
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#ifndef MBOXD_HEADER
|
||||
#define MBOXD_HEADER
|
||||
|
||||
#include "odevice.h"
|
||||
|
||||
class MboxD : public OutputDevice
|
||||
{
|
||||
public:
|
||||
|
||||
virtual int print(const char *str,int len)
|
||||
{
|
||||
char *string=new char[len+1];
|
||||
memset(string,0,len+1);
|
||||
memcpy(string,str,len);
|
||||
MessageBox(NULL,string,"Debug Message", MB_OK | MB_ICONINFORMATION);
|
||||
delete[](string);
|
||||
return(len);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
57
LAUNCHER/UTIL/MONOD.CPP
Normal file
57
LAUNCHER/UTIL/MONOD.CPP
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#include "monod.h"
|
||||
|
||||
MonoD::MonoD(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
unsigned long retval;
|
||||
handle = CreateFile("\\\\.\\MONO", GENERIC_READ|GENERIC_WRITE, 0, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DeviceIoControl(handle, (DWORD)IOCTL_MONO_CLEAR_SCREEN, NULL, 0, NULL, 0,
|
||||
&retval,0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
MonoD::~MonoD()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
CloseHandle(handle);
|
||||
handle=NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
int MonoD::print(const char *str, int len)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
unsigned long retval;
|
||||
WriteFile(handle, str, len, &retval, NULL);
|
||||
////DeviceIoControl(handle, (DWORD)IOCTL_MONO_PRINT_RAW, (void *)str, len, NULL, 0,
|
||||
//// &retval,0);
|
||||
return(len);
|
||||
#else
|
||||
for (int i=0; i<len; i++)
|
||||
fprintf(stderr,"%c",str[i]);
|
||||
return(len);
|
||||
#endif
|
||||
}
|
74
LAUNCHER/UTIL/MONOD.H
Normal file
74
LAUNCHER/UTIL/MONOD.H
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#ifndef MONOD_HEADER
|
||||
#define MONOD_HEADER
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "odevice.h"
|
||||
|
||||
///////////////////////// WIN32 ONLY ///////////////////////////////////
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
|
||||
/*
|
||||
** This is the identifier for the Monochrome Display Driver
|
||||
*/
|
||||
#define FILE_DEVICE_MONO 0x00008000
|
||||
|
||||
/*
|
||||
** These are the IOCTL commands supported by the Monochrome Display Driver.
|
||||
*/
|
||||
#define IOCTL_MONO_HELP_SCREEN CTL_CODE(FILE_DEVICE_MONO, 0x800, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_CLEAR_SCREEN CTL_CODE(FILE_DEVICE_MONO, 0x801, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_PRINT_RAW CTL_CODE(FILE_DEVICE_MONO, 0x802, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_SET_CURSOR CTL_CODE(FILE_DEVICE_MONO, 0x803, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_SCROLL CTL_CODE(FILE_DEVICE_MONO, 0x804, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_BRING_TO_TOP CTL_CODE(FILE_DEVICE_MONO, 0x805, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_SET_ATTRIBUTE CTL_CODE(FILE_DEVICE_MONO, 0x806, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_PAN CTL_CODE(FILE_DEVICE_MONO, 0x807, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_LOCK CTL_CODE(FILE_DEVICE_MONO, 0x808, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_UNLOCK CTL_CODE(FILE_DEVICE_MONO, 0x809, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_SET_WINDOW CTL_CODE(FILE_DEVICE_MONO, 0x80A, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_RESET_WINDOW CTL_CODE(FILE_DEVICE_MONO, 0x80B, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_SET_FLAG CTL_CODE(FILE_DEVICE_MONO, 0x80C, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_CLEAR_FLAG CTL_CODE(FILE_DEVICE_MONO, 0x80D, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
#define IOCTL_MONO_FILL_ATTRIB CTL_CODE(FILE_DEVICE_MONO, 0x80E, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
|
||||
#endif // ifdef _WIN32
|
||||
|
||||
class MonoD : public OutputDevice
|
||||
{
|
||||
public:
|
||||
MonoD();
|
||||
~MonoD();
|
||||
|
||||
virtual int print(const char *str,int len);
|
||||
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
HANDLE handle;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
32
LAUNCHER/UTIL/ODEVICE.H
Normal file
32
LAUNCHER/UTIL/ODEVICE.H
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#ifndef ODEVICE_HEADER
|
||||
#define ODEVICE_HEADER
|
||||
|
||||
// This virtual base class provides an interface for output devices
|
||||
// that can be used for the debugging package.
|
||||
class OutputDevice
|
||||
{
|
||||
public:
|
||||
OutputDevice() {}
|
||||
virtual ~OutputDevice() {};
|
||||
virtual int print(const char *s,int len)=0;
|
||||
};
|
||||
|
||||
#endif
|
39
LAUNCHER/UTIL/STDERRD.H
Normal file
39
LAUNCHER/UTIL/STDERRD.H
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#ifndef STDERRD_HEADER
|
||||
#define STDERRD_HEADER
|
||||
|
||||
#include "odevice.h"
|
||||
|
||||
class StderrD : public OutputDevice
|
||||
{
|
||||
public:
|
||||
|
||||
virtual int print(const char *str,int len)
|
||||
{
|
||||
char *string=new char[len+1];
|
||||
memset(string,0,len+1);
|
||||
memcpy(string,str,len);
|
||||
fprintf(stderr,"%s",string);
|
||||
delete[](string);
|
||||
return(len);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
40
LAUNCHER/UTIL/STDOUTD.H
Normal file
40
LAUNCHER/UTIL/STDOUTD.H
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#ifndef STDOUTD_HEADER
|
||||
#define STDOUTD_HEADER
|
||||
|
||||
#include "odevice.h"
|
||||
|
||||
class StdoutD : public OutputDevice
|
||||
{
|
||||
public:
|
||||
|
||||
virtual int print(const char *str,int len)
|
||||
{
|
||||
char *string=new char[len+1];
|
||||
memcpy(string,str,len);
|
||||
string[len]=0;
|
||||
fprintf(stdout,"%s",string);
|
||||
fflush(stdout);
|
||||
delete[](string);
|
||||
return(len);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
139
LAUNCHER/UTIL/STREAMER.CPP
Normal file
139
LAUNCHER/UTIL/STREAMER.CPP
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "streamer.h"
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
Streamer::Streamer() : streambuf()
|
||||
{
|
||||
int state=unbuffered();
|
||||
unbuffered(0); // 0 = buffered, 1 = unbuffered
|
||||
}
|
||||
|
||||
Streamer::~Streamer()
|
||||
{
|
||||
sync();
|
||||
delete[](base());
|
||||
}
|
||||
|
||||
int Streamer::setOutputDevice(OutputDevice *device)
|
||||
{
|
||||
Output_Device=device;
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
// put n chars from string into buffer
|
||||
int Streamer::xsputn(const char* buf, int size) //implementation of sputn
|
||||
{
|
||||
if (size<=0) // Nothing to do
|
||||
return(0);
|
||||
|
||||
const unsigned char *ptr=(const unsigned char *)buf;
|
||||
for (int i=0; i<size; i++, ptr++)
|
||||
{
|
||||
if(*ptr=='\n')
|
||||
{
|
||||
if (overflow(*ptr)==EOF)
|
||||
return(i);
|
||||
}
|
||||
else if (sputc(*ptr)==EOF)
|
||||
return(i);
|
||||
}
|
||||
return(size);
|
||||
}
|
||||
|
||||
// Flush the buffer and make more room if needed
|
||||
int Streamer::overflow(int c)
|
||||
{
|
||||
if (c==EOF)
|
||||
return(sync());
|
||||
if ((pbase()==0) && (doallocate()==0))
|
||||
return(EOF);
|
||||
if((pptr() >= epptr()) && (sync()==EOF))
|
||||
return(EOF);
|
||||
else {
|
||||
sputc(c);
|
||||
if ((unbuffered() && c=='\n' || pptr() >= epptr())
|
||||
&& sync()==EOF) {
|
||||
return(EOF);
|
||||
}
|
||||
return(c);
|
||||
}
|
||||
}
|
||||
|
||||
// This is a write only stream, this should never happen
|
||||
int Streamer::underflow(void)
|
||||
{
|
||||
return(EOF);
|
||||
}
|
||||
|
||||
int Streamer::doallocate()
|
||||
{
|
||||
if (base()==NULL)
|
||||
{
|
||||
char *buf=new char[(2*STREAMER_BUFSIZ)]; // deleted by destructor
|
||||
memset(buf,0,2*STREAMER_BUFSIZ);
|
||||
|
||||
// Buffer
|
||||
setb(
|
||||
buf, // base pointer
|
||||
buf+STREAMER_BUFSIZ, // ebuf pointer (end of buffer);
|
||||
0); // 0 = manual deletion of buff
|
||||
|
||||
// Get area
|
||||
setg(
|
||||
buf, // eback
|
||||
buf, // gptr
|
||||
buf); // egptr
|
||||
|
||||
buf+=STREAMER_BUFSIZ;
|
||||
// Put area
|
||||
setp(buf,buf+STREAMER_BUFSIZ);
|
||||
return(1);
|
||||
}
|
||||
else
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int Streamer::sync()
|
||||
{
|
||||
if (pptr()<=pbase()) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
int wlen=pptr()-pbase();
|
||||
|
||||
if (Output_Device)
|
||||
{
|
||||
Output_Device->print(pbase(),wlen);
|
||||
}
|
||||
|
||||
if (unbuffered()) {
|
||||
setp(pbase(),pbase());
|
||||
}
|
||||
else {
|
||||
setp(pbase(),pbase()+STREAMER_BUFSIZ);
|
||||
}
|
||||
return(0);
|
||||
}
|
60
LAUNCHER/UTIL/STREAMER.H
Normal file
60
LAUNCHER/UTIL/STREAMER.H
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#ifndef STREAMER_HEADER
|
||||
#define STREAMER_HEADER
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <iostream.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "odevice.h"
|
||||
|
||||
#ifndef STREAMER_BUFSIZ
|
||||
// This limits the number of characters that can be sent to a single 'print'
|
||||
// call. If your debug message is bigger than this, it will get split over
|
||||
// multiple 'print' calls. That's usually not a problem.
|
||||
#define STREAMER_BUFSIZ 2048
|
||||
#endif
|
||||
|
||||
|
||||
// Provide a streambuf interface for a class that can 'print'
|
||||
class Streamer : public streambuf
|
||||
{
|
||||
public:
|
||||
Streamer();
|
||||
virtual ~Streamer();
|
||||
|
||||
int setOutputDevice(OutputDevice *output_device);
|
||||
|
||||
protected:
|
||||
// Virtual methods from streambuf
|
||||
int xsputn(const char* s, int n); // buffer some characters
|
||||
int overflow(int = EOF); // flush buffer and make more room
|
||||
int underflow(void); // Does nothing
|
||||
int sync();
|
||||
|
||||
int doallocate(); // allocate a buffer
|
||||
|
||||
|
||||
OutputDevice *Output_Device;
|
||||
};
|
||||
|
||||
#endif
|
35
LAUNCHER/UTIL/SYSLOGD.CPP
Normal file
35
LAUNCHER/UTIL/SYSLOGD.CPP
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#include "syslogd.h"
|
||||
|
||||
SyslogD::SyslogD(char *ident,int logopt,int facility,int _priority)
|
||||
{
|
||||
openlog(ident,logopt,facility);
|
||||
priority=_priority;
|
||||
}
|
||||
|
||||
int SyslogD::print(const char *str, int len)
|
||||
{
|
||||
char *temp_str=new char[len+1];
|
||||
memset(temp_str,0,len+1);
|
||||
strncpy(temp_str,str,len);
|
||||
syslog(priority,temp_str);
|
||||
delete[](temp_str);
|
||||
return(len);
|
||||
}
|
38
LAUNCHER/UTIL/SYSLOGD.H
Normal file
38
LAUNCHER/UTIL/SYSLOGD.H
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#ifndef SYSLOGD_HEADER
|
||||
#define SYSLOGD_HEADER
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include "odevice.h"
|
||||
|
||||
class SyslogD : public OutputDevice
|
||||
{
|
||||
public:
|
||||
SyslogD(char *ident,int logopt,int facility,int priority);
|
||||
virtual int print(const char *str,int len);
|
||||
|
||||
private:
|
||||
int priority;
|
||||
};
|
||||
|
||||
#endif
|
148
LAUNCHER/UTIL/WDEBUG.CPP
Normal file
148
LAUNCHER/UTIL/WDEBUG.CPP
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "wdebug.h"
|
||||
#include "streamer.h"
|
||||
#include "odevice.h"
|
||||
|
||||
|
||||
static MsgManager *msg_manager=NULL;
|
||||
|
||||
static int debug_enabled=0;
|
||||
static ostream *debug_ostream=NULL;
|
||||
static Streamer debug_streamer;
|
||||
|
||||
static int info_enabled=0;
|
||||
static ostream *info_ostream=NULL;
|
||||
static Streamer info_streamer;
|
||||
|
||||
static int warn_enabled=0;
|
||||
static ostream *warn_ostream=NULL;
|
||||
static Streamer warn_streamer;
|
||||
|
||||
static int error_enabled=0;
|
||||
static ostream *error_ostream=NULL;
|
||||
static Streamer error_streamer;
|
||||
|
||||
|
||||
// Don't dare touch this semaphore in application code!
|
||||
Sem4 DebugLibSemaphore;
|
||||
|
||||
|
||||
int MsgManager::setAllStreams(OutputDevice *device)
|
||||
{
|
||||
if (device==NULL)
|
||||
return(1);
|
||||
|
||||
DebugLibSemaphore.Wait();
|
||||
debug_streamer.setOutputDevice(device);
|
||||
delete(debug_ostream);
|
||||
debug_ostream=new ostream(&debug_streamer);
|
||||
|
||||
info_streamer.setOutputDevice(device);
|
||||
delete(info_ostream);
|
||||
info_ostream=new ostream(&info_streamer);
|
||||
|
||||
warn_streamer.setOutputDevice(device);
|
||||
delete(warn_ostream);
|
||||
warn_ostream=new ostream(&warn_streamer);
|
||||
|
||||
error_streamer.setOutputDevice(device);
|
||||
delete(error_ostream);
|
||||
error_ostream=new ostream(&error_streamer);
|
||||
|
||||
DebugLibSemaphore.Post();
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int MsgManager::setDebugStream(OutputDevice *device)
|
||||
{
|
||||
if (device==NULL)
|
||||
return(1);
|
||||
|
||||
DebugLibSemaphore.Wait();
|
||||
debug_streamer.setOutputDevice(device);
|
||||
delete(debug_ostream);
|
||||
debug_ostream=new ostream(&debug_streamer);
|
||||
DebugLibSemaphore.Post();
|
||||
return(0);
|
||||
}
|
||||
|
||||
int MsgManager::setInfoStream(OutputDevice *device)
|
||||
{
|
||||
if (device==NULL)
|
||||
return(1);
|
||||
|
||||
DebugLibSemaphore.Wait();
|
||||
info_streamer.setOutputDevice(device);
|
||||
delete(info_ostream);
|
||||
info_ostream=new ostream(&info_streamer);
|
||||
DebugLibSemaphore.Post();
|
||||
return(0);
|
||||
}
|
||||
|
||||
int MsgManager::setWarnStream(OutputDevice *device)
|
||||
{
|
||||
if (device==NULL)
|
||||
return(1);
|
||||
|
||||
DebugLibSemaphore.Wait();
|
||||
warn_streamer.setOutputDevice(device);
|
||||
delete(warn_ostream);
|
||||
warn_ostream=new ostream(&warn_streamer);
|
||||
DebugLibSemaphore.Post();
|
||||
return(0);
|
||||
}
|
||||
|
||||
int MsgManager::setErrorStream(OutputDevice *device)
|
||||
{
|
||||
if (device==NULL)
|
||||
return(1);
|
||||
|
||||
DebugLibSemaphore.Wait();
|
||||
error_streamer.setOutputDevice(device);
|
||||
delete(error_ostream);
|
||||
error_ostream=new ostream(&error_streamer);
|
||||
DebugLibSemaphore.Post();
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ostream *MsgManager::debugStream(void)
|
||||
{
|
||||
return(debug_ostream);
|
||||
}
|
||||
|
||||
ostream *MsgManager::infoStream(void)
|
||||
{
|
||||
return(info_ostream);
|
||||
}
|
||||
|
||||
ostream *MsgManager::warnStream(void)
|
||||
{
|
||||
return(warn_ostream);
|
||||
}
|
||||
|
||||
ostream *MsgManager::errorStream(void)
|
||||
{
|
||||
return(error_ostream);
|
||||
}
|
216
LAUNCHER/UTIL/WDEBUG.H
Normal file
216
LAUNCHER/UTIL/WDEBUG.H
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
/*****************************************************************************\
|
||||
wdebug Neal Kettler
|
||||
|
||||
MT-LEVEL
|
||||
MT-Safe
|
||||
|
||||
The debugging module is pretty good for debugging and it has some message
|
||||
printing stuff as well. The basic idea is that you write a class that
|
||||
inherits from OutputDevice (severall are provided) and assign that output
|
||||
device to a stream. There are seperate streams for debugging, information,
|
||||
warning, and error messages. Each one can have a seperate output device,
|
||||
or they can all have the same one. Debugging messages only get compiled
|
||||
in if your module defines 'DEBUG'. If you don't define debug, then not even
|
||||
the text of the debugging message gets into the binary. All the other
|
||||
output streams get printed regardless of whether DEBUG is defined.
|
||||
|
||||
Sample usage:
|
||||
FileD debug_device("gameres.debug"); // create a file device
|
||||
MsgManager::setDebugStream(&debug_device);
|
||||
DBGMSG("This debug message #" << 1 << " you use C++ streams");
|
||||
|
||||
Note that since these are defines you really don't need to put a semicolon
|
||||
at the end, and it can be bad in situations like this:
|
||||
|
||||
if (x)
|
||||
DBGMSG("Stuff is broken");
|
||||
else
|
||||
DBGMSG("Stuff is NOT broken");
|
||||
|
||||
This won't compile, read the code until you figure it out. Only then
|
||||
will you be ready to leave grasshopper.
|
||||
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef WDEBUG_HEADER
|
||||
#define WDEBUG_HEADER
|
||||
|
||||
#include <iostream.h>
|
||||
#include "sem4.h"
|
||||
#include "odevice.h"
|
||||
#include "streamer.h"
|
||||
|
||||
// This is needed because the streams return a pointer. Every time you
|
||||
// change the output device the old stream is deleted, and a new one
|
||||
// is created.
|
||||
extern Sem4 DebugLibSemaphore;
|
||||
|
||||
// Print an information message
|
||||
#define INFMSG(X)\
|
||||
{\
|
||||
char timebuf[40]; \
|
||||
time_t clock=time(NULL); \
|
||||
cftime(timebuf,"%D %T",&clock); \
|
||||
DebugLibSemaphore.Wait(); \
|
||||
if (MsgManager::infoStream()) \
|
||||
(*(MsgManager::infoStream())) << "INF " << timebuf << " [" << \
|
||||
__FILE__ << " " << __LINE__ << "] " << X << endl; \
|
||||
DebugLibSemaphore.Post(); \
|
||||
}
|
||||
|
||||
// Print a warning message
|
||||
#define WRNMSG(X)\
|
||||
{\
|
||||
char timebuf[40]; \
|
||||
time_t clock=time(NULL); \
|
||||
cftime(timebuf,"%D %T",&clock); \
|
||||
DebugLibSemaphore.Wait(); \
|
||||
if (MsgManager::warnStream()) \
|
||||
(*(MsgManager::warnStream())) << "WRN " << timebuf << " [" << \
|
||||
__FILE__ << " " << __LINE__ << "] " << X << endl; \
|
||||
DebugLibSemaphore.Post(); \
|
||||
}
|
||||
|
||||
// Print an error message
|
||||
#define ERRMSG(X)\
|
||||
{\
|
||||
char timebuf[40]; \
|
||||
time_t clock=time(NULL); \
|
||||
cftime(timebuf,"%D %T",&clock); \
|
||||
DebugLibSemaphore.Wait(); \
|
||||
if (MsgManager::errorStream()) \
|
||||
(*(MsgManager::errorStream())) << "ERR " << timebuf << " [" << \
|
||||
__FILE__ << " " << __LINE__ << "] " << X << endl; \
|
||||
DebugLibSemaphore.Post(); \
|
||||
}
|
||||
|
||||
|
||||
// Just get a stream to the information device, no extra junk
|
||||
#define INFSTREAM(X)\
|
||||
{\
|
||||
DebugLibSemaphore.Wait(); \
|
||||
if (MsgManager::infoStream()) \
|
||||
(*(MsgManager::infoStream())) << X;\
|
||||
DebugLibSemaphore.Post(); \
|
||||
}
|
||||
|
||||
// Just get a stream to the warning device, no extra junk
|
||||
#define WRNSTREAM(X)\
|
||||
{\
|
||||
DebugLibSemaphore.Wait(); \
|
||||
if (MsgManager::warnStream()) \
|
||||
(*(MsgManager::warnStream())) << X;\
|
||||
DebugLibSemaphore.Post(); \
|
||||
}
|
||||
|
||||
// Just get a stream to the error device, no extra junk
|
||||
#define ERRSTREAM(X)\
|
||||
{\
|
||||
DebugLibSemaphore.Wait(); \
|
||||
if (MsgManager::errorStream()) \
|
||||
(*(MsgManager::errorStream())) << X;\
|
||||
DebugLibSemaphore.Post(); \
|
||||
}
|
||||
|
||||
#ifndef DEBUG
|
||||
|
||||
// No debugging, no debug messages.
|
||||
// Note that anything enclosed in "DBG()" will NOT get executed
|
||||
// unless DEBUG is defined.
|
||||
// They are defined to {} for consistency when DEBUG is defined
|
||||
|
||||
#define DBG(X)
|
||||
#define DBGSTREAM(X) {}
|
||||
#define PVAR(v) {}
|
||||
#define DBGMSG(X) {}
|
||||
#define VERBOSE(X) {}
|
||||
|
||||
#else // DEBUG _is_ defined
|
||||
|
||||
// Execute only if in debugging mode
|
||||
#define DBG(X) X
|
||||
|
||||
// Print a variable
|
||||
#define PVAR(v) \
|
||||
{ \
|
||||
DebugLibSemaphore.Wait(); \
|
||||
if (MsgManager::debugStream()) \
|
||||
(*(MsgManager::debugStream())) << __FILE__ << "[" << __LINE__ << \
|
||||
"]: " << ##V << " = " << V << endl; \
|
||||
DebugLibSemaphore.Post(); \
|
||||
}
|
||||
|
||||
|
||||
#define DBGMSG(X)\
|
||||
{\
|
||||
DebugLibSemaphore.Wait(); \
|
||||
if (MsgManager::debugStream()) \
|
||||
(*(MsgManager::debugStream())) << "DBG [" << __FILE__ << \
|
||||
" " << __LINE__ << "] " << X << endl;\
|
||||
DebugLibSemaphore.Post(); \
|
||||
}
|
||||
|
||||
// Just get a stream to the debugging device, no extra junk
|
||||
#define DBGSTREAM(X)\
|
||||
{\
|
||||
DebugLibSemaphore.Wait(); \
|
||||
if (MsgManager::debugStream()) \
|
||||
(*(MsgManager::debugStream())) << X;\
|
||||
DebugLibSemaphore.Post(); \
|
||||
}
|
||||
|
||||
// Verbosely execute a statement
|
||||
#define VERBOSE(X)\
|
||||
{ \
|
||||
DebugLibSemaphore.Wait(); \
|
||||
if (MsgManager::debugStream()) \
|
||||
(*(DebugManager::debugStream())) << __FILE__ << "[" << __LINE__ << \
|
||||
"]: " << ##X << endl; X \
|
||||
DebugLibSemaphore.Post(); \
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
|
||||
class MsgManager
|
||||
{
|
||||
protected:
|
||||
MsgManager();
|
||||
|
||||
public:
|
||||
static int setAllStreams(OutputDevice *device);
|
||||
static int setDebugStream(OutputDevice *device);
|
||||
static int setInfoStream(OutputDevice *device);
|
||||
static int setWarnStream(OutputDevice *device);
|
||||
static int setErrorStream(OutputDevice *device);
|
||||
|
||||
static void enableDebug(int flag);
|
||||
static void enableInfo(int flag);
|
||||
static void enableWarn(int flag);
|
||||
static void enableError(int flag);
|
||||
|
||||
static ostream *debugStream(void);
|
||||
static ostream *infoStream(void);
|
||||
static ostream *warnStream(void);
|
||||
static ostream *errorStream(void);
|
||||
};
|
||||
|
||||
#endif
|
143
LAUNCHER/WDEBUG.CPP
Normal file
143
LAUNCHER/WDEBUG.CPP
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "wdebug.h"
|
||||
#include "streamer.h"
|
||||
#include "odevice.h"
|
||||
|
||||
|
||||
static MsgManager *msg_manager=NULL;
|
||||
|
||||
static int debug_enabled=0;
|
||||
static ostream *debug_ostream=NULL;
|
||||
static Streamer debug_streamer;
|
||||
|
||||
static int info_enabled=0;
|
||||
static ostream *info_ostream=NULL;
|
||||
static Streamer info_streamer;
|
||||
|
||||
static int warn_enabled=0;
|
||||
static ostream *warn_ostream=NULL;
|
||||
static Streamer warn_streamer;
|
||||
|
||||
static int error_enabled=0;
|
||||
static ostream *error_ostream=NULL;
|
||||
static Streamer error_streamer;
|
||||
|
||||
|
||||
|
||||
int MsgManager::setAllStreams(OutputDevice *device)
|
||||
{
|
||||
if (device==NULL)
|
||||
return(1);
|
||||
|
||||
|
||||
debug_streamer.setOutputDevice(device);
|
||||
delete(debug_ostream);
|
||||
debug_ostream=new ostream(&debug_streamer);
|
||||
|
||||
info_streamer.setOutputDevice(device);
|
||||
delete(info_ostream);
|
||||
info_ostream=new ostream(&info_streamer);
|
||||
|
||||
warn_streamer.setOutputDevice(device);
|
||||
delete(warn_ostream);
|
||||
warn_ostream=new ostream(&warn_streamer);
|
||||
|
||||
error_streamer.setOutputDevice(device);
|
||||
delete(error_ostream);
|
||||
error_ostream=new ostream(&error_streamer);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int MsgManager::setDebugStream(OutputDevice *device)
|
||||
{
|
||||
if (device==NULL)
|
||||
return(1);
|
||||
|
||||
|
||||
debug_streamer.setOutputDevice(device);
|
||||
delete(debug_ostream);
|
||||
debug_ostream=new ostream(&debug_streamer);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int MsgManager::setInfoStream(OutputDevice *device)
|
||||
{
|
||||
if (device==NULL)
|
||||
return(1);
|
||||
|
||||
|
||||
info_streamer.setOutputDevice(device);
|
||||
delete(info_ostream);
|
||||
info_ostream=new ostream(&info_streamer);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int MsgManager::setWarnStream(OutputDevice *device)
|
||||
{
|
||||
if (device==NULL)
|
||||
return(1);
|
||||
|
||||
|
||||
warn_streamer.setOutputDevice(device);
|
||||
delete(warn_ostream);
|
||||
warn_ostream=new ostream(&warn_streamer);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int MsgManager::setErrorStream(OutputDevice *device)
|
||||
{
|
||||
if (device==NULL)
|
||||
return(1);
|
||||
|
||||
|
||||
error_streamer.setOutputDevice(device);
|
||||
delete(error_ostream);
|
||||
error_ostream=new ostream(&error_streamer);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ostream *MsgManager::debugStream(void)
|
||||
{
|
||||
return(debug_ostream);
|
||||
}
|
||||
|
||||
ostream *MsgManager::infoStream(void)
|
||||
{
|
||||
return(info_ostream);
|
||||
}
|
||||
|
||||
ostream *MsgManager::warnStream(void)
|
||||
{
|
||||
return(warn_ostream);
|
||||
}
|
||||
|
||||
ostream *MsgManager::errorStream(void)
|
||||
{
|
||||
return(error_ostream);
|
||||
}
|
193
LAUNCHER/WDEBUG.H
Normal file
193
LAUNCHER/WDEBUG.H
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
/*****************************************************************************\
|
||||
wdebug Neal Kettler
|
||||
|
||||
MT-LEVEL
|
||||
MT-UnSafe! (UNIX version is safe though)
|
||||
|
||||
The debugging module is pretty good for debugging and it has some message
|
||||
printing stuff as well. The basic idea is that you write a class that
|
||||
inherits from OutputDevice (severall are provided) and assign that output
|
||||
device to a stream. There are seperate streams for debugging, information,
|
||||
warning, and error messages. Each one can have a seperate output device,
|
||||
or they can all have the same one. Debugging messages only get compiled
|
||||
in if your module defines 'DEBUG'. If you don't define debug, then not even
|
||||
the text of the debugging message gets into the binary. All the other
|
||||
output streams get printed regardless of whether DEBUG is defined.
|
||||
|
||||
Sample usage:
|
||||
FileD debug_device("gameres.debug"); // create a file device
|
||||
MsgManager::setDebugStream(&debug_device);
|
||||
DBGMSG("This debug message #" << 1 << " you use C++ streams");
|
||||
|
||||
Note that since these are defines you really don't need to put a semicolon
|
||||
at the end, and it can be bad in situations like this:
|
||||
|
||||
if (x)
|
||||
DBGMSG("Stuff is broken");
|
||||
else
|
||||
DBGMSG("Stuff is NOT broken");
|
||||
|
||||
This won't compile, read the code until you figure it out. Only then
|
||||
will you be ready to leave grasshopper.
|
||||
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef WDEBUG_HEADER
|
||||
#define WDEBUG_HEADER
|
||||
|
||||
#include <iostream.h>
|
||||
#include "odevice.h"
|
||||
#include "streamer.h"
|
||||
#include <time.h>
|
||||
|
||||
|
||||
|
||||
// Print an information message
|
||||
#define INFMSG(X)\
|
||||
{\
|
||||
char timebuf[40]; \
|
||||
time_t clock=time(NULL); \
|
||||
cftime(timebuf,"%D %T",&clock); \
|
||||
if (MsgManager::infoStream()) \
|
||||
(*(MsgManager::infoStream())) << "INF " << timebuf << " [" << \
|
||||
__FILE__ << " " << __LINE__ << "] " << X << endl; \
|
||||
}
|
||||
|
||||
// Print a warning message
|
||||
#define WRNMSG(X)\
|
||||
{\
|
||||
char timebuf[40]; \
|
||||
time_t clock=time(NULL); \
|
||||
cftime(timebuf,"%D %T",&clock); \
|
||||
if (MsgManager::warnStream()) \
|
||||
(*(MsgManager::warnStream())) << "WRN " << timebuf << " [" << \
|
||||
__FILE__ << " " << __LINE__ << "] " << X << endl; \
|
||||
}
|
||||
|
||||
// Print an error message
|
||||
#define ERRMSG(X)\
|
||||
{\
|
||||
char timebuf[40]; \
|
||||
time_t clock=time(NULL); \
|
||||
strcpy(timebuf,ctime(&clock)); \
|
||||
if (MsgManager::errorStream()) \
|
||||
(*(MsgManager::errorStream())) << "ERR " << timebuf << " [" << \
|
||||
__FILE__ << " " << __LINE__ << "] " << X << endl; \
|
||||
}
|
||||
|
||||
|
||||
// Just get a stream to the information device, no extra junk
|
||||
#define INFSTREAM(X)\
|
||||
{\
|
||||
if (MsgManager::infoStream()) \
|
||||
(*(MsgManager::infoStream())) << X;\
|
||||
}
|
||||
|
||||
// Just get a stream to the warning device, no extra junk
|
||||
#define WRNSTREAM(X)\
|
||||
{\
|
||||
if (MsgManager::warnStream()) \
|
||||
(*(MsgManager::warnStream())) << X;\
|
||||
}
|
||||
|
||||
// Just get a stream to the error device, no extra junk
|
||||
#define ERRSTREAM(X)\
|
||||
{\
|
||||
if (MsgManager::errorStream()) \
|
||||
(*(MsgManager::errorStream())) << X;\
|
||||
}
|
||||
|
||||
#ifndef DEBUG
|
||||
|
||||
// No debugging, no debug messages.
|
||||
// Note that anything enclosed in "DBG()" will NOT get executed
|
||||
// unless DEBUG is defined.
|
||||
// They are defined to {} for consistency when DEBUG is defined
|
||||
|
||||
#define DBG(X)
|
||||
#define DBGSTREAM(X) {}
|
||||
#define PVAR(v) {}
|
||||
#define DBGMSG(X) {}
|
||||
#define VERBOSE(X) {}
|
||||
|
||||
#else // DEBUG _is_ defined
|
||||
|
||||
// Execute only if in debugging mode
|
||||
#define DBG(X) X
|
||||
|
||||
// Print a variable
|
||||
#define PVAR(v) \
|
||||
{ \
|
||||
if (MsgManager::debugStream()) \
|
||||
(*(MsgManager::debugStream())) << __FILE__ << "[" << __LINE__ << \
|
||||
"]: " << ##V << " = " << V << endl; \
|
||||
}
|
||||
|
||||
|
||||
#define DBGMSG(X)\
|
||||
{\
|
||||
if (MsgManager::debugStream()) \
|
||||
(*(MsgManager::debugStream())) << "DBG [" << __FILE__ << \
|
||||
" " << __LINE__ << "] " << X << endl;\
|
||||
}
|
||||
|
||||
// Just get a stream to the debugging device, no extra junk
|
||||
#define DBGSTREAM(X)\
|
||||
{\
|
||||
if (MsgManager::debugStream()) \
|
||||
(*(MsgManager::debugStream())) << X;\
|
||||
}
|
||||
|
||||
// Verbosely execute a statement
|
||||
#define VERBOSE(X)\
|
||||
{ \
|
||||
if (MsgManager::debugStream()) \
|
||||
(*(DebugManager::debugStream())) << __FILE__ << "[" << __LINE__ << \
|
||||
"]: " << ##X << endl; X \
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
|
||||
class MsgManager
|
||||
{
|
||||
protected:
|
||||
MsgManager();
|
||||
|
||||
public:
|
||||
static int setAllStreams(OutputDevice *device);
|
||||
static int setDebugStream(OutputDevice *device);
|
||||
static int setInfoStream(OutputDevice *device);
|
||||
static int setWarnStream(OutputDevice *device);
|
||||
static int setErrorStream(OutputDevice *device);
|
||||
|
||||
static void enableDebug(int flag);
|
||||
static void enableInfo(int flag);
|
||||
static void enableWarn(int flag);
|
||||
static void enableError(int flag);
|
||||
|
||||
static ostream *debugStream(void);
|
||||
static ostream *infoStream(void);
|
||||
static ostream *warnStream(void);
|
||||
static ostream *errorStream(void);
|
||||
};
|
||||
|
||||
#endif
|
186
LAUNCHER/WINBLOWS.CPP
Normal file
186
LAUNCHER/WINBLOWS.CPP
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "winblows.h"
|
||||
|
||||
|
||||
HINSTANCE Global_instance;
|
||||
LPSTR Global_commandline;
|
||||
int Global_commandshow;
|
||||
|
||||
|
||||
/*
|
||||
* WinMain - initialization, message loop
|
||||
*/
|
||||
int PASCAL WinMain( HINSTANCE instance, HINSTANCE, char *command_line, int command_show)
|
||||
{
|
||||
//////MSG msg;
|
||||
|
||||
Global_instance = instance;
|
||||
Global_commandline = command_line;
|
||||
Global_commandshow = command_show;
|
||||
|
||||
int argc;
|
||||
char *argv[64];
|
||||
|
||||
char path_to_exe[512];
|
||||
GetModuleFileName(instance,(char *)&path_to_exe,512);
|
||||
argc=1;
|
||||
argv[0]=path_to_exe;
|
||||
|
||||
|
||||
int command_scan=0;
|
||||
char command_char;
|
||||
do
|
||||
{
|
||||
/*
|
||||
** Scan for non-space character on command line
|
||||
*/
|
||||
do
|
||||
{
|
||||
command_char = *( command_line+command_scan++ );
|
||||
} while ( command_char==' ' );
|
||||
|
||||
if ( command_char!=0 && command_char != 13 )
|
||||
{
|
||||
argv[argc++]=command_line+command_scan-1;
|
||||
|
||||
/*
|
||||
** Scan for space character on command line
|
||||
*/
|
||||
do
|
||||
{
|
||||
command_char = *( command_line+command_scan++ );
|
||||
} while ( command_char!=' ' && command_char != 0 && command_char!=13);
|
||||
*( command_line+command_scan-1 ) = 0;
|
||||
}
|
||||
|
||||
} while ( command_char != 0 && command_char != 13 && argc<20 );
|
||||
|
||||
return(main(argc,argv));
|
||||
|
||||
} /* WinMain */
|
||||
|
||||
|
||||
int Print_WM(UINT message,char *out)
|
||||
{
|
||||
switch(message)
|
||||
{
|
||||
case WM_NULL:
|
||||
sprintf(out,"WM_NULL");
|
||||
break;
|
||||
case WM_CREATE:
|
||||
sprintf(out,"WM_CREATE");
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
sprintf(out,"WM_DESTROY");
|
||||
break;
|
||||
case WM_CANCELMODE:
|
||||
sprintf(out,"WM_CANCELMODE");
|
||||
break;
|
||||
case WM_ERASEBKGND:
|
||||
sprintf(out,"WM_ERASEBKGND");
|
||||
break;
|
||||
case WM_GETTEXT:
|
||||
sprintf(out,"WM_GETTEXT");
|
||||
break;
|
||||
case WM_QUERYOPEN:
|
||||
sprintf(out,"WM_QUERYOPEN");
|
||||
break;
|
||||
case WM_MOVE:
|
||||
sprintf(out,"WM_MOVE");
|
||||
break;
|
||||
case WM_SIZE:
|
||||
sprintf(out,"WM_SIZE");
|
||||
break;
|
||||
case WM_ACTIVATE:
|
||||
sprintf(out,"WM_ACTIVATE");
|
||||
break;
|
||||
case WM_SETFOCUS:
|
||||
sprintf(out,"WM_SETFOCUS");
|
||||
break;
|
||||
case WM_KILLFOCUS:
|
||||
sprintf(out,"WM_KILLFOCUS");
|
||||
break;
|
||||
case WM_ENABLE:
|
||||
sprintf(out,"WM_ENABLE");
|
||||
break;
|
||||
case WM_SETREDRAW:
|
||||
sprintf(out,"WM_REDRAW");
|
||||
break;
|
||||
case WM_PAINT:
|
||||
sprintf(out,"WM_PAINT");
|
||||
break;
|
||||
case WM_CLOSE:
|
||||
sprintf(out,"WM_CLOSE");
|
||||
break;
|
||||
case WM_QUIT:
|
||||
sprintf(out,"WM_QUIT");
|
||||
break;
|
||||
case WM_ACTIVATEAPP:
|
||||
sprintf(out,"WM_ACTIVATEAPP");
|
||||
break;
|
||||
case WM_SETCURSOR:
|
||||
sprintf(out,"WM_SETCURSOR");
|
||||
break;
|
||||
case WM_KEYDOWN:
|
||||
sprintf(out,"WM_KEYDOWN");
|
||||
break;
|
||||
case WM_MOUSEMOVE:
|
||||
sprintf(out,"WM_MOUSEMOVE");
|
||||
break;
|
||||
case WM_WINDOWPOSCHANGING:
|
||||
sprintf(out,"WM_WINDOWPOSCHANGING");
|
||||
break;
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
sprintf(out,"WM_WINDOWPOSCHANGED");
|
||||
break;
|
||||
case WM_DISPLAYCHANGE:
|
||||
sprintf(out,"WM_DISPLAYCHANGE");
|
||||
break;
|
||||
case WM_NCPAINT:
|
||||
sprintf(out,"WM_NCPAINT");
|
||||
break;
|
||||
case WM_PALETTEISCHANGING:
|
||||
sprintf(out,"WM_PALETTEISCHANGING");
|
||||
break;
|
||||
case WM_PALETTECHANGED:
|
||||
sprintf(out,"WM_PALETTECHANGED");
|
||||
break;
|
||||
case WM_NCACTIVATE:
|
||||
sprintf(out,"WM_NCACTIVATE");
|
||||
break;
|
||||
case WM_NCCALCSIZE:
|
||||
sprintf(out,"WM_NCCALCSIZE");
|
||||
break;
|
||||
case WM_SYSCOMMAND:
|
||||
sprintf(out,"WM_SYSCOMMAND");
|
||||
break;
|
||||
default:
|
||||
sprintf(out,"? UNKNOWN ?");
|
||||
return(-1);
|
||||
}
|
||||
return(0);
|
||||
}
|
37
LAUNCHER/WINBLOWS.H
Normal file
37
LAUNCHER/WINBLOWS.H
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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/>.
|
||||
*/
|
||||
|
||||
#ifndef WINBLOWS_HEADER
|
||||
#define WINBLOWS_HEADER
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include"wstypes.h"
|
||||
|
||||
extern HINSTANCE Global_instance;
|
||||
extern LPSTR Global_commandline;
|
||||
extern int Global_commandshow;
|
||||
|
||||
extern int main(int argc, char *argv[]);
|
||||
|
||||
int Print_WM(UINT wm,char *out);
|
||||
|
||||
#endif
|
611
LAUNCHER/WSTRING.CPP
Normal file
611
LAUNCHER/WSTRING.CPP
Normal file
@@ -0,0 +1,611 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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 S T U D I O S *
|
||||
******************************************************************************
|
||||
Project Name: Carpenter (The RedAlert ladder creator)
|
||||
File Name : string.cpp
|
||||
Author : Neal Kettler
|
||||
Start Date : June 1, 1997
|
||||
Last Update : June 17, 1997
|
||||
|
||||
A fairly typical string class. This string class always copies any input
|
||||
string to it's own memory (for assignment or construction).
|
||||
\***************************************************************************/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wstring.h"
|
||||
|
||||
Wstring::Wstring():str(NULL)
|
||||
{ }
|
||||
|
||||
Wstring::Wstring(IN char *string):str(NULL)
|
||||
{ set(string); }
|
||||
|
||||
Wstring::Wstring(IN const Wstring &other):str(NULL)
|
||||
{
|
||||
if (other.str!=NULL)
|
||||
{
|
||||
str=new char[strlen(other.str)+1];
|
||||
strcpy(str,other.str);
|
||||
}
|
||||
}
|
||||
|
||||
Wstring::~Wstring()
|
||||
{ clear(); }
|
||||
|
||||
bit8 Wstring::operator==(IN char *other)
|
||||
{
|
||||
if ((str==NULL)&&(other==NULL))
|
||||
return(TRUE);
|
||||
if(strcmp(str, other) != 0)
|
||||
return(FALSE);
|
||||
else
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
bit8 Wstring::operator==(IN Wstring &other)
|
||||
{
|
||||
if((str == NULL) && (other.str == NULL))
|
||||
return(TRUE);
|
||||
|
||||
if((str == NULL) || (other.str == NULL))
|
||||
return(FALSE);
|
||||
|
||||
if(strcmp(str, other.str) != 0)
|
||||
return(FALSE);
|
||||
else
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
bit8 Wstring::operator!=(IN char *other)
|
||||
{
|
||||
if(strcmp(str, other) != 0)
|
||||
return(TRUE);
|
||||
else
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
|
||||
bit8 Wstring::operator!=(IN Wstring &other)
|
||||
{
|
||||
if((str == NULL) && (other.str == NULL))
|
||||
return(FALSE);
|
||||
|
||||
if((str == NULL) || (other.str == NULL))
|
||||
return(TRUE);
|
||||
|
||||
if(strcmp(str, other.str) != 0)
|
||||
return(TRUE);
|
||||
else
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
|
||||
Wstring &Wstring::operator=(char *other)
|
||||
{
|
||||
set(other);
|
||||
return(*this);
|
||||
}
|
||||
|
||||
|
||||
Wstring &Wstring::operator=(IN Wstring &other)
|
||||
{
|
||||
if(*this == other)
|
||||
return(*this);
|
||||
|
||||
set(other.get());
|
||||
return(*this);
|
||||
}
|
||||
|
||||
|
||||
bit8 Wstring::cat(IN char *s)
|
||||
{
|
||||
char *oldStr;
|
||||
uint32 len;
|
||||
|
||||
if (s==NULL) // it's OK to cat nothing
|
||||
return(TRUE);
|
||||
|
||||
// Save the contents of the string.
|
||||
oldStr = str;
|
||||
|
||||
// Determine the length of the resultant string.
|
||||
len = strlen(s) + 1;
|
||||
if(oldStr)
|
||||
len += strlen(oldStr);
|
||||
|
||||
// Allocate memory for the new string.
|
||||
|
||||
if(!(str = new char[(len * sizeof(char))]))
|
||||
{
|
||||
str = oldStr;
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
// Copy the contents of the old string and concatenate the passed
|
||||
// string.
|
||||
if(oldStr) strcpy(str, oldStr);
|
||||
else str[0] = 0;
|
||||
|
||||
strcat(str, s);
|
||||
|
||||
// delete the old string.
|
||||
if(oldStr)
|
||||
delete[](oldStr);
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
bit8 Wstring::cat(uint32 size, IN char *s)
|
||||
{
|
||||
char *oldStr;
|
||||
uint32 len;
|
||||
|
||||
// Save the contents of the string.
|
||||
oldStr = str;
|
||||
|
||||
// Determine the length of the resultant string.
|
||||
len = size + 1;
|
||||
if(oldStr)
|
||||
len += strlen(oldStr);
|
||||
|
||||
// Allocate memory for the new string.
|
||||
if(!(str = new char[(len * sizeof(char))]))
|
||||
{
|
||||
str = oldStr;
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
// Copy the contents of the old string and concatenate the passed
|
||||
// string.
|
||||
if(oldStr)
|
||||
strcpy(str, oldStr);
|
||||
else
|
||||
str[0] = 0;
|
||||
|
||||
strncat(str, s, size);
|
||||
|
||||
// delete the old string.
|
||||
if(oldStr)
|
||||
delete[](oldStr);
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
bit8 Wstring::cat(IN Wstring &other)
|
||||
{
|
||||
return cat(other.get());
|
||||
}
|
||||
|
||||
Wstring &Wstring::operator+=(IN char *string)
|
||||
{
|
||||
cat(string);
|
||||
return(*this);
|
||||
}
|
||||
|
||||
Wstring &Wstring::operator+=(IN Wstring &other)
|
||||
{
|
||||
cat(other.get());
|
||||
return(*this);
|
||||
}
|
||||
|
||||
Wstring Wstring::operator+(IN char *string)
|
||||
{
|
||||
Wstring temp = *this;
|
||||
temp.cat(string);
|
||||
return(temp);
|
||||
}
|
||||
|
||||
Wstring Wstring::operator+(IN Wstring &s)
|
||||
{
|
||||
Wstring temp = *this;
|
||||
temp.cat(s);
|
||||
return(temp);
|
||||
}
|
||||
|
||||
//
|
||||
// This function deletes 'count' characters indexed by `pos' from the Wstring.
|
||||
// If `pos'+'count' is > the length of the array, the last 'count' characters
|
||||
// of the string are removed. If an error occurs, FALSE is returned.
|
||||
// Otherwise, TRUE is returned. Note: count has a default value of 1.
|
||||
//
|
||||
//
|
||||
char Wstring::remove(sint32 pos,sint32 count)
|
||||
{
|
||||
char *s;
|
||||
sint32 len;
|
||||
|
||||
if (!str)
|
||||
return(FALSE);
|
||||
|
||||
len = (sint32)strlen(str);
|
||||
|
||||
if(pos+count > len)
|
||||
pos = len - count;
|
||||
if (pos < 0)
|
||||
{
|
||||
count+=pos; // If they remove before 0, ignore up till beginning
|
||||
pos=0;
|
||||
}
|
||||
if (count<=0)
|
||||
return(FALSE);
|
||||
|
||||
if(!(s = new char[len-count+1]))
|
||||
{
|
||||
//ErrorMessage(SET_EM, "Insufficient memory to modify Wstring.");
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
///////DBGMSG("Wstring::remove POS: "<<pos<<" LEN: "<<len);
|
||||
|
||||
// put nulls on both ends of substring to be removed
|
||||
str[pos] = 0;
|
||||
str[pos+count-1] = 0;
|
||||
|
||||
strcpy(s, str);
|
||||
strcat(s, &(str[pos + count]));
|
||||
delete[](str);
|
||||
str = s;
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
// Remove all instances of a char from the string
|
||||
bit8 Wstring::removeChar(char c)
|
||||
{
|
||||
int len=0;
|
||||
char *cptr=NULL;
|
||||
bit8 removed=FALSE;
|
||||
|
||||
if (str==NULL)
|
||||
return(FALSE);
|
||||
|
||||
len=strlen(str);
|
||||
while ((cptr=strchr(str,c)) !=NULL)
|
||||
{
|
||||
memmove(cptr,cptr+1,len-1-((int)(cptr-str)));
|
||||
len--;
|
||||
str[len]=0;
|
||||
removed=TRUE;
|
||||
}
|
||||
if (removed)
|
||||
{
|
||||
char *newStr=new char[strlen(str)+1];
|
||||
strcpy(newStr,str);
|
||||
delete[](str);
|
||||
str=newStr;
|
||||
}
|
||||
return(removed);
|
||||
}
|
||||
|
||||
void Wstring::removeSpaces(void)
|
||||
{
|
||||
removeChar(' ');
|
||||
removeChar('\t');
|
||||
}
|
||||
|
||||
void Wstring::clear(void)
|
||||
{
|
||||
if(str)
|
||||
delete[](str);
|
||||
str=NULL;
|
||||
}
|
||||
|
||||
void Wstring::setSize(sint32 size)
|
||||
{
|
||||
clear();
|
||||
if (size<0)
|
||||
return;
|
||||
str=new char[size];
|
||||
memset(str,0,size);
|
||||
}
|
||||
|
||||
void Wstring::cellCopy(char *dest, uint32 len)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
strncpy(dest, str, len);
|
||||
for(i = (uint32)strlen(str); i < len; i++)
|
||||
dest[i] = ' ';
|
||||
dest[len] = 0;
|
||||
}
|
||||
|
||||
char *Wstring::get(void)
|
||||
{
|
||||
if(!str)
|
||||
return "";
|
||||
return str;
|
||||
}
|
||||
|
||||
char Wstring::get(uint32 index)
|
||||
{
|
||||
if(index < strlen(str))
|
||||
return str[index];
|
||||
return(0);
|
||||
}
|
||||
|
||||
uint32 Wstring::length(void)
|
||||
{
|
||||
if(str == NULL)
|
||||
return(0);
|
||||
return((uint32)strlen(str));
|
||||
}
|
||||
|
||||
|
||||
// Insert at given position and shift old stuff to right
|
||||
bit8 Wstring::insert(char *instring, uint32 pos)
|
||||
{
|
||||
if (str==NULL)
|
||||
return(set(instring));
|
||||
if (pos>strlen(str))
|
||||
pos=strlen(str);
|
||||
char *newstr=new char[strlen(str)+strlen(instring)+1];
|
||||
memset(newstr,0,strlen(str)+strlen(instring)+1);
|
||||
strcpy(newstr,str);
|
||||
// move the old data out of the way
|
||||
int bytes=strlen(str)+1-pos;
|
||||
memmove(newstr+pos+strlen(instring),newstr+pos,bytes);
|
||||
// move the new data into place
|
||||
memmove(newstr+pos,instring,strlen(instring));
|
||||
delete[](str);
|
||||
str=newstr;
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
// This function inserts the character specified by `k' into the string at the
|
||||
// position indexed by `pos'. If `pos' is >= the length of the string, it is
|
||||
// appended to the string. If an error occurs, FALSE is returned. Otherwise,
|
||||
// TRUE is returned.
|
||||
bit8 Wstring::insert(char k, uint32 pos)
|
||||
{
|
||||
char *s;
|
||||
uint32 len;
|
||||
char c[2];
|
||||
|
||||
if(!str)
|
||||
{
|
||||
c[0] = k;
|
||||
c[1] = 0;
|
||||
return(set(c));
|
||||
}
|
||||
|
||||
len = (uint32)strlen(str);
|
||||
|
||||
if(pos > len)
|
||||
pos = len;
|
||||
|
||||
if(!(s = (char *)new char[(len + 2)]))
|
||||
{
|
||||
//ErrorMessage(SET_EM, "Insufficient memory to modify Wstring.");
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
c[0] = str[pos];
|
||||
str[pos] = 0;
|
||||
c[1] = 0;
|
||||
strcpy(s, str);
|
||||
str[pos] = c[0];
|
||||
c[0] = k;
|
||||
strcat(s, c);
|
||||
strcat(s, &(str[pos]));
|
||||
delete[](str);
|
||||
str = s;
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// This function replaces any occurences of the string pointed to by
|
||||
// `replaceThis' with the string pointed to by `withThis'. If an error
|
||||
// occurs, FALSE is returned. Otherwise, TRUE is returned.
|
||||
bit8 Wstring::replace(char *replaceThis, char *withThis)
|
||||
{
|
||||
Wstring dest;
|
||||
char *foundStr, *src;
|
||||
uint32 len;
|
||||
|
||||
src=get();
|
||||
while(src && src[0])
|
||||
{
|
||||
foundStr = strstr(src, replaceThis);
|
||||
if(foundStr)
|
||||
{
|
||||
len = (uint32)foundStr - (uint32)src;
|
||||
if(len)
|
||||
{
|
||||
if(!dest.cat(len, src))
|
||||
return(FALSE);
|
||||
}
|
||||
if(!dest.cat(withThis))
|
||||
return(FALSE);
|
||||
src = foundStr + strlen(replaceThis);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!dest.cat(src))
|
||||
return(FALSE);
|
||||
|
||||
src=NULL;
|
||||
}
|
||||
}
|
||||
return(set(dest.get()));
|
||||
}
|
||||
|
||||
|
||||
bit8 Wstring::set(IN char *s)
|
||||
{
|
||||
uint32 len;
|
||||
|
||||
clear();
|
||||
|
||||
len = (uint32)strlen(s) + 1;
|
||||
|
||||
if(!(str = new char[len]))
|
||||
{
|
||||
//ErrorMessage(SET_EM, "Insufficient memory to set Wstring.");
|
||||
return(FALSE);
|
||||
}
|
||||
strcpy(str, s);
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
bit8 Wstring::set(char c, uint32 index)
|
||||
{
|
||||
if(index >= (uint32)strlen(str))
|
||||
return FALSE;
|
||||
|
||||
str[index] = c;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
char Wstring::set(uint32 size, IN char *string)
|
||||
{
|
||||
uint32 len;
|
||||
|
||||
clear();
|
||||
len = size + 1;
|
||||
|
||||
if(!(str = new char[len]))
|
||||
{
|
||||
//ErrorMessage(SET_EM, "Insufficient memory to set Wstring.");
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
// Copy the bytes in the string, and NULL-terminate it.
|
||||
strncpy(str, string, size);
|
||||
str[size] = 0;
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// This function converts all alphabetical characters in the string to lower
|
||||
// case.
|
||||
void Wstring::toLower(void)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
for(i = 0; i < length(); i++)
|
||||
{
|
||||
if((str[i] >= 'A') && (str[i] <= 'Z'))
|
||||
str[i] = tolower(str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This function converts all alphabetical characters in the string to upper
|
||||
// case.
|
||||
void Wstring::toUpper(void)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
for(i = 0; i < length(); i++)
|
||||
{
|
||||
if((str[i] >= 'a') && (str[i] <= 'z'))
|
||||
str[i] = toupper(str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This function truncates the string so its length will match the specified
|
||||
// `len'. If an error occurs, FALSE is returned. Otherwise, TRUE is returned.
|
||||
bit8 Wstring::truncate(uint32 len)
|
||||
{
|
||||
Wstring tmp;
|
||||
if(!tmp.set(len, get()) || !set(tmp.get()))
|
||||
return(FALSE);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
// Truncate the string after the character 'c' (gets rid of 'c' as well)
|
||||
// Do nothing if 'c' isn't in the string
|
||||
bit8 Wstring::truncate(char c)
|
||||
{
|
||||
sint32 len;
|
||||
|
||||
if (str==NULL)
|
||||
return(FALSE);
|
||||
|
||||
char *cptr=strchr(str,c);
|
||||
if (cptr==NULL)
|
||||
return(FALSE);
|
||||
len=(sint32)(cptr-str);
|
||||
truncate((uint32)len);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
// Get a token from this string that's seperated by one or more
|
||||
// chars from the 'delim' string , start at offset & return offset
|
||||
sint32 Wstring::getToken(int offset,char *delim,Wstring &out)
|
||||
{
|
||||
int i;
|
||||
sint32 start;
|
||||
sint32 stop;
|
||||
for (i=offset; i<length(); i++) {
|
||||
if(strchr(delim,str[i])==NULL)
|
||||
break;
|
||||
}
|
||||
if (i>=length())
|
||||
return(-1);
|
||||
start=i;
|
||||
|
||||
for (; i<length(); i++) {
|
||||
if(strchr(delim,str[i])!=NULL)
|
||||
break;
|
||||
}
|
||||
stop=i-1;
|
||||
out.set(str+start);
|
||||
out.truncate((uint32)stop-start+1);
|
||||
return(stop+1);
|
||||
}
|
||||
|
||||
// Get the first line of text after offset. Lines are terminated by '\r\n' or '\n'
|
||||
sint32 Wstring::getLine(int offset, Wstring &out)
|
||||
{
|
||||
int i;
|
||||
sint32 start;
|
||||
sint32 stop;
|
||||
|
||||
start=i=offset;
|
||||
if (start >= length())
|
||||
return(-1);
|
||||
|
||||
for (; i<length(); i++) {
|
||||
if(strchr("\r\n",str[i])!=NULL)
|
||||
break;
|
||||
}
|
||||
stop=i;
|
||||
if ((str[stop]=='\r')&&(str[stop+1]=='\n'))
|
||||
stop++;
|
||||
|
||||
out.set(str+start);
|
||||
out.truncate((uint32)stop-start+1);
|
||||
return(stop+1);
|
||||
}
|
87
LAUNCHER/WSTRING.H
Normal file
87
LAUNCHER/WSTRING.H
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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 S T U D I O S *
|
||||
******************************************************************************
|
||||
Project Name: Carpenter (The RedAlert ladder creator)
|
||||
File Name : main.cpp
|
||||
Author : Neal Kettler
|
||||
Start Date : June 1, 1997
|
||||
Last Update : June 17, 1997
|
||||
\****************************************************************************/
|
||||
|
||||
#ifndef WSTRING_HEADER
|
||||
#define WSTRING_HEADER
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "wstypes.h"
|
||||
|
||||
class Wstring
|
||||
{
|
||||
public:
|
||||
Wstring();
|
||||
Wstring(IN const Wstring &other);
|
||||
Wstring(IN char *string);
|
||||
~Wstring();
|
||||
|
||||
void clear(void);
|
||||
|
||||
bit8 cat(IN char *string);
|
||||
bit8 cat(uint32 size,IN char *string);
|
||||
bit8 cat(IN Wstring &string);
|
||||
|
||||
void cellCopy(OUT char *dest, uint32 len);
|
||||
char remove(sint32 pos, sint32 count);
|
||||
bit8 removeChar(char c);
|
||||
void removeSpaces(void);
|
||||
char *get(void);
|
||||
char get(uint32 index);
|
||||
uint32 length(void);
|
||||
bit8 insert(char c, uint32 pos);
|
||||
bit8 insert(char *instring, uint32 pos);
|
||||
bit8 replace(IN char *replaceThis,IN char *withThis);
|
||||
char set(IN char *str);
|
||||
char set(uint32 size,IN char *str);
|
||||
bit8 set(char c, uint32 index);
|
||||
void setSize(sint32 bytes); // create an empty string
|
||||
void toLower(void);
|
||||
void toUpper(void);
|
||||
bit8 truncate(uint32 len);
|
||||
bit8 truncate(char c); // trunc after char c
|
||||
sint32 getToken(int offset,char *delim,Wstring &out);
|
||||
sint32 getLine(int offset, Wstring &out);
|
||||
|
||||
bit8 operator==(IN char *other);
|
||||
bit8 operator==(IN Wstring &other);
|
||||
bit8 operator!=(IN char *other);
|
||||
bit8 operator!=(IN Wstring &other);
|
||||
|
||||
Wstring &operator=(IN char *other);
|
||||
Wstring &operator=(IN Wstring &other);
|
||||
Wstring &operator+=(IN char *other);
|
||||
Wstring &operator+=(IN Wstring &other);
|
||||
Wstring operator+(IN char *other);
|
||||
Wstring operator+(IN Wstring &other);
|
||||
|
||||
private:
|
||||
char *str; // Pointer to allocated string.
|
||||
};
|
||||
|
||||
#endif
|
82
LAUNCHER/WSTYPES.H
Normal file
82
LAUNCHER/WSTYPES.H
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(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 S T U D I O S *
|
||||
******************************************************************************
|
||||
Project Name:
|
||||
File Name : wtypes.h
|
||||
Author : Neal Kettler
|
||||
Start Date : June 3, 1997
|
||||
Last Update : June 17, 1997
|
||||
|
||||
Standard type definitions for the sake of portability and readability.
|
||||
\***************************************************************************/
|
||||
|
||||
#ifndef WTYPES_HEADER
|
||||
#define WTYPES_HEADER
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(x,y) (((x)<(y))?(x):(y))
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(x,y) (((x)>(y))?(x):(y))
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
//These are used for readability purposes mostly, when a method takes a
|
||||
// pointer or reference these help specify what will happen to the data
|
||||
// that is sent in.
|
||||
#define IN
|
||||
#define OUT
|
||||
#define INOUT
|
||||
|
||||
typedef char bit8;
|
||||
typedef char sint8;
|
||||
typedef unsigned char uint8;
|
||||
typedef signed short int sint16;
|
||||
typedef unsigned short int uint16;
|
||||
typedef signed int sint32;
|
||||
typedef unsigned int uint32;
|
||||
|
||||
#define MAX_BIT8 0x1
|
||||
#define MAX_UINT32 0xFFFFFFFF
|
||||
#define MAX_UINT16 0xFFFF
|
||||
#define MAX_UINT8 0xFF
|
||||
#define MAX_SINT32 0x7FFFFFFF
|
||||
#define MAX_SINT16 0x7FFF
|
||||
#define MAX_SINT8 0x7F
|
||||
|
||||
#ifdef _WIN32
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user