Mercurial > otakunoraifu
annotate scn2k/scn2k_cmd.cc @ 24:c9e218c2c3f1
Makes xclannad buildable without libvorbis
author | thib |
---|---|
date | Fri, 27 Feb 2009 16:02:32 +0000 |
parents | d1bb7b365816 |
children | d229cce98f50 |
rev | line source |
---|---|
0 | 1 /* |
2 * Copyright (c) 2004-2006 Kazunori "jagarl" Ueno | |
3 * All rights reserved. | |
4 * | |
5 * Redistribution and use in source and binary forms, with or without | |
6 * modification, are permitted provided that the following conditions | |
7 * are met: | |
8 * 1. Redistributions of source code must retain the above copyright | |
9 * notice, this list of conditions and the following disclaimer. | |
10 * 2. Redistributions in binary form must reproduce the above copyright | |
11 * notice, this list of conditions and the following disclaimer in the | |
12 * documentation and/or other materials provided with the distribution. | |
13 * 3. The name of the author may not be used to endorse or promote products | |
14 * derived from this software without specific prior written permission. | |
15 * | |
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
26 */ | |
27 | |
28 | |
29 #include"scn2k.h" | |
30 | |
31 #include<stdlib.h> | |
32 #include<stdarg.h> | |
33 #include<stdio.h> | |
34 #include<string.h> | |
35 #include<string> | |
36 #include"system/file.h" | |
37 | |
38 using namespace std; | |
39 | |
40 | |
41 // #define SCN_DUMP | |
42 /* 注意点: @@@ で表記 */ | |
43 | |
44 | |
45 | |
46 //bool debug_flag = true; | |
47 bool debug_flag = false; | |
48 void dprintf(const char* fmt, ...) { | |
49 if (debug_flag) { | |
50 va_list ap; va_start(ap, fmt); | |
51 vprintf(fmt, ap); | |
52 va_end(ap); | |
53 } | |
54 } | |
55 | |
56 | |
57 void eprintf(const char* fmt, ...) { | |
58 va_list ap; va_start(ap, fmt); | |
59 // vprintf(fmt, ap); | |
60 va_end(ap); | |
61 } | |
62 | |
63 /************************************************************** | |
64 ** Flag | |
65 */ | |
66 | |
67 Flags::Flags(void) { | |
68 int i,j; | |
69 for (i=0; i<=TYPE_VARMAX; i++) { | |
70 for (j=0; j<2000; j++) { | |
71 var[i][j] = 0; | |
72 } | |
73 } | |
74 sys = 0; | |
75 } | |
76 | |
77 bool Flags::IsInt(int type) const { | |
78 int v = type % 26; | |
79 return v >= 0 && v < 7 || v == 25; | |
80 } | |
81 | |
82 int Flags::MaxIndex(int type) const { | |
83 switch (type / 26) { | |
84 case 1: | |
85 return 63999; | |
86 case 2: | |
87 return 31999; | |
88 case 3: | |
89 return 15999; | |
90 case 4: | |
91 return 7999; | |
92 default: | |
93 return 1999; | |
94 } | |
95 } | |
96 | |
97 int Flags::operator()() const { | |
98 return sys; // rand() % 10000; | |
99 } | |
100 | |
101 int Flags::operator() (VarInfo info) const { | |
102 return Get(info.type, info.number); | |
103 } | |
104 | |
105 int Flags::Get(int type, int number) const { | |
106 int index = type % 26; | |
107 type /= 26; | |
108 if (index == 25) { | |
109 if (var[7][number] != 0) return var[7][number]; | |
110 if (cgm_data.find(number) == cgm_data.end()) return 0; | |
111 else return 1; | |
112 } | |
113 if (index == 10) index = 8; | |
114 if (index == 11) index = 9; | |
115 if (index > TYPE_VARMAX || uint(type) > 4) return 0; | |
116 if (type == 0) { | |
117 // A[]..G[], Z[] を直に読む | |
118 if (uint(number) >= 2000) return 0; | |
119 return var[index][number]; | |
120 } else { | |
121 // Ab[]..G4b[], Z8b[] などを読む | |
122 int factor = 1 << (type - 1); | |
123 int eltsize = 32 / factor; | |
124 if (uint(number) >= (64000 / factor)) return 0; | |
125 return (var[index][number / eltsize] >> ((number % eltsize) * factor)) & ((1 << factor) - 1); | |
126 } | |
127 } | |
128 | |
129 void Flags::Set(VarInfo info, int value) { | |
130 int type = info.type / 26; | |
131 int index = info.type % 26; | |
132 if (index == 25) { | |
133 if (uint(info.number) >= 2000) return; | |
134 if (value == 0) | |
135 cgm_data.erase(info.number); | |
136 else | |
137 cgm_data.insert(info.number); | |
138 index = 7; | |
139 } | |
140 if (index == 10) index = 8; | |
141 if (index == 11) index = 9; | |
142 if (index < 0 || index > TYPE_VARMAX) { | |
143 fprintf(stderr,"Error: invalid access to Var<%d>[%d]\n",info.type,info.number); | |
144 } | |
145 if (type == 0) { | |
146 // A[]..G[], Z[] を直に書く | |
147 if (uint(info.number) >= 2000) return; | |
148 var[index][info.number] = value; | |
149 } else { | |
150 // Ab[]..G4b[], Z8b[] などを書く | |
151 int factor = 1 << (type - 1); | |
152 int eltsize = 32 / factor; | |
153 int eltmask = (1 << factor) - 1; | |
154 int shift = (info.number % eltsize) * factor; | |
155 if (uint(info.number) >= (64000 / factor)) return; | |
156 var[index][info.number / eltsize] = | |
157 (var[index][info.number / eltsize] & ~(eltmask << shift)) | |
158 | (value & eltmask) << shift; | |
159 } | |
160 } | |
161 | |
162 void Flags::SetSys(int value) { | |
163 sys = value; | |
164 } | |
165 void Flags::SetStr(VarInfo info, string val) { | |
166 switch(info.type) { | |
167 case TYPE_VARLOCSTR: | |
168 if (info.number >= 3) return; | |
169 loc_str[info.number] = val; | |
170 break; | |
171 case TYPE_VARSYSSTR: | |
172 if (info.number >= 2000) return; | |
173 sys_str[info.number] = val; | |
174 break; | |
175 case TYPE_VARSTR: | |
176 if (info.number >= 2000) return; | |
177 str[info.number] = val; | |
178 break; | |
179 } | |
180 return; | |
181 } | |
182 void Flags::Str(int type, unsigned int number, char* buf, int sz) const { | |
183 if (sz <= 0) return; | |
184 buf[0] = 0; | |
185 const string* sptr; | |
186 switch(type) { | |
187 case TYPE_VARLOCSTR: | |
188 if (number >= 3) return; | |
189 sptr = &loc_str[number]; | |
190 break; | |
191 case TYPE_VARSYSSTR: | |
192 if (number >= 2000) return; | |
193 sptr = &sys_str[number]; | |
194 break; | |
195 case TYPE_VARSTR: | |
196 if (number >= 2000) return; | |
197 sptr = &str[number]; | |
198 break; | |
199 } | |
200 | |
201 int len = sptr->length(); | |
202 if (sz-1 > len) sz = len; | |
203 sptr->copy(buf, sz, 0); | |
204 buf[sz] = 0; | |
205 return; | |
206 } | |
207 string Flags::Str(int type, unsigned int number) const { | |
208 switch(type) { | |
209 case TYPE_VARLOCSTR: | |
210 if (number >= 3) return ""; | |
211 return loc_str[number]; | |
212 case TYPE_VARSYSSTR: | |
213 if (number >= 2000) return ""; | |
214 return sys_str[number]; | |
215 case TYPE_VARSTR: | |
216 if (number >= 2000) return ""; | |
217 return str[number]; | |
218 } | |
219 return ""; | |
220 } | |
221 | |
222 void Flags::Save(string& save) { | |
223 char buf[1024]; | |
224 save = "\n[Flags]\n"; | |
225 int i,j; | |
226 for (i=0; i<=TYPE_NONSYSVARMAX; i++) { | |
227 for (j=0; j<2000; j++) { | |
228 if (var[i][j] != 0) { | |
229 sprintf(buf, "V<%d>[%04d]=%d\n",i,j,var[i][j]); | |
230 save += buf; | |
231 } | |
232 } | |
233 } | |
234 for (j=0; j<2000; j++) { | |
235 if (str[j].length() != 0) { | |
236 sprintf(buf, "V<C>[%04d]=%s\n", j, str[j].c_str()); | |
237 save += buf; | |
238 } | |
239 } | |
240 } | |
241 void Flags::Load(const char* save) { | |
242 int i,j; | |
243 for (i=0; i<=TYPE_NONSYSVARMAX; i++) { | |
244 for (j=0; j<2000; j++) { | |
245 var[i][j] = 0; | |
246 } | |
247 } | |
248 sys = 0; | |
249 for (j=0; j<2000; j++) { | |
250 str[j] = ""; | |
251 } | |
252 | |
253 save = strstr(save, "\n[Flags]\n"); | |
254 | |
255 if (save) { | |
256 save += strlen("\n[Flags]\n"); | |
257 do { | |
258 if (save[0] == '[') break; // next section | |
259 if (strncmp(save, "V<",2) == 0) { | |
260 if (strncmp(save, "V<C>[",5) == 0) { // string | |
261 char buf[1024]; | |
262 int n; | |
263 if (sscanf(save, "V<C>[%04d]=",&n) == 1) { | |
264 char* s = strchr(save, '='); | |
265 s++; | |
266 char* send = strchr(s, '\n'); | |
267 int slen = send - s; | |
268 strncpy(buf, s, slen); | |
269 buf[slen] = 0; | |
270 if (n >= 0 && n < 2000) str[n] = buf; | |
271 } | |
272 } else if (save[2] >= '0' && save[2] <= '9') { | |
273 int c,n,v; | |
274 if (sscanf(save, "V<%d>[%04d]=%d\n",&c,&n,&v) == 3) { | |
275 if (c >= 0 && c <= TYPE_NONSYSVARMAX && n >= 0 && n < 2000) | |
276 var[c][n] = v; | |
277 } | |
278 } | |
279 } | |
280 save = strchr(save, '\n'); | |
281 if (save) save++; | |
282 } while (save); | |
283 } | |
284 return; | |
285 } | |
286 | |
287 void Flags::SaveSys(string& save) { | |
288 char buf[1024]; | |
289 int j; | |
290 save = "\n[Flags]\n"; | |
291 for (j=0; j<2000; j++) { | |
292 if (var[6][j] != 0) { | |
293 sprintf(buf, "V<6>[%04d]=%d\n",j,var[6][j]); | |
294 save += buf; | |
295 } | |
296 } | |
297 for (j=0; j<2000; j++) { | |
298 if (var[7][j] != 0) { | |
299 sprintf(buf, "V<25>[%04d]=%d\n",j,var[7][j]); | |
300 save += buf; | |
301 } | |
302 } | |
303 for (j=0; j<2000; j++) { | |
304 if (sys_str[j].length() != 0) { | |
305 sprintf(buf, "V<M>[%04d]=%s\n", j, sys_str[j].c_str()); | |
306 save += buf; | |
307 } | |
308 } | |
309 } | |
310 void Flags::LoadSys(const char* save) { | |
311 int i,j; | |
312 for (i=6; i<=7; i++) { | |
313 for (j=0; j<2000; j++) { | |
314 var[i][j] = 0; | |
315 } | |
316 } | |
317 for (j=0; j<2000; j++) { | |
318 sys_str[j] = ""; | |
319 } | |
320 sys = 0; | |
321 | |
322 save = strstr(save, "\n[Flags]\n"); | |
323 | |
324 if (save) { | |
325 save += strlen("\n[Flags]\n"); | |
326 do { | |
327 if (save[0] == '[') break; // next section | |
328 if (strncmp(save, "V<",2) == 0) { | |
329 if (strncmp(save, "V<M>[",5) == 0) { // string | |
330 char buf[1024]; | |
331 int n; | |
332 if (sscanf(save, "V<M>[%04d]=",&n) == 1) { | |
333 char* s = strchr(save, '='); | |
334 s++; | |
335 char* send = strchr(s, '\n'); | |
336 int slen = send - s; | |
337 strncpy(buf, s, slen); | |
338 buf[slen] = 0; | |
339 if (n >= 0 && n < 2000) sys_str[n] = buf; | |
340 } | |
341 } else if (save[2] >= '0' && save[2] <= '9') { | |
342 int c,n,v; | |
343 if (sscanf(save, "V<%d>[%04d]=%d\n",&c,&n,&v) == 3) { | |
344 if (c == 6 && n >= 0 && n < 2000) | |
345 var[6][n] = v; | |
346 else if (c == 25 && n >= 0 && n < 2000) | |
347 var[7][n] = v; | |
348 } | |
349 } | |
350 } | |
351 save = strchr(save, '\n'); | |
352 if (save) save++; | |
353 } while (save); | |
354 } | |
355 return; | |
356 } | |
357 | |
358 bool Flags::Exec(Cmd& cmd) { | |
359 if (cmd.cmd_type == CMD_FLAGS) { // 代入演算 | |
360 if (cmd.args.size() != 2) return false; | |
361 Set(cmd.args[0], cmd.args[1].value); | |
362 cmd.clear(); | |
363 return true; | |
364 } | |
365 if (cmd.cmd1 == 1 && cmd.cmd2 == 0x0a) { // 文字列演算 | |
366 VarInfo arg1 = cmd.args[0]; | |
367 switch(cmd.cmd3) { | |
368 case 0: | |
369 if (cmd.cmd4 == 0) { | |
370 SetStr(arg1, cmd.Str(cmd.args[1])); | |
371 } else if (cmd.cmd4 == 1) { | |
372 string s = cmd.Str(cmd.args[1]); | |
373 const char* sc = s.c_str(); | |
374 int len = cmd.args[2].value; | |
375 int i;for (i=0; i<sc[i]!=0 && len != 0; i++, len--) { | |
376 if (sc[i]<0 && sc[i+1]!=0) i++; | |
377 } | |
378 s.erase(i); // 全角で len 文字まで切り詰める | |
379 SetStr(arg1, s); | |
380 // fprintf(stderr,"Set[%d,%d]<-%s\n",arg1.type,arg1.number,s.c_str()); | |
381 } else break; | |
382 cmd.clear(); | |
383 break; | |
384 case 1: | |
385 if (cmd.cmd4 == 0) { | |
386 SetStr(arg1, ""); | |
387 cmd.clear(); | |
388 } else if (cmd.cmd4 == 1) { | |
389 // 領域指定で文字列クリア | |
390 VarInfo v1 = cmd.args[0]; | |
391 VarInfo v2 = cmd.args[1]; | |
392 eprintf("memclear(str). Var[%d]<%d> - Var[%d]<%d>\n",v1.type, v1.number, v2.type, v2.number); | |
393 if (v1.type != v2.type || (v1.type != TYPE_VARSTR && v1.type != TYPE_VARSYSSTR && v1.type != TYPE_VARLOCSTR)) { | |
394 eprintf(" error: bad args\n"); | |
395 } else { | |
396 if (v1.number < 0) v1.number = 0; | |
397 if (v2.number > 2000) v2.number = 2000; | |
398 for (; v1.number <= v2.number; v1.number++) { | |
399 SetStr(v1, ""); | |
400 } | |
401 } | |
402 cmd.clear(); | |
403 } | |
404 case 2: | |
405 SetStr(arg1, Str(arg1.type,arg1.number) + cmd.Str(cmd.args[1])); | |
406 // fprintf(stderr,"Append[%d,%d]<-%s(%d:%d)\n",arg1.type,arg1.number,Str(arg1.type,arg1.number).c_str(),cmd.args[1].type,cmd.args[1].number); | |
407 cmd.clear(); | |
408 break; | |
409 case 3: | |
410 SetSys(strlen(cmd.Str(cmd.args[0]))); | |
411 cmd.clear(); | |
412 break; | |
413 case 4: | |
414 { int v = strcmp(cmd.Str(cmd.args[0]), cmd.Str(cmd.args[1])); | |
415 // string s1=cmd.Str(cmd.args[0]); | |
416 // string s2=cmd.Str(cmd.args[1]); | |
417 // fprintf(stderr,"Cmp %s(%d:%d):%s(%d:%d):%d\n",s1.c_str(),cmd.args[0].type,cmd.args[0].number,s2.c_str(),cmd.args[1].type,cmd.args[1].number,v); | |
418 if (v < 0) SetSys(-1); | |
419 else if (v > 0) SetSys(1); | |
420 else SetSys(0); | |
421 cmd.clear(); | |
422 break; } | |
423 case 5: // substring, index from left | |
424 case 6: // substring, index from right | |
425 // 全角対応らしい | |
13 | 426 //FIXME: Make sure it works properly |
0 | 427 { int offset = cmd.args[2].value; |
428 int len = strlen(cmd.Str(cmd.args[1])); | |
429 string str = cmd.Str(cmd.args[1]); | |
430 const char* s = str.c_str(); | |
431 if (cmd.cmd3 == 6) offset = len - offset; | |
432 if (offset < 0) offset = 0; | |
433 // 先頭 N 文字を読み飛ばす | |
434 int i; | |
435 int offset_top = 0; | |
436 for (i=0; i<offset && s[offset_top] != 0; i++) { | |
437 if (s[offset_top] < 0 && s[offset_top+1] != 0) offset_top += 2; | |
438 else offset_top += 1; | |
439 } | |
440 if (s[offset_top] == 0) { | |
441 SetStr(arg1, ""); | |
442 } else if (cmd.cmd4 == 0) { // 長さ制限なし | |
13 | 443 SetStr(arg1, string(s, offset_top, len-offset_top)); |
0 | 444 } else { // cmd.cmd4 == 1 |
445 int slen = cmd.args[3].value; | |
446 int offset_end = offset_top; | |
447 for (i=0; i<slen && s[offset_end] != 0; i++) { | |
448 if (s[offset_end] < 0 && s[offset_end]+1 != 0) offset_end += 2; | |
449 else offset_end += 1; | |
450 } | |
451 string result(s, offset_top, offset_end-offset_top); | |
452 SetStr(arg1, result); | |
453 } | |
454 cmd.clear(); | |
455 break; } | |
456 case 7: {// strlen w/ kanji | |
457 const char* s = cmd.Str(cmd.args[0]); int i; | |
458 for (i=0; *s != 0; i++) { | |
459 if (*s < 0 && s[1] != 0) s += 2; | |
460 else s++; | |
461 } | |
462 SetSys(i); | |
463 cmd.clear(); | |
464 break; } | |
465 case 8: // 文字列を切って短くする | |
466 if (cmd.args[1].value <= 0) { | |
467 SetStr(arg1, ""); | |
468 } else if (cmd.args[1].value < strlen(cmd.Str(cmd.args[1]))) { | |
469 Str(arg1.type,arg1.number).erase(cmd.args[1].value); | |
470 } | |
471 cmd.clear(); | |
472 break; | |
473 case 0x0e: // 漢字モードでitoa | |
474 { | |
475 int arg1 = cmd.args[0].value; | |
476 string result; | |
477 char wc[3]; wc[2]=0; | |
478 char buf[20]; | |
479 if (cmd.cmd4 == 0) { | |
480 sprintf(buf, "%d", arg1); | |
481 } else { // cmd.cmd4 == 1 | |
482 char fmt[20]; | |
483 sprintf(fmt, "%%%dd", cmd.args[2].value); | |
484 sprintf(buf, fmt, arg1); | |
485 } | |
486 int i; | |
487 for (i=0; buf[i] != 0; i++) { | |
488 if (buf[i] == ' ') { | |
489 wc[0] = 0x81; | |
490 wc[0] = 0x40; | |
491 } else if (buf[i] == '-') { | |
492 wc[0] = 0x81; | |
493 wc[0] = 0x7c; | |
494 } else if (isdigit(buf[i])) { | |
495 wc[0] = 0x82; | |
496 wc[1] = buf[i] - '0' + 0x4f; | |
497 } else { | |
498 continue; | |
499 } | |
500 result += wc; | |
501 } | |
502 SetStr(cmd.args[1], result); | |
503 cmd.clear(); | |
504 } | |
505 break; | |
506 case 0x0f: case 0x11: // itoa (0x11 の方は zero padding するっぽい) | |
507 if (cmd.cmd4 == 0) { | |
508 int arg1 = cmd.args[0].value; | |
509 char buf[1024]; sprintf(buf, "%d", arg1); | |
510 SetStr(cmd.args[1], buf); | |
511 cmd.clear(); | |
512 } else if (cmd.cmd4 == 1) { | |
513 // 漢字(SJIS) : 82 [4f+N] | |
514 // やはり漢字じゃない? | |
515 int arg1 = cmd.args[0].value; | |
516 char buf[1024]; char fmt[1024]; | |
517 if (cmd.cmd3 == 0x0f) { | |
518 sprintf(fmt, "%%%dd",cmd.args[2].value); /* 空白でパディング */ | |
519 } else { | |
520 sprintf(fmt, "%%0%dd",cmd.args[2].value); | |
521 } | |
522 sprintf(buf, fmt, arg1); | |
523 SetStr(cmd.args[1], buf); | |
524 cmd.clear(); | |
525 } | |
526 break; | |
527 case 0x64: // 文字列の表示 : 引数をテキストウィンドウに表示 | |
528 if (cmd.cmd4 == 1) { | |
529 char buf[256]; | |
530 snprintf(buf, 255, "%d", Get(cmd.args[0].type, cmd.args[0].number)); | |
531 cmd.args[0].type = TYPE_STR; | |
532 cmd.args[0].value = cmd.AddStr(buf); | |
533 cmd.cmd4 = 0; | |
534 } | |
535 | |
536 #if 0 | |
537 @@@ | |
538 save 27 | |
539 ともよメガネのところ | |
540 - オブジェクト関連:seen9061:0 呼び出しで黒い背景画をかさねるところ、変になる | |
541 @@@ | |
542 %Xで置換する名前の設定。0x51e で読みだし。セーブファイルごとに保存されるはずなので実装を考えること | |
543 %は0-3 (4 以降は使ってない)で、渚、秋生、渚、伊吹先生、など | |
544 StrVar を拡張して代入すること | |
545 初期値はこの辺 | |
546 Text側に納め、セーブファイルでも同じようにすべきだろうなあ | |
547 args:0,"渚" | |
548 args:1,"秋生" | |
549 args:2,"渚" | |
550 args:3,"伊吹先生" | |
551 args:4,"朋也くん" | |
552 args:5,"岡崎さん" | |
553 | |
554 | |
555 106737 : 0x23 - cmd 01-04:051f:00[ 2] | |
556 args:0,"古河" | |
557 106758 : line 1712 | |
558 106761 : 0x23 - cmd 01-04:051f:00[ 2] | |
559 args:2,"古河" | |
560 106782 : line 1713 | |
561 106785 : 0x23 - cmd 01-04:051f:00[ 2] | |
562 args:4,"岡崎さん" | |
563 | |
564 47382 : 0x23 - cmd 01-04:051e:00[ 2] | |
565 args:4,V<18>[0](=0) | |
566 | |
567 47408 : 0x23 - cmd 01-0a:0004:00[ 2] | |
568 args:V<18>[0](=0),"岡崎さん" | |
569 47437 : expr: V<0>[1000](=0)=V<sys> | |
570 47451 : 0x23 - cmd 01-0a:0004:00[ 2] | |
571 args:V<18>[0](=0),"朋也くん" | |
572 47480 : expr: V<0>[1001](=0)=V<sys> | |
573 47494 : V<0>[1000](=0)==0(=true)-> 47589 | |
574 47526 : 0x23 - cmd 01-04:0514:00[ 2] | |
575 args:0,V<18>[0](=0) /* NAME.A を帰す */ | |
576 47552 : 0x23 - cmd 01-0a:0002:00[ 2] | |
577 args:V<18>[0](=0),"さん" | |
578 47577 : jmp -> 47672 | |
579 47589 : V<0>[1001](=0)==0(=true)-> 47672 | |
580 47621 : 0x23 - cmd 01-04:0514:00[ 2] | |
581 args:1,V<18>[0](=0) /* NAME.B を帰す */ | |
582 47647 : 0x23 - cmd 01-0a:0002:00[ 2] | |
583 args:V<18>[0](=0),"くん" | |
584 47672 : pos. 279 | |
585 47675 : 0x23 - cmd 01-0a:0064:00[ 1] | |
586 args:V<18>[0](=0) | |
587 | |
588 #endif | |
589 cmd.cmd_type = CMD_TEXT; | |
590 break; | |
591 } | |
592 } | |
593 if (cmd.cmd1 == 1 && cmd.cmd2 == 0x0b) { // 数値変数演算 | |
594 if (cmd.cmd3 == 0 && cmd.cmd4 == 0) { | |
595 /* 複数の変数をセット */ | |
596 VarInfo v1 = cmd.args[0]; | |
597 eprintf("set multiple-var Var[%d]<%d> <- ",v1.type, v1.number); | |
598 int i; | |
599 if (cmd.args.size() < cmd.argc) { | |
600 eprintf(" error: argsize changed %d -> %d\n",cmd.argc, cmd.args.size()); | |
601 cmd.argc = cmd.args.size(); | |
602 } | |
603 for (i=0; i<cmd.argc; i++) { | |
604 eprintf("%d, ",cmd.args[i+1].value); | |
605 Set(v1, cmd.args[i+1].value); | |
606 v1.number++; | |
607 } | |
608 eprintf("\n"); | |
609 cmd.clear(); | |
610 } else if (cmd.cmd3 == 1 && cmd.cmd4 == 0) { | |
611 /* 領域指定で変数をクリア */ | |
612 VarInfo v1 = cmd.args[0]; | |
613 VarInfo v2 = cmd.args[1]; | |
614 eprintf("memclear. Var[%d]<%d> - Var[%d]<%d>\n",v1.type, v1.number, v2.type, v2.number); | |
615 if (v1.type != v2.type || !IsInt(v1.type)) eprintf(" error: bad args\n"); | |
616 else { | |
617 if (v1.number < 0) v1.number = 0; | |
618 if (v2.number > MaxIndex(v2.type)) v2.number = MaxIndex(v2.type); | |
619 for (; v1.number <= v2.number; v1.number++) | |
620 Set(v1, 0); | |
621 } | |
622 cmd.clear(); | |
623 } else if (cmd.cmd3 == 1 && cmd.cmd4 == 1) { | |
624 /* 領域指定で変数をセット */ | |
625 VarInfo v1 = cmd.args[0]; | |
626 VarInfo v2 = cmd.args[1]; | |
627 int value = cmd.args[2].value; | |
628 eprintf("memset. Var[%d]<%d> - Var[%d]<%d> <- %d\n",v1.type, v1.number, v2.type, v2.number, value); | |
629 if (v1.type != v2.type || !IsInt(v1.type)) eprintf(" error: bad args\n"); | |
630 else { | |
631 if (v1.number < 0) v1.number = 0; | |
632 if (v2.number > MaxIndex(v2.type)) v2.number = MaxIndex(v2.type); | |
633 for (; v1.number <= v2.number; v1.number++) | |
634 Set(v1, value); | |
635 } | |
636 cmd.clear(); | |
637 } else if (cmd.cmd3 == 4 && cmd.cmd4 == 1) { // 領域クリア(sysfunc.txt) | |
638 VarInfo v1 = cmd.args[0]; | |
639 int step = cmd.args[1].value; | |
640 int deal = cmd.args[2].value; | |
641 int val = cmd.args[3].value; | |
642 eprintf("memclear. Var[%d]<%d> step %d deal %d <- val %d\n",v1.type, v1.number, step, deal, val); | |
643 int i; for (i=0; i<deal; i++) { | |
644 Set(v1, val); | |
645 v1.number += step; | |
646 } | |
647 cmd.clear(); | |
648 } else if (cmd.cmd3 == 0x64 && cmd.cmd4 == 0) { //領域で数値を合計する | |
649 VarInfo v1 = cmd.args[0]; | |
650 VarInfo v2 = cmd.args[1]; | |
651 eprintf("sum var. Var[%d]<%d> - Var[%d]<%d>\n",v1.type, v1.number, v2.type, v2.number); | |
652 int sum = 0; | |
653 if (v1.type != v2.type || !IsInt(v1.type)) eprintf(" error: bad args\n"); | |
654 else { | |
655 if (v1.number < 0) v1.number = 0; | |
656 if (v2.number > MaxIndex(v2.type)) v2.number = MaxIndex(v2.type); | |
657 for (; v1.number <= v2.number; v1.number++) | |
658 sum += (*this)(v1); | |
659 } | |
660 eprintf(" ret %d\n",sum); | |
661 cmd.SetSysvar(sum); | |
662 } | |
663 } | |
664 return false; | |
665 } | |
666 | |
667 /********************************************************************* | |
668 ** Cmd | |
669 */ | |
670 | |
671 /* 数値 num := 0x24 0xff <int num> */ | |
672 /* 変数 var := 0x24 <uchar type> 0x5b <exp> 0x5d */ | |
673 /* 項 token := num | var | 0x28 <exp> 0x29 | <plus|minus> token */ | |
674 | |
675 int Cmd::GetLeftToken(const char*& d, VarInfo& info) { | |
676 bool var_flag = true; | |
677 int minus_flag = 0; | |
678 int value = 0; | |
679 if (d[0] == 0x5c && (d[1] == 1 || d[1] == 0) ) { | |
680 if (d[1] == 1) {dprintf("minus-"); minus_flag ^= 1;} | |
681 else dprintf("plus-"); | |
682 d += 2; | |
683 var_flag = false; | |
684 } | |
685 if (d[0] == 0x24 && ((unsigned const char*)d)[1] == 0xff) { | |
686 // if ( (d[0] == 0x30 || d[0] == 0x31) && d[1] == 0x24 && ((unsigned const char*)d)[2] == 0xff) /* @@@ not supported; selection 内で、0x30|0x31 が付随することがある */ | |
687 // numerical atom | |
688 d += 6; | |
689 value = read_little_endian_int(d-4); | |
690 dprintf("%d",value); | |
691 var_flag = false; | |
692 } else if (d[0] == 0x24 && *(unsigned char*)(d+1) == 0xc8) { | |
693 dprintf("V<sys>"); | |
694 d += 2; | |
695 info.type = TYPE_SYS; info.number = 0; | |
696 value = info.value = flags(); | |
697 } else if (d[0] == 0x24 && d[2] == 0x5b) { | |
698 // 0x24,<type>,0x5b,<expr>,0x5d-terminated term | |
699 info.type = *(unsigned char*)(d+1); | |
700 d += 3; | |
701 dprintf("V<%d>[",info.type); | |
702 info.number = GetExpression(d); | |
703 dprintf("]"); | |
704 if (*d == 0x5d) d++; | |
705 else SetError(); | |
706 if (info.type == TYPE_VARSTR || info.type == TYPE_VARSYSSTR || info.type == TYPE_VARLOCSTR) { | |
707 value = 0; | |
708 info.value = StrVar(info.type, info.number); | |
709 } else { | |
710 value = info.value = flags(info); | |
711 } | |
712 dprintf("(=%d)",value); | |
713 } else SetError(); | |
714 | |
715 if (minus_flag) value = -value; | |
716 if (!var_flag) { | |
717 info.type = TYPE_VAL; | |
718 info.value = value; | |
719 } | |
720 return value; | |
721 } | |
722 | |
723 static char* op_str[70] = { | |
724 // 0 1 2 3 4 5 6 7 8 9 | |
725 "+", "-", "*", "/", "%", "&", "|", "^", "<<", ">>", // +00 | |
726 "err.","err.","err.","err.","err.","err.","err.","err.","err.","err.", // +10 | |
727 "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>=", // +20 | |
728 "=", "err.","err.","err.","err.","err.","err.","err.","err.","err.", // +30 | |
729 "==", "!=", "<=", "<", ">=", ">", "err.","err.","err.","err.", // +40 | |
730 "err.","err.","err.","err.","err.","err.","err.","err.","err.","err.", // +50 | |
731 "&&", "||", "err.","err.","err.","err.","err.","err.","err.","err.", // +60 | |
732 }; | |
733 | |
734 static int op_pri_tbl[12] = { | |
735 // + - * / % & | ^ << >> | |
736 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 10, 10}; | |
737 | |
738 inline int op_pri(int op) { | |
739 if (op > 11) return 10; | |
740 return op_pri_tbl[op]; | |
741 } | |
742 inline int op_pri_cond(int op) { | |
743 if (op <= 11) return op_pri_tbl[op]; | |
744 else if (op < 50) return 7; | |
745 else if (op == 60) return 8; | |
746 else if (op == 61) return 8; | |
747 else return 10; | |
748 } | |
749 | |
750 | |
751 inline int eval(int v1, int op, int v2) { | |
752 switch(op) { | |
753 case 0: return v1+v2; | |
754 case 1: return v1-v2; | |
755 case 2: return v1*v2; | |
756 case 3: return v2!=0 ? v1/v2 : v1; | |
757 case 4: return v2!=0 ? v1%v2 : v1; | |
758 case 5: return v1&v2; | |
759 case 6: return v1|v2; | |
760 case 7: return v1^v2; | |
761 case 8: return v1<<v2; | |
762 case 9: return v1>>v2; | |
763 case 40: return v1 == v2; | |
764 case 41: return v1 != v2; | |
765 case 42: return v1 <= v2; | |
766 case 43: return v1 < v2; | |
767 case 44: return v1 >= v2; | |
768 case 45: return v1 > v2; | |
769 case 60: return v1 && v2; | |
770 case 61: return v1 || v2; | |
771 } | |
772 return v2; | |
773 } | |
774 | |
775 /* 演算子 op := 0x5c <uchar op> */ | |
776 /* 数式 exp: [op] <token> [op <token> [...]] */ | |
777 int Cmd::GetExpression(const char*& d, VarInfo* info_ptr) { | |
778 #define STACK_DEPTH 1024 | |
779 #define OP_LB 11 | |
780 char op_stack[STACK_DEPTH]; | |
781 int val_stack[STACK_DEPTH]; | |
782 int stack_count = 0; | |
783 | |
784 // 第一項の読み込み | |
785 while(*d == 0x28) { | |
786 d++; | |
787 dprintf("("); | |
788 op_stack[stack_count++] = OP_LB; | |
789 } | |
790 VarInfo info; | |
791 int value = GetLeftToken(d, info); | |
792 | |
793 while(*d == 0x29 && stack_count > 0 && op_stack[stack_count-1] == OP_LB) { | |
794 d++; | |
795 dprintf(")"); | |
796 stack_count--; | |
797 } | |
798 | |
799 if (*d != 0x5c && stack_count == 0) { | |
800 if (info_ptr) *info_ptr = info; | |
801 return value; // 単純なleft-termはここで終了。有効なinfo_ptrを帰す(可能性がある) | |
802 } | |
803 | |
804 while(*d == 0x5c) { | |
805 int op_type = *(unsigned char*)(d+1); | |
806 d += 2; | |
807 if (op_type < 70) dprintf("%s",op_str[op_type]); | |
808 else dprintf("err."); | |
809 if (op_type >= 10) SetError(); | |
810 int cur_pri = op_pri(op_type); | |
811 while(stack_count != 0 && op_pri(op_stack[stack_count-1]) <= cur_pri) { | |
812 // 優先順位の高い、先行する演算を行う | |
813 value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value); | |
814 stack_count--; | |
815 } | |
816 val_stack[stack_count] = value; | |
817 op_stack[stack_count++] = op_type; | |
818 while(*d == 0x28) { | |
819 d++; | |
820 dprintf("("); | |
821 op_stack[stack_count++] = OP_LB; | |
822 } | |
823 if (stack_count >= STACK_DEPTH) SetError(); | |
824 value = GetLeftToken(d, info); | |
825 | |
826 while (*d != 0x5c && stack_count > 0) { | |
827 // 未実行の演算を終わらせる | |
828 if (op_stack[stack_count-1] != OP_LB) { | |
829 value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value); | |
830 stack_count--; | |
831 } else if (*d == 0x29) { /* op_stack == OP_LB */ | |
832 // bracket 終端があれば、閉じておく | |
833 d++; | |
834 dprintf(")"); | |
835 stack_count--; | |
836 } else break; // error | |
837 } | |
838 } | |
839 if (stack_count) SetError(); // unbalanced bracket | |
840 dprintf("(=%d)",value); | |
841 if (info_ptr) { | |
842 info_ptr->type = TYPE_VAL; | |
843 info_ptr->value = value; | |
844 } | |
845 return value; | |
846 } | |
847 | |
848 // 条件分岐専用に、条件演算と算術演算の混合を検知できる専用ルーチン(本来はGetExpressionで差し支えない) | |
849 int Cmd::GetExpressionCond(const char*& d) { | |
850 char op_stack[STACK_DEPTH]; | |
851 int val_stack[STACK_DEPTH]; | |
852 int valattr_stack[STACK_DEPTH]; | |
853 #define ATTR_VAL 0 | |
854 #define ATTR_FLAG 1 | |
855 int stack_count = 0; | |
856 | |
857 // 第一項の読み込み | |
858 while(*d == 0x28) { | |
859 d++; | |
860 dprintf("("); | |
861 op_stack[stack_count++] = OP_LB; | |
862 } | |
863 VarInfo info; | |
864 int value = GetLeftToken(d, info); | |
865 while(*d == 0x29 && stack_count > 0 && op_stack[stack_count-1] == OP_LB) { | |
866 d++; | |
867 dprintf(")"); | |
868 stack_count--; | |
869 } | |
870 bool valattr = ATTR_VAL; | |
871 | |
872 while(*d == 0x5c) { | |
873 int op_type = *(unsigned char*)(d+1); | |
874 d += 2; | |
875 if (op_type < 70) dprintf("%s",op_str[op_type]); | |
876 else dprintf("err."); | |
877 int cur_pri = op_pri_cond(op_type); | |
878 while(stack_count != 0 && op_pri_cond(op_stack[stack_count-1]) <= cur_pri) { | |
879 // 優先順位の高い、先行する演算を行う | |
880 if (op_stack[stack_count-1] >= 60) { | |
881 if (valattr_stack[stack_count-1] != ATTR_FLAG || valattr != ATTR_FLAG) SetError(); | |
882 } else { | |
883 if (valattr_stack[stack_count-1] != ATTR_VAL || valattr != ATTR_VAL) SetError(); | |
884 } | |
885 value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value); | |
886 if (op_stack[stack_count-1] >= 40) valattr = ATTR_FLAG; | |
887 stack_count--; | |
888 } | |
889 val_stack[stack_count] = value; | |
890 valattr_stack[stack_count] = valattr; | |
891 op_stack[stack_count++] = op_type; | |
892 while(*d == 0x28) { | |
893 d++; | |
894 dprintf("("); | |
895 op_stack[stack_count++] = OP_LB; | |
896 } | |
897 if (stack_count >= STACK_DEPTH) SetError(); | |
898 value = GetLeftToken(d, info); | |
899 valattr = ATTR_VAL; | |
900 | |
901 while (*d != 0x5c && stack_count > 0) { | |
902 // 未実行の演算を終わらせる | |
903 if (op_stack[stack_count-1] != OP_LB) { | |
904 if (op_stack[stack_count-1] >= 60) { | |
905 if (valattr_stack[stack_count-1] != ATTR_FLAG || valattr != ATTR_FLAG) SetError(); | |
906 } else { | |
907 if (valattr_stack[stack_count-1] != ATTR_VAL || valattr != ATTR_VAL) SetError(); | |
908 } | |
909 value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value); | |
910 if (op_stack[stack_count-1] >= 40) valattr = ATTR_FLAG; | |
911 stack_count--; | |
912 // bracket 終端があれば、閉じておく | |
913 } else if (*d == 0x29) { /* op_stack == OP_LB */ | |
914 d++; | |
915 dprintf(")"); | |
916 stack_count--; | |
917 } else break; // error | |
918 } | |
919 } | |
920 if (stack_count) SetError(); // unbalanced bracket | |
921 if (value) dprintf("(=true)"); | |
922 else dprintf("(=false)"); | |
923 return value; | |
924 } | |
925 | |
926 | |
927 /* | |
928 str = | |
929 arg = | |
930 args = 0x28 <exp> [[0x2c] <exp> [[0x2c] <exp> [...] ]] | |
931 */ | |
932 | |
933 int Cmd::GetArgs(const char*& d) { | |
934 if (*d != 0x28) return 0; /* 引数なし */ | |
935 d++; | |
936 dprintf("args:"); | |
937 VarInfo var; | |
938 int i; for (i=0; i<100 ; i++) { | |
939 /* number, variable, string の種別なく値を得る */ | |
940 if (*d == 0x61) { // よくわからない(智代アフター) | |
941 dprintf("*%d*",d[1]); | |
942 d += 2; | |
943 if (*d == 0x28) { | |
944 dprintf("{"); | |
945 GetArgs(d); // (A,B,C)節が含まれることがある | |
946 dprintf("}"); | |
947 } else { | |
948 dprintf("{}"); | |
949 } | |
950 } else if (d[0] == 0x0a || d[0] == 0x40) { // よくわからない (Little Busters!) | |
951 int var; | |
952 if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;} | |
953 else { var = read_little_endian_short(d+1); d += 3;} | |
954 dprintf("line %d; ",var); | |
955 } else if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0)) || *d == 0x28) { | |
956 GetExpression(d, &var); | |
957 args.push_back(var); | |
958 } else if (StrType(d)) { | |
959 var.type = TYPE_STR; | |
960 var.value = GetString(d); | |
961 args.push_back(var); | |
962 } else SetError(); | |
963 if (*d == 0x29) break; | |
964 if (*d == 0x2c) {d++;} // 次の arg が演算子で始まる、などがなければ存在しない | |
965 dprintf(","); | |
966 } | |
967 if (*d == 0x29) d++; | |
968 else SetError(); | |
969 return i; | |
970 } | |
971 | |
972 int Cmd::GetArgsSpecial(int normal_args,const char*& d) { | |
973 if (*d != 0x28) return 0; /* 引数なし */ | |
974 d++; | |
975 dprintf("args:"); | |
976 int i; for (i=0; i<normal_args; i++) { | |
977 /* number, variable, string の種別なく値を得る */ | |
978 if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0)) || *d == 0x28) { | |
979 GetExpression(d); | |
980 } else if (StrType(d)) { | |
981 GetString(d); | |
982 } else SetError(); | |
983 if (*d == 0x29) break; | |
984 if (*d == 0x2c) {d++;} // 次の arg が演算子で始まる、などがなければ存在しない | |
985 dprintf(","); | |
986 } | |
987 for (i=0; i<argc ; i++) { | |
988 if (*d == 0x28) { | |
989 /* | |
990 ** cmd 01-22:0c1c, 01-22:0835 | |
991 ** Princess Bride のカードが落ちるアニメの場面 | |
992 ** なお、_PBCARDANM* の画像はこのコマンドでのみ使われているので、特殊処理として無視することも可能 | |
993 ** | |
994 ** cmd 01-04:0276, 026c, 0270 | |
995 ** 複数の enum が args の数だけ続く処理。特殊処理として分離する | |
996 */ | |
997 dprintf("enum.<"); | |
998 /* (...) は列挙型 or 構造体の可能性がある */ | |
999 const char* d_orig = d; | |
1000 int pt = args.size(); args.push_back(VarInfo(0)); | |
1001 int count = GetArgs(d); | |
1002 args[pt] = VarInfo(count); | |
1003 dprintf(">"); | |
1004 } else if (*d == 0x61 && (d[1] >= 0x00 && d[1] <= 0x04) && d[2] == 0x28 ) { | |
1005 /* 使われるコマンドは 01-21:004b, 01-28:0064 のいずれか(R,C,PB,LO) | |
1006 ** それらのコマンドは | |
1007 ** arg1: 画像ファイル名 | |
1008 ** arg2 : Sel 番号 | |
1009 ** らしく、arg3 以降が 0x61 <00-04> (a,b,c,...) となる(ダンプ上は enum と表記される) | |
1010 ** () 内の引数はさまざまで、a のみ(画像ファイル名)、 | |
1011 ** a,b b=SEL? | |
1012 ** a,b,c (b,c)=座標? | |
1013 ** a,(b,c,d,e,f,g) b-g = src / dest? | |
1014 ** らしい | |
1015 */ | |
1016 dprintf("kasane. #%d <",d[1]); | |
1017 d += 2; | |
1018 int pt = args.size(); args.push_back(VarInfo(0)); | |
1019 int count = GetArgs(d); | |
1020 args[pt] = VarInfo(count); | |
1021 dprintf(">"); | |
1022 } else if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0))) { | |
1023 /* cmd 01-15:0028 ; 始めに 0x24 節があり、続いて 0x28 節になる */ | |
1024 VarInfo var; | |
1025 GetExpression(d, &var); | |
1026 args.push_back(var); | |
1027 i--; // この引数はargc の数には入らない | |
1028 } else SetError(); | |
1029 if (d[0] == 0x0a || d[0] == 0x40) { | |
1030 /* cmd 01-15:0028 ; 0x28 節の後に毎回 0x0a 節が来る */ | |
1031 int var; | |
1032 if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;} | |
1033 else { var = read_little_endian_short(d+1); d += 3;} | |
1034 dprintf("line %d; ",var); | |
1035 } | |
1036 if (*d == 0x29) break; | |
1037 if (*d == 0x2c) {d++;} // 次の arg が演算子で始まる、などがなければ存在しない | |
1038 dprintf(","); | |
1039 } | |
1040 if (*d == 0x29) d++; | |
1041 else SetError(); | |
1042 return 0; | |
1043 } | |
1044 | |
1045 /* switch | |
1046 <exp> | |
1047 0x7b | |
1048 <exp> <int> | |
1049 ... | |
1050 0x7d | |
1051 */ | |
1052 | |
1053 int Cmd::GetSwitch(const char*& d) { | |
1054 if (*d != 0x28) {SetError(); return -1;} | |
1055 d++; | |
1056 dprintf("switch. "); | |
1057 int var = GetExpression(d); | |
1058 if (*d != 0x29) {SetError(); return -1;} | |
1059 d++; | |
1060 dprintf("->\n"); | |
1061 if (*d == 0x7b) { | |
1062 d++; | |
1063 } else SetError(); | |
1064 | |
1065 int default_jmp = -1; int jmpto = -1; | |
1066 int i; for (i=0; i<argc; i++) { | |
1067 dprintf("\t"); | |
1068 if (*d++ != 0x28) {SetError(); return -1;} | |
1069 int item = -1; // default | |
1070 if (*d != 0x29) { | |
1071 int item = GetExpression(d); | |
1072 if (*d++ != 0x29) {SetError(); return -1;} | |
1073 int jmp = read_little_endian_int(d); | |
1074 if (var == item) { | |
1075 dprintf("(selected)"); | |
1076 jmpto = jmp; | |
1077 } | |
1078 dprintf(" -> %d\n", jmp); | |
1079 } else { | |
1080 d++; | |
1081 default_jmp = read_little_endian_int(d); | |
1082 } | |
1083 d += 4; | |
1084 } | |
1085 if (default_jmp != -1) { | |
1086 dprintf("default -> %d\n",default_jmp); | |
1087 if (jmpto == -1) jmpto = default_jmp; | |
1088 } | |
1089 if (*d == 0x7d) { | |
1090 d++; | |
1091 } else SetError(); | |
1092 return jmpto; | |
1093 } | |
1094 /* simple switch | |
1095 <exp> | |
1096 0x7b | |
1097 <int> | |
1098 ... | |
1099 0x7d | |
1100 */ | |
1101 int Cmd::GetSimpleSwitch(const char*& d) { | |
1102 if (*d != 0x28) {SetError(); return -1;} | |
1103 d++; | |
1104 dprintf("simple switch. "); | |
1105 int var = GetExpression(d); | |
1106 if (*d != 0x29) {SetError(); return -1;} | |
1107 d++; | |
1108 dprintf(" ->\n"); | |
1109 int jumpto = -1; | |
1110 if (*d == 0x7b) { | |
1111 d++; | |
1112 } else SetError(); | |
1113 int i; for (i=0; i<argc; i++) { | |
1114 int j = read_little_endian_int(d); | |
1115 d += 4; | |
1116 dprintf("\t%d -> %d\n", i+1, j); | |
1117 if (var == i) jumpto = j; | |
1118 } | |
1119 if (*d == 0x7d) { | |
1120 d++; | |
1121 } else SetError(); | |
1122 return jumpto; | |
1123 } | |
1124 | |
1125 /* | |
1126 selection | |
1127 ? <exp> | |
1128 0x7b | |
1129 <0x0a|0x40> <ushort | uint> | |
1130 */ | |
1131 void Cmd::GetSelection(const char*& d) { | |
1132 dprintf("selection. "); | |
1133 if (*d == 0x28) { | |
1134 d++; | |
1135 GetExpression(d); | |
1136 if (*d != 0x29) { SetError(); return;} | |
1137 d++; | |
1138 } | |
1139 if (*d == 0x7b) { | |
1140 d++; | |
1141 dprintf("{\n\t"); | |
1142 } else SetError(); | |
1143 int arg_count = 0; | |
1144 string text = ""; | |
1145 int cond_result = false; | |
1146 int sel_no = 0; | |
1147 while(*d != 0x7d) { | |
1148 if (d[0] == 0x0a || d[0] == 0x40) { | |
1149 int var; | |
1150 if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;} | |
1151 else { var = read_little_endian_short(d+1); d += 3;} | |
1152 dprintf("Line %d; ",var); | |
1153 if (text.length() != 0) { | |
1154 if (cond_result) ; // 条件節が true なら表示しない | |
1155 else { | |
1156 const char* str = text.c_str(); | |
1157 VarInfo var; | |
1158 var.type = TYPE_STR; | |
1159 var.value = CopyString(str); | |
1160 args.push_back(var); | |
1161 var.type = TYPE_VAL; | |
1162 var.value = sel_no; | |
1163 args.push_back(var); | |
1164 } | |
1165 sel_no++; | |
1166 } | |
1167 text = ""; | |
1168 cond_result = false; | |
1169 } else if (d[0] == 0x2c) { | |
1170 dprintf(":comma:"); | |
1171 } else if (d[0] == 0x28) { | |
1172 dprintf(":cond:"); | |
1173 d++; | |
1174 while(d[0] != 0x29) { | |
1175 int result = GetExpressionCond(d); // PRINT- 節でないばあい、条件表示。次は文字節、またはPRINT節のはず | |
1176 if (*d == 0x32) { // 0x32 なら、現在の条件節を表示しない | |
1177 d++; dprintf("##"); | |
1178 cond_result = result; | |
1179 } else if (*d == 0x31) { // 0x31 なら、現在の条件節を表示する | |
1180 // Little Busters! : この条件で正しいかは未検証 | |
1181 d++; dprintf("***"); | |
1182 cond_result = !result; | |
1183 } | |
1184 dprintf(":"); | |
1185 } | |
1186 d++; | |
1187 } else if (StrType(d)) { | |
1188 int strpt = GetString(d); | |
1189 text += strheap + strpt; | |
1190 arg_count++; | |
1191 dprintf("\n\t"); | |
1192 } else if (*d == 0x23 && strncmp(d,"###PRINT",8) == 0) { | |
1193 d += 8; | |
1194 if (d[0] != 0x28) SetError(); | |
1195 else { // 文字変数の内容の表示 | |
1196 d++; | |
1197 dprintf("Print."); | |
1198 VarInfo info; | |
1199 GetLeftToken(d, info); | |
1200 if (d[0] != 0x29 || info.type == -1) SetError(); | |
1201 d++; | |
21
d1bb7b365816
Fixed dynamic strings in selections (Fuko Pranks for instance)
thib
parents:
13
diff
changeset
|
1202 dprintf(";");/* |
0 | 1203 // 数値を全角文字に変換して登録 |
1204 char str[10], str2[20]; // itoa | |
1205 sprintf(str, "%d", info.value); | |
1206 int i; for (i=0; str[i] != 0; i++) { | |
1207 str2[i*2] = 0xa3; | |
1208 str2[i*2+1] = 0xb0 + str[i]-'0'; | |
1209 } | |
21
d1bb7b365816
Fixed dynamic strings in selections (Fuko Pranks for instance)
thib
parents:
13
diff
changeset
|
1210 str2[i*2] = 0;*/ |
d1bb7b365816
Fixed dynamic strings in selections (Fuko Pranks for instance)
thib
parents:
13
diff
changeset
|
1211 text += strheap + info.value; |
0 | 1212 } |
1213 } else { SetError(); break;} | |
1214 } | |
1215 d++; | |
1216 /* @@@ */ | |
1217 /* 一致しない場合があるのでコメントアウト */ | |
1218 // if (arg_count != argc) SetError(); | |
1219 dprintf("\n}\n"); | |
1220 return; | |
1221 } | |
1222 | |
1223 static char* op_str3[11] = { "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>=", "="}; | |
1224 void Cmd::GetCmd(Flags& flags_orig, const char*& d ) { | |
1225 if (d == 0) { SetError(); return;} | |
1226 if (cmd_type != CMD_NOP) return; | |
1227 | |
1228 cmdstr[0] = 0; | |
1229 rawdata = d; | |
1230 if (*d == 0x23) { /* コマンド */ | |
1231 cmd_type = CMD_OTHER; | |
1232 cmd1 = *(unsigned const char*)(d+1); | |
1233 cmd2 = *(unsigned const char*)(d+2); | |
1234 cmd3 = read_little_endian_short(d+3); | |
1235 argc = read_little_endian_short(d+5); | |
1236 cmd4 = *(unsigned const char*)(d+7); | |
1237 d += 8; | |
1238 /* verbose */ | |
1239 // dprintf(" 0x23 - cmd %02x-%02x:%04x:%02x[%2d] \n",cmd1,cmd2,cmd3,cmd4,argc); | |
1240 sprintf(cmdstr, "%02x-%02x:%04x:%02x",cmd1,cmd2,cmd3,cmd4); | |
1241 /* 引数を得る */ | |
1242 /* 特殊引数のもの */ | |
1243 int is_special = 0; | |
1244 if (cmd1 == 0) { | |
1245 if (cmd2 == 1) { | |
1246 int jump_arg = -1; | |
1247 if (cmd3 == 0 || cmd3 == 5) { | |
1248 /* gosub / goto */ | |
1249 jump_arg =read_little_endian_int(d); | |
1250 d += 4; | |
1251 if (cmd3 == 0) | |
1252 dprintf("\tjmp -> %d\n", jump_arg); | |
1253 else /* cmd3 == 5 */ | |
1254 dprintf("\tcall -> %d\n", jump_arg); | |
1255 is_special = 1; | |
1256 } else if (cmd3 == 1 || cmd3 == 2) { | |
1257 /* conditional jump (if / unless) */ | |
1258 if (*d++ != 0x28) { SetError(); return;} | |
1259 dprintf("\t"); | |
1260 int cond = GetExpressionCond(d); | |
1261 if (cmd3 == 1) cond = !cond; // 逆になる | |
1262 if (*d++ != 0x29) { SetError(); return; } | |
1263 int jumpto = read_little_endian_int(d); | |
1264 d += 4; | |
1265 dprintf("-> %d\n", jumpto); | |
1266 if (! cond) jump_arg = jumpto; /* condition が満たされない場合、ジャンプ */ | |
1267 is_special = 1; | |
1268 } else if (cmd3 == 4) { | |
1269 /* switch to */ | |
1270 jump_arg = GetSwitch(d); | |
1271 is_special = 1; | |
1272 } else if (cmd3 == 8 || cmd3 == 3) { | |
1273 /* switch to */ | |
1274 jump_arg = GetSimpleSwitch(d); | |
1275 is_special = 1; | |
1276 } else if (cmd3 == 16) { // call with parameters | |
1277 GetArgs(d); | |
1278 jump_arg = read_little_endian_int(d); | |
1279 d += 4; | |
1280 is_special = 1; | |
1281 } else goto retry; | |
1282 if (jump_arg == -1) { | |
1283 cmd_type = CMD_NOP; | |
1284 } | |
1285 else { | |
1286 cmd_type = CMD_JMP; | |
1287 args.push_back(VarInfo(jump_arg)); | |
1288 } | |
1289 } else if (cmd2 == 2 && (cmd3 == 0 || cmd3 == 1 || cmd3 == 2 || cmd3 == 3 || cmd3 == 0x0d) ) { | |
1290 /* selection */ | |
1291 GetSelection(d); | |
1292 is_special = 1; | |
1293 } | |
1294 } | |
1295 retry: | |
1296 /* 一般引数のもの */ | |
1297 if (!is_special) { | |
1298 dprintf(" 0x23 - cmd %02x-%02x:%04x:%02x[%2d] \n",cmd1,cmd2,cmd3,cmd4,argc); | |
1299 dprintf("\t"); | |
1300 if (cmd1 == 1 && cmd2 == 0x22 && (cmd3 == 0xc1c || cmd3 == 0x835)) GetArgsSpecial(3, d); | |
1301 else if (cmd1 == 1 && cmd2 == 0x0b && cmd3 == 0x65) GetArgsSpecial(0, d); | |
1302 else if (cmd1 == 1 && cmd2 == 0x15 && cmd3 == 0x28) GetArgsSpecial(0, d); | |
1303 else if (cmd1 == 1 && cmd2 == 4 && (cmd3 == 0x26c || cmd3 == 0x26d || cmd3 == 0x270 || cmd3 == 0x276)) GetArgsSpecial(0, d); | |
1304 else if (cmd1 == 1 && cmd2 == 4 && cmd3 == 0x586) GetArgsSpecial(1, d); | |
1305 else if (cmd1 == 1 && (cmd2 == 0x21 && cmd3 == 0x4b) || (cmd2 == 0x28 && cmd3 == 0x64)) GetArgsSpecial(2,d); | |
1306 else GetArgs(d); | |
1307 dprintf("\n"); | |
1308 | |
1309 } | |
1310 } else if (*d == 0x24) { /* 代入演算 */ | |
1311 if (d[1] == 0x12 || d[2] != 0x5b) SetError(); | |
1312 dprintf("expr: "); | |
1313 sprintf(cmdstr, "expr"); | |
1314 | |
1315 VarInfo info; | |
1316 int value = GetLeftToken(d, info); | |
1317 if (d[0] != 0x5c) SetError(); | |
1318 int type = d[1]; | |
1319 if (type < 20 || type > 30) SetError(); | |
1320 else dprintf("%s",op_str[type]); | |
1321 d += 2; | |
1322 int value2 = GetExpression(d); | |
1323 // 代入情報を埋め込む | |
1324 if (type != 30) value2 = eval(value, type-20, value2); | |
1325 cmd_type = CMD_FLAGS; | |
1326 args.push_back(info); | |
1327 args.push_back(value2); | |
1328 dprintf("\n"); | |
1329 } else if (StrType(d)) { /* 文字出力 */ | |
1330 VarInfo info; | |
1331 info.type = TYPE_STR; | |
1332 info.value = GetString(d); | |
1333 args.push_back(info); | |
1334 cmd_type = CMD_TEXT; | |
1335 dprintf("\n"); | |
1336 } else if (*d == 0x0a || *d == 0x40 || *d == 0x21) { /* デバッグ用データと既読フラグ */ | |
1337 cmd_type = CMD_NOP; | |
1338 if (*d == 0x0a) { | |
1339 dprintf("line "); | |
1340 d++; | |
1341 int l; | |
1342 if (system_version == 0) { | |
1343 l = read_little_endian_int(d); | |
1344 d += 4; | |
1345 } else { | |
1346 l = read_little_endian_short(d); | |
1347 d += 2; | |
1348 } | |
1349 dprintf("%d\n", l); | |
1350 } else { /* 0x40, 0x21 */ | |
1351 // 既読マーカーらしい。エントリーポイントとセーブポイントも使われる。 | |
1352 // RealLive 1.2.5から、0x40はセーブポイント、0x21はエントリーポイント。 | |
1353 // 1.2.5以前、どちらも0x40が使われる。 | |
1354 int kidoku_index; | |
1355 d++; | |
1356 if (system_version == 0) { | |
1357 kidoku_index = read_little_endian_int(d); | |
1358 d += 4; | |
1359 } else { | |
1360 kidoku_index = read_little_endian_short(d); | |
1361 d += 2; | |
1362 } | |
1363 dprintf("kidoku marker %d\n", kidoku_index); | |
1364 // text_readflagは、このkidoku_indexを使ったら良いかな。 | |
1365 } | |
1366 } else if (*d == 0x2c) { /* ??? */ | |
1367 dprintf("commd;0x2c\n"); // conditional jump の行き先によくあるらしい(常に、かはわからない) | |
1368 d++; | |
1369 } else { | |
1370 SetError(); | |
1371 } | |
1372 return; | |
1373 } | |
1374 void Cmd::clear(void) { | |
1375 cmd_type = CMD_NOP; | |
1376 ResetString(); | |
1377 args.clear(); | |
1378 errorflag = false; | |
1379 pos = -1; | |
1380 } | |
1381 | |
1382 char Cmd::strtype[256] = { | |
1383 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +00 */ | |
1384 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +10 */ // 0123456789ABCDEF | |
1385 1,0,3,0, 0,0,0,1, 0,0,0,0, 0,1,1,0, /* +20 */ // !"#$%&'()*+,-./ | |
1386 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,1, /* +30 */ // 0123456789:;<=>? | |
1387 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, /* +40 */ // @ABCDEFGHIJKLMNO | |
1388 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,1, /* +50 */ // PQRSTUVWXYZ[\]^_ | |
1389 0,0,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, /* +60 */ // `abcdefghijklmno | |
1390 1,1,1,1, 1,1,1,1, 1,1,1,1, 0,0,0,0, /* +70 */ // pqrstuvwxyz{|}~ | |
1391 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +80 */ | |
1392 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +90 */ | |
1393 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +A0 */ | |
1394 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +B0 */ | |
1395 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +C0 */ | |
1396 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +D0 */ | |
1397 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +E0 */ | |
1398 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,0,0 /* +F0 */ | |
1399 }; | |
1400 | |
1401 int Cmd::GetString(const char*& d) { | |
1402 int retnum = -1; | |
1403 bool quote_flag = false; | |
1404 int stype; | |
1405 retnum = strend; | |
1406 while(1) { | |
1407 if (*d == '\\') { | |
1408 d++; | |
1409 strheap[strend++] = *d++; | |
1410 } else if (*d == '"') { | |
1411 if (quote_flag) quote_flag = false; | |
1412 else quote_flag = true; | |
1413 d++; | |
1414 } else if (quote_flag) { | |
1415 strheap[strend++] = *d++; | |
1416 } else if (stype = StrType(d)) { | |
1417 strheap[strend++] = *d++; | |
1418 if (stype == 2) strheap[strend++] = *d++; | |
1419 } else break; | |
1420 } | |
1421 strheap[strend++] = 0; | |
1422 dprintf("\"%s\"", strheap + retnum); | |
1423 if (strend >= STRHEAP_SIZE) { | |
1424 dprintf("Error: string heap overflow\n"); | |
1425 } | |
1426 return retnum; | |
1427 } | |
1428 | |
1429 int Cmd::CopyString(const char* d) { | |
1430 int retnum = strend; | |
1431 int len = strlen(d); | |
1432 memcpy(strheap+strend, d, len+1); | |
1433 strend += len+1; | |
1434 d += len+1; | |
1435 return retnum; | |
1436 } | |
1437 | |
1438 int Cmd::StrVar(int type, int var_num) { | |
1439 int retnum = strend; | |
1440 flags.Str(type, var_num, strheap+strend, STRHEAP_SIZE-strend); | |
1441 strend += strlen(strheap+strend)+1; | |
1442 return retnum; | |
1443 } | |
1444 | |
1445 void Cmd::SetSysvar(int n, int val) { | |
1446 VarInfo info; | |
1447 if (cmd_type != CMD_SYSVAR) { | |
1448 args.clear(); | |
1449 } | |
1450 cmd_type = CMD_SYSVAR; | |
1451 | |
1452 info.type = TYPE_SYS; | |
1453 info.number = n; | |
1454 info.value = val; | |
1455 args.push_back(info); | |
1456 } | |
1457 void Cmd::SetFlagvar(VarInfo info, int val) { | |
1458 if (cmd_type != CMD_SYSVAR) { | |
1459 args.clear(); | |
1460 } | |
1461 cmd_type = CMD_SYSVAR; | |
1462 | |
1463 info.value = val; | |
1464 args.push_back(info); | |
1465 } | |
1466 | |
1467 void Cmd::SetStrvar(VarInfo info, const string& s) { | |
1468 if (cmd_type != CMD_SYSVAR) { | |
1469 args.clear(); | |
1470 } | |
1471 | |
1472 cmd_type = CMD_SYSVAR; | |
1473 const char* ss = s.c_str(); | |
1474 info.value = CopyString(ss); | |
1475 args.push_back(info); | |
1476 } | |
1477 | |
1478 void Cmd::read(const CmdSimplified& from) { | |
1479 errorflag = false; | |
1480 ResetString(); | |
1481 | |
1482 cmd_type = Cmdtype(from.type); | |
1483 cmd1 = from.cmd1; | |
1484 cmd2 = from.cmd2; | |
1485 cmd3 = from.cmd3; | |
1486 cmd4 = from.cmd4; | |
1487 argc = from.argc; | |
1488 /* args の読み込み */ | |
1489 args.clear(); | |
1490 char* d = from.args; | |
1491 if (d == 0) return; | |
1492 while(*d != TYPE_END) { | |
1493 VarInfo info; | |
1494 switch(*d) { | |
1495 case TYPE_VAL: | |
1496 info.type = TYPE_VAL; | |
1497 info.number = 0; | |
1498 info.value = read_little_endian_int(d+1); | |
1499 d += 5; | |
1500 args.push_back(info); | |
1501 break; | |
1502 case TYPE_STR: | |
1503 info.type = TYPE_STR; | |
1504 info.number = 0; | |
1505 d++; | |
1506 info.value = CopyString( d); | |
1507 d += strlen(d)+1; | |
1508 args.push_back(info); | |
1509 break; | |
1510 default: | |
1511 fprintf(stderr,"Cmd::read: Invalid Load Data\n"); | |
1512 *d = TYPE_END; | |
1513 } | |
1514 } | |
1515 return; | |
1516 } | |
1517 void Cmd::write(CmdSimplified& to, char*& buffer) const { | |
1518 /* | |
1519 if (cmd_type != CMD_OTHER) { | |
1520 fprintf(stderr,"Cmd::write: Invalid Cmd during Saving Data\n"); | |
1521 to.cmd1 = 0; to.cmd2 = 0; to.cmd3 = 0; to.cmd4 = 0; to.argc = 0; to.args = 0; | |
1522 return; | |
1523 } | |
1524 */ | |
1525 to.type = cmd_type; | |
1526 to.cmd1 = cmd1; | |
1527 to.cmd2 = cmd2; | |
1528 to.cmd3 = cmd3; | |
1529 to.cmd4 = cmd4; | |
1530 to.argc = argc; | |
1531 /* args の書き込み */ | |
1532 if (args.empty()) { | |
1533 to.args = 0; | |
1534 } else { | |
1535 to.args = buffer; | |
1536 char* d = to.args; | |
1537 vector<VarInfo>::const_iterator it; | |
1538 for (it = args.begin(); it != args.end(); it++) { | |
1539 int type = it->type; | |
1540 if ( (type >= 0 && type < 7) || type == TYPE_VAL || type == char(TYPE_SYS)) { // digits | |
1541 *d++ = TYPE_VAL; | |
1542 write_little_endian_int(d, it->value); | |
1543 d += 4; | |
1544 } else if (type == TYPE_VARSTR || type == TYPE_VARSYSSTR || type == TYPE_VARLOCSTR || type == TYPE_STR) { // string | |
1545 *d++ = TYPE_STR; | |
1546 const char* s = Str(*it); | |
1547 int len = strlen(s); | |
1548 memcpy(d, s, len+1); | |
1549 d += len+1; | |
1550 } else { | |
1551 fprintf(stderr,"Cmd::write: Invalid Cmd args during Saving Data\n"); | |
1552 } | |
1553 } | |
1554 *d++ = TYPE_END; | |
1555 buffer = d; | |
1556 } | |
1557 } | |
1558 void CmdSimplified::copy(const CmdSimplified& from, char*& args_buffer) { | |
1559 *this = from; | |
1560 if (args == 0) return; | |
1561 char* args_old = from.args; | |
1562 /* args のコピー */ | |
1563 while(*args_old != TYPE_END) { | |
1564 if (*args_old == TYPE_VAL) { | |
1565 args_old += 5; | |
1566 } else { /* TYPE_STR */ | |
1567 args_old += strlen(args_old)+1; | |
1568 } | |
1569 } | |
1570 args_old++; | |
1571 int args_len = args_old - from.args; | |
1572 memmove(args_buffer, from.args, args_len); | |
1573 args = args_buffer; | |
1574 args_buffer += args_len; | |
1575 } | |
1576 void CmdSimplified::Save(string& saveret) { | |
1577 char buf[1024]; | |
1578 sprintf(buf, "%02x-%02x:%04x:%02x(%02d),", cmd1, cmd2, cmd3, cmd4, argc); | |
1579 saveret += buf; | |
1580 | |
1581 /* args のコピー */ | |
1582 char* d = args; | |
1583 while(d && *d != TYPE_END) { | |
1584 if (*d == TYPE_VAL) { | |
1585 d++; | |
1586 sprintf(buf, "%d,", read_little_endian_int(d)); | |
1587 d += 4; | |
1588 } else { /* TYPE_STR と仮定 */ | |
1589 d++; | |
1590 if (strlen(d) > 1000) d[1000] = 0; // ありえない・・・ | |
1591 int i; int cnt = 0; | |
1592 buf[cnt++] = '"'; | |
1593 for (i=0; d[i] != 0; i++) { | |
1594 if (d[i] == '"') buf[cnt++] = '"'; | |
1595 buf[cnt++] = d[i]; | |
1596 } | |
1597 buf[cnt++]='"'; | |
1598 buf[cnt++] = ','; | |
1599 buf[cnt++] = 0; | |
1600 d += strlen(d)+1; | |
1601 } | |
1602 saveret += buf; | |
1603 } | |
1604 saveret += 'E'; | |
1605 } | |
1606 | |
1607 void CmdSimplified::Load(const char* save, char*& args_buffer) { | |
1608 args = args_buffer; | |
1609 | |
1610 type = CMD_OTHER; | |
1611 sscanf(save, "%02x-%02x:%04x:%02x(%02d),", &cmd1, &cmd2, &cmd3, &cmd4, &argc); | |
1612 save = strchr(save, ','); | |
1613 if (save == 0) { | |
1614 *args_buffer++ = TYPE_END; | |
1615 return; | |
1616 } | |
1617 save++; | |
1618 while(*save != 'E' && *save != '\n' && *save != '\0') { | |
1619 if (isdigit(*save)) { | |
1620 int v; | |
1621 sscanf(save,"%d,",&v); | |
1622 *args_buffer++ = TYPE_VAL; | |
1623 write_little_endian_int(args_buffer, v); | |
1624 args_buffer+= 4; | |
1625 save = strchr(save, ','); | |
1626 if (save) save++; | |
1627 } else { // *save == '"' | |
1628 save++; | |
1629 *args_buffer++ = TYPE_STR; | |
1630 while(1) { | |
1631 if (*save == 0) break; | |
1632 if (*save == '"') { | |
1633 if (save[1] != '"') break; | |
1634 save++; | |
1635 } | |
1636 *args_buffer++ = *save++; | |
1637 } | |
1638 save += 2; | |
1639 *args_buffer++ = 0; | |
1640 } | |
1641 } | |
1642 *args_buffer++ = TYPE_END; | |
1643 return; | |
1644 } | |
1645 | |
1646 #ifdef SCN_DUMP | |
1647 void usage(void) { | |
1648 fprintf(stderr,"usage : scn2kdump [inputfile] [outputfile]\n"); | |
1649 fprintf(stderr," inputfile: seen.txt(default)\n"); | |
1650 fprintf(stderr," outputfile: seen.txt_out(default)\n"); | |
1651 exit(-1); | |
1652 } | |
1653 int main(int argc, char** argv) { | |
1654 /* determine file names */ | |
1655 bool verbose = false; | |
1656 char* inname = "seen.txt"; | |
1657 char* outname = 0; | |
1658 if (argc > 2 && strcmp(argv[1],"-v") == 0) { | |
1659 int i; for (i=1; i<argc; i++) argv[i] = argv[i+1]; | |
1660 argc--; | |
1661 verbose = true; | |
1662 } | |
1663 switch(argc) { | |
1664 case 1: break; | |
1665 case 2: inname = argv[1]; break; | |
1666 case 3: inname = argv[1]; outname = argv[2]; break; | |
1667 default: usage(); | |
1668 } | |
1669 /* open output file */ | |
1670 FILE* outstream = stdout; | |
1671 /* create archive instance */ | |
1672 SCN2kFILE archive(inname); | |
1673 archive.Init(); | |
1674 if (archive.Deal() == 0) { | |
1675 fprintf(stderr,"Cannot open / Invalid archive file %s\n",inname); | |
1676 usage(); | |
1677 } | |
1678 /* dump files */ | |
1679 archive.InitList(); | |
1680 char* fname; | |
1681 fprintf(stderr,"Dump start\n"); | |
1682 int system_version = 0; | |
1683 while( (fname = archive.ListItem()) != 0) { | |
1684 ARCINFO* info = archive.Find(fname,""); | |
1685 if (info == 0) continue; | |
1686 char* data = info->CopyRead(); | |
1687 char* d = data; | |
1688 char* dend = d + info->Size(); | |
1689 /* version 確認 */ | |
1690 if (read_little_endian_int(d) == 0x1cc) { | |
1691 system_version = 0; | |
1692 } else if (read_little_endian_int(d) == 0x1d0) { | |
1693 system_version = 1; | |
1694 } else { | |
1695 continue; | |
1696 } | |
1697 if (read_little_endian_int(d+4) == 0x1adb2) ; // little busters! | |
1698 else if (read_little_endian_int(d+4) != 0x2712) continue; | |
1699 int header_size; | |
1700 if (system_version == 0) { | |
1701 header_size = 0x1cc + read_little_endian_int(d+0x20) * 4; | |
1702 } else { | |
1703 header_size = read_little_endian_int(d+0x20); | |
1704 } | |
1705 d += header_size; | |
1706 | |
1707 const char* dcur = d; | |
1708 const char* dstart = d; | |
1709 fprintf(stderr,"Dumping %s\n",fname); | |
1710 Flags flags; | |
1711 /* 最初から最後までコマンド取得 -> 出力を繰り返す */ | |
1712 while(dcur<dend) { | |
1713 const char* dprev = dcur; | |
1714 Cmd cmd(flags, system_version); cmd.ClearError(); | |
1715 | |
1716 /* end? */ | |
1717 if (*dcur == -1) { | |
1718 /* 0xff x 32byte + 0x00 : end sign */ | |
1719 int i; for (i=0; i<0x20; i++) | |
1720 if (dcur[i] != -1) break; | |
1721 if (i == 0x20 && dcur[i] == 0) break; | |
1722 } | |
1723 dprintf("%d : ",dcur-dstart); | |
1724 cmd.GetCmd(flags, dcur); | |
1725 if (cmd.IsError()) { | |
1726 fprintf(outstream, "Error at %6d\n",dprev-dstart); | |
1727 while(dcur < dend) { | |
1728 if (*dcur == 0x29 && dcur[1] == 0x0a) {dcur++;break;} | |
1729 dcur++; | |
1730 } | |
1731 dprev -= 2*16; | |
1732 int ilen = (dcur-dprev+15)/16; | |
1733 int i; for (i=0; i<ilen; i++) { | |
1734 fprintf(outstream, "%6d: ",dprev-dstart); | |
1735 int j; for (j=0; j<16; j++) { | |
1736 if (dprev >= dend) break; | |
1737 if (dprev < data) continue; | |
1738 fprintf(outstream, "%02x ",*(unsigned char*)(dprev)); | |
1739 dprev++; | |
1740 } | |
1741 fprintf(outstream, "\n"); | |
1742 } | |
1743 } | |
1744 } | |
1745 delete info; | |
1746 } | |
1747 return 0; | |
1748 } | |
1749 #endif | |
1750 |