Allow providing Android APK/AAB as base packs for patch PCKs
This commit is contained in:
parent
0df713417b
commit
f21053e4ef
8 changed files with 242 additions and 98 deletions
|
|
@ -36,9 +36,9 @@
|
|||
#include "core/os/os.h"
|
||||
#include "core/version.h"
|
||||
|
||||
Error PackedData::add_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) {
|
||||
Error PackedData::add_pack(const String &p_path, bool p_replace_files, uint64_t p_offset, const Vector<uint8_t> &p_decryption_key) {
|
||||
for (int i = 0; i < sources.size(); i++) {
|
||||
if (sources[i]->try_open_pack(p_path, p_replace_files, p_offset)) {
|
||||
if (sources[i]->try_open_pack(p_path, p_replace_files, p_offset, p_decryption_key)) {
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
|
@ -215,7 +215,7 @@ PackedData::~PackedData() {
|
|||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) {
|
||||
bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset, const Vector<uint8_t> &p_decryption_key) {
|
||||
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
|
||||
if (f.is_null()) {
|
||||
return false;
|
||||
|
|
@ -330,9 +330,18 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files,
|
|||
ERR_FAIL_COND_V_MSG(fae.is_null(), false, "Can't open encrypted pack directory.");
|
||||
|
||||
Vector<uint8_t> key;
|
||||
key.resize(32);
|
||||
for (int i = 0; i < key.size(); i++) {
|
||||
key.write[i] = script_encryption_key[i];
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (!p_decryption_key.is_empty()) {
|
||||
ERR_FAIL_COND_V_MSG(p_decryption_key.size() != 32, false, "Decryption key must be 256-bit.");
|
||||
constexpr uint8_t empty_key[32] = {};
|
||||
if (memcmp(script_encryption_key, empty_key, sizeof(empty_key)) == 0) {
|
||||
key = p_decryption_key;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
key.resize(32);
|
||||
memcpy(key.ptrw(), script_encryption_key, 32);
|
||||
}
|
||||
|
||||
Error err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_READ, false);
|
||||
|
|
@ -364,8 +373,8 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files,
|
|||
return true;
|
||||
}
|
||||
|
||||
Ref<FileAccess> PackedSourcePCK::get_file(const String &p_path, PackedData::PackedFile *p_file) {
|
||||
Ref<FileAccess> file(memnew(FileAccessPack(p_path, *p_file)));
|
||||
Ref<FileAccess> PackedSourcePCK::get_file(const String &p_path, PackedData::PackedFile *p_file, const Vector<uint8_t> &p_decryption_key) {
|
||||
Ref<FileAccess> file(memnew(FileAccessPack(p_path, *p_file, p_decryption_key)));
|
||||
|
||||
if (PackedData::get_singleton()->has_delta_patches(p_path)) {
|
||||
Ref<FileAccessPatched> file_patched;
|
||||
|
|
@ -380,7 +389,7 @@ Ref<FileAccess> PackedSourcePCK::get_file(const String &p_path, PackedData::Pack
|
|||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
bool PackedSourceDirectory::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) {
|
||||
bool PackedSourceDirectory::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset, const Vector<uint8_t> &p_decryption_key) {
|
||||
// Load with offset feature only supported for PCK files.
|
||||
ERR_FAIL_COND_V_MSG(p_offset != 0, false, "Invalid PCK data. Note that loading files with a non-zero offset isn't supported with directories.");
|
||||
|
||||
|
|
@ -391,7 +400,7 @@ bool PackedSourceDirectory::try_open_pack(const String &p_path, bool p_replace_f
|
|||
return true;
|
||||
}
|
||||
|
||||
Ref<FileAccess> PackedSourceDirectory::get_file(const String &p_path, PackedData::PackedFile *p_file) {
|
||||
Ref<FileAccess> PackedSourceDirectory::get_file(const String &p_path, PackedData::PackedFile *p_file, const Vector<uint8_t> &p_decryption_key) {
|
||||
Ref<FileAccess> ret = FileAccess::create_for_path(p_path);
|
||||
ret->reopen(p_path, FileAccess::READ);
|
||||
return ret;
|
||||
|
|
@ -514,16 +523,24 @@ void FileAccessPack::close() {
|
|||
f = Ref<FileAccess>();
|
||||
}
|
||||
|
||||
FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file) {
|
||||
FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file, const Vector<uint8_t> &p_decryption_key) {
|
||||
path = p_path;
|
||||
pf = p_file;
|
||||
if (pf.bundle) {
|
||||
String simplified_path = p_path.simplify_path();
|
||||
if (pf.salt.is_empty()) {
|
||||
f = FileAccess::open(simplified_path, FileAccess::READ | FileAccess::SKIP_PACK);
|
||||
String path_to_load = simplified_path;
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (!pf.salt.is_empty()) {
|
||||
path_to_load = pf.pack.get_base_dir().path_join((simplified_path + pf.salt).sha256_text());
|
||||
} else {
|
||||
f = FileAccess::open("res://" + (simplified_path + pf.salt).sha256_text(), FileAccess::READ | FileAccess::SKIP_PACK);
|
||||
path_to_load = pf.pack.get_base_dir().path_join(simplified_path.replace("res://", ""));
|
||||
}
|
||||
#else
|
||||
if (!pf.salt.is_empty()) {
|
||||
path_to_load = "res://" + (simplified_path + pf.salt).sha256_text();
|
||||
}
|
||||
#endif
|
||||
f = FileAccess::open(path_to_load, FileAccess::READ | FileAccess::SKIP_PACK);
|
||||
ERR_FAIL_COND_MSG(f.is_null(), vformat(R"(Can't open pack-referenced file "%s" from sparse pack "%s".)", simplified_path, pf.pack));
|
||||
off = 0; // For the sparse pack offset is always zero.
|
||||
} else {
|
||||
|
|
@ -539,9 +556,18 @@ FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFil
|
|||
ERR_FAIL_COND_MSG(fae.is_null(), vformat(R"(Can't open encrypted pack-referenced file "%s" from pack "%s".)", p_path, pf.pack));
|
||||
|
||||
Vector<uint8_t> key;
|
||||
key.resize(32);
|
||||
for (int i = 0; i < key.size(); i++) {
|
||||
key.write[i] = script_encryption_key[i];
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (!p_decryption_key.is_empty()) {
|
||||
ERR_FAIL_COND_MSG(p_decryption_key.size() != 32, "Decryption key must be 256-bit.");
|
||||
constexpr uint8_t empty_key[32] = {};
|
||||
if (memcmp(script_encryption_key, empty_key, sizeof(empty_key)) == 0) {
|
||||
key = p_decryption_key;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
key.resize(32);
|
||||
memcpy(key.ptrw(), script_encryption_key, 32);
|
||||
}
|
||||
|
||||
Error err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_READ, false);
|
||||
|
|
|
|||
|
|
@ -132,11 +132,11 @@ public:
|
|||
_FORCE_INLINE_ bool is_disabled() const { return disabled; }
|
||||
|
||||
static PackedData *get_singleton() { return singleton; }
|
||||
Error add_pack(const String &p_path, bool p_replace_files, uint64_t p_offset);
|
||||
Error add_pack(const String &p_path, bool p_replace_files, uint64_t p_offset, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>());
|
||||
|
||||
void clear();
|
||||
|
||||
_FORCE_INLINE_ Ref<FileAccess> try_open_path(const String &p_path);
|
||||
_FORCE_INLINE_ Ref<FileAccess> try_open_path(const String &p_path, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>());
|
||||
_FORCE_INLINE_ bool has_path(const String &p_path);
|
||||
|
||||
_FORCE_INLINE_ int64_t get_size(const String &p_path);
|
||||
|
|
@ -150,23 +150,23 @@ public:
|
|||
|
||||
class PackSource {
|
||||
public:
|
||||
virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) = 0;
|
||||
virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file) = 0;
|
||||
virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>()) = 0;
|
||||
virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>()) = 0;
|
||||
virtual ~PackSource() {}
|
||||
};
|
||||
|
||||
class PackedSourcePCK : public PackSource {
|
||||
public:
|
||||
virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) override;
|
||||
virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file) override;
|
||||
virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>()) override;
|
||||
virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>()) override;
|
||||
};
|
||||
|
||||
class PackedSourceDirectory : public PackSource {
|
||||
void add_directory(const String &p_path, bool p_replace_files);
|
||||
|
||||
public:
|
||||
virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) override;
|
||||
virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file) override;
|
||||
virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>()) override;
|
||||
virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>()) override;
|
||||
};
|
||||
|
||||
class FileAccessPack : public FileAccess {
|
||||
|
|
@ -218,7 +218,7 @@ public:
|
|||
|
||||
virtual void close() override;
|
||||
|
||||
FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file);
|
||||
FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>());
|
||||
};
|
||||
|
||||
int64_t PackedData::get_size(const String &p_path) {
|
||||
|
|
@ -234,7 +234,7 @@ int64_t PackedData::get_size(const String &p_path) {
|
|||
return E->value.size;
|
||||
}
|
||||
|
||||
Ref<FileAccess> PackedData::try_open_path(const String &p_path) {
|
||||
Ref<FileAccess> PackedData::try_open_path(const String &p_path, const Vector<uint8_t> &p_decryption_key) {
|
||||
String simplified_path = p_path.simplify_path().trim_prefix("res://");
|
||||
PathMD5 pmd5(simplified_path.md5_buffer());
|
||||
HashMap<PathMD5, PackedFile, PathMD5>::Iterator E = files.find(pmd5);
|
||||
|
|
@ -242,7 +242,7 @@ Ref<FileAccess> PackedData::try_open_path(const String &p_path) {
|
|||
return nullptr; // Not found.
|
||||
}
|
||||
|
||||
return E->value.src->get_file(p_path, &E->value);
|
||||
return E->value.src->get_file(p_path, &E->value, p_decryption_key);
|
||||
}
|
||||
|
||||
bool PackedData::has_path(const String &p_path) {
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ unzFile ZipArchive::get_file_handle(const String &p_file) const {
|
|||
return pkg;
|
||||
}
|
||||
|
||||
bool ZipArchive::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset = 0) {
|
||||
bool ZipArchive::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset, const Vector<uint8_t> &p_decryption_key) {
|
||||
// load with offset feature only supported for PCK files
|
||||
ERR_FAIL_COND_V_MSG(p_offset != 0, false, "Invalid PCK data. Note that loading files with a non-zero offset isn't supported with ZIP archives.");
|
||||
|
||||
|
|
@ -209,7 +209,7 @@ bool ZipArchive::file_exists(const String &p_name) const {
|
|||
return files.has(p_name);
|
||||
}
|
||||
|
||||
Ref<FileAccess> ZipArchive::get_file(const String &p_path, PackedData::PackedFile *p_file) {
|
||||
Ref<FileAccess> ZipArchive::get_file(const String &p_path, PackedData::PackedFile *p_file, const Vector<uint8_t> &p_decryption_key) {
|
||||
return memnew(FileAccessZip(p_path, *p_file));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,8 +61,8 @@ public:
|
|||
|
||||
bool file_exists(const String &p_name) const;
|
||||
|
||||
virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) override;
|
||||
Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file) override;
|
||||
virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>()) override;
|
||||
Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file, const Vector<uint8_t> &p_decryption_key = Vector<uint8_t>()) override;
|
||||
|
||||
static ZipArchive *get_singleton();
|
||||
|
||||
|
|
|
|||
|
|
@ -220,22 +220,154 @@ bool EditorExportPlatform::fill_log_messages(RichTextLabel *p_log, Error p_err)
|
|||
return has_messages;
|
||||
}
|
||||
|
||||
Error EditorExportPlatform::_load_patches(const Vector<String> &p_patches) {
|
||||
Error EditorExportPlatform::_extract_android_assets(const String &p_bundle_path, String &r_pck_path, String &r_temp_dir) {
|
||||
Error err = OK;
|
||||
|
||||
Ref<FileAccess> io_fa;
|
||||
zlib_filefunc_def io = zipio_create_io(&io_fa);
|
||||
unzFile zip_file = unzOpen2(p_bundle_path.utf8().get_data(), &io);
|
||||
if (!zip_file) {
|
||||
return ERR_FILE_CANT_OPEN;
|
||||
}
|
||||
|
||||
const char *pck_name = "assets.sparsepck";
|
||||
String pck_base_dir;
|
||||
|
||||
int ret = unzGoToFirstFile(zip_file);
|
||||
while (ret == UNZ_OK) {
|
||||
unz_file_info64 file_info = {};
|
||||
char file_name_buf[16384];
|
||||
ret = unzGetCurrentFileInfo64(zip_file, &file_info, file_name_buf, sizeof(file_name_buf), nullptr, 0, nullptr, 0);
|
||||
if (ret != UNZ_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
String file_name = String::utf8(file_name_buf);
|
||||
if (file_name.ends_with(pck_name)) {
|
||||
pck_base_dir = file_name.trim_suffix(pck_name);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = unzGoToNextFile(zip_file);
|
||||
}
|
||||
|
||||
if (ret != UNZ_OK || pck_base_dir.is_empty()) {
|
||||
unzClose(zip_file);
|
||||
return ERR_FILE_UNRECOGNIZED;
|
||||
}
|
||||
|
||||
Ref<DirAccess> temp_dir = DirAccess::create_temp("export_patch_base", true, &err);
|
||||
if (err != OK) {
|
||||
unzClose(zip_file);
|
||||
return err;
|
||||
}
|
||||
|
||||
String temp_dir_path = temp_dir->get_current_dir();
|
||||
|
||||
ret = unzGoToFirstFile(zip_file);
|
||||
while (ret == UNZ_OK) {
|
||||
unz_file_info64 zip_file_info = {};
|
||||
char file_name_buf[16384];
|
||||
if (unzGetCurrentFileInfo64(zip_file, &zip_file_info, file_name_buf, sizeof(file_name_buf), nullptr, 0, nullptr, 0) != UNZ_OK) {
|
||||
err = ERR_FILE_CORRUPT;
|
||||
break;
|
||||
}
|
||||
|
||||
String file_name = String::utf8(file_name_buf);
|
||||
if (!file_name.begins_with(pck_base_dir)) {
|
||||
ret = unzGoToNextFile(zip_file);
|
||||
continue;
|
||||
}
|
||||
|
||||
String file_path_relative = file_name.trim_prefix(pck_base_dir).simplify_path();
|
||||
if (file_path_relative.is_empty()) {
|
||||
ret = unzGoToNextFile(zip_file);
|
||||
continue;
|
||||
}
|
||||
|
||||
String file_output_path = temp_dir_path.path_join(file_path_relative);
|
||||
err = DirAccess::make_dir_recursive_absolute(file_output_path.get_base_dir());
|
||||
if (err != OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (unzOpenCurrentFile(zip_file) != UNZ_OK) {
|
||||
err = ERR_FILE_CANT_OPEN;
|
||||
break;
|
||||
}
|
||||
|
||||
LocalVector<uint8_t> uncomp_data;
|
||||
uncomp_data.resize(zip_file_info.uncompressed_size);
|
||||
int read_bytes = unzReadCurrentFile(zip_file, uncomp_data.ptr(), uncomp_data.size());
|
||||
unzCloseCurrentFile(zip_file);
|
||||
|
||||
if (read_bytes < 0 || read_bytes != (int)uncomp_data.size()) {
|
||||
err = ERR_FILE_CANT_READ;
|
||||
break;
|
||||
}
|
||||
|
||||
Ref<FileAccess> temp_file = FileAccess::open(file_output_path, FileAccess::WRITE, &err);
|
||||
if (err != OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!temp_file->store_buffer(uncomp_data.ptr(), uncomp_data.size())) {
|
||||
err = ERR_FILE_CANT_WRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = unzGoToNextFile(zip_file);
|
||||
}
|
||||
|
||||
unzClose(zip_file);
|
||||
|
||||
r_pck_path = temp_dir_path.path_join(pck_name);
|
||||
r_temp_dir = temp_dir_path;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
Error EditorExportPlatform::_load_patches(const Ref<EditorExportPreset> &p_preset, const Vector<String> &p_patches) {
|
||||
if (!p_patches.is_empty()) {
|
||||
for (const String &path : p_patches) {
|
||||
err = PackedData::get_singleton()->add_pack(path, true, 0);
|
||||
String pck_path = path;
|
||||
|
||||
if (path.ends_with(".apk") || path.ends_with(".aab")) {
|
||||
String temp_dir;
|
||||
Error err = _extract_android_assets(path, pck_path, temp_dir);
|
||||
if (err != OK) {
|
||||
_unload_patches();
|
||||
add_message(EXPORT_MESSAGE_ERROR, TTR("Patch Creation"), vformat(TTR("Could not extract assets from Android bundle \"%s\", due to error \"%s\"."), path, error_names[err]));
|
||||
return err;
|
||||
}
|
||||
|
||||
patch_temp_dirs.push_back(temp_dir);
|
||||
}
|
||||
|
||||
Error err = PackedData::get_singleton()->add_pack(pck_path, true, 0, _get_script_encryption_key_bytes(p_preset));
|
||||
if (err != OK) {
|
||||
add_message(EXPORT_MESSAGE_ERROR, TTR("Patch Creation"), vformat(TTR("Could not load patch pack with path \"%s\"."), path));
|
||||
_unload_patches();
|
||||
add_message(EXPORT_MESSAGE_ERROR, TTR("Patch Creation"), vformat(TTR("Could not load patch pack with path \"%s\"."), pck_path));
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
return err;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void EditorExportPlatform::_unload_patches() {
|
||||
PackedData::get_singleton()->clear();
|
||||
|
||||
for (const String &temp_dir : patch_temp_dirs) {
|
||||
Ref<DirAccess> temp_dir_da = DirAccess::open(temp_dir);
|
||||
if (temp_dir_da.is_valid()) {
|
||||
temp_dir_da->erase_contents_recursive();
|
||||
temp_dir_da->remove(temp_dir);
|
||||
}
|
||||
}
|
||||
|
||||
patch_temp_dirs.clear();
|
||||
}
|
||||
|
||||
Error EditorExportPlatform::_encrypt_and_store_data(Ref<FileAccess> p_fd, const String &p_path, const Vector<uint8_t> &p_data, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed, bool &r_encrypt) {
|
||||
|
|
@ -347,7 +479,7 @@ Error EditorExportPlatform::_save_pack_file(const Ref<EditorExportPreset> &p_pre
|
|||
}
|
||||
|
||||
Error EditorExportPlatform::_save_pack_patch_file(const Ref<EditorExportPreset> &p_preset, void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed, bool p_delta) {
|
||||
Ref<FileAccess> old_file = PackedData::get_singleton()->try_open_path(p_path);
|
||||
Ref<FileAccess> old_file = PackedData::get_singleton()->try_open_path(p_path, _get_script_encryption_key_bytes(p_preset));
|
||||
if (old_file.is_null()) {
|
||||
return _save_pack_file(p_preset, p_userdata, p_path, p_data, p_file, p_total, p_enc_in_filters, p_enc_ex_filters, p_key, p_seed, false);
|
||||
}
|
||||
|
|
@ -993,7 +1125,7 @@ String EditorExportPlatform::_export_customize(const String &p_path, LocalVector
|
|||
return save_path.is_empty() ? p_path : save_path;
|
||||
}
|
||||
|
||||
String EditorExportPlatform::_get_script_encryption_key(const Ref<EditorExportPreset> &p_preset) const {
|
||||
String EditorExportPlatform::_get_script_encryption_key(const Ref<EditorExportPreset> &p_preset) {
|
||||
const String from_env = OS::get_singleton()->get_environment(ENV_SCRIPT_ENCRYPTION_KEY);
|
||||
if (!from_env.is_empty()) {
|
||||
return from_env.to_lower();
|
||||
|
|
@ -1001,6 +1133,39 @@ String EditorExportPlatform::_get_script_encryption_key(const Ref<EditorExportPr
|
|||
return p_preset->get_script_encryption_key().to_lower();
|
||||
}
|
||||
|
||||
Vector<uint8_t> EditorExportPlatform::_get_script_encryption_key_bytes(const Ref<EditorExportPreset> &p_preset) {
|
||||
Vector<uint8_t> key;
|
||||
String script_key = _get_script_encryption_key(p_preset);
|
||||
if (script_key.length() == 64) {
|
||||
key.resize(32);
|
||||
for (int i = 0; i < 32; i++) {
|
||||
int v = 0;
|
||||
if (i * 2 < script_key.length()) {
|
||||
char32_t ct = script_key[i * 2];
|
||||
if (is_digit(ct)) {
|
||||
ct = ct - '0';
|
||||
} else if (ct >= 'a' && ct <= 'f') {
|
||||
ct = 10 + ct - 'a';
|
||||
}
|
||||
v |= ct << 4;
|
||||
}
|
||||
|
||||
if (i * 2 + 1 < script_key.length()) {
|
||||
char32_t ct = script_key[i * 2 + 1];
|
||||
if (is_digit(ct)) {
|
||||
ct = ct - '0';
|
||||
} else if (ct >= 'a' && ct <= 'f') {
|
||||
ct = 10 + ct - 'a';
|
||||
}
|
||||
v |= ct;
|
||||
}
|
||||
key.write[i] = v;
|
||||
}
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
Dictionary EditorExportPlatform::get_internal_export_files(const Ref<EditorExportPreset> &p_preset, bool p_debug) {
|
||||
Dictionary files;
|
||||
|
||||
|
|
@ -1229,33 +1394,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
|
|||
}
|
||||
|
||||
// Get encryption key.
|
||||
String script_key = _get_script_encryption_key(p_preset);
|
||||
key.resize(32);
|
||||
if (script_key.length() == 64) {
|
||||
for (int i = 0; i < 32; i++) {
|
||||
int v = 0;
|
||||
if (i * 2 < script_key.length()) {
|
||||
char32_t ct = script_key[i * 2];
|
||||
if (is_digit(ct)) {
|
||||
ct = ct - '0';
|
||||
} else if (ct >= 'a' && ct <= 'f') {
|
||||
ct = 10 + ct - 'a';
|
||||
}
|
||||
v |= ct << 4;
|
||||
}
|
||||
|
||||
if (i * 2 + 1 < script_key.length()) {
|
||||
char32_t ct = script_key[i * 2 + 1];
|
||||
if (is_digit(ct)) {
|
||||
ct = ct - '0';
|
||||
} else if (ct >= 'a' && ct <= 'f') {
|
||||
ct = 10 + ct - 'a';
|
||||
}
|
||||
v |= ct;
|
||||
}
|
||||
key.write[i] = v;
|
||||
}
|
||||
}
|
||||
key = _get_script_encryption_key_bytes(p_preset);
|
||||
}
|
||||
|
||||
EditorExportSaveProxy save_proxy(p_save_func, p_remove_func != nullptr);
|
||||
|
|
@ -2168,33 +2307,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
|
|||
|
||||
Vector<uint8_t> key;
|
||||
if (p_preset->get_enc_pck() && p_preset->get_enc_directory()) {
|
||||
String script_key = _get_script_encryption_key(p_preset);
|
||||
key.resize(32);
|
||||
if (script_key.length() == 64) {
|
||||
for (int i = 0; i < 32; i++) {
|
||||
int v = 0;
|
||||
if (i * 2 < script_key.length()) {
|
||||
char32_t ct = script_key[i * 2];
|
||||
if (is_digit(ct)) {
|
||||
ct = ct - '0';
|
||||
} else if (ct >= 'a' && ct <= 'f') {
|
||||
ct = 10 + ct - 'a';
|
||||
}
|
||||
v |= ct << 4;
|
||||
}
|
||||
|
||||
if (i * 2 + 1 < script_key.length()) {
|
||||
char32_t ct = script_key[i * 2 + 1];
|
||||
if (is_digit(ct)) {
|
||||
ct = ct - '0';
|
||||
} else if (ct >= 'a' && ct <= 'f') {
|
||||
ct = 10 + ct - 'a';
|
||||
}
|
||||
v |= ct;
|
||||
}
|
||||
key.write[i] = v;
|
||||
}
|
||||
}
|
||||
key = _get_script_encryption_key_bytes(p_preset);
|
||||
}
|
||||
|
||||
if (!_encrypt_and_store_directory(f, pd, key, p_preset->get_seed(), file_base)) {
|
||||
|
|
@ -2288,7 +2401,7 @@ Error EditorExportPlatform::export_zip(const Ref<EditorExportPreset> &p_preset,
|
|||
|
||||
Error EditorExportPlatform::export_pack_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, const Vector<String> &p_patches, BitField<EditorExportPlatform::DebugFlags> p_flags) {
|
||||
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
|
||||
Error err = _load_patches(p_patches.is_empty() ? p_preset->get_patches() : p_patches);
|
||||
Error err = _load_patches(p_preset, p_patches.is_empty() ? p_preset->get_patches() : p_patches);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
|
|
@ -2299,7 +2412,7 @@ Error EditorExportPlatform::export_pack_patch(const Ref<EditorExportPreset> &p_p
|
|||
|
||||
Error EditorExportPlatform::export_zip_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, const Vector<String> &p_patches, BitField<EditorExportPlatform::DebugFlags> p_flags) {
|
||||
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
|
||||
Error err = _load_patches(p_patches.is_empty() ? p_preset->get_patches() : p_patches);
|
||||
Error err = _load_patches(p_preset, p_patches.is_empty() ? p_preset->get_patches() : p_patches);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,8 @@ public:
|
|||
static bool _store_header(Ref<FileAccess> p_fd, bool p_enc, bool p_sparse, uint64_t &r_file_base_ofs, uint64_t &r_dir_base_ofs, const String &p_salt);
|
||||
static bool _encrypt_and_store_directory(Ref<FileAccess> p_fd, PackData &p_pack_data, const Vector<uint8_t> &p_key, uint64_t p_seed, uint64_t p_file_base);
|
||||
static Error _encrypt_and_store_data(Ref<FileAccess> p_fd, const String &p_path, const Vector<uint8_t> &p_data, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed, bool &r_encrypt);
|
||||
String _get_script_encryption_key(const Ref<EditorExportPreset> &p_preset) const;
|
||||
static String _get_script_encryption_key(const Ref<EditorExportPreset> &p_preset);
|
||||
static Vector<uint8_t> _get_script_encryption_key_bytes(const Ref<EditorExportPreset> &p_preset);
|
||||
|
||||
private:
|
||||
struct ZipData {
|
||||
|
|
@ -116,6 +117,7 @@ private:
|
|||
};
|
||||
|
||||
Vector<ExportMessage> messages;
|
||||
Vector<String> patch_temp_dirs;
|
||||
|
||||
void _export_find_resources(EditorFileSystemDirectory *p_dir, HashSet<String> &p_paths);
|
||||
void _export_find_customized_resources(const Ref<EditorExportPreset> &p_preset, EditorFileSystemDirectory *p_dir, EditorExportPreset::FileExportMode p_mode, HashSet<String> &p_paths);
|
||||
|
|
@ -205,7 +207,8 @@ protected:
|
|||
Error ssh_run_on_remote_no_wait(const String &p_host, const String &p_port, const Vector<String> &p_ssh_args, const String &p_cmd_args, OS::ProcessID *r_pid = nullptr, int p_port_fwd = -1) const;
|
||||
Error ssh_push_to_remote(const String &p_host, const String &p_port, const Vector<String> &p_scp_args, const String &p_src_file, const String &p_dst_file) const;
|
||||
|
||||
Error _load_patches(const Vector<String> &p_patches);
|
||||
Error _extract_android_assets(const String &p_bundle_path, String &r_pck_path, String &r_temp_dir);
|
||||
Error _load_patches(const Ref<EditorExportPreset> &p_preset, const Vector<String> &p_patches);
|
||||
void _unload_patches();
|
||||
|
||||
Ref<Image> _load_icon_or_splash_image(const String &p_path, Error *r_error) const;
|
||||
|
|
|
|||
|
|
@ -310,7 +310,7 @@ Error EditorExportPlatformExtension::export_zip(const Ref<EditorExportPreset> &p
|
|||
Error EditorExportPlatformExtension::export_pack_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, const Vector<String> &p_patches, BitField<EditorExportPlatform::DebugFlags> p_flags) {
|
||||
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
|
||||
|
||||
Error err = _load_patches(p_patches.is_empty() ? p_preset->get_patches() : p_patches);
|
||||
Error err = _load_patches(p_preset, p_patches.is_empty() ? p_preset->get_patches() : p_patches);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
|
|
@ -329,7 +329,7 @@ Error EditorExportPlatformExtension::export_pack_patch(const Ref<EditorExportPre
|
|||
Error EditorExportPlatformExtension::export_zip_patch(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, const Vector<String> &p_patches, BitField<EditorExportPlatform::DebugFlags> p_flags) {
|
||||
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
|
||||
|
||||
Error err = _load_patches(p_patches.is_empty() ? p_preset->get_patches() : p_patches);
|
||||
Error err = _load_patches(p_preset, p_patches.is_empty() ? p_preset->get_patches() : p_patches);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1795,6 +1795,8 @@ ProjectExportDialog::ProjectExportDialog() {
|
|||
|
||||
patch_dialog = memnew(EditorFileDialog);
|
||||
patch_dialog->add_filter("*.pck", TTR("Godot Project Pack"));
|
||||
patch_dialog->add_filter("*.aab", TTR("Android App Bundle"));
|
||||
patch_dialog->add_filter("*.apk", TTR("Android Package"));
|
||||
patch_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
|
||||
patch_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
|
||||
patch_dialog->connect("file_selected", callable_mp(this, &ProjectExportDialog::_patch_file_selected));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue