ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/1541d64.cpp
Revision: 1.11
Committed: 2010-04-21T19:52:53Z (14 years, 6 months ago) by cebix
Branch: MAIN
CVS Tags: HEAD
Changes since 1.10: +7 -1 lines
Error occurred while calculating annotation data.
Log Message:
init image file descriptor

File Contents

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