20130420
[gdash.git] / src / fileops / binaryimport.cpp
blobe655140d9746153094c5a9dc1f313b03accb6cf1
1 /*
2 * Copyright (c) 2007-2013 Czirkos Zoltan http://code.google.com/p/gdash/
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
19 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
20 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 #include "fileops/binaryimport.hpp"
25 #include "fileops/c64import.hpp"
27 #include <cstring>
28 #include <glib.h>
29 #include <stdexcept>
30 #include "misc/logger.hpp"
31 #include "misc/printf.hpp"
34 class ResizingByteArray : public std::vector<unsigned char> {
35 public:
36 using std::vector<unsigned char>::size;
37 using std::vector<unsigned char>::empty;
38 using std::vector<unsigned char>::clear;
39 unsigned char &operator[](size_t s) {
40 if (s >= size())
41 this->resize(s + 1);
42 // call op[] of parent class
43 return this->std::vector<unsigned char>::operator[](s);
48 static ResizingByteArray out;
49 static int outpos;
52 /* default effect table, taken from afl boulder dash. used to detect if
53 game-wide diego effects are present. */
54 static unsigned char default_effect[] = {
55 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x08, 0x09, 0x0a, 0x0b,
56 0x10, 0x10, 0x12, 0x12, 0x14, 0x14, 0x16, 0x16, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
57 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2a, 0x2c, 0x2d, 0x2e, 0x2f,
58 0x30, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32, 0x33, 0x38, 0x38, 0x3a, 0x3a, 0x3c, 0x3d, 0x3e, 0x3f,
59 0x40, 0x60, 0x46, 0x4e, 0x22, 0x2e, 0x62, 0x2e, 0x4a, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
60 0x64, 0x44, 0x44, 0x44, 0x44, 0x48, 0x48, 0x48, 0x48, 0x00, 0x00, 0x00, 0x66, 0x68, 0x6a, 0x68,
61 0x66, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x62, 0x66, 0x68, 0x6a, 0x00, 0x4e, 0x4e, 0x00, 0x00, 0x00,
62 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4c, 0x4c, 0x40, 0x40, 0x42, 0x2e, 0x40,
66 static void startwith(C64Import::GdCavefileFormat format) {
67 out.clear();
68 for (size_t i = 0; C64Import::gd_format_strings[format][i] != 0; ++i) {
69 out[i] = C64Import::gd_format_strings[format][i];
71 outpos = 12;
75 /* save bd1 caves from memory map */
76 /* atari: a boolean value, true if try atari map. */
77 static bool try_bd1(std::vector<unsigned char> const &memory, bool atari) {
78 /* there are cave pointers at 0x5806. two byte entries pointing to caves. */
79 /* their value is relative to 0x582e. */
80 /* atari values are 3500 and 3528. */
81 int cavepointers = atari ? 0x3500 : 0x5806;
82 int cavestart = atari ? 0x3528 : 0x582e;
83 int positions[20];
84 const char *type = atari ? "atari" : "c64";
85 SetLoggerContextForFunction context(SPrintf("BD1 import %s") % type);
87 startwith(atari ? C64Import::GD_FORMAT_BD1_ATARI : C64Import::GD_FORMAT_BD1);
89 /* try to autodetect */
91 /* fixme what is this? */
92 if (!atari) {
93 if (memory[0x5f3a] != 0x44 || memory[0x5f3b] != 0x44 || memory[0x5f3c] != 0x48 || memory[0x5f3d] != 0x48) {
94 gd_debug("Assumptions failed for BD1(e).");
95 return false;
99 /* 20 (4 groups * 5 caves (4cave+1intermission)) */
100 for (int i = 0; i < 20; i++) {
101 int lo = memory[cavepointers + i * 2];
102 int hi = memory[cavepointers + i * 2 + 1];
103 int start = hi * 256 + lo + cavestart, pos = start;
104 positions[i] = start;
105 /* check if position is not the same as any previous cave */
106 for (int j = 0; j < i; ++j)
107 if (positions[j] == positions[i]) {
108 gd_debug(CPrintf("Invalid cave position %x at index %d - same as for cave at index %d") % pos % i % j);
109 return false;
112 if (pos > (0xffff - 0x0400)) {
113 gd_debug("Cannot interpret memory contents as BD1(e) -- invalid cave pointer.");
114 return false;
116 if (i < 16)
117 gd_debug(CPrintf("Cave %c, addr: %04x") % char(i + 'A') % pos);
118 else
119 gd_debug(CPrintf("Intermission %d, addr: %04x") % int(i - 15) % pos);
121 /* copy */
122 /* first 32 bytes - cave options */
123 for (int j = 0; j < 32; j++)
124 out[outpos++] = memory[pos++]; /* 5levels: 5random, 5diamond, 5time */
126 /* now cave objects */
127 int j = memory[pos++];
128 while (j != 0xFF) { /* végét jelenti; de kiírtuk ezt is */
129 if (pos - start > 0x400) {
130 /* bd1 caves cannot be this long */
131 gd_debug("Cannot interpret memory contents as BD1(e) -- cave data too long.");
132 return false;
134 out[outpos++] = j;
135 if (j == 0x0F) {
136 /* crazy cream 3 extension: escape byte 0x0f means raster */
137 out[outpos++] = memory[pos++]; /* param byte 1: object to draw */
138 out[outpos++] = memory[pos++]; /* param byte 2: begin column */
139 out[outpos++] = memory[pos++]; /* param byte 3: begin row */
140 out[outpos++] = memory[pos++]; /* param byte 4: amount of rows */
141 out[outpos++] = memory[pos++]; /* param byte 5: amount of columns */
142 out[outpos++] = memory[pos++]; /* param byte 6: distance between rows */
143 out[outpos++] = memory[pos++]; /* param byte 7: distance between columns */
144 } else {
145 switch (j >> 6) {
146 case 0: /* point */
147 out[outpos++] = memory[pos++]; /* x */
148 out[outpos++] = memory[pos++]; /* y */
149 break;
150 case 1: /* line */
151 out[outpos++] = memory[pos++]; /* x */
152 out[outpos++] = memory[pos++]; /* y */
153 out[outpos++] = memory[pos++]; /* len */
154 out[outpos++] = memory[pos++]; /* dir */
155 break;
156 case 2: /* fillrect */
157 out[outpos++] = memory[pos++]; /* x */
158 out[outpos++] = memory[pos++]; /* y */
159 out[outpos++] = memory[pos++]; /* w */
160 out[outpos++] = memory[pos++]; /* h */
161 out[outpos++] = memory[pos++]; /* fill */
162 break;
163 case 3: /* outline */
164 out[outpos++] = memory[pos++]; /* x */
165 out[outpos++] = memory[pos++]; /* y */
166 out[outpos++] = memory[pos++]; /* w */
167 out[outpos++] = memory[pos++]; /* h */
168 break;
171 j = memory[pos++];
173 out[outpos++] = j; /* lezáró 0xff kiírása */
175 gd_debug("Found 20 BD1 caves!");
176 return true;
180 /* save plck caves from c64 memory map */
181 static bool try_plck(std::vector<unsigned char> const &memory) {
182 SetLoggerContextForFunction context("PLCK import");
183 int x, i;
184 int has_names = 0;
185 int has_diego = 0;
186 int valid;
187 int ok;
189 startwith(C64Import::GD_FORMAT_PLC);
190 /* try plck */
191 valid = 0;
193 /* try to detect plck cave selection table. assume there are at least 5 caves. */
194 /* selection table without names. */
195 ok = 0;
196 for (x = 0; x < 5; x++)
197 if (memory[0x5e8b + x] == 0x0e || memory[0x5e8b + x] == 0x19)
198 ok++;
199 if (ok == 5) {
200 valid = 1;
201 has_names = 0;
204 /* selection table with names. */
205 ok = 0;
206 for (x = 0; x < 5; x++)
207 if (memory[0x5e8b + 13 * x + 12] == 0x0e || memory[0x5e8b + 13 * x + 12] == 0x19)
208 ok++;
209 if (ok == 5) {
210 valid = 1;
211 has_names = 1;
213 if (!valid) {
214 gd_debug("Assumptions failed for PLCK - could not find cave selection table.");
215 return false;
218 gd_debug(has_names ? "PLCK caves have names." : "PLCK caves have no names.");
220 i = 0;
221 //~ while (i<17) { // For Bert Bogger Pro 2
222 /* while present and (selectable or nonselectable) <- find any valid byte in cave selection table. */
223 while ((!has_names && (memory[0x5e8b + i] != 0 && (memory[0x5e8b + i] == 0x0e || memory[0x5e8b + i] == 0x19)))
224 || (has_names && (memory[0x5e8b + i * 13 + 12] != 0 && (memory[0x5e8b + i * 13 + 12] == 0x0e || memory[0x5e8b + i * 13 + 12] == 0x19)))) {
225 int j, pos, zero;
227 pos = 0x7000 + 0x200 * i;
229 /* check if memory is not filled with zeroes. */
230 zero = 1;
231 for (j = 0; j < 512 && zero; j++)
232 if (memory[pos + j] != 0)
233 zero = 0;
234 if (zero)
235 break;
237 /* check for error */
238 if (i > 71) {
239 /* caves cannot be this long */
240 gd_debug("Data corrupt or detection failed for plck caves -- too many caves.");
241 return false;
244 if (memory[pos + 0x1e5] == 0x20 && memory[pos + 0x1e6] == 0x90 && memory[pos + 0x1e7] == 0x46)
245 has_diego = 1;
246 gd_debug(CPrintf("Cave %d, addr: %04x%s") % int(i + 1) % pos % (has_diego ? " - has diego effects." : ""));
248 /* copy 1f0 bytes for cave */
249 for (j = 0; j < 0x1f0; ++j)
250 out[outpos++] = memory[pos++];
252 /* and fill the rest with our own data. this way we stay compatible, as cave was always 1f0 bytes */
253 if (has_names) { /* we detected that it has names */
254 if (memory[0x5e8b + i * 13 + 12] != 0x0e && memory[0x5e8b + i * 13 + 12] != 0x19) {
255 gd_debug("ERROR: cave selection table corrupt or autodetection failed");
256 out[outpos++] = 0x19;
257 out[outpos++] = 0x19 + 1;
258 } else {
259 out[outpos++] = memory[0x5e8b + i * 13 + 12];
260 out[outpos++] = memory[0x5e8b + i * 13 + 12] + 1; /* save twice, add +1 for second for detection in gdash */
262 for (j = 0; j < 12; j++)
263 out[outpos++] = memory[0x5e8b + i * 13 + j];
264 out[outpos++] = 0; /* fill the rest with zero */
265 out[outpos++] = 0;
266 } else { /* no names */
267 if (memory[0x5e8b + i] != 0x0e && memory[0x5e8b + i] != 0x19) {
268 gd_debug("ERROR: cave selection table corrupt or autodetection failed");
269 out[outpos++] = 0x19;
270 out[outpos++] = 0x19 + 1;
271 } else {
272 out[outpos++] = memory[0x5e8b + i];
273 out[outpos++] = memory[0x5e8b + i] + 1; /* save twice for detection, add 1 to second one */
275 for (j = 2; j < 16; j++)
276 out[outpos++] = 0;
279 i++;
281 gd_debug(CPrintf("Found %d PLCK caves in %d bytes!") % i % outpos);
283 /* now try to do something about diego effects. */
284 /* if we found at least one cave with diego effects, this check can be skipped. */
285 if (!has_diego) {
286 int j;
287 const int numbers = sizeof(default_effect) / sizeof(default_effect[0]);
288 char diffs[numbers];
289 int n;
291 /* check effect table from memory at 3b00. */
292 n = 0;
293 for (j = 0; j < numbers; j++)
294 if (default_effect[j] != memory[0x3b00 + j]) {
295 n++;
296 diffs[j] = 1;
297 } else
298 diffs[j] = 0;
299 if (n != 0) {
300 /* found an unstandard effect table */
301 int b_stone_to = memory[0x3b00 + 0x11];
302 int f_diamond_to = memory[0x3b00 + 0x17];
303 int explosion_to = memory[0x3b00 + 0x1e];
304 int dirt_pointer = memory[0x3b00 + 0x42];
305 int growing_pointer = memory[0x3b00 + 0x6b];
307 /* report effect table changes that we are able to convert to the per cave description. */
308 gd_debug("Found global diego effects!");
309 if (b_stone_to != 0x10)
310 gd_debug("Effect for bouncing stone.");
311 if (f_diamond_to != 0x16)
312 gd_debug("Effect for falling diamond.");
313 if (explosion_to != 0x1e)
314 gd_debug("Effect for explosion.");
315 if (dirt_pointer != 0x46)
316 gd_debug("Dirt looks like effect.");
317 if (growing_pointer != 0x4e)
318 gd_debug("Growing wall looks like effect.");
320 /* go through all caves and add no1v5.3e compatible flags */
321 for (j = 0; j < i; j++) {
322 /* flags used previously on c64; gdash also knows them */
323 out[12 + 0x0200 * j + 0x1e5] = 0x20;
324 out[12 + 0x0200 * j + 0x1e6] = 0x90;
325 out[12 + 0x0200 * j + 0x1e7] = 0x46;
327 /* set detected stuff for cave */
328 out[12 + 0x0200 * j + 0x1ea] = b_stone_to;
329 out[12 + 0x0200 * j + 0x1eb] = f_diamond_to;
330 out[12 + 0x0200 * j + 0x1ec] = explosion_to;
331 out[12 + 0x0200 * j + 0x1ed] = dirt_pointer;
332 out[12 + 0x0200 * j + 0x1ee] = growing_pointer;
333 out[12 + 0x0200 * j + 0x1ef] = 200; /* FIXME AMOEBA THRESHOLD */
336 /* null out effects we could handle */
337 diffs[0x11] = 0;
338 diffs[0x17] = 0;
339 diffs[0x1e] = 0;
340 diffs[0x42] = 0;
341 diffs[0x6b] = 0;
342 /* check if growing wall (delayed)==growing wall in terms of graphics, if it is, then it is no diff to original */
343 if (memory[0x3b00 + 0x6b] == memory[0x3b00 + 0x6c])
344 diffs[0x6c] = 0;
346 /* and check if there are others we cannot fit into a "standard" cawe */
347 for (j = 0; j < numbers; j++)
348 if (diffs[j]) {
349 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]);
352 return true;
357 /* save plck caves from atari memory map */
358 static bool try_atari_plck(std::vector<unsigned char> const &memory) {
359 SetLoggerContextForFunction context("PLCK import Atari");
360 int x, i;
361 int ok;
362 int has_selection;
364 startwith(C64Import::GD_FORMAT_PLC_ATARI);
366 /* try to detect the cave selection table. assume there are at least 5 caves. */
367 /* example:
368 6040: 66 60 4A 41 49 4C 20 20 20 20 2E 43 41 56 59 53 f.JAIL .CAVYS
369 6050: 41 46 45 20 20 20 20 2E 43 41 56 59 52 41 49 4E AFE .CAVYRAIN
370 6060: 20 20 20 20 2E 43 41 56 59 45 53 43 41 50 41 44 .CAVYESCAPAD
371 6070: 45 2E 43 41 56 59 43 48 41 53 45 20 20 20 2E 49 E.CAVYCHASE .I
372 6080: 4E 54 4E 52 45 53 43 55 45 20 20 2E 43 41 56 59 NTNRESCUE .CAVY
373 we detect the Y's and N's after CAV or INT
376 /* caves are preceded with $ab $ab $ab $ab CAVENAME */
378 6FF0: AB AB AB AB 4A 41 49 4C 2E 43 41 56 9B 20 20 20 ....JAIL.CAV.
379 7000: 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
380 7010: 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
382 /* try to detect this; assume at least 5 caves. */
383 ok = 0;
384 for (x = 0; x < 5; x++) {
385 int pos = 0x6ff0 + x * 0x200;
386 if (memory[pos] == 0xAB && memory[pos + 1] == 0xAB && memory[pos + 2] == 0xAB && memory[pos + 3] == 0xAB)
387 ok++;
389 if (ok != 5) {
390 gd_debug("Assumptions failed for Atari PLCK - could not find $ab $ab $ab $ab before caves.");
391 return false;
394 /* check if it has a selection table */
395 ok = 0;
396 for (x = 0; x < 5; x++) {
397 if (memory[0x604e + x * 13] == 'Y' || memory[0x604e + x * 13] == 'N')
398 ok++;
400 has_selection = (ok == 5);
401 if (has_selection)
402 gd_debug("Found selection table.");
404 i = 0;
405 /* detect caves by $ab bytes before them */
406 while (memory[0x6ff0 + i * 0x200] == 0xAB && memory[0x6ff1 + i * 0x200] == 0xAB && memory[0x6ff2 + i * 0x200] == 0xAB && memory[0x6ff3 + i * 0x200] == 0xAB) {
407 int j, pos;
408 int selectable;
410 pos = 0x7000 + 0x200 * i;
411 if (has_selection)
412 selectable = memory[0x604e + i * 13] == 'Y';
413 else
414 /* has no selection table... we make intermissions unselectable. */
415 selectable = memory[pos + 0x1da] == 0;
417 /* check for error */
418 if (i > 71) {
419 /* caves cannot be this long */
420 gd_debug("Data corrupt or detection failed for plck caves -- too many caves.");
421 return false;
424 bool has_diego = false;
425 if (memory[pos + 0x1e5] == 0x20 && memory[pos + 0x1e6] == 0x90 && memory[pos + 0x1e7] == 0x46)
426 has_diego = true;
427 gd_debug(CPrintf("Cave %d, addr: %04x, sel: %d%s") % (i + 1) % pos % selectable % (has_diego ? " - has diego effects." : ""));
429 /* copy 1f0 bytes for cave */
430 for (j = 0; j < 0x1f0; ++j)
431 out[outpos++] = memory[pos++];
433 /* and fill the rest with our own data. this way we stay compatible, as cave was always 1f0 bytes */
434 /* we have to stay compatible with c64 plck import routine above. */
435 /* so we use 0x19 for selectable caves, 0x0e for nonselectable. */
436 out[outpos++] = selectable ? 0x19 : 0x0e;
437 out[outpos++] = (selectable ? 0x19 : 0x0e) + 1; /* save twice, add +1 for second for detection in gdash */
438 /* copy cave name, which is:
439 6FE0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
440 6FF0: AB AB AB AB 4A 41 49 4C 2E 43 41 56 9B 20 20 20 ....JAIL.CAV. ... cave name
441 7000: 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD ... cave data
442 7010: 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
443 7020: 44 44 44 44 44 44 44 44 4E 77 77 77 77 77 77 77 DDDDDDDDNwwwwwww
446 pos = 0x7000 + 0x200 * i;
447 for (j = 0; j < 12; j++) {
448 unsigned char c = memory[pos - 0x10 + 4 + j];
450 /* somehow this character set the end-of-string in atari version */
451 if (c == 0x9b)
452 c = 0x20;
453 out[outpos++] = c;
455 out[outpos++] = 0; /* fill the rest with zero */
456 out[outpos++] = 0;
458 i++;
460 gd_debug(CPrintf("Found %d PLCK caves in %d bytes!") % i % outpos);
462 return true;
467 /* save crazy light caves from memory map */
468 static bool try_crli(std::vector<unsigned char> const &memory) {
469 SetLoggerContextForFunction context("CrLi import");
471 startwith(C64Import::GD_FORMAT_CRLI);
473 /* try autodetect */
474 bool b = true;
475 if (memory[0x6ffc] != 'V' || memory[0x6ffd] != '3' || memory[0x6ffe] != '.' || memory[0x6fff] != '0') /* version string */
476 b = false;
477 for (int x = 0x7060; x < 0x7090; x++) /* cave selection table */
478 if (memory[x] != 0 && memory[x] != 1 && memory[x] != 255)
479 b = false;
480 if (!b) {
481 gd_debug("Assumptions failed for crazy light.");
482 return false;
485 int caves = 0;
486 for (int i = 0; i < 48; i++) {
487 if (memory[0x7060 + i] != 0xFF) {
488 caves++;
490 int startpos = memory[0x7000 + i] + memory[0x7030 + i] * 256L;
491 int pos = startpos;
492 int cavepos = 0;
493 /* 'decompress' data, to see how many bytes there are */
494 while (cavepos < 0x3b0) { /* <- loop until the uncompressed reaches its size */
495 if (memory[pos] == 0xbf) {
496 /* escaped byte */
497 cavepos += memory[pos + 2]; /* number of bytes */
498 pos += 3;
499 } else {
500 /* plain data */
501 cavepos++;
502 pos++;
505 pos += 14; /* add 14 bytes for name */
506 int n = pos - startpos; /* bytes to copy */
507 startpos -= 14; /* name is BEFORE the cave data */
508 gd_debug(CPrintf("Cave %d, addr: %04x (%d), length %d bytes") % caves % pos % pos % n);
510 out[outpos++] = memory[0x7060 + i]; /* is_selectable */
511 for (int j = 0; j < n; j++)
512 out[outpos++] = memory[startpos++];
515 gd_debug(CPrintf("Found %d crazy light caves in %d bytes!") % caves % outpos);
516 return true;
519 static bool try_crdr(std::vector<unsigned char> const &memory) {
520 SetLoggerContextForFunction context("CrDr import");
521 int i, caves;
523 startwith(C64Import::GD_FORMAT_CRDR_7);
525 /* try autodetect */
526 // if (memory[0x6ffc]!='V' || memory[0x6ffd]!='3' || memory[0x6ffe]!='.' || memory[0x6fff]!='0') /* version string */
527 // b=0;
529 caves = 0;
530 for (i = 0; i < 20; i++) {
531 caves++;
533 int startpos = memory[0x7500 + i] + memory[0x7580 + i] * 256L;
534 int pos = startpos;
536 /* name */
537 for (int j = 0; j < 14; j++)
538 out[outpos++] = memory[0x8c00 + i * 16 + j];
540 /* selectable */
541 /* XXX seems to be broken; rather set unselectable intermissions */
542 out[outpos++] =/*memory[0x7410+caves]*/(caves % 5) != 0;
544 /* cave data */
545 for (int j = 0; j < 0x49; j++)
546 out[outpos++] = memory[pos++];
547 /* cave objects */
548 while (memory[pos] != 0xff) {
549 switch (memory[pos]) {
550 case 1: /* point */
551 for (int j = 0; j < 4; j++)
552 out[outpos++] = memory[pos++];
553 break;
554 case 2: /* rectangle */
555 for (int j = 0; j < 6; j++)
556 out[outpos++] = memory[pos++];
557 break;
558 case 3: /* fillrect */
559 for (int j = 0; j < 6; j++)
560 out[outpos++] = memory[pos++];
561 break;
562 case 4: /* line */
563 for (int j = 0; j < 6; j++)
564 out[outpos++] = memory[pos++];
565 break;
566 case 6: /* ??? */
567 for (int j = 0; j < 5; j++) {
568 out[outpos++] = memory[pos++];
570 break;
571 case 7: /* ??? */
572 for (int j = 0; j < 3; j++) {
573 out[outpos++] = memory[pos++];
575 break;
576 case 11: /* raster */
577 for (int j = 0; j < 8; j++)
578 out[outpos++] = memory[pos++];
579 break;
580 default:
581 gd_debug(CPrintf("Unknown crdr object code %x at %d. Aborting.") % memory[pos] % pos);
582 return false;
583 break;
586 out[outpos++] = memory[pos++]; /* copy $ff */
587 int n = pos - startpos; /* bytes to copied */
588 gd_debug(CPrintf("Cave %d, addr: %04x (%d), length %d bytes") % caves % pos % pos % n);
590 gd_debug(CPrintf("Found %d crazy dream caves in %d bytes!") % caves % outpos);
591 return true;
596 /* save bd2 caves from memory map */
597 static bool try_bd2(std::vector<unsigned char> const &memory, bool atari) {
598 const int cavepointers = atari ? 0x86b0 : 0x89b0;
599 const int cavecolors = atari ? 0x86d8 : 0x89d8;
600 int i;
601 int unsupported = 0, uns[256];
602 const char *type = atari ? "atari" : "c64";
603 SetLoggerContextForFunction context(SPrintf("BD2 import %s") % type);
605 /* 256 counters for the 256 possible bytes (8bit). mark each unsupported extension found. */
606 /* if more than 5 types found, bail out with error */
607 for (i = 0; i < 256; ++i)
608 uns[i] = 0;
610 startwith(C64Import::GD_FORMAT_BD2);
612 /* 4*5 (4 groups * 5 caves (4cave+1intermission)) */
613 for (i = 0; i < 4 * 5; i++) {
614 int lo, hi, j, pos, start;
615 int amount, n, mappos;
617 lo = cavepointers + i * 2;
618 hi = cavepointers + i * 2 + 1;
619 start = pos = memory[hi] * 256L + memory[lo];
620 if (pos > (0xffff - 0x0400)) {
621 gd_debug("Cannot interpret memory contents as BD2 -- invalid cave pointer.");
622 return false;
624 if (i < 16)
625 gd_debug(CPrintf("Cave %c, addr: %04x") % char(i + 'A') % pos);
626 else
627 gd_debug(CPrintf("Intermission %d, addr: %04x") % int(i - 15) % pos);
629 /* copy */
630 /* first bytes: cave options */
631 for (j = 0; j <= 0x19; j++)
632 out[outpos++] = memory[pos++]; /* cave options */
634 j = memory[pos++];
635 while (j != 0xFF) { /* végét jelenti; de kiírtuk ezt is */
636 if (pos - start > 0x400) {
637 /* bd1 caves cannot be this long */
638 gd_debug("Data corrupt or detection failed for bd2 caves -- cave data too long.");
639 return false;
641 out[outpos++] = j;
642 switch (j) {
643 case 0: /* line */
644 out[outpos++] = memory[pos++]; /* obj */
645 out[outpos++] = memory[pos++]; /* y */
646 out[outpos++] = memory[pos++]; /* x */
647 out[outpos++] = memory[pos++]; /* dir */
648 out[outpos++] = memory[pos++]; /* len */
649 break;
650 case 1: /* rectangle (outline) */
651 out[outpos++] = memory[pos++]; /* obj */
652 out[outpos++] = memory[pos++]; /* y */
653 out[outpos++] = memory[pos++]; /* x */
654 out[outpos++] = memory[pos++]; /* h */
655 out[outpos++] = memory[pos++]; /* w */
656 break;
657 case 2: /* fillrect */
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++]; /* fillobj */
664 break;
665 case 3: /* point */
666 out[outpos++] = memory[pos++]; /* obj */
667 out[outpos++] = memory[pos++]; /* y */
668 out[outpos++] = memory[pos++]; /* x */
669 break;
670 case 4: /* raster */
671 out[outpos++] = memory[pos++]; /* obj */
672 out[outpos++] = memory[pos++]; /* y */
673 out[outpos++] = memory[pos++]; /* x */
674 out[outpos++] = memory[pos++]; /* h */
675 out[outpos++] = memory[pos++]; /* w */
676 out[outpos++] = memory[pos++]; /* dy */
677 out[outpos++] = memory[pos++]; /* dx */
678 break;
679 case 5: /* profi boulder extension: bitmap */
680 out[outpos++] = memory[pos++]; /* obj */
681 amount = memory[pos++];
682 out[outpos++] = amount; /* amount */
683 out[outpos++] = memory[pos++]; /* target msb */
684 out[outpos++] = memory[pos++]; /* target lsb */
685 for (n = 0; n < amount; ++n)
686 out[outpos++] = memory[pos++]; /* data */
687 break;
688 case 6: /* join */
689 out[outpos++] = memory[pos++]; /* add to this */
690 out[outpos++] = memory[pos++]; /* add this */
691 out[outpos++] = memory[pos++]; /* dy*40+dx */
692 break;
693 case 7: /* slime permeabilty */
694 out[outpos++] = memory[pos++]; /* perm */
695 break;
696 case 9: /* profi boulder extension: plck map */
697 lo = memory[pos++];
698 hi = memory[pos++];
699 mappos = hi * 256 + lo;
700 out[outpos++] = memory[pos++]; /* inbox y */
701 out[outpos++] = memory[pos++]; /* inbox x */
702 for (n = 0; n < 40 * (22 - 2) / 2; n++) /* 40*20 caves, upper and lower row not contained, 1byte/2 elements */
703 out[outpos++] = memory[mappos + n];
704 break;
705 default:
706 if (uns[j] == 0) {
707 /* not seen this extension previously */
708 gd_debug(CPrintf("Found unsupported bd2 extension n.%d") % j);
709 unsupported++;
710 uns[j] = 1; /* mark the newly found unknown extension */
712 if (unsupported > 5) {
713 /* found to many unsupported extensions - this can't be bd2 */
714 gd_debug("Data corrupt or detection failed for bd2 caves -- too many unknown extensions.");
715 return false;
717 break;
719 j = memory[pos++]; /* read next */
721 out[outpos++] = j; /* closing 0xff */
722 out[outpos++] = memory[pos++]; /* animation */
724 /* color table */
725 lo = cavecolors + i * 2;
726 hi = cavecolors + i * 2 + 1;
727 pos = memory[hi] * 256L + memory[lo]; /* pointer to the three colors */
728 out[outpos++] = memory[pos++];
729 out[outpos++] = memory[pos++];
730 out[outpos++] = memory[pos++];
733 return true;
737 /* save plck caves from memory map */
738 static bool try_1stb(std::vector<unsigned char> const &memory) {
739 SetLoggerContextForFunction context("1stB import");
740 startwith(C64Import::GD_FORMAT_FIRSTB);
742 /* there must be exactly 20 caves, according to bd inside faq. */
743 int i;
744 for (i = 0; i < 20; i++) {
745 int pos = 0x7010 + 0x400 * i;
747 /* 1stb caves have cave time, diamonds and the like encoded in bcd numbers,
748 one digit in each bytes. check that. */
749 for (int j = 0x370; j < 0x379 + 3; j++)
750 if (memory[pos + j] > 9) {
751 gd_debug("Data corrupt or detection failed for 1stb caves.");
752 return false;
754 gd_debug(CPrintf("Cave %d, addr: %04x") % (i + 1) % pos);
756 for (int j = 0; j < 0x400; ++j)
757 out[outpos++] = memory[pos++];
759 gd_debug(CPrintf("Found %d 1stb caves!") % i);
760 return true;
764 /** load memory dump, and fill memory map. returns the memory dump, or throws an exception describing the problem. */
765 std::vector<unsigned char> load_memory_dump(unsigned char const *file, size_t length) {
766 const unsigned char vicemagic[] = {
767 0x56, 0x49, 0x43, 0x45, 0x20, 0x53, 0x6E, 0x61, 0x70, 0x73, 0x68, 0x6F,
768 0x74, 0x20, 0x46, 0x69, 0x6C, 0x65, 0x1A, 0x01, 0x00, 0x43, 0x36, 0x34
770 std::vector<unsigned char> memory(65536);
772 if (memcmp(vicemagic, file, sizeof(vicemagic)) == 0) {
773 /* FOUND a vice snapshot file. */
774 gd_debug("File is a VICE snapshot.");
775 memcpy(&memory[0], file + 0x80, 65536);
776 return memory;
779 /* 65538 bytes: we hope that this is a full-memory map saved by vice. check it. */
780 if (length == 65538) {
781 /* check start address */
782 if (file[0] != 0 || file[1] != 0)
783 throw std::runtime_error(
784 "Memory map should begin from address 0000. "
785 "Use save \"filename\" 0 0000 ffff in vice monitor.");
786 memcpy(&memory[0], file + 2, 65536);
787 gd_debug("%s looks like a proper VICE memory map.");
788 return memory;
791 /* or maybe a 64k map saved by atari800. read it. */
792 if (length == 65536) {
793 memcpy(&memory[0], file, 65536);
794 gd_debug("%s is maybe an atari800 memory map.");
795 return memory;
798 throw std::runtime_error(
799 "Memory map file should be 65536+2 bytes long or 65536 bytes long. "
800 "Use save \"filename\" 0 0000 ffff in vice monitor. "
801 "Use write 0000 ffff filename in atari800 monitor.");
805 std::vector<unsigned char> gdash_binary_import(std::vector<unsigned char> const &memory) {
806 if (try_plck(memory) || try_atari_plck(memory) || try_bd1(memory, false) || try_bd1(memory, true)
807 || try_bd2(memory, false) || try_bd2(memory, true) || try_crli(memory) || try_1stb(memory) || try_crdr(memory)) {
808 /* write data length in little endian */
809 out[8] = ((outpos - 12)) & 0xff;
810 out[9] = ((outpos - 12) >> 8) & 0xff;
811 out[10] = ((outpos - 12) >> 16) & 0xff;
812 out[11] = ((outpos - 12) >> 24) & 0xff;
814 return out;
817 throw std::runtime_error("Could not import cave data -- unknown cave format!");