diff options
author | 2016-03-18 22:41:17 +0100 | |
---|---|---|
committer | 2016-03-18 22:41:17 +0100 | |
commit | e39daaf5bdcf21d64abf239e1133963643dc6df1 (patch) | |
tree | 1f1b5f333e84bf056ce82c27bebdbad933f26c0d /src/lib/util/zippath.cpp | |
parent | 421656e108e7091ee9e1b14c84f0a3f6efc2ad2e (diff) | |
parent | b79020559ea3617b2d6bd4c92041d314045e2938 (diff) |
Merge remote-tracking branch 'refs/remotes/mamedev/master'
Diffstat (limited to 'src/lib/util/zippath.cpp')
-rw-r--r-- | src/lib/util/zippath.cpp | 341 |
1 files changed, 146 insertions, 195 deletions
diff --git a/src/lib/util/zippath.cpp b/src/lib/util/zippath.cpp index 18e2031dcdd..edeecf80c47 100644 --- a/src/lib/util/zippath.cpp +++ b/src/lib/util/zippath.cpp @@ -8,15 +8,19 @@ ***************************************************************************/ -#include <ctype.h> -#include <stdlib.h> -#include <new> -#include <assert.h> #include "zippath.h" #include "unzip.h" #include "corestr.h" #include "osdcore.h" +#include <stdlib.h> + +#include <cassert> +#include <cctype> +#include <new> + + +namespace util { /*************************************************************************** TYPE DEFINITIONS @@ -66,7 +70,7 @@ public: /** @brief true to called zip first. */ bool called_zip_first; /** @brief The zipfile. */ - zip_file::ptr zipfile; + archive_file::ptr zipfile; /** @brief The zipprefix. */ std::string zipprefix; /** @brief The returned dirlist. */ @@ -78,10 +82,10 @@ public: FUNCTION PROTOTYPES ***************************************************************************/ -static const zip_file::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); -static int is_7z_file(const char *path); +static int zippath_find_sub_path(archive_file &zipfile, std::string const &subpath, osd_dir_entry_type &type); +static bool is_zip_file(std::string const &path); +static bool is_zip_file_separator(char c); +static bool is_7z_file(std::string const &path); /*************************************************************************** @@ -148,29 +152,15 @@ static void parse_parent_path(const char *path, int *beginpos, int *endpos) zippath_parent - retrieves the parent directory -------------------------------------------------*/ -/** - * @fn std::string &zippath_parent(std::string &dst, const char *path) - * - * @brief Zippath parent. - * - * @param [in,out] dst Destination for the. - * @param path Full pathname of the file. - * - * @return A std::string& - */ - std::string &zippath_parent(std::string &dst, const char *path) { int pos; parse_parent_path(path, &pos, nullptr); - /* return the result */ - if (pos >= 0) { + if (pos >= 0) dst.assign(path, pos + 1); - } - else { + else dst.clear(); - } return dst; } @@ -255,7 +245,7 @@ std::string &zippath_combine(std::string &dst, const char *path1, const char *pa -------------------------------------------------*/ /** - * @fn static osd_file::error file_error_from_zip_error(zip_file::error ziperr) + * @fn static osd_file::error file_error_from_zip_error(archive_file::error ziperr) * * @brief File error from zip error. * @@ -264,26 +254,26 @@ std::string &zippath_combine(std::string &dst, const char *path1, const char *pa * @return A osd_file::error. */ -static osd_file::error file_error_from_zip_error(zip_file::error ziperr) +static osd_file::error file_error_from_zip_error(archive_file::error ziperr) { osd_file::error filerr; switch(ziperr) { - case zip_file::error::NONE: + case archive_file::error::NONE: filerr = osd_file::error::NONE; break; - case zip_file::error::OUT_OF_MEMORY: + case archive_file::error::OUT_OF_MEMORY: filerr = osd_file::error::OUT_OF_MEMORY; break; - case zip_file::error::BAD_SIGNATURE: - case zip_file::error::DECOMPRESS_ERROR: - case zip_file::error::FILE_TRUNCATED: - case zip_file::error::FILE_CORRUPT: - case zip_file::error::UNSUPPORTED: - case zip_file::error::FILE_ERROR: + case archive_file::error::BAD_SIGNATURE: + case archive_file::error::DECOMPRESS_ERROR: + case archive_file::error::FILE_TRUNCATED: + case archive_file::error::FILE_CORRUPT: + case archive_file::error::UNSUPPORTED: + case archive_file::error::FILE_ERROR: filerr = osd_file::error::INVALID_DATA; break; - case zip_file::error::BUFFER_TOO_SMALL: + case archive_file::error::BUFFER_TOO_SMALL: default: filerr = osd_file::error::FAILURE; break; @@ -298,7 +288,7 @@ static osd_file::error file_error_from_zip_error(zip_file::error ziperr) -------------------------------------------------*/ /** - * @fn static osd_file::error create_core_file_from_zip(zip_file *zip, const zip_file_header *header, util::core_file::ptr &file) + * @fn static osd_file::error create_core_file_from_zip(archive_file *zip, util::core_file::ptr &file) * * @brief Creates core file from zip. * @@ -309,27 +299,27 @@ static osd_file::error file_error_from_zip_error(zip_file::error ziperr) * @return The new core file from zip. */ -static osd_file::error create_core_file_from_zip(zip_file &zip, const zip_file::file_header *header, util::core_file::ptr &file) +static osd_file::error create_core_file_from_zip(archive_file &zip, util::core_file::ptr &file) { osd_file::error filerr; - zip_file::error ziperr; + archive_file::error ziperr; void *ptr; - ptr = malloc(header->uncompressed_length); + ptr = malloc(zip.current_uncompressed_length()); if (ptr == nullptr) { filerr = osd_file::error::OUT_OF_MEMORY; goto done; } - ziperr = zip.decompress(ptr, header->uncompressed_length); - if (ziperr != zip_file::error::NONE) + ziperr = zip.decompress(ptr, zip.current_uncompressed_length()); + if (ziperr != archive_file::error::NONE) { filerr = file_error_from_zip_error(ziperr); goto done; } - filerr = util::core_file::open_ram_copy(ptr, header->uncompressed_length, OPEN_FLAG_READ, file); + filerr = util::core_file::open_ram_copy(ptr, zip.current_uncompressed_length(), OPEN_FLAG_READ, file); if (filerr != osd_file::error::NONE) goto done; @@ -360,9 +350,9 @@ done: osd_file::error zippath_fopen(const char *filename, UINT32 openflags, util::core_file::ptr &file, std::string &revised_path) { osd_file::error filerr = osd_file::error::NOT_FOUND; - zip_file::error ziperr; - zip_file::ptr zip; - const zip_file::file_header *header; + archive_file::error ziperr; + archive_file::ptr zip; + int header; osd_dir_entry_type entry_type; int len; @@ -376,11 +366,11 @@ osd_file::error zippath_fopen(const char *filename, UINT32 openflags, util::core && ((openflags == OPEN_FLAG_READ) || (subpath.length() == 0))) { /* is the mainpath a ZIP path? */ - if (is_zip_file(mainpath.c_str())) + if (is_zip_file(mainpath) || is_7z_file(mainpath)) { /* this file might be a zip file - lets take a look */ - ziperr = zip_file::open(mainpath, zip); - if (ziperr == zip_file::error::NONE) + ziperr = is_zip_file(mainpath) ? archive_file::open_zip(mainpath, zip) : archive_file::open_7z(mainpath, zip); + if (ziperr == archive_file::error::NONE) { /* it is a zip file - error if we're not opening for reading */ if (openflags != OPEN_FLAG_READ) @@ -390,34 +380,29 @@ osd_file::error zippath_fopen(const char *filename, UINT32 openflags, util::core } if (subpath.length() > 0) - header = zippath_find_sub_path(*zip, subpath.c_str(), &entry_type); + header = zippath_find_sub_path(*zip, subpath, entry_type); else header = zip->first_file(); - if (header == nullptr) + if (header < 0) { filerr = osd_file::error::NOT_FOUND; goto done; } /* attempt to read the file */ - filerr = create_core_file_from_zip(*zip, header, file); + filerr = create_core_file_from_zip(*zip, file); if (filerr != osd_file::error::NONE) goto done; /* update subpath, if appropriate */ if (subpath.length() == 0) - subpath.assign(header->filename); + subpath.assign(zip->current_name()); /* we're done */ goto done; } } - else if (is_7z_file(mainpath.c_str())) - { - filerr = osd_file::error::INVALID_DATA; - goto done; - } if (subpath.length() == 0) filerr = util::core_file::open(filename, openflags, file); @@ -523,10 +508,10 @@ static int is_root(const char *path) * @return An int. */ -static int is_7z_file(const char *path) +static bool is_7z_file(std::string const &path) { - const char *s = strrchr(path, '.'); - return (s != nullptr) && !core_stricmp(s, ".7z"); + auto const s = path.rfind('.'); + return (std::string::npos != s) && !core_stricmp(path.c_str() + s, ".7z"); } @@ -535,20 +520,10 @@ static int is_7z_file(const char *path) ZIP file -------------------------------------------------*/ -/** - * @fn static int is_zip_file(const char *path) - * - * @brief Is zip file. - * - * @param path Full pathname of the file. - * - * @return An int. - */ - -static int is_zip_file(const char *path) +static bool is_zip_file(std::string const &path) { - const char *s = strrchr(path, '.'); - return (s != nullptr) && !core_stricmp(s, ".zip"); + auto const s = path.rfind('.'); + return (std::string::npos != s) && !core_stricmp(path.c_str() + s, ".zip"); } @@ -568,7 +543,7 @@ static int is_zip_file(const char *path) * @return An int. */ -static int is_zip_file_separator(char c) +static bool is_zip_file_separator(char c) { return (c == '/') || (c == '\\'); } @@ -590,7 +565,7 @@ static int is_zip_file_separator(char c) * @return An int. */ -static int is_zip_path_separator(char c) +static bool is_zip_path_separator(char c) { return is_zip_file_separator(c) || is_path_separator(c); } @@ -613,38 +588,35 @@ static int is_zip_path_separator(char c) * @return A char. */ -static char next_path_char(const char *s, int *pos) +static char next_path_char(std::string const &s, std::string::size_type &pos) { - char result; - - /* skip over any initial separators */ - if (*pos == 0) + // skip over any initial separators + if (pos == 0) { - while(is_zip_file_separator(s[*pos])) - (*pos)++; + while ((pos < s.length()) && is_zip_file_separator(s[pos])) + pos++; } - /* are we at a path separator? */ - if (is_zip_file_separator(s[*pos])) + // are we at a path separator? + if (pos == s.length()) { - /* skip over path separators */ - while(is_zip_file_separator(s[*pos])) - (*pos)++; - - /* normalize as '/' */ - result = '/'; + // return NUL + return '\0'; } - else if (s[*pos] != '\0') + else if (is_zip_file_separator(s[pos])) { - /* return character */ - result = tolower(s[(*pos)++]); + // skip over path separators + while((pos < s.length()) && is_zip_file_separator(s[pos])) + pos++; + + // normalize as '/' + return '/'; } else { - /* return NUL */ - result = '\0'; + // return character + return std::tolower(s[pos++]); } - return result; } @@ -656,7 +628,7 @@ static char next_path_char(const char *s, int *pos) -------------------------------------------------*/ /** - * @fn static const zip_file_header *zippath_find_sub_path(zip_file *zipfile, const char *subpath, osd_dir_entry_type *type) + * @fn static const zip_file_header *zippath_find_sub_path(archive_file *zipfile, const char *subpath, osd_dir_entry_type *type) * * @brief Zippath find sub path. * @@ -667,50 +639,36 @@ static char next_path_char(const char *s, int *pos) * @return null if it fails, else a zip_file_header*. */ -static const zip_file::file_header *zippath_find_sub_path(zip_file &zipfile, const char *subpath, osd_dir_entry_type *type) +static int zippath_find_sub_path(archive_file &zipfile, std::string const &subpath, osd_dir_entry_type &type) { - int i, j; - char c1, c2, last_char; - const zip_file::file_header *header; - - for (header = zipfile.first_file(); header != nullptr; header = zipfile.next_file()) + for (int header = zipfile.first_file(); header >= 0; header = zipfile.next_file()) { - /* special case */ - if (subpath == nullptr) + std::string::size_type i = 0, j = 0; + char c1, c2; + do { - if (type != nullptr) - *type = ENTTYPE_FILE; - return header; + c1 = next_path_char(zipfile.current_name(), i); + c2 = next_path_char(subpath, j); } + while ((c1 == c2) && c1 && c2); - 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 (!c2 || ((c2 == '/') && !(c2 = next_path_char(subpath, j)))) { - if (c1 == '\0') + if (!c1) { - if (type != nullptr) - *type = ENTTYPE_FILE; + type = zipfile.current_is_directory() ? ENTTYPE_DIR : ENTTYPE_FILE; return header; } - else if ((last_char == '/') || (c1 == '/')) + else if ((c1 == '/') || (i <= 1U)) { - if (type != nullptr) - *type = ENTTYPE_DIR; + type = ENTTYPE_DIR; return header; } } } - if (type != nullptr) - *type = ENTTYPE_NONE; - return nullptr; + type = ENTTYPE_NONE; + return -1; } @@ -721,7 +679,7 @@ static const zip_file::file_header *zippath_find_sub_path(zip_file &zipfile, con -------------------------------------------------*/ /** - * @fn static osd_file::error zippath_resolve(const char *path, osd_dir_entry_type &entry_type, zip_file *&zipfile, std::string &newpath) + * @fn static osd_file::error zippath_resolve(const char *path, osd_dir_entry_type &entry_type, archive_file *&zipfile, std::string &newpath) * * @brief Zippath resolve. * @@ -733,94 +691,78 @@ static const zip_file::file_header *zippath_find_sub_path(zip_file &zipfile, con * @return A osd_file::error. */ -static osd_file::error zippath_resolve(const char *path, osd_dir_entry_type &entry_type, zip_file::ptr &zipfile, std::string &newpath) +static osd_file::error zippath_resolve(const char *path, osd_dir_entry_type &entry_type, archive_file::ptr &zipfile, std::string &newpath) { - osd_file::error err; - osd_directory_entry *current_entry = nullptr; - osd_dir_entry_type current_entry_type; - int went_up = FALSE; - int i; - newpath.clear(); - /* be conservative */ + // be conservative entry_type = ENTTYPE_NONE; zipfile.reset(); std::string apath(path); std::string apath_trimmed; + osd_dir_entry_type current_entry_type; + bool went_up = false; do { - /* trim the path of trailing path separators */ - i = apath.length(); - while (i > 1 && is_path_separator(apath[i - 1])) + // trim the path of trailing path separators + auto i = apath.length(); + while ((i > 1) && is_path_separator(apath[i - 1])) i--; - apath = apath.substr(0, i); - apath_trimmed.assign(apath); + apath.resize(i); + apath_trimmed = apath; - /* stat the path */ - current_entry = osd_stat(apath_trimmed.c_str()); + // stat the path + std::unique_ptr<osd_directory_entry, void (*)(void *)> current_entry(osd_stat(apath_trimmed), &osd_free); - /* did we find anything? */ - if (current_entry != nullptr) + // did we find anything? + if (current_entry) { - /* get the entry type and free the stat entry */ + // get the entry type and free the stat entry current_entry_type = current_entry->type; - osd_free(current_entry); - current_entry = nullptr; } else { - /* if we have not found the file or directory, go up */ + // if we have not found the file or directory, go up current_entry_type = ENTTYPE_NONE; - went_up = TRUE; + went_up = true; std::string parent; - apath.assign(zippath_parent(parent, apath.c_str())); + apath = zippath_parent(parent, apath.c_str()); } } - while (current_entry_type == ENTTYPE_NONE && !is_root(apath.c_str())); + while ((current_entry_type == ENTTYPE_NONE) && !is_root(apath.c_str())); - /* if we did not find anything, then error out */ + // if we did not find anything, then error out if (current_entry_type == ENTTYPE_NONE) - { - err = osd_file::error::NOT_FOUND; - goto done; - } + return osd_file::error::NOT_FOUND; - /* is this file a ZIP file? */ - if ((current_entry_type == ENTTYPE_FILE) && is_zip_file(apath_trimmed.c_str()) - && (zip_file::open(apath_trimmed, zipfile) == zip_file::error::NONE)) + // is this file a ZIP file? + if ((current_entry_type == ENTTYPE_FILE) && + ((is_zip_file(apath_trimmed) && (archive_file::open_zip(apath_trimmed, zipfile) == archive_file::error::NONE)) || + (is_7z_file(apath_trimmed) && (archive_file::open_7z(apath_trimmed, zipfile) == archive_file::error::NONE)))) { - i = strlen(path + apath.length()); - while (i > 0 && is_zip_path_separator(path[apath.length() + i - 1])) + auto i = strlen(path + apath.length()); + while ((i > 0) && is_zip_path_separator(path[apath.length() + i - 1])) i--; newpath.assign(path + apath.length(), i); - /* this was a true ZIP path - attempt to identify the type of path */ - zippath_find_sub_path(*zipfile, newpath.c_str(), ¤t_entry_type); + // this was a true ZIP path - attempt to identify the type of path + zippath_find_sub_path(*zipfile, newpath, current_entry_type); if (current_entry_type == ENTTYPE_NONE) - { - err = osd_file::error::NOT_FOUND; - goto done; - } + return osd_file::error::NOT_FOUND; } else { - /* this was a normal path */ + // this was a normal path if (went_up) - { - err = osd_file::error::NOT_FOUND; - goto done; - } - newpath.assign(path); + return osd_file::error::NOT_FOUND; + + newpath = path; } - /* success! */ + // success! entry_type = current_entry_type; - err = osd_file::error::NONE; - -done: - return err; + return osd_file::error::NONE; } @@ -868,11 +810,11 @@ osd_file::error zippath_opendir(const char *path, zippath_directory **directory) } /* was the result a ZIP? */ - if (result->zipfile == nullptr) + if (!result->zipfile) { /* a conventional directory */ result->directory = osd_opendir(path); - if (result->directory == nullptr) + if (!result->directory) { err = osd_file::error::FAILURE; goto done; @@ -943,20 +885,27 @@ void zippath_closedir(zippath_directory *directory) * @return null if it fails, else the relative path. */ -static const char *get_relative_path(zippath_directory *directory, const zip_file::file_header *header) +static const char *get_relative_path(zippath_directory const &directory) { - const char *result = nullptr; - int len = directory->zipprefix.length(); + auto len = directory.zipprefix.length(); + const char *prefix = directory.zipprefix.c_str(); + while (is_zip_file_separator(*prefix)) + { + len--; + prefix++; + } - if ((len <= strlen(header->filename)) - && !strncmp(directory->zipprefix.c_str(), header->filename, len)) + if ((len <= directory.zipfile->current_name().length()) && + !strncmp(prefix, directory.zipfile->current_name().c_str(), len)) { - result = &header->filename[len]; - while(is_zip_file_separator(*result)) + const char *result = &directory.zipfile->current_name().c_str()[len]; + while (is_zip_file_separator(*result)) result++; + + return *result ? result : nullptr; } - return result; + return nullptr; } @@ -977,7 +926,7 @@ static const char *get_relative_path(zippath_directory *directory, const zip_fil const osd_directory_entry *zippath_readdir(zippath_directory *directory) { const osd_directory_entry *result = nullptr; - const zip_file::file_header *header; + int header; const char *relpath; const char *separator; const char *s; @@ -992,7 +941,7 @@ const osd_directory_entry *zippath_readdir(zippath_directory *directory) directory->returned_entry.type = ENTTYPE_DIR; result = &directory->returned_entry; } - else if (directory->directory != nullptr) + else if (directory->directory) { /* a normal directory read */ do @@ -1002,7 +951,7 @@ const osd_directory_entry *zippath_readdir(zippath_directory *directory) while((result != nullptr) && (!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 != nullptr) && is_zip_file(result->name)) + if ((result != nullptr) && (is_zip_file(result->name) || is_7z_file(result->name))) { /* copy; but change the entry type */ directory->returned_entry = *result; @@ -1010,7 +959,7 @@ const osd_directory_entry *zippath_readdir(zippath_directory *directory) result = &directory->returned_entry; } } - else if (directory->zipfile != nullptr) + else if (directory->zipfile) { do { @@ -1024,7 +973,7 @@ const osd_directory_entry *zippath_readdir(zippath_directory *directory) directory->called_zip_first = true; relpath = nullptr; } - while((header != nullptr) && ((relpath = get_relative_path(directory, header)) == nullptr)); + while((header >= 0) && ((relpath = get_relative_path(*directory)) == nullptr)); if (relpath != nullptr) { @@ -1063,7 +1012,7 @@ const osd_directory_entry *zippath_readdir(zippath_directory *directory) 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; + directory->returned_entry.size = directory->zipfile->current_uncompressed_length(); result = &directory->returned_entry; } } @@ -1094,3 +1043,5 @@ int zippath_is_zip(zippath_directory *directory) { return directory->zipfile != nullptr; } + +} // namespace util |