From 297e8450d80411d81f0aaeee642053354125bd6d Mon Sep 17 00:00:00 2001 From: fusion32 Date: Thu, 22 May 2025 11:40:04 -0300 Subject: implement TWriteScriptFile --- TODO.md | 4 +- reference/game.c | 385 ------------------------------------------------------- src/script.cc | 185 +++++++++++++++++++++++++- src/script.hh | 12 +- 4 files changed, 193 insertions(+), 393 deletions(-) diff --git a/TODO.md b/TODO.md index 8551046..f9d6da5 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,8 @@ ## TODO NEXT -- TReadScript / TWriteScript - THREADS +- TReadStream/TWriteStream +- TReadBuffer/TWriteBuffer +- TReadBinaryFile/TWriteBinaryFile - TCreature - TPlayer - TNonPlayer diff --git a/reference/game.c b/reference/game.c index 1affc5c..975bc84 100644 --- a/reference/game.c +++ b/reference/game.c @@ -3594,391 +3594,6 @@ LAB_0804eb1e: return; } -// DWARF original prototype: void TWriteScriptFile(TWriteScriptFile * this) - -void __thiscall TWriteScriptFile::TWriteScriptFile(TWriteScriptFile *this) - -{ - this->File = (FILE *)0x0; - return; -} - - - -// DWARF original prototype: void TWriteScriptFile(TWriteScriptFile * this) - -void __thiscall TWriteScriptFile::TWriteScriptFile(TWriteScriptFile *this) - -{ - this->File = (FILE *)0x0; - return; -} - - - -// DWARF original prototype: void ~TWriteScriptFile(TWriteScriptFile * this, int __in_chrg) - -void __thiscall TWriteScriptFile::~TWriteScriptFile(TWriteScriptFile *this,int __in_chrg) - -{ - char *pcVar1; - int iVar2; - int *piVar3; - - if (this->File != (FILE *)0x0) { - pcVar1 = ""; - if (this != (TWriteScriptFile *)0xfffffffc) { - pcVar1 = this->Filename; - } - ::error("TWriteScriptFile::~TWriteScriptFile: Datei %s ist noch offen.\n",pcVar1); - iVar2 = fclose((FILE *)this->File); - if (iVar2 != 0) { - piVar3 = __errno_location(); - ::error(&DAT_080ef6e0,*piVar3); - } - } - return; -} - - - -// DWARF original prototype: void ~TWriteScriptFile(TWriteScriptFile * this, int __in_chrg) - -void __thiscall TWriteScriptFile::~TWriteScriptFile(TWriteScriptFile *this,int __in_chrg) - -{ - char *pcVar1; - int iVar2; - int *piVar3; - - if (this->File != (FILE *)0x0) { - pcVar1 = ""; - if (this != (TWriteScriptFile *)0xfffffffc) { - pcVar1 = this->Filename; - } - ::error("TWriteScriptFile::~TWriteScriptFile: Datei %s ist noch offen.\n",pcVar1); - iVar2 = fclose((FILE *)this->File); - if (iVar2 != 0) { - piVar3 = __errno_location(); - ::error(&DAT_080ef6e0,*piVar3); - } - } - return; -} - - - -// DWARF original prototype: void open(TWriteScriptFile * this, char * FileName) - -int __thiscall TWriteScriptFile::open(TWriteScriptFile *this,char *__file,int __oflag,...) - -{ - FILE *pFVar1; - char *pcVar2; - int *piVar3; - undefined4 *puVar4; - int iVar5; - - if (this->File != (FILE *)0x0) { - ::error("TWriteScriptFile::open: Altes Skript ist noch offen.\n"); - iVar5 = fclose((FILE *)this->File); - if (iVar5 != 0) { - piVar3 = __errno_location(); - ::error(&DAT_080ef7c0,*piVar3); - } - this->File = (FILE *)0x0; - } - pFVar1 = fopen(__file,"wb"); - this->File = (FILE *)pFVar1; - if (pFVar1 != (FILE *)0x0) { - this->Line = 0; - pcVar2 = strcpy(this->Filename,__file); - return (int)pcVar2; - } - piVar3 = __errno_location(); - iVar5 = *piVar3; - // try { // try from 08050063 to 080500eb has its CatchHandler @ 080500f0 - ::error("TWriteScriptFile: Kann Datei %s nicht anlegen.\n",__file); - pcVar2 = strerror(iVar5); - ::error("Fehler %d: %s.\n",iVar5,pcVar2); - puVar4 = (undefined4 *)__cxa_allocate_exception(4); - *puVar4 = "Cannot create script-file"; - // WARNING: Subroutine does not return - __cxa_throw(puVar4,char_const*::typeinfo,0); -} - - - -// DWARF original prototype: void close(TWriteScriptFile * this) - -int __thiscall TWriteScriptFile::close(TWriteScriptFile *this,int __fd) - -{ - int iVar1; - int *piVar2; - FILE *__stream; - - __stream = (FILE *)this->File; - if (__stream != (FILE *)0x0) { - iVar1 = fclose(__stream); - if (iVar1 != 0) { - piVar2 = __errno_location(); - iVar1 = *piVar2; - ::error(&DAT_080ef800,iVar1); - } - this->File = (FILE *)0x0; - return iVar1; - } - ::error("TWriteScriptFile::close: Kein Skript offen.\n"); - return (int)__stream; -} - - - -// DWARF original prototype: void error(TWriteScriptFile * this, char * Text) - -void __thiscall TWriteScriptFile::error(TWriteScriptFile *this,char *Text) - -{ - int iVar1; - int *piVar2; - undefined4 *puVar3; - - if ((FILE *)this->File != (FILE *)0x0) { - iVar1 = fclose((FILE *)this->File); - if (iVar1 != 0) { - piVar2 = __errno_location(); - // try { // try from 080501b0 to 08050223 has its CatchHandler @ 08050224 - ::error(&DAT_080ef880,*piVar2); - } - } - this->File = (FILE *)0x0; - snprintf(ErrorString,100,"error in script-file \"%s\", line %d: %s",this->Filename,this->Line, - Text); - puVar3 = (undefined4 *)__cxa_allocate_exception(4); - *puVar3 = ErrorString; - // WARNING: Subroutine does not return - __cxa_throw(puVar3,char*::typeinfo,0); -} - - - -// DWARF original prototype: void writeLn(TWriteScriptFile * this) - -void __thiscall TWriteScriptFile::writeLn(TWriteScriptFile *this) - -{ - undefined4 *puVar1; - - if ((FILE *)this->File != (FILE *)0x0) { - putc(10,(FILE *)this->File); - return; - } - // try { // try from 0805026a to 08050298 has its CatchHandler @ 08050299 - ::error(&DAT_080ef8c0); - puVar1 = (undefined4 *)__cxa_allocate_exception(4); - *puVar1 = "Cannot write linefeed"; - // WARNING: Subroutine does not return - __cxa_throw(puVar1,char_const*::typeinfo,0); -} - - - -// DWARF original prototype: void writeText(TWriteScriptFile * this, char * Text) - -void __thiscall TWriteScriptFile::writeText(TWriteScriptFile *this,char *Text) - -{ - char cVar1; - undefined4 *puVar2; - FILE *__stream; - char *Text_00; - - __stream = (FILE *)this->File; - if (__stream == (FILE *)0x0) { - Text_00 = &DAT_080ef940; - } - else { - if (Text != (char *)0x0) { - cVar1 = *Text; - if (cVar1 != '\0') { - while( true ) { - Text = Text + 1; - putc((int)cVar1,__stream); - cVar1 = *Text; - if (cVar1 == '\0') break; - __stream = (FILE *)this->File; - } - } - return; - } - Text_00 = "TWriteScriptFile::writeText: Text ist NULL.\n"; - } - // try { // try from 080502fe to 0805032c has its CatchHandler @ 08050336 - ::error(Text_00); - puVar2 = (undefined4 *)__cxa_allocate_exception(4); - *puVar2 = "Cannot write text"; - // WARNING: Subroutine does not return - __cxa_throw(puVar2,char_const*::typeinfo,0); -} - - - -// DWARF original prototype: void writeString(TWriteScriptFile * this, char * Text) - -void __thiscall TWriteScriptFile::writeString(TWriteScriptFile *this,char *Text) - -{ - undefined4 *puVar1; - char cVar2; - char *Text_00; - - if ((FILE *)this->File == (FILE *)0x0) { - Text_00 = &DAT_080ef9e0; - } - else { - if (Text != (char *)0x0) { - putc(0x22,(FILE *)this->File); - cVar2 = *Text; - while (cVar2 != '\0') { - if ((cVar2 == '\"') || (cVar2 == '\\')) { - putc(0x5c,(FILE *)this->File); - cVar2 = *Text; - } - if (cVar2 == '\n') { - putc(0x5c,(FILE *)this->File); - putc(0x6e,(FILE *)this->File); - } - else { - putc((int)cVar2,(FILE *)this->File); - } - Text = Text + 1; - cVar2 = *Text; - } - putc(0x22,(FILE *)this->File); - return; - } - Text_00 = "TWriteScriptFile::writeString: Text ist NULL.\n"; - } - // try { // try from 08050416 to 08050444 has its CatchHandler @ 0805044e - ::error(Text_00); - puVar1 = (undefined4 *)__cxa_allocate_exception(4); - *puVar1 = "Cannot write string"; - // WARNING: Subroutine does not return - __cxa_throw(puVar1,char_const*::typeinfo,0); -} - - - -// DWARF original prototype: void writeNumber(TWriteScriptFile * this, int Number) - -void __thiscall TWriteScriptFile::writeNumber(TWriteScriptFile *this,int Number) - -{ - undefined4 *puVar1; - char local_2c [4]; - char s [20]; - - if (this->File != (FILE *)0x0) { - sprintf(local_2c,"%d",Number); - // try { // try from 080504a6 to 080504ea has its CatchHandler @ 080504f0 - writeText(this,local_2c); - return; - } - ::error(&DAT_080efa40); - puVar1 = (undefined4 *)__cxa_allocate_exception(4); - *puVar1 = "Cannot write number"; - // WARNING: Subroutine does not return - __cxa_throw(puVar1,char_const*::typeinfo,0); -} - - - -// DWARF original prototype: void writeBytesequence(TWriteScriptFile * this, uchar * Sequence, int -// Length) - -void __thiscall -TWriteScriptFile::writeBytesequence(TWriteScriptFile *this,uchar *Sequence,int Length) - -{ - undefined4 *puVar1; - int i; - int iVar2; - char *Text; - char local_3c [4]; - char s [20]; - - if (this->File == (FILE *)0x0) { - Text = &DAT_080efb20; - } - else if (Sequence == (uchar *)0x0) { - Text = "TWriteScriptFile::writeBytesequence: Sequence ist NULL.\n"; - } - else { - if (0 < Length) { - iVar2 = 0; - if (0 < Length) { - do { - if (iVar2 != 0) { - // try { // try from 080505de to 0805061d has its CatchHandler @ 08050648 - writeText(this,"-"); - } - if (this->File == (FILE *)0x0) { - ::error(&DAT_080efa40); - puVar1 = (undefined4 *)__cxa_allocate_exception(4); - *puVar1 = "Cannot write number"; - // WARNING: Subroutine does not return - __cxa_throw(puVar1,char_const*::typeinfo,0); - } - sprintf(local_3c,"%d",(uint)Sequence[iVar2]); - // try { // try from 0805057c to 080505d2 has its CatchHandler @ 08050630 - writeText(this,local_3c); - iVar2 = iVar2 + 1; - } while (iVar2 < Length); - } - return; - } - Text = &DAT_080efaa0; - } - ::error(Text); - puVar1 = (undefined4 *)__cxa_allocate_exception(4); - *puVar1 = "Cannot write bytesequence"; - // WARNING: Subroutine does not return - __cxa_throw(puVar1,char_const*::typeinfo,0); -} - - - -// DWARF original prototype: void writeCoordinate(TWriteScriptFile * this, int x, int y, int z) - -void __thiscall TWriteScriptFile::writeCoordinate(TWriteScriptFile *this,int x,int y,int z) - -{ - undefined4 *puVar1; - char local_2c [4]; - char s [20]; - - if (this->File == (FILE *)0x0) { - ::error(&DAT_080efbe0); - puVar1 = (undefined4 *)__cxa_allocate_exception(4); - *puVar1 = "Cannot write coordinate"; - } - else { - if (((-1 < x) && (-1 < y)) && (-1 < z)) { - sprintf(local_2c,"[%u,%u,%u]",x,y,z); - // try { // try from 080506b4 to 08050710 has its CatchHandler @ 08050725 - writeText(this,local_2c); - return; - } - ::error(&DAT_080efb80,x,y,z); - puVar1 = (undefined4 *)__cxa_allocate_exception(4); - *puVar1 = "Invalid coordinates"; - } - // WARNING: Subroutine does not return - __cxa_throw(puVar1,char_const*::typeinfo,0); -} - - // DWARF original prototype: void TReadBinaryFile(TReadBinaryFile * this) diff --git a/src/script.cc b/src/script.cc index d3e8134..5c8c7d7 100644 --- a/src/script.cc +++ b/src/script.cc @@ -1,6 +1,15 @@ #include "script.hh" -// ============================================================================= +// NOTE(fusion): Throwing a character array on the stack as an exception won't +// work because it implicitly decays into a character pointer which would then +// point to invalid data when actually parsed. It is the reason `ErrorString` is +// declared statically, or else you'd need to throw some heap allocated string +// which then becomes ambiguous whether you should free it or not. Used in: +// - TReadScriptFile::error +// - TWriteScriptFile::error +static char ErrorString[100]; + +// Helper Functions // ============================================================================= // TODO(fusion): Move to `util.cc`? @@ -104,9 +113,8 @@ static char *findLast(char *s, char c){ return Last; } -// ============================================================================= -// ============================================================================= - +// TWriteScriptFile +//============================================================================== TReadScriptFile::TReadScriptFile(void){ this->RecursionDepth = -1; this->Bytes = (uint8*)this->String; @@ -172,8 +180,6 @@ void TReadScriptFile::close(void){ } void TReadScriptFile::error(const char *Text){ - static char ErrorString[100]; - int Depth = this->RecursionDepth; ASSERT(Depth >= 0 && Depth <= NARRAY(this->File)); @@ -615,3 +621,170 @@ int main(int argc, char **argv){ return EXIT_FAILURE; } + +// TWriteScriptFile +//============================================================================== +TWriteScriptFile::TWriteScriptFile(void){ + this->File = NULL; +} + +TWriteScriptFile::~TWriteScriptFile(void){ + if(this->File != NULL){ + ::error("TWriteScriptFile::~TWriteScriptFile: Datei %s ist noch offen.\n", this->Filename); + if(fclose(this->File) != 0){ + ::error("TWriteScriptFile::~TWriteScriptFile: Fehler %d beim Schließen der Datei.\n", errno); + } + } +} + +void TWriteScriptFile::open(char *FileName){ + if(this->File != NULL){ + ::error("TWriteScriptFile::open: Altes Skript ist noch offen.\n"); + if(fclose(this->File) != 0){ + ::error("TWriteScriptFile::open: Fehler %d beim Schließen der Datei.\n", errno); + } + this->File = NULL; + } + + this->File = fopen(FileName, "wb"); + if(this->File == NULL){ + ::error("TWriteScriptFile: Kann Datei %s nicht anlegen.\n", FileName); + ::error("Fehler %d: %s.\n", errno, strerror(errno)); + throw "Cannot create script-file"; + } + + strcpy(this->Filename, FileName); + this->Line = 0; +} + +void TWriteScriptFile::close(void){ + if(this->File == NULL){ + ::error("TWriteScriptFile::close: Kein Skript offen.\n"); + return; + } + + if(fclose(this->File) != 0){ + ::error("TWriteScriptFile::close: Fehler %d beim Schließen der Datei.\n", errno); + } + this->File = NULL; +} + +void TWriteScriptFile::error(char *Text){ + if(this->File != NULL){ + if(fclose(this->File) != 0){ + ::error("TWriteScriptFile::error: Fehler %d beim Schließen der Datei.\n", errno); + } + this->File = NULL; + } + + snprintf(ErrorString, sizeof(ErrorString), + "error in script-file \"%s\", line %d: %s", + this->Filename, this->Line); + + throw ErrorString; +} + +void TWriteScriptFile::writeLn(void){ + if(this->File == NULL){ + ::error("TWriteScriptFile::writeLn: Kein Skript zum Schreiben geöffnet.\n"); + throw "Cannot write linefeed"; + } + + putc('\n', this->File); +} + +void TWriteScriptFile::writeText(char *Text){ + if(this->File == NULL){ + ::error("TWriteScriptFile::writeText: Kein Skript zum Schreiben geöffnet.\n"); + throw "Cannot write text"; + } + + if(Text == NULL){ + ::error("TWriteScriptFile::writeText: Text ist NULL.\n"); + throw "Cannot write text"; + } + + for(int i = 0; Text[i] != 0; i += 1){ + putc(Text[i], this->File); + } +} + +void TWriteScriptFile::writeNumber(int Number){ + if(this->File == NULL){ + ::error("TWriteScriptFile::writeNumber: Kein Skript zum Schreiben geöffnet.\n"); + throw "Cannot write number"; + } + + char s[32]; + snprintf(s, sizeof(s), "%d", Number); + this->writeText(s); +} + +void TWriteScriptFile::writeString(char *Text){ + if(this->File == NULL){ + ::error(); + throw "Cannot write string"; + } + + if(Text == NULL){ + ::error("TWriteScriptFile::writeString: Text ist NULL.\n"); + throw "Cannot write string"; + } + + putc('"', this->File); + for(int i = 0; Text[i] != 0; i += 1){ + if(Text[i] == '\"' || Text[i] == '\\'){ + putc('\\', this->File); + putc(Text[i], this->File); + }else if(Text[i] == '\n'){ + putc('\\', this->File); + putc('n', this->File); + }else{ + putc(Text[i], this->File); + } + } + putc('"', this->File); +} + +void TWriteScriptFile::writeCoordinate(int x ,int y ,int z){ + if(this->File == NULL){ + ::error("TWriteScriptFile::writeCoordinate: Kein Skript zum Schreiben geöffnet.\n"); + throw "Cannot write coordinate"; + } + + // TODO(fusion): This is weird because we support loading negative coordinates values. + if(x < 0 || y < 0 || z < 0){ + ::error("TWriteScriptFile::writeCoordinate: Ungültige Koordinaten [%d,%d,%d].\n", x, y, z); + throw "Invalid coordinates"; + } + + char s[64]; + snprintf(s, sizeof(s), "[%u,%u,%u]", x, y, z); + this->writeText(s); +} + +void TWriteScriptFile::writeBytesequence(uint8 *Sequence, int Length){ + if(this->File == NULL){ + ::error("TWriteScriptFile::writeBytesequence: Kein Skript zum Schreiben geöffnet.\n"); + throw "Cannot write bytesequence"; + } + + if(Sequence == NULL){ + ::error("TWriteScriptFile::writeBytesequence: Sequence ist NULL.\n"); + throw "Cannot write bytesequence"; + } + + if(Length <= 0){ + ::error("TWriteScriptFile::writeBytesequence: Ungültige Sequenzlänge.\n"); + throw "Cannot write bytesequence"; + } + + for(int i = 0; i < Length; i += 1){ + if(i > 0){ + putc('-', this->File); + } + + snprintf(s, sizeof(s), "%u", Sequence[i]); + this->writeText(s); + } +} diff --git a/src/script.hh b/src/script.hh index 2825d6d..5b63f56 100644 --- a/src/script.hh +++ b/src/script.hh @@ -82,7 +82,17 @@ struct TReadScriptFile { struct TWriteScriptFile { // REGULAR FUNCTIONS // ========================================================================= - //TWriteScriptFile(void); + TWriteScriptFile(void); + ~TWriteScriptFile(void); + void open(char *FileName); + void close(void); + void error(char *Text); + void writeLn(void); + void writeText(char *Text); + void writeNumber(int Number); + void writeString(char *Text); + void writeCoordinate(int x ,int y ,int z); + void writeBytesequence(uint8 *Sequence, int Length); // DATA // ========================================================================= -- cgit v1.2.3