summaryrefslogtreecommitdiff
path: root/core/io
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
parent0e49da1687bc8192ed210947da52c9e5c5f301bb (diff)
GODOT IS OPEN SOURCE
Diffstat (limited to 'core/io')
-rw-r--r--core/io/SCsub9
-rw-r--r--core/io/base64.c110
-rw-r--r--core/io/base64.h11
-rw-r--r--core/io/compression.cpp91
-rw-r--r--core/io/compression.h53
-rw-r--r--core/io/config_file.cpp744
-rw-r--r--core/io/config_file.h63
-rw-r--r--core/io/crypt.h131
-rw-r--r--core/io/fastlz.c551
-rw-r--r--core/io/fastlz.h100
-rw-r--r--core/io/file_access_buffered.cpp184
-rw-r--r--core/io/file_access_buffered.h97
-rw-r--r--core/io/file_access_buffered_fa.h147
-rw-r--r--core/io/file_access_compressed.cpp421
-rw-r--r--core/io/file_access_compressed.h101
-rw-r--r--core/io/file_access_memory.cpp188
-rw-r--r--core/io/file_access_memory.h76
-rw-r--r--core/io/file_access_network.cpp566
-rw-r--r--core/io/file_access_network.h169
-rw-r--r--core/io/file_access_pack.cpp469
-rw-r--r--core/io/file_access_pack.h204
-rw-r--r--core/io/file_access_zip.cpp367
-rw-r--r--core/io/file_access_zip.h125
-rw-r--r--core/io/http_client.cpp641
-rw-r--r--core/io/http_client.h188
-rw-r--r--core/io/image_loader.cpp112
-rw-r--r--core/io/image_loader.h91
-rw-r--r--core/io/ioapi.c235
-rw-r--r--core/io/ioapi.h199
-rw-r--r--core/io/ip.cpp270
-rw-r--r--core/io/ip.h91
-rw-r--r--core/io/ip_address.cpp60
-rw-r--r--core/io/ip_address.h50
-rw-r--r--core/io/json.cpp477
-rw-r--r--core/io/json.h81
-rw-r--r--core/io/marshalls.cpp1195
-rw-r--r--core/io/marshalls.h190
-rw-r--r--core/io/md5.cpp269
-rw-r--r--core/io/md5.h61
-rw-r--r--core/io/object_format_binary.cpp1491
-rw-r--r--core/io/object_format_binary.h158
-rw-r--r--core/io/object_format_xml.cpp3190
-rw-r--r--core/io/object_format_xml.h196
-rw-r--r--core/io/object_loader.cpp84
-rw-r--r--core/io/object_loader.h76
-rw-r--r--core/io/object_saver.cpp157
-rw-r--r--core/io/object_saver.h128
-rw-r--r--core/io/object_saver_base.cpp150
-rw-r--r--core/io/object_saver_base.h76
-rw-r--r--core/io/packet_peer.cpp255
-rw-r--r--core/io/packet_peer.h94
-rw-r--r--core/io/resource_format_binary.cpp1918
-rw-r--r--core/io/resource_format_binary.h184
-rw-r--r--core/io/resource_format_xml.cpp2557
-rw-r--r--core/io/resource_format_xml.h155
-rw-r--r--core/io/resource_loader.cpp378
-rw-r--r--core/io/resource_loader.h114
-rw-r--r--core/io/resource_saver.cpp127
-rw-r--r--core/io/resource_saver.h95
-rw-r--r--core/io/stream_peer.cpp126
-rw-r--r--core/io/stream_peer.h58
-rw-r--r--core/io/stream_peer_tcp.cpp56
-rw-r--r--core/io/stream_peer_tcp.h75
-rw-r--r--core/io/tcp_server.cpp62
-rw-r--r--core/io/tcp_server.h59
-rw-r--r--core/io/translation_loader_po.cpp201
-rw-r--r--core/io/translation_loader_po.h46
-rw-r--r--core/io/unzip.c2216
-rw-r--r--core/io/unzip.h445
-rw-r--r--core/io/xml_parser.cpp576
-rw-r--r--core/io/xml_parser.h123
-rw-r--r--core/io/zip.c2004
-rw-r--r--core/io/zip.h361
-rw-r--r--core/io/zip_io.h129
74 files changed, 27307 insertions, 0 deletions
diff --git a/core/io/SCsub b/core/io/SCsub
new file mode 100644
index 0000000000..5aecb4b915
--- /dev/null
+++ b/core/io/SCsub
@@ -0,0 +1,9 @@
+Import('env')
+
+env.add_source_files(env.core_sources,"*.cpp")
+env.add_source_files(env.core_sources,"*.c")
+#env.core_sources.append("io/fastlz.c")
+
+Export('env')
+
+
diff --git a/core/io/base64.c b/core/io/base64.c
new file mode 100644
index 0000000000..0c799e9f07
--- /dev/null
+++ b/core/io/base64.c
@@ -0,0 +1,110 @@
+#include <string.h>
+
+char b64string[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+long base64_encode (to, from, len)
+ char *to, *from;
+ unsigned int len;
+{
+ char *fromp = from;
+ char *top = to;
+ unsigned char cbyte;
+ unsigned char obyte;
+ char end[3];
+
+ for (; len >= 3; len -= 3) {
+ cbyte = *fromp++;
+ *top++ = b64string[(int)(cbyte >> 2)];
+ obyte = (cbyte << 4) & 0x30; /* 0011 0000 */
+
+ cbyte = *fromp++;
+ obyte |= (cbyte >> 4); /* 0000 1111 */
+ *top++ = b64string[(int)obyte];
+ obyte = (cbyte << 2) & 0x3C; /* 0011 1100 */
+
+ cbyte = *fromp++;
+ obyte |= (cbyte >> 6); /* 0000 0011 */
+ *top++ = b64string[(int)obyte];
+ *top++ = b64string[(int)(cbyte & 0x3F)];/* 0011 1111 */
+ }
+
+ if (len) {
+ end[0] = *fromp++;
+ if (--len) end[1] = *fromp++; else end[1] = 0;
+ end[2] = 0;
+
+ cbyte = end[0];
+ *top++ = b64string[(int)(cbyte >> 2)];
+ obyte = (cbyte << 4) & 0x30; /* 0011 0000 */
+
+ cbyte = end[1];
+ obyte |= (cbyte >> 4);
+ *top++ = b64string[(int)obyte];
+ obyte = (cbyte << 2) & 0x3C; /* 0011 1100 */
+
+ if (len) *top++ = b64string[(int)obyte];
+ else *top++ = '=';
+ *top++ = '=';
+ }
+ *top = 0;
+ return top - to;
+}
+
+/* badchar(): check if c is decent; puts either the */
+/* location of c or null into p. */
+#define badchar(c,p) (!(p = memchr(b64string, c, 64)))
+
+long base64_decode (to, from, len)
+ char *to, *from;
+ unsigned int len;
+{
+ char *fromp = from;
+ char *top = to;
+ char *p;
+ unsigned char cbyte;
+ unsigned char obyte;
+ int padding = 0;
+
+ for (; len >= 4; len -= 4) {
+ if ((cbyte = *fromp++) == '=') cbyte = 0;
+ else {
+ if (badchar(cbyte, p)) return -1;
+ cbyte = (p - b64string);
+ }
+ obyte = cbyte << 2; /* 1111 1100 */
+
+ if ((cbyte = *fromp++) == '=') cbyte = 0;
+ else {
+ if (badchar(cbyte, p)) return -1;
+ cbyte = p - b64string;
+ }
+ obyte |= cbyte >> 4; /* 0000 0011 */
+ *top++ = obyte;
+
+ obyte = cbyte << 4; /* 1111 0000 */
+ if ((cbyte = *fromp++) == '=') { cbyte = 0; padding++; }
+ else {
+ padding = 0;
+ if (badchar (cbyte, p)) return -1;
+ cbyte = p - b64string;
+ }
+ obyte |= cbyte >> 2; /* 0000 1111 */
+ *top++ = obyte;
+
+ obyte = cbyte << 6; /* 1100 0000 */
+ if ((cbyte = *fromp++) == '=') { cbyte = 0; padding++; }
+ else {
+ padding = 0;
+ if (badchar (cbyte, p)) return -1;
+ cbyte = p - b64string;
+ }
+ obyte |= cbyte; /* 0011 1111 */
+ *top++ = obyte;
+ }
+
+ *top = 0;
+ if (len) return -1;
+ return (top - to) - padding;
+}
+
diff --git a/core/io/base64.h b/core/io/base64.h
new file mode 100644
index 0000000000..b70b387983
--- /dev/null
+++ b/core/io/base64.h
@@ -0,0 +1,11 @@
+#ifndef BASE64_H
+#define BASE64_H
+
+extern "C" {
+
+uint32_t base64_encode (char* to, char* from, uint32_t len);
+uint32_t base64_decode (char* to, char* from, uint32_t len);
+
+};
+
+#endif /* BASE64_H */
diff --git a/core/io/compression.cpp b/core/io/compression.cpp
new file mode 100644
index 0000000000..156767d241
--- /dev/null
+++ b/core/io/compression.cpp
@@ -0,0 +1,91 @@
+/*************************************************************************/
+/* compression.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. */
+/*************************************************************************/
+#include "compression.h"
+
+#include "fastlz.h"
+#include "os/copymem.h"
+
+int Compression::compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size,Mode p_mode) {
+
+ switch(p_mode) {
+ case MODE_FASTLZ: {
+
+ if (p_src_size<16) {
+ uint8_t src[16];
+ zeromem(&src[p_src_size],16-p_src_size);
+ copymem(src,p_src,p_src_size);
+ return fastlz_compress(src,16,p_dst);
+ } else {
+ return fastlz_compress(p_src,p_src_size,p_dst);
+ }
+
+ } break;
+ }
+
+ ERR_FAIL_V(-1);
+}
+
+int Compression::get_max_compressed_buffer_size(int p_src_size,Mode p_mode){
+
+ switch(p_mode) {
+ case MODE_FASTLZ: {
+
+
+ int ss = p_src_size+p_src_size*6/100;
+ if (ss<66)
+ ss=66;
+ return ss;
+
+ } break;
+ }
+
+ ERR_FAIL_V(-1);
+
+}
+
+
+
+void Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size,Mode p_mode){
+
+ switch(p_mode) {
+ case MODE_FASTLZ: {
+
+ if (p_dst_max_size<16) {
+ uint8_t dst[16];
+ fastlz_decompress(p_src,p_src_size,dst,16);
+ copymem(p_dst,dst,p_dst_max_size);
+ } else {
+ fastlz_decompress(p_src,p_src_size,p_dst,p_dst_max_size);
+ }
+ return;
+ } break;
+ }
+
+ ERR_FAIL();
+}
diff --git a/core/io/compression.h b/core/io/compression.h
new file mode 100644
index 0000000000..70742d42d6
--- /dev/null
+++ b/core/io/compression.h
@@ -0,0 +1,53 @@
+/*************************************************************************/
+/* compression.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef COMPRESSION_H
+#define COMPRESSION_H
+
+#include "typedefs.h"
+
+class Compression
+{
+public:
+
+ enum Mode {
+ MODE_FASTLZ,
+ MODE_DEFLATE
+ };
+
+
+ static int compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size,Mode p_mode=MODE_FASTLZ);
+ static int get_max_compressed_buffer_size(int p_src_size,Mode p_mode=MODE_FASTLZ);
+ static void decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size,Mode p_mode=MODE_FASTLZ);
+
+ Compression();
+};
+
+
+
+#endif // COMPRESSION_H
diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp
new file mode 100644
index 0000000000..45e8cf69ab
--- /dev/null
+++ b/core/io/config_file.cpp
@@ -0,0 +1,744 @@
+/*************************************************************************/
+/* config_file.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. */
+/*************************************************************************/
+#include "config_file.h"
+#include "os/keyboard.h"
+#include "os/file_access.h"
+
+StringArray ConfigFile::_get_sections() const {
+
+ List<String> s;
+ get_sections(&s);
+ StringArray arr;
+ arr.resize(s.size());
+ int idx=0;
+ for(const List<String>::Element *E=s.front();E;E=E->next()) {
+
+ arr.set(idx++,E->get());
+ }
+
+ return arr;
+}
+
+StringArray ConfigFile::_get_section_keys(const String& p_section) const{
+
+ List<String> s;
+ get_section_keys(p_section,&s);
+ StringArray arr;
+ arr.resize(s.size());
+ int idx=0;
+ for(const List<String>::Element *E=s.front();E;E=E->next()) {
+
+ arr.set(idx++,E->get());
+ }
+
+ return arr;
+
+}
+
+
+void ConfigFile::set_value(const String& p_section, const String& p_key, const Variant& p_value){
+
+ if (p_value.get_type()==Variant::NIL) {
+ //erase
+ if (!values.has(p_section))
+ return; // ?
+ values[p_section].erase(p_key);
+ if (values[p_section].empty()) {
+ values.erase(p_section);
+ }
+
+ } else {
+ if (!values.has(p_section)) {
+ values[p_section]=Map<String, Variant>();
+ }
+
+ values[p_section][p_key]=p_value;
+
+ }
+
+}
+Variant ConfigFile::get_value(const String& p_section, const String& p_key) const{
+
+ ERR_FAIL_COND_V(!values.has(p_section),Variant());
+ ERR_FAIL_COND_V(!values[p_section].has(p_key),Variant());
+ return values[p_section][p_key];
+
+}
+
+bool ConfigFile::has_section(const String& p_section) const {
+
+ return values.has(p_section);
+}
+bool ConfigFile::has_section_key(const String& p_section,const String& p_key) const {
+
+ if (!values.has(p_section))
+ return false;
+ return values[p_section].has(p_key);
+}
+
+void ConfigFile::get_sections(List<String> *r_sections) const{
+
+ for(const Map< String, Map<String, Variant> >::Element *E=values.front();E;E=E->next()) {
+ r_sections->push_back(E->key());
+ }
+}
+void ConfigFile::get_section_keys(const String& p_section,List<String> *r_keys) const{
+
+ ERR_FAIL_COND(!values.has(p_section));
+
+ for(const Map<String, Variant> ::Element *E=values[p_section].front();E;E=E->next()) {
+ r_keys->push_back(E->key());
+ }
+
+}
+
+static String _encode_variant(const Variant& p_variant) {
+
+ switch(p_variant.get_type()) {
+
+ case Variant::BOOL: {
+ bool val = p_variant;
+ return (val?"true":"false");
+ } break;
+ case Variant::INT: {
+ int val = p_variant;
+ return itos(val);
+ } break;
+ case Variant::REAL: {
+ float val = p_variant;
+ return rtos(val)+(val==int(val)?".0":"");
+ } break;
+ case Variant::STRING: {
+ String val = p_variant;
+ return "\""+val.xml_escape()+"\"";
+ } break;
+ case Variant::COLOR: {
+
+ Color val = p_variant;
+ return "#"+val.to_html();
+ } break;
+ case Variant::STRING_ARRAY:
+ case Variant::INT_ARRAY:
+ case Variant::REAL_ARRAY:
+ case Variant::ARRAY: {
+ Array arr = p_variant;
+ String str="[";
+ for(int i=0;i<arr.size();i++) {
+
+ if (i>0)
+ str+=", ";
+ str+=_encode_variant(arr[i]);
+ }
+ str+="]";
+ return str;
+ } break;
+ case Variant::DICTIONARY: {
+ Dictionary d = p_variant;
+ String str="{";
+ List<Variant> keys;
+ d.get_key_list(&keys);
+ for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+ if (E!=keys.front())
+ str+=", ";
+ str+=_encode_variant(E->get());
+ str+=":";
+ str+=_encode_variant(d[E->get()]);
+
+ }
+ str+="}";
+ return str;
+ } break;
+ case Variant::IMAGE: {
+ String str="img(";
+
+ Image img=p_variant;
+ if (!img.empty()) {
+
+ String format;
+ switch(img.get_format()) {
+
+ case Image::FORMAT_GRAYSCALE: format="grayscale"; break;
+ case Image::FORMAT_INTENSITY: format="intensity"; break;
+ case Image::FORMAT_GRAYSCALE_ALPHA: format="grayscale_alpha"; break;
+ case Image::FORMAT_RGB: format="rgb"; break;
+ case Image::FORMAT_RGBA: format="rgba"; break;
+ case Image::FORMAT_INDEXED : format="indexed"; break;
+ case Image::FORMAT_INDEXED_ALPHA: format="indexed_alpha"; break;
+ case Image::FORMAT_BC1: format="bc1"; break;
+ case Image::FORMAT_BC2: format="bc2"; break;
+ case Image::FORMAT_BC3: format="bc3"; break;
+ case Image::FORMAT_BC4: format="bc4"; break;
+ case Image::FORMAT_BC5: format="bc5"; break;
+ case Image::FORMAT_CUSTOM: format="custom custom_size="+itos(img.get_data().size())+""; break;
+ default: {}
+ }
+
+ str+=format+", ";
+ str+=itos(img.get_mipmaps())+", ";
+ str+=itos(img.get_width())+", ";
+ str+=itos(img.get_height())+", ";
+ DVector<uint8_t> data = img.get_data();
+ int ds=data.size();
+ DVector<uint8_t>::Read r = data.read();
+ for(int i=0;i<ds;i++) {
+ uint8_t byte = r[i];
+ const char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+ char bstr[3]={ hex[byte>>4], hex[byte&0xF], 0};
+ str+=bstr;
+ }
+ }
+ str+=")";
+ return str;
+ } break;
+ case Variant::INPUT_EVENT: {
+
+ InputEvent ev = p_variant;
+
+ switch(ev.type) {
+
+ case InputEvent::KEY: {
+
+ String mods;
+ if (ev.key.mod.control)
+ mods+="C";
+ if (ev.key.mod.shift)
+ mods+="S";
+ if (ev.key.mod.alt)
+ mods+="A";
+ if (ev.key.mod.meta)
+ mods+="M";
+ if (mods!="")
+ mods=", "+mods;
+
+ return "key("+keycode_get_string(ev.key.scancode)+mods+")";
+ } break;
+ case InputEvent::MOUSE_BUTTON: {
+
+ return "mbutton("+itos(ev.device)+", "+itos(ev.mouse_button.button_index)+")";
+ } break;
+ case InputEvent::JOYSTICK_BUTTON: {
+
+ return "jbutton("+itos(ev.device)+", "+itos(ev.joy_button.button_index)+")";
+ } break;
+ case InputEvent::JOYSTICK_MOTION: {
+
+ return "jaxis("+itos(ev.device)+", "+itos(ev.joy_motion.axis)+")";
+ } break;
+ default: {
+
+ return "nil";
+ } break;
+
+ }
+ } break;
+ default: {}
+ }
+
+ return "nil"; //don't know wha to do with this
+}
+
+
+Error ConfigFile::save(const String& p_path){
+
+ Error err;
+ FileAccess *file = FileAccess::open(p_path,FileAccess::WRITE,&err);
+
+ if (err) {
+ return err;
+ }
+
+
+ for(Map< String, Map<String, Variant> >::Element *E=values.front();E;E=E->next()) {
+
+ if (E!=values.front())
+ file->store_string("\n");
+ file->store_string("["+E->key()+"]\n\n");
+
+ for(Map<String, Variant>::Element *F=E->get().front();F;F=F->next()) {
+
+ file->store_string(F->key()+"="+_encode_variant(F->get())+"\n");
+ }
+ }
+
+ memdelete(file);
+
+ return OK;
+}
+
+static Vector<String> _decode_params(const String& p_string) {
+
+ int begin=p_string.find("(");
+ ERR_FAIL_COND_V(begin==-1,Vector<String>());
+ begin++;
+ int end=p_string.find(")");
+ ERR_FAIL_COND_V(end<begin,Vector<String>());
+ return p_string.substr(begin,end-begin).split(",");
+}
+
+static String _get_chunk(const String& str,int &pos, int close_pos) {
+
+
+ enum {
+ MIN_COMMA,
+ MIN_COLON,
+ MIN_CLOSE,
+ MIN_QUOTE,
+ MIN_PARENTHESIS,
+ MIN_CURLY_OPEN,
+ MIN_OPEN
+ };
+
+ int min_pos=close_pos;
+ int min_what=MIN_CLOSE;
+
+#define TEST_MIN(m_how,m_what) \
+{\
+int res = str.find(m_how,pos);\
+if (res!=-1 && res < min_pos) {\
+ min_pos=res;\
+ min_what=m_what;\
+}\
+}\
+
+
+ TEST_MIN(",",MIN_COMMA);
+ TEST_MIN("[",MIN_OPEN);
+ TEST_MIN("{",MIN_CURLY_OPEN);
+ TEST_MIN("(",MIN_PARENTHESIS);
+ TEST_MIN("\"",MIN_QUOTE);
+
+ int end=min_pos;
+
+
+ switch(min_what) {
+
+ case MIN_COMMA: {
+ } break;
+ case MIN_CLOSE: {
+ //end because it's done
+ } break;
+ case MIN_QUOTE: {
+ end=str.find("\"",min_pos+1)+1;
+ ERR_FAIL_COND_V(end==-1,Variant());
+
+ } break;
+ case MIN_PARENTHESIS: {
+
+ end=str.find(")",min_pos+1)+1;
+ ERR_FAIL_COND_V(end==-1,Variant());
+
+ } break;
+ case MIN_OPEN: {
+ int level=1;
+ while(end<close_pos) {
+
+ if (str[end]=='[')
+ level++;
+ if (str[end]==']') {
+ level--;
+ if (level==0)
+ break;
+ }
+ end++;
+ }
+ ERR_FAIL_COND_V(level!=0,Variant());
+ end++;
+ } break;
+ case MIN_CURLY_OPEN: {
+ int level=1;
+ while(end<close_pos) {
+
+ if (str[end]=='{')
+ level++;
+ if (str[end]=='}') {
+ level--;
+ if (level==0)
+ break;
+ }
+ end++;
+ }
+ ERR_FAIL_COND_V(level!=0,Variant());
+ end++;
+ } break;
+
+ }
+
+ String ret = str.substr(pos,end-pos);
+
+ pos=end;
+ while(pos<close_pos) {
+ if (str[pos]!=',' && str[pos]!=' ' && str[pos]!=':')
+ break;
+ pos++;
+ }
+
+ return ret;
+
+}
+
+
+static Variant _decode_variant(const String& p_string) {
+
+
+ String str = p_string.strip_edges();
+
+ if (str.nocasecmp_to("true")==0)
+ return Variant(true);
+ if (str.nocasecmp_to("false")==0)
+ return Variant(false);
+ if (str.nocasecmp_to("nil")==0)
+ return Variant();
+ if (str.is_valid_float()) {
+ if (str.find(".")==-1)
+ return str.to_int();
+ else
+ return str.to_double();
+
+ }
+ if (str.begins_with("#")) { //string
+ return Color::html(str);
+ }
+ if (str.begins_with("\"")) { //string
+ int end = str.find_last("\"");
+ ERR_FAIL_COND_V(end==0,Variant());
+ return str.substr(1,end-1).xml_unescape();
+
+ }
+
+ if (str.begins_with("[")) { //array
+
+ int close_pos = str.find_last("]");
+ ERR_FAIL_COND_V(close_pos==-1,Variant());
+ Array array;
+
+ int pos=1;
+
+ while(pos<close_pos) {
+
+ String s = _get_chunk(str,pos,close_pos);
+ array.push_back(_decode_variant(s));
+ }
+ return array;
+
+ }
+
+ if (str.begins_with("{")) { //array
+
+ int close_pos = str.find_last("}");
+ ERR_FAIL_COND_V(close_pos==-1,Variant());
+ Dictionary d;
+
+ int pos=1;
+
+ while(pos<close_pos) {
+
+ String key = _get_chunk(str,pos,close_pos);
+ String data = _get_chunk(str,pos,close_pos);
+ d[_decode_variant(key)]=_decode_variant(data);
+ }
+ return d;
+
+ }
+ if (str.begins_with("key")) {
+ Vector<String> params = _decode_params(p_string);
+ ERR_FAIL_COND_V(params.size()!=1 && params.size()!=2,Variant());
+ int scode=0;
+
+ if (params[0].is_numeric())
+ scode=params[0].to_int();
+ else
+ scode=find_keycode(params[0]);
+
+ InputEvent ie;
+ ie.type=InputEvent::KEY;
+ ie.key.scancode=scode;
+
+ if (params.size()==2) {
+ String mods=params[1];
+ if (mods.findn("C")!=-1)
+ ie.key.mod.control=true;
+ if (mods.findn("A")!=-1)
+ ie.key.mod.alt=true;
+ if (mods.findn("S")!=-1)
+ ie.key.mod.shift=true;
+ if (mods.findn("M")!=-1)
+ ie.key.mod.meta=true;
+ }
+ return ie;
+
+ }
+
+ if (str.begins_with("mbutton")) {
+ Vector<String> params = _decode_params(p_string);
+ ERR_FAIL_COND_V(params.size()!=2,Variant());
+
+ InputEvent ie;
+ ie.type=InputEvent::MOUSE_BUTTON;
+ ie.device=params[0].to_int();
+ ie.mouse_button.button_index=params[1].to_int();
+
+ return ie;
+ }
+
+ if (str.begins_with("jbutton")) {
+ Vector<String> params = _decode_params(p_string);
+ ERR_FAIL_COND_V(params.size()!=2,Variant());
+
+ InputEvent ie;
+ ie.type=InputEvent::JOYSTICK_BUTTON;
+ ie.device=params[0].to_int();
+ ie.joy_button.button_index=params[1].to_int();
+
+ return ie;
+ }
+
+ if (str.begins_with("jaxis")) {
+ Vector<String> params = _decode_params(p_string);
+ ERR_FAIL_COND_V(params.size()!=2,Variant());
+
+ InputEvent ie;
+ ie.type=InputEvent::JOYSTICK_MOTION;
+ ie.device=params[0].to_int();
+ ie.joy_motion.axis=params[1].to_int();
+
+ return ie;
+ }
+ if (str.begins_with("img")) {
+ Vector<String> params = _decode_params(p_string);
+ if (params.size()==0) {
+ return Image();
+ }
+
+ ERR_FAIL_COND_V(params.size()!=5,Image());
+
+ String format=params[0].strip_edges();
+
+ Image::Format imgformat;
+
+ if (format=="grayscale") {
+ imgformat=Image::FORMAT_GRAYSCALE;
+ } else if (format=="intensity") {
+ imgformat=Image::FORMAT_INTENSITY;
+ } else if (format=="grayscale_alpha") {
+ imgformat=Image::FORMAT_GRAYSCALE_ALPHA;
+ } else if (format=="rgb") {
+ imgformat=Image::FORMAT_RGB;
+ } else if (format=="rgba") {
+ imgformat=Image::FORMAT_RGBA;
+ } else if (format=="indexed") {
+ imgformat=Image::FORMAT_INDEXED;
+ } else if (format=="indexed_alpha") {
+ imgformat=Image::FORMAT_INDEXED_ALPHA;
+ } else if (format=="bc1") {
+ imgformat=Image::FORMAT_BC1;
+ } else if (format=="bc2") {
+ imgformat=Image::FORMAT_BC2;
+ } else if (format=="bc3") {
+ imgformat=Image::FORMAT_BC3;
+ } else if (format=="bc4") {
+ imgformat=Image::FORMAT_BC4;
+ } else if (format=="bc5") {
+ imgformat=Image::FORMAT_BC5;
+ } else if (format=="custom") {
+ imgformat=Image::FORMAT_CUSTOM;
+ } else {
+
+ ERR_FAIL_V( Image() );
+ }
+
+ int mipmaps=params[1].to_int();
+ int w=params[2].to_int();
+ int h=params[3].to_int();
+
+ if (w == 0 && w == 0) {
+ //r_v = Image(w, h, imgformat);
+ return Image();
+ };
+
+
+ String data=params[4];
+ int datasize=data.length()/2;
+ DVector<uint8_t> pixels;
+ pixels.resize(datasize);
+ DVector<uint8_t>::Write wb = pixels.write();
+ const CharType *cptr=data.c_str();
+
+ int idx=0;
+ uint8_t byte;
+ while( idx<datasize*2) {
+
+ CharType c=*(cptr++);
+
+ ERR_FAIL_COND_V(c=='<',ERR_FILE_CORRUPT);
+
+ if ( (c>='0' && c<='9') || (c>='A' && c<='F') || (c>='a' && c<='f') ) {
+
+ if (idx&1) {
+
+ byte|=HEX2CHR(c);
+ wb[idx>>1]=byte;
+ } else {
+
+ byte=HEX2CHR(c)<<4;
+ }
+
+ idx++;
+ }
+
+ }
+
+ wb = DVector<uint8_t>::Write();
+
+ return Image(w,h,mipmaps,imgformat,pixels);
+ }
+
+ if (str.find(",")!=-1) { //vector2 or vector3
+ Vector<float> farr = str.split_floats(",",true);
+ if (farr.size()==2) {
+ return Point2(farr[0],farr[1]);
+ }
+ if (farr.size()==3) {
+ return Vector3(farr[0],farr[1],farr[2]);
+ }
+ ERR_FAIL_V(Variant());
+ }
+
+
+ return Variant();
+}
+
+Error ConfigFile::load(const String& p_path) {
+
+ Error err;
+ FileAccess *f= FileAccess::open(p_path,FileAccess::READ,&err);
+
+ if (err!=OK) {
+
+ return err;
+ }
+
+
+ String line;
+ String section;
+ String subpath;
+
+ int line_count = 0;
+
+ while(!f->eof_reached()) {
+
+ String line = f->get_line().strip_edges();
+ line_count++;
+
+ if (line=="")
+ continue;
+
+ // find comments
+
+ {
+
+ int pos=0;
+ while (true) {
+ int ret = line.find(";",pos);
+ if (ret==-1)
+ break;
+
+ int qc=0;
+ for(int i=0;i<ret;i++) {
+
+ if (line[i]=='"')
+ qc++;
+ }
+
+ if ( !(qc&1) ) {
+ //not inside string, real comment
+ line=line.substr(0,ret);
+ break;
+
+ }
+
+ pos=ret+1;
+
+
+ }
+ }
+
+ if (line.begins_with("[")) {
+
+ int end = line.find_last("]");
+ ERR_CONTINUE(end!=line.length()-1);
+
+ section=line.substr(1,line.length()-2);
+
+ } else if (line.find("=")!=-1) {
+
+
+ int eqpos = line.find("=");
+ String var=line.substr(0,eqpos).strip_edges();
+ String value=line.substr(eqpos+1,line.length()).strip_edges();
+
+ Variant val = _decode_variant(value);
+
+ set_value(section,var,val);
+
+ } else {
+
+ if (line.length() > 0) {
+ ERR_PRINT(String("Syntax error on line "+itos(line_count)+" of file "+p_path).ascii().get_data());
+ };
+ };
+ }
+
+ memdelete(f);
+
+ return OK;
+}
+
+
+
+void ConfigFile::_bind_methods(){
+
+ ObjectTypeDB::bind_method(_MD("set_value","section","key","value"),&ConfigFile::set_value);
+ ObjectTypeDB::bind_method(_MD("get_value","section","key"),&ConfigFile::get_value);
+
+ ObjectTypeDB::bind_method(_MD("has_section","section"),&ConfigFile::has_section);
+ ObjectTypeDB::bind_method(_MD("has_section_key","section","key"),&ConfigFile::has_section_key);
+
+ ObjectTypeDB::bind_method(_MD("get_sections"),&ConfigFile::_get_sections);
+ ObjectTypeDB::bind_method(_MD("get_section_keys"),&ConfigFile::_get_section_keys);
+
+ ObjectTypeDB::bind_method(_MD("load:Error","path"),&ConfigFile::load);
+ ObjectTypeDB::bind_method(_MD("save:Error","path"),&ConfigFile::save);
+
+}
+
+
+ConfigFile::ConfigFile()
+{
+}
diff --git a/core/io/config_file.h b/core/io/config_file.h
new file mode 100644
index 0000000000..e132e46fea
--- /dev/null
+++ b/core/io/config_file.h
@@ -0,0 +1,63 @@
+/*************************************************************************/
+/* config_file.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef CONFIG_FILE_H
+#define CONFIG_FILE_H
+
+#include "reference.h"
+
+
+class ConfigFile : public Reference {
+
+ OBJ_TYPE(ConfigFile,Reference);
+
+ Map< String, Map<String, Variant> > values;
+
+ StringArray _get_sections() const;
+ StringArray _get_section_keys(const String& p_section) const;
+protected:
+
+ static void _bind_methods();
+public:
+
+ void set_value(const String& p_section, const String& p_key, const Variant& p_value);
+ Variant get_value(const String& p_section, const String& p_key) const;
+
+ bool has_section(const String& p_section) const;
+ bool has_section_key(const String& p_section,const String& p_key) const;
+
+ void get_sections(List<String> *r_sections) const;
+ void get_section_keys(const String& p_section,List<String> *r_keys) const;
+
+ Error save(const String& p_path);
+ Error load(const String& p_path);
+
+ ConfigFile();
+};
+
+#endif // CONFIG_FILE_H
diff --git a/core/io/crypt.h b/core/io/crypt.h
new file mode 100644
index 0000000000..a01d08d932
--- /dev/null
+++ b/core/io/crypt.h
@@ -0,0 +1,131 @@
+/* crypt.h -- base code for crypt/uncrypt ZIPfile
+
+
+ Version 1.01e, February 12th, 2005
+
+ Copyright (C) 1998-2005 Gilles Vollant
+
+ This code is a modified version of crypting code in Infozip distribution
+
+ The encryption/decryption parts of this source code (as opposed to the
+ non-echoing password parts) were originally written in Europe. The
+ whole source package can be freely distributed, including from the USA.
+ (Prior to January 2000, re-export from the US was a violation of US law.)
+
+ This encryption code is a direct transcription of the algorithm from
+ Roger Schlafly, described by Phil Katz in the file appnote.txt. This
+ file (appnote.txt) is distributed with the PKZIP program (even in the
+ version without encryption capabilities).
+
+ If you don't need crypting in your application, just define symbols
+ NOCRYPT and NOUNCRYPT.
+
+ This code support the "Traditional PKWARE Encryption".
+
+ The new AES encryption added on Zip format by Winzip (see the page
+ http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
+ Encryption is not supported.
+*/
+
+#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
+
+/***********************************************************************
+ * Return the next byte in the pseudo-random sequence
+ */
+static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab)
+{
+ unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an
+ * unpredictable manner on 16-bit systems; not a problem
+ * with any known compiler so far, though */
+
+ temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2;
+ return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
+}
+
+/***********************************************************************
+ * Update the encryption keys with the next byte of plain text
+ */
+static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c)
+{
+ (*(pkeys+0)) = CRC32((*(pkeys+0)), c);
+ (*(pkeys+1)) += (*(pkeys+0)) & 0xff;
+ (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
+ {
+ register int keyshift = (int)((*(pkeys+1)) >> 24);
+ (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift);
+ }
+ return c;
+}
+
+
+/***********************************************************************
+ * Initialize the encryption keys and the random header according to
+ * the given password.
+ */
+static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab)
+{
+ *(pkeys+0) = 305419896L;
+ *(pkeys+1) = 591751049L;
+ *(pkeys+2) = 878082192L;
+ while (*passwd != '\0') {
+ update_keys(pkeys,pcrc_32_tab,(int)*passwd);
+ passwd++;
+ }
+}
+
+#define zdecode(pkeys,pcrc_32_tab,c) \
+ (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab)))
+
+#define zencode(pkeys,pcrc_32_tab,c,t) \
+ (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c))
+
+#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED
+
+#define RAND_HEAD_LEN 12
+ /* "last resort" source for second part of crypt seed pattern */
+# ifndef ZCR_SEED2
+# define ZCR_SEED2 3141592654UL /* use PI as default pattern */
+# endif
+
+static int crypthead(const char* passwd, /* password string */
+ unsigned char* buf, /* where to write header */
+ int bufSize,
+ unsigned long* pkeys,
+ const unsigned long* pcrc_32_tab,
+ unsigned long crcForCrypting)
+{
+ int n; /* index in random header */
+ int t; /* temporary */
+ int c; /* random byte */
+ unsigned char header[RAND_HEAD_LEN-2]; /* random header */
+ static unsigned calls = 0; /* ensure different random header each time */
+
+ if (bufSize<RAND_HEAD_LEN)
+ return 0;
+
+ /* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the
+ * output of rand() to get less predictability, since rand() is
+ * often poorly implemented.
+ */
+ if (++calls == 1)
+ {
+ srand((unsigned)(time(NULL) ^ ZCR_SEED2));
+ }
+ init_keys(passwd, pkeys, pcrc_32_tab);
+ for (n = 0; n < RAND_HEAD_LEN-2; n++)
+ {
+ c = (rand() >> 7) & 0xff;
+ header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t);
+ }
+ /* Encrypt random header (last two bytes is high word of crc) */
+ init_keys(passwd, pkeys, pcrc_32_tab);
+ for (n = 0; n < RAND_HEAD_LEN-2; n++)
+ {
+ buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t);
+ }
+ buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t);
+ buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t);
+ return n;
+}
+
+#endif
diff --git a/core/io/fastlz.c b/core/io/fastlz.c
new file mode 100644
index 0000000000..508f6ea2ae
--- /dev/null
+++ b/core/io/fastlz.c
@@ -0,0 +1,551 @@
+ /*
+ FastLZ - lightning-fast lossless compression library
+
+ Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
+ Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
+ Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
+
+ 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.
+*/
+
+#if !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR)
+
+/*
+ * Always check for bound when decompressing.
+ * Generally it is best to leave it defined.
+ */
+#define FASTLZ_SAFE
+
+/*
+ * Give hints to the compiler for branch prediction optimization.
+ */
+#if defined(__GNUC__) && (__GNUC__ > 2)
+#define FASTLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1))
+#define FASTLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0))
+#else
+#define FASTLZ_EXPECT_CONDITIONAL(c) (c)
+#define FASTLZ_UNEXPECT_CONDITIONAL(c) (c)
+#endif
+
+/*
+ * Use inlined functions for supported systems.
+ */
+#if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C)
+#define FASTLZ_INLINE inline
+#elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__)
+#define FASTLZ_INLINE __inline
+#else
+#define FASTLZ_INLINE
+#endif
+
+/*
+ * Prevent accessing more than 8-bit at once, except on x86 architectures.
+ */
+#if !defined(FASTLZ_STRICT_ALIGN)
+#define FASTLZ_STRICT_ALIGN
+#if defined(__i386__) || defined(__386) /* GNU C, Sun Studio */
+#undef FASTLZ_STRICT_ALIGN
+#elif defined(__i486__) || defined(__i586__) || defined(__i686__) /* GNU C */
+#undef FASTLZ_STRICT_ALIGN
+#elif defined(_M_IX86) /* Intel, MSVC */
+#undef FASTLZ_STRICT_ALIGN
+#elif defined(__386)
+#undef FASTLZ_STRICT_ALIGN
+#elif defined(_X86_) /* MinGW */
+#undef FASTLZ_STRICT_ALIGN
+#elif defined(__I86__) /* Digital Mars */
+#undef FASTLZ_STRICT_ALIGN
+#endif
+#endif
+
+/*
+ * FIXME: use preprocessor magic to set this on different platforms!
+ */
+typedef unsigned char flzuint8;
+typedef unsigned short flzuint16;
+typedef unsigned int flzuint32;
+
+/* prototypes */
+int fastlz_compress(const void* input, int length, void* output);
+int fastlz_compress_level(int level, const void* input, int length, void* output);
+int fastlz_decompress(const void* input, int length, void* output, int maxout);
+
+#define MAX_COPY 32
+#define MAX_LEN 264 /* 256 + 8 */
+#define MAX_DISTANCE 8192
+
+#if !defined(FASTLZ_STRICT_ALIGN)
+#define FASTLZ_READU16(p) *((const flzuint16*)(p))
+#else
+#define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8)
+#endif
+
+#define HASH_LOG 13
+#define HASH_SIZE (1<< HASH_LOG)
+#define HASH_MASK (HASH_SIZE-1)
+#define HASH_FUNCTION(v,p) { v = FASTLZ_READU16(p); v ^= FASTLZ_READU16(p+1)^(v>>(16-HASH_LOG));v &= HASH_MASK; }
+
+#undef FASTLZ_LEVEL
+#define FASTLZ_LEVEL 1
+
+#undef FASTLZ_COMPRESSOR
+#undef FASTLZ_DECOMPRESSOR
+#define FASTLZ_COMPRESSOR fastlz1_compress
+#define FASTLZ_DECOMPRESSOR fastlz1_decompress
+static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output);
+static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout);
+#include "fastlz.c"
+
+#undef FASTLZ_LEVEL
+#define FASTLZ_LEVEL 2
+
+#undef MAX_DISTANCE
+#define MAX_DISTANCE 8191
+#define MAX_FARDISTANCE (65535+MAX_DISTANCE-1)
+
+#undef FASTLZ_COMPRESSOR
+#undef FASTLZ_DECOMPRESSOR
+#define FASTLZ_COMPRESSOR fastlz2_compress
+#define FASTLZ_DECOMPRESSOR fastlz2_decompress
+static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output);
+static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout);
+#include "fastlz.c"
+
+int fastlz_compress(const void* input, int length, void* output)
+{
+ /* for short block, choose fastlz1 */
+ if(length < 65536)
+ return fastlz1_compress(input, length, output);
+
+ /* else... */
+ return fastlz2_compress(input, length, output);
+}
+
+int fastlz_decompress(const void* input, int length, void* output, int maxout)
+{
+ /* magic identifier for compression level */
+ int level = ((*(const flzuint8*)input) >> 5) + 1;
+
+ if(level == 1)
+ return fastlz1_decompress(input, length, output, maxout);
+ if(level == 2)
+ return fastlz2_decompress(input, length, output, maxout);
+
+ /* unknown level, trigger error */
+ return 0;
+}
+
+int fastlz_compress_level(int level, const void* input, int length, void* output)
+{
+ if(level == 1)
+ return fastlz1_compress(input, length, output);
+ if(level == 2)
+ return fastlz2_compress(input, length, output);
+
+ return 0;
+}
+
+#else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */
+
+static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output)
+{
+ const flzuint8* ip = (const flzuint8*) input;
+ const flzuint8* ip_bound = ip + length - 2;
+ const flzuint8* ip_limit = ip + length - 12;
+ flzuint8* op = (flzuint8*) output;
+
+ const flzuint8* htab[HASH_SIZE];
+ const flzuint8** hslot;
+ flzuint32 hval;
+
+ flzuint32 copy;
+
+ /* sanity check */
+ if(FASTLZ_UNEXPECT_CONDITIONAL(length < 4))
+ {
+ if(length)
+ {
+ /* create literal copy only */
+ *op++ = length-1;
+ ip_bound++;
+ while(ip <= ip_bound)
+ *op++ = *ip++;
+ return length+1;
+ }
+ else
+ return 0;
+ }
+
+ /* initializes hash table */
+ for (hslot = htab; hslot < htab + HASH_SIZE; hslot++)
+ *hslot = ip;
+
+ /* we start with literal copy */
+ copy = 2;
+ *op++ = MAX_COPY-1;
+ *op++ = *ip++;
+ *op++ = *ip++;
+
+ /* main loop */
+ while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit))
+ {
+ const flzuint8* ref;
+ flzuint32 distance;
+
+ /* minimum match length */
+ flzuint32 len = 3;
+
+ /* comparison starting-point */
+ const flzuint8* anchor = ip;
+
+ /* check for a run */
+#if FASTLZ_LEVEL==2
+ if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1))
+ {
+ distance = 1;
+ ip += 3;
+ ref = anchor - 1 + 3;
+ goto match;
+ }
+#endif
+
+ /* find potential match */
+ HASH_FUNCTION(hval,ip);
+ hslot = htab + hval;
+ ref = htab[hval];
+
+ /* calculate distance to the match */
+ distance = anchor - ref;
+
+ /* update hash table */
+ *hslot = anchor;
+
+ /* is this a match? check the first 3 bytes */
+ if(distance==0 ||
+#if FASTLZ_LEVEL==1
+ (distance >= MAX_DISTANCE) ||
+#else
+ (distance >= MAX_FARDISTANCE) ||
+#endif
+ *ref++ != *ip++ || *ref++!=*ip++ || *ref++!=*ip++)
+ goto literal;
+
+#if FASTLZ_LEVEL==2
+ /* far, needs at least 5-byte match */
+ if(distance >= MAX_DISTANCE)
+ {
+ if(*ip++ != *ref++ || *ip++!= *ref++)
+ goto literal;
+ len += 2;
+ }
+
+ match:
+#endif
+
+ /* last matched byte */
+ ip = anchor + len;
+
+ /* distance is biased */
+ distance--;
+
+ if(!distance)
+ {
+ /* zero distance means a run */
+ flzuint8 x = ip[-1];
+ while(ip < ip_bound)
+ if(*ref++ != x) break; else ip++;
+ }
+ else
+ for(;;)
+ {
+ /* safe because the outer check against ip limit */
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ while(ip < ip_bound)
+ if(*ref++ != *ip++) break;
+ break;
+ }
+
+ /* if we have copied something, adjust the copy count */
+ if(copy)
+ /* copy is biased, '0' means 1 byte copy */
+ *(op-copy-1) = copy-1;
+ else
+ /* back, to overwrite the copy count */
+ op--;
+
+ /* reset literal counter */
+ copy = 0;
+
+ /* length is biased, '1' means a match of 3 bytes */
+ ip -= 3;
+ len = ip - anchor;
+
+ /* encode the match */
+#if FASTLZ_LEVEL==2
+ if(distance < MAX_DISTANCE)
+ {
+ if(len < 7)
+ {
+ *op++ = (len << 5) + (distance >> 8);
+ *op++ = (distance & 255);
+ }
+ else
+ {
+ *op++ = (7 << 5) + (distance >> 8);
+ for(len-=7; len >= 255; len-= 255)
+ *op++ = 255;
+ *op++ = len;
+ *op++ = (distance & 255);
+ }
+ }
+ else
+ {
+ /* far away, but not yet in the another galaxy... */
+ if(len < 7)
+ {
+ distance -= MAX_DISTANCE;
+ *op++ = (len << 5) + 31;
+ *op++ = 255;
+ *op++ = distance >> 8;
+ *op++ = distance & 255;
+ }
+ else
+ {
+ distance -= MAX_DISTANCE;
+ *op++ = (7 << 5) + 31;
+ for(len-=7; len >= 255; len-= 255)
+ *op++ = 255;
+ *op++ = len;
+ *op++ = 255;
+ *op++ = distance >> 8;
+ *op++ = distance & 255;
+ }
+ }
+#else
+
+ if(FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN-2))
+ while(len > MAX_LEN-2)
+ {
+ *op++ = (7 << 5) + (distance >> 8);
+ *op++ = MAX_LEN - 2 - 7 -2;
+ *op++ = (distance & 255);
+ len -= MAX_LEN-2;
+ }
+
+ if(len < 7)
+ {
+ *op++ = (len << 5) + (distance >> 8);
+ *op++ = (distance & 255);
+ }
+ else
+ {
+ *op++ = (7 << 5) + (distance >> 8);
+ *op++ = len - 7;
+ *op++ = (distance & 255);
+ }
+#endif
+
+ /* update the hash at match boundary */
+ HASH_FUNCTION(hval,ip);
+ htab[hval] = ip++;
+ HASH_FUNCTION(hval,ip);
+ htab[hval] = ip++;
+
+ /* assuming literal copy */
+ *op++ = MAX_COPY-1;
+
+ continue;
+
+ literal:
+ *op++ = *anchor++;
+ ip = anchor;
+ copy++;
+ if(FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY))
+ {
+ copy = 0;
+ *op++ = MAX_COPY-1;
+ }
+ }
+
+ /* left-over as literal copy */
+ ip_bound++;
+ while(ip <= ip_bound)
+ {
+ *op++ = *ip++;
+ copy++;
+ if(copy == MAX_COPY)
+ {
+ copy = 0;
+ *op++ = MAX_COPY-1;
+ }
+ }
+
+ /* if we have copied something, adjust the copy length */
+ if(copy)
+ *(op-copy-1) = copy-1;
+ else
+ op--;
+
+#if FASTLZ_LEVEL==2
+ /* marker for fastlz2 */
+ *(flzuint8*)output |= (1 << 5);
+#endif
+
+ return op - (flzuint8*)output;
+}
+
+static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout)
+{
+ const flzuint8* ip = (const flzuint8*) input;
+ const flzuint8* ip_limit = ip + length;
+ flzuint8* op = (flzuint8*) output;
+ flzuint8* op_limit = op + maxout;
+ flzuint32 ctrl = (*ip++) & 31;
+ int loop = 1;
+
+ do
+ {
+ const flzuint8* ref = op;
+ flzuint32 len = ctrl >> 5;
+ flzuint32 ofs = (ctrl & 31) << 8;
+
+ if(ctrl >= 32)
+ {
+#if FASTLZ_LEVEL==2
+ flzuint8 code;
+#endif
+ len--;
+ ref -= ofs;
+ if (len == 7-1)
+#if FASTLZ_LEVEL==1
+ len += *ip++;
+ ref -= *ip++;
+#else
+ do
+ {
+ code = *ip++;
+ len += code;
+ } while (code==255);
+ code = *ip++;
+ ref -= code;
+
+ /* match from 16-bit distance */
+ if(FASTLZ_UNEXPECT_CONDITIONAL(code==255))
+ if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8)))
+ {
+ ofs = (*ip++) << 8;
+ ofs += *ip++;
+ ref = op - ofs - MAX_DISTANCE;
+ }
+#endif
+
+#ifdef FASTLZ_SAFE
+ if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit))
+ return 0;
+
+ if (FASTLZ_UNEXPECT_CONDITIONAL(ref-1 < (flzuint8 *)output))
+ return 0;
+#endif
+
+ if(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit))
+ ctrl = *ip++;
+ else
+ loop = 0;
+
+ if(ref == op)
+ {
+ /* optimize copy for a run */
+ flzuint8 b = ref[-1];
+ *op++ = b;
+ *op++ = b;
+ *op++ = b;
+ for(; len; --len)
+ *op++ = b;
+ }
+ else
+ {
+#if !defined(FASTLZ_STRICT_ALIGN)
+ const flzuint16* p;
+ flzuint16* q;
+#endif
+ /* copy from reference */
+ ref--;
+ *op++ = *ref++;
+ *op++ = *ref++;
+ *op++ = *ref++;
+
+#if !defined(FASTLZ_STRICT_ALIGN)
+ /* copy a byte, so that now it's word aligned */
+ if(len & 1)
+ {
+ *op++ = *ref++;
+ len--;
+ }
+
+ /* copy 16-bit at once */
+ q = (flzuint16*) op;
+ op += len;
+ p = (const flzuint16*) ref;
+ for(len>>=1; len > 4; len-=4)
+ {
+ *q++ = *p++;
+ *q++ = *p++;
+ *q++ = *p++;
+ *q++ = *p++;
+ }
+ for(; len; --len)
+ *q++ = *p++;
+#else
+ for(; len; --len)
+ *op++ = *ref++;
+#endif
+ }
+ }
+ else
+ {
+ ctrl++;
+#ifdef FASTLZ_SAFE
+ if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit))
+ return 0;
+ if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit))
+ return 0;
+#endif
+
+ *op++ = *ip++;
+ for(--ctrl; ctrl; ctrl--)
+ *op++ = *ip++;
+
+ loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit);
+ if(loop)
+ ctrl = *ip++;
+ }
+ }
+ while(FASTLZ_EXPECT_CONDITIONAL(loop));
+
+ return op - (flzuint8*)output;
+}
+
+#endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */
diff --git a/core/io/fastlz.h b/core/io/fastlz.h
new file mode 100644
index 0000000000..f87bc7be31
--- /dev/null
+++ b/core/io/fastlz.h
@@ -0,0 +1,100 @@
+/*
+ FastLZ - lightning-fast lossless compression library
+
+ Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
+ Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
+ Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
+
+ 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.
+*/
+
+#ifndef FASTLZ_H
+#define FASTLZ_H
+
+#define FASTLZ_VERSION 0x000100
+
+#define FASTLZ_VERSION_MAJOR 0
+#define FASTLZ_VERSION_MINOR 0
+#define FASTLZ_VERSION_REVISION 0
+
+#define FASTLZ_VERSION_STRING "0.1.0"
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/**
+ Compress a block of data in the input buffer and returns the size of
+ compressed block. The size of input buffer is specified by length. The
+ minimum input buffer size is 16.
+
+ The output buffer must be at least 5% larger than the input buffer
+ and can not be smaller than 66 bytes.
+
+ If the input is not compressible, the return value might be larger than
+ length (input buffer size).
+
+ The input buffer and the output buffer can not overlap.
+*/
+
+int fastlz_compress(const void* input, int length, void* output);
+
+/**
+ Decompress a block of compressed data and returns the size of the
+ decompressed block. If error occurs, e.g. the compressed data is
+ corrupted or the output buffer is not large enough, then 0 (zero)
+ will be returned instead.
+
+ The input buffer and the output buffer can not overlap.
+
+ Decompression is memory safe and guaranteed not to write the output buffer
+ more than what is specified in maxout.
+ */
+
+int fastlz_decompress(const void* input, int length, void* output, int maxout);
+
+/**
+ Compress a block of data in the input buffer and returns the size of
+ compressed block. The size of input buffer is specified by length. The
+ minimum input buffer size is 16.
+
+ The output buffer must be at least 5% larger than the input buffer
+ and can not be smaller than 66 bytes.
+
+ If the input is not compressible, the return value might be larger than
+ length (input buffer size).
+
+ The input buffer and the output buffer can not overlap.
+
+ Compression level can be specified in parameter level. At the moment,
+ only level 1 and level 2 are supported.
+ Level 1 is the fastest compression and generally useful for short data.
+ Level 2 is slightly slower but it gives better compression ratio.
+
+ Note that the compressed data, regardless of the level, can always be
+ decompressed using the function fastlz_decompress above.
+*/
+
+int fastlz_compress_level(int level, const void* input, int length, void* output);
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* FASTLZ_H */
diff --git a/core/io/file_access_buffered.cpp b/core/io/file_access_buffered.cpp
new file mode 100644
index 0000000000..6927b3772f
--- /dev/null
+++ b/core/io/file_access_buffered.cpp
@@ -0,0 +1,184 @@
+/*************************************************************************/
+/* file_access_buffered.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. */
+/*************************************************************************/
+#include "file_access_buffered.h"
+
+#include <string.h>
+
+#include "error_macros.h"
+
+Error FileAccessBuffered::set_error(Error p_error) const {
+
+ return (last_error = p_error);
+};
+
+void FileAccessBuffered::set_cache_size(int p_size) {
+
+ cache_size = p_size;
+};
+
+int FileAccessBuffered::get_cache_size() {
+
+ return cache_size;
+};
+
+int FileAccessBuffered::cache_data_left() const {
+
+ if (file.offset >= file.size) {
+ return 0;
+ };
+
+ if (cache.offset == -1 || file.offset < cache.offset || file.offset >= cache.offset + cache.buffer.size()) {
+
+ return read_data_block(file.offset, cache_size);
+
+ } else {
+
+ return cache.buffer.size() - (file.offset - cache.offset);
+ };
+
+ return 0;
+};
+
+void FileAccessBuffered::seek(size_t p_position) {
+
+ file.offset = p_position;
+};
+
+void FileAccessBuffered::seek_end(int64_t p_position) {
+
+ file.offset = file.size + p_position;
+};
+
+size_t FileAccessBuffered::get_pos() const {
+
+ return file.offset;
+};
+
+size_t FileAccessBuffered::get_len() const {
+
+ return file.size;
+};
+
+bool FileAccessBuffered::eof_reached() const {
+
+ return file.offset > file.size;
+};
+
+uint8_t FileAccessBuffered::get_8() const {
+
+ ERR_FAIL_COND_V(!file.open,0);
+
+ uint8_t byte = 0;
+ if (cache_data_left() >= 1) {
+
+ byte = cache.buffer[file.offset - cache.offset];
+ };
+
+ ++file.offset;
+
+ return byte;
+};
+
+int FileAccessBuffered::get_buffer(uint8_t *p_dest,int p_elements) const {
+
+ ERR_FAIL_COND_V(!file.open, -1);
+
+ if (p_elements > cache_size) {
+
+ int total_read = 0;
+
+ if (!(cache.offset == -1 || file.offset < cache.offset || file.offset >= cache.offset + cache.buffer.size())) {
+
+ int size = (cache.buffer.size() - (file.offset - cache.offset));
+ size = size - (size % 4);
+ //DVector<uint8_t>::Read read = cache.buffer.read();
+ //memcpy(p_dest, read.ptr() + (file.offset - cache.offset), size);
+ memcpy(p_dest, cache.buffer.ptr() + (file.offset - cache.offset), size);
+ p_dest += size;
+ p_elements -= size;
+ file.offset += size;
+ total_read += size;
+ };
+
+ int err = read_data_block(file.offset, p_elements, p_dest);
+ if (err >= 0) {
+ total_read += err;
+ file.offset += err;
+ };
+
+ return total_read;
+ };
+
+
+ int to_read = p_elements;
+ int total_read = 0;
+ while (to_read > 0) {
+
+ int left = cache_data_left();
+ if (left == 0) {
+ if (to_read > 0) {
+ file.offset += to_read;
+ };
+ return total_read;
+ };
+ if (left < 0) {
+ return left;
+ };
+
+ int r = MIN(left, to_read);
+ //DVector<uint8_t>::Read read = cache.buffer.read();
+ //memcpy(p_dest+total_read, &read.ptr()[file.offset - cache.offset], r);
+ memcpy(p_dest+total_read, cache.buffer.ptr() + (file.offset - cache.offset), r);
+
+ file.offset += r;
+ total_read += r;
+ to_read -= r;
+ };
+
+ return p_elements;
+};
+
+bool FileAccessBuffered::is_open() const {
+
+ return file.open;
+};
+
+Error FileAccessBuffered::get_error() const {
+
+ return last_error;
+};
+
+FileAccessBuffered::FileAccessBuffered() {
+
+ cache_size = DEFAULT_CACHE_SIZE;
+};
+
+FileAccessBuffered::~FileAccessBuffered(){
+
+}
diff --git a/core/io/file_access_buffered.h b/core/io/file_access_buffered.h
new file mode 100644
index 0000000000..533cc6c7dd
--- /dev/null
+++ b/core/io/file_access_buffered.h
@@ -0,0 +1,97 @@
+/*************************************************************************/
+/* file_access_buffered.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef FILE_ACCESS_BUFFERED_H
+#define FILE_ACCESS_BUFFERED_H
+
+#include "os/file_access.h"
+
+#include "dvector.h"
+#include "ustring.h"
+
+class FileAccessBuffered : public FileAccess {
+
+public:
+ enum {
+ DEFAULT_CACHE_SIZE = 128 * 1024,
+ };
+
+private:
+
+ int cache_size;
+
+ int cache_data_left() const;
+ mutable Error last_error;
+
+protected:
+
+ Error set_error(Error p_error) const;
+
+ mutable struct File {
+
+ bool open;
+ int size;
+ int offset;
+ String name;
+ int access_flags;
+ } file;
+
+ mutable struct Cache {
+
+ Vector<uint8_t> buffer;
+ int offset;
+ } cache;
+
+ virtual int read_data_block(int p_offset, int p_size, uint8_t *p_dest = 0) const =0;
+
+ void set_cache_size(int p_size);
+ int get_cache_size();
+
+public:
+
+ virtual size_t get_pos() const; ///< get position in the file
+ virtual size_t get_len() const; ///< get size of the file
+
+ virtual void seek(size_t p_position); ///< seek to a given position
+ virtual void seek_end(int64_t p_position=0); ///< seek from the end of file
+
+ virtual bool eof_reached() const;
+
+ virtual uint8_t get_8() const;
+ virtual int get_buffer(uint8_t *p_dst,int p_length) const; ///< get an array of bytes
+
+ virtual bool is_open() const;
+
+ virtual Error get_error() const;
+
+ FileAccessBuffered();
+ virtual ~FileAccessBuffered();
+};
+
+#endif
+
diff --git a/core/io/file_access_buffered_fa.h b/core/io/file_access_buffered_fa.h
new file mode 100644
index 0000000000..5de2f66ace
--- /dev/null
+++ b/core/io/file_access_buffered_fa.h
@@ -0,0 +1,147 @@
+/*************************************************************************/
+/* file_access_buffered_fa.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef FILE_ACCESS_BUFFERED_FA_H
+#define FILE_ACCESS_BUFFERED_FA_H
+
+#include "core/io/file_access_buffered.h"
+
+template<class T>
+class FileAccessBufferedFA : public FileAccessBuffered {
+
+ T f;
+
+ int read_data_block(int p_offset, int p_size, uint8_t *p_dest = 0) const {
+
+ ERR_FAIL_COND_V( !f.is_open(), -1 );
+
+ ((T*)&f)->seek(p_offset);
+
+ if (p_dest) {
+
+ f.get_buffer(p_dest, p_size);
+ return p_size;
+
+ } else {
+
+ cache.offset = p_offset;
+ cache.buffer.resize(p_size);
+
+ // on dvector
+ //DVector<uint8_t>::Write write = cache.buffer.write();
+ //f.get_buffer(write.ptr(), p_size);
+
+ // on vector
+ f.get_buffer(cache.buffer.ptr(), p_size);
+
+ return p_size;
+ };
+ };
+
+ static FileAccess* create() {
+
+ return memnew( FileAccessBufferedFA<T>() );
+ };
+
+protected:
+ virtual void _set_access_type(AccessType p_access) {
+ f._set_access_type(p_access);
+ FileAccessBuffered::_set_access_type(p_access);
+ };
+
+public:
+
+
+ void store_8(uint8_t p_dest) {
+
+ f.store_8(p_dest);
+ };
+
+ void store_buffer(const uint8_t *p_src,int p_length) {
+
+ f.store_buffer(p_src, p_length);
+ };
+
+ bool file_exists(const String& p_name) {
+
+ return f.file_exists(p_name);
+ };
+
+ Error _open(const String& p_path, int p_mode_flags) {
+
+ close();
+
+ Error ret = f._open(p_path, p_mode_flags);
+ if (ret !=OK)
+ return ret;
+ //ERR_FAIL_COND_V( ret != OK, ret );
+
+ file.size = f.get_len();
+ file.offset = 0;
+ file.open = true;
+ file.name = p_path;
+ file.access_flags = p_mode_flags;
+
+ cache.buffer.resize(0);
+ cache.offset = 0;
+
+ return set_error(OK);
+ };
+
+ void close() {
+
+ f.close();
+
+ file.offset = 0;
+ file.size = 0;
+ file.open = false;
+ file.name = "";
+
+ cache.buffer.resize(0);
+ cache.offset = 0;
+ set_error(OK);
+ };
+
+// static void make_default() {
+
+ //FileAccess::create_func = FileAccessBufferedFA<T>::create;
+// };
+
+ virtual uint64_t _get_modified_time(const String& p_file) {
+
+ return f._get_modified_time(p_file);
+ }
+
+ FileAccessBufferedFA() {
+
+
+ };
+};
+
+
+#endif // FILE_ACCESS_BUFFERED_FA_H
diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
new file mode 100644
index 0000000000..ec9dce28e2
--- /dev/null
+++ b/core/io/file_access_compressed.cpp
@@ -0,0 +1,421 @@
+/*************************************************************************/
+/* file_access_compressed.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. */
+/*************************************************************************/
+#include "file_access_compressed.h"
+#include "print_string.h"
+void FileAccessCompressed::configure(const String& p_magic, Compression::Mode p_mode, int p_block_size) {
+
+ magic=p_magic.ascii().get_data();
+ if (magic.length()>4)
+ magic=magic.substr(0,4);
+ else {
+ while(magic.length()<4)
+ magic+=" ";
+ }
+
+ cmode=p_mode;
+ block_size=p_block_size;
+
+}
+
+
+#define WRITE_FIT(m_bytes) \
+{\
+if (write_pos+(m_bytes) > write_max) {\
+ write_max=write_pos+(m_bytes);\
+}\
+if (write_max > write_buffer_size) {\
+ write_buffer_size = nearest_power_of_2( write_max );\
+ buffer.resize(write_buffer_size);\
+ write_ptr=buffer.ptr();\
+}\
+}
+
+
+Error FileAccessCompressed::open_after_magic(FileAccess *p_base) {
+
+
+ f=p_base;
+ cmode=(Compression::Mode)f->get_32();
+ block_size=f->get_32();
+ read_total=f->get_32();
+ int bc = (read_total/block_size)+1;
+ int acc_ofs=f->get_pos()+bc*4;
+ int max_bs=0;
+ for(int i=0;i<bc;i++) {
+
+ ReadBlock rb;
+ rb.offset=acc_ofs;
+ rb.csize=f->get_32();
+ acc_ofs+=rb.csize;
+ max_bs=MAX(max_bs,rb.csize);
+ read_blocks.push_back(rb);
+
+
+ }
+
+ comp_buffer.resize(max_bs);
+ buffer.resize(block_size);
+ read_ptr=buffer.ptr();
+ f->get_buffer(comp_buffer.ptr(),read_blocks[0].csize);
+ at_end=false;
+ read_eof=false;
+ read_block_count=bc;
+ read_block_size=read_blocks.size()==1?read_total:block_size;
+
+ Compression::decompress(buffer.ptr(),read_block_size,comp_buffer.ptr(),read_blocks[0].csize,cmode);
+ read_block=0;
+ read_pos=0;
+
+ return OK;
+
+}
+
+Error FileAccessCompressed::_open(const String& p_path, int p_mode_flags){
+
+ ERR_FAIL_COND_V(p_mode_flags==READ_WRITE,ERR_UNAVAILABLE);
+
+ if (f)
+ close();
+
+
+ Error err;
+ f = FileAccess::open(p_path,p_mode_flags,&err);
+ if (err!=OK) {
+ //not openable
+
+ f=NULL;
+ return err;
+ }
+
+ if (p_mode_flags&WRITE) {
+
+ buffer.clear();
+ writing=true;
+ write_pos=0;
+ write_buffer_size=256;
+ buffer.resize(256);
+ write_max=0;
+ write_ptr=buffer.ptr();
+
+
+
+ //don't store anything else unless it's done saving!
+ } else {
+
+ char rmagic[5];
+ f->get_buffer((uint8_t*)rmagic,4);
+ rmagic[4]=0;
+ if (magic!=rmagic) {
+ memdelete(f);
+ f=NULL;
+ return ERR_FILE_UNRECOGNIZED;
+ }
+
+ open_after_magic(f);
+
+ }
+
+ return OK;
+
+}
+void FileAccessCompressed::close(){
+
+ if (!f)
+ return;
+
+
+ if (writing) {
+ //save block table and all compressed blocks
+
+ CharString mgc = magic.utf8();
+ f->store_buffer((const uint8_t*)mgc.get_data(),mgc.length()); //write header 4
+ f->store_32(cmode); //write compression mode 4
+ f->store_32(block_size); //write block size 4
+ f->store_32(write_max); //max amount of data written 4
+ int bc=(write_max/block_size)+1;
+
+ for(int i=0;i<bc;i++) {
+ f->store_32(0); //compressed sizes, will update later
+ }
+
+
+ Vector<int> block_sizes;
+ for(int i=0;i<bc;i++) {
+
+ int bl = i==(bc-1) ? write_max % block_size : block_size;
+ uint8_t *bp = &write_ptr[i*block_size];
+
+ Vector<uint8_t> cblock;
+ cblock.resize(Compression::get_max_compressed_buffer_size(bl,cmode));
+ int s = Compression::compress(cblock.ptr(),bp,bl,cmode);
+
+ f->store_buffer(cblock.ptr(),s);
+ block_sizes.push_back(s);
+ }
+
+ f->seek(16); //ok write block sizes
+ for(int i=0;i<bc;i++)
+ f->store_32(block_sizes[i]);
+ f->seek_end();
+ f->store_buffer((const uint8_t*)mgc.get_data(),mgc.length()); //magic at the end too
+
+ buffer.clear();
+
+ } else {
+
+
+ comp_buffer.clear();
+ buffer.clear();
+ read_blocks.clear();
+ }
+
+ memdelete(f);
+ f=NULL;
+
+}
+
+bool FileAccessCompressed::is_open() const{
+
+ return f!=NULL;
+}
+
+void FileAccessCompressed::seek(size_t p_position){
+
+ ERR_FAIL_COND(!f);
+ if (writing) {
+
+ ERR_FAIL_COND(p_position>write_max);
+
+ write_pos=p_position;
+
+ } else {
+
+ ERR_FAIL_COND(p_position>read_total);
+ if (p_position==read_total) {
+ at_end=true;
+ } else {
+
+ int block_idx = p_position/block_size;
+ if (block_idx!=read_block) {
+
+ read_block=block_idx;
+ f->seek(read_blocks[read_block].offset);
+ f->get_buffer(comp_buffer.ptr(),read_blocks[read_block].csize);
+ Compression::decompress(buffer.ptr(),read_blocks.size()==1?read_total:block_size,comp_buffer.ptr(),read_blocks[read_block].csize,cmode);
+ read_block_size=read_block==read_block_count-1?read_total%block_size:block_size;
+ }
+
+ read_pos=p_position%block_size;
+ }
+ }
+}
+
+
+void FileAccessCompressed::seek_end(int64_t p_position){
+
+ ERR_FAIL_COND(!f);
+ if (writing) {
+
+ seek(write_max+p_position);
+ } else {
+
+ seek(read_total+p_position);
+
+ }
+
+
+}
+size_t FileAccessCompressed::get_pos() const{
+
+ ERR_FAIL_COND_V(!f,0);
+ if (writing) {
+
+ return write_pos;
+ } else {
+
+ return read_block*block_size+read_pos;
+ }
+
+}
+size_t FileAccessCompressed::get_len() const{
+
+ ERR_FAIL_COND_V(!f,0);
+ if (writing) {
+
+ return write_max;
+ } else {
+ return read_total;
+ }
+}
+
+bool FileAccessCompressed::eof_reached() const{
+
+ ERR_FAIL_COND_V(!f,false);
+ if (writing) {
+ return false;
+ } else {
+ return read_eof;
+ }
+}
+
+uint8_t FileAccessCompressed::get_8() const{
+
+ ERR_FAIL_COND_V(writing,0);
+ ERR_FAIL_COND_V(!f,0);
+
+ if (at_end) {
+ read_eof=true;
+ return 0;
+ }
+
+ uint8_t ret = read_ptr[read_pos];
+
+ read_pos++;
+ if (read_pos>=read_block_size) {
+ read_block++;
+
+ if (read_block<read_block_count) {
+ //read another block of compressed data
+ f->get_buffer(comp_buffer.ptr(),read_blocks[read_block].csize);
+ Compression::decompress(buffer.ptr(),read_blocks.size()==1?read_total:block_size,comp_buffer.ptr(),read_blocks[read_block].csize,cmode);
+ read_block_size=read_block==read_block_count-1?read_total%block_size:block_size;
+ read_pos=0;
+
+ } else {
+ read_block--;
+ at_end=true;
+ ret =0;
+ }
+ }
+
+ return ret;
+
+}
+int FileAccessCompressed::get_buffer(uint8_t *p_dst, int p_length) const{
+
+ ERR_FAIL_COND_V(writing,0);
+ ERR_FAIL_COND_V(!f,0);
+
+ if (at_end) {
+ read_eof=true;
+ return 0;
+ }
+
+
+ for(int i=0;i<p_length;i++) {
+
+
+ p_dst[i]=read_ptr[read_pos];
+ read_pos++;
+ if (read_pos>=read_block_size) {
+ read_block++;
+
+ if (read_block<read_block_count) {
+ //read another block of compressed data
+ f->get_buffer(comp_buffer.ptr(),read_blocks[read_block].csize);
+ Compression::decompress(buffer.ptr(),read_blocks.size()==1?read_total:block_size,comp_buffer.ptr(),read_blocks[read_block].csize,cmode);
+ read_block_size=read_block==read_block_count-1?read_total%block_size:block_size;
+ read_pos=0;
+
+ } else {
+ read_block--;
+ at_end=true;
+ if (i<p_length-1)
+ read_eof=true;
+ return i;
+
+ }
+ }
+
+ }
+
+ return p_length;
+
+}
+
+Error FileAccessCompressed::get_error() const{
+
+ return read_eof?ERR_FILE_EOF:OK;
+}
+
+void FileAccessCompressed::store_8(uint8_t p_dest){
+
+ ERR_FAIL_COND(!f);
+ ERR_FAIL_COND(!writing);
+
+ WRITE_FIT(1);
+ write_ptr[write_pos++]=p_dest;
+
+}
+
+bool FileAccessCompressed::file_exists(const String& p_name){
+
+ FileAccess *fa = FileAccess::open(p_name,FileAccess::READ);
+ if (!fa)
+ return false;
+ memdelete(fa);
+ return true;
+}
+
+uint64_t FileAccessCompressed::_get_modified_time(const String& p_file) {
+
+ if (f)
+ return f->get_modified_time(p_file);
+ else
+ return 0;
+}
+
+FileAccessCompressed::FileAccessCompressed() {
+
+ f=NULL;
+ magic="GCMP";
+ block_size=4096;
+ cmode=Compression::MODE_FASTLZ;
+ writing=false;
+ write_ptr=0;
+ write_buffer_size=0;
+ write_max=0;
+ block_size=0;
+ read_eof=false;
+ at_end=false;
+ read_total=0;
+ read_ptr=NULL;
+ read_block=0;
+ read_block_count=0;
+ read_block_size=0;
+ read_pos=0;
+
+}
+
+FileAccessCompressed::~FileAccessCompressed(){
+
+ if (f)
+ close();
+
+}
diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h
new file mode 100644
index 0000000000..3039b5c8be
--- /dev/null
+++ b/core/io/file_access_compressed.h
@@ -0,0 +1,101 @@
+/*************************************************************************/
+/* file_access_compressed.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef FILE_ACCESS_COMPRESSED_H
+#define FILE_ACCESS_COMPRESSED_H
+
+#include "io/compression.h"
+#include "os/file_access.h"
+
+class FileAccessCompressed : public FileAccess {
+
+ Compression::Mode cmode;
+ bool writing;
+ int write_pos;
+ uint8_t*write_ptr;
+ int write_buffer_size;
+ int write_max;
+ int block_size;
+ mutable bool read_eof;
+ mutable bool at_end;
+
+ struct ReadBlock {
+ int csize;
+ int offset;
+ };
+
+ mutable Vector<uint8_t> comp_buffer;
+ uint8_t *read_ptr;
+ mutable int read_block;
+ int read_block_count;
+ mutable int read_block_size;
+ mutable int read_pos;
+ Vector<ReadBlock> read_blocks;
+ int read_total;
+
+
+
+
+ String magic;
+ mutable Vector<uint8_t> buffer;
+ FileAccess *f;
+public:
+
+ void configure(const String& p_magic, Compression::Mode p_mode=Compression::MODE_FASTLZ, int p_block_size=4096);
+
+ Error open_after_magic(FileAccess *p_base);
+
+ virtual Error _open(const String& p_path, int p_mode_flags); ///< open a file
+ virtual void close(); ///< close a file
+ virtual bool is_open() const; ///< true when file is open
+
+ virtual void seek(size_t p_position); ///< seek to a given position
+ virtual void seek_end(int64_t p_position=0); ///< seek from the end of file
+ virtual size_t get_pos() const; ///< get position in the file
+ virtual size_t get_len() const; ///< get size of the file
+
+ virtual bool eof_reached() const; ///< reading passed EOF
+
+ virtual uint8_t get_8() const; ///< get a byte
+ virtual int get_buffer(uint8_t *p_dst, int p_length) const;
+
+ virtual Error get_error() const; ///< get last error
+
+ virtual void store_8(uint8_t p_dest); ///< store a byte
+
+ virtual bool file_exists(const String& p_name); ///< return true if a file exists
+
+ virtual uint64_t _get_modified_time(const String& p_file);
+
+
+ FileAccessCompressed();
+ virtual ~FileAccessCompressed();
+
+};
+
+#endif // FILE_ACCESS_COMPRESSED_H
diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp
new file mode 100644
index 0000000000..a1dd2e48bb
--- /dev/null
+++ b/core/io/file_access_memory.cpp
@@ -0,0 +1,188 @@
+/*************************************************************************/
+/* file_access_memory.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. */
+/*************************************************************************/
+#include "file_access_memory.h"
+
+#include "os/dir_access.h"
+#include "os/copymem.h"
+#include "globals.h"
+#include "map.h"
+
+static Map<String, Vector<uint8_t> >* files = NULL;
+
+void FileAccessMemory::register_file(String p_name, Vector<uint8_t> p_data) {
+
+ if (!files) {
+ files = memnew((Map<String, Vector<uint8_t> >));
+ };
+
+ String name;
+ if (Globals::get_singleton())
+ name = Globals::get_singleton()->globalize_path(p_name);
+ else
+ name = p_name;
+ name = DirAccess::normalize_path(name);
+
+ (*files)[name] = p_data;
+};
+
+void FileAccessMemory::cleanup() {
+
+ if (!files)
+ return;
+
+ memdelete(files);
+};
+
+
+FileAccess* FileAccessMemory::create() {
+
+ return memnew(FileAccessMemory);
+};
+
+bool FileAccessMemory::file_exists(const String& p_name) {
+
+ String name = fix_path(p_name);
+ name = DirAccess::normalize_path(name);
+
+ return files && (files->find(name) != NULL);
+};
+
+
+Error FileAccessMemory::_open(const String& p_path, int p_mode_flags) {
+
+ ERR_FAIL_COND_V(!files, ERR_FILE_NOT_FOUND);
+
+ String name = fix_path(p_path);
+ name = DirAccess::normalize_path(name);
+
+ Map<String, Vector<uint8_t> >::Element* E = files->find(name);
+ ERR_FAIL_COND_V(!E, ERR_FILE_NOT_FOUND);
+
+ data = &(E->get()[0]);
+ length = E->get().size();
+ pos = 0;
+
+ return OK;
+};
+
+void FileAccessMemory::close() {
+
+ data = NULL;
+};
+
+bool FileAccessMemory::is_open() const {
+
+ return data != NULL;
+};
+
+void FileAccessMemory::seek(size_t p_position) {
+
+ ERR_FAIL_COND(!data);
+ pos = p_position;
+};
+
+void FileAccessMemory::seek_end(int64_t p_position) {
+
+ ERR_FAIL_COND(!data);
+ pos = length + p_position;
+};
+
+size_t FileAccessMemory::get_pos() const {
+
+ ERR_FAIL_COND_V(!data, 0);
+ return pos;
+};
+
+size_t FileAccessMemory::get_len() const {
+
+ ERR_FAIL_COND_V(!data, 0);
+ return length;
+};
+
+bool FileAccessMemory::eof_reached() const {
+
+ return pos >= length;
+};
+
+uint8_t FileAccessMemory::get_8() const {
+
+ uint8_t ret;
+ if (pos < length) {
+ ret = data[pos];
+ };
+ ++pos;
+
+ return ret;
+};
+
+int FileAccessMemory::get_buffer(uint8_t *p_dst,int p_length) const {
+
+ ERR_FAIL_COND_V(!data, -1);
+
+ int left = length - pos;
+ int read = MIN(p_length, left);
+
+ if (read < p_length) {
+ WARN_PRINT("Reading less data than requested");
+ };
+
+ copymem(p_dst, &data[pos], read);
+ pos += p_length;
+
+ return read;
+};
+
+Error FileAccessMemory::get_error() const {
+
+ return pos >= length ? ERR_FILE_EOF : OK;
+};
+
+void FileAccessMemory::store_8(uint8_t p_byte) {
+
+ ERR_FAIL_COND(!data);
+ ERR_FAIL_COND(pos >= length);
+ data[pos++] = p_byte;
+};
+
+void FileAccessMemory::store_buffer(const uint8_t *p_src,int p_length) {
+
+ int left = length - pos;
+ int write = MIN(p_length, left);
+ if (write < p_length) {
+ WARN_PRINT("Writing less data than requested");
+ };
+
+ copymem(&data[pos], p_src, write);
+ pos += p_length;
+};
+
+FileAccessMemory::FileAccessMemory() {
+
+ data = NULL;
+}
diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h
new file mode 100644
index 0000000000..a02a022a4f
--- /dev/null
+++ b/core/io/file_access_memory.h
@@ -0,0 +1,76 @@
+/*************************************************************************/
+/* file_access_memory.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef FILE_ACCESS_MEMORY_H
+#define FILE_ACCESS_MEMORY_H
+
+#include "os/file_access.h"
+
+class FileAccessMemory : public FileAccess {
+
+ uint8_t* data;
+ int length;
+ mutable int pos;
+
+ static FileAccess* create();
+
+public:
+
+ static void register_file(String p_name, Vector<uint8_t> p_data);
+ static void cleanup();
+
+ virtual Error _open(const String& p_path, int p_mode_flags); ///< open a file
+ virtual void close(); ///< close a file
+ virtual bool is_open() const; ///< true when file is open
+
+ virtual void seek(size_t p_position); ///< seek to a given position
+ virtual void seek_end(int64_t p_position); ///< seek from the end of file
+ virtual size_t get_pos() const; ///< get position in the file
+ virtual size_t get_len() const; ///< get size of the file
+
+ virtual bool eof_reached() const; ///< reading passed EOF
+
+ virtual uint8_t get_8() const; ///< get a byte
+
+ virtual int get_buffer(uint8_t *p_dst,int p_length) const; ///< get an array of bytes
+
+ virtual Error get_error() const; ///< get last error
+
+ virtual void store_8(uint8_t p_dest); ///< store a byte
+ virtual void store_buffer(const uint8_t *p_src,int p_length); ///< store an array of bytes
+
+ virtual bool file_exists(const String& p_name); ///< return true if a file exists
+
+ virtual uint64_t _get_modified_time(const String& p_file) { return 0; }
+
+
+
+ FileAccessMemory();
+};
+
+#endif // FILE_ACCESS_MEMORY_H
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
new file mode 100644
index 0000000000..a5636b137d
--- /dev/null
+++ b/core/io/file_access_network.cpp
@@ -0,0 +1,566 @@
+/*************************************************************************/
+/* file_access_network.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. */
+/*************************************************************************/
+#include "file_access_network.h"
+#include "marshalls.h"
+#include "globals.h"
+#include "os/os.h"
+#include "io/ip.h"
+
+
+
+#define DEBUG_PRINT(m_p) print_line(m_p)
+//#define DEBUG_TIME(m_what) printf("MS: %s - %lli\n",m_what,OS::get_singleton()->get_ticks_usec());
+//#define DEBUG_PRINT(m_p)
+#define DEBUG_TIME(m_what)
+
+
+void FileAccessNetworkClient::lock_mutex() {
+
+ mutex->lock();
+ lockcount++;
+}
+
+void FileAccessNetworkClient::unlock_mutex() {
+
+ lockcount--;
+ mutex->unlock();
+
+}
+
+void FileAccessNetworkClient::put_32(int p_32) {
+
+ uint8_t buf[4];
+ encode_uint32(p_32,buf);
+ client->put_data(buf,4);
+ DEBUG_PRINT("put32: "+itos(p_32));
+}
+
+void FileAccessNetworkClient::put_64(int64_t p_64) {
+
+ uint8_t buf[8];
+ encode_uint64(p_64,buf);
+ client->put_data(buf,8);
+ DEBUG_PRINT("put64: "+itos(p_64));
+
+}
+
+int FileAccessNetworkClient::get_32() {
+
+ uint8_t buf[4];
+ client->get_data(buf,4);
+ return decode_uint32(buf);
+
+}
+
+int64_t FileAccessNetworkClient::get_64() {
+
+ uint8_t buf[8];
+ client->get_data(buf,8);
+ return decode_uint64(buf);
+
+}
+
+void FileAccessNetworkClient::_thread_func() {
+
+ client->set_nodelay(true);
+ while(!quit) {
+
+ DEBUG_PRINT("SEM WAIT - "+itos(sem->get()));
+ Error err = sem->wait();
+ DEBUG_TIME("sem_unlock");
+ //DEBUG_PRINT("semwait returned "+itos(werr));
+ DEBUG_PRINT("MUTEX LOCK "+itos(lockcount));
+ DEBUG_PRINT("POPO");
+ DEBUG_PRINT("PEPE");
+ lock_mutex();
+ DEBUG_PRINT("MUTEX PASS");
+
+ blockrequest_mutex->lock();
+ while(block_requests.size()) {
+ put_32(block_requests.front()->get().id);
+ put_32(FileAccessNetwork::COMMAND_READ_BLOCK);
+ put_64(block_requests.front()->get().offset);
+ put_32(block_requests.front()->get().size);
+ block_requests.pop_front();
+ }
+ blockrequest_mutex->unlock();
+
+ DEBUG_PRINT("THREAD ITER");
+
+ DEBUG_TIME("sem_read");
+ int id = get_32();
+
+ int response = get_32();
+ DEBUG_PRINT("GET RESPONSE: "+itos(response));
+
+ FileAccessNetwork *fa=NULL;
+
+ if (response!=FileAccessNetwork::RESPONSE_DATA) {
+ ERR_FAIL_COND(!accesses.has(id));
+ }
+
+ if (accesses.has(id))
+ fa=accesses[id];
+
+
+ switch(response) {
+
+ case FileAccessNetwork::RESPONSE_OPEN: {
+
+
+ DEBUG_TIME("sem_open");
+ int status = get_32();
+ if (status!=OK) {
+ fa->_respond(0,Error(status));
+ } else {
+ uint64_t len = get_64();
+ fa->_respond(len,Error(status));
+ }
+
+ fa->sem->post();
+
+
+ } break;
+ case FileAccessNetwork::RESPONSE_DATA: {
+
+ int64_t offset = get_64();
+ uint32_t len = get_32();
+
+ Vector<uint8_t> block;
+ block.resize(len);
+ client->get_data(block.ptr(),len);
+
+ if (fa) //may have been queued
+ fa->_set_block(offset,block);
+
+ } break;
+ case FileAccessNetwork::RESPONSE_FILE_EXISTS: {
+
+
+ int status = get_32();
+ fa->exists_modtime=status!=0;
+ fa->sem->post();
+
+
+
+ } break;
+ case FileAccessNetwork::RESPONSE_GET_MODTIME: {
+
+
+ uint64_t status = get_64();
+ fa->exists_modtime=status;
+ fa->sem->post();
+
+ } break;
+
+ }
+
+
+ unlock_mutex();
+ }
+
+}
+
+void FileAccessNetworkClient::_thread_func(void *s) {
+
+ FileAccessNetworkClient *self =(FileAccessNetworkClient*)s;
+
+ self->_thread_func();
+
+}
+
+Error FileAccessNetworkClient::connect(const String& p_host,int p_port,const String& p_password) {
+
+ IP_Address ip;
+
+ if (p_host.is_valid_ip_address()) {
+ ip=p_host;
+ } else {
+ ip=IP::get_singleton()->resolve_hostname(p_host);
+ }
+
+ DEBUG_PRINT("IP: "+String(ip)+" port "+itos(p_port));
+ Error err = client->connect(ip,p_port);
+ ERR_FAIL_COND_V(err,err);
+ while(client->get_status()==StreamPeerTCP::STATUS_CONNECTING) {
+//DEBUG_PRINT("trying to connect....");
+ OS::get_singleton()->delay_usec(1000);
+ }
+
+ if (client->get_status()!=StreamPeerTCP::STATUS_CONNECTED) {
+ return ERR_CANT_CONNECT;
+ }
+
+ CharString cs = p_password.utf8();
+ put_32(cs.length());
+ client->put_data((const uint8_t*)cs.ptr(),cs.length());
+
+ int e = get_32();
+
+ if (e!=OK) {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ thread = Thread::create(_thread_func,this);
+
+ return OK;
+}
+
+FileAccessNetworkClient *FileAccessNetworkClient::singleton=NULL;
+
+
+FileAccessNetworkClient::FileAccessNetworkClient() {
+
+ thread=NULL;
+ mutex = Mutex::create();
+ blockrequest_mutex = Mutex::create();
+ quit=false;
+ singleton=this;
+ last_id=0;
+ client = Ref<StreamPeerTCP>( StreamPeerTCP::create() );
+ sem=Semaphore::create();
+ lockcount=0;
+}
+
+FileAccessNetworkClient::~FileAccessNetworkClient() {
+
+ if (thread) {
+ quit=true;
+ sem->post();
+ Thread::wait_to_finish(thread);
+ }
+
+ memdelete(blockrequest_mutex);
+ memdelete(mutex);
+ memdelete(sem);
+
+
+}
+
+void FileAccessNetwork::_set_block(size_t p_offset,const Vector<uint8_t>& p_block) {
+
+
+ int page = p_offset/page_size;
+ ERR_FAIL_INDEX(page,pages.size());
+ if (page<pages.size()-1) {
+ ERR_FAIL_COND(p_block.size()!=page_size);
+ } else {
+ ERR_FAIL_COND( (p_block.size() != (total_size%page_size)));
+ }
+
+ buffer_mutex->lock();
+ pages[page].buffer=p_block;
+ pages[page].queued=false;
+ buffer_mutex->unlock();
+
+ if (waiting_on_page==page) {
+ waiting_on_page=-1;
+ page_sem->post();
+ }
+}
+
+
+void FileAccessNetwork::_respond(size_t p_len,Error p_status) {
+
+ DEBUG_PRINT("GOT RESPONSE - len: "+itos(p_len)+" status: "+itos(p_status));
+ response=p_status;
+ if (response!=OK)
+ return;
+ opened=true;
+ total_size=p_len;
+ int pc = ((total_size-1)/page_size)+1;
+ pages.resize(pc);
+
+
+
+
+}
+
+Error FileAccessNetwork::_open(const String& p_path, int p_mode_flags) {
+
+ ERR_FAIL_COND_V(p_mode_flags!=READ,ERR_UNAVAILABLE);
+ if (opened)
+ close();
+ FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
+ DEBUG_PRINT("open: "+p_path);
+
+ DEBUG_TIME("open_begin");
+
+ nc->lock_mutex();
+ nc->put_32(id);
+ nc->accesses[id]=this;
+ nc->put_32(COMMAND_OPEN_FILE);
+ CharString cs =p_path.utf8();
+ nc->put_32(cs.length());
+ nc->client->put_data((const uint8_t*)cs.ptr(),cs.length());
+ pos=0;
+ eof_flag=false;
+ last_page=-1;
+ last_page_buff=NULL;
+
+// buffers.clear();
+ nc->unlock_mutex();
+ DEBUG_PRINT("OPEN POST");
+ DEBUG_TIME("open_post");
+ nc->sem->post(); //awaiting answer
+ DEBUG_PRINT("WAIT...");
+ sem->wait();
+ DEBUG_TIME("open_end");
+ DEBUG_PRINT("WAIT ENDED...");
+
+ return response;
+}
+
+void FileAccessNetwork::close(){
+
+ if (!opened)
+ return;
+
+ FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
+
+ DEBUG_PRINT("CLOSE");
+ nc->lock_mutex();
+ nc->put_32(id);
+ nc->put_32(COMMAND_CLOSE);
+ pages.clear();
+ opened=false;
+ nc->unlock_mutex();
+
+
+}
+bool FileAccessNetwork::is_open() const{
+
+ return opened;
+}
+
+void FileAccessNetwork::seek(size_t p_position){
+
+ ERR_FAIL_COND(!opened);
+ eof_flag=p_position>total_size;
+
+ if (p_position>=total_size) {
+ p_position=total_size;
+ }
+
+ pos=p_position;
+}
+
+void FileAccessNetwork::seek_end(int64_t p_position){
+
+ seek(total_size+p_position);
+
+}
+size_t FileAccessNetwork::get_pos() const{
+
+ ERR_FAIL_COND_V(!opened,0);
+ return pos;
+}
+size_t FileAccessNetwork::get_len() const{
+
+ ERR_FAIL_COND_V(!opened,0);
+ return total_size;
+}
+
+bool FileAccessNetwork::eof_reached() const{
+
+ ERR_FAIL_COND_V(!opened,false);
+ return eof_flag;
+}
+
+uint8_t FileAccessNetwork::get_8() const{
+
+ uint8_t v;
+ get_buffer(&v,1);
+ return v;
+
+}
+
+
+void FileAccessNetwork::_queue_page(int p_page) const {
+
+ if (p_page>=pages.size())
+ return;
+ if (pages[p_page].buffer.empty() && !pages[p_page].queued) {
+
+
+ FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
+
+ nc->blockrequest_mutex->lock();
+ FileAccessNetworkClient::BlockRequest br;
+ br.id=id;
+ br.offset=size_t(p_page)*page_size;
+ br.size=page_size;
+ nc->block_requests.push_back(br);
+ pages[p_page].queued=true;
+ nc->blockrequest_mutex->unlock();
+ DEBUG_PRINT("QUEUE PAGE POST");
+ nc->sem->post();
+ DEBUG_PRINT("queued "+itos(p_page));
+ }
+
+}
+
+int FileAccessNetwork::get_buffer(uint8_t *p_dst, int p_length) const{
+
+ //bool eof=false;
+ if (pos+p_length>total_size) {
+ eof_flag=true;
+ }
+ if (pos+p_length>=total_size) {
+ p_length=total_size-pos;
+ }
+
+// FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
+
+ uint8_t *buff=last_page_buff;
+
+ for(int i=0;i<p_length;i++) {
+
+ int page=pos/page_size;
+
+ if (page!=last_page) {
+ buffer_mutex->lock();
+ if (pages[page].buffer.empty()) {
+ //fuck
+
+ waiting_on_page=page;
+ for(int j=0;j<read_ahead;j++) {
+
+ _queue_page(page+j);
+ }
+ buffer_mutex->unlock();
+ DEBUG_PRINT("wait");
+ page_sem->wait();
+ DEBUG_PRINT("done");
+ } else {
+
+ for(int j=0;j<read_ahead;j++) {
+
+ _queue_page(page+j);
+ }
+ buff=pages[page].buffer.ptr();
+ //queue pages
+ buffer_mutex->unlock();
+ }
+
+ buff=pages[page].buffer.ptr();
+ last_page_buff=buff;
+ last_page=page;
+ }
+
+ p_dst[i]=buff[pos-uint64_t(page)*page_size];
+ pos++;
+ }
+
+ return p_length;
+}
+
+Error FileAccessNetwork::get_error() const{
+
+ return pos==total_size?ERR_FILE_EOF:OK;
+}
+
+void FileAccessNetwork::store_8(uint8_t p_dest) {
+
+ ERR_FAIL();
+}
+
+bool FileAccessNetwork::file_exists(const String& p_path){
+
+ FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
+ nc->lock_mutex();
+ nc->put_32(id);
+ nc->put_32(COMMAND_FILE_EXISTS);
+ CharString cs=p_path.utf8();
+ nc->put_32(cs.length());
+ nc->client->put_data((const uint8_t*)cs.ptr(),cs.length());
+ nc->unlock_mutex();
+ DEBUG_PRINT("FILE EXISTS POST");
+ nc->sem->post();
+ sem->wait();
+
+ return exists_modtime!=0;
+
+}
+
+uint64_t FileAccessNetwork::_get_modified_time(const String& p_file){
+
+ FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
+ nc->lock_mutex();
+ nc->put_32(id);
+ nc->put_32(COMMAND_GET_MODTIME);
+ CharString cs=p_file.utf8();
+ nc->put_32(cs.length());
+ nc->client->put_data((const uint8_t*)cs.ptr(),cs.length());
+ nc->unlock_mutex();
+ DEBUG_PRINT("MODTIME POST");
+ nc->sem->post();
+ sem->wait();
+
+ return exists_modtime;
+
+}
+
+FileAccessNetwork::FileAccessNetwork() {
+
+ eof_flag=false;
+ opened=false;
+ pos=0;
+ sem=Semaphore::create();
+ page_sem=Semaphore::create();
+ buffer_mutex=Mutex::create();
+ FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
+ nc->lock_mutex();
+ id=nc->last_id++;
+ nc->accesses[id]=this;
+ nc->unlock_mutex();
+ page_size = GLOBAL_DEF("remote_fs/page_size",65536);
+ read_ahead = GLOBAL_DEF("remote_fs/page_read_ahead",4);
+ max_pages = GLOBAL_DEF("remote_fs/max_pages",20);
+ last_activity_val=0;
+ waiting_on_page=-1;
+ last_page=-1;
+
+
+}
+
+FileAccessNetwork::~FileAccessNetwork() {
+
+ close();
+ memdelete(sem);
+ memdelete(page_sem);
+ memdelete(buffer_mutex);
+
+ FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
+ nc->lock_mutex();
+ id=nc->last_id++;
+ nc->accesses.erase(id);
+ nc->unlock_mutex();
+
+}
diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h
new file mode 100644
index 0000000000..f338bea43f
--- /dev/null
+++ b/core/io/file_access_network.h
@@ -0,0 +1,169 @@
+/*************************************************************************/
+/* file_access_network.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef FILE_ACCESS_NETWORK_H
+#define FILE_ACCESS_NETWORK_H
+
+#include "os/file_access.h"
+#include "os/semaphore.h"
+#include "os/thread.h"
+#include "io/stream_peer_tcp.h"
+
+class FileAccessNetwork;
+
+class FileAccessNetworkClient {
+
+
+ struct BlockRequest {
+
+ int id;
+ uint64_t offset;
+ int size;
+ };
+
+ int ml;
+
+ List<BlockRequest> block_requests;
+
+ Semaphore *sem;
+ Thread *thread;
+ bool quit;
+ Mutex *mutex;
+ Mutex *blockrequest_mutex;
+ Map<int,FileAccessNetwork*> accesses;
+ Ref<StreamPeerTCP> client;
+ int last_id;
+
+ Vector<uint8_t> block;
+
+ void _thread_func();
+ static void _thread_func(void *s);
+
+ void put_32(int p_32);
+ void put_64(int64_t p_64);
+ int get_32();
+ int64_t get_64();
+ int lockcount;
+ void lock_mutex();
+ void unlock_mutex();
+
+friend class FileAccessNetwork;
+ static FileAccessNetworkClient *singleton;
+
+public:
+
+ static FileAccessNetworkClient *get_singleton() { return singleton; }
+
+ Error connect(const String& p_host,int p_port,const String& p_password="");
+
+ FileAccessNetworkClient();
+ ~FileAccessNetworkClient();
+
+};
+
+class FileAccessNetwork : public FileAccess {
+
+ Semaphore *sem;
+ Semaphore *page_sem;
+ Mutex *buffer_mutex;
+ bool opened;
+ size_t total_size;
+ mutable size_t pos;
+ int id;
+ mutable bool eof_flag;
+ mutable int last_page;
+ mutable uint8_t *last_page_buff;
+
+ uint32_t page_size;
+ int read_ahead;
+ int max_pages;
+
+ mutable int waiting_on_page;
+ mutable int last_activity_val;
+ struct Page {
+ int activity;
+ bool queued;
+ Vector<uint8_t> buffer;
+ Page() { activity=0; queued=false; }
+ };
+
+ mutable Vector< Page > pages;
+
+ mutable Error response;
+
+ uint64_t exists_modtime;
+friend class FileAccessNetworkClient;
+ void _queue_page(int p_page) const;
+ void _respond(size_t p_len,Error p_status);
+ void _set_block(size_t p_offset,const Vector<uint8_t>& p_block);
+
+public:
+
+ enum Command {
+ COMMAND_OPEN_FILE,
+ COMMAND_READ_BLOCK,
+ COMMAND_CLOSE,
+ COMMAND_FILE_EXISTS,
+ COMMAND_GET_MODTIME,
+ };
+
+ enum Response {
+ RESPONSE_OPEN,
+ RESPONSE_DATA,
+ RESPONSE_FILE_EXISTS,
+ RESPONSE_GET_MODTIME,
+ };
+
+
+ virtual Error _open(const String& p_path, int p_mode_flags); ///< open a file
+ virtual void close(); ///< close a file
+ virtual bool is_open() const; ///< true when file is open
+
+ virtual void seek(size_t p_position); ///< seek to a given position
+ virtual void seek_end(int64_t p_position=0); ///< seek from the end of file
+ virtual size_t get_pos() const; ///< get position in the file
+ virtual size_t get_len() const; ///< get size of the file
+
+ virtual bool eof_reached() const; ///< reading passed EOF
+
+ virtual uint8_t get_8() const; ///< get a byte
+ virtual int get_buffer(uint8_t *p_dst, int p_length) const;
+
+ virtual Error get_error() const; ///< get last error
+
+ virtual void store_8(uint8_t p_dest); ///< store a byte
+
+ virtual bool file_exists(const String& p_path); ///< return true if a file exists
+
+ virtual uint64_t _get_modified_time(const String& p_file);
+
+ FileAccessNetwork();
+ ~FileAccessNetwork();
+};
+
+#endif // FILE_ACCESS_NETWORK_H
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
new file mode 100644
index 0000000000..4443dd3575
--- /dev/null
+++ b/core/io/file_access_pack.cpp
@@ -0,0 +1,469 @@
+/*************************************************************************/
+/* file_access_pack.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. */
+/*************************************************************************/
+#include "file_access_pack.h"
+#include "version.h"
+
+#include <stdio.h>
+
+Error PackedData::add_pack(const String& p_path) {
+
+ for (int i=0; i<sources.size(); i++) {
+
+ if (sources[i]->try_open_pack(p_path)) {
+
+ return OK;
+ };
+ };
+
+ return ERR_FILE_UNRECOGNIZED;
+};
+
+void PackedData::add_path(const String& pkg_path, const String& path, uint64_t ofs, uint64_t size, PackSource* p_src) {
+
+ bool exists = files.has(path);
+
+ PackedFile pf;
+ pf.pack=pkg_path;
+ pf.offset=ofs;
+ pf.size=size;
+ pf.src = p_src;
+
+ files[path]=pf;
+
+ if (!exists) {
+ //search for dir
+ String p = path.replace_first("res://","");
+ PackedDir *cd=root;
+
+ if (p.find("/")!=-1) { //in a subdir
+
+ Vector<String> ds=p.get_base_dir().split("/");
+
+ for(int j=0;j<ds.size();j++) {
+
+ if (!cd->subdirs.has(ds[j])) {
+
+ PackedDir *pd = memnew( PackedDir );
+ pd->name=ds[j];
+ pd->parent=cd;
+ cd->subdirs[pd->name]=pd;
+ cd=pd;
+ } else {
+ cd=cd->subdirs[ds[j]];
+ }
+ }
+ }
+ cd->files.insert(path.get_file());
+ }
+}
+
+void PackedData::add_pack_source(PackSource *p_source) {
+
+ sources.push_back(p_source);
+};
+
+PackedData *PackedData::singleton=NULL;
+
+PackedData::PackedData() {
+
+ singleton=this;
+ root=memnew(PackedDir);
+ root->parent=NULL;
+ disabled=false;
+
+ add_pack_source(memnew(PackedSourcePCK));
+}
+
+
+//////////////////////////////////////////////////////////////////
+
+bool PackedSourcePCK::try_open_pack(const String& p_path) {
+
+ FileAccess *f = FileAccess::open(p_path,FileAccess::READ);
+ if (!f)
+ return false;
+
+ uint32_t magic= f->get_32();
+
+ if (magic != 0x4b435047) {
+ //maybe at he end.... self contained exe
+ f->seek_end();
+ f->seek( f->get_pos() -4 );
+ magic = f->get_32();
+ if (magic != 0x4b435047) {
+
+ memdelete(f);
+ return false;
+ }
+ f->seek( f->get_pos() -12 );
+
+
+ uint64_t ds = f->get_64();
+ f->seek( f->get_pos() -ds-8 );
+
+ magic = f->get_32();
+ if (magic != 0x4b435047) {
+
+ memdelete(f);
+ return false;
+ }
+
+ }
+
+ uint32_t ver_major = f->get_32();
+ uint32_t ver_minor = f->get_32();
+ uint32_t ver_rev = f->get_32();
+
+ ERR_EXPLAIN("Pack created with a newer version of the engine: "+itos(ver_major)+"."+itos(ver_minor)+"."+itos(ver_rev));
+ ERR_FAIL_COND_V( ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR), ERR_INVALID_DATA);
+
+ for(int i=0;i<16;i++) {
+ //reserved
+ f->get_32();
+ }
+
+ int file_count = f->get_32();
+
+ for(int i=0;i<file_count;i++) {
+
+ uint32_t sl = f->get_32();
+ CharString cs;
+ cs.resize(sl+1);
+ f->get_buffer((uint8_t*)cs.ptr(),sl);
+ cs[sl]=0;
+
+ String path;
+ path.parse_utf8(cs.ptr());
+
+ uint64_t ofs = f->get_64();
+ uint64_t size = f->get_64();
+
+ PackedData::get_singleton()->add_path(p_path, path, ofs, size, this);
+ };
+
+ return true;
+};
+
+FileAccess* PackedSourcePCK::get_file(const String &p_path, PackedData::PackedFile* p_file) {
+
+ return memnew( FileAccessPack(p_path, *p_file));
+};
+
+//////////////////////////////////////////////////////////////////
+
+
+Error FileAccessPack::_open(const String& p_path, int p_mode_flags) {
+
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+ return ERR_UNAVAILABLE;
+}
+
+void FileAccessPack::close() {
+
+ f->close();
+}
+
+bool FileAccessPack::is_open() const{
+
+ return f->is_open();
+}
+
+void FileAccessPack::seek(size_t p_position){
+
+ if (p_position>pf.size) {
+ eof=true;
+ } else {
+ eof=false;
+ }
+
+ f->seek(pf.offset+p_position);
+}
+void FileAccessPack::seek_end(int64_t p_position){
+
+ seek(pf.size+p_position);
+
+}
+size_t FileAccessPack::get_pos() const {
+
+ return pos;
+}
+size_t FileAccessPack::get_len() const{
+
+ return pf.size;
+}
+
+bool FileAccessPack::eof_reached() const{
+
+ return eof;
+}
+
+uint8_t FileAccessPack::get_8() const {
+
+ if (pos>=pf.size) {
+ eof=true;
+ return 0;
+ }
+
+ pos++;
+ return f->get_8();
+}
+
+
+int FileAccessPack::get_buffer(uint8_t *p_dst,int p_length) const {
+
+ if (eof)
+ return 0;
+
+ int64_t to_read=p_length;
+ if (to_read+pos > pf.size) {
+ eof=true;
+ to_read=int64_t(pf.size)-int64_t(pos);
+ }
+
+ pos+=p_length;
+
+ if (to_read<=0)
+ return 0;
+ f->get_buffer(p_dst,to_read);
+
+ return to_read;
+}
+
+void FileAccessPack::set_endian_swap(bool p_swap) {
+ FileAccess::set_endian_swap(p_swap);
+ f->set_endian_swap(p_swap);
+}
+
+Error FileAccessPack::get_error() const {
+
+ if (eof)
+ return ERR_FILE_EOF;
+ return OK;
+}
+
+void FileAccessPack::store_8(uint8_t p_dest) {
+
+ ERR_FAIL();
+
+}
+
+void FileAccessPack::store_buffer(const uint8_t *p_src,int p_length) {
+
+ ERR_FAIL();
+
+}
+
+bool FileAccessPack::file_exists(const String& p_name) {
+
+ return false;
+}
+
+
+FileAccessPack::FileAccessPack(const String& p_path, const PackedData::PackedFile& p_file) {
+
+ pf=p_file;
+ f=FileAccess::open(pf.pack,FileAccess::READ);
+ if (!f) {
+ ERR_EXPLAIN("Can't open pack-referenced file: "+String(pf.pack));
+ ERR_FAIL_COND(!f);
+ }
+ f->seek(pf.offset);
+ pos=0;
+ eof=false;
+}
+
+FileAccessPack::~FileAccessPack() {
+ if (f)
+ memdelete(f);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////
+// DIR ACCESS
+//////////////////////////////////////////////////////////////////////////////////
+
+
+bool DirAccessPack::list_dir_begin() {
+
+
+ list_dirs.clear();
+ list_files.clear();
+
+ for (Map<String,PackedData::PackedDir*>::Element *E=current->subdirs.front();E;E=E->next()) {
+
+ list_dirs.push_back(E->key());
+ }
+
+ for (Set<String>::Element *E=current->files.front();E;E=E->next()) {
+
+ list_files.push_back(E->get());
+ }
+
+ return true;
+}
+
+String DirAccessPack::get_next(){
+
+ if (list_dirs.size()) {
+ cdir=true;
+ String d = list_dirs.front()->get();
+ list_dirs.pop_front();
+ return d;
+ } else if (list_files.size()) {
+ cdir=false;
+ String f = list_files.front()->get();
+ list_files.pop_front();
+ return f;
+ } else {
+ return String();
+ }
+}
+bool DirAccessPack::current_is_dir() const{
+
+ return cdir;
+}
+void DirAccessPack::list_dir_end() {
+
+ list_dirs.clear();
+ list_files.clear();
+}
+
+int DirAccessPack::get_drive_count() {
+
+ return 0;
+}
+String DirAccessPack::get_drive(int p_drive) {
+
+ return "";
+}
+
+Error DirAccessPack::change_dir(String p_dir) {
+
+ String nd = p_dir.replace("\\","/");
+ bool absolute=false;
+ if (nd.begins_with("res://")) {
+ nd=nd.replace_first("res://","");
+ absolute=true;
+ }
+
+ nd=nd.simplify_path();
+
+ if (nd.begins_with("/")) {
+ nd=nd.replace_first("/","") ;
+ absolute=true;
+ }
+
+ Vector<String> paths = nd.split("/");
+
+ PackedData::PackedDir *pd;
+
+ if (absolute)
+ pd = PackedData::get_singleton()->root;
+ else
+ pd = current;
+
+ for(int i=0;i<paths.size();i++) {
+
+ String p = paths[i];
+ if (p==".") {
+ continue;
+ } else if (p=="..") {
+ if (pd->parent) {
+ pd=pd->parent;
+ }
+ } else if (pd->subdirs.has(p)) {
+
+ pd=pd->subdirs[p];
+
+ } else {
+
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+
+ current=pd;
+
+ return OK;
+
+
+}
+
+String DirAccessPack::get_current_dir() {
+
+ String p;
+ PackedData::PackedDir *pd = current;
+ while(pd->parent) {
+
+ if (pd!=current)
+ p="/"+p;
+ p=p+pd->name;
+ }
+
+ return "res://"+p;
+
+}
+
+bool DirAccessPack::file_exists(String p_file){
+
+ return current->files.has(p_file);
+}
+
+Error DirAccessPack::make_dir(String p_dir){
+
+ return ERR_UNAVAILABLE;
+}
+
+Error DirAccessPack::rename(String p_from, String p_to){
+
+ return ERR_UNAVAILABLE;
+
+}
+Error DirAccessPack::remove(String p_name){
+
+ return ERR_UNAVAILABLE;
+
+}
+
+size_t DirAccessPack::get_space_left(){
+
+ return 0;
+}
+
+DirAccessPack::DirAccessPack() {
+
+ current=PackedData::get_singleton()->root;
+ cdir=false;
+}
+
+DirAccessPack::~DirAccessPack() {
+
+
+}
+
+
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
new file mode 100644
index 0000000000..97e236009e
--- /dev/null
+++ b/core/io/file_access_pack.h
@@ -0,0 +1,204 @@
+/*************************************************************************/
+/* file_access_pack.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef FILE_ACCESS_PACK_H
+#define FILE_ACCESS_PACK_H
+
+#include "os/file_access.h"
+#include "os/dir_access.h"
+#include "map.h"
+#include "list.h"
+#include "print_string.h"
+
+class PackSource;
+
+class PackedData {
+friend class FileAccessPack;
+friend class DirAccessPack;
+friend class PackSource;
+
+public:
+ struct PackedFile {
+
+ String pack;
+ uint64_t offset;
+ uint64_t size;
+ PackSource* src;
+ };
+
+private:
+ struct PackedDir {
+ PackedDir *parent;
+ String name;
+ Map<String,PackedDir*> subdirs;
+ Set<String> files;
+ };
+
+
+ Map<String,PackedFile> files;
+ Vector<PackSource*> sources;
+
+ PackedDir *root;
+ //Map<String,PackedDir*> dirs;
+
+ static PackedData *singleton;
+ bool disabled;
+
+public:
+
+ void add_pack_source(PackSource* p_source);
+ void add_path(const String& pkg_path, const String& path, uint64_t ofs, uint64_t size, PackSource* p_src); // for PackSource
+
+ void set_disabled(bool p_disabled) { disabled=p_disabled; }
+ _FORCE_INLINE_ bool is_disabled() const { return disabled; }
+
+ static PackedData *get_singleton() { return singleton; }
+ Error add_pack(const String& p_path);
+
+ _FORCE_INLINE_ FileAccess *try_open_path(const String& p_path);
+ _FORCE_INLINE_ bool has_path(const String& p_path);
+
+ PackedData();
+};
+
+class PackSource {
+
+public:
+
+ virtual bool try_open_pack(const String& p_path)=0;
+ virtual FileAccess* get_file(const String& p_path, PackedData::PackedFile* p_file)=0;
+};
+
+class PackedSourcePCK : public PackSource {
+
+public:
+
+ virtual bool try_open_pack(const String &p_path);
+ virtual FileAccess* get_file(const String& p_path, PackedData::PackedFile* p_file);
+};
+
+
+class FileAccessPack : public FileAccess {
+
+ PackedData::PackedFile pf;
+
+ mutable size_t pos;
+ mutable bool eof;
+
+ FileAccess *f;
+ virtual Error _open(const String& p_path, int p_mode_flags);
+ virtual uint64_t _get_modified_time(const String& p_file) { return 0; }
+
+public:
+
+
+ virtual void close();
+ virtual bool is_open() const;
+
+ virtual void seek(size_t p_position);
+ virtual void seek_end(int64_t p_position=0);
+ virtual size_t get_pos() const;
+ virtual size_t get_len() const;
+
+ virtual bool eof_reached() const;
+
+ virtual uint8_t get_8() const;
+
+
+ virtual int get_buffer(uint8_t *p_dst,int p_length) const;
+
+ virtual void set_endian_swap(bool p_swap);
+
+ virtual Error get_error() const;
+
+ virtual void store_8(uint8_t p_dest);
+
+ virtual void store_buffer(const uint8_t *p_src,int p_length);
+
+ virtual bool file_exists(const String& p_name);
+
+
+ FileAccessPack(const String& p_path, const PackedData::PackedFile& p_file);
+ ~FileAccessPack();
+};
+
+
+FileAccess *PackedData::try_open_path(const String& p_path) {
+
+ if (files.has(p_path)) {
+ return files[p_path].src->get_file(p_path, &files[p_path]);
+ }
+
+ return NULL;
+}
+
+bool PackedData::has_path(const String& p_path) {
+
+ return files.has(p_path);
+}
+
+
+class DirAccessPack : public DirAccess {
+
+
+ PackedData::PackedDir *current;
+
+ List<String> list_dirs;
+ List<String> list_files;
+ bool cdir;
+
+public:
+
+ virtual bool list_dir_begin();
+ virtual String get_next();
+ virtual bool current_is_dir() const;
+ virtual void list_dir_end();
+
+ virtual int get_drive_count();
+ virtual String get_drive(int p_drive);
+
+ virtual Error change_dir(String p_dir);
+ virtual String get_current_dir();
+
+
+ virtual bool file_exists(String p_file);
+
+ virtual Error make_dir(String p_dir);
+
+ virtual Error rename(String p_from, String p_to);
+ virtual Error remove(String p_name);
+
+ size_t get_space_left();
+
+ DirAccessPack();
+ ~DirAccessPack();
+
+};
+
+
+#endif // FILE_ACCESS_PACK_H
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
diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h
new file mode 100644
index 0000000000..88272e6cfc
--- /dev/null
+++ b/core/io/file_access_zip.h
@@ -0,0 +1,125 @@
+/*************************************************************************/
+/* file_access_zip.h */
+/*************************************************************************/
+/* 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
+
+#ifndef FILE_ACCESS_Zip_H
+#define FILE_ACCESS_Zip_H
+
+#include <stdlib.h>
+#include "core/io/file_access_pack.h"
+#include "unzip.h"
+#include "map.h"
+
+class ZipArchive : public PackSource {
+
+public:
+
+ struct File {
+
+ int package;
+ unz_file_pos file_pos;
+ File() {
+
+ package = -1;
+ };
+ };
+
+
+private:
+
+ struct Package {
+ String filename;
+ unzFile zfile;
+ };
+ Vector<Package> packages;
+
+ Map<String,File> files;
+
+ static ZipArchive* instance;
+
+ FileAccess::CreateFunc fa_create_func;
+
+public:
+
+ void close_handle(unzFile p_file) const;
+ unzFile get_file_handle(String p_file) const;
+
+ Error add_package(String p_name);
+
+ bool file_exists(String p_name) const;
+
+ virtual bool try_open_pack(const String& p_path);
+ FileAccess* get_file(const String& p_path, PackedData::PackedFile* p_file);
+
+ static ZipArchive* get_singleton();
+
+ ZipArchive();
+ ~ZipArchive();
+};
+
+
+class FileAccessZip : public FileAccess {
+
+ unzFile zfile;
+ unz_file_info64 file_info;
+
+ mutable bool at_eof;
+
+ ZipArchive* archive;
+
+public:
+
+ virtual Error _open(const String& p_path, int p_mode_flags); ///< open a file
+ virtual void close(); ///< close a file
+ virtual bool is_open() const; ///< true when file is open
+
+ virtual void seek(size_t p_position); ///< seek to a given position
+ virtual void seek_end(int64_t p_position=0); ///< seek from the end of file
+ virtual size_t get_pos() const; ///< get position in the file
+ virtual size_t get_len() const; ///< get size of the file
+
+ virtual bool eof_reached() const; ///< reading passed EOF
+
+ virtual uint8_t get_8() const; ///< get a byte
+ virtual int get_buffer(uint8_t *p_dst,int p_length) const;
+
+ virtual Error get_error() const; ///< get last error
+
+ virtual void store_8(uint8_t p_dest); ///< store a byte
+ virtual bool file_exists(const String& p_name); ///< return true if a file exists
+
+ virtual uint64_t _get_modified_time(const String& p_file) { return 0; } // todo
+
+ FileAccessZip(const String& p_path, const PackedData::PackedFile& p_file);
+ ~FileAccessZip();
+};
+
+#endif // FILE_ACCESS_ZIP_H
+
+#endif
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp
new file mode 100644
index 0000000000..33c5f23f6d
--- /dev/null
+++ b/core/io/http_client.cpp
@@ -0,0 +1,641 @@
+/*************************************************************************/
+/* http_client.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. */
+/*************************************************************************/
+#include "http_client.h"
+
+
+Error HTTPClient::connect_url(const String& p_url) {
+
+ return OK;
+}
+
+Error HTTPClient::connect(const String &p_host,int p_port){
+
+ close();
+ conn_port=p_port;
+ conn_host=p_host;
+
+ if (conn_host.begins_with("http://")) {
+
+ conn_host=conn_host.replace_first("http://","");
+ } else if (conn_host.begins_with("https://")) {
+ //use https
+ conn_host=conn_host.replace_first("https://","");
+ }
+
+
+ connection=tcp_connection;
+ if (conn_host.is_valid_ip_address()) {
+ //is ip
+ Error err = tcp_connection->connect(IP_Address(conn_host),p_port);
+ if (err) {
+ status=STATUS_CANT_CONNECT;
+ return err;
+ }
+
+ status=STATUS_CONNECTING;
+ } else {
+ //is hostname
+ resolving=IP::get_singleton()->resolve_hostname_queue_item(conn_host);
+ status=STATUS_RESOLVING;
+
+ }
+
+ return OK;
+}
+
+
+void HTTPClient::set_connection(const Ref<StreamPeer>& p_connection){
+
+ close();
+ connection=p_connection;
+
+}
+
+
+Error HTTPClient::request( Method p_method, const String& p_url, const Vector<String>& p_headers,const String& p_body) {
+
+ ERR_FAIL_INDEX_V(p_method,METHOD_MAX,ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(status!=STATUS_CONNECTED,ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(connection.is_null(),ERR_INVALID_DATA);
+
+
+ static const char* _methods[METHOD_MAX]={
+ "GET",
+ "HEAD",
+ "POST",
+ "PUT",
+ "DELETE",
+ "OPTIONS",
+ "TRACE",
+ "CONNECT"};
+
+ String request=String(_methods[p_method])+" "+p_url+" HTTP/1.1\r\n";
+ request+="Host: "+conn_host+":"+itos(conn_port)+"\r\n";
+ for(int i=0;i<p_headers.size();i++) {
+ request+=p_headers[i]+"\r\n";
+ }
+ request+="\r\n";
+ request+=p_body;
+
+ CharString cs=request.utf8();
+ Error err = connection->put_data((const uint8_t*)cs.ptr(),cs.length());
+ if (err) {
+ close();
+ status=STATUS_CONNECTION_ERROR;
+ return err;
+ }
+
+ status=STATUS_REQUESTING;
+
+ return OK;
+}
+
+Error HTTPClient::send_body_text(const String& p_body){
+
+ return OK;
+}
+
+Error HTTPClient::send_body_data(const ByteArray& p_body){
+
+ return OK;
+}
+
+bool HTTPClient::has_response() const {
+
+ return response_headers.size()!=0;
+}
+
+bool HTTPClient::is_response_chunked() const {
+
+ return chunked;
+}
+
+int HTTPClient::get_response_code() const {
+
+ return response_num;
+}
+Error HTTPClient::get_response_headers(List<String> *r_response) {
+
+ if (!response_headers.size())
+ return ERR_INVALID_PARAMETER;
+
+ for(int i=0;i<response_headers.size();i++) {
+
+ r_response->push_back(response_headers[i]);
+ }
+
+ response_headers.clear();
+
+ return OK;
+}
+
+
+void HTTPClient::close(){
+
+ if (tcp_connection->get_status()!=StreamPeerTCP::STATUS_NONE)
+ tcp_connection->disconnect();
+
+ connection.unref();
+ status=STATUS_DISCONNECTED;
+ if (resolving!=IP::RESOLVER_INVALID_ID) {
+
+ IP::get_singleton()->erase_resolve_item(resolving);
+ resolving=IP::RESOLVER_INVALID_ID;
+
+ }
+
+ response_headers.clear();
+ response_str.clear();
+ body_size=0;
+ body_left=0;
+ chunk_left=0;
+ response_num=0;
+}
+
+
+Error HTTPClient::poll(){
+
+ switch(status) {
+
+
+ case STATUS_RESOLVING: {
+ ERR_FAIL_COND_V(resolving==IP::RESOLVER_INVALID_ID,ERR_BUG);
+
+ IP::ResolverStatus rstatus = IP::get_singleton()->get_resolve_item_status(resolving);
+ switch(rstatus) {
+ case IP::RESOLVER_STATUS_WAITING: return OK; //still resolving
+
+ case IP::RESOLVER_STATUS_DONE: {
+
+ IP_Address host = IP::get_singleton()->get_resolve_item_address(resolving);
+ Error err = tcp_connection->connect(host,conn_port);
+ IP::get_singleton()->erase_resolve_item(resolving);
+ resolving=IP::RESOLVER_INVALID_ID;
+ if (err) {
+ status=STATUS_CANT_CONNECT;
+ return err;
+ }
+
+ status=STATUS_CONNECTING;
+ } break;
+ case IP::RESOLVER_STATUS_NONE:
+ case IP::RESOLVER_STATUS_ERROR: {
+
+ IP::get_singleton()->erase_resolve_item(resolving);
+ resolving=IP::RESOLVER_INVALID_ID;
+ close();
+ status=STATUS_CANT_RESOLVE;
+ return ERR_CANT_RESOLVE;
+ } break;
+
+ }
+ } break;
+ case STATUS_CONNECTING: {
+
+ StreamPeerTCP::Status s = tcp_connection->get_status();
+ switch(s) {
+
+ case StreamPeerTCP::STATUS_CONNECTING: {
+ return OK; //do none
+ } break;
+ case StreamPeerTCP::STATUS_CONNECTED: {
+ status=STATUS_CONNECTED;
+ return OK;
+ } break;
+ case StreamPeerTCP::STATUS_ERROR:
+ case StreamPeerTCP::STATUS_NONE: {
+
+ close();
+ status=STATUS_CANT_CONNECT;
+ return ERR_CANT_CONNECT;
+ } break;
+ }
+ } break;
+ case STATUS_CONNECTED: {
+ //request something please
+ return OK;
+ } break;
+ case STATUS_REQUESTING: {
+
+
+ while(true) {
+ uint8_t byte;
+ int rec=0;
+ Error err = connection->get_partial_data(&byte,1,rec);
+ if (err!=OK) {
+ close();
+ status=STATUS_CONNECTION_ERROR;
+ return ERR_CONNECTION_ERROR;
+ }
+
+ if (rec==0)
+ return OK; //keep trying!
+
+ response_str.push_back(byte);
+ int rs = response_str.size();
+ if (
+ (rs>=2 && response_str[rs-2]=='\n' && response_str[rs-1]=='\n') ||
+ (rs>=4 && response_str[rs-4]=='\r' && response_str[rs-3]=='\n' && rs>=4 && response_str[rs-2]=='\r' && response_str[rs-1]=='\n')
+ ) {
+
+
+ //end of response, parse.
+ response_str.push_back(0);
+ String response;
+ response.parse_utf8((const char*)response_str.ptr());
+ print_line("END OF RESPONSE? :\n"+response+"\n------");
+ Vector<String> responses = response.split("\n");
+ body_size=0;
+ chunked=false;
+ body_left=0;
+ chunk_left=0;
+ response_headers.clear();
+ response_num = RESPONSE_OK;
+
+ for(int i=0;i<responses.size();i++) {
+
+ String s = responses[i].strip_edges();
+ if (s.length()==0)
+ continue;
+ if (s.begins_with("Content-Length:")) {
+ body_size = s.substr(s.find(":")+1,s.length()).strip_edges().to_int();
+ body_left=body_size;
+ }
+
+ if (s.begins_with("Transfer-Encoding:")) {
+ String encoding = s.substr(s.find(":")+1,s.length()).strip_edges();
+ print_line("TRANSFER ENCODING: "+encoding);
+ if (encoding=="chunked") {
+ chunked=true;
+ }
+
+ }
+
+ if (i==0 && responses[i].begins_with("HTTP")) {
+
+ String num = responses[i].get_slice(" ",1);
+ response_num=num.to_int();
+ } else {
+
+ response_headers.push_back(s);
+ }
+
+ }
+
+ if (body_size==0 && !chunked) {
+
+ status=STATUS_CONNECTED; //ask for something again?
+ } else {
+ status=STATUS_BODY;
+ }
+ return OK;
+ }
+ }
+ //wait for response
+ return OK;
+ } break;
+ case STATUS_DISCONNECTED: {
+ return ERR_UNCONFIGURED;
+ } break;
+ case STATUS_CONNECTION_ERROR: {
+ return ERR_CONNECTION_ERROR;
+ } break;
+ case STATUS_CANT_CONNECT: {
+ return ERR_CANT_CONNECT;
+ } break;
+ case STATUS_CANT_RESOLVE: {
+ return ERR_CANT_RESOLVE;
+ } break;
+ }
+
+
+ return OK;
+}
+
+
+Dictionary HTTPClient::_get_response_headers_as_dictionary() {
+
+ List<String> rh;
+ get_response_headers(&rh);
+ Dictionary ret;
+ for(const List<String>::Element *E=rh.front();E;E=E->next()) {
+ String s = E->get();
+ int sp = s.find(":");
+ if (sp==-1)
+ continue;
+ String key = s.substr(0,sp).strip_edges();
+ String value = s.substr(sp+1,s.length()).strip_edges();
+ ret[key]=value;
+
+ }
+
+ return ret;
+}
+
+StringArray HTTPClient::_get_response_headers() {
+
+ List<String> rh;
+ get_response_headers(&rh);
+ StringArray ret;
+ ret.resize(rh.size());
+ int idx=0;
+ for(const List<String>::Element *E=rh.front();E;E=E->next()) {
+ ret.set(idx++,E->get());
+ }
+
+ return ret;
+}
+
+int HTTPClient::get_response_body_length() const {
+
+ return body_size;
+}
+
+ByteArray HTTPClient::read_response_body_chunk() {
+
+ ERR_FAIL_COND_V( status !=STATUS_BODY, ByteArray() );
+
+ Error err=OK;
+
+ if (chunked) {
+
+ while(true) {
+
+ if (chunk_left==0) {
+ //reading len
+ uint8_t b;
+ int rec=0;
+ err = connection->get_partial_data(&b,1,rec);
+
+ if (rec==0)
+ break;
+
+ chunk.push_back(b);
+
+ if (chunk.size()>32) {
+ ERR_PRINT("HTTP Invalid chunk hex len");
+ status=STATUS_CONNECTION_ERROR;
+ return ByteArray();
+ }
+
+ if (chunk.size()>2 && chunk[chunk.size()-2]=='\r' && chunk[chunk.size()-1]=='\n') {
+
+ int len=0;
+ for(int i=0;i<chunk.size()-2;i++) {
+ char c = chunk[i];
+ int v=0;
+ if (c>='0' && c<='9')
+ v=c-'0';
+ else if (c>='a' && c<='f')
+ v=c-'a'+10;
+ else if (c>='A' && c<='F')
+ v=c-'A'+10;
+ else {
+ ERR_PRINT("HTTP Chunk len not in hex!!");
+ status=STATUS_CONNECTION_ERROR;
+ return ByteArray();
+ }
+ len<<=4;
+ len|=v;
+ if (len>(1<<24)) {
+ ERR_PRINT("HTTP Chunk too big!! >16mb");
+ status=STATUS_CONNECTION_ERROR;
+ return ByteArray();
+ }
+
+ }
+
+ if (len==0) {
+ //end!
+ status=STATUS_CONNECTED;
+ chunk.clear();
+ return ByteArray();
+ }
+
+ chunk_left=len+2;
+ chunk.resize(chunk_left);
+
+ }
+ } else {
+
+ int rec=0;
+ err = connection->get_partial_data(&chunk[chunk.size()-chunk_left],chunk_left,rec);
+ if (rec==0) {
+ break;
+ }
+ chunk_left-=rec;
+
+ if (chunk_left==0) {
+
+ if (chunk[chunk.size()-2]!='\r' || chunk[chunk.size()-1]!='\n') {
+ ERR_PRINT("HTTP Invalid chunk terminator (not \\r\\n)");
+ status=STATUS_CONNECTION_ERROR;
+ return ByteArray();
+ }
+
+ ByteArray ret;
+ ret.resize(chunk.size()-2);
+ {
+ ByteArray::Write w = ret.write();
+ copymem(w.ptr(),chunk.ptr(),chunk.size()-2);
+ }
+ chunk.clear();
+
+ return ret;
+
+ }
+
+ break;
+ }
+ }
+
+ } else {
+ ByteArray::Write r = tmp_read.write();
+ int rec=0;
+ err = connection->get_partial_data(r.ptr(),MIN(body_left,tmp_read.size()),rec);
+ if (rec>0) {
+ ByteArray ret;
+ ret.resize(rec);
+ ByteArray::Write w = ret.write();
+ copymem(w.ptr(),r.ptr(),rec);
+ body_left-=rec;
+ if (body_left==0) {
+ status=STATUS_CONNECTED;
+ }
+ return ret;
+ }
+
+ }
+
+
+ if (err!=OK) {
+ close();
+ if (err==ERR_FILE_EOF) {
+
+ status=STATUS_DISCONNECTED; //server disconnected
+ } else {
+
+ status=STATUS_CONNECTION_ERROR;
+ }
+ } else if (body_left==0 && !chunked) {
+
+ status=STATUS_CONNECTED;
+ }
+
+ return ByteArray();
+}
+
+HTTPClient::Status HTTPClient::get_status() const {
+
+
+ return status;
+}
+
+void HTTPClient::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("connect:Error","host","port"),&HTTPClient::connect);
+ ObjectTypeDB::bind_method(_MD("set_connection","connection:StreamPeer"),&HTTPClient::set_connection);
+ ObjectTypeDB::bind_method(_MD("request","method","url","headers","body"),&HTTPClient::request,DEFVAL(String()));
+ ObjectTypeDB::bind_method(_MD("send_body_text","body"),&HTTPClient::send_body_text);
+ ObjectTypeDB::bind_method(_MD("send_body_data","body"),&HTTPClient::send_body_data);
+ ObjectTypeDB::bind_method(_MD("close"),&HTTPClient::close);
+
+ ObjectTypeDB::bind_method(_MD("has_response"),&HTTPClient::has_response);
+ ObjectTypeDB::bind_method(_MD("is_response_chunked"),&HTTPClient::is_response_chunked);
+ ObjectTypeDB::bind_method(_MD("get_response_code"),&HTTPClient::get_response_code);
+ ObjectTypeDB::bind_method(_MD("get_response_headers"),&HTTPClient::_get_response_headers);
+ ObjectTypeDB::bind_method(_MD("get_response_headers_as_dictionary"),&HTTPClient::_get_response_headers_as_dictionary);
+ ObjectTypeDB::bind_method(_MD("get_response_body_length"),&HTTPClient::get_response_body_length);
+ ObjectTypeDB::bind_method(_MD("read_response_body_chunk"),&HTTPClient::read_response_body_chunk);
+
+ ObjectTypeDB::bind_method(_MD("get_status"),&HTTPClient::get_status);
+ ObjectTypeDB::bind_method(_MD("poll:Error"),&HTTPClient::poll);
+
+ BIND_CONSTANT( METHOD_GET );
+ BIND_CONSTANT( METHOD_HEAD );
+ BIND_CONSTANT( METHOD_POST );
+ BIND_CONSTANT( METHOD_PUT );
+ BIND_CONSTANT( METHOD_DELETE );
+ BIND_CONSTANT( METHOD_OPTIONS );
+ BIND_CONSTANT( METHOD_TRACE );
+ BIND_CONSTANT( METHOD_CONNECT );
+ BIND_CONSTANT( METHOD_MAX );
+
+ BIND_CONSTANT( STATUS_DISCONNECTED );
+ BIND_CONSTANT( STATUS_RESOLVING ); //resolving hostname (if passed a hostname)
+ BIND_CONSTANT( STATUS_CANT_RESOLVE );
+ BIND_CONSTANT( STATUS_CONNECTING ); //connecting to ip
+ BIND_CONSTANT( STATUS_CANT_CONNECT );
+ BIND_CONSTANT( STATUS_CONNECTED ); //connected ); requests only accepted here
+ BIND_CONSTANT( STATUS_REQUESTING ); // request in progress
+ BIND_CONSTANT( STATUS_BODY ); // request resulted in body ); which must be read
+ BIND_CONSTANT( STATUS_CONNECTION_ERROR );
+
+
+ BIND_CONSTANT( RESPONSE_CONTINUE );
+ BIND_CONSTANT( RESPONSE_SWITCHING_PROTOCOLS );
+ BIND_CONSTANT( RESPONSE_PROCESSING );
+
+ // 2xx successful
+ BIND_CONSTANT( RESPONSE_OK );
+ BIND_CONSTANT( RESPONSE_CREATED );
+ BIND_CONSTANT( RESPONSE_ACCEPTED );
+ BIND_CONSTANT( RESPONSE_NON_AUTHORITATIVE_INFORMATION );
+ BIND_CONSTANT( RESPONSE_NO_CONTENT );
+ BIND_CONSTANT( RESPONSE_RESET_CONTENT );
+ BIND_CONSTANT( RESPONSE_PARTIAL_CONTENT );
+ BIND_CONSTANT( RESPONSE_MULTI_STATUS );
+ BIND_CONSTANT( RESPONSE_IM_USED );
+
+ // 3xx redirection
+ BIND_CONSTANT( RESPONSE_MULTIPLE_CHOICES );
+ BIND_CONSTANT( RESPONSE_MOVED_PERMANENTLY );
+ BIND_CONSTANT( RESPONSE_FOUND );
+ BIND_CONSTANT( RESPONSE_SEE_OTHER );
+ BIND_CONSTANT( RESPONSE_NOT_MODIFIED );
+ BIND_CONSTANT( RESPONSE_USE_PROXY );
+ BIND_CONSTANT( RESPONSE_TEMPORARY_REDIRECT );
+
+ // 4xx client error
+ BIND_CONSTANT( RESPONSE_BAD_REQUEST );
+ BIND_CONSTANT( RESPONSE_UNAUTHORIZED );
+ BIND_CONSTANT( RESPONSE_PAYMENT_REQUIRED );
+ BIND_CONSTANT( RESPONSE_FORBIDDEN );
+ BIND_CONSTANT( RESPONSE_NOT_FOUND );
+ BIND_CONSTANT( RESPONSE_METHOD_NOT_ALLOWED );
+ BIND_CONSTANT( RESPONSE_NOT_ACCEPTABLE );
+ BIND_CONSTANT( RESPONSE_PROXY_AUTHENTICATION_REQUIRED );
+ BIND_CONSTANT( RESPONSE_REQUEST_TIMEOUT );
+ BIND_CONSTANT( RESPONSE_CONFLICT );
+ BIND_CONSTANT( RESPONSE_GONE );
+ BIND_CONSTANT( RESPONSE_LENGTH_REQUIRED );
+ BIND_CONSTANT( RESPONSE_PRECONDITION_FAILED );
+ BIND_CONSTANT( RESPONSE_REQUEST_ENTITY_TOO_LARGE );
+ BIND_CONSTANT( RESPONSE_REQUEST_URI_TOO_LONG );
+ BIND_CONSTANT( RESPONSE_UNSUPPORTED_MEDIA_TYPE );
+ BIND_CONSTANT( RESPONSE_REQUESTED_RANGE_NOT_SATISFIABLE );
+ BIND_CONSTANT( RESPONSE_EXPECTATION_FAILED );
+ BIND_CONSTANT( RESPONSE_UNPROCESSABLE_ENTITY );
+ BIND_CONSTANT( RESPONSE_LOCKED );
+ BIND_CONSTANT( RESPONSE_FAILED_DEPENDENCY );
+ BIND_CONSTANT( RESPONSE_UPGRADE_REQUIRED );
+
+ // 5xx server error
+ BIND_CONSTANT( RESPONSE_INTERNAL_SERVER_ERROR );
+ BIND_CONSTANT( RESPONSE_NOT_IMPLEMENTED );
+ BIND_CONSTANT( RESPONSE_BAD_GATEWAY );
+ BIND_CONSTANT( RESPONSE_SERVICE_UNAVAILABLE );
+ BIND_CONSTANT( RESPONSE_GATEWAY_TIMEOUT );
+ BIND_CONSTANT( RESPONSE_HTTP_VERSION_NOT_SUPPORTED );
+ BIND_CONSTANT( RESPONSE_INSUFFICIENT_STORAGE );
+ BIND_CONSTANT( RESPONSE_NOT_EXTENDED );
+
+}
+
+HTTPClient::HTTPClient(){
+
+ tcp_connection = StreamPeerTCP::create();
+ resolving = IP::RESOLVER_INVALID_ID;
+ status=STATUS_DISCONNECTED;
+ conn_port=80;
+ body_size=0;
+ chunked=false;
+ body_left=0;
+ chunk_left=0;
+ response_num=0;
+
+ tmp_read.resize(4096);
+}
+
+HTTPClient::~HTTPClient(){
+
+
+}
+
+
diff --git a/core/io/http_client.h b/core/io/http_client.h
new file mode 100644
index 0000000000..2f22ba1fde
--- /dev/null
+++ b/core/io/http_client.h
@@ -0,0 +1,188 @@
+/*************************************************************************/
+/* http_client.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef HTTP_CLIENT_H
+#define HTTP_CLIENT_H
+
+#include "io/stream_peer.h"
+#include "io/stream_peer_tcp.h"
+#include "io/ip.h"
+#include "reference.h"
+
+
+class HTTPClient : public Reference {
+
+ OBJ_TYPE(HTTPClient,Reference);
+public:
+
+ enum RespondeCode {
+
+ // 1xx informational
+ RESPONSE_CONTINUE = 100,
+ RESPONSE_SWITCHING_PROTOCOLS = 101,
+ RESPONSE_PROCESSING = 102,
+
+ // 2xx successful
+ RESPONSE_OK = 200,
+ RESPONSE_CREATED = 201,
+ RESPONSE_ACCEPTED = 202,
+ RESPONSE_NON_AUTHORITATIVE_INFORMATION = 203,
+ RESPONSE_NO_CONTENT = 204,
+ RESPONSE_RESET_CONTENT = 205,
+ RESPONSE_PARTIAL_CONTENT = 206,
+ RESPONSE_MULTI_STATUS = 207,
+ RESPONSE_IM_USED = 226,
+
+ // 3xx redirection
+ RESPONSE_MULTIPLE_CHOICES = 300,
+ RESPONSE_MOVED_PERMANENTLY = 301,
+ RESPONSE_FOUND = 302,
+ RESPONSE_SEE_OTHER = 303,
+ RESPONSE_NOT_MODIFIED = 304,
+ RESPONSE_USE_PROXY = 305,
+ RESPONSE_TEMPORARY_REDIRECT = 307,
+
+ // 4xx client error
+ RESPONSE_BAD_REQUEST = 400,
+ RESPONSE_UNAUTHORIZED = 401,
+ RESPONSE_PAYMENT_REQUIRED = 402,
+ RESPONSE_FORBIDDEN = 403,
+ RESPONSE_NOT_FOUND = 404,
+ RESPONSE_METHOD_NOT_ALLOWED = 405,
+ RESPONSE_NOT_ACCEPTABLE = 406,
+ RESPONSE_PROXY_AUTHENTICATION_REQUIRED = 407,
+ RESPONSE_REQUEST_TIMEOUT = 408,
+ RESPONSE_CONFLICT = 409,
+ RESPONSE_GONE = 410,
+ RESPONSE_LENGTH_REQUIRED = 411,
+ RESPONSE_PRECONDITION_FAILED = 412,
+ RESPONSE_REQUEST_ENTITY_TOO_LARGE = 413,
+ RESPONSE_REQUEST_URI_TOO_LONG = 414,
+ RESPONSE_UNSUPPORTED_MEDIA_TYPE = 415,
+ RESPONSE_REQUESTED_RANGE_NOT_SATISFIABLE = 416,
+ RESPONSE_EXPECTATION_FAILED = 417,
+ RESPONSE_UNPROCESSABLE_ENTITY = 422,
+ RESPONSE_LOCKED = 423,
+ RESPONSE_FAILED_DEPENDENCY = 424,
+ RESPONSE_UPGRADE_REQUIRED = 426,
+
+ // 5xx server error
+ RESPONSE_INTERNAL_SERVER_ERROR = 500,
+ RESPONSE_NOT_IMPLEMENTED = 501,
+ RESPONSE_BAD_GATEWAY = 502,
+ RESPONSE_SERVICE_UNAVAILABLE = 503,
+ RESPONSE_GATEWAY_TIMEOUT = 504,
+ RESPONSE_HTTP_VERSION_NOT_SUPPORTED = 505,
+ RESPONSE_INSUFFICIENT_STORAGE = 507,
+ RESPONSE_NOT_EXTENDED = 510,
+
+ };
+
+ enum Method {
+
+ METHOD_GET,
+ METHOD_HEAD,
+ METHOD_POST,
+ METHOD_PUT,
+ METHOD_DELETE,
+ METHOD_OPTIONS,
+ METHOD_TRACE,
+ METHOD_CONNECT,
+ METHOD_MAX
+ };
+
+ enum Status {
+ STATUS_DISCONNECTED,
+ STATUS_RESOLVING, //resolving hostname (if passed a hostname)
+ STATUS_CANT_RESOLVE,
+ STATUS_CONNECTING, //connecting to ip
+ STATUS_CANT_CONNECT,
+ STATUS_CONNECTED, //connected, requests only accepted here
+ STATUS_REQUESTING, // request in progress
+ STATUS_BODY, // request resulted in body, which must be read
+ STATUS_CONNECTION_ERROR,
+ };
+
+private:
+
+ Status status;
+ IP::ResolverID resolving;
+ int conn_port;
+ String conn_host;
+
+ Vector<uint8_t> response_str;
+
+ bool chunked;
+ Vector<uint8_t> chunk;
+ int chunk_left;
+ int body_size;
+ int body_left;
+
+ Ref<StreamPeerTCP> tcp_connection;
+ Ref<StreamPeer> connection;
+
+ int response_num;
+ Vector<String> response_headers;
+
+ static void _bind_methods();
+ StringArray _get_response_headers();
+ Dictionary _get_response_headers_as_dictionary();
+ ByteArray tmp_read;
+public:
+
+
+ Error connect_url(const String& p_url); //connects to a full url and perform request
+ Error connect(const String &p_host,int p_port);
+
+ void set_connection(const Ref<StreamPeer>& p_connection);
+
+ Error request( Method p_method, const String& p_url, const Vector<String>& p_headers,const String& p_body=String());
+ Error send_body_text(const String& p_body);
+ Error send_body_data(const ByteArray& p_body);
+
+ void close();
+
+ Status get_status() const;
+
+ bool has_response() const;
+ bool is_response_chunked() const;
+ int get_response_code() const;
+ Error get_response_headers(List<String> *r_response);
+ int get_response_body_length() const;
+
+ ByteArray read_response_body_chunk(); // can't get body as partial text because of most encodings UTF8, gzip, etc.
+
+ Error poll();
+
+ HTTPClient();
+ ~HTTPClient();
+};
+
+VARIANT_ENUM_CAST(HTTPClient::Method);
+
+#endif // HTTP_CLIENT_H
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
new file mode 100644
index 0000000000..180df8964b
--- /dev/null
+++ b/core/io/image_loader.cpp
@@ -0,0 +1,112 @@
+/*************************************************************************/
+/* image_loader.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. */
+/*************************************************************************/
+#include "image_loader.h"
+
+#include "print_string.h"
+bool ImageFormatLoader::recognize(const String& p_extension) const {
+
+
+ List<String> extensions;
+ get_recognized_extensions(&extensions);
+ for (List<String>::Element *E=extensions.front();E;E=E->next()) {
+
+ if (E->get().nocasecmp_to(p_extension.extension())==0)
+ return true;
+ }
+
+ return false;
+}
+
+Error ImageLoader::load_image(String p_file,Image *p_image, FileAccess *p_custom) {
+
+
+ FileAccess *f=p_custom;
+ if (!f) {
+ Error err;
+ f=FileAccess::open(p_file,FileAccess::READ,&err);
+ if (!f)
+ return err;
+ }
+
+ String extension = p_file.extension();
+
+
+ for (int i=0;i<loader_count;i++) {
+
+ if (!loader[i]->recognize(extension))
+ continue;
+ Error err = loader[i]->load_image(p_image,f);
+ if (err!=ERR_FILE_UNRECOGNIZED) {
+ if (!p_custom)
+ memdelete(f);
+ return err;
+ }
+
+
+ }
+
+ if (!p_custom)
+ memdelete(f);
+
+ return ERR_FILE_UNRECOGNIZED;
+
+}
+
+void ImageLoader::get_recognized_extensions(List<String> *p_extensions) {
+
+ for (int i=0;i<loader_count;i++) {
+
+ loader[i]->get_recognized_extensions(p_extensions);
+
+ }
+}
+
+bool ImageLoader::recognize(const String& p_extension) {
+
+ for (int i=0;i<loader_count;i++) {
+
+ if (loader[i]->recognize(p_extension))
+ return true;
+
+ }
+
+ return false;
+}
+
+ImageFormatLoader *ImageLoader::loader[MAX_LOADERS];
+int ImageLoader::loader_count=0;
+
+void ImageLoader::add_image_format_loader(ImageFormatLoader *p_loader) {
+
+ ERR_FAIL_COND(loader_count >=MAX_LOADERS );
+ loader[loader_count++]=p_loader;
+}
+
+
+
diff --git a/core/io/image_loader.h b/core/io/image_loader.h
new file mode 100644
index 0000000000..665cc0b460
--- /dev/null
+++ b/core/io/image_loader.h
@@ -0,0 +1,91 @@
+/*************************************************************************/
+/* image_loader.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef IMAGE_LOADER_H
+#define IMAGE_LOADER_H
+
+#include "image.h"
+#include "ustring.h"
+#include "os/file_access.h"
+#include "list.h"
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+
+/**
+ * @class ImageScanLineLoader
+ * @author Juan Linietsky <reduzio@gmail.com>
+ *
+
+ */
+class ImageLoader;
+
+
+/**
+ * @class ImageLoader
+ * Base Class and singleton for loading images from disk
+ * Can load images in one go, or by scanline
+ */
+
+
+class ImageFormatLoader {
+friend class ImageLoader;
+protected:
+ virtual Error load_image(Image *p_image,FileAccess *p_fileaccess)=0;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const=0;
+ bool recognize(const String& p_extension) const;
+
+
+public:
+ virtual ~ImageFormatLoader() {}
+};
+
+class ImageLoader {
+
+ enum {
+ MAX_LOADERS=8
+ };
+
+ static ImageFormatLoader *loader[MAX_LOADERS];
+ static int loader_count;
+
+protected:
+
+
+public:
+
+ static Error load_image(String p_file,Image *p_image, FileAccess *p_custom=NULL);
+ static void get_recognized_extensions(List<String> *p_extensions) ;
+ static bool recognize(const String& p_extension) ;
+
+ static void add_image_format_loader(ImageFormatLoader *p_loader);
+
+};
+
+#endif
diff --git a/core/io/ioapi.c b/core/io/ioapi.c
new file mode 100644
index 0000000000..cc49d775b9
--- /dev/null
+++ b/core/io/ioapi.c
@@ -0,0 +1,235 @@
+/* ioapi.h -- IO base function header for compress/uncompress .zip
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+*/
+
+#if (defined(_WIN32))
+ #define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include "ioapi.h"
+
+voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)
+{
+ if (pfilefunc->zfile_func64.zopen64_file != NULL)
+ return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode);
+ else
+ {
+ return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode);
+ }
+}
+
+long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)
+{
+ if (pfilefunc->zfile_func64.zseek64_file != NULL)
+ return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin);
+ else
+ {
+ uLong offsetTruncated = (uLong)offset;
+ if (offsetTruncated != offset)
+ return -1;
+ else
+ return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin);
+ }
+}
+
+ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)
+{
+ if (pfilefunc->zfile_func64.zseek64_file != NULL)
+ return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream);
+ else
+ {
+ uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream);
+ if ((tell_uLong) == ((uLong)-1))
+ return (ZPOS64_T)-1;
+ else
+ return tell_uLong;
+ }
+}
+
+void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32)
+{
+ p_filefunc64_32->zfile_func64.zopen64_file = NULL;
+ p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file;
+ p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
+ p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file;
+ p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file;
+ p_filefunc64_32->zfile_func64.ztell64_file = NULL;
+ p_filefunc64_32->zfile_func64.zseek64_file = NULL;
+ p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file;
+ p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
+ p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque;
+ p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file;
+ p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;
+}
+
+/*
+
+
+static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode));
+static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size));
+static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size));
+static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream));
+static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
+static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream));
+static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream));
+
+static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode)
+{
+ FILE* file = NULL;
+ const char* mode_fopen = NULL;
+ if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
+ mode_fopen = "rb";
+ else
+ if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+ mode_fopen = "r+b";
+ else
+ if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+ mode_fopen = "wb";
+
+ if ((filename!=NULL) && (mode_fopen != NULL))
+ file = fopen(filename, mode_fopen);
+ return file;
+}
+
+static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode)
+{
+ FILE* file = NULL;
+ const char* mode_fopen = NULL;
+ if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
+ mode_fopen = "rb";
+ else
+ if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+ mode_fopen = "r+b";
+ else
+ if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+ mode_fopen = "wb";
+
+ if ((filename!=NULL) && (mode_fopen != NULL))
+ file = fopen64((const char*)filename, mode_fopen);
+ return file;
+}
+
+static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size)
+{
+ uLong ret;
+ ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream);
+ return ret;
+}
+
+static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size)
+{
+ uLong ret;
+ ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream);
+ return ret;
+}
+
+static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream)
+{
+ long ret;
+ ret = ftell((FILE *)stream);
+ return ret;
+}
+
+static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream)
+{
+ ZPOS64_T ret;
+ ret = ftello64((FILE *)stream);
+ return ret;
+}
+
+static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin)
+{
+ int fseek_origin=0;
+ long ret;
+ switch (origin)
+ {
+ case ZLIB_FILEFUNC_SEEK_CUR :
+ fseek_origin = SEEK_CUR;
+ break;
+ case ZLIB_FILEFUNC_SEEK_END :
+ fseek_origin = SEEK_END;
+ break;
+ case ZLIB_FILEFUNC_SEEK_SET :
+ fseek_origin = SEEK_SET;
+ break;
+ default: return -1;
+ }
+ ret = 0;
+ if (fseek((FILE *)stream, offset, fseek_origin) != 0)
+ ret = -1;
+ return ret;
+}
+
+static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)
+{
+ int fseek_origin=0;
+ long ret;
+ switch (origin)
+ {
+ case ZLIB_FILEFUNC_SEEK_CUR :
+ fseek_origin = SEEK_CUR;
+ break;
+ case ZLIB_FILEFUNC_SEEK_END :
+ fseek_origin = SEEK_END;
+ break;
+ case ZLIB_FILEFUNC_SEEK_SET :
+ fseek_origin = SEEK_SET;
+ break;
+ default: return -1;
+ }
+ ret = 0;
+
+ if(fseeko64((FILE *)stream, offset, fseek_origin) != 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream)
+{
+ int ret;
+ ret = fclose((FILE *)stream);
+ return ret;
+}
+
+static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream)
+{
+ int ret;
+ ret = ferror((FILE *)stream);
+ return ret;
+}
+
+void fill_fopen_filefunc (pzlib_filefunc_def)
+ zlib_filefunc_def* pzlib_filefunc_def;
+{
+ pzlib_filefunc_def->zopen_file = fopen_file_func;
+ pzlib_filefunc_def->zread_file = fread_file_func;
+ pzlib_filefunc_def->zwrite_file = fwrite_file_func;
+ pzlib_filefunc_def->ztell_file = ftell_file_func;
+ pzlib_filefunc_def->zseek_file = fseek_file_func;
+ pzlib_filefunc_def->zclose_file = fclose_file_func;
+ pzlib_filefunc_def->zerror_file = ferror_file_func;
+ pzlib_filefunc_def->opaque = NULL;
+}
+
+void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def)
+{
+ pzlib_filefunc_def->zopen64_file = fopen64_file_func;
+ pzlib_filefunc_def->zread_file = fread_file_func;
+ pzlib_filefunc_def->zwrite_file = fwrite_file_func;
+ pzlib_filefunc_def->ztell64_file = ftell64_file_func;
+ pzlib_filefunc_def->zseek64_file = fseek64_file_func;
+ pzlib_filefunc_def->zclose_file = fclose_file_func;
+ pzlib_filefunc_def->zerror_file = ferror_file_func;
+ pzlib_filefunc_def->opaque = NULL;
+}
+*/
diff --git a/core/io/ioapi.h b/core/io/ioapi.h
new file mode 100644
index 0000000000..53d01d65c5
--- /dev/null
+++ b/core/io/ioapi.h
@@ -0,0 +1,199 @@
+/* this file is part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+ Changes
+
+ Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this)
+ Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux.
+ More if/def section may be needed to support other platforms
+ Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows.
+ (but you should use iowin32.c for windows instead)
+
+*/
+
+#ifndef _ZLIBIOAPI64_H
+#define _ZLIBIOAPI64_H
+
+#if (!defined(_WIN32)) && (!defined(WIN32))
+
+ // Linux needs this to support file operation on files larger then 4+GB
+ // But might need better if/def to select just the platforms that needs them.
+
+ #ifndef __USE_FILE_OFFSET64
+ #define __USE_FILE_OFFSET64
+ #endif
+ #ifndef __USE_LARGEFILE64
+ #define __USE_LARGEFILE64
+ #endif
+ #ifndef _LARGEFILE64_SOURCE
+ #define _LARGEFILE64_SOURCE
+ #endif
+ #ifndef _FILE_OFFSET_BIT
+ #define _FILE_OFFSET_BIT 64
+ #endif
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "zlib.h"
+
+#if defined(USE_FILE32API)
+#define fopen64 fopen
+#define ftello64 ftell
+#define fseeko64 fseek
+#else
+#ifdef _MSC_VER
+ #define fopen64 fopen
+ #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC)))
+ #define ftello64 _ftelli64
+ #define fseeko64 _fseeki64
+ #else // old MSC
+ #define ftello64 ftell
+ #define fseeko64 fseek
+ #endif
+#endif
+#endif
+
+/*
+#ifndef ZPOS64_T
+ #ifdef _WIN32
+ #define ZPOS64_T fpos_t
+ #else
+ #include <stdint.h>
+ #define ZPOS64_T uint64_t
+ #endif
+#endif
+*/
+
+#ifdef HAVE_MINIZIP64_CONF_H
+#include "mz64conf.h"
+#endif
+
+/* a type choosen by DEFINE */
+#ifdef HAVE_64BIT_INT_CUSTOM
+typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T;
+#else
+#ifdef HAS_STDINT_H
+#include "stdint.h"
+typedef uint64_t ZPOS64_T;
+#else
+
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef unsigned __int64 ZPOS64_T;
+#else
+typedef unsigned long long int ZPOS64_T;
+#endif
+#endif
+#endif
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define ZLIB_FILEFUNC_SEEK_CUR (1)
+#define ZLIB_FILEFUNC_SEEK_END (2)
+#define ZLIB_FILEFUNC_SEEK_SET (0)
+
+#define ZLIB_FILEFUNC_MODE_READ (1)
+#define ZLIB_FILEFUNC_MODE_WRITE (2)
+#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
+
+#define ZLIB_FILEFUNC_MODE_EXISTING (4)
+#define ZLIB_FILEFUNC_MODE_CREATE (8)
+
+
+#ifndef ZCALLBACK
+ #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
+ #define ZCALLBACK CALLBACK
+ #else
+ #define ZCALLBACK
+ #endif
+#endif
+
+
+
+
+typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode));
+typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size));
+typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
+typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream));
+typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
+
+typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream));
+typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin));
+
+
+/* here is the "old" 32 bits structure structure */
+typedef struct zlib_filefunc_def_s
+{
+ open_file_func zopen_file;
+ read_file_func zread_file;
+ write_file_func zwrite_file;
+ tell_file_func ztell_file;
+ seek_file_func zseek_file;
+ close_file_func zclose_file;
+ testerror_file_func zerror_file;
+ voidpf opaque;
+} zlib_filefunc_def;
+
+typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream));
+typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
+typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode));
+
+typedef struct zlib_filefunc64_def_s
+{
+ open64_file_func zopen64_file;
+ read_file_func zread_file;
+ write_file_func zwrite_file;
+ tell64_file_func ztell64_file;
+ seek64_file_func zseek64_file;
+ close_file_func zclose_file;
+ testerror_file_func zerror_file;
+ voidpf opaque;
+} zlib_filefunc64_def;
+
+void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def));
+void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
+
+/* now internal definition, only for zip.c and unzip.h */
+typedef struct zlib_filefunc64_32_def_s
+{
+ zlib_filefunc64_def zfile_func64;
+ open_file_func zopen32_file;
+ tell_file_func ztell32_file;
+ seek_file_func zseek32_file;
+} zlib_filefunc64_32_def;
+
+
+#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
+#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
+//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))
+//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode))
+#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream))
+#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream))
+
+voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode));
+long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin));
+ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream));
+
+void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32);
+
+#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode)))
+#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream)))
+#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/core/io/ip.cpp b/core/io/ip.cpp
new file mode 100644
index 0000000000..503a009444
--- /dev/null
+++ b/core/io/ip.cpp
@@ -0,0 +1,270 @@
+/*************************************************************************/
+/* ip.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. */
+/*************************************************************************/
+#include "ip.h"
+#include "os/thread.h"
+#include "os/semaphore.h"
+#include "hash_map.h"
+
+
+
+/************* RESOLVER ******************/
+
+
+struct _IP_ResolverPrivate {
+
+ struct QueueItem {
+
+ volatile IP::ResolverStatus status;
+ IP_Address response;
+ String hostname;
+
+ void clear() {
+ status = IP::RESOLVER_STATUS_NONE;
+ response = IP_Address();
+ hostname="";
+ };
+
+ QueueItem() {
+ clear();
+ };
+ };
+
+ QueueItem queue[IP::RESOLVER_MAX_QUERIES];
+
+ IP::ResolverID find_empty_id() const {
+
+ for(int i=0;i<IP::RESOLVER_MAX_QUERIES;i++) {
+ if (queue[i].status==IP::RESOLVER_STATUS_NONE)
+ return i;
+ }
+ return IP::RESOLVER_INVALID_ID;
+ }
+
+ Semaphore *sem;
+
+ Thread* thread;
+ //Semaphore* semaphore;
+ bool thread_abort;
+
+ void resolve_queues() {
+
+ for(int i=0;i<IP::RESOLVER_MAX_QUERIES;i++) {
+
+ if (queue[i].status!=IP::RESOLVER_STATUS_WAITING)
+ continue;
+ queue[i].response=IP::get_singleton()->resolve_hostname(queue[i].hostname);
+
+ if (queue[i].response.host==0)
+ queue[i].status=IP::RESOLVER_STATUS_ERROR;
+ else
+ queue[i].status=IP::RESOLVER_STATUS_DONE;
+
+ }
+ }
+
+
+ static void _thread_function(void *self) {
+
+ _IP_ResolverPrivate *ipr=(_IP_ResolverPrivate*)self;
+
+ while(!ipr->thread_abort) {
+
+ ipr->sem->wait();
+ GLOBAL_LOCK_FUNCTION;
+ ipr->resolve_queues();
+
+ }
+
+ }
+
+ HashMap<String, IP_Address> cache;
+
+};
+
+
+
+IP_Address IP::resolve_hostname(const String& p_hostname) {
+
+ GLOBAL_LOCK_FUNCTION
+
+ if (resolver->cache.has(p_hostname))
+ return resolver->cache[p_hostname];
+
+ IP_Address res = _resolve_hostname(p_hostname);
+ resolver->cache[p_hostname]=res;
+ return res;
+
+}
+IP::ResolverID IP::resolve_hostname_queue_item(const String& p_hostname) {
+
+ GLOBAL_LOCK_FUNCTION
+
+ ResolverID id = resolver->find_empty_id();
+
+ if (id==RESOLVER_INVALID_ID) {
+ WARN_PRINT("Out of resolver queries");
+ return id;
+ }
+
+ resolver->queue[id].hostname=p_hostname;
+ if (resolver->cache.has(p_hostname)) {
+ resolver->queue[id].response=resolver->cache[p_hostname];
+ resolver->queue[id].status=IP::RESOLVER_STATUS_DONE;
+ } else {
+ resolver->queue[id].response=IP_Address();
+ resolver->queue[id].status=IP::RESOLVER_STATUS_WAITING;
+ if (resolver->thread)
+ resolver->sem->post();
+ else
+ resolver->resolve_queues();
+ }
+
+
+
+
+
+ return id;
+}
+
+IP::ResolverStatus IP::get_resolve_item_status(ResolverID p_id) const {
+
+ ERR_FAIL_INDEX_V(p_id,IP::RESOLVER_MAX_QUERIES,IP::RESOLVER_STATUS_NONE);
+
+ GLOBAL_LOCK_FUNCTION;
+ ERR_FAIL_COND_V(resolver->queue[p_id].status==IP::RESOLVER_STATUS_NONE,IP::RESOLVER_STATUS_NONE);
+
+ return resolver->queue[p_id].status;
+
+}
+IP_Address IP::get_resolve_item_address(ResolverID p_id) const {
+
+ ERR_FAIL_INDEX_V(p_id,IP::RESOLVER_MAX_QUERIES,IP_Address());
+
+ GLOBAL_LOCK_FUNCTION;
+
+ if (resolver->queue[p_id].status!=IP::RESOLVER_STATUS_DONE) {
+ ERR_EXPLAIN("Resolve of '"+resolver->queue[p_id].hostname+"'' didn't complete yet.");
+ ERR_FAIL_COND_V(resolver->queue[p_id].status!=IP::RESOLVER_STATUS_DONE,IP_Address());
+ }
+
+
+ return resolver->queue[p_id].response;
+
+}
+void IP::erase_resolve_item(ResolverID p_id) {
+
+ ERR_FAIL_INDEX(p_id,IP::RESOLVER_MAX_QUERIES);
+
+ GLOBAL_LOCK_FUNCTION;
+
+ resolver->queue[p_id].status=IP::RESOLVER_STATUS_DONE;
+
+}
+
+
+void IP::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("resolve_hostname","host"),&IP::resolve_hostname);
+ ObjectTypeDB::bind_method(_MD("resolve_hostname_queue_item","host"),&IP::resolve_hostname_queue_item);
+ ObjectTypeDB::bind_method(_MD("get_resolve_item_status","id"),&IP::get_resolve_item_status);
+ ObjectTypeDB::bind_method(_MD("get_resolve_item_address","id"),&IP::get_resolve_item_address);
+ ObjectTypeDB::bind_method(_MD("erase_resolve_item","id"),&IP::erase_resolve_item);
+
+ BIND_CONSTANT( RESOLVER_STATUS_NONE );
+ BIND_CONSTANT( RESOLVER_STATUS_WAITING );
+ BIND_CONSTANT( RESOLVER_STATUS_DONE );
+ BIND_CONSTANT( RESOLVER_STATUS_ERROR );
+
+ BIND_CONSTANT( RESOLVER_MAX_QUERIES );
+ BIND_CONSTANT( RESOLVER_INVALID_ID );
+
+}
+
+
+IP*IP::singleton=NULL;
+
+IP* IP::get_singleton() {
+
+ return singleton;
+}
+
+
+IP* (*IP::_create)()=NULL;
+
+IP* IP::create() {
+
+ ERR_FAIL_COND_V(singleton,NULL);
+ ERR_FAIL_COND_V(!_create,NULL);
+ return _create();
+}
+
+IP::IP() {
+
+ singleton=this;
+ resolver = memnew( _IP_ResolverPrivate );
+ resolver->sem=NULL;
+
+#ifndef NO_THREADS
+
+ //resolver->sem = Semaphore::create();
+
+ resolver->sem=NULL;
+ if (resolver->sem) {
+ resolver->thread_abort=false;
+
+ resolver->thread = Thread::create( _IP_ResolverPrivate::_thread_function,resolver );
+
+ if (!resolver->thread)
+ memdelete(resolver->sem); //wtf
+ } else {
+ resolver->thread=NULL;
+ }
+#else
+ resolver->sem = NULL;
+ resolver->thread=NULL;
+#endif
+
+
+}
+
+IP::~IP() {
+
+#ifndef NO_THREADS
+ if (resolver->thread) {
+ resolver->thread_abort=true;
+ resolver->sem->post();
+ Thread::wait_to_finish(resolver->thread);
+ memdelete( resolver->thread );
+ memdelete( resolver->sem);
+ }
+ memdelete(resolver);
+
+#endif
+
+}
diff --git a/core/io/ip.h b/core/io/ip.h
new file mode 100644
index 0000000000..f1ef5fe794
--- /dev/null
+++ b/core/io/ip.h
@@ -0,0 +1,91 @@
+/*************************************************************************/
+/* ip.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef IP_H
+#define IP_H
+
+
+#include "os/os.h"
+#include "io/ip_address.h"
+
+struct _IP_ResolverPrivate;
+
+class IP : public Object {
+ OBJ_TYPE( IP, Object );
+ OBJ_CATEGORY("Networking");
+public:
+
+ enum ResolverStatus {
+
+ RESOLVER_STATUS_NONE,
+ RESOLVER_STATUS_WAITING,
+ RESOLVER_STATUS_DONE,
+ RESOLVER_STATUS_ERROR,
+ };
+
+ enum {
+ RESOLVER_MAX_QUERIES = 32,
+ RESOLVER_INVALID_ID=-1
+ };
+
+
+ typedef int ResolverID;
+
+
+private:
+
+ _IP_ResolverPrivate *resolver;
+protected:
+
+ static IP*singleton;
+ static void _bind_methods();
+
+ virtual IP_Address _resolve_hostname(const String& p_hostname)=0;
+
+ static IP* (*_create)();
+public:
+
+
+ IP_Address resolve_hostname(const String& p_hostname);
+ // async resolver hostname
+ ResolverID resolve_hostname_queue_item(const String& p_hostname);
+ ResolverStatus get_resolve_item_status(ResolverID p_id) const;
+ IP_Address get_resolve_item_address(ResolverID p_id) const;
+ void erase_resolve_item(ResolverID p_id);
+
+ static IP* get_singleton();
+
+ static IP* create();
+
+ IP();
+ ~IP();
+
+
+};
+
+#endif // IP_H
diff --git a/core/io/ip_address.cpp b/core/io/ip_address.cpp
new file mode 100644
index 0000000000..a1400adbb6
--- /dev/null
+++ b/core/io/ip_address.cpp
@@ -0,0 +1,60 @@
+/*************************************************************************/
+/* ip_address.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. */
+/*************************************************************************/
+#include "ip_address.h"
+/*
+IP_Address::operator Variant() const {
+
+ return operator String();
+}*/
+IP_Address::operator String() const {
+
+ return itos(field[0])+"."+itos(field[1])+"."+itos(field[2])+"."+itos(field[3]);
+}
+
+IP_Address::IP_Address(const String& p_string) {
+
+ host=0;
+ int slices = p_string.get_slice_count(".");
+ if (slices!=4) {
+ ERR_EXPLAIN("Invalid IP Address String: "+p_string);
+ ERR_FAIL();
+ }
+ for(int i=0;i<4;i++) {
+
+ field[i]=p_string.get_slice(".",i).to_int();
+ }
+}
+
+IP_Address::IP_Address(uint8_t p_a,uint8_t p_b,uint8_t p_c,uint8_t p_d) {
+
+ field[0]=p_a;
+ field[1]=p_b;
+ field[2]=p_c;
+ field[3]=p_d;
+}
diff --git a/core/io/ip_address.h b/core/io/ip_address.h
new file mode 100644
index 0000000000..cd39aa6c81
--- /dev/null
+++ b/core/io/ip_address.h
@@ -0,0 +1,50 @@
+/*************************************************************************/
+/* ip_address.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef IP_ADDRESS_H
+#define IP_ADDRESS_H
+
+#include "ustring.h"
+
+struct IP_Address {
+
+ union {
+ uint8_t field[4];
+ uint32_t host;
+ };
+
+ //operator Variant() const;
+ operator String() const;
+ IP_Address(const String& p_string);
+ IP_Address(uint8_t p_a,uint8_t p_b,uint8_t p_c,uint8_t p_d);
+ IP_Address() { host=0; }
+};
+
+
+
+#endif // IP_ADDRESS_H
diff --git a/core/io/json.cpp b/core/io/json.cpp
new file mode 100644
index 0000000000..a83d7e4d6e
--- /dev/null
+++ b/core/io/json.cpp
@@ -0,0 +1,477 @@
+/*************************************************************************/
+/* json.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. */
+/*************************************************************************/
+#include "json.h"
+#include "print_string.h"
+
+const char * JSON::tk_name[TK_MAX] = {
+ "'{'",
+ "'}'",
+ "'['",
+ "']'",
+ "identifier",
+ "string",
+ "number",
+ "':'",
+ "','",
+ "EOF",
+};
+
+
+
+String JSON::_print_var(const Variant& p_var) {
+
+ switch(p_var.get_type()) {
+
+ case Variant::NIL: return "null";
+ case Variant::BOOL: return p_var.operator bool() ? "true": "false";
+ case Variant::INT: return itos(p_var);
+ case Variant::REAL: return rtos(p_var);
+ case Variant::INT_ARRAY:
+ case Variant::REAL_ARRAY:
+ case Variant::STRING_ARRAY:
+ case Variant::ARRAY: {
+
+ String s = "[";
+ Array a = p_var;
+ for(int i=0;i<a.size();i++) {
+ if (i>0)
+ s+=", ";
+ s+=_print_var(a[i]);
+ }
+ s+="]";
+ return s;
+ };
+ case Variant::DICTIONARY: {
+
+ String s = "{";
+ Dictionary d = p_var;
+ List<Variant> keys;
+ d.get_key_list(&keys);
+
+ for (List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+ if (E!=keys.front())
+ s+=", ";
+ s+=_print_var(String(E->get()));
+ s+=":";
+ s+=_print_var(d[E->get()]);
+ }
+
+ s+="}";
+ return s;
+ };
+ default: return "\""+String(p_var).c_escape()+"\"";
+
+ }
+
+}
+
+String JSON::print(const Dictionary& p_dict) {
+
+ return _print_var(p_dict);
+}
+
+
+Error JSON::_get_token(const CharType *p_str, int &idx, int p_len, Token& r_token,int &line,String &r_err_str) {
+
+ while (true) {
+ switch(p_str[idx]) {
+
+ case '\n': {
+
+ line++;
+ idx++;
+ break;
+ };
+ case 0: {
+ r_token.type=TK_EOF;
+ return OK;
+ } break;
+ case '{': {
+
+ r_token.type=TK_CURLY_BRACKET_OPEN;
+ idx++;
+ return OK;
+ };
+ case '}': {
+
+ r_token.type=TK_CURLY_BRACKET_CLOSE;
+ idx++;
+ return OK;
+ };
+ case '[': {
+
+ r_token.type=TK_BRACKET_OPEN;
+ idx++;
+ return OK;
+ };
+ case ']': {
+
+ r_token.type=TK_BRACKET_CLOSE;
+ idx++;
+ return OK;
+ };
+ case ':': {
+
+ r_token.type=TK_COLON;
+ idx++;
+ return OK;
+ };
+ case ',': {
+
+ r_token.type=TK_COMMA;
+ idx++;
+ return OK;
+ };
+ case '"': {
+
+ idx++;
+ String str;
+ while(true) {
+ if (p_str[idx]==0) {
+ r_err_str="Unterminated String";
+ return ERR_PARSE_ERROR;
+ } else if (p_str[idx]=='"') {
+ idx++;
+ break;
+ } else if (p_str[idx]=='\\') {
+ //escaped characters...
+ idx++;
+ CharType next = p_str[idx];
+ if (next==0) {
+ r_err_str="Unterminated String";
+ return ERR_PARSE_ERROR;
+ }
+ CharType res=0;
+
+ switch(next) {
+
+ case 'b': res=8; break;
+ case 't': res=9; break;
+ case 'n': res=10; break;
+ case 'f': res=12; break;
+ case 'r': res=13; break;
+ case '\"': res='\"'; break;
+ case '\\': res='\\'; break;
+ case '/': res='/'; break; //wtf
+ case 'u': {
+ //hexnumbarh - oct is deprecated
+
+
+ for(int j=0;j<4;j++) {
+ CharType c = p_str[idx+j+1];
+ if (c==0) {
+ r_err_str="Unterminated String";
+ return ERR_PARSE_ERROR;
+ }
+ if (!((c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F'))) {
+
+ r_err_str="Malformed hex constant in string";
+ return ERR_PARSE_ERROR;
+ }
+ CharType v;
+ if (c>='0' && c<='9') {
+ v=c-'0';
+ } else if (c>='a' && c<='f') {
+ v=c-'a';
+ v+=10;
+ } else if (c>='A' && c<='F') {
+ v=c-'A';
+ v+=10;
+ } else {
+ ERR_PRINT("BUG");
+ v=0;
+ }
+
+ res<<=4;
+ res|=v;
+
+
+ }
+ idx+=4; //will add at the end anyway
+
+
+ } break;
+ default: {
+
+ r_err_str="Invalid escape sequence";
+ return ERR_PARSE_ERROR;
+ } break;
+ }
+
+ str+=res;
+
+ } else {
+ if (p_str[idx]=='\n')
+ line++;
+ str+=p_str[idx];
+ }
+ idx++;
+ }
+
+ r_token.type=TK_STRING;
+ r_token.value=str;
+ return OK;
+
+ } break;
+ default: {
+
+ if (p_str[idx]<=32) {
+ idx++;
+ break;
+ }
+
+ if (p_str[idx]=='-' || (p_str[idx]>='0' && p_str[idx]<='9')) {
+ //a number
+ const CharType *rptr;
+ double number = String::to_double(&p_str[idx],-1,&rptr);
+ idx+=(rptr - &p_str[idx]);
+ r_token.type=TK_NUMBER;
+ r_token.value=number;
+ return OK;
+
+ } else if ((p_str[idx]>='A' && p_str[idx]<='Z') || (p_str[idx]>='a' && p_str[idx]<='z')) {
+
+ String id;
+
+ while((p_str[idx]>='A' && p_str[idx]<='Z') || (p_str[idx]>='a' && p_str[idx]<='z')) {
+
+ id+=p_str[idx];
+ idx++;
+ }
+
+ r_token.type=TK_IDENTIFIER;
+ r_token.value=id;
+ return OK;
+ } else {
+ r_err_str="Unexpected character.";
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ }
+ }
+
+ return ERR_PARSE_ERROR;
+}
+
+
+
+Error JSON::_parse_value(Variant &value,Token& token,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str) {
+
+
+ if (token.type==TK_CURLY_BRACKET_OPEN) {
+
+ Dictionary d;
+ Error err = _parse_object(d,p_str,index,p_len,line,r_err_str);
+ if (err)
+ return err;
+ value=d;
+ return OK;
+ } else if (token.type==TK_BRACKET_OPEN) {
+
+ Array a;
+ Error err = _parse_array(a,p_str,index,p_len,line,r_err_str);
+ if (err)
+ return err;
+ value=a;
+ return OK;
+
+ } else if (token.type==TK_IDENTIFIER) {
+
+ String id = token.value;
+ if (id=="true")
+ value=true;
+ else if (id=="false")
+ value=false;
+ else if (id=="null")
+ value=Variant();
+ else {
+ r_err_str="Expected 'true','false' or 'null', got '"+id+"'.";
+ return ERR_PARSE_ERROR;
+ }
+ return OK;
+
+ } else if (token.type==TK_NUMBER) {
+
+ value=token.value;
+ return OK;
+ } else if (token.type==TK_STRING) {
+
+ value=token.value;
+ return OK;
+ } else {
+ r_err_str="Expected value, got "+String(tk_name[token.type])+".";
+ return ERR_PARSE_ERROR;
+ }
+
+ return ERR_PARSE_ERROR;
+}
+
+
+Error JSON::_parse_array(Array &array,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str) {
+
+ Token token;
+ bool need_comma=false;
+
+
+ while(index<p_len) {
+
+ Error err = _get_token(p_str,index,p_len,token,line,r_err_str);
+ if (err!=OK)
+ return err;
+
+ if (token.type==TK_BRACKET_CLOSE) {
+
+ return OK;
+ }
+
+ if (need_comma) {
+
+ if (token.type!=TK_COMMA) {
+
+ r_err_str="Expected ','";
+ return ERR_PARSE_ERROR;
+ } else {
+ need_comma=false;
+ continue;
+ }
+ }
+
+ Variant v;
+ err = _parse_value(v,token,p_str,index,p_len,line,r_err_str);
+ if (err)
+ return err;
+
+ array.push_back(v);
+ need_comma=true;
+
+ }
+
+ return OK;
+
+}
+
+Error JSON::_parse_object(Dictionary &object,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str) {
+
+ bool at_key=true;
+ String key;
+ Token token;
+ bool need_comma=false;
+
+
+ while(index<p_len) {
+
+
+ if (at_key) {
+
+ Error err = _get_token(p_str,index,p_len,token,line,r_err_str);
+ if (err!=OK)
+ return err;
+
+ if (token.type==TK_CURLY_BRACKET_CLOSE) {
+
+ return OK;
+ }
+
+ if (need_comma) {
+
+ if (token.type!=TK_COMMA) {
+
+ r_err_str="Expected '}' or ','";
+ return ERR_PARSE_ERROR;
+ } else {
+ need_comma=false;
+ continue;
+ }
+ }
+
+ if (token.type!=TK_STRING) {
+
+
+ r_err_str="Expected key";
+ return ERR_PARSE_ERROR;
+ }
+
+ key=token.value;
+ err = _get_token(p_str,index,p_len,token,line,r_err_str);
+ if (err!=OK)
+ return err;
+ if (token.type!=TK_COLON) {
+
+ r_err_str="Expected ':'";
+ return ERR_PARSE_ERROR;
+ }
+ at_key=false;
+ } else {
+
+
+ Error err = _get_token(p_str,index,p_len,token,line,r_err_str);
+ if (err!=OK)
+ return err;
+
+ Variant v;
+ err = _parse_value(v,token,p_str,index,p_len,line,r_err_str);
+ if (err)
+ return err;
+ object[key]=v;
+ need_comma=true;
+ at_key=true;
+ }
+ }
+
+ return OK;
+}
+
+
+Error JSON::parse(const String& p_json,Dictionary& r_ret,String &r_err_str,int &r_err_line) {
+
+
+ const CharType *str = p_json.ptr();
+ int idx = 0;
+ int len = p_json.length();
+ Token token;
+ int line=0;
+ String aux_key;
+
+ Error err = _get_token(str,idx,len,token,line,r_err_str);
+ if (err)
+ return err;
+
+ if (token.type!=TK_CURLY_BRACKET_OPEN) {
+
+ r_err_str="Expected '{'";
+ return ERR_PARSE_ERROR;
+ }
+
+ return _parse_object(r_ret,str,idx,len,r_err_line,r_err_str);
+
+}
+
+
diff --git a/core/io/json.h b/core/io/json.h
new file mode 100644
index 0000000000..d113d0e4ef
--- /dev/null
+++ b/core/io/json.h
@@ -0,0 +1,81 @@
+/*************************************************************************/
+/* json.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef JSON_H
+#define JSON_H
+
+
+
+#include "variant.h"
+
+
+class JSON {
+
+ enum TokenType {
+ TK_CURLY_BRACKET_OPEN,
+ TK_CURLY_BRACKET_CLOSE,
+ TK_BRACKET_OPEN,
+ TK_BRACKET_CLOSE,
+ TK_IDENTIFIER,
+ TK_STRING,
+ TK_NUMBER,
+ TK_COLON,
+ TK_COMMA,
+ TK_EOF,
+ TK_MAX
+ };
+
+ enum Expecting {
+
+ EXPECT_OBJECT,
+ EXPECT_OBJECT_KEY,
+ EXPECT_COLON,
+ EXPECT_OBJECT_VALUE,
+ };
+
+ struct Token {
+
+ TokenType type;
+ Variant value;
+ };
+
+ static const char * tk_name[TK_MAX];
+
+ static String _print_var(const Variant& p_var);
+
+ static Error _get_token(const CharType *p_str,int &index, int p_len,Token& r_token,int &line,String &r_err_str);
+ static Error _parse_value(Variant &value,Token& token,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str);
+ static Error _parse_array(Array &array,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str);
+ static Error _parse_object(Dictionary &object,const CharType *p_str,int &index, int p_len,int &line,String &r_err_str);
+
+public:
+ static String print(const Dictionary& p_dict);
+ static Error parse(const String& p_json,Dictionary& r_ret,String &r_err_str,int &r_err_line);
+};
+
+#endif // JSON_H
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp
new file mode 100644
index 0000000000..f5f9d34439
--- /dev/null
+++ b/core/io/marshalls.cpp
@@ -0,0 +1,1195 @@
+/*************************************************************************/
+/* marshalls.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. */
+/*************************************************************************/
+#include "marshalls.h"
+#include "print_string.h"
+#include "os/keyboard.h"
+#include <stdio.h>
+
+Error decode_variant(Variant& r_variant,const uint8_t *p_buffer, int p_len,int *r_len) {
+
+ const uint8_t * buf=p_buffer;
+ int len=p_len;
+
+ ERR_FAIL_COND_V(len<4,ERR_INVALID_DATA);
+
+
+ uint32_t type=decode_uint32(buf);
+
+ ERR_FAIL_COND_V(type>=Variant::VARIANT_MAX,ERR_INVALID_DATA);
+
+ buf+=4;
+ len-=4;
+ if (r_len)
+ *r_len=4;
+
+ switch(type) {
+
+ case Variant::NIL: {
+
+ r_variant=Variant();
+ } break;
+ case Variant::BOOL: {
+
+ ERR_FAIL_COND_V(len<4,ERR_INVALID_DATA);
+ bool val = decode_uint32(buf);
+ r_variant=val;
+ if (r_len)
+ (*r_len)+=4;
+ } break;
+ case Variant::INT: {
+
+ ERR_FAIL_COND_V(len<4,ERR_INVALID_DATA);
+ int val = decode_uint32(buf);
+ r_variant=val;
+ if (r_len)
+ (*r_len)+=4;
+
+ } break;
+ case Variant::REAL: {
+
+ ERR_FAIL_COND_V(len<(int)4,ERR_INVALID_DATA);
+ float val = decode_float(buf);
+ r_variant=val;
+ if (r_len)
+ (*r_len)+=4;
+
+ } break;
+ case Variant::STRING: {
+
+ ERR_FAIL_COND_V(len<4,ERR_INVALID_DATA);
+ uint32_t strlen = decode_uint32(buf);
+ buf+=4;
+ len-=4;
+ ERR_FAIL_COND_V((int)strlen>len,ERR_INVALID_DATA);
+
+ String str;
+ str.parse_utf8((const char*)buf,strlen);
+ r_variant=str;
+
+ if (r_len) {
+ if (strlen%4)
+ (*r_len)+=4-strlen%4;
+ (*r_len)+=4+strlen;
+
+ }
+
+ } break;
+ // math types
+
+ case Variant::VECTOR2: {
+
+ ERR_FAIL_COND_V(len<(int)4*2,ERR_INVALID_DATA);
+ Vector2 val;
+ val.x=decode_float(&buf[0]);
+ val.y=decode_float(&buf[4]);
+ r_variant=val;
+
+ if (r_len)
+ (*r_len)+=4*2;
+
+ } break; // 5
+ case Variant::RECT2: {
+
+ ERR_FAIL_COND_V(len<(int)4*4,ERR_INVALID_DATA);
+ Rect2 val;
+ val.pos.x=decode_float(&buf[0]);
+ val.pos.y=decode_float(&buf[4]);
+ val.size.x=decode_float(&buf[8]);
+ val.size.y=decode_float(&buf[12]);
+ r_variant=val;
+
+ if (r_len)
+ (*r_len)+=4*4;
+
+ } break;
+ case Variant::VECTOR3: {
+
+ ERR_FAIL_COND_V(len<(int)4*3,ERR_INVALID_DATA);
+ Vector3 val;
+ val.x=decode_float(&buf[0]);
+ val.y=decode_float(&buf[4]);
+ val.z=decode_float(&buf[8]);
+ r_variant=val;
+
+ if (r_len)
+ (*r_len)+=4*3;
+
+ } break;
+ case Variant::PLANE: {
+
+ ERR_FAIL_COND_V(len<(int)4*4,ERR_INVALID_DATA);
+ Plane val;
+ val.normal.x=decode_float(&buf[0]);
+ val.normal.y=decode_float(&buf[4]);
+ val.normal.z=decode_float(&buf[8]);
+ val.d=decode_float(&buf[12]);
+ r_variant=val;
+
+ if (r_len)
+ (*r_len)+=4*4;
+
+ } break;
+ case Variant::QUAT: {
+
+ ERR_FAIL_COND_V(len<(int)4*4,ERR_INVALID_DATA);
+ Quat val;
+ val.x=decode_float(&buf[0]);
+ val.y=decode_float(&buf[4]);
+ val.z=decode_float(&buf[8]);
+ val.w=decode_float(&buf[12]);
+ r_variant=val;
+
+ if (r_len)
+ (*r_len)+=4*4;
+
+ } break;
+ case Variant::_AABB: {
+
+ ERR_FAIL_COND_V(len<(int)4*6,ERR_INVALID_DATA);
+ AABB val;
+ val.pos.x=decode_float(&buf[0]);
+ val.pos.y=decode_float(&buf[4]);
+ val.pos.z=decode_float(&buf[8]);
+ val.size.x=decode_float(&buf[12]);
+ val.size.y=decode_float(&buf[16]);
+ val.size.z=decode_float(&buf[20]);
+ r_variant=val;
+
+ if (r_len)
+ (*r_len)+=4*6;
+
+ } break;
+ case Variant::MATRIX3: {
+
+ ERR_FAIL_COND_V(len<(int)4*9,ERR_INVALID_DATA);
+ Matrix3 val;
+ for(int i=0;i<3;i++) {
+ for(int j=0;j<3;j++) {
+
+ val.elements[i][j]=decode_float(&buf[(i*3+j)*4]);
+ }
+ }
+
+ r_variant=val;
+
+ if (r_len)
+ (*r_len)+=4*9;
+
+ } break;
+ case Variant::TRANSFORM: {
+
+ ERR_FAIL_COND_V(len<(int)4*12,ERR_INVALID_DATA);
+ Transform val;
+ for(int i=0;i<3;i++) {
+ for(int j=0;j<3;j++) {
+
+ val.basis.elements[i][j]=decode_float(&buf[(i*3+j)*4]);
+ }
+ }
+ val.origin[0]=decode_float(&buf[36]);
+ val.origin[1]=decode_float(&buf[40]);
+ val.origin[2]=decode_float(&buf[44]);
+
+ r_variant=val;
+
+ if (r_len)
+ (*r_len)+=4*12;
+
+ } break;
+
+ // misc types
+ case Variant::COLOR: {
+
+ ERR_FAIL_COND_V(len<(int)4*4,ERR_INVALID_DATA);
+ Color val;
+ val.r=decode_float(&buf[0]);
+ val.g=decode_float(&buf[4]);
+ val.b=decode_float(&buf[8]);
+ val.a=decode_float(&buf[12]);
+ r_variant=val;
+
+ if (r_len)
+ (*r_len)+=4*4;
+
+ } break;
+ case Variant::IMAGE: {
+
+ ERR_FAIL_COND_V(len<(int)5*4,ERR_INVALID_DATA);
+ Image::Format fmt = (Image::Format)decode_uint32(&buf[0]);
+ ERR_FAIL_INDEX_V( fmt, Image::FORMAT_MAX, ERR_INVALID_DATA);
+ uint32_t mipmaps = decode_uint32(&buf[4]);
+ uint32_t w = decode_uint32(&buf[8]);
+ uint32_t h = decode_uint32(&buf[12]);
+ uint32_t datalen = decode_uint32(&buf[16]);
+
+ Image img;
+ if (datalen>0) {
+ len-=5*4;
+ ERR_FAIL_COND_V( len < datalen, ERR_INVALID_DATA );
+ DVector<uint8_t> data;
+ data.resize(datalen);
+ DVector<uint8_t>::Write wr = data.write();
+ copymem(&wr[0],&buf[20],datalen);
+ wr = DVector<uint8_t>::Write();
+
+
+
+ img=Image(w,h,mipmaps,fmt,data);
+ }
+
+ r_variant=img;
+ if (r_len)
+ (*r_len)+=4*5+datalen;
+
+ } break;
+ case Variant::NODE_PATH: {
+
+ ERR_FAIL_COND_V(len<4,ERR_INVALID_DATA);
+ uint32_t strlen = decode_uint32(buf);
+ buf+=4;
+ len-=4;
+ ERR_FAIL_COND_V((int)strlen>len,ERR_INVALID_DATA);
+
+
+ String str;
+ str.parse_utf8((const char*)buf,strlen);
+
+ r_variant=NodePath(str);
+
+ if (r_len)
+ (*r_len)+=4+strlen;
+
+ } break;
+ /*case Variant::RESOURCE: {
+
+ ERR_EXPLAIN("Can't marshallize resources");
+ ERR_FAIL_V(ERR_INVALID_DATA); //no, i'm sorry, no go
+ } break;*/
+ case Variant::_RID: {
+
+ r_variant = RID();
+ } break;
+ case Variant::OBJECT: {
+
+
+ r_variant = (Object*)NULL;
+ } break;
+ case Variant::INPUT_EVENT: {
+
+ InputEvent ie;
+
+ ie.type=decode_uint32(&buf[0]);
+ ie.device=decode_uint32(&buf[4]);
+ uint32_t len = decode_uint32(&buf[8])-12;
+
+ if (r_len)
+ (*r_len)+=12;
+
+ switch(ie.type) {
+
+ case InputEvent::KEY: {
+
+ uint32_t mods=decode_uint32(&buf[12]);
+ if (mods&KEY_MASK_SHIFT)
+ ie.key.mod.shift=true;
+ if (mods&KEY_MASK_CTRL)
+ ie.key.mod.control=true;
+ if (mods&KEY_MASK_ALT)
+ ie.key.mod.alt=true;
+ if (mods&KEY_MASK_META)
+ ie.key.mod.meta=true;
+ ie.key.scancode=decode_uint32(&buf[16]);
+
+ if (r_len)
+ (*r_len)+=8;
+
+
+ } break;
+ case InputEvent::MOUSE_BUTTON: {
+
+ ie.mouse_button.button_index=decode_uint32(&buf[12]);
+ if (r_len)
+ (*r_len)+=4;
+
+ } break;
+ case InputEvent::JOYSTICK_BUTTON: {
+
+ ie.joy_button.button_index=decode_uint32(&buf[12]);
+ if (r_len)
+ (*r_len)+=4;
+ } break;
+ case InputEvent::SCREEN_TOUCH: {
+
+ ie.screen_touch.index=decode_uint32(&buf[12]);
+ if (r_len)
+ (*r_len)+=4;
+ } break;
+ case InputEvent::JOYSTICK_MOTION: {
+
+ ie.joy_motion.axis=decode_uint32(&buf[12]);
+ if (r_len)
+ (*r_len)+=4;
+ } break;
+ }
+
+ r_variant = ie;
+
+ } break;
+ case Variant::DICTIONARY: {
+
+ ERR_FAIL_COND_V(len<4,ERR_INVALID_DATA);
+ uint32_t count = decode_uint32(buf);
+ bool shared = count&0x80000000;
+ count&=0x7FFFFFFF;
+
+ buf+=4;
+ len-=4;
+
+ if (r_len) {
+ (*r_len)+=4;
+ }
+
+ Dictionary d(shared);
+
+ for(uint32_t i=0;i<count;i++) {
+
+ Variant key,value;
+
+ int used;
+ Error err = decode_variant(key,buf,len,&used);
+ ERR_FAIL_COND_V(err,err);
+
+ buf+=used;
+ len-=used;
+ if (r_len) {
+ (*r_len)+=used;
+ }
+
+ err = decode_variant(value,buf,len,&used);
+ ERR_FAIL_COND_V(err,err);
+
+ buf+=used;
+ len-=used;
+ if (r_len) {
+ (*r_len)+=used;
+ }
+
+ d[key]=value;
+ }
+
+ r_variant=d;
+
+ } break;
+ case Variant::ARRAY: {
+
+ ERR_FAIL_COND_V(len<4,ERR_INVALID_DATA);
+ uint32_t count = decode_uint32(buf);
+ bool shared = count&0x80000000;
+ count&=0x7FFFFFFF;
+
+ buf+=4;
+ len-=4;
+
+ if (r_len) {
+ (*r_len)+=4;
+ }
+
+ Array varr(shared);
+
+ for(uint32_t i=0;i<count;i++) {
+
+ int used=0;
+ Variant v;
+ Error err = decode_variant(v,buf,len,&used);
+ ERR_FAIL_COND_V(err,err);
+ buf+=used;
+ len-=used;
+ varr.push_back(v);
+ if (r_len) {
+ (*r_len)+=used;
+ }
+ }
+
+ r_variant=varr;
+
+
+ } break;
+
+ // arrays
+ case Variant::RAW_ARRAY: {
+
+ ERR_FAIL_COND_V(len<4,ERR_INVALID_DATA);
+ uint32_t count = decode_uint32(buf);
+ buf+=4;
+ len-=4;
+ ERR_FAIL_COND_V((int)count>len,ERR_INVALID_DATA);
+
+
+ DVector<uint8_t> data;
+
+ if (count) {
+ data.resize(count);
+ DVector<uint8_t>::Write w = data.write();
+ for(int i=0;i<count;i++) {
+
+ w[i]=buf[i];
+ }
+
+ w = DVector<uint8_t>::Write();
+ }
+
+ r_variant=data;
+
+ if (r_len) {
+ if (count%4)
+ (*r_len)+=4-count%4;
+ (*r_len)+=4+count;
+ }
+
+
+
+ } break;
+ case Variant::INT_ARRAY: {
+
+ ERR_FAIL_COND_V(len<4,ERR_INVALID_DATA);
+ uint32_t count = decode_uint32(buf);
+ buf+=4;
+ len-=4;
+ ERR_FAIL_COND_V((int)count*4>len,ERR_INVALID_DATA);
+
+ DVector<int> data;
+
+ if (count) {
+ //const int*rbuf=(const int*)buf;
+ data.resize(count);
+ DVector<int>::Write w = data.write();
+ for(int i=0;i<count;i++) {
+
+ w[i]=decode_uint32(&buf[i*4]);
+ }
+
+ w = DVector<int>::Write();
+ }
+ r_variant=Variant(data);
+ if (r_len) {
+ (*r_len)+=4+count*sizeof(int);
+ }
+
+ } break;
+ case Variant::REAL_ARRAY: {
+
+ ERR_FAIL_COND_V(len<4,ERR_INVALID_DATA);
+ uint32_t count = decode_uint32(buf);
+ buf+=4;
+ len-=4;
+ ERR_FAIL_COND_V((int)count*4>len,ERR_INVALID_DATA);
+
+ DVector<float> data;
+
+ if (count) {
+ //const float*rbuf=(const float*)buf;
+ data.resize(count);
+ DVector<float>::Write w = data.write();
+ for(int i=0;i<count;i++) {
+
+ w[i]=decode_float(&buf[i*4]);
+ }
+
+ w = DVector<float>::Write();
+ }
+ r_variant=data;
+
+ if (r_len) {
+ (*r_len)+=4+count*sizeof(float);
+ }
+
+
+ } break;
+ case Variant::STRING_ARRAY: {
+
+ ERR_FAIL_COND_V(len<4,ERR_INVALID_DATA);
+ uint32_t count = decode_uint32(buf);
+ ERR_FAIL_COND_V(count<0,ERR_INVALID_DATA);
+
+ DVector<String> strings;
+ buf+=4;
+ len-=4;
+
+ if (r_len)
+ (*r_len)+=4;
+ //printf("string count: %i\n",count);
+
+ for(int i=0;i<(int)count;i++) {
+
+ ERR_FAIL_COND_V(len<4,ERR_INVALID_DATA);
+ uint32_t strlen = decode_uint32(buf);
+
+ buf+=4;
+ len-=4;
+ ERR_FAIL_COND_V((int)strlen>len,ERR_INVALID_DATA);
+
+ //printf("loaded string: %s\n",(const char*)buf);
+ String str;
+ str.parse_utf8((const char*)buf,strlen);
+
+ strings.push_back(str);
+
+ buf+=strlen;
+ len-=strlen;
+
+ if (r_len)
+ (*r_len)+=4+strlen;
+
+ if (strlen%4) {
+ int pad = 4-(strlen%4);
+ buf+=pad;
+ len-=pad;
+ if (r_len) {
+ (*r_len)+=pad;
+ }
+ }
+
+ }
+
+ r_variant=strings;
+
+
+ } break;
+ case Variant::VECTOR3_ARRAY: {
+
+ ERR_FAIL_COND_V(len<4,ERR_INVALID_DATA);
+ uint32_t count = decode_uint32(buf);
+ ERR_FAIL_COND_V(count<0,ERR_INVALID_DATA);
+ buf+=4;
+ len-=4;
+
+ ERR_FAIL_COND_V((int)count*4*3>len,ERR_INVALID_DATA);
+ DVector<Vector3> varray;
+
+ if (r_len) {
+ (*r_len)+=4;
+ }
+
+ if (count) {
+ varray.resize(count);
+ DVector<Vector3>::Write w = varray.write();
+ const float *r = (const float*)buf;
+
+ for(int i=0;i<(int)count;i++) {
+
+ w[i].x=decode_float(buf+i*4*3+4*0);
+ w[i].y=decode_float(buf+i*4*3+4*1);
+ w[i].z=decode_float(buf+i*4*3+4*2);
+
+ }
+
+ int adv = 4*3*count;
+
+ if (r_len)
+ (*r_len)+=adv;
+ len-=adv;
+ buf+=adv;
+
+ }
+
+ r_variant=varray;
+
+ } break;
+ case Variant::COLOR_ARRAY: {
+
+ ERR_FAIL_COND_V(len<4,ERR_INVALID_DATA);
+ uint32_t count = decode_uint32(buf);
+ ERR_FAIL_COND_V(count<0,ERR_INVALID_DATA);
+ buf+=4;
+ len-=4;
+
+ ERR_FAIL_COND_V((int)count*4*4>len,ERR_INVALID_DATA);
+ DVector<Color> carray;
+
+ if (r_len) {
+ (*r_len)+=4;
+ }
+
+ if (count) {
+ carray.resize(count);
+ DVector<Color>::Write w = carray.write();
+ const float *r = (const float*)buf;
+
+ for(int i=0;i<(int)count;i++) {
+
+ w[i].r=decode_float(buf+i*4*4+4*0);
+ w[i].g=decode_float(buf+i*4*4+4*1);
+ w[i].b=decode_float(buf+i*4*4+4*2);
+ w[i].a=decode_float(buf+i*4*4+4*3);
+
+ }
+
+ int adv = 4*4*count;
+
+ if (r_len)
+ (*r_len)+=adv;
+ len-=adv;
+ buf+=adv;
+
+ }
+
+ r_variant=carray;
+
+ } break;
+ default: { ERR_FAIL_V(ERR_BUG); }
+ }
+
+ return OK;
+}
+
+Error encode_variant(const Variant& p_variant, uint8_t *r_buffer, int &r_len) {
+
+ uint8_t * buf=r_buffer;
+
+ r_len=0;
+
+ if (buf) {
+ encode_uint32(p_variant.get_type(),buf);
+ buf+=4;
+ }
+ r_len+=4;
+
+ switch(p_variant.get_type()) {
+
+ case Variant::NIL: {
+
+ //nothing to do
+ } break;
+ case Variant::BOOL: {
+
+ if (buf) {
+ encode_uint32(p_variant.operator bool(),buf);
+ }
+
+ r_len+=4;
+
+ } break;
+ case Variant::INT: {
+
+ if (buf) {
+ encode_uint32(p_variant.operator int(),buf);
+ }
+
+ r_len+=4;
+
+ } break;
+ case Variant::REAL: {
+
+ if (buf) {
+ encode_float(p_variant.operator float(),buf);
+ }
+
+ r_len+=4;
+
+ } break;
+ case Variant::NODE_PATH:
+ case Variant::STRING: {
+
+
+ CharString utf8 = p_variant.operator String().utf8();
+
+ if (buf) {
+ encode_uint32(utf8.length(),buf);
+ buf+=4;
+ copymem(buf,utf8.get_data(),utf8.length());
+ }
+
+ r_len+=4+utf8.length();
+ while (r_len%4)
+ r_len++; //pad
+
+ } break;
+ // math types
+
+ case Variant::VECTOR2: {
+
+ if (buf) {
+ Vector2 v2=p_variant;
+ encode_float(v2.x,&buf[0]);
+ encode_float(v2.y,&buf[4]);
+
+ }
+
+ r_len+=2*4;
+
+ } break; // 5
+ case Variant::RECT2: {
+
+ if (buf) {
+ Rect2 r2=p_variant;
+ encode_float(r2.pos.x,&buf[0]);
+ encode_float(r2.pos.y,&buf[4]);
+ encode_float(r2.size.x,&buf[8]);
+ encode_float(r2.size.y,&buf[12]);
+ }
+ r_len+=4*4;
+
+ } break;
+ case Variant::VECTOR3: {
+
+ if (buf) {
+ Vector3 v3=p_variant;
+ encode_float(v3.x,&buf[0]);
+ encode_float(v3.y,&buf[4]);
+ encode_float(v3.z,&buf[8]);
+ }
+
+ r_len+=3*4;
+
+ } break;
+ case Variant::PLANE: {
+
+ if (buf) {
+ Plane p=p_variant;
+ encode_float(p.normal.x,&buf[0]);
+ encode_float(p.normal.y,&buf[4]);
+ encode_float(p.normal.z,&buf[8]);
+ encode_float(p.d,&buf[12]);
+ }
+
+ r_len+=4*4;
+
+ } break;
+ case Variant::QUAT: {
+
+ if (buf) {
+ Quat q=p_variant;
+ encode_float(q.x,&buf[0]);
+ encode_float(q.y,&buf[4]);
+ encode_float(q.z,&buf[8]);
+ encode_float(q.w,&buf[12]);
+ }
+
+ r_len+=4*4;
+
+ } break;
+ case Variant::_AABB: {
+
+ if (buf) {
+ AABB aabb=p_variant;
+ encode_float(aabb.pos.x,&buf[0]);
+ encode_float(aabb.pos.y,&buf[4]);
+ encode_float(aabb.pos.z,&buf[8]);
+ encode_float(aabb.size.x,&buf[12]);
+ encode_float(aabb.size.y,&buf[16]);
+ encode_float(aabb.size.z,&buf[20]);
+ }
+
+ r_len+=6*4;
+
+
+ } break;
+ case Variant::MATRIX3: {
+
+ if (buf) {
+ Matrix3 val=p_variant;
+ for(int i=0;i<3;i++) {
+ for(int j=0;j<3;j++) {
+
+ copymem(&buf[(i*3+j)*4],&val.elements[i][j],sizeof(float));
+ }
+ }
+ }
+
+
+ r_len+=9*4;
+
+ } break;
+ case Variant::TRANSFORM: {
+
+ if (buf) {
+ Transform val=p_variant;
+ for(int i=0;i<3;i++) {
+ for(int j=0;j<3;j++) {
+
+ copymem(&buf[(i*3+j)*4],&val.basis.elements[i][j],sizeof(float));
+ }
+ }
+
+ encode_float(val.origin.x,&buf[36]);
+ encode_float(val.origin.y,&buf[40]);
+ encode_float(val.origin.z,&buf[44]);
+
+
+ }
+
+ r_len+=12*4;
+
+ } break;
+
+ // misc types
+ case Variant::COLOR: {
+
+ if (buf) {
+ Color c=p_variant;
+ encode_float(c.r,&buf[0]);
+ encode_float(c.g,&buf[4]);
+ encode_float(c.b,&buf[8]);
+ encode_float(c.a,&buf[12]);
+ }
+
+ r_len+=4*4;
+
+ } break;
+ case Variant::IMAGE: {
+
+ Image image = p_variant;
+ DVector<uint8_t> data=image.get_data();
+
+ if (buf) {
+
+ encode_uint32(image.get_format(),&buf[0]);
+ encode_uint32(image.get_mipmaps(),&buf[4]);
+ encode_uint32(image.get_width(),&buf[8]);
+ encode_uint32(image.get_height(),&buf[12]);
+ int ds=data.size();
+ encode_uint32(ds,&buf[16]);
+ DVector<uint8_t>::Read r = data.read();
+ copymem(&buf[20],&r[0],ds);
+ }
+
+ r_len+=data.size()+5*4;
+
+ } break;
+ /*case Variant::RESOURCE: {
+
+ ERR_EXPLAIN("Can't marshallize resources");
+ ERR_FAIL_V(ERR_INVALID_DATA); //no, i'm sorry, no go
+ } break;*/
+ case Variant::_RID:
+ case Variant::OBJECT: {
+
+
+ } break;
+ case Variant::INPUT_EVENT: {
+
+
+ InputEvent ie=p_variant;
+
+ if (buf) {
+
+ encode_uint32(ie.type,&buf[0]);
+ encode_uint32(ie.device,&buf[4]);
+ encode_uint32(0,&buf[8]);
+ }
+
+ int llen=12;
+
+ switch(ie.type) {
+
+ case InputEvent::KEY: {
+
+ if (buf) {
+
+ uint32_t mods=0;
+ if (ie.key.mod.shift)
+ mods|=KEY_MASK_SHIFT;
+ if (ie.key.mod.control)
+ mods|=KEY_MASK_CTRL;
+ if (ie.key.mod.alt)
+ mods|=KEY_MASK_ALT;
+ if (ie.key.mod.meta)
+ mods|=KEY_MASK_META;
+
+ encode_uint32(mods,&buf[llen]);
+ encode_uint32(ie.key.scancode,&buf[llen+4]);
+ }
+ llen+=8;
+
+ } break;
+ case InputEvent::MOUSE_BUTTON: {
+
+ if (buf) {
+
+ encode_uint32(ie.mouse_button.button_index,&buf[llen]);
+ }
+ llen+=4;
+ } break;
+ case InputEvent::JOYSTICK_BUTTON: {
+
+ if (buf) {
+
+ encode_uint32(ie.joy_button.button_index,&buf[llen]);
+ }
+ llen+=4;
+ } break;
+ case InputEvent::SCREEN_TOUCH: {
+
+ if (buf) {
+
+ encode_uint32(ie.screen_touch.index,&buf[llen]);
+ }
+ llen+=4;
+ } break;
+ case InputEvent::JOYSTICK_MOTION: {
+
+ if (buf) {
+
+ int axis = ie.joy_motion.axis;
+ encode_uint32(axis,&buf[llen]);
+ }
+ llen+=4;
+ } break;
+ }
+
+ if (buf)
+ encode_uint32(llen,&buf[8]);
+ r_len+=llen;
+
+
+ // not supported
+ } break;
+ case Variant::DICTIONARY: {
+
+ Dictionary d = p_variant;
+
+ if (buf) {
+ encode_uint32(uint32_t(d.size())|(d.is_shared()?0x80000000:0),buf);
+ buf+=4;
+ }
+ r_len+=4;
+
+ List<Variant> keys;
+ d.get_key_list(&keys);
+
+
+ for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+ /*
+ CharString utf8 = E->->utf8();
+
+ if (buf) {
+ encode_uint32(utf8.length()+1,buf);
+ buf+=4;
+ copymem(buf,utf8.get_data(),utf8.length()+1);
+ }
+
+ r_len+=4+utf8.length()+1;
+ while (r_len%4)
+ r_len++; //pad
+ */
+ int len;
+ encode_variant(E->get(),buf,len);
+ ERR_FAIL_COND_V(len%4,ERR_BUG);
+ r_len+=len;
+ if (buf)
+ buf += len;
+ encode_variant(d[E->get()],buf,len);
+ ERR_FAIL_COND_V(len%4,ERR_BUG);
+ r_len+=len;
+ if (buf)
+ buf += len;
+ }
+
+ } break;
+ case Variant::ARRAY: {
+
+ Array v = p_variant;
+
+ if (buf) {
+ encode_uint32(uint32_t(v.size())|(v.is_shared()?0x80000000:0),buf);
+ buf+=4;
+ }
+
+ r_len+=4;
+
+ for(int i=0;i<v.size();i++) {
+
+ int len;
+ encode_variant(v.get(i),buf,len);
+ ERR_FAIL_COND_V(len%4,ERR_BUG);
+ r_len+=len;
+ if (buf)
+ buf+=len;
+ }
+
+
+ } break;
+ // arrays
+ case Variant::RAW_ARRAY: {
+
+ DVector<uint8_t> data = p_variant;
+ int datalen=data.size();
+ int datasize=sizeof(uint8_t);
+
+ if (buf) {
+ encode_uint32(datalen,buf);
+ buf+=4;
+ DVector<uint8_t>::Read r = data.read();
+ copymem(buf,&r[0],datalen*datasize);
+
+ }
+
+ r_len+=4+datalen*datasize;
+ while(r_len%4)
+ r_len++;
+
+ } break;
+ case Variant::INT_ARRAY: {
+
+ DVector<int> data = p_variant;
+ int datalen=data.size();
+ int datasize=sizeof(int32_t);
+
+ if (buf) {
+ encode_uint32(datalen,buf);
+ buf+=4;
+ DVector<int>::Read r = data.read();
+ for(int i=0;i<datalen;i++)
+ encode_uint32(r[i],&buf[i*datasize]);
+
+ }
+
+ r_len+=4+datalen*datasize;
+
+ } break;
+ case Variant::REAL_ARRAY: {
+
+ DVector<real_t> data = p_variant;
+ int datalen=data.size();
+ int datasize=sizeof(real_t);
+
+ if (buf) {
+ encode_uint32(datalen,buf);
+ buf+=4;
+ DVector<real_t>::Read r = data.read();
+ for(int i=0;i<datalen;i++)
+ encode_float(r[i],&buf[i*datasize]);
+
+ }
+
+ r_len+=4+datalen*datasize;
+
+ } break;
+ case Variant::STRING_ARRAY: {
+
+
+ DVector<String> data = p_variant;
+ int len=data.size();
+
+ if (buf) {
+ encode_uint32(len,buf);
+ buf+=4;
+ }
+
+ r_len+=4;
+
+ for(int i=0;i<len;i++) {
+
+
+ CharString utf8 = data.get(i).utf8();
+
+ if (buf) {
+ encode_uint32(utf8.length()+1,buf);
+ buf+=4;
+ copymem(buf,utf8.get_data(),utf8.length()+1);
+ buf+=utf8.length()+1;
+ }
+
+ r_len+=4+utf8.length()+1;
+ while (r_len%4) {
+ r_len++; //pad
+ if (buf)
+ buf++;
+ }
+ }
+
+ } break;
+ case Variant::VECTOR3_ARRAY: {
+
+ DVector<Vector3> data = p_variant;
+ int len=data.size();
+
+ if (buf) {
+ encode_uint32(len,buf);
+ buf+=4;
+ }
+
+ r_len+=4;
+
+ if (buf) {
+
+ for(int i=0;i<len;i++) {
+
+ Vector3 v = data.get(i);
+
+ encode_float(v.x,&buf[0]);
+ encode_float(v.y,&buf[4]);
+ encode_float(v.z,&buf[8]);
+ buf+=4*3;
+
+ }
+ }
+
+ r_len+=4*3*len;
+
+ } break;
+ case Variant::COLOR_ARRAY: {
+
+ DVector<Color> data = p_variant;
+ int len=data.size();
+
+ if (buf) {
+ encode_uint32(len,buf);
+ buf+=4;
+ }
+
+ r_len+=4;
+
+ if (buf) {
+
+ for(int i=0;i<len;i++) {
+
+ Color c = data.get(i);
+
+
+ encode_float(c.r,&buf[0]);
+ encode_float(c.g,&buf[4]);
+ encode_float(c.b,&buf[8]);
+ encode_float(c.a,&buf[12]);
+ buf+=4*4;
+ }
+ }
+
+ r_len+=4*4*len;
+
+ } break;
+ default: { ERR_FAIL_V(ERR_BUG); }
+ }
+
+ return OK;
+
+}
+
+
diff --git a/core/io/marshalls.h b/core/io/marshalls.h
new file mode 100644
index 0000000000..bb8d3b336a
--- /dev/null
+++ b/core/io/marshalls.h
@@ -0,0 +1,190 @@
+/*************************************************************************/
+/* marshalls.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef MARSHALLS_H
+#define MARSHALLS_H
+
+#include "typedefs.h"
+
+#include "variant.h"
+
+/**
+ * Miscelaneous helpers for marshalling data types, and encoding
+ * in an endian independent way
+ */
+
+
+union MarshallFloat {
+
+ uint32_t i; ///< int
+ float f; ///< float
+};
+
+union MarshallDouble {
+
+ uint64_t l; ///< long long
+ double d; ///< double
+};
+
+static inline unsigned int encode_uint16(uint16_t p_uint, uint8_t *p_arr) {
+
+ for (int i=0;i<2;i++) {
+
+ *p_arr=p_uint&0xFF;
+ p_arr++; p_uint>>=8;
+ }
+
+ return sizeof( uint16_t );
+}
+
+static inline unsigned int encode_uint32(uint32_t p_uint, uint8_t *p_arr) {
+
+ for (int i=0;i<4;i++) {
+
+ *p_arr=p_uint&0xFF;
+ p_arr++; p_uint>>=8;
+ }
+
+ return sizeof( uint32_t );
+}
+
+static inline unsigned int encode_float(float p_float, uint8_t *p_arr) {
+
+ MarshallFloat mf;
+ mf.f=p_float;
+ encode_uint32( mf.i, p_arr );
+
+ return sizeof( uint32_t );
+}
+
+static inline unsigned int encode_uint64(uint64_t p_uint, uint8_t *p_arr) {
+
+ for (int i=0;i<8;i++) {
+
+ *p_arr=p_uint&0xFF;
+ p_arr++; p_uint>>=8;
+ }
+
+ return sizeof(uint64_t);
+}
+
+static inline unsigned int encode_double(double p_double, uint8_t *p_arr) {
+
+ MarshallDouble md;
+ md.d=p_double;
+ encode_uint64( md.l, p_arr );
+
+ return sizeof(uint64_t);
+
+}
+
+
+static inline int encode_cstring(const char *p_string, uint8_t * p_data) {
+
+ int len=0;
+
+ while (*p_string) {
+
+ if (p_data) {
+
+ *p_data=(uint8_t)*p_string;
+ p_data++;
+ }
+ p_string++;
+ len++;
+ };
+
+ if (p_data) *p_data = 0;
+ return len+1;
+}
+
+static inline uint16_t decode_uint16(const uint8_t *p_arr) {
+
+ uint16_t u=0;
+
+ for (int i=0;i<2;i++) {
+
+ uint16_t b = *p_arr;
+ b<<=(i*8);
+ u|=b;
+ p_arr++;
+ }
+
+ return u;
+}
+
+static inline uint32_t decode_uint32(const uint8_t *p_arr) {
+
+ uint32_t u=0;
+
+ for (int i=0;i<4;i++) {
+
+ uint32_t b = *p_arr;
+ b<<=(i*8);
+ u|=b;
+ p_arr++;
+ }
+
+ return u;
+}
+
+static inline float decode_float(const uint8_t *p_arr) {
+
+ MarshallFloat mf;
+ mf.i = decode_uint32(p_arr);
+ return mf.f;
+}
+
+static inline uint64_t decode_uint64(const uint8_t *p_arr) {
+
+ uint64_t u=0;
+
+ for (int i=0;i<8;i++) {
+
+ uint64_t b = (*p_arr)&0xFF;
+ b<<=(i*8);
+ u|=b;
+ p_arr++;
+ }
+
+ return u;
+}
+
+static inline double decode_double(const uint8_t *p_arr) {
+
+ MarshallDouble md;
+ md.l = decode_uint64( p_arr );
+ return md.d;
+
+}
+
+
+Error decode_variant(Variant& r_variant,const uint8_t *p_buffer, int p_len,int *r_len=NULL);
+Error encode_variant(const Variant& p_variant, uint8_t *r_buffer, int &r_len);
+
+#endif
diff --git a/core/io/md5.cpp b/core/io/md5.cpp
new file mode 100644
index 0000000000..5a88328dd4
--- /dev/null
+++ b/core/io/md5.cpp
@@ -0,0 +1,269 @@
+#include "md5.h"
+
+/*
+ **********************************************************************
+ ** md5.c **
+ ** RSA Data Security, Inc. MD5 Message Digest Algorithm **
+ ** Created: 2/17/90 RLR **
+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C Version **
+ **********************************************************************
+ */
+
+/*
+ **********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ ** **
+ ** License to copy and use this software is granted provided that **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function. **
+ ** **
+ ** License is also granted to make and use derivative works **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD5 Message Digest Algorithm" in all **
+ ** material mentioning or referencing the derived work. **
+ ** **
+ ** RSA Data Security, Inc. makes no representations concerning **
+ ** either the merchantability of this software or the suitability **
+ ** of this software for any particular purpose. It is provided "as **
+ ** is" without express or implied warranty of any kind. **
+ ** **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software. **
+ **********************************************************************
+ */
+
+/* -- include the following line if the md5.h header file is separate -- */
+/* #include "md5.h" */
+
+/* forward declaration */
+static void Transform (uint32_t *buf, uint32_t *in);
+
+
+static unsigned char PADDING[64] = {
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* F, G and H are basic MD5 functions: selection, majority, parity */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s, ac) \
+ {(a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) \
+ {(a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) \
+ {(a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) \
+ {(a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+void MD5Init (MD5_CTX *mdContext)
+{
+ mdContext->i[0] = mdContext->i[1] = (uint32_t)0;
+
+ /* Load magic initialization constants.
+ */
+ mdContext->buf[0] = (uint32_t)0x67452301;
+ mdContext->buf[1] = (uint32_t)0xefcdab89;
+ mdContext->buf[2] = (uint32_t)0x98badcfe;
+ mdContext->buf[3] = (uint32_t)0x10325476;
+}
+
+void MD5Update (MD5_CTX *mdContext,unsigned char *inBuf,unsigned int inLen) {
+ uint32_t in[16];
+ int mdi;
+ unsigned int i, ii;
+
+ /* compute number of bytes mod 64 */
+ mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+ /* update number of bits */
+ if ((mdContext->i[0] + ((uint32_t)inLen << 3)) < mdContext->i[0])
+ mdContext->i[1]++;
+ mdContext->i[0] += ((uint32_t)inLen << 3);
+ mdContext->i[1] += ((uint32_t)inLen >> 29);
+
+ while (inLen--) {
+ /* add new character to buffer, increment mdi */
+ mdContext->in[mdi++] = *inBuf++;
+
+ /* transform if necessary */
+ if (mdi == 0x40) {
+ for (i = 0, ii = 0; i < 16; i++, ii += 4)
+ in[i] = (((uint32_t)mdContext->in[ii+3]) << 24) |
+ (((uint32_t)mdContext->in[ii+2]) << 16) |
+ (((uint32_t)mdContext->in[ii+1]) << 8) |
+ ((uint32_t)mdContext->in[ii]);
+ Transform (mdContext->buf, in);
+ mdi = 0;
+ }
+ }
+}
+
+void MD5Final (MD5_CTX *mdContext) {
+ uint32_t in[16];
+ int mdi;
+ unsigned int i, ii;
+ unsigned int padLen;
+
+ /* save number of bits */
+ in[14] = mdContext->i[0];
+ in[15] = mdContext->i[1];
+
+ /* compute number of bytes mod 64 */
+ mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+ /* pad out to 56 mod 64 */
+ padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
+ MD5Update (mdContext, PADDING, padLen);
+
+ /* append length in bits and transform */
+ for (i = 0, ii = 0; i < 14; i++, ii += 4)
+ in[i] = (((uint32_t)mdContext->in[ii+3]) << 24) |
+ (((uint32_t)mdContext->in[ii+2]) << 16) |
+ (((uint32_t)mdContext->in[ii+1]) << 8) |
+ ((uint32_t)mdContext->in[ii]);
+ Transform (mdContext->buf, in);
+
+ /* store buffer in digest */
+ for (i = 0, ii = 0; i < 4; i++, ii += 4) {
+ mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
+ mdContext->digest[ii+1] =
+ (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
+ mdContext->digest[ii+2] =
+ (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
+ mdContext->digest[ii+3] =
+ (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
+ }
+}
+
+/* Basic MD5 step. Transform buf based on in.
+ */
+static void Transform (uint32_t *buf, uint32_t *in) {
+ uint32_t a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+ /* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+ FF ( a, b, c, d, in[ 0], S11, 3614090360); /* 1 */
+ FF ( d, a, b, c, in[ 1], S12, 3905402710); /* 2 */
+ FF ( c, d, a, b, in[ 2], S13, 606105819); /* 3 */
+ FF ( b, c, d, a, in[ 3], S14, 3250441966); /* 4 */
+ FF ( a, b, c, d, in[ 4], S11, 4118548399); /* 5 */
+ FF ( d, a, b, c, in[ 5], S12, 1200080426); /* 6 */
+ FF ( c, d, a, b, in[ 6], S13, 2821735955); /* 7 */
+ FF ( b, c, d, a, in[ 7], S14, 4249261313); /* 8 */
+ FF ( a, b, c, d, in[ 8], S11, 1770035416); /* 9 */
+ FF ( d, a, b, c, in[ 9], S12, 2336552879); /* 10 */
+ FF ( c, d, a, b, in[10], S13, 4294925233); /* 11 */
+ FF ( b, c, d, a, in[11], S14, 2304563134); /* 12 */
+ FF ( a, b, c, d, in[12], S11, 1804603682); /* 13 */
+ FF ( d, a, b, c, in[13], S12, 4254626195); /* 14 */
+ FF ( c, d, a, b, in[14], S13, 2792965006); /* 15 */
+ FF ( b, c, d, a, in[15], S14, 1236535329); /* 16 */
+
+ /* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+ GG ( a, b, c, d, in[ 1], S21, 4129170786); /* 17 */
+ GG ( d, a, b, c, in[ 6], S22, 3225465664); /* 18 */
+ GG ( c, d, a, b, in[11], S23, 643717713); /* 19 */
+ GG ( b, c, d, a, in[ 0], S24, 3921069994); /* 20 */
+ GG ( a, b, c, d, in[ 5], S21, 3593408605); /* 21 */
+ GG ( d, a, b, c, in[10], S22, 38016083); /* 22 */
+ GG ( c, d, a, b, in[15], S23, 3634488961); /* 23 */
+ GG ( b, c, d, a, in[ 4], S24, 3889429448); /* 24 */
+ GG ( a, b, c, d, in[ 9], S21, 568446438); /* 25 */
+ GG ( d, a, b, c, in[14], S22, 3275163606); /* 26 */
+ GG ( c, d, a, b, in[ 3], S23, 4107603335); /* 27 */
+ GG ( b, c, d, a, in[ 8], S24, 1163531501); /* 28 */
+ GG ( a, b, c, d, in[13], S21, 2850285829); /* 29 */
+ GG ( d, a, b, c, in[ 2], S22, 4243563512); /* 30 */
+ GG ( c, d, a, b, in[ 7], S23, 1735328473); /* 31 */
+ GG ( b, c, d, a, in[12], S24, 2368359562); /* 32 */
+
+ /* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+ HH ( a, b, c, d, in[ 5], S31, 4294588738); /* 33 */
+ HH ( d, a, b, c, in[ 8], S32, 2272392833); /* 34 */
+ HH ( c, d, a, b, in[11], S33, 1839030562); /* 35 */
+ HH ( b, c, d, a, in[14], S34, 4259657740); /* 36 */
+ HH ( a, b, c, d, in[ 1], S31, 2763975236); /* 37 */
+ HH ( d, a, b, c, in[ 4], S32, 1272893353); /* 38 */
+ HH ( c, d, a, b, in[ 7], S33, 4139469664); /* 39 */
+ HH ( b, c, d, a, in[10], S34, 3200236656); /* 40 */
+ HH ( a, b, c, d, in[13], S31, 681279174); /* 41 */
+ HH ( d, a, b, c, in[ 0], S32, 3936430074); /* 42 */
+ HH ( c, d, a, b, in[ 3], S33, 3572445317); /* 43 */
+ HH ( b, c, d, a, in[ 6], S34, 76029189); /* 44 */
+ HH ( a, b, c, d, in[ 9], S31, 3654602809); /* 45 */
+ HH ( d, a, b, c, in[12], S32, 3873151461); /* 46 */
+ HH ( c, d, a, b, in[15], S33, 530742520); /* 47 */
+ HH ( b, c, d, a, in[ 2], S34, 3299628645); /* 48 */
+
+ /* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+ II ( a, b, c, d, in[ 0], S41, 4096336452); /* 49 */
+ II ( d, a, b, c, in[ 7], S42, 1126891415); /* 50 */
+ II ( c, d, a, b, in[14], S43, 2878612391); /* 51 */
+ II ( b, c, d, a, in[ 5], S44, 4237533241); /* 52 */
+ II ( a, b, c, d, in[12], S41, 1700485571); /* 53 */
+ II ( d, a, b, c, in[ 3], S42, 2399980690); /* 54 */
+ II ( c, d, a, b, in[10], S43, 4293915773); /* 55 */
+ II ( b, c, d, a, in[ 1], S44, 2240044497); /* 56 */
+ II ( a, b, c, d, in[ 8], S41, 1873313359); /* 57 */
+ II ( d, a, b, c, in[15], S42, 4264355552); /* 58 */
+ II ( c, d, a, b, in[ 6], S43, 2734768916); /* 59 */
+ II ( b, c, d, a, in[13], S44, 1309151649); /* 60 */
+ II ( a, b, c, d, in[ 4], S41, 4149444226); /* 61 */
+ II ( d, a, b, c, in[11], S42, 3174756917); /* 62 */
+ II ( c, d, a, b, in[ 2], S43, 718787259); /* 63 */
+ II ( b, c, d, a, in[ 9], S44, 3951481745); /* 64 */
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+/*
+ **********************************************************************
+ ** End of md5.c **
+ ******************************* (cut) ********************************
+ */
diff --git a/core/io/md5.h b/core/io/md5.h
new file mode 100644
index 0000000000..e99d58b443
--- /dev/null
+++ b/core/io/md5.h
@@ -0,0 +1,61 @@
+#ifndef MD5_H
+#define MD5_H
+
+/*
+ **********************************************************************
+ ** md5.h -- Header file for implementation of MD5 **
+ ** RSA Data Security, Inc. MD5 Message Digest Algorithm **
+ ** Created: 2/17/90 RLR **
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version **
+ ** Revised (for MD5): RLR 4/27/91 **
+ ** -- G modified to have y&~z instead of y&z **
+ ** -- FF, GG, HH modified to add in last register done **
+ ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 **
+ ** -- distinct additive constant for each step **
+ ** -- round 4 added, working mod 7 **
+ **********************************************************************
+ */
+
+/*
+ **********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ ** **
+ ** License to copy and use this software is granted provided that **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function. **
+ ** **
+ ** License is also granted to make and use derivative works **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD5 Message Digest Algorithm" in all **
+ ** material mentioning or referencing the derived work. **
+ ** **
+ ** RSA Data Security, Inc. makes no representations concerning **
+ ** either the merchantability of this software or the suitability **
+ ** of this software for any particular purpose. It is provided "as **
+ ** is" without express or implied warranty of any kind. **
+ ** **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software. **
+ **********************************************************************
+ */
+
+/* NOT typedef a 32 bit type */
+
+#include "typedefs.h"
+
+/* Data structure for MD5 (Message Digest) computation */
+typedef struct {
+ uint32_t i[2]; /* number of _bits_ handled mod 2^64 */
+ uint32_t buf[4]; /* scratch buffer */
+ unsigned char in[64]; /* input buffer */
+ unsigned char digest[16]; /* actual digest after MD5Final call */
+} MD5_CTX;
+
+void MD5Init (MD5_CTX *mdContext);
+void MD5Update (MD5_CTX *mdContext,unsigned char *inBuf,unsigned int inLen);
+void MD5Final (MD5_CTX *mdContext);
+
+
+
+#endif // MD5_H
diff --git a/core/io/object_format_binary.cpp b/core/io/object_format_binary.cpp
new file mode 100644
index 0000000000..c031f6e82b
--- /dev/null
+++ b/core/io/object_format_binary.cpp
@@ -0,0 +1,1491 @@
+/*************************************************************************/
+/* object_format_binary.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. */
+/*************************************************************************/
+#include "object_format_binary.h"
+#include "resource.h"
+#include "io/resource_loader.h"
+#include "print_string.h"
+#include "object_type_db.h"
+#include "globals.h"
+#include "os/os.h"
+#include "version.h"
+
+
+#define print_bl(m_what)
+#ifdef OLD_SCENE_FORMAT_ENABLED
+
+
+enum {
+
+ SECTION_RESOURCE=0,
+ SECTION_OBJECT=1,
+ SECTION_META_OBJECT=2,
+ SECTION_PROPERTY=3,
+ SECTION_END=4,
+
+ //numbering must be different from variant, in case new variant types are added (variant must be always contiguous for jumptable optimization)
+ VARIANT_NIL=1,
+ VARIANT_BOOL=2,
+ VARIANT_INT=3,
+ VARIANT_REAL=4,
+ VARIANT_STRING=5,
+ VARIANT_VECTOR2=10,
+ VARIANT_RECT2=11,
+ VARIANT_VECTOR3=12,
+ VARIANT_PLANE=13,
+ VARIANT_QUAT=14,
+ VARIANT_AABB=15,
+ VARIANT_MATRIX3=16,
+ VARIANT_TRANSFORM=17,
+ VARIANT_MATRIX32=18,
+ VARIANT_COLOR=20,
+ VARIANT_IMAGE=21,
+ VARIANT_NODE_PATH=22,
+ VARIANT_RID=23,
+ VARIANT_OBJECT=24,
+ VARIANT_INPUT_EVENT=25,
+ VARIANT_DICTIONARY=26,
+ VARIANT_ARRAY=30,
+ VARIANT_RAW_ARRAY=31,
+ VARIANT_INT_ARRAY=32,
+ VARIANT_REAL_ARRAY=33,
+ VARIANT_STRING_ARRAY=34,
+ VARIANT_VECTOR3_ARRAY=35,
+ VARIANT_COLOR_ARRAY=36,
+ VARIANT_VECTOR2_ARRAY=37,
+
+ IMAGE_ENCODING_EMPTY=0,
+ IMAGE_ENCODING_RAW=1,
+ IMAGE_ENCODING_PNG=2, //not yet
+ IMAGE_ENCODING_JPG=3,
+
+ IMAGE_FORMAT_GRAYSCALE=0,
+ IMAGE_FORMAT_INTENSITY=1,
+ IMAGE_FORMAT_GRAYSCALE_ALPHA=2,
+ IMAGE_FORMAT_RGB=3,
+ IMAGE_FORMAT_RGBA=4,
+ IMAGE_FORMAT_INDEXED=5,
+ IMAGE_FORMAT_INDEXED_ALPHA=6,
+ IMAGE_FORMAT_BC1=7,
+ IMAGE_FORMAT_BC2=8,
+ IMAGE_FORMAT_BC3=9,
+ IMAGE_FORMAT_BC4=10,
+ IMAGE_FORMAT_BC5=11,
+ IMAGE_FORMAT_CUSTOM=12,
+
+ OBJECT_EMPTY=0,
+ OBJECT_EXTERNAL_RESOURCE=1,
+ OBJECT_INTERNAL_RESOURCE=2,
+
+
+};
+
+
+void ObjectFormatSaverBinary::_pad_buffer(int p_bytes) {
+
+ int extra = 4-(p_bytes%4);
+ if (extra<4) {
+ for(int i=0;i<extra;i++)
+ f->store_8(0); //pad to 32
+ }
+
+}
+
+
+void ObjectFormatSaverBinary::write_property(int p_idx,const Variant& p_property) {
+
+ f->store_32(SECTION_PROPERTY);
+ f->store_32(p_idx);
+
+ switch(p_property.get_type()) {
+
+ case Variant::NIL: {
+
+ f->store_32(VARIANT_NIL);
+ // don't store anything
+ } break;
+ case Variant::BOOL: {
+
+ f->store_32(VARIANT_BOOL);
+ bool val=p_property;
+ f->store_32(val);
+ } break;
+ case Variant::INT: {
+
+ f->store_32(VARIANT_INT);
+ int val=p_property;
+ f->store_32(val);
+ } break;
+ case Variant::REAL: {
+
+ f->store_32(VARIANT_REAL);
+ real_t val=p_property;
+ f->store_real(val);
+
+ } break;
+ case Variant::STRING: {
+
+ f->store_32(VARIANT_STRING);
+ String val=p_property;
+ save_unicode_string(val);
+
+ } break;
+ case Variant::VECTOR2: {
+
+ f->store_32(VARIANT_VECTOR2);
+ Vector2 val=p_property;
+ f->store_real(val.x);
+ f->store_real(val.y);
+
+ } break;
+ case Variant::RECT2: {
+
+ f->store_32(VARIANT_RECT2);
+ Rect2 val=p_property;
+ f->store_real(val.pos.x);
+ f->store_real(val.pos.y);
+ f->store_real(val.size.x);
+ f->store_real(val.size.y);
+
+ } break;
+ case Variant::VECTOR3: {
+
+ f->store_32(VARIANT_VECTOR3);
+ Vector3 val=p_property;
+ f->store_real(val.x);
+ f->store_real(val.y);
+ f->store_real(val.z);
+
+ } break;
+ case Variant::PLANE: {
+
+ f->store_32(VARIANT_PLANE);
+ Plane val=p_property;
+ f->store_real(val.normal.x);
+ f->store_real(val.normal.y);
+ f->store_real(val.normal.z);
+ f->store_real(val.d);
+
+ } break;
+ case Variant::QUAT: {
+
+ f->store_32(VARIANT_QUAT);
+ Quat val=p_property;
+ f->store_real(val.x);
+ f->store_real(val.y);
+ f->store_real(val.z);
+ f->store_real(val.w);
+
+ } break;
+ case Variant::_AABB: {
+
+ f->store_32(VARIANT_AABB);
+ AABB val=p_property;
+ f->store_real(val.pos.x);
+ f->store_real(val.pos.y);
+ f->store_real(val.pos.z);
+ f->store_real(val.size.x);
+ f->store_real(val.size.y);
+ f->store_real(val.size.z);
+
+ } break;
+ case Variant::MATRIX32: {
+
+ f->store_32(VARIANT_MATRIX32);
+ Matrix32 val=p_property;
+ f->store_real(val.elements[0].x);
+ f->store_real(val.elements[0].y);
+ f->store_real(val.elements[1].x);
+ f->store_real(val.elements[1].y);
+ f->store_real(val.elements[2].x);
+ f->store_real(val.elements[2].y);
+
+ } break;
+ case Variant::MATRIX3: {
+
+ f->store_32(VARIANT_MATRIX3);
+ Matrix3 val=p_property;
+ f->store_real(val.elements[0].x);
+ f->store_real(val.elements[0].y);
+ f->store_real(val.elements[0].z);
+ f->store_real(val.elements[1].x);
+ f->store_real(val.elements[1].y);
+ f->store_real(val.elements[1].z);
+ f->store_real(val.elements[2].x);
+ f->store_real(val.elements[2].y);
+ f->store_real(val.elements[2].z);
+
+ } break;
+ case Variant::TRANSFORM: {
+
+ f->store_32(VARIANT_TRANSFORM);
+ Transform val=p_property;
+ f->store_real(val.basis.elements[0].x);
+ f->store_real(val.basis.elements[0].y);
+ f->store_real(val.basis.elements[0].z);
+ f->store_real(val.basis.elements[1].x);
+ f->store_real(val.basis.elements[1].y);
+ f->store_real(val.basis.elements[1].z);
+ f->store_real(val.basis.elements[2].x);
+ f->store_real(val.basis.elements[2].y);
+ f->store_real(val.basis.elements[2].z);
+ f->store_real(val.origin.x);
+ f->store_real(val.origin.y);
+ f->store_real(val.origin.z);
+
+ } break;
+ case Variant::COLOR: {
+
+ f->store_32(VARIANT_COLOR);
+ Color val=p_property;
+ f->store_real(val.r);
+ f->store_real(val.g);
+ f->store_real(val.b);
+ f->store_real(val.a);
+
+ } break;
+ case Variant::IMAGE: {
+
+ f->store_32(VARIANT_IMAGE);
+ Image val =p_property;
+ if (val.empty()) {
+ f->store_32(IMAGE_ENCODING_EMPTY);
+ break;
+ }
+ f->store_32(IMAGE_ENCODING_RAW); //raw encoding
+ f->store_32(val.get_width());
+ f->store_32(val.get_height());
+ f->store_32(val.get_mipmaps());
+ switch(val.get_format()) {
+
+ case Image::FORMAT_GRAYSCALE: f->store_32(IMAGE_FORMAT_GRAYSCALE ); break; ///< one byte per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255
+ case Image::FORMAT_INTENSITY: f->store_32(IMAGE_FORMAT_INTENSITY ); break; ///< one byte per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255
+ case Image::FORMAT_GRAYSCALE_ALPHA: f->store_32(IMAGE_FORMAT_GRAYSCALE_ALPHA ); break; ///< two bytes per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255. alpha 0-255
+ case Image::FORMAT_RGB: f->store_32(IMAGE_FORMAT_RGB ); break; ///< one byte R: f->store_32(IMAGE_FORMAT_ ); break; one byte G: f->store_32(IMAGE_FORMAT_ ); break; one byte B
+ case Image::FORMAT_RGBA: f->store_32(IMAGE_FORMAT_RGBA ); break; ///< one byte R: f->store_32(IMAGE_FORMAT_ ); break; one byte G: f->store_32(IMAGE_FORMAT_ ); break; one byte B: f->store_32(IMAGE_FORMAT_ ); break; one byte A
+ case Image::FORMAT_INDEXED: f->store_32(IMAGE_FORMAT_INDEXED ); break; ///< index byte 0-256: f->store_32(IMAGE_FORMAT_ ); break; and after image end: f->store_32(IMAGE_FORMAT_ ); break; 256*3 bytes of palette
+ case Image::FORMAT_INDEXED_ALPHA: f->store_32(IMAGE_FORMAT_INDEXED_ALPHA ); break; ///< index byte 0-256: f->store_32(IMAGE_FORMAT_ ); break; and after image end: f->store_32(IMAGE_FORMAT_ ); break; 256*4 bytes of palette (alpha)
+ case Image::FORMAT_BC1: f->store_32(IMAGE_FORMAT_BC1 ); break; // DXT1
+ case Image::FORMAT_BC2: f->store_32(IMAGE_FORMAT_BC2 ); break; // DXT3
+ case Image::FORMAT_BC3: f->store_32(IMAGE_FORMAT_BC3 ); break; // DXT5
+ case Image::FORMAT_BC4: f->store_32(IMAGE_FORMAT_BC4 ); break; // ATI1
+ case Image::FORMAT_BC5: f->store_32(IMAGE_FORMAT_BC5 ); break; // ATI2
+ case Image::FORMAT_CUSTOM: f->store_32(IMAGE_FORMAT_CUSTOM ); break;
+ default: {}
+
+ }
+
+ int dlen = val.get_data().size();
+ f->store_32(dlen);
+ DVector<uint8_t>::Read r = val.get_data().read();
+ f->store_buffer(r.ptr(),dlen);
+ _pad_buffer(dlen);
+
+ } break;
+ case Variant::NODE_PATH: {
+ f->store_32(VARIANT_NODE_PATH);
+ save_unicode_string(p_property);
+ } break;
+ case Variant::_RID: {
+
+ f->store_32(VARIANT_RID);
+ WARN_PRINT("Can't save RIDs");
+ RID val = p_property;
+ f->store_32(val.get_id());
+ } break;
+ case Variant::OBJECT: {
+
+ f->store_32(VARIANT_OBJECT);
+ RES res = p_property;
+ if (res.is_null()) {
+ f->store_32(OBJECT_EMPTY);
+ return; // don't save it
+ }
+
+ if (res->get_path().length() && res->get_path().find("::")==-1) {
+ f->store_32(OBJECT_EXTERNAL_RESOURCE);
+ save_unicode_string(res->get_type());
+ String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path();
+ save_unicode_string(path);
+ } else {
+
+ if (!resource_map.has(res)) {
+ f->store_32(OBJECT_EMPTY);
+ ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?");
+ ERR_FAIL();
+ }
+
+ f->store_32(OBJECT_INTERNAL_RESOURCE);
+ f->store_32(resource_map[res]);
+ //internal resource
+ }
+
+
+ } break;
+ case Variant::INPUT_EVENT: {
+
+ f->store_32(VARIANT_INPUT_EVENT);
+ WARN_PRINT("Can't save InputEvent (maybe it could..)");
+ } break;
+ case Variant::DICTIONARY: {
+
+ f->store_32(VARIANT_DICTIONARY);
+ Dictionary d = p_property;
+ f->store_32(d.size());
+
+ List<Variant> keys;
+ d.get_key_list(&keys);
+
+ for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+ //if (!_check_type(dict[E->get()]))
+ // continue;
+
+ write_property(0,E->get());
+ write_property(0,d[E->get()]);
+ }
+
+
+ } break;
+ case Variant::ARRAY: {
+
+ f->store_32(VARIANT_ARRAY);
+ Array a=p_property;
+ f->store_32(a.size());
+ for(int i=0;i<a.size();i++) {
+
+ write_property(i,a[i]);
+ }
+
+ } break;
+ case Variant::RAW_ARRAY: {
+
+ f->store_32(VARIANT_RAW_ARRAY);
+ DVector<uint8_t> arr = p_property;
+ int len=arr.size();
+ f->store_32(len);
+ DVector<uint8_t>::Read r = arr.read();
+ f->store_buffer(r.ptr(),len);
+ _pad_buffer(len);
+
+ } break;
+ case Variant::INT_ARRAY: {
+
+ f->store_32(VARIANT_INT_ARRAY);
+ DVector<int> arr = p_property;
+ int len=arr.size();
+ f->store_32(len);
+ DVector<int>::Read r = arr.read();
+ for(int i=0;i<len;i++)
+ f->store_32(r[i]);
+
+ } break;
+ case Variant::REAL_ARRAY: {
+
+ f->store_32(VARIANT_REAL_ARRAY);
+ DVector<real_t> arr = p_property;
+ int len=arr.size();
+ f->store_32(len);
+ DVector<real_t>::Read r = arr.read();
+ for(int i=0;i<len;i++) {
+ f->store_real(r[i]);
+ }
+
+ } break;
+ case Variant::STRING_ARRAY: {
+
+ f->store_32(VARIANT_STRING_ARRAY);
+ DVector<String> arr = p_property;
+ int len=arr.size();
+ f->store_32(len);
+ DVector<String>::Read r = arr.read();
+ for(int i=0;i<len;i++) {
+ save_unicode_string(r[i]);
+ }
+
+ } break;
+ case Variant::VECTOR3_ARRAY: {
+
+ f->store_32(VARIANT_VECTOR3_ARRAY);
+ DVector<Vector3> arr = p_property;
+ int len=arr.size();
+ f->store_32(len);
+ DVector<Vector3>::Read r = arr.read();
+ for(int i=0;i<len;i++) {
+ f->store_real(r[i].x);
+ f->store_real(r[i].y);
+ f->store_real(r[i].z);
+ }
+
+ } break;
+ case Variant::VECTOR2_ARRAY: {
+
+ f->store_32(VARIANT_VECTOR2_ARRAY);
+ DVector<Vector2> arr = p_property;
+ int len=arr.size();
+ f->store_32(len);
+ DVector<Vector2>::Read r = arr.read();
+ for(int i=0;i<len;i++) {
+ f->store_real(r[i].x);
+ f->store_real(r[i].y);
+ }
+
+ } break;
+ case Variant::COLOR_ARRAY: {
+
+ f->store_32(VARIANT_COLOR_ARRAY);
+ DVector<Color> arr = p_property;
+ int len=arr.size();
+ f->store_32(len);
+ DVector<Color>::Read r = arr.read();
+ for(int i=0;i<len;i++) {
+ f->store_real(r[i].r);
+ f->store_real(r[i].g);
+ f->store_real(r[i].b);
+ f->store_real(r[i].a);
+ }
+
+ } break;
+ default: {
+
+ ERR_EXPLAIN("Invalid variant");
+ ERR_FAIL();
+ }
+ }
+}
+
+
+void ObjectFormatSaverBinary::_find_resources(const Variant& p_variant) {
+
+
+ switch(p_variant.get_type()) {
+ case Variant::OBJECT: {
+
+
+ RES res = p_variant.operator RefPtr();
+
+ if (res.is_null())
+ return;
+
+ if (!bundle_resources && res->get_path().length() && res->get_path().find("::") == -1 )
+ return;
+
+ if (resource_map.has(res))
+ return;
+
+ List<PropertyInfo> property_list;
+
+ res->get_property_list(&property_list);
+
+ for(List<PropertyInfo>::Element *E=property_list.front();E;E=E->next()) {
+
+ if (E->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && E->get().usage&PROPERTY_USAGE_BUNDLE)) {
+
+ _find_resources(res->get(E->get().name));
+ }
+ }
+
+ SavedObject *so = memnew( SavedObject );
+ _save_obj(res.ptr(),so);
+ so->meta=res.get_ref_ptr();
+
+ resource_map[ res ] = saved_resources.size();
+ saved_resources.push_back(so);
+
+ } break;
+
+ case Variant::ARRAY: {
+
+ Array varray=p_variant;
+ int len=varray.size();
+ for(int i=0;i<len;i++) {
+
+ Variant v=varray.get(i);
+ _find_resources(v);
+ }
+
+ } break;
+
+ case Variant::DICTIONARY: {
+
+ Dictionary d=p_variant;
+ List<Variant> keys;
+ d.get_key_list(&keys);
+ for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+ Variant v = d[E->get()];
+ _find_resources(v);
+ }
+ } break;
+ default: {}
+ }
+
+}
+Error ObjectFormatSaverBinary::_save_obj(const Object *p_object,SavedObject *so) {
+
+ if (optimizer.is_valid()) {
+ //use optimizer
+
+ List<OptimizedSaver::Property> props;
+ optimizer->get_property_list(p_object,&props);
+
+ for(List<OptimizedSaver::Property>::Element *E=props.front();E;E=E->next()) {
+
+ if (skip_editor && String(E->get().name).begins_with("__editor"))
+ continue;
+ _find_resources(E->get().value);
+ SavedObject::SavedProperty sp;
+
+ sp.name_idx=get_string_index(E->get().name);
+ sp.value=E->get().value;
+ so->properties.push_back(sp);
+ }
+
+ } else {
+ //use classic way
+ List<PropertyInfo> property_list;
+ p_object->get_property_list( &property_list );
+
+ for(List<PropertyInfo>::Element *E=property_list.front();E;E=E->next()) {
+
+ if (skip_editor && E->get().name.begins_with("__editor"))
+ continue;
+ if (E->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && E->get().usage&PROPERTY_USAGE_BUNDLE)) {
+
+ SavedObject::SavedProperty sp;
+ sp.name_idx=get_string_index(E->get().name);
+ sp.value = p_object->get(E->get().name);
+ _find_resources(sp.value);
+ so->properties.push_back(sp);
+ }
+ }
+ }
+
+ return OK;
+
+}
+
+Error ObjectFormatSaverBinary::save(const Object *p_object,const Variant &p_meta) {
+
+ ERR_FAIL_COND_V(!f,ERR_UNCONFIGURED);
+ ERR_EXPLAIN("write_object should supply either an object, a meta, or both");
+ ERR_FAIL_COND_V(!p_object && p_meta.get_type()==Variant::NIL, ERR_INVALID_PARAMETER);
+
+ SavedObject *so = memnew( SavedObject );
+
+ if (p_object)
+ so->type=p_object->get_type();
+
+ _find_resources(p_meta);
+ so->meta=p_meta;
+ Error err = _save_obj(p_object,so);
+ ERR_FAIL_COND_V( err, ERR_INVALID_DATA );
+
+ saved_objects.push_back(so);
+
+ return OK;
+}
+
+void ObjectFormatSaverBinary::save_unicode_string(const String& p_string) {
+
+
+ CharString utf8 = p_string.utf8();
+ f->store_32(utf8.length()+1);
+ f->store_buffer((const uint8_t*)utf8.get_data(),utf8.length()+1);
+}
+
+ObjectFormatSaverBinary::ObjectFormatSaverBinary(FileAccess *p_file,const String& p_magic,const String& p_local_path,uint32_t p_flags,const Ref<OptimizedSaver>& p_optimizer) {
+
+ optimizer=p_optimizer;
+ relative_paths=p_flags&ObjectSaver::FLAG_RELATIVE_PATHS;
+ skip_editor=p_flags&ObjectSaver::FLAG_OMIT_EDITOR_PROPERTIES;
+ bundle_resources=p_flags&ObjectSaver::FLAG_BUNDLE_RESOURCES;
+ big_endian=p_flags&ObjectSaver::FLAG_SAVE_BIG_ENDIAN;
+ f=p_file; // should be already opened
+ local_path=p_local_path;
+ magic=p_magic;
+
+ bin_meta_idx = get_string_index("__bin_meta__"); //is often used, so create
+}
+
+int ObjectFormatSaverBinary::get_string_index(const String& p_string) {
+
+ StringName s=p_string;
+ if (string_map.has(s))
+ return string_map[s];
+
+ string_map[s]=strings.size();
+ strings.push_back(s);
+ return strings.size()-1;
+}
+
+ObjectFormatSaverBinary::~ObjectFormatSaverBinary() {
+
+
+ static const uint8_t header[4]={'O','B','D','B'};
+ f->store_buffer(header,4);
+ if (big_endian) {
+ f->store_32(1);
+ f->set_endian_swap(true);
+ } else
+ f->store_32(0);
+
+ f->store_32(0); //64 bits file, false for now
+ f->store_32(VERSION_MAJOR);
+ f->store_32(VERSION_MINOR);
+ save_unicode_string(magic);
+ for(int i=0;i<16;i++)
+ f->store_32(0); // reserved
+
+ f->store_32(strings.size()); //string table size
+ for(int i=0;i<strings.size();i++) {
+ print_bl("saving string: "+strings[i]);
+ save_unicode_string(strings[i]);
+ }
+
+ // save resources
+
+ for(int i=0;i<saved_resources.size();i++) {
+
+ SavedObject *so = saved_resources[i];
+ RES res = so->meta;
+ ERR_CONTINUE(!resource_map.has(res));
+
+ f->store_32(SECTION_RESOURCE);
+ size_t skip_pos = f->get_pos();
+ f->store_64(0); // resource skip seek pos
+ save_unicode_string(res->get_type());
+
+ if (res->get_path().length() && res->get_path().find("::") == -1 )
+ save_unicode_string(res->get_path());
+ else
+ save_unicode_string("local://"+itos(i));
+
+
+
+ List<SavedObject::SavedProperty>::Element *SE = so->properties.front();
+
+ while(SE) {
+
+ write_property(SE->get().name_idx,SE->get().value);
+ SE=SE->next();
+ }
+
+ f->store_32(SECTION_END);
+
+ size_t end=f->get_pos();
+ f->seek(skip_pos);
+ f->store_64(end);
+ f->seek_end();
+
+ memdelete( so );
+ }
+
+ if (!saved_objects.empty()) {
+
+
+ for(List<SavedObject*>::Element *E=saved_objects.front();E;E=E->next()) {
+
+ SavedObject *so = E->get();
+
+
+ size_t section_end;
+
+ if (so->type!="") {
+ f->store_32(SECTION_OBJECT);
+ section_end=f->get_pos();
+ f->store_64(0); //section end
+ save_unicode_string(so->type);
+ } else {
+ f->store_32(SECTION_META_OBJECT);
+ section_end=f->get_pos();
+ f->store_64(0); //section end
+ }
+
+
+ if (so->meta.get_type()!=Variant::NIL)
+ write_property(bin_meta_idx,so->meta);
+
+ List<SavedObject::SavedProperty>::Element *SE = so->properties.front();
+
+ while(SE) {
+
+ write_property(SE->get().name_idx,SE->get().value);
+ SE=SE->next();
+ }
+
+ f->store_32(SECTION_END);
+
+ size_t end=f->get_pos();
+ f->seek(section_end);
+ f->store_64(end);
+ f->seek_end();
+
+ memdelete(so); //no longer needed
+ }
+
+
+ }
+
+ f->store_32(SECTION_END);
+
+ f->close();
+ memdelete(f);
+}
+
+
+ObjectFormatSaver* ObjectFormatSaverInstancerBinary::instance(const String& p_file,const String& p_magic,uint32_t p_flags,const Ref<OptimizedSaver>& p_optimizer) {
+
+ FileAccess *f = FileAccess::open(p_file, FileAccess::WRITE);
+
+ ERR_FAIL_COND_V( !f, NULL );
+ String local_path = Globals::get_singleton()->localize_path(p_file);
+
+ return memnew( ObjectFormatSaverBinary( f, p_magic,local_path,p_flags,p_optimizer ) );
+}
+
+void ObjectFormatSaverInstancerBinary::get_recognized_extensions(List<String> *p_extensions) const {
+
+ p_extensions->push_back("bin");
+}
+
+
+ObjectFormatSaverInstancerBinary::~ObjectFormatSaverInstancerBinary() {
+
+
+}
+
+
+
+/************************************************/
+/************************************************/
+/************************************************/
+/************************************************/
+/************************************************/
+
+
+void ObjectFormatLoaderBinary::_advance_padding(uint32_t p_len) {
+
+ uint32_t extra = 4-(p_len%4);
+ if (extra<4) {
+ for(uint32_t i=0;i<extra;i++)
+ f->get_8(); //pad to 32
+ }
+
+}
+
+Error ObjectFormatLoaderBinary::parse_property(Variant& r_v, int &r_index) {
+
+
+ uint32_t prop = f->get_32();
+ if (prop==SECTION_END)
+ return ERR_FILE_EOF;
+ ERR_FAIL_COND_V(prop!=SECTION_PROPERTY,ERR_FILE_CORRUPT);
+
+ r_index = f->get_32();
+
+ uint32_t type = f->get_32();
+ print_bl("find property of type: "+itos(type));
+
+
+ switch(type) {
+
+ case VARIANT_NIL: {
+
+ r_v=Variant();
+ } break;
+ case VARIANT_BOOL: {
+
+ r_v=bool(f->get_32());
+ } break;
+ case VARIANT_INT: {
+
+ r_v=int(f->get_32());
+ } break;
+ case VARIANT_REAL: {
+
+ r_v=f->get_real();
+ } break;
+ case VARIANT_STRING: {
+
+ r_v=get_unicode_string();
+ } break;
+ case VARIANT_VECTOR2: {
+
+ Vector2 v;
+ v.x=f->get_real();
+ v.y=f->get_real();
+ r_v=v;
+
+ } break;
+ case VARIANT_RECT2: {
+
+ Rect2 v;
+ v.pos.x=f->get_real();
+ v.pos.y=f->get_real();
+ v.size.x=f->get_real();
+ v.size.y=f->get_real();
+ r_v=v;
+
+ } break;
+ case VARIANT_VECTOR3: {
+
+ Vector3 v;
+ v.x=f->get_real();
+ v.y=f->get_real();
+ v.z=f->get_real();
+ r_v=v;
+ } break;
+ case VARIANT_PLANE: {
+
+ Plane v;
+ v.normal.x=f->get_real();
+ v.normal.y=f->get_real();
+ v.normal.z=f->get_real();
+ v.d=f->get_real();
+ r_v=v;
+ } break;
+ case VARIANT_QUAT: {
+ Quat v;
+ v.x=f->get_real();
+ v.y=f->get_real();
+ v.z=f->get_real();
+ v.w=f->get_real();
+ r_v=v;
+
+ } break;
+ case VARIANT_AABB: {
+
+ AABB v;
+ v.pos.x=f->get_real();
+ v.pos.y=f->get_real();
+ v.pos.z=f->get_real();
+ v.size.x=f->get_real();
+ v.size.y=f->get_real();
+ v.size.z=f->get_real();
+ r_v=v;
+
+ } break;
+ case VARIANT_MATRIX32: {
+
+ Matrix32 v;
+ v.elements[0].x=f->get_real();
+ v.elements[0].y=f->get_real();
+ v.elements[1].x=f->get_real();
+ v.elements[1].y=f->get_real();
+ v.elements[2].x=f->get_real();
+ v.elements[2].y=f->get_real();
+ r_v=v;
+
+ } break;
+ case VARIANT_MATRIX3: {
+
+ Matrix3 v;
+ v.elements[0].x=f->get_real();
+ v.elements[0].y=f->get_real();
+ v.elements[0].z=f->get_real();
+ v.elements[1].x=f->get_real();
+ v.elements[1].y=f->get_real();
+ v.elements[1].z=f->get_real();
+ v.elements[2].x=f->get_real();
+ v.elements[2].y=f->get_real();
+ v.elements[2].z=f->get_real();
+ r_v=v;
+
+ } break;
+ case VARIANT_TRANSFORM: {
+
+ Transform v;
+ v.basis.elements[0].x=f->get_real();
+ v.basis.elements[0].y=f->get_real();
+ v.basis.elements[0].z=f->get_real();
+ v.basis.elements[1].x=f->get_real();
+ v.basis.elements[1].y=f->get_real();
+ v.basis.elements[1].z=f->get_real();
+ v.basis.elements[2].x=f->get_real();
+ v.basis.elements[2].y=f->get_real();
+ v.basis.elements[2].z=f->get_real();
+ v.origin.x=f->get_real();
+ v.origin.y=f->get_real();
+ v.origin.z=f->get_real();
+ r_v=v;
+ } break;
+ case VARIANT_COLOR: {
+
+ Color v;
+ v.r=f->get_real();
+ v.g=f->get_real();
+ v.b=f->get_real();
+ v.a=f->get_real();
+ r_v=v;
+
+ } break;
+ case VARIANT_IMAGE: {
+
+
+ uint32_t encoding = f->get_32();
+ if (encoding==IMAGE_ENCODING_EMPTY) {
+ r_v=Variant();
+ break;
+ }
+
+ if (encoding==IMAGE_ENCODING_RAW) {
+ uint32_t width = f->get_32();
+ uint32_t height = f->get_32();
+ uint32_t mipmaps = f->get_32();
+ uint32_t format = f->get_32();
+ Image::Format fmt;
+ switch(format) {
+
+ case IMAGE_FORMAT_GRAYSCALE: { fmt=Image::FORMAT_GRAYSCALE; } break;
+ case IMAGE_FORMAT_INTENSITY: { fmt=Image::FORMAT_INTENSITY; } break;
+ case IMAGE_FORMAT_GRAYSCALE_ALPHA: { fmt=Image::FORMAT_GRAYSCALE_ALPHA; } break;
+ case IMAGE_FORMAT_RGB: { fmt=Image::FORMAT_RGB; } break;
+ case IMAGE_FORMAT_RGBA: { fmt=Image::FORMAT_RGBA; } break;
+ case IMAGE_FORMAT_INDEXED: { fmt=Image::FORMAT_INDEXED; } break;
+ case IMAGE_FORMAT_INDEXED_ALPHA: { fmt=Image::FORMAT_INDEXED_ALPHA; } break;
+ case IMAGE_FORMAT_BC1: { fmt=Image::FORMAT_BC1; } break;
+ case IMAGE_FORMAT_BC2: { fmt=Image::FORMAT_BC2; } break;
+ case IMAGE_FORMAT_BC3: { fmt=Image::FORMAT_BC3; } break;
+ case IMAGE_FORMAT_BC4: { fmt=Image::FORMAT_BC4; } break;
+ case IMAGE_FORMAT_BC5: { fmt=Image::FORMAT_BC5; } break;
+ case IMAGE_FORMAT_CUSTOM: { fmt=Image::FORMAT_CUSTOM; } break;
+ default: {
+
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ }
+
+ }
+
+
+ uint32_t datalen = f->get_32();
+
+ print_bl("width: "+itos(width));
+ print_bl("height: "+itos(height));
+ print_bl("mipmaps: "+itos(mipmaps));
+ print_bl("format: "+itos(format));
+ print_bl("datalen: "+itos(datalen));
+
+ DVector<uint8_t> imgdata;
+ imgdata.resize(datalen);
+ DVector<uint8_t>::Write w = imgdata.write();
+ f->get_buffer(w.ptr(),datalen);
+ _advance_padding(datalen);
+ w=DVector<uint8_t>::Write();
+
+ r_v=Image(width,height,mipmaps,fmt,imgdata);
+ }
+
+
+ } break;
+ case VARIANT_NODE_PATH: {
+
+ r_v=NodePath(get_unicode_string());
+ } break;
+ case VARIANT_RID: {
+
+ r_v=f->get_32();
+ } break;
+ case VARIANT_OBJECT: {
+
+ uint32_t type=f->get_32();
+
+ switch(type) {
+
+ case OBJECT_EMPTY: {
+ //do none
+
+ } break;
+ case OBJECT_INTERNAL_RESOURCE: {
+ uint32_t index=f->get_32();
+ String path = local_path+"::"+itos(index);
+ RES res = ResourceLoader::load(path);
+ if (res.is_null()) {
+ WARN_PRINT(String("Couldn't load resource: "+path).utf8().get_data());
+ }
+ r_v=res;
+
+ } break;
+ case OBJECT_EXTERNAL_RESOURCE: {
+
+ String type = get_unicode_string();
+ String path = get_unicode_string();
+
+ if (path.find("://")==-1 && path.is_rel_path()) {
+ // path is relative to file being loaded, so convert to a resource path
+ path=Globals::get_singleton()->localize_path(local_path.get_base_dir()+"/"+path);
+
+ }
+
+ RES res=ResourceLoader::load(path,type);
+
+ if (res.is_null()) {
+ WARN_PRINT(String("Couldn't load resource: "+path).utf8().get_data());
+ }
+ r_v=res;
+
+ } break;
+ default: {
+
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ } break;
+ }
+
+ } break;
+ case VARIANT_INPUT_EVENT: {
+
+ } break;
+ case VARIANT_DICTIONARY: {
+
+ int len=f->get_32();
+ Dictionary d;
+ for(int i=0;i<len;i++) {
+ int idx;
+ Variant key;
+ Error err = parse_property(key,idx);
+ ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT);
+ Variant value;
+ err = parse_property(value,idx);
+ ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT);
+ d[key]=value;
+ }
+ r_v=d;
+ } break;
+ case VARIANT_ARRAY: {
+ int len=f->get_32();
+ Array a;
+ a.resize(len);
+ for(int i=0;i<len;i++) {
+ int idx;
+ Variant val;
+ Error err = parse_property(val,idx);
+ ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT);
+ a[i]=val;
+ }
+ r_v=a;
+
+ } break;
+ case VARIANT_RAW_ARRAY: {
+
+ uint32_t len = f->get_32();
+
+ DVector<uint8_t> array;
+ array.resize(len);
+ DVector<uint8_t>::Write w = array.write();
+ f->get_buffer(w.ptr(),len);
+ _advance_padding(len);
+ w=DVector<uint8_t>::Write();
+ r_v=array;
+
+ } break;
+ case VARIANT_INT_ARRAY: {
+
+ uint32_t len = f->get_32();
+
+ DVector<int> array;
+ array.resize(len);
+ DVector<int>::Write w = array.write();
+ f->get_buffer((uint8_t*)w.ptr(),len*4);
+ w=DVector<int>::Write();
+ r_v=array;
+ } break;
+ case VARIANT_REAL_ARRAY: {
+
+ uint32_t len = f->get_32();
+
+ DVector<real_t> array;
+ array.resize(len);
+ DVector<real_t>::Write w = array.write();
+ f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t));
+ w=DVector<real_t>::Write();
+ r_v=array;
+ } break;
+ case VARIANT_STRING_ARRAY: {
+
+ uint32_t len = f->get_32();
+ DVector<String> array;
+ array.resize(len);
+ DVector<String>::Write w = array.write();
+ for(int i=0;i<len;i++)
+ w[i]=get_unicode_string();
+ w=DVector<String>::Write();
+ r_v=array;
+
+
+ } break;
+ case VARIANT_VECTOR2_ARRAY: {
+
+ uint32_t len = f->get_32();
+
+ DVector<Vector2> array;
+ array.resize(len);
+ DVector<Vector2>::Write w = array.write();
+ if (sizeof(Vector2)==8) {
+ f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*2);
+ } else {
+ ERR_EXPLAIN("Vector2 size is NOT 8!");
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+ }
+ w=DVector<Vector2>::Write();
+ r_v=array;
+
+ } break;
+ case VARIANT_VECTOR3_ARRAY: {
+
+ uint32_t len = f->get_32();
+
+ DVector<Vector3> array;
+ array.resize(len);
+ DVector<Vector3>::Write w = array.write();
+ if (sizeof(Vector3)==12) {
+ f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*3);
+ } else {
+ ERR_EXPLAIN("Vector3 size is NOT 12!");
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+ }
+ w=DVector<Vector3>::Write();
+ r_v=array;
+
+ } break;
+ case VARIANT_COLOR_ARRAY: {
+
+ uint32_t len = f->get_32();
+
+ DVector<Color> array;
+ array.resize(len);
+ DVector<Color>::Write w = array.write();
+ if (sizeof(Color)==16) {
+ f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*4);
+ } else {
+ ERR_EXPLAIN("Color size is NOT 16!");
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+ }
+ w=DVector<Color>::Write();
+ r_v=array;
+ } break;
+
+ default: {
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ } break;
+ }
+
+
+
+ return OK; //never reach anyway
+
+}
+
+Error ObjectFormatLoaderBinary::load(Object **p_object,Variant &p_meta) {
+
+
+
+ while(true) {
+
+ if (f->eof_reached()) {
+ ERR_EXPLAIN("Premature end of file at: "+local_path);
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ }
+
+ RES resource;
+ Object *obj=NULL;
+ bool meta=false;
+
+ uint32_t section = f->get_32();
+
+ switch(section) {
+
+
+ case SECTION_RESOURCE: {
+
+ print_bl("resource found");
+
+ size_t section_end = f->get_64();
+ print_bl("section end: "+itos(section_end));
+ String type = get_unicode_string();
+ String path = get_unicode_string();
+ print_bl("path: "+path);
+
+ if (path.begins_with("local://")) {
+ //built-in resource (but really external)
+ path=path.replace("local://",local_path+"::");
+ }
+
+ if (ResourceCache::has(path)) {
+ f->seek(section_end);
+ continue;
+ }
+
+ //load properties
+
+
+ obj = ObjectTypeDB::instance(type);
+ if (!obj) {
+ ERR_EXPLAIN("Object of unrecognized type '"+type+"' in file: "+type);
+ }
+
+ ERR_FAIL_COND_V(!obj,ERR_FILE_CORRUPT);
+
+ Resource *r = obj->cast_to<Resource>();
+ if (!r) {
+ memdelete(obj); //bye
+ ERR_EXPLAIN("Object type in resource field not a resource, type is: "+obj->get_type());
+ ERR_FAIL_COND_V(!obj->cast_to<Resource>(),ERR_FILE_CORRUPT);
+ }
+
+ resource = RES( r );
+ r->set_path(path);
+ } break;
+ case SECTION_META_OBJECT:
+ meta=true;
+ print_bl("meta found");
+
+ case SECTION_OBJECT: {
+
+ uint64_t section_end = f->get_64();
+
+ if (!meta) {
+ print_bl("object");
+
+ String type = get_unicode_string();
+ if (ObjectTypeDB::can_instance(type)) {
+ obj = ObjectTypeDB::instance(type);
+ if (!obj) {
+ ERR_EXPLAIN("Object of unrecognized type in file: "+type);
+ }
+ ERR_FAIL_COND_V(!obj,ERR_FILE_CORRUPT);
+ } else {
+
+ f->seek(section_end);
+ return ERR_SKIP;
+ };
+
+
+ }
+
+
+ } break;
+ case SECTION_END: {
+
+
+ return ERR_FILE_EOF;
+ } break;
+
+ default: {
+
+ ERR_EXPLAIN("Invalid Section ID '"+itos(section)+"' in file: "+local_path);
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+
+ }
+
+ }
+
+
+ //load properties
+
+ while(true) {
+
+ int name_idx;
+ Variant v;
+ Error err;
+ err = parse_property(v,name_idx);
+
+ print_bl("prop idx "+itos(name_idx)+" value: "+String(v));
+
+ if (err==ERR_FILE_EOF)
+ break;
+
+ if (err!=OK) {
+ ERR_EXPLAIN("File Corrupted");
+ ERR_FAIL_COND_V(err!=OK,ERR_FILE_CORRUPT);
+ }
+
+
+ if (resource.is_null() && name_idx==0) { //0 is __bin_meta__
+
+ p_meta=v;
+ continue;
+ } else if (!obj) {
+
+ ERR_EXPLAIN("Normal property found in meta object.");
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ }
+
+ Map<int,StringName>::Element *E=string_map.find(name_idx);
+ if (!E) {
+ ERR_EXPLAIN("Property ID has no matching name: "+itos(name_idx));
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ }
+
+ obj->set(E->get(),v);
+ }
+
+ if (!obj) {
+ *p_object=NULL;
+ return OK; // it was a meta object
+ }
+
+ if (resource.is_null()) {
+
+ //regular object
+ *p_object=obj;
+ return OK;
+ } else {
+
+ resource_cache.push_back(resource); //keep it in mem until finished loading
+ }
+
+ }
+}
+
+
+ObjectFormatLoaderBinary::~ObjectFormatLoaderBinary() {
+
+ if (f) {
+ if (f->is_open())
+ f->close();
+ memdelete(f);
+ }
+}
+
+
+String ObjectFormatLoaderBinary::get_unicode_string() {
+
+ uint32_t len = f->get_32();
+ if (len>str_buf.size()) {
+ str_buf.resize(len);
+ }
+ f->get_buffer((uint8_t*)&str_buf[0],len);
+ String s;
+ s.parse_utf8(&str_buf[0]);
+ return s;
+}
+
+ObjectFormatLoaderBinary::ObjectFormatLoaderBinary(FileAccess *p_f,bool p_endian_swap,bool p_use64) {
+
+ f=p_f;
+ endian_swap=p_endian_swap;
+ use_real64=p_use64;
+
+ //load string table
+ uint32_t string_table_size = f->get_32();
+ print_bl("string table size: "+itos(string_table_size));
+ for(int i=0;i<string_table_size;i++) {
+
+ String str = get_unicode_string();
+ print_bl("string "+itos(i)+" is: "+str);
+ string_map[i]=str;
+ }
+
+
+}
+
+ObjectFormatLoaderBinary* ObjectFormatLoaderInstancerBinary::instance(const String& p_file,const String& p_magic) {
+
+ FileAccess *f=FileAccess::open(p_file,FileAccess::READ);
+ ERR_FAIL_COND_V(!f,NULL);
+
+ uint8_t header[4];
+ f->get_buffer(header,4);
+ if (header[0]!='O' || header[1]!='B' || header[2]!='D' || header[3]!='B') {
+
+ ERR_EXPLAIN("File not in valid binary format: "+p_file);
+ ERR_FAIL_V(NULL);
+ }
+
+ uint32_t big_endian = f->get_32();
+#ifdef BIG_ENDIAN_ENABLED
+ bool endian_swap = !big_endian;
+#else
+ bool endian_swap = big_endian;
+#endif
+
+ bool use_real64 = f->get_32();
+
+ f->set_endian_swap(big_endian!=0); //read big endian if saved as big endian
+
+ uint32_t ver_major=f->get_32();
+ uint32_t ver_minor=f->get_32();
+
+ print_bl("big endian: "+itos(big_endian));
+ print_bl("endian swap: "+itos(endian_swap));
+ print_bl("real64: "+itos(use_real64));
+ print_bl("major: "+itos(ver_major));
+ print_bl("minor: "+itos(ver_minor));
+
+ if (ver_major>VERSION_MAJOR || (ver_major==VERSION_MAJOR && ver_minor>VERSION_MINOR)) {
+
+ f->close();
+ memdelete(f);
+ ERR_EXPLAIN("File Format '"+itos(ver_major)+"."+itos(ver_minor)+"' is too new! Please upgrade to a a new engine version: "+p_file);
+ ERR_FAIL_V(NULL);
+
+ }
+
+ uint32_t magic_len = f->get_32();
+ Vector<char> magic;
+ magic.resize(magic_len);
+ f->get_buffer((uint8_t*)&magic[0],magic_len);
+ String magic_str;
+ magic_str.parse_utf8(&magic[0]);
+
+ print_bl("magic: "+magic_str);
+ if (magic_str!=p_magic) {
+
+ f->close();
+ memdelete(f);
+ ERR_EXPLAIN("File magic mismatch, found '"+magic_str+"' in : "+p_file);
+ ERR_FAIL_V(NULL);
+ }
+
+ print_bl("skipping 32");
+ for(int i=0;i<16;i++)
+ f->get_32(); //skip a few reserved fields
+
+ if (f->eof_reached()) {
+
+ f->close();
+ memdelete(f);
+ ERR_EXPLAIN("Premature End Of File: "+p_file);
+ ERR_FAIL_V(NULL);
+
+ }
+
+ print_bl("creating loader");
+ ObjectFormatLoaderBinary *loader = memnew( ObjectFormatLoaderBinary(f,endian_swap,use_real64) );
+ loader->local_path=p_file;
+
+ return loader;
+}
+
+void ObjectFormatLoaderInstancerBinary::get_recognized_extensions(List<String> *p_extensions) const {
+
+ p_extensions->push_back("bin");
+}
+
+
+#endif
diff --git a/core/io/object_format_binary.h b/core/io/object_format_binary.h
new file mode 100644
index 0000000000..aaf6bf357a
--- /dev/null
+++ b/core/io/object_format_binary.h
@@ -0,0 +1,158 @@
+/*************************************************************************/
+/* object_format_binary.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef OBJECT_FORMAT_BINARY_H
+#define OBJECT_FORMAT_BINARY_H
+
+#include "object_loader.h"
+#include "object_saver_base.h"
+#include "dvector.h"
+#include "core/os/file_access.h"
+
+#ifdef OLD_SCENE_FORMAT_ENABLED
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+
+class ObjectFormatSaverBinary : public ObjectFormatSaver {
+
+ String local_path;
+
+
+ Ref<OptimizedSaver> optimizer;
+
+ bool relative_paths;
+ bool bundle_resources;
+ bool skip_editor;
+ bool big_endian;
+ int bin_meta_idx;
+ FileAccess *f;
+ String magic;
+ Map<RES,int> resource_map;
+ Map<StringName,int> string_map;
+ Vector<StringName> strings;
+
+ struct SavedObject {
+
+ Variant meta;
+ String type;
+
+
+ struct SavedProperty {
+
+ int name_idx;
+ Variant value;
+ };
+
+ List<SavedProperty> properties;
+ };
+
+
+ int get_string_index(const String& p_string);
+ void save_unicode_string(const String& p_string);
+
+ List<SavedObject*> saved_objects;
+ List<SavedObject*> saved_resources;
+
+ void _pad_buffer(int p_bytes);
+ Error _save_obj(const Object *p_object,SavedObject *so);
+ void _find_resources(const Variant& p_variant);
+ void write_property(int p_idx,const Variant& p_property);
+
+
+public:
+
+ virtual Error save(const Object *p_object,const Variant &p_meta);
+
+ ObjectFormatSaverBinary(FileAccess *p_file,const String& p_magic,const String& p_local_path,uint32_t p_flags,const Ref<OptimizedSaver>& p_optimizer);
+ ~ObjectFormatSaverBinary();
+};
+
+class ObjectFormatSaverInstancerBinary : public ObjectFormatSaverInstancer {
+public:
+
+ virtual ObjectFormatSaver* instance(const String& p_file,const String& p_magic,uint32_t p_flags=0,const Ref<OptimizedSaver>& p_optimizer=Ref<OptimizedSaver>());
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+
+ virtual ~ObjectFormatSaverInstancerBinary();
+};
+
+
+
+
+/***********************************/
+/***********************************/
+/***********************************/
+/***********************************/
+
+class ObjectFormatLoaderBinary : public ObjectFormatLoader {
+
+ String local_path;
+
+ FileAccess *f;
+
+ bool endian_swap;
+ bool use_real64;
+
+ Vector<char> str_buf;
+ List<RES> resource_cache;
+
+ Map<int,StringName> string_map;
+
+ String get_unicode_string();
+ void _advance_padding(uint32_t p_len);
+
+friend class ObjectFormatLoaderInstancerBinary;
+
+
+ Error parse_property(Variant& r_v, int& r_index);
+
+public:
+
+
+ virtual Error load(Object **p_object,Variant &p_meta);
+
+ ObjectFormatLoaderBinary(FileAccess *f,bool p_endian_swap,bool p_use64);
+ virtual ~ObjectFormatLoaderBinary();
+};
+
+class ObjectFormatLoaderInstancerBinary : public ObjectFormatLoaderInstancer {
+public:
+
+ virtual ObjectFormatLoaderBinary* instance(const String& p_file,const String& p_magic);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+
+
+
+};
+
+
+
+#endif // OBJECT_FORMAT_BINARY_H
+#endif
diff --git a/core/io/object_format_xml.cpp b/core/io/object_format_xml.cpp
new file mode 100644
index 0000000000..0a8ce70d5e
--- /dev/null
+++ b/core/io/object_format_xml.cpp
@@ -0,0 +1,3190 @@
+/*************************************************************************/
+/* object_format_xml.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 XML_ENABLED
+#ifdef OLD_SCENE_FORMAT_ENABLED
+#include "object_format_xml.h"
+#include "resource.h"
+#include "io/resource_loader.h"
+#include "print_string.h"
+#include "object_type_db.h"
+#include "globals.h"
+#include "os/os.h"
+#include "version.h"
+
+void ObjectFormatSaverXML::escape(String& p_str) {
+
+ p_str=p_str.replace("&","&amp;");
+ p_str=p_str.replace("<","&gt;");
+ p_str=p_str.replace(">","&lt;");
+ p_str=p_str.replace("'","&apos;");
+ p_str=p_str.replace("\"","&quot;");
+ for (int i=1;i<32;i++) {
+
+ char chr[2]={i,0};
+ p_str=p_str.replace(chr,"&#"+String::num(i)+";");
+ }
+
+
+}
+void ObjectFormatSaverXML::write_tabs(int p_diff) {
+
+ for (int i=0;i<depth+p_diff;i++) {
+
+ f->store_8('\t');
+ }
+}
+
+void ObjectFormatSaverXML::write_string(String p_str,bool p_escape) {
+
+ /* write an UTF8 string */
+ if (p_escape)
+ escape(p_str);
+
+ f->store_string(p_str);;
+ /*
+ CharString cs=p_str.utf8();
+ const char *data=cs.get_data();
+
+ while (*data) {
+ f->store_8(*data);
+ data++;
+ }*/
+
+
+}
+
+void ObjectFormatSaverXML::enter_tag(const String& p_section,const String& p_args) {
+
+ if (p_args.length())
+ write_string("<"+p_section+" "+p_args+">",false);
+ else
+ write_string("<"+p_section+">",false);
+ depth++;
+}
+void ObjectFormatSaverXML::exit_tag(const String& p_section) {
+
+ depth--;
+ write_string("</"+p_section+">",false);
+
+}
+
+/*
+static bool _check_type(const Variant& p_property) {
+
+ if (p_property.get_type()==Variant::_RID)
+ return false;
+ if (p_property.get_type()==Variant::OBJECT) {
+ RES res = p_property;
+ if (res.is_null())
+ return false;
+ }
+
+ return true;
+}*/
+
+void ObjectFormatSaverXML::write_property(const String& p_name,const Variant& p_property,bool *r_ok) {
+
+ if (r_ok)
+ *r_ok=false;
+
+ String type;
+ String params;
+ bool oneliner=true;
+
+ switch( p_property.get_type() ) {
+
+ case Variant::NIL: type="nil"; break;
+ case Variant::BOOL: type="bool"; break;
+ case Variant::INT: type="int"; break;
+ case Variant::REAL: type="real"; break;
+ case Variant::STRING: type="string"; break;
+ case Variant::VECTOR2: type="vector2"; break;
+ case Variant::RECT2: type="rect2"; break;
+ case Variant::VECTOR3: type="vector3"; break;
+ case Variant::PLANE: type="plane"; break;
+ case Variant::_AABB: type="aabb"; break;
+ case Variant::QUAT: type="quaternion"; break;
+ case Variant::MATRIX32: type="matrix32"; break;
+ case Variant::MATRIX3: type="matrix3"; break;
+ case Variant::TRANSFORM: type="transform"; break;
+ case Variant::COLOR: type="color"; break;
+ case Variant::IMAGE: {
+ type="image";
+ Image img=p_property;
+ if (img.empty()) {
+ enter_tag(type,"name=\""+p_name+"\"");
+ exit_tag(type);
+ if (r_ok)
+ *r_ok=true;
+ return;
+ }
+ params+="encoding=\"raw\"";
+ params+=" width=\""+itos(img.get_width())+"\"";
+ params+=" height=\""+itos(img.get_height())+"\"";
+ params+=" mipmaps=\""+itos(img.get_mipmaps())+"\"";
+
+ switch(img.get_format()) {
+
+ case Image::FORMAT_GRAYSCALE: params+=" format=\"grayscale\""; break;
+ case Image::FORMAT_INTENSITY: params+=" format=\"intensity\""; break;
+ case Image::FORMAT_GRAYSCALE_ALPHA: params+=" format=\"grayscale_alpha\""; break;
+ case Image::FORMAT_RGB: params+=" format=\"rgb\""; break;
+ case Image::FORMAT_RGBA: params+=" format=\"rgba\""; break;
+ case Image::FORMAT_INDEXED : params+=" format=\"indexed\""; break;
+ case Image::FORMAT_INDEXED_ALPHA: params+=" format=\"indexed_alpha\""; break;
+ case Image::FORMAT_BC1: params+=" format=\"bc1\""; break;
+ case Image::FORMAT_BC2: params+=" format=\"bc2\""; break;
+ case Image::FORMAT_BC3: params+=" format=\"bc3\""; break;
+ case Image::FORMAT_BC4: params+=" format=\"bc4\""; break;
+ case Image::FORMAT_BC5: params+=" format=\"bc5\""; break;
+ case Image::FORMAT_CUSTOM: params+=" format=\"custom\" custom_size=\""+itos(img.get_data().size())+"\""; break;
+ default: {}
+ }
+ } break;
+ case Variant::NODE_PATH: type="node_path"; break;
+ case Variant::OBJECT: {
+ type="resource";
+ RES res = p_property;
+ if (res.is_null()) {
+ enter_tag(type,"name=\""+p_name+"\"");
+ exit_tag(type);
+ if (r_ok)
+ *r_ok=true;
+
+ return; // don't save it
+ }
+
+ params="resource_type=\""+res->get_type()+"\"";
+
+ if (res->get_path().length() && res->get_path().find("::")==-1) {
+ //external resource
+ String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path();
+ escape(path);
+ params+=" path=\""+path+"\"";
+ } else {
+
+ //internal resource
+ ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?");
+ ERR_FAIL_COND(!resource_map.has(res));
+
+ params+=" path=\"local://"+itos(resource_map[res])+"\"";
+ }
+
+ } break;
+ case Variant::INPUT_EVENT: type="input_event"; break;
+ case Variant::DICTIONARY: type="dictionary" ; oneliner=false; break;
+ case Variant::ARRAY: type="array"; params="len=\""+itos(p_property.operator Array().size())+"\""; oneliner=false; break;
+
+ case Variant::RAW_ARRAY: type="raw_array"; params="len=\""+itos(p_property.operator DVector < uint8_t >().size())+"\""; break;
+ case Variant::INT_ARRAY: type="int_array"; params="len=\""+itos(p_property.operator DVector < int >().size())+"\""; break;
+ case Variant::REAL_ARRAY: type="real_array"; params="len=\""+itos(p_property.operator DVector < real_t >().size())+"\""; break;
+ case Variant::STRING_ARRAY: type="string_array"; params="len=\""+itos(p_property.operator DVector < String >().size())+"\""; break;
+ case Variant::VECTOR2_ARRAY: type="vector2_array"; params="len=\""+itos(p_property.operator DVector < Vector2 >().size())+"\""; break;
+ case Variant::VECTOR3_ARRAY: type="vector3_array"; params="len=\""+itos(p_property.operator DVector < Vector3 >().size())+"\""; break;
+ case Variant::COLOR_ARRAY: type="color_array"; params="len=\""+itos(p_property.operator DVector < Color >().size())+"\""; break;
+ default: {
+
+ ERR_PRINT("Unknown Variant type.");
+ ERR_FAIL();
+ }
+
+ }
+
+ write_tabs();
+
+ if (p_name!="") {
+ if (params.length())
+ enter_tag(type,"name=\""+p_name+"\" "+params);
+ else
+ enter_tag(type,"name=\""+p_name+"\"");
+ } else {
+ if (params.length())
+ enter_tag(type," "+params);
+ else
+ enter_tag(type,"");
+ }
+
+ if (!oneliner)
+ write_string("\n",false);
+ else
+ write_string(" ",false);
+
+
+ switch( p_property.get_type() ) {
+
+ case Variant::NIL: {
+
+ } break;
+ case Variant::BOOL: {
+
+ write_string( p_property.operator bool() ? "True":"False" );
+ } break;
+ case Variant::INT: {
+
+ write_string( itos(p_property.operator int()) );
+ } break;
+ case Variant::REAL: {
+
+ write_string( rtos(p_property.operator real_t()) );
+ } break;
+ case Variant::STRING: {
+
+ String str=p_property;
+ escape(str);
+ str="\""+str+"\"";
+ write_string( str,false );
+ } break;
+ case Variant::VECTOR2: {
+
+ Vector2 v = p_property;
+ write_string( rtoss(v.x) +", "+rtoss(v.y) );
+ } break;
+ case Variant::RECT2: {
+
+ Rect2 aabb = p_property;
+ write_string( rtoss(aabb.pos.x) +", "+rtoss(aabb.pos.y) +", "+rtoss(aabb.size.x) +", "+rtoss(aabb.size.y) );
+
+ } break;
+ case Variant::VECTOR3: {
+
+ Vector3 v = p_property;
+ write_string( rtoss(v.x) +", "+rtoss(v.y)+", "+rtoss(v.z) );
+ } break;
+ case Variant::PLANE: {
+
+ Plane p = p_property;
+ write_string( rtoss(p.normal.x) +", "+rtoss(p.normal.y)+", "+rtoss(p.normal.z)+", "+rtoss(p.d) );
+
+ } break;
+ case Variant::_AABB: {
+
+ AABB aabb = p_property;
+ write_string( rtoss(aabb.pos.x) +", "+rtoss(aabb.pos.y) +", "+rtoss(aabb.pos.z) +", "+rtoss(aabb.size.x) +", "+rtoss(aabb.size.y) +", "+rtoss(aabb.size.z) );
+
+ } break;
+ case Variant::QUAT: {
+
+ Quat quat = p_property;
+ write_string( rtoss(quat.x)+", "+rtoss(quat.y)+", "+rtoss(quat.z)+", "+rtoss(quat.w)+", ");
+
+ } break;
+ case Variant::MATRIX32: {
+
+ String s;
+ Matrix32 m3 = p_property;
+ for (int i=0;i<3;i++) {
+ for (int j=0;j<2;j++) {
+
+ if (i!=0 || j!=0)
+ s+=", ";
+ s+=rtoss( m3.elements[i][j] );
+ }
+ }
+
+ write_string(s);
+
+ } break;
+ case Variant::MATRIX3: {
+
+ String s;
+ Matrix3 m3 = p_property;
+ for (int i=0;i<3;i++) {
+ for (int j=0;j<3;j++) {
+
+ if (i!=0 || j!=0)
+ s+=", ";
+ s+=rtoss( m3.elements[i][j] );
+ }
+ }
+
+ write_string(s);
+
+ } break;
+ case Variant::TRANSFORM: {
+
+ String s;
+ Transform t = p_property;
+ Matrix3 &m3 = t.basis;
+ for (int i=0;i<3;i++) {
+ for (int j=0;j<3;j++) {
+
+ if (i!=0 || j!=0)
+ s+=", ";
+ s+=rtoss( m3.elements[i][j] );
+ }
+ }
+
+ s=s+", "+rtoss(t.origin.x) +", "+rtoss(t.origin.y)+", "+rtoss(t.origin.z);
+
+ write_string(s);
+ } break;
+
+ // misc types
+ case Variant::COLOR: {
+
+ Color c = p_property;
+ write_string( rtoss(c.r) +", "+rtoss(c.g)+", "+rtoss(c.b)+", "+rtoss(c.a) );
+
+ } break;
+ case Variant::IMAGE: {
+
+ String s;
+ Image img = p_property;
+ DVector<uint8_t> data = img.get_data();
+ int len = data.size();
+ DVector<uint8_t>::Read r = data.read();
+ const uint8_t *ptr=r.ptr();;
+ for (int i=0;i<len;i++) {
+
+ uint8_t byte = ptr[i];
+ const char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+ char str[3]={ hex[byte>>4], hex[byte&0xF], 0};
+ s+=str;
+ }
+
+ write_string(s);
+ } break;
+ case Variant::NODE_PATH: {
+
+ String str=p_property;
+ escape(str);
+ str="\""+str+"\"";
+ write_string( str,false);
+
+ } break;
+
+ case Variant::OBJECT: {
+ /* this saver does not save resources in here
+ RES res = p_property;
+
+ if (!res.is_null()) {
+
+ String path=res->get_path();
+ if (!res->is_shared() || !path.length()) {
+ // if no path, or path is from inside a scene
+ write_object( *res );
+ }
+
+ }
+ */
+
+ } break;
+ case Variant::INPUT_EVENT: {
+
+ write_string( p_property.operator String() );
+ } break;
+ case Variant::DICTIONARY: {
+
+ Dictionary dict = p_property;
+
+
+ List<Variant> keys;
+ dict.get_key_list(&keys);
+
+ for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+ //if (!_check_type(dict[E->get()]))
+ // continue;
+
+ bool ok;
+ write_property("",E->get(),&ok);
+ ERR_CONTINUE(!ok);
+
+ write_property("",dict[E->get()],&ok);
+ if (!ok)
+ write_property("",Variant()); //at least make the file consistent..
+ }
+
+
+
+
+ } break;
+ case Variant::ARRAY: {
+
+ Array array = p_property;
+ int len=array.size();
+ for (int i=0;i<len;i++) {
+
+ write_property("",array[i]);
+
+ }
+
+ } break;
+
+ case Variant::RAW_ARRAY: {
+
+ String s;
+ DVector<uint8_t> data = p_property;
+ int len = data.size();
+ DVector<uint8_t>::Read r = data.read();
+ const uint8_t *ptr=r.ptr();;
+ for (int i=0;i<len;i++) {
+
+ uint8_t byte = ptr[i];
+ const char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+ char str[3]={ hex[byte>>4], hex[byte&0xF], 0};
+ s+=str;
+ }
+
+ write_string(s,false);
+
+ } break;
+ case Variant::INT_ARRAY: {
+
+ DVector<int> data = p_property;
+ int len = data.size();
+ DVector<int>::Read r = data.read();
+ const int *ptr=r.ptr();;
+ write_tabs();
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ write_string(", ",false);
+
+ write_string(itos(ptr[i]),false);
+ }
+
+
+
+ } break;
+ case Variant::REAL_ARRAY: {
+
+ DVector<real_t> data = p_property;
+ int len = data.size();
+ DVector<real_t>::Read r = data.read();
+ const real_t *ptr=r.ptr();;
+ write_tabs();
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ write_string(", ",false);
+ write_string(rtoss(ptr[i]),false);
+ }
+
+
+ } break;
+ case Variant::STRING_ARRAY: {
+
+ DVector<String> data = p_property;
+ int len = data.size();
+ DVector<String>::Read r = data.read();
+ const String *ptr=r.ptr();;
+ String s;
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ s+=", ";
+ String str=ptr[i];
+ escape(str);
+ s=s+"\""+str+"\"";
+ }
+
+ write_string(s,false);
+
+ } break;
+ case Variant::VECTOR2_ARRAY: {
+
+ DVector<Vector2> data = p_property;
+ int len = data.size();
+ DVector<Vector2>::Read r = data.read();
+ const Vector2 *ptr=r.ptr();;
+ write_tabs();
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ write_string(", ",false);
+ write_string(rtoss(ptr[i].x),false);
+ write_string(", "+rtoss(ptr[i].y),false);
+
+ }
+
+
+ } break;
+ case Variant::VECTOR3_ARRAY: {
+
+ DVector<Vector3> data = p_property;
+ int len = data.size();
+ DVector<Vector3>::Read r = data.read();
+ const Vector3 *ptr=r.ptr();;
+ write_tabs();
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ write_string(", ",false);
+ write_string(rtoss(ptr[i].x),false);
+ write_string(", "+rtoss(ptr[i].y),false);
+ write_string(", "+rtoss(ptr[i].z),false);
+
+ }
+
+
+ } break;
+ case Variant::COLOR_ARRAY: {
+
+ DVector<Color> data = p_property;
+ int len = data.size();
+ DVector<Color>::Read r = data.read();
+ const Color *ptr=r.ptr();;
+ write_tabs();
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ write_string(", ",false);
+
+ write_string(rtoss(ptr[i].r),false);
+ write_string(", "+rtoss(ptr[i].g),false);
+ write_string(", "+rtoss(ptr[i].b),false);
+ write_string(", "+rtoss(ptr[i].a),false);
+
+ }
+
+ } break;
+ default: {}
+
+ }
+ if (oneliner)
+ write_string(" ");
+ else
+ write_tabs(-1);
+ exit_tag(type);
+
+ write_string("\n",false);
+
+ if (r_ok)
+ *r_ok=true;
+
+}
+
+
+void ObjectFormatSaverXML::_find_resources(const Variant& p_variant) {
+
+
+ switch(p_variant.get_type()) {
+ case Variant::OBJECT: {
+
+
+
+ RES res = p_variant.operator RefPtr();
+
+ if (res.is_null())
+ return;
+
+ if (!bundle_resources && res->get_path().length() && res->get_path().find("::") == -1 )
+ return;
+
+ if (resource_map.has(res))
+ return;
+
+ List<PropertyInfo> property_list;
+
+ res->get_property_list( &property_list );
+
+ List<PropertyInfo>::Element *I=property_list.front();
+
+ while(I) {
+
+ PropertyInfo pi=I->get();
+
+ if (pi.usage&PROPERTY_USAGE_STORAGE || (bundle_resources && pi.usage&PROPERTY_USAGE_BUNDLE)) {
+
+ Variant v=res->get(I->get().name);
+ _find_resources(v);
+ }
+
+ I=I->next();
+ }
+
+ resource_map[ res ] = resource_map.size(); //saved after, so the childs it needs are available when loaded
+ saved_resources.push_back(res);
+
+ } break;
+
+ case Variant::ARRAY: {
+
+ Array varray=p_variant;
+ int len=varray.size();
+ for(int i=0;i<len;i++) {
+
+ Variant v=varray.get(i);
+ _find_resources(v);
+ }
+
+ } break;
+
+ case Variant::DICTIONARY: {
+
+ Dictionary d=p_variant;
+ List<Variant> keys;
+ d.get_key_list(&keys);
+ for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+ Variant v = d[E->get()];
+ _find_resources(v);
+ }
+ } break;
+ default: {}
+ }
+
+}
+
+
+
+Error ObjectFormatSaverXML::save(const Object *p_object,const Variant &p_meta) {
+
+ ERR_FAIL_COND_V(!f,ERR_UNCONFIGURED);
+ ERR_EXPLAIN("write_object should supply either an object, a meta, or both");
+ ERR_FAIL_COND_V(!p_object && p_meta.get_type()==Variant::NIL, ERR_INVALID_PARAMETER);
+
+ SavedObject *so = memnew( SavedObject );
+
+ if (p_object)
+ so->type=p_object->get_type();
+
+ _find_resources(p_meta);
+ so->meta=p_meta;
+
+ if (p_object) {
+
+
+ if (optimizer.is_valid()) {
+ //use optimizer
+
+ List<OptimizedSaver::Property> props;
+ optimizer->get_property_list(p_object,&props);
+
+ for(List<OptimizedSaver::Property>::Element *E=props.front();E;E=E->next()) {
+
+ if (skip_editor && String(E->get().name).begins_with("__editor"))
+ continue;
+ _find_resources(E->get().value);
+ SavedObject::SavedProperty sp;
+ sp.name=E->get().name;
+ sp.value=E->get().value;
+ so->properties.push_back(sp);
+ }
+
+ } else {
+ //use classic way
+ List<PropertyInfo> property_list;
+ p_object->get_property_list( &property_list );
+
+ for(List<PropertyInfo>::Element *E=property_list.front();E;E=E->next()) {
+
+ if (skip_editor && E->get().name.begins_with("__editor"))
+ continue;
+ if (E->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && E->get().usage&PROPERTY_USAGE_BUNDLE)) {
+
+ SavedObject::SavedProperty sp;
+ sp.name=E->get().name;
+ sp.value = p_object->get(E->get().name);
+ _find_resources(sp.value);
+ so->properties.push_back(sp);
+ }
+ }
+ }
+
+ }
+
+ saved_objects.push_back(so);
+
+ return OK;
+}
+
+ObjectFormatSaverXML::ObjectFormatSaverXML(FileAccess *p_file,const String& p_magic,const String& p_local_path,uint32_t p_flags,const Ref<OptimizedSaver>& p_optimizer) {
+
+ optimizer=p_optimizer;
+ relative_paths=p_flags&ObjectSaver::FLAG_RELATIVE_PATHS;
+ skip_editor=p_flags&ObjectSaver::FLAG_OMIT_EDITOR_PROPERTIES;
+ bundle_resources=p_flags&ObjectSaver::FLAG_BUNDLE_RESOURCES;
+ f=p_file; // should be already opened
+ depth=0;
+ local_path=p_local_path;
+ magic=p_magic;
+}
+ObjectFormatSaverXML::~ObjectFormatSaverXML() {
+
+ write_string("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>",false); //no escape
+ write_string("\n",false);
+ enter_tag("object_file","magic=\""+magic+"\" "+"version=\""+itos(VERSION_MAJOR)+"."+itos(VERSION_MINOR)+"\" version_name=\""+VERSION_FULL_NAME+"\"");
+ write_string("\n",false);
+
+ // save resources
+
+ for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {
+
+ RES res = E->get();
+ ERR_CONTINUE(!resource_map.has(res));
+
+ write_tabs();
+ if (res->get_path().length() && res->get_path().find("::") == -1 )
+ enter_tag("resource","type=\""+res->get_type()+"\" path=\""+res->get_path()+"\""); //bundled
+ else
+ enter_tag("resource","type=\""+res->get_type()+"\" path=\"local://"+itos(resource_map[res])+"\"");
+
+ if (optimizer.is_valid()) {
+
+ List<OptimizedSaver::Property> props;
+ optimizer->get_property_list(res.ptr(),&props);
+
+ for(List<OptimizedSaver::Property>::Element *E=props.front();E;E=E->next()) {
+
+ if (skip_editor && String(E->get().name).begins_with("__editor"))
+ continue;
+
+ write_property(E->get().name,E->get().value);
+ }
+
+
+ } else {
+
+ List<PropertyInfo> property_list;
+ res->get_property_list(&property_list);
+ for(List<PropertyInfo>::Element *PE = property_list.front();PE;PE=PE->next()) {
+
+
+ if (skip_editor && PE->get().name.begins_with("__editor"))
+ continue;
+
+ if (PE->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && PE->get().usage&PROPERTY_USAGE_BUNDLE)) {
+
+ String name = PE->get().name;
+ Variant value = res->get(name);
+ write_property(name,value);
+ }
+
+
+ }
+
+ }
+ write_tabs(-1);
+ exit_tag("resource");
+ write_string("\n",false);
+ }
+
+ if (!saved_objects.empty()) {
+
+
+ for(List<SavedObject*>::Element *E=saved_objects.front();E;E=E->next()) {
+
+ SavedObject *so = E->get();
+
+
+
+ write_tabs();
+ if (so->type!="")
+ enter_tag("object","type=\""+so->type+"\"");
+ else
+ enter_tag("object");
+ write_string("\n",false);
+
+ if (so->meta.get_type()!=Variant::NIL) {
+
+ write_property("__xml_meta__",so->meta);
+
+ }
+
+ List<SavedObject::SavedProperty>::Element *SE = so->properties.front();
+
+ while(SE) {
+
+ write_property(SE->get().name,SE->get().value);
+ SE=SE->next();
+ }
+
+
+ write_tabs(-1);
+ exit_tag("object");
+ write_string("\n",false);
+ memdelete(so); //no longer needed
+ }
+
+
+ } else {
+
+ WARN_PRINT("File contains no saved objects.");
+ }
+
+ exit_tag("object_file");
+ f->close();
+ memdelete(f);
+}
+
+
+ObjectFormatSaver* ObjectFormatSaverInstancerXML::instance(const String& p_file,const String& p_magic,uint32_t p_flags,const Ref<OptimizedSaver>& p_optimizer) {
+
+ Error err;
+ FileAccess *f = FileAccess::open(p_file, FileAccess::WRITE,&err);
+
+ ERR_FAIL_COND_V( err, NULL );
+ String local_path = Globals::get_singleton()->localize_path(p_file);
+
+ return memnew( ObjectFormatSaverXML( f, p_magic,local_path,p_flags,p_optimizer ) );
+}
+
+void ObjectFormatSaverInstancerXML::get_recognized_extensions(List<String> *p_extensions) const {
+
+ p_extensions->push_back("xml");
+}
+
+
+ObjectFormatSaverInstancerXML::~ObjectFormatSaverInstancerXML() {
+
+
+}
+
+/************************************************/
+/************************************************/
+/************************************************/
+/************************************************/
+/************************************************/
+
+
+
+#ifdef OPTIMIZED_XML_LOADER
+
+#define IS_FLOAT_CHAR(m_c) \
+ ((m_c>='0' && m_c<='9') || m_c=='e' || m_c=='-' || m_c=='+' || m_c=='.')
+
+#define XML_FAIL(m_cond,m_err) \
+ if (m_cond) {\
+ ERR_EXPLAIN(local_path+":"+itos(parser->get_current_line())+": "+String(m_err));\
+ ERR_FAIL_COND_V( m_cond, ERR_FILE_CORRUPT );\
+ }
+
+
+Error ObjectFormatLoaderXML::_parse_property(Variant& r_v,String& r_name) {
+
+ XML_FAIL( parser->is_empty(), "unexpected empty tag");
+
+ String type=parser->get_node_name();
+ String name=parser->get_attribute_value_safe("name");
+
+ r_v=Variant();
+ r_name=name;
+
+ if (type=="dictionary") {
+
+ Dictionary d;
+ int reading=0;
+ Variant key;
+ while(parser->read()==OK) {
+
+ if (parser->get_node_type()==XMLParser::NODE_ELEMENT) {
+ Error err;
+ String tagname;
+
+ if (reading==0) {
+
+ err=_parse_property(key,tagname);
+ XML_FAIL( err,"error parsing dictionary key: "+name);
+ reading++;
+ } else {
+
+ reading=0;
+ Variant value;
+ err=_parse_property(value,tagname);
+ XML_FAIL( err,"error parsing dictionary value: "+name);
+ d[key]=value;
+ }
+
+ } else if (parser->get_node_type()==XMLParser::NODE_ELEMENT_END && parser->get_node_name()=="dictionary") {
+ r_v=d;
+ return OK;
+ }
+ }
+
+
+ XML_FAIL( true, "unexpected end of file while reading dictionary: "+name);
+
+ } else if (type=="array") {
+
+ XML_FAIL( !parser->has_attribute("len"), "array missing 'len' attribute");
+
+ int len=parser->get_attribute_value("len").to_int();
+
+ Array array;
+ array.resize(len);
+
+
+ Variant v;
+ String tagname;
+ int idx=0;
+
+
+ while(parser->read()==OK) {
+
+ if (parser->get_node_type()==XMLParser::NODE_ELEMENT) {
+
+ XML_FAIL( idx >= len, "array size mismatch (too many elements)");
+ Error err;
+ String tagname;
+ Variant key;
+
+ err=_parse_property(key,tagname);
+ XML_FAIL( err,"error parsing element of array: "+name);
+ array[idx]=key;
+ idx++;
+
+
+ } else if (parser->get_node_type()==XMLParser::NODE_ELEMENT_END && parser->get_node_name()=="array") {
+
+ XML_FAIL( idx != len, "array size mismatch (not "+itos(len)+"):"+name);
+ r_v=array;
+ return OK;
+ }
+ }
+
+ XML_FAIL( true, "unexpected end of file while reading dictionary: "+name);
+
+ } else if (type=="resource") {
+
+
+ XML_FAIL(!parser->has_attribute("path"),"resource property has no 'path' set (embedding not supported).")
+
+ String path=parser->get_attribute_value("path");
+ String hint = parser->get_attribute_value_safe("resource_type");
+
+ if (path.begins_with("local://"))
+ path=path.replace("local://",local_path+"::");
+ else if (path.find("://")==-1 && path.is_rel_path()) {
+ // path is relative to file being loaded, so convert to a resource path
+ path=Globals::get_singleton()->localize_path(local_path.get_base_dir()+"/"+path);
+
+ }
+
+ //take advantage of the resource loader cache. The resource is cached on it, even if
+ RES res=ResourceLoader::load(path,hint);
+
+
+ if (res.is_null()) {
+
+ WARN_PRINT(String("Couldn't load resource: "+path).ascii().get_data());
+ }
+
+ r_v=res.get_ref_ptr();
+
+ } else if (type=="image") {
+
+ if (parser->has_attribute("encoding")) { //there is image data
+
+ String encoding=parser->get_attribute_value("encoding");
+
+ if (encoding=="raw") {
+
+ //raw image (bytes)
+
+ XML_FAIL( !parser->has_attribute("width"), "missing attribute in raw encoding: 'width'.");
+ XML_FAIL( !parser->has_attribute("height"), "missing attribute in raw encoding: 'height'.");
+ XML_FAIL( !parser->has_attribute("format"), "missing attribute in raw encoding: 'format'.");
+
+ String format = parser->get_attribute_value("format");
+ String width = parser->get_attribute_value("width");
+ String height = parser->get_attribute_value("height");
+
+ Image::Format imgformat;
+ int chans=0;
+ int pal=0;
+
+ if (format=="grayscale") {
+ imgformat=Image::FORMAT_GRAYSCALE;
+ chans=1;
+ } else if (format=="intensity") {
+ imgformat=Image::FORMAT_INTENSITY;
+ chans=1;
+ } else if (format=="grayscale_alpha") {
+ imgformat=Image::FORMAT_GRAYSCALE_ALPHA;
+ chans=2;
+ } else if (format=="rgb") {
+ imgformat=Image::FORMAT_RGB;
+ chans=3;
+ } else if (format=="rgba") {
+ imgformat=Image::FORMAT_RGBA;
+ chans=4;
+ } else if (format=="indexed") {
+ imgformat=Image::FORMAT_INDEXED;
+ chans=1;
+ pal=256*3;
+ } else if (format=="indexed_alpha") {
+ imgformat=Image::FORMAT_INDEXED_ALPHA;
+ chans=1;
+ pal=256*4;
+ } else {
+
+ XML_FAIL(true, "invalid format for image: "+format);
+
+ }
+
+ XML_FAIL( chans==0, "invalid number of color channels in image (0).");
+
+ int w=width.to_int();
+ int h=height.to_int();
+
+ if (w == 0 && w == 0) { //epmty, don't even bother
+ //r_v = Image(w, h, imgformat);
+ r_v=Image();
+ return OK;
+ } else {
+
+ //decode hexa
+
+ DVector<uint8_t> pixels;
+ pixels.resize(chans*w*h+pal);
+ int pixels_size=pixels.size();
+ XML_FAIL( pixels_size==0, "corrupt");
+
+ ERR_FAIL_COND_V(pixels_size==0,ERR_FILE_CORRUPT);
+ DVector<uint8_t>::Write wr=pixels.write();
+ uint8_t *bytes=wr.ptr();
+
+ XML_FAIL( parser->read()!=OK, "error reading" );
+ XML_FAIL( parser->get_node_type()!=XMLParser::NODE_TEXT, "expected text!");
+
+ String text = parser->get_node_data().strip_edges();
+ XML_FAIL( text.length()/2 != pixels_size, "unexpected image data size" );
+
+ for(int i=0;i<pixels_size*2;i++) {
+
+ uint8_t byte;
+ CharType c=text[i];
+
+ if ( (c>='0' && c<='9') || (c>='A' && c<='F') || (c>='a' && c<='f') ) {
+
+ if (i&1) {
+
+ byte|=HEX2CHR(c);
+ bytes[i>>1]=byte;
+ } else {
+
+ byte=HEX2CHR(c)<<4;
+ }
+
+
+ }
+ }
+
+ wr=DVector<uint8_t>::Write();
+ r_v=Image(w,h,imgformat,pixels);
+ }
+ }
+
+ } else {
+ r_v=Image(); // empty image, since no encoding defined
+ }
+
+ } else if (type=="raw_array") {
+
+ XML_FAIL( !parser->has_attribute("len"), "array missing 'len' attribute");
+
+ int len=parser->get_attribute_value("len").to_int();
+ if (len>0) {
+
+ XML_FAIL( parser->read()!=OK, "error reading" );
+ XML_FAIL( parser->get_node_type()!=XMLParser::NODE_TEXT, "expected text!");
+ String text = parser->get_node_data();
+
+ XML_FAIL( text.length() != len*2, "raw array length mismatch" );
+
+ DVector<uint8_t> bytes;
+ bytes.resize(len);
+ DVector<uint8_t>::Write w=bytes.write();
+ uint8_t *bytesptr=w.ptr();
+
+
+ for(int i=0;i<len*2;i++) {
+
+ uint8_t byte;
+ CharType c=text[i];
+
+ if ( (c>='0' && c<='9') || (c>='A' && c<='F') || (c>='a' && c<='f') ) {
+
+ if (i&1) {
+
+ byte|=HEX2CHR(c);
+ bytesptr[i>>1]=byte;
+ } else {
+
+ byte=HEX2CHR(c)<<4;
+ }
+ }
+ }
+
+ w=DVector<uint8_t>::Write();
+ r_v=bytes;
+ }
+
+ } else if (type=="int_array") {
+
+ int len=parser->get_attribute_value("len").to_int();
+
+ if (len>0) {
+
+ XML_FAIL( parser->read()!=OK, "error reading" );
+ XML_FAIL( parser->get_node_type()!=XMLParser::NODE_TEXT, "expected text!");
+ String text = parser->get_node_data();
+
+ const CharType *c=text.c_str();
+ DVector<int> varray;
+ varray.resize(len);
+ DVector<int>::Write w = varray.write();
+
+ int idx=0;
+ const CharType *from=c-1;
+
+ while(*c) {
+
+ bool ischar = (*c >='0' && *c<='9') || *c=='+' || *c=='-';
+ if (!ischar) {
+
+ if (int64_t(c-from)>1) {
+
+ int i = String::to_int(from+1,int64_t(c-from));
+ w[idx++]=i;
+ }
+
+ from=c;
+ } else {
+
+ XML_FAIL( idx >= len, "array too big");
+ }
+
+ c++;
+ }
+
+ XML_FAIL( idx != len, "array size mismatch");
+
+ w = varray.write();
+ r_v=varray;
+ }
+
+
+
+ } else if (type=="real_array") {
+
+ int len=parser->get_attribute_value("len").to_int();
+
+ if (len>0) {
+
+ XML_FAIL( parser->read()!=OK, "error reading" );
+ XML_FAIL( parser->get_node_type()!=XMLParser::NODE_TEXT, "expected text!");
+ String text = parser->get_node_data();
+
+ const CharType *c=text.c_str();
+ DVector<real_t> varray;
+ varray.resize(len);
+ DVector<real_t>::Write w = varray.write();
+
+ int idx=0;
+ const CharType *from=c-1;
+
+ while(*c) {
+
+ bool ischar = IS_FLOAT_CHAR((*c));
+ if (!ischar) {
+
+ if (int64_t(c-from)>1) {
+
+ real_t f = String::to_double(from+1,int64_t(c-from));
+ w[idx++]=f;
+ }
+
+ from=c;
+ } else {
+
+ XML_FAIL( idx >= len, "array too big");
+ }
+
+ c++;
+ }
+
+ XML_FAIL( idx != len, "array size mismatch");
+
+ w = varray.write();
+ r_v=varray;
+ }
+
+ } else if (type=="string_array") {
+
+
+ // this is invalid xml, and will have to be fixed at some point..
+
+ int len=parser->get_attribute_value("len").to_int();
+
+ if (len>0) {
+
+ XML_FAIL( parser->read()!=OK, "error reading" );
+ XML_FAIL( parser->get_node_type()!=XMLParser::NODE_TEXT, "expected text!");
+ String text = parser->get_node_data();
+
+ const CharType *c=text.c_str();
+ DVector<String> sarray;
+ sarray.resize(len);
+ DVector<String>::Write w = sarray.write();
+
+
+ bool inside=false;
+ const CharType *from=c;
+ int idx=0;
+
+ while(*c) {
+
+ if (inside) {
+
+ if (*c == '"') {
+ inside=false;
+ String s = String(from,int64_t(c-from));
+ w[idx]=s;
+ idx++;
+ }
+ } else {
+
+ if (*c == '"') {
+ inside=true;
+ from=c+1;
+ XML_FAIL( idx>=len, "string array is too big!!: "+name);
+ }
+ }
+
+ c++;
+ }
+
+ XML_FAIL( inside, "unterminated string array: "+name);
+ XML_FAIL( len != idx, "string array size mismatch: "+name);
+
+ w = DVector<String>::Write();
+
+ r_v=sarray;
+
+ }
+ } else if (type=="vector3_array") {
+
+ int len=parser->get_attribute_value("len").to_int();
+
+ if (len>0) {
+
+ XML_FAIL( parser->read()!=OK, "error reading" );
+ XML_FAIL( parser->get_node_type()!=XMLParser::NODE_TEXT, "expected text!");
+ String text = parser->get_node_data();
+
+ const CharType *c=text.c_str();
+ DVector<Vector3> varray;
+ varray.resize(len);
+ DVector<Vector3>::Write w = varray.write();
+
+ int idx=0;
+ int sidx=0;
+ Vector3 v;
+ const CharType *from=c-1;
+
+ while(*c) {
+
+ bool ischar = IS_FLOAT_CHAR((*c));
+ if (!ischar) {
+
+ if (int64_t(c-from)>1) {
+
+ real_t f = String::to_double(from+1,int64_t(c-from));
+ v[sidx++]=f;
+ if (sidx==3) {
+ w[idx++]=v;
+ sidx=0;
+
+ }
+ }
+
+ from=c;
+ } else {
+
+ XML_FAIL( idx >= len, "array too big");
+ }
+
+ c++;
+ }
+
+ XML_FAIL( idx != len, "array size mismatch");
+
+ w = varray.write();
+ r_v=varray;
+ }
+
+ } else if (type=="color_array") {
+
+ int len=parser->get_attribute_value("len").to_int();
+
+ if (len>0) {
+
+ XML_FAIL( parser->read()!=OK, "error reading" );
+ XML_FAIL( parser->get_node_type()!=XMLParser::NODE_TEXT, "expected text!");
+ String text = parser->get_node_data();
+
+ const CharType *c=text.c_str();
+ DVector<Color> carray;
+ carray.resize(len);
+ DVector<Color>::Write w = carray.write();
+
+ int idx=0;
+ int sidx=0;
+ Color v;
+ const CharType *from=c-1;
+
+ while(*c) {
+
+ bool ischar = IS_FLOAT_CHAR((*c));
+ if (!ischar) {
+
+ if (int64_t(c-from)>1) {
+
+ real_t f = String::to_double(from+1,int64_t(c-from));
+ v[sidx++]=f;
+ if (sidx==4) {
+ w[idx++]=v;
+ sidx=0;
+
+ }
+ }
+
+ from=c;
+ } else {
+
+ XML_FAIL( idx >= len, "array too big");
+ }
+
+ c++;
+ }
+
+ XML_FAIL( idx != len, "array size mismatch");
+
+ w = carray.write();
+ r_v=carray;
+ }
+ } else {
+ // simple string parsing code
+ XML_FAIL( parser->read()!=OK, "can't read data" );
+
+ String data=parser->get_node_data();
+ data=data.strip_edges();
+
+ if (type=="nil") {
+ // uh do nothing
+
+ } else if (type=="bool") {
+ // uh do nothing
+ if (data.nocasecmp_to("true")==0 || data.to_int()!=0)
+ r_v=true;
+ else
+ r_v=false;
+
+ } else if (type=="int") {
+
+ r_v=data.to_int();
+ } else if (type=="real") {
+
+ r_v=data.to_double();
+ } else if (type=="string") {
+
+ String str=data;
+ str=str.substr(1,str.length()-2);
+ r_v=str;
+ } else if (type=="vector3") {
+
+ r_v=Vector3(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double(),
+ data.get_slice(",",2).to_double()
+ );
+
+ } else if (type=="vector2") {
+
+
+ r_v=Vector2(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double()
+ );
+
+ } else if (type=="plane") {
+
+ r_v=Plane(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double(),
+ data.get_slice(",",2).to_double(),
+ data.get_slice(",",3).to_double()
+ );
+
+ } else if (type=="quaternion") {
+
+ r_v=Quat(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double(),
+ data.get_slice(",",2).to_double(),
+ data.get_slice(",",3).to_double()
+ );
+
+ } else if (type=="rect2") {
+
+ r_v=Rect2(
+ Vector2(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double()
+ ),
+ Vector2(
+ data.get_slice(",",2).to_double(),
+ data.get_slice(",",3).to_double()
+ )
+ );
+
+
+ } else if (type=="aabb") {
+
+ r_v=AABB(
+ Vector3(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double(),
+ data.get_slice(",",2).to_double()
+ ),
+ Vector3(
+ data.get_slice(",",3).to_double(),
+ data.get_slice(",",4).to_double(),
+ data.get_slice(",",5).to_double()
+ )
+ );
+
+
+ } else if (type=="matrix3") {
+
+ Matrix3 m3;
+ for (int i=0;i<3;i++) {
+ for (int j=0;j<3;j++) {
+ m3.elements[i][j]=data.get_slice(",",i*3+j).to_double();
+ }
+ }
+ r_v=m3;
+
+ } else if (type=="transform") {
+
+ Transform tr;
+ for (int i=0;i<3;i++) {
+ for (int j=0;j<3;j++) {
+ tr.basis.elements[i][j]=data.get_slice(",",i*3+j).to_double();
+ }
+
+ }
+ tr.origin=Vector3(
+ data.get_slice(",",9).to_double(),
+ data.get_slice(",",10).to_double(),
+ data.get_slice(",",11).to_double()
+ );
+ r_v=tr;
+
+ } else if (type=="color") {
+
+ r_v=Color(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double(),
+ data.get_slice(",",2).to_double(),
+ data.get_slice(",",3).to_double()
+ );
+
+ } else if (type=="node_path") {
+
+ String str=data;
+ str=str.substr(1,str.length()-2);
+ r_v=NodePath( str );
+
+ } else if (type=="input_event") {
+
+ // ?
+ } else {
+
+ XML_FAIL(true,"unrecognized property tag: "+type);
+ }
+ }
+
+ _close_tag(type);
+
+ return OK;
+}
+
+
+
+
+Error ObjectFormatLoaderXML::_close_tag(const String& p_tag) {
+
+ int c=1;
+
+ while(parser->read()==OK) {
+
+
+ if (parser->get_node_type()==XMLParser::NODE_ELEMENT && parser->get_node_name()==p_tag) {
+ c++;
+ } else if (parser->get_node_type()==XMLParser::NODE_ELEMENT_END && parser->get_node_name()==p_tag) {
+ c--;
+
+ if (c==0)
+ return OK;
+ }
+
+ }
+
+ return ERR_FILE_CORRUPT;
+}
+
+Error ObjectFormatLoaderXML::load(Object **p_object,Variant &p_meta) {
+
+ *p_object=NULL;
+ p_meta=Variant();
+
+ while(parser->read()==OK) {
+
+ if (parser->get_node_type()==XMLParser::NODE_ELEMENT) {
+
+ String name = parser->get_node_name();
+
+
+ XML_FAIL( !parser->has_attribute("type"), "'type' attribute missing." );
+ String type = parser->get_attribute_value("type");
+
+
+ Object *obj=NULL;
+ Ref<Resource> resource;
+ if (name=="resource") {
+
+ XML_FAIL( !parser->has_attribute("path"), "'path' attribute missing." );
+ String path = parser->get_attribute_value("path");
+
+ XML_FAIL(!path.begins_with("local://"),"path does not begin with 'local://'");
+
+
+ path=path.replace("local://",local_path+"::");
+
+ if (ResourceCache::has(path)) {
+ Error err = _close_tag(name);
+ XML_FAIL( err, "error skipping resource.");
+ continue; //it's a resource, and it's already loaded
+
+ }
+
+ obj = ObjectTypeDB::instance(type);
+ XML_FAIL(!obj,"couldn't instance object of type: '"+type+"'");
+
+ Resource *r = obj->cast_to<Resource>();
+ XML_FAIL(!obj,"object isn't of type Resource: '"+type+"'");
+
+ resource = RES( r );
+ r->set_path(path);
+
+
+ } else if (name=="object") {
+
+
+ if (ObjectTypeDB::can_instance(type)) {
+ obj = ObjectTypeDB::instance(type);
+ XML_FAIL(!obj,"couldn't instance object of type: '"+type+"'");
+ } else {
+
+ _close_tag(name);
+ return ERR_SKIP;
+ };
+ } else {
+ XML_FAIL(true,"Unknown main tag: "+parser->get_node_name());
+ }
+
+ //load properties
+
+ while (parser->read()==OK) {
+
+ if (parser->get_node_type()==XMLParser::NODE_ELEMENT_END && parser->get_node_name()==name)
+ break;
+ else if (parser->get_node_type()==XMLParser::NODE_ELEMENT) {
+
+ String name;
+ Variant v;
+ Error err;
+ err = _parse_property(v,name);
+ XML_FAIL(err,"Error parsing property: "+name);
+
+ if (resource.is_null() && name=="__xml_meta__") {
+
+ p_meta=v;
+ continue;
+ } else {
+
+ XML_FAIL( !obj, "Normal property found in meta object");
+
+ }
+
+ obj->set(name,v);
+
+
+ }
+ }
+
+
+ if (!obj) {
+ *p_object=NULL;
+ return OK; // it was a meta object
+ }
+
+ if (resource.is_null()) {
+ //regular object
+ *p_object=obj;
+ return OK;
+ } else {
+
+ resource_cache.push_back(resource); //keep it in mem until finished loading and load next
+ }
+
+
+ } else if (parser->get_node_type()==XMLParser::NODE_ELEMENT_END && parser->get_node_name()=="object_file")
+ return ERR_FILE_EOF;
+ }
+
+ return OK; //never reach anyway
+}
+
+ObjectFormatLoaderXML* ObjectFormatLoaderInstancerXML::instance(const String& p_file,const String& p_magic) {
+
+ Ref<XMLParser> parser = memnew( XMLParser );
+
+ Error err = parser->open(p_file);
+ ERR_FAIL_COND_V(err,NULL);
+
+ ObjectFormatLoaderXML *loader = memnew( ObjectFormatLoaderXML );
+
+ loader->parser=parser;
+ loader->local_path = Globals::get_singleton()->localize_path(p_file);
+
+ while(parser->read()==OK) {
+
+ if (parser->get_node_type()==XMLParser::NODE_ELEMENT && parser->get_node_name()=="object_file") {
+
+ ERR_FAIL_COND_V( parser->is_empty(), NULL );
+
+ String version = parser->get_attribute_value_safe("version");
+ String magic = parser->get_attribute_value_safe("MAGIC");
+
+ if (version.get_slice_count(".")!=2) {
+
+ ERR_EXPLAIN("Invalid Version String '"+version+"'' in file: "+p_file);
+ ERR_FAIL_V(NULL);
+ }
+
+ int major = version.get_slice(".",0).to_int();
+ int minor = version.get_slice(".",1).to_int();
+
+ if (major>VERSION_MAJOR || (major==VERSION_MAJOR && minor>VERSION_MINOR)) {
+
+ ERR_EXPLAIN("File Format '"+version+"' is too new! Please upgrade to a a new engine version: "+p_file);
+ ERR_FAIL_V(NULL);
+
+ }
+
+ return loader;
+ }
+
+ }
+
+ ERR_EXPLAIN("No data found in file!");
+ ERR_FAIL_V(NULL);
+}
+
+void ObjectFormatLoaderInstancerXML::get_recognized_extensions(List<String> *p_extensions) const {
+
+ p_extensions->push_back("xml");
+}
+
+
+
+#else
+
+ObjectFormatLoaderXML::Tag* ObjectFormatLoaderXML::parse_tag(bool *r_exit) {
+
+
+ while(get_char()!='<' && !f->eof_reached()) {}
+ if (f->eof_reached())
+ return NULL;
+
+ Tag tag;
+ bool exit=false;
+ if (r_exit)
+ *r_exit=false;
+
+ bool complete=false;
+ while(!f->eof_reached()) {
+
+ CharType c=get_char();
+ if (c<33 && tag.name.length() && !exit) {
+ break;
+ } else if (c=='>') {
+ complete=true;
+ break;
+ } else if (c=='/') {
+ exit=true;
+ } else {
+ tag.name+=c;
+ }
+ }
+
+ if (f->eof_reached())
+ return NULL;
+
+ if (exit) {
+ if (!tag_stack.size()) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Unmatched exit tag </"+tag.name+">");
+ ERR_FAIL_COND_V(!tag_stack.size(),NULL);
+ }
+
+ if (tag_stack.back()->get().name!=tag.name) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Mismatched exit tag. Got </"+tag.name+">, expected </"+tag_stack.back()->get().name+">");
+ ERR_FAIL_COND_V(tag_stack.back()->get().name!=tag.name,NULL);
+ }
+
+ if (!complete) {
+ while(get_char()!='>' && !f->eof_reached()) {}
+ if (f->eof_reached())
+ return NULL;
+ }
+
+ if (r_exit)
+ *r_exit=true;
+
+ tag_stack.pop_back();
+ return NULL;
+
+ }
+
+ if (!complete) {
+ String name;
+ String value;
+ bool reading_value=false;
+
+ while(!f->eof_reached()) {
+
+ CharType c=get_char();
+ if (c=='>') {
+ if (value.length()) {
+
+ tag.args[name]=value;
+ }
+ break;
+
+ } else if ( ((!reading_value && (c<33)) || c=='=' || c=='"') && tag.name.length()) {
+
+ if (!reading_value && name.length()) {
+
+ reading_value=true;
+ } else if (reading_value && value.length()) {
+
+ tag.args[name]=value;
+ name="";
+ value="";
+ reading_value=false;
+ }
+
+ } else if (reading_value) {
+
+ value+=c;
+ } else {
+
+ name+=c;
+ }
+ }
+
+ if (f->eof_reached())
+ return NULL;
+ }
+
+ tag_stack.push_back(tag);
+
+ return &tag_stack.back()->get();
+}
+
+
+Error ObjectFormatLoaderXML::close_tag(const String& p_name) {
+
+ int level=0;
+ bool inside_tag=false;
+
+ while(true) {
+
+ if (f->eof_reached()) {
+
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": EOF found while attempting to find </"+p_name+">");
+ ERR_FAIL_COND_V( f->eof_reached(), ERR_FILE_CORRUPT );
+ }
+
+ uint8_t c = get_char();
+
+ if (c == '<') {
+
+ if (inside_tag) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Malformed XML. Already inside Tag.");
+ ERR_FAIL_COND_V(inside_tag,ERR_FILE_CORRUPT);
+ }
+ inside_tag=true;
+ c = get_char();
+ if (c == '/') {
+
+ --level;
+ } else {
+
+ ++level;
+ };
+ } else if (c == '>') {
+
+ if (!inside_tag) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Malformed XML. Already outside Tag");
+ ERR_FAIL_COND_V(!inside_tag,ERR_FILE_CORRUPT);
+ }
+ inside_tag=false;
+ if (level == -1) {
+ tag_stack.pop_back();
+ return OK;
+ };
+ };
+ }
+
+ return OK;
+}
+
+void ObjectFormatLoaderXML::unquote(String& p_str) {
+
+ p_str=p_str.strip_edges();
+ p_str=p_str.replace("\"","");
+ p_str=p_str.replace("&gt;","<");
+ p_str=p_str.replace("&lt;",">");
+ p_str=p_str.replace("&apos;","'");
+ p_str=p_str.replace("&quot;","\"");
+ for (int i=1;i<32;i++) {
+
+ char chr[2]={i,0};
+ p_str=p_str.replace("&#"+String::num(i)+";",chr);
+ }
+ p_str=p_str.replace("&amp;","&");
+
+ //p_str.parse_utf8( p_str.ascii(true).get_data() );
+
+}
+
+Error ObjectFormatLoaderXML::goto_end_of_tag() {
+
+ uint8_t c;
+ while(true) {
+
+ c=get_char();
+ if (c=='>') //closetag
+ break;
+ if (f->eof_reached()) {
+
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": EOF found while attempting to find close tag.");
+ ERR_FAIL_COND_V( f->eof_reached(), ERR_FILE_CORRUPT );
+ }
+
+ }
+ tag_stack.pop_back();
+
+ return OK;
+}
+
+
+Error ObjectFormatLoaderXML::parse_property_data(String &r_data) {
+
+ r_data="";
+ CharString cs;
+ while(true) {
+
+ CharType c=get_char();
+ if (c=='<')
+ break;
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+ cs.push_back(c);
+ }
+
+ cs.push_back(0);
+
+ r_data.parse_utf8(cs.get_data());
+
+ while(get_char()!='>' && !f->eof_reached()) {}
+ if (f->eof_reached()) {
+
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Malformed XML.");
+ ERR_FAIL_COND_V( f->eof_reached(), ERR_FILE_CORRUPT );
+ }
+
+ r_data=r_data.strip_edges();
+ tag_stack.pop_back();
+
+ return OK;
+}
+
+
+Error ObjectFormatLoaderXML::_parse_array_element(Vector<char> &buff,bool p_number_only,FileAccess *f,bool *end) {
+
+ if (buff.empty())
+ buff.resize(32); // optimize
+
+ int buff_max=buff.size();
+ int buff_size=0;
+ *end=false;
+ char *buffptr=&buff[0];
+ bool found=false;
+ bool quoted=false;
+
+ while(true) {
+
+ char c=get_char();
+
+ if (c==0) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": File corrupt (zero found).");
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ } else if (c=='"') {
+ quoted=!quoted;
+ } else if ((!quoted && ((p_number_only && c<33) || c==',')) || c=='<') {
+
+
+ if (c=='<') {
+ *end=true;
+ break;
+ }
+ if (c<32 && f->eof_reached()) {
+ *end=true;
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": File corrupt (unexpected EOF).");
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ }
+
+ if (found)
+ break;
+
+ } else {
+
+ found=true;
+ if (buff_size>=buff_max) {
+
+ buff_max++;
+ buff.resize(buff_max);
+
+ }
+
+ buffptr[buff_size]=c;
+ buff_size++;
+ }
+ }
+
+ if (buff_size>=buff_max) {
+
+ buff_max++;
+ buff.resize(buff_max);
+
+ }
+
+ buff[buff_size]=0;
+ buff_size++;
+
+ return OK;
+}
+
+Error ObjectFormatLoaderXML::parse_property(Variant& r_v, String &r_name) {
+
+ bool exit;
+ Tag *tag = parse_tag(&exit);
+
+ if (!tag) {
+ if (exit) // shouldn't have exited
+ return ERR_FILE_EOF;
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": File corrupt (No Property Tag).");
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ }
+
+ r_v=Variant();
+ r_name="";
+
+
+ //ERR_FAIL_COND_V(tag->name!="property",ERR_FILE_CORRUPT);
+ //ERR_FAIL_COND_V(!tag->args.has("name"),ERR_FILE_CORRUPT);
+// ERR_FAIL_COND_V(!tag->args.has("type"),ERR_FILE_CORRUPT);
+
+ //String name=tag->args["name"];
+ //ERR_FAIL_COND_V(name=="",ERR_FILE_CORRUPT);
+ String type=tag->name;
+ String name=tag->args["name"];
+
+ if (type=="") {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": 'type' field is empty.");
+ ERR_FAIL_COND_V(type=="",ERR_FILE_CORRUPT);
+ }
+
+ if (type=="dictionary") {
+
+ Dictionary d;
+
+ while(true) {
+
+ Error err;
+ String tagname;
+ Variant key;
+
+ int dictline = get_current_line();
+
+
+ err=parse_property(key,tagname);
+
+ if (err && err!=ERR_FILE_EOF) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Error parsing dictionary: "+name+" (from line "+itos(dictline)+")");
+ ERR_FAIL_COND_V(err && err!=ERR_FILE_EOF,err);
+ }
+ //ERR_FAIL_COND_V(tagname!="key",ERR_FILE_CORRUPT);
+ if (err)
+ break;
+ Variant value;
+ err=parse_property(value,tagname);
+ if (err) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Error parsing dictionary: "+name+" (from line "+itos(dictline)+")");
+ }
+
+ ERR_FAIL_COND_V(err,err);
+ //ERR_FAIL_COND_V(tagname!="value",ERR_FILE_CORRUPT);
+
+ d[key]=value;
+ }
+
+
+ //err=parse_property_data(name); // skip the rest
+ //ERR_FAIL_COND_V(err,err);
+
+ r_name=name;
+ r_v=d;
+ return OK;
+
+ } else if (type=="array") {
+
+ if (!tag->args.has("len")) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
+ ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
+ }
+
+
+ int len=tag->args["len"].to_int();
+
+ Array array;
+ array.resize(len);
+
+ Error err;
+ Variant v;
+ String tagname;
+ int idx=0;
+ while( (err=parse_property(v,tagname))==OK ) {
+
+ ERR_CONTINUE( idx <0 || idx >=len );
+
+ array.set(idx,v);
+ idx++;
+ }
+
+ if (idx!=len) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Error loading array (size mismatch): "+name);
+ ERR_FAIL_COND_V(idx!=len,err);
+ }
+
+ if (err!=ERR_FILE_EOF) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Error loading array: "+name);
+ ERR_FAIL_COND_V(err!=ERR_FILE_EOF,err);
+ }
+
+ //err=parse_property_data(name); // skip the rest
+ //ERR_FAIL_COND_V(err,err);
+
+ r_name=name;
+ r_v=array;
+ return OK;
+
+ } else if (type=="resource") {
+
+ if (tag->args.has("path")) {
+
+ String path=tag->args["path"];
+ String hint;
+ if (tag->args.has("resource_type"))
+ hint=tag->args["resource_type"];
+
+ if (path.begins_with("local://"))
+ path=path.replace("local://",local_path+"::");
+ else if (path.find("://")==-1 && path.is_rel_path()) {
+ // path is relative to file being loaded, so convert to a resource path
+ path=Globals::get_singleton()->localize_path(local_path.get_base_dir()+"/"+path);
+
+ }
+
+ //take advantage of the resource loader cache. The resource is cached on it, even if
+ RES res=ResourceLoader::load(path,hint);
+
+
+ if (res.is_null()) {
+
+ WARN_PRINT(String("Couldn't load resource: "+path).ascii().get_data());
+ }
+
+ r_v=res.get_ref_ptr();
+ }
+
+
+
+ Error err=goto_end_of_tag();
+ if (err) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Error closing <resource> tag.");
+ ERR_FAIL_COND_V(err,err);
+ }
+
+
+ r_name=name;
+
+ return OK;
+
+ } else if (type=="image") {
+
+ if (!tag->args.has("encoding")) {
+ //empty image
+ r_v=Image();
+ String sdfsdfg;
+ Error err=parse_property_data(sdfsdfg);
+ return OK;
+ }
+
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Image missing 'encoding' field.");
+ ERR_FAIL_COND_V( !tag->args.has("encoding"), ERR_FILE_CORRUPT );
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Image missing 'width' field.");
+ ERR_FAIL_COND_V( !tag->args.has("width"), ERR_FILE_CORRUPT );
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Image missing 'height' field.");
+ ERR_FAIL_COND_V( !tag->args.has("height"), ERR_FILE_CORRUPT );
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Image missing 'format' field.");
+ ERR_FAIL_COND_V( !tag->args.has("format"), ERR_FILE_CORRUPT );
+
+ String encoding=tag->args["encoding"];
+
+ if (encoding=="raw") {
+ String width=tag->args["width"];
+ String height=tag->args["height"];
+ String format=tag->args["format"];
+ int mipmaps=tag->args.has("mipmaps")?int(tag->args["mipmaps"].to_int()):int(0);
+ int custom_size = tag->args.has("custom_size")?int(tag->args["custom_size"].to_int()):int(0);
+
+ r_name=name;
+
+ Image::Format imgformat;
+
+
+ if (format=="grayscale") {
+ imgformat=Image::FORMAT_GRAYSCALE;
+ } else if (format=="intensity") {
+ imgformat=Image::FORMAT_INTENSITY;
+ } else if (format=="grayscale_alpha") {
+ imgformat=Image::FORMAT_GRAYSCALE_ALPHA;
+ } else if (format=="rgb") {
+ imgformat=Image::FORMAT_RGB;
+ } else if (format=="rgba") {
+ imgformat=Image::FORMAT_RGBA;
+ } else if (format=="indexed") {
+ imgformat=Image::FORMAT_INDEXED;
+ } else if (format=="indexed_alpha") {
+ imgformat=Image::FORMAT_INDEXED_ALPHA;
+ } else if (format=="bc1") {
+ imgformat=Image::FORMAT_BC1;
+ } else if (format=="bc2") {
+ imgformat=Image::FORMAT_BC2;
+ } else if (format=="bc3") {
+ imgformat=Image::FORMAT_BC3;
+ } else if (format=="bc4") {
+ imgformat=Image::FORMAT_BC4;
+ } else if (format=="bc5") {
+ imgformat=Image::FORMAT_BC5;
+ } else if (format=="custom") {
+ imgformat=Image::FORMAT_CUSTOM;
+ } else {
+
+ ERR_FAIL_V( ERR_FILE_CORRUPT );
+ }
+
+
+ int datasize;
+ int w=width.to_int();
+ int h=height.to_int();
+
+ if (w == 0 && w == 0) {
+ //r_v = Image(w, h, imgformat);
+ r_v=Image();
+ String sdfsdfg;
+ Error err=parse_property_data(sdfsdfg);
+ return OK;
+ };
+
+ if (imgformat==Image::FORMAT_CUSTOM) {
+
+ datasize=custom_size;
+ } else {
+
+ datasize = Image::get_image_data_size(h,w,imgformat,mipmaps);
+ }
+
+ if (datasize==0) {
+ //r_v = Image(w, h, imgformat);
+ r_v=Image();
+ String sdfsdfg;
+ Error err=parse_property_data(sdfsdfg);
+ return OK;
+ };
+
+ DVector<uint8_t> pixels;
+ pixels.resize(datasize);
+ DVector<uint8_t>::Write wb = pixels.write();
+
+ int idx=0;
+ uint8_t byte;
+ while( idx<datasize*2) {
+
+ CharType c=get_char();
+
+ ERR_FAIL_COND_V(c=='<',ERR_FILE_CORRUPT);
+
+ if ( (c>='0' && c<='9') || (c>='A' && c<='F') || (c>='a' && c<='f') ) {
+
+ if (idx&1) {
+
+ byte|=HEX2CHR(c);
+ wb[idx>>1]=byte;
+ } else {
+
+ byte=HEX2CHR(c)<<4;
+ }
+
+ idx++;
+ }
+
+ }
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+
+ wb=DVector<uint8_t>::Write();
+
+ r_v=Image(w,h,mipmaps,imgformat,pixels);
+ String sdfsdfg;
+ Error err=parse_property_data(sdfsdfg);
+ ERR_FAIL_COND_V(err,err);
+
+ return OK;
+ }
+
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+
+ } else if (type=="raw_array") {
+
+ if (!tag->args.has("len")) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": RawArray missing 'len' field: "+name);
+ ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
+ }
+ int len=tag->args["len"].to_int();
+
+ DVector<uint8_t> bytes;
+ bytes.resize(len);
+ DVector<uint8_t>::Write w=bytes.write();
+ uint8_t *bytesptr=w.ptr();
+ int idx=0;
+ uint8_t byte;
+ while( idx<len*2) {
+
+ CharType c=get_char();
+
+ if (idx&1) {
+
+ byte|=HEX2CHR(c);
+ bytesptr[idx>>1]=byte;
+ } else {
+
+ byte=HEX2CHR(c)<<4;
+ }
+
+ idx++;
+ }
+
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+
+ w=DVector<uint8_t>::Write();
+ r_v=bytes;
+ String sdfsdfg;
+ Error err=parse_property_data(sdfsdfg);
+ ERR_FAIL_COND_V(err,err);
+ r_name=name;
+
+ return OK;
+
+ } else if (type=="int_array") {
+
+ if (!tag->args.has("len")) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
+ ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
+ }
+ int len=tag->args["len"].to_int();
+
+ DVector<int> ints;
+ ints.resize(len);
+ DVector<int>::Write w=ints.write();
+ int *intsptr=w.ptr();
+ int idx=0;
+ String str;
+#if 0
+ while( idx<len ) {
+
+
+ CharType c=get_char();
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+
+ if (c<33 || c==',' || c=='<') {
+
+ if (str.length()) {
+
+ intsptr[idx]=str.to_int();
+ str="";
+ idx++;
+ }
+
+ if (c=='<') {
+
+ while(get_char()!='>' && !f->eof_reached()) {}
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+ break;
+ }
+
+ } else {
+
+ str+=c;
+ }
+ }
+
+#else
+
+ Vector<char> tmpdata;
+
+ while( idx<len ) {
+
+ bool end=false;
+ Error err = _parse_array_element(tmpdata,true,f,&end);
+ ERR_FAIL_COND_V(err,err);
+
+ intsptr[idx]=String::to_int(&tmpdata[0]);
+ idx++;
+ if (end)
+ break;
+
+ }
+
+#endif
+ w=DVector<int>::Write();
+
+ r_v=ints;
+ Error err=goto_end_of_tag();
+ ERR_FAIL_COND_V(err,err);
+ r_name=name;
+
+ return OK;
+ } else if (type=="real_array") {
+
+ if (!tag->args.has("len")) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
+ ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
+ }
+ int len=tag->args["len"].to_int();;
+
+ DVector<real_t> reals;
+ reals.resize(len);
+ DVector<real_t>::Write w=reals.write();
+ real_t *realsptr=w.ptr();
+ int idx=0;
+ String str;
+
+
+#if 0
+ while( idx<len ) {
+
+
+ CharType c=get_char();
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+
+
+ if (c<33 || c==',' || c=='<') {
+
+ if (str.length()) {
+
+ realsptr[idx]=str.to_double();
+ str="";
+ idx++;
+ }
+
+ if (c=='<') {
+
+ while(get_char()!='>' && !f->eof_reached()) {}
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+ break;
+ }
+
+ } else {
+
+ str+=c;
+ }
+ }
+
+#else
+
+
+
+ Vector<char> tmpdata;
+
+ while( idx<len ) {
+
+ bool end=false;
+ Error err = _parse_array_element(tmpdata,true,f,&end);
+ ERR_FAIL_COND_V(err,err);
+
+ realsptr[idx]=String::to_double(&tmpdata[0]);
+ idx++;
+
+ if (end)
+ break;
+ }
+
+#endif
+
+ w=DVector<real_t>::Write();
+ r_v=reals;
+
+ Error err=goto_end_of_tag();
+ ERR_FAIL_COND_V(err,err);
+ r_name=name;
+
+ return OK;
+ } else if (type=="string_array") {
+
+ if (!tag->args.has("len")) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
+ ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
+ }
+ int len=tag->args["len"].to_int();
+
+ DVector<String> strings;
+ strings.resize(len);
+ DVector<String>::Write w=strings.write();
+ String *stringsptr=w.ptr();
+ int idx=0;
+ String str;
+
+ bool inside_str=false;
+ CharString cs;
+ while( idx<len ) {
+
+
+ CharType c=get_char();
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+
+
+ if (c=='"') {
+ if (inside_str) {
+
+ cs.push_back(0);
+ String str;
+ str.parse_utf8(cs.get_data());
+ unquote(str);
+ stringsptr[idx]=str;
+ cs.clear();
+ idx++;
+ inside_str=false;
+ } else {
+ inside_str=true;
+ }
+ } else if (c=='<') {
+
+ while(get_char()!='>' && !f->eof_reached()) {}
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+ break;
+
+
+ } else if (inside_str){
+
+ cs.push_back(c);
+ }
+ }
+ w=DVector<String>::Write();
+ r_v=strings;
+ String sdfsdfg;
+ Error err=parse_property_data(sdfsdfg);
+ ERR_FAIL_COND_V(err,err);
+
+ r_name=name;
+
+ return OK;
+ } else if (type=="vector3_array") {
+
+ if (!tag->args.has("len")) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
+ ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
+ }
+ int len=tag->args["len"].to_int();;
+
+ DVector<Vector3> vectors;
+ vectors.resize(len);
+ DVector<Vector3>::Write w=vectors.write();
+ Vector3 *vectorsptr=w.ptr();
+ int idx=0;
+ int subidx=0;
+ Vector3 auxvec;
+ String str;
+
+// uint64_t tbegin = OS::get_singleton()->get_ticks_usec();
+#if 0
+ while( idx<len ) {
+
+
+ CharType c=get_char();
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+
+
+ if (c<33 || c==',' || c=='<') {
+
+ if (str.length()) {
+
+ auxvec[subidx]=str.to_double();
+ subidx++;
+ str="";
+ if (subidx==3) {
+ vectorsptr[idx]=auxvec;
+
+ idx++;
+ subidx=0;
+ }
+ }
+
+ if (c=='<') {
+
+ while(get_char()!='>' && !f->eof_reached()) {}
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+ break;
+ }
+
+ } else {
+
+ str+=c;
+ }
+ }
+#else
+
+ Vector<char> tmpdata;
+
+ while( idx<len ) {
+
+ bool end=false;
+ Error err = _parse_array_element(tmpdata,true,f,&end);
+ ERR_FAIL_COND_V(err,err);
+
+
+ auxvec[subidx]=String::to_double(&tmpdata[0]);
+ subidx++;
+ if (subidx==3) {
+ vectorsptr[idx]=auxvec;
+
+ idx++;
+ subidx=0;
+ }
+
+ if (end)
+ break;
+ }
+
+
+
+#endif
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Premature end of vector3 array");
+ ERR_FAIL_COND_V(idx<len,ERR_FILE_CORRUPT);
+// double time_taken = (OS::get_singleton()->get_ticks_usec() - tbegin)/1000000.0;
+
+
+ w=DVector<Vector3>::Write();
+ r_v=vectors;
+ String sdfsdfg;
+ Error err=goto_end_of_tag();
+ ERR_FAIL_COND_V(err,err);
+ r_name=name;
+
+ return OK;
+
+ } else if (type=="vector2_array") {
+
+ if (!tag->args.has("len")) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
+ ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
+ }
+ int len=tag->args["len"].to_int();;
+
+ DVector<Vector2> vectors;
+ vectors.resize(len);
+ DVector<Vector2>::Write w=vectors.write();
+ Vector2 *vectorsptr=w.ptr();
+ int idx=0;
+ int subidx=0;
+ Vector2 auxvec;
+ String str;
+
+// uint64_t tbegin = OS::get_singleton()->get_ticks_usec();
+#if 0
+ while( idx<len ) {
+
+
+ CharType c=get_char();
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+
+
+ if (c<22 || c==',' || c=='<') {
+
+ if (str.length()) {
+
+ auxvec[subidx]=str.to_double();
+ subidx++;
+ str="";
+ if (subidx==2) {
+ vectorsptr[idx]=auxvec;
+
+ idx++;
+ subidx=0;
+ }
+ }
+
+ if (c=='<') {
+
+ while(get_char()!='>' && !f->eof_reached()) {}
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+ break;
+ }
+
+ } else {
+
+ str+=c;
+ }
+ }
+#else
+
+ Vector<char> tmpdata;
+
+ while( idx<len ) {
+
+ bool end=false;
+ Error err = _parse_array_element(tmpdata,true,f,&end);
+ ERR_FAIL_COND_V(err,err);
+
+
+ auxvec[subidx]=String::to_double(&tmpdata[0]);
+ subidx++;
+ if (subidx==2) {
+ vectorsptr[idx]=auxvec;
+
+ idx++;
+ subidx=0;
+ }
+
+ if (end)
+ break;
+ }
+
+
+
+#endif
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Premature end of vector2 array");
+ ERR_FAIL_COND_V(idx<len,ERR_FILE_CORRUPT);
+// double time_taken = (OS::get_singleton()->get_ticks_usec() - tbegin)/1000000.0;
+
+
+ w=DVector<Vector2>::Write();
+ r_v=vectors;
+ String sdfsdfg;
+ Error err=goto_end_of_tag();
+ ERR_FAIL_COND_V(err,err);
+ r_name=name;
+
+ return OK;
+
+ } else if (type=="color_array") {
+
+ if (!tag->args.has("len")) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
+ ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
+ }
+ int len=tag->args["len"].to_int();;
+
+ DVector<Color> colors;
+ colors.resize(len);
+ DVector<Color>::Write w=colors.write();
+ Color *colorsptr=w.ptr();
+ int idx=0;
+ int subidx=0;
+ Color auxcol;
+ String str;
+
+ while( idx<len ) {
+
+
+ CharType c=get_char();
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+
+
+ if (c<33 || c==',' || c=='<') {
+
+ if (str.length()) {
+
+ auxcol[subidx]=str.to_double();
+ subidx++;
+ str="";
+ if (subidx==4) {
+ colorsptr[idx]=auxcol;
+ idx++;
+ subidx=0;
+ }
+ }
+
+ if (c=='<') {
+
+ while(get_char()!='>' && !f->eof_reached()) {}
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+ break;
+ }
+
+ } else {
+
+ str+=c;
+ }
+ }
+ w=DVector<Color>::Write();
+ r_v=colors;
+ String sdfsdfg;
+ Error err=parse_property_data(sdfsdfg);
+ ERR_FAIL_COND_V(err,err);
+ r_name=name;
+
+ return OK;
+ }
+
+
+ String data;
+ Error err = parse_property_data(data);
+ ERR_FAIL_COND_V(err!=OK,err);
+
+ if (type=="nil") {
+ // uh do nothing
+
+ } else if (type=="bool") {
+ // uh do nothing
+ if (data.nocasecmp_to("true")==0 || data.to_int()!=0)
+ r_v=true;
+ else
+ r_v=false;
+ } else if (type=="int") {
+
+ r_v=data.to_int();
+ } else if (type=="real") {
+
+ r_v=data.to_double();
+ } else if (type=="string") {
+
+ String str=data;
+ unquote(str);
+ r_v=str;
+ } else if (type=="vector3") {
+
+
+ r_v=Vector3(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double(),
+ data.get_slice(",",2).to_double()
+ );
+
+ } else if (type=="vector2") {
+
+
+ r_v=Vector2(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double()
+ );
+
+ } else if (type=="plane") {
+
+ r_v=Plane(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double(),
+ data.get_slice(",",2).to_double(),
+ data.get_slice(",",3).to_double()
+ );
+
+ } else if (type=="quaternion") {
+
+ r_v=Quat(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double(),
+ data.get_slice(",",2).to_double(),
+ data.get_slice(",",3).to_double()
+ );
+
+ } else if (type=="rect2") {
+
+ r_v=Rect2(
+ Vector2(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double()
+ ),
+ Vector2(
+ data.get_slice(",",2).to_double(),
+ data.get_slice(",",3).to_double()
+ )
+ );
+
+
+ } else if (type=="aabb") {
+
+ r_v=AABB(
+ Vector3(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double(),
+ data.get_slice(",",2).to_double()
+ ),
+ Vector3(
+ data.get_slice(",",3).to_double(),
+ data.get_slice(",",4).to_double(),
+ data.get_slice(",",5).to_double()
+ )
+ );
+
+ } else if (type=="matrix32") {
+
+ Matrix32 m3;
+ for (int i=0;i<3;i++) {
+ for (int j=0;j<2;j++) {
+ m3.elements[i][j]=data.get_slice(",",i*2+j).to_double();
+ }
+ }
+ r_v=m3;
+
+ } else if (type=="matrix3") {
+
+ Matrix3 m3;
+ for (int i=0;i<3;i++) {
+ for (int j=0;j<3;j++) {
+ m3.elements[i][j]=data.get_slice(",",i*3+j).to_double();
+ }
+ }
+ r_v=m3;
+
+ } else if (type=="transform") {
+
+ Transform tr;
+ for (int i=0;i<3;i++) {
+ for (int j=0;j<3;j++) {
+ tr.basis.elements[i][j]=data.get_slice(",",i*3+j).to_double();
+ }
+
+ }
+ tr.origin=Vector3(
+ data.get_slice(",",9).to_double(),
+ data.get_slice(",",10).to_double(),
+ data.get_slice(",",11).to_double()
+ );
+ r_v=tr;
+
+ } else if (type=="color") {
+
+ r_v=Color(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double(),
+ data.get_slice(",",2).to_double(),
+ data.get_slice(",",3).to_double()
+ );
+
+ } else if (type=="node_path") {
+
+ String str=data;
+ unquote(str);
+ r_v=NodePath( str );
+ } else if (type=="input_event") {
+
+ // ?
+ } else {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Unrecognized tag in file: "+type);
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ }
+ r_name=name;
+ return OK;
+}
+
+
+Error ObjectFormatLoaderXML::load(Object **p_object,Variant &p_meta) {
+
+ *p_object=NULL;
+ p_meta=Variant();
+
+
+
+ while(true) {
+
+
+ bool exit;
+ Tag *tag = parse_tag(&exit);
+
+
+ if (!tag) {
+ if (!exit) // shouldn't have exited
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ *p_object=NULL;
+ return ERR_FILE_EOF;
+ }
+
+ RES resource;
+ Object *obj=NULL;
+
+ if (tag->name=="resource") {
+ //loading resource
+
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <resource> missing 'len' field.");
+ ERR_FAIL_COND_V(!tag->args.has("path"),ERR_FILE_CORRUPT);
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <resource> missing 'type' field.");
+ ERR_FAIL_COND_V(!tag->args.has("type"),ERR_FILE_CORRUPT);
+ String path=tag->args["path"];
+
+ if (path.begins_with("local://")) {
+ //built-in resource (but really external)
+ path=path.replace("local://",local_path+"::");
+ }
+
+
+ if (ResourceCache::has(path)) {
+ Error err = close_tag(tag->name);
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Unable to close <resource> tag.");
+ ERR_FAIL_COND_V( err, err );
+ continue; //it's a resource, and it's already loaded
+
+ }
+
+ String type = tag->args["type"];
+
+ obj = ObjectTypeDB::instance(type);
+ if (!obj) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Object of unrecognized type in file: "+type);
+ }
+ ERR_FAIL_COND_V(!obj,ERR_FILE_CORRUPT);
+
+ Resource *r = obj->cast_to<Resource>();
+ if (!r) {
+ memdelete(obj); //bye
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Object type in resource field not a resource, type is: "+obj->get_type());
+ ERR_FAIL_COND_V(!obj->cast_to<Resource>(),ERR_FILE_CORRUPT);
+ }
+
+ resource = RES( r );
+ r->set_path(path);
+
+
+
+ } else if (tag->name=="object") {
+
+ if ( tag->args.has("type") ) {
+
+ ERR_FAIL_COND_V(!ObjectTypeDB::type_exists(tag->args["type"]), ERR_FILE_CORRUPT);
+
+ if (ObjectTypeDB::can_instance(tag->args["type"])) {
+ obj = ObjectTypeDB::instance(tag->args["type"]);
+ if (!obj) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Object of unrecognized type in file: "+tag->args["type"]);
+ }
+ ERR_FAIL_COND_V(!obj,ERR_FILE_CORRUPT);
+ } else {
+
+ close_tag(tag->name);
+ return ERR_SKIP;
+ };
+ } else {
+ //otherwise it's a meta object
+ }
+
+ } else {
+
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Unknown main tag: "+tag->name);
+ ERR_FAIL_V( ERR_FILE_CORRUPT );
+ }
+
+ //load properties
+
+ while(true) {
+
+ String name;
+ Variant v;
+ Error err;
+ err = parse_property(v,name);
+ if (err==ERR_FILE_EOF) //tag closed
+ break;
+ if (err!=OK) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": XML Parsing aborted.");
+ ERR_FAIL_COND_V(err!=OK,ERR_FILE_CORRUPT);
+ }
+ if (resource.is_null() && name=="__xml_meta__") {
+
+ p_meta=v;
+ continue;
+ } else if (!obj) {
+
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Normal property found in meta object.");
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ }
+
+ obj->set(name,v);
+ }
+
+ if (!obj) {
+ *p_object=NULL;
+ return OK; // it was a meta object
+ }
+
+ if (resource.is_null()) {
+
+ //regular object
+ *p_object=obj;
+ return OK;
+ } else {
+
+
+ resource_cache.push_back(resource); //keep it in mem until finished loading
+ }
+
+ // a resource.. continue!
+
+ }
+
+
+
+ return OK; //never reach anyway
+
+}
+
+int ObjectFormatLoaderXML::get_current_line() const {
+
+ return lines;
+}
+
+
+uint8_t ObjectFormatLoaderXML::get_char() const {
+
+ uint8_t c = f->get_8();
+ if (c=='\n')
+ lines++;
+ return c;
+
+}
+
+ObjectFormatLoaderXML::~ObjectFormatLoaderXML() {
+
+ if (f) {
+ if (f->is_open())
+ f->close();
+ memdelete(f);
+ }
+}
+
+
+
+ObjectFormatLoaderXML* ObjectFormatLoaderInstancerXML::instance(const String& p_file,const String& p_magic) {
+
+ Error err;
+ FileAccess *f=FileAccess::open(p_file,FileAccess::READ,&err);
+ if (err!=OK) {
+
+ ERR_FAIL_COND_V(err!=OK,NULL);
+ }
+
+ ObjectFormatLoaderXML *loader = memnew( ObjectFormatLoaderXML );
+
+ loader->lines=1;
+ loader->f=f;
+ loader->local_path = Globals::get_singleton()->localize_path(p_file);
+
+ ObjectFormatLoaderXML::Tag *tag = loader->parse_tag();
+ if (!tag || tag->name!="?xml" || !tag->args.has("version") || !tag->args.has("encoding") || tag->args["encoding"]!="UTF-8") {
+
+ f->close();
+ memdelete(loader);
+ ERR_EXPLAIN("Not a XML:UTF-8 File: "+p_file);
+ ERR_FAIL_V(NULL);
+ }
+
+ loader->tag_stack.clear();
+
+ tag = loader->parse_tag();
+
+ if (!tag || tag->name!="object_file" || !tag->args.has("magic") || !tag->args.has("version") || tag->args["magic"]!=p_magic) {
+
+ f->close();
+ memdelete(loader);
+ ERR_EXPLAIN("Unrecognized XML File: "+p_file);
+ ERR_FAIL_V(NULL);
+ }
+
+ String version = tag->args["version"];
+ if (version.get_slice_count(".")!=2) {
+
+ f->close();
+ memdelete(loader);
+ ERR_EXPLAIN("Invalid Version String '"+version+"'' in file: "+p_file);
+ ERR_FAIL_V(NULL);
+ }
+
+ int major = version.get_slice(".",0).to_int();
+ int minor = version.get_slice(".",1).to_int();
+
+ if (major>VERSION_MAJOR || (major==VERSION_MAJOR && minor>VERSION_MINOR)) {
+
+ f->close();
+ memdelete(loader);
+ ERR_EXPLAIN("File Format '"+version+"' is too new! Please upgrade to a a new engine version: "+p_file);
+ ERR_FAIL_V(NULL);
+
+ }
+
+ return loader;
+}
+
+void ObjectFormatLoaderInstancerXML::get_recognized_extensions(List<String> *p_extensions) const {
+
+ p_extensions->push_back("xml");
+}
+
+
+#endif
+#endif
+#endif
diff --git a/core/io/object_format_xml.h b/core/io/object_format_xml.h
new file mode 100644
index 0000000000..1169a1de58
--- /dev/null
+++ b/core/io/object_format_xml.h
@@ -0,0 +1,196 @@
+/*************************************************************************/
+/* object_format_xml.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef OBJECT_FORMAT_XML_H
+#define OBJECT_FORMAT_XML_H
+
+#ifdef XML_ENABLED
+#ifdef OLD_SCENE_FORMAT_ENABLED
+#include "io/object_loader.h"
+#include "io/object_saver.h"
+#include "os/file_access.h"
+#include "map.h"
+#include "resource.h"
+#include "xml_parser.h"
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+class ObjectFormatSaverXML : public ObjectFormatSaver {
+
+ String local_path;
+
+
+ Ref<OptimizedSaver> optimizer;
+
+ bool relative_paths;
+ bool bundle_resources;
+ bool skip_editor;
+ FileAccess *f;
+ String magic;
+ int depth;
+ Map<RES,int> resource_map;
+
+ struct SavedObject {
+
+ Variant meta;
+ String type;
+
+
+ struct SavedProperty {
+
+ String name;
+ Variant value;
+ };
+
+ List<SavedProperty> properties;
+ };
+
+ List<RES> saved_resources;
+
+ List<SavedObject*> saved_objects;
+
+ void enter_tag(const String& p_section,const String& p_args="");
+ void exit_tag(const String& p_section);
+
+ void _find_resources(const Variant& p_variant);
+ void write_property(const String& p_name,const Variant& p_property,bool *r_ok=NULL);
+
+
+ void escape(String& p_str);
+ void write_tabs(int p_diff=0);
+ void write_string(String p_str,bool p_escape=true);
+
+public:
+
+ virtual Error save(const Object *p_object,const Variant &p_meta);
+
+ ObjectFormatSaverXML(FileAccess *p_file,const String& p_magic,const String& p_local_path,uint32_t p_flags,const Ref<OptimizedSaver>& p_optimizer);
+ ~ObjectFormatSaverXML();
+};
+
+class ObjectFormatSaverInstancerXML : public ObjectFormatSaverInstancer {
+public:
+
+ virtual ObjectFormatSaver* instance(const String& p_file,const String& p_magic,uint32_t p_flags=0,const Ref<OptimizedSaver>& p_optimizer=Ref<OptimizedSaver>());
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+
+ virtual ~ObjectFormatSaverInstancerXML();
+};
+
+/***********************************/
+/***********************************/
+/***********************************/
+/***********************************/
+
+//#define OPTIMIZED_XML_LOADER
+
+#ifdef OPTIMIZED_XML_LOADER
+
+class ObjectFormatLoaderXML : public ObjectFormatLoader {
+
+ Ref<XMLParser> parser;
+ String local_path;
+
+ Error _close_tag(const String& p_tag);
+ Error _parse_property(Variant& r_property,String& r_name);
+
+friend class ObjectFormatLoaderInstancerXML;
+
+ List<RES> resource_cache;
+public:
+
+
+ virtual Error load(Object **p_object,Variant &p_meta);
+
+
+};
+
+class ObjectFormatLoaderInstancerXML : public ObjectFormatLoaderInstancer {
+public:
+
+ virtual ObjectFormatLoaderXML* instance(const String& p_file,const String& p_magic);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+
+};
+
+#else
+
+
+class ObjectFormatLoaderXML : public ObjectFormatLoader {
+
+ String local_path;
+
+ FileAccess *f;
+
+ struct Tag {
+
+ String name;
+ HashMap<String,String> args;
+ };
+
+ _FORCE_INLINE_ Error _parse_array_element(Vector<char> &buff,bool p_number_only,FileAccess *f,bool *end);
+
+ mutable int lines;
+ uint8_t get_char() const;
+ int get_current_line() const;
+
+friend class ObjectFormatLoaderInstancerXML;
+ List<Tag> tag_stack;
+
+ List<RES> resource_cache;
+ Tag* parse_tag(bool* r_exit=NULL);
+ Error close_tag(const String& p_name);
+ void unquote(String& p_str);
+ Error goto_end_of_tag();
+ Error parse_property_data(String &r_data);
+ Error parse_property(Variant& r_v, String &r_name);
+
+public:
+
+
+ virtual Error load(Object **p_object,Variant &p_meta);
+
+ virtual ~ObjectFormatLoaderXML();
+};
+
+class ObjectFormatLoaderInstancerXML : public ObjectFormatLoaderInstancer {
+public:
+
+ virtual ObjectFormatLoaderXML* instance(const String& p_file,const String& p_magic);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+
+
+
+};
+
+#endif
+#endif
+#endif
+#endif
diff --git a/core/io/object_loader.cpp b/core/io/object_loader.cpp
new file mode 100644
index 0000000000..bb42cf7338
--- /dev/null
+++ b/core/io/object_loader.cpp
@@ -0,0 +1,84 @@
+/*************************************************************************/
+/* object_loader.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. */
+/*************************************************************************/
+#include "object_loader.h"
+
+#ifdef OLD_SCENE_FORMAT_ENABLED
+
+bool ObjectFormatLoaderInstancer::recognize(const String& p_extension) const {
+
+
+ List<String> extensions;
+ get_recognized_extensions(&extensions);
+ for (List<String>::Element *E=extensions.front();E;E=E->next()) {
+
+ if (E->get().nocasecmp_to(p_extension)==0)
+ return true;
+ }
+
+ return false;
+}
+
+ObjectFormatLoaderInstancer *ObjectLoader::loader[MAX_LOADERS];
+int ObjectLoader::loader_count=0;
+
+
+ObjectFormatLoader *ObjectLoader::instance_format_loader(const String& p_path,const String& p_magic,String p_force_extension) {
+
+ String extension=p_force_extension.length()?p_force_extension:p_path.extension();
+
+ for (int i=0;i<loader_count;i++) {
+
+ if (!loader[i]->recognize(extension))
+ continue;
+ ObjectFormatLoader *format_loader = loader[i]->instance(p_path,p_magic);
+ if (format_loader)
+ return format_loader;
+ }
+
+ return NULL;
+}
+
+void ObjectLoader::get_recognized_extensions(List<String> *p_extensions) {
+
+ for (int i=0;i<loader_count;i++) {
+
+ loader[i]->get_recognized_extensions(p_extensions);
+ }
+}
+
+
+
+void ObjectLoader::add_object_format_loader_instancer(ObjectFormatLoaderInstancer *p_format_loader_instancer) {
+
+ ERR_FAIL_COND(loader_count>=MAX_LOADERS );
+ loader[loader_count++]=p_format_loader_instancer;
+}
+
+
+#endif
diff --git a/core/io/object_loader.h b/core/io/object_loader.h
new file mode 100644
index 0000000000..9199313f04
--- /dev/null
+++ b/core/io/object_loader.h
@@ -0,0 +1,76 @@
+/*************************************************************************/
+/* object_loader.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef OBJECT_LOADER_H
+#define OBJECT_LOADER_H
+
+#include "object.h"
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+#ifdef OLD_SCENE_FORMAT_ENABLED
+class ObjectFormatLoader {
+public:
+
+ virtual Error load(Object **p_object,Variant &p_meta)=0;
+
+ virtual ~ObjectFormatLoader() {}
+};
+
+class ObjectFormatLoaderInstancer {
+public:
+
+ virtual ObjectFormatLoader* instance(const String& p_file,const String& p_magic)=0;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const=0;
+ bool recognize(const String& p_extension) const;
+
+ virtual ~ObjectFormatLoaderInstancer() {}
+};
+
+class ObjectLoader {
+
+ enum {
+ MAX_LOADERS=64
+ };
+
+ static ObjectFormatLoaderInstancer *loader[MAX_LOADERS];
+ static int loader_count;
+
+public:
+
+ static ObjectFormatLoader *instance_format_loader(const String& p_path,const String& p_magic,String p_force_extension="");
+ static void add_object_format_loader_instancer(ObjectFormatLoaderInstancer *p_format_loader_instancer);
+ static void get_recognized_extensions(List<String> *p_extensions);
+
+
+
+};
+
+#endif
+#endif
diff --git a/core/io/object_saver.cpp b/core/io/object_saver.cpp
new file mode 100644
index 0000000000..cff2e836a7
--- /dev/null
+++ b/core/io/object_saver.cpp
@@ -0,0 +1,157 @@
+/*************************************************************************/
+/* object_saver.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. */
+/*************************************************************************/
+#include "object_saver.h"
+#ifdef OLD_SCENE_FORMAT_ENABLED
+
+void OptimizedSaver::add_property(const StringName& p_name, const Variant& p_value) {
+
+ ERR_FAIL_COND(!_list);
+ Property p;
+ p.name=p_name;
+ p.value=p_value;
+ _list->push_back(p);
+}
+
+bool OptimizedSaver::optimize_object(const Object *p_object) {
+
+ return false; //not optimize
+}
+
+void OptimizedSaver::get_property_list(const Object* p_object,List<Property> *p_properties) {
+
+
+ _list=p_properties;
+
+ bool res = call("optimize_object",p_object);
+
+ if (!res) {
+
+ List<PropertyInfo> plist;
+ p_object->get_property_list(&plist);
+ for(List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) {
+
+ PropertyInfo pinfo=E->get();
+ if ((pinfo.usage&PROPERTY_USAGE_STORAGE) || (is_bundle_resources_enabled() && pinfo.usage&PROPERTY_USAGE_BUNDLE)) {
+
+ add_property(pinfo.name,p_object->get(pinfo.name));
+ }
+ }
+
+ }
+
+ _list=NULL;
+}
+
+void OptimizedSaver::set_target_platform(const String& p_platform) {
+
+ ERR_FAIL_COND(p_platform!="" && !p_platform.is_valid_identifier());
+ platform=p_platform;
+}
+
+String OptimizedSaver::get_target_platform() const {
+
+ return platform;
+}
+
+void OptimizedSaver::set_target_name(const String& p_name) {
+
+ name=p_name;
+}
+
+String OptimizedSaver::get_target_name() const {
+
+ return name;
+}
+
+void OptimizedSaver::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_target_platform","name"),&OptimizedSaver::set_target_platform);
+ ObjectTypeDB::bind_method(_MD("get_target_platform"),&OptimizedSaver::get_target_platform);
+ ObjectTypeDB::bind_method(_MD("set_target_name","name"),&OptimizedSaver::set_target_name);
+ ObjectTypeDB::bind_method(_MD("add_property","name","value"),&OptimizedSaver::add_property);
+ ObjectTypeDB::bind_method(_MD("optimize_object","obj"),&OptimizedSaver::optimize_object);
+}
+
+OptimizedSaver::OptimizedSaver() {
+
+ _list=NULL;
+}
+
+ObjectFormatSaverInstancer *ObjectSaver::saver[MAX_LOADERS];
+int ObjectSaver::saver_count=0;
+
+bool ObjectFormatSaverInstancer::recognize(const String& p_extension) const {
+
+
+ List<String> extensions;
+ get_recognized_extensions(&extensions);
+ for (List<String>::Element *E=extensions.front();E;E=E->next()) {
+
+ if (E->get().nocasecmp_to(p_extension.extension())==0)
+ return true;
+ }
+
+ return false;
+}
+
+ObjectFormatSaver *ObjectSaver::instance_format_saver(const String& p_path,const String& p_magic,String p_force_extension,uint32_t p_flags,const Ref<OptimizedSaver>& p_optimizer) {
+
+ String extension=p_force_extension.length()?p_force_extension:p_path.extension();
+
+ for (int i=0;i<saver_count;i++) {
+
+ if (!saver[i]->recognize(extension))
+ continue;
+ ObjectFormatSaver *format_saver = saver[i]->instance(p_path,p_magic,p_flags,p_optimizer);
+ if (format_saver)
+ return format_saver;
+ }
+
+ return NULL;
+}
+
+void ObjectSaver::get_recognized_extensions(List<String> *p_extensions) {
+
+ for (int i=0;i<saver_count;i++) {
+
+ saver[i]->get_recognized_extensions(p_extensions);
+ }
+}
+
+
+
+void ObjectSaver::add_object_format_saver_instancer(ObjectFormatSaverInstancer *p_format_saver_instancer) {
+
+ ERR_FAIL_COND(saver_count>=MAX_LOADERS );
+ saver[saver_count++]=p_format_saver_instancer;
+}
+
+
+
+#endif
diff --git a/core/io/object_saver.h b/core/io/object_saver.h
new file mode 100644
index 0000000000..b22f7e05bb
--- /dev/null
+++ b/core/io/object_saver.h
@@ -0,0 +1,128 @@
+/*************************************************************************/
+/* object_saver.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef OBJECT_SAVER_H
+#define OBJECT_SAVER_H
+
+#include "object.h"
+#include "resource.h"
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+#ifdef OLD_SCENE_FORMAT_ENABLED
+
+class OptimizedSaver : public Reference {
+
+ OBJ_TYPE(OptimizedSaver,Reference);
+public:
+
+ struct Property {
+
+ StringName name;
+ Variant value;
+ };
+
+private:
+
+ String name;
+ String platform;
+ List<Property> *_list;
+protected:
+
+
+ void set_target_platform(const String& p_platform);
+ void set_target_name(const String& p_name);
+ void add_property(const StringName& p_name, const Variant& p_value);
+ static void _bind_methods();
+
+ virtual bool optimize_object(const Object *p_object);
+
+public:
+
+
+ virtual bool is_bundle_resources_enabled() const { return false; }
+
+ String get_target_platform() const;
+ String get_target_name() const;
+ void get_property_list(const Object* p_object, List<Property> *p_properties);
+
+
+ OptimizedSaver();
+
+};
+
+
+class ObjectFormatSaver {
+public:
+
+ virtual Error save(const Object *p_object,const Variant &p_meta=Variant())=0;
+
+ virtual ~ObjectFormatSaver() {}
+};
+
+class ObjectFormatSaverInstancer {
+public:
+
+ virtual void get_recognized_extensions(List<String> *p_extensions) const=0;
+ virtual ObjectFormatSaver* instance(const String& p_file,const String& p_magic="",uint32_t p_flags=0,const Ref<OptimizedSaver>& p_optimizer=Ref<OptimizedSaver>())=0;
+ bool recognize(const String& p_extension) const;
+
+ virtual ~ObjectFormatSaverInstancer() {}
+};
+
+class ObjectSaver {
+
+ enum {
+ MAX_LOADERS=64
+ };
+
+ static ObjectFormatSaverInstancer *saver[MAX_LOADERS];
+ static int saver_count;
+
+public:
+
+ enum SaverFlags {
+
+ FLAG_RELATIVE_PATHS=1,
+ FLAG_BUNDLE_RESOURCES=2,
+ FLAG_OMIT_EDITOR_PROPERTIES=4,
+ FLAG_SAVE_BIG_ENDIAN=8
+ };
+
+
+ static ObjectFormatSaver *instance_format_saver(const String& p_path,const String& p_magic,String p_force_extension="",uint32_t p_flags=0,const Ref<OptimizedSaver>& p_optimizer=Ref<OptimizedSaver>());
+ static void get_recognized_extensions(List<String> *p_extensions);
+
+ static void add_object_format_saver_instancer(ObjectFormatSaverInstancer *p_format_saver_instancer);
+
+
+};
+
+#endif
+#endif
diff --git a/core/io/object_saver_base.cpp b/core/io/object_saver_base.cpp
new file mode 100644
index 0000000000..94d715de28
--- /dev/null
+++ b/core/io/object_saver_base.cpp
@@ -0,0 +1,150 @@
+/*************************************************************************/
+/* object_saver_base.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. */
+/*************************************************************************/
+#include "object_saver_base.h"
+#ifdef OLD_SCENE_FORMAT_ENABLED
+void ObjectSaverBase::_find_resources(const Variant& p_variant) {
+
+ switch(p_variant.get_type()) {
+ case Variant::OBJECT: {
+
+
+ RES res = p_variant.operator RefPtr();
+
+ if (res.is_null() || (res->get_path().length() && res->get_path().find("::") == -1 ))
+ return;
+
+ if (resource_map.has(res))
+ return;
+
+ List<PropertyInfo> property_list;
+
+ res->get_property_list( &property_list );
+
+ List<PropertyInfo>::Element *I=property_list.front();
+
+ while(I) {
+
+ PropertyInfo pi=I->get();
+
+ if (pi.usage&PROPERTY_USAGE_STORAGE) {
+
+ if (pi.type==Variant::OBJECT) {
+
+ Variant v=res->get(I->get().name);
+ _find_resources(v);
+ }
+ }
+
+ I=I->next();
+ }
+
+ resource_map[ res ] = resource_map.size(); //saved after, so the childs it needs are available when loaded
+ saved_resources.push_back(res);
+
+ } break;
+
+ case Variant::ARRAY: {
+
+ Array varray=p_variant;
+ int len=varray.size();
+ for(int i=0;i<len;i++) {
+
+ Variant v=varray.get(i);
+ _find_resources(v);
+ }
+
+ } break;
+
+ case Variant::DICTIONARY: {
+
+ Dictionary d=p_variant;
+ List<Variant> keys;
+ d.get_key_list(&keys);
+ for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+ Variant v = d[E->get()];
+ _find_resources(v);
+ }
+ } break;
+ default: {}
+ }
+
+}
+
+
+Error ObjectSaverBase::save(const Object *p_object,const Variant &p_meta) {
+
+ ERR_EXPLAIN("write_object should supply either an object, a meta, or both");
+ ERR_FAIL_COND_V(!p_object && p_meta.get_type()==Variant::NIL, ERR_INVALID_PARAMETER);
+
+ SavedObject *so = memnew( SavedObject );
+
+ if (p_object) {
+ so->type=p_object->get_type();
+ };
+
+ _find_resources(p_meta);
+ so->meta=p_meta;
+
+ if (p_object) {
+
+ List<PropertyInfo> property_list;
+ p_object->get_property_list( &property_list );
+
+ List<PropertyInfo>::Element *I=property_list.front();
+
+ while(I) {
+
+ if (I->get().usage&PROPERTY_USAGE_STORAGE) {
+
+ SavedObject::SavedProperty sp;
+ sp.name=I->get().name;
+ sp.value = p_object->get(I->get().name);
+ _find_resources(sp.value);
+ so->properties.push_back(sp);
+ }
+
+ I=I->next();
+ }
+
+ }
+
+ saved_objects.push_back(so);
+
+ return OK;
+}
+
+ObjectSaverBase::ObjectSaverBase() {
+
+};
+
+ObjectSaverBase::~ObjectSaverBase() {
+
+};
+#endif
diff --git a/core/io/object_saver_base.h b/core/io/object_saver_base.h
new file mode 100644
index 0000000000..d9ec4a3aba
--- /dev/null
+++ b/core/io/object_saver_base.h
@@ -0,0 +1,76 @@
+/*************************************************************************/
+/* object_saver_base.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef OBJECT_SAVER_BASE_H
+#define OBJECT_SAVER_BASE_H
+
+
+#ifdef OLD_SCENE_FORMAT_ENABLED
+#include "object_saver.h"
+
+#include "map.h"
+#include "resource.h"
+
+class ObjectSaverBase : public ObjectFormatSaver {
+
+protected:
+
+ Map<RES,int> resource_map;
+
+ struct SavedObject {
+
+ Variant meta;
+ String type;
+
+
+ struct SavedProperty {
+
+ String name;
+ Variant value;
+ };
+
+ List<SavedProperty> properties;
+ };
+
+ List<RES> saved_resources;
+
+ List<SavedObject*> saved_objects;
+
+ void _find_resources(const Variant& p_variant);
+
+ virtual Error write()=0;
+public:
+
+ virtual Error save(const Object *p_object,const Variant &p_meta);
+
+ ObjectSaverBase();
+ ~ObjectSaverBase();
+};
+
+#endif
+#endif // OBJECT_SAVER_BASE_H
diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp
new file mode 100644
index 0000000000..f67a10df2e
--- /dev/null
+++ b/core/io/packet_peer.cpp
@@ -0,0 +1,255 @@
+/*************************************************************************/
+/* packet_peer.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. */
+/*************************************************************************/
+#include "packet_peer.h"
+
+#include "io/marshalls.h"
+#include "globals.h"
+/* helpers / binders */
+
+
+
+PacketPeer::PacketPeer() {
+
+
+}
+
+Error PacketPeer::get_packet_buffer(DVector<uint8_t> &r_buffer) const {
+
+ const uint8_t *buffer;
+ int buffer_size;
+ Error err = get_packet(&buffer,buffer_size);
+ if (err)
+ return err;
+
+ r_buffer.resize(buffer_size);
+ if (buffer_size==0)
+ return OK;
+
+ DVector<uint8_t>::Write w = r_buffer.write();
+ for(int i=0;i<buffer_size;i++)
+ w[i]=buffer[i];
+
+ return OK;
+
+}
+
+Error PacketPeer::put_packet_buffer(const DVector<uint8_t> &p_buffer) {
+
+ int len = p_buffer.size();
+ if (len==0)
+ return OK;
+
+ DVector<uint8_t>::Read r = p_buffer.read();
+ return put_packet(&r[0],len);
+
+}
+
+Error PacketPeer::get_var(Variant &r_variant) const {
+
+ const uint8_t *buffer;
+ int buffer_size;
+ Error err = get_packet(&buffer,buffer_size);
+ if (err)
+ return err;
+
+ return decode_variant(r_variant,buffer,buffer_size);
+
+}
+
+Error PacketPeer::put_var(const Variant& p_packet) {
+
+ int len;
+ Error err = encode_variant(p_packet,NULL,len); // compute len first
+ if (err)
+ return err;
+
+ if (len==0)
+ return OK;
+
+ uint8_t *buf = (uint8_t*)alloca(len);
+ ERR_FAIL_COND_V(!buf,ERR_OUT_OF_MEMORY);
+ err = encode_variant(p_packet,buf,len);
+ ERR_FAIL_COND_V(err, err);
+
+ return put_packet(buf, len);
+
+}
+
+Variant PacketPeer::_bnd_get_var() const {
+ Variant var;
+ get_var(var);
+
+ return var;
+};
+
+void PacketPeer::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("get_var"),&PacketPeer::_bnd_get_var);
+ ObjectTypeDB::bind_method(_MD("put_var", "var:Variant"),&PacketPeer::put_var);
+};
+
+/***************/
+
+
+void PacketPeerStream::_set_stream_peer(REF p_peer) {
+
+ ERR_FAIL_COND(p_peer.is_null());
+ set_stream_peer(p_peer);
+}
+
+void PacketPeerStream::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_stream_peer","peer:StreamPeer"),&PacketPeerStream::_set_stream_peer);
+}
+
+Error PacketPeerStream::_poll_buffer() const {
+
+ ERR_FAIL_COND_V(peer.is_null(),ERR_UNCONFIGURED);
+
+ int read = 0;
+ Error err = peer->get_partial_data(&temp_buffer[0], ring_buffer.space_left(), read);
+ if (err)
+ return err;
+
+ if (read==0)
+ return OK;
+
+ int w = ring_buffer.write(&temp_buffer[0],read);
+ ERR_FAIL_COND_V(w!=read,ERR_BUG);
+
+ return OK;
+}
+
+int PacketPeerStream::get_available_packet_count() const {
+
+ _poll_buffer();
+
+ uint32_t remaining = ring_buffer.data_left();
+
+ int ofs=0;
+ int count=0;
+
+ while(remaining>=4) {
+
+ uint8_t lbuf[4];
+ ring_buffer.copy(lbuf,ofs,4);
+ uint32_t len = decode_uint32(lbuf);
+ remaining-=4;
+ ofs+=4;
+ if (len>remaining)
+ break;
+ remaining-=len;
+ ofs+=len;
+ count++;
+ }
+
+ return count;
+}
+
+Error PacketPeerStream::get_packet(const uint8_t **r_buffer,int &r_buffer_size) const {
+
+ ERR_FAIL_COND_V(peer.is_null(),ERR_UNCONFIGURED);
+ _poll_buffer();
+
+ int remaining = ring_buffer.data_left();
+ ERR_FAIL_COND_V(remaining<4,ERR_UNAVAILABLE);
+ uint8_t lbuf[4];
+ ring_buffer.copy(lbuf,0,4);
+ remaining-=4;
+ uint32_t len = decode_uint32(lbuf);
+ ERR_FAIL_COND_V(remaining<(int)len,ERR_UNAVAILABLE);
+
+ ring_buffer.read(lbuf,4); //get rid of first 4 bytes
+ ring_buffer.read(&temp_buffer[0],len); // read packet
+
+ *r_buffer=&temp_buffer[0];
+ r_buffer_size=len;
+ return OK;
+
+}
+
+Error PacketPeerStream::put_packet(const uint8_t *p_buffer,int p_buffer_size) {
+
+ ERR_FAIL_COND_V(peer.is_null(),ERR_UNCONFIGURED);
+ Error err = _poll_buffer(); //won't hurt to poll here too
+
+ if (err)
+ return err;
+
+ if (p_buffer_size==0)
+ return OK;
+
+ ERR_FAIL_COND_V( p_buffer_size<0, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V( p_buffer_size+4 > temp_buffer.size(), ERR_INVALID_PARAMETER );
+
+ encode_uint32(p_buffer_size,&temp_buffer[0]);
+ uint8_t *dst=&temp_buffer[4];
+ for(int i=0;i<p_buffer_size;i++)
+ dst[i]=p_buffer[i];
+
+ return peer->put_data(&temp_buffer[0],p_buffer_size+4);
+}
+
+int PacketPeerStream::get_max_packet_size() const {
+
+
+ return temp_buffer.size();
+}
+
+void PacketPeerStream::set_stream_peer(const Ref<StreamPeer> &p_peer) {
+
+ ERR_FAIL_COND(p_peer.is_null());
+
+ if (p_peer.ptr() != peer.ptr()) {
+ ring_buffer.advance_read(ring_buffer.data_left()); // reset the ring buffer
+ };
+
+ peer=p_peer;
+}
+
+void PacketPeerStream::set_input_buffer_max_size(int p_max_size) {
+
+ //warning may lose packets
+ ERR_EXPLAIN("Buffer in use, resizing would cause loss of data");
+ ERR_FAIL_COND(ring_buffer.data_left());
+ ring_buffer.resize(nearest_shift(p_max_size+4));
+ temp_buffer.resize(nearest_power_of_2(p_max_size+4));
+
+}
+
+PacketPeerStream::PacketPeerStream() {
+
+
+ int rbsize=GLOBAL_DEF( "core/packet_stream_peer_max_buffer_po2",(16));
+
+ ring_buffer.resize(rbsize);
+ temp_buffer.resize(1<<rbsize);
+
+
+}
diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h
new file mode 100644
index 0000000000..e9d6be4fb9
--- /dev/null
+++ b/core/io/packet_peer.h
@@ -0,0 +1,94 @@
+/*************************************************************************/
+/* packet_peer.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef PACKET_PEER_H
+#define PACKET_PEER_H
+
+#include "object.h"
+#include "io/stream_peer.h"
+#include "ring_buffer.h"
+class PacketPeer : public Reference {
+
+ OBJ_TYPE( PacketPeer, Reference );
+
+ Variant _bnd_get_var() const;
+ void _bnd_put_var(const Variant& p_var);
+
+ static void _bind_methods();
+
+public:
+
+ virtual int get_available_packet_count() const=0;
+ virtual Error get_packet(const uint8_t **r_buffer,int &r_buffer_size) const=0; ///< buffer is GONE after next get_packet
+ virtual Error put_packet(const uint8_t *p_buffer,int p_buffer_size)=0;
+
+ virtual int get_max_packet_size() const=0;
+
+ /* helpers / binders */
+
+ virtual Error get_packet_buffer(DVector<uint8_t> &r_buffer) const;
+ virtual Error put_packet_buffer(const DVector<uint8_t> &p_buffer);
+
+ virtual Error get_var(Variant &r_variant) const;
+ virtual Error put_var(const Variant& p_packet);
+
+ PacketPeer();
+ ~PacketPeer(){}
+};
+
+class PacketPeerStream : public PacketPeer {
+
+ OBJ_TYPE(PacketPeerStream,PacketPeer);
+
+ //the way the buffers work sucks, will change later
+
+ mutable Ref<StreamPeer> peer;
+ mutable RingBuffer<uint8_t> ring_buffer;
+ mutable Vector<uint8_t> temp_buffer;
+
+ Error _poll_buffer() const;
+protected:
+
+ void _set_stream_peer(REF p_peer);
+ static void _bind_methods();
+public:
+
+ virtual int get_available_packet_count() const;
+ virtual Error get_packet(const uint8_t **r_buffer,int &r_buffer_size) const;
+ virtual Error put_packet(const uint8_t *p_buffer,int p_buffer_size);
+
+ virtual int get_max_packet_size() const;
+
+ void set_stream_peer(const Ref<StreamPeer>& p_peer);
+ void set_input_buffer_max_size(int p_max_size);
+ PacketPeerStream();
+
+};
+
+
+#endif // PACKET_STREAM_H
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
new file mode 100644
index 0000000000..d2461498a6
--- /dev/null
+++ b/core/io/resource_format_binary.cpp
@@ -0,0 +1,1918 @@
+/*************************************************************************/
+/* resource_format_binary.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. */
+/*************************************************************************/
+#include "version.h"
+#include "resource_format_binary.h"
+#include "globals.h"
+#include "io/file_access_compressed.h"
+#include "io/marshalls.h"
+//#define print_bl(m_what) print_line(m_what)
+#define print_bl(m_what)
+
+
+enum {
+
+ //numbering must be different from variant, in case new variant types are added (variant must be always contiguous for jumptable optimization)
+ VARIANT_NIL=1,
+ VARIANT_BOOL=2,
+ VARIANT_INT=3,
+ VARIANT_REAL=4,
+ VARIANT_STRING=5,
+ VARIANT_VECTOR2=10,
+ VARIANT_RECT2=11,
+ VARIANT_VECTOR3=12,
+ VARIANT_PLANE=13,
+ VARIANT_QUAT=14,
+ VARIANT_AABB=15,
+ VARIANT_MATRIX3=16,
+ VARIANT_TRANSFORM=17,
+ VARIANT_MATRIX32=18,
+ VARIANT_COLOR=20,
+ VARIANT_IMAGE=21,
+ VARIANT_NODE_PATH=22,
+ VARIANT_RID=23,
+ VARIANT_OBJECT=24,
+ VARIANT_INPUT_EVENT=25,
+ VARIANT_DICTIONARY=26,
+ VARIANT_ARRAY=30,
+ VARIANT_RAW_ARRAY=31,
+ VARIANT_INT_ARRAY=32,
+ VARIANT_REAL_ARRAY=33,
+ VARIANT_STRING_ARRAY=34,
+ VARIANT_VECTOR3_ARRAY=35,
+ VARIANT_COLOR_ARRAY=36,
+ VARIANT_VECTOR2_ARRAY=37,
+
+ IMAGE_ENCODING_EMPTY=0,
+ IMAGE_ENCODING_RAW=1,
+ IMAGE_ENCODING_LOSSLESS=2,
+ IMAGE_ENCODING_LOSSY=3,
+
+ IMAGE_FORMAT_GRAYSCALE=0,
+ IMAGE_FORMAT_INTENSITY=1,
+ IMAGE_FORMAT_GRAYSCALE_ALPHA=2,
+ IMAGE_FORMAT_RGB=3,
+ IMAGE_FORMAT_RGBA=4,
+ IMAGE_FORMAT_INDEXED=5,
+ IMAGE_FORMAT_INDEXED_ALPHA=6,
+ IMAGE_FORMAT_BC1=7,
+ IMAGE_FORMAT_BC2=8,
+ IMAGE_FORMAT_BC3=9,
+ IMAGE_FORMAT_BC4=10,
+ IMAGE_FORMAT_BC5=11,
+ IMAGE_FORMAT_PVRTC2=12,
+ IMAGE_FORMAT_PVRTC2_ALPHA=13,
+ IMAGE_FORMAT_PVRTC4=14,
+ IMAGE_FORMAT_PVRTC4_ALPHA=15,
+ IMAGE_FORMAT_ETC=16,
+ IMAGE_FORMAT_CUSTOM=30,
+
+
+ OBJECT_EMPTY=0,
+ OBJECT_EXTERNAL_RESOURCE=1,
+ OBJECT_INTERNAL_RESOURCE=2,
+ FORMAT_VERSION=0
+
+
+};
+
+
+void ResourceInteractiveLoaderBinary::_advance_padding(uint32_t p_len) {
+
+ uint32_t extra = 4-(p_len%4);
+ if (extra<4) {
+ for(uint32_t i=0;i<extra;i++)
+ f->get_8(); //pad to 32
+ }
+
+}
+
+Error ResourceInteractiveLoaderBinary::parse_variant(Variant& r_v) {
+
+
+ uint32_t type = f->get_32();
+ print_bl("find property of type: "+itos(type));
+
+
+ switch(type) {
+
+ case VARIANT_NIL: {
+
+ r_v=Variant();
+ } break;
+ case VARIANT_BOOL: {
+
+ r_v=bool(f->get_32());
+ } break;
+ case VARIANT_INT: {
+
+ r_v=int(f->get_32());
+ } break;
+ case VARIANT_REAL: {
+
+ r_v=f->get_real();
+ } break;
+ case VARIANT_STRING: {
+
+ r_v=get_unicode_string();
+ } break;
+ case VARIANT_VECTOR2: {
+
+ Vector2 v;
+ v.x=f->get_real();
+ v.y=f->get_real();
+ r_v=v;
+
+ } break;
+ case VARIANT_RECT2: {
+
+ Rect2 v;
+ v.pos.x=f->get_real();
+ v.pos.y=f->get_real();
+ v.size.x=f->get_real();
+ v.size.y=f->get_real();
+ r_v=v;
+
+ } break;
+ case VARIANT_VECTOR3: {
+
+ Vector3 v;
+ v.x=f->get_real();
+ v.y=f->get_real();
+ v.z=f->get_real();
+ r_v=v;
+ } break;
+ case VARIANT_PLANE: {
+
+ Plane v;
+ v.normal.x=f->get_real();
+ v.normal.y=f->get_real();
+ v.normal.z=f->get_real();
+ v.d=f->get_real();
+ r_v=v;
+ } break;
+ case VARIANT_QUAT: {
+ Quat v;
+ v.x=f->get_real();
+ v.y=f->get_real();
+ v.z=f->get_real();
+ v.w=f->get_real();
+ r_v=v;
+
+ } break;
+ case VARIANT_AABB: {
+
+ AABB v;
+ v.pos.x=f->get_real();
+ v.pos.y=f->get_real();
+ v.pos.z=f->get_real();
+ v.size.x=f->get_real();
+ v.size.y=f->get_real();
+ v.size.z=f->get_real();
+ r_v=v;
+
+ } break;
+ case VARIANT_MATRIX32: {
+
+ Matrix32 v;
+ v.elements[0].x=f->get_real();
+ v.elements[0].y=f->get_real();
+ v.elements[1].x=f->get_real();
+ v.elements[1].y=f->get_real();
+ v.elements[2].x=f->get_real();
+ v.elements[2].y=f->get_real();
+ r_v=v;
+
+ } break;
+ case VARIANT_MATRIX3: {
+
+ Matrix3 v;
+ v.elements[0].x=f->get_real();
+ v.elements[0].y=f->get_real();
+ v.elements[0].z=f->get_real();
+ v.elements[1].x=f->get_real();
+ v.elements[1].y=f->get_real();
+ v.elements[1].z=f->get_real();
+ v.elements[2].x=f->get_real();
+ v.elements[2].y=f->get_real();
+ v.elements[2].z=f->get_real();
+ r_v=v;
+
+ } break;
+ case VARIANT_TRANSFORM: {
+
+ Transform v;
+ v.basis.elements[0].x=f->get_real();
+ v.basis.elements[0].y=f->get_real();
+ v.basis.elements[0].z=f->get_real();
+ v.basis.elements[1].x=f->get_real();
+ v.basis.elements[1].y=f->get_real();
+ v.basis.elements[1].z=f->get_real();
+ v.basis.elements[2].x=f->get_real();
+ v.basis.elements[2].y=f->get_real();
+ v.basis.elements[2].z=f->get_real();
+ v.origin.x=f->get_real();
+ v.origin.y=f->get_real();
+ v.origin.z=f->get_real();
+ r_v=v;
+ } break;
+ case VARIANT_COLOR: {
+
+ Color v;
+ v.r=f->get_real();
+ v.g=f->get_real();
+ v.b=f->get_real();
+ v.a=f->get_real();
+ r_v=v;
+
+ } break;
+ case VARIANT_IMAGE: {
+
+
+ uint32_t encoding = f->get_32();
+ if (encoding==IMAGE_ENCODING_EMPTY) {
+ r_v=Variant();
+ break;
+ } else if (encoding==IMAGE_ENCODING_RAW) {
+ uint32_t width = f->get_32();
+ uint32_t height = f->get_32();
+ uint32_t mipmaps = f->get_32();
+ uint32_t format = f->get_32();
+ Image::Format fmt;
+ switch(format) {
+
+ case IMAGE_FORMAT_GRAYSCALE: { fmt=Image::FORMAT_GRAYSCALE; } break;
+ case IMAGE_FORMAT_INTENSITY: { fmt=Image::FORMAT_INTENSITY; } break;
+ case IMAGE_FORMAT_GRAYSCALE_ALPHA: { fmt=Image::FORMAT_GRAYSCALE_ALPHA; } break;
+ case IMAGE_FORMAT_RGB: { fmt=Image::FORMAT_RGB; } break;
+ case IMAGE_FORMAT_RGBA: { fmt=Image::FORMAT_RGBA; } break;
+ case IMAGE_FORMAT_INDEXED: { fmt=Image::FORMAT_INDEXED; } break;
+ case IMAGE_FORMAT_INDEXED_ALPHA: { fmt=Image::FORMAT_INDEXED_ALPHA; } break;
+ case IMAGE_FORMAT_BC1: { fmt=Image::FORMAT_BC1; } break;
+ case IMAGE_FORMAT_BC2: { fmt=Image::FORMAT_BC2; } break;
+ case IMAGE_FORMAT_BC3: { fmt=Image::FORMAT_BC3; } break;
+ case IMAGE_FORMAT_BC4: { fmt=Image::FORMAT_BC4; } break;
+ case IMAGE_FORMAT_BC5: { fmt=Image::FORMAT_BC5; } break;
+ case IMAGE_FORMAT_PVRTC2: { fmt=Image::FORMAT_PVRTC2; } break;
+ case IMAGE_FORMAT_PVRTC2_ALPHA: { fmt=Image::FORMAT_PVRTC2_ALPHA; } break;
+ case IMAGE_FORMAT_PVRTC4: { fmt=Image::FORMAT_PVRTC4; } break;
+ case IMAGE_FORMAT_PVRTC4_ALPHA: { fmt=Image::FORMAT_PVRTC4_ALPHA; } break;
+ case IMAGE_FORMAT_ETC: { fmt=Image::FORMAT_ETC; } break;
+ case IMAGE_FORMAT_CUSTOM: { fmt=Image::FORMAT_CUSTOM; } break;
+ default: {
+
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ }
+
+ }
+
+
+ uint32_t datalen = f->get_32();
+
+ DVector<uint8_t> imgdata;
+ imgdata.resize(datalen);
+ DVector<uint8_t>::Write w = imgdata.write();
+ f->get_buffer(w.ptr(),datalen);
+ _advance_padding(datalen);
+ w=DVector<uint8_t>::Write();
+
+ r_v=Image(width,height,mipmaps,fmt,imgdata);
+
+ } else {
+ //compressed
+ DVector<uint8_t> data;
+ data.resize(f->get_32());
+ DVector<uint8_t>::Write w = data.write();
+ f->get_buffer(w.ptr(),data.size());
+ w = DVector<uint8_t>::Write();
+
+ Image img;
+
+ if (encoding==IMAGE_ENCODING_LOSSY && Image::lossy_unpacker) {
+
+ img = Image::lossy_unpacker(data);
+ } else if (encoding==IMAGE_ENCODING_LOSSLESS && Image::lossless_unpacker) {
+
+ img = Image::lossless_unpacker(data);
+ }
+ _advance_padding(data.size());
+
+
+ r_v=img;
+
+ }
+
+ } break;
+ case VARIANT_NODE_PATH: {
+
+ Vector<StringName> names;
+ Vector<StringName> subnames;
+ StringName property;
+ bool absolute;
+
+ int name_count = f->get_16();
+ uint32_t subname_count = f->get_16();
+ absolute=subname_count&0x8000;
+ subname_count&=0x7FFF;
+
+
+ for(int i=0;i<name_count;i++)
+ names.push_back(string_map[f->get_32()]);
+ for(uint32_t i=0;i<subname_count;i++)
+ subnames.push_back(string_map[f->get_32()]);
+ property=string_map[f->get_32()];
+
+ NodePath np = NodePath(names,subnames,absolute,property);
+ //print_line("got path: "+String(np));
+
+ r_v=np;
+
+ } break;
+ case VARIANT_RID: {
+
+ r_v=f->get_32();
+ } break;
+ case VARIANT_OBJECT: {
+
+ uint32_t type=f->get_32();
+
+ switch(type) {
+
+ case OBJECT_EMPTY: {
+ //do none
+
+ } break;
+ case OBJECT_INTERNAL_RESOURCE: {
+ uint32_t index=f->get_32();
+ String path = res_path+"::"+itos(index);
+ RES res = ResourceLoader::load(path);
+ if (res.is_null()) {
+ WARN_PRINT(String("Couldn't load resource: "+path).utf8().get_data());
+ }
+ r_v=res;
+
+ } break;
+ case OBJECT_EXTERNAL_RESOURCE: {
+
+ String type = get_unicode_string();
+ String path = get_unicode_string();
+
+ if (path.find("://")==-1 && path.is_rel_path()) {
+ // path is relative to file being loaded, so convert to a resource path
+ path=Globals::get_singleton()->localize_path(res_path.get_base_dir()+"/"+path);
+
+ }
+
+ RES res=ResourceLoader::load(path,type);
+
+ if (res.is_null()) {
+ WARN_PRINT(String("Couldn't load resource: "+path).utf8().get_data());
+ }
+ r_v=res;
+
+ } break;
+ default: {
+
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ } break;
+ }
+
+ } break;
+ case VARIANT_INPUT_EVENT: {
+
+ } break;
+ case VARIANT_DICTIONARY: {
+
+ uint32_t len=f->get_32();
+ Dictionary d(len&0x80000000); //last bit means shared
+ len&=0x7FFFFFFF;
+ for(uint32_t i=0;i<len;i++) {
+ Variant key;
+ Error err = parse_variant(key);
+ ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT);
+ Variant value;
+ err = parse_variant(value);
+ ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT);
+ d[key]=value;
+ }
+ r_v=d;
+ } break;
+ case VARIANT_ARRAY: {
+
+ uint32_t len=f->get_32();
+ Array a(len&0x80000000); //last bit means shared
+ len&=0x7FFFFFFF;
+ a.resize(len);
+ for(uint32_t i=0;i<len;i++) {
+ Variant val;
+ Error err = parse_variant(val);
+ ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT);
+ a[i]=val;
+ }
+ r_v=a;
+
+ } break;
+ case VARIANT_RAW_ARRAY: {
+
+ uint32_t len = f->get_32();
+
+ DVector<uint8_t> array;
+ array.resize(len);
+ DVector<uint8_t>::Write w = array.write();
+ f->get_buffer(w.ptr(),len);
+ _advance_padding(len);
+ w=DVector<uint8_t>::Write();
+ r_v=array;
+
+ } break;
+ case VARIANT_INT_ARRAY: {
+
+ uint32_t len = f->get_32();
+
+ DVector<int> array;
+ array.resize(len);
+ DVector<int>::Write w = array.write();
+ f->get_buffer((uint8_t*)w.ptr(),len*4);
+#ifdef BIG_ENDIAN_ENABLED
+ {
+ uint32_t *ptr=(uint32_t*)w.ptr();
+ for(int i=0;i<len;i++) {
+
+ ptr[i]=BSWAP32(ptr[i]);
+ }
+ }
+
+#endif
+ w=DVector<int>::Write();
+ r_v=array;
+ } break;
+ case VARIANT_REAL_ARRAY: {
+
+ uint32_t len = f->get_32();
+
+ DVector<real_t> array;
+ array.resize(len);
+ DVector<real_t>::Write w = array.write();
+ f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t));
+#ifdef BIG_ENDIAN_ENABLED
+ {
+ uint32_t *ptr=(uint32_t*)w.ptr();
+ for(int i=0;i<len;i++) {
+
+ ptr[i]=BSWAP32(ptr[i]);
+ }
+ }
+
+#endif
+
+ w=DVector<real_t>::Write();
+ r_v=array;
+ } break;
+ case VARIANT_STRING_ARRAY: {
+
+ uint32_t len = f->get_32();
+ DVector<String> array;
+ array.resize(len);
+ DVector<String>::Write w = array.write();
+ for(uint32_t i=0;i<len;i++)
+ w[i]=get_unicode_string();
+ w=DVector<String>::Write();
+ r_v=array;
+
+
+ } break;
+ case VARIANT_VECTOR2_ARRAY: {
+
+ uint32_t len = f->get_32();
+
+ DVector<Vector2> array;
+ array.resize(len);
+ DVector<Vector2>::Write w = array.write();
+ if (sizeof(Vector2)==8) {
+ f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*2);
+#ifdef BIG_ENDIAN_ENABLED
+ {
+ uint32_t *ptr=(uint32_t*)w.ptr();
+ for(int i=0;i<len*2;i++) {
+
+ ptr[i]=BSWAP32(ptr[i]);
+ }
+ }
+
+#endif
+
+ } else {
+ ERR_EXPLAIN("Vector2 size is NOT 8!");
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+ }
+ w=DVector<Vector2>::Write();
+ r_v=array;
+
+ } break;
+ case VARIANT_VECTOR3_ARRAY: {
+
+ uint32_t len = f->get_32();
+
+ DVector<Vector3> array;
+ array.resize(len);
+ DVector<Vector3>::Write w = array.write();
+ if (sizeof(Vector3)==12) {
+ f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*3);
+#ifdef BIG_ENDIAN_ENABLED
+ {
+ uint32_t *ptr=(uint32_t*)w.ptr();
+ for(int i=0;i<len*3;i++) {
+
+ ptr[i]=BSWAP32(ptr[i]);
+ }
+ }
+
+#endif
+
+ } else {
+ ERR_EXPLAIN("Vector3 size is NOT 12!");
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+ }
+ w=DVector<Vector3>::Write();
+ r_v=array;
+
+ } break;
+ case VARIANT_COLOR_ARRAY: {
+
+ uint32_t len = f->get_32();
+
+ DVector<Color> array;
+ array.resize(len);
+ DVector<Color>::Write w = array.write();
+ if (sizeof(Color)==16) {
+ f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*4);
+#ifdef BIG_ENDIAN_ENABLED
+ {
+ uint32_t *ptr=(uint32_t*)w.ptr();
+ for(int i=0;i<len*4;i++) {
+
+ ptr[i]=BSWAP32(ptr[i]);
+ }
+ }
+
+#endif
+
+ } else {
+ ERR_EXPLAIN("Color size is NOT 16!");
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+ }
+ w=DVector<Color>::Write();
+ r_v=array;
+ } break;
+
+ default: {
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ } break;
+ }
+
+
+
+ return OK; //never reach anyway
+
+}
+
+
+void ResourceInteractiveLoaderBinary::set_local_path(const String& p_local_path) {
+
+ res_path=p_local_path;
+}
+
+Ref<Resource> ResourceInteractiveLoaderBinary::get_resource(){
+
+
+ return resource;
+}
+Error ResourceInteractiveLoaderBinary::poll(){
+
+ if (error!=OK)
+ return error;
+
+
+ int s = stage;
+
+ if (s<external_resources.size()) {
+
+ RES res = ResourceLoader::load(external_resources[s].path,external_resources[s].type);
+ if (res.is_null()) {
+
+ if (!ResourceLoader::get_abort_on_missing_resources()) {
+
+ ResourceLoader::notify_load_error("Resource Not Found: "+external_resources[s].path);
+ } else {
+
+
+ error=ERR_FILE_CORRUPT;
+ ERR_EXPLAIN("Can't load dependency: "+external_resources[s].path);
+ ERR_FAIL_V(error);
+ }
+
+ } else {
+ resource_cache.push_back(res);
+ }
+
+ stage++;
+ return OK;
+ }
+
+ s-=external_resources.size();
+
+
+ if (s>=internal_resources.size()) {
+
+ error=ERR_BUG;
+ ERR_FAIL_COND_V(s>=internal_resources.size(),error);
+ }
+
+ bool main = s==(internal_resources.size()-1);
+
+ //maybe it is loaded already
+ String path;
+
+
+
+ if (!main) {
+
+ path=internal_resources[s].path;
+ if (path.begins_with("local://"))
+ path=path.replace("local://",res_path+"::");
+
+
+
+ if (ResourceCache::has(path)) {
+ //already loaded, don't do anything
+ stage++;
+ error=OK;
+ return error;
+ }
+ } else {
+
+ path=res_path;
+ }
+
+ uint64_t offset = internal_resources[s].offset;
+
+ f->seek(offset);
+
+ String t = get_unicode_string();
+
+ Object *obj = ObjectTypeDB::instance(t);
+ if (!obj) {
+ error=ERR_FILE_CORRUPT;
+ ERR_EXPLAIN(local_path+":Resource of unrecognized type in file: "+t);
+ }
+ ERR_FAIL_COND_V(!obj,ERR_FILE_CORRUPT);
+
+ Resource *r = obj->cast_to<Resource>();
+ if (!r) {
+ error=ERR_FILE_CORRUPT;
+ memdelete(obj); //bye
+ ERR_EXPLAIN(local_path+":Resoucre type in resource field not a resource, type is: "+obj->get_type());
+ ERR_FAIL_COND_V(!r,ERR_FILE_CORRUPT);
+ }
+
+ RES res = RES( r );
+
+ r->set_path(path);
+
+ int pc = f->get_32();
+
+ //set properties
+
+ for(int i=0;i<pc;i++) {
+
+ uint32_t name_idx = f->get_32();
+ if (name_idx>=(uint32_t)string_map.size()) {
+ error=ERR_FILE_CORRUPT;
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ }
+
+ Variant value;
+
+ error = parse_variant(value);
+ if (error)
+ return error;
+
+ res->set(string_map[name_idx],value);
+ }
+#ifdef TOOLS_ENABLED
+ res->set_edited(false);
+#endif
+ stage++;
+
+ resource_cache.push_back(res);
+
+ if (main) {
+ if (importmd_ofs) {
+
+ f->seek(importmd_ofs);
+ Ref<ResourceImportMetadata> imd = memnew( ResourceImportMetadata );
+ imd->set_editor(get_unicode_string());
+ int sc = f->get_32();
+ for(int i=0;i<sc;i++) {
+
+ String src = get_unicode_string();
+ String md5 = get_unicode_string();
+ imd->add_source(src,md5);
+ }
+ int pc = f->get_32();
+
+ for(int i=0;i<pc;i++) {
+
+ String name = get_unicode_string();
+ Variant val;
+ parse_variant(val);
+ imd->set_option(name,val);
+ }
+ res->set_import_metadata(imd);
+
+ }
+ f->close();
+ resource=res;
+ error=ERR_FILE_EOF;
+
+ } else {
+ error=OK;
+ }
+
+ return OK;
+
+}
+int ResourceInteractiveLoaderBinary::get_stage() const{
+
+ return stage;
+}
+int ResourceInteractiveLoaderBinary::get_stage_count() const {
+
+ return external_resources.size()+internal_resources.size();
+}
+
+String ResourceInteractiveLoaderBinary::get_unicode_string() {
+
+ int len = f->get_32();
+ if (len>str_buf.size()) {
+ str_buf.resize(len);
+ }
+ f->get_buffer((uint8_t*)&str_buf[0],len);
+ String s;
+ s.parse_utf8(&str_buf[0]);
+ return s;
+}
+
+
+
+void ResourceInteractiveLoaderBinary::get_dependencies(FileAccess *p_f,List<String> *p_dependencies) {
+
+ open(p_f);
+ if (error)
+ return;
+
+ for(int i=0;i<external_resources.size();i++) {
+
+ p_dependencies->push_back(external_resources[i].path);
+ }
+
+}
+
+
+
+
+void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) {
+
+
+ error=OK;
+
+ f=p_f;
+ uint8_t header[4];
+ f->get_buffer(header,4);
+ if (header[0]=='R' && header[1]=='S' && header[2]=='C' && header[3]=='C') {
+ //compressed
+ FileAccessCompressed *fac = memnew( FileAccessCompressed );
+ fac->open_after_magic(f);
+ f=fac;
+
+ } else if (header[0]!='R' || header[1]!='S' || header[2]!='R' || header[3]!='C') {
+ //not normal
+
+ error=ERR_FILE_UNRECOGNIZED;
+ ERR_EXPLAIN("Unrecognized binary resource file: "+local_path);
+ ERR_FAIL_V();
+ }
+
+ bool big_endian = f->get_32();
+#ifdef BIG_ENDIAN_ENABLED
+ endian_swap = !big_endian;
+#else
+ bool endian_swap = big_endian;
+#endif
+
+ bool use_real64 = f->get_32();
+
+ f->set_endian_swap(big_endian!=0); //read big endian if saved as big endian
+
+ uint32_t ver_major=f->get_32();
+ uint32_t ver_minor=f->get_32();
+ uint32_t ver_format=f->get_32();
+
+ print_bl("big endian: "+itos(big_endian));
+ print_bl("endian swap: "+itos(endian_swap));
+ print_bl("real64: "+itos(use_real64));
+ print_bl("major: "+itos(ver_major));
+ print_bl("minor: "+itos(ver_minor));
+ print_bl("format: "+itos(ver_format));
+
+ if (ver_format<FORMAT_VERSION || ver_major>VERSION_MAJOR || (ver_major==VERSION_MAJOR && ver_minor>VERSION_MINOR)) {
+
+ f->close();
+ ERR_EXPLAIN("File Format '"+itos(FORMAT_VERSION)+"."+itos(ver_major)+"."+itos(ver_minor)+"' is too new! Please upgrade to a a new engine version: "+local_path);
+ ERR_FAIL();
+
+ }
+
+ type=get_unicode_string();
+
+ print_bl("type: "+type);
+
+ importmd_ofs = f->get_64();
+ for(int i=0;i<14;i++)
+ f->get_32(); //skip a few reserved fields
+
+ uint32_t string_table_size=f->get_32();
+ string_map.resize(string_table_size);
+ for(uint32_t i=0;i<string_table_size;i++) {
+
+ StringName s = get_unicode_string();
+ string_map[i]=s;
+ }
+
+ print_bl("strings: "+itos(string_table_size));
+
+ uint32_t ext_resources_size=f->get_32();
+ for(uint32_t i=0;i<ext_resources_size;i++) {
+
+ ExtResoucre er;
+ er.type=get_unicode_string();
+ er.path=get_unicode_string();
+ external_resources.push_back(er);
+
+ }
+
+ print_bl("ext resources: "+itos(ext_resources_size));
+ uint32_t int_resources_size=f->get_32();
+
+ for(uint32_t i=0;i<int_resources_size;i++) {
+
+ IntResoucre ir;
+ ir.path=get_unicode_string();
+ ir.offset=f->get_64();
+ internal_resources.push_back(ir);
+ }
+
+ print_bl("int resources: "+itos(int_resources_size));
+
+
+ if (f->eof_reached()) {
+
+ error=ERR_FILE_CORRUPT;
+ ERR_EXPLAIN("Premature End Of File: "+local_path);
+ ERR_FAIL();
+ }
+
+}
+
+String ResourceInteractiveLoaderBinary::recognize(FileAccess *p_f) {
+
+ error=OK;
+
+
+ f=p_f;
+ uint8_t header[4];
+ f->get_buffer(header,4);
+ if (header[0]=='R' && header[1]=='S' && header[2]=='C' && header[3]=='C') {
+ //compressed
+ FileAccessCompressed *fac = memnew( FileAccessCompressed );
+ fac->open_after_magic(f);
+ f=fac;
+
+ } else if (header[0]!='R' || header[1]!='S' || header[2]!='R' || header[3]!='C') {
+ //not normal
+ return "";
+ }
+
+ bool big_endian = f->get_32();
+#ifdef BIG_ENDIAN_ENABLED
+ endian_swap = !big_endian;
+#else
+ bool endian_swap = big_endian;
+#endif
+
+ bool use_real64 = f->get_32();
+
+ f->set_endian_swap(big_endian!=0); //read big endian if saved as big endian
+
+ uint32_t ver_major=f->get_32();
+ uint32_t ver_minor=f->get_32();
+ uint32_t ver_format=f->get_32();
+
+ if (ver_format<FORMAT_VERSION || ver_major>VERSION_MAJOR || (ver_major==VERSION_MAJOR && ver_minor>VERSION_MINOR)) {
+
+ f->close();
+ return "";
+ }
+
+ String type=get_unicode_string();
+
+ return type;
+}
+
+ResourceInteractiveLoaderBinary::ResourceInteractiveLoaderBinary() {
+
+ f=NULL;
+ stage=0;
+ endian_swap=false;
+ use_real64=false;
+ error=OK;
+}
+
+ResourceInteractiveLoaderBinary::~ResourceInteractiveLoaderBinary() {
+
+ if (f)
+ memdelete(f);
+}
+
+
+Ref<ResourceInteractiveLoader> ResourceFormatLoaderBinary::load_interactive(const String &p_path) {
+
+
+ Error err;
+ FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err);
+
+ if (err!=OK) {
+
+ ERR_FAIL_COND_V(err!=OK,Ref<ResourceInteractiveLoader>());
+ }
+
+ Ref<ResourceInteractiveLoaderBinary> ria = memnew( ResourceInteractiveLoaderBinary );
+ ria->local_path=Globals::get_singleton()->localize_path(p_path);
+ ria->res_path=ria->local_path;
+// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
+ ria->open(f);
+
+
+ return ria;
+}
+
+void ResourceFormatLoaderBinary::get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const {
+
+ if (p_type=="") {
+ get_recognized_extensions(p_extensions);
+ return;
+ }
+
+ List<String> extensions;
+ ObjectTypeDB::get_extensions_for_type(p_type,&extensions);
+
+ extensions.sort();
+
+ for(List<String>::Element *E=extensions.front();E;E=E->next()) {
+ String ext = E->get().to_lower();
+ if (ext=="res")
+ continue;
+// p_extensions->push_back("x"+ext);
+ p_extensions->push_back(ext);
+ }
+
+ p_extensions->push_back("res");
+
+}
+void ResourceFormatLoaderBinary::get_recognized_extensions(List<String> *p_extensions) const{
+
+ List<String> extensions;
+ ObjectTypeDB::get_resource_base_extensions(&extensions);
+ extensions.sort();
+
+ for(List<String>::Element *E=extensions.front();E;E=E->next()) {
+ String ext = E->get().to_lower();
+ if (ext=="res")
+ continue;
+ p_extensions->push_back(ext);
+ }
+
+ p_extensions->push_back("res");
+}
+
+bool ResourceFormatLoaderBinary::handles_type(const String& p_type) const{
+
+
+ return true; //handles all
+}
+
+Error ResourceFormatLoaderBinary::load_import_metadata(const String &p_path, Ref<ResourceImportMetadata>& r_var) const {
+
+
+ FileAccess *f = FileAccess::open(p_path,FileAccess::READ);
+ if (!f) {
+ return ERR_FILE_CANT_OPEN;
+ }
+
+ Ref<ResourceInteractiveLoaderBinary> ria = memnew( ResourceInteractiveLoaderBinary );
+ ria->local_path=Globals::get_singleton()->localize_path(p_path);
+ ria->res_path=ria->local_path;
+// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
+ ria->recognize(f);
+ if(ria->error!=OK)
+ return ERR_FILE_UNRECOGNIZED;
+ f=ria->f;
+ uint64_t imp_ofs = f->get_64();
+
+ if (imp_ofs==0)
+ return ERR_UNAVAILABLE;
+
+ f->seek(imp_ofs);
+ Ref<ResourceImportMetadata> imd = memnew( ResourceImportMetadata );
+ imd->set_editor(ria->get_unicode_string());
+ int sc = f->get_32();
+ for(int i=0;i<sc;i++) {
+
+ String src = ria->get_unicode_string();
+ String md5 = ria->get_unicode_string();
+ imd->add_source(src,md5);
+ }
+ int pc = f->get_32();
+
+ for(int i=0;i<pc;i++) {
+
+ String name = ria->get_unicode_string();
+ Variant val;
+ ria->parse_variant(val);
+ imd->set_option(name,val);
+ }
+
+ r_var=imd;
+
+ return OK;
+
+}
+
+
+void ResourceFormatLoaderBinary::get_dependencies(const String& p_path,List<String> *p_dependencies) {
+
+ FileAccess *f = FileAccess::open(p_path,FileAccess::READ);
+ ERR_FAIL_COND(!f);
+
+ Ref<ResourceInteractiveLoaderBinary> ria = memnew( ResourceInteractiveLoaderBinary );
+ ria->local_path=Globals::get_singleton()->localize_path(p_path);
+ ria->res_path=ria->local_path;
+// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
+ ria->get_dependencies(f,p_dependencies);
+}
+
+
+String ResourceFormatLoaderBinary::get_resource_type(const String &p_path) const {
+
+ FileAccess *f = FileAccess::open(p_path,FileAccess::READ);
+ if (!f) {
+ return ""; //could not rwead
+ }
+
+ Ref<ResourceInteractiveLoaderBinary> ria = memnew( ResourceInteractiveLoaderBinary );
+ ria->local_path=Globals::get_singleton()->localize_path(p_path);
+ ria->res_path=ria->local_path;
+// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
+ String r = ria->recognize(f);
+ return r;
+
+
+}
+
+
+
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////
+
+
+void ResourceFormatSaverBinaryInstance::_pad_buffer(int p_bytes) {
+
+ int extra = 4-(p_bytes%4);
+ if (extra<4) {
+ for(int i=0;i<extra;i++)
+ f->store_8(0); //pad to 32
+ }
+
+}
+
+
+void ResourceFormatSaverBinaryInstance::write_variant(const Variant& p_property,const PropertyInfo& p_hint) {
+
+ switch(p_property.get_type()) {
+
+ case Variant::NIL: {
+
+ f->store_32(VARIANT_NIL);
+ // don't store anything
+ } break;
+ case Variant::BOOL: {
+
+ f->store_32(VARIANT_BOOL);
+ bool val=p_property;
+ f->store_32(val);
+ } break;
+ case Variant::INT: {
+
+ f->store_32(VARIANT_INT);
+ int val=p_property;
+ f->store_32(val);
+ } break;
+ case Variant::REAL: {
+
+ f->store_32(VARIANT_REAL);
+ real_t val=p_property;
+ f->store_real(val);
+
+ } break;
+ case Variant::STRING: {
+
+ f->store_32(VARIANT_STRING);
+ String val=p_property;
+ save_unicode_string(val);
+
+ } break;
+ case Variant::VECTOR2: {
+
+ f->store_32(VARIANT_VECTOR2);
+ Vector2 val=p_property;
+ f->store_real(val.x);
+ f->store_real(val.y);
+
+ } break;
+ case Variant::RECT2: {
+
+ f->store_32(VARIANT_RECT2);
+ Rect2 val=p_property;
+ f->store_real(val.pos.x);
+ f->store_real(val.pos.y);
+ f->store_real(val.size.x);
+ f->store_real(val.size.y);
+
+ } break;
+ case Variant::VECTOR3: {
+
+ f->store_32(VARIANT_VECTOR3);
+ Vector3 val=p_property;
+ f->store_real(val.x);
+ f->store_real(val.y);
+ f->store_real(val.z);
+
+ } break;
+ case Variant::PLANE: {
+
+ f->store_32(VARIANT_PLANE);
+ Plane val=p_property;
+ f->store_real(val.normal.x);
+ f->store_real(val.normal.y);
+ f->store_real(val.normal.z);
+ f->store_real(val.d);
+
+ } break;
+ case Variant::QUAT: {
+
+ f->store_32(VARIANT_QUAT);
+ Quat val=p_property;
+ f->store_real(val.x);
+ f->store_real(val.y);
+ f->store_real(val.z);
+ f->store_real(val.w);
+
+ } break;
+ case Variant::_AABB: {
+
+ f->store_32(VARIANT_AABB);
+ AABB val=p_property;
+ f->store_real(val.pos.x);
+ f->store_real(val.pos.y);
+ f->store_real(val.pos.z);
+ f->store_real(val.size.x);
+ f->store_real(val.size.y);
+ f->store_real(val.size.z);
+
+ } break;
+ case Variant::MATRIX32: {
+
+ f->store_32(VARIANT_MATRIX32);
+ Matrix32 val=p_property;
+ f->store_real(val.elements[0].x);
+ f->store_real(val.elements[0].y);
+ f->store_real(val.elements[1].x);
+ f->store_real(val.elements[1].y);
+ f->store_real(val.elements[2].x);
+ f->store_real(val.elements[2].y);
+
+ } break;
+ case Variant::MATRIX3: {
+
+ f->store_32(VARIANT_MATRIX3);
+ Matrix3 val=p_property;
+ f->store_real(val.elements[0].x);
+ f->store_real(val.elements[0].y);
+ f->store_real(val.elements[0].z);
+ f->store_real(val.elements[1].x);
+ f->store_real(val.elements[1].y);
+ f->store_real(val.elements[1].z);
+ f->store_real(val.elements[2].x);
+ f->store_real(val.elements[2].y);
+ f->store_real(val.elements[2].z);
+
+ } break;
+ case Variant::TRANSFORM: {
+
+ f->store_32(VARIANT_TRANSFORM);
+ Transform val=p_property;
+ f->store_real(val.basis.elements[0].x);
+ f->store_real(val.basis.elements[0].y);
+ f->store_real(val.basis.elements[0].z);
+ f->store_real(val.basis.elements[1].x);
+ f->store_real(val.basis.elements[1].y);
+ f->store_real(val.basis.elements[1].z);
+ f->store_real(val.basis.elements[2].x);
+ f->store_real(val.basis.elements[2].y);
+ f->store_real(val.basis.elements[2].z);
+ f->store_real(val.origin.x);
+ f->store_real(val.origin.y);
+ f->store_real(val.origin.z);
+
+ } break;
+ case Variant::COLOR: {
+
+ f->store_32(VARIANT_COLOR);
+ Color val=p_property;
+ f->store_real(val.r);
+ f->store_real(val.g);
+ f->store_real(val.b);
+ f->store_real(val.a);
+
+ } break;
+ case Variant::IMAGE: {
+
+ f->store_32(VARIANT_IMAGE);
+ Image val =p_property;
+ if (val.empty()) {
+ f->store_32(IMAGE_ENCODING_EMPTY);
+ break;
+ }
+
+ int encoding=IMAGE_ENCODING_RAW;
+ float quality=0.7;
+
+ if (val.get_format() <= Image::FORMAT_INDEXED_ALPHA) {
+ //can only compress uncompressed stuff
+
+ if (p_hint.hint==PROPERTY_HINT_IMAGE_COMPRESS_LOSSY && Image::lossy_packer) {
+ encoding=IMAGE_ENCODING_LOSSY;
+ float qs=p_hint.hint_string.to_double();
+ if (qs!=0.0)
+ quality=qs;
+
+ } else if (p_hint.hint==PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS && Image::lossless_packer) {
+ encoding=IMAGE_ENCODING_LOSSLESS;
+
+ }
+ }
+
+ f->store_32(encoding); //raw encoding
+
+ if (encoding==IMAGE_ENCODING_RAW) {
+
+
+ f->store_32(val.get_width());
+ f->store_32(val.get_height());
+ f->store_32(val.get_mipmaps());
+ switch(val.get_format()) {
+
+ case Image::FORMAT_GRAYSCALE: f->store_32(IMAGE_FORMAT_GRAYSCALE ); break; ///< one byte per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255
+ case Image::FORMAT_INTENSITY: f->store_32(IMAGE_FORMAT_INTENSITY ); break; ///< one byte per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255
+ case Image::FORMAT_GRAYSCALE_ALPHA: f->store_32(IMAGE_FORMAT_GRAYSCALE_ALPHA ); break; ///< two bytes per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255. alpha 0-255
+ case Image::FORMAT_RGB: f->store_32(IMAGE_FORMAT_RGB ); break; ///< one byte R: f->store_32(IMAGE_FORMAT_ ); break; one byte G: f->store_32(IMAGE_FORMAT_ ); break; one byte B
+ case Image::FORMAT_RGBA: f->store_32(IMAGE_FORMAT_RGBA ); break; ///< one byte R: f->store_32(IMAGE_FORMAT_ ); break; one byte G: f->store_32(IMAGE_FORMAT_ ); break; one byte B: f->store_32(IMAGE_FORMAT_ ); break; one byte A
+ case Image::FORMAT_INDEXED: f->store_32(IMAGE_FORMAT_INDEXED ); break; ///< index byte 0-256: f->store_32(IMAGE_FORMAT_ ); break; and after image end: f->store_32(IMAGE_FORMAT_ ); break; 256*3 bytes of palette
+ case Image::FORMAT_INDEXED_ALPHA: f->store_32(IMAGE_FORMAT_INDEXED_ALPHA ); break; ///< index byte 0-256: f->store_32(IMAGE_FORMAT_ ); break; and after image end: f->store_32(IMAGE_FORMAT_ ); break; 256*4 bytes of palette (alpha)
+ case Image::FORMAT_BC1: f->store_32(IMAGE_FORMAT_BC1 ); break; // DXT1
+ case Image::FORMAT_BC2: f->store_32(IMAGE_FORMAT_BC2 ); break; // DXT3
+ case Image::FORMAT_BC3: f->store_32(IMAGE_FORMAT_BC3 ); break; // DXT5
+ case Image::FORMAT_BC4: f->store_32(IMAGE_FORMAT_BC4 ); break; // ATI1
+ case Image::FORMAT_BC5: f->store_32(IMAGE_FORMAT_BC5 ); break; // ATI2
+ case Image::FORMAT_PVRTC2: f->store_32(IMAGE_FORMAT_PVRTC2 ); break;
+ case Image::FORMAT_PVRTC2_ALPHA: f->store_32(IMAGE_FORMAT_PVRTC2_ALPHA ); break;
+ case Image::FORMAT_PVRTC4: f->store_32(IMAGE_FORMAT_PVRTC4 ); break;
+ case Image::FORMAT_PVRTC4_ALPHA: f->store_32(IMAGE_FORMAT_PVRTC4_ALPHA ); break;
+ case Image::FORMAT_ETC: f->store_32(IMAGE_FORMAT_ETC); break;
+ case Image::FORMAT_CUSTOM: f->store_32(IMAGE_FORMAT_CUSTOM ); break;
+ default: {}
+
+ }
+
+ int dlen = val.get_data().size();
+ f->store_32(dlen);
+ DVector<uint8_t>::Read r = val.get_data().read();
+ f->store_buffer(r.ptr(),dlen);
+ _pad_buffer(dlen);
+ } else {
+
+ DVector<uint8_t> data;
+ if (encoding==IMAGE_ENCODING_LOSSY) {
+ data=Image::lossy_packer(val,quality);
+
+ } else if (encoding==IMAGE_ENCODING_LOSSLESS) {
+ data=Image::lossless_packer(val);
+
+ }
+
+ int ds=data.size();
+ f->store_32(ds);
+ if (ds>0) {
+ DVector<uint8_t>::Read r = data.read();
+ f->store_buffer(r.ptr(),ds);
+
+ _pad_buffer(ds);
+
+ }
+ }
+
+ } break;
+ case Variant::NODE_PATH: {
+ f->store_32(VARIANT_NODE_PATH);
+ NodePath np=p_property;
+ f->store_16(np.get_name_count());
+ uint16_t snc = np.get_subname_count();
+ if (np.is_absolute())
+ snc|=0x8000;
+ f->store_16(snc);
+ for(int i=0;i<np.get_name_count();i++)
+ f->store_32(get_string_index(np.get_name(i)));
+ for(int i=0;i<np.get_subname_count();i++)
+ f->store_32(get_string_index(np.get_subname(i)));
+ f->store_32(get_string_index(np.get_property()));
+
+ } break;
+ case Variant::_RID: {
+
+ f->store_32(VARIANT_RID);
+ WARN_PRINT("Can't save RIDs");
+ RID val = p_property;
+ f->store_32(val.get_id());
+ } break;
+ case Variant::OBJECT: {
+
+ f->store_32(VARIANT_OBJECT);
+ RES res = p_property;
+ if (res.is_null()) {
+ f->store_32(OBJECT_EMPTY);
+ return; // don't save it
+ }
+
+ if (res->get_path().length() && res->get_path().find("::")==-1) {
+ f->store_32(OBJECT_EXTERNAL_RESOURCE);
+ save_unicode_string(res->get_save_type());
+ String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path();
+ if (no_extensions)
+ path=path.basename()+".*";
+ save_unicode_string(path);
+ } else {
+
+ if (!resource_map.has(res)) {
+ f->store_32(OBJECT_EMPTY);
+ ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?");
+ ERR_FAIL();
+ }
+
+ f->store_32(OBJECT_INTERNAL_RESOURCE);
+ f->store_32(resource_map[res]);
+ //internal resource
+ }
+
+
+ } break;
+ case Variant::INPUT_EVENT: {
+
+ f->store_32(VARIANT_INPUT_EVENT);
+ WARN_PRINT("Can't save InputEvent (maybe it could..)");
+ } break;
+ case Variant::DICTIONARY: {
+
+ f->store_32(VARIANT_DICTIONARY);
+ Dictionary d = p_property;
+ f->store_32(uint32_t(d.size())|(d.is_shared()?0x80000000:0));
+
+ List<Variant> keys;
+ d.get_key_list(&keys);
+
+ for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+ //if (!_check_type(dict[E->get()]))
+ // continue;
+
+ write_variant(E->get());
+ write_variant(d[E->get()]);
+ }
+
+
+ } break;
+ case Variant::ARRAY: {
+
+ f->store_32(VARIANT_ARRAY);
+ Array a=p_property;
+ f->store_32(uint32_t(a.size())|(a.is_shared()?0x80000000:0));
+ for(int i=0;i<a.size();i++) {
+
+ write_variant(a[i]);
+ }
+
+ } break;
+ case Variant::RAW_ARRAY: {
+
+ f->store_32(VARIANT_RAW_ARRAY);
+ DVector<uint8_t> arr = p_property;
+ int len=arr.size();
+ f->store_32(len);
+ DVector<uint8_t>::Read r = arr.read();
+ f->store_buffer(r.ptr(),len);
+ _pad_buffer(len);
+
+ } break;
+ case Variant::INT_ARRAY: {
+
+ f->store_32(VARIANT_INT_ARRAY);
+ DVector<int> arr = p_property;
+ int len=arr.size();
+ f->store_32(len);
+ DVector<int>::Read r = arr.read();
+ for(int i=0;i<len;i++)
+ f->store_32(r[i]);
+
+ } break;
+ case Variant::REAL_ARRAY: {
+
+ f->store_32(VARIANT_REAL_ARRAY);
+ DVector<real_t> arr = p_property;
+ int len=arr.size();
+ f->store_32(len);
+ DVector<real_t>::Read r = arr.read();
+ for(int i=0;i<len;i++) {
+ f->store_real(r[i]);
+ }
+
+ } break;
+ case Variant::STRING_ARRAY: {
+
+ f->store_32(VARIANT_STRING_ARRAY);
+ DVector<String> arr = p_property;
+ int len=arr.size();
+ f->store_32(len);
+ DVector<String>::Read r = arr.read();
+ for(int i=0;i<len;i++) {
+ save_unicode_string(r[i]);
+ }
+
+ } break;
+ case Variant::VECTOR3_ARRAY: {
+
+ f->store_32(VARIANT_VECTOR3_ARRAY);
+ DVector<Vector3> arr = p_property;
+ int len=arr.size();
+ f->store_32(len);
+ DVector<Vector3>::Read r = arr.read();
+ for(int i=0;i<len;i++) {
+ f->store_real(r[i].x);
+ f->store_real(r[i].y);
+ f->store_real(r[i].z);
+ }
+
+ } break;
+ case Variant::VECTOR2_ARRAY: {
+
+ f->store_32(VARIANT_VECTOR2_ARRAY);
+ DVector<Vector2> arr = p_property;
+ int len=arr.size();
+ f->store_32(len);
+ DVector<Vector2>::Read r = arr.read();
+ for(int i=0;i<len;i++) {
+ f->store_real(r[i].x);
+ f->store_real(r[i].y);
+ }
+
+ } break;
+ case Variant::COLOR_ARRAY: {
+
+ f->store_32(VARIANT_COLOR_ARRAY);
+ DVector<Color> arr = p_property;
+ int len=arr.size();
+ f->store_32(len);
+ DVector<Color>::Read r = arr.read();
+ for(int i=0;i<len;i++) {
+ f->store_real(r[i].r);
+ f->store_real(r[i].g);
+ f->store_real(r[i].b);
+ f->store_real(r[i].a);
+ }
+
+ } break;
+ default: {
+
+ ERR_EXPLAIN("Invalid variant");
+ ERR_FAIL();
+ }
+ }
+}
+
+
+void ResourceFormatSaverBinaryInstance::_find_resources(const Variant& p_variant,bool p_main) {
+
+
+ switch(p_variant.get_type()) {
+ case Variant::OBJECT: {
+
+
+ RES res = p_variant.operator RefPtr();
+
+ if (res.is_null())
+ return;
+
+ if (!p_main && (!bundle_resources ) && res->get_path().length() && res->get_path().find("::") == -1 ) {
+ external_resources.insert(res);
+ return;
+ }
+
+
+ if (resource_map.has(res))
+ return;
+
+ List<PropertyInfo> property_list;
+
+ res->get_property_list(&property_list);
+
+ for(List<PropertyInfo>::Element *E=property_list.front();E;E=E->next()) {
+
+ if (E->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && E->get().usage&PROPERTY_USAGE_BUNDLE)) {
+
+ _find_resources(res->get(E->get().name));
+ }
+ }
+
+ resource_map[ res ] = saved_resources.size();
+ saved_resources.push_back(res);
+
+ } break;
+
+ case Variant::ARRAY: {
+
+ Array varray=p_variant;
+ int len=varray.size();
+ for(int i=0;i<len;i++) {
+
+ Variant v=varray.get(i);
+ _find_resources(v);
+ }
+
+ } break;
+
+ case Variant::DICTIONARY: {
+
+ Dictionary d=p_variant;
+ List<Variant> keys;
+ d.get_key_list(&keys);
+ for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+ _find_resources(E->get());
+ Variant v = d[E->get()];
+ _find_resources(v);
+ }
+ } break;
+ case Variant::NODE_PATH: {
+ //take the chance and save node path strings
+ NodePath np = p_variant;
+ for(int i=0;i<np.get_name_count();i++)
+ get_string_index(np.get_name(i));
+ for(int i=0;i<np.get_subname_count();i++)
+ get_string_index(np.get_subname(i));
+ get_string_index(np.get_property());
+
+
+ } break;
+
+ default: {}
+ }
+
+}
+#if 0
+Error ResourceFormatSaverBinary::_save_obj(const Object *p_object,SavedObject *so) {
+
+ //use classic way
+ List<PropertyInfo> property_list;
+ p_object->get_property_list( &property_list );
+
+ for(List<PropertyInfo>::Element *E=property_list.front();E;E=E->next()) {
+
+ if (skip_editor && E->get().name.begins_with("__editor"))
+ continue;
+ if (E->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && E->get().usage&PROPERTY_USAGE_BUNDLE)) {
+
+ SavedObject::SavedProperty sp;
+ sp.name_idx=get_string_index(E->get().name);
+ sp.value = p_object->get(E->get().name);
+ _find_resources(sp.value);
+ so->properties.push_back(sp);
+ }
+ }
+
+ return OK;
+
+}
+
+
+
+Error ResourceFormatSaverBinary::save(const Object *p_object,const Variant &p_meta) {
+
+ ERR_FAIL_COND_V(!f,ERR_UNCONFIGURED);
+ ERR_EXPLAIN("write_object should supply either an object, a meta, or both");
+ ERR_FAIL_COND_V(!p_object && p_meta.get_type()==Variant::NIL, ERR_INVALID_PARAMETER);
+
+ SavedObject *so = memnew( SavedObject );
+
+ if (p_object)
+ so->type=p_object->get_type();
+
+ _find_resources(p_meta);
+ so->meta=p_meta;
+ Error err = _save_obj(p_object,so);
+ ERR_FAIL_COND_V( err, ERR_INVALID_DATA );
+
+ saved_objects.push_back(so);
+
+ return OK;
+}
+#endif
+
+void ResourceFormatSaverBinaryInstance::save_unicode_string(const String& p_string) {
+
+
+ CharString utf8 = p_string.utf8();
+ f->store_32(utf8.length()+1);
+ f->store_buffer((const uint8_t*)utf8.get_data(),utf8.length()+1);
+}
+
+int ResourceFormatSaverBinaryInstance::get_string_index(const String& p_string) {
+
+ StringName s=p_string;
+ if (string_map.has(s))
+ return string_map[s];
+
+ string_map[s]=strings.size();
+ strings.push_back(s);
+ return strings.size()-1;
+}
+
+
+Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_resource,uint32_t p_flags) {
+
+ Error err;
+ if (p_flags&ResourceSaver::FLAG_COMPRESS) {
+ FileAccessCompressed *fac = memnew( FileAccessCompressed );
+ fac->configure("RSCC");
+ f=fac;
+ err = fac->_open(p_path,FileAccess::WRITE);
+ if (err)
+ memdelete(f);
+
+ } else {
+ f=FileAccess::open(p_path,FileAccess::WRITE,&err);
+ }
+
+
+ ERR_FAIL_COND_V(err,err);
+ FileAccessRef _fref(f);
+
+
+ relative_paths=p_flags&ResourceSaver::FLAG_RELATIVE_PATHS;
+ skip_editor=p_flags&ResourceSaver::FLAG_OMIT_EDITOR_PROPERTIES;
+ bundle_resources=p_flags&ResourceSaver::FLAG_BUNDLE_RESOURCES;
+ big_endian=p_flags&ResourceSaver::FLAG_SAVE_BIG_ENDIAN;
+ no_extensions=p_flags&ResourceSaver::FLAG_NO_EXTENSION;
+
+ local_path=p_path.get_base_dir();
+ //bin_meta_idx = get_string_index("__bin_meta__"); //is often used, so create
+
+ _find_resources(p_resource,true);
+
+ if (!(p_flags&ResourceSaver::FLAG_COMPRESS)) {
+ //save header compressed
+ static const uint8_t header[4]={'R','S','R','C'};
+ f->store_buffer(header,4);
+ }
+
+ if (big_endian) {
+ f->store_32(1);
+ f->set_endian_swap(true);
+ } else
+ f->store_32(0);
+
+ f->store_32(0); //64 bits file, false for now
+ f->store_32(VERSION_MAJOR);
+ f->store_32(VERSION_MINOR);
+ f->store_32(FORMAT_VERSION);
+
+ //f->store_32(saved_resources.size()+external_resources.size()); // load steps -not needed
+ save_unicode_string(p_resource->get_type());
+ uint64_t md_at = f->get_pos();
+ f->store_64(0); //offset to impoty metadata
+ for(int i=0;i<14;i++)
+ f->store_32(0); // reserved
+
+
+ List<ResourceData> resources;
+
+
+ {
+
+
+ for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {
+
+
+ ResourceData &rd = resources.push_back(ResourceData())->get();
+ rd.type=E->get()->get_type();
+
+ List<PropertyInfo> property_list;
+ E->get()->get_property_list( &property_list );
+
+ for(List<PropertyInfo>::Element *F=property_list.front();F;F=F->next()) {
+
+ if (skip_editor && F->get().name.begins_with("__editor"))
+ continue;
+ if (F->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && F->get().usage&PROPERTY_USAGE_BUNDLE)) {
+ Property p;
+ p.name_idx=get_string_index(F->get().name);
+ p.value=E->get()->get(F->get().name);
+ if (F->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO && p.value.is_zero())
+ continue;
+ p.pi=F->get();
+
+ rd.properties.push_back(p);
+
+ }
+ }
+
+
+
+ }
+ }
+
+
+ f->store_32(strings.size()); //string table size
+ for(int i=0;i<strings.size();i++) {
+ //print_bl("saving string: "+strings[i]);
+ save_unicode_string(strings[i]);
+ }
+
+ // save external resource table
+ f->store_32(external_resources.size()); //amount of external resources
+ for(Set<RES>::Element *E=external_resources.front();E;E=E->next()) {
+
+ save_unicode_string(E->get()->get_save_type());
+ String path = E->get()->get_path();
+ if (no_extensions)
+ path=path.basename()+".*";
+ save_unicode_string(path);
+ }
+ // save internal resource table
+ f->store_32(saved_resources.size()); //amount of internal resources
+ Vector<uint64_t> ofs_pos;
+ for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {
+
+ RES r = E->get();
+ if (r->get_path()=="" || r->get_path().find("::")!=-1)
+ save_unicode_string("local://"+itos(ofs_pos.size()));
+ else
+ save_unicode_string(r->get_path()); //actual external
+ ofs_pos.push_back(f->get_pos());
+ f->store_64(0); //offset in 64 bits
+ }
+
+ Vector<uint64_t> ofs_table;
+// int saved_idx=0;
+ //now actually save the resources
+
+ for(List<ResourceData>::Element *E=resources.front();E;E=E->next()) {
+
+ ResourceData & rd = E->get();
+
+ ofs_table.push_back(f->get_pos());
+ save_unicode_string(rd.type);
+ f->store_32(rd.properties.size());
+
+ for (List<Property>::Element *F=rd.properties.front();F;F=F->next()) {
+
+ Property &p=F->get();
+ f->store_32(p.name_idx);
+ write_variant(p.value,F->get().pi);
+ }
+
+ }
+
+ for(int i=0;i<ofs_table.size();i++) {
+ f->seek(ofs_pos[i]);
+ f->store_64(ofs_table[i]);
+ }
+
+ f->seek_end();
+ if (p_resource->get_import_metadata().is_valid()) {
+ uint64_t md_pos = f->get_pos();
+ Ref<ResourceImportMetadata> imd=p_resource->get_import_metadata();
+ save_unicode_string(imd->get_editor());
+ f->store_32(imd->get_source_count());
+ for(int i=0;i<imd->get_source_count();i++) {
+ save_unicode_string(imd->get_source_path(i));
+ save_unicode_string(imd->get_source_md5(i));
+ }
+ List<String> options;
+ imd->get_options(&options);
+ f->store_32(options.size());
+ for(List<String>::Element *E=options.front();E;E=E->next()) {
+ save_unicode_string(E->get());
+ write_variant(imd->get_option(E->get()));
+ }
+
+ f->seek(md_at);
+ f->store_64(md_pos);
+ f->seek_end();
+ }
+
+
+ f->store_buffer((const uint8_t*)"RSRC",4); //magic at end
+
+ f->close();
+
+
+ return OK;
+}
+
+
+
+Error ResourceFormatSaverBinary::save(const String &p_path,const RES& p_resource,uint32_t p_flags) {
+
+
+ String local_path = Globals::get_singleton()->localize_path(p_path);
+ ResourceFormatSaverBinaryInstance saver;
+ return saver.save(local_path,p_resource,p_flags);
+
+}
+
+
+bool ResourceFormatSaverBinary::recognize(const RES& p_resource) const {
+
+ return true; //all recognized
+
+}
+
+void ResourceFormatSaverBinary::get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const {
+
+
+ //here comes the sun, lalalala
+ String base = p_resource->get_base_extension().to_lower();
+ if (base!="res") {
+
+ p_extensions->push_back(base);
+ }
+
+ p_extensions->push_back("res");
+
+
+}
+
diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h
new file mode 100644
index 0000000000..006148f5a8
--- /dev/null
+++ b/core/io/resource_format_binary.h
@@ -0,0 +1,184 @@
+/*************************************************************************/
+/* resource_format_binary.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef RESOURCE_FORMAT_BINARY_H
+#define RESOURCE_FORMAT_BINARY_H
+
+#include "io/resource_loader.h"
+#include "io/resource_saver.h"
+#include "os/file_access.h"
+
+
+class ResourceInteractiveLoaderBinary : public ResourceInteractiveLoader {
+
+ String local_path;
+ String res_path;
+ String type;
+ Ref<Resource> resource;
+
+ FileAccess *f;
+
+
+ bool endian_swap;
+ bool use_real64;
+ uint64_t importmd_ofs;
+
+ Vector<char> str_buf;
+ List<RES> resource_cache;
+
+ //Map<int,StringName> string_map;
+ Vector<StringName> string_map;
+
+ struct ExtResoucre {
+ String path;
+ String type;
+ };
+
+ Vector<ExtResoucre> external_resources;
+
+ struct IntResoucre {
+ String path;
+ uint64_t offset;
+ };
+
+ Vector<IntResoucre> internal_resources;
+
+ String get_unicode_string();
+ void _advance_padding(uint32_t p_len);
+
+ Error error;
+
+ int stage;
+
+friend class ResourceFormatLoaderBinary;
+
+
+ Error parse_variant(Variant& r_v);
+
+public:
+
+ virtual void set_local_path(const String& p_local_path);
+ virtual Ref<Resource> get_resource();
+ virtual Error poll();
+ virtual int get_stage() const;
+ virtual int get_stage_count() const;
+
+ void open(FileAccess *p_f);
+ String recognize(FileAccess *p_f);
+ void get_dependencies(FileAccess *p_f,List<String> *p_dependencies);
+
+
+ ResourceInteractiveLoaderBinary();
+ ~ResourceInteractiveLoaderBinary();
+
+};
+
+class ResourceFormatLoaderBinary : public ResourceFormatLoader {
+public:
+
+ virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path);
+ virtual void get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String& p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+ virtual void get_dependencies(const String& p_path,List<String> *p_dependencies);
+ virtual Error load_import_metadata(const String &p_path, Ref<ResourceImportMetadata>& r_var) const;
+
+
+
+};
+
+
+
+
+class ResourceFormatSaverBinaryInstance {
+
+ String local_path;
+
+ bool no_extensions;
+ bool relative_paths;
+ bool bundle_resources;
+ bool skip_editor;
+ bool big_endian;
+ int bin_meta_idx;
+ FileAccess *f;
+ String magic;
+ Map<RES,int> resource_map;
+ Map<StringName,int> string_map;
+ Vector<StringName> strings;
+
+
+ Set<RES> external_resources;
+ List<RES> saved_resources;
+
+
+ struct Property {
+ int name_idx;
+ Variant value;
+ PropertyInfo pi;
+
+ };
+
+ struct ResourceData {
+
+ String type;
+ List<Property> properties;
+ };
+
+
+
+
+ void _pad_buffer(int p_bytes);
+ void write_variant(const Variant& p_property,const PropertyInfo& p_hint=PropertyInfo());
+ void _find_resources(const Variant& p_variant,bool p_main=false);
+ void save_unicode_string(const String& p_string);
+ int get_string_index(const String& p_string);
+public:
+
+
+ Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0);
+};
+
+
+
+class ResourceFormatSaverBinary : public ResourceFormatSaver {
+
+
+
+
+public:
+
+ virtual Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0);
+ virtual bool recognize(const RES& p_resource) const;
+ virtual void get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const;
+
+
+};
+
+
+#endif // RESOURCE_FORMAT_BINARY_H
diff --git a/core/io/resource_format_xml.cpp b/core/io/resource_format_xml.cpp
new file mode 100644
index 0000000000..f175c73e98
--- /dev/null
+++ b/core/io/resource_format_xml.cpp
@@ -0,0 +1,2557 @@
+/*************************************************************************/
+/* resource_format_xml.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. */
+/*************************************************************************/
+#include "resource_format_xml.h"
+#include "globals.h"
+#include "version.h"
+
+
+
+ResourceInteractiveLoaderXML::Tag* ResourceInteractiveLoaderXML::parse_tag(bool *r_exit,bool p_printerr) {
+
+
+ while(get_char()!='<' && !f->eof_reached()) {}
+ if (f->eof_reached()) {
+ return NULL;
+ }
+
+ Tag tag;
+ bool exit=false;
+ if (r_exit)
+ *r_exit=false;
+
+ bool complete=false;
+ while(!f->eof_reached()) {
+
+ CharType c=get_char();
+ if (c<33 && tag.name.length() && !exit) {
+ break;
+ } else if (c=='>') {
+ complete=true;
+ break;
+ } else if (c=='/') {
+ exit=true;
+ } else {
+ tag.name+=c;
+ }
+ }
+
+ if (f->eof_reached()) {
+
+ return NULL;
+ }
+
+ if (exit) {
+ if (!tag_stack.size()) {
+ if (!p_printerr)
+ return NULL;
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Unmatched exit tag </"+tag.name+">");
+ ERR_FAIL_COND_V(!tag_stack.size(),NULL);
+ }
+
+ if (tag_stack.back()->get().name!=tag.name) {
+ if (!p_printerr)
+ return NULL;
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Mismatched exit tag. Got </"+tag.name+">, expected </"+tag_stack.back()->get().name+">");
+ ERR_FAIL_COND_V(tag_stack.back()->get().name!=tag.name,NULL);
+ }
+
+ if (!complete) {
+ while(get_char()!='>' && !f->eof_reached()) {}
+ if (f->eof_reached())
+ return NULL;
+ }
+
+ if (r_exit)
+ *r_exit=true;
+
+ tag_stack.pop_back();
+ return NULL;
+
+ }
+
+ if (!complete) {
+ String name;
+ String value;
+ bool reading_value=false;
+
+ while(!f->eof_reached()) {
+
+ CharType c=get_char();
+ if (c=='>') {
+ if (value.length()) {
+
+ tag.args[name]=value;
+ }
+ break;
+
+ } else if ( ((!reading_value && (c<33)) || c=='=' || c=='"') && tag.name.length()) {
+
+ if (!reading_value && name.length()) {
+
+ reading_value=true;
+ } else if (reading_value && value.length()) {
+
+ tag.args[name]=value;
+ name="";
+ value="";
+ reading_value=false;
+ }
+
+ } else if (reading_value) {
+
+ value+=c;
+ } else {
+
+ name+=c;
+ }
+ }
+
+ if (f->eof_reached())
+ return NULL;
+ }
+
+ tag_stack.push_back(tag);
+
+ return &tag_stack.back()->get();
+}
+
+
+Error ResourceInteractiveLoaderXML::close_tag(const String& p_name) {
+
+ int level=0;
+ bool inside_tag=false;
+
+ while(true) {
+
+ if (f->eof_reached()) {
+
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": EOF found while attempting to find </"+p_name+">");
+ ERR_FAIL_COND_V( f->eof_reached(), ERR_FILE_CORRUPT );
+ }
+
+ uint8_t c = get_char();
+
+ if (c == '<') {
+
+ if (inside_tag) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Malformed XML. Already inside Tag.");
+ ERR_FAIL_COND_V(inside_tag,ERR_FILE_CORRUPT);
+ }
+ inside_tag=true;
+ c = get_char();
+ if (c == '/') {
+
+ --level;
+ } else {
+
+ ++level;
+ };
+ } else if (c == '>') {
+
+ if (!inside_tag) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Malformed XML. Already outside Tag");
+ ERR_FAIL_COND_V(!inside_tag,ERR_FILE_CORRUPT);
+ }
+ inside_tag=false;
+ if (level == -1) {
+ tag_stack.pop_back();
+ return OK;
+ };
+ };
+ }
+
+ return OK;
+}
+
+void ResourceInteractiveLoaderXML::unquote(String& p_str) {
+
+ p_str=p_str.strip_edges();
+ p_str=p_str.replace("\"","");
+ p_str=p_str.replace("&gt;","<");
+ p_str=p_str.replace("&lt;",">");
+ p_str=p_str.replace("&apos;","'");
+ p_str=p_str.replace("&quot;","\"");
+ for (int i=1;i<32;i++) {
+
+ char chr[2]={i,0};
+ p_str=p_str.replace("&#"+String::num(i)+";",chr);
+ }
+ p_str=p_str.replace("&amp;","&");
+
+ //p_str.parse_utf8( p_str.ascii(true).get_data() );
+
+}
+
+Error ResourceInteractiveLoaderXML::goto_end_of_tag() {
+
+ uint8_t c;
+ while(true) {
+
+ c=get_char();
+ if (c=='>') //closetag
+ break;
+ if (f->eof_reached()) {
+
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": EOF found while attempting to find close tag.");
+ ERR_FAIL_COND_V( f->eof_reached(), ERR_FILE_CORRUPT );
+ }
+
+ }
+ tag_stack.pop_back();
+
+ return OK;
+}
+
+
+Error ResourceInteractiveLoaderXML::parse_property_data(String &r_data) {
+
+ r_data="";
+ CharString cs;
+ while(true) {
+
+ CharType c=get_char();
+ if (c=='<')
+ break;
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+ cs.push_back(c);
+ }
+
+ cs.push_back(0);
+
+ r_data.parse_utf8(cs.get_data());
+
+ while(get_char()!='>' && !f->eof_reached()) {}
+ if (f->eof_reached()) {
+
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Malformed XML.");
+ ERR_FAIL_COND_V( f->eof_reached(), ERR_FILE_CORRUPT );
+ }
+
+ r_data=r_data.strip_edges();
+ tag_stack.pop_back();
+
+ return OK;
+}
+
+
+Error ResourceInteractiveLoaderXML::_parse_array_element(Vector<char> &buff,bool p_number_only,FileAccess *f,bool *end) {
+
+ if (buff.empty())
+ buff.resize(32); // optimi
+
+ int buff_max=buff.size();
+ int buff_size=0;
+ *end=false;
+ char *buffptr=&buff[0];
+ bool found=false;
+ bool quoted=false;
+
+ while(true) {
+
+ char c=get_char();
+
+ if (c==0) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": File corrupt (zero found).");
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ } else if (c=='"') {
+ quoted=!quoted;
+ } else if ((!quoted && ((p_number_only && c<33) || c==',')) || c=='<') {
+
+
+ if (c=='<') {
+ *end=true;
+ break;
+ }
+ if (c<32 && f->eof_reached()) {
+ *end=true;
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": File corrupt (unexpected EOF).");
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ }
+
+ if (found)
+ break;
+
+ } else {
+
+ found=true;
+ if (buff_size>=buff_max) {
+
+ buff_max++;
+ buff.resize(buff_max);
+
+ }
+
+ buffptr[buff_size]=c;
+ buff_size++;
+ }
+ }
+
+ if (buff_size>=buff_max) {
+
+ buff_max++;
+ buff.resize(buff_max);
+
+ }
+
+ buff[buff_size]=0;
+ buff_size++;
+
+ return OK;
+}
+
+Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name) {
+
+ bool exit;
+ Tag *tag = parse_tag(&exit);
+
+ if (!tag) {
+ if (exit) // shouldn't have exited
+ return ERR_FILE_EOF;
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": File corrupt (No Property Tag).");
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ }
+
+ r_v=Variant();
+ r_name="";
+
+
+ //ERR_FAIL_COND_V(tag->name!="property",ERR_FILE_CORRUPT);
+ //ERR_FAIL_COND_V(!tag->args.has("name"),ERR_FILE_CORRUPT);
+// ERR_FAIL_COND_V(!tag->args.has("type"),ERR_FILE_CORRUPT);
+
+ //String name=tag->args["name"];
+ //ERR_FAIL_COND_V(name=="",ERR_FILE_CORRUPT);
+ String type=tag->name;
+ String name=tag->args["name"];
+
+ if (type=="") {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": 'type' field is empty.");
+ ERR_FAIL_COND_V(type=="",ERR_FILE_CORRUPT);
+ }
+
+ if (type=="dictionary") {
+
+ Dictionary d( tag->args.has("shared") && (String(tag->args["shared"])=="true" || String(tag->args["shared"])=="1"));
+
+ while(true) {
+
+ Error err;
+ String tagname;
+ Variant key;
+
+ int dictline = get_current_line();
+
+
+ err=parse_property(key,tagname);
+
+ if (err && err!=ERR_FILE_EOF) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Error parsing dictionary: "+name+" (from line "+itos(dictline)+")");
+ ERR_FAIL_COND_V(err && err!=ERR_FILE_EOF,err);
+ }
+ //ERR_FAIL_COND_V(tagname!="key",ERR_FILE_CORRUPT);
+ if (err)
+ break;
+ Variant value;
+ err=parse_property(value,tagname);
+ if (err) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Error parsing dictionary: "+name+" (from line "+itos(dictline)+")");
+ }
+
+ ERR_FAIL_COND_V(err,err);
+ //ERR_FAIL_COND_V(tagname!="value",ERR_FILE_CORRUPT);
+
+ d[key]=value;
+ }
+
+
+ //err=parse_property_data(name); // skip the rest
+ //ERR_FAIL_COND_V(err,err);
+
+ r_name=name;
+ r_v=d;
+ return OK;
+
+ } else if (type=="array") {
+
+ if (!tag->args.has("len")) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
+ ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
+ }
+
+
+ int len=tag->args["len"].to_int();
+ bool shared = tag->args.has("shared") && (String(tag->args["shared"])=="true" || String(tag->args["shared"])=="1");
+
+ Array array(shared);
+ array.resize(len);
+
+ Error err;
+ Variant v;
+ String tagname;
+ int idx=0;
+ while( (err=parse_property(v,tagname))==OK ) {
+
+ ERR_CONTINUE( idx <0 || idx >=len );
+
+ array.set(idx,v);
+ idx++;
+ }
+
+ if (idx!=len) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Error loading array (size mismatch): "+name);
+ ERR_FAIL_COND_V(idx!=len,err);
+ }
+
+ if (err!=ERR_FILE_EOF) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Error loading array: "+name);
+ ERR_FAIL_COND_V(err!=ERR_FILE_EOF,err);
+ }
+
+ //err=parse_property_data(name); // skip the rest
+ //ERR_FAIL_COND_V(err,err);
+
+ r_name=name;
+ r_v=array;
+ return OK;
+
+ } else if (type=="resource") {
+
+ if (tag->args.has("path")) {
+
+ String path=tag->args["path"];
+ String hint;
+ if (tag->args.has("resource_type"))
+ hint=tag->args["resource_type"];
+
+ if (path.begins_with("local://"))
+ path=path.replace("local://",local_path+"::");
+ else if (path.find("://")==-1 && path.is_rel_path()) {
+ // path is relative to file being loaded, so convert to a resource path
+ path=Globals::get_singleton()->localize_path(local_path.get_base_dir()+"/"+path);
+
+ }
+
+ //take advantage of the resource loader cache. The resource is cached on it, even if
+ RES res=ResourceLoader::load(path,hint);
+
+
+ if (res.is_null()) {
+
+ WARN_PRINT(String("Couldn't load resource: "+path).ascii().get_data());
+ }
+
+ r_v=res.get_ref_ptr();
+ }
+
+
+
+ Error err=goto_end_of_tag();
+ if (err) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Error closing <resource> tag.");
+ ERR_FAIL_COND_V(err,err);
+ }
+
+
+ r_name=name;
+
+ return OK;
+
+ } else if (type=="image") {
+
+ if (!tag->args.has("encoding")) {
+ //empty image
+ r_v=Image();
+ String sdfsdfg;
+ Error err=parse_property_data(sdfsdfg);
+ return OK;
+ }
+
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Image missing 'encoding' field.");
+ ERR_FAIL_COND_V( !tag->args.has("encoding"), ERR_FILE_CORRUPT );
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Image missing 'width' field.");
+ ERR_FAIL_COND_V( !tag->args.has("width"), ERR_FILE_CORRUPT );
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Image missing 'height' field.");
+ ERR_FAIL_COND_V( !tag->args.has("height"), ERR_FILE_CORRUPT );
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Image missing 'format' field.");
+ ERR_FAIL_COND_V( !tag->args.has("format"), ERR_FILE_CORRUPT );
+
+ String encoding=tag->args["encoding"];
+
+ if (encoding=="raw") {
+ String width=tag->args["width"];
+ String height=tag->args["height"];
+ String format=tag->args["format"];
+ int mipmaps=tag->args.has("mipmaps")?int(tag->args["mipmaps"].to_int()):int(0);
+ int custom_size = tag->args.has("custom_size")?int(tag->args["custom_size"].to_int()):int(0);
+
+ r_name=name;
+
+ Image::Format imgformat;
+
+
+ if (format=="grayscale") {
+ imgformat=Image::FORMAT_GRAYSCALE;
+ } else if (format=="intensity") {
+ imgformat=Image::FORMAT_INTENSITY;
+ } else if (format=="grayscale_alpha") {
+ imgformat=Image::FORMAT_GRAYSCALE_ALPHA;
+ } else if (format=="rgb") {
+ imgformat=Image::FORMAT_RGB;
+ } else if (format=="rgba") {
+ imgformat=Image::FORMAT_RGBA;
+ } else if (format=="indexed") {
+ imgformat=Image::FORMAT_INDEXED;
+ } else if (format=="indexed_alpha") {
+ imgformat=Image::FORMAT_INDEXED_ALPHA;
+ } else if (format=="bc1") {
+ imgformat=Image::FORMAT_BC1;
+ } else if (format=="bc2") {
+ imgformat=Image::FORMAT_BC2;
+ } else if (format=="bc3") {
+ imgformat=Image::FORMAT_BC3;
+ } else if (format=="bc4") {
+ imgformat=Image::FORMAT_BC4;
+ } else if (format=="bc5") {
+ imgformat=Image::FORMAT_BC5;
+ } else if (format=="pvrtc2") {
+ imgformat=Image::FORMAT_PVRTC2;
+ } else if (format=="pvrtc2a") {
+ imgformat=Image::FORMAT_PVRTC2_ALPHA;
+ } else if (format=="pvrtc4") {
+ imgformat=Image::FORMAT_PVRTC4;
+ } else if (format=="pvrtc4a") {
+ imgformat=Image::FORMAT_PVRTC4_ALPHA;
+ } else if (format=="etc") {
+ imgformat=Image::FORMAT_ETC;
+ } else if (format=="custom") {
+ imgformat=Image::FORMAT_CUSTOM;
+ } else {
+
+ ERR_FAIL_V( ERR_FILE_CORRUPT );
+ }
+
+
+ int datasize;
+ int w=width.to_int();
+ int h=height.to_int();
+
+ if (w == 0 && w == 0) {
+ //r_v = Image(w, h, imgformat);
+ r_v=Image();
+ String sdfsdfg;
+ Error err=parse_property_data(sdfsdfg);
+ return OK;
+ };
+
+ if (imgformat==Image::FORMAT_CUSTOM) {
+
+ datasize=custom_size;
+ } else {
+
+ datasize = Image::get_image_data_size(h,w,imgformat,mipmaps);
+ }
+
+ if (datasize==0) {
+ //r_v = Image(w, h, imgformat);
+ r_v=Image();
+ String sdfsdfg;
+ Error err=parse_property_data(sdfsdfg);
+ return OK;
+ };
+
+ DVector<uint8_t> pixels;
+ pixels.resize(datasize);
+ DVector<uint8_t>::Write wb = pixels.write();
+
+ int idx=0;
+ uint8_t byte;
+ while( idx<datasize*2) {
+
+ CharType c=get_char();
+
+ ERR_FAIL_COND_V(c=='<',ERR_FILE_CORRUPT);
+
+ if ( (c>='0' && c<='9') || (c>='A' && c<='F') || (c>='a' && c<='f') ) {
+
+ if (idx&1) {
+
+ byte|=HEX2CHR(c);
+ wb[idx>>1]=byte;
+ } else {
+
+ byte=HEX2CHR(c)<<4;
+ }
+
+ idx++;
+ }
+
+ }
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+
+ wb=DVector<uint8_t>::Write();
+
+ r_v=Image(w,h,mipmaps,imgformat,pixels);
+ String sdfsdfg;
+ Error err=parse_property_data(sdfsdfg);
+ ERR_FAIL_COND_V(err,err);
+
+ return OK;
+ }
+
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+
+ } else if (type=="raw_array") {
+
+ if (!tag->args.has("len")) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": RawArray missing 'len' field: "+name);
+ ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
+ }
+ int len=tag->args["len"].to_int();
+
+ DVector<uint8_t> bytes;
+ bytes.resize(len);
+ DVector<uint8_t>::Write w=bytes.write();
+ uint8_t *bytesptr=w.ptr();
+ int idx=0;
+ uint8_t byte;
+
+ while( idx<len*2) {
+
+ CharType c=get_char();
+
+ if (idx&1) {
+
+ byte|=HEX2CHR(c);
+ bytesptr[idx>>1]=byte;
+ } else {
+
+ byte=HEX2CHR(c)<<4;
+ }
+
+ idx++;
+ }
+
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+
+ w=DVector<uint8_t>::Write();
+ r_v=bytes;
+ String sdfsdfg;
+ Error err=parse_property_data(sdfsdfg);
+ ERR_FAIL_COND_V(err,err);
+ r_name=name;
+
+ return OK;
+
+ } else if (type=="int_array") {
+
+ if (!tag->args.has("len")) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
+ ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
+ }
+ int len=tag->args["len"].to_int();
+
+ DVector<int> ints;
+ ints.resize(len);
+ DVector<int>::Write w=ints.write();
+ int *intsptr=w.ptr();
+ int idx=0;
+ String str;
+#if 0
+ while( idx<len ) {
+
+
+ CharType c=get_char();
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+
+ if (c<33 || c==',' || c=='<') {
+
+ if (str.length()) {
+
+ intsptr[idx]=str.to_int();
+ str="";
+ idx++;
+ }
+
+ if (c=='<') {
+
+ while(get_char()!='>' && !f->eof_reached()) {}
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+ break;
+ }
+
+ } else {
+
+ str+=c;
+ }
+ }
+
+#else
+
+ Vector<char> tmpdata;
+
+ while( idx<len ) {
+
+ bool end=false;
+ Error err = _parse_array_element(tmpdata,true,f,&end);
+ ERR_FAIL_COND_V(err,err);
+
+ intsptr[idx]=String::to_int(&tmpdata[0]);
+ idx++;
+ if (end)
+ break;
+
+ }
+
+#endif
+ w=DVector<int>::Write();
+
+ r_v=ints;
+ Error err=goto_end_of_tag();
+ ERR_FAIL_COND_V(err,err);
+ r_name=name;
+
+ return OK;
+ } else if (type=="real_array") {
+
+ if (!tag->args.has("len")) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
+ ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
+ }
+ int len=tag->args["len"].to_int();;
+
+ DVector<real_t> reals;
+ reals.resize(len);
+ DVector<real_t>::Write w=reals.write();
+ real_t *realsptr=w.ptr();
+ int idx=0;
+ String str;
+
+
+#if 0
+ while( idx<len ) {
+
+
+ CharType c=get_char();
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+
+
+ if (c<33 || c==',' || c=='<') {
+
+ if (str.length()) {
+
+ realsptr[idx]=str.to_double();
+ str="";
+ idx++;
+ }
+
+ if (c=='<') {
+
+ while(get_char()!='>' && !f->eof_reached()) {}
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+ break;
+ }
+
+ } else {
+
+ str+=c;
+ }
+ }
+
+#else
+
+
+
+ Vector<char> tmpdata;
+
+ while( idx<len ) {
+
+ bool end=false;
+ Error err = _parse_array_element(tmpdata,true,f,&end);
+ ERR_FAIL_COND_V(err,err);
+
+ realsptr[idx]=String::to_double(&tmpdata[0]);
+ idx++;
+
+ if (end)
+ break;
+ }
+
+#endif
+
+ w=DVector<real_t>::Write();
+ r_v=reals;
+
+ Error err=goto_end_of_tag();
+ ERR_FAIL_COND_V(err,err);
+ r_name=name;
+
+ return OK;
+ } else if (type=="string_array") {
+#if 0
+ if (!tag->args.has("len")) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
+ ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
+ }
+ int len=tag->args["len"].to_int();
+
+ DVector<String> strings;
+ strings.resize(len);
+ DVector<String>::Write w=strings.write();
+ String *stringsptr=w.ptr();
+ int idx=0;
+ String str;
+
+ bool inside_str=false;
+ CharString cs;
+ while( idx<len ) {
+
+
+ CharType c=get_char();
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+
+
+ if (c=='"') {
+ if (inside_str) {
+
+ cs.push_back(0);
+ String str;
+ str.parse_utf8(cs.get_data());
+ unquote(str);
+ stringsptr[idx]=str;
+ cs.clear();
+ idx++;
+ inside_str=false;
+ } else {
+ inside_str=true;
+ }
+ } else if (c=='<') {
+
+ while(get_char()!='>' && !f->eof_reached()) {}
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+ break;
+
+
+ } else if (inside_str){
+
+ cs.push_back(c);
+ }
+ }
+ w=DVector<String>::Write();
+ r_v=strings;
+ String sdfsdfg;
+ Error err=parse_property_data(sdfsdfg);
+ ERR_FAIL_COND_V(err,err);
+
+ r_name=name;
+
+ return OK;
+#endif
+ if (!tag->args.has("len")) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": String Array missing 'len' field: "+name);
+ ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
+ }
+
+
+ int len=tag->args["len"].to_int();
+
+ StringArray array;
+ array.resize(len);
+ DVector<String>::Write w = array.write();
+
+ Error err;
+ Variant v;
+ String tagname;
+ int idx=0;
+
+
+ while( (err=parse_property(v,tagname))==OK ) {
+
+ ERR_CONTINUE( idx <0 || idx >=len );
+ String str = v; //convert back to string
+ w[idx]=str;
+ idx++;
+ }
+
+ if (idx!=len) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Error loading array (size mismatch): "+name);
+ ERR_FAIL_COND_V(idx!=len,err);
+ }
+
+ if (err!=ERR_FILE_EOF) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Error loading array: "+name);
+ ERR_FAIL_COND_V(err!=ERR_FILE_EOF,err);
+ }
+
+ //err=parse_property_data(name); // skip the rest
+ //ERR_FAIL_COND_V(err,err);
+
+ r_name=name;
+ r_v=array;
+ return OK;
+
+ } else if (type=="vector3_array") {
+
+ if (!tag->args.has("len")) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
+ ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
+ }
+ int len=tag->args["len"].to_int();;
+
+ DVector<Vector3> vectors;
+ vectors.resize(len);
+ DVector<Vector3>::Write w=vectors.write();
+ Vector3 *vectorsptr=w.ptr();
+ int idx=0;
+ int subidx=0;
+ Vector3 auxvec;
+ String str;
+
+// uint64_t tbegin = OS::get_singleton()->get_ticks_usec();
+#if 0
+ while( idx<len ) {
+
+
+ CharType c=get_char();
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+
+
+ if (c<33 || c==',' || c=='<') {
+
+ if (str.length()) {
+
+ auxvec[subidx]=str.to_double();
+ subidx++;
+ str="";
+ if (subidx==3) {
+ vectorsptr[idx]=auxvec;
+
+ idx++;
+ subidx=0;
+ }
+ }
+
+ if (c=='<') {
+
+ while(get_char()!='>' && !f->eof_reached()) {}
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+ break;
+ }
+
+ } else {
+
+ str+=c;
+ }
+ }
+#else
+
+ Vector<char> tmpdata;
+
+ while( idx<len ) {
+
+ bool end=false;
+ Error err = _parse_array_element(tmpdata,true,f,&end);
+ ERR_FAIL_COND_V(err,err);
+
+
+ auxvec[subidx]=String::to_double(&tmpdata[0]);
+ subidx++;
+ if (subidx==3) {
+ vectorsptr[idx]=auxvec;
+
+ idx++;
+ subidx=0;
+ }
+
+ if (end)
+ break;
+ }
+
+
+
+#endif
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Premature end of vector3 array");
+ ERR_FAIL_COND_V(idx<len,ERR_FILE_CORRUPT);
+// double time_taken = (OS::get_singleton()->get_ticks_usec() - tbegin)/1000000.0;
+
+
+ w=DVector<Vector3>::Write();
+ r_v=vectors;
+ String sdfsdfg;
+ Error err=goto_end_of_tag();
+ ERR_FAIL_COND_V(err,err);
+ r_name=name;
+
+ return OK;
+
+ } else if (type=="vector2_array") {
+
+ if (!tag->args.has("len")) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
+ ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
+ }
+ int len=tag->args["len"].to_int();;
+
+ DVector<Vector2> vectors;
+ vectors.resize(len);
+ DVector<Vector2>::Write w=vectors.write();
+ Vector2 *vectorsptr=w.ptr();
+ int idx=0;
+ int subidx=0;
+ Vector2 auxvec;
+ String str;
+
+// uint64_t tbegin = OS::get_singleton()->get_ticks_usec();
+#if 0
+ while( idx<len ) {
+
+
+ CharType c=get_char();
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+
+
+ if (c<22 || c==',' || c=='<') {
+
+ if (str.length()) {
+
+ auxvec[subidx]=str.to_double();
+ subidx++;
+ str="";
+ if (subidx==2) {
+ vectorsptr[idx]=auxvec;
+
+ idx++;
+ subidx=0;
+ }
+ }
+
+ if (c=='<') {
+
+ while(get_char()!='>' && !f->eof_reached()) {}
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+ break;
+ }
+
+ } else {
+
+ str+=c;
+ }
+ }
+#else
+
+ Vector<char> tmpdata;
+
+ while( idx<len ) {
+
+ bool end=false;
+ Error err = _parse_array_element(tmpdata,true,f,&end);
+ ERR_FAIL_COND_V(err,err);
+
+
+ auxvec[subidx]=String::to_double(&tmpdata[0]);
+ subidx++;
+ if (subidx==2) {
+ vectorsptr[idx]=auxvec;
+
+ idx++;
+ subidx=0;
+ }
+
+ if (end)
+ break;
+ }
+
+
+
+#endif
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Premature end of vector2 array");
+ ERR_FAIL_COND_V(idx<len,ERR_FILE_CORRUPT);
+// double time_taken = (OS::get_singleton()->get_ticks_usec() - tbegin)/1000000.0;
+
+
+ w=DVector<Vector2>::Write();
+ r_v=vectors;
+ String sdfsdfg;
+ Error err=goto_end_of_tag();
+ ERR_FAIL_COND_V(err,err);
+ r_name=name;
+
+ return OK;
+
+ } else if (type=="color_array") {
+
+ if (!tag->args.has("len")) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Array missing 'len' field: "+name);
+ ERR_FAIL_COND_V(!tag->args.has("len"),ERR_FILE_CORRUPT);
+ }
+ int len=tag->args["len"].to_int();;
+
+ DVector<Color> colors;
+ colors.resize(len);
+ DVector<Color>::Write w=colors.write();
+ Color *colorsptr=w.ptr();
+ int idx=0;
+ int subidx=0;
+ Color auxcol;
+ String str;
+
+ while( idx<len ) {
+
+
+ CharType c=get_char();
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+
+
+ if (c<33 || c==',' || c=='<') {
+
+ if (str.length()) {
+
+ auxcol[subidx]=str.to_double();
+ subidx++;
+ str="";
+ if (subidx==4) {
+ colorsptr[idx]=auxcol;
+ idx++;
+ subidx=0;
+ }
+ }
+
+ if (c=='<') {
+
+ while(get_char()!='>' && !f->eof_reached()) {}
+ ERR_FAIL_COND_V(f->eof_reached(),ERR_FILE_CORRUPT);
+ break;
+ }
+
+ } else {
+
+ str+=c;
+ }
+ }
+ w=DVector<Color>::Write();
+ r_v=colors;
+ String sdfsdfg;
+ Error err=parse_property_data(sdfsdfg);
+ ERR_FAIL_COND_V(err,err);
+ r_name=name;
+
+ return OK;
+ }
+
+
+ String data;
+ Error err = parse_property_data(data);
+ ERR_FAIL_COND_V(err!=OK,err);
+
+ if (type=="nil") {
+ // uh do nothing
+
+ } else if (type=="bool") {
+ // uh do nothing
+ if (data.nocasecmp_to("true")==0 || data.to_int()!=0)
+ r_v=true;
+ else
+ r_v=false;
+ } else if (type=="int") {
+
+ r_v=data.to_int();
+ } else if (type=="real") {
+
+ r_v=data.to_double();
+ } else if (type=="string") {
+
+ String str=data;
+ unquote(str);
+ r_v=str;
+ } else if (type=="vector3") {
+
+
+ r_v=Vector3(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double(),
+ data.get_slice(",",2).to_double()
+ );
+
+ } else if (type=="vector2") {
+
+
+ r_v=Vector2(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double()
+ );
+
+ } else if (type=="plane") {
+
+ r_v=Plane(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double(),
+ data.get_slice(",",2).to_double(),
+ data.get_slice(",",3).to_double()
+ );
+
+ } else if (type=="quaternion") {
+
+ r_v=Quat(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double(),
+ data.get_slice(",",2).to_double(),
+ data.get_slice(",",3).to_double()
+ );
+
+ } else if (type=="rect2") {
+
+ r_v=Rect2(
+ Vector2(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double()
+ ),
+ Vector2(
+ data.get_slice(",",2).to_double(),
+ data.get_slice(",",3).to_double()
+ )
+ );
+
+
+ } else if (type=="aabb") {
+
+ r_v=AABB(
+ Vector3(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double(),
+ data.get_slice(",",2).to_double()
+ ),
+ Vector3(
+ data.get_slice(",",3).to_double(),
+ data.get_slice(",",4).to_double(),
+ data.get_slice(",",5).to_double()
+ )
+ );
+
+ } else if (type=="matrix32") {
+
+ Matrix32 m3;
+ for (int i=0;i<3;i++) {
+ for (int j=0;j<2;j++) {
+ m3.elements[i][j]=data.get_slice(",",i*2+j).to_double();
+ }
+ }
+ r_v=m3;
+
+ } else if (type=="matrix3") {
+
+ Matrix3 m3;
+ for (int i=0;i<3;i++) {
+ for (int j=0;j<3;j++) {
+ m3.elements[i][j]=data.get_slice(",",i*3+j).to_double();
+ }
+ }
+ r_v=m3;
+
+ } else if (type=="transform") {
+
+ Transform tr;
+ for (int i=0;i<3;i++) {
+ for (int j=0;j<3;j++) {
+ tr.basis.elements[i][j]=data.get_slice(",",i*3+j).to_double();
+ }
+
+ }
+ tr.origin=Vector3(
+ data.get_slice(",",9).to_double(),
+ data.get_slice(",",10).to_double(),
+ data.get_slice(",",11).to_double()
+ );
+ r_v=tr;
+
+ } else if (type=="color") {
+
+ r_v=Color(
+ data.get_slice(",",0).to_double(),
+ data.get_slice(",",1).to_double(),
+ data.get_slice(",",2).to_double(),
+ data.get_slice(",",3).to_double()
+ );
+
+ } else if (type=="node_path") {
+
+ String str=data;
+ unquote(str);
+ r_v=NodePath( str );
+ } else if (type=="input_event") {
+
+ // ?
+ } else {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Unrecognized tag in file: "+type);
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ }
+ r_name=name;
+ return OK;
+}
+
+
+
+int ResourceInteractiveLoaderXML::get_current_line() const {
+
+ return lines;
+}
+
+
+uint8_t ResourceInteractiveLoaderXML::get_char() const {
+
+ uint8_t c = f->get_8();
+ if (c=='\n')
+ lines++;
+ return c;
+
+}
+
+
+
+
+///
+
+void ResourceInteractiveLoaderXML::set_local_path(const String& p_local_path) {
+
+ res_path=p_local_path;
+}
+
+Ref<Resource> ResourceInteractiveLoaderXML::get_resource() {
+
+ return resource;
+}
+Error ResourceInteractiveLoaderXML::poll() {
+
+ if (error!=OK)
+ return error;
+
+
+ bool exit;
+ Tag *tag = parse_tag(&exit);
+
+
+ if (!tag) {
+ error=ERR_FILE_CORRUPT;
+ if (!exit) // shouldn't have exited
+ ERR_FAIL_V(error);
+ error=ERR_FILE_EOF;
+ return error;
+ }
+
+ RES res;
+ //Object *obj=NULL;
+
+ bool main;
+
+ if (tag->name=="ext_resource") {
+
+ error=ERR_FILE_CORRUPT;
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <ext_resource> missing 'path' field.");
+ ERR_FAIL_COND_V(!tag->args.has("path"),ERR_FILE_CORRUPT);
+
+ String type;
+ if (tag->args.has("type"))
+ type=tag->args["type"];
+
+ String path = tag->args["path"];
+
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <ext_resource> can't use a local path, this is a bug?.");
+ ERR_FAIL_COND_V(path.begins_with("local://"),ERR_FILE_CORRUPT);
+
+ if (path.find("://")==-1 && path.is_rel_path()) {
+ // path is relative to file being loaded, so convert to a resource path
+ path=Globals::get_singleton()->localize_path(local_path.get_base_dir()+"/"+path);
+ }
+
+
+ RES res = ResourceLoader::load(path,type);
+
+ if (res.is_null()) {
+
+ if (ResourceLoader::get_abort_on_missing_resources()) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <ext_resource> referenced unexisting resource at: "+path);
+ ERR_FAIL_V(error);
+ } else {
+ ResourceLoader::notify_load_error("Resource Not Found: "+path);
+ }
+ } else {
+
+ resource_cache.push_back(res);
+ }
+
+ Error err = close_tag("ext_resource");
+ if (err)
+ return error;
+
+
+ error=OK;
+ resource_current++;
+ return error;
+
+ } else if (tag->name=="resource") {
+
+ main=false;
+ } else if (tag->name=="main_resource") {
+ main=true;
+ } else {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": unexpected main tag: "+tag->name);
+ error=ERR_FILE_CORRUPT;
+ ERR_FAIL_V(error);
+ }
+
+
+ String type;
+ String path;
+
+ if (!main) {
+ //loading resource
+
+ error=ERR_FILE_CORRUPT;
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <resource> missing 'len' field.");
+ ERR_FAIL_COND_V(!tag->args.has("path"),ERR_FILE_CORRUPT);
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <resource> missing 'type' field.");
+ ERR_FAIL_COND_V(!tag->args.has("type"),ERR_FILE_CORRUPT);
+ path=tag->args["path"];
+ error=OK;
+
+ if (path.begins_with("local://")) {
+ //built-in resource (but really external)
+ path=path.replace("local://",local_path+"::");
+ }
+
+
+ if (ResourceCache::has(path)) {
+ Error err = close_tag(tag->name);
+ if (err) {
+ error=ERR_FILE_CORRUPT;
+ }
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Unable to close <resource> tag.");
+ ERR_FAIL_COND_V( err, err );
+ resource_current++;
+ error=OK;
+ return OK;
+ }
+
+ type = tag->args["type"];
+ } else {
+ type=resource_type;
+ }
+
+ Object *obj = ObjectTypeDB::instance(type);
+ if (!obj) {
+ error=ERR_FILE_CORRUPT;
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Object of unrecognized type in file: "+type);
+ }
+ ERR_FAIL_COND_V(!obj,ERR_FILE_CORRUPT);
+
+ Resource *r = obj->cast_to<Resource>();
+ if (!r) {
+ error=ERR_FILE_CORRUPT;
+ memdelete(obj); //bye
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Object type in resource field not a resource, type is: "+obj->get_type());
+ ERR_FAIL_COND_V(!r,ERR_FILE_CORRUPT);
+ }
+
+ res = RES( r );
+ if (path!="")
+ r->set_path(path);
+
+ //load properties
+
+ while(true) {
+
+ String name;
+ Variant v;
+ Error err;
+ err = parse_property(v,name);
+ if (err==ERR_FILE_EOF) //tag closed
+ break;
+ if (err!=OK) {
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": XML Parsing aborted.");
+ ERR_FAIL_COND_V(err!=OK,ERR_FILE_CORRUPT);
+ }
+
+ obj->set(name,v);
+ }
+#ifdef TOOLS_ENABLED
+ res->set_edited(false);
+#endif
+ resource_cache.push_back(res); //keep it in mem until finished loading
+ resource_current++;
+ if (main) {
+ f->close();
+ resource=res;
+ resource->set_path(res_path);
+ error=ERR_FILE_EOF;
+ return error;
+
+ }
+ error=OK;
+ return OK;
+}
+
+int ResourceInteractiveLoaderXML::get_stage() const {
+
+ return resource_current;
+}
+int ResourceInteractiveLoaderXML::get_stage_count() const {
+
+ return resources_total;
+}
+
+ResourceInteractiveLoaderXML::~ResourceInteractiveLoaderXML() {
+
+ memdelete(f);
+}
+
+void ResourceInteractiveLoaderXML::get_dependencies(FileAccess *f,List<String> *p_dependencies) {
+
+
+ open(f);
+ ERR_FAIL_COND(error!=OK);
+
+ while(true) {
+ bool exit;
+ Tag *tag = parse_tag(&exit);
+
+
+ if (!tag) {
+ error=ERR_FILE_CORRUPT;
+ ERR_FAIL_COND(!exit);
+ error=ERR_FILE_EOF;
+ return;
+ }
+
+ if (tag->name!="ext_resource") {
+
+ return;
+ }
+
+ error=ERR_FILE_CORRUPT;
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <ext_resource> missing 'path' field.");
+ ERR_FAIL_COND(!tag->args.has("path"));
+
+ String path = tag->args["path"];
+
+ ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <ext_resource> can't use a local path, this is a bug?.");
+ ERR_FAIL_COND(path.begins_with("local://"));
+
+ if (path.find("://")==-1 && path.is_rel_path()) {
+ // path is relative to file being loaded, so convert to a resource path
+ path=Globals::get_singleton()->localize_path(local_path.get_base_dir()+"/"+path);
+ }
+
+ p_dependencies->push_back(path);
+
+ Error err = close_tag("ext_resource");
+ if (err)
+ return;
+
+ error=OK;
+ }
+
+}
+
+
+void ResourceInteractiveLoaderXML::open(FileAccess *p_f) {
+
+ error=OK;
+
+ lines=1;
+ f=p_f;
+
+
+ ResourceInteractiveLoaderXML::Tag *tag = parse_tag();
+ if (!tag || tag->name!="?xml" || !tag->args.has("version") || !tag->args.has("encoding") || tag->args["encoding"]!="UTF-8") {
+
+ error=ERR_FILE_CORRUPT;
+ ResourceLoader::notify_load_error("XML is invalid (missing header tags)");
+ ERR_EXPLAIN("Not a XML:UTF-8 File: "+local_path);
+ ERR_FAIL();
+ }
+
+ tag_stack.clear();
+
+ tag = parse_tag();
+
+
+ if (!tag || tag->name!="resource_file" || !tag->args.has("type") || !tag->args.has("version")) {
+
+ ResourceLoader::notify_load_error(local_path+": XML is not a valid resource file.");
+ error=ERR_FILE_CORRUPT;
+ ERR_EXPLAIN("Unrecognized XML File: "+local_path);
+ ERR_FAIL();
+ }
+
+
+ if (tag->args.has("subresource_count"))
+ resources_total=tag->args["subresource_count"].to_int();
+ resource_current=0;
+ resource_type=tag->args["type"];
+
+ String version = tag->args["version"];
+ if (version.get_slice_count(".")!=2) {
+
+ error=ERR_FILE_CORRUPT;
+ ResourceLoader::notify_load_error(local_path+":XML version string is invalid: "+version);
+ ERR_EXPLAIN("Invalid Version String '"+version+"'' in file: "+local_path);
+ ERR_FAIL();
+ }
+
+ int major = version.get_slice(".",0).to_int();
+ int minor = version.get_slice(".",1).to_int();
+
+ if (major>VERSION_MAJOR || (major==VERSION_MAJOR && minor>VERSION_MINOR)) {
+
+ error=ERR_FILE_UNRECOGNIZED;
+ ResourceLoader::notify_load_error(local_path+": File Format '"+version+"' is too new. Please upgrade to a newer engine version.");
+ ERR_EXPLAIN("File Format '"+version+"' is too new! Please upgrade to a a new engine version: "+local_path);
+ ERR_FAIL();
+
+ }
+
+}
+
+String ResourceInteractiveLoaderXML::recognize(FileAccess *p_f) {
+
+ error=OK;
+
+ lines=1;
+ f=p_f;
+
+ ResourceInteractiveLoaderXML::Tag *tag = parse_tag();
+ if (!tag || tag->name!="?xml" || !tag->args.has("version") || !tag->args.has("encoding") || tag->args["encoding"]!="UTF-8") {
+
+
+ return ""; //unrecognized
+ }
+
+ tag_stack.clear();
+
+ tag = parse_tag();
+
+ if (!tag || tag->name!="resource_file" || !tag->args.has("type") || !tag->args.has("version")) {
+
+ return ""; //unrecognized
+ }
+
+ return tag->args["type"];
+
+}
+
+/////////////////////
+
+Ref<ResourceInteractiveLoader> ResourceFormatLoaderXML::load_interactive(const String &p_path) {
+
+ Error err;
+ FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err);
+
+
+ if (err!=OK) {
+
+ ERR_FAIL_COND_V(err!=OK,Ref<ResourceInteractiveLoader>());
+ }
+
+ Ref<ResourceInteractiveLoaderXML> ria = memnew( ResourceInteractiveLoaderXML );
+ ria->local_path=Globals::get_singleton()->localize_path(p_path);
+ ria->res_path=ria->local_path;
+// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
+ ria->open(f);
+
+ return ria;
+}
+
+void ResourceFormatLoaderXML::get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const {
+
+ if (p_type=="") {
+ get_recognized_extensions(p_extensions);
+ return;
+ }
+
+ List<String> extensions;
+ ObjectTypeDB::get_extensions_for_type(p_type,&extensions);
+
+ extensions.sort();
+
+ for(List<String>::Element *E=extensions.front();E;E=E->next()) {
+ String ext = E->get().to_lower();
+ if (ext=="res")
+ continue;
+ p_extensions->push_back("x"+ext);
+ p_extensions->push_back(ext);
+ }
+
+ p_extensions->push_back("xml");
+
+
+}
+void ResourceFormatLoaderXML::get_recognized_extensions(List<String> *p_extensions) const{
+
+ List<String> extensions;
+ ObjectTypeDB::get_resource_base_extensions(&extensions);
+ extensions.sort();
+
+ for(List<String>::Element *E=extensions.front();E;E=E->next()) {
+ String ext = E->get().to_lower();
+ if (ext=="res")
+ continue;
+ p_extensions->push_back("x"+ext);
+ }
+
+ p_extensions->push_back("xml");
+}
+
+bool ResourceFormatLoaderXML::handles_type(const String& p_type) const{
+
+ return true;
+}
+String ResourceFormatLoaderXML::get_resource_type(const String &p_path) const{
+
+
+ String ext=p_path.extension().to_lower();
+ if (!ext.begins_with("x")) //a lie but..
+ return "";
+
+ FileAccess *f = FileAccess::open(p_path,FileAccess::READ);
+ if (!f) {
+
+ return ""; //could not rwead
+ }
+
+ Ref<ResourceInteractiveLoaderXML> ria = memnew( ResourceInteractiveLoaderXML );
+ ria->local_path=Globals::get_singleton()->localize_path(p_path);
+ ria->res_path=ria->local_path;
+// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
+ String r = ria->recognize(f);
+ return r;
+}
+
+
+void ResourceFormatLoaderXML::get_dependencies(const String& p_path,List<String> *p_dependencies) {
+
+ FileAccess *f = FileAccess::open(p_path,FileAccess::READ);
+ if (!f) {
+
+ ERR_FAIL();
+ }
+
+ Ref<ResourceInteractiveLoaderXML> ria = memnew( ResourceInteractiveLoaderXML );
+ ria->local_path=Globals::get_singleton()->localize_path(p_path);
+ ria->res_path=ria->local_path;
+// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
+ ria->get_dependencies(f,p_dependencies);
+
+
+}
+
+/****************************************************************************************/
+/****************************************************************************************/
+/****************************************************************************************/
+/****************************************************************************************/
+/****************************************************************************************/
+/****************************************************************************************/
+/****************************************************************************************/
+/****************************************************************************************/
+/****************************************************************************************/
+/****************************************************************************************/
+/****************************************************************************************/
+/****************************************************************************************/
+/****************************************************************************************/
+
+
+
+void ResourceFormatSaverXMLInstance::escape(String& p_str) {
+
+ p_str=p_str.replace("&","&amp;");
+ p_str=p_str.replace("<","&gt;");
+ p_str=p_str.replace(">","&lt;");
+ p_str=p_str.replace("'","&apos;");
+ p_str=p_str.replace("\"","&quot;");
+ for (int i=1;i<32;i++) {
+
+ char chr[2]={i,0};
+ p_str=p_str.replace(chr,"&#"+String::num(i)+";");
+ }
+
+
+}
+void ResourceFormatSaverXMLInstance::write_tabs(int p_diff) {
+
+ for (int i=0;i<depth+p_diff;i++) {
+
+ f->store_8('\t');
+ }
+}
+
+void ResourceFormatSaverXMLInstance::write_string(String p_str,bool p_escape) {
+
+ /* write an UTF8 string */
+ if (p_escape)
+ escape(p_str);
+
+ f->store_string(p_str);;
+ /*
+ CharString cs=p_str.utf8();
+ const char *data=cs.get_data();
+
+ while (*data) {
+ f->store_8(*data);
+ data++;
+ }*/
+
+
+}
+
+void ResourceFormatSaverXMLInstance::enter_tag(const char* p_tag,const String& p_args) {
+
+ f->store_8('<');
+ int cc = 0;
+ const char *c=p_tag;
+ while(*c) {
+ cc++;
+ c++;
+ }
+ f->store_buffer((const uint8_t*)p_tag,cc);
+ if (p_args.length()) {
+ f->store_8(' ');
+ f->store_string(p_args);
+ }
+ f->store_8('>');
+ depth++;
+
+}
+void ResourceFormatSaverXMLInstance::exit_tag(const char* p_tag) {
+
+ depth--;
+ f->store_8('<');
+ f->store_8('/');
+ int cc = 0;
+ const char *c=p_tag;
+ while(*c) {
+ cc++;
+ c++;
+ }
+ f->store_buffer((const uint8_t*)p_tag,cc);
+ f->store_8('>');
+
+}
+
+/*
+static bool _check_type(const Variant& p_property) {
+
+ if (p_property.get_type()==Variant::_RID)
+ return false;
+ if (p_property.get_type()==Variant::OBJECT) {
+ RES res = p_property;
+ if (res.is_null())
+ return false;
+ }
+
+ return true;
+}*/
+
+void ResourceFormatSaverXMLInstance::write_property(const String& p_name,const Variant& p_property,bool *r_ok) {
+
+ if (r_ok)
+ *r_ok=false;
+
+ const char* type;
+ String params;
+ bool oneliner=true;
+
+ switch( p_property.get_type() ) {
+
+ case Variant::NIL: type="nil"; break;
+ case Variant::BOOL: type="bool"; break;
+ case Variant::INT: type="int"; break;
+ case Variant::REAL: type="real"; break;
+ case Variant::STRING: type="string"; break;
+ case Variant::VECTOR2: type="vector2"; break;
+ case Variant::RECT2: type="rect2"; break;
+ case Variant::VECTOR3: type="vector3"; break;
+ case Variant::PLANE: type="plane"; break;
+ case Variant::_AABB: type="aabb"; break;
+ case Variant::QUAT: type="quaternion"; break;
+ case Variant::MATRIX32: type="matrix32"; break;
+ case Variant::MATRIX3: type="matrix3"; break;
+ case Variant::TRANSFORM: type="transform"; break;
+ case Variant::COLOR: type="color"; break;
+ case Variant::IMAGE: {
+ type="image";
+ Image img=p_property;
+ if (img.empty()) {
+ write_tabs();
+ enter_tag(type,"name=\""+p_name+"\"");
+ exit_tag(type);
+ if (r_ok)
+ *r_ok=true;
+ return;
+ }
+ params+="encoding=\"raw\"";
+ params+=" width=\""+itos(img.get_width())+"\"";
+ params+=" height=\""+itos(img.get_height())+"\"";
+ params+=" mipmaps=\""+itos(img.get_mipmaps())+"\"";
+
+ switch(img.get_format()) {
+
+ case Image::FORMAT_GRAYSCALE: params+=" format=\"grayscale\""; break;
+ case Image::FORMAT_INTENSITY: params+=" format=\"intensity\""; break;
+ case Image::FORMAT_GRAYSCALE_ALPHA: params+=" format=\"grayscale_alpha\""; break;
+ case Image::FORMAT_RGB: params+=" format=\"rgb\""; break;
+ case Image::FORMAT_RGBA: params+=" format=\"rgba\""; break;
+ case Image::FORMAT_INDEXED : params+=" format=\"indexed\""; break;
+ case Image::FORMAT_INDEXED_ALPHA: params+=" format=\"indexed_alpha\""; break;
+ case Image::FORMAT_BC1: params+=" format=\"bc1\""; break;
+ case Image::FORMAT_BC2: params+=" format=\"bc2\""; break;
+ case Image::FORMAT_BC3: params+=" format=\"bc3\""; break;
+ case Image::FORMAT_BC4: params+=" format=\"bc4\""; break;
+ case Image::FORMAT_BC5: params+=" format=\"bc5\""; break;
+ case Image::FORMAT_PVRTC2: params+=" format=\"pvrtc2\""; break;
+ case Image::FORMAT_PVRTC2_ALPHA: params+=" format=\"pvrtc2a\""; break;
+ case Image::FORMAT_PVRTC4: params+=" format=\"pvrtc4\""; break;
+ case Image::FORMAT_PVRTC4_ALPHA: params+=" format=\"pvrtc4a\""; break;
+ case Image::FORMAT_ETC: params+=" format=\"etc\""; break;
+ case Image::FORMAT_CUSTOM: params+=" format=\"custom\" custom_size=\""+itos(img.get_data().size())+"\""; break;
+ default: {}
+ }
+ } break;
+ case Variant::NODE_PATH: type="node_path"; break;
+ case Variant::OBJECT: {
+ type="resource";
+ RES res = p_property;
+ if (res.is_null()) {
+ write_tabs();
+ enter_tag(type,"name=\""+p_name+"\"");
+ exit_tag(type);
+ if (r_ok)
+ *r_ok=true;
+
+ return; // don't save it
+ }
+
+ params="resource_type=\""+res->get_save_type()+"\"";
+
+ if (res->get_path().length() && res->get_path().find("::")==-1) {
+ //external resource
+ String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path();
+ if (no_extension)
+ path=path.basename()+".*";
+ escape(path);
+ params+=" path=\""+path+"\"";
+ } else {
+
+ //internal resource
+ ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?");
+ ERR_FAIL_COND(!resource_map.has(res));
+
+ params+=" path=\"local://"+itos(resource_map[res])+"\"";
+ }
+
+ } break;
+ case Variant::INPUT_EVENT: type="input_event"; break;
+ case Variant::DICTIONARY: type="dictionary"; params="shared=\""+String(p_property.is_shared()?"true":"false")+"\""; oneliner=false; break;
+ case Variant::ARRAY: type="array"; params="len=\""+itos(p_property.operator Array().size())+"\" shared=\""+String(p_property.is_shared()?"true":"false")+"\""; oneliner=false; break;
+
+ case Variant::RAW_ARRAY: type="raw_array"; params="len=\""+itos(p_property.operator DVector < uint8_t >().size())+"\""; break;
+ case Variant::INT_ARRAY: type="int_array"; params="len=\""+itos(p_property.operator DVector < int >().size())+"\""; break;
+ case Variant::REAL_ARRAY: type="real_array"; params="len=\""+itos(p_property.operator DVector < real_t >().size())+"\""; break;
+ case Variant::STRING_ARRAY: oneliner=false; type="string_array"; params="len=\""+itos(p_property.operator DVector < String >().size())+"\""; break;
+ case Variant::VECTOR2_ARRAY: type="vector2_array"; params="len=\""+itos(p_property.operator DVector < Vector2 >().size())+"\""; break;
+ case Variant::VECTOR3_ARRAY: type="vector3_array"; params="len=\""+itos(p_property.operator DVector < Vector3 >().size())+"\""; break;
+ case Variant::COLOR_ARRAY: type="color_array"; params="len=\""+itos(p_property.operator DVector < Color >().size())+"\""; break;
+ default: {
+
+ ERR_PRINT("Unknown Variant type.");
+ ERR_FAIL();
+ }
+
+ }
+
+ write_tabs();
+
+ if (p_name!="") {
+ if (params.length())
+ enter_tag(type,"name=\""+p_name+"\" "+params);
+ else
+ enter_tag(type,"name=\""+p_name+"\"");
+ } else {
+ if (params.length())
+ enter_tag(type," "+params);
+ else
+ enter_tag(type,String());
+ }
+
+ if (!oneliner)
+ f->store_8('\n');
+ else
+ f->store_8(' ');
+
+
+ switch( p_property.get_type() ) {
+
+ case Variant::NIL: {
+
+ } break;
+ case Variant::BOOL: {
+
+ write_string( p_property.operator bool() ? "True":"False" );
+ } break;
+ case Variant::INT: {
+
+ write_string( itos(p_property.operator int()) );
+ } break;
+ case Variant::REAL: {
+
+ write_string( rtos(p_property.operator real_t()) );
+ } break;
+ case Variant::STRING: {
+
+ String str=p_property;
+ escape(str);
+ str="\""+str+"\"";
+ write_string( str,false );
+ } break;
+ case Variant::VECTOR2: {
+
+ Vector2 v = p_property;
+ write_string( rtoss(v.x) +", "+rtoss(v.y) );
+ } break;
+ case Variant::RECT2: {
+
+ Rect2 aabb = p_property;
+ write_string( rtoss(aabb.pos.x) +", "+rtoss(aabb.pos.y) +", "+rtoss(aabb.size.x) +", "+rtoss(aabb.size.y) );
+
+ } break;
+ case Variant::VECTOR3: {
+
+ Vector3 v = p_property;
+ write_string( rtoss(v.x) +", "+rtoss(v.y)+", "+rtoss(v.z) );
+ } break;
+ case Variant::PLANE: {
+
+ Plane p = p_property;
+ write_string( rtoss(p.normal.x) +", "+rtoss(p.normal.y)+", "+rtoss(p.normal.z)+", "+rtoss(p.d) );
+
+ } break;
+ case Variant::_AABB: {
+
+ AABB aabb = p_property;
+ write_string( rtoss(aabb.pos.x) +", "+rtoss(aabb.pos.y) +", "+rtoss(aabb.pos.z) +", "+rtoss(aabb.size.x) +", "+rtoss(aabb.size.y) +", "+rtoss(aabb.size.z) );
+
+ } break;
+ case Variant::QUAT: {
+
+ Quat quat = p_property;
+ write_string( rtoss(quat.x)+", "+rtoss(quat.y)+", "+rtoss(quat.z)+", "+rtoss(quat.w)+", ");
+
+ } break;
+ case Variant::MATRIX32: {
+
+ String s;
+ Matrix32 m3 = p_property;
+ for (int i=0;i<3;i++) {
+ for (int j=0;j<2;j++) {
+
+ if (i!=0 || j!=0)
+ s+=", ";
+ s+=rtoss( m3.elements[i][j] );
+ }
+ }
+
+ write_string(s);
+
+ } break;
+ case Variant::MATRIX3: {
+
+ String s;
+ Matrix3 m3 = p_property;
+ for (int i=0;i<3;i++) {
+ for (int j=0;j<3;j++) {
+
+ if (i!=0 || j!=0)
+ s+=", ";
+ s+=rtoss( m3.elements[i][j] );
+ }
+ }
+
+ write_string(s);
+
+ } break;
+ case Variant::TRANSFORM: {
+
+ String s;
+ Transform t = p_property;
+ Matrix3 &m3 = t.basis;
+ for (int i=0;i<3;i++) {
+ for (int j=0;j<3;j++) {
+
+ if (i!=0 || j!=0)
+ s+=", ";
+ s+=rtoss( m3.elements[i][j] );
+ }
+ }
+
+ s=s+", "+rtoss(t.origin.x) +", "+rtoss(t.origin.y)+", "+rtoss(t.origin.z);
+
+ write_string(s);
+ } break;
+
+ // misc types
+ case Variant::COLOR: {
+
+ Color c = p_property;
+ write_string( rtoss(c.r) +", "+rtoss(c.g)+", "+rtoss(c.b)+", "+rtoss(c.a) );
+
+ } break;
+ case Variant::IMAGE: {
+
+ String s;
+ Image img = p_property;
+ DVector<uint8_t> data = img.get_data();
+ int len = data.size();
+ DVector<uint8_t>::Read r = data.read();
+ const uint8_t *ptr=r.ptr();;
+ for (int i=0;i<len;i++) {
+
+ uint8_t byte = ptr[i];
+ const char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+ char str[3]={ hex[byte>>4], hex[byte&0xF], 0};
+ s+=str;
+ }
+
+ write_string(s);
+ } break;
+ case Variant::NODE_PATH: {
+
+ String str=p_property;
+ escape(str);
+ str="\""+str+"\"";
+ write_string( str,false);
+
+ } break;
+
+ case Variant::OBJECT: {
+ /* this saver does not save resources in here
+ RES res = p_property;
+
+ if (!res.is_null()) {
+
+ String path=res->get_path();
+ if (!res->is_shared() || !path.length()) {
+ // if no path, or path is from inside a scene
+ write_object( *res );
+ }
+
+ }
+ */
+
+ } break;
+ case Variant::INPUT_EVENT: {
+
+ write_string( p_property.operator String() );
+ } break;
+ case Variant::DICTIONARY: {
+
+ Dictionary dict = p_property;
+
+
+ List<Variant> keys;
+ dict.get_key_list(&keys);
+
+ for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+ //if (!_check_type(dict[E->get()]))
+ // continue;
+
+ bool ok;
+ write_property("",E->get(),&ok);
+ ERR_CONTINUE(!ok);
+
+ write_property("",dict[E->get()],&ok);
+ if (!ok)
+ write_property("",Variant()); //at least make the file consistent..
+ }
+
+
+
+
+ } break;
+ case Variant::ARRAY: {
+
+ Array array = p_property;
+ int len=array.size();
+ for (int i=0;i<len;i++) {
+
+ write_property("",array[i]);
+
+ }
+
+ } break;
+
+ case Variant::RAW_ARRAY: {
+
+ String s;
+ DVector<uint8_t> data = p_property;
+ int len = data.size();
+ DVector<uint8_t>::Read r = data.read();
+ const uint8_t *ptr=r.ptr();;
+ for (int i=0;i<len;i++) {
+
+ uint8_t byte = ptr[i];
+ const char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+ char str[3]={ hex[byte>>4], hex[byte&0xF], 0};
+ s+=str;
+ }
+
+ write_string(s,false);
+
+ } break;
+ case Variant::INT_ARRAY: {
+
+ DVector<int> data = p_property;
+ int len = data.size();
+ DVector<int>::Read r = data.read();
+ const int *ptr=r.ptr();;
+ write_tabs();
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ write_string(", ",false);
+
+ write_string(itos(ptr[i]),false);
+ }
+
+
+
+ } break;
+ case Variant::REAL_ARRAY: {
+
+ DVector<real_t> data = p_property;
+ int len = data.size();
+ DVector<real_t>::Read r = data.read();
+ const real_t *ptr=r.ptr();;
+ write_tabs();
+ String cm=", " ;
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ write_string(cm,false);
+ write_string(rtoss(ptr[i]),false);
+ }
+
+
+ } break;
+ case Variant::STRING_ARRAY: {
+
+ DVector<String> data = p_property;
+ int len = data.size();
+ DVector<String>::Read r = data.read();
+ const String *ptr=r.ptr();;
+ String s;
+ //write_string("\n");
+
+
+
+ for (int i=0;i<len;i++) {
+
+ write_tabs(0);
+ String str=ptr[i];
+ escape(str);
+ write_string("<string> \""+str+"\" </string>\n",false);
+ }
+ } break;
+ case Variant::VECTOR2_ARRAY: {
+
+ DVector<Vector2> data = p_property;
+ int len = data.size();
+ DVector<Vector2>::Read r = data.read();
+ const Vector2 *ptr=r.ptr();;
+ write_tabs();
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ write_string(", ",false);
+ write_string(rtoss(ptr[i].x),false);
+ write_string(", "+rtoss(ptr[i].y),false);
+
+ }
+
+
+ } break;
+ case Variant::VECTOR3_ARRAY: {
+
+ DVector<Vector3> data = p_property;
+ int len = data.size();
+ DVector<Vector3>::Read r = data.read();
+ const Vector3 *ptr=r.ptr();;
+ write_tabs();
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ write_string(", ",false);
+ write_string(rtoss(ptr[i].x),false);
+ write_string(", "+rtoss(ptr[i].y),false);
+ write_string(", "+rtoss(ptr[i].z),false);
+
+ }
+
+
+ } break;
+ case Variant::COLOR_ARRAY: {
+
+ DVector<Color> data = p_property;
+ int len = data.size();
+ DVector<Color>::Read r = data.read();
+ const Color *ptr=r.ptr();;
+ write_tabs();
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ write_string(", ",false);
+
+ write_string(rtoss(ptr[i].r),false);
+ write_string(", "+rtoss(ptr[i].g),false);
+ write_string(", "+rtoss(ptr[i].b),false);
+ write_string(", "+rtoss(ptr[i].a),false);
+
+ }
+
+ } break;
+ default: {}
+
+ }
+ if (oneliner)
+ f->store_8(' ');
+ else
+ write_tabs(-1);
+ exit_tag(type);
+
+ f->store_8('\n');
+
+ if (r_ok)
+ *r_ok=true;
+
+}
+
+
+void ResourceFormatSaverXMLInstance::_find_resources(const Variant& p_variant,bool p_main) {
+
+
+ switch(p_variant.get_type()) {
+ case Variant::OBJECT: {
+
+
+ RES res = p_variant.operator RefPtr();
+
+ if (res.is_null())
+ return;
+
+ if (!p_main && (!bundle_resources ) && res->get_path().length() && res->get_path().find("::") == -1 ) {
+ external_resources.insert(res);
+ return;
+ }
+
+ if (resource_map.has(res))
+ return;
+
+ List<PropertyInfo> property_list;
+
+ res->get_property_list( &property_list );
+
+ List<PropertyInfo>::Element *I=property_list.front();
+
+ while(I) {
+
+ PropertyInfo pi=I->get();
+
+ if (pi.usage&PROPERTY_USAGE_STORAGE || (bundle_resources && pi.usage&PROPERTY_USAGE_BUNDLE)) {
+
+ Variant v=res->get(I->get().name);
+ _find_resources(v);
+ }
+
+ I=I->next();
+ }
+
+ resource_map[ res ] = resource_map.size(); //saved after, so the childs it needs are available when loaded
+ saved_resources.push_back(res);
+
+ } break;
+ case Variant::ARRAY: {
+
+ Array varray=p_variant;
+ int len=varray.size();
+ for(int i=0;i<len;i++) {
+
+ Variant v=varray.get(i);
+ _find_resources(v);
+ }
+
+ } break;
+ case Variant::DICTIONARY: {
+
+ Dictionary d=p_variant;
+ List<Variant> keys;
+ d.get_key_list(&keys);
+ for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+ Variant v = d[E->get()];
+ _find_resources(v);
+ }
+ } break;
+ default: {}
+ }
+
+}
+
+
+
+Error ResourceFormatSaverXMLInstance::save(const String &p_path,const RES& p_resource,uint32_t p_flags) {
+
+ Error err;
+ f = FileAccess::open(p_path, FileAccess::WRITE,&err);
+ ERR_FAIL_COND_V( err, ERR_CANT_OPEN );
+ FileAccessRef _fref(f);
+
+ local_path = Globals::get_singleton()->localize_path(p_path);
+
+ relative_paths=p_flags&ResourceSaver::FLAG_RELATIVE_PATHS;
+ skip_editor=p_flags&ResourceSaver::FLAG_OMIT_EDITOR_PROPERTIES;
+ bundle_resources=p_flags&ResourceSaver::FLAG_BUNDLE_RESOURCES;
+ no_extension=p_flags&ResourceSaver::FLAG_NO_EXTENSION;
+ depth=0;
+
+ // save resources
+ _find_resources(p_resource,true);
+
+ ERR_FAIL_COND_V(err!=OK,err);
+
+ write_string("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>",false); //no escape
+ write_string("\n",false);
+ enter_tag("resource_file","type=\""+p_resource->get_type()+"\" subresource_count=\""+itos(saved_resources.size()+external_resources.size())+"\" version=\""+itos(VERSION_MAJOR)+"."+itos(VERSION_MINOR)+"\" version_name=\""+VERSION_FULL_NAME+"\"");
+ write_string("\n",false);
+
+ for(Set<RES>::Element *E=external_resources.front();E;E=E->next()) {
+
+ write_tabs();
+ String p = E->get()->get_path();
+ if (no_extension)
+ p=p.basename()+".*";
+
+ enter_tag("ext_resource","path=\""+p+"\" type=\""+E->get()->get_save_type()+"\""); //bundled
+ exit_tag("ext_resource"); //bundled
+ write_string("\n",false);
+ }
+
+
+
+ for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {
+
+ RES res = E->get();
+ ERR_CONTINUE(!resource_map.has(res));
+ bool main = (E->next()==NULL);
+
+ write_tabs();
+
+ if (main)
+ enter_tag("main_resource",""); //bundled
+ else if (res->get_path().length() && res->get_path().find("::") == -1 )
+ enter_tag("resource","type=\""+res->get_type()+"\" path=\""+res->get_path()+"\""); //bundled
+ else
+ enter_tag("resource","type=\""+res->get_type()+"\" path=\"local://"+itos(resource_map[res])+"\"");
+ write_string("\n",false);
+
+
+ List<PropertyInfo> property_list;
+ res->get_property_list(&property_list);
+ for(List<PropertyInfo>::Element *PE = property_list.front();PE;PE=PE->next()) {
+
+
+ if (skip_editor && PE->get().name.begins_with("__editor"))
+ continue;
+
+ if (PE->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && PE->get().usage&PROPERTY_USAGE_BUNDLE)) {
+
+ String name = PE->get().name;
+ Variant value = res->get(name);
+ if (PE->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO && value.is_zero())
+ continue;
+
+ write_property(name,value);
+ }
+
+
+ }
+
+ write_string("\n",false);
+ write_tabs(-1);
+ if (main)
+ exit_tag("main_resource");
+ else
+ exit_tag("resource");
+
+ write_string("\n",false);
+ }
+
+ exit_tag("resource_file");
+ f->close();
+ //memdelete(f);
+
+ return OK;
+}
+
+
+
+Error ResourceFormatSaverXML::save(const String &p_path,const RES& p_resource,uint32_t p_flags) {
+
+ ResourceFormatSaverXMLInstance saver;
+ return saver.save(p_path,p_resource,p_flags);
+
+}
+
+bool ResourceFormatSaverXML::recognize(const RES& p_resource) const {
+
+
+ return true; // all recognized!
+}
+void ResourceFormatSaverXML::get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const {
+
+
+ //here comes the sun, lalalala
+ String base = p_resource->get_base_extension().to_lower();
+ p_extensions->push_back("xml");
+ if (base!="res") {
+
+ p_extensions->push_back("x"+base);
+ }
+
+}
diff --git a/core/io/resource_format_xml.h b/core/io/resource_format_xml.h
new file mode 100644
index 0000000000..05313ffbd7
--- /dev/null
+++ b/core/io/resource_format_xml.h
@@ -0,0 +1,155 @@
+/*************************************************************************/
+/* resource_format_xml.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef RESOURCE_FORMAT_XML_H
+#define RESOURCE_FORMAT_XML_H
+
+#include "io/resource_loader.h"
+#include "io/resource_saver.h"
+#include "os/file_access.h"
+
+
+
+class ResourceInteractiveLoaderXML : public ResourceInteractiveLoader {
+
+ String local_path;
+ String res_path;
+
+ FileAccess *f;
+
+ struct Tag {
+
+ String name;
+ HashMap<String,String> args;
+ };
+
+ _FORCE_INLINE_ Error _parse_array_element(Vector<char> &buff,bool p_number_only,FileAccess *f,bool *end);
+
+ int resources_total;
+ int resource_current;
+ String resource_type;
+
+ mutable int lines;
+ uint8_t get_char() const;
+ int get_current_line() const;
+
+friend class ResourceFormatLoaderXML;
+ List<Tag> tag_stack;
+
+ List<RES> resource_cache;
+ Tag* parse_tag(bool* r_exit=NULL,bool p_printerr=true);
+ Error close_tag(const String& p_name);
+ void unquote(String& p_str);
+ Error goto_end_of_tag();
+ Error parse_property_data(String &r_data);
+ Error parse_property(Variant& r_v, String &r_name);
+
+ Error error;
+
+ RES resource;
+
+public:
+
+ virtual void set_local_path(const String& p_local_path);
+ virtual Ref<Resource> get_resource();
+ virtual Error poll();
+ virtual int get_stage() const;
+ virtual int get_stage_count() const;
+
+ void open(FileAccess *p_f);
+ String recognize(FileAccess *p_f);
+ void get_dependencies(FileAccess *p_f,List<String> *p_dependencies);
+
+
+ ~ResourceInteractiveLoaderXML();
+
+};
+
+class ResourceFormatLoaderXML : public ResourceFormatLoader {
+public:
+
+ virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path);
+ virtual void get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String& p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+ virtual void get_dependencies(const String& p_path,List<String> *p_dependencies);
+
+
+};
+
+
+////////////////////////////////////////////////////////////////////////////////////////////
+
+
+class ResourceFormatSaverXMLInstance {
+
+ String local_path;
+
+
+
+ bool no_extension;
+ bool relative_paths;
+ bool bundle_resources;
+ bool skip_editor;
+ FileAccess *f;
+ int depth;
+ Map<RES,int> resource_map;
+ List<RES> saved_resources;
+ Set<RES> external_resources;
+
+ void enter_tag(const char* p_tag,const String& p_args=String());
+ void exit_tag(const char* p_tag);
+
+ void _find_resources(const Variant& p_variant,bool p_main=false);
+ void write_property(const String& p_name,const Variant& p_property,bool *r_ok=NULL);
+
+
+ void escape(String& p_str);
+ void write_tabs(int p_diff=0);
+ void write_string(String p_str,bool p_escape=true);
+
+
+public:
+
+ Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0);
+
+
+};
+
+class ResourceFormatSaverXML : public ResourceFormatSaver {
+public:
+ virtual Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0);
+ virtual bool recognize(const RES& p_resource) const;
+ virtual void get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const;
+
+
+};
+
+
+#endif // RESOURCE_FORMAT_XML_H
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
new file mode 100644
index 0000000000..3bae6be83c
--- /dev/null
+++ b/core/io/resource_loader.cpp
@@ -0,0 +1,378 @@
+/*************************************************************************/
+/* resource_loader.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. */
+/*************************************************************************/
+#include "resource_loader.h"
+#include "print_string.h"
+#include "globals.h"
+#include "path_remap.h"
+#include "os/file_access.h"
+#include "os/os.h"
+ResourceFormatLoader *ResourceLoader::loader[MAX_LOADERS];
+
+int ResourceLoader::loader_count=0;
+
+
+Error ResourceInteractiveLoader::wait() {
+
+ Error err = poll();
+ while (err==OK) {
+ err=poll();
+ }
+
+ return err;
+}
+
+
+bool ResourceFormatLoader::recognize(const String& p_extension) const {
+
+
+ List<String> extensions;
+ get_recognized_extensions(&extensions);
+ for (List<String>::Element *E=extensions.front();E;E=E->next()) {
+
+ if (E->get().nocasecmp_to(p_extension.extension())==0)
+ return true;
+ }
+
+ return false;
+}
+
+void ResourceFormatLoader::get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const {
+
+ if (p_type=="" || handles_type(p_type))
+ get_recognized_extensions(p_extensions);
+}
+
+void ResourceLoader::get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) {
+
+ for (int i=0;i<loader_count;i++) {
+ loader[i]->get_recognized_extensions_for_type(p_type,p_extensions);
+ }
+
+}
+
+void ResourceInteractiveLoader::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("get_resource"),&ResourceInteractiveLoader::get_resource);
+ ObjectTypeDB::bind_method(_MD("poll"),&ResourceInteractiveLoader::poll);
+ ObjectTypeDB::bind_method(_MD("wait"),&ResourceInteractiveLoader::wait);
+ ObjectTypeDB::bind_method(_MD("get_stage"),&ResourceInteractiveLoader::get_stage);
+ ObjectTypeDB::bind_method(_MD("get_stage_count"),&ResourceInteractiveLoader::get_stage_count);
+}
+
+class ResourceInteractiveLoaderDefault : public ResourceInteractiveLoader {
+
+ OBJ_TYPE( ResourceInteractiveLoaderDefault, ResourceInteractiveLoader );
+public:
+
+ Ref<Resource> resource;
+
+ virtual void set_local_path(const String& p_local_path) { /*scene->set_filename(p_local_path);*/ }
+ virtual Ref<Resource> get_resource() { return resource; }
+ virtual Error poll() { return ERR_FILE_EOF; }
+ virtual int get_stage() const { return 1; }
+ virtual int get_stage_count() const { return 1; }
+
+ ResourceInteractiveLoaderDefault() {}
+};
+
+
+
+Ref<ResourceInteractiveLoader> ResourceFormatLoader::load_interactive(const String &p_path) {
+
+ //either this
+ Ref<Resource> res = load(p_path);
+ if (res.is_null())
+ return Ref<ResourceInteractiveLoader>();
+
+ Ref<ResourceInteractiveLoaderDefault> ril = Ref<ResourceInteractiveLoaderDefault>( memnew( ResourceInteractiveLoaderDefault ));
+ ril->resource=res;
+ return ril;
+}
+
+RES ResourceFormatLoader::load(const String &p_path,const String& p_original_path) {
+
+
+ //or this must be implemented
+ Ref<ResourceInteractiveLoader> ril = load_interactive(p_path);
+ if (!ril.is_valid())
+ return RES();
+ ril->set_local_path(p_original_path);
+
+ while(true) {
+
+ Error err = ril->poll();
+
+ if (err==ERR_FILE_EOF) {
+ return ril->get_resource();
+ }
+
+ ERR_FAIL_COND_V(err!=OK,RES());
+ }
+
+ return RES();
+
+}
+
+void ResourceFormatLoader::get_dependencies(const String& p_path,List<String> *p_dependencies) {
+
+ //do nothing by default
+}
+
+
+///////////////////////////////////
+
+
+RES ResourceLoader::load(const String &p_path,const String& p_type_hint,bool p_no_cache) {
+
+ String local_path = Globals::get_singleton()->localize_path(p_path);
+
+ local_path=find_complete_path(p_path,p_type_hint);
+ ERR_FAIL_COND_V(local_path=="",RES());
+
+ if (!p_no_cache && ResourceCache::has(local_path)) {
+
+ if (OS::get_singleton()->is_stdout_verbose())
+ print_line("load resource: "+local_path+" (cached)");
+
+ return RES( ResourceCache::get(local_path ) );
+ }
+
+ String remapped_path = PathRemap::get_singleton()->get_remap(local_path);
+
+ if (OS::get_singleton()->is_stdout_verbose())
+ print_line("load resource: ");
+
+ String extension=remapped_path.extension();
+ bool found=false;
+
+ for (int i=0;i<loader_count;i++) {
+
+ if (!loader[i]->recognize(extension))
+ continue;
+ if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint))
+ continue;
+ found=true;
+ RES res = loader[i]->load(remapped_path,local_path);
+ if (res.is_null())
+ continue;
+ if (!p_no_cache)
+ res->set_path(local_path);
+#ifdef TOOLS_ENABLED
+
+ res->set_edited(false);
+ if (timestamp_on_load) {
+ uint64_t mt = FileAccess::get_modified_time(remapped_path);
+ //printf("mt %s: %lli\n",remapped_path.utf8().get_data(),mt);
+ res->set_last_modified_time(mt);
+ }
+#endif
+ return res;
+ }
+
+ if (found) {
+ ERR_EXPLAIN("Failed loading resource: "+p_path);
+ } else {
+ ERR_EXPLAIN("No loader found for resource: "+p_path);
+ }
+ ERR_FAIL_V(RES());
+ return RES();
+}
+
+
+Ref<ResourceImportMetadata> ResourceLoader::load_import_metadata(const String &p_path) {
+
+
+ String local_path = Globals::get_singleton()->localize_path(p_path);
+
+ String extension=p_path.extension();
+ bool found=false;
+ Ref<ResourceImportMetadata> ret;
+
+ for (int i=0;i<loader_count;i++) {
+
+ if (!loader[i]->recognize(extension))
+ continue;
+ found=true;
+
+ Error err = loader[i]->load_import_metadata(local_path,ret);
+ if (err==OK)
+ break;
+ }
+
+ return ret;
+
+}
+
+
+
+String ResourceLoader::find_complete_path(const String& p_path,const String& p_type) {
+
+ String local_path = p_path;
+ if (local_path.ends_with("*")) {
+
+ //find the extension for resource that ends with *
+ local_path = local_path.substr(0,local_path.length()-1);
+ List<String> extensions;
+ get_recognized_extensions_for_type(p_type,&extensions);
+ List<String> candidates;
+
+ for(List<String>::Element *E=extensions.front();E;E=E->next()) {
+
+ String path = local_path+E->get();
+
+ if (FileAccess::exists(path)) {
+ candidates.push_back(path);
+ }
+
+ }
+
+
+ if (candidates.size()==0) {
+ return "";
+ } else if (candidates.size()==1 || p_type=="") {
+ return candidates.front()->get();
+ } else {
+
+ for(List<String>::Element *E=candidates.front();E;E=E->next()) {
+
+ String rt = get_resource_type(E->get());
+ if (ObjectTypeDB::is_type(rt,p_type)) {
+ return E->get();
+ }
+ }
+
+ return "";
+ }
+ }
+
+ return local_path;
+}
+
+Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_path,const String& p_type_hint,bool p_no_cache) {
+
+
+
+ String local_path = Globals::get_singleton()->localize_path(p_path);
+
+ local_path=find_complete_path(p_path,p_type_hint);
+ ERR_FAIL_COND_V(local_path=="",Ref<ResourceInteractiveLoader>());
+
+
+
+ if (!p_no_cache && ResourceCache::has(local_path)) {
+
+ if (OS::get_singleton()->is_stdout_verbose())
+ print_line("load resource: "+local_path+" (cached)");
+
+ return RES( ResourceCache::get(local_path ) );
+ }
+
+ if (OS::get_singleton()->is_stdout_verbose())
+ print_line("load resource: ");
+
+ String remapped_path = PathRemap::get_singleton()->get_remap(local_path);
+
+ String extension=remapped_path.extension();
+ bool found=false;
+
+ for (int i=0;i<loader_count;i++) {
+
+ if (!loader[i]->recognize(extension))
+ continue;
+ if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint))
+ continue;
+ found=true;
+ Ref<ResourceInteractiveLoader> ril = loader[i]->load_interactive(remapped_path);
+ if (ril.is_null())
+ continue;
+ if (!p_no_cache)
+ ril->set_local_path(local_path);
+
+ return ril;
+ }
+
+ if (found) {
+ ERR_EXPLAIN("Failed loading resource: "+p_path);
+ } else {
+ ERR_EXPLAIN("No loader found for resource: "+p_path);
+ }
+ ERR_FAIL_V(Ref<ResourceInteractiveLoader>());
+ return Ref<ResourceInteractiveLoader>();
+
+}
+
+void ResourceLoader::add_resource_format_loader(ResourceFormatLoader *p_format_loader) {
+
+ ERR_FAIL_COND( loader_count >= MAX_LOADERS );
+ loader[loader_count++]=p_format_loader;
+}
+
+void ResourceLoader::get_dependencies(const String& p_path,List<String> *p_dependencies) {
+
+ String local_path = Globals::get_singleton()->localize_path(p_path);
+ String remapped_path = PathRemap::get_singleton()->get_remap(local_path);
+
+ String extension=remapped_path.extension();
+
+ for (int i=0;i<loader_count;i++) {
+
+ if (!loader[i]->recognize(extension))
+ continue;
+ //if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint))
+ // continue;
+
+ loader[i]->get_dependencies(remapped_path,p_dependencies);
+
+ }
+}
+
+
+String ResourceLoader::get_resource_type(const String &p_path) {
+
+ String local_path = Globals::get_singleton()->localize_path(p_path);
+ String remapped_path = PathRemap::get_singleton()->get_remap(local_path);
+ String extension=remapped_path.extension();
+
+ bool found=false;
+ for (int i=0;i<loader_count;i++) {
+
+ String result = loader[i]->get_resource_type(local_path);
+ if (result!="")
+ return result;
+ }
+
+ return "";
+
+}
+ResourceLoadErrorNotify ResourceLoader::err_notify=NULL;
+void *ResourceLoader::err_notify_ud=NULL;
+
+bool ResourceLoader::abort_on_missing_resource=true;
+bool ResourceLoader::timestamp_on_load=false;
+
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
new file mode 100644
index 0000000000..70b1a79582
--- /dev/null
+++ b/core/io/resource_loader.h
@@ -0,0 +1,114 @@
+/*************************************************************************/
+/* resource_loader.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef RESOURCE_LOADER_H
+#define RESOURCE_LOADER_H
+
+#include "resource.h"
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+class ResourceInteractiveLoader : public Reference {
+
+ OBJ_TYPE(ResourceInteractiveLoader,Reference);
+protected:
+
+ static void _bind_methods();
+public:
+
+ virtual void set_local_path(const String& p_local_path)=0;
+ virtual Ref<Resource> get_resource()=0;
+ virtual Error poll()=0;
+ virtual int get_stage() const=0;
+ virtual int get_stage_count() const=0;
+ virtual Error wait();
+
+ ResourceInteractiveLoader() {}
+};
+
+
+class ResourceFormatLoader {
+public:
+
+ virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path);
+ virtual RES load(const String &p_path,const String& p_original_path="");
+ virtual void get_recognized_extensions(List<String> *p_extensions) const=0;
+ virtual void get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const;
+ bool recognize(const String& p_extension) const;
+ virtual bool handles_type(const String& p_type) const=0;
+ virtual String get_resource_type(const String &p_path) const=0;
+ virtual void get_dependencies(const String& p_path,List<String> *p_dependencies);
+ virtual Error load_import_metadata(const String &p_path, Ref<ResourceImportMetadata>& r_var) const { return ERR_UNAVAILABLE; }
+
+ virtual ~ResourceFormatLoader() {}
+};
+
+
+typedef void (*ResourceLoadErrorNotify)(void *p_ud,const String& p_text);
+
+
+class ResourceLoader {
+
+ enum {
+ MAX_LOADERS=64
+ };
+
+ static ResourceFormatLoader *loader[MAX_LOADERS];
+ static int loader_count;
+ static bool timestamp_on_load;
+
+ static void* err_notify_ud;
+ static ResourceLoadErrorNotify err_notify;
+ static bool abort_on_missing_resource;
+
+ static String find_complete_path(const String& p_path,const String& p_type);
+public:
+
+
+
+ static Ref<ResourceInteractiveLoader> load_interactive(const String &p_path,const String& p_type_hint="",bool p_no_cache=false);
+ static RES load(const String &p_path,const String& p_type_hint="",bool p_no_cache=false);
+ static Ref<ResourceImportMetadata> load_import_metadata(const String &p_path);
+
+ static void get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions);
+ static void add_resource_format_loader(ResourceFormatLoader *p_format_loader);
+ static String get_resource_type(const String &p_path);
+ static void get_dependencies(const String& p_path,List<String> *p_dependencies);
+
+
+ static void set_timestamp_on_load(bool p_timestamp) { timestamp_on_load=p_timestamp; }
+
+ static void notify_load_error(const String& p_err) { if (err_notify) err_notify(err_notify_ud,p_err); }
+ static void set_error_notify_func(void* p_ud,ResourceLoadErrorNotify p_err_notify) { err_notify=p_err_notify; err_notify_ud=p_ud;}
+ static void set_abort_on_missing_resources(bool p_abort) { abort_on_missing_resource=p_abort; }
+ static bool get_abort_on_missing_resources() { return abort_on_missing_resource; }
+};
+
+#endif
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
new file mode 100644
index 0000000000..598f517d76
--- /dev/null
+++ b/core/io/resource_saver.cpp
@@ -0,0 +1,127 @@
+/*************************************************************************/
+/* resource_saver.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. */
+/*************************************************************************/
+#include "resource_saver.h"
+#include "globals.h"
+#include "os/file_access.h"
+#include "script_language.h"
+#include "resource_loader.h"
+
+ResourceFormatSaver *ResourceSaver::saver[MAX_SAVERS];
+
+int ResourceSaver::saver_count=0;
+bool ResourceSaver::timestamp_on_save=false;
+ResourceSavedCallback ResourceSaver::save_callback=0;
+
+Error ResourceSaver::save(const String &p_path,const RES& p_resource,uint32_t p_flags) {
+
+ String extension=p_path.extension();
+ Error err=ERR_FILE_UNRECOGNIZED;
+
+ for (int i=0;i<saver_count;i++) {
+
+ if (!saver[i]->recognize(p_resource))
+ continue;
+
+ List<String> extensions;
+ bool recognized=false;
+ saver[i]->get_recognized_extensions(p_resource,&extensions);
+
+ for (List<String>::Element *E=extensions.front();E;E=E->next()) {
+
+ if (E->get().nocasecmp_to(extension.extension())==0)
+ recognized=true;
+ }
+
+ if (!recognized)
+ continue;
+
+ String old_path=p_resource->get_path();
+
+
+ String local_path=Globals::get_singleton()->localize_path(p_path);
+
+ RES rwcopy = p_resource;
+ if (p_flags&FLAG_CHANGE_PATH)
+ rwcopy->set_path(local_path);
+
+ err = saver[i]->save(p_path,p_resource,p_flags);
+
+ if (err == OK ) {
+
+#ifdef TOOLS_ENABLED
+
+ ((Resource*)p_resource.ptr())->set_edited(false);
+ if (timestamp_on_save) {
+ uint64_t mt = FileAccess::get_modified_time(p_path);
+
+ ((Resource*)p_resource.ptr())->set_last_modified_time(mt);
+ }
+#endif
+
+ if (p_flags&FLAG_CHANGE_PATH)
+ rwcopy->set_path(old_path);
+
+ if (save_callback && p_path.begins_with("res://"))
+ save_callback(p_path);
+
+ return OK;
+ } else {
+
+ }
+ }
+
+ return err;
+}
+
+
+void ResourceSaver::set_save_callback(ResourceSavedCallback p_callback) {
+
+ save_callback=p_callback;
+}
+
+
+void ResourceSaver::get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) {
+
+
+ for (int i=0;i<saver_count;i++) {
+
+ saver[i]->get_recognized_extensions(p_resource,p_extensions);
+ }
+
+}
+
+void ResourceSaver::add_resource_format_saver(ResourceFormatSaver *p_format_saver) {
+
+ ERR_FAIL_COND( saver_count >= MAX_SAVERS );
+ saver[saver_count++]=p_format_saver;
+}
+
+
+
+
diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h
new file mode 100644
index 0000000000..4b794247e0
--- /dev/null
+++ b/core/io/resource_saver.h
@@ -0,0 +1,95 @@
+/*************************************************************************/
+/* resource_saver.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef RESOURCE_SAVER_H
+#define RESOURCE_SAVER_H
+
+#include "resource.h"
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+
+
+
+
+
+
+class ResourceFormatSaver {
+public:
+
+ virtual Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0)=0;
+ virtual bool recognize(const RES& p_resource) const=0;
+ virtual void get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const=0;
+
+ virtual ~ResourceFormatSaver() {}
+};
+
+typedef void (*ResourceSavedCallback)(const String& p_path);
+
+class ResourceSaver {
+
+ enum {
+ MAX_SAVERS=64
+ };
+
+ static ResourceFormatSaver *saver[MAX_SAVERS];
+ static int saver_count;
+ static bool timestamp_on_save;
+ static ResourceSavedCallback save_callback;
+
+
+public:
+
+ enum SaverFlags {
+
+ FLAG_RELATIVE_PATHS=1,
+ FLAG_BUNDLE_RESOURCES=2,
+ FLAG_CHANGE_PATH=4,
+ FLAG_OMIT_EDITOR_PROPERTIES=8,
+ FLAG_SAVE_BIG_ENDIAN=16,
+ FLAG_COMPRESS=32,
+ FLAG_NO_EXTENSION=64,
+
+
+ };
+
+
+ static Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0);
+ static void get_recognized_extensions(const RES& p_resource,List<String> *p_extensions);
+ static void add_resource_format_saver(ResourceFormatSaver *p_format_saver);
+
+ static void set_timestamp_on_save(bool p_timestamp) { timestamp_on_save=p_timestamp; }
+ static void set_save_callback(ResourceSavedCallback p_callback);
+
+
+
+};
+
+
+#endif
diff --git a/core/io/stream_peer.cpp b/core/io/stream_peer.cpp
new file mode 100644
index 0000000000..0eae660373
--- /dev/null
+++ b/core/io/stream_peer.cpp
@@ -0,0 +1,126 @@
+/*************************************************************************/
+/* stream_peer.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. */
+/*************************************************************************/
+#include "stream_peer.h"
+
+
+Error StreamPeer::_put_data(const DVector<uint8_t>& p_data) {
+
+ int len = p_data.size();
+ if (len==0)
+ return OK;
+ DVector<uint8_t>::Read r = p_data.read();
+ return put_data(&r[0],len);
+}
+
+Array StreamPeer::_put_partial_data(const DVector<uint8_t>& p_data) {
+
+ Array ret;
+
+ int len = p_data.size();
+ if (len==0) {
+ ret.push_back(OK);
+ ret.push_back(0);
+ return ret;
+ }
+
+ DVector<uint8_t>::Read r = p_data.read();
+ int sent;
+ Error err = put_partial_data(&r[0],len,sent);
+
+ if (err!=OK) {
+ sent=0;
+ }
+ ret.push_back(err);
+ ret.push_back(sent);
+ return ret;
+}
+
+
+Array StreamPeer::_get_data(int p_bytes) {
+
+ Array ret;
+
+ DVector<uint8_t> data;
+ data.resize(p_bytes);
+ if (data.size()!=p_bytes) {
+
+ ret.push_back(ERR_OUT_OF_MEMORY);
+ ret.push_back(DVector<uint8_t>());
+ return ret;
+ }
+
+ DVector<uint8_t>::Write w = data.write();
+ Error err = get_data(&w[0],p_bytes);
+ w = DVector<uint8_t>::Write();
+ ret.push_back(err);
+ ret.push_back(data);
+ return ret;
+
+}
+
+Array StreamPeer::_get_partial_data(int p_bytes) {
+
+ Array ret;
+
+ DVector<uint8_t> data;
+ data.resize(p_bytes);
+ if (data.size()!=p_bytes) {
+
+ ret.push_back(ERR_OUT_OF_MEMORY);
+ ret.push_back(DVector<uint8_t>());
+ return ret;
+ }
+
+ DVector<uint8_t>::Write w = data.write();
+ int received;
+ Error err = get_partial_data(&w[0],p_bytes,received);
+ w = DVector<uint8_t>::Write();
+
+ if (err!=OK) {
+ data.resize(0);
+ } else if (received!=data.size()) {
+
+ data.resize(received);
+ }
+
+ ret.push_back(err);
+ ret.push_back(data);
+ return ret;
+
+}
+
+
+void StreamPeer::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("put_data","data"),&StreamPeer::_put_data);
+ ObjectTypeDB::bind_method(_MD("put_partial_data","data"),&StreamPeer::_put_partial_data);
+
+ ObjectTypeDB::bind_method(_MD("get_data","bytes"),&StreamPeer::_get_data);
+ ObjectTypeDB::bind_method(_MD("get_partial_data","bytes"),&StreamPeer::_get_partial_data);
+}
diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h
new file mode 100644
index 0000000000..84552cfd3e
--- /dev/null
+++ b/core/io/stream_peer.h
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* stream_peer.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef STREAM_PEER_H
+#define STREAM_PEER_H
+
+#include "reference.h"
+
+class StreamPeer : public Reference {
+ OBJ_TYPE( StreamPeer, Reference );
+ OBJ_CATEGORY("Networking");
+protected:
+ static void _bind_methods();
+
+ //bind helpers
+ Error _put_data(const DVector<uint8_t>& p_data);
+ Array _put_partial_data(const DVector<uint8_t>& p_data);
+
+ Array _get_data(int p_bytes);
+ Array _get_partial_data(int p_bytes);
+
+public:
+
+ virtual Error put_data(const uint8_t* p_data,int p_bytes)=0; ///< put a whole chunk of data, blocking until it sent
+ virtual Error put_partial_data(const uint8_t* p_data,int p_bytes, int &r_sent)=0; ///< put as much data as possible, without blocking.
+
+ virtual Error get_data(uint8_t* p_buffer, int p_bytes)=0; ///< read p_bytes of data, if p_bytes > available, it will block
+ virtual Error get_partial_data(uint8_t* p_buffer, int p_bytes,int &r_received)=0; ///< read as much data as p_bytes into buffer, if less was read, return in r_received
+
+ StreamPeer() {}
+};
+
+#endif // STREAM_PEER_H
diff --git a/core/io/stream_peer_tcp.cpp b/core/io/stream_peer_tcp.cpp
new file mode 100644
index 0000000000..0fdaab885a
--- /dev/null
+++ b/core/io/stream_peer_tcp.cpp
@@ -0,0 +1,56 @@
+/*************************************************************************/
+/* stream_peer_tcp.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. */
+/*************************************************************************/
+#include "stream_peer_tcp.h"
+
+StreamPeerTCP* (*StreamPeerTCP::_create)()=NULL;
+
+void StreamPeerTCP::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("connect","host","ip"),&StreamPeerTCP::connect);
+ ObjectTypeDB::bind_method(_MD("is_connected"),&StreamPeerTCP::is_connected);
+ ObjectTypeDB::bind_method(_MD("get_connected_host"),&StreamPeerTCP::get_connected_host);
+ ObjectTypeDB::bind_method(_MD("get_connected_port"),&StreamPeerTCP::get_connected_port);
+ ObjectTypeDB::bind_method(_MD("disconnect"),&StreamPeerTCP::disconnect);
+}
+
+Ref<StreamPeerTCP> StreamPeerTCP::create() {
+
+ if (!_create)
+ return Ref<StreamPeerTCP>();
+ return Ref<StreamPeerTCP>(_create());
+}
+
+StreamPeerTCP::StreamPeerTCP() {
+
+}
+
+StreamPeerTCP::~StreamPeerTCP() {
+
+};
+
diff --git a/core/io/stream_peer_tcp.h b/core/io/stream_peer_tcp.h
new file mode 100644
index 0000000000..428ccd3d32
--- /dev/null
+++ b/core/io/stream_peer_tcp.h
@@ -0,0 +1,75 @@
+/*************************************************************************/
+/* stream_peer_tcp.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef STREAM_PEER_TCP_H
+#define STREAM_PEER_TCP_H
+
+#include "stream_peer.h"
+
+#include "ip_address.h"
+
+class StreamPeerTCP : public StreamPeer {
+
+ OBJ_TYPE( StreamPeerTCP, StreamPeer );
+ OBJ_CATEGORY("Networking");
+
+public:
+
+ enum Status {
+
+ STATUS_NONE,
+ STATUS_CONNECTING,
+ STATUS_CONNECTED,
+ STATUS_ERROR,
+ };
+
+protected:
+
+ static StreamPeerTCP* (*_create)();
+ static void _bind_methods();
+
+public:
+
+ virtual Error connect(const IP_Address& p_host, uint16_t p_port)=0;
+
+ //read/write from streampeer
+
+ virtual bool is_connected() const=0;
+ virtual Status get_status() const=0;
+ virtual void disconnect()=0;
+ virtual IP_Address get_connected_host() const=0;
+ virtual uint16_t get_connected_port() const=0;
+ virtual void set_nodelay(bool p_enabled)=0;
+
+ static Ref<StreamPeerTCP> create();
+
+ StreamPeerTCP();
+ ~StreamPeerTCP();
+};
+
+#endif
diff --git a/core/io/tcp_server.cpp b/core/io/tcp_server.cpp
new file mode 100644
index 0000000000..06419b9c6b
--- /dev/null
+++ b/core/io/tcp_server.cpp
@@ -0,0 +1,62 @@
+/*************************************************************************/
+/* tcp_server.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. */
+/*************************************************************************/
+#include "tcp_server.h"
+
+TCP_Server* (*TCP_Server::_create)()=NULL;
+
+Ref<TCP_Server> TCP_Server::create() {
+
+ if (!_create)
+ return NULL;
+ return Ref<TCP_Server>(_create());
+}
+
+Error TCP_Server::_listen(uint16_t p_port,DVector<String> p_accepted_hosts) {
+
+ List<String> hosts;
+ for(int i=0;i<p_accepted_hosts.size();i++)
+ hosts.push_back(p_accepted_hosts.get(i));
+
+ return listen(p_port,hosts.size()?&hosts:NULL);
+
+}
+
+void TCP_Server::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("listen","port","accepted_hosts"),&TCP_Server::_listen,DEFVAL(DVector<String>()));
+ ObjectTypeDB::bind_method(_MD("is_connection_available"),&TCP_Server::is_connection_available);
+ ObjectTypeDB::bind_method(_MD("take_connection"),&TCP_Server::take_connection);
+ ObjectTypeDB::bind_method(_MD("stop"),&TCP_Server::stop);
+
+}
+
+
+TCP_Server::TCP_Server()
+{
+}
diff --git a/core/io/tcp_server.h b/core/io/tcp_server.h
new file mode 100644
index 0000000000..31949be3b6
--- /dev/null
+++ b/core/io/tcp_server.h
@@ -0,0 +1,59 @@
+/*************************************************************************/
+/* tcp_server.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef TCP_SERVER_H
+#define TCP_SERVER_H
+
+#include "io/stream_peer.h"
+#include "io/ip.h"
+#include "stream_peer_tcp.h"
+
+class TCP_Server : public Reference {
+
+ OBJ_TYPE( TCP_Server, Reference );
+protected:
+
+ static TCP_Server* (*_create)();
+
+ //bind helper
+ Error _listen(uint16_t p_port,DVector<String> p_accepted_hosts=DVector<String>());
+ static void _bind_methods();
+public:
+
+ virtual Error listen(uint16_t p_port,const List<String> *p_accepted_hosts=NULL)=0;
+ virtual bool is_connection_available() const=0;
+ virtual Ref<StreamPeerTCP> take_connection()=0;
+
+ virtual void stop()=0; //stop listening
+
+ static Ref<TCP_Server> create();
+
+ TCP_Server();
+};
+
+#endif // TCP_SERVER_H
diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp
new file mode 100644
index 0000000000..0d42cebb41
--- /dev/null
+++ b/core/io/translation_loader_po.cpp
@@ -0,0 +1,201 @@
+/*************************************************************************/
+/* translation_loader_po.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. */
+/*************************************************************************/
+#include "translation_loader_po.h"
+#include "os/file_access.h"
+#include "translation.h"
+
+RES TranslationLoaderPO::load(const String &p_path,const String& p_original_path) {
+
+ FileAccess *f=FileAccess::open(p_path,FileAccess::READ);
+ ERR_FAIL_COND_V(!f,RES());
+
+ String l = f->get_line();
+
+ enum Status {
+
+ STATUS_NONE,
+ STATUS_READING_ID,
+ STATUS_READING_STRING,
+ };
+
+ Status status=STATUS_NONE;
+
+ String msg_id;
+ String msg_str;
+ String config;
+
+ Ref<Translation> translation = Ref<Translation>( memnew( Translation ));
+ int line = 1;
+
+ while(true) {
+
+ String l = f->get_line();
+
+ if (f->eof_reached()) {
+
+ if ( status == STATUS_READING_STRING) {
+
+ if (msg_id!="")
+ translation->add_message(msg_id,msg_str);
+ else if (config=="")
+ config=msg_str;
+ break;
+
+ } else if ( status==STATUS_NONE)
+ break;
+
+ memdelete(f);
+ ERR_EXPLAIN(p_path+":"+itos(line)+" Unexpected EOF while reading 'msgid' at file: ");
+ ERR_FAIL_V(RES());
+ }
+
+ l=l.strip_edges();
+
+ if (l.begins_with("msgid")) {
+
+ if (status==STATUS_READING_ID) {
+
+ memdelete(f);
+ ERR_EXPLAIN(p_path+":"+itos(line)+" nexpected 'msgid', was expecting 'msgstr' while parsing: ");
+ ERR_FAIL_V(RES());
+ }
+
+ if (msg_id!="")
+ translation->add_message(msg_id,msg_str);
+ else if (config=="")
+ config=msg_str;
+
+ l=l.substr(5,l.length()).strip_edges();
+ status=STATUS_READING_ID;
+ msg_id="";
+ msg_str="";
+ }
+
+ if (l.begins_with("msgstr")) {
+
+ if (status!=STATUS_READING_ID) {
+
+ memdelete(f);
+ ERR_EXPLAIN(p_path+":"+itos(line)+" Unexpected 'msgstr', was expecting 'msgid' while parsing: ");
+ ERR_FAIL_V(RES());
+ }
+
+ l=l.substr(6,l.length()).strip_edges();
+ status=STATUS_READING_STRING;
+ }
+
+ if (l=="" || l.begins_with("#")) {
+ line++;
+ continue; //nothing to read or comment
+ }
+
+ if (!l.begins_with("\"") || status==STATUS_NONE) {
+ //not a string? failure!
+ ERR_EXPLAIN(p_path+":"+itos(line)+" Invalid line '"+l+"' while parsing: ");
+ ERR_FAIL_V(RES());
+
+ }
+
+ l=l.substr(1,l.length());
+ //find final quote
+ int end_pos=-1;
+ for(int i=0;i<l.length();i++) {
+
+ if (l[i]=='"' && (i==0 || l[i-1]!='\\')) {
+ end_pos=i;
+ break;
+ }
+ }
+
+ if (end_pos==-1) {
+ ERR_EXPLAIN(p_path+":"+itos(line)+" Expected '\"' at end of message while parsing file: ");
+ ERR_FAIL_V(RES());
+ }
+
+ l=l.substr(0,end_pos);
+ l=l.c_unescape();
+
+
+ if (status==STATUS_READING_ID)
+ msg_id+=l;
+ else
+ msg_str+=l;
+
+ line++;
+ }
+
+
+ f->close();
+ memdelete(f);
+
+ if (config=="") {
+ ERR_EXPLAIN("No config found in file: "+p_path);
+ ERR_FAIL_V(RES());
+ }
+
+ Vector<String> configs = config.split("\n");
+ for(int i=0;i<configs.size();i++) {
+
+ String c = configs[i].strip_edges();
+ int p = c.find(":");
+ if (p==-1)
+ continue;
+ String prop = c.substr(0,p).strip_edges();
+ String value = c.substr(p+1,c.length()).strip_edges();
+
+ if (prop=="X-Language") {
+ translation->set_locale(value);
+ }
+ }
+
+
+ return translation;
+
+}
+
+void TranslationLoaderPO::get_recognized_extensions(List<String> *p_extensions) const{
+
+ p_extensions->push_back("po");
+ //p_extensions->push_back("mo"); //mo in the future...
+}
+bool TranslationLoaderPO::handles_type(const String& p_type) const{
+
+ return (p_type=="Translation");
+}
+
+String TranslationLoaderPO::get_resource_type(const String &p_path) const {
+
+ if (p_path.extension().to_lower()=="po")
+ return "Translation";
+ return "";
+}
+
+TranslationLoaderPO::TranslationLoaderPO()
+{
+}
diff --git a/core/io/translation_loader_po.h b/core/io/translation_loader_po.h
new file mode 100644
index 0000000000..7a0c4e10dc
--- /dev/null
+++ b/core/io/translation_loader_po.h
@@ -0,0 +1,46 @@
+/*************************************************************************/
+/* translation_loader_po.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef TRANSLATION_LOADER_PO_H
+#define TRANSLATION_LOADER_PO_H
+
+#include "io/resource_loader.h"
+
+class TranslationLoaderPO : public ResourceFormatLoader {
+public:
+
+ virtual RES load(const String &p_path,const String& p_original_path="");
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String& p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+
+
+ TranslationLoaderPO();
+};
+
+#endif // TRANSLATION_LOADER_PO_H
diff --git a/core/io/unzip.c b/core/io/unzip.c
new file mode 100644
index 0000000000..ac72457f38
--- /dev/null
+++ b/core/io/unzip.c
@@ -0,0 +1,2216 @@
+/* unzip.c -- IO for uncompress .zip files using zlib
+ Version 1.1, February 14h, 2010
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications of Unzip for Zip64
+ Copyright (C) 2007-2008 Even Rouault
+
+ Modifications for Zip64 support on both zip and unzip
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+
+ ------------------------------------------------------------------------------------
+ Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of
+ compatibility with older software. The following is from the original crypt.c.
+ Code woven in by Terry Thorsen 1/2003.
+
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+
+ crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h]
+
+ The encryption/decryption parts of this source code (as opposed to the
+ non-echoing password parts) were originally written in Europe. The
+ whole source package can be freely distributed, including from the USA.
+ (Prior to January 2000, re-export from the US was a violation of US law.)
+
+ This encryption code is a direct transcription of the algorithm from
+ Roger Schlafly, described by Phil Katz in the file appnote.txt. This
+ file (appnote.txt) is distributed with the PKZIP program (even in the
+ version without encryption capabilities).
+
+ ------------------------------------------------------------------------------------
+
+ Changes in unzip.c
+
+ 2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos
+ 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz*
+ 2007-2008 - Even Rouault - Remove old C style function prototypes
+ 2007-2008 - Even Rouault - Add unzip support for ZIP64
+
+ Copyright (C) 2007-2008 Even Rouault
+
+
+ Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again).
+ Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G
+ should only read the compressed/uncompressed size from the Zip64 format if
+ the size from normal header was 0xFFFFFFFF
+ Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant
+ Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required)
+ Patch created by Daniel Borca
+
+ Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer
+
+ Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson
+
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef NOUNCRYPT
+ #define NOUNCRYPT
+#endif
+
+#include "zlib.h"
+#include "unzip.h"
+
+#ifdef STDC
+# include <stddef.h>
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+ extern int errno;
+#else
+# include <errno.h>
+#endif
+
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+
+#ifndef CASESENSITIVITYDEFAULT_NO
+# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES)
+# define CASESENSITIVITYDEFAULT_NO
+# endif
+#endif
+
+
+#ifndef UNZ_BUFSIZE
+#define UNZ_BUFSIZE (16384)
+#endif
+
+#ifndef UNZ_MAXFILENAMEINZIP
+#define UNZ_MAXFILENAMEINZIP (256)
+#endif
+
+#ifndef ALLOC
+# define ALLOC(size) (malloc(size))
+#endif
+#ifndef TRYFREE
+# define TRYFREE(p) {if (p) free(p);}
+#endif
+
+#define SIZECENTRALDIRITEM (0x2e)
+#define SIZEZIPLOCALHEADER (0x1e)
+
+
+const char unz_copyright[] =
+ " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
+
+/* unz_file_info_interntal contain internal info about a file in zipfile*/
+typedef struct unz_file_info64_internal_s
+{
+ ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */
+} unz_file_info64_internal;
+
+
+/* file_in_zip_read_info_s contain internal information about a file in zipfile,
+ when reading and decompress it */
+typedef struct
+{
+ char *read_buffer; /* internal buffer for compressed data */
+ z_stream stream; /* zLib stream structure for inflate */
+
+#ifdef HAVE_BZIP2
+ bz_stream bstream; /* bzLib stream structure for bziped */
+#endif
+
+ ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/
+ uLong stream_initialised; /* flag set if stream structure is initialised*/
+
+ ZPOS64_T offset_local_extrafield;/* offset of the local extra field */
+ uInt size_local_extrafield;/* size of the local extra field */
+ ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/
+ ZPOS64_T total_out_64;
+
+ uLong crc32; /* crc32 of all data uncompressed */
+ uLong crc32_wait; /* crc32 we must obtain after decompress all */
+ ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */
+ ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/
+ zlib_filefunc64_32_def z_filefunc;
+ voidpf filestream; /* io structore of the zipfile */
+ uLong compression_method; /* compression method (0==store) */
+ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+ int raw;
+ int extra_size;
+} file_in_zip64_read_info_s;
+
+
+/* unz64_s contain internal information about the zipfile
+*/
+typedef struct
+{
+ zlib_filefunc64_32_def z_filefunc;
+ int is64bitOpenFunction;
+ voidpf filestream; /* io structore of the zipfile */
+ unz_global_info64 gi; /* public global information */
+ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+ ZPOS64_T num_file; /* number of the current file in the zipfile*/
+ ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/
+ ZPOS64_T current_file_ok; /* flag about the usability of the current file*/
+ ZPOS64_T central_pos; /* position of the beginning of the central dir*/
+
+ ZPOS64_T size_central_dir; /* size of the central directory */
+ ZPOS64_T offset_central_dir; /* offset of start of central directory with
+ respect to the starting disk number */
+
+ unz_file_info64 cur_file_info; /* public info about the current file in zip*/
+ unz_file_info64_internal cur_file_info_internal; /* private info about it*/
+ file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current
+ file if we are decompressing it */
+ int encrypted;
+
+ int isZip64;
+
+# ifndef NOUNCRYPT
+ unsigned long keys[3]; /* keys defining the pseudo-random sequence */
+ const unsigned long* pcrc_32_tab;
+# endif
+} unz64_s;
+
+
+#ifndef NOUNCRYPT
+#include "crypt.h"
+#endif
+
+/* ===========================================================================
+ Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+ for end of file.
+ IN assertion: the stream s has been sucessfully opened for reading.
+*/
+
+
+local int unz64local_getByte OF((
+ const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ int *pi));
+
+local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)
+{
+ unsigned char c;
+ int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1);
+ if (err==1)
+ {
+ *pi = (int)c;
+ return UNZ_OK;
+ }
+ else
+ {
+ if (ZERROR64(*pzlib_filefunc_def,filestream))
+ return UNZ_ERRNO;
+ else
+ return UNZ_EOF;
+ }
+}
+
+
+/* ===========================================================================
+ Reads a long in LSB order from the given gz_stream. Sets
+*/
+local int unz64local_getShort OF((
+ const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ uLong *pX));
+
+local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ uLong *pX)
+{
+ uLong x ;
+ int i = 0;
+ int err;
+
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (uLong)i;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((uLong)i)<<8;
+
+ if (err==UNZ_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+local int unz64local_getLong OF((
+ const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ uLong *pX));
+
+local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ uLong *pX)
+{
+ uLong x ;
+ int i = 0;
+ int err;
+
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (uLong)i;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((uLong)i)<<8;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((uLong)i)<<16;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<24;
+
+ if (err==UNZ_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+local int unz64local_getLong64 OF((
+ const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ ZPOS64_T *pX));
+
+
+local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ ZPOS64_T *pX)
+{
+ ZPOS64_T x ;
+ int i = 0;
+ int err;
+
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (ZPOS64_T)i;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<8;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<16;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<24;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<32;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<40;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<48;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<56;
+
+ if (err==UNZ_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+/* My own strcmpi / strcasecmp */
+local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2)
+{
+ for (;;)
+ {
+ char c1=*(fileName1++);
+ char c2=*(fileName2++);
+ if ((c1>='a') && (c1<='z'))
+ c1 -= 0x20;
+ if ((c2>='a') && (c2<='z'))
+ c2 -= 0x20;
+ if (c1=='\0')
+ return ((c2=='\0') ? 0 : -1);
+ if (c2=='\0')
+ return 1;
+ if (c1<c2)
+ return -1;
+ if (c1>c2)
+ return 1;
+ }
+}
+
+
+#ifdef CASESENSITIVITYDEFAULT_NO
+#define CASESENSITIVITYDEFAULTVALUE 2
+#else
+#define CASESENSITIVITYDEFAULTVALUE 1
+#endif
+
+#ifndef STRCMPCASENOSENTIVEFUNCTION
+#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal
+#endif
+
+/*
+ Compare two filename (fileName1,fileName2).
+ If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
+ If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
+ or strcasecmp)
+ If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
+ (like 1 on Unix, 2 on Windows)
+
+*/
+extern int ZEXPORT unzStringFileNameCompare (const char* fileName1,
+ const char* fileName2,
+ int iCaseSensitivity)
+
+{
+ if (iCaseSensitivity==0)
+ iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;
+
+ if (iCaseSensitivity==1)
+ return strcmp(fileName1,fileName2);
+
+ return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2);
+}
+
+#ifndef BUFREADCOMMENT
+#define BUFREADCOMMENT (0x400)
+#endif
+
+/*
+ Locate the Central directory of a zipfile (at the end, just before
+ the global comment)
+*/
+local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream));
+local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)
+{
+ unsigned char* buf;
+ ZPOS64_T uSizeFile;
+ ZPOS64_T uBackRead;
+ ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
+ ZPOS64_T uPosFound=0;
+
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+ return 0;
+
+
+ uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
+
+ if (uMaxBack>uSizeFile)
+ uMaxBack = uSizeFile;
+
+ buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+ if (buf==NULL)
+ return 0;
+
+ uBackRead = 4;
+ while (uBackRead<uMaxBack)
+ {
+ uLong uReadSize;
+ ZPOS64_T uReadPos ;
+ int i;
+ if (uBackRead+BUFREADCOMMENT>uMaxBack)
+ uBackRead = uMaxBack;
+ else
+ uBackRead+=BUFREADCOMMENT;
+ uReadPos = uSizeFile-uBackRead ;
+
+ uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
+ (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ break;
+
+ if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
+ break;
+
+ for (i=(int)uReadSize-3; (i--)>0;)
+ if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
+ ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
+ {
+ uPosFound = uReadPos+i;
+ break;
+ }
+
+ if (uPosFound!=0)
+ break;
+ }
+ TRYFREE(buf);
+ return uPosFound;
+}
+
+
+/*
+ Locate the Central directory 64 of a zipfile (at the end, just before
+ the global comment)
+*/
+local ZPOS64_T unz64local_SearchCentralDir64 OF((
+ const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream));
+
+local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream)
+{
+ unsigned char* buf;
+ ZPOS64_T uSizeFile;
+ ZPOS64_T uBackRead;
+ ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
+ ZPOS64_T uPosFound=0;
+ uLong uL;
+ ZPOS64_T relativeOffset;
+
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+ return 0;
+
+
+ uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
+
+ if (uMaxBack>uSizeFile)
+ uMaxBack = uSizeFile;
+
+ buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+ if (buf==NULL)
+ return 0;
+
+ uBackRead = 4;
+ while (uBackRead<uMaxBack)
+ {
+ uLong uReadSize;
+ ZPOS64_T uReadPos;
+ int i;
+ if (uBackRead+BUFREADCOMMENT>uMaxBack)
+ uBackRead = uMaxBack;
+ else
+ uBackRead+=BUFREADCOMMENT;
+ uReadPos = uSizeFile-uBackRead ;
+
+ uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
+ (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ break;
+
+ if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
+ break;
+
+ for (i=(int)uReadSize-3; (i--)>0;)
+ if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
+ ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07))
+ {
+ uPosFound = uReadPos+i;
+ break;
+ }
+
+ if (uPosFound!=0)
+ break;
+ }
+ TRYFREE(buf);
+ if (uPosFound == 0)
+ return 0;
+
+ /* Zip64 end of central directory locator */
+ if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return 0;
+
+ /* the signature, already checked */
+ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
+ return 0;
+
+ /* number of the disk with the start of the zip64 end of central directory */
+ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
+ return 0;
+ if (uL != 0)
+ return 0;
+
+ /* relative offset of the zip64 end of central directory record */
+ if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK)
+ return 0;
+
+ /* total number of disks */
+ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
+ return 0;
+ if (uL != 1)
+ return 0;
+
+ /* Goto end of central directory record */
+ if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return 0;
+
+ /* the signature */
+ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
+ return 0;
+
+ if (uL != 0x06064b50)
+ return 0;
+
+ return relativeOffset;
+}
+
+/*
+ Open a Zip file. path contain the full pathname (by example,
+ on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer
+ "zlib/zlib114.zip".
+ If the zipfile cannot be opened (file doesn't exist or in not valid), the
+ return value is NULL.
+ Else, the return value is a unzFile Handle, usable with other function
+ of this unzip package.
+*/
+local unzFile unzOpenInternal (const void *path,
+ zlib_filefunc64_32_def* pzlib_filefunc64_32_def,
+ int is64bitOpenFunction)
+{
+ unz64_s us;
+ unz64_s *s;
+ ZPOS64_T central_pos;
+ uLong uL;
+
+ uLong number_disk; /* number of the current dist, used for
+ spaning ZIP, unsupported, always 0*/
+ uLong number_disk_with_CD; /* number the the disk with central dir, used
+ for spaning ZIP, unsupported, always 0*/
+ ZPOS64_T number_entry_CD; /* total number of entries in
+ the central dir
+ (same than number_entry on nospan) */
+
+ int err=UNZ_OK;
+
+ if (unz_copyright[0]!=' ')
+ return NULL;
+
+ us.z_filefunc.zseek32_file = NULL;
+ us.z_filefunc.ztell32_file = NULL;
+ if (pzlib_filefunc64_32_def==NULL)
+ return NULL; // standard i/o not supported
+ us.z_filefunc = *pzlib_filefunc64_32_def;
+ us.is64bitOpenFunction = is64bitOpenFunction;
+
+
+
+ us.filestream = ZOPEN64(us.z_filefunc,
+ path,
+ ZLIB_FILEFUNC_MODE_READ |
+ ZLIB_FILEFUNC_MODE_EXISTING);
+ if (us.filestream==NULL) {
+ printf("no stream\n");
+ return NULL;
+ };
+
+ central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream);
+ if (central_pos)
+ {
+ uLong uS;
+ ZPOS64_T uL64;
+
+ us.isZip64 = 1;
+
+ if (ZSEEK64(us.z_filefunc, us.filestream,
+ central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err=UNZ_ERRNO;
+
+ /* the signature, already checked */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* size of zip64 end of central directory record */
+ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* version made by */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* version needed to extract */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* number of this disk */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* number of the disk with the start of the central directory */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* total number of entries in the central directory on this disk */
+ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* total number of entries in the central directory */
+ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if ((number_entry_CD!=us.gi.number_entry) ||
+ (number_disk_with_CD!=0) ||
+ (number_disk!=0))
+ err=UNZ_BADZIPFILE;
+
+ /* size of the central directory */
+ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* offset of start of central directory with respect to the
+ starting disk number */
+ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ us.gi.size_comment = 0;
+ }
+ else
+ {
+ central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream);
+ if (central_pos==0)
+ err=UNZ_ERRNO;
+
+ us.isZip64 = 0;
+
+ if (ZSEEK64(us.z_filefunc, us.filestream,
+ central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err=UNZ_ERRNO;
+
+ /* the signature, already checked */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* number of this disk */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* number of the disk with the start of the central directory */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* total number of entries in the central dir on this disk */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ us.gi.number_entry = uL;
+
+ /* total number of entries in the central dir */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ number_entry_CD = uL;
+
+ if ((number_entry_CD!=us.gi.number_entry) ||
+ (number_disk_with_CD!=0) ||
+ (number_disk!=0))
+ err=UNZ_BADZIPFILE;
+
+ /* size of the central directory */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ us.size_central_dir = uL;
+
+ /* offset of start of central directory with respect to the
+ starting disk number */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ us.offset_central_dir = uL;
+
+ /* zipfile comment length */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ }
+
+ if ((central_pos<us.offset_central_dir+us.size_central_dir) &&
+ (err==UNZ_OK))
+ err=UNZ_BADZIPFILE;
+
+ if (err!=UNZ_OK)
+ {
+ printf("err is %i, %x\n", err, err);
+ ZCLOSE64(us.z_filefunc, us.filestream);
+ return NULL;
+ }
+
+ us.byte_before_the_zipfile = central_pos -
+ (us.offset_central_dir+us.size_central_dir);
+ us.central_pos = central_pos;
+ us.pfile_in_zip_read = NULL;
+ us.encrypted = 0;
+
+
+ s=(unz64_s*)ALLOC(sizeof(unz64_s));
+ if( s != NULL)
+ {
+ *s=us;
+ unzGoToFirstFile((unzFile)s);
+ }
+ return (unzFile)s;
+}
+
+
+extern unzFile ZEXPORT unzOpen2 (const char *path,
+ zlib_filefunc_def* pzlib_filefunc32_def)
+{
+ if (pzlib_filefunc32_def != NULL)
+ {
+ zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+ fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def);
+ return unzOpenInternal(path, &zlib_filefunc64_32_def_fill, 0);
+ }
+ else
+ return unzOpenInternal(path, NULL, 0);
+}
+
+extern unzFile ZEXPORT unzOpen2_64 (const void *path,
+ zlib_filefunc64_def* pzlib_filefunc_def)
+{
+ if (pzlib_filefunc_def != NULL)
+ {
+ zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+ zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
+ zlib_filefunc64_32_def_fill.ztell32_file = NULL;
+ zlib_filefunc64_32_def_fill.zseek32_file = NULL;
+ return unzOpenInternal(path, &zlib_filefunc64_32_def_fill, 1);
+ }
+ else
+ return unzOpenInternal(path, NULL, 1);
+}
+
+extern unzFile ZEXPORT unzOpen (const char *path)
+{
+ return unzOpenInternal(path, NULL, 0);
+}
+
+extern unzFile ZEXPORT unzOpen64 (const void *path)
+{
+ return unzOpenInternal(path, NULL, 1);
+}
+
+extern void* unzGetOpaque(unzFile file) {
+
+ unz64_s* s;
+ if (file==NULL)
+ return NULL;
+ s=(unz64_s*)file;
+
+ return s->z_filefunc.zfile_func64.opaque;
+};
+
+/*
+ Close a ZipFile opened with unzipOpen.
+ If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),
+ these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
+ return UNZ_OK if there is no problem. */
+extern int ZEXPORT unzClose (unzFile file)
+{
+ unz64_s* s;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+
+ if (s->pfile_in_zip_read!=NULL)
+ unzCloseCurrentFile(file);
+
+ ZCLOSE64(s->z_filefunc, s->filestream);
+ TRYFREE(s);
+ return UNZ_OK;
+}
+
+
+/*
+ Write info about the ZipFile in the *pglobal_info structure.
+ No preparation of the structure is needed
+ return UNZ_OK if there is no problem. */
+extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info)
+{
+ unz64_s* s;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ *pglobal_info=s->gi;
+ return UNZ_OK;
+}
+
+extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32)
+{
+ unz64_s* s;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ /* to do : check if number_entry is not truncated */
+ pglobal_info32->number_entry = (uLong)s->gi.number_entry;
+ pglobal_info32->size_comment = s->gi.size_comment;
+ return UNZ_OK;
+}
+/*
+ Translate date/time from Dos format to tm_unz (readable more easilty)
+*/
+local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm)
+{
+ ZPOS64_T uDate;
+ uDate = (ZPOS64_T)(ulDosDate>>16);
+ ptm->tm_mday = (uInt)(uDate&0x1f) ;
+ ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ;
+ ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ;
+
+ ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800);
+ ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ;
+ ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ;
+}
+
+/*
+ Get Info about the current file in the zipfile, with internal only info
+*/
+local int unz64local_GetCurrentFileInfoInternal OF((unzFile file,
+ unz_file_info64 *pfile_info,
+ unz_file_info64_internal
+ *pfile_info_internal,
+ char *szFileName,
+ uLong fileNameBufferSize,
+ void *extraField,
+ uLong extraFieldBufferSize,
+ char *szComment,
+ uLong commentBufferSize));
+
+local int unz64local_GetCurrentFileInfoInternal (unzFile file,
+ unz_file_info64 *pfile_info,
+ unz_file_info64_internal
+ *pfile_info_internal,
+ char *szFileName,
+ uLong fileNameBufferSize,
+ void *extraField,
+ uLong extraFieldBufferSize,
+ char *szComment,
+ uLong commentBufferSize)
+{
+ unz64_s* s;
+ unz_file_info64 file_info;
+ unz_file_info64_internal file_info_internal;
+ int err=UNZ_OK;
+ uLong uMagic;
+ long lSeek=0;
+ uLong uL;
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ if (ZSEEK64(s->z_filefunc, s->filestream,
+ s->pos_in_central_dir+s->byte_before_the_zipfile,
+ ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err=UNZ_ERRNO;
+
+
+ /* we check the magic */
+ if (err==UNZ_OK)
+ {
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
+ err=UNZ_ERRNO;
+ else if (uMagic!=0x02014b50)
+ err=UNZ_BADZIPFILE;
+ }
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
+ err=UNZ_ERRNO;
+ file_info.compressed_size = uL;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
+ err=UNZ_ERRNO;
+ file_info.uncompressed_size = uL;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ // relative offset of local header
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
+ err=UNZ_ERRNO;
+ file_info_internal.offset_curfile = uL;
+
+ lSeek+=file_info.size_filename;
+ if ((err==UNZ_OK) && (szFileName!=NULL))
+ {
+ uLong uSizeRead ;
+ if (file_info.size_filename<fileNameBufferSize)
+ {
+ *(szFileName+file_info.size_filename)='\0';
+ uSizeRead = file_info.size_filename;
+ }
+ else
+ uSizeRead = fileNameBufferSize;
+
+ if ((file_info.size_filename>0) && (fileNameBufferSize>0))
+ if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead)
+ err=UNZ_ERRNO;
+ lSeek -= uSizeRead;
+ }
+
+ // Read extrafield
+ if ((err==UNZ_OK) && (extraField!=NULL))
+ {
+ ZPOS64_T uSizeRead ;
+ if (file_info.size_file_extra<extraFieldBufferSize)
+ uSizeRead = file_info.size_file_extra;
+ else
+ uSizeRead = extraFieldBufferSize;
+
+ if (lSeek!=0)
+ {
+ if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
+ lSeek=0;
+ else
+ err=UNZ_ERRNO;
+ }
+
+ if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
+ if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead)
+ err=UNZ_ERRNO;
+
+ lSeek += file_info.size_file_extra - (uLong)uSizeRead;
+ }
+ else
+ lSeek += file_info.size_file_extra;
+
+
+ if ((err==UNZ_OK) && (file_info.size_file_extra != 0))
+ {
+ uLong acc = 0;
+
+ // since lSeek now points to after the extra field we need to move back
+ lSeek -= file_info.size_file_extra;
+
+ if (lSeek!=0)
+ {
+ if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
+ lSeek=0;
+ else
+ err=UNZ_ERRNO;
+ }
+
+ while(acc < file_info.size_file_extra)
+ {
+ uLong headerId;
+ uLong dataSize;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* ZIP64 extra fields */
+ if (headerId == 0x0001)
+ {
+ uLong uL;
+
+ if(file_info.uncompressed_size == (ZPOS64_T)(unsigned long)-1)
+ {
+ if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK)
+ err=UNZ_ERRNO;
+ }
+
+ if(file_info.compressed_size == (ZPOS64_T)(unsigned long)-1)
+ {
+ if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK)
+ err=UNZ_ERRNO;
+ }
+
+ if(file_info_internal.offset_curfile == (ZPOS64_T)(unsigned long)-1)
+ {
+ /* Relative Header offset */
+ if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK)
+ err=UNZ_ERRNO;
+ }
+
+ if(file_info.disk_num_start == (unsigned long)-1)
+ {
+ /* Disk Start Number */
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
+ err=UNZ_ERRNO;
+ }
+
+ }
+ else
+ {
+ if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0)
+ err=UNZ_ERRNO;
+ }
+
+ acc += 2 + 2 + dataSize;
+ }
+ }
+
+ if ((err==UNZ_OK) && (szComment!=NULL))
+ {
+ uLong uSizeRead ;
+ if (file_info.size_file_comment<commentBufferSize)
+ {
+ *(szComment+file_info.size_file_comment)='\0';
+ uSizeRead = file_info.size_file_comment;
+ }
+ else
+ uSizeRead = commentBufferSize;
+
+ if (lSeek!=0)
+ {
+ if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
+ lSeek=0;
+ else
+ err=UNZ_ERRNO;
+ }
+
+ if ((file_info.size_file_comment>0) && (commentBufferSize>0))
+ if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead)
+ err=UNZ_ERRNO;
+ lSeek+=file_info.size_file_comment - uSizeRead;
+ }
+ else
+ lSeek+=file_info.size_file_comment;
+
+
+ if ((err==UNZ_OK) && (pfile_info!=NULL))
+ *pfile_info=file_info;
+
+ if ((err==UNZ_OK) && (pfile_info_internal!=NULL))
+ *pfile_info_internal=file_info_internal;
+
+ return err;
+}
+
+
+
+/*
+ Write info about the ZipFile in the *pglobal_info structure.
+ No preparation of the structure is needed
+ return UNZ_OK if there is no problem.
+*/
+extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file,
+ unz_file_info64 * pfile_info,
+ char * szFileName, uLong fileNameBufferSize,
+ void *extraField, uLong extraFieldBufferSize,
+ char* szComment, uLong commentBufferSize)
+{
+ return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL,
+ szFileName,fileNameBufferSize,
+ extraField,extraFieldBufferSize,
+ szComment,commentBufferSize);
+}
+
+extern int ZEXPORT unzGetCurrentFileInfo (unzFile file,
+ unz_file_info * pfile_info,
+ char * szFileName, uLong fileNameBufferSize,
+ void *extraField, uLong extraFieldBufferSize,
+ char* szComment, uLong commentBufferSize)
+{
+ int err;
+ unz_file_info64 file_info64;
+ err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL,
+ szFileName,fileNameBufferSize,
+ extraField,extraFieldBufferSize,
+ szComment,commentBufferSize);
+ if (err==UNZ_OK)
+ {
+ pfile_info->version = file_info64.version;
+ pfile_info->version_needed = file_info64.version_needed;
+ pfile_info->flag = file_info64.flag;
+ pfile_info->compression_method = file_info64.compression_method;
+ pfile_info->dosDate = file_info64.dosDate;
+ pfile_info->crc = file_info64.crc;
+
+ pfile_info->size_filename = file_info64.size_filename;
+ pfile_info->size_file_extra = file_info64.size_file_extra;
+ pfile_info->size_file_comment = file_info64.size_file_comment;
+
+ pfile_info->disk_num_start = file_info64.disk_num_start;
+ pfile_info->internal_fa = file_info64.internal_fa;
+ pfile_info->external_fa = file_info64.external_fa;
+
+ pfile_info->tmu_date = file_info64.tmu_date,
+
+
+ pfile_info->compressed_size = (uLong)file_info64.compressed_size;
+ pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size;
+
+ }
+ return err;
+}
+/*
+ Set the current file of the zipfile to the first file.
+ return UNZ_OK if there is no problem
+*/
+extern int ZEXPORT unzGoToFirstFile (unzFile file)
+{
+ int err=UNZ_OK;
+ unz64_s* s;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ s->pos_in_central_dir=s->offset_central_dir;
+ s->num_file=0;
+ err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+ &s->cur_file_info_internal,
+ NULL,0,NULL,0,NULL,0);
+ s->current_file_ok = (err == UNZ_OK);
+ return err;
+}
+
+/*
+ Set the current file of the zipfile to the next file.
+ return UNZ_OK if there is no problem
+ return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+*/
+extern int ZEXPORT unzGoToNextFile (unzFile file)
+{
+ unz64_s* s;
+ int err;
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_END_OF_LIST_OF_FILE;
+ if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */
+ if (s->num_file+1==s->gi.number_entry)
+ return UNZ_END_OF_LIST_OF_FILE;
+
+ s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
+ s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;
+ s->num_file++;
+ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+ &s->cur_file_info_internal,
+ NULL,0,NULL,0,NULL,0);
+ s->current_file_ok = (err == UNZ_OK);
+ return err;
+}
+
+
+/*
+ Try locate the file szFileName in the zipfile.
+ For the iCaseSensitivity signification, see unzipStringFileNameCompare
+
+ return value :
+ UNZ_OK if the file is found. It becomes the current file.
+ UNZ_END_OF_LIST_OF_FILE if the file is not found
+*/
+extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity)
+{
+ unz64_s* s;
+ int err;
+
+ /* We remember the 'current' position in the file so that we can jump
+ * back there if we fail.
+ */
+ unz_file_info64 cur_file_infoSaved;
+ unz_file_info64_internal cur_file_info_internalSaved;
+ ZPOS64_T num_fileSaved;
+ ZPOS64_T pos_in_central_dirSaved;
+
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+
+ if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)
+ return UNZ_PARAMERROR;
+
+ s=(unz64_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_END_OF_LIST_OF_FILE;
+
+ /* Save the current state */
+ num_fileSaved = s->num_file;
+ pos_in_central_dirSaved = s->pos_in_central_dir;
+ cur_file_infoSaved = s->cur_file_info;
+ cur_file_info_internalSaved = s->cur_file_info_internal;
+
+ err = unzGoToFirstFile(file);
+
+ while (err == UNZ_OK)
+ {
+ char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
+ err = unzGetCurrentFileInfo64(file,NULL,
+ szCurrentFileName,sizeof(szCurrentFileName)-1,
+ NULL,0,NULL,0);
+ if (err == UNZ_OK)
+ {
+ if (unzStringFileNameCompare(szCurrentFileName,
+ szFileName,iCaseSensitivity)==0)
+ return UNZ_OK;
+ err = unzGoToNextFile(file);
+ }
+ }
+
+ /* We failed, so restore the state of the 'current file' to where we
+ * were.
+ */
+ s->num_file = num_fileSaved ;
+ s->pos_in_central_dir = pos_in_central_dirSaved ;
+ s->cur_file_info = cur_file_infoSaved;
+ s->cur_file_info_internal = cur_file_info_internalSaved;
+ return err;
+}
+
+
+/*
+///////////////////////////////////////////
+// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net)
+// I need random access
+//
+// Further optimization could be realized by adding an ability
+// to cache the directory in memory. The goal being a single
+// comprehensive file read to put the file I need in a memory.
+*/
+
+/*
+typedef struct unz_file_pos_s
+{
+ ZPOS64_T pos_in_zip_directory; // offset in file
+ ZPOS64_T num_of_file; // # of file
+} unz_file_pos;
+*/
+
+extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos)
+{
+ unz64_s* s;
+
+ if (file==NULL || file_pos==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_END_OF_LIST_OF_FILE;
+
+ file_pos->pos_in_zip_directory = s->pos_in_central_dir;
+ file_pos->num_of_file = s->num_file;
+
+ return UNZ_OK;
+}
+
+extern int ZEXPORT unzGetFilePos(
+ unzFile file,
+ unz_file_pos* file_pos)
+{
+ unz64_file_pos file_pos64;
+ int err = unzGetFilePos64(file,&file_pos64);
+ if (err==UNZ_OK)
+ {
+ file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory;
+ file_pos->num_of_file = (uLong)file_pos64.num_of_file;
+ }
+ return err;
+}
+
+extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos)
+{
+ unz64_s* s;
+ int err;
+
+ if (file==NULL || file_pos==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+
+ /* jump to the right spot */
+ s->pos_in_central_dir = file_pos->pos_in_zip_directory;
+ s->num_file = file_pos->num_of_file;
+
+ /* set the current file */
+ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+ &s->cur_file_info_internal,
+ NULL,0,NULL,0,NULL,0);
+ /* return results */
+ s->current_file_ok = (err == UNZ_OK);
+ return err;
+}
+
+extern int ZEXPORT unzGoToFilePos(
+ unzFile file,
+ unz_file_pos* file_pos)
+{
+ unz64_file_pos file_pos64;
+ if (file_pos == NULL)
+ return UNZ_PARAMERROR;
+
+ file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory;
+ file_pos64.num_of_file = file_pos->num_of_file;
+ return unzGoToFilePos64(file,&file_pos64);
+}
+
+/*
+// Unzip Helper Functions - should be here?
+///////////////////////////////////////////
+*/
+
+/*
+ Read the local header of the current zipfile
+ Check the coherency of the local header and info in the end of central
+ directory about this file
+ store in *piSizeVar the size of extra info in local header
+ (filename and size of extra field data)
+*/
+local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar,
+ ZPOS64_T * poffset_local_extrafield,
+ uInt * psize_local_extrafield)
+{
+ uLong uMagic,uData,uFlags;
+ uLong size_filename;
+ uLong size_extra_field;
+ int err=UNZ_OK;
+
+ *piSizeVar = 0;
+ *poffset_local_extrafield = 0;
+ *psize_local_extrafield = 0;
+
+ if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile +
+ s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return UNZ_ERRNO;
+
+
+ if (err==UNZ_OK)
+ {
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
+ err=UNZ_ERRNO;
+ else if (uMagic!=0x04034b50)
+ err=UNZ_BADZIPFILE;
+ }
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
+ err=UNZ_ERRNO;
+/*
+ else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
+ err=UNZ_BADZIPFILE;
+*/
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
+ err=UNZ_ERRNO;
+ else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
+ err=UNZ_BADZIPFILE;
+
+ if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
+/* #ifdef HAVE_BZIP2 */
+ (s->cur_file_info.compression_method!=Z_BZIP2ED) &&
+/* #endif */
+ (s->cur_file_info.compression_method!=Z_DEFLATED))
+ err=UNZ_BADZIPFILE;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */
+ err=UNZ_ERRNO;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */
+ err=UNZ_ERRNO;
+ else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0))
+ err=UNZ_BADZIPFILE;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */
+ err=UNZ_ERRNO;
+ else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0))
+ err=UNZ_BADZIPFILE;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */
+ err=UNZ_ERRNO;
+ else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0))
+ err=UNZ_BADZIPFILE;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK)
+ err=UNZ_ERRNO;
+ else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
+ err=UNZ_BADZIPFILE;
+
+ *piSizeVar += (uInt)size_filename;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK)
+ err=UNZ_ERRNO;
+ *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +
+ SIZEZIPLOCALHEADER + size_filename;
+ *psize_local_extrafield = (uInt)size_extra_field;
+
+ *piSizeVar += (uInt)size_extra_field;
+
+ return err;
+}
+
+/*
+ Open for reading data the current file in the zipfile.
+ If there is no error and the file is opened, the return value is UNZ_OK.
+*/
+extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method,
+ int* level, int raw, const char* password)
+{
+ int err=UNZ_OK;
+ uInt iSizeVar;
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ ZPOS64_T offset_local_extrafield; /* offset of the local extra field */
+ uInt size_local_extrafield; /* size of the local extra field */
+# ifndef NOUNCRYPT
+ char source[12];
+# else
+ if (password != NULL)
+ return UNZ_PARAMERROR;
+# endif
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_PARAMERROR;
+
+ if (s->pfile_in_zip_read != NULL)
+ unzCloseCurrentFile(file);
+
+ if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
+ return UNZ_BADZIPFILE;
+
+ pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s));
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_INTERNALERROR;
+
+ pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);
+ pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
+ pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
+ pfile_in_zip_read_info->pos_local_extrafield=0;
+ pfile_in_zip_read_info->raw=raw;
+
+ if (pfile_in_zip_read_info->read_buffer==NULL)
+ {
+ TRYFREE(pfile_in_zip_read_info);
+ return UNZ_INTERNALERROR;
+ }
+
+ pfile_in_zip_read_info->stream_initialised=0;
+
+ if (method!=NULL)
+ *method = (int)s->cur_file_info.compression_method;
+
+ if (level!=NULL)
+ {
+ *level = 6;
+ switch (s->cur_file_info.flag & 0x06)
+ {
+ case 6 : *level = 1; break;
+ case 4 : *level = 2; break;
+ case 2 : *level = 9; break;
+ }
+ }
+
+ if ((s->cur_file_info.compression_method!=0) &&
+/* #ifdef HAVE_BZIP2 */
+ (s->cur_file_info.compression_method!=Z_BZIP2ED) &&
+/* #endif */
+ (s->cur_file_info.compression_method!=Z_DEFLATED))
+
+ err=UNZ_BADZIPFILE;
+
+ pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
+ pfile_in_zip_read_info->crc32=0;
+ pfile_in_zip_read_info->total_out_64=0;
+ pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method;
+ pfile_in_zip_read_info->filestream=s->filestream;
+ pfile_in_zip_read_info->z_filefunc=s->z_filefunc;
+ pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
+
+ pfile_in_zip_read_info->stream.total_out = 0;
+
+ if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw))
+ {
+#ifdef HAVE_BZIP2
+ pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0;
+ pfile_in_zip_read_info->bstream.bzfree = (free_func)0;
+ pfile_in_zip_read_info->bstream.opaque = (voidpf)0;
+ pfile_in_zip_read_info->bstream.state = (voidpf)0;
+
+ pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
+ pfile_in_zip_read_info->stream.zfree = (free_func)0;
+ pfile_in_zip_read_info->stream.opaque = (voidpf)0;
+ pfile_in_zip_read_info->stream.next_in = (voidpf)0;
+ pfile_in_zip_read_info->stream.avail_in = 0;
+
+ err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0);
+ if (err == Z_OK)
+ pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED;
+ else
+ {
+ TRYFREE(pfile_in_zip_read_info);
+ return err;
+ }
+#else
+ pfile_in_zip_read_info->raw=1;
+#endif
+ }
+ else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw))
+ {
+ pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
+ pfile_in_zip_read_info->stream.zfree = (free_func)0;
+ pfile_in_zip_read_info->stream.opaque = (voidpf)0;
+ pfile_in_zip_read_info->stream.next_in = 0;
+ pfile_in_zip_read_info->stream.avail_in = 0;
+
+ err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
+ if (err == Z_OK)
+ pfile_in_zip_read_info->stream_initialised=Z_DEFLATED;
+ else
+ {
+ TRYFREE(pfile_in_zip_read_info);
+ return err;
+ }
+ /* windowBits is passed < 0 to tell that there is no zlib header.
+ * Note that in this case inflate *requires* an extra "dummy" byte
+ * after the compressed stream in order to complete decompression and
+ * return Z_STREAM_END.
+ * In unzip, i don't wait absolutely Z_STREAM_END because I known the
+ * size of both compressed and uncompressed data
+ */
+ }
+ pfile_in_zip_read_info->rest_read_compressed =
+ s->cur_file_info.compressed_size ;
+ pfile_in_zip_read_info->rest_read_uncompressed =
+ s->cur_file_info.uncompressed_size ;
+
+
+ pfile_in_zip_read_info->pos_in_zipfile =
+ s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +
+ iSizeVar;
+
+ pfile_in_zip_read_info->stream.avail_in = (uInt)0;
+ pfile_in_zip_read_info->extra_size = iSizeVar;
+
+ s->pfile_in_zip_read = pfile_in_zip_read_info;
+ s->encrypted = 0;
+
+# ifndef NOUNCRYPT
+ if (password != NULL)
+ {
+ int i;
+ s->pcrc_32_tab = get_crc_table();
+ init_keys(password,s->keys,s->pcrc_32_tab);
+ if (ZSEEK64(s->z_filefunc, s->filestream,
+ s->pfile_in_zip_read->pos_in_zipfile +
+ s->pfile_in_zip_read->byte_before_the_zipfile,
+ SEEK_SET)!=0)
+ return UNZ_INTERNALERROR;
+ if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12)
+ return UNZ_INTERNALERROR;
+
+ for (i = 0; i<12; i++)
+ zdecode(s->keys,s->pcrc_32_tab,source[i]);
+
+ s->pfile_in_zip_read->pos_in_zipfile+=12;
+ s->encrypted=1;
+ }
+# endif
+
+
+ return UNZ_OK;
+}
+
+extern int ZEXPORT unzSeekCurrentFile(unzFile file, int pos) {
+
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+ if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) { // don't know how to support bzip
+ return UNZ_INTERNALERROR;
+ };
+
+ if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) {
+
+ pfile_in_zip_read_info->rest_read_compressed =
+ s->cur_file_info.compressed_size - pos;
+ pfile_in_zip_read_info->rest_read_uncompressed =
+ s->cur_file_info.uncompressed_size - pos;
+
+ pfile_in_zip_read_info->pos_in_zipfile =
+ s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +
+ pfile_in_zip_read_info->extra_size + pos;
+
+ pfile_in_zip_read_info->stream.avail_in = (uInt)0;
+ pfile_in_zip_read_info->stream.total_out = pos;
+
+ return ZSEEK64(pfile_in_zip_read_info->z_filefunc,
+ pfile_in_zip_read_info->filestream,
+ pfile_in_zip_read_info->byte_before_the_zipfile + pfile_in_zip_read_info->pos_in_zipfile,
+ ZLIB_FILEFUNC_SEEK_SET);
+
+ } else { // gzip
+
+ if (pos < pfile_in_zip_read_info->stream.total_out) { // negative seek, rewind
+
+ pfile_in_zip_read_info->rest_read_compressed =
+ s->cur_file_info.compressed_size ;
+ pfile_in_zip_read_info->rest_read_uncompressed =
+ s->cur_file_info.uncompressed_size ;
+
+ pfile_in_zip_read_info->pos_in_zipfile =
+ s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +
+ pfile_in_zip_read_info->extra_size;
+
+ (void)inflateReset(&pfile_in_zip_read_info->stream);
+
+ pfile_in_zip_read_info->stream.avail_in = (uInt)0;
+ pfile_in_zip_read_info->stream.total_out = 0;
+ pfile_in_zip_read_info->stream.next_in = 0;
+ };
+
+ // not sure where to read, so read on the stack
+ {
+ char buf[512];
+ int to_read = pos - pfile_in_zip_read_info->stream.total_out;
+ while (to_read) {
+
+ int len = to_read > sizeof(buf)?sizeof(buf):to_read;
+ int read = unzReadCurrentFile(file, buf, len);
+ if (read < 0) {
+ return read;
+ };
+ to_read -= read;
+ if (read == UNZ_EOF) {
+ return pos;
+ };
+ };
+ };
+ };
+
+ return pos;
+};
+
+extern int ZEXPORT unzOpenCurrentFile (unzFile file)
+{
+ return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);
+}
+
+extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password)
+{
+ return unzOpenCurrentFile3(file, NULL, NULL, 0, password);
+}
+
+extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw)
+{
+ return unzOpenCurrentFile3(file, method, level, raw, NULL);
+}
+
+/** Addition for GDAL : START */
+
+extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file)
+{
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ s=(unz64_s*)file;
+ if (file==NULL)
+ return 0; //UNZ_PARAMERROR;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+ if (pfile_in_zip_read_info==NULL)
+ return 0; //UNZ_PARAMERROR;
+ return pfile_in_zip_read_info->pos_in_zipfile +
+ pfile_in_zip_read_info->byte_before_the_zipfile;
+}
+
+/** Addition for GDAL : END */
+
+/*
+ Read bytes from the current file.
+ buf contain buffer where data must be copied
+ len the size of buf.
+
+ return the number of byte copied if somes bytes are copied
+ return 0 if the end of file was reached
+ return <0 with error code if there is an error
+ (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+*/
+extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len)
+{
+ int err=UNZ_OK;
+ uInt iRead = 0;
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+
+ if ((pfile_in_zip_read_info->read_buffer == NULL))
+ return UNZ_END_OF_LIST_OF_FILE;
+ if (len==0)
+ return 0;
+
+ pfile_in_zip_read_info->stream.next_out = (Bytef*)buf;
+
+ pfile_in_zip_read_info->stream.avail_out = (uInt)len;
+
+ if ((len>pfile_in_zip_read_info->rest_read_uncompressed) &&
+ (!(pfile_in_zip_read_info->raw)))
+ pfile_in_zip_read_info->stream.avail_out =
+ (uInt)pfile_in_zip_read_info->rest_read_uncompressed;
+
+ if ((len>pfile_in_zip_read_info->rest_read_compressed+
+ pfile_in_zip_read_info->stream.avail_in) &&
+ (pfile_in_zip_read_info->raw))
+ pfile_in_zip_read_info->stream.avail_out =
+ (uInt)pfile_in_zip_read_info->rest_read_compressed+
+ pfile_in_zip_read_info->stream.avail_in;
+
+ while (pfile_in_zip_read_info->stream.avail_out>0)
+ {
+ if ((pfile_in_zip_read_info->stream.avail_in==0) &&
+ (pfile_in_zip_read_info->rest_read_compressed>0))
+ {
+ uInt uReadThis = UNZ_BUFSIZE;
+ if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
+ uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
+ if (uReadThis == 0)
+ return UNZ_EOF;
+ if (ZSEEK64(pfile_in_zip_read_info->z_filefunc,
+ pfile_in_zip_read_info->filestream,
+ pfile_in_zip_read_info->pos_in_zipfile +
+ pfile_in_zip_read_info->byte_before_the_zipfile,
+ ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return UNZ_ERRNO;
+ if (ZREAD64(pfile_in_zip_read_info->z_filefunc,
+ pfile_in_zip_read_info->filestream,
+ pfile_in_zip_read_info->read_buffer,
+ uReadThis)!=uReadThis)
+ return UNZ_ERRNO;
+
+
+# ifndef NOUNCRYPT
+ if(s->encrypted)
+ {
+ uInt i;
+ for(i=0;i<uReadThis;i++)
+ pfile_in_zip_read_info->read_buffer[i] =
+ zdecode(s->keys,s->pcrc_32_tab,
+ pfile_in_zip_read_info->read_buffer[i]);
+ }
+# endif
+
+
+ pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
+
+ pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
+
+ pfile_in_zip_read_info->stream.next_in =
+ (Bytef*)pfile_in_zip_read_info->read_buffer;
+ pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
+ }
+
+ if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw))
+ {
+ uInt uDoCopy,i ;
+
+ if ((pfile_in_zip_read_info->stream.avail_in == 0) &&
+ (pfile_in_zip_read_info->rest_read_compressed == 0))
+ return (iRead==0) ? UNZ_EOF : iRead;
+
+ if (pfile_in_zip_read_info->stream.avail_out <
+ pfile_in_zip_read_info->stream.avail_in)
+ uDoCopy = pfile_in_zip_read_info->stream.avail_out ;
+ else
+ uDoCopy = pfile_in_zip_read_info->stream.avail_in ;
+
+ for (i=0;i<uDoCopy;i++)
+ *(pfile_in_zip_read_info->stream.next_out+i) =
+ *(pfile_in_zip_read_info->stream.next_in+i);
+
+ pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy;
+
+ pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,
+ pfile_in_zip_read_info->stream.next_out,
+ uDoCopy);
+ pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
+ pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
+ pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
+ pfile_in_zip_read_info->stream.next_out += uDoCopy;
+ pfile_in_zip_read_info->stream.next_in += uDoCopy;
+ pfile_in_zip_read_info->stream.total_out += uDoCopy;
+ iRead += uDoCopy;
+ }
+ else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED)
+ {
+#ifdef HAVE_BZIP2
+ uLong uTotalOutBefore,uTotalOutAfter;
+ const Bytef *bufBefore;
+ uLong uOutThis;
+
+ pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in;
+ pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in;
+ pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in;
+ pfile_in_zip_read_info->bstream.total_in_hi32 = 0;
+ pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out;
+ pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out;
+ pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out;
+ pfile_in_zip_read_info->bstream.total_out_hi32 = 0;
+
+ uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32;
+ bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out;
+
+ err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream);
+
+ uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32;
+ uOutThis = uTotalOutAfter-uTotalOutBefore;
+
+ pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis;
+
+ pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis));
+ pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis;
+ iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
+
+ pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in;
+ pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in;
+ pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32;
+ pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out;
+ pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out;
+ pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32;
+
+ if (err==BZ_STREAM_END)
+ return (iRead==0) ? UNZ_EOF : iRead;
+ if (err!=BZ_OK)
+ break;
+#endif
+ } // end Z_BZIP2ED
+ else
+ {
+ ZPOS64_T uTotalOutBefore,uTotalOutAfter;
+ const Bytef *bufBefore;
+ ZPOS64_T uOutThis;
+ int flush=Z_SYNC_FLUSH;
+
+ uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
+ bufBefore = pfile_in_zip_read_info->stream.next_out;
+
+ /*
+ if ((pfile_in_zip_read_info->rest_read_uncompressed ==
+ pfile_in_zip_read_info->stream.avail_out) &&
+ (pfile_in_zip_read_info->rest_read_compressed == 0))
+ flush = Z_FINISH;
+ */
+ err=inflate(&pfile_in_zip_read_info->stream,flush);
+
+ if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL))
+ err = Z_DATA_ERROR;
+
+ uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
+ uOutThis = uTotalOutAfter-uTotalOutBefore;
+
+ pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis;
+
+ pfile_in_zip_read_info->crc32 =
+ crc32(pfile_in_zip_read_info->crc32,bufBefore,
+ (uInt)(uOutThis));
+
+ pfile_in_zip_read_info->rest_read_uncompressed -=
+ uOutThis;
+
+ iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
+
+ if (err==Z_STREAM_END)
+ return (iRead==0) ? UNZ_EOF : iRead;
+ if (err!=Z_OK)
+ break;
+ }
+ }
+
+ if (err==Z_OK)
+ return iRead;
+ return err;
+}
+
+
+/*
+ Give the current position in uncompressed data
+*/
+extern z_off_t ZEXPORT unztell (unzFile file)
+{
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+ return (z_off_t)pfile_in_zip_read_info->stream.total_out;
+}
+
+extern ZPOS64_T ZEXPORT unztell64 (unzFile file)
+{
+
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return (ZPOS64_T)-1;
+ s=(unz64_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return (ZPOS64_T)-1;
+
+ return pfile_in_zip_read_info->total_out_64;
+}
+
+
+/*
+ return 1 if the end of file was reached, 0 elsewhere
+*/
+extern int ZEXPORT unzeof (unzFile file)
+{
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+ if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
+ return 1;
+ else
+ return 0;
+}
+
+
+
+/*
+Read extra field from the current file (opened by unzOpenCurrentFile)
+This is the local-header version of the extra field (sometimes, there is
+more info in the local-header version than in the central-header)
+
+ if buf==NULL, it return the size of the local extra field that can be read
+
+ if buf!=NULL, len is the size of the buffer, the extra header is copied in
+ buf.
+ the return value is the number of bytes copied in buf, or (if <0)
+ the error code
+*/
+extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len)
+{
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ uInt read_now;
+ ZPOS64_T size_to_read;
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+ size_to_read = (pfile_in_zip_read_info->size_local_extrafield -
+ pfile_in_zip_read_info->pos_local_extrafield);
+
+ if (buf==NULL)
+ return (int)size_to_read;
+
+ if (len>size_to_read)
+ read_now = (uInt)size_to_read;
+ else
+ read_now = (uInt)len ;
+
+ if (read_now==0)
+ return 0;
+
+ if (ZSEEK64(pfile_in_zip_read_info->z_filefunc,
+ pfile_in_zip_read_info->filestream,
+ pfile_in_zip_read_info->offset_local_extrafield +
+ pfile_in_zip_read_info->pos_local_extrafield,
+ ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return UNZ_ERRNO;
+
+ if (ZREAD64(pfile_in_zip_read_info->z_filefunc,
+ pfile_in_zip_read_info->filestream,
+ buf,read_now)!=read_now)
+ return UNZ_ERRNO;
+
+ return (int)read_now;
+}
+
+/*
+ Close the file in zip opened with unzipOpenCurrentFile
+ Return UNZ_CRCERROR if all the file was read but the CRC is not good
+*/
+extern int ZEXPORT unzCloseCurrentFile (unzFile file)
+{
+ int err=UNZ_OK;
+
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+
+ if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) &&
+ (!pfile_in_zip_read_info->raw))
+ {
+ if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
+ err=UNZ_CRCERROR;
+ }
+
+
+ TRYFREE(pfile_in_zip_read_info->read_buffer);
+ pfile_in_zip_read_info->read_buffer = NULL;
+ if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED)
+ inflateEnd(&pfile_in_zip_read_info->stream);
+#ifdef HAVE_BZIP2
+ else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED)
+ BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream);
+#endif
+
+
+ pfile_in_zip_read_info->stream_initialised = 0;
+ TRYFREE(pfile_in_zip_read_info);
+
+ s->pfile_in_zip_read=NULL;
+
+ return err;
+}
+
+
+/*
+ Get the global comment string of the ZipFile, in the szComment buffer.
+ uSizeBuf is the size of the szComment buffer.
+ return the number of byte copied or an error code <0
+*/
+extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf)
+{
+ unz64_s* s;
+ uLong uReadThis ;
+ if (file==NULL)
+ return (int)UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+
+ uReadThis = uSizeBuf;
+ if (uReadThis>s->gi.size_comment)
+ uReadThis = s->gi.size_comment;
+
+ if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return UNZ_ERRNO;
+
+ if (uReadThis>0)
+ {
+ *szComment='\0';
+ if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis)
+ return UNZ_ERRNO;
+ }
+
+ if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))
+ *(szComment+s->gi.size_comment)='\0';
+ return (int)uReadThis;
+}
+
+/* Additions by RX '2004 */
+extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file)
+{
+ unz64_s* s;
+
+ if (file==NULL)
+ return 0; //UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ if (!s->current_file_ok)
+ return 0;
+ if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff)
+ if (s->num_file==s->gi.number_entry)
+ return 0;
+ return s->pos_in_central_dir;
+}
+
+extern uLong ZEXPORT unzGetOffset (unzFile file)
+{
+ ZPOS64_T offset64;
+
+ if (file==NULL)
+ return 0; //UNZ_PARAMERROR;
+ offset64 = unzGetOffset64(file);
+ return (uLong)offset64;
+}
+
+extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos)
+{
+ unz64_s* s;
+ int err;
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+
+ s->pos_in_central_dir = pos;
+ s->num_file = s->gi.number_entry; /* hack */
+ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+ &s->cur_file_info_internal,
+ NULL,0,NULL,0,NULL,0);
+ s->current_file_ok = (err == UNZ_OK);
+ return err;
+}
+
+extern int ZEXPORT unzSetOffset (unzFile file, uLong pos)
+{
+ return unzSetOffset64(file,pos);
+}
diff --git a/core/io/unzip.h b/core/io/unzip.h
new file mode 100644
index 0000000000..fe7ad1ddf5
--- /dev/null
+++ b/core/io/unzip.h
@@ -0,0 +1,445 @@
+/* unzip.h -- IO for uncompress .zip files using zlib
+ Version 1.1, February 14h, 2010
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications of Unzip for Zip64
+ Copyright (C) 2007-2008 Even Rouault
+
+ Modifications for Zip64 support on both zip and unzip
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+ ---------------------------------------------------------------------------------
+
+ Condition of use and distribution are the same than zlib :
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ ---------------------------------------------------------------------------------
+
+ Changes
+
+ See header of unzip64.c
+
+*/
+
+#ifndef _unz64_H
+#define _unz64_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#ifndef _ZLIBIOAPI_H
+#include "ioapi.h"
+#endif
+
+#ifdef HAVE_BZIP2
+#include "bzlib.h"
+#endif
+
+#define Z_BZIP2ED 12
+
+#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+ from (void*) without cast */
+typedef struct TagunzFile__ { int unused; } unzFile__;
+typedef unzFile__ *unzFile;
+#else
+typedef voidp unzFile;
+#endif
+
+
+#define UNZ_OK (0)
+#define UNZ_END_OF_LIST_OF_FILE (-100)
+#define UNZ_ERRNO (Z_ERRNO)
+#define UNZ_EOF (0)
+#define UNZ_PARAMERROR (-102)
+#define UNZ_BADZIPFILE (-103)
+#define UNZ_INTERNALERROR (-104)
+#define UNZ_CRCERROR (-105)
+
+/* tm_unz contain date/time info */
+typedef struct tm_unz_s
+{
+ uInt tm_sec; /* seconds after the minute - [0,59] */
+ uInt tm_min; /* minutes after the hour - [0,59] */
+ uInt tm_hour; /* hours since midnight - [0,23] */
+ uInt tm_mday; /* day of the month - [1,31] */
+ uInt tm_mon; /* months since January - [0,11] */
+ uInt tm_year; /* years - [1980..2044] */
+} tm_unz;
+
+/* unz_global_info structure contain global data about the ZIPfile
+ These data comes from the end of central dir */
+typedef struct unz_global_info64_s
+{
+ ZPOS64_T number_entry; /* total number of entries in
+ the central dir on this disk */
+ uLong size_comment; /* size of the global comment of the zipfile */
+} unz_global_info64;
+
+typedef struct unz_global_info_s
+{
+ uLong number_entry; /* total number of entries in
+ the central dir on this disk */
+ uLong size_comment; /* size of the global comment of the zipfile */
+} unz_global_info;
+
+/* unz_file_info contain information about a file in the zipfile */
+typedef struct unz_file_info64_s
+{
+ uLong version; /* version made by 2 bytes */
+ uLong version_needed; /* version needed to extract 2 bytes */
+ uLong flag; /* general purpose bit flag 2 bytes */
+ uLong compression_method; /* compression method 2 bytes */
+ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
+ uLong crc; /* crc-32 4 bytes */
+ ZPOS64_T compressed_size; /* compressed size 8 bytes */
+ ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */
+ uLong size_filename; /* filename length 2 bytes */
+ uLong size_file_extra; /* extra field length 2 bytes */
+ uLong size_file_comment; /* file comment length 2 bytes */
+
+ uLong disk_num_start; /* disk number start 2 bytes */
+ uLong internal_fa; /* internal file attributes 2 bytes */
+ uLong external_fa; /* external file attributes 4 bytes */
+
+ tm_unz tmu_date;
+} unz_file_info64;
+
+typedef struct unz_file_info_s
+{
+ uLong version; /* version made by 2 bytes */
+ uLong version_needed; /* version needed to extract 2 bytes */
+ uLong flag; /* general purpose bit flag 2 bytes */
+ uLong compression_method; /* compression method 2 bytes */
+ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
+ uLong crc; /* crc-32 4 bytes */
+ uLong compressed_size; /* compressed size 4 bytes */
+ uLong uncompressed_size; /* uncompressed size 4 bytes */
+ uLong size_filename; /* filename length 2 bytes */
+ uLong size_file_extra; /* extra field length 2 bytes */
+ uLong size_file_comment; /* file comment length 2 bytes */
+
+ uLong disk_num_start; /* disk number start 2 bytes */
+ uLong internal_fa; /* internal file attributes 2 bytes */
+ uLong external_fa; /* external file attributes 4 bytes */
+
+ tm_unz tmu_date;
+} unz_file_info;
+
+extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
+ const char* fileName2,
+ int iCaseSensitivity));
+/*
+ Compare two filename (fileName1,fileName2).
+ If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
+ If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
+ or strcasecmp)
+ If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
+ (like 1 on Unix, 2 on Windows)
+*/
+
+
+extern unzFile ZEXPORT unzOpen OF((const char *path));
+extern unzFile ZEXPORT unzOpen64 OF((const void *path));
+/*
+ Open a Zip file. path contain the full pathname (by example,
+ on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer
+ "zlib/zlib113.zip".
+ If the zipfile cannot be opened (file don't exist or in not valid), the
+ return value is NULL.
+ Else, the return value is a unzFile Handle, usable with other function
+ of this unzip package.
+ the "64" function take a const void* pointer, because the path is just the
+ value passed to the open64_file_func callback.
+ Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path
+ is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char*
+ does not describe the reality
+*/
+
+
+extern unzFile ZEXPORT unzOpen2 OF((const char *path,
+ zlib_filefunc_def* pzlib_filefunc_def));
+/*
+ Open a Zip file, like unzOpen, but provide a set of file low level API
+ for read/write the zip file (see ioapi.h)
+*/
+
+extern unzFile ZEXPORT unzOpen2_64 OF((const void *path,
+ zlib_filefunc64_def* pzlib_filefunc_def));
+/*
+ Open a Zip file, like unz64Open, but provide a set of file low level API
+ for read/write the zip file (see ioapi.h)
+*/
+
+extern int ZEXPORT unzClose OF((unzFile file));
+/*
+ Close a ZipFile opened with unzipOpen.
+ If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
+ these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
+ return UNZ_OK if there is no problem. */
+
+extern void* unzGetOpaque(unzFile file);
+
+
+extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
+ unz_global_info *pglobal_info));
+
+extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file,
+ unz_global_info64 *pglobal_info));
+/*
+ Write info about the ZipFile in the *pglobal_info structure.
+ No preparation of the structure is needed
+ return UNZ_OK if there is no problem. */
+
+
+extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
+ char *szComment,
+ uLong uSizeBuf));
+/*
+ Get the global comment string of the ZipFile, in the szComment buffer.
+ uSizeBuf is the size of the szComment buffer.
+ return the number of byte copied or an error code <0
+*/
+
+
+/***************************************************************************/
+/* Unzip package allow you browse the directory of the zipfile */
+
+extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
+/*
+ Set the current file of the zipfile to the first file.
+ return UNZ_OK if there is no problem
+*/
+
+extern int ZEXPORT unzGoToNextFile OF((unzFile file));
+/*
+ Set the current file of the zipfile to the next file.
+ return UNZ_OK if there is no problem
+ return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+*/
+
+extern int ZEXPORT unzLocateFile OF((unzFile file,
+ const char *szFileName,
+ int iCaseSensitivity));
+/*
+ Try locate the file szFileName in the zipfile.
+ For the iCaseSensitivity signification, see unzStringFileNameCompare
+
+ return value :
+ UNZ_OK if the file is found. It becomes the current file.
+ UNZ_END_OF_LIST_OF_FILE if the file is not found
+*/
+
+
+/* ****************************************** */
+/* Ryan supplied functions */
+/* unz_file_info contain information about a file in the zipfile */
+typedef struct unz_file_pos_s
+{
+ uLong pos_in_zip_directory; /* offset in zip file directory */
+ uLong num_of_file; /* # of file */
+} unz_file_pos;
+
+extern int ZEXPORT unzGetFilePos(
+ unzFile file,
+ unz_file_pos* file_pos);
+
+extern int ZEXPORT unzGoToFilePos(
+ unzFile file,
+ unz_file_pos* file_pos);
+
+typedef struct unz64_file_pos_s
+{
+ ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */
+ ZPOS64_T num_of_file; /* # of file */
+} unz64_file_pos;
+
+extern int ZEXPORT unzGetFilePos64(
+ unzFile file,
+ unz64_file_pos* file_pos);
+
+extern int ZEXPORT unzGoToFilePos64(
+ unzFile file,
+ const unz64_file_pos* file_pos);
+
+/* ****************************************** */
+
+extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file,
+ unz_file_info64 *pfile_info,
+ char *szFileName,
+ uLong fileNameBufferSize,
+ void *extraField,
+ uLong extraFieldBufferSize,
+ char *szComment,
+ uLong commentBufferSize));
+
+extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
+ unz_file_info *pfile_info,
+ char *szFileName,
+ uLong fileNameBufferSize,
+ void *extraField,
+ uLong extraFieldBufferSize,
+ char *szComment,
+ uLong commentBufferSize));
+/*
+ Get Info about the current file
+ if pfile_info!=NULL, the *pfile_info structure will contain somes info about
+ the current file
+ if szFileName!=NULL, the filemane string will be copied in szFileName
+ (fileNameBufferSize is the size of the buffer)
+ if extraField!=NULL, the extra field information will be copied in extraField
+ (extraFieldBufferSize is the size of the buffer).
+ This is the Central-header version of the extra field
+ if szComment!=NULL, the comment string of the file will be copied in szComment
+ (commentBufferSize is the size of the buffer)
+*/
+
+
+/** Addition for GDAL : START */
+
+extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file));
+
+/** Addition for GDAL : END */
+
+
+/***************************************************************************/
+/* for reading the content of the current zipfile, you can open it, read data
+ from it, and close it (you can close it before reading all the file)
+ */
+
+extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
+/*
+ Open for reading data the current file in the zipfile.
+ If there is no error, the return value is UNZ_OK.
+*/
+
+extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file,
+ const char* password));
+/*
+ Open for reading data the current file in the zipfile.
+ password is a crypting password
+ If there is no error, the return value is UNZ_OK.
+*/
+
+extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file,
+ int* method,
+ int* level,
+ int raw));
+/*
+ Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
+ if raw==1
+ *method will receive method of compression, *level will receive level of
+ compression
+ note : you can set level parameter as NULL (if you did not want known level,
+ but you CANNOT set method parameter as NULL
+*/
+
+extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file,
+ int* method,
+ int* level,
+ int raw,
+ const char* password));
+/*
+ Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
+ if raw==1
+ *method will receive method of compression, *level will receive level of
+ compression
+ note : you can set level parameter as NULL (if you did not want known level,
+ but you CANNOT set method parameter as NULL
+*/
+
+
+extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
+/*
+ Close the file in zip opened with unzOpenCurrentFile
+ Return UNZ_CRCERROR if all the file was read but the CRC is not good
+*/
+
+extern int ZEXPORT unzReadCurrentFile OF((unzFile file,
+ voidp buf,
+ unsigned len));
+/*
+ Read bytes from the current file (opened by unzOpenCurrentFile)
+ buf contain buffer where data must be copied
+ len the size of buf.
+
+ return the number of byte copied if somes bytes are copied
+ return 0 if the end of file was reached
+ return <0 with error code if there is an error
+ (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+*/
+
+extern int ZEXPORT unzSeekCurrentFile(unzFile file, int pos);
+/*
+ Seek to position in uncompressed data
+*/
+
+extern z_off_t ZEXPORT unztell OF((unzFile file));
+
+extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file));
+/*
+ Give the current position in uncompressed data
+*/
+
+extern int ZEXPORT unzeof OF((unzFile file));
+/*
+ return 1 if the end of file was reached, 0 elsewhere
+*/
+
+extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
+ voidp buf,
+ unsigned len));
+/*
+ Read extra field from the current file (opened by unzOpenCurrentFile)
+ This is the local-header version of the extra field (sometimes, there is
+ more info in the local-header version than in the central-header)
+
+ if buf==NULL, it return the size of the local extra field
+
+ if buf!=NULL, len is the size of the buffer, the extra header is copied in
+ buf.
+ the return value is the number of bytes copied in buf, or (if <0)
+ the error code
+*/
+
+/***************************************************************************/
+
+/* Get the current file offset */
+extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file);
+extern uLong ZEXPORT unzGetOffset (unzFile file);
+
+/* Set the current file offset */
+extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos);
+extern int ZEXPORT unzSetOffset (unzFile file, uLong pos);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _unz64_H */
diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp
new file mode 100644
index 0000000000..150643b2e1
--- /dev/null
+++ b/core/io/xml_parser.cpp
@@ -0,0 +1,576 @@
+/*************************************************************************/
+/* xml_parser.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. */
+/*************************************************************************/
+#include "xml_parser.h"
+#include "print_string.h"
+//#define DEBUG_XML
+
+static bool _equalsn(const CharType* str1, const CharType* str2, int len) {
+ int i;
+ for(i=0; str1[i] && str2[i] && i < len; ++i)
+ if (str1[i] != str2[i])
+ return false;
+
+ // if one (or both) of the strings was smaller then they
+ // are only equal if they have the same lenght
+ return (i == len) || (str1[i] == 0 && str2[i] == 0);
+}
+
+
+String XMLParser::_replace_special_characters(const String& origstr) {
+
+ int pos = origstr.find("&");
+ int oldPos = 0;
+
+ if (pos == -1)
+ return origstr;
+
+ String newstr;
+
+ while(pos != -1 && pos < origstr.length()-2) {
+ // check if it is one of the special characters
+
+ int specialChar = -1;
+ for (int i=0; i<(int)special_characters.size(); ++i)
+ {
+ const CharType* p = &origstr[pos]+1;
+
+ if (_equalsn(&special_characters[i][1], p, special_characters[i].length()-1))
+ {
+ specialChar = i;
+ break;
+ }
+ }
+
+ if (specialChar != -1)
+ {
+ newstr+=(origstr.substr(oldPos, pos - oldPos));
+ newstr+=(special_characters[specialChar][0]);
+ pos += special_characters[specialChar].length();
+ }
+ else
+ {
+ newstr+=(origstr.substr(oldPos, pos - oldPos + 1));
+ pos += 1;
+ }
+
+ // find next &
+ oldPos = pos;
+ pos = origstr.find("&", pos);
+ }
+
+ if (oldPos < origstr.length()-1)
+ newstr+=(origstr.substr(oldPos, origstr.length()-oldPos));
+
+ return newstr;
+}
+
+
+static inline bool _is_white_space(char c)
+{
+ return (c==' ' || c=='\t' || c=='\n' || c=='\r');
+}
+
+
+//! sets the state that text was found. Returns true if set should be set
+bool XMLParser::_set_text(char* start, char* end) {
+ // check if text is more than 2 characters, and if not, check if there is
+ // only white space, so that this text won't be reported
+ if (end - start < 3)
+ {
+ char* p = start;
+ for(; p != end; ++p)
+ if (!_is_white_space(*p))
+ break;
+
+ if (p == end)
+ return false;
+ }
+
+ // set current text to the parsed text, and replace xml special characters
+ String s = String::utf8(start, (int)(end - start));
+ node_name = _replace_special_characters(s);
+
+ // current XML node type is text
+ node_type = NODE_TEXT;
+
+ return true;
+}
+
+void XMLParser::_parse_closing_xml_element() {
+ node_type = NODE_ELEMENT_END;
+ node_empty = false;
+ attributes.clear();
+
+ ++P;
+ const char* pBeginClose = P;
+
+ while(*P != '>')
+ ++P;
+
+ node_name = String::utf8(pBeginClose, (int)(P - pBeginClose));
+#ifdef DEBUG_XML
+ print_line("XML CLOSE: "+node_name);
+#endif
+ ++P;
+}
+
+void XMLParser::_ignore_definition() {
+ node_type = NODE_UNKNOWN;
+
+ char *F=P;
+ // move until end marked with '>' reached
+ while(*P != '>')
+ ++P;
+ node_name.parse_utf8(F,P-F);
+ ++P;
+}
+
+bool XMLParser::_parse_cdata() {
+
+ if (*(P+1) != '[')
+ return false;
+
+ node_type = NODE_CDATA;
+
+ // skip '<![CDATA['
+ int count=0;
+ while( *P && count<8 )
+ {
+ ++P;
+ ++count;
+ }
+
+ if (!*P)
+ return true;
+
+ char *cDataBegin = P;
+ char *cDataEnd = 0;
+
+ // find end of CDATA
+ while(*P && !cDataEnd) {
+ if (*P == '>' &&
+ (*(P-1) == ']') &&
+ (*(P-2) == ']'))
+ {
+ cDataEnd = P - 2;
+ }
+
+ ++P;
+ }
+
+ if ( cDataEnd )
+ node_name = String::utf8(cDataBegin, (int)(cDataEnd - cDataBegin));
+ else
+ node_name = "";
+#ifdef DEBUG_XML
+ print_line("XML CDATA: "+node_name);
+#endif
+
+ return true;
+}
+
+void XMLParser::_parse_comment() {
+
+ node_type = NODE_COMMENT;
+ P += 1;
+
+ char *pCommentBegin = P;
+
+ int count = 1;
+
+ // move until end of comment reached
+ while(count)
+ {
+ if (*P == '>')
+ --count;
+ else
+ if (*P == '<')
+ ++count;
+
+ ++P;
+ }
+
+ P -= 3;
+ node_name = String::utf8(pCommentBegin+2, (int)(P - pCommentBegin-2));
+ P += 3;
+#ifdef DEBUG_XML
+ print_line("XML COMMENT: "+node_name);
+#endif
+
+}
+
+void XMLParser::_parse_opening_xml_element() {
+
+ node_type = NODE_ELEMENT;
+ node_empty = false;
+ attributes.clear();
+
+ // find name
+ const char* startName = P;
+
+ // find end of element
+ while(*P != '>' && !_is_white_space(*P))
+ ++P;
+
+ const char* endName = P;
+
+ // find attributes
+ while(*P != '>')
+ {
+ if (_is_white_space(*P))
+ ++P;
+ else
+ {
+ if (*P != '/')
+ {
+ // we've got an attribute
+
+ // read the attribute names
+ const char* attributeNameBegin = P;
+
+ while(!_is_white_space(*P) && *P != '=')
+ ++P;
+
+ const char* attributeNameEnd = P;
+ ++P;
+
+ // read the attribute value
+ // check for quotes and single quotes, thx to murphy
+ while( (*P != '\"') && (*P != '\'') && *P)
+ ++P;
+
+ if (!*P) // malformatted xml file
+ return;
+
+ const char attributeQuoteChar = *P;
+
+ ++P;
+ const char* attributeValueBegin = P;
+
+ while(*P != attributeQuoteChar && *P)
+ ++P;
+
+ if (!*P) // malformatted xml file
+ return;
+
+ const char* attributeValueEnd = P;
+ ++P;
+
+ Attribute attr;
+ attr.name = String::utf8(attributeNameBegin,
+ (int)(attributeNameEnd - attributeNameBegin));
+
+ String s =String::utf8(attributeValueBegin,
+ (int)(attributeValueEnd - attributeValueBegin));
+
+ attr.value = _replace_special_characters(s);
+ attributes.push_back(attr);
+ }
+ else
+ {
+ // tag is closed directly
+ ++P;
+ node_empty = true;
+ break;
+ }
+ }
+ }
+
+ // check if this tag is closing directly
+ if (endName > startName && *(endName-1) == '/')
+ {
+ // directly closing tag
+ node_empty = true;
+ endName--;
+ }
+
+ node_name = String::utf8(startName, (int)(endName - startName));
+#ifdef DEBUG_XML
+ print_line("XML OPEN: "+node_name);
+#endif
+
+ ++P;
+}
+
+
+void XMLParser::_parse_current_node() {
+
+ char* start = P;
+ node_offset = P - data;
+
+ // more forward until '<' found
+ while(*P != '<' && *P)
+ ++P;
+
+ if (!*P)
+ return;
+
+ if (P - start > 0)
+ {
+ // we found some text, store it
+ if (_set_text(start, P))
+ return;
+ }
+
+ ++P;
+
+ // based on current token, parse and report next element
+ switch(*P)
+ {
+ case '/':
+ _parse_closing_xml_element();
+ break;
+ case '?':
+ _ignore_definition();
+ break;
+ case '!':
+ if (!_parse_cdata())
+ _parse_comment();
+ break;
+ default:
+ _parse_opening_xml_element();
+ break;
+ }
+}
+
+
+uint64_t XMLParser::get_node_offset() const {
+
+ return node_offset;
+};
+
+Error XMLParser::seek(uint64_t p_pos) {
+
+ ERR_FAIL_COND_V(!data, ERR_FILE_EOF)
+ ERR_FAIL_COND_V(p_pos >= length, ERR_FILE_EOF);
+
+ P = data + p_pos;
+
+ return read();
+};
+
+void XMLParser::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("read"),&XMLParser::read);
+ ObjectTypeDB::bind_method(_MD("get_node_type"),&XMLParser::get_node_type);
+ ObjectTypeDB::bind_method(_MD("get_node_name"),&XMLParser::get_node_name);
+ ObjectTypeDB::bind_method(_MD("get_node_data"),&XMLParser::get_node_data);
+ ObjectTypeDB::bind_method(_MD("get_node_offset"),&XMLParser::get_node_offset);
+ ObjectTypeDB::bind_method(_MD("get_attribute_count"),&XMLParser::get_attribute_count);
+ ObjectTypeDB::bind_method(_MD("get_attribute_name"),&XMLParser::get_attribute_name);
+ ObjectTypeDB::bind_method(_MD("get_attribute_value"),(String (XMLParser::*)(int) const) &XMLParser::get_attribute_value);
+ ObjectTypeDB::bind_method(_MD("has_attribute"),&XMLParser::has_attribute);
+ ObjectTypeDB::bind_method(_MD("get_named_attribute_value"), (String (XMLParser::*)(const String&) const) &XMLParser::get_attribute_value);
+ ObjectTypeDB::bind_method(_MD("get_named_attribute_value_safe"), &XMLParser::get_attribute_value_safe);
+ ObjectTypeDB::bind_method(_MD("is_empty"),&XMLParser::is_empty);
+ ObjectTypeDB::bind_method(_MD("get_current_line"),&XMLParser::get_current_line);
+ ObjectTypeDB::bind_method(_MD("skip_section"),&XMLParser::skip_section);
+ ObjectTypeDB::bind_method(_MD("seek"),&XMLParser::seek);
+ ObjectTypeDB::bind_method(_MD("open"),&XMLParser::open);
+
+ BIND_CONSTANT( NODE_NONE );
+ BIND_CONSTANT( NODE_ELEMENT );
+ BIND_CONSTANT( NODE_ELEMENT_END );
+ BIND_CONSTANT( NODE_TEXT );
+ BIND_CONSTANT( NODE_COMMENT );
+ BIND_CONSTANT( NODE_CDATA );
+ BIND_CONSTANT( NODE_UNKNOWN );
+
+};
+
+
+
+Error XMLParser::read() {
+
+ // if not end reached, parse the node
+ if (P && (P - data) < length - 1 && *P != 0)
+ {
+ _parse_current_node();
+ return OK;
+ }
+
+ return ERR_FILE_EOF;
+}
+
+XMLParser::NodeType XMLParser::get_node_type() {
+
+ return node_type;
+}
+String XMLParser::get_node_data() const {
+
+ ERR_FAIL_COND_V( node_type != NODE_TEXT, "");
+ return node_name;
+}
+
+String XMLParser::get_node_name() const {
+ ERR_FAIL_COND_V( node_type == NODE_TEXT, "");
+ return node_name;
+}
+int XMLParser::get_attribute_count() const {
+
+ return attributes.size();
+}
+String XMLParser::get_attribute_name(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx,attributes.size(),"");
+ return attributes[p_idx].name;
+}
+String XMLParser::get_attribute_value(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx,attributes.size(),"");
+ return attributes[p_idx].value;
+}
+bool XMLParser::has_attribute(const String& p_name) const {
+
+ for(int i=0;i<attributes.size();i++) {
+ if (attributes[i].name==p_name)
+ return true;
+ }
+
+ return false;
+}
+String XMLParser::get_attribute_value(const String& p_name) const {
+
+ int idx=-1;
+ for(int i=0;i<attributes.size();i++) {
+ if (attributes[i].name==p_name) {
+ idx=i;
+ break;
+ }
+ }
+
+ if (idx<0) {
+ ERR_EXPLAIN("Attribute not found: "+p_name);
+ }
+ ERR_FAIL_COND_V(idx<0,"");
+ return attributes[idx].value;
+
+}
+
+String XMLParser::get_attribute_value_safe(const String& p_name) const {
+
+ int idx=-1;
+ for(int i=0;i<attributes.size();i++) {
+ if (attributes[i].name==p_name) {
+ idx=i;
+ break;
+ }
+ }
+
+ if (idx<0)
+ return "";
+ return attributes[idx].value;
+
+}
+bool XMLParser::is_empty() const {
+
+ return node_empty;
+}
+
+Error XMLParser::open(const String& p_path) {
+
+ Error err;
+ FileAccess * file = FileAccess::open(p_path,FileAccess::READ,&err);
+
+ if (err) {
+ ERR_FAIL_COND_V(err!=OK,err);
+ }
+
+ length = file->get_len();
+ ERR_FAIL_COND_V(length<1, ERR_FILE_CORRUPT);
+
+ data = memnew_arr( char, length+1);
+ file->get_buffer((uint8_t*)data,length);
+ data[length]=0;
+ P=data;
+
+ memdelete(file);
+
+ return OK;
+
+}
+
+void XMLParser::skip_section() {
+
+ // skip if this element is empty anyway.
+ if (is_empty())
+ return;
+
+ // read until we've reached the last element in this section
+ int tagcount = 1;
+
+ while(tagcount && read()==OK)
+ {
+ if (get_node_type() == XMLParser::NODE_ELEMENT &&
+ !is_empty())
+ {
+ ++tagcount;
+ }
+ else
+ if (get_node_type() == XMLParser::NODE_ELEMENT_END)
+ --tagcount;
+ }
+
+}
+
+void XMLParser::close() {
+
+ if (data)
+ memdelete_arr(data);
+ data=NULL;
+ length=0;
+ P=NULL;
+ node_empty=false;
+ node_type=NODE_NONE;
+ node_offset = 0;
+}
+
+int XMLParser::get_current_line() const {
+
+ return 0;
+}
+
+XMLParser::XMLParser() {
+
+ data=NULL;
+ close();
+ special_characters.push_back("&amp;");
+ special_characters.push_back("<lt;");
+ special_characters.push_back(">gt;");
+ special_characters.push_back("\"quot;");
+ special_characters.push_back("'apos;");
+
+
+}
+XMLParser::~XMLParser() {
+
+
+ if (data)
+ memdelete_arr(data);
+}
diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h
new file mode 100644
index 0000000000..3025c041b3
--- /dev/null
+++ b/core/io/xml_parser.h
@@ -0,0 +1,123 @@
+/*************************************************************************/
+/* xml_parser.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef XML_PARSER_H
+#define XML_PARSER_H
+
+#include "ustring.h"
+#include "vector.h"
+#include "os/file_access.h"
+#include "reference.h"
+
+/*
+ Based on irrXML (see their zlib license). Added mainly for compatibility with their Collada loader.
+*/
+
+class XMLParser : public Reference {
+
+ OBJ_TYPE( XMLParser, Reference );
+public:
+ //! Enumeration of all supported source text file formats
+ enum SourceFormat {
+ SOURCE_ASCII,
+ SOURCE_UTF8,
+ SOURCE_UTF16_BE,
+ SOURCE_UTF16_LE,
+ SOURCE_UTF32_BE,
+ SOURCE_UTF32_LE
+ };
+
+ enum NodeType {
+ NODE_NONE,
+ NODE_ELEMENT,
+ NODE_ELEMENT_END,
+ NODE_TEXT,
+ NODE_COMMENT,
+ NODE_CDATA,
+ NODE_UNKNOWN
+ };
+
+private:
+
+ char *data;
+ char *P;
+ int length;
+ void unescape(String& p_str);
+ Vector<String> special_characters;
+ String node_name;
+ bool node_empty;
+ NodeType node_type;
+ uint64_t node_offset;
+
+ struct Attribute {
+ String name;
+ String value;
+ };
+
+ Vector<Attribute> attributes;
+
+ String _replace_special_characters(const String& origstr);
+ bool _set_text(char* start, char* end);
+ void _parse_closing_xml_element();
+ void _ignore_definition();
+ bool _parse_cdata();
+ void _parse_comment();
+ void _parse_opening_xml_element();
+ void _parse_current_node();
+
+ static void _bind_methods();
+
+public:
+
+
+ Error read();
+ NodeType get_node_type();
+ String get_node_name() const;
+ String get_node_data() const;
+ uint64_t get_node_offset() const;
+ int get_attribute_count() const;
+ String get_attribute_name(int p_idx) const;
+ String get_attribute_value(int p_idx) const;
+ bool has_attribute(const String& p_name) const;
+ String get_attribute_value(const String& p_name) const;
+ String get_attribute_value_safe(const String& p_name) const; // do not print error if doesn't exist
+ bool is_empty() const;
+ int get_current_line() const;
+
+ void skip_section();
+ Error seek(uint64_t p_pos);
+
+ Error open(const String& p_path);
+ void close();
+
+ XMLParser();
+ ~XMLParser();
+};
+
+#endif
+
diff --git a/core/io/zip.c b/core/io/zip.c
new file mode 100644
index 0000000000..edf5560ddb
--- /dev/null
+++ b/core/io/zip.c
@@ -0,0 +1,2004 @@
+/* zip.c -- IO on .zip files using zlib
+ Version 1.1, February 14h, 2010
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+ Changes
+ Oct-2009 - Mathias Svensson - Remove old C style function prototypes
+ Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives
+ Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions.
+ Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data
+ It is used when recreting zip archive with RAW when deleting items from a zip.
+ ZIP64 data is automaticly added to items that needs it, and existing ZIP64 data need to be removed.
+ Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required)
+ Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer
+
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "zlib.h"
+#include "zip.h"
+
+#ifdef STDC
+# include <stddef.h>
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+ extern int errno;
+#else
+# include <errno.h>
+#endif
+
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+#ifndef VERSIONMADEBY
+# define VERSIONMADEBY (0x0) /* platform depedent */
+#endif
+
+#ifndef Z_BUFSIZE
+#define Z_BUFSIZE (64*1024) //(16384)
+#endif
+
+#ifndef Z_MAXFILENAMEINZIP
+#define Z_MAXFILENAMEINZIP (256)
+#endif
+
+#ifndef ALLOC
+# define ALLOC(size) (malloc(size))
+#endif
+#ifndef TRYFREE
+# define TRYFREE(p) {if (p) free(p);}
+#endif
+
+/*
+#define SIZECENTRALDIRITEM (0x2e)
+#define SIZEZIPLOCALHEADER (0x1e)
+*/
+
+/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
+
+
+// NOT sure that this work on ALL platform
+#define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32))
+
+#ifndef SEEK_CUR
+#define SEEK_CUR 1
+#endif
+
+#ifndef SEEK_END
+#define SEEK_END 2
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+#ifndef DEF_MEM_LEVEL
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+#endif
+const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
+
+
+#define SIZEDATA_INDATABLOCK (4096-(4*4))
+
+#define LOCALHEADERMAGIC (0x04034b50)
+#define CENTRALHEADERMAGIC (0x02014b50)
+#define ENDHEADERMAGIC (0x06054b50)
+#define ZIP64ENDHEADERMAGIC (0x6064b50)
+#define ZIP64ENDLOCHEADERMAGIC (0x7064b50)
+
+#define FLAG_LOCALHEADER_OFFSET (0x06)
+#define CRC_LOCALHEADER_OFFSET (0x0e)
+
+#define SIZECENTRALHEADER (0x2e) /* 46 */
+
+typedef struct linkedlist_datablock_internal_s
+{
+ struct linkedlist_datablock_internal_s* next_datablock;
+ uLong avail_in_this_block;
+ uLong filled_in_this_block;
+ uLong unused; /* for future use and alignement */
+ unsigned char data[SIZEDATA_INDATABLOCK];
+} linkedlist_datablock_internal;
+
+typedef struct linkedlist_data_s
+{
+ linkedlist_datablock_internal* first_block;
+ linkedlist_datablock_internal* last_block;
+} linkedlist_data;
+
+
+typedef struct
+{
+ z_stream stream; /* zLib stream structure for inflate */
+#ifdef HAVE_BZIP2
+ bz_stream bstream; /* bzLib stream structure for bziped */
+#endif
+
+ int stream_initialised; /* 1 is stream is initialised */
+ uInt pos_in_buffered_data; /* last written byte in buffered_data */
+
+ ZPOS64_T pos_local_header; /* offset of the local header of the file
+ currenty writing */
+ char* central_header; /* central header data for the current file */
+ uLong size_centralExtra;
+ uLong size_centralheader; /* size of the central header for cur file */
+ uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */
+ uLong flag; /* flag of the file currently writing */
+
+ int method; /* compression method of file currenty wr.*/
+ int raw; /* 1 for directly writing raw data */
+ Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/
+ uLong dosDate;
+ uLong crc32;
+ int encrypt;
+ int zip64; /* Add ZIP64 extened information in the extra field */
+ ZPOS64_T pos_zip64extrainfo;
+ ZPOS64_T totalCompressedData;
+ ZPOS64_T totalUncompressedData;
+#ifndef NOCRYPT
+ unsigned long keys[3]; /* keys defining the pseudo-random sequence */
+ const unsigned long* pcrc_32_tab;
+ int crypt_header_size;
+#endif
+} curfile64_info;
+
+typedef struct
+{
+ zlib_filefunc64_32_def z_filefunc;
+ voidpf filestream; /* io structore of the zipfile */
+ linkedlist_data central_dir;/* datablock with central dir in construction*/
+ int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/
+ curfile64_info ci; /* info on the file curretly writing */
+
+ ZPOS64_T begin_pos; /* position of the beginning of the zipfile */
+ ZPOS64_T add_position_when_writting_offset;
+ ZPOS64_T number_entry;
+
+#ifndef NO_ADDFILEINEXISTINGZIP
+ char *globalcomment;
+#endif
+
+} zip64_internal;
+
+
+#ifndef NOCRYPT
+#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED
+#include "crypt.h"
+#endif
+
+local linkedlist_datablock_internal* allocate_new_datablock()
+{
+ linkedlist_datablock_internal* ldi;
+ ldi = (linkedlist_datablock_internal*)
+ ALLOC(sizeof(linkedlist_datablock_internal));
+ if (ldi!=NULL)
+ {
+ ldi->next_datablock = NULL ;
+ ldi->filled_in_this_block = 0 ;
+ ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ;
+ }
+ return ldi;
+}
+
+local void free_datablock(linkedlist_datablock_internal* ldi)
+{
+ while (ldi!=NULL)
+ {
+ linkedlist_datablock_internal* ldinext = ldi->next_datablock;
+ TRYFREE(ldi);
+ ldi = ldinext;
+ }
+}
+
+local void init_linkedlist(linkedlist_data* ll)
+{
+ ll->first_block = ll->last_block = NULL;
+}
+
+local void free_linkedlist(linkedlist_data* ll)
+{
+ free_datablock(ll->first_block);
+ ll->first_block = ll->last_block = NULL;
+}
+
+
+local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len)
+{
+ linkedlist_datablock_internal* ldi;
+ const unsigned char* from_copy;
+
+ if (ll==NULL)
+ return ZIP_INTERNALERROR;
+
+ if (ll->last_block == NULL)
+ {
+ ll->first_block = ll->last_block = allocate_new_datablock();
+ if (ll->first_block == NULL)
+ return ZIP_INTERNALERROR;
+ }
+
+ ldi = ll->last_block;
+ from_copy = (unsigned char*)buf;
+
+ while (len>0)
+ {
+ uInt copy_this;
+ uInt i;
+ unsigned char* to_copy;
+
+ if (ldi->avail_in_this_block==0)
+ {
+ ldi->next_datablock = allocate_new_datablock();
+ if (ldi->next_datablock == NULL)
+ return ZIP_INTERNALERROR;
+ ldi = ldi->next_datablock ;
+ ll->last_block = ldi;
+ }
+
+ if (ldi->avail_in_this_block < len)
+ copy_this = (uInt)ldi->avail_in_this_block;
+ else
+ copy_this = (uInt)len;
+
+ to_copy = &(ldi->data[ldi->filled_in_this_block]);
+
+ for (i=0;i<copy_this;i++)
+ *(to_copy+i)=*(from_copy+i);
+
+ ldi->filled_in_this_block += copy_this;
+ ldi->avail_in_this_block -= copy_this;
+ from_copy += copy_this ;
+ len -= copy_this;
+ }
+ return ZIP_OK;
+}
+
+
+
+/****************************************************************************/
+
+#ifndef NO_ADDFILEINEXISTINGZIP
+/* ===========================================================================
+ Inputs a long in LSB order to the given file
+ nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T)
+*/
+
+local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte));
+local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)
+{
+ unsigned char buf[8];
+ int n;
+ for (n = 0; n < nbByte; n++)
+ {
+ buf[n] = (unsigned char)(x & 0xff);
+ x >>= 8;
+ }
+ if (x != 0)
+ { /* data overflow - hack for ZIP64 (X Roche) */
+ for (n = 0; n < nbByte; n++)
+ {
+ buf[n] = 0xff;
+ }
+ }
+
+ if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte)
+ return ZIP_ERRNO;
+ else
+ return ZIP_OK;
+}
+
+local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte));
+local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte)
+{
+ unsigned char* buf=(unsigned char*)dest;
+ int n;
+ for (n = 0; n < nbByte; n++) {
+ buf[n] = (unsigned char)(x & 0xff);
+ x >>= 8;
+ }
+
+ if (x != 0)
+ { /* data overflow - hack for ZIP64 */
+ for (n = 0; n < nbByte; n++)
+ {
+ buf[n] = 0xff;
+ }
+ }
+}
+
+/****************************************************************************/
+
+
+local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm)
+{
+ uLong year = (uLong)ptm->tm_year;
+ if (year>=1980)
+ year-=1980;
+ else if (year>=80)
+ year-=80;
+ return
+ (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) |
+ ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour));
+}
+
+
+/****************************************************************************/
+
+local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi));
+
+local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi)
+{
+ unsigned char c;
+ int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1);
+ if (err==1)
+ {
+ *pi = (int)c;
+ return ZIP_OK;
+ }
+ else
+ {
+ if (ZERROR64(*pzlib_filefunc_def,filestream))
+ return ZIP_ERRNO;
+ else
+ return ZIP_EOF;
+ }
+}
+
+
+/* ===========================================================================
+ Reads a long in LSB order from the given gz_stream. Sets
+*/
+local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX));
+
+local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX)
+{
+ uLong x ;
+ int i = 0;
+ int err;
+
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (uLong)i;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<8;
+
+ if (err==ZIP_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX));
+
+local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX)
+{
+ uLong x ;
+ int i = 0;
+ int err;
+
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (uLong)i;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<8;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<16;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<24;
+
+ if (err==ZIP_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX));
+
+
+local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)
+{
+ ZPOS64_T x;
+ int i = 0;
+ int err;
+
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (ZPOS64_T)i;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<8;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<16;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<24;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<32;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<40;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<48;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<56;
+
+ if (err==ZIP_OK)
+ *pX = x;
+ else
+ *pX = 0;
+
+ return err;
+}
+
+#ifndef BUFREADCOMMENT
+#define BUFREADCOMMENT (0x400)
+#endif
+/*
+ Locate the Central directory of a zipfile (at the end, just before
+ the global comment)
+*/
+local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream));
+
+local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)
+{
+ unsigned char* buf;
+ ZPOS64_T uSizeFile;
+ ZPOS64_T uBackRead;
+ ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
+ ZPOS64_T uPosFound=0;
+
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+ return 0;
+
+
+ uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
+
+ if (uMaxBack>uSizeFile)
+ uMaxBack = uSizeFile;
+
+ buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+ if (buf==NULL)
+ return 0;
+
+ uBackRead = 4;
+ while (uBackRead<uMaxBack)
+ {
+ uLong uReadSize;
+ ZPOS64_T uReadPos ;
+ int i;
+ if (uBackRead+BUFREADCOMMENT>uMaxBack)
+ uBackRead = uMaxBack;
+ else
+ uBackRead+=BUFREADCOMMENT;
+ uReadPos = uSizeFile-uBackRead ;
+
+ uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
+ (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ break;
+
+ if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
+ break;
+
+ for (i=(int)uReadSize-3; (i--)>0;)
+ if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
+ ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
+ {
+ uPosFound = uReadPos+i;
+ break;
+ }
+
+ if (uPosFound!=0)
+ break;
+ }
+ TRYFREE(buf);
+ return uPosFound;
+}
+
+/*
+Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before
+the global comment)
+*/
+local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream));
+
+local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)
+{
+ unsigned char* buf;
+ ZPOS64_T uSizeFile;
+ ZPOS64_T uBackRead;
+ ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
+ ZPOS64_T uPosFound=0;
+ uLong uL;
+ ZPOS64_T relativeOffset;
+
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+ return 0;
+
+ uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
+
+ if (uMaxBack>uSizeFile)
+ uMaxBack = uSizeFile;
+
+ buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+ if (buf==NULL)
+ return 0;
+
+ uBackRead = 4;
+ while (uBackRead<uMaxBack)
+ {
+ uLong uReadSize;
+ ZPOS64_T uReadPos;
+ int i;
+ if (uBackRead+BUFREADCOMMENT>uMaxBack)
+ uBackRead = uMaxBack;
+ else
+ uBackRead+=BUFREADCOMMENT;
+ uReadPos = uSizeFile-uBackRead ;
+
+ uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
+ (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ break;
+
+ if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
+ break;
+
+ for (i=(int)uReadSize-3; (i--)>0;)
+ {
+ // Signature "0x07064b50" Zip64 end of central directory locater
+ if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07))
+ {
+ uPosFound = uReadPos+i;
+ break;
+ }
+ }
+
+ if (uPosFound!=0)
+ break;
+ }
+
+ TRYFREE(buf);
+ if (uPosFound == 0)
+ return 0;
+
+ /* Zip64 end of central directory locator */
+ if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return 0;
+
+ /* the signature, already checked */
+ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
+ return 0;
+
+ /* number of the disk with the start of the zip64 end of central directory */
+ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
+ return 0;
+ if (uL != 0)
+ return 0;
+
+ /* relative offset of the zip64 end of central directory record */
+ if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK)
+ return 0;
+
+ /* total number of disks */
+ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
+ return 0;
+ if (uL != 1)
+ return 0;
+
+ /* Goto Zip64 end of central directory record */
+ if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return 0;
+
+ /* the signature */
+ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
+ return 0;
+
+ if (uL != 0x06064b50) // signature of 'Zip64 end of central directory'
+ return 0;
+
+ return relativeOffset;
+}
+
+int LoadCentralDirectoryRecord(zip64_internal* pziinit)
+{
+ int err=ZIP_OK;
+ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+
+ ZPOS64_T size_central_dir; /* size of the central directory */
+ ZPOS64_T offset_central_dir; /* offset of start of central directory */
+ ZPOS64_T central_pos;
+ uLong uL;
+
+ uLong number_disk; /* number of the current dist, used for
+ spaning ZIP, unsupported, always 0*/
+ uLong number_disk_with_CD; /* number the the disk with central dir, used
+ for spaning ZIP, unsupported, always 0*/
+ ZPOS64_T number_entry;
+ ZPOS64_T number_entry_CD; /* total number of entries in
+ the central dir
+ (same than number_entry on nospan) */
+ uLong VersionMadeBy;
+ uLong VersionNeeded;
+ uLong size_comment;
+
+ int hasZIP64Record = 0;
+
+ // check first if we find a ZIP64 record
+ central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream);
+ if(central_pos > 0)
+ {
+ hasZIP64Record = 1;
+ }
+ else if(central_pos == 0)
+ {
+ central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream);
+ }
+
+/* disable to allow appending to empty ZIP archive
+ if (central_pos==0)
+ err=ZIP_ERRNO;
+*/
+
+ if(hasZIP64Record)
+ {
+ ZPOS64_T sizeEndOfCentralDirectory;
+ if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
+ err=ZIP_ERRNO;
+
+ /* the signature, already checked */
+ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* size of zip64 end of central directory record */
+ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* version made by */
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* version needed to extract */
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* number of this disk */
+ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* number of the disk with the start of the central directory */
+ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* total number of entries in the central directory on this disk */
+ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* total number of entries in the central directory */
+ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&number_entry_CD)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0))
+ err=ZIP_BADZIPFILE;
+
+ /* size of the central directory */
+ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* offset of start of central directory with respect to the
+ starting disk number */
+ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ // TODO..
+ // read the comment from the standard central header.
+ size_comment = 0;
+ }
+ else
+ {
+ // Read End of central Directory info
+ if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err=ZIP_ERRNO;
+
+ /* the signature, already checked */
+ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* number of this disk */
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* number of the disk with the start of the central directory */
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* total number of entries in the central dir on this disk */
+ number_entry = 0;
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)
+ err=ZIP_ERRNO;
+ else
+ number_entry = uL;
+
+ /* total number of entries in the central dir */
+ number_entry_CD = 0;
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)
+ err=ZIP_ERRNO;
+ else
+ number_entry_CD = uL;
+
+ if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0))
+ err=ZIP_BADZIPFILE;
+
+ /* size of the central directory */
+ size_central_dir = 0;
+ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)
+ err=ZIP_ERRNO;
+ else
+ size_central_dir = uL;
+
+ /* offset of start of central directory with respect to the starting disk number */
+ offset_central_dir = 0;
+ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)
+ err=ZIP_ERRNO;
+ else
+ offset_central_dir = uL;
+
+
+ /* zipfile global comment length */
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK)
+ err=ZIP_ERRNO;
+ }
+
+ if ((central_pos<offset_central_dir+size_central_dir) &&
+ (err==ZIP_OK))
+ err=ZIP_BADZIPFILE;
+
+ if (err!=ZIP_OK)
+ {
+ ZCLOSE64(pziinit->z_filefunc, pziinit->filestream);
+ return ZIP_ERRNO;
+ }
+
+ if (size_comment>0)
+ {
+ pziinit->globalcomment = (char*)ALLOC(size_comment+1);
+ if (pziinit->globalcomment)
+ {
+ size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment);
+ pziinit->globalcomment[size_comment]=0;
+ }
+ }
+
+ byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir);
+ pziinit->add_position_when_writting_offset = byte_before_the_zipfile;
+
+ {
+ ZPOS64_T size_central_dir_to_read = size_central_dir;
+ size_t buf_size = SIZEDATA_INDATABLOCK;
+ void* buf_read = (void*)ALLOC(buf_size);
+ if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0)
+ err=ZIP_ERRNO;
+
+ while ((size_central_dir_to_read>0) && (err==ZIP_OK))
+ {
+ ZPOS64_T read_this = SIZEDATA_INDATABLOCK;
+ if (read_this > size_central_dir_to_read)
+ read_this = size_central_dir_to_read;
+
+ if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,(uLong)read_this) != read_this)
+ err=ZIP_ERRNO;
+
+ if (err==ZIP_OK)
+ err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this);
+
+ size_central_dir_to_read-=read_this;
+ }
+ TRYFREE(buf_read);
+ }
+ pziinit->begin_pos = byte_before_the_zipfile;
+ pziinit->number_entry = number_entry_CD;
+
+ if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0)
+ err=ZIP_ERRNO;
+
+ return err;
+}
+
+
+#endif /* !NO_ADDFILEINEXISTINGZIP*/
+
+
+/************************************************************/
+extern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def)
+{
+ zip64_internal ziinit;
+ zip64_internal* zi;
+ int err=ZIP_OK;
+
+ ziinit.z_filefunc.zseek32_file = NULL;
+ ziinit.z_filefunc.ztell32_file = NULL;
+ if (pzlib_filefunc64_32_def==NULL) {
+// fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64);
+ } else
+ ziinit.z_filefunc = *pzlib_filefunc64_32_def;
+
+ ziinit.filestream = ZOPEN64(ziinit.z_filefunc,
+ pathname,
+ (append == APPEND_STATUS_CREATE) ?
+ (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) :
+ (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING));
+
+ if (ziinit.filestream == NULL)
+ return NULL;
+
+ if (append == APPEND_STATUS_CREATEAFTER)
+ ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END);
+
+ ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream);
+ ziinit.in_opened_file_inzip = 0;
+ ziinit.ci.stream_initialised = 0;
+ ziinit.number_entry = 0;
+ ziinit.add_position_when_writting_offset = 0;
+ init_linkedlist(&(ziinit.central_dir));
+
+
+
+ zi = (zip64_internal*)ALLOC(sizeof(zip64_internal));
+ if (zi==NULL)
+ {
+ ZCLOSE64(ziinit.z_filefunc,ziinit.filestream);
+ return NULL;
+ }
+
+ /* now we add file in a zipfile */
+# ifndef NO_ADDFILEINEXISTINGZIP
+ ziinit.globalcomment = NULL;
+ if (append == APPEND_STATUS_ADDINZIP)
+ {
+ // Read and Cache Central Directory Records
+ err = LoadCentralDirectoryRecord(&ziinit);
+ }
+
+ if (globalcomment)
+ {
+ *globalcomment = ziinit.globalcomment;
+ }
+# endif /* !NO_ADDFILEINEXISTINGZIP*/
+
+ if (err != ZIP_OK)
+ {
+# ifndef NO_ADDFILEINEXISTINGZIP
+ TRYFREE(ziinit.globalcomment);
+# endif /* !NO_ADDFILEINEXISTINGZIP*/
+ TRYFREE(zi);
+ return NULL;
+ }
+ else
+ {
+ *zi = ziinit;
+ return (zipFile)zi;
+ }
+}
+
+extern zipFile ZEXPORT zipOpen2 (const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def)
+{
+ if (pzlib_filefunc32_def != NULL)
+ {
+ zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+ fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def);
+ return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill);
+ }
+ else
+ return zipOpen3(pathname, append, globalcomment, NULL);
+}
+
+extern zipFile ZEXPORT zipOpen2_64 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def)
+{
+ if (pzlib_filefunc_def != NULL)
+ {
+ zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+ zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
+ zlib_filefunc64_32_def_fill.ztell32_file = NULL;
+ zlib_filefunc64_32_def_fill.zseek32_file = NULL;
+ return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill);
+ }
+ else
+ return zipOpen3(pathname, append, globalcomment, NULL);
+}
+
+
+
+extern zipFile ZEXPORT zipOpen (const char* pathname, int append)
+{
+ return zipOpen3((const void*)pathname,append,NULL,NULL);
+}
+
+extern zipFile ZEXPORT zipOpen64 (const void* pathname, int append)
+{
+ return zipOpen3(pathname,append,NULL,NULL);
+}
+
+int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local)
+{
+ /* write the local header */
+ int err;
+ uInt size_filename = (uInt)strlen(filename);
+ uInt size_extrafield = size_extrafield_local;
+
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4);
+
+ if (err==ZIP_OK)
+ {
+ if(zi->ci.zip64)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);/* version needed to extract */
+ else
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */
+ }
+
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2);
+
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2);
+
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4);
+
+ // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */
+ if (err==ZIP_OK)
+ {
+ if(zi->ci.zip64)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* compressed size, unknown */
+ else
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */
+ }
+ if (err==ZIP_OK)
+ {
+ if(zi->ci.zip64)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* uncompressed size, unknown */
+ else
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */
+ }
+
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2);
+
+ if(zi->ci.zip64)
+ {
+ size_extrafield += 20;
+ }
+
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield,2);
+
+ if ((err==ZIP_OK) && (size_filename > 0))
+ {
+ if (ZWRITE64(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename)
+ err = ZIP_ERRNO;
+ }
+
+ if ((err==ZIP_OK) && (size_extrafield_local > 0))
+ {
+ if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local)
+ err = ZIP_ERRNO;
+ }
+
+
+ if ((err==ZIP_OK) && (zi->ci.zip64))
+ {
+ // write the Zip64 extended info
+ short HeaderID = 1;
+ short DataSize = 16;
+ ZPOS64_T CompressedSize = 0;
+ ZPOS64_T UncompressedSize = 0;
+
+ // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file)
+ zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream);
+
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2);
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2);
+
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8);
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8);
+ }
+
+ return err;
+}
+
+/*
+ NOTE.
+ When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped
+ before calling this function it can be done with zipRemoveExtraInfoBlock
+
+ It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize
+ unnecessary allocations.
+ */
+extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void* extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int raw,
+ int windowBits,int memLevel, int strategy,
+ const char* password, uLong crcForCrypting,
+ uLong versionMadeBy, uLong flagBase, int zip64)
+{
+ zip64_internal* zi;
+ uInt size_filename;
+ uInt size_comment;
+ uInt i;
+ int err = ZIP_OK;
+
+# ifdef NOCRYPT
+ if (password != NULL)
+ return ZIP_PARAMERROR;
+# endif
+
+ if (file == NULL)
+ return ZIP_PARAMERROR;
+
+#ifdef HAVE_BZIP2
+ if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED))
+ return ZIP_PARAMERROR;
+#else
+ if ((method!=0) && (method!=Z_DEFLATED))
+ return ZIP_PARAMERROR;
+#endif
+
+ zi = (zip64_internal*)file;
+
+ if (zi->in_opened_file_inzip == 1)
+ {
+ err = zipCloseFileInZip (file);
+ if (err != ZIP_OK)
+ return err;
+ }
+
+ if (filename==NULL)
+ filename="-";
+
+ if (comment==NULL)
+ size_comment = 0;
+ else
+ size_comment = (uInt)strlen(comment);
+
+ size_filename = (uInt)strlen(filename);
+
+ if (zipfi == NULL)
+ zi->ci.dosDate = 0;
+ else
+ {
+ if (zipfi->dosDate != 0)
+ zi->ci.dosDate = zipfi->dosDate;
+ else
+ zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date);
+ }
+
+ zi->ci.flag = flagBase;
+ if ((level==8) || (level==9))
+ zi->ci.flag |= 2;
+ if ((level==2))
+ zi->ci.flag |= 4;
+ if ((level==1))
+ zi->ci.flag |= 6;
+ if (password != NULL)
+ zi->ci.flag |= 1;
+
+ zi->ci.crc32 = 0;
+ zi->ci.method = method;
+ zi->ci.encrypt = 0;
+ zi->ci.stream_initialised = 0;
+ zi->ci.pos_in_buffered_data = 0;
+ zi->ci.raw = raw;
+ zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream);
+
+ zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment;
+ zi->ci.size_centralExtraFree = 32; // Extra space we have reserved in case we need to add ZIP64 extra info data
+
+ zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree);
+
+ zi->ci.size_centralExtra = size_extrafield_global;
+ zip64local_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4);
+ /* version info */
+ zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4);
+ zip64local_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/
+ zip64local_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/
+ zip64local_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/
+ zip64local_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/
+
+ if (zipfi==NULL)
+ zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2);
+ else
+ zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2);
+
+ if (zipfi==NULL)
+ zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4);
+ else
+ zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4);
+
+ if(zi->ci.pos_local_header >= 0xffffffff)
+ zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4);
+ else
+ zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset,4);
+
+ for (i=0;i<size_filename;i++)
+ *(zi->ci.central_header+SIZECENTRALHEADER+i) = *(filename+i);
+
+ for (i=0;i<size_extrafield_global;i++)
+ *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+i) =
+ *(((const char*)extrafield_global)+i);
+
+ for (i=0;i<size_comment;i++)
+ *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+
+ size_extrafield_global+i) = *(comment+i);
+ if (zi->ci.central_header == NULL)
+ return ZIP_INTERNALERROR;
+
+ zi->ci.zip64 = zip64;
+ zi->ci.totalCompressedData = 0;
+ zi->ci.totalUncompressedData = 0;
+ zi->ci.pos_zip64extrainfo = 0;
+
+ err = Write_LocalFileHeader(zi, filename, size_extrafield_local, extrafield_local);
+
+#ifdef HAVE_BZIP2
+ zi->ci.bstream.avail_in = (uInt)0;
+ zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.bstream.next_out = (char*)zi->ci.buffered_data;
+ zi->ci.bstream.total_in_hi32 = 0;
+ zi->ci.bstream.total_in_lo32 = 0;
+ zi->ci.bstream.total_out_hi32 = 0;
+ zi->ci.bstream.total_out_lo32 = 0;
+#endif
+
+ zi->ci.stream.avail_in = (uInt)0;
+ zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.stream.next_out = zi->ci.buffered_data;
+ zi->ci.stream.total_in = 0;
+ zi->ci.stream.total_out = 0;
+ zi->ci.stream.data_type = Z_BINARY;
+
+#ifdef HAVE_BZIP2
+ if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED || zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))
+#else
+ if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
+#endif
+ {
+ if(zi->ci.method == Z_DEFLATED)
+ {
+ zi->ci.stream.zalloc = (alloc_func)0;
+ zi->ci.stream.zfree = (free_func)0;
+ zi->ci.stream.opaque = (voidpf)0;
+
+ if (windowBits>0)
+ windowBits = -windowBits;
+
+ err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy);
+
+ if (err==Z_OK)
+ zi->ci.stream_initialised = Z_DEFLATED;
+ }
+ else if(zi->ci.method == Z_BZIP2ED)
+ {
+#ifdef HAVE_BZIP2
+ // Init BZip stuff here
+ zi->ci.bstream.bzalloc = 0;
+ zi->ci.bstream.bzfree = 0;
+ zi->ci.bstream.opaque = (voidpf)0;
+
+ err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0,35);
+ if(err == BZ_OK)
+ zi->ci.stream_initialised = Z_BZIP2ED;
+#endif
+ }
+
+ }
+
+# ifndef NOCRYPT
+ zi->ci.crypt_header_size = 0;
+ if ((err==Z_OK) && (password != NULL))
+ {
+ unsigned char bufHead[RAND_HEAD_LEN];
+ unsigned int sizeHead;
+ zi->ci.encrypt = 1;
+ zi->ci.pcrc_32_tab = get_crc_table();
+ /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/
+
+ sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting);
+ zi->ci.crypt_header_size = sizeHead;
+
+ if (ZWRITE64(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead)
+ err = ZIP_ERRNO;
+ }
+# endif
+
+ if (err==Z_OK)
+ zi->in_opened_file_inzip = 1;
+ return err;
+}
+
+extern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void* extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int raw,
+ int windowBits,int memLevel, int strategy,
+ const char* password, uLong crcForCrypting,
+ uLong versionMadeBy, uLong flagBase)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, raw,
+ windowBits, memLevel, strategy,
+ password, crcForCrypting, versionMadeBy, flagBase, 0);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void* extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int raw,
+ int windowBits,int memLevel, int strategy,
+ const char* password, uLong crcForCrypting)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, raw,
+ windowBits, memLevel, strategy,
+ password, crcForCrypting, VERSIONMADEBY, 0, 0);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void* extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int raw,
+ int windowBits,int memLevel, int strategy,
+ const char* password, uLong crcForCrypting, int zip64)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, raw,
+ windowBits, memLevel, strategy,
+ password, crcForCrypting, VERSIONMADEBY, 0, zip64);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void* extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int raw)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, raw,
+ -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
+ NULL, 0, VERSIONMADEBY, 0, 0);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void* extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int raw, int zip64)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, raw,
+ -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
+ NULL, 0, VERSIONMADEBY, 0, zip64);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void*extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int zip64)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, 0,
+ -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
+ NULL, 0, VERSIONMADEBY, 0, zip64);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void*extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, 0,
+ -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
+ NULL, 0, VERSIONMADEBY, 0, 0);
+}
+
+local int zip64FlushWriteBuffer(zip64_internal* zi)
+{
+ int err=ZIP_OK;
+
+ if (zi->ci.encrypt != 0)
+ {
+#ifndef NOCRYPT
+ uInt i;
+ int t;
+ for (i=0;i<zi->ci.pos_in_buffered_data;i++)
+ zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t);
+#endif
+ }
+
+ if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data)
+ err = ZIP_ERRNO;
+
+ zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data;
+
+#ifdef HAVE_BZIP2
+ if(zi->ci.method == Z_BZIP2ED)
+ {
+ zi->ci.totalUncompressedData += zi->ci.bstream.total_in_lo32;
+ zi->ci.bstream.total_in_lo32 = 0;
+ zi->ci.bstream.total_in_hi32 = 0;
+ }
+ else
+#endif
+ {
+ zi->ci.totalUncompressedData += zi->ci.stream.total_in;
+ zi->ci.stream.total_in = 0;
+ }
+
+
+ zi->ci.pos_in_buffered_data = 0;
+
+ return err;
+}
+
+extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len)
+{
+ zip64_internal* zi;
+ int err=ZIP_OK;
+
+ if (file == NULL)
+ return ZIP_PARAMERROR;
+ zi = (zip64_internal*)file;
+
+ if (zi->in_opened_file_inzip == 0)
+ return ZIP_PARAMERROR;
+
+ zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len);
+
+#ifdef HAVE_BZIP2
+ if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw))
+ {
+ zi->ci.bstream.next_in = (void*)buf;
+ zi->ci.bstream.avail_in = len;
+ err = BZ_RUN_OK;
+
+ while ((err==BZ_RUN_OK) && (zi->ci.bstream.avail_in>0))
+ {
+ if (zi->ci.bstream.avail_out == 0)
+ {
+ if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
+ err = ZIP_ERRNO;
+ zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.bstream.next_out = (char*)zi->ci.buffered_data;
+ }
+
+
+ if(err != BZ_RUN_OK)
+ break;
+
+ if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))
+ {
+ uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32;
+// uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32;
+ err=BZ2_bzCompress(&zi->ci.bstream, BZ_RUN);
+
+ zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ;
+ }
+ }
+
+ if(err == BZ_RUN_OK)
+ err = ZIP_OK;
+ }
+ else
+#endif
+ {
+ zi->ci.stream.next_in = (Bytef*)buf;
+ zi->ci.stream.avail_in = len;
+
+ while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0))
+ {
+ if (zi->ci.stream.avail_out == 0)
+ {
+ if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
+ err = ZIP_ERRNO;
+ zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.stream.next_out = zi->ci.buffered_data;
+ }
+
+
+ if(err != ZIP_OK)
+ break;
+
+ if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
+ {
+ uLong uTotalOutBefore = zi->ci.stream.total_out;
+ err=deflate(&zi->ci.stream, Z_NO_FLUSH);
+ if(uTotalOutBefore > zi->ci.stream.total_out)
+ {
+ int bBreak = 0;
+ bBreak++;
+ }
+
+ zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
+ }
+ else
+ {
+ uInt copy_this,i;
+ if (zi->ci.stream.avail_in < zi->ci.stream.avail_out)
+ copy_this = zi->ci.stream.avail_in;
+ else
+ copy_this = zi->ci.stream.avail_out;
+
+ for (i = 0; i < copy_this; i++)
+ *(((char*)zi->ci.stream.next_out)+i) =
+ *(((const char*)zi->ci.stream.next_in)+i);
+ {
+ zi->ci.stream.avail_in -= copy_this;
+ zi->ci.stream.avail_out-= copy_this;
+ zi->ci.stream.next_in+= copy_this;
+ zi->ci.stream.next_out+= copy_this;
+ zi->ci.stream.total_in+= copy_this;
+ zi->ci.stream.total_out+= copy_this;
+ zi->ci.pos_in_buffered_data += copy_this;
+ }
+ }
+ }// while(...)
+ }
+
+ return err;
+}
+
+extern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32)
+{
+ return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32);
+}
+
+extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32)
+{
+ zip64_internal* zi;
+ ZPOS64_T compressed_size;
+ uLong invalidValue = 0xffffffff;
+ short datasize = 0;
+ int err=ZIP_OK;
+
+ if (file == NULL)
+ return ZIP_PARAMERROR;
+ zi = (zip64_internal*)file;
+
+ if (zi->in_opened_file_inzip == 0)
+ return ZIP_PARAMERROR;
+ zi->ci.stream.avail_in = 0;
+
+ if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
+ {
+ while (err==ZIP_OK)
+ {
+ uLong uTotalOutBefore;
+ if (zi->ci.stream.avail_out == 0)
+ {
+ if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
+ err = ZIP_ERRNO;
+ zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.stream.next_out = zi->ci.buffered_data;
+ }
+ uTotalOutBefore = zi->ci.stream.total_out;
+ err=deflate(&zi->ci.stream, Z_FINISH);
+ zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
+ }
+ }
+ else if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))
+ {
+#ifdef HAVE_BZIP2
+ err = BZ_FINISH_OK;
+ while (err==BZ_FINISH_OK)
+ {
+ uLong uTotalOutBefore;
+ if (zi->ci.bstream.avail_out == 0)
+ {
+ if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
+ err = ZIP_ERRNO;
+ zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.bstream.next_out = (char*)zi->ci.buffered_data;
+ }
+ uTotalOutBefore = zi->ci.bstream.total_out_lo32;
+ err=BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH);
+ if(err == BZ_STREAM_END)
+ err = Z_STREAM_END;
+
+ zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore);
+ }
+
+ if(err == BZ_FINISH_OK)
+ err = ZIP_OK;
+#endif
+ }
+
+ if (err==Z_STREAM_END)
+ err=ZIP_OK; /* this is normal */
+
+ if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK))
+ {
+ if (zip64FlushWriteBuffer(zi)==ZIP_ERRNO)
+ err = ZIP_ERRNO;
+ }
+
+ if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
+ {
+ int tmp_err = deflateEnd(&zi->ci.stream);
+ if (err == ZIP_OK)
+ err = tmp_err;
+ zi->ci.stream_initialised = 0;
+ }
+#ifdef HAVE_BZIP2
+ else if((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))
+ {
+ int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream);
+ if (err==ZIP_OK)
+ err = tmperr;
+ zi->ci.stream_initialised = 0;
+ }
+#endif
+
+ if (!zi->ci.raw)
+ {
+ crc32 = (uLong)zi->ci.crc32;
+ uncompressed_size = zi->ci.totalUncompressedData;
+ }
+ compressed_size = zi->ci.totalCompressedData;
+
+# ifndef NOCRYPT
+ compressed_size += zi->ci.crypt_header_size;
+# endif
+
+ // update Current Item crc and sizes,
+ if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff)
+ {
+ /*version Made by*/
+ zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)45,2);
+ /*version needed*/
+ zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)45,2);
+
+ }
+
+ zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/
+
+
+ if(compressed_size >= 0xffffffff)
+ zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/
+ else
+ zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/
+
+ /// set internal file attributes field
+ if (zi->ci.stream.data_type == Z_ASCII)
+ zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2);
+
+ if(uncompressed_size >= 0xffffffff)
+ zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/
+ else
+ zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/
+
+ // Add ZIP64 extra info field for uncompressed size
+ if(uncompressed_size >= 0xffffffff)
+ datasize += 8;
+
+ // Add ZIP64 extra info field for compressed size
+ if(compressed_size >= 0xffffffff)
+ datasize += 8;
+
+ // Add ZIP64 extra info field for relative offset to local file header of current file
+ if(zi->ci.pos_local_header >= 0xffffffff)
+ datasize += 8;
+
+ if(datasize > 0)
+ {
+ char* p = NULL;
+
+ if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree)
+ {
+ // we can not write more data to the buffer that we have room for.
+ return ZIP_BADZIPFILE;
+ }
+
+ p = zi->ci.central_header + zi->ci.size_centralheader;
+
+ // Add Extra Information Header for 'ZIP64 information'
+ zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID
+ p += 2;
+ zip64local_putValue_inmemory(p, datasize, 2); // DataSize
+ p += 2;
+
+ if(uncompressed_size >= 0xffffffff)
+ {
+ zip64local_putValue_inmemory(p, uncompressed_size, 8);
+ p += 8;
+ }
+
+ if(compressed_size >= 0xffffffff)
+ {
+ zip64local_putValue_inmemory(p, compressed_size, 8);
+ p += 8;
+ }
+
+ if(zi->ci.pos_local_header >= 0xffffffff)
+ {
+ zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8);
+ p += 8;
+ }
+
+ // Update how much extra free space we got in the memory buffer
+ // and increase the centralheader size so the new ZIP64 fields are included
+ // ( 4 below is the size of HeaderID and DataSize field )
+ zi->ci.size_centralExtraFree -= datasize + 4;
+ zi->ci.size_centralheader += datasize + 4;
+
+ // Update the extra info size field
+ zi->ci.size_centralExtra += datasize + 4;
+ zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2);
+ }
+
+ if (err==ZIP_OK)
+ err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader);
+
+ free(zi->ci.central_header);
+
+ if (err==ZIP_OK)
+ {
+ // Update the LocalFileHeader with the new values.
+
+ ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream);
+
+ if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err = ZIP_ERRNO;
+
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */
+
+ if(uncompressed_size >= 0xffffffff)
+ {
+ if(zi->ci.pos_zip64extrainfo > 0)
+ {
+ // Update the size in the ZIP64 extended field.
+ if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err = ZIP_ERRNO;
+
+ if (err==ZIP_OK) /* compressed size, unknown */
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8);
+
+ if (err==ZIP_OK) /* uncompressed size, unknown */
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8);
+ }
+ }
+ else
+ {
+ if (err==ZIP_OK) /* compressed size, unknown */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4);
+
+ if (err==ZIP_OK) /* uncompressed size, unknown */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4);
+ }
+
+ if (ZSEEK64(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err = ZIP_ERRNO;
+ }
+
+ zi->number_entry ++;
+ zi->in_opened_file_inzip = 0;
+
+ return err;
+}
+
+extern int ZEXPORT zipCloseFileInZip (zipFile file)
+{
+ return zipCloseFileInZipRaw (file,0,0);
+}
+
+int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip)
+{
+ int err = ZIP_OK;
+ ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset;
+
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4);
+
+ /*num disks*/
+ if (err==ZIP_OK) /* number of the disk with the start of the central directory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4);
+
+ /*relative offset*/
+ if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8);
+
+ /*total disks*/ /* Do not support spawning of disk so always say 1 here*/
+ if (err==ZIP_OK) /* number of the disk with the start of the central directory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4);
+
+ return err;
+}
+
+int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip)
+{
+ int err = ZIP_OK;
+
+ uLong Zip64DataSize = 44;
+
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4);
+
+ if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); // why ZPOS64_T of this ?
+
+ if (err==ZIP_OK) /* version made by */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);
+
+ if (err==ZIP_OK) /* version needed */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);
+
+ if (err==ZIP_OK) /* number of this disk */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4);
+
+ if (err==ZIP_OK) /* number of the disk with the start of the central directory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4);
+
+ if (err==ZIP_OK) /* total number of entries in the central dir on this disk */
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8);
+
+ if (err==ZIP_OK) /* total number of entries in the central dir */
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8);
+
+ if (err==ZIP_OK) /* size of the central directory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)size_centraldir,8);
+
+ if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */
+ {
+ ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset;
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8);
+ }
+ return err;
+}
+int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip)
+{
+ int err = ZIP_OK;
+
+ /*signature*/
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4);
+
+ if (err==ZIP_OK) /* number of this disk */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2);
+
+ if (err==ZIP_OK) /* number of the disk with the start of the central directory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2);
+
+ if (err==ZIP_OK) /* total number of entries in the central dir on this disk */
+ {
+ {
+ if(zi->number_entry >= 0xFFFF)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record
+ else
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2);
+ }
+ }
+
+ if (err==ZIP_OK) /* total number of entries in the central dir */
+ {
+ if(zi->number_entry >= 0xFFFF)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record
+ else
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2);
+ }
+
+ if (err==ZIP_OK) /* size of the central directory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4);
+
+ if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */
+ {
+ ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset;
+ if(pos >= 0xffffffff)
+ {
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4);
+ }
+ else
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4);
+ }
+
+ return err;
+}
+
+int Write_GlobalComment(zip64_internal* zi, const char* global_comment)
+{
+ int err = ZIP_OK;
+ uInt size_global_comment = 0;
+
+ if(global_comment != NULL)
+ size_global_comment = (uInt)strlen(global_comment);
+
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2);
+
+ if (err == ZIP_OK && size_global_comment > 0)
+ {
+ if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment)
+ err = ZIP_ERRNO;
+ }
+ return err;
+}
+
+extern int ZEXPORT zipClose (zipFile file, const char* global_comment)
+{
+ zip64_internal* zi;
+ int err = 0;
+ uLong size_centraldir = 0;
+ ZPOS64_T centraldir_pos_inzip;
+ ZPOS64_T pos;
+
+ if (file == NULL)
+ return ZIP_PARAMERROR;
+
+ zi = (zip64_internal*)file;
+
+ if (zi->in_opened_file_inzip == 1)
+ {
+ err = zipCloseFileInZip (file);
+ }
+
+#ifndef NO_ADDFILEINEXISTINGZIP
+ if (global_comment==NULL)
+ global_comment = zi->globalcomment;
+#endif
+
+ centraldir_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream);
+
+ if (err==ZIP_OK)
+ {
+ linkedlist_datablock_internal* ldi = zi->central_dir.first_block;
+ while (ldi!=NULL)
+ {
+ if ((err==ZIP_OK) && (ldi->filled_in_this_block>0))
+ {
+ if (ZWRITE64(zi->z_filefunc,zi->filestream, ldi->data, ldi->filled_in_this_block) != ldi->filled_in_this_block)
+ err = ZIP_ERRNO;
+ }
+
+ size_centraldir += ldi->filled_in_this_block;
+ ldi = ldi->next_datablock;
+ }
+ }
+ free_linkedlist(&(zi->central_dir));
+
+ pos = centraldir_pos_inzip - zi->add_position_when_writting_offset;
+ if(pos >= 0xffffffff)
+ {
+ ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream);
+ Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip);
+
+ Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos);
+ }
+
+ if (err==ZIP_OK)
+ err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip);
+
+ if(err == ZIP_OK)
+ err = Write_GlobalComment(zi, global_comment);
+
+ if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0)
+ if (err == ZIP_OK)
+ err = ZIP_ERRNO;
+
+#ifndef NO_ADDFILEINEXISTINGZIP
+ TRYFREE(zi->globalcomment);
+#endif
+ TRYFREE(zi);
+
+ return err;
+}
+
+extern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader)
+{
+ char* p = pData;
+ int size = 0;
+ char* pNewHeader;
+ char* pTmp;
+ short header;
+ short dataSize;
+
+ int retVal = ZIP_OK;
+
+ if(pData == NULL || *dataLen < 4)
+ return ZIP_PARAMERROR;
+
+ pNewHeader = (char*)ALLOC(*dataLen);
+ pTmp = pNewHeader;
+
+ while(p < (pData + *dataLen))
+ {
+ header = *(short*)p;
+ dataSize = *(((short*)p)+1);
+
+ if( header == sHeader ) // Header found.
+ {
+ p += dataSize + 4; // skip it. do not copy to temp buffer
+ }
+ else
+ {
+ // Extra Info block should not be removed, So copy it to the temp buffer.
+ memcpy(pTmp, p, dataSize + 4);
+ p += dataSize + 4;
+ size += dataSize + 4;
+ }
+
+ }
+
+ if(size < *dataLen)
+ {
+ // clean old extra info block.
+ memset(pData,0, *dataLen);
+
+ // copy the new extra info block over the old
+ if(size > 0)
+ memcpy(pData, pNewHeader, size);
+
+ // set the new extra info size
+ *dataLen = size;
+
+ retVal = ZIP_OK;
+ }
+ else
+ retVal = ZIP_ERRNO;
+
+ TRYFREE(pNewHeader);
+
+ return retVal;
+}
diff --git a/core/io/zip.h b/core/io/zip.h
new file mode 100644
index 0000000000..3c723f093d
--- /dev/null
+++ b/core/io/zip.h
@@ -0,0 +1,361 @@
+/* Version 1.1, February 14h, 2010
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+ ---------------------------------------------------------------------------
+
+ Condition of use and distribution are the same than zlib :
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ ---------------------------------------------------------------------------
+
+ Changes
+
+ See header of zip.h
+
+*/
+
+#ifndef _zip12_H
+#define _zip12_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//#define HAVE_BZIP2
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#ifndef _ZLIBIOAPI_H
+#include "ioapi.h"
+#endif
+
+#ifdef HAVE_BZIP2
+#include "bzlib.h"
+#endif
+
+#define Z_BZIP2ED 12
+
+#if defined(STRICTZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+ from (void*) without cast */
+typedef struct TagzipFile__ { int unused; } zipFile__;
+typedef zipFile__ *zipFile;
+#else
+typedef voidp zipFile;
+#endif
+
+#define ZIP_OK (0)
+#define ZIP_EOF (0)
+#define ZIP_ERRNO (Z_ERRNO)
+#define ZIP_PARAMERROR (-102)
+#define ZIP_BADZIPFILE (-103)
+#define ZIP_INTERNALERROR (-104)
+
+#ifndef DEF_MEM_LEVEL
+# if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+# else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+# endif
+#endif
+/* default memLevel */
+
+/* tm_zip contain date/time info */
+typedef struct tm_zip_s
+{
+ uInt tm_sec; /* seconds after the minute - [0,59] */
+ uInt tm_min; /* minutes after the hour - [0,59] */
+ uInt tm_hour; /* hours since midnight - [0,23] */
+ uInt tm_mday; /* day of the month - [1,31] */
+ uInt tm_mon; /* months since January - [0,11] */
+ uInt tm_year; /* years - [1980..2044] */
+} tm_zip;
+
+typedef struct
+{
+ tm_zip tmz_date; /* date in understandable format */
+ uLong dosDate; /* if dos_date == 0, tmu_date is used */
+/* uLong flag; */ /* general purpose bit flag 2 bytes */
+
+ uLong internal_fa; /* internal file attributes 2 bytes */
+ uLong external_fa; /* external file attributes 4 bytes */
+} zip_fileinfo;
+
+typedef const char* zipcharpc;
+
+
+#define APPEND_STATUS_CREATE (0)
+#define APPEND_STATUS_CREATEAFTER (1)
+#define APPEND_STATUS_ADDINZIP (2)
+
+extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append));
+extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append));
+/*
+ Create a zipfile.
+ pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on
+ an Unix computer "zlib/zlib113.zip".
+ if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip
+ will be created at the end of the file.
+ (useful if the file contain a self extractor code)
+ if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will
+ add files in existing zip (be sure you don't add file that doesn't exist)
+ If the zipfile cannot be opened, the return value is NULL.
+ Else, the return value is a zipFile Handle, usable with other function
+ of this zip package.
+*/
+
+/* Note : there is no delete function into a zipfile.
+ If you want delete file into a zipfile, you must open a zipfile, and create another
+ Of couse, you can use RAW reading and writing to copy the file you did not want delte
+*/
+
+extern zipFile ZEXPORT zipOpen2 OF((const char *pathname,
+ int append,
+ zipcharpc* globalcomment,
+ zlib_filefunc_def* pzlib_filefunc_def));
+
+extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname,
+ int append,
+ zipcharpc* globalcomment,
+ zlib_filefunc64_def* pzlib_filefunc_def));
+
+extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level));
+
+extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int zip64));
+
+/*
+ Open a file in the ZIP for writing.
+ filename : the filename in zip (if NULL, '-' without quote will be used
+ *zipfi contain supplemental information
+ if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local
+ contains the extrafield data the the local header
+ if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global
+ contains the extrafield data the the local header
+ if comment != NULL, comment contain the comment string
+ method contain the compression method (0 for store, Z_DEFLATED for deflate)
+ level contain the level of compression (can be Z_DEFAULT_COMPRESSION)
+ zip64 is set to 1 if a zip64 extended information block should be added to the local file header.
+ this MUST be '1' if the uncompressed size is >= 0xffffffff.
+
+*/
+
+
+extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int raw));
+
+
+extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int raw,
+ int zip64));
+/*
+ Same than zipOpenNewFileInZip, except if raw=1, we write raw file
+ */
+
+extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int raw,
+ int windowBits,
+ int memLevel,
+ int strategy,
+ const char* password,
+ uLong crcForCrypting));
+
+extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int raw,
+ int windowBits,
+ int memLevel,
+ int strategy,
+ const char* password,
+ uLong crcForCrypting,
+ int zip64
+ ));
+
+/*
+ Same than zipOpenNewFileInZip2, except
+ windowBits,memLevel,,strategy : see parameter strategy in deflateInit2
+ password : crypting password (NULL for no crypting)
+ crcForCrypting : crc of file to compress (needed for crypting)
+ */
+
+extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int raw,
+ int windowBits,
+ int memLevel,
+ int strategy,
+ const char* password,
+ uLong crcForCrypting,
+ uLong versionMadeBy,
+ uLong flagBase
+ ));
+
+
+extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int raw,
+ int windowBits,
+ int memLevel,
+ int strategy,
+ const char* password,
+ uLong crcForCrypting,
+ uLong versionMadeBy,
+ uLong flagBase,
+ int zip64
+ ));
+/*
+ Same than zipOpenNewFileInZip4, except
+ versionMadeBy : value for Version made by field
+ flag : value for flag field (compression level info will be added)
+ */
+
+
+extern int ZEXPORT zipWriteInFileInZip OF((zipFile file,
+ const void* buf,
+ unsigned len));
+/*
+ Write data in the zipfile
+*/
+
+extern int ZEXPORT zipCloseFileInZip OF((zipFile file));
+/*
+ Close the current file in the zipfile
+*/
+
+extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file,
+ uLong uncompressed_size,
+ uLong crc32));
+
+extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file,
+ ZPOS64_T uncompressed_size,
+ uLong crc32));
+
+/*
+ Close the current file in the zipfile, for file opened with
+ parameter raw=1 in zipOpenNewFileInZip2
+ uncompressed_size and crc32 are value for the uncompressed size
+*/
+
+extern int ZEXPORT zipClose OF((zipFile file,
+ const char* global_comment));
+/*
+ Close the zipfile
+*/
+
+
+extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader));
+/*
+ zipRemoveExtraInfoBlock - Added by Mathias Svensson
+
+ Remove extra information block from a extra information data for the local file header or central directory header
+
+ It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode.
+
+ 0x0001 is the signature header for the ZIP64 extra information blocks
+
+ usage.
+ Remove ZIP64 Extra information from a central director extra field data
+ zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001);
+
+ Remove ZIP64 Extra information from a Local File Header extra field data
+ zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001);
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _zip64_H */
diff --git a/core/io/zip_io.h b/core/io/zip_io.h
new file mode 100644
index 0000000000..c7d5a70135
--- /dev/null
+++ b/core/io/zip_io.h
@@ -0,0 +1,129 @@
+/*************************************************************************/
+/* zip_io.h */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+#ifndef ZIP_IO_H
+#define ZIP_IO_H
+
+#include "io/zip.h"
+#include "io/unzip.h"
+#include "os/file_access.h"
+
+static void* zipio_open(void* data, const char* p_fname, int mode) {
+
+ FileAccess *&f = *(FileAccess**)data;
+
+ if (mode & ZLIB_FILEFUNC_MODE_WRITE) {
+ f = FileAccess::open(p_fname,FileAccess::WRITE);
+ } else {
+
+ f = FileAccess::open(p_fname,FileAccess::READ);
+ }
+
+ if (!f)
+ return NULL;
+
+ return data;
+
+};
+
+static uLong zipio_read(void* data, void* fdata, void* buf, uLong size) {
+
+ FileAccess* f = *(FileAccess**)data;
+ return f->get_buffer((uint8_t*)buf, size);
+
+};
+
+static uLong zipio_write(voidpf opaque, voidpf stream, const void* buf, uLong size) {
+
+ FileAccess* f = *(FileAccess**)opaque;
+ f->store_buffer((uint8_t*)buf, size);
+ return size;
+};
+
+
+static long zipio_tell (voidpf opaque, voidpf stream) {
+
+ FileAccess* f = *(FileAccess**)opaque;
+ return f->get_pos();
+};
+
+static long zipio_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 zipio_close(voidpf opaque, voidpf stream) {
+
+ FileAccess*& f = *(FileAccess**)opaque;
+ if (f) {
+ f->close();
+ f=NULL;
+ }
+ return 0;
+};
+
+static int zipio_testerror(voidpf opaque, voidpf stream) {
+
+ FileAccess* f = *(FileAccess**)opaque;
+ return (f && f->get_error()!=OK)?1:0;
+};
+
+
+static zlib_filefunc_def zipio_create_io_from_file(FileAccess **p_file) {
+
+ zlib_filefunc_def io;
+ io.opaque = p_file;
+ io.zopen_file = zipio_open;
+ io.zread_file = zipio_read;
+ io.zwrite_file = zipio_write;
+ io.ztell_file = zipio_tell;
+ io.zseek_file = zipio_seek;
+ io.zclose_file = zipio_close;
+ io.zerror_file = zipio_testerror;
+ return io;
+}
+
+
+
+#endif // ZIP_IO_H