Initial commit of Command & Conquer Generals and Command & Conquer Generals Zero Hour source code.

This commit is contained in:
LFeenanEA 2025-02-27 17:34:39 +00:00
parent 2e338c00cb
commit 3d0ee53a05
No known key found for this signature in database
GPG key ID: C6EBE8C2EA08F7E0
6072 changed files with 2283311 additions and 0 deletions

View file

@ -0,0 +1,597 @@
/*
** Command & Conquer Generals(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 : Blowfish Component *
* *
* $Archive:: /Sun/Blowfish/bfish.cpp $*
* *
* $Author:: Joe_b $*
* *
* $Modtime:: 12/02/97 9:35p $*
* *
* $Revision:: 6 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* BlowfishEngine::Decrypt -- Decrypts data using blowfish algorithm. *
* BlowfishEngine::Encrypt -- Encrypt an arbitrary block of data. *
* BlowfishEngine::Process_Block -- Process a block of data using Blowfish algorithm. *
* BlowfishEngine::Sub_Key_Encrypt -- Encrypts a block for use in S-Box processing. *
* BlowfishEngine::Submit_Key -- Submit a key that will allow data processing. *
* BlowfishEngine::~BlowfishEngine -- Destructor for the Blowfish engine. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#pragma warning(disable : 4514)
#include "bfish.h"
#include <string.h>
#include <assert.h>
/*
** Byte order controlled long integer. This integer is constructed
** so that character 0 (C0) is the most significant byte of the
** integer. This is biased toward big endian architecture, but that
** just happens to be how the Blowfish algorithm was designed.
*/
typedef union {
unsigned long Long;
struct {
unsigned char C3;
unsigned char C2;
unsigned char C1;
unsigned char C0;
} Char;
} Int;
/***********************************************************************************************
* BlowfishEngine::~BlowfishEngine -- Destructor for the Blowfish engine. *
* *
* This destructor will clear out the s-box tables so that even if the memory for the *
* class remains, it will contain no compromising data. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 07/08/1996 JLB : Created. *
*=============================================================================================*/
BlowfishEngine::~BlowfishEngine(void)
{
if (IsKeyed) {
Submit_Key(NULL, 0);
}
}
/***********************************************************************************************
* BlowfishEngine::Submit_Key -- Submit a key that will allow data processing. *
* *
* This routine must be called before any data can be encrypted or decrypted. This routine *
* need only be called when the key is to be changed or set for the first time. Once the *
* key has been set, the engine may be used to encrypt, decrypt, or both operations *
* indefinitely. The key must be 56 bytes or less in length. This is necessary because *
* any keys longer than that will not correctly affect the encryption process. *
* *
* If the key pointer is NULL, then the S-Box tables are reset to identity. This will *
* mask the previous key setting. Use this method to clear the engine after processing in *
* order to gain a measure of security. *
* *
* INPUT: key -- Pointer to the key data block. *
* *
* length -- The length of the submitted key. *
* *
* OUTPUT: none *
* *
* WARNINGS: This is a time consuming process. *
* *
* HISTORY: *
* 04/14/1996 JLB : Created. *
*=============================================================================================*/
void BlowfishEngine::Submit_Key(void const * key, int length)
{
assert(length <= MAX_KEY_LENGTH);
/*
** Initialize the permutation and S-Box tables to a known
** constant value.
*/
memcpy(P_Encrypt, P_Init, sizeof(P_Init));
memcpy(P_Decrypt, P_Init, sizeof(P_Init));
memcpy(bf_S, S_Init, sizeof(S_Init));
/*
** Validate parameters.
*/
if (key == 0 || length == 0) {
IsKeyed = false;
return;
}
/*
** Combine the key with the permutation table. Wrap the key
** as many times as necessary to ensure that the entire
** permutation table has been modified. The key is lifted
** into a long by using endian independent means.
*/
int j = 0;
unsigned char const * key_ptr = (unsigned char const *)key;
unsigned long * p_ptr = &P_Encrypt[0];
for (int index = 0; index < ROUNDS+2; index++) {
unsigned long data = 0;
data = (data << CHAR_BIT) | key_ptr[j++ % length];
data = (data << CHAR_BIT) | key_ptr[j++ % length];
data = (data << CHAR_BIT) | key_ptr[j++ % length];
data = (data << CHAR_BIT) | key_ptr[j++ % length];
*p_ptr++ ^= data;
}
/*
** The permutation table must be scrambled by means of the key. This
** is how the key is factored into the encryption -- by merely altering
** the permutation (and S-Box) tables. Because this transformation alters
** the table data WHILE it is using the table data, the tables are
** thoroughly obfuscated by this process.
*/
unsigned long left = 0x00000000L;
unsigned long right = 0x00000000L;
unsigned long * p_en = &P_Encrypt[0]; // Encryption table.
unsigned long * p_de = &P_Decrypt[ROUNDS+1]; // Decryption table.
for (int p_index = 0; p_index < ROUNDS+2; p_index += 2) {
Sub_Key_Encrypt(left, right);
*p_en++ = left;
*p_en++ = right;
*p_de-- = left;
*p_de-- = right;
}
/*
** Perform a similar transmutation to the S-Box tables. Also notice that the
** working 64 bit number is carried into this process from the previous
** operation.
*/
for (int sbox_index = 0; sbox_index < 4; sbox_index++) {
for (int ss_index = 0; ss_index < UCHAR_MAX+1; ss_index += 2) {
Sub_Key_Encrypt(left, right);
bf_S[sbox_index][ss_index] = left;
bf_S[sbox_index][ss_index + 1] = right;
}
}
IsKeyed = true;
}
/***********************************************************************************************
* BlowfishEngine::Encrypt -- Encrypt an arbitrary block of data. *
* *
* Use this routine to encrypt an arbitrary block of data. The block must be an even *
* multiple of 8 bytes. Any bytes left over will not be encrypted. The 8 byte requirement *
* is necessary because the underlying algorithm processes blocks in 8 byte chunks. *
* Partial blocks are unrecoverable and useless. *
* *
* INPUT: plaintext-- Pointer to the data block to be encrypted. *
* *
* length -- The length of the data block. *
* *
* cyphertext- Pointer to the output buffer that will hold the encrypted data. *
* *
* OUTPUT: Returns with the actual number of bytes encrypted. *
* *
* WARNINGS: You must submit the key before calling this routine. This will only encrypt *
* the plaintext in 8 byte increments. Modulo bytes left over are not processed. *
* *
* HISTORY: *
* 04/14/1996 JLB : Created. *
*=============================================================================================*/
int BlowfishEngine::Encrypt(void const * plaintext, int length, void * cyphertext)
{
if (plaintext == 0 || length == 0) {
return(0);
}
if (cyphertext == 0) cyphertext = (void *)plaintext;
if (IsKeyed) {
/*
** Validate parameters.
*/
int blocks = length / BYTES_PER_BLOCK;
/*
** Process the buffer in 64 bit chunks.
*/
for (int index = 0; index < blocks; index++) {
Process_Block(plaintext, cyphertext, P_Encrypt);
plaintext = ((char *)plaintext) + BYTES_PER_BLOCK;
cyphertext = ((char *)cyphertext) + BYTES_PER_BLOCK;
}
int encrypted = blocks * BYTES_PER_BLOCK;
/*
** Copy over any trailing left over appendix bytes.
*/
if (encrypted < length) {
memmove(cyphertext, plaintext, length - encrypted);
}
return(encrypted);
}
/*
** Non-keyed processing merely copies the data.
*/
if (plaintext != cyphertext) {
memmove(cyphertext, plaintext, length);
}
return(length);
}
/***********************************************************************************************
* BlowfishEngine::Decrypt -- Decrypt an arbitrary block of data. *
* *
* Use this routine to decrypt an arbitrary block of data. The block must be an even *
* multiple of 8 bytes. Any bytes left over will not be decrypted. The 8 byte requirement *
* is necessary because the underlying algorithm processes blocks in 8 byte chunks. *
* Partial blocks are unrecoverable and useless. *
* *
* INPUT: cyphertext- Pointer to the data block to be decrypted. *
* *
* length -- The length of the data block. *
* *
* plaintext-- Pointer to the output buffer that will hold the decrypted data. *
* *
* OUTPUT: Returns with the actual number of bytes decrypted. *
* *
* WARNINGS: You must submit the key before calling this routine. This will only decrypt *
* the cyphertext in 8 byte increments. Modulo bytes left over are not processed. *
* *
* HISTORY: *
* 04/14/1996 JLB : Created. *
*=============================================================================================*/
int BlowfishEngine::Decrypt(void const * cyphertext, int length, void * plaintext)
{
if (cyphertext == 0 || length == 0) {
return(0);
}
if (plaintext == 0) plaintext = (void *)cyphertext;
if (IsKeyed) {
/*
** Validate parameters.
*/
int blocks = length / BYTES_PER_BLOCK;
/*
** Process the buffer in 64 bit chunks.
*/
for (int index = 0; index < blocks; index++) {
Process_Block(cyphertext, plaintext, P_Decrypt);
cyphertext = ((char *)cyphertext) + BYTES_PER_BLOCK;
plaintext = ((char *)plaintext) + BYTES_PER_BLOCK;
}
int encrypted = blocks * BYTES_PER_BLOCK;
/*
** Copy over any trailing left over appendix bytes.
*/
if (encrypted < length) {
memmove(plaintext, cyphertext, length - encrypted);
}
return(encrypted);
}
/*
** Non-keyed processing merely copies the data.
*/
if (plaintext != cyphertext) {
memmove(plaintext, cyphertext, length);
}
return(length);
}
/***********************************************************************************************
* BlowfishEngine::Process_Block -- Process a block of data using Blowfish algorithm. *
* *
* This is the main processing routine for encryption and decryption. The algorithm *
* consists of a 16 round Feistal network and uses mathematics from different algebraic *
* groups (strengthens against differential cryptanalysis). The large S-Boxes and the *
* rounds strengthen it against linear cryptanalysis. *
* *
* INPUT: plaintext -- Pointer to the source text (it actually might be a pointer to *
* the cyphertext if this is called as a decryption process). *
* *
* cyphertext -- Pointer to the output buffer that will hold the processed block. *
* *
* ptable -- Pointer to the permutation table. This algorithm will encrypt *
* and decrypt using the same S-Box tables. The encryption control *
* is handled by the permutation table. *
* *
* OUTPUT: none *
* *
* WARNINGS: The source and destination buffers must be 8 bytes long. *
* *
* HISTORY: *
* 04/19/1996 JLB : Created. *
*=============================================================================================*/
void BlowfishEngine::Process_Block(void const * plaintext, void * cyphertext, unsigned long const * ptable)
{
/*
** Input the left and right halves of the source block such that
** the byte order is constant regardless of the endian
** persuasion of the current processor. The blowfish algorithm is
** biased toward "big endian" architecture and some optimizations
** could be done for big endian processors in that case.
*/
unsigned char const * source = (unsigned char const *)plaintext;
Int left;
left.Char.C0 = *source++;
left.Char.C1 = *source++;
left.Char.C2 = *source++;
left.Char.C3 = *source++;
Int right;
right.Char.C0 = *source++;
right.Char.C1 = *source++;
right.Char.C2 = *source++;
right.Char.C3 = *source;
/*
** Perform all Feistal rounds on the block. This is the encryption/decryption
** process. Since there is an exchange that occurs after each round, two
** rounds are combined in this loop to avoid unnecessary exchanging.
*/
for (int index = 0; index < ROUNDS/2; index++) {
left.Long ^= *ptable++;
right.Long ^= ((( bf_S[0][left.Char.C0] + bf_S[1][left.Char.C1]) ^ bf_S[2][left.Char.C2]) + bf_S[3][left.Char.C3]);
right.Long ^= *ptable++;
left.Long ^= ((( bf_S[0][right.Char.C0] + bf_S[1][right.Char.C1]) ^ bf_S[2][right.Char.C2]) + bf_S[3][right.Char.C3]);
}
/*
** The final two longs in the permutation table are processed into the block.
** The left and right halves are still reversed as a side effect of the last
** round.
*/
left.Long ^= *ptable++;
right.Long ^= *ptable;
/*
** The final block data is output in endian architecture
** independent format. Notice that the blocks are output as
** right first and left second. This is to counteract the final
** superfluous exchange that occurs as a side effect of the
** encryption rounds.
*/
unsigned char * out = (unsigned char *)cyphertext;
*out++ = right.Char.C0;
*out++ = right.Char.C1;
*out++ = right.Char.C2;
*out++ = right.Char.C3;
*out++ = left.Char.C0;
*out++ = left.Char.C1;
*out++ = left.Char.C2;
*out = left.Char.C3;
}
/***********************************************************************************************
* BlowfishEngine::Sub_Key_Encrypt -- Encrypts a block for use in S-Box processing. *
* *
* This is the same as the normal process block function but it doesn't have the endian *
* fixup logic. Since this routine is only called for S-Box table generation and it is *
* known that the S-Box initial data is already in local machine endian format, the *
* byte order fixups are not needed. This also has a tendency to speed up S-Box generation *
* as well. *
* *
* INPUT: left -- The left half of the data block. *
* *
* right -- The right half of the data block. *
* *
* OUTPUT: none, but the processed block is stored back into the left and right half *
* integers. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 04/19/1996 JLB : Created. *
*=============================================================================================*/
void BlowfishEngine::Sub_Key_Encrypt(unsigned long & left, unsigned long & right)
{
Int l;
l.Long = left;
Int r;
r.Long = right;
for (int index = 0; index < ROUNDS; index += 2) {
l.Long ^= P_Encrypt[index];
r.Long ^= ((( bf_S[0][l.Char.C0] + bf_S[1][l.Char.C1]) ^ bf_S[2][l.Char.C2]) + bf_S[3][l.Char.C3]);
r.Long ^= P_Encrypt[index+1];
l.Long ^= ((( bf_S[0][r.Char.C0] + bf_S[1][r.Char.C1]) ^ bf_S[2][r.Char.C2]) + bf_S[3][r.Char.C3]);
}
left = r.Long ^ P_Encrypt[ROUNDS+1];
right = l.Long ^ P_Encrypt[ROUNDS];
}
/*
** These tables have the bytes stored in machine endian format. Because of this,
** a special block cypher routine is needed when the sub-keys are generated.
** This is kludgier than it otherwise should be. However, storing these
** integers in machine independent format would be even more painful.
*/
unsigned long const BlowfishEngine::P_Init[BlowfishEngine::ROUNDS+2] = {
0x243F6A88U,0x85A308D3U,0x13198A2EU,0x03707344U,0xA4093822U,0x299F31D0U,0x082EFA98U,0xEC4E6C89U,
0x452821E6U,0x38D01377U,0xBE5466CFU,0x34E90C6CU,0xC0AC29B7U,0xC97C50DDU,0x3F84D5B5U,0xB5470917U,
0x9216D5D9U,0x8979FB1BU
};
unsigned long const BlowfishEngine::S_Init[4][UCHAR_MAX+1] = {
{
0xD1310BA6U,0x98DFB5ACU,0x2FFD72DBU,0xD01ADFB7U,0xB8E1AFEDU,0x6A267E96U,0xBA7C9045U,0xF12C7F99U,
0x24A19947U,0xB3916CF7U,0x0801F2E2U,0x858EFC16U,0x636920D8U,0x71574E69U,0xA458FEA3U,0xF4933D7EU,
0x0D95748FU,0x728EB658U,0x718BCD58U,0x82154AEEU,0x7B54A41DU,0xC25A59B5U,0x9C30D539U,0x2AF26013U,
0xC5D1B023U,0x286085F0U,0xCA417918U,0xB8DB38EFU,0x8E79DCB0U,0x603A180EU,0x6C9E0E8BU,0xB01E8A3EU,
0xD71577C1U,0xBD314B27U,0x78AF2FDAU,0x55605C60U,0xE65525F3U,0xAA55AB94U,0x57489862U,0x63E81440U,
0x55CA396AU,0x2AAB10B6U,0xB4CC5C34U,0x1141E8CEU,0xA15486AFU,0x7C72E993U,0xB3EE1411U,0x636FBC2AU,
0x2BA9C55DU,0x741831F6U,0xCE5C3E16U,0x9B87931EU,0xAFD6BA33U,0x6C24CF5CU,0x7A325381U,0x28958677U,
0x3B8F4898U,0x6B4BB9AFU,0xC4BFE81BU,0x66282193U,0x61D809CCU,0xFB21A991U,0x487CAC60U,0x5DEC8032U,
0xEF845D5DU,0xE98575B1U,0xDC262302U,0xEB651B88U,0x23893E81U,0xD396ACC5U,0x0F6D6FF3U,0x83F44239U,
0x2E0B4482U,0xA4842004U,0x69C8F04AU,0x9E1F9B5EU,0x21C66842U,0xF6E96C9AU,0x670C9C61U,0xABD388F0U,
0x6A51A0D2U,0xD8542F68U,0x960FA728U,0xAB5133A3U,0x6EEF0B6CU,0x137A3BE4U,0xBA3BF050U,0x7EFB2A98U,
0xA1F1651DU,0x39AF0176U,0x66CA593EU,0x82430E88U,0x8CEE8619U,0x456F9FB4U,0x7D84A5C3U,0x3B8B5EBEU,
0xE06F75D8U,0x85C12073U,0x401A449FU,0x56C16AA6U,0x4ED3AA62U,0x363F7706U,0x1BFEDF72U,0x429B023DU,
0x37D0D724U,0xD00A1248U,0xDB0FEAD3U,0x49F1C09BU,0x075372C9U,0x80991B7BU,0x25D479D8U,0xF6E8DEF7U,
0xE3FE501AU,0xB6794C3BU,0x976CE0BDU,0x04C006BAU,0xC1A94FB6U,0x409F60C4U,0x5E5C9EC2U,0x196A2463U,
0x68FB6FAFU,0x3E6C53B5U,0x1339B2EBU,0x3B52EC6FU,0x6DFC511FU,0x9B30952CU,0xCC814544U,0xAF5EBD09U,
0xBEE3D004U,0xDE334AFDU,0x660F2807U,0x192E4BB3U,0xC0CBA857U,0x45C8740FU,0xD20B5F39U,0xB9D3FBDBU,
0x5579C0BDU,0x1A60320AU,0xD6A100C6U,0x402C7279U,0x679F25FEU,0xFB1FA3CCU,0x8EA5E9F8U,0xDB3222F8U,
0x3C7516DFU,0xFD616B15U,0x2F501EC8U,0xAD0552ABU,0x323DB5FAU,0xFD238760U,0x53317B48U,0x3E00DF82U,
0x9E5C57BBU,0xCA6F8CA0U,0x1A87562EU,0xDF1769DBU,0xD542A8F6U,0x287EFFC3U,0xAC6732C6U,0x8C4F5573U,
0x695B27B0U,0xBBCA58C8U,0xE1FFA35DU,0xB8F011A0U,0x10FA3D98U,0xFD2183B8U,0x4AFCB56CU,0x2DD1D35BU,
0x9A53E479U,0xB6F84565U,0xD28E49BCU,0x4BFB9790U,0xE1DDF2DAU,0xA4CB7E33U,0x62FB1341U,0xCEE4C6E8U,
0xEF20CADAU,0x36774C01U,0xD07E9EFEU,0x2BF11FB4U,0x95DBDA4DU,0xAE909198U,0xEAAD8E71U,0x6B93D5A0U,
0xD08ED1D0U,0xAFC725E0U,0x8E3C5B2FU,0x8E7594B7U,0x8FF6E2FBU,0xF2122B64U,0x8888B812U,0x900DF01CU,
0x4FAD5EA0U,0x688FC31CU,0xD1CFF191U,0xB3A8C1ADU,0x2F2F2218U,0xBE0E1777U,0xEA752DFEU,0x8B021FA1U,
0xE5A0CC0FU,0xB56F74E8U,0x18ACF3D6U,0xCE89E299U,0xB4A84FE0U,0xFD13E0B7U,0x7CC43B81U,0xD2ADA8D9U,
0x165FA266U,0x80957705U,0x93CC7314U,0x211A1477U,0xE6AD2065U,0x77B5FA86U,0xC75442F5U,0xFB9D35CFU,
0xEBCDAF0CU,0x7B3E89A0U,0xD6411BD3U,0xAE1E7E49U,0x00250E2DU,0x2071B35EU,0x226800BBU,0x57B8E0AFU,
0x2464369BU,0xF009B91EU,0x5563911DU,0x59DFA6AAU,0x78C14389U,0xD95A537FU,0x207D5BA2U,0x02E5B9C5U,
0x83260376U,0x6295CFA9U,0x11C81968U,0x4E734A41U,0xB3472DCAU,0x7B14A94AU,0x1B510052U,0x9A532915U,
0xD60F573FU,0xBC9BC6E4U,0x2B60A476U,0x81E67400U,0x08BA6FB5U,0x571BE91FU,0xF296EC6BU,0x2A0DD915U,
0xB6636521U,0xE7B9F9B6U,0xFF34052EU,0xC5855664U,0x53B02D5DU,0xA99F8FA1U,0x08BA4799U,0x6E85076AU,
},{
0x4B7A70E9U,0xB5B32944U,0xDB75092EU,0xC4192623U,0xAD6EA6B0U,0x49A7DF7DU,0x9CEE60B8U,0x8FEDB266U,
0xECAA8C71U,0x699A17FFU,0x5664526CU,0xC2B19EE1U,0x193602A5U,0x75094C29U,0xA0591340U,0xE4183A3EU,
0x3F54989AU,0x5B429D65U,0x6B8FE4D6U,0x99F73FD6U,0xA1D29C07U,0xEFE830F5U,0x4D2D38E6U,0xF0255DC1U,
0x4CDD2086U,0x8470EB26U,0x6382E9C6U,0x021ECC5EU,0x09686B3FU,0x3EBAEFC9U,0x3C971814U,0x6B6A70A1U,
0x687F3584U,0x52A0E286U,0xB79C5305U,0xAA500737U,0x3E07841CU,0x7FDEAE5CU,0x8E7D44ECU,0x5716F2B8U,
0xB03ADA37U,0xF0500C0DU,0xF01C1F04U,0x0200B3FFU,0xAE0CF51AU,0x3CB574B2U,0x25837A58U,0xDC0921BDU,
0xD19113F9U,0x7CA92FF6U,0x94324773U,0x22F54701U,0x3AE5E581U,0x37C2DADCU,0xC8B57634U,0x9AF3DDA7U,
0xA9446146U,0x0FD0030EU,0xECC8C73EU,0xA4751E41U,0xE238CD99U,0x3BEA0E2FU,0x3280BBA1U,0x183EB331U,
0x4E548B38U,0x4F6DB908U,0x6F420D03U,0xF60A04BFU,0x2CB81290U,0x24977C79U,0x5679B072U,0xBCAF89AFU,
0xDE9A771FU,0xD9930810U,0xB38BAE12U,0xDCCF3F2EU,0x5512721FU,0x2E6B7124U,0x501ADDE6U,0x9F84CD87U,
0x7A584718U,0x7408DA17U,0xBC9F9ABCU,0xE94B7D8CU,0xEC7AEC3AU,0xDB851DFAU,0x63094366U,0xC464C3D2U,
0xEF1C1847U,0x3215D908U,0xDD433B37U,0x24C2BA16U,0x12A14D43U,0x2A65C451U,0x50940002U,0x133AE4DDU,
0x71DFF89EU,0x10314E55U,0x81AC77D6U,0x5F11199BU,0x043556F1U,0xD7A3C76BU,0x3C11183BU,0x5924A509U,
0xF28FE6EDU,0x97F1FBFAU,0x9EBABF2CU,0x1E153C6EU,0x86E34570U,0xEAE96FB1U,0x860E5E0AU,0x5A3E2AB3U,
0x771FE71CU,0x4E3D06FAU,0x2965DCB9U,0x99E71D0FU,0x803E89D6U,0x5266C825U,0x2E4CC978U,0x9C10B36AU,
0xC6150EBAU,0x94E2EA78U,0xA5FC3C53U,0x1E0A2DF4U,0xF2F74EA7U,0x361D2B3DU,0x1939260FU,0x19C27960U,
0x5223A708U,0xF71312B6U,0xEBADFE6EU,0xEAC31F66U,0xE3BC4595U,0xA67BC883U,0xB17F37D1U,0x018CFF28U,
0xC332DDEFU,0xBE6C5AA5U,0x65582185U,0x68AB9802U,0xEECEA50FU,0xDB2F953BU,0x2AEF7DADU,0x5B6E2F84U,
0x1521B628U,0x29076170U,0xECDD4775U,0x619F1510U,0x13CCA830U,0xEB61BD96U,0x0334FE1EU,0xAA0363CFU,
0xB5735C90U,0x4C70A239U,0xD59E9E0BU,0xCBAADE14U,0xEECC86BCU,0x60622CA7U,0x9CAB5CABU,0xB2F3846EU,
0x648B1EAFU,0x19BDF0CAU,0xA02369B9U,0x655ABB50U,0x40685A32U,0x3C2AB4B3U,0x319EE9D5U,0xC021B8F7U,
0x9B540B19U,0x875FA099U,0x95F7997EU,0x623D7DA8U,0xF837889AU,0x97E32D77U,0x11ED935FU,0x16681281U,
0x0E358829U,0xC7E61FD6U,0x96DEDFA1U,0x7858BA99U,0x57F584A5U,0x1B227263U,0x9B83C3FFU,0x1AC24696U,
0xCDB30AEBU,0x532E3054U,0x8FD948E4U,0x6DBC3128U,0x58EBF2EFU,0x34C6FFEAU,0xFE28ED61U,0xEE7C3C73U,
0x5D4A14D9U,0xE864B7E3U,0x42105D14U,0x203E13E0U,0x45EEE2B6U,0xA3AAABEAU,0xDB6C4F15U,0xFACB4FD0U,
0xC742F442U,0xEF6ABBB5U,0x654F3B1DU,0x41CD2105U,0xD81E799EU,0x86854DC7U,0xE44B476AU,0x3D816250U,
0xCF62A1F2U,0x5B8D2646U,0xFC8883A0U,0xC1C7B6A3U,0x7F1524C3U,0x69CB7492U,0x47848A0BU,0x5692B285U,
0x095BBF00U,0xAD19489DU,0x1462B174U,0x23820E00U,0x58428D2AU,0x0C55F5EAU,0x1DADF43EU,0x233F7061U,
0x3372F092U,0x8D937E41U,0xD65FECF1U,0x6C223BDBU,0x7CDE3759U,0xCBEE7460U,0x4085F2A7U,0xCE77326EU,
0xA6078084U,0x19F8509EU,0xE8EFD855U,0x61D99735U,0xA969A7AAU,0xC50C06C2U,0x5A04ABFCU,0x800BCADCU,
0x9E447A2EU,0xC3453484U,0xFDD56705U,0x0E1E9EC9U,0xDB73DBD3U,0x105588CDU,0x675FDA79U,0xE3674340U,
0xC5C43465U,0x713E38D8U,0x3D28F89EU,0xF16DFF20U,0x153E21E7U,0x8FB03D4AU,0xE6E39F2BU,0xDB83ADF7U,
},{
0xE93D5A68U,0x948140F7U,0xF64C261CU,0x94692934U,0x411520F7U,0x7602D4F7U,0xBCF46B2EU,0xD4A20068U,
0xD4082471U,0x3320F46AU,0x43B7D4B7U,0x500061AFU,0x1E39F62EU,0x97244546U,0x14214F74U,0xBF8B8840U,
0x4D95FC1DU,0x96B591AFU,0x70F4DDD3U,0x66A02F45U,0xBFBC09ECU,0x03BD9785U,0x7FAC6DD0U,0x31CB8504U,
0x96EB27B3U,0x55FD3941U,0xDA2547E6U,0xABCA0A9AU,0x28507825U,0x530429F4U,0x0A2C86DAU,0xE9B66DFBU,
0x68DC1462U,0xD7486900U,0x680EC0A4U,0x27A18DEEU,0x4F3FFEA2U,0xE887AD8CU,0xB58CE006U,0x7AF4D6B6U,
0xAACE1E7CU,0xD3375FECU,0xCE78A399U,0x406B2A42U,0x20FE9E35U,0xD9F385B9U,0xEE39D7ABU,0x3B124E8BU,
0x1DC9FAF7U,0x4B6D1856U,0x26A36631U,0xEAE397B2U,0x3A6EFA74U,0xDD5B4332U,0x6841E7F7U,0xCA7820FBU,
0xFB0AF54EU,0xD8FEB397U,0x454056ACU,0xBA489527U,0x55533A3AU,0x20838D87U,0xFE6BA9B7U,0xD096954BU,
0x55A867BCU,0xA1159A58U,0xCCA92963U,0x99E1DB33U,0xA62A4A56U,0x3F3125F9U,0x5EF47E1CU,0x9029317CU,
0xFDF8E802U,0x04272F70U,0x80BB155CU,0x05282CE3U,0x95C11548U,0xE4C66D22U,0x48C1133FU,0xC70F86DCU,
0x07F9C9EEU,0x41041F0FU,0x404779A4U,0x5D886E17U,0x325F51EBU,0xD59BC0D1U,0xF2BCC18FU,0x41113564U,
0x257B7834U,0x602A9C60U,0xDFF8E8A3U,0x1F636C1BU,0x0E12B4C2U,0x02E1329EU,0xAF664FD1U,0xCAD18115U,
0x6B2395E0U,0x333E92E1U,0x3B240B62U,0xEEBEB922U,0x85B2A20EU,0xE6BA0D99U,0xDE720C8CU,0x2DA2F728U,
0xD0127845U,0x95B794FDU,0x647D0862U,0xE7CCF5F0U,0x5449A36FU,0x877D48FAU,0xC39DFD27U,0xF33E8D1EU,
0x0A476341U,0x992EFF74U,0x3A6F6EABU,0xF4F8FD37U,0xA812DC60U,0xA1EBDDF8U,0x991BE14CU,0xDB6E6B0DU,
0xC67B5510U,0x6D672C37U,0x2765D43BU,0xDCD0E804U,0xF1290DC7U,0xCC00FFA3U,0xB5390F92U,0x690FED0BU,
0x667B9FFBU,0xCEDB7D9CU,0xA091CF0BU,0xD9155EA3U,0xBB132F88U,0x515BAD24U,0x7B9479BFU,0x763BD6EBU,
0x37392EB3U,0xCC115979U,0x8026E297U,0xF42E312DU,0x6842ADA7U,0xC66A2B3BU,0x12754CCCU,0x782EF11CU,
0x6A124237U,0xB79251E7U,0x06A1BBE6U,0x4BFB6350U,0x1A6B1018U,0x11CAEDFAU,0x3D25BDD8U,0xE2E1C3C9U,
0x44421659U,0x0A121386U,0xD90CEC6EU,0xD5ABEA2AU,0x64AF674EU,0xDA86A85FU,0xBEBFE988U,0x64E4C3FEU,
0x9DBC8057U,0xF0F7C086U,0x60787BF8U,0x6003604DU,0xD1FD8346U,0xF6381FB0U,0x7745AE04U,0xD736FCCCU,
0x83426B33U,0xF01EAB71U,0xB0804187U,0x3C005E5FU,0x77A057BEU,0xBDE8AE24U,0x55464299U,0xBF582E61U,
0x4E58F48FU,0xF2DDFDA2U,0xF474EF38U,0x8789BDC2U,0x5366F9C3U,0xC8B38E74U,0xB475F255U,0x46FCD9B9U,
0x7AEB2661U,0x8B1DDF84U,0x846A0E79U,0x915F95E2U,0x466E598EU,0x20B45770U,0x8CD55591U,0xC902DE4CU,
0xB90BACE1U,0xBB8205D0U,0x11A86248U,0x7574A99EU,0xB77F19B6U,0xE0A9DC09U,0x662D09A1U,0xC4324633U,
0xE85A1F02U,0x09F0BE8CU,0x4A99A025U,0x1D6EFE10U,0x1AB93D1DU,0x0BA5A4DFU,0xA186F20FU,0x2868F169U,
0xDCB7DA83U,0x573906FEU,0xA1E2CE9BU,0x4FCD7F52U,0x50115E01U,0xA70683FAU,0xA002B5C4U,0x0DE6D027U,
0x9AF88C27U,0x773F8641U,0xC3604C06U,0x61A806B5U,0xF0177A28U,0xC0F586E0U,0x006058AAU,0x30DC7D62U,
0x11E69ED7U,0x2338EA63U,0x53C2DD94U,0xC2C21634U,0xBBCBEE56U,0x90BCB6DEU,0xEBFC7DA1U,0xCE591D76U,
0x6F05E409U,0x4B7C0188U,0x39720A3DU,0x7C927C24U,0x86E3725FU,0x724D9DB9U,0x1AC15BB4U,0xD39EB8FCU,
0xED545578U,0x08FCA5B5U,0xD83D7CD3U,0x4DAD0FC4U,0x1E50EF5EU,0xB161E6F8U,0xA28514D9U,0x6C51133CU,
0x6FD5C7E7U,0x56E14EC4U,0x362ABFCEU,0xDDC6C837U,0xD79A3234U,0x92638212U,0x670EFA8EU,0x406000E0U,
},{
0x3A39CE37U,0xD3FAF5CFU,0xABC27737U,0x5AC52D1BU,0x5CB0679EU,0x4FA33742U,0xD3822740U,0x99BC9BBEU,
0xD5118E9DU,0xBF0F7315U,0xD62D1C7EU,0xC700C47BU,0xB78C1B6BU,0x21A19045U,0xB26EB1BEU,0x6A366EB4U,
0x5748AB2FU,0xBC946E79U,0xC6A376D2U,0x6549C2C8U,0x530FF8EEU,0x468DDE7DU,0xD5730A1DU,0x4CD04DC6U,
0x2939BBDBU,0xA9BA4650U,0xAC9526E8U,0xBE5EE304U,0xA1FAD5F0U,0x6A2D519AU,0x63EF8CE2U,0x9A86EE22U,
0xC089C2B8U,0x43242EF6U,0xA51E03AAU,0x9CF2D0A4U,0x83C061BAU,0x9BE96A4DU,0x8FE51550U,0xBA645BD6U,
0x2826A2F9U,0xA73A3AE1U,0x4BA99586U,0xEF5562E9U,0xC72FEFD3U,0xF752F7DAU,0x3F046F69U,0x77FA0A59U,
0x80E4A915U,0x87B08601U,0x9B09E6ADU,0x3B3EE593U,0xE990FD5AU,0x9E34D797U,0x2CF0B7D9U,0x022B8B51U,
0x96D5AC3AU,0x017DA67DU,0xD1CF3ED6U,0x7C7D2D28U,0x1F9F25CFU,0xADF2B89BU,0x5AD6B472U,0x5A88F54CU,
0xE029AC71U,0xE019A5E6U,0x47B0ACFDU,0xED93FA9BU,0xE8D3C48DU,0x283B57CCU,0xF8D56629U,0x79132E28U,
0x785F0191U,0xED756055U,0xF7960E44U,0xE3D35E8CU,0x15056DD4U,0x88F46DBAU,0x03A16125U,0x0564F0BDU,
0xC3EB9E15U,0x3C9057A2U,0x97271AECU,0xA93A072AU,0x1B3F6D9BU,0x1E6321F5U,0xF59C66FBU,0x26DCF319U,
0x7533D928U,0xB155FDF5U,0x03563482U,0x8ABA3CBBU,0x28517711U,0xC20AD9F8U,0xABCC5167U,0xCCAD925FU,
0x4DE81751U,0x3830DC8EU,0x379D5862U,0x9320F991U,0xEA7A90C2U,0xFB3E7BCEU,0x5121CE64U,0x774FBE32U,
0xA8B6E37EU,0xC3293D46U,0x48DE5369U,0x6413E680U,0xA2AE0810U,0xDD6DB224U,0x69852DFDU,0x09072166U,
0xB39A460AU,0x6445C0DDU,0x586CDECFU,0x1C20C8AEU,0x5BBEF7DDU,0x1B588D40U,0xCCD2017FU,0x6BB4E3BBU,
0xDDA26A7EU,0x3A59FF45U,0x3E350A44U,0xBCB4CDD5U,0x72EACEA8U,0xFA6484BBU,0x8D6612AEU,0xBF3C6F47U,
0xD29BE463U,0x542F5D9EU,0xAEC2771BU,0xF64E6370U,0x740E0D8DU,0xE75B1357U,0xF8721671U,0xAF537D5DU,
0x4040CB08U,0x4EB4E2CCU,0x34D2466AU,0x0115AF84U,0xE1B00428U,0x95983A1DU,0x06B89FB4U,0xCE6EA048U,
0x6F3F3B82U,0x3520AB82U,0x011A1D4BU,0x277227F8U,0x611560B1U,0xE7933FDCU,0xBB3A792BU,0x344525BDU,
0xA08839E1U,0x51CE794BU,0x2F32C9B7U,0xA01FBAC9U,0xE01CC87EU,0xBCC7D1F6U,0xCF0111C3U,0xA1E8AAC7U,
0x1A908749U,0xD44FBD9AU,0xD0DADECBU,0xD50ADA38U,0x0339C32AU,0xC6913667U,0x8DF9317CU,0xE0B12B4FU,
0xF79E59B7U,0x43F5BB3AU,0xF2D519FFU,0x27D9459CU,0xBF97222CU,0x15E6FC2AU,0x0F91FC71U,0x9B941525U,
0xFAE59361U,0xCEB69CEBU,0xC2A86459U,0x12BAA8D1U,0xB6C1075EU,0xE3056A0CU,0x10D25065U,0xCB03A442U,
0xE0EC6E0EU,0x1698DB3BU,0x4C98A0BEU,0x3278E964U,0x9F1F9532U,0xE0D392DFU,0xD3A0342BU,0x8971F21EU,
0x1B0A7441U,0x4BA3348CU,0xC5BE7120U,0xC37632D8U,0xDF359F8DU,0x9B992F2EU,0xE60B6F47U,0x0FE3F11DU,
0xE54CDA54U,0x1EDAD891U,0xCE6279CFU,0xCD3E7E6FU,0x1618B166U,0xFD2C1D05U,0x848FD2C5U,0xF6FB2299U,
0xF523F357U,0xA6327623U,0x93A83531U,0x56CCCD02U,0xACF08162U,0x5A75EBB5U,0x6E163697U,0x88D273CCU,
0xDE966292U,0x81B949D0U,0x4C50901BU,0x71C65614U,0xE6C6C7BDU,0x327A140AU,0x45E1D006U,0xC3F27B9AU,
0xC9AA53FDU,0x62A80F00U,0xBB25BFE2U,0x35BDD2F6U,0x71126905U,0xB2040222U,0xB6CBCF7CU,0xCD769C2BU,
0x53113EC0U,0x1640E3D3U,0x38ABBD60U,0x2547ADF0U,0xBA38209CU,0xF746CE76U,0x77AFA1C5U,0x20756060U,
0x85CBFE4EU,0x8AE88DD8U,0x7AAAF9B0U,0x4CF9AA7EU,0x1948C25CU,0x02FB8A8CU,0x01C36AE4U,0xD6EBE1F9U,
0x90D4F869U,0xA65CDEA0U,0x3F09252DU,0xC208E69FU,0xB74E6132U,0xCE77E25BU,0x578FDFE3U,0x3AC372E6U
}
};

