//------------------------------------------------- // audit_software //------------------------------------------------- media_auditor::summary media_auditor::audit_software(const char *list_name, software_info *swinfo, const char *validation) { // start fresh m_record_list.reset(); // store validation for later m_validation = validation; std::string combinedpath(swinfo->shortname()); combinedpath.append(";"); combinedpath.append(list_name); combinedpath.append(PATH_SEPARATOR); combinedpath.append(swinfo->shortname()); std::string locationtag(list_name); locationtag.append("%"); locationtag.append(swinfo->shortname()); locationtag.append("%"); if (swinfo->parentname() != NULL) { locationtag.append(swinfo->parentname()); combinedpath.append(";").append(swinfo->parentname()).append(";").append(list_name).append(PATH_SEPARATOR).append(swinfo->parentname()); } m_searchpath = combinedpath.c_str(); int found = 0; int required = 0; // now iterate over software parts for ( software_part *part = swinfo->first_part(); part != NULL; part = part->next() ) { // now iterate over regions for ( const rom_entry *region = part->romdata(); region; region = rom_next_region( region ) ) { // now iterate over rom definitions for (const rom_entry *rom = rom_first_file(region); rom; rom = rom_next_file(rom)) { hash_collection hashes(ROM_GETHASHDATA(rom)); // count the number of files with hashes if (!hashes.flag(hash_collection::FLAG_NO_DUMP) && !ROM_ISOPTIONAL(rom)) { required++; } // audit a file audit_record *record = NULL; if (ROMREGION_ISROMDATA(region)) { record = audit_one_rom(rom); } // audit a disk else if (ROMREGION_ISDISKDATA(region)) { record = audit_one_disk(rom, locationtag.c_str()); } // count the number of files that are found. if (record != NULL && (record->status() == audit_record::STATUS_GOOD || record->status() == audit_record::STATUS_FOUND_INVALID)) { found++; } } } } if (found == 0 && required > 0) { m_record_list.reset(); return NOTFOUND; } // return a summary return summarize(list_name); }
void info_xml_creator::output_rom() { // iterate over 3 different ROM "types": BIOS, ROMs, DISKs for (int rom_type = 0; rom_type < 3; rom_type++) { // iterate over ROM sources: first the game, then any devices for (const rom_source *source = rom_first_source(m_drivlist.config()); source != NULL; source = rom_next_source(*source)) for (const rom_entry *region = rom_first_region(*source); region != NULL; region = rom_next_region(region)) { bool is_disk = ROMREGION_ISDISKDATA(region); // disk regions only work for disks if ((is_disk && rom_type != 2) || (!is_disk && rom_type == 2)) continue; // iterate through ROM entries for (const rom_entry *rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom)) { bool is_bios = ROM_GETBIOSFLAGS(rom); const char *name = ROM_GETNAME(rom); int offset = ROM_GETOFFSET(rom); const char *merge_name = NULL; char bios_name[100]; // BIOS ROMs only apply to bioses if ((is_bios && rom_type != 0) || (!is_bios && rom_type == 0)) continue; // if we have a valid ROM and we are a clone, see if we can find the parent ROM hash_collection hashes(ROM_GETHASHDATA(rom)); if (!hashes.flag(hash_collection::FLAG_NO_DUMP)) merge_name = get_merge_name(hashes); // scan for a BIOS name bios_name[0] = 0; if (!is_disk && is_bios) { // scan backwards through the ROM entries for (const rom_entry *brom = rom - 1; brom != m_drivlist.driver().rom; brom--) if (ROMENTRY_ISSYSTEM_BIOS(brom)) { strcpy(bios_name, ROM_GETNAME(brom)); break; } } // opening tag if (!is_disk) fprintf(m_output, "\t\t<rom"); else fprintf(m_output, "\t\t<disk"); // add name, merge, bios, and size tags */ if (name != NULL && name[0] != 0) fprintf(m_output, " name=\"%s\"", xml_normalize_string(name)); if (merge_name != NULL) fprintf(m_output, " merge=\"%s\"", xml_normalize_string(merge_name)); if (bios_name[0] != 0) fprintf(m_output, " bios=\"%s\"", xml_normalize_string(bios_name)); if (!is_disk) fprintf(m_output, " size=\"%d\"", rom_file_size(rom)); // dump checksum information only if there is a known dump if (!hashes.flag(hash_collection::FLAG_NO_DUMP)) { // iterate over hash function types and print m_output their values astring tempstr; for (hash_base *hash = hashes.first(); hash != NULL; hash = hash->next()) fprintf(m_output, " %s=\"%s\"", hash->name(), hash->string(tempstr)); } // append a region name fprintf(m_output, " region=\"%s\"", ROMREGION_GETTAG(region)); // add nodump/baddump flags if (hashes.flag(hash_collection::FLAG_NO_DUMP)) fprintf(m_output, " status=\"nodump\""); if (hashes.flag(hash_collection::FLAG_BAD_DUMP)) fprintf(m_output, " status=\"baddump\""); // for non-disk entries, print offset if (!is_disk) fprintf(m_output, " offset=\"%x\"", offset); // for disk entries, add the disk index else { fprintf(m_output, " index=\"%x\"", DISK_GETINDEX(rom)); fprintf(m_output, " writeable=\"%s\"", DISK_ISREADONLY(rom) ? "no" : "yes"); } // add optional flag if ((!is_disk && ROM_ISOPTIONAL(rom)) || (is_disk && DISK_ISOPTIONAL(rom))) fprintf(m_output, " optional=\"yes\""); fprintf(m_output, "/>\n"); } } } }
static int audit_one_rom(const rom_entry *rom, const game_driver *gamedrv, UINT32 validation, audit_record *record) { const game_driver *drv; const rom_entry *chunk; UINT32 crc = 0; UINT8 crcs[4]; int has_crc; /* fill in the record basics */ record->type = AUDIT_FILE_ROM; record->name = ROM_GETNAME(rom); record->exphash = ROM_GETHASHDATA(rom); /* compute the expected length by summing the chunks */ for (chunk = rom_first_chunk(rom); chunk; chunk = rom_next_chunk(chunk)) record->explength += ROM_GETLENGTH(chunk); /* see if we have a CRC and extract it if so */ has_crc = hash_data_extract_binary_checksum(record->exphash, HASH_CRC, crcs); if (has_crc) crc = (crcs[0] << 24) | (crcs[1] << 16) | (crcs[2] << 8) | crcs[3]; /* find the file and checksum it, getting the file length along the way */ for (drv = gamedrv; drv != NULL; drv = driver_get_clone(drv)) { mame_file_error filerr; mame_file *file; char *fname; /* open the file if we can */ fname = assemble_3_strings(drv->name, PATH_SEPARATOR, ROM_GETNAME(rom)); if (has_crc) filerr = mame_fopen_crc(SEARCHPATH_ROM, fname, crc, OPEN_FLAG_READ, &file); else filerr = mame_fopen(SEARCHPATH_ROM, fname, OPEN_FLAG_READ, &file); free(fname); /* if we got it, extract the hash and length */ if (filerr == FILERR_NONE) { hash_data_copy(record->hash, mame_fhash(file, validation)); record->length = (UINT32)mame_fsize(file); mame_fclose(file); break; } } /* if we failed to find the file, set the appropriate status */ if (drv == NULL) { const game_driver *parent; /* no good dump */ if (hash_data_has_info(record->exphash, HASH_INFO_NO_DUMP)) set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND_NODUMP); /* optional ROM */ else if (ROM_ISOPTIONAL(rom)) set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND_OPTIONAL); /* not found and used by parent */ else if (rom_used_by_parent(gamedrv, rom, &parent)) set_status(record, AUDIT_STATUS_NOT_FOUND, (parent->flags & NOT_A_DRIVER) ? SUBSTATUS_NOT_FOUND_BIOS : SUBSTATUS_NOT_FOUND_PARENT); /* just plain old not found */ else set_status(record, AUDIT_STATUS_NOT_FOUND, SUBSTATUS_NOT_FOUND); } /* if we did find the file, do additional verification */ else { /* length mismatch */ if (record->explength != record->length) set_status(record, AUDIT_STATUS_FOUND_INVALID, SUBSTATUS_FOUND_WRONG_LENGTH); /* found but needs a dump */ else if (hash_data_has_info(record->exphash, HASH_INFO_NO_DUMP)) set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_FOUND_NODUMP); /* incorrect hash */ else if (!hash_data_is_equal(record->exphash, record->hash, 0)) set_status(record, AUDIT_STATUS_FOUND_INVALID, SUBSTATUS_FOUND_BAD_CHECKSUM); /* correct hash but needs a redump */ else if (hash_data_has_info(record->exphash, HASH_INFO_BAD_DUMP)) set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD_NEEDS_REDUMP); /* just plain old good */ else set_status(record, AUDIT_STATUS_GOOD, SUBSTATUS_GOOD); } /* return TRUE if we found anything at all */ return (drv != NULL); }
/* Fills in an audit record for each rom in the romset. Sets 'audit' to point to the list of audit records. Returns total number of roms in the romset (same as number of audit records), 0 if romset missing. */ int audit_roms (int game, audit_record **audit) { const rom_entry *region, *rom, *chunk; const char *name; const game_driver *gamedrv; const game_driver *clone_of; int count = 0; audit_record *aud; int err; if (!audit_records) { audit_records = (audit_record *)malloc (AUD_MAX_ROMS * sizeof (audit_record)); // Make sure the memory is cleared - it's needed by the hashing // engine memset(audit_records, 0, AUD_MAX_ROMS * sizeof(audit_record)); } if (audit_records) *audit = aud = audit_records; else return 0; gamedrv = drivers[game]; clone_of = driver_get_clone(gamedrv); if (!gamedrv->rom) return -1; /* check for existence of romset */ if (!mame_faccess (gamedrv->name, FILETYPE_ROM)) { /* if the game is a clone, check for parent */ if (clone_of == NULL || (clone_of->flags & NOT_A_DRIVER) || !mame_faccess(clone_of->name,FILETYPE_ROM)) return 0; } for (region = rom_first_region(gamedrv); region; region = rom_next_region(region)) for (rom = rom_first_file(region); rom; rom = rom_next_file(rom)) { if (ROMREGION_ISROMDATA(region)) { const game_driver *drv; name = ROM_GETNAME(rom); strcpy (aud->rom, name); aud->explength = 0; aud->length = 0; aud->exphash = ROM_GETHASHDATA(rom); /* Copy into the variable we pass to the functions to support load-by-checksum */ hash_data_copy(aud->hash, aud->exphash); count++; /* obtain hash checksums and length of ROM file */ drv = gamedrv; do { err = mame_fchecksum(drv->name, name, &aud->length, aud->hash); drv = driver_get_clone(drv); } while (err && drv); /* spin through ROM_CONTINUEs, totaling length */ for (chunk = rom_first_chunk(rom); chunk; chunk = rom_next_chunk(chunk)) aud->explength += ROM_GETLENGTH(chunk); if (err) { if (hash_data_has_info(aud->exphash, HASH_INFO_NO_DUMP)) { /* not found but it's not good anyway */ aud->status = AUD_NOT_AVAILABLE; } else if (ROM_ISOPTIONAL(rom)) { /* optional ROM not found */ aud->status = AUD_OPTIONAL_ROM_NOT_FOUND; } else { /* not found */ aud->status = AUD_ROM_NOT_FOUND; drv = clone_of; /* If missing ROM is also present in a parent set, indicate that */ while (drv) { if (audit_is_rom_used (drv, aud->exphash)) { if (drv->flags & NOT_A_DRIVER) { aud->status = AUD_ROM_NOT_FOUND_BIOS; break; } else aud->status = AUD_ROM_NOT_FOUND_PARENT; } // Walk up the inheritance list. If this ROM is a clone of a set which // contains a BIOS that is missing, we can correctly mark it as // such. drv = driver_get_clone(drv); } } } /* all cases below assume the ROM was at least found */ else if (aud->explength != aud->length) aud->status = AUD_LENGTH_MISMATCH; else if (hash_data_has_info(aud->exphash, HASH_INFO_NO_DUMP)) aud->status = AUD_ROM_NEED_DUMP; /* new case - found but not known to be dumped */ else if (!hash_data_is_equal(aud->exphash, aud->hash, 0)) { /* non-matching hash */ aud->status = AUD_BAD_CHECKSUM; } else { /* matching hash */ if (hash_data_has_info(aud->exphash, HASH_INFO_BAD_DUMP)) aud->status = AUD_ROM_NEED_REDUMP; else aud->status = AUD_ROM_GOOD; } aud++; } else if (ROMREGION_ISDISKDATA(region)) { const UINT8 nullhash[HASH_BUF_SIZE] = { 0 }; void *source; chd_header header; name = ROM_GETNAME(rom); strcpy (aud->rom, name); aud->explength = 0; aud->length = 0; aud->exphash = ROM_GETHASHDATA(rom); hash_data_clear(aud->hash); count++; chd_gamedrv = gamedrv; chd_set_interface(&audit_chd_interface); source = chd_open( name, 0, NULL ); if( source == NULL ) { err = chd_get_last_error(); if( err == CHDERR_OUT_OF_MEMORY ) { aud->status = AUD_MEM_ERROR; } else if (hash_data_has_info(aud->exphash, HASH_INFO_NO_DUMP)) { /* not found but it's not good anyway */ aud->status = AUD_DISK_NOT_AVAILABLE; } else { /* not found */ aud->status = AUD_DISK_NOT_FOUND; } } else { header = *chd_get_header(source); if (memcmp(nullhash, header.md5, sizeof(header.md5))) hash_data_insert_binary_checksum(aud->hash, HASH_MD5, header.md5); if (memcmp(nullhash, header.sha1, sizeof(header.sha1))) hash_data_insert_binary_checksum(aud->hash, HASH_SHA1, header.sha1); if (hash_data_has_info(aud->exphash, HASH_INFO_NO_DUMP)) { aud->status = AUD_DISK_NEED_DUMP; } else if (!hash_data_is_equal(aud->exphash, aud->hash, 0)) { aud->status = AUD_DISK_BAD_MD5; } else { aud->status = AUD_DISK_GOOD; } chd_close( source ); } aud++; } } #ifdef MESS if (!count) return -1; else #endif return count; }
media_auditor::summary media_auditor::audit_media(const char *validation) { // start fresh m_record_list.reset(); // store validation for later m_validation = validation; // temporary hack until romload is update: get the driver path and support it for // all searches const char *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 device_iterator deviter(m_enumerator.config().root_device()); for (device_t *device = deviter.first(); device != nullptr; device = deviter.next()) { // determine the search path for this source and iterate through the regions m_searchpath = device->searchpath(); // now iterate over regions and ROMs within for (const rom_entry *region = rom_first_region(*device); region != nullptr; region = rom_next_region(region)) { // temporary hack: add the driver path & region name std::string combinedpath = std::string(device->searchpath()).append(";").append(driverpath); if (device->shortname()) combinedpath.append(";").append(device->shortname()); m_searchpath = combinedpath.c_str(); for (const rom_entry *rom = rom_first_file(region); rom; rom = rom_next_file(rom)) { const char *name = ROM_GETNAME(rom); hash_collection hashes(ROM_GETHASHDATA(rom)); device_t *shared_device = find_shared_device(*device, name, hashes, ROM_GETLENGTH(rom)); // count the number of files with hashes if (!hashes.flag(hash_collection::FLAG_NO_DUMP) && !ROM_ISOPTIONAL(rom)) { required++; if (shared_device != nullptr) shared_required++; } // audit a file audit_record *record = nullptr; if (ROMREGION_ISROMDATA(region)) record = audit_one_rom(rom); // audit a disk else if (ROMREGION_ISDISKDATA(region)) record = audit_one_disk(rom); if (record != nullptr) { // count the number of files that are found. if (record->status() == audit_record::STATUS_GOOD || (record->status() == audit_record::STATUS_FOUND_INVALID && find_shared_device(*device, name, record->actual_hashes(), record->actual_length()) == nullptr)) { found++; if (shared_device != nullptr) 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.reset(); return NOTFOUND; } // return a summary return summarize(m_enumerator.driver().name); }