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 (12 years, 9 months ago) by cebix
Branch: MAIN
CVS Tags: HEAD
Changes since 1.10: +7 -1 lines
Log Message:
init image file descriptor

File Contents

# User Rev Content
1 cebix 1.1 /*
2 cebix 1.5 * 1541d64.cpp - 1541 emulation in disk image files (.d64/.x64/zipcode)
3 cebix 1.1 *
4 cebix 1.11 * Frodo Copyright (C) Christian Bauer
5 cebix 1.5 * zipcode decoding routines (C) 1993-1997 Marko Mäkelä, Paul David Doherty
6 cebix 1.1 *
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 cebix 1.5 * Incompatibilities:
24     * - No support for relative files
25     * - Unimplemented commands: P
26     * - Impossible to implement: B-E, M-E
27 cebix 1.1 */
28    
29     #include "sysdeps.h"
30    
31     #include "1541d64.h"
32     #include "IEC.h"
33     #include "Prefs.h"
34 cebix 1.3 #include "C64.h"
35 cebix 1.5 #include "main.h"
36 cebix 1.1
37 cebix 1.7 #define DEBUG 0
38     #include "debug.h"
39    
40 cebix 1.1
41     // Channel modes (IRC users listen up :-)
42     enum {
43     CHMOD_FREE, // Channel free
44     CHMOD_COMMAND, // Command/error channel
45 cebix 1.5 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 cebix 1.1 };
99    
100 cebix 1.5 // 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 cebix 1.1
110     // Prototypes
111 cebix 1.5 static bool match(const uint8 *p, int p_len, const uint8 *n);
112 cebix 1.9 static FILE *open_image_file(const char *path, bool write_mode);
113     static bool parse_image_file(FILE *f, image_file_desc &desc);
114 cebix 1.1
115    
116     /*
117 cebix 1.5 * Constructor: Prepare emulation, open image file
118 cebix 1.1 */
119    
120 cebix 1.6 ImageDrive::ImageDrive(IEC *iec, const char *filepath) : Drive(iec), the_file(NULL), bam(ram + 0x700), bam_dirty(false)
121 cebix 1.1 {
122 cebix 1.11 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 cebix 1.5 for (int i=0; i<18; i++) {
129     ch[i].mode = CHMOD_FREE;
130     ch[i].buf = NULL;
131 cebix 1.1 }
132 cebix 1.5 ch[15].mode = CHMOD_COMMAND;
133 cebix 1.1
134 cebix 1.5 Reset();
135 cebix 1.1
136 cebix 1.5 // Open image file
137     if (change_image(filepath))
138 cebix 1.1 Ready = true;
139     }
140    
141    
142     /*
143     * Destructor
144     */
145    
146 cebix 1.6 ImageDrive::~ImageDrive()
147 cebix 1.1 {
148 cebix 1.5 close_image();
149 cebix 1.1 }
150    
151    
152     /*
153 cebix 1.5 * Close the image file
154 cebix 1.1 */
155    
156 cebix 1.6 void ImageDrive::close_image(void)
157 cebix 1.1 {
158 cebix 1.5 if (the_file) {
159 cebix 1.1 close_all_channels();
160 cebix 1.5 if (bam_dirty) {
161     write_sector(DIR_TRACK, 0, bam);
162     bam_dirty = false;
163     }
164 cebix 1.1 fclose(the_file);
165     the_file = NULL;
166     }
167 cebix 1.5 }
168    
169 cebix 1.1
170 cebix 1.5 /*
171     * Open the image file
172     */
173 cebix 1.1
174 cebix 1.6 bool ImageDrive::change_image(const char *path)
175 cebix 1.5 {
176     // Close old image file
177     close_image();
178 cebix 1.1
179 cebix 1.5 // 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 cebix 1.1
188 cebix 1.5 // 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 cebix 1.1 }
194 cebix 1.5
195     // Read BAM
196     read_sector(DIR_TRACK, 0, bam);
197     bam_dirty = false;
198     return true;
199     } else
200     return false;
201 cebix 1.1 }
202    
203    
204     /*
205     * Open channel
206     */
207    
208 cebix 1.6 uint8 ImageDrive::Open(int channel, const uint8 *name, int name_len)
209 cebix 1.1 {
210 cebix 1.7 D(bug("ImageDrive::Open channel %d, file %s\n", channel, name));
211    
212 cebix 1.1 set_error(ERR_OK);
213    
214     // Channel 15: execute file name as command
215     if (channel == 15) {
216 cebix 1.4 execute_cmd(name, name_len);
217 cebix 1.1 return ST_OK;
218     }
219    
220 cebix 1.5 if (ch[channel].mode != CHMOD_FREE) {
221 cebix 1.1 set_error(ERR_NOCHANNEL);
222     return ST_OK;
223     }
224    
225 cebix 1.4 if (name[0] == '$')
226 cebix 1.1 if (channel)
227 cebix 1.5 return open_file_ts(channel, DIR_TRACK, 0);
228 cebix 1.1 else
229 cebix 1.4 return open_directory(name + 1, name_len - 1);
230 cebix 1.1
231 cebix 1.4 if (name[0] == '#')
232     return open_direct(channel, name);
233 cebix 1.1
234 cebix 1.4 return open_file(channel, name, name_len);
235 cebix 1.1 }
236    
237    
238     /*
239     * Open file
240     */
241    
242 cebix 1.6 uint8 ImageDrive::open_file(int channel, const uint8 *name, int name_len)
243 cebix 1.1 {
244 cebix 1.5 uint8 plain_name[NAMEBUF_LENGTH];
245 cebix 1.4 int plain_name_len;
246     int mode = FMODE_READ;
247 cebix 1.5 int type = FTYPE_DEL;
248 cebix 1.4 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 cebix 1.7 D(bug(" plain name %s, type %d, mode %d\n", plain_name, type, mode));
254    
255 cebix 1.4 // 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 cebix 1.1 }
261    
262 cebix 1.5 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 cebix 1.1 set_error(ERR_WRITEPROTECT);
273     return ST_OK;
274     }
275    
276 cebix 1.4 // Relative files are not supported
277     if (type == FTYPE_REL) {
278     set_error(ERR_UNIMPLEMENTED);
279     return ST_OK;
280     }
281    
282 cebix 1.5 // 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 cebix 1.7 D(bug(" file exists, dir track %d, sector %d, entry %d\n", dir_track, dir_sector, entry));
288 cebix 1.5 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 cebix 1.1
302 cebix 1.5 } else if (mode == FMODE_WRITE) {
303 cebix 1.1
304 cebix 1.5 if (name[0] == '@') {
305 cebix 1.1
306 cebix 1.5 // Open old file for overwriting (save-replace)
307     return create_file(channel, plain_name, plain_name_len, type, true);
308 cebix 1.1
309 cebix 1.5 } else {
310 cebix 1.1
311 cebix 1.5 // File to be written already exists, error
312     set_error(ERR_FILEEXISTS);
313     }
314 cebix 1.1
315 cebix 1.5 } else if (mode == FMODE_APPEND) {
316 cebix 1.1
317 cebix 1.5 // Open old file for appending
318     open_file_ts(channel, de[DE_TRACK], de[DE_SECTOR]);
319 cebix 1.1
320 cebix 1.5 // 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 cebix 1.1 }
327 cebix 1.5
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 cebix 1.1 }
349 cebix 1.5
350     } else {
351    
352     // File doesn't exist
353 cebix 1.7 D(bug(" file not found\n"));
354    
355 cebix 1.5 // 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 cebix 1.1 }
367 cebix 1.5 return ST_OK;
368 cebix 1.1 }
369    
370    
371     /*
372 cebix 1.5 * Open channel for reading from file given track/sector of first block
373 cebix 1.1 */
374    
375 cebix 1.6 uint8 ImageDrive::open_file_ts(int channel, int track, int sector)
376 cebix 1.1 {
377 cebix 1.7 D(bug("open_file_ts track %d, sector %d\n", track, sector));
378    
379 cebix 1.5 // 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 cebix 1.1
389     // On the next call to Read, the first block will be read
390 cebix 1.5 ch[channel].buf[0] = track;
391     ch[channel].buf[1] = sector;
392     ch[channel].buf_len = 0;
393 cebix 1.1
394     return ST_OK;
395     }
396    
397    
398     /*
399 cebix 1.5 * Create file and open channel for writing to file
400 cebix 1.1 */
401    
402 cebix 1.6 uint8 ImageDrive::create_file(int channel, const uint8 *name, int name_len, int type, bool overwrite)
403 cebix 1.5 {
404 cebix 1.7 D(bug("create_file %s, type %d\n", name, type));
405    
406 cebix 1.5 // 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 cebix 1.1
415 cebix 1.5 // 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 cebix 1.1
424 cebix 1.5 // 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 cebix 1.7 D(bug(" first data block on track %d, sector %d\n", ch[channel].track, ch[channel].sector));
433 cebix 1.1
434 cebix 1.5 // 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 cebix 1.1 }
455    
456 cebix 1.5
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 cebix 1.6 uint8 ImageDrive::open_directory(const uint8 *pattern, int pattern_len)
466 cebix 1.1 {
467     // Special treatment for "$0"
468 cebix 1.5 if (pattern[0] == '0' && pattern_len == 1) {
469 cebix 1.4 pattern++;
470     pattern_len--;
471     }
472 cebix 1.1
473     // Skip everything before the ':' in the pattern
474 cebix 1.4 uint8 *t = (uint8 *)memchr(pattern, ':', pattern_len);
475     if (t) {
476     t++;
477     pattern_len -= t - pattern;
478     pattern = t;
479     }
480 cebix 1.1
481 cebix 1.5 ch[0].mode = CHMOD_DIRECTORY;
482     uint8 *p = ch[0].buf_ptr = ch[0].buf = new uint8[8192];
483 cebix 1.1
484 cebix 1.5 // Create directory title with disk name, ID and format type
485 cebix 1.1 *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 cebix 1.5 uint8 *q = bam + BAM_DISK_NAME;
495 cebix 1.4 for (int i=0; i<23; i++) {
496     int c;
497 cebix 1.1 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 cebix 1.5 dir[DIR_NEXT_TRACK] = DIR_TRACK;
507     dir[DIR_NEXT_SECTOR] = 1;
508 cebix 1.1
509 cebix 1.5 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 cebix 1.1 return ST_OK;
513 cebix 1.5 num_dir_blocks++;
514 cebix 1.1
515     // Scan all 8 entries of a block
516 cebix 1.5 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 cebix 1.1
520 cebix 1.5 // Dummy line link
521     *p++ = 0x01;
522 cebix 1.1 *p++ = 0x01;
523    
524 cebix 1.5 // Line number = number of blocks
525     *p++ = de[DE_NUM_BLOCKS_L];
526     *p++ = de[DE_NUM_BLOCKS_H];
527 cebix 1.1
528 cebix 1.5 // Appropriate number of spaces to align file names
529 cebix 1.1 *p++ = ' ';
530 cebix 1.5 int n = (de[DE_NUM_BLOCKS_H] << 8) + de[DE_NUM_BLOCKS_L];
531 cebix 1.1 if (n<10) *p++ = ' ';
532     if (n<100) *p++ = ' ';
533    
534 cebix 1.5 // File name enclosed in quotes
535 cebix 1.1 *p++ = '\"';
536 cebix 1.5 q = de + DE_NAME;
537 cebix 1.4 uint8 c;
538 cebix 1.5 bool m = false;
539 cebix 1.4 for (int i=0; i<16; i++) {
540 cebix 1.1 if ((c = *q++) == 0xa0) {
541     if (m)
542 cebix 1.4 *p++ = ' '; // Replace all 0xa0 by spaces
543 cebix 1.1 else
544 cebix 1.5 m = (*p++ = '\"'); // But the first by a '"'
545 cebix 1.1 } else
546     *p++ = c;
547     }
548     if (m)
549     *p++ = ' ';
550     else
551     *p++ = '\"'; // No 0xa0, then append a space
552    
553 cebix 1.4 // Open files are marked by '*'
554 cebix 1.5 if (de[DE_TYPE] & 0x80)
555 cebix 1.1 *p++ = ' ';
556     else
557     *p++ = '*';
558    
559 cebix 1.4 // File type
560 cebix 1.5 *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 cebix 1.1
564 cebix 1.4 // Protected files are marked by '<'
565 cebix 1.5 if (de[DE_TYPE] & 0x40)
566 cebix 1.1 *p++ = '<';
567     else
568     *p++ = ' ';
569    
570 cebix 1.4 // Appropriate number of spaces at the end
571 cebix 1.1 *p++ = ' ';
572     if (n >= 10) *p++ = ' ';
573     if (n >= 100) *p++ = ' ';
574     *p++ = 0;
575     }
576     }
577     }
578    
579 cebix 1.4 // Final line, count number of free blocks
580     int n = 0;
581 cebix 1.5 for (int i=1; i<=35; i++) {
582     if (i != DIR_TRACK) // exclude track 18
583     n += num_free_blocks(i);
584 cebix 1.4 }
585 cebix 1.1
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 cebix 1.4 memset(p, ' ', 13);
605     p += 13;
606    
607 cebix 1.1 *p++ = 0;
608     *p++ = 0;
609     *p++ = 0;
610    
611 cebix 1.5 ch[0].buf_len = p - ch[0].buf;
612 cebix 1.1 return ST_OK;
613     }
614    
615    
616     /*
617     * Open channel for direct buffer access
618     */
619    
620 cebix 1.6 uint8 ImageDrive::open_direct(int channel, const uint8 *name)
621 cebix 1.1 {
622     int buf = -1;
623    
624 cebix 1.4 if (name[1] == 0)
625 cebix 1.1 buf = alloc_buffer(-1);
626     else
627 cebix 1.4 if ((name[1] >= '0') && (name[1] <= '3') && (name[2] == 0))
628     buf = alloc_buffer(name[1] - '0');
629 cebix 1.1
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 cebix 1.5 ch[channel].mode = CHMOD_DIRECT;
637     ch[channel].buf = ram + 0x300 + buf * 0x100;
638     ch[channel].buf_num = buf;
639 cebix 1.1
640     // Store actual buffer number in buffer
641 cebix 1.5 ch[channel].buf[1] = buf + '0';
642     ch[channel].buf_len = 1;
643     ch[channel].buf_ptr = ch[channel].buf + 1;
644 cebix 1.1
645     return ST_OK;
646     }
647    
648    
649     /*
650     * Close channel
651     */
652    
653 cebix 1.6 uint8 ImageDrive::Close(int channel)
654 cebix 1.1 {
655 cebix 1.7 D(bug("ImageDrive::Close channel %d\n", channel));
656    
657 cebix 1.5 switch (ch[channel].mode) {
658 cebix 1.1 case CHMOD_FREE:
659     break;
660    
661 cebix 1.5 case CHMOD_COMMAND:
662     close_all_channels();
663     break;
664    
665 cebix 1.1 case CHMOD_DIRECT:
666 cebix 1.5 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 cebix 1.7 D(bug(" writing last data block\n"));
684 cebix 1.5 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 cebix 1.7 D(bug(" directory entry updated\n"));
702 cebix 1.5 }
703     free: free_buffer(ch[channel].buf_num);
704     ch[channel].buf = NULL;
705     ch[channel].mode = CHMOD_FREE;
706 cebix 1.1 break;
707    
708 cebix 1.5 case CHMOD_DIRECTORY:
709     delete[] ch[channel].buf;
710     ch[channel].buf = NULL;
711     ch[channel].mode = CHMOD_FREE;
712 cebix 1.1 break;
713     }
714    
715     return ST_OK;
716     }
717    
718    
719     /*
720     * Close all channels
721     */
722    
723 cebix 1.6 void ImageDrive::close_all_channels()
724 cebix 1.1 {
725     for (int i=0; i<15; i++)
726     Close(i);
727 cebix 1.5 Close(16);
728     Close(17);
729 cebix 1.1
730     cmd_len = 0;
731     }
732    
733    
734     /*
735     * Read from channel
736     */
737    
738 cebix 1.6 uint8 ImageDrive::Read(int channel, uint8 &byte)
739 cebix 1.1 {
740 cebix 1.7 // D(bug("ImageDrive::Read channel %d\n", channel));
741    
742 cebix 1.5 switch (ch[channel].mode) {
743     case CHMOD_FREE:
744     if (current_error == ERR_OK)
745     set_error(ERR_FILENOTOPEN);
746     break;
747    
748 cebix 1.1 case CHMOD_COMMAND:
749 cebix 1.5 // Read error channel
750     byte = *error_ptr++;
751 cebix 1.1 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 cebix 1.5 if (ch[channel].writing)
761     return ST_READ_TIMEOUT;
762     if (current_error != ERR_OK)
763     return ST_READ_TIMEOUT;
764    
765 cebix 1.1 // Read next block if necessary
766 cebix 1.5 if (ch[channel].buf_len == 0 && ch[channel].buf[0]) {
767 cebix 1.7 D(bug(" reading next data block track %d, sector %d\n", ch[channel].buf[0], ch[channel].buf[1]));
768 cebix 1.5 if (!read_sector(ch[channel].buf[0], ch[channel].buf[1], ch[channel].buf))
769 cebix 1.1 return ST_READ_TIMEOUT;
770 cebix 1.5 ch[channel].buf_ptr = ch[channel].buf + 2;
771 cebix 1.1
772     // Determine block length
773 cebix 1.5 ch[channel].buf_len = ch[channel].buf[0] ? 254 : ch[channel].buf[1] - 1;
774 cebix 1.1 }
775    
776 cebix 1.5 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 cebix 1.1 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 cebix 1.5 if (ch[channel].buf_len > 0) {
789     byte = *(ch[channel].buf_ptr)++;
790     if (--(ch[channel].buf_len))
791 cebix 1.1 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 cebix 1.6 uint8 ImageDrive::Write(int channel, uint8 byte, bool eoi)
807 cebix 1.1 {
808 cebix 1.7 // D(bug("ImageDrive::Write channel %d, byte %02x, eoi %d\n", channel, byte, eoi));
809    
810 cebix 1.5 switch (ch[channel].mode) {
811 cebix 1.1 case CHMOD_FREE:
812 cebix 1.5 if (current_error == ERR_OK)
813     set_error(ERR_FILENOTOPEN);
814 cebix 1.1 break;
815    
816     case CHMOD_COMMAND:
817     // Collect characters and execute command on EOI
818 cebix 1.5 if (cmd_len > 58) {
819     set_error(ERR_SYNTAX32);
820 cebix 1.1 return ST_TIMEOUT;
821 cebix 1.5 }
822 cebix 1.1
823 cebix 1.4 cmd_buf[cmd_len++] = byte;
824 cebix 1.1
825     if (eoi) {
826 cebix 1.4 execute_cmd(cmd_buf, cmd_len);
827 cebix 1.1 cmd_len = 0;
828     }
829     return ST_OK;
830    
831     case CHMOD_DIRECTORY:
832     set_error(ERR_WRITEFILEOPEN);
833     break;
834    
835 cebix 1.5 case CHMOD_FILE:
836     if (!ch[channel].writing)
837     return ST_TIMEOUT;
838     if (current_error != ERR_OK)
839     return ST_TIMEOUT;
840 cebix 1.1
841 cebix 1.5 // Buffer full?
842     if (ch[channel].buf_len >= 256) {
843 cebix 1.1
844 cebix 1.5 // 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 cebix 1.7 D(bug("next data block on track %d, sector %d\n", track, sector));
850 cebix 1.5
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 cebix 1.1
866 cebix 1.5 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 cebix 1.4 }
875 cebix 1.5 return ST_TIMEOUT;
876 cebix 1.1 }
877    
878    
879     /*
880     * Reset drive
881     */
882    
883 cebix 1.6 void ImageDrive::Reset(void)
884 cebix 1.1 {
885     close_all_channels();
886    
887     cmd_len = 0;
888     for (int i=0; i<4; i++)
889     buf_free[i] = true;
890    
891 cebix 1.5 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 cebix 1.1 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 cebix 1.6 int ImageDrive::alloc_buffer(int want)
911 cebix 1.1 {
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 cebix 1.6 void ImageDrive::free_buffer(int buf)
937 cebix 1.1 {
938     buf_free[buf] = true;
939     }
940    
941    
942     /*
943 cebix 1.5 * Search file in directory, return directory track/sector and entry number
944     * false: not found, true: found
945 cebix 1.1 */
946    
947 cebix 1.5 // 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 cebix 1.6 bool ImageDrive::find_file(const uint8 *pattern, int pattern_len, int &dir_track, int &dir_sector, int &entry, bool cont)
966 cebix 1.1 {
967 cebix 1.5 // Counter to prevent cyclic directories from resulting in an infinite loop
968     int num_dir_blocks = 0;
969 cebix 1.1
970 cebix 1.5 // 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 cebix 1.1 }
979    
980 cebix 1.5 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 cebix 1.1 }
1000 cebix 1.5 return false;
1001     }
1002    
1003 cebix 1.6 bool ImageDrive::find_first_file(const uint8 *pattern, int pattern_len, int &dir_track, int &dir_sector, int &entry)
1004 cebix 1.5 {
1005     return find_file(pattern, pattern_len, dir_track, dir_sector, entry, false);
1006     }
1007 cebix 1.1
1008 cebix 1.6 bool ImageDrive::find_next_file(const uint8 *pattern, int pattern_len, int &dir_track, int &dir_sector, int &entry)
1009 cebix 1.5 {
1010     return find_file(pattern, pattern_len, dir_track, dir_sector, entry, true);
1011 cebix 1.1 }
1012    
1013    
1014     /*
1015 cebix 1.5 * 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 cebix 1.1 */
1019    
1020 cebix 1.6 bool ImageDrive::alloc_dir_entry(int &track, int &sector, int &entry)
1021 cebix 1.5 {
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 cebix 1.7 if (de[DE_TYPE] == 0) {
1032     D(bug(" allocated entry %d in dir track %d, sector %d\n", entry, track, sector));
1033 cebix 1.5 return true;
1034 cebix 1.7 }
1035 cebix 1.5 }
1036     }
1037 cebix 1.1
1038 cebix 1.5 // 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 cebix 1.7 D(bug(" new directory block track %d, sector %d\n", track, sector));
1043 cebix 1.5
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 cebix 1.6 bool ImageDrive::is_block_free(int track, int sector)
1062 cebix 1.5 {
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 cebix 1.6 int ImageDrive::num_free_blocks(int track)
1075 cebix 1.5 {
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 cebix 1.6 int ImageDrive::alloc_block(int track, int sector)
1101 cebix 1.5 {
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 cebix 1.7 D(bug("allocating block at track %d, sector %d\n", track, sector));
1114 cebix 1.5 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 cebix 1.6 int ImageDrive::free_block(int track, int sector)
1129 cebix 1.5 {
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 cebix 1.7 D(bug("freeing block at track %d, sector %d\n", track, sector));
1142 cebix 1.5 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 cebix 1.6 bool ImageDrive::alloc_block_chain(int track, int sector)
1155 cebix 1.5 {
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 cebix 1.6 bool ImageDrive::free_block_chain(int track, int sector)
1172 cebix 1.5 {
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 cebix 1.6 bool ImageDrive::alloc_next_block(int &track, int &sector, int interleave)
1192 cebix 1.5 {
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 cebix 1.1 };
1301    
1302 cebix 1.5 // Read sector, return error code
1303 cebix 1.9 static int read_sector(FILE *f, const image_file_desc &desc, int track, int sector, uint8 *buffer)
1304 cebix 1.5 {
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 cebix 1.9 static int write_sector(FILE *f, const image_file_desc &desc, int track, int sector, uint8 *buffer)
1324 cebix 1.1 {
1325 cebix 1.5 // 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 cebix 1.6 bool ImageDrive::read_sector(int track, int sector, uint8 *buffer)
1342 cebix 1.5 {
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 cebix 1.6 bool ImageDrive::write_sector(int track, int sector, uint8 *buffer)
1351 cebix 1.5 {
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 cebix 1.9 static void write_back_error_info(FILE *f, const image_file_desc &desc)
1360 cebix 1.5 {
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 cebix 1.9 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 cebix 1.5 {
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 cebix 1.6 void ImageDrive::block_read_cmd(int channel, int track, int sector, bool user_cmd)
1434 cebix 1.5 {
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 cebix 1.6 void ImageDrive::block_write_cmd(int channel, int track, int sector, bool user_cmd)
1452 cebix 1.5 {
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 cebix 1.6 void ImageDrive::block_allocate_cmd(int track, int sector)
1473 cebix 1.5 {
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 cebix 1.6 void ImageDrive::block_free_cmd(int track, int sector)
1501 cebix 1.5 {
1502     int err = free_block(track, sector);
1503     if (err)
1504     set_error(err, track, sector);
1505     }
1506    
1507     // BUFFER-POINTER:channel,pos
1508 cebix 1.6 void ImageDrive::buffer_pointer_cmd(int channel, int pos)
1509 cebix 1.5 {
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 cebix 1.6 void ImageDrive::mem_read_cmd(uint16 adr, uint8 len)
1520 cebix 1.5 {
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 cebix 1.6 void ImageDrive::mem_write_cmd(uint16 adr, uint8 len, uint8 *p)
1537 cebix 1.5 {
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 cebix 1.6 void ImageDrive::copy_cmd(const uint8 *new_file, int new_file_len, const uint8 *old_files, int old_files_len)
1554 cebix 1.5 {
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 cebix 1.6 void ImageDrive::rename_cmd(const uint8 *new_file, int new_file_len, const uint8 *old_file, int old_file_len)
1617 cebix 1.5 {
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 cebix 1.6 void ImageDrive::scratch_cmd(const uint8 *files, int files_len)
1648 cebix 1.5 {
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 cebix 1.6 void ImageDrive::initialize_cmd(void)
1696 cebix 1.5 {
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 cebix 1.6 void ImageDrive::new_cmd(const uint8 *name, int name_len, const uint8 *comma)
1710 cebix 1.5 {
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 cebix 1.6 void ImageDrive::validate_cmd(void)
1747 cebix 1.5 {
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 cebix 1.9 static FILE *open_image_file(const char *path, bool write_mode)
1967 cebix 1.5 {
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 cebix 1.9 static bool parse_image_file(FILE *f, image_file_desc &desc)
2051 cebix 1.5 {
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 cebix 1.9 }
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 cebix 1.5 }
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 cebix 1.1
2170 cebix 1.5 // Close file
2171     fclose(f);
2172     return true;
2173 cebix 1.1 }