2014-02-10 09:10:30 +08:00
/*************************************************************************/
/* file_access_pack.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 20:16:55 +08:00
/* https://godotengine.org */
2014-02-10 09:10:30 +08:00
/*************************************************************************/
2020-01-01 18:16:22 +08:00
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
2014-02-10 09:10:30 +08:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
2018-01-05 07:50:27 +08:00
2014-02-10 09:10:30 +08:00
# ifndef FILE_ACCESS_PACK_H
# define FILE_ACCESS_PACK_H
2018-09-12 00:13:45 +08:00
# include "core/os/dir_access.h"
# include "core/os/file_access.h"
2020-11-08 06:33:38 +08:00
# include "core/string/print_string.h"
# include "core/templates/list.h"
# include "core/templates/map.h"
2014-02-10 09:10:30 +08:00
2019-12-01 00:22:22 +08:00
// Godot's packed file magic header ("GDPC" in ASCII).
# define PACK_HEADER_MAGIC 0x43504447
// The current packed file format version number.
2020-04-29 01:51:29 +08:00
# define PACK_FORMAT_VERSION 2
enum PackFlags {
PACK_DIR_ENCRYPTED = 1 < < 0
} ;
enum PackFileFlags {
PACK_FILE_ENCRYPTED = 1 < < 0
} ;
2019-12-01 00:22:22 +08:00
2014-02-10 09:10:30 +08:00
class PackSource ;
class PackedData {
2017-03-05 23:44:50 +08:00
friend class FileAccessPack ;
friend class DirAccessPack ;
friend class PackSource ;
2014-02-10 09:10:30 +08:00
public :
struct PackedFile {
String pack ;
2014-02-14 05:03:28 +08:00
uint64_t offset ; //if offset is ZERO, the file was ERASED
2014-02-10 09:10:30 +08:00
uint64_t size ;
2014-02-14 05:03:28 +08:00
uint8_t md5 [ 16 ] ;
2017-03-05 23:44:50 +08:00
PackSource * src ;
2020-04-29 01:51:29 +08:00
bool encrypted ;
2014-02-10 09:10:30 +08:00
} ;
private :
struct PackedDir {
2020-05-12 23:01:17 +08:00
PackedDir * parent = nullptr ;
2014-02-10 09:10:30 +08:00
String name ;
2017-03-05 23:44:50 +08:00
Map < String , PackedDir * > subdirs ;
2014-02-10 09:10:30 +08:00
Set < String > files ;
} ;
2014-08-02 09:10:38 +08:00
struct PathMD5 {
2020-05-12 23:01:17 +08:00
uint64_t a = 0 ;
uint64_t b = 0 ;
2017-03-05 23:44:50 +08:00
bool operator < ( const PathMD5 & p_md5 ) const {
2014-08-02 09:10:38 +08:00
if ( p_md5 . a = = a ) {
return b < p_md5 . b ;
} else {
return a < p_md5 . a ;
}
}
2017-03-05 23:44:50 +08:00
bool operator = = ( const PathMD5 & p_md5 ) const {
2014-08-02 09:10:38 +08:00
return a = = p_md5 . a & & b = = p_md5 . b ;
2020-05-19 21:46:49 +08:00
}
2014-08-02 09:10:38 +08:00
2020-05-12 23:01:17 +08:00
PathMD5 ( ) { }
2014-08-02 09:10:38 +08:00
PathMD5 ( const Vector < uint8_t > p_buf ) {
2017-03-05 23:44:50 +08:00
a = * ( ( uint64_t * ) & p_buf [ 0 ] ) ;
b = * ( ( uint64_t * ) & p_buf [ 8 ] ) ;
2020-05-12 23:01:17 +08:00
}
2014-08-02 09:10:38 +08:00
} ;
2017-03-05 23:44:50 +08:00
Map < PathMD5 , PackedFile > files ;
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
Vector < PackSource * > sources ;
2014-02-10 09:10:30 +08:00
PackedDir * root ;
static PackedData * singleton ;
2020-05-12 23:01:17 +08:00
bool disabled = false ;
2014-02-10 09:10:30 +08:00
2015-04-21 06:38:02 +08:00
void _free_packed_dirs ( PackedDir * p_dir ) ;
2014-02-10 09:10:30 +08:00
public :
2017-03-05 23:44:50 +08:00
void add_pack_source ( PackSource * p_source ) ;
2020-04-29 01:51:29 +08:00
void add_path ( const String & pkg_path , const String & path , uint64_t ofs , uint64_t size , const uint8_t * p_md5 , PackSource * p_src , bool p_replace_files , bool p_encrypted = false ) ; // for PackSource
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
void set_disabled ( bool p_disabled ) { disabled = p_disabled ; }
2014-02-10 09:10:30 +08:00
_FORCE_INLINE_ bool is_disabled ( ) const { return disabled ; }
static PackedData * get_singleton ( ) { return singleton ; }
2020-07-14 00:22:06 +08:00
Error add_pack ( const String & p_path , bool p_replace_files , size_t p_offset ) ;
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
_FORCE_INLINE_ FileAccess * try_open_path ( const String & p_path ) ;
_FORCE_INLINE_ bool has_path ( const String & p_path ) ;
2014-02-10 09:10:30 +08:00
2020-07-27 18:06:40 +08:00
_FORCE_INLINE_ DirAccess * try_open_directory ( const String & p_path ) ;
_FORCE_INLINE_ bool has_directory ( const String & p_path ) ;
2014-02-10 09:10:30 +08:00
PackedData ( ) ;
2015-04-21 06:38:02 +08:00
~ PackedData ( ) ;
2014-02-10 09:10:30 +08:00
} ;
class PackSource {
public :
2020-07-14 00:22:06 +08:00
virtual bool try_open_pack ( const String & p_path , bool p_replace_files , size_t p_offset ) = 0 ;
2017-03-05 23:44:50 +08:00
virtual FileAccess * get_file ( const String & p_path , PackedData : : PackedFile * p_file ) = 0 ;
2015-04-21 06:38:02 +08:00
virtual ~ PackSource ( ) { }
2014-02-10 09:10:30 +08:00
} ;
class PackedSourcePCK : public PackSource {
public :
2020-07-14 00:22:06 +08:00
virtual bool try_open_pack ( const String & p_path , bool p_replace_files , size_t p_offset ) ;
2017-03-05 23:44:50 +08:00
virtual FileAccess * get_file ( const String & p_path , PackedData : : PackedFile * p_file ) ;
2014-02-10 09:10:30 +08:00
} ;
class FileAccessPack : public FileAccess {
PackedData : : PackedFile pf ;
mutable size_t pos ;
mutable bool eof ;
2020-04-29 01:51:29 +08:00
uint64_t off ;
2014-02-10 09:10:30 +08:00
FileAccess * f ;
2017-03-05 23:44:50 +08: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-08 02:46:52 +08: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 09:10:30 +08:00
public :
virtual void close ( ) ;
virtual bool is_open ( ) const ;
virtual void seek ( size_t p_position ) ;
2017-03-05 23:44:50 +08:00
virtual void seek_end ( int64_t p_position = 0 ) ;
2017-09-10 21:37:49 +08:00
virtual size_t get_position ( ) const ;
2014-02-10 09:10:30 +08:00
virtual size_t get_len ( ) const ;
virtual bool eof_reached ( ) const ;
virtual uint8_t get_8 ( ) const ;
2017-03-05 23:44:50 +08:00
virtual int get_buffer ( uint8_t * p_dst , int p_length ) const ;
2014-02-10 09:10:30 +08:00
virtual void set_endian_swap ( bool p_swap ) ;
virtual Error get_error ( ) const ;
2017-09-22 13:56:02 +08:00
virtual void flush ( ) ;
2014-02-10 09:10:30 +08:00
virtual void store_8 ( uint8_t p_dest ) ;
2017-03-05 23:44:50 +08:00
virtual void store_buffer ( const uint8_t * p_src , int p_length ) ;
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
virtual bool file_exists ( const String & p_name ) ;
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
FileAccessPack ( const String & p_path , const PackedData : : PackedFile & p_file ) ;
2014-02-10 09:10:30 +08:00
~ FileAccessPack ( ) ;
} ;
2017-03-05 23:44:50 +08:00
FileAccess * PackedData : : try_open_path ( const String & p_path ) {
2014-08-02 09:10:38 +08:00
PathMD5 pmd5 ( p_path . md5_buffer ( ) ) ;
2017-03-05 23:44:50 +08:00
Map < PathMD5 , PackedFile > : : Element * E = files . find ( pmd5 ) ;
2020-05-14 22:41:43 +08:00
if ( ! E ) {
2020-04-02 07:20:12 +08:00
return nullptr ; //not found
2020-05-14 22:41:43 +08:00
}
if ( E - > get ( ) . offset = = 0 ) {
2020-04-02 07:20:12 +08:00
return nullptr ; //was erased
2020-05-14 22:41:43 +08:00
}
2014-02-10 09:10:30 +08:00
2014-02-14 05:03:28 +08:00
return E - > get ( ) . src - > get_file ( p_path , & E - > get ( ) ) ;
2014-02-10 09:10:30 +08:00
}
2017-03-05 23:44:50 +08:00
bool PackedData : : has_path ( const String & p_path ) {
2014-08-02 09:10:38 +08:00
return files . has ( PathMD5 ( p_path . md5_buffer ( ) ) ) ;
2014-02-10 09:10:30 +08:00
}
2020-07-27 18:06:40 +08:00
bool PackedData : : has_directory ( const String & p_path ) {
DirAccess * da = try_open_directory ( p_path ) ;
if ( da ) {
memdelete ( da ) ;
return true ;
} else {
return false ;
}
}
2014-02-10 09:10:30 +08:00
class DirAccessPack : public DirAccess {
PackedData : : PackedDir * current ;
List < String > list_dirs ;
List < String > list_files ;
2020-05-12 23:01:17 +08:00
bool cdir = false ;
2014-02-10 09:10:30 +08:00
2020-07-27 18:06:40 +08:00
PackedData : : PackedDir * _find_dir ( String p_dir ) ;
2014-02-10 09:10:30 +08:00
public :
2017-01-14 20:16:41 +08:00
virtual Error list_dir_begin ( ) ;
2014-02-10 09:10:30 +08:00
virtual String get_next ( ) ;
virtual bool current_is_dir ( ) const ;
2015-03-22 01:33:32 +08:00
virtual bool current_is_hidden ( ) const ;
2014-02-10 09:10:30 +08: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 ) ;
2020-02-10 16:19:29 +08:00
virtual String get_current_dir ( bool p_include_drive = true ) ;
2014-02-10 09:10:30 +08:00
virtual bool file_exists ( String p_file ) ;
2014-05-25 11:34:51 +08:00
virtual bool dir_exists ( String p_dir ) ;
2014-02-10 09:10:30 +08:00
virtual Error make_dir ( String p_dir ) ;
virtual Error rename ( String p_from , String p_to ) ;
virtual Error remove ( String p_name ) ;
size_t get_space_left ( ) ;
2019-01-22 02:23:08 +08:00
virtual String get_filesystem_type ( ) const ;
2014-02-10 09:10:30 +08:00
DirAccessPack ( ) ;
2020-05-12 23:01:17 +08:00
~ DirAccessPack ( ) { }
2014-02-10 09:10:30 +08:00
} ;
2020-07-27 18:06:40 +08:00
DirAccess * PackedData : : try_open_directory ( const String & p_path ) {
DirAccess * da = memnew ( DirAccessPack ( ) ) ;
if ( da - > change_dir ( p_path ) ! = OK ) {
memdelete ( da ) ;
da = nullptr ;
}
return da ;
}
2014-02-10 09:10:30 +08:00
# endif // FILE_ACCESS_PACK_H