Initial commit of Command & Conquer Generals and Command & Conquer Generals Zero Hour source code.
This commit is contained in:
parent
2e338c00cb
commit
3d0ee53a05
6072 changed files with 2283311 additions and 0 deletions
59
Generals/Code/Tools/mangler/Makefile
Normal file
59
Generals/Code/Tools/mangler/Makefile
Normal file
|
@ -0,0 +1,59 @@
|
|||
all = mangler
|
||||
|
||||
TARGET=mangler
|
||||
TESTTARGET=manglertest
|
||||
|
||||
OBJECTS=mangler.o crc.o
|
||||
TESTOBJECTS=manglertest.o crc.o
|
||||
|
||||
|
||||
LINKFLAGS=
|
||||
LINKDIRS=-L. -Lwlib -Lwnet
|
||||
############################################################################
|
||||
### -lpthread ### MUST MUST MUST be the last library!
|
||||
############################################################################
|
||||
LINKLIBS = -lwnet -lwlib -lsocket -lnsl -lposix4 -lpthread
|
||||
|
||||
INCDIR=-I. -Iwlib -Iwnet
|
||||
|
||||
CPPFLAGS=$(INCDIR) -c -gstabs+ -DDEBUG -D_UNIX
|
||||
#CPPFLAGS=$(INCDIR) -c -gstabs+ -D_UNIX
|
||||
|
||||
CPPFILES=${OBJECTS:.o=.cpp}
|
||||
CFILES=${OBJECTS:.o=.c}
|
||||
.SUFFIXES : .c .cpp
|
||||
|
||||
|
||||
$(TARGET) : $(OBJECTS)
|
||||
g++ $(LINKFLAGS) $(OBJECTS) $(LINKDIRS) $(LINKLIBS) -o $(TARGET)
|
||||
|
||||
$(TESTTARGET) : $(TESTOBJECTS) $(TARGET)
|
||||
g++ $(LINKFLAGS) $(TESTOBJECTS) $(LINKDIRS) $(LINKLIBS) -o $(TESTTARGET)
|
||||
|
||||
.cpp.o:
|
||||
g++ $(CPPFLAGS) $<
|
||||
|
||||
.c.o:
|
||||
g++ $(CPPFLAGS) $<
|
||||
|
||||
|
||||
depend:
|
||||
g++ -M $(INCDIR) ${CFILES} $(CPPFILES) > dependencies
|
||||
|
||||
|
||||
clean:
|
||||
-rm *.o $(TARGET) $(TESTTARGET) core *.dat
|
||||
|
||||
rebuild:
|
||||
make clean; make
|
||||
|
||||
run:
|
||||
make; $(TARGET)
|
||||
|
||||
debug:
|
||||
gdb -s noxc noxc
|
||||
|
||||
dist:
|
||||
make clean; make; cp wdtd gavin; cp START gavin; cp STOP gavin; cp world.wdt gavin;
|
||||
|
||||
#include dependencies
|
181
Generals/Code/Tools/mangler/crc.cpp
Normal file
181
Generals/Code/Tools/mangler/crc.cpp
Normal file
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
** 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 <iostream>
|
||||
#include <signal.h>
|
||||
#ifdef _WINDOWS
|
||||
#include <process.h> // *MUST* be included before ANY Wnet/Wlib headers if _REENTRANT is defined
|
||||
#endif
|
||||
|
||||
#include "crc.h"
|
||||
|
||||
#include "configfile.h"
|
||||
#include "threadfac.h"
|
||||
|
||||
#include "endian.h"
|
||||
|
||||
#include "xtime.h"
|
||||
#include <filed.h>
|
||||
#include <wstring.h>
|
||||
#include <wdebug.h>
|
||||
#include <udp.h>
|
||||
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* Add_CRC -- Adds a value to a CRC *
|
||||
* *
|
||||
* INPUT: *
|
||||
* crc ptr to crc *
|
||||
* val value to add *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* none *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* none *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 05/09/1995 BRR : Created. *
|
||||
*=========================================================================*/
|
||||
void Add_CRC(unsigned long *crc, unsigned char val)
|
||||
{
|
||||
int hibit;
|
||||
|
||||
//cout << "\t\t" << hex << val;
|
||||
// val = htonl(val);
|
||||
//cout << " / " << hex << val <<endl;
|
||||
|
||||
if ((*crc) & 0x80000000) {
|
||||
hibit = 1;
|
||||
} else {
|
||||
hibit = 0;
|
||||
}
|
||||
|
||||
(*crc) <<= 1;
|
||||
(*crc) += val;
|
||||
(*crc) += hibit;
|
||||
|
||||
//cout << hex << (*crc) <<endl;
|
||||
}
|
||||
|
||||
|
||||
void Build_Packet_CRC(unsigned char *buf, int len)
|
||||
{
|
||||
if (len < 5)
|
||||
{
|
||||
DBGMSG("Ack! Constructing a packet too small to hold a CRC!");
|
||||
return;
|
||||
}
|
||||
if (!buf)
|
||||
{
|
||||
DBGMSG("Ack! Constructing a CRC for a void *");
|
||||
return;
|
||||
}
|
||||
|
||||
*((unsigned long *)buf) = 0;
|
||||
|
||||
unsigned long *crc_ptr = (unsigned long *)buf;
|
||||
unsigned char *packetptr = (unsigned char*) (buf+4);
|
||||
|
||||
len -= 4; // look past CRC
|
||||
|
||||
for (int i=0 ; i<len ; i++) {
|
||||
Add_CRC (crc_ptr, *packetptr++);
|
||||
}
|
||||
/*
|
||||
int leftover = len & 3;
|
||||
if (leftover) {
|
||||
unsigned long val = 0;
|
||||
unsigned char *c = (unsigned char *)packetptr;
|
||||
for (int i=0; i<leftover; i++)
|
||||
{
|
||||
val += (c[i] << (i*8));
|
||||
}
|
||||
val = htonl(val);
|
||||
Add_CRC (crc_ptr, val);
|
||||
}
|
||||
*/
|
||||
*crc_ptr = htonl(*crc_ptr);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Passes_CRC_Check -- Checks the CRC for a packet *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* INPUT: ptr to packet *
|
||||
* *
|
||||
* OUTPUT: true if packet passes CRC check *
|
||||
* *
|
||||
* WARNINGS: None *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 10/5/99 1:26PM ST : Created *
|
||||
* 1/9/2001 2:21PM MDC: Ripped from RA2 (WinsockInterfaceClass in wsproto.cpp/queue.cpp) *
|
||||
* 1/31/2001 4:30PM MDC: Converted to network-byte-order so Sparc boxes can talk with Intels. *
|
||||
* 2/1/2001 4:07PM MDC: Converted back to Intel order to avoid messing with C&C packets *
|
||||
*=============================================================================================*/
|
||||
bool Passes_CRC_Check(unsigned char *buf, int len)
|
||||
{
|
||||
if (len < 5)
|
||||
{
|
||||
DBGMSG("Recieved packet too small to contain a CRC");
|
||||
return false;
|
||||
}
|
||||
if (!buf)
|
||||
{
|
||||
DBGMSG("Ack! Checking a CRC for a void *");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned long crc = 0;
|
||||
|
||||
unsigned long *crc_ptr = &crc;
|
||||
unsigned char *packetptr = (unsigned char*) (buf+4);
|
||||
|
||||
len -= 4; // remove the CRC from packet size - just look at payload
|
||||
|
||||
for (int i=0 ; i<len ; i++) {
|
||||
Add_CRC (crc_ptr, *packetptr++);
|
||||
}
|
||||
/*
|
||||
int leftover = len & 3;
|
||||
if (leftover) {
|
||||
unsigned long val = 0;
|
||||
unsigned char *c = (unsigned char *)packetptr;
|
||||
for (int i=0; i<leftover; i++)
|
||||
{
|
||||
val += (c[i] << (i*8));
|
||||
}
|
||||
val = htonl(val);
|
||||
Add_CRC (crc_ptr, val);
|
||||
}
|
||||
*/
|
||||
crc = htonl(crc);
|
||||
|
||||
if (crc == *((unsigned long *)buf)) {
|
||||
return (true);
|
||||
}
|
||||
|
||||
DBGMSG("Invalid packet CRC");
|
||||
return (false);
|
||||
}
|
26
Generals/Code/Tools/mangler/crc.h
Normal file
26
Generals/Code/Tools/mangler/crc.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
** 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 __CRC_H__
|
||||
#define __CRC_H__
|
||||
|
||||
void Build_Packet_CRC(unsigned char *buf, int len); // len includes 4-byte CRC at head
|
||||
bool Passes_CRC_Check(unsigned char *buf, int len); // len includes 4-byte CRC at head
|
||||
void Add_CRC(unsigned long *crc, unsigned long val);
|
||||
|
||||
#endif // __CRC_H__
|
65
Generals/Code/Tools/mangler/endian.h
Normal file
65
Generals/Code/Tools/mangler/endian.h
Normal 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __ENDIAN_H__
|
||||
#define __ENDIAN_H__
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Network order is big-endian.
|
||||
**
|
||||
** Packet router and mangler order is big or little endian depending on server platform.
|
||||
**
|
||||
** Game client order is little endian.
|
||||
*/
|
||||
extern bool BigEndian;
|
||||
|
||||
template<class T> inline T Endian(T val)
|
||||
{
|
||||
if (!BigEndian) {
|
||||
return(val);
|
||||
}
|
||||
|
||||
/*
|
||||
char temp[sizeof(T)];
|
||||
*((T*)(&temp[0])) = val;
|
||||
*/
|
||||
|
||||
T retval = 0;
|
||||
|
||||
/*
|
||||
for (int i=0 ; i<sizeof(T) ; i++) {
|
||||
retval <<= 8;
|
||||
retval |= temp[i];
|
||||
}
|
||||
*/
|
||||
|
||||
int len = sizeof(T);
|
||||
unsigned char *c = (unsigned char *)(&val);
|
||||
for (int i=0; i<len; i++)
|
||||
{
|
||||
retval |= ( (*c++) << (8*i) );
|
||||
}
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
|
||||
#endif //__ENDIAN_H__
|
||||
|
208
Generals/Code/Tools/mangler/mangler.cpp
Normal file
208
Generals/Code/Tools/mangler/mangler.cpp
Normal file
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
** 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 <iostream.h>
|
||||
#include <signal.h>
|
||||
#ifdef _WINDOWS
|
||||
#include <process.h> // *MUST* be included before ANY Wnet/Wlib headers if _REENTRANT is defined
|
||||
#endif
|
||||
|
||||
#include "mangler.h"
|
||||
#include "crc.h"
|
||||
#include "endian.h"
|
||||
|
||||
#include <configfile.h>
|
||||
#include "threadfac.h"
|
||||
|
||||
#include "xtime.h"
|
||||
#include <filed.h>
|
||||
#include <wstring.h>
|
||||
#include <wdebug.h>
|
||||
#include <udp.h>
|
||||
|
||||
void DisplayHelp(const char *prog)
|
||||
{
|
||||
cout << "Usage: " << prog << " <config file>" << endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ConfigFile config;
|
||||
FILE* conf;
|
||||
|
||||
if( argc <= 1 )
|
||||
{
|
||||
// No args - use a default config file
|
||||
if ((conf = fopen("mangler.cfg", "r")) == NULL) {
|
||||
cout << "Cannot open mangler.cfg for reading." << endl;
|
||||
DisplayHelp(argv[0]);
|
||||
}
|
||||
config.readFile(conf);
|
||||
fclose(conf);
|
||||
}
|
||||
else if( argc == 2 && (strcmp(argv[1], "help") == 0 || strcmp(argv[1], "?") == 0 ||
|
||||
strcmp(argv[1], "-h") == 0) )
|
||||
DisplayHelp(argv[0]);
|
||||
else if( argc == 2 )
|
||||
{
|
||||
// Use a user-supplied config file
|
||||
if ((conf = fopen(argv[1], "r")) == NULL) {
|
||||
cout << "Cannot open " << argv[1] << " for reading." << endl;
|
||||
DisplayHelp(argv[0]);
|
||||
}
|
||||
config.readFile(conf);
|
||||
fclose(conf);
|
||||
}
|
||||
|
||||
// ----- LOGGING -----
|
||||
// Setup debugging & logging output
|
||||
Wstring output_file("mangler.log");
|
||||
config.getString("LOGFILE", output_file);
|
||||
Wstring backup_file;
|
||||
backup_file = output_file;
|
||||
backup_file += ".bak";
|
||||
rename(output_file.get(),backup_file.get()); // save the old file
|
||||
FileD output_device(output_file.get());
|
||||
MsgManager::setAllStreams(&output_device);
|
||||
DBGMSG("DBG working...");
|
||||
INFMSG("INF working...");
|
||||
WRNMSG("WRN working...");
|
||||
|
||||
if (htonl(0x12345678) == 0x12345678)
|
||||
{
|
||||
INFMSG("Host is network-byte-order");
|
||||
}
|
||||
else
|
||||
{
|
||||
INFMSG("Host is Intel-byte-order");
|
||||
}
|
||||
|
||||
|
||||
// ----- Initialize Winsock -----
|
||||
#ifdef _WINDOWS
|
||||
WORD verReq = MAKEWORD(2, 2);
|
||||
WSADATA wsadata;
|
||||
|
||||
int err = WSAStartup(verReq, &wsadata);
|
||||
if (err != 0) {
|
||||
ERRMSG("Winsock Init failed.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((LOBYTE(wsadata.wVersion) != 2) || (HIBYTE(wsadata.wVersion) !=2)) {
|
||||
ERRMSG("Winsock DLL is not 2.2");
|
||||
WSACleanup();
|
||||
ERRMSG("Winsock Init failed.");
|
||||
return 1;
|
||||
}
|
||||
INFMSG("Winsock Init done.");
|
||||
#endif
|
||||
|
||||
|
||||
// Set up a UDP listener
|
||||
uint8 *buff=new uint8[1024];
|
||||
int retval;
|
||||
UDP udp;
|
||||
UDP udp2;
|
||||
UDP udp3;
|
||||
UDP udp4;
|
||||
int port = 4321;
|
||||
config.getInt("PORT", port);
|
||||
uint8 blitz = 0;
|
||||
|
||||
uint32 localIP = 0;
|
||||
Wstring hostIPStr = "";
|
||||
config.getString("IP", hostIPStr);
|
||||
if (hostIPStr.length())
|
||||
{
|
||||
INFMSG("Binding to "<<hostIPStr.get()<<":"<<port<<"-"<<(port+3));
|
||||
localIP = ntohl(inet_addr(hostIPStr.get()));
|
||||
}
|
||||
else
|
||||
{
|
||||
INFMSG("Binding to localhost:"<<port<<"-"<<(port+3));
|
||||
}
|
||||
|
||||
retval = udp.Bind(localIP,(uint16)port);
|
||||
retval |= udp2.Bind(localIP,(uint16)port+1);
|
||||
retval |= udp3.Bind(localIP,(uint16)port+2);
|
||||
retval |= udp4.Bind(localIP,(uint16)port+3);
|
||||
if (retval != 0)
|
||||
{
|
||||
ERRMSG("Couldn't bind - error " << retval);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
unsigned char buf[1024];
|
||||
struct sockaddr_in addr;
|
||||
int packet_size = sizeof(ManglerData);
|
||||
INFMSG("sizeof(packet) == " << packet_size);
|
||||
unsigned char *theAddr;
|
||||
fd_set fdset;
|
||||
while (1)
|
||||
{
|
||||
retval = udp.Wait(15, 0, fdset);
|
||||
if (!retval)
|
||||
continue;
|
||||
|
||||
//DBGMSG("Wait returned " << retval);
|
||||
retval = udp.Read(buf, packet_size, &addr); // Wait until there is something on the socket
|
||||
if (retval > 0)
|
||||
{
|
||||
ManglerData *packet = (ManglerData *)buf;
|
||||
theAddr = (unsigned char *)&(addr.sin_addr.s_addr);
|
||||
if (retval != packet_size)
|
||||
{
|
||||
WRNMSG("Recieved mis-sized packet (" << retval << " bytes) from " << theAddr[0] << "." << theAddr[1] << "." << theAddr[2] << "." << theAddr[3] << ":" << addr.sin_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Passes_CRC_Check(buf, packet_size))
|
||||
{
|
||||
WRNMSG("Recieved a bad packet - good length!");
|
||||
continue;
|
||||
}
|
||||
packet->NetCommandType = 44;
|
||||
packet->MyMangledPortNumber = addr.sin_port; // not changing to host order, cause its in network byte order now, and the game will expect it to stay that way.
|
||||
packet->MyMangledAddress[0] = theAddr[0];
|
||||
packet->MyMangledAddress[1] = theAddr[1];
|
||||
packet->MyMangledAddress[2] = theAddr[2];
|
||||
packet->MyMangledAddress[3] = theAddr[3];
|
||||
blitz = packet->BlitzMe;
|
||||
INFMSG("Packet ID = " << packet->packetID);
|
||||
Build_Packet_CRC(buf, packet_size);
|
||||
udp.Write(buf,packet_size,ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port));
|
||||
INFMSG("Saw " << (int)theAddr[0] << "." << (int)theAddr[1] << "." << (int)theAddr[2] << "." << (int)theAddr[3] << ":" << ntohs(addr.sin_port) << ((blitz)?" Blitzed":"") );
|
||||
|
||||
if (blitz)
|
||||
{
|
||||
udp2.Write(buf,packet_size,ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port)+1);
|
||||
udp3.Write(buf,packet_size,ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port)+2);
|
||||
udp4.Write(buf,packet_size,ntohl(addr.sin_addr.s_addr), ntohs(addr.sin_port)+3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
326
Generals/Code/Tools/mangler/mangler.dsp
Normal file
326
Generals/Code/Tools/mangler/mangler.dsp
Normal file
|
@ -0,0 +1,326 @@
|
|||
# Microsoft Developer Studio Project File - Name="mangler" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
CFG=mangler - 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 "mangler.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 "mangler.mak" CFG="mangler - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "mangler - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "mangler - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName "mangler"
|
||||
# PROP Scc_LocalPath ".."
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "mangler - 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 "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /W3 /GX /O2 /I "wlib" /I "wnet" /I "." /D "_WINDOWS" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# 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 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:console /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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /machine:I386
|
||||
|
||||
!ELSEIF "$(CFG)" == "mangler - 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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "wlib" /I "wnet" /I "." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /D "DEBUG" /YX /FD /GZ /c
|
||||
# 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 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:console /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 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /debug /machine:I386
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "mangler - Win32 Release"
|
||||
# Name "mangler - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Group "wlib"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\configfile.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\critsec.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\Makefile
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\monod.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\sem4.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\streamer.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\syslogd.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\threadfac.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\timezone.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\wdebug.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\wstring.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\wtime.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\xtime.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "wnet"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wnet\field.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wnet\Makefile
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wnet\packet.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wnet\tcp.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wnet\udp.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\crc.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Makefile
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\mangler.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Group "wlib.H"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\arraylist.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\configfile.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\critsec.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\dictionary.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\filed.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\linkedlist.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\mboxd.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\monod.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\odevice.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\sem4.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\stderrd.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\stdoutd.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\streamer.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\syslogd.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\threadfac.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\threadsafe.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\timezone.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\ustring.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\wdebug.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\wstring.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\wstypes.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\wtime.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wlib\xtime.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "wnet.H"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wnet\field.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wnet\packet.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wnet\tcp.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=wnet\udp.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\crc.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\endian.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\mangler.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
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\mangler.cfg
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\mangler.log
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
49
Generals/Code/Tools/mangler/mangler.dsw
Normal file
49
Generals/Code/Tools/mangler/mangler.dsw
Normal file
|
@ -0,0 +1,49 @@
|
|||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "mangler"=.\mangler.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
begin source code control
|
||||
mangler
|
||||
..
|
||||
end source code control
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "manglertest"=.\manglertest.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
begin source code control
|
||||
manglertest
|
||||
..
|
||||
end source code control
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
79
Generals/Code/Tools/mangler/mangler.h
Normal file
79
Generals/Code/Tools/mangler/mangler.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
** 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 __MANGLER_H__
|
||||
#define __MANGLER_H__
|
||||
|
||||
// Packet should consist of a GlobalHeaderType followed by a GlobalPacketType with the fields set as
|
||||
// indicated.
|
||||
|
||||
|
||||
/*
|
||||
********************************** Defines **********************************
|
||||
*/
|
||||
|
||||
// This is the number of additional ports to which to reply.
|
||||
#define BLITZ_SIZE 3
|
||||
|
||||
#define MPLAYER_NAME_MAX 20
|
||||
#define SERIAL_MAX 23
|
||||
typedef unsigned char ForwardMaskType;
|
||||
typedef enum NetCommandType {
|
||||
NET_MANGLER_REQUEST = 43,
|
||||
NET_MANGLER_RESPONSE = 44
|
||||
} NetCommandType;
|
||||
|
||||
/*
|
||||
** One byte alignment.
|
||||
*/
|
||||
#if !defined(__GNUC__)
|
||||
#pragma pack(push, 1)
|
||||
#define PACK
|
||||
#else
|
||||
#define PACK __attribute__ ((__packed__))
|
||||
#endif
|
||||
|
||||
// size = 20 bytes
|
||||
struct ManglerData {
|
||||
unsigned int CRC PACK;
|
||||
unsigned short magic PACK;
|
||||
unsigned short packetID PACK;
|
||||
unsigned short MyMangledPortNumber PACK;
|
||||
unsigned short OriginalPortNumber PACK;
|
||||
unsigned char MyMangledAddress[4] PACK;
|
||||
unsigned char NetCommandType PACK;
|
||||
unsigned char BlitzMe PACK;
|
||||
unsigned short Padding PACK;
|
||||
};
|
||||
|
||||
/*
|
||||
This is for older GCC versions that can't do byte-packing.
|
||||
Instead of declaring
|
||||
GlobalPacketType p;
|
||||
p.Command = NET_MANGLER_REQUEST;
|
||||
you would do something like this:
|
||||
GlobalPacketStruct p;
|
||||
Eval(&p, GPCommand, NetCommandType) = NET_MANGLER_REQUEST;
|
||||
*/
|
||||
#define Eval(x, y, z) ( *((z *)(&((x)->payload[(y)]))) )
|
||||
|
||||
#if !defined(__GNUC__)
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
#endif // __MANGLER_H__
|
245
Generals/Code/Tools/mangler/manglertest.cpp
Normal file
245
Generals/Code/Tools/mangler/manglertest.cpp
Normal file
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
** 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 <iostream.h>
|
||||
#include <signal.h>
|
||||
#ifdef _WINDOWS
|
||||
#include <process.h> // *MUST* be included before ANY Wnet/Wlib headers if _REENTRANT is defined
|
||||
#endif
|
||||
|
||||
#include "mangler.h"
|
||||
#include "crc.h"
|
||||
|
||||
#include <configfile.h>
|
||||
#include "threadfac.h"
|
||||
|
||||
#include "endian.h"
|
||||
|
||||
#include "xtime.h"
|
||||
#include <filed.h>
|
||||
#include <wstring.h>
|
||||
#include <wdebug.h>
|
||||
#include <udp.h>
|
||||
|
||||
// ST - 2/1/01 12:46PM
|
||||
bool BigEndian = false;
|
||||
|
||||
unsigned long ResolveIP(char *Server)
|
||||
{
|
||||
char serverName[100];
|
||||
struct hostent *serverStruct;
|
||||
struct in_addr *serverNode;
|
||||
|
||||
if (Server == NULL)
|
||||
{
|
||||
ERRMSG("Can't resolve NULL");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isdigit(Server[0]))
|
||||
return ( ntohl(inet_addr(Server)) );
|
||||
|
||||
strcpy(serverName, Server);
|
||||
|
||||
serverStruct = gethostbyname(Server);
|
||||
if (serverStruct == NULL)
|
||||
{
|
||||
ERRMSG("Can't resolve " << Server);
|
||||
return 0;
|
||||
}
|
||||
serverNode = (struct in_addr *) serverStruct->h_addr;
|
||||
return ( ntohl(serverNode->s_addr) );
|
||||
}
|
||||
|
||||
void DisplayHelp(const char *prog)
|
||||
{
|
||||
cout << "Usage: " << prog << " <config file>" << endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ConfigFile config;
|
||||
FILE* conf;
|
||||
|
||||
if( argc <= 1 )
|
||||
{
|
||||
// No args - use a default config file
|
||||
if ((conf = fopen("manglertest.cfg", "r")) == NULL) {
|
||||
cout << "Cannot open mangler.cfg for reading." << endl;
|
||||
DisplayHelp(argv[0]);
|
||||
}
|
||||
config.readFile(conf);
|
||||
fclose(conf);
|
||||
}
|
||||
else if( argc == 2 && (strcmp(argv[1], "help") == 0 || strcmp(argv[1], "?") == 0 ||
|
||||
strcmp(argv[1], "-h") == 0) )
|
||||
DisplayHelp(argv[0]);
|
||||
else if( argc == 2 )
|
||||
{
|
||||
// Use a user-supplied config file
|
||||
if ((conf = fopen(argv[1], "r")) == NULL) {
|
||||
cout << "Cannot open " << argv[1] << " for reading." << endl;
|
||||
DisplayHelp(argv[0]);
|
||||
}
|
||||
config.readFile(conf);
|
||||
fclose(conf);
|
||||
}
|
||||
|
||||
// ----- LOGGING -----
|
||||
// Setup debugging & logging output
|
||||
Wstring output_file("manglertest.log");
|
||||
config.getString("LOGFILE", output_file);
|
||||
Wstring backup_file;
|
||||
backup_file = output_file;
|
||||
backup_file += ".bak";
|
||||
rename(output_file.get(),backup_file.get()); // save the old file
|
||||
FileD output_device(output_file.get());
|
||||
MsgManager::setAllStreams(&output_device);
|
||||
DBGMSG("DBG working...");
|
||||
INFMSG("INF working...");
|
||||
WRNMSG("WRN working...");
|
||||
|
||||
|
||||
//
|
||||
// See if our processor is big or little endian. Network order is big endian.
|
||||
// ST - 2/1/01 12:11PM
|
||||
//
|
||||
if (htonl(0x12345678) == 0x12345678) {
|
||||
BigEndian = true;
|
||||
}
|
||||
|
||||
|
||||
// ----- Initialize Winsock -----
|
||||
#ifdef _WINDOWS
|
||||
WORD verReq = MAKEWORD(2, 2);
|
||||
WSADATA wsadata;
|
||||
|
||||
int err = WSAStartup(verReq, &wsadata);
|
||||
if (err != 0) {
|
||||
ERRMSG("Winsock Init failed.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((LOBYTE(wsadata.wVersion) != 2) || (HIBYTE(wsadata.wVersion) !=2)) {
|
||||
ERRMSG("Winsock DLL is not 2.2");
|
||||
WSACleanup();
|
||||
ERRMSG("Winsock Init failed.");
|
||||
return 1;
|
||||
}
|
||||
INFMSG("Winsock Init done.");
|
||||
#endif
|
||||
|
||||
|
||||
// Set up a UDP listener
|
||||
uint8 *buff=new uint8[1024];
|
||||
int retval;
|
||||
UDP udp;
|
||||
int port = 4321;
|
||||
config.getInt("MANGLERPORT", port);
|
||||
|
||||
int localport = 4444;
|
||||
config.getInt("CLIENTPORT", localport);
|
||||
retval = udp.Bind((uint32)0,(uint16)localport);
|
||||
DBGMSG("Bind returned " << retval);
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
const int packet_size = sizeof(ManglerData);
|
||||
INFMSG("sizeof(packet) == " << packet_size);
|
||||
|
||||
unsigned char buf[packet_size];
|
||||
memset(buf, 0x44, packet_size); // init to something known for memory dumps :)
|
||||
struct sockaddr_in addr;
|
||||
|
||||
int doBlitz = 0;
|
||||
config.getInt("BLITZ", doBlitz);
|
||||
if (doBlitz)
|
||||
{
|
||||
INFMSG("Requsting port blitz");
|
||||
}
|
||||
|
||||
unsigned char *theAddr;
|
||||
fd_set fdset;
|
||||
unsigned long server_addr;
|
||||
Wstring manglername = "localhost";
|
||||
config.getString("MANGLERIP", manglername);
|
||||
server_addr = ResolveIP(manglername.get());
|
||||
if (!server_addr)
|
||||
{
|
||||
ERRMSG("Cannot resolve mangler server IP");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ManglerData *packet = (ManglerData *)buf;
|
||||
packet->NetCommandType = 12;
|
||||
packet->packetID = 9999;
|
||||
packet->BlitzMe = doBlitz;
|
||||
packet->magic = htons((unsigned short)0xf00d);
|
||||
Build_Packet_CRC(buf, packet_size);
|
||||
DBGMSG("Writing to " << manglername.get() << ":" << port);
|
||||
udp.Write(buf,packet_size,server_addr, 4321);
|
||||
|
||||
retval = udp.Wait(5, 0, fdset);
|
||||
if (retval)
|
||||
{
|
||||
DBGMSG("Wait returned " << retval);
|
||||
retval = udp.Read(buf, packet_size, &addr); // Wait until there is something on the socket
|
||||
if (retval > 0)
|
||||
{
|
||||
theAddr = (unsigned char *)&(addr.sin_addr.s_addr);
|
||||
if (retval != packet_size)
|
||||
{
|
||||
WRNMSG("Recieved mis-sized packet (" << retval << " bytes) from " << theAddr[0] << "." << theAddr[1] << "." << theAddr[2] << "." << theAddr[3] << ":" << addr.sin_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
int packetCommand;
|
||||
packetCommand = packet->NetCommandType;
|
||||
if (!Passes_CRC_Check(buf, packet_size))
|
||||
{
|
||||
WRNMSG("CRC error!");
|
||||
}
|
||||
else if (packetCommand != 13)
|
||||
{
|
||||
WRNMSG("Returned packet had command type " << packetCommand);
|
||||
}
|
||||
else
|
||||
{
|
||||
int addr[4];
|
||||
unsigned short retPort;
|
||||
retPort = htons(packet->MyMangledPortNumber);
|
||||
addr[0] = packet->MyMangledAddress[0];
|
||||
addr[1] = packet->MyMangledAddress[1];
|
||||
addr[2] = packet->MyMangledAddress[2];
|
||||
addr[3] = packet->MyMangledAddress[3];
|
||||
DBGMSG("Saw " << addr[0] << "." << addr[1] << "." << addr[2] << "." << addr[3] << ":" << retPort);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DBGMSG("Wait timed out");
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
318
Generals/Code/Tools/mangler/manglertest.dsp
Normal file
318
Generals/Code/Tools/mangler/manglertest.dsp
Normal file
|
@ -0,0 +1,318 @@
|
|||
# Microsoft Developer Studio Project File - Name="manglertest" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
CFG=manglertest - 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 "manglertest.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 "manglertest.mak" CFG="manglertest - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "manglertest - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "manglertest - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName "manglertest"
|
||||
# PROP Scc_LocalPath ".."
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "manglertest - 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 "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /W3 /GX /O2 /I "wlib" /I "wnet" /I "." /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WINDOWS" /YX /FD /c
|
||||
# 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 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:console /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 wsock32.lib /nologo /subsystem:console /machine:I386
|
||||
|
||||
!ELSEIF "$(CFG)" == "manglertest - 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 "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I ".." /I "wlib" /I "wnet" /I "." /D "_DEBUG" /D "_WINDOWS" /D "DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# 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 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:console /debug /machine:I386
|
||||
# ADD LINK32 wsock32.lib 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:console /debug /machine:I386
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "manglertest - Win32 Release"
|
||||
# Name "manglertest - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Group "wnet"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wnet\field.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wnet\Makefile
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wnet\packet.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wnet\tcp.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wnet\udp.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "wlib"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\configfile.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\critsec.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\Makefile
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\monod.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\sem4.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\streamer.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\syslogd.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\threadfac.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\timezone.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\wdebug.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\wstring.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\wtime.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\xtime.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\crc.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\manglertest.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Group "wnet.H"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wnet\field.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wnet\packet.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wnet\tcp.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wnet\udp.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "wlib.H"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\arraylist.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\configfile.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\critsec.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\dictionary.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\filed.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\linkedlist.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\mboxd.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\monod.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\odevice.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\sem4.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\stderrd.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\stdoutd.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\streamer.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\syslogd.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\threadfac.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\threadsafe.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\timezone.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\ustring.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\wdebug.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\wstring.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\wstypes.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\wtime.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wlib\xtime.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\crc.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\endian.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
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\manglertest.cfg
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\manglertest.log
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
41
Generals/Code/Tools/mangler/wlib/Makefile
Normal file
41
Generals/Code/Tools/mangler/wlib/Makefile
Normal file
|
@ -0,0 +1,41 @@
|
|||
###########################################################################
|
||||
# WLIB library makefile
|
||||
##########################################################################
|
||||
|
||||
#Define cc to be your C compiler
|
||||
CC = g++
|
||||
|
||||
#This tells make how to go from a .cpp to a .o
|
||||
.SUFFIXES: .cpp
|
||||
.cpp.o:
|
||||
${CC} ${CFLAGS} -c $<
|
||||
|
||||
INCLUDE = -I. -I..
|
||||
|
||||
CFLAGS = ${INCLUDE} -D_REENTRANT -DDEBUG -D_UNIX
|
||||
|
||||
AR = ar -r
|
||||
#CC is dumb and won't include templates in a library uness you define
|
||||
#CC -xar as your replacement for 'ar'
|
||||
#AR = CC -xar
|
||||
|
||||
RM = rm -f
|
||||
RANLIB = ranlib
|
||||
|
||||
############################################################################
|
||||
#Dont mess with any of this stuff
|
||||
OBJECTS = wtime.o monod.o wdebug.o sem4.o streamer.o syslogd.o wstring.o \
|
||||
configfile.o threadfac.o critsec.o xtime.o timezone.o
|
||||
|
||||
LIBRARY = libwlib.a
|
||||
|
||||
all: $(LIBRARY)
|
||||
|
||||
$(LIBRARY): $(OBJECTS)
|
||||
${RM} libwlib.a
|
||||
${AR} libwlib.a $(OBJECTS)
|
||||
#${AR} $(OBJECTS) -o libwlib.a
|
||||
$(RANLIB) libwlib.a
|
||||
|
||||
clean:
|
||||
- rm -f $(LIBRARY) *.o core
|
709
Generals/Code/Tools/mangler/wlib/arraylist.h
Normal file
709
Generals/Code/Tools/mangler/wlib/arraylist.h
Normal file
|
@ -0,0 +1,709 @@
|
|||
/*
|
||||
** 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 : arraylist.h
|
||||
Author : Neal Kettler
|
||||
Start Date : Jan 19, 1997
|
||||
Last Update : Jan 19, 1997
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Array implementation of a list. Note: There are some freaky C++ memory tricks
|
||||
going on here. If you think there's a leak, see me before changing it.
|
||||
The way this works is that it allocates an array to hold 'N' items on the
|
||||
first list add. It doesn't call the constructors for those 'N' items until
|
||||
necessary (for efficiency). When an item is added to a slot then a new
|
||||
class is constructed inside the array element using the placement new operator
|
||||
and the class's copy constructor. When elements are removed the destructor
|
||||
is then manually called on this memory location.
|
||||
|
||||
All data added to the list is copied so feel free to delete/destroy/modify
|
||||
the original after an add.
|
||||
|
||||
You _must_ have a good copy constructor for any classes that you use this template
|
||||
for! A good copy constructor is one that won't blindly duplicate pointers
|
||||
that don't belong to them, etc...
|
||||
|
||||
\****************************************************************************/
|
||||
|
||||
#ifndef ARRAYLIST_HEADER
|
||||
#define ARRAYLIST_HEADER
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <new.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "wstypes.h"
|
||||
|
||||
//
|
||||
// Usage: ArrayList<int> TheList;
|
||||
//
|
||||
template <class T>
|
||||
class ArrayList
|
||||
{
|
||||
public:
|
||||
ArrayList();
|
||||
ArrayList(ArrayList<T> &other);
|
||||
~ArrayList();
|
||||
|
||||
// Remove all entries from the lsit
|
||||
void clear(void);
|
||||
|
||||
// Add a node after the zero based 'pos'
|
||||
bit8 add(IN T &node,sint32 pos);
|
||||
bit8 addTail(IN T &node);
|
||||
bit8 addHead(IN T &node);
|
||||
bit8 addSortedAsc(IN T &node); // Ascending
|
||||
bit8 addSortedDes(IN T &node); // Descending
|
||||
/*bit8 addNumSortedAsc(IN T &node); // Ascending
|
||||
bit8 addNumSortedDes(IN T &node); // Descending*/
|
||||
|
||||
// Remove a node
|
||||
bit8 remove(OUT T &node,sint32 pos);
|
||||
bit8 remove(sint32 pos);
|
||||
bit8 removeHead(OUT T &node);
|
||||
bit8 removeTail(OUT T &node);
|
||||
|
||||
// Replace one obj with another
|
||||
bit8 replace(IN T &node, sint32 pos);
|
||||
|
||||
|
||||
// Get a node without removing from the list
|
||||
bit8 get(OUT T &node,sint32 pos) RO;
|
||||
bit8 getHead(OUT T &node) RO;
|
||||
bit8 getTail(OUT T &node) RO;
|
||||
|
||||
// Get a pointer to the interally managed copy (careful!)
|
||||
bit8 getPointer(OUT T **node,sint32 pos) RO;
|
||||
|
||||
// Get the number of entries in the list
|
||||
sint32 length(void) RO;
|
||||
|
||||
// UNSAFE! for classes, see note below!
|
||||
bit8 setSize(sint32 newsize, IN T &filler);
|
||||
|
||||
// Print information on the list
|
||||
void print(FILE *out);
|
||||
|
||||
// assignment operator
|
||||
ArrayList<T> &operator=(IN ArrayList<T> &other);
|
||||
|
||||
private:
|
||||
sint32 _sortedLookup(IN T &target, int ascending);
|
||||
sint32 Entries_; // Number of entries
|
||||
sint32 Slots_; // Number of available slots
|
||||
|
||||
T *Vector_; // The actual memory where the list is held
|
||||
|
||||
enum
|
||||
{
|
||||
INITIAL_SIZE = 10
|
||||
};
|
||||
|
||||
bit8 growVector(void); // Expand the number of slots
|
||||
bit8 shrinkVector(void); // Reduce the number of slots
|
||||
};
|
||||
|
||||
|
||||
//Create the empty list
|
||||
template <class T>
|
||||
ArrayList<T>::ArrayList()
|
||||
{
|
||||
Entries_=0;
|
||||
Slots_=0;
|
||||
Vector_=NULL;
|
||||
}
|
||||
|
||||
// copy constructor
|
||||
template <class T>
|
||||
ArrayList<T>::ArrayList(ArrayList<T> &other)
|
||||
{
|
||||
Entries_=0;
|
||||
Slots_=0;
|
||||
Vector_=NULL;
|
||||
(*this)=other;
|
||||
}
|
||||
|
||||
//Free all the memory...
|
||||
template <class T>
|
||||
ArrayList<T>::~ArrayList()
|
||||
{
|
||||
clear(); // Remove the entries & call destructors on them
|
||||
|
||||
delete[]((uint8*)Vector_); // this will prevent the destructors from
|
||||
// gettting called on elements not
|
||||
// containing valid objects.
|
||||
|
||||
//fprintf(stderr,"Arraylist destructor\n");
|
||||
}
|
||||
|
||||
// assignment operator
|
||||
template <class T>
|
||||
ArrayList<T> &ArrayList<T>::operator=(IN ArrayList<T> &other)
|
||||
{
|
||||
T node;
|
||||
clear();
|
||||
for (int i=0; i<other.length(); i++)
|
||||
{
|
||||
other.get(node,i);
|
||||
addTail(node);
|
||||
}
|
||||
return(*this);
|
||||
}
|
||||
|
||||
|
||||
// Remove all the entries and free the memory
|
||||
template <class T>
|
||||
void ArrayList<T>::clear()
|
||||
{
|
||||
for (int i=0; i<Entries_; i++)
|
||||
{
|
||||
(Vector_+i)->~T(); // Call the destructor manually. Don't try this
|
||||
// at home kiddies!
|
||||
}
|
||||
Entries_=0;
|
||||
}
|
||||
|
||||
// ************************* UNSAFE UNSAFE UNSAFE *************************
|
||||
// Note - Don't call this on any type with a constructor/destructor since this
|
||||
// is really dumb and just puts a new one of filler in. Well, it's kindof safe
|
||||
// just be careful.
|
||||
// It's fine for simple classes like ints though..
|
||||
//
|
||||
// Add/remove entries in a stupid manner...
|
||||
//
|
||||
// **************************************************************************
|
||||
template <class T>
|
||||
bit8 ArrayList<T>::setSize(sint32 newsize, IN T &filler)
|
||||
{
|
||||
int oldEntries=Entries_;
|
||||
Entries_ = newsize;
|
||||
|
||||
if (newsize<0)
|
||||
return(false);
|
||||
|
||||
// Grow the vector as much as we need to
|
||||
while (newsize > Slots_)
|
||||
growVector();
|
||||
|
||||
// Create new objects in the blank holes
|
||||
for (int i=oldEntries; i<Entries_; i++)
|
||||
{
|
||||
// Now put the replacement object in there...
|
||||
new((void *)(Vector_+i)) T(filler); // Trust me, this isn't a memory leak
|
||||
}
|
||||
|
||||
// If we're at 33% usage or less, shrink the vector
|
||||
if ((Entries_*3) <= Slots_) // don't do while, because I think shrink will never goto 0
|
||||
shrinkVector();
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
// When adding into a position, the new node goes at the zero based slot
|
||||
// specified by pos. All other nodes get moved one slot down.
|
||||
template <class T>
|
||||
bit8 ArrayList<T>::add(IN T &node,sint32 pos)
|
||||
{
|
||||
if (pos > Entries_) // You can only access one of the end of the vector
|
||||
pos=Entries_;
|
||||
if (pos >= Slots_) // If we're at the end, grow the list
|
||||
growVector();
|
||||
if (Entries_ >= Slots_) // enuff space?
|
||||
growVector();
|
||||
|
||||
// If we are insering into the middle or front of the list we have to
|
||||
// slide the old objects forward.
|
||||
if (pos < Entries_) // If there are elements after the add point
|
||||
memmove(Vector_+pos+1,Vector_+pos,sizeof(T)*(Entries_-pos)); // move them forward
|
||||
|
||||
//fprintf(stderr,"Placement new to %p\n",(Vector_+pos));
|
||||
|
||||
// This uses the placement new operator. placement new allows us to
|
||||
// specify the memory address for the new object. In this case we
|
||||
// want it at the 'pos' index into our array.
|
||||
new((void *)(Vector_+pos)) T((T &)node); // Trust me, this isn't a memory leak
|
||||
Entries_++; // one new entry
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// Add to the first node, all others get shifted down one slot
|
||||
template <class T>
|
||||
bit8 ArrayList<T>::addHead(IN T &node)
|
||||
{
|
||||
return(add(node,0));
|
||||
}
|
||||
|
||||
|
||||
// Append to the end of the list
|
||||
template <class T>
|
||||
bit8 ArrayList<T>::addTail(IN T &node)
|
||||
{
|
||||
return(add(node,length()));
|
||||
}
|
||||
|
||||
|
||||
// addSortedX only works (properly) if evrerything else in the list is added
|
||||
// using addSorted.
|
||||
template <class T>
|
||||
bit8 ArrayList<T>::addSortedAsc(IN T &node)
|
||||
{
|
||||
sint32 pos = _sortedLookup(node, 1);
|
||||
return(add(node, pos));
|
||||
}
|
||||
|
||||
|
||||
// addSortedX only works (properly) if evrerything else in the list is added
|
||||
// using addSorted.
|
||||
template <class T>
|
||||
bit8 ArrayList<T>::addSortedDes(IN T &node)
|
||||
{
|
||||
sint32 pos = _sortedLookup(node, 0);
|
||||
return(add(node, pos));
|
||||
}
|
||||
|
||||
|
||||
// This is the binary search used by addSorted
|
||||
template <class T>
|
||||
sint32 ArrayList<T>::_sortedLookup(IN T &target, int ascending)
|
||||
{
|
||||
int low, mid, high;
|
||||
T* lowtarget;
|
||||
T* hightarget;
|
||||
T* midtarget;
|
||||
|
||||
|
||||
// Trivial cases
|
||||
if( Entries_ == 0 )
|
||||
return 0;
|
||||
|
||||
low = 0;
|
||||
high = Entries_ - 1;
|
||||
while( 1 )
|
||||
{
|
||||
assert( low <= high );
|
||||
mid = low + (int)(floor(((double)high - (double)low) / (double)2));
|
||||
|
||||
getPointer(&lowtarget, low);
|
||||
getPointer(&hightarget, high);
|
||||
getPointer(&midtarget, mid);
|
||||
|
||||
// Exact match
|
||||
if( *midtarget == target ) return mid;
|
||||
|
||||
// Single element
|
||||
if( high == low )
|
||||
{
|
||||
if( ascending )
|
||||
{
|
||||
if( target <= *lowtarget )
|
||||
return low;
|
||||
else
|
||||
return low + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( target <= *lowtarget )
|
||||
return low + 1;
|
||||
else
|
||||
return low;
|
||||
}
|
||||
}
|
||||
|
||||
// Two elemsnts
|
||||
if( (high - low) == 1 )
|
||||
{
|
||||
if( ascending )
|
||||
{
|
||||
if( target <= *lowtarget )
|
||||
return low;
|
||||
else if( target <= *hightarget )
|
||||
return high;
|
||||
else
|
||||
return high + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( target <= *hightarget )
|
||||
return high + 1;
|
||||
else if( target <= *lowtarget )
|
||||
return high;
|
||||
else
|
||||
return low;
|
||||
}
|
||||
}
|
||||
|
||||
// Sorry, try again...
|
||||
if( ascending )
|
||||
{
|
||||
if( target < *midtarget )
|
||||
high = mid;
|
||||
else
|
||||
low = mid;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( target < *midtarget )
|
||||
low = mid;
|
||||
else
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*// addNumSortedX works in much the same way as addSortedX, except that I needed
|
||||
// it for a very specific thing. I needed a list of strings numerically sorted,
|
||||
// not alphabetically sorted. Furthermore these strings were composed of numbers
|
||||
// delimited by underscores. In the interest of keeping it generic, these
|
||||
// functions take as args a node, a delimiting character, and a count of the
|
||||
// number of fields to include in a sort. If this is the list of strings:
|
||||
//
|
||||
// 55_100, 2_5, 23_32, 98_445, 2_48, 8_88, 2_3, 2_4
|
||||
//
|
||||
// An alphabetical sort is:
|
||||
//
|
||||
// 2_3, 2_4, 2_48, 2_5, 55_100, 8_88, 98_445
|
||||
//
|
||||
// But a numerical sort by calling addNumSortedAsc(<whatever>, "_", 2) will result in:
|
||||
//
|
||||
// 2_3, 2_4, 2_5, 2_48, 8_88, 55_100, 98_445
|
||||
//
|
||||
// Yes...now that you mention it I am on crack...
|
||||
//
|
||||
template <class T>
|
||||
bit8 ArrayList<T>::addNumSortedAsc(IN T &node, char delim, int fields)
|
||||
{
|
||||
sint32 pos = _numSortedLookup(node, delim, fields, 1);
|
||||
return(add(node, pos));
|
||||
}
|
||||
|
||||
|
||||
// See addNumSortedAsc comment above.
|
||||
template <class T>
|
||||
bit8 ArrayList<T>::addSortedDes(IN T &node, char delim, int fields)
|
||||
{
|
||||
sint32 pos = _sortedLookup(node, delim, fields, 0);
|
||||
return(add(node, pos));
|
||||
}
|
||||
|
||||
|
||||
// This is the binary search used by addSorted
|
||||
template <class T>
|
||||
sint32 ArrayList<T>::_numSortedLookup(IN T &target, char delim, int fields, int ascending)
|
||||
{
|
||||
int low, mid, high;
|
||||
T* lowtarget;
|
||||
T* hightarget;
|
||||
T* midtarget;
|
||||
|
||||
|
||||
// Trivial case
|
||||
if( Entries_ == 0 )
|
||||
return 0;
|
||||
|
||||
low = 0;
|
||||
high = Entries_;
|
||||
while( 1 )
|
||||
{
|
||||
assert( low <= high );
|
||||
mid = low + (int)(floor(((double)high - (double)low) / (double)2));
|
||||
|
||||
getPointer(&lowtarget, low);
|
||||
getPointer(&hightarget, high);
|
||||
getPointer(&midtarget, mid);
|
||||
|
||||
// Exact match
|
||||
if( *midtarget == target ) return mid;
|
||||
|
||||
// Single element
|
||||
if( high == low )
|
||||
{
|
||||
if( ascending )
|
||||
{
|
||||
if( target <= *lowtarget )
|
||||
return low;
|
||||
else
|
||||
return low + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( target <= *lowtarget )
|
||||
return low + 1;
|
||||
else
|
||||
return low;
|
||||
}
|
||||
}
|
||||
|
||||
// Two elemsnts
|
||||
if( (high - low) == 1 )
|
||||
{
|
||||
if( ascending )
|
||||
{
|
||||
if( target <= *lowtarget )
|
||||
return low;
|
||||
else
|
||||
return high;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( target <= *lowtarget )
|
||||
return high;
|
||||
else
|
||||
return low;
|
||||
}
|
||||
}
|
||||
|
||||
// Sorry, try again...
|
||||
if( ascending )
|
||||
{
|
||||
if( target < *midtarget )
|
||||
high = mid;
|
||||
else
|
||||
low = mid;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( target < *midtarget )
|
||||
low = mid;
|
||||
else
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
//
|
||||
// Delete an item at this index and construct a new one in it's place
|
||||
//
|
||||
template <class T>
|
||||
bit8 ArrayList<T>::replace(IN T &node, sint32 pos)
|
||||
{
|
||||
if (Entries_==0)
|
||||
return(FALSE);
|
||||
if (pos<0)
|
||||
pos=0;
|
||||
if (pos >= Entries_)
|
||||
pos=Entries_-1;
|
||||
|
||||
(Vector_+pos)->~T(); // Call the destructor manually. Don't try this
|
||||
// at home kiddies!
|
||||
|
||||
// Now put the replacement object in there...
|
||||
new((void *)(Vector_+pos)) T(node); // Trust me, this isn't a memory leak
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Remove at the zero based index specified by 'pos'. When removing from
|
||||
// a slot, all others get shifted up by one.
|
||||
template <class T>
|
||||
bit8 ArrayList<T>::remove(sint32 pos)
|
||||
{
|
||||
if (Entries_==0)
|
||||
return(FALSE);
|
||||
if (pos<0)
|
||||
pos=0;
|
||||
if (pos >= Entries_)
|
||||
pos=Entries_-1;
|
||||
|
||||
(Vector_+pos)->~T(); // Call the destructor manually. Don't try this
|
||||
// at home kiddies!
|
||||
|
||||
memmove(Vector_+pos,Vector_+pos+1,sizeof(T)*(Entries_-pos-1));
|
||||
|
||||
Entries_--;
|
||||
|
||||
// If we're at 33% usage or less, shrink the vector
|
||||
if ( (Entries_*3) <= Slots_)
|
||||
shrinkVector();
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// Remove at the zero based index specified by 'pos'. When removing from
|
||||
// a slot, all others get shifted up by one.
|
||||
template <class T>
|
||||
bit8 ArrayList<T>::remove(OUT T &node, sint32 pos)
|
||||
{
|
||||
bit8 retval;
|
||||
retval=get(node,pos);
|
||||
if (retval==FALSE)
|
||||
return(FALSE);
|
||||
return(remove(pos));
|
||||
}
|
||||
|
||||
|
||||
// Remove the first node of the list
|
||||
template <class T>
|
||||
bit8 ArrayList<T>::removeHead(OUT T &node)
|
||||
{
|
||||
return(remove(node,0));
|
||||
}
|
||||
|
||||
|
||||
// Remove the last node of the list
|
||||
template <class T>
|
||||
bit8 ArrayList<T>::removeTail(OUT T &node)
|
||||
{
|
||||
return(remove(node,Entries_-1));
|
||||
}
|
||||
|
||||
// get a pointer to the internally managed object. Try and avoid this, but
|
||||
// sometimes efficiency requires it...
|
||||
// get a copy of an item
|
||||
template <class T>
|
||||
bit8 ArrayList<T>::getPointer(OUT T **node,sint32 pos) RO
|
||||
{
|
||||
if ((pos < 0)||(pos >= Entries_))
|
||||
return(FALSE);
|
||||
*node=&(Vector_[pos]);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// get a copy of an item
|
||||
template <class T>
|
||||
bit8 ArrayList<T>::get(OUT T &node,sint32 pos) RO
|
||||
{
|
||||
if ((pos < 0)||(pos >= Entries_))
|
||||
return(FALSE);
|
||||
node=Vector_[pos];
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// get a copy of the first node of the list
|
||||
template <class T>
|
||||
bit8 ArrayList<T>::getHead(OUT T &node) RO
|
||||
{
|
||||
return(get(node,0));
|
||||
}
|
||||
|
||||
|
||||
// get a copy of the last node
|
||||
template <class T>
|
||||
bit8 ArrayList<T>::getTail(OUT T &node) RO
|
||||
{
|
||||
return(get(node,Entries_-1));
|
||||
}
|
||||
|
||||
// just for debugging
|
||||
template <class T>
|
||||
void ArrayList<T>::print(FILE *out)
|
||||
{
|
||||
fprintf(out,"--------------------\n");
|
||||
//for (int i=0; i<Entries_; i++)
|
||||
// Vector_[i].print();
|
||||
fprintf(out,"Entries: %d Slots: %d sizeof(T): %d\n",Entries_,Slots_,
|
||||
sizeof(T));
|
||||
fprintf(out,"--------------------\n");
|
||||
}
|
||||
|
||||
// Return the current length of the list
|
||||
template <class T>
|
||||
sint32 ArrayList<T>::length(void) RO
|
||||
{
|
||||
return(Entries_);
|
||||
}
|
||||
|
||||
// Grow the vector by a factor of 2X
|
||||
template <class T>
|
||||
bit8 ArrayList<T>::growVector(void)
|
||||
{
|
||||
if (Entries_ < Slots_) // Don't grow until we're at 100% usage
|
||||
return(FALSE);
|
||||
|
||||
int newSlots=Entries_*2;
|
||||
if(newSlots < INITIAL_SIZE)
|
||||
newSlots=INITIAL_SIZE;
|
||||
|
||||
//fprintf(stderr,"Growing vector to: %d\n",newSlots);
|
||||
|
||||
// The goofy looking new below prevents operator new from getting called
|
||||
// unnecessarily. This is severall times faster than allocating all of
|
||||
// the slots as objects and then calling the assignment operator on them
|
||||
// when they actually get used.
|
||||
//
|
||||
T *newVector=(T *)(new uint8[newSlots * sizeof(T)]);
|
||||
memset(newVector,0,newSlots * sizeof(T)); // zero just to be safe
|
||||
|
||||
if (Vector_ != NULL)
|
||||
memcpy(newVector,Vector_,Entries_*sizeof(T));
|
||||
|
||||
delete[]((uint8 *)Vector_); // Get rid of the old vector without calling
|
||||
// destructors
|
||||
|
||||
Vector_=newVector;
|
||||
Slots_=newSlots;
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// Shrink the vector by a factor of 2X
|
||||
template <class T>
|
||||
bit8 ArrayList<T>::shrinkVector(void)
|
||||
{
|
||||
//fprintf(stderr,"Shrink called\n");
|
||||
|
||||
// Don't need to shrink until usage goes below 33%
|
||||
if ( (Entries_*3) > Slots_)
|
||||
return(FALSE);
|
||||
|
||||
int newSlots=Slots_/2;
|
||||
if(newSlots < INITIAL_SIZE) // never shrink past initial size
|
||||
newSlots=INITIAL_SIZE;
|
||||
|
||||
if (newSlots >= Slots_) // don't need to shrink
|
||||
return(FALSE);
|
||||
|
||||
//fprintf(stderr,"Shrinking vector to: %d\n",newSlots);
|
||||
|
||||
// The goofy looking new below prevents operator new from getting called
|
||||
// unnecessarily. This is severall times faster than allocating all of
|
||||
// the slots as objects and then calling the assignment operator on them
|
||||
// when they actually get used.
|
||||
//
|
||||
T *newVector=(T *)(new uint8[newSlots * sizeof(T)]);
|
||||
|
||||
if (Vector_ != NULL) // Vector_ better not be NULL!
|
||||
memcpy(newVector,Vector_,Entries_*sizeof(T));
|
||||
|
||||
delete[]((uint8 *)Vector_); // Get rid of the old vector without calling
|
||||
// destructors
|
||||
|
||||
Vector_=newVector;
|
||||
Slots_=newSlots;
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
483
Generals/Code/Tools/mangler/wlib/configfile.cpp
Normal file
483
Generals/Code/Tools/mangler/wlib/configfile.cpp
Normal file
|
@ -0,0 +1,483 @@
|
|||
/*
|
||||
** 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"
|
||||
#include "wdebug.h"
|
||||
|
||||
static uint32 Wstring_Hash(const 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];
|
||||
char sectionname[256]; // section name like '[user parameters]'
|
||||
Wstring key;
|
||||
Wstring value;
|
||||
char *cptr;
|
||||
|
||||
memset(string,0,256);
|
||||
memset(sectionname,0,256);
|
||||
sectionList.clear();
|
||||
|
||||
while (fgets(string,256,in))
|
||||
{
|
||||
cptr=Eat_Spaces(string);
|
||||
if ((*cptr==0)||(*cptr=='#')) // '#' signals a comment
|
||||
continue;
|
||||
|
||||
if (*cptr=='[') // new section
|
||||
{
|
||||
key=cptr;
|
||||
key.truncate(']'); // remove after & including the ]
|
||||
key.cat("]"); // put the ] back
|
||||
strcpy(sectionname,key.get()); // set the current section name
|
||||
Wstring wssectionname;
|
||||
|
||||
if (strlen(sectionname)==2) // clear section with a "[]"
|
||||
{
|
||||
sectionname[0]=0;
|
||||
wssectionname.set("");
|
||||
}
|
||||
else
|
||||
wssectionname.set(sectionname+1);
|
||||
|
||||
wssectionname.truncate(']');
|
||||
sectionList.addTail(wssectionname);
|
||||
|
||||
|
||||
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
|
||||
|
||||
// Add the section name to the end of the key
|
||||
if (strlen(sectionname))
|
||||
key.cat(sectionname);
|
||||
|
||||
cptr=Eat_Spaces(strchr(cptr,'=')+1); // Jump to after the '='
|
||||
value=cptr;
|
||||
value.truncate('\r');
|
||||
value.truncate('\n');
|
||||
value.truncate('#');
|
||||
|
||||
// Remove trailing spaces
|
||||
while(isgraph(value.get()[strlen(value.get())-1])==0)
|
||||
value.get()[strlen(value.get())-1]=0;
|
||||
|
||||
Critsec_.lock();
|
||||
Dictionary_.add(key,value);
|
||||
Critsec_.unlock();
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Enum through the config strings. To start, index & offset should be 0
|
||||
// If retval is false you're done, ignore whatever's in key & value.
|
||||
//
|
||||
// Section specifies the configfile section. Set to NULL if you don't care.
|
||||
//
|
||||
bit8 ConfigFile::enumerate(int &index, int &offset, Wstring &key, Wstring &value, IN char *section) const
|
||||
{
|
||||
int seclen = strlen(section);
|
||||
while(1)
|
||||
{
|
||||
Critsec_.lock();
|
||||
if (Dictionary_.iterate(index,offset,key,value)==FALSE) // out of keys?
|
||||
{
|
||||
Critsec_.unlock();
|
||||
return(FALSE);
|
||||
}
|
||||
Critsec_.unlock();
|
||||
|
||||
if (section==NULL) // no specified section, so any will do...
|
||||
break;
|
||||
|
||||
if (strlen(section)+2 >= strlen(key.get())) // key should have form: X[section]
|
||||
continue;
|
||||
|
||||
// Is this key part of our section?
|
||||
const char *keystr = key.get() + strlen(key.get())-seclen-1;
|
||||
if (strncmp(keystr,section,strlen(section))==0)
|
||||
break;
|
||||
}
|
||||
key.truncate('['); // remove the section name
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Get a config entry as a string
|
||||
bit8 ConfigFile::getString(IN Wstring &_key, Wstring &value, IN char *section) const
|
||||
{
|
||||
Wstring key(_key);
|
||||
key.toUpper();
|
||||
|
||||
if (section) // append section name to key
|
||||
{
|
||||
key+="[";
|
||||
key+=section;
|
||||
key+="]";
|
||||
}
|
||||
|
||||
Critsec_.lock();
|
||||
bit8 retval=Dictionary_.getValue(key,value);
|
||||
Critsec_.unlock();
|
||||
|
||||
if (retval==FALSE)
|
||||
{
|
||||
DBGMSG("Config entry missing: "<<key.get());
|
||||
}
|
||||
|
||||
return(retval);
|
||||
}
|
||||
|
||||
// Get a config entry as a string
|
||||
bit8 ConfigFile::getString(IN char *key,Wstring &value, IN char *section) const
|
||||
{
|
||||
Wstring sKey;
|
||||
sKey.set(key);
|
||||
return(getString(sKey,value,section));
|
||||
}
|
||||
|
||||
// Get a config entry as an integer
|
||||
bit8 ConfigFile::getInt(IN Wstring &_key,sint32 &value, IN char *section) const
|
||||
{
|
||||
Wstring key(_key);
|
||||
key.toUpper();
|
||||
|
||||
if (section) // append section name to key
|
||||
{
|
||||
key+="[";
|
||||
key+=section;
|
||||
key+="]";
|
||||
}
|
||||
|
||||
Wstring svalue;
|
||||
Critsec_.lock();
|
||||
bit8 retval=Dictionary_.getValue(key,svalue);
|
||||
Critsec_.unlock();
|
||||
|
||||
if (retval==FALSE)
|
||||
{ DBGMSG("Config entry missing: "<<key.get()); }
|
||||
|
||||
if (retval==FALSE)
|
||||
return(FALSE);
|
||||
value=atol(svalue.get());
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
// Get a config entry as an integer
|
||||
bit8 ConfigFile::getInt(IN char *key,sint32 &value, IN char *section) const
|
||||
{
|
||||
Wstring sKey;
|
||||
sKey.set(key);
|
||||
|
||||
return(getInt(sKey,value,section));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Get a config entry as an integer
|
||||
bit8 ConfigFile::getInt(IN Wstring &_key,sint16 &value, IN char *section) const
|
||||
{
|
||||
Wstring key(_key);
|
||||
key.toUpper();
|
||||
|
||||
if (section) // append section name to key
|
||||
{
|
||||
key+="[";
|
||||
key+=section;
|
||||
key+="]";
|
||||
}
|
||||
|
||||
Wstring svalue;
|
||||
Critsec_.lock();
|
||||
bit8 retval=Dictionary_.getValue(key,svalue);
|
||||
Critsec_.unlock();
|
||||
|
||||
if (retval==FALSE)
|
||||
{ DBGMSG("Config entry missing: "<<key.get()); }
|
||||
|
||||
if (retval==FALSE)
|
||||
return(FALSE);
|
||||
value=atoi(svalue.get());
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
// Get a config entry as an integer
|
||||
bit8 ConfigFile::getInt(IN char *key,sint16 &value, IN char *section) const
|
||||
{
|
||||
Wstring sKey;
|
||||
sKey.set(key);
|
||||
|
||||
return(getInt(sKey,value,section));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/************* MDC; Added functionality for updating and saving config files ************/
|
||||
|
||||
// Remove an entry
|
||||
bit8 ConfigFile::removeEntry(IN Wstring &_key, IN char *section)
|
||||
{
|
||||
Wstring key(_key);
|
||||
key.toUpper();
|
||||
|
||||
if (section) // append section name to key
|
||||
{
|
||||
key+="[";
|
||||
key+=section;
|
||||
key+="]";
|
||||
}
|
||||
|
||||
Critsec_.lock();
|
||||
bit8 retval=Dictionary_.remove(key);
|
||||
Critsec_.unlock();
|
||||
|
||||
if (retval==FALSE)
|
||||
{ DBGMSG("Config entry missing: "<<key.get()); }
|
||||
|
||||
if (retval==FALSE)
|
||||
return(FALSE);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
// Remove an entry
|
||||
bit8 ConfigFile::removeEntry(IN char *key, IN char *section)
|
||||
{
|
||||
Wstring sKey;
|
||||
sKey.set(key);
|
||||
return removeEntry(sKey, section);
|
||||
}
|
||||
|
||||
// Set a config entry as a string
|
||||
bit8 ConfigFile::setString(IN Wstring &_key, IN Wstring &value, IN char *section)
|
||||
{
|
||||
Wstring key(_key);
|
||||
key.toUpper();
|
||||
|
||||
if (section) // append section name to key
|
||||
{
|
||||
key+="[";
|
||||
key+=section;
|
||||
key+="]";
|
||||
}
|
||||
else
|
||||
{
|
||||
section = ""; // give it a default
|
||||
}
|
||||
|
||||
Critsec_.lock();
|
||||
Dictionary_.remove(key);
|
||||
bit8 retval=Dictionary_.add(key,value);
|
||||
|
||||
// Test for a new section
|
||||
Wstring test;
|
||||
int i;
|
||||
for (i=0; i<sectionList.length(); i++)
|
||||
{
|
||||
sectionList.get(test, i);
|
||||
if (!strcmp(test.get(), section))
|
||||
break;
|
||||
}
|
||||
if (i == sectionList.length())
|
||||
{
|
||||
// New section!
|
||||
//DBGMSG("New section " << section << ", " << sectionList.length() << " entries");
|
||||
test.set(section);
|
||||
sectionList.addTail(test);
|
||||
}
|
||||
Critsec_.unlock();
|
||||
|
||||
if (retval==FALSE)
|
||||
{
|
||||
DBGMSG("Config could not set entry: "<<key.get());
|
||||
}
|
||||
|
||||
return(retval);
|
||||
}
|
||||
|
||||
// Set a config entry as a string
|
||||
bit8 ConfigFile::setString(IN char *key,IN Wstring &value, IN char *section)
|
||||
{
|
||||
Wstring sKey;
|
||||
sKey.set(key);
|
||||
return(setString(sKey,value,section));
|
||||
}
|
||||
|
||||
// Set a config entry as an integer
|
||||
bit8 ConfigFile::setInt(IN Wstring &_key,IN sint32 &value, IN char *section)
|
||||
{
|
||||
Wstring key(_key);
|
||||
key.toUpper();
|
||||
|
||||
if (section) // append section name to key
|
||||
{
|
||||
key+="[";
|
||||
key+=section;
|
||||
key+="]";
|
||||
}
|
||||
else
|
||||
{
|
||||
section = ""; // give it a default
|
||||
}
|
||||
|
||||
Wstring svalue;
|
||||
svalue.setFormatted("%d", value);
|
||||
Critsec_.lock();
|
||||
Dictionary_.remove(key);
|
||||
bit8 retval=Dictionary_.add(key,svalue);
|
||||
// Test for a new section
|
||||
Wstring test;
|
||||
//DBGMSG("Testing " << sectionList.length() << " entries for " << section);
|
||||
int i;
|
||||
for (i=0; i<sectionList.length(); i++)
|
||||
{
|
||||
sectionList.get(test, i);
|
||||
//DBGMSG("Looking at " << test.get());
|
||||
if (!strcmp(test.get(), section))
|
||||
break;
|
||||
}
|
||||
if (i == sectionList.length() && section)
|
||||
{
|
||||
// New section!
|
||||
//DBGMSG("New section " << section << ", " << sectionList.length() << " entries");
|
||||
test.set(section);
|
||||
sectionList.addTail(test);
|
||||
}
|
||||
Critsec_.unlock();
|
||||
|
||||
if (retval==FALSE)
|
||||
{ DBGMSG("Config could not set entry: "<<key.get()); }
|
||||
|
||||
if (retval==FALSE)
|
||||
return(FALSE);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
// Set a config entry as an integer
|
||||
bit8 ConfigFile::setInt(IN char *key,IN sint32 &value, IN char *section)
|
||||
{
|
||||
Wstring sKey;
|
||||
sKey.set(key);
|
||||
return(setInt(sKey,value,section));
|
||||
}
|
||||
|
||||
|
||||
// Write config file to disk. Does not preserve comments, etc.
|
||||
bit8 ConfigFile::writeFile(FILE *config)
|
||||
{
|
||||
if (!config)
|
||||
{
|
||||
ERRMSG("No FP on config file write!");
|
||||
return FALSE;
|
||||
}
|
||||
int index = 0;
|
||||
int offset = 0;
|
||||
Wstring key;
|
||||
Wstring value;
|
||||
|
||||
Wstring section;
|
||||
//DBGMSG(sectionList.length() << " entries");
|
||||
for (int i=0; i<sectionList.length(); i++)
|
||||
{
|
||||
sectionList.get(section, i);
|
||||
//DBGMSG("Writing " << section.get());
|
||||
fprintf(config, "[%s]\n", section.get());
|
||||
index = 0;
|
||||
offset = 0;
|
||||
while (enumerate(index, offset, key, value, section.get())!=FALSE)
|
||||
{
|
||||
fprintf(config, "%s=%s\n", key.get(), value.get());
|
||||
}
|
||||
fprintf(config, "\n");
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/************* 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(const 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);
|
||||
}
|
76
Generals/Code/Tools/mangler/wlib/configfile.h
Normal file
76
Generals/Code/Tools/mangler/wlib/configfile.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
** 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 : May 13, 1999
|
||||
\***************************************************************************/
|
||||
|
||||
#ifndef CONFIGFILE_HEADER
|
||||
#define CONFIGFILE_HEADER
|
||||
|
||||
#include "wstypes.h"
|
||||
#include "dictionary.h"
|
||||
#include "wstring.h"
|
||||
#include "critsec.h"
|
||||
#include "arraylist.h"
|
||||
|
||||
class ConfigFile
|
||||
{
|
||||
public:
|
||||
ConfigFile();
|
||||
~ConfigFile();
|
||||
bit8 readFile(FILE *config);
|
||||
bit8 getString(IN Wstring &key,OUT Wstring &value, IN char *section=NULL) const;
|
||||
bit8 getString(IN char *key,OUT Wstring &value, IN char *section=NULL) const;
|
||||
|
||||
bit8 getInt(IN Wstring &key,OUT sint32 &value, IN char *section=NULL) const;
|
||||
bit8 getInt(IN char *key,OUT sint32 &value, IN char *section=NULL) const;
|
||||
|
||||
bit8 getInt(IN Wstring &key,OUT sint16 &value, IN char *section=NULL) const;
|
||||
bit8 getInt(IN char *key,OUT sint16 &value, IN char *section=NULL) const;
|
||||
|
||||
// Enumerate through the config lines
|
||||
bit8 enumerate(int &index, int &offset, Wstring &key, Wstring &value, IN char *section=NULL) const;
|
||||
|
||||
// Manual update of config file
|
||||
bit8 setString(IN Wstring &key,IN Wstring &value, IN char *section=NULL);
|
||||
bit8 setString(IN char *key,IN Wstring &value, IN char *section=NULL);
|
||||
bit8 setInt(IN Wstring &key,IN sint32 &value, IN char *section=NULL);
|
||||
bit8 setInt(IN char *key,IN sint32 &value, IN char *section=NULL);
|
||||
bit8 removeEntry(IN Wstring &key, IN char *section=NULL);
|
||||
bit8 removeEntry(IN char *key, IN char *section=NULL);
|
||||
bit8 writeFile(FILE *config); // Does not preserve comments, etc
|
||||
|
||||
ArrayList<Wstring> sectionList; // stores the names of all sections
|
||||
|
||||
private:
|
||||
Dictionary<Wstring,Wstring> Dictionary_; // stores the mappings from keys
|
||||
// to value strings
|
||||
|
||||
// The lock is only needed around the immediate access to the dictionary, no writes
|
||||
// are allowed so you don't need to worry about an outer lock around the enumerate
|
||||
CritSec Critsec_; // lock around dictionary
|
||||
};
|
||||
|
||||
#endif
|
129
Generals/Code/Tools/mangler/wlib/critsec.cpp
Normal file
129
Generals/Code/Tools/mangler/wlib/critsec.cpp
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
** 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 "critsec.h"
|
||||
#include <assert.h>
|
||||
#include "wlib/wdebug.h"
|
||||
|
||||
|
||||
|
||||
CritSec::CritSec()
|
||||
{
|
||||
#ifdef _UNIX
|
||||
pthread_mutex_init(&Mutex_, NULL);
|
||||
RefCount_ = 0;
|
||||
#elif defined(_WIN32)
|
||||
InitializeCriticalSection(&CritSec_);
|
||||
#endif
|
||||
}
|
||||
|
||||
CritSec::~CritSec()
|
||||
{
|
||||
#ifdef _UNIX
|
||||
pthread_mutex_destroy(&Mutex_);
|
||||
#elif defined(_WIN32)
|
||||
DeleteCriticalSection(&CritSec_);
|
||||
#endif
|
||||
}
|
||||
|
||||
// The "lock" function blocks until the mutex is available.
|
||||
// Returns 0 on success, error code on error.
|
||||
//
|
||||
// A thread that already has a lock will increment a reference count if it calls
|
||||
// lock again. It must then call unlock() enough times to get the reference to 0.
|
||||
//
|
||||
// If refcount is not null you can get the current ref counter after the lock.
|
||||
//
|
||||
sint32 CritSec::lock(int *refcount) RO
|
||||
{
|
||||
#ifdef _UNIX
|
||||
sint32 status;
|
||||
|
||||
// I TRY to get the lock. IF I succeed, OR if I fail because
|
||||
// I already have the lock, I just increment the reference
|
||||
// count and return.
|
||||
if (((status = pthread_mutex_trylock(&Mutex_)) == 0) ||
|
||||
((status == EBUSY) && (ThreadId_ == pthread_self())))
|
||||
{
|
||||
ThreadId_ = pthread_self();
|
||||
RefCount_++;
|
||||
if (refcount)
|
||||
*refcount=RefCount_;
|
||||
return(0);
|
||||
}
|
||||
|
||||
// Otherwise, I wait for the lock.
|
||||
if ((status = pthread_mutex_lock(&Mutex_)) == 0)
|
||||
{
|
||||
assert(RefCount_ == 0);
|
||||
ThreadId_ = pthread_self();
|
||||
RefCount_++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRMSG("pthread_mutex_lock: " << strerror(errno));
|
||||
}
|
||||
|
||||
if (refcount)
|
||||
*refcount=RefCount_;
|
||||
|
||||
return(status);
|
||||
#elif defined(_WIN32)
|
||||
// TOFIX update the refcount
|
||||
EnterCriticalSection(&CritSec_);
|
||||
return(0);
|
||||
#else
|
||||
#error Must define either _WIN32 or _UNIX
|
||||
#endif
|
||||
}
|
||||
|
||||
// The "unlock" function release the critical section.
|
||||
sint32 CritSec::unlock(void) RO
|
||||
{
|
||||
#ifdef _UNIX
|
||||
sint32 status = 0;
|
||||
|
||||
assert(RefCount_ >= 0);
|
||||
if (RefCount_ <= 0)
|
||||
{
|
||||
//ERRMSG("unlocking unlocked mutex!");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
///assert(ThreadId_ == pthread_self());
|
||||
if (ThreadId_ != pthread_self())
|
||||
{
|
||||
WRNMSG("tried to unlock a mutex not owned by self");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if (--RefCount_ == 0)
|
||||
{
|
||||
// Set thread id to zero -- we're going to release mutex
|
||||
ThreadId_ = (pthread_t)0;
|
||||
|
||||
// Unlock the mutex.
|
||||
if ((status = pthread_mutex_unlock(&Mutex_)) != 0)
|
||||
ERRMSG("pthread_mutex_lock: " << strerror(errno));
|
||||
}
|
||||
return status;
|
||||
#elif defined(_WIN32)
|
||||
LeaveCriticalSection(&CritSec_);
|
||||
return(0);
|
||||
#endif
|
||||
}
|
62
Generals/Code/Tools/mangler/wlib/critsec.h
Normal file
62
Generals/Code/Tools/mangler/wlib/critsec.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
** 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 CRITSEC_HEADER
|
||||
#define CRITSEC_HEADER
|
||||
|
||||
#include "wstypes.h"
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <winbase.h>
|
||||
#elif defined(_UNIX)
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
// Windows headers have a tendency to redefine IN
|
||||
#ifdef IN
|
||||
#undef IN
|
||||
#endif
|
||||
#define IN const
|
||||
|
||||
//
|
||||
// Critical Section built either on a POSIX Mutex, or a Win32 Critical Section
|
||||
//
|
||||
// POSIX version is done by keeping a thread_id and a reference count. Win32 version
|
||||
// just calls the built in functions.
|
||||
//
|
||||
class CritSec
|
||||
{
|
||||
public:
|
||||
CritSec();
|
||||
~CritSec();
|
||||
|
||||
sint32 lock(int *refcount=NULL) RO;
|
||||
sint32 unlock(void) RO;
|
||||
|
||||
protected:
|
||||
#ifdef _WIN32
|
||||
mutable CRITICAL_SECTION CritSec_;
|
||||
#else
|
||||
mutable pthread_mutex_t Mutex_; // Mutex lock
|
||||
mutable pthread_t ThreadId_; // Owner of mutex
|
||||
mutable int RefCount_; // Reference count
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
680
Generals/Code/Tools/mangler/wlib/dictionary.h
Normal file
680
Generals/Code/Tools/mangler/wlib/dictionary.h
Normal file
|
@ -0,0 +1,680 @@
|
|||
/*
|
||||
** 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"
|
||||
|
||||
// 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));
|
||||
|
||||
|
||||
// Note: I had to put this inside the class definition because VC5 sucks butt
|
||||
|
||||
//Create the empty hash dictionary
|
||||
Dictionary(uint32 (*hashFn)(const 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(128) // 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;
|
||||
}
|
||||
|
||||
|
||||
~Dictionary();
|
||||
|
||||
void clear(void);
|
||||
bit8 add(IN K &key,IN V &value);
|
||||
bool getValue(IN K &key, OUT V &value) RO;
|
||||
bool getPointer(IN K &key, OUT V **value) RO; // ptr to internal storage (Careful!)
|
||||
void print(FILE *out) RO;
|
||||
uint32 getSize(void) RO;
|
||||
uint32 getEntries(void) RO;
|
||||
bit8 contains(IN K &key) RO;
|
||||
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) RO;
|
||||
bit8 iterate(INOUT int &index,INOUT int &offset, OUT K &key, OUT V &value) RO;
|
||||
Dictionary<K,V> &operator=(Dictionary<K,V> &other);
|
||||
|
||||
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)(IN K &key); // User provided hash function
|
||||
uint32 keyHash(IN K &key) RO; // 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
|
||||
};
|
||||
|
||||
|
||||
|
||||
//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) RO
|
||||
{
|
||||
uint32 retval=hashFunc(key);
|
||||
retval &= ((1<<tableBits)-1);
|
||||
assert(retval<getSize());
|
||||
return(retval);
|
||||
}
|
||||
|
||||
|
||||
template <class K,class V>
|
||||
void Dictionary<K,V>::print(FILE *out) RO
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
template <class K, class V>
|
||||
Dictionary<K,V> &Dictionary<K,V>::operator=(Dictionary<K,V> &other)
|
||||
{
|
||||
_ASSERTE(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// 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) RO
|
||||
{
|
||||
DNode<K,V> *temp;
|
||||
|
||||
// index out of range
|
||||
if ((index<0)||(index >= (int)getSize()))
|
||||
return(FALSE);
|
||||
|
||||
temp=table[index];
|
||||
while ((temp==NULL)&&((++index) < (int)getSize()))
|
||||
{
|
||||
temp=table[index];
|
||||
offset=0;
|
||||
}
|
||||
|
||||
if (temp==NULL) // no more slots with data
|
||||
return(FALSE);
|
||||
|
||||
uint32 i=0;
|
||||
while ((temp!=NULL) && ((int)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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// 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 K &key, OUT V &value) RO
|
||||
{
|
||||
DNode<K,V> *temp;
|
||||
|
||||
// index out of range
|
||||
if ((index<0)||(index >= (int)getSize()))
|
||||
return(FALSE);
|
||||
|
||||
temp=table[index];
|
||||
while ((temp==NULL)&&((++index) < (int)getSize()))
|
||||
{
|
||||
temp=table[index];
|
||||
offset=0;
|
||||
}
|
||||
|
||||
if (temp==NULL) // no more slots with data
|
||||
return(FALSE);
|
||||
|
||||
uint32 i=0;
|
||||
while ((temp!=NULL) && ((int)i < offset))
|
||||
{
|
||||
temp=temp->hashNext;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (temp==NULL) // should never happen
|
||||
return(FALSE);
|
||||
|
||||
value=temp->value;
|
||||
key=temp->key;
|
||||
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) RO
|
||||
{ return(size); }
|
||||
|
||||
|
||||
// Return the current number of entries in the table
|
||||
template <class K,class V>
|
||||
uint32 Dictionary<K,V>::getEntries(void) RO
|
||||
{ return(entries); }
|
||||
|
||||
|
||||
// Does the Dictionary contain the key?
|
||||
template <class K,class V>
|
||||
bit8 Dictionary<K,V>::contains(IN K &key) RO
|
||||
{
|
||||
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); // Hopefully this will be false...
|
||||
|
||||
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;
|
||||
|
||||
bit8 retval=FALSE; // wow, didn't add this for years... (DOH!)
|
||||
|
||||
//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);
|
||||
retval=TRUE; // yes, we deleted something
|
||||
break;
|
||||
}
|
||||
last=node;
|
||||
node=node->hashNext;
|
||||
}
|
||||
|
||||
if (percent <= SHRINK_THRESHOLD)
|
||||
shrink();
|
||||
return(retval);
|
||||
}
|
||||
|
||||
|
||||
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>
|
||||
bool Dictionary<K,V>::getValue(IN K &key,OUT V &value) RO
|
||||
{
|
||||
V *valptr=NULL;
|
||||
bool retval=getPointer(key,&valptr);
|
||||
if (retval && valptr)
|
||||
{
|
||||
#ifdef VALUE_MEM_OPS
|
||||
assert(0);
|
||||
#else
|
||||
value=*valptr;
|
||||
#endif
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
|
||||
// Try and avoid this since you're getting a pointer to the internally
|
||||
// managed data!
|
||||
template <class K,class V>
|
||||
bool Dictionary<K,V>::getPointer(IN K &key,OUT V **valptr) RO
|
||||
{
|
||||
int offset;
|
||||
DNode<K,V> *node;
|
||||
|
||||
if (entries==0)
|
||||
return(FALSE);
|
||||
|
||||
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); }
|
||||
|
||||
*valptr=&(node->value);
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
//A note about Shrink and Expand: They are never necessary, they are
|
||||
//only here to improve performance of the hash table by reducing
|
||||
//the length of the linked list at each table entry.
|
||||
|
||||
// Shrink the hash table by a factor of 2 (and relocate entries)
|
||||
template <class K,class V>
|
||||
void Dictionary<K,V>::shrink(void)
|
||||
{
|
||||
int i;
|
||||
int oldsize;
|
||||
uint32 offset;
|
||||
DNode<K,V> **oldtable,*temp,*first,*next;
|
||||
|
||||
if ((size<=(uint32)MIN_TABLE_SIZE)||(keepSize==TRUE))
|
||||
return;
|
||||
|
||||
//fprintf(stderr,"Shrinking....\n");
|
||||
|
||||
oldtable=table;
|
||||
oldsize=size;
|
||||
size/=2;
|
||||
tableBits--;
|
||||
|
||||
table=(DNode<K,V> **)new DNode<K,V>*[size];
|
||||
assert(table!=NULL);
|
||||
memset((void *)table,0,size*sizeof(void *));
|
||||
|
||||
for (i=0; i<oldsize; i++)
|
||||
{
|
||||
temp=oldtable[i];
|
||||
while (temp!=NULL)
|
||||
{
|
||||
offset=keyHash(temp->key);
|
||||
first=table[offset];
|
||||
table[offset]=temp;
|
||||
next=temp->hashNext;
|
||||
temp->hashNext=first;
|
||||
temp=next;
|
||||
}
|
||||
}
|
||||
delete[](oldtable);
|
||||
}
|
||||
|
||||
|
||||
template <class K,class V>
|
||||
void Dictionary<K,V>::expand(void)
|
||||
{
|
||||
int i;
|
||||
int oldsize;
|
||||
uint32 offset;
|
||||
DNode<K,V> **oldtable,*temp,*first,*next;
|
||||
|
||||
if (keepSize==TRUE)
|
||||
return;
|
||||
|
||||
//fprintf(stderr,"Expanding...\n");
|
||||
|
||||
oldtable=table;
|
||||
oldsize=size;
|
||||
size*=2;
|
||||
tableBits++;
|
||||
|
||||
table=(DNode<K,V> **)new DNode<K,V>* [size];
|
||||
assert(table!=NULL);
|
||||
memset((void *)table,0,size*sizeof(void *));
|
||||
|
||||
for (i=0; i<oldsize; i++)
|
||||
{
|
||||
temp=oldtable[i];
|
||||
while (temp!=NULL)
|
||||
{
|
||||
offset=keyHash(temp->key);
|
||||
first=table[offset];
|
||||
table[offset]=temp;
|
||||
next=temp->hashNext;
|
||||
temp->hashNext=first;
|
||||
temp=next;
|
||||
}
|
||||
}
|
||||
delete[](oldtable);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
51
Generals/Code/Tools/mangler/wlib/filed.h
Normal file
51
Generals/Code/Tools/mangler/wlib/filed.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
** 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(IN char *filename, IN char *mode = "w")
|
||||
{
|
||||
out=fopen(filename,mode);
|
||||
if (out==NULL)
|
||||
out=fopen("FileDev.out",mode);
|
||||
}
|
||||
|
||||
virtual ~FileD()
|
||||
{ fclose(out); }
|
||||
|
||||
virtual int print(const char *str,int len)
|
||||
{
|
||||
char *string=new char[len+1];
|
||||
memset(string,0,len+1);
|
||||
memcpy(string,str,len);
|
||||
fprintf(out,"%s",string);
|
||||
delete[](string);
|
||||
fflush(out);
|
||||
return(len);
|
||||
}
|
||||
|
||||
FILE *out;
|
||||
};
|
||||
|
||||
#endif
|
495
Generals/Code/Tools/mangler/wlib/linkedlist.h
Normal file
495
Generals/Code/Tools/mangler/wlib/linkedlist.h
Normal file
|
@ -0,0 +1,495 @@
|
|||
/*
|
||||
** 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 : linkedlist.h
|
||||
Author : Neal Kettler
|
||||
Start Date : June 19, 1997
|
||||
Last Update : June 19, 1997
|
||||
|
||||
Linked list template. This is a fairly standard doubly linked list that
|
||||
allows insertion and removal at any point in the list. A current pointer
|
||||
is used to quickly access items when they are examined sequentially.
|
||||
Copies of the data are stored instead of a pointer to the original.
|
||||
|
||||
If you want to store pointers then the template should be of a pointer type.
|
||||
\****************************************************************************/
|
||||
|
||||
#ifndef LINKEDLIST_HEADER
|
||||
#define LINKEDLIST_HEADER
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "wstypes.h"
|
||||
|
||||
template <class T>
|
||||
class LNode
|
||||
{
|
||||
public:
|
||||
T Node;
|
||||
LNode<T> *Next;
|
||||
LNode<T> *Prev;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class LinkedList
|
||||
{
|
||||
public:
|
||||
LinkedList();
|
||||
LinkedList(LinkedList<T> &other);
|
||||
~LinkedList();
|
||||
|
||||
// Remove all entries from the lsit
|
||||
void clear(void);
|
||||
|
||||
// Add a node after the zero based 'pos'
|
||||
bit8 add(IN T &node,sint32 pos, OUT T **newnodeptr=NULL);
|
||||
bit8 addTail(IN T &node, OUT T **newnodeptr=NULL);
|
||||
bit8 addHead(IN T &node, OUT T **newnodeptr=NULL);
|
||||
|
||||
// Remove a node
|
||||
bit8 remove(OUT T &node,sint32 pos);
|
||||
bit8 remove(sint32 pos);
|
||||
bit8 removeHead(OUT T &node);
|
||||
bit8 removeTail(OUT T &node);
|
||||
|
||||
|
||||
// Get a node without removing from the list
|
||||
bit8 get(OUT T &node,sint32 pos);
|
||||
bit8 getHead(OUT T &node);
|
||||
bit8 getTail(OUT T &node);
|
||||
|
||||
// Get a pointer to the internally managed data (careful!)
|
||||
bit8 getPointer(OUT T **node, sint32 pos);
|
||||
|
||||
// Get the number of entries in the list
|
||||
sint32 length(void);
|
||||
|
||||
// Print information on the list
|
||||
void print(IN FILE *out);
|
||||
|
||||
// assignment operator
|
||||
LinkedList<T> &operator=(LinkedList<T> &other);
|
||||
|
||||
private:
|
||||
sint32 Entries; // Number of entries
|
||||
LNode<T> *Head; // Head of the list
|
||||
LNode<T> *Tail; // Tail of the list
|
||||
|
||||
LNode<T> *Current; // Current pointer & index for speed only
|
||||
sint32 CurIndex;
|
||||
};
|
||||
|
||||
|
||||
//Create the empty list
|
||||
template <class T>
|
||||
LinkedList<T>::LinkedList()
|
||||
{
|
||||
Entries=0;
|
||||
Head=Tail=Current=NULL;
|
||||
CurIndex=-1; // Not valid when 0 entries
|
||||
}
|
||||
|
||||
// copy constructor
|
||||
template <class T>
|
||||
LinkedList<T>::LinkedList(LinkedList<T> &other)
|
||||
{
|
||||
Entries=0;
|
||||
Head=Tail=Current=NULL;
|
||||
CurIndex=-1; // Not valid when 0 entries
|
||||
(*this)=other;
|
||||
}
|
||||
|
||||
//Free all the memory...
|
||||
template <class T>
|
||||
LinkedList<T>::~LinkedList()
|
||||
{
|
||||
clear(); // Remove the entries
|
||||
}
|
||||
|
||||
// assignment operator
|
||||
template <class T>
|
||||
LinkedList<T> &LinkedList<T>::operator=(LinkedList<T> &other)
|
||||
{
|
||||
T node;
|
||||
clear();
|
||||
for (int i=0; i<other.length(); i++)
|
||||
{
|
||||
other.get(node,i);
|
||||
addTail(node);
|
||||
}
|
||||
return(*this);
|
||||
}
|
||||
|
||||
|
||||
// Remove all the entries and free the memory
|
||||
template <class T>
|
||||
void LinkedList<T>::clear()
|
||||
{
|
||||
LNode<T> *temp,*del;
|
||||
|
||||
temp=Head;
|
||||
while (temp) {
|
||||
del=temp;
|
||||
temp=temp->Next;
|
||||
delete(del);
|
||||
}
|
||||
Entries=0;
|
||||
CurIndex=-1;
|
||||
Head=Tail=Current=NULL;
|
||||
}
|
||||
|
||||
// When adding into a position, the new node goes at the zero based slot
|
||||
// specified by pos. All other nodes get moved one slot down.
|
||||
template <class T>
|
||||
bit8 LinkedList<T>::add(IN T &node,sint32 pos, OUT T **newnodeptr)
|
||||
{
|
||||
LNode<T> *temp;
|
||||
LNode<T> *item;
|
||||
|
||||
if (pos<0)
|
||||
pos=0;
|
||||
if (pos>Entries)
|
||||
pos=Entries;
|
||||
|
||||
item=(LNode<T> *)new LNode<T>;
|
||||
assert(item!=NULL);
|
||||
item->Node=node; // copy the passed in object
|
||||
item->Prev=NULL;
|
||||
item->Next=NULL;
|
||||
|
||||
if (newnodeptr)
|
||||
*newnodeptr=&(item->Node);
|
||||
|
||||
if ((pos==0)||(pos==Entries)) { // Both cases can be true for a new list!
|
||||
if (pos==0) {
|
||||
item->Next=Head;
|
||||
if (Head)
|
||||
Head->Prev=item;
|
||||
Head=item;
|
||||
}
|
||||
if (pos==Entries) {
|
||||
item->Prev=Tail;
|
||||
if (Tail)
|
||||
Tail->Next=item;
|
||||
Tail=item;
|
||||
}
|
||||
Entries++;
|
||||
Current=item;
|
||||
CurIndex=pos;
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
// If control is here, we know the new node is not an endpoint
|
||||
|
||||
// Check for possible speedup, so we don't have to scan the list
|
||||
if (pos==CurIndex) {
|
||||
item->Next=Current;
|
||||
item->Prev=Current->Prev;
|
||||
Current->Prev=item;
|
||||
item->Prev->Next=item;
|
||||
Current=item;
|
||||
Entries++;
|
||||
return(TRUE);
|
||||
}
|
||||
// Check the other possible speedup (adding after CurIndex)
|
||||
if (pos==CurIndex+1) {
|
||||
item->Next=Current->Next;
|
||||
item->Prev=Current;
|
||||
Current->Next=item;
|
||||
item->Next->Prev=item;
|
||||
Current=item;
|
||||
CurIndex++;
|
||||
Entries++;
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
// If control reaches here we have to scan the whole thing
|
||||
temp=Head->Next; // Can start at node '1' because head was special cased
|
||||
for (int i=1; i<pos; i++) {
|
||||
temp=temp->Next;
|
||||
assert(temp!=NULL);
|
||||
}
|
||||
item->Next=temp;
|
||||
item->Prev=temp->Prev;
|
||||
temp->Prev=item;
|
||||
item->Prev->Next=item;
|
||||
Current=item;
|
||||
CurIndex=pos;
|
||||
Entries++;
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// Add to the first node, all others get shifted down one slot
|
||||
template <class T>
|
||||
bit8 LinkedList<T>::addHead(IN T &node, OUT T **newnodeptr)
|
||||
{
|
||||
return(add(node,0,newnodeptr));
|
||||
}
|
||||
|
||||
|
||||
// Append to the end of the list
|
||||
template <class T>
|
||||
bit8 LinkedList<T>::addTail(IN T &node, OUT T **newnodeptr)
|
||||
{
|
||||
return(add(node,length(),newnodeptr));
|
||||
}
|
||||
|
||||
|
||||
// Remove at the zero based index specified by 'pos'. When removing from
|
||||
// a slot, all others get shifted up by one.
|
||||
template <class T>
|
||||
bit8 LinkedList<T>::remove(OUT T &node, sint32 pos)
|
||||
{
|
||||
////////LNode<T> *temp;
|
||||
LNode<T> *item;
|
||||
|
||||
if (Entries==0)
|
||||
return(FALSE);
|
||||
|
||||
if (pos<0)
|
||||
pos=0;
|
||||
if (pos>=Entries)
|
||||
pos=Entries-1;
|
||||
|
||||
if ((pos==0)||(pos==Entries-1)) { // Both can be true for a 1 item list
|
||||
if (pos==0) {
|
||||
item=Head;
|
||||
if (item->Next)
|
||||
item->Next->Prev=NULL;
|
||||
Head=item->Next;
|
||||
node=item->Node;
|
||||
Current=Head;
|
||||
CurIndex=0;
|
||||
}
|
||||
if (pos==Entries-1) {
|
||||
item=Tail;
|
||||
if (item->Prev)
|
||||
item->Prev->Next=NULL;
|
||||
Tail=item->Prev;
|
||||
node=item->Node;
|
||||
Current=Tail;
|
||||
CurIndex=Entries-2;
|
||||
}
|
||||
delete(item);
|
||||
Entries--;
|
||||
|
||||
if (Entries==0) { // Super paranoia check
|
||||
assert(Current==NULL);
|
||||
assert(CurIndex==-1);
|
||||
assert(Head==NULL);
|
||||
assert(Tail==NULL);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
// If control is here, we know the target node is not an endpoint
|
||||
|
||||
// Check for possible speedup, so we don't have to scan the list
|
||||
if (pos==CurIndex) {
|
||||
item=Current;
|
||||
item->Prev->Next=item->Next;
|
||||
item->Next->Prev=item->Prev;
|
||||
Current=item->Next;
|
||||
// CurIndex stays the same
|
||||
node=item->Node;
|
||||
delete(item);
|
||||
Entries--;
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
// Check the other possible speedup (removing after CurIndex)
|
||||
if (pos==CurIndex+1) {
|
||||
item=Current->Next;
|
||||
item->Prev->Next=item->Next;
|
||||
item->Next->Prev=item->Prev;
|
||||
Current=item->Next;
|
||||
CurIndex++;
|
||||
node=item->Node;
|
||||
delete(item);
|
||||
Entries--;
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// If control reaches here we have to scan the whole thing
|
||||
item=Head->Next; // Can start at node '1' because head was special cased
|
||||
for (int i=1; i<pos; i++) {
|
||||
item=item->Next;
|
||||
assert(item!=NULL);
|
||||
}
|
||||
|
||||
item->Prev->Next=item->Next;
|
||||
item->Next->Prev=item->Prev;
|
||||
Current=item->Next;
|
||||
CurIndex=pos;
|
||||
node=item->Node;
|
||||
delete(item);
|
||||
Entries--;
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Remove at the zero based index specified by 'pos'. When removing from
|
||||
// a slot, all others get shifted up by one.
|
||||
template <class T>
|
||||
bit8 LinkedList<T>::remove(sint32 pos)
|
||||
{
|
||||
T temp_node;
|
||||
return(remove(temp_node,pos));
|
||||
}
|
||||
|
||||
|
||||
// Remove the first node of the list
|
||||
template <class T>
|
||||
bit8 LinkedList<T>::removeHead(OUT T &node)
|
||||
{
|
||||
return(remove(node,0));
|
||||
}
|
||||
|
||||
|
||||
// Remove the last node of the list
|
||||
template <class T>
|
||||
bit8 LinkedList<T>::removeTail(OUT T &node)
|
||||
{
|
||||
return(remove(node,Entries-1));
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class T>
|
||||
bit8 LinkedList<T>::get(OUT T &node, sint32 pos)
|
||||
{
|
||||
T *objptr;
|
||||
bool retval=getPointer(&objptr,pos);
|
||||
if (retval && objptr)
|
||||
node=*objptr;
|
||||
|
||||
return(retval);
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
bit8 LinkedList<T>::getPointer(OUT T **node,sint32 pos)
|
||||
{
|
||||
if ((node==0)||(Entries==0))
|
||||
return(FALSE);
|
||||
|
||||
LNode<T> *item;
|
||||
|
||||
if (pos<0)
|
||||
{
|
||||
//pos=0;
|
||||
return(FALSE);
|
||||
}
|
||||
if (pos>=Entries)
|
||||
{
|
||||
//pos=Entries-1;
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
if (pos==0) {
|
||||
*node=&(Head->Node);
|
||||
return(TRUE);
|
||||
} else if (pos==Entries-1) {
|
||||
*node=&(Tail->Node);
|
||||
return(TRUE);
|
||||
}
|
||||
// If control reaches here, we know target is not an endpoint
|
||||
|
||||
// Check for possible speedup, so we don't have to scan the list
|
||||
if (pos==CurIndex) {
|
||||
*node=&(Current->Node);
|
||||
return(TRUE);
|
||||
} else if (pos==CurIndex+1) {
|
||||
*node=&(Current->Next->Node);
|
||||
CurIndex++;
|
||||
Current=Current->Next;
|
||||
return(TRUE);
|
||||
} else if (pos==CurIndex-1) {
|
||||
*node=&(Current->Prev->Node);
|
||||
CurIndex--;
|
||||
Current=Current->Prev;
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
// If control reaches here we have to scan the whole thing
|
||||
item=Head->Next; // Can start at node '1' because head was special cased
|
||||
for (int i=1; i<pos; i++) {
|
||||
item=item->Next;
|
||||
assert(item!=NULL);
|
||||
}
|
||||
*node=&(item->Node);
|
||||
CurIndex=pos;
|
||||
Current=item;
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// Remove the first node of the list
|
||||
template <class T>
|
||||
bit8 LinkedList<T>::getHead(OUT T &node)
|
||||
{
|
||||
return(get(node,0));
|
||||
}
|
||||
|
||||
|
||||
// Remove the last node of the list
|
||||
template <class T>
|
||||
bit8 LinkedList<T>::getTail(OUT T &node)
|
||||
{
|
||||
return(get(node,Entries-1));
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
void LinkedList<T>::print(IN FILE *out)
|
||||
{
|
||||
LNode<T> *temp;
|
||||
|
||||
fprintf(out,"--------------------\n");
|
||||
fprintf(out,"Entries = %d\n",length());
|
||||
fprintf(out,"H = %8p C = %8p (%d) T = %8p\n",Head,Current,CurIndex,Tail);
|
||||
|
||||
temp=Head;
|
||||
while (temp) {
|
||||
fprintf(out," %8p<-((%8p))->%8p \n",temp->Prev,temp,temp->Next);
|
||||
temp=temp->Next;
|
||||
}
|
||||
|
||||
fprintf(out,"--------------------\n");
|
||||
}
|
||||
|
||||
// Return the current length of the list
|
||||
template <class T>
|
||||
sint32 LinkedList<T>::length(void) {
|
||||
return(Entries);
|
||||
}
|
||||
|
||||
#endif
|
40
Generals/Code/Tools/mangler/wlib/mboxd.h
Normal file
40
Generals/Code/Tools/mangler/wlib/mboxd.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
** 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 MBOXD_HEADER
|
||||
#define MBOXD_HEADER
|
||||
|
||||
#include "odevice.h"
|
||||
|
||||
class MboxD : public OutputDevice
|
||||
{
|
||||
public:
|
||||
|
||||
virtual int print(const char *str,int len)
|
||||
{
|
||||
char *string=new char[len+1];
|
||||
memset(string,0,len+1);
|
||||
memcpy(string,str,len);
|
||||
MessageBox(NULL,string,"Debug Message", MB_OK | MB_ICONINFORMATION);
|
||||
delete[](string);
|
||||
return(len);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
57
Generals/Code/Tools/mangler/wlib/monod.cpp
Normal file
57
Generals/Code/Tools/mangler/wlib/monod.cpp
Normal 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
|
||||
}
|
74
Generals/Code/Tools/mangler/wlib/monod.h
Normal file
74
Generals/Code/Tools/mangler/wlib/monod.h
Normal 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
|
32
Generals/Code/Tools/mangler/wlib/odevice.h
Normal file
32
Generals/Code/Tools/mangler/wlib/odevice.h
Normal 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
|
182
Generals/Code/Tools/mangler/wlib/sem4.cpp
Normal file
182
Generals/Code/Tools/mangler/wlib/sem4.cpp
Normal file
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
** 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/>.
|
||||
*/
|
||||
|
||||
/******************************************************************************\
|
||||
sem4.cpp Neal Kettler
|
||||
|
||||
Simple Posix semaphore class
|
||||
This is useful because the constructor will automatically call sem_init
|
||||
and you don't have to worry about it. It also allows for other semaphore
|
||||
libraries if you don't have posix.
|
||||
\******************************************************************************/
|
||||
|
||||
#include "sem4.h"
|
||||
|
||||
#ifdef _REENTRANT
|
||||
|
||||
Sem4::Sem4()
|
||||
{
|
||||
#ifndef _WINDOWS
|
||||
sem_init(&sem,1,1);
|
||||
#else
|
||||
sem = CreateSemaphore(NULL, 1, 1, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
Sem4::Sem4(uint32 value)
|
||||
{
|
||||
#ifndef _WINDOWS
|
||||
sem_init(&sem,1,value);
|
||||
#else
|
||||
sem = CreateSemaphore(NULL, value, value, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
Sem4::~Sem4()
|
||||
{
|
||||
#ifndef _WINDOWS
|
||||
sem_destroy(&sem);
|
||||
#else
|
||||
if (sem) CloseHandle(sem);
|
||||
#endif
|
||||
}
|
||||
|
||||
sint32 Sem4::Wait(void) const
|
||||
{
|
||||
#ifndef _WINDOWS
|
||||
return(sem_wait((sem_t *)&sem));
|
||||
#else
|
||||
if (!sem)
|
||||
return -1; // no semaphore!
|
||||
|
||||
DWORD dwWaitResult = WaitForSingleObject(sem, INFINITE);
|
||||
switch (dwWaitResult) {
|
||||
case WAIT_OBJECT_0: // The semaphore object was signaled.
|
||||
return 0;
|
||||
break;
|
||||
case WAIT_TIMEOUT: // Should not happen ;)
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
sint32 Sem4::Post(void) const
|
||||
{
|
||||
#ifndef _WINDOWS
|
||||
return(sem_post((sem_t *)&sem));
|
||||
#else
|
||||
if (!sem)
|
||||
return -1;
|
||||
if (!ReleaseSemaphore(sem, 1 ,NULL))
|
||||
return -1;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
sint32 Sem4::TryWait(void) const
|
||||
{
|
||||
#ifndef _WINDOWS
|
||||
return(sem_trywait((sem_t *)&sem));
|
||||
#else
|
||||
if (!sem)
|
||||
return -1;
|
||||
DWORD dwWaitResult = WaitForSingleObject(sem, 0L);
|
||||
switch (dwWaitResult) {
|
||||
case WAIT_OBJECT_0: // The semaphore object was signaled.
|
||||
return 0;
|
||||
break;
|
||||
case WAIT_TIMEOUT:
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
sint32 Sem4::GetValue(int *sval) const
|
||||
{
|
||||
#ifndef _WINDOWS
|
||||
return(sem_getvalue((sem_t *)&sem,sval));
|
||||
#else
|
||||
if (!sem)
|
||||
return -1;
|
||||
long prev;
|
||||
if (!ReleaseSemaphore(sem, 0, &prev))
|
||||
return -1;
|
||||
if (sval)
|
||||
*sval = prev;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
sint32 Sem4::Destroy(void)
|
||||
{
|
||||
#ifndef _WINDOWS
|
||||
return(sem_destroy(&sem));
|
||||
#else
|
||||
return CloseHandle(sem);
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/****************************************************************************
|
||||
non threaded versions that do nothing
|
||||
*****************************************************************************/
|
||||
|
||||
Sem4::Sem4()
|
||||
{
|
||||
}
|
||||
|
||||
Sem4::Sem4(uint32)
|
||||
{
|
||||
}
|
||||
|
||||
Sem4::~Sem4()
|
||||
{
|
||||
}
|
||||
|
||||
sint32 Sem4::Wait(void) const
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
sint32 Sem4::Post(void) const
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
sint32 Sem4::TryWait(void) const
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
sint32 Sem4::GetValue(int *) const
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
sint32 Sem4::Destroy(void)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
64
Generals/Code/Tools/mangler/wlib/sem4.h
Normal file
64
Generals/Code/Tools/mangler/wlib/sem4.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
** 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 SEM4_HEADER
|
||||
#define SEM4_HEADER
|
||||
|
||||
#include <limits.h>
|
||||
#ifndef _WINDOWS
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "wstypes.h"
|
||||
|
||||
#ifdef _REENTRANT
|
||||
#ifndef _WINDOWS
|
||||
#include <semaphore.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#endif // _WINDOWS
|
||||
#endif // _REENTRANT
|
||||
|
||||
// Windows headers have a tendency to redefine IN
|
||||
#ifdef IN
|
||||
#undef IN
|
||||
#endif
|
||||
#define IN const
|
||||
|
||||
class Sem4
|
||||
{
|
||||
private:
|
||||
#ifdef _REENTRANT
|
||||
#ifndef _WINDOWS
|
||||
sem_t sem;
|
||||
#else
|
||||
HANDLE sem;
|
||||
#endif
|
||||
#endif
|
||||
public:
|
||||
Sem4();
|
||||
Sem4(uint32 value);
|
||||
~Sem4();
|
||||
|
||||
sint32 Wait(void) const;
|
||||
sint32 TryWait(void) const;
|
||||
sint32 Post(void) const;
|
||||
sint32 GetValue(int *sval) const;
|
||||
sint32 Destroy(void);
|
||||
};
|
||||
|
||||
#endif
|
39
Generals/Code/Tools/mangler/wlib/stderrd.h
Normal file
39
Generals/Code/Tools/mangler/wlib/stderrd.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
** 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 STDERRD_HEADER
|
||||
#define STDERRD_HEADER
|
||||
|
||||
#include "odevice.h"
|
||||
|
||||
class StderrD : public OutputDevice
|
||||
{
|
||||
public:
|
||||
|
||||
virtual int print(const char *str,int len)
|
||||
{
|
||||
char *string=new char[len+1];
|
||||
memset(string,0,len+1);
|
||||
memcpy(string,str,len);
|
||||
fprintf(stderr,"%s",string);
|
||||
delete[](string);
|
||||
return(len);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
40
Generals/Code/Tools/mangler/wlib/stdoutd.h
Normal file
40
Generals/Code/Tools/mangler/wlib/stdoutd.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
** 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 STDOUTD_HEADER
|
||||
#define STDOUTD_HEADER
|
||||
|
||||
#include "odevice.h"
|
||||
|
||||
class StdoutD : public OutputDevice
|
||||
{
|
||||
public:
|
||||
|
||||
virtual int print(const char *str,int len)
|
||||
{
|
||||
char *string=new char[len+1];
|
||||
memcpy(string,str,len);
|
||||
string[len]=0;
|
||||
fprintf(stdout,"%s",string);
|
||||
fflush(stdout);
|
||||
delete[](string);
|
||||
return(len);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
140
Generals/Code/Tools/mangler/wlib/streamer.cpp
Normal file
140
Generals/Code/Tools/mangler/wlib/streamer.cpp
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
** 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()
|
||||
{
|
||||
///////// calling sync seems to cause crashes here on Win32
|
||||
//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);
|
||||
}
|
66
Generals/Code/Tools/mangler/wlib/streamer.h
Normal file
66
Generals/Code/Tools/mangler/wlib/streamer.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
** 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>
|
||||
|
||||
// Windows headers have a tendency to redefine IN
|
||||
#ifdef IN
|
||||
#undef IN
|
||||
#endif
|
||||
#define IN const
|
||||
|
||||
#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
|
39
Generals/Code/Tools/mangler/wlib/syslogd.cpp
Normal file
39
Generals/Code/Tools/mangler/wlib/syslogd.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
** 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 "syslogd.h"
|
||||
|
||||
SyslogD::SyslogD(char *ident,int logopt,int facility,int _priority)
|
||||
{
|
||||
#ifndef _WINDOWS
|
||||
openlog(ident,logopt,facility);
|
||||
priority=_priority;
|
||||
#endif
|
||||
}
|
||||
|
||||
int SyslogD::print(const char *str, int len)
|
||||
{
|
||||
#ifndef _WINDOWS
|
||||
char *temp_str=new char[len+1];
|
||||
memset(temp_str,0,len+1);
|
||||
strncpy(temp_str,str,len);
|
||||
syslog(priority,temp_str);
|
||||
delete[](temp_str);
|
||||
#endif
|
||||
return(len);
|
||||
}
|
48
Generals/Code/Tools/mangler/wlib/syslogd.h
Normal file
48
Generals/Code/Tools/mangler/wlib/syslogd.h
Normal 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/>.
|
||||
*/
|
||||
|
||||
#ifndef SYSLOGD_HEADER
|
||||
#define SYSLOGD_HEADER
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#ifndef _WINDOWS
|
||||
#include <syslog.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
|
||||
// Windows headers have a tendency to redefine IN
|
||||
#ifdef IN
|
||||
#undef IN
|
||||
#endif
|
||||
#define IN const
|
||||
|
||||
#include "odevice.h"
|
||||
|
||||
// Windows doesn't have a syslog equivalent (does it?), so this class does little there
|
||||
class SyslogD : public OutputDevice
|
||||
{
|
||||
public:
|
||||
SyslogD(char *ident,int logopt,int facility,int priority);
|
||||
virtual int print(const char *str,int len);
|
||||
|
||||
private:
|
||||
int priority;
|
||||
};
|
||||
|
||||
#endif
|
221
Generals/Code/Tools/mangler/wlib/threadfac.cpp
Normal file
221
Generals/Code/Tools/mangler/wlib/threadfac.cpp
Normal file
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
** 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 THREADFAC_CODE
|
||||
|
||||
#include "threadfac.h"
|
||||
|
||||
int Runnable::ThreadCount_ = 0;
|
||||
CritSec Runnable::CritSec_; // to protect ThreadCount_
|
||||
|
||||
// MDC: Made all this dependent on _REENTRANT being defined so VC++ doesn't complain on
|
||||
// single-threaded programs...
|
||||
|
||||
|
||||
//
|
||||
// Note: I chose the following type signature for thread functions
|
||||
// void function(void *data);
|
||||
//
|
||||
//
|
||||
// Since Win32 & POSIX have different type signatures for the thread entry points
|
||||
// an intermediate system-dependent function in this file gets called first.
|
||||
// That function then calls the system independent version. So the system dependent
|
||||
// version needs 2 Items 1) The address of the _real_ thread func 2) the data
|
||||
// to pass. We only have 1 argument available, so you figure out the rest...
|
||||
//
|
||||
// This is for internal use only
|
||||
//
|
||||
struct ThreadInformation
|
||||
{
|
||||
void *startPoint; // The address of the _real_ thread function, or class
|
||||
void *data; // data to pass to real thread function or class
|
||||
bit8 destroy; // only applies to classes, should delete after execution?
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Start a thread inside a class
|
||||
//
|
||||
bit8 ThreadFactory::startThread(Runnable &runable, void *data, bit8 destroy)
|
||||
{
|
||||
#ifdef _REENTRANT
|
||||
|
||||
{
|
||||
Runnable::CritSec_.lock();
|
||||
Runnable::ThreadCount_++;
|
||||
Runnable::CritSec_.unlock();
|
||||
}
|
||||
|
||||
|
||||
ThreadInformation *tInfo=new ThreadInformation;
|
||||
tInfo->startPoint=(void *)&runable;
|
||||
tInfo->data=data;
|
||||
tInfo->destroy=destroy;
|
||||
|
||||
#ifdef _WIN32
|
||||
// Under windows call _beginthreadex instead of CreateThread so you can
|
||||
// use all the normal C library stuff. (IMPORTANT!!!)
|
||||
uint32 handle;
|
||||
uint32 stup1d;
|
||||
handle=_beginthreadex(NULL,0, threadClassLauncher, tInfo, 0, &stup1d);
|
||||
if (handle!=NULL)
|
||||
return(TRUE);
|
||||
else
|
||||
{
|
||||
{
|
||||
runable.CritSec_.lock();
|
||||
runable.ThreadCount_--; // Ok, so it didn't really start
|
||||
runable.CritSec_.unlock();
|
||||
}
|
||||
return(FALSE);
|
||||
}
|
||||
#else // UNIX
|
||||
// Setup thread attributes for client threads
|
||||
int retval;
|
||||
pthread_attr_t threadAttr;
|
||||
pthread_attr_init(&threadAttr);
|
||||
pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
|
||||
pthread_attr_setscope(&threadAttr,PTHREAD_SCOPE_SYSTEM);
|
||||
retval=pthread_create(NULL,&threadAttr, threadClassLauncher, tInfo);
|
||||
if (retval==0)
|
||||
return(TRUE);
|
||||
else
|
||||
{
|
||||
{
|
||||
runable.CritSec_.lock();
|
||||
runable.ThreadCount_--; // Ok, so it didn't really start
|
||||
runable.CritSec_.unlock();
|
||||
}
|
||||
return(FALSE);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
return (FALSE);
|
||||
#endif /* _REENTRANT */
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Start a thread inside a function
|
||||
//
|
||||
bit8 ThreadFactory::startThread(void (*start_func)(void *), void *data)
|
||||
{
|
||||
#ifdef _REENTRANT
|
||||
ThreadInformation *tInfo=new ThreadInformation;
|
||||
tInfo->startPoint=start_func;
|
||||
tInfo->data=data;
|
||||
|
||||
#ifdef _WIN32
|
||||
// Under windows call _beginthreadex instead of CreateThread so you can
|
||||
// use all the normal C library stuff. (IMPORTANT!!!)
|
||||
uint32 handle;
|
||||
unsigned temp;
|
||||
handle=_beginthreadex(NULL,0, threadFuncLauncher, tInfo, 0, &temp);
|
||||
if (handle!=NULL)
|
||||
return(TRUE);
|
||||
return(FALSE);
|
||||
#else // UNIX
|
||||
// Setup thread attributes for client threads
|
||||
int retval;
|
||||
pthread_attr_t threadAttr;
|
||||
pthread_attr_init(&threadAttr);
|
||||
pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
|
||||
pthread_attr_setscope(&threadAttr,PTHREAD_SCOPE_SYSTEM);
|
||||
retval=pthread_create(NULL,&threadAttr, threadFuncLauncher, tInfo);
|
||||
if (retval==0)
|
||||
return(TRUE);
|
||||
else
|
||||
return(FALSE);
|
||||
#endif
|
||||
#else
|
||||
return(FALSE);
|
||||
#endif /* REENTRANT */
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
unsigned __stdcall threadFuncLauncher(void *temp)
|
||||
#else // UNIX
|
||||
void *threadFuncLauncher(void *temp)
|
||||
#endif
|
||||
{
|
||||
ThreadInformation *tInfo=(ThreadInformation *)temp;
|
||||
|
||||
void (*start_func)(void *);
|
||||
start_func=(void (*)(void *))tInfo->startPoint;
|
||||
|
||||
void *data=tInfo->data;
|
||||
delete(tInfo);
|
||||
|
||||
start_func(data);
|
||||
return(0);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
unsigned __stdcall threadClassLauncher(void *temp)
|
||||
#else // UNIX
|
||||
void *threadClassLauncher(void *temp)
|
||||
#endif
|
||||
{
|
||||
ThreadInformation *tInfo=(ThreadInformation *)temp;
|
||||
|
||||
Runnable *thrClass=(Runnable *)tInfo->startPoint;
|
||||
void *data=tInfo->data;
|
||||
bit8 destroy=tInfo->destroy;
|
||||
delete(tInfo);
|
||||
|
||||
thrClass->run(data);
|
||||
|
||||
if (destroy) // May want to free memory after thread finishes
|
||||
delete(thrClass);
|
||||
|
||||
{
|
||||
Runnable::CritSec_.lock();
|
||||
Runnable::ThreadCount_--;
|
||||
Runnable::CritSec_.unlock();
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
ExitThread(0); // is this really needed?
|
||||
#endif
|
||||
return(0);
|
||||
}
|
||||
|
||||
Runnable::Runnable()
|
||||
{ }
|
||||
|
||||
Runnable::~Runnable()
|
||||
{ }
|
||||
|
||||
// Is there a thread running in this class
|
||||
bit8 Runnable::isRunning(void)
|
||||
{
|
||||
// Don't need to lock a simple assignment
|
||||
int temp=ThreadCount_;
|
||||
return((temp>0)?TRUE:FALSE);
|
||||
}
|
||||
|
||||
// How many threads are running in this class
|
||||
int Runnable::getThreadCount(void)
|
||||
{
|
||||
// Don't need to lock a simple assignment
|
||||
int temp=ThreadCount_;
|
||||
return(temp);
|
||||
}
|
||||
|
||||
#undef THREADFAC_CODE
|
124
Generals/Code/Tools/mangler/wlib/threadfac.h
Normal file
124
Generals/Code/Tools/mangler/wlib/threadfac.h
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
** 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/>.
|
||||
*/
|
||||
|
||||
//
|
||||
// Platform independent thread creation (Win32 & POSIX)
|
||||
//
|
||||
|
||||
#ifndef THREADFAC_HEADER
|
||||
#define THREADFAC_HEADER
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <process.h>
|
||||
#endif
|
||||
#include "wstypes.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <wtypes.h>
|
||||
#else // UNIX
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
// Windows headers have a tendency to redefine IN
|
||||
#ifdef IN
|
||||
#undef IN
|
||||
#endif
|
||||
#define IN const
|
||||
|
||||
#include "critsec.h"
|
||||
|
||||
|
||||
|
||||
#ifdef THREADFAC_CODE
|
||||
// This is the fake thread entry point for functions
|
||||
#ifdef _WIN32
|
||||
static unsigned __stdcall threadFuncLauncher(void *temp);
|
||||
#else // UNIX
|
||||
static void *threadFuncLauncher(void *temp);
|
||||
#endif
|
||||
|
||||
// Fake entry point for classes
|
||||
#ifdef _WIN32
|
||||
static unsigned __stdcall threadClassLauncher(void *temp);
|
||||
#else // UNIX
|
||||
static void *threadClassLauncher(void *temp);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Forward definition of base class for threaded classes
|
||||
class Runnable;
|
||||
|
||||
//
|
||||
// Call the static method startThread to begin a new thread.
|
||||
//
|
||||
class ThreadFactory
|
||||
{
|
||||
public:
|
||||
static bit8 startThread(void (*start_func)(void *), void *data);
|
||||
static bit8 startThread(Runnable &runable, void *data, bit8 destroy=FALSE);
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Base class for when you want a thread to execute inside a class
|
||||
// instead of a function.
|
||||
//
|
||||
class Runnable
|
||||
{
|
||||
public:
|
||||
Runnable();
|
||||
virtual ~Runnable();
|
||||
|
||||
|
||||
// ThreadFactory needs to be able to access the private
|
||||
// IsRunning_ field.
|
||||
friend class ThreadFactory;
|
||||
|
||||
// So do the threadClassLaunchers
|
||||
#ifdef _WIN32
|
||||
friend static unsigned __stdcall threadClassLauncher(void *temp);
|
||||
#else // UNIX
|
||||
friend void *threadClassLauncher(void *temp);
|
||||
#endif
|
||||
|
||||
virtual void run(void *data)=0; // Thread entry point
|
||||
|
||||
void startThread(void *data,bit8 destroy=FALSE) // nice way to start a thread
|
||||
{
|
||||
ThreadFactory::startThread(*this,data,destroy);
|
||||
};
|
||||
|
||||
// Is there a thread running in this class?
|
||||
static bit8 isRunning(void);
|
||||
|
||||
// Get the count of threads running inside this class
|
||||
static int getThreadCount();
|
||||
|
||||
|
||||
private:
|
||||
static int ThreadCount_;
|
||||
static CritSec CritSec_; // to protect ThreadCount_
|
||||
};
|
||||
|
||||
#endif
|
62
Generals/Code/Tools/mangler/wlib/threadsafe.h
Normal file
62
Generals/Code/Tools/mangler/wlib/threadsafe.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
** 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/>.
|
||||
*/
|
||||
|
||||
//
|
||||
// threadsafe.h
|
||||
//
|
||||
// If you include this file and call non-threadsafe functions, it'll
|
||||
// prevent your program from compiling. It's meant to be a slap
|
||||
// on the wrist in case you forget and call an unsafe function
|
||||
// from a threadsafe program.
|
||||
//
|
||||
|
||||
//
|
||||
// Reminder to self - use sigwait, not signal handlers!
|
||||
//
|
||||
|
||||
#ifdef _REENTRANT
|
||||
|
||||
#ifndef THREADSAFE_HEADER
|
||||
#define THREADSAFE_HEADER
|
||||
|
||||
#define strtok ("strtok() is not MT-SAFE!")
|
||||
#define ascctime ("asctime() is not MT-SAFE!")
|
||||
// Can't just do ctime, as Windows' objidl.h uses it as a FILETIME thingie
|
||||
#define ctime(x) ("ctime() is not MT-SAFE!")
|
||||
#define gmtime ("gmtime() is not MT-SAFE!")
|
||||
#define localtime ("localtime() is not MT-SAFE!")
|
||||
#define tzset ("tzset() is not MT-SAFE!")
|
||||
#define tzsetwall ("tzsetwall() is not MT-SAFE!")
|
||||
#define readdir ("readdir() is not MT-SAFE!")
|
||||
|
||||
#define rand ("rand() is not MT-SAFE!")
|
||||
#define srand ("srand() is not MT-SAFE!")
|
||||
#define random ("random() is not MT-SAFE!")
|
||||
#define srandom ("srandom() is not MT-SAFE!")
|
||||
|
||||
#define tmpnam ("tmpnam() is not MT-SAFE!")
|
||||
#define vfork ("vfork() is not MT-SAFE!")
|
||||
|
||||
#define system ("system() is not MT-SAFE!")
|
||||
#define popen ("popen() is not MT-SAFE!")
|
||||
#define pclose ("pclose() is not MT-SAFE!")
|
||||
#define ctermid ("ctermid() is not MT-SAFE!")
|
||||
#define getlogin ("getlogin() is not MT-SAFE!");
|
||||
|
||||
#endif // THREADSAFE_HEADER
|
||||
#endif // _REENTRANT
|
71
Generals/Code/Tools/mangler/wlib/timezone.cpp
Normal file
71
Generals/Code/Tools/mangler/wlib/timezone.cpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
** 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 "wlib/xtime.h"
|
||||
#include "timezone.h"
|
||||
|
||||
void GetTimezoneInfo(const char * &timezone_str, int &timezone_offset) {
|
||||
timezone_str = "Unknown Timezone";
|
||||
timezone_offset = 0;
|
||||
#ifdef _WINDOWS
|
||||
struct _timeb wintime;
|
||||
_ftime(&wintime);
|
||||
|
||||
if (wintime.dstflag) {
|
||||
// Daylight savings time
|
||||
if (_daylight) {
|
||||
timezone_str = _tzname[1];
|
||||
}
|
||||
} else {
|
||||
timezone_str = _tzname[0];
|
||||
}
|
||||
timezone_offset = wintime.timezone * 60; // its in minutes...
|
||||
|
||||
#endif
|
||||
#ifndef _WINDOWS
|
||||
struct timeval unixtime;
|
||||
struct timezone unixtzone;
|
||||
gettimeofday(&unixtime,&unixtzone);
|
||||
|
||||
struct tm unixtm;
|
||||
localtime_r(&unixtime.tv_sec, &unixtm);
|
||||
|
||||
if (unixtm.tm_isdst) {
|
||||
// Daylight savings time
|
||||
if (daylight) timezone_str = tzname[1];
|
||||
timezone_offset = altzone;
|
||||
} else {
|
||||
timezone_str = tzname[0];
|
||||
timezone_offset = timezone;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
const char * TimezoneString(void) {
|
||||
const char *timezone_str;
|
||||
int timezone_offset;
|
||||
GetTimezoneInfo(timezone_str, timezone_offset);
|
||||
return timezone_str;
|
||||
}
|
||||
|
||||
int TimezoneOffset(void) {
|
||||
const char *timezone_str;
|
||||
int timezone_offset;
|
||||
GetTimezoneInfo(timezone_str, timezone_offset);
|
||||
return timezone_offset;
|
||||
}
|
41
Generals/Code/Tools/mangler/wlib/timezone.h
Normal file
41
Generals/Code/Tools/mangler/wlib/timezone.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
** 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/>.
|
||||
*/
|
||||
|
||||
/****************************************************************************\
|
||||
timezone Matthew D. Campbell
|
||||
|
||||
This is just a couple of convenience functions for determining what timezone
|
||||
we are now in. It even accounts for daylight savings! One caveat is that it
|
||||
only tells you info about what the daylight savings info is now, not 5 minutes
|
||||
from now, not 2 hours ago. Oh well.
|
||||
\****************************************************************************/
|
||||
|
||||
#ifndef _TIMEZONE_H_
|
||||
#define _TIMEZONE_H_
|
||||
|
||||
// Just fill in both the timezone description and its offset from GMT
|
||||
void GetTimezoneInfo(const char * &timezone_str, int &timezone_offset);
|
||||
|
||||
// Returns the description of the current timezone (daylight savings included)
|
||||
const char * TimezoneString(void);
|
||||
|
||||
// Returns the offset from GMT of the current timezone
|
||||
int TimezoneOffset(void);
|
||||
|
||||
#endif // _TIMEZONE_H_
|
||||
|
61
Generals/Code/Tools/mangler/wlib/ustring.h
Normal file
61
Generals/Code/Tools/mangler/wlib/ustring.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
** 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 USTRING_HEADER
|
||||
#define USTRING_HEADER
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <iostream.h>
|
||||
#include <string>
|
||||
|
||||
// Windows headers have a tendency to redefine IN
|
||||
#ifdef IN
|
||||
#undef IN
|
||||
#endif
|
||||
#define IN const
|
||||
|
||||
#define MAX_BYTES_PER_CHAR 1
|
||||
|
||||
template <class charT>
|
||||
class UstringT : public basic_string<charT, string_char_traits<charT> >
|
||||
{
|
||||
public:
|
||||
explicit UstringT(int max_charlength) {
|
||||
set_max_bytelength(max_charlength*MAX_BYTES_PER_CHAR);
|
||||
}
|
||||
|
||||
UstringT() { max_bytelength=4000; }
|
||||
|
||||
size_t get_max_bytelength(void) { return(max_bytelength); }
|
||||
void set_max_bytelength(size_t max) { max_bytelength=max; }
|
||||
|
||||
bool operator==(const UstringT<charT> &other)
|
||||
{
|
||||
const basic_string<charT, string_char_traits<charT> > *other_basic=&other;
|
||||
const basic_string<charT, string_char_traits<charT> > *this_basic=this;
|
||||
return((*other_basic)==(*this_basic));
|
||||
}
|
||||
|
||||
private:
|
||||
size_t max_bytelength;
|
||||
};
|
||||
|
||||
typedef UstringT<char> Ustring;
|
||||
|
||||
#endif
|
190
Generals/Code/Tools/mangler/wlib/wdebug.cpp
Normal file
190
Generals/Code/Tools/mangler/wlib/wdebug.cpp
Normal file
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
** 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;
|
||||
|
||||
|
||||
// Don't dare touch this semaphore in application code!
|
||||
#ifdef USE_DEBUG_SEM
|
||||
Sem4 DebugLibSemaphore;
|
||||
#else
|
||||
CritSec DebugLibSemaphore;
|
||||
#endif
|
||||
|
||||
|
||||
int MsgManager::setAllStreams(OutputDevice *device)
|
||||
{
|
||||
if (device==NULL)
|
||||
return(1);
|
||||
|
||||
DEBUGLOCK;
|
||||
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);
|
||||
|
||||
DEBUGUNLOCK;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int MsgManager::ReplaceAllStreams(FileD * output_device, IN char *device_filename, IN char *copy_filename)
|
||||
{
|
||||
DebugLibSemaphore.Wait();
|
||||
|
||||
delete(debug_ostream);
|
||||
delete(info_ostream);
|
||||
delete(warn_ostream);
|
||||
delete(error_ostream);
|
||||
|
||||
if (output_device != NULL)
|
||||
{
|
||||
delete(output_device);
|
||||
output_device = NULL;
|
||||
}
|
||||
|
||||
rename(device_filename, copy_filename);
|
||||
|
||||
// FileD new_device(device_filename);
|
||||
output_device = new FileD(device_filename);
|
||||
|
||||
debug_streamer.setOutputDevice(output_device);
|
||||
debug_ostream = new ostream(&debug_streamer);
|
||||
|
||||
info_streamer.setOutputDevice(output_device);
|
||||
info_ostream=new ostream(&info_streamer);
|
||||
|
||||
warn_streamer.setOutputDevice(output_device);
|
||||
warn_ostream = new ostream(&warn_streamer);
|
||||
|
||||
error_streamer.setOutputDevice(output_device);
|
||||
error_ostream = new ostream(&error_streamer);
|
||||
|
||||
DebugLibSemaphore.Post();
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int MsgManager::setDebugStream(OutputDevice *device)
|
||||
{
|
||||
if (device==NULL)
|
||||
return(1);
|
||||
|
||||
DEBUGLOCK;
|
||||
debug_streamer.setOutputDevice(device);
|
||||
delete(debug_ostream);
|
||||
debug_ostream=new ostream(&debug_streamer);
|
||||
DEBUGUNLOCK;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int MsgManager::setInfoStream(OutputDevice *device)
|
||||
{
|
||||
if (device==NULL)
|
||||
return(1);
|
||||
|
||||
DEBUGLOCK;
|
||||
info_streamer.setOutputDevice(device);
|
||||
delete(info_ostream);
|
||||
info_ostream=new ostream(&info_streamer);
|
||||
DEBUGUNLOCK;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int MsgManager::setWarnStream(OutputDevice *device)
|
||||
{
|
||||
if (device==NULL)
|
||||
return(1);
|
||||
|
||||
DEBUGLOCK;
|
||||
warn_streamer.setOutputDevice(device);
|
||||
delete(warn_ostream);
|
||||
warn_ostream=new ostream(&warn_streamer);
|
||||
DEBUGUNLOCK;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int MsgManager::setErrorStream(OutputDevice *device)
|
||||
{
|
||||
if (device==NULL)
|
||||
return(1);
|
||||
|
||||
DEBUGLOCK;
|
||||
error_streamer.setOutputDevice(device);
|
||||
delete(error_ostream);
|
||||
error_ostream=new ostream(&error_streamer);
|
||||
DEBUGUNLOCK;
|
||||
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);
|
||||
}
|
317
Generals/Code/Tools/mangler/wlib/wdebug.h
Normal file
317
Generals/Code/Tools/mangler/wlib/wdebug.h
Normal file
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
** 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-Safe
|
||||
|
||||
The debugging module is pretty good for debugging and it has some message
|
||||
printing stuff as well. The basic idea is that you write a class that
|
||||
inherits from OutputDevice (several 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
|
||||
|
||||
#define USE_DEBUG_SEM
|
||||
|
||||
#include "wstypes.h"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <iostream.h>
|
||||
#include <strstrea.h>
|
||||
#else
|
||||
#include <iostream>
|
||||
|
||||
// Windows headers have a tendency to redefine IN
|
||||
#ifdef IN
|
||||
#undef IN
|
||||
#endif
|
||||
#define IN const
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_DEBUG_SEM
|
||||
#include "sem4.h"
|
||||
#else
|
||||
#include "critsec.h"
|
||||
#endif
|
||||
#include "odevice.h"
|
||||
#include "streamer.h"
|
||||
#include "xtime.h"
|
||||
#include "timezone.h" // MDC
|
||||
#include "filed.h"
|
||||
|
||||
// This is needed because the streams return a pointer. Every time you
|
||||
// change the output device the old stream is deleted, and a new one
|
||||
// is created.
|
||||
// MDC: Added a macro to switch between semaphores & critsecs to debug a
|
||||
// problem in Win32.
|
||||
|
||||
#ifdef USE_DEBUG_SEM
|
||||
extern Sem4 DebugLibSemaphore;
|
||||
#define DEBUGLOCK DebugLibSemaphore.Wait()
|
||||
#define DEBUGUNLOCK DebugLibSemaphore.Post()
|
||||
#else
|
||||
extern CritSec DebugLibSemaphore;
|
||||
#define DEBUGLOCK DebugLibSemaphore.lock()
|
||||
#define DEBUGUNLOCK DebugLibSemaphore.unlock()
|
||||
#endif
|
||||
|
||||
// Print an information message
|
||||
#define INFMSG(X)\
|
||||
{\
|
||||
char timebuf[40]; \
|
||||
Xtime now; \
|
||||
now -= TimezoneOffset(); \
|
||||
now.FormatTime(timebuf, "mm/dd/yy hh:mm:ss"); \
|
||||
DEBUGLOCK; \
|
||||
if (MsgManager::infoStream()) \
|
||||
(*(MsgManager::infoStream())) << "INF " << timebuf << " [" << \
|
||||
__FILE__ << " " << __LINE__ << "] " << X << endl; \
|
||||
DEBUGUNLOCK; \
|
||||
}
|
||||
|
||||
// Print a warning message
|
||||
#define WRNMSG(X)\
|
||||
{\
|
||||
char timebuf[40]; \
|
||||
Xtime now; \
|
||||
now -= TimezoneOffset(); \
|
||||
now.FormatTime(timebuf, "mm/dd/yy hh:mm:ss"); \
|
||||
DEBUGLOCK; \
|
||||
if (MsgManager::warnStream()) \
|
||||
(*(MsgManager::warnStream())) << "WRN " << timebuf << " [" << \
|
||||
__FILE__ << " " << __LINE__ << "] " << X << endl; \
|
||||
DEBUGUNLOCK; \
|
||||
}
|
||||
|
||||
// Print an error message
|
||||
#define ERRMSG(X)\
|
||||
{\
|
||||
char timebuf[40]; \
|
||||
Xtime now; \
|
||||
now -= TimezoneOffset(); \
|
||||
now.FormatTime(timebuf, "mm/dd/yy hh:mm:ss"); \
|
||||
DEBUGLOCK; \
|
||||
if (MsgManager::errorStream()) \
|
||||
(*(MsgManager::errorStream())) << "ERR " << timebuf << " [" << \
|
||||
__FILE__ << " " << __LINE__ << "] " << X << endl; \
|
||||
DEBUGUNLOCK; \
|
||||
}
|
||||
|
||||
|
||||
// Just get a stream to the information device, no extra junk
|
||||
#define INFSTREAM(X)\
|
||||
{\
|
||||
DEBUGLOCK; \
|
||||
if (MsgManager::infoStream()) \
|
||||
(*(MsgManager::infoStream())) << X;\
|
||||
DEBUGUNLOCK; \
|
||||
}
|
||||
|
||||
// Just get a stream to the warning device, no extra junk
|
||||
#define WRNSTREAM(X)\
|
||||
{\
|
||||
DEBUGLOCK; \
|
||||
if (MsgManager::warnStream()) \
|
||||
(*(MsgManager::warnStream())) << X;\
|
||||
DEBUGUNLOCK; \
|
||||
}
|
||||
|
||||
// Just get a stream to the error device, no extra junk
|
||||
#define ERRSTREAM(X)\
|
||||
{\
|
||||
DEBUGLOCK; \
|
||||
if (MsgManager::errorStream()) \
|
||||
(*(MsgManager::errorStream())) << X;\
|
||||
DEBUGUNLOCK; \
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
// In Windows, send a copy to the debugger window
|
||||
#ifdef _WINDOWS
|
||||
|
||||
// Print a variable
|
||||
#define PVAR(v) \
|
||||
{ \
|
||||
DEBUGLOCK; \
|
||||
if (MsgManager::debugStream()) \
|
||||
(*(MsgManager::debugStream())) << __FILE__ << "[" << __LINE__ << \
|
||||
"]: " << ##V << " = " << V << endl; \
|
||||
strstream __s;\
|
||||
__s << __FILE__ << "[" << __LINE__ << \
|
||||
"]: " << ##V << " = " << V << '\n' << '\0';\
|
||||
OutputDebugString(__s.str());\
|
||||
DEBUGUNLOCK; \
|
||||
}
|
||||
|
||||
|
||||
#define DBGMSG(X)\
|
||||
{\
|
||||
DEBUGLOCK; \
|
||||
if (MsgManager::debugStream()) \
|
||||
(*(MsgManager::debugStream())) << "DBG [" << __FILE__ << \
|
||||
" " << __LINE__ << "] " << X << endl;\
|
||||
strstream __s;\
|
||||
__s << "DBG [" << __FILE__ << \
|
||||
" " << __LINE__ << "] " << X << '\n' << '\0';\
|
||||
OutputDebugString(__s.str());\
|
||||
DEBUGUNLOCK; \
|
||||
}
|
||||
|
||||
// Just get a stream to the debugging device, no extra junk
|
||||
#define DBGSTREAM(X)\
|
||||
{\
|
||||
DEBUGLOCK; \
|
||||
if (MsgManager::debugStream()) \
|
||||
(*(MsgManager::debugStream())) << X;\
|
||||
strstream __s;\
|
||||
__s << X << '\0';\
|
||||
OutputDebugString(__s.str());\
|
||||
DEBUGUNLOCK; \
|
||||
}
|
||||
|
||||
// Verbosely execute a statement
|
||||
#define VERBOSE(X)\
|
||||
{ \
|
||||
DEBUGLOCK; \
|
||||
if (MsgManager::debugStream()) \
|
||||
(*(DebugManager::debugStream())) << __FILE__ << "[" << __LINE__ << \
|
||||
"]: " << ##X << endl; X \
|
||||
strstream __s;\
|
||||
__s << __FILE__ << "[" << __LINE__ << \
|
||||
"]: " << ##X << '\n' << '\0';\
|
||||
OutputDebugString(__s.str());\
|
||||
DEBUGUNLOCK; \
|
||||
}
|
||||
|
||||
#else // _WINDOWS
|
||||
|
||||
// Print a variable
|
||||
#define PVAR(v) \
|
||||
{ \
|
||||
DEBUGLOCK; \
|
||||
if (MsgManager::debugStream()) \
|
||||
(*(MsgManager::debugStream())) << __FILE__ << "[" << __LINE__ << \
|
||||
"]: " << ##V << " = " << V << endl; \
|
||||
DEBUGUNLOCK; \
|
||||
}
|
||||
|
||||
|
||||
#define DBGMSG(X)\
|
||||
{\
|
||||
DEBUGLOCK; \
|
||||
if (MsgManager::debugStream()) \
|
||||
(*(MsgManager::debugStream())) << "DBG [" << __FILE__ << \
|
||||
" " << __LINE__ << "] " << X << endl;\
|
||||
DEBUGUNLOCK; \
|
||||
}
|
||||
|
||||
// Just get a stream to the debugging device, no extra junk
|
||||
#define DBGSTREAM(X)\
|
||||
{\
|
||||
DEBUGLOCK; \
|
||||
if (MsgManager::debugStream()) \
|
||||
(*(MsgManager::debugStream())) << X;\
|
||||
DEBUGUNLOCK; \
|
||||
}
|
||||
|
||||
// Verbosely execute a statement
|
||||
#define VERBOSE(X)\
|
||||
{ \
|
||||
DEBUGLOCK; \
|
||||
if (MsgManager::debugStream()) \
|
||||
(*(DebugManager::debugStream())) << __FILE__ << "[" << __LINE__ << \
|
||||
"]: " << ##X << endl; X \
|
||||
DEBUGUNLOCK; \
|
||||
}
|
||||
#endif // _WINDOWS
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
//#undef DEBUGLOCK
|
||||
//#undef DEBUGUNLOCK
|
||||
|
||||
class MsgManager
|
||||
{
|
||||
protected:
|
||||
MsgManager();
|
||||
|
||||
public:
|
||||
static int setAllStreams(OutputDevice *device);
|
||||
static int ReplaceAllStreams(FileD *output_device, IN char *device_filename, IN char *copy_filename);
|
||||
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
|
597
Generals/Code/Tools/mangler/wlib/wstring.cpp
Normal file
597
Generals/Code/Tools/mangler/wlib/wstring.cpp
Normal 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: 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 <stdarg.h>
|
||||
|
||||
#include "wstring.h"
|
||||
|
||||
#define PADSIZE 32 // include a little padding on alloc for future growth
|
||||
|
||||
Wstring::Wstring() : str(NULL), strsize(0)
|
||||
{ }
|
||||
|
||||
Wstring::Wstring(IN char *string):str(NULL), strsize(0)
|
||||
{ set(string); }
|
||||
|
||||
Wstring::Wstring(IN Wstring &other):str(NULL), strsize(0)
|
||||
{
|
||||
if (other.str!=NULL)
|
||||
{
|
||||
str=new char[strlen(other.str)+PADSIZE+1];
|
||||
strsize=strlen(other.str)+PADSIZE+1;
|
||||
strcpy(str,other.str);
|
||||
}
|
||||
}
|
||||
|
||||
Wstring::~Wstring()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
bool Wstring::operator<(IN Wstring &other) RO
|
||||
{
|
||||
if (str == NULL && other.str == NULL)
|
||||
return false;
|
||||
|
||||
if (str == NULL)
|
||||
return true;
|
||||
|
||||
return ( strcmp(str, other.str) < 0 );
|
||||
}
|
||||
|
||||
bit8 Wstring::operator==(IN char *other) RO
|
||||
{
|
||||
if ((str==NULL)&&(other==NULL))
|
||||
return(TRUE);
|
||||
if(strcmp(str, other) != 0)
|
||||
return(FALSE);
|
||||
else
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
bit8 Wstring::operator==(IN Wstring &other) RO
|
||||
{
|
||||
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) RO
|
||||
{
|
||||
if(strcmp(str, other) != 0)
|
||||
return(TRUE);
|
||||
else
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
|
||||
bit8 Wstring::operator!=(IN Wstring &other) RO
|
||||
{
|
||||
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=(IN 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)
|
||||
{
|
||||
uint32 len;
|
||||
|
||||
if (s==NULL) // it's OK to cat nothing
|
||||
return(TRUE);
|
||||
|
||||
// Determine the length of the resultant string.
|
||||
len = strlen(s) + 1;
|
||||
if(str)
|
||||
len += strlen(str);
|
||||
|
||||
// Space check
|
||||
strgrow(len);
|
||||
|
||||
strcat(str, s);
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
bit8 Wstring::cat(uint32 size, IN char *s)
|
||||
{
|
||||
uint32 len;
|
||||
|
||||
// Determine the length of the resultant string.
|
||||
len = size + 1;
|
||||
if(str)
|
||||
len += strlen(str);
|
||||
|
||||
// Allocate memory for the new string.
|
||||
strgrow(len);
|
||||
|
||||
strncat(str, s, size);
|
||||
str[len-1]=0; // make sure null term'd
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
memmove(str+pos,str+pos+count,len-pos-count+1);
|
||||
|
||||
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;
|
||||
}
|
||||
return(removed);
|
||||
}
|
||||
|
||||
void Wstring::removeSpaces(void)
|
||||
{
|
||||
removeChar(' ');
|
||||
removeChar('\t');
|
||||
}
|
||||
|
||||
void Wstring::clear(void)
|
||||
{
|
||||
if(str)
|
||||
delete[](str);
|
||||
strsize=0;
|
||||
str=NULL;
|
||||
}
|
||||
|
||||
// This is usually used for raw storage instead of string ops...
|
||||
void Wstring::setSize(sint32 size)
|
||||
{
|
||||
clear();
|
||||
if (size<0)
|
||||
return;
|
||||
|
||||
str=new char[size];
|
||||
strsize=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) RO
|
||||
{
|
||||
if(!str)
|
||||
return "";
|
||||
return str;
|
||||
}
|
||||
|
||||
char Wstring::get(uint32 index) RO
|
||||
{
|
||||
if(index < strlen(str))
|
||||
return str[index];
|
||||
return(0);
|
||||
}
|
||||
|
||||
uint32 Wstring::length(void) RO
|
||||
{
|
||||
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);
|
||||
|
||||
strgrow(strlen(str)+strlen(instring)+1);
|
||||
memmove(str+pos+strlen(instring),str+pos,strlen(str)-pos+1);
|
||||
memmove(str+pos,instring,strlen(instring));
|
||||
|
||||
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 temp[2];
|
||||
temp[0]=k;
|
||||
temp[1]=0;
|
||||
return(insert(temp,pos));
|
||||
}
|
||||
|
||||
|
||||
// Joe Howes (05/19/2000): This function inserts commas to nicely format a
|
||||
// large number (i.e. 1234567890 -> 1,234,567,890). It doesn't really care
|
||||
// if the string is really a number or not.
|
||||
bit8 Wstring::beautifyNumber()
|
||||
{
|
||||
int len = length();
|
||||
int accum = 3 - (len % 3);
|
||||
int numcommas = 0;
|
||||
|
||||
|
||||
if( accum == 3 ) accum = -1;
|
||||
for(int i = 0; i < len; i++)
|
||||
{
|
||||
if( accum == 3 )
|
||||
{
|
||||
insert(',', i + numcommas);
|
||||
numcommas++;
|
||||
}
|
||||
accum = ( accum == 3 || accum == -1 ) ? 1 : accum + 1;
|
||||
}
|
||||
|
||||
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(IN char *replaceThis,IN 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;
|
||||
|
||||
strgrow(strlen(s)+1);
|
||||
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;
|
||||
|
||||
strgrow(size+1);
|
||||
strncpy(str,string,size);
|
||||
str[size]=0;
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// Added by Joe Howes. Takes a printf formatted string and a set of args.
|
||||
// The expanded string must not exceed 1k or twice the length of the format
|
||||
// string, whichever is larger. It would probably be better to traverse
|
||||
// the format string and properly calculate, the length so this will
|
||||
// work in all cases, but this should be good enough for 99% of Wstring usage.
|
||||
char Wstring::setFormatted(IN char *msg, ...)
|
||||
{
|
||||
if( msg == NULL || strlen(msg) <= 0 ) return FALSE;
|
||||
|
||||
char* string;
|
||||
va_list args;
|
||||
int len = (strlen(msg) < 1024) ? 1024 : (strlen(msg)*2);
|
||||
|
||||
string = new char[len];
|
||||
va_start(args, msg);
|
||||
vsprintf(string, msg, args);
|
||||
va_end(args);
|
||||
set(string);
|
||||
delete[] string;
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// This function converts all alphabetical characters in the string to lower
|
||||
// case.
|
||||
void Wstring::toLower(void)
|
||||
{
|
||||
uint32 i;
|
||||
int strlength=length();
|
||||
|
||||
for(i = 0; i < (uint32)strlength; i++)
|
||||
{
|
||||
if((str[i] >= 'A') && (str[i] <= 'Z'))
|
||||
str[i] = (sint8)tolower(str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This function converts all alphabetical characters in the string to upper
|
||||
// case.
|
||||
void Wstring::toUpper(void)
|
||||
{
|
||||
uint32 i;
|
||||
int strlength=length();
|
||||
|
||||
for(i = 0; i < (uint32)strlength; i++)
|
||||
{
|
||||
if((str[i] >= 'a') && (str[i] <= 'z'))
|
||||
str[i] = (sint8)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)
|
||||
{
|
||||
strgrow(len+1);
|
||||
str[len]=0;
|
||||
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) RO
|
||||
{
|
||||
int i;
|
||||
sint32 start;
|
||||
sint32 stop;
|
||||
|
||||
if (offset<0) // check for bad input
|
||||
return(-1);
|
||||
|
||||
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 >= (sint32)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);
|
||||
}
|
||||
|
||||
//
|
||||
// Make sure there's AT LEAST length bytes in this string object
|
||||
//
|
||||
void Wstring::strgrow(int length)
|
||||
{
|
||||
if (str==NULL)
|
||||
{
|
||||
str=new char[length+PADSIZE];
|
||||
str[0]=0;
|
||||
strsize=length+PADSIZE;
|
||||
return;
|
||||
}
|
||||
else if (strsize >= length) // no need to alloc more data
|
||||
return;
|
||||
else // bah, gotta grow...
|
||||
{
|
||||
char *newstr=new char[length+PADSIZE];
|
||||
strsize=length+PADSIZE;
|
||||
strcpy(newstr,str);
|
||||
delete[](str);
|
||||
str=newstr;
|
||||
return;
|
||||
}
|
||||
}
|
93
Generals/Code/Tools/mangler/wlib/wstring.h
Normal file
93
Generals/Code/Tools/mangler/wlib/wstring.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
** 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 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) RO;
|
||||
char get(uint32 index) RO;
|
||||
uint32 length(void) RO;
|
||||
bit8 insert(char c, uint32 pos);
|
||||
bit8 insert(char *instring, uint32 pos);
|
||||
bit8 beautifyNumber();
|
||||
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);
|
||||
char setFormatted(IN char *str, ...); // Added by Joe Howes
|
||||
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) RO;
|
||||
sint32 getLine(int offset, Wstring &out);
|
||||
void strgrow(int length);
|
||||
|
||||
bit8 operator==(IN char *other) RO;
|
||||
bit8 operator==(IN Wstring &other) RO;
|
||||
bit8 operator!=(IN char *other) RO;
|
||||
bit8 operator!=(IN Wstring &other) RO;
|
||||
|
||||
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);
|
||||
|
||||
bool operator<(IN Wstring &other) RO;
|
||||
|
||||
private:
|
||||
char *str; // Pointer to allocated string.
|
||||
int strsize; // allocated data length
|
||||
};
|
||||
|
||||
#endif
|
118
Generals/Code/Tools/mangler/wlib/wstypes.h
Normal file
118
Generals/Code/Tools/mangler/wlib/wstypes.h
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
** 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 : wstypes.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 WSTYPES_HEADER
|
||||
#define WSTYPES_HEADER
|
||||
|
||||
#ifdef _REENTRANT // reentrant = threaded
|
||||
// Headers with non threadsafe libs need to come before my hacky
|
||||
// threadsafe.h otherwise they won't compile
|
||||
|
||||
#include <time.h>
|
||||
#ifndef _WINDOWS
|
||||
#define _POSIX_C_SOURCE 199506L
|
||||
#define _POSIX_PTHREAD_SEMANTICS
|
||||
#define __EXTENSIONS__
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifndef _WINDOWS
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <dirent.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#include <sys/timeb.h>
|
||||
#endif
|
||||
#include "threadsafe.h" // enforce threadsafe-only calls
|
||||
#endif
|
||||
|
||||
#define adelete(X) (delete[](X))
|
||||
|
||||
#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.
|
||||
#ifdef IN
|
||||
#undef IN
|
||||
#endif
|
||||
#define IN const
|
||||
#define OUT
|
||||
#define INOUT
|
||||
#define _IN_ const
|
||||
|
||||
// Used to declare a function or method as const or Read Only
|
||||
#define RO const
|
||||
|
||||
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;
|
||||
|
||||
typedef float float32;
|
||||
typedef double float64;
|
||||
|
||||
#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 _WINDOWS
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
#endif
|
802
Generals/Code/Tools/mangler/wlib/wtime.cpp
Normal file
802
Generals/Code/Tools/mangler/wlib/wtime.cpp
Normal file
|
@ -0,0 +1,802 @@
|
|||
/*
|
||||
** 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/>.
|
||||
*/
|
||||
|
||||
/****************************************************************************\
|
||||
wtime Neal Kettler
|
||||
\****************************************************************************/
|
||||
|
||||
#include <ctype.h>
|
||||
#include "wtime.h"
|
||||
|
||||
static char *DAYS[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
|
||||
|
||||
static char *FULLDAYS[]={"Sunday","Monday","Tuesday","Wednesday","Thursday",
|
||||
"Friday","Saturday"};
|
||||
|
||||
static char *MONTHS[]={"Jan","Feb","Mar","Apr","May","Jun","Jul",
|
||||
"Aug","Sep","Oct","Nov","Dec"};
|
||||
|
||||
static char *FULLMONTHS[]={"January","February","March","April","May","June",
|
||||
"July","August","September","October","November","December"};
|
||||
|
||||
// MDC: Windows doesn't provide a localtime_r, so make our own...
|
||||
#ifdef _WINDOWS
|
||||
#ifdef _REENTRANT
|
||||
#include "critsec.h"
|
||||
static CritSec localtime_critsec;
|
||||
#undef localtime
|
||||
struct tm *localtime(const time_t *clockval);
|
||||
#endif // _REENTRANT
|
||||
|
||||
static struct tm *localtime_r(const time_t *clockval, struct tm *res) {
|
||||
#ifdef _REENTRANT
|
||||
localtime_critsec.lock();
|
||||
#endif
|
||||
struct tm *static_tm = localtime(clockval);
|
||||
res = (struct tm *)memcpy(res, static_tm, sizeof(tm));
|
||||
#ifdef _REENTRANT
|
||||
localtime_critsec.unlock();
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
#endif // _WINDOWS
|
||||
|
||||
Wtime::Wtime(void)
|
||||
{
|
||||
Update();
|
||||
}
|
||||
|
||||
Wtime::Wtime( Wtime &other )
|
||||
{
|
||||
sign=other.sign;
|
||||
sec=other.sec;
|
||||
usec=other.usec;
|
||||
}
|
||||
|
||||
Wtime::Wtime( uint32 other )
|
||||
{
|
||||
sign=POSITIVE;
|
||||
sec=other;
|
||||
usec=0;
|
||||
}
|
||||
|
||||
Wtime::~Wtime()
|
||||
{
|
||||
}
|
||||
|
||||
void Wtime::Update(void)
|
||||
{
|
||||
sign=POSITIVE;
|
||||
#ifdef _WINDOWS
|
||||
struct _timeb wintime;
|
||||
_ftime(&wintime);
|
||||
sec=wintime.time;
|
||||
usec=(wintime.millitm)*1000;
|
||||
#endif
|
||||
#ifndef _WINDOWS
|
||||
struct timeval unixtime;
|
||||
struct timezone unixtzone;
|
||||
gettimeofday(&unixtime,&unixtzone);
|
||||
sec=unixtime.tv_sec;
|
||||
usec=unixtime.tv_usec;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Parses a date string that's in modified RFC 1123 format
|
||||
// Can have a +minutes after the normal time
|
||||
// eg: Thu, 20 Jun 1996 17:33:49 +100
|
||||
// Returns true if successfully parsed, false otherwise
|
||||
bit8 Wtime::ParseDate(char *in)
|
||||
{
|
||||
int i;
|
||||
uint32 minOffset;
|
||||
struct tm t;
|
||||
char *ptr=in;
|
||||
while ((!isgraph(*ptr))&&(*ptr!=0)) ptr++; // skip to start of string
|
||||
if (*ptr==0) return(FALSE);
|
||||
t.tm_wday=-1;
|
||||
for (i=0; i<7; i++) // parse day of week
|
||||
if (strncmp(ptr,DAYS[i],strlen(DAYS[i]))==0)
|
||||
t.tm_wday=i;
|
||||
if (t.tm_wday==-1)
|
||||
return(FALSE);
|
||||
while ((!isdigit(*ptr))&&(*ptr!=0)) ptr++; // skip to day of month
|
||||
if (*ptr==0) return(FALSE);
|
||||
t.tm_mday=atoi(ptr);
|
||||
while ((!isalpha(*ptr))&&(*ptr!=0)) ptr++; // skip to month
|
||||
if (*ptr==0) return(FALSE);
|
||||
t.tm_mon=-1;
|
||||
for (i=0; i<12; i++) // match month
|
||||
if (strncmp(ptr,MONTHS[i],strlen(MONTHS[i]))==0) t.tm_mon=i;
|
||||
if (t.tm_mon==-1) return(FALSE);
|
||||
while ((!isdigit(*ptr))&&(*ptr!=0)) ptr++;
|
||||
if (*ptr==0) return(FALSE);
|
||||
t.tm_year=atoi(ptr);
|
||||
if (t.tm_year<70) // if they specify a 2 digit year, we'll be nice
|
||||
t.tm_year+=2000;
|
||||
else if (t.tm_year<100)
|
||||
t.tm_year+=1900;
|
||||
if (t.tm_year>2200) // I doubt my code will be around for another 203 years
|
||||
return(FALSE);
|
||||
while ((isdigit(*ptr))&&(*ptr!=0)) ptr++; // skip to end of year
|
||||
if (*ptr==0) return(FALSE);
|
||||
|
||||
while ((!isgraph(*ptr))&&(*ptr!=0)) ptr++; // skip to start of time
|
||||
if (*ptr==0) return(FALSE);
|
||||
|
||||
t.tm_hour=atoi(ptr);
|
||||
while ((*ptr!=':')&&(*ptr!=0)) ptr++;
|
||||
ptr++; // skip past colon
|
||||
if (*ptr==0) return(FALSE);
|
||||
t.tm_min=atoi(ptr);
|
||||
while ((*ptr!=':')&&(*ptr!=0)) ptr++;
|
||||
ptr++; // skip past colon
|
||||
if (*ptr==0) return(FALSE);
|
||||
t.tm_sec=atoi(ptr);
|
||||
t.tm_year%=100; // 1996 is stored as 96, not 1996
|
||||
t.tm_isdst=-1; // daylight savings info isn't available
|
||||
|
||||
sec=(uint32)(mktime(&t));
|
||||
if ((sint32)sec==-1)
|
||||
return(FALSE);
|
||||
|
||||
|
||||
// The next part of the time is OPTIONAL (+minutes)
|
||||
|
||||
// first skip past the seconds
|
||||
while ((isdigit(*ptr))&&(*ptr!=0)) ptr++;
|
||||
if (*ptr==0) return(TRUE);
|
||||
|
||||
// skip past any spaces
|
||||
while ((isspace(*ptr))&&(*ptr!=0)) ptr++;
|
||||
if (*ptr!='+')
|
||||
{
|
||||
//printf("\nNOPE ptr was '%s'\n",ptr);
|
||||
return(TRUE);
|
||||
}
|
||||
ptr++;
|
||||
if (*ptr==0)
|
||||
{
|
||||
//printf("\nPTR WAS 0\n");
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
minOffset=atol(ptr);
|
||||
//printf("\n\nAdding %d minutes!\n\n",minOffset);
|
||||
sec+=minOffset*60; // add the minutes as seconds
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// This takes the standard Microsoft time formatting string
|
||||
// make sure the out string is big enough
|
||||
// An example format would be "mm/dd/yy hh:mm:ss"
|
||||
// CHANGE: Joe Howes 06/30/99
|
||||
// To specify 12-hour format, use "aa" instead of "hh".
|
||||
// The hours will be 12 hour and the string will be
|
||||
// appended with " AM" or " PM".
|
||||
bit8 Wtime::FormatTime(char *out, char *format)
|
||||
{
|
||||
int lastWasH=0;
|
||||
int ampmflag = 0;
|
||||
out[0]=0;
|
||||
char *ptr=format;
|
||||
|
||||
if (*ptr=='"') ptr++; // skip past open quote if exists
|
||||
|
||||
while (*ptr!=0)
|
||||
{
|
||||
if (lastWasH>0)
|
||||
lastWasH--;
|
||||
|
||||
if (isspace(*ptr))
|
||||
{
|
||||
if (lastWasH==1) lastWasH=2;
|
||||
sprintf(out+strlen(out),"%c",*ptr);
|
||||
ptr+=1;
|
||||
}
|
||||
else if (strncmp(ptr,"\"",1)==0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (strncmp(ptr,":",1)==0)
|
||||
{
|
||||
if (lastWasH==1) lastWasH=2;
|
||||
sprintf(out+strlen(out),":");
|
||||
ptr+=1;
|
||||
}
|
||||
else if (strncmp(ptr,"/",1)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"/");
|
||||
ptr+=1;
|
||||
}
|
||||
else if (strncmp(ptr,"c",1)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%ld/%ld/%02ld %ld:%02ld:%02ld",GetMonth(),
|
||||
GetMDay(),GetYear()%100,GetHour(),GetMinute(),GetSecond());
|
||||
ptr+=1;
|
||||
}
|
||||
else if (strncmp(ptr,"dddddd",6)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%s %02ld, %ld",FULLMONTHS[GetMonth()-1],
|
||||
GetMDay(),GetYear());
|
||||
ptr+=6;
|
||||
}
|
||||
else if (strncmp(ptr,"ddddd",5)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%ld/%ld/%02ld",GetMonth(),GetMDay(),
|
||||
GetYear()%100);
|
||||
ptr+=5;
|
||||
}
|
||||
else if (strncmp(ptr,"dddd",4)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%s",FULLDAYS[GetWDay()-1]);
|
||||
ptr+=4;
|
||||
}
|
||||
else if (strncmp(ptr,"ddd",3)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%s",DAYS[GetWDay()-1]);
|
||||
ptr+=3;
|
||||
}
|
||||
else if (strncmp(ptr,"dd",2)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%02ld",GetMDay());
|
||||
ptr+=2;
|
||||
}
|
||||
else if (strncmp(ptr,"d",1)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%ld",GetMDay());
|
||||
ptr+=1;
|
||||
}
|
||||
else if (strncmp(ptr,"ww",2)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%02ld",GetYWeek());
|
||||
ptr+=2;
|
||||
}
|
||||
else if (strncmp(ptr,"w",1)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%ld",GetWDay());
|
||||
ptr+=1;
|
||||
}
|
||||
else if (strncmp(ptr,"mmmm",4)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%s",FULLMONTHS[GetMonth()-1]);
|
||||
ptr+=4;
|
||||
}
|
||||
else if (strncmp(ptr,"mmm",3)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%s",MONTHS[GetMonth()-1]);
|
||||
ptr+=3;
|
||||
}
|
||||
else if (strncmp(ptr,"mm",2)==0)
|
||||
{
|
||||
if (lastWasH==1)
|
||||
sprintf(out+strlen(out),"%02ld",GetMinute());
|
||||
else
|
||||
sprintf(out+strlen(out),"%02ld",GetMonth());
|
||||
ptr+=2;
|
||||
}
|
||||
else if (strncmp(ptr,"m",1)==0)
|
||||
{
|
||||
if (lastWasH==1)
|
||||
sprintf(out+strlen(out),"%ld",GetMinute());
|
||||
else
|
||||
sprintf(out+strlen(out),"%ld",GetMonth());
|
||||
ptr+=1;
|
||||
}
|
||||
else if (strncmp(ptr,"q",1)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%ld",((GetMonth()-1)/4)+1); // GetQuarter
|
||||
ptr+=1;
|
||||
}
|
||||
else if (strncmp(ptr,"yyyy",4)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%ld",GetYear());
|
||||
ptr+=4;
|
||||
}
|
||||
else if (strncmp(ptr,"yy",2)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%02ld",GetYear()%100);
|
||||
ptr+=2;
|
||||
}
|
||||
else if (strncmp(ptr,"y",1)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%ld",GetYDay());
|
||||
ptr+=1;
|
||||
}
|
||||
else if (strncmp(ptr,"hh",2)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%02ld",GetHour());
|
||||
lastWasH=2; // needs to be 1 after top of loop decs it
|
||||
ptr+=2;
|
||||
}
|
||||
else if (strncmp(ptr,"h",1)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%ld",GetHour());
|
||||
lastWasH=2; // needs to be 1 after top of loop decs it
|
||||
ptr+=1;
|
||||
}
|
||||
else if (strncmp(ptr,"nn",2)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%02ld",GetMinute());
|
||||
ptr+=2;
|
||||
}
|
||||
else if (strncmp(ptr,"n",1)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%ld",GetMinute());
|
||||
ptr+=1;
|
||||
}
|
||||
else if (strncmp(ptr,"ss",2)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%02ld",GetSecond());
|
||||
ptr+=2;
|
||||
}
|
||||
else if (strncmp(ptr,"s",1)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%ld",GetSecond());
|
||||
ptr+=1;
|
||||
}
|
||||
else if (strncmp(ptr,"ttttt",5)==0)
|
||||
{
|
||||
sprintf(out+strlen(out),"%ld:%02ld:%02ld",GetHour(),GetMinute(),
|
||||
GetSecond());
|
||||
ptr+=5;
|
||||
}
|
||||
else if (strncmp(ptr,"aa",2)==0)
|
||||
{
|
||||
uint32 tmp = (GetHour() <= 12) ? GetHour() : GetHour() - 12;
|
||||
sprintf(out+strlen(out),"%02ld", tmp);
|
||||
lastWasH=2; // needs to be 1 after top of loop decs it
|
||||
ptr+=2;
|
||||
ampmflag = 1;
|
||||
}
|
||||
else // an unknown char, move to next
|
||||
ptr++;
|
||||
}
|
||||
if(ampmflag)
|
||||
{
|
||||
char ampm[4];
|
||||
if( GetHour() < 12 )
|
||||
strcpy(ampm, " AM");
|
||||
else
|
||||
strcpy(ampm, " PM");
|
||||
sprintf(out+strlen(out), "%s", ampm);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// In addition to PrintTime & PrintDate there is the 'Print' function
|
||||
// which prints both in RFC 1123 format
|
||||
|
||||
void Wtime::PrintTime(FILE *out) const
|
||||
{
|
||||
char string[80];
|
||||
PrintTime(string);
|
||||
fprintf(out,"%s",string);
|
||||
}
|
||||
|
||||
void Wtime::PrintTime(char *out) const
|
||||
{
|
||||
sprintf(out," %02lu:%02lu:%02lu",GetHour(),GetMinute(),GetSecond());
|
||||
}
|
||||
|
||||
void Wtime::PrintDate(FILE *out) const
|
||||
{
|
||||
char string[80];
|
||||
PrintDate(string);
|
||||
fprintf(out,"%s",string);
|
||||
}
|
||||
|
||||
void Wtime::PrintDate(char *out) const
|
||||
{
|
||||
sprintf(out,"%s, %lu %s %lu",DAYS[GetWDay()-1],GetMDay(),MONTHS[GetMonth()-1],
|
||||
GetYear());
|
||||
}
|
||||
|
||||
uint32 Wtime::GetSec(void) const
|
||||
{
|
||||
return(sec);
|
||||
}
|
||||
|
||||
uint32 Wtime::GetUsec(void) const
|
||||
{
|
||||
return(usec);
|
||||
}
|
||||
|
||||
void Wtime::SetSec(uint32 newsec)
|
||||
{
|
||||
sec=newsec;
|
||||
}
|
||||
|
||||
void Wtime::SetUsec(uint32 newusec)
|
||||
{
|
||||
usec=newusec;
|
||||
}
|
||||
|
||||
void Wtime::Set(uint32 newsec, uint32 newusec)
|
||||
{
|
||||
sec=newsec;
|
||||
usec=newusec;
|
||||
}
|
||||
|
||||
// Get a timeval ptr from a Wtime class
|
||||
struct timeval *Wtime::GetTimeval(void)
|
||||
{
|
||||
static struct timeval tv;
|
||||
tv.tv_sec=sec;
|
||||
tv.tv_usec=usec;
|
||||
return(&tv);
|
||||
}
|
||||
|
||||
// Get a timeval ptr from a Wtime class
|
||||
void Wtime::GetTimevalMT(struct timeval &tv)
|
||||
{
|
||||
tv.tv_sec=sec;
|
||||
tv.tv_usec=usec;
|
||||
}
|
||||
|
||||
|
||||
uint32 Wtime::GetSecond(void) const
|
||||
{
|
||||
struct tm t;
|
||||
struct tm *tptr;
|
||||
tptr=localtime_r((time_t *)&sec,&t);
|
||||
return(tptr->tm_sec);
|
||||
}
|
||||
uint32 Wtime::GetMinute(void) const
|
||||
{
|
||||
struct tm t;
|
||||
struct tm *tptr;
|
||||
tptr=localtime_r((time_t *)&sec,&t);
|
||||
return(tptr->tm_min);
|
||||
}
|
||||
uint32 Wtime::GetHour(void) const
|
||||
{
|
||||
struct tm t;
|
||||
struct tm *tptr;
|
||||
tptr=localtime_r((time_t *)&sec,&t);
|
||||
return(tptr->tm_hour);
|
||||
}
|
||||
uint32 Wtime::GetMDay(void) const
|
||||
{
|
||||
struct tm t;
|
||||
struct tm *tptr;
|
||||
tptr=localtime_r((time_t *)&sec,&t);
|
||||
return(tptr->tm_mday);
|
||||
}
|
||||
uint32 Wtime::GetWDay(void) const
|
||||
{
|
||||
struct tm t;
|
||||
struct tm *tptr;
|
||||
tptr=localtime_r((time_t *)&sec,&t);
|
||||
return(tptr->tm_wday+1);
|
||||
}
|
||||
uint32 Wtime::GetYDay(void) const
|
||||
{
|
||||
struct tm t;
|
||||
struct tm *tptr;
|
||||
tptr=localtime_r((time_t *)&sec,&t);
|
||||
return(tptr->tm_yday+1);
|
||||
}
|
||||
uint32 Wtime::GetYWeek(void) const
|
||||
{
|
||||
uint32 yweek;
|
||||
uint32 yday=GetYDay();
|
||||
uint32 wday=GetWDay();
|
||||
//phase holds the first weekday of the year. If (Jan 1 = Sun) phase = 0
|
||||
sint32 phase=((wday-yday)%7);
|
||||
if (phase<0) phase+=7;
|
||||
yweek=((yday+phase-1)/7)+1;
|
||||
return(yweek);
|
||||
}
|
||||
uint32 Wtime::GetMonth(void) const
|
||||
{
|
||||
struct tm t;
|
||||
struct tm *tptr;
|
||||
tptr=localtime_r((time_t *)&sec,&t);
|
||||
return(tptr->tm_mon+1);
|
||||
}
|
||||
|
||||
uint32 Wtime::GetYear(void) const
|
||||
{
|
||||
struct tm t;
|
||||
struct tm *tptr;
|
||||
tptr=localtime_r((time_t *)&sec,&t);
|
||||
if ((tptr->tm_year)>=70)
|
||||
return((tptr->tm_year)+1900);
|
||||
else
|
||||
return((tptr->tm_year)+2000);
|
||||
}
|
||||
|
||||
|
||||
bit8 Wtime::GetSign(void) const
|
||||
{
|
||||
return(sign);
|
||||
}
|
||||
|
||||
// 1 = *this > other
|
||||
//-1 = *this < other
|
||||
// 0 = *this == other
|
||||
int Wtime::Compare(const Wtime &other) const
|
||||
{
|
||||
if ((sec==other.sec)&&(usec==other.usec))
|
||||
return(0); // equal
|
||||
|
||||
else if (sec>other.sec)
|
||||
return(1);
|
||||
else if (sec<other.sec)
|
||||
return(-1);
|
||||
else if (usec>other.usec)
|
||||
return(1);
|
||||
else
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
bit8 Wtime::operator == ( const Wtime &other ) const
|
||||
{
|
||||
bit8 retval=Compare(other);
|
||||
if (retval==0)
|
||||
return(TRUE);
|
||||
else
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
bit8 Wtime::operator != ( const Wtime &other ) const
|
||||
{
|
||||
bit8 retval=Compare(other);
|
||||
if (retval==0)
|
||||
return(FALSE);
|
||||
else
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
bit8 Wtime::operator < ( const Wtime &other ) const
|
||||
{
|
||||
int retval=Compare(other);
|
||||
if (retval==-1)
|
||||
return(TRUE);
|
||||
else
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
bit8 Wtime::operator > ( const Wtime &other ) const
|
||||
{
|
||||
int retval=Compare(other);
|
||||
if (retval==1)
|
||||
return(TRUE);
|
||||
else
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
bit8 Wtime::operator <= ( const Wtime &other ) const
|
||||
{
|
||||
int retval=Compare(other);
|
||||
if ((retval==-1)||(retval==0))
|
||||
return(TRUE);
|
||||
else
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
bit8 Wtime::operator >= ( const Wtime &other ) const
|
||||
{
|
||||
int retval=Compare(other);
|
||||
if ((retval==1)||(retval==0))
|
||||
return(TRUE);
|
||||
else
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
|
||||
// None of the operators pay attention to sign
|
||||
// only the functions that begin with 'Signed'
|
||||
void Wtime::SignedAdd(const Wtime &other)
|
||||
{
|
||||
Wtime temp;
|
||||
|
||||
if ((sign==POSITIVE)&&(other.sign==POSITIVE))
|
||||
{
|
||||
*this+=other;
|
||||
sign=POSITIVE;
|
||||
}
|
||||
else if ((sign==POSITIVE)&&(other.sign==NEGATIVE))
|
||||
{
|
||||
if (*this>other)
|
||||
{
|
||||
*this-=other;
|
||||
sign=POSITIVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp=other;
|
||||
temp-=*this;
|
||||
*this=temp;
|
||||
sign=NEGATIVE;
|
||||
}
|
||||
}
|
||||
else if ((sign==NEGATIVE)&&(other.sign==POSITIVE))
|
||||
{
|
||||
if (*this<other)
|
||||
{
|
||||
temp=other;
|
||||
temp-=*this;
|
||||
*this=temp;
|
||||
sign=POSITIVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*this-=other;
|
||||
sign=NEGATIVE;
|
||||
}
|
||||
}
|
||||
else if ((sign==NEGATIVE)&&(other.sign==NEGATIVE))
|
||||
{
|
||||
*this+=other;
|
||||
sign=NEGATIVE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// None of the operators pay attention to sign
|
||||
// only the functions that begin with 'Signed'
|
||||
void Wtime::SignedSubtract(const Wtime &other)
|
||||
{
|
||||
Wtime temp;
|
||||
|
||||
if ((sign==POSITIVE)&&(other.sign==NEGATIVE))
|
||||
{
|
||||
*this+=other;
|
||||
sign=POSITIVE;
|
||||
}
|
||||
else if ((sign==POSITIVE)&&(other.sign==POSITIVE))
|
||||
{
|
||||
if (*this>other)
|
||||
{
|
||||
*this-=other;
|
||||
sign=POSITIVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp=other;
|
||||
temp-=*this;
|
||||
*this=temp;
|
||||
sign=NEGATIVE;
|
||||
}
|
||||
}
|
||||
else if ((sign==NEGATIVE)&&(other.sign==NEGATIVE))
|
||||
{
|
||||
if (*this<other)
|
||||
{
|
||||
temp=other;
|
||||
temp-=*this;
|
||||
*this=temp;
|
||||
sign=POSITIVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*this-=other;
|
||||
sign=NEGATIVE;
|
||||
}
|
||||
}
|
||||
else if ((sign==NEGATIVE)&&(other.sign==POSITIVE))
|
||||
{
|
||||
*this+=other;
|
||||
sign=NEGATIVE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Wtime &Wtime::operator += (const Wtime &other)
|
||||
{
|
||||
sec+=other.sec;
|
||||
usec+=other.usec;
|
||||
if (usec>1000000)
|
||||
{
|
||||
sec++;
|
||||
usec-=1000000;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Wtime &Wtime::operator -= (const Wtime &other)
|
||||
{
|
||||
sint32 temp;
|
||||
if (Compare(other)==-1)
|
||||
{
|
||||
sec=0; // can't handle negative time
|
||||
usec=0;
|
||||
return *this;
|
||||
}
|
||||
sec-=other.sec;
|
||||
temp=(sint32)usec;
|
||||
temp-=(sint32)other.usec;
|
||||
if (temp<0)
|
||||
{
|
||||
sec--;
|
||||
temp+=1000000;
|
||||
}
|
||||
usec=temp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Wtime Wtime::operator - (Wtime &other)
|
||||
{
|
||||
Wtime temp(*this);
|
||||
temp-=other;
|
||||
return(temp);
|
||||
}
|
||||
|
||||
Wtime Wtime::operator + (Wtime &other)
|
||||
{
|
||||
Wtime temp(*this);
|
||||
temp+=other;
|
||||
return(temp);
|
||||
}
|
||||
|
||||
|
||||
Wtime &Wtime::operator = (const Wtime &other)
|
||||
{
|
||||
sign=other.sign;
|
||||
sec=other.sec;
|
||||
usec=other.usec;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Wtime &Wtime::operator += (const uint32 other)
|
||||
{
|
||||
sec+=other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Wtime &Wtime::operator -= (const uint32 other)
|
||||
{
|
||||
sec-=other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Wtime Wtime::operator - (uint32 other)
|
||||
{
|
||||
Wtime temp(*this);
|
||||
temp-=other;
|
||||
return(temp);
|
||||
}
|
||||
|
||||
|
||||
Wtime Wtime::operator + (uint32 other)
|
||||
{
|
||||
Wtime temp(*this);
|
||||
temp+=other;
|
||||
return(temp);
|
||||
}
|
||||
|
||||
|
||||
Wtime &Wtime::operator = (const uint32 other)
|
||||
{
|
||||
sign=POSITIVE;
|
||||
sec=other;
|
||||
usec=0;
|
||||
return *this;
|
||||
}
|
128
Generals/Code/Tools/mangler/wlib/wtime.h
Normal file
128
Generals/Code/Tools/mangler/wlib/wtime.h
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
** 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/>.
|
||||
*/
|
||||
|
||||
/****************************************************************************\
|
||||
wtime Neal Kettler
|
||||
|
||||
\****************************************************************************/
|
||||
#ifndef WTIME_HEADER
|
||||
#define WTIME_HEADER
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef _WINDOWS
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <sys/timeb.h>
|
||||
#include <winsock.h>
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wstypes.h"
|
||||
|
||||
class Wtime
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
POSITIVE=0,
|
||||
NEGATIVE=1
|
||||
};
|
||||
|
||||
Wtime(); // init to system time
|
||||
Wtime( Wtime &other );
|
||||
Wtime( uint32 other );
|
||||
~Wtime();
|
||||
|
||||
void Update(); // Update members sec & usec to system time
|
||||
|
||||
|
||||
void PrintTime(FILE *out) const;
|
||||
void PrintTime(char *out) const;
|
||||
void PrintDate(FILE *out) const;
|
||||
void PrintDate(char *out) const;
|
||||
|
||||
uint32 GetSec(void) const; // Get member variable 'sec'
|
||||
uint32 GetUsec(void) const; // Get member variable 'usec'
|
||||
void SetSec(uint32 newsec);
|
||||
void SetUsec(uint32 newusec);
|
||||
void Set(uint32 newsec,uint32 newusec);
|
||||
bit8 ParseDate(char *in);
|
||||
bit8 FormatTime(char *out, char *format);
|
||||
|
||||
struct timeval *GetTimeval(void);
|
||||
void GetTimevalMT(struct timeval &tv);
|
||||
|
||||
uint32 GetSecond(void) const; // Second (0- 60) (60 is for a leap second)
|
||||
uint32 GetMinute(void) const; // Minute (0 - 59)
|
||||
uint32 GetHour(void) const; // Hour (0-23)
|
||||
uint32 GetMDay(void) const; // Day of Month (1-31)
|
||||
uint32 GetWDay(void) const; // Day of Week (1-7)
|
||||
uint32 GetYDay(void) const; // Day of Year (1-366)
|
||||
uint32 GetMonth(void) const; // Month (1-12)
|
||||
uint32 GetYWeek(void) const; // Week of Year (1-53)
|
||||
uint32 GetYear(void) const; // Year (e.g. 1997)
|
||||
|
||||
bit8 GetSign(void) const; // 0 = pos 1 = neg
|
||||
|
||||
int Compare(const Wtime &other) const;
|
||||
|
||||
// comparisons
|
||||
bit8 operator == ( const Wtime &other ) const;
|
||||
bit8 operator != ( const Wtime &other ) const;
|
||||
bit8 operator < ( const Wtime &other ) const;
|
||||
bit8 operator > ( const Wtime &other ) const;
|
||||
bit8 operator <= ( const Wtime &other ) const;
|
||||
bit8 operator >= ( const Wtime &other ) const;
|
||||
|
||||
// assignments
|
||||
Wtime &operator = (const Wtime &other);
|
||||
Wtime &operator = (const uint32 other);
|
||||
|
||||
// math
|
||||
// signed
|
||||
void SignedAdd(const Wtime &other);
|
||||
void SignedSubtract(const Wtime &other);
|
||||
|
||||
// unsigned
|
||||
Wtime &operator += (const Wtime &other);
|
||||
Wtime &operator -= (const Wtime &other);
|
||||
Wtime operator + (Wtime &other);
|
||||
Wtime operator - (Wtime &other);
|
||||
|
||||
Wtime &operator += (const uint32 other);
|
||||
Wtime &operator -= (const uint32 other);
|
||||
Wtime operator + (uint32 other);
|
||||
Wtime operator - (uint32 other);
|
||||
|
||||
protected:
|
||||
uint32 sec; // seconds since Jan 1, 1970
|
||||
uint32 usec; // microseconds (millionths of a second)
|
||||
bit8 sign; // for time differences 0 = pos 1 = neg
|
||||
};
|
||||
|
||||
#endif
|
1015
Generals/Code/Tools/mangler/wlib/xtime.cpp
Normal file
1015
Generals/Code/Tools/mangler/wlib/xtime.cpp
Normal file
File diff suppressed because it is too large
Load diff
146
Generals/Code/Tools/mangler/wlib/xtime.h
Normal file
146
Generals/Code/Tools/mangler/wlib/xtime.h
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
** 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/>.
|
||||
*/
|
||||
|
||||
/****************************************************************************\
|
||||
xtime Neal Kettler
|
||||
|
||||
This is version 2 of the Wtime library (now xtime). It now supports
|
||||
time storage from the year 0 to well after the sun
|
||||
will have gone supernova (OK, OK I admit it'll break in the
|
||||
year 5 Million.)
|
||||
|
||||
The call to update the current time will break in 2038.
|
||||
Hopefully by then somebody will replace the lame time()
|
||||
function :-)
|
||||
\****************************************************************************/
|
||||
|
||||
#ifndef XTIME_HEADER
|
||||
#define XTIME_HEADER
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef _WINDOWS
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <sys/timeb.h>
|
||||
#include <winsock.h>
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wstypes.h"
|
||||
|
||||
class Xtime
|
||||
{
|
||||
public:
|
||||
|
||||
Xtime(); // init to system time
|
||||
Xtime( Xtime &other );
|
||||
Xtime( time_t other ); // 1970-2038
|
||||
~Xtime();
|
||||
|
||||
void addSeconds(sint32 seconds);
|
||||
|
||||
bit8 getTime(int &month, int &mday, int &year, int &hour, int &minute,
|
||||
int &second) const;
|
||||
|
||||
bit8 setTime(int month, int mday, int year, int hour, int minute,
|
||||
int second);
|
||||
|
||||
void update(); // Update members sec & usec to system time
|
||||
// This will break after 2038
|
||||
|
||||
/********
|
||||
void PrintTime(FILE *out) const;
|
||||
void PrintTime(char *out) const;
|
||||
void PrintDate(FILE *out) const;
|
||||
void PrintDate(char *out) const;
|
||||
**********/
|
||||
|
||||
sint32 getDay(void) const; // Get days since year 0
|
||||
sint32 getMsec(void) const; // Get milliseconds into the day
|
||||
|
||||
void setDay(sint32 day);
|
||||
void setMsec(sint32 msec);
|
||||
|
||||
void set(sint32 newday, sint32 newmsec);
|
||||
bit8 ParseDate(char *in);
|
||||
bit8 FormatTime(char *out, char *format);
|
||||
|
||||
bit8 getTimeval(struct timeval &tv);
|
||||
|
||||
// All of these may return -1 if the time is invalid
|
||||
int getSecond(void) const; // Second (0-60) (60 is for a leap second)
|
||||
int getMinute(void) const; // Minute (0-59)
|
||||
int getHour(void) const; // Hour (0-23)
|
||||
int getMDay(void) const; // Day of Month (1-31)
|
||||
int getWDay(void) const; // Day of Week (1-7)
|
||||
int getYDay(void) const; // Day of Year (1-366) (366 = leap yr)
|
||||
int getMonth(void) const; // Month (1-12)
|
||||
int getYWeek(void) const; // Week of Year (1-53)
|
||||
int getYear(void) const; // Year (e.g. 1997)
|
||||
|
||||
// Modify the time components. Return FALSE if fail
|
||||
bit8 setSecond(sint32 sec);
|
||||
bit8 setMinute(sint32 min);
|
||||
bit8 setHour(sint32 hour);
|
||||
bit8 setYear(sint32 year);
|
||||
bit8 setMonth(sint32 month);
|
||||
bit8 setMDay(sint32 mday);
|
||||
|
||||
void normalize(void); // move msec overflows to the day
|
||||
|
||||
// Compare two times
|
||||
int compare(const Xtime &other) const;
|
||||
|
||||
// comparisons
|
||||
bit8 operator == ( const Xtime &other ) const;
|
||||
bit8 operator != ( const Xtime &other ) const;
|
||||
bit8 operator < ( const Xtime &other ) const;
|
||||
bit8 operator > ( const Xtime &other ) const;
|
||||
bit8 operator <= ( const Xtime &other ) const;
|
||||
bit8 operator >= ( const Xtime &other ) const;
|
||||
|
||||
// assignments
|
||||
Xtime &operator = (const Xtime &other);
|
||||
Xtime &operator = (const time_t other);
|
||||
|
||||
// signed
|
||||
Xtime &operator += (const Xtime &other);
|
||||
Xtime &operator -= (const Xtime &other);
|
||||
Xtime operator + (Xtime &other);
|
||||
Xtime operator - (Xtime &other);
|
||||
|
||||
Xtime &operator += (const time_t other);
|
||||
Xtime &operator -= (const time_t other);
|
||||
Xtime operator + (time_t other);
|
||||
Xtime operator - (time_t other);
|
||||
|
||||
protected:
|
||||
sint32 day_; // days since Jan 1, 0
|
||||
sint32 msec_; // milliseconds (thousandths of a sec)
|
||||
};
|
||||
|
||||
#endif
|
33
Generals/Code/Tools/mangler/wnet/Makefile
Normal file
33
Generals/Code/Tools/mangler/wnet/Makefile
Normal file
|
@ -0,0 +1,33 @@
|
|||
###########################################################################
|
||||
# TCP library makefile
|
||||
##########################################################################
|
||||
|
||||
#Define cc to be your C compiler
|
||||
CC = g++
|
||||
CFLAGS = -gstabs ${INCLUDE} -D_REENTRANT #-DDEBUG
|
||||
|
||||
#This tells make how to go from a .cpp to a .o
|
||||
.SUFFIXES: .cpp
|
||||
.cpp.o:
|
||||
${CC} ${CFLAGS} -c $<
|
||||
|
||||
INCLUDE = -I.. -I.
|
||||
|
||||
AR = ar -r
|
||||
RM = rm -f
|
||||
RANLIB = ranlib
|
||||
|
||||
############################################################################
|
||||
#Dont mess with any of this stuff
|
||||
OBJECTS = tcp.o udp.o packet.o field.o
|
||||
LIBRARY = libwnet.a
|
||||
|
||||
all: $(LIBRARY)
|
||||
|
||||
$(LIBRARY): $(OBJECTS)
|
||||
$(RM) $(LIBRARY)
|
||||
$(AR) $(LIBRARY) $(OBJECTS)
|
||||
$(RANLIB) $(LIBRARY)
|
||||
|
||||
clean:
|
||||
- rm -f $(LIBRARY) $(OBJECTS) core
|
319
Generals/Code/Tools/mangler/wnet/field.cpp
Normal file
319
Generals/Code/Tools/mangler/wnet/field.cpp
Normal file
|
@ -0,0 +1,319 @@
|
|||
/*
|
||||
** 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/>.
|
||||
*/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* Project Name : Westwood Auto Registration App *
|
||||
* *
|
||||
* File Name : FIELD.CPP *
|
||||
* *
|
||||
* Programmer : Philip W. Gorrow *
|
||||
* *
|
||||
* Start Date : 04/22/96 *
|
||||
* *
|
||||
* Last Update : April 22, 1996 [PWG] *
|
||||
* *
|
||||
* Actual member function for the field class. *
|
||||
*-------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#ifndef _WINDOWS
|
||||
#include <netinet/in.h>
|
||||
#else
|
||||
#define Win32_Winsock
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include "field.h"
|
||||
|
||||
|
||||
// private member func
|
||||
void FieldClass::Clear(void)
|
||||
{
|
||||
delete[](Data);
|
||||
|
||||
strcpy(ID,"");
|
||||
DataType=0;
|
||||
Size=0;
|
||||
Data=NULL;
|
||||
Next=NULL;
|
||||
}
|
||||
|
||||
|
||||
FieldClass::FieldClass(char *id, char data)
|
||||
{
|
||||
Data=NULL;
|
||||
Set(id,data);
|
||||
}
|
||||
|
||||
FieldClass::FieldClass(char *id, unsigned char data)
|
||||
{
|
||||
Data=NULL;
|
||||
Set(id,data);
|
||||
}
|
||||
|
||||
FieldClass::FieldClass(char *id, short data)
|
||||
{
|
||||
Data=NULL;
|
||||
Set(id,data);
|
||||
}
|
||||
|
||||
FieldClass::FieldClass(char *id, unsigned short data)
|
||||
{
|
||||
Data=NULL;
|
||||
Set(id,data);
|
||||
}
|
||||
|
||||
FieldClass::FieldClass(char *id, long data)
|
||||
{
|
||||
Data=NULL;
|
||||
Set(id,data);
|
||||
}
|
||||
|
||||
FieldClass::FieldClass(char *id, unsigned long data)
|
||||
{
|
||||
Data=NULL;
|
||||
Set(id,data);
|
||||
}
|
||||
|
||||
FieldClass::FieldClass(char *id, char *data)
|
||||
{
|
||||
Data=NULL;
|
||||
Set(id,data);
|
||||
}
|
||||
|
||||
FieldClass::FieldClass(char *id, void *data, int length)
|
||||
{
|
||||
Data=NULL;
|
||||
Set(id,data,length);
|
||||
}
|
||||
|
||||
void FieldClass::Set(char *id, char data)
|
||||
{
|
||||
FieldClass *Nextsave=Next;
|
||||
|
||||
Clear();
|
||||
strncpy(ID, id, sizeof(ID));
|
||||
DataType = TYPE_CHAR;
|
||||
Size = sizeof(data);
|
||||
Data = new char[Size];
|
||||
memcpy(Data, &data, Size);
|
||||
Next = Nextsave;
|
||||
}
|
||||
|
||||
void FieldClass::Set(char *id, unsigned char data)
|
||||
{
|
||||
FieldClass *Nextsave=Next;
|
||||
Clear();
|
||||
strncpy(ID, id, sizeof(ID));
|
||||
DataType = TYPE_UNSIGNED_CHAR;
|
||||
Size = sizeof(data);
|
||||
Data = new char[Size];
|
||||
memcpy(Data, &data, Size);
|
||||
Next = Nextsave;
|
||||
}
|
||||
|
||||
void FieldClass::Set(char *id, short data)
|
||||
{
|
||||
FieldClass *Nextsave=Next;
|
||||
Clear();
|
||||
strncpy(ID, id, sizeof(ID));
|
||||
DataType = TYPE_SHORT;
|
||||
Size = sizeof(data);
|
||||
Data = new char[Size];
|
||||
memcpy(Data, &data, Size);
|
||||
Next = Nextsave;
|
||||
}
|
||||
|
||||
void FieldClass::Set(char *id, unsigned short data)
|
||||
{
|
||||
FieldClass *Nextsave=Next;
|
||||
Clear();
|
||||
strncpy(ID, id, sizeof(ID));
|
||||
DataType = TYPE_UNSIGNED_SHORT;
|
||||
Size = sizeof(data);
|
||||
Data = new char[Size];
|
||||
memcpy(Data, &data, Size);
|
||||
Next = Nextsave;
|
||||
}
|
||||
|
||||
void FieldClass::Set(char *id, long data)
|
||||
{
|
||||
FieldClass *Nextsave=Next;
|
||||
Clear();
|
||||
strncpy(ID, id, sizeof(ID));
|
||||
DataType = TYPE_LONG;
|
||||
Size = sizeof(data);
|
||||
Data = new char[Size];
|
||||
memcpy(Data, &data, Size);
|
||||
Next = Nextsave;
|
||||
}
|
||||
|
||||
void FieldClass::Set(char *id, unsigned long data)
|
||||
{
|
||||
FieldClass *Nextsave=Next;
|
||||
Clear();
|
||||
strncpy(ID, id, sizeof(ID));
|
||||
DataType = TYPE_UNSIGNED_LONG;
|
||||
Size = sizeof(data);
|
||||
Data = new char[Size];
|
||||
memcpy(Data, &data, Size);
|
||||
Next = Nextsave;
|
||||
}
|
||||
|
||||
void FieldClass::Set(char *id, char *data)
|
||||
{
|
||||
FieldClass *Nextsave=Next;
|
||||
Clear();
|
||||
strncpy(ID, id, sizeof(ID));
|
||||
DataType = TYPE_STRING;
|
||||
Size = (unsigned short)(strlen(data)+1);
|
||||
Data = new char[Size];
|
||||
memcpy(Data, data, Size);
|
||||
Next = Nextsave;
|
||||
}
|
||||
|
||||
|
||||
void FieldClass::Set(char *id, void *data, int length)
|
||||
{
|
||||
FieldClass *Nextsave=Next;
|
||||
Clear();
|
||||
strncpy(ID, id, sizeof(ID));
|
||||
DataType = TYPE_CHUNK;
|
||||
Size = (unsigned short)length;
|
||||
Data = new char[Size];
|
||||
memcpy(Data, data, Size);
|
||||
Next = Nextsave;
|
||||
}
|
||||
|
||||
|
||||
FieldClass::~FieldClass()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
// Fetch the datatype
|
||||
int FieldClass::Get_Type(void)
|
||||
{
|
||||
return(DataType);
|
||||
}
|
||||
|
||||
void *FieldClass::Get_Data(void)
|
||||
{
|
||||
return(Data);
|
||||
}
|
||||
|
||||
char *FieldClass::Get_ID(void)
|
||||
{
|
||||
return(ID);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* PACKETCLASS::HOST_TO_NET_FIELD -- Converts host field to net format *
|
||||
* *
|
||||
* INPUT: FIELD * to the data field we need to convert *
|
||||
* *
|
||||
* OUTPUT: none *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/22/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
void FieldClass::Host_To_Net(void)
|
||||
{
|
||||
//
|
||||
// Before we convert the data type, we should convert the actual data
|
||||
// sent.
|
||||
//
|
||||
switch (DataType) {
|
||||
case TYPE_CHAR:
|
||||
case TYPE_UNSIGNED_CHAR:
|
||||
case TYPE_STRING:
|
||||
break;
|
||||
|
||||
case TYPE_SHORT:
|
||||
case TYPE_UNSIGNED_SHORT:
|
||||
*((unsigned short *)Data) = htons(*((unsigned short *)Data));
|
||||
break;
|
||||
|
||||
case TYPE_LONG:
|
||||
case TYPE_UNSIGNED_LONG:
|
||||
*((unsigned long *)Data) = htonl(*((unsigned long *)Data));
|
||||
break;
|
||||
|
||||
//
|
||||
// Might be good to insert some type of error message here for unknown
|
||||
// datatypes -- but will leave that for later.
|
||||
//
|
||||
default:
|
||||
break;
|
||||
}
|
||||
//
|
||||
// Finally convert over the data type and the size of the packet.
|
||||
//
|
||||
DataType = htons(DataType);
|
||||
Size = htons(Size);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* PACKETCLASS::NET_TO_HOST_FIELD -- Converts net field to host format *
|
||||
* *
|
||||
* INPUT: FIELD * to the data field we need to convert *
|
||||
* *
|
||||
* OUTPUT: none *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/22/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
void FieldClass::Net_To_Host(void)
|
||||
{
|
||||
//
|
||||
// Finally convert over the data type and the size of the packet.
|
||||
//
|
||||
DataType = ntohs(DataType);
|
||||
Size = ntohs(Size);
|
||||
|
||||
//
|
||||
// Before we convert the data type, we should convert the actual data
|
||||
// sent.
|
||||
//
|
||||
switch (DataType) {
|
||||
case TYPE_CHAR:
|
||||
case TYPE_UNSIGNED_CHAR:
|
||||
case TYPE_STRING:
|
||||
break;
|
||||
|
||||
case TYPE_SHORT:
|
||||
case TYPE_UNSIGNED_SHORT:
|
||||
*((unsigned short *)Data) = ntohs(*((unsigned short *)Data));
|
||||
break;
|
||||
|
||||
case TYPE_LONG:
|
||||
case TYPE_UNSIGNED_LONG:
|
||||
*((unsigned long *)Data) = ntohl(*((unsigned long *)Data));
|
||||
break;
|
||||
|
||||
//
|
||||
// Might be good to insert some type of error message here for unknown
|
||||
// datatypes -- but will leave that for later.
|
||||
//
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
101
Generals/Code/Tools/mangler/wnet/field.h
Normal file
101
Generals/Code/Tools/mangler/wnet/field.h
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
** 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/>.
|
||||
*/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* Project Name : Westwood Auto Registration App *
|
||||
* *
|
||||
* File Name : FIELD.H *
|
||||
* *
|
||||
* Programmer : Philip W. Gorrow *
|
||||
* *
|
||||
* Start Date : 04/22/96 *
|
||||
* *
|
||||
* Last Update : April 22, 1996 [PWG] *
|
||||
* *
|
||||
* This module takes care of maintaining the field list used to process *
|
||||
* packets. *
|
||||
* *
|
||||
*-------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#define FIELD_HEADER_SIZE (sizeof(FieldClass) - (sizeof(void *) * 2))
|
||||
|
||||
#define TYPE_CHAR 1
|
||||
#define TYPE_UNSIGNED_CHAR 2
|
||||
#define TYPE_SHORT 3
|
||||
#define TYPE_UNSIGNED_SHORT 4
|
||||
#define TYPE_LONG 5
|
||||
#define TYPE_UNSIGNED_LONG 6
|
||||
#define TYPE_STRING 7
|
||||
#define TYPE_CHUNK 20
|
||||
|
||||
class PacketClass;
|
||||
|
||||
class FieldClass
|
||||
{
|
||||
public:
|
||||
friend PacketClass;
|
||||
//
|
||||
// Define constructors to be able to create all the different kinds
|
||||
// of fields.
|
||||
//
|
||||
FieldClass(void) {};
|
||||
FieldClass(char *id, char data);
|
||||
FieldClass(char *id, unsigned char data);
|
||||
FieldClass(char *id, short data);
|
||||
FieldClass(char *id, unsigned short data);
|
||||
FieldClass(char *id, long data);
|
||||
FieldClass(char *id, unsigned long data);
|
||||
FieldClass(char *id, char *data);
|
||||
FieldClass(char *id, void *data, int length);
|
||||
|
||||
~FieldClass();
|
||||
|
||||
// Change the field contents
|
||||
void Set(char *id, char data);
|
||||
void Set(char *id, unsigned char data);
|
||||
void Set(char *id, short data);
|
||||
void Set(char *id, unsigned short data);
|
||||
void Set(char *id, long data);
|
||||
void Set(char *id, unsigned long data);
|
||||
void Set(char *id, char *data);
|
||||
void Set(char *id, void *data, int length);
|
||||
|
||||
int Get_Type(void); // get the datatype of this field
|
||||
unsigned short Get_Size(void) { return Size; }
|
||||
void * Get_Data(void); // get the datatype of this field
|
||||
char * Get_ID(void); // get the datatype of this field
|
||||
|
||||
void Host_To_Net(void);
|
||||
void Net_To_Host(void);
|
||||
|
||||
private:
|
||||
|
||||
void Clear(void); // dealloc mem & zero safely
|
||||
|
||||
char ID[4]; // id value of this field
|
||||
unsigned short DataType; // id of the data type we are using
|
||||
unsigned short Size; // size of the data portion of this field
|
||||
char *Data; // pointer to the data portion of this field
|
||||
FieldClass *Next; // pointer to the next field in the field list
|
||||
};
|
||||
|
||||
|
||||
|
522
Generals/Code/Tools/mangler/wnet/packet.cpp
Normal file
522
Generals/Code/Tools/mangler/wnet/packet.cpp
Normal file
|
@ -0,0 +1,522 @@
|
|||
/*
|
||||
** 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/>.
|
||||
*/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* Project Name : Westwood Auto Registration App *
|
||||
* *
|
||||
* File Name : PACKET.CPP *
|
||||
* *
|
||||
* Programmer : Philip W. Gorrow *
|
||||
* *
|
||||
* Start Date : 04/22/96 *
|
||||
* *
|
||||
* Last Update : April 24, 1996 [PWG] *
|
||||
* *
|
||||
*-------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* *PacketClass::Find_Field -- Finds a field if it exists in the packets *
|
||||
* Get_Field -- Find specified name and returns data *
|
||||
* PacketClass::~PacketClass -- destroys a packet class be freeing list *
|
||||
* PacketClass::Add_Field -- Adds a FieldClass entry to head of packet li*
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#ifndef _WINDOWS
|
||||
#include <netinet/in.h>
|
||||
#else
|
||||
#define Win32_Winsock
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "packet.h"
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* PACKETCLASS::~PACKETCLASS -- destroys a packet class be freeing list *
|
||||
* *
|
||||
* INPUT: none *
|
||||
* *
|
||||
* OUTPUT: none *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/24/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
PacketClass::~PacketClass()
|
||||
{
|
||||
FieldClass *current;
|
||||
FieldClass *next;
|
||||
|
||||
//
|
||||
// Loop through the entire field list and delete each entry.
|
||||
//
|
||||
for (current = Head; current; current = next) {
|
||||
next = current->Next;
|
||||
delete(current);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* PACKETCLASS::ADD_FIELD -- Adds a FieldClass entry to head of packet li *
|
||||
* *
|
||||
* INPUT: FieldClass * - a properly constructed field class entry. *
|
||||
* *
|
||||
* OUTPUT: none *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/24/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
void PacketClass::Add_Field(FieldClass *field)
|
||||
{
|
||||
field->Next = Head;
|
||||
Head = field;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* PACKETCLASS::PACKETCLASS -- Creates a Packet object from a COMMS packe *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/22/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
PacketClass::PacketClass(char *curbuf)
|
||||
{
|
||||
int remaining_size;
|
||||
//
|
||||
// Pull the size and packet ID out of the linear packet stream.
|
||||
//
|
||||
Size = *((unsigned short *)curbuf);
|
||||
curbuf += sizeof(unsigned short);
|
||||
Size = ntohs(Size);
|
||||
ID = *((short *)curbuf);
|
||||
curbuf += sizeof(unsigned short);
|
||||
ID = ntohs(ID);
|
||||
Head = NULL;
|
||||
|
||||
//
|
||||
// Calculate the remaining size so that we can loop through the
|
||||
// packets and extract them.
|
||||
//
|
||||
remaining_size = Size - 4;
|
||||
|
||||
//
|
||||
// Loop through the linear packet until we run out of room and
|
||||
// create a field for each.
|
||||
//
|
||||
while (remaining_size > 0)
|
||||
{
|
||||
FieldClass *field = new FieldClass;
|
||||
|
||||
//
|
||||
// Copy the adjusted header into the buffer and then advance the buffer
|
||||
//
|
||||
memcpy(field, curbuf, FIELD_HEADER_SIZE);
|
||||
curbuf += FIELD_HEADER_SIZE;
|
||||
remaining_size -= FIELD_HEADER_SIZE;
|
||||
|
||||
//
|
||||
// Copy the data into the buffer
|
||||
//
|
||||
int size = ntohs(field->Size);
|
||||
field->Data = new char[size];
|
||||
memcpy(field->Data, curbuf, size);
|
||||
curbuf += size;
|
||||
remaining_size -= size;
|
||||
|
||||
//
|
||||
// Make sure we allow for the pad bytes.
|
||||
//
|
||||
int pad = (4 - (ntohs(field->Size) & 3)) & 3;
|
||||
curbuf += pad;
|
||||
remaining_size -= pad;
|
||||
|
||||
//
|
||||
// Convert the field back to the host format
|
||||
//
|
||||
field->Net_To_Host();
|
||||
|
||||
//
|
||||
// Finally add the field to the field list in the packet
|
||||
// structure.
|
||||
//
|
||||
Add_Field(field);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* CREATE_COMMS_PACKET -- Walks field list creating a packet *
|
||||
* *
|
||||
* INPUT: short - the id of the packet so the server can identify it *
|
||||
* unsigned short & - the size of the packet returned here *
|
||||
* *
|
||||
* OUTPUT: void * pointer to the linear packet data *
|
||||
* *
|
||||
* WARNINGS: This routine allocates memory that the user is responsible *
|
||||
* for freeing. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/22/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
char *PacketClass::Create_Comms_Packet(int &size)
|
||||
{
|
||||
FieldClass *current;
|
||||
|
||||
//
|
||||
// Size starts at four because that is the size of the packet header.
|
||||
//
|
||||
size = 4;
|
||||
|
||||
//
|
||||
// Take a quick spin through and calculate the size of the packet we
|
||||
// are building.
|
||||
//
|
||||
for (current = Head; current; current=current->Next)
|
||||
{
|
||||
size += (unsigned short)FIELD_HEADER_SIZE; // add in packet header size
|
||||
size += current->Size; // add in data size
|
||||
size += (4 - (size & 3)) & 3; // add in pad value to dword align next packet
|
||||
}
|
||||
|
||||
//
|
||||
// Now that we know the size allocate a buffer big enough to hold the
|
||||
// packet.
|
||||
//
|
||||
char *retval = new char[size];
|
||||
char *curbuf = retval;
|
||||
|
||||
//
|
||||
// write the size into the packet header
|
||||
//
|
||||
*((unsigned short *)curbuf) = (unsigned short)htons(size);
|
||||
curbuf += sizeof(unsigned short);
|
||||
*((short *)curbuf) = htons(ID);
|
||||
curbuf += sizeof(unsigned short);
|
||||
|
||||
//
|
||||
// Ok now that the actual header information has been written we need to write out
|
||||
// field information.
|
||||
//
|
||||
for (current = Head; current; current = current->Next)
|
||||
{
|
||||
//
|
||||
// Temporarily convert the packet to net format (this saves alot of
|
||||
// effort, and seems safe...)
|
||||
//
|
||||
current->Host_To_Net();
|
||||
|
||||
//
|
||||
// Copy the adjusted header into the buffer and then advance the buffer
|
||||
//
|
||||
memcpy(curbuf, current, FIELD_HEADER_SIZE);
|
||||
curbuf += FIELD_HEADER_SIZE;
|
||||
|
||||
//
|
||||
// Copy the data into the buffer and then advance the buffer
|
||||
//
|
||||
memcpy(curbuf, current->Data, ntohs(current->Size));
|
||||
curbuf += ntohs(current->Size);
|
||||
|
||||
//
|
||||
// Finally take care of any pad bytes by setting them to 0
|
||||
//
|
||||
int pad = (4 - (ntohs(current->Size) & 3)) & 3;
|
||||
curbuf += pad;
|
||||
|
||||
current->Net_To_Host();
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* PACKETCLASS::FIND_FIELD -- Finds a field if it exists in the packets *
|
||||
* *
|
||||
* INPUT: char * - the id of the field we are looking for. *
|
||||
* *
|
||||
* OUTPUT: FieldClass * pointer to the field class *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/23/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
FieldClass *PacketClass::Find_Field(char *id)
|
||||
{
|
||||
for (FieldClass *current = Head; current; current = current->Next)
|
||||
{
|
||||
if ( strncmp(id, current->ID, 4) == 0)
|
||||
return current;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// gks 9/25/2000
|
||||
FieldClass *PacketClass::Get_Field_At(int position)
|
||||
{
|
||||
int i = 0;
|
||||
FieldClass *current = Head;
|
||||
for (; (current && (i < position)); current = current->Next, i++) {
|
||||
}
|
||||
|
||||
if (current) return current;
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
// gks 9/25/2000
|
||||
int PacketClass::Get_Num_Fields()
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (FieldClass *current = Head; current; current = current->Next, i++) {}
|
||||
|
||||
return i;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* GET_FIELD -- Find specified name and returns data *
|
||||
* *
|
||||
* INPUT: char * - the id of the field that holds the data. *
|
||||
* char & - the reference to store the data into *
|
||||
* *
|
||||
* OUTPUT: true if the field was found, false if it was not. *
|
||||
* *
|
||||
* WARNINGS: The data reference is not changed if the field is not *
|
||||
* found. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/23/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
bit8 PacketClass::Get_Field(char *id, char &data)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field) {
|
||||
data = *((char *)field->Data);
|
||||
}
|
||||
return((field) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* GET_FIELD -- Find specified name and returns data *
|
||||
* *
|
||||
* INPUT: char * - the id of the field that holds the data. *
|
||||
* unsigned char & - the reference to store the data into *
|
||||
* *
|
||||
* OUTPUT: true if the field was found, false if it was not. *
|
||||
* *
|
||||
* WARNINGS: The data reference is not changed if the field is not *
|
||||
* found. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/23/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
bit8 PacketClass::Get_Field(char *id, unsigned char &data)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field) {
|
||||
data = *((unsigned char *)field->Data);
|
||||
}
|
||||
return((field) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* GET_FIELD -- Find specified name and returns data *
|
||||
* *
|
||||
* INPUT: char * - the id of the field that holds the data. *
|
||||
* short & - the reference to store the data into *
|
||||
* *
|
||||
* OUTPUT: true if the field was found, false if it was not. *
|
||||
* *
|
||||
* WARNINGS: The data reference is not changed if the field is not *
|
||||
* found. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/23/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
bit8 PacketClass::Get_Field(char *id, short &data)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field) {
|
||||
data = *((short *)field->Data);
|
||||
}
|
||||
return((field) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* GET_FIELD -- Find specified name and returns data *
|
||||
* *
|
||||
* INPUT: char * - the id of the field that holds the data. *
|
||||
* unsigned short & - the reference to store the data into *
|
||||
* *
|
||||
* OUTPUT: true if the field was found, false if it was not. *
|
||||
* *
|
||||
* WARNINGS: The data reference is not changed if the field is not *
|
||||
* found. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/23/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
bit8 PacketClass::Get_Field(char *id, unsigned short &data)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field) {
|
||||
data = *((unsigned short *)field->Data);
|
||||
}
|
||||
return((field) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* GET_FIELD -- Find specified name and returns data *
|
||||
* *
|
||||
* INPUT: char * - the id of the field that holds the data. *
|
||||
* long & - the reference to store the data into *
|
||||
* *
|
||||
* OUTPUT: true if the field was found, false if it was not. *
|
||||
* *
|
||||
* WARNINGS: The data reference is not changed if the field is not *
|
||||
* found. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/23/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
bit8 PacketClass::Get_Field(char *id, long &data)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field) {
|
||||
data = *((long *)field->Data);
|
||||
}
|
||||
return((field) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bit8 PacketClass::Get_Field(char *id, int &data)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field) {
|
||||
data = *((int *)field->Data);
|
||||
}
|
||||
return((field) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* GET_FIELD -- Find specified name and returns data as a string *
|
||||
* *
|
||||
* INPUT: char * - the id of the field that holds the data. *
|
||||
* char * - the string to store the data into *
|
||||
* *
|
||||
* OUTPUT: true if the field was found, false if it was not. *
|
||||
* *
|
||||
* WARNINGS: The string is not changed if the field is not found. It *
|
||||
* is assumed that the string variabled specified by the *
|
||||
* pointer is large enough to hold the data. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/23/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
bit8 PacketClass::Get_Field(char *id, char *data)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field) {
|
||||
strcpy(data, (char *)field->Data);
|
||||
}
|
||||
return((field) ? true : false);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* GET_FIELD -- Find specified name and returns data *
|
||||
* *
|
||||
* INPUT: char * - the id of the field that holds the data. *
|
||||
* unsigned long & - the reference to store the data into *
|
||||
* *
|
||||
* OUTPUT: true if the field was found, false if it was not. *
|
||||
* *
|
||||
* WARNINGS: The data reference is not changed if the field is not *
|
||||
* found. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 04/23/1996 PWG : Created. *
|
||||
*========================================================================*/
|
||||
bit8 PacketClass::Get_Field(char *id, unsigned long &data)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field) {
|
||||
data = *((unsigned long *)field->Data);
|
||||
}
|
||||
return((field) ? true : false);
|
||||
}
|
||||
|
||||
bit8 PacketClass::Get_Field(char *id, unsigned &data)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field) {
|
||||
data = *((unsigned *)field->Data);
|
||||
}
|
||||
return((field) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* GET_FIELD -- Find specified name and returns data *
|
||||
* *
|
||||
* INPUT: char * - the id of the field that holds the data. *
|
||||
* void * - the reference to store the data into *
|
||||
* int - the length of the buffer passed in *
|
||||
* *
|
||||
* OUTPUT: true if the field was found, false if it was not. *
|
||||
* *
|
||||
* WARNINGS: The data reference is not changed if the field is not *
|
||||
* found. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 6/4/96 4:46PM ST : Created *
|
||||
*========================================================================*/
|
||||
bit8 PacketClass::Get_Field(char *id, void *data, int &length)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field) {
|
||||
memcpy (data, field->Data, MIN(field->Size, length));
|
||||
length = (int) field->Size;
|
||||
}
|
||||
return((field) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
unsigned short PacketClass::Get_Field_Size(char* id)
|
||||
{
|
||||
FieldClass *field = Find_Field(id);
|
||||
if (field)
|
||||
return field->Get_Size();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
108
Generals/Code/Tools/mangler/wnet/packet.h
Normal file
108
Generals/Code/Tools/mangler/wnet/packet.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
** 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/>.
|
||||
*/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* Project Name : Westwood Auto Registration App *
|
||||
* *
|
||||
* File Name : PACKET.H *
|
||||
* *
|
||||
* Programmer : Philip W. Gorrow *
|
||||
* *
|
||||
* Start Date : 04/19/96 *
|
||||
* *
|
||||
* Last Update : April 19, 1996 [PWG] *
|
||||
* *
|
||||
* This header defines the functions for the PacketClass. The packet *
|
||||
* class is used to create a linked list of field entries which can be *
|
||||
* converted to a linear packet in a COMMS API compatible format. *
|
||||
* *
|
||||
* Packets can be created empty and then have fields added to them or can *
|
||||
* be created from an existing linear packet. *
|
||||
* *
|
||||
*-------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "field.h"
|
||||
#include <wlib/wstypes.h>
|
||||
|
||||
|
||||
class PacketClass
|
||||
{
|
||||
public:
|
||||
|
||||
PacketClass(short id = 0)
|
||||
{
|
||||
Size = 0;
|
||||
ID = id;
|
||||
Head = 0;
|
||||
}
|
||||
PacketClass(char *cur_buf);
|
||||
~PacketClass();
|
||||
|
||||
//
|
||||
// This function allows us to add a field to the start of the list. As the field is just
|
||||
// a big linked list it makes no difference which end we add a member to.
|
||||
//
|
||||
void Add_Field(FieldClass *field);
|
||||
|
||||
//
|
||||
// These conveniance functions allow us to add a field directly to the list without
|
||||
// having to worry about newing one first.
|
||||
//
|
||||
void Add_Field(char *field, char data) {Add_Field(new FieldClass(field, data));};
|
||||
void Add_Field(char *field, unsigned char data) {Add_Field(new FieldClass(field, data));};
|
||||
void Add_Field(char *field, short data) {Add_Field(new FieldClass(field, data));};
|
||||
void Add_Field(char *field, unsigned short data) {Add_Field(new FieldClass(field, data));};
|
||||
void Add_Field(char *field, long data) {Add_Field(new FieldClass(field, data));};
|
||||
void Add_Field(char *field, unsigned long data) {Add_Field(new FieldClass(field, data));};
|
||||
void Add_Field(char *field, char *data) {Add_Field(new FieldClass(field, data));};
|
||||
void Add_Field(char *field, void *data, int length) {Add_Field(new FieldClass(field, data, length));};
|
||||
|
||||
//
|
||||
// These functions search for a field of a given name in the list and
|
||||
// return the data via a reference value.
|
||||
//
|
||||
FieldClass *Find_Field(char *id);
|
||||
|
||||
bit8 Get_Field(char *id, int &data);
|
||||
bit8 Get_Field(char *id, char &data);
|
||||
bit8 Get_Field(char *id, unsigned char &data);
|
||||
bit8 Get_Field(char *id, short &data);
|
||||
bit8 Get_Field(char *id, unsigned short &data);
|
||||
bit8 Get_Field(char *id, long &data);
|
||||
bit8 Get_Field(char *id, unsigned long &data);
|
||||
bit8 Get_Field(char *id, unsigned &data);
|
||||
bit8 Get_Field(char *id, char *data);
|
||||
bit8 Get_Field(char *id, void *data, int &length);
|
||||
unsigned short Get_Field_Size(char* id);
|
||||
|
||||
// gks 9/25/2000
|
||||
FieldClass *Get_Field_At(int position);
|
||||
int Get_Num_Fields();
|
||||
|
||||
char *Create_Comms_Packet(int &size);
|
||||
|
||||
private:
|
||||
unsigned short Size;
|
||||
short ID;
|
||||
FieldClass *Head;
|
||||
FieldClass *Current;
|
||||
};
|
||||
|
1242
Generals/Code/Tools/mangler/wnet/tcp.cpp
Normal file
1242
Generals/Code/Tools/mangler/wnet/tcp.cpp
Normal file
File diff suppressed because it is too large
Load diff
199
Generals/Code/Tools/mangler/wnet/tcp.h
Normal file
199
Generals/Code/Tools/mangler/wnet/tcp.h
Normal file
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
** 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/>.
|
||||
*/
|
||||
|
||||
/****************************************************************************\
|
||||
TCP Neal Kettler neal@westwood.com
|
||||
|
||||
\****************************************************************************/
|
||||
|
||||
#ifndef TCP_HEADER
|
||||
#define TCP_HEADER
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef _WINDOWS
|
||||
|
||||
#include <winsock.h>
|
||||
#include <io.h>
|
||||
#define close _close
|
||||
#define read _read
|
||||
#define write _write
|
||||
|
||||
#else //UNIX
|
||||
#include <netdb.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
|
||||
typedef signed int SOCKET;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef AIX
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
#define DEFAULT_PROTOCOL 0
|
||||
|
||||
#include "wlib/wstypes.h"
|
||||
#include "wlib/wdebug.h"
|
||||
#include "wlib/wtime.h"
|
||||
|
||||
class TCP
|
||||
{
|
||||
|
||||
// DATA ---------------
|
||||
|
||||
private:
|
||||
int mode; // client or server
|
||||
sint32 fd; // the primary FD
|
||||
|
||||
uint32 myIP; // after bind myIP & myPort will be
|
||||
uint16 myPort; // whatever we bound to
|
||||
|
||||
struct sockaddr_in addr;
|
||||
int maxFD; // value of the biggest FD
|
||||
int clientCount; // how many clients open
|
||||
|
||||
|
||||
sint32 inputDelay; // default delay for semi-blocking reads
|
||||
sint32 outputDelay; // default delay for semi-blocking writes
|
||||
|
||||
enum ConnectionState
|
||||
{
|
||||
CLOSED,
|
||||
CONNECTING,
|
||||
CONNECTED
|
||||
} connectionState; // What state is client FD in
|
||||
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
CLIENT = 1,
|
||||
SERVER = 2
|
||||
};
|
||||
|
||||
// These defines specify a system independent way to
|
||||
// get error codes for socket services.
|
||||
enum
|
||||
{
|
||||
OK, // Everything's cool
|
||||
UNKNOWN, // There was an error of unknown type
|
||||
ISCONN, // The socket is already connected
|
||||
INPROGRESS, // The socket is non-blocking and the operation
|
||||
// isn't done yet
|
||||
ALREADY, // The socket is already attempting a connection
|
||||
// but isn't done yet
|
||||
AGAIN, // Try again.
|
||||
ADDRINUSE, // Address already in use
|
||||
ADDRNOTAVAIL, // That address is not available on the remote host
|
||||
BADF, // Not a valid FD
|
||||
CONNREFUSED, // Connection was refused
|
||||
INTR, // Operation was interrupted
|
||||
NOTSOCK, // FD wasn't a socket
|
||||
PIPE, // That operation just made a SIGPIPE
|
||||
WOULDBLOCK, // That operation would block
|
||||
INVAL, // Invalid
|
||||
TIMEDOUT // Timeout
|
||||
};
|
||||
|
||||
// for client list (if this is a server)
|
||||
fd_set clientList;
|
||||
|
||||
|
||||
// CODE ----------------
|
||||
|
||||
public:
|
||||
TCP(int newMode);
|
||||
TCP(int newMode,sint16 socket);
|
||||
~TCP();
|
||||
bit8 Bind(uint32 IP,uint16 port,bit8 reuseAddr=FALSE);
|
||||
bit8 Bind(char *Host,uint16 port,bit8 reuseAddr=FALSE);
|
||||
|
||||
sint32 GetMaxFD(void);
|
||||
|
||||
bit8 Connect(uint32 IP,uint16 port);
|
||||
bit8 Connect(char *Host,uint16 port);
|
||||
bit8 ConnectAsync(uint32 IP,uint16 port);
|
||||
bit8 ConnectAsync(char *Host,uint16 port);
|
||||
|
||||
bit8 IsConnected(sint32 whichFD=0);
|
||||
|
||||
sint32 GetFD(void);
|
||||
sint32 GetClientCount(void) { return(clientCount); }
|
||||
|
||||
// Get IP or Port of a connected endpoint
|
||||
uint32 GetRemoteIP(sint32 whichFD=0);
|
||||
uint16 GetRemotePort(sint32 whichFD=0);
|
||||
|
||||
sint32 GetConnection(void);
|
||||
sint32 GetConnection(struct sockaddr *clientAddr);
|
||||
void WaitWrite(sint32 whichFD=0);
|
||||
bit8 CanWrite(sint32 whichFD=0);
|
||||
sint32 Write(const uint8 *msg,uint32 len,sint32 whichFD=0);
|
||||
sint32 WriteNB(uint8 *msg,uint32 len,sint32 whichFD=0);
|
||||
sint32 EncapsulatedWrite(uint8 *msg,uint32 len,sint32 whichFD=0);
|
||||
sint32 WriteString(char *msg,sint32 whichFD=0);
|
||||
sint32 Printf(sint32 whichFD,const char *format,...);
|
||||
sint32 Read(uint8 *msg,uint32 len,sint32 whichFD=0);
|
||||
sint32 TimedRead(uint8 *msg,uint32 len,int seconds,sint32 whichFD=0);
|
||||
sint32 Peek(uint8 *msg,uint32 len,sint32 whichFD=0);
|
||||
sint32 EncapsulatedRead(uint8 *msg,uint32 len,sint32 whichFD=0);
|
||||
|
||||
char *Gets(char *string,int n,int whichFD=0);
|
||||
|
||||
// Wait on all sockets (or a specified one)
|
||||
// return when ready for reading (or timeout occurs)
|
||||
int Wait(sint32 sec,sint32 usec,fd_set &returnSet,sint32 whichFD=0);
|
||||
int Wait(sint32 sec,sint32 usec,fd_set &inputSet,fd_set &returnSet);
|
||||
|
||||
int GetStatus(void);
|
||||
void ClearStatus(void);
|
||||
|
||||
//sint32 GetSockStatus(sint32 whichFD=0);
|
||||
|
||||
// give up ownership of the socket without closing it
|
||||
void DisownSocket(void);
|
||||
|
||||
sint32 Close(sint32 whichFD=0);
|
||||
sint32 CloseAll(void); // close all sockets (same as close for client)
|
||||
|
||||
sint32 SetBlocking(bit8 block,sint32 whichFD=0);
|
||||
|
||||
// Set default delays for semi-blocking reads & writes
|
||||
// default input = 5, output = 5
|
||||
// this is new and not used everywhere
|
||||
//
|
||||
bit8 SetInputDelay(sint32 delay) { inputDelay=delay; return(TRUE); };
|
||||
bit8 SetOutputDelay(sint32 delay) { outputDelay=delay; return(TRUE); };
|
||||
|
||||
};
|
||||
|
||||
#endif
|
372
Generals/Code/Tools/mangler/wnet/udp.cpp
Normal file
372
Generals/Code/Tools/mangler/wnet/udp.cpp
Normal file
|
@ -0,0 +1,372 @@
|
|||
/*
|
||||
** 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 "udp.h"
|
||||
#include "wlib/wdebug.h"
|
||||
|
||||
UDP::UDP()
|
||||
{
|
||||
fd=0;
|
||||
}
|
||||
|
||||
UDP::~UDP()
|
||||
{
|
||||
}
|
||||
|
||||
sint32 UDP::Bind(char *Host,uint16 port)
|
||||
{
|
||||
char hostName[100];
|
||||
struct hostent *hostStruct;
|
||||
struct in_addr *hostNode;
|
||||
|
||||
if (isdigit(Host[0]))
|
||||
return ( Bind( ntohl(inet_addr(Host)), port) );
|
||||
|
||||
strcpy(hostName, Host);
|
||||
|
||||
hostStruct = gethostbyname(Host);
|
||||
if (hostStruct == NULL)
|
||||
return (0);
|
||||
hostNode = (struct in_addr *) hostStruct->h_addr;
|
||||
return ( Bind(ntohl(hostNode->s_addr),port) );
|
||||
}
|
||||
|
||||
// You must call bind, implicit binding is for sissies
|
||||
// Well... you can get implicit binding if you pass 0 for either arg
|
||||
sint32 UDP::Bind(uint32 IP,uint16 Port)
|
||||
{
|
||||
int retval;
|
||||
int status;
|
||||
|
||||
IP=htonl(IP);
|
||||
Port=htons(Port);
|
||||
|
||||
addr.sin_family=AF_INET;
|
||||
addr.sin_port=Port;
|
||||
addr.sin_addr.s_addr=IP;
|
||||
fd=socket(AF_INET,SOCK_DGRAM,DEFAULT_PROTOCOL);
|
||||
#ifdef _WINDOWS
|
||||
if (fd==SOCKET_ERROR)
|
||||
fd=-1;
|
||||
#endif
|
||||
if (fd==-1)
|
||||
return(UNKNOWN);
|
||||
|
||||
retval=bind(fd,(struct sockaddr *)&addr,sizeof(addr));
|
||||
|
||||
#ifdef _WINDOWS
|
||||
if (retval==SOCKET_ERROR)
|
||||
retval=-1;
|
||||
#endif
|
||||
if (retval==-1)
|
||||
{
|
||||
status=GetStatus();
|
||||
//CERR("Bind failure (" << status << ") IP " << IP << " PORT " << Port )
|
||||
return(status);
|
||||
}
|
||||
|
||||
int namelen=sizeof(addr);
|
||||
getsockname(fd, (struct sockaddr *)&addr, &namelen);
|
||||
|
||||
myIP=ntohl(addr.sin_addr.s_addr);
|
||||
myPort=ntohs(addr.sin_port);
|
||||
|
||||
retval=SetBlocking(FALSE);
|
||||
if (retval==-1)
|
||||
fprintf(stderr,"Couldn't set nonblocking mode!\n");
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
bit8 UDP::getLocalAddr(uint32 &ip, uint16 &port)
|
||||
{
|
||||
ip=myIP;
|
||||
port=myPort;
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
// private function
|
||||
sint32 UDP::SetBlocking(bit8 block)
|
||||
{
|
||||
#ifdef _WINDOWS
|
||||
unsigned long flag=1;
|
||||
if (block)
|
||||
flag=0;
|
||||
int retval;
|
||||
retval=ioctlsocket(fd,FIONBIO,&flag);
|
||||
if (retval==SOCKET_ERROR)
|
||||
return(UNKNOWN);
|
||||
else
|
||||
return(OK);
|
||||
#else // UNIX
|
||||
int flags = fcntl(fd, F_GETFL, 0);
|
||||
if (block==FALSE) // set nonblocking
|
||||
flags |= O_NONBLOCK;
|
||||
else // set blocking
|
||||
flags &= ~(O_NONBLOCK);
|
||||
|
||||
if (fcntl(fd, F_SETFL, flags) < 0)
|
||||
{
|
||||
return(UNKNOWN);
|
||||
}
|
||||
return(OK);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
sint32 UDP::Write(uint8 *msg,uint32 len,uint32 IP,uint16 port)
|
||||
{
|
||||
sint32 retval;
|
||||
struct sockaddr_in to;
|
||||
|
||||
// This happens frequently
|
||||
if ((IP==0)||(port==0)) return(ADDRNOTAVAIL);
|
||||
|
||||
errno=0;
|
||||
to.sin_port=htons(port);
|
||||
to.sin_addr.s_addr=htonl(IP);
|
||||
to.sin_family=AF_INET;
|
||||
|
||||
ClearStatus();
|
||||
retval=sendto(fd,(char *)msg,len,0,(struct sockaddr *)&to,sizeof(to));
|
||||
#ifdef _WINDOWS
|
||||
if (retval==SOCKET_ERROR)
|
||||
retval=-1;
|
||||
#endif
|
||||
|
||||
return(retval);
|
||||
}
|
||||
|
||||
sint32 UDP::Read(uint8 *msg,uint32 len,sockaddr_in *from)
|
||||
{
|
||||
sint32 retval;
|
||||
int alen=sizeof(sockaddr_in);
|
||||
|
||||
if (from!=NULL)
|
||||
{
|
||||
retval=recvfrom(fd,(char *)msg,len,0,(struct sockaddr *)from,&alen);
|
||||
#ifdef _WINDOWS
|
||||
if (retval==SOCKET_ERROR)
|
||||
retval=-1;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
retval=recvfrom(fd,(char *)msg,len,0,NULL,NULL);
|
||||
#ifdef _WINDOWS
|
||||
if (retval==SOCKET_ERROR)
|
||||
retval=-1;
|
||||
#endif
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
|
||||
|
||||
void UDP::ClearStatus(void)
|
||||
{
|
||||
#ifndef _WINDOWS
|
||||
errno=0;
|
||||
#endif
|
||||
}
|
||||
|
||||
UDP::sockStat UDP::GetStatus(void)
|
||||
{
|
||||
#ifdef _WINDOWS
|
||||
int status=WSAGetLastError();
|
||||
if (status==0) return(OK);
|
||||
else if (status==WSAEINTR) return(INTR);
|
||||
else if (status==WSAEINPROGRESS) return(INPROGRESS);
|
||||
else if (status==WSAECONNREFUSED) return(CONNREFUSED);
|
||||
else if (status==WSAEINVAL) return(INVAL);
|
||||
else if (status==WSAEISCONN) return(ISCONN);
|
||||
else if (status==WSAENOTSOCK) return(NOTSOCK);
|
||||
else if (status==WSAETIMEDOUT) return(TIMEDOUT);
|
||||
else if (status==WSAEALREADY) return(ALREADY);
|
||||
else if (status==WSAEWOULDBLOCK) return(WOULDBLOCK);
|
||||
else if (status==WSAEBADF) return(BADF);
|
||||
else return(UNKNOWN);
|
||||
#else
|
||||
int status=errno;
|
||||
if (status==0) return(OK);
|
||||
else if (status==EINTR) return(INTR);
|
||||
else if (status==EINPROGRESS) return(INPROGRESS);
|
||||
else if (status==ECONNREFUSED) return(CONNREFUSED);
|
||||
else if (status==EINVAL) return(INVAL);
|
||||
else if (status==EISCONN) return(ISCONN);
|
||||
else if (status==ENOTSOCK) return(NOTSOCK);
|
||||
else if (status==ETIMEDOUT) return(TIMEDOUT);
|
||||
else if (status==EALREADY) return(ALREADY);
|
||||
else if (status==EAGAIN) return(AGAIN);
|
||||
else if (status==EWOULDBLOCK) return(WOULDBLOCK);
|
||||
else if (status==EBADF) return(BADF);
|
||||
else return(UNKNOWN);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Wait for net activity on this socket
|
||||
//
|
||||
int UDP::Wait(sint32 sec,sint32 usec,fd_set &returnSet)
|
||||
{
|
||||
fd_set inputSet;
|
||||
|
||||
FD_ZERO(&inputSet);
|
||||
FD_SET(fd,&inputSet);
|
||||
|
||||
return(Wait(sec,usec,inputSet,returnSet));
|
||||
}
|
||||
|
||||
//
|
||||
// Wait for net activity on a list of sockets
|
||||
//
|
||||
int UDP::Wait(sint32 sec,sint32 usec,fd_set &givenSet,fd_set &returnSet)
|
||||
{
|
||||
Wtime timeout,timenow,timethen;
|
||||
fd_set backupSet;
|
||||
int retval=0,done,givenMax;
|
||||
bit8 noTimeout=FALSE;
|
||||
timeval tv;
|
||||
|
||||
returnSet=givenSet;
|
||||
backupSet=returnSet;
|
||||
|
||||
if ((sec==-1)&&(usec==-1))
|
||||
noTimeout=TRUE;
|
||||
|
||||
timeout.SetSec(sec);
|
||||
timeout.SetUsec(usec);
|
||||
timethen+=timeout;
|
||||
|
||||
givenMax=fd;
|
||||
for (uint32 i=0; i<(sizeof(fd_set)*8); i++) // i=maxFD+1
|
||||
{
|
||||
if (FD_ISSET(i,&givenSet))
|
||||
givenMax=i;
|
||||
}
|
||||
///DBGMSG("WAIT fd="<<fd<<" givenMax="<<givenMax);
|
||||
|
||||
done=0;
|
||||
while( ! done)
|
||||
{
|
||||
if (noTimeout)
|
||||
retval=select(givenMax+1,&returnSet,0,0,NULL);
|
||||
else
|
||||
{
|
||||
timeout.GetTimevalMT(tv);
|
||||
retval=select(givenMax+1,&returnSet,0,0,&tv);
|
||||
}
|
||||
|
||||
if (retval>=0)
|
||||
done=1;
|
||||
|
||||
else if ((retval==-1)&&(errno==EINTR)) // in case of signal
|
||||
{
|
||||
if (noTimeout==FALSE)
|
||||
{
|
||||
timenow.Update();
|
||||
timeout=timethen-timenow;
|
||||
}
|
||||
if ((noTimeout==FALSE)&&(timenow.GetSec()==0)&&(timenow.GetUsec()==0))
|
||||
done=1;
|
||||
else
|
||||
returnSet=backupSet;
|
||||
}
|
||||
else // maybe out of memory?
|
||||
{
|
||||
done=1;
|
||||
}
|
||||
}
|
||||
///DBGMSG("Wait retval: "<<retval);
|
||||
return(retval);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Set the kernel buffer sizes for incoming, and outgoing packets
|
||||
//
|
||||
// Linux seems to have a buffer max of 32767 bytes for this,
|
||||
// (which is the default). If you try and set the size to
|
||||
// greater than the default it just sets it to 32767.
|
||||
|
||||
bit8 UDP::SetInputBuffer(uint32 bytes)
|
||||
{
|
||||
#ifndef _WINDOWS
|
||||
int retval,arg=bytes;
|
||||
|
||||
retval=setsockopt(fd,SOL_SOCKET,SO_RCVBUF,
|
||||
(char *)&arg,sizeof(int));
|
||||
if (retval==0)
|
||||
return(TRUE);
|
||||
else
|
||||
return(FALSE);
|
||||
#else
|
||||
return(FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Same note goes for the output buffer
|
||||
|
||||
bit8 UDP::SetOutputBuffer(uint32 bytes)
|
||||
{
|
||||
#ifndef _WINDOWS
|
||||
int retval,arg=bytes;
|
||||
|
||||
retval=setsockopt(fd,SOL_SOCKET,SO_SNDBUF,
|
||||
(char *)&arg,sizeof(int));
|
||||
if (retval==0)
|
||||
return(TRUE);
|
||||
else
|
||||
return(FALSE);
|
||||
#else
|
||||
return(FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get the system buffer sizes
|
||||
|
||||
int UDP::GetInputBuffer(void)
|
||||
{
|
||||
#ifndef _WINDOWS
|
||||
int retval,arg=0,len=sizeof(int);
|
||||
|
||||
retval=getsockopt(fd,SOL_SOCKET,SO_RCVBUF,
|
||||
(char *)&arg,&len);
|
||||
return(arg);
|
||||
#else
|
||||
return(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int UDP::GetOutputBuffer(void)
|
||||
{
|
||||
#ifndef _WINDOWS
|
||||
int retval,arg=0,len=sizeof(int);
|
||||
|
||||
retval=getsockopt(fd,SOL_SOCKET,SO_SNDBUF,
|
||||
(char *)&arg,&len);
|
||||
return(arg);
|
||||
#else
|
||||
return(0);
|
||||
#endif
|
||||
}
|
114
Generals/Code/Tools/mangler/wnet/udp.h
Normal file
114
Generals/Code/Tools/mangler/wnet/udp.h
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
** 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 UDP_HEADER
|
||||
#define UDP_HEADER
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <winsock.h>
|
||||
#include <io.h>
|
||||
#define close _close
|
||||
#define read _read
|
||||
#define write _write
|
||||
|
||||
#else //UNIX
|
||||
#include <netdb.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
#ifdef AIX
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
#define DEFAULT_PROTOCOL 0
|
||||
|
||||
#include <wlib/wstypes.h>
|
||||
#include <wlib/wtime.h>
|
||||
|
||||
class UDP
|
||||
{
|
||||
// DATA
|
||||
private:
|
||||
sint32 fd;
|
||||
uint32 myIP;
|
||||
uint16 myPort;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
// These defines specify a system independent way to
|
||||
// get error codes for socket services.
|
||||
enum sockStat
|
||||
{
|
||||
OK = 0, // Everything's cool
|
||||
UNKNOWN = -1, // There was an error of unknown type
|
||||
ISCONN = -2, // The socket is already connected
|
||||
INPROGRESS = -3, // The socket is non-blocking and the operation
|
||||
// isn't done yet
|
||||
ALREADY = -4, // The socket is already attempting a connection
|
||||
// but isn't done yet
|
||||
AGAIN = -5, // Try again.
|
||||
ADDRINUSE = -6, // Address already in use
|
||||
ADDRNOTAVAIL = -7, // That address is not available on the remote host
|
||||
BADF = -8, // Not a valid FD
|
||||
CONNREFUSED = -9, // Connection was refused
|
||||
INTR =-10, // Operation was interrupted
|
||||
NOTSOCK =-11, // FD wasn't a socket
|
||||
PIPE =-12, // That operation just made a SIGPIPE
|
||||
WOULDBLOCK =-13, // That operation would block
|
||||
INVAL =-14, // Invalid
|
||||
TIMEDOUT =-15 // Timeout
|
||||
};
|
||||
|
||||
// CODE
|
||||
private:
|
||||
sint32 SetBlocking(bit8 block);
|
||||
|
||||
public:
|
||||
UDP();
|
||||
~UDP();
|
||||
sint32 Bind(uint32 IP,uint16 port);
|
||||
sint32 Bind(char *Host,uint16 port);
|
||||
sint32 Write(uint8 *msg,uint32 len,uint32 IP,uint16 port);
|
||||
sint32 Read(uint8 *msg,uint32 len,sockaddr_in *from);
|
||||
sockStat GetStatus(void);
|
||||
void ClearStatus(void);
|
||||
int Wait(sint32 sec,sint32 usec,fd_set &returnSet);
|
||||
int Wait(sint32 sec,sint32 usec,fd_set &givenSet,fd_set &returnSet);
|
||||
|
||||
bit8 getLocalAddr(uint32 &ip, uint16 &port);
|
||||
sint32 getFD(void) { return(fd); }
|
||||
|
||||
bit8 SetInputBuffer(uint32 bytes);
|
||||
bit8 SetOutputBuffer(uint32 bytes);
|
||||
int GetInputBuffer(void);
|
||||
int GetOutputBuffer(void);
|
||||
};
|
||||
|
||||
#endif
|
Reference in a new issue