comparison scn2k/scn2kdump.cc @ 29:d229cce98f50

* no more (or, at least, less) duplicate code between scn2kdump and the rest
author thib
date Fri, 06 Mar 2009 20:02:26 +0000
parents 3a6aaeab7b4e
children 15a18fbe6f21
comparison
equal deleted inserted replaced
28:f1f22bfc4496 29:d229cce98f50
29 using namespace std; 29 using namespace std;
30 30
31 #include"system/file.h" 31 #include"system/file.h"
32 #include"system/file_impl.h" 32 #include"system/file_impl.h"
33 33
34 /* 注意点: @@@ で表記 */ 34 #include "scn2k.h"
35 35
36 struct VarInfo { 36
37 #define TYPE_VARSTR 18 37 #define SCN_DUMP
38 #define TYPE_VARMAX 7 38
39 #define TYPE_STR 58 39 class CmdD : public Cmd
40 #define TYPE_VAL 68 40 {
41 #define TYPE_SYS 0xc8 41 public:
42 int type; 42 CmdD(const Flags& flags, int system_version) : Cmd(flags, system_version) {}
43 int number; 43 //CmdD(const Flags& f) : flags(f) { argc = 0; errorflag = false; cmdstr[0] = 0;}
44 int value; 44 bool ClearError() { /*errorflag = false;*/}
45 VarInfo() { type = TYPE_VAL; value = 0;} 45 static map<int, struct CmdDescrItem*> cmd_descr;
46 VarInfo(int n) { type = TYPE_VAL; value = n;} 46 const char* CmdDescr(int cmd1, int cmd2, int cmd3, int cmd4);
47 VarInfo(const VarInfo& i) { type = i.type; number = i.number; value = i.value;}
48 }; 47 };
49 class Flags {
50 /* flag:
51 ** type 0-5 : ローカル整数、各2000個
52 ** type 6, 25 : グローバル整数、2000個
53 ** type 12 : グローバル文字列、2000個 (今は無視しても良いが)
54 ** type 18 : ローカル文字列、2000個
55 ** type 25: システム変数(マウス座標など?) 1000 個?
56 ** type 26-32, 51 : 1-bit access to 0-6, 25
57 ** type 52-58, 77 : 2-bit access to 0-6, 25
58 ** type 78-84, 103 : 4-bit access to 0-6, 25
59 ** type 104-110, 129 : 8-bit access to 0-6, 25
60 */
61 typedef unsigned int uint;
62 int sys;
63 int var[8][2000];
64 string str[2000];
65 public:
66 int operator () () const;
67 int operator () (VarInfo info) const;
68 void Str(unsigned int number, char* buf, int sz) const;
69
70 bool IsInt(int type) const;
71 int MaxIndex(int type) const;
72
73 void Set(VarInfo info, int value);
74 int Get(int type, int number) const;
75 void SetSys(int value);
76 void SetStr(unsigned int number, string val);
77 };
78
79 bool Flags::IsInt(int type) const {
80 int v = type % 26;
81 return v >= 0 && v < 7 || v == 25;
82 }
83
84 int Flags::MaxIndex(int type) const {
85 switch (type / 26) {
86 case 1:
87 return 63999;
88 case 2:
89 return 31999;
90 case 3:
91 return 15999;
92 case 4:
93 return 7999;
94 default:
95 return 1999;
96 }
97 }
98
99 int Flags::operator()() const {
100 return rand() % 10000;
101 }
102 int Flags::operator() (VarInfo info) const {
103 return Get(info.type, info.number);
104 }
105 int Flags::Get(int type, int number) const {
106 int index = type % 26;
107 type /= 26;
108 if (index == 25) index = 7;
109 if (index > 7 || uint(type) > 4) return 0;
110 if (type == 0) {
111 // A[]..G[], Z[] を直に読む
112 if (uint(number) >= 2000) return 0;
113 return var[index][number];
114 } else {
115 // Ab[]..G4b[], Z8b[] などを読む
116 int factor = 1 << (type - 1);
117 int eltsize = 32 / factor;
118 if (uint(number) >= (64000 / factor)) return 0;
119 return (var[index][number / eltsize] >> ((number % eltsize) * factor)) & ((1 << factor) - 1);
120 }
121 }
122
123 void Flags::Set(VarInfo info, int value) {
124 int type = info.type / 26;
125 int index = info.type % 26;
126 if (index == 25) index = 7;
127 if (type == 0) {
128 // A[]..G[], Z[] を直に書く
129 if (uint(info.number) >= 2000) return;
130 var[index][info.number] = value;
131 } else {
132 // Ab[]..G4b[], Z8b[] などを書く
133 int factor = 1 << (type - 1);
134 int eltsize = 32 / factor;
135 int eltmask = (1 << factor) - 1;
136 int shift = (info.number % eltsize) * factor;
137 if (uint(info.number) >= (64000 / factor)) return;
138 var[index][info.number / eltsize] =
139 (var[index][info.number / eltsize] & ~(eltmask << shift))
140 | (value & eltmask) << shift;
141 }
142 }
143
144 void Flags::SetSys(int value) {
145 sys = value;
146 }
147 void Flags::SetStr(unsigned int number, string val) {
148 if (number >= 2000) return;
149 str[number] = val;
150 }
151 void Flags::Str(unsigned int number, char* buf, int sz) const {
152 if (number >= 2000) {if(sz>0) buf[0] = 0; return;}
153 const string& s = str[number];
154 int len = s.length();
155 if (sz-1 > len) sz = len;
156 s.copy(buf, sz, 0);
157 buf[sz] = 0;
158 return;
159 }
160
161 /* commands */
162 enum Cmdtype { CMD_FLAGS, CMD_JMP, CMD_TEXT, CMD_OTHER};
163 class Cmd {
164 Cmdtype cmd_type;
165 int cmd1, cmd2, cmd3, cmd4;
166 int argc;
167 bool errorflag;
168 char cmdstr[1024];
169 const Flags& flags;
170 vector<VarInfo> args;
171
172 int GetArgs(const char*& d);
173 int GetArgsSpecial(int normal_args,const char*& d);
174 void GetSelection(const char*& d);
175 int GetSwitch(const char*& d);
176 int GetSimpleSwitch(const char*& d);
177 int GetExpression(const char*& d, struct VarInfo* info = 0);
178 int GetExpressionCond(const char*& d);
179 int GetLeftToken(const char*& d, struct VarInfo& info);
180 static int GetString(const char*& d);
181 int StrVar(int number);
182 static char strtype[256];
183 static int StrType(const char* d) { return strtype[*(unsigned const char*)d];}
184 int AddStr(char* s) {
185 // 1-0a-0064 はこういうものが必要らしい
186 int start = strend;
187 while (*s) strheap[strend++] = *s++;
188 strheap[strend++] = 0;
189 return start;
190 }
191 #define STRHEAP_SIZE 10000
192 static char strheap[STRHEAP_SIZE];
193 static int strend;
194 void SetError(void) { errorflag = true;}
195 static void ResetString(void) {
196 strend = 0;
197 }
198 static map<int, struct CmdDescrItem*> cmd_descr;
199 const char* CmdDescr(int cmd1, int cmd2, int cmd3, int cmd4);
200 public:
201 void GetCmd(Flags& f, const char*& d);
202 bool IsError() { return errorflag;}
203 bool ClearError() { errorflag = false;}
204 Cmd(const Flags& f) : flags(f) { argc = 0; errorflag = false; cmdstr[0] = 0;}
205
206 };
207
208 bool debug_flag = false;
209 void dprintf(const char* fmt, ...) {
210 if (debug_flag) {
211 va_list ap; va_start(ap, fmt);
212 vprintf(fmt, ap);
213 va_end(ap);
214 }
215 }
216
217
218 #define SCN_DUMP
219 48
220 int system_version = 0; 49 int system_version = 0;
221 bool ruby_flag = false; 50 bool ruby_flag = false;
222 bool ret_flag = false; 51 bool ret_flag = false;
223 bool text_flag = false; 52 bool text_flag = false;
224 bool selection_flag = false; 53 bool selection_flag = false;
225 char Cmd::strheap[STRHEAP_SIZE];
226 int Cmd::strend = 0;
227
228 /* 数値 num := 0x24 0xff <int num> */
229 /* 変数 var := 0x24 <uchar type> 0x5b <exp> 0x5d */
230 /* 項 token := num | var | 0x28 <exp> 0x29 | <plus|minus> token */
231
232 int Cmd::GetLeftToken(const char*& d, VarInfo& info) {
233 bool var_flag = true;
234 int minus_flag = 0;
235 int value = 0;
236 if (d[0] == 0x5c && (d[1] == 1 || d[1] == 0) ) {
237 if (d[1] == 1) {dprintf("minus-"); minus_flag ^= 1;}
238 else dprintf("plus-");
239 d += 2;
240 var_flag = false;
241 }
242 if (d[0] == 0x24 && ((unsigned const char*)d)[1] == 0xff) {
243 // if ( (d[0] == 0x30 || d[0] == 0x31) && d[1] == 0x24 && ((unsigned const char*)d)[2] == 0xff) /* @@@ not supported; selection 内で、0x30|0x31 が付随することがある */
244 // numerical atom
245 d += 6;
246 value = read_little_endian_int(d-4);
247 dprintf("%d",value);
248 var_flag = false;
249 } else if (d[0] == 0x24 && *(unsigned char*)(d+1) == 0xc8) {
250 dprintf("V<sys>");
251 d += 2;
252 info.type = TYPE_SYS; info.number = 0;
253 value = info.value = flags();
254 } else if (d[0] == 0x24 && d[2] == 0x5b) {
255 // 0x24,<type>,0x5b,<expr>,0x5d-terminated term
256 info.type = *(unsigned char*)(d+1);
257 d += 3;
258 dprintf("V<%d>[",info.type);
259 info.number = GetExpression(d);
260 dprintf("]");
261 if (*d == 0x5d) d++;
262 else SetError();
263 if (info.type == TYPE_VARSTR) {
264 value = 0;
265 info.value = StrVar(info.number);
266 } else {
267 value = info.value = flags(info);
268 }
269 dprintf("(=%d)",value);
270 } else SetError();
271
272 if (minus_flag) value = -value;
273 if (!var_flag) {
274 info.type = TYPE_VAL;
275 info.value = value;
276 }
277 return value;
278 }
279
280 static char* op_str[70] = {
281 // 0 1 2 3 4 5 6 7 8 9
282 "+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", // +00
283 "err.","err.","err.","err.","err.","err.","err.","err.","err.","err.", // +10
284 "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>=", // +20
285 "=", "err.","err.","err.","err.","err.","err.","err.","err.","err.", // +30
286 "==", "!=", "<=", "<", ">=", ">", "err.","err.","err.","err.", // +40
287 "err.","err.","err.","err.","err.","err.","err.","err.","err.","err.", // +50
288 "&&", "||", "err.","err.","err.","err.","err.","err.","err.","err.", // +60
289 };
290
291 static int op_pri_tbl[12] = {
292 // + - * / % & | ^ << >>
293 1, 1, 0, 0, 0, 3, 5, 4, 2, 2, 10, 10};
294
295 inline int op_pri(int op) {
296 if (op > 11) return 10;
297 return op_pri_tbl[op];
298 }
299 inline int op_pri_cond(int op) {
300 if (op <= 11) return op_pri_tbl[op];
301 else if (op < 50) return 7;
302 else if (op == 60) return 8;
303 else if (op == 61) return 9;
304 else return 10;
305 }
306 54
307 55
308 inline int eval(int v1, int op, int v2) { 56 inline int eval(int v1, int op, int v2) {
309 switch(op) { 57 switch(op) {
310 case 0: return v1+v2; 58 case 0: return v1+v2;
327 case 61: return v1 || v2; 75 case 61: return v1 || v2;
328 } 76 }
329 return v2; 77 return v2;
330 } 78 }
331 79
332 /* 演算子 op := 0x5c <uchar op> */
333 /* 数式 exp: [op] <token> [op <token> [...]] */
334 int Cmd::GetExpression(const char*& d, VarInfo* info_ptr) {
335 #define STACK_DEPTH 1024
336 #define OP_LB 11
337 char op_stack[STACK_DEPTH];
338 int val_stack[STACK_DEPTH];
339 int stack_count = 0;
340
341 // 第一項の読み込み
342 while(*d == 0x28) {
343 d++;
344 dprintf("(");
345 op_stack[stack_count++] = OP_LB;
346 }
347 VarInfo info;
348 int value = GetLeftToken(d, info);
349
350 while(*d == 0x29 && stack_count > 0 && op_stack[stack_count-1] == OP_LB) {
351 d++;
352 dprintf(")");
353 stack_count--;
354 }
355
356 if (*d != 0x5c && stack_count == 0) {
357 if (info_ptr) *info_ptr = info;
358 return value; // 単純なleft-termはここで終了。有効なinfo_ptrを帰す(可能性がある)
359 }
360
361 while(*d == 0x5c) {
362 int op_type = *(unsigned char*)(d+1);
363 d += 2;
364 if (op_type < 70) dprintf("%s",op_str[op_type]);
365 else dprintf("err.");
366 if (op_type >= 10) SetError();
367 int cur_pri = op_pri(op_type);
368 while(stack_count != 0 && op_pri(op_stack[stack_count-1]) <= cur_pri) {
369 // 優先順位の高い、先行する演算を行う
370 value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value);
371 stack_count--;
372 }
373 val_stack[stack_count] = value;
374 op_stack[stack_count++] = op_type;
375 while(*d == 0x28) {
376 d++;
377 dprintf("(");
378 op_stack[stack_count++] = OP_LB;
379 }
380 if (stack_count >= STACK_DEPTH) SetError();
381 value = GetLeftToken(d, info);
382
383 while (*d != 0x5c && stack_count > 0) {
384 // 未実行の演算を終わらせる
385 if (op_stack[stack_count-1] != OP_LB) {
386 value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value);
387 stack_count--;
388 } else if (*d == 0x29) { /* op_stack == OP_LB */
389 // bracket 終端があれば、閉じておく
390 d++;
391 dprintf(")");
392 stack_count--;
393 } else break; // error
394 }
395 }
396 if (stack_count) SetError(); // unbalanced bracket
397 dprintf("(=%d)",value);
398 if (info_ptr) {
399 info_ptr->type = TYPE_VAL;
400 info_ptr->value = value;
401 }
402 return value;
403 }
404
405 // 条件分岐専用に、条件演算と算術演算の混合を検知できる専用ルーチン(本来はGetExpressionで差し支えない)
406 int Cmd::GetExpressionCond(const char*& d) {
407 char op_stack[STACK_DEPTH];
408 int val_stack[STACK_DEPTH];
409 int valattr_stack[STACK_DEPTH];
410 #define ATTR_VAL 0
411 #define ATTR_FLAG 1
412 int stack_count = 0;
413
414 // 第一項の読み込み
415 while(*d == 0x28) {
416 d++;
417 dprintf("(");
418 op_stack[stack_count++] = OP_LB;
419 }
420 VarInfo info;
421 int value = GetLeftToken(d, info);
422 bool valattr = ATTR_VAL;
423
424 while(*d == 0x5c) {
425 int op_type = *(unsigned char*)(d+1);
426 d += 2;
427 if (op_type < 70) dprintf("%s",op_str[op_type]);
428 else dprintf("err.");
429 int cur_pri = op_pri_cond(op_type);
430 while(stack_count != 0 && op_pri_cond(op_stack[stack_count-1]) <= cur_pri) {
431 // 優先順位の高い、先行する演算を行う
432 if (op_stack[stack_count-1] >= 60) {
433 if (valattr_stack[stack_count-1] != ATTR_FLAG || valattr != ATTR_FLAG) SetError();
434 } else {
435 if (valattr_stack[stack_count-1] != ATTR_VAL || valattr != ATTR_VAL) SetError();
436 }
437 value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value);
438 if (op_stack[stack_count-1] >= 40) valattr = ATTR_FLAG;
439 stack_count--;
440 }
441 val_stack[stack_count] = value;
442 valattr_stack[stack_count] = valattr;
443 op_stack[stack_count++] = op_type;
444 while(*d == 0x28) {
445 d++;
446 dprintf("(");
447 op_stack[stack_count++] = OP_LB;
448 }
449 if (stack_count >= STACK_DEPTH) SetError();
450 value = GetLeftToken(d, info);
451 valattr = ATTR_VAL;
452
453 while (*d != 0x5c && stack_count > 0) {
454 // 未実行の演算を終わらせる
455 if (op_stack[stack_count-1] != OP_LB) {
456 if (op_stack[stack_count-1] >= 60) {
457 if (valattr_stack[stack_count-1] != ATTR_FLAG || valattr != ATTR_FLAG) SetError();
458 } else {
459 if (valattr_stack[stack_count-1] != ATTR_VAL || valattr != ATTR_VAL) SetError();
460 }
461 value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value);
462 if (op_stack[stack_count-1] >= 40) valattr = ATTR_FLAG;
463 stack_count--;
464 // bracket 終端があれば、閉じておく
465 } else if (*d == 0x29) { /* op_stack == OP_LB */
466 d++;
467 dprintf(")");
468 stack_count--;
469 } else break; // error
470 }
471 }
472 if (stack_count) SetError(); // unbalanced bracket
473 if (value) dprintf("(=true)");
474 else dprintf("(=false)");
475 return value;
476 }
477
478
479 /*
480 str =
481 arg =
482 args = 0x28 <exp> [[0x2c] <exp> [[0x2c] <exp> [...] ]]
483 */
484
485 int Cmd::GetArgs(const char*& d) {
486 if (*d != 0x28) return 0; /* 引数なし */
487 d++;
488 dprintf("args:");
489 VarInfo var;
490 int i; for (i=0; i<100 ; i++) {
491 /* number, variable, string の種別なく値を得る */
492 if (*d == 0x61) { // よくわからない(智代アフター)
493 dprintf("@%d",d[1]);
494 d += 2;
495 if (*d == 0x28) {
496 dprintf("{");
497 GetArgs(d); // (A,B,C)節が含まれることがある
498 dprintf("}");
499 } else {
500 dprintf("{}");
501 }
502 } else if (d[0] == 0x0a || d[0] == 0x40) { // よくわからない (Little Busters!)
503 int var;
504 if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;}
505 else { var = read_little_endian_short(d+1); d += 3;}
506 dprintf("line %d; ",var);
507 } else if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0)) || *d == 0x28) {
508 GetExpression(d, &var);
509 args.push_back(var);
510 } else if (StrType(d)) {
511 var.type = TYPE_STR;
512 var.value = GetString(d);
513 args.push_back(var);
514 } else SetError();
515 if (*d == 0x29) break;
516 if (*d == 0x2c) {d++;} // 次の arg が演算子で始まる、などがなければ存在しない
517 dprintf(",");
518 }
519 if (*d == 0x29) d++;
520 else SetError();
521 return i;
522 }
523
524 int Cmd::GetArgsSpecial(int normal_args,const char*& d) {
525 if (*d != 0x28) return 0; /* 引数なし */
526 d++;
527 dprintf("args:");
528 int i; for (i=0; i<normal_args; i++) {
529 /* number, variable, string の種別なく値を得る */
530 if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0)) || *d == 0x28) {
531 GetExpression(d);
532 } else if (StrType(d)) {
533 GetString(d);
534 } else SetError();
535 if (*d == 0x29) break;
536 if (*d == 0x2c) {d++;} // 次の arg が演算子で始まる、などがなければ存在しない
537 dprintf(",");
538 }
539 for (i=0; i<argc ; i++) {
540 if (*d == 0x28) {
541 /*
542 ** cmd 01-22:0c1c, 01-22:0835
543 ** Princess Bride のカードが落ちるアニメの場面
544 ** なお、_PBCARDANM* の画像はこのコマンドでのみ使われているので、特殊処理として無視することも可能
545 **
546 ** cmd 01-04:0276, 026c, 0270
547 ** 複数の enum が args の数だけ続く処理。特殊処理として分離する
548 */
549 dprintf("enum.<");
550 /* (...) は列挙型 or 構造体の可能性がある */
551 const char* d_orig = d;
552 int pt = args.size(); args.push_back(VarInfo(0));
553 int count = GetArgs(d);
554 args[pt] = VarInfo(count);
555 dprintf(">");
556 } else if (*d == 0x61 && (d[1] >= 0x00 && d[1] <= 0x04) && d[2] == 0x28 ) {
557 /* 使われるコマンドは 01-21:004b, 01-28:0064 のいずれか(R,C,PB,LO)
558 ** それらのコマンドは
559 ** arg1: 画像ファイル名
560 ** arg2 : Sel 番号
561 ** らしく、arg3 以降が 0x61 <00-04> (a,b,c,...) となる(ダンプ上は enum と表記される)
562 ** () 内の引数はさまざまで、a のみ(画像ファイル名)、
563 ** a,b b=SEL?
564 ** a,b,c (b,c)=座標?
565 ** a,(b,c,d,e,f,g) b-g = src / dest?
566 ** らしい
567 */
568 dprintf("kasane. #%d <",d[1]);
569 d += 2;
570 int pt = args.size(); args.push_back(VarInfo(0));
571 int count = GetArgs(d);
572 args[pt] = VarInfo(count);
573 dprintf(">");
574 } else if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0))) {
575 /* cmd 01-15:0028 ; 始めに 0x24 節があり、続いて 0x28 節になる */
576 VarInfo var;
577 GetExpression(d, &var);
578 args.push_back(var);
579 i--; // この引数はargc の数には入らない
580 } else SetError();
581 if (d[0] == 0x0a || d[0] == 0x40) {
582 /* cmd 01-15:0028 ; 0x28 節の後に毎回 0x0a 節が来る */
583 int var;
584 if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;}
585 else { var = read_little_endian_short(d+1); d += 3;}
586 dprintf("line %d; ",var);
587 }
588 if (*d == 0x29) break;
589 if (*d == 0x2c) {d++;} // 次の arg が演算子で始まる、などがなければ存在しない
590 dprintf(",");
591 }
592 if (*d == 0x29) d++;
593 else SetError();
594 return 0;
595 }
596
597 /* switch
598 <exp>
599 0x7b
600 <exp> <int>
601 ...
602 0x7d
603 */
604
605 int Cmd::GetSwitch(const char*& d) {
606 if (*d != 0x28) {SetError(); return -1;}
607 d++;
608 dprintf("switch. ");
609 int var = GetExpression(d);
610 if (*d != 0x29) {SetError(); return -1;}
611 d++;
612 dprintf("->\n");
613 if (*d == 0x7b) {
614 d++;
615 } else SetError();
616
617 int default_jmp = -1; int jmpto = -1;
618 int i; for (i=0; i<argc; i++) {
619 dprintf("\t");
620 if (*d++ != 0x28) {SetError(); return -1;}
621 int item = -1; // default
622 if (*d != 0x29) {
623 int item = GetExpression(d);
624 if (*d++ != 0x29) {SetError(); return -1;}
625 int jmp = read_little_endian_int(d);
626 if (var == item) {
627 dprintf("(selected)");
628 jmpto = jmp;
629 }
630 dprintf(" -> %d\n", jmp);
631 } else {
632 d++;
633 default_jmp = read_little_endian_int(d);
634 }
635 d += 4;
636 }
637 if (default_jmp != -1) {
638 dprintf("default -> %d\n",default_jmp);
639 if (jmpto == -1) jmpto = default_jmp;
640 }
641 if (*d == 0x7d) {
642 d++;
643 } else SetError();
644 return jmpto;
645 }
646 /* simple switch
647 <exp>
648 0x7b
649 <int>
650 ...
651 0x7d
652 */
653 int Cmd::GetSimpleSwitch(const char*& d) {
654 if (*d != 0x28) {SetError(); return -1;}
655 d++;
656 dprintf("simple switch. ");
657 int var = GetExpression(d);
658 if (*d != 0x29) {SetError(); return -1;}
659 d++;
660 dprintf(" ->\n");
661 int jumpto = -1;
662 if (*d == 0x7b) {
663 d++;
664 } else SetError();
665 int i; for (i=0; i<argc; i++) {
666 int j = read_little_endian_int(d);
667 d += 4;
668 dprintf("\t%d -> %d\n", i+1, j);
669 if (var == i+1) jumpto = j;
670 }
671 if (*d == 0x7d) {
672 d++;
673 } else SetError();
674 return jumpto;
675 }
676
677 /*
678 selection
679 ? <exp>
680 0x7b
681 <0x0a|0x40> <ushort | uint>
682 */
683 void Cmd::GetSelection(const char*& d) {
684 dprintf("selection. ");
685 if (*d == 0x28) {
686 d++;
687 GetExpression(d);
688 if (*d != 0x29) { SetError(); return;}
689 d++;
690 }
691 if (*d == 0x7b) {
692 d++;
693 dprintf("{\n\t");
694 } else SetError();
695 int arg_count = 0;
696 while(*d != 0x7d) {
697 if (d[0] == 0x0a || d[0] == 0x40) {
698 int var;
699 if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;}
700 else { var = read_little_endian_short(d+1); d += 3;}
701 dprintf("line %d; ",var);
702 } else if (d[0] == 0x2c) {
703 dprintf(":comma:");
704 } else if (d[0] == 0x28) {
705 dprintf(":cond:");
706 d++;
707 while(d[0] != 0x29) {
708 GetExpressionCond(d); // PRINT- 節でないばあい、条件表示。次は文字節、またはPRINT節のはず
709 if (IsError()) break;
710 if (*d == 0x32) { d++; dprintf("##");} // 0x32 なら、現在の条件節を表示しない
711 if (*d == 0x31) { d++; dprintf("**");} // 0x31 なら、現在の条件節を表示する(Little Busters! : 処理が正しいかは分からない)
712 dprintf(":");
713 }
714 d++;
715 } else if (StrType(d)) {
716 GetString(d);
717 arg_count++;
718 dprintf("\n\t");
719 } else if (*d == 0x23 && strncmp(d,"###PRINT",8) == 0) {
720 d += 8;
721 if (d[0] != 0x28) SetError();
722 else { // 文字変数の内容の表示
723 d++;
724 dprintf("Print.");
725 VarInfo info;
726 GetLeftToken(d, info);
727 if (d[0] != 0x29 || info.type == -1) SetError();
728 d++;
729 dprintf(";");
730 }
731 } else { SetError(); break;}
732 }
733 d++;
734 /* @@@ */
735 /* 一致しない場合があるのでコメントアウト */
736 // if (arg_count != argc) SetError();
737 dprintf("\n}\n");
738 return;
739 }
740
741 char* op_str3[11] = { "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>=", "="};
742 void Cmd::GetCmd(Flags& flags_orig, const char*& d ) {
743 ResetString();
744
745 cmdstr[0] = 0;
746 debug_flag = true;
747 if (*d == 0x23) { /* コマンド */
748 cmd_type = CMD_OTHER;
749 cmd1 = *(unsigned const char*)(d+1);
750 cmd2 = *(unsigned const char*)(d+2);
751 cmd3 = read_little_endian_short(d+3);
752 argc = read_little_endian_short(d+5);
753 cmd4 = *(unsigned const char*)(d+7);
754 d += 8;
755 /* verbose */
756 // dprintf(" 0x23 - cmd %02x-%02x:%04x:%02x[%2d] \n",cmd1,cmd2,cmd3,cmd4,argc);
757 sprintf(cmdstr, "%02x-%02x:%04x:%02x : %s",cmd1,cmd2,cmd3,cmd4,CmdDescr(cmd1,cmd2,cmd3,cmd4));
758 /* 引数を得る */
759 /* 特殊引数のもの */
760 int is_special = 0;
761 if (cmd1 == 0) {
762 if (cmd2 == 1) {
763 int jump_arg = -1;
764 if (cmd3 == 0 || cmd3 == 5) {
765 /* gosub / goto */
766 jump_arg =read_little_endian_int(d);
767 d += 4;
768 dprintf("\tjmp -> %d\n", jump_arg);
769 is_special = 1;
770 } else if (cmd3 == 1 || cmd3 == 2) {
771 /* conditional jump (if / unless) */
772 if (*d++ != 0x28) { SetError(); return;}
773 dprintf("\t");
774 int cond = GetExpressionCond(d);
775 if (IsError()) return;
776 if (*d++ != 0x29) { SetError(); return; }
777 int jumpto = read_little_endian_int(d);
778 d += 4;
779 dprintf("-> %d\n", jumpto);
780 if (cond) jump_arg = jumpto;
781 is_special = 1;
782 } else if (cmd3 == 4) {
783 /* switch to */
784 jump_arg = GetSwitch(d);
785 is_special = 1;
786 } else if (cmd3 == 16) {
787 dprintf("local call with paramters;\n");
788 GetArgs(d);
789 int jumpto = read_little_endian_int(d);
790 d += 4;
791 dprintf("\tjmp -> %d\n",jumpto);
792 is_special = 1;
793 } else if (cmd3 == 8 || cmd3 == 3) {
794 /* switch to */
795 jump_arg = GetSimpleSwitch(d);
796 dprintf("\tjmp -> %d\n",jump_arg);
797 is_special = 1;
798 }
799 cmd_type = CMD_OTHER;
800 args.push_back(VarInfo(jump_arg));
801 } else if (cmd2 == 2 && (cmd3 == 0 || cmd3 == 1 || cmd3 == 2 || cmd3 == 3 || cmd3 == 0x0d) ) {
802 /* selection */
803 GetSelection(d);
804 is_special = 1;
805 }
806 }
807 /* 一般引数のもの */
808 if (!is_special) {
809 dprintf(" 0x23 - cmd %02x-%02x:%04x:%02x[%2d] : %s\n",cmd1,cmd2,cmd3,cmd4,argc,CmdDescr(cmd1,cmd2,cmd3,cmd4));
810 dprintf("\t");
811 if (cmd1 == 1 && cmd2 == 0x22 && (cmd3 == 0xc1c || cmd3 == 0x835)) GetArgsSpecial(3, d);
812 else if (cmd1 == 1 && cmd2 == 0x0b && cmd3 == 0x65) GetArgsSpecial(0, d);
813 else if (cmd1 == 1 && cmd2 == 0x15 && cmd3 == 0x28) GetArgsSpecial(0, d);
814 else if (cmd1 == 1 && cmd2 == 4 && (cmd3 == 0x26c || cmd3 == 0x26d || cmd3 == 0x270 || cmd3 == 0x276)) GetArgsSpecial(0, d);
815 else if (cmd1 == 1 && (cmd2 == 0x21 && cmd3 == 0x4b) || (cmd2 == 0x28 && cmd3 == 0x64)) GetArgsSpecial(2,d);
816 else GetArgs(d);
817 dprintf("\n");
818
819 }
820 if (cmd2 == 3 && cmd3 == 0x78 && cmd4 == 0) ruby_flag = true;
821 if (cmd2 == 3 && cmd3 == 0x11) ret_flag = true;
822 } else if (*d == 0x24) { /* 代入演算 */
823 if (d[1] == 0x12 || d[2] != 0x5b) SetError();
824 dprintf("expr: ");
825 sprintf(cmdstr, "expr");
826
827 VarInfo info;
828 int value = GetLeftToken(d, info);
829 if (d[0] != 0x5c) SetError();
830 int type = d[1];
831 if (type < 20 || type > 30) SetError();
832 else dprintf("%s",op_str[type]);
833 d += 2;
834 int value2 = GetExpression(d);
835 // 代入情報を埋め込む
836 if (type != 30) value2 = eval(value, type-20, value2);
837 cmd_type = CMD_FLAGS;
838 args.push_back(info);
839 args.push_back(value2);
840 dprintf("\n");
841 } else if (StrType(d)) { /* 文字出力 */
842 VarInfo info;
843 info.type = TYPE_STR;
844 info.value = GetString(d);
845 args.push_back(info);
846 cmd_type = CMD_TEXT;
847 text_flag = true;
848 dprintf("\n");
849 } else if (*d == 0x0a || *d == 0x40 || *d == 0x21) { /* デバッグ用データと既読フラグ */
850 cmd_type = CMD_OTHER;
851 if (*d == 0x0a) {
852 dprintf("line ");
853 d++;
854 int l;
855 if (system_version == 0) {
856 l = read_little_endian_int(d);
857 d += 4;
858 } else {
859 l = read_little_endian_short(d);
860 d += 2;
861 }
862 dprintf("%d\n", l);
863 } else { /* 0x40, 0x21 */
864 // 既読マーカーらしい。エントリーポイントとセーブポイントも使われる。
865 // RealLive 1.2.5から、0x40はセーブポイント、0x21はエントリーポイント。
866 // 1.2.5以前、どちらも0x40が使われる。
867 int kidoku_index;
868 d++;
869 if (system_version == 0) {
870 kidoku_index = read_little_endian_int(d);
871 d += 4;
872 } else {
873 kidoku_index = read_little_endian_short(d);
874 d += 2;
875 }
876 dprintf("kidoku marker %d\n", kidoku_index);
877 // text_readflagは、このkidoku_indexを使ったら良いかな。
878 }
879 } else if (*d == 0x2c) { /* ??? */
880 dprintf("commd;0x2c\n"); // conditional jump の行き先によくあるらしい(常に、かはわからない)
881 d++;
882 } else {
883 SetError();
884 }
885 return;
886 }
887
888 char Cmd::strtype[256] = {
889 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +00 */
890 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +10 */
891 0,0,3,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +20 */
892 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,1, /* +30 */
893 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, /* +40 */
894 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,1, /* +50 */
895 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +60 */
896 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +70 */
897 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +80 */
898 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +90 */
899 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +A0 */
900 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +B0 */
901 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +C0 */
902 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +D0 */
903 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +E0 */
904 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,0,0 /* +F0 */
905 };
906
907 int Cmd::GetString(const char*& d) {
908 int retnum = -1;
909 while(1) {
910 if (*d == '\\') {
911 d++;
912 strheap[strend++] = *d++;
913 } else if (*d == '"') {
914 d++;
915 if (retnum == -1) retnum = strend;
916 while(*d != '"') strheap[strend++] = *d++;
917 d++;
918 } else if (StrType(d)) {
919 if (retnum == -1) retnum = strend;
920 int stype;
921 while( (stype = StrType(d)) ) {
922 if (stype == 3) break; // 文中に '"' が現れた場合
923 strheap[strend++] = *d++;
924 if (stype == 2) strheap[strend++] = *d++;
925 }
926 } else break;
927 }
928 if (retnum != -1) strheap[strend++] = 0;
929 dprintf("\"%s\"", strheap + retnum);
930 if (strend >= STRHEAP_SIZE) {
931 dprintf("Error: string heap overflow\n");
932 }
933 return retnum;
934 }
935
936 int Cmd::StrVar(int var_num) {
937 int retnum = strend;
938 flags.Str(var_num, strheap+strend, STRHEAP_SIZE-strend);
939 strend += strlen(strheap+strend)+1;
940 return retnum;
941 }
942 80
943 void usage(void) { 81 void usage(void) {
944 fprintf(stderr,"usage : scn2kdump [inputfile] [outputfile]\n"); 82 fprintf(stderr,"usage : scn2kdump [inputfile] [outputfile]\n");
945 fprintf(stderr," inputfile: seen.txt(default)\n"); 83 fprintf(stderr," inputfile: seen.txt(default)\n");
946 fprintf(stderr," outputfile: seen.txt_out(default)\n"); 84 fprintf(stderr," outputfile: seen.txt_out(default)\n");
947 exit(-1); 85 exit(-1);
948 } 86 }
87
88 extern int debug_flag;
89
949 int main(int argc, char** argv) { 90 int main(int argc, char** argv) {
950 /* determine file names */ 91 /* determine file names */
92 debug_flag = true;
951 bool verbose = false; 93 bool verbose = false;
952 char* inname = "seen.txt"; 94 char* inname = "seen.txt";
953 char* outname = 0; 95 char* outname = 0;
954 if (argc > 2 && strcmp(argv[1],"-v") == 0) { 96 if (argc > 2 && strcmp(argv[1],"-v") == 0) {
955 int i; for (i=1; i<argc; i++) argv[i] = argv[i+1]; 97 int i; for (i=1; i<argc; i++) argv[i] = argv[i+1];
1009 }} 151 }}
1010 Flags flags; 152 Flags flags;
1011 /* 最初から最後までコマンド取得 -> 出力を繰り返す */ 153 /* 最初から最後までコマンド取得 -> 出力を繰り返す */
1012 while(dcur<dend) { 154 while(dcur<dend) {
1013 const char* dprev = dcur; 155 const char* dprev = dcur;
1014 Cmd cmd(flags); cmd.ClearError(); 156 CmdD cmd(flags, system_version); cmd.ClearError();
1015 157
1016 /* end? */ 158 /* end? */
1017 if (*dcur == -1) { 159 if (*dcur == -1) {
1018 /* 0xff x 32byte + 0x00 : end sign */ 160 /* 0xff x 32byte + 0x00 : end sign */
1019 int i; for (i=0; i<0x20; i++) 161 int i; for (i=0; i<0x20; i++)
1121 {0,0,0x01,0x04,0x4b1,"GoMenu"}, 263 {0,0,0x01,0x04,0x4b1,"GoMenu"},
1122 {0,0,0x01,0x04,0x4b3,"GoMenu_Badend"}, 264 {0,0,0x01,0x04,0x4b3,"GoMenu_Badend"},
1123 {0,0,0x01,0x04,0xcc, "ShowMouseCursor"}, 265 {0,0,0x01,0x04,0xcc, "ShowMouseCursor"},
1124 {0,0,0x01,0x04,0xcd, "HideMouseCursor"}, 266 {0,0,0x01,0x04,0xcd, "HideMouseCursor"},
1125 {0,0,0x01,0x04,0xcf, "SetCursorType"}, 267 {0,0,0x01,0x04,0xcf, "SetCursorType"},
1126 // scn2k_cmd.cc; Cmd::GetCmd() 268 // scn2k_cmd.cc; CmdD::GetCmd()
1127 {0,0,0x00,0x01,0, "local jump"}, 269 {0,0,0x00,0x01,0, "local jump"},
1128 {0,0,0x00,0x01,1, "local jump-if"}, 270 {0,0,0x00,0x01,1, "local jump-if"},
1129 {0,0,0x00,0x01,2, "local jump-unless"}, 271 {0,0,0x00,0x01,2, "local jump-unless"},
1130 {0,0,0x00,0x01,3, "local jump-switch??"}, 272 {0,0,0x00,0x01,3, "local jump-switch??"},
1131 {0,0,0x00,0x01,4, "local switch"}, 273 {0,0,0x00,0x01,4, "local switch"},
1329 {0,0,0x02,0x52,0x419,"SetGrpObj_rotate(2)(2)"}, 471 {0,0,0x02,0x52,0x419,"SetGrpObj_rotate(2)(2)"},
1330 {0,0,0x02,0x54,0x3e8,"GetGrpObj_xy(2)"}, 472 {0,0,0x02,0x54,0x3e8,"GetGrpObj_xy(2)"},
1331 {0,0,0x02,0x54,0x44c,"GetGrpObj_wh(2)"}, 473 {0,0,0x02,0x54,0x44c,"GetGrpObj_wh(2)"},
1332 {0,0,0,0,0,0} 474 {0,0,0,0,0,0}
1333 }; 475 };
1334 map<int, CmdDescrItem*> Cmd::cmd_descr; 476 map<int, CmdDescrItem*> CmdD::cmd_descr;
1335 const char* Cmd::CmdDescr(int cmd1, int cmd2, int cmd3, int cmd4) { 477 const char* CmdD::CmdDescr(int cmd1, int cmd2, int cmd3, int cmd4) {
1336 if (cmd_descr.empty()) { 478 if (cmd_descr.empty()) {
1337 int i; 479 int i;
1338 for (i=0; cmd_descr_orig[i].cmd_descr != 0; i++) { 480 for (i=0; cmd_descr_orig[i].cmd_descr != 0; i++) {
1339 CmdDescrItem& cur = cmd_descr_orig[i]; 481 CmdDescrItem& cur = cmd_descr_orig[i];
1340 int item_num = cur.cmd1*1000000+cur.cmd2*10000+cur.cmd3; 482 int item_num = cur.cmd1*1000000+cur.cmd2*10000+cur.cmd3;