ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/1541d64.cpp
Revision: 1.6
Committed: 2004-01-12T14:31:57Z (19 years ago) by cebix
Branch: MAIN
Changes since 1.5: +43 -43 lines
Log Message:
D64Drive -> ImageDrive

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