static Boolean __CFStringAppendFormatCore()

in CoreFoundation/String.subproj/CFString.c [7155:7878]


static Boolean __CFStringAppendFormatCore(CFMutableStringRef outputString, CFStringRef (*copyDescFunc)(void *, const void *), CFStringRef (*contextDescFunc)(void *, const void *, const void *, bool, bool *), CFDictionaryRef formatOptions, CFDictionaryRef stringsDictConfig, CFStringRef validFormatSpecifiers, CFStringRef formatString, CFIndex initialArgPosition, const void *origValues, CFIndex originalValuesSize, va_list args, CFArrayRef *outReplacementMetadata, CFErrorRef *errorPtr) {
    int32_t numSpecs, sizeSpecs, sizeArgNum, formatIdx, curSpec, argNum;
    CFIndex formatLen;
    const uint8_t *cformat = NULL;
    const UniChar *uformat = NULL;
    UniChar *formatChars = NULL;
    UniChar localFormatBuffer[FORMAT_BUFFER_LEN];
    CFFormatSpec localSpecsBuffer[VPRINTF_BUFFER_LEN];
    CFFormatSpec *specs;
    CFPrintValue localValuesBuffer[VPRINTF_BUFFER_LEN];
    CFPrintValue *values;
    const CFPrintValue *originalValues = (const CFPrintValue *)origValues;
    CFDictionaryRef localConfigs[VPRINTF_BUFFER_LEN];
    CFDictionaryRef *configs;
    CFMutableDictionaryRef formattingConfig = NULL;
    CFIndex numConfigs;
    CFAllocatorRef tmpAlloc = NULL;
    bool localizedFormatting = formatOptions && (CFGetTypeID(formatOptions) == CFLocaleGetTypeID());
    
    CFMutableArrayRef metadataStorage = NULL;
    CFMutableArrayRef *metadata = outReplacementMetadata ? &metadataStorage : NULL;
    
    intmax_t dummyLocation;	    // A place for %n to do its thing in; should be the widest possible int value

    numSpecs = 0;
    sizeSpecs = 0;
    sizeArgNum = 0;
    numConfigs = 0;
    specs = NULL;
    values = NULL;
    configs = NULL;


    if (validFormatSpecifiers) {
        const uint8_t *cExpectedFormat = NULL;
        const UniChar *uExpectedFormat = NULL;
        UniChar *expectedFormatChars = NULL;
        UniChar expectedLocalFormatBuffer[FORMAT_BUFFER_LEN];
        CFFormatSpec *expectedSpecs = NULL;
        CFFormatSpec localExpectedSpecsBuffer[VPRINTF_BUFFER_LEN];
        CFStringRef *expectedFormatSpecs = NULL;
        CFStringRef expectedFormatSpecsBuffer[VPRINTF_BUFFER_LEN];
        
        CFIndex expectedFormatLen = CFStringGetLength(validFormatSpecifiers);
        __CFStringSetUpFormatAndSpecBuffers(validFormatSpecifiers, expectedFormatLen, &cExpectedFormat, &uExpectedFormat, &expectedFormatChars, expectedLocalFormatBuffer, &expectedSpecs, localExpectedSpecsBuffer, &expectedFormatSpecs, expectedFormatSpecsBuffer);
        
        SInt32 numExpectedSpecs = __CFStringFindFormatSpecifiersInString(cExpectedFormat, uExpectedFormat, expectedFormatLen, expectedSpecs, NULL, NULL);
        
        if (expectedFormatChars != expectedLocalFormatBuffer) CFAllocatorDeallocate(tmpAlloc, expectedFormatChars);
        if (expectedSpecs != localExpectedSpecsBuffer) CFAllocatorDeallocate(tmpAlloc, expectedSpecs);
        if (expectedFormatSpecs != expectedFormatSpecsBuffer) CFAllocatorDeallocate(tmpAlloc, expectedFormatSpecs);
        
        if (expectedFormatLen == 0 || numExpectedSpecs == 0) {
            if (errorPtr) {
                CFStringRef debugMsg = CFStringCreateWithFormat(tmpAlloc, NULL, CFSTR("Expected format '%@' is invalid"), validFormatSpecifiers);
                CFMutableDictionaryRef userInfo = CFDictionaryCreateMutable(tmpAlloc, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
                CFDictionarySetValue(userInfo, kCFErrorDebugDescriptionKey, debugMsg);
                *errorPtr = CFErrorCreate(tmpAlloc, kCFErrorDomainCocoa, NSFormattingError, userInfo);
                CFRelease(debugMsg);
                CFRelease(userInfo);
            }
            return false;
        }
        
        /* Validate expected format specifiers against untrusted format string */
            if (__CFStringValidateFormat(validFormatSpecifiers, formatString, 0, errorPtr) < 0) {
                return false;
            }
    }

    Boolean success = true;
    
    formatLen = CFStringGetLength(formatString);
    
    /* Avoid overflow of formatIdx in loops below that compare to formatIdx */
    if (formatLen > INT32_MAX) {
        if (errorPtr) *errorPtr = __CFCreateOverflowError();
        success = false;
        goto cleanup;
    }
    
    if (!CF_IS_OBJC(_kCFRuntimeIDCFString, formatString) && !CF_IS_SWIFT(CFStringGetTypeID(), formatString)) {
        __CFAssertIsString(formatString);
        if (!__CFStrIsUnicode(formatString)) {
            cformat = (const uint8_t *)__CFStrContents(formatString);
            if (cformat) cformat += __CFStrSkipAnyLengthByte(formatString);
        } else {
            uformat = (const UniChar *)__CFStrContents(formatString);
        }
    }
    if (!cformat && !uformat) {
        formatChars = (formatLen > FORMAT_BUFFER_LEN) ? (UniChar *)CFAllocatorAllocate(tmpAlloc = __CFGetDefaultAllocator(), formatLen * sizeof(UniChar), 0) : localFormatBuffer; 
	if (formatChars != localFormatBuffer && __CFOASafe) __CFSetLastAllocationEventName(formatChars, "CFString (temp)");
        CFStringGetCharacters(formatString, CFRangeMake(0, formatLen), formatChars);
        uformat = formatChars;
    }

    /* Compute an upper bound for the number of format specifications */
    if (cformat) {
        for (formatIdx = 0; formatIdx < formatLen; formatIdx++) {
            if ('%' == cformat[formatIdx]) {
                if (__builtin_sadd_overflow(sizeSpecs, 1, &sizeSpecs)) {
                    if (errorPtr) *errorPtr = __CFCreateOverflowError();
                    success = false;
                    goto cleanup;
                }
            }
        }
    } else {
        for (formatIdx = 0; formatIdx < formatLen; formatIdx++) {
            if ('%' == uformat[formatIdx]) {
                if (__builtin_sadd_overflow(sizeSpecs, 1, &sizeSpecs)) {
                    if (errorPtr) *errorPtr = __CFCreateOverflowError();
                    success = false;
                    goto cleanup;
                }
            }
        }
    }
    
    /* The code following this point makes multiple integer calcuations based off sizeSpecs, which is an upper-bound of the number of tokens in the string based on the number of '%' characters found. In order to avoid integer overflow at multiple points throughout this function, we will cap sizeSpec to an amount that won't overflow, but is still plenty large enough to support any reasonable format strings */
#define MAX_SIZE_SPECS (0xfffff) /* Won't overflow a 32-bit integer up to and including a multiplicative factor of 256 */
    if (sizeSpecs > MAX_SIZE_SPECS) {
        if (errorPtr) *errorPtr = __CFCreateOverflowError();
        success = false;
        goto cleanup;
    }
    
    tmpAlloc = __CFGetDefaultAllocator();
    specs = ((2 * sizeSpecs + 1) > VPRINTF_BUFFER_LEN) ? (CFFormatSpec *)CFAllocatorAllocate(tmpAlloc, (2 * sizeSpecs + 1) * sizeof(CFFormatSpec), 0) : localSpecsBuffer;
    if (specs != localSpecsBuffer && __CFOASafe) __CFSetLastAllocationEventName(specs, "CFString (temp)");

    configs = ((sizeSpecs < VPRINTF_BUFFER_LEN) ? localConfigs : (CFDictionaryRef *)CFAllocatorAllocate(tmpAlloc, sizeof(CFStringRef) * sizeSpecs, 0));

    /* Collect format specification information from the format string */
    for (curSpec = 0, formatIdx = 0; formatIdx < formatLen; curSpec++) {
	SInt32 newFmtIdx;
	specs[curSpec].loc = formatIdx;
	specs[curSpec].len = 0;
	specs[curSpec].size = 0;
	specs[curSpec].type = 0;
	specs[curSpec].flags = 0;
	specs[curSpec].widthArg = -1;
	specs[curSpec].precArg = -1;
	specs[curSpec].mainArgNum = -1;
	specs[curSpec].precArgNum = -1;
	specs[curSpec].widthArgNum = -1;
	specs[curSpec].configDictIndex = -1;
        if (cformat) {
            for (newFmtIdx = formatIdx; newFmtIdx < formatLen && '%' != cformat[newFmtIdx]; newFmtIdx++);
        } else {
            for (newFmtIdx = formatIdx; newFmtIdx < formatLen && '%' != uformat[newFmtIdx]; newFmtIdx++);
        }
	if (newFmtIdx != formatIdx) {	/* Literal chunk */
	    specs[curSpec].type = CFFormatLiteralType;
	    specs[curSpec].len = newFmtIdx - formatIdx;
	} else {
	    CFStringRef configKey = NULL;
	    newFmtIdx++;	/* Skip % */
            if (!__CFParseFormatSpec(uformat, cformat, &newFmtIdx, formatLen, &(specs[curSpec]), &configKey, errorPtr)) {
                success = false;
                goto cleanup;
            }
            if (CFFormatLiteralType == specs[curSpec].type) {
		specs[curSpec].loc = formatIdx + 1;
		specs[curSpec].len = 1;
                specs[curSpec].flags |= kCFStringFormatPercentReplacementFlag;
	    } else {
		specs[curSpec].len = newFmtIdx - formatIdx;
	    }
	}
	formatIdx = newFmtIdx;

// fprintf(stderr, "specs[%d] = {\n  size = %d,\n  type = %d,\n  loc = %d,\n  len = %d,\n  mainArgNum = %d,\n  precArgNum = %d,\n  widthArgNum = %d\n}\n", curSpec, specs[curSpec].size, specs[curSpec].type, specs[curSpec].loc, specs[curSpec].len, specs[curSpec].mainArgNum, specs[curSpec].precArgNum, specs[curSpec].widthArgNum);

    }
    numSpecs = curSpec;

    if (originalValues == NULL) {
        // Max of three args per spec, reasoning thus: 1 width, 1 prec, 1 value
        sizeArgNum = 3 * sizeSpecs + 1;
    } else {
#define MAX_SIZE_ORIGINAL_VALUES (0x2ffffe) /* Max size of original values is (3 * MAX_SIZE_SPECS + 1) */
        if (originalValuesSize > MAX_SIZE_ORIGINAL_VALUES) {
            if (errorPtr) *errorPtr = __CFCreateOverflowError();
            success = false;
            goto cleanup;
        }

        sizeArgNum = originalValuesSize;
    }

    values = (sizeArgNum > VPRINTF_BUFFER_LEN) ? (CFPrintValue *)CFAllocatorAllocate(tmpAlloc, sizeArgNum * sizeof(CFPrintValue), 0) : localValuesBuffer;
    if (values != localValuesBuffer && __CFOASafe) __CFSetLastAllocationEventName(values, "CFString (temp)");
    memset(values, 0, sizeArgNum * sizeof(CFPrintValue));

    va_list copiedArgs;
    if (numConfigs > 0) va_copy(copiedArgs, args); // we need to preserve the original state for passing down

    /* Compute values array */
    argNum = initialArgPosition;
    CFIndex validatedDictSpecs = 0;
    for (curSpec = 0; curSpec < numSpecs; curSpec++) {
	SInt32 newMaxArgNum;
	if (0 == specs[curSpec].type) continue;
	if (CFFormatLiteralType == specs[curSpec].type) continue;
        if (CFFormatIncompleteSpecifierType == specs[curSpec].type) continue;
	newMaxArgNum = sizeArgNum;
	if (newMaxArgNum < specs[curSpec].mainArgNum) {
	    newMaxArgNum = specs[curSpec].mainArgNum;
	}
	if (newMaxArgNum < specs[curSpec].precArgNum) {
	    newMaxArgNum = specs[curSpec].precArgNum;
	}
	if (newMaxArgNum < specs[curSpec].widthArgNum) {
	    newMaxArgNum = specs[curSpec].widthArgNum;
	}
	if (sizeArgNum < newMaxArgNum) {
	    if (specs != localSpecsBuffer) CFAllocatorDeallocate(tmpAlloc, specs);
	    if (values != localValuesBuffer) CFAllocatorDeallocate(tmpAlloc, values);
	    if (formatChars && (formatChars != localFormatBuffer)) CFAllocatorDeallocate(tmpAlloc, formatChars);
            
            // More arguments than expected - not an error case though.
	    return true;
	}
	/* It is actually incorrect to reorder some specs and not all; we just do some random garbage here */
	if (-2 == specs[curSpec].widthArgNum) {
	    specs[curSpec].widthArgNum = argNum++;
	}
	if (-2 == specs[curSpec].precArgNum) {
	    specs[curSpec].precArgNum = argNum++;
	}
	if (-1 == specs[curSpec].mainArgNum) {
	    specs[curSpec].mainArgNum = argNum++;
	}

	values[specs[curSpec].mainArgNum].size = specs[curSpec].size;
	values[specs[curSpec].mainArgNum].type = specs[curSpec].type;


	if (-1 != specs[curSpec].widthArgNum) {
	    values[specs[curSpec].widthArgNum].size = 0;
	    values[specs[curSpec].widthArgNum].type = CFFormatLongType;
	}
	if (-1 != specs[curSpec].precArgNum) {
	    values[specs[curSpec].precArgNum].size = 0;
	    values[specs[curSpec].precArgNum].type = CFFormatLongType;
	}
    }
    
    CFIndex validatedInnerSpecs = 0;
    /* Collect the arguments in correct type from vararg list */
    for (argNum = 0; argNum < sizeArgNum; argNum++) {
	if ((NULL != originalValues) && (0 == values[argNum].type)) values[argNum] = originalValues[argNum];
	switch (values[argNum].type) {
	case 0:
        case CFFormatIncompleteSpecifierType:
	case CFFormatLiteralType:
	    break;
	case CFFormatLongType:
        case CFFormatSingleUnicharType:
	    if (CFFormatSize1 == values[argNum].size) {
		values[argNum].value.int64Value = (int64_t)(int8_t)va_arg(args, int);
	    } else if (CFFormatSize2 == values[argNum].size) {
		values[argNum].value.int64Value = (int64_t)(int16_t)va_arg(args, int);
	    } else if (CFFormatSize4 == values[argNum].size) {
		values[argNum].value.int64Value = (int64_t)va_arg(args, int32_t);
	    } else if (CFFormatSize8 == values[argNum].size) {
		values[argNum].value.int64Value = (int64_t)va_arg(args, int64_t);
	    } else {
		values[argNum].value.int64Value = (int64_t)va_arg(args, int);
	    }
	    break;
	case CFFormatDoubleType:
#if LONG_DOUBLE_SUPPORT
	    if (CFFormatSize16 == values[argNum].size) {
		values[argNum].value.longDoubleValue = va_arg(args, long double);
	    } else 
#endif
	    {
		values[argNum].value.doubleValue = va_arg(args, double);
	    }
	    break;
	case CFFormatPointerType:
	case CFFormatCFType:
	case CFFormatUnicharsType:
	case CFFormatCharsType:
	case CFFormatPascalCharsType:
	    values[argNum].value.pointerValue = va_arg(args, void *);
	    break;
	case CFFormatDummyPointerType:
	    (void)va_arg(args, void *);	    // Skip the provided argument
	    values[argNum].value.pointerValue = &dummyLocation;
	    break;
	}
    }
    va_end(args);

    /* Format the pieces together */

    if (NULL == originalValues) {
	originalValues = values;
	originalValuesSize = sizeArgNum;
    }

    SInt32 numSpecsContext = 0;
    CFFormatSpec *specsContext = NULL;
    if (numSpecs > 0) {
        specsContext = (CFFormatSpec *)calloc(numSpecs, sizeof(CFFormatSpec));
    }
    const CFStringRef replacement = CFSTR("%@NSCONTEXT");
    
    for (curSpec = 0; curSpec < numSpecs; curSpec++) {
	SInt32 width = 0, precision = 0;
	UniChar *up, ch;
	Boolean hasWidth = false, hasPrecision = false;

	// widthArgNum and widthArg are never set at the same time; same for precArg*
	if (-1 != specs[curSpec].widthArgNum) {
	    width = (SInt32)values[specs[curSpec].widthArgNum].value.int64Value;
	    hasWidth = true;
	}
	if (-1 != specs[curSpec].precArgNum) {
	    precision = (SInt32)values[specs[curSpec].precArgNum].value.int64Value;
	    hasPrecision = true;
	}
	if (-1 != specs[curSpec].widthArg) {
	    width = specs[curSpec].widthArg;
	    hasWidth = true;
	}
	if (-1 != specs[curSpec].precArg) {
	    precision = specs[curSpec].precArg;
	    hasPrecision = true;
	}

#define __CFStringFormatOutputLengthIfNeeded() (metadata ? CFStringGetLength(outputString) : 0)
        CFIndex oldLength = 0;
        
	switch (specs[curSpec].type) {
	case CFFormatLongType:
	case CFFormatDoubleType:
#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX
            if (localizedFormatting && (specs[curSpec].flags & kCFStringFormatLocalizable)) {    // We have a locale, so we do localized formatting
                oldLength = __CFStringFormatOutputLengthIfNeeded();
                if (__CFStringFormatLocalizedNumber(outputString, (CFLocaleRef)formatOptions, values, &specs[curSpec], width, precision, hasPrecision)) {
                    _CFStringFormatAppendMetadata(metadata, numSpecs, values, sizeArgNum, specs[curSpec], oldLength, __CFStringFormatOutputLengthIfNeeded());
                    break;
                }
            }
            /* Otherwise fall-thru to the next case! */
#endif
         case CFFormatPointerType: {
             char stackFormatBuffer[128];
             char *dynamicFormatBuffer = NULL;
             char *formatBuffer = stackFormatBuffer;
             if (specs[curSpec].len + 1 > sizeof(stackFormatBuffer)) {
                 // Leave space for the null terminator (+1)
                 dynamicFormatBuffer = (char *)CFAllocatorAllocate(kCFAllocatorSystemDefault, specs[curSpec].len + 1, 0);
                 formatBuffer = dynamicFormatBuffer;
             }
#define EXTRA_BUFFER_LEN_FOR_WIDTH_PRECISION (16)
                char stackBuffer[BUFFER_LEN + EXTRA_BUFFER_LEN_FOR_WIDTH_PRECISION];
                char *dynamicBuffer = NULL;
                char *buffer = stackBuffer;
                size_t bufferSize = sizeof(stackBuffer);
                if (width + precision > EXTRA_BUFFER_LEN_FOR_WIDTH_PRECISION) {
                    bufferSize = BUFFER_LEN + width + precision;
                    dynamicBuffer = (char *)CFAllocatorAllocate(kCFAllocatorSystemDefault, bufferSize, 0);
                    buffer = dynamicBuffer;
                }
                SInt32 cidx, idx, loc;
		Boolean appended = false;
                loc = specs[curSpec].loc;
                // In preparation to call snprintf(), copy the format string out
                if (cformat) {
                    for (idx = 0, cidx = 0; cidx < specs[curSpec].len; idx++, cidx++) {
                        if ('$' == cformat[loc + cidx]) {
                            if (idx > -1) {
                                for (idx--; '0' <= formatBuffer[idx] && formatBuffer[idx] <= '9'; idx--);
                            }
                        } else {
                            formatBuffer[idx] = cformat[loc + cidx];
                        }
                    }
                } else {
                    for (idx = 0, cidx = 0; cidx < specs[curSpec].len; idx++, cidx++) {
                        if ('$' == uformat[loc + cidx]) {
                            if (idx > -1) {
                                for (idx--; '0' <= formatBuffer[idx] && formatBuffer[idx] <= '9'; idx--);
                            }
                        } else {
                            formatBuffer[idx] = (int8_t)uformat[loc + cidx];
                        }
                    }
                }
                formatBuffer[idx] = '\0';
		// Should modify format buffer here if necessary; for example, to translate %qd to
		// the equivalent, on architectures which do not have %q.
                buffer[bufferSize - 1] = '\0';
                oldLength = __CFStringFormatOutputLengthIfNeeded();
                switch (specs[curSpec].type) {
                    case CFFormatLongType:
                        if (CFFormatSize8 == specs[curSpec].size) {
                            SNPRINTF(int64_t, values[specs[curSpec].mainArgNum].value.int64Value)
                        } else {
                            SNPRINTF(SInt32, values[specs[curSpec].mainArgNum].value.int64Value)
                        }
                        break;
                    case CFFormatPointerType:
                    case CFFormatDummyPointerType:
                        SNPRINTF(void *, values[specs[curSpec].mainArgNum].value.pointerValue)
                        break;

                    case CFFormatDoubleType:
#if LONG_DOUBLE_SUPPORT
                        if (CFFormatSize16 == specs[curSpec].size) {
			    SNPRINTF(long double, values[specs[curSpec].mainArgNum].value.longDoubleValue)
			} else 
#endif
			{
			    SNPRINTF(double, values[specs[curSpec].mainArgNum].value.doubleValue)
			}
			// See if we need to localize the decimal point
                        if (formatOptions) {	// We have localization info
#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_LINUX || TARGET_OS_BSD
			    CFStringRef decimalSeparator = (CFGetTypeID(formatOptions) == CFLocaleGetTypeID()) ? (CFStringRef)CFLocaleGetValue((CFLocaleRef)formatOptions, kCFLocaleDecimalSeparatorKey) : (CFStringRef)CFDictionaryGetValue(formatOptions, CFSTR("NSDecimalSeparator"));
#else
                            CFStringRef decimalSeparator = CFSTR(".");
#endif
                            if (decimalSeparator != NULL) {	// We have a decimal separator in there
                                CFIndex decimalPointLoc = 0;
                                while (buffer[decimalPointLoc] != 0 && buffer[decimalPointLoc] != '.') decimalPointLoc++;
                                if (buffer[decimalPointLoc] == '.') {	// And we have a decimal point in the formatted string
                                    buffer[decimalPointLoc] = 0;
                                    CFStringAppendCString(outputString, (const char *)buffer, __CFStringGetEightBitStringEncoding());
                                    CFStringAppend(outputString, decimalSeparator);
                                    CFStringAppendCString(outputString, (const char *)(buffer + decimalPointLoc + 1), __CFStringGetEightBitStringEncoding());
                                    appended = true;
                                }
                            }
                        }
                        break;
                }
                if (!appended) CFStringAppendCString(outputString, (const char *)buffer, __CFStringGetEightBitStringEncoding());
                _CFStringFormatAppendMetadata(metadata, numSpecs, values, sizeArgNum, specs[curSpec], oldLength, __CFStringFormatOutputLengthIfNeeded());
                if (dynamicBuffer) {
                        CFAllocatorDeallocate(kCFAllocatorSystemDefault, dynamicBuffer);
                }
             if (dynamicFormatBuffer) {
                 CFAllocatorDeallocate(kCFAllocatorSystemDefault, dynamicFormatBuffer);
             }
            }
            break;
	case CFFormatLiteralType:
            oldLength = __CFStringFormatOutputLengthIfNeeded();
            if (cformat) {
                __CFStringAppendBytes(outputString, (const char *)(cformat+specs[curSpec].loc), specs[curSpec].len, __CFStringGetEightBitStringEncoding());
            } else {
                CFStringAppendCharacters(outputString, uformat+specs[curSpec].loc, specs[curSpec].len);
            }
            _CFStringFormatAppendMetadata(metadata, numSpecs, values, sizeArgNum, specs[curSpec], oldLength, __CFStringFormatOutputLengthIfNeeded());
	    break;
        case CFFormatIncompleteSpecifierType:
            oldLength = __CFStringFormatOutputLengthIfNeeded();
            _CFStringFormatAppendMetadata(metadata, numSpecs, values, sizeArgNum, specs[curSpec], oldLength, oldLength);
            break;
	case CFFormatPascalCharsType:
        case CFFormatCharsType:
            oldLength = __CFStringFormatOutputLengthIfNeeded();
	    if (values[specs[curSpec].mainArgNum].value.pointerValue == NULL) {
		CFStringAppendCString(outputString, "(null)", kCFStringEncodingASCII);
            } else {
                int len;
                const char *str = (const char *)values[specs[curSpec].mainArgNum].value.pointerValue;
                if (specs[curSpec].type == CFFormatPascalCharsType) {	// Pascal string case
                    len = ((unsigned char *)str)[0];
                    str++;
                    if (hasPrecision && precision < len) len = precision;
                } else {	// C-string case
                    if (!hasPrecision) {	// No precision, so rely on the terminating null character
                        len = strlen(str);
                    } else {	// Don't blindly call strlen() if there is a precision; the string might not have a terminating null (3131988)
                        const char *terminatingNull = (const char *)memchr(str, 0, precision);	// Basically strlen() on only the first precision characters of str
                        if (terminatingNull) {	// There was a null in the first precision characters
                            len = terminatingNull - str;
                        } else {
                            len = precision;
                        }
                    }
                }
		// Since the spec says the behavior of the ' ', '0', '#', and '+' flags is undefined for
		// '%s', and since we have ignored them in the past, the behavior is hereby cast in stone
		// to ignore those flags (and, say, never pad with '0' instead of space).
		if (specs[curSpec].flags & kCFStringFormatMinusFlag) {
		    __CFStringAppendBytes(outputString, str, len, __CFStringGetSystemEncoding());
		    if (hasWidth && width > len) {
			int w = width - len;	// We need this many spaces; do it ten at a time
			do {__CFStringAppendBytes(outputString, "          ", (w > 10 ? 10 : w), kCFStringEncodingASCII);} while ((w -= 10) > 0);
		    }
		} else {
		    if (hasWidth && width > len) {
			int w = width - len;	// We need this many spaces; do it ten at a time
			do {__CFStringAppendBytes(outputString, "          ", (w > 10 ? 10 : w), kCFStringEncodingASCII);} while ((w -= 10) > 0);
		    }
		    __CFStringAppendBytes(outputString, str, len, __CFStringGetSystemEncoding());
		}
	    }
            _CFStringFormatAppendMetadata(metadata, numSpecs, values, sizeArgNum,  specs[curSpec], oldLength, __CFStringFormatOutputLengthIfNeeded());
            break;
        case CFFormatSingleUnicharType:
            oldLength = __CFStringFormatOutputLengthIfNeeded();
            ch = (UniChar)values[specs[curSpec].mainArgNum].value.int64Value;
            CFStringAppendCharacters(outputString, &ch, 1);
            _CFStringFormatAppendMetadata(metadata, numSpecs, values, sizeArgNum, specs[curSpec], oldLength, __CFStringFormatOutputLengthIfNeeded());
            break;
        case CFFormatUnicharsType:
            oldLength = __CFStringFormatOutputLengthIfNeeded();
            up = (UniChar *)values[specs[curSpec].mainArgNum].value.pointerValue;
            if (NULL == up) {
                CFStringAppendCString(outputString, "(null)", kCFStringEncodingASCII);
            } else {
                int len;
                if (hasPrecision) {
                    // if we have precision, still pay attention to earlier null termination, as we do with %s (19784466)
                    for (len = 0; (len < precision) && (0 != up[len]); len++);
                } else {
                    // if no precision, then simply find the length
                    for (len = 0; 0 != up[len]; len++);
                }
		// Since the spec says the behavior of the ' ', '0', '#', and '+' flags is undefined for
		// '%s', and since we have ignored them in the past, the behavior is hereby cast in stone
		// to ignore those flags (and, say, never pad with '0' instead of space).
		if (specs[curSpec].flags & kCFStringFormatMinusFlag) {
		    CFStringAppendCharacters(outputString, up, len);
		    if (hasWidth && width > len) {
			int w = width - len;	// We need this many spaces; do it ten at a time
			do {__CFStringAppendBytes(outputString, "          ", (w > 10 ? 10 : w), kCFStringEncodingASCII);} while ((w -= 10) > 0);
		    }
		} else {
		    if (hasWidth && width > len) {
			int w = width - len;	// We need this many spaces; do it ten at a time
			do {__CFStringAppendBytes(outputString, "          ", (w > 10 ? 10 : w), kCFStringEncodingASCII);} while ((w -= 10) > 0);
		    }
		    CFStringAppendCharacters(outputString, up, len);
		}
            }
            _CFStringFormatAppendMetadata(metadata, numSpecs, values, sizeArgNum, specs[curSpec], oldLength, __CFStringFormatOutputLengthIfNeeded());
            break;
	case CFFormatCFType:
            oldLength = __CFStringFormatOutputLengthIfNeeded();
	    if (specs[curSpec].configDictIndex != -1) { // config dict
		CFTypeRef object = NULL;
		switch (values[specs[curSpec].mainArgNum].type) {
		    case CFFormatLongType:
			object = CFNumberCreate(tmpAlloc, kCFNumberSInt64Type, &(values[specs[curSpec].mainArgNum].value.int64Value));
			break;
			
		    case CFFormatDoubleType:
#if LONG_DOUBLE_SUPPORT
			if (CFFormatSize16 == values[specs[curSpec].mainArgNum].size) {
			    double aValue = values[specs[curSpec].mainArgNum].value.longDoubleValue; // losing precision

			    object = CFNumberCreate(tmpAlloc, kCFNumberDoubleType, &aValue);
			} else
#endif
			{
			    object = CFNumberCreate(tmpAlloc, kCFNumberDoubleType, &(values[specs[curSpec].mainArgNum].value.doubleValue));
			}
			break;

		    case CFFormatPointerType:
			object = CFNumberCreate(tmpAlloc, kCFNumberCFIndexType, &(values[specs[curSpec].mainArgNum].value.pointerValue));
			break;

		    case CFFormatPascalCharsType:
		    case CFFormatCharsType:
			if (NULL != values[specs[curSpec].mainArgNum].value.pointerValue) {
			    CFMutableStringRef aString = CFStringCreateMutable(tmpAlloc, 0);
			    int len;
			    const char *str = (const char *)values[specs[curSpec].mainArgNum].value.pointerValue;
			    if (specs[curSpec].type == CFFormatPascalCharsType) {	// Pascal string case
				len = ((unsigned char *)str)[0];
				str++;
				if (hasPrecision && precision < len) len = precision;
			    } else {	// C-string case
				if (!hasPrecision) {	// No precision, so rely on the terminating null character
				    len = strlen(str);
				} else {	// Don't blindly call strlen() if there is a precision; the string might not have a terminating null (3131988)
				    const char *terminatingNull = (const char *)memchr(str, 0, precision);	// Basically strlen() on only the first precision characters of str
				    if (terminatingNull) {	// There was a null in the first precision characters
					len = terminatingNull - str;
				    } else {
					len = precision;
				    }
				}
			    }
			    // Since the spec says the behavior of the ' ', '0', '#', and '+' flags is undefined for
			    // '%s', and since we have ignored them in the past, the behavior is hereby cast in stone
			    // to ignore those flags (and, say, never pad with '0' instead of space).
			    if (specs[curSpec].flags & kCFStringFormatMinusFlag) {
				__CFStringAppendBytes(aString, str, len, __CFStringGetSystemEncoding());
				if (hasWidth && width > len) {
				    int w = width - len;	// We need this many spaces; do it ten at a time
				    do {__CFStringAppendBytes(aString, "          ", (w > 10 ? 10 : w), kCFStringEncodingASCII);} while ((w -= 10) > 0);
				}
			    } else {
				if (hasWidth && width > len) {
				    int w = width - len;	// We need this many spaces; do it ten at a time
				    do {__CFStringAppendBytes(aString, "          ", (w > 10 ? 10 : w), kCFStringEncodingASCII);} while ((w -= 10) > 0);
				}
				__CFStringAppendBytes(aString, str, len, __CFStringGetSystemEncoding());
			    }

			    object = aString;
			}
			break;

		    case CFFormatSingleUnicharType:
			ch = (UniChar)values[specs[curSpec].mainArgNum].value.int64Value;
			object = CFStringCreateWithCharactersNoCopy(tmpAlloc, &ch, 1, kCFAllocatorNull);
			break;

		    case CFFormatUnicharsType:
			//??? need to handle width, precision, and padding arguments
			up = (UniChar *)values[specs[curSpec].mainArgNum].value.pointerValue;
			if (NULL != up) {
			    CFMutableStringRef aString = CFStringCreateMutable(tmpAlloc, 0);
			    int len;
			    for (len = 0; 0 != up[len]; len++);
			    // Since the spec says the behavior of the ' ', '0', '#', and '+' flags is undefined for
			    // '%s', and since we have ignored them in the past, the behavior is hereby cast in stone
			    // to ignore those flags (and, say, never pad with '0' instead of space).
			    if (hasPrecision && precision < len) len = precision;
			    if (specs[curSpec].flags & kCFStringFormatMinusFlag) {
				CFStringAppendCharacters(aString, up, len);
				if (hasWidth && width > len) {
				    int w = width - len;	// We need this many spaces; do it ten at a time
				    do {__CFStringAppendBytes(aString, "          ", (w > 10 ? 10 : w), kCFStringEncodingASCII);} while ((w -= 10) > 0);
				}
			    } else {
				if (hasWidth && width > len) {
				    int w = width - len;	// We need this many spaces; do it ten at a time
				    do {__CFStringAppendBytes(aString, "          ", (w > 10 ? 10 : w), kCFStringEncodingASCII);} while ((w -= 10) > 0);
				}
				CFStringAppendCharacters(aString, up, len);
			    }
			    object = aString;
			}
			break;

		    case CFFormatCFType:
			if (NULL != values[specs[curSpec].mainArgNum].value.pointerValue) object = CFRetain(values[specs[curSpec].mainArgNum].value.pointerValue);
			break;
		}

		if (NULL != object) CFRelease(object);
                
	    } else if (NULL != values[specs[curSpec].mainArgNum].value.pointerValue) {
                CFStringRef str = NULL;
                if (contextDescFunc) {
                    bool found = NO;
                    str = contextDescFunc(values[specs[curSpec].mainArgNum].value.pointerValue, formatString, replacement, NO, &found);
                    if (found) {
                        str = CFRetain(replacement);
                        specsContext[numSpecsContext] = specs[curSpec];
                        numSpecsContext++;
                    }
                }
                if (!str) {
                    if (copyDescFunc) {
                        str = copyDescFunc(values[specs[curSpec].mainArgNum].value.pointerValue, formatOptions);
                    } else {
                        str = __CFCopyFormattingDescription(values[specs[curSpec].mainArgNum].value.pointerValue, formatOptions);
                        if (NULL == str) {
                            str = CFCopyDescription(values[specs[curSpec].mainArgNum].value.pointerValue);
                        }
                    }
                }
                if (str) {
                        CFStringAppend(outputString, str);
                    CFRelease(str);
                } else {
                    CFStringAppendCString(outputString, "(null description)", kCFStringEncodingASCII);
                }
            } else {
		CFStringAppendCString(outputString, "(null)", kCFStringEncodingASCII);
            }
            _CFStringFormatAppendMetadata(metadata, numSpecs, values, sizeArgNum, specs[curSpec], oldLength, __CFStringFormatOutputLengthIfNeeded());
            break;
        }
        if (validFormatSpecifiers && specs[curSpec].type != CFFormatLiteralType && specs[curSpec].configDictIndex == -1) {
            // We already took care of confirming special strings with config dictionaries;
            // this makes other types of specs as validated as well
            validatedInnerSpecs += 1;
        }
    }
    
    for (SInt32 i = 0; i < numSpecsContext; i++) {
        CFRange range = CFStringFind(outputString, replacement, 0);
        CFStringRef str = contextDescFunc(values[specsContext[i].mainArgNum].value.pointerValue, outputString, replacement, true, NULL);
        if (str) {
            CFStringReplace(outputString, range, str);
            CFRelease(str);
        }
    }

    free(specsContext);

cleanup:

    if (numConfigs > 0) va_end(copiedArgs);
    if (specs != localSpecsBuffer) CFAllocatorDeallocate(tmpAlloc, specs);
    if (values != localValuesBuffer) CFAllocatorDeallocate(tmpAlloc, values);
    if (formatChars && (formatChars != localFormatBuffer)) CFAllocatorDeallocate(tmpAlloc, formatChars);
    if (configs != localConfigs) CFAllocatorDeallocate(tmpAlloc, configs);
    if (formattingConfig != NULL) CFRelease(formattingConfig);
    
    if (metadataStorage && outReplacementMetadata) {
        *outReplacementMetadata = CFArrayCreateCopy(kCFAllocatorSystemDefault, metadataStorage);
        CFRelease(metadataStorage);
    }
    
    return success;
}