View file

@ -0,0 +1,105 @@
/*
** Command & Conquer Generals(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 : Blowfish Component *
* *
* $Archive:: /Sun/Blowfish/bfish.h $*
* *
* $Author:: Joe_b $*
* *
* $Modtime:: 12/02/97 9:35p $*
* *
* $Revision:: 6 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef BFISH_H
#define BFISH_H
#include <limits.h>
/*
** This engine will process data blocks by encryption and decryption.
** The "Blowfish" algorithm is in the public domain. It uses
** a Feistal network (similar to IDEA). It has no known
** weaknesses, but is still relatively new. Blowfish is particularly strong
** against brute force attacks. It is also quite strong against linear and
** differential cryptanalysis. Unlike public key encription, it is very
** fast at encryption, as far as cryptography goes. Its weakness is that
** it takes a relatively long time to set up with a new key (1/100th of
** a second on a P6-200). The time to set up a key is equivalent to
** encrypting 4240 bytes.
*/
class BlowfishEngine {
public:
BlowfishEngine(void) : IsKeyed(false) {}
~BlowfishEngine(void);
void Submit_Key(void const * key, int length);
int Encrypt(void const * plaintext, int length, void * cyphertext);
int Decrypt(void const * cyphertext, int length, void * plaintext);
/*
** This is the maximum key length supported.
*/
enum {MAX_KEY_LENGTH=56,
BYTES_PER_BLOCK=8 // The number of bytes in each cypher block (don't change).
};
private:
bool IsKeyed;
void Sub_Key_Encrypt(unsigned long & left, unsigned long & right);
void Process_Block(void const * plaintext, void * cyphertext, unsigned long const * ptable);
void Initialize_Tables(void);
enum {
ROUNDS = 16 // Feistal round count (16 is standard).
};
/*
** Initialization data for sub keys. The initial values are constant and
** filled with a number generated from pi. Thus they are not random but
** they don't hold a weak pattern either.
*/
static unsigned long const P_Init[ROUNDS+2];
static unsigned long const S_Init[4][UCHAR_MAX+1];
/*
** Permutation tables for encryption and decryption.
*/
unsigned long P_Encrypt[ROUNDS+2];
unsigned long P_Decrypt[ROUNDS+2];
/*
** S-Box tables (four).
*/
unsigned long bf_S[4][UCHAR_MAX+1];
};
#endif

