XenonSDK-Load.m 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. //
  2. // XenonSDK-Load.m
  3. // XenonSDK
  4. //
  5. // Created by SAGESSE on 2019/3/11.
  6. // Copyright © 2019 SAGESSE. All rights reserved.
  7. //
  8. #import <UIKit/UIKit.h>
  9. #import <objc/runtime.h>
  10. /// Load the file from the Forwarder.
  11. id sdk_load_mapper = nil;
  12. id sdk_load_root = nil;
  13. //unsigned char* sdk_load_data(const char* name, const char* mode, size_t* osize) {
  14. //
  15. // printf("loader: %s - %s\n", name, mode);
  16. //
  17. // FILE* fp = fopen(name, mode);
  18. //
  19. // if (fp == nil) {
  20. // *osize = 0;
  21. // return nil;
  22. // }
  23. //
  24. // fseek(fp,0,SEEK_END);
  25. // ssize_t size = ftell(fp);
  26. // fseek(fp,0,SEEK_SET);
  27. //
  28. // unsigned char* buffer = malloc(size + 1);
  29. // size_t readed = fread(buffer, 1, size, fp);
  30. //
  31. // if (readed >= 0) {
  32. // buffer[readed] = '\0';
  33. // }
  34. //
  35. // *osize = readed;
  36. // fclose(fp);
  37. // return buffer;
  38. //}
  39. //// Register methods with NSFileManager.
  40. //@implementation NSFileManager (XenonSDK)
  41. //
  42. //- (BOOL)sdk_fileExistsAtPath:(NSString*)path {
  43. // //printf("chcker: %s\n", path.UTF8String);;
  44. //
  45. // // Find the path after removing the bundle.
  46. // if (sdk_load_root != nil ) {
  47. // NSString* root = NSBundle.mainBundle.bundlePath;
  48. // if ([path hasPrefix:root]) {
  49. // NSString* relative = [path stringByReplacingOccurrencesOfString:root withString:@""];
  50. // NSDictionary* descriptor = [sdk_load_mapper objectForKeyedSubscript:relative];
  51. // if (descriptor != nil) {
  52. // relative = [descriptor objectForKeyedSubscript:@"path"];
  53. // path = [sdk_load_root stringByAppendingPathComponent: relative];
  54. // }
  55. // }
  56. // }
  57. //
  58. // return [self sdk_fileExistsAtPath:path];
  59. //}
  60. //
  61. //@end
  62. // Register methods with NSBundle.
  63. @implementation NSBundle (XenonSDK)
  64. + (void)load {
  65. // Load mapper.
  66. NSURL* url = [NSBundle.mainBundle.executableURL URLByAppendingPathExtension:@"plist"];
  67. NSDictionary* mapper = [NSDictionary dictionaryWithContentsOfURL:url];
  68. // If the mapper file fails to load, ignore it.
  69. if (mapper == nil) {
  70. return;
  71. }
  72. // Save the map table.
  73. sdk_load_mapper = mapper;
  74. // Check if the app is unity project.
  75. if ([mapper[@"*"] isEqual:@"u"] || [mapper[@"*"] isEqual:@"k"]) {
  76. NSString* realBundlePath = NSBundle.mainBundle.bundlePath;
  77. NSString* linkBundlePath = [[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSAllDomainsMask, YES) firstObject] stringByAppendingPathComponent:realBundlePath.lastPathComponent];
  78. NSError* error = nil;
  79. NSFileManager* fileManager = [NSFileManager defaultManager];
  80. // The relink each time to prevent changes.
  81. [fileManager removeItemAtPath:linkBundlePath error:&error];
  82. [fileManager createDirectoryAtPath:linkBundlePath withIntermediateDirectories:YES attributes:nil error:&error];
  83. // Create the connection file the first time you install it.
  84. [mapper enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, NSDictionary* obj, BOOL * _Nonnull stop) {
  85. if ([key isEqual:@"*"]) {
  86. return;
  87. }
  88. NSString* src = [realBundlePath stringByAppendingPathComponent:obj[@"path"]];
  89. NSString* dest = [linkBundlePath stringByAppendingPathComponent:key];
  90. BOOL isDirectory = NO;
  91. NSError* suberror = nil;
  92. // If the file does not exist, ignore it.
  93. if (![fileManager fileExistsAtPath:src isDirectory:&isDirectory]) {
  94. return ;
  95. }
  96. // If this is a directory file, create it directly.
  97. if (isDirectory) {
  98. [fileManager createDirectoryAtPath:dest withIntermediateDirectories:YES attributes:nil error:&suberror];
  99. return;
  100. }
  101. // Check that the root directory exists, and if it does not, create it.
  102. if (![fileManager fileExistsAtPath:dest.stringByDeletingLastPathComponent]) {
  103. [fileManager createDirectoryAtPath:dest.stringByDeletingLastPathComponent withIntermediateDirectories:YES attributes:nil error:&suberror];
  104. }
  105. // Create file a soft link.
  106. [fileManager createSymbolicLinkAtPath:dest withDestinationPath:src error:&suberror];
  107. }];
  108. if ([mapper[@"*"] isEqual:@"k"]) {
  109. sdk_load_root = linkBundlePath;
  110. Method m1 = class_getInstanceMethod(self, @selector(URLForResource:withExtension:subdirectory:));
  111. Method m2 = class_getInstanceMethod(self, @selector(sdk_URLForResource:withExtension:subdirectory:));
  112. method_exchangeImplementations(m1, m2);
  113. // Method m3 = class_getInstanceMethod(NSFileManager.class, @selector(fileExistsAtPath:));
  114. // Method m4 = class_getInstanceMethod(NSFileManager.class, @selector(sdk_fileExistsAtPath:));
  115. // method_exchangeImplementations(m3, m4);
  116. return;
  117. }
  118. // Register with the project class.
  119. Class tmp = objc_allocateClassPair(NSObject.class, "XCBundle", 0);
  120. objc_registerClassPair(tmp);
  121. class_addMethod(objc_getMetaClass("XCBundle"), @selector(bundlePath), imp_implementationWithBlock((id)^{ return linkBundlePath; }), "@:");
  122. return;
  123. }
  124. // Check if the app is cocos project.
  125. if ([mapper[@"*"] isEqual:@"c"]) {
  126. Method m1 = class_getInstanceMethod(self, @selector(URLForResource:withExtension:subdirectory:));
  127. Method m2 = class_getInstanceMethod(self, @selector(sdk_URLForResource:withExtension:subdirectory:));
  128. method_exchangeImplementations(m1, m2);
  129. }
  130. }
  131. - (NSURL*)sdk_URLForResource:(NSString*)resource withExtension:(NSString*)extension subdirectory:(NSString*)subdirectory {
  132. NSString* path = resource;
  133. if (subdirectory != nil) {
  134. path = [subdirectory stringByAppendingPathComponent:path];
  135. }
  136. if (extension != nil) {
  137. path = [path stringByAppendingPathExtension:extension];
  138. }
  139. if (path.length != 0 && [path hasPrefix:@"/"]) {
  140. path = [path substringFromIndex:1];
  141. }
  142. NSDictionary* descriptor = [sdk_load_mapper objectForKeyedSubscript:path];
  143. if (descriptor != nil) {
  144. if (sdk_load_root != nil) {
  145. return [NSURL URLWithString:[sdk_load_root stringByAppendingPathComponent:path]];
  146. }
  147. path = [descriptor objectForKeyedSubscript:@"path"];
  148. if (path != nil) {
  149. return [self sdk_URLForResource:path withExtension:nil subdirectory:nil];
  150. }
  151. }
  152. return [self sdk_URLForResource:resource withExtension:extension subdirectory:subdirectory];
  153. }
  154. @end
  155. //// Register methods with NSObject.
  156. //@implementation NSObject (XenonSDK)
  157. //
  158. //+ (void*)XCForwarderInit {
  159. // printf("loader: init\n");
  160. //
  161. //// Method m1 = class_getInstanceMethod(NSBundle.class, @selector(pathForResource:ofType:inDirectory:));
  162. //// Method m2 = class_getInstanceMethod(NSBundle.class, @selector(sdk_pathForResource:ofType:inDirectory:));
  163. //// method_exchangeImplementations(m1, m2);
  164. //
  165. //// Method m3 = class_getInstanceMethod(NSBundle.class, @selector(fileExistsAtPath:));
  166. //// Method m4 = class_getInstanceMethod(NSBundle.class, @selector(sdk_fileExistsAtPath:));
  167. //// method_exchangeImplementations(m3, m4);
  168. //
  169. //// return &sdk_load_data;
  170. // return nil;
  171. //}
  172. //
  173. //@end