GODOT IS OPEN SOURCE
This commit is contained in:
parent
0e49da1687
commit
0b806ee0fc
3138 changed files with 1294441 additions and 0 deletions
9
core/io/SCsub
Normal file
9
core/io/SCsub
Normal file
|
|
@ -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')
|
||||
|
||||
|
||||
110
core/io/base64.c
Normal file
110
core/io/base64.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
|
||||
11
core/io/base64.h
Normal file
11
core/io/base64.h
Normal file
|
|
@ -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 */
|
||||
91
core/io/compression.cpp
Normal file
91
core/io/compression.cpp
Normal file
|
|
@ -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();
|
||||
}
|
||||
53
core/io/compression.h
Normal file
53
core/io/compression.h
Normal file
|
|
@ -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
|
||||
744
core/io/config_file.cpp
Normal file
744
core/io/config_file.cpp
Normal file
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
63
core/io/config_file.h
Normal file
63
core/io/config_file.h
Normal file
|
|
@ -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
|
||||
131
core/io/crypt.h
Normal file
131
core/io/crypt.h
Normal file
|
|
@ -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
|
||||
551
core/io/fastlz.c
Normal file
551
core/io/fastlz.c
Normal file
|
|
@ -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) */
|
||||
100
core/io/fastlz.h
Normal file
100
core/io/fastlz.h
Normal file
|
|
@ -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 */
|
||||
184
core/io/file_access_buffered.cpp
Normal file
184
core/io/file_access_buffered.cpp
Normal file
|
|
@ -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(){
|
||||
|
||||
}
|
||||
97
core/io/file_access_buffered.h
Normal file
97
core/io/file_access_buffered.h
Normal file
|
|
@ -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
|
||||
|
||||
147
core/io/file_access_buffered_fa.h
Normal file
147
core/io/file_access_buffered_fa.h
Normal file
|
|
@ -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
|
||||
421
core/io/file_access_compressed.cpp
Normal file
421
core/io/file_access_compressed.cpp
Normal file
|
|
@ -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();
|
||||
|
||||
}
|
||||
101
core/io/file_access_compressed.h
Normal file
101
core/io/file_access_compressed.h
Normal file
|
|
@ -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
|
||||
188
core/io/file_access_memory.cpp
Normal file
188
core/io/file_access_memory.cpp
Normal file
|
|
@ -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;
|
||||
}
|
||||
76
core/io/file_access_memory.h
Normal file
76
core/io/file_access_memory.h
Normal file
|
|
@ -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
|
||||
566
core/io/file_access_network.cpp
Normal file
566
core/io/file_access_network.cpp
Normal file
|
|
@ -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();
|
||||
|
||||
}
|
||||
169
core/io/file_access_network.h
Normal file
169
core/io/file_access_network.h
Normal file
|
|
@ -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
|
||||
469
core/io/file_access_pack.cpp
Normal file
469
core/io/file_access_pack.cpp
Normal file
|
|
@ -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() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
204
core/io/file_access_pack.h
Normal file
204
core/io/file_access_pack.h
Normal file
|
|
@ -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
|
||||
367
core/io/file_access_zip.cpp
Normal file
367
core/io/file_access_zip.cpp
Normal file
|
|
@ -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
|
||||
125
core/io/file_access_zip.h
Normal file
125
core/io/file_access_zip.h
Normal file
|
|
@ -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
|
||||
641
core/io/http_client.cpp
Normal file
641
core/io/http_client.cpp
Normal file
|
|
@ -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(){
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
188
core/io/http_client.h
Normal file
188
core/io/http_client.h
Normal file
|
|
@ -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
|
||||
112
core/io/image_loader.cpp
Normal file
112
core/io/image_loader.cpp
Normal file
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
91
core/io/image_loader.h
Normal file
91
core/io/image_loader.h
Normal file
|
|
@ -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
|
||||
235
core/io/ioapi.c
Normal file
235
core/io/ioapi.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
*/
|
||||
199
core/io/ioapi.h
Normal file
199
core/io/ioapi.h
Normal file
|
|
@ -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
|
||||
270
core/io/ip.cpp
Normal file
270
core/io/ip.cpp
Normal file
|
|
@ -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
|
||||
|
||||
}
|
||||
91
core/io/ip.h
Normal file
91
core/io/ip.h
Normal file
|
|
@ -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
|
||||
60
core/io/ip_address.cpp
Normal file
60
core/io/ip_address.cpp
Normal file
|
|
@ -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;
|
||||
}
|
||||
50
core/io/ip_address.h
Normal file
50
core/io/ip_address.h
Normal file
|
|
@ -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
|
||||
477
core/io/json.cpp
Normal file
477
core/io/json.cpp
Normal file
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
81
core/io/json.h
Normal file
81
core/io/json.h
Normal file
|
|
@ -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
|
||||
1195
core/io/marshalls.cpp
Normal file
1195
core/io/marshalls.cpp
Normal file
File diff suppressed because it is too large
Load diff
190
core/io/marshalls.h
Normal file
190
core/io/marshalls.h
Normal file
|
|
@ -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
|
||||
269
core/io/md5.cpp
Normal file
269
core/io/md5.cpp
Normal file
|
|
@ -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) ********************************
|
||||
*/
|
||||
61
core/io/md5.h
Normal file
61
core/io/md5.h
Normal file
|
|
@ -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
|
||||
1491
core/io/object_format_binary.cpp
Normal file
1491
core/io/object_format_binary.cpp
Normal file
File diff suppressed because it is too large
Load diff
158
core/io/object_format_binary.h
Normal file
158
core/io/object_format_binary.h
Normal file
|
|
@ -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
|
||||
3190
core/io/object_format_xml.cpp
Normal file
3190
core/io/object_format_xml.cpp
Normal file
File diff suppressed because it is too large
Load diff
196
core/io/object_format_xml.h
Normal file
196
core/io/object_format_xml.h
Normal file
|
|
@ -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
|
||||
84
core/io/object_loader.cpp
Normal file
84
core/io/object_loader.cpp
Normal file
|
|
@ -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
|
||||
76
core/io/object_loader.h
Normal file
76
core/io/object_loader.h
Normal file
|
|
@ -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
|
||||
157
core/io/object_saver.cpp
Normal file
157
core/io/object_saver.cpp
Normal file
|
|
@ -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
|
||||
128
core/io/object_saver.h
Normal file
128
core/io/object_saver.h
Normal file
|
|
@ -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
|
||||
150
core/io/object_saver_base.cpp
Normal file
150
core/io/object_saver_base.cpp
Normal file
|
|
@ -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
|
||||
76
core/io/object_saver_base.h
Normal file
76
core/io/object_saver_base.h
Normal file
|
|
@ -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
|
||||
255
core/io/packet_peer.cpp
Normal file
255
core/io/packet_peer.cpp
Normal file
|
|
@ -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);
|
||||
|
||||
|
||||
}
|
||||
94
core/io/packet_peer.h
Normal file
94
core/io/packet_peer.h
Normal file
|
|
@ -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
|
||||
1918
core/io/resource_format_binary.cpp
Normal file
1918
core/io/resource_format_binary.cpp
Normal file
File diff suppressed because it is too large
Load diff
184
core/io/resource_format_binary.h
Normal file
184
core/io/resource_format_binary.h
Normal file
|
|
@ -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
|
||||
2557
core/io/resource_format_xml.cpp
Normal file
2557
core/io/resource_format_xml.cpp
Normal file
File diff suppressed because it is too large
Load diff
155
core/io/resource_format_xml.h
Normal file
155
core/io/resource_format_xml.h
Normal file
|
|
@ -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
|
||||
378
core/io/resource_loader.cpp
Normal file
378
core/io/resource_loader.cpp
Normal file
|
|
@ -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;
|
||||
|
||||
114
core/io/resource_loader.h
Normal file
114
core/io/resource_loader.h
Normal file
|
|
@ -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
|
||||
127
core/io/resource_saver.cpp
Normal file
127
core/io/resource_saver.cpp
Normal file
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
95
core/io/resource_saver.h
Normal file
95
core/io/resource_saver.h
Normal file
|
|
@ -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
|
||||
126
core/io/stream_peer.cpp
Normal file
126
core/io/stream_peer.cpp
Normal file
|
|
@ -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);
|
||||
}
|
||||
58
core/io/stream_peer.h
Normal file
58
core/io/stream_peer.h
Normal file
|
|
@ -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
|
||||
56
core/io/stream_peer_tcp.cpp
Normal file
56
core/io/stream_peer_tcp.cpp
Normal file
|
|
@ -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() {
|
||||
|
||||
};
|
||||
|
||||
75
core/io/stream_peer_tcp.h
Normal file
75
core/io/stream_peer_tcp.h
Normal file
|
|
@ -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
|
||||
62
core/io/tcp_server.cpp
Normal file
62
core/io/tcp_server.cpp
Normal file
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
59
core/io/tcp_server.h
Normal file
59
core/io/tcp_server.h
Normal file
|
|
@ -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
|
||||
201
core/io/translation_loader_po.cpp
Normal file
201
core/io/translation_loader_po.cpp
Normal file
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
46
core/io/translation_loader_po.h
Normal file
46
core/io/translation_loader_po.h
Normal file
|
|
@ -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
|
||||
2216
core/io/unzip.c
Normal file
2216
core/io/unzip.c
Normal file
File diff suppressed because it is too large
Load diff
445
core/io/unzip.h
Normal file
445
core/io/unzip.h
Normal file
|
|
@ -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 */
|
||||
576
core/io/xml_parser.cpp
Normal file
576
core/io/xml_parser.cpp
Normal file
|
|
@ -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("&");
|
||||
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);
|
||||
}
|
||||
123
core/io/xml_parser.h
Normal file
123
core/io/xml_parser.h
Normal file
|
|
@ -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
|
||||
|
||||
2004
core/io/zip.c
Normal file
2004
core/io/zip.c
Normal file
File diff suppressed because it is too large
Load diff
361
core/io/zip.h
Normal file
361
core/io/zip.h
Normal file
|
|
@ -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 */
|
||||
129
core/io/zip_io.h
Normal file
129
core/io/zip_io.h
Normal file
|
|
@ -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
|
||||
Loading…
Add table
Add a link
Reference in a new issue