2014-02-10 01:10:30 +00:00
/*************************************************************************/
/* resource_format_binary.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
2017-01-01 21:01:57 +00:00
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
2014-02-10 01:10:30 +00: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. */
/*************************************************************************/
# include "version.h"
# include "resource_format_binary.h"
# include "globals.h"
# include "io/file_access_compressed.h"
# include "io/marshalls.h"
2015-08-23 23:15:56 +00:00
# include "os/dir_access.h"
2014-02-10 01:10:30 +00:00
//#define print_bl(m_what) print_line(m_what)
# define print_bl(m_what)
enum {
//numbering must be different from variant, in case new variant types are added (variant must be always contiguous for jumptable optimization)
VARIANT_NIL = 1 ,
VARIANT_BOOL = 2 ,
VARIANT_INT = 3 ,
VARIANT_REAL = 4 ,
VARIANT_STRING = 5 ,
VARIANT_VECTOR2 = 10 ,
VARIANT_RECT2 = 11 ,
VARIANT_VECTOR3 = 12 ,
VARIANT_PLANE = 13 ,
VARIANT_QUAT = 14 ,
VARIANT_AABB = 15 ,
VARIANT_MATRIX3 = 16 ,
VARIANT_TRANSFORM = 17 ,
VARIANT_MATRIX32 = 18 ,
VARIANT_COLOR = 20 ,
VARIANT_IMAGE = 21 ,
VARIANT_NODE_PATH = 22 ,
VARIANT_RID = 23 ,
VARIANT_OBJECT = 24 ,
VARIANT_INPUT_EVENT = 25 ,
VARIANT_DICTIONARY = 26 ,
VARIANT_ARRAY = 30 ,
VARIANT_RAW_ARRAY = 31 ,
VARIANT_INT_ARRAY = 32 ,
VARIANT_REAL_ARRAY = 33 ,
VARIANT_STRING_ARRAY = 34 ,
VARIANT_VECTOR3_ARRAY = 35 ,
VARIANT_COLOR_ARRAY = 36 ,
VARIANT_VECTOR2_ARRAY = 37 ,
IMAGE_ENCODING_EMPTY = 0 ,
IMAGE_ENCODING_RAW = 1 ,
IMAGE_ENCODING_LOSSLESS = 2 ,
IMAGE_ENCODING_LOSSY = 3 ,
OBJECT_EMPTY = 0 ,
OBJECT_EXTERNAL_RESOURCE = 1 ,
OBJECT_INTERNAL_RESOURCE = 2 ,
2015-08-23 23:15:56 +00:00
OBJECT_EXTERNAL_RESOURCE_INDEX = 3 ,
FORMAT_VERSION = 1 ,
FORMAT_VERSION_CAN_RENAME_DEPS = 1
2014-02-10 01:10:30 +00:00
} ;
void ResourceInteractiveLoaderBinary : : _advance_padding ( uint32_t p_len ) {
uint32_t extra = 4 - ( p_len % 4 ) ;
if ( extra < 4 ) {
for ( uint32_t i = 0 ; i < extra ; i + + )
f - > get_8 ( ) ; //pad to 32
}
}
Error ResourceInteractiveLoaderBinary : : parse_variant ( Variant & r_v ) {
uint32_t type = f - > get_32 ( ) ;
print_bl ( " find property of type: " + itos ( type ) ) ;
switch ( type ) {
case VARIANT_NIL : {
r_v = Variant ( ) ;
} break ;
case VARIANT_BOOL : {
r_v = bool ( f - > get_32 ( ) ) ;
} break ;
case VARIANT_INT : {
r_v = int ( f - > get_32 ( ) ) ;
} break ;
case VARIANT_REAL : {
r_v = f - > get_real ( ) ;
} break ;
case VARIANT_STRING : {
r_v = get_unicode_string ( ) ;
} break ;
case VARIANT_VECTOR2 : {
Vector2 v ;
v . x = f - > get_real ( ) ;
v . y = f - > get_real ( ) ;
r_v = v ;
} break ;
case VARIANT_RECT2 : {
Rect2 v ;
v . pos . x = f - > get_real ( ) ;
v . pos . y = f - > get_real ( ) ;
v . size . x = f - > get_real ( ) ;
v . size . y = f - > get_real ( ) ;
r_v = v ;
} break ;
case VARIANT_VECTOR3 : {
Vector3 v ;
v . x = f - > get_real ( ) ;
v . y = f - > get_real ( ) ;
v . z = f - > get_real ( ) ;
r_v = v ;
} break ;
case VARIANT_PLANE : {
Plane v ;
v . normal . x = f - > get_real ( ) ;
v . normal . y = f - > get_real ( ) ;
v . normal . z = f - > get_real ( ) ;
v . d = f - > get_real ( ) ;
r_v = v ;
} break ;
case VARIANT_QUAT : {
Quat v ;
v . x = f - > get_real ( ) ;
v . y = f - > get_real ( ) ;
v . z = f - > get_real ( ) ;
v . w = f - > get_real ( ) ;
r_v = v ;
} break ;
case VARIANT_AABB : {
AABB v ;
v . pos . x = f - > get_real ( ) ;
v . pos . y = f - > get_real ( ) ;
v . pos . z = f - > get_real ( ) ;
v . size . x = f - > get_real ( ) ;
v . size . y = f - > get_real ( ) ;
v . size . z = f - > get_real ( ) ;
r_v = v ;
} break ;
case VARIANT_MATRIX32 : {
Matrix32 v ;
v . elements [ 0 ] . x = f - > get_real ( ) ;
v . elements [ 0 ] . y = f - > get_real ( ) ;
v . elements [ 1 ] . x = f - > get_real ( ) ;
v . elements [ 1 ] . y = f - > get_real ( ) ;
v . elements [ 2 ] . x = f - > get_real ( ) ;
v . elements [ 2 ] . y = f - > get_real ( ) ;
r_v = v ;
} break ;
case VARIANT_MATRIX3 : {
Matrix3 v ;
v . elements [ 0 ] . x = f - > get_real ( ) ;
v . elements [ 0 ] . y = f - > get_real ( ) ;
v . elements [ 0 ] . z = f - > get_real ( ) ;
v . elements [ 1 ] . x = f - > get_real ( ) ;
v . elements [ 1 ] . y = f - > get_real ( ) ;
v . elements [ 1 ] . z = f - > get_real ( ) ;
v . elements [ 2 ] . x = f - > get_real ( ) ;
v . elements [ 2 ] . y = f - > get_real ( ) ;
v . elements [ 2 ] . z = f - > get_real ( ) ;
r_v = v ;
} break ;
case VARIANT_TRANSFORM : {
Transform v ;
v . basis . elements [ 0 ] . x = f - > get_real ( ) ;
v . basis . elements [ 0 ] . y = f - > get_real ( ) ;
v . basis . elements [ 0 ] . z = f - > get_real ( ) ;
v . basis . elements [ 1 ] . x = f - > get_real ( ) ;
v . basis . elements [ 1 ] . y = f - > get_real ( ) ;
v . basis . elements [ 1 ] . z = f - > get_real ( ) ;
v . basis . elements [ 2 ] . x = f - > get_real ( ) ;
v . basis . elements [ 2 ] . y = f - > get_real ( ) ;
v . basis . elements [ 2 ] . z = f - > get_real ( ) ;
v . origin . x = f - > get_real ( ) ;
v . origin . y = f - > get_real ( ) ;
v . origin . z = f - > get_real ( ) ;
r_v = v ;
} break ;
case VARIANT_COLOR : {
Color v ;
v . r = f - > get_real ( ) ;
v . g = f - > get_real ( ) ;
v . b = f - > get_real ( ) ;
v . a = f - > get_real ( ) ;
r_v = v ;
} break ;
case VARIANT_IMAGE : {
uint32_t encoding = f - > get_32 ( ) ;
if ( encoding = = IMAGE_ENCODING_EMPTY ) {
r_v = Variant ( ) ;
break ;
} else if ( encoding = = IMAGE_ENCODING_RAW ) {
uint32_t width = f - > get_32 ( ) ;
uint32_t height = f - > get_32 ( ) ;
uint32_t mipmaps = f - > get_32 ( ) ;
uint32_t format = f - > get_32 ( ) ;
2016-10-03 19:33:42 +00:00
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 ) {
2014-02-10 01:10:30 +00:00
2016-10-03 19:33:42 +00:00
ERR_PRINT ( " Format version for encoded binary image is too new " ) ;
return ERR_PARSE_ERROR ;
2014-02-10 01:10:30 +00:00
}
2016-10-03 19:33:42 +00:00
Image : : Format fmt = Image : : Format ( format & format_version_mask ) ; //if format changes, we can add a compatibility bit on top
2014-02-10 01:10:30 +00:00
uint32_t datalen = f - > get_32 ( ) ;
DVector < uint8_t > imgdata ;
imgdata . resize ( datalen ) ;
DVector < uint8_t > : : Write w = imgdata . write ( ) ;
f - > get_buffer ( w . ptr ( ) , datalen ) ;
_advance_padding ( datalen ) ;
w = DVector < uint8_t > : : Write ( ) ;
r_v = Image ( width , height , mipmaps , fmt , imgdata ) ;
} else {
//compressed
DVector < uint8_t > data ;
data . resize ( f - > get_32 ( ) ) ;
DVector < uint8_t > : : Write w = data . write ( ) ;
f - > get_buffer ( w . ptr ( ) , data . size ( ) ) ;
w = DVector < uint8_t > : : Write ( ) ;
Image img ;
if ( encoding = = IMAGE_ENCODING_LOSSY & & Image : : lossy_unpacker ) {
img = Image : : lossy_unpacker ( data ) ;
} else if ( encoding = = IMAGE_ENCODING_LOSSLESS & & Image : : lossless_unpacker ) {
img = Image : : lossless_unpacker ( data ) ;
}
_advance_padding ( data . size ( ) ) ;
r_v = img ;
}
} break ;
case VARIANT_NODE_PATH : {
Vector < StringName > names ;
Vector < StringName > subnames ;
StringName property ;
bool absolute ;
int name_count = f - > get_16 ( ) ;
uint32_t subname_count = f - > get_16 ( ) ;
absolute = subname_count & 0x8000 ;
subname_count & = 0x7FFF ;
for ( int i = 0 ; i < name_count ; i + + )
names . push_back ( string_map [ f - > get_32 ( ) ] ) ;
for ( uint32_t i = 0 ; i < subname_count ; i + + )
subnames . push_back ( string_map [ f - > get_32 ( ) ] ) ;
property = string_map [ f - > get_32 ( ) ] ;
NodePath np = NodePath ( names , subnames , absolute , property ) ;
//print_line("got path: "+String(np));
r_v = np ;
} break ;
case VARIANT_RID : {
r_v = f - > get_32 ( ) ;
} break ;
case VARIANT_OBJECT : {
uint32_t type = f - > get_32 ( ) ;
switch ( type ) {
case OBJECT_EMPTY : {
//do none
} break ;
case OBJECT_INTERNAL_RESOURCE : {
uint32_t index = f - > get_32 ( ) ;
2016-03-08 23:00:52 +00:00
String path = res_path + " :: " + itos ( index ) ;
2014-02-10 01:10:30 +00:00
RES res = ResourceLoader : : load ( path ) ;
if ( res . is_null ( ) ) {
WARN_PRINT ( String ( " Couldn't load resource: " + path ) . utf8 ( ) . get_data ( ) ) ;
}
r_v = res ;
} break ;
case OBJECT_EXTERNAL_RESOURCE : {
2015-08-23 23:15:56 +00:00
//old file format, still around for compatibility
2014-02-10 01:10:30 +00:00
String type = get_unicode_string ( ) ;
String path = get_unicode_string ( ) ;
if ( path . find ( " :// " ) = = - 1 & & path . is_rel_path ( ) ) {
// path is relative to file being loaded, so convert to a resource path
2015-04-18 19:33:31 +00:00
path = Globals : : get_singleton ( ) - > localize_path ( res_path . get_base_dir ( ) . plus_file ( path ) ) ;
2014-02-10 01:10:30 +00:00
}
2015-08-23 23:15:56 +00:00
if ( remaps . find ( path ) ) {
path = remaps [ path ] ;
}
2014-02-10 01:10:30 +00:00
RES res = ResourceLoader : : load ( path , type ) ;
if ( res . is_null ( ) ) {
WARN_PRINT ( String ( " Couldn't load resource: " + path ) . utf8 ( ) . get_data ( ) ) ;
}
r_v = res ;
2015-08-23 23:15:56 +00:00
} break ;
case OBJECT_EXTERNAL_RESOURCE_INDEX : {
//new file format, just refers to an index in the external list
uint32_t erindex = f - > get_32 ( ) ;
if ( erindex > = external_resources . size ( ) ) {
WARN_PRINT ( " Broken external resource! (index out of size " ) ;
r_v = Variant ( ) ;
} else {
String type = external_resources [ erindex ] . type ;
String path = external_resources [ erindex ] . path ;
if ( path . find ( " :// " ) = = - 1 & & path . is_rel_path ( ) ) {
// path is relative to file being loaded, so convert to a resource path
path = Globals : : get_singleton ( ) - > localize_path ( res_path . get_base_dir ( ) . plus_file ( path ) ) ;
}
RES res = ResourceLoader : : load ( path , type ) ;
if ( res . is_null ( ) ) {
WARN_PRINT ( String ( " Couldn't load resource: " + path ) . utf8 ( ) . get_data ( ) ) ;
}
r_v = res ;
}
2014-02-10 01:10:30 +00:00
} break ;
default : {
ERR_FAIL_V ( ERR_FILE_CORRUPT ) ;
} break ;
}
} break ;
case VARIANT_INPUT_EVENT : {
2016-08-07 22:22:33 +00:00
InputEvent ev ;
ev . type = f - > get_32 ( ) ; //will only work for null though.
r_v = ev ;
2014-02-10 01:10:30 +00:00
} break ;
case VARIANT_DICTIONARY : {
2016-08-07 22:22:33 +00:00
uint32_t len = f - > get_32 ( ) ;
Dictionary d ( len & 0x80000000 ) ; //last bit means shared
len & = 0x7FFFFFFF ;
for ( uint32_t i = 0 ; i < len ; i + + ) {
2014-02-10 01:10:30 +00:00
Variant key ;
Error err = parse_variant ( key ) ;
ERR_FAIL_COND_V ( err , ERR_FILE_CORRUPT ) ;
Variant value ;
err = parse_variant ( value ) ;
ERR_FAIL_COND_V ( err , ERR_FILE_CORRUPT ) ;
d [ key ] = value ;
}
r_v = d ;
} break ;
case VARIANT_ARRAY : {
2016-08-07 22:22:33 +00:00
uint32_t len = f - > get_32 ( ) ;
Array a ( len & 0x80000000 ) ; //last bit means shared
len & = 0x7FFFFFFF ;
2014-02-10 01:10:30 +00:00
a . resize ( len ) ;
2016-08-07 22:22:33 +00:00
for ( uint32_t i = 0 ; i < len ; i + + ) {
2014-02-10 01:10:30 +00:00
Variant val ;
Error err = parse_variant ( val ) ;
ERR_FAIL_COND_V ( err , ERR_FILE_CORRUPT ) ;
a [ i ] = val ;
}
r_v = a ;
} break ;
case VARIANT_RAW_ARRAY : {
uint32_t len = f - > get_32 ( ) ;
DVector < uint8_t > array ;
array . resize ( len ) ;
DVector < uint8_t > : : Write w = array . write ( ) ;
f - > get_buffer ( w . ptr ( ) , len ) ;
_advance_padding ( len ) ;
w = DVector < uint8_t > : : Write ( ) ;
r_v = array ;
} break ;
case VARIANT_INT_ARRAY : {
uint32_t len = f - > get_32 ( ) ;
DVector < int > array ;
array . resize ( len ) ;
DVector < int > : : Write w = array . write ( ) ;
f - > get_buffer ( ( uint8_t * ) w . ptr ( ) , len * 4 ) ;
# ifdef BIG_ENDIAN_ENABLED
{
uint32_t * ptr = ( uint32_t * ) w . ptr ( ) ;
for ( int i = 0 ; i < len ; i + + ) {
ptr [ i ] = BSWAP32 ( ptr [ i ] ) ;
}
}
# endif
w = DVector < int > : : Write ( ) ;
r_v = array ;
} break ;
case VARIANT_REAL_ARRAY : {
uint32_t len = f - > get_32 ( ) ;
DVector < real_t > array ;
array . resize ( len ) ;
DVector < real_t > : : Write w = array . write ( ) ;
f - > get_buffer ( ( uint8_t * ) w . ptr ( ) , len * sizeof ( real_t ) ) ;
# ifdef BIG_ENDIAN_ENABLED
{
uint32_t * ptr = ( uint32_t * ) w . ptr ( ) ;
for ( int i = 0 ; i < len ; i + + ) {
ptr [ i ] = BSWAP32 ( ptr [ i ] ) ;
}
}
# endif
w = DVector < real_t > : : Write ( ) ;
r_v = array ;
} break ;
case VARIANT_STRING_ARRAY : {
uint32_t len = f - > get_32 ( ) ;
DVector < String > array ;
array . resize ( len ) ;
DVector < String > : : Write w = array . write ( ) ;
for ( uint32_t i = 0 ; i < len ; i + + )
w [ i ] = get_unicode_string ( ) ;
w = DVector < String > : : Write ( ) ;
r_v = array ;
} break ;
case VARIANT_VECTOR2_ARRAY : {
uint32_t len = f - > get_32 ( ) ;
DVector < Vector2 > array ;
array . resize ( len ) ;
DVector < Vector2 > : : Write w = array . write ( ) ;
if ( sizeof ( Vector2 ) = = 8 ) {
f - > get_buffer ( ( uint8_t * ) w . ptr ( ) , len * sizeof ( real_t ) * 2 ) ;
# ifdef BIG_ENDIAN_ENABLED
{
uint32_t * ptr = ( uint32_t * ) w . ptr ( ) ;
for ( int i = 0 ; i < len * 2 ; i + + ) {
ptr [ i ] = BSWAP32 ( ptr [ i ] ) ;
}
}
# endif
} else {
ERR_EXPLAIN ( " Vector2 size is NOT 8! " ) ;
ERR_FAIL_V ( ERR_UNAVAILABLE ) ;
}
w = DVector < Vector2 > : : Write ( ) ;
r_v = array ;
} break ;
case VARIANT_VECTOR3_ARRAY : {
uint32_t len = f - > get_32 ( ) ;
DVector < Vector3 > array ;
array . resize ( len ) ;
DVector < Vector3 > : : Write w = array . write ( ) ;
if ( sizeof ( Vector3 ) = = 12 ) {
f - > get_buffer ( ( uint8_t * ) w . ptr ( ) , len * sizeof ( real_t ) * 3 ) ;
# ifdef BIG_ENDIAN_ENABLED
{
uint32_t * ptr = ( uint32_t * ) w . ptr ( ) ;
for ( int i = 0 ; i < len * 3 ; i + + ) {
ptr [ i ] = BSWAP32 ( ptr [ i ] ) ;
}
}
# endif
} else {
ERR_EXPLAIN ( " Vector3 size is NOT 12! " ) ;
ERR_FAIL_V ( ERR_UNAVAILABLE ) ;
}
w = DVector < Vector3 > : : Write ( ) ;
r_v = array ;
} break ;
case VARIANT_COLOR_ARRAY : {
uint32_t len = f - > get_32 ( ) ;
DVector < Color > array ;
array . resize ( len ) ;
DVector < Color > : : Write w = array . write ( ) ;
if ( sizeof ( Color ) = = 16 ) {
f - > get_buffer ( ( uint8_t * ) w . ptr ( ) , len * sizeof ( real_t ) * 4 ) ;
# ifdef BIG_ENDIAN_ENABLED
{
uint32_t * ptr = ( uint32_t * ) w . ptr ( ) ;
for ( int i = 0 ; i < len * 4 ; i + + ) {
ptr [ i ] = BSWAP32 ( ptr [ i ] ) ;
}
}
# endif
} else {
ERR_EXPLAIN ( " Color size is NOT 16! " ) ;
ERR_FAIL_V ( ERR_UNAVAILABLE ) ;
}
w = DVector < Color > : : Write ( ) ;
r_v = array ;
} break ;
default : {
ERR_FAIL_V ( ERR_FILE_CORRUPT ) ;
} break ;
}
return OK ; //never reach anyway
}
void ResourceInteractiveLoaderBinary : : set_local_path ( const String & p_local_path ) {
res_path = p_local_path ;
}
Ref < Resource > ResourceInteractiveLoaderBinary : : get_resource ( ) {
return resource ;
}
Error ResourceInteractiveLoaderBinary : : poll ( ) {
if ( error ! = OK )
return error ;
int s = stage ;
if ( s < external_resources . size ( ) ) {
2015-08-23 23:15:56 +00:00
String path = external_resources [ s ] . path ;
if ( remaps . has ( path ) ) {
path = remaps [ path ] ;
}
RES res = ResourceLoader : : load ( path , external_resources [ s ] . type ) ;
2014-02-10 01:10:30 +00:00
if ( res . is_null ( ) ) {
if ( ! ResourceLoader : : get_abort_on_missing_resources ( ) ) {
2015-08-23 23:15:56 +00:00
ResourceLoader : : notify_dependency_error ( local_path , path , external_resources [ s ] . type ) ;
2014-02-10 01:10:30 +00:00
} else {
2015-08-23 23:15:56 +00:00
error = ERR_FILE_MISSING_DEPENDENCIES ;
ERR_EXPLAIN ( " Can't load dependency: " + path ) ;
2014-02-10 01:10:30 +00:00
ERR_FAIL_V ( error ) ;
}
} else {
resource_cache . push_back ( res ) ;
}
stage + + ;
2014-03-14 01:57:24 +00:00
return error ;
2014-02-10 01:10:30 +00:00
}
s - = external_resources . size ( ) ;
if ( s > = internal_resources . size ( ) ) {
error = ERR_BUG ;
ERR_FAIL_COND_V ( s > = internal_resources . size ( ) , error ) ;
}
bool main = s = = ( internal_resources . size ( ) - 1 ) ;
//maybe it is loaded already
String path ;
2015-06-22 03:03:19 +00:00
int subindex = 0 ;
2014-02-10 01:10:30 +00:00
if ( ! main ) {
path = internal_resources [ s ] . path ;
2015-06-22 03:03:19 +00:00
if ( path . begins_with ( " local:// " ) ) {
path = path . replace_first ( " local:// " , " " ) ;
subindex = path . to_int ( ) ;
path = res_path + " :: " + path ;
}
2014-02-10 01:10:30 +00:00
if ( ResourceCache : : has ( path ) ) {
//already loaded, don't do anything
stage + + ;
error = OK ;
return error ;
}
} else {
2016-01-14 14:06:20 +00:00
if ( ! ResourceCache : : has ( res_path ) )
path = res_path ;
2014-02-10 01:10:30 +00:00
}
uint64_t offset = internal_resources [ s ] . offset ;
f - > seek ( offset ) ;
String t = get_unicode_string ( ) ;
Object * obj = ObjectTypeDB : : instance ( t ) ;
if ( ! obj ) {
error = ERR_FILE_CORRUPT ;
ERR_EXPLAIN ( local_path + " :Resource of unrecognized type in file: " + t ) ;
}
ERR_FAIL_COND_V ( ! obj , ERR_FILE_CORRUPT ) ;
Resource * r = obj - > cast_to < Resource > ( ) ;
if ( ! r ) {
error = ERR_FILE_CORRUPT ;
memdelete ( obj ) ; //bye
ERR_EXPLAIN ( local_path + " :Resoucre type in resource field not a resource, type is: " + obj - > get_type ( ) ) ;
ERR_FAIL_COND_V ( ! r , ERR_FILE_CORRUPT ) ;
}
RES res = RES ( r ) ;
r - > set_path ( path ) ;
2015-06-22 03:03:19 +00:00
r - > set_subindex ( subindex ) ;
2014-02-10 01:10:30 +00:00
int pc = f - > get_32 ( ) ;
//set properties
for ( int i = 0 ; i < pc ; i + + ) {
uint32_t name_idx = f - > get_32 ( ) ;
if ( name_idx > = ( uint32_t ) string_map . size ( ) ) {
error = ERR_FILE_CORRUPT ;
ERR_FAIL_V ( ERR_FILE_CORRUPT ) ;
}
Variant value ;
error = parse_variant ( value ) ;
if ( error )
return error ;
res - > set ( string_map [ name_idx ] , value ) ;
}
# ifdef TOOLS_ENABLED
res - > set_edited ( false ) ;
# endif
stage + + ;
resource_cache . push_back ( res ) ;
if ( main ) {
if ( importmd_ofs ) {
f - > seek ( importmd_ofs ) ;
Ref < ResourceImportMetadata > imd = memnew ( ResourceImportMetadata ) ;
imd - > set_editor ( get_unicode_string ( ) ) ;
int sc = f - > get_32 ( ) ;
for ( int i = 0 ; i < sc ; i + + ) {
String src = get_unicode_string ( ) ;
String md5 = get_unicode_string ( ) ;
imd - > add_source ( src , md5 ) ;
}
int pc = f - > get_32 ( ) ;
for ( int i = 0 ; i < pc ; i + + ) {
String name = get_unicode_string ( ) ;
Variant val ;
parse_variant ( val ) ;
imd - > set_option ( name , val ) ;
}
res - > set_import_metadata ( imd ) ;
}
f - > close ( ) ;
resource = res ;
error = ERR_FILE_EOF ;
} else {
error = OK ;
}
return OK ;
}
int ResourceInteractiveLoaderBinary : : get_stage ( ) const {
return stage ;
}
int ResourceInteractiveLoaderBinary : : get_stage_count ( ) const {
return external_resources . size ( ) + internal_resources . size ( ) ;
}
2015-08-23 23:15:56 +00:00
static void save_ustring ( FileAccess * f , const String & p_string ) {
CharString utf8 = p_string . utf8 ( ) ;
f - > store_32 ( utf8 . length ( ) + 1 ) ;
f - > store_buffer ( ( const uint8_t * ) utf8 . get_data ( ) , utf8 . length ( ) + 1 ) ;
}
static String get_ustring ( FileAccess * f ) {
int len = f - > get_32 ( ) ;
Vector < char > str_buf ;
str_buf . resize ( len ) ;
f - > get_buffer ( ( uint8_t * ) & str_buf [ 0 ] , len ) ;
String s ;
s . parse_utf8 ( & str_buf [ 0 ] ) ;
return s ;
}
2014-02-10 01:10:30 +00:00
String ResourceInteractiveLoaderBinary : : get_unicode_string ( ) {
int len = f - > get_32 ( ) ;
if ( len > str_buf . size ( ) ) {
str_buf . resize ( len ) ;
}
2015-12-09 12:08:41 +00:00
if ( len = = 0 )
return String ( ) ;
2014-02-10 01:10:30 +00:00
f - > get_buffer ( ( uint8_t * ) & str_buf [ 0 ] , len ) ;
String s ;
s . parse_utf8 ( & str_buf [ 0 ] ) ;
return s ;
}
2015-08-23 23:15:56 +00:00
void ResourceInteractiveLoaderBinary : : get_dependencies ( FileAccess * p_f , List < String > * p_dependencies , bool p_add_types ) {
2014-02-10 01:10:30 +00:00
open ( p_f ) ;
if ( error )
return ;
for ( int i = 0 ; i < external_resources . size ( ) ; i + + ) {
2014-03-14 01:57:24 +00:00
String dep = external_resources [ i ] . path ;
if ( dep . ends_with ( " * " ) ) {
dep = ResourceLoader : : guess_full_filename ( dep , external_resources [ i ] . type ) ;
}
2015-08-23 23:15:56 +00:00
if ( p_add_types & & external_resources [ i ] . type ! = String ( ) ) {
dep + = " :: " + external_resources [ i ] . type ;
}
2014-03-14 01:57:24 +00:00
p_dependencies - > push_back ( dep ) ;
2014-02-10 01:10:30 +00:00
}
}
void ResourceInteractiveLoaderBinary : : open ( FileAccess * p_f ) {
error = OK ;
f = p_f ;
uint8_t header [ 4 ] ;
f - > get_buffer ( header , 4 ) ;
if ( header [ 0 ] = = ' R ' & & header [ 1 ] = = ' S ' & & header [ 2 ] = = ' C ' & & header [ 3 ] = = ' C ' ) {
//compressed
FileAccessCompressed * fac = memnew ( FileAccessCompressed ) ;
fac - > open_after_magic ( f ) ;
f = fac ;
} else if ( header [ 0 ] ! = ' R ' | | header [ 1 ] ! = ' S ' | | header [ 2 ] ! = ' R ' | | header [ 3 ] ! = ' C ' ) {
//not normal
error = ERR_FILE_UNRECOGNIZED ;
ERR_EXPLAIN ( " Unrecognized binary resource file: " + local_path ) ;
2015-12-06 23:22:45 +00:00
ERR_FAIL ( ) ;
2014-02-10 01:10:30 +00:00
}
bool big_endian = f - > get_32 ( ) ;
# ifdef BIG_ENDIAN_ENABLED
endian_swap = ! big_endian ;
# else
bool endian_swap = big_endian ;
# endif
bool use_real64 = f - > get_32 ( ) ;
f - > set_endian_swap ( big_endian ! = 0 ) ; //read big endian if saved as big endian
uint32_t ver_major = f - > get_32 ( ) ;
uint32_t ver_minor = f - > get_32 ( ) ;
uint32_t ver_format = f - > get_32 ( ) ;
print_bl ( " big endian: " + itos ( big_endian ) ) ;
print_bl ( " endian swap: " + itos ( endian_swap ) ) ;
print_bl ( " real64: " + itos ( use_real64 ) ) ;
print_bl ( " major: " + itos ( ver_major ) ) ;
print_bl ( " minor: " + itos ( ver_minor ) ) ;
print_bl ( " format: " + itos ( ver_format ) ) ;
2015-08-23 23:15:56 +00:00
if ( ver_format > FORMAT_VERSION | | ver_major > VERSION_MAJOR ) {
2014-02-10 01:10:30 +00:00
f - > close ( ) ;
ERR_EXPLAIN ( " File Format ' " + itos ( FORMAT_VERSION ) + " . " + itos ( ver_major ) + " . " + itos ( ver_minor ) + " ' is too new! Please upgrade to a a new engine version: " + local_path ) ;
ERR_FAIL ( ) ;
}
type = get_unicode_string ( ) ;
print_bl ( " type: " + type ) ;
importmd_ofs = f - > get_64 ( ) ;
for ( int i = 0 ; i < 14 ; i + + )
f - > get_32 ( ) ; //skip a few reserved fields
uint32_t string_table_size = f - > get_32 ( ) ;
string_map . resize ( string_table_size ) ;
for ( uint32_t i = 0 ; i < string_table_size ; i + + ) {
StringName s = get_unicode_string ( ) ;
string_map [ i ] = s ;
}
print_bl ( " strings: " + itos ( string_table_size ) ) ;
uint32_t ext_resources_size = f - > get_32 ( ) ;
for ( uint32_t i = 0 ; i < ext_resources_size ; i + + ) {
ExtResoucre er ;
er . type = get_unicode_string ( ) ;
er . path = get_unicode_string ( ) ;
external_resources . push_back ( er ) ;
}
2014-03-14 01:57:24 +00:00
//see if the exporter has different set of external resources for more efficient loading
2015-08-23 23:15:56 +00:00
/*
2014-03-14 01:57:24 +00:00
String preload_depts = " deps/ " + res_path . md5_text ( ) ;
if ( Globals : : get_singleton ( ) - > has ( preload_depts ) ) {
external_resources . clear ( ) ;
//ignore external resources and use these
NodePath depts = Globals : : get_singleton ( ) - > get ( preload_depts ) ;
external_resources . resize ( depts . get_name_count ( ) ) ;
for ( int i = 0 ; i < depts . get_name_count ( ) ; i + + ) {
external_resources [ i ] . path = depts . get_name ( i ) ;
}
print_line ( res_path + " - EXTERNAL RESOURCES: " + itos ( external_resources . size ( ) ) ) ;
2015-08-23 23:15:56 +00:00
} */
2014-03-14 01:57:24 +00:00
2014-02-10 01:10:30 +00:00
print_bl ( " ext resources: " + itos ( ext_resources_size ) ) ;
uint32_t int_resources_size = f - > get_32 ( ) ;
for ( uint32_t i = 0 ; i < int_resources_size ; i + + ) {
IntResoucre ir ;
ir . path = get_unicode_string ( ) ;
ir . offset = f - > get_64 ( ) ;
internal_resources . push_back ( ir ) ;
}
print_bl ( " int resources: " + itos ( int_resources_size ) ) ;
if ( f - > eof_reached ( ) ) {
error = ERR_FILE_CORRUPT ;
ERR_EXPLAIN ( " Premature End Of File: " + local_path ) ;
ERR_FAIL ( ) ;
}
}
String ResourceInteractiveLoaderBinary : : recognize ( FileAccess * p_f ) {
error = OK ;
f = p_f ;
uint8_t header [ 4 ] ;
f - > get_buffer ( header , 4 ) ;
if ( header [ 0 ] = = ' R ' & & header [ 1 ] = = ' S ' & & header [ 2 ] = = ' C ' & & header [ 3 ] = = ' C ' ) {
//compressed
FileAccessCompressed * fac = memnew ( FileAccessCompressed ) ;
fac - > open_after_magic ( f ) ;
f = fac ;
} else if ( header [ 0 ] ! = ' R ' | | header [ 1 ] ! = ' S ' | | header [ 2 ] ! = ' R ' | | header [ 3 ] ! = ' C ' ) {
//not normal
2014-04-05 15:39:30 +00:00
error = ERR_FILE_UNRECOGNIZED ;
2014-02-10 01:10:30 +00:00
return " " ;
}
bool big_endian = f - > get_32 ( ) ;
# ifdef BIG_ENDIAN_ENABLED
endian_swap = ! big_endian ;
# else
bool endian_swap = big_endian ;
# endif
bool use_real64 = f - > get_32 ( ) ;
f - > set_endian_swap ( big_endian ! = 0 ) ; //read big endian if saved as big endian
uint32_t ver_major = f - > get_32 ( ) ;
uint32_t ver_minor = f - > get_32 ( ) ;
uint32_t ver_format = f - > get_32 ( ) ;
2015-08-23 23:15:56 +00:00
if ( ver_format > FORMAT_VERSION | | ver_major > VERSION_MAJOR ) {
2014-02-10 01:10:30 +00:00
f - > close ( ) ;
return " " ;
}
String type = get_unicode_string ( ) ;
return type ;
}
ResourceInteractiveLoaderBinary : : ResourceInteractiveLoaderBinary ( ) {
f = NULL ;
stage = 0 ;
endian_swap = false ;
use_real64 = false ;
error = OK ;
}
ResourceInteractiveLoaderBinary : : ~ ResourceInteractiveLoaderBinary ( ) {
if ( f )
memdelete ( f ) ;
}
2015-08-23 23:15:56 +00:00
Ref < ResourceInteractiveLoader > ResourceFormatLoaderBinary : : load_interactive ( const String & p_path , Error * r_error ) {
2014-02-10 01:10:30 +00:00
2015-08-23 23:15:56 +00:00
if ( r_error )
* r_error = ERR_FILE_CANT_OPEN ;
2014-02-10 01:10:30 +00:00
Error err ;
FileAccess * f = FileAccess : : open ( p_path , FileAccess : : READ , & err ) ;
if ( err ! = OK ) {
ERR_FAIL_COND_V ( err ! = OK , Ref < ResourceInteractiveLoader > ( ) ) ;
}
Ref < ResourceInteractiveLoaderBinary > ria = memnew ( ResourceInteractiveLoaderBinary ) ;
ria - > local_path = Globals : : get_singleton ( ) - > localize_path ( p_path ) ;
ria - > res_path = ria - > local_path ;
// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
ria - > open ( f ) ;
return ria ;
}
void ResourceFormatLoaderBinary : : get_recognized_extensions_for_type ( const String & p_type , List < String > * p_extensions ) const {
if ( p_type = = " " ) {
get_recognized_extensions ( p_extensions ) ;
return ;
}
List < String > extensions ;
ObjectTypeDB : : get_extensions_for_type ( p_type , & extensions ) ;
extensions . sort ( ) ;
for ( List < String > : : Element * E = extensions . front ( ) ; E ; E = E - > next ( ) ) {
String ext = E - > get ( ) . to_lower ( ) ;
p_extensions - > push_back ( ext ) ;
}
}
void ResourceFormatLoaderBinary : : get_recognized_extensions ( List < String > * p_extensions ) const {
List < String > extensions ;
ObjectTypeDB : : get_resource_base_extensions ( & extensions ) ;
extensions . sort ( ) ;
for ( List < String > : : Element * E = extensions . front ( ) ; E ; E = E - > next ( ) ) {
String ext = E - > get ( ) . to_lower ( ) ;
p_extensions - > push_back ( ext ) ;
}
}
bool ResourceFormatLoaderBinary : : handles_type ( const String & p_type ) const {
return true ; //handles all
}
Error ResourceFormatLoaderBinary : : load_import_metadata ( const String & p_path , Ref < ResourceImportMetadata > & r_var ) const {
FileAccess * f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
if ( ! f ) {
return ERR_FILE_CANT_OPEN ;
}
Ref < ResourceInteractiveLoaderBinary > ria = memnew ( ResourceInteractiveLoaderBinary ) ;
ria - > local_path = Globals : : get_singleton ( ) - > localize_path ( p_path ) ;
ria - > res_path = ria - > local_path ;
// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
ria - > recognize ( f ) ;
if ( ria - > error ! = OK )
return ERR_FILE_UNRECOGNIZED ;
f = ria - > f ;
uint64_t imp_ofs = f - > get_64 ( ) ;
if ( imp_ofs = = 0 )
return ERR_UNAVAILABLE ;
f - > seek ( imp_ofs ) ;
Ref < ResourceImportMetadata > imd = memnew ( ResourceImportMetadata ) ;
imd - > set_editor ( ria - > get_unicode_string ( ) ) ;
int sc = f - > get_32 ( ) ;
for ( int i = 0 ; i < sc ; i + + ) {
String src = ria - > get_unicode_string ( ) ;
String md5 = ria - > get_unicode_string ( ) ;
imd - > add_source ( src , md5 ) ;
}
int pc = f - > get_32 ( ) ;
for ( int i = 0 ; i < pc ; i + + ) {
String name = ria - > get_unicode_string ( ) ;
Variant val ;
ria - > parse_variant ( val ) ;
imd - > set_option ( name , val ) ;
}
r_var = imd ;
return OK ;
}
2015-08-23 23:15:56 +00:00
void ResourceFormatLoaderBinary : : get_dependencies ( const String & p_path , List < String > * p_dependencies , bool p_add_types ) {
2014-02-10 01:10:30 +00:00
FileAccess * f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
ERR_FAIL_COND ( ! f ) ;
Ref < ResourceInteractiveLoaderBinary > ria = memnew ( ResourceInteractiveLoaderBinary ) ;
ria - > local_path = Globals : : get_singleton ( ) - > localize_path ( p_path ) ;
ria - > res_path = ria - > local_path ;
// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
2015-08-23 23:15:56 +00:00
ria - > get_dependencies ( f , p_dependencies , p_add_types ) ;
}
Error ResourceFormatLoaderBinary : : rename_dependencies ( const String & p_path , const Map < String , String > & p_map ) {
// Error error=OK;
FileAccess * f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
ERR_FAIL_COND_V ( ! f , ERR_CANT_OPEN ) ;
FileAccess * fw = NULL ; //=FileAccess::open(p_path+".depren");
String local_path = p_path . get_base_dir ( ) ;
uint8_t header [ 4 ] ;
f - > get_buffer ( header , 4 ) ;
if ( header [ 0 ] = = ' R ' & & header [ 1 ] = = ' S ' & & header [ 2 ] = = ' C ' & & header [ 3 ] = = ' C ' ) {
//compressed
FileAccessCompressed * fac = memnew ( FileAccessCompressed ) ;
fac - > open_after_magic ( f ) ;
f = fac ;
FileAccessCompressed * facw = memnew ( FileAccessCompressed ) ;
facw - > configure ( " RSCC " ) ;
Error err = facw - > _open ( p_path + " .depren " , FileAccess : : WRITE ) ;
if ( err ) {
memdelete ( fac ) ;
memdelete ( facw ) ;
ERR_FAIL_COND_V ( err , ERR_FILE_CORRUPT ) ;
}
fw = facw ;
} else if ( header [ 0 ] ! = ' R ' | | header [ 1 ] ! = ' S ' | | header [ 2 ] ! = ' R ' | | header [ 3 ] ! = ' C ' ) {
//not normal
//error=ERR_FILE_UNRECOGNIZED;
memdelete ( f ) ;
ERR_EXPLAIN ( " Unrecognized binary resource file: " + local_path ) ;
ERR_FAIL_V ( ERR_FILE_UNRECOGNIZED ) ;
} else {
fw = FileAccess : : open ( p_path + " .depren " , FileAccess : : WRITE ) ;
if ( ! fw ) {
memdelete ( f ) ;
}
ERR_FAIL_COND_V ( ! fw , ERR_CANT_CREATE ) ;
}
bool big_endian = f - > get_32 ( ) ;
# ifdef BIG_ENDIAN_ENABLED
endian_swap = ! big_endian ;
# else
bool endian_swap = big_endian ;
# endif
bool use_real64 = f - > get_32 ( ) ;
f - > set_endian_swap ( big_endian ! = 0 ) ; //read big endian if saved as big endian
fw - > store_32 ( endian_swap ) ;
fw - > set_endian_swap ( big_endian ! = 0 ) ;
fw - > store_32 ( use_real64 ) ; //use real64
uint32_t ver_major = f - > get_32 ( ) ;
uint32_t ver_minor = f - > get_32 ( ) ;
uint32_t ver_format = f - > get_32 ( ) ;
if ( ver_format < FORMAT_VERSION_CAN_RENAME_DEPS ) {
memdelete ( f ) ;
memdelete ( fw ) ;
DirAccess * da = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
da - > remove ( p_path + " .depren " ) ;
memdelete ( da ) ;
//fuck it, use the old approach;
WARN_PRINT ( ( " This file is old, so it can't refactor dependencies, opening and resaving: " + p_path ) . utf8 ( ) . get_data ( ) ) ;
Error err ;
f = FileAccess : : open ( p_path , FileAccess : : READ , & err ) ;
if ( err ! = OK ) {
ERR_FAIL_COND_V ( err ! = OK , ERR_FILE_CANT_OPEN ) ;
}
Ref < ResourceInteractiveLoaderBinary > ria = memnew ( ResourceInteractiveLoaderBinary ) ;
ria - > local_path = Globals : : get_singleton ( ) - > localize_path ( p_path ) ;
ria - > res_path = ria - > local_path ;
ria - > remaps = p_map ;
// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
ria - > open ( f ) ;
err = ria - > poll ( ) ;
while ( err = = OK ) {
err = ria - > poll ( ) ;
}
ERR_FAIL_COND_V ( err ! = ERR_FILE_EOF , ERR_FILE_CORRUPT ) ;
RES res = ria - > get_resource ( ) ;
ERR_FAIL_COND_V ( ! res . is_valid ( ) , ERR_FILE_CORRUPT ) ;
return ResourceFormatSaverBinary : : singleton - > save ( p_path , res ) ;
}
if ( ver_format > FORMAT_VERSION | | ver_major > VERSION_MAJOR ) {
memdelete ( f ) ;
memdelete ( fw ) ;
ERR_EXPLAIN ( " File Format ' " + itos ( FORMAT_VERSION ) + " . " + itos ( ver_major ) + " . " + itos ( ver_minor ) + " ' is too new! Please upgrade to a a new engine version: " + local_path ) ;
ERR_FAIL_V ( ERR_FILE_UNRECOGNIZED ) ;
}
fw - > store_32 ( VERSION_MAJOR ) ; //current version
fw - > store_32 ( VERSION_MINOR ) ;
fw - > store_32 ( FORMAT_VERSION ) ;
save_ustring ( fw , get_ustring ( f ) ) ; //type
size_t md_ofs = f - > get_pos ( ) ;
size_t importmd_ofs = f - > get_64 ( ) ;
fw - > store_64 ( 0 ) ; //metadata offset
for ( int i = 0 ; i < 14 ; i + + ) {
fw - > store_32 ( 0 ) ;
f - > get_32 ( ) ;
}
//string table
uint32_t string_table_size = f - > get_32 ( ) ;
fw - > store_32 ( string_table_size ) ;
for ( uint32_t i = 0 ; i < string_table_size ; i + + ) {
String s = get_ustring ( f ) ;
save_ustring ( fw , s ) ;
}
//external resources
uint32_t ext_resources_size = f - > get_32 ( ) ;
fw - > store_32 ( ext_resources_size ) ;
for ( uint32_t i = 0 ; i < ext_resources_size ; i + + ) {
String type = get_ustring ( f ) ;
String path = get_ustring ( f ) ;
bool relative = false ;
if ( ! path . begins_with ( " res:// " ) ) {
path = local_path . plus_file ( path ) . simplify_path ( ) ;
relative = true ;
}
if ( p_map . has ( path ) ) {
String np = p_map [ path ] ;
path = np ;
}
if ( relative ) {
//restore relative
path = local_path . path_to_file ( path ) ;
}
save_ustring ( fw , type ) ;
save_ustring ( fw , path ) ;
}
int64_t size_diff = ( int64_t ) fw - > get_pos ( ) - ( int64_t ) f - > get_pos ( ) ;
//internal resources
uint32_t int_resources_size = f - > get_32 ( ) ;
fw - > store_32 ( int_resources_size ) ;
for ( uint32_t i = 0 ; i < int_resources_size ; i + + ) {
String path = get_ustring ( f ) ;
uint64_t offset = f - > get_64 ( ) ;
save_ustring ( fw , path ) ;
fw - > store_64 ( offset + size_diff ) ;
}
//rest of file
uint8_t b = f - > get_8 ( ) ;
while ( ! f - > eof_reached ( ) ) {
fw - > store_8 ( b ) ;
b = f - > get_8 ( ) ;
}
bool all_ok = fw - > get_error ( ) = = OK ;
fw - > seek ( md_ofs ) ;
fw - > store_64 ( importmd_ofs + size_diff ) ;
memdelete ( f ) ;
memdelete ( fw ) ;
if ( ! all_ok ) {
return ERR_CANT_CREATE ;
}
DirAccess * da = DirAccess : : create ( DirAccess : : ACCESS_RESOURCES ) ;
da - > remove ( p_path ) ;
da - > rename ( p_path + " .depren " , p_path ) ;
memdelete ( da ) ;
return OK ;
2014-02-10 01:10:30 +00:00
}
String ResourceFormatLoaderBinary : : get_resource_type ( const String & p_path ) const {
FileAccess * f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
if ( ! f ) {
return " " ; //could not rwead
}
Ref < ResourceInteractiveLoaderBinary > ria = memnew ( ResourceInteractiveLoaderBinary ) ;
ria - > local_path = Globals : : get_singleton ( ) - > localize_path ( p_path ) ;
ria - > res_path = ria - > local_path ;
// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
String r = ria - > recognize ( f ) ;
return r ;
}
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
void ResourceFormatSaverBinaryInstance : : _pad_buffer ( int p_bytes ) {
int extra = 4 - ( p_bytes % 4 ) ;
if ( extra < 4 ) {
for ( int i = 0 ; i < extra ; i + + )
f - > store_8 ( 0 ) ; //pad to 32
}
}
void ResourceFormatSaverBinaryInstance : : write_variant ( const Variant & p_property , const PropertyInfo & p_hint ) {
switch ( p_property . get_type ( ) ) {
case Variant : : NIL : {
f - > store_32 ( VARIANT_NIL ) ;
// don't store anything
} break ;
case Variant : : BOOL : {
f - > store_32 ( VARIANT_BOOL ) ;
bool val = p_property ;
f - > store_32 ( val ) ;
} break ;
case Variant : : INT : {
f - > store_32 ( VARIANT_INT ) ;
int val = p_property ;
f - > store_32 ( val ) ;
} break ;
case Variant : : REAL : {
f - > store_32 ( VARIANT_REAL ) ;
real_t val = p_property ;
f - > store_real ( val ) ;
} break ;
case Variant : : STRING : {
f - > store_32 ( VARIANT_STRING ) ;
String val = p_property ;
save_unicode_string ( val ) ;
} break ;
case Variant : : VECTOR2 : {
f - > store_32 ( VARIANT_VECTOR2 ) ;
Vector2 val = p_property ;
f - > store_real ( val . x ) ;
f - > store_real ( val . y ) ;
} break ;
case Variant : : RECT2 : {
f - > store_32 ( VARIANT_RECT2 ) ;
Rect2 val = p_property ;
f - > store_real ( val . pos . x ) ;
f - > store_real ( val . pos . y ) ;
f - > store_real ( val . size . x ) ;
f - > store_real ( val . size . y ) ;
} break ;
case Variant : : VECTOR3 : {
f - > store_32 ( VARIANT_VECTOR3 ) ;
Vector3 val = p_property ;
f - > store_real ( val . x ) ;
f - > store_real ( val . y ) ;
f - > store_real ( val . z ) ;
} break ;
case Variant : : PLANE : {
f - > store_32 ( VARIANT_PLANE ) ;
Plane val = p_property ;
f - > store_real ( val . normal . x ) ;
f - > store_real ( val . normal . y ) ;
f - > store_real ( val . normal . z ) ;
f - > store_real ( val . d ) ;
} break ;
case Variant : : QUAT : {
f - > store_32 ( VARIANT_QUAT ) ;
Quat val = p_property ;
f - > store_real ( val . x ) ;
f - > store_real ( val . y ) ;
f - > store_real ( val . z ) ;
f - > store_real ( val . w ) ;
} break ;
case Variant : : _AABB : {
f - > store_32 ( VARIANT_AABB ) ;
AABB val = p_property ;
f - > store_real ( val . pos . x ) ;
f - > store_real ( val . pos . y ) ;
f - > store_real ( val . pos . z ) ;
f - > store_real ( val . size . x ) ;
f - > store_real ( val . size . y ) ;
f - > store_real ( val . size . z ) ;
} break ;
case Variant : : MATRIX32 : {
f - > store_32 ( VARIANT_MATRIX32 ) ;
Matrix32 val = p_property ;
f - > store_real ( val . elements [ 0 ] . x ) ;
f - > store_real ( val . elements [ 0 ] . y ) ;
f - > store_real ( val . elements [ 1 ] . x ) ;
f - > store_real ( val . elements [ 1 ] . y ) ;
f - > store_real ( val . elements [ 2 ] . x ) ;
f - > store_real ( val . elements [ 2 ] . y ) ;
} break ;
case Variant : : MATRIX3 : {
f - > store_32 ( VARIANT_MATRIX3 ) ;
Matrix3 val = p_property ;
f - > store_real ( val . elements [ 0 ] . x ) ;
f - > store_real ( val . elements [ 0 ] . y ) ;
f - > store_real ( val . elements [ 0 ] . z ) ;
f - > store_real ( val . elements [ 1 ] . x ) ;
f - > store_real ( val . elements [ 1 ] . y ) ;
f - > store_real ( val . elements [ 1 ] . z ) ;
f - > store_real ( val . elements [ 2 ] . x ) ;
f - > store_real ( val . elements [ 2 ] . y ) ;
f - > store_real ( val . elements [ 2 ] . z ) ;
} break ;
case Variant : : TRANSFORM : {
f - > store_32 ( VARIANT_TRANSFORM ) ;
Transform val = p_property ;
f - > store_real ( val . basis . elements [ 0 ] . x ) ;
f - > store_real ( val . basis . elements [ 0 ] . y ) ;
f - > store_real ( val . basis . elements [ 0 ] . z ) ;
f - > store_real ( val . basis . elements [ 1 ] . x ) ;
f - > store_real ( val . basis . elements [ 1 ] . y ) ;
f - > store_real ( val . basis . elements [ 1 ] . z ) ;
f - > store_real ( val . basis . elements [ 2 ] . x ) ;
f - > store_real ( val . basis . elements [ 2 ] . y ) ;
f - > store_real ( val . basis . elements [ 2 ] . z ) ;
f - > store_real ( val . origin . x ) ;
f - > store_real ( val . origin . y ) ;
f - > store_real ( val . origin . z ) ;
} break ;
case Variant : : COLOR : {
f - > store_32 ( VARIANT_COLOR ) ;
Color val = p_property ;
f - > store_real ( val . r ) ;
f - > store_real ( val . g ) ;
f - > store_real ( val . b ) ;
f - > store_real ( val . a ) ;
} break ;
case Variant : : IMAGE : {
f - > store_32 ( VARIANT_IMAGE ) ;
Image val = p_property ;
if ( val . empty ( ) ) {
f - > store_32 ( IMAGE_ENCODING_EMPTY ) ;
break ;
}
int encoding = IMAGE_ENCODING_RAW ;
float quality = 0.7 ;
2016-10-03 19:33:42 +00:00
if ( ! val . is_compressed ( ) ) {
2014-02-10 01:10:30 +00:00
//can only compress uncompressed stuff
if ( p_hint . hint = = PROPERTY_HINT_IMAGE_COMPRESS_LOSSY & & Image : : lossy_packer ) {
encoding = IMAGE_ENCODING_LOSSY ;
float qs = p_hint . hint_string . to_double ( ) ;
if ( qs ! = 0.0 )
quality = qs ;
} else if ( p_hint . hint = = PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS & & Image : : lossless_packer ) {
encoding = IMAGE_ENCODING_LOSSLESS ;
}
}
f - > store_32 ( encoding ) ; //raw encoding
if ( encoding = = IMAGE_ENCODING_RAW ) {
f - > store_32 ( val . get_width ( ) ) ;
f - > store_32 ( val . get_height ( ) ) ;
2016-10-03 19:33:42 +00:00
f - > store_32 ( val . has_mipmaps ( ) ) ;
f - > store_32 ( val . get_format ( ) ) ; //if format changes we can add a compatibility version bit
2014-02-10 01:10:30 +00:00
int dlen = val . get_data ( ) . size ( ) ;
f - > store_32 ( dlen ) ;
DVector < uint8_t > : : Read r = val . get_data ( ) . read ( ) ;
f - > store_buffer ( r . ptr ( ) , dlen ) ;
_pad_buffer ( dlen ) ;
} else {
DVector < uint8_t > data ;
if ( encoding = = IMAGE_ENCODING_LOSSY ) {
data = Image : : lossy_packer ( val , quality ) ;
} else if ( encoding = = IMAGE_ENCODING_LOSSLESS ) {
data = Image : : lossless_packer ( val ) ;
}
int ds = data . size ( ) ;
f - > store_32 ( ds ) ;
if ( ds > 0 ) {
DVector < uint8_t > : : Read r = data . read ( ) ;
f - > store_buffer ( r . ptr ( ) , ds ) ;
_pad_buffer ( ds ) ;
}
}
} break ;
case Variant : : NODE_PATH : {
f - > store_32 ( VARIANT_NODE_PATH ) ;
NodePath np = p_property ;
f - > store_16 ( np . get_name_count ( ) ) ;
uint16_t snc = np . get_subname_count ( ) ;
if ( np . is_absolute ( ) )
snc | = 0x8000 ;
f - > store_16 ( snc ) ;
for ( int i = 0 ; i < np . get_name_count ( ) ; i + + )
f - > store_32 ( get_string_index ( np . get_name ( i ) ) ) ;
for ( int i = 0 ; i < np . get_subname_count ( ) ; i + + )
f - > store_32 ( get_string_index ( np . get_subname ( i ) ) ) ;
f - > store_32 ( get_string_index ( np . get_property ( ) ) ) ;
} break ;
case Variant : : _RID : {
f - > store_32 ( VARIANT_RID ) ;
WARN_PRINT ( " Can't save RIDs " ) ;
RID val = p_property ;
f - > store_32 ( val . get_id ( ) ) ;
} break ;
case Variant : : OBJECT : {
f - > store_32 ( VARIANT_OBJECT ) ;
RES res = p_property ;
if ( res . is_null ( ) ) {
f - > store_32 ( OBJECT_EMPTY ) ;
return ; // don't save it
}
if ( res - > get_path ( ) . length ( ) & & res - > get_path ( ) . find ( " :: " ) = = - 1 ) {
2015-08-23 23:15:56 +00:00
f - > store_32 ( OBJECT_EXTERNAL_RESOURCE_INDEX ) ;
f - > store_32 ( external_resources [ res ] ) ;
2014-02-10 01:10:30 +00:00
} else {
2015-06-22 03:03:19 +00:00
if ( ! resource_set . has ( res ) ) {
2014-02-10 01:10:30 +00:00
f - > store_32 ( OBJECT_EMPTY ) ;
ERR_EXPLAIN ( " Resource was not pre cached for the resource section, bug? " ) ;
ERR_FAIL ( ) ;
}
f - > store_32 ( OBJECT_INTERNAL_RESOURCE ) ;
2015-06-22 03:03:19 +00:00
f - > store_32 ( res - > get_subindex ( ) ) ;
2014-02-10 01:10:30 +00:00
//internal resource
}
} break ;
case Variant : : INPUT_EVENT : {
f - > store_32 ( VARIANT_INPUT_EVENT ) ;
2016-08-07 22:22:33 +00:00
InputEvent event = p_property ;
f - > store_32 ( 0 ) ; //event type none, nothing else suported for now.
2014-02-10 01:10:30 +00:00
} break ;
case Variant : : DICTIONARY : {
f - > store_32 ( VARIANT_DICTIONARY ) ;
Dictionary d = p_property ;
2014-03-14 01:57:24 +00:00
f - > store_32 ( uint32_t ( d . size ( ) ) | ( d . is_shared ( ) ? 0x80000000 : 0 ) ) ;
2014-02-10 01:10:30 +00:00
List < Variant > keys ;
d . get_key_list ( & keys ) ;
for ( List < Variant > : : Element * E = keys . front ( ) ; E ; E = E - > next ( ) ) {
//if (!_check_type(dict[E->get()]))
// continue;
write_variant ( E - > get ( ) ) ;
write_variant ( d [ E - > get ( ) ] ) ;
}
} break ;
case Variant : : ARRAY : {
f - > store_32 ( VARIANT_ARRAY ) ;
Array a = p_property ;
f - > store_32 ( uint32_t ( a . size ( ) ) | ( a . is_shared ( ) ? 0x80000000 : 0 ) ) ;
for ( int i = 0 ; i < a . size ( ) ; i + + ) {
write_variant ( a [ i ] ) ;
}
} break ;
case Variant : : RAW_ARRAY : {
f - > store_32 ( VARIANT_RAW_ARRAY ) ;
DVector < uint8_t > arr = p_property ;
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
DVector < uint8_t > : : Read r = arr . read ( ) ;
f - > store_buffer ( r . ptr ( ) , len ) ;
_pad_buffer ( len ) ;
} break ;
case Variant : : INT_ARRAY : {
f - > store_32 ( VARIANT_INT_ARRAY ) ;
DVector < int > arr = p_property ;
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
DVector < int > : : Read r = arr . read ( ) ;
for ( int i = 0 ; i < len ; i + + )
f - > store_32 ( r [ i ] ) ;
} break ;
case Variant : : REAL_ARRAY : {
f - > store_32 ( VARIANT_REAL_ARRAY ) ;
DVector < real_t > arr = p_property ;
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
DVector < real_t > : : Read r = arr . read ( ) ;
for ( int i = 0 ; i < len ; i + + ) {
f - > store_real ( r [ i ] ) ;
}
} break ;
case Variant : : STRING_ARRAY : {
f - > store_32 ( VARIANT_STRING_ARRAY ) ;
DVector < String > arr = p_property ;
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
DVector < String > : : Read r = arr . read ( ) ;
for ( int i = 0 ; i < len ; i + + ) {
save_unicode_string ( r [ i ] ) ;
}
} break ;
case Variant : : VECTOR3_ARRAY : {
f - > store_32 ( VARIANT_VECTOR3_ARRAY ) ;
DVector < Vector3 > arr = p_property ;
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
DVector < Vector3 > : : Read r = arr . read ( ) ;
for ( int i = 0 ; i < len ; i + + ) {
f - > store_real ( r [ i ] . x ) ;
f - > store_real ( r [ i ] . y ) ;
f - > store_real ( r [ i ] . z ) ;
}
} break ;
case Variant : : VECTOR2_ARRAY : {
f - > store_32 ( VARIANT_VECTOR2_ARRAY ) ;
DVector < Vector2 > arr = p_property ;
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
DVector < Vector2 > : : Read r = arr . read ( ) ;
for ( int i = 0 ; i < len ; i + + ) {
f - > store_real ( r [ i ] . x ) ;
f - > store_real ( r [ i ] . y ) ;
}
} break ;
case Variant : : COLOR_ARRAY : {
f - > store_32 ( VARIANT_COLOR_ARRAY ) ;
DVector < Color > arr = p_property ;
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
DVector < Color > : : Read r = arr . read ( ) ;
for ( int i = 0 ; i < len ; i + + ) {
f - > store_real ( r [ i ] . r ) ;
f - > store_real ( r [ i ] . g ) ;
f - > store_real ( r [ i ] . b ) ;
f - > store_real ( r [ i ] . a ) ;
}
} break ;
default : {
ERR_EXPLAIN ( " Invalid variant " ) ;
ERR_FAIL ( ) ;
}
}
}
void ResourceFormatSaverBinaryInstance : : _find_resources ( const Variant & p_variant , bool p_main ) {
switch ( p_variant . get_type ( ) ) {
case Variant : : OBJECT : {
RES res = p_variant . operator RefPtr ( ) ;
2015-08-23 23:15:56 +00:00
if ( res . is_null ( ) | | external_resources . has ( res ) )
2014-02-10 01:10:30 +00:00
return ;
if ( ! p_main & & ( ! bundle_resources ) & & res - > get_path ( ) . length ( ) & & res - > get_path ( ) . find ( " :: " ) = = - 1 ) {
2015-08-23 23:15:56 +00:00
int idx = external_resources . size ( ) ;
external_resources [ res ] = idx ;
2014-02-10 01:10:30 +00:00
return ;
}
2015-06-22 03:03:19 +00:00
if ( resource_set . has ( res ) )
2014-02-10 01:10:30 +00:00
return ;
List < PropertyInfo > property_list ;
res - > get_property_list ( & property_list ) ;
for ( List < PropertyInfo > : : Element * E = property_list . front ( ) ; E ; E = E - > next ( ) ) {
if ( E - > get ( ) . usage & PROPERTY_USAGE_STORAGE | | ( bundle_resources & & E - > get ( ) . usage & PROPERTY_USAGE_BUNDLE ) ) {
_find_resources ( res - > get ( E - > get ( ) . name ) ) ;
}
}
2015-06-22 03:03:19 +00:00
resource_set . insert ( res ) ;
2014-02-10 01:10:30 +00:00
saved_resources . push_back ( res ) ;
} break ;
case Variant : : ARRAY : {
Array varray = p_variant ;
int len = varray . size ( ) ;
for ( int i = 0 ; i < len ; i + + ) {
Variant v = varray . get ( i ) ;
_find_resources ( v ) ;
}
} break ;
case Variant : : DICTIONARY : {
Dictionary d = p_variant ;
List < Variant > keys ;
d . get_key_list ( & keys ) ;
for ( List < Variant > : : Element * E = keys . front ( ) ; E ; E = E - > next ( ) ) {
_find_resources ( E - > get ( ) ) ;
Variant v = d [ E - > get ( ) ] ;
_find_resources ( v ) ;
}
} break ;
case Variant : : NODE_PATH : {
//take the chance and save node path strings
NodePath np = p_variant ;
for ( int i = 0 ; i < np . get_name_count ( ) ; i + + )
get_string_index ( np . get_name ( i ) ) ;
for ( int i = 0 ; i < np . get_subname_count ( ) ; i + + )
get_string_index ( np . get_subname ( i ) ) ;
get_string_index ( np . get_property ( ) ) ;
} break ;
default : { }
}
}
#if 0
Error ResourceFormatSaverBinary : : _save_obj ( const Object * p_object , SavedObject * so ) {
//use classic way
List < PropertyInfo > property_list ;
p_object - > get_property_list ( & property_list ) ;
for ( List < PropertyInfo > : : Element * E = property_list . front ( ) ; E ; E = E - > next ( ) ) {
if ( skip_editor & & E - > get ( ) . name . begins_with ( " __editor " ) )
continue ;
if ( E - > get ( ) . usage & PROPERTY_USAGE_STORAGE | | ( bundle_resources & & E - > get ( ) . usage & PROPERTY_USAGE_BUNDLE ) ) {
SavedObject : : SavedProperty sp ;
sp . name_idx = get_string_index ( E - > get ( ) . name ) ;
sp . value = p_object - > get ( E - > get ( ) . name ) ;
_find_resources ( sp . value ) ;
so - > properties . push_back ( sp ) ;
}
}
return OK ;
}
Error ResourceFormatSaverBinary : : save ( const Object * p_object , const Variant & p_meta ) {
ERR_FAIL_COND_V ( ! f , ERR_UNCONFIGURED ) ;
ERR_EXPLAIN ( " write_object should supply either an object, a meta, or both " ) ;
ERR_FAIL_COND_V ( ! p_object & & p_meta . get_type ( ) = = Variant : : NIL , ERR_INVALID_PARAMETER ) ;
SavedObject * so = memnew ( SavedObject ) ;
if ( p_object )
so - > type = p_object - > get_type ( ) ;
_find_resources ( p_meta ) ;
so - > meta = p_meta ;
Error err = _save_obj ( p_object , so ) ;
ERR_FAIL_COND_V ( err , ERR_INVALID_DATA ) ;
saved_objects . push_back ( so ) ;
return OK ;
}
# endif
void ResourceFormatSaverBinaryInstance : : save_unicode_string ( const String & p_string ) {
CharString utf8 = p_string . utf8 ( ) ;
f - > store_32 ( utf8 . length ( ) + 1 ) ;
f - > store_buffer ( ( const uint8_t * ) utf8 . get_data ( ) , utf8 . length ( ) + 1 ) ;
}
int ResourceFormatSaverBinaryInstance : : get_string_index ( const String & p_string ) {
StringName s = p_string ;
if ( string_map . has ( s ) )
return string_map [ s ] ;
string_map [ s ] = strings . size ( ) ;
strings . push_back ( s ) ;
return strings . size ( ) - 1 ;
}
Error ResourceFormatSaverBinaryInstance : : save ( const String & p_path , const RES & p_resource , uint32_t p_flags ) {
Error err ;
if ( p_flags & ResourceSaver : : FLAG_COMPRESS ) {
FileAccessCompressed * fac = memnew ( FileAccessCompressed ) ;
fac - > configure ( " RSCC " ) ;
f = fac ;
err = fac - > _open ( p_path , FileAccess : : WRITE ) ;
if ( err )
memdelete ( f ) ;
} else {
f = FileAccess : : open ( p_path , FileAccess : : WRITE , & err ) ;
}
ERR_FAIL_COND_V ( err , err ) ;
FileAccessRef _fref ( f ) ;
relative_paths = p_flags & ResourceSaver : : FLAG_RELATIVE_PATHS ;
skip_editor = p_flags & ResourceSaver : : FLAG_OMIT_EDITOR_PROPERTIES ;
bundle_resources = p_flags & ResourceSaver : : FLAG_BUNDLE_RESOURCES ;
big_endian = p_flags & ResourceSaver : : FLAG_SAVE_BIG_ENDIAN ;
2014-06-28 02:21:45 +00:00
takeover_paths = p_flags & ResourceSaver : : FLAG_REPLACE_SUBRESOURCE_PATHS ;
2014-03-14 01:57:24 +00:00
2014-06-28 02:21:45 +00:00
if ( ! p_path . begins_with ( " res:// " ) )
takeover_paths = false ;
2014-02-10 01:10:30 +00:00
local_path = p_path . get_base_dir ( ) ;
//bin_meta_idx = get_string_index("__bin_meta__"); //is often used, so create
_find_resources ( p_resource , true ) ;
if ( ! ( p_flags & ResourceSaver : : FLAG_COMPRESS ) ) {
//save header compressed
static const uint8_t header [ 4 ] = { ' R ' , ' S ' , ' R ' , ' C ' } ;
f - > store_buffer ( header , 4 ) ;
}
if ( big_endian ) {
f - > store_32 ( 1 ) ;
f - > set_endian_swap ( true ) ;
} else
f - > store_32 ( 0 ) ;
f - > store_32 ( 0 ) ; //64 bits file, false for now
f - > store_32 ( VERSION_MAJOR ) ;
f - > store_32 ( VERSION_MINOR ) ;
f - > store_32 ( FORMAT_VERSION ) ;
2015-03-02 03:54:10 +00:00
if ( f - > get_error ( ) ! = OK & & f - > get_error ( ) ! = ERR_FILE_EOF ) {
f - > close ( ) ;
return ERR_CANT_CREATE ;
}
2014-02-10 01:10:30 +00:00
//f->store_32(saved_resources.size()+external_resources.size()); // load steps -not needed
save_unicode_string ( p_resource - > get_type ( ) ) ;
uint64_t md_at = f - > get_pos ( ) ;
f - > store_64 ( 0 ) ; //offset to impoty metadata
for ( int i = 0 ; i < 14 ; i + + )
f - > store_32 ( 0 ) ; // reserved
List < ResourceData > resources ;
{
for ( List < RES > : : Element * E = saved_resources . front ( ) ; E ; E = E - > next ( ) ) {
ResourceData & rd = resources . push_back ( ResourceData ( ) ) - > get ( ) ;
rd . type = E - > get ( ) - > get_type ( ) ;
List < PropertyInfo > property_list ;
E - > get ( ) - > get_property_list ( & property_list ) ;
for ( List < PropertyInfo > : : Element * F = property_list . front ( ) ; F ; F = F - > next ( ) ) {
if ( skip_editor & & F - > get ( ) . name . begins_with ( " __editor " ) )
continue ;
if ( F - > get ( ) . usage & PROPERTY_USAGE_STORAGE | | ( bundle_resources & & F - > get ( ) . usage & PROPERTY_USAGE_BUNDLE ) ) {
Property p ;
p . name_idx = get_string_index ( F - > get ( ) . name ) ;
p . value = E - > get ( ) - > get ( F - > get ( ) . name ) ;
2015-06-29 03:29:49 +00:00
if ( ( F - > get ( ) . usage & PROPERTY_USAGE_STORE_IF_NONZERO & & p . value . is_zero ( ) ) | | ( F - > get ( ) . usage & PROPERTY_USAGE_STORE_IF_NONONE & & p . value . is_one ( ) ) )
2014-02-10 01:10:30 +00:00
continue ;
2016-03-08 23:00:52 +00:00
p . pi = F - > get ( ) ;
2014-02-10 01:10:30 +00:00
rd . properties . push_back ( p ) ;
}
}
}
}
f - > store_32 ( strings . size ( ) ) ; //string table size
for ( int i = 0 ; i < strings . size ( ) ; i + + ) {
//print_bl("saving string: "+strings[i]);
save_unicode_string ( strings [ i ] ) ;
}
// save external resource table
f - > store_32 ( external_resources . size ( ) ) ; //amount of external resources
2015-08-23 23:15:56 +00:00
Vector < RES > save_order ;
save_order . resize ( external_resources . size ( ) ) ;
for ( Map < RES , int > : : Element * E = external_resources . front ( ) ; E ; E = E - > next ( ) ) {
save_order [ E - > get ( ) ] = E - > key ( ) ;
}
2014-02-10 01:10:30 +00:00
2015-08-23 23:15:56 +00:00
for ( int i = 0 ; i < save_order . size ( ) ; i + + ) {
save_unicode_string ( save_order [ i ] - > get_save_type ( ) ) ;
String path = save_order [ i ] - > get_path ( ) ;
path = relative_paths ? local_path . path_to_file ( path ) : path ;
2014-02-10 01:10:30 +00:00
save_unicode_string ( path ) ;
}
// save internal resource table
f - > store_32 ( saved_resources . size ( ) ) ; //amount of internal resources
Vector < uint64_t > ofs_pos ;
2015-06-22 03:03:19 +00:00
Set < int > used_indices ;
for ( List < RES > : : Element * E = saved_resources . front ( ) ; E ; E = E - > next ( ) ) {
RES r = E - > get ( ) ;
if ( r - > get_path ( ) = = " " | | r - > get_path ( ) . find ( " :: " ) ! = - 1 ) {
if ( r - > get_subindex ( ) ! = 0 ) {
if ( used_indices . has ( r - > get_subindex ( ) ) ) {
r - > set_subindex ( 0 ) ; //repeated
} else {
used_indices . insert ( r - > get_subindex ( ) ) ;
}
}
}
}
2014-02-10 01:10:30 +00:00
for ( List < RES > : : Element * E = saved_resources . front ( ) ; E ; E = E - > next ( ) ) {
2015-06-22 03:03:19 +00:00
2014-02-10 01:10:30 +00:00
RES r = E - > get ( ) ;
2014-06-28 02:21:45 +00:00
if ( r - > get_path ( ) = = " " | | r - > get_path ( ) . find ( " :: " ) ! = - 1 ) {
2015-06-22 03:03:19 +00:00
if ( r - > get_subindex ( ) = = 0 ) {
int new_subindex = 1 ;
if ( used_indices . size ( ) ) {
new_subindex = used_indices . back ( ) - > get ( ) + 1 ;
}
r - > set_subindex ( new_subindex ) ;
used_indices . insert ( new_subindex ) ;
}
save_unicode_string ( " local:// " + itos ( r - > get_subindex ( ) ) ) ;
2014-06-28 02:21:45 +00:00
if ( takeover_paths ) {
2015-10-22 02:57:43 +00:00
r - > set_path ( p_path + " :: " + itos ( r - > get_subindex ( ) ) , true ) ;
2014-06-28 02:21:45 +00:00
}
2016-08-31 20:58:51 +00:00
# ifdef TOOLS_ENABLED
r - > set_edited ( false ) ;
# endif
2015-10-22 02:57:43 +00:00
} else {
2014-02-10 01:10:30 +00:00
save_unicode_string ( r - > get_path ( ) ) ; //actual external
2015-10-22 02:57:43 +00:00
}
2014-02-10 01:10:30 +00:00
ofs_pos . push_back ( f - > get_pos ( ) ) ;
f - > store_64 ( 0 ) ; //offset in 64 bits
}
Vector < uint64_t > ofs_table ;
// int saved_idx=0;
//now actually save the resources
for ( List < ResourceData > : : Element * E = resources . front ( ) ; E ; E = E - > next ( ) ) {
ResourceData & rd = E - > get ( ) ;
ofs_table . push_back ( f - > get_pos ( ) ) ;
save_unicode_string ( rd . type ) ;
f - > store_32 ( rd . properties . size ( ) ) ;
for ( List < Property > : : Element * F = rd . properties . front ( ) ; F ; F = F - > next ( ) ) {
Property & p = F - > get ( ) ;
f - > store_32 ( p . name_idx ) ;
write_variant ( p . value , F - > get ( ) . pi ) ;
}
}
for ( int i = 0 ; i < ofs_table . size ( ) ; i + + ) {
f - > seek ( ofs_pos [ i ] ) ;
f - > store_64 ( ofs_table [ i ] ) ;
}
f - > seek_end ( ) ;
2014-03-14 01:57:24 +00:00
print_line ( " SAVING: " + p_path ) ;
2014-02-10 01:10:30 +00:00
if ( p_resource - > get_import_metadata ( ) . is_valid ( ) ) {
uint64_t md_pos = f - > get_pos ( ) ;
Ref < ResourceImportMetadata > imd = p_resource - > get_import_metadata ( ) ;
save_unicode_string ( imd - > get_editor ( ) ) ;
f - > store_32 ( imd - > get_source_count ( ) ) ;
for ( int i = 0 ; i < imd - > get_source_count ( ) ; i + + ) {
save_unicode_string ( imd - > get_source_path ( i ) ) ;
save_unicode_string ( imd - > get_source_md5 ( i ) ) ;
2014-03-14 01:57:24 +00:00
print_line ( " SAVE PATH: " + imd - > get_source_path ( i ) ) ;
print_line ( " SAVE MD5: " + imd - > get_source_md5 ( i ) ) ;
2014-02-10 01:10:30 +00:00
}
List < String > options ;
imd - > get_options ( & options ) ;
f - > store_32 ( options . size ( ) ) ;
for ( List < String > : : Element * E = options . front ( ) ; E ; E = E - > next ( ) ) {
save_unicode_string ( E - > get ( ) ) ;
write_variant ( imd - > get_option ( E - > get ( ) ) ) ;
}
f - > seek ( md_at ) ;
f - > store_64 ( md_pos ) ;
f - > seek_end ( ) ;
}
f - > store_buffer ( ( const uint8_t * ) " RSRC " , 4 ) ; //magic at end
2015-03-02 03:54:10 +00:00
if ( f - > get_error ( ) ! = OK & & f - > get_error ( ) ! = ERR_FILE_EOF ) {
f - > close ( ) ;
return ERR_CANT_CREATE ;
}
2014-02-10 01:10:30 +00:00
f - > close ( ) ;
return OK ;
}
Error ResourceFormatSaverBinary : : save ( const String & p_path , const RES & p_resource , uint32_t p_flags ) {
String local_path = Globals : : get_singleton ( ) - > localize_path ( p_path ) ;
ResourceFormatSaverBinaryInstance saver ;
return saver . save ( local_path , p_resource , p_flags ) ;
}
bool ResourceFormatSaverBinary : : recognize ( const RES & p_resource ) const {
return true ; //all recognized
}
void ResourceFormatSaverBinary : : get_recognized_extensions ( const RES & p_resource , List < String > * p_extensions ) const {
String base = p_resource - > get_base_extension ( ) . to_lower ( ) ;
2016-06-28 16:58:40 +00:00
p_extensions - > push_back ( base ) ;
2014-02-10 01:10:30 +00:00
}
2015-08-23 23:15:56 +00:00
ResourceFormatSaverBinary * ResourceFormatSaverBinary : : singleton = NULL ;
ResourceFormatSaverBinary : : ResourceFormatSaverBinary ( ) {
singleton = this ;
}