ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/1541d64.cpp
Revision: 1.10
Committed: 2005-06-27T19:55:48Z (18 years, 8 months ago) by cebix
Branch: MAIN
CVS Tags: VERSION_4_2
Changes since 1.9: +1 -1 lines
Log Message:
updated copyright dates

File Contents

# Content
1 /*
2 * 1541d64.cpp - 1541 emulation in disk image files (.d64/.x64/zipcode)
3 *
4 * Frodo (C) 1994-1997,2002-2005 Christian Bauer
5 * zipcode decoding routines (C) 1993-1997 Marko Mäkelä, Paul David Doherty
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 /*
23 * Incompatibilities:
24 * - No support for relative files
25 * - Unimplemented commands: P
26 * - Impossible to implement: B-E, M-E
27 */
28
29 #include "sysdeps.h"
30
31 #include "1541d64.h"
32 #include "IEC.h"
33 #include "Prefs.h"
34 #include "C64.h"
35 #include "main.h"
36
37 #define DEBUG 0
38 #include "debug.h"
39
40
41 // Channel modes (IRC users listen up :-)
42 enum {
43 CHMOD_FREE, // Channel free
44 CHMOD_COMMAND, // Command/error channel
45 CHMOD_DIRECTORY, // Reading directory, using large allocated buffer
46 CHMOD_FILE, // Sequential file open, using buffer in 1541 RAM
47 CHMOD_REL, // Relative file open, using buffer in 1541 RAM
48 CHMOD_DIRECT // Direct buffer access ('#'), using buffer in 1541 RAM
49 };
50
51 // Directory track
52 const int DIR_TRACK = 18;
53
54 // BAM structure
55 enum {
56 BAM_DIR_TRACK = 0, // Track...
57 BAM_DIR_SECTOR = 1, // ...and sector of first directory block (unused)
58 BAM_FMT_TYPE = 2, // Format type
59 BAM_BITMAP = 4, // Sector allocation map
60 BAM_DISK_NAME = 144, // Disk name
61 BAM_DISK_ID = 162, // Disk ID
62 BAM_FMT_CHAR = 165 // Format characters
63 };
64
65 // Directory structure
66 enum {
67 DIR_NEXT_TRACK = 0, // Track...
68 DIR_NEXT_SECTOR = 1, // ... and sector of next directory block
69 DIR_ENTRIES = 2, // Start of directory entries (8)
70
71 DE_TYPE = 0, // File type/flags
72 DE_TRACK = 1, // Track...
73 DE_SECTOR = 2, // ...and sector of first data block
74 DE_NAME = 3, // File name
75 DE_SIDE_TRACK = 19, // Track...
76 DE_SIDE_SECTOR = 20, // ...and sector of first side sector
77 DE_REC_LEN = 21, // Record length
78 DE_OVR_TRACK = 26, // Track...
79 DE_OVR_SECTOR = 27, // ...and sector on overwrite (@)
80 DE_NUM_BLOCKS_L = 28, // Number of blocks, LSB
81 DE_NUM_BLOCKS_H = 29, // Number of blocks, MSB
82
83 SIZEOF_DE = 32 // Size of directory entry
84 };
85
86 // Interleave of directory and data blocks
87 const int DIR_INTERLEAVE = 3;
88 const int DATA_INTERLEAVE = 10;
89
90 // Number of sectors per track, for all tracks
91 const int num_sectors[41] = {
92 0,
93 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
94 19,19,19,19,19,19,19,
95 18,18,18,18,18,18,
96 17,17,17,17,17,
97 17,17,17,17,17 // Tracks 36..40
98 };
99
100 // Accumulated number of sectors
101 const int accum_num_sectors[41] = {
102 0,
103 0,21,42,63,84,105,126,147,168,189,210,231,252,273,294,315,336,
104 357,376,395,414,433,452,471,
105 490,508,526,544,562,580,
106 598,615,632,649,666,
107 683,700,717,734,751 // Tracks 36..40
108 };
109
110 // Prototypes
111 static bool match(const uint8 *p, int p_len, const uint8 *n);
112 static FILE *open_image_file(const char *path, bool write_mode);
113 static bool parse_image_file(FILE *f, image_file_desc &desc);
114
115
116 /*
117 * Constructor: Prepare emulation, open image file
118 */
119
120 ImageDrive::ImageDrive(IEC *iec, const char *filepath) : Drive(iec), the_file(NULL), bam(ram + 0x700), bam_dirty(false)
121 {
122 for (int i=0; i<18; i++) {
123 ch[i].mode = CHMOD_FREE;
124 ch[i].buf = NULL;
125 }
126 ch[15].mode = CHMOD_COMMAND;
127
128 Reset();
129
130 // Open image file
131 if (change_image(filepath))
132 Ready = true;
133 }
134
135
136 /*
137 * Destructor
138 */
139
140 ImageDrive::~ImageDrive()
141 {
142 close_image();
143 }
144
145
146 /*
147 * Close the image file
148 */
149
150 void ImageDrive::close_image(void)
151 {
152 if (the_file) {
153 close_all_channels();
154 if (bam_dirty) {
155 write_sector(DIR_TRACK, 0, bam);
156 bam_dirty = false;
157 }
158 fclose(the_file);
159 the_file = NULL;
160 }
161 }
162
163
164 /*
165 * Open the image file
166 */
167
168 bool ImageDrive::change_image(const char *path)
169 {
170 // Close old image file
171 close_image();
172
173 // Open new image file (try write access first, then read-only)
174 write_protected = false;
175 the_file = open_image_file(path, true);
176 if (the_file == NULL) {
177 write_protected = true;
178 the_file = open_image_file(path, false);
179 }
180 if (the_file) {
181
182 // Determine file type and fill in image_file_desc structure
183 if (!parse_image_file(the_file, desc)) {
184 fclose(the_file);
185 the_file = false;
186 return false;
187 }
188
189 // Read BAM
190 read_sector(DIR_TRACK, 0, bam);
191 bam_dirty = false;
192 return true;
193 } else
194 return false;
195 }
196
197
198 /*
199 * Open channel
200 */
201
202 uint8 ImageDrive::Open(int channel, const uint8 *name, int name_len)
203 {
204 D(bug("ImageDrive::Open channel %d, file %s\n", channel, name));
205
206 set_error(ERR_OK);
207
208 // Channel 15: execute file name as command
209 if (channel == 15) {
210 execute_cmd(name, name_len);
211 return ST_OK;
212 }
213
214 if (ch[channel].mode != CHMOD_FREE) {
215 set_error(ERR_NOCHANNEL);
216 return ST_OK;
217 }
218
219 if (name[0] == '$')
220 if (channel)
221 return open_file_ts(channel, DIR_TRACK, 0);
222 else
223 return open_directory(name + 1, name_len - 1);
224
225 if (name[0] == '#')
226 return open_direct(channel, name);
227
228 return open_file(channel, name, name_len);
229 }
230
231
232 /*
233 * Open file
234 */
235
236 uint8 ImageDrive::open_file(int channel, const uint8 *name, int name_len)
237 {
238 uint8 plain_name[NAMEBUF_LENGTH];
239 int plain_name_len;
240 int mode = FMODE_READ;
241 int type = FTYPE_DEL;
242 int rec_len = 0;
243 parse_file_name(name, name_len, plain_name, plain_name_len, mode, type, rec_len);
244 if (plain_name_len > 16)
245 plain_name_len = 16;
246
247 D(bug(" plain name %s, type %d, mode %d\n", plain_name, type, mode));
248
249 // Channel 0 is READ, channel 1 is WRITE
250 if (channel == 0 || channel == 1) {
251 mode = channel ? FMODE_WRITE : FMODE_READ;
252 if (type == FTYPE_DEL)
253 type = FTYPE_PRG;
254 }
255
256 ch[channel].writing = (mode == FMODE_WRITE || mode == FMODE_APPEND);
257
258 // Wildcards are only allowed on reading
259 if (ch[channel].writing && (strchr((const char *)plain_name, '*') || strchr((const char *)plain_name, '?'))) {
260 set_error(ERR_SYNTAX33);
261 return ST_OK;
262 }
263
264 // Check for write-protection if writing
265 if (ch[channel].writing && write_protected) {
266 set_error(ERR_WRITEPROTECT);
267 return ST_OK;
268 }
269
270 // Relative files are not supported
271 if (type == FTYPE_REL) {
272 set_error(ERR_UNIMPLEMENTED);
273 return ST_OK;
274 }
275
276 // Find file in directory
277 int dir_track, dir_sector, entry;
278 if (find_first_file(plain_name, plain_name_len, dir_track, dir_sector, entry)) {
279
280 // File exists
281 D(bug(" file exists, dir track %d, sector %d, entry %d\n", dir_track, dir_sector, entry));
282 ch[channel].dir_track = dir_track;
283 ch[channel].dir_sector = dir_sector;
284 ch[channel].entry = entry;
285 uint8 *de = dir + DIR_ENTRIES + entry * SIZEOF_DE;
286
287 // Get file type from existing file if not specified in file name
288 if (type == FTYPE_DEL)
289 type = de[DE_TYPE] & 7;
290
291 if ((de[DE_TYPE] & 7) != type) {
292
293 // File type doesn't match
294 set_error(ERR_FILETYPE);
295
296 } else if (mode == FMODE_WRITE) {
297
298 if (name[0] == '@') {
299
300 // Open old file for overwriting (save-replace)
301 return create_file(channel, plain_name, plain_name_len, type, true);
302
303 } else {
304
305 // File to be written already exists, error
306 set_error(ERR_FILEEXISTS);
307 }
308
309 } else if (mode == FMODE_APPEND) {
310
311 // Open old file for appending
312 open_file_ts(channel, de[DE_TRACK], de[DE_SECTOR]);
313
314 // Seek to end of file
315 int track = 0, sector = 0, num_blocks = 0;
316 while (ch[channel].buf[0]) {
317 if (!read_sector(track = ch[channel].buf[0], sector = ch[channel].buf[1], ch[channel].buf))
318 return ST_OK;
319 num_blocks++;
320 }
321
322 // Change channel mode to writing, adjust buffer pointer
323 ch[channel].writing = true;
324 ch[channel].buf_len = ch[channel].buf[1] + 1;
325 ch[channel].buf_ptr = ch[channel].buf + ch[channel].buf_len;
326 ch[channel].track = track;
327 ch[channel].sector = sector;
328 ch[channel].num_blocks = num_blocks;
329
330 } else if (mode == FMODE_M) {
331
332 // Open old file for reading, even if it is not closed
333 return open_file_ts(channel, de[DE_TRACK], de[DE_SECTOR]);
334
335 } else {
336
337 // Open old file for reading, error if file is open
338 if (de[DE_TYPE] & 0x80)
339 return open_file_ts(channel, de[DE_TRACK], de[DE_SECTOR]);
340 else
341 set_error(ERR_WRITEFILEOPEN);
342 }
343
344 } else {
345
346 // File doesn't exist
347 D(bug(" file not found\n"));
348
349 // Set file type to SEQ if not specified in file name
350 if (type == FTYPE_DEL)
351 type = FTYPE_SEQ;
352
353 if (mode == FMODE_WRITE) {
354
355 // Create new file for writing
356 return create_file(channel, plain_name, plain_name_len, type);
357
358 } else
359 set_error(ERR_FILENOTFOUND);
360 }
361 return ST_OK;
362 }
363
364
365 /*
366 * Open channel for reading from file given track/sector of first block
367 */
368
369 uint8 ImageDrive::open_file_ts(int channel, int track, int sector)
370 {
371 D(bug("open_file_ts track %d, sector %d\n", track, sector));
372
373 // Allocate buffer and set channel mode
374 int buf = alloc_buffer(-1);
375 if (buf == -1) {
376 set_error(ERR_NOCHANNEL);
377 return ST_OK;
378 }
379 ch[channel].buf_num = buf;
380 ch[channel].buf = ram + 0x300 + buf * 0x100;
381 ch[channel].mode = CHMOD_FILE;
382
383 // On the next call to Read, the first block will be read
384 ch[channel].buf[0] = track;
385 ch[channel].buf[1] = sector;
386 ch[channel].buf_len = 0;
387
388 return ST_OK;
389 }
390
391
392 /*
393 * Create file and open channel for writing to file
394 */
395
396 uint8 ImageDrive::create_file(int channel, const uint8 *name, int name_len, int type, bool overwrite)
397 {
398 D(bug("create_file %s, type %d\n", name, type));
399
400 // Allocate buffer
401 int buf = alloc_buffer(-1);
402 if (buf == -1) {
403 set_error(ERR_NOCHANNEL);
404 return ST_OK;
405 }
406 ch[channel].buf_num = buf;
407 ch[channel].buf = ram + 0x300 + buf * 0x100;
408
409 // Allocate new directory entry if not overwriting
410 if (!overwrite) {
411 if (!alloc_dir_entry(ch[channel].dir_track, ch[channel].dir_sector, ch[channel].entry)) {
412 free_buffer(buf);
413 return ST_OK;
414 }
415 }
416 uint8 *de = dir + DIR_ENTRIES + ch[channel].entry * SIZEOF_DE;
417
418 // Allocate first data block
419 ch[channel].track = DIR_TRACK - 1;
420 ch[channel].sector = -DATA_INTERLEAVE;
421 if (!alloc_next_block(ch[channel].track, ch[channel].sector, DATA_INTERLEAVE)) {
422 free_buffer(buf);
423 return ST_OK;
424 }
425 ch[channel].num_blocks = 1;
426 D(bug(" first data block on track %d, sector %d\n", ch[channel].track, ch[channel].sector));
427
428 // Write directory entry
429 memset(de, 0, SIZEOF_DE);
430 de[DE_TYPE] = type; // bit 7 not set -> open file
431 if (overwrite) {
432 de[DE_OVR_TRACK] = ch[channel].track;
433 de[DE_OVR_SECTOR] = ch[channel].sector;
434 } else {
435 de[DE_TRACK] = ch[channel].track;
436 de[DE_SECTOR] = ch[channel].sector;
437 }
438 memset(de + DE_NAME, 0xa0, 16);
439 memcpy(de + DE_NAME, name, name_len);
440 write_sector(ch[channel].dir_track, ch[channel].dir_sector, dir);
441
442 // Set channel descriptor
443 ch[channel].mode = CHMOD_FILE;
444 ch[channel].writing = true;
445 ch[channel].buf_ptr = ch[channel].buf + 2;
446 ch[channel].buf_len = 2;
447 return ST_OK;
448 }
449
450
451 /*
452 * Prepare directory as BASIC program (channel 0)
453 */
454
455 const char type_char_1[] = "DSPUREER";
456 const char type_char_2[] = "EERSELQG";
457 const char type_char_3[] = "LQGRL???";
458
459 uint8 ImageDrive::open_directory(const uint8 *pattern, int pattern_len)
460 {
461 // Special treatment for "$0"
462 if (pattern[0] == '0' && pattern_len == 1) {
463 pattern++;
464 pattern_len--;
465 }
466
467 // Skip everything before the ':' in the pattern
468 uint8 *t = (uint8 *)memchr(pattern, ':', pattern_len);
469 if (t) {
470 t++;
471 pattern_len -= t - pattern;
472 pattern = t;
473 }
474
475 ch[0].mode = CHMOD_DIRECTORY;
476 uint8 *p = ch[0].buf_ptr = ch[0].buf = new uint8[8192];
477
478 // Create directory title with disk name, ID and format type
479 *p++ = 0x01; // Load address $0401 (from PET days :-)
480 *p++ = 0x04;
481 *p++ = 0x01; // Dummy line link
482 *p++ = 0x01;
483 *p++ = 0; // Drive number (0) as line number
484 *p++ = 0;
485 *p++ = 0x12; // RVS ON
486 *p++ = '\"';
487
488 uint8 *q = bam + BAM_DISK_NAME;
489 for (int i=0; i<23; i++) {
490 int c;
491 if ((c = *q++) == 0xa0)
492 *p++ = ' '; // Replace 0xa0 by space
493 else
494 *p++ = c;
495 }
496 *(p-7) = '\"';
497 *p++ = 0;
498
499 // Scan all directory blocks
500 dir[DIR_NEXT_TRACK] = DIR_TRACK;
501 dir[DIR_NEXT_SECTOR] = 1;
502
503 int num_dir_blocks = 0;
504 while (dir[DIR_NEXT_TRACK] && num_dir_blocks < num_sectors[DIR_TRACK]) {
505 if (!read_sector(dir[DIR_NEXT_TRACK], dir[DIR_NEXT_SECTOR], dir))
506 return ST_OK;
507 num_dir_blocks++;
508
509 // Scan all 8 entries of a block
510 uint8 *de = dir + DIR_ENTRIES;
511 for (int j=0; j<8; j++, de+=SIZEOF_DE) {
512 if (de[DE_TYPE] && (pattern_len == 0 || match(pattern, pattern_len, de + DE_NAME))) {
513
514 // Dummy line link
515 *p++ = 0x01;
516 *p++ = 0x01;
517
518 // Line number = number of blocks
519 *p++ = de[DE_NUM_BLOCKS_L];
520 *p++ = de[DE_NUM_BLOCKS_H];
521
522 // Appropriate number of spaces to align file names
523 *p++ = ' ';
524 int n = (de[DE_NUM_BLOCKS_H] << 8) + de[DE_NUM_BLOCKS_L];
525 if (n<10) *p++ = ' ';
526 if (n<100) *p++ = ' ';
527
528 // File name enclosed in quotes
529 *p++ = '\"';
530 q = de + DE_NAME;
531 uint8 c;
532 bool m = false;
533 for (int i=0; i<16; i++) {
534 if ((c = *q++) == 0xa0) {
535 if (m)
536 *p++ = ' '; // Replace all 0xa0 by spaces
537 else
538 m = (*p++ = '\"'); // But the first by a '"'
539 } else
540 *p++ = c;
541 }
542 if (m)
543 *p++ = ' ';
544 else
545 *p++ = '\"'; // No 0xa0, then append a space
546
547 // Open files are marked by '*'
548 if (de[DE_TYPE] & 0x80)
549 *p++ = ' ';
550 else
551 *p++ = '*';
552
553 // File type
554 *p++ = type_char_1[de[DE_TYPE] & 7];
555 *p++ = type_char_2[de[DE_TYPE] & 7];
556 *p++ = type_char_3[de[DE_TYPE] & 7];
557
558 // Protected files are marked by '<'
559 if (de[DE_TYPE] & 0x40)
560 *p++ = '<';
561 else
562 *p++ = ' ';
563
564 // Appropriate number of spaces at the end
565 *p++ = ' ';
566 if (n >= 10) *p++ = ' ';
567 if (n >= 100) *p++ = ' ';
568 *p++ = 0;
569 }
570 }
571 }
572
573 // Final line, count number of free blocks
574 int n = 0;
575 for (int i=1; i<=35; i++) {
576 if (i != DIR_TRACK) // exclude track 18
577 n += num_free_blocks(i);
578 }
579
580 *p++ = 0x01; // Dummy line link
581 *p++ = 0x01;
582 *p++ = n & 0xff; // Number of free blocks as line number
583 *p++ = (n >> 8) & 0xff;
584
585 *p++ = 'B';
586 *p++ = 'L';
587 *p++ = 'O';
588 *p++ = 'C';
589 *p++ = 'K';
590 *p++ = 'S';
591 *p++ = ' ';
592 *p++ = 'F';
593 *p++ = 'R';
594 *p++ = 'E';
595 *p++ = 'E';
596 *p++ = '.';
597
598 memset(p, ' ', 13);
599 p += 13;
600
601 *p++ = 0;
602 *p++ = 0;
603 *p++ = 0;
604
605 ch[0].buf_len = p - ch[0].buf;
606 return ST_OK;
607 }
608
609
610 /*
611 * Open channel for direct buffer access
612 */
613
614 uint8 ImageDrive::open_direct(int channel, const uint8 *name)
615 {
616 int buf = -1;
617
618 if (name[1] == 0)
619 buf = alloc_buffer(-1);
620 else
621 if ((name[1] >= '0') && (name[1] <= '3') && (name[2] == 0))
622 buf = alloc_buffer(name[1] - '0');
623
624 if (buf == -1) {
625 set_error(ERR_NOCHANNEL);
626 return ST_OK;
627 }
628
629 // The buffers are in the 1541 RAM at $300 and are 256 bytes each
630 ch[channel].mode = CHMOD_DIRECT;
631 ch[channel].buf = ram + 0x300 + buf * 0x100;
632 ch[channel].buf_num = buf;
633
634 // Store actual buffer number in buffer
635 ch[channel].buf[1] = buf + '0';
636 ch[channel].buf_len = 1;
637 ch[channel].buf_ptr = ch[channel].buf + 1;
638
639 return ST_OK;
640 }
641
642
643 /*
644 * Close channel
645 */
646
647 uint8 ImageDrive::Close(int channel)
648 {
649 D(bug("ImageDrive::Close channel %d\n", channel));
650
651 switch (ch[channel].mode) {
652 case CHMOD_FREE:
653 break;
654
655 case CHMOD_COMMAND:
656 close_all_channels();
657 break;
658
659 case CHMOD_DIRECT:
660 free_buffer(ch[channel].buf_num);
661 ch[channel].buf = NULL;
662 ch[channel].mode = CHMOD_FREE;
663 break;
664
665 case CHMOD_FILE:
666 if (ch[channel].writing) {
667
668 // Current block empty? Then write CR character
669 if (ch[channel].buf_len == 2) {
670 ch[channel].buf[2] = 0x0d;
671 ch[channel].buf_len++;
672 }
673
674 // Write last data block
675 ch[channel].buf[0] = 0;
676 ch[channel].buf[1] = ch[channel].buf_len - 1;
677 D(bug(" writing last data block\n"));
678 if (!write_sector(ch[channel].track, ch[channel].sector, ch[channel].buf))
679 goto free;
680
681 // Close write file in directory
682 read_sector(ch[channel].dir_track, ch[channel].dir_sector, dir);
683 uint8 *de = dir + DIR_ENTRIES + ch[channel].entry * SIZEOF_DE;
684 de[DE_TYPE] |= 0x80;
685 de[DE_NUM_BLOCKS_L] = ch[channel].num_blocks & 0xff;
686 de[DE_NUM_BLOCKS_H] = ch[channel].num_blocks >> 8;
687 if (de[DE_OVR_TRACK]) {
688 // Overwriting, free old data blocks and set pointer to new ones
689 free_block_chain(de[DE_TRACK], de[DE_SECTOR]);
690 de[DE_TRACK] = de[DE_OVR_TRACK];
691 de[DE_SECTOR] = de[DE_OVR_SECTOR];
692 de[DE_OVR_TRACK] = de[DE_OVR_SECTOR] = 0;
693 }
694 write_sector(ch[channel].dir_track, ch[channel].dir_sector, dir);
695 D(bug(" directory entry updated\n"));
696 }
697 free: free_buffer(ch[channel].buf_num);
698 ch[channel].buf = NULL;
699 ch[channel].mode = CHMOD_FREE;
700 break;
701
702 case CHMOD_DIRECTORY:
703 delete[] ch[channel].buf;
704 ch[channel].buf = NULL;
705 ch[channel].mode = CHMOD_FREE;
706 break;
707 }
708
709 return ST_OK;
710 }
711
712
713 /*
714 * Close all channels
715 */
716
717 void ImageDrive::close_all_channels()
718 {
719 for (int i=0; i<15; i++)
720 Close(i);
721 Close(16);
722 Close(17);
723
724 cmd_len = 0;
725 }
726
727
728 /*
729 * Read from channel
730 */
731
732 uint8 ImageDrive::Read(int channel, uint8 &byte)
733 {
734 // D(bug("ImageDrive::Read channel %d\n", channel));
735
736 switch (ch[channel].mode) {
737 case CHMOD_FREE:
738 if (current_error == ERR_OK)
739 set_error(ERR_FILENOTOPEN);
740 break;
741
742 case CHMOD_COMMAND:
743 // Read error channel
744 byte = *error_ptr++;
745 if (--error_len)
746 return ST_OK;
747 else {
748 set_error(ERR_OK);
749 return ST_EOF;
750 }
751 break;
752
753 case CHMOD_FILE:
754 if (ch[channel].writing)
755 return ST_READ_TIMEOUT;
756 if (current_error != ERR_OK)
757 return ST_READ_TIMEOUT;
758
759 // Read next block if necessary
760 if (ch[channel].buf_len == 0 && ch[channel].buf[0]) {
761 D(bug(" reading next data block track %d, sector %d\n", ch[channel].buf[0], ch[channel].buf[1]));
762 if (!read_sector(ch[channel].buf[0], ch[channel].buf[1], ch[channel].buf))
763 return ST_READ_TIMEOUT;
764 ch[channel].buf_ptr = ch[channel].buf + 2;
765
766 // Determine block length
767 ch[channel].buf_len = ch[channel].buf[0] ? 254 : ch[channel].buf[1] - 1;
768 }
769
770 if (ch[channel].buf_len > 0) {
771 byte = *(ch[channel].buf_ptr)++;
772 if (--(ch[channel].buf_len) == 0 && ch[channel].buf[0] == 0)
773 return ST_EOF;
774 else
775 return ST_OK;
776 } else
777 return ST_READ_TIMEOUT;
778 break;
779
780 case CHMOD_DIRECTORY:
781 case CHMOD_DIRECT:
782 if (ch[channel].buf_len > 0) {
783 byte = *(ch[channel].buf_ptr)++;
784 if (--(ch[channel].buf_len))
785 return ST_OK;
786 else
787 return ST_EOF;
788 } else
789 return ST_READ_TIMEOUT;
790 break;
791 }
792 return ST_READ_TIMEOUT;
793 }
794
795
796 /*
797 * Write byte to channel
798 */
799
800 uint8 ImageDrive::Write(int channel, uint8 byte, bool eoi)
801 {
802 // D(bug("ImageDrive::Write channel %d, byte %02x, eoi %d\n", channel, byte, eoi));
803
804 switch (ch[channel].mode) {
805 case CHMOD_FREE:
806 if (current_error == ERR_OK)
807 set_error(ERR_FILENOTOPEN);
808 break;
809
810 case CHMOD_COMMAND:
811 // Collect characters and execute command on EOI
812 if (cmd_len > 58) {
813 set_error(ERR_SYNTAX32);
814 return ST_TIMEOUT;
815 }
816
817 cmd_buf[cmd_len++] = byte;
818
819 if (eoi) {
820 execute_cmd(cmd_buf, cmd_len);
821 cmd_len = 0;
822 }
823 return ST_OK;
824
825 case CHMOD_DIRECTORY:
826 set_error(ERR_WRITEFILEOPEN);
827 break;
828
829 case CHMOD_FILE:
830 if (!ch[channel].writing)
831 return ST_TIMEOUT;
832 if (current_error != ERR_OK)
833 return ST_TIMEOUT;
834
835 // Buffer full?
836 if (ch[channel].buf_len >= 256) {
837
838 // Yes, allocate new block
839 int track = ch[channel].track, sector = ch[channel].sector;
840 if (!alloc_next_block(track, sector, DATA_INTERLEAVE))
841 return ST_TIMEOUT;
842 ch[channel].num_blocks++;
843 D(bug("next data block on track %d, sector %d\n", track, sector));
844
845 // Write buffer with link to new block
846 ch[channel].buf[0] = track;
847 ch[channel].buf[1] = sector;
848 write_sector(ch[channel].track, ch[channel].sector, ch[channel].buf);
849
850 // Reset buffer
851 ch[channel].buf_ptr = ch[channel].buf + 2;
852 ch[channel].buf_len = 2;
853 ch[channel].track = track;
854 ch[channel].sector = sector;
855 }
856 *(ch[channel].buf_ptr)++ = byte;
857 ch[channel].buf_len++;
858 return ST_OK;
859
860 case CHMOD_DIRECT:
861 if (ch[channel].buf_len < 256) {
862 *(ch[channel].buf_ptr)++ = byte;
863 ch[channel].buf_len++;
864 return ST_OK;
865 } else
866 return ST_TIMEOUT;
867 break;
868 }
869 return ST_TIMEOUT;
870 }
871
872
873 /*
874 * Reset drive
875 */
876
877 void ImageDrive::Reset(void)
878 {
879 close_all_channels();
880
881 cmd_len = 0;
882 for (int i=0; i<4; i++)
883 buf_free[i] = true;
884
885 if (bam_dirty) {
886 write_sector(DIR_TRACK, 0, bam);
887 bam_dirty = false;
888 }
889
890 memset(ram, 0, sizeof(ram));
891
892 read_sector(DIR_TRACK, 0, bam);
893
894 set_error(ERR_STARTUP);
895 }
896
897
898 /*
899 * Allocate floppy buffer
900 * -> Desired buffer number or -1
901 * <- Allocated buffer number or -1
902 */
903
904 int ImageDrive::alloc_buffer(int want)
905 {
906 if (want == -1) {
907 for (want=3; want>=0; want--)
908 if (buf_free[want]) {
909 buf_free[want] = false;
910 return want;
911 }
912 return -1;
913 }
914
915 if (want < 4)
916 if (buf_free[want]) {
917 buf_free[want] = false;
918 return want;
919 } else
920 return -1;
921 else
922 return -1;
923 }
924
925
926 /*
927 * Free floppy buffer
928 */
929
930 void ImageDrive::free_buffer(int buf)
931 {
932 buf_free[buf] = true;
933 }
934
935
936 /*
937 * Search file in directory, return directory track/sector and entry number
938 * false: not found, true: found
939 */
940
941 // Return true if name 'n' matches pattern 'p'
942 static bool match(const uint8 *p, int p_len, const uint8 *n)
943 {
944 if (p_len > 16)
945 p_len = 16;
946
947 int c = 0;
948 while (p_len-- > 0) {
949 if (*p == '*') // Wildcard '*' matches all following characters
950 return true;
951 if ((*p != *n) && (*p != '?')) // Wildcard '?' matches single character
952 return false;
953 p++; n++; c++;
954 }
955
956 return *n == 0xa0 || c == 16;
957 }
958
959 bool ImageDrive::find_file(const uint8 *pattern, int pattern_len, int &dir_track, int &dir_sector, int &entry, bool cont)
960 {
961 // Counter to prevent cyclic directories from resulting in an infinite loop
962 int num_dir_blocks = 0;
963
964 // Pointer to current directory entry
965 uint8 *de = NULL;
966 if (cont)
967 de = dir + DIR_ENTRIES + entry * SIZEOF_DE;
968 else {
969 dir[DIR_NEXT_TRACK] = DIR_TRACK;
970 dir[DIR_NEXT_SECTOR] = 1;
971 entry = 8;
972 }
973
974 while (num_dir_blocks < num_sectors[DIR_TRACK]) {
975
976 // Goto next entry
977 entry++; de += SIZEOF_DE;
978 if (entry >= 8) {
979
980 // Read next directory block
981 if (dir[DIR_NEXT_TRACK] == 0)
982 return false;
983 if (!read_sector(dir_track = dir[DIR_NEXT_TRACK], dir_sector = dir[DIR_NEXT_SECTOR], dir))
984 return false;
985 num_dir_blocks++;
986 entry = 0;
987 de = dir + DIR_ENTRIES;
988 }
989
990 // Does entry match pattern?
991 if (de[DE_TYPE] && match(pattern, pattern_len, de + DE_NAME))
992 return true;
993 }
994 return false;
995 }
996
997 bool ImageDrive::find_first_file(const uint8 *pattern, int pattern_len, int &dir_track, int &dir_sector, int &entry)
998 {
999 return find_file(pattern, pattern_len, dir_track, dir_sector, entry, false);
1000 }
1001
1002 bool ImageDrive::find_next_file(const uint8 *pattern, int pattern_len, int &dir_track, int &dir_sector, int &entry)
1003 {
1004 return find_file(pattern, pattern_len, dir_track, dir_sector, entry, true);
1005 }
1006
1007
1008 /*
1009 * Allocate new entry in directory, returns false on error (usually when
1010 * all sectors of track 18 are allocated)
1011 * The track/sector and entry numbers are returned
1012 */
1013
1014 bool ImageDrive::alloc_dir_entry(int &track, int &sector, int &entry)
1015 {
1016 // First look for free entry in existing directory blocks
1017 dir[DIR_NEXT_TRACK] = DIR_TRACK;
1018 dir[DIR_NEXT_SECTOR] = 1;
1019 while (dir[DIR_NEXT_TRACK]) {
1020 if (!read_sector(track = dir[DIR_NEXT_TRACK], sector = dir[DIR_NEXT_SECTOR], dir))
1021 return false;
1022
1023 uint8 *de = dir + DIR_ENTRIES;
1024 for (entry=0; entry<8; entry++, de+=SIZEOF_DE) {
1025 if (de[DE_TYPE] == 0) {
1026 D(bug(" allocated entry %d in dir track %d, sector %d\n", entry, track, sector));
1027 return true;
1028 }
1029 }
1030 }
1031
1032 // No free entry found, allocate new directory block
1033 int last_track = track, last_sector = sector;
1034 if (!alloc_next_block(track, sector, DIR_INTERLEAVE))
1035 return false;
1036 D(bug(" new directory block track %d, sector %d\n", track, sector));
1037
1038 // Write link to new block to last block
1039 dir[DIR_NEXT_TRACK] = track;
1040 dir[DIR_NEXT_SECTOR] = sector;
1041 write_sector(last_track, last_sector, dir);
1042
1043 // Write new empty directory block and return first entry
1044 memset(dir, 0, 256);
1045 dir[DIR_NEXT_SECTOR] = 0xff;
1046 write_sector(track, sector, dir);
1047 entry = 0;
1048 return true;
1049 }
1050
1051 /*
1052 * Test if block is free in BAM (track/sector are not checked for validity)
1053 */
1054
1055 bool ImageDrive::is_block_free(int track, int sector)
1056 {
1057 uint8 *p = bam + BAM_BITMAP + (track - 1) * 4;
1058 int byte = sector / 8 + 1;
1059 int bit = sector & 7;
1060 return p[byte] & (1 << bit);
1061 }
1062
1063
1064 /*
1065 * Get number of free blocks on a track
1066 */
1067
1068 int ImageDrive::num_free_blocks(int track)
1069 {
1070 return bam[BAM_BITMAP + (track - 1) * 4];
1071 }
1072
1073
1074 /*
1075 * Clear BAM, mark all blocks as free
1076 */
1077
1078 static void clear_bam(uint8 *bam)
1079 {
1080 for (int track=1; track<=35; track++) {
1081 static const uint8 num2bits[8] = {0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
1082 (bam + BAM_BITMAP)[(track-1) * 4 + 0] = num_sectors[track];
1083 (bam + BAM_BITMAP)[(track-1) * 4 + 1] = 0xff;
1084 (bam + BAM_BITMAP)[(track-1) * 4 + 2] = 0xff;
1085 (bam + BAM_BITMAP)[(track-1) * 4 + 3] = num2bits[num_sectors[track] - 16];
1086 }
1087 }
1088
1089
1090 /*
1091 * Allocate block in BAM, returns error code
1092 */
1093
1094 int ImageDrive::alloc_block(int track, int sector)
1095 {
1096 if (track < 1 || track > 35 || sector < 0 || sector >= num_sectors[track])
1097 return ERR_ILLEGALTS;
1098
1099 uint8 *p = bam + BAM_BITMAP + (track - 1) * 4;
1100 int byte = sector / 8 + 1;
1101 int bit = sector & 7;
1102
1103 // Block free?
1104 if (p[byte] & (1 << bit)) {
1105
1106 // Yes, allocate and decrement free block count
1107 D(bug("allocating block at track %d, sector %d\n", track, sector));
1108 p[byte] &= ~(1 << bit);
1109 p[0]--;
1110 bam_dirty = true;
1111 return ERR_OK;
1112
1113 } else
1114 return ERR_NOBLOCK;
1115 }
1116
1117
1118 /*
1119 * Free block in BAM, returns error code
1120 */
1121
1122 int ImageDrive::free_block(int track, int sector)
1123 {
1124 if (track < 1 || track > 35 || sector < 0 || sector >= num_sectors[track])
1125 return ERR_ILLEGALTS;
1126
1127 uint8 *p = bam + BAM_BITMAP + (track - 1) * 4;
1128 int byte = sector / 8 + 1;
1129 int bit = sector & 7;
1130
1131 // Block allocated?
1132 if (!(p[byte] & (1 << bit))) {
1133
1134 // Yes, free and increment free block count
1135 D(bug("freeing block at track %d, sector %d\n", track, sector));
1136 p[byte] |= (1 << bit);
1137 p[0]++;
1138 bam_dirty = true;
1139 }
1140 return ERR_OK;
1141 }
1142
1143
1144 /*
1145 * Allocate chain of data blocks in BAM
1146 */
1147
1148 bool ImageDrive::alloc_block_chain(int track, int sector)
1149 {
1150 uint8 buf[256];
1151 while (alloc_block(track, sector) == ERR_OK) {
1152 if (!read_sector(track, sector, buf))
1153 return false;
1154 track = buf[0];
1155 sector = buf[1];
1156 }
1157 return true;
1158 }
1159
1160
1161 /*
1162 * Free chain of data blocks in BAM
1163 */
1164
1165 bool ImageDrive::free_block_chain(int track, int sector)
1166 {
1167 uint8 buf[256];
1168 while (free_block(track, sector) == ERR_OK) {
1169 if (!read_sector(track, sector, buf))
1170 return false;
1171 track = buf[0];
1172 sector = buf[1];
1173 }
1174 return true;
1175 }
1176
1177
1178 /*
1179 * Search and allocate next free block, returns false if no more blocks
1180 * are free (ERR_DISKFULL is also set in this case)
1181 * "track" and "sector" must be set to the block where the search should
1182 * begin
1183 */
1184
1185 bool ImageDrive::alloc_next_block(int &track, int &sector, int interleave)
1186 {
1187 // Find track with free blocks
1188 bool side_changed = false;
1189 while (num_free_blocks(track) == 0) {
1190 if (track == DIR_TRACK) { // Directory doesn't grow to other tracks
1191 full: track = sector = 0;
1192 set_error(ERR_DISKFULL);
1193 return false;
1194 } else if (track > DIR_TRACK) {
1195 track++;
1196 if (track > 35) {
1197 if (!side_changed)
1198 side_changed = true;
1199 else
1200 goto full;
1201 track = DIR_TRACK - 1;
1202 sector = 0;
1203 }
1204 } else {
1205 track--;
1206 if (track < 1) {
1207 if (!side_changed)
1208 side_changed = true;
1209 else
1210 goto full;
1211 track = DIR_TRACK + 1;
1212 sector = 0;
1213 }
1214 }
1215 }
1216
1217 // Find next free block on track
1218 int num = num_sectors[track];
1219 sector = sector + interleave;
1220 if (sector >= num) {
1221 sector -= num;
1222 if (sector)
1223 sector--;
1224 }
1225 while (!is_block_free(track, sector)) {
1226 sector++;
1227 if (sector >= num_sectors[track]) {
1228 sector = 0;
1229 while (!is_block_free(track, sector)) {
1230 sector++;
1231 if (sector >= num_sectors[track]) {
1232 // Something is wrong: the BAM free block count for this
1233 // track was >0, but we found no free blocks
1234 track = sector = 0;
1235 set_error(ERR_DIRERROR);
1236 return false;
1237 }
1238 }
1239 }
1240 }
1241
1242 alloc_block(track, sector);
1243 return true;
1244 }
1245
1246
1247 /*
1248 * Sector reading/writing routines
1249 */
1250
1251 static long offset_from_ts(const image_file_desc &desc, int track, int sector)
1252 {
1253 if ((track < 1) || (track > desc.num_tracks)
1254 || (sector < 0) || (sector >= num_sectors[track]))
1255 return -1;
1256
1257 return ((accum_num_sectors[track] + sector) << 8) + desc.header_size;
1258 }
1259
1260 // Get number of sectors per given track
1261 int sectors_per_track(const image_file_desc &desc, int track)
1262 {
1263 return num_sectors[track];
1264 }
1265
1266 // Get reference to error info byte of given track/sector
1267 uint8 &error_info_for_sector(image_file_desc &desc, int track, int sector)
1268 {
1269 return desc.error_info[accum_num_sectors[track] + sector];
1270 }
1271
1272 static inline const uint8 &error_info_for_sector(const image_file_desc &desc, int track, int sector)
1273 {
1274 return desc.error_info[accum_num_sectors[track] + sector];
1275 }
1276
1277 const int conv_job_error[16] = {
1278 ERR_OK, // 0 -> 00 OK
1279 ERR_OK, // 1 -> 00 OK
1280 ERR_READ20, // 2 -> 20 READ ERROR
1281 ERR_READ21, // 3 -> 21 READ ERROR
1282 ERR_READ22, // 4 -> 22 READ ERROR
1283 ERR_READ23, // 5 -> 23 READ ERROR
1284 ERR_READ24, // 6 -> 24 READ ERROR (undetected by 1541)
1285 ERR_WRITE25, // 7 -> 25 WRITE ERROR
1286 ERR_WRITEPROTECT, // 8 -> 26 WRITE PROTECT ON
1287 ERR_READ27, // 9 -> 27 READ ERROR
1288 ERR_WRITE28, // 10 -> 28 WRITE ERROR
1289 ERR_DISKID, // 11 -> 29 DISK ID MISMATCH
1290 ERR_OK, // 12 -> 00 OK
1291 ERR_OK, // 13 -> 00 OK
1292 ERR_OK, // 14 -> 00 OK
1293 ERR_NOTREADY // 15 -> 74 DRIVE NOT READY
1294 };
1295
1296 // Read sector, return error code
1297 static int read_sector(FILE *f, const image_file_desc &desc, int track, int sector, uint8 *buffer)
1298 {
1299 // Convert track/sector to byte offset in file
1300 long offset = offset_from_ts(desc, track, sector);
1301 if (offset < 0)
1302 return ERR_ILLEGALTS;
1303
1304 if (f == NULL)
1305 return ERR_NOTREADY;
1306
1307 fseek(f, offset, SEEK_SET);
1308 if (fread(buffer, 1, 256, f) != 256)
1309 return ERR_READ22;
1310 else {
1311 unsigned int error = error_info_for_sector(desc, track, sector);
1312 return conv_job_error[error & 0x0f];
1313 }
1314 }
1315
1316 // Write sector, return error code
1317 static int write_sector(FILE *f, const image_file_desc &desc, int track, int sector, uint8 *buffer)
1318 {
1319 // Convert track/sector to byte offset in file
1320 long offset = offset_from_ts(desc, track, sector);
1321 if (offset < 0)
1322 return ERR_ILLEGALTS;
1323
1324 if (f == NULL)
1325 return ERR_NOTREADY;
1326
1327 fseek(f, offset, SEEK_SET);
1328 if (fwrite(buffer, 1, 256, f) != 256)
1329 return ERR_WRITE25;
1330 else
1331 return ERR_OK;
1332 }
1333
1334 // Read sector and set error message, returns false on error
1335 bool ImageDrive::read_sector(int track, int sector, uint8 *buffer)
1336 {
1337 int error = ::read_sector(the_file, desc, track, sector, buffer);
1338 if (error)
1339 set_error(error, track, sector);
1340 return error == ERR_OK;
1341 }
1342
1343 // Write sector and set error message, returns false on error
1344 bool ImageDrive::write_sector(int track, int sector, uint8 *buffer)
1345 {
1346 int error = ::write_sector(the_file, desc, track, sector, buffer);
1347 if (error)
1348 set_error(error, track, sector);
1349 return error == ERR_OK;
1350 }
1351
1352 // Write error info back to image file
1353 static void write_back_error_info(FILE *f, const image_file_desc &desc)
1354 {
1355 if (desc.type == TYPE_D64 && desc.has_error_info) {
1356 int num_sectors = desc.num_tracks == 40 ? NUM_SECTORS_40 : NUM_SECTORS_35;
1357 fseek(f, num_sectors * 256, SEEK_SET);
1358 fwrite(desc.error_info, num_sectors, 1, f);
1359 }
1360 }
1361
1362 // Format disk image
1363 static bool format_image(FILE *f, image_file_desc &desc, bool lowlevel, uint8 id1, uint8 id2, const uint8 *disk_name, int disk_name_len)
1364 {
1365 uint8 p[256];
1366
1367 if (lowlevel) {
1368
1369 // Fill buffer with 1541 empty sector pattern (4b 01 01 ...,
1370 // except on track 1 where it's 01 01 01 ...)
1371 memset(p, 1, 256);
1372
1373 // Overwrite all blocks
1374 for (int track=1; track<=35; track++) {
1375 if (track == 2)
1376 p[0] = 0x4b;
1377 for (int sector=0; sector<num_sectors[track]; sector++) {
1378 if (write_sector(f, desc, track, sector, p) != ERR_OK)
1379 return false;
1380 }
1381 }
1382
1383 // Clear and write error info
1384 memset(desc.error_info, 1, sizeof(desc.error_info));
1385 write_back_error_info(f, desc);
1386
1387 // Clear BAM
1388 memset(p, 0, 256);
1389
1390 } else {
1391
1392 // Read BAM
1393 if (read_sector(f, desc, DIR_TRACK, 0, p) != ERR_OK)
1394 return false;
1395 }
1396
1397 // Create and write empty BAM
1398 p[BAM_DIR_TRACK] = DIR_TRACK;
1399 p[BAM_DIR_SECTOR] = 1;
1400 p[BAM_FMT_TYPE] = 'A';
1401 clear_bam(p);
1402 p[BAM_BITMAP + (DIR_TRACK - 1) * 4 + 0] -= 2; // Allocate BAM and first directory block
1403 p[BAM_BITMAP + (DIR_TRACK - 1) * 4 + 1] &= 0xfc;
1404 memset(p + BAM_DISK_NAME, 0xa0, 27);
1405 if (disk_name_len > 16)
1406 disk_name_len = 16;
1407 memcpy(p + BAM_DISK_NAME, disk_name, disk_name_len);
1408 p[BAM_DISK_ID] = id1;
1409 p[BAM_DISK_ID + 1] = id2;
1410 p[BAM_FMT_CHAR] = '2';
1411 p[BAM_FMT_CHAR + 1] = 'A';
1412 if (write_sector(f, desc, DIR_TRACK, 0, p) != ERR_OK)
1413 return false;
1414
1415 // Create and write empty directory
1416 memset(p, 0, 256);
1417 p[1] = 255;
1418 return write_sector(f, desc, DIR_TRACK, 1, p) == ERR_OK;
1419 }
1420
1421
1422 /*
1423 * Execute drive commands
1424 */
1425
1426 // BLOCK-READ:channel,0,track,sector
1427 void ImageDrive::block_read_cmd(int channel, int track, int sector, bool user_cmd)
1428 {
1429 if (channel >= 16 || ch[channel].mode != CHMOD_DIRECT) {
1430 set_error(ERR_NOCHANNEL);
1431 return;
1432 }
1433 if (!read_sector(track, sector, ch[channel].buf))
1434 return;
1435 if (user_cmd) {
1436 ch[channel].buf_len = 256;
1437 ch[channel].buf_ptr = ch[channel].buf;
1438 } else {
1439 ch[channel].buf_len = ch[channel].buf[0];
1440 ch[channel].buf_ptr = ch[channel].buf + 1;
1441 }
1442 }
1443
1444 // BLOCK-WRITE:channel,0,track,sector
1445 void ImageDrive::block_write_cmd(int channel, int track, int sector, bool user_cmd)
1446 {
1447 if (write_protected) {
1448 set_error(ERR_WRITEPROTECT);
1449 return;
1450 }
1451 if (channel >= 16 || ch[channel].mode != CHMOD_DIRECT) {
1452 set_error(ERR_NOCHANNEL);
1453 return;
1454 }
1455 if (!user_cmd)
1456 ch[channel].buf[0] = ch[channel].buf_len ? ch[channel].buf_len - 1 : 1;
1457 if (!write_sector(track, sector, ch[channel].buf))
1458 return;
1459 if (!user_cmd) {
1460 ch[channel].buf_len = 1;
1461 ch[channel].buf_ptr = ch[channel].buf + 1;
1462 }
1463 }
1464
1465 // BLOCK-ALLOCATE:0,track,sector
1466 void ImageDrive::block_allocate_cmd(int track, int sector)
1467 {
1468 int err = alloc_block(track, sector);
1469 if (err) {
1470 if (err == ERR_NOBLOCK) {
1471 // Find next free block and return its track/sector address in the
1472 // error message (only look on higher tracks)
1473 for (;;) {
1474 sector++;
1475 if (sector >= num_sectors[track]) {
1476 track++;
1477 sector = 0;
1478 if (track > 35) {
1479 set_error(ERR_NOBLOCK, 0, 0);
1480 return;
1481 }
1482 }
1483 if (is_block_free(track, sector)) {
1484 set_error(ERR_NOBLOCK, track, sector);
1485 return;
1486 }
1487 }
1488 } else
1489 set_error(err, track, sector);
1490 }
1491 }
1492
1493 // BLOCK-FREE:0,track,sector
1494 void ImageDrive::block_free_cmd(int track, int sector)
1495 {
1496 int err = free_block(track, sector);
1497 if (err)
1498 set_error(err, track, sector);
1499 }
1500
1501 // BUFFER-POINTER:channel,pos
1502 void ImageDrive::buffer_pointer_cmd(int channel, int pos)
1503 {
1504 if (channel >= 16 || ch[channel].mode != CHMOD_DIRECT) {
1505 set_error(ERR_NOCHANNEL);
1506 return;
1507 }
1508 ch[channel].buf_ptr = ch[channel].buf + pos;
1509 ch[channel].buf_len = 256 - pos;
1510 }
1511
1512 // M-R<adr low><adr high>[<number>]
1513 void ImageDrive::mem_read_cmd(uint16 adr, uint8 len)
1514 {
1515 error_len = len;
1516 if (adr >= 0x300 && adr < 0x1000) {
1517 // Read from RAM
1518 error_ptr = (char *)ram + (adr & 0x7ff);
1519 } else if (adr >= 0xc000) {
1520 // Read from ROM
1521 error_ptr = (char *)(TheC64->ROM1541) + (adr - 0xc000);
1522 } else {
1523 unsupp_cmd();
1524 memset(error_buf, 0, len);
1525 error_ptr = error_buf;
1526 }
1527 }
1528
1529 // M-W<adr low><adr high><number><data...>
1530 void ImageDrive::mem_write_cmd(uint16 adr, uint8 len, uint8 *p)
1531 {
1532 while (len) {
1533 if (adr >= 0x300 && adr < 0x1000) {
1534 // Write to RAM
1535 ram[adr & 0x7ff] = *p;
1536 } else if (adr < 0xc000) {
1537 unsupp_cmd();
1538 return;
1539 }
1540 len--; adr++; p++;
1541 }
1542 }
1543
1544 // COPY:new=file1,file2,...
1545 // ^ ^
1546 // new_file old_files
1547 void ImageDrive::copy_cmd(const uint8 *new_file, int new_file_len, const uint8 *old_files, int old_files_len)
1548 {
1549 // Check if destination file is already present
1550 int dir_track, dir_sector, entry;
1551 if (find_first_file(new_file, new_file_len, dir_track, dir_sector, entry)) {
1552 set_error(ERR_FILEEXISTS);
1553 return;
1554 }
1555
1556 // Loop for all source files
1557 bool first = true;
1558 while (old_files_len > 0) {
1559 uint8 *comma = (uint8 *)memchr(old_files, ',', old_files_len);
1560 int name_len = comma ? comma - old_files : old_files_len;
1561
1562 // Check if source file is present
1563 if (!find_first_file(old_files, name_len, dir_track, dir_sector, entry)) {
1564 set_error(ERR_FILENOTFOUND);
1565 Close(17);
1566 return;
1567 }
1568 uint8 *de = dir + DIR_ENTRIES + entry * SIZEOF_DE;
1569 uint8 type = de[DE_TYPE] & 7, track = de[DE_TRACK], sector = de[DE_SECTOR];
1570
1571 // If this is the first source file, open internal write channel for destination file
1572 if (first) {
1573 create_file(17, new_file, new_file_len, type, false);
1574 if (ch[17].mode == CHMOD_FREE)
1575 return;
1576 first = false;
1577 }
1578
1579 // Open internal read channel for source file
1580 open_file_ts(16, track, sector);
1581 if (ch[16].mode == CHMOD_FREE) {
1582 Close(17);
1583 return;
1584 }
1585
1586 // Copy file
1587 uint8 byte, st;
1588 do {
1589 st = Read(16, byte);
1590 Write(17, byte, false);
1591 } while (st == ST_OK);
1592 Close(16);
1593 if (st != ST_EOF) {
1594 Close(17);
1595 return;
1596 }
1597
1598 if (comma) {
1599 old_files_len -= name_len + 1;
1600 old_files = comma + 1;
1601 } else
1602 old_files_len = 0;
1603 }
1604 Close(17);
1605 }
1606
1607 // RENAME:new=old
1608 // ^ ^
1609 // new_file old_file
1610 void ImageDrive::rename_cmd(const uint8 *new_file, int new_file_len, const uint8 *old_file, int old_file_len)
1611 {
1612 // Check if destination file is already present
1613 int dir_track, dir_sector, entry;
1614 if (find_first_file(new_file, new_file_len, dir_track, dir_sector, entry)) {
1615 set_error(ERR_FILEEXISTS);
1616 return;
1617 }
1618
1619 // Check if source file is present
1620 if (!find_first_file(old_file, old_file_len, dir_track, dir_sector, entry)) {
1621 set_error(ERR_FILENOTFOUND);
1622 return;
1623 }
1624
1625 // Check for write-protection
1626 if (write_protected) {
1627 set_error(ERR_WRITEPROTECT);
1628 return;
1629 }
1630
1631 // Rename file in directory entry
1632 uint8 *p = dir + DIR_ENTRIES + entry * SIZEOF_DE;
1633 memset(p + DE_NAME, 0xa0, 16);
1634 memcpy(p + DE_NAME, new_file, new_file_len);
1635 write_sector(dir_track, dir_sector, dir);
1636 }
1637
1638 // SCRATCH:file1,file2,...
1639 // ^
1640 // files
1641 void ImageDrive::scratch_cmd(const uint8 *files, int files_len)
1642 {
1643 // Check for write-protection
1644 if (write_protected) {
1645 set_error(ERR_WRITEPROTECT);
1646 return;
1647 }
1648
1649 // Loop for all files
1650 int num_files = 0;
1651 while (files_len > 0) {
1652 uint8 *comma = (uint8 *)memchr(files, ',', files_len);
1653 int name_len = comma ? comma - files : files_len;
1654
1655 int dir_track, dir_sector, entry;
1656 if (find_first_file(files, name_len, dir_track, dir_sector, entry)) {
1657 do {
1658 uint8 *de = dir + DIR_ENTRIES + entry * SIZEOF_DE;
1659
1660 // File protected? Then skip
1661 if (de[DE_TYPE] & 0x40)
1662 continue;
1663
1664 // Free allocated data blocks and side sectors
1665 free_block_chain(de[DE_TRACK], de[DE_SECTOR]);
1666 free_block_chain(de[DE_SIDE_TRACK], de[DE_SIDE_SECTOR]);
1667
1668 // Clear file type
1669 de[DE_TYPE] = 0;
1670
1671 // Write directory block back
1672 write_sector(dir_track, dir_sector, dir);
1673 num_files++;
1674 } while (find_next_file(files, name_len, dir_track, dir_sector, entry));
1675 }
1676
1677 if (comma) {
1678 files_len -= name_len + 1;
1679 files = comma + 1;
1680 } else
1681 files_len = 0;
1682 }
1683
1684 // Report number of files scratched
1685 set_error(ERR_SCRATCHED, num_files);
1686 }
1687
1688 // INITIALIZE
1689 void ImageDrive::initialize_cmd(void)
1690 {
1691 // Close all channels and re-read BAM
1692 close_all_channels();
1693 if (bam_dirty) {
1694 write_sector(DIR_TRACK, 0, bam);
1695 bam_dirty = false;
1696 }
1697 read_sector(DIR_TRACK, 0, bam);
1698 }
1699
1700 // NEW:name,id
1701 // ^ ^
1702 // name comma (or NULL)
1703 void ImageDrive::new_cmd(const uint8 *name, int name_len, const uint8 *comma)
1704 {
1705 // Check for write-protection
1706 if (write_protected) {
1707 set_error(ERR_WRITEPROTECT);
1708 return;
1709 }
1710
1711 // Remember current ID
1712 uint8 id1 = bam[BAM_DISK_ID], id2 = bam[BAM_DISK_ID + 1];
1713
1714 // Formatting with ID?
1715 if (comma) {
1716
1717 close_all_channels();
1718
1719 // Clear BAM buffer
1720 memset(bam, 0, 256);
1721
1722 // Get ID from command
1723 if (comma[1]) {
1724 id1 = comma[1];
1725 id2 = comma[2] ? comma[2] : ' ';
1726 } else {
1727 id1 = id2 = ' ';
1728 }
1729 }
1730
1731 // Format disk image
1732 format_image(the_file, desc, comma, id1, id2, name, name_len);
1733
1734 // Re-read BAM
1735 read_sector(DIR_TRACK, 0, bam);
1736 bam_dirty = false;
1737 }
1738
1739 // VALIDATE
1740 void ImageDrive::validate_cmd(void)
1741 {
1742 // Backup of old BAM in case something goes amiss
1743 uint8 old_bam[256];
1744 memcpy(old_bam, bam, 256);
1745
1746 // Clear BAM
1747 clear_bam(bam);
1748 bam_dirty = true;
1749
1750 // Allocate BAM and directory
1751 if (!alloc_block_chain(DIR_TRACK, 0)) {
1752 memcpy(bam, old_bam, 256);
1753 return;
1754 }
1755
1756 // Allocate all file data and side sector blocks
1757 int dir_track, dir_sector, entry;
1758 if (find_first_file((uint8 *)"*", 1, dir_track, dir_sector, entry)) {
1759 do {
1760 uint8 *de = dir + DIR_ENTRIES + entry * SIZEOF_DE;
1761
1762 if (de[DE_TYPE] & 0x80) {
1763 // Closed file, allocate all file data and side sector blocks
1764 if (!alloc_block_chain(de[DE_TRACK], de[DE_SECTOR]) || !alloc_block_chain(de[DE_SIDE_TRACK], de[DE_SIDE_SECTOR])) {
1765 memcpy(bam, old_bam, 256);
1766 return;
1767 }
1768 } else {
1769 // Open file, delete it
1770 de[DE_TYPE] = 0;
1771 write_sector(dir_track, dir_sector, dir);
1772 }
1773 } while (find_next_file((uint8 *)"*", 1, dir_track, dir_sector, entry));
1774 }
1775 }
1776
1777
1778 /*
1779 * Check whether file with given header (64 bytes) and size looks like one
1780 * of the file types supported by this module
1781 */
1782
1783 static bool is_d64_file(const uint8 *header, long size)
1784 {
1785 return size == NUM_SECTORS_35 * 256 || size == NUM_SECTORS_35 * 257
1786 || size == NUM_SECTORS_40 * 256 || size == NUM_SECTORS_40 * 257;
1787 }
1788
1789 static bool is_ed64_file(const uint8 *header, long size)
1790 {
1791 // 35-track d64 file with header ID at the end (only used internally for
1792 // converted zipcode files)
1793 return size == NUM_SECTORS_35 * 256 + 2;
1794 }
1795
1796 static bool is_x64_file(const uint8 *header, long size)
1797 {
1798 return memcmp(header, "C\x15\x41\x64\x01\x02", 6) == 0;
1799 }
1800
1801 static bool is_zipcode_file(const char *path)
1802 {
1803 #if 0
1804 string base, part;
1805 SplitPath(path, base, part);
1806 return part.length() > 2 && part[0] >= '1' && part[0] <= '4' && part[1] == '!';
1807 #else
1808 return false;
1809 #endif
1810 }
1811
1812 bool IsImageFile(const char *path, const uint8 *header, long size)
1813 {
1814 return is_d64_file(header, size) || is_x64_file(header, size) || is_zipcode_file(path);
1815 }
1816
1817
1818 #if 0
1819 /*
1820 * Convert zipcode file to extended d64 file (d64 file with header ID)
1821 */
1822
1823 static FILE *open_zipcode_file(FILE *old, int num, const string &base, string &part, uint8 &id1, uint8 &id2)
1824 {
1825 if (old)
1826 fclose(old);
1827 part[0] = num + '1';
1828 FILE *f = fopen(AddToPath(base, part).c_str(), "rb");
1829 if (f == NULL)
1830 return NULL;
1831 if (fseek(f, 2, SEEK_SET) < 0) {
1832 fclose(f);
1833 return NULL;
1834 }
1835 if (num == 0) {
1836 id1 = getc(f);
1837 id2 = getc(f);
1838 }
1839 return f;
1840 }
1841
1842 static FILE *convert_zipcode_to_ed64(const string &path)
1843 {
1844 FILE *in = NULL, *out = NULL;
1845 uint8 id1, id2;
1846
1847 // Split input file name
1848 string base, part;
1849 SplitPath(path, base, part);
1850
1851 // Open output file
1852 out = tmpfile();
1853 if (out == NULL)
1854 goto error;
1855
1856 // Decode all tracks
1857 for (int track=1; track<=35; track++) {
1858 int max_sect = 17 + ((track < 31) ? 1 : 0) + ((track < 25) ? 1 : 0) + ((track < 18) ? 2 : 0);
1859
1860 // Select appropriate input file
1861 switch (track) {
1862 case 1:
1863 if ((in = open_zipcode_file(NULL, 0, base, part, id1, id2)) == NULL)
1864 goto error;
1865 break;
1866 case 9:
1867 if ((in = open_zipcode_file(in, 1, base, part, id1, id2)) == NULL)
1868 goto error;
1869 break;
1870 case 17:
1871 if ((in = open_zipcode_file(in, 2, base, part, id1, id2)) == NULL)
1872 goto error;
1873 break;
1874 case 26:
1875 if ((in = open_zipcode_file(in, 3, base, part, id1, id2)) == NULL)
1876 goto error;
1877 break;
1878 }
1879
1880 // Clear "sector read" flags
1881 bool sect_flag[21];
1882 for (int i=0; i<max_sect; i++)
1883 sect_flag[i] = false;
1884
1885 // Read track
1886 uint8 act_track[21 * 256];
1887 for (int i=0; i<max_sect; i++) {
1888
1889 // Read and verify track/sector number
1890 uint8 t = getc(in);
1891 uint8 s = getc(in);
1892 if ((t & 0x3f) != track || s >= max_sect || sect_flag[s] || feof(in))
1893 goto error;
1894 sect_flag[s] = true;
1895 uint8 *p = act_track + s * 256;
1896
1897 // Uncompress sector
1898 if (t & 0x80) {
1899 // Run-length encoded sector
1900 uint8 len = getc(in);
1901 uint8 rep = getc(in);
1902 int count = 0;
1903 for (int j=0; j<len; j++) {
1904 if (feof(in))
1905 goto error;
1906 uint8 c = getc(in);
1907 if (c != rep)
1908 p[count++] = c;
1909 else {
1910 uint8 repnum = getc(in);
1911 if (feof(in))
1912 goto error;
1913 c = getc(in);
1914 j += 2;
1915 for (int k=0; k<repnum; k++)
1916 p[count++] = c;
1917 }
1918 }
1919 } else if (t & 0x40) {
1920 // Sector filled with constant byte
1921 if (feof(in))
1922 goto error;
1923 uint8 c = getc(in);
1924 memset(p, c, 256);
1925 } else {
1926 // Plain sector
1927 if (fread(p, 1, 256, in) != 256)
1928 goto error;
1929 }
1930 }
1931
1932 // Write track
1933 if (fwrite(act_track, 256, max_sect, out) != (size_t)max_sect)
1934 goto error;
1935 }
1936
1937 // Write header ID
1938 putc(id1, out);
1939 putc(id2, out);
1940
1941 // Done
1942 fclose(in);
1943 fseek(out, 0, SEEK_SET);
1944 return out;
1945
1946 error:
1947 if (in)
1948 fclose(in);
1949 if (out)
1950 fclose(out);
1951 return NULL;
1952 }
1953 #endif
1954
1955
1956 /*
1957 * Open disk image file, return file handle
1958 */
1959
1960 static FILE *open_image_file(const char *path, bool write_mode)
1961 {
1962 #if 0
1963 if (is_zipcode_file(path)) {
1964 if (write_mode)
1965 return NULL;
1966 else
1967 return convert_zipcode_to_ed64(path);
1968 } else
1969 #endif
1970 return fopen(path, write_mode ? "r+b" : "rb");
1971 }
1972
1973
1974 /*
1975 * Parse image file and fill in image_file_desc structure
1976 */
1977
1978 static bool parse_d64_file(FILE *f, image_file_desc &desc, bool has_header_id)
1979 {
1980 // .d64 files have no header
1981 desc.type = has_header_id ? TYPE_ED64 : TYPE_D64;
1982 desc.header_size = 0;
1983
1984 // Determine number of tracks
1985 fseek(f, 0, SEEK_END);
1986 long size = ftell(f);
1987 if (size == NUM_SECTORS_40 * 256 || size == NUM_SECTORS_40 * 257)
1988 desc.num_tracks = 40;
1989 else
1990 desc.num_tracks = 35;
1991
1992 if (has_header_id) {
1993 // Read header ID from image file (last 2 bytes)
1994 fseek(f, -2, SEEK_END);
1995 desc.id1 = getc(f);
1996 desc.id2 = getc(f);
1997 } else {
1998 // Read header ID from BAM (use error_info as buffer)
1999 fseek(f, accum_num_sectors[18] * 256, SEEK_SET);
2000 fread(desc.error_info, 1, 256, f);
2001 desc.id1 = desc.error_info[BAM_DISK_ID];
2002 desc.id2 = desc.error_info[BAM_DISK_ID + 1];
2003 }
2004
2005 // Read error info
2006 memset(desc.error_info, 1, sizeof(desc.error_info));
2007 if (size == NUM_SECTORS_35 * 257) {
2008 fseek(f, NUM_SECTORS_35 * 256, SEEK_SET);
2009 fread(desc.error_info, NUM_SECTORS_35, 1, f);
2010 desc.has_error_info = true;
2011 } else if (size == NUM_SECTORS_40 * 257) {
2012 fseek(f, NUM_SECTORS_40 * 256, SEEK_SET);
2013 fread(desc.error_info, NUM_SECTORS_40, 1, f);
2014 desc.has_error_info = true;
2015 } else
2016 desc.has_error_info = false;
2017
2018 return true;
2019 }
2020
2021 static bool parse_x64_file(FILE *f, image_file_desc &desc)
2022 {
2023 desc.type = TYPE_X64;
2024 desc.header_size = 64;
2025
2026 // Read number of tracks
2027 fseek(f, 7, SEEK_SET);
2028 desc.num_tracks = getc(f);
2029 if (desc.num_tracks < 35 || desc.num_tracks > 40)
2030 return false;
2031
2032 // Read header ID from BAM (use error_info as buffer)
2033 fseek(f, desc.header_size + accum_num_sectors[18] * 256, SEEK_SET);
2034 fread(desc.error_info, 1, 256, f);
2035 desc.id1 = desc.error_info[BAM_DISK_ID];
2036 desc.id2 = desc.error_info[BAM_DISK_ID + 1];
2037
2038 // .x64 files have no error info
2039 memset(desc.error_info, 1, sizeof(desc.error_info));
2040 desc.has_error_info = false;
2041 return true;
2042 }
2043
2044 static bool parse_image_file(FILE *f, image_file_desc &desc)
2045 {
2046 // Read header
2047 uint8 header[64];
2048 fread(header, 1, sizeof(header), f);
2049
2050 // Determine file size
2051 fseek(f, 0, SEEK_END);
2052 long size = ftell(f);
2053
2054 // Determine file type and fill in image_file_desc structure
2055 if (is_x64_file(header, size))
2056 return parse_x64_file(f, desc);
2057 else if (is_d64_file(header, size))
2058 return parse_d64_file(f, desc, false);
2059 else if (is_ed64_file(header, size))
2060 return parse_d64_file(f, desc, true);
2061 else
2062 return false;
2063 }
2064
2065
2066 /*
2067 * Read directory of disk image file into (empty) c64_dir_entry vector,
2068 * returns false on error
2069 */
2070
2071 bool ReadImageDirectory(const char *path, vector<c64_dir_entry> &vec)
2072 {
2073 bool result = false;
2074
2075 // Open file
2076 FILE *f = open_image_file(path, false);
2077 if (f) {
2078 int num_dir_blocks = 0;
2079
2080 // Determine file type and fill in image_file_desc structure
2081 image_file_desc desc;
2082 if (!parse_image_file(f, desc))
2083 goto done;
2084
2085 // Scan all directory blocks
2086 uint8 dir[256];
2087 dir[DIR_NEXT_TRACK] = DIR_TRACK;
2088 dir[DIR_NEXT_SECTOR] = 1;
2089
2090 while (dir[DIR_NEXT_TRACK] && num_dir_blocks < num_sectors[DIR_TRACK]) {
2091 if (read_sector(f, desc, dir[DIR_NEXT_TRACK], dir[DIR_NEXT_SECTOR], dir) != ERR_OK)
2092 break;
2093 num_dir_blocks++;
2094
2095 // Scan all 8 entries of a block
2096 uint8 *de = dir + DIR_ENTRIES;
2097 for (int j=0; j<8; j++, de+=SIZEOF_DE) {
2098
2099 // Skip empty entries
2100 if (de[DE_TYPE] == 0)
2101 continue;
2102
2103 // Convert file name (strip everything after and including the first trailing space)
2104 uint8 name_buf[17];
2105 memcpy(name_buf, de + DE_NAME, 16);
2106 name_buf[16] = 0;
2107 uint8 *p = (uint8 *)memchr(name_buf, 0xa0, 16);
2108 if (p)
2109 *p = 0;
2110
2111 // Convert file type
2112 int type = de[DE_TYPE] & 7;
2113 if (type > 4)
2114 type = FTYPE_UNKNOWN;
2115
2116 // Read start address
2117 uint8 sa_lo = 0, sa_hi = 0;
2118 uint8 buf[256];
2119 if (read_sector(f, desc, de[DE_TRACK], de[DE_SECTOR], buf) == ERR_OK) {
2120 sa_lo = buf[2];
2121 sa_hi = buf[3];
2122 }
2123
2124 // Add entry
2125 vec.push_back(c64_dir_entry(name_buf, type, !(de[DE_TYPE] & 0x80), de[DE_TYPE] & 0x40, ((de[DE_NUM_BLOCKS_H] << 8) + de[DE_NUM_BLOCKS_L]) * 254, 0, sa_lo, sa_hi));
2126 }
2127 }
2128
2129 result = true;
2130 done: fclose(f);
2131 }
2132 return result;
2133 }
2134
2135
2136 /*
2137 * Create new blank disk image file, returns false on error
2138 */
2139
2140 bool CreateImageFile(const char *path)
2141 {
2142 // Open file for writing
2143 FILE *f = fopen(path, "wb");
2144 if (f == NULL)
2145 return false;
2146
2147 // Create descriptor
2148 image_file_desc desc;
2149 desc.type = TYPE_D64;
2150 desc.header_size = 0;
2151 desc.num_tracks = 35;
2152 desc.id1 = 'F';
2153 desc.id1 = 'R';
2154 memset(desc.error_info, 1, sizeof(desc.error_info));
2155 desc.has_error_info = false;
2156
2157 // Format image file
2158 if (!format_image(f, desc, true, 'F', 'R', (uint8 *)"D64 FILE", 8)) {
2159 fclose(f);
2160 remove(path);
2161 return false;
2162 }
2163
2164 // Close file
2165 fclose(f);
2166 return true;
2167 }