/ NSString.m
NSString.m
  1  //
  2  //  NSString.m
  3  //  CoreFoundation
  4  //
  5  //  Copyright (c) 2014 Apportable. All rights reserved.
  6  //
  7  
  8  #import <Foundation/NSData.h>
  9  #import <unicode/uchar.h>
 10  #import <objc/runtime.h>
 11  #import "NSStringInternal.h"
 12  #import "NSObjectInternal.h"
 13  #import "CFPriv.h"
 14  #import "ForFoundationOnly.h"
 15  
 16  static inline CFStringRef __CFExceptionProem(id self, SEL _cmd) {
 17      const char *className = class_getName([self class]);
 18      if (!className) {
 19          className = "NULL CLASS";
 20      }
 21      const char *selName = sel_getName(_cmd);
 22      if (!selName) {
 23          selName = "NULL SEL";
 24      }
 25  
 26      CFStringRef proem = nil;
 27      char *allocBuf = NULL;
 28      asprintf(&allocBuf, "(%s/%s)", className, selName);
 29      if (allocBuf) {
 30          proem = CFStringCreateWithCString(NULL, allocBuf, kCFStringEncodingUTF8);
 31          proem = CFMakeCollectable(proem);
 32          free(allocBuf);
 33      }
 34      return proem;
 35  }
 36  
 37  static inline void mutateError(id self, SEL _cmd, int err) {
 38      switch (err) {
 39          case _CFStringErrNone:
 40              break;
 41          case _CFStringErrNotMutable:
 42              NSSTRING_INVALIDMUTATIONERROR;
 43              break;
 44          case _CFStringErrNilArg:
 45              NSSTRING_NILSTRINGERROR;
 46              break;
 47          case _CFStringErrBounds:
 48              NSSTRING_BOUNDSERROR;
 49              break;
 50          default:
 51              NSSTRING_ILLEGALREQUESTERROR;
 52              break;
 53      }
 54  }
 55  
 56  @implementation __NSCFString
 57  
 58  + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key
 59  {
 60      return NO;
 61  }
 62  
 63  - (NSUInteger)replaceOccurrencesOfString:(NSString *)target withString:(NSString *)replacement options:(NSStringCompareOptions)options range:(NSRange)searchRange
 64  {
 65      if (!_CFStringIsMutable((CFStringRef)self))
 66      {
 67          NSInvalidMutation();
 68          return NSNotFound;
 69      }
 70  
 71      if ((options & NSRegularExpressionSearch) != 0)
 72      {
 73          return [super replaceOccurrencesOfString:target withString:replacement options:options range:searchRange];
 74      }
 75      else
 76      {
 77          CFStringCompareFlags flags = (CFStringCompareFlags)options;
 78          if ((options & NSLiteralSearch) == 0)
 79          {
 80              flags |= kCFCompareNonliteral;
 81          }
 82          return CFStringFindAndReplace((CFMutableStringRef)self, (CFStringRef)target, (CFStringRef)replacement, CFRangeMake(searchRange.location, searchRange.length), flags);
 83      }
 84  }
 85  
 86  - (void)appendCharacters:(unichar *)characters length:(NSUInteger)length
 87  {
 88      if (_CFStringIsMutable((CFStringRef)self))
 89      {
 90          CFStringAppendCharacters((CFMutableStringRef)self, characters, length);
 91      }
 92      else
 93      {
 94          NSInvalidMutation();
 95      }
 96  }
 97  
 98  - (void)setString:(NSString *)str
 99  {
100      if (_CFStringIsMutable((CFStringRef)self))
101      {
102          CFStringReplaceAll((CFMutableStringRef)self, (CFStringRef)str);
103      }
104      else
105      {
106          NSInvalidMutation();
107      }
108  }
109  
110  - (void)appendFormat:(NSString *)format, ...
111  {
112      if (_CFStringIsMutable((CFStringRef)self))
113      {
114          va_list args;
115          va_start(args, format);
116          _CFStringAppendFormatAndArgumentsAux((CFMutableStringRef)self, &_NSCFCopyDescription2, NULL, (CFStringRef)format, args);
117          va_end(args);
118      }
119      else
120      {
121          NSInvalidMutation();
122      }
123  }
124  
125  - (void)deleteCharactersInRange:(NSRange)range
126  {
127      if (_CFStringIsMutable((CFStringRef)self))
128      {
129          CFStringDelete((CFMutableStringRef)self, CFRangeMake(range.location, range.length));
130      }
131      else
132      {
133          NSInvalidMutation();
134      }
135  }
136  
137  - (void)appendString:(NSString *)str
138  {
139      CFIndex len = _CFStringGetLength2((CFStringRef)self);
140      int ret = __CFStringCheckAndReplace((CFMutableStringRef)self, CFRangeMake(len, 0), (CFStringRef)str);
141      mutateError(self, _cmd, ret);
142  }
143  
144  - (void)insertString:(NSString *)str atIndex:(NSUInteger)index
145  {
146      if (_CFStringIsMutable((CFStringRef)self))
147      {
148          CFStringInsert((CFMutableStringRef)self, index, (CFStringRef)str);
149      }
150      else
151      {
152          NSInvalidMutation();
153      }
154  }
155  
156  - (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)replacement
157  {
158      if (_CFStringIsMutable((CFStringRef)self))
159      {
160          CFStringReplace((CFMutableStringRef)self, CFRangeMake(range.location, range.length), (CFStringRef)replacement);
161      }
162      else
163      {
164          NSInvalidMutation();
165      }
166  }
167  
168  - (BOOL)_isCString
169  {
170      return __CFStringIsEightBit((CFStringRef)self);
171  }
172  
173  - (Class)classForCoder
174  {
175      if (_CFStringIsMutable((CFStringRef)self))
176      {
177          return objc_lookUpClass("NSMutableString");
178      }
179      else
180      {
181          return objc_lookUpClass("NSString");
182      }
183  }
184  
185  - (NSStringEncoding)smallestEncoding
186  {
187      return CFStringConvertEncodingToNSStringEncoding(CFStringGetSmallestEncoding((CFStringRef)self));
188  }
189  
190  - (NSStringEncoding)fastestEncoding
191  {
192      return CFStringConvertEncodingToNSStringEncoding(CFStringGetFastestEncoding((CFStringRef)self));
193  }
194  
195  - (id)mutableCopyWithZone:(NSZone *)zone
196  {
197      return (id)CFStringCreateMutableCopy(kCFAllocatorDefault, 0, (CFStringRef)self);
198  }
199  
200  - (id)copyWithZone:(NSZone *)zone
201  {
202      return (id)CFStringCreateCopy(kCFAllocatorDefault, (CFStringRef)self);
203  }
204  
205  - (void)getLineStart:(NSUInteger *)startPtr end:(NSUInteger *)lineEndPtr contentsEnd:(NSUInteger *)contentsEndPtr forRange:(NSRange)range
206  {
207      CFStringGetLineBounds((CFStringRef)self, CFRangeMake(range.location, range.length), (CFIndex *)startPtr, (CFIndex *)lineEndPtr, (CFIndex *)contentsEndPtr);
208  }
209  
210  - (BOOL)hasSuffix:(NSString *)prefix
211  {
212      return CFStringHasSuffix((CFStringRef)self, (CFStringRef)prefix);
213  }
214  
215  - (BOOL)hasPrefix:(NSString *)suffix
216  {
217      return CFStringHasPrefix((CFStringRef)self, (CFStringRef)suffix);
218  }
219  
220  - (BOOL)isEqualToString:(NSString *)other
221  {
222      if (other == nil)
223      {
224          return NO;
225      }
226  
227      return CFEqual((CFTypeRef)self, (CFTypeRef)other);
228  }
229  
230  - (BOOL)isEqual:(id)other
231  {
232      if (other == nil)
233      {
234          return NO;
235      }
236  
237      return CFEqual((CFTypeRef)self, (CFTypeRef)other);
238  }
239  
240  - (id)substringWithRange:(NSRange)range
241  {
242      return [(__NSCFString *)CFStringCreateWithSubstring(kCFAllocatorDefault, (CFStringRef)self, CFRangeMake(range.location, range.length)) autorelease];
243  }
244  
245  - (BOOL)getCString:(char *)bytes maxLength:(NSUInteger)maxLength encoding:(NSStringEncoding)encoding
246  {
247      return CFStringGetCString((CFStringRef)self, bytes, maxLength, CFStringConvertNSStringEncodingToEncoding(encoding));
248  }
249  
250  - (const char *)cStringUsingEncoding:(NSStringEncoding)encoding
251  {
252      CFStringEncoding cfEncoding = CFStringConvertNSStringEncodingToEncoding(encoding);
253  
254      if (cfEncoding == kCFStringEncodingInvalidId)
255      {
256          return NULL;
257      }
258      const char *str = CFStringGetCStringPtr((CFStringRef)self, cfEncoding);
259  
260      if (str != NULL)
261      {
262          return str;
263      }
264      else
265      {
266  #pragma clang diagnostic push
267  #pragma clang diagnostic ignored "-Wobjc-method-access"
268          return [super cStringUsingEncoding:encoding];
269  #pragma clang diagnostic pop
270      }
271  }
272  
273  - (NSUInteger)cStringLength
274  {
275      return [(NSString *)self lengthOfBytesUsingEncoding:CFStringConvertEncodingToNSStringEncoding(CFStringGetSystemEncoding())];
276  }
277  
278  static inline const char *cStringForEncoding(__NSCFString *self, CFStringEncoding encoding, BOOL allowLossyConversion)
279  {
280      const char *str = CFStringGetCStringPtr((CFStringRef)self, encoding);
281  
282      if (str == NULL)
283      {
284          NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(encoding);
285          NSUInteger length = [(NSString *)self lengthOfBytesUsingEncoding:enc];
286          NSMutableData *data = [[NSMutableData alloc] initWithCapacity:length + 1];
287          [data setLength:length + 1];
288          NSStringEncodingConversionOptions opts = 0;
289          if (allowLossyConversion)
290          {
291              opts = NSStringEncodingConversionAllowLossy|NSStringEncodingConversionExternalRepresentation;
292          }
293          [self getBytes:[data mutableBytes] maxLength:length usedLength:NULL encoding:enc options:opts range:NSMakeRange(0, [self length]) remainingRange:NULL];
294          str = [data bytes];
295          [data autorelease];
296      }
297      
298      return str;
299  }
300  
301  - (const char *)UTF8String
302  {
303      return cStringForEncoding(self, kCFStringEncodingUTF8, NO);
304  }
305  
306  - (const char *)cString
307  {
308      return cStringForEncoding(self, CFStringGetSystemEncoding(), NO);
309  }
310  
311  - (const char *)lossyCString
312  {
313      return cStringForEncoding(self, CFStringGetSystemEncoding(), YES);
314  }
315  
316  - (const char *)_fastCStringContents:(BOOL)unused
317  {
318      CFStringEncoding encoding = CFStringGetSystemEncoding();
319      return CFStringGetCStringPtr((CFStringRef)self, encoding);
320  }
321  
322  - (const unichar*)_fastCharacterContents
323  {
324      return CFStringGetCharactersPtr((CFStringRef)self);
325  }
326  
327  - (void)getCharacters:(unichar *)buffer range:(NSRange)range
328  {
329      CFStringGetCharacters((CFStringRef)self, CFRangeMake(range.location, range.length), buffer);
330  }
331  
332  - (unichar)characterAtIndex:(NSUInteger)index
333  {
334      return CFStringGetCharacterAtIndex((CFStringRef)self, index);
335  }
336  
337  - (NSUInteger)length
338  {
339      return _CFStringGetLength2((CFStringRef)self);
340  }
341  
342  - (NSUInteger)hash
343  {
344      return __CFStringHash((CFTypeRef)self);
345  }
346  
347  - (NSUInteger)retainCount
348  {
349      return CFGetRetainCount((CFTypeRef)self);
350  }
351  
352  - (BOOL)_isDeallocating
353  {
354      return _CFIsDeallocating((CFTypeRef)self);
355  }
356  
357  - (BOOL)_tryRetain
358  {
359      return _CFTryRetain((CFTypeRef)self) != NULL;
360  }
361  
362  - (oneway void)release
363  {
364      CFRelease((CFTypeRef)self);
365  }
366  
367  - (id)retain
368  {
369      return (id)CFRetain((CFTypeRef)self);
370  }
371  
372  - (BOOL)isNSString__
373  {
374      return YES;
375  }
376  
377  - (CFTypeID)_cfTypeID
378  {
379      return CFStringGetTypeID();
380  }
381  
382  @end