static int addrs_configure(backend_t *chain, hash_t *config){ ssize_t ret; DT_UINT32T elements_per_level = 0; DT_UINT32T read_per_calc = READ_PER_CALC_DEFAULT; addrs_userdata *data = (addrs_userdata *)chain->userdata; hash_data_copy(ret, TYPE_UINT32T, elements_per_level, config, HK(perlevel)); hash_data_copy(ret, TYPE_UINT32T, read_per_calc, config, HK(read_size)); if(elements_per_level <= 1) return -EINVAL; // "chain blocks-address variable 'per-level' invalid"); if(read_per_calc < 1) read_per_calc = READ_PER_CALC_DEFAULT; if( (data->tree = tree_alloc(chain, elements_per_level, read_per_calc)) == NULL) return error("chain blocks-address no memory"); if(tree_recalc(data->tree) != 0){ tree_free(data->tree); return error("chain blocks-address tree recalc failed"); } return 0; }
static ssize_t mphf_configure_any(backend_t *backend, config_t *config, request_t *fork_req){ // {{{ ssize_t ret; uintmax_t fork_only = 0; char *mphf_type_str = NULL; mphf_userdata *userdata = (mphf_userdata *)backend->userdata; hash_data_copy(ret, TYPE_STRINGT, mphf_type_str, config, HK(type)); hash_data_copy(ret, TYPE_UINTT, fork_only, config, HK(fork_only)); hash_data_copy(ret, TYPE_HASHKEYT, userdata->input, config, HK(input)); hash_data_copy(ret, TYPE_HASHKEYT, userdata->output, config, HK(output)); if(fork_only == 1 && fork_req == NULL) return 0; if( (userdata->mphf_proto = mphf_string_to_proto(mphf_type_str)) == NULL) return error("backend mphf parameter mphf_type invalid or not supplied"); memset(&userdata->mphf, 0, sizeof(userdata->mphf)); userdata->mphf.config = config; userdata->broken = 0; if(fork_req == NULL){ if( (ret = userdata->mphf_proto->func_load(&userdata->mphf)) < 0) return ret; }else{ if( (ret = userdata->mphf_proto->func_fork(&userdata->mphf, fork_req)) < 0) return ret; } return 0; } // }}}
static int call_configure(backend_t *backend, config_t *config){ // {{{ ssize_t ret; call_userdata *userdata = (call_userdata *)backend->userdata; hash_data_copy(ret, TYPE_HASHKEYT, userdata->hk_backend, config, HK(input)); hash_data_copy(ret, TYPE_UINTT, userdata->retry_request, config, HK(retry)); return 0; } // }}}
static int hashtable_configure(backend_t *backend, config_t *config){ // {{{ ssize_t ret; hashtable_userdata *userdata = (hashtable_userdata *)backend->userdata; hash_data_copy(ret, TYPE_HASHKEYT, userdata->input, config, HK(input)); hash_data_copy(ret, TYPE_UINTT, userdata->hashtable_size, config, HK(nelements)); if(userdata->hashtable_size == 0) return error("invalid hashtable size"); return 0; } // }}}
static int lookup_configure(backend_t *backend, config_t *config){ // {{{ ssize_t ret; lookup_userdata *userdata = (lookup_userdata *)backend->userdata; hash_data_copy(ret, TYPE_HASHKEYT, userdata->output, config, HK(output)); hash_data_copy(ret, TYPE_DATATYPET, userdata->output_type, config, HK(output_type)); hash_data_copy(ret, TYPE_UINTT, userdata->fatal, config, HK(fatal)); hash_data_copy(ret, TYPE_UINTT, userdata->force_query, config, HK(force_query)); hash_data_copy(ret, TYPE_BACKENDT, userdata->backend_index, config, HK(index)); if(ret != 0) return error("supplied index backend not valid, or not found"); return 0; } // }}}
static ssize_t addrs_set(backend_t *chain, request_t *request){ ssize_t ret; uint32_t r_block_vid, r_block_off, r_block_size, insert = 1; addrs_userdata *data = (addrs_userdata *)chain->userdata; hash_data_copy(ret, TYPE_UINT32T, r_block_size, request, HK(block_size)); if(ret != 0) return error("no block_size supplied"); hash_data_copy(ret, TYPE_UINT32T, r_block_off, request, HK(block_off)); if(ret != 0) insert = 0; hash_data_copy(ret, TYPE_UINT32T, r_block_vid, request, HK(block_vid)); if(ret != 0) r_block_vid = tree_blocks_count(data->tree); if(insert == 0){ return tree_resize_block(data->tree, r_block_vid, r_block_size); } return tree_insert(data->tree, r_block_vid, r_block_off, r_block_size); }
static int null_configure(backend_t *backend, config_t *config){ // {{{ ssize_t ret; null_userdata *userdata = (null_userdata *)backend->userdata; hash_data_copy(ret, TYPE_UINTT, userdata->testparam, config, HK(test)); return 0; } // }}}
static ssize_t lists_set(backend_t *backend, request_t *request){ ssize_t ret; off_t from, to; if(hash_find(request, HK(insert)) != NULL){ // on insert we move all items from 'key' to 'key'+1 // recommended use of 'blocks' backend as under-lying backend to improve perfomance hash_data_copy(ret, TYPE_OFFT, from, request, HK(offset)); if(ret != 0) return warning("no offset supplied"); to = from + 1; hash_t new_request[] = { { HK(action), DATA_UINT32T(ACTION_MOVE) }, { HK(offset_from), DATA_PTR_OFFT(&from) }, { HK(offset_to), DATA_PTR_OFFT(&to) }, { HK(size), DATA_VOID }, hash_next(request) }; if( (ret = backend_pass(backend, new_request)) < 0) return ret; } return ( (ret = backend_pass(backend, request)) < 0) ? ret : -EEXIST; }
static int stdout_configure(backend_t *backend, hash_t *config){ // {{{ ssize_t ret; std_userdata *userdata = (std_userdata *)backend->userdata; hash_data_copy(ret, TYPE_HASHKEYT, userdata->key, config, HK(input)); return 0; } // }}}
static ssize_t call_handler(backend_t *backend, request_t *request){ // {{{ ssize_t ret; backend_t *call_to = NULL; call_userdata *userdata = (call_userdata *)backend->userdata; hash_data_copy(ret, TYPE_BACKENDT, call_to, request, userdata->hk_backend); if(call_to) return ( (ret = backend_query(call_to, request)) < 0 ) ? ret : -EEXIST; ret = ( (ret = backend_pass(backend, request)) < 0 ) ? ret : -EEXIST; if(userdata->retry_request != 0){ hash_data_copy(ret, TYPE_BACKENDT, call_to, request, userdata->hk_backend); if(call_to) return ( (ret = backend_query(call_to, request)) < 0 ) ? ret : -EEXIST; } return ret; } // }}}
static ssize_t hashtable_handler(backend_t *backend, request_t *request){ // {{{ ssize_t ret; uint32_t action; uintmax_t d_input; hashtable_userdata *userdata = (hashtable_userdata *)backend->userdata; hash_data_copy(ret, TYPE_UINT32T, action, request, HK(action)); if(ret != 0) return -ENOSYS; hash_data_copy(ret, TYPE_UINTT, d_input, request, userdata->input); if(ret == 0){ d_input = d_input % userdata->hashtable_size; request_t r_next[] = { { userdata->input, DATA_PTR_UINTT(&d_input) }, hash_next(request) }; return ( (ret = backend_pass(backend, r_next)) < 0 ) ? ret : -EEXIST; } return ( (ret = backend_pass(backend, request)) < 0 ) ? ret : -EEXIST; } // }}}
static ssize_t null_create(backend_t *backend, request_t *request){ ssize_t ret; size_t value; hash_data_copy(ret, TYPE_SIZET, value, request, HK(size)); if(ret == 0 && value == 0x0000BEEF) return value; return ( (ret = backend_pass(backend, request)) < 0) ? ret : -EEXIST; }
static ssize_t addrs_delete(backend_t *chain, request_t *request){ ssize_t ret; uint32_t r_block_vid; addrs_userdata *data = (addrs_userdata *)chain->userdata; hash_data_copy(ret, TYPE_UINT32T, r_block_vid, request, HK(block_vid)); if(ret != 0) return -EINVAL; return tree_delete_block(data->tree, r_block_vid); }
static ssize_t lists_delete(backend_t *backend, request_t *request){ ssize_t ret; off_t from, to; size_t size; hash_data_copy(ret, TYPE_SIZET, size, request, HK(size)); if(ret != 0) return warning("no size supplied"); hash_data_copy(ret, TYPE_OFFT, from, request, HK(offset)); if(ret != 0) return warning("no offset supplied"); to = from; from += size; hash_t new_request[] = { { HK(action), DATA_UINT32T(ACTION_MOVE) }, { HK(offset_from), DATA_PTR_OFFT(&from) }, { HK(offset_to), DATA_PTR_OFFT(&to) }, { HK(size), DATA_VOID }, hash_next(request) }; return ( (ret = backend_pass(backend, new_request)) < 0) ? ret : -EEXIST; }
static ssize_t addrs_get(backend_t *chain, request_t *request){ ssize_t ret; data_t *temp; off_t def_real_offset; unsigned int def_block_vid; unsigned int def_block_size; off_t *o_real_offset = &def_real_offset; unsigned int *o_block_vid = &def_block_vid; unsigned int *o_block_size = &def_block_size; block_info block; off_t r_virt_key; uint32_t r_block_vid; hash_t *r_virt_key, *r_block_vid; addrs_userdata *data = (addrs_userdata *)chain->userdata; temp = hash_find_typed(request, TYPE_OFFT, HK(real_offset)); if(temp != NULL) o_real_offset = data_value_ptr(temp); temp = hash_find_typed(request, TYPE_UINT32T, HK(block_vid)); if(temp != NULL) o_block_vid = data_value_ptr(temp); temp = hash_find_typed(request, TYPE_UINT32T, HK(block_size)); if(temp != NULL) o_block_size = data_value_ptr(temp); if(hash_find(request, HK(blocks)) == NULL){ hash_data_copy(ret, TYPE_OFFT, r_virt_key, request, HK(offset)); if(ret != 0) return warning("no offset supplied"); if(tree_get(data->tree, r_virt_key, o_block_vid, o_real_offset) != 0) return -EFAULT; }else{ hash_data_copy(ret, TYPE_UINT32T, r_block_vid, request, HK(block_vid)); if(ret != 0) return warning("no block_vid supplied"); if(tree_get_block(data->tree, r_block_vid, &block) != 0) return -EFAULT; *o_real_offset = (off_t)(block.real_block_off); *o_block_size = (unsigned int)(block.size); } return 0; }
int mame_fchecksum(const char *gamename, const char *filename, unsigned int *length, char* hash) { mame_file *file; /* first open the file; we pass the source hash because it contains the expected checksum for the file (used to load by checksum) */ file = generic_fopen(FILETYPE_ROM, gamename, filename, hash, FILEFLAG_OPENREAD | FILEFLAG_HASH | FILEFLAG_VERIFY_ONLY); /* if we didn't succeed return -1 */ if (!file) return -1; /* close the file and save the length & checksum */ hash_data_copy(hash, file->hash); *length = file->length; mame_fclose(file); return 0; }
static ssize_t mphf_handler(backend_t *backend, request_t *request){ // {{{ ssize_t ret; uint32_t action; uintmax_t d_input; uintmax_t *d_output; data_t *data_output; mphf_userdata *userdata = (mphf_userdata *)backend->userdata; hash_data_copy(ret, TYPE_UINT32T, action, request, HK(action)); if(ret != 0) return -ENOSYS; // rebuilds if(action == ACTION_REBUILD){ if( (ret = userdata->mphf_proto->func_rebuild(&userdata->mphf)) < 0) return ret; userdata->broken = 0; return -EBADF; } if(userdata->broken != 0) return -EBADF; // hash_data_copy(ret, TYPE_UINTT, d_input, request, userdata->input); if(ret != 0) return -EINVAL; data_output = hash_data_find(request, userdata->output); if(data_output == NULL) return -EINVAL; d_output = data_output->ptr; switch(action){ case ACTION_CREATE: if( (ret = userdata->mphf_proto->func_insert( &userdata->mphf, d_input, *d_output )) < 0){ if(ret == -EBADF) userdata->broken = 1; return ret; } break; case ACTION_WRITE: if( (ret = userdata->mphf_proto->func_update( &userdata->mphf, d_input, *d_output )) < 0){ if(ret == -EBADF) userdata->broken = 1; return ret; } break; case ACTION_READ: switch( (ret = userdata->mphf_proto->func_query( &userdata->mphf, d_input, d_output ))){ case MPHF_QUERY_NOTFOUND: return -ENOENT; case MPHF_QUERY_FOUND: break; default: return ret; }; break; case ACTION_DELETE: if( (ret = userdata->mphf_proto->func_delete( &userdata->mphf, d_input )) < 0){ if(ret == -EBADF) userdata->broken = 1; return ret; } break; } return 0; } // }}}
static void audit_one_rom(core_options *options, const rom_entry *rom, const char *regiontag, const game_driver *gamedrv, UINT32 validation, audit_record *record) { const game_driver *drv; 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); record->length = 0; record->explength = rom_file_size(rom); /* 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)) { file_error filerr; mame_file *file; /* open the file if we can */ astring fname(drv->name, PATH_SEPARATOR, ROM_GETNAME(rom)); if (has_crc) filerr = mame_fopen_crc_options(options, libretro_content_directory, fname, crc, OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD, &file); else filerr = mame_fopen_options(options, libretro_content_directory, fname, OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD, &file); /* 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 not found, check the region as a backup */ if (record->length == 0 && regiontag != NULL) { file_error filerr; mame_file *file; /* open the file if we can */ astring fname(regiontag, PATH_SEPARATOR, ROM_GETNAME(rom)); if (has_crc) filerr = mame_fopen_crc_options(options, libretro_content_directory, fname, crc, OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD, &file); else filerr = mame_fopen_options(options, libretro_content_directory, fname, OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD, &file); /* 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); } } /* if we failed to find the file, set the appropriate status */ if (record->length == 0) { 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 & GAME_IS_BIOS_ROOT) ? 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); } }
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); }
static ssize_t chm_imp_configure (mphf_t *mphf, request_t *fork_req){ // {{{ ssize_t ret; backend_t *t; backend_t *be_g = NULL; backend_t *be_v = NULL; backend_t *be_e = NULL; char *backend = NULL; uintmax_t nelements_min = CAPACITY_MIN_DEFAULT; uintmax_t nelements_step = CAPACITY_STEP_DEFAULT; uintmax_t nelements_mul = CAPACITY_MUL_DEFAULT; uintmax_t bi_value = VALUE_BITS_DEFAULT; uintmax_t readonly = 0; chm_imp_t *data = (chm_imp_t *)&mphf->data; if( (data->status & FILLED) == 0){ hash_data_copy(ret, TYPE_UINTT, nelements_min, mphf->config, HK(nelements_min)); hash_data_copy(ret, TYPE_UINTT, nelements_step, mphf->config, HK(nelements_step)); hash_data_copy(ret, TYPE_UINTT, nelements_mul, mphf->config, HK(nelements_mul)); hash_data_copy(ret, TYPE_UINTT, bi_value, mphf->config, HK(value_bits)); // number of bits per value to store hash_data_copy(ret, TYPE_UINTT, readonly, mphf->config, HK(readonly)); // run in read-only mode hash_data_copy(ret, TYPE_STRINGT, backend, mphf->config, HK(backend_g)); if(ret == 0){ be_g = t = backend_acquire(backend); if(fork_req){ be_g = backend_fork(t, fork_req); backend_destroy(t); } } hash_data_copy(ret, TYPE_STRINGT, backend, mphf->config, HK(backend_v)); if(ret == 0){ be_v = t = backend_acquire(backend); if(fork_req){ be_v = backend_fork(t, fork_req); backend_destroy(t); } } hash_data_copy(ret, TYPE_STRINGT, backend, mphf->config, HK(backend_e)); if(ret == 0){ be_e = t = backend_acquire(backend); if(fork_req){ be_e = backend_fork(t, fork_req); backend_destroy(t); } } if(be_g == NULL) return error("backend chm_imp parameter backend_g invalid"); if(be_v == NULL || be_e == NULL || readonly != 0){ data->status &= ~WRITEABLE; }else{ data->status |= WRITEABLE; } data->be_g = be_g; data->be_v = be_v; data->be_e = be_e; data->nelements_min = nelements_min; data->nelements_step = nelements_step; data->nelements_mul = nelements_mul; data->bi_value = bi_value; data->bt_value = BITS_TO_BYTES(data->bi_value); data->status |= FILLED; } return 0; } // }}}
/* 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; }