|
@@ -33,9 +33,7 @@
|
|
|
#include "core/config/project_settings.h"
|
|
|
#include "core/io/dir_access.h"
|
|
|
#include "core/io/missing_resource.h"
|
|
|
-#include "core/io/resource_format_binary.h"
|
|
|
#include "core/object/script_language.h"
|
|
|
-#include "core/version.h"
|
|
|
|
|
|
// Version 2: changed names for Basis, AABB, Vectors, etc.
|
|
|
// Version 3: new string ID for ext/subresources, breaks forward compat.
|
|
@@ -43,11 +41,6 @@
|
|
|
#define FORMAT_VERSION_COMPAT 3
|
|
|
#define FORMAT_VERSION 4
|
|
|
|
|
|
-#define BINARY_FORMAT_VERSION 4
|
|
|
-
|
|
|
-#include "core/io/dir_access.h"
|
|
|
-#include "core/version.h"
|
|
|
-
|
|
|
#define _printerr() ERR_PRINT(String(res_path + ":" + itos(lines) + " - Parse Error: " + error_text).utf8().get_data());
|
|
|
|
|
|
///
|
|
@@ -1126,298 +1119,6 @@ void ResourceLoaderText::open(Ref<FileAccess> p_f, bool p_skip_first_tag) {
|
|
|
rp.userdata = this;
|
|
|
}
|
|
|
|
|
|
-static void bs_save_unicode_string(Ref<FileAccess> p_f, const String &p_string, bool p_bit_on_len = false) {
|
|
|
- CharString utf8 = p_string.utf8();
|
|
|
- if (p_bit_on_len) {
|
|
|
- p_f->store_32((utf8.length() + 1) | 0x80000000);
|
|
|
- } else {
|
|
|
- p_f->store_32(utf8.length() + 1);
|
|
|
- }
|
|
|
- p_f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1);
|
|
|
-}
|
|
|
-
|
|
|
-Error ResourceLoaderText::save_as_binary(const String &p_path) {
|
|
|
- if (error) {
|
|
|
- return error;
|
|
|
- }
|
|
|
-
|
|
|
- Ref<FileAccess> wf = FileAccess::open(p_path, FileAccess::WRITE);
|
|
|
- if (wf.is_null()) {
|
|
|
- return ERR_CANT_OPEN;
|
|
|
- }
|
|
|
-
|
|
|
- //save header compressed
|
|
|
- static const uint8_t header[4] = { 'R', 'S', 'R', 'C' };
|
|
|
- wf->store_buffer(header, 4);
|
|
|
-
|
|
|
- wf->store_32(0); //endianness, little endian
|
|
|
- wf->store_32(0); //64 bits file, false for now
|
|
|
- wf->store_32(VERSION_MAJOR);
|
|
|
- wf->store_32(VERSION_MINOR);
|
|
|
- static const int save_format_version = BINARY_FORMAT_VERSION;
|
|
|
- wf->store_32(save_format_version);
|
|
|
-
|
|
|
- bs_save_unicode_string(wf, is_scene ? "PackedScene" : resource_type);
|
|
|
- wf->store_64(0); //offset to import metadata, this is no longer used
|
|
|
-
|
|
|
- wf->store_32(ResourceFormatSaverBinaryInstance::FORMAT_FLAG_NAMED_SCENE_IDS | ResourceFormatSaverBinaryInstance::FORMAT_FLAG_UIDS);
|
|
|
-
|
|
|
- wf->store_64(res_uid);
|
|
|
-
|
|
|
- for (int i = 0; i < ResourceFormatSaverBinaryInstance::RESERVED_FIELDS; i++) {
|
|
|
- wf->store_32(0); // reserved
|
|
|
- }
|
|
|
-
|
|
|
- wf->store_32(0); //string table size, will not be in use
|
|
|
- uint64_t ext_res_count_pos = wf->get_position();
|
|
|
-
|
|
|
- wf->store_32(0); //zero ext resources, still parsing them
|
|
|
-
|
|
|
- //go with external resources
|
|
|
-
|
|
|
- DummyReadData dummy_read;
|
|
|
- VariantParser::ResourceParser rp_new;
|
|
|
- rp_new.ext_func = _parse_ext_resource_dummys;
|
|
|
- rp_new.sub_func = _parse_sub_resource_dummys;
|
|
|
- rp_new.userdata = &dummy_read;
|
|
|
-
|
|
|
- while (next_tag.name == "ext_resource") {
|
|
|
- if (!next_tag.fields.has("path")) {
|
|
|
- error = ERR_FILE_CORRUPT;
|
|
|
- error_text = "Missing 'path' in external resource tag";
|
|
|
- _printerr();
|
|
|
- return error;
|
|
|
- }
|
|
|
-
|
|
|
- if (!next_tag.fields.has("type")) {
|
|
|
- error = ERR_FILE_CORRUPT;
|
|
|
- error_text = "Missing 'type' in external resource tag";
|
|
|
- _printerr();
|
|
|
- return error;
|
|
|
- }
|
|
|
-
|
|
|
- if (!next_tag.fields.has("id")) {
|
|
|
- error = ERR_FILE_CORRUPT;
|
|
|
- error_text = "Missing 'id' in external resource tag";
|
|
|
- _printerr();
|
|
|
- return error;
|
|
|
- }
|
|
|
-
|
|
|
- String path = next_tag.fields["path"];
|
|
|
- String type = next_tag.fields["type"];
|
|
|
- String id = next_tag.fields["id"];
|
|
|
- ResourceUID::ID uid = ResourceUID::INVALID_ID;
|
|
|
- if (next_tag.fields.has("uid")) {
|
|
|
- String uidt = next_tag.fields["uid"];
|
|
|
- uid = ResourceUID::get_singleton()->text_to_id(uidt);
|
|
|
- }
|
|
|
-
|
|
|
- bs_save_unicode_string(wf, type);
|
|
|
- bs_save_unicode_string(wf, path);
|
|
|
- wf->store_64(uid);
|
|
|
-
|
|
|
- int lindex = dummy_read.external_resources.size();
|
|
|
- Ref<DummyResource> dr;
|
|
|
- dr.instantiate();
|
|
|
- dr->set_path("res://dummy" + itos(lindex)); //anything is good to detect it for saving as external
|
|
|
- dummy_read.external_resources[dr] = lindex;
|
|
|
- dummy_read.rev_external_resources[id] = dr;
|
|
|
-
|
|
|
- error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp_new);
|
|
|
-
|
|
|
- if (error) {
|
|
|
- _printerr();
|
|
|
- return error;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // save external resource table
|
|
|
- wf->seek(ext_res_count_pos);
|
|
|
- wf->store_32(dummy_read.external_resources.size());
|
|
|
- wf->seek_end();
|
|
|
-
|
|
|
- //now, save resources to a separate file, for now
|
|
|
-
|
|
|
- uint64_t sub_res_count_pos = wf->get_position();
|
|
|
- wf->store_32(0); //zero sub resources, still parsing them
|
|
|
-
|
|
|
- String temp_file = p_path + ".temp";
|
|
|
- Vector<uint64_t> local_offsets;
|
|
|
- Vector<uint64_t> local_pointers_pos;
|
|
|
- {
|
|
|
- Ref<FileAccess> wf2 = FileAccess::open(temp_file, FileAccess::WRITE);
|
|
|
- if (wf2.is_null()) {
|
|
|
- return ERR_CANT_OPEN;
|
|
|
- }
|
|
|
-
|
|
|
- while (next_tag.name == "sub_resource" || next_tag.name == "resource") {
|
|
|
- String type;
|
|
|
- String id;
|
|
|
- bool main_res;
|
|
|
-
|
|
|
- if (next_tag.name == "sub_resource") {
|
|
|
- if (!next_tag.fields.has("type")) {
|
|
|
- error = ERR_FILE_CORRUPT;
|
|
|
- error_text = "Missing 'type' in external resource tag";
|
|
|
- _printerr();
|
|
|
- return error;
|
|
|
- }
|
|
|
-
|
|
|
- if (!next_tag.fields.has("id")) {
|
|
|
- error = ERR_FILE_CORRUPT;
|
|
|
- error_text = "Missing 'id' in external resource tag";
|
|
|
- _printerr();
|
|
|
- return error;
|
|
|
- }
|
|
|
-
|
|
|
- type = next_tag.fields["type"];
|
|
|
- id = next_tag.fields["id"];
|
|
|
- main_res = false;
|
|
|
-
|
|
|
- if (!dummy_read.resource_map.has(id)) {
|
|
|
- Ref<DummyResource> dr;
|
|
|
- dr.instantiate();
|
|
|
- dr->set_scene_unique_id(id);
|
|
|
- dummy_read.resource_map[id] = dr;
|
|
|
- uint32_t im_size = dummy_read.resource_index_map.size();
|
|
|
- dummy_read.resource_index_map.insert(dr, im_size);
|
|
|
- }
|
|
|
-
|
|
|
- } else {
|
|
|
- type = res_type;
|
|
|
- String uid_text = ResourceUID::get_singleton()->id_to_text(res_uid);
|
|
|
- id = type + "_" + uid_text.replace("uid://", "").replace("<invalid>", "0");
|
|
|
- main_res = true;
|
|
|
- }
|
|
|
-
|
|
|
- local_offsets.push_back(wf2->get_position());
|
|
|
-
|
|
|
- bs_save_unicode_string(wf, "local://" + id);
|
|
|
- local_pointers_pos.push_back(wf->get_position());
|
|
|
- wf->store_64(0); //temp local offset
|
|
|
-
|
|
|
- bs_save_unicode_string(wf2, type);
|
|
|
- uint64_t propcount_ofs = wf2->get_position();
|
|
|
- wf2->store_32(0);
|
|
|
-
|
|
|
- int prop_count = 0;
|
|
|
-
|
|
|
- while (true) {
|
|
|
- String assign;
|
|
|
- Variant value;
|
|
|
-
|
|
|
- error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp_new);
|
|
|
-
|
|
|
- if (error) {
|
|
|
- if (main_res && error == ERR_FILE_EOF) {
|
|
|
- next_tag.name = ""; //exit
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- _printerr();
|
|
|
- return error;
|
|
|
- }
|
|
|
-
|
|
|
- if (!assign.is_empty()) {
|
|
|
- HashMap<StringName, int> empty_string_map; //unused
|
|
|
- bs_save_unicode_string(wf2, assign, true);
|
|
|
- ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_index_map, dummy_read.external_resources, empty_string_map);
|
|
|
- prop_count++;
|
|
|
-
|
|
|
- } else if (!next_tag.name.is_empty()) {
|
|
|
- error = OK;
|
|
|
- break;
|
|
|
- } else {
|
|
|
- error = ERR_FILE_CORRUPT;
|
|
|
- error_text = "Premature end of file while parsing [sub_resource]";
|
|
|
- _printerr();
|
|
|
- return error;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- wf2->seek(propcount_ofs);
|
|
|
- wf2->store_32(prop_count);
|
|
|
- wf2->seek_end();
|
|
|
- }
|
|
|
-
|
|
|
- if (next_tag.name == "node") {
|
|
|
- // This is a node, must save one more!
|
|
|
-
|
|
|
- if (!is_scene) {
|
|
|
- error_text += "found the 'node' tag on a resource file!";
|
|
|
- _printerr();
|
|
|
- error = ERR_FILE_CORRUPT;
|
|
|
- return error;
|
|
|
- }
|
|
|
-
|
|
|
- Ref<PackedScene> packed_scene = _parse_node_tag(rp_new);
|
|
|
-
|
|
|
- if (!packed_scene.is_valid()) {
|
|
|
- return error;
|
|
|
- }
|
|
|
-
|
|
|
- error = OK;
|
|
|
- //get it here
|
|
|
- List<PropertyInfo> props;
|
|
|
- packed_scene->get_property_list(&props);
|
|
|
-
|
|
|
- String id = "PackedScene_" + ResourceUID::get_singleton()->id_to_text(res_uid).replace("uid://", "").replace("<invalid>", "0");
|
|
|
- bs_save_unicode_string(wf, "local://" + id);
|
|
|
- local_pointers_pos.push_back(wf->get_position());
|
|
|
- wf->store_64(0); //temp local offset
|
|
|
-
|
|
|
- local_offsets.push_back(wf2->get_position());
|
|
|
- bs_save_unicode_string(wf2, "PackedScene");
|
|
|
- uint64_t propcount_ofs = wf2->get_position();
|
|
|
- wf2->store_32(0);
|
|
|
-
|
|
|
- int prop_count = 0;
|
|
|
-
|
|
|
- for (const PropertyInfo &E : props) {
|
|
|
- if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- String name = E.name;
|
|
|
- Variant value = packed_scene->get(name);
|
|
|
-
|
|
|
- HashMap<StringName, int> empty_string_map; //unused
|
|
|
- bs_save_unicode_string(wf2, name, true);
|
|
|
- ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_index_map, dummy_read.external_resources, empty_string_map);
|
|
|
- prop_count++;
|
|
|
- }
|
|
|
-
|
|
|
- wf2->seek(propcount_ofs);
|
|
|
- wf2->store_32(prop_count);
|
|
|
- wf2->seek_end();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- uint64_t offset_from = wf->get_position();
|
|
|
- wf->seek(sub_res_count_pos); //plus one because the saved one
|
|
|
- wf->store_32(local_offsets.size());
|
|
|
-
|
|
|
- for (int i = 0; i < local_offsets.size(); i++) {
|
|
|
- wf->seek(local_pointers_pos[i]);
|
|
|
- wf->store_64(local_offsets[i] + offset_from);
|
|
|
- }
|
|
|
-
|
|
|
- wf->seek_end();
|
|
|
-
|
|
|
- Vector<uint8_t> data = FileAccess::get_file_as_bytes(temp_file);
|
|
|
- wf->store_buffer(data.ptr(), data.size());
|
|
|
- {
|
|
|
- Ref<DirAccess> dar = DirAccess::open(temp_file.get_base_dir());
|
|
|
- ERR_FAIL_COND_V(dar.is_null(), FAILED);
|
|
|
-
|
|
|
- dar->remove(temp_file);
|
|
|
- }
|
|
|
-
|
|
|
- wf->store_buffer((const uint8_t *)"RSRC", 4); //magic at end
|
|
|
-
|
|
|
- return OK;
|
|
|
-}
|
|
|
-
|
|
|
Error ResourceLoaderText::get_classes_used(HashSet<StringName> *r_classes) {
|
|
|
if (error) {
|
|
|
return error;
|
|
@@ -1834,29 +1535,6 @@ Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const
|
|
|
|
|
|
ResourceFormatLoaderText *ResourceFormatLoaderText::singleton = nullptr;
|
|
|
|
|
|
-Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path, const String &p_dst_path) {
|
|
|
- Error err;
|
|
|
- Ref<FileAccess> f = FileAccess::open(p_src_path, FileAccess::READ, &err);
|
|
|
-
|
|
|
- ERR_FAIL_COND_V_MSG(err != OK, ERR_CANT_OPEN, "Cannot open file '" + p_src_path + "'.");
|
|
|
-
|
|
|
- ResourceLoaderText loader;
|
|
|
- const String &path = p_src_path;
|
|
|
- loader.local_path = ProjectSettings::get_singleton()->localize_path(path);
|
|
|
- loader.res_path = loader.local_path;
|
|
|
- loader.open(f);
|
|
|
- return loader.save_as_binary(p_dst_path);
|
|
|
-}
|
|
|
-
|
|
|
-/*****************************************************************************************************/
|
|
|
-/*****************************************************************************************************/
|
|
|
-/*****************************************************************************************************/
|
|
|
-/*****************************************************************************************************/
|
|
|
-/*****************************************************************************************************/
|
|
|
-/*****************************************************************************************************/
|
|
|
-/*****************************************************************************************************/
|
|
|
-/*****************************************************************************************************/
|
|
|
-/*****************************************************************************************************/
|
|
|
/*****************************************************************************************************/
|
|
|
|
|
|
String ResourceFormatSaverTextInstance::_write_resources(void *ud, const Ref<Resource> &p_resource) {
|