From 848bf53c3d7e1093f262a9b8826e662dfb5fa473 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 16 Jun 2010 18:04:30 +0000 Subject: - moved opresolv and zippath into /lib/util from MESS [Miodrag Milanovic] - removed ifdef MESS from osd part since calls are needed by zippath --- .gitattributes | 6 +- src/emu/emu.mak | 1 - src/emu/opresolv.c | 585 ------------------------------ src/emu/opresolv.h | 160 --------- src/lib/lib.mak | 2 + src/lib/util/opresolv.c | 565 +++++++++++++++++++++++++++++ src/lib/util/opresolv.h | 160 +++++++++ src/lib/util/zippath.c | 859 +++++++++++++++++++++++++++++++++++++++++++++ src/lib/util/zippath.h | 66 ++++ src/osd/osdcore.h | 2 - src/osd/sdl/sdlos_macosx.c | 8 - src/osd/sdl/sdlos_unix.c | 8 - src/osd/sdl/sdlos_win32.c | 8 - 13 files changed, 1656 insertions(+), 774 deletions(-) delete mode 100644 src/emu/opresolv.c delete mode 100644 src/emu/opresolv.h create mode 100644 src/lib/util/opresolv.c create mode 100644 src/lib/util/opresolv.h create mode 100644 src/lib/util/zippath.c create mode 100644 src/lib/util/zippath.h diff --git a/.gitattributes b/.gitattributes index 368f68ec80e..79b1a19343a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -792,8 +792,6 @@ src/emu/mconfig.h svneol=native#text/plain src/emu/memconv.h svneol=native#text/plain src/emu/memory.c svneol=native#text/plain src/emu/memory.h svneol=native#text/plain -src/emu/opresolv.c svneol=native#text/plain -src/emu/opresolv.h svneol=native#text/plain src/emu/output.c svneol=native#text/plain src/emu/output.h svneol=native#text/plain src/emu/profiler.c svneol=native#text/plain @@ -1153,6 +1151,8 @@ src/lib/util/jedparse.c svneol=native#text/plain src/lib/util/jedparse.h svneol=native#text/plain src/lib/util/md5.c svneol=native#text/plain src/lib/util/md5.h svneol=native#text/plain +src/lib/util/opresolv.c svneol=native#text/plain +src/lib/util/opresolv.h svneol=native#text/plain src/lib/util/options.c svneol=native#text/plain src/lib/util/options.h svneol=native#text/plain src/lib/util/palette.c svneol=native#text/plain @@ -1173,6 +1173,8 @@ src/lib/util/vbiparse.c svneol=native#text/plain src/lib/util/vbiparse.h svneol=native#text/plain src/lib/util/xmlfile.c svneol=native#text/plain src/lib/util/xmlfile.h svneol=native#text/plain +src/lib/util/zippath.c svneol=native#text/plain +src/lib/util/zippath.h svneol=native#text/plain src/lib/zlib/Makefile svneol=native#text/plain src/lib/zlib/Makefile.in svneol=native#text/plain src/lib/zlib/adler32.c svneol=native#text/plain diff --git a/src/emu/emu.mak b/src/emu/emu.mak index 1e83756a748..91c964f2a83 100644 --- a/src/emu/emu.mak +++ b/src/emu/emu.mak @@ -71,7 +71,6 @@ EMUOBJS = \ $(EMUOBJ)/mconfig.o \ $(EMUOBJ)/memory.o \ $(EMUOBJ)/output.o \ - $(EMUOBJ)/opresolv.o \ $(EMUOBJ)/render.o \ $(EMUOBJ)/rendfont.o \ $(EMUOBJ)/rendlay.o \ diff --git a/src/emu/opresolv.c b/src/emu/opresolv.c deleted file mode 100644 index aa63396804e..00000000000 --- a/src/emu/opresolv.c +++ /dev/null @@ -1,585 +0,0 @@ -/**************************************************************************** - - opresolv.h - - Extensible ranged option resolution handling - -****************************************************************************/ - -#include -#include -#include -#include - -#include "pool.h" -#include "opresolv.h" -#include "emu.h" - -enum resolution_entry_state -{ - RESOLUTION_ENTRY_STATE_UNSPECIFIED, - RESOLUTION_ENTRY_STATE_SPECIFIED -}; - -struct option_resolution_entry -{ - const option_guide *guide_entry; - enum resolution_entry_state state; - union - { - int int_value; - const char *str_value; - } u; -}; - -struct _option_resolution -{ - object_pool *pool; - const char *specification; - size_t option_count; - struct option_resolution_entry *entries; -}; - - - -/* syntax errors are generally indicative of some sort of internal error */ -static void syntaxerror(const char *str) -{ -#ifdef MAME_DEBUG - logerror("Option resolution syntax error! str='%s'\n", str); -#endif -} - - - -static optreserr_t resolve_single_param(const char *specification, int *param_value, - struct OptionRange *range, size_t range_count) -{ - int FLAG_IN_RANGE = 0x01; - int FLAG_IN_DEFAULT = 0x02; - int FLAG_DEFAULT_SPECIFIED = 0x04; - int FLAG_HALF_RANGE = 0x08; - - int last_value = 0; - int value = 0; - int flags = 0; - const char *s = specification; - - while(*s && !isalpha(*s)) - { - if (*s == '-') - { - /* range specifier */ - if (flags & (FLAG_IN_RANGE|FLAG_IN_DEFAULT)) - { - syntaxerror(NULL); - return OPTIONRESOLUTION_ERROR_SYNTAX; - } - flags |= FLAG_IN_RANGE; - s++; - - if (range) - { - range->max = -1; - if ((flags & FLAG_HALF_RANGE) == 0) - { - range->min = -1; - flags |= FLAG_HALF_RANGE; - } - } - } - else if (*s == '[') - { - /* begin default value */ - if (flags & (FLAG_IN_DEFAULT|FLAG_DEFAULT_SPECIFIED)) - { - syntaxerror(NULL); - return OPTIONRESOLUTION_ERROR_SYNTAX; - } - flags |= FLAG_IN_DEFAULT; - s++; - } - else if (*s == ']') - { - /* end default value */ - if ((flags & FLAG_IN_DEFAULT) == 0) - { - syntaxerror(NULL); - return OPTIONRESOLUTION_ERROR_SYNTAX; - } - flags &= ~FLAG_IN_DEFAULT; - flags |= FLAG_DEFAULT_SPECIFIED; - s++; - - if (param_value && *param_value == -1) - *param_value = value; - } - else if (*s == '/') - { - /* value separator */ - if (flags & (FLAG_IN_DEFAULT|FLAG_IN_RANGE)) - { - syntaxerror(NULL); - return OPTIONRESOLUTION_ERROR_SYNTAX; - } - s++; - - /* if we are spitting out ranges, complete the range */ - if (range && (flags & FLAG_HALF_RANGE)) - { - range++; - flags &= ~FLAG_HALF_RANGE; - if (--range_count == 0) - range = NULL; - } - } - else if (*s == ';') - { - /* basic separator */ - s++; - } - else if (isdigit(*s)) - { - /* numeric value */ - last_value = value; - value = 0; - do - { - value *= 10; - value += *s - '0'; - s++; - } - while(isdigit(*s)); - - if (range) - { - if ((flags & FLAG_HALF_RANGE) == 0) - { - range->min = value; - flags |= FLAG_HALF_RANGE; - } - range->max = value; - } - - /* if we have a value; check to see if it is out of range */ - if (param_value && (*param_value != -1) && (*param_value != value)) - { - if ((last_value < *param_value) && (*param_value < value)) - { - if ((flags & FLAG_IN_RANGE) == 0) - return OPTIONRESOLUTION_ERROR_PARAMOUTOFRANGE; - } - } - flags &= ~FLAG_IN_RANGE; - } - else - { - syntaxerror(NULL); - return OPTIONRESOLUTION_ERROR_SYNTAX; - } - } - - /* we can't have zero length guidelines strings */ - if (s == specification) - { - syntaxerror(NULL); - return OPTIONRESOLUTION_ERROR_SYNTAX; - } - - return OPTIONRESOLUTION_ERROR_SUCCESS; -} - - - -static const char *lookup_in_specification(const char *specification, const option_guide *option) -{ - const char *s; - s = strchr(specification, option->parameter); - return s ? s + 1 : NULL; -} - - - -option_resolution *option_resolution_create(const option_guide *guide, const char *specification) -{ - option_resolution *resolution = NULL; - const option_guide *guide_entry; - int option_count; - int opt = -1; - object_pool *pool; - - assert(guide); - - /* first count the number of options specified in the guide */ - option_count = option_resolution_countoptions(guide, specification); - - /* create a memory pool for this structure */ - pool = pool_alloc_lib(NULL); - if (!pool) - goto outofmemory; - - /* allocate the main structure */ - resolution = (option_resolution *)pool_malloc_lib(pool, sizeof(option_resolution)); - if (!resolution) - goto outofmemory; - memset(resolution, 0, sizeof(*resolution)); - resolution->pool = pool; - - /* set up the entries list */ - resolution->option_count = option_count; - resolution->specification = specification; - resolution->entries = (option_resolution_entry *)pool_malloc_lib(resolution->pool, sizeof(struct option_resolution_entry) * option_count); - if (!resolution->entries) - goto outofmemory; - memset(resolution->entries, 0, sizeof(struct option_resolution_entry) * option_count); - - /* initialize each of the entries */ - opt = 0; - guide_entry = guide; - while(guide_entry->option_type != OPTIONTYPE_END) - { - switch(guide_entry->option_type) { - case OPTIONTYPE_INT: - case OPTIONTYPE_ENUM_BEGIN: - case OPTIONTYPE_STRING: - if (lookup_in_specification(specification, guide_entry)) - resolution->entries[opt++].guide_entry = guide_entry; - break; - case OPTIONTYPE_ENUM_VALUE: - break; - default: - goto unexpected; - } - guide_entry++; - } - assert(opt == option_count); - return resolution; - -unexpected: - assert(FALSE); -outofmemory: - if (resolution) - option_resolution_close(resolution); - return NULL; -} - - - -optreserr_t option_resolution_add_param(option_resolution *resolution, const char *param, const char *value) -{ - int i; - int must_resolve; - optreserr_t err; - const char *option_specification; - struct option_resolution_entry *entry = NULL; - - for (i = 0; i < resolution->option_count; i++) - { - if (!strcmp(param, resolution->entries[i].guide_entry->identifier)) - { - entry = &resolution->entries[i]; - break; - } - } - if (!entry) - return OPTIONRESOLUTION_ERROR_PARAMNOTFOUND; - - if (entry->state != RESOLUTION_ENTRY_STATE_UNSPECIFIED) - return OPTIONRESOLUTION_ERROR_PARAMALREADYSPECIFIED; - - switch(entry->guide_entry->option_type) { - case OPTIONTYPE_INT: - entry->u.int_value = atoi(value); - entry->state = RESOLUTION_ENTRY_STATE_SPECIFIED; - must_resolve = TRUE; - break; - - case OPTIONTYPE_STRING: - entry->u.str_value = pool_strdup_lib(resolution->pool, value); - if (!entry->u.str_value) - { - err = OPTIONRESOLUTION_ERROR_OUTOFMEMORY; - goto done; - } - entry->state = RESOLUTION_ENTRY_STATE_SPECIFIED; - must_resolve = FALSE; - break; - - case OPTIONTYPE_ENUM_BEGIN: - for (i = 1; entry->guide_entry[i].option_type == OPTIONTYPE_ENUM_VALUE; i++) - { - if (!mame_stricmp(value, entry->guide_entry[i].identifier)) - { - entry->u.int_value = entry->guide_entry[i].parameter; - entry->state = RESOLUTION_ENTRY_STATE_SPECIFIED; - break; - } - } - if (entry->state != RESOLUTION_ENTRY_STATE_SPECIFIED) - { - err = OPTIONRESOLUTION_ERROR_BADPARAM; - goto done; - } - must_resolve = TRUE; - break; - - default: - err = OPTIONRESOLTUION_ERROR_INTERNAL; - assert(0); - goto done; - } - - /* do a resolution step if necessary */ - if (must_resolve) - { - option_specification = lookup_in_specification(resolution->specification, entry->guide_entry); - err = resolve_single_param(option_specification, &entry->u.int_value, NULL, 0); - if (err) - goto done; - - /* did we not get a real value? */ - if (entry->u.int_value < 0) - { - err = OPTIONRESOLUTION_ERROR_PARAMNOTSPECIFIED; - goto done; - } - } - - err = OPTIONRESOLUTION_ERROR_SUCCESS; - -done: - return err; -} - - - -void option_resolution_close(option_resolution *resolution) -{ - pool_free_lib(resolution->pool); -} - - - -optreserr_t option_resolution_finish(option_resolution *resolution) -{ - int i; - optreserr_t err; - struct option_resolution_entry *entry; - const char *option_specification; - - for (i = 0; i < resolution->option_count; i++) - { - entry = &resolution->entries[i]; - - if (entry->state == RESOLUTION_ENTRY_STATE_UNSPECIFIED) - { - switch(entry->guide_entry->option_type) { - case OPTIONTYPE_INT: - case OPTIONTYPE_ENUM_BEGIN: - option_specification = lookup_in_specification(resolution->specification, entry->guide_entry); - assert(option_specification); - entry->u.int_value = -1; - err = resolve_single_param(option_specification, &entry->u.int_value, NULL, 0); - if (err) - return err; - break; - - case OPTIONTYPE_STRING: - entry->u.str_value = ""; - break; - - default: - assert(FALSE); - return OPTIONRESOLTUION_ERROR_INTERNAL; - } - entry->state = RESOLUTION_ENTRY_STATE_SPECIFIED; - } - } - return OPTIONRESOLUTION_ERROR_SUCCESS; -} - - - -static const struct option_resolution_entry *option_resolution_lookup_entry(option_resolution *resolution, int option_char) -{ - size_t i; - const struct option_resolution_entry *entry; - - for (i = 0; i < resolution->option_count; i++) - { - entry = &resolution->entries[i]; - - switch(entry->guide_entry->option_type) { - case OPTIONTYPE_INT: - case OPTIONTYPE_STRING: - case OPTIONTYPE_ENUM_BEGIN: - if (entry->guide_entry->parameter == option_char) - return entry; - break; - - default: - assert(FALSE); - return NULL; - } - } - return NULL; -} - - - -int option_resolution_lookup_int(option_resolution *resolution, int option_char) -{ - const struct option_resolution_entry *entry; - entry = option_resolution_lookup_entry(resolution, option_char); - return entry ? entry->u.int_value : -1; -} - - - -const char *option_resolution_lookup_string(option_resolution *resolution, int option_char) -{ - const struct option_resolution_entry *entry; - entry = option_resolution_lookup_entry(resolution, option_char); - return entry ? entry->u.str_value : NULL; -} - - - -const char *option_resolution_specification(option_resolution *resolution) -{ - return resolution->specification; -} - - - -const option_guide *option_resolution_find_option(option_resolution *resolution, int option_char) -{ - const struct option_resolution_entry *entry; - entry = option_resolution_lookup_entry(resolution, option_char); - return entry ? entry->guide_entry : NULL; -} - - - -const option_guide *option_resolution_index_option(option_resolution *resolution, int indx) -{ - if ((indx < 0) || (indx >= resolution->option_count)) - return NULL; - return resolution->entries[indx].guide_entry; -} - - - -int option_resolution_countoptions(const option_guide *guide, const char *specification) -{ - int option_count = 0; - - while(guide->option_type != OPTIONTYPE_END) - { - switch(guide->option_type) { - case OPTIONTYPE_INT: - case OPTIONTYPE_STRING: - case OPTIONTYPE_ENUM_BEGIN: - if (lookup_in_specification(specification, guide)) - option_count++; - break; - case OPTIONTYPE_ENUM_VALUE: - break; - default: - assert(FALSE); - return 0; - } - guide++; - } - return option_count; -} - - - -optreserr_t option_resolution_listranges(const char *specification, int option_char, - struct OptionRange *range, size_t range_count) -{ - assert(range_count > 0); - - /* clear out range */ - memset(range, -1, sizeof(*range) * range_count); - range_count--; - - specification = strchr(specification, option_char); - if (!specification) - { - syntaxerror(NULL); - return OPTIONRESOLUTION_ERROR_SYNTAX; - } - - return resolve_single_param(specification + 1, NULL, range, range_count); -} - - - -optreserr_t option_resolution_getdefault(const char *specification, int option_char, int *val) -{ - assert(val); - - /* clear out default */ - *val = -1; - - specification = strchr(specification, option_char); - if (!specification) - { - syntaxerror(NULL); - return OPTIONRESOLUTION_ERROR_SYNTAX; - } - - return resolve_single_param(specification + 1, val, NULL, 0); -} - - - -optreserr_t option_resolution_isvalidvalue(const char *specification, int option_char, int val) -{ - optreserr_t err; - struct OptionRange ranges[256]; - int i; - - err = option_resolution_listranges(specification, option_char, ranges, ARRAY_LENGTH(ranges)); - if (err) - return err; - - for (i = 0; (ranges[i].min >= 0) && (ranges[i].max >= 0); i++) - { - if ((ranges[i].min <= val) && (ranges[i].max >= val)) - return OPTIONRESOLUTION_ERROR_SUCCESS; - } - return OPTIONRESOLUTION_ERROR_PARAMOUTOFRANGE; -} - - - -int option_resolution_contains(const char *specification, int option_char) -{ - return strchr(specification, option_char) != NULL; -} - - - -const char *option_resolution_error_string(optreserr_t err) -{ - static const char *const errors[] = - { - "The operation completed successfully", /* OPTIONRESOLUTION_ERROR_SUCCESS */ - "Out of memory", /* OPTIONRESOLUTION_ERROR_OUTOFMEMORY */ - "Parameter out of range", /* OPTIONRESOLUTION_ERROR_PARAMOUTOFRANGE */ - "Parameter not specified", /* OPTIONRESOLUTION_ERROR_PARAMNOTSPECIFIED */ - "Unknown parameter", /* OPTIONRESOLUTION_ERROR_PARAMNOTFOUND */ - "Paramter specified multiple times", /* OPTIONRESOLUTION_ERROR_PARAMALREADYSPECIFIED */ - "Invalid parameter", /* OPTIONRESOLUTION_ERROR_BADPARAM */ - "Syntax error", /* OPTIONRESOLUTION_ERROR_SYNTAX */ - "Internal error" /* OPTIONRESOLTUION_ERROR_INTERNAL */ - }; - - if ((err < 0) || (err >= ARRAY_LENGTH(errors))) - return NULL; - return errors[err]; -} - diff --git a/src/emu/opresolv.h b/src/emu/opresolv.h deleted file mode 100644 index 7048e8b1538..00000000000 --- a/src/emu/opresolv.h +++ /dev/null @@ -1,160 +0,0 @@ -/**************************************************************************** - - opresolv.h - - Extensible ranged option resolution handling - - An extensible mechanism for handling options is a major need in MESS and - Imgtool. Unfortunately, since we are using straight C for everything, it - can be hard and awkward to create non-arcane mechanisms for representing - these options. - - In this system, we have the following concepts: - 1. An "option specification"; a string that represents what options are - available, their defaults, and their allowed ranges. Here is an - example: - - Examples: - "H[1]-2;T[35]/40/80;S[18]" - Allow 1-2 heads; 35, 40 or 80 tracks, and 18 sectors, - defaulting to 1 heads and 35 tracks. - - "N'Simon''s desk'" - Simon's desk (strings are not subject to range checking) - - 2. An "option guide"; a struct that provides information about what the - various members of the option specification mean (i.e. - H=heads) - - 3. An "option resolution"; an object that represents a set of interpreted - options. At this stage, the option bid has been processed and it is - guaranteed that all options reside in their expected ranges. - - An option_resolution object is created based on an option guide and an - option specification. It is then possible to specify individual parameters - to the option_resolution object. Argument checks occur at this time. When - one is all done, you can then query the object for any given value. - -****************************************************************************/ - -#ifndef __OPRESOLV_H__ -#define __OPRESOLV_H__ - -#include - - -/*************************************************************************** - - Type definitions - -***************************************************************************/ - -enum option_type -{ - OPTIONTYPE_END, - OPTIONTYPE_INT, - OPTIONTYPE_STRING, - OPTIONTYPE_ENUM_BEGIN, - OPTIONTYPE_ENUM_VALUE -}; - -typedef struct _option_guide option_guide; -struct _option_guide -{ - enum option_type option_type; - int parameter; - const char *identifier; - const char *display_name; -}; - -#define OPTION_GUIDE_START(option_guide_) \ - const option_guide option_guide_[] = \ - { \ - -#define OPTION_GUIDE_END \ - { OPTIONTYPE_END } \ - }; \ - -#define OPTION_GUIDE_EXTERN(option_guide_) \ - extern const option_guide option_guide_[] \ - -#define OPTION_INT(option_char, identifier, display_name) \ - { OPTIONTYPE_INT, (option_char), (identifier), (display_name) }, \ - -#define OPTION_STRING(option_char, identifier, display_name) \ - { OPTIONTYPE_STRING, (option_char), (identifier), (display_name) }, \ - -#define OPTION_ENUM_START(option_char, identifier, display_name) \ - { OPTIONTYPE_ENUM_BEGIN, (option_char), (identifier), (display_name) }, \ - -#define OPTION_ENUM(value, identifier, display_name) \ - { OPTIONTYPE_ENUM_VALUE, (value), (identifier), (display_name) }, \ - -#define OPTION_ENUM_END - - -typedef enum -{ - OPTIONRESOLUTION_ERROR_SUCCESS, - OPTIONRESOLUTION_ERROR_OUTOFMEMORY, - OPTIONRESOLUTION_ERROR_PARAMOUTOFRANGE, - OPTIONRESOLUTION_ERROR_PARAMNOTSPECIFIED, - OPTIONRESOLUTION_ERROR_PARAMNOTFOUND, - OPTIONRESOLUTION_ERROR_PARAMALREADYSPECIFIED, - OPTIONRESOLUTION_ERROR_BADPARAM, - OPTIONRESOLUTION_ERROR_SYNTAX, - OPTIONRESOLTUION_ERROR_INTERNAL -} optreserr_t; - - - -struct OptionResolutionError -{ - const option_guide *option; - optreserr_t error; -}; - - - -typedef struct _option_resolution option_resolution; - -struct OptionRange -{ - int min, max; -}; - - - -/*************************************************************************** - - Prototypes - -***************************************************************************/ - -/* processing options with option_resolution objects */ -option_resolution *option_resolution_create(const option_guide *guide, const char *specification); -optreserr_t option_resolution_add_param(option_resolution *resolution, const char *param, const char *value); -optreserr_t option_resolution_finish(option_resolution *resolution); -void option_resolution_close(option_resolution *resolution); -int option_resolution_lookup_int(option_resolution *resolution, int option_char); -const char *option_resolution_lookup_string(option_resolution *resolution, int option_char); - -/* option resolution accessors */ -const char *option_resolution_specification(option_resolution *resolution); -const option_guide *option_resolution_find_option(option_resolution *resolution, int option_char); -const option_guide *option_resolution_index_option(option_resolution *resolution, int indx); - -/* processing option guides */ -int option_resolution_countoptions(const option_guide *guide, const char *specification); - -/* processing option specifications */ -optreserr_t option_resolution_listranges(const char *specification, int option_char, - struct OptionRange *range, size_t range_count); -optreserr_t option_resolution_getdefault(const char *specification, int option_char, int *val); -optreserr_t option_resolution_isvalidvalue(const char *specification, int option_char, int val); -int option_resolution_contains(const char *specification, int option_char); - -/* misc */ -const char *option_resolution_error_string(optreserr_t err); - -#endif /* __OPRESOLV_H__ */ - diff --git a/src/lib/lib.mak b/src/lib/lib.mak index c60ed5da003..bea500db4be 100644 --- a/src/lib/lib.mak +++ b/src/lib/lib.mak @@ -39,6 +39,7 @@ UTILOBJS = \ $(LIBOBJ)/util/huffman.o \ $(LIBOBJ)/util/jedparse.o \ $(LIBOBJ)/util/md5.o \ + $(LIBOBJ)/util/opresolv.o \ $(LIBOBJ)/util/options.o \ $(LIBOBJ)/util/palette.o \ $(LIBOBJ)/util/png.o \ @@ -49,6 +50,7 @@ UTILOBJS = \ $(LIBOBJ)/util/unzip.o \ $(LIBOBJ)/util/vbiparse.o \ $(LIBOBJ)/util/xmlfile.o \ + $(LIBOBJ)/util/zippath.o \ $(OBJ)/libutil.a: $(UTILOBJS) diff --git a/src/lib/util/opresolv.c b/src/lib/util/opresolv.c new file mode 100644 index 00000000000..db9e81a3536 --- /dev/null +++ b/src/lib/util/opresolv.c @@ -0,0 +1,565 @@ +/**************************************************************************** + + opresolv.h + + Extensible ranged option resolution handling + +****************************************************************************/ + +#include +#include +#include +#include + +#include "pool.h" +#include "corestr.h" +#include "opresolv.h" + +enum resolution_entry_state +{ + RESOLUTION_ENTRY_STATE_UNSPECIFIED, + RESOLUTION_ENTRY_STATE_SPECIFIED +}; + +struct option_resolution_entry +{ + const option_guide *guide_entry; + enum resolution_entry_state state; + union + { + int int_value; + const char *str_value; + } u; +}; + +struct _option_resolution +{ + object_pool *pool; + const char *specification; + size_t option_count; + struct option_resolution_entry *entries; +}; + +static optreserr_t resolve_single_param(const char *specification, int *param_value, + struct OptionRange *range, size_t range_count) +{ + int FLAG_IN_RANGE = 0x01; + int FLAG_IN_DEFAULT = 0x02; + int FLAG_DEFAULT_SPECIFIED = 0x04; + int FLAG_HALF_RANGE = 0x08; + + int last_value = 0; + int value = 0; + int flags = 0; + const char *s = specification; + + while(*s && !isalpha(*s)) + { + if (*s == '-') + { + /* range specifier */ + if (flags & (FLAG_IN_RANGE|FLAG_IN_DEFAULT)) + { + return OPTIONRESOLUTION_ERROR_SYNTAX; + } + flags |= FLAG_IN_RANGE; + s++; + + if (range) + { + range->max = -1; + if ((flags & FLAG_HALF_RANGE) == 0) + { + range->min = -1; + flags |= FLAG_HALF_RANGE; + } + } + } + else if (*s == '[') + { + /* begin default value */ + if (flags & (FLAG_IN_DEFAULT|FLAG_DEFAULT_SPECIFIED)) + { + return OPTIONRESOLUTION_ERROR_SYNTAX; + } + flags |= FLAG_IN_DEFAULT; + s++; + } + else if (*s == ']') + { + /* end default value */ + if ((flags & FLAG_IN_DEFAULT) == 0) + { + return OPTIONRESOLUTION_ERROR_SYNTAX; + } + flags &= ~FLAG_IN_DEFAULT; + flags |= FLAG_DEFAULT_SPECIFIED; + s++; + + if (param_value && *param_value == -1) + *param_value = value; + } + else if (*s == '/') + { + /* value separator */ + if (flags & (FLAG_IN_DEFAULT|FLAG_IN_RANGE)) + { + return OPTIONRESOLUTION_ERROR_SYNTAX; + } + s++; + + /* if we are spitting out ranges, complete the range */ + if (range && (flags & FLAG_HALF_RANGE)) + { + range++; + flags &= ~FLAG_HALF_RANGE; + if (--range_count == 0) + range = NULL; + } + } + else if (*s == ';') + { + /* basic separator */ + s++; + } + else if (isdigit(*s)) + { + /* numeric value */ + last_value = value; + value = 0; + do + { + value *= 10; + value += *s - '0'; + s++; + } + while(isdigit(*s)); + + if (range) + { + if ((flags & FLAG_HALF_RANGE) == 0) + { + range->min = value; + flags |= FLAG_HALF_RANGE; + } + range->max = value; + } + + /* if we have a value; check to see if it is out of range */ + if (param_value && (*param_value != -1) && (*param_value != value)) + { + if ((last_value < *param_value) && (*param_value < value)) + { + if ((flags & FLAG_IN_RANGE) == 0) + return OPTIONRESOLUTION_ERROR_PARAMOUTOFRANGE; + } + } + flags &= ~FLAG_IN_RANGE; + } + else + { + return OPTIONRESOLUTION_ERROR_SYNTAX; + } + } + + /* we can't have zero length guidelines strings */ + if (s == specification) + { + return OPTIONRESOLUTION_ERROR_SYNTAX; + } + + return OPTIONRESOLUTION_ERROR_SUCCESS; +} + + + +static const char *lookup_in_specification(const char *specification, const option_guide *option) +{ + const char *s; + s = strchr(specification, option->parameter); + return s ? s + 1 : NULL; +} + + + +option_resolution *option_resolution_create(const option_guide *guide, const char *specification) +{ + option_resolution *resolution = NULL; + const option_guide *guide_entry; + int option_count; + int opt = -1; + object_pool *pool; + + assert(guide); + + /* first count the number of options specified in the guide */ + option_count = option_resolution_countoptions(guide, specification); + + /* create a memory pool for this structure */ + pool = pool_alloc_lib(NULL); + if (!pool) + goto outofmemory; + + /* allocate the main structure */ + resolution = (option_resolution *)pool_malloc_lib(pool, sizeof(option_resolution)); + if (!resolution) + goto outofmemory; + memset(resolution, 0, sizeof(*resolution)); + resolution->pool = pool; + + /* set up the entries list */ + resolution->option_count = option_count; + resolution->specification = specification; + resolution->entries = (option_resolution_entry *)pool_malloc_lib(resolution->pool, sizeof(struct option_resolution_entry) * option_count); + if (!resolution->entries) + goto outofmemory; + memset(resolution->entries, 0, sizeof(struct option_resolution_entry) * option_count); + + /* initialize each of the entries */ + opt = 0; + guide_entry = guide; + while(guide_entry->option_type != OPTIONTYPE_END) + { + switch(guide_entry->option_type) { + case OPTIONTYPE_INT: + case OPTIONTYPE_ENUM_BEGIN: + case OPTIONTYPE_STRING: + if (lookup_in_specification(specification, guide_entry)) + resolution->entries[opt++].guide_entry = guide_entry; + break; + case OPTIONTYPE_ENUM_VALUE: + break; + default: + goto unexpected; + } + guide_entry++; + } + assert(opt == option_count); + return resolution; + +unexpected: + assert(FALSE); +outofmemory: + if (resolution) + option_resolution_close(resolution); + return NULL; +} + + + +optreserr_t option_resolution_add_param(option_resolution *resolution, const char *param, const char *value) +{ + int i; + int must_resolve; + optreserr_t err; + const char *option_specification; + struct option_resolution_entry *entry = NULL; + + for (i = 0; i < resolution->option_count; i++) + { + if (!strcmp(param, resolution->entries[i].guide_entry->identifier)) + { + entry = &resolution->entries[i]; + break; + } + } + if (!entry) + return OPTIONRESOLUTION_ERROR_PARAMNOTFOUND; + + if (entry->state != RESOLUTION_ENTRY_STATE_UNSPECIFIED) + return OPTIONRESOLUTION_ERROR_PARAMALREADYSPECIFIED; + + switch(entry->guide_entry->option_type) { + case OPTIONTYPE_INT: + entry->u.int_value = atoi(value); + entry->state = RESOLUTION_ENTRY_STATE_SPECIFIED; + must_resolve = TRUE; + break; + + case OPTIONTYPE_STRING: + entry->u.str_value = pool_strdup_lib(resolution->pool, value); + if (!entry->u.str_value) + { + err = OPTIONRESOLUTION_ERROR_OUTOFMEMORY; + goto done; + } + entry->state = RESOLUTION_ENTRY_STATE_SPECIFIED; + must_resolve = FALSE; + break; + + case OPTIONTYPE_ENUM_BEGIN: + for (i = 1; entry->guide_entry[i].option_type == OPTIONTYPE_ENUM_VALUE; i++) + { + if (!core_stricmp(value, entry->guide_entry[i].identifier)) + { + entry->u.int_value = entry->guide_entry[i].parameter; + entry->state = RESOLUTION_ENTRY_STATE_SPECIFIED; + break; + } + } + if (entry->state != RESOLUTION_ENTRY_STATE_SPECIFIED) + { + err = OPTIONRESOLUTION_ERROR_BADPARAM; + goto done; + } + must_resolve = TRUE; + break; + + default: + err = OPTIONRESOLTUION_ERROR_INTERNAL; + assert(0); + goto done; + } + + /* do a resolution step if necessary */ + if (must_resolve) + { + option_specification = lookup_in_specification(resolution->specification, entry->guide_entry); + err = resolve_single_param(option_specification, &entry->u.int_value, NULL, 0); + if (err) + goto done; + + /* did we not get a real value? */ + if (entry->u.int_value < 0) + { + err = OPTIONRESOLUTION_ERROR_PARAMNOTSPECIFIED; + goto done; + } + } + + err = OPTIONRESOLUTION_ERROR_SUCCESS; + +done: + return err; +} + + + +void option_resolution_close(option_resolution *resolution) +{ + pool_free_lib(resolution->pool); +} + + + +optreserr_t option_resolution_finish(option_resolution *resolution) +{ + int i; + optreserr_t err; + struct option_resolution_entry *entry; + const char *option_specification; + + for (i = 0; i < resolution->option_count; i++) + { + entry = &resolution->entries[i]; + + if (entry->state == RESOLUTION_ENTRY_STATE_UNSPECIFIED) + { + switch(entry->guide_entry->option_type) { + case OPTIONTYPE_INT: + case OPTIONTYPE_ENUM_BEGIN: + option_specification = lookup_in_specification(resolution->specification, entry->guide_entry); + assert(option_specification); + entry->u.int_value = -1; + err = resolve_single_param(option_specification, &entry->u.int_value, NULL, 0); + if (err) + return err; + break; + + case OPTIONTYPE_STRING: + entry->u.str_value = ""; + break; + + default: + assert(FALSE); + return OPTIONRESOLTUION_ERROR_INTERNAL; + } + entry->state = RESOLUTION_ENTRY_STATE_SPECIFIED; + } + } + return OPTIONRESOLUTION_ERROR_SUCCESS; +} + + + +static const struct option_resolution_entry *option_resolution_lookup_entry(option_resolution *resolution, int option_char) +{ + size_t i; + const struct option_resolution_entry *entry; + + for (i = 0; i < resolution->option_count; i++) + { + entry = &resolution->entries[i]; + + switch(entry->guide_entry->option_type) { + case OPTIONTYPE_INT: + case OPTIONTYPE_STRING: + case OPTIONTYPE_ENUM_BEGIN: + if (entry->guide_entry->parameter == option_char) + return entry; + break; + + default: + assert(FALSE); + return NULL; + } + } + return NULL; +} + + + +int option_resolution_lookup_int(option_resolution *resolution, int option_char) +{ + const struct option_resolution_entry *entry; + entry = option_resolution_lookup_entry(resolution, option_char); + return entry ? entry->u.int_value : -1; +} + + + +const char *option_resolution_lookup_string(option_resolution *resolution, int option_char) +{ + const struct option_resolution_entry *entry; + entry = option_resolution_lookup_entry(resolution, option_char); + return entry ? entry->u.str_value : NULL; +} + + + +const char *option_resolution_specification(option_resolution *resolution) +{ + return resolution->specification; +} + + + +const option_guide *option_resolution_find_option(option_resolution *resolution, int option_char) +{ + const struct option_resolution_entry *entry; + entry = option_resolution_lookup_entry(resolution, option_char); + return entry ? entry->guide_entry : NULL; +} + + + +const option_guide *option_resolution_index_option(option_resolution *resolution, int indx) +{ + if ((indx < 0) || (indx >= resolution->option_count)) + return NULL; + return resolution->entries[indx].guide_entry; +} + + + +int option_resolution_countoptions(const option_guide *guide, const char *specification) +{ + int option_count = 0; + + while(guide->option_type != OPTIONTYPE_END) + { + switch(guide->option_type) { + case OPTIONTYPE_INT: + case OPTIONTYPE_STRING: + case OPTIONTYPE_ENUM_BEGIN: + if (lookup_in_specification(specification, guide)) + option_count++; + break; + case OPTIONTYPE_ENUM_VALUE: + break; + default: + assert(FALSE); + return 0; + } + guide++; + } + return option_count; +} + + + +optreserr_t option_resolution_listranges(const char *specification, int option_char, + struct OptionRange *range, size_t range_count) +{ + assert(range_count > 0); + + /* clear out range */ + memset(range, -1, sizeof(*range) * range_count); + range_count--; + + specification = strchr(specification, option_char); + if (!specification) + { + return OPTIONRESOLUTION_ERROR_SYNTAX; + } + + return resolve_single_param(specification + 1, NULL, range, range_count); +} + + + +optreserr_t option_resolution_getdefault(const char *specification, int option_char, int *val) +{ + assert(val); + + /* clear out default */ + *val = -1; + + specification = strchr(specification, option_char); + if (!specification) + { + return OPTIONRESOLUTION_ERROR_SYNTAX; + } + + return resolve_single_param(specification + 1, val, NULL, 0); +} + + + +optreserr_t option_resolution_isvalidvalue(const char *specification, int option_char, int val) +{ + optreserr_t err; + struct OptionRange ranges[256]; + int i; + + err = option_resolution_listranges(specification, option_char, ranges, ARRAY_LENGTH(ranges)); + if (err) + return err; + + for (i = 0; (ranges[i].min >= 0) && (ranges[i].max >= 0); i++) + { + if ((ranges[i].min <= val) && (ranges[i].max >= val)) + return OPTIONRESOLUTION_ERROR_SUCCESS; + } + return OPTIONRESOLUTION_ERROR_PARAMOUTOFRANGE; +} + + + +int option_resolution_contains(const char *specification, int option_char) +{ + return strchr(specification, option_char) != NULL; +} + + + +const char *option_resolution_error_string(optreserr_t err) +{ + static const char *const errors[] = + { + "The operation completed successfully", /* OPTIONRESOLUTION_ERROR_SUCCESS */ + "Out of memory", /* OPTIONRESOLUTION_ERROR_OUTOFMEMORY */ + "Parameter out of range", /* OPTIONRESOLUTION_ERROR_PARAMOUTOFRANGE */ + "Parameter not specified", /* OPTIONRESOLUTION_ERROR_PARAMNOTSPECIFIED */ + "Unknown parameter", /* OPTIONRESOLUTION_ERROR_PARAMNOTFOUND */ + "Paramter specified multiple times", /* OPTIONRESOLUTION_ERROR_PARAMALREADYSPECIFIED */ + "Invalid parameter", /* OPTIONRESOLUTION_ERROR_BADPARAM */ + "Syntax error", /* OPTIONRESOLUTION_ERROR_SYNTAX */ + "Internal error" /* OPTIONRESOLTUION_ERROR_INTERNAL */ + }; + + if ((err < 0) || (err >= ARRAY_LENGTH(errors))) + return NULL; + return errors[err]; +} + diff --git a/src/lib/util/opresolv.h b/src/lib/util/opresolv.h new file mode 100644 index 00000000000..7048e8b1538 --- /dev/null +++ b/src/lib/util/opresolv.h @@ -0,0 +1,160 @@ +/**************************************************************************** + + opresolv.h + + Extensible ranged option resolution handling + + An extensible mechanism for handling options is a major need in MESS and + Imgtool. Unfortunately, since we are using straight C for everything, it + can be hard and awkward to create non-arcane mechanisms for representing + these options. + + In this system, we have the following concepts: + 1. An "option specification"; a string that represents what options are + available, their defaults, and their allowed ranges. Here is an + example: + + Examples: + "H[1]-2;T[35]/40/80;S[18]" + Allow 1-2 heads; 35, 40 or 80 tracks, and 18 sectors, + defaulting to 1 heads and 35 tracks. + + "N'Simon''s desk'" + Simon's desk (strings are not subject to range checking) + + 2. An "option guide"; a struct that provides information about what the + various members of the option specification mean (i.e. - H=heads) + + 3. An "option resolution"; an object that represents a set of interpreted + options. At this stage, the option bid has been processed and it is + guaranteed that all options reside in their expected ranges. + + An option_resolution object is created based on an option guide and an + option specification. It is then possible to specify individual parameters + to the option_resolution object. Argument checks occur at this time. When + one is all done, you can then query the object for any given value. + +****************************************************************************/ + +#ifndef __OPRESOLV_H__ +#define __OPRESOLV_H__ + +#include + + +/*************************************************************************** + + Type definitions + +***************************************************************************/ + +enum option_type +{ + OPTIONTYPE_END, + OPTIONTYPE_INT, + OPTIONTYPE_STRING, + OPTIONTYPE_ENUM_BEGIN, + OPTIONTYPE_ENUM_VALUE +}; + +typedef struct _option_guide option_guide; +struct _option_guide +{ + enum option_type option_type; + int parameter; + const char *identifier; + const char *display_name; +}; + +#define OPTION_GUIDE_START(option_guide_) \ + const option_guide option_guide_[] = \ + { \ + +#define OPTION_GUIDE_END \ + { OPTIONTYPE_END } \ + }; \ + +#define OPTION_GUIDE_EXTERN(option_guide_) \ + extern const option_guide option_guide_[] \ + +#define OPTION_INT(option_char, identifier, display_name) \ + { OPTIONTYPE_INT, (option_char), (identifier), (display_name) }, \ + +#define OPTION_STRING(option_char, identifier, display_name) \ + { OPTIONTYPE_STRING, (option_char), (identifier), (display_name) }, \ + +#define OPTION_ENUM_START(option_char, identifier, display_name) \ + { OPTIONTYPE_ENUM_BEGIN, (option_char), (identifier), (display_name) }, \ + +#define OPTION_ENUM(value, identifier, display_name) \ + { OPTIONTYPE_ENUM_VALUE, (value), (identifier), (display_name) }, \ + +#define OPTION_ENUM_END + + +typedef enum +{ + OPTIONRESOLUTION_ERROR_SUCCESS, + OPTIONRESOLUTION_ERROR_OUTOFMEMORY, + OPTIONRESOLUTION_ERROR_PARAMOUTOFRANGE, + OPTIONRESOLUTION_ERROR_PARAMNOTSPECIFIED, + OPTIONRESOLUTION_ERROR_PARAMNOTFOUND, + OPTIONRESOLUTION_ERROR_PARAMALREADYSPECIFIED, + OPTIONRESOLUTION_ERROR_BADPARAM, + OPTIONRESOLUTION_ERROR_SYNTAX, + OPTIONRESOLTUION_ERROR_INTERNAL +} optreserr_t; + + + +struct OptionResolutionError +{ + const option_guide *option; + optreserr_t error; +}; + + + +typedef struct _option_resolution option_resolution; + +struct OptionRange +{ + int min, max; +}; + + + +/*************************************************************************** + + Prototypes + +***************************************************************************/ + +/* processing options with option_resolution objects */ +option_resolution *option_resolution_create(const option_guide *guide, const char *specification); +optreserr_t option_resolution_add_param(option_resolution *resolution, const char *param, const char *value); +optreserr_t option_resolution_finish(option_resolution *resolution); +void option_resolution_close(option_resolution *resolution); +int option_resolution_lookup_int(option_resolution *resolution, int option_char); +const char *option_resolution_lookup_string(option_resolution *resolution, int option_char); + +/* option resolution accessors */ +const char *option_resolution_specification(option_resolution *resolution); +const option_guide *option_resolution_find_option(option_resolution *resolution, int option_char); +const option_guide *option_resolution_index_option(option_resolution *resolution, int indx); + +/* processing option guides */ +int option_resolution_countoptions(const option_guide *guide, const char *specification); + +/* processing option specifications */ +optreserr_t option_resolution_listranges(const char *specification, int option_char, + struct OptionRange *range, size_t range_count); +optreserr_t option_resolution_getdefault(const char *specification, int option_char, int *val); +optreserr_t option_resolution_isvalidvalue(const char *specification, int option_char, int val); +int option_resolution_contains(const char *specification, int option_char); + +/* misc */ +const char *option_resolution_error_string(optreserr_t err); + +#endif /* __OPRESOLV_H__ */ + diff --git a/src/lib/util/zippath.c b/src/lib/util/zippath.c new file mode 100644 index 00000000000..e46f8710d6e --- /dev/null +++ b/src/lib/util/zippath.c @@ -0,0 +1,859 @@ +/*************************************************************************** + + zippath.c + + File/directory/path operations that work with ZIP files + +***************************************************************************/ + +#include +#include +#include "zippath.h" +#include "unzip.h" +#include "corestr.h" +#include "osdcore.h" + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +typedef struct _zippath_returned_directory zippath_returned_directory; +struct _zippath_returned_directory +{ + zippath_returned_directory *next; + char name[1]; +}; + + + +struct _zippath_directory +{ + /* common */ + unsigned int returned_parent : 1; + osd_directory_entry returned_entry; + + /* specific to normal directories */ + osd_directory *directory; + + /* specific to ZIP directories */ + unsigned int called_zip_first : 1; + zip_file *zipfile; + astring *zipprefix; + zippath_returned_directory *returned_dirlist; +}; + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +static const zip_file_header *zippath_find_sub_path(zip_file *zipfile, const char *subpath, osd_dir_entry_type *type); +static int is_zip_file(const char *path); +static int is_zip_file_separator(char c); + + +/*************************************************************************** + PATH OPERATIONS +***************************************************************************/ + +//============================================================ +// is_path_separator +//============================================================ + +int is_path_separator(char c) +{ + return (c == '/') || (c == '\\'); +} + +/*------------------------------------------------- + parse_parent_path - parses out the parent path +-------------------------------------------------*/ + +static void parse_parent_path(const char *path, int *beginpos, int *endpos) +{ + int length = strlen(path); + int pos; + + /* skip over trailing path separators */ + pos = length - 1; + while((pos > 0) && is_path_separator(path[pos])) + pos--; + + /* return endpos */ + if (endpos != NULL) + *endpos = pos; + + /* now skip until we find a path separator */ + while((pos >= 0) && !is_path_separator(path[pos])) + pos--; + + /* return beginpos */ + if (beginpos != NULL) + *beginpos = pos; +} + + + +/*------------------------------------------------- + zippath_parent - retrieves the parent directory +-------------------------------------------------*/ + +astring *zippath_parent(astring *dst, const char *path) +{ + int pos; + parse_parent_path(path, &pos, NULL); + + /* return the result */ + return (pos >= 0) ? astring_cpych(dst, path, pos + 1) : astring_cpyc(dst, ""); +} + + + +/*------------------------------------------------- + zippath_parent_basename - retrieves the parent + directory basename +-------------------------------------------------*/ + +astring *zippath_parent_basename(astring *dst, const char *path) +{ + int beginpos, endpos; + parse_parent_path(path, &beginpos, &endpos); + + return astring_cpych(dst, path + beginpos + 1, endpos - beginpos); +} + + + +/*------------------------------------------------- + zippath_combine - combines two paths +-------------------------------------------------*/ + +astring *zippath_combine(astring *dst, const char *path1, const char *path2) +{ + astring *result; + + if (!strcmp(path2, ".")) + { + result = astring_cpyc(dst, path1); + } + else if (!strcmp(path2, "..")) + { + result = zippath_parent(dst, path1); + } + else if (osd_is_absolute_path(path2)) + { + result = astring_cpyc(dst, path2); + } + else if ((path1[0] != '\0') && !is_path_separator(path1[strlen(path1) - 1])) + { + result = astring_assemble_3(dst, path1, PATH_SEPARATOR, path2); + } + else + { + result = astring_assemble_2(dst, path1, path2); + } + return result; +} + + + +/*************************************************************************** + FILE OPERATIONS +***************************************************************************/ + +/*------------------------------------------------- + file_error_from_zip_error - translates a + file_error to a zip_error +-------------------------------------------------*/ + +static file_error file_error_from_zip_error(zip_error ziperr) +{ + file_error filerr; + switch(ziperr) + { + case ZIPERR_NONE: + filerr = FILERR_NONE; + break; + case ZIPERR_OUT_OF_MEMORY: + filerr = FILERR_OUT_OF_MEMORY; + break; + case ZIPERR_BAD_SIGNATURE: + case ZIPERR_DECOMPRESS_ERROR: + case ZIPERR_FILE_TRUNCATED: + case ZIPERR_FILE_CORRUPT: + case ZIPERR_UNSUPPORTED: + case ZIPERR_FILE_ERROR: + filerr = FILERR_INVALID_DATA; + break; + case ZIPERR_BUFFER_TOO_SMALL: + default: + filerr = FILERR_FAILURE; + break; + } + return filerr; +} + + +/*------------------------------------------------- + create_core_file_from_zip - creates a core_file + from a zip file entry +-------------------------------------------------*/ + +static file_error create_core_file_from_zip(zip_file *zip, const zip_file_header *header, core_file **file) +{ + file_error filerr; + zip_error ziperr; + void *ptr; + + ptr = malloc(header->uncompressed_length); + if (ptr == NULL) + { + filerr = FILERR_OUT_OF_MEMORY; + goto done; + } + + ziperr = zip_file_decompress(zip, ptr, header->uncompressed_length); + if (ziperr != ZIPERR_NONE) + { + filerr = file_error_from_zip_error(ziperr); + goto done; + } + + filerr = core_fopen_ram_copy(ptr, header->uncompressed_length, OPEN_FLAG_READ, file); + if (filerr != FILERR_NONE) + goto done; + +done: + if (ptr != NULL) + free(ptr); + return filerr; +} + + +/*------------------------------------------------- + zippath_fopen - opens a zip path file +-------------------------------------------------*/ + +file_error zippath_fopen(const char *filename, UINT32 openflags, core_file **file, astring *revised_path) +{ + file_error filerr = FILERR_NOT_FOUND; + zip_error ziperr; + zip_file *zip = NULL; + const zip_file_header *header; + osd_dir_entry_type entry_type; + astring *mainpath; + astring *subpath; + astring *temp; + astring *temp2; + char *alloc_fullpath = NULL; + int len; + + /* first, set up the two types of paths */ + mainpath = astring_cpyc(astring_alloc(), filename); + subpath = astring_alloc(); + temp = astring_alloc(); + temp2 = astring_alloc(); + *file = NULL; + + /* loop through */ + while((*file == NULL) && (astring_len(mainpath) > 0) + && ((openflags == OPEN_FLAG_READ) || (astring_len(subpath) == 0))) + { + /* is the mainpath a ZIP path? */ + if (is_zip_file(astring_c(mainpath))) + { + /* this file might be a zip file - lets take a look */ + ziperr = zip_file_open(astring_c(mainpath), &zip); + if (ziperr == ZIPERR_NONE) + { + /* it is a zip file - error if we're not opening for reading */ + if (openflags != OPEN_FLAG_READ) + { + filerr = FILERR_ACCESS_DENIED; + goto done; + } + + if (astring_len(subpath) > 0) + header = zippath_find_sub_path(zip, astring_c(subpath), &entry_type); + else + header = zip_file_first_file(zip); + + if (header == NULL) + { + filerr = FILERR_NOT_FOUND; + goto done; + } + + /* attempt to read the file */ + filerr = create_core_file_from_zip(zip, header, file); + if (filerr != FILERR_NONE) + goto done; + + /* update subpath, if appropriate */ + if (astring_len(subpath) == 0) + astring_cpyc(subpath, header->filename); + + /* we're done */ + goto done; + } + } + + if (astring_len(subpath) == 0) + filerr = core_fopen(filename, openflags, file); + else + filerr = FILERR_NOT_FOUND; + + /* if we errored, then go up a directory */ + if (filerr != FILERR_NONE) + { + /* go up a directory */ + zippath_parent(temp, astring_c(mainpath)); + + /* append to the sub path */ + if (astring_len(subpath) > 0) + { + astring_assemble_3(temp2, astring_c(mainpath) + astring_len(temp), PATH_SEPARATOR, astring_c(subpath)); + astring_cpy(subpath, temp2); + } + else + { + astring_cpyc(subpath, astring_c(mainpath) + astring_len(temp)); + } + + /* get the new main path, truncating path separators */ + len = astring_len(temp); + while((len > 0) && is_zip_file_separator(astring_c(temp)[len - 1])) + len--; + astring_cpych(mainpath, astring_c(temp), len); + } + } + +done: + /* store the revised path if appropriate */ + if (revised_path != NULL) + { + astring_cpyc(revised_path, ""); + if (filerr == FILERR_NONE) + { + /* cannonicalize mainpath */ + filerr = osd_get_full_path(&alloc_fullpath, astring_c(mainpath)); + if (filerr == FILERR_NONE) + { + if (astring_len(subpath) > 0) + astring_assemble_3(revised_path, alloc_fullpath, PATH_SEPARATOR, astring_c(subpath)); + else + astring_cpyc(revised_path, alloc_fullpath); + } + } + } + + if (zip != NULL) + zip_file_close(zip); + if (mainpath != NULL) + astring_free(mainpath); + if (subpath != NULL) + astring_free(subpath); + if (temp != NULL) + astring_free(temp); + if (temp2 != NULL) + astring_free(temp2); + if (alloc_fullpath != NULL) + free(alloc_fullpath); + return filerr; +} + + +/*************************************************************************** + DIRECTORY OPERATIONS +***************************************************************************/ + +/*------------------------------------------------- + is_root - tests to see if this path is the root +-------------------------------------------------*/ + +static int is_root(const char *path) +{ + int i = 0; + + /* skip drive letter */ + if (isalpha(path[i]) && (path[i + 1] == ':')) + i += 2; + + /* skip path separators */ + while (is_path_separator(path[i])) + i++; + + return path[i] == '\0'; +} + + + +/*------------------------------------------------- + is_zip_file - tests to see if this file is a + ZIP file +-------------------------------------------------*/ + +static int is_zip_file(const char *path) +{ + const char *s = strrchr(path, '.'); + return (s != NULL) && !core_stricmp(s, ".zip"); +} + + + +/*------------------------------------------------- + is_zip_file_separator - returns whether this + character is a path separator within a ZIP file +-------------------------------------------------*/ + +static int is_zip_file_separator(char c) +{ + return (c == '/') || (c == '\\'); +} + + + +/*------------------------------------------------- + is_zip_path_separator - returns whether this + character is a path separator within a ZIP path +-------------------------------------------------*/ + +static int is_zip_path_separator(char c) +{ + return is_zip_file_separator(c) || is_path_separator(c); +} + + + +/*------------------------------------------------- + next_path_char - lexes out the next path + character, normalizing separators as '/' +-------------------------------------------------*/ + +static char next_path_char(const char *s, int *pos) +{ + char result; + + /* skip over any initial separators */ + if (*pos == 0) + { + while(is_zip_file_separator(s[*pos])) + (*pos)++; + } + + /* are we at a path separator? */ + if (is_zip_file_separator(s[*pos])) + { + /* skip over path separators */ + while(is_zip_file_separator(s[*pos])) + (*pos)++; + + /* normalize as '/' */ + result = '/'; + } + else if (s[*pos] != '\0') + { + /* return character */ + result = tolower(s[(*pos)++]); + } + else + { + /* return NUL */ + result = '\0'; + } + return result; +} + + + + +/*------------------------------------------------- + zippath_find_sub_path - attempts to identify the + type of a sub path in a zip file +-------------------------------------------------*/ + +static const zip_file_header *zippath_find_sub_path(zip_file *zipfile, const char *subpath, osd_dir_entry_type *type) +{ + int i, j; + char c1, c2, last_char; + const zip_file_header *header; + + for (header = zip_file_first_file(zipfile); header != NULL; header = zip_file_next_file(zipfile)) + { + /* special case */ + if (subpath == NULL) + { + if (type != NULL) + *type = ENTTYPE_FILE; + return header; + } + + i = 0; + j = 0; + last_char = '/'; + while(((c1 = next_path_char(header->filename, &i)) == (c2 = next_path_char(subpath, &j))) && + ( c1 != '\0' && c2 != '\0' )) + last_char = c2; + + + if (c2 == '\0') + { + if (c1 == '\0') + { + if (type != NULL) + *type = ENTTYPE_FILE; + return header; + } + else if ((last_char == '/') || (c1 == '/')) + { + if (type != NULL) + *type = ENTTYPE_DIR; + return header; + } + } + } + + if (type != NULL) + *type = ENTTYPE_NONE; + return NULL; +} + + + +/*------------------------------------------------- + zippath_resolve - separates a ZIP path out into + true path and ZIP entry components +-------------------------------------------------*/ + +static file_error zippath_resolve(const char *path, osd_dir_entry_type *entry_type, + zip_file **zipfile, astring *newpath) +{ + file_error err; + osd_directory_entry *current_entry = NULL; + osd_dir_entry_type current_entry_type; + astring *apath = astring_cpyc(astring_alloc(), path); + astring *apath_trimmed = astring_alloc(); + astring *parent = NULL; + int went_up = FALSE; + int i; + + /* be conservative */ + *entry_type = ENTTYPE_NONE; + *zipfile = NULL; + + do + { + /* trim the path of trailing path separators */ + i = astring_len(apath); + while((i > 1) && is_path_separator(astring_c(apath)[i - 1])) + i--; + apath_trimmed = astring_cpysubstr(apath_trimmed, apath, 0, i); + + /* stat the path */ + current_entry = osd_stat(astring_c(apath_trimmed)); + + /* did we find anything? */ + if (current_entry != NULL) + { + /* get the entry type and free the stat entry */ + current_entry_type = current_entry->type; + free(current_entry); + current_entry = NULL; + } + else + { + /* if we have not found the file or directory, go up */ + current_entry_type = ENTTYPE_NONE; + went_up = TRUE; + parent = zippath_parent(astring_alloc(), astring_c(apath)); + astring_free(apath); + apath = parent; + } + } + while((current_entry_type == ENTTYPE_NONE) && (apath != NULL) && !is_root(astring_c(apath))); + + /* if we did not find anything, then error out */ + if (current_entry_type == ENTTYPE_NONE) + { + err = FILERR_NOT_FOUND; + goto done; + } + + /* is this file a ZIP file? */ + if ((current_entry_type == ENTTYPE_FILE) && is_zip_file(astring_c(apath_trimmed)) + && (zip_file_open(astring_c(apath_trimmed), zipfile) == ZIPERR_NONE)) + { + i = strlen(path + astring_len(apath)); + while((i > 0) && is_zip_path_separator(path[astring_len(apath) + i - 1])) + i--; + astring_cpych(newpath, path + astring_len(apath), i); + + /* this was a true ZIP path - attempt to identify the type of path */ + zippath_find_sub_path(*zipfile, astring_c(newpath), ¤t_entry_type); + if (current_entry_type == ENTTYPE_NONE) + { + err = FILERR_NOT_FOUND; + goto done; + } + } + else + { + /* this was a normal path */ + if (went_up) + { + err = FILERR_NOT_FOUND; + goto done; + } + astring_cpyc(newpath, path); + } + + /* success! */ + *entry_type = current_entry_type; + err = FILERR_NONE; + +done: + if (apath != NULL) + astring_free(apath); + if (apath_trimmed != NULL) + astring_free(apath_trimmed); + return err; +} + + +/*------------------------------------------------- + zippath_opendir - opens a directory +-------------------------------------------------*/ + +file_error zippath_opendir(const char *path, zippath_directory **directory) +{ + file_error err; + osd_dir_entry_type entry_type; + astring *newpath = astring_alloc(); + zippath_directory *result; + + /* allocate a directory */ + result = (zippath_directory *) malloc(sizeof(*result)); + if (result == NULL) + { + err = FILERR_OUT_OF_MEMORY; + goto done; + } + memset(result, 0, sizeof(*result)); + + /* resolve the path */ + err = zippath_resolve(path, &entry_type, &result->zipfile, newpath); + if (err != FILERR_NONE) + goto done; + + /* we have to be a directory */ + if (entry_type != ENTTYPE_DIR) + { + err = FILERR_NOT_FOUND; + goto done; + } + + /* was the result a ZIP? */ + if (result->zipfile != NULL) + { + result->zipprefix = newpath; + newpath = NULL; + } + else + { + /* a conventional directory */ + result->directory = osd_opendir(path); + if (result->directory == NULL) + { + err = FILERR_FAILURE; + goto done; + } + + /* is this path the root? if so, pretend we've already returned the parent */ + if (is_root(path)) + result->returned_parent = TRUE; + } + +done: + if (((directory == NULL) || (err != FILERR_NONE)) && (result != NULL)) + { + zippath_closedir(result); + result = NULL; + } + if (newpath != NULL) + { + astring_free(newpath); + newpath = NULL; + } + if (directory != NULL) + *directory = result; + return err; +} + + +/*------------------------------------------------- + zippath_closedir - closes a directory +-------------------------------------------------*/ + +void zippath_closedir(zippath_directory *directory) +{ + zippath_returned_directory *dirlist; + + if (directory->directory != NULL) + osd_closedir(directory->directory); + + if (directory->zipfile != NULL) + zip_file_close(directory->zipfile); + + if (directory->zipprefix != NULL) + astring_free(directory->zipprefix); + + while(directory->returned_dirlist != NULL) + { + dirlist = directory->returned_dirlist; + directory->returned_dirlist = directory->returned_dirlist->next; + free(dirlist); + } + + free(directory); +} + + +/*------------------------------------------------- + get_relative_path - checks to see if a specified + header is in the zippath_directory, and if so + returns the relative path +-------------------------------------------------*/ + +static const char *get_relative_path(zippath_directory *directory, const zip_file_header *header) +{ + const char *result = NULL; + int len = astring_len(directory->zipprefix); + + if ((len <= strlen(header->filename)) + && !strncmp(astring_c(directory->zipprefix), header->filename, len)) + { + result = &header->filename[len]; + while(is_zip_file_separator(*result)) + result++; + } + + return result; +} + + +/*------------------------------------------------- + zippath_readdir - reads a directory +-------------------------------------------------*/ + +const osd_directory_entry *zippath_readdir(zippath_directory *directory) +{ + const osd_directory_entry *result = NULL; + const zip_file_header *header; + const char *relpath; + const char *separator; + const char *s; + zippath_returned_directory *rdent; + + if (!directory->returned_parent) + { + /* first thing's first - return parent directory */ + directory->returned_parent = TRUE; + memset(&directory->returned_entry, 0, sizeof(directory->returned_entry)); + directory->returned_entry.name = ".."; + directory->returned_entry.type = ENTTYPE_DIR; + result = &directory->returned_entry; + } + else if (directory->directory != NULL) + { + /* a normal directory read */ + do + { + result = osd_readdir(directory->directory); + } + while((result != NULL) && (!strcmp(result->name, ".") || !strcmp(result->name, ".."))); + + /* special case - is this entry a ZIP file? if so we need to return it as a "directory" */ + if ((result != NULL) && is_zip_file(result->name)) + { + /* copy; but change the entry type */ + directory->returned_entry = *result; + directory->returned_entry.type = ENTTYPE_DIR; + result = &directory->returned_entry; + } + } + else if (directory->zipfile != NULL) + { + do + { + /* a zip file read */ + do + { + if (!directory->called_zip_first) + header = zip_file_first_file(directory->zipfile); + else + header = zip_file_next_file(directory->zipfile); + directory->called_zip_first = TRUE; + relpath = NULL; + } + while((header != NULL) && ((relpath = get_relative_path(directory, header)) == NULL)); + + if (relpath != NULL) + { + /* we've found a ZIP entry; but this may be an entry deep within the target directory */ + for (s = relpath; *s && !is_zip_file_separator(*s); s++) + ; + separator = *s ? s : NULL; + + if (separator != NULL) + { + /* a nested entry; loop through returned_dirlist to see if we've returned the parent directory */ + for (rdent = directory->returned_dirlist; rdent != NULL; rdent = rdent->next) + { + if (!core_strnicmp(rdent->name, relpath, separator - relpath)) + break; + } + + if (rdent == NULL) + { + /* we've found a new directory; add this to returned_dirlist */ + rdent = (zippath_returned_directory *)malloc(sizeof(*rdent) + (separator - relpath)); + rdent->next = directory->returned_dirlist; + memcpy(rdent->name, relpath, (separator - relpath) * sizeof(rdent->name[0])); + rdent->name[separator - relpath] = '\0'; + directory->returned_dirlist = rdent; + + /* ...and return it */ + memset(&directory->returned_entry, 0, sizeof(directory->returned_entry)); + directory->returned_entry.name = rdent->name; + directory->returned_entry.type = ENTTYPE_DIR; + result = &directory->returned_entry; + } + } + else + { + /* a real file */ + memset(&directory->returned_entry, 0, sizeof(directory->returned_entry)); + directory->returned_entry.name = relpath; + directory->returned_entry.type = ENTTYPE_FILE; + directory->returned_entry.size = header->uncompressed_length; + result = &directory->returned_entry; + } + } + } + while((relpath != NULL) && (result == NULL)); + } + return result; +} + + + +/*------------------------------------------------- + zippath_is_zip - returns TRUE if this path is + a ZIP path or FALSE if not +-------------------------------------------------*/ + +int zippath_is_zip(zippath_directory *directory) +{ + return directory->zipfile != NULL; +} diff --git a/src/lib/util/zippath.h b/src/lib/util/zippath.h new file mode 100644 index 00000000000..2411ad392a3 --- /dev/null +++ b/src/lib/util/zippath.h @@ -0,0 +1,66 @@ +/*************************************************************************** + + zippath.h + + File/directory/path operations that work with ZIP files + +***************************************************************************/ + +#pragma once + +#ifndef __ZIPPATH_H__ +#define __ZIPPATH_H__ + +#include "corefile.h" +#include "astring.h" +#include "unzip.h" +#include "astring.h" + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +typedef struct _zippath_directory zippath_directory; + + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +/* ----- path operations ----- */ + +/* retrieves the parent directory */ +astring *zippath_parent(astring *dst, const char *path); + +/* retrieves the parent directory basename */ +astring *zippath_parent_basename(astring *dst, const char *path); + +/* combines two paths */ +astring *zippath_combine(astring *dst, const char *path1, const char *path2); + + +/* ----- file operations ----- */ + +/* opens a zip path file */ +file_error zippath_fopen(const char *filename, UINT32 openflags, core_file **file, astring *revised_path); + + +/* ----- directory operations ----- */ + +/* opens a directory */ +file_error zippath_opendir(const char *path, zippath_directory **directory); + +/* closes a directory */ +void zippath_closedir(zippath_directory *directory); + +/* reads a directory entry */ +const osd_directory_entry *zippath_readdir(zippath_directory *directory); + +/* returns TRUE if this path is a ZIP path or FALSE if not */ +int zippath_is_zip(zippath_directory *directory); + + + +#endif /* __ZIPPATH_H__ */ diff --git a/src/osd/osdcore.h b/src/osd/osdcore.h index 2ac0ad1d87d..872fc80bb49 100644 --- a/src/osd/osdcore.h +++ b/src/osd/osdcore.h @@ -828,7 +828,6 @@ void osd_break_into_debugger(const char *message); char *osd_get_clipboard_text(void); -#ifdef MESS /*************************************************************************** DIRECTORY INTERFACES ***************************************************************************/ @@ -885,7 +884,6 @@ file_error osd_get_full_path(char **dst, const char *path); -----------------------------------------------------------------------------*/ const char *osd_get_volume_name(int idx); -#endif #ifdef __cplusplus } diff --git a/src/osd/sdl/sdlos_macosx.c b/src/osd/sdl/sdlos_macosx.c index b59e3a2376e..baa8ac2d167 100644 --- a/src/osd/sdl/sdlos_macosx.c +++ b/src/osd/sdl/sdlos_macosx.c @@ -306,12 +306,6 @@ char *osd_get_clipboard_text(void) return result; } -//============================================================ -// MESS specific code below -//============================================================ - -#ifdef MESS - //============================================================ // osd_stat //============================================================ @@ -388,5 +382,3 @@ file_error osd_get_full_path(char **dst, const char *path) return err; } - -#endif diff --git a/src/osd/sdl/sdlos_unix.c b/src/osd/sdl/sdlos_unix.c index 6e79fb365bf..8d487c0c33a 100644 --- a/src/osd/sdl/sdlos_unix.c +++ b/src/osd/sdl/sdlos_unix.c @@ -226,12 +226,6 @@ char *osd_get_clipboard_text(void) } #endif -//============================================================ -// MESS specific code below -//============================================================ - -#ifdef MESS - //============================================================ // osd_stat //============================================================ @@ -308,5 +302,3 @@ file_error osd_get_full_path(char **dst, const char *path) return err; } - -#endif diff --git a/src/osd/sdl/sdlos_win32.c b/src/osd/sdl/sdlos_win32.c index 9aac9d86607..31be832703b 100644 --- a/src/osd/sdl/sdlos_win32.c +++ b/src/osd/sdl/sdlos_win32.c @@ -273,10 +273,6 @@ int osd_setenv(const char *name, const char *value, int overwrite) return result; } -//============================================================ -// MESS specific code below -//============================================================ - //============================================================ // get_clipboard_text_by_format //============================================================ @@ -358,8 +354,6 @@ char *osd_get_clipboard_text(void) return result; } -#ifdef MESS - //============================================================ // astring_from_utf8 //============================================================ @@ -552,5 +546,3 @@ done: osd_free(t_path); return err; } - -#endif -- cgit v1.2.3