README: remove TODO item
[rofl0r-agsutils.git] / RoomFile.c
blob3e74ca7e1fd2a5888d485ff860694df0ba590cb6
1 #include "RoomFile.h"
2 #include <stdlib.h>
4 ssize_t ARF_find_code_start(AF* f, size_t start) {
5 if(!AF_set_pos(f, start)) return -1;
6 char buf[4];
7 unsigned match = 0;
8 while(1) {
9 if(AF_read(f, buf, 1) != 1) break;;
10 switch(match) {
11 case 0:
12 if(*buf == 'S') match++;
13 else match = 0;
14 break;
15 case 1:
16 if(*buf == 'C') match++;
17 else match = 0;
18 break;
19 case 2:
20 if(*buf == 'O') match++;
21 else match = 0;
22 break;
23 case 3:
24 if(*buf == 'M') return AF_get_pos(f) - 4;
25 else match = 0;
26 break;
27 default:
28 assert(0);
31 return -1;
34 enum BlockType {
35 BLOCKTYPE_MAIN = 1,
36 BLOCKTYPE_SCRIPT = 2,
37 BLOCKTYPE_COMPSCRIPT = 3,
38 BLOCKTYPE_COMPSCRIPT2 = 4,
39 BLOCKTYPE_OBJECTNAMES = 5,
40 BLOCKTYPE_ANIMBKGRND = 6,
41 BLOCKTYPE_COMPSCRIPT3 = 7, /* only bytecode script type supported by released engine code */
42 BLOCKTYPE_PROPERTIES = 8,
43 BLOCKTYPE_OBJECTSCRIPTNAMES = 9,
44 BLOCKTYPE_EOF = 0xFF
47 static void roomfile_decrypt_text(char *s, int len) {
48 unsigned i = 0;
49 while (i < len) {
50 *s += "Avis Durgan"[i % 11];
51 if (!*s) break;
52 ++i; ++s;
57 int RoomFile_read(AF *f, struct RoomFile *r, int flags) {
58 if(!AF_set_pos(f, 0)) return 0;
59 r->version = AF_read_short(f);
60 while(1) {
61 unsigned char blocktype;
62 if((size_t) -1 == AF_read(f, &blocktype, 1)) return 0;
63 if(blocktype == BLOCKTYPE_EOF) break;
64 int blocklen = AF_read_int(f);
65 off_t curr_pos = AF_get_pos(f), next_block = curr_pos + blocklen;
66 switch(blocktype) {
67 case BLOCKTYPE_SCRIPT:
68 if(flags & RF_FLAGS_EXTRACT_CODE) {
69 int scriptlen = AF_read_int(f);
70 r->sourcecode = malloc(scriptlen+1);
71 if((size_t) -1 == AF_read(f, r->sourcecode, scriptlen)) return 0;
72 roomfile_decrypt_text(r->sourcecode, scriptlen);
73 r->sourcecode[scriptlen] = 0;
74 r->sourcecode_len = scriptlen;
76 break;
77 case BLOCKTYPE_COMPSCRIPT3:
79 char sig[4];
80 AF_read(f, sig, 4);
81 assert(!memcmp(sig, "SCOM", 4));
82 r->scriptpos = curr_pos;
84 break;
85 /* the older script types weren't supported by the released AGS sources ever */
86 default:
87 break;
89 if(!AF_set_pos(f, next_block)) return 0;
91 return 1;