lang.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "io/stream.h"
  24. #include "io/fileStream.h"
  25. #include "io/resource/resourceManager.h"
  26. #include "console/console.h"
  27. #include "console/consoleInternal.h"
  28. #include "console/ast.h"
  29. #include "console/compiler.h"
  30. #include "memory/safeDelete.h"
  31. #include "gui/language/lang.h"
  32. //////////////////////////////////////////////////////////////////////////
  33. // LangFile Class
  34. //////////////////////////////////////////////////////////////////////////
  35. LangFile::LangFile(const UTF8 *langName /* = NULL */)
  36. {
  37. if(langName)
  38. {
  39. mLangName = new UTF8 [dStrlen(langName) + 1];
  40. dStrcpy(mLangName, langName);
  41. }
  42. else
  43. mLangName = NULL;
  44. mLangFile = NULL;
  45. }
  46. LangFile::~LangFile()
  47. {
  48. // [tom, 3/1/2005] Note: If this is freed in FreeTable() then when the file
  49. // is loaded, the language name will be blitzed.
  50. // Programming after 36 hours without sleep != good.
  51. SAFE_DELETE(mLangName);
  52. SAFE_DELETE(mLangFile);
  53. freeTable();
  54. }
  55. void LangFile::freeTable()
  56. {
  57. U32 i;
  58. for(i = 0;i < (U32)mStringTable.size();i++)
  59. {
  60. if(mStringTable[i])
  61. delete [] mStringTable[i];
  62. }
  63. mStringTable.clear();
  64. }
  65. bool LangFile::load(const UTF8 *filename)
  66. {
  67. Stream *pS;
  68. bool bRet = false;
  69. if((pS = ResourceManager->openStream((const char*)filename)))
  70. {
  71. bRet = load(pS);
  72. ResourceManager->closeStream(pS);
  73. }
  74. return bRet;
  75. }
  76. bool LangFile::load(Stream *s)
  77. {
  78. freeTable();
  79. while(s->getStatus() != Stream::EOS)
  80. {
  81. char buf[256];
  82. s->readString(buf);
  83. addString((const UTF8*)buf);
  84. }
  85. return true;
  86. }
  87. bool LangFile::save(const UTF8 *filename)
  88. {
  89. FileStream fs;
  90. bool bRet = false;
  91. if(!isLoaded())
  92. return false;
  93. if(ResourceManager->openFileForWrite(fs, (const char*)filename))
  94. {
  95. bRet = save(&fs);
  96. fs.close();
  97. }
  98. return bRet;
  99. }
  100. bool LangFile::save(Stream *s)
  101. {
  102. if(!isLoaded())
  103. return false;
  104. U32 i;
  105. for(i = 0;i < (U32)mStringTable.size();i++)
  106. {
  107. s->writeString((char*)mStringTable[i]);
  108. }
  109. return true;
  110. }
  111. const UTF8 * LangFile::getString(U32 id)
  112. {
  113. if(id == LANG_INVALID_ID || id >= (U32)mStringTable.size())
  114. return NULL;
  115. return mStringTable[id];
  116. }
  117. U32 LangFile::addString(const UTF8 *str)
  118. {
  119. UTF8 *newstr = new UTF8 [dStrlen(str) + 1];
  120. dStrcpy(newstr, str);
  121. mStringTable.push_back(newstr);
  122. return mStringTable.size() - 1;
  123. }
  124. void LangFile::setString(U32 id, const UTF8 *str)
  125. {
  126. if(id >= (U32)mStringTable.size())
  127. mStringTable.setSize(id+1);
  128. UTF8 *newstr = new UTF8 [dStrlen(str) + 1];
  129. dStrcpy(newstr, str);
  130. mStringTable[id] = newstr;
  131. }
  132. void LangFile::setLangName(const UTF8 *newName)
  133. {
  134. if(mLangName)
  135. delete [] mLangName;
  136. mLangName = new UTF8 [dStrlen(newName) + 1];
  137. dStrcpy(mLangName, newName);
  138. }
  139. void LangFile::setLangFile(const UTF8 *langFile)
  140. {
  141. if(mLangFile)
  142. delete [] mLangFile;
  143. mLangFile = new UTF8 [dStrlen(langFile) + 1];
  144. dStrcpy(mLangFile, langFile);
  145. }
  146. bool LangFile::activateLanguage()
  147. {
  148. if(isLoaded())
  149. return true;
  150. if(mLangFile)
  151. {
  152. return load(mLangFile);
  153. }
  154. return false;
  155. }
  156. void LangFile::deactivateLanguage()
  157. {
  158. if(mLangFile && isLoaded())
  159. freeTable();
  160. }
  161. //////////////////////////////////////////////////////////////////////////
  162. // LangTable Class
  163. //////////////////////////////////////////////////////////////////////////
  164. IMPLEMENT_CONOBJECT(LangTable);
  165. LangTable::LangTable() : mDefaultLang(-1), mCurrentLang(-1)
  166. {
  167. }
  168. LangTable::~LangTable()
  169. {
  170. S32 i;
  171. for(i = 0;i < mLangTable.size();i++)
  172. {
  173. if(mLangTable[i])
  174. delete mLangTable[i];
  175. }
  176. mLangTable.clear();
  177. }
  178. S32 LangTable::addLanguage(LangFile *lang, const UTF8 *name /* = NULL */)
  179. {
  180. if(name)
  181. lang->setLangName(name);
  182. mLangTable.push_back(lang);
  183. if(mDefaultLang == -1)
  184. setDefaultLanguage(mLangTable.size() - 1);
  185. if(mCurrentLang == -1)
  186. setCurrentLanguage(mLangTable.size() - 1);
  187. return mLangTable.size() - 1;
  188. }
  189. S32 LangTable::addLanguage(const UTF8 *filename, const UTF8 *name /* = NULL */)
  190. {
  191. LangFile *pLang;
  192. S32 ret = -1;
  193. if((pLang = new LangFile(name)))
  194. {
  195. if(bool(ResourceManager->find((const char*)filename)))
  196. {
  197. pLang->setLangFile(filename);
  198. if((ret = addLanguage(pLang)) >= 0)
  199. return ret;
  200. }
  201. delete pLang;
  202. }
  203. return -1;
  204. }
  205. const UTF8 *LangTable::getString(const U32 id) const
  206. {
  207. const UTF8 *s = NULL;
  208. if(mCurrentLang >= 0)
  209. s = mLangTable[mCurrentLang]->getString(id);
  210. if(s == NULL && mDefaultLang >= 0 && mDefaultLang != mCurrentLang)
  211. s = mLangTable[mDefaultLang]->getString(id);
  212. return s;
  213. }
  214. const U32 LangTable::getStringLength(const U32 id) const
  215. {
  216. const UTF8 *s = getString(id);
  217. if(s)
  218. return dStrlen(s);
  219. return 0;
  220. }
  221. void LangTable::setDefaultLanguage(S32 langid)
  222. {
  223. if(langid >= 0 && langid < mLangTable.size())
  224. {
  225. if(mLangTable[langid]->activateLanguage())
  226. {
  227. if(mDefaultLang >= 0)
  228. mLangTable[mDefaultLang]->deactivateLanguage();
  229. mDefaultLang = langid;
  230. }
  231. }
  232. }
  233. void LangTable::setCurrentLanguage(S32 langid)
  234. {
  235. if(langid >= 0 && langid < mLangTable.size())
  236. {
  237. if(mLangTable[langid]->activateLanguage())
  238. {
  239. Con::printf("Language %s [%s] activated.", mLangTable[langid]->getLangName(), mLangTable[langid]->getLangFile());
  240. if(mCurrentLang >= 0 && mCurrentLang != mDefaultLang)
  241. {
  242. mLangTable[mCurrentLang]->deactivateLanguage();
  243. Con::printf("Language %s [%s] deactivated.", mLangTable[mCurrentLang]->getLangName(), mLangTable[mCurrentLang]->getLangFile());
  244. }
  245. mCurrentLang = langid;
  246. }
  247. }
  248. }
  249. //////////////////////////////////////////////////////////////////////////
  250. // LangTable Console Methods
  251. //////////////////////////////////////////////////////////////////////////
  252. ConsoleMethod(LangTable, addLanguage, S32, 3, 4, "(string filename, [string languageName]) Adds the specified language to a table from file\n"
  253. "@param filename Filename of file containing language data\n"
  254. "@param languageName (Optional) Name of language\n"
  255. "@return The size of the language table or -1 on failure")
  256. {
  257. UTF8 scriptFilenameBuffer[1024];
  258. Con::expandPath((char*)scriptFilenameBuffer, sizeof(scriptFilenameBuffer), argv[2]);
  259. return object->addLanguage(scriptFilenameBuffer, argc == 4 ? (const UTF8*)argv[3] : NULL);
  260. }
  261. ConsoleMethod(LangTable, getString, const char *, 3, 3, "(string) ")
  262. {
  263. char *ret;
  264. const char *str;
  265. if((str = (const char*)object->getString(dAtoi(argv[2]))))
  266. {
  267. ret = Con::getReturnBuffer(dStrlen(str) + 1);
  268. dStrcpy(ret, str);
  269. return ret;
  270. }
  271. return "";
  272. }
  273. ConsoleMethod(LangTable, setDefaultLanguage, void, 3, 3, "(int language) Sets the default language to the one specified\n"
  274. "@param language ID of the desired language\n"
  275. "@return No return value.")
  276. {
  277. object->setDefaultLanguage(dAtoi(argv[2]));
  278. }
  279. ConsoleMethod(LangTable, setCurrentLanguage, void, 3, 3, "(int language) Sets the current language to the one specified\n"
  280. "@param language ID of the desired language\n"
  281. "@return No return value.")
  282. {
  283. object->setCurrentLanguage(dAtoi(argv[2]));
  284. }
  285. ConsoleMethod(LangTable, getCurrentLanguage, S32, 2, 2, "() @return Returns the ID of the currentlt used language")
  286. {
  287. return object->getCurrentLanguage();
  288. }
  289. ConsoleMethod(LangTable, getLangName, const char *, 3, 3, "(int language) Returns the name of the langauge specified by the given ID\n"
  290. "@param language The ID of the desired language to check\n"
  291. "@return The name of the specified language, or the empty string on failure.")
  292. {
  293. char *ret;
  294. const char *str;
  295. if((str = (const char*)object->getLangName(dAtoi(argv[2]))))
  296. {
  297. ret = Con::getReturnBuffer(dStrlen(str) + 1);
  298. dStrcpy(ret, str);
  299. return ret;
  300. }
  301. return "";
  302. }
  303. ConsoleMethod(LangTable, getNumLang, S32, 2, 2, "() Returns the number of currently stored languages\n"
  304. "@return The number of laguages as an integer")
  305. {
  306. return object->getNumLang();
  307. }
  308. //////////////////////////////////////////////////////////////////////////
  309. // Support Functions
  310. //////////////////////////////////////////////////////////////////////////
  311. UTF8 *sanitiseVarName(const UTF8 *varName, UTF8 *buffer, U32 bufsize)
  312. {
  313. if(! varName || bufsize < 10) // [tom, 3/3/2005] bufsize check gives room to be lazy below
  314. {
  315. *buffer = 0;
  316. return NULL;
  317. }
  318. dStrcpy(buffer, (const UTF8*)"I18N::");
  319. UTF8 *dptr = buffer + 6;
  320. const UTF8 *sptr = varName;
  321. while(*sptr)
  322. {
  323. if(dIsalnum(*sptr))
  324. *dptr++ = *sptr++;
  325. else
  326. {
  327. if(*(dptr - 1) != '_')
  328. *dptr++ = '_';
  329. sptr++;
  330. }
  331. if((dptr - buffer) >= S32(bufsize - 1))
  332. break;
  333. }
  334. *dptr = 0;
  335. return buffer;
  336. }
  337. UTF8 *getCurrentModVarName(UTF8 *buffer, U32 bufsize)
  338. {
  339. char varName[256];
  340. StringTableEntry cbName = CodeBlock::getCurrentCodeBlockName();
  341. const UTF8 *slash = (const UTF8*)dStrchr(cbName, '/');
  342. if (slash == NULL)
  343. {
  344. Con::errorf("Illegal CodeBlock path detected in sanitiseVarName() (no mod directory): %s", cbName);
  345. return NULL;
  346. }
  347. dStrncpy(varName, cbName, slash - (const UTF8*)cbName);
  348. varName[slash - (const UTF8*)cbName] = 0;
  349. return sanitiseVarName((UTF8*)varName, buffer, bufsize);
  350. }
  351. const LangTable *getCurrentModLangTable()
  352. {
  353. UTF8 saneVarName[256];
  354. if(getCurrentModVarName(saneVarName, sizeof(saneVarName)))
  355. {
  356. const LangTable *lt = dynamic_cast<LangTable *>(Sim::findObject(Con::getIntVariable((const char*)saneVarName)));
  357. return lt;
  358. }
  359. return NULL;
  360. }
  361. const LangTable *getModLangTable(const UTF8 *mod)
  362. {
  363. UTF8 saneVarName[256];
  364. if(sanitiseVarName(mod, saneVarName, sizeof(saneVarName)))
  365. {
  366. const LangTable *lt = dynamic_cast<LangTable *>(Sim::findObject(Con::getIntVariable((const char*)saneVarName)));
  367. return lt;
  368. }
  369. return NULL;
  370. }