/ NSAttributedString.m
NSAttributedString.m
1 // 2 // NSAttributedString.m 3 // CoreFoundation 4 // 5 // Copyright (c) 2014 Apportable. All rights reserved. 6 // 7 8 #import "NSAttributedStringInternal.h" 9 #import "NSObjectInternal.h" 10 #import <objc/runtime.h> 11 12 // These are in Foundation 13 /* 14 @implementation NSAttributedString 15 16 @end 17 18 @implementation NSMutableAttributedString 19 20 @end 21 */ 22 23 @implementation __NSCFAttributedString 24 25 + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key 26 { 27 return NO; 28 } 29 30 static BOOL _rangeCheckRange(__NSCFAttributedString *self, NSRange range) 31 { 32 if ((uint64_t)range.location + range.length > [self length]) 33 { 34 [NSException raise:NSRangeException format:@"range (%d,%d) beyond NSAttributedString bounds (%d)", range.location, range.length, [self length]]; 35 return NO; 36 } 37 return YES; 38 } 39 40 #define RANGE_CHECK_RANGE(val) if (!_rangeCheckRange(self, range)) return val; 41 42 static BOOL _rangeCheckIndex(__NSCFAttributedString *self, NSUInteger index) 43 { 44 if (index > [self length]) 45 { 46 [NSException raise:NSRangeException format:@"index (%d) beyond NSAttributedString bounds (%d)", index, [self length]]; 47 return NO; 48 } 49 return YES; 50 } 51 52 #define RANGE_CHECK_INDEX() if (!_rangeCheckIndex(self, index)) return 0; 53 54 - (void)removeAttribute:(NSString *)name range:(NSRange)range 55 { 56 RANGE_CHECK_RANGE(); 57 CFAttributedStringRemoveAttribute((CFMutableAttributedStringRef)self, CFRangeMake(range.location, range.length), (CFStringRef) name); 58 } 59 60 - (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)range 61 { 62 NSDictionary *d = @{ name : value }; 63 [self addAttributes:d range:range]; 64 } 65 66 - (void)addAttributes:(NSDictionary *)attrs range:(NSRange)range 67 { 68 RANGE_CHECK_RANGE(); 69 CFAttributedStringSetAttributes((CFMutableAttributedStringRef)self, CFRangeMake(range.location, range.length), (CFDictionaryRef)attrs, false); 70 } 71 72 - (void)setAttributedString:(NSAttributedString *)attrString 73 { 74 CFAttributedStringReplaceAttributedString((CFMutableAttributedStringRef)self, CFRangeMake(0, [self length]), (CFAttributedStringRef)attrString); 75 } 76 - (void)deleteCharactersInRange:(NSRange)range 77 { 78 RANGE_CHECK_RANGE(); 79 CFAttributedStringReplaceString((CFMutableAttributedStringRef)self, CFRangeMake(range.location, range.length), CFSTR("")); 80 } 81 82 - (void)appendAttributedString:(NSAttributedString *)attrString 83 { 84 CFAttributedStringReplaceAttributedString((CFMutableAttributedStringRef)self, CFRangeMake([self length], 0), (CFAttributedStringRef)attrString); 85 } 86 87 - (void)insertAttributedString:(NSAttributedString *)attrString atIndex:(NSUInteger)loc 88 { 89 CFAttributedStringReplaceAttributedString((CFMutableAttributedStringRef)self, CFRangeMake(loc, 0), (CFAttributedStringRef)attrString); 90 } 91 - (void)replaceCharactersInRange:(NSRange)range withAttributedString:(NSAttributedString *)attrString 92 { 93 RANGE_CHECK_RANGE(); 94 CFAttributedStringReplaceAttributedString((CFMutableAttributedStringRef)self, CFRangeMake(range.location, range.length), (CFAttributedStringRef)attrString); 95 } 96 97 - (void)setAttributes:(NSDictionary *)attributes range:(NSRange)range 98 { 99 RANGE_CHECK_RANGE(); 100 CFAttributedStringSetAttributes((CFMutableAttributedStringRef)self, CFRangeMake(range.location, range.length), (CFDictionaryRef)attributes, true); 101 } 102 103 - (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)string 104 { 105 RANGE_CHECK_RANGE(); 106 CFAttributedStringReplaceString((CFMutableAttributedStringRef)self, CFRangeMake(range.location, range.length), (CFStringRef)string); 107 } 108 109 - (Class)classForCoder 110 { 111 return [objc_getClass("NSAttributedString") self]; 112 } 113 114 - (id)mutableCopyWithZone:(NSZone *)zone 115 { 116 return (id)CFAttributedStringCreateMutableCopy(kCFAllocatorSystemDefault, 0, (CFAttributedStringRef)self); 117 } 118 119 - (id)copyWithZone:(NSZone *)zone 120 { 121 return (id)CFAttributedStringCreateCopy(kCFAllocatorSystemDefault, (CFAttributedStringRef)self); 122 } 123 124 - (NSAttributedString *)attributedSubstringFromRange:(NSRange)range 125 { 126 RANGE_CHECK_RANGE(nil); 127 128 NSAttributedString *res = (NSAttributedString *) CFAttributedStringCreateWithSubstring( 129 kCFAllocatorSystemDefault, (CFAttributedStringRef) self, 130 CFRangeMake(range.location, range.length)); 131 132 if (range.length == 0 && res == nil) 133 { 134 // Core Foundation returns NULL/nil here, but Foundation returns an empty attributed string 135 res = [[objc_getClass("NSAttributedString") alloc] initWithString: @""]; 136 } 137 return [res autorelease]; 138 } 139 140 - (NSDictionary *)attributesAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)range inRange:(NSRange)rangeLimit 141 { 142 RANGE_CHECK_INDEX(); 143 NSDictionary *retVal = (NSDictionary *)CFAttributedStringGetAttributesAndLongestEffectiveRange((CFAttributedStringRef)self, index, 144 CFRangeMake(rangeLimit.location, rangeLimit.length), (CFRange *)range); 145 // CF doesn't zero out missing ranges 146 if (retVal && range) { 147 if ((signed)(range->length) <= 0) 148 { 149 *range = NSMakeRange(0,0); 150 } 151 } 152 return retVal; 153 } 154 155 - (id)attribute:(NSString *)attrName atIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)range inRange:(NSRange)rangeLimit 156 { 157 RANGE_CHECK_INDEX(); 158 id retVal = (id)CFAttributedStringGetAttributeAndLongestEffectiveRange((CFAttributedStringRef)self, index, 159 (CFStringRef)attrName, CFRangeMake(rangeLimit.location, rangeLimit.length), (CFRange *)range); 160 // CF doesn't zero out missing ranges 161 if (retVal && range) { 162 if ((signed)(range->length) <= 0) 163 { 164 *range = NSMakeRange(0,0); 165 } 166 } 167 return retVal; 168 } 169 170 - (id)attribute:(NSString *)attrName atIndex:(NSUInteger)index effectiveRange:(NSRangePointer)rangePtr 171 { 172 RANGE_CHECK_INDEX(); 173 return CFAttributedStringGetAttribute((CFAttributedStringRef)self, index, (CFStringRef)attrName, (CFRange *)rangePtr); 174 } 175 176 - (NSUInteger)length 177 { 178 return CFAttributedStringGetLength((CFAttributedStringRef)self); 179 } 180 181 - (NSDictionary *)attributesAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange 182 { 183 RANGE_CHECK_INDEX(); 184 return (NSDictionary *)CFAttributedStringGetAttributes((CFAttributedStringRef)self, index, (CFRange *)aRange); 185 } 186 187 - (NSString *)string 188 { 189 return (NSString *)CFAttributedStringGetString((CFAttributedStringRef)self); 190 } 191 192 - (BOOL)isEqual:(id)other 193 { 194 if (other == nil) 195 { 196 return NO; 197 } 198 return CFEqual((CFAttributedStringRef)self, (CFAttributedStringRef)other); 199 } 200 201 - (BOOL)isEqualToAttributedString:(NSAttributedString *)other 202 { 203 if (other == nil) 204 { 205 return NO; 206 } 207 return CFEqual((CFAttributedStringRef)self, (CFAttributedStringRef)other); 208 } 209 210 - (NSUInteger)retainCount 211 { 212 return CFGetRetainCount((CFTypeRef)self); 213 } 214 215 - (BOOL)_isDeallocating 216 { 217 return _CFIsDeallocating((CFTypeRef)self); 218 } 219 220 - (BOOL)_tryRetain 221 { 222 return _CFTryRetain((CFTypeRef)self) != NULL; 223 } 224 225 - (oneway void)release 226 { 227 CFRelease(self); 228 } 229 230 - (id)retain 231 { 232 return CFRetain(self); 233 } 234 235 @end