Browse Source

[macOS/iOS] Use framework Info.plist to determine library name.

bruvzg 2 years ago
parent
commit
104258c5c5

+ 2 - 0
platform/ios/os_ios.h

@@ -77,6 +77,8 @@ private:
 	CGFloat _stretch_to_ct(int p_stretch) const;
 	CGFloat _stretch_to_ct(int p_stretch) const;
 	String _get_default_fontname(const String &p_font_name) 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();
 	void deinitialize_modules();
 
 
 public:
 public:

+ 44 - 1
platform/ios/os_ios.mm

@@ -198,8 +198,31 @@ void OS_IOS::finalize() {
 
 
 // MARK: Dynamic Libraries
 // 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) {
 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) {
 	if (p_path.length() == 0) {
+		// Static xcframework.
 		p_library_handle = RTLD_SELF;
 		p_library_handle = RTLD_SELF;
 
 
 		if (r_resolved_path != nullptr) {
 		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 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) {
 Error OS_IOS::close_dynamic_library(void *p_library_handle) {

+ 287 - 3
platform/macos/export/plist.cpp

@@ -30,6 +30,119 @@
 
 
 #include "plist.h"
 #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> PListNode::new_array() {
 	Ref<PListNode> node = memnew(PListNode());
 	Ref<PListNode> node = memnew(PListNode());
 	ERR_FAIL_COND_V(node.is_null(), Ref<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>());
 	ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
 	node->data_type = PList::PLNodeType::PL_NODE_TYPE_DATE;
 	node->data_type = PList::PLNodeType::PL_NODE_TYPE_DATE;
 	node->data_string = p_string.utf8();
 	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;
 	return node;
 }
 }
 
 
@@ -76,7 +190,7 @@ Ref<PListNode> PListNode::new_bool(bool p_bool) {
 	return node;
 	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());
 	Ref<PListNode> node = memnew(PListNode());
 	ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
 	ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
 	node->data_type = PList::PLNodeType::PL_NODE_TYPE_INTEGER;
 	node->data_type = PList::PLNodeType::PL_NODE_TYPE_INTEGER;
@@ -84,7 +198,7 @@ Ref<PListNode> PListNode::new_int(int32_t p_int) {
 	return node;
 	return node;
 }
 }
 
 
-Ref<PListNode> PListNode::new_real(float p_real) {
+Ref<PListNode> PListNode::new_real(double p_real) {
 	Ref<PListNode> node = memnew(PListNode());
 	Ref<PListNode> node = memnew(PListNode());
 	ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
 	ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
 	node->data_type = PList::PLNodeType::PL_NODE_TYPE_REAL;
 	node->data_type = PList::PLNodeType::PL_NODE_TYPE_REAL;
@@ -337,6 +451,168 @@ PList::PList(const String &p_string) {
 	load_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) {
 bool PList::load_file(const String &p_filename) {
 	root = Ref<PListNode>();
 	root = Ref<PListNode>();
 
 
@@ -349,7 +625,15 @@ bool PList::load_file(const String &p_filename) {
 	fb->get_buffer(magic, 8);
 	fb->get_buffer(magic, 8);
 
 
 	if (String((const char *)magic, 8) == "bplist00") {
 	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 {
 	} else {
 		// Load text plist.
 		// Load text plist.
 		Error err;
 		Error err;

+ 21 - 4
platform/macos/export/plist.h

@@ -35,6 +35,7 @@
 
 
 #include "core/crypto/crypto_core.h"
 #include "core/crypto/crypto_core.h"
 #include "core/io/file_access.h"
 #include "core/io/file_access.h"
+#include "core/os/time.h"
 
 
 class PListNode;
 class PListNode;
 
 
@@ -55,8 +56,20 @@ public:
 	};
 	};
 
 
 private:
 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;
 	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:
 public:
 	PList();
 	PList();
 	PList(const String &p_string);
 	PList(const String &p_string);
@@ -82,19 +95,23 @@ public:
 	Vector<Ref<PListNode>> data_array;
 	Vector<Ref<PListNode>> data_array;
 	HashMap<String, Ref<PListNode>> data_dict;
 	HashMap<String, Ref<PListNode>> data_dict;
 	union {
 	union {
-		int32_t data_int;
+		int64_t data_int;
 		bool data_bool;
 		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_array();
 	static Ref<PListNode> new_dict();
 	static Ref<PListNode> new_dict();
 	static Ref<PListNode> new_string(const String &p_string);
 	static Ref<PListNode> new_string(const String &p_string);
 	static Ref<PListNode> new_data(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_date(const String &p_string);
 	static Ref<PListNode> new_bool(bool p_bool);
 	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 = "");
 	bool push_subnode(const Ref<PListNode> &p_node, const String &p_key = "");
 
 

+ 22 - 10
platform/macos/os_macos.mm

@@ -45,16 +45,6 @@
 #include <os/log.h>
 #include <os/log.h>
 #include <sys/sysctl.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) {
 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.
 	// 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.
 	// 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) {
 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);
 	String path = get_framework_executable(p_path);