11#import < string.h>
22#import " NSSlowTaggedLocalizedString.h"
33#import < dlfcn.h>
4+ #import < objc/runtime.h>
5+
6+ // If and when CF starts linking Swift we may need to rethink this
7+ #import < CoreFoundation/CoreFoundation.h>
48
59@implementation NSSlowTaggedLocalizedString
610
7- uintptr_t *obfuscator;
8- void (*_objc_registerTaggedPointerClass)(uint16_t tag, Class cls);
11+ typedef struct _NSRange {
12+ uint64_t location;
13+ uint64_t length;
14+ } NSRange ;
915
1016+ (instancetype ) createTestString {
1117#if __LP64__
12- if (obfuscator == NULL ) {
13- obfuscator = dlsym (RTLD_DEFAULT, " objc_debug_taggedpointer_obfuscator" );
14- *obfuscator = 0 ;
15- _objc_registerTaggedPointerClass = dlsym (RTLD_DEFAULT, " _objc_registerTaggedPointerClass" );
16- (*_objc_registerTaggedPointerClass)(0 , self); // 0 would be unsafe if we loaded Foundation, but we aren't doing that
17- }
18- #if __x86_64__
19- return (id )(void *)(uintptr_t )1 ; // x86_64 uses the LSB as the tag bit, and we want tag 0
20- #else
21- return (id )(void *)(uintptr_t )(1llu << 63 ); // MSB everywhere else
22- #endif
18+ static dispatch_once_t onceToken;
19+ dispatch_once (&onceToken, ^{
20+ Class tagClass = objc_lookUpClass (" NSTaggedPointerString" );
21+ Class ourClass = [NSSlowTaggedLocalizedString class ];
22+
23+ Method fastCString = class_getInstanceMethod (ourClass, @selector (_fastCStringContents: ));
24+ class_replaceMethod (tagClass, @selector (_fastCStringContents: ), method_getImplementation (fastCString), method_getTypeEncoding (fastCString));
25+
26+ Method length = class_getInstanceMethod (ourClass, @selector (length ));
27+ class_replaceMethod (tagClass, @selector (length ), method_getImplementation (length), method_getTypeEncoding (length));
28+
29+ Method charIndex = class_getInstanceMethod (ourClass, @selector (characterAtIndex: ));
30+ class_replaceMethod (tagClass, @selector (characterAtIndex: ), method_getImplementation (charIndex), method_getTypeEncoding (charIndex));
31+
32+ Method fastChars = class_getInstanceMethod (ourClass, @selector (_fastCharacterContents ));
33+ class_replaceMethod (tagClass, @selector (_fastCharacterContents ), method_getImplementation (fastChars), method_getTypeEncoding (fastChars));
34+
35+ Method retain = class_getInstanceMethod (ourClass, @selector (retain ));
36+ class_replaceMethod (tagClass, @selector (retain ), method_getImplementation (retain), method_getTypeEncoding (retain));
37+
38+ Method release = class_getInstanceMethod (ourClass, @selector (release ));
39+ class_replaceMethod (tagClass, @selector (release ), method_getImplementation (release), method_getTypeEncoding (release));
40+
41+ Method typeID = class_getInstanceMethod (ourClass, @selector (_cfTypeID ));
42+ class_replaceMethod (tagClass, @selector (_cfTypeID ), method_getImplementation (typeID), method_getTypeEncoding (typeID));
43+
44+ Method description = class_getInstanceMethod (ourClass, @selector (description ));
45+ class_replaceMethod (tagClass, @selector (description ), method_getImplementation (description), method_getTypeEncoding (description));
46+
47+ Method getBytes = class_getInstanceMethod (ourClass, @selector (getBytes:maxLength:usedLength:encoding:options:range:remainingRange: ));
48+ class_replaceMethod (tagClass, @selector (getBytes:maxLength:usedLength:encoding:options:range:remainingRange: ), method_getImplementation (getBytes), method_getTypeEncoding (getBytes));
49+ });
50+ return (NSSlowTaggedLocalizedString *)(void *)CFStringCreateWithCString (NULL , " a" , kCFStringEncodingASCII ); // make a tagged pointer string
2351#else
2452 return nil ;
2553#endif
@@ -29,7 +57,11 @@ + (instancetype) createTestString {
2957
3058+ (void ) setContents : (const char *)newContents {
3159 const char *oldContents = contents;
32- contents = strdup (newContents);
60+ if (newContents) {
61+ contents = strdup (newContents);
62+ } else {
63+ contents = NULL ;
64+ }
3365 free ((void *)oldContents);
3466}
3567
@@ -46,6 +78,7 @@ - (id)copyWithZone:(id)unused {
4678}
4779
4880- (uint16_t )characterAtIndex : (NSUInteger )index {
81+ abort ();
4982 if (index >= [self length ]) {
5083 // throw the appropriate exception
5184 abort ();
@@ -57,4 +90,27 @@ - (void *) _fastCharacterContents {
5790 return nil ;
5891}
5992
93+ - (id ) retain { return self; }
94+ - (oneway void ) release {}
95+
96+ - (uint64_t )_cfTypeID {
97+ return 7 ; // CFString
98+ }
99+
100+ - (id ) description {
101+ return self;
102+ }
103+
104+ - (BOOL )getBytes : (void *)buffer maxLength : (uint64_t )max usedLength : (uint64_t *)used encoding : (uint64_t )encoding options : (uint64_t )options range : (NSRange )range remainingRange : (NSRange *)leftover {
105+ strncpy (buffer, contents, max);
106+ if (strlen (contents) > max) {
107+ leftover->location = max;
108+ leftover->length = strlen (contents) - max;
109+ return false ;
110+ }
111+ leftover->location = 0 ;
112+ leftover->length = 0 ;
113+ return true ;
114+ }
115+
60116@end
0 commit comments