Ticket #8358: descumm-lib.cpp

File descumm-lib.cpp, 6.4 KB (added by SF/florob, 20 years ago)
Line 
1/* DeScumm - Scumm Script Disassembler
2 * Copyright (C) 2001 Ludvig Strigeus
3 * Copyright (C) 2002-2004 The ScummVM Team
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (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, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 *
19 * $Header: /cvsroot/scummvm/tools/descumm-tool.cpp,v 1.9 2004/10/01 18:16:41 fingolfin Exp $
20 *
21 */
22
23#include "descumm.h"
24
25int (*pt2Print)(const char *format, ...);
26
27int skipVerbHeader_V12(byte *p)
28{
29 byte code;
30 int offset = 15;
31 int minOffset = 255;
32 p += offset;
33
34 pt2Print("Events:\n");
35
36 while ((code = *p++) != 0) {
37 offset = *p++;
38 pt2Print(" %2X - %.4X\n", code, offset);
39 if (minOffset > offset)
40 minOffset = offset;
41 }
42 return minOffset;
43}
44
45int skipVerbHeader_V34(byte *p)
46{
47 byte code;
48 int offset = GF_UNBLOCKED ? 17 : 19;
49 int minOffset = 255;
50 p += offset;
51
52 pt2Print("Events:\n");
53
54 while ((code = *p++) != 0) {
55 offset = TO_LE_16(*(uint16 *)p);
56 p += 2;
57 pt2Print(" %2X - %.4X\n", code, offset);
58 if (minOffset > offset)
59 minOffset = offset;
60 }
61 return minOffset;
62}
63
64int skipVerbHeader_V567(byte *p)
65{
66 byte code;
67 int offset = 8;
68 int minOffset = 255;
69 p += offset;
70
71 pt2Print("Events:\n");
72
73 while ((code = *p++) != 0) {
74 offset = TO_LE_16(*(uint16 *)p);
75 p += 2;
76 pt2Print(" %2X - %.4X\n", code, offset);
77 if (minOffset > offset)
78 minOffset = offset;
79 }
80 return minOffset;
81}
82
83int skipVerbHeader_V8(byte *p)
84{
85 uint32 *ptr;
86 uint32 code;
87 int offset;
88 int minOffset = 255;
89
90 ptr = (uint32 *)p;
91 while ((code = TO_LE_32(*ptr++)) != 0) {
92 offset = TO_LE_32(*ptr++);
93 pt2Print(" %2d - %.4X\n", code, offset);
94 if (minOffset > offset)
95 minOffset = offset;
96 }
97 return minOffset;
98}
99
100
101/*
102This function will parse the given memory buffer.
103Return values:
1040 = success
1051 = scriptVersion out of bound
1062 = ScriptType unknown
107*/
108int descummScript(byte *mem, int len, int scriptVersion, int (*pt2OutFunc)(const char *format, ...))
109{
110 byte *memorg;
111 char *buf;
112 int len;
113
114 memorg = mem;
115 pt2Print = pt2OutFunc;
116 size_of_code = len;
117
118 if (scriptVersion <= 0 || scriptVersion >= 8)
119 return 1;
120
121 switch (scriptVersion) {
122 case 1:
123 case 2:
124 GF_UNBLOCKED = true;
125 g_jump_opcode = 0x18;
126 break;
127
128 case 3:
129 case 4:
130 case 5:
131 g_jump_opcode = 0x18;
132 break;
133
134 case 6:
135 case 7:
136 g_jump_opcode = 0x73;
137 break;
138
139 case 8:
140 g_jump_opcode = 0x66;
141 break;
142 }
143
144 buf = (char *)malloc(8192);
145
146 offs_of_line = 0;
147
148 if (GF_UNBLOCKED) {
149 if (size_of_code < 4) {
150 pt2Print("File too small to be a script\n");
151 return 2;
152 }
153 // Hack to detect verb script: first 4 bytes should be file length
154 if (TO_LE_32(*((uint32 *)mem)) == size_of_code) {
155 if (scriptVersion <= 2)
156 offs_of_line = skipVerbHeader_V12(mem);
157 else
158 offs_of_line = skipVerbHeader_V34(mem );
159 } else {
160 mem += 4;
161 }
162 } else if (scriptVersion >= 5) {
163 if (size_of_code < (scriptVersion == 5 ? 8 : 10)) {
164 pt2Print("File too small to be a script\n");
165 return 2;
166 }
167
168 switch (TO_BE_32(*((uint32 *)mem))) {
169 case 'LSC2':
170 pt2Print("Script# %d\n", TO_LE_32(*((int32 *)(mem+8))));
171 mem += 12;
172 break; /* Local script */
173 case 'LSCR':
174 if (scriptVersion == 8) {
175 pt2Print("Script# %d\n", TO_LE_32(*((int32 *)(mem+8))));
176 mem += 12;
177 } else if (scriptVersion == 7) {
178 pt2Print("Script# %d\n", TO_LE_16(*((int16 *)(mem+8))));
179 mem += 10;
180 } else {
181 pt2Print("Script# %d\n", (byte)mem[8]);
182 mem += 9;
183 }
184 break; /* Local script */
185 case 'SCRP':
186 mem += 8;
187 break; /* Script */
188 case 'ENCD':
189 mem += 8;
190 break; /* Entry code */
191 case 'EXCD':
192 mem += 8;
193 break; /* Exit code */
194 case 'VERB':
195 if (scriptVersion == 8) {
196 mem += 8;
197 offs_of_line = skipVerbHeader_V8(mem);
198 } else
199 offs_of_line = skipVerbHeader_V567(mem);
200 break; /* Verb */
201 default:
202 pt2Print("Unknown script type!\n");
203 return 3;
204 }
205 } else {
206 if (size_of_code < 6) {
207 pt2Print("File too small to be a script\n");
208 return 2;
209 }
210 switch (TO_LE_16(*((uint16 *)mem + 2))) {
211 case MKID('LS'):
212 pt2Print("Script# %d\n", (byte)mem[6]);
213 mem += 7;
214 break; /* Local script */
215 case MKID('SC'):
216 mem += 6;
217 break; /* Script */
218 case MKID('EN'):
219 mem += 6;
220 break; /* Entry code */
221 case MKID('EX'):
222 mem += 6;
223 break; /* Exit code */
224 case MKID('OC'):
225 offs_of_line = skipVerbHeader_V34(mem);
226 break; /* Verb */
227 default:
228 pt2Print("Unknown script type!\n");
229 return 3;
230 }
231 }
232
233 org_pos = mem;
234 cur_pos = org_pos + offs_of_line;
235 len -= mem - memorg;
236
237 while (cur_pos < mem + len) {
238 byte opcode = *cur_pos;
239 int j = num_block_stack;
240 buf[0] = 0;
241 switch (scriptVersion) {
242 case 1:
243 case 2:
244 next_line_V12(buf);
245 break;
246 case 3:
247 case 4:
248 case 5:
249 next_line_V345(buf);
250 break;
251 case 6:
252 if (heVersion)
253 next_line_HE_V72(buf);
254 else
255 next_line_V67(buf);
256 break;
257 case 7:
258 next_line_V67(buf);
259 break;
260 case 8:
261 next_line_V8(buf);
262 break;
263 }
264 if (buf[0]) {
265 writePendingElse();
266 if (haveElse) {
267 haveElse = false;
268 j--;
269 }
270 outputLine(buf, offs_of_line, opcode, j);
271 offs_of_line = get_curoffs();
272 }
273 while (indentBlock(get_curoffs())) {
274 outputLine("}", offs_of_line, -1, -1);
275 offs_of_line = get_curoffs();
276 }
277 fflush(stdout);
278 }
279
280 pt2Print("END\n");
281
282/*
283 if (scriptVersion >= 6 && num_stack != 0) {
284 pt2Print("Stack count: %d\n", num_stack);
285 if (num_stack > 0) {
286 pt2Print("Stack contents:\n");
287 while (num_stack) {
288 buf[0] = 0;
289 se_astext(pop(), buf);
290 pt2Print("%s\n", buf);
291 }
292 }
293 }
294*/
295 free(memorg);
296
297 return 0;
298}