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

File Contents

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