mirror of
https://github.com/alliedmodders/amxmodx.git
synced 2024-12-26 14:55:36 +03:00
Rewrote language backend for integrity checking and optimization
Replaced CRC32 system with real hash-map
This commit is contained in:
parent
bb292d13ad
commit
f13599177f
@ -46,9 +46,9 @@
|
|||||||
#define INSERT_STRING 3
|
#define INSERT_STRING 3
|
||||||
#define INSERT_NEWLINE 4
|
#define INSERT_NEWLINE 4
|
||||||
|
|
||||||
// dictionary format is Fast-Format-Hash-Lookup, v4
|
// dictionary format is Fast-Format-Hash-Lookup, v5
|
||||||
#define MAGIC_HDR 0x4646484C
|
#define MAGIC_HDR 0x4646484C
|
||||||
#define FFHL_VERSION 4
|
#define FFHL_VERSION 5
|
||||||
#define FFHL_MIN_VERSION 4
|
#define FFHL_MIN_VERSION 4
|
||||||
|
|
||||||
/*version history:
|
/*version history:
|
||||||
@ -56,6 +56,7 @@
|
|||||||
* 2 (BAILOPAN) - One language per file with full reverse
|
* 2 (BAILOPAN) - One language per file with full reverse
|
||||||
* 3 (PM OnoTo) - 2^32 languages per file with full reverse
|
* 3 (PM OnoTo) - 2^32 languages per file with full reverse
|
||||||
* 4 (BAILOPAN) - Optimized by separating and relocating tables (normalization)
|
* 4 (BAILOPAN) - Optimized by separating and relocating tables (normalization)
|
||||||
|
* 5 (BAILOPAN) - Removed hash storage
|
||||||
FORMAT:
|
FORMAT:
|
||||||
Magic 4bytes
|
Magic 4bytes
|
||||||
Version 1byte
|
Version 1byte
|
||||||
@ -65,13 +66,11 @@ LANG INFO TABLE[]
|
|||||||
Language Name 2bytes
|
Language Name 2bytes
|
||||||
Offset 4bytes
|
Offset 4bytes
|
||||||
KEY TABLE[]
|
KEY TABLE[]
|
||||||
Key Hash 4bytes
|
|
||||||
Key Lookup Offset 4bytes
|
Key Lookup Offset 4bytes
|
||||||
LANGUAGES TABLE[]
|
LANGUAGES TABLE[]
|
||||||
Language[]
|
Language[]
|
||||||
Definitions 4bytes
|
Definitions 4bytes
|
||||||
Key Hash # 4bytes (virtual # in hash table, 0 indexed)
|
Key # 4bytes (0-index into key table)
|
||||||
Def Hash 4bytes
|
|
||||||
Def Offset 4bytes
|
Def Offset 4bytes
|
||||||
KEY LOOKUP TABLE[]
|
KEY LOOKUP TABLE[]
|
||||||
Key length 1byte
|
Key length 1byte
|
||||||
@ -81,70 +80,32 @@ DEF LOOKUP TABLE[]
|
|||||||
Def string variable
|
Def string variable
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/******** CRC & Strip *********/
|
template<>
|
||||||
const uint32_t CRCTable[256] = {
|
int Compare<String>(const String &k1, const String &k2)
|
||||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
|
||||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
|
||||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
|
||||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
|
||||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
|
||||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
|
||||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
|
||||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
|
||||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
|
||||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
|
||||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
|
||||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
|
||||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
|
||||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
|
||||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
|
||||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
|
||||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
|
||||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
|
||||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
|
||||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
|
||||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
|
||||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
|
||||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
|
||||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
|
||||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
|
||||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
|
||||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
|
||||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
|
||||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
|
||||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
|
||||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
|
||||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
|
||||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
|
||||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
|
||||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
|
||||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
|
||||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
|
||||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
|
||||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
|
||||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
|
||||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
|
||||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
|
||||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
|
|
||||||
|
|
||||||
uint32_t CLangMngr::CLang::MakeHash(const char *src, bool makeLower)
|
|
||||||
{
|
{
|
||||||
uint32_t crc = 0xFFFFFFFF;
|
return k1.compare(k2.c_str());
|
||||||
|
|
||||||
while (*src)
|
|
||||||
crc = ((crc>>8)&0xFFFFFFFF)^CRCTable[(crc^ (makeLower ? tolower(*src++) : *src++) )&0xFF];
|
|
||||||
|
|
||||||
return ~crc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t CLangMngr::MakeHash(const char *src, bool makeLower)
|
template<>
|
||||||
|
int HashFunction<String>(const String &k)
|
||||||
{
|
{
|
||||||
uint32_t crc = 0xFFFFFFFF;
|
unsigned long hash = 5381;
|
||||||
|
const char *str = k.c_str();
|
||||||
|
char c;
|
||||||
|
while (c = *str++) hash = ((hash << 5) + hash) + c; // hash*33 + c
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
while (*src)
|
template<>
|
||||||
crc = ((crc>>8)&0xFFFFFFFF)^CRCTable[(crc^ (makeLower ? tolower(*src++) : *src++) )&0xFF];
|
int HashFunction<int>(const int &k)
|
||||||
|
{
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
return ~crc;
|
template<>
|
||||||
|
int Compare<int>(const int &k1, const int &k2)
|
||||||
|
{
|
||||||
|
return (k1-k2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// strip the whitespaces at the beginning and the end of a string
|
// strip the whitespaces at the beginning and the end of a string
|
||||||
@ -188,86 +149,6 @@ size_t CLangMngr::strip(char *str, char *newstr, bool makelower)
|
|||||||
return ptr - str + 1;
|
return ptr - str + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******** CLangMngr::CLang::LangEntry *********/
|
|
||||||
uint32_t CLangMngr::CLang::LangEntry::GetDefHash()
|
|
||||||
{
|
|
||||||
return m_DefHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLangMngr::CLang::LangEntry::SetCache(bool c)
|
|
||||||
{
|
|
||||||
m_isCache = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CLangMngr::CLang::LangEntry::GetCache()
|
|
||||||
{
|
|
||||||
return m_isCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *CLangMngr::CLang::LangEntry::GetDef()
|
|
||||||
{
|
|
||||||
return m_pDef.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
int CLangMngr::CLang::LangEntry::GetDefLength()
|
|
||||||
{
|
|
||||||
return m_pDef.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
int CLangMngr::CLang::LangEntry::GetKey()
|
|
||||||
{
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
CLangMngr::CLang::LangEntry::LangEntry()
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
CLangMngr::CLang::LangEntry::LangEntry(int pKey)
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
SetKey(pKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
CLangMngr::CLang::LangEntry::LangEntry(int pKey, const char *pDef)
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
SetKey(pKey);
|
|
||||||
SetDef(pDef);
|
|
||||||
}
|
|
||||||
|
|
||||||
CLangMngr::CLang::LangEntry::LangEntry(const LangEntry &other)
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
SetKey(other.key);
|
|
||||||
SetDef(other.m_pDef.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
CLangMngr::CLang::LangEntry::LangEntry(int pKey, uint32_t defHash, const char *pDef)
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
key = pKey;
|
|
||||||
m_DefHash = defHash;
|
|
||||||
m_pDef.assign(pDef);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLangMngr::CLang::LangEntry::Clear()
|
|
||||||
{
|
|
||||||
m_pDef.clear();
|
|
||||||
key = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLangMngr::CLang::LangEntry::SetKey(int pkey)
|
|
||||||
{
|
|
||||||
key = pkey;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLangMngr::CLang::LangEntry::SetDef(const char *pDef)
|
|
||||||
{
|
|
||||||
m_pDef.assign(pDef);
|
|
||||||
m_DefHash = MakeHash(pDef);
|
|
||||||
}
|
|
||||||
|
|
||||||
/******** CLangMngr::CLang *********/
|
/******** CLangMngr::CLang *********/
|
||||||
|
|
||||||
@ -283,15 +164,14 @@ CLangMngr::CLang::CLang(const char *lang)
|
|||||||
m_LanguageName[2] = 0;
|
m_LanguageName[2] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
CLangMngr::CLang::LangEntry *CLangMngr::CLang::AddEntry(int pKey, uint32_t defHash, const char *def, bool cache)
|
void CLangMngr::CLang::AddEntry(int key, const char *definition)
|
||||||
{
|
{
|
||||||
LangEntry *p = new LangEntry(pKey, defHash, def);
|
defentry &d = m_LookUpTable[key];
|
||||||
|
|
||||||
p->SetCache(cache);
|
if (d.definition)
|
||||||
|
delete d.definition;
|
||||||
|
|
||||||
m_LookUpTable.push_back(p);
|
d.definition = new String(definition);
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CLangMngr::CLang::~CLang()
|
CLangMngr::CLang::~CLang()
|
||||||
@ -301,99 +181,66 @@ CLangMngr::CLang::~CLang()
|
|||||||
|
|
||||||
void CLangMngr::CLang::Clear()
|
void CLangMngr::CLang::Clear()
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < m_LookUpTable.size(); i++)
|
THash<int, defentry>::iterator iter;
|
||||||
|
for (iter=m_LookUpTable.begin(); iter!=m_LookUpTable.end(); iter++)
|
||||||
{
|
{
|
||||||
if (m_LookUpTable[i])
|
if (iter->val.definition)
|
||||||
delete m_LookUpTable[i];
|
{
|
||||||
|
delete iter->val.definition;
|
||||||
|
iter->val.definition = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_LookUpTable.clear();
|
m_LookUpTable.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
CLangMngr::CLang::LangEntry * CLangMngr::CLang::GetEntry(int pkey)
|
void CLangMngr::CLang::MergeDefinitions(CQueue<sKeyDef> &vec)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
String *pDef;
|
||||||
|
|
||||||
for (i = 0; i < m_LookUpTable.size(); i++)
|
|
||||||
{
|
|
||||||
if (m_LookUpTable[i]->GetKey() == pkey)
|
|
||||||
{
|
|
||||||
return m_LookUpTable[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LangEntry *e = new LangEntry(pkey);
|
|
||||||
e->SetKey(pkey);
|
|
||||||
e->SetCache(true);
|
|
||||||
m_LookUpTable.push_back(e);
|
|
||||||
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLangMngr::CLang::MergeDefinitions(CQueue<sKeyDef*> &vec)
|
|
||||||
{
|
|
||||||
const char *def = 0;
|
|
||||||
int key = -1;
|
int key = -1;
|
||||||
|
|
||||||
while (!vec.empty())
|
while (!vec.empty())
|
||||||
{
|
{
|
||||||
key = vec.front()->key;
|
key = vec.front().key;
|
||||||
def = vec.front()->def->c_str();
|
pDef = vec.front().definition;
|
||||||
LangEntry *entry = GetEntry(key);
|
|
||||||
|
|
||||||
if (entry->GetDefHash() != MakeHash(def))
|
AddEntry(key, pDef->c_str());
|
||||||
{
|
|
||||||
if (entry->GetCache())
|
delete vec.front().definition;
|
||||||
{
|
|
||||||
entry->SetDef(def);
|
|
||||||
entry->SetKey(key);
|
|
||||||
entry->SetCache(false);
|
|
||||||
} else {
|
|
||||||
//AMXXLOG_Log("[AMXX] Language key %s[%s] defined twice", m_LMan->GetKey(key), m_LanguageName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete vec.front();
|
|
||||||
vec.pop();
|
vec.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char * CLangMngr::CLang::GetDef(const char *key, int &status)
|
const char * CLangMngr::CLang::GetDef(int key, int &status)
|
||||||
{
|
{
|
||||||
int ikey = m_LMan->GetKeyEntry(key);
|
defentry &def = m_LookUpTable[key];
|
||||||
|
|
||||||
if (ikey == -1)
|
if (!def.definition)
|
||||||
{
|
{
|
||||||
|
status = LANG_STATUS_KLNOTFOUND;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < m_LookUpTable.size(); i++)
|
return def.definition->c_str();
|
||||||
{
|
|
||||||
if (m_LookUpTable[i]->GetKey() == ikey)
|
|
||||||
return m_LookUpTable[i]->GetDef();
|
|
||||||
}
|
|
||||||
|
|
||||||
status = LANG_STATUS_KLNOTFOUND;
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OffsetPair
|
|
||||||
{
|
|
||||||
uint32_t defOffset;
|
|
||||||
uint32_t keyOffset;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Assumes fp is set to the right position
|
// Assumes fp is set to the right position
|
||||||
bool CLangMngr::CLang::SaveDefinitions(FILE *fp, uint32_t &curOffset)
|
bool CLangMngr::CLang::SaveDefinitions(FILE *fp, uint32_t &curOffset)
|
||||||
{
|
{
|
||||||
unsigned short defLen = 0;
|
unsigned short defLen = 0;
|
||||||
|
String *pdef;
|
||||||
|
String blank;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < m_LookUpTable.size(); i++)
|
THash<int, defentry>::iterator iter;
|
||||||
|
for (iter=m_LookUpTable.begin(); iter!=m_LookUpTable.end(); iter++)
|
||||||
{
|
{
|
||||||
defLen = m_LookUpTable[i]->GetDefLength();
|
pdef = iter->val.definition;
|
||||||
|
if (!pdef)
|
||||||
|
pdef = ␣
|
||||||
|
defLen = pdef->size();
|
||||||
fwrite((void *)&defLen, sizeof(unsigned short), 1, fp);
|
fwrite((void *)&defLen, sizeof(unsigned short), 1, fp);
|
||||||
curOffset += sizeof(unsigned short);
|
curOffset += sizeof(unsigned short);
|
||||||
fwrite(m_LookUpTable[i]->GetDef(), sizeof(char), defLen, fp);
|
fwrite(pdef->c_str(), sizeof(char), defLen, fp);
|
||||||
curOffset += defLen;
|
curOffset += defLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,24 +251,26 @@ bool CLangMngr::CLang::SaveDefinitions(FILE *fp, uint32_t &curOffset)
|
|||||||
bool CLangMngr::CLang::Save(FILE *fp, int &defOffset, uint32_t &curOffset)
|
bool CLangMngr::CLang::Save(FILE *fp, int &defOffset, uint32_t &curOffset)
|
||||||
{
|
{
|
||||||
uint32_t keynum = 0;
|
uint32_t keynum = 0;
|
||||||
uint32_t defhash = 0;
|
|
||||||
uint32_t size = m_LookUpTable.size();
|
uint32_t size = m_LookUpTable.size();
|
||||||
|
String *pdef;
|
||||||
|
String blank;
|
||||||
|
|
||||||
fwrite((void*)&size, sizeof(uint32_t), 1, fp);
|
fwrite((void*)&size, sizeof(uint32_t), 1, fp);
|
||||||
curOffset += sizeof(uint32_t);
|
curOffset += sizeof(uint32_t);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < m_LookUpTable.size(); i++)
|
THash<int, defentry>::iterator iter;
|
||||||
|
for (iter=m_LookUpTable.begin(); iter!=m_LookUpTable.end(); iter++)
|
||||||
{
|
{
|
||||||
keynum = m_LookUpTable[i]->GetKey();
|
keynum = iter->key;
|
||||||
defhash = m_LookUpTable[i]->GetDefHash();
|
pdef = iter->val.definition;
|
||||||
|
if (!pdef)
|
||||||
|
pdef = ␣
|
||||||
fwrite((void *)&keynum, sizeof(uint32_t), 1, fp);
|
fwrite((void *)&keynum, sizeof(uint32_t), 1, fp);
|
||||||
curOffset += sizeof(uint32_t);
|
curOffset += sizeof(uint32_t);
|
||||||
fwrite((void *)&defhash, sizeof(uint32_t), 1, fp);
|
|
||||||
curOffset += sizeof(uint32_t);
|
|
||||||
fwrite((void *)&defOffset, sizeof(uint32_t), 1, fp);
|
fwrite((void *)&defOffset, sizeof(uint32_t), 1, fp);
|
||||||
curOffset += sizeof(uint32_t);
|
curOffset += sizeof(uint32_t);
|
||||||
defOffset += sizeof(short);
|
defOffset += sizeof(short);
|
||||||
defOffset += m_LookUpTable[i]->GetDefLength();
|
defOffset += pdef->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -443,69 +292,36 @@ CLangMngr::CLangMngr()
|
|||||||
const char * CLangMngr::GetKey(int key)
|
const char * CLangMngr::GetKey(int key)
|
||||||
{
|
{
|
||||||
if (key < 0 || key >= (int)KeyList.size())
|
if (key < 0 || key >= (int)KeyList.size())
|
||||||
return 0;
|
return NULL;
|
||||||
|
|
||||||
return KeyList[key]->key.c_str();
|
return KeyList[key]->c_str();
|
||||||
}
|
|
||||||
|
|
||||||
int CLangMngr::GetKeyHash(int key)
|
|
||||||
{
|
|
||||||
if (key < 0 || key >= (int)KeyList.size())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return KeyList[key]->hash;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int CLangMngr::GetKeyEntry(const char *key)
|
int CLangMngr::GetKeyEntry(const char *key)
|
||||||
{
|
{
|
||||||
uint32_t hKey = MakeHash(key, true);
|
keytbl_val val = KeyTable[key];
|
||||||
uint32_t cmpKey = 0;
|
|
||||||
unsigned int i = 0;
|
|
||||||
|
|
||||||
if (hKey == 0)
|
return val.index;
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < KeyList.size(); i++)
|
|
||||||
{
|
|
||||||
cmpKey = KeyList[i]->hash;
|
|
||||||
|
|
||||||
if (hKey == cmpKey)
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int CLangMngr::AddKeyEntry(String &key)
|
int CLangMngr::AddKeyEntry(String &key)
|
||||||
{
|
{
|
||||||
uint32_t hKey = MakeHash(key.c_str(), true);
|
keytbl_val val;
|
||||||
|
val.index = static_cast<int>(KeyList.size());
|
||||||
|
|
||||||
keyEntry *e = new keyEntry;
|
String *pString = new String(key);
|
||||||
e->key.assign(key);
|
KeyList.push_back(pString);
|
||||||
e->hash = hKey;
|
|
||||||
KeyList.push_back(e);
|
|
||||||
|
|
||||||
return (KeyList.size() - 1);
|
KeyTable[key] = val;
|
||||||
|
|
||||||
|
return val.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CLangMngr::GetKeyEntry(String &key)
|
int CLangMngr::GetKeyEntry(String &key)
|
||||||
{
|
{
|
||||||
uint32_t hKey = MakeHash(key.c_str(), true);
|
keytbl_val val = KeyTable[key];
|
||||||
unsigned int i = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < KeyList.size(); i++)
|
return val.index;
|
||||||
{
|
|
||||||
if (hKey == KeyList[i]->hash)
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CHECK_PTR(ptr, start, bufsize) if ((ptr) - (start) >= (bufsize)) { \
|
#define CHECK_PTR(ptr, start, bufsize) if ((ptr) - (start) >= (bufsize)) { \
|
||||||
@ -993,7 +809,7 @@ char *CLangMngr::FormatString(const char *fmt, va_list &ap)
|
|||||||
return outbuf;
|
return outbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CLangMngr::MergeDefinitions(const char *lang, CQueue<sKeyDef*> &tmpVec)
|
void CLangMngr::MergeDefinitions(const char *lang, CQueue<sKeyDef> &tmpVec)
|
||||||
{
|
{
|
||||||
CLang * language = GetLang(lang);
|
CLang * language = GetLang(lang);
|
||||||
if (language)
|
if (language)
|
||||||
@ -1062,10 +878,10 @@ int CLangMngr::MergeDefinitionFile(const char *file)
|
|||||||
// Allocate enough memory to store everything
|
// Allocate enough memory to store everything
|
||||||
bool multiline = 0;
|
bool multiline = 0;
|
||||||
int pos = 0, line = 0;
|
int pos = 0, line = 0;
|
||||||
CQueue<sKeyDef*> Defq;
|
CQueue<sKeyDef> Defq;
|
||||||
String buf;
|
String buf;
|
||||||
char language[3];
|
char language[3];
|
||||||
sKeyDef *tmpEntry = NULL;
|
sKeyDef tmpEntry;
|
||||||
|
|
||||||
while (!feof(fp))
|
while (!feof(fp))
|
||||||
{
|
{
|
||||||
@ -1082,9 +898,8 @@ int CLangMngr::MergeDefinitionFile(const char *file)
|
|||||||
if (multiline)
|
if (multiline)
|
||||||
{
|
{
|
||||||
AMXXLOG_Log("New section, multiline unterminated (file \"%s\" line %d)", file, line);
|
AMXXLOG_Log("New section, multiline unterminated (file \"%s\" line %d)", file, line);
|
||||||
if (tmpEntry)
|
tmpEntry.key = -1;
|
||||||
delete tmpEntry;
|
tmpEntry.definition = NULL;
|
||||||
tmpEntry = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Defq.empty())
|
if (!Defq.empty())
|
||||||
@ -1102,7 +917,6 @@ int CLangMngr::MergeDefinitionFile(const char *file)
|
|||||||
|
|
||||||
if (pos > String::npos)
|
if (pos > String::npos)
|
||||||
{
|
{
|
||||||
tmpEntry = new sKeyDef;
|
|
||||||
String key;
|
String key;
|
||||||
key.assign(buf.substr(0, pos).c_str());
|
key.assign(buf.substr(0, pos).c_str());
|
||||||
String def;
|
String def;
|
||||||
@ -1112,18 +926,18 @@ int CLangMngr::MergeDefinitionFile(const char *file)
|
|||||||
int iKey = GetKeyEntry(key);
|
int iKey = GetKeyEntry(key);
|
||||||
if (iKey == -1)
|
if (iKey == -1)
|
||||||
iKey = AddKeyEntry(key);
|
iKey = AddKeyEntry(key);
|
||||||
tmpEntry->key = iKey;
|
tmpEntry.key = iKey;
|
||||||
tmpEntry->def = new String;
|
tmpEntry.definition = new String;
|
||||||
tmpEntry->def->assign(def.c_str());
|
tmpEntry.definition->assign(def.c_str());
|
||||||
tmpEntry->def->trim();
|
tmpEntry.definition->trim();
|
||||||
Defq.push(tmpEntry);
|
Defq.push(tmpEntry);
|
||||||
tmpEntry = 0;
|
tmpEntry.key = -1;
|
||||||
|
tmpEntry.definition = NULL;
|
||||||
} else {
|
} else {
|
||||||
pos = buf.find(':');
|
pos = buf.find(':');
|
||||||
|
|
||||||
if (pos > String::npos)
|
if (pos > String::npos)
|
||||||
{
|
{
|
||||||
tmpEntry = new sKeyDef;
|
|
||||||
String key;
|
String key;
|
||||||
key.assign(buf.substr(0, pos).c_str());;
|
key.assign(buf.substr(0, pos).c_str());;
|
||||||
key.trim();
|
key.trim();
|
||||||
@ -1131,8 +945,8 @@ int CLangMngr::MergeDefinitionFile(const char *file)
|
|||||||
int iKey = GetKeyEntry(key);
|
int iKey = GetKeyEntry(key);
|
||||||
if (iKey == -1)
|
if (iKey == -1)
|
||||||
iKey = AddKeyEntry(key);
|
iKey = AddKeyEntry(key);
|
||||||
tmpEntry->key = iKey;
|
tmpEntry.key = iKey;
|
||||||
tmpEntry->def = new String;
|
tmpEntry.definition = new String;
|
||||||
multiline = true;
|
multiline = true;
|
||||||
} else {
|
} else {
|
||||||
//user typed a line with no directives
|
//user typed a line with no directives
|
||||||
@ -1143,10 +957,13 @@ int CLangMngr::MergeDefinitionFile(const char *file)
|
|||||||
if (buf[0] == ':')
|
if (buf[0] == ':')
|
||||||
{
|
{
|
||||||
Defq.push(tmpEntry);
|
Defq.push(tmpEntry);
|
||||||
tmpEntry = 0;
|
tmpEntry.key = -1;
|
||||||
|
tmpEntry.definition = NULL;
|
||||||
multiline = false;
|
multiline = false;
|
||||||
} else {
|
} else {
|
||||||
tmpEntry->def->append(buf);
|
if (!tmpEntry.definition)
|
||||||
|
tmpEntry.definition = new String();
|
||||||
|
tmpEntry.definition->append(buf);
|
||||||
}
|
}
|
||||||
} // if !multiline
|
} // if !multiline
|
||||||
} //if - main
|
} //if - main
|
||||||
@ -1194,16 +1011,30 @@ CLangMngr::CLang * CLangMngr::GetLangR(const char *name)
|
|||||||
const char *CLangMngr::GetDef(const char *langName, const char *key, int &status)
|
const char *CLangMngr::GetDef(const char *langName, const char *key, int &status)
|
||||||
{
|
{
|
||||||
CLang *lang = GetLangR(langName);
|
CLang *lang = GetLangR(langName);
|
||||||
if (lang)
|
keytbl_val val = KeyTable[key];
|
||||||
|
if (lang == NULL)
|
||||||
{
|
{
|
||||||
//status = LANG_STATUS_OK;
|
|
||||||
return lang->GetDef(key, status);
|
|
||||||
} else {
|
|
||||||
status = LANG_STATUS_LNOTFOUND;
|
status = LANG_STATUS_LNOTFOUND;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
} else if (val.index == -1) {
|
||||||
|
status = LANG_STATUS_KLNOTFOUND;
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
return lang->GetDef(val.index, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CLangMngr::InvalidateCache()
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < FileList.size(); i++)
|
||||||
|
{
|
||||||
|
if (FileList[i])
|
||||||
|
delete FileList[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
FileList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
bool CLangMngr::Save(const char *filename)
|
bool CLangMngr::Save(const char *filename)
|
||||||
{
|
{
|
||||||
FILE *fp = fopen(filename, "wb");
|
FILE *fp = fopen(filename, "wb");
|
||||||
@ -1217,7 +1048,7 @@ bool CLangMngr::Save(const char *filename)
|
|||||||
const char *langName = 0;
|
const char *langName = 0;
|
||||||
uint32_t curOffset = 0;
|
uint32_t curOffset = 0;
|
||||||
uint32_t keyNum = KeyList.size();
|
uint32_t keyNum = KeyList.size();
|
||||||
uint32_t ktbSize = KeyList.size() * (sizeof(uint32_t) + sizeof(uint32_t));
|
uint32_t ktbSize = KeyList.size() * sizeof(uint32_t);
|
||||||
uint32_t ltbSize = m_Languages.size() * ((sizeof(char)*2) + sizeof(uint32_t));
|
uint32_t ltbSize = m_Languages.size() * ((sizeof(char)*2) + sizeof(uint32_t));
|
||||||
|
|
||||||
fwrite((void *)&magic, sizeof(uint32_t), 1, fp);
|
fwrite((void *)&magic, sizeof(uint32_t), 1, fp);
|
||||||
@ -1237,7 +1068,7 @@ bool CLangMngr::Save(const char *filename)
|
|||||||
fwrite(langName, sizeof(char), 2, fp);
|
fwrite(langName, sizeof(char), 2, fp);
|
||||||
curOffset += sizeof(char) * 2;
|
curOffset += sizeof(char) * 2;
|
||||||
fwrite((void *)&langOffset, sizeof(uint32_t), 1, fp);
|
fwrite((void *)&langOffset, sizeof(uint32_t), 1, fp);
|
||||||
langOffset += sizeof(uint32_t) + (m_Languages[i]->Entries() * (sizeof(uint32_t) * 3));
|
langOffset += sizeof(uint32_t) + (m_Languages[i]->Entries() * (sizeof(uint32_t) * 2));
|
||||||
curOffset += sizeof(uint32_t);
|
curOffset += sizeof(uint32_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1246,13 +1077,10 @@ bool CLangMngr::Save(const char *filename)
|
|||||||
uint32_t keyOffset = langOffset;
|
uint32_t keyOffset = langOffset;
|
||||||
for (unsigned int i = 0; i < KeyList.size(); i++)
|
for (unsigned int i = 0; i < KeyList.size(); i++)
|
||||||
{
|
{
|
||||||
keyHash = KeyList[i]->hash;
|
|
||||||
fwrite((void*)&keyHash, sizeof(uint32_t), 1, fp);
|
|
||||||
curOffset += sizeof(uint32_t);
|
|
||||||
fwrite((void*)&keyOffset, sizeof(uint32_t), 1, fp);
|
fwrite((void*)&keyOffset, sizeof(uint32_t), 1, fp);
|
||||||
curOffset += sizeof(uint32_t);
|
curOffset += sizeof(uint32_t);
|
||||||
keyOffset += sizeof(char);
|
keyOffset += sizeof(char);
|
||||||
keyOffset += KeyList[i]->key.size();
|
keyOffset += KeyList[i]->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Note - now keyOffset points toward the start of the def table
|
//Note - now keyOffset points toward the start of the def table
|
||||||
@ -1267,10 +1095,10 @@ bool CLangMngr::Save(const char *filename)
|
|||||||
unsigned char keyLen = 0;
|
unsigned char keyLen = 0;
|
||||||
for (unsigned int i = 0; i < KeyList.size(); i++)
|
for (unsigned int i = 0; i < KeyList.size(); i++)
|
||||||
{
|
{
|
||||||
keyLen = KeyList[i]->key.size();
|
keyLen = KeyList[i]->size();
|
||||||
fwrite((void*)&keyLen, sizeof(unsigned char), 1, fp);
|
fwrite((void*)&keyLen, sizeof(unsigned char), 1, fp);
|
||||||
curOffset += sizeof(unsigned char);
|
curOffset += sizeof(unsigned char);
|
||||||
fwrite(KeyList[i]->key.c_str(), sizeof(char), keyLen, fp);
|
fwrite(KeyList[i]->c_str(), sizeof(char), keyLen, fp);
|
||||||
curOffset += sizeof(char) * keyLen;
|
curOffset += sizeof(char) * keyLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1314,6 +1142,19 @@ bool CLangMngr::SaveCache(const char *filename)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define CACHEREAD(expr, type) \
|
||||||
|
if (! (expr==sizeof(type)) ) { \
|
||||||
|
FileList.clear(); \
|
||||||
|
fclose(fp); \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
|
#define CACHEREAD_S(expr, size) \
|
||||||
|
if (! (expr==size) ) { \
|
||||||
|
FileList.clear(); \
|
||||||
|
fclose(fp); \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
|
|
||||||
bool CLangMngr::LoadCache(const char *filename)
|
bool CLangMngr::LoadCache(const char *filename)
|
||||||
{
|
{
|
||||||
FILE *fp = fopen(filename, "rb");
|
FILE *fp = fopen(filename, "rb");
|
||||||
@ -1326,15 +1167,15 @@ bool CLangMngr::LoadCache(const char *filename)
|
|||||||
char len = 0;
|
char len = 0;
|
||||||
char buf[255];
|
char buf[255];
|
||||||
char md5[34];
|
char md5[34];
|
||||||
fread((void*)&dictCount, sizeof(short), 1, fp);
|
CACHEREAD(fread((void*)&dictCount, sizeof(short), 1, fp), short);
|
||||||
md5Pair *p = 0;
|
md5Pair *p = 0;
|
||||||
|
|
||||||
for (int i = 1; i <= dictCount; i++)
|
for (int i = 1; i <= dictCount; i++)
|
||||||
{
|
{
|
||||||
fread((void*)&len, sizeof(char), 1, fp);
|
CACHEREAD(fread((void*)&len, sizeof(char), 1, fp), char);
|
||||||
fread(buf, sizeof(char), len, fp);
|
CACHEREAD_S(fread(buf, sizeof(char), len, fp), len);
|
||||||
buf[len] = 0;
|
buf[len] = 0;
|
||||||
fread(md5, sizeof(char), 32, fp);
|
CACHEREAD_S(fread(md5, sizeof(char), 32, fp), 32);
|
||||||
md5[32] = 0;
|
md5[32] = 0;
|
||||||
p = new md5Pair;
|
p = new md5Pair;
|
||||||
p->file.assign(buf);
|
p->file.assign(buf);
|
||||||
@ -1348,6 +1189,19 @@ bool CLangMngr::LoadCache(const char *filename)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DATREAD(expr, type) \
|
||||||
|
if (! (expr==1) ) { \
|
||||||
|
Clear(); \
|
||||||
|
fclose(fp); \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
|
#define DATREAD_S(expr, size) \
|
||||||
|
if (! (expr==size) ) { \
|
||||||
|
Clear(); \
|
||||||
|
fclose(fp); \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
|
|
||||||
bool CLangMngr::Load(const char *filename)
|
bool CLangMngr::Load(const char *filename)
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
@ -1362,75 +1216,93 @@ bool CLangMngr::Load(const char *filename)
|
|||||||
uint32_t keycount = 0;
|
uint32_t keycount = 0;
|
||||||
char version = 0;
|
char version = 0;
|
||||||
|
|
||||||
fread((void*)&magic, sizeof(uint32_t), 1, fp);
|
fseek(fp, 0, SEEK_END);
|
||||||
|
long size = ftell(fp);
|
||||||
|
rewind(fp);
|
||||||
|
|
||||||
|
DATREAD(fread((void*)&magic, sizeof(uint32_t), 1, fp), uint32_t);
|
||||||
if (magic != MAGIC_HDR)
|
if (magic != MAGIC_HDR)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
fread((void*)&version, sizeof(char), 1, fp);
|
DATREAD(fread((void*)&version, sizeof(char), 1, fp), char);
|
||||||
if (version > FFHL_VERSION || version < FFHL_MIN_VERSION)
|
if (version > FFHL_VERSION || version < FFHL_MIN_VERSION)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
fread((void*)&keycount, sizeof(uint32_t), 1, fp);
|
DATREAD(fread((void*)&keycount, sizeof(uint32_t), 1, fp), uint32_t);
|
||||||
fread((void*)&langCount, sizeof(uint32_t), 1, fp);
|
DATREAD(fread((void*)&langCount, sizeof(uint32_t), 1, fp), uint32_t);
|
||||||
|
|
||||||
uint32_t *LangOffsets = new uint32_t[langCount];
|
uint32_t *LangOffsets = new uint32_t[langCount];
|
||||||
char langname[3];
|
char langname[3];
|
||||||
|
|
||||||
for (unsigned int i = 0; i < langCount; i++)
|
for (unsigned int i = 0; i < langCount; i++)
|
||||||
{
|
{
|
||||||
fread(langname, sizeof(char), 2, fp);
|
DATREAD_S(fread(langname, sizeof(char), 2, fp), 2);
|
||||||
langname[2] = 0;
|
langname[2] = 0;
|
||||||
GetLang(langname); //this will initialize for us
|
GetLang(langname); //this will initialize for us
|
||||||
fread((void *)&(LangOffsets[i]), sizeof(uint32_t), 1, fp);
|
DATREAD(fread((void *)&(LangOffsets[i]), sizeof(uint32_t), 1, fp), uint32_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
//we should now be at the key table
|
//we should now be at the key table
|
||||||
int ktbOffset = ftell(fp);
|
int ktbOffset = ftell(fp);
|
||||||
keyEntry *e = 0;
|
|
||||||
unsigned char keylen;
|
unsigned char keylen;
|
||||||
|
char keybuf[255];
|
||||||
|
uint32_t bogus;
|
||||||
uint32_t keyoffset, save;
|
uint32_t keyoffset, save;
|
||||||
|
String _tmpkey;
|
||||||
|
|
||||||
for (unsigned i = 0; i < keycount; i++)
|
for (unsigned i = 0; i < keycount; i++)
|
||||||
{
|
{
|
||||||
e = new keyEntry;
|
if (version == 4)
|
||||||
fread((void*)&(e->hash), sizeof(uint32_t), 1, fp);
|
fread((void*)&(bogus), sizeof(uint32_t), 1, fp);
|
||||||
fread((void*)&keyoffset, sizeof(uint32_t), 1, fp);
|
DATREAD(fread((void*)&keyoffset, sizeof(uint32_t), 1, fp), uint32_t);
|
||||||
|
if (keyoffset > size-sizeof(uint32_t))
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
save = ftell(fp);
|
save = ftell(fp);
|
||||||
fseek(fp, keyoffset, SEEK_SET);
|
fseek(fp, keyoffset, SEEK_SET);
|
||||||
fread((void*)&keylen, sizeof(char), 1, fp);
|
DATREAD(fread((void*)&keylen, sizeof(char), 1, fp), char);
|
||||||
char *data = new char[keylen + 1];
|
DATREAD_S(fread(keybuf, sizeof(char), keylen, fp), keylen);
|
||||||
fread(data, sizeof(char), keylen, fp);
|
keybuf[keylen] = 0;
|
||||||
data[keylen] = 0;
|
_tmpkey.assign(keybuf);
|
||||||
e->key.assign(data);
|
AddKeyEntry(_tmpkey);
|
||||||
delete [] data;
|
|
||||||
KeyList.push_back(e);
|
|
||||||
fseek(fp, save, SEEK_SET); //bring back to next key
|
fseek(fp, save, SEEK_SET); //bring back to next key
|
||||||
}
|
}
|
||||||
|
|
||||||
//we should now be at the languages table
|
//we should now be at the languages table
|
||||||
uint32_t numentries;
|
uint32_t numentries;
|
||||||
uint32_t keynum;
|
uint32_t keynum;
|
||||||
uint32_t defhash;
|
|
||||||
uint32_t defoffset;
|
uint32_t defoffset;
|
||||||
unsigned short deflen;
|
unsigned short deflen;
|
||||||
|
char valbuf[4096];
|
||||||
|
|
||||||
for (unsigned int i = 0; i < langCount; i++)
|
for (unsigned int i = 0; i < langCount; i++)
|
||||||
{
|
{
|
||||||
fread((void*)&numentries, sizeof(uint32_t), 1, fp);
|
DATREAD(fread((void*)&numentries, sizeof(uint32_t), 1, fp), uint32_t);
|
||||||
|
|
||||||
for (unsigned int j = 0; j < numentries; j++)
|
for (unsigned int j = 0; j < numentries; j++)
|
||||||
{
|
{
|
||||||
fread((void *)&keynum, sizeof(uint32_t), 1, fp);
|
DATREAD(fread((void *)&keynum, sizeof(uint32_t), 1, fp), uint32_t);
|
||||||
fread((void *)&defhash, sizeof(uint32_t), 1, fp);
|
if (version == 4)
|
||||||
fread((void *)&defoffset, sizeof(uint32_t), 1, fp);
|
{
|
||||||
|
DATREAD(fread((void *)&bogus, sizeof(uint32_t), 1, fp), uint32_t);
|
||||||
|
}
|
||||||
|
DATREAD(fread((void *)&defoffset, sizeof(uint32_t), 1, fp), uint32_t);
|
||||||
|
if (defoffset > size-sizeof(uint32_t))
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
save = ftell(fp);
|
save = ftell(fp);
|
||||||
fseek(fp, defoffset, SEEK_SET);
|
fseek(fp, defoffset, SEEK_SET);
|
||||||
fread((void *)&deflen, sizeof(unsigned short), 1, fp);
|
DATREAD(fread((void *)&deflen, sizeof(unsigned short), 1, fp), short);
|
||||||
char *data = new char[deflen + 1];
|
//:TODO: possible string overflow here.
|
||||||
fread(data, sizeof(char), deflen, fp);
|
DATREAD_S(fread(valbuf, sizeof(char), deflen, fp), deflen);
|
||||||
data[deflen] = 0;
|
valbuf[deflen] = 0;
|
||||||
m_Languages[i]->AddEntry(keynum, defhash, data, true);
|
m_Languages[i]->AddEntry(keynum, valbuf);
|
||||||
delete [] data;
|
|
||||||
fseek(fp, save, SEEK_SET); //bring back to next entry
|
fseek(fp, save, SEEK_SET); //bring back to next entry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1452,6 +1324,8 @@ void CLangMngr::Clear()
|
|||||||
{
|
{
|
||||||
unsigned int i = 0;
|
unsigned int i = 0;
|
||||||
|
|
||||||
|
KeyTable.clear();
|
||||||
|
|
||||||
for (i = 0; i < m_Languages.size(); i++)
|
for (i = 0; i < m_Languages.size(); i++)
|
||||||
{
|
{
|
||||||
if (m_Languages[i])
|
if (m_Languages[i])
|
||||||
|
@ -32,6 +32,8 @@
|
|||||||
#ifndef _INCLUDE_CLANG_H
|
#ifndef _INCLUDE_CLANG_H
|
||||||
#define _INCLUDE_CLANG_H
|
#define _INCLUDE_CLANG_H
|
||||||
|
|
||||||
|
#include "sh_tinyhash.h"
|
||||||
|
|
||||||
#define LANG_SERVER 0
|
#define LANG_SERVER 0
|
||||||
#define LANG_PLAYER -1
|
#define LANG_PLAYER -1
|
||||||
|
|
||||||
@ -45,19 +47,35 @@ struct md5Pair
|
|||||||
String val;
|
String val;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct keyEntry
|
|
||||||
{
|
|
||||||
String key;
|
|
||||||
uint32_t hash;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sKeyDef
|
struct sKeyDef
|
||||||
{
|
{
|
||||||
sKeyDef() { key = -1; def = 0; }
|
String *definition;
|
||||||
~sKeyDef() { if (def) delete def; }
|
|
||||||
|
|
||||||
int key;
|
int key;
|
||||||
String *def;
|
};
|
||||||
|
|
||||||
|
class defentry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
defentry() : definition(NULL)
|
||||||
|
{
|
||||||
|
};
|
||||||
|
~defentry()
|
||||||
|
{
|
||||||
|
if (definition)
|
||||||
|
{
|
||||||
|
delete definition;
|
||||||
|
definition = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String *definition;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct keytbl_val
|
||||||
|
{
|
||||||
|
keytbl_val() : index(-1)
|
||||||
|
{
|
||||||
|
};
|
||||||
|
int index;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CLangMngr
|
class CLangMngr
|
||||||
@ -73,9 +91,9 @@ class CLangMngr
|
|||||||
~CLang();
|
~CLang();
|
||||||
|
|
||||||
// Get the definition
|
// Get the definition
|
||||||
const char *GetDef(const char *key, int &status);
|
const char *GetDef(int key, int &status);
|
||||||
// Add definitions to this language
|
// Add definitions to this language
|
||||||
void MergeDefinitions(CQueue <sKeyDef*> & vec);
|
void MergeDefinitions(CQueue <sKeyDef> & vec);
|
||||||
// Reset this language
|
// Reset this language
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
@ -95,49 +113,9 @@ class CLangMngr
|
|||||||
void SetMngr(CLangMngr *l) { m_LMan = l; }
|
void SetMngr(CLangMngr *l) { m_LMan = l; }
|
||||||
// Get number of entries
|
// Get number of entries
|
||||||
int Entries() { return m_LookUpTable.size(); }
|
int Entries() { return m_LookUpTable.size(); }
|
||||||
// Make a hash from a string; convert to lowercase first if needed
|
|
||||||
static uint32_t MakeHash(const char *src, bool makeLower = false);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// An entry in the language
|
typedef THash<int, defentry> LookUpVec;
|
||||||
class LangEntry
|
typedef LookUpVec::iterator LookUpVecIter;
|
||||||
{
|
|
||||||
// the definition hash
|
|
||||||
uint32_t m_DefHash;
|
|
||||||
// index into the lookup table?
|
|
||||||
int key;
|
|
||||||
// the definition
|
|
||||||
String m_pDef;
|
|
||||||
// is this from the cache or not?
|
|
||||||
bool m_isCache;
|
|
||||||
public:
|
|
||||||
// Set
|
|
||||||
void SetKey(int key);
|
|
||||||
void SetDef(const char *pDef);
|
|
||||||
void SetCache(bool c);
|
|
||||||
// Get
|
|
||||||
uint32_t GetDefHash();
|
|
||||||
int GetKey();
|
|
||||||
const char *GetDef();
|
|
||||||
int GetDefLength();
|
|
||||||
bool GetCache();
|
|
||||||
|
|
||||||
// Constructors / destructors
|
|
||||||
LangEntry();
|
|
||||||
LangEntry(int key);
|
|
||||||
LangEntry(int key, const char *pDef);
|
|
||||||
LangEntry(const LangEntry &other);
|
|
||||||
LangEntry(int pKey, uint32_t defHash, const char *pDef);
|
|
||||||
|
|
||||||
// Reset
|
|
||||||
void Clear();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get (construct if needed) an entry
|
|
||||||
LangEntry * GetEntry(int key);
|
|
||||||
|
|
||||||
typedef CVector<LangEntry*> LookUpVec;
|
|
||||||
typedef LookUpVec::iterator LookUpVecIter;
|
|
||||||
|
|
||||||
char m_LanguageName[3];
|
char m_LanguageName[3];
|
||||||
|
|
||||||
@ -145,11 +123,11 @@ class CLangMngr
|
|||||||
LookUpVec m_LookUpTable;
|
LookUpVec m_LookUpTable;
|
||||||
CLangMngr *m_LMan;
|
CLangMngr *m_LMan;
|
||||||
public:
|
public:
|
||||||
LangEntry *AddEntry(int pKey, uint32_t defHash, const char *def, bool cache);
|
void AddEntry(int key, const char *definition);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Merge definitions into a language
|
// Merge definitions into a language
|
||||||
void MergeDefinitions(const char *lang, CQueue <sKeyDef*> &tmpVec);
|
void MergeDefinitions(const char *lang, CQueue <sKeyDef> &tmpVec);
|
||||||
// strip lowercase; make lower if needed
|
// strip lowercase; make lower if needed
|
||||||
static size_t strip(char *str, char *newstr, bool makelower = false);
|
static size_t strip(char *str, char *newstr, bool makelower = false);
|
||||||
|
|
||||||
@ -159,7 +137,8 @@ class CLangMngr
|
|||||||
LangVec m_Languages;
|
LangVec m_Languages;
|
||||||
|
|
||||||
CVector<md5Pair *> FileList;
|
CVector<md5Pair *> FileList;
|
||||||
CVector<keyEntry*> KeyList;
|
CVector<String *> KeyList;
|
||||||
|
THash<String, keytbl_val> KeyTable;
|
||||||
|
|
||||||
// Get a lang object (construct if needed)
|
// Get a lang object (construct if needed)
|
||||||
CLang * GetLang(const char *name);
|
CLang * GetLang(const char *name);
|
||||||
@ -185,16 +164,15 @@ public:
|
|||||||
// Cache
|
// Cache
|
||||||
bool LoadCache(const char *filename);
|
bool LoadCache(const char *filename);
|
||||||
bool SaveCache(const char *filename);
|
bool SaveCache(const char *filename);
|
||||||
|
void InvalidateCache();
|
||||||
// Get index
|
// Get index
|
||||||
int GetKeyEntry(String &key);
|
int GetKeyEntry(String &key);
|
||||||
int GetKeyEntry(const char *key);
|
int GetKeyEntry(const char *key);
|
||||||
int GetKeyHash(int key);
|
int GetKeyIndex(const char *key);
|
||||||
// Get key from index
|
// Get key from index
|
||||||
const char *GetKey(int key);
|
const char *GetKey(int key);
|
||||||
// Add key
|
// Add key
|
||||||
int AddKeyEntry(String &key);
|
int AddKeyEntry(String &key);
|
||||||
// Make a hash from a string; convert to lowercase first if needed
|
|
||||||
uint32_t MakeHash(const char *src, bool makeLower);
|
|
||||||
|
|
||||||
// Get the number of languages
|
// Get the number of languages
|
||||||
int GetLangsNum();
|
int GetLangsNum();
|
||||||
|
@ -118,7 +118,7 @@ public:
|
|||||||
v[0] = '\0';
|
v[0] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
int compare (const char *d)
|
int compare (const char *d) const
|
||||||
{
|
{
|
||||||
if (!v)
|
if (!v)
|
||||||
return strcmp("", d);
|
return strcmp("", d);
|
||||||
|
@ -249,7 +249,10 @@ int C_Spawn(edict_t *pent)
|
|||||||
// ###### Load lang
|
// ###### Load lang
|
||||||
char file[256];
|
char file[256];
|
||||||
g_langMngr.LoadCache(build_pathname_r(file, sizeof(file) - 1, "%s/dictionary.cache", get_localinfo("amxx_datadir", "addons/amxmodx/data")));
|
g_langMngr.LoadCache(build_pathname_r(file, sizeof(file) - 1, "%s/dictionary.cache", get_localinfo("amxx_datadir", "addons/amxmodx/data")));
|
||||||
g_langMngr.Load(build_pathname_r(file, sizeof(file) - 1, "%s/languages.dat", get_localinfo("amxmodx_datadir", "addons/amxmodx/data")));
|
if (!g_langMngr.Load(build_pathname_r(file, sizeof(file) - 1, "%s/languages.dat", get_localinfo("amxmodx_datadir", "addons/amxmodx/data"))))
|
||||||
|
{
|
||||||
|
g_langMngr.InvalidateCache();
|
||||||
|
}
|
||||||
|
|
||||||
// ###### Initialize commands prefixes
|
// ###### Initialize commands prefixes
|
||||||
g_commands.registerPrefix("amx");
|
g_commands.registerPrefix("amx");
|
||||||
|
@ -257,7 +257,7 @@
|
|||||||
LinkIncremental="1"
|
LinkIncremental="1"
|
||||||
SuppressStartupBanner="TRUE"
|
SuppressStartupBanner="TRUE"
|
||||||
AdditionalLibraryDirectories="..\extra\lib_win32"
|
AdditionalLibraryDirectories="..\extra\lib_win32"
|
||||||
IgnoreDefaultLibraryNames="LIBC"
|
IgnoreDefaultLibraryNames="MSVCRT"
|
||||||
ModuleDefinitionFile=""
|
ModuleDefinitionFile=""
|
||||||
GenerateDebugInformation="TRUE"
|
GenerateDebugInformation="TRUE"
|
||||||
ProgramDatabaseFile=".\memtestrelease/amxx_mm.pdb"
|
ProgramDatabaseFile=".\memtestrelease/amxx_mm.pdb"
|
||||||
@ -822,9 +822,15 @@
|
|||||||
<File
|
<File
|
||||||
RelativePath="..\resource.h">
|
RelativePath="..\resource.h">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\sh_list.h">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\sh_stack.h">
|
RelativePath="..\sh_stack.h">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\sh_tinyhash.h">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\zlib\zconf.h">
|
RelativePath="..\zlib\zconf.h">
|
||||||
</File>
|
</File>
|
||||||
|
@ -32,7 +32,9 @@
|
|||||||
#define _INCLUDE_NATIVES_H
|
#define _INCLUDE_NATIVES_H
|
||||||
|
|
||||||
//only 16 for now sorry
|
//only 16 for now sorry
|
||||||
|
#if !defined CALLFUNC_MAXPARAMS
|
||||||
#define CALLFUNC_MAXPARAMS 16
|
#define CALLFUNC_MAXPARAMS 16
|
||||||
|
#endif
|
||||||
|
|
||||||
#define CALLFUNC_FLAG_BYREF 1
|
#define CALLFUNC_FLAG_BYREF 1
|
||||||
#define CALLFUNC_FLAG_BYREF_REUSED 2
|
#define CALLFUNC_FLAG_BYREF_REUSED 2
|
||||||
|
268
amxmodx/sh_list.h
Normal file
268
amxmodx/sh_list.h
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
/* ======== SourceMM ========
|
||||||
|
* Copyright (C) 2004-2005 Metamod:Source Development Team
|
||||||
|
* No warranties of any kind
|
||||||
|
*
|
||||||
|
* License: zlib/libpng
|
||||||
|
*
|
||||||
|
* Author(s): David "BAILOPAN" Anderson
|
||||||
|
* ============================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE_SMM_LIST_H
|
||||||
|
#define _INCLUDE_SMM_LIST_H
|
||||||
|
|
||||||
|
//namespace SourceHook
|
||||||
|
//{
|
||||||
|
//This class is from CSDM for AMX Mod X
|
||||||
|
template <class T>
|
||||||
|
class List
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
class iterator;
|
||||||
|
friend class iterator;
|
||||||
|
class ListNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ListNode(const T & o) : obj(o) { };
|
||||||
|
ListNode() { };
|
||||||
|
~ListNode()
|
||||||
|
{
|
||||||
|
};
|
||||||
|
T obj;
|
||||||
|
ListNode *next;
|
||||||
|
ListNode *prev;
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
ListNode *_Initialize()
|
||||||
|
{
|
||||||
|
ListNode *n = (ListNode *)malloc(sizeof(ListNode));
|
||||||
|
n->next = NULL;
|
||||||
|
n->prev = NULL;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
List() : m_Head(_Initialize()), m_Size(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
List(const List &src) : m_Head(_Initialize()), m_Size(0)
|
||||||
|
{
|
||||||
|
iterator iter;
|
||||||
|
for (iter=src.begin(); iter!=src.end(); iter++)
|
||||||
|
push_back( (*iter) );
|
||||||
|
}
|
||||||
|
~List()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
if (m_Head)
|
||||||
|
{
|
||||||
|
free(m_Head);
|
||||||
|
m_Head = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void push_back(const T &obj)
|
||||||
|
{
|
||||||
|
ListNode *node = new ListNode(obj);
|
||||||
|
|
||||||
|
if (!m_Head->prev)
|
||||||
|
{
|
||||||
|
//link in the node as the first item
|
||||||
|
node->next = m_Head;
|
||||||
|
node->prev = m_Head;
|
||||||
|
m_Head->prev = node;
|
||||||
|
m_Head->next = node;
|
||||||
|
} else {
|
||||||
|
node->prev = m_Head->prev;
|
||||||
|
node->next = m_Head;
|
||||||
|
m_Head->prev->next = node;
|
||||||
|
m_Head->prev = node;
|
||||||
|
}
|
||||||
|
m_Size++;
|
||||||
|
}
|
||||||
|
size_t size()
|
||||||
|
{
|
||||||
|
return m_Size;
|
||||||
|
}
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
ListNode *node = m_Head->next;
|
||||||
|
ListNode *temp;
|
||||||
|
m_Head->next = NULL;
|
||||||
|
m_Head->prev = NULL;
|
||||||
|
while (node && node != m_Head)
|
||||||
|
{
|
||||||
|
temp = node->next;
|
||||||
|
delete node;
|
||||||
|
node = temp;
|
||||||
|
}
|
||||||
|
m_Size = 0;
|
||||||
|
}
|
||||||
|
bool empty()
|
||||||
|
{
|
||||||
|
return (m_Head->next == NULL);
|
||||||
|
}
|
||||||
|
T & back()
|
||||||
|
{
|
||||||
|
return m_Head->prev->obj;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
ListNode *m_Head;
|
||||||
|
size_t m_Size;
|
||||||
|
public:
|
||||||
|
class iterator
|
||||||
|
{
|
||||||
|
friend class List;
|
||||||
|
public:
|
||||||
|
iterator()
|
||||||
|
{
|
||||||
|
m_This = NULL;
|
||||||
|
}
|
||||||
|
iterator(const List &src)
|
||||||
|
{
|
||||||
|
m_This = src.m_Head;
|
||||||
|
}
|
||||||
|
iterator(ListNode *n) : m_This(n)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
iterator(const iterator &where)
|
||||||
|
{
|
||||||
|
m_This = where.m_This;
|
||||||
|
}
|
||||||
|
//pre decrement
|
||||||
|
iterator & operator--()
|
||||||
|
{
|
||||||
|
if (m_This)
|
||||||
|
m_This = m_This->prev;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
//post decrement
|
||||||
|
iterator operator--(int)
|
||||||
|
{
|
||||||
|
iterator old(*this);
|
||||||
|
if (m_This)
|
||||||
|
m_This = m_This->prev;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
//pre increment
|
||||||
|
iterator & operator++()
|
||||||
|
{
|
||||||
|
if (m_This)
|
||||||
|
m_This = m_This->next;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
//post increment
|
||||||
|
iterator operator++(int)
|
||||||
|
{
|
||||||
|
iterator old(*this);
|
||||||
|
if (m_This)
|
||||||
|
m_This = m_This->next;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T & operator * () const
|
||||||
|
{
|
||||||
|
return m_This->obj;
|
||||||
|
}
|
||||||
|
T & operator * ()
|
||||||
|
{
|
||||||
|
return m_This->obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
T * operator -> ()
|
||||||
|
{
|
||||||
|
return &(m_This->obj);
|
||||||
|
}
|
||||||
|
const T * operator -> () const
|
||||||
|
{
|
||||||
|
return &(m_This->obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator != (const iterator &where) const
|
||||||
|
{
|
||||||
|
return (m_This != where.m_This);
|
||||||
|
}
|
||||||
|
bool operator ==(const iterator &where) const
|
||||||
|
{
|
||||||
|
return (m_This == where.m_This);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
ListNode *m_This;
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
iterator begin() const
|
||||||
|
{
|
||||||
|
if (m_Size)
|
||||||
|
return iterator(m_Head->next);
|
||||||
|
else
|
||||||
|
return iterator(m_Head);
|
||||||
|
}
|
||||||
|
iterator end() const
|
||||||
|
{
|
||||||
|
return iterator(m_Head);
|
||||||
|
}
|
||||||
|
iterator erase(iterator &where)
|
||||||
|
{
|
||||||
|
ListNode *pNode = where.m_This;
|
||||||
|
iterator iter(where);
|
||||||
|
iter++;
|
||||||
|
|
||||||
|
//If we are both the head and tail...
|
||||||
|
if (m_Head->next == pNode && m_Head->prev == pNode)
|
||||||
|
{
|
||||||
|
m_Head->next = NULL;
|
||||||
|
m_Head->prev = NULL;
|
||||||
|
} else if (m_Head->next == pNode) {
|
||||||
|
//we are only the first
|
||||||
|
pNode->next->prev = m_Head;
|
||||||
|
m_Head->next = pNode->next;
|
||||||
|
} else if (m_Head->prev == pNode) {
|
||||||
|
//we are the tail
|
||||||
|
pNode->prev->next = m_Head;
|
||||||
|
m_Head->prev = pNode->prev;
|
||||||
|
} else {
|
||||||
|
//middle unlink
|
||||||
|
pNode->prev->next = pNode->next;
|
||||||
|
pNode->next->prev = pNode->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete pNode;
|
||||||
|
m_Size--;
|
||||||
|
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
void remove(const T & obj)
|
||||||
|
{
|
||||||
|
iterator b;
|
||||||
|
for (b=begin(); b!=end(); b++)
|
||||||
|
{
|
||||||
|
if ( (*b) == obj )
|
||||||
|
{
|
||||||
|
erase( b );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template <typename U>
|
||||||
|
iterator find(const U & equ)
|
||||||
|
{
|
||||||
|
iterator iter;
|
||||||
|
for (iter=begin(); iter!=end(); iter++)
|
||||||
|
{
|
||||||
|
if ( (*iter) == equ )
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
List & operator =(List &src)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
iterator iter;
|
||||||
|
for (iter=src.begin(); iter!=src.end(); iter++)
|
||||||
|
push_back( (*iter) );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//}; //NAMESPACE
|
||||||
|
|
||||||
|
#endif //_INCLUDE_CSDM_LIST_H
|
483
amxmodx/sh_tinyhash.h
Normal file
483
amxmodx/sh_tinyhash.h
Normal file
@ -0,0 +1,483 @@
|
|||||||
|
/* ======== SourceMM ========
|
||||||
|
* Copyright (C) 2004-2005 Metamod:Source Development Team
|
||||||
|
* No warranties of any kind
|
||||||
|
*
|
||||||
|
* License: zlib/libpng
|
||||||
|
*
|
||||||
|
* Author(s): David "BAILOPAN" Anderson
|
||||||
|
* ============================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE_SH_TINYHASH_H_
|
||||||
|
#define _INCLUDE_SH_TINYHASH_H_
|
||||||
|
|
||||||
|
#include "sh_list.h"
|
||||||
|
|
||||||
|
#define _T_INIT_HASH_SIZE 32
|
||||||
|
|
||||||
|
//namespace SourceHook
|
||||||
|
//{
|
||||||
|
template <class K>
|
||||||
|
int HashFunction(const K & k);
|
||||||
|
|
||||||
|
template <class K>
|
||||||
|
int Compare(const K & k1, const K & k2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a tiny, growable hash class.
|
||||||
|
* Meant for quick and dirty dictionaries only!
|
||||||
|
*/
|
||||||
|
template <class K, class V>
|
||||||
|
class THash
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct THashNode
|
||||||
|
{
|
||||||
|
THashNode(const K & k, const V & v) :
|
||||||
|
key(k), val(v)
|
||||||
|
{
|
||||||
|
};
|
||||||
|
~THashNode()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
K key;
|
||||||
|
V val;
|
||||||
|
};
|
||||||
|
typedef List<THashNode *> * NodePtr;
|
||||||
|
public:
|
||||||
|
THash() : m_Buckets(NULL), m_numBuckets(0), m_percentUsed(0.0f), m_NumItems(0)
|
||||||
|
{
|
||||||
|
_Refactor();
|
||||||
|
}
|
||||||
|
THash(const THash &other) : m_Buckets(new NodePtr[other.m_numBuckets]),
|
||||||
|
m_numBuckets(other.m_numBuckets), m_percentUsed(other.m_percentUsed)
|
||||||
|
{
|
||||||
|
for (size_t i=0; i<m_numBuckets; i++)
|
||||||
|
m_Buckets[i] = NULL;
|
||||||
|
for (const_iterator iter = other.begin(); iter != other.end(); ++iter)
|
||||||
|
_FindOrInsert(iter->key)->val = iter->val;
|
||||||
|
}
|
||||||
|
void operator=(const THash &other)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
for (const_iterator iter = other.begin(); iter != other.end(); ++iter)
|
||||||
|
_FindOrInsert(iter->key)->val = iter->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
~THash()
|
||||||
|
{
|
||||||
|
_Clear();
|
||||||
|
}
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
_Clear();
|
||||||
|
_Refactor();
|
||||||
|
}
|
||||||
|
size_t GetBuckets()
|
||||||
|
{
|
||||||
|
return m_numBuckets;
|
||||||
|
}
|
||||||
|
float PercentUsed()
|
||||||
|
{
|
||||||
|
return m_percentUsed;
|
||||||
|
}
|
||||||
|
size_t size()
|
||||||
|
{
|
||||||
|
return m_NumItems;
|
||||||
|
}
|
||||||
|
V & operator [](const K & key)
|
||||||
|
{
|
||||||
|
THashNode *pNode = _FindOrInsert(key);
|
||||||
|
return pNode->val;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
void _Clear()
|
||||||
|
{
|
||||||
|
List<THashNode *>::iterator iter, begin, end;
|
||||||
|
for (size_t i=0; i<m_numBuckets; i++)
|
||||||
|
{
|
||||||
|
if (m_Buckets[i])
|
||||||
|
{
|
||||||
|
begin = m_Buckets[i]->begin();
|
||||||
|
end = m_Buckets[i]->end();
|
||||||
|
for (iter=begin; iter!=end; iter++)
|
||||||
|
delete (*iter);
|
||||||
|
delete m_Buckets[i];
|
||||||
|
m_Buckets[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_Buckets)
|
||||||
|
delete [] m_Buckets;
|
||||||
|
m_Buckets = NULL;
|
||||||
|
m_numBuckets = 0;
|
||||||
|
m_NumItems = 0;
|
||||||
|
}
|
||||||
|
THashNode *_FindOrInsert(const K & key)
|
||||||
|
{
|
||||||
|
size_t place = HashFunction(key) % m_numBuckets;
|
||||||
|
THashNode *pNode = NULL;
|
||||||
|
if (!m_Buckets[place])
|
||||||
|
{
|
||||||
|
m_Buckets[place] = new List<THashNode *>;
|
||||||
|
pNode = new THashNode(key, V());
|
||||||
|
m_Buckets[place]->push_back(pNode);
|
||||||
|
m_percentUsed += (1.0f / (float)m_numBuckets);
|
||||||
|
m_NumItems++;
|
||||||
|
} else {
|
||||||
|
typename List<THashNode *>::iterator iter;
|
||||||
|
for (iter=m_Buckets[place]->begin(); iter!=m_Buckets[place]->end(); iter++)
|
||||||
|
{
|
||||||
|
if (Compare((*iter)->key, key) == 0)
|
||||||
|
return (*iter);
|
||||||
|
}
|
||||||
|
//node does not exist
|
||||||
|
pNode = new THashNode(key, V());
|
||||||
|
m_Buckets[place]->push_back(pNode);
|
||||||
|
m_NumItems++;
|
||||||
|
}
|
||||||
|
if (PercentUsed() > 0.75f)
|
||||||
|
_Refactor();
|
||||||
|
return pNode;
|
||||||
|
}
|
||||||
|
void _Refactor()
|
||||||
|
{
|
||||||
|
m_percentUsed = 0.0f;
|
||||||
|
if (!m_numBuckets)
|
||||||
|
{
|
||||||
|
m_numBuckets = _T_INIT_HASH_SIZE;
|
||||||
|
m_Buckets = new NodePtr[m_numBuckets];
|
||||||
|
for (size_t i=0; i<m_numBuckets; i++)
|
||||||
|
m_Buckets[i] = NULL;
|
||||||
|
} else {
|
||||||
|
size_t oldSize = m_numBuckets;
|
||||||
|
m_numBuckets *= 2;
|
||||||
|
typename List<THashNode *>::iterator iter;
|
||||||
|
size_t place;
|
||||||
|
THashNode *pHashNode;
|
||||||
|
NodePtr *temp = new NodePtr[m_numBuckets];
|
||||||
|
for (size_t i=0; i<m_numBuckets; i++)
|
||||||
|
temp[i] = NULL;
|
||||||
|
//look in old hash table
|
||||||
|
for (size_t i=0; i<oldSize; i++)
|
||||||
|
{
|
||||||
|
//does a bucket have anything?
|
||||||
|
if (m_Buckets[i])
|
||||||
|
{
|
||||||
|
//go through the list of items
|
||||||
|
for (iter = m_Buckets[i]->begin(); iter != m_Buckets[i]->end(); iter++)
|
||||||
|
{
|
||||||
|
pHashNode = (*iter);
|
||||||
|
//rehash it with the new bucket filter
|
||||||
|
place = HashFunction(pHashNode->key) % m_numBuckets;
|
||||||
|
//add it to the new hash table
|
||||||
|
if (!temp[place])
|
||||||
|
{
|
||||||
|
temp[place] = new List<THashNode *>;
|
||||||
|
m_percentUsed += (1.0f / (float)m_numBuckets);
|
||||||
|
}
|
||||||
|
temp[place]->push_back(pHashNode);
|
||||||
|
}
|
||||||
|
//delete that bucket!
|
||||||
|
delete m_Buckets[i];
|
||||||
|
m_Buckets[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//reassign bucket table
|
||||||
|
delete [] m_Buckets;
|
||||||
|
m_Buckets = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
friend class iterator;
|
||||||
|
friend class const_iterator;
|
||||||
|
class iterator
|
||||||
|
{
|
||||||
|
friend class THash;
|
||||||
|
public:
|
||||||
|
iterator() : curbucket(-1), hash(NULL), end(true)
|
||||||
|
{
|
||||||
|
};
|
||||||
|
iterator(THash *h) : curbucket(-1), hash(h), end(false)
|
||||||
|
{
|
||||||
|
if (!h->m_Buckets)
|
||||||
|
end = true;
|
||||||
|
else
|
||||||
|
_Inc();
|
||||||
|
};
|
||||||
|
//pre increment
|
||||||
|
iterator & operator++()
|
||||||
|
{
|
||||||
|
_Inc();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
//post increment
|
||||||
|
iterator operator++(int)
|
||||||
|
{
|
||||||
|
iterator old(*this);
|
||||||
|
_Inc();
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
const THashNode & operator * () const
|
||||||
|
{
|
||||||
|
return *(*iter);
|
||||||
|
}
|
||||||
|
THashNode & operator * ()
|
||||||
|
{
|
||||||
|
return *(*iter);
|
||||||
|
}
|
||||||
|
const THashNode * operator ->() const
|
||||||
|
{
|
||||||
|
return (*iter);
|
||||||
|
}
|
||||||
|
THashNode * operator ->()
|
||||||
|
{
|
||||||
|
return (*iter);
|
||||||
|
}
|
||||||
|
bool operator ==(const iterator &where) const
|
||||||
|
{
|
||||||
|
if (where.hash == this->hash
|
||||||
|
&& where.end == this->end
|
||||||
|
&&
|
||||||
|
(this->end ||
|
||||||
|
((where.curbucket == this->curbucket)
|
||||||
|
&& (where.iter == iter))
|
||||||
|
))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool operator !=(const iterator &where) const
|
||||||
|
{
|
||||||
|
return !( (*this) == where );
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase()
|
||||||
|
{
|
||||||
|
if (end || !hash || curbucket < 0 || curbucket >= static_cast<int>(hash->m_numBuckets))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Remove this element and move to the next one
|
||||||
|
iterator tmp = *this;
|
||||||
|
++tmp;
|
||||||
|
hash->m_Buckets[curbucket]->erase(iter);
|
||||||
|
*this = tmp;
|
||||||
|
m_NumItems--;
|
||||||
|
|
||||||
|
// :TODO: Maybe refactor to a lower size if required
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
void _Inc()
|
||||||
|
{
|
||||||
|
if (end || !hash || curbucket >= static_cast<int>(hash->m_numBuckets))
|
||||||
|
return;
|
||||||
|
if (curbucket < 0)
|
||||||
|
{
|
||||||
|
for (int i=0; i<(int)hash->m_numBuckets; i++)
|
||||||
|
{
|
||||||
|
if (hash->m_Buckets[i])
|
||||||
|
{
|
||||||
|
iter = hash->m_Buckets[i]->begin();
|
||||||
|
if (iter == hash->m_Buckets[i]->end())
|
||||||
|
continue;
|
||||||
|
curbucket = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (curbucket < 0)
|
||||||
|
end = true;
|
||||||
|
} else {
|
||||||
|
if (iter != hash->m_Buckets[curbucket]->end())
|
||||||
|
iter++;
|
||||||
|
if (iter == hash->m_Buckets[curbucket]->end())
|
||||||
|
{
|
||||||
|
int oldbucket = curbucket;
|
||||||
|
for (int i=curbucket+1; i<(int)hash->m_numBuckets; i++)
|
||||||
|
{
|
||||||
|
if (hash->m_Buckets[i])
|
||||||
|
{
|
||||||
|
iter = hash->m_Buckets[i]->begin();
|
||||||
|
if (iter == hash->m_Buckets[i]->end())
|
||||||
|
continue;
|
||||||
|
curbucket = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (curbucket == oldbucket)
|
||||||
|
end = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
int curbucket;
|
||||||
|
typename List<THashNode *>::iterator iter;
|
||||||
|
THash *hash;
|
||||||
|
bool end;
|
||||||
|
};
|
||||||
|
class const_iterator
|
||||||
|
{
|
||||||
|
friend class THash;
|
||||||
|
public:
|
||||||
|
const_iterator() : curbucket(-1), hash(NULL), end(true)
|
||||||
|
{
|
||||||
|
};
|
||||||
|
const_iterator(const THash *h) : curbucket(-1), hash(h), end(false)
|
||||||
|
{
|
||||||
|
if (!h->m_Buckets)
|
||||||
|
end = true;
|
||||||
|
else
|
||||||
|
_Inc();
|
||||||
|
};
|
||||||
|
//pre increment
|
||||||
|
const_iterator & operator++()
|
||||||
|
{
|
||||||
|
_Inc();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
//post increment
|
||||||
|
const_iterator operator++(int)
|
||||||
|
{
|
||||||
|
iterator old(*this);
|
||||||
|
_Inc();
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
const THashNode & operator * () const
|
||||||
|
{
|
||||||
|
return *(*iter);
|
||||||
|
}
|
||||||
|
const THashNode * operator ->() const
|
||||||
|
{
|
||||||
|
return (*iter);
|
||||||
|
}
|
||||||
|
bool operator ==(const const_iterator &where) const
|
||||||
|
{
|
||||||
|
if (where.hash == this->hash
|
||||||
|
&& where.end == this->end
|
||||||
|
&&
|
||||||
|
(this->end ||
|
||||||
|
((where.curbucket == this->curbucket)
|
||||||
|
&& (where.iter == iter))
|
||||||
|
))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool operator !=(const const_iterator &where) const
|
||||||
|
{
|
||||||
|
return !( (*this) == where );
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
void _Inc()
|
||||||
|
{
|
||||||
|
if (end || !hash || curbucket >= static_cast<int>(hash->m_numBuckets))
|
||||||
|
return;
|
||||||
|
if (curbucket < 0)
|
||||||
|
{
|
||||||
|
for (int i=0; i<(int)hash->m_numBuckets; i++)
|
||||||
|
{
|
||||||
|
if (hash->m_Buckets[i])
|
||||||
|
{
|
||||||
|
iter = hash->m_Buckets[i]->begin();
|
||||||
|
if (iter == hash->m_Buckets[i]->end())
|
||||||
|
continue;
|
||||||
|
curbucket = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (curbucket < 0)
|
||||||
|
end = true;
|
||||||
|
} else {
|
||||||
|
if (iter != hash->m_Buckets[curbucket]->end())
|
||||||
|
iter++;
|
||||||
|
if (iter == hash->m_Buckets[curbucket]->end())
|
||||||
|
{
|
||||||
|
int oldbucket = curbucket;
|
||||||
|
for (int i=curbucket+1; i<(int)hash->m_numBuckets; i++)
|
||||||
|
{
|
||||||
|
if (hash->m_Buckets[i])
|
||||||
|
{
|
||||||
|
iter = hash->m_Buckets[i]->begin();
|
||||||
|
if (iter == hash->m_Buckets[i]->end())
|
||||||
|
continue;
|
||||||
|
curbucket = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (curbucket == oldbucket)
|
||||||
|
end = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
int curbucket;
|
||||||
|
typename List<THashNode *>::iterator iter;
|
||||||
|
const THash *hash;
|
||||||
|
bool end;
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
return iterator(this);
|
||||||
|
}
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
iterator iter;
|
||||||
|
iter.hash = this;
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const
|
||||||
|
{
|
||||||
|
return const_iterator(this);
|
||||||
|
}
|
||||||
|
const_iterator end() const
|
||||||
|
{
|
||||||
|
const_iterator iter;
|
||||||
|
iter.hash = this;
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
iterator find(const U & u) const
|
||||||
|
{
|
||||||
|
iterator b = begin();
|
||||||
|
iterator e = end();
|
||||||
|
for (iterator iter = b; iter != e; iter++)
|
||||||
|
{
|
||||||
|
if ( (*iter).key == u )
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
template <typename U>
|
||||||
|
iterator find(const U & u)
|
||||||
|
{
|
||||||
|
iterator b = begin();
|
||||||
|
iterator e = end();
|
||||||
|
for (iterator iter = b; iter != e; iter++)
|
||||||
|
{
|
||||||
|
if ( (*iter).key == u )
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator erase(iterator where)
|
||||||
|
{
|
||||||
|
where.erase();
|
||||||
|
return where;
|
||||||
|
}
|
||||||
|
template <typename U>
|
||||||
|
void erase(const U & u)
|
||||||
|
{
|
||||||
|
iterator iter = find(u);
|
||||||
|
if (iter == end())
|
||||||
|
return;
|
||||||
|
iter.erase();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
NodePtr *m_Buckets;
|
||||||
|
size_t m_numBuckets;
|
||||||
|
float m_percentUsed;
|
||||||
|
size_t m_NumItems;
|
||||||
|
};
|
||||||
|
//};
|
||||||
|
|
||||||
|
#endif //_INCLUDE_SH_TINYHASH_H_
|
Loading…
Reference in New Issue
Block a user