// // RSSwizzle.m // RSSwizzleTests // // Created by Yan Rabovik on 05.09.13. // // #import "RSSwizzle.h" #import #include #import #if !__has_feature(objc_arc) #error This code needs ARC. Use compiler option -fobjc-arc #endif #pragma mark - Block Helpers #if !defined(NS_BLOCK_ASSERTIONS) // See http://clang.llvm.org/docs/Block-ABI-Apple.html#high-level struct Block_literal_1 { void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock int flags; int reserved; void (*invoke)(void *, ...); struct Block_descriptor_1 { unsigned long int reserved; // NULL unsigned long int size; // sizeof(struct Block_literal_1) // optional helper functions void (*copy_helper)(void *dst, void *src); // IFF (1<<25) void (*dispose_helper)(void *src); // IFF (1<<25) // required ABI.2010.3.16 const char *signature; // IFF (1<<30) } *descriptor; // imported variables }; enum { BLOCK_HAS_COPY_DISPOSE = (1 << 25), BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code BLOCK_IS_GLOBAL = (1 << 28), BLOCK_HAS_STRET = (1 << 29), // IFF BLOCK_HAS_SIGNATURE BLOCK_HAS_SIGNATURE = (1 << 30), }; typedef int BlockFlags; static const char *blockGetType(id block){ struct Block_literal_1 *blockRef = (__bridge struct Block_literal_1 *)block; BlockFlags flags = blockRef->flags; if (flags & BLOCK_HAS_SIGNATURE) { void *signatureLocation = blockRef->descriptor; signatureLocation += sizeof(unsigned long int); signatureLocation += sizeof(unsigned long int); if (flags & BLOCK_HAS_COPY_DISPOSE) { signatureLocation += sizeof(void(*)(void *dst, void *src)); signatureLocation += sizeof(void (*)(void *src)); } const char *signature = (*(const char **)signatureLocation); return signature; } return NULL; } static BOOL blockIsCompatibleWithMethodType(id block, const char *methodType){ const char *blockType = blockGetType(block); NSMethodSignature *blockSignature; if (0 == strncmp(blockType, (const char *)"@\"", 2)) { // Block return type includes class name for id types // while methodType does not include. // Stripping out return class name. char *quotePtr = strchr(blockType+2, '"'); if (NULL != quotePtr) { ++quotePtr; size_t filterTypeLen = strlen(quotePtr) + 2; if (strlen(quotePtr) > filterTypeLen) { // integer overflow check NSCAssert(false, @"Method signature is too long to swizzle"); return NO; } char filteredType[filterTypeLen]; memset(filteredType, 0, sizeof(filteredType)); *filteredType = '@'; strncpy(filteredType + 1, quotePtr, sizeof(filteredType) - 2); blockSignature = [NSMethodSignature signatureWithObjCTypes:filteredType]; }else{ return NO; } }else{ blockSignature = [NSMethodSignature signatureWithObjCTypes:blockType]; } NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:methodType]; if (!blockSignature || !methodSignature) { return NO; } if (blockSignature.numberOfArguments != methodSignature.numberOfArguments){ return NO; } if (strcmp(blockSignature.methodReturnType, methodSignature.methodReturnType) != 0) { return NO; } for (int i=0; i