From 848bf53c3d7e1093f262a9b8826e662dfb5fa473 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 16 Jun 2010 18:04:30 +0000 Subject: [PATCH] - 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/lib/lib.mak | 2 + src/{emu => lib/util}/opresolv.c | 24 +- src/{emu => lib/util}/opresolv.h | 0 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 - 11 files changed, 933 insertions(+), 51 deletions(-) rename src/{emu => lib/util}/opresolv.c (96%) rename src/{emu => lib/util}/opresolv.h (100%) 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/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/emu/opresolv.c b/src/lib/util/opresolv.c similarity index 96% rename from src/emu/opresolv.c rename to src/lib/util/opresolv.c index aa63396804e..db9e81a3536 100644 --- a/src/emu/opresolv.c +++ b/src/lib/util/opresolv.c @@ -12,8 +12,8 @@ #include #include "pool.h" +#include "corestr.h" #include "opresolv.h" -#include "emu.h" enum resolution_entry_state { @@ -40,18 +40,6 @@ struct _option_resolution 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) { @@ -72,7 +60,6 @@ static optreserr_t resolve_single_param(const char *specification, int *param_va /* range specifier */ if (flags & (FLAG_IN_RANGE|FLAG_IN_DEFAULT)) { - syntaxerror(NULL); return OPTIONRESOLUTION_ERROR_SYNTAX; } flags |= FLAG_IN_RANGE; @@ -93,7 +80,6 @@ static optreserr_t resolve_single_param(const char *specification, int *param_va /* begin default value */ if (flags & (FLAG_IN_DEFAULT|FLAG_DEFAULT_SPECIFIED)) { - syntaxerror(NULL); return OPTIONRESOLUTION_ERROR_SYNTAX; } flags |= FLAG_IN_DEFAULT; @@ -104,7 +90,6 @@ static optreserr_t resolve_single_param(const char *specification, int *param_va /* end default value */ if ((flags & FLAG_IN_DEFAULT) == 0) { - syntaxerror(NULL); return OPTIONRESOLUTION_ERROR_SYNTAX; } flags &= ~FLAG_IN_DEFAULT; @@ -119,7 +104,6 @@ static optreserr_t resolve_single_param(const char *specification, int *param_va /* value separator */ if (flags & (FLAG_IN_DEFAULT|FLAG_IN_RANGE)) { - syntaxerror(NULL); return OPTIONRESOLUTION_ERROR_SYNTAX; } s++; @@ -174,7 +158,6 @@ static optreserr_t resolve_single_param(const char *specification, int *param_va } else { - syntaxerror(NULL); return OPTIONRESOLUTION_ERROR_SYNTAX; } } @@ -182,7 +165,6 @@ static optreserr_t resolve_single_param(const char *specification, int *param_va /* we can't have zero length guidelines strings */ if (s == specification) { - syntaxerror(NULL); return OPTIONRESOLUTION_ERROR_SYNTAX; } @@ -308,7 +290,7 @@ optreserr_t option_resolution_add_param(option_resolution *resolution, const cha 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)) + if (!core_stricmp(value, entry->guide_entry[i].identifier)) { entry->u.int_value = entry->guide_entry[i].parameter; entry->state = RESOLUTION_ENTRY_STATE_SPECIFIED; @@ -508,7 +490,6 @@ optreserr_t option_resolution_listranges(const char *specification, int option_c specification = strchr(specification, option_char); if (!specification) { - syntaxerror(NULL); return OPTIONRESOLUTION_ERROR_SYNTAX; } @@ -527,7 +508,6 @@ optreserr_t option_resolution_getdefault(const char *specification, int option_c specification = strchr(specification, option_char); if (!specification) { - syntaxerror(NULL); return OPTIONRESOLUTION_ERROR_SYNTAX; } diff --git a/src/emu/opresolv.h b/src/lib/util/opresolv.h similarity index 100% rename from src/emu/opresolv.h rename to src/lib/util/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