/** * Determine the common suffix of two strings. * @param text1 First string. * @param text2 Second string. * @return The number of characters common to the end of each string. */ CFIndex diff_commonSuffix(CFStringRef text1, CFStringRef text2) { // Performance analysis: http://neil.fraser.name/news/2007/10/09/ CFIndex text1_length = CFStringGetLength(text1); CFIndex text2_length = CFStringGetLength(text2); CFStringInlineBuffer text1_inlineBuffer, text2_inlineBuffer; CFStringInitInlineBuffer(text1, &text1_inlineBuffer, CFRangeMake(0, text1_length)); CFStringInitInlineBuffer(text2, &text2_inlineBuffer, CFRangeMake(0, text2_length)); UniChar char1, char2; CFIndex n = MIN(text1_length, text2_length); for (CFIndex i = 1; i <= n; i++) { char1 = CFStringGetCharacterFromInlineBuffer(&text1_inlineBuffer, (text1_length - i)); char2 = CFStringGetCharacterFromInlineBuffer(&text2_inlineBuffer, (text2_length - i)); if (char1 != char2) { return i - 1; } } return n; }
void stringGettingAtCharactersExample(void) { CFStringRef str; const UniChar *chars; show(CFSTR("------------------Character Manipulations---------------")); // Create some test CFString str = CFStringCreateWithCString(NULL, "Hello World", kCFStringEncodingASCII); show(CFSTR("Original String : %@"), str); // The fastest way to get the contents; this might return NULL though // depending on the system, the release, etc, so don't depend on it // (unless you used CFStringCreateMutableWithExternalCharactersNoCopy()) chars = CFStringGetCharactersPtr(str); // If that fails, you can try copying the UniChars out // either into some stack buffer or some allocated piece of memory... // Using the former is fine, but you need to know the size; the latter // always works but requires allocating some memory; not too efficient. if (chars == NULL) { CFIndex length = CFStringGetLength(str); UniChar *buffer = (UniChar*)malloc(length * sizeof(UniChar)); CFStringGetCharacters(str, CFRangeMake(0, length), buffer); // Process the chars... free(buffer); } else show(CFSTR("Characters : %@"), str); // You can use CFStringGetCharacterAtIndex() to get at the characters one at a time, // but doing a lot of characters this way might get slow... // An option is to use "inline buffer" functionality which mixes the convenience of // one-at-a-time char access with efficiency of bulk access { CFStringInlineBuffer inlineBuffer; CFIndex length = CFStringGetLength(str); CFIndex cnt; CFStringInitInlineBuffer(str, &inlineBuffer, CFRangeMake(0, length)); for (cnt = 0; cnt < length; cnt++) { UniChar ch = CFStringGetCharacterFromInlineBuffer(&inlineBuffer, cnt); // Process character... (void)ch; // Dummy processing to prevent compiler warning... } } }
static void printObjAsString(CFStringRef obj) { CFStringInlineBuffer buf; CFIndex len = CFStringGetLength(obj); CFStringInitInlineBuffer(obj, &buf, CFRangeMake(0, len)); printf("\""); for (CFIndex i = 0; i < len; ++ i) { UniChar c = CFStringGetCharacterFromInlineBuffer(&buf, i); if (c == '"' || c == '\\') printf("\\%C", c); else if (c >= ' ' && c <= '\x7F') printf("%C", c); else if (c == '\t') printf("\\t"); else if (c == '\n') printf("\\n"); else printf("\\U%04x", c); } printf("\""); }
__private_extern__ CFIndex CFPreferencesAppIntegerValue(CFStringRef key, CFStringRef appName, Boolean *keyExistsAndHasValidFormat) { CFPropertyListRef value; CFIndex result; CFTypeID typeID = 0; Boolean valid; CFAssert1(appName != NULL, __kCFLogAssertion, "%s(): Cannot access application preferences with a NULL application name", __PRETTY_FUNCTION__); CFAssert1(key != NULL, __kCFLogAssertion, "%s(): Cannot access preferences with a NULL key", __PRETTY_FUNCTION__); value = CFPreferencesCopyAppValue(key, appName); if (!keyExistsAndHasValidFormat) { keyExistsAndHasValidFormat = &valid; } if (!value) { *keyExistsAndHasValidFormat = false; return 0; } typeID = CFGetTypeID(value); if (typeID == CFStringGetTypeID()) { SInt32 charIndex = 0; SInt32 intVal; CFStringInlineBuffer buf; Boolean success; CFStringInitInlineBuffer((CFStringRef)value, &buf, CFRangeMake(0, CFStringGetLength((CFStringRef)value))); success = __CFStringScanInteger(&buf, NULL, &charIndex, false, &intVal); *keyExistsAndHasValidFormat = (success && charIndex == CFStringGetLength((CFStringRef)value)); result = (*keyExistsAndHasValidFormat) ? intVal : 0; } else if (typeID == CFNumberGetTypeID()) { *keyExistsAndHasValidFormat = !CFNumberIsFloatType((CFNumberRef)value); if (*keyExistsAndHasValidFormat) { CFNumberGetValue((CFNumberRef)value, kCFNumberCFIndexType, &result); } else { result = 0; } } else { // Unknown type result = 0; *keyExistsAndHasValidFormat = false; } CFRelease(value); return result; }
/* There has got to be an easier way to do this. For now we based this code on CFNetwork/Connection/URLResponse.cpp. */ static CFStringRef copyParseMaxAge(CFStringRef cacheControlHeader) { /* The format of the cache control header is a comma-separated list, but each list element could be a key-value pair, with the value quoted and possibly containing a comma. */ CFStringInlineBuffer inlineBuf; CFRange componentRange; CFIndex length = CFStringGetLength(cacheControlHeader); bool done = false; CFCharacterSetRef whitespaceSet = CFCharacterSetGetPredefined(kCFCharacterSetWhitespace); CFStringRef maxAgeValue = NULL; CFStringInitInlineBuffer(cacheControlHeader, &inlineBuf, CFRangeMake(0, length)); componentRange.location = 0; while (!done) { bool inQuotes = false; bool foundComponentStart = false; CFIndex charIndex = componentRange.location; CFIndex componentEnd = -1; CFRange maxAgeRg; componentRange.length = 0; while (charIndex < length) { UniChar ch = CFStringGetCharacterFromInlineBuffer(&inlineBuf, charIndex); if (!inQuotes && ch == ',') { componentRange.length = charIndex - componentRange.location; break; } if (!CFCharacterSetIsCharacterMember(whitespaceSet, ch)) { if (!foundComponentStart) { foundComponentStart = true; componentRange.location = charIndex; } else { componentEnd = charIndex; } if (ch == '\"') { inQuotes = (inQuotes == false); } } charIndex ++; } if (componentEnd == -1) { componentRange.length = charIndex - componentRange.location; } else { componentRange.length = componentEnd - componentRange.location + 1; } if (charIndex == length) { /* Fell off the end; this is the last component. */ done = true; } /* componentRange should now contain the range of the current component; trimmed of any whitespace. */ /* We want to look for a max-age value. */ if (!maxAgeValue && CFStringFindWithOptions(cacheControlHeader, CFSTR("max-age"), componentRange, kCFCompareCaseInsensitive | kCFCompareAnchored, &maxAgeRg)) { CFIndex equalIdx; CFIndex maxCompRg = componentRange.location + componentRange.length; for (equalIdx = maxAgeRg.location + maxAgeRg.length; equalIdx < maxCompRg; equalIdx ++) { UniChar equalCh = CFStringGetCharacterFromInlineBuffer(&inlineBuf, equalIdx); if (equalCh == '=') { // Parse out max-age value equalIdx ++; while (equalIdx < maxCompRg && CFCharacterSetIsCharacterMember(whitespaceSet, CFStringGetCharacterAtIndex(cacheControlHeader, equalIdx))) { equalIdx ++; } if (equalIdx < maxCompRg) { maxAgeValue = CFStringCreateWithSubstring(kCFAllocatorDefault, cacheControlHeader, CFRangeMake(equalIdx, maxCompRg-equalIdx)); } } else if (!CFCharacterSetIsCharacterMember(whitespaceSet, equalCh)) { // Not a valid max-age header; break out doing nothing break; } } } if (!done && maxAgeValue) { done = true; } if (!done) { /* Advance to the next component; + 1 to get past the comma. */ componentRange.location = charIndex + 1; } } return maxAgeValue; }