Initial commit of Command & Conquer Red Alert source code.

This commit is contained in:
LFeenanEA
2025-02-27 16:15:05 +00:00
parent b685cea758
commit 5e733d5dcc
2082 changed files with 797727 additions and 0 deletions

213
LAUNCHER/256BMP.C Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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,&regKey);
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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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,
&regKey,
&regPrevious);
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,&regKey);
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
View 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
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

54
LAUNCHER/RESOURCE.H Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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