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