ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/1541d64.cpp
Revision: 1.7
Committed: 2004-01-12T14:58:26Z (20 years, 10 months ago) by cebix
Branch: MAIN
Changes since 1.6: +31 -1 lines
Log Message:
restored debugging code

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