diff --git a/source/funkin/external/apple/FNFCUtil.hx b/source/funkin/external/apple/FNFCUtil.hx index a724c93b6..f55d6102d 100644 --- a/source/funkin/external/apple/FNFCUtil.hx +++ b/source/funkin/external/apple/FNFCUtil.hx @@ -1,12 +1,21 @@ package funkin.external.apple; -#if ios +#if ((ios || macos) && cpp) +/** + * A utility class for FNFC loading on apple devices. + */ @:build(funkin.util.macro.LinkerMacro.xml('project/Build.xml')) @:include('FNFCUtil.hpp') @:unreflective extern class FNFCUtil { - @:native('copyFNFCIntoCache') + /** + * Copies the FNFC resource from the specified URL into the cache. + * + * @param url The URL of the FNFC resource to copy into the cache. + * @param callback A function to be called when the copy operation completes. + */ + @:native('Apple_FNFCUtil_CopyFNFCIntoCache') static function copyFNFCIntoCache(url:cpp.ConstCharStar, callback:cpp.Callable<(event:cpp.ConstCharStar, value:cpp.ConstCharStar) -> Void>):Void; } #end diff --git a/source/funkin/external/apple/project/include/FNFCUtil.hpp b/source/funkin/external/apple/project/include/FNFCUtil.hpp index 9edeaf94c..45f297097 100644 --- a/source/funkin/external/apple/project/include/FNFCUtil.hpp +++ b/source/funkin/external/apple/project/include/FNFCUtil.hpp @@ -1,5 +1,17 @@ #pragma once +/** + * Function pointer type for handling events with associated string values. + * + * @param event The name of the event as a null-terminated string. + * @param value The value associated with the event as a null-terminated string. + */ typedef void (*FNFCCallback)(const char* event, const char* value); -void copyFNFCIntoCache(const char *url, FNFCCallback callback); +/** + * Copies the FNFC resource from the specified URL into the cache. + * + * @param url The URL of the FNFC resource to copy into the cache. + * @param callback A function to be called when the copy operation completes. + */ +void Apple_FNFCUtil_CopyFNFCIntoCache(const char *url, FNFCCallback callback); diff --git a/source/funkin/external/apple/project/src/FNFCUtil.mm b/source/funkin/external/apple/project/src/FNFCUtil.mm index b8352a6b3..6a12f1a26 100644 --- a/source/funkin/external/apple/project/src/FNFCUtil.mm +++ b/source/funkin/external/apple/project/src/FNFCUtil.mm @@ -3,95 +3,130 @@ static FNFCCallback fnfcCallback = nullptr; -void copyFNFCIntoCache(const char *url, FNFCCallback callback) +void Apple_FNFCUtil_CopyFNFCIntoCache(const char *url, FNFCCallback callback) { - if (!fnfcCallback) { - fnfcCallback = callback; + #if TARGET_OS_IOS + if (!fnfcCallback) + { + fnfcCallback = callback; } - if (!url) { - if (fnfcCallback) { - dispatch_async(dispatch_get_main_queue(), ^{ - fnfcCallback("FNFC_URL_NIL", "The URL passed to the conversion was null."); - }); - } + if (!url) + { + if (fnfcCallback) + { + dispatch_async(dispatch_get_main_queue(), ^{ + fnfcCallback("FNFC_URL_NIL", "The URL passed to the conversion was null."); + }); + } + return; } NSString *urlString = [NSString stringWithUTF8String:url]; + NSURL *fileURL = [NSURL URLWithString:urlString]; - if (!fileURL || !fileURL.isFileURL) { + + if (!fileURL || !fileURL.isFileURL) + { fileURL = [NSURL fileURLWithPath:urlString]; } - if (!fileURL || !fileURL.isFileURL) { - if (fnfcCallback) { - dispatch_async(dispatch_get_main_queue(), ^{ - NSString *msg = [NSString stringWithFormat:@"The passed URL '%@' doesn't point at a FNFC file.", urlString]; - fnfcCallback("FNFC_FILE_MISMATC", [msg UTF8String]); - }); - } + if (!fileURL || !fileURL.isFileURL) + { + if (fnfcCallback) + { + dispatch_async(dispatch_get_main_queue(), ^{ + char *msg = strdup([[NSString stringWithFormat:@"The passed URL '%@' doesn't point at a FNFC file.", urlString] UTF8String]); + fnfcCallback("FNFC_FILE_MISMATC", msg); + free(msg); + }); + } + return; } BOOL accessed = [fileURL startAccessingSecurityScopedResource]; - if (!accessed) { - if (fnfcCallback) { - dispatch_async(dispatch_get_main_queue(), ^{ - NSString *msg = [NSString stringWithFormat:@"Failed to get access to URL '%@'.", urlString]; - fnfcCallback("FNFC_FILE_ACCESS_ERR", [msg UTF8String]); - }); - } + + if (!accessed) + { + if (fnfcCallback) + { + dispatch_async(dispatch_get_main_queue(), ^{ + char *msg = strdup([[NSString stringWithFormat:@"Failed to get access to URL '%@'.", urlString] UTF8String]); + fnfcCallback("FNFC_FILE_ACCESS_ERR", msg); + free(msg); + }); + } } NSString *sourcePath = [fileURL path]; + NSString *filename = [sourcePath lastPathComponent]; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + NSString *cacheDir = [[paths firstObject] stringByAppendingPathComponent:@"fnfc"]; NSFileManager *fm = [NSFileManager defaultManager]; + NSError *dirError = nil; - if (![fm fileExistsAtPath:cacheDir]) { - if(![fm createDirectoryAtPath:cacheDir withIntermediateDirectories:YES attributes:nil error:&dirError]) { - if (fnfcCallback) { - dispatch_async(dispatch_get_main_queue(), ^{ - NSString *msg = [NSString stringWithFormat:@"Failed to create directory %@: %@", cacheDir, dirError]; - fnfcCallback("FNFC_DIR_CREATE_ERR", [msg UTF8String]); - }); - } + + if (![fm fileExistsAtPath:cacheDir]) + { + if (![fm createDirectoryAtPath:cacheDir withIntermediateDirectories:YES attributes:nil error:&dirError]) + { + if (fnfcCallback) + { + dispatch_async(dispatch_get_main_queue(), ^{ + char *msg = strdup([[NSString stringWithFormat:@"Failed to create directory %@: %@", cacheDir, dirError] UTF8String]); + fnfcCallback("FNFC_DIR_CREATE_ERR", msg); + free(msg); + }); + } } } NSString *destPath = [cacheDir stringByAppendingPathComponent:filename]; NSError *error = nil; - if ([fm fileExistsAtPath:destPath]) { + + if ([fm fileExistsAtPath:destPath]) + { [fm removeItemAtPath:destPath error:nil]; } - if (![fm copyItemAtPath:sourcePath toPath:destPath error:&error]) { - if (fnfcCallback) { - dispatch_async(dispatch_get_main_queue(), ^{ - NSString *msg = [NSString stringWithFormat:@"Failed to copy FNFC from URL %@ to directory %@: %@", sourcePath, destPath, error]; - fnfcCallback("FNFC_COPY_ERR", [msg UTF8String]); - }); - } - if (accessed) { + if (![fm copyItemAtPath:sourcePath toPath:destPath error:&error]) + { + if (fnfcCallback) + { + dispatch_async(dispatch_get_main_queue(), ^{ + char *msg = strdup([[NSString stringWithFormat:@"Failed to copy FNFC from URL %@ to directory %@: %@", sourcePath, destPath, error] UTF8String]); + fnfcCallback("FNFC_COPY_ERR", msg); + free(msg); + }); + } + + if (accessed) + { [fileURL stopAccessingSecurityScopedResource]; } + return; } - if (accessed) { + if (accessed) + { [fileURL stopAccessingSecurityScopedResource]; } - if (fnfcCallback) { - const char *val = strdup([destPath UTF8String]); - dispatch_async(dispatch_get_main_queue(), ^{ - fnfcCallback("FNFC_RESULTS", val); - free((void *)val); - }); - } + if (fnfcCallback) + { + dispatch_async(dispatch_get_main_queue(), ^{ + char *val = strdup([destPath UTF8String]); + fnfcCallback("FNFC_RESULTS", val); + free(val); + }); + } + #endif }