/RbfConv/main.cpp

http://modstudio2.googlecode.com/ · C++ · 324 lines · 272 code · 27 blank · 25 comment · 37 complexity · f81ca949338b4243fac3bfe9dbc10b76 MD5 · raw file

  1. /*
  2. Copyright (c) 2008 Peter "Corsix" Cawley
  3. Permission is hereby granted, free of charge, to any person
  4. obtaining a copy of this software and associated documentation
  5. files (the "Software"), to deal in the Software without
  6. restriction, including without limitation the rights to use,
  7. copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. copies of the Software, and to permit persons to whom the
  9. Software is furnished to do so, subject to the following
  10. conditions:
  11. The above copyright notice and this permission notice shall be
  12. included in all copies or substantial portions of the Software.
  13. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  14. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  15. OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  16. NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  17. HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  18. WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. OTHER DEALINGS IN THE SOFTWARE.
  21. */
  22. #include "TextFileWriter.h"
  23. #include "TextFileReader.h"
  24. #include <stdio.h>
  25. struct command_line_options_t
  26. {
  27. command_line_options_t()
  28. : ePrintLevel(PRINT_NORMAL)
  29. , cPathSeperator('|')
  30. , pUCS(0)
  31. , iUcsLimit(100)
  32. , bSort(true)
  33. , bCache(true)
  34. , bInputIsList(false)
  35. , bRelicStyle(false)
  36. {
  37. }
  38. RainString sInput;
  39. RainString sOutput;
  40. RainString sUCS;
  41. UcsFile *pUCS;
  42. long iUcsLimit;
  43. enum
  44. {
  45. PRINT_VERBOSE,
  46. PRINT_NORMAL,
  47. PRINT_QUIET,
  48. } ePrintLevel;
  49. char cPathSeperator;
  50. bool bSort;
  51. bool bCache;
  52. bool bRelicStyle;
  53. bool bInputIsList;
  54. } g_oCommandLine;
  55. int nullprintf(const wchar_t*, ...) {return 0;}
  56. #define VERBOSEwprintf(...) ((g_oCommandLine.ePrintLevel <= command_line_options_t::PRINT_VERBOSE ? wprintf : nullprintf)(__VA_ARGS__))
  57. #define NOTQUIETwprintf(...) ((g_oCommandLine.ePrintLevel < command_line_options_t::PRINT_QUIET ? wprintf : nullprintf)(__VA_ARGS__))
  58. IFile* OpenInputFile(const RainString& sFile)
  59. {
  60. if(sFile.length() == 1 && sFile[0] == '-')
  61. return RainOpenFilePtr(stdin, false);
  62. else
  63. return RainOpenFileNoThrow(sFile, FM_Read);
  64. }
  65. IFile* OpenOutputFile(const RainString& sFile, const RainString& sFileIn)
  66. {
  67. if(sFile.isEmpty())
  68. {
  69. RainString sNewFileName = sFileIn.beforeLast('.');
  70. if(sFileIn.afterLast('.').compareCaseless("rbf") == 0)
  71. sNewFileName += L".txt";
  72. else
  73. sNewFileName += L".rbf";
  74. return RainOpenFileNoThrow(sNewFileName, FM_Write);
  75. }
  76. else
  77. return RainOpenFileNoThrow(sFile, FM_Write);
  78. }
  79. void ConvertRbfToTxt(IFile *pIn, IFile *pOut)
  80. {
  81. RbfAttributeFile oAttribFile;
  82. if(!g_oCommandLine.bSort)
  83. oAttribFile.enableTableChildrenSort(false);
  84. try
  85. {
  86. oAttribFile.load(pIn);
  87. }
  88. CATCH_THROW_SIMPLE({}, L"Cannot load input RBF");
  89. RbfTxtWriter oWriter(pOut);
  90. oWriter.setUCS(g_oCommandLine.pUCS, g_oCommandLine.iUcsLimit);
  91. oWriter.setIndentProperties(2, ' ', g_oCommandLine.cPathSeperator);
  92. std::auto_ptr<IAttributeTable> pTable(oAttribFile.getRootTable());
  93. oWriter.writeTable(&*pTable);
  94. }
  95. void ConvertTxtToRbf(IFile *pIn, IFile *pOut)
  96. {
  97. RbfWriter oWriter;
  98. TxtReader oReader(pIn, &oWriter);
  99. if(!g_oCommandLine.bCache)
  100. oWriter.enableCaching(false);
  101. oWriter.initialise();
  102. oReader.read();
  103. if(g_oCommandLine.bRelicStyle)
  104. {
  105. RbfWriter oRelicStyled;
  106. oRelicStyled.initialise();
  107. oWriter.rewriteInRelicStyle(&oRelicStyled);
  108. oRelicStyled.writeToFile(pOut, true);
  109. }
  110. else
  111. oWriter.writeToFile(pOut);
  112. VERBOSEwprintf(L"RBF stats:\n");
  113. VERBOSEwprintf(L" %lu tables\n", oWriter.getTableCount());
  114. VERBOSEwprintf(L" %lu keys\n", oWriter.getKeyCount());
  115. VERBOSEwprintf(L" %lu data items via %lu indicies\n", oWriter.getDataCount(), oWriter.getDataIndexCount());
  116. VERBOSEwprintf(L" %lu strings over %lu bytes\n", oWriter.getStringCount(), oWriter.getStringsLength());
  117. VERBOSEwprintf(L" %lu bytes saved by caching\n", oWriter.getAmountSavedByCache());
  118. }
  119. bool DoWork(RainString& sInput, RainString& sOutput)
  120. {
  121. std::auto_ptr<IFile> pInFile;
  122. std::auto_ptr<IFile> pOutFile;
  123. pInFile.reset(OpenInputFile(sInput));
  124. pOutFile.reset(OpenOutputFile(sOutput, sInput));
  125. if(pInFile.get() && pOutFile.get())
  126. {
  127. if(sInput.afterLast('.').compareCaseless("rbf") == 0)
  128. {
  129. NOTQUIETwprintf(L"Converting RBF to text...\n");
  130. ConvertRbfToTxt(&*pInFile, &*pOutFile);
  131. }
  132. else
  133. {
  134. NOTQUIETwprintf(L"Converting text to RBF...\n");
  135. ConvertTxtToRbf(&*pInFile, &*pOutFile);
  136. }
  137. return true;
  138. }
  139. else
  140. {
  141. if(!pInFile.get())
  142. fwprintf(stderr, L"Cannot open input file \'%s\'\n", sInput.getCharacters());
  143. if(!pOutFile.get())
  144. fwprintf(stderr, L"Cannot open output file \'%s\'\n", sOutput.getCharacters());
  145. }
  146. return false;
  147. }
  148. int wmain(int argc, wchar_t** argv)
  149. {
  150. #define REQUIRE_NEXT_ARG(noun) if((i + 1) >= argc) { \
  151. fwprintf(stderr, L"Expected " L ## noun L" to follow \"%s\"\n", arg); \
  152. return -2; \
  153. }
  154. for(int i = 1; i < argc; ++i)
  155. {
  156. wchar_t *arg = argv[i];
  157. if(arg[0] == '-')
  158. {
  159. bool bValid = false;
  160. if(arg[1] != 0 && arg[2] == 0)
  161. {
  162. bValid = true;
  163. switch(arg[1])
  164. {
  165. case 'i':
  166. REQUIRE_NEXT_ARG("filename");
  167. g_oCommandLine.sInput = argv[++i];
  168. break;
  169. case 'o':
  170. REQUIRE_NEXT_ARG("filename");
  171. g_oCommandLine.sOutput = argv[++i];
  172. break;
  173. case 's':
  174. g_oCommandLine.bSort = false;
  175. break;
  176. case 'R':
  177. g_oCommandLine.bRelicStyle = true;
  178. // no break
  179. case 'c':
  180. g_oCommandLine.bCache = false;
  181. break;
  182. case 'v':
  183. g_oCommandLine.ePrintLevel = command_line_options_t::PRINT_VERBOSE;
  184. break;
  185. case 'q':
  186. g_oCommandLine.ePrintLevel = command_line_options_t::PRINT_QUIET;
  187. break;
  188. case 'p':
  189. REQUIRE_NEXT_ARG("path seperator");
  190. g_oCommandLine.cPathSeperator = argv[++i][0];
  191. break;
  192. case 'u':
  193. REQUIRE_NEXT_ARG("filename");
  194. g_oCommandLine.sUCS = argv[++i];
  195. break;
  196. case 'U':
  197. REQUIRE_NEXT_ARG("number");
  198. g_oCommandLine.iUcsLimit = _wtoi(argv[++i]);
  199. break;
  200. case 'L':
  201. g_oCommandLine.bInputIsList = true;
  202. break;
  203. default:
  204. bValid = false;
  205. break;
  206. }
  207. }
  208. if(!bValid)
  209. {
  210. fwprintf(stderr, L"Unrecognised command line switch \"%s\"\n", arg);
  211. return -1;
  212. }
  213. }
  214. else
  215. {
  216. fwprintf(stderr, L"Expected command line switch rather than \"%s\"\n", arg);
  217. return -3;
  218. }
  219. }
  220. #undef REQUIRE_NEXT_ARG
  221. NOTQUIETwprintf(L"** Corsix\'s Crude RBF Convertor **\n");
  222. if(g_oCommandLine.sInput.isEmpty())
  223. {
  224. fwprintf(stderr, L"Expected an input filename. Command format is:\n");
  225. fwprintf(stderr, L"%s -i infile [-L | -o outfile] [-q | -v] [-p \".\" | -p \" \"] [-u ucsfile] [-U threshold] [-s] [-R | -c]\n", wcsrchr(*argv, '\\') ? (wcsrchr(*argv, '\\') + 1) : (*argv));
  226. fwprintf(stderr, L" -i; file to read from, either a .rbf file or a .txt file\n");
  227. fwprintf(stderr, L" if \"-\", then uses stdin as input text file or input list file\n");
  228. fwprintf(stderr, L" -o; file to write to, either a .rbf file or a .txt file\n");
  229. fwprintf(stderr, L" if not given, then uses input name with .txt swapped for .rbf (and vice versa)\n");
  230. fwprintf(stderr, L" -L; infile is a file containing a list of input files (one per line)\n");
  231. fwprintf(stderr, L" -q; quiet output to console\n");
  232. fwprintf(stderr, L" -v; verbose output to console\n");
  233. fwprintf(stderr, L" Options for writing text files:\n");
  234. fwprintf(stderr, L" -p; path seperator to use (defaults to vertical bar)\n");
  235. fwprintf(stderr, L" -u; UCS file to use to comment number values\n");
  236. fwprintf(stderr, L" -U; Integers above which to interpret as UCS references (defaults to 100)\n");
  237. fwprintf(stderr, L" -s; Disable sorting of values (use order from RBF file)\n");
  238. fwprintf(stderr, L" Options for writing RBF files:\n");
  239. fwprintf(stderr, L" -c; Disable caching of data (faster, but makes larger file)\n");
  240. fwprintf(stderr, L" -R; Write in Relic style (takes longer, also forces -c)\n");
  241. return -4;
  242. }
  243. if(g_oCommandLine.sInput.compareCaseless(g_oCommandLine.sOutput) == 0)
  244. {
  245. fwprintf(stderr, L"Expected input file and output file to be different files");
  246. return -5;
  247. }
  248. bool bAllGood = false;
  249. try
  250. {
  251. if(!g_oCommandLine.sUCS.isEmpty())
  252. {
  253. g_oCommandLine.pUCS = new UcsFile;
  254. g_oCommandLine.pUCS->loadFromFile(g_oCommandLine.sUCS);
  255. }
  256. if(g_oCommandLine.bInputIsList)
  257. {
  258. bAllGood = true;
  259. g_oCommandLine.sOutput.clear();
  260. std::auto_ptr<IFile> pListFile(OpenInputFile(g_oCommandLine.sInput));
  261. BufferingInputTextStream<char> oListFile(&*pListFile);
  262. while(!oListFile.isEOF())
  263. {
  264. RainString sLine(oListFile.readLine().trimWhitespace());
  265. if(!sLine.isEmpty())
  266. {
  267. NOTQUIETwprintf(L"%s\n", sLine.getCharacters());
  268. bAllGood = DoWork(sLine, g_oCommandLine.sOutput) && bAllGood;
  269. }
  270. }
  271. }
  272. else
  273. bAllGood = DoWork(g_oCommandLine.sInput, g_oCommandLine.sOutput);
  274. }
  275. catch(RainException *pE)
  276. {
  277. bAllGood = false;
  278. fwprintf(stderr, L"Fatal exception:\n");
  279. for(RainException *p = pE; p; p = p->getPrevious())
  280. {
  281. fwprintf(stderr, L"%s:%li - %s\n", p->getFile().getCharacters(), p->getLine(), p->getMessage().getCharacters());
  282. if(g_oCommandLine.ePrintLevel >= command_line_options_t::PRINT_QUIET)
  283. break;
  284. }
  285. delete pE;
  286. }
  287. delete g_oCommandLine.pUCS;
  288. if(bAllGood)
  289. {
  290. NOTQUIETwprintf(L"Done\n");
  291. return 0;
  292. }
  293. return -10;
  294. }