2014-02-10 02:10:30 +01:00
/*************************************************************************/
/* resource_format_binary.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 14:16:55 +02:00
/* https://godotengine.org */
2014-02-10 02:10:30 +01:00
/*************************************************************************/
2020-01-01 11:16:22 +01:00
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
2014-02-10 02:10:30 +01:00
/* */
/* 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. */
/*************************************************************************/
2018-01-05 00:50:27 +01:00
2014-02-10 02:10:30 +01:00
# include "resource_format_binary.h"
2017-08-26 17:46:49 +02:00
# include "core/image.h"
# include "core/io/file_access_compressed.h"
# include "core/io/marshalls.h"
# include "core/os/dir_access.h"
# include "core/project_settings.h"
# include "core/version.h"
2014-02-10 02:10:30 +01:00
//#define print_bl(m_what) print_line(m_what)
2017-09-02 22:32:31 +02:00
# define print_bl(m_what) (void)(m_what)
2014-02-10 02:10:30 +01:00
enum {
//numbering must be different from variant, in case new variant types are added (variant must be always contiguous for jumptable optimization)
2017-03-05 16:44:50 +01:00
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 ,
2017-11-17 03:09:00 +01:00
VARIANT_AABB = 15 ,
2017-03-05 16:44:50 +01:00
VARIANT_MATRIX3 = 16 ,
VARIANT_TRANSFORM = 17 ,
VARIANT_MATRIX32 = 18 ,
VARIANT_COLOR = 20 ,
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 ,
VARIANT_INT64 = 40 ,
VARIANT_DOUBLE = 41 ,
2017-07-15 06:23:10 +02:00
# ifndef DISABLE_DEPRECATED
VARIANT_IMAGE = 21 , // - no longer variant type
IMAGE_ENCODING_EMPTY = 0 ,
IMAGE_ENCODING_RAW = 1 ,
IMAGE_ENCODING_LOSSLESS = 2 ,
IMAGE_ENCODING_LOSSY = 3 ,
# endif
2017-03-05 16:44:50 +01:00
OBJECT_EMPTY = 0 ,
OBJECT_EXTERNAL_RESOURCE = 1 ,
OBJECT_INTERNAL_RESOURCE = 2 ,
OBJECT_EXTERNAL_RESOURCE_INDEX = 3 ,
2017-01-25 18:30:40 +01:00
//version 2: added 64 bits support for float and int
2017-11-22 12:34:43 +01:00
//version 3: changed nodepath encoding
FORMAT_VERSION = 3 ,
FORMAT_VERSION_CAN_RENAME_DEPS = 1 ,
FORMAT_VERSION_NO_NODEPATH_PROPERTY = 3 ,
2014-02-10 02:10:30 +01:00
} ;
void ResourceInteractiveLoaderBinary : : _advance_padding ( uint32_t p_len ) {
2017-03-05 16:44:50 +01:00
uint32_t extra = 4 - ( p_len % 4 ) ;
if ( extra < 4 ) {
for ( uint32_t i = 0 ; i < extra ; i + + )
2014-02-10 02:10:30 +01:00
f - > get_8 ( ) ; //pad to 32
}
}
2017-02-15 12:29:46 +01:00
StringName ResourceInteractiveLoaderBinary : : _get_string ( ) {
uint32_t id = f - > get_32 ( ) ;
2017-03-05 16:44:50 +01:00
if ( id & 0x80000000 ) {
2017-12-15 13:04:57 +01:00
uint32_t len = id & 0x7FFFFFFF ;
2019-02-21 20:57:39 +01:00
if ( ( int ) len > str_buf . size ( ) ) {
2017-02-15 12:29:46 +01:00
str_buf . resize ( len ) ;
}
2017-03-05 16:44:50 +01:00
if ( len = = 0 )
2017-02-15 12:29:46 +01:00
return StringName ( ) ;
2017-03-05 16:44:50 +01:00
f - > get_buffer ( ( uint8_t * ) & str_buf [ 0 ] , len ) ;
2017-02-15 12:29:46 +01:00
String s ;
s . parse_utf8 ( & str_buf [ 0 ] ) ;
return s ;
}
return string_map [ id ] ;
}
2017-03-05 16:44:50 +01:00
Error ResourceInteractiveLoaderBinary : : parse_variant ( Variant & r_v ) {
2014-02-10 02:10:30 +01:00
uint32_t type = f - > get_32 ( ) ;
2017-03-05 16:44:50 +01:00
print_bl ( " find property of type: " + itos ( type ) ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
switch ( type ) {
2014-02-10 02:10:30 +01:00
case VARIANT_NIL : {
2017-03-05 16:44:50 +01:00
r_v = Variant ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_BOOL : {
2017-03-05 16:44:50 +01:00
r_v = bool ( f - > get_32 ( ) ) ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_INT : {
2017-03-05 16:44:50 +01:00
r_v = int ( f - > get_32 ( ) ) ;
2014-02-10 02:10:30 +01:00
} break ;
2017-01-09 00:58:39 +01:00
case VARIANT_INT64 : {
2017-03-05 16:44:50 +01:00
r_v = int64_t ( f - > get_64 ( ) ) ;
2017-01-09 00:58:39 +01:00
} break ;
2014-02-10 02:10:30 +01:00
case VARIANT_REAL : {
2017-03-05 16:44:50 +01:00
r_v = f - > get_real ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
2017-01-09 00:58:39 +01:00
case VARIANT_DOUBLE : {
2017-03-05 16:44:50 +01:00
r_v = f - > get_double ( ) ;
2017-01-09 00:58:39 +01:00
} break ;
2014-02-10 02:10:30 +01:00
case VARIANT_STRING : {
2017-03-05 16:44:50 +01:00
r_v = get_unicode_string ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_VECTOR2 : {
Vector2 v ;
2017-03-05 16:44:50 +01:00
v . x = f - > get_real ( ) ;
v . y = f - > get_real ( ) ;
r_v = v ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_RECT2 : {
Rect2 v ;
2017-06-04 00:25:13 +02:00
v . position . x = f - > get_real ( ) ;
v . position . y = f - > get_real ( ) ;
2017-03-05 16:44:50 +01:00
v . size . x = f - > get_real ( ) ;
v . size . y = f - > get_real ( ) ;
r_v = v ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_VECTOR3 : {
Vector3 v ;
2017-03-05 16:44:50 +01:00
v . x = f - > get_real ( ) ;
v . y = f - > get_real ( ) ;
v . z = f - > get_real ( ) ;
r_v = v ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_PLANE : {
Plane v ;
2017-03-05 16:44:50 +01:00
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 ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_QUAT : {
Quat v ;
2017-03-05 16:44:50 +01:00
v . x = f - > get_real ( ) ;
v . y = f - > get_real ( ) ;
v . z = f - > get_real ( ) ;
v . w = f - > get_real ( ) ;
r_v = v ;
2014-02-10 02:10:30 +01:00
} break ;
2017-11-17 03:09:00 +01:00
case VARIANT_AABB : {
2014-02-10 02:10:30 +01:00
2017-11-17 03:09:00 +01:00
AABB v ;
2017-06-06 20:33:51 +02:00
v . position . x = f - > get_real ( ) ;
v . position . y = f - > get_real ( ) ;
v . position . z = f - > get_real ( ) ;
2017-03-05 16:44:50 +01:00
v . size . x = f - > get_real ( ) ;
v . size . y = f - > get_real ( ) ;
v . size . z = f - > get_real ( ) ;
r_v = v ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_MATRIX32 : {
2017-01-11 04:52:51 +01:00
Transform2D v ;
2017-03-05 16:44:50 +01:00
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 ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_MATRIX3 : {
2017-01-11 04:52:51 +01:00
Basis v ;
2017-03-05 16:44:50 +01:00
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 ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_TRANSFORM : {
Transform v ;
2017-03-05 16:44:50 +01:00
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 ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_COLOR : {
Color v ;
2017-03-05 16:44:50 +01:00
v . r = f - > get_real ( ) ;
v . g = f - > get_real ( ) ;
v . b = f - > get_real ( ) ;
v . a = f - > get_real ( ) ;
r_v = v ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_NODE_PATH : {
Vector < StringName > names ;
Vector < StringName > subnames ;
bool absolute ;
int name_count = f - > get_16 ( ) ;
uint32_t subname_count = f - > get_16 ( ) ;
2017-03-05 16:44:50 +01:00
absolute = subname_count & 0x8000 ;
subname_count & = 0x7FFF ;
2017-11-22 12:34:43 +01:00
if ( ver_format < FORMAT_VERSION_NO_NODEPATH_PROPERTY ) {
subname_count + = 1 ; // has a property field, so we should count it as well
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < name_count ; i + + )
2017-02-15 12:29:46 +01:00
names . push_back ( _get_string ( ) ) ;
2017-03-05 16:44:50 +01:00
for ( uint32_t i = 0 ; i < subname_count ; i + + )
2017-02-15 12:29:46 +01:00
subnames . push_back ( _get_string ( ) ) ;
2014-02-10 02:10:30 +01:00
2017-05-30 22:20:15 +02:00
NodePath np = NodePath ( names , subnames , absolute ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
r_v = np ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_RID : {
2017-03-05 16:44:50 +01:00
r_v = f - > get_32 ( ) ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_OBJECT : {
2019-02-12 21:10:08 +01:00
uint32_t objtype = f - > get_32 ( ) ;
2014-02-10 02:10:30 +01:00
2019-02-12 21:10:08 +01:00
switch ( objtype ) {
2014-02-10 02:10:30 +01:00
case OBJECT_EMPTY : {
//do none
} break ;
case OBJECT_INTERNAL_RESOURCE : {
2017-03-05 16:44:50 +01:00
uint32_t index = f - > get_32 ( ) ;
String path = res_path + " :: " + itos ( index ) ;
2014-02-10 02:10:30 +01:00
RES res = ResourceLoader : : load ( path ) ;
if ( res . is_null ( ) ) {
2017-03-05 16:44:50 +01:00
WARN_PRINT ( String ( " Couldn't load resource: " + path ) . utf8 ( ) . get_data ( ) ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
r_v = res ;
2014-02-10 02:10:30 +01:00
} break ;
case OBJECT_EXTERNAL_RESOURCE : {
2015-08-24 01:15:56 +02:00
//old file format, still around for compatibility
2014-02-10 02:10:30 +01:00
2019-02-12 21:10:08 +01:00
String exttype = get_unicode_string ( ) ;
2014-02-10 02:10:30 +01:00
String path = get_unicode_string ( ) ;
2017-03-05 16:44:50 +01:00
if ( path . find ( " :// " ) = = - 1 & & path . is_rel_path ( ) ) {
2014-02-10 02:10:30 +01:00
// path is relative to file being loaded, so convert to a resource path
2017-07-19 22:00:46 +02:00
path = ProjectSettings : : get_singleton ( ) - > localize_path ( res_path . get_base_dir ( ) . plus_file ( path ) ) ;
2014-02-10 02:10:30 +01:00
}
2015-08-24 01:15:56 +02:00
if ( remaps . find ( path ) ) {
2017-03-05 16:44:50 +01:00
path = remaps [ path ] ;
2015-08-24 01:15:56 +02:00
}
2019-02-12 21:10:08 +01:00
RES res = ResourceLoader : : load ( path , exttype ) ;
2014-02-10 02:10:30 +01:00
if ( res . is_null ( ) ) {
2017-03-05 16:44:50 +01:00
WARN_PRINT ( String ( " Couldn't load resource: " + path ) . utf8 ( ) . get_data ( ) ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
r_v = res ;
2014-02-10 02:10:30 +01:00
2015-08-24 01:15:56 +02:00
} break ;
case OBJECT_EXTERNAL_RESOURCE_INDEX : {
//new file format, just refers to an index in the external list
2017-08-31 23:30:35 +02:00
int erindex = f - > get_32 ( ) ;
2015-08-24 01:15:56 +02:00
2017-08-31 23:30:35 +02:00
if ( erindex < 0 | | erindex > = external_resources . size ( ) ) {
2019-01-26 22:35:31 +01:00
WARN_PRINT ( " Broken external resource! (index out of size) " ) ;
2017-03-05 16:44:50 +01:00
r_v = Variant ( ) ;
2015-08-24 01:15:56 +02:00
} else {
2019-02-12 21:10:08 +01:00
String exttype = external_resources [ erindex ] . type ;
2015-08-24 01:15:56 +02:00
String path = external_resources [ erindex ] . path ;
2017-03-05 16:44:50 +01:00
if ( path . find ( " :// " ) = = - 1 & & path . is_rel_path ( ) ) {
2015-08-24 01:15:56 +02:00
// path is relative to file being loaded, so convert to a resource path
2017-07-19 22:00:46 +02:00
path = ProjectSettings : : get_singleton ( ) - > localize_path ( res_path . get_base_dir ( ) . plus_file ( path ) ) ;
2015-08-24 01:15:56 +02:00
}
2019-02-12 21:10:08 +01:00
RES res = ResourceLoader : : load ( path , exttype ) ;
2015-08-24 01:15:56 +02:00
if ( res . is_null ( ) ) {
2017-03-05 16:44:50 +01:00
WARN_PRINT ( String ( " Couldn't load resource: " + path ) . utf8 ( ) . get_data ( ) ) ;
2015-08-24 01:15:56 +02:00
}
2017-03-05 16:44:50 +01:00
r_v = res ;
2015-08-24 01:15:56 +02:00
}
2014-02-10 02:10:30 +01:00
} break ;
default : {
ERR_FAIL_V ( ERR_FILE_CORRUPT ) ;
} break ;
}
} break ;
case VARIANT_DICTIONARY : {
2017-03-05 16:44:50 +01:00
uint32_t len = f - > get_32 ( ) ;
2017-01-11 12:53:31 +01:00
Dictionary d ; //last bit means shared
2017-03-05 16:44:50 +01:00
len & = 0x7FFFFFFF ;
for ( uint32_t i = 0 ; i < len ; i + + ) {
2014-02-10 02:10:30 +01:00
Variant key ;
Error err = parse_variant ( key ) ;
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( err , ERR_FILE_CORRUPT , " Error when trying to parse Variant. " ) ;
2014-02-10 02:10:30 +01:00
Variant value ;
err = parse_variant ( value ) ;
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( err , ERR_FILE_CORRUPT , " Error when trying to parse Variant. " ) ;
2017-03-05 16:44:50 +01:00
d [ key ] = value ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
r_v = d ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_ARRAY : {
2017-03-05 16:44:50 +01:00
uint32_t len = f - > get_32 ( ) ;
2017-01-11 12:53:31 +01:00
Array a ; //last bit means shared
2017-03-05 16:44:50 +01:00
len & = 0x7FFFFFFF ;
2014-02-10 02:10:30 +01:00
a . resize ( len ) ;
2017-03-05 16:44:50 +01:00
for ( uint32_t i = 0 ; i < len ; i + + ) {
2014-02-10 02:10:30 +01:00
Variant val ;
Error err = parse_variant ( val ) ;
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( err , ERR_FILE_CORRUPT , " Error when trying to parse Variant. " ) ;
2017-03-05 16:44:50 +01:00
a [ i ] = val ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
r_v = a ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_RAW_ARRAY : {
uint32_t len = f - > get_32 ( ) ;
2017-01-07 22:25:37 +01:00
PoolVector < uint8_t > array ;
2014-02-10 02:10:30 +01:00
array . resize ( len ) ;
2017-01-07 22:25:37 +01:00
PoolVector < uint8_t > : : Write w = array . write ( ) ;
2017-03-05 16:44:50 +01:00
f - > get_buffer ( w . ptr ( ) , len ) ;
2014-02-10 02:10:30 +01:00
_advance_padding ( len ) ;
2019-07-05 19:08:43 +02:00
w . release ( ) ;
2017-03-05 16:44:50 +01:00
r_v = array ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_INT_ARRAY : {
uint32_t len = f - > get_32 ( ) ;
2017-01-07 22:25:37 +01:00
PoolVector < int > array ;
2014-02-10 02:10:30 +01:00
array . resize ( len ) ;
2017-01-07 22:25:37 +01:00
PoolVector < int > : : Write w = array . write ( ) ;
2017-03-05 16:44:50 +01:00
f - > get_buffer ( ( uint8_t * ) w . ptr ( ) , len * 4 ) ;
2014-02-10 02:10:30 +01:00
# ifdef BIG_ENDIAN_ENABLED
{
2017-03-05 16:44:50 +01:00
uint32_t * ptr = ( uint32_t * ) w . ptr ( ) ;
for ( int i = 0 ; i < len ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ptr [ i ] = BSWAP32 ( ptr [ i ] ) ;
2014-02-10 02:10:30 +01:00
}
}
# endif
2019-07-05 19:08:43 +02:00
w . release ( ) ;
2017-03-05 16:44:50 +01:00
r_v = array ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_REAL_ARRAY : {
uint32_t len = f - > get_32 ( ) ;
2017-01-07 22:25:37 +01:00
PoolVector < real_t > array ;
2014-02-10 02:10:30 +01:00
array . resize ( len ) ;
2017-01-07 22:25:37 +01:00
PoolVector < real_t > : : Write w = array . write ( ) ;
2017-03-05 16:44:50 +01:00
f - > get_buffer ( ( uint8_t * ) w . ptr ( ) , len * sizeof ( real_t ) ) ;
2014-02-10 02:10:30 +01:00
# ifdef BIG_ENDIAN_ENABLED
{
2017-03-05 16:44:50 +01:00
uint32_t * ptr = ( uint32_t * ) w . ptr ( ) ;
for ( int i = 0 ; i < len ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ptr [ i ] = BSWAP32 ( ptr [ i ] ) ;
2014-02-10 02:10:30 +01:00
}
}
# endif
2019-07-05 19:08:43 +02:00
w . release ( ) ;
2017-03-05 16:44:50 +01:00
r_v = array ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_STRING_ARRAY : {
uint32_t len = f - > get_32 ( ) ;
2017-01-07 22:25:37 +01:00
PoolVector < String > array ;
2014-02-10 02:10:30 +01:00
array . resize ( len ) ;
2017-01-07 22:25:37 +01:00
PoolVector < String > : : Write w = array . write ( ) ;
2017-03-05 16:44:50 +01:00
for ( uint32_t i = 0 ; i < len ; i + + )
w [ i ] = get_unicode_string ( ) ;
2019-07-05 19:08:43 +02:00
w . release ( ) ;
2017-03-05 16:44:50 +01:00
r_v = array ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_VECTOR2_ARRAY : {
uint32_t len = f - > get_32 ( ) ;
2017-01-07 22:25:37 +01:00
PoolVector < Vector2 > array ;
2014-02-10 02:10:30 +01:00
array . resize ( len ) ;
2017-01-07 22:25:37 +01:00
PoolVector < Vector2 > : : Write w = array . write ( ) ;
2017-03-05 16:44:50 +01:00
if ( sizeof ( Vector2 ) = = 8 ) {
f - > get_buffer ( ( uint8_t * ) w . ptr ( ) , len * sizeof ( real_t ) * 2 ) ;
2014-02-10 02:10:30 +01:00
# ifdef BIG_ENDIAN_ENABLED
2017-03-05 16:44:50 +01:00
{
uint32_t * ptr = ( uint32_t * ) w . ptr ( ) ;
for ( int i = 0 ; i < len * 2 ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ptr [ i ] = BSWAP32 ( ptr [ i ] ) ;
}
2014-02-10 02:10:30 +01:00
}
# endif
} else {
2019-08-15 04:57:49 +02:00
ERR_FAIL_V_MSG ( ERR_UNAVAILABLE , " Vector2 size is NOT 8! " ) ;
2014-02-10 02:10:30 +01:00
}
2019-07-05 19:08:43 +02:00
w . release ( ) ;
2017-03-05 16:44:50 +01:00
r_v = array ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_VECTOR3_ARRAY : {
uint32_t len = f - > get_32 ( ) ;
2017-01-07 22:25:37 +01:00
PoolVector < Vector3 > array ;
2014-02-10 02:10:30 +01:00
array . resize ( len ) ;
2017-01-07 22:25:37 +01:00
PoolVector < Vector3 > : : Write w = array . write ( ) ;
2017-03-05 16:44:50 +01:00
if ( sizeof ( Vector3 ) = = 12 ) {
f - > get_buffer ( ( uint8_t * ) w . ptr ( ) , len * sizeof ( real_t ) * 3 ) ;
2014-02-10 02:10:30 +01:00
# ifdef BIG_ENDIAN_ENABLED
{
2017-03-05 16:44:50 +01:00
uint32_t * ptr = ( uint32_t * ) w . ptr ( ) ;
for ( int i = 0 ; i < len * 3 ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ptr [ i ] = BSWAP32 ( ptr [ i ] ) ;
2014-02-10 02:10:30 +01:00
}
}
# endif
} else {
2019-08-15 04:57:49 +02:00
ERR_FAIL_V_MSG ( ERR_UNAVAILABLE , " Vector3 size is NOT 12! " ) ;
2014-02-10 02:10:30 +01:00
}
2019-07-05 19:08:43 +02:00
w . release ( ) ;
2017-03-05 16:44:50 +01:00
r_v = array ;
2014-02-10 02:10:30 +01:00
} break ;
case VARIANT_COLOR_ARRAY : {
uint32_t len = f - > get_32 ( ) ;
2017-01-07 22:25:37 +01:00
PoolVector < Color > array ;
2014-02-10 02:10:30 +01:00
array . resize ( len ) ;
2017-01-07 22:25:37 +01:00
PoolVector < Color > : : Write w = array . write ( ) ;
2017-03-05 16:44:50 +01:00
if ( sizeof ( Color ) = = 16 ) {
f - > get_buffer ( ( uint8_t * ) w . ptr ( ) , len * sizeof ( real_t ) * 4 ) ;
2014-02-10 02:10:30 +01:00
# ifdef BIG_ENDIAN_ENABLED
2017-03-05 16:44:50 +01:00
{
uint32_t * ptr = ( uint32_t * ) w . ptr ( ) ;
for ( int i = 0 ; i < len * 4 ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ptr [ i ] = BSWAP32 ( ptr [ i ] ) ;
}
2014-02-10 02:10:30 +01:00
}
# endif
} else {
2019-08-15 04:57:49 +02:00
ERR_FAIL_V_MSG ( ERR_UNAVAILABLE , " Color size is NOT 16! " ) ;
2014-02-10 02:10:30 +01:00
}
2019-07-05 19:08:43 +02:00
w . release ( ) ;
2017-03-05 16:44:50 +01:00
r_v = array ;
2014-02-10 02:10:30 +01:00
} break ;
2017-07-15 06:23:10 +02:00
# ifndef DISABLE_DEPRECATED
case VARIANT_IMAGE : {
uint32_t encoding = f - > get_32 ( ) ;
if ( encoding = = IMAGE_ENCODING_EMPTY ) {
r_v = Ref < Image > ( ) ;
break ;
} else if ( encoding = = IMAGE_ENCODING_RAW ) {
uint32_t width = f - > get_32 ( ) ;
uint32_t height = f - > get_32 ( ) ;
uint32_t mipmaps = f - > get_32 ( ) ;
uint32_t format = f - > get_32 ( ) ;
const uint32_t format_version_shift = 24 ;
const uint32_t format_version_mask = format_version_shift - 1 ;
uint32_t format_version = format > > format_version_shift ;
const uint32_t current_version = 0 ;
if ( format_version > current_version ) {
2019-08-15 04:57:49 +02:00
ERR_PRINT ( " Format version for encoded binary image is too new. " ) ;
2017-07-15 06:23:10 +02:00
return ERR_PARSE_ERROR ;
}
Image : : Format fmt = Image : : Format ( format & format_version_mask ) ; //if format changes, we can add a compatibility bit on top
uint32_t datalen = f - > get_32 ( ) ;
PoolVector < uint8_t > imgdata ;
imgdata . resize ( datalen ) ;
PoolVector < uint8_t > : : Write w = imgdata . write ( ) ;
f - > get_buffer ( w . ptr ( ) , datalen ) ;
_advance_padding ( datalen ) ;
2019-07-05 19:08:43 +02:00
w . release ( ) ;
2017-07-15 06:23:10 +02:00
Ref < Image > image ;
image . instance ( ) ;
image - > create ( width , height , mipmaps , fmt , imgdata ) ;
r_v = image ;
} else {
//compressed
PoolVector < uint8_t > data ;
data . resize ( f - > get_32 ( ) ) ;
PoolVector < uint8_t > : : Write w = data . write ( ) ;
f - > get_buffer ( w . ptr ( ) , data . size ( ) ) ;
2019-07-05 19:08:43 +02:00
w . release ( ) ;
2017-07-15 06:23:10 +02:00
Ref < Image > image ;
2014-02-10 02:10:30 +01:00
2017-07-15 06:23:10 +02:00
if ( encoding = = IMAGE_ENCODING_LOSSY & & Image : : lossy_unpacker ) {
image = Image : : lossy_unpacker ( data ) ;
} else if ( encoding = = IMAGE_ENCODING_LOSSLESS & & Image : : lossless_unpacker ) {
image = Image : : lossless_unpacker ( data ) ;
}
_advance_padding ( data . size ( ) ) ;
r_v = image ;
}
} break ;
# endif
2014-02-10 02:10:30 +01:00
default : {
ERR_FAIL_V ( ERR_FILE_CORRUPT ) ;
} break ;
}
return OK ; //never reach anyway
}
2017-03-05 16:44:50 +01:00
void ResourceInteractiveLoaderBinary : : set_local_path ( const String & p_local_path ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
res_path = p_local_path ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
Ref < Resource > ResourceInteractiveLoaderBinary : : get_resource ( ) {
2014-02-10 02:10:30 +01:00
return resource ;
}
2017-03-05 16:44:50 +01:00
Error ResourceInteractiveLoaderBinary : : poll ( ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( error ! = OK )
2014-02-10 02:10:30 +01:00
return error ;
int s = stage ;
2017-03-05 16:44:50 +01:00
if ( s < external_resources . size ( ) ) {
2014-02-10 02:10:30 +01:00
2015-08-24 01:15:56 +02:00
String path = external_resources [ s ] . path ;
2017-02-15 12:29:46 +01:00
2015-08-24 01:15:56 +02:00
if ( remaps . has ( path ) ) {
2017-03-05 16:44:50 +01:00
path = remaps [ path ] ;
2015-08-24 01:15:56 +02:00
}
2017-03-05 16:44:50 +01:00
RES res = ResourceLoader : : load ( path , external_resources [ s ] . type ) ;
2014-02-10 02:10:30 +01:00
if ( res . is_null ( ) ) {
if ( ! ResourceLoader : : get_abort_on_missing_resources ( ) ) {
2017-03-05 16:44:50 +01:00
ResourceLoader : : notify_dependency_error ( local_path , path , external_resources [ s ] . type ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-03-05 16:44:50 +01:00
error = ERR_FILE_MISSING_DEPENDENCIES ;
2019-08-15 04:57:49 +02:00
ERR_FAIL_V_MSG ( error , " Can't load dependency: " + path + " . " ) ;
2014-02-10 02:10:30 +01:00
}
} else {
resource_cache . push_back ( res ) ;
}
stage + + ;
2014-03-14 02:57:24 +01:00
return error ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
s - = external_resources . size ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( s > = internal_resources . size ( ) ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
error = ERR_BUG ;
ERR_FAIL_COND_V ( s > = internal_resources . size ( ) , error ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
bool main = s = = ( internal_resources . size ( ) - 1 ) ;
2014-02-10 02:10:30 +01:00
//maybe it is loaded already
String path ;
2017-03-05 16:44:50 +01:00
int subindex = 0 ;
2014-02-10 02:10:30 +01:00
if ( ! main ) {
2017-03-05 16:44:50 +01:00
path = internal_resources [ s ] . path ;
2015-06-22 05:03:19 +02:00
if ( path . begins_with ( " local:// " ) ) {
2017-03-05 16:44:50 +01:00
path = path . replace_first ( " local:// " , " " ) ;
2015-06-22 05:03:19 +02:00
subindex = path . to_int ( ) ;
2017-03-05 16:44:50 +01:00
path = res_path + " :: " + path ;
2015-06-22 05:03:19 +02:00
}
2014-02-10 02:10:30 +01:00
if ( ResourceCache : : has ( path ) ) {
//already loaded, don't do anything
stage + + ;
2017-03-05 16:44:50 +01:00
error = OK ;
2014-02-10 02:10:30 +01:00
return error ;
}
} else {
2016-01-14 15:06:20 +01:00
if ( ! ResourceCache : : has ( res_path ) )
2017-03-05 16:44:50 +01:00
path = res_path ;
2014-02-10 02:10:30 +01:00
}
uint64_t offset = internal_resources [ s ] . offset ;
f - > seek ( offset ) ;
String t = get_unicode_string ( ) ;
2017-01-03 03:03:46 +01:00
Object * obj = ClassDB : : instance ( t ) ;
2014-02-10 02:10:30 +01:00
if ( ! obj ) {
2017-03-05 16:44:50 +01:00
error = ERR_FILE_CORRUPT ;
2019-08-15 04:57:49 +02:00
ERR_FAIL_V_MSG ( ERR_FILE_CORRUPT , local_path + " :Resource of unrecognized type in file: " + t + " . " ) ;
2014-02-10 02:10:30 +01:00
}
2017-08-24 22:58:51 +02:00
Resource * r = Object : : cast_to < Resource > ( obj ) ;
2014-02-10 02:10:30 +01:00
if ( ! r ) {
2019-08-15 04:57:49 +02:00
String obj_class = obj - > get_class ( ) ;
2017-03-05 16:44:50 +01:00
error = ERR_FILE_CORRUPT ;
2019-07-23 09:14:31 +02:00
memdelete ( obj ) ; //bye
2019-08-15 04:57:49 +02:00
ERR_FAIL_V_MSG ( ERR_FILE_CORRUPT , local_path + " :Resource type in resource field not a resource, type is: " + obj_class + " . " ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
RES res = RES ( r ) ;
2014-02-10 02:10:30 +01:00
r - > set_path ( path ) ;
2015-06-22 05:03:19 +02:00
r - > set_subindex ( subindex ) ;
2014-02-10 02:10:30 +01:00
int pc = f - > get_32 ( ) ;
//set properties
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < pc ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-02-15 12:29:46 +01:00
StringName name = _get_string ( ) ;
2017-12-15 12:38:24 +01:00
2017-03-05 16:44:50 +01:00
if ( name = = StringName ( ) ) {
error = ERR_FILE_CORRUPT ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_V ( ERR_FILE_CORRUPT ) ;
}
Variant value ;
error = parse_variant ( value ) ;
if ( error )
return error ;
2017-03-05 16:44:50 +01:00
res - > set ( name , value ) ;
2014-02-10 02:10:30 +01:00
}
# ifdef TOOLS_ENABLED
res - > set_edited ( false ) ;
# endif
stage + + ;
resource_cache . push_back ( res ) ;
if ( main ) {
f - > close ( ) ;
2017-03-05 16:44:50 +01:00
resource = res ;
2017-06-28 22:00:18 +02:00
resource - > set_as_translation_remapped ( translation_remapped ) ;
2017-03-05 16:44:50 +01:00
error = ERR_FILE_EOF ;
2014-02-10 02:10:30 +01:00
} else {
2017-03-05 16:44:50 +01:00
error = OK ;
2014-02-10 02:10:30 +01:00
}
return OK ;
}
2017-03-05 16:44:50 +01:00
int ResourceInteractiveLoaderBinary : : get_stage ( ) const {
2014-02-10 02:10:30 +01:00
return stage ;
}
int ResourceInteractiveLoaderBinary : : get_stage_count ( ) const {
2017-03-05 16:44:50 +01:00
return external_resources . size ( ) + internal_resources . size ( ) ;
2014-02-10 02:10:30 +01:00
}
2017-06-28 22:00:18 +02:00
void ResourceInteractiveLoaderBinary : : set_translation_remapped ( bool p_remapped ) {
translation_remapped = p_remapped ;
}
2017-03-05 16:44:50 +01:00
static void save_ustring ( FileAccess * f , const String & p_string ) {
2015-08-24 01:15:56 +02:00
CharString utf8 = p_string . utf8 ( ) ;
2017-03-05 16:44:50 +01:00
f - > store_32 ( utf8 . length ( ) + 1 ) ;
f - > store_buffer ( ( const uint8_t * ) utf8 . get_data ( ) , utf8 . length ( ) + 1 ) ;
2015-08-24 01:15:56 +02:00
}
static String get_ustring ( FileAccess * f ) {
int len = f - > get_32 ( ) ;
Vector < char > str_buf ;
str_buf . resize ( len ) ;
2017-03-05 16:44:50 +01:00
f - > get_buffer ( ( uint8_t * ) & str_buf [ 0 ] , len ) ;
2015-08-24 01:15:56 +02:00
String s ;
s . parse_utf8 ( & str_buf [ 0 ] ) ;
return s ;
}
2014-02-10 02:10:30 +01:00
String ResourceInteractiveLoaderBinary : : get_unicode_string ( ) {
int len = f - > get_32 ( ) ;
2017-03-05 16:44:50 +01:00
if ( len > str_buf . size ( ) ) {
2014-02-10 02:10:30 +01:00
str_buf . resize ( len ) ;
}
2017-03-05 16:44:50 +01:00
if ( len = = 0 )
2015-12-09 13:08:41 +01:00
return String ( ) ;
2017-03-05 16:44:50 +01:00
f - > get_buffer ( ( uint8_t * ) & str_buf [ 0 ] , len ) ;
2014-02-10 02:10:30 +01:00
String s ;
s . parse_utf8 ( & str_buf [ 0 ] ) ;
return s ;
}
2017-03-05 16:44:50 +01:00
void ResourceInteractiveLoaderBinary : : get_dependencies ( FileAccess * p_f , List < String > * p_dependencies , bool p_add_types ) {
2014-02-10 02:10:30 +01:00
open ( p_f ) ;
if ( error )
return ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < external_resources . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
String dep = external_resources [ i ] . path ;
2014-03-14 02:57:24 +01:00
2017-03-05 16:44:50 +01:00
if ( p_add_types & & external_resources [ i ] . type ! = String ( ) ) {
dep + = " :: " + external_resources [ i ] . type ;
2015-08-24 01:15:56 +02:00
}
2014-03-14 02:57:24 +01:00
p_dependencies - > push_back ( dep ) ;
2014-02-10 02:10:30 +01:00
}
}
void ResourceInteractiveLoaderBinary : : open ( FileAccess * p_f ) {
2017-03-05 16:44:50 +01:00
error = OK ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
f = p_f ;
2014-02-10 02:10:30 +01:00
uint8_t header [ 4 ] ;
2017-03-05 16:44:50 +01:00
f - > get_buffer ( header , 4 ) ;
if ( header [ 0 ] = = ' R ' & & header [ 1 ] = = ' S ' & & header [ 2 ] = = ' C ' & & header [ 3 ] = = ' C ' ) {
2020-02-11 04:39:20 +01:00
// Compressed.
2017-03-05 16:44:50 +01:00
FileAccessCompressed * fac = memnew ( FileAccessCompressed ) ;
2020-02-11 04:39:20 +01:00
error = fac - > open_after_magic ( f ) ;
if ( error ! = OK ) {
memdelete ( fac ) ;
f - > close ( ) ;
ERR_FAIL_MSG ( " Failed to open binary resource file: " + local_path + " . " ) ;
}
2017-03-05 16:44:50 +01:00
f = fac ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
} else if ( header [ 0 ] ! = ' R ' | | header [ 1 ] ! = ' S ' | | header [ 2 ] ! = ' R ' | | header [ 3 ] ! = ' C ' ) {
2020-02-11 04:39:20 +01:00
// Not normal.
2017-03-05 16:44:50 +01:00
error = ERR_FILE_UNRECOGNIZED ;
2020-02-11 04:39:20 +01:00
f - > close ( ) ;
2019-08-15 04:57:49 +02:00
ERR_FAIL_MSG ( " Unrecognized binary resource file: " + local_path + " . " ) ;
2014-02-10 02:10:30 +01:00
}
bool big_endian = f - > get_32 ( ) ;
bool use_real64 = f - > get_32 ( ) ;
2017-03-05 16:44:50 +01:00
f - > set_endian_swap ( big_endian ! = 0 ) ; //read big endian if saved as big endian
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
uint32_t ver_major = f - > get_32 ( ) ;
uint32_t ver_minor = f - > get_32 ( ) ;
2017-11-22 12:34:43 +01:00
ver_format = f - > get_32 ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
print_bl ( " big endian: " + itos ( big_endian ) ) ;
2017-09-02 22:32:31 +02:00
# ifdef BIG_ENDIAN_ENABLED
print_bl ( " endian swap: " + itos ( ! big_endian ) ) ;
# else
print_bl ( " endian swap: " + itos ( big_endian ) ) ;
# endif
2017-03-05 16:44:50 +01:00
print_bl ( " real64: " + itos ( use_real64 ) ) ;
print_bl ( " major: " + itos ( ver_major ) ) ;
print_bl ( " minor: " + itos ( ver_minor ) ) ;
print_bl ( " format: " + itos ( ver_format ) ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( ver_format > FORMAT_VERSION | | ver_major > VERSION_MAJOR ) {
2014-02-10 02:10:30 +01:00
f - > close ( ) ;
2019-08-15 04:57:49 +02:00
ERR_FAIL_MSG ( " File format ' " + itos ( FORMAT_VERSION ) + " . " + itos ( ver_major ) + " . " + itos ( ver_minor ) + " ' is too new! Please upgrade to a new engine version: " + local_path + " . " ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
type = get_unicode_string ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
print_bl ( " type: " + type ) ;
2014-02-10 02:10:30 +01:00
importmd_ofs = f - > get_64 ( ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < 14 ; i + + )
2014-02-10 02:10:30 +01:00
f - > get_32 ( ) ; //skip a few reserved fields
2017-03-05 16:44:50 +01:00
uint32_t string_table_size = f - > get_32 ( ) ;
2014-02-10 02:10:30 +01:00
string_map . resize ( string_table_size ) ;
2017-03-05 16:44:50 +01:00
for ( uint32_t i = 0 ; i < string_table_size ; i + + ) {
2014-02-10 02:10:30 +01:00
StringName s = get_unicode_string ( ) ;
2018-07-25 03:11:03 +02:00
string_map . write [ i ] = s ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
print_bl ( " strings: " + itos ( string_table_size ) ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
uint32_t ext_resources_size = f - > get_32 ( ) ;
for ( uint32_t i = 0 ; i < ext_resources_size ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-08-08 07:02:49 +02:00
ExtResource er ;
2017-03-05 16:44:50 +01:00
er . type = get_unicode_string ( ) ;
2017-12-15 12:38:24 +01:00
2017-03-05 16:44:50 +01:00
er . path = get_unicode_string ( ) ;
2017-12-15 12:38:24 +01:00
2014-02-10 02:10:30 +01:00
external_resources . push_back ( er ) ;
}
2017-03-05 16:44:50 +01:00
print_bl ( " ext resources: " + itos ( ext_resources_size ) ) ;
uint32_t int_resources_size = f - > get_32 ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( uint32_t i = 0 ; i < int_resources_size ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-08-08 07:02:49 +02:00
IntResource ir ;
2017-03-05 16:44:50 +01:00
ir . path = get_unicode_string ( ) ;
ir . offset = f - > get_64 ( ) ;
2014-02-10 02:10:30 +01:00
internal_resources . push_back ( ir ) ;
}
2017-03-05 16:44:50 +01:00
print_bl ( " int resources: " + itos ( int_resources_size ) ) ;
2014-02-10 02:10:30 +01:00
if ( f - > eof_reached ( ) ) {
2017-03-05 16:44:50 +01:00
error = ERR_FILE_CORRUPT ;
2020-02-11 04:39:20 +01:00
f - > close ( ) ;
2019-08-15 04:57:49 +02:00
ERR_FAIL_MSG ( " Premature end of file (EOF): " + local_path + " . " ) ;
2014-02-10 02:10:30 +01:00
}
}
String ResourceInteractiveLoaderBinary : : recognize ( FileAccess * p_f ) {
2017-03-05 16:44:50 +01:00
error = OK ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
f = p_f ;
2014-02-10 02:10:30 +01:00
uint8_t header [ 4 ] ;
2017-03-05 16:44:50 +01:00
f - > get_buffer ( header , 4 ) ;
if ( header [ 0 ] = = ' R ' & & header [ 1 ] = = ' S ' & & header [ 2 ] = = ' C ' & & header [ 3 ] = = ' C ' ) {
2020-02-11 04:39:20 +01:00
// Compressed.
2017-03-05 16:44:50 +01:00
FileAccessCompressed * fac = memnew ( FileAccessCompressed ) ;
2020-02-11 04:39:20 +01:00
error = fac - > open_after_magic ( f ) ;
if ( error ! = OK ) {
memdelete ( fac ) ;
f - > close ( ) ;
return " " ;
}
2017-03-05 16:44:50 +01:00
f = fac ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
} else if ( header [ 0 ] ! = ' R ' | | header [ 1 ] ! = ' S ' | | header [ 2 ] ! = ' R ' | | header [ 3 ] ! = ' C ' ) {
2020-02-11 04:39:20 +01:00
// Not normal.
2017-03-05 16:44:50 +01:00
error = ERR_FILE_UNRECOGNIZED ;
2020-02-11 04:39:20 +01:00
f - > close ( ) ;
2014-02-10 02:10:30 +01:00
return " " ;
}
bool big_endian = f - > get_32 ( ) ;
2017-09-02 22:32:31 +02:00
f - > get_32 ( ) ; // use_real64
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
f - > set_endian_swap ( big_endian ! = 0 ) ; //read big endian if saved as big endian
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
uint32_t ver_major = f - > get_32 ( ) ;
2017-09-02 22:32:31 +02:00
f - > get_32 ( ) ; // ver_minor
2017-03-05 16:44:50 +01:00
uint32_t ver_format = f - > get_32 ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( ver_format > FORMAT_VERSION | | ver_major > VERSION_MAJOR ) {
2014-02-10 02:10:30 +01:00
f - > close ( ) ;
return " " ;
}
2017-03-05 16:44:50 +01:00
String type = get_unicode_string ( ) ;
2014-02-10 02:10:30 +01:00
return type ;
}
2018-12-08 21:07:33 +01:00
ResourceInteractiveLoaderBinary : : ResourceInteractiveLoaderBinary ( ) :
translation_remapped ( false ) ,
f ( NULL ) ,
error ( OK ) ,
stage ( 0 ) {
2014-02-10 02:10:30 +01:00
}
ResourceInteractiveLoaderBinary : : ~ ResourceInteractiveLoaderBinary ( ) {
if ( f )
memdelete ( f ) ;
}
2017-08-31 23:57:03 +02:00
Ref < ResourceInteractiveLoader > ResourceFormatLoaderBinary : : load_interactive ( const String & p_path , const String & p_original_path , Error * r_error ) {
2014-02-10 02:10:30 +01:00
2015-08-24 01:15:56 +02:00
if ( r_error )
2017-03-05 16:44:50 +01:00
* r_error = ERR_FILE_CANT_OPEN ;
2014-02-10 02:10:30 +01:00
Error err ;
2017-03-05 16:44:50 +01:00
FileAccess * f = FileAccess : : open ( p_path , FileAccess : : READ , & err ) ;
2014-02-10 02:10:30 +01:00
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( err ! = OK , Ref < ResourceInteractiveLoader > ( ) , " Cannot open file ' " + p_path + " '. " ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Ref < ResourceInteractiveLoaderBinary > ria = memnew ( ResourceInteractiveLoaderBinary ) ;
2017-08-31 23:57:03 +02:00
String path = p_original_path ! = " " ? p_original_path : p_path ;
ria - > local_path = ProjectSettings : : get_singleton ( ) - > localize_path ( path ) ;
2017-03-05 16:44:50 +01:00
ria - > res_path = ria - > local_path ;
2017-01-14 12:26:56 +01:00
//ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
2014-02-10 02:10:30 +01:00
ria - > open ( f ) ;
return ria ;
}
2017-03-05 16:44:50 +01:00
void ResourceFormatLoaderBinary : : get_recognized_extensions_for_type ( const String & p_type , List < String > * p_extensions ) const {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( p_type = = " " ) {
2014-02-10 02:10:30 +01:00
get_recognized_extensions ( p_extensions ) ;
return ;
}
List < String > extensions ;
2017-03-05 16:44:50 +01:00
ClassDB : : get_extensions_for_type ( p_type , & extensions ) ;
2014-02-10 02:10:30 +01:00
extensions . sort ( ) ;
2017-03-05 16:44:50 +01:00
for ( List < String > : : Element * E = extensions . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
String ext = E - > get ( ) . to_lower ( ) ;
p_extensions - > push_back ( ext ) ;
}
}
2017-03-05 16:44:50 +01:00
void ResourceFormatLoaderBinary : : get_recognized_extensions ( List < String > * p_extensions ) const {
2014-02-10 02:10:30 +01:00
List < String > extensions ;
2017-01-03 03:03:46 +01:00
ClassDB : : get_resource_base_extensions ( & extensions ) ;
2014-02-10 02:10:30 +01:00
extensions . sort ( ) ;
2017-03-05 16:44:50 +01:00
for ( List < String > : : Element * E = extensions . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
String ext = E - > get ( ) . to_lower ( ) ;
p_extensions - > push_back ( ext ) ;
}
}
2017-03-05 16:44:50 +01:00
bool ResourceFormatLoaderBinary : : handles_type ( const String & p_type ) const {
2014-02-10 02:10:30 +01:00
return true ; //handles all
}
2017-03-05 16:44:50 +01:00
void ResourceFormatLoaderBinary : : get_dependencies ( const String & p_path , List < String > * p_dependencies , bool p_add_types ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
FileAccess * f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_MSG ( ! f , " Cannot open file ' " + p_path + " '. " ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Ref < ResourceInteractiveLoaderBinary > ria = memnew ( ResourceInteractiveLoaderBinary ) ;
2017-07-19 22:00:46 +02:00
ria - > local_path = ProjectSettings : : get_singleton ( ) - > localize_path ( p_path ) ;
2017-03-05 16:44:50 +01:00
ria - > res_path = ria - > local_path ;
2017-01-14 12:26:56 +01:00
//ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
2017-03-05 16:44:50 +01:00
ria - > get_dependencies ( f , p_dependencies , p_add_types ) ;
2015-08-24 01:15:56 +02:00
}
2017-03-05 16:44:50 +01:00
Error ResourceFormatLoaderBinary : : rename_dependencies ( const String & p_path , const Map < String , String > & p_map ) {
2015-08-24 01:15:56 +02:00
2017-01-14 12:26:56 +01:00
//Error error=OK;
2015-08-24 01:15:56 +02:00
2017-03-05 16:44:50 +01:00
FileAccess * f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( ! f , ERR_CANT_OPEN , " Cannot open file ' " + p_path + " '. " ) ;
2015-08-24 01:15:56 +02:00
2017-03-05 16:44:50 +01:00
FileAccess * fw = NULL ; //=FileAccess::open(p_path+".depren");
2015-08-24 01:15:56 +02:00
2017-03-05 16:44:50 +01:00
String local_path = p_path . get_base_dir ( ) ;
2015-08-24 01:15:56 +02:00
uint8_t header [ 4 ] ;
2017-03-05 16:44:50 +01:00
f - > get_buffer ( header , 4 ) ;
if ( header [ 0 ] = = ' R ' & & header [ 1 ] = = ' S ' & & header [ 2 ] = = ' C ' & & header [ 3 ] = = ' C ' ) {
2020-02-11 04:39:20 +01:00
// Compressed.
2017-03-05 16:44:50 +01:00
FileAccessCompressed * fac = memnew ( FileAccessCompressed ) ;
2020-02-11 04:39:20 +01:00
Error err = fac - > open_after_magic ( f ) ;
if ( err ! = OK ) {
memdelete ( fac ) ;
memdelete ( f ) ;
ERR_FAIL_V_MSG ( err , " Cannot open file ' " + p_path + " '. " ) ;
}
2017-03-05 16:44:50 +01:00
f = fac ;
2015-08-24 01:15:56 +02:00
2017-03-05 16:44:50 +01:00
FileAccessCompressed * facw = memnew ( FileAccessCompressed ) ;
2015-08-24 01:15:56 +02:00
facw - > configure ( " RSCC " ) ;
2020-02-11 04:39:20 +01:00
err = facw - > _open ( p_path + " .depren " , FileAccess : : WRITE ) ;
2015-08-24 01:15:56 +02:00
if ( err ) {
memdelete ( fac ) ;
memdelete ( facw ) ;
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( err , ERR_FILE_CORRUPT , " Cannot create file ' " + p_path + " .depren'. " ) ;
2015-08-24 01:15:56 +02:00
}
2017-03-05 16:44:50 +01:00
fw = facw ;
2015-08-24 01:15:56 +02:00
2017-03-05 16:44:50 +01:00
} else if ( header [ 0 ] ! = ' R ' | | header [ 1 ] ! = ' S ' | | header [ 2 ] ! = ' R ' | | header [ 3 ] ! = ' C ' ) {
2020-02-11 04:39:20 +01:00
// Not normal.
2015-08-24 01:15:56 +02:00
memdelete ( f ) ;
2019-09-25 10:28:50 +02:00
ERR_FAIL_V_MSG ( ERR_FILE_UNRECOGNIZED , " Unrecognized binary resource file ' " + local_path + " '. " ) ;
2015-08-24 01:15:56 +02:00
} else {
2017-03-05 16:44:50 +01:00
fw = FileAccess : : open ( p_path + " .depren " , FileAccess : : WRITE ) ;
2015-08-24 01:15:56 +02:00
if ( ! fw ) {
memdelete ( f ) ;
}
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( ! fw , ERR_CANT_CREATE , " Cannot create file ' " + p_path + " .depren'. " ) ;
2017-09-03 05:22:54 +02:00
uint8_t magic [ 4 ] = { ' R ' , ' S ' , ' R ' , ' C ' } ;
fw - > store_buffer ( magic , 4 ) ;
2015-08-24 01:15:56 +02:00
}
bool big_endian = f - > get_32 ( ) ;
bool use_real64 = f - > get_32 ( ) ;
2017-03-05 16:44:50 +01:00
f - > set_endian_swap ( big_endian ! = 0 ) ; //read big endian if saved as big endian
2017-09-02 22:32:31 +02:00
# ifdef BIG_ENDIAN_ENABLED
fw - > store_32 ( ! big_endian ) ;
# else
fw - > store_32 ( big_endian ) ;
# endif
2017-03-05 16:44:50 +01:00
fw - > set_endian_swap ( big_endian ! = 0 ) ;
2015-08-24 01:15:56 +02:00
fw - > store_32 ( use_real64 ) ; //use real64
2017-03-05 16:44:50 +01:00
uint32_t ver_major = f - > get_32 ( ) ;
uint32_t ver_minor = f - > get_32 ( ) ;
uint32_t ver_format = f - > get_32 ( ) ;
2015-08-24 01:15:56 +02:00
2017-03-05 16:44:50 +01:00
if ( ver_format < FORMAT_VERSION_CAN_RENAME_DEPS ) {
2015-08-24 01:15:56 +02:00
memdelete ( f ) ;
memdelete ( fw ) ;
DirAccess * da = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
2017-03-05 16:44:50 +01:00
da - > remove ( p_path + " .depren " ) ;
2015-08-24 01:15:56 +02:00
memdelete ( da ) ;
2018-02-17 14:00:39 +01:00
//use the old approach
2015-08-24 01:15:56 +02:00
2019-09-25 10:28:50 +02:00
WARN_PRINTS ( " This file is old, so it can't refactor dependencies, opening and resaving ' " + p_path + " '. " ) ;
2015-08-24 01:15:56 +02:00
Error err ;
2017-03-05 16:44:50 +01:00
f = FileAccess : : open ( p_path , FileAccess : : READ , & err ) ;
2019-06-20 16:59:48 +02:00
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( err ! = OK , ERR_FILE_CANT_OPEN , " Cannot open file ' " + p_path + " '. " ) ;
2015-08-24 01:15:56 +02:00
2017-03-05 16:44:50 +01:00
Ref < ResourceInteractiveLoaderBinary > ria = memnew ( ResourceInteractiveLoaderBinary ) ;
2017-07-19 22:00:46 +02:00
ria - > local_path = ProjectSettings : : get_singleton ( ) - > localize_path ( p_path ) ;
2017-03-05 16:44:50 +01:00
ria - > res_path = ria - > local_path ;
ria - > remaps = p_map ;
2017-01-14 12:26:56 +01:00
//ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
2015-08-24 01:15:56 +02:00
ria - > open ( f ) ;
err = ria - > poll ( ) ;
2017-03-05 16:44:50 +01:00
while ( err = = OK ) {
err = ria - > poll ( ) ;
2015-08-24 01:15:56 +02:00
}
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( err ! = ERR_FILE_EOF , ERR_FILE_CORRUPT ) ;
2015-08-24 01:15:56 +02:00
RES res = ria - > get_resource ( ) ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! res . is_valid ( ) , ERR_FILE_CORRUPT ) ;
2015-08-24 01:15:56 +02:00
2017-03-05 16:44:50 +01:00
return ResourceFormatSaverBinary : : singleton - > save ( p_path , res ) ;
2015-08-24 01:15:56 +02:00
}
2017-03-05 16:44:50 +01:00
if ( ver_format > FORMAT_VERSION | | ver_major > VERSION_MAJOR ) {
2015-08-24 01:15:56 +02:00
memdelete ( f ) ;
memdelete ( fw ) ;
2019-08-15 04:57:49 +02:00
ERR_FAIL_V_MSG ( ERR_FILE_UNRECOGNIZED , " File format ' " + itos ( FORMAT_VERSION ) + " . " + itos ( ver_major ) + " . " + itos ( ver_minor ) + " ' is too new! Please upgrade to a new engine version: " + local_path + " . " ) ;
2015-08-24 01:15:56 +02:00
}
2018-03-19 16:37:57 +01:00
// Since we're not actually converting the file contents, leave the version
// numbers in the file untouched.
fw - > store_32 ( ver_major ) ;
fw - > store_32 ( ver_minor ) ;
fw - > store_32 ( ver_format ) ;
2015-08-24 01:15:56 +02:00
2017-03-05 16:44:50 +01:00
save_ustring ( fw , get_ustring ( f ) ) ; //type
2015-08-24 01:15:56 +02:00
2017-09-10 15:37:49 +02:00
size_t md_ofs = f - > get_position ( ) ;
2015-08-24 01:15:56 +02:00
size_t importmd_ofs = f - > get_64 ( ) ;
fw - > store_64 ( 0 ) ; //metadata offset
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < 14 ; i + + ) {
2015-08-24 01:15:56 +02:00
fw - > store_32 ( 0 ) ;
f - > get_32 ( ) ;
}
//string table
2017-03-05 16:44:50 +01:00
uint32_t string_table_size = f - > get_32 ( ) ;
2015-08-24 01:15:56 +02:00
fw - > store_32 ( string_table_size ) ;
2017-03-05 16:44:50 +01:00
for ( uint32_t i = 0 ; i < string_table_size ; i + + ) {
2015-08-24 01:15:56 +02:00
String s = get_ustring ( f ) ;
2017-03-05 16:44:50 +01:00
save_ustring ( fw , s ) ;
2015-08-24 01:15:56 +02:00
}
//external resources
2017-03-05 16:44:50 +01:00
uint32_t ext_resources_size = f - > get_32 ( ) ;
2015-08-24 01:15:56 +02:00
fw - > store_32 ( ext_resources_size ) ;
2017-03-05 16:44:50 +01:00
for ( uint32_t i = 0 ; i < ext_resources_size ; i + + ) {
2015-08-24 01:15:56 +02:00
String type = get_ustring ( f ) ;
String path = get_ustring ( f ) ;
2017-03-05 16:44:50 +01:00
bool relative = false ;
2015-08-24 01:15:56 +02:00
if ( ! path . begins_with ( " res:// " ) ) {
2017-03-05 16:44:50 +01:00
path = local_path . plus_file ( path ) . simplify_path ( ) ;
relative = true ;
2015-08-24 01:15:56 +02:00
}
if ( p_map . has ( path ) ) {
2017-03-05 16:44:50 +01:00
String np = p_map [ path ] ;
path = np ;
2015-08-24 01:15:56 +02:00
}
if ( relative ) {
//restore relative
2017-03-05 16:44:50 +01:00
path = local_path . path_to_file ( path ) ;
2015-08-24 01:15:56 +02:00
}
2017-03-05 16:44:50 +01:00
save_ustring ( fw , type ) ;
save_ustring ( fw , path ) ;
2015-08-24 01:15:56 +02:00
}
2017-09-10 15:37:49 +02:00
int64_t size_diff = ( int64_t ) fw - > get_position ( ) - ( int64_t ) f - > get_position ( ) ;
2015-08-24 01:15:56 +02:00
//internal resources
2017-03-05 16:44:50 +01:00
uint32_t int_resources_size = f - > get_32 ( ) ;
2015-08-24 01:15:56 +02:00
fw - > store_32 ( int_resources_size ) ;
2017-03-05 16:44:50 +01:00
for ( uint32_t i = 0 ; i < int_resources_size ; i + + ) {
2015-08-24 01:15:56 +02:00
2017-03-05 16:44:50 +01:00
String path = get_ustring ( f ) ;
uint64_t offset = f - > get_64 ( ) ;
save_ustring ( fw , path ) ;
fw - > store_64 ( offset + size_diff ) ;
2015-08-24 01:15:56 +02:00
}
//rest of file
uint8_t b = f - > get_8 ( ) ;
2017-03-05 16:44:50 +01:00
while ( ! f - > eof_reached ( ) ) {
2015-08-24 01:15:56 +02:00
fw - > store_8 ( b ) ;
b = f - > get_8 ( ) ;
}
2017-03-05 16:44:50 +01:00
bool all_ok = fw - > get_error ( ) = = OK ;
2015-08-24 01:15:56 +02:00
fw - > seek ( md_ofs ) ;
2017-03-05 16:44:50 +01:00
fw - > store_64 ( importmd_ofs + size_diff ) ;
2015-08-24 01:15:56 +02:00
memdelete ( f ) ;
memdelete ( fw ) ;
if ( ! all_ok ) {
return ERR_CANT_CREATE ;
}
DirAccess * da = DirAccess : : create ( DirAccess : : ACCESS_RESOURCES ) ;
da - > remove ( p_path ) ;
2017-03-05 16:44:50 +01:00
da - > rename ( p_path + " .depren " , p_path ) ;
2015-08-24 01:15:56 +02:00
memdelete ( da ) ;
return OK ;
2014-02-10 02:10:30 +01:00
}
String ResourceFormatLoaderBinary : : get_resource_type ( const String & p_path ) const {
2017-03-05 16:44:50 +01:00
FileAccess * f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
2014-02-10 02:10:30 +01:00
if ( ! f ) {
return " " ; //could not rwead
}
2017-03-05 16:44:50 +01:00
Ref < ResourceInteractiveLoaderBinary > ria = memnew ( ResourceInteractiveLoaderBinary ) ;
2017-07-19 22:00:46 +02:00
ria - > local_path = ProjectSettings : : get_singleton ( ) - > localize_path ( p_path ) ;
2017-03-05 16:44:50 +01:00
ria - > res_path = ria - > local_path ;
2017-01-14 12:26:56 +01:00
//ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
2014-02-10 02:10:30 +01:00
String r = ria - > recognize ( f ) ;
return r ;
}
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
2017-12-15 12:38:24 +01:00
void ResourceFormatSaverBinaryInstance : : _pad_buffer ( FileAccess * f , int p_bytes ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
int extra = 4 - ( p_bytes % 4 ) ;
if ( extra < 4 ) {
for ( int i = 0 ; i < extra ; i + + )
2014-02-10 02:10:30 +01:00
f - > store_8 ( 0 ) ; //pad to 32
}
}
2017-12-15 12:38:24 +01:00
void ResourceFormatSaverBinaryInstance : : _write_variant ( const Variant & p_property , const PropertyInfo & p_hint ) {
write_variant ( f , p_property , resource_set , external_resources , string_map , p_hint ) ;
}
void ResourceFormatSaverBinaryInstance : : write_variant ( FileAccess * f , const Variant & p_property , Set < RES > & resource_set , Map < RES , int > & external_resources , Map < StringName , int > & string_map , const PropertyInfo & p_hint ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
switch ( p_property . get_type ( ) ) {
2014-02-10 02:10:30 +01:00
case Variant : : NIL : {
f - > store_32 ( VARIANT_NIL ) ;
// don't store anything
} break ;
case Variant : : BOOL : {
f - > store_32 ( VARIANT_BOOL ) ;
2017-03-05 16:44:50 +01:00
bool val = p_property ;
2014-02-10 02:10:30 +01:00
f - > store_32 ( val ) ;
} break ;
case Variant : : INT : {
2017-01-09 00:58:39 +01:00
int64_t val = p_property ;
2018-10-04 15:38:52 +02:00
if ( val > 0x7FFFFFFF | | val < - ( int64_t ) 0x80000000 ) {
2017-01-09 00:58:39 +01:00
f - > store_32 ( VARIANT_INT64 ) ;
f - > store_64 ( val ) ;
} else {
f - > store_32 ( VARIANT_INT ) ;
2019-02-12 21:10:08 +01:00
f - > store_32 ( int32_t ( p_property ) ) ;
2017-01-09 00:58:39 +01:00
}
2014-02-10 02:10:30 +01:00
} break ;
case Variant : : REAL : {
2017-01-09 00:58:39 +01:00
double d = p_property ;
float fl = d ;
2017-03-05 16:44:50 +01:00
if ( double ( fl ) ! = d ) {
2017-01-09 00:58:39 +01:00
f - > store_32 ( VARIANT_DOUBLE ) ;
f - > store_double ( d ) ;
} else {
f - > store_32 ( VARIANT_REAL ) ;
f - > store_real ( fl ) ;
}
2014-02-10 02:10:30 +01:00
} break ;
case Variant : : STRING : {
f - > store_32 ( VARIANT_STRING ) ;
2017-03-05 16:44:50 +01:00
String val = p_property ;
2017-12-15 12:38:24 +01:00
save_unicode_string ( f , val ) ;
2014-02-10 02:10:30 +01:00
} break ;
case Variant : : VECTOR2 : {
f - > store_32 ( VARIANT_VECTOR2 ) ;
2017-03-05 16:44:50 +01:00
Vector2 val = p_property ;
2014-02-10 02:10:30 +01:00
f - > store_real ( val . x ) ;
f - > store_real ( val . y ) ;
} break ;
case Variant : : RECT2 : {
f - > store_32 ( VARIANT_RECT2 ) ;
2017-03-05 16:44:50 +01:00
Rect2 val = p_property ;
2017-06-04 00:25:13 +02:00
f - > store_real ( val . position . x ) ;
f - > store_real ( val . position . y ) ;
2014-02-10 02:10:30 +01:00
f - > store_real ( val . size . x ) ;
f - > store_real ( val . size . y ) ;
} break ;
case Variant : : VECTOR3 : {
f - > store_32 ( VARIANT_VECTOR3 ) ;
2017-03-05 16:44:50 +01:00
Vector3 val = p_property ;
2014-02-10 02:10:30 +01:00
f - > store_real ( val . x ) ;
f - > store_real ( val . y ) ;
f - > store_real ( val . z ) ;
} break ;
case Variant : : PLANE : {
f - > store_32 ( VARIANT_PLANE ) ;
2017-03-05 16:44:50 +01:00
Plane val = p_property ;
2014-02-10 02:10:30 +01:00
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 ) ;
2017-03-05 16:44:50 +01:00
Quat val = p_property ;
2014-02-10 02:10:30 +01:00
f - > store_real ( val . x ) ;
f - > store_real ( val . y ) ;
f - > store_real ( val . z ) ;
f - > store_real ( val . w ) ;
} break ;
2017-11-17 03:09:00 +01:00
case Variant : : AABB : {
2014-02-10 02:10:30 +01:00
2017-11-17 03:09:00 +01:00
f - > store_32 ( VARIANT_AABB ) ;
AABB val = p_property ;
2017-06-06 20:33:51 +02:00
f - > store_real ( val . position . x ) ;
f - > store_real ( val . position . y ) ;
f - > store_real ( val . position . z ) ;
2014-02-10 02:10:30 +01:00
f - > store_real ( val . size . x ) ;
f - > store_real ( val . size . y ) ;
f - > store_real ( val . size . z ) ;
} break ;
2017-01-11 04:52:51 +01:00
case Variant : : TRANSFORM2D : {
2014-02-10 02:10:30 +01:00
f - > store_32 ( VARIANT_MATRIX32 ) ;
2017-03-05 16:44:50 +01:00
Transform2D val = p_property ;
2014-02-10 02:10:30 +01:00
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 ;
2017-01-11 04:52:51 +01:00
case Variant : : BASIS : {
2014-02-10 02:10:30 +01:00
f - > store_32 ( VARIANT_MATRIX3 ) ;
2017-03-05 16:44:50 +01:00
Basis val = p_property ;
2014-02-10 02:10:30 +01:00
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 ) ;
2017-03-05 16:44:50 +01:00
Transform val = p_property ;
2014-02-10 02:10:30 +01:00
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 ) ;
2017-03-05 16:44:50 +01:00
Color val = p_property ;
2014-02-10 02:10:30 +01:00
f - > store_real ( val . r ) ;
f - > store_real ( val . g ) ;
f - > store_real ( val . b ) ;
f - > store_real ( val . a ) ;
} break ;
case Variant : : NODE_PATH : {
f - > store_32 ( VARIANT_NODE_PATH ) ;
2017-03-05 16:44:50 +01:00
NodePath np = p_property ;
2014-02-10 02:10:30 +01:00
f - > store_16 ( np . get_name_count ( ) ) ;
uint16_t snc = np . get_subname_count ( ) ;
if ( np . is_absolute ( ) )
2017-03-05 16:44:50 +01:00
snc | = 0x8000 ;
2014-02-10 02:10:30 +01:00
f - > store_16 ( snc ) ;
2017-12-15 12:38:24 +01:00
for ( int i = 0 ; i < np . get_name_count ( ) ; i + + ) {
if ( string_map . has ( np . get_name ( i ) ) ) {
f - > store_32 ( string_map [ np . get_name ( i ) ] ) ;
} else {
save_unicode_string ( f , np . get_name ( i ) , true ) ;
}
}
for ( int i = 0 ; i < np . get_subname_count ( ) ; i + + ) {
if ( string_map . has ( np . get_subname ( i ) ) ) {
f - > store_32 ( string_map [ np . get_subname ( i ) ] ) ;
} else {
save_unicode_string ( f , np . get_subname ( i ) , true ) ;
}
}
2014-02-10 02:10:30 +01:00
} break ;
case Variant : : _RID : {
f - > store_32 ( VARIANT_RID ) ;
2019-08-15 04:57:49 +02:00
WARN_PRINT ( " Can't save RIDs. " ) ;
2014-02-10 02:10:30 +01:00
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
}
2017-03-05 16:44:50 +01:00
if ( res - > get_path ( ) . length ( ) & & res - > get_path ( ) . find ( " :: " ) = = - 1 ) {
2015-08-24 01:15:56 +02:00
f - > store_32 ( OBJECT_EXTERNAL_RESOURCE_INDEX ) ;
f - > store_32 ( external_resources [ res ] ) ;
2014-02-10 02:10:30 +01:00
} else {
2015-06-22 05:03:19 +02:00
if ( ! resource_set . has ( res ) ) {
2014-02-10 02:10:30 +01:00
f - > store_32 ( OBJECT_EMPTY ) ;
2019-08-15 04:57:49 +02:00
ERR_FAIL_MSG ( " Resource was not pre cached for the resource section, most likely due to circular reference. " ) ;
2014-02-10 02:10:30 +01:00
}
f - > store_32 ( OBJECT_INTERNAL_RESOURCE ) ;
2015-06-22 05:03:19 +02:00
f - > store_32 ( res - > get_subindex ( ) ) ;
2014-02-10 02:10:30 +01:00
//internal resource
}
} break ;
case Variant : : DICTIONARY : {
f - > store_32 ( VARIANT_DICTIONARY ) ;
Dictionary d = p_property ;
2017-01-11 12:53:31 +01:00
f - > store_32 ( uint32_t ( d . size ( ) ) ) ;
2014-02-10 02:10:30 +01:00
List < Variant > keys ;
d . get_key_list ( & keys ) ;
2017-03-05 16:44:50 +01:00
for ( List < Variant > : : Element * E = keys . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
2017-01-14 12:26:56 +01:00
/*
if ( ! _check_type ( dict [ E - > get ( ) ] ) )
continue ;
*/
2014-02-10 02:10:30 +01:00
2017-12-15 12:38:24 +01:00
write_variant ( f , E - > get ( ) , resource_set , external_resources , string_map ) ;
write_variant ( f , d [ E - > get ( ) ] , resource_set , external_resources , string_map ) ;
2014-02-10 02:10:30 +01:00
}
} break ;
case Variant : : ARRAY : {
f - > store_32 ( VARIANT_ARRAY ) ;
2017-03-05 16:44:50 +01:00
Array a = p_property ;
2017-01-11 12:53:31 +01:00
f - > store_32 ( uint32_t ( a . size ( ) ) ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < a . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-12-15 12:38:24 +01:00
write_variant ( f , a [ i ] , resource_set , external_resources , string_map ) ;
2014-02-10 02:10:30 +01:00
}
} break ;
2017-01-11 04:52:51 +01:00
case Variant : : POOL_BYTE_ARRAY : {
2014-02-10 02:10:30 +01:00
f - > store_32 ( VARIANT_RAW_ARRAY ) ;
2017-01-07 22:25:37 +01:00
PoolVector < uint8_t > arr = p_property ;
2017-03-05 16:44:50 +01:00
int len = arr . size ( ) ;
2014-02-10 02:10:30 +01:00
f - > store_32 ( len ) ;
2017-01-07 22:25:37 +01:00
PoolVector < uint8_t > : : Read r = arr . read ( ) ;
2017-03-05 16:44:50 +01:00
f - > store_buffer ( r . ptr ( ) , len ) ;
2017-12-15 12:38:24 +01:00
_pad_buffer ( f , len ) ;
2014-02-10 02:10:30 +01:00
} break ;
2017-01-11 04:52:51 +01:00
case Variant : : POOL_INT_ARRAY : {
2014-02-10 02:10:30 +01:00
f - > store_32 ( VARIANT_INT_ARRAY ) ;
2017-01-07 22:25:37 +01:00
PoolVector < int > arr = p_property ;
2017-03-05 16:44:50 +01:00
int len = arr . size ( ) ;
2014-02-10 02:10:30 +01:00
f - > store_32 ( len ) ;
2017-01-07 22:25:37 +01:00
PoolVector < int > : : Read r = arr . read ( ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < len ; i + + )
2014-02-10 02:10:30 +01:00
f - > store_32 ( r [ i ] ) ;
} break ;
2017-01-11 04:52:51 +01:00
case Variant : : POOL_REAL_ARRAY : {
2014-02-10 02:10:30 +01:00
f - > store_32 ( VARIANT_REAL_ARRAY ) ;
2017-01-07 22:25:37 +01:00
PoolVector < real_t > arr = p_property ;
2017-03-05 16:44:50 +01:00
int len = arr . size ( ) ;
2014-02-10 02:10:30 +01:00
f - > store_32 ( len ) ;
2017-01-07 22:25:37 +01:00
PoolVector < real_t > : : Read r = arr . read ( ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < len ; i + + ) {
2014-02-10 02:10:30 +01:00
f - > store_real ( r [ i ] ) ;
}
} break ;
2017-01-11 04:52:51 +01:00
case Variant : : POOL_STRING_ARRAY : {
2014-02-10 02:10:30 +01:00
f - > store_32 ( VARIANT_STRING_ARRAY ) ;
2017-01-07 22:25:37 +01:00
PoolVector < String > arr = p_property ;
2017-03-05 16:44:50 +01:00
int len = arr . size ( ) ;
2014-02-10 02:10:30 +01:00
f - > store_32 ( len ) ;
2017-01-07 22:25:37 +01:00
PoolVector < String > : : Read r = arr . read ( ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < len ; i + + ) {
2017-12-15 12:38:24 +01:00
save_unicode_string ( f , r [ i ] ) ;
2014-02-10 02:10:30 +01:00
}
} break ;
2017-01-11 04:52:51 +01:00
case Variant : : POOL_VECTOR3_ARRAY : {
2014-02-10 02:10:30 +01:00
f - > store_32 ( VARIANT_VECTOR3_ARRAY ) ;
2017-01-07 22:25:37 +01:00
PoolVector < Vector3 > arr = p_property ;
2017-03-05 16:44:50 +01:00
int len = arr . size ( ) ;
2014-02-10 02:10:30 +01:00
f - > store_32 ( len ) ;
2017-01-07 22:25:37 +01:00
PoolVector < Vector3 > : : Read r = arr . read ( ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < len ; i + + ) {
2014-02-10 02:10:30 +01:00
f - > store_real ( r [ i ] . x ) ;
f - > store_real ( r [ i ] . y ) ;
f - > store_real ( r [ i ] . z ) ;
}
} break ;
2017-01-11 04:52:51 +01:00
case Variant : : POOL_VECTOR2_ARRAY : {
2014-02-10 02:10:30 +01:00
f - > store_32 ( VARIANT_VECTOR2_ARRAY ) ;
2017-01-07 22:25:37 +01:00
PoolVector < Vector2 > arr = p_property ;
2017-03-05 16:44:50 +01:00
int len = arr . size ( ) ;
2014-02-10 02:10:30 +01:00
f - > store_32 ( len ) ;
2017-01-07 22:25:37 +01:00
PoolVector < Vector2 > : : Read r = arr . read ( ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < len ; i + + ) {
2014-02-10 02:10:30 +01:00
f - > store_real ( r [ i ] . x ) ;
f - > store_real ( r [ i ] . y ) ;
}
} break ;
2017-01-11 04:52:51 +01:00
case Variant : : POOL_COLOR_ARRAY : {
2014-02-10 02:10:30 +01:00
f - > store_32 ( VARIANT_COLOR_ARRAY ) ;
2017-01-07 22:25:37 +01:00
PoolVector < Color > arr = p_property ;
2017-03-05 16:44:50 +01:00
int len = arr . size ( ) ;
2014-02-10 02:10:30 +01:00
f - > store_32 ( len ) ;
2017-01-07 22:25:37 +01:00
PoolVector < Color > : : Read r = arr . read ( ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < len ; i + + ) {
2014-02-10 02:10:30 +01:00
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 : {
2019-08-15 04:57:49 +02:00
ERR_FAIL_MSG ( " Invalid variant. " ) ;
2014-02-10 02:10:30 +01:00
}
}
}
2017-03-05 16:44:50 +01:00
void ResourceFormatSaverBinaryInstance : : _find_resources ( const Variant & p_variant , bool p_main ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
switch ( p_variant . get_type ( ) ) {
2014-02-10 02:10:30 +01:00
case Variant : : OBJECT : {
RES res = p_variant . operator RefPtr ( ) ;
2015-08-24 01:15:56 +02:00
if ( res . is_null ( ) | | external_resources . has ( res ) )
2014-02-10 02:10:30 +01:00
return ;
2017-03-05 16:44:50 +01:00
if ( ! p_main & & ( ! bundle_resources ) & & res - > get_path ( ) . length ( ) & & res - > get_path ( ) . find ( " :: " ) = = - 1 ) {
2019-02-24 14:45:08 +01:00
if ( res - > get_path ( ) = = path ) {
ERR_PRINTS ( " Circular reference to resource being saved found: ' " + local_path + " ' will be null next time it's loaded. " ) ;
return ;
}
2015-08-24 01:15:56 +02:00
int idx = external_resources . size ( ) ;
2017-03-05 16:44:50 +01:00
external_resources [ res ] = idx ;
2014-02-10 02:10:30 +01:00
return ;
}
2015-06-22 05:03:19 +02:00
if ( resource_set . has ( res ) )
2014-02-10 02:10:30 +01:00
return ;
List < PropertyInfo > property_list ;
res - > get_property_list ( & property_list ) ;
2017-03-05 16:44:50 +01:00
for ( List < PropertyInfo > : : Element * E = property_list . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( E - > get ( ) . usage & PROPERTY_USAGE_STORAGE ) {
2014-02-10 02:10:30 +01:00
2019-02-22 00:49:42 +01:00
Variant value = res - > get ( E - > get ( ) . name ) ;
if ( E - > get ( ) . usage & PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT ) {
RES sres = value ;
if ( sres . is_valid ( ) ) {
NonPersistentKey npk ;
npk . base = res ;
npk . property = E - > get ( ) . name ;
non_persistent_map [ npk ] = sres ;
resource_set . insert ( sres ) ;
saved_resources . push_back ( sres ) ;
}
} else {
_find_resources ( value ) ;
}
2014-02-10 02:10:30 +01:00
}
}
2015-06-22 05:03:19 +02:00
resource_set . insert ( res ) ;
2014-02-10 02:10:30 +01:00
saved_resources . push_back ( res ) ;
} break ;
case Variant : : ARRAY : {
2017-03-05 16:44:50 +01:00
Array varray = p_variant ;
int len = varray . size ( ) ;
for ( int i = 0 ; i < len ; i + + ) {
2014-02-10 02:10:30 +01:00
2019-06-26 15:08:25 +02:00
const Variant & v = varray . get ( i ) ;
2014-02-10 02:10:30 +01:00
_find_resources ( v ) ;
}
} break ;
case Variant : : DICTIONARY : {
2017-03-05 16:44:50 +01:00
Dictionary d = p_variant ;
2014-02-10 02:10:30 +01:00
List < Variant > keys ;
d . get_key_list ( & keys ) ;
2017-03-05 16:44:50 +01:00
for ( List < Variant > : : Element * E = keys . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
_find_resources ( E - > get ( ) ) ;
Variant v = d [ E - > get ( ) ] ;
_find_resources ( v ) ;
}
} break ;
case Variant : : NODE_PATH : {
//take the chance and save node path strings
NodePath np = p_variant ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < np . get_name_count ( ) ; i + + )
2014-02-10 02:10:30 +01:00
get_string_index ( np . get_name ( i ) ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < np . get_subname_count ( ) ; i + + )
2014-02-10 02:10:30 +01:00
get_string_index ( np . get_subname ( i ) ) ;
} break ;
2019-04-09 17:08:36 +02:00
default : {
}
2014-02-10 02:10:30 +01:00
}
}
2017-12-15 12:38:24 +01:00
void ResourceFormatSaverBinaryInstance : : save_unicode_string ( FileAccess * f , const String & p_string , bool p_bit_on_len ) {
2014-02-10 02:10:30 +01:00
CharString utf8 = p_string . utf8 ( ) ;
2017-12-15 12:38:24 +01:00
if ( p_bit_on_len ) {
2018-09-26 16:35:32 +02:00
f - > store_32 ( ( utf8 . length ( ) + 1 ) | 0x80000000 ) ;
2017-12-15 12:38:24 +01:00
} else {
f - > store_32 ( utf8 . length ( ) + 1 ) ;
}
2017-03-05 16:44:50 +01:00
f - > store_buffer ( ( const uint8_t * ) utf8 . get_data ( ) , utf8 . length ( ) + 1 ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
int ResourceFormatSaverBinaryInstance : : get_string_index ( const String & p_string ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
StringName s = p_string ;
2014-02-10 02:10:30 +01:00
if ( string_map . has ( s ) )
return string_map [ s ] ;
2017-03-05 16:44:50 +01:00
string_map [ s ] = strings . size ( ) ;
2014-02-10 02:10:30 +01:00
strings . push_back ( s ) ;
2017-03-05 16:44:50 +01:00
return strings . size ( ) - 1 ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
Error ResourceFormatSaverBinaryInstance : : save ( const String & p_path , const RES & p_resource , uint32_t p_flags ) {
2014-02-10 02:10:30 +01:00
Error err ;
2017-03-05 16:44:50 +01:00
if ( p_flags & ResourceSaver : : FLAG_COMPRESS ) {
FileAccessCompressed * fac = memnew ( FileAccessCompressed ) ;
2014-02-10 02:10:30 +01:00
fac - > configure ( " RSCC " ) ;
2017-03-05 16:44:50 +01:00
f = fac ;
err = fac - > _open ( p_path , FileAccess : : WRITE ) ;
2014-02-10 02:10:30 +01:00
if ( err )
memdelete ( f ) ;
} else {
2017-03-05 16:44:50 +01:00
f = FileAccess : : open ( p_path , FileAccess : : WRITE , & err ) ;
2014-02-10 02:10:30 +01:00
}
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( err ! = OK , err , " Cannot create file ' " + p_path + " '. " ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
relative_paths = p_flags & ResourceSaver : : FLAG_RELATIVE_PATHS ;
skip_editor = p_flags & ResourceSaver : : FLAG_OMIT_EDITOR_PROPERTIES ;
bundle_resources = p_flags & ResourceSaver : : FLAG_BUNDLE_RESOURCES ;
big_endian = p_flags & ResourceSaver : : FLAG_SAVE_BIG_ENDIAN ;
takeover_paths = p_flags & ResourceSaver : : FLAG_REPLACE_SUBRESOURCE_PATHS ;
2014-03-14 02:57:24 +01:00
2014-06-28 04:21:45 +02:00
if ( ! p_path . begins_with ( " res:// " ) )
2017-03-05 16:44:50 +01:00
takeover_paths = false ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
local_path = p_path . get_base_dir ( ) ;
2019-02-24 14:45:08 +01:00
path = ProjectSettings : : get_singleton ( ) - > localize_path ( p_path ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
_find_resources ( p_resource , true ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( ! ( p_flags & ResourceSaver : : FLAG_COMPRESS ) ) {
2014-02-10 02:10:30 +01:00
//save header compressed
2017-03-05 16:44:50 +01:00
static const uint8_t header [ 4 ] = { ' R ' , ' S ' , ' R ' , ' C ' } ;
f - > store_buffer ( header , 4 ) ;
2014-02-10 02:10:30 +01:00
}
if ( big_endian ) {
f - > store_32 ( 1 ) ;
f - > set_endian_swap ( true ) ;
} else
f - > store_32 ( 0 ) ;
f - > store_32 ( 0 ) ; //64 bits file, false for now
f - > store_32 ( VERSION_MAJOR ) ;
f - > store_32 ( VERSION_MINOR ) ;
f - > store_32 ( FORMAT_VERSION ) ;
2017-03-05 16:44:50 +01:00
if ( f - > get_error ( ) ! = OK & & f - > get_error ( ) ! = ERR_FILE_EOF ) {
2015-03-02 04:54:10 +01:00
f - > close ( ) ;
2019-08-30 13:46:05 +02:00
memdelete ( f ) ;
2015-03-02 04:54:10 +01:00
return ERR_CANT_CREATE ;
}
2017-12-15 12:38:24 +01:00
save_unicode_string ( f , p_resource - > get_class ( ) ) ;
2017-09-02 22:32:31 +02:00
f - > store_64 ( 0 ) ; //offset to import metadata
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < 14 ; i + + )
2014-02-10 02:10:30 +01:00
f - > store_32 ( 0 ) ; // reserved
List < ResourceData > resources ;
{
2017-03-05 16:44:50 +01:00
for ( List < RES > : : Element * E = saved_resources . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
ResourceData & rd = resources . push_back ( ResourceData ( ) ) - > get ( ) ;
2017-03-05 16:44:50 +01:00
rd . type = E - > get ( ) - > get_class ( ) ;
2014-02-10 02:10:30 +01:00
List < PropertyInfo > property_list ;
2017-03-05 16:44:50 +01:00
E - > get ( ) - > get_property_list ( & property_list ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( List < PropertyInfo > : : Element * F = property_list . front ( ) ; F ; F = F - > next ( ) ) {
2014-02-10 02:10:30 +01:00
if ( skip_editor & & F - > get ( ) . name . begins_with ( " __editor " ) )
continue ;
2017-09-07 21:48:50 +02:00
if ( ( F - > get ( ) . usage & PROPERTY_USAGE_STORAGE ) ) {
2014-02-10 02:10:30 +01:00
Property p ;
2017-03-05 16:44:50 +01:00
p . name_idx = get_string_index ( F - > get ( ) . name ) ;
2019-02-22 00:49:42 +01:00
if ( F - > get ( ) . usage & PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT ) {
NonPersistentKey npk ;
npk . base = E - > get ( ) ;
npk . property = F - > get ( ) . name ;
if ( non_persistent_map . has ( npk ) ) {
p . value = non_persistent_map [ npk ] ;
}
} else {
p . value = E - > get ( ) - > get ( F - > get ( ) . name ) ;
}
2018-11-08 15:30:02 +01:00
Variant default_value = ClassDB : : class_get_default_property_value ( E - > get ( ) - > get_class ( ) , F - > get ( ) . name ) ;
if ( default_value . get_type ( ) ! = Variant : : NIL & & bool ( Variant : : evaluate ( Variant : : OP_EQUAL , p . value , default_value ) ) ) {
2014-02-10 02:10:30 +01:00
continue ;
2018-11-08 15:30:02 +01:00
}
2017-03-05 16:44:50 +01:00
p . pi = F - > get ( ) ;
2014-02-10 02:10:30 +01:00
rd . properties . push_back ( p ) ;
}
}
}
}
f - > store_32 ( strings . size ( ) ) ; //string table size
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < strings . size ( ) ; i + + ) {
2017-12-15 12:38:24 +01:00
save_unicode_string ( f , strings [ i ] ) ;
2014-02-10 02:10:30 +01:00
}
// save external resource table
f - > store_32 ( external_resources . size ( ) ) ; //amount of external resources
2015-08-24 01:15:56 +02:00
Vector < RES > save_order ;
save_order . resize ( external_resources . size ( ) ) ;
2017-03-05 16:44:50 +01:00
for ( Map < RES , int > : : Element * E = external_resources . front ( ) ; E ; E = E - > next ( ) ) {
2018-07-25 03:11:03 +02:00
save_order . write [ E - > get ( ) ] = E - > key ( ) ;
2015-08-24 01:15:56 +02:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < save_order . size ( ) ; i + + ) {
2015-08-24 01:15:56 +02:00
2017-12-15 12:38:24 +01:00
save_unicode_string ( f , save_order [ i ] - > get_save_class ( ) ) ;
2015-08-24 01:15:56 +02:00
String path = save_order [ i ] - > get_path ( ) ;
2017-03-05 16:44:50 +01:00
path = relative_paths ? local_path . path_to_file ( path ) : path ;
2017-12-15 12:38:24 +01:00
save_unicode_string ( f , path ) ;
2014-02-10 02:10:30 +01:00
}
// save internal resource table
f - > store_32 ( saved_resources . size ( ) ) ; //amount of internal resources
Vector < uint64_t > ofs_pos ;
2015-06-22 05:03:19 +02:00
Set < int > used_indices ;
2017-03-05 16:44:50 +01:00
for ( List < RES > : : Element * E = saved_resources . front ( ) ; E ; E = E - > next ( ) ) {
2015-06-22 05:03:19 +02:00
RES r = E - > get ( ) ;
2017-03-05 16:44:50 +01:00
if ( r - > get_path ( ) = = " " | | r - > get_path ( ) . find ( " :: " ) ! = - 1 ) {
2015-06-22 05:03:19 +02:00
2017-03-05 16:44:50 +01:00
if ( r - > get_subindex ( ) ! = 0 ) {
2015-06-22 05:03:19 +02:00
if ( used_indices . has ( r - > get_subindex ( ) ) ) {
r - > set_subindex ( 0 ) ; //repeated
} else {
used_indices . insert ( r - > get_subindex ( ) ) ;
}
}
}
}
2017-03-05 16:44:50 +01:00
for ( List < RES > : : Element * E = saved_resources . front ( ) ; E ; E = E - > next ( ) ) {
2015-06-22 05:03:19 +02:00
2014-02-10 02:10:30 +01:00
RES r = E - > get ( ) ;
2017-03-05 16:44:50 +01:00
if ( r - > get_path ( ) = = " " | | r - > get_path ( ) . find ( " :: " ) ! = - 1 ) {
if ( r - > get_subindex ( ) = = 0 ) {
int new_subindex = 1 ;
2015-06-22 05:03:19 +02:00
if ( used_indices . size ( ) ) {
2017-03-05 16:44:50 +01:00
new_subindex = used_indices . back ( ) - > get ( ) + 1 ;
2015-06-22 05:03:19 +02:00
}
r - > set_subindex ( new_subindex ) ;
used_indices . insert ( new_subindex ) ;
}
2017-12-15 12:38:24 +01:00
save_unicode_string ( f , " local:// " + itos ( r - > get_subindex ( ) ) ) ;
2014-06-28 04:21:45 +02:00
if ( takeover_paths ) {
2017-03-05 16:44:50 +01:00
r - > set_path ( p_path + " :: " + itos ( r - > get_subindex ( ) ) , true ) ;
2014-06-28 04:21:45 +02:00
}
2016-08-31 22:58:51 +02:00
# ifdef TOOLS_ENABLED
r - > set_edited ( false ) ;
# endif
2015-10-22 04:57:43 +02:00
} else {
2017-12-15 12:38:24 +01:00
save_unicode_string ( f , r - > get_path ( ) ) ; //actual external
2015-10-22 04:57:43 +02:00
}
2017-09-10 15:37:49 +02:00
ofs_pos . push_back ( f - > get_position ( ) ) ;
2014-02-10 02:10:30 +01:00
f - > store_64 ( 0 ) ; //offset in 64 bits
}
Vector < uint64_t > ofs_table ;
2017-08-26 17:46:49 +02:00
//now actually save the resources
2017-03-05 16:44:50 +01:00
for ( List < ResourceData > : : Element * E = resources . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
ResourceData & rd = E - > get ( ) ;
2014-02-10 02:10:30 +01:00
2017-09-10 15:37:49 +02:00
ofs_table . push_back ( f - > get_position ( ) ) ;
2017-12-15 12:38:24 +01:00
save_unicode_string ( f , rd . type ) ;
2014-02-10 02:10:30 +01:00
f - > store_32 ( rd . properties . size ( ) ) ;
2017-03-05 16:44:50 +01:00
for ( List < Property > : : Element * F = rd . properties . front ( ) ; F ; F = F - > next ( ) ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Property & p = F - > get ( ) ;
2014-02-10 02:10:30 +01:00
f - > store_32 ( p . name_idx ) ;
2017-12-15 12:38:24 +01:00
_write_variant ( p . value , F - > get ( ) . pi ) ;
2014-02-10 02:10:30 +01:00
}
}
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < ofs_table . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
f - > seek ( ofs_pos [ i ] ) ;
f - > store_64 ( ofs_table [ i ] ) ;
}
f - > seek_end ( ) ;
2017-03-05 16:44:50 +01:00
f - > store_buffer ( ( const uint8_t * ) " RSRC " , 4 ) ; //magic at end
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( f - > get_error ( ) ! = OK & & f - > get_error ( ) ! = ERR_FILE_EOF ) {
2015-03-02 04:54:10 +01:00
f - > close ( ) ;
2019-08-30 13:46:05 +02:00
memdelete ( f ) ;
2015-03-02 04:54:10 +01:00
return ERR_CANT_CREATE ;
}
2014-02-10 02:10:30 +01:00
f - > close ( ) ;
2019-08-30 13:46:05 +02:00
memdelete ( f ) ;
2014-02-10 02:10:30 +01:00
return OK ;
}
2017-03-05 16:44:50 +01:00
Error ResourceFormatSaverBinary : : save ( const String & p_path , const RES & p_resource , uint32_t p_flags ) {
2014-02-10 02:10:30 +01:00
2017-07-19 22:00:46 +02:00
String local_path = ProjectSettings : : get_singleton ( ) - > localize_path ( p_path ) ;
2014-02-10 02:10:30 +01:00
ResourceFormatSaverBinaryInstance saver ;
2017-03-05 16:44:50 +01:00
return saver . save ( local_path , p_resource , p_flags ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
bool ResourceFormatSaverBinary : : recognize ( const RES & p_resource ) const {
2014-02-10 02:10:30 +01:00
return true ; //all recognized
}
2017-03-05 16:44:50 +01:00
void ResourceFormatSaverBinary : : get_recognized_extensions ( const RES & p_resource , List < String > * p_extensions ) const {
2014-02-10 02:10:30 +01:00
String base = p_resource - > get_base_extension ( ) . to_lower ( ) ;
2016-06-28 18:58:40 +02:00
p_extensions - > push_back ( base ) ;
2017-03-05 16:44:50 +01:00
if ( base ! = " res " )
2017-02-15 12:29:46 +01:00
p_extensions - > push_back ( " res " ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
ResourceFormatSaverBinary * ResourceFormatSaverBinary : : singleton = NULL ;
2015-08-24 01:15:56 +02:00
ResourceFormatSaverBinary : : ResourceFormatSaverBinary ( ) {
2017-03-05 16:44:50 +01:00
singleton = this ;
2015-08-24 01:15:56 +02:00
}