diff --git a/StaticAnalyser/AmstradCPC/StaticAnalyser.cpp b/StaticAnalyser/AmstradCPC/StaticAnalyser.cpp index 9f0b2273f..73ee8930e 100644 --- a/StaticAnalyser/AmstradCPC/StaticAnalyser.cpp +++ b/StaticAnalyser/AmstradCPC/StaticAnalyser.cpp @@ -27,9 +27,10 @@ void StaticAnalyser::AmstradCPC::AddTargets( // This is CPC data format. Storage::Disk::CPM::ParameterBlock parameters; parameters.sectors_per_track = 9; - parameters.sector_size = 512; + parameters.block_size = 1024; parameters.first_sector = 0xc1; parameters.catalogue_allocation_bitmap = 0xc000; + parameters.logic_extents_per_physical = 1; parameters.reserved_tracks = 0; Storage::Disk::CPM::GetCatalogue(target.disks.front(), parameters); diff --git a/Storage/Disk/Parsers/CPM.cpp b/Storage/Disk/Parsers/CPM.cpp index 96302b788..cf340ca18 100644 --- a/Storage/Disk/Parsers/CPM.cpp +++ b/Storage/Disk/Parsers/CPM.cpp @@ -17,7 +17,9 @@ std::unique_ptr Storage::Disk::CPM::GetCatalogue( // Assemble the actual bytes of the catalogue. std::vector catalogue; + size_t sector_size = 1; uint16_t catalogue_allocation_bitmap = parameters.catalogue_allocation_bitmap; + if(!catalogue_allocation_bitmap) return nullptr; int sector = 0; int track = parameters.reserved_tracks; while(catalogue_allocation_bitmap) { @@ -28,6 +30,7 @@ std::unique_ptr Storage::Disk::CPM::GetCatalogue( } catalogue.insert(catalogue.end(), sector_contents->data.begin(), sector_contents->data.end()); + sector_size = sector_contents->data.size(); } catalogue_allocation_bitmap <<= 1; @@ -39,5 +42,73 @@ std::unique_ptr Storage::Disk::CPM::GetCatalogue( } } - return nullptr; + std::unique_ptr result(new Catalogue); + + // From the catalogue, create files. + std::map, size_t> indices_by_name; + File empty_file; + for(size_t c = 0; c < catalogue.size(); c += 32) { + // Skip this file if it's deleted; this is marked by it having 0xe5 as its user number + if(catalogue[c] == 0xe5) continue; + + // Check whether this file has yet been seen; if not then add it to the list + std::vector descriptor; + size_t index; + descriptor.insert(descriptor.begin(), &catalogue[c], &catalogue[c + 12]); + auto iterator = indices_by_name.find(descriptor); + if(iterator != indices_by_name.end()) { + index = iterator->second; + } else { + File new_file; + new_file.user_number = catalogue[c]; + for(size_t s = 0; s < 8; s++) new_file.name.push_back((char)catalogue[c + s + 1]); + for(size_t s = 0; s < 3; s++) new_file.type.push_back((char)catalogue[c + s + 9] & 0x7f); + new_file.read_only = catalogue[c + 9] & 0x80; + new_file.system = catalogue[c + 10] & 0x80; + index = result->files.size(); + result->files.push_back(new_file); + indices_by_name[descriptor] = index; + + printf("%s\n", new_file.name.c_str()); + } + + // figure out where this data needs to be pasted in + int extent = catalogue[c + 12] + (catalogue[c + 14] << 5); + int number_of_records = catalogue[c + 15]; + + size_t required_size = (size_t)(extent * 128 + number_of_records) * 128; + if(result->files[index].data.size() < required_size) { + result->files[index].data.resize(required_size); + } + + printf("%d records for extent %d: ", number_of_records, extent); + int sectors_per_block = parameters.block_size / (int)sector_size; + int records_per_sector = (int)sector_size / 128; + int record = 0; + for(size_t block = 0; block < 16; block++) { + int block_number = catalogue[c + 16 + block]; + if(!block_number) continue; + int first_sector = block_number * sectors_per_block; + + sector = first_sector % parameters.sectors_per_track; + track = first_sector / parameters.sectors_per_track; + + for(int s = 0; s < sectors_per_block && record < number_of_records; s++) { + std::shared_ptr sector_contents = parser.get_sector((uint8_t)track, (uint8_t)(parameters.first_sector + sector)); + if(!sector_contents) break; + sector++; + if(sector == parameters.sectors_per_track) { + sector = 0; + track++; + } + + int records_to_copy = std::min(number_of_records - record, records_per_sector); + memcpy(&result->files[index].data[extent * 16384 + record * 128], sector_contents->data.data(), records_to_copy * 128); + record += records_to_copy; + } + } + printf("\n"); + } + + return result; } diff --git a/Storage/Disk/Parsers/CPM.hpp b/Storage/Disk/Parsers/CPM.hpp index 4ee333e98..78f62d5b5 100644 --- a/Storage/Disk/Parsers/CPM.hpp +++ b/Storage/Disk/Parsers/CPM.hpp @@ -10,7 +10,11 @@ #define Storage_Disk_Parsers_CPM_hpp #include "../Disk.hpp" + +#include #include +#include +#include namespace Storage { namespace Disk { @@ -18,16 +22,24 @@ namespace CPM { struct ParameterBlock { int sectors_per_track; - int sector_size; + int block_size; int first_sector; + int logic_extents_per_physical; uint16_t catalogue_allocation_bitmap; int reserved_tracks; }; struct File { + uint8_t user_number; + std::string name; + std::string type; + bool read_only; + bool system; + std::vector data; }; struct Catalogue { + std::vector files; }; std::unique_ptr GetCatalogue(const std::shared_ptr &disk, const ParameterBlock ¶meters);