View file

@ -0,0 +1,193 @@
/*
** Command & Conquer Generals(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/>.
*/
// DatGen.cpp : Defines the entry point for the application.
//
#include <windows.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include "bfish.h"
#include "SafeDisk\CdaPfn.h"
#include <Debug\DebugPrint.h>
void __cdecl doIt(void);
CDAPFN_DECLARE_GLOBAL(doIt, CDAPFN_OVERHEAD_L5, CDAPFN_CONSTRAINT_NONE);
static void doIt(void)
{
// Generate passkey
char passKey[128];
passKey[0] = '\0';
unsigned char installPath[MAX_PATH] = "";
// Get game information
HKEY hKey;
bool usesHKeycurrentUser = false;
LONG result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Electronic Arts\\EA Games\\Generals", 0, KEY_READ, &hKey);
if (result != ERROR_SUCCESS)
{
result = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Electronic Arts\\EA Games\\Generals", 0, KEY_READ, &hKey);
usesHKeycurrentUser = true;
}
assert((result == ERROR_SUCCESS) && "Failed to open game registry key");
if (result != ERROR_SUCCESS)
{
return;
}
// Retrieve install path
DWORD type;
DWORD sizeOfBuffer = sizeof(installPath);
result = RegQueryValueEx(hKey, "InstallPath", NULL, &type, installPath, &sizeOfBuffer);
assert((result == ERROR_SUCCESS) && "Failed to obtain game install path!");
assert((strlen((const char*)installPath) > 0) && "Game install path invalid!");
DebugPrint("Game install path: %s\n", installPath);
// Retrieve Hard drive S/N
char drive[8];
_splitpath((const char*)installPath, drive, NULL, NULL, NULL);
strcat(drive, "\\");
DWORD volumeSerialNumber = 0;
DWORD maxComponentLength;
DWORD fileSystemFlags;
BOOL volInfoSuccess = GetVolumeInformation((const char*)drive, NULL, 0,
&volumeSerialNumber, &maxComponentLength, &fileSystemFlags, NULL, 0);
if (volInfoSuccess == FALSE)
{
PrintWin32Error("***** GetVolumeInformation() Failed!");
}
DebugPrint("Drive Serial Number: %lx\n", volumeSerialNumber);
// Add hard drive serial number portion
char volumeSN[16];
sprintf(volumeSN, "%lx-", volumeSerialNumber);
strcat(passKey, volumeSN);
// Retrieve game serial #
unsigned char gameSerialNumber[64];
gameSerialNumber[0] = '\0';
sizeOfBuffer = sizeof(gameSerialNumber);
if (usesHKeycurrentUser)
{
result = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Electronic Arts\\EA Games\\Generals\\ergc", 0, KEY_READ, &hKey);
}
else
{
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Electronic Arts\\EA Games\\Generals\\ergc", 0, KEY_READ, &hKey);
}
assert((result == ERROR_SUCCESS) && "Failed to open game serial registry key");
if (result == ERROR_SUCCESS)
{
result = RegQueryValueEx(hKey, "", NULL, &type, gameSerialNumber, &sizeOfBuffer);
assert((result == ERROR_SUCCESS) && "Failed to obtain game serial number!");
assert((strlen((const char*)gameSerialNumber) > 0) && "Game serial number invalid!");
}
DebugPrint("Game serial number: %s\n", gameSerialNumber);
RegCloseKey(hKey);
// Add game serial number portion
strcat(passKey, (char*)gameSerialNumber);
// Obtain windows product ID
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", 0, KEY_READ, &hKey);
assert((result == ERROR_SUCCESS) && "Failed to open windows registry key!");
if (result == ERROR_SUCCESS)
{
// Retrieve Windows Product ID
unsigned char winProductID[64];
winProductID[0] = '\0';
DWORD type;
DWORD sizeOfBuffer = sizeof(winProductID);
result = RegQueryValueEx(hKey, "ProductID", NULL, &type, winProductID, &sizeOfBuffer);
assert((result == ERROR_SUCCESS) && "Failed to obtain windows product ID!");
assert((strlen((const char*)winProductID) > 0) && "Invalid windows product ID");
DebugPrint("Windows Product ID: %s\n", winProductID);
RegCloseKey(hKey);
// Add windows product ID portion
strcat(passKey, "-");
strcat(passKey, (char*)winProductID);
}
DebugPrint("Retrieved PassKey: %s\n", passKey);
const char *plainText = "Play the \"Command & Conquer: Generals\" Multiplayer Test.";
int textLen = strlen(plainText);
char cypherText[128];
DebugPrint("Retrieved PassKey: %s\n", passKey);
// Decrypt protected data into the memory mapped file
BlowfishEngine blowfish;
int len = strlen(passKey);
if (len > BlowfishEngine::MAX_KEY_LENGTH)
len = BlowfishEngine::MAX_KEY_LENGTH;
blowfish.Submit_Key(passKey, len);
blowfish.Encrypt(plainText, textLen, cypherText);
cypherText[textLen] = 0;
DebugPrint("Encrypted data: %s\n", cypherText);
DebugPrint("Install dir = '%s'\n", installPath);
char *lastBackslash = strrchr((char *)installPath, '\\');
if (lastBackslash)
*lastBackslash = 0; // strip of \\game.exe from install path
strcat((char *)installPath, "\\Generals.dat");
DebugPrint("DAT file = '%s'\n", installPath);
FILE *fp = fopen((char *)installPath, "wb");
if (fp)
{
fwrite(cypherText, textLen, 1, fp);
fclose(fp);
}
CDAPFN_ENDMARK(doIt);
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
doIt();
return 0;
}

