1/*************************************************************************/
2/*  ios_support.mm                                                       */
3/*************************************************************************/
4/*                       This file is part of:                           */
5/*                           GODOT ENGINE                                */
6/*                      https://godotengine.org                          */
7/*************************************************************************/
8/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
9/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
10/*                                                                       */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the       */
13/* "Software"), to deal in the Software without restriction, including   */
14/* without limitation the rights to use, copy, modify, merge, publish,   */
15/* distribute, sublicense, and/or sell copies of the Software, and to    */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions:                                             */
18/*                                                                       */
19/* The above copyright notice and this permission notice shall be        */
20/* included in all copies or substantial portions of the Software.       */
21/*                                                                       */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29/*************************************************************************/
30
31#include "ios_support.h"
32
33#if defined(IPHONE_ENABLED)
34
35#import <Foundation/Foundation.h>
36#include <os/log.h>
37
38#include "core/ustring.h"
39
40#include "../gd_mono_marshal.h"
41
42// Implemented mostly following: https://github.com/mono/mono/blob/master/sdks/ios/app/runtime.m
43
44// Definition generated by the Godot exporter
45extern "C" void gd_mono_setup_aot();
46
47namespace gdmono {
48namespace ios {
49namespace support {
50
51void ios_mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) {
52	os_log_info(OS_LOG_DEFAULT, "(%s %s) %s", log_domain, log_level, message);
53	if (fatal) {
54		os_log_info(OS_LOG_DEFAULT, "Exit code: %d.", 1);
55		exit(1);
56	}
57}
58
59void initialize() {
60	mono_dllmap_insert(NULL, "System.Native", NULL, "__Internal", NULL);
61	mono_dllmap_insert(NULL, "System.IO.Compression.Native", NULL, "__Internal", NULL);
62	mono_dllmap_insert(NULL, "System.Security.Cryptography.Native.Apple", NULL, "__Internal", NULL);
63
64#ifdef IOS_DEVICE
65	// This function is defined in an auto-generated source file
66	gd_mono_setup_aot();
67#endif
68
69	mono_set_signal_chaining(true);
70	mono_set_crash_chaining(true);
71}
72
73void cleanup() {
74}
75
76} // namespace support
77} // namespace ios
78} // namespace gdmono
79
80// The following are P/Invoke functions required by the monotouch profile of the BCL.
81// These are P/Invoke functions and not internal calls, hence why they use
82// 'mono_bool' and 'const char*' instead of 'MonoBoolean' and 'MonoString*'.
83
84#define GD_PINVOKE_EXPORT extern "C" __attribute__((visibility("default")))
85
86GD_PINVOKE_EXPORT const char *xamarin_get_locale_country_code() {
87	NSLocale *locale = [NSLocale currentLocale];
88	NSString *countryCode = [locale objectForKey:NSLocaleCountryCode];
89	if (countryCode == NULL) {
90		return strdup("US");
91	}
92	return strdup([countryCode UTF8String]);
93}
94
95GD_PINVOKE_EXPORT void xamarin_log(const uint16_t *p_unicode_message) {
96	int length = 0;
97	const uint16_t *ptr = p_unicode_message;
98	while (*ptr++)
99		length += sizeof(uint16_t);
100	NSString *msg = [[NSString alloc] initWithBytes:p_unicode_message length:length encoding:NSUTF16LittleEndianStringEncoding];
101
102	os_log_info(OS_LOG_DEFAULT, "%{public}@", msg);
103}
104
105GD_PINVOKE_EXPORT const char *xamarin_GetFolderPath(int p_folder) {
106	NSSearchPathDirectory dd = (NSSearchPathDirectory)p_folder;
107	NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:dd inDomains:NSUserDomainMask] lastObject];
108	NSString *path = [url path];
109	return strdup([path UTF8String]);
110}
111
112GD_PINVOKE_EXPORT char *xamarin_timezone_get_local_name() {
113	NSTimeZone *tz = nil;
114	tz = [NSTimeZone localTimeZone];
115	NSString *name = [tz name];
116	return (name != nil) ? strdup([name UTF8String]) : strdup("Local");
117}
118
119GD_PINVOKE_EXPORT char **xamarin_timezone_get_names(uint32_t *p_count) {
120	NSArray *array = [NSTimeZone knownTimeZoneNames];
121	*p_count = array.count;
122	char **result = (char **)malloc(sizeof(char *) * (*p_count));
123	for (uint32_t i = 0; i < *p_count; i++) {
124		NSString *s = [array objectAtIndex:i];
125		result[i] = strdup(s.UTF8String);
126	}
127	return result;
128}
129
130GD_PINVOKE_EXPORT void *xamarin_timezone_get_data(const char *p_name, uint32_t *p_size) { // FIXME: uint32_t since Dec 2019, unsigned long before
131	NSTimeZone *tz = nil;
132	if (p_name) {
133		NSString *n = [[NSString alloc] initWithUTF8String:p_name];
134		tz = [[[NSTimeZone alloc] initWithName:n] autorelease];
135		[n release];
136	} else {
137		tz = [NSTimeZone localTimeZone];
138	}
139	NSData *data = [tz data];
140	*p_size = [data length];
141	void *result = malloc(*p_size);
142	memcpy(result, data.bytes, *p_size);
143	return result;
144}
145
146GD_PINVOKE_EXPORT void xamarin_start_wwan(const char *p_uri) {
147	// FIXME: What's this for? No idea how to implement.
148	os_log_error(OS_LOG_DEFAULT, "Not implemented: 'xamarin_start_wwan'");
149}
150
151#endif // IPHONE_ENABLED
152