diff options
Diffstat (limited to 'core/io/file_access_pack.cpp')
-rw-r--r-- | core/io/file_access_pack.cpp | 165 |
1 files changed, 86 insertions, 79 deletions
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index 7b43daf9c0..595a6e9873 100644 --- a/core/io/file_access_pack.cpp +++ b/core/io/file_access_pack.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -32,6 +32,7 @@ #include "core/io/file_access_encrypted.h" #include "core/object/script_language.h" +#include "core/os/os.h" #include "core/version.h" #include <stdio.h> @@ -70,7 +71,7 @@ void PackedData::add_path(const String &p_pkg_path, const String &p_path, uint64 String p = p_path.replace_first("res://", ""); PackedDir *cd = root; - if (p.find("/") != -1) { //in a subdir + if (p.contains("/")) { //in a subdir Vector<String> ds = p.get_base_dir().split("/"); @@ -110,8 +111,8 @@ PackedData::PackedData() { } void PackedData::_free_packed_dirs(PackedDir *p_dir) { - for (Map<String, PackedDir *>::Element *E = p_dir->subdirs.front(); E; E = E->next()) { - _free_packed_dirs(E->get()); + for (const KeyValue<String, PackedDir *> &E : p_dir->subdirs) { + _free_packed_dirs(E.value); } memdelete(p_dir); } @@ -126,60 +127,81 @@ PackedData::~PackedData() { ////////////////////////////////////////////////////////////////// bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) { - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + if (f.is_null()) { return false; } - f->seek(p_offset); + bool pck_header_found = false; + // Search for the header at the start offset - standalone PCK file. + f->seek(p_offset); uint32_t magic = f->get_32(); + if (magic == PACK_HEADER_MAGIC) { + pck_header_found = true; + } - if (magic != PACK_HEADER_MAGIC) { - // loading with offset feature not supported for self contained exe files + // 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) { - f->close(); - memdelete(f); ERR_FAIL_V_MSG(false, "Loading self-contained executable with offset not supported."); } - //maybe at the end.... self contained exe - f->seek_end(); - f->seek(f->get_position() - 4); - magic = f->get_32(); - if (magic != PACK_HEADER_MAGIC) { - f->close(); - memdelete(f); - return false; + 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++; + } } - f->seek(f->get_position() - 12); + } - uint64_t ds = f->get_64(); - f->seek(f->get_position() - ds - 8); + // 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."); + } + f->seek_end(); + f->seek(f->get_position() - 4); magic = f->get_32(); - if (magic != PACK_HEADER_MAGIC) { - f->close(); - memdelete(f); - return false; + + 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; + } } } + if (!pck_header_found) { + return false; + } + uint32_t version = f->get_32(); uint32_t ver_major = f->get_32(); uint32_t ver_minor = f->get_32(); f->get_32(); // patch number, not used for validation. - if (version != PACK_FORMAT_VERSION) { - f->close(); - memdelete(f); - ERR_FAIL_V_MSG(false, "Pack version unsupported: " + itos(version) + "."); - } - if (ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR)) { - f->close(); - memdelete(f); - ERR_FAIL_V_MSG(false, "Pack created with a newer version of the engine: " + itos(ver_major) + "." + itos(ver_minor) + "."); - } + ERR_FAIL_COND_V_MSG(version != PACK_FORMAT_VERSION, false, "Pack version unsupported: " + itos(version) + "."); + ERR_FAIL_COND_V_MSG(ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR), false, "Pack created with a newer version of the engine: " + itos(ver_major) + "." + itos(ver_minor) + "."); uint32_t pack_flags = f->get_32(); uint64_t file_base = f->get_64(); @@ -194,12 +216,9 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, int file_count = f->get_32(); if (enc_directory) { - FileAccessEncrypted *fae = memnew(FileAccessEncrypted); - if (!fae) { - f->close(); - memdelete(f); - ERR_FAIL_V_MSG(false, "Can't open encrypted pack directory."); - } + Ref<FileAccessEncrypted> fae; + fae.instantiate(); + ERR_FAIL_COND_V_MSG(fae.is_null(), false, "Can't open encrypted pack directory."); Vector<uint8_t> key; key.resize(32); @@ -208,12 +227,7 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, } Error err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_READ, false); - if (err) { - f->close(); - memdelete(f); - memdelete(fae); - ERR_FAIL_V_MSG(false, "Can't open encrypted pack directory."); - } + ERR_FAIL_COND_V_MSG(err, false, "Can't open encrypted pack directory."); f = fae; } @@ -236,12 +250,10 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, PackedData::get_singleton()->add_path(p_path, path, ofs + p_offset, size, md5, this, p_replace_files, (flags & PACK_FILE_ENCRYPTED)); } - f->close(); - memdelete(f); return true; } -FileAccess *PackedSourcePCK::get_file(const String &p_path, PackedData::PackedFile *p_file) { +Ref<FileAccess> PackedSourcePCK::get_file(const String &p_path, PackedData::PackedFile *p_file) { return memnew(FileAccessPack(p_path, *p_file)); } @@ -252,15 +264,17 @@ Error FileAccessPack::_open(const String &p_path, int p_mode_flags) { return ERR_UNAVAILABLE; } -void FileAccessPack::close() { - f->close(); -} - bool FileAccessPack::is_open() const { - return f->is_open(); + if (f.is_valid()) { + return f->is_open(); + } else { + return false; + } } void FileAccessPack::seek(uint64_t p_position) { + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use."); + if (p_position > pf.size) { eof = true; } else { @@ -288,6 +302,7 @@ bool FileAccessPack::eof_reached() const { } uint8_t FileAccessPack::get_8() const { + ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use."); if (pos >= pf.size) { eof = true; return 0; @@ -298,6 +313,7 @@ uint8_t FileAccessPack::get_8() const { } uint64_t FileAccessPack::get_buffer(uint8_t *p_dst, uint64_t p_length) const { + ERR_FAIL_COND_V_MSG(f.is_null(), -1, "File must be opened before use."); ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); if (eof) { @@ -321,6 +337,8 @@ uint64_t FileAccessPack::get_buffer(uint8_t *p_dst, uint64_t p_length) const { } void FileAccessPack::set_big_endian(bool p_big_endian) { + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use."); + FileAccess::set_big_endian(p_big_endian); f->set_big_endian(p_big_endian); } @@ -351,16 +369,15 @@ bool FileAccessPack::file_exists(const String &p_name) { FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file) : pf(p_file), f(FileAccess::open(pf.pack, FileAccess::READ)) { - ERR_FAIL_COND_MSG(!f, "Can't open pack-referenced file '" + String(pf.pack) + "'."); + ERR_FAIL_COND_MSG(f.is_null(), "Can't open pack-referenced file '" + String(pf.pack) + "'."); f->seek(pf.offset); off = pf.offset; if (pf.encrypted) { - FileAccessEncrypted *fae = memnew(FileAccessEncrypted); - if (!fae) { - ERR_FAIL_MSG("Can't open encrypted pack-referenced file '" + String(pf.pack) + "'."); - } + Ref<FileAccessEncrypted> fae; + fae.instantiate(); + ERR_FAIL_COND_MSG(fae.is_null(), "Can't open encrypted pack-referenced file '" + String(pf.pack) + "'."); Vector<uint8_t> key; key.resize(32); @@ -369,10 +386,7 @@ FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFil } Error err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_READ, false); - if (err) { - memdelete(fae); - ERR_FAIL_MSG("Can't open encrypted pack-referenced file '" + String(pf.pack) + "'."); - } + ERR_FAIL_COND_MSG(err, "Can't open encrypted pack-referenced file '" + String(pf.pack) + "'."); f = fae; off = 0; } @@ -380,13 +394,6 @@ FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFil eof = false; } -FileAccessPack::~FileAccessPack() { - if (f) { - f->close(); - memdelete(f); - } -} - ////////////////////////////////////////////////////////////////////////////////// // DIR ACCESS ////////////////////////////////////////////////////////////////////////////////// @@ -395,12 +402,12 @@ Error DirAccessPack::list_dir_begin() { list_dirs.clear(); list_files.clear(); - for (Map<String, PackedData::PackedDir *>::Element *E = current->subdirs.front(); E; E = E->next()) { - list_dirs.push_back(E->key()); + for (const KeyValue<String, PackedData::PackedDir *> &E : current->subdirs) { + list_dirs.push_back(E.key); } - for (Set<String>::Element *E = current->files.front(); E; E = E->next()) { - list_files.push_back(E->get()); + for (const String &E : current->files) { + list_files.push_back(E); } return OK; @@ -459,7 +466,7 @@ PackedData::PackedDir *DirAccessPack::_find_dir(String p_dir) { nd = nd.simplify_path(); - if (nd == "") { + if (nd.is_empty()) { nd = "."; } @@ -507,7 +514,7 @@ Error DirAccessPack::change_dir(String p_dir) { } } -String DirAccessPack::get_current_dir(bool p_include_drive) { +String DirAccessPack::get_current_dir(bool p_include_drive) const { PackedData::PackedDir *pd = current; String p = current->name; |