Advertisement
Guest User

Untitled

a guest
Jun 22nd, 2017
55
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.94 KB | None | 0 0
  1. //
  2. // Licensed under the terms in License.txt
  3. //
  4. // Copyright 2010 Allen Ding. All rights reserved.
  5. //
  6.  
  7. #import "KWIntercept.h"
  8. #import "KWMessagePattern.h"
  9. #import "KWMessageSpying.h"
  10. #import "KWStub.h"
  11.  
  12. static const char * const KWInterceptClassSuffix = "_KWIntercept";
  13. static NSMutableDictionary *KWObjectStubs = nil;
  14. static NSMutableDictionary *KWMessageSpies = nil;
  15.  
  16. #pragma mark -
  17. #pragma mark Intercept Enabled Method Implementations
  18.  
  19. void KWInterceptedForwardInvocation(id anObject, SEL aSelector, NSInvocation* anInvocation);
  20. void KWInterceptedDealloc(id anObject, SEL aSelector);
  21. Class KWInterceptedClass(id anObject, SEL aSelector);
  22. Class KWInterceptedSuperclass(id anObject, SEL aSelector);
  23.  
  24. #pragma mark -
  25. #pragma mark Getting Forwarding Implementations
  26.  
  27. IMP KWRegularForwardingImplementation(void) {
  28. return class_getMethodImplementation([NSObject class], @selector(KWNonExistantSelector));
  29. }
  30.  
  31. IMP KWStretForwardingImplementation(void) {
  32. return class_getMethodImplementation_stret([NSObject class], @selector(KWNonExistantSelector));
  33. }
  34.  
  35. IMP KWForwardingImplementationForMethodEncoding(const char* encoding) {
  36. #if TARGET_CPU_ARM
  37. const NSUInteger stretLengthThreshold = 4;
  38. #elif TARGET_CPU_X86
  39. const NSUInteger stretLengthThreshold = 8;
  40. #else
  41. // TODO: This just makes an assumption right now. Expand to support all
  42. // official architectures correctly.
  43. const NSUInteger stretLengthThreshold = 8;
  44. #endif // #if TARGET_CPU_ARM
  45.  
  46. NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:encoding];
  47.  
  48. if (*[signature methodReturnType] == '{' && [signature methodReturnLength] > stretLengthThreshold) {
  49. NSLog(@"Warning: The Objective-C runtime appears to have bugs when forwarding messages with certain struct layouts as return types, so if a crash occurs this could be the culprit");
  50. return KWStretForwardingImplementation();
  51. } else {
  52. return KWRegularForwardingImplementation();
  53. }
  54. }
  55.  
  56. #pragma mark -
  57. #pragma mark Getting Intercept Class Information
  58.  
  59. BOOL KWObjectIsClass(id anObject) {
  60. return class_isMetaClass(object_getClass(anObject));
  61. }
  62.  
  63. BOOL KWClassIsInterceptClass(Class aClass) {
  64. const char *name = class_getName(aClass);
  65. char *result = strstr(name, KWInterceptClassSuffix);
  66. return result != nil;
  67. }
  68.  
  69. NSString *KWInterceptClassNameForClass(Class aClass) {
  70. const char *className = class_getName(aClass);
  71. return [NSString stringWithFormat:@"%s%s", className, KWInterceptClassSuffix];
  72. }
  73.  
  74. Class KWInterceptClassForCanonicalClass(Class canonicalClass) {
  75. NSString *interceptClassName = KWInterceptClassNameForClass(canonicalClass);
  76. Class interceptClass = NSClassFromString(interceptClassName);
  77.  
  78. if (interceptClass != nil)
  79. return interceptClass;
  80.  
  81. interceptClass = objc_allocateClassPair(canonicalClass, [interceptClassName UTF8String], 0);
  82. objc_registerClassPair(interceptClass);
  83.  
  84. class_addMethod(interceptClass, @selector(forwardInvocation:), (IMP)KWInterceptedForwardInvocation, "v@:@");
  85. class_addMethod(interceptClass, @selector(dealloc), (IMP)KWInterceptedDealloc, "v@:");
  86. class_addMethod(interceptClass, @selector(class), (IMP)KWInterceptedClass, "#@:");
  87. class_addMethod(interceptClass, @selector(superclass), (IMP)KWInterceptedSuperclass, "#@:");
  88.  
  89. Class interceptMetaClass = object_getClass(interceptClass);
  90. class_addMethod(interceptMetaClass, @selector(forwardInvocation:), (IMP)KWInterceptedForwardInvocation, "v@:@");
  91.  
  92. return interceptClass;
  93. }
  94.  
  95. Class KWRealClassForClass(Class aClass) {
  96. if (KWClassIsInterceptClass(aClass))
  97. return [aClass superclass];
  98.  
  99. return aClass;
  100. }
  101.  
  102. #pragma mark -
  103. #pragma mark Enabling Intercepting
  104.  
  105. // Canonical class is the non-intercept, non-metaclass, class for an object.
  106. //
  107. // (e.g. [Animal class] would be canonical, not
  108. // object_getClass([Animal class]), if the Animal class has not been touched
  109. // by the intercept mechanism.
  110.  
  111. Class KWSetupObjectInterceptSupport(id anObject) {
  112. Class objectClass = object_getClass(anObject);
  113.  
  114. if (KWClassIsInterceptClass(objectClass))
  115. return objectClass;
  116.  
  117. BOOL objectIsClass = KWObjectIsClass(anObject);
  118. Class canonicalClass = objectIsClass ? anObject : objectClass;
  119. Class canonicalInterceptClass = KWInterceptClassForCanonicalClass(canonicalClass);
  120. Class interceptClass = objectIsClass ? object_getClass(canonicalInterceptClass) : canonicalInterceptClass;
  121.  
  122. anObject->isa = interceptClass;
  123. return interceptClass;
  124. }
  125.  
  126. void KWSetupMethodInterceptSupport(Class interceptClass, SEL aSelector) {
  127. BOOL isMetaClass = class_isMetaClass(interceptClass);
  128. Method method = isMetaClass ? class_getClassMethod(interceptClass, aSelector)
  129. : class_getInstanceMethod(interceptClass, aSelector);
  130.  
  131. if (method == nil) {
  132. [NSException raise:NSInvalidArgumentException format:@"cannot setup intercept support for -%@ because there is no such method exists",
  133. NSStringFromSelector(aSelector)];
  134. }
  135.  
  136. const char *encoding = method_getTypeEncoding(method);
  137. IMP forwardingImplementation = KWForwardingImplementationForMethodEncoding(encoding);
  138. class_addMethod(interceptClass, aSelector, forwardingImplementation, encoding);
  139. }
  140.  
  141. #pragma mark -
  142. #pragma mark Intercept Enabled Method Implementations
  143.  
  144. void KWInterceptedForwardInvocation(id anObject, SEL aSelector, NSInvocation* anInvocation) {
  145. NSValue *key = [NSValue valueWithNonretainedObject:anObject];
  146. NSMutableDictionary *spyArrayDictionary = [KWMessageSpies objectForKey:key];
  147.  
  148. for (KWMessagePattern *messagePattern in spyArrayDictionary) {
  149. if ([messagePattern matchesInvocation:anInvocation]) {
  150. NSArray *spies = [spyArrayDictionary objectForKey:messagePattern];
  151.  
  152. for (NSValue *spyWrapper in spies) {
  153. id<KWMessageSpying> spy = [spyWrapper nonretainedObjectValue];
  154. [spy object:anObject didReceiveInvocation:anInvocation];
  155. }
  156. }
  157. }
  158.  
  159. NSMutableArray *stubs = [KWObjectStubs objectForKey:key];
  160.  
  161. for (KWStub *stub in stubs) {
  162. if ([stub processInvocation:anInvocation])
  163. return;
  164. }
  165.  
  166. Class interceptClass = object_getClass(anObject);
  167. Class originalClass = class_getSuperclass(interceptClass);
  168. anObject->isa = originalClass;
  169. [anInvocation invoke];
  170. anObject->isa = interceptClass;
  171. }
  172.  
  173. void KWInterceptedDealloc(id anObject, SEL aSelector) {
  174. NSValue *key = [NSValue valueWithNonretainedObject:anObject];
  175. [KWMessageSpies removeObjectForKey:key];
  176. [KWObjectStubs removeObjectForKey:key];
  177.  
  178. Class interceptClass = object_getClass(anObject);
  179. Class originalClass = class_getSuperclass(interceptClass);
  180. anObject->isa = originalClass;
  181. [anObject dealloc];
  182. }
  183.  
  184. Class KWInterceptedClass(id anObject, SEL aSelector) {
  185. Class interceptClass = object_getClass(anObject);
  186. Class originalClass = class_getSuperclass(interceptClass);
  187. return originalClass;
  188. }
  189.  
  190. Class KWInterceptedSuperclass(id anObject, SEL aSelector) {
  191. Class interceptClass = object_getClass(anObject);
  192. Class originalClass = class_getSuperclass(interceptClass);
  193. Class originalSuperclass = class_getSuperclass(originalClass);
  194. return originalSuperclass;
  195. }
  196.  
  197. #pragma mark -
  198. #pragma mark Managing Objects Stubs
  199.  
  200. void KWAssociateObjectStub(id anObject, KWStub *aStub) {
  201. if (KWObjectStubs == nil)
  202. KWObjectStubs = [[NSMutableDictionary alloc] init];
  203.  
  204. NSValue *key = [NSValue valueWithNonretainedObject:anObject];
  205. NSMutableArray *stubs = [KWObjectStubs objectForKey:key];
  206.  
  207. if (stubs == nil) {
  208. stubs = [[NSMutableArray alloc] init];
  209. [KWObjectStubs setObject:stubs forKey:key];
  210. [stubs release];
  211. }
  212.  
  213. NSUInteger stubCount = [stubs count];
  214.  
  215. for (int i = 0; i < stubCount; ++i) {
  216. KWStub *existingStub = [stubs objectAtIndex:i];
  217.  
  218. if ([aStub.messagePattern isEqualToMessagePattern:existingStub.messagePattern]) {
  219. [stubs removeObjectAtIndex:i];
  220. break;
  221. }
  222. }
  223.  
  224. [stubs addObject:aStub];
  225. }
  226.  
  227. void KWClearObjectStubs(id anObject) {
  228. NSValue *key = [NSValue valueWithNonretainedObject:anObject];
  229. [KWObjectStubs removeObjectForKey:key];
  230. }
  231.  
  232. void KWClearAllObjectStubs(void) {
  233. [KWObjectStubs removeAllObjects];
  234. }
  235.  
  236. #pragma mark -
  237. #pragma mark Managing Message Spies
  238.  
  239. void KWAssociateMessageSpy(id anObject, id aSpy, KWMessagePattern *aMessagePattern) {
  240. if (KWMessageSpies == nil)
  241. KWMessageSpies = [[NSMutableDictionary alloc] init];
  242.  
  243. NSValue *key = [NSValue valueWithNonretainedObject:anObject];
  244. NSMutableDictionary *spies = [KWMessageSpies objectForKey:key];
  245.  
  246. if (spies == nil) {
  247. spies = [[NSMutableDictionary alloc] init];
  248. [KWMessageSpies setObject:spies forKey:key];
  249. [spies release];
  250. }
  251.  
  252. NSMutableArray *messagePatternSpies = [spies objectForKey:aMessagePattern];
  253.  
  254. if (messagePatternSpies == nil) {
  255. messagePatternSpies = [[NSMutableArray alloc] init];
  256. [spies setObject:messagePatternSpies forKey:aMessagePattern];
  257. [messagePatternSpies release];
  258. }
  259.  
  260. NSValue *spyWrapper = [NSValue valueWithNonretainedObject:aSpy];
  261.  
  262. if ([messagePatternSpies containsObject:spyWrapper])
  263. return;
  264.  
  265. [messagePatternSpies addObject:spyWrapper];
  266. }
  267.  
  268. void KWClearObjectSpy(id anObject, id aSpy, KWMessagePattern *aMessagePattern) {
  269. NSValue *key = [NSValue valueWithNonretainedObject:anObject];
  270. NSMutableDictionary *spyArrayDictionary = [KWMessageSpies objectForKey:key];
  271. NSMutableArray *spies = [spyArrayDictionary objectForKey:aMessagePattern];
  272. NSValue *spyWrapper = [NSValue valueWithNonretainedObject:aSpy];
  273. [spies removeObject:spyWrapper];
  274. }
  275.  
  276. void KWClearAllMessageSpies(void) {
  277. [KWMessageSpies removeAllObjects];
  278. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement