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++;
|
|
1202 dprintf(";");
|
|
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 }
|
|
1210 str2[i*2] = 0;
|
|
1211 text += str2;
|
|
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
|