diff --git a/Storage/Disk/DiskImage/Formats/CPCDSK.cpp b/Storage/Disk/DiskImage/Formats/CPCDSK.cpp index c74f4daef..9c3e0d1ce 100644 --- a/Storage/Disk/DiskImage/Formats/CPCDSK.cpp +++ b/Storage/Disk/DiskImage/Formats/CPCDSK.cpp @@ -18,6 +18,7 @@ using namespace Storage::Disk; CPCDSK::CPCDSK(const char *file_name) : + file_name_(file_name), is_extended_(false) { FileHolder file(file_name); is_read_only_ = file.get_is_known_read_only(); @@ -230,6 +231,7 @@ void CPCDSK::set_tracks(const std::map<::Storage::Disk::Track::Address, std::sha size_t chronological_track = index_for_track(pair.first); if(chronological_track >= tracks_.size()) { tracks_.resize(chronological_track+1); + head_position_count_ = pair.first.position; } // Get the track, or create it if necessary. @@ -263,6 +265,113 @@ void CPCDSK::set_tracks(const std::map<::Storage::Disk::Track::Address, std::sha } // Rewrite the entire disk image, in extended form. + Storage::FileHolder output(file_name_, Storage::FileHolder::FileMode::Rewrite); + output.write(reinterpret_cast("EXTENDED CPC DSK File\r\nDisk-Info\r\n"), 34); + output.write(reinterpret_cast("Clock Signal "), 14); + output.put8(static_cast(head_position_count_)); + output.put8(static_cast(head_count_)); + output.putn(2, 0); + + // Output size table. + for(size_t index = 0; index < static_cast(head_position_count_ * head_count_); ++index) { + if(index >= tracks_.size()) { + output.put8(0); + continue; + } + Track *track = tracks_[index].get(); + if(!track) { + output.put8(0); + continue; + } + + // Calculate size of track. + size_t track_size = 256; + for(auto §or: track->sectors) { + for(auto &sample: sector.samples) { + track_size += sample.size(); + } + } + + // Round upward and output. + track_size += (256 - (track_size & 255)) & 255; + output.put8(static_cast(track_size >> 8)); + } + + // Advance to offset 256. + output.putn(static_cast(256 - output.tell()), 0); + + // Output each track. + for(size_t index = 0; index < static_cast(head_position_count_ * head_count_); ++index) { + if(index >= tracks_.size()) continue; + Track *track = tracks_[index].get(); + if(!track) continue; + + // Output track header. + output.write(reinterpret_cast("Track-Info\r\n"), 13); + output.putn(3, 0); + output.put8(track->track); + output.put8(track->side); + switch (track->data_rate) { + default: + output.put8(0); + break; + case Track::DataRate::SingleOrDoubleDensity: + output.put8(1); + break; + case Track::DataRate::HighDensity: + output.put8(2); + break; + case Track::DataRate::ExtendedDensity: + output.put8(3); + break; + } + switch (track->data_encoding) { + default: + output.put8(0); + break; + case Track::DataEncoding::FM: + output.put8(1); + break; + case Track::DataEncoding::MFM: + output.put8(2); + break; + } + output.put8(track->sector_length); + output.put8(static_cast(track->sectors.size())); + output.put8(track->gap3_length); + output.put8(track->filler_byte); + + // Output sector information list. + for(auto §or: track->sectors) { + output.put8(sector.address.track); + output.put8(sector.address.side); + output.put8(sector.address.sector); + output.put8(sector.size); + output.put8(sector.fdc_status1); + output.put8(sector.fdc_status2); + + size_t data_size = 0; + for(auto &sample: sector.samples) { + data_size += sample.size(); + } + output.put16le(static_cast(data_size)); + } + + // Move to next 256-byte boundary. + long distance = (256 - output.tell()&255)&255; + output.putn(static_cast(distance), 0); + + // Output sector contents. + for(auto §or: track->sectors) { + for(auto &sample: sector.samples) { + output.write(sample); + } + } + + // Move to next 256-byte boundary. + distance = (256 - output.tell()&255)&255; + output.putn(static_cast(distance), 0); + } } bool CPCDSK::get_is_read_only() { diff --git a/Storage/Disk/DiskImage/Formats/CPCDSK.hpp b/Storage/Disk/DiskImage/Formats/CPCDSK.hpp index 394d8dfba..58edf60e9 100644 --- a/Storage/Disk/DiskImage/Formats/CPCDSK.hpp +++ b/Storage/Disk/DiskImage/Formats/CPCDSK.hpp @@ -64,6 +64,7 @@ class CPCDSK: public DiskImage { std::vector sectors; }; + std::string file_name_; std::vector> tracks_; size_t index_for_track(::Storage::Disk::Track::Address address); diff --git a/Storage/FileHolder.cpp b/Storage/FileHolder.cpp index d9c6e88c1..1745fe53f 100644 --- a/Storage/FileHolder.cpp +++ b/Storage/FileHolder.cpp @@ -92,6 +92,24 @@ uint8_t FileHolder::get8() { return static_cast(fgetc(file_)); } +void FileHolder::put16be(uint16_t value) { + fputc(value >> 8, file_); + fputc(value, file_); +} + +void FileHolder::put16le(uint16_t value) { + fputc(value, file_); + fputc(value >> 8, file_); +} + +void FileHolder::put8(uint8_t value) { + fputc(value, file_); +} + +void FileHolder::putn(size_t repeats, uint8_t value) { + while(repeats--) put8(value); +} + std::vector FileHolder::read(size_t size) { std::vector result(size); fread(result.data(), 1, size, file_); diff --git a/Storage/FileHolder.hpp b/Storage/FileHolder.hpp index add50aac0..7ac73a3a7 100644 --- a/Storage/FileHolder.hpp +++ b/Storage/FileHolder.hpp @@ -62,21 +62,27 @@ class FileHolder final { and returning the two assembled in little endian order. */ uint16_t get16le(); + void put16le(uint16_t value); /*! Performs @c get8 two times on @c file, casting each result to a @c uint32_t and returning the two assembled in big endian order. */ uint16_t get16be(); + void put16be(uint16_t value); - /*! Reads a single byte from @c file */ + /*! Reads a single byte from @c file. */ uint8_t get8(); - + + /*! Writes a single byte from @c file. */ + void put8(uint8_t value); + void putn(size_t repeats, uint8_t value); + std::vector read(size_t size); size_t read(uint8_t *buffer, size_t size); size_t write(const std::vector &); size_t write(const uint8_t *buffer, size_t size); - + void seek(long offset, int whence); long tell(); void flush();