ripent.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. /***
  2. *
  3. * Copyright (c) 1998, Valve LLC. All rights reserved.
  4. *
  5. * This product contains software technology licensed from Id
  6. * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
  7. * All Rights Reserved.
  8. *
  9. ****/
  10. // csg4.c
  11. #include "ripent.h"
  12. typedef enum
  13. {
  14. hl_undefined = -1,
  15. hl_export = 0,
  16. hl_import = 1
  17. }
  18. hl_types;
  19. static hl_types g_mode = hl_undefined;
  20. // g_parse: command line switch (-parse).
  21. // Added by: Ryan Gregg aka Nem
  22. bool g_parse = DEFAULT_PARSE;
  23. bool g_chart = DEFAULT_CHART;
  24. bool g_info = DEFAULT_INFO;
  25. // ScanForToken()
  26. // Added by: Ryan Gregg aka Nem
  27. //
  28. // Scans entity data starting at iIndex for cToken. Every time a \n char
  29. // is encountered iLine is incremented. If iToken is not null, the index
  30. // cToken was found at is inserted into it.
  31. bool ScanForToken(char cToken, int &iIndex, int &iLine, bool bIgnoreWhiteSpace, bool bIgnoreOthers, int *iToken = 0)
  32. {
  33. for(; iIndex < g_entdatasize; iIndex++)
  34. {
  35. // If we found a null char, consider it end of data.
  36. if(g_dentdata[iIndex] == '\0')
  37. {
  38. iIndex = g_entdatasize;
  39. return false;
  40. }
  41. // Count lines (for error message).
  42. if(g_dentdata[iIndex] == '\n')
  43. {
  44. iLine++;
  45. }
  46. // Ignore white space, if we are ignoring it.
  47. if(!bIgnoreWhiteSpace && isspace(g_dentdata[iIndex]))
  48. {
  49. continue;
  50. }
  51. if(g_dentdata[iIndex] != cToken)
  52. {
  53. if(bIgnoreOthers)
  54. continue;
  55. else
  56. return false;
  57. }
  58. // Advance the index past the token.
  59. iIndex++;
  60. // Return the index of the token if requested.
  61. if(iToken != 0)
  62. {
  63. *iToken = iIndex - 1;
  64. }
  65. return true;
  66. }
  67. // End of data.
  68. return false;
  69. }
  70. #include <list>
  71. typedef std::list<char *> CEntityPairList;
  72. typedef std::list<CEntityPairList *> CEntityList;
  73. // ParseEntityData()
  74. // Added by: Ryan Gregg aka Nem
  75. //
  76. // Pareses and reformats entity data stripping all non essential
  77. // formatting and using the formatting options passed through this
  78. // function. The length is specified because in some cases (i.e. the
  79. // terminator) a null char is desired to be printed.
  80. void ParseEntityData(const char *cTab, int iTabLength, const char *cNewLine, int iNewLineLength, const char *cTerminator, int iTerminatorLength)
  81. {
  82. CEntityList EntityList; // Parsed entities.
  83. int iIndex = 0; // Current char in g_dentdata.
  84. int iLine = 0; // Current line in g_dentdata.
  85. char cError[256] = "";
  86. try
  87. {
  88. //
  89. // Parse entity data.
  90. //
  91. Log("\nParsing entity data.\n");
  92. while(true)
  93. {
  94. // Parse the start of an entity.
  95. if(!ScanForToken('{', iIndex, iLine, false, false))
  96. {
  97. if(iIndex == g_entdatasize)
  98. {
  99. // We read all the entities.
  100. break;
  101. }
  102. else
  103. {
  104. sprintf_s(cError, "expected token %s on line %d.", "{", iLine);
  105. throw cError;
  106. }
  107. }
  108. CEntityPairList *EntityPairList = new CEntityPairList();
  109. // Parse the rest of the entity.
  110. while(true)
  111. {
  112. // Parse the key and value.
  113. for(int j = 0; j < 2; j++)
  114. {
  115. int iStart;
  116. // Parse the start of a string.
  117. if(!ScanForToken('\"', iIndex, iLine, false, false, &iStart))
  118. {
  119. sprintf_s(cError, "expected token %s on line %d.", "\"", iLine);
  120. throw cError;
  121. }
  122. int iEnd;
  123. // Parse the end of a string.
  124. if(!ScanForToken('\"', iIndex, iLine, true, true, &iEnd))
  125. {
  126. sprintf_s(cError, "expected token %s on line %d.", "\"", iLine);
  127. throw cError;
  128. }
  129. // Extract the string.
  130. int iLength = iEnd - iStart - 1;
  131. char *cString = new char[iLength + 1];
  132. memcpy(cString, &g_dentdata[iStart + 1], iLength);
  133. cString[iLength] = '\0';
  134. // Save it.
  135. EntityPairList->push_back(cString);
  136. }
  137. // Parse the end of an entity.
  138. if(!ScanForToken('}', iIndex, iLine, false, false))
  139. {
  140. if(g_dentdata[iIndex] == '\"')
  141. {
  142. // We arn't done the entity yet.
  143. continue;
  144. }
  145. else
  146. {
  147. sprintf_s(cError, "expected token %s on line %d.", "}", iLine);
  148. throw cError;
  149. }
  150. }
  151. // We read the entity.
  152. EntityList.push_back(EntityPairList);
  153. break;
  154. }
  155. }
  156. Log("%d entities parsed.\n", EntityList.size());
  157. //
  158. // Calculate new data length.
  159. //
  160. int iNewLength = 0;
  161. for(CEntityList::iterator i = EntityList.begin(); i != EntityList.end(); ++i)
  162. {
  163. // Opening brace.
  164. iNewLength += 1;
  165. // New line.
  166. iNewLength += iNewLineLength;
  167. CEntityPairList *EntityPairList = *i;
  168. for(CEntityPairList::iterator j = EntityPairList->begin(); j != EntityPairList->end(); ++j)
  169. {
  170. // Tab.
  171. iNewLength += iTabLength;
  172. // String.
  173. iNewLength += 1;
  174. iNewLength += (int)strlen(*j);
  175. iNewLength += 1;
  176. // String seperator.
  177. iNewLength += 1;
  178. ++j;
  179. // String.
  180. iNewLength += 1;
  181. iNewLength += (int)strlen(*j);
  182. iNewLength += 1;
  183. // New line.
  184. iNewLength += iNewLineLength;
  185. }
  186. // Closing brace.
  187. iNewLength += 1;
  188. // New line.
  189. iNewLength += iNewLineLength;
  190. }
  191. // Terminator.
  192. iNewLength += iTerminatorLength;
  193. //
  194. // Check our parsed data.
  195. //
  196. assume(iNewLength != 0, "No entity data.");
  197. assume(iNewLength < sizeof(g_dentdata), "Entity data size exceedes dentdata limit.");
  198. //
  199. // Clear current data.
  200. //
  201. g_entdatasize = 0;
  202. //
  203. // Fill new data.
  204. //
  205. Log("Formating entity data.\n\n");
  206. for(CEntityList::iterator i = EntityList.begin(); i != EntityList.end(); ++i)
  207. {
  208. // Opening brace.
  209. g_dentdata[g_entdatasize] = '{';
  210. g_entdatasize += 1;
  211. // New line.
  212. memcpy(&g_dentdata[g_entdatasize], cNewLine, iNewLineLength);
  213. g_entdatasize += iNewLineLength;
  214. CEntityPairList *EntityPairList = *i;
  215. for(CEntityPairList::iterator j = EntityPairList->begin(); j != EntityPairList->end(); ++j)
  216. {
  217. // Tab.
  218. memcpy(&g_dentdata[g_entdatasize], cTab, iTabLength);
  219. g_entdatasize += iTabLength;
  220. // String.
  221. g_dentdata[g_entdatasize] = '\"';
  222. g_entdatasize += 1;
  223. memcpy(&g_dentdata[g_entdatasize], *j, strlen(*j));
  224. g_entdatasize += (int)strlen(*j);
  225. g_dentdata[g_entdatasize] = '\"';
  226. g_entdatasize += 1;
  227. // String seperator.
  228. g_dentdata[g_entdatasize] = ' ';
  229. g_entdatasize += 1;
  230. ++j;
  231. // String.
  232. g_dentdata[g_entdatasize] = '\"';
  233. g_entdatasize += 1;
  234. memcpy(&g_dentdata[g_entdatasize], *j, strlen(*j));
  235. g_entdatasize += (int)strlen(*j);
  236. g_dentdata[g_entdatasize] = '\"';
  237. g_entdatasize += 1;
  238. // New line.
  239. memcpy(&g_dentdata[g_entdatasize], cNewLine, iNewLineLength);
  240. g_entdatasize += iNewLineLength;
  241. }
  242. // Closing brace.
  243. g_dentdata[g_entdatasize] = '}';
  244. g_entdatasize += 1;
  245. // New line.
  246. memcpy(&g_dentdata[g_entdatasize], cNewLine, iNewLineLength);
  247. g_entdatasize += iNewLineLength;
  248. }
  249. // Terminator.
  250. memcpy(&g_dentdata[g_entdatasize], cTerminator, iTerminatorLength);
  251. g_entdatasize += iTerminatorLength;
  252. //
  253. // Delete entity data.
  254. //
  255. for(CEntityList::iterator i = EntityList.begin(); i != EntityList.end(); ++i)
  256. {
  257. CEntityPairList *EntityPairList = *i;
  258. for(CEntityPairList::iterator j = EntityPairList->begin(); j != EntityPairList->end(); ++j)
  259. {
  260. delete []*j;
  261. }
  262. delete EntityPairList;
  263. }
  264. //return true;
  265. }
  266. catch(...)
  267. {
  268. //
  269. // Delete entity data.
  270. //
  271. for(CEntityList::iterator i = EntityList.begin(); i != EntityList.end(); ++i)
  272. {
  273. CEntityPairList *EntityPairList = *i;
  274. for(CEntityPairList::iterator j = EntityPairList->begin(); j != EntityPairList->end(); ++j)
  275. {
  276. delete []*j;
  277. }
  278. delete EntityPairList;
  279. }
  280. // If we threw the error cError wont be null, this is
  281. // a message, print it.
  282. if(*cError != '\0')
  283. {
  284. Error(cError);
  285. }
  286. Error("unknowen exception.");
  287. //return false;
  288. }
  289. }
  290. static void ReadBSP(const char* const name)
  291. {
  292. char filename[_MAX_PATH];
  293. safe_strncpy(filename, name, _MAX_PATH);
  294. StripExtension(filename);
  295. DefaultExtension(filename, ".bsp");
  296. LoadBSPFile(name);
  297. }
  298. static void WriteBSP(const char* const name)
  299. {
  300. char filename[_MAX_PATH];
  301. safe_strncpy(filename, name, _MAX_PATH);
  302. StripExtension(filename);
  303. DefaultExtension(filename, ".bsp");
  304. WriteBSPFile(filename);
  305. }
  306. static void WriteEntities(const char* const name)
  307. {
  308. char filename[_MAX_PATH];
  309. safe_strncpy(filename, name, _MAX_PATH);
  310. StripExtension(filename);
  311. DefaultExtension(filename, ".ent");
  312. _unlink(filename);
  313. {
  314. if(g_parse) // Added by Nem.
  315. {
  316. ParseEntityData(" ", 2, "\r\n", 2, "", 0);
  317. }
  318. FILE *f = SafeOpenWrite(filename);
  319. Log("\nWriting %s.\n", filename); // Added by Nem.
  320. SafeWrite(f, g_dentdata, g_entdatasize);
  321. fclose(f);
  322. }
  323. }
  324. static void ReadEntities(const char* const name)
  325. {
  326. char filename[_MAX_PATH];
  327. safe_strncpy(filename, name, _MAX_PATH);
  328. StripExtension(filename);
  329. DefaultExtension(filename, ".ent");
  330. {
  331. FILE *f = SafeOpenRead(filename);
  332. Log("\nReading %s.\n", filename); // Added by Nem.
  333. g_entdatasize = q_filelength(f);
  334. assume(g_entdatasize != 0, "No entity data.");
  335. assume(g_entdatasize < sizeof(g_dentdata), "Entity data size exceedes dentdata limit.");
  336. SafeRead(f, g_dentdata, g_entdatasize);
  337. fclose(f);
  338. if (g_dentdata[g_entdatasize-1] != 0)
  339. {
  340. // Log("g_dentdata[g_entdatasize-1] = %d\n", g_dentdata[g_entdatasize-1]);
  341. if(g_parse) // Added by Nem.
  342. {
  343. ParseEntityData("", 0, "\n", 1, "\0", 1);
  344. }
  345. else
  346. {
  347. if(g_dentdata[g_entdatasize - 1] != '\0')
  348. {
  349. g_dentdata[g_entdatasize] = '\0';
  350. g_entdatasize++;
  351. }
  352. }
  353. }
  354. }
  355. }
  356. //======================================================================
  357. static void Usage(void)
  358. {
  359. //Log("%s " ZHLT_VERSIONSTRING "\n" MODIFICATIONS_STRING "\n", g_Program);
  360. //Log(" Usage: ripent [-import|-export] [-texdata n] bspname\n");
  361. // Modified to behave like other tools by Nem.
  362. Banner();
  363. Log("\n-= %s Options =-\n\n", g_Program);
  364. Log(" -export : Export entity data\n");
  365. Log(" -import : Import entity data\n\n");
  366. Log(" -parse : Parse and format entity data\n\n");
  367. Log(" -texdata # : Alter maximum texture memory limit (in kb)\n");
  368. Log(" -lightdata # : Alter maximum lighting memory limit (in kb)\n");
  369. Log(" -chart : Display bsp statitics\n");
  370. Log(" -noinfo : Do not show tool configuration information\n\n");
  371. Log(" mapfile : The mapfile to process\n\n");
  372. exit(1);
  373. }
  374. // =====================================================================================
  375. // Settings
  376. // =====================================================================================
  377. static void Settings()
  378. {
  379. char* tmp;
  380. if (!g_info)
  381. {
  382. return;
  383. }
  384. Log("\n-= Current %s Settings =-\n", g_Program);
  385. Log("Name | Setting | Default\n" "-------------------|-------------|-------------------------\n");
  386. // ZHLT Common Settings
  387. Log("chart [ %9s ] [ %9s ]\n", g_chart ? "on" : "off", DEFAULT_CHART ? "on" : "off");
  388. Log("max texture memory [ %9d ] [ %9d ]\n", g_max_map_miptex, DEFAULT_MAX_MAP_MIPTEX);
  389. Log("max lighting memory [ %9d ] [ %9d ]\n", g_max_map_lightdata, DEFAULT_MAX_MAP_LIGHTDATA);
  390. switch (g_mode)
  391. {
  392. case hl_import:
  393. default:
  394. tmp = "Import";
  395. break;
  396. case hl_export:
  397. tmp = "Export";
  398. break;
  399. }
  400. Log("\n");
  401. // RipEnt Specific Settings
  402. Log("mode [ %9s ] [ %9s ]\n", tmp, "N/A");
  403. Log("parse [ %9s ] [ %9s ]\n", g_parse ? "on" : "off", DEFAULT_PARSE ? "on" : "off");
  404. Log("\n\n");
  405. }
  406. /*
  407. * ============
  408. * main
  409. * ============
  410. */
  411. int main(int argc, char** argv)
  412. {
  413. int i;
  414. double start, end;
  415. g_Program = "ripent";
  416. if (argc == 1)
  417. {
  418. Usage();
  419. }
  420. for (i = 1; i < argc; i++)
  421. {
  422. if (!strcasecmp(argv[i], "-import"))
  423. {
  424. g_mode = hl_import;
  425. }
  426. else if (!strcasecmp(argv[i], "-export"))
  427. {
  428. g_mode = hl_export;
  429. }
  430. // g_parse: command line switch (-parse).
  431. // Added by: Ryan Gregg aka Nem
  432. else if(!strcasecmp(argv[i], "-parse"))
  433. {
  434. g_parse = true;
  435. }
  436. else if (!strcasecmp(argv[i], "-texdata"))
  437. {
  438. if (i < argc)
  439. {
  440. int x = atoi(argv[++i]) * 1024;
  441. if (x > g_max_map_miptex)
  442. {
  443. g_max_map_miptex = x;
  444. }
  445. }
  446. else
  447. {
  448. Usage();
  449. }
  450. }
  451. else if (!strcasecmp(argv[i], "-lightdata"))
  452. {
  453. if (i < argc)
  454. {
  455. int x = atoi(argv[++i]) * 1024;
  456. if (x > g_max_map_lightdata)
  457. {
  458. g_max_map_lightdata = x;
  459. }
  460. }
  461. else
  462. {
  463. Usage();
  464. }
  465. }
  466. else if (!strcasecmp(argv[i], "-chart"))
  467. {
  468. g_chart = true;
  469. }
  470. else if (!strcasecmp(argv[i], "-noinfo"))
  471. {
  472. g_info = false;
  473. }
  474. else
  475. {
  476. safe_strncpy(g_Mapname, argv[i], _MAX_PATH);
  477. StripExtension(g_Mapname);
  478. DefaultExtension(g_Mapname, ".bsp");
  479. }
  480. }
  481. if (g_mode == hl_undefined)
  482. {
  483. fprintf(stderr, "%s", "Must specify either -import or -export\n");
  484. Usage();
  485. }
  486. if (!q_exists(g_Mapname))
  487. {
  488. fprintf(stderr, "%s", "bspfile '%s' does not exist\n", g_Mapname);
  489. Usage();
  490. }
  491. LogStart(argc, argv);
  492. atexit(LogEnd);
  493. Settings();
  494. dtexdata_init();
  495. atexit(dtexdata_free);
  496. // BEGIN RipEnt
  497. start = I_FloatTime();
  498. switch (g_mode)
  499. {
  500. case hl_import:
  501. ReadBSP(g_Mapname);
  502. ReadEntities(g_Mapname);
  503. WriteBSP(g_Mapname);
  504. break;
  505. case hl_export:
  506. ReadBSP(g_Mapname);
  507. WriteEntities(g_Mapname);
  508. break;
  509. }
  510. if (g_chart)
  511. PrintBSPFileSizes();
  512. end = I_FloatTime();
  513. LogTimeElapsed(end - start);
  514. // END RipEnt
  515. return 0;
  516. }
  517. // do nothing - we don't have params to fetch
  518. void GetParamsFromEnt(entity_t* mapent) {}