1 /* ScummVM Tools
2 *
3 * ScummVM Tools is the legal property of its developers, whose
4 * names are too numerous to list here. Please refer to the
5 * COPYRIGHT 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 /* GobEngine Script disassembler */
23
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <string.h>
27 #include <stdio.h>
28
29 #include "degob_script.h"
30 #include "common/endian.h"
31 #include "common/util.h"
32
ExtTable(byte * data,uint32 size,byte * dataCom,uint32 sizeCom)33 ExtTable::ExtTable(byte *data, uint32 size, byte *dataCom, uint32 sizeCom) :
34 _data(data), _size(size), _dataCom(dataCom), _sizeCom(sizeCom) {
35
36 assert(data && (size >= 3));
37
38 init();
39 }
40
~ExtTable()41 ExtTable::~ExtTable() {
42 delete[] _items;
43 }
44
init()45 void ExtTable::init() {
46 byte *data = _data;
47
48 _itemsCount = READ_LE_UINT16(data);
49 _items = _itemsCount ? new Item[_itemsCount] : 0;
50 data += 3;
51
52 assert(_size >= (uint32) (3 + _itemsCount * 10));
53
54 for (uint16 i = 0; i < _itemsCount; i++, data += 10) {
55 _items[i].offset = READ_LE_UINT32(data);
56 _items[i].size = READ_LE_UINT16(data + 4);
57 _items[i].width = READ_LE_UINT16(data + 6);
58 _items[i].height = READ_LE_UINT16(data + 8);
59 _items[i].isPacked = (_items[i].width & 0x8000) != 0;
60
61 _items[i].width &= 0x7FFF;
62
63 if (_items[i].width & 0x4000)
64 _items[i].size += 1 << 16;
65 if (_items[i].width & 0x2000)
66 _items[i].size += 2 << 16;
67 if (_items[i].width & 0x1000)
68 _items[i].size += 4 << 16;
69 if (_items[i].height == 0)
70 _items[i].size += _items[i].width << 16;
71
72 _items[i].width &= 0xFFF;
73 }
74 }
75
getItem(uint16 i,uint32 & size) const76 byte *ExtTable::getItem(uint16 i, uint32 &size) const {
77 assert(i < _itemsCount);
78
79 Item &item = _items[i];
80 int32 offset = item.offset;
81 byte *data, *dataBuf;
82
83 if (offset < 0) {
84 offset = -(offset + 1);
85
86 if (!_dataCom)
87 error("commun.exN needed");
88
89 assert(((uint32) offset) < _sizeCom);
90
91 data = _dataCom;
92 } else {
93 assert(((uint32) offset) < _size);
94
95 data = _data + (3 + _itemsCount * 10);
96 }
97
98 size = item.size;
99
100 if (item.isPacked)
101 dataBuf = new byte[size + 2];
102 else
103 dataBuf = new byte[size];
104
105 memcpy(dataBuf, data + offset, size);
106
107 if (item.isPacked) {
108 byte *packedBuf = dataBuf;
109 dataBuf = unpack(packedBuf, size);
110 delete[] packedBuf;
111 }
112
113 return dataBuf;
114 }
115
116 // Some LZ77-variant
unpack(const byte * packedData,uint32 & size) const117 byte *ExtTable::unpack(const byte *packedData, uint32 &size) const {
118 byte *dataBuf, *tmpBuf, *dest;
119 uint32 counter;
120 uint16 tmpIndex;
121 uint16 cmd;
122 int16 off;
123 byte len;
124
125 counter = size = READ_LE_UINT32(packedData);
126 dataBuf = new byte[size];
127
128 tmpBuf = new byte[4114];
129
130 for (int i = 0; i < 4078; i++)
131 tmpBuf[i] = 0x20;
132 tmpIndex = 4078;
133
134 packedData += 4;
135
136 dest = dataBuf;
137 cmd = 0;
138 while (1) {
139 cmd >>= 1;
140 if ((cmd & 0x0100) == 0) {
141 cmd = *packedData | 0xFF00;
142 packedData++;
143 }
144 if ((cmd & 1) != 0) { /* copy */
145 *dest++ = *packedData;
146 tmpBuf[tmpIndex] = *packedData;
147 packedData++;
148 tmpIndex++;
149 tmpIndex %= 4096;
150 counter--;
151 if (counter == 0)
152 break;
153 } else { /* copy string */
154
155 off = *packedData++;
156 off |= (*packedData & 0xF0) << 4;
157 len = (*packedData & 0x0F) + 3;
158 packedData++;
159
160 for (int i = 0; i < len; i++) {
161 *dest++ = tmpBuf[(off + i) % 4096];
162 counter--;
163 if (counter == 0) {
164 delete[] tmpBuf;
165 return dataBuf;
166 }
167 tmpBuf[tmpIndex] = tmpBuf[(off + i) % 4096];
168 tmpIndex++;
169 tmpIndex %= 4096;
170 }
171
172 }
173 }
174 delete[] tmpBuf;
175
176 return dataBuf;
177 }
178
Script(byte * totData,uint32 totSize,ExtTable * extTable)179 Script::Script(byte *totData, uint32 totSize, ExtTable *extTable) :
180 _totData(totData), _ptr(totData), _totSize(totSize), _extTable(extTable) {
181
182 assert(totData && (totSize > 128));
183
184 _indent = 0;
185
186 loadProperties(totData);
187 }
~Script()188 Script::~Script() {}
189
getStart() const190 uint16 Script::getStart() const { return _start; }
getTextCenter() const191 uint16 Script::getTextCenter() const { return _textCenter; }
getVarsCount() const192 uint16 Script::getVarsCount() const { return _varsCount; }
getTotTextCount() const193 uint32 Script::getTotTextCount() const { return _totTextCount; }
getTotResOffset() const194 uint32 Script::getTotResOffset() const { return _totResOffset; }
getTotResCount() const195 uint16 Script::getTotResCount() const { return _totResCount; }
getAnimDataSize() const196 uint16 Script::getAnimDataSize() const { return _animDataSize; }
getVerScript() const197 uint8 Script::getVerScript() const { return _verScript; }
getVerIMEX() const198 uint8 Script::getVerIMEX() const { return _verIMEX; }
getSuffixIM() const199 uint8 Script::getSuffixIM() const { return _suffixIM; }
getSuffixEX() const200 uint8 Script::getSuffixEX() const { return _suffixEX; }
201
putString(const char * s) const202 void Script::putString(const char *s) const {
203 printf("%s", s);
204 }
print(const char * s,...) const205 void Script::print(const char *s, ...) const {
206 char buf[1024];
207 va_list va;
208
209 va_start(va, s);
210 vsnprintf(buf, 1024, s, va);
211 va_end(va);
212
213 putString(buf);
214 }
printIndent() const215 void Script::printIndent() const {
216 print("%08d:", getPos());
217 for (uint32 i = 0; i < _indent; i++)
218 putString(" ");
219 }
printLine(const char * str) const220 void Script::printLine(const char *str) const {
221 printIndent(); putString(str); putString("\n");
222 }
printStr(const char * s,...) const223 std::string Script::printStr(const char *s, ...) const {
224 char buf[1024];
225 va_list va;
226
227 va_start(va, s);
228 vsnprintf(buf, 1024, s, va);
229 va_end(va);
230
231 return buf;
232 }
233
incIndent()234 void Script::incIndent() { _indent++; }
decIndent()235 void Script::decIndent() { _indent--; }
236
getPos() const237 uint32 Script::getPos() const { return _ptr - _totData; }
skip(uint32 off)238 void Script::skip(uint32 off) { seek(off, SEEK_CUR); }
seek(uint32 off,int whence)239 void Script::seek(uint32 off, int whence) {
240 switch (whence) {
241 case SEEK_END:
242 off = _totSize - off;
243 // fall through
244 case SEEK_SET:
245 _ptr = _totData + off;
246 break;
247
248 case SEEK_CUR:
249 _ptr += (int32) off;
250 break;
251 }
252 }
253
peekUint8() const254 uint8 Script::peekUint8() const { return *_ptr; }
peekUint16() const255 uint16 Script::peekUint16() const { return READ_LE_UINT16(_ptr); }
peekUint32() const256 uint32 Script::peekUint32() const { return READ_LE_UINT32(_ptr); }
readUint8()257 uint8 Script::readUint8() { uint8 i = peekUint8(); _ptr += 1; return i; }
readUint16()258 uint16 Script::readUint16() { uint16 i = peekUint16(); _ptr += 2; return i; }
readUint32()259 uint32 Script::readUint32() { uint32 i = peekUint32(); _ptr += 4; return i; }
peekString() const260 const char *Script::peekString() const { return (char *) _ptr; }
readString()261 const char *Script::readString() { const char *i = peekString(); _ptr += strlen(i) + 1; return i; }
262
skipExpr(char stopToken)263 void Script::skipExpr(char stopToken) {
264 int16 dimCount;
265 byte operation;
266 int16 num;
267 int16 dim;
268
269 num = 0;
270 while (1) {
271 operation = readUint8();
272
273 if ((operation >= 14) && (operation <= 29)) {
274 switch (operation) {
275 case 14:
276 skip(4);
277 if (peekUint8() == 97)
278 skip(1);
279 break;
280
281 case 17:
282 case 18:
283 case 20:
284 case 23:
285 case 24:
286 skip(2);
287 break;
288
289 case 19:
290 skip(4);
291 break;
292
293 case 21:
294 skip(1);
295 break;
296
297 case 22:
298 skip(strlen((char *) _ptr) + 1);
299 break;
300
301 case 25:
302 skip(2);
303 if (peekUint8() == 13) {
304 skip(1);
305 skipExpr(12);
306 }
307 break;
308
309 case 15:
310 skip(2);
311 // fall through
312 case 16:
313 case 26:
314 case 27:
315 case 28:
316 dimCount = _ptr[2];
317 // skip header and dimensions
318 skip(3 + dimCount);
319 // skip indices
320 for (dim = 0; dim < dimCount; dim++)
321 skipExpr(12);
322
323 if ((operation == 28) && (peekUint8() == 13)) {
324 skip(1);
325 skipExpr(12);
326 }
327 break;
328
329 case 29:
330 skip(1);
331 skipExpr(10);
332 }
333 continue;
334 } // if ((operation >= 14) && (operation <= 29))
335
336 if (operation == 9) {
337 num++;
338 continue;
339 }
340
341 if ((operation == 11) || ((operation >= 1) && (operation <= 8)))
342 continue;
343
344 if ((operation >= 30) && (operation <= 37))
345 continue;
346
347 if (operation == 10)
348 num--;
349
350 if (operation != stopToken)
351 continue;
352
353 if ((stopToken != 10) || (num < 0))
354 return;
355 }
356 }
357
readExpr(char stopToken)358 std::string Script::readExpr(char stopToken) {
359 std::string expr;
360 int16 dimCount;
361 byte operation;
362 int16 num;
363 int16 dim;
364 byte *arrDesc;
365 byte func;
366
367 num = 0;
368 while (1) {
369 operation = readUint8();
370
371 while ((operation == 14) || (operation == 15)) {
372 if (operation == 14) {
373 expr += printStr("#%d#", readUint16() * 4);
374
375 skip(2);
376 if (peekUint8() == 97)
377 skip(1);
378 } else if (operation == 15) {
379 expr += printStr("#%d->", readUint16() * 4);
380
381 skip(2);
382 uint8 var_A = readUint8();
383
384 skip(var_A);
385
386 for (int i = 0; i < var_A; i++)
387 expr += readExpr(12) + "->";
388
389 expr += "#";
390
391 if (peekUint8() == 97)
392 skip(1);
393 }
394
395 operation = readUint8();
396 }
397
398 if ((operation >= 16) && (operation <= 29)) {
399 // operands
400
401 switch (operation) {
402 case 17: // uint16 variable load
403 expr += printStr("var16_%d", readUint16() * 2);
404 break;
405
406 case 18: // uint8 variable load:
407 expr += printStr("var8_%d", readUint16());
408 break;
409
410 case 19: // int32/uint32 immediate
411 expr += printStr("%d", readUint32());
412 break;
413
414 case 20: // int16 immediate
415 expr += printStr("%d", (int16) readUint16());
416 break;
417
418 case 21: // int8 immediate
419 expr += printStr("%d", (int8) readUint8());
420 break;
421
422 case 22: // string immediate
423 expr += printStr("\"%s\"", readString());
424 break;
425
426 case 23: // uint32 variable load
427 case 24: // uint32 variable load as uint16
428 expr += printStr("var32_%d", readUint16() * 4);
429 break;
430
431 case 25: // string variable load
432 expr += printStr("(&var8_%d)", readUint16() * 4);
433 if (peekUint8() == 13) {
434 skip(1);
435 expr += "+{*";
436 expr += readExpr(12); // this also prints the closing }
437 }
438 break;
439
440 case 16: // uint8 array access
441 case 26: // uint32 array access
442 case 27: // uint16 array access
443 case 28: // string array access
444
445 if (operation == 16)
446 expr += printStr("var8_%d[", readUint16());
447 else if (operation == 26)
448 expr += printStr("var32_%d[", readUint16() * 4);
449 else if (operation == 27)
450 expr += printStr("var16_%d[", readUint16() * 2);
451 else if (operation == 28)
452 expr += printStr("(&var8_%d[", readUint16() * 4);
453
454 dimCount = readUint8();
455 arrDesc = _ptr;
456 skip(dimCount);
457 for (dim = 0; dim < dimCount; dim++) {
458 expr += readExpr(12) + printStr(" of %d", (int16) arrDesc[dim]);
459 if (dim != dimCount - 1)
460 expr += "][";
461 }
462
463 expr += "]";
464 if (operation == 28)
465 expr += ")";
466
467 if ((operation == 28) && (peekUint8() == 13)) {
468 skip(1);
469 expr += "+{*" + readExpr(12);
470 }
471 break;
472
473 case 29: // function
474 func = readUint8();
475 if (func == 5)
476 expr += "sqr(";
477 else if (func == 10)
478 expr += "rand(";
479 else if (func == 7)
480 expr += "abs(";
481 else if ((func == 0) || (func == 1) || (func == 6))
482 expr += "sqrt(";
483 else
484 expr += "id(";
485 expr += readExpr(10);
486 break;
487 }
488 continue;
489 } // if ((operation >= 16) && (operation <= 29))
490
491 // operators
492 switch (operation) {
493 case 9:
494 expr += "(";
495 break;
496
497 case 11:
498 expr += "!";
499 break;
500
501 case 10:
502 expr += ")";
503 break;
504
505 case 1:
506 expr += "-";
507 break;
508
509 case 2:
510 expr += "+";
511 break;
512
513 case 3:
514 expr += "-";
515 break;
516
517 case 4:
518 expr += "|";
519 break;
520
521 case 5:
522 expr += "*";
523 break;
524
525 case 6:
526 expr += "/";
527 break;
528
529 case 7:
530 expr += "%";
531 break;
532
533 case 8:
534 expr += "&";
535 break;
536
537 case 30:
538 expr += " || ";
539 break;
540
541 case 31:
542 expr += " && ";
543 break;
544
545 case 32:
546 expr += "<";
547 break;
548
549 case 33:
550 expr += "<=";
551 break;
552
553 case 34:
554 expr += ">";
555 break;
556
557 case 35:
558 expr += ">=";
559 break;
560
561 case 36:
562 expr += "==";
563 break;
564
565 case 37:
566 expr += "!=";
567 break;
568
569 case 99:
570 // expr += "\n";
571 break;
572
573 case 12:
574 expr += "}";
575 if (stopToken != 12)
576 warning("Closing paren without opening?");
577 break;
578
579 default:
580 // Unknown token -- don't know how to handle this, so just
581 // skip over everything until we reach the stopToken.
582 while (((char) readUint8()) != stopToken) {}
583 return printStr("Invalid operator in expression: <%d>", (int16) operation);
584 break;
585 }
586
587 if (operation == 9) {
588 num++;
589 continue;
590 }
591
592 if ((operation == 11) || ((operation >= 1) && (operation <= 8)))
593 continue;
594
595 if ((operation >= 30) && (operation <= 37))
596 continue;
597
598 if (operation == 10)
599 num--;
600
601 if (operation == stopToken) {
602 if ((stopToken != 10) || (num < 0)) {
603 return expr;
604 }
605 }
606 }
607 }
608
readVarIndex(uint16 * arg_0,uint16 * arg_4)609 std::string Script::readVarIndex(uint16 *arg_0, uint16 *arg_4) {
610 std::string expr, pref;
611 byte *arrDesc;
612 int16 dim;
613 int16 dimCount;
614 int16 operation;
615 int16 temp;
616
617 operation = readUint8();
618
619 while ((operation == 14) || (operation == 15)) {
620 if (operation == 14) {
621 pref += printStr("#%d#", readUint16() * 4);
622
623 if (arg_0)
624 *arg_0 = peekUint16();
625 if (arg_4)
626 *arg_4 = 14;
627
628 skip(2);
629 if (peekUint8() != 97)
630 return expr;
631
632 skip(1);
633 } else if (operation == 15) {
634 pref += printStr("#%d->", readUint16() * 4);
635
636 if (arg_0)
637 *arg_0 = peekUint16();
638 if (arg_4)
639 *arg_4 = 14;
640
641 skip(2);
642 uint8 var_A = readUint8();
643
644 skip(var_A);
645
646 for (int i = 0; i < var_A; i++)
647 pref += readExpr(12) + "->";
648
649 pref += "#";
650
651 if (peekUint8() != 97)
652 return expr;
653
654 skip(1);
655 }
656
657 operation = readUint8();
658 }
659
660 if (arg_0)
661 *arg_0 = 0;
662 if (arg_4)
663 *arg_4 = operation;
664
665 if ((operation == 16) || (operation == 18) || (operation == 25) || (operation == 28))
666 expr = "var8_";
667 else if ((operation == 17) || (operation == 24) || (operation == 27))
668 expr = "var16_";
669 else if ((operation == 23) || (operation == 26))
670 expr = "var32_";
671
672 expr += pref;
673
674 switch (operation) {
675 case 23:
676 case 24:
677 case 25:
678 temp = readUint16() * 4;
679 expr += printStr("%d", temp);
680 if ((operation == 25) && (peekUint8() == 13)) {
681 skip(1);
682 expr += "+{*";
683 expr += readExpr(12);
684 }
685 break;
686
687 case 17:
688 expr += printStr("%d", readUint16() * 2);
689 break;
690
691 case 18:
692 expr += printStr("%d", readUint16());
693 break;
694
695 case 16:
696 case 26:
697 case 27:
698 case 28:
699 if (operation == 16)
700 expr += printStr("%d[", readUint16());
701 else if (operation == 26)
702 expr += printStr("%d[", readUint16() * 4);
703 else if (operation == 27)
704 expr += printStr("%d[", readUint16() * 2);
705 else if (operation == 28)
706 expr += printStr("%d[", readUint16() * 4);
707
708 dimCount = readUint8();
709 arrDesc = _ptr;
710 skip(dimCount);
711 for (dim = 0; dim < dimCount; dim++) {
712 expr += readExpr(12);
713 expr += printStr(" of %d", (int16) arrDesc[dim]);
714 if (dim != dimCount - 1)
715 expr += "][";
716 }
717 expr += "]";
718
719 if ((operation == 28) && (peekUint8() == 13)) {
720 skip(1);
721 expr += "+{*";
722 expr += readExpr(12);
723 }
724 break;
725
726 default:
727 expr += "var_0";
728 break;
729 }
730
731 return expr;
732 }
733
getBlockSize() const734 uint16 Script::getBlockSize() const {
735 return READ_LE_UINT16(_ptr + 2) + 2;
736 }
737
evaluateParams(const Param * params)738 void Script::evaluateParams(const Param *params) {
739 bool first = true;
740
741 while (*params != PARAM_NONE) {
742 if (!first)
743 print(", ");
744 else
745 first = false;
746
747 switch (*params++) {
748 case PARAM_UINT8:
749 print("%u", readUint8());
750 break;
751
752 case PARAM_UINT16:
753 print("%u", readUint16());
754 break;
755
756 case PARAM_UINT32:
757 print("%u", readUint32());
758 break;
759
760 case PARAM_INT8:
761 print("%d", (int8) readUint8());
762 break;
763
764 case PARAM_INT16:
765 print("%d", (int16) readUint16());
766 break;
767
768 case PARAM_INT32:
769 print("%d", (int32) readUint32());
770 break;
771
772 case PARAM_STR:
773 print("\"%s\"", readString());
774 break;
775
776 case PARAM_EXPR:
777 print("%s", readExpr().c_str());
778 break;
779
780 case PARAM_VARINDEX:
781 print("%s", readVarIndex().c_str());
782 break;
783
784 default:
785 error("Unknown parameter type");
786 break;
787 }
788 }
789 }
790
printFuncDesc(const FuncParams & fParams,const Param * params)791 void Script::printFuncDesc(const FuncParams &fParams, const Param *params) {
792 if (!fParams.desc)
793 return;
794
795 printIndent();
796 putString(fParams.desc);
797 putString("(");
798
799 if (params)
800 evaluateParams(params);
801
802 putString(");\n");
803 }
804
printFuncDesc(const FuncParams & fParams) const805 void Script::printFuncDesc(const FuncParams &fParams) const {
806 if (!fParams.desc)
807 return;
808
809 printIndent();
810 putString(fParams.desc);
811 putString("(");
812
813 print("%d, %d", fParams.objIndex, fParams.extraData);
814
815 putString(");\n");
816 }
817
startFunc(const FuncParams & fParams) const818 void Script::startFunc(const FuncParams &fParams) const {
819 printIndent();
820 print("%s(", fParams.desc);
821 }
822
endFunc() const823 void Script::endFunc() const {
824 print(");\n");
825 }
826
loadProperties(byte * data)827 void Script::loadProperties(byte *data) {
828 _start = READ_LE_UINT16(data + 0x64);
829 assert(_start >= 128);
830
831 _varsCount = READ_LE_UINT16(data + 0x2C);
832 _totTextCount = READ_LE_UINT32(data + 0x30);
833 _totResOffset = READ_LE_UINT32(data + 0x34);
834 _totResCount = (_totResOffset == 0xFFFFFFFF) ? 0 : READ_LE_UINT16(data + _totResOffset);
835 _verScript = data[0x29];
836 _verIMEX = data[0x3D];
837 _suffixIM = data[0x3B];
838 _suffixEX = data[0x3C];
839 _animDataSize = READ_LE_UINT16(data + 0x38);
840 _textCenter = READ_LE_UINT16(data + 0x7E);
841 }
842
funcBlock(int16 retFlag)843 void Script::funcBlock(int16 retFlag) {
844 FuncParams params;
845 byte cmd;
846 byte cmd2;
847
848 params.retFlag = retFlag;
849
850 skip(1);
851 params.cmdCount = readUint8();
852 skip(2);
853
854 if (params.cmdCount == 0)
855 return;
856
857 params.counter = 0;
858 do {
859 cmd = readUint8();
860 if ((cmd >> 4) >= 12) {
861 cmd2 = 16 - (cmd >> 4);
862 cmd &= 0xF;
863 } else
864 cmd2 = 0;
865
866 params.counter++;
867
868 if (cmd2 == 0)
869 cmd >>= 4;
870
871 funcOpcode(cmd2, cmd, params);
872
873 } while (params.counter != params.cmdCount);
874 }
875
addStartingOffsets()876 void Script::addStartingOffsets() {
877 for (int i = 100; i < 128; i += 2) {
878 uint16 offset = READ_LE_UINT16(_totData + i);
879 if ((offset >= 128) && (offset != ((uint16) -1)))
880 addFuncOffset(offset);
881 }
882 }
883
addFuncOffset(uint32 offset)884 void Script::addFuncOffset(uint32 offset) {
885 for (std::list<uint32>::iterator it = _funcOffsets.begin(); it != _funcOffsets.end(); ++it)
886 if (*it == offset)
887 return;
888
889 _funcOffsets.push_back(offset);
890 }
891
deGob(int32 offset)892 void Script::deGob(int32 offset) {
893 _funcOffsets.clear();
894
895 if (offset < 0)
896 addStartingOffsets();
897 else
898 _funcOffsets.push_back(offset);
899
900 for (std::list<uint32>::iterator it = _funcOffsets.begin(); it != _funcOffsets.end(); ++it) {
901 seek(*it);
902 deGobFunction();
903 print("\n");
904 }
905 }
906
deGobFunction()907 void Script::deGobFunction() {
908 printIndent();
909 print("sub_%d {\n", getPos());
910 incIndent();
911
912 funcBlock(2);
913
914 decIndent();
915 printIndent();
916 print("}\n");
917 }
918