//------------------------------------------------- // audit_one_disk - validate a single disk entry //------------------------------------------------- audit_record audit_one_disk(ListPointer <rom_entry> rom, string locationtag = null) //const rom_entry *rom { // allocate and append a new record audit_record record = m_record_list.emplace_back(new audit_record(rom, audit_record.media_type.MEDIA_DISK)).Value; //audit_record &record = *m_record_list.emplace(m_record_list.end(), *rom, media_type::DISK); // open the disk chd_file source = new chd_file(); chd_error err = (chd_error)romload_global.open_disk_image(m_enumerator.options(), m_enumerator.driver(), rom[0], source, locationtag); // if we succeeded, get the hashes if (err == chd_error.CHDERR_NONE) { util.hash_collection hashes = new util.hash_collection(); // if there's a SHA1 hash, add them to the output hash if (source.sha1() != null) { hashes.add_sha1(source.sha1()); } // update the actual values record.set_actual(hashes); } // compute the final status compute_status(record, rom[0], err == chd_error.CHDERR_NONE); return(record); }
//------------------------------------------------- // compute_status - compute a detailed status // based on the information we have //------------------------------------------------- void compute_status(audit_record record, rom_entry rom, bool found) { // if not found, provide more details if (!found) { // no good dump if (record.expected_hashes().flag(util.hash_collection.FLAG_NO_DUMP)) { record.set_status(audit_record.audit_status.STATUS_NOT_FOUND, audit_record.audit_substatus.SUBSTATUS_NOT_FOUND_NODUMP); } // optional ROM else if (romload_global.ROM_ISOPTIONAL(rom)) { record.set_status(audit_record.audit_status.STATUS_NOT_FOUND, audit_record.audit_substatus.SUBSTATUS_NOT_FOUND_OPTIONAL); } // just plain old not found else { record.set_status(audit_record.audit_status.STATUS_NOT_FOUND, audit_record.audit_substatus.SUBSTATUS_NOT_FOUND); } } // if found, provide more details else { // length mismatch if (record.expected_length() != record.actual_length()) { record.set_status(audit_record.audit_status.STATUS_FOUND_INVALID, audit_record.audit_substatus.SUBSTATUS_FOUND_WRONG_LENGTH); } // found but needs a dump else if (record.expected_hashes().flag(util.hash_collection.FLAG_NO_DUMP)) { record.set_status(audit_record.audit_status.STATUS_GOOD, audit_record.audit_substatus.SUBSTATUS_FOUND_NODUMP); } // incorrect hash else if (record.expected_hashes() != record.actual_hashes()) { record.set_status(audit_record.audit_status.STATUS_FOUND_INVALID, audit_record.audit_substatus.SUBSTATUS_FOUND_BAD_CHECKSUM); } // correct hash but needs a redump else if (record.expected_hashes().flag(util.hash_collection.FLAG_BAD_DUMP)) { record.set_status(audit_record.audit_status.STATUS_GOOD, audit_record.audit_substatus.SUBSTATUS_GOOD_NEEDS_REDUMP); } // just plain old good else { record.set_status(audit_record.audit_status.STATUS_GOOD, audit_record.audit_substatus.SUBSTATUS_GOOD); } } }
//------------------------------------------------- // audit_device - audit the device //------------------------------------------------- public summary audit_device(device_t device, string validation = AUDIT_VALIDATE_FULL) { // start fresh m_record_list.clear(); // store validation for later m_validation = validation; m_searchpath = device.shortname(); int found = 0; int required = 0; // now iterate over regions and ROMs within for (ListPointer <rom_entry> region = romload_global.rom_first_region(device); region != null; region = romload_global.rom_next_region(region)) { for (ListPointer <rom_entry> rom = romload_global.rom_first_file(region); rom != null; rom = romload_global.rom_next_file(rom)) { util.hash_collection hashes = new util.hash_collection(romload_global.ROM_GETHASHDATA(rom[0])); // count the number of files with hashes if (!hashes.flag(util.hash_collection.FLAG_NO_DUMP) && !romload_global.ROM_ISOPTIONAL(rom[0])) { required++; } // audit a file audit_record record = null; if (romload_global.ROMREGION_ISROMDATA(region[0])) { record = audit_one_rom(rom); } // audit a disk else if (romload_global.ROMREGION_ISDISKDATA(region[0])) { record = audit_one_disk(rom); } // count the number of files that are found. if (record != null && (record.status() == audit_record.audit_status.STATUS_GOOD || record.status() == audit_record.audit_status.STATUS_FOUND_INVALID)) { found++; } } } if (found == 0 && required > 0) { m_record_list.clear(); return(summary.NOTFOUND); } // return a summary string unused = ""; return(summarize(device.shortname(), ref unused)); }
//------------------------------------------------- // audit_one_disk - validate a single disk entry //------------------------------------------------- audit_record audit_one_disk(Pointer <rom_entry> rom, object args) //template <typename... T> audit_record &audit_one_disk(const rom_entry *rom, T &&... args); { // allocate and append a new record audit_record record = m_record_list.emplace_back(new audit_record(rom, media_type.DISK)).Value; //audit_record &record = *m_record_list.emplace(m_record_list.end(), *rom, media_type::DISK); // open the disk chd_file source = new chd_file(); throw new emu_unimplemented(); #if false #endif }
// internal helpers //------------------------------------------------- // audit_one_rom - validate a single ROM entry //------------------------------------------------- audit_record audit_one_rom(ListPointer <rom_entry> rom) //(const rom_entry *rom) { // allocate and append a new record audit_record record = m_record_list.emplace_back(new audit_record(rom, audit_record.media_type.MEDIA_ROM)).Value; //audit_record &record = *m_record_list.emplace(m_record_list.end(), *rom, media_type::ROM); // see if we have a CRC and extract it if so UInt32 crc; bool has_crc = record.expected_hashes().crc(out crc); // find the file and checksum it, getting the file length along the way emu_file file = new emu_file(m_enumerator.options().media_path(), osdcore_global.OPEN_FLAG_READ | osdcore_global.OPEN_FLAG_NO_PRELOAD); file.set_restrict_to_mediapath(true); path_iterator path = new path_iterator(m_searchpath); string curpath; while (path.next(out curpath, record.name())) { // open the file if we can osd_file.error filerr; if (has_crc) { filerr = file.open(curpath, crc); } else { filerr = file.open(curpath); } // if it worked, get the actual length and hashes, then stop if (filerr == osd_file.error.NONE) { record.set_actual(file.hashes(m_validation), file.size()); break; } } file.close(); // compute the final status compute_status(record, rom[0], record.actual_length() != 0); return(record); }
//------------------------------------------------- // audit_one_rom - validate a single ROM entry //------------------------------------------------- audit_record audit_one_rom(std.vector <string> searchpath, Pointer <rom_entry> rom) //audit_record &audit_one_rom(const std::vector<std::string> &searchpath, const rom_entry *rom); { // allocate and append a new record audit_record record = m_record_list.emplace_back(new audit_record(rom, media_type.ROM)).Value; //audit_record &record = *m_record_list.emplace(m_record_list.end(), *rom, media_type::ROM); // see if we have a CRC and extract it if so uint32_t crc; bool has_crc = record.expected_hashes().crc(out crc); // find the file and checksum it, getting the file length along the way emu_file file = new emu_file(m_enumerator.options().media_path(), searchpath, OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD); file.set_restrict_to_mediapath(1); // open the file if we can std.error_condition filerr; if (has_crc) { filerr = file.open(record.name(), crc); } else { filerr = file.open(record.name()); } // if it worked, get the actual length and hashes, then stop if (!filerr) { record.set_actual(file.hashes(m_validation), file.size()); } file.close(); // compute the final status compute_status(record, rom.op, record.actual_length() != 0); return(record); }
//------------------------------------------------- // audit_samples - validate the samples for the // currently-enumerated driver //------------------------------------------------- public summary audit_samples() { // start fresh m_record_list.clear(); int required = 0; int found = 0; // iterate over sample entries foreach (samples_device device in new samples_device_iterator(m_enumerator.config().root_device())) { // by default we just search using the driver name string searchpath = m_enumerator.driver().name; // add the alternate path if present samples_iterator samplesiter = new samples_iterator(device); if (samplesiter.altbasename() != null) { searchpath += ";" + samplesiter.altbasename(); } // iterate over samples in this entry for (string samplename = samplesiter.first(); samplename != null; samplename = samplesiter.next()) { required++; // create a new record audit_record record = m_record_list.emplace_back(new audit_record(samplename, audit_record.media_type.MEDIA_SAMPLE)).Value; //audit_record &record = *m_record_list.emplace(m_record_list.end(), samplename, media_type::SAMPLE); // look for the files emu_file file = new emu_file(m_enumerator.options().sample_path(), osdcore_global.OPEN_FLAG_READ | osdcore_global.OPEN_FLAG_NO_PRELOAD); path_iterator path = new path_iterator(searchpath); string curpath; while (path.next(out curpath, samplename)) { // attempt to access the file (.flac) or (.wav) osd_file.error filerr = file.open(curpath, ".flac"); if (filerr != osd_file.error.NONE) { filerr = file.open(curpath, ".wav"); } if (filerr == osd_file.error.NONE) { record.set_status(audit_record.audit_status.STATUS_GOOD, audit_record.audit_substatus.SUBSTATUS_GOOD); found++; } else { record.set_status(audit_record.audit_status.STATUS_NOT_FOUND, audit_record.audit_substatus.SUBSTATUS_NOT_FOUND); } } file.close(); } } if (found == 0 && required > 0) { m_record_list.clear(); return(summary.NOTFOUND); } // return a summary string unused = ""; return(summarize(m_enumerator.driver().name, ref unused)); }
// getters //const simple_list<audit_record> &records() const { return m_record_list; } // audit operations //------------------------------------------------- // audit_media - audit the media described by the // currently-enumerated driver //------------------------------------------------- public summary audit_media(string validation = AUDIT_VALIDATE_FULL) { // start fresh m_record_list.clear(); // store validation for later m_validation = validation; // temporary hack until romload is update: get the driver path and support it for // all searches string driverpath = m_enumerator.config().root_device().searchpath(); int found = 0; int required = 0; int shared_found = 0; int shared_required = 0; // iterate over devices and regions foreach (device_t device in new device_iterator(m_enumerator.config().root_device())) { // determine the search path for this source and iterate through the regions m_searchpath = device.searchpath(); // now iterate over regions and ROMs within for (ListPointer <rom_entry> region = romload_global.rom_first_region(device); region != null; region = romload_global.rom_next_region(region)) { // temporary hack: add the driver path & region name string combinedpath = device.searchpath() + ";" + driverpath; if (!string.IsNullOrEmpty(device.shortname())) { combinedpath += ";" + device.shortname(); } m_searchpath = combinedpath; for (ListPointer <rom_entry> rom = romload_global.rom_first_file(region); rom != null; rom = romload_global.rom_next_file(rom)) { string name = romload_global.ROM_GETNAME(rom[0]); util.hash_collection hashes = new util.hash_collection(romload_global.ROM_GETHASHDATA(rom[0])); device_t shared_device = find_shared_device(device, name, hashes, romload_global.ROM_GETLENGTH(rom[0])); // count the number of files with hashes if (!hashes.flag(util.hash_collection.FLAG_NO_DUMP) && !romload_global.ROM_ISOPTIONAL(rom[0])) { required++; if (shared_device != null) { shared_required++; } } // audit a file audit_record record = null; if (romload_global.ROMREGION_ISROMDATA(region[0])) { record = audit_one_rom(rom); } // audit a disk else if (romload_global.ROMREGION_ISDISKDATA(region[0])) { record = audit_one_disk(rom); } if (record != null) { // count the number of files that are found. if (record.status() == audit_record.audit_status.STATUS_GOOD || (record.status() == audit_record.audit_status.STATUS_FOUND_INVALID && find_shared_device(device, name, record.actual_hashes(), record.actual_length()) == null)) { found++; if (shared_device != null) { shared_found++; } } record.set_shared_device(shared_device); } } } } // if we only find files that are in the parent & either the set has no unique files or the parent is not found, then assume we don't have the set at all if (found == shared_found && required > 0 && (required != shared_required || shared_found == 0)) { m_record_list.clear(); return(summary.NOTFOUND); } // return a summary string unused = ""; return(summarize(m_enumerator.driver().name, ref unused)); }
// audit operations //------------------------------------------------- // audit_media - audit the media described by the // currently-enumerated driver //------------------------------------------------- public summary audit_media(string validation = AUDIT_VALIDATE_FULL) { // start fresh m_record_list.clear(); // store validation for later m_validation = validation; // first walk the parent chain for required ROMs parent_rom_vector parentroms = new parent_rom_vector(); for (var drvindex = driver_list.find(m_enumerator.driver().parent); 0 <= drvindex; drvindex = driver_list.find(driver_list.driver((size_t)drvindex).parent)) //for (auto drvindex = m_enumerator.find(m_enumerator.driver().parent); 0 <= drvindex; drvindex = m_enumerator.find(m_enumerator.driver(drvindex).parent)) { game_driver parent = driver_list.driver((size_t)drvindex); LOG(null, "Checking parent {0} for ROM files\n", parent.type.shortname()); std.vector <rom_entry> roms = rom_build_entries(parent.rom); for (Pointer <rom_entry> region = rom_first_region(new Pointer <rom_entry>(roms)); region != null; region = rom_next_region(region)) //for (rom_entry const *region = rom_first_region(&roms.front()); region; region = rom_next_region(region)) { for (Pointer <rom_entry> rom = rom_first_file(region); rom != null; rom = rom_next_file(rom)) //for (rom_entry const *rom = rom_first_file(region); rom; rom = rom_next_file(rom)) { LOG(null, "Adding parent ROM {0}\n", rom.op.name()); parentroms.emplace_back(new parent_rom(parent.type, rom)); } } } parentroms.remove_redundant_parents(); // count ROMs required/found size_t found = 0; size_t required = 0; size_t shared_found = 0; size_t shared_required = 0; size_t parent_found = 0; // iterate over devices and regions std.vector <string> searchpath = new std.vector <string>(); foreach (device_t device in new device_enumerator(m_enumerator.config().root_device())) { searchpath.clear(); // now iterate over regions and ROMs within for (Pointer <rom_entry> region = rom_first_region(device); region != null; region = rom_next_region(region)) { for (Pointer <rom_entry> rom = rom_first_file(region); rom != null; rom = rom_next_file(rom)) { if (searchpath.empty()) { LOG(null, "Audit media for device {0}({1})\n", device.shortname(), device.tag()); searchpath = device.searchpath(); } // look for a matching parent or device ROM string name = rom.op.name(); util.hash_collection hashes = new util.hash_collection(rom.op.hashdata()); bool dumped = !hashes.flag(util.hash_collection.FLAG_NO_DUMP); device_type shared_device = parentroms.find_shared_device(device, name, hashes, rom_file_size(rom)); if (shared_device != null) { LOG(null, "File '{0}' {1}{2}dumped shared with {3}\n", name, ROM_ISOPTIONAL(rom.op) ? "optional " : "", dumped ? "" : "un", shared_device.shortname()); } else { LOG(null, "File '{0}' {1}{2}dumped\n", name, ROM_ISOPTIONAL(rom.op) ? "optional " : "", dumped ? "" : "un"); } // count the number of files with hashes if (dumped && !ROM_ISOPTIONAL(rom.op)) { required++; if (shared_device != null) { shared_required++; } } // audit a file audit_record record = null; if (ROMREGION_ISROMDATA(region.op)) { record = audit_one_rom(searchpath, rom); } // audit a disk else if (ROMREGION_ISDISKDATA(region.op)) { record = audit_one_disk(rom, device); } if (record != null) { // see if the actual content found belongs to a parent var matchesshared = parentroms.actual_matches_shared(device, record); if (matchesshared.first != null) { LOG(null, "Actual ROM file shared with {0}parent {1}\n", matchesshared.second ? "immediate " : "", matchesshared.first.shortname()); } // count the number of files that are found. if ((record.status() == audit_status.GOOD) || ((record.status() == audit_status.FOUND_INVALID) && (matchesshared.first == null))) { found++; if (shared_device != null) { shared_found++; } if (matchesshared.second) { parent_found++; } } record.set_shared_device(shared_device); } } } } if (!searchpath.empty()) { LOG(null, "Total required={0} (shared={1}) found={2} (shared={3} parent={4})\n", required, shared_required, found, shared_found, parent_found); } // if we only find files that are in the parent & either the set has no unique files or the parent is not found, then assume we don't have the set at all if ((found == shared_found) && required != 0 && ((required != shared_required) || parent_found == 0)) { m_record_list.clear(); return(summary.NOTFOUND); } // return a summary return(summarize(m_enumerator.driver().name)); }