summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--.gitattributes2
-rw-r--r--src/emu/emu.mak1
-rw-r--r--src/emu/hashfile.c591
-rw-r--r--src/emu/hashfile.h62
4 files changed, 656 insertions, 0 deletions
diff --git a/.gitattributes b/.gitattributes
index 79b1a19343a..9f5b4dbca5c 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -604,6 +604,8 @@ src/emu/fileio.c svneol=native#text/plain
src/emu/fileio.h svneol=native#text/plain
src/emu/hash.c svneol=native#text/plain
src/emu/hash.h svneol=native#text/plain
+src/emu/hashfile.c svneol=native#text/plain
+src/emu/hashfile.h svneol=native#text/plain
src/emu/info.c svneol=native#text/plain
src/emu/info.h svneol=native#text/plain
src/emu/inptport.c svneol=native#text/plain
diff --git a/src/emu/emu.mak b/src/emu/emu.mak
index 91c964f2a83..55e0923f6be 100644
--- a/src/emu/emu.mak
+++ b/src/emu/emu.mak
@@ -63,6 +63,7 @@ EMUOBJS = \
$(EMUOBJ)/emupal.o \
$(EMUOBJ)/fileio.o \
$(EMUOBJ)/hash.o \
+ $(EMUOBJ)/hashfile.o \
$(EMUOBJ)/info.o \
$(EMUOBJ)/input.o \
$(EMUOBJ)/inputseq.o \
diff --git a/src/emu/hashfile.c b/src/emu/hashfile.c
new file mode 100644
index 00000000000..021c1cc21ef
--- /dev/null
+++ b/src/emu/hashfile.c
@@ -0,0 +1,591 @@
+/*********************************************************************
+
+ hashfile.c
+
+ Code for parsing hash info (*.hsi) files
+
+*********************************************************************/
+
+#include "hashfile.h"
+#include "pool.h"
+#include "expat.h"
+#include "emuopts.h"
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+struct _hash_file
+{
+ mame_file *file;
+ object_pool *pool;
+ unsigned int functions[IO_COUNT];
+
+ hash_info **preloaded_hashes;
+ int preloaded_hash_count;
+
+ void (*error_proc)(const char *message);
+};
+
+
+
+enum hash_parse_position
+{
+ POS_ROOT,
+ POS_MAIN,
+ POS_HASH
+};
+
+
+
+struct hash_parse_state
+{
+ XML_Parser parser;
+ hash_file *hashfile;
+ int done;
+
+ int (*selector_proc)(hash_file *hashfile, void *param, const char *name, const char *hash);
+ void (*use_proc)(hash_file *hashfile, void *param, hash_info *hi);
+ void (*error_proc)(const char *message);
+ void *param;
+
+ enum hash_parse_position pos;
+ char **text_dest;
+ hash_info *hi;
+};
+
+
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+
+static void *expat_malloc(size_t size);
+static void *expat_realloc(void *ptr, size_t size);
+static void expat_free(void *ptr);
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ parse_error
+-------------------------------------------------*/
+
+static void ATTR_PRINTF(2,3) parse_error(struct hash_parse_state *state, const char *fmt, ...)
+{
+ char buf[256];
+ va_list va;
+
+ if (state->error_proc)
+ {
+ va_start(va, fmt);
+ vsnprintf(buf, ARRAY_LENGTH(buf), fmt, va);
+ va_end(va);
+ (*state->error_proc)(buf);
+ }
+}
+
+
+
+/*-------------------------------------------------
+ unknown_tag
+-------------------------------------------------*/
+
+static void unknown_tag(struct hash_parse_state *state, const char *tagname)
+{
+ parse_error(state, "[%lu:%lu]: Unknown tag: %s\n",
+ XML_GetCurrentLineNumber(state->parser),
+ XML_GetCurrentColumnNumber(state->parser),
+ tagname);
+}
+
+
+
+/*-------------------------------------------------
+ unknown_attribute
+-------------------------------------------------*/
+
+static void unknown_attribute(struct hash_parse_state *state, const char *attrname)
+{
+ parse_error(state, "[%lu:%lu]: Unknown attribute: %s\n",
+ XML_GetCurrentLineNumber(state->parser),
+ XML_GetCurrentColumnNumber(state->parser),
+ attrname);
+}
+
+
+
+/*-------------------------------------------------
+ unknown_attribute_value
+-------------------------------------------------*/
+
+static void unknown_attribute_value(struct hash_parse_state *state,
+ const char *attrname, const char *attrvalue)
+{
+ parse_error(state, "[%lu:%lu]: Unknown attribute value: %s\n",
+ XML_GetCurrentLineNumber(state->parser),
+ XML_GetCurrentColumnNumber(state->parser),
+ attrvalue);
+}
+
+
+
+/*-------------------------------------------------
+ start_handler
+-------------------------------------------------*/
+
+static void start_handler(void *data, const char *tagname, const char **attributes)
+{
+ struct hash_parse_state *state = (struct hash_parse_state *) data;
+ const char *name;
+ hash_info *hi;
+ char **text_dest;
+ char hash_string[HASH_BUF_SIZE];
+ unsigned int functions, all_functions;
+ iodevice_t device;
+ int i;
+
+ switch(state->pos)
+ {
+ case POS_ROOT:
+ if (!strcmp(tagname, "hashfile"))
+ {
+ }
+ else
+ {
+ unknown_tag(state, tagname);
+ }
+ break;
+
+ case POS_MAIN:
+ if (!strcmp(tagname, "hash"))
+ {
+ // we are now examining a hash tag
+ name = NULL;
+ memset(hash_string, 0, sizeof(hash_string));
+ all_functions = 0;
+ device = IO_COUNT;
+
+ while(attributes[0])
+ {
+ functions = 0;
+ if (!strcmp(attributes[0], "name"))
+ {
+ /* name attribute */
+ name = attributes[1];
+ }
+ else if (!strcmp(attributes[0], "crc32"))
+ {
+ /* crc32 attribute */
+ functions = HASH_CRC;
+ }
+ else if (!strcmp(attributes[0], "md5"))
+ {
+ /* md5 attribute */
+ functions = HASH_MD5;
+ }
+ else if (!strcmp(attributes[0], "sha1"))
+ {
+ /* sha1 attribute */
+ functions = HASH_SHA1;
+ }
+ else if (!strcmp(attributes[0], "type"))
+ {
+ /* type attribute */
+ i = 0;//device_typeid(attributes[1]);
+ if (i < 0)
+ unknown_attribute_value(state, attributes[0], attributes[1]);
+ else
+ device = (iodevice_t) i;
+ }
+ else
+ {
+ /* unknown attribute */
+ unknown_attribute(state, attributes[0]);
+ }
+
+ if (functions)
+ {
+ hash_data_insert_printable_checksum(hash_string, functions, attributes[1]);
+ all_functions |= functions;
+ }
+
+ attributes += 2;
+ }
+
+ if (device == IO_COUNT)
+ {
+ for (i = 0; i < IO_COUNT; i++)
+ state->hashfile->functions[i] |= all_functions;
+ }
+ else
+ state->hashfile->functions[device] |= all_functions;
+
+ /* do we use this hash? */
+ if (!state->selector_proc || state->selector_proc(state->hashfile, state->param, name, hash_string))
+ {
+ hi = (hash_info*)pool_malloc_lib(state->hashfile->pool, sizeof(hash_info));
+ if (!hi)
+ return;
+ memset(hi, 0, sizeof(*hi));
+
+ hi->longname = pool_strdup_lib(state->hashfile->pool, name);
+ if (!hi->longname)
+ return;
+
+ strcpy(hi->hash, hash_string);
+ state->hi = hi;
+ }
+ }
+ else
+ {
+ unknown_tag(state, tagname);
+ }
+ break;
+
+ case POS_HASH:
+ text_dest = NULL;
+
+ if (!strcmp(tagname, "year"))
+ text_dest = (char **) &state->hi->year;
+ else if (!strcmp(tagname, "manufacturer"))
+ text_dest = (char **) &state->hi->manufacturer;
+ else if (!strcmp(tagname, "status"))
+ text_dest = (char **) &state->hi->playable;
+ else if (!strcmp(tagname, "pcb"))
+ text_dest = (char **) &state->hi->pcb;
+ else if (!strcmp(tagname, "extrainfo"))
+ text_dest = (char **) &state->hi->extrainfo;
+ else
+ unknown_tag(state, tagname);
+
+ if (text_dest && state->hi)
+ state->text_dest = text_dest;
+ break;
+ }
+ state->pos = (hash_parse_position) (state->pos + 1);
+}
+
+
+
+/*-------------------------------------------------
+ end_handler
+-------------------------------------------------*/
+
+static void end_handler(void *data, const char *name)
+{
+ struct hash_parse_state *state = (struct hash_parse_state *) data;
+ state->text_dest = NULL;
+
+ state->pos = (hash_parse_position) (state->pos - 1);
+ switch(state->pos)
+ {
+ case POS_ROOT:
+ case POS_HASH:
+ break;
+
+ case POS_MAIN:
+ if (state->hi)
+ {
+ if (state->use_proc)
+ (*state->use_proc)(state->hashfile, state->param, state->hi);
+ state->hi = NULL;
+ }
+ break;
+ }
+}
+
+
+
+/*-------------------------------------------------
+ data_handler
+-------------------------------------------------*/
+
+static void data_handler(void *data, const XML_Char *s, int len)
+{
+ struct hash_parse_state *state = (struct hash_parse_state *) data;
+ int text_len;
+ char *text;
+
+ if (state->text_dest)
+ {
+ text = *state->text_dest;
+
+ text_len = text ? strlen(text) : 0;
+ text = (char*)pool_realloc_lib(state->hashfile->pool, text, text_len + len + 1);
+ if (!text)
+ return;
+
+ memcpy(&text[text_len], s, len);
+ text[text_len + len] = '\0';
+ *state->text_dest = text;
+ }
+}
+
+
+
+/*-------------------------------------------------
+ hashfile_parse
+-------------------------------------------------*/
+
+static void hashfile_parse(hash_file *hashfile,
+ int (*selector_proc)(hash_file *hashfile, void *param, const char *name, const char *hash),
+ void (*use_proc)(hash_file *hashfile, void *param, hash_info *hi),
+ void (*error_proc)(const char *message),
+ void *param)
+{
+ struct hash_parse_state state;
+ char buf[1024];
+ UINT32 len;
+ XML_Memory_Handling_Suite memcallbacks;
+
+ mame_fseek(hashfile->file, 0, SEEK_SET);
+
+ memset(&state, 0, sizeof(state));
+ state.hashfile = hashfile;
+ state.selector_proc = selector_proc;
+ state.use_proc = use_proc;
+ state.error_proc = error_proc;
+ state.param = param;
+
+ /* create the XML parser */
+ memcallbacks.malloc_fcn = expat_malloc;
+ memcallbacks.realloc_fcn = expat_realloc;
+ memcallbacks.free_fcn = expat_free;
+ state.parser = XML_ParserCreate_MM(NULL, &memcallbacks, NULL);
+ if (!state.parser)
+ goto done;
+
+ XML_SetUserData(state.parser, &state);
+ XML_SetElementHandler(state.parser, start_handler, end_handler);
+ XML_SetCharacterDataHandler(state.parser, data_handler);
+
+ while(!state.done)
+ {
+ len = mame_fread(hashfile->file, buf, sizeof(buf));
+ state.done = mame_feof(hashfile->file);
+ if (XML_Parse(state.parser, buf, len, state.done) == XML_STATUS_ERROR)
+ {
+ parse_error(&state, "[%lu:%lu]: %s\n",
+ XML_GetCurrentLineNumber(state.parser),
+ XML_GetCurrentColumnNumber(state.parser),
+ XML_ErrorString(XML_GetErrorCode(state.parser)));
+ goto done;
+ }
+ }
+
+done:
+ if (state.parser)
+ XML_ParserFree(state.parser);
+}
+
+
+
+/*-------------------------------------------------
+ preload_use_proc
+-------------------------------------------------*/
+
+static void preload_use_proc(hash_file *hashfile, void *param, hash_info *hi)
+{
+ hash_info **new_preloaded_hashes;
+
+ new_preloaded_hashes = (hash_info **)pool_realloc_lib(hashfile->pool, hashfile->preloaded_hashes,
+ (hashfile->preloaded_hash_count + 1) * sizeof(*new_preloaded_hashes));
+ if (!new_preloaded_hashes)
+ return;
+
+ hashfile->preloaded_hashes = new_preloaded_hashes;
+ hashfile->preloaded_hashes[hashfile->preloaded_hash_count++] = hi;
+}
+
+
+
+/*-------------------------------------------------
+ hashfile_open_options
+-------------------------------------------------*/
+
+hash_file *hashfile_open_options(core_options *opts, const char *sysname, int is_preload,
+ void (*error_proc)(const char *message))
+{
+ file_error filerr;
+ astring *fname;
+ hash_file *hashfile = NULL;
+ object_pool *pool = NULL;
+
+ /* create a pool for this hash file */
+ pool = pool_alloc_lib(error_proc);
+ if (!pool)
+ goto error;
+
+ /* allocate space for this hash file */
+ hashfile = (hash_file *) pool_malloc_lib(pool, sizeof(*hashfile));
+ if (!hashfile)
+ goto error;
+
+ /* set up the hashfile structure */
+ memset(hashfile, 0, sizeof(*hashfile));
+ hashfile->pool = pool;
+ hashfile->error_proc = error_proc;
+
+ /* open a file */
+ fname = astring_assemble_2(astring_alloc(), sysname, ".hsi");
+ filerr = mame_fopen_options(opts, SEARCHPATH_HASH, astring_c(fname), OPEN_FLAG_READ, &hashfile->file);
+ astring_free(fname);
+
+ if (filerr != FILERR_NONE)
+ goto error;
+
+ if (is_preload)
+ hashfile_parse(hashfile, NULL, preload_use_proc, hashfile->error_proc, NULL);
+
+ return hashfile;
+
+error:
+ if (hashfile != NULL)
+ hashfile_close(hashfile);
+ return NULL;
+}
+
+
+
+/*-------------------------------------------------
+ hashfile_open
+-------------------------------------------------*/
+
+hash_file *hashfile_open(const char *sysname, int is_preload,
+ void (*error_proc)(const char *message))
+{
+ return hashfile_open_options(mame_options(), sysname, is_preload, error_proc);
+}
+
+
+
+/*-------------------------------------------------
+ hashfile_close
+-------------------------------------------------*/
+
+void hashfile_close(hash_file *hashfile)
+{
+ if (hashfile->file)
+ mame_fclose(hashfile->file);
+ pool_free_lib(hashfile->pool);
+}
+
+
+
+/*-------------------------------------------------
+ singular_selector_proc
+-------------------------------------------------*/
+
+struct hashlookup_params
+{
+ const char *hash;
+ hash_info *hi;
+};
+
+static int singular_selector_proc(hash_file *hashfile, void *param, const char *name, const char *hash)
+{
+ struct hashlookup_params *hlparams = (struct hashlookup_params *) param;
+ return hash_data_is_equal(hash, hlparams->hash,
+ hash_data_used_functions(hash)) == 1;
+}
+
+
+
+/*-------------------------------------------------
+ singular_use_proc
+-------------------------------------------------*/
+
+static void singular_use_proc(hash_file *hashfile, void *param, hash_info *hi)
+{
+ struct hashlookup_params *hlparams = (struct hashlookup_params *) param;
+ hlparams->hi = hi;
+}
+
+
+
+/*-------------------------------------------------
+ hashfile_lookup
+-------------------------------------------------*/
+
+const hash_info *hashfile_lookup(hash_file *hashfile, const char *hash)
+{
+ struct hashlookup_params param;
+ int i;
+
+ param.hash = hash;
+ param.hi = NULL;
+
+ for (i = 0; i < hashfile->preloaded_hash_count; i++)
+ {
+ if (singular_selector_proc(hashfile, &param, NULL, hashfile->preloaded_hashes[i]->hash))
+ return hashfile->preloaded_hashes[i];
+ }
+
+ hashfile_parse(hashfile, singular_selector_proc, singular_use_proc,
+ hashfile->error_proc, (void *) &param);
+ return param.hi;
+}
+
+
+
+/*-------------------------------------------------
+ hashfile_functions_used
+-------------------------------------------------*/
+
+unsigned int hashfile_functions_used(hash_file *hashfile, iodevice_t devtype)
+{
+ assert(devtype >= 0);
+ assert(devtype < IO_COUNT);
+ return hashfile->functions[devtype];
+}
+
+
+
+/*-------------------------------------------------
+ hashfile_verify
+-------------------------------------------------*/
+
+int hashfile_verify(const char *sysname, void (*my_error_proc)(const char *message))
+{
+ hash_file *hashfile;
+
+ hashfile = hashfile_open(sysname, FALSE, my_error_proc);
+ if (!hashfile)
+ return -1;
+
+ hashfile_parse(hashfile, NULL, NULL, my_error_proc, NULL);
+ hashfile_close(hashfile);
+ return 0;
+}
+
+
+
+/***************************************************************************
+ EXPAT INTERFACES
+***************************************************************************/
+
+/*-------------------------------------------------
+ expat_malloc/expat_realloc/expat_free -
+ wrappers for memory allocation functions so
+ that they pass through out memory tracking
+ systems
+-------------------------------------------------*/
+
+static void *expat_malloc(size_t size)
+{
+ return global_alloc_array_clear(UINT8,size);
+}
+
+static void *expat_realloc(void *ptr, size_t size)
+{
+ if (ptr) global_free(ptr);
+ return global_alloc_array_clear(UINT8,size);
+}
+
+static void expat_free(void *ptr)
+{
+ global_free(ptr);
+}
diff --git a/src/emu/hashfile.h b/src/emu/hashfile.h
new file mode 100644
index 00000000000..23467d17b5d
--- /dev/null
+++ b/src/emu/hashfile.h
@@ -0,0 +1,62 @@
+/*********************************************************************
+
+ hashfile.h
+
+ Code for parsing hash info (*.hsi) files
+
+*********************************************************************/
+
+#ifndef __HASHFILE_H__
+#define __HASHFILE_H__
+
+#include "emu.h"
+#include "hash.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _hash_info hash_info;
+struct _hash_info
+{
+ char hash[HASH_BUF_SIZE];
+ const char *longname;
+ const char *manufacturer;
+ const char *year;
+ const char *playable;
+ const char *pcb;
+ const char *extrainfo;
+};
+
+typedef struct _hash_file hash_file;
+
+typedef void (*hashfile_error_func)(const char *message);
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* opens a hash file; if is_preload is non-zero, the entire file is preloaded */
+hash_file *hashfile_open(const char *sysname, int is_preload, hashfile_error_func error_proc);
+
+/* opens a hash file; if is_preload is non-zero, the entire file is preloaded */
+hash_file *hashfile_open_options(core_options *opts, const char *sysname, int is_preload,
+ hashfile_error_func error_proc);
+
+/* closes a hash file and associated resources */
+void hashfile_close(hash_file *hashfile);
+
+/* looks up information in a hash file */
+const hash_info *hashfile_lookup(hash_file *hashfile, const char *hash);
+
+/* performs a syntax check on a hash file */
+int hashfile_verify(const char *sysname, void (*error_proc)(const char *message));
+
+/* returns the functions used in this hash file */
+unsigned int hashfile_functions_used(hash_file *hashfile, iodevice_t devtype);
+
+
+#endif /* __HASHFILE_H__ */