2014-02-10 01:10:30 +00:00
/*************************************************************************/
/* file_access_pack.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 12:16:55 +00:00
/* https://godotengine.org */
2014-02-10 01:10:30 +00:00
/*************************************************************************/
2022-01-03 20:27:34 +00:00
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
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. */
/*************************************************************************/
2018-01-04 23:50:27 +00:00
2014-02-10 01:10:30 +00:00
# ifndef FILE_ACCESS_PACK_H
# define FILE_ACCESS_PACK_H
2021-06-11 12:51:48 +00:00
# include "core/io/dir_access.h"
# include "core/io/file_access.h"
2020-11-07 22:33:38 +00:00
# include "core/string/print_string.h"
2022-05-19 15:00:06 +00:00
# include "core/templates/hash_set.h"
2020-11-07 22:33:38 +00:00
# include "core/templates/list.h"
2022-05-13 13:04:37 +00:00
# include "core/templates/rb_map.h"
2014-02-10 01:10:30 +00:00
2019-11-30 16:22:22 +00:00
// Godot's packed file magic header ("GDPC" in ASCII).
# define PACK_HEADER_MAGIC 0x43504447
// The current packed file format version number.
2020-04-28 17:51:29 +00:00
# define PACK_FORMAT_VERSION 2
enum PackFlags {
PACK_DIR_ENCRYPTED = 1 < < 0
} ;
enum PackFileFlags {
PACK_FILE_ENCRYPTED = 1 < < 0
} ;
2019-11-30 16:22:22 +00:00
2014-02-10 01:10:30 +00:00
class PackSource ;
class PackedData {
2017-03-05 15:44:50 +00:00
friend class FileAccessPack ;
friend class DirAccessPack ;
friend class PackSource ;
2014-02-10 01:10:30 +00:00
public :
struct PackedFile {
String pack ;
2014-02-13 21:03:28 +00:00
uint64_t offset ; //if offset is ZERO, the file was ERASED
2014-02-10 01:10:30 +00:00
uint64_t size ;
2014-02-13 21:03:28 +00:00
uint8_t md5 [ 16 ] ;
2022-04-04 13:06:57 +00:00
PackSource * src = nullptr ;
2020-04-28 17:51:29 +00:00
bool encrypted ;
2014-02-10 01:10:30 +00:00
} ;
private :
struct PackedDir {
2020-05-12 15:01:17 +00:00
PackedDir * parent = nullptr ;
2014-02-10 01:10:30 +00:00
String name ;
2022-05-13 13:04:37 +00:00
HashMap < String , PackedDir * > subdirs ;
2022-05-19 15:00:06 +00:00
HashSet < String > files ;
2014-02-10 01:10:30 +00:00
} ;
2014-08-02 01:10:38 +00:00
struct PathMD5 {
2020-05-12 15:01:17 +00:00
uint64_t a = 0 ;
uint64_t b = 0 ;
2014-08-02 01:10:38 +00:00
2022-05-13 13:04:37 +00:00
bool operator = = ( const PathMD5 & p_val ) const {
return ( a = = p_val . a ) & & ( b = = p_val . b ) ;
}
static uint32_t hash ( const PathMD5 & p_val ) {
uint32_t h = hash_djb2_one_32 ( p_val . a ) ;
return hash_djb2_one_32 ( p_val . b , h ) ;
2020-05-19 13:46:49 +00:00
}
2014-08-02 01:10:38 +00:00
2020-05-12 15:01:17 +00:00
PathMD5 ( ) { }
2014-08-02 01:10:38 +00:00
2022-04-07 10:23:40 +00:00
explicit PathMD5 ( const Vector < uint8_t > & p_buf ) {
2017-03-05 15:44:50 +00:00
a = * ( ( uint64_t * ) & p_buf [ 0 ] ) ;
b = * ( ( uint64_t * ) & p_buf [ 8 ] ) ;
2020-05-12 15:01:17 +00:00
}
2014-08-02 01:10:38 +00:00
} ;
2022-05-13 13:04:37 +00:00
HashMap < PathMD5 , PackedFile , PathMD5 > files ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Vector < PackSource * > sources ;
2014-02-10 01:10:30 +00:00
2022-04-04 13:06:57 +00:00
PackedDir * root = nullptr ;
2014-02-10 01:10:30 +00:00
static PackedData * singleton ;
2020-05-12 15:01:17 +00:00
bool disabled = false ;
2014-02-10 01:10:30 +00:00
2015-04-20 22:38:02 +00:00
void _free_packed_dirs ( PackedDir * p_dir ) ;
2014-02-10 01:10:30 +00:00
public :
2017-03-05 15:44:50 +00:00
void add_pack_source ( PackSource * p_source ) ;
2019-03-26 17:51:13 +00:00
void 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 = false ) ; // for PackSource
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
void set_disabled ( bool p_disabled ) { disabled = p_disabled ; }
2014-02-10 01:10:30 +00:00
_FORCE_INLINE_ bool is_disabled ( ) const { return disabled ; }
static PackedData * get_singleton ( ) { return singleton ; }
2019-03-26 17:51:13 +00:00
Error add_pack ( const String & p_path , bool p_replace_files , uint64_t p_offset ) ;
2014-02-10 01:10:30 +00:00
2022-03-23 09:08:58 +00:00
_FORCE_INLINE_ Ref < FileAccess > try_open_path ( const String & p_path ) ;
2017-03-05 15:44:50 +00:00
_FORCE_INLINE_ bool has_path ( const String & p_path ) ;
2014-02-10 01:10:30 +00:00
2022-03-23 09:08:58 +00:00
_FORCE_INLINE_ Ref < DirAccess > try_open_directory ( const String & p_path ) ;
2020-07-27 10:06:40 +00:00
_FORCE_INLINE_ bool has_directory ( const String & p_path ) ;
2014-02-10 01:10:30 +00:00
PackedData ( ) ;
2015-04-20 22:38:02 +00:00
~ PackedData ( ) ;
2014-02-10 01:10:30 +00:00
} ;
class PackSource {
public :
2019-03-26 17:51:13 +00:00
virtual bool try_open_pack ( const String & p_path , bool p_replace_files , uint64_t p_offset ) = 0 ;
2022-03-23 09:08:58 +00:00
virtual Ref < FileAccess > get_file ( const String & p_path , PackedData : : PackedFile * p_file ) = 0 ;
2015-04-20 22:38:02 +00:00
virtual ~ PackSource ( ) { }
2014-02-10 01:10:30 +00:00
} ;
class PackedSourcePCK : public PackSource {
public :
2022-04-05 10:40:26 +00:00
virtual bool try_open_pack ( const String & p_path , bool p_replace_files , uint64_t p_offset ) override ;
2022-03-23 09:08:58 +00:00
virtual Ref < FileAccess > get_file ( const String & p_path , PackedData : : PackedFile * p_file ) override ;
2014-02-10 01:10:30 +00:00
} ;
class FileAccessPack : public FileAccess {
PackedData : : PackedFile pf ;
2019-03-26 17:51:13 +00:00
mutable uint64_t pos ;
2014-02-10 01:10:30 +00:00
mutable bool eof ;
2020-04-28 17:51:29 +00:00
uint64_t off ;
2014-02-10 01:10:30 +00:00
2022-03-23 09:08:58 +00:00
Ref < FileAccess > f ;
2017-03-05 15:44:50 +00:00
virtual Error _open ( const String & p_path , int p_mode_flags ) ;
virtual uint64_t _get_modified_time ( const String & p_file ) { return 0 ; }
2019-04-07 18:46:52 +00:00
virtual uint32_t _get_unix_permissions ( const String & p_file ) { return 0 ; }
virtual Error _set_unix_permissions ( const String & p_file , uint32_t p_permissions ) { return FAILED ; }
2014-02-10 01:10:30 +00:00
public :
virtual bool is_open ( ) const ;
2019-03-26 17:51:13 +00:00
virtual void seek ( uint64_t p_position ) ;
2017-03-05 15:44:50 +00:00
virtual void seek_end ( int64_t p_position = 0 ) ;
2019-03-26 17:51:13 +00:00
virtual uint64_t get_position ( ) const ;
2021-05-25 06:58:49 +00:00
virtual uint64_t get_length ( ) const ;
2014-02-10 01:10:30 +00:00
virtual bool eof_reached ( ) const ;
virtual uint8_t get_8 ( ) const ;
2019-03-26 17:51:13 +00:00
virtual uint64_t get_buffer ( uint8_t * p_dst , uint64_t p_length ) const ;
2014-02-10 01:10:30 +00:00
2021-05-20 12:58:03 +00:00
virtual void set_big_endian ( bool p_big_endian ) ;
2014-02-10 01:10:30 +00:00
virtual Error get_error ( ) const ;
2017-09-22 05:56:02 +00:00
virtual void flush ( ) ;
2014-02-10 01:10:30 +00:00
virtual void store_8 ( uint8_t p_dest ) ;
2019-03-26 17:51:13 +00:00
virtual void store_buffer ( const uint8_t * p_src , uint64_t p_length ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
virtual bool file_exists ( const String & p_name ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
FileAccessPack ( const String & p_path , const PackedData : : PackedFile & p_file ) ;
2014-02-10 01:10:30 +00:00
} ;
2022-03-23 09:08:58 +00:00
Ref < FileAccess > PackedData : : try_open_path ( const String & p_path ) {
2014-08-02 01:10:38 +00:00
PathMD5 pmd5 ( p_path . md5_buffer ( ) ) ;
2022-05-13 13:04:37 +00:00
HashMap < PathMD5 , PackedFile , PathMD5 > : : Iterator E = files . find ( pmd5 ) ;
2020-05-14 14:41:43 +00:00
if ( ! E ) {
2020-04-01 23:20:12 +00:00
return nullptr ; //not found
2020-05-14 14:41:43 +00:00
}
2022-05-13 13:04:37 +00:00
if ( E - > value . offset = = 0 ) {
2020-04-01 23:20:12 +00:00
return nullptr ; //was erased
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2022-05-13 13:04:37 +00:00
return E - > value . src - > get_file ( p_path , & E - > value ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
bool PackedData : : has_path ( const String & p_path ) {
2014-08-02 01:10:38 +00:00
return files . has ( PathMD5 ( p_path . md5_buffer ( ) ) ) ;
2014-02-10 01:10:30 +00:00
}
2020-07-27 10:06:40 +00:00
bool PackedData : : has_directory ( const String & p_path ) {
2022-03-23 09:08:58 +00:00
Ref < DirAccess > da = try_open_directory ( p_path ) ;
if ( da . is_valid ( ) ) {
2020-07-27 10:06:40 +00:00
return true ;
} else {
return false ;
}
}
2014-02-10 01:10:30 +00:00
class DirAccessPack : public DirAccess {
PackedData : : PackedDir * current ;
List < String > list_dirs ;
List < String > list_files ;
2020-05-12 15:01:17 +00:00
bool cdir = false ;
2014-02-10 01:10:30 +00:00
2020-07-27 10:06:40 +00:00
PackedData : : PackedDir * _find_dir ( String p_dir ) ;
2014-02-10 01:10:30 +00:00
public :
2017-01-14 12:16:41 +00:00
virtual Error list_dir_begin ( ) ;
2014-02-10 01:10:30 +00:00
virtual String get_next ( ) ;
virtual bool current_is_dir ( ) const ;
2015-03-21 17:33:32 +00:00
virtual bool current_is_hidden ( ) const ;
2014-02-10 01:10:30 +00:00
virtual void list_dir_end ( ) ;
virtual int get_drive_count ( ) ;
virtual String get_drive ( int p_drive ) ;
virtual Error change_dir ( String p_dir ) ;
2022-03-23 09:08:58 +00:00
virtual String get_current_dir ( bool p_include_drive = true ) const ;
2014-02-10 01:10:30 +00:00
virtual bool file_exists ( String p_file ) ;
2014-05-25 03:34:51 +00:00
virtual bool dir_exists ( String p_dir ) ;
2014-02-10 01:10:30 +00:00
virtual Error make_dir ( String p_dir ) ;
virtual Error rename ( String p_from , String p_to ) ;
virtual Error remove ( String p_name ) ;
2019-03-26 17:51:13 +00:00
uint64_t get_space_left ( ) ;
2014-02-10 01:10:30 +00:00
2021-03-10 10:55:31 +00:00
virtual bool is_link ( String p_file ) { return false ; }
virtual String read_link ( String p_file ) { return p_file ; }
virtual Error create_link ( String p_source , String p_target ) { return FAILED ; }
2019-01-21 18:23:08 +00:00
virtual String get_filesystem_type ( ) const ;
2014-02-10 01:10:30 +00:00
DirAccessPack ( ) ;
} ;
2022-03-23 09:08:58 +00:00
Ref < DirAccess > PackedData : : try_open_directory ( const String & p_path ) {
Ref < DirAccess > da = memnew ( DirAccessPack ( ) ) ;
2020-07-27 10:06:40 +00:00
if ( da - > change_dir ( p_path ) ! = OK ) {
2022-03-23 09:08:58 +00:00
da = Ref < DirAccess > ( ) ;
2020-07-27 10:06:40 +00:00
}
return da ;
}
2014-02-10 01:10:30 +00:00
# endif // FILE_ACCESS_PACK_H