summaryrefslogtreecommitdiff
path: root/core/io/file_access_zip.cpp
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2014-02-09 22:10:30 -0300
committerJuan Linietsky <reduzio@gmail.com>2014-02-09 22:10:30 -0300
commit0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac (patch)
tree276c4d099e178eb67fbd14f61d77b05e3808e9e3 /core/io/file_access_zip.cpp
parent0e49da1687bc8192ed210947da52c9e5c5f301bb (diff)
GODOT IS OPEN SOURCE
Diffstat (limited to 'core/io/file_access_zip.cpp')
-rw-r--r--core/io/file_access_zip.cpp367
1 files changed, 367 insertions, 0 deletions
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
new file mode 100644
index 0000000000..72e929619f
--- /dev/null
+++ b/core/io/file_access_zip.cpp
@@ -0,0 +1,367 @@
+/*************************************************************************/
+/* file_access_zip.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 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"
+
+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;
+};
+
+
+};
+
+
+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;
+
+ 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 pkg = unzOpen2(packages[file.package].filename.utf8().get_data(), &io);
+ ERR_FAIL_COND_V(!pkg, NULL);
+ unzGoToFilePos(pkg, &file.file_pos);
+ if (unzOpenCurrentFile(pkg) != UNZ_OK) {
+
+ unzClose(pkg);
+ ERR_FAIL_V(NULL);
+ };
+
+ return pkg;
+};
+
+bool ZipArchive::try_open_pack(const String& p_name) {
+
+ printf("opening pack %ls, %i, %i\n", p_name.c_str(), p_name.extension().nocasecmp_to("zip"), p_name.extension().nocasecmp_to("pcz"));
+ if (p_name.extension().nocasecmp_to("zip") != 0 && p_name.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;i<gi.number_entry;i++) {
+
+ char filename_inzip[256];
+
+ unz_file_info64 file_info;
+ err = unzGetCurrentFileInfo64(zfile,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
+ ERR_CONTINUE(err != UNZ_OK);
+
+ File f;
+ f.package = pkg_num;
+ unzGetFilePos(zfile, &f.file_pos);
+
+ String fname = String("res://") + filename_inzip;
+ files[fname] = f;
+
+ PackedData::get_singleton()->add_path(p_name, fname, 0, 0, this);
+
+ if ((i+1)<gi.number_entry) {
+ unzGoToNextFile(zfile);
+ };
+ };
+
+ return true;
+};
+
+bool ZipArchive::file_exists(String p_name) const {
+
+ return files.has(p_name);
+};
+
+FileAccess* ZipArchive::get_file(const String& p_path, PackedData::PackedFile* p_file) {
+
+ return memnew(FileAccessZip(p_path, *p_file));
+};
+
+
+ZipArchive* ZipArchive::get_singleton() {
+
+ if (instance == NULL) {
+ instance = memnew(ZipArchive);
+ };
+
+ return instance;
+};
+
+ZipArchive::ZipArchive() {
+
+ instance = this;
+ //fa_create_func = FileAccess::get_create_func();
+};
+
+ZipArchive::~ZipArchive() {
+
+ for (int i=0; i<packages.size(); i++) {
+
+ FileAccess* f = (FileAccess*)unzGetOpaque(packages[i].zfile);
+ unzClose(packages[i].zfile);
+ memdelete(f);
+ };
+
+ packages.clear();
+};
+
+
+Error FileAccessZip::_open(const String& p_path, int p_mode_flags) {
+
+ close();
+
+ ERR_FAIL_COND_V(p_mode_flags & FileAccess::WRITE, FAILED);
+ ZipArchive* arch = ZipArchive::get_singleton();
+ ERR_FAIL_COND_V(!arch, FAILED);
+ zfile = arch->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