From e5b60ae075e571a29868993a5f0d191d91f8d266 Mon Sep 17 00:00:00 2001 From: fusion32 Date: Thu, 29 May 2025 00:04:19 -0300 Subject: impl `strings.cc` --- reference/game.c | 355 ----------------------------------------------------- reference/types.hh | 14 --- src/common.hh | 5 + src/strings.cc | 207 +++++++++++++++++++++++++++++++ src/stubs.hh | 5 - 5 files changed, 212 insertions(+), 374 deletions(-) diff --git a/reference/game.c b/reference/game.c index dff762d..e8bb7cd 100644 --- a/reference/game.c +++ b/reference/game.c @@ -2667,339 +2667,6 @@ void __static_initialization_and_destruction_0(int __initialize_p,int __priority return; } - - -// WARNING: Variable defined which should be unmapped: p - -char * AddStaticString(char *String) - -{ - size_t sVar1; - char *__dest; - listnode<> *plVar2; - TStaticStringTableBlock *pTVar3; - listIterator<> iter; - TStaticStringTableBlock *local_18; - char *p; - - sVar1 = strlen(String); - if ((int)sVar1 < 0x10000) { - __dest = ""; - if (sVar1 != 0) { - for (plVar2 = StaticStringTable.firstNode; plVar2 != (listnode<> *)0x0; - plVar2 = plVar2->next) { - if ((int)(sVar1 + 1) < 0x10000 - (plVar2->data).TotalTextLength) { - if (plVar2 != (listnode<> *)0x0) goto LAB_0805197a; - break; - } - } - plVar2 = list<>::append(&StaticStringTable); - if (plVar2 == (listnode<> *)0x0) { - error("listIterator::operator*: Iterator ist NULL.\n"); - pTVar3 = (TStaticStringTableBlock *)0x0; - } - else { - pTVar3 = &plVar2->data; - } - pTVar3->TotalTextLength = 0; - if (plVar2 == (listnode<> *)0x0) { - error("listIterator::operator*: Iterator ist NULL.\n"); - local_18 = (TStaticStringTableBlock *)0x0; - } - else { -LAB_0805197a: - local_18 = &plVar2->data; - } - if (plVar2 == (listnode<> *)0x0) { - error("listIterator::operator*: Iterator ist NULL.\n"); - pTVar3 = (TStaticStringTableBlock *)0x0; - } - else { - pTVar3 = &plVar2->data; - } - __dest = local_18->Text + pTVar3->TotalTextLength; - memcpy(__dest,String,sVar1 + 1); - if (plVar2 == (listnode<> *)0x0) { - error("listIterator::operator*: Iterator ist NULL.\n"); - pTVar3 = (TStaticStringTableBlock *)0x0; - } - else { - pTVar3 = &plVar2->data; - } - pTVar3->TotalTextLength = sVar1 + pTVar3->TotalTextLength + 1; - } - } - else { - error("AddStaticString: String zu lang (%d).\n",sVar1); - __dest = (char *)0x0; - } - return __dest; -} - - - -// WARNING: Variable defined which should be unmapped: iter - -ulong AddDynamicString(char *String) - -{ - int iVar1; - int i_1; - size_t sVar2; - int i; - int iVar3; - TDynamicStringTableBlock *pTVar4; - int pos; - int iVar5; - int local_18; - int count; - listIterator<> iter; - - sVar2 = strlen(String); - if ((int)sVar2 < 0x8000) { - if (sVar2 == 0) { - return 0; - } - local_18 = 0; - count = (int)DynamicStringTable.firstNode; - while ((listnode<> *)count != (listnode<> *)0x0) { - if (0 < (((listnode<> *)count)->data).FreeEntries) { - if ((listnode<> *)count == (listnode<> *)0x0) { - error("listIterator::operator*: Iterator ist NULL.\n"); - pTVar4 = (TDynamicStringTableBlock *)0x0; - } - else { - pTVar4 = &((listnode<> *)count)->data; - } - if ((int)(sVar2 + 1) < 0x8000 - pTVar4->TotalTextLength) { - if ((listnode<> *)count != (listnode<> *)0x0) goto LAB_08051ae9; - break; - } - } - if ((listnode<> *)count == (listnode<> *)0x0) { - error("listIterator::operator++: Iterator ist NULL.\n"); - } - else { - count = (int)((listnode<> *)count)->next; - } - local_18 = local_18 + 1; - } - count = (int)list<>::append(&DynamicStringTable); - if ((listnode<> *)count == (listnode<> *)0x0) { - error("listIterator::operator*: Iterator ist NULL.\n"); - pTVar4 = (TDynamicStringTableBlock *)0x0; - } - else { - pTVar4 = &((listnode<> *)count)->data; - } - pTVar4->FreeEntries = 0x100; - iVar3 = 0; - pTVar4->TotalTextLength = 0; - pTVar4->Dirty = false; - do { - pTVar4->EntryType[iVar3] = '\0'; - iVar3 = iVar3 + 1; - } while (iVar3 < 0x100); - if ((listnode<> *)count == (listnode<> *)0x0) { - pTVar4 = (TDynamicStringTableBlock *)0x0; - error("listIterator::operator*: Iterator ist NULL.\n"); - } - else { -LAB_08051ae9: - pTVar4 = &((listnode<> *)count)->data; - } - iVar3 = 0; - do { - iVar5 = iVar3; - if (pTVar4->EntryType[iVar3] == '\0') break; - iVar3 = iVar3 + 1; - iVar5 = -1; - } while (iVar3 < 0x100); - if (iVar5 != -1) { - iVar1 = pTVar4->TotalTextLength; - pTVar4->EntryType[iVar5] = '\x01'; - iVar3 = pTVar4->TotalTextLength; - pTVar4->FreeEntries = pTVar4->FreeEntries + -1; - pTVar4->StringOffset[iVar5] = (ushort)iVar1; - memcpy(pTVar4->Text + iVar3,String,sVar2 + 1); - pTVar4->TotalTextLength = sVar2 + pTVar4->TotalTextLength + 1; - return iVar5 + 1 + local_18 * 0x100; - } - error("AddDynamicString: Keinen freien Platz gefunden.\n"); - } - else { - error("AddDynamicString: String zu lang (%d)\n",sVar2); - } - return 0; -} - - - -// WARNING: Variable defined which should be unmapped: iter - -char * GetDynamicString(ulong Number) - -{ - int count; - int iVar1; - int Block; - uint uVar2; - uint uVar3; - char *Text; - listnode<> *local_10; - listIterator<> iter; - - if (Number == 0) { - return (char *)0x0; - } - uVar2 = Number - 1 >> 8; - iVar1 = 0; - uVar3 = Number - 1 & 0xff; - local_10 = DynamicStringTable.firstNode; - if (uVar2 == 0) { -LAB_08051c50: - if (local_10 != (listnode<> *)0x0) { - if ((local_10->data).EntryType[uVar3] == '\x01') { - return (local_10->data).Text + (local_10->data).StringOffset[uVar3]; - } - Text = &DAT_080f0540; - goto LAB_08051c3a; - } - } - else if (DynamicStringTable.firstNode != (listnode<> *)0x0) { - do { - local_10 = local_10->next; - iVar1 = iVar1 + 1; - if ((int)uVar2 <= iVar1) goto LAB_08051c50; - } while (local_10 != (listnode<> *)0x0); - } - Text = &DAT_080f0500; -LAB_08051c3a: - error(Text,Number); - return (char *)0x0; -} - - - -// WARNING: Variable defined which should be unmapped: iter - -void DeleteDynamicString(ulong Number) - -{ - int count; - int iVar1; - int Block; - uint uVar2; - uint uVar3; - char *Text; - listnode<> *local_10; - listIterator<> iter; - - if (Number == 0) { - return; - } - uVar2 = Number - 1 >> 8; - iVar1 = 0; - uVar3 = Number - 1 & 0xff; - local_10 = DynamicStringTable.firstNode; - if (uVar2 == 0) { -LAB_08051ce0: - if (local_10 != (listnode<> *)0x0) { - if ((local_10->data).EntryType[uVar3] == '\x01') { - (local_10->data).EntryType[uVar3] = '\x02'; - (local_10->data).Dirty = true; - return; - } - Text = &DAT_080f05c0; - goto LAB_08051cca; - } - } - else if (DynamicStringTable.firstNode != (listnode<> *)0x0) { - do { - local_10 = local_10->next; - iVar1 = iVar1 + 1; - if ((int)uVar2 <= iVar1) goto LAB_08051ce0; - } while (local_10 != (listnode<> *)0x0); - } - Text = &DAT_080f0580; -LAB_08051cca: - error(Text,Number); - return; -} - - - -// WARNING: Variable defined which should be unmapped: iter -// WARNING: Unknown calling convention -- yet parameter storage is locked - -void CleanupDynamicStrings(void) - -{ - int *piVar1; - int iVar2; - char *__s; - ushort uVar3; - int Help; - size_t sVar4; - int j; - int iVar5; - int Offset; - uint uVar6; - int Length; - int local_18; - int i; - listIterator<> iter; - - i = (int)DynamicStringTable.firstNode; - if (DynamicStringTable.firstNode != (listnode<> *)0x0) { - do { - piVar1 = (int *)(i + 8); - if (*(char *)(i + 0x10) != '\0') { - local_18 = 0; - do { - if (*(char *)(local_18 + 9 + (int)piVar1) == '\x02') { - uVar6 = (uint)*(ushort *)(i + 0x112 + local_18 * 2); - __s = (char *)(uVar6 + 0x30a + (int)piVar1); - sVar4 = strlen(__s); - iVar2 = sVar4 + 1; - *(int *)(i + 0xc) = *(int *)(i + 0xc) - iVar2; - *(undefined1 *)(local_18 + 9 + (int)piVar1) = 0; - if ((int)(iVar2 + uVar6) < 0x8001) { - sVar4 = (-iVar2 - uVar6) + 0x8000; - if (0 < (int)sVar4) { - memmove(__s,(void *)(iVar2 + uVar6 + 0x30a + (int)piVar1),sVar4); - } - *piVar1 = *piVar1 + 1; - iVar5 = 0; - do { - if ((*(char *)(iVar5 + 9 + (int)piVar1) != '\0') && - (uVar3 = *(ushort *)(i + 0x112 + iVar5 * 2), uVar6 < uVar3)) { - *(ushort *)(i + 0x112 + iVar5 * 2) = uVar3 - (short)iVar2; - } - iVar5 = iVar5 + 1; - } while (iVar5 < 0x100); - } - else { - error("CleanupDynamicStrings: Stringende fehlt\n"); - } - } - local_18 = local_18 + 1; - } while (local_18 < 0x100); - *(undefined1 *)(i + 0x10) = 0; - } - if (i == 0) { - error("listIterator::operator++: Iterator ist NULL.\n"); - } - else { - i = *(int *)i; - } - } while (i != 0); - } - return; -} - - - bool IsCountable(char *s) { @@ -3809,28 +3476,6 @@ char * Capitals(char *Text) return Text; } - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -void InitStrings(void) - -{ - return; -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -void ExitStrings(void) - -{ - return; -} - - - void __tcf_0(void *param_1) { diff --git a/reference/types.hh b/reference/types.hh index 2fc67a0..b87faf2 100644 --- a/reference/types.hh +++ b/reference/types.hh @@ -197,15 +197,6 @@ struct TAttackWave { struct vector ExtraItem; }; -struct TDynamicStringTableBlock { - int FreeEntries; - int TotalTextLength; - bool Dirty; - uchar EntryType[256]; - ushort StringOffset[256]; - char Text[32768]; -}; - struct TNonplayer { struct TCreature super_TCreature; // INHERITANCE? enum STATE State; @@ -254,11 +245,6 @@ struct TMonsterhome { int Timer; }; -struct TStaticStringTableBlock { - int TotalTextLength; - char Text[65536]; -}; - struct TCondition { int Type; ulong Text; diff --git a/src/common.hh b/src/common.hh index b981b2b..33fd694 100644 --- a/src/common.hh +++ b/src/common.hh @@ -117,6 +117,11 @@ void ExitSHMExtern(void); // strings.cc // ============================================================================= +const char *AddStaticString(const char *String); +uint32 AddDynamicString(const char *String); +const char *GetDynamicString(uint32 Number); +void DeleteDynamicString(uint32 Number); +void CleanupDynamicStrings(void); void InitStrings(void); void ExitStrings(void); diff --git a/src/strings.cc b/src/strings.cc index 478ad69..41fdc44 100644 --- a/src/strings.cc +++ b/src/strings.cc @@ -1,4 +1,211 @@ #include "common.hh" +#include "containers.hh" + +struct TStaticStringTableBlock { + int TotalTextLength; + char Text[65536]; +}; + +struct TDynamicStringTableBlock { + int FreeEntries; + int TotalTextLength; + bool Dirty; + uint8 EntryType[256]; + uint16 StringOffset[256]; + char Text[32768]; +}; + +constexpr int StaticBlockSize = NARRAY(TStaticStringTableBlock::Text); +constexpr int DynamicBlockSize = NARRAY(TDynamicStringTableBlock::Text); +constexpr int DynamicBlockEntries = NARRAY(TDynamicStringTableBlock::EntryType); + +enum : uint8 { + DYNAMIC_STRING_FREE = 0, + DYNAMIC_STRING_ALLOCATED = 1, + DYNAMIC_STRING_DELETED = 2, +}; + +static list StaticStringTable; +static list DynamicStringTable; + +const char *AddStaticString(const char *String){ + int StringLen = (int)strlen(String); + if((StringLen + 1) > StaticBlockSize){ + error("AddStaticString: String zu lang (%d).\n", StringLen); + return NULL; + } + + if(StringLen == 0){ + return ""; + } + + listnode *Node = StaticStringTable.firstNode; + while(Node != NULL){ + if((Node->data.TotalTextLength + StringLen + 1) <= StaticBlockSize){ + break; + } + Node = Node->next; + } + + if(Node == NULL){ + Node = StaticStringTable.append(); + memset(&Node->data, 0, sizeof(TStaticStringTableBlock)); + } + + TStaticStringTableBlock *Block = &Node->data; + char *Result = &Block->Text[Block->TotalTextLength]; + memcpy(Result, String, StringLen + 1); + Block->TotalTextLength += StringLen + 1; + return Result; +} + +uint32 AddDynamicString(const char *String){ + int StringLen = (int)strlen(String); + if((StringLen + 1) > DynamicBlockSize){ + error("AddDynamicString: String zu lang (%d)\n", StringLen); + return 0; + } + + if(StringLen == 0){ + return 0; + } + + int BlockIndex = 0; + listnode *Node = DynamicStringTable.firstNode; + while(Node != NULL){ + if(Node->data.FreeEntries > 0){ + if((Node->data.TotalTextLength + StringLen + 1) <= DynamicBlockSize){ + break; + } + } + Node = Node->next; + BlockIndex += 1; + } + + if(Node == NULL){ + Node = DynamicStringTable.append(); + memset(&Node->data, 0, sizeof(TDynamicStringTableBlock)); + Node->data.FreeEntries = DynamicBlockEntries; + } + + TDynamicStringTableBlock *Block = &Node->data; + int EntryIndex = -1; + for(int i = 0; i < DynamicBlockEntries; i += 1){ + if(Block->EntryType[i] == DYNAMIC_STRING_FREE){ + EntryIndex = i; + break; + } + } + + if(EntryIndex == -1){ + error("AddDynamicString: Keinen freien Platz gefunden.\n"); + return 0; + } + + int StringOffset = Block->TotalTextLength; + Block->FreeEntries -= 1; + Block->TotalTextLength += StringLen + 1; + Block->EntryType[EntryIndex] = DYNAMIC_STRING_ALLOCATED; + Block->StringOffset[EntryIndex] = (uint16)StringOffset; + memcpy(&Block->Text[StringOffset], String, StringLen + 1); + + return (uint32)(1 + BlockIndex * DynamicBlockEntries + EntryIndex); +} + +const char *GetDynamicString(uint32 Number){ + if(Number == 0){ + return NULL; + } + + int BlockIndex = (int)(Number - 1) / DynamicBlockEntries; + int EntryIndex = (int)(Number - 1) % DynamicBlockEntries; + listnode *Node = DynamicStringTable.firstNode; + while(BlockIndex > 0 && Node != NULL){ + Node = Node->next; + BlockIndex -= 1; + } + + if(Node == NULL){ + error("GetDynamicString: Block für String %u existiert nicht\n", Number); + return NULL; + } + + TDynamicStringTableBlock *Block = &Node->data; + if(Block->EntryType[EntryIndex] != DYNAMIC_STRING_ALLOCATED){ + error("GetDynamicString: Eintrag für String %u existiert nicht\n", Number); + return NULL; + } + + int StringOffset = (int)Block->StringOffset[EntryIndex]; + return &Block->Text[StringOffset]; +} + +void DeleteDynamicString(uint32 Number){ + if(Number == 0){ + return; + } + + int BlockIndex = (int)(Number - 1) / DynamicBlockEntries; + int EntryIndex = (int)(Number - 1) % DynamicBlockEntries; + listnode *Node = DynamicStringTable.firstNode; + while(BlockIndex > 0 && Node != NULL){ + Node = Node->next; + BlockIndex -= 1; + } + + if(Node == NULL){ + error("DeleteDynamicString: Block für String %u existiert nicht\n", Number); + return; + } + + TDynamicStringTableBlock *Block = &Node->data; + if(Block->EntryType[EntryIndex] != DYNAMIC_STRING_ALLOCATED){ + error("DeleteDynamicString: Eintrag für String %u existiert nicht\n", Number); + return; + } + + Block->EntryType[EntryIndex] = DYNAMIC_STRING_DELETED; + Block->Dirty = true; +} + +void CleanupDynamicStrings(void){ + // IMPORTANT(fusion): The way we manage dynamic strings also mean pointers + // returned from `GetDynamicString` aren't stable. + for(listnode *Node = DynamicStringTable.firstNode; + Node != NULL; + Node = Node->next){ + TDynamicStringTableBlock *Block = &Node->data; + if(!Block->Dirty){ + continue; + } + + for(int i = 0; i < DynamicBlockEntries; i += 1){ + if(Block->EntryType[i] == DYNAMIC_STRING_DELETED){ + int StringOffset = Block->StringOffset[i]; + char *String = &Block->Text[StringOffset]; + int StringLen = (int)strlen(String); + int StringEnd = StringOffset + StringLen + 1; + Block->EntryType[i] = DYNAMIC_STRING_FREE; + + if(StringEnd > DynamicBlockSize){ + error("CleanupDynamicStrings: Stringende fehlt\n"); + continue; + } + + if(StringEnd < DynamicBlockSize){ + memmove(String, String + StringEnd, DynamicBlockSize - StringEnd); + } + + for(int j = 0; j < DynamicBlockEntries; j += 1){ + if(Block->EntryType[j] != DYNAMIC_STRING_FREE + && Block->StringOffset[j] > StringOffset){ + Block->StringOffset[j] -= StringLen + 1; + } + } + } + } + } +} void InitStrings(void){ // no-op diff --git a/src/stubs.hh b/src/stubs.hh index 316a2fe..372ca92 100644 --- a/src/stubs.hh +++ b/src/stubs.hh @@ -15,18 +15,13 @@ typedef void TRefreshSectorFunction(int SectorX, int SectorY, int SectorZ, const typedef void TSendMailsFunction(TPlayerData *PlayerData); extern void AbortWriter(void); -extern uint32 AddDynamicString(const char *String); -extern const char *AddStaticString(const char *String); extern void AnnounceChangedCreature(uint32 CreatureID, int Type); extern void BroadcastMessage(int Mode, const char *Text, ...) ATTR_PRINTF(2, 3); extern void Change(Object Obj, ObjectType NewType, uint32 Value); extern bool CheckRight(uint32 CreatureID, RIGHT Right); extern void CleanHouseField(int x, int y, int z); -extern void CleanupDynamicStrings(void); extern void CreatePlayerList(bool Online); -extern void DeleteDynamicString(uint32 Number); extern TCreature *GetCreature(uint32 CreatureID); -extern const char *GetDynamicString(uint32 Number); extern TConnection *GetFirstConnection(void); extern TConnection *GetNextConnection(void); extern void Log(const char *ProtocolName, const char *Text, ...) ATTR_PRINTF(2, 3); -- cgit v1.2.3