X-Git-Url: https://git.mdrn.pl/wl-app.git/blobdiff_plain/53b27422d140022594fc241cca91c3183be57bca..48b2fe9f7c2dc3d9aeaaa6dbfb27c7da4f3235ff:/iOS/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/GULSwizzler.m diff --git a/iOS/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/GULSwizzler.m b/iOS/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/GULSwizzler.m new file mode 100644 index 0000000..9839124 --- /dev/null +++ b/iOS/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/GULSwizzler.m @@ -0,0 +1,185 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Private/GULSwizzler.h" + +#import + +#import +#import "../Common/GULLoggerCodes.h" + +#ifdef GUL_UNSWIZZLING_ENABLED +#import +// We need a private method for an assert. +#import +#endif + +static GULLoggerService kGULLoggerSwizzler = @"[GoogleUtilites/MethodSwizzler]"; + +dispatch_queue_t GetGULSwizzlingQueue() { + static dispatch_queue_t queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + queue = dispatch_queue_create("com.google.GULSwizzler", DISPATCH_QUEUE_SERIAL); + }); + return queue; +} + +@implementation GULSwizzler + ++ (void)swizzleClass:(Class)aClass + selector:(SEL)selector + isClassSelector:(BOOL)isClassSelector + withBlock:(nullable id)block { + dispatch_sync(GetGULSwizzlingQueue(), ^{ + NSAssert(selector, @"The selector cannot be NULL"); + NSAssert(aClass, @"The class cannot be Nil"); + Class resolvedClass = aClass; + Method method = nil; + if (isClassSelector) { + method = class_getClassMethod(aClass, selector); + resolvedClass = object_getClass(aClass); + } else { + method = class_getInstanceMethod(aClass, selector); + } + NSAssert(method, @"You're attempting to swizzle a method that doesn't exist. (%@, %@)", + NSStringFromClass(resolvedClass), NSStringFromSelector(selector)); + IMP newImp = imp_implementationWithBlock(block); + +#ifdef GUL_UNSWIZZLING_ENABLED + IMP currentImp = class_getMethodImplementation(resolvedClass, selector); + [[GULSwizzlingCache sharedInstance] cacheCurrentIMP:currentImp + forNewIMP:newImp + forClass:resolvedClass + withSelector:selector]; +#endif + + const char *typeEncoding = method_getTypeEncoding(method); + __unused IMP originalImpOfClass = + class_replaceMethod(resolvedClass, selector, newImp, typeEncoding); + +#ifdef GUL_UNSWIZZLING_ENABLED + // If !originalImpOfClass, then the IMP came from a superclass. + if (originalImpOfClass) { + if (originalImpOfClass != + [[GULSwizzlingCache sharedInstance] originalIMPOfCurrentIMP:currentImp]) { + GULLogWarning(kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeMethodSwizzling000], + @"Swizzling class: %@ SEL:%@ after it has been previously been swizzled.", + NSStringFromClass(resolvedClass), NSStringFromSelector(selector)); + } + } +#endif + }); +} + ++ (void)unswizzleClass:(Class)aClass selector:(SEL)selector isClassSelector:(BOOL)isClassSelector { +#ifdef GUL_UNSWIZZLING_ENABLED + dispatch_sync(GetGULSwizzlingQueue(), ^{ + NSAssert(aClass != nil && selector != nil, @"You cannot unswizzle a nil class or selector."); + Method method = nil; + Class resolvedClass = aClass; + if (isClassSelector) { + resolvedClass = object_getClass(aClass); + method = class_getClassMethod(aClass, selector); + } else { + method = class_getInstanceMethod(aClass, selector); + } + NSAssert(method, @"Couldn't find the method you're unswizzling in the runtime."); + IMP originalImp = + [[GULSwizzlingCache sharedInstance] cachedIMPForClass:resolvedClass withSelector:selector]; + NSAssert(originalImp, @"This class/selector combination hasn't been swizzled"); + IMP currentImp = method_setImplementation(method, originalImp); + BOOL didRemoveBlock = imp_removeBlock(currentImp); + NSAssert(didRemoveBlock, @"Wasn't able to remove the block of a swizzled IMP."); + [[GULSwizzlingCache sharedInstance] clearCacheForSwizzledIMP:currentImp + selector:selector + aClass:resolvedClass]; + }); +#else + NSAssert(NO, @"Unswizzling is disabled."); +#endif +} + ++ (nullable IMP)originalImplementationForClass:(Class)aClass + selector:(SEL)selector + isClassSelector:(BOOL)isClassSelector { +#ifdef GUL_UNSWIZZLING_ENABLED + __block IMP originalImp = nil; + dispatch_sync(GetGULSwizzlingQueue(), ^{ + Class resolvedClass = isClassSelector ? object_getClass(aClass) : aClass; + originalImp = + [[GULSwizzlingCache sharedInstance] cachedIMPForClass:resolvedClass withSelector:selector]; + NSAssert(originalImp, @"The IMP for this class/selector combo doesn't exist (%@, %@).", + NSStringFromClass(resolvedClass), NSStringFromSelector(selector)); + }); + return originalImp; +#else + NSAssert(NO, @"Unswizzling is disabled and the original IMP is not cached."); + return nil; +#endif +} + ++ (nullable IMP)currentImplementationForClass:(Class)aClass + selector:(SEL)selector + isClassSelector:(BOOL)isClassSelector { + NSAssert(selector, @"The selector cannot be NULL"); + NSAssert(aClass, @"The class cannot be Nil"); + if (selector == NULL || aClass == nil) { + return nil; + } + __block IMP currentIMP = nil; + dispatch_sync(GetGULSwizzlingQueue(), ^{ + Method method = nil; + if (isClassSelector) { + method = class_getClassMethod(aClass, selector); + } else { + method = class_getInstanceMethod(aClass, selector); + } + NSAssert(method, @"The Method for this class/selector combo doesn't exist (%@, %@).", + NSStringFromClass(aClass), NSStringFromSelector(selector)); + if (method == nil) { + return; + } + currentIMP = method_getImplementation(method); + NSAssert(currentIMP, @"The IMP for this class/selector combo doesn't exist (%@, %@).", + NSStringFromClass(aClass), NSStringFromSelector(selector)); + }); + return currentIMP; +} + ++ (BOOL)selector:(SEL)selector existsInClass:(Class)aClass isClassSelector:(BOOL)isClassSelector { + Method method = isClassSelector ? class_getClassMethod(aClass, selector) + : class_getInstanceMethod(aClass, selector); + return method != nil; +} + ++ (NSArray *)ivarObjectsForObject:(id)object { + NSMutableArray *array = [NSMutableArray array]; + unsigned int count; + Ivar *vars = class_copyIvarList([object class], &count); + for (NSUInteger i = 0; i < count; i++) { + const char *typeEncoding = ivar_getTypeEncoding(vars[i]); + // Check to see if the ivar is an object. + if (strncmp(typeEncoding, "@", 1) == 0) { + id ivarObject = object_getIvar(object, vars[i]); + [array addObject:ivarObject]; + } + } + free(vars); + return array; +} + +@end