diff --git a/amxmodx/CLang.cpp b/amxmodx/CLang.cpp new file mode 100755 index 00000000..3d569fc3 --- /dev/null +++ b/amxmodx/CLang.cpp @@ -0,0 +1,845 @@ +/* AMX Mod X +* +* by the AMX Mod X Development Team +* originally developed by OLO +* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +*/ + +#include "amxmodx.h" +#include "CLang.h" + + +#define LITIDX_NONE 0 +#define LITIDX_BRACKET 1 +#define LITIDX_DEFINITION 2 + +#define INSERT_NUMBER 1 +#define INSERT_FLOAT 2 +#define INSERT_STRING 3 +#define INSERT_NEWLINE 4 + +// dictionary format is Fast-Format-Hash-Lookup, v3 +#define MAGIC_HDR 0x4646484C + +/* + FORMAT: + Magic (4 bytes) + Number of languages (4 bytes) + LANGUAGE INFO TABLE + For every language: + Language Name (2 bytes) + Absolut offset (4 bytes) + LANGUAGES + For every language: + Number of entries (4 bytes) + + Offset to Definition Table (4 bytes) + Length of Definition Table (4 bytes) + + Offset to Reverse Lookup Table (4 bytes) + Size of Reverse Lookup Table (4 bytes) + + + LOOK UP TABLE + For every entry: + Key hash (4 bytes) + Definition hash (4 bytes) + Definition offset (4 bytes) (into the Def table) + Key offset (4 bytes) (into the Rev table) + DEFINITION TABLE + For every entry: + Definition length (2 bytes) + Definition (variable size) + REVERSE LOOKUP TABLE + For every entry: + Key length (1 byte) + Key (variable size) +*/ + +/******** 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) +{ + uint32_t crc = 0xFFFFFFFF; + + while (*src) + crc = ((crc>>8)&0xFFFFFFFF)^CRCTable[(crc^*src++)&0xFF]; + + return ~crc; +} + + +// strip the whitespaces at the beginning and the end of a string +// also convert to lowercase if needed +// return the number of written characters (including the terimating zero char) +size_t CLangMngr::strip(char *str, char *newstr, bool makelower) +{ + size_t i = 0; + size_t pos = 0; + int flag = 0; + size_t strln = strlen(str); + + for (i=strln-1; i>=0; i--) + { + if (str[i] == '\n' || str[i] == ' ' || str[i] == '\t') + { + str[i] = 0; + } else { + break; + } + } + + char *ptr = str; + while (*ptr) + { + if (!flag) + { + if (*ptr != '\n' && *ptr != ' ' && *ptr != '\t') + { + flag = 1; + newstr[pos++] = makelower ? tolower(*ptr) : *ptr; + } + } else { + newstr[pos++] = makelower ? tolower(*ptr) : *ptr; + } + ++ptr; + } + + newstr[pos] = 0; + return ptr - str + 1; +} + +/******** CLangMngr::CLang::LangEntry *********/ +uint32_t CLangMngr::CLang::LangEntry::GetDefHash() +{ + return m_DefHash; +} + +uint32_t CLangMngr::CLang::LangEntry::GetKeyHash() +{ + return m_KeyHash; +} + +const char *CLangMngr::CLang::LangEntry::GetKey() +{ + return m_pKey; +} + +const char *CLangMngr::CLang::LangEntry::GetDef() +{ + return m_pDef; +} + + +CLangMngr::CLang::LangEntry::LangEntry() +{ + Clear(); +} + +CLangMngr::CLang::LangEntry::LangEntry(const char *pKey) +{ + Clear(); + SetKey(pKey); +} + +CLangMngr::CLang::LangEntry::LangEntry(const char *pKey, const char *pDef) +{ + Clear(); + SetKey(pKey); + SetDef(pDef); +} + +CLangMngr::CLang::LangEntry::LangEntry(const LangEntry &other) +{ + Clear(); + SetKey(other.m_pKey); + SetDef(other.m_pDef); +} + + +void CLangMngr::CLang::LangEntry::operator= (const char *pNewDef) +{ + SetDef(pNewDef); +} + +bool CLangMngr::CLang::LangEntry::operator== (uint32_t hash) +{ + return m_KeyHash == hash; +} + +void CLangMngr::CLang::LangEntry::Clear() +{ + m_pKey = NULL; + m_pDef = NULL; + m_KeyHash = 0; + m_DefHash = 0; +} + +void CLangMngr::CLang::LangEntry::SetKey(const char *pKey) +{ + delete [] m_pKey; + m_pKey = new char[strlen(pKey)+1]; + strcpy(m_pKey, pKey); + m_KeyHash = MakeHash(pKey); +} + +void CLangMngr::CLang::LangEntry::SetDef(const char *pDef) +{ + delete [] m_pDef; + m_pDef = new char[strlen(pDef)+1]; + strcpy(m_pDef, pDef); + m_DefHash = MakeHash(pDef); +} + +/******** CLangMngr::CLang *********/ + +CLangMngr::CLang::CLang() +{ + m_LookUpTable.clear(); +} + +CLangMngr::CLang::CLang(const char *lang) +{ + m_LookUpTable.clear(); + strncpy(m_LanguageName, lang, 2); + m_LanguageName[2]=0; +} + +CLangMngr::CLang::~CLang() +{ + Clear(); +} + +void CLangMngr::CLang::Clear() +{ + m_LookUpTable.clear(); +} + +CLangMngr::CLang::LangEntry & CLangMngr::CLang::GetEntry(const char *key) +{ + LookUpVecIter iter; + uint32_t hash = MakeHash(key); + for (iter = m_LookUpTable.begin(); iter != m_LookUpTable.end(); ++iter) + if (*iter == hash) + break; + if (iter != m_LookUpTable.end()) + return *iter; + + m_LookUpTable.push_back(LangEntry(key)); + return m_LookUpTable.back(); +} + +void CLangMngr::CLang::MergeDefinitions(CVector &vec) +{ + for (CVector::iterator iter = vec.begin(); iter != vec.end(); ++iter) + { + LangEntry & entry = GetEntry(iter->key); + if (entry.GetDefHash() != MakeHash(iter->def)) + entry = iter->def; + } +} + +void CLangMngr::CLang::Dump() +{ + LookUpVecIter iter; + for (iter = m_LookUpTable.begin(); iter != m_LookUpTable.end(); ++iter) + printf(" %s(%d)=%s(%d)\n", iter->GetKey(), iter->GetKeyHash(), iter->GetDef(), iter->GetDefHash()); +} + + +const char * CLangMngr::CLang::GetDef(const char *key) +{ + uint32_t hash = MakeHash(key); + for (LookUpVecIter iter = m_LookUpTable.begin(); iter != m_LookUpTable.end(); ++iter) + if (*iter == hash) + return iter->GetDef(); + return "(not found)"; +} + + +struct OffsetPair +{ + uint32_t defOffset; + uint32_t keyOffset; +}; +// Assumes fp is set to the right position +bool CLangMngr::CLang::Save(FILE *fp) +{ + uint32_t tmpu32; + + long startOffset = ftell(fp); + + tmpu32 = m_LookUpTable.size(); + fflush(fp); + // number of entries + fwrite((void*)&tmpu32, sizeof(tmpu32), 1, fp); + + // write fields that will be filled later + tmpu32 = 0; + // offset to definition table + fwrite((void*)&tmpu32, sizeof(tmpu32), 1, fp); + // size of definition table + fwrite((void*)&tmpu32, sizeof(tmpu32), 1, fp); + // offset to rev lookup table + fwrite((void*)&tmpu32, sizeof(tmpu32), 1, fp); + // size of rev lookup table + fwrite((void*)&tmpu32, sizeof(tmpu32), 1, fp); + uint32_t dtb, rtb; + + fflush(fp); + // Write the lookup table + for (LookUpVecIter iter = m_LookUpTable.begin(); iter != m_LookUpTable.end(); ++iter) + { + uint32_t ltbE[4] = { + iter->GetKeyHash(), + iter->GetDefHash(), + 0, // def offset + 0 // key offset + }; + fwrite((void*)ltbE, sizeof(uint32_t), 4, fp); + } + + // Write the definition table + dtb = ftell(fp); + CVector offsetVec; + offsetVec.reserve(m_LookUpTable.size()); + OffsetPair tmp; + tmp.keyOffset = 0; + for (LookUpVecIter iter = m_LookUpTable.begin(); iter != m_LookUpTable.end(); ++iter) + { + tmp.defOffset = ftell(fp); + offsetVec.push_back(tmp); + uint16_t defLength = strlen(iter->GetDef()); + fwrite((void*)&defLength, sizeof(defLength), 1, fp); + fwrite((void*)iter->GetDef(), 1, defLength, fp); + } + + // Write the reverse lookup table + rtb = ftell(fp); + CVector::iterator offsetVecIter = offsetVec.begin(); + for (LookUpVecIter iter = m_LookUpTable.begin(); iter != m_LookUpTable.end(); ++iter) + { + offsetVecIter->keyOffset = ftell(fp); + ++offsetVecIter; + + char keyLength = strlen(iter->GetKey()); + fwrite((void*)&keyLength, 1, 1, fp); + fwrite((void*)iter->GetKey(), 1, keyLength, fp); + } + + // Write the offsets + fflush(fp); + int i = 0; + for (CVector::iterator iter = offsetVec.begin(); iter != offsetVec.end(); ++iter) + { + fseek(fp, startOffset + 20 + i*16 + 8, SEEK_SET); + + tmpu32 = iter->defOffset; + fwrite((void*)&tmpu32, sizeof(tmpu32), 1, fp); + tmpu32 = iter->keyOffset; + fwrite((void*)&tmpu32, sizeof(tmpu32), 1, fp); + fflush(fp); + ++i; + } + + fseek(fp, 0, SEEK_END); + uint32_t dtbSize = rtb - dtb; + uint32_t rtbSize = ftell(fp) - rtb; + fseek(fp, startOffset + 4, SEEK_SET); + fwrite((void*)&dtb, sizeof(uint32_t), 1,fp); + fwrite((void*)&dtbSize, sizeof(uint32_t), 1,fp); + fwrite((void*)&rtb, sizeof(uint32_t), 1,fp); + fwrite((void*)&rtbSize, sizeof(uint32_t), 1,fp); + return true; +} + +// assumes fp is set to the right position +bool CLangMngr::CLang::Load(FILE *fp) +{ + uint32_t numOfEntries; + uint32_t dtb, rtb, dtbSize, rtbSize; + + Clear(); + + fread((void*)&numOfEntries, sizeof(uint32_t), 1, fp); + fread((void*)&dtb, sizeof(uint32_t), 1, fp); + fread((void*)&dtbSize, sizeof(uint32_t), 1, fp); + fread((void*)&rtb, sizeof(uint32_t), 1, fp); + fread((void*)&rtbSize, sizeof(uint32_t), 1, fp); + + char keyBuf[257]; + char defBuf[4096]; + + for (int i = 0; i < numOfEntries; ++i) + { + uint32_t keyHash, defHash; + uint32_t tmp1, tmp2, tmp3; + fread((void*)&keyHash, sizeof(uint32_t), 1, fp); + fread((void*)&defHash, sizeof(uint32_t), 1, fp); + fread((void*)&tmp1, sizeof(uint32_t), 1, fp); + fread((void*)&tmp2, sizeof(uint32_t), 1, fp); + tmp3 = ftell(fp); + unsigned char tmpu8; + uint16_t tmpu16; + // definition + fseek(fp, tmp2, SEEK_SET); + fread((void*)&tmpu8, 1, 1, fp); + fread((void*)keyBuf, 1, tmpu8, fp); + keyBuf[tmpu8] = 0; + //key + fseek(fp, tmp1, SEEK_SET); + fread((void*)&tmpu16, 2, 1, fp); + fread((void*)defBuf, 1, tmpu16, fp); + defBuf[tmpu16] = 0; + + // add to the entries + m_LookUpTable.push_back(LangEntry(keyBuf, defBuf)); + + // seek back + fseek(fp, tmp3, SEEK_SET); + } + return true; +} + +/******** CLangMngr *********/ + +const char *CLangMngr::Format(const char *pKey, ...) +{ + va_list argptr; + va_start(argptr, pKey); + static char outbuf[4096]; + char *outptr = outbuf; + enum State + { + S_Normal, + S_PercentSign, + }; + + State curState = S_Normal; + + while (*pKey) + { + if (*pKey == '%' && curState == S_Normal) + curState = S_PercentSign; + else if (curState == S_PercentSign) + { + switch (*pKey) + { + case 's': + { + char *tmpArg = va_arg(argptr, char*); + while (*tmpArg) + *outptr++ = *tmpArg++; + break; + } + case 'd': + { + itoa(va_arg(argptr, int), outptr, 10); + outptr += strlen(outptr); + break; + } + case 'f': + case 'g': + { + double tmpArg = va_arg(argptr, double); + sprintf(outptr, "%f", tmpArg); + outptr += strlen(outptr); + break; + } + case 'L': + { + char *langName = va_arg(argptr, char*); + char *key = va_arg(argptr, char*); + const char *def = GetDef(langName, key); + while (*def) + { + switch (*def) + { + case INSERT_NUMBER: + { + itoa(va_arg(argptr, int), outptr, 10); + outptr += strlen(outptr); + break; + } + case INSERT_STRING: + { + char *tmpArg = va_arg(argptr, char*); + while (*tmpArg) + *outptr++ = *tmpArg++; + break; + } + case INSERT_FLOAT: + { + double tmpArg = va_arg(argptr, double); + sprintf(outptr, "%f", tmpArg); + outptr += strlen(outptr); + break; + break; + } + case INSERT_NEWLINE: + *outptr++ = '\n'; + break; + default: + *outptr++ = *def; + } + ++def; + } + break; + } + default: + *outptr++= '%'; + *outptr++ = *pKey; + } + curState = S_Normal; + } + else + *outptr++ = *pKey; + ++pKey; + } + return outbuf; +} + + +void CLangMngr::MergeDefinitions(const char *lang, CVector &tmpVec) +{ + CLang & language = GetLang(lang); + language.MergeDefinitions(tmpVec); +} + +//this is the file parser for dictionary text files +// -- BAILOPAN +int CLangMngr::MergeDefinitionFile(const char *file) +{ + FILE *fp = fopen(file, "rt"); + if (!fp) + return 0; + char buf[4096]; + char language[3]; + char bufstk[4096]; + + // Allocate enough memory to store everything + fseek(fp, 0, SEEK_END); + long fileSize = ftell(fp); + char *tempStorage = new char[fileSize]; + fseek(fp, 0, SEEK_SET); + char *ptrStorage = tempStorage; + + unsigned int i = 0, j = 0; + int litidx = LITIDX_NONE; + int stk = 0; + int max = 0; + int multiline = 0; + CLang lang; + CVector tmpVec; + sKeyDef tmpEntry; + while (fgets(buf, 4095, fp) != NULL) + { + j++; + size_t len=strlen(buf); + for (i=0; iGetName()); + iter->Dump(); + } +} + +const char *CLangMngr::GetDef(const char *langName, const char *key) +{ + CLang & lang = GetLang(langName); + return lang.GetDef(key); +} + +bool CLangMngr::Save(const char *filename) +{ + FILE *fp = fopen(filename, "wb"); + if (!fp) + return false; + uint32_t tmpu32; + // Magic + tmpu32 = MAGIC_HDR; + fwrite((void*)&tmpu32, sizeof(tmpu32), 1, fp); + tmpu32 = m_Languages.size(); + fwrite((void*)&tmpu32, sizeof(tmpu32), 1, fp); + // Write language info table + tmpu32 = 0; + for (LangVecIter iter = m_Languages.begin(); iter != m_Languages.end(); ++iter) + { + // name + fwrite((void*)iter->GetName(), 2, 1, fp); + // offset ( to be set later ) + fwrite((void*)&tmpu32, sizeof(tmpu32), 1, fp); + } + fflush(fp); + CVector langOffsets; + langOffsets.reserve(m_Languages.size()); + + // write the languages + for (LangVecIter iter1 = m_Languages.begin(); iter1 != m_Languages.end(); ++iter1) + { + langOffsets.push_back((uint32_t)ftell(fp)); + if (!iter1->Save(fp)) + { + fclose(fp); + return false; + } + // Make sure we are at the end of the file again + fseek(fp, 0, SEEK_END); + } + + // write the offsets + int i = 0; + for (CVector::iterator iter2 = langOffsets.begin(); iter2 != langOffsets.end(); ++iter2) + { + fseek(fp, 8 + i*6 + 2, SEEK_SET); + tmpu32 = *iter2; + fwrite((void*)&tmpu32, sizeof(tmpu32), 1, fp); + ++i; + } + fclose(fp); + return true; +} + +bool CLangMngr::Load(const char *filename) +{ + Clear(); + + // open the file + FILE *fp = fopen(filename, "rb"); + if (!fp) + return false; + + uint32_t tmpu32; + // Check magic + fread((void*)&tmpu32, sizeof(uint32_t), 1, fp); + if (tmpu32 != MAGIC_HDR) + return false; + + uint32_t numOfLangs; + fread((void*)&numOfLangs, sizeof(uint32_t), 1, fp); + + // Read language info table + CVector langOffsets; + langOffsets.reserve(numOfLangs); + for (uint32_t i = 0; i < numOfLangs; ++i) + { + char langName[3]; + fread((void*)langName, 2, 1, fp); + langName[2] = 0; + GetLang(langName); + fread((void*)&tmpu32, sizeof(uint32_t), 1, fp); + langOffsets.push_back(tmpu32); + } + + // read languages + for (uint32_t i = 0; i < numOfLangs; ++i) + { + fseek(fp, langOffsets[i], SEEK_SET); + if (!m_Languages[i].Load(fp)) + return false; + } + fclose(fp); + return true; +} + +void CLangMngr::Clear() +{ + m_Languages.clear(); +} \ No newline at end of file diff --git a/amxmodx/CLang.h b/amxmodx/CLang.h new file mode 100755 index 00000000..c571ffbb --- /dev/null +++ b/amxmodx/CLang.h @@ -0,0 +1,120 @@ +/* AMX Mod X +* +* by the AMX Mod X Development Team +* originally developed by OLO +* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +*/ + +#ifndef _INCLUDE_CLANG_H +#define _INCLUDE_CLANG_H + +class CLangMngr +{ + struct sKeyDef + { + const char *key; + const char *def; + }; + + class CLang + { + public: + CLang(); + CLang(const char *lang); + ~CLang(); + + const char *GetDef(const char *key); + void MergeDefinitions(CVector & vec); + void Clear(); + + friend bool operator == (const CLang &left, const char *right) + { + return strcmp(left.m_LanguageName, right)==0 ? true : false; + } + const char *GetName() { return m_LanguageName; } + void Dump(); + bool Save(FILE *fp); + bool Load(FILE *fp); + private: + + static uint32_t MakeHash(const char *src); + + class LangEntry + { + uint32_t m_DefHash; + uint32_t m_KeyHash; + char *m_pKey; + char *m_pDef; + void SetKey(const char *pKey); + void SetDef(const char *pDef); + public: + uint32_t GetDefHash(); + uint32_t GetKeyHash(); + const char *GetKey(); + const char *GetDef(); + + LangEntry(); + LangEntry(const char *pKey); + LangEntry(const char *pKey, const char *pDef); + LangEntry(const LangEntry &other); + + void operator= (const char *pNewDef); + bool operator== (uint32_t hash); + + void Clear(); + }; + + LangEntry & GetEntry(const char *key); + typedef CVector LookUpVec; + typedef LookUpVec::iterator LookUpVecIter; + + char m_LanguageName[3]; + + LookUpVec m_LookUpTable; + }; + + void MergeDefinitions(const char *lang, CVector &tmpVec); + static size_t strip(char *str, char *newstr, bool makelower=false); + + typedef CVector LangVec; + typedef LangVec::iterator LangVecIter; + + LangVec m_Languages; + + CLang & GetLang(const char *name); + + void Clear(); +public: + int MergeDefinitionFile(const char *file); + void Dump(); + const char *GetDef(const char *langName, const char *key); + const char *Format(const char *Key, ...); + bool Save(const char *filename); + bool Load(const char *filename); +}; + +#endif //_INCLUDE_CLANG_H