View file

@ -0,0 +1,131 @@
# Microsoft Developer Studio Project File - Name="DatGen" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Application" 0x0101
CFG=DatGen - 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 "DatGen.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 "DatGen.mak" CFG="DatGen - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "DatGen - Win32 Release" (based on "Win32 (x86) Application")
!MESSAGE "DatGen - Win32 Debug" (based on "Win32 (x86) Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName "DatGen"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "DatGen - 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" /D "_MBCS" /Yu"stdafx.h" /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I ".." /I "../toolkit" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
# SUBTRACT CPP /YX /Yc /Yu
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /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 /nologo /subsystem:windows /pdb:"../../../../Run/DatGen.pdb" /map:"../../../../Run/DatGen.map" /debug /machine:I386 /out:"../../../../Run/DatGen.exe"
# SUBTRACT LINK32
!ELSEIF "$(CFG)" == "DatGen - 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" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I ".." /I "../toolkit" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
# SUBTRACT CPP /YX /Yc /Yu
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /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
# 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 /nologo /subsystem:windows /pdb:"../../../../Run/DatGenD.pdb" /map:"../../../../Run/DatGenD.map" /debug /machine:I386 /out:"../../../../Run/DatGenD.exe"
# SUBTRACT LINK32
!ENDIF
# Begin Target
# Name "DatGen - Win32 Release"
# Name "DatGen - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=..\BFISH.CPP
# End Source File
# Begin Source File
SOURCE=.\DatGen.cpp
# End Source File
# Begin Source File
SOURCE=..\Toolkit\Debug\DebugPrint.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=..\BFISH.H
# End Source File
# Begin Source File
SOURCE=..\SafeDisk\CdaPfn.h
# End Source File
# Begin Source File
SOURCE=..\Toolkit\Debug\DebugPrint.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View file

@ -0,0 +1,336 @@
/*
** Command & Conquer Generals(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/>.
*/
/******************************************************************************
*
* FILE
* $Archive: /APILauncher/Protect.cpp $
*
* DESCRIPTION
*
* PROGRAMMER
* Denzil E. Long, Jr.
* $Author: Mcampbell $
*
* VERSION INFO
* $Modtime: 6/21/01 5:09p $
* $Revision: 6 $
*
******************************************************************************/
#include "Protect.h"
#ifdef COPY_PROTECT
#include "BFish.h"
#include <Support\UString.h>
#include <Support\RefPtr.h>
#include <Storage\File.h>
#include <windows.h>
#include <memory>
#include <assert.h>
#include <stdio.h>
#include <Debug\DebugPrint.h>
#include "SafeDisk\CdaPfn.h"
// This GUID should be unique for each product. (CHANGE IT WHEN DOING THE
// NEXT PRODUCT) Note that the game will need to agree on this GUID also, so
// the game will have to be modified also.
const char* const LAUNCHER_GUID =
"150C6462-4E49-4ccf-B073-57579569D994"; // Generals Multiplayer Test Launcher GUID
const char* const protectGUID =
"6096561D-8A70-48ed-9FF8-18552419E50D"; // Generals Multiplayer Test Protect GUID
/*
const char* const LAUNCHER_GUID =
"FB327081-64F2-43d8-9B72-503C3B765134"; // Generals Launcher GUID
const char* const protectGUID =
"7BEB9006-CC19-4aca-913A-C870A88DE01A"; // Generals Protect GUID
*/
HANDLE mLauncherMutex = NULL;
HANDLE mMappedFile = NULL;
void InitializeProtect(void)
{
ShutdownProtect();
DebugPrint("Initializing protection\n");
mLauncherMutex = NULL;
mMappedFile = NULL;
// Secure launcher mutex
mLauncherMutex = CreateMutex(NULL, FALSE, LAUNCHER_GUID);
if ((mLauncherMutex == NULL) || (mLauncherMutex && (GetLastError() == ERROR_ALREADY_EXISTS)))
{
DebugPrint("***** Failed to create launcher mutex\n");
return;
}
// Create memory mapped file to mirror protected file
File file("Generals.dat", Rights_ReadOnly);
if (!file.IsAvailable())
{
DebugPrint("***** Unable to find Generals.dat\n");
return;
}
UInt32 fileSize = file.GetLength();
SECURITY_ATTRIBUTES security;
security.nLength = sizeof(security);
security.lpSecurityDescriptor = NULL;
security.bInheritHandle = TRUE;
mMappedFile = CreateFileMapping(INVALID_HANDLE_VALUE, &security, PAGE_READWRITE, 0, fileSize, NULL);
if ((mMappedFile == NULL) || (mMappedFile && (GetLastError() == ERROR_ALREADY_EXISTS)))
{
PrintWin32Error("***** CreateFileMapping() Failed!");
CloseHandle(mMappedFile);
mMappedFile = NULL;
return;
}
}
CDAPFN_DECLARE_GLOBAL(SendProtectMessage, CDAPFN_OVERHEAD_L5, CDAPFN_CONSTRAINT_NONE);
void SendProtectMessage(HANDLE process, DWORD threadID)
{
// Decrypt protected file contents to mapping file
File file("Generals.dat", Rights_ReadOnly);
if (!file.IsAvailable())
{
DebugPrint("***** Unable to find Generals.dat\n");
return;
}
// Map file to programs address space
LPVOID mapAddress = MapViewOfFileEx(mMappedFile, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
if (mapAddress == NULL)
{
PrintWin32Error("***** MapViewOfFileEx() Failed!");
return;
}
void* buffer = NULL;
UInt32 bufferSize = 0;
file.Load(buffer, bufferSize);
if (buffer && (bufferSize > 0))
{
DebugPrint("Generating PassKey\n");
// Generate passkey
char passKey[128];
passKey[0] = '\0';
// Get game information
HKEY hKey;
bool usesHKeycurrentUser = false;
LONG result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Electronic Arts\\EA Games\\Generals", 0, KEY_READ, &hKey);
if (result != ERROR_SUCCESS)
{
result = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Electronic Arts\\EA Games\\Generals", 0, KEY_READ, &hKey);
usesHKeycurrentUser = true;
}
assert((result == ERROR_SUCCESS) && "Failed to open game registry key");
if (result == ERROR_SUCCESS)
{
// Retrieve install path
unsigned char installPath[MAX_PATH];
DWORD type;
DWORD sizeOfBuffer = sizeof(installPath);
result = RegQueryValueEx(hKey, "InstallPath", NULL, &type, installPath, &sizeOfBuffer);
assert((result == ERROR_SUCCESS) && "Failed to obtain game install path!");
assert((strlen((const char*)installPath) > 0) && "Game install path invalid!");
DebugPrint("Game install path: %s\n", installPath);
// Retrieve Hard drive S/N
char drive[8];
_splitpath((const char*)installPath, drive, NULL, NULL, NULL);
strcat(drive, "\\");
DWORD volumeSerialNumber = 0;
DWORD maxComponentLength;
DWORD fileSystemFlags;
BOOL volInfoSuccess = GetVolumeInformation((const char*)drive, NULL, 0,
&volumeSerialNumber, &maxComponentLength, &fileSystemFlags, NULL, 0);
if (volInfoSuccess == FALSE)
{
PrintWin32Error("***** GetVolumeInformation() Failed!");
}
DebugPrint("Drive Serial Number: %lx\n", volumeSerialNumber);
// Add hard drive serial number portion
char volumeSN[16];
sprintf(volumeSN, "%lx-", volumeSerialNumber);
strcat(passKey, volumeSN);
// Retrieve game serial #
unsigned char gameSerialNumber[64];
gameSerialNumber[0] = '\0';
sizeOfBuffer = sizeof(gameSerialNumber);
if (usesHKeycurrentUser)
{
result = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Electronic Arts\\EA Games\\Generals\\ergc", 0, KEY_READ, &hKey);
}
else
{
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Electronic Arts\\EA Games\\Generals\\ergc", 0, KEY_READ, &hKey);
}
assert((result == ERROR_SUCCESS) && "Failed to open game serial registry key");
if (result == ERROR_SUCCESS)
{
result = RegQueryValueEx(hKey, "", NULL, &type, gameSerialNumber, &sizeOfBuffer);
assert((result == ERROR_SUCCESS) && "Failed to obtain game serial number!");
assert((strlen((const char*)gameSerialNumber) > 0) && "Game serial number invalid!");
}
DebugPrint("Game serial number: %s\n", gameSerialNumber);
RegCloseKey(hKey);
// Add game serial number portion
strcat(passKey, (char*)gameSerialNumber);
}
// Obtain windows product ID
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", 0, KEY_READ, &hKey);
assert((result == ERROR_SUCCESS) && "Failed to open windows registry key!");
if (result == ERROR_SUCCESS)
{
// Retrieve Windows Product ID
unsigned char winProductID[64];
winProductID[0] = '\0';
DWORD type;
DWORD sizeOfBuffer = sizeof(winProductID);
result = RegQueryValueEx(hKey, "ProductID", NULL, &type, winProductID, &sizeOfBuffer);
assert((result == ERROR_SUCCESS) && "Failed to obtain windows product ID!");
assert((strlen((const char*)winProductID) > 0) && "Invalid windows product ID");
DebugPrint("Windows Product ID: %s\n", winProductID);
RegCloseKey(hKey);
// Add windows product ID portion
strcat(passKey, "-");
strcat(passKey, (char*)winProductID);
}
DebugPrint("Retrieved PassKey: %s\n", passKey);
// Decrypt protected data into the memory mapped file
BlowfishEngine blowfish;
int len = strlen(passKey);
if (len > BlowfishEngine::MAX_KEY_LENGTH)
len = BlowfishEngine::MAX_KEY_LENGTH;
blowfish.Submit_Key(passKey, len);
blowfish.Decrypt(buffer, bufferSize, mapAddress);
DebugPrint("Decrypted data: %s\n", mapAddress);
free(buffer);
}
UnmapViewOfFile(mapAddress);
//---------------------------------------------------------------------------
// Send protection message
//---------------------------------------------------------------------------
DebugPrint("Sending protect message\n");
DebugPrint("Creating running notification event.\n");
HANDLE event = CreateEvent(NULL, FALSE, FALSE, protectGUID);
if ((event == NULL) || (event && (GetLastError() == ERROR_ALREADY_EXISTS)))
{
PrintWin32Error("***** CreateEvent() Failed!");
return;
}
DebugPrint("Waiting for game (timeout in %.02f seconds)...\n", ((float)((5 * 60) * 1000) * 0.001));
#ifdef _DEBUG
unsigned long start = timeGetTime();
#endif
HANDLE handles[2];
handles[0] = event;
handles[1] = process;
DWORD waitResult = WaitForMultipleObjects(2, &handles[0], FALSE, ((5 * 60) * 1000));
#ifdef _DEBUG
unsigned long stop = timeGetTime();
#endif
DebugPrint("WaitResult = %ld (WAIT_OBJECT_0 = %ld)\n", waitResult, WAIT_OBJECT_0);
if (waitResult == WAIT_OBJECT_0)
{
if (mMappedFile != NULL)
{
DebugPrint("Sending game the beef. (%lx)\n", mMappedFile);
BOOL sent = PostThreadMessage(threadID, 0xBEEF, 0, (LPARAM)mMappedFile);
assert(sent == TRUE);
}
}
else
{
DebugPrint("***** Timeout!\n");
}
#ifdef _DEBUG
DebugPrint("Waited %.02f seconds\n", ((float)(stop - start) * 0.001));
#endif
CloseHandle(event);
CDAPFN_ENDMARK(SendProtectMessage);
}
void ShutdownProtect(void)
{
if (mMappedFile)
{
CloseHandle(mMappedFile);
mMappedFile = NULL;
}
if (mLauncherMutex)
{
CloseHandle(mLauncherMutex);
mLauncherMutex = NULL;
}
}
#endif // COPY_PROTECT

View file

@ -0,0 +1,89 @@
/*
** Command & Conquer Generals(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/>.
*/
/******************************************************************************
*
* FILE
* $Archive: /APILauncher/Protect.h $
*
* DESCRIPTION
* Copy protection
*
* PROGRAMMER
* Denzil E. Long, Jr.
* $Author: Mcampbell $
*
* VERSION INFO
* $Modtime: 6/18/01 8:24p $
* $Revision: 4 $
*
******************************************************************************/
#ifndef __PROTECT_H__
#define __PROTECT_H__
#ifdef COPY_PROTECT
#include <windows.h>
//#define OLDWAY
#ifdef OLDWAY
template<typename T> class RefPtr;
class UString;
class Protect
{
public:
Protect();
~Protect();
void SendMappedFileHandle(HANDLE process, DWORD threadID) const;
private:
// Prevent copy & assignment
Protect(const Protect&);
const Protect& operator=(const Protect&);
// Retrieve machine unique key
RefPtr<UString> GetPassKey(void) const;
HANDLE mLauncherMutex;
HANDLE mMappedFile;
};
#else
#ifdef __cplusplus
extern "C" {
#endif
void __cdecl InitializeProtect(void);
void __cdecl ShutdownProtect(void);
void __cdecl SendProtectMessage(HANDLE process, DWORD threadID);
#ifdef __cplusplus
};
#endif
#endif
#endif // COPY_PROTECT
#endif // PROTECT_H

View file

@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

View file

@ -0,0 +1,185 @@
/*
** Command & Conquer Generals(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/>.
*/
/******************************************************************************
*
* FILE
* $Archive: $
*
* DESCRIPTION
* Debug printing mechanism
*
* PROGRAMMER
* Denzil E. Long, Jr.
* $Author: $
*
* VERSION INFO
* $Modtime: $
* $Revision: $
*
******************************************************************************/
#ifdef _DEBUG
#include "DebugPrint.h"
#include <windows.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
char debugLogName[_MAX_PATH];
/******************************************************************************
*
* NAME
* DebugPrint(String, ArgList...)
*
* DESCRIPTION
* Ouput debug print messages to the debugger and log file.
*
* INPUTS
* String - String to output.
* ArgList - Argument list
*
* RESULT
* NONE
*
******************************************************************************/
void __cdecl DebugPrint(const char* string, ...)
{
static char _buffer[1024];
static char _filename[512] = "";
if (string != NULL)
{
// Format string
va_list va;
va_start(va, string);
vsprintf(&_buffer[0], string, va);
va_end(va);
// Open log file
HANDLE file = INVALID_HANDLE_VALUE;
if (strlen(_filename) == 0)
{
char path[_MAX_PATH];
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
GetModuleFileName(GetModuleHandle(NULL), &path[0], sizeof(path));
_splitpath(path, drive, dir, NULL, NULL);
_makepath(_filename, drive, dir, debugLogName, "txt");
OutputDebugString("Creating ");
OutputDebugString(_filename);
OutputDebugString("\n");
file = CreateFile(_filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
}
else
{
file = CreateFile(_filename, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
}
// Send string to debugger
OutputDebugString(_buffer);
// Insert carriage return after newlines
int i = 0;
while (_buffer[i] != '\0')
{
if (_buffer[i] == '\n')
{
int end = strlen(_buffer);
assert((end + 1) <= sizeof(_buffer));
while (end >= i)
{
_buffer[end + 1] = _buffer[end];
end--;
}
_buffer[i] = '\r';
i++;
}
i++;
}
// Send string to log file
assert(file != INVALID_HANDLE_VALUE);
if (file != INVALID_HANDLE_VALUE)
{
SetFilePointer(file, 0, NULL, FILE_END);
DWORD written;
WriteFile(file, &_buffer[0], strlen(_buffer), &written, NULL);
CloseHandle(file);
}
}
}
/******************************************************************************
*
* NAME
* PrintWin32Error
*
* DESCRIPTION
* Display Win32 error message (Error retrieved from GetLastError())
*
* INPUTS
* Message string
*
* RESULT
* NONE
*
******************************************************************************/
void __cdecl PrintWin32Error(const char* string, ...)
{
static char _buffer[1024];
if (string != NULL)
{
// Format string
va_list va;
va_start(va, string);
vsprintf(&_buffer[0], string, va);
va_end(va);
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL);
DebugPrint("***** Win32 Error: %s\n", _buffer);
DebugPrint(" Reason: %s\n", (char*)lpMsgBuf);
LocalFree(lpMsgBuf);
}
}
#endif // _DEBUG

View file

@ -0,0 +1,65 @@
/*
** Command & Conquer Generals(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/>.
*/
/******************************************************************************
*
* FILE
* $Archive: $
*
* DESCRIPTION
* Debug printing mechanism
*
* PROGRAMMER
* Denzil E. Long, Jr.
* $Author: $
*
* VERSION INFO
* $Modtime: $
* $Revision: $
*
******************************************************************************/
#ifndef _DEBUGPRINT_H_
#define _DEBUGPRINT_H_
#ifdef _DEBUG
#ifdef __cplusplus
extern "C"
{
#endif
//! Ouput debug print messages to the debugger and log file.
void __cdecl DebugPrint(const char* string, ...);
void __cdecl PrintWin32Error(const char* string, ...);
extern char debugLogName[];
#ifdef __cplusplus
}
#endif
#else // _DEBUG
#define DebugPrint
#define PrintWin32Error
#endif // _DEBUG
#endif // _DEBUGPRINT_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,153 @@
/*
** Command & Conquer Generals(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/>.
*/
/****************************************************************************
*
* FILE
* $Archive: $
*
* DESCRIPTION
* File definitions (Windows)
*
* PROGRAMMER
* Denzil E. Long, Jr.
* $Author: $
*
* VERSION INFO
* $Modtime: $
* $Revision: $
*
****************************************************************************/
#ifndef FILE_H
#define FILE_H
#include <Support\UTypes.h>
#include "Stream.h"
#include "Rights.h"
#include <Support\UString.h>
#include <windows.h>
class File : public Stream
{
public:
// File Error conditions
typedef enum
{
FileError_None = 0,
FileError_FNF,
FileError_Access,
FileError_Open,
FileError_Read,
FileError_Write,
FileError_Seek,
FileError_Nomem,
FileError_Fault,
} EFileError;
//! Default constructor - Create an unassociated File
File();
//! Name constructor - Create a File with an associated name
File(const Char* name, ERights rights = Rights_ReadOnly);
File(const UString& name, ERights rights = Rights_ReadOnly);
//! Destructor
virtual ~File();
//! Retrieve name of file
const UString& GetName(void) const;
//! Associate a name to the file
virtual void SetName(const UString& name);
//! Retrieve file access rights
virtual ERights GetRights(void) const;
//! Set file access rights
virtual void SetRights(ERights rights);
//! Check if the file is available
virtual bool IsAvailable(bool force = false);
//! Check if te file is open
virtual bool IsOpen(void) const;
//! Open the file for access.
virtual EFileError Open(ERights rights);
//! Open the file with the associated name for access
virtual EFileError Open(const UString& name, ERights rights);
//! Close the file
virtual void Close(void);
//! Create a new file
virtual EFileError Create(void);
//! Delete an existing file
virtual EFileError Delete(void);
//! Load the file into memory
virtual EFileError Load(void*& outBuffer, UInt32& outSize);
//! Write file data
virtual EFileError Save(const void* buffer, UInt32 size);
//! Error handling hook
virtual bool OnFileError(EFileError error, bool canRetry);
//-----------------------------------------------------------------------
// STREAM INTERFACE
//-----------------------------------------------------------------------
//! Get the length of the file
virtual UInt32 GetLength(void);
//! Set the length of the file
virtual void SetLength(UInt32 length);
//! Get file position marker
virtual UInt32 GetMarker(void);
//! Set file position marker
virtual void SetMarker(Int32 offset, EStreamFrom from);
//! End of file test
virtual bool AtEnd(void);
//! Read bytes from the file
virtual UInt32 GetBytes(void* ptr, UInt32 bytes);
//! Write bytes to the file
virtual UInt32 PutBytes(const void* ptr, UInt32 bytes);
//! Read bytes from the file without marker adjustment
virtual UInt32 PeekBytes(void* ptr, UInt32 bytes);
//! Flush the stream
virtual void Flush(void);
private:
UString mName;
ERights mRights;
HANDLE mHandle;
static const HANDLE INVALID_HANDLE;
};
#endif // FILE_H

View file

@ -0,0 +1,48 @@
/*
** Command & Conquer Generals(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/>.
*/
/****************************************************************************
*
* FILE
* $Archive: $
*
* DESCRIPTION
* Access privilege definitions.
*
* PROGRAMMER
* Denzil E. Long, Jr.
* $Author: $
*
* VERSION INFO
* $Modtime: $
* $Revision: $
*
****************************************************************************/
#ifndef RIGHTS_H
#define RIGHTS_H
// Access rights
typedef enum
{
Rights_ReadOnly = 0,
Rights_WriteOnly,
Rights_ReadWrite,
} ERights;
#endif // RIGHTS_H

View file

@ -0,0 +1,81 @@
/*
** Command & Conquer Generals(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/>.
*/
/****************************************************************************
*
* FILE
* $Archive: $
*
* DESCRIPTION
* Base class for data streaming functionality
*
* PROGRAMMER
* Denzil E. Long, Jr.
* $Author: $
*
* VERSION INFO
* $Modtime: $
* $Revision: $
*
****************************************************************************/
#ifndef STREAM_H
#define STREAM_H
#include <Support\UTypes.h>
class Stream
{
public:
// Stream marker positioning
typedef enum
{
FromStart = 0,
FromMarker,
FromEnd,
} EStreamFrom;
//! Get the length of the stream
virtual UInt32 GetLength(void) = 0;
//! Set the length of the stream
virtual void SetLength(UInt32 length) = 0;
//! Get current position of stream marker
virtual UInt32 GetMarker(void) = 0;
//! Set position of stream marker
virtual void SetMarker(Int32 offset, EStreamFrom from) = 0;
//! End of stream test
virtual bool AtEnd(void) = 0;
//! Retrieve a sequence of bytes.
virtual UInt32 GetBytes(void* ptr, UInt32 bytes) = 0;
//! Write a sequence of bytes
virtual UInt32 PutBytes(const void* ptr, UInt32 bytes) = 0;
//! Retrieve a sequence of bytes without advancing marker.
virtual UInt32 PeekBytes(void* ptr, UInt32 bytes) = 0;
//! Flush the stream
virtual void Flush(void) = 0;
};
#endif // STREAM_H

View file

@ -0,0 +1,86 @@
/*
** Command & Conquer Generals(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/>.
*/
/******************************************************************************
*
* FILE
* $Archive: $
*
* DESCRIPTION
* Base class for reference counted classes.
* Use with the reference counting smart pointer RefPtr<Type>
*
* Release() is virtual. This helps support cached object and singletons
*
* PROGRAMMER
* Steven Clinard
* $Author: $
*
* VERSION INFO
* $Modtime: $
* $Revision: $
*
******************************************************************************/
#ifndef REFCOUNTED_H
#define REFCOUNTED_H
#include <assert.h>
class RefCounted
{
protected:
RefCounted()
: mRefCount(0)
{}
RefCounted(const RefCounted&)
: mRefCount(0)
{}
inline const RefCounted& operator=(const RefCounted&)
{}
virtual ~RefCounted()
{assert(mRefCount == 0);}
// Should not be allowed by default
inline virtual bool operator==(const RefCounted&) const
{return false;}
inline bool operator!=(const RefCounted&) const
{return false;}
// Add reference
inline void AddReference(void)
{++mRefCount;}
// Release reference
inline virtual void Release(void)
{if (--mRefCount == 0) delete this;}
inline int ReferenceCount(void) const
{return mRefCount;}
private:
friend class RefPtrBase;
unsigned int mRefCount;
};
#endif // REFCOUNTED_H

View file

@ -0,0 +1,361 @@
/*
** Command & Conquer Generals(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/>.
*/
/******************************************************************************
*
* FILE
* $Archive: $
*
* DESCRIPTION
* RefPtr<> and RefPtrConst<> are const-friendly, polymorphic reference
* counting smart pointers.
*
* The pointed-to class must be derived from RefCount.
*
* RefPtr<X> replaces X*
* RefPtrConst<X> replaces const X*
*
* Dynamic_Cast<X> replaces dynamic_cast<X*> and dynamic_cast<X&>
* Reinterpret_Cast<X> replaces reinterpret_cast<X*> and reinterpret_cast<X&>
* Const_Cast<X> replaces const_cast<X*> and const_cast<X&>
*
* IsValid() replaces (x != NULL)
*
* Member function Attach() or assigning RefPtr<X>() will NULL a pointer.
*
* Generally, RefPtr<> and RefPtrConst<> behave like their raw pointer
* counterparts, except of course they are reference counted and will delete
* the pointed-to object when the last reference is lost. The major
* syntatical differences are the use of RefPtrConst<> to represent a pointer
* to a constant object (I found it impossible to represent this within rc_ptr)
* and the use of the upper-case cast functions (it is not possible to overload
* these built-in functions).
*
* An explicit goal of this class is to completely avoid the "new" and "delete"
* operators in client code. The constructors for these pointers are private;
* they are friends of the pointed-to class. This forces the use of Factory
* Method functions (or similar) in the pointed-to class. Pointed-to classes
* should make the constructor protected or private to disallow clients from
* creating an instance with "new". If this is done, it becomes very difficult
* for the client to accidentally leak objects and/or misuse the pointed-to
* class or the reference counting pointers.
*
* PROGRAMMER
* Steven Clinard
* $Author: $
*
* VERSION INFO
* $Modtime: $
* $Revision: $
*
******************************************************************************/
#ifndef REFPTR_H
#define REFPTR_H
#include "VisualC.h"
#include "RefCounted.h"
#include <stddef.h>
#include <assert.h>
template<typename Type> class RefPtr;
template<typename Type> class RefPtrConst;
class RefPtrBase
{
public:
inline bool operator==(const RefPtrBase& rhs) const
{return (mRefObject == rhs.mRefObject);}
inline bool operator!=(const RefPtrBase& rhs) const
{return !operator==(rhs);}
inline bool IsValid(void) const
{return (mRefObject != NULL);}
inline void Detach(void)
{
if (IsValid())
{
mRefObject->Release();
mRefObject = NULL;
}
}
protected:
RefPtrBase()
: mRefObject(NULL)
{}
RefPtrBase(RefCounted* object)
: mRefObject(object)
{
assert((mRefObject == NULL) || (mRefObject->mRefCount == 0));
if (IsValid())
{
mRefObject->AddReference();
}
}
RefPtrBase(const RefPtrBase& object)
: mRefObject(object.mRefObject)
{
assert(false); // why is this being called?
if (IsValid())
{
mRefObject->AddReference();
}
}
virtual ~RefPtrBase()
{Detach();}
const RefPtrBase& operator=(const RefPtrBase&);
inline RefCounted* const GetRefObject(void)
{return mRefObject;}
inline const RefCounted* const GetRefObject(void) const
{return mRefObject;}
inline void Attach(RefCounted* object)
{
// If objects are different
if (object != mRefObject)
{
// Add reference to new object
if (object != NULL)
{
object->AddReference();
}
// Release reference to old object
Detach();
// Assign new object
mRefObject = object;
}
}
private:
RefCounted* mRefObject;
template<typename Derived>
friend RefPtr<Derived> Dynamic_Cast(RefPtrBase&);
template<typename Type>
friend RefPtr<Type> Reinterpret_Cast(RefPtrBase&);
};
template<typename Type> class RefPtr
: public RefPtrBase
{
public:
RefPtr()
: RefPtrBase()
{}
template<typename Derived>
RefPtr(const RefPtr<Derived>& derived)
: RefPtrBase()
{
Attach(const_cast<Derived*>(derived.ReferencedObject()));
}
RefPtr(const RefPtr<Type>& object)
: RefPtrBase()
{
Attach(const_cast<Type*>(object.ReferencedObject()));
}
virtual ~RefPtr()
{}
template<typename Derived>
inline const RefPtr<Type>& operator=(const RefPtr<Derived>& derived)
{
Attach(const_cast<Derived*>(derived.ReferencedObject()));
return *this;
}
inline const RefPtr<Type>& operator=(const RefPtr<Type>& object)
{
Attach(const_cast<Type*>(object.ReferencedObject()));
return *this;
}
inline Type& operator*() const
{
assert(IsValid());
return *const_cast<Type*>(ReferencedObject());
}
inline Type* const operator->() const
{
assert(IsValid());
return const_cast<Type*>(ReferencedObject());
}
// These are public mostly because I can't seem to declare rc_ptr<Other> as a friend
inline Type* const ReferencedObject(void)
{return reinterpret_cast<Type*>(GetRefObject());}
inline const Type* const ReferencedObject(void) const
{return reinterpret_cast<const Type*>(GetRefObject());}
RefPtr(Type* object)
: RefPtrBase()
{
Attach(object);
}
inline const RefPtr<Type>& operator=(Type* object)
{
Attach(object);
return *this;
}
private:
friend RefPtr<Type> Dynamic_Cast(RefPtrBase&);
friend RefPtr<Type> Reinterpret_Cast(RefPtrBase&);
friend RefPtr<Type> Const_Cast(RefPtrConst<Type>&);
};
template<typename Type> class RefPtrConst
: public RefPtrBase
{
public:
RefPtrConst()
: RefPtrConst()
{}
template<typename Derived>
RefPtrConst(const RefPtr<Derived>& derived)
: RefPtrBase()
{
Attach(derived.ReferencedObject());
}
RefPtrConst(const RefPtr<Type>& object)
: RefPtrBase()
{
Attach(const_cast<Type* const >(object.ReferencedObject()));
}
template<typename Derived>
RefPtrConst(const RefPtrConst<Derived>& derived)
: RefPtrBase()
{
Attach(derived.ReferencedObject());
}
RefPtrConst(const RefPtrConst<Type>& object)
: RefPtrBase()
{
Attach(object.ReferencedObject());
}
template<typename Derived>
inline const RefPtrConst<Type>& operator=(const RefPtr<Derived>& derived)
{
Attach(derived.ReferencedObject());
return *this;
}
inline const RefPtrConst<Type>& operator=(const RefPtr<Type>& object)
{
Attach(object.ReferencedObject());
return *this;
}
template<typename Derived>
inline const RefPtrConst<Type>& operator=(const RefPtrConst<Derived>& derived)
{
Attach(derived.ReferencedObject());
return *this;
}
inline const RefPtrConst<Type>& operator=(const RefPtrConst<Type>& object)
{
Attach(object.ReferencedObject());
return *this;
}
virtual ~RefPtrConst()
{}
inline const Type& operator*() const
{
assert(IsValid());
return *ReferencedObject();
}
inline const Type* const operator->() const
{
assert(IsValid());
return ReferencedObject();
}
// This is public mostly because I can't seem to declare rc_ptr<Other> as a friend
inline const Type* const ReferencedObject() const
{return reinterpret_cast<const Type*>(GetRefObject());}
RefPtrConst(const Type* object)
: RefPtrBase()
{
Attach(object);
}
const RefPtrConst<Type>& operator=(const Type* object)
{
Attach(object);
}
};
template<typename Derived>
RefPtr<Derived> Dynamic_Cast(RefPtrBase& base)
{
RefPtr<Derived> derived;
derived.Attach(base.GetRefObject());
return derived;
}
template<typename Type>
RefPtr<Type> Reinterpret_Cast(RefPtrBase& rhs)
{
RefPtr<Type> object;
object.Attach(rhs.GetRefObject());
return object;
}
template<typename Type>
RefPtr<Type> Const_Cast(RefPtrConst<Type>& rhs)
{
RefPtr<Type> object;
object.Attach(rhs.ReferencedObject());
return object;
}
#endif // RC_PTR_H

View file

@ -0,0 +1,107 @@
/*
** Command & Conquer Generals(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/>.
*/
/******************************************************************************
*
* FILE
* $Archive: $
*
* DESCRIPTION
* Perform ANSI <-> Unicode string conversions
*
* PROGRAMMER
* Denzil E. Long, Jr.
* $Author: $
*
* VERSION INFO
* $Modtime: $
* $Revision: $
*
******************************************************************************/
#include "StringConvert.h"
#include "UString.h"
#include <windows.h>
#include <Debug\DebugPrint.h>
#include <assert.h>
/******************************************************************************
*
* NAME
* UStringToANSI
*
* DESCRIPTION
* Convert UString to an ANSI string
*
* INPUTS
* String - String to convert
* Buffer - Pointer to buffer to receive conversion.
* BufferLength - Length of buffer
*
* RESULT
* ANSI - Pointer to ANSI string
*
******************************************************************************/
Char* UStringToANSI(const UString& string, Char* buffer, UInt bufferLength)
{
return UnicodeToANSI(string.Get(), buffer, bufferLength);
}
/******************************************************************************
*
* NAME
* UnicodeToANSI
*
* DESCRIPTION
* Convert Unicode string to an ANSI string
*
* INPUTS
* String - Unicode string to convert
* Buffer - Pointer to buffer to receive conversion.
* BufferLength - Length of buffer
*
* RESULT
* ANSI - Pointer to ANSI string
*
******************************************************************************/
Char* UnicodeToANSI(const WChar* string, Char* buffer, UInt bufferLength)
{
if ((string == NULL) || (buffer == NULL))
{
return NULL;
}
#ifdef _DEBUG
int result =
#endif
WideCharToMultiByte(CP_ACP, 0, string, -1, buffer, bufferLength,
NULL, NULL);
#ifdef _DEBUG
if (result == 0)
{
PrintWin32Error("ConvertToANSI() Failed");
assert(false);
}
#endif
return buffer;
}

View file

@ -0,0 +1,47 @@
/*
** Command & Conquer Generals(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/>.
*/
/******************************************************************************
*
* FILE
* $Archive: $
*
* DESCRIPTION
* ANSI <-> Unicode string conversions
*
* PROGRAMMER
* Denzil E. Long, Jr.
* $Author: $
*
* VERSION INFO
* $Modtime: $
* $Revision: $
*
******************************************************************************/
#ifndef STRINGCONVERT_H
#define STRINGCONVERT_H
#include "UTypes.h"
class UString;
Char* UStringToANSI(const UString& string, Char* buffer, UInt bufferLength);
Char* UnicodeToANSI(const WChar* string, Char* buffer, UInt bufferLength);
#endif // STRINGCONVERT_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,239 @@
/*
** Command & Conquer Generals(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/>.
*/
/******************************************************************************
*
* FILE
* $Archive: $
*
* DESCRIPTION
* String management class (Unicode)
*
* PROGRAMMER
* Denzil E. Long, Jr.
* $Author: $
*
* VERSION INFO
* $Modtime: $
* $Revision: $
*
******************************************************************************/
#ifndef USTRING_H
#define USTRING_H
#include "UTypes.h"
#include "RefCounted.h"
class UString
: public RefCounted
{
public:
// Constructors
UString();
UString(UInt capacity);
UString(const Char* s);
UString(const WChar* ws);
UString(const UString& s);
virtual ~UString();
//! Get the length of the string
UInt Length(void) const;
//! Copy string
void Copy(const Char* s);
void Copy(const WChar* ws);
void Copy(const UString& s);
//! Concatenate string
void Concat(const Char* s);
void Concat(const WChar* ws);
void Concat(const UString& s);
//! Compare strings
Int Compare(const Char* s) const;
Int Compare(const WChar* s) const;
Int Compare(const UString& s) const;
//! Compare strings not case-sensitive
Int CompareNoCase(const Char* s) const;
Int CompareNoCase(const WChar* ws) const;
Int CompareNoCase(const UString& s) const;
//! Find the first occurance of character
Int Find(Char c) const;
Int Find(WChar wc) const;
//! Find the last occurance of a character
Int FindLast(Char c) const;
Int FindLast(WChar c) const;
//! Find a substring
UString SubString(const Char* s);
UString SubString(const WChar* ws);
UString SubString(const UString& s);
//! Extract left part of the string
UString Left(UInt count);
//! Extract middle part of the string.
UString Middle(UInt first, UInt count);
//! Extract right part of the string.
UString Right(UInt count);
//! Convert string to uppercase
void ToUpper(void);
//! Convert string to lowercase
void ToLower(void);
//! Reverse characters of string
void Reverse(void);
//! Remove leading and trailing characters from string.
// Returns true if any characters removed
bool Trim(const Char* trimChars);
bool Trim(const WChar* trimChars);
bool Trim(const UString& trimChars);
//! Remove characters from left side of string
// Returns true if any characters removed
bool TrimLeft(const Char* trimChars);
bool TrimLeft(const WChar* trimChars);
bool TrimLeft(const UString& trimChars);
//! Remove characters from right side of string
// Returns true if any characters removed
bool TrimRight(const Char* trimChars);
bool TrimRight(const WChar* trimChars);
bool TrimRight(const UString& trimChars);
// Convert string to ANSI
void ConvertToANSI(Char* buffer, UInt bufferLength) const;
//! Get the size (in bytes) of the string.
UInt Size(void) const;
//! Get the maximum number of characters this string can hold.
UInt Capacity(void) const;
//! Resize the string
bool Resize(UInt size);
const WChar* Get(void) const
{return (mData != NULL) ? mData : L"";}
//! Assignment operator
UString operator=(const Char* s)
{Copy(s); return *this;};
UString operator=(const WChar* ws)
{Copy(ws); return *this;};
UString operator=(const UString& s)
{Copy(s); return *this;};
//! Addition operator (concatenate)
UString operator+(const Char* s)
{UString ns(*this); ns += s; return ns;}
UString operator+(const WChar* ws)
{UString ns(*this); ns += ws; return ns;}
UString operator+(const UString& s)
{UString ns(*this); ns += s; return ns;}
UString operator+=(const Char* s)
{Concat(s); return *this;}
UString operator+=(const WChar* ws)
{Concat(ws); return *this;}
UString operator+=(const UString& s)
{Concat(s); return *this;}
//! Equal operator (case sensitive compare)
bool operator==(const Char* s)
{return (Compare(s) == 0);}
bool operator==(const WChar* ws)
{return (Compare(ws) == 0);}
bool operator==(const UString& s)
{return (Compare(s) == 0);}
bool operator!=(const Char* s)
{return (Compare(s) != 0);}
bool operator!=(const WChar* ws)
{return (Compare(ws) != 0);}
bool operator!=(const UString& s)
{return (Compare(s) != 0);}
//! Less than operator (case sensitive compare)
bool operator<(const Char* s)
{return (Compare(s) == -1);}
bool operator<(const WChar* ws)
{return (Compare(ws) == -1);}
bool operator<(const UString& s)
{return (Compare(s) == -1);}
bool operator<=(const Char* s)
{return (Compare(s) <= 0);}
bool operator<=(const WChar* ws)
{return (Compare(ws) <= 0);}
bool operator<=(const UString& s)
{return (Compare(s) <= 0);}
//! Greater than operator (case sensitive compare)
bool operator>(const Char* s)
{return (Compare(s) == 1);}
bool operator>(const WChar* ws)
{return (Compare(ws) == 1);}
bool operator>(const UString& s)
{return (Compare(s) == 1);}
bool operator>=(const Char* s)
{return (Compare(s) >= 0);}
bool operator>=(const WChar* ws)
{return (Compare(ws) >= 0);}
bool operator>=(const UString& s)
{return (Compare(s) >= 0);}
// Conversion operator
operator const WChar*() const
{return Get();}
private:
bool AllocString(UInt size);
WChar* mData;
UInt mCapacity;
};
#endif // USTRING_H

View file

@ -0,0 +1,90 @@
/*
** Command & Conquer Generals(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/>.
*/
/******************************************************************************
*
* FILE
* $Archive: $
*
* DESCRIPTION
* Generic user type definitions
*
* PROGRAMMER
* Denzil E. Long, Jr.
* $Author: $
*
* VERSION INFO
* $Modtime: $
* $Revision: $
*
******************************************************************************/
#ifndef UTYPES_H
#define UTYPES_H
//! Signed integer value
typedef int Int;
//! Unsigned integer value
typedef unsigned int UInt;
//! Signed 8bit value (-127 - 128)
typedef char Int8;
//! Unsigned 8bit value (0 - 255)
typedef unsigned char UInt8;
//! Signed 16bit value (-32767 - 32768)
typedef short Int16;
//! Unsigned 16bit value (0 - 65535)
typedef unsigned short UInt16;
//! Signed 32bit value
typedef long Int32;
//! Unsigned 32bit value
typedef unsigned long UInt32;
//! Signed character (ASCII)
typedef char Char;
//! Unsigned character (ANSI)
typedef unsigned char UChar;
//! Wide character (Unicode)
typedef unsigned short WChar;
//! 32bit floating point value
typedef float Float32;
//! 64bit floating point value
typedef double Float64;
//! Floating point value
typedef Float32 Float;
//! TriState
typedef enum {OFF = false, ON = true, PENDING = -1} TriState;
//! Empty pointer
#ifndef NULL
#define NULL (0L)
#endif
#endif // UTYPES_H

View file

@ -0,0 +1,90 @@
/*
** Command & Conquer Generals(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/>.
*/
/******************************************************************************
*
* FILE
* $Archive: $
*
* DESCRIPTION
* Disable specific warnings generated by Microsoft Visual C++ 6.0
*
* PROGRAMMER
* Denzil E. Long, Jr.
* $Author: $
*
* VERSION INFO
* $Modtime: $
* $Revision: $
*
******************************************************************************/
#pragma once
#ifndef _VISUALC_H_
#define _VISUALC_H_
#if defined(_MSC_VER)
// "unreferenced inline function has been removed"
// Inline functions are used in headers and this warning will appear everywhere
// without explicitly being disabled.
#pragma warning(disable:4514)
// "conversion from 'double' to 'float', possible loss of data"
// This occurs during non-constant floating point arithmetic. Since all floating
// point math is silently upcasted to doubles, it should silently downcast
// back to 'float' when complete -- hence this warning should not be displayed.
#pragma warning(disable:4244)
// "overflow in floating-point constant arithmetic"
// This warning occurs even when there is no overflow. It occurs when a double
// is downcasted to a float during constant arithmetic (this is not worthy of
// a warning message).
#pragma warning(disable:4056)
// "argument trunation from const double to float"
// This warning is of little use since the compiler uses doubles whenever
// possible, therfore this warning will appear frequently. It is similar to
// warning 4244 and is similarly irrelevant.
#pragma warning(disable:4305)
// "'this' used in base member initializer list"
// Using "this" in a base member initializer is valid -- no need for this warning.
#pragma warning(disable:4355)
// "typedef-name used as a synonym for class-name"
// This is by design and should not be a warning.
#pragma warning(disable:4097)
// "function not inlined"
// This warning is typically useless. The inline keyword only serves as a
// suggestion to the compiler and it may or may not inline a function on a
// case by case basis. No need to be told of this.
#pragma warning(disable:4710)
// "function selected for automatic inline expansion"
// There is no need to announce this with a warning message.
#pragma warning(disable:4711)
// "identifier was truncated to 'number' characters in the debug information"
// The debugger cannot debug code with symbols longer than 255 characters.
// In the debugger, you cannot view, evaluate, update, or watch the truncated symbols.
#pragma warning(disable:4786)
#endif // _MSC_VER
#endif // _VISUALC_H_

View file

@ -0,0 +1,165 @@
/*
** Command & Conquer Generals(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);
}

View file

@ -0,0 +1,55 @@
/*
** Command & Conquer Generals(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

View file

@ -0,0 +1,80 @@
/*
** Command & Conquer Generals(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_PATCHPROGRESS),
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);
}

View file

@ -0,0 +1,28 @@
/*
** Command & Conquer Generals(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

View file

@ -0,0 +1,586 @@
/*
** Command & Conquer Generals(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

View file

@ -0,0 +1,56 @@
/*
** Command & Conquer Generals(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, bool outputDebug) : m_outputDebug(outputDebug)
{
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);
if (m_outputDebug)
{
OutputDebugString(string);
}
delete[](string);
fflush(out);
return(len);
}
FILE *out;
bool m_outputDebug;
};
#endif

View file

@ -0,0 +1,213 @@
/*
** Command & Conquer Generals(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);
}
sprintf(string,"download\\*.%s",extensions[i]);
hFile=FindFirstFile(string,&findData);
if (hFile!=INVALID_HANDLE_VALUE)
{
_getcwd(filename,MAX_PATH);
strcat(filename,"\\download\\");
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;
}

View file

@ -0,0 +1,33 @@
/*
** Command & Conquer Generals(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

View file

@ -0,0 +1,326 @@
# 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 ""$/APILauncher", DJDAAAAA"
# 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 /I "ToolKit" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "USE_NOTEPAD" /FR /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 /pdb:"../../../Run/Generals.pdb" /map:"../../../Run/Generals.map" /debug /machine:I386 /out:"../../../Run/Generals.exe"
# SUBTRACT LINK32
!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 /I "ToolKit" /D "_DEBUG" /D "DEBUG" /D "USE_GAMEDIR_FROM_LCF" /D "WIN32" /D "_WINDOWS" /D "USE_NOTEPAD" /FR /FD /c
# SUBTRACT CPP /YX
# 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
# 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 winmm.lib /nologo /subsystem:windows /pdb:"../../../Run/GeneralsD.pdb" /map:"../../../Run/GeneralsD.map" /debug /machine:I386 /out:"../../../Run/GeneralsD.exe" /libpath:"."
# SUBTRACT LINK32
!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 Group "Support"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\Toolkit\Support\RefCounted.h
# End Source File
# Begin Source File
SOURCE=.\Toolkit\Support\RefPtr.h
# End Source File
# Begin Source File
SOURCE=.\Toolkit\Support\StringConvert.cpp
# End Source File
# Begin Source File
SOURCE=.\Toolkit\Support\StringConvert.h
# End Source File
# Begin Source File
SOURCE=.\Toolkit\Support\UString.cpp
# End Source File
# Begin Source File
SOURCE=.\Toolkit\Support\UString.h
# End Source File
# Begin Source File
SOURCE=.\Toolkit\Support\UTypes.h
# End Source File
# Begin Source File
SOURCE=.\Toolkit\Support\Visualc.h
# End Source File
# End Group
# Begin Group "Debug"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\Toolkit\Debug\DebugPrint.cpp
# End Source File
# Begin Source File
SOURCE=.\Toolkit\Debug\DebugPrint.h
# End Source File
# End Group
# Begin Group "Storage"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\Toolkit\Storage\File.cpp
# End Source File
# Begin Source File
SOURCE=.\Toolkit\Storage\File.h
# End Source File
# Begin Source File
SOURCE=.\Toolkit\Storage\Rights.h
# End Source File
# Begin Source File
SOURCE=.\Toolkit\Storage\Stream.h
# End Source File
# End Group
# Begin Group "SafeDisk"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\SafeDisk\CdaPfn.h
# End Source File
# End Group
# Begin Source File
SOURCE=.\BFISH.CPP
# End Source File
# Begin Source File
SOURCE=.\BFISH.H
# End Source File
# 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=.\Generals.ico
# End Source File
# Begin Source File
SOURCE=..\..\..\Run\generals.lcf
# End Source File
# Begin Source File
SOURCE=..\..\..\Run\launcher.bmp
# 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=..\..\..\Run\patchw32.dll
# 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=.\Protect.cpp
# End Source File
# Begin Source File
SOURCE=.\Protect.h
# 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

View file

@ -0,0 +1,151 @@
//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_PATCHPROGRESS 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_PATCHPROGRESS, 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_GENERALS ICON DISCARDABLE "Generals.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."
IDS_ERR_PATCH "Patch error. Existing game files may have been modified. You should re-install the game from the CD."
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View file

@ -0,0 +1,215 @@
/*
** Command & Conquer Generals(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;
HANDLE hBitmapFile;
DWORD dwRead;
BITMAPFILEHEADER bitmapHeader;
BITMAPINFOHEADER bitmapInfoHeader;
LPLOGPALETTE lpLogPalette;
char *palData;
HGLOBAL hmem2;
LPVOID lpvBits;
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];
if (BitmapHandle_ == NULL) // NAK - new
return(FALSE);
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);
}

View file

@ -0,0 +1,46 @@
/*
** Command & Conquer Generals(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

View file

@ -0,0 +1,399 @@
/*
** Command & Conquer Generals(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
# RUN2 = the 2nd launcher if using one
RUN2 = . wordpad.exe
# FLAG = time in seconds of when to stop using 2nd launcher
FLAG = 996778113
#
# 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>
#ifdef COPY_PROTECT
#include "Protect.h"
#endif
#include <Debug\DebugPrint.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);
void RunGame(char *thePath, ConfigFile &config, Process &proc)
{
char patchFile[MAX_PATH];
bool launchgame = true;
// MDC 8/23/2001 Wait 3 seconds for the installer to release the mutex
///Sleep(3000);
while (true)
{
int skuIndex;
while ((skuIndex = Find_Patch(patchFile, MAX_PATH, config)) != 0)
{
Apply_Patch(patchFile, config, skuIndex);
launchgame = true;
}
// launch the game if first pass, or found a patch
if (launchgame)
{
// don't relaunch unless we find a patch (or checking for patches)
launchgame = false;
myChdir(thePath);
#ifndef COPY_PROTECT
Create_Process(proc);
#else // COPY_PROTECT
InitializeProtect();
Create_Process(proc);
SendProtectMessage(proc.hProcess, proc.dwThreadID);
#endif // COPY_PROTECT
DWORD exit_code;
Wait_Process(proc, &exit_code);
if (exit_code == UPDATE_RETVAL)
{
// They just want to check for patches
launchgame = true;
// Start patchgrabber
Process patchgrab;
strcpy(patchgrab.directory,proc.directory); // same dir as game
strcpy(patchgrab.command,"patchget.dat"); // the program that grabs game patches
strcpy(patchgrab.args,"");
Create_Process(patchgrab);
Wait_Process(patchgrab); // wait for completion
}
#ifdef COPY_PROTECT
ShutdownProtect();
#endif
}
else
{
Delete_Patches(config); // delete all patches
break;
}
}
}
// The other launcher will handle itself. Just fire and forget.
void RunLauncher(char *thePath, Process &proc)
{
myChdir(thePath);
Create_Process(proc);
}
//
// Called by WinMain
//
int main(int argc, char *argv[])
{
char patchFile[MAX_PATH];
char cwd[MAX_PATH]; // save current directory before game start
_getcwd(cwd, MAX_PATH);
// 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;
}
#ifdef DEBUG
///MonoD outputDevice;
char debugFile[MAX_PATH + 3];
strcpy(debugFile, configName);
strcat(debugFile, ".txt");
strcpy(debugLogName, strrchr(configName, '\\'));
strcat(debugLogName, "Log");
FileD outputDevice(debugFile, true);
MsgManager::setAllStreams(&outputDevice);
DBGMSG("Launcher initialized");
#endif
CreatePrimaryWin("generals");
InitCommonControls();
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);
}
bit8 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);
// Possible 2nd EXE
Process proc2;
int hasSecondEXE = Read_Process_Info(config,proc2,"RUN2");
DBGMSG("Read process info");
for (int i = 1; i < argc; i++)
{
strcat(proc.args, " ");
strcat(proc.args, argv[i]);
if (hasSecondEXE)
{
strcat(proc2.args, " ");
strcat(proc2.args, argv[i]);
}
}
DBGMSG("ARGS: "<<proc.args);
// Just spawn the patchgrabber & apply any patches it downloads
if ((argc >= 2) && (strcmp(argv[1], "GrabPatches") == 0))
{
// Start patchgrabber
Process patchgrab;
// same dir as game
strcpy(patchgrab.directory, proc.directory);
// the program that grabs game patches
strcpy(patchgrab.command, "patchget.dat");
strcpy(patchgrab.args, "");
Create_Process(patchgrab);
Wait_Process(patchgrab);
// Apply any patches I find
int skuIndex;
while ((skuIndex = Find_Patch(patchFile, MAX_PATH, config)) != 0)
{
Apply_Patch(patchFile, config, skuIndex);
}
myChdir(cwd);
return 0;
}
// Look for patch file(s) to apply
bool launchgame = true;
time_t cutoffTime = 0;
if (hasSecondEXE)
{
Wstring timeStr;
if (config.getString("FLAG", timeStr)!=FALSE)
{
cutoffTime = atoi(timeStr.get());
}
if (cutoffTime == 0)
{
// We didn't have the FLAG parameter; somebody's been hacking. No game for you! Bad hacker!
DBGMSG("Saw cutoffTime of 0; real time is " << time(NULL));
MessageBox(NULL,"File 'launcher.cfg' is corrupt","Error",MB_OK);
exit(-1);
}
if (time(NULL) > cutoffTime)
{
// The future is now! Just run the game.
RunGame(argv[0], config, proc);
}
else
{
// Its still early in the product's lifetime, so run the 2nd (SafeDisk'd) launcher.
// We don't have to wait around since it'll do the entire talk to game, look for patches,
// etc. deal.
RunLauncher(argv[0], proc2);
}
}
else
{
// We're the second (or only) launcher, so act normally
RunGame(argv[0], config, proc);
}
myChdir(cwd);
// Exit normally
return 0;
}
//
// Create a primary window
//
void CreatePrimaryWin(char *prefix)
{
char name[256];
sprintf(name, "launcher_%s", prefix);
DBGMSG("CreatePrimary: "<<name);
/*
** set up and register window class
*/
WNDCLASS wc;
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_GENERALS));
wc.hCursor = NULL; /////////LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = NULL;
wc.lpszMenuName = name;
wc.lpszClassName = name;
RegisterClass(&wc);
/*
** create a window
*/
HWND 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....
}

View file

@ -0,0 +1,57 @@
/*
** Command & Conquer Generals(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
}

View file

@ -0,0 +1,74 @@
/*
** Command & Conquer Generals(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

View file

@ -0,0 +1,32 @@
/*
** Command & Conquer Generals(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

View file

@ -0,0 +1,574 @@
/*
** Command & Conquer Generals(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);
__declspec(dllexport) LPVOID CALLBACK 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);
exit(-1);
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
// Don't update the registry if the patch failed to update.
if (rtpErrCode != 0)
{
ERRMSG("Patch error: " << rtpErrCode);
return;
}
// 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)
{
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
#ifdef USE_NOTEPAD
{
Process notepad;
// same dir as game
strcpy(notepad.directory, ".");
// the program that grabs game patches
strcpy(notepad.command, "notepad");
strcpy(notepad.args, " launcher.txt");
Create_Process(notepad);
Wait_Process(notepad);
}
#else
DialogBox(Global_instance,MAKEINTRESOURCE(IDD_CHANGELOG),NULL,(DLGPROC)Update_Info_Proc);
#endif
}
//
// 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
//
__declspec(dllexport) LPVOID CALLBACK 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;
char errmsg[256];
LoadString(NULL,IDS_ERR_PATCH,errmsg,256);
MessageBox(NULL,(char *)Param,errmsg,MB_OK);
{
FILE *out=fopen("patch.err","a");
time_t timet=time(NULL);
fprintf(out,"\n\nPatch Error: %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);
}

View file

@ -0,0 +1,30 @@
/*
** Command & Conquer Generals(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);
#endif

View file

@ -0,0 +1,176 @@
/*
** Command & Conquer Generals(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);
DBGMSG("PROCESS CMD="<<cmdargs<<" DIR="<<process.directory);
#ifndef COPY_PROTECT
retval=CreateProcess(NULL,cmdargs,NULL,NULL,FALSE, 0 ,NULL, NULL/*process.directory*/,&si,&piProcess);
#else
#ifdef USE_GAMEDIR_FROM_LCF
retval=CreateProcess(NULL,cmdargs,NULL,NULL,TRUE, 0 ,NULL, process.directory,&si,&piProcess);
#else
retval=CreateProcess(NULL,cmdargs,NULL,NULL,TRUE, 0 ,NULL, NULL/*process.directory*/,&si,&piProcess);
#endif
#endif
DBGMSG("("<<retval<<") New process: HANDLE " << (void *)piProcess.hProcess << " ID "
<< (DWORD)piProcess.dwProcessId);
DBGMSG("("<<retval<<") New thread: HANDLE " << (void *)piProcess.hThread << " ID "
<< (DWORD)piProcess.dwThreadId);
if (retval==0)
{
char message_buffer[256];
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &message_buffer[0], 256, NULL );
DBGMSG("ERR: "<<message_buffer);
}
process.hProcess=piProcess.hProcess;
process.dwProcessID = piProcess.dwProcessId;
process.hThread=piProcess.hThread;
process.dwThreadID = piProcess.dwThreadId;
return(TRUE);
}
//
// Wait for a process to complete, and fill in the exit code
//
bit8 Wait_Process(Process &process, DWORD *exit_code)
{
DWORD retval;
retval=WaitForSingleObject(process.hProcess,INFINITE);
if (exit_code != NULL)
*exit_code=-1;
if (retval==WAIT_OBJECT_0) // process exited
{
// MDC 1/10/2003 Inserting sleep here to let game exit before applying patch
Sleep(3000);
if (exit_code != NULL)
GetExitCodeProcess(process.hProcess,exit_code);
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, IN char *key)
{
Wstring keyStr = "RUN";
if (key)
keyStr = key;
Wstring procinfo;
if (config.getString(keyStr.get(), 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);
**********************************************/
}

View file

@ -0,0 +1,46 @@
/*
** Command & Conquer Generals(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;
DWORD dwProcessID;
HANDLE hThread;
DWORD dwThreadID;
};
bit8 Read_Process_Info(ConfigFile &config,OUT Process &info, IN char *key = NULL);
bit8 Create_Process(Process &process);
bit8 Wait_Process(Process &process, DWORD *exit_code=NULL);
#endif

View file

@ -0,0 +1,35 @@
//{{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 IDS_ERR_PATCH 11
#define IDD_DIALOG1 101
#define IDD_PATCHPROGRESS 101
#define IDI_GENERALS 102
#define IDD_CHANGELOG 103
#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 104
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1013
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View file

@ -0,0 +1,142 @@
/*
** Command & Conquer Generals(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);
}

View file

@ -0,0 +1,60 @@
/*
** Command & Conquer Generals(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

View file

@ -0,0 +1,143 @@
/*
** Command & Conquer Generals(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);
}

View file

@ -0,0 +1,193 @@
/*
** Command & Conquer Generals(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

View file

@ -0,0 +1,186 @@
/*
** Command & Conquer Generals(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);
}

View file

@ -0,0 +1,37 @@
/*
** Command & Conquer Generals(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

View file

@ -0,0 +1,611 @@
/*
** Command & Conquer Generals(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<(int)length(); i++) {
if(strchr(delim,str[i])==NULL)
break;
}
if (i>=(int)length())
return(-1);
start=i;
for (; i<(int)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 >= (int)length())
return(-1);
for (; i<(int)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);
}

View file

@ -0,0 +1,87 @@
/*
** Command & Conquer Generals(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

View file

@ -0,0 +1,82 @@
/*
** Command & Conquer Generals(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