diff options
Diffstat (limited to 'core/io/object_format_binary.cpp')
| -rw-r--r-- | core/io/object_format_binary.cpp | 1491 |
1 files changed, 1491 insertions, 0 deletions
diff --git a/core/io/object_format_binary.cpp b/core/io/object_format_binary.cpp new file mode 100644 index 000000000..c031f6e82 --- /dev/null +++ b/core/io/object_format_binary.cpp @@ -0,0 +1,1491 @@ +/*************************************************************************/ +/* object_format_binary.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "object_format_binary.h" +#include "resource.h" +#include "io/resource_loader.h" +#include "print_string.h" +#include "object_type_db.h" +#include "globals.h" +#include "os/os.h" +#include "version.h" + + +#define print_bl(m_what) +#ifdef OLD_SCENE_FORMAT_ENABLED + + +enum { + + SECTION_RESOURCE=0, + SECTION_OBJECT=1, + SECTION_META_OBJECT=2, + SECTION_PROPERTY=3, + SECTION_END=4, + + //numbering must be different from variant, in case new variant types are added (variant must be always contiguous for jumptable optimization) + VARIANT_NIL=1, + VARIANT_BOOL=2, + VARIANT_INT=3, + VARIANT_REAL=4, + VARIANT_STRING=5, + VARIANT_VECTOR2=10, + VARIANT_RECT2=11, + VARIANT_VECTOR3=12, + VARIANT_PLANE=13, + VARIANT_QUAT=14, + VARIANT_AABB=15, + VARIANT_MATRIX3=16, + VARIANT_TRANSFORM=17, + VARIANT_MATRIX32=18, + VARIANT_COLOR=20, + VARIANT_IMAGE=21, + VARIANT_NODE_PATH=22, + VARIANT_RID=23, + VARIANT_OBJECT=24, + VARIANT_INPUT_EVENT=25, + VARIANT_DICTIONARY=26, + VARIANT_ARRAY=30, + VARIANT_RAW_ARRAY=31, + VARIANT_INT_ARRAY=32, + VARIANT_REAL_ARRAY=33, + VARIANT_STRING_ARRAY=34, + VARIANT_VECTOR3_ARRAY=35, + VARIANT_COLOR_ARRAY=36, + VARIANT_VECTOR2_ARRAY=37, + + IMAGE_ENCODING_EMPTY=0, + IMAGE_ENCODING_RAW=1, + IMAGE_ENCODING_PNG=2, //not yet + IMAGE_ENCODING_JPG=3, + + IMAGE_FORMAT_GRAYSCALE=0, + IMAGE_FORMAT_INTENSITY=1, + IMAGE_FORMAT_GRAYSCALE_ALPHA=2, + IMAGE_FORMAT_RGB=3, + IMAGE_FORMAT_RGBA=4, + IMAGE_FORMAT_INDEXED=5, + IMAGE_FORMAT_INDEXED_ALPHA=6, + IMAGE_FORMAT_BC1=7, + IMAGE_FORMAT_BC2=8, + IMAGE_FORMAT_BC3=9, + IMAGE_FORMAT_BC4=10, + IMAGE_FORMAT_BC5=11, + IMAGE_FORMAT_CUSTOM=12, + + OBJECT_EMPTY=0, + OBJECT_EXTERNAL_RESOURCE=1, + OBJECT_INTERNAL_RESOURCE=2, + + +}; + + +void ObjectFormatSaverBinary::_pad_buffer(int p_bytes) { + + int extra = 4-(p_bytes%4); + if (extra<4) { + for(int i=0;i<extra;i++) + f->store_8(0); //pad to 32 + } + +} + + +void ObjectFormatSaverBinary::write_property(int p_idx,const Variant& p_property) { + + f->store_32(SECTION_PROPERTY); + f->store_32(p_idx); + + switch(p_property.get_type()) { + + case Variant::NIL: { + + f->store_32(VARIANT_NIL); + // don't store anything + } break; + case Variant::BOOL: { + + f->store_32(VARIANT_BOOL); + bool val=p_property; + f->store_32(val); + } break; + case Variant::INT: { + + f->store_32(VARIANT_INT); + int val=p_property; + f->store_32(val); + } break; + case Variant::REAL: { + + f->store_32(VARIANT_REAL); + real_t val=p_property; + f->store_real(val); + + } break; + case Variant::STRING: { + + f->store_32(VARIANT_STRING); + String val=p_property; + save_unicode_string(val); + + } break; + case Variant::VECTOR2: { + + f->store_32(VARIANT_VECTOR2); + Vector2 val=p_property; + f->store_real(val.x); + f->store_real(val.y); + + } break; + case Variant::RECT2: { + + f->store_32(VARIANT_RECT2); + Rect2 val=p_property; + f->store_real(val.pos.x); + f->store_real(val.pos.y); + f->store_real(val.size.x); + f->store_real(val.size.y); + + } break; + case Variant::VECTOR3: { + + f->store_32(VARIANT_VECTOR3); + Vector3 val=p_property; + f->store_real(val.x); + f->store_real(val.y); + f->store_real(val.z); + + } break; + case Variant::PLANE: { + + f->store_32(VARIANT_PLANE); + Plane val=p_property; + f->store_real(val.normal.x); + f->store_real(val.normal.y); + f->store_real(val.normal.z); + f->store_real(val.d); + + } break; + case Variant::QUAT: { + + f->store_32(VARIANT_QUAT); + Quat val=p_property; + f->store_real(val.x); + f->store_real(val.y); + f->store_real(val.z); + f->store_real(val.w); + + } break; + case Variant::_AABB: { + + f->store_32(VARIANT_AABB); + AABB val=p_property; + f->store_real(val.pos.x); + f->store_real(val.pos.y); + f->store_real(val.pos.z); + f->store_real(val.size.x); + f->store_real(val.size.y); + f->store_real(val.size.z); + + } break; + case Variant::MATRIX32: { + + f->store_32(VARIANT_MATRIX32); + Matrix32 val=p_property; + f->store_real(val.elements[0].x); + f->store_real(val.elements[0].y); + f->store_real(val.elements[1].x); + f->store_real(val.elements[1].y); + f->store_real(val.elements[2].x); + f->store_real(val.elements[2].y); + + } break; + case Variant::MATRIX3: { + + f->store_32(VARIANT_MATRIX3); + Matrix3 val=p_property; + f->store_real(val.elements[0].x); + f->store_real(val.elements[0].y); + f->store_real(val.elements[0].z); + f->store_real(val.elements[1].x); + f->store_real(val.elements[1].y); + f->store_real(val.elements[1].z); + f->store_real(val.elements[2].x); + f->store_real(val.elements[2].y); + f->store_real(val.elements[2].z); + + } break; + case Variant::TRANSFORM: { + + f->store_32(VARIANT_TRANSFORM); + Transform val=p_property; + f->store_real(val.basis.elements[0].x); + f->store_real(val.basis.elements[0].y); + f->store_real(val.basis.elements[0].z); + f->store_real(val.basis.elements[1].x); + f->store_real(val.basis.elements[1].y); + f->store_real(val.basis.elements[1].z); + f->store_real(val.basis.elements[2].x); + f->store_real(val.basis.elements[2].y); + f->store_real(val.basis.elements[2].z); + f->store_real(val.origin.x); + f->store_real(val.origin.y); + f->store_real(val.origin.z); + + } break; + case Variant::COLOR: { + + f->store_32(VARIANT_COLOR); + Color val=p_property; + f->store_real(val.r); + f->store_real(val.g); + f->store_real(val.b); + f->store_real(val.a); + + } break; + case Variant::IMAGE: { + + f->store_32(VARIANT_IMAGE); + Image val =p_property; + if (val.empty()) { + f->store_32(IMAGE_ENCODING_EMPTY); + break; + } + f->store_32(IMAGE_ENCODING_RAW); //raw encoding + f->store_32(val.get_width()); + f->store_32(val.get_height()); + f->store_32(val.get_mipmaps()); + switch(val.get_format()) { + + case Image::FORMAT_GRAYSCALE: f->store_32(IMAGE_FORMAT_GRAYSCALE ); break; ///< one byte per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255 + case Image::FORMAT_INTENSITY: f->store_32(IMAGE_FORMAT_INTENSITY ); break; ///< one byte per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255 + case Image::FORMAT_GRAYSCALE_ALPHA: f->store_32(IMAGE_FORMAT_GRAYSCALE_ALPHA ); break; ///< two bytes per pixel: f->store_32(IMAGE_FORMAT_ ); break; 0-255. alpha 0-255 + case Image::FORMAT_RGB: f->store_32(IMAGE_FORMAT_RGB ); break; ///< one byte R: f->store_32(IMAGE_FORMAT_ ); break; one byte G: f->store_32(IMAGE_FORMAT_ ); break; one byte B + case Image::FORMAT_RGBA: f->store_32(IMAGE_FORMAT_RGBA ); break; ///< one byte R: f->store_32(IMAGE_FORMAT_ ); break; one byte G: f->store_32(IMAGE_FORMAT_ ); break; one byte B: f->store_32(IMAGE_FORMAT_ ); break; one byte A + case Image::FORMAT_INDEXED: f->store_32(IMAGE_FORMAT_INDEXED ); break; ///< index byte 0-256: f->store_32(IMAGE_FORMAT_ ); break; and after image end: f->store_32(IMAGE_FORMAT_ ); break; 256*3 bytes of palette + case Image::FORMAT_INDEXED_ALPHA: f->store_32(IMAGE_FORMAT_INDEXED_ALPHA ); break; ///< index byte 0-256: f->store_32(IMAGE_FORMAT_ ); break; and after image end: f->store_32(IMAGE_FORMAT_ ); break; 256*4 bytes of palette (alpha) + case Image::FORMAT_BC1: f->store_32(IMAGE_FORMAT_BC1 ); break; // DXT1 + case Image::FORMAT_BC2: f->store_32(IMAGE_FORMAT_BC2 ); break; // DXT3 + case Image::FORMAT_BC3: f->store_32(IMAGE_FORMAT_BC3 ); break; // DXT5 + case Image::FORMAT_BC4: f->store_32(IMAGE_FORMAT_BC4 ); break; // ATI1 + case Image::FORMAT_BC5: f->store_32(IMAGE_FORMAT_BC5 ); break; // ATI2 + case Image::FORMAT_CUSTOM: f->store_32(IMAGE_FORMAT_CUSTOM ); break; + default: {} + + } + + int dlen = val.get_data().size(); + f->store_32(dlen); + DVector<uint8_t>::Read r = val.get_data().read(); + f->store_buffer(r.ptr(),dlen); + _pad_buffer(dlen); + + } break; + case Variant::NODE_PATH: { + f->store_32(VARIANT_NODE_PATH); + save_unicode_string(p_property); + } break; + case Variant::_RID: { + + f->store_32(VARIANT_RID); + WARN_PRINT("Can't save RIDs"); + RID val = p_property; + f->store_32(val.get_id()); + } break; + case Variant::OBJECT: { + + f->store_32(VARIANT_OBJECT); + RES res = p_property; + if (res.is_null()) { + f->store_32(OBJECT_EMPTY); + return; // don't save it + } + + if (res->get_path().length() && res->get_path().find("::")==-1) { + f->store_32(OBJECT_EXTERNAL_RESOURCE); + save_unicode_string(res->get_type()); + String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path(); + save_unicode_string(path); + } else { + + if (!resource_map.has(res)) { + f->store_32(OBJECT_EMPTY); + ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?"); + ERR_FAIL(); + } + + f->store_32(OBJECT_INTERNAL_RESOURCE); + f->store_32(resource_map[res]); + //internal resource + } + + + } break; + case Variant::INPUT_EVENT: { + + f->store_32(VARIANT_INPUT_EVENT); + WARN_PRINT("Can't save InputEvent (maybe it could..)"); + } break; + case Variant::DICTIONARY: { + + f->store_32(VARIANT_DICTIONARY); + Dictionary d = p_property; + f->store_32(d.size()); + + List<Variant> keys; + d.get_key_list(&keys); + + for(List<Variant>::Element *E=keys.front();E;E=E->next()) { + + //if (!_check_type(dict[E->get()])) + // continue; + + write_property(0,E->get()); + write_property(0,d[E->get()]); + } + + + } break; + case Variant::ARRAY: { + + f->store_32(VARIANT_ARRAY); + Array a=p_property; + f->store_32(a.size()); + for(int i=0;i<a.size();i++) { + + write_property(i,a[i]); + } + + } break; + case Variant::RAW_ARRAY: { + + f->store_32(VARIANT_RAW_ARRAY); + DVector<uint8_t> arr = p_property; + int len=arr.size(); + f->store_32(len); + DVector<uint8_t>::Read r = arr.read(); + f->store_buffer(r.ptr(),len); + _pad_buffer(len); + + } break; + case Variant::INT_ARRAY: { + + f->store_32(VARIANT_INT_ARRAY); + DVector<int> arr = p_property; + int len=arr.size(); + f->store_32(len); + DVector<int>::Read r = arr.read(); + for(int i=0;i<len;i++) + f->store_32(r[i]); + + } break; + case Variant::REAL_ARRAY: { + + f->store_32(VARIANT_REAL_ARRAY); + DVector<real_t> arr = p_property; + int len=arr.size(); + f->store_32(len); + DVector<real_t>::Read r = arr.read(); + for(int i=0;i<len;i++) { + f->store_real(r[i]); + } + + } break; + case Variant::STRING_ARRAY: { + + f->store_32(VARIANT_STRING_ARRAY); + DVector<String> arr = p_property; + int len=arr.size(); + f->store_32(len); + DVector<String>::Read r = arr.read(); + for(int i=0;i<len;i++) { + save_unicode_string(r[i]); + } + + } break; + case Variant::VECTOR3_ARRAY: { + + f->store_32(VARIANT_VECTOR3_ARRAY); + DVector<Vector3> arr = p_property; + int len=arr.size(); + f->store_32(len); + DVector<Vector3>::Read r = arr.read(); + for(int i=0;i<len;i++) { + f->store_real(r[i].x); + f->store_real(r[i].y); + f->store_real(r[i].z); + } + + } break; + case Variant::VECTOR2_ARRAY: { + + f->store_32(VARIANT_VECTOR2_ARRAY); + DVector<Vector2> arr = p_property; + int len=arr.size(); + f->store_32(len); + DVector<Vector2>::Read r = arr.read(); + for(int i=0;i<len;i++) { + f->store_real(r[i].x); + f->store_real(r[i].y); + } + + } break; + case Variant::COLOR_ARRAY: { + + f->store_32(VARIANT_COLOR_ARRAY); + DVector<Color> arr = p_property; + int len=arr.size(); + f->store_32(len); + DVector<Color>::Read r = arr.read(); + for(int i=0;i<len;i++) { + f->store_real(r[i].r); + f->store_real(r[i].g); + f->store_real(r[i].b); + f->store_real(r[i].a); + } + + } break; + default: { + + ERR_EXPLAIN("Invalid variant"); + ERR_FAIL(); + } + } +} + + +void ObjectFormatSaverBinary::_find_resources(const Variant& p_variant) { + + + switch(p_variant.get_type()) { + case Variant::OBJECT: { + + + RES res = p_variant.operator RefPtr(); + + if (res.is_null()) + return; + + if (!bundle_resources && res->get_path().length() && res->get_path().find("::") == -1 ) + return; + + if (resource_map.has(res)) + return; + + List<PropertyInfo> property_list; + + res->get_property_list(&property_list); + + for(List<PropertyInfo>::Element *E=property_list.front();E;E=E->next()) { + + if (E->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && E->get().usage&PROPERTY_USAGE_BUNDLE)) { + + _find_resources(res->get(E->get().name)); + } + } + + SavedObject *so = memnew( SavedObject ); + _save_obj(res.ptr(),so); + so->meta=res.get_ref_ptr(); + + resource_map[ res ] = saved_resources.size(); + saved_resources.push_back(so); + + } break; + + case Variant::ARRAY: { + + Array varray=p_variant; + int len=varray.size(); + for(int i=0;i<len;i++) { + + Variant v=varray.get(i); + _find_resources(v); + } + + } break; + + case Variant::DICTIONARY: { + + Dictionary d=p_variant; + List<Variant> keys; + d.get_key_list(&keys); + for(List<Variant>::Element *E=keys.front();E;E=E->next()) { + + Variant v = d[E->get()]; + _find_resources(v); + } + } break; + default: {} + } + +} +Error ObjectFormatSaverBinary::_save_obj(const Object *p_object,SavedObject *so) { + + if (optimizer.is_valid()) { + //use optimizer + + List<OptimizedSaver::Property> props; + optimizer->get_property_list(p_object,&props); + + for(List<OptimizedSaver::Property>::Element *E=props.front();E;E=E->next()) { + + if (skip_editor && String(E->get().name).begins_with("__editor")) + continue; + _find_resources(E->get().value); + SavedObject::SavedProperty sp; + + sp.name_idx=get_string_index(E->get().name); + sp.value=E->get().value; + so->properties.push_back(sp); + } + + } else { + //use classic way + List<PropertyInfo> property_list; + p_object->get_property_list( &property_list ); + + for(List<PropertyInfo>::Element *E=property_list.front();E;E=E->next()) { + + if (skip_editor && E->get().name.begins_with("__editor")) + continue; + if (E->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && E->get().usage&PROPERTY_USAGE_BUNDLE)) { + + SavedObject::SavedProperty sp; + sp.name_idx=get_string_index(E->get().name); + sp.value = p_object->get(E->get().name); + _find_resources(sp.value); + so->properties.push_back(sp); + } + } + } + + return OK; + +} + +Error ObjectFormatSaverBinary::save(const Object *p_object,const Variant &p_meta) { + + ERR_FAIL_COND_V(!f,ERR_UNCONFIGURED); + ERR_EXPLAIN("write_object should supply either an object, a meta, or both"); + ERR_FAIL_COND_V(!p_object && p_meta.get_type()==Variant::NIL, ERR_INVALID_PARAMETER); + + SavedObject *so = memnew( SavedObject ); + + if (p_object) + so->type=p_object->get_type(); + + _find_resources(p_meta); + so->meta=p_meta; + Error err = _save_obj(p_object,so); + ERR_FAIL_COND_V( err, ERR_INVALID_DATA ); + + saved_objects.push_back(so); + + return OK; +} + +void ObjectFormatSaverBinary::save_unicode_string(const String& p_string) { + + + CharString utf8 = p_string.utf8(); + f->store_32(utf8.length()+1); + f->store_buffer((const uint8_t*)utf8.get_data(),utf8.length()+1); +} + +ObjectFormatSaverBinary::ObjectFormatSaverBinary(FileAccess *p_file,const String& p_magic,const String& p_local_path,uint32_t p_flags,const Ref<OptimizedSaver>& p_optimizer) { + + optimizer=p_optimizer; + relative_paths=p_flags&ObjectSaver::FLAG_RELATIVE_PATHS; + skip_editor=p_flags&ObjectSaver::FLAG_OMIT_EDITOR_PROPERTIES; + bundle_resources=p_flags&ObjectSaver::FLAG_BUNDLE_RESOURCES; + big_endian=p_flags&ObjectSaver::FLAG_SAVE_BIG_ENDIAN; + f=p_file; // should be already opened + local_path=p_local_path; + magic=p_magic; + + bin_meta_idx = get_string_index("__bin_meta__"); //is often used, so create +} + +int ObjectFormatSaverBinary::get_string_index(const String& p_string) { + + StringName s=p_string; + if (string_map.has(s)) + return string_map[s]; + + string_map[s]=strings.size(); + strings.push_back(s); + return strings.size()-1; +} + +ObjectFormatSaverBinary::~ObjectFormatSaverBinary() { + + + static const uint8_t header[4]={'O','B','D','B'}; + f->store_buffer(header,4); + if (big_endian) { + f->store_32(1); + f->set_endian_swap(true); + } else + f->store_32(0); + + f->store_32(0); //64 bits file, false for now + f->store_32(VERSION_MAJOR); + f->store_32(VERSION_MINOR); + save_unicode_string(magic); + for(int i=0;i<16;i++) + f->store_32(0); // reserved + + f->store_32(strings.size()); //string table size + for(int i=0;i<strings.size();i++) { + print_bl("saving string: "+strings[i]); + save_unicode_string(strings[i]); + } + + // save resources + + for(int i=0;i<saved_resources.size();i++) { + + SavedObject *so = saved_resources[i]; + RES res = so->meta; + ERR_CONTINUE(!resource_map.has(res)); + + f->store_32(SECTION_RESOURCE); + size_t skip_pos = f->get_pos(); + f->store_64(0); // resource skip seek pos + save_unicode_string(res->get_type()); + + if (res->get_path().length() && res->get_path().find("::") == -1 ) + save_unicode_string(res->get_path()); + else + save_unicode_string("local://"+itos(i)); + + + + List<SavedObject::SavedProperty>::Element *SE = so->properties.front(); + + while(SE) { + + write_property(SE->get().name_idx,SE->get().value); + SE=SE->next(); + } + + f->store_32(SECTION_END); + + size_t end=f->get_pos(); + f->seek(skip_pos); + f->store_64(end); + f->seek_end(); + + memdelete( so ); + } + + if (!saved_objects.empty()) { + + + for(List<SavedObject*>::Element *E=saved_objects.front();E;E=E->next()) { + + SavedObject *so = E->get(); + + + size_t section_end; + + if (so->type!="") { + f->store_32(SECTION_OBJECT); + section_end=f->get_pos(); + f->store_64(0); //section end + save_unicode_string(so->type); + } else { + f->store_32(SECTION_META_OBJECT); + section_end=f->get_pos(); + f->store_64(0); //section end + } + + + if (so->meta.get_type()!=Variant::NIL) + write_property(bin_meta_idx,so->meta); + + List<SavedObject::SavedProperty>::Element *SE = so->properties.front(); + + while(SE) { + + write_property(SE->get().name_idx,SE->get().value); + SE=SE->next(); + } + + f->store_32(SECTION_END); + + size_t end=f->get_pos(); + f->seek(section_end); + f->store_64(end); + f->seek_end(); + + memdelete(so); //no longer needed + } + + + } + + f->store_32(SECTION_END); + + f->close(); + memdelete(f); +} + + +ObjectFormatSaver* ObjectFormatSaverInstancerBinary::instance(const String& p_file,const String& p_magic,uint32_t p_flags,const Ref<OptimizedSaver>& p_optimizer) { + + FileAccess *f = FileAccess::open(p_file, FileAccess::WRITE); + + ERR_FAIL_COND_V( !f, NULL ); + String local_path = Globals::get_singleton()->localize_path(p_file); + + return memnew( ObjectFormatSaverBinary( f, p_magic,local_path,p_flags,p_optimizer ) ); +} + +void ObjectFormatSaverInstancerBinary::get_recognized_extensions(List<String> *p_extensions) const { + + p_extensions->push_back("bin"); +} + + +ObjectFormatSaverInstancerBinary::~ObjectFormatSaverInstancerBinary() { + + +} + + + +/************************************************/ +/************************************************/ +/************************************************/ +/************************************************/ +/************************************************/ + + +void ObjectFormatLoaderBinary::_advance_padding(uint32_t p_len) { + + uint32_t extra = 4-(p_len%4); + if (extra<4) { + for(uint32_t i=0;i<extra;i++) + f->get_8(); //pad to 32 + } + +} + +Error ObjectFormatLoaderBinary::parse_property(Variant& r_v, int &r_index) { + + + uint32_t prop = f->get_32(); + if (prop==SECTION_END) + return ERR_FILE_EOF; + ERR_FAIL_COND_V(prop!=SECTION_PROPERTY,ERR_FILE_CORRUPT); + + r_index = f->get_32(); + + uint32_t type = f->get_32(); + print_bl("find property of type: "+itos(type)); + + + switch(type) { + + case VARIANT_NIL: { + + r_v=Variant(); + } break; + case VARIANT_BOOL: { + + r_v=bool(f->get_32()); + } break; + case VARIANT_INT: { + + r_v=int(f->get_32()); + } break; + case VARIANT_REAL: { + + r_v=f->get_real(); + } break; + case VARIANT_STRING: { + + r_v=get_unicode_string(); + } break; + case VARIANT_VECTOR2: { + + Vector2 v; + v.x=f->get_real(); + v.y=f->get_real(); + r_v=v; + + } break; + case VARIANT_RECT2: { + + Rect2 v; + v.pos.x=f->get_real(); + v.pos.y=f->get_real(); + v.size.x=f->get_real(); + v.size.y=f->get_real(); + r_v=v; + + } break; + case VARIANT_VECTOR3: { + + Vector3 v; + v.x=f->get_real(); + v.y=f->get_real(); + v.z=f->get_real(); + r_v=v; + } break; + case VARIANT_PLANE: { + + Plane v; + v.normal.x=f->get_real(); + v.normal.y=f->get_real(); + v.normal.z=f->get_real(); + v.d=f->get_real(); + r_v=v; + } break; + case VARIANT_QUAT: { + Quat v; + v.x=f->get_real(); + v.y=f->get_real(); + v.z=f->get_real(); + v.w=f->get_real(); + r_v=v; + + } break; + case VARIANT_AABB: { + + AABB v; + v.pos.x=f->get_real(); + v.pos.y=f->get_real(); + v.pos.z=f->get_real(); + v.size.x=f->get_real(); + v.size.y=f->get_real(); + v.size.z=f->get_real(); + r_v=v; + + } break; + case VARIANT_MATRIX32: { + + Matrix32 v; + v.elements[0].x=f->get_real(); + v.elements[0].y=f->get_real(); + v.elements[1].x=f->get_real(); + v.elements[1].y=f->get_real(); + v.elements[2].x=f->get_real(); + v.elements[2].y=f->get_real(); + r_v=v; + + } break; + case VARIANT_MATRIX3: { + + Matrix3 v; + v.elements[0].x=f->get_real(); + v.elements[0].y=f->get_real(); + v.elements[0].z=f->get_real(); + v.elements[1].x=f->get_real(); + v.elements[1].y=f->get_real(); + v.elements[1].z=f->get_real(); + v.elements[2].x=f->get_real(); + v.elements[2].y=f->get_real(); + v.elements[2].z=f->get_real(); + r_v=v; + + } break; + case VARIANT_TRANSFORM: { + + Transform v; + v.basis.elements[0].x=f->get_real(); + v.basis.elements[0].y=f->get_real(); + v.basis.elements[0].z=f->get_real(); + v.basis.elements[1].x=f->get_real(); + v.basis.elements[1].y=f->get_real(); + v.basis.elements[1].z=f->get_real(); + v.basis.elements[2].x=f->get_real(); + v.basis.elements[2].y=f->get_real(); + v.basis.elements[2].z=f->get_real(); + v.origin.x=f->get_real(); + v.origin.y=f->get_real(); + v.origin.z=f->get_real(); + r_v=v; + } break; + case VARIANT_COLOR: { + + Color v; + v.r=f->get_real(); + v.g=f->get_real(); + v.b=f->get_real(); + v.a=f->get_real(); + r_v=v; + + } break; + case VARIANT_IMAGE: { + + + uint32_t encoding = f->get_32(); + if (encoding==IMAGE_ENCODING_EMPTY) { + r_v=Variant(); + break; + } + + if (encoding==IMAGE_ENCODING_RAW) { + uint32_t width = f->get_32(); + uint32_t height = f->get_32(); + uint32_t mipmaps = f->get_32(); + uint32_t format = f->get_32(); + Image::Format fmt; + switch(format) { + + case IMAGE_FORMAT_GRAYSCALE: { fmt=Image::FORMAT_GRAYSCALE; } break; + case IMAGE_FORMAT_INTENSITY: { fmt=Image::FORMAT_INTENSITY; } break; + case IMAGE_FORMAT_GRAYSCALE_ALPHA: { fmt=Image::FORMAT_GRAYSCALE_ALPHA; } break; + case IMAGE_FORMAT_RGB: { fmt=Image::FORMAT_RGB; } break; + case IMAGE_FORMAT_RGBA: { fmt=Image::FORMAT_RGBA; } break; + case IMAGE_FORMAT_INDEXED: { fmt=Image::FORMAT_INDEXED; } break; + case IMAGE_FORMAT_INDEXED_ALPHA: { fmt=Image::FORMAT_INDEXED_ALPHA; } break; + case IMAGE_FORMAT_BC1: { fmt=Image::FORMAT_BC1; } break; + case IMAGE_FORMAT_BC2: { fmt=Image::FORMAT_BC2; } break; + case IMAGE_FORMAT_BC3: { fmt=Image::FORMAT_BC3; } break; + case IMAGE_FORMAT_BC4: { fmt=Image::FORMAT_BC4; } break; + case IMAGE_FORMAT_BC5: { fmt=Image::FORMAT_BC5; } break; + case IMAGE_FORMAT_CUSTOM: { fmt=Image::FORMAT_CUSTOM; } break; + default: { + + ERR_FAIL_V(ERR_FILE_CORRUPT); + } + + } + + + uint32_t datalen = f->get_32(); + + print_bl("width: "+itos(width)); + print_bl("height: "+itos(height)); + print_bl("mipmaps: "+itos(mipmaps)); + print_bl("format: "+itos(format)); + print_bl("datalen: "+itos(datalen)); + + DVector<uint8_t> imgdata; + imgdata.resize(datalen); + DVector<uint8_t>::Write w = imgdata.write(); + f->get_buffer(w.ptr(),datalen); + _advance_padding(datalen); + w=DVector<uint8_t>::Write(); + + r_v=Image(width,height,mipmaps,fmt,imgdata); + } + + + } break; + case VARIANT_NODE_PATH: { + + r_v=NodePath(get_unicode_string()); + } break; + case VARIANT_RID: { + + r_v=f->get_32(); + } break; + case VARIANT_OBJECT: { + + uint32_t type=f->get_32(); + + switch(type) { + + case OBJECT_EMPTY: { + //do none + + } break; + case OBJECT_INTERNAL_RESOURCE: { + uint32_t index=f->get_32(); + String path = local_path+"::"+itos(index); + RES res = ResourceLoader::load(path); + if (res.is_null()) { + WARN_PRINT(String("Couldn't load resource: "+path).utf8().get_data()); + } + r_v=res; + + } break; + case OBJECT_EXTERNAL_RESOURCE: { + + String type = get_unicode_string(); + String path = get_unicode_string(); + + if (path.find("://")==-1 && path.is_rel_path()) { + // path is relative to file being loaded, so convert to a resource path + path=Globals::get_singleton()->localize_path(local_path.get_base_dir()+"/"+path); + + } + + RES res=ResourceLoader::load(path,type); + + if (res.is_null()) { + WARN_PRINT(String("Couldn't load resource: "+path).utf8().get_data()); + } + r_v=res; + + } break; + default: { + + ERR_FAIL_V(ERR_FILE_CORRUPT); + } break; + } + + } break; + case VARIANT_INPUT_EVENT: { + + } break; + case VARIANT_DICTIONARY: { + + int len=f->get_32(); + Dictionary d; + for(int i=0;i<len;i++) { + int idx; + Variant key; + Error err = parse_property(key,idx); + ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT); + Variant value; + err = parse_property(value,idx); + ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT); + d[key]=value; + } + r_v=d; + } break; + case VARIANT_ARRAY: { + int len=f->get_32(); + Array a; + a.resize(len); + for(int i=0;i<len;i++) { + int idx; + Variant val; + Error err = parse_property(val,idx); + ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT); + a[i]=val; + } + r_v=a; + + } break; + case VARIANT_RAW_ARRAY: { + + uint32_t len = f->get_32(); + + DVector<uint8_t> array; + array.resize(len); + DVector<uint8_t>::Write w = array.write(); + f->get_buffer(w.ptr(),len); + _advance_padding(len); + w=DVector<uint8_t>::Write(); + r_v=array; + + } break; + case VARIANT_INT_ARRAY: { + + uint32_t len = f->get_32(); + + DVector<int> array; + array.resize(len); + DVector<int>::Write w = array.write(); + f->get_buffer((uint8_t*)w.ptr(),len*4); + w=DVector<int>::Write(); + r_v=array; + } break; + case VARIANT_REAL_ARRAY: { + + uint32_t len = f->get_32(); + + DVector<real_t> array; + array.resize(len); + DVector<real_t>::Write w = array.write(); + f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)); + w=DVector<real_t>::Write(); + r_v=array; + } break; + case VARIANT_STRING_ARRAY: { + + uint32_t len = f->get_32(); + DVector<String> array; + array.resize(len); + DVector<String>::Write w = array.write(); + for(int i=0;i<len;i++) + w[i]=get_unicode_string(); + w=DVector<String>::Write(); + r_v=array; + + + } break; + case VARIANT_VECTOR2_ARRAY: { + + uint32_t len = f->get_32(); + + DVector<Vector2> array; + array.resize(len); + DVector<Vector2>::Write w = array.write(); + if (sizeof(Vector2)==8) { + f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*2); + } else { + ERR_EXPLAIN("Vector2 size is NOT 8!"); + ERR_FAIL_V(ERR_UNAVAILABLE); + } + w=DVector<Vector2>::Write(); + r_v=array; + + } break; + case VARIANT_VECTOR3_ARRAY: { + + uint32_t len = f->get_32(); + + DVector<Vector3> array; + array.resize(len); + DVector<Vector3>::Write w = array.write(); + if (sizeof(Vector3)==12) { + f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*3); + } else { + ERR_EXPLAIN("Vector3 size is NOT 12!"); + ERR_FAIL_V(ERR_UNAVAILABLE); + } + w=DVector<Vector3>::Write(); + r_v=array; + + } break; + case VARIANT_COLOR_ARRAY: { + + uint32_t len = f->get_32(); + + DVector<Color> array; + array.resize(len); + DVector<Color>::Write w = array.write(); + if (sizeof(Color)==16) { + f->get_buffer((uint8_t*)w.ptr(),len*sizeof(real_t)*4); + } else { + ERR_EXPLAIN("Color size is NOT 16!"); + ERR_FAIL_V(ERR_UNAVAILABLE); + } + w=DVector<Color>::Write(); + r_v=array; + } break; + + default: { + ERR_FAIL_V(ERR_FILE_CORRUPT); + } break; + } + + + + return OK; //never reach anyway + +} + +Error ObjectFormatLoaderBinary::load(Object **p_object,Variant &p_meta) { + + + + while(true) { + + if (f->eof_reached()) { + ERR_EXPLAIN("Premature end of file at: "+local_path); + ERR_FAIL_V(ERR_FILE_CORRUPT); + } + + RES resource; + Object *obj=NULL; + bool meta=false; + + uint32_t section = f->get_32(); + + switch(section) { + + + case SECTION_RESOURCE: { + + print_bl("resource found"); + + size_t section_end = f->get_64(); + print_bl("section end: "+itos(section_end)); + String type = get_unicode_string(); + String path = get_unicode_string(); + print_bl("path: "+path); + + if (path.begins_with("local://")) { + //built-in resource (but really external) + path=path.replace("local://",local_path+"::"); + } + + if (ResourceCache::has(path)) { + f->seek(section_end); + continue; + } + + //load properties + + + obj = ObjectTypeDB::instance(type); + if (!obj) { + ERR_EXPLAIN("Object of unrecognized type '"+type+"' in file: "+type); + } + + ERR_FAIL_COND_V(!obj,ERR_FILE_CORRUPT); + + Resource *r = obj->cast_to<Resource>(); + if (!r) { + memdelete(obj); //bye + ERR_EXPLAIN("Object type in resource field not a resource, type is: "+obj->get_type()); + ERR_FAIL_COND_V(!obj->cast_to<Resource>(),ERR_FILE_CORRUPT); + } + + resource = RES( r ); + r->set_path(path); + } break; + case SECTION_META_OBJECT: + meta=true; + print_bl("meta found"); + + case SECTION_OBJECT: { + + uint64_t section_end = f->get_64(); + + if (!meta) { + print_bl("object"); + + String type = get_unicode_string(); + if (ObjectTypeDB::can_instance(type)) { + obj = ObjectTypeDB::instance(type); + if (!obj) { + ERR_EXPLAIN("Object of unrecognized type in file: "+type); + } + ERR_FAIL_COND_V(!obj,ERR_FILE_CORRUPT); + } else { + + f->seek(section_end); + return ERR_SKIP; + }; + + + } + + + } break; + case SECTION_END: { + + + return ERR_FILE_EOF; + } break; + + default: { + + ERR_EXPLAIN("Invalid Section ID '"+itos(section)+"' in file: "+local_path); + ERR_FAIL_V(ERR_FILE_CORRUPT); + + } + + } + + + //load properties + + while(true) { + + int name_idx; + Variant v; + Error err; + err = parse_property(v,name_idx); + + print_bl("prop idx "+itos(name_idx)+" value: "+String(v)); + + if (err==ERR_FILE_EOF) + break; + + if (err!=OK) { + ERR_EXPLAIN("File Corrupted"); + ERR_FAIL_COND_V(err!=OK,ERR_FILE_CORRUPT); + } + + + if (resource.is_null() && name_idx==0) { //0 is __bin_meta__ + + p_meta=v; + continue; + } else if (!obj) { + + ERR_EXPLAIN("Normal property found in meta object."); + ERR_FAIL_V(ERR_FILE_CORRUPT); + } + + Map<int,StringName>::Element *E=string_map.find(name_idx); + if (!E) { + ERR_EXPLAIN("Property ID has no matching name: "+itos(name_idx)); + ERR_FAIL_V(ERR_FILE_CORRUPT); + } + + obj->set(E->get(),v); + } + + if (!obj) { + *p_object=NULL; + return OK; // it was a meta object + } + + if (resource.is_null()) { + + //regular object + *p_object=obj; + return OK; + } else { + + resource_cache.push_back(resource); //keep it in mem until finished loading + } + + } +} + + +ObjectFormatLoaderBinary::~ObjectFormatLoaderBinary() { + + if (f) { + if (f->is_open()) + f->close(); + memdelete(f); + } +} + + +String ObjectFormatLoaderBinary::get_unicode_string() { + + uint32_t len = f->get_32(); + if (len>str_buf.size()) { + str_buf.resize(len); + } + f->get_buffer((uint8_t*)&str_buf[0],len); + String s; + s.parse_utf8(&str_buf[0]); + return s; +} + +ObjectFormatLoaderBinary::ObjectFormatLoaderBinary(FileAccess *p_f,bool p_endian_swap,bool p_use64) { + + f=p_f; + endian_swap=p_endian_swap; + use_real64=p_use64; + + //load string table + uint32_t string_table_size = f->get_32(); + print_bl("string table size: "+itos(string_table_size)); + for(int i=0;i<string_table_size;i++) { + + String str = get_unicode_string(); + print_bl("string "+itos(i)+" is: "+str); + string_map[i]=str; + } + + +} + +ObjectFormatLoaderBinary* ObjectFormatLoaderInstancerBinary::instance(const String& p_file,const String& p_magic) { + + FileAccess *f=FileAccess::open(p_file,FileAccess::READ); + ERR_FAIL_COND_V(!f,NULL); + + uint8_t header[4]; + f->get_buffer(header,4); + if (header[0]!='O' || header[1]!='B' || header[2]!='D' || header[3]!='B') { + + ERR_EXPLAIN("File not in valid binary format: "+p_file); + ERR_FAIL_V(NULL); + } + + uint32_t big_endian = f->get_32(); +#ifdef BIG_ENDIAN_ENABLED + bool endian_swap = !big_endian; +#else + bool endian_swap = big_endian; +#endif + + bool use_real64 = f->get_32(); + + f->set_endian_swap(big_endian!=0); //read big endian if saved as big endian + + uint32_t ver_major=f->get_32(); + uint32_t ver_minor=f->get_32(); + + print_bl("big endian: "+itos(big_endian)); + print_bl("endian swap: "+itos(endian_swap)); + print_bl("real64: "+itos(use_real64)); + print_bl("major: "+itos(ver_major)); + print_bl("minor: "+itos(ver_minor)); + + if (ver_major>VERSION_MAJOR || (ver_major==VERSION_MAJOR && ver_minor>VERSION_MINOR)) { + + f->close(); + memdelete(f); + ERR_EXPLAIN("File Format '"+itos(ver_major)+"."+itos(ver_minor)+"' is too new! Please upgrade to a a new engine version: "+p_file); + ERR_FAIL_V(NULL); + + } + + uint32_t magic_len = f->get_32(); + Vector<char> magic; + magic.resize(magic_len); + f->get_buffer((uint8_t*)&magic[0],magic_len); + String magic_str; + magic_str.parse_utf8(&magic[0]); + + print_bl("magic: "+magic_str); + if (magic_str!=p_magic) { + + f->close(); + memdelete(f); + ERR_EXPLAIN("File magic mismatch, found '"+magic_str+"' in : "+p_file); + ERR_FAIL_V(NULL); + } + + print_bl("skipping 32"); + for(int i=0;i<16;i++) + f->get_32(); //skip a few reserved fields + + if (f->eof_reached()) { + + f->close(); + memdelete(f); + ERR_EXPLAIN("Premature End Of File: "+p_file); + ERR_FAIL_V(NULL); + + } + + print_bl("creating loader"); + ObjectFormatLoaderBinary *loader = memnew( ObjectFormatLoaderBinary(f,endian_swap,use_real64) ); + loader->local_path=p_file; + + return loader; +} + +void ObjectFormatLoaderInstancerBinary::get_recognized_extensions(List<String> *p_extensions) const { + + p_extensions->push_back("bin"); +} + + +#endif |
