1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "stdafx.h"
24 #include "cpthelp.h"
25 #include "TextFile.h"
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 uint32 crop(char *line);
31 uint16 findCptId(char *name, TextFile *cptFile);
32
33 #define MAX_CPTS 0xA000
34 #define MAX_OBJ_SIZE (0x2000 * 2)
35 #define NUM_DATA_LISTS 9
36 #define ASCII_SIZE (65536 * 2)
37
38 enum CptType {
39 PTR_NULL = 0,
40 COMPACT,
41 TURNTAB,
42 ANIMSEQ,
43 MISCBIN,
44 GETTOTAB,
45 ROUTEBUF,
46 MAINLIST
47 };
48
processMainLists(FILE * inf,CptObj * destArr,uint16 * idList)49 void processMainLists(FILE *inf, CptObj *destArr, uint16 *idList) {
50 char line[1024];
51 dofgets(line, 1024, inf);
52 assert(lineMatchSection(line, "MAINLISTS"));
53 uint16 *resBuf = (uint16 *)malloc(MAX_OBJ_SIZE);
54 uint32 idNum = 0;
55 do {
56 dofgets(line, 1024, inf);
57 if (!isEndOfSection(line)) {
58 char cptName[50];
59 uint16 id = getInfo(line, "MAINLST", cptName);
60 CptObj *dest = destArr + id;
61 assertEmpty(dest);
62 dest->type = MAINLIST;
63 dest->dbgName = (char *)malloc(strlen(cptName) + 1);
64 strcpy(dest->dbgName, cptName);
65 memset(resBuf, 0, MAX_OBJ_SIZE);
66 uint32 resPos = 0;
67 idList[idNum] = id;
68 idNum++;
69
70 do {
71 dofgets(line, 1024, inf);
72 if (!isEndOfObject(line, "MAINLST", id)) {
73 assert((line[0] == '\t') && (line[1] == '\t'));
74 char *stopCh;
75 uint16 destId = (uint16)strtoul(line + 2, &stopCh, 16);
76 assert(stopCh == (line + 6));
77 assert((stopCh[0] == ':') && (stopCh[1] == ':'));
78 resBuf[resPos] = destId;
79 resPos++;
80 } else
81 break;
82 } while (1);
83 assert(resPos < (MAX_OBJ_SIZE / 2));
84 dest->len = resPos;
85 dest->data = (uint16 *)malloc(resPos * 2);
86 memcpy(dest->data, resBuf, resPos * 2);
87 } else
88 break;
89 } while (1);
90
91 free(resBuf);
92 }
93
processCpts(FILE * inf,CptObj * destArr)94 void processCpts(FILE *inf, CptObj *destArr) {
95 char line[1024];
96 dofgets(line, 1024, inf);
97 assert(lineMatchSection(line, "COMPACTS"));
98 uint16 *resBuf = (uint16 *)malloc(MAX_OBJ_SIZE);
99 do {
100 dofgets(line, 1024, inf);
101 if (!isEndOfSection(line)) {
102 char cptName[50];
103 uint16 id = getInfo(line, "COMPACT", cptName);
104 CptObj *dest = destArr + id;
105 assertEmpty(dest);
106 dest->dbgName = (char *)malloc(strlen(cptName) + 1);
107 dest->type = COMPACT;
108 strcpy(dest->dbgName, cptName);
109 memset(resBuf, 0, MAX_OBJ_SIZE);
110 uint32 resPos = 0;
111
112 do {
113 dofgets(line, 1024, inf);
114 if (!isEndOfObject(line, "COMPACT", id)) {
115 assert((line[0] == '\t') && (line[1] == '\t'));
116 char *stopCh;
117 uint16 destId = (uint16)strtoul(line + 2, &stopCh, 16);
118 assert(stopCh != (line + 2));
119 assert((stopCh[0] == '-') && (stopCh[1] == '>'));
120 if (resPos == 23) { // grafixProg
121 assert(destId == 0);
122 resBuf[resPos] = resBuf[resPos + 1] = 0;
123 resPos += 2;
124 } else if (resPos == 48) { // turnProg. shouldn't it be 49?
125 assert(destId == 0);
126 resBuf[resPos] = resBuf[resPos + 1] = 0;
127 resPos += 2;
128 } else {
129 resBuf[resPos] = destId;
130 resPos++;
131 }
132 } else
133 break;
134 } while (1);
135 assert(resPos < (MAX_OBJ_SIZE / 2));
136 dest->len = resPos;
137 dest->data = (uint16 *)malloc(resPos * 2);
138 memcpy(dest->data, resBuf, resPos * 2);
139 } else
140 break;
141 } while (1);
142
143 free(resBuf);
144 }
145
processTurntabs(FILE * inf,CptObj * destArr)146 void processTurntabs(FILE *inf, CptObj *destArr) {
147 char line[1024];
148 dofgets(line, 1024, inf);
149 assert(lineMatchSection(line, "TURNTABS"));
150 uint16 *resBuf = (uint16 *)malloc(MAX_OBJ_SIZE);
151 do {
152 dofgets(line, 1024, inf);
153 if (!isEndOfSection(line)) {
154 char cptName[50];
155 uint16 id = getInfo(line, "TURNTAB", cptName);
156 CptObj *dest = destArr + id;
157 assertEmpty(dest);
158 dest->dbgName = (char *)malloc(strlen(cptName) + 1);
159 dest->type = TURNTAB;
160 strcpy(dest->dbgName, cptName);
161 memset(resBuf, 0, MAX_OBJ_SIZE);
162 uint32 resPos = 0;
163
164 do {
165 dofgets(line, 1024, inf);
166 if (!isEndOfObject(line, "TURNTAB", id)) {
167 assert((line[0] == '\t') && (line[1] == '\t'));
168 char *stopCh;
169 uint16 destId = (uint16)strtoul(line + 2, &stopCh, 16);
170 assert(stopCh == (line + 6));
171 assert((stopCh[0] == '-') && (stopCh[1] == '>'));
172 resBuf[resPos] = destId;
173 resPos++;
174 } else
175 break;
176 } while (1);
177 assert(resPos < (MAX_OBJ_SIZE / 2));
178 dest->len = resPos;
179 dest->data = (uint16 *)malloc(resPos * 2);
180 memcpy(dest->data, resBuf, resPos * 2);
181 } else
182 break;
183 } while (1);
184
185 free(resBuf);
186 }
187
processBins(FILE * inf,CptObj * destArr,const char * typeName,const char * objName,uint8 cTypeId)188 void processBins(FILE *inf, CptObj *destArr, const char *typeName, const char *objName, uint8 cTypeId) {
189 char line[1024];
190 dofgets(line, 1024, inf);
191 assert(lineMatchSection(line, typeName));
192 uint16 *resBuf = (uint16 *)malloc(MAX_OBJ_SIZE);
193 do {
194 dofgets(line, 1024, inf);
195 if (!isEndOfSection(line)) {
196 char cptName[50];
197 uint16 id = getInfo(line, objName, cptName);
198 CptObj *dest = destArr + id;
199 assertEmpty(dest);
200 dest->dbgName = (char *)malloc(strlen(cptName) + 1);
201 dest->type = cTypeId;
202 strcpy(dest->dbgName, cptName);
203 memset(resBuf, 0, MAX_OBJ_SIZE);
204 uint32 resPos = 0;
205
206 do {
207 dofgets(line, 1024, inf);
208 if (!isEndOfObject(line, objName, id)) {
209 assert((line[0] == '\t') && (line[1] == '\t'));
210 char *stopCh;
211 uint16 destId = (uint16)strtoul(line + 2, &stopCh, 16);
212 assert(stopCh == (line + 6));
213 assert(*stopCh == '\0');
214 resBuf[resPos] = destId;
215 resPos++;
216 } else
217 break;
218 } while (1);
219 assert(resPos < (MAX_OBJ_SIZE / 2));
220 dest->len = resPos;
221 dest->data = (uint16 *)malloc(resPos * 2);
222 memcpy(dest->data, resBuf, resPos * 2);
223 } else
224 break;
225 } while (1);
226
227 free(resBuf);
228 }
229
230 uint16 dlinkCount = 0;
231 static uint16 dlinks[1024];
232 static char* dlinkNames[512];
233
processSymlinks(FILE * inf,CptObj * destArr,uint16 * baseLists)234 void processSymlinks(FILE *inf, CptObj *destArr, uint16 *baseLists) {
235 char line[1024];
236 dofgets(line, 1024, inf);
237 assert(lineMatchSection(line, "SYMLINKS"));
238 do {
239 dofgets(line, 1024, inf);
240 if (!isEndOfSection(line)) {
241 char cptName[50];
242 uint16 fromId = getInfo(line, "SYMLINK", cptName);
243 CptObj *from = destArr + fromId;
244 assertEmpty(from);
245 dlinkNames[dlinkCount] = (char *)malloc(strlen(cptName) + 1);
246 strcpy(dlinkNames[dlinkCount], cptName);
247
248 dofgets(line, 1024, inf);
249 assert((line[0] == '\t') && (line[1] == '\t') && (line[2] == '-') && (line[3] == '>'));
250 char *stopCh;
251 uint16 destId = (uint16)strtoul(line + 4, &stopCh, 16);
252 assert(stopCh == (line + 8));
253 assert((stopCh[0] == ':') && (stopCh[1] == ':'));
254
255 dlinks[dlinkCount * 2 + 0] = fromId;
256 dlinks[dlinkCount * 2 + 1] = destId;
257
258 dlinkCount++;
259
260 dofgets(line, 1024, inf);
261 assert(isEndOfObject(line, "SYMLINK", fromId));
262 } else
263 break;
264 } while (1);
265 }
266
doCompile(FILE * inf,FILE * debOutf,FILE * resOutf,TextFile * cptDef,FILE * sve)267 void doCompile(FILE *inf, FILE *debOutf, FILE *resOutf, TextFile *cptDef, FILE *sve) {
268 uint16 maxStrl = 0;
269 uint16 maxCptl = 0;
270
271 printf("Processing...\n");
272 CptObj *resCpts;
273 uint16 baseLists[NUM_DATA_LISTS];
274 memset(baseLists, 0, NUM_DATA_LISTS * 2);
275 resCpts = (CptObj *)malloc(MAX_CPTS * sizeof(CptObj));
276 memset(resCpts, 0, MAX_CPTS * sizeof(CptObj));
277 printf(" MainLists...\n");
278 processMainLists(inf, resCpts, baseLists);
279 printf(" Compacts...\n");
280 processCpts(inf, resCpts);
281 printf(" Turntables...\n");
282 processTurntabs(inf, resCpts);
283 printf(" Animation tables...\n");
284 processBins(inf, resCpts, "ANIMSEQS", "ANIMSEQ", ANIMSEQ);
285 printf(" Unknown binaries...\n");
286 processBins(inf, resCpts, "MISCBINS", "MISCBIN", MISCBIN);
287 printf(" Get To tables...\n");
288 processBins(inf, resCpts, "GETTOTAB", "GET_TOS", GETTOTAB);
289 printf(" Scratch buffers...\n");
290 processBins(inf, resCpts, "SCRATCHR", "SCRATCH", ROUTEBUF);
291 printf(" Symbolic links...\n");
292 processSymlinks(inf, resCpts, baseLists);
293 printf("Converting to binary data...\n");
294 uint32 numCpts = 1;
295 for (uint32 cnt = 1; cnt < MAX_CPTS; cnt++)
296 if (resCpts[cnt].data || resCpts[cnt].dbgName || resCpts[cnt].len)
297 numCpts++;
298
299 uint16 dataListLen[NUM_DATA_LISTS];
300 for (uint32 cnt = 0; cnt < NUM_DATA_LISTS; cnt++)
301 for (uint16 elemCnt = 0; elemCnt < 0x1000; elemCnt++) {
302 uint32 id = (cnt << 12) | elemCnt;
303 if (resCpts[id].data || resCpts[id].dbgName || resCpts[id].len)
304 dataListLen[cnt] = elemCnt + 1;
305 }
306
307 // write the header
308 uint32 rev = 0;
309 fwrite(&rev, 2, 1, debOutf);
310 fwrite(&rev, 2, 1, resOutf);
311 rev = NUM_DATA_LISTS;
312 fwrite(&rev, 2, 1, debOutf);
313 fwrite(&rev, 2, 1, resOutf);
314 for (uint32 cnt = 0; cnt < NUM_DATA_LISTS; cnt++) {
315 fwrite(dataListLen + cnt, 2, 1, debOutf);
316 fwrite(dataListLen + cnt, 2, 1, resOutf);
317 }
318
319 uint32 binSize = 0;
320 uint32 binDest = ftell(debOutf);
321 fwrite(&binSize, 1, 4, debOutf);
322 fwrite(&binSize, 1, 4, resOutf);
323 fwrite(&binSize, 1, 4, debOutf);
324 fwrite(&binSize, 1, 4, resOutf);
325
326 char *asciiBuf = (char *)malloc(ASCII_SIZE);
327 char *asciiPos = asciiBuf;
328
329 // now process all the compacts
330 uint32 cptSize[2];
331 cptSize[0] = ftell(debOutf);
332 cptSize[1] = ftell(resOutf);
333 for (uint32 lcnt = 0; lcnt < NUM_DATA_LISTS; lcnt++) {
334 for (uint32 eCnt = 0; eCnt < dataListLen[lcnt]; eCnt++) {
335 uint32 cId = (lcnt << 12) | eCnt;
336 CptObj *cpt = resCpts + cId;
337 if (resCpts[cId].data || resCpts[cId].dbgName || resCpts[cId].len || resCpts[cId].type) {
338 strcpy(asciiPos, cpt->dbgName);
339 asciiPos += strlen(cpt->dbgName) + 1;
340
341 assert(cpt->len < 0xFFFF);
342 uint16 dlen = (uint16)cpt->len;
343 if (dlen > maxCptl)
344 maxCptl = dlen;
345 binSize += dlen;
346 assert(dlen != 0);
347
348 fwrite(&dlen, 2, 1, debOutf);
349 fwrite(&dlen, 2, 1, resOutf);
350
351 uint16 field = resCpts[cId].type;
352 fwrite(&field, 2, 1, debOutf);
353
354 fwrite(cpt->data, 2, dlen, debOutf);
355 fwrite(cpt->data, 2, dlen, resOutf);
356 } else {
357 uint16 tmp = 0;
358 fwrite(&tmp, 2, 1, debOutf);
359 fwrite(&tmp, 2, 1, resOutf);
360 }
361 }
362 printf("DEBUG lcnt: %lu Output File Position: 0x%08lX\r\n", lcnt, ftell(debOutf));
363 }
364 cptSize[0] = ftell(debOutf) - cptSize[0];
365 cptSize[1] = ftell(resOutf) - cptSize[1];
366 assert(!(cptSize[0] & 1));
367 assert(!(cptSize[1] & 1));
368 cptSize[0] /= 2;
369 cptSize[1] /= 2;
370
371 for (uint32 cnt = 0; cnt < dlinkCount; cnt++) {
372 strcpy(asciiPos, dlinkNames[cnt]);
373 asciiPos += strlen(dlinkNames[cnt]) + 1;
374 }
375
376 uint32 asciiSize = (uint32)(asciiPos - asciiBuf);
377 fwrite(&asciiSize, 1, 4, debOutf);
378 fwrite(asciiBuf, 1, asciiSize, debOutf);
379 free(asciiBuf);
380
381 // the direct links...
382 fwrite(&dlinkCount, 2, 1, debOutf);
383 fwrite(&dlinkCount, 2, 1, resOutf);
384 for (uint32 cnt = 0; cnt < dlinkCount; cnt++) {
385 fwrite(dlinks + cnt * 2 + 0, 2, 1, debOutf);
386 fwrite(dlinks + cnt * 2 + 0, 2, 1, resOutf);
387
388 fwrite(dlinks + cnt * 2 + 1, 2, 1, debOutf);
389 fwrite(dlinks + cnt * 2 + 1, 2, 1, resOutf);
390 }
391 printf("Processing diff data...\n");
392 printf("DEBUG Output File Position: 0x%08lX\r\n", ftell(debOutf));
393 // 288 diffdata
394 FILE *dif = fopen("288diff.txt", "r");
395 assert(dif);
396 char line[1024];
397 uint16 diff[8192];
398 uint16 diffDest = 0;
399 uint16 diffNo = 0;
400 while (fgets(line, 1024, dif)) {
401 crop(line);
402 if (line[0] != '$') {
403 assert(memcmp(line, "data_", 5) == 0);
404 char *pos = line + 5;
405 char *stopCh;
406 uint16 lId = (uint16)strtoul(pos, &stopCh, 10);
407 assert(*stopCh == '[');
408 uint16 eId = (uint16)strtoul(stopCh + 1, &stopCh, 10);
409 assert((stopCh[0] == ']') && (stopCh[1] == '[') && (eId <= 0xFFF) && (lId <= 7));
410 uint16 id = (lId << 12) | eId;
411 uint16 elemNo = (uint16)strtoul(stopCh + 2, &stopCh, 10);
412 assert(*stopCh == ']');
413 stopCh = strstr(stopCh, "0x") + 2;
414 uint16 val = (uint16)strtoul(stopCh, &stopCh, 16);
415 assert(*stopCh == ';');
416 diff[diffDest++] = id;
417 diff[diffDest++] = elemNo;
418 diff[diffDest++] = 1;
419 diff[diffDest++] = val;
420 diffNo++;
421 } else {
422 char *pos = strchr(line, ' ');
423 *pos = '\0';
424 uint16 id = findCptId(line + 1, cptDef);
425 assert(id);
426 diff[diffDest++] = id;
427 diff[diffDest++] = 0;
428 pos++;
429 uint16 len = (uint16)strtoul(pos, &pos, 10);
430 diff[diffDest++] = len;
431 assert(len);
432 assert(resCpts[id].len == len);
433 for (uint16 cnt = 0; cnt < len; cnt++) {
434 assert(*pos == ' ');
435 pos++;
436 diff[diffDest++] = (uint16)strtoul(pos, &pos, 16);
437 }
438 assert(diff[diffDest - 1] == 0xFFFF);
439 diffNo++;
440 }
441 }
442 fclose(dif);
443 free(resCpts);
444 assert(diffDest <= 8192);
445 fwrite(&diffNo, 1, 2, debOutf);
446 fwrite(&diffDest, 1, 2, debOutf);
447 fwrite(diff, 2, diffDest, debOutf);
448 fwrite(&diffNo, 1, 2, resOutf);
449 fwrite(&diffDest, 1, 2, resOutf);
450 fwrite(diff, 2, diffDest, resOutf);
451
452 printf("Converting Save data...\n");
453 printf("DEBUG Output File Position: 0x%08lX\r\n", ftell(debOutf));
454 // the IDs of the compacts to be saved
455 char cptName[1024];
456 uint16 saveIds[2048];
457 uint16 numIds = 0;
458 while (fgets(cptName, 1024, sve)) {
459 crop(cptName);
460 uint16 resId = findCptId(cptName, cptDef);
461 if (!resId)
462 printf("ERROR: Can't find definition of %s\n", cptName);
463 else {
464 saveIds[numIds] = resId;
465 numIds++;
466 }
467 }
468 printf("%d saveIds\n", numIds);
469 fwrite(&numIds, 2, 1, debOutf);
470 fwrite(saveIds, 2, numIds, debOutf);
471 fwrite(&numIds, 2, 1, resOutf);
472 fwrite(saveIds, 2, numIds, resOutf);
473
474 printf("Converting Reset data...\n");
475 // now append the reset data
476 uint16 gameVers[7] = { 303, 331, 348, 365, 368, 372, 288 };
477 // make sure all files exist
478 bool filesExist = true;
479 char inName[32];
480 for (int i = 0; i < 7; i++) {
481 sprintf(inName, "RESET.%03d", gameVers[i]);
482 FILE *test = fopen(inName, "rb");
483 if (test)
484 fclose(test);
485 else {
486 filesExist = false;
487 printf("File %s not found\n", inName);
488 }
489 }
490
491 if (filesExist) {
492 FILE *res288 = fopen("RESET.288", "rb");
493 fseek(res288, 0, SEEK_END);
494 assert((ftell(res288) / 2) < 65536);
495 uint16 resSize = (uint16)(ftell(res288) / 2);
496 fseek(res288, 0, SEEK_SET);
497 uint16 *buf288 = (uint16 *)malloc(resSize * 2);
498 fread(buf288, 2, resSize, res288);
499 fclose(res288);
500 fwrite(&resSize, 1, 2, debOutf);
501 fwrite(buf288, 2, resSize, debOutf);
502
503 uint16 tmp = 7;
504 fwrite(&tmp, 2, 1, debOutf);
505 tmp = 288;
506 fwrite(&tmp, 2, 1, debOutf);
507 tmp = 0;
508 fwrite(&tmp, 2, 1, debOutf);
509
510 printf("DEBUG Output File Position: 0x%08lX\r\n", ftell(debOutf));
511 printf("reset destination: %ld\n", ftell(debOutf));
512 for (int cnt = 0; cnt < 6; cnt++) {
513 printf("Processing diff v0.0%03d\n", gameVers[cnt]);
514 uint16 diffPos = 0;
515 sprintf(inName, "RESET.%03d", gameVers[cnt]);
516 FILE *resDiff = fopen(inName, "rb");
517 fseek(resDiff, 0, SEEK_END);
518 assert(ftell(resDiff) == (resSize * 2));
519 fseek(resDiff, 0, SEEK_SET);
520 uint16 *bufDif = (uint16 *)malloc(resSize *2);
521 fread(bufDif, 2, resSize, resDiff);
522 fclose(resDiff);
523 for (uint16 eCnt = 0; eCnt < resSize; eCnt++)
524 if (buf288[eCnt] != bufDif[eCnt]) {
525 diff[diffPos++] = eCnt;
526 diff[diffPos++] = bufDif[eCnt];
527 }
528 free(bufDif);
529 fwrite(gameVers + cnt, 1, 2, debOutf);
530 assert(!(diffPos & 1));
531 diffPos /= 2;
532 fwrite(&diffPos, 1, 2, debOutf);
533 fwrite(diff, 2, 2 * diffPos, debOutf);
534 printf("diff v0.0%03d: 2 * 2 * %d\n", gameVers[cnt], diffPos);
535 printf("DEBUG Output File Position: 0x%08lX\r\n", ftell(debOutf));
536 }
537 free(buf288);
538 } else {
539 printf("Creating CPT file with Dummy reset data @ %ld\n", ftell(debOutf));
540 uint16 resetFields16 = 4;
541 fwrite(&resetFields16, 2, 1, debOutf);
542 uint32 blah = 8;
543 fwrite(&blah, 4, 1, debOutf); // size field: 8 bytes
544 blah = (uint32)-1;
545 fwrite(&blah, 4, 1, debOutf); // save file revision. -1 is unknown to scummvm, so it'll refuse to load it.
546 resetFields16 = 0;
547 fwrite(&resetFields16, 2, 1, debOutf); // numDiffs: 0, no further reset blocks.
548 }
549
550 // now fill the raw-compact-data-size header field
551 fseek(resOutf, binDest, SEEK_SET);
552 fseek(debOutf, binDest, SEEK_SET);
553 fwrite(&binSize, 1, 4, debOutf);
554 fwrite(&binSize, 1, 4, resOutf);
555 fwrite(cptSize + 0, 1, 4, debOutf);
556 fwrite(cptSize + 1, 1, 4, resOutf);
557
558 printf("%d diffs\n", diffNo);
559 printf("%ld Compacts in total\n", numCpts);
560 printf("max strlen = %d\n", maxStrl);
561 printf("raw size = 2 * %ld\n", binSize);
562 printf("max cptlen = %d\n", maxCptl);
563 }
564