/*************************************************************************/ /* file_access_zip.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ /* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ /* the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #ifdef MINIZIP_ENABLED #include "file_access_zip.h" #include "core/os/file_access.h" #include "core/os/copymem.h" ZipArchive* ZipArchive::instance = NULL; extern "C" { static void* godot_open(void* data, const char* p_fname, int mode) { if (mode & ZLIB_FILEFUNC_MODE_WRITE) { return NULL; }; FileAccess* f = (FileAccess*)data; f->open(p_fname, FileAccess::READ); return f->is_open()?data:NULL; }; static uLong godot_read(void* data, void* fdata, void* buf, uLong size) { FileAccess* f = (FileAccess*)data; f->get_buffer((uint8_t*)buf, size); return size; }; static uLong godot_write(voidpf opaque, voidpf stream, const void* buf, uLong size) { return 0; }; static long godot_tell (voidpf opaque, voidpf stream) { FileAccess* f = (FileAccess*)opaque; return f->get_pos(); }; static long godot_seek(voidpf opaque, voidpf stream, uLong offset, int origin) { FileAccess* f = (FileAccess*)opaque; int pos = offset; switch (origin) { case ZLIB_FILEFUNC_SEEK_CUR: pos = f->get_pos() + offset; break; case ZLIB_FILEFUNC_SEEK_END: pos = f->get_len() + offset; break; default: break; }; f->seek(pos); return 0; }; static int godot_close(voidpf opaque, voidpf stream) { FileAccess* f = (FileAccess*)opaque; f->close(); return 0; }; static int godot_testerror(voidpf opaque, voidpf stream) { FileAccess* f = (FileAccess*)opaque; return f->get_error()!=OK?1:0; }; static voidpf godot_alloc(voidpf opaque, uInt items, uInt size) { return memalloc(items * size); }; static void godot_free(voidpf opaque, voidpf address) { memfree(address); }; }; // extern "C" void ZipArchive::close_handle(unzFile p_file) const { ERR_FAIL_COND(!p_file); FileAccess* f = (FileAccess*)unzGetOpaque(p_file); unzCloseCurrentFile(p_file); unzClose(p_file); memdelete(f); }; unzFile ZipArchive::get_file_handle(String p_file) const { ERR_FAIL_COND_V(!file_exists(p_file), NULL); File file = files[p_file]; FileAccess* f = FileAccess::open(packages[file.package].filename, FileAccess::READ); ERR_FAIL_COND_V(!f, NULL); zlib_filefunc_def io; zeromem(&io, sizeof(io)); io.opaque = f; io.zopen_file = godot_open; io.zread_file = godot_read; io.zwrite_file = godot_write; io.ztell_file = godot_tell; io.zseek_file = godot_seek; io.zclose_file = godot_close; io.zerror_file = godot_testerror; io.alloc_mem = godot_alloc; io.free_mem = godot_free; unzFile pkg = unzOpen2(packages[file.package].filename.utf8().get_data(), &io); ERR_FAIL_COND_V(!pkg, NULL); int unz_err = unzGoToFilePos(pkg, &file.file_pos); ERR_FAIL_COND_V(unz_err != UNZ_OK, NULL); if (unzOpenCurrentFile(pkg) != UNZ_OK) { unzClose(pkg); ERR_FAIL_V(NULL); }; return pkg; }; bool ZipArchive::try_open_pack(const String& p_name) { //printf("opening zip pack %ls, %i, %i\n", p_name.c_str(), p_name.extension().nocasecmp_to("zip"), p_name.extension().nocasecmp_to("pcz")); if (p_name.get_extension().nocasecmp_to("zip") != 0 && p_name.get_extension().nocasecmp_to("pcz") != 0) return false; zlib_filefunc_def io; FileAccess* f = FileAccess::open(p_name, FileAccess::READ); if (!f) return false; io.opaque = f; io.zopen_file = godot_open; io.zread_file = godot_read; io.zwrite_file = godot_write; io.ztell_file = godot_tell; io.zseek_file = godot_seek; io.zclose_file = godot_close; io.zerror_file = godot_testerror; unzFile zfile = unzOpen2(p_name.utf8().get_data(), &io); ERR_FAIL_COND_V(!zfile, false); unz_global_info64 gi; int err = unzGetGlobalInfo64(zfile, &gi); ERR_FAIL_COND_V(err!=UNZ_OK, false); Package pkg; pkg.filename = p_name; pkg.zfile = zfile; packages.push_back(pkg); int pkg_num = packages.size()-1; for (unsigned int i=0;iadd_path(p_name, fname, 1, 0, md5, this); //printf("packed data add path %ls, %ls\n", p_name.c_str(), fname.c_str()); if ((i+1)get_file_handle(p_path); ERR_FAIL_COND_V(!zfile, FAILED); int err = unzGetCurrentFileInfo64(zfile,&file_info,NULL,0,NULL,0,NULL,0); ERR_FAIL_COND_V(err != UNZ_OK, FAILED); return OK; }; void FileAccessZip::close() { if (!zfile) return; ZipArchive* arch = ZipArchive::get_singleton(); ERR_FAIL_COND(!arch); arch->close_handle(zfile); zfile = NULL; }; bool FileAccessZip::is_open() const { return zfile != NULL; }; void FileAccessZip::seek(size_t p_position) { ERR_FAIL_COND(!zfile); unzSeekCurrentFile(zfile, p_position); }; void FileAccessZip::seek_end(int64_t p_position) { ERR_FAIL_COND(!zfile); unzSeekCurrentFile(zfile, get_len() + p_position); }; size_t FileAccessZip::get_pos() const { ERR_FAIL_COND_V(!zfile, 0); return unztell(zfile); }; size_t FileAccessZip::get_len() const { ERR_FAIL_COND_V(!zfile, 0); return file_info.uncompressed_size; }; bool FileAccessZip::eof_reached() const { ERR_FAIL_COND_V(!zfile, true); return at_eof; }; uint8_t FileAccessZip::get_8() const { uint8_t ret = 0; get_buffer(&ret, 1); return ret; }; int FileAccessZip::get_buffer(uint8_t *p_dst,int p_length) const { ERR_FAIL_COND_V(!zfile, -1); at_eof = unzeof(zfile); if (at_eof) return 0; int read = unzReadCurrentFile(zfile, p_dst, p_length); ERR_FAIL_COND_V(read < 0, read); if (read < p_length) at_eof = true; return read; }; Error FileAccessZip::get_error() const { if (!zfile) { return ERR_UNCONFIGURED; }; if (eof_reached()) { return ERR_FILE_EOF; }; return OK; }; void FileAccessZip::store_8(uint8_t p_dest) { ERR_FAIL(); }; bool FileAccessZip::file_exists(const String& p_name) { return false; }; FileAccessZip::FileAccessZip(const String& p_path, const PackedData::PackedFile& p_file) { zfile = NULL; _open(p_path, FileAccess::READ); }; FileAccessZip::~FileAccessZip() { close(); }; #endif