PageRenderTime 124ms CodeModel.GetById 75ms app.highlight 45ms RepoModel.GetById 1ms app.codeStats 0ms

/RbfConv/main.cpp

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