Merge pull request #69477 from bruvzg/bplist_and_fwrk

[macOS/iOS] Use framework Info.plist to determine library name.
This commit is contained in:
Rémi Verschelde 2022-12-16 13:48:02 +01:00
commit 2e657e51f8
No known key found for this signature in database
GPG Key ID: C3336907360768E1
5 changed files with 376 additions and 18 deletions

View File

@ -77,6 +77,8 @@ private:
CGFloat _stretch_to_ct(int p_stretch) const;
String _get_default_fontname(const String &p_font_name) const;
static _FORCE_INLINE_ String get_framework_executable(const String &p_path);
void deinitialize_modules();
public:

View File

@ -198,8 +198,31 @@ void OS_IOS::finalize() {
// MARK: Dynamic Libraries
_FORCE_INLINE_ String OS_IOS::get_framework_executable(const String &p_path) {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
// Read framework bundle to get executable name.
NSURL *url = [NSURL fileURLWithPath:@(p_path.utf8().get_data())];
NSBundle *bundle = [NSBundle bundleWithURL:url];
if (bundle) {
String exe_path = String::utf8([[bundle executablePath] UTF8String]);
if (da->file_exists(exe_path)) {
return exe_path;
}
}
// Try default executable name (invalid framework).
if (da->dir_exists(p_path) && da->file_exists(p_path.path_join(p_path.get_file().get_basename()))) {
return p_path.path_join(p_path.get_file().get_basename());
}
// Not a framework, try loading as .dylib.
return p_path;
}
Error OS_IOS::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) {
if (p_path.length() == 0) {
// Static xcframework.
p_library_handle = RTLD_SELF;
if (r_resolved_path != nullptr) {
@ -208,7 +231,27 @@ Error OS_IOS::open_dynamic_library(const String p_path, void *&p_library_handle,
return OK;
}
return OS_Unix::open_dynamic_library(p_path, p_library_handle, p_also_set_library_path, r_resolved_path);
String path = get_framework_executable(p_path);
if (!FileAccess::exists(path)) {
// Load .dylib or framework from within the executable path.
path = get_framework_executable(get_executable_path().get_base_dir().path_join(p_path.get_file()));
}
if (!FileAccess::exists(path)) {
// Load .dylib or framework from a standard iOS location.
path = get_framework_executable(get_executable_path().get_base_dir().path_join("Frameworks").path_join(p_path.get_file()));
}
p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + dlerror() + ".");
if (r_resolved_path != nullptr) {
*r_resolved_path = path;
}
return OK;
}
Error OS_IOS::close_dynamic_library(void *p_library_handle) {

View File

@ -30,6 +30,119 @@
#include "plist.h"
PList::PLNodeType PListNode::get_type() const {
return data_type;
}
Variant PListNode::get_value() const {
switch (data_type) {
case PList::PL_NODE_TYPE_NIL: {
return Variant();
} break;
case PList::PL_NODE_TYPE_STRING: {
return String::utf8(data_string.get_data());
} break;
case PList::PL_NODE_TYPE_ARRAY: {
Array arr;
for (const Ref<PListNode> &E : data_array) {
arr.push_back(E);
}
return arr;
} break;
case PList::PL_NODE_TYPE_DICT: {
Dictionary dict;
for (const KeyValue<String, Ref<PListNode>> &E : data_dict) {
dict[E.key] = E.value;
}
return dict;
} break;
case PList::PL_NODE_TYPE_BOOLEAN: {
return data_bool;
} break;
case PList::PL_NODE_TYPE_INTEGER: {
return data_int;
} break;
case PList::PL_NODE_TYPE_REAL: {
return data_real;
} break;
case PList::PL_NODE_TYPE_DATA: {
int strlen = data_string.length();
size_t arr_len = 0;
Vector<uint8_t> buf;
{
buf.resize(strlen / 4 * 3 + 1);
uint8_t *w = buf.ptrw();
ERR_FAIL_COND_V(CryptoCore::b64_decode(&w[0], buf.size(), &arr_len, (unsigned char *)data_string.get_data(), strlen) != OK, Vector<uint8_t>());
}
buf.resize(arr_len);
return buf;
} break;
case PList::PL_NODE_TYPE_DATE: {
return String(data_string.get_data());
} break;
}
return Variant();
}
Ref<PListNode> PListNode::new_node(const Variant &p_value) {
Ref<PListNode> node;
node.instantiate();
switch (p_value.get_type()) {
case Variant::NIL: {
node->data_type = PList::PL_NODE_TYPE_NIL;
} break;
case Variant::BOOL: {
node->data_type = PList::PL_NODE_TYPE_BOOLEAN;
node->data_bool = p_value;
} break;
case Variant::INT: {
node->data_type = PList::PL_NODE_TYPE_INTEGER;
node->data_int = p_value;
} break;
case Variant::FLOAT: {
node->data_type = PList::PL_NODE_TYPE_REAL;
node->data_real = p_value;
} break;
case Variant::STRING_NAME:
case Variant::STRING: {
node->data_type = PList::PL_NODE_TYPE_STRING;
node->data_string = p_value.operator String().utf8();
} break;
case Variant::DICTIONARY: {
node->data_type = PList::PL_NODE_TYPE_DICT;
Dictionary dict = p_value;
const Variant *next = dict.next(nullptr);
while (next) {
Ref<PListNode> sub_node = dict[*next];
ERR_FAIL_COND_V_MSG(sub_node.is_null(), Ref<PListNode>(), "Invalid dictionary element, should be PListNode.");
node->data_dict[*next] = sub_node;
next = dict.next(next);
}
} break;
case Variant::ARRAY: {
node->data_type = PList::PL_NODE_TYPE_ARRAY;
Array ar = p_value;
for (int i = 0; i < ar.size(); i++) {
Ref<PListNode> sub_node = ar[i];
ERR_FAIL_COND_V_MSG(sub_node.is_null(), Ref<PListNode>(), "Invalid array element, should be PListNode.");
node->data_array.push_back(sub_node);
}
} break;
case Variant::PACKED_BYTE_ARRAY: {
node->data_type = PList::PL_NODE_TYPE_DATA;
PackedByteArray buf = p_value;
node->data_string = CryptoCore::b64_encode_str(buf.ptr(), buf.size()).utf8();
} break;
default: {
ERR_FAIL_V_MSG(Ref<PListNode>(), "Unsupported data type.");
} break;
}
return node;
}
Ref<PListNode> PListNode::new_array() {
Ref<PListNode> node = memnew(PListNode());
ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
@ -65,6 +178,7 @@ Ref<PListNode> PListNode::new_date(const String &p_string) {
ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
node->data_type = PList::PLNodeType::PL_NODE_TYPE_DATE;
node->data_string = p_string.utf8();
node->data_real = (double)Time::get_singleton()->get_unix_time_from_datetime_string(p_string) - 978307200.0;
return node;
}
@ -76,7 +190,7 @@ Ref<PListNode> PListNode::new_bool(bool p_bool) {
return node;
}
Ref<PListNode> PListNode::new_int(int32_t p_int) {
Ref<PListNode> PListNode::new_int(int64_t p_int) {
Ref<PListNode> node = memnew(PListNode());
ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
node->data_type = PList::PLNodeType::PL_NODE_TYPE_INTEGER;
@ -84,7 +198,7 @@ Ref<PListNode> PListNode::new_int(int32_t p_int) {
return node;
}
Ref<PListNode> PListNode::new_real(float p_real) {
Ref<PListNode> PListNode::new_real(double p_real) {
Ref<PListNode> node = memnew(PListNode());
ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
node->data_type = PList::PLNodeType::PL_NODE_TYPE_REAL;
@ -337,6 +451,168 @@ PList::PList(const String &p_string) {
load_string(p_string);
}
uint64_t PList::read_bplist_var_size_int(Ref<FileAccess> p_file, uint8_t p_size) {
uint64_t pos = p_file->get_position();
uint64_t ret = 0;
switch (p_size) {
case 1: {
ret = p_file->get_8();
} break;
case 2: {
ret = BSWAP16(p_file->get_16());
} break;
case 3: {
ret = BSWAP32(p_file->get_32() & 0x00FFFFFF);
} break;
case 4: {
ret = BSWAP32(p_file->get_32());
} break;
case 5: {
ret = BSWAP64(p_file->get_64() & 0x000000FFFFFFFFFF);
} break;
case 6: {
ret = BSWAP64(p_file->get_64() & 0x0000FFFFFFFFFFFF);
} break;
case 7: {
ret = BSWAP64(p_file->get_64() & 0x00FFFFFFFFFFFFFF);
} break;
case 8: {
ret = BSWAP64(p_file->get_64());
} break;
default: {
ret = 0;
}
}
p_file->seek(pos + p_size);
return ret;
}
Ref<PListNode> PList::read_bplist_obj(Ref<FileAccess> p_file, uint64_t p_offset_idx) {
Ref<PListNode> node;
node.instantiate();
uint64_t ot_off = trailer.offset_table_start + p_offset_idx * trailer.offset_size;
p_file->seek(ot_off);
uint64_t marker_off = read_bplist_var_size_int(p_file, trailer.offset_size);
ERR_FAIL_COND_V_MSG(marker_off == 0, Ref<PListNode>(), "Invalid marker size.");
p_file->seek(marker_off);
uint8_t marker = p_file->get_8();
uint8_t marker_type = marker & 0xF0;
uint64_t marker_size = marker & 0x0F;
switch (marker_type) {
case 0x00: {
if (marker_size == 0x00) {
node->data_type = PL_NODE_TYPE_NIL;
} else if (marker_size == 0x08) {
node->data_type = PL_NODE_TYPE_BOOLEAN;
node->data_bool = false;
} else if (marker_size == 0x09) {
node->data_type = PL_NODE_TYPE_BOOLEAN;
node->data_bool = true;
} else {
ERR_FAIL_V_MSG(Ref<PListNode>(), "Invalid nil/bool marker value.");
}
} break;
case 0x10: {
node->data_type = PL_NODE_TYPE_INTEGER;
node->data_int = static_cast<int64_t>(read_bplist_var_size_int(p_file, pow(2, marker_size)));
} break;
case 0x20: {
node->data_type = PL_NODE_TYPE_REAL;
node->data_int = static_cast<int64_t>(read_bplist_var_size_int(p_file, pow(2, marker_size)));
} break;
case 0x30: {
node->data_type = PL_NODE_TYPE_DATE;
node->data_int = BSWAP64(p_file->get_64());
node->data_string = Time::get_singleton()->get_datetime_string_from_unix_time(node->data_real + 978307200.0).utf8();
} break;
case 0x40: {
if (marker_size == 0x0F) {
uint8_t ext = p_file->get_8() & 0xF;
marker_size = read_bplist_var_size_int(p_file, pow(2, ext));
}
node->data_type = PL_NODE_TYPE_DATA;
PackedByteArray buf;
buf.resize(marker_size + 1);
p_file->get_buffer(reinterpret_cast<uint8_t *>(buf.ptrw()), marker_size);
node->data_string = CryptoCore::b64_encode_str(buf.ptr(), buf.size()).utf8();
} break;
case 0x50: {
if (marker_size == 0x0F) {
uint8_t ext = p_file->get_8() & 0xF;
marker_size = read_bplist_var_size_int(p_file, pow(2, ext));
}
node->data_type = PL_NODE_TYPE_STRING;
node->data_string.resize(marker_size + 1);
p_file->get_buffer(reinterpret_cast<uint8_t *>(node->data_string.ptrw()), marker_size);
} break;
case 0x60: {
if (marker_size == 0x0F) {
uint8_t ext = p_file->get_8() & 0xF;
marker_size = read_bplist_var_size_int(p_file, pow(2, ext));
}
Char16String cs16;
cs16.resize(marker_size + 1);
for (uint64_t i = 0; i < marker_size; i++) {
cs16[i] = BSWAP16(p_file->get_16());
}
node->data_type = PL_NODE_TYPE_STRING;
node->data_string = String::utf16(cs16.ptr(), cs16.length()).utf8();
} break;
case 0x80: {
node->data_type = PL_NODE_TYPE_INTEGER;
node->data_int = static_cast<int64_t>(read_bplist_var_size_int(p_file, marker_size + 1));
} break;
case 0xA0:
case 0xC0: {
if (marker_size == 0x0F) {
uint8_t ext = p_file->get_8() & 0xF;
marker_size = read_bplist_var_size_int(p_file, pow(2, ext));
}
uint64_t pos = p_file->get_position();
node->data_type = PL_NODE_TYPE_ARRAY;
for (uint64_t i = 0; i < marker_size; i++) {
p_file->seek(pos + trailer.ref_size * i);
uint64_t ref = read_bplist_var_size_int(p_file, trailer.ref_size);
Ref<PListNode> element = read_bplist_obj(p_file, ref);
ERR_FAIL_COND_V(element.is_null(), Ref<PListNode>());
node->data_array.push_back(element);
}
} break;
case 0xD0: {
if (marker_size == 0x0F) {
uint8_t ext = p_file->get_8() & 0xF;
marker_size = read_bplist_var_size_int(p_file, pow(2, ext));
}
uint64_t pos = p_file->get_position();
node->data_type = PL_NODE_TYPE_DICT;
for (uint64_t i = 0; i < marker_size; i++) {
p_file->seek(pos + trailer.ref_size * i);
uint64_t key_ref = read_bplist_var_size_int(p_file, trailer.ref_size);
p_file->seek(pos + trailer.ref_size * (i + marker_size));
uint64_t obj_ref = read_bplist_var_size_int(p_file, trailer.ref_size);
Ref<PListNode> element_key = read_bplist_obj(p_file, key_ref);
ERR_FAIL_COND_V(element_key.is_null() || element_key->data_type != PL_NODE_TYPE_STRING, Ref<PListNode>());
Ref<PListNode> element = read_bplist_obj(p_file, obj_ref);
ERR_FAIL_COND_V(element.is_null(), Ref<PListNode>());
node->data_dict[String::utf8(element_key->data_string.ptr(), element_key->data_string.length())] = element;
}
} break;
default: {
ERR_FAIL_V_MSG(Ref<PListNode>(), "Invalid marker type.");
}
}
return node;
}
bool PList::load_file(const String &p_filename) {
root = Ref<PListNode>();
@ -349,7 +625,15 @@ bool PList::load_file(const String &p_filename) {
fb->get_buffer(magic, 8);
if (String((const char *)magic, 8) == "bplist00") {
ERR_FAIL_V_MSG(false, "PList: Binary property lists are not supported.");
fb->seek_end(-26);
trailer.offset_size = fb->get_8();
trailer.ref_size = fb->get_8();
trailer.object_num = BSWAP64(fb->get_64());
trailer.root_offset_idx = BSWAP64(fb->get_64());
trailer.offset_table_start = BSWAP64(fb->get_64());
root = read_bplist_obj(fb, trailer.root_offset_idx);
return root.is_valid();
} else {
// Load text plist.
Error err;

View File

@ -35,6 +35,7 @@
#include "core/crypto/crypto_core.h"
#include "core/io/file_access.h"
#include "core/os/time.h"
class PListNode;
@ -55,8 +56,20 @@ public:
};
private:
struct PListTrailer {
uint8_t offset_size;
uint8_t ref_size;
uint64_t object_num;
uint64_t root_offset_idx;
uint64_t offset_table_start;
};
PListTrailer trailer;
Ref<PListNode> root;
uint64_t read_bplist_var_size_int(Ref<FileAccess> p_file, uint8_t p_size);
Ref<PListNode> read_bplist_obj(Ref<FileAccess> p_file, uint64_t p_offset_idx);
public:
PList();
PList(const String &p_string);
@ -82,19 +95,23 @@ public:
Vector<Ref<PListNode>> data_array;
HashMap<String, Ref<PListNode>> data_dict;
union {
int32_t data_int;
int64_t data_int;
bool data_bool;
float data_real;
double data_real;
};
PList::PLNodeType get_type() const;
Variant get_value() const;
static Ref<PListNode> new_node(const Variant &p_value);
static Ref<PListNode> new_array();
static Ref<PListNode> new_dict();
static Ref<PListNode> new_string(const String &p_string);
static Ref<PListNode> new_data(const String &p_string);
static Ref<PListNode> new_date(const String &p_string);
static Ref<PListNode> new_bool(bool p_bool);
static Ref<PListNode> new_int(int32_t p_int);
static Ref<PListNode> new_real(float p_real);
static Ref<PListNode> new_int(int64_t p_int);
static Ref<PListNode> new_real(double p_real);
bool push_subnode(const Ref<PListNode> &p_node, const String &p_key = "");

View File

@ -45,16 +45,6 @@
#include <os/log.h>
#include <sys/sysctl.h>
_FORCE_INLINE_ String OS_MacOS::get_framework_executable(const String &p_path) {
// Append framework executable name, or return as is if p_path is not a framework.
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (da->dir_exists(p_path) && da->file_exists(p_path.path_join(p_path.get_file().get_basename()))) {
return p_path.path_join(p_path.get_file().get_basename());
} else {
return p_path;
}
}
void OS_MacOS::pre_wait_observer_cb(CFRunLoopObserverRef p_observer, CFRunLoopActivity p_activiy, void *p_context) {
// Prevent main loop from sleeping and redraw window during modal popup display.
// Do not redraw when rendering is done from the separate thread, it will conflict with the OpenGL context updates.
@ -162,6 +152,28 @@ void OS_MacOS::alert(const String &p_alert, const String &p_title) {
}
}
_FORCE_INLINE_ String OS_MacOS::get_framework_executable(const String &p_path) {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
// Read framework bundle to get executable name.
NSURL *url = [NSURL fileURLWithPath:@(p_path.utf8().get_data())];
NSBundle *bundle = [NSBundle bundleWithURL:url];
if (bundle) {
String exe_path = String::utf8([[bundle executablePath] UTF8String]);
if (da->file_exists(exe_path)) {
return exe_path;
}
}
// Try default executable name (invalid framework).
if (da->dir_exists(p_path) && da->file_exists(p_path.path_join(p_path.get_file().get_basename()))) {
return p_path.path_join(p_path.get_file().get_basename());
}
// Not a framework, try loading as .dylib.
return p_path;
}
Error OS_MacOS::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) {
String path = get_framework_executable(p_path);