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/unzip.cpp | 362 ++++++++++++++++++++++++++----------------------- 1 file changed, 194 insertions(+), 168 deletions(-) (limited to 'src/lib/util/unzip.cpp') diff --git a/src/lib/util/unzip.cpp b/src/lib/util/unzip.cpp index 321f4e0b69f..06ab41aae3a 100644 --- a/src/lib/util/unzip.cpp +++ b/src/lib/util/unzip.cpp @@ -8,21 +8,25 @@ ***************************************************************************/ -#include "osdcore.h" #include "unzip.h" +#include "corestr.h" +#include "osdcore.h" + + #include #include #include #include #include +#include #include #include #include - +namespace util { namespace { /*************************************************************************** CONSTANTS @@ -71,29 +75,8 @@ namespace { #define ZIPCRC 0x0e #define ZIPSIZE 0x12 #define ZIPUNCMP 0x16 - -/** - * @def ZIPFNLN - * - * @brief A macro that defines zipfnln. - */ - #define ZIPFNLN 0x1a - -/** - * @def ZIPXTRALN - * - * @brief A macro that defines zipxtraln. - */ - #define ZIPXTRALN 0x1c - -/** - * @def ZIPNAME - * - * @brief A macro that defines zipname. - */ - #define ZIPNAME 0x1e @@ -115,6 +98,8 @@ public: , m_cd() , m_cd_pos(0) , m_header() + , m_curr_is_dir(false) + , m_curr_name() , m_buffer() { std::memset(&m_header, 0, sizeof(m_header)); @@ -123,6 +108,7 @@ public: static ptr find_cached(const std::string &filename) { + std::lock_guard guard(s_cache_mutex); for (std::size_t cachenum = 0; cachenum < s_cache.size(); cachenum++) { // if we have a valid entry and it matches our filename, use it and remove from the cache @@ -139,37 +125,65 @@ public: static void cache_clear() { // clear call cache entries + std::lock_guard guard(s_cache_mutex); for (std::size_t cachenum = 0; cachenum < s_cache.size(); s_cache[cachenum++].reset()) { } } - zip_file::error initialize() + archive_file::error initialize() { // read ecd data auto const ziperr = read_ecd(); - if (ziperr != zip_file::error::NONE) + if (ziperr != archive_file::error::NONE) return ziperr; // verify that we can work with this zipfile (no disk spanning allowed) if ((m_ecd.disk_number != m_ecd.cd_start_disk_number) || (m_ecd.cd_disk_entries != m_ecd.cd_total_entries)) - return zip_file::error::UNSUPPORTED; + return archive_file::error::UNSUPPORTED; // allocate memory for the central directory try { m_cd.resize(m_ecd.cd_size + 1); } - catch (...) { return zip_file::error::OUT_OF_MEMORY; } + catch (...) { return archive_file::error::OUT_OF_MEMORY; } // read the central directory std::uint32_t read_length; auto const filerr = m_file->read(&m_cd[0], m_ecd.cd_start_disk_offset, m_ecd.cd_size, read_length); if ((filerr != osd_file::error::NONE) || (read_length != m_ecd.cd_size)) - return (filerr == osd_file::error::NONE) ? zip_file::error::FILE_TRUNCATED : zip_file::error::FILE_ERROR; + return (filerr == osd_file::error::NONE) ? archive_file::error::FILE_TRUNCATED : archive_file::error::FILE_ERROR; - return zip_file::error::NONE; + return archive_file::error::NONE; } - // contained file access - const zip_file::file_header *first_file(); - const zip_file::file_header *next_file(); - zip_file::error decompress(void *buffer, std::uint32_t length); + int first_file() + { + m_cd_pos = 0; + return search(0, std::string(), false, false); + } + int next_file() + { + return search(0, std::string(), false, false); + } + int search(std::uint32_t crc) + { + m_cd_pos = 0; + return search(crc, std::string(), true, false); + } + int search(const std::string &filename) + { + m_cd_pos = 0; + return search(0, filename, false, true); + } + int search(std::uint32_t crc, const std::string &filename) + { + m_cd_pos = 0; + return search(crc, filename, true, true); + } + + bool current_is_directory() const { return m_curr_is_dir; } + const std::string ¤t_name() const { return m_curr_name; } + std::uint64_t current_uncompressed_length() const { return m_header.uncompressed_length; } + std::uint32_t current_crc() const { return m_header.crc; } + + archive_file::error decompress(void *buffer, std::uint32_t length); private: zip_file_impl(const zip_file_impl &) = delete; @@ -177,30 +191,47 @@ private: zip_file_impl &operator=(const zip_file_impl &) = delete; zip_file_impl &operator=(zip_file_impl &&) = delete; - zip_file::error reopen() + int search(std::uint32_t search_crc, const std::string &search_filename, bool matchcrc, bool matchname); + + archive_file::error reopen() { if (!m_file) { auto const filerr = osd_file::open(m_filename, OPEN_FLAG_READ, m_file, m_length); if (filerr != osd_file::error::NONE) - return zip_file::error::FILE_ERROR; + return archive_file::error::FILE_ERROR; } - return zip_file::error::NONE; + return archive_file::error::NONE; } // ZIP file parsing - zip_file::error read_ecd(); - zip_file::error get_compressed_data_offset(std::uint64_t &offset); + archive_file::error read_ecd(); + archive_file::error get_compressed_data_offset(std::uint64_t &offset); // decompression interfaces - zip_file::error decompress_data_type_0(std::uint64_t offset, void *buffer, std::uint32_t length); - zip_file::error decompress_data_type_8(std::uint64_t offset, void *buffer, std::uint32_t length); + archive_file::error decompress_data_type_0(std::uint64_t offset, void *buffer, std::uint32_t length); + archive_file::error decompress_data_type_8(std::uint64_t offset, void *buffer, std::uint32_t length); - struct file_header_int : zip_file::file_header + struct file_header { - std::uint8_t * raw; // pointer to the raw data - std::uint32_t rawlength; // length of the raw data - std::uint8_t saved; // saved byte from after filename + std::uint32_t signature; // central file header signature + std::uint16_t version_created; // version made by + std::uint16_t version_needed; // version needed to extract + std::uint16_t bit_flag; // general purpose bit flag + std::uint16_t compression; // compression method + std::uint16_t file_time; // last mod file time + std::uint16_t file_date; // last mod file date + std::uint32_t crc; // crc-32 + std::uint32_t compressed_length; // compressed size + std::uint32_t uncompressed_length; // uncompressed size + std::uint16_t filename_length; // filename length + std::uint16_t extra_field_length; // extra field length + std::uint16_t file_comment_length; // file comment length + std::uint16_t start_disk_number; // disk number start + std::uint16_t internal_attributes; // internal file attributes + std::uint32_t external_attributes; // external file attributes + std::uint32_t local_header_offset; // relative offset of local header + const char * filename; // filename }; // contains extracted end of central directory information @@ -220,9 +251,10 @@ private: std::uint32_t rawlength; // length of the raw data }; - static constexpr std::size_t DECOMPRESS_BUFSIZE = 16384; - static constexpr std::size_t CACHE_SIZE = 8; // number of open files to cache - static std::array s_cache; + static constexpr std::size_t DECOMPRESS_BUFSIZE = 16384; + static constexpr std::size_t CACHE_SIZE = 8; // number of open files to cache + static std::array s_cache; + static std::mutex s_cache_mutex; const std::string m_filename; // copy of ZIP filename (for caching) osd_file::ptr m_file; // OSD file handle @@ -232,20 +264,32 @@ private: std::vector m_cd; // central directory raw data std::uint32_t m_cd_pos; // position in central directory - file_header_int m_header; // current file header + file_header m_header; // current file header + bool m_curr_is_dir; // current file is directory + std::string m_curr_name; // current file name std::array m_buffer; // buffer for decompression }; -class zip_file_wrapper : public zip_file +class zip_file_wrapper : public archive_file { public: zip_file_wrapper(zip_file_impl::ptr &&impl) : m_impl(std::move(impl)) { assert(m_impl); } virtual ~zip_file_wrapper() { zip_file_impl::close(std::move(m_impl)); } - virtual const file_header *first_file() override { return m_impl->first_file(); } - virtual const file_header *next_file() override { return m_impl->next_file(); } + virtual int first_file() override { return m_impl->first_file(); } + virtual int next_file() override { return m_impl->next_file(); } + + virtual int search(std::uint32_t crc) override { return m_impl->search(crc); } + virtual int search(const std::string &filename) override { return m_impl->search(filename); } + virtual int search(std::uint32_t crc, const std::string &filename) override { return m_impl->search(crc, filename); } + + virtual bool current_is_directory() const override { return m_impl->current_is_directory(); } + virtual const std::string ¤t_name() const override { return m_impl->current_name(); } + virtual std::uint64_t current_uncompressed_length() const override { return m_impl->current_uncompressed_length(); } + virtual std::uint32_t current_crc() const override { return m_impl->current_crc(); } + virtual error decompress(void *buffer, std::uint32_t length) override { return m_impl->decompress(buffer, length); } private: @@ -268,7 +312,7 @@ private: * @return The word. */ -inline UINT16 read_word(UINT8 *buf) +inline std::uint16_t read_word(std::uint8_t const *buf) { return (buf[1] << 8) | buf[0]; } @@ -283,7 +327,7 @@ inline UINT16 read_word(UINT8 *buf) * @return The double word. */ -inline UINT32 read_dword(UINT8 *buf) +inline std::uint32_t read_dword(std::uint8_t const *buf) { return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; } @@ -296,6 +340,7 @@ inline UINT32 read_dword(UINT8 *buf) /** @brief The zip cache[ zip cache size]. */ std::array zip_file_impl::s_cache; +std::mutex zip_file_impl::s_cache_mutex; @@ -320,6 +365,7 @@ void zip_file_impl::close(ptr &&zip) zip->m_file.reset(); // find the first NULL entry in the cache + std::lock_guard guard(s_cache_mutex); std::size_t cachenum; for (cachenum = 0; cachenum < s_cache.size(); cachenum++) if (!s_cache[cachenum]) @@ -345,88 +391,63 @@ void zip_file_impl::close(ptr &&zip) in the ZIP -------------------------------------------------*/ -/** - * @fn const zip_file_header *zip_file_first_file(zip_file *zip) - * - * @brief Zip file first file. - * - * @param [in,out] zip If non-null, the zip. - * - * @return null if it fails, else a zip_file_header*. - */ - -const zip_file::file_header *zip_file_impl::first_file() -{ - /* reset the position and go from there */ - m_cd_pos = 0; - return next_file(); -} - - /*------------------------------------------------- zip_file_next_entry - return the next entry in the ZIP -------------------------------------------------*/ -/** - * @fn const zip_file_header *zip_file_next_file(zip_file *zip) - * - * @brief Zip file next file. - * - * @param [in,out] zip If non-null, the zip. - * - * @return null if it fails, else a zip_file_header*. - */ - -const zip_file::file_header *zip_file_impl::next_file() +int zip_file_impl::search(std::uint32_t search_crc, const std::string &search_filename, bool matchcrc, bool matchname) { - // fix up any modified data - if (m_header.raw) + // if we're at or past the end, we're done + std::string filename; + while (m_cd_pos <= m_ecd.cd_size) { - m_header.raw[ZIPCFN + m_header.filename_length] = m_header.saved; - m_header.raw = nullptr; - } + // extract file header info + std::uint8_t const *const raw = &m_cd[0] + m_cd_pos; + m_header.signature = read_dword(raw + ZIPCENSIG); + m_header.version_created = read_word (raw + ZIPCVER); + m_header.version_needed = read_word (raw + ZIPCVXT); + m_header.bit_flag = read_word (raw + ZIPCFLG); + m_header.compression = read_word (raw + ZIPCMTHD); + m_header.file_time = read_word (raw + ZIPCTIM); + m_header.file_date = read_word (raw + ZIPCDAT); + m_header.crc = read_dword(raw + ZIPCCRC); + m_header.compressed_length = read_dword(raw + ZIPCSIZ); + m_header.uncompressed_length = read_dword(raw + ZIPCUNC); + m_header.filename_length = read_word (raw + ZIPCFNL); + m_header.extra_field_length = read_word (raw + ZIPCXTL); + m_header.file_comment_length = read_word (raw + ZIPCCML); + m_header.start_disk_number = read_word (raw + ZIPDSK); + m_header.internal_attributes = read_word (raw + ZIPINT); + m_header.external_attributes = read_dword(raw + ZIPEXT); + m_header.local_header_offset = read_dword(raw + ZIPOFST); + m_header.filename = reinterpret_cast(raw + ZIPCFN); + + // make sure we have enough data + std::uint32_t const rawlength = ZIPCFN + m_header.filename_length + m_header.extra_field_length + m_header.file_comment_length; + if ((m_cd_pos + rawlength) > m_ecd.cd_size) + break; - // if we're at or past the end, we're done - if (m_cd_pos >= m_ecd.cd_size) - return nullptr; - - // extract file header info - m_header.raw = &m_cd[0] + m_cd_pos; - m_header.rawlength = ZIPCFN; - m_header.signature = read_dword(m_header.raw + ZIPCENSIG); - m_header.version_created = read_word (m_header.raw + ZIPCVER); - m_header.version_needed = read_word (m_header.raw + ZIPCVXT); - m_header.bit_flag = read_word (m_header.raw + ZIPCFLG); - m_header.compression = read_word (m_header.raw + ZIPCMTHD); - m_header.file_time = read_word (m_header.raw + ZIPCTIM); - m_header.file_date = read_word (m_header.raw + ZIPCDAT); - m_header.crc = read_dword(m_header.raw + ZIPCCRC); - m_header.compressed_length = read_dword(m_header.raw + ZIPCSIZ); - m_header.uncompressed_length = read_dword(m_header.raw + ZIPCUNC); - m_header.filename_length = read_word (m_header.raw + ZIPCFNL); - m_header.extra_field_length = read_word (m_header.raw + ZIPCXTL); - m_header.file_comment_length = read_word (m_header.raw + ZIPCCML); - m_header.start_disk_number = read_word (m_header.raw + ZIPDSK); - m_header.internal_attributes = read_word (m_header.raw + ZIPINT); - m_header.external_attributes = read_dword(m_header.raw + ZIPEXT); - m_header.local_header_offset = read_dword(m_header.raw + ZIPOFST); - m_header.filename = reinterpret_cast(m_header.raw + ZIPCFN); - - // make sure we have enough data - m_header.rawlength += m_header.filename_length; - m_header.rawlength += m_header.extra_field_length; - m_header.rawlength += m_header.file_comment_length; - if (m_cd_pos + m_header.rawlength > m_ecd.cd_size) - return nullptr; - - // NULL terminate the filename - m_header.saved = m_header.raw[ZIPCFN + m_header.filename_length]; - m_header.raw[ZIPCFN + m_header.filename_length] = 0; - - // advance the position - m_cd_pos += m_header.rawlength; - return &m_header; + // advance the position + m_cd_pos += rawlength; + + // copy the filename filename + bool const is_dir((m_header.filename_length > 0) && (m_header.filename[m_header.filename_length - 1] == '/')); + filename.assign(m_header.filename, m_header.filename_length - (is_dir ? 1 : 0)); + + // check to see if it matches query + bool const crcmatch(search_crc == m_header.crc); + const bool namematch(!core_stricmp(search_filename.c_str(), filename.c_str())); + + bool const found = ((!matchcrc && !matchname) || !is_dir) && (!matchcrc || crcmatch) && (!matchname || namematch); + if (found) + { + m_curr_is_dir = is_dir; + m_curr_name = std::move(filename); + return 0; + } + } + return -1; } @@ -447,22 +468,22 @@ const zip_file::file_header *zip_file_impl::next_file() * @return A zip_error. */ -zip_file::error zip_file_impl::decompress(void *buffer, UINT32 length) +archive_file::error zip_file_impl::decompress(void *buffer, std::uint32_t length) { - zip_file::error ziperr; + archive_file::error ziperr; std::uint64_t offset; // if we don't have enough buffer, error if (length < m_header.uncompressed_length) - return zip_file::error::BUFFER_TOO_SMALL; + return archive_file::error::BUFFER_TOO_SMALL; // make sure the info in the header aligns with what we know if (m_header.start_disk_number != m_ecd.disk_number) - return zip_file::error::UNSUPPORTED; + return archive_file::error::UNSUPPORTED; // get the compressed data offset ziperr = get_compressed_data_offset(offset); - if (ziperr != zip_file::error::NONE) + if (ziperr != archive_file::error::NONE) return ziperr; // handle compression types @@ -477,7 +498,7 @@ zip_file::error zip_file_impl::decompress(void *buffer, UINT32 length) break; default: - ziperr = zip_file::error::UNSUPPORTED; + ziperr = archive_file::error::UNSUPPORTED; break; } return ziperr; @@ -503,11 +524,11 @@ zip_file::error zip_file_impl::decompress(void *buffer, UINT32 length) * @return The ecd. */ -zip_file::error zip_file_impl::read_ecd() +archive_file::error zip_file_impl::read_ecd() { // make sure the file handle is open auto const ziperr = reopen(); - if (ziperr != zip_file::error::NONE) + if (ziperr != archive_file::error::NONE) return ziperr; // we may need multiple tries @@ -521,13 +542,13 @@ zip_file::error zip_file_impl::read_ecd() // allocate buffer std::unique_ptr buffer; try { buffer.reset(new std::uint8_t[buflen + 1]); } - catch (...) { return zip_file::error::OUT_OF_MEMORY; } + catch (...) { return archive_file::error::OUT_OF_MEMORY; } // read in one buffers' worth of data std::uint32_t read_length; auto const error = m_file->read(&buffer[0], m_length - buflen, buflen, read_length); if (error != osd_file::error::NONE || read_length != buflen) - return zip_file::error::FILE_ERROR; + return archive_file::error::FILE_ERROR; // find the ECD signature std::int32_t offset; @@ -556,16 +577,16 @@ zip_file::error zip_file_impl::read_ecd() m_ecd.cd_start_disk_offset = read_dword(&m_ecd.raw[ZIPEOFST]); m_ecd.comment_length = read_word (&m_ecd.raw[ZIPECOML]); m_ecd.comment = reinterpret_cast(&m_ecd.raw[ZIPECOM]); - return zip_file::error::NONE; + return archive_file::error::NONE; } // didn't find it; free this buffer and expand our search if (buflen < m_length) buflen *= 2; else - return zip_file::error::BAD_SIGNATURE; + return archive_file::error::BAD_SIGNATURE; } - return zip_file::error::OUT_OF_MEMORY; + return archive_file::error::OUT_OF_MEMORY; } @@ -585,25 +606,25 @@ zip_file::error zip_file_impl::read_ecd() * @return The compressed data offset. */ -zip_file::error zip_file_impl::get_compressed_data_offset(std::uint64_t &offset) +archive_file::error zip_file_impl::get_compressed_data_offset(std::uint64_t &offset) { // make sure the file handle is open auto const ziperr = reopen(); - if (ziperr != zip_file::error::NONE) + if (ziperr != archive_file::error::NONE) return ziperr; // now go read the fixed-sized part of the local file header std::uint32_t read_length; auto const error = m_file->read(&m_buffer[0], m_header.local_header_offset, ZIPNAME, read_length); if (error != osd_file::error::NONE || read_length != ZIPNAME) - return (error == osd_file::error::NONE) ? zip_file::error::FILE_TRUNCATED : zip_file::error::FILE_ERROR; + return (error == osd_file::error::NONE) ? archive_file::error::FILE_TRUNCATED : archive_file::error::FILE_ERROR; /* compute the final offset */ offset = m_header.local_header_offset + ZIPNAME; offset += read_word(&m_buffer[ZIPFNLN]); offset += read_word(&m_buffer[ZIPXTRALN]); - return zip_file::error::NONE; + return archive_file::error::NONE; } @@ -630,18 +651,18 @@ zip_file::error zip_file_impl::get_compressed_data_offset(std::uint64_t &offset) * @return A zip_error. */ -zip_file::error zip_file_impl::decompress_data_type_0(std::uint64_t offset, void *buffer, std::uint32_t length) +archive_file::error zip_file_impl::decompress_data_type_0(std::uint64_t offset, void *buffer, std::uint32_t length) { std::uint32_t read_length; // the data is uncompressed; just read it auto const filerr = m_file->read(buffer, offset, m_header.compressed_length, read_length); if (filerr != osd_file::error::NONE) - return zip_file::error::FILE_ERROR; + return archive_file::error::FILE_ERROR; else if (read_length != m_header.compressed_length) - return zip_file::error::FILE_TRUNCATED; + return archive_file::error::FILE_TRUNCATED; else - return zip_file::error::NONE; + return archive_file::error::NONE; } @@ -663,14 +684,14 @@ zip_file::error zip_file_impl::decompress_data_type_0(std::uint64_t offset, void * @return A zip_error. */ -zip_file::error zip_file_impl::decompress_data_type_8(std::uint64_t offset, void *buffer, std::uint32_t length) +archive_file::error zip_file_impl::decompress_data_type_8(std::uint64_t offset, void *buffer, std::uint32_t length) { std::uint32_t input_remaining = m_header.compressed_length; int zerr; // make sure we don't need a newer mechanism if (m_header.version_needed > 0x14) - return zip_file::error::UNSUPPORTED; + return archive_file::error::UNSUPPORTED; /* reset the stream */ z_stream stream; @@ -681,7 +702,7 @@ zip_file::error zip_file_impl::decompress_data_type_8(std::uint64_t offset, void // initialize the decompressor zerr = inflateInit2(&stream, -MAX_WBITS); if (zerr != Z_OK) - return zip_file::error::DECOMPRESS_ERROR; + return archive_file::error::DECOMPRESS_ERROR; // loop until we're done while (1) @@ -692,7 +713,7 @@ zip_file::error zip_file_impl::decompress_data_type_8(std::uint64_t offset, void if (filerr != osd_file::error::NONE) { inflateEnd(&stream); - return zip_file::error::FILE_ERROR; + return archive_file::error::FILE_ERROR; } offset += read_length; @@ -700,7 +721,7 @@ zip_file::error zip_file_impl::decompress_data_type_8(std::uint64_t offset, void if (read_length == 0 && input_remaining > 0) { inflateEnd(&stream); - return zip_file::error::FILE_TRUNCATED; + return archive_file::error::FILE_TRUNCATED; } // fill out the input data @@ -719,26 +740,34 @@ zip_file::error zip_file_impl::decompress_data_type_8(std::uint64_t offset, void if (zerr != Z_OK) { inflateEnd(&stream); - return zip_file::error::DECOMPRESS_ERROR; + return archive_file::error::DECOMPRESS_ERROR; } } // finish decompression zerr = inflateEnd(&stream); if (zerr != Z_OK) - return zip_file::error::DECOMPRESS_ERROR; + return archive_file::error::DECOMPRESS_ERROR; /* if anything looks funny, report an error */ if (stream.avail_out > 0 || input_remaining > 0) - return zip_file::error::DECOMPRESS_ERROR; + return archive_file::error::DECOMPRESS_ERROR; - return zip_file::error::NONE; + return archive_file::error::NONE; } } // anonymous namespace +/*************************************************************************** + un7z.cpp TRAMPOLINES +***************************************************************************/ + +void m7z_file_cache_clear(); + + + /*************************************************************************** ZIP FILE ACCESS ***************************************************************************/ @@ -758,10 +787,10 @@ zip_file::error zip_file_impl::decompress_data_type_8(std::uint64_t offset, void * @return A zip_error. */ -zip_file::error zip_file::open(const std::string &filename, ptr &zip) +archive_file::error archive_file::open_zip(const std::string &filename, ptr &result) { // ensure we start with a NULL result - zip.reset(); + result.reset(); // see if we are in the cache, and reopen if so zip_file_impl::ptr newimpl(zip_file_impl::find_cached(filename)); @@ -777,7 +806,7 @@ zip_file::error zip_file::open(const std::string &filename, ptr &zip) try { - zip = std::make_unique(std::move(newimpl)); + result = std::make_unique(std::move(newimpl)); return error::NONE; } catch (...) @@ -793,18 +822,15 @@ zip_file::error zip_file::open(const std::string &filename, ptr &zip) cache and free all memory -------------------------------------------------*/ -/** - * @fn void zip_file_cache_clear(void) - * - * @brief Zip file cache clear. - */ - -void zip_file::cache_clear() +void archive_file::cache_clear() { zip_file_impl::cache_clear(); + m7z_file_cache_clear(); } -zip_file::~zip_file() +archive_file::~archive_file() { } + +} // namespace util -- cgit v1.2.3-70-g09d2