summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatarGravatar Miodrag Milanovic <mmicko@gmail.com>2010-06-17 06:57:05 +0000
committerGravatarGravatar Miodrag Milanovic <mmicko@gmail.com>2010-06-17 06:57:05 +0000
commitd2a7b5f332d42f1a7d47102cecd4dcadd3d15acd (patch)
tree5e9a339c1cbcdce22804b3f87695b2c8725ebc40
parent861db1eb49e7d1734d07ae8aafce2b6fdd88fece (diff)
hashfile moved from MESS to emu section (needed for now in image support until softlist implementation is finished), this doesn't affect mame side (no whatsnew)mame0138u2
-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__ */