diff --git a/cocos/base/ZipUtils.cpp b/cocos/base/ZipUtils.cpp index 903231acd5..d9c14b5b1d 100644 --- a/cocos/base/ZipUtils.cpp +++ b/cocos/base/ZipUtils.cpp @@ -511,6 +511,7 @@ struct ZipEntryInfo class ZipFilePrivate { public: + std::string zipFileName; unzFile zipFile; std::mutex zipFileMtx; std::unique_ptr memfs; @@ -520,6 +521,110 @@ public: FileListContainer fileList; }; +// unzip overrides to support FileStream +long ZipFile_tell_file_func(voidpf opaque, voidpf stream) +{ + if (stream == nullptr) + return -1; + + auto* fs = (FileStream*)stream; + + return fs->tell(); +} + +long ZipFile_seek_file_func(voidpf opaque, voidpf stream, uint32_t offset, int origin) +{ + if (stream == nullptr) + return -1; + + auto* fs = (FileStream*)stream; + + return fs->seek((long)offset, origin); // must return 0 for success or -1 for error +} + +voidpf ZipFile_open_file_func(voidpf opaque, const char* filename, int mode) +{ + FileStream::Mode fsMode; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) + fsMode = FileStream::Mode::READ; + else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + fsMode = FileStream::Mode::APPEND; + else if (mode & ZLIB_FILEFUNC_MODE_CREATE) + fsMode = FileStream::Mode::WRITE; + else + return nullptr; + + return FileUtils::getInstance()->openFileStream(filename, fsMode); +} + +voidpf ZipFile_opendisk_file_func(voidpf opaque, voidpf stream, uint32_t number_disk, int mode) +{ + if (stream == nullptr) + return nullptr; + + auto* zipFileInfo = (ZipFilePrivate*)opaque; + std::string diskFilename = zipFileInfo->zipFileName; + + const auto pos = diskFilename.rfind('.', std::string::npos); + + if (pos != std::string::npos && pos != 0) + { + const size_t bufferSize = 5; + char extensionBuffer[bufferSize]; + snprintf(&extensionBuffer[0], bufferSize, ".z%02u", number_disk + 1); + diskFilename.replace(pos, std::min((size_t)4, zipFileInfo->zipFileName.size() - pos), extensionBuffer); + return ZipFile_open_file_func(opaque, diskFilename.c_str(), mode); + } + + return nullptr; +} + +uint32_t ZipFile_read_file_func(voidpf opaque, voidpf stream, void* buf, uint32_t size) +{ + if (stream == nullptr) + return (uint32_t)-1; + + auto* fs = (FileStream*)stream; + return fs->read(buf, size); +} + +uint32_t ZipFile_write_file_func(voidpf opaque, voidpf stream, const void* buf, uint32_t size) +{ + if (stream == nullptr) + return (uint32_t)-1; + + auto* fs = (FileStream*)stream; + return fs->write(buf, size); +} + +int ZipFile_close_file_func(voidpf opaque, voidpf stream) +{ + if (stream == nullptr) + return -1; + + auto* fs = (FileStream*)stream; + return fs->close(); // 0 for success, -1 for error +} + +// THis isn't supported by FileStream, so just check if the stream is null and open +int ZipFile_error_file_func(voidpf opaque, voidpf stream) +{ + if (stream == nullptr) + { + return -1; + } + + auto* fs = (FileStream*)stream; + + if (fs->isOpen()) + { + return 0; + } + + return -1; +} +// End of Overrides + ZipFile *ZipFile::createWithBuffer(const void* buffer, uLong size) { ZipFile *zip = new (std::nothrow) ZipFile(); @@ -534,13 +639,16 @@ ZipFile *ZipFile::createWithBuffer(const void* buffer, uLong size) ZipFile::ZipFile() : _data(new ZipFilePrivate) { + fillFunctionOverrides(); _data->zipFile = nullptr; } ZipFile::ZipFile(const std::string &zipFile, const std::string &filter) : _data(new ZipFilePrivate) { - _data->zipFile = unzOpen(zipFile.c_str()); + fillFunctionOverrides(); + _data->zipFileName = zipFile; + _data->zipFile = unzOpen2(zipFile.c_str(), &_functionOverrides); setFilter(filter); } @@ -877,4 +985,17 @@ unsigned char* ZipFile::getFileDataFromZip(const std::string& zipFilePath, const return buffer; } +void ZipFile::fillFunctionOverrides() +{ + _functionOverrides.zopen_file = ZipFile_open_file_func; + _functionOverrides.zopendisk_file = ZipFile_opendisk_file_func; + _functionOverrides.zread_file = ZipFile_read_file_func; + _functionOverrides.zwrite_file = ZipFile_write_file_func; + _functionOverrides.ztell_file = ZipFile_tell_file_func; + _functionOverrides.zseek_file = ZipFile_seek_file_func; + _functionOverrides.zclose_file = ZipFile_close_file_func; + _functionOverrides.zerror_file = ZipFile_error_file_func; + _functionOverrides.opaque = _data; +} + NS_CC_END diff --git a/cocos/base/ZipUtils.h b/cocos/base/ZipUtils.h index 8bc861f4ee..664a5333e8 100644 --- a/cocos/base/ZipUtils.h +++ b/cocos/base/ZipUtils.h @@ -29,6 +29,8 @@ THE SOFTWARE. #define __SUPPORT_ZIPUTILS_H__ /// @cond DO_NOT_SHOW +#include + #include "platform/CCPlatformMacros.h" #include "platform/CCFileUtils.h" #include @@ -316,6 +318,7 @@ namespace cocos2d CC_DEPRECATED() static unsigned char* getFileDataFromZip(const std::string& zipFilePath, const std::string& filename, ssize_t* size); private: + void fillFunctionOverrides(); /* Only used internal for createWithBuffer() */ ZipFile(); @@ -324,6 +327,7 @@ namespace cocos2d /** Internal data like zip file pointer / file list array and so on */ ZipFilePrivate *_data; + zlib_filefunc_def _functionOverrides{}; }; } // end of namespace cocos2d diff --git a/cocos/platform/CCFileStream.h b/cocos/platform/CCFileStream.h index 68df1831d8..83cf790430 100644 --- a/cocos/platform/CCFileStream.h +++ b/cocos/platform/CCFileStream.h @@ -19,14 +19,54 @@ public: APPEND, }; + /** + * Open a file + * @param path file to open + * @param mode File open mode, being READ | WRITE | APPEND + * @return true if successful, false if not + */ virtual bool open(const std::string& path, FileStream::Mode mode) = 0; + + /** + * Close a file stream + * @return 0 if successful, -1 if not + */ virtual int close() = 0; + /** + * Seek to position in a file stream + * @param offset how many bytes to move within the stream + * @param origin SEEK_SET | SEEK_CUR | SEEK_END + * @return 0 if successful, -1 if not + */ virtual int seek(long offset, int origin) = 0; + + /** + * Read data from file stream + * @param buf pointer to data + * @param size the amount of data to read in bytes + * @return amount of data read successfully, -1 if error + */ virtual int read(void* buf, unsigned int size) = 0; + /** + * Write data to file stream + * @param buf pointer to data + * @param size the amount of data to write in bytes + * @return amount of data written successfully, -1 if error + */ virtual int write(const void* buf, unsigned int size) = 0; + + /** + * Get the current position in the file stream + * @return current position, -1 if error + */ virtual int tell() = 0; + + /** + * Get status of file stream + * @return true if open, false if closed + */ virtual bool isOpen() const = 0; virtual operator bool() const { return isOpen(); }