feat: godot-engine-source-4.3-stable

This commit is contained in:
Jan van der Weide 2025-01-17 16:36:38 +01:00
parent c59a7dcade
commit 7125d019b5
11149 changed files with 5070401 additions and 0 deletions

View file

@ -0,0 +1,5 @@
#!/usr/bin/env python
Import("env")
env.add_source_files(env.editor_sources, "*.cpp")

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,367 @@
/**************************************************************************/
/* codesign.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#ifndef CODESIGN_H
#define CODESIGN_H
// macOS code signature creation utility.
//
// Current implementation has the following limitation:
// - Only version 11.3.0 signatures are supported.
// - Only "framework" and "app" bundle types are supported.
// - Page hash array scattering is not supported.
// - Reading and writing binary property lists i snot supported (third-party frameworks with binary Info.plist will not work unless .plist is converted to text format).
// - Requirements code generator is not implemented (only hard-coded requirements for the ad-hoc signing is supported).
// - RFC5652/CMS blob generation is not implemented, supports ad-hoc signing only.
#include "core/crypto/crypto_core.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "core/io/plist.h"
#include "core/object/ref_counted.h"
#include "modules/modules_enabled.gen.h" // For regex.
#ifdef MODULE_REGEX_ENABLED
#include "modules/regex/regex.h"
#endif
#ifdef MODULE_REGEX_ENABLED
/*************************************************************************/
/* CodeSignCodeResources */
/*************************************************************************/
class CodeSignCodeResources {
public:
enum class CRMatch {
CR_MATCH_NO,
CR_MATCH_YES,
CR_MATCH_NESTED,
CR_MATCH_OPTIONAL,
};
private:
struct CRFile {
String name;
String hash;
String hash2;
bool optional;
bool nested;
String requirements;
};
struct CRRule {
String file_pattern;
String key;
int weight;
bool store;
CRRule() {
weight = 1;
store = true;
}
CRRule(const String &p_file_pattern, const String &p_key, int p_weight, bool p_store) {
file_pattern = p_file_pattern;
key = p_key;
weight = p_weight;
store = p_store;
}
};
Vector<CRRule> rules1;
Vector<CRRule> rules2;
Vector<CRFile> files1;
Vector<CRFile> files2;
String hash_sha1_base64(const String &p_path);
String hash_sha256_base64(const String &p_path);
public:
void add_rule1(const String &p_rule, const String &p_key = "", int p_weight = 0, bool p_store = true);
void add_rule2(const String &p_rule, const String &p_key = "", int p_weight = 0, bool p_store = true);
CRMatch match_rules1(const String &p_path) const;
CRMatch match_rules2(const String &p_path) const;
bool add_file1(const String &p_root, const String &p_path);
bool add_file2(const String &p_root, const String &p_path);
bool add_nested_file(const String &p_root, const String &p_path, const String &p_exepath);
bool add_folder_recursive(const String &p_root, const String &p_path = "", const String &p_main_exe_path = "");
bool save_to_file(const String &p_path);
};
/*************************************************************************/
/* CodeSignBlob */
/*************************************************************************/
class CodeSignBlob : public RefCounted {
public:
virtual PackedByteArray get_hash_sha1() const = 0;
virtual PackedByteArray get_hash_sha256() const = 0;
virtual int get_size() const = 0;
virtual uint32_t get_index_type() const = 0;
virtual void write_to_file(Ref<FileAccess> p_file) const = 0;
};
/*************************************************************************/
/* CodeSignRequirements */
/*************************************************************************/
// Note: Proper code generator is not implemented (any we probably won't ever need it), just a hardcoded bytecode for the limited set of cases.
class CodeSignRequirements : public CodeSignBlob {
PackedByteArray blob;
static inline size_t PAD(size_t s, size_t a) {
return (s % a == 0) ? 0 : (a - s % a);
}
_FORCE_INLINE_ void _parse_certificate_slot(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const;
_FORCE_INLINE_ void _parse_key(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const;
_FORCE_INLINE_ void _parse_oid_key(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const;
_FORCE_INLINE_ void _parse_hash_string(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const;
_FORCE_INLINE_ void _parse_value(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const;
_FORCE_INLINE_ void _parse_date(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const;
_FORCE_INLINE_ bool _parse_match(uint32_t &r_pos, String &r_out, uint32_t p_rq_size) const;
public:
CodeSignRequirements();
CodeSignRequirements(const PackedByteArray &p_data);
Vector<String> parse_requirements() const;
virtual PackedByteArray get_hash_sha1() const override;
virtual PackedByteArray get_hash_sha256() const override;
virtual int get_size() const override;
virtual uint32_t get_index_type() const override { return 0x00000002; };
virtual void write_to_file(Ref<FileAccess> p_file) const override;
};
/*************************************************************************/
/* CodeSignEntitlementsText */
/*************************************************************************/
// PList formatted entitlements.
class CodeSignEntitlementsText : public CodeSignBlob {
PackedByteArray blob;
public:
CodeSignEntitlementsText();
CodeSignEntitlementsText(const String &p_string);
virtual PackedByteArray get_hash_sha1() const override;
virtual PackedByteArray get_hash_sha256() const override;
virtual int get_size() const override;
virtual uint32_t get_index_type() const override { return 0x00000005; };
virtual void write_to_file(Ref<FileAccess> p_file) const override;
};
/*************************************************************************/
/* CodeSignEntitlementsBinary */
/*************************************************************************/
// ASN.1 serialized entitlements.
class CodeSignEntitlementsBinary : public CodeSignBlob {
PackedByteArray blob;
public:
CodeSignEntitlementsBinary();
CodeSignEntitlementsBinary(const String &p_string);
virtual PackedByteArray get_hash_sha1() const override;
virtual PackedByteArray get_hash_sha256() const override;
virtual int get_size() const override;
virtual uint32_t get_index_type() const override { return 0x00000007; };
virtual void write_to_file(Ref<FileAccess> p_file) const override;
};
/*************************************************************************/
/* CodeSignCodeDirectory */
/*************************************************************************/
// Code Directory, runtime options, code segment and special structure hashes.
class CodeSignCodeDirectory : public CodeSignBlob {
public:
enum Slot {
SLOT_INFO_PLIST = -1,
SLOT_REQUIREMENTS = -2,
SLOT_RESOURCES = -3,
SLOT_APP_SPECIFIC = -4, // Unused.
SLOT_ENTITLEMENTS = -5,
SLOT_RESERVER1 = -6, // Unused.
SLOT_DER_ENTITLEMENTS = -7,
};
enum CodeSignExecSegFlags {
EXECSEG_MAIN_BINARY = 0x1,
EXECSEG_ALLOW_UNSIGNED = 0x10,
EXECSEG_DEBUGGER = 0x20,
EXECSEG_JIT = 0x40,
EXECSEG_SKIP_LV = 0x80,
EXECSEG_CAN_LOAD_CDHASH = 0x100,
EXECSEG_CAN_EXEC_CDHASH = 0x200,
};
enum CodeSignatureFlags {
SIGNATURE_HOST = 0x0001,
SIGNATURE_ADHOC = 0x0002,
SIGNATURE_TASK_ALLOW = 0x0004,
SIGNATURE_INSTALLER = 0x0008,
SIGNATURE_FORCED_LV = 0x0010,
SIGNATURE_INVALID_ALLOWED = 0x0020,
SIGNATURE_FORCE_HARD = 0x0100,
SIGNATURE_FORCE_KILL = 0x0200,
SIGNATURE_FORCE_EXPIRATION = 0x0400,
SIGNATURE_RESTRICT = 0x0800,
SIGNATURE_ENFORCEMENT = 0x1000,
SIGNATURE_LIBRARY_VALIDATION = 0x2000,
SIGNATURE_ENTITLEMENTS_VALIDATED = 0x4000,
SIGNATURE_NVRAM_UNRESTRICTED = 0x8000,
SIGNATURE_RUNTIME = 0x10000,
SIGNATURE_LINKER_SIGNED = 0x20000,
};
private:
PackedByteArray blob;
struct CodeDirectoryHeader {
uint32_t version; // Using version 0x0020500.
uint32_t flags; // // Option flags.
uint32_t hash_offset; // Slot zero offset.
uint32_t ident_offset; // Identifier string offset.
uint32_t special_slots; // Nr. of slots with negative index.
uint32_t code_slots; // Nr. of slots with index >= 0, (code_limit / page_size).
uint32_t code_limit; // Everything before code signature load command offset.
uint8_t hash_size; // 20 (SHA-1) or 32 (SHA-256).
uint8_t hash_type; // 1 (SHA-1) or 2 (SHA-256).
uint8_t platform; // Not used.
uint8_t page_size; // Page size, power of two, 2^12 (4096).
uint32_t spare2; // Not used.
// Version 0x20100
uint32_t scatter_vector_offset; // Set to 0 and ignore.
// Version 0x20200
uint32_t team_offset; // Team id string offset.
// Version 0x20300
uint32_t spare3; // Not used.
uint64_t code_limit_64; // Set to 0 and ignore.
// Version 0x20400
uint64_t exec_seg_base; // Start of the signed code segmet.
uint64_t exec_seg_limit; // Code segment (__TEXT) vmsize.
uint64_t exec_seg_flags; // Executable segment flags.
// Version 0x20500
uint32_t runtime; // Runtime version.
uint32_t pre_encrypt_offset; // Set to 0 and ignore.
};
int32_t pages = 0;
int32_t remain = 0;
int32_t code_slots = 0;
int32_t special_slots = 0;
public:
CodeSignCodeDirectory();
CodeSignCodeDirectory(uint8_t p_hash_size, uint8_t p_hash_type, bool p_main, const CharString &p_id, const CharString &p_team_id, uint32_t p_page_size, uint64_t p_exe_limit, uint64_t p_code_limit);
int32_t get_page_count();
int32_t get_page_remainder();
bool set_hash_in_slot(const PackedByteArray &p_hash, int p_slot);
virtual PackedByteArray get_hash_sha1() const override;
virtual PackedByteArray get_hash_sha256() const override;
virtual int get_size() const override;
virtual uint32_t get_index_type() const override { return 0x00000000; };
virtual void write_to_file(Ref<FileAccess> p_file) const override;
};
/*************************************************************************/
/* CodeSignSignature */
/*************************************************************************/
class CodeSignSignature : public CodeSignBlob {
PackedByteArray blob;
public:
CodeSignSignature();
virtual PackedByteArray get_hash_sha1() const override;
virtual PackedByteArray get_hash_sha256() const override;
virtual int get_size() const override;
virtual uint32_t get_index_type() const override { return 0x00010000; };
virtual void write_to_file(Ref<FileAccess> p_file) const override;
};
/*************************************************************************/
/* CodeSignSuperBlob */
/*************************************************************************/
class CodeSignSuperBlob {
Vector<Ref<CodeSignBlob>> blobs;
public:
bool add_blob(const Ref<CodeSignBlob> &p_blob);
int get_size() const;
void write_to_file(Ref<FileAccess> p_file) const;
};
/*************************************************************************/
/* CodeSign */
/*************************************************************************/
class CodeSign {
static PackedByteArray file_hash_sha1(const String &p_path);
static PackedByteArray file_hash_sha256(const String &p_path);
static Error _codesign_file(bool p_use_hardened_runtime, bool p_force, const String &p_info, const String &p_exe_path, const String &p_bundle_path, const String &p_ent_path, bool p_ios_bundle, String &r_error_msg);
public:
static Error codesign(bool p_use_hardened_runtime, bool p_force, const String &p_path, const String &p_ent_path, String &r_error_msg);
};
#endif // MODULE_REGEX_ENABLED
#endif // CODESIGN_H

View file

@ -0,0 +1,434 @@
/**************************************************************************/
/* editor_export.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#include "editor_export.h"
#include "core/config/project_settings.h"
#include "core/io/config_file.h"
#include "editor/editor_settings.h"
EditorExport *EditorExport::singleton = nullptr;
void EditorExport::_save() {
Ref<ConfigFile> config;
Ref<ConfigFile> credentials;
config.instantiate();
credentials.instantiate();
for (int i = 0; i < export_presets.size(); i++) {
Ref<EditorExportPreset> preset = export_presets[i];
String section = "preset." + itos(i);
config->set_value(section, "name", preset->get_name());
config->set_value(section, "platform", preset->get_platform()->get_name());
config->set_value(section, "runnable", preset->is_runnable());
config->set_value(section, "advanced_options", preset->are_advanced_options_enabled());
config->set_value(section, "dedicated_server", preset->is_dedicated_server());
config->set_value(section, "custom_features", preset->get_custom_features());
bool save_files = false;
switch (preset->get_export_filter()) {
case EditorExportPreset::EXPORT_ALL_RESOURCES: {
config->set_value(section, "export_filter", "all_resources");
} break;
case EditorExportPreset::EXPORT_SELECTED_SCENES: {
config->set_value(section, "export_filter", "scenes");
save_files = true;
} break;
case EditorExportPreset::EXPORT_SELECTED_RESOURCES: {
config->set_value(section, "export_filter", "resources");
save_files = true;
} break;
case EditorExportPreset::EXCLUDE_SELECTED_RESOURCES: {
config->set_value(section, "export_filter", "exclude");
save_files = true;
} break;
case EditorExportPreset::EXPORT_CUSTOMIZED: {
config->set_value(section, "export_filter", "customized");
config->set_value(section, "customized_files", preset->get_customized_files());
save_files = false;
};
}
if (save_files) {
Vector<String> export_files = preset->get_files_to_export();
config->set_value(section, "export_files", export_files);
}
config->set_value(section, "include_filter", preset->get_include_filter());
config->set_value(section, "exclude_filter", preset->get_exclude_filter());
config->set_value(section, "export_path", preset->get_export_path());
config->set_value(section, "encryption_include_filters", preset->get_enc_in_filter());
config->set_value(section, "encryption_exclude_filters", preset->get_enc_ex_filter());
config->set_value(section, "encrypt_pck", preset->get_enc_pck());
config->set_value(section, "encrypt_directory", preset->get_enc_directory());
config->set_value(section, "script_export_mode", preset->get_script_export_mode());
credentials->set_value(section, "script_encryption_key", preset->get_script_encryption_key());
String option_section = "preset." + itos(i) + ".options";
for (const KeyValue<StringName, Variant> &E : preset->values) {
PropertyInfo *prop = preset->properties.getptr(E.key);
if (prop && prop->usage & PROPERTY_USAGE_SECRET) {
credentials->set_value(option_section, E.key, E.value);
} else {
config->set_value(option_section, E.key, E.value);
}
}
}
config->save("res://export_presets.cfg");
credentials->save("res://.godot/export_credentials.cfg");
}
void EditorExport::save_presets() {
if (block_save) {
return;
}
save_timer->start();
}
void EditorExport::emit_presets_runnable_changed() {
emit_signal(_export_presets_runnable_updated);
}
void EditorExport::_bind_methods() {
ADD_SIGNAL(MethodInfo(_export_presets_updated));
ADD_SIGNAL(MethodInfo(_export_presets_runnable_updated));
}
void EditorExport::add_export_platform(const Ref<EditorExportPlatform> &p_platform) {
export_platforms.push_back(p_platform);
should_update_presets = true;
}
int EditorExport::get_export_platform_count() {
return export_platforms.size();
}
Ref<EditorExportPlatform> EditorExport::get_export_platform(int p_idx) {
ERR_FAIL_INDEX_V(p_idx, export_platforms.size(), Ref<EditorExportPlatform>());
return export_platforms[p_idx];
}
void EditorExport::add_export_preset(const Ref<EditorExportPreset> &p_preset, int p_at_pos) {
if (p_at_pos < 0) {
export_presets.push_back(p_preset);
} else {
export_presets.insert(p_at_pos, p_preset);
}
emit_presets_runnable_changed();
}
int EditorExport::get_export_preset_count() const {
return export_presets.size();
}
Ref<EditorExportPreset> EditorExport::get_export_preset(int p_idx) {
ERR_FAIL_INDEX_V(p_idx, export_presets.size(), Ref<EditorExportPreset>());
return export_presets[p_idx];
}
void EditorExport::remove_export_preset(int p_idx) {
export_presets.remove_at(p_idx);
save_presets();
emit_presets_runnable_changed();
}
void EditorExport::add_export_plugin(const Ref<EditorExportPlugin> &p_plugin) {
if (!export_plugins.has(p_plugin)) {
export_plugins.push_back(p_plugin);
should_update_presets = true;
}
}
void EditorExport::remove_export_plugin(const Ref<EditorExportPlugin> &p_plugin) {
export_plugins.erase(p_plugin);
should_update_presets = true;
}
Vector<Ref<EditorExportPlugin>> EditorExport::get_export_plugins() {
return export_plugins;
}
void EditorExport::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
load_config();
} break;
case NOTIFICATION_PROCESS: {
update_export_presets();
} break;
case NOTIFICATION_EXIT_TREE: {
for (int i = 0; i < export_platforms.size(); i++) {
export_platforms.write[i]->cleanup();
}
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
for (int i = 0; i < export_platforms.size(); i++) {
export_platforms.write[i]->notification(p_what);
}
} break;
}
}
void EditorExport::load_config() {
Ref<ConfigFile> config;
config.instantiate();
Error err = config->load("res://export_presets.cfg");
if (err != OK) {
return;
}
Ref<ConfigFile> credentials;
credentials.instantiate();
err = credentials->load("res://.godot/export_credentials.cfg");
if (!(err == OK || err == ERR_FILE_NOT_FOUND)) {
return;
}
block_save = true;
int index = 0;
while (true) {
String section = "preset." + itos(index);
if (!config->has_section(section)) {
break;
}
String platform = config->get_value(section, "platform");
#ifndef DISABLE_DEPRECATED
// Compatibility with Linux platform before 4.3.
if (platform == "Linux/X11") {
platform = "Linux";
}
#endif
Ref<EditorExportPreset> preset;
for (int i = 0; i < export_platforms.size(); i++) {
if (export_platforms[i]->get_name() == platform) {
preset = export_platforms.write[i]->create_preset();
break;
}
}
if (!preset.is_valid()) {
index++;
ERR_CONTINUE(!preset.is_valid());
}
preset->set_name(config->get_value(section, "name"));
preset->set_advanced_options_enabled(config->get_value(section, "advanced_options", false));
preset->set_runnable(config->get_value(section, "runnable"));
preset->set_dedicated_server(config->get_value(section, "dedicated_server", false));
if (config->has_section_key(section, "custom_features")) {
preset->set_custom_features(config->get_value(section, "custom_features"));
}
String export_filter = config->get_value(section, "export_filter");
bool get_files = false;
if (export_filter == "all_resources") {
preset->set_export_filter(EditorExportPreset::EXPORT_ALL_RESOURCES);
} else if (export_filter == "scenes") {
preset->set_export_filter(EditorExportPreset::EXPORT_SELECTED_SCENES);
get_files = true;
} else if (export_filter == "resources") {
preset->set_export_filter(EditorExportPreset::EXPORT_SELECTED_RESOURCES);
get_files = true;
} else if (export_filter == "exclude") {
preset->set_export_filter(EditorExportPreset::EXCLUDE_SELECTED_RESOURCES);
get_files = true;
} else if (export_filter == "customized") {
preset->set_export_filter(EditorExportPreset::EXPORT_CUSTOMIZED);
preset->set_customized_files(config->get_value(section, "customized_files", Dictionary()));
get_files = false;
}
if (get_files) {
Vector<String> files = config->get_value(section, "export_files");
for (int i = 0; i < files.size(); i++) {
if (!FileAccess::exists(files[i])) {
preset->remove_export_file(files[i]);
} else {
preset->add_export_file(files[i]);
}
}
}
preset->set_include_filter(config->get_value(section, "include_filter"));
preset->set_exclude_filter(config->get_value(section, "exclude_filter"));
preset->set_export_path(config->get_value(section, "export_path", ""));
preset->set_script_export_mode(config->get_value(section, "script_export_mode", EditorExportPreset::MODE_SCRIPT_BINARY_TOKENS_COMPRESSED));
if (config->has_section_key(section, "encrypt_pck")) {
preset->set_enc_pck(config->get_value(section, "encrypt_pck"));
}
if (config->has_section_key(section, "encrypt_directory")) {
preset->set_enc_directory(config->get_value(section, "encrypt_directory"));
}
if (config->has_section_key(section, "encryption_include_filters")) {
preset->set_enc_in_filter(config->get_value(section, "encryption_include_filters"));
}
if (config->has_section_key(section, "encryption_exclude_filters")) {
preset->set_enc_ex_filter(config->get_value(section, "encryption_exclude_filters"));
}
if (credentials->has_section_key(section, "script_encryption_key")) {
preset->set_script_encryption_key(credentials->get_value(section, "script_encryption_key"));
}
String option_section = "preset." + itos(index) + ".options";
List<String> options;
config->get_section_keys(option_section, &options);
for (const String &E : options) {
Variant value = config->get_value(option_section, E);
preset->set(E, value);
}
if (credentials->has_section(option_section)) {
options.clear();
credentials->get_section_keys(option_section, &options);
for (const String &E : options) {
// Drop values for secret properties that no longer exist, or during the next save they would end up in the regular config file.
if (preset->get_properties().has(E)) {
Variant value = credentials->get_value(option_section, E);
preset->set(E, value);
}
}
}
add_export_preset(preset);
index++;
}
block_save = false;
}
void EditorExport::update_export_presets() {
HashMap<StringName, List<EditorExportPlatform::ExportOption>> platform_options;
for (int i = 0; i < export_platforms.size(); i++) {
Ref<EditorExportPlatform> platform = export_platforms[i];
bool should_update = should_update_presets;
should_update |= platform->should_update_export_options();
for (int j = 0; j < export_plugins.size(); j++) {
should_update |= export_plugins.write[j]->_should_update_export_options(platform);
}
if (should_update) {
List<EditorExportPlatform::ExportOption> options;
platform->get_export_options(&options);
for (int j = 0; j < export_plugins.size(); j++) {
export_plugins[j]->_get_export_options(platform, &options);
}
platform_options[platform->get_name()] = options;
}
}
should_update_presets = false;
bool export_presets_updated = false;
for (int i = 0; i < export_presets.size(); i++) {
Ref<EditorExportPreset> preset = export_presets[i];
if (platform_options.has(preset->get_platform()->get_name())) {
export_presets_updated = true;
bool update_value_overrides = false;
List<EditorExportPlatform::ExportOption> options = platform_options[preset->get_platform()->get_name()];
// Clear the preset properties prior to reloading, keep the values to preserve options from plugins that may be currently disabled.
preset->properties.clear();
preset->update_visibility.clear();
for (const EditorExportPlatform::ExportOption &E : options) {
StringName option_name = E.option.name;
preset->properties[option_name] = E.option;
if (!preset->has(option_name)) {
preset->values[option_name] = E.default_value;
}
preset->update_visibility[option_name] = E.update_visibility;
if (E.update_visibility) {
update_value_overrides = true;
}
}
if (update_value_overrides) {
preset->update_value_overrides();
}
}
}
if (export_presets_updated) {
emit_signal(_export_presets_updated);
}
}
bool EditorExport::poll_export_platforms() {
bool changed = false;
for (int i = 0; i < export_platforms.size(); i++) {
if (export_platforms.write[i]->poll_export()) {
changed = true;
}
}
return changed;
}
void EditorExport::connect_presets_runnable_updated(const Callable &p_target) {
connect(_export_presets_runnable_updated, p_target);
}
EditorExport::EditorExport() {
save_timer = memnew(Timer);
add_child(save_timer);
save_timer->set_wait_time(0.8);
save_timer->set_one_shot(true);
save_timer->connect("timeout", callable_mp(this, &EditorExport::_save));
_export_presets_updated = StringName("export_presets_updated", true);
_export_presets_runnable_updated = StringName("export_presets_runnable_updated", true);
singleton = this;
set_process(true);
}
EditorExport::~EditorExport() {
}

View file

@ -0,0 +1,88 @@
/**************************************************************************/
/* editor_export.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#ifndef EDITOR_EXPORT_H
#define EDITOR_EXPORT_H
#include "editor_export_platform.h"
#include "editor_export_plugin.h"
class EditorExport : public Node {
GDCLASS(EditorExport, Node);
Vector<Ref<EditorExportPlatform>> export_platforms;
Vector<Ref<EditorExportPreset>> export_presets;
Vector<Ref<EditorExportPlugin>> export_plugins;
static inline StringName _export_presets_updated;
static inline StringName _export_presets_runnable_updated;
Timer *save_timer = nullptr;
bool block_save = false;
bool should_update_presets = false;
static EditorExport *singleton;
void _save();
protected:
friend class EditorExportPreset;
void save_presets();
void emit_presets_runnable_changed();
void _notification(int p_what);
static void _bind_methods();
public:
static EditorExport *get_singleton() { return singleton; }
void add_export_platform(const Ref<EditorExportPlatform> &p_platform);
int get_export_platform_count();
Ref<EditorExportPlatform> get_export_platform(int p_idx);
void add_export_preset(const Ref<EditorExportPreset> &p_preset, int p_at_pos = -1);
int get_export_preset_count() const;
Ref<EditorExportPreset> get_export_preset(int p_idx);
void remove_export_preset(int p_idx);
void add_export_plugin(const Ref<EditorExportPlugin> &p_plugin);
void remove_export_plugin(const Ref<EditorExportPlugin> &p_plugin);
Vector<Ref<EditorExportPlugin>> get_export_plugins();
void load_config();
void update_export_presets();
bool poll_export_platforms();
void connect_presets_runnable_updated(const Callable &p_target);
EditorExport();
~EditorExport();
};
#endif // EDITOR_EXPORT_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,259 @@
/**************************************************************************/
/* editor_export_platform.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#ifndef EDITOR_EXPORT_PLATFORM_H
#define EDITOR_EXPORT_PLATFORM_H
class EditorFileSystemDirectory;
struct EditorProgress;
#include "core/io/dir_access.h"
#include "core/io/zip_io.h"
#include "core/os/shared_object.h"
#include "editor_export_preset.h"
#include "scene/gui/rich_text_label.h"
#include "scene/main/node.h"
#include "scene/resources/image_texture.h"
class EditorExportPlugin;
const String ENV_SCRIPT_ENCRYPTION_KEY = "GODOT_SCRIPT_ENCRYPTION_KEY";
class EditorExportPlatform : public RefCounted {
GDCLASS(EditorExportPlatform, RefCounted);
protected:
static void _bind_methods();
public:
typedef Error (*EditorExportSaveFunction)(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);
typedef Error (*EditorExportSaveSharedObject)(void *p_userdata, const SharedObject &p_so);
enum ExportMessageType {
EXPORT_MESSAGE_NONE,
EXPORT_MESSAGE_INFO,
EXPORT_MESSAGE_WARNING,
EXPORT_MESSAGE_ERROR,
};
struct ExportMessage {
ExportMessageType msg_type;
String category;
String text;
};
private:
struct SavedData {
uint64_t ofs = 0;
uint64_t size = 0;
bool encrypted = false;
Vector<uint8_t> md5;
CharString path_utf8;
bool operator<(const SavedData &p_data) const {
return path_utf8 < p_data.path_utf8;
}
};
struct PackData {
Ref<FileAccess> f;
Vector<SavedData> file_ofs;
EditorProgress *ep = nullptr;
Vector<SharedObject> *so_files = nullptr;
};
struct ZipData {
void *zip = nullptr;
EditorProgress *ep = nullptr;
};
Vector<ExportMessage> messages;
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);
void _export_find_dependencies(const String &p_path, HashSet<String> &p_paths);
static Error _save_pack_file(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);
static Error _save_zip_file(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);
void _edit_files_with_filter(Ref<DirAccess> &da, const Vector<String> &p_filters, HashSet<String> &r_list, bool exclude);
void _edit_filter_list(HashSet<String> &r_list, const String &p_filter, bool exclude);
static Error _add_shared_object(void *p_userdata, const SharedObject &p_so);
struct FileExportCache {
uint64_t source_modified_time = 0;
String source_md5;
String saved_path;
bool used = false;
};
bool _export_customize_dictionary(Dictionary &dict, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins);
bool _export_customize_array(Array &array, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins);
bool _export_customize_object(Object *p_object, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins);
bool _export_customize_scene_resources(Node *p_root, Node *p_node, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins);
bool _is_editable_ancestor(Node *p_root, Node *p_node);
String _export_customize(const String &p_path, LocalVector<Ref<EditorExportPlugin>> &customize_resources_plugins, LocalVector<Ref<EditorExportPlugin>> &customize_scenes_plugins, HashMap<String, FileExportCache> &export_cache, const String &export_base_path, bool p_force_save);
String _get_script_encryption_key(const Ref<EditorExportPreset> &p_preset) const;
protected:
struct ExportNotifier {
ExportNotifier(EditorExportPlatform &p_platform, const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags);
~ExportNotifier();
};
HashSet<String> get_features(const Ref<EditorExportPreset> &p_preset, bool p_debug) const;
bool exists_export_template(const String &template_file_name, String *err) const;
String find_export_template(const String &template_file_name, String *err = nullptr) const;
void gen_export_flags(Vector<String> &r_flags, int p_flags);
void gen_debug_flags(Vector<String> &r_flags, int p_flags);
virtual void zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name);
Error ssh_run_on_remote(const String &p_host, const String &p_port, const Vector<String> &p_ssh_args, const String &p_cmd_args, String *r_out = nullptr, int p_port_fwd = -1) const;
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;
public:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const = 0;
struct ExportOption {
PropertyInfo option;
Variant default_value;
bool update_visibility = false;
bool required = false;
ExportOption(const PropertyInfo &p_info, const Variant &p_default, bool p_update_visibility = false, bool p_required = false) :
option(p_info),
default_value(p_default),
update_visibility(p_update_visibility),
required(p_required) {
}
ExportOption() {}
};
virtual Ref<EditorExportPreset> create_preset();
virtual bool is_executable(const String &p_path) const { return false; }
virtual void clear_messages() { messages.clear(); }
virtual void add_message(ExportMessageType p_type, const String &p_category, const String &p_message) {
ExportMessage msg;
msg.category = p_category;
msg.text = p_message;
msg.msg_type = p_type;
messages.push_back(msg);
switch (p_type) {
case EXPORT_MESSAGE_INFO: {
print_line(vformat("%s: %s", msg.category, msg.text));
} break;
case EXPORT_MESSAGE_WARNING: {
WARN_PRINT(vformat("%s: %s", msg.category, msg.text));
} break;
case EXPORT_MESSAGE_ERROR: {
ERR_PRINT(vformat("%s: %s", msg.category, msg.text));
} break;
default:
break;
}
}
virtual int get_message_count() const {
return messages.size();
}
virtual ExportMessage get_message(int p_index) const {
ERR_FAIL_INDEX_V(p_index, messages.size(), ExportMessage());
return messages[p_index];
}
virtual ExportMessageType get_worst_message_type() const {
ExportMessageType worst_type = EXPORT_MESSAGE_NONE;
for (int i = 0; i < messages.size(); i++) {
worst_type = MAX(worst_type, messages[i].msg_type);
}
return worst_type;
}
static Vector<String> get_forced_export_files();
virtual bool fill_log_messages(RichTextLabel *p_log, Error p_err);
virtual void get_export_options(List<ExportOption> *r_options) const = 0;
virtual bool should_update_export_options() { return false; }
virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const { return true; }
virtual String get_export_option_warning(const EditorExportPreset *p_preset, const StringName &p_name) const { return String(); }
virtual String get_os_name() const = 0;
virtual String get_name() const = 0;
virtual Ref<Texture2D> get_logo() const = 0;
Error export_project_files(const Ref<EditorExportPreset> &p_preset, bool p_debug, EditorExportSaveFunction p_func, void *p_udata, EditorExportSaveSharedObject p_so_func = nullptr);
Error save_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files = nullptr, bool p_embed = false, int64_t *r_embedded_start = nullptr, int64_t *r_embedded_size = nullptr);
Error save_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path);
virtual bool poll_export() { return false; }
virtual int get_options_count() const { return 0; }
virtual String get_options_tooltip() const { return ""; }
virtual Ref<ImageTexture> get_option_icon(int p_index) const;
virtual String get_option_label(int p_device) const { return ""; }
virtual String get_option_tooltip(int p_device) const { return ""; }
virtual String get_device_architecture(int p_device) const { return ""; }
enum DebugFlags {
DEBUG_FLAG_DUMB_CLIENT = 1,
DEBUG_FLAG_REMOTE_DEBUG = 2,
DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST = 4,
DEBUG_FLAG_VIEW_COLLISIONS = 8,
DEBUG_FLAG_VIEW_NAVIGATION = 16,
};
virtual void cleanup() {}
virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) { return OK; }
virtual Ref<Texture2D> get_run_icon() const { return get_logo(); }
bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug = false) const;
virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug = false) const = 0;
virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const = 0;
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const = 0;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) = 0;
virtual Error export_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
virtual Error export_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0);
virtual void get_platform_features(List<String> *r_features) const = 0;
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, HashSet<String> &p_features) = 0;
virtual String get_debug_protocol() const { return "tcp://"; }
EditorExportPlatform();
};
#endif // EDITOR_EXPORT_PLATFORM_H

View file

@ -0,0 +1,268 @@
/**************************************************************************/
/* editor_export_platform_pc.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#include "editor_export_platform_pc.h"
#include "core/config/project_settings.h"
#include "scene/resources/image_texture.h"
void EditorExportPlatformPC::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const {
if (p_preset->get("texture_format/s3tc_bptc")) {
r_features->push_back("s3tc");
r_features->push_back("bptc");
}
if (p_preset->get("texture_format/etc2_astc")) {
r_features->push_back("etc2");
r_features->push_back("astc");
}
// PC platforms only have one architecture per export, since
// we export a single executable instead of a bundle.
r_features->push_back(p_preset->get("binary_format/architecture"));
}
void EditorExportPlatformPC::get_export_options(List<ExportOption> *r_options) const {
String ext_filter = (get_os_name() == "Windows") ? "*.exe" : "";
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, ext_filter), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, ext_filter), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "debug/export_console_wrapper", PROPERTY_HINT_ENUM, "No,Debug Only,Debug and Release"), 1));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "binary_format/embed_pck"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc_bptc"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2_astc"), false));
}
String EditorExportPlatformPC::get_name() const {
return name;
}
String EditorExportPlatformPC::get_os_name() const {
return os_name;
}
Ref<Texture2D> EditorExportPlatformPC::get_logo() const {
return logo;
}
bool EditorExportPlatformPC::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug) const {
String err;
bool valid = false;
// Look for export templates (first official, and if defined custom templates).
String arch = p_preset->get("binary_format/architecture");
bool dvalid = exists_export_template(get_template_file_name("debug", arch), &err);
bool rvalid = exists_export_template(get_template_file_name("release", arch), &err);
if (p_preset->get("custom_template/debug") != "") {
dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
if (!dvalid) {
err += TTR("Custom debug template not found.") + "\n";
}
}
if (p_preset->get("custom_template/release") != "") {
rvalid = FileAccess::exists(p_preset->get("custom_template/release"));
if (!rvalid) {
err += TTR("Custom release template not found.") + "\n";
}
}
valid = dvalid || rvalid;
r_missing_templates = !valid;
bool uses_s3tc_bptc = p_preset->get("texture_format/s3tc_bptc");
bool uses_etc2_astc = p_preset->get("texture_format/etc2_astc");
if (!uses_s3tc_bptc && !uses_etc2_astc) {
valid = false;
err += TTR("A texture format must be selected to export the project. Please select at least one texture format.");
}
if (!err.is_empty()) {
r_error = err;
}
return valid;
}
bool EditorExportPlatformPC::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
return true;
}
Error EditorExportPlatformPC::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
Error err = prepare_template(p_preset, p_debug, p_path, p_flags);
if (err == OK) {
err = modify_template(p_preset, p_debug, p_path, p_flags);
}
if (err == OK) {
err = export_project_data(p_preset, p_debug, p_path, p_flags);
}
return err;
}
Error EditorExportPlatformPC::prepare_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
if (!DirAccess::exists(p_path.get_base_dir())) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Template"), TTR("The given export path doesn't exist."));
return ERR_FILE_BAD_PATH;
}
String custom_debug = p_preset->get("custom_template/debug");
String custom_release = p_preset->get("custom_template/release");
String template_path = p_debug ? custom_debug : custom_release;
template_path = template_path.strip_edges();
if (template_path.is_empty()) {
template_path = find_export_template(get_template_file_name(p_debug ? "debug" : "release", p_preset->get("binary_format/architecture")));
}
if (!template_path.is_empty() && !FileAccess::exists(template_path)) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Template"), vformat(TTR("Template file not found: \"%s\"."), template_path));
return ERR_FILE_NOT_FOUND;
}
// Matching the extensions in platform/windows/console_wrapper_windows.cpp
static const char *const wrapper_extensions[] = {
".console.exe",
"_console.exe",
" console.exe",
"console.exe",
nullptr,
};
int con_wrapper_mode = p_preset->get("debug/export_console_wrapper");
bool copy_wrapper = (con_wrapper_mode == 1 && p_debug) || (con_wrapper_mode == 2);
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
da->make_dir_recursive(p_path.get_base_dir());
Error err = da->copy(template_path, p_path, get_chmod_flags());
if (err == OK && copy_wrapper) {
for (int i = 0; wrapper_extensions[i]; ++i) {
const String wrapper_path = template_path.get_basename() + wrapper_extensions[i];
if (FileAccess::exists(wrapper_path)) {
err = da->copy(wrapper_path, p_path.get_basename() + ".console.exe", get_chmod_flags());
break;
}
}
}
if (err != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Template"), TTR("Failed to copy export template."));
return err;
}
return err;
}
Error EditorExportPlatformPC::export_project_data(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
String pck_path;
if (p_preset->get("binary_format/embed_pck")) {
pck_path = p_path;
} else {
pck_path = p_path.get_basename() + ".pck";
}
Vector<SharedObject> so_files;
int64_t embedded_pos;
int64_t embedded_size;
Error err = save_pack(p_preset, p_debug, pck_path, &so_files, p_preset->get("binary_format/embed_pck"), &embedded_pos, &embedded_size);
if (err == OK && p_preset->get("binary_format/embed_pck")) {
if (embedded_size >= 0x100000000 && String(p_preset->get("binary_format/architecture")).contains("32")) {
add_message(EXPORT_MESSAGE_ERROR, TTR("PCK Embedding"), TTR("On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."));
return ERR_INVALID_PARAMETER;
}
err = fixup_embedded_pck(p_path, embedded_pos, embedded_size);
}
if (err == OK && !so_files.is_empty()) {
// If shared object files, copy them.
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
for (int i = 0; i < so_files.size() && err == OK; i++) {
String src_path = ProjectSettings::get_singleton()->globalize_path(so_files[i].path);
String target_path;
if (so_files[i].target.is_empty()) {
target_path = p_path.get_base_dir();
} else {
target_path = p_path.get_base_dir().path_join(so_files[i].target);
da->make_dir_recursive(target_path);
}
target_path = target_path.path_join(src_path.get_file());
if (da->dir_exists(src_path)) {
err = da->make_dir_recursive(target_path);
if (err == OK) {
err = da->copy_dir(src_path, target_path, -1, true);
}
} else {
err = da->copy(src_path, target_path);
if (err == OK) {
err = sign_shared_object(p_preset, p_debug, target_path);
}
}
}
}
return err;
}
Error EditorExportPlatformPC::sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) {
return OK;
}
void EditorExportPlatformPC::set_name(const String &p_name) {
name = p_name;
}
void EditorExportPlatformPC::set_os_name(const String &p_name) {
os_name = p_name;
}
void EditorExportPlatformPC::set_logo(const Ref<Texture2D> &p_logo) {
logo = p_logo;
}
void EditorExportPlatformPC::get_platform_features(List<String> *r_features) const {
r_features->push_back("pc"); // Identify PC platforms as such.
r_features->push_back(get_os_name().to_lower()); // OS name is a feature.
}
void EditorExportPlatformPC::resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, HashSet<String> &p_features) {
}
int EditorExportPlatformPC::get_chmod_flags() const {
return chmod_flags;
}
void EditorExportPlatformPC::set_chmod_flags(int p_flags) {
chmod_flags = p_flags;
}

View file

@ -0,0 +1,82 @@
/**************************************************************************/
/* editor_export_platform_pc.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#ifndef EDITOR_EXPORT_PLATFORM_PC_H
#define EDITOR_EXPORT_PLATFORM_PC_H
#include "editor_export_platform.h"
class EditorExportPlatformPC : public EditorExportPlatform {
GDCLASS(EditorExportPlatformPC, EditorExportPlatform);
private:
Ref<ImageTexture> logo;
String name;
String os_name;
int chmod_flags = -1;
public:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
virtual void get_export_options(List<ExportOption> *r_options) const override;
virtual String get_name() const override;
virtual String get_os_name() const override;
virtual Ref<Texture2D> get_logo() const override;
virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug = false) const override;
virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path);
virtual String get_template_file_name(const String &p_target, const String &p_arch) const = 0;
virtual Error prepare_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags);
virtual Error modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { return OK; };
virtual Error export_project_data(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags);
void set_name(const String &p_name);
void set_os_name(const String &p_name);
void set_logo(const Ref<Texture2D> &p_logo);
void add_platform_feature(const String &p_feature);
virtual void get_platform_features(List<String> *r_features) const override;
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, HashSet<String> &p_features) override;
int get_chmod_flags() const;
void set_chmod_flags(int p_flags);
virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) {
return Error::OK;
}
};
#endif // EDITOR_EXPORT_PLATFORM_PC_H

View file

@ -0,0 +1,360 @@
/**************************************************************************/
/* editor_export_plugin.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#include "editor_export_plugin.h"
#include "core/config/project_settings.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "editor/editor_paths.h"
#include "editor/editor_settings.h"
#include "editor/export/editor_export_platform.h"
#include "scene/resources/resource_format_text.h"
void EditorExportPlugin::set_export_preset(const Ref<EditorExportPreset> &p_preset) {
if (p_preset.is_valid()) {
export_preset = p_preset;
}
}
Ref<EditorExportPreset> EditorExportPlugin::get_export_preset() const {
return export_preset;
}
void EditorExportPlugin::add_file(const String &p_path, const Vector<uint8_t> &p_file, bool p_remap) {
ExtraFile ef;
ef.data = p_file;
ef.path = p_path;
ef.remap = p_remap;
extra_files.push_back(ef);
}
void EditorExportPlugin::add_shared_object(const String &p_path, const Vector<String> &p_tags, const String &p_target) {
shared_objects.push_back(SharedObject(p_path, p_tags, p_target));
}
void EditorExportPlugin::_add_shared_object(const SharedObject &p_shared_object) {
shared_objects.push_back(p_shared_object);
}
void EditorExportPlugin::add_ios_framework(const String &p_path) {
ios_frameworks.push_back(p_path);
}
void EditorExportPlugin::add_ios_embedded_framework(const String &p_path) {
ios_embedded_frameworks.push_back(p_path);
}
Vector<String> EditorExportPlugin::get_ios_frameworks() const {
return ios_frameworks;
}
Vector<String> EditorExportPlugin::get_ios_embedded_frameworks() const {
return ios_embedded_frameworks;
}
void EditorExportPlugin::add_ios_plist_content(const String &p_plist_content) {
ios_plist_content += p_plist_content + "\n";
}
String EditorExportPlugin::get_ios_plist_content() const {
return ios_plist_content;
}
void EditorExportPlugin::add_ios_linker_flags(const String &p_flags) {
if (ios_linker_flags.length() > 0) {
ios_linker_flags += ' ';
}
ios_linker_flags += p_flags;
}
String EditorExportPlugin::get_ios_linker_flags() const {
return ios_linker_flags;
}
void EditorExportPlugin::add_ios_bundle_file(const String &p_path) {
ios_bundle_files.push_back(p_path);
}
Vector<String> EditorExportPlugin::get_ios_bundle_files() const {
return ios_bundle_files;
}
void EditorExportPlugin::add_ios_cpp_code(const String &p_code) {
ios_cpp_code += p_code;
}
String EditorExportPlugin::get_ios_cpp_code() const {
return ios_cpp_code;
}
void EditorExportPlugin::add_macos_plugin_file(const String &p_path) {
macos_plugin_files.push_back(p_path);
}
const Vector<String> &EditorExportPlugin::get_macos_plugin_files() const {
return macos_plugin_files;
}
void EditorExportPlugin::add_ios_project_static_lib(const String &p_path) {
ios_project_static_libs.push_back(p_path);
}
Vector<String> EditorExportPlugin::get_ios_project_static_libs() const {
return ios_project_static_libs;
}
Variant EditorExportPlugin::get_option(const StringName &p_name) const {
ERR_FAIL_NULL_V(export_preset, Variant());
return export_preset->get(p_name);
}
String EditorExportPlugin::_has_valid_export_configuration(const Ref<EditorExportPlatform> &p_export_platform, const Ref<EditorExportPreset> &p_preset) {
String warning;
if (!supports_platform(p_export_platform)) {
warning += vformat(TTR("Plugin \"%s\" is not supported on \"%s\""), get_name(), p_export_platform->get_name());
warning += "\n";
return warning;
}
set_export_preset(p_preset);
List<EditorExportPlatform::ExportOption> options;
_get_export_options(p_export_platform, &options);
for (const EditorExportPlatform::ExportOption &E : options) {
String option_warning = _get_export_option_warning(p_export_platform, E.option.name);
if (!option_warning.is_empty()) {
warning += option_warning + "\n";
}
}
return warning;
}
void EditorExportPlugin::_export_file_script(const String &p_path, const String &p_type, const Vector<String> &p_features) {
GDVIRTUAL_CALL(_export_file, p_path, p_type, p_features);
}
void EditorExportPlugin::_export_begin_script(const Vector<String> &p_features, bool p_debug, const String &p_path, int p_flags) {
GDVIRTUAL_CALL(_export_begin, p_features, p_debug, p_path, p_flags);
}
void EditorExportPlugin::_export_end_script() {
GDVIRTUAL_CALL(_export_end);
}
// Customization
bool EditorExportPlugin::_begin_customize_resources(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) {
bool ret = false;
GDVIRTUAL_CALL(_begin_customize_resources, p_platform, p_features, ret);
return ret;
}
Ref<Resource> EditorExportPlugin::_customize_resource(const Ref<Resource> &p_resource, const String &p_path) {
Ref<Resource> ret;
GDVIRTUAL_REQUIRED_CALL(_customize_resource, p_resource, p_path, ret);
return ret;
}
bool EditorExportPlugin::_begin_customize_scenes(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) {
bool ret = false;
GDVIRTUAL_CALL(_begin_customize_scenes, p_platform, p_features, ret);
return ret;
}
Node *EditorExportPlugin::_customize_scene(Node *p_root, const String &p_path) {
Node *ret = nullptr;
GDVIRTUAL_REQUIRED_CALL(_customize_scene, p_root, p_path, ret);
return ret;
}
uint64_t EditorExportPlugin::_get_customization_configuration_hash() const {
uint64_t ret = 0;
GDVIRTUAL_REQUIRED_CALL(_get_customization_configuration_hash, ret);
return ret;
}
void EditorExportPlugin::_end_customize_scenes() {
GDVIRTUAL_CALL(_end_customize_scenes);
}
void EditorExportPlugin::_end_customize_resources() {
GDVIRTUAL_CALL(_end_customize_resources);
}
String EditorExportPlugin::get_name() const {
String ret;
GDVIRTUAL_REQUIRED_CALL(_get_name, ret);
return ret;
}
bool EditorExportPlugin::supports_platform(const Ref<EditorExportPlatform> &p_export_platform) const {
bool ret = false;
GDVIRTUAL_CALL(_supports_platform, p_export_platform, ret);
return ret;
}
PackedStringArray EditorExportPlugin::get_android_dependencies(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const {
PackedStringArray ret;
GDVIRTUAL_CALL(_get_android_dependencies, p_export_platform, p_debug, ret);
return ret;
}
PackedStringArray EditorExportPlugin::get_android_dependencies_maven_repos(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const {
PackedStringArray ret;
GDVIRTUAL_CALL(_get_android_dependencies_maven_repos, p_export_platform, p_debug, ret);
return ret;
}
PackedStringArray EditorExportPlugin::get_android_libraries(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const {
PackedStringArray ret;
GDVIRTUAL_CALL(_get_android_libraries, p_export_platform, p_debug, ret);
return ret;
}
String EditorExportPlugin::get_android_manifest_activity_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const {
String ret;
GDVIRTUAL_CALL(_get_android_manifest_activity_element_contents, p_export_platform, p_debug, ret);
return ret;
}
String EditorExportPlugin::get_android_manifest_application_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const {
String ret;
GDVIRTUAL_CALL(_get_android_manifest_application_element_contents, p_export_platform, p_debug, ret);
return ret;
}
String EditorExportPlugin::get_android_manifest_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const {
String ret;
GDVIRTUAL_CALL(_get_android_manifest_element_contents, p_export_platform, p_debug, ret);
return ret;
}
PackedStringArray EditorExportPlugin::_get_export_features(const Ref<EditorExportPlatform> &p_platform, bool p_debug) const {
PackedStringArray ret;
GDVIRTUAL_CALL(_get_export_features, p_platform, p_debug, ret);
return ret;
}
void EditorExportPlugin::_get_export_options(const Ref<EditorExportPlatform> &p_platform, List<EditorExportPlatform::ExportOption> *r_options) const {
TypedArray<Dictionary> ret;
GDVIRTUAL_CALL(_get_export_options, p_platform, ret);
for (int i = 0; i < ret.size(); i++) {
Dictionary option = ret[i];
ERR_CONTINUE_MSG(!option.has("option"), "Missing required element 'option'");
ERR_CONTINUE_MSG(!option.has("default_value"), "Missing required element 'default_value'");
PropertyInfo property_info = PropertyInfo::from_dict(option["option"]);
Variant default_value = option["default_value"];
bool update_visibility = option.has("update_visibility") && option["update_visibility"];
r_options->push_back(EditorExportPlatform::ExportOption(property_info, default_value, update_visibility));
}
}
bool EditorExportPlugin::_should_update_export_options(const Ref<EditorExportPlatform> &p_platform) const {
bool ret = false;
GDVIRTUAL_CALL(_should_update_export_options, p_platform, ret);
return ret;
}
String EditorExportPlugin::_get_export_option_warning(const Ref<EditorExportPlatform> &p_export_platform, const String &p_option_name) const {
String ret;
GDVIRTUAL_CALL(_get_export_option_warning, p_export_platform, p_option_name, ret);
return ret;
}
Dictionary EditorExportPlugin::_get_export_options_overrides(const Ref<EditorExportPlatform> &p_platform) const {
Dictionary ret;
GDVIRTUAL_CALL(_get_export_options_overrides, p_platform, ret);
return ret;
}
void EditorExportPlugin::_export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) {
}
void EditorExportPlugin::_export_begin(const HashSet<String> &p_features, bool p_debug, const String &p_path, int p_flags) {
}
void EditorExportPlugin::_export_end() {}
void EditorExportPlugin::skip() {
skipped = true;
}
void EditorExportPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_shared_object", "path", "tags", "target"), &EditorExportPlugin::add_shared_object);
ClassDB::bind_method(D_METHOD("add_ios_project_static_lib", "path"), &EditorExportPlugin::add_ios_project_static_lib);
ClassDB::bind_method(D_METHOD("add_file", "path", "file", "remap"), &EditorExportPlugin::add_file);
ClassDB::bind_method(D_METHOD("add_ios_framework", "path"), &EditorExportPlugin::add_ios_framework);
ClassDB::bind_method(D_METHOD("add_ios_embedded_framework", "path"), &EditorExportPlugin::add_ios_embedded_framework);
ClassDB::bind_method(D_METHOD("add_ios_plist_content", "plist_content"), &EditorExportPlugin::add_ios_plist_content);
ClassDB::bind_method(D_METHOD("add_ios_linker_flags", "flags"), &EditorExportPlugin::add_ios_linker_flags);
ClassDB::bind_method(D_METHOD("add_ios_bundle_file", "path"), &EditorExportPlugin::add_ios_bundle_file);
ClassDB::bind_method(D_METHOD("add_ios_cpp_code", "code"), &EditorExportPlugin::add_ios_cpp_code);
ClassDB::bind_method(D_METHOD("add_macos_plugin_file", "path"), &EditorExportPlugin::add_macos_plugin_file);
ClassDB::bind_method(D_METHOD("skip"), &EditorExportPlugin::skip);
ClassDB::bind_method(D_METHOD("get_option", "name"), &EditorExportPlugin::get_option);
GDVIRTUAL_BIND(_export_file, "path", "type", "features");
GDVIRTUAL_BIND(_export_begin, "features", "is_debug", "path", "flags");
GDVIRTUAL_BIND(_export_end);
GDVIRTUAL_BIND(_begin_customize_resources, "platform", "features");
GDVIRTUAL_BIND(_customize_resource, "resource", "path");
GDVIRTUAL_BIND(_begin_customize_scenes, "platform", "features");
GDVIRTUAL_BIND(_customize_scene, "scene", "path");
GDVIRTUAL_BIND(_get_customization_configuration_hash);
GDVIRTUAL_BIND(_end_customize_scenes);
GDVIRTUAL_BIND(_end_customize_resources);
GDVIRTUAL_BIND(_get_export_options, "platform");
GDVIRTUAL_BIND(_get_export_options_overrides, "platform");
GDVIRTUAL_BIND(_should_update_export_options, "platform");
GDVIRTUAL_BIND(_get_export_option_warning, "platform", "option");
GDVIRTUAL_BIND(_get_export_features, "platform", "debug");
GDVIRTUAL_BIND(_get_name);
GDVIRTUAL_BIND(_supports_platform, "platform");
GDVIRTUAL_BIND(_get_android_dependencies, "platform", "debug");
GDVIRTUAL_BIND(_get_android_dependencies_maven_repos, "platform", "debug");
GDVIRTUAL_BIND(_get_android_libraries, "platform", "debug");
GDVIRTUAL_BIND(_get_android_manifest_activity_element_contents, "platform", "debug");
GDVIRTUAL_BIND(_get_android_manifest_application_element_contents, "platform", "debug");
GDVIRTUAL_BIND(_get_android_manifest_element_contents, "platform", "debug");
}
EditorExportPlugin::EditorExportPlugin() {
EDITOR_DEF("export/ssh/ssh", "");
EDITOR_DEF("export/ssh/scp", "");
}

View file

@ -0,0 +1,189 @@
/**************************************************************************/
/* editor_export_plugin.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#ifndef EDITOR_EXPORT_PLUGIN_H
#define EDITOR_EXPORT_PLUGIN_H
#include "core/extension/gdextension.h"
#include "core/os/shared_object.h"
#include "editor_export_platform.h"
#include "editor_export_preset.h"
#include "scene/main/node.h"
class EditorExportPlugin : public RefCounted {
GDCLASS(EditorExportPlugin, RefCounted);
friend class EditorExport;
friend class EditorExportPlatform;
friend class EditorExportPreset;
Ref<EditorExportPreset> export_preset;
Vector<SharedObject> shared_objects;
struct ExtraFile {
String path;
Vector<uint8_t> data;
bool remap = false;
};
Vector<ExtraFile> extra_files;
bool skipped = false;
Vector<String> ios_frameworks;
Vector<String> ios_embedded_frameworks;
Vector<String> ios_project_static_libs;
String ios_plist_content;
String ios_linker_flags;
Vector<String> ios_bundle_files;
String ios_cpp_code;
Vector<String> macos_plugin_files;
_FORCE_INLINE_ void _clear() {
shared_objects.clear();
extra_files.clear();
skipped = false;
}
_FORCE_INLINE_ void _export_end_clear() {
ios_frameworks.clear();
ios_embedded_frameworks.clear();
ios_bundle_files.clear();
ios_plist_content = "";
ios_linker_flags = "";
ios_cpp_code = "";
macos_plugin_files.clear();
}
// Export
void _export_file_script(const String &p_path, const String &p_type, const Vector<String> &p_features);
void _export_begin_script(const Vector<String> &p_features, bool p_debug, const String &p_path, int p_flags);
void _export_end_script();
String _has_valid_export_configuration(const Ref<EditorExportPlatform> &p_export_platform, const Ref<EditorExportPreset> &p_preset);
protected:
void set_export_preset(const Ref<EditorExportPreset> &p_preset);
Ref<EditorExportPreset> get_export_preset() const;
void add_file(const String &p_path, const Vector<uint8_t> &p_file, bool p_remap);
void add_shared_object(const String &p_path, const Vector<String> &tags, const String &p_target = String());
void _add_shared_object(const SharedObject &p_shared_object);
void add_ios_framework(const String &p_path);
void add_ios_embedded_framework(const String &p_path);
void add_ios_project_static_lib(const String &p_path);
void add_ios_plist_content(const String &p_plist_content);
void add_ios_linker_flags(const String &p_flags);
void add_ios_bundle_file(const String &p_path);
void add_ios_cpp_code(const String &p_code);
void add_macos_plugin_file(const String &p_path);
void skip();
virtual void _export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features);
virtual void _export_begin(const HashSet<String> &p_features, bool p_debug, const String &p_path, int p_flags);
virtual void _export_end();
static void _bind_methods();
GDVIRTUAL3(_export_file, String, String, Vector<String>)
GDVIRTUAL4(_export_begin, Vector<String>, bool, String, uint32_t)
GDVIRTUAL0(_export_end)
GDVIRTUAL2RC(bool, _begin_customize_resources, const Ref<EditorExportPlatform> &, const Vector<String> &)
GDVIRTUAL2R(Ref<Resource>, _customize_resource, const Ref<Resource> &, String)
GDVIRTUAL2RC(bool, _begin_customize_scenes, const Ref<EditorExportPlatform> &, const Vector<String> &)
GDVIRTUAL2R(Node *, _customize_scene, Node *, String)
GDVIRTUAL0RC(uint64_t, _get_customization_configuration_hash)
GDVIRTUAL0(_end_customize_scenes)
GDVIRTUAL0(_end_customize_resources)
GDVIRTUAL2RC(PackedStringArray, _get_export_features, const Ref<EditorExportPlatform> &, bool);
GDVIRTUAL1RC(TypedArray<Dictionary>, _get_export_options, const Ref<EditorExportPlatform> &);
GDVIRTUAL1RC(Dictionary, _get_export_options_overrides, const Ref<EditorExportPlatform> &);
GDVIRTUAL1RC(bool, _should_update_export_options, const Ref<EditorExportPlatform> &);
GDVIRTUAL2RC(String, _get_export_option_warning, const Ref<EditorExportPlatform> &, String);
GDVIRTUAL0RC(String, _get_name)
GDVIRTUAL1RC(bool, _supports_platform, const Ref<EditorExportPlatform> &);
GDVIRTUAL2RC(PackedStringArray, _get_android_dependencies, const Ref<EditorExportPlatform> &, bool);
GDVIRTUAL2RC(PackedStringArray, _get_android_dependencies_maven_repos, const Ref<EditorExportPlatform> &, bool);
GDVIRTUAL2RC(PackedStringArray, _get_android_libraries, const Ref<EditorExportPlatform> &, bool);
GDVIRTUAL2RC(String, _get_android_manifest_activity_element_contents, const Ref<EditorExportPlatform> &, bool);
GDVIRTUAL2RC(String, _get_android_manifest_application_element_contents, const Ref<EditorExportPlatform> &, bool);
GDVIRTUAL2RC(String, _get_android_manifest_element_contents, const Ref<EditorExportPlatform> &, bool);
virtual bool _begin_customize_resources(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features); // Return true if this plugin does property export customization
virtual Ref<Resource> _customize_resource(const Ref<Resource> &p_resource, const String &p_path); // If nothing is returned, it means do not touch (nothing changed). If something is returned (either the same or a different resource) it means changes are made.
virtual bool _begin_customize_scenes(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features); // Return true if this plugin does property export customization
virtual Node *_customize_scene(Node *p_root, const String &p_path); // Return true if a change was made
virtual uint64_t _get_customization_configuration_hash() const; // Hash used for caching customized resources and scenes.
virtual void _end_customize_scenes();
virtual void _end_customize_resources();
virtual PackedStringArray _get_export_features(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const;
virtual void _get_export_options(const Ref<EditorExportPlatform> &p_export_platform, List<EditorExportPlatform::ExportOption> *r_options) const;
virtual Dictionary _get_export_options_overrides(const Ref<EditorExportPlatform> &p_export_platform) const;
virtual bool _should_update_export_options(const Ref<EditorExportPlatform> &p_export_platform) const;
virtual String _get_export_option_warning(const Ref<EditorExportPlatform> &p_export_platform, const String &p_option_name) const;
public:
virtual String get_name() const;
virtual bool supports_platform(const Ref<EditorExportPlatform> &p_export_platform) const;
virtual PackedStringArray get_android_dependencies(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const;
virtual PackedStringArray get_android_dependencies_maven_repos(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const;
virtual PackedStringArray get_android_libraries(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const;
virtual String get_android_manifest_activity_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const;
virtual String get_android_manifest_application_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const;
virtual String get_android_manifest_element_contents(const Ref<EditorExportPlatform> &p_export_platform, bool p_debug) const;
Vector<String> get_ios_frameworks() const;
Vector<String> get_ios_embedded_frameworks() const;
Vector<String> get_ios_project_static_libs() const;
String get_ios_plist_content() const;
String get_ios_linker_flags() const;
Vector<String> get_ios_bundle_files() const;
String get_ios_cpp_code() const;
const Vector<String> &get_macos_plugin_files() const;
Variant get_option(const StringName &p_name) const;
EditorExportPlugin();
};
#endif // EDITOR_EXPORT_PLUGIN_H

View file

@ -0,0 +1,456 @@
/**************************************************************************/
/* editor_export_preset.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#include "editor_export.h"
#include "core/config/project_settings.h"
bool EditorExportPreset::_set(const StringName &p_name, const Variant &p_value) {
values[p_name] = p_value;
EditorExport::singleton->save_presets();
if (update_visibility.has(p_name)) {
if (update_visibility[p_name]) {
update_value_overrides();
notify_property_list_changed();
}
return true;
}
return false;
}
bool EditorExportPreset::_get(const StringName &p_name, Variant &r_ret) const {
if (value_overrides.has(p_name)) {
r_ret = value_overrides[p_name];
return true;
}
if (values.has(p_name)) {
r_ret = values[p_name];
return true;
}
return false;
}
void EditorExportPreset::_bind_methods() {
ClassDB::bind_method(D_METHOD("_get_property_warning", "name"), &EditorExportPreset::_get_property_warning);
}
String EditorExportPreset::_get_property_warning(const StringName &p_name) const {
if (value_overrides.has(p_name)) {
return String();
}
String warning = platform->get_export_option_warning(this, p_name);
if (!warning.is_empty()) {
warning += "\n";
}
// Get property warning from editor export plugins.
Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
for (int i = 0; i < export_plugins.size(); i++) {
if (!export_plugins[i]->supports_platform(platform)) {
continue;
}
export_plugins.write[i]->set_export_preset(Ref<EditorExportPreset>(this));
String plugin_warning = export_plugins[i]->_get_export_option_warning(platform, p_name);
if (!plugin_warning.is_empty()) {
warning += plugin_warning + "\n";
}
}
return warning;
}
void EditorExportPreset::_get_property_list(List<PropertyInfo> *p_list) const {
for (const KeyValue<StringName, PropertyInfo> &E : properties) {
if (!value_overrides.has(E.key) && platform->get_export_option_visibility(this, E.key)) {
p_list->push_back(E.value);
}
}
}
Ref<EditorExportPlatform> EditorExportPreset::get_platform() const {
return platform;
}
void EditorExportPreset::update_files() {
{
Vector<String> to_remove;
for (const String &E : selected_files) {
if (!FileAccess::exists(E)) {
to_remove.push_back(E);
}
}
for (int i = 0; i < to_remove.size(); ++i) {
selected_files.erase(to_remove[i]);
}
}
{
Vector<String> to_remove;
for (const KeyValue<String, FileExportMode> &E : customized_files) {
if (!FileAccess::exists(E.key) && !DirAccess::exists(E.key)) {
to_remove.push_back(E.key);
}
}
for (int i = 0; i < to_remove.size(); ++i) {
customized_files.erase(to_remove[i]);
}
}
}
void EditorExportPreset::update_value_overrides() {
Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
HashMap<StringName, Variant> new_value_overrides;
value_overrides.clear();
for (int i = 0; i < export_plugins.size(); i++) {
if (!export_plugins[i]->supports_platform(platform)) {
continue;
}
export_plugins.write[i]->set_export_preset(Ref<EditorExportPreset>(this));
Dictionary plugin_overrides = export_plugins[i]->_get_export_options_overrides(platform);
if (!plugin_overrides.is_empty()) {
Array keys = plugin_overrides.keys();
for (int x = 0; x < keys.size(); x++) {
StringName key = keys[x];
Variant value = plugin_overrides[key];
if (new_value_overrides.has(key) && new_value_overrides[key] != value) {
WARN_PRINT_ED(vformat("Editor export plugin '%s' overrides pre-existing export option override '%s' with new value.", export_plugins[i]->get_name(), key));
}
new_value_overrides[key] = value;
}
}
}
value_overrides = new_value_overrides;
notify_property_list_changed();
}
Vector<String> EditorExportPreset::get_files_to_export() const {
Vector<String> files;
for (const String &E : selected_files) {
files.push_back(E);
}
return files;
}
Dictionary EditorExportPreset::get_customized_files() const {
Dictionary files;
for (const KeyValue<String, FileExportMode> &E : customized_files) {
String mode;
switch (E.value) {
case MODE_FILE_NOT_CUSTOMIZED: {
continue;
} break;
case MODE_FILE_STRIP: {
mode = "strip";
} break;
case MODE_FILE_KEEP: {
mode = "keep";
} break;
case MODE_FILE_REMOVE: {
mode = "remove";
}
}
files[E.key] = mode;
}
return files;
}
int EditorExportPreset::get_customized_files_count() const {
return customized_files.size();
}
void EditorExportPreset::set_customized_files(const Dictionary &p_files) {
for (const Variant *key = p_files.next(nullptr); key; key = p_files.next(key)) {
EditorExportPreset::FileExportMode mode = EditorExportPreset::MODE_FILE_NOT_CUSTOMIZED;
String value = p_files[*key];
if (value == "strip") {
mode = EditorExportPreset::MODE_FILE_STRIP;
} else if (value == "keep") {
mode = EditorExportPreset::MODE_FILE_KEEP;
} else if (value == "remove") {
mode = EditorExportPreset::MODE_FILE_REMOVE;
}
set_file_export_mode(*key, mode);
}
}
void EditorExportPreset::set_name(const String &p_name) {
name = p_name;
EditorExport::singleton->save_presets();
}
String EditorExportPreset::get_name() const {
return name;
}
void EditorExportPreset::set_runnable(bool p_enable) {
runnable = p_enable;
EditorExport::singleton->emit_presets_runnable_changed();
EditorExport::singleton->save_presets();
}
bool EditorExportPreset::is_runnable() const {
return runnable;
}
void EditorExportPreset::set_advanced_options_enabled(bool p_enabled) {
if (advanced_options_enabled == p_enabled) {
return;
}
advanced_options_enabled = p_enabled;
EditorExport::singleton->save_presets();
notify_property_list_changed();
}
bool EditorExportPreset::are_advanced_options_enabled() const {
return advanced_options_enabled;
}
void EditorExportPreset::set_dedicated_server(bool p_enable) {
dedicated_server = p_enable;
EditorExport::singleton->save_presets();
}
bool EditorExportPreset::is_dedicated_server() const {
return dedicated_server;
}
void EditorExportPreset::set_export_filter(ExportFilter p_filter) {
export_filter = p_filter;
EditorExport::singleton->save_presets();
}
EditorExportPreset::ExportFilter EditorExportPreset::get_export_filter() const {
return export_filter;
}
void EditorExportPreset::set_include_filter(const String &p_include) {
include_filter = p_include;
EditorExport::singleton->save_presets();
}
String EditorExportPreset::get_include_filter() const {
return include_filter;
}
void EditorExportPreset::set_export_path(const String &p_path) {
export_path = p_path;
/* NOTE(SonerSound): if there is a need to implement a PropertyHint that specifically indicates a relative path,
* this should be removed. */
if (export_path.is_absolute_path()) {
String res_path = OS::get_singleton()->get_resource_dir();
export_path = res_path.path_to_file(export_path);
}
EditorExport::singleton->save_presets();
}
String EditorExportPreset::get_export_path() const {
return export_path;
}
void EditorExportPreset::set_exclude_filter(const String &p_exclude) {
exclude_filter = p_exclude;
EditorExport::singleton->save_presets();
}
String EditorExportPreset::get_exclude_filter() const {
return exclude_filter;
}
void EditorExportPreset::add_export_file(const String &p_path) {
selected_files.insert(p_path);
EditorExport::singleton->save_presets();
}
void EditorExportPreset::remove_export_file(const String &p_path) {
selected_files.erase(p_path);
EditorExport::singleton->save_presets();
}
bool EditorExportPreset::has_export_file(const String &p_path) {
return selected_files.has(p_path);
}
void EditorExportPreset::set_file_export_mode(const String &p_path, EditorExportPreset::FileExportMode p_mode) {
if (p_mode == FileExportMode::MODE_FILE_NOT_CUSTOMIZED) {
customized_files.erase(p_path);
} else {
customized_files.insert(p_path, p_mode);
}
EditorExport::singleton->save_presets();
}
EditorExportPreset::FileExportMode EditorExportPreset::get_file_export_mode(const String &p_path, EditorExportPreset::FileExportMode p_default) const {
HashMap<String, FileExportMode>::ConstIterator i = customized_files.find(p_path);
if (i) {
return i->value;
}
return p_default;
}
void EditorExportPreset::set_custom_features(const String &p_custom_features) {
custom_features = p_custom_features;
EditorExport::singleton->save_presets();
}
String EditorExportPreset::get_custom_features() const {
return custom_features;
}
void EditorExportPreset::set_enc_in_filter(const String &p_filter) {
enc_in_filters = p_filter;
EditorExport::singleton->save_presets();
}
String EditorExportPreset::get_enc_in_filter() const {
return enc_in_filters;
}
void EditorExportPreset::set_enc_ex_filter(const String &p_filter) {
enc_ex_filters = p_filter;
EditorExport::singleton->save_presets();
}
String EditorExportPreset::get_enc_ex_filter() const {
return enc_ex_filters;
}
void EditorExportPreset::set_enc_pck(bool p_enabled) {
enc_pck = p_enabled;
EditorExport::singleton->save_presets();
}
bool EditorExportPreset::get_enc_pck() const {
return enc_pck;
}
void EditorExportPreset::set_enc_directory(bool p_enabled) {
enc_directory = p_enabled;
EditorExport::singleton->save_presets();
}
bool EditorExportPreset::get_enc_directory() const {
return enc_directory;
}
void EditorExportPreset::set_script_encryption_key(const String &p_key) {
script_key = p_key;
EditorExport::singleton->save_presets();
}
String EditorExportPreset::get_script_encryption_key() const {
return script_key;
}
void EditorExportPreset::set_script_export_mode(int p_mode) {
script_mode = p_mode;
EditorExport::singleton->save_presets();
}
int EditorExportPreset::get_script_export_mode() const {
return script_mode;
}
Variant EditorExportPreset::get_or_env(const StringName &p_name, const String &p_env_var, bool *r_valid) const {
const String from_env = OS::get_singleton()->get_environment(p_env_var);
if (!from_env.is_empty()) {
if (r_valid) {
*r_valid = true;
}
return from_env;
}
return get(p_name, r_valid);
}
_FORCE_INLINE_ bool _check_digits(const String &p_str) {
for (int i = 0; i < p_str.length(); i++) {
char32_t c = p_str.operator[](i);
if (!is_digit(c)) {
return false;
}
}
return true;
}
String EditorExportPreset::get_version(const StringName &p_preset_string, bool p_windows_version) const {
String result = get(p_preset_string);
if (result.is_empty()) {
result = GLOBAL_GET("application/config/version");
// Split and validate version number components.
const PackedStringArray result_split = result.split(".", false);
bool valid_version = !result_split.is_empty();
for (const String &E : result_split) {
if (!_check_digits(E)) {
valid_version = false;
break;
}
}
if (valid_version) {
if (p_windows_version) {
// Modify version number to match Windows constraints (version numbers must have 4 components).
if (result_split.size() == 1) {
result = result + ".0.0.0";
} else if (result_split.size() == 2) {
result = result + ".0.0";
} else if (result_split.size() == 3) {
result = result + ".0";
} else {
result = vformat("%s.%s.%s.%s", result_split[0], result_split[1], result_split[2], result_split[3]);
}
} else {
result = String(".").join(result_split);
}
} else {
if (!result.is_empty()) {
WARN_PRINT(vformat("Invalid version number \"%s\". The version number can only contain numeric characters (0-9) and non-consecutive periods (.).", result));
}
if (p_windows_version) {
result = "1.0.0.0";
} else {
result = "1.0.0";
}
}
}
return result;
}
EditorExportPreset::EditorExportPreset() {}

View file

@ -0,0 +1,186 @@
/**************************************************************************/
/* editor_export_preset.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#ifndef EDITOR_EXPORT_PRESET_H
#define EDITOR_EXPORT_PRESET_H
class EditorExportPlatform;
#include "core/object/ref_counted.h"
class EditorExportPreset : public RefCounted {
GDCLASS(EditorExportPreset, RefCounted);
public:
enum ExportFilter {
EXPORT_ALL_RESOURCES,
EXPORT_SELECTED_SCENES,
EXPORT_SELECTED_RESOURCES,
EXCLUDE_SELECTED_RESOURCES,
EXPORT_CUSTOMIZED,
};
enum FileExportMode {
MODE_FILE_NOT_CUSTOMIZED,
MODE_FILE_STRIP,
MODE_FILE_KEEP,
MODE_FILE_REMOVE,
};
enum ScriptExportMode {
MODE_SCRIPT_TEXT,
MODE_SCRIPT_BINARY_TOKENS,
MODE_SCRIPT_BINARY_TOKENS_COMPRESSED,
};
private:
Ref<EditorExportPlatform> platform;
ExportFilter export_filter = EXPORT_ALL_RESOURCES;
String include_filter;
String exclude_filter;
String export_path;
String exporter;
HashSet<String> selected_files;
HashMap<String, FileExportMode> customized_files;
bool runnable = false;
bool advanced_options_enabled = false;
bool dedicated_server = false;
friend class EditorExport;
friend class EditorExportPlatform;
HashMap<StringName, PropertyInfo> properties;
HashMap<StringName, Variant> values;
HashMap<StringName, Variant> value_overrides;
HashMap<StringName, bool> update_visibility;
String name;
String custom_features;
String enc_in_filters;
String enc_ex_filters;
bool enc_pck = false;
bool enc_directory = false;
String script_key;
int script_mode = MODE_SCRIPT_BINARY_TOKENS_COMPRESSED;
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
String _get_property_warning(const StringName &p_name) const;
static void _bind_methods();
public:
Ref<EditorExportPlatform> get_platform() const;
bool has(const StringName &p_property) const { return values.has(p_property); }
void update_files();
void update_value_overrides();
Vector<String> get_files_to_export() const;
Dictionary get_customized_files() const;
int get_customized_files_count() const;
void set_customized_files(const Dictionary &p_files);
void add_export_file(const String &p_path);
void remove_export_file(const String &p_path);
bool has_export_file(const String &p_path);
void set_file_export_mode(const String &p_path, FileExportMode p_mode);
FileExportMode get_file_export_mode(const String &p_path, FileExportMode p_default = MODE_FILE_NOT_CUSTOMIZED) const;
void set_name(const String &p_name);
String get_name() const;
void set_runnable(bool p_enable);
bool is_runnable() const;
void set_advanced_options_enabled(bool p_enabled);
bool are_advanced_options_enabled() const;
void set_dedicated_server(bool p_enable);
bool is_dedicated_server() const;
void set_export_filter(ExportFilter p_filter);
ExportFilter get_export_filter() const;
void set_include_filter(const String &p_include);
String get_include_filter() const;
void set_exclude_filter(const String &p_exclude);
String get_exclude_filter() const;
void set_custom_features(const String &p_custom_features);
String get_custom_features() const;
void set_export_path(const String &p_path);
String get_export_path() const;
void set_enc_in_filter(const String &p_filter);
String get_enc_in_filter() const;
void set_enc_ex_filter(const String &p_filter);
String get_enc_ex_filter() const;
void set_enc_pck(bool p_enabled);
bool get_enc_pck() const;
void set_enc_directory(bool p_enabled);
bool get_enc_directory() const;
void set_script_encryption_key(const String &p_key);
String get_script_encryption_key() const;
void set_script_export_mode(int p_mode);
int get_script_export_mode() const;
Variant get_or_env(const StringName &p_name, const String &p_env_var, bool *r_valid = nullptr) const;
// Return the preset's version number, or fall back to the
// `application/config/version` project setting if set to an empty string.
// If `p_windows_version` is `true`, formats the returned version number to
// be compatible with Windows executable metadata (which requires a
// 4-component format).
String get_version(const StringName &p_name, bool p_windows_version = false) const;
const HashMap<StringName, PropertyInfo> &get_properties() const { return properties; }
const HashMap<StringName, Variant> &get_values() const { return values; }
EditorExportPreset();
};
#endif // EDITOR_EXPORT_PRESET_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,140 @@
/**************************************************************************/
/* export_template_manager.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#ifndef EXPORT_TEMPLATE_MANAGER_H
#define EXPORT_TEMPLATE_MANAGER_H
#include "scene/gui/dialogs.h"
class EditorExportPreset;
class ExportTemplateVersion;
class FileDialog;
class HTTPRequest;
class MenuButton;
class OptionButton;
class ProgressBar;
class Tree;
class ExportTemplateManager : public AcceptDialog {
GDCLASS(ExportTemplateManager, AcceptDialog);
bool current_version_exists = false;
bool downloads_available = true;
bool mirrors_available = false;
bool is_refreshing_mirrors = false;
bool is_downloading_templates = false;
float update_countdown = 0;
Label *current_value = nullptr;
Label *current_missing_label = nullptr;
Label *current_installed_label = nullptr;
HBoxContainer *current_installed_hb = nullptr;
LineEdit *current_installed_path = nullptr;
Button *current_open_button = nullptr;
Button *current_uninstall_button = nullptr;
VBoxContainer *install_options_vb = nullptr;
OptionButton *mirrors_list = nullptr;
enum MirrorAction {
VISIT_WEB_MIRROR,
COPY_MIRROR_URL,
};
MenuButton *mirror_options_button = nullptr;
HBoxContainer *download_progress_hb = nullptr;
ProgressBar *download_progress_bar = nullptr;
Label *download_progress_label = nullptr;
HTTPRequest *download_templates = nullptr;
Button *install_file_button = nullptr;
HTTPRequest *request_mirrors = nullptr;
enum TemplatesAction {
OPEN_TEMPLATE_FOLDER,
UNINSTALL_TEMPLATE,
};
Tree *installed_table = nullptr;
ConfirmationDialog *uninstall_confirm = nullptr;
String uninstall_version;
FileDialog *install_file_dialog = nullptr;
AcceptDialog *hide_dialog_accept = nullptr;
void _update_template_status();
void _download_current();
void _download_template(const String &p_url, bool p_skip_check = false);
void _download_template_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data);
void _cancel_template_download();
void _refresh_mirrors();
void _refresh_mirrors_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data);
bool _humanize_http_status(HTTPRequest *p_request, String *r_status, int *r_downloaded_bytes, int *r_total_bytes);
void _set_current_progress_status(const String &p_status, bool p_error = false);
void _set_current_progress_value(float p_value, const String &p_status);
void _install_file();
bool _install_file_selected(const String &p_file, bool p_skip_progress = false);
void _uninstall_template(const String &p_version);
void _uninstall_template_confirmed();
String _get_selected_mirror() const;
void _mirror_options_button_cbk(int p_id);
void _installed_table_button_cbk(Object *p_item, int p_column, int p_id, MouseButton p_button);
void _open_template_folder(const String &p_version);
virtual void ok_pressed() override;
void _hide_dialog();
protected:
void _notification(int p_what);
static void _bind_methods();
public:
static String get_android_build_directory(const Ref<EditorExportPreset> &p_preset);
static String get_android_source_zip(const Ref<EditorExportPreset> &p_preset);
static String get_android_template_identifier(const Ref<EditorExportPreset> &p_preset);
bool is_android_template_installed(const Ref<EditorExportPreset> &p_preset);
bool can_install_android_template(const Ref<EditorExportPreset> &p_preset);
Error install_android_template(const Ref<EditorExportPreset> &p_preset);
Error install_android_template_from_file(const String &p_file, const Ref<EditorExportPreset> &p_preset);
void popup_manager();
ExportTemplateManager();
};
#endif // EXPORT_TEMPLATE_MANAGER_H

View file

@ -0,0 +1,338 @@
/**************************************************************************/
/* lipo.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#include "lipo.h"
bool LipO::is_lipo(const String &p_path) {
Ref<FileAccess> fb = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V_MSG(fb.is_null(), false, vformat("LipO: Can't open file: \"%s\".", p_path));
uint32_t magic = fb->get_32();
return (magic == 0xbebafeca || magic == 0xcafebabe || magic == 0xbfbafeca || magic == 0xcafebabf);
}
bool LipO::create_file(const String &p_output_path, const Vector<String> &p_files) {
close();
fa = FileAccess::open(p_output_path, FileAccess::WRITE);
ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("LipO: Can't open file: \"%s\".", p_output_path));
uint64_t max_size = 0;
for (int i = 0; i < p_files.size(); i++) {
{
MachO mh;
if (!mh.open_file(p_files[i])) {
ERR_FAIL_V_MSG(false, vformat("LipO: Invalid MachO file: \"%s\".", p_files[i]));
}
FatArch arch;
arch.cputype = mh.get_cputype();
arch.cpusubtype = mh.get_cpusubtype();
arch.offset = 0;
arch.size = mh.get_size();
arch.align = mh.get_align();
max_size += arch.size;
archs.push_back(arch);
}
Ref<FileAccess> fb = FileAccess::open(p_files[i], FileAccess::READ);
if (fb.is_null()) {
close();
ERR_FAIL_V_MSG(false, vformat("LipO: Can't open file: \"%s\".", p_files[i]));
}
}
// Write header.
bool is_64 = (max_size >= std::numeric_limits<uint32_t>::max());
if (is_64) {
fa->store_32(0xbfbafeca);
} else {
fa->store_32(0xbebafeca);
}
fa->store_32(BSWAP32(archs.size()));
uint64_t offset = archs.size() * (is_64 ? 32 : 20) + 8;
for (int i = 0; i < archs.size(); i++) {
archs.write[i].offset = offset + PAD(offset, uint64_t(1) << archs[i].align);
if (is_64) {
fa->store_32(BSWAP32(archs[i].cputype));
fa->store_32(BSWAP32(archs[i].cpusubtype));
fa->store_64(BSWAP64(archs[i].offset));
fa->store_64(BSWAP64(archs[i].size));
fa->store_32(BSWAP32(archs[i].align));
fa->store_32(0);
} else {
fa->store_32(BSWAP32(archs[i].cputype));
fa->store_32(BSWAP32(archs[i].cpusubtype));
fa->store_32(BSWAP32(archs[i].offset));
fa->store_32(BSWAP32(archs[i].size));
fa->store_32(BSWAP32(archs[i].align));
}
offset = archs[i].offset + archs[i].size;
}
// Write files and padding.
for (int i = 0; i < archs.size(); i++) {
Ref<FileAccess> fb = FileAccess::open(p_files[i], FileAccess::READ);
if (fb.is_null()) {
close();
ERR_FAIL_V_MSG(false, vformat("LipO: Can't open file: \"%s\".", p_files[i]));
}
uint64_t cur = fa->get_position();
for (uint64_t j = cur; j < archs[i].offset; j++) {
fa->store_8(0);
}
int pages = archs[i].size / 4096;
int remain = archs[i].size % 4096;
unsigned char step[4096];
for (int j = 0; j < pages; j++) {
uint64_t br = fb->get_buffer(step, 4096);
if (br > 0) {
fa->store_buffer(step, br);
}
}
uint64_t br = fb->get_buffer(step, remain);
if (br > 0) {
fa->store_buffer(step, br);
}
}
return true;
}
bool LipO::create_file(const String &p_output_path, const Vector<String> &p_files, const Vector<Vector2i> &p_cputypes) {
close();
fa = FileAccess::open(p_output_path, FileAccess::WRITE);
ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("LipO: Can't open file: \"%s\".", p_output_path));
ERR_FAIL_COND_V(p_files.size() != p_cputypes.size(), false);
uint64_t max_size = 0;
for (int i = 0; i < p_files.size(); i++) {
Ref<FileAccess> fb = FileAccess::open(p_files[i], FileAccess::READ);
if (fb.is_null()) {
close();
ERR_FAIL_V_MSG(false, vformat("LipO: Can't open file: \"%s\".", p_files[i]));
}
{
FatArch arch;
MachO mh;
if (MachO::is_macho(p_files[i]) && mh.open_file(p_files[i])) {
arch.cputype = mh.get_cputype();
arch.cpusubtype = mh.get_cpusubtype();
arch.offset = 0;
arch.size = mh.get_size();
arch.align = mh.get_align();
ERR_FAIL_V_MSG(arch.cputype != (uint32_t)p_cputypes[i].x || arch.cpusubtype != (uint32_t)p_cputypes[i].y, vformat("Mismatching MachO architecture: \"%s\".", p_files[i]));
} else {
arch.cputype = (uint32_t)p_cputypes[i].x;
arch.cpusubtype = (uint32_t)p_cputypes[i].y;
arch.offset = 0;
arch.size = fb->get_length();
arch.align = 0x03;
}
max_size += arch.size;
archs.push_back(arch);
}
}
// Write header.
bool is_64 = (max_size >= std::numeric_limits<uint32_t>::max());
if (is_64) {
fa->store_32(0xbfbafeca);
} else {
fa->store_32(0xbebafeca);
}
fa->store_32(BSWAP32(archs.size()));
uint64_t offset = archs.size() * (is_64 ? 32 : 20) + 8;
for (int i = 0; i < archs.size(); i++) {
archs.write[i].offset = offset + PAD(offset, uint64_t(1) << archs[i].align);
if (is_64) {
fa->store_32(BSWAP32(archs[i].cputype));
fa->store_32(BSWAP32(archs[i].cpusubtype));
fa->store_64(BSWAP64(archs[i].offset));
fa->store_64(BSWAP64(archs[i].size));
fa->store_32(BSWAP32(archs[i].align));
fa->store_32(0);
} else {
fa->store_32(BSWAP32(archs[i].cputype));
fa->store_32(BSWAP32(archs[i].cpusubtype));
fa->store_32(BSWAP32(archs[i].offset));
fa->store_32(BSWAP32(archs[i].size));
fa->store_32(BSWAP32(archs[i].align));
}
offset = archs[i].offset + archs[i].size;
}
// Write files and padding.
for (int i = 0; i < archs.size(); i++) {
Ref<FileAccess> fb = FileAccess::open(p_files[i], FileAccess::READ);
if (fb.is_null()) {
close();
ERR_FAIL_V_MSG(false, vformat("LipO: Can't open file: \"%s\".", p_files[i]));
}
uint64_t cur = fa->get_position();
for (uint64_t j = cur; j < archs[i].offset; j++) {
fa->store_8(0);
}
int pages = archs[i].size / 4096;
int remain = archs[i].size % 4096;
unsigned char step[4096];
for (int j = 0; j < pages; j++) {
uint64_t br = fb->get_buffer(step, 4096);
if (br > 0) {
fa->store_buffer(step, br);
}
}
uint64_t br = fb->get_buffer(step, remain);
if (br > 0) {
fa->store_buffer(step, br);
}
}
return true;
}
bool LipO::open_file(const String &p_path) {
close();
fa = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("LipO: Can't open file: \"%s\".", p_path));
uint32_t magic = fa->get_32();
if (magic == 0xbebafeca) {
// 32-bit fat binary, bswap.
uint32_t nfat_arch = BSWAP32(fa->get_32());
for (uint32_t i = 0; i < nfat_arch; i++) {
FatArch arch;
arch.cputype = BSWAP32(fa->get_32());
arch.cpusubtype = BSWAP32(fa->get_32());
arch.offset = BSWAP32(fa->get_32());
arch.size = BSWAP32(fa->get_32());
arch.align = BSWAP32(fa->get_32());
archs.push_back(arch);
}
} else if (magic == 0xcafebabe) {
// 32-bit fat binary.
uint32_t nfat_arch = fa->get_32();
for (uint32_t i = 0; i < nfat_arch; i++) {
FatArch arch;
arch.cputype = fa->get_32();
arch.cpusubtype = fa->get_32();
arch.offset = fa->get_32();
arch.size = fa->get_32();
arch.align = fa->get_32();
archs.push_back(arch);
}
} else if (magic == 0xbfbafeca) {
// 64-bit fat binary, bswap.
uint32_t nfat_arch = BSWAP32(fa->get_32());
for (uint32_t i = 0; i < nfat_arch; i++) {
FatArch arch;
arch.cputype = BSWAP32(fa->get_32());
arch.cpusubtype = BSWAP32(fa->get_32());
arch.offset = BSWAP64(fa->get_64());
arch.size = BSWAP64(fa->get_64());
arch.align = BSWAP32(fa->get_32());
fa->get_32(); // Skip, reserved.
archs.push_back(arch);
}
} else if (magic == 0xcafebabf) {
// 64-bit fat binary.
uint32_t nfat_arch = fa->get_32();
for (uint32_t i = 0; i < nfat_arch; i++) {
FatArch arch;
arch.cputype = fa->get_32();
arch.cpusubtype = fa->get_32();
arch.offset = fa->get_64();
arch.size = fa->get_64();
arch.align = fa->get_32();
fa->get_32(); // Skip, reserved.
archs.push_back(arch);
}
} else {
close();
ERR_FAIL_V_MSG(false, vformat("LipO: Invalid fat binary: \"%s\".", p_path));
}
return true;
}
int LipO::get_arch_count() const {
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "LipO: File not opened.");
return archs.size();
}
uint32_t LipO::get_arch_cputype(int p_index) const {
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "LipO: File not opened.");
ERR_FAIL_INDEX_V(p_index, archs.size(), 0);
return archs[p_index].cputype;
}
uint32_t LipO::get_arch_cpusubtype(int p_index) const {
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "LipO: File not opened.");
ERR_FAIL_INDEX_V(p_index, archs.size(), 0);
return archs[p_index].cpusubtype;
}
bool LipO::extract_arch(int p_index, const String &p_path) {
ERR_FAIL_COND_V_MSG(fa.is_null(), false, "LipO: File not opened.");
ERR_FAIL_INDEX_V(p_index, archs.size(), false);
Ref<FileAccess> fb = FileAccess::open(p_path, FileAccess::WRITE);
ERR_FAIL_COND_V_MSG(fb.is_null(), false, vformat("LipO: Can't open file: \"%s\".", p_path));
fa->seek(archs[p_index].offset);
int pages = archs[p_index].size / 4096;
int remain = archs[p_index].size % 4096;
unsigned char step[4096];
for (int i = 0; i < pages; i++) {
uint64_t br = fa->get_buffer(step, 4096);
if (br > 0) {
fb->store_buffer(step, br);
}
}
uint64_t br = fa->get_buffer(step, remain);
if (br > 0) {
fb->store_buffer(step, br);
}
return true;
}
void LipO::close() {
archs.clear();
}
LipO::~LipO() {
close();
}

View file

@ -0,0 +1,74 @@
/**************************************************************************/
/* lipo.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#ifndef LIPO_H
#define LIPO_H
// Universal / Universal 2 fat binary file creator and extractor.
#include "macho.h"
#include "core/io/file_access.h"
#include "core/object/ref_counted.h"
class LipO : public RefCounted {
struct FatArch {
uint32_t cputype;
uint32_t cpusubtype;
uint64_t offset;
uint64_t size;
uint32_t align;
};
Ref<FileAccess> fa;
Vector<FatArch> archs;
static inline size_t PAD(size_t s, size_t a) {
return (a - s % a);
}
public:
static bool is_lipo(const String &p_path);
bool create_file(const String &p_output_path, const Vector<String> &p_files);
bool create_file(const String &p_output_path, const Vector<String> &p_files, const Vector<Vector2i> &p_cputypes);
bool open_file(const String &p_path);
int get_arch_count() const;
uint32_t get_arch_cputype(int p_index) const;
uint32_t get_arch_cpusubtype(int p_index) const;
bool extract_arch(int p_index, const String &p_path);
void close();
~LipO();
};
#endif // LIPO_H

View file

@ -0,0 +1,562 @@
/**************************************************************************/
/* macho.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#include "macho.h"
uint32_t MachO::seg_align(uint64_t p_vmaddr, uint32_t p_min, uint32_t p_max) {
uint32_t salign = p_max;
if (p_vmaddr != 0) {
uint64_t seg_align = 1;
salign = 0;
while ((seg_align & p_vmaddr) == 0) {
seg_align = seg_align << 1;
salign++;
}
salign = CLAMP(salign, p_min, p_max);
}
return salign;
}
bool MachO::alloc_signature(uint64_t p_size) {
ERR_FAIL_COND_V_MSG(fa.is_null(), false, "MachO: File not opened.");
if (signature_offset != 0) {
// Nothing to do, already have signature load command.
return true;
}
if (lc_limit == 0 || lc_limit + 16 > exe_base) {
ERR_FAIL_V_MSG(false, "MachO: Can't allocate signature load command, please use \"codesign_allocate\" utility first.");
} else {
// Add signature load command.
signature_offset = lc_limit;
fa->seek(lc_limit);
LoadCommandHeader lc;
lc.cmd = LC_CODE_SIGNATURE;
lc.cmdsize = 16;
if (swap) {
lc.cmdsize = BSWAP32(lc.cmdsize);
}
fa->store_buffer((const uint8_t *)&lc, sizeof(LoadCommandHeader));
uint32_t lc_offset = fa->get_length() + PAD(fa->get_length(), 16);
uint32_t lc_size = 0;
if (swap) {
lc_offset = BSWAP32(lc_offset);
lc_size = BSWAP32(lc_size);
}
fa->store_32(lc_offset);
fa->store_32(lc_size);
// Write new command number.
fa->seek(0x10);
uint32_t ncmds = fa->get_32();
uint32_t cmdssize = fa->get_32();
if (swap) {
ncmds = BSWAP32(ncmds);
cmdssize = BSWAP32(cmdssize);
}
ncmds += 1;
cmdssize += 16;
if (swap) {
ncmds = BSWAP32(ncmds);
cmdssize = BSWAP32(cmdssize);
}
fa->seek(0x10);
fa->store_32(ncmds);
fa->store_32(cmdssize);
lc_limit = lc_limit + sizeof(LoadCommandHeader) + 8;
return true;
}
}
bool MachO::is_macho(const String &p_path) {
Ref<FileAccess> fb = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V_MSG(fb.is_null(), false, vformat("MachO: Can't open file: \"%s\".", p_path));
uint32_t magic = fb->get_32();
return (magic == 0xcefaedfe || magic == 0xfeedface || magic == 0xcffaedfe || magic == 0xfeedfacf);
}
uint32_t MachO::get_filetype(const String &p_path) {
Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, vformat("MachO: Can't open file: \"%s\".", p_path));
uint32_t magic = fa->get_32();
MachHeader mach_header;
// Read MachO header.
if (magic == 0xcefaedfe || magic == 0xfeedface) {
// Thin 32-bit binary.
fa->get_buffer((uint8_t *)&mach_header, sizeof(MachHeader));
} else if (magic == 0xcffaedfe || magic == 0xfeedfacf) {
// Thin 64-bit binary.
fa->get_buffer((uint8_t *)&mach_header, sizeof(MachHeader));
fa->get_32(); // Skip extra reserved field.
} else {
ERR_FAIL_V_MSG(0, vformat("MachO: File is not a valid MachO binary: \"%s\".", p_path));
}
return mach_header.filetype;
}
bool MachO::open_file(const String &p_path) {
fa = FileAccess::open(p_path, FileAccess::READ_WRITE);
ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("MachO: Can't open file: \"%s\".", p_path));
uint32_t magic = fa->get_32();
MachHeader mach_header;
// Read MachO header.
swap = (magic == 0xcffaedfe || magic == 0xcefaedfe);
if (magic == 0xcefaedfe || magic == 0xfeedface) {
// Thin 32-bit binary.
fa->get_buffer((uint8_t *)&mach_header, sizeof(MachHeader));
} else if (magic == 0xcffaedfe || magic == 0xfeedfacf) {
// Thin 64-bit binary.
fa->get_buffer((uint8_t *)&mach_header, sizeof(MachHeader));
fa->get_32(); // Skip extra reserved field.
} else {
ERR_FAIL_V_MSG(false, vformat("MachO: File is not a valid MachO binary: \"%s\".", p_path));
}
if (swap) {
mach_header.ncmds = BSWAP32(mach_header.ncmds);
mach_header.cpusubtype = BSWAP32(mach_header.cpusubtype);
mach_header.cputype = BSWAP32(mach_header.cputype);
}
cpusubtype = mach_header.cpusubtype;
cputype = mach_header.cputype;
align = 0;
exe_base = std::numeric_limits<uint64_t>::max();
exe_limit = 0;
lc_limit = 0;
link_edit_offset = 0;
signature_offset = 0;
// Read load commands.
for (uint32_t i = 0; i < mach_header.ncmds; i++) {
LoadCommandHeader lc;
fa->get_buffer((uint8_t *)&lc, sizeof(LoadCommandHeader));
if (swap) {
lc.cmd = BSWAP32(lc.cmd);
lc.cmdsize = BSWAP32(lc.cmdsize);
}
uint64_t ps = fa->get_position();
switch (lc.cmd) {
case LC_SEGMENT: {
LoadCommandSegment lc_seg;
fa->get_buffer((uint8_t *)&lc_seg, sizeof(LoadCommandSegment));
if (swap) {
lc_seg.nsects = BSWAP32(lc_seg.nsects);
lc_seg.vmaddr = BSWAP32(lc_seg.vmaddr);
lc_seg.vmsize = BSWAP32(lc_seg.vmsize);
}
align = MAX(align, seg_align(lc_seg.vmaddr, 2, 15));
if (String(lc_seg.segname) == "__TEXT") {
exe_limit = MAX(exe_limit, lc_seg.vmsize);
for (uint32_t j = 0; j < lc_seg.nsects; j++) {
Section lc_sect;
fa->get_buffer((uint8_t *)&lc_sect, sizeof(Section));
if (String(lc_sect.sectname) == "__text") {
if (swap) {
exe_base = MIN(exe_base, BSWAP32(lc_sect.offset));
} else {
exe_base = MIN(exe_base, lc_sect.offset);
}
}
if (swap) {
align = MAX(align, BSWAP32(lc_sect.align));
} else {
align = MAX(align, lc_sect.align);
}
}
} else if (String(lc_seg.segname) == "__LINKEDIT") {
link_edit_offset = ps - 8;
}
} break;
case LC_SEGMENT_64: {
LoadCommandSegment64 lc_seg;
fa->get_buffer((uint8_t *)&lc_seg, sizeof(LoadCommandSegment64));
if (swap) {
lc_seg.nsects = BSWAP32(lc_seg.nsects);
lc_seg.vmaddr = BSWAP64(lc_seg.vmaddr);
lc_seg.vmsize = BSWAP64(lc_seg.vmsize);
}
align = MAX(align, seg_align(lc_seg.vmaddr, 3, 15));
if (String(lc_seg.segname) == "__TEXT") {
exe_limit = MAX(exe_limit, lc_seg.vmsize);
for (uint32_t j = 0; j < lc_seg.nsects; j++) {
Section64 lc_sect;
fa->get_buffer((uint8_t *)&lc_sect, sizeof(Section64));
if (String(lc_sect.sectname) == "__text") {
if (swap) {
exe_base = MIN(exe_base, BSWAP32(lc_sect.offset));
} else {
exe_base = MIN(exe_base, lc_sect.offset);
}
if (swap) {
align = MAX(align, BSWAP32(lc_sect.align));
} else {
align = MAX(align, lc_sect.align);
}
}
}
} else if (String(lc_seg.segname) == "__LINKEDIT") {
link_edit_offset = ps - 8;
}
} break;
case LC_CODE_SIGNATURE: {
signature_offset = ps - 8;
} break;
default: {
} break;
}
fa->seek(ps + lc.cmdsize - 8);
lc_limit = ps + lc.cmdsize - 8;
}
if (exe_limit == 0 || lc_limit == 0) {
ERR_FAIL_V_MSG(false, vformat("MachO: No load commands or executable code found: \"%s\".", p_path));
}
return true;
}
uint64_t MachO::get_exe_base() {
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened.");
return exe_base;
}
uint64_t MachO::get_exe_limit() {
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened.");
return exe_limit;
}
int32_t MachO::get_align() {
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened.");
return align;
}
uint32_t MachO::get_cputype() {
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened.");
return cputype;
}
uint32_t MachO::get_cpusubtype() {
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened.");
return cpusubtype;
}
uint64_t MachO::get_size() {
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened.");
return fa->get_length();
}
uint64_t MachO::get_signature_offset() {
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened.");
ERR_FAIL_COND_V_MSG(signature_offset == 0, 0, "MachO: No signature load command.");
fa->seek(signature_offset + 8);
if (swap) {
return BSWAP32(fa->get_32());
} else {
return fa->get_32();
}
}
uint64_t MachO::get_code_limit() {
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened.");
if (signature_offset == 0) {
return fa->get_length() + PAD(fa->get_length(), 16);
} else {
return get_signature_offset();
}
}
uint64_t MachO::get_signature_size() {
ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened.");
ERR_FAIL_COND_V_MSG(signature_offset == 0, 0, "MachO: No signature load command.");
fa->seek(signature_offset + 12);
if (swap) {
return BSWAP32(fa->get_32());
} else {
return fa->get_32();
}
}
bool MachO::is_signed() {
ERR_FAIL_COND_V_MSG(fa.is_null(), false, "MachO: File not opened.");
if (signature_offset == 0) {
return false;
}
fa->seek(get_signature_offset());
uint32_t magic = BSWAP32(fa->get_32());
if (magic != 0xfade0cc0) {
return false; // No SuperBlob found.
}
fa->get_32(); // Skip size field, unused.
uint32_t count = BSWAP32(fa->get_32());
for (uint32_t i = 0; i < count; i++) {
uint32_t index_type = BSWAP32(fa->get_32());
uint32_t offset = BSWAP32(fa->get_32());
if (index_type == 0x00000000) { // CodeDirectory index type.
fa->seek(get_signature_offset() + offset + 12);
uint32_t flags = BSWAP32(fa->get_32());
if (flags & 0x20000) {
return false; // Found CD, linker-signed.
} else {
return true; // Found CD, not linker-signed.
}
}
}
return false; // No CD found.
}
PackedByteArray MachO::get_cdhash_sha1() {
ERR_FAIL_COND_V_MSG(fa.is_null(), PackedByteArray(), "MachO: File not opened.");
if (signature_offset == 0) {
return PackedByteArray();
}
fa->seek(get_signature_offset());
uint32_t magic = BSWAP32(fa->get_32());
if (magic != 0xfade0cc0) {
return PackedByteArray(); // No SuperBlob found.
}
fa->get_32(); // Skip size field, unused.
uint32_t count = BSWAP32(fa->get_32());
for (uint32_t i = 0; i < count; i++) {
fa->get_32(); // Index type, skip.
uint32_t offset = BSWAP32(fa->get_32());
uint64_t pos = fa->get_position();
fa->seek(get_signature_offset() + offset);
uint32_t cdmagic = BSWAP32(fa->get_32());
uint32_t cdsize = BSWAP32(fa->get_32());
if (cdmagic == 0xfade0c02) { // CodeDirectory.
fa->seek(get_signature_offset() + offset + 36);
uint8_t hash_size = fa->get_8();
uint8_t hash_type = fa->get_8();
if (hash_size == 0x14 && hash_type == 0x01) { /* SHA-1 */
PackedByteArray hash;
hash.resize(0x14);
fa->seek(get_signature_offset() + offset);
PackedByteArray blob;
blob.resize(cdsize);
fa->get_buffer(blob.ptrw(), cdsize);
CryptoCore::SHA1Context ctx;
ctx.start();
ctx.update(blob.ptr(), blob.size());
ctx.finish(hash.ptrw());
return hash;
}
}
fa->seek(pos);
}
return PackedByteArray();
}
PackedByteArray MachO::get_cdhash_sha256() {
ERR_FAIL_COND_V_MSG(fa.is_null(), PackedByteArray(), "MachO: File not opened.");
if (signature_offset == 0) {
return PackedByteArray();
}
fa->seek(get_signature_offset());
uint32_t magic = BSWAP32(fa->get_32());
if (magic != 0xfade0cc0) {
return PackedByteArray(); // No SuperBlob found.
}
fa->get_32(); // Skip size field, unused.
uint32_t count = BSWAP32(fa->get_32());
for (uint32_t i = 0; i < count; i++) {
fa->get_32(); // Index type, skip.
uint32_t offset = BSWAP32(fa->get_32());
uint64_t pos = fa->get_position();
fa->seek(get_signature_offset() + offset);
uint32_t cdmagic = BSWAP32(fa->get_32());
uint32_t cdsize = BSWAP32(fa->get_32());
if (cdmagic == 0xfade0c02) { // CodeDirectory.
fa->seek(get_signature_offset() + offset + 36);
uint8_t hash_size = fa->get_8();
uint8_t hash_type = fa->get_8();
if (hash_size == 0x20 && hash_type == 0x02) { /* SHA-256 */
PackedByteArray hash;
hash.resize(0x20);
fa->seek(get_signature_offset() + offset);
PackedByteArray blob;
blob.resize(cdsize);
fa->get_buffer(blob.ptrw(), cdsize);
CryptoCore::SHA256Context ctx;
ctx.start();
ctx.update(blob.ptr(), blob.size());
ctx.finish(hash.ptrw());
return hash;
}
}
fa->seek(pos);
}
return PackedByteArray();
}
PackedByteArray MachO::get_requirements() {
ERR_FAIL_COND_V_MSG(fa.is_null(), PackedByteArray(), "MachO: File not opened.");
if (signature_offset == 0) {
return PackedByteArray();
}
fa->seek(get_signature_offset());
uint32_t magic = BSWAP32(fa->get_32());
if (magic != 0xfade0cc0) {
return PackedByteArray(); // No SuperBlob found.
}
fa->get_32(); // Skip size field, unused.
uint32_t count = BSWAP32(fa->get_32());
for (uint32_t i = 0; i < count; i++) {
fa->get_32(); // Index type, skip.
uint32_t offset = BSWAP32(fa->get_32());
uint64_t pos = fa->get_position();
fa->seek(get_signature_offset() + offset);
uint32_t rqmagic = BSWAP32(fa->get_32());
uint32_t rqsize = BSWAP32(fa->get_32());
if (rqmagic == 0xfade0c01) { // Requirements.
PackedByteArray blob;
fa->seek(get_signature_offset() + offset);
blob.resize(rqsize);
fa->get_buffer(blob.ptrw(), rqsize);
return blob;
}
fa->seek(pos);
}
return PackedByteArray();
}
const Ref<FileAccess> MachO::get_file() const {
return fa;
}
Ref<FileAccess> MachO::get_file() {
return fa;
}
bool MachO::set_signature_size(uint64_t p_size) {
ERR_FAIL_COND_V_MSG(fa.is_null(), false, "MachO: File not opened.");
// Ensure signature load command exists.
ERR_FAIL_COND_V_MSG(link_edit_offset == 0, false, "MachO: No __LINKEDIT segment found.");
ERR_FAIL_COND_V_MSG(!alloc_signature(p_size), false, "MachO: Can't allocate signature load command.");
// Update signature load command.
uint64_t old_size = get_signature_size();
uint64_t new_size = p_size + PAD(p_size, 16384);
if (new_size <= old_size) {
fa->seek(get_signature_offset());
for (uint64_t i = 0; i < old_size; i++) {
fa->store_8(0x00);
}
return true;
}
fa->seek(signature_offset + 12);
if (swap) {
fa->store_32(BSWAP32(new_size));
} else {
fa->store_32(new_size);
}
uint64_t end = get_signature_offset() + new_size;
// Update "__LINKEDIT" segment.
LoadCommandHeader lc;
fa->seek(link_edit_offset);
fa->get_buffer((uint8_t *)&lc, sizeof(LoadCommandHeader));
if (swap) {
lc.cmd = BSWAP32(lc.cmd);
lc.cmdsize = BSWAP32(lc.cmdsize);
}
switch (lc.cmd) {
case LC_SEGMENT: {
LoadCommandSegment lc_seg;
fa->get_buffer((uint8_t *)&lc_seg, sizeof(LoadCommandSegment));
if (swap) {
lc_seg.vmsize = BSWAP32(lc_seg.vmsize);
lc_seg.filesize = BSWAP32(lc_seg.filesize);
lc_seg.fileoff = BSWAP32(lc_seg.fileoff);
}
lc_seg.vmsize = end - lc_seg.fileoff;
lc_seg.vmsize += PAD(lc_seg.vmsize, 4096);
lc_seg.filesize = end - lc_seg.fileoff;
if (swap) {
lc_seg.vmsize = BSWAP32(lc_seg.vmsize);
lc_seg.filesize = BSWAP32(lc_seg.filesize);
}
fa->seek(link_edit_offset + 8);
fa->store_buffer((const uint8_t *)&lc_seg, sizeof(LoadCommandSegment));
} break;
case LC_SEGMENT_64: {
LoadCommandSegment64 lc_seg;
fa->get_buffer((uint8_t *)&lc_seg, sizeof(LoadCommandSegment64));
if (swap) {
lc_seg.vmsize = BSWAP64(lc_seg.vmsize);
lc_seg.filesize = BSWAP64(lc_seg.filesize);
lc_seg.fileoff = BSWAP64(lc_seg.fileoff);
}
lc_seg.vmsize = end - lc_seg.fileoff;
lc_seg.vmsize += PAD(lc_seg.vmsize, 4096);
lc_seg.filesize = end - lc_seg.fileoff;
if (swap) {
lc_seg.vmsize = BSWAP64(lc_seg.vmsize);
lc_seg.filesize = BSWAP64(lc_seg.filesize);
}
fa->seek(link_edit_offset + 8);
fa->store_buffer((const uint8_t *)&lc_seg, sizeof(LoadCommandSegment64));
} break;
default: {
ERR_FAIL_V_MSG(false, "MachO: Invalid __LINKEDIT segment type.");
} break;
}
fa->seek(get_signature_offset());
for (uint64_t i = 0; i < new_size; i++) {
fa->store_8(0x00);
}
return true;
}

View file

@ -0,0 +1,228 @@
/**************************************************************************/
/* macho.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#ifndef MACHO_H
#define MACHO_H
// Mach-O binary object file format parser and editor.
#include "core/crypto/crypto.h"
#include "core/crypto/crypto_core.h"
#include "core/io/file_access.h"
#include "core/object/ref_counted.h"
class MachO : public RefCounted {
public:
struct MachHeader {
uint32_t cputype;
uint32_t cpusubtype;
uint32_t filetype;
uint32_t ncmds;
uint32_t sizeofcmds;
uint32_t flags;
};
enum LoadCommandID {
LC_SEGMENT = 0x00000001,
LC_SYMTAB = 0x00000002,
LC_SYMSEG = 0x00000003,
LC_THREAD = 0x00000004,
LC_UNIXTHREAD = 0x00000005,
LC_LOADFVMLIB = 0x00000006,
LC_IDFVMLIB = 0x00000007,
LC_IDENT = 0x00000008,
LC_FVMFILE = 0x00000009,
LC_PREPAGE = 0x0000000a,
LC_DYSYMTAB = 0x0000000b,
LC_LOAD_DYLIB = 0x0000000c,
LC_ID_DYLIB = 0x0000000d,
LC_LOAD_DYLINKER = 0x0000000e,
LC_ID_DYLINKER = 0x0000000f,
LC_PREBOUND_DYLIB = 0x00000010,
LC_ROUTINES = 0x00000011,
LC_SUB_FRAMEWORK = 0x00000012,
LC_SUB_UMBRELLA = 0x00000013,
LC_SUB_CLIENT = 0x00000014,
LC_SUB_LIBRARY = 0x00000015,
LC_TWOLEVEL_HINTS = 0x00000016,
LC_PREBIND_CKSUM = 0x00000017,
LC_LOAD_WEAK_DYLIB = 0x80000018,
LC_SEGMENT_64 = 0x00000019,
LC_ROUTINES_64 = 0x0000001a,
LC_UUID = 0x0000001b,
LC_RPATH = 0x8000001c,
LC_CODE_SIGNATURE = 0x0000001d,
LC_SEGMENT_SPLIT_INFO = 0x0000001e,
LC_REEXPORT_DYLIB = 0x8000001f,
LC_LAZY_LOAD_DYLIB = 0x00000020,
LC_ENCRYPTION_INFO = 0x00000021,
LC_DYLD_INFO = 0x00000022,
LC_DYLD_INFO_ONLY = 0x80000022,
LC_LOAD_UPWARD_DYLIB = 0x80000023,
LC_VERSION_MIN_MACOSX = 0x00000024,
LC_VERSION_MIN_IPHONEOS = 0x00000025,
LC_FUNCTION_STARTS = 0x00000026,
LC_DYLD_ENVIRONMENT = 0x00000027,
LC_MAIN = 0x80000028,
LC_DATA_IN_CODE = 0x00000029,
LC_SOURCE_VERSION = 0x0000002a,
LC_DYLIB_CODE_SIGN_DRS = 0x0000002b,
LC_ENCRYPTION_INFO_64 = 0x0000002c,
LC_LINKER_OPTION = 0x0000002d,
LC_LINKER_OPTIMIZATION_HINT = 0x0000002e,
LC_VERSION_MIN_TVOS = 0x0000002f,
LC_VERSION_MIN_WATCHOS = 0x00000030,
LC_BUILD_VERSION = 0x00000032,
};
enum PlatformID {
PLATFORM_UNKNOWN = 0,
PLATFORM_MACOS = 1,
PLATFORM_IOS = 2,
PLATFORM_TVOS = 3,
PLATFORM_WATCHOS = 4,
PLATFORM_BRIDGEOS = 5,
PLATFORM_MACCATALYST = 6,
PLATFORM_IOSSIMULATOR = 7,
PLATFORM_TVOSSIMULATOR = 8,
PLATFORM_WATCHOSSIMULATOR = 9,
PLATFORM_DRIVERKIT = 10,
};
struct LoadCommandHeader {
uint32_t cmd;
uint32_t cmdsize;
};
struct LoadCommandSegment {
char segname[16];
uint32_t vmaddr;
uint32_t vmsize;
uint32_t fileoff;
uint32_t filesize;
uint32_t maxprot;
uint32_t initprot;
uint32_t nsects;
uint32_t flags;
};
struct LoadCommandSegment64 {
char segname[16];
uint64_t vmaddr;
uint64_t vmsize;
uint64_t fileoff;
uint64_t filesize;
uint32_t maxprot;
uint32_t initprot;
uint32_t nsects;
uint32_t flags;
};
struct Section {
char sectname[16];
char segname[16];
uint32_t addr;
uint32_t size;
uint32_t offset;
uint32_t align;
uint32_t reloff;
uint32_t nreloc;
uint32_t flags;
uint32_t reserved1;
uint32_t reserved2;
};
struct Section64 {
char sectname[16];
char segname[16];
uint64_t addr;
uint64_t size;
uint32_t offset;
uint32_t align;
uint32_t reloff;
uint32_t nreloc;
uint32_t flags;
uint32_t reserved1;
uint32_t reserved2;
uint32_t reserved3;
};
private:
Ref<FileAccess> fa;
bool swap = false;
uint64_t lc_limit = 0;
uint64_t exe_limit = 0;
uint64_t exe_base = std::numeric_limits<uint64_t>::max(); // Start of first __text section.
uint32_t align = 0;
uint32_t cputype = 0;
uint32_t cpusubtype = 0;
uint64_t link_edit_offset = 0; // __LINKEDIT segment offset.
uint64_t signature_offset = 0; // Load command offset.
uint32_t seg_align(uint64_t p_vmaddr, uint32_t p_min, uint32_t p_max);
bool alloc_signature(uint64_t p_size);
static inline size_t PAD(size_t s, size_t a) {
return (a - s % a);
}
public:
static bool is_macho(const String &p_path);
static uint32_t get_filetype(const String &p_path);
bool open_file(const String &p_path);
uint64_t get_exe_base();
uint64_t get_exe_limit();
int32_t get_align();
uint32_t get_cputype();
uint32_t get_cpusubtype();
uint64_t get_size();
uint64_t get_code_limit();
uint64_t get_signature_offset();
bool is_signed();
PackedByteArray get_cdhash_sha1();
PackedByteArray get_cdhash_sha256();
PackedByteArray get_requirements();
const Ref<FileAccess> get_file() const;
Ref<FileAccess> get_file();
uint64_t get_signature_size();
bool set_signature_size(uint64_t p_size);
};
#endif // MACHO_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,212 @@
/**************************************************************************/
/* project_export.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#ifndef PROJECT_EXPORT_H
#define PROJECT_EXPORT_H
#include "editor/export/editor_export_preset.h"
#include "scene/gui/dialogs.h"
class CheckBox;
class CheckButton;
class EditorFileDialog;
class EditorFileSystemDirectory;
class EditorInspector;
class EditorPropertyPath;
class ItemList;
class LinkButton;
class MenuButton;
class OptionButton;
class PopupMenu;
class RichTextLabel;
class TabContainer;
class Tree;
class TreeItem;
class ProjectExportTextureFormatError : public HBoxContainer {
GDCLASS(ProjectExportTextureFormatError, HBoxContainer);
Label *texture_format_error_label = nullptr;
LinkButton *fix_texture_format_button = nullptr;
String setting_identifier;
void _on_fix_texture_format_pressed();
protected:
static void _bind_methods();
void _notification(int p_what);
public:
void show_for_texture_format(const String &p_friendly_name, const String &p_setting_identifier);
ProjectExportTextureFormatError();
};
class ProjectExportDialog : public ConfirmationDialog {
GDCLASS(ProjectExportDialog, ConfirmationDialog);
TabContainer *sections = nullptr;
MenuButton *add_preset = nullptr;
Button *duplicate_preset = nullptr;
Button *delete_preset = nullptr;
ItemList *presets = nullptr;
LineEdit *name = nullptr;
EditorPropertyPath *export_path = nullptr;
EditorInspector *parameters = nullptr;
CheckButton *runnable = nullptr;
CheckButton *advanced_options = nullptr;
Button *button_export = nullptr;
bool updating = false;
RichTextLabel *result_dialog_log = nullptr;
AcceptDialog *result_dialog = nullptr;
ConfirmationDialog *delete_confirm = nullptr;
OptionButton *export_filter = nullptr;
LineEdit *include_filters = nullptr;
LineEdit *exclude_filters = nullptr;
Tree *include_files = nullptr;
Label *server_strip_message = nullptr;
PopupMenu *file_mode_popup = nullptr;
Label *include_label = nullptr;
MarginContainer *include_margin = nullptr;
Button *export_button = nullptr;
Button *export_all_button = nullptr;
AcceptDialog *export_all_dialog = nullptr;
RBSet<String> feature_set;
LineEdit *custom_features = nullptr;
RichTextLabel *custom_feature_display = nullptr;
LineEdit *script_key = nullptr;
Label *script_key_error = nullptr;
ProjectExportTextureFormatError *export_texture_format_error = nullptr;
Label *export_error = nullptr;
Label *export_warning = nullptr;
HBoxContainer *export_templates_error = nullptr;
String default_filename;
bool exporting = false;
void _advanced_options_pressed();
void _runnable_pressed();
void _update_parameters(const String &p_edited_property);
void _name_changed(const String &p_string);
void _export_path_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing);
void _add_preset(int p_platform);
void _edit_preset(int p_index);
void _duplicate_preset();
void _delete_preset();
void _delete_preset_confirm();
void _update_export_all();
void _force_update_current_preset_parameters();
void _update_current_preset();
void _update_presets();
void _export_type_changed(int p_which);
void _filter_changed(const String &p_filter);
String _get_resource_export_header(EditorExportPreset::ExportFilter p_filter) const;
void _fill_resource_tree();
void _setup_item_for_file_mode(TreeItem *p_item, EditorExportPreset::FileExportMode p_mode);
bool _fill_tree(EditorFileSystemDirectory *p_dir, TreeItem *p_item, Ref<EditorExportPreset> &current, EditorExportPreset::ExportFilter p_export_filter);
void _propagate_file_export_mode(TreeItem *p_item, EditorExportPreset::FileExportMode p_inherited_export_mode);
void _tree_changed();
void _check_propagated_to_item(Object *p_obj, int column);
void _tree_popup_edited(bool p_arrow_clicked);
void _set_file_export_mode(int p_id);
Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
EditorFileDialog *export_pck_zip = nullptr;
EditorFileDialog *export_project = nullptr;
CheckButton *enc_pck = nullptr;
CheckButton *enc_directory = nullptr;
LineEdit *enc_in_filters = nullptr;
LineEdit *enc_ex_filters = nullptr;
OptionButton *script_mode = nullptr;
void _open_export_template_manager();
void _export_pck_zip();
void _export_pck_zip_selected(const String &p_path);
void _validate_export_path(const String &p_path);
void _export_project();
void _export_project_to_path(const String &p_path);
void _export_all_dialog();
void _export_all_dialog_action(const String &p_str);
void _export_all(bool p_debug);
void _update_feature_list();
void _custom_features_changed(const String &p_text);
bool updating_script_key = false;
bool updating_enc_filters = false;
void _enc_pck_changed(bool p_pressed);
void _enc_directory_changed(bool p_pressed);
void _enc_filters_changed(const String &p_text);
void _script_encryption_key_changed(const String &p_key);
bool _validate_script_encryption_key(const String &p_key);
void _script_export_mode_changed(int p_mode);
void _open_key_help_link();
void _tab_changed(int);
protected:
void _notification(int p_what);
static void _bind_methods();
public:
void popup_export();
void set_export_path(const String &p_value);
String get_export_path();
Ref<EditorExportPreset> get_current_preset() const;
bool is_exporting() const { return exporting; };
ProjectExportDialog();
~ProjectExportDialog();
};
#endif // PROJECT_EXPORT_H