From 100fa28671af455853a6de1b2d7a3499fa6e185c Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Fri, 18 Mar 2016 19:22:43 +1100 Subject: * Remove confusing method from vectorstreams that hide base_ios method (fixes disassembly view) * Allow std::string to pass through core_file unmolested (reduces temporary allocations) * Make zip/7z instances of same class with uniform interface * zippath browsing is broken at the moment This is another step towards transparent archive support. It's now possible to access zip and 7z archives with the same code. Nothing is taking advantage of it yet. There's now some very similar code in fileio.cpp and clifront.cpp that could be folded at some point. --- src/lib/util/zippath.cpp | 103 +++++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 52 deletions(-) (limited to 'src/lib/util/zippath.cpp') diff --git a/src/lib/util/zippath.cpp b/src/lib/util/zippath.cpp index 18e2031dcdd..a8fddb64b85 100644 --- a/src/lib/util/zippath.cpp +++ b/src/lib/util/zippath.cpp @@ -18,6 +18,8 @@ #include "osdcore.h" +namespace util { + /*************************************************************************** TYPE DEFINITIONS ***************************************************************************/ @@ -66,7 +68,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,7 +80,7 @@ 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 zippath_find_sub_path(archive_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); @@ -255,7 +257,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 +266,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 +300,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 +311,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 +362,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; @@ -379,8 +381,8 @@ osd_file::error zippath_fopen(const char *filename, UINT32 openflags, util::core if (is_zip_file(mainpath.c_str())) { /* this file might be a zip file - lets take a look */ - ziperr = zip_file::open(mainpath, zip); - if (ziperr == zip_file::error::NONE) + ziperr = archive_file::open_zip(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) @@ -394,20 +396,20 @@ osd_file::error zippath_fopen(const char *filename, UINT32 openflags, util::core 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; @@ -656,7 +658,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,13 +669,9 @@ 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, const char *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) @@ -683,13 +681,12 @@ static const zip_file::file_header *zippath_find_sub_path(zip_file &zipfile, con return header; } - i = 0; - j = 0; + // FIXME: how is this actually supposed to work? I'm pretty sure it's broken right now anyway. + int i = 0, j = 0; + char c1, c2, last_char; last_char = '/'; - while(((c1 = next_path_char(header->filename, &i)) == (c2 = next_path_char(subpath, &j))) && - ( c1 != '\0' && c2 != '\0' )) - last_char = c2; - + while(((c1 = next_path_char(zipfile.current_name().c_str(), &i)) == (c2 = next_path_char(subpath, &j))) && (c1 != '\0' && c2 != '\0')) + last_char = c2; if (c2 == '\0') { @@ -710,7 +707,7 @@ static const zip_file::file_header *zippath_find_sub_path(zip_file &zipfile, con if (type != nullptr) *type = ENTTYPE_NONE; - return nullptr; + return -1; } @@ -721,7 +718,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,7 +730,7 @@ 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; @@ -789,7 +786,7 @@ static osd_file::error zippath_resolve(const char *path, osd_dir_entry_type &ent /* 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)) + && (archive_file::open_zip(apath_trimmed, zipfile) == archive_file::error::NONE)) { i = strlen(path + apath.length()); while (i > 0 && is_zip_path_separator(path[apath.length() + i - 1])) @@ -943,15 +940,15 @@ 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 *directory) { const char *result = nullptr; int len = directory->zipprefix.length(); - if ((len <= strlen(header->filename)) - && !strncmp(directory->zipprefix.c_str(), header->filename, len)) + if ((len <= directory->zipfile->current_name().length()) + && !strncmp(directory->zipprefix.c_str(), directory->zipfile->current_name().c_str(), len)) { - result = &header->filename[len]; + result = &directory->zipfile->current_name().c_str()[len]; while(is_zip_file_separator(*result)) result++; } @@ -977,7 +974,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; @@ -1024,7 +1021,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 +1060,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 +1091,5 @@ int zippath_is_zip(zippath_directory *directory) { return directory->zipfile != nullptr; } + +} // namespace util -- cgit v1.2.3-70-g09d2 From 142292ee00eec5337f8c587521807243e1c0a1ab Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Fri, 18 Mar 2016 20:37:44 +1100 Subject: Fold some redundant code --- src/emu/clifront.cpp | 62 +++++++++------------------------- src/emu/fileio.cpp | 87 ++++++++++-------------------------------------- src/emu/fileio.h | 8 +---- src/lib/util/zippath.cpp | 33 ++++++++---------- 4 files changed, 46 insertions(+), 144 deletions(-) (limited to 'src/lib/util/zippath.cpp') diff --git a/src/emu/clifront.cpp b/src/emu/clifront.cpp index ee2777257e2..975c3c8f71b 100644 --- a/src/emu/clifront.cpp +++ b/src/emu/clifront.cpp @@ -1757,64 +1757,32 @@ void media_identifier::identify(const char *filename) } // if that failed, and the filename ends with .zip, identify as a ZIP file - if (core_filename_ends_with(filename, ".7z")) + if (core_filename_ends_with(filename, ".7z") || core_filename_ends_with(filename, ".zip")) { // first attempt to examine it as a valid _7Z file - util::archive_file::ptr _7z; - util::archive_file::error _7zerr = util::archive_file::open_7z(filename, _7z); - if ((_7zerr == util::archive_file::error::NONE) && _7z) + util::archive_file::ptr archive; + util::archive_file::error err; + if (core_filename_ends_with(filename, ".7z")) + err = util::archive_file::open_7z(filename, archive); + else + err = util::archive_file::open_zip(filename, archive); + if ((err == util::archive_file::error::NONE) && archive) { std::vector data; // loop over entries in the .7z, skipping empty files and directories - for (int i = _7z->first_file(); i >= 0; i = _7z->next_file()) - { - const std::uint64_t length(_7z->current_uncompressed_length()); - if (!_7z->current_is_directory() && (length != 0) && (std::uint32_t(length) == length)) - { - // decompress data into RAM and identify it - try - { - data.resize(std::size_t(length)); - _7zerr = _7z->decompress(&data[0], std::uint32_t(length)); - if (_7zerr == util::archive_file::error::NONE) - identify_data(_7z->current_name().c_str(), &data[0], length); - } - catch (...) - { - // resizing the buffer could cause a bad_alloc if archive contains large files - } - data.clear(); - } - } - } - - // clear out any cached files - _7z.reset(); - util::archive_file::cache_clear(); - } - else if (core_filename_ends_with(filename, ".zip")) - { - // first attempt to examine it as a valid ZIP file - util::archive_file::ptr zip; - util::archive_file::error ziperr = util::archive_file::open_zip(filename, zip); - if (ziperr == util::archive_file::error::NONE && zip) - { - std::vector data; - - // loop over entries in the ZIP, skipping empty files and directories - for (int i = zip->first_file(); i >= 0; i = zip->next_file()) + for (int i = archive->first_file(); i >= 0; i = archive->next_file()) { - const std::uint64_t length(zip->current_uncompressed_length()); - if (!zip->current_is_directory() && (length != 0) && (std::uint32_t(length) == length)) + const std::uint64_t length(archive->current_uncompressed_length()); + if (!archive->current_is_directory() && (length != 0) && (std::uint32_t(length) == length)) { // decompress data into RAM and identify it try { data.resize(std::size_t(length)); - ziperr = zip->decompress(&data[0], std::uint32_t(length)); - if (ziperr == util::archive_file::error::NONE) - identify_data(zip->current_name().c_str(), &data[0], length); + err = archive->decompress(&data[0], std::uint32_t(length)); + if (err == util::archive_file::error::NONE) + identify_data(archive->current_name().c_str(), &data[0], length); } catch (...) { @@ -1826,7 +1794,7 @@ void media_identifier::identify(const char *filename) } // clear out any cached files - zip.reset(); + archive.reset(); util::archive_file::cache_clear(); } diff --git a/src/emu/fileio.cpp b/src/emu/fileio.cpp index 2b0f607160c..812f2a7007f 100644 --- a/src/emu/fileio.cpp +++ b/src/emu/fileio.cpp @@ -145,8 +145,6 @@ emu_file::emu_file(UINT32 openflags) m_openflags(openflags), m_zipfile(nullptr), m_ziplength(0), - m__7zfile(), - m__7zlength(0), m_remove_on_close(false), m_restrict_to_mediapath(false) { @@ -163,8 +161,6 @@ emu_file::emu_file(const char *searchpath, UINT32 openflags) m_openflags(openflags), m_zipfile(nullptr), m_ziplength(0), - m__7zfile(), - m__7zlength(0), m_remove_on_close(false), m_restrict_to_mediapath(false) { @@ -227,12 +223,6 @@ hash_collection &emu_file::hashes(const char *types) return m_hashes; // if we have ZIP data, just hash that directly - if (!m__7zdata.empty()) - { - m_hashes.compute(&m__7zdata[0], m__7zdata.size(), needed.c_str()); - return m_hashes; - } - if (!m_zipdata.empty()) { m_hashes.compute(&m_zipdata[0], m_zipdata.size(), needed.c_str()); @@ -385,11 +375,9 @@ osd_file::error emu_file::open_ram(const void *data, UINT32 length) void emu_file::close() { // close files and free memory - m__7zfile.reset(); m_zipfile.reset(); m_file.reset(); - m__7zdata.clear(); m_zipdata.clear(); if (m_remove_on_close) @@ -422,10 +410,7 @@ osd_file::error emu_file::compress(int level) bool emu_file::compressed_file_ready(void) { // load the ZIP file now if we haven't yet - if (m__7zfile != nullptr && load__7zped_file() != osd_file::error::NONE) - return true; - - if (m_zipfile != nullptr && load_zipped_file() != osd_file::error::NONE) + if (m_zipfile && (load_zipped_file() != osd_file::error::NONE)) return true; return false; @@ -492,9 +477,6 @@ bool emu_file::eof() UINT64 emu_file::size() { // use the ZIP length if present - if (m__7zfile != nullptr) - return m__7zlength; - if (m_zipfile != nullptr) return m_ziplength; @@ -715,41 +697,6 @@ osd_file::error emu_file::attempt_zipped() } -//------------------------------------------------- -// load_zipped_file - load a ZIPped file -//------------------------------------------------- - -osd_file::error emu_file::load_zipped_file() -{ - assert(m_file == nullptr); - assert(m_zipdata.empty()); - assert(m_zipfile != nullptr); - - // allocate some memory - m_zipdata.resize(m_ziplength); - - // read the data into our buffer and return - auto const ziperr = m_zipfile->decompress(&m_zipdata[0], m_zipdata.size()); - if (ziperr != util::archive_file::error::NONE) - { - m_zipdata.clear(); - return osd_file::error::FAILURE; - } - - // convert to RAM file - osd_file::error filerr = util::core_file::open_ram(&m_zipdata[0], m_zipdata.size(), m_openflags, m_file); - if (filerr != osd_file::error::NONE) - { - m_zipdata.clear(); - return osd_file::error::FAILURE; - } - - // close out the ZIP file - m_zipfile.reset(); - return osd_file::error::NONE; -} - - //------------------------------------------------- // attempt__7zped - attempt to open a .7z file //------------------------------------------------- @@ -803,13 +750,13 @@ osd_file::error emu_file::attempt__7zped() if (fileno >= 0) { - m__7zfile = std::move(_7z); - m__7zlength = m__7zfile->current_uncompressed_length(); + m_zipfile = std::move(_7z); + m_ziplength = m_zipfile->current_uncompressed_length(); // build a hash with just the CRC m_hashes.reset(); - m_hashes.add_crc(m__7zfile->current_crc()); - return (m_openflags & OPEN_FLAG_NO_PRELOAD) ? osd_file::error::NONE : load__7zped_file(); + m_hashes.add_crc(m_zipfile->current_crc()); + return (m_openflags & OPEN_FLAG_NO_PRELOAD) ? osd_file::error::NONE : load_zipped_file(); } // close up the _7Z file and try the next level @@ -819,35 +766,35 @@ osd_file::error emu_file::attempt__7zped() //------------------------------------------------- -// load__7zped_file - load a _7Zped file +// load_zipped_file - load a ZIPped file //------------------------------------------------- -osd_file::error emu_file::load__7zped_file() +osd_file::error emu_file::load_zipped_file() { assert(m_file == nullptr); - assert(m__7zdata.empty()); - assert(m__7zfile); + assert(m_zipdata.empty()); + assert(m_zipfile); // allocate some memory - m__7zdata.resize(m__7zlength); + m_zipdata.resize(m_ziplength); // read the data into our buffer and return - auto const _7zerr = m__7zfile->decompress(&m__7zdata[0], m__7zdata.size()); - if (_7zerr != util::archive_file::error::NONE) + auto const ziperr = m_zipfile->decompress(&m_zipdata[0], m_zipdata.size()); + if (ziperr != util::archive_file::error::NONE) { - m__7zdata.clear(); + m_zipdata.clear(); return osd_file::error::FAILURE; } // convert to RAM file - osd_file::error filerr = util::core_file::open_ram(&m__7zdata[0], m__7zdata.size(), m_openflags, m_file); + osd_file::error filerr = util::core_file::open_ram(&m_zipdata[0], m_zipdata.size(), m_openflags, m_file); if (filerr != osd_file::error::NONE) { - m__7zdata.clear(); + m_zipdata.clear(); return osd_file::error::FAILURE; } - // close out the _7Z file - m__7zfile.reset(); + // close out the ZIP file + m_zipfile.reset(); return osd_file::error::NONE; } diff --git a/src/emu/fileio.h b/src/emu/fileio.h index f45e8be3533..a29372f071d 100644 --- a/src/emu/fileio.h +++ b/src/emu/fileio.h @@ -145,10 +145,8 @@ private: // internal helpers osd_file::error attempt_zipped(); - osd_file::error load_zipped_file(); - osd_file::error attempt__7zped(); - osd_file::error load__7zped_file(); + osd_file::error load_zipped_file(); // internal state std::string m_filename; // original filename provided @@ -164,10 +162,6 @@ private: dynamic_buffer m_zipdata; // ZIP file data UINT64 m_ziplength; // ZIP file length - std::unique_ptr m__7zfile; // 7Z file pointer - dynamic_buffer m__7zdata; // 7Z file data - UINT64 m__7zlength; // 7Z file length - bool m_remove_on_close; // flag: remove the file when closing bool m_restrict_to_mediapath; // flag: restrict to paths inside the media-path }; diff --git a/src/lib/util/zippath.cpp b/src/lib/util/zippath.cpp index a8fddb64b85..77170d1e696 100644 --- a/src/lib/util/zippath.cpp +++ b/src/lib/util/zippath.cpp @@ -80,7 +80,7 @@ public: FUNCTION PROTOTYPES ***************************************************************************/ -static int zippath_find_sub_path(archive_file &zipfile, const char *subpath, osd_dir_entry_type *type); +static int zippath_find_sub_path(archive_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); @@ -392,7 +392,7 @@ 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.c_str(), entry_type); else header = zip->first_file(); @@ -669,44 +669,37 @@ static char next_path_char(const char *s, int *pos) * @return null if it fails, else a zip_file_header*. */ -static int zippath_find_sub_path(archive_file &zipfile, const char *subpath, osd_dir_entry_type *type) +static int zippath_find_sub_path(archive_file &zipfile, const char *subpath, osd_dir_entry_type &type) { for (int header = zipfile.first_file(); header >= 0; header = zipfile.next_file()) { /* special case */ if (subpath == nullptr) { - if (type != nullptr) - *type = ENTTYPE_FILE; + type = ENTTYPE_FILE; return header; } - // FIXME: how is this actually supposed to work? I'm pretty sure it's broken right now anyway. int i = 0, j = 0; - char c1, c2, last_char; - last_char = '/'; - while(((c1 = next_path_char(zipfile.current_name().c_str(), &i)) == (c2 = next_path_char(subpath, &j))) && (c1 != '\0' && c2 != '\0')) - last_char = c2; + char c1, c2; + while (((c1 = next_path_char(zipfile.current_name().c_str(), &i)) == (c2 = next_path_char(subpath, &j))) && c1 && c2) { } - if (c2 == '\0') + if (!c1) { - if (c1 == '\0') + if (!c2) { - if (type != nullptr) - *type = ENTTYPE_FILE; + type = zipfile.current_is_directory() ? ENTTYPE_DIR : ENTTYPE_FILE; return header; } - else if ((last_char == '/') || (c1 == '/')) + else if ((c2 == '/') && !(c2 = next_path_char(subpath, &j)) && zipfile.current_is_directory()) { - if (type != nullptr) - *type = ENTTYPE_DIR; + type = ENTTYPE_DIR; return header; } } } - if (type != nullptr) - *type = ENTTYPE_NONE; + type = ENTTYPE_NONE; return -1; } @@ -794,7 +787,7 @@ static osd_file::error zippath_resolve(const char *path, osd_dir_entry_type &ent 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); + zippath_find_sub_path(*zipfile, newpath.c_str(), current_entry_type); if (current_entry_type == ENTTYPE_NONE) { err = osd_file::error::NOT_FOUND; -- cgit v1.2.3-70-g09d2 From a320eaf2386f81bf6de213bc2b295344cc0dc207 Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Fri, 18 Mar 2016 22:56:08 +1100 Subject: Fix zippath browsing and allow zippath to browse/load 7zip This code is still horrible and needs rewriting, but not tonight --- src/lib/util/zippath.cpp | 253 ++++++++++++++++++++--------------------------- 1 file changed, 106 insertions(+), 147 deletions(-) (limited to 'src/lib/util/zippath.cpp') diff --git a/src/lib/util/zippath.cpp b/src/lib/util/zippath.cpp index 77170d1e696..edeecf80c47 100644 --- a/src/lib/util/zippath.cpp +++ b/src/lib/util/zippath.cpp @@ -8,15 +8,17 @@ ***************************************************************************/ -#include -#include -#include -#include #include "zippath.h" #include "unzip.h" #include "corestr.h" #include "osdcore.h" +#include + +#include +#include +#include + namespace util { @@ -80,10 +82,10 @@ public: FUNCTION PROTOTYPES ***************************************************************************/ -static int zippath_find_sub_path(archive_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); /*************************************************************************** @@ -150,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; } @@ -378,10 +366,10 @@ 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 = archive_file::open_zip(mainpath, zip); + 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 */ @@ -392,7 +380,7 @@ 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(); @@ -415,11 +403,6 @@ osd_file::error zippath_fopen(const char *filename, UINT32 openflags, util::core 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); @@ -525,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"); } @@ -537,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"); } @@ -570,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 == '\\'); } @@ -592,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); } @@ -615,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; } @@ -669,29 +639,27 @@ static char next_path_char(const char *s, int *pos) * @return null if it fails, else a zip_file_header*. */ -static int zippath_find_sub_path(archive_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) { 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 { - type = ENTTYPE_FILE; - return header; + c1 = next_path_char(zipfile.current_name(), i); + c2 = next_path_char(subpath, j); } + while ((c1 == c2) && c1 && c2); - int i = 0, j = 0; - char c1, c2; - while (((c1 = next_path_char(zipfile.current_name().c_str(), &i)) == (c2 = next_path_char(subpath, &j))) && c1 && c2) { } - - if (!c1) + if (!c2 || ((c2 == '/') && !(c2 = next_path_char(subpath, j)))) { - if (!c2) + if (!c1) { type = zipfile.current_is_directory() ? ENTTYPE_DIR : ENTTYPE_FILE; return header; } - else if ((c2 == '/') && !(c2 = next_path_char(subpath, &j)) && zipfile.current_is_directory()) + else if ((c1 == '/') || (i <= 1U)) { type = ENTTYPE_DIR; return header; @@ -725,92 +693,76 @@ static int zippath_find_sub_path(archive_file &zipfile, const char *subpath, osd 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 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()) - && (archive_file::open_zip(apath_trimmed, zipfile) == archive_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(), current_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; } @@ -858,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; @@ -933,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) +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 <= directory->zipfile->current_name().length()) - && !strncmp(directory->zipprefix.c_str(), directory->zipfile->current_name().c_str(), len)) + if ((len <= directory.zipfile->current_name().length()) && + !strncmp(prefix, directory.zipfile->current_name().c_str(), len)) { - result = &directory->zipfile->current_name().c_str()[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; } @@ -982,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 @@ -992,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; @@ -1000,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 { @@ -1014,7 +973,7 @@ const osd_directory_entry *zippath_readdir(zippath_directory *directory) directory->called_zip_first = true; relpath = nullptr; } - while((header >= 0) && ((relpath = get_relative_path(directory)) == nullptr)); + while((header >= 0) && ((relpath = get_relative_path(*directory)) == nullptr)); if (relpath != nullptr) { -- cgit v1.2.3-70-g09d2