20130313
[gdash.git] / src / fileops / binaryimport.cpp
blob3324a7e874f5df01f1815fbd8de6e40cac2177b8
1 /*
2 * Copyright (c) 2007-2013 Czirkos Zoltan http://code.google.com/p/gdash/
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <cstring>
18 #include <glib.h>
19 #include <vector>
20 #include <fstream>
21 #include <stdexcept>
22 #include "fileops/binaryimport.hpp"
23 #include "fileops/c64import.hpp"
24 #include "misc/logger.hpp"
25 #include "misc/printf.hpp"
28 class ResizingByteArray : public std::vector<unsigned char> {
29 public:
30 using std::vector<unsigned char>::size;
31 using std::vector<unsigned char>::empty;
32 using std::vector<unsigned char>::clear;
33 unsigned char & operator[] (size_t s) {
34 if (s >= size())
35 this->resize(s+1);
36 // call op[] of parent class
37 return this->std::vector<unsigned char>::operator[](s);
42 static ResizingByteArray out;
43 static int outpos;
46 /* default effect table, taken from afl boulder dash. used to detect if
47 game-wide diego effects are present. */
48 static unsigned char default_effect[] = {
49 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x08, 0x09, 0x0a, 0x0b,
50 0x10, 0x10, 0x12, 0x12, 0x14, 0x14, 0x16, 0x16, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
51 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2a, 0x2c, 0x2d, 0x2e, 0x2f,
52 0x30, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32, 0x33, 0x38, 0x38, 0x3a, 0x3a, 0x3c, 0x3d, 0x3e, 0x3f,
53 0x40, 0x60, 0x46, 0x4e, 0x22, 0x2e, 0x62, 0x2e, 0x4a, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
54 0x64, 0x44, 0x44, 0x44, 0x44, 0x48, 0x48, 0x48, 0x48, 0x00, 0x00, 0x00, 0x66, 0x68, 0x6a, 0x68,
55 0x66, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x62, 0x66, 0x68, 0x6a, 0x00, 0x4e, 0x4e, 0x00, 0x00, 0x00,
56 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4c, 0x4c, 0x40, 0x40, 0x42, 0x2e, 0x40,
60 static void startwith(C64Import::GdCavefileFormat format) {
61 out.clear();
62 for (size_t i = 0; C64Import::gd_format_strings[format][i] != 0; ++i) {
63 out[i] = C64Import::gd_format_strings[format][i];
65 outpos = 12;
69 /* save bd1 caves from memory map */
70 /* atari: a boolean value, true if try atari map. */
71 static bool try_bd1(std::vector<unsigned char> const &memory, bool atari) {
72 /* there are cave pointers at 0x5806. two byte entries pointing to caves. */
73 /* their value is relative to 0x582e. */
74 /* atari values are 3500 and 3528. */
75 int cavepointers=atari?0x3500:0x5806;
76 int cavestart=atari?0x3528:0x582e;
77 int positions[20];
78 const char *type=atari?"atari":"c64";
79 SetLoggerContextForFunction context(SPrintf("BD1 import %s") % type);
81 startwith(atari ? C64Import::GD_FORMAT_BD1_ATARI : C64Import::GD_FORMAT_BD1);
83 /* try to autodetect */
85 /* fixme what is this? */
86 if (!atari) {
87 if (memory[0x5f3a]!=0x44 || memory[0x5f3b]!=0x44 || memory[0x5f3c]!=0x48 || memory[0x5f3d]!=0x48) {
88 gd_debug("Assumptions failed for BD1(e).");
89 return false;
93 /* 20 (4 groups * 5 caves (4cave+1intermission)) */
94 for (int i=0; i<20; i++) {
95 int lo = memory[cavepointers+i*2];
96 int hi = memory[cavepointers+i*2+1];
97 int start = hi*256+lo+cavestart, pos = start;
98 positions[i]=start;
99 /* check if position is not the same as any previous cave */
100 for (int j=0; j<i; ++j)
101 if (positions[j]==positions[i]) {
102 gd_debug(CPrintf("Invalid cave position %x at index %d - same as for cave at index %d") % pos % i % j);
103 return false;
106 if (pos>(0xffff-0x0400)) {
107 gd_debug("Cannot interpret memory contents as BD1(e) -- invalid cave pointer.");
108 return false;
110 if (i<16)
111 gd_debug(CPrintf("Cave %c, addr: %04x") % char(i+'A') % pos);
112 else
113 gd_debug(CPrintf("Intermission %d, addr: %04x") % int(i-15) % pos);
115 /* copy */
116 /* first 32 bytes - cave options */
117 for (int j=0; j<32; j++)
118 out[outpos++]=memory[pos++]; /* 5levels: 5random, 5diamond, 5time */
120 /* now cave objects */
121 int j=memory[pos++];
122 while (j!=0xFF) { /* végét jelenti; de kiírtuk ezt is */
123 if (pos-start > 0x400) {
124 /* bd1 caves cannot be this long */
125 gd_debug("Cannot interpret memory contents as BD1(e) -- cave data too long.");
126 return false;
128 out[outpos++]=j;
129 if (j==0x0F) {
130 /* crazy cream 3 extension: escape byte 0x0f means raster */
131 out[outpos++]=memory[pos++]; /* param byte 1: object to draw */
132 out[outpos++]=memory[pos++]; /* param byte 2: begin column */
133 out[outpos++]=memory[pos++]; /* param byte 3: begin row */
134 out[outpos++]=memory[pos++]; /* param byte 4: amount of rows */
135 out[outpos++]=memory[pos++]; /* param byte 5: amount of columns */
136 out[outpos++]=memory[pos++]; /* param byte 6: distance between rows */
137 out[outpos++]=memory[pos++]; /* param byte 7: distance between columns */
138 } else {
139 switch (j>>6) {
140 case 0: /* point */
141 out[outpos++]=memory[pos++]; /* x */
142 out[outpos++]=memory[pos++]; /* y */
143 break;
144 case 1: /* line */
145 out[outpos++]=memory[pos++]; /* x */
146 out[outpos++]=memory[pos++]; /* y */
147 out[outpos++]=memory[pos++]; /* len */
148 out[outpos++]=memory[pos++]; /* dir */
149 break;
150 case 2: /* fillrect */
151 out[outpos++]=memory[pos++]; /* x */
152 out[outpos++]=memory[pos++]; /* y */
153 out[outpos++]=memory[pos++]; /* w */
154 out[outpos++]=memory[pos++]; /* h */
155 out[outpos++]=memory[pos++]; /* fill */
156 break;
157 case 3: /* outline */
158 out[outpos++]=memory[pos++]; /* x */
159 out[outpos++]=memory[pos++]; /* y */
160 out[outpos++]=memory[pos++]; /* w */
161 out[outpos++]=memory[pos++]; /* h */
162 break;
165 j=memory[pos++];
167 out[outpos++]=j; /* lezáró 0xff kiírása */
169 gd_debug("Found 20 BD1 caves!");
170 return true;
174 /* save plck caves from c64 memory map */
175 static bool try_plck(std::vector<unsigned char> const &memory) {
176 SetLoggerContextForFunction context("PLCK import");
177 int x, i;
178 int has_names=0;
179 int has_diego=0;
180 int valid;
181 int ok;
183 startwith(C64Import::GD_FORMAT_PLC);
184 /* try plck */
185 valid=0;
187 /* try to detect plck cave selection table. assume there are at least 5 caves. */
188 /* selection table without names. */
189 ok=0;
190 for (x=0; x<5; x++)
191 if (memory[0x5e8b+x]==0x0e || memory[0x5e8b+x]==0x19)
192 ok++;
193 if (ok==5) {
194 valid=1;
195 has_names=0;
198 /* selection table with names. */
199 ok=0;
200 for (x=0; x<5; x++)
201 if (memory[0x5e8b+13*x+12]==0x0e || memory[0x5e8b+13*x+12]==0x19)
202 ok++;
203 if (ok==5) {
204 valid=1;
205 has_names=1;
207 if (!valid) {
208 gd_debug("Assumptions failed for PLCK - could not find cave selection table.");
209 return false;
212 gd_debug(has_names ? "PLCK caves have names." : "PLCK caves have no names.");
214 i=0;
215 /* while present and (selectable or nonselectable) <- find any valid byte in cave selection table. */
216 while ((!has_names && (memory[0x5e8b+i]!=0 && (memory[0x5e8b+i]==0x0e || memory[0x5e8b+i]==0x19)))
217 || (has_names && (memory[0x5e8b+i*13+12]!=0 && (memory[0x5e8b+i*13+12]==0x0e || memory[0x5e8b+i*13+12]==0x19)))) {
218 int j, pos, zero;
220 pos=0x7000+0x200*i;
222 /* check if memory is not filled with zeroes. */
223 zero=1;
224 for (j=0; j<512 && zero; j++)
225 if (memory[pos+j]!=0)
226 zero=0;
227 if (zero)
228 break;
230 /* check for error */
231 if (i>71) {
232 /* caves cannot be this long */
233 gd_debug("Data corrupt or detection failed for plck caves -- too many caves.");
234 return false;
237 if (memory[pos+0x1e5]==0x20 && memory[pos+0x1e6]==0x90 && memory[pos+0x1e7]==0x46)
238 has_diego=1;
239 gd_debug(CPrintf("Cave %d, addr: %04x%s") % int(i+1) % pos % (has_diego ? " - has diego effects." : ""));
241 /* copy 1f0 bytes for cave */
242 for (j=0; j<0x1f0; ++j)
243 out[outpos++]=memory[pos++];
245 /* and fill the rest with our own data. this way we stay compatible, as cave was always 1f0 bytes */
246 if (has_names) { /* we detected that it has names */
247 out[outpos++]=memory[0x5e8b+i*13+12];
248 out[outpos++]=memory[0x5e8b+i*13+12]+1; /* save twice, add +1 for second for detection in gdash */
249 if (memory[0x5e8b+i*13+12]!=0x0e && memory[0x5e8b+i*13+12]!=0x19)
250 gd_debug("ERROR: cave selection table corrupt or autodetection failed");
251 for (j=0; j<12; j++)
252 out[outpos++]=memory[0x5e8b+i*13+j];
253 out[outpos++]=0; /* fill the rest with zero */
254 out[outpos++]=0;
256 else { /* no names */
257 out[outpos++]=memory[0x5e8b+i];
258 out[outpos++]=memory[0x5e8b+i]+1; /* save twice for detection, add 1 to second one */
259 if (memory[0x5e8b+i]!=0x0e && memory[0x5e8b+i]!=0x19)
260 gd_debug("ERROR: cave selection table corrupt or autodetection failed");
261 for (j=2; j<16; j++)
262 out[outpos++]=0;
265 i++;
267 gd_debug(CPrintf("Found %d PLCK caves in %d bytes!") % i % outpos);
269 /* now try to do something about diego effects. */
270 /* if we found at least one cave with diego effects, this check can be skipped. */
271 if (!has_diego) {
272 int j;
273 const int numbers=sizeof(default_effect)/sizeof(default_effect[0]);
274 char diffs[numbers];
275 int n;
277 /* check effect table from memory at 3b00. */
278 n=0;
279 for (j=0; j<numbers; j++)
280 if (default_effect[j]!=memory[0x3b00+j]) {
281 n++;
282 diffs[j]=1;
283 } else
284 diffs[j]=0;
285 if (n!=0) {
286 /* found an unstandard effect table */
287 int b_stone_to=memory[0x3b00 + 0x11];
288 int f_diamond_to=memory[0x3b00 + 0x17];
289 int explosion_to=memory[0x3b00 + 0x1e];
290 int dirt_pointer=memory[0x3b00 + 0x42];
291 int growing_pointer=memory[0x3b00 + 0x6b];
293 /* report effect table changes that we are able to convert to the per cave description. */
294 gd_debug("Found global diego effects!");
295 if (b_stone_to != 0x10)
296 gd_debug("Effect for bouncing stone.");
297 if (f_diamond_to != 0x16)
298 gd_debug("Effect for falling diamond.");
299 if (explosion_to != 0x1e)
300 gd_debug("Effect for explosion.");
301 if (dirt_pointer != 0x46)
302 gd_debug("Dirt looks like effect.");
303 if (growing_pointer != 0x4e)
304 gd_debug("Growing wall looks like effect.");
306 /* go through all caves and add no1v5.3e compatible flags */
307 for (j=0; j<i; j++) {
308 /* flags used previously on c64; gdash also knows them */
309 out[12+0x0200*j+0x1e5]=0x20;
310 out[12+0x0200*j+0x1e6]=0x90;
311 out[12+0x0200*j+0x1e7]=0x46;
313 /* set detected stuff for cave */
314 out[12+0x0200*j+0x1ea]=b_stone_to;
315 out[12+0x0200*j+0x1eb]=f_diamond_to;
316 out[12+0x0200*j+0x1ec]=explosion_to;
317 out[12+0x0200*j+0x1ed]=dirt_pointer;
318 out[12+0x0200*j+0x1ee]=growing_pointer;
319 out[12+0x0200*j+0x1ef]=200; /* FIXME AMOEBA THRESHOLD */
322 /* null out effects we could handle */
323 diffs[0x11]=0;
324 diffs[0x17]=0;
325 diffs[0x1e]=0;
326 diffs[0x42]=0;
327 diffs[0x6b]=0;
328 /* check if growing wall (delayed)==growing wall in terms of graphics, if it is, then it is no diff to original */
329 if (memory[0x3b00+0x6b]==memory[0x3b00+0x6c])
330 diffs[0x6c]=0;
332 /* and check if there are others we cannot fit into a "standard" cawe */
333 for (j=0; j<numbers; j++)
334 if (diffs[j]) {
335 gd_debug(CPrintf("Don't know how to handle effect for element number %x, default %x, this one %x") % j % default_effect[j] % memory[0x3b00+j]);
338 return true;
343 /* save plck caves from atari memory map */
344 static bool try_atari_plck(std::vector<unsigned char> const &memory) {
345 SetLoggerContextForFunction context("PLCK import Atari");
346 int x, i;
347 int ok;
348 int has_selection;
350 startwith(C64Import::GD_FORMAT_PLC_ATARI);
352 /* try to detect the cave selection table. assume there are at least 5 caves. */
353 /* example:
354 6040: 66 60 4A 41 49 4C 20 20 20 20 2E 43 41 56 59 53 f.JAIL .CAVYS
355 6050: 41 46 45 20 20 20 20 2E 43 41 56 59 52 41 49 4E AFE .CAVYRAIN
356 6060: 20 20 20 20 2E 43 41 56 59 45 53 43 41 50 41 44 .CAVYESCAPAD
357 6070: 45 2E 43 41 56 59 43 48 41 53 45 20 20 20 2E 49 E.CAVYCHASE .I
358 6080: 4E 54 4E 52 45 53 43 55 45 20 20 2E 43 41 56 59 NTNRESCUE .CAVY
359 we detect the Y's and N's after CAV or INT
362 /* caves are preceded with $ab $ab $ab $ab CAVENAME */
364 6FF0: AB AB AB AB 4A 41 49 4C 2E 43 41 56 9B 20 20 20 ....JAIL.CAV.
365 7000: 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
366 7010: 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
368 /* try to detect this; assume at least 5 caves. */
369 ok=0;
370 for (x=0; x<5; x++) {
371 int pos=0x6ff0 + x*0x200;
372 if (memory[pos]==0xAB && memory[pos+1]==0xAB && memory[pos+2]==0xAB && memory[pos+3]==0xAB)
373 ok++;
375 if (ok!=5) {
376 gd_debug("Assumptions failed for Atari PLCK - could not find $ab $ab $ab $ab before caves.");
377 return false;
380 /* check if it has a selection table */
381 ok=0;
382 for (x=0; x<5; x++) {
383 if (memory[0x604e + x*13]=='Y' || memory[0x604e + x*13]=='N')
384 ok++;
386 has_selection=(ok==5);
387 if (has_selection)
388 gd_debug("Found selection table.");
390 i=0;
391 /* detect caves by $ab bytes before them */
392 while (memory[0x6ff0+i*0x200]==0xAB && memory[0x6ff1+i*0x200]==0xAB && memory[0x6ff2+i*0x200]==0xAB && memory[0x6ff3+i*0x200]==0xAB) {
393 int j, pos;
394 int selectable;
396 pos=0x7000+0x200*i;
397 if (has_selection)
398 selectable=memory[0x604e + i*13]=='Y';
399 else
400 /* has no selection table... we make intermissions unselectable. */
401 selectable=memory[pos + 0x1da]==0;
403 /* check for error */
404 if (i>71) {
405 /* caves cannot be this long */
406 gd_debug("Data corrupt or detection failed for plck caves -- too many caves.");
407 return false;
410 bool has_diego = false;
411 if (memory[pos+0x1e5]==0x20 && memory[pos+0x1e6]==0x90 && memory[pos+0x1e7]==0x46)
412 has_diego = true;
413 gd_debug(CPrintf("Cave %d, addr: %04x, sel: %d%s") % (i+1) % pos % selectable % (has_diego ? " - has diego effects." : ""));
415 /* copy 1f0 bytes for cave */
416 for (j=0; j<0x1f0; ++j)
417 out[outpos++]=memory[pos++];
419 /* and fill the rest with our own data. this way we stay compatible, as cave was always 1f0 bytes */
420 /* we have to stay compatible with c64 plck import routine above. */
421 /* so we use 0x19 for selectable caves, 0x0e for nonselectable. */
422 out[outpos++]=selectable?0x19:0x0e;
423 out[outpos++]=(selectable?0x19:0x0e)+1; /* save twice, add +1 for second for detection in gdash */
424 /* copy cave name, which is:
425 6FE0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
426 6FF0: AB AB AB AB 4A 41 49 4C 2E 43 41 56 9B 20 20 20 ....JAIL.CAV. ... cave name
427 7000: 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD ... cave data
428 7010: 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
429 7020: 44 44 44 44 44 44 44 44 4E 77 77 77 77 77 77 77 DDDDDDDDNwwwwwww
432 pos=0x7000+0x200*i;
433 for (j=0; j<12; j++) {
434 unsigned char c=memory[pos-0x10+4+j];
436 /* somehow this character set the end-of-string in atari version */
437 if (c==0x9b)
438 c=0x20;
439 out[outpos++]=c;
441 out[outpos++]=0; /* fill the rest with zero */
442 out[outpos++]=0;
444 i++;
446 gd_debug(CPrintf("Found %d PLCK caves in %d bytes!") % i % outpos);
448 return true;
453 /* save crazy light caves from memory map */
454 static bool try_crli(std::vector<unsigned char> const &memory) {
455 SetLoggerContextForFunction context("CrLi import");
457 startwith(C64Import::GD_FORMAT_CRLI);
459 /* try autodetect */
460 bool b=true;
461 if (memory[0x6ffc]!='V' || memory[0x6ffd]!='3' || memory[0x6ffe]!='.' || memory[0x6fff]!='0') /* version string */
462 b=false;
463 for (int x=0x7060; x<0x7090; x++) /* cave selection table */
464 if (memory[x]!=0 && memory[x]!=1 && memory[x]!=255)
465 b=false;
466 if (!b) {
467 gd_debug("Assumptions failed for crazy light.");
468 return false;
471 int caves=0;
472 for (int i=0; i<48; i++) {
473 if (memory[0x7060+i]!=0xFF) {
474 caves++;
476 int startpos=memory[0x7000+i] + memory[0x7030+i]*256L;
477 int pos=startpos;
478 int cavepos=0;
479 /* 'decompress' data, to see how many bytes there are */
480 while (cavepos < 0x3b0) { /* <- loop until the uncompressed reaches its size */
481 if (memory[pos] == 0xbf) {
482 /* escaped byte */
483 cavepos+=memory[pos+2]; /* number of bytes */
484 pos += 3;
486 else {
487 /* plain data */
488 cavepos++;
489 pos++;
492 pos+=14; /* add 14 bytes for name */
493 int n=pos-startpos; /* bytes to copy */
494 startpos-=14; /* name is BEFORE the cave data */
495 gd_debug(CPrintf("Cave %d, addr: %04x (%d), length %d bytes") % caves % pos % pos % n);
497 out[outpos++]=memory[0x7060+i]; /* is_selectable */
498 for (int j=0; j<n; j++)
499 out[outpos++]=memory[startpos++];
502 gd_debug(CPrintf("Found %d crazy light caves in %d bytes!") % caves % outpos);
503 return true;
506 static bool try_crdr(std::vector<unsigned char> const &memory) {
507 SetLoggerContextForFunction context("CrDr import");
508 int i, caves;
510 startwith(C64Import::GD_FORMAT_CRDR_7);
512 /* try autodetect */
513 // if (memory[0x6ffc]!='V' || memory[0x6ffd]!='3' || memory[0x6ffe]!='.' || memory[0x6fff]!='0') /* version string */
514 // b=0;
516 caves=0;
517 for (i=0; i<20; i++) {
518 caves++;
520 int startpos=memory[0x7500+i] + memory[0x7580+i]*256L;
521 int pos=startpos;
523 /* name */
524 for (int j=0; j<14; j++)
525 out[outpos++]=memory[0x8c00+i*16+j];
527 /* selectable */
528 /* XXX seems to be broken; rather set unselectable intermissions */
529 out[outpos++]=/*memory[0x7410+caves]*/(caves%5)!=0;
531 /* cave data */
532 for (int j=0; j<0x49; j++)
533 out[outpos++]=memory[pos++];
534 /* cave objects */
535 while (memory[pos]!=0xff) {
536 switch(memory[pos]) {
537 case 1: /* point */
538 for (int j=0; j<4; j++)
539 out[outpos++]=memory[pos++];
540 break;
541 case 2: /* rectangle */
542 for (int j=0; j<6; j++)
543 out[outpos++]=memory[pos++];
544 break;
545 case 3: /* fillrect */
546 for (int j=0; j<6; j++)
547 out[outpos++]=memory[pos++];
548 break;
549 case 4: /* line */
550 for (int j=0; j<6; j++)
551 out[outpos++]=memory[pos++];
552 break;
553 case 6: /* ??? */
554 for (int j=0; j<5; j++) {
555 out[outpos++]=memory[pos++];
557 break;
558 case 7: /* ??? */
559 for (int j=0; j<3; j++) {
560 out[outpos++]=memory[pos++];
562 break;
563 case 11: /* raster */
564 for (int j=0; j<8; j++)
565 out[outpos++]=memory[pos++];
566 break;
567 default:
568 gd_debug(CPrintf("Unknown crdr object code %x at %d. Aborting.") % memory[pos] % pos);
569 return false;
570 break;
573 out[outpos++]=memory[pos++]; /* copy $ff */
574 int n=pos-startpos; /* bytes to copied */
575 gd_debug(CPrintf("Cave %d, addr: %04x (%d), length %d bytes") % caves % pos % pos % n);
577 gd_debug(CPrintf("Found %d crazy dream caves in %d bytes!") % caves % outpos);
578 return true;
583 /* save bd2 caves from memory map */
584 static bool try_bd2(std::vector<unsigned char> const &memory, bool atari) {
585 const int cavepointers=atari ? 0x86b0 : 0x89b0;
586 const int cavecolors=atari ? 0x86d8 : 0x89d8;
587 int i;
588 int unsupported=0, uns[256];
589 const char *type=atari?"atari":"c64";
590 SetLoggerContextForFunction context(SPrintf("BD2 import %s") % type);
592 /* 256 counters for the 256 possible bytes (8bit). mark each unsupported extension found. */
593 /* if more than 5 types found, bail out with error */
594 for (i=0; i<256; ++i)
595 uns[i]=0;
597 startwith(C64Import::GD_FORMAT_BD2);
599 /* 4*5 (4 groups * 5 caves (4cave+1intermission)) */
600 for (i=0; i<4*5; i++) {
601 int lo, hi, j, pos, start;
602 int amount, n, mappos;
604 lo=cavepointers+i*2;
605 hi=cavepointers+i*2+1;
606 start=pos=memory[hi]*256L+memory[lo];
607 if (pos> (0xffff-0x0400)) {
608 gd_debug("Cannot interpret memory contents as BD2 -- invalid cave pointer.");
609 return false;
611 if (i<16)
612 gd_debug(CPrintf("Cave %c, addr: %04x") % char(i+'A') % pos);
613 else
614 gd_debug(CPrintf("Intermission %d, addr: %04x") % int(i-15) % pos);
616 /* copy */
617 /* first bytes: cave options */
618 for (j=0; j<=0x19; j++)
619 out[outpos++]=memory[pos++]; /* cave options */
621 j=memory[pos++];
622 while (j!=0xFF) { /* végét jelenti; de kiírtuk ezt is */
623 if (pos-start > 0x400) {
624 /* bd1 caves cannot be this long */
625 gd_debug("Data corrupt or detection failed for bd2 caves -- cave data too long.");
626 return false;
628 out[outpos++]=j;
629 switch (j) {
630 case 0: /* line */
631 out[outpos++]=memory[pos++]; /* obj */
632 out[outpos++]=memory[pos++]; /* y */
633 out[outpos++]=memory[pos++]; /* x */
634 out[outpos++]=memory[pos++]; /* dir */
635 out[outpos++]=memory[pos++]; /* len */
636 break;
637 case 1: /* rectangle (outline) */
638 out[outpos++]=memory[pos++]; /* obj */
639 out[outpos++]=memory[pos++]; /* y */
640 out[outpos++]=memory[pos++]; /* x */
641 out[outpos++]=memory[pos++]; /* h */
642 out[outpos++]=memory[pos++]; /* w */
643 break;
644 case 2: /* fillrect */
645 out[outpos++]=memory[pos++]; /* obj */
646 out[outpos++]=memory[pos++]; /* y */
647 out[outpos++]=memory[pos++]; /* x */
648 out[outpos++]=memory[pos++]; /* h */
649 out[outpos++]=memory[pos++]; /* w */
650 out[outpos++]=memory[pos++]; /* fillobj */
651 break;
652 case 3: /* point */
653 out[outpos++]=memory[pos++]; /* obj */
654 out[outpos++]=memory[pos++]; /* y */
655 out[outpos++]=memory[pos++]; /* x */
656 break;
657 case 4: /* raster */
658 out[outpos++]=memory[pos++]; /* obj */
659 out[outpos++]=memory[pos++]; /* y */
660 out[outpos++]=memory[pos++]; /* x */
661 out[outpos++]=memory[pos++]; /* h */
662 out[outpos++]=memory[pos++]; /* w */
663 out[outpos++]=memory[pos++]; /* dy */
664 out[outpos++]=memory[pos++]; /* dx */
665 break;
666 case 5: /* profi boulder extension: bitmap */
667 out[outpos++]=memory[pos++]; /* obj */
668 amount=memory[pos++];
669 out[outpos++]=amount; /* amount */
670 out[outpos++]=memory[pos++]; /* target msb */
671 out[outpos++]=memory[pos++]; /* target lsb */
672 for (n=0; n<amount; ++n)
673 out[outpos++]=memory[pos++]; /* data */
674 break;
675 case 6: /* join */
676 out[outpos++]=memory[pos++]; /* add to this */
677 out[outpos++]=memory[pos++]; /* add this */
678 out[outpos++]=memory[pos++]; /* dy*40+dx */
679 break;
680 case 7: /* slime permeabilty */
681 out[outpos++]=memory[pos++]; /* perm */
682 break;
683 case 9: /* profi boulder extension: plck map */
684 lo=memory[pos++];
685 hi=memory[pos++];
686 mappos=hi*256+lo;
687 out[outpos++]=memory[pos++]; /* inbox y */
688 out[outpos++]=memory[pos++]; /* inbox x */
689 for (n=0; n<40*(22-2)/2; n++) /* 40*20 caves, upper and lower row not contained, 1byte/2 elements */
690 out[outpos++]=memory[mappos+n];
691 break;
692 default:
693 if (uns[j]==0) {
694 /* not seen this extension previously */
695 gd_debug(CPrintf("Found unsupported bd2 extension n.%d") % j);
696 unsupported++;
697 uns[j]=1; /* mark the newly found unknown extension */
699 if (unsupported>5) {
700 /* found to many unsupported extensions - this can't be bd2 */
701 gd_debug("Data corrupt or detection failed for bd2 caves -- too many unknown extensions.");
702 return false;
704 break;
706 j=memory[pos++]; /* read next */
708 out[outpos++]=j; /* closing 0xff */
709 out[outpos++]=memory[pos++]; /* animation */
711 /* color table */
712 lo=cavecolors+i*2;
713 hi=cavecolors+i*2+1;
714 pos=memory[hi]*256L+memory[lo]; /* pointer to the three colors */
715 out[outpos++]=memory[pos++];
716 out[outpos++]=memory[pos++];
717 out[outpos++]=memory[pos++];
720 return true;
724 /* save plck caves from memory map */
725 static bool try_1stb(std::vector<unsigned char> const &memory) {
726 SetLoggerContextForFunction context("1stB import");
727 startwith(C64Import::GD_FORMAT_FIRSTB);
729 /* there must be exactly 20 caves, according to bd inside faq. */
730 int i;
731 for (i=0; i<20; i++) {
732 int pos=0x7010+0x400*i;
734 /* 1stb caves have cave time, diamonds and the like encoded in bcd numbers,
735 one digit in each bytes. check that. */
736 for (int j=0x370; j<0x379+3; j++)
737 if (memory[pos+j]>9) {
738 gd_debug("Data corrupt or detection failed for 1stb caves.");
739 return false;
741 gd_debug(CPrintf("Cave %d, addr: %04x") % (i+1) % pos);
743 for (int j=0; j<0x400; ++j)
744 out[outpos++]=memory[pos++];
746 gd_debug(CPrintf("Found %d 1stb caves!") % i);
747 return true;
751 /** load memory dump, and fill memory map. returns the memory dump, or throws an exception describing the problem. */
752 std::vector<unsigned char> load_memory_dump(unsigned char const *file, size_t length) {
753 const unsigned char vicemagic[] = {
754 0x56, 0x49, 0x43, 0x45, 0x20, 0x53, 0x6E, 0x61, 0x70, 0x73, 0x68, 0x6F,
755 0x74, 0x20, 0x46, 0x69, 0x6C, 0x65, 0x1A, 0x01, 0x00, 0x43, 0x36, 0x34
757 std::vector<unsigned char> memory(65536);
759 if (memcmp(vicemagic, file, sizeof(vicemagic))==0) {
760 /* FOUND a vice snapshot file. */
761 gd_debug("File is a VICE snapshot.");
762 memcpy(&memory[0], file + 0x80, 65536);
763 return memory;
766 /* 65538 bytes: we hope that this is a full-memory map saved by vice. check it. */
767 if (length==65538) {
768 /* check start address */
769 if (file[0]!=0 || file[1]!=0)
770 throw std::runtime_error(
771 "Memory map should begin from address 0000. "
772 "Use save \"filename\" 0 0000 ffff in vice monitor.");
773 memcpy(&memory[0], file + 2, 65536);
774 gd_debug("%s looks like a proper VICE memory map.");
775 return memory;
778 /* or maybe a 64k map saved by atari800. read it. */
779 if (length==65536) {
780 memcpy(&memory[0], file, 65536);
781 gd_debug("%s is maybe an atari800 memory map.");
782 return memory;
785 throw std::runtime_error(
786 "Memory map file should be 65536+2 bytes long or 65536 bytes long. "
787 "Use save \"filename\" 0 0000 ffff in vice monitor. "
788 "Use write 0000 ffff filename in atari800 monitor.");
792 std::vector<unsigned char> gdash_binary_import(std::vector<unsigned char> const &memory) {
793 if (try_plck(memory) || try_atari_plck(memory) || try_bd1(memory, false) || try_bd1(memory, true)
794 || try_bd2(memory, false) || try_bd2(memory, true) || try_crli(memory) || try_1stb(memory) || try_crdr(memory)) {
795 /* write data length in little endian */
796 out[8]=((outpos-12))&0xff;
797 out[9]=((outpos-12)>>8)&0xff;
798 out[10]=((outpos-12)>>16)&0xff;
799 out[11]=((outpos-12)>>24)&0xff;
801 return out;
804 throw std::runtime_error("Could not import cave data -- unknown cave format!");