forked from wdmchaft/iSpy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTypeDescription.xm
129 lines (109 loc) · 4.45 KB
/
TypeDescription.xm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
//
// NSBlock+TypedDescription.m
// BlockTypeDescription
//
// Created by Conrad Kramer on 3/17/13.
// Copyright (c) 2013 Kramer Software Productions, LLC. All rights reserved.
//
#import "NSBlock+TypedDescription.h"
#import <objc/runtime.h>
static NSString * (*TDOriginalDescription)(id, SEL);
static NSString *TDFormattedStringForComplexType(const char *encoding) {
NSString *type;
if (*encoding == '(') {
type = @"union";
} else if (*encoding == '{') {
type = @"struct";
} else {
return nil;
}
const char *namePtr = encoding + 1;
unsigned length = 0;
while (*namePtr && *namePtr != '=' && *namePtr != '}' && *namePtr != ')') {
namePtr++;
length++;
}
NSString *name = [[NSString alloc] initWithBytes:(encoding + 1) length:length encoding:NSUTF8StringEncoding];
return [NSString stringWithFormat:@"%@%@%@", type, name.length ? @" " : @"", name];
}
static NSString *TDFormattedStringForType(const char *encoding) {
char type = *encoding;
switch (type) {
case 'c': return @"char";
case 'i': return @"int";
case 's': return @"short";
case 'l': return @"long";
case 'q': return @"long long";
case 'C': return @"unsigned char";
case 'I': return @"unsigned int";
case 'S': return @"unsigned short";
case 'L': return @"unsigned long";
case 'Q': return @"unsigned long long";
case 'f': return @"float";
case 'd': return @"double";
case 'D': return @"long double";
case 'B': return @"_Bool"; // C99 _Bool or C++ bool
case 'v': return @"void";
case '*': return @"STR";
case '#': return @"Class";
case ':': return @"SEL";
case '%': return @"NXAtom";
case '?': return @"void";
case 'j': return @"_Complex";
case 'r': return @"const";
case 'n': return @"in";
case 'N': return @"inout";
case 'o': return @"out";
case 'O': return @"bycopy";
case 'R': return @"byref";
case 'V': return @"oneway";
case '@': return @"id";
case '^': return [NSString stringWithFormat:@"%@*", TDFormattedStringForType(encoding + 1)];
case '[': {
char *type;
long size = strtol(encoding + 1, &type, 10);
return [NSString stringWithFormat:@"%@[%li]", TDFormattedStringForType(type), size];
}
case '(':
case '{':
return TDFormattedStringForComplexType(encoding);
default:
break;
}
return @"";
}
NSString *TDFormattedStringForBlockSignature(id block) {
struct TD_Block_literal_1 *blockRef = (__bridge struct TD_Block_literal_1 *)block;
int flags = blockRef->flags;
if ((flags & TD_BLOCK_HAS_SIGNATURE) == 0) return nil;
struct TD_Block_descriptor_1 *descriptor = blockRef->descriptor;
void *signaturePtr = descriptor;
signaturePtr += sizeof(descriptor->reserved);
signaturePtr += sizeof(descriptor->size);
if (flags & TD_BLOCK_HAS_COPY_DISPOSE) {
signaturePtr += sizeof(descriptor->copy_helper);
signaturePtr += sizeof(descriptor->dispose_helper);
}
const char *signature = *(const char **)signaturePtr;
NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:signature];
// Purposefully ignore first argument, it is a reference to the block itself
NSMutableArray *arguments = [NSMutableArray array];
for (int i=1; i < methodSignature.numberOfArguments; i++) {
NSString *type = TDFormattedStringForType([methodSignature getArgumentTypeAtIndex:i]);
[arguments addObject:type];
}
NSString *returnType = TDFormattedStringForType(methodSignature.methodReturnType);
return [NSString stringWithFormat:@"(%@ (^)(%@))", returnType, [arguments componentsJoinedByString:@", "]];
}
static NSString * TDReplacedDescription(id self, SEL _cmd) {
NSString *blockType = TDFormattedStringForBlockSignature(self);
if (blockType) {
return [NSString stringWithFormat:@"<%@: %@>", NSStringFromClass([self class]), blockType];
} else {
return TDOriginalDescription(self, _cmd);
}
}
static __attribute__((constructor)) void constructor() {
Method descriptionMethod = class_getInstanceMethod(NSClassFromString(@"NSBlock"), @selector(description));
TDOriginalDescription = (NSString * (*)(id, SEL))method_setImplementation(descriptionMethod, (IMP)&TDReplacedDescription);
}