openclonk/standard/src/StdResStr2.cpp

172 lines
4.3 KiB
C++

/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2003, 2005-2006 Matthes Bender
* Copyright (c) 2005-2007 Günther Brammer
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
*
* Portions might be copyrighted by other authors who have contributed
* to OpenClonk.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
* See isc_license.txt for full license and disclaimer.
*
* "Clonk" is a registered trademark of Matthes Bender.
* See clonk_trademark_license.txt for full license.
*/
/* Load strings from a primitive memory string table */
#include <Standard.h>
#include <StdResStr2.h>
#include <StdBuf.h>
#include <stdio.h>
class ResTable {
public:
ResTable(const char * table): Capacity(int(1.10 * SCharCount('\n', table))), Count(0), Entries(new Entry[Capacity]) {
// reduce the capacity so that there is always an empty entry to mark the end of the search for an nonexistant key
--Capacity;
while (Count < Capacity) {
// search '='
const char * pos = table;
const char * equalpos = 0;
while (*pos && *pos != '\n' && *pos != '\r') {
if (*pos == '=') equalpos = pos;
++pos;
}
if (equalpos) {
unsigned int h = Hash(table);
// Get a pointer to the bucket
Entry * e = &(Entries[h % Capacity]);
// Search an empty spot
int i = 0;
while (e->Data) {
#ifdef _DEBUG
if (e->Hash == h) printf("Hash Collision: %d (\"%.50s\")\nSTRINGTABLE WILL BREAK\n", h, table);
#endif
e = &(Entries[(h + ++i) % Capacity]);
}
// Fill
e->Hash = h;
e->Data.CopyUntil(equalpos + 1, *pos);
// Compile line feeds ("\n" -> 0D0A)
for (i = 0; i < pos - equalpos; ++i)
if (e->Data.getMData()[i] == '\\' && e->Data.getMData()[i + 1] == 'n')
{ e->Data.getMData()[i] = 0x0D; e->Data.getMData()[i + 1] = 0x0A; }
// Count!
++Count;
}
while (*pos == '\n' || *pos == '\r') ++pos;
table = pos;
if (!*table) break;
}
}
~ResTable() {
delete[] Entries;
}
const char * GetEntry(const char * Key) {
if (!Key) return NULL;
unsigned int h = Hash(Key);
Entry * e = &(Entries[h % Capacity]);
int i = 0;
while (e->Hash != h && *e) e = &(Entries[(h + ++i) % Capacity]);
return e->Data.getData();
}
private:
struct Entry {
StdCopyStrBuf Data;
unsigned int Hash;
Entry(): Data(), Hash(0) { }
Entry(const StdStrBuf & Data, int32_t Hash): Data(Data), Hash(Hash) { }
operator const void * () { return Data; }
};
int Capacity;
int Count;
Entry * Entries;
static unsigned int Hash(const char * Key) {
// Fowler/Noll/Vo hash
unsigned int h = 2166136261u;
while (*Key && *Key != '=')
h = (h ^ *(Key++)) * 16777619;
return h;
}
};
static ResTable * Table = 0;
void SetResStrTable(char *pTable)
{
// Clear any old table
ClearResStrTable();
// Create new Table
Table = new ResTable(pTable);
delete[] pTable;
}
void ClearResStrTable()
{
delete Table;
Table = 0;
}
bool IsResStrTableLoaded() { return Table != 0; }
const char *GetResStr(const char *id, ResTable * Table) {
if (!Table) return "Language string table not loaded.";
const char * r = Table->GetEntry(id);
if (!r) {
static char strResult[1024];
// Default
sprintf(strResult, "[Undefined:%s]", id);
return strResult;
}
// Return string
return r;
}
const char *LoadResStr(const char *id)
{
return GetResStr(id, Table);
}
const int ResStrMaxLen = 4096;
static char strResult[ResStrMaxLen + 1];
char *LoadResStrNoAmp(const char *id)
{
const char * str = LoadResStr(id);
char * cpd = strResult;
for (const char * cps = str; *cps; ++cps, ++cpd)
{
if (*cps == '&')
--cpd;
else
*cpd = *cps;
}
*cpd = 0;
return strResult;
}
char *GetResStr(const char *id, const char *strTable)
{
const char *pos;
// Default
sprintf(strResult, "[Undefined:%s]", id);
// Compose identifier with operator
char idExt[256 + 1 + 1]; SCopy(id, idExt, 256); SAppendChar('=', idExt);
// String table present and id not empty
if (strTable && id && id[0])
// Search for identifier with operator
if ((pos = SSearch(strTable, idExt)))
// Get string until end of line
SCopyUntil(pos, strResult, "\r\n", ResStrMaxLen);
// Return string
return strResult;
}