2014-02-10 01:10:30 +00:00
/**************************************************************************/
/* file_access_pack.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
2018-01-04 23:50:27 +00:00
2014-02-10 01:10:30 +00:00
# include "file_access_pack.h"
2018-09-11 16:13:45 +00:00
2020-04-28 17:51:29 +00:00
# include "core/io/file_access_encrypted.h"
2020-11-07 22:33:38 +00:00
# include "core/object/script_language.h"
2021-12-20 09:28:54 +00:00
# include "core/os/os.h"
2018-09-11 16:13:45 +00:00
# include "core/version.h"
2014-02-10 01:10:30 +00:00
# include <stdio.h>
2019-03-26 17:51:13 +00:00
Error PackedData : : add_pack ( const String & p_path , bool p_replace_files , uint64_t p_offset ) {
2014-02-10 01:10:30 +00:00
for ( int i = 0 ; i < sources . size ( ) ; i + + ) {
2020-07-13 16:22:06 +00:00
if ( sources [ i ] - > try_open_pack ( p_path , p_replace_files , p_offset ) ) {
2014-02-10 01:10:30 +00:00
return OK ;
2020-05-19 13:46:49 +00:00
}
}
2014-02-10 01:10:30 +00:00
return ERR_FILE_UNRECOGNIZED ;
2020-05-19 13:46:49 +00:00
}
2014-02-10 01:10:30 +00:00
2019-03-26 17:51:13 +00:00
void PackedData : : add_path ( const String & p_pkg_path , const String & p_path , uint64_t p_ofs , uint64_t p_size , const uint8_t * p_md5 , PackSource * p_src , bool p_replace_files , bool p_encrypted ) {
2023-05-22 18:03:05 +00:00
String simplified_path = p_path . simplify_path ( ) ;
PathMD5 pmd5 ( simplified_path . md5_buffer ( ) ) ;
2014-08-02 01:10:38 +00:00
bool exists = files . has ( pmd5 ) ;
2014-02-10 01:10:30 +00:00
PackedFile pf ;
2020-04-28 17:51:29 +00:00
pf . encrypted = p_encrypted ;
2019-03-26 17:51:13 +00:00
pf . pack = p_pkg_path ;
pf . offset = p_ofs ;
pf . size = p_size ;
2020-05-14 14:41:43 +00:00
for ( int i = 0 ; i < 16 ; i + + ) {
2014-02-13 21:03:28 +00:00
pf . md5 [ i ] = p_md5 [ i ] ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
pf . src = p_src ;
2020-05-14 14:41:43 +00:00
if ( ! exists | | p_replace_files ) {
2019-09-23 20:41:25 +00:00
files [ pmd5 ] = pf ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
if ( ! exists ) {
//search for dir
2023-05-22 18:03:05 +00:00
String p = simplified_path . replace_first ( " res:// " , " " ) ;
2014-02-10 01:10:30 +00:00
PackedDir * cd = root ;
2022-02-03 16:03:38 +00:00
if ( p . contains ( " / " ) ) { //in a subdir
2014-02-10 01:10:30 +00:00
Vector < String > ds = p . get_base_dir ( ) . split ( " / " ) ;
for ( int j = 0 ; j < ds . size ( ) ; j + + ) {
if ( ! cd - > subdirs . has ( ds [ j ] ) ) {
PackedDir * pd = memnew ( PackedDir ) ;
pd - > name = ds [ j ] ;
pd - > parent = cd ;
cd - > subdirs [ pd - > name ] = pd ;
cd = pd ;
} else {
cd = cd - > subdirs [ ds [ j ] ] ;
}
}
}
2023-05-22 18:03:05 +00:00
String filename = simplified_path . get_file ( ) ;
2020-04-20 08:56:27 +00:00
// Don't add as a file if the path points to a directory
2020-12-15 12:04:21 +00:00
if ( ! filename . is_empty ( ) ) {
2018-03-18 13:04:50 +00:00
cd - > files . insert ( filename ) ;
}
2014-02-10 01:10:30 +00:00
}
}
void PackedData : : add_pack_source ( PackSource * p_source ) {
2020-04-01 23:20:12 +00:00
if ( p_source ! = nullptr ) {
2015-05-06 23:37:25 +00:00
sources . push_back ( p_source ) ;
}
2020-05-19 13:46:49 +00:00
}
2014-02-10 01:10:30 +00:00
2024-09-17 10:48:10 +00:00
uint8_t * PackedData : : get_file_hash ( const String & p_path ) {
PathMD5 pmd5 ( p_path . md5_buffer ( ) ) ;
HashMap < PathMD5 , PackedFile , PathMD5 > : : Iterator E = files . find ( pmd5 ) ;
if ( ! E | | E - > value . offset = = 0 ) {
return nullptr ;
}
return E - > value . md5 ;
}
void PackedData : : clear ( ) {
files . clear ( ) ;
_free_packed_dirs ( root ) ;
root = memnew ( PackedDir ) ;
}
2020-04-01 23:20:12 +00:00
PackedData * PackedData : : singleton = nullptr ;
2014-02-10 01:10:30 +00:00
PackedData : : PackedData ( ) {
singleton = this ;
root = memnew ( PackedDir ) ;
add_pack_source ( memnew ( PackedSourcePCK ) ) ;
}
2015-04-20 22:38:02 +00:00
void PackedData : : _free_packed_dirs ( PackedDir * p_dir ) {
2021-08-09 20:13:42 +00:00
for ( const KeyValue < String , PackedDir * > & E : p_dir - > subdirs ) {
_free_packed_dirs ( E . value ) ;
2020-05-14 14:41:43 +00:00
}
2015-04-20 22:38:02 +00:00
memdelete ( p_dir ) ;
}
PackedData : : ~ PackedData ( ) {
2024-08-09 01:33:51 +00:00
if ( singleton = = this ) {
singleton = nullptr ;
}
2015-04-20 22:38:02 +00:00
for ( int i = 0 ; i < sources . size ( ) ; i + + ) {
memdelete ( sources [ i ] ) ;
}
_free_packed_dirs ( root ) ;
}
2014-02-10 01:10:30 +00:00
//////////////////////////////////////////////////////////////////
2019-03-26 17:51:13 +00:00
bool PackedSourcePCK : : try_open_pack ( const String & p_path , bool p_replace_files , uint64_t p_offset ) {
2022-03-23 09:08:58 +00:00
Ref < FileAccess > f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
if ( f . is_null ( ) ) {
2014-02-10 01:10:30 +00:00
return false ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2021-12-20 09:28:54 +00:00
bool pck_header_found = false ;
2020-07-13 16:22:06 +00:00
2021-12-20 09:28:54 +00:00
// Search for the header at the start offset - standalone PCK file.
f - > seek ( p_offset ) ;
2014-02-10 01:10:30 +00:00
uint32_t magic = f - > get_32 ( ) ;
2021-12-20 09:28:54 +00:00
if ( magic = = PACK_HEADER_MAGIC ) {
pck_header_found = true ;
}
2014-02-10 01:10:30 +00:00
2021-12-20 09:28:54 +00:00
// Search for the header in the executable "pck" section - self contained executable.
if ( ! pck_header_found ) {
// Loading with offset feature not supported for self contained exe files.
if ( p_offset ! = 0 ) {
ERR_FAIL_V_MSG ( false , " Loading self-contained executable with offset not supported. " ) ;
}
2020-07-13 16:22:06 +00:00
2021-12-20 09:28:54 +00:00
int64_t pck_off = OS : : get_singleton ( ) - > get_embedded_pck_offset ( ) ;
if ( pck_off ! = 0 ) {
// Search for the header, in case PCK start and section have different alignment.
for ( int i = 0 ; i < 8 ; i + + ) {
f - > seek ( pck_off ) ;
magic = f - > get_32 ( ) ;
if ( magic = = PACK_HEADER_MAGIC ) {
# ifdef DEBUG_ENABLED
print_verbose ( " PCK header found in executable pck section, loading from offset 0x " + String : : num_int64 ( pck_off - 4 , 16 ) ) ;
# endif
pck_header_found = true ;
break ;
}
pck_off + + ;
}
2014-02-10 01:10:30 +00:00
}
2021-12-20 09:28:54 +00:00
}
2014-02-10 01:10:30 +00:00
2021-12-20 09:28:54 +00:00
// Search for the header at the end of file - self contained executable.
if ( ! pck_header_found ) {
// Loading with offset feature not supported for self contained exe files.
if ( p_offset ! = 0 ) {
ERR_FAIL_V_MSG ( false , " Loading self-contained executable with offset not supported. " ) ;
}
2014-02-10 01:10:30 +00:00
2021-12-20 09:28:54 +00:00
f - > seek_end ( ) ;
f - > seek ( f - > get_position ( ) - 4 ) ;
2014-02-10 01:10:30 +00:00
magic = f - > get_32 ( ) ;
2021-12-20 09:28:54 +00:00
if ( magic = = PACK_HEADER_MAGIC ) {
f - > seek ( f - > get_position ( ) - 12 ) ;
uint64_t ds = f - > get_64 ( ) ;
f - > seek ( f - > get_position ( ) - ds - 8 ) ;
magic = f - > get_32 ( ) ;
if ( magic = = PACK_HEADER_MAGIC ) {
# ifdef DEBUG_ENABLED
print_verbose ( " PCK header found at the end of executable, loading from offset 0x " + String : : num_int64 ( f - > get_position ( ) - 4 , 16 ) ) ;
# endif
pck_header_found = true ;
}
2014-02-10 01:10:30 +00:00
}
}
2021-12-20 09:28:54 +00:00
if ( ! pck_header_found ) {
return false ;
}
2024-02-10 19:58:08 +00:00
int64_t pck_start_pos = f - > get_position ( ) - 4 ;
2014-02-15 05:01:39 +00:00
uint32_t version = f - > get_32 ( ) ;
2014-02-10 01:10:30 +00:00
uint32_t ver_major = f - > get_32 ( ) ;
uint32_t ver_minor = f - > get_32 ( ) ;
2019-11-30 16:22:22 +00:00
f - > get_32 ( ) ; // patch number, not used for validation.
2014-02-10 01:10:30 +00:00
2024-10-11 14:17:49 +00:00
ERR_FAIL_COND_V_MSG ( version ! = PACK_FORMAT_VERSION , false , vformat ( " Pack version unsupported: %d. " , version ) ) ;
ERR_FAIL_COND_V_MSG ( ver_major > VERSION_MAJOR | | ( ver_major = = VERSION_MAJOR & & ver_minor > VERSION_MINOR ) , false , vformat ( " Pack created with a newer version of the engine: %d.%d. " , ver_major , ver_minor ) ) ;
2014-02-10 01:10:30 +00:00
2020-04-28 17:51:29 +00:00
uint32_t pack_flags = f - > get_32 ( ) ;
uint64_t file_base = f - > get_64 ( ) ;
bool enc_directory = ( pack_flags & PACK_DIR_ENCRYPTED ) ;
2024-02-10 19:58:08 +00:00
bool rel_filebase = ( pack_flags & PACK_REL_FILEBASE ) ;
2020-04-28 17:51:29 +00:00
2014-02-10 01:10:30 +00:00
for ( int i = 0 ; i < 16 ; i + + ) {
//reserved
f - > get_32 ( ) ;
}
int file_count = f - > get_32 ( ) ;
2024-02-10 19:58:08 +00:00
if ( rel_filebase ) {
file_base + = pck_start_pos ;
}
2020-04-28 17:51:29 +00:00
if ( enc_directory ) {
2022-03-23 09:08:58 +00:00
Ref < FileAccessEncrypted > fae ;
fae . instantiate ( ) ;
ERR_FAIL_COND_V_MSG ( fae . is_null ( ) , false , " Can't open encrypted pack directory. " ) ;
2020-04-28 17:51:29 +00:00
Vector < uint8_t > key ;
key . resize ( 32 ) ;
for ( int i = 0 ; i < key . size ( ) ; i + + ) {
key . write [ i ] = script_encryption_key [ i ] ;
}
Error err = fae - > open_and_parse ( f , key , FileAccessEncrypted : : MODE_READ , false ) ;
2022-03-23 09:08:58 +00:00
ERR_FAIL_COND_V_MSG ( err , false , " Can't open encrypted pack directory. " ) ;
2020-04-28 17:51:29 +00:00
f = fae ;
}
2014-02-10 01:10:30 +00:00
for ( int i = 0 ; i < file_count ; i + + ) {
uint32_t sl = f - > get_32 ( ) ;
CharString cs ;
cs . resize ( sl + 1 ) ;
f - > get_buffer ( ( uint8_t * ) cs . ptr ( ) , sl ) ;
cs [ sl ] = 0 ;
String path ;
path . parse_utf8 ( cs . ptr ( ) ) ;
2020-04-28 17:51:29 +00:00
uint64_t ofs = file_base + f - > get_64 ( ) ;
2014-02-10 01:10:30 +00:00
uint64_t size = f - > get_64 ( ) ;
2014-02-13 21:03:28 +00:00
uint8_t md5 [ 16 ] ;
f - > get_buffer ( md5 , 16 ) ;
2020-04-28 17:51:29 +00:00
uint32_t flags = f - > get_32 ( ) ;
PackedData : : get_singleton ( ) - > add_path ( p_path , path , ofs + p_offset , size , md5 , this , p_replace_files , ( flags & PACK_FILE_ENCRYPTED ) ) ;
2020-05-19 13:46:49 +00:00
}
2014-02-10 01:10:30 +00:00
return true ;
2020-05-19 13:46:49 +00:00
}
2014-02-10 01:10:30 +00:00
2022-03-23 09:08:58 +00:00
Ref < FileAccess > PackedSourcePCK : : get_file ( const String & p_path , PackedData : : PackedFile * p_file ) {
2014-02-10 01:10:30 +00:00
return memnew ( FileAccessPack ( p_path , * p_file ) ) ;
2020-05-19 13:46:49 +00:00
}
2014-02-10 01:10:30 +00:00
//////////////////////////////////////////////////////////////////
2022-09-05 11:01:31 +00:00
Error FileAccessPack : : open_internal ( const String & p_path , int p_mode_flags ) {
2023-04-18 07:20:48 +00:00
ERR_PRINT ( " Can't open pack-referenced file. " ) ;
2014-02-10 01:10:30 +00:00
return ERR_UNAVAILABLE ;
}
bool FileAccessPack : : is_open ( ) const {
2022-04-12 07:12:40 +00:00
if ( f . is_valid ( ) ) {
return f - > is_open ( ) ;
} else {
return false ;
}
2014-02-10 01:10:30 +00:00
}
2019-03-26 17:51:13 +00:00
void FileAccessPack : : seek ( uint64_t p_position ) {
2022-04-12 07:12:40 +00:00
ERR_FAIL_COND_MSG ( f . is_null ( ) , " File must be opened before use. " ) ;
2014-02-10 01:10:30 +00:00
if ( p_position > pf . size ) {
eof = true ;
} else {
eof = false ;
}
2020-04-28 17:51:29 +00:00
f - > seek ( off + p_position ) ;
2014-04-29 00:56:43 +00:00
pos = p_position ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 12:29:06 +00:00
2014-02-10 01:10:30 +00:00
void FileAccessPack : : seek_end ( int64_t p_position ) {
seek ( pf . size + p_position ) ;
}
2020-05-14 12:29:06 +00:00
2019-03-26 17:51:13 +00:00
uint64_t FileAccessPack : : get_position ( ) const {
2014-02-10 01:10:30 +00:00
return pos ;
}
2020-05-14 12:29:06 +00:00
2021-05-25 06:58:49 +00:00
uint64_t FileAccessPack : : get_length ( ) const {
2014-02-10 01:10:30 +00:00
return pf . size ;
}
bool FileAccessPack : : eof_reached ( ) const {
return eof ;
}
2019-03-26 17:51:13 +00:00
uint64_t FileAccessPack : : get_buffer ( uint8_t * p_dst , uint64_t p_length ) const {
2022-04-12 07:12:40 +00:00
ERR_FAIL_COND_V_MSG ( f . is_null ( ) , - 1 , " File must be opened before use. " ) ;
2021-03-16 21:55:11 +00:00
ERR_FAIL_COND_V ( ! p_dst & & p_length > 0 , - 1 ) ;
2021-03-09 01:37:35 +00:00
2020-05-14 14:41:43 +00:00
if ( eof ) {
2014-02-10 01:10:30 +00:00
return 0 ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2019-03-26 17:51:13 +00:00
int64_t to_read = p_length ;
2014-02-10 01:10:30 +00:00
if ( to_read + pos > pf . size ) {
eof = true ;
2019-03-26 17:51:13 +00:00
to_read = ( int64_t ) pf . size - ( int64_t ) pos ;
2014-02-10 01:10:30 +00:00
}
2023-12-10 08:21:16 +00:00
pos + = to_read ;
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( to_read < = 0 ) {
2014-02-10 01:10:30 +00:00
return 0 ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
f - > get_buffer ( p_dst , to_read ) ;
return to_read ;
}
2021-05-20 12:58:03 +00:00
void FileAccessPack : : set_big_endian ( bool p_big_endian ) {
2022-04-12 07:12:40 +00:00
ERR_FAIL_COND_MSG ( f . is_null ( ) , " File must be opened before use. " ) ;
2021-05-20 12:58:03 +00:00
FileAccess : : set_big_endian ( p_big_endian ) ;
f - > set_big_endian ( p_big_endian ) ;
2014-02-10 01:10:30 +00:00
}
Error FileAccessPack : : get_error ( ) const {
2020-05-14 14:41:43 +00:00
if ( eof ) {
2014-02-10 01:10:30 +00:00
return ERR_FILE_EOF ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
return OK ;
}
2017-09-22 05:56:02 +00:00
void FileAccessPack : : flush ( ) {
ERR_FAIL ( ) ;
}
2019-03-26 17:51:13 +00:00
void FileAccessPack : : store_buffer ( const uint8_t * p_src , uint64_t p_length ) {
2014-02-10 01:10:30 +00:00
ERR_FAIL ( ) ;
}
bool FileAccessPack : : file_exists ( const String & p_name ) {
return false ;
}
2023-02-16 13:25:32 +00:00
void FileAccessPack : : close ( ) {
f = Ref < FileAccess > ( ) ;
}
2017-12-06 20:36:34 +00:00
FileAccessPack : : FileAccessPack ( const String & p_path , const PackedData : : PackedFile & p_file ) :
pf ( p_file ) ,
f ( FileAccess : : open ( pf . pack , FileAccess : : READ ) ) {
2024-10-11 14:17:49 +00:00
ERR_FAIL_COND_MSG ( f . is_null ( ) , vformat ( " Can't open pack-referenced file '%s'. " , String ( pf . pack ) ) ) ;
2019-08-15 02:57:49 +00:00
2014-02-10 01:10:30 +00:00
f - > seek ( pf . offset ) ;
2020-04-28 17:51:29 +00:00
off = pf . offset ;
if ( pf . encrypted ) {
2022-03-23 09:08:58 +00:00
Ref < FileAccessEncrypted > fae ;
fae . instantiate ( ) ;
2024-10-11 14:17:49 +00:00
ERR_FAIL_COND_MSG ( fae . is_null ( ) , vformat ( " Can't open encrypted pack-referenced file '%s'. " , String ( pf . pack ) ) ) ;
2020-04-28 17:51:29 +00:00
Vector < uint8_t > key ;
key . resize ( 32 ) ;
for ( int i = 0 ; i < key . size ( ) ; i + + ) {
key . write [ i ] = script_encryption_key [ i ] ;
}
Error err = fae - > open_and_parse ( f , key , FileAccessEncrypted : : MODE_READ , false ) ;
2024-10-11 14:17:49 +00:00
ERR_FAIL_COND_MSG ( err , vformat ( " Can't open encrypted pack-referenced file '%s'. " , String ( pf . pack ) ) ) ;
2020-04-28 17:51:29 +00:00
f = fae ;
off = 0 ;
}
2014-02-10 01:10:30 +00:00
pos = 0 ;
eof = false ;
}
//////////////////////////////////////////////////////////////////////////////////
// DIR ACCESS
//////////////////////////////////////////////////////////////////////////////////
2017-01-14 12:16:41 +00:00
Error DirAccessPack : : list_dir_begin ( ) {
2014-02-10 01:10:30 +00:00
list_dirs . clear ( ) ;
list_files . clear ( ) ;
2021-08-09 20:13:42 +00:00
for ( const KeyValue < String , PackedData : : PackedDir * > & E : current - > subdirs ) {
list_dirs . push_back ( E . key ) ;
2014-02-10 01:10:30 +00:00
}
2022-05-18 23:43:40 +00:00
for ( const String & E : current - > files ) {
list_files . push_back ( E ) ;
2014-02-10 01:10:30 +00:00
}
2017-01-14 12:16:41 +00:00
return OK ;
2014-02-10 01:10:30 +00:00
}
String DirAccessPack : : get_next ( ) {
if ( list_dirs . size ( ) ) {
cdir = true ;
String d = list_dirs . front ( ) - > get ( ) ;
list_dirs . pop_front ( ) ;
return d ;
} else if ( list_files . size ( ) ) {
cdir = false ;
String f = list_files . front ( ) - > get ( ) ;
list_files . pop_front ( ) ;
return f ;
} else {
return String ( ) ;
}
}
2020-05-14 12:29:06 +00:00
2014-02-10 01:10:30 +00:00
bool DirAccessPack : : current_is_dir ( ) const {
return cdir ;
}
2020-05-14 12:29:06 +00:00
2015-03-21 17:33:32 +00:00
bool DirAccessPack : : current_is_hidden ( ) const {
return false ;
}
2020-05-14 12:29:06 +00:00
2014-02-10 01:10:30 +00:00
void DirAccessPack : : list_dir_end ( ) {
list_dirs . clear ( ) ;
list_files . clear ( ) ;
}
int DirAccessPack : : get_drive_count ( ) {
return 0 ;
}
2020-05-14 12:29:06 +00:00
2014-02-10 01:10:30 +00:00
String DirAccessPack : : get_drive ( int p_drive ) {
return " " ;
}
2024-01-09 01:36:19 +00:00
PackedData : : PackedDir * DirAccessPack : : _find_dir ( const String & p_dir ) {
2014-02-10 01:10:30 +00:00
String nd = p_dir . replace ( " \\ " , " / " ) ;
2020-07-27 10:06:40 +00:00
// Special handling since simplify_path() will forbid it
if ( p_dir = = " .. " ) {
return current - > parent ;
}
2014-02-10 01:10:30 +00:00
bool absolute = false ;
if ( nd . begins_with ( " res:// " ) ) {
nd = nd . replace_first ( " res:// " , " " ) ;
absolute = true ;
}
nd = nd . simplify_path ( ) ;
2021-12-09 09:42:46 +00:00
if ( nd . is_empty ( ) ) {
2016-09-03 22:35:42 +00:00
nd = " . " ;
2020-05-14 14:41:43 +00:00
}
2016-09-03 22:35:42 +00:00
2014-02-10 01:10:30 +00:00
if ( nd . begins_with ( " / " ) ) {
nd = nd . replace_first ( " / " , " " ) ;
absolute = true ;
}
Vector < String > paths = nd . split ( " / " ) ;
PackedData : : PackedDir * pd ;
2020-05-14 14:41:43 +00:00
if ( absolute ) {
2014-02-10 01:10:30 +00:00
pd = PackedData : : get_singleton ( ) - > root ;
2020-05-14 14:41:43 +00:00
} else {
2014-02-10 01:10:30 +00:00
pd = current ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
for ( int i = 0 ; i < paths . size ( ) ; i + + ) {
2023-11-18 22:40:56 +00:00
const String & p = paths [ i ] ;
2014-02-10 01:10:30 +00:00
if ( p = = " . " ) {
continue ;
} else if ( p = = " .. " ) {
if ( pd - > parent ) {
pd = pd - > parent ;
}
} else if ( pd - > subdirs . has ( p ) ) {
pd = pd - > subdirs [ p ] ;
} else {
2020-07-27 10:06:40 +00:00
return nullptr ;
2014-02-10 01:10:30 +00:00
}
}
2020-07-27 10:06:40 +00:00
return pd ;
}
2014-02-10 01:10:30 +00:00
2020-07-27 10:06:40 +00:00
Error DirAccessPack : : change_dir ( String p_dir ) {
PackedData : : PackedDir * pd = _find_dir ( p_dir ) ;
if ( pd ) {
current = pd ;
return OK ;
} else {
return ERR_INVALID_PARAMETER ;
}
2014-02-10 01:10:30 +00:00
}
2022-03-23 09:08:58 +00:00
String DirAccessPack : : get_current_dir ( bool p_include_drive ) const {
2014-02-10 01:10:30 +00:00
PackedData : : PackedDir * pd = current ;
2017-05-04 00:20:53 +00:00
String p = current - > name ;
2014-02-10 01:10:30 +00:00
2017-05-04 00:20:53 +00:00
while ( pd - > parent ) {
pd = pd - > parent ;
2022-08-30 00:34:01 +00:00
p = pd - > name . path_join ( p ) ;
2014-02-10 01:10:30 +00:00
}
return " res:// " + p ;
}
bool DirAccessPack : : file_exists ( String p_file ) {
2019-08-17 17:03:18 +00:00
p_file = fix_path ( p_file ) ;
2020-07-27 10:06:40 +00:00
PackedData : : PackedDir * pd = _find_dir ( p_file . get_base_dir ( ) ) ;
if ( ! pd ) {
return false ;
}
return pd - > files . has ( p_file . get_file ( ) ) ;
2014-02-10 01:10:30 +00:00
}
2014-05-25 03:34:51 +00:00
bool DirAccessPack : : dir_exists ( String p_dir ) {
2019-08-17 17:03:18 +00:00
p_dir = fix_path ( p_dir ) ;
2020-07-27 10:06:40 +00:00
return _find_dir ( p_dir ) ! = nullptr ;
2014-05-25 03:34:51 +00:00
}
2014-02-10 01:10:30 +00:00
Error DirAccessPack : : make_dir ( String p_dir ) {
return ERR_UNAVAILABLE ;
}
Error DirAccessPack : : rename ( String p_from , String p_to ) {
return ERR_UNAVAILABLE ;
}
2020-05-14 12:29:06 +00:00
2014-02-10 01:10:30 +00:00
Error DirAccessPack : : remove ( String p_name ) {
return ERR_UNAVAILABLE ;
}
2019-03-26 17:51:13 +00:00
uint64_t DirAccessPack : : get_space_left ( ) {
2014-02-10 01:10:30 +00:00
return 0 ;
}
2019-01-21 18:23:08 +00:00
String DirAccessPack : : get_filesystem_type ( ) const {
return " PCK " ;
}
2014-02-10 01:10:30 +00:00
DirAccessPack : : DirAccessPack ( ) {
current = PackedData : : get_singleton ( ) - > root ;
}