mirror of
https://github.com/alliedmodders/amxmodx.git
synced 2024-12-25 06:15:37 +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_NEWLINE 4
|
||||
|
||||
// dictionary format is Fast-Format-Hash-Lookup, v4
|
||||
// dictionary format is Fast-Format-Hash-Lookup, v5
|
||||
#define MAGIC_HDR 0x4646484C
|
||||
#define FFHL_VERSION 4
|
||||
#define FFHL_VERSION 5
|
||||
#define FFHL_MIN_VERSION 4
|
||||
|
||||
/*version history:
|
||||
@ -56,6 +56,7 @@
|
||||
* 2 (BAILOPAN) - One language 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)
|
||||
* 5 (BAILOPAN) - Removed hash storage
|
||||
FORMAT:
|
||||
Magic 4bytes
|
||||
Version 1byte
|
||||
@ -65,13 +66,11 @@ LANG INFO TABLE[]
|
||||
Language Name 2bytes
|
||||
Offset 4bytes
|
||||
KEY TABLE[]
|
||||
Key Hash 4bytes
|
||||
Key Lookup Offset 4bytes
|
||||
LANGUAGES TABLE[]
|
||||
Language[]
|
||||
Definitions 4bytes
|
||||
Key Hash # 4bytes (virtual # in hash table, 0 indexed)
|
||||
Def Hash 4bytes
|
||||
Key # 4bytes (0-index into key table)
|
||||
Def Offset 4bytes
|
||||
KEY LOOKUP TABLE[]
|
||||
Key length 1byte
|
||||
@ -81,70 +80,32 @@ DEF LOOKUP TABLE[]
|
||||
Def string variable
|
||||
*/
|
||||
|
||||
/******** CRC & Strip *********/
|
||||
const uint32_t CRCTable[256] = {
|
||||
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)
|
||||
template<>
|
||||
int Compare<String>(const String &k1, const String &k2)
|
||||
{
|
||||
uint32_t crc = 0xFFFFFFFF;
|
||||
|
||||
while (*src)
|
||||
crc = ((crc>>8)&0xFFFFFFFF)^CRCTable[(crc^ (makeLower ? tolower(*src++) : *src++) )&0xFF];
|
||||
|
||||
return ~crc;
|
||||
return k1.compare(k2.c_str());
|
||||
}
|
||||
|
||||
uint32_t CLangMngr::MakeHash(const char *src, bool makeLower)
|
||||
template<>
|
||||
int HashFunction<String>(const String &k)
|
||||
{
|
||||
uint32_t crc = 0xFFFFFFFF;
|
||||
|
||||
while (*src)
|
||||
crc = ((crc>>8)&0xFFFFFFFF)^CRCTable[(crc^ (makeLower ? tolower(*src++) : *src++) )&0xFF];
|
||||
|
||||
return ~crc;
|
||||
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;
|
||||
}
|
||||
|
||||
template<>
|
||||
int HashFunction<int>(const int &k)
|
||||
{
|
||||
return k;
|
||||
}
|
||||
|
||||
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
|
||||
@ -188,86 +149,6 @@ size_t CLangMngr::strip(char *str, char *newstr, bool makelower)
|
||||
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 *********/
|
||||
|
||||
@ -283,15 +164,14 @@ CLangMngr::CLang::CLang(const char *lang)
|
||||
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];
|
||||
|
||||
if (d.definition)
|
||||
delete d.definition;
|
||||
|
||||
p->SetCache(cache);
|
||||
|
||||
m_LookUpTable.push_back(p);
|
||||
|
||||
return p;
|
||||
d.definition = new String(definition);
|
||||
}
|
||||
|
||||
CLangMngr::CLang::~CLang()
|
||||
@ -301,99 +181,66 @@ CLangMngr::CLang::~CLang()
|
||||
|
||||
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])
|
||||
delete m_LookUpTable[i];
|
||||
if (iter->val.definition)
|
||||
{
|
||||
delete iter->val.definition;
|
||||
iter->val.definition = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
m_LookUpTable.clear();
|
||||
}
|
||||
|
||||
CLangMngr::CLang::LangEntry * CLangMngr::CLang::GetEntry(int pkey)
|
||||
void CLangMngr::CLang::MergeDefinitions(CQueue<sKeyDef> &vec)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
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;
|
||||
String *pDef;
|
||||
int key = -1;
|
||||
|
||||
while (!vec.empty())
|
||||
{
|
||||
key = vec.front()->key;
|
||||
def = vec.front()->def->c_str();
|
||||
LangEntry *entry = GetEntry(key);
|
||||
key = vec.front().key;
|
||||
pDef = vec.front().definition;
|
||||
|
||||
AddEntry(key, pDef->c_str());
|
||||
|
||||
delete vec.front().definition;
|
||||
|
||||
if (entry->GetDefHash() != MakeHash(def))
|
||||
{
|
||||
if (entry->GetCache())
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (ikey == -1)
|
||||
defentry &def = m_LookUpTable[key];
|
||||
|
||||
if (!def.definition)
|
||||
{
|
||||
status = LANG_STATUS_KLNOTFOUND;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < m_LookUpTable.size(); i++)
|
||||
{
|
||||
if (m_LookUpTable[i]->GetKey() == ikey)
|
||||
return m_LookUpTable[i]->GetDef();
|
||||
}
|
||||
|
||||
status = LANG_STATUS_KLNOTFOUND;
|
||||
return NULL;
|
||||
return def.definition->c_str();
|
||||
}
|
||||
|
||||
struct OffsetPair
|
||||
{
|
||||
uint32_t defOffset;
|
||||
uint32_t keyOffset;
|
||||
};
|
||||
|
||||
// Assumes fp is set to the right position
|
||||
bool CLangMngr::CLang::SaveDefinitions(FILE *fp, uint32_t &curOffset)
|
||||
{
|
||||
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);
|
||||
curOffset += sizeof(unsigned short);
|
||||
fwrite(m_LookUpTable[i]->GetDef(), sizeof(char), defLen, fp);
|
||||
fwrite(pdef->c_str(), sizeof(char), defLen, fp);
|
||||
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)
|
||||
{
|
||||
uint32_t keynum = 0;
|
||||
uint32_t defhash = 0;
|
||||
uint32_t size = m_LookUpTable.size();
|
||||
String *pdef;
|
||||
String blank;
|
||||
|
||||
fwrite((void*)&size, sizeof(uint32_t), 1, fp);
|
||||
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();
|
||||
defhash = m_LookUpTable[i]->GetDefHash();
|
||||
keynum = iter->key;
|
||||
pdef = iter->val.definition;
|
||||
if (!pdef)
|
||||
pdef = ␣
|
||||
fwrite((void *)&keynum, sizeof(uint32_t), 1, fp);
|
||||
curOffset += sizeof(uint32_t);
|
||||
fwrite((void *)&defhash, sizeof(uint32_t), 1, fp);
|
||||
curOffset += sizeof(uint32_t);
|
||||
fwrite((void *)&defOffset, sizeof(uint32_t), 1, fp);
|
||||
curOffset += sizeof(uint32_t);
|
||||
defOffset += sizeof(short);
|
||||
defOffset += m_LookUpTable[i]->GetDefLength();
|
||||
defOffset += pdef->size();
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -443,69 +292,36 @@ CLangMngr::CLangMngr()
|
||||
const char * CLangMngr::GetKey(int key)
|
||||
{
|
||||
if (key < 0 || key >= (int)KeyList.size())
|
||||
return 0;
|
||||
return NULL;
|
||||
|
||||
return KeyList[key]->key.c_str();
|
||||
}
|
||||
|
||||
int CLangMngr::GetKeyHash(int key)
|
||||
{
|
||||
if (key < 0 || key >= (int)KeyList.size())
|
||||
return 0;
|
||||
|
||||
return KeyList[key]->hash;
|
||||
return KeyList[key]->c_str();
|
||||
}
|
||||
|
||||
int CLangMngr::GetKeyEntry(const char *key)
|
||||
{
|
||||
uint32_t hKey = MakeHash(key, true);
|
||||
uint32_t cmpKey = 0;
|
||||
unsigned int i = 0;
|
||||
keytbl_val val = KeyTable[key];
|
||||
|
||||
if (hKey == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < KeyList.size(); i++)
|
||||
{
|
||||
cmpKey = KeyList[i]->hash;
|
||||
|
||||
if (hKey == cmpKey)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
return val.index;
|
||||
}
|
||||
|
||||
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;
|
||||
e->key.assign(key);
|
||||
e->hash = hKey;
|
||||
KeyList.push_back(e);
|
||||
String *pString = new String(key);
|
||||
KeyList.push_back(pString);
|
||||
|
||||
return (KeyList.size() - 1);
|
||||
KeyTable[key] = val;
|
||||
|
||||
return val.index;
|
||||
}
|
||||
|
||||
int CLangMngr::GetKeyEntry(String &key)
|
||||
{
|
||||
uint32_t hKey = MakeHash(key.c_str(), true);
|
||||
unsigned int i = 0;
|
||||
keytbl_val val = KeyTable[key];
|
||||
|
||||
for (i = 0; i < KeyList.size(); i++)
|
||||
{
|
||||
if (hKey == KeyList[i]->hash)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
return val.index;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
void CLangMngr::MergeDefinitions(const char *lang, CQueue<sKeyDef*> &tmpVec)
|
||||
void CLangMngr::MergeDefinitions(const char *lang, CQueue<sKeyDef> &tmpVec)
|
||||
{
|
||||
CLang * language = GetLang(lang);
|
||||
if (language)
|
||||
@ -1062,10 +878,10 @@ int CLangMngr::MergeDefinitionFile(const char *file)
|
||||
// Allocate enough memory to store everything
|
||||
bool multiline = 0;
|
||||
int pos = 0, line = 0;
|
||||
CQueue<sKeyDef*> Defq;
|
||||
CQueue<sKeyDef> Defq;
|
||||
String buf;
|
||||
char language[3];
|
||||
sKeyDef *tmpEntry = NULL;
|
||||
sKeyDef tmpEntry;
|
||||
|
||||
while (!feof(fp))
|
||||
{
|
||||
@ -1082,9 +898,8 @@ int CLangMngr::MergeDefinitionFile(const char *file)
|
||||
if (multiline)
|
||||
{
|
||||
AMXXLOG_Log("New section, multiline unterminated (file \"%s\" line %d)", file, line);
|
||||
if (tmpEntry)
|
||||
delete tmpEntry;
|
||||
tmpEntry = 0;
|
||||
tmpEntry.key = -1;
|
||||
tmpEntry.definition = NULL;
|
||||
}
|
||||
|
||||
if (!Defq.empty())
|
||||
@ -1102,7 +917,6 @@ int CLangMngr::MergeDefinitionFile(const char *file)
|
||||
|
||||
if (pos > String::npos)
|
||||
{
|
||||
tmpEntry = new sKeyDef;
|
||||
String key;
|
||||
key.assign(buf.substr(0, pos).c_str());
|
||||
String def;
|
||||
@ -1112,18 +926,18 @@ int CLangMngr::MergeDefinitionFile(const char *file)
|
||||
int iKey = GetKeyEntry(key);
|
||||
if (iKey == -1)
|
||||
iKey = AddKeyEntry(key);
|
||||
tmpEntry->key = iKey;
|
||||
tmpEntry->def = new String;
|
||||
tmpEntry->def->assign(def.c_str());
|
||||
tmpEntry->def->trim();
|
||||
tmpEntry.key = iKey;
|
||||
tmpEntry.definition = new String;
|
||||
tmpEntry.definition->assign(def.c_str());
|
||||
tmpEntry.definition->trim();
|
||||
Defq.push(tmpEntry);
|
||||
tmpEntry = 0;
|
||||
tmpEntry.key = -1;
|
||||
tmpEntry.definition = NULL;
|
||||
} else {
|
||||
pos = buf.find(':');
|
||||
|
||||
if (pos > String::npos)
|
||||
{
|
||||
tmpEntry = new sKeyDef;
|
||||
String key;
|
||||
key.assign(buf.substr(0, pos).c_str());;
|
||||
key.trim();
|
||||
@ -1131,8 +945,8 @@ int CLangMngr::MergeDefinitionFile(const char *file)
|
||||
int iKey = GetKeyEntry(key);
|
||||
if (iKey == -1)
|
||||
iKey = AddKeyEntry(key);
|
||||
tmpEntry->key = iKey;
|
||||
tmpEntry->def = new String;
|
||||
tmpEntry.key = iKey;
|
||||
tmpEntry.definition = new String;
|
||||
multiline = true;
|
||||
} else {
|
||||
//user typed a line with no directives
|
||||
@ -1143,10 +957,13 @@ int CLangMngr::MergeDefinitionFile(const char *file)
|
||||
if (buf[0] == ':')
|
||||
{
|
||||
Defq.push(tmpEntry);
|
||||
tmpEntry = 0;
|
||||
tmpEntry.key = -1;
|
||||
tmpEntry.definition = NULL;
|
||||
multiline = false;
|
||||
} else {
|
||||
tmpEntry->def->append(buf);
|
||||
if (!tmpEntry.definition)
|
||||
tmpEntry.definition = new String();
|
||||
tmpEntry.definition->append(buf);
|
||||
}
|
||||
} // if !multiline
|
||||
} //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)
|
||||
{
|
||||
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;
|
||||
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)
|
||||
{
|
||||
FILE *fp = fopen(filename, "wb");
|
||||
@ -1217,7 +1048,7 @@ bool CLangMngr::Save(const char *filename)
|
||||
const char *langName = 0;
|
||||
uint32_t curOffset = 0;
|
||||
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));
|
||||
|
||||
fwrite((void *)&magic, sizeof(uint32_t), 1, fp);
|
||||
@ -1237,7 +1068,7 @@ bool CLangMngr::Save(const char *filename)
|
||||
fwrite(langName, sizeof(char), 2, fp);
|
||||
curOffset += sizeof(char) * 2;
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1246,13 +1077,10 @@ bool CLangMngr::Save(const char *filename)
|
||||
uint32_t keyOffset = langOffset;
|
||||
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);
|
||||
curOffset += sizeof(uint32_t);
|
||||
keyOffset += sizeof(char);
|
||||
keyOffset += KeyList[i]->key.size();
|
||||
keyOffset += KeyList[i]->size();
|
||||
}
|
||||
|
||||
//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;
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1314,6 +1142,19 @@ bool CLangMngr::SaveCache(const char *filename)
|
||||
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)
|
||||
{
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
@ -1326,15 +1167,15 @@ bool CLangMngr::LoadCache(const char *filename)
|
||||
char len = 0;
|
||||
char buf[255];
|
||||
char md5[34];
|
||||
fread((void*)&dictCount, sizeof(short), 1, fp);
|
||||
CACHEREAD(fread((void*)&dictCount, sizeof(short), 1, fp), short);
|
||||
md5Pair *p = 0;
|
||||
|
||||
for (int i = 1; i <= dictCount; i++)
|
||||
{
|
||||
fread((void*)&len, sizeof(char), 1, fp);
|
||||
fread(buf, sizeof(char), len, fp);
|
||||
CACHEREAD(fread((void*)&len, sizeof(char), 1, fp), char);
|
||||
CACHEREAD_S(fread(buf, sizeof(char), len, fp), len);
|
||||
buf[len] = 0;
|
||||
fread(md5, sizeof(char), 32, fp);
|
||||
CACHEREAD_S(fread(md5, sizeof(char), 32, fp), 32);
|
||||
md5[32] = 0;
|
||||
p = new md5Pair;
|
||||
p->file.assign(buf);
|
||||
@ -1348,6 +1189,19 @@ bool CLangMngr::LoadCache(const char *filename)
|
||||
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)
|
||||
{
|
||||
Clear();
|
||||
@ -1362,75 +1216,93 @@ bool CLangMngr::Load(const char *filename)
|
||||
uint32_t keycount = 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)
|
||||
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)
|
||||
return false;
|
||||
|
||||
fread((void*)&keycount, sizeof(uint32_t), 1, fp);
|
||||
fread((void*)&langCount, sizeof(uint32_t), 1, fp);
|
||||
DATREAD(fread((void*)&keycount, sizeof(uint32_t), 1, fp), uint32_t);
|
||||
DATREAD(fread((void*)&langCount, sizeof(uint32_t), 1, fp), uint32_t);
|
||||
|
||||
uint32_t *LangOffsets = new uint32_t[langCount];
|
||||
char langname[3];
|
||||
|
||||
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;
|
||||
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
|
||||
int ktbOffset = ftell(fp);
|
||||
keyEntry *e = 0;
|
||||
unsigned char keylen;
|
||||
char keybuf[255];
|
||||
uint32_t bogus;
|
||||
uint32_t keyoffset, save;
|
||||
String _tmpkey;
|
||||
|
||||
for (unsigned i = 0; i < keycount; i++)
|
||||
{
|
||||
e = new keyEntry;
|
||||
fread((void*)&(e->hash), sizeof(uint32_t), 1, fp);
|
||||
fread((void*)&keyoffset, sizeof(uint32_t), 1, fp);
|
||||
if (version == 4)
|
||||
fread((void*)&(bogus), 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);
|
||||
fseek(fp, keyoffset, SEEK_SET);
|
||||
fread((void*)&keylen, sizeof(char), 1, fp);
|
||||
char *data = new char[keylen + 1];
|
||||
fread(data, sizeof(char), keylen, fp);
|
||||
data[keylen] = 0;
|
||||
e->key.assign(data);
|
||||
delete [] data;
|
||||
KeyList.push_back(e);
|
||||
DATREAD(fread((void*)&keylen, sizeof(char), 1, fp), char);
|
||||
DATREAD_S(fread(keybuf, sizeof(char), keylen, fp), keylen);
|
||||
keybuf[keylen] = 0;
|
||||
_tmpkey.assign(keybuf);
|
||||
AddKeyEntry(_tmpkey);
|
||||
fseek(fp, save, SEEK_SET); //bring back to next key
|
||||
}
|
||||
|
||||
//we should now be at the languages table
|
||||
uint32_t numentries;
|
||||
uint32_t keynum;
|
||||
uint32_t defhash;
|
||||
uint32_t defoffset;
|
||||
unsigned short deflen;
|
||||
char valbuf[4096];
|
||||
|
||||
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++)
|
||||
{
|
||||
fread((void *)&keynum, sizeof(uint32_t), 1, fp);
|
||||
fread((void *)&defhash, sizeof(uint32_t), 1, fp);
|
||||
fread((void *)&defoffset, sizeof(uint32_t), 1, fp);
|
||||
DATREAD(fread((void *)&keynum, sizeof(uint32_t), 1, fp), uint32_t);
|
||||
if (version == 4)
|
||||
{
|
||||
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);
|
||||
fseek(fp, defoffset, SEEK_SET);
|
||||
fread((void *)&deflen, sizeof(unsigned short), 1, fp);
|
||||
char *data = new char[deflen + 1];
|
||||
fread(data, sizeof(char), deflen, fp);
|
||||
data[deflen] = 0;
|
||||
m_Languages[i]->AddEntry(keynum, defhash, data, true);
|
||||
delete [] data;
|
||||
DATREAD(fread((void *)&deflen, sizeof(unsigned short), 1, fp), short);
|
||||
//:TODO: possible string overflow here.
|
||||
DATREAD_S(fread(valbuf, sizeof(char), deflen, fp), deflen);
|
||||
valbuf[deflen] = 0;
|
||||
m_Languages[i]->AddEntry(keynum, valbuf);
|
||||
fseek(fp, save, SEEK_SET); //bring back to next entry
|
||||
}
|
||||
}
|
||||
@ -1451,6 +1323,8 @@ CLangMngr::~CLangMngr()
|
||||
void CLangMngr::Clear()
|
||||
{
|
||||
unsigned int i = 0;
|
||||
|
||||
KeyTable.clear();
|
||||
|
||||
for (i = 0; i < m_Languages.size(); i++)
|
||||
{
|
||||
|
@ -32,6 +32,8 @@
|
||||
#ifndef _INCLUDE_CLANG_H
|
||||
#define _INCLUDE_CLANG_H
|
||||
|
||||
#include "sh_tinyhash.h"
|
||||
|
||||
#define LANG_SERVER 0
|
||||
#define LANG_PLAYER -1
|
||||
|
||||
@ -45,19 +47,35 @@ struct md5Pair
|
||||
String val;
|
||||
};
|
||||
|
||||
struct keyEntry
|
||||
{
|
||||
String key;
|
||||
uint32_t hash;
|
||||
};
|
||||
|
||||
struct sKeyDef
|
||||
{
|
||||
sKeyDef() { key = -1; def = 0; }
|
||||
~sKeyDef() { if (def) delete def; }
|
||||
|
||||
String *definition;
|
||||
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
|
||||
@ -73,9 +91,9 @@ class CLangMngr
|
||||
~CLang();
|
||||
|
||||
// Get the definition
|
||||
const char *GetDef(const char *key, int &status);
|
||||
const char *GetDef(int key, int &status);
|
||||
// Add definitions to this language
|
||||
void MergeDefinitions(CQueue <sKeyDef*> & vec);
|
||||
void MergeDefinitions(CQueue <sKeyDef> & vec);
|
||||
// Reset this language
|
||||
void Clear();
|
||||
|
||||
@ -95,49 +113,9 @@ class CLangMngr
|
||||
void SetMngr(CLangMngr *l) { m_LMan = l; }
|
||||
// Get number of entries
|
||||
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:
|
||||
// An entry in the language
|
||||
class LangEntry
|
||||
{
|
||||
// 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;
|
||||
typedef THash<int, defentry> LookUpVec;
|
||||
typedef LookUpVec::iterator LookUpVecIter;
|
||||
|
||||
char m_LanguageName[3];
|
||||
|
||||
@ -145,11 +123,11 @@ class CLangMngr
|
||||
LookUpVec m_LookUpTable;
|
||||
CLangMngr *m_LMan;
|
||||
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
|
||||
void MergeDefinitions(const char *lang, CQueue <sKeyDef*> &tmpVec);
|
||||
void MergeDefinitions(const char *lang, CQueue <sKeyDef> &tmpVec);
|
||||
// strip lowercase; make lower if needed
|
||||
static size_t strip(char *str, char *newstr, bool makelower = false);
|
||||
|
||||
@ -159,7 +137,8 @@ class CLangMngr
|
||||
LangVec m_Languages;
|
||||
|
||||
CVector<md5Pair *> FileList;
|
||||
CVector<keyEntry*> KeyList;
|
||||
CVector<String *> KeyList;
|
||||
THash<String, keytbl_val> KeyTable;
|
||||
|
||||
// Get a lang object (construct if needed)
|
||||
CLang * GetLang(const char *name);
|
||||
@ -185,16 +164,15 @@ public:
|
||||
// Cache
|
||||
bool LoadCache(const char *filename);
|
||||
bool SaveCache(const char *filename);
|
||||
void InvalidateCache();
|
||||
// Get index
|
||||
int GetKeyEntry(String &key);
|
||||
int GetKeyEntry(const char *key);
|
||||
int GetKeyHash(int key);
|
||||
int GetKeyIndex(const char *key);
|
||||
// Get key from index
|
||||
const char *GetKey(int key);
|
||||
// Add 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
|
||||
int GetLangsNum();
|
||||
|
@ -118,7 +118,7 @@ public:
|
||||
v[0] = '\0';
|
||||
}
|
||||
|
||||
int compare (const char *d)
|
||||
int compare (const char *d) const
|
||||
{
|
||||
if (!v)
|
||||
return strcmp("", d);
|
||||
|
@ -249,7 +249,10 @@ int C_Spawn(edict_t *pent)
|
||||
// ###### Load lang
|
||||
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.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
|
||||
g_commands.registerPrefix("amx");
|
||||
|
@ -257,7 +257,7 @@
|
||||
LinkIncremental="1"
|
||||
SuppressStartupBanner="TRUE"
|
||||
AdditionalLibraryDirectories="..\extra\lib_win32"
|
||||
IgnoreDefaultLibraryNames="LIBC"
|
||||
IgnoreDefaultLibraryNames="MSVCRT"
|
||||
ModuleDefinitionFile=""
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile=".\memtestrelease/amxx_mm.pdb"
|
||||
@ -822,9 +822,15 @@
|
||||
<File
|
||||
RelativePath="..\resource.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sh_list.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sh_stack.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\sh_tinyhash.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\zlib\zconf.h">
|
||||
</File>
|
||||
|
@ -32,7 +32,9 @@
|
||||
#define _INCLUDE_NATIVES_H
|
||||
|
||||
//only 16 for now sorry
|
||||
#if !defined CALLFUNC_MAXPARAMS
|
||||
#define CALLFUNC_MAXPARAMS 16
|
||||
#endif
|
||||
|
||||
#define CALLFUNC_FLAG_BYREF 1
|
||||
#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