--- Frodo4/Src/1541d64.cpp 2004/01/12 14:31:57 1.6 +++ Frodo4/Src/1541d64.cpp 2010/04/21 19:52:53 1.11 @@ -1,7 +1,7 @@ /* * 1541d64.cpp - 1541 emulation in disk image files (.d64/.x64/zipcode) * - * Frodo (C) 1994-1997,2002-2003 Christian Bauer + * Frodo Copyright (C) Christian Bauer * zipcode decoding routines (C) 1993-1997 Marko Mäkelä, Paul David Doherty * * This program is free software; you can redistribute it and/or modify @@ -34,6 +34,9 @@ #include "C64.h" #include "main.h" +#define DEBUG 0 +#include "debug.h" + // Channel modes (IRC users listen up :-) enum { @@ -106,6 +109,8 @@ const int accum_num_sectors[41] = { // Prototypes static bool match(const uint8 *p, int p_len, const uint8 *n); +static FILE *open_image_file(const char *path, bool write_mode); +static bool parse_image_file(FILE *f, image_file_desc &desc); /* @@ -114,6 +119,12 @@ static bool match(const uint8 *p, int p_ ImageDrive::ImageDrive(IEC *iec, const char *filepath) : Drive(iec), the_file(NULL), bam(ram + 0x700), bam_dirty(false) { + desc.type = TYPE_D64; + desc.header_size = 0; + desc.num_tracks = 35; + desc.id1 = desc.id2 = 0; + desc.has_error_info = false; + for (int i=0; i<18; i++) { ch[i].mode = CHMOD_FREE; ch[i].buf = NULL; @@ -196,6 +207,8 @@ bool ImageDrive::change_image(const char uint8 ImageDrive::Open(int channel, const uint8 *name, int name_len) { + D(bug("ImageDrive::Open channel %d, file %s\n", channel, name)); + set_error(ERR_OK); // Channel 15: execute file name as command @@ -237,6 +250,8 @@ uint8 ImageDrive::open_file(int channel, if (plain_name_len > 16) plain_name_len = 16; + D(bug(" plain name %s, type %d, mode %d\n", plain_name, type, mode)); + // Channel 0 is READ, channel 1 is WRITE if (channel == 0 || channel == 1) { mode = channel ? FMODE_WRITE : FMODE_READ; @@ -269,6 +284,7 @@ uint8 ImageDrive::open_file(int channel, if (find_first_file(plain_name, plain_name_len, dir_track, dir_sector, entry)) { // File exists + D(bug(" file exists, dir track %d, sector %d, entry %d\n", dir_track, dir_sector, entry)); ch[channel].dir_track = dir_track; ch[channel].dir_sector = dir_sector; ch[channel].entry = entry; @@ -334,6 +350,8 @@ uint8 ImageDrive::open_file(int channel, } else { // File doesn't exist + D(bug(" file not found\n")); + // Set file type to SEQ if not specified in file name if (type == FTYPE_DEL) type = FTYPE_SEQ; @@ -356,6 +374,8 @@ uint8 ImageDrive::open_file(int channel, uint8 ImageDrive::open_file_ts(int channel, int track, int sector) { + D(bug("open_file_ts track %d, sector %d\n", track, sector)); + // Allocate buffer and set channel mode int buf = alloc_buffer(-1); if (buf == -1) { @@ -381,6 +401,8 @@ uint8 ImageDrive::open_file_ts(int chann uint8 ImageDrive::create_file(int channel, const uint8 *name, int name_len, int type, bool overwrite) { + D(bug("create_file %s, type %d\n", name, type)); + // Allocate buffer int buf = alloc_buffer(-1); if (buf == -1) { @@ -407,6 +429,7 @@ uint8 ImageDrive::create_file(int channe return ST_OK; } ch[channel].num_blocks = 1; + D(bug(" first data block on track %d, sector %d\n", ch[channel].track, ch[channel].sector)); // Write directory entry memset(de, 0, SIZEOF_DE); @@ -629,6 +652,8 @@ uint8 ImageDrive::open_direct(int channe uint8 ImageDrive::Close(int channel) { + D(bug("ImageDrive::Close channel %d\n", channel)); + switch (ch[channel].mode) { case CHMOD_FREE: break; @@ -655,6 +680,7 @@ uint8 ImageDrive::Close(int channel) // Write last data block ch[channel].buf[0] = 0; ch[channel].buf[1] = ch[channel].buf_len - 1; + D(bug(" writing last data block\n")); if (!write_sector(ch[channel].track, ch[channel].sector, ch[channel].buf)) goto free; @@ -672,6 +698,7 @@ uint8 ImageDrive::Close(int channel) de[DE_OVR_TRACK] = de[DE_OVR_SECTOR] = 0; } write_sector(ch[channel].dir_track, ch[channel].dir_sector, dir); + D(bug(" directory entry updated\n")); } free: free_buffer(ch[channel].buf_num); ch[channel].buf = NULL; @@ -710,6 +737,8 @@ void ImageDrive::close_all_channels() uint8 ImageDrive::Read(int channel, uint8 &byte) { +// D(bug("ImageDrive::Read channel %d\n", channel)); + switch (ch[channel].mode) { case CHMOD_FREE: if (current_error == ERR_OK) @@ -735,6 +764,7 @@ uint8 ImageDrive::Read(int channel, uint // Read next block if necessary if (ch[channel].buf_len == 0 && ch[channel].buf[0]) { + D(bug(" reading next data block track %d, sector %d\n", ch[channel].buf[0], ch[channel].buf[1])); if (!read_sector(ch[channel].buf[0], ch[channel].buf[1], ch[channel].buf)) return ST_READ_TIMEOUT; ch[channel].buf_ptr = ch[channel].buf + 2; @@ -775,6 +805,8 @@ uint8 ImageDrive::Read(int channel, uint uint8 ImageDrive::Write(int channel, uint8 byte, bool eoi) { +// D(bug("ImageDrive::Write channel %d, byte %02x, eoi %d\n", channel, byte, eoi)); + switch (ch[channel].mode) { case CHMOD_FREE: if (current_error == ERR_OK) @@ -814,6 +846,7 @@ uint8 ImageDrive::Write(int channel, uin if (!alloc_next_block(track, sector, DATA_INTERLEAVE)) return ST_TIMEOUT; ch[channel].num_blocks++; + D(bug("next data block on track %d, sector %d\n", track, sector)); // Write buffer with link to new block ch[channel].buf[0] = track; @@ -995,8 +1028,10 @@ bool ImageDrive::alloc_dir_entry(int &tr uint8 *de = dir + DIR_ENTRIES; for (entry=0; entry<8; entry++, de+=SIZEOF_DE) { - if (de[DE_TYPE] == 0) + if (de[DE_TYPE] == 0) { + D(bug(" allocated entry %d in dir track %d, sector %d\n", entry, track, sector)); return true; + } } } @@ -1004,6 +1039,7 @@ bool ImageDrive::alloc_dir_entry(int &tr int last_track = track, last_sector = sector; if (!alloc_next_block(track, sector, DIR_INTERLEAVE)) return false; + D(bug(" new directory block track %d, sector %d\n", track, sector)); // Write link to new block to last block dir[DIR_NEXT_TRACK] = track; @@ -1074,6 +1110,7 @@ int ImageDrive::alloc_block(int track, i if (p[byte] & (1 << bit)) { // Yes, allocate and decrement free block count + D(bug("allocating block at track %d, sector %d\n", track, sector)); p[byte] &= ~(1 << bit); p[0]--; bam_dirty = true; @@ -1101,6 +1138,7 @@ int ImageDrive::free_block(int track, in if (!(p[byte] & (1 << bit))) { // Yes, free and increment free block count + D(bug("freeing block at track %d, sector %d\n", track, sector)); p[byte] |= (1 << bit); p[0]++; bam_dirty = true; @@ -1262,7 +1300,7 @@ const int conv_job_error[16] = { }; // Read sector, return error code -int read_sector(FILE *f, const image_file_desc &desc, int track, int sector, uint8 *buffer) +static int read_sector(FILE *f, const image_file_desc &desc, int track, int sector, uint8 *buffer) { // Convert track/sector to byte offset in file long offset = offset_from_ts(desc, track, sector); @@ -1282,7 +1320,7 @@ int read_sector(FILE *f, const image_fil } // Write sector, return error code -int write_sector(FILE *f, const image_file_desc &desc, int track, int sector, uint8 *buffer) +static int write_sector(FILE *f, const image_file_desc &desc, int track, int sector, uint8 *buffer) { // Convert track/sector to byte offset in file long offset = offset_from_ts(desc, track, sector); @@ -1318,7 +1356,7 @@ bool ImageDrive::write_sector(int track, } // Write error info back to image file -void write_back_error_info(FILE *f, const image_file_desc &desc) +static void write_back_error_info(FILE *f, const image_file_desc &desc) { if (desc.type == TYPE_D64 && desc.has_error_info) { int num_sectors = desc.num_tracks == 40 ? NUM_SECTORS_40 : NUM_SECTORS_35; @@ -1328,7 +1366,7 @@ void write_back_error_info(FILE *f, cons } // Format disk image -bool format_image(FILE *f, image_file_desc &desc, bool lowlevel, uint8 id1, uint8 id2, const uint8 *disk_name, int disk_name_len) +static bool format_image(FILE *f, image_file_desc &desc, bool lowlevel, uint8 id1, uint8 id2, const uint8 *disk_name, int disk_name_len) { uint8 p[256]; @@ -1925,7 +1963,7 @@ error: * Open disk image file, return file handle */ -FILE *open_image_file(const char *path, bool write_mode) +static FILE *open_image_file(const char *path, bool write_mode) { #if 0 if (is_zipcode_file(path)) { @@ -2009,7 +2047,7 @@ static bool parse_x64_file(FILE *f, imag return true; } -bool parse_image_file(FILE *f, image_file_desc &desc) +static bool parse_image_file(FILE *f, image_file_desc &desc) { // Read header uint8 header[64]; @@ -2031,6 +2069,76 @@ bool parse_image_file(FILE *f, image_fil } +/* + * Read directory of disk image file into (empty) c64_dir_entry vector, + * returns false on error + */ + +bool ReadImageDirectory(const char *path, vector &vec) +{ + bool result = false; + + // Open file + FILE *f = open_image_file(path, false); + if (f) { + int num_dir_blocks = 0; + + // Determine file type and fill in image_file_desc structure + image_file_desc desc; + if (!parse_image_file(f, desc)) + goto done; + + // Scan all directory blocks + uint8 dir[256]; + dir[DIR_NEXT_TRACK] = DIR_TRACK; + dir[DIR_NEXT_SECTOR] = 1; + + while (dir[DIR_NEXT_TRACK] && num_dir_blocks < num_sectors[DIR_TRACK]) { + if (read_sector(f, desc, dir[DIR_NEXT_TRACK], dir[DIR_NEXT_SECTOR], dir) != ERR_OK) + break; + num_dir_blocks++; + + // Scan all 8 entries of a block + uint8 *de = dir + DIR_ENTRIES; + for (int j=0; j<8; j++, de+=SIZEOF_DE) { + + // Skip empty entries + if (de[DE_TYPE] == 0) + continue; + + // Convert file name (strip everything after and including the first trailing space) + uint8 name_buf[17]; + memcpy(name_buf, de + DE_NAME, 16); + name_buf[16] = 0; + uint8 *p = (uint8 *)memchr(name_buf, 0xa0, 16); + if (p) + *p = 0; + + // Convert file type + int type = de[DE_TYPE] & 7; + if (type > 4) + type = FTYPE_UNKNOWN; + + // Read start address + uint8 sa_lo = 0, sa_hi = 0; + uint8 buf[256]; + if (read_sector(f, desc, de[DE_TRACK], de[DE_SECTOR], buf) == ERR_OK) { + sa_lo = buf[2]; + sa_hi = buf[3]; + } + + // Add entry + vec.push_back(c64_dir_entry(name_buf, type, !(de[DE_TYPE] & 0x80), de[DE_TYPE] & 0x40, ((de[DE_NUM_BLOCKS_H] << 8) + de[DE_NUM_BLOCKS_L]) * 254, 0, sa_lo, sa_hi)); + } + } + + result = true; +done: fclose(f); + } + return result; +} + + /* * Create new blank disk image file, returns false on error */