loadsave.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. //
  19. // loadsave.cpp
  20. //
  21. #include "stdAfx.h"
  22. #include "iff.h"
  23. #include "TransDB.h"
  24. #include "noxstringdlg.h"
  25. #define FORM_NOXDB MakeID ('N','X','D','B')
  26. #define FORM_LABEL MakeID ('N','L','B','L')
  27. #define FORM_TEXT MakeID ('N','T','X','T')
  28. #define FORM_TRANS MakeID ('N','T','R','N')
  29. #define CHUNK_COMMENT MakeID ('C','M','N','T')
  30. #define CHUNK_CONTEXT MakeID ('C','T','X','T')
  31. #define CHUNK_SPEAKER MakeID ('S','P','K','R')
  32. #define CHUNK_LISTENER MakeID ('L','T','N','R')
  33. #define CHUNK_TEXT MakeID ('T','E','X','T')
  34. #define CHUNK_WAVE MakeID ('W','A','V','E')
  35. #define CHUNK_WAVE_INFO MakeID ('W','V','I','N')
  36. #define CHUNK_INFO MakeID ('I','N','F','O')
  37. #define CHUNK_NAME MakeID ('N','A','M','E')
  38. #define MAX_BUFFER (100*1024)
  39. static OLECHAR buffer[MAX_BUFFER];
  40. typedef struct
  41. {
  42. int num_labels;
  43. int next_id;
  44. } DBINFO;
  45. typedef struct
  46. {
  47. int max_len;
  48. } LBINFO;
  49. typedef struct
  50. {
  51. int id;
  52. int revision;
  53. } TXINFO;
  54. typedef struct
  55. {
  56. LangID lang;
  57. int revision;
  58. } TRINFO;
  59. typedef struct
  60. {
  61. int valid;
  62. DWORD lo;
  63. DWORD hi;
  64. } WVINFO;
  65. static int writeString ( IFF_FILE *iff, OLECHAR *string, int chunk_id )
  66. {
  67. int len = (wcslen ( string ) );
  68. int bytes = (len+1)*sizeof(OLECHAR);
  69. if ( len )
  70. {
  71. IFF_NEWCHUNK ( iff, chunk_id, error );
  72. IFF_WRITE ( iff, string, bytes, error);
  73. IFF_CloseChunk ( iff );
  74. }
  75. return TRUE;
  76. error:
  77. return FALSE;
  78. }
  79. static int readString ( IFF_FILE *iff, OLECHAR *string )
  80. {
  81. *string = 0;
  82. IFF_READ ( iff, string, iff->ChunkSize, error);
  83. return TRUE;
  84. error:
  85. return FALSE;
  86. }
  87. static int writeTransForm ( IFF_FILE *iff, Translation *trans )
  88. {
  89. TRINFO trinfo;
  90. WVINFO wvinfo;
  91. if ( !IFF_NewForm ( iff, FORM_TRANS ))
  92. {
  93. goto error;
  94. }
  95. trinfo.lang = trans->GetLangID ();
  96. trinfo.revision = trans->Revision ();
  97. if ( !IFF_NewChunk ( iff, CHUNK_INFO ))
  98. {
  99. goto error;
  100. }
  101. IFF_Write ( iff, &trinfo, sizeof ( trinfo ));
  102. IFF_CloseChunk ( iff );
  103. writeString ( iff, trans->Get (), CHUNK_TEXT );
  104. writeString ( iff, trans->Comment (), CHUNK_COMMENT );
  105. if ( (wvinfo.valid = trans->WaveInfo.Valid()) )
  106. {
  107. wvinfo.lo = trans->WaveInfo.Lo ();
  108. wvinfo.hi = trans->WaveInfo.Hi ();
  109. if ( !IFF_NewChunk ( iff, CHUNK_WAVE_INFO ))
  110. {
  111. goto error;
  112. }
  113. IFF_Write ( iff, &wvinfo, sizeof ( wvinfo ));
  114. IFF_CloseChunk ( iff );
  115. }
  116. IFF_CloseForm ( iff );
  117. return TRUE;
  118. error:
  119. return FALSE;
  120. }
  121. static int writeTextForm ( IFF_FILE *iff, NoxText *text )
  122. {
  123. TXINFO txinfo;
  124. WVINFO wvinfo;
  125. if ( !IFF_NewForm ( iff, FORM_TEXT ))
  126. {
  127. goto error;
  128. }
  129. txinfo.id = text->ID ();
  130. txinfo.revision = text->Revision ();
  131. if ( !IFF_NewChunk ( iff, CHUNK_INFO ))
  132. {
  133. goto error;
  134. }
  135. IFF_Write ( iff, &txinfo, sizeof ( txinfo ));
  136. IFF_CloseChunk ( iff );
  137. writeString ( iff, text->Get (), CHUNK_TEXT );
  138. writeString ( iff, text->Wave (), CHUNK_WAVE );
  139. if ( (wvinfo.valid = text->WaveInfo.Valid()) )
  140. {
  141. wvinfo.lo = text->WaveInfo.Lo ();
  142. wvinfo.hi = text->WaveInfo.Hi ();
  143. if ( !IFF_NewChunk ( iff, CHUNK_WAVE_INFO ))
  144. {
  145. goto error;
  146. }
  147. IFF_Write ( iff, &wvinfo, sizeof ( wvinfo ));
  148. IFF_CloseChunk ( iff );
  149. }
  150. IFF_CloseForm ( iff );
  151. return TRUE;
  152. error:
  153. return FALSE;
  154. }
  155. int WriteMainDB(TransDB *db, const char *filename, CNoxstringDlg *dlg )
  156. {
  157. NoxText *text;
  158. NoxLabel *label;
  159. ListSearch sh_label;
  160. ListSearch sh_text;
  161. int count = 0;
  162. IFF_FILE *iff = NULL;
  163. DBINFO dbinfo;
  164. int ok = FALSE;
  165. if ( dlg )
  166. {
  167. dlg->InitProgress ( db->NumLabels ());
  168. }
  169. if ( !( iff = IFF_New ( filename )))
  170. {
  171. goto error;
  172. }
  173. if ( !IFF_NewForm ( iff, FORM_NOXDB ) )
  174. {
  175. goto error;
  176. }
  177. dbinfo.next_id = db->ID ();
  178. dbinfo.num_labels = db->NumLabels ();
  179. if ( !IFF_NewChunk ( iff, CHUNK_INFO ))
  180. {
  181. goto error;
  182. }
  183. IFF_Write ( iff, &dbinfo, sizeof ( dbinfo ));
  184. IFF_CloseChunk ( iff );
  185. IFF_CloseForm ( iff );
  186. text = db->FirstObsolete ( sh_text );
  187. while ( text )
  188. {
  189. if ( !writeTextForm ( iff, text ) )
  190. {
  191. goto error;
  192. }
  193. text = db->NextObsolete ( sh_text );
  194. }
  195. label = db->FirstLabel ( sh_label );
  196. while ( label )
  197. {
  198. LBINFO lbinfo;
  199. if ( !IFF_NewForm ( iff, FORM_LABEL ))
  200. {
  201. goto error;
  202. }
  203. lbinfo.max_len = label->MaxLen ();
  204. if ( !IFF_NewChunk ( iff, CHUNK_INFO ))
  205. {
  206. goto error;
  207. }
  208. IFF_Write ( iff, &lbinfo, sizeof ( lbinfo ));
  209. IFF_CloseChunk ( iff );
  210. writeString ( iff, label->Name (), CHUNK_NAME );
  211. writeString ( iff, label->Comment (), CHUNK_COMMENT );
  212. writeString ( iff, label->Context (), CHUNK_CONTEXT );
  213. writeString ( iff, label->Speaker (), CHUNK_SPEAKER );
  214. writeString ( iff, label->Listener (), CHUNK_LISTENER );
  215. IFF_CloseForm ( iff );
  216. text = label->FirstText ( sh_text );
  217. while ( text )
  218. {
  219. Translation *trans;
  220. ListSearch sh_trans;
  221. if ( !writeTextForm ( iff, text ) )
  222. {
  223. goto error;
  224. }
  225. trans = text->FirstTranslation ( sh_trans );
  226. while ( trans )
  227. {
  228. if ( !writeTransForm ( iff, trans ) )
  229. {
  230. goto error;
  231. }
  232. trans = text->NextTranslation ( sh_trans );
  233. }
  234. text = label->NextText ( sh_text );
  235. }
  236. count++;
  237. if ( dlg )
  238. {
  239. dlg->SetProgress ( count );
  240. }
  241. label = db->NextLabel ( sh_label );
  242. }
  243. ok = TRUE;
  244. db->ClearChanges ();
  245. error:
  246. if ( iff )
  247. {
  248. IFF_Close ( iff );
  249. }
  250. return ok;
  251. }
  252. int LoadMainDB(TransDB *db, const char *filename, void (*cb) (void) )
  253. {
  254. NoxLabel *label = NULL;
  255. NoxText *text = NULL;
  256. Translation *trans = NULL;
  257. int count = 0;
  258. IFF_FILE *iff = NULL;
  259. DBINFO dbinfo;
  260. int ok = FALSE;
  261. if ( !(iff = IFF_Load ( filename ) ) )
  262. {
  263. goto error;
  264. }
  265. if ( !IFF_NextForm ( iff ) || iff->FormID != FORM_NOXDB )
  266. {
  267. goto error;
  268. }
  269. dbinfo.next_id = -1;
  270. dbinfo.num_labels = 0;
  271. while ( IFF_NextChunk ( iff ))
  272. {
  273. switch (iff->ChunkID )
  274. {
  275. case CHUNK_INFO:
  276. IFF_READ ( iff, &dbinfo, sizeof ( dbinfo ), error );
  277. break;
  278. }
  279. }
  280. db->SetID ( dbinfo.next_id );
  281. while ( IFF_NextForm ( iff ) )
  282. {
  283. switch ( iff->FormID )
  284. {
  285. case FORM_LABEL:
  286. {
  287. LBINFO lbinfo;
  288. // new label
  289. if ( text )
  290. {
  291. if ( label )
  292. {
  293. label->AddText ( text );
  294. }
  295. else
  296. {
  297. db->AddObsolete ( text );
  298. }
  299. text = NULL;
  300. }
  301. if ( label )
  302. {
  303. count++;
  304. db->AddLabel ( label );
  305. label = NULL;
  306. if ( cb )
  307. {
  308. cb ();
  309. }
  310. }
  311. if ( ! (label = new NoxLabel ()))
  312. {
  313. goto error;
  314. }
  315. while ( IFF_NextChunk ( iff ))
  316. {
  317. switch ( iff->ChunkID )
  318. {
  319. case CHUNK_INFO:
  320. IFF_READ ( iff, &lbinfo, sizeof (lbinfo), error );
  321. label->SetMaxLen ( lbinfo.max_len );
  322. break;
  323. case CHUNK_COMMENT:
  324. readString ( iff, buffer );
  325. label->SetComment ( buffer );
  326. break;
  327. case CHUNK_CONTEXT:
  328. readString ( iff, buffer );
  329. label->SetContext ( buffer );
  330. break;
  331. case CHUNK_SPEAKER:
  332. readString ( iff, buffer );
  333. label->SetSpeaker ( buffer );
  334. break;
  335. case CHUNK_LISTENER:
  336. readString ( iff, buffer );
  337. label->SetListener ( buffer );
  338. break;
  339. case CHUNK_NAME:
  340. readString ( iff, buffer );
  341. label->SetName ( buffer );
  342. break;
  343. }
  344. }
  345. break;
  346. }
  347. case FORM_TEXT:
  348. {
  349. TXINFO txinfo;
  350. if ( text )
  351. {
  352. if ( label )
  353. {
  354. label->AddText ( text );
  355. }
  356. else
  357. {
  358. db->AddObsolete ( text );
  359. }
  360. text = NULL;
  361. }
  362. if ( ! (text = new NoxText ()))
  363. {
  364. goto error;
  365. }
  366. while ( IFF_NextChunk ( iff ))
  367. {
  368. switch ( iff->ChunkID )
  369. {
  370. case CHUNK_INFO:
  371. IFF_READ ( iff, &txinfo, sizeof (txinfo), error );
  372. text->SetID ( txinfo.id );
  373. text->SetRevision ( txinfo.revision );
  374. break;
  375. case CHUNK_TEXT:
  376. readString ( iff, buffer );
  377. text->Set ( buffer );
  378. break;
  379. case CHUNK_WAVE:
  380. readString ( iff, buffer );
  381. text->SetWave ( buffer );
  382. break;
  383. case CHUNK_WAVE_INFO:
  384. {
  385. WVINFO wvinfo;
  386. IFF_READ ( iff, &wvinfo, sizeof (wvinfo), error );
  387. text->WaveInfo.SetValid ( wvinfo.valid );
  388. text->WaveInfo.SetLo ( wvinfo.lo );
  389. text->WaveInfo.SetHi ( wvinfo.hi );
  390. break;
  391. }
  392. }
  393. }
  394. break;
  395. }
  396. case FORM_TRANS:
  397. {
  398. TRINFO trinfo;
  399. if ( ! (trans = new Translation ()))
  400. {
  401. goto error;
  402. }
  403. while ( IFF_NextChunk ( iff ))
  404. {
  405. switch ( iff->ChunkID )
  406. {
  407. case CHUNK_INFO:
  408. IFF_READ ( iff, &trinfo, sizeof (trinfo), error );
  409. trans->SetLangID ( trinfo.lang );
  410. trans->SetRevision ( trinfo.revision );
  411. break;
  412. case CHUNK_TEXT:
  413. readString ( iff, buffer );
  414. trans->Set ( buffer );
  415. break;
  416. case CHUNK_COMMENT:
  417. readString ( iff, buffer );
  418. trans->SetComment ( buffer );
  419. break;
  420. case CHUNK_WAVE_INFO:
  421. {
  422. WVINFO wvinfo;
  423. IFF_READ ( iff, &wvinfo, sizeof (wvinfo), error );
  424. trans->WaveInfo.SetValid ( wvinfo.valid );
  425. trans->WaveInfo.SetLo ( wvinfo.lo );
  426. trans->WaveInfo.SetHi ( wvinfo.hi );
  427. }
  428. break;
  429. }
  430. }
  431. if ( text )
  432. {
  433. text->AddTranslation ( trans );
  434. }
  435. else
  436. {
  437. delete trans;
  438. }
  439. trans = NULL;
  440. break;
  441. }
  442. }
  443. }
  444. if ( text )
  445. {
  446. if ( label )
  447. {
  448. label->AddText ( text );
  449. }
  450. else
  451. {
  452. db->AddObsolete ( text );
  453. }
  454. text = NULL;
  455. }
  456. if ( label )
  457. {
  458. count++;
  459. db->AddLabel ( label );
  460. label = NULL;
  461. if ( cb )
  462. {
  463. cb ();
  464. }
  465. }
  466. ok = TRUE;
  467. error:
  468. if ( label )
  469. {
  470. delete label;
  471. }
  472. if ( text )
  473. {
  474. delete text;
  475. }
  476. if ( trans )
  477. {
  478. delete trans;
  479. }
  480. if ( iff )
  481. {
  482. IFF_Close ( iff );
  483. }
  484. db->ClearChanges ();
  485. if ( !ok )
  486. {
  487. db->Clear ();
  488. }
  489. return ok;
  490. }
  491. int GetLabelCountDB ( char *filename )
  492. {
  493. IFF_FILE *iff = NULL;
  494. DBINFO dbinfo;
  495. int count = 0;
  496. if ( !(iff = IFF_Open ( filename ) ) )
  497. {
  498. goto error;
  499. }
  500. if ( !IFF_NextForm ( iff ) || iff->FormID != FORM_NOXDB )
  501. {
  502. goto error;
  503. }
  504. dbinfo.next_id = -1;
  505. dbinfo.num_labels = 0;
  506. while ( IFF_NextChunk ( iff ))
  507. {
  508. switch (iff->ChunkID )
  509. {
  510. case CHUNK_INFO:
  511. IFF_READ ( iff, &dbinfo, sizeof ( dbinfo ), error );
  512. break;
  513. }
  514. }
  515. count = dbinfo.num_labels;
  516. error:
  517. if ( iff )
  518. {
  519. IFF_Close ( iff );
  520. }
  521. return count;
  522. }