]> git.saurik.com Git - apple/cf.git/blobdiff - CFNumberFormatter.c
CF-550.tar.gz
[apple/cf.git] / CFNumberFormatter.c
index 12e2a635c3e2ad153f312099dde37e4cfb541be6..cde8c2b303590310ca9fe414721d399dbc7e1dd9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
 /*     CFNumberFormatter.c
-       Copyright 2002-2003, Apple, Inc. All rights reserved.
+       Copyright (c) 2002-2009, Apple Inc. All rights reserved.
        Responsibility: Christopher Kane
 */
 
 #include <CoreFoundation/CFNumberFormatter.h>
 #include "CFInternal.h"
+#include "CFLocaleInternal.h"
 #include <unicode/unum.h>
 #include <unicode/ucurr.h>
 #include <math.h>
 #include <float.h>
 
 static void __CFNumberFormatterCustomize(CFNumberFormatterRef formatter);
+static CFStringRef __CFNumberFormatterCreateCompressedString(CFStringRef inString, Boolean isFormat, CFRange *rangep);
+static UErrorCode __CFNumberFormatterApplyPattern(CFNumberFormatterRef formatter, CFStringRef pattern);
 
 #define BUFFER_SIZE 768
 
@@ -43,8 +46,11 @@ struct __CFNumberFormatter {
     CFNumberFormatterStyle _style;
     CFStringRef _format;       // NULL for RBNFs
     CFStringRef _defformat;
+    CFStringRef _compformat;
     CFNumberRef _multiplier;
     CFStringRef _zeroSym;
+    Boolean _isLenient;
+    Boolean _userSetMultiplier;
 };
 
 static CFStringRef __CFNumberFormatterCopyDescription(CFTypeRef cf) {
@@ -58,6 +64,7 @@ static void __CFNumberFormatterDeallocate(CFTypeRef cf) {
     if (formatter->_locale) CFRelease(formatter->_locale);
     if (formatter->_format) CFRelease(formatter->_format);
     if (formatter->_defformat) CFRelease(formatter->_defformat);
+    if (formatter->_compformat) CFRelease(formatter->_compformat);
     if (formatter->_multiplier) CFRelease(formatter->_multiplier);
     if (formatter->_zeroSym) CFRelease(formatter->_zeroSym);
 }
@@ -99,8 +106,11 @@ CFNumberFormatterRef CFNumberFormatterCreate(CFAllocatorRef allocator, CFLocaleR
     memory->_locale = NULL;
     memory->_format = NULL;
     memory->_defformat = NULL;
+    memory->_compformat = NULL;
     memory->_multiplier = NULL;
     memory->_zeroSym = NULL;
+    memory->_isLenient = false;
+    memory->_userSetMultiplier = false;
     if (NULL == locale) locale = CFLocaleGetSystem();
     memory->_style = style;
     uint32_t ustyle;
@@ -153,6 +163,7 @@ CFNumberFormatterRef CFNumberFormatterCreate(CFAllocatorRef allocator, CFLocaleR
        }
     }
     memory->_defformat = memory->_format ? (CFStringRef)CFRetain(memory->_format) : NULL;
+    memory->_compformat = memory->_format ? __CFNumberFormatterCreateCompressedString(memory->_format, true, NULL) : NULL;
     if (kCFNumberFormatterSpellOutStyle != memory->_style) {
        int32_t n = unum_getAttribute(memory->_nf, UNUM_MULTIPLIER);
        if (1 != n) {
@@ -160,6 +171,7 @@ CFNumberFormatterRef CFNumberFormatterCreate(CFAllocatorRef allocator, CFLocaleR
            unum_setAttribute(memory->_nf, UNUM_MULTIPLIER, 1);
        }
     }
+    unum_setAttribute(memory->_nf, UNUM_LENIENT_PARSE, 0);
     return (CFNumberFormatterRef)memory;
 }
 
@@ -217,15 +229,7 @@ static void __substituteFormatStringFromPrefsNF(CFNumberFormatterRef formatter)
                        CFRange result;
                        if (CFStringFindWithOptions(formatString, numberString, CFRangeMake(0, formatter_len), 0, &result)) {
                            CFStringReplace(formatString, result, pref);
-                           int32_t new_len = CFStringGetLength(formatString);
-                           STACK_BUFFER_DECL(UChar, new_buffer, new_len);
-                           const UChar *new_ustr = (const UChar *)CFStringGetCharactersPtr(formatString);
-                           if (NULL == new_ustr) {
-                               CFStringGetCharacters(formatString, CFRangeMake(0, new_len), (UniChar *)new_buffer);
-                               new_ustr = new_buffer;
-                           }
-                           status = U_ZERO_ERROR;
-                           unum_applyPattern(formatter->_nf, false, new_ustr, new_len, NULL, &status);
+                           __CFNumberFormatterApplyPattern(formatter, formatString);
                        }
                        CFRelease(formatString);
                    }
@@ -237,6 +241,40 @@ static void __substituteFormatStringFromPrefsNF(CFNumberFormatterRef formatter)
     }
 }
 
+static UniChar __CFNumberFormatterNormalizeCharacter(UniChar c) {
+    if (CFCharacterSetIsCharacterMember(CFCharacterSetGetPredefined(kCFCharacterSetWhitespace), c)) {
+       return ' ';
+    } else {
+       return c;
+    }
+}
+
+/* Attempt to match the unimplemented lenient parsing behavior described at http://www.unicode.org/reports/tr35/#Lenient_Parsing -- specifically any whitespace is ignored that does not exist between two letters or two numbers, and no-break spaces map to spaces. */
+static CFStringRef __CFNumberFormatterCreateCompressedString(CFStringRef inString, Boolean isFormat, CFRange *rangep) {
+    if (!inString) return NULL;
+    CFRange range = { 0, 0 };
+    if (rangep) {
+       range = *rangep;
+    } else {
+       range.length = CFStringGetLength(inString);
+    }
+    CFMutableStringRef outString = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
+    CFCharacterSetRef letters = CFCharacterSetGetPredefined(kCFCharacterSetLetter);
+    CFCharacterSetRef numbers = CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit);
+    UniChar prevCh = 0, nextCh = 0;
+    Boolean inQuote = false;
+    for (CFIndex in_idx = range.location; in_idx < range.location + range.length; in_idx++) {
+        UniChar ch = __CFNumberFormatterNormalizeCharacter(CFStringGetCharacterAtIndex(inString, in_idx));
+       nextCh = (in_idx+1 < range.length) ? CFStringGetCharacterAtIndex(inString, in_idx+1) : 0;
+       if (isFormat && ch == '\'') inQuote = !inQuote;
+       if (inQuote || ch != ' ' || (CFCharacterSetIsCharacterMember(letters, prevCh) && CFCharacterSetIsCharacterMember(letters, nextCh)) || (CFCharacterSetIsCharacterMember(numbers, prevCh) && CFCharacterSetIsCharacterMember(numbers, nextCh))) {
+           CFStringAppendCharacters(outString, &ch, 1);
+           prevCh = ch;
+       }
+    }
+    return outString;
+}
+
 static void __CFNumberFormatterApplySymbolPrefs(const void *key, const void *value, void *context) {
     if (CFGetTypeID(key) == CFStringGetTypeID() && CFGetTypeID(value) == CFStringGetTypeID()) {
        CFNumberFormatterRef formatter = (CFNumberFormatterRef)context;
@@ -254,6 +292,35 @@ static void __CFNumberFormatterApplySymbolPrefs(const void *key, const void *val
    }
 }
 
+static UErrorCode __CFNumberFormatterApplyPattern(CFNumberFormatterRef formatter, CFStringRef pattern) {
+    CFIndex cnt = CFStringGetLength(pattern);
+    STACK_BUFFER_DECL(UChar, ubuffer, cnt);
+    const UChar *ustr = (const UChar *)CFStringGetCharactersPtr(pattern);
+    if (NULL == ustr) {
+       CFStringGetCharacters(pattern, CFRangeMake(0, cnt), (UniChar *)ubuffer);
+       ustr = ubuffer;
+    }
+    UErrorCode status = U_ZERO_ERROR;
+    unum_applyPattern(formatter->_nf, false, ustr, cnt, NULL, &status);
+
+    // unum_applyPattern() may have magically changed other attributes based on
+    // the contents of the format string; we simply expose that ICU behavior, except
+    // for UNUM_MULTIPLIER, which we re-read and reset, like we did at initialization
+    // time though any user-set multiplier state takes precedence.
+    if (formatter->_userSetMultiplier) {
+       unum_setAttribute(formatter->_nf, UNUM_MULTIPLIER, 1);
+    } else {
+       if (formatter->_multiplier) CFRelease(formatter->_multiplier);
+        formatter->_multiplier = NULL;
+        int32_t n = unum_getAttribute(formatter->_nf, UNUM_MULTIPLIER);
+        if (1 != n) {
+           formatter->_multiplier = CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
+           unum_setAttribute(formatter->_nf, UNUM_MULTIPLIER, 1);
+        }
+    }
+    return status;
+}
+
 static void __CFNumberFormatterCustomize(CFNumberFormatterRef formatter) {
     __substituteFormatStringFromPrefsNF(formatter);
     CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale);
@@ -285,9 +352,13 @@ CFStringRef CFNumberFormatterGetFormat(CFNumberFormatterRef formatter) {
     }
     if (newString && !formatter->_format) {
        formatter->_format = newString;
+       if (formatter->_compformat) CFRelease(formatter->_compformat);
+       formatter->_compformat = __CFNumberFormatterCreateCompressedString(formatter->_format, true, NULL);
     } else if (newString && !CFEqual(newString, formatter->_format)) {
        CFRelease(formatter->_format);
        formatter->_format = newString;
+       if (formatter->_compformat) CFRelease(formatter->_compformat);
+       formatter->_compformat = __CFNumberFormatterCreateCompressedString(formatter->_format, true, NULL);
     } else if (newString) {
        CFRelease(newString);
     }
@@ -301,21 +372,16 @@ void CFNumberFormatterSetFormat(CFNumberFormatterRef formatter, CFStringRef form
     CFIndex cnt = CFStringGetLength(formatString);
     CFAssert1(cnt <= 1024, __kCFLogAssertion, "%s(): format string too long", __PRETTY_FUNCTION__);
     if ((!formatter->_format || !CFEqual(formatter->_format, formatString)) && cnt <= 1024) {
-       STACK_BUFFER_DECL(UChar, ubuffer, cnt);
-       const UChar *ustr = (const UChar *)CFStringGetCharactersPtr(formatString);
-       if (NULL == ustr) {
-           CFStringGetCharacters(formatString, CFRangeMake(0, cnt), (UniChar *)ubuffer);
-           ustr = ubuffer;
-       }
-       UErrorCode status = U_ZERO_ERROR;
-       unum_applyPattern(formatter->_nf, false, ustr, cnt, NULL, &status);
+       UErrorCode status = __CFNumberFormatterApplyPattern(formatter, formatString);
        if (U_SUCCESS(status)) {
-           if (formatter->_format) CFRelease(formatter->_format);
            UChar ubuffer2[BUFFER_SIZE];
            status = U_ZERO_ERROR;
            int32_t ret = unum_toPattern(formatter->_nf, false, ubuffer2, BUFFER_SIZE, &status);
            if (U_SUCCESS(status) && ret <= BUFFER_SIZE) {
+               if (formatter->_format) CFRelease(formatter->_format);
                formatter->_format = CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer2, ret);
+               if (formatter->_compformat) CFRelease(formatter->_compformat);
+               formatter->_compformat = __CFNumberFormatterCreateCompressedString(formatter->_format, true, NULL);
            }
        }
     }
@@ -335,7 +401,14 @@ CFStringRef CFNumberFormatterCreateStringWithNumber(CFAllocatorRef allocator, CF
 #define FORMAT(T, FUNC)                                                        \
        T value = *(T *)valuePtr;                                       \
        if (0 == value && formatter->_zeroSym) { return (CFStringRef)CFRetain(formatter->_zeroSym); }   \
-       if (1.0 != multiplier) value = (T)(value * multiplier);         \
+       if (1.0 != multiplier) {                                        \
+               double dummy;                                           \
+               if (modf(multiplier, &dummy) < FLT_EPSILON) { /* float epsilon specifically chosen cuz it is a bit bigger */    \
+                       value = value * (T)floor(multiplier);           \
+               } else {                                                \
+                       value = (T)(value * multiplier);                \
+               }                                                       \
+       }                                                               \
        status = U_ZERO_ERROR;                                          \
        used = FUNC(formatter->_nf, value, ubuffer, cnt, NULL, &status); \
        if (status == U_BUFFER_OVERFLOW_ERROR || cnt < used) {          \
@@ -406,25 +479,41 @@ CFNumberRef CFNumberFormatterCreateNumberFromString(CFAllocatorRef allocator, CF
 Boolean CFNumberFormatterGetValueFromString(CFNumberFormatterRef formatter, CFStringRef string, CFRange *rangep, CFNumberType numberType, void *valuePtr) {
     __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
     __CFGenericValidateType(string, CFStringGetTypeID());
-    Boolean isZero = false;
+    CFStringRef stringToParse = formatter->_isLenient ? __CFNumberFormatterCreateCompressedString(string, false, rangep) : (CFStringRef)CFRetain(string);
     CFRange range = {0, 0};
-    if (rangep) {
-       range = *rangep;
+    if(formatter->_isLenient) {
+        range.length = CFStringGetLength(stringToParse);
     } else {
-        range.length = CFStringGetLength(string);
+        if (rangep) {
+            range = *rangep;
+        } else {
+            range.length = CFStringGetLength(stringToParse);
+        }
+        // unum_parse chokes on leading whitespace
+        CFCharacterSetRef whitespace = CFCharacterSetGetPredefined(kCFCharacterSetWhitespace);
+        while(range.length > 0 && CFCharacterSetIsCharacterMember(whitespace, CFStringGetCharacterAtIndex(stringToParse, range.location))) {
+            range.location++;
+            range.length--;
+        }
     }
-    if (formatter->_zeroSym && kCFCompareEqualTo == CFStringCompareWithOptions(string, formatter->_zeroSym, range, 0)) {
-       isZero = true;
+    Boolean isZero = false;
+    if (formatter->_zeroSym) {
+       CFStringRef zeroSym = formatter->_isLenient ? __CFNumberFormatterCreateCompressedString(formatter->_zeroSym, false, NULL) : (CFStringRef)CFRetain(formatter->_zeroSym);
+       if (kCFCompareEqualTo == CFStringCompare(stringToParse, zeroSym, 0)) {
+           isZero = true;
+       }
+       CFRelease(zeroSym);
     }
     if (1024 < range.length) range.length = 1024;
-    const UChar *ustr = (const UChar *)CFStringGetCharactersPtr(string);
+    const UChar *ustr = (const UChar *)CFStringGetCharactersPtr(stringToParse);
     STACK_BUFFER_DECL(UChar, ubuffer, (NULL == ustr) ? range.length : 1);
     if (NULL == ustr) {
-       CFStringGetCharacters(string, range, (UniChar *)ubuffer);
+       CFStringGetCharacters(stringToParse, range, (UniChar *)ubuffer);
        ustr = ubuffer;
-    } else {
-        ustr += range.location;
+    } else if (!formatter->_isLenient) {
+       ustr += range.location;
     }
+    if (formatter->_isLenient) __CFNumberFormatterApplyPattern(formatter, formatter->_compformat);
     Boolean integerOnly = 1;
     switch (numberType) {
     case kCFNumberSInt8Type: case kCFNumberCharType:
@@ -452,7 +541,20 @@ Boolean CFNumberFormatterGetValueFromString(CFNumberFormatterRef formatter, CFSt
            dretd = unum_parseDouble(formatter->_nf, ustr, range.length, &dpos, &status);
        }
     }
-    if (rangep) rangep->length = dpos;
+    if (formatter->_isLenient) {
+       if (rangep) {
+           CFIndex uncompEnd = rangep->location + rangep->length;
+           CFIndex uncompIdx = rangep->location;
+           for (CFIndex compIdx = 0; compIdx < dpos && uncompIdx < uncompEnd; compIdx++, uncompIdx++) {
+               while (uncompIdx < uncompEnd && ustr[compIdx] != __CFNumberFormatterNormalizeCharacter(CFStringGetCharacterAtIndex(string, uncompIdx))) uncompIdx++;
+           }
+           rangep->length = uncompIdx - rangep->location;
+       }
+       __CFNumberFormatterApplyPattern(formatter, formatter->_format);
+    } else if (rangep) {
+        rangep->length = dpos + (range.location - rangep->location);
+    }
+    CFRelease(stringToParse);
     if (U_FAILURE(status)) {
        return false;
     }
@@ -519,195 +621,203 @@ void CFNumberFormatterSetProperty(CFNumberFormatterRef formatter, CFStringRef ke
     CFIndex cnt;
     __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
     __CFGenericValidateType(key, CFStringGetTypeID());
-    if (kCFNumberFormatterCurrencyCode == key) {
+    if (kCFNumberFormatterCurrencyCodeKey == key) {
        __CFGenericValidateType(value, CFStringGetTypeID());
        cnt = CFStringGetLength((CFStringRef)value);
        if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
        CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
        unum_setTextAttribute(formatter->_nf, UNUM_CURRENCY_CODE, ubuffer, cnt, &status);
-    } else if (kCFNumberFormatterDecimalSeparator == key) {
+    } else if (kCFNumberFormatterDecimalSeparatorKey == key) {
        __CFGenericValidateType(value, CFStringGetTypeID());
        cnt = CFStringGetLength((CFStringRef)value);
        if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
        CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
        unum_setSymbol(formatter->_nf, UNUM_DECIMAL_SEPARATOR_SYMBOL, ubuffer, cnt, &status);
-    } else if (kCFNumberFormatterCurrencyDecimalSeparator == key) {
+    } else if (kCFNumberFormatterCurrencyDecimalSeparatorKey == key) {
        __CFGenericValidateType(value, CFStringGetTypeID());
        cnt = CFStringGetLength((CFStringRef)value);
        if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
        CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
        unum_setSymbol(formatter->_nf, UNUM_MONETARY_SEPARATOR_SYMBOL, ubuffer, cnt, &status);
-    } else if (kCFNumberFormatterAlwaysShowDecimalSeparator == key) {
+    } else if (kCFNumberFormatterAlwaysShowDecimalSeparatorKey == key) {
        __CFGenericValidateType(value, CFBooleanGetTypeID());
        unum_setAttribute(formatter->_nf, UNUM_DECIMAL_ALWAYS_SHOWN, (kCFBooleanTrue == value));
-    } else if (kCFNumberFormatterGroupingSeparator == key) {
+    } else if (kCFNumberFormatterGroupingSeparatorKey == key) {
        __CFGenericValidateType(value, CFStringGetTypeID());
        cnt = CFStringGetLength((CFStringRef)value);
        if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
        CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
        unum_setSymbol(formatter->_nf, UNUM_GROUPING_SEPARATOR_SYMBOL, (const UChar *)ubuffer, cnt, &status);
-    } else if (kCFNumberFormatterUseGroupingSeparator == key) {
+    } else if (kCFNumberFormatterUseGroupingSeparatorKey == key) {
        __CFGenericValidateType(value, CFBooleanGetTypeID());
        unum_setAttribute(formatter->_nf, UNUM_GROUPING_USED, (kCFBooleanTrue == value));
-    } else if (kCFNumberFormatterPercentSymbol == key) {
+    } else if (kCFNumberFormatterPercentSymbolKey == key) {
        __CFGenericValidateType(value, CFStringGetTypeID());
        cnt = CFStringGetLength((CFStringRef)value);
        if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
        CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
        unum_setSymbol(formatter->_nf, UNUM_PERCENT_SYMBOL, ubuffer, cnt, &status);
-    } else if (kCFNumberFormatterZeroSymbol == key) {
+    } else if (kCFNumberFormatterZeroSymbolKey == key) {
         __CFGenericValidateType(value, CFStringGetTypeID());
         CFStringRef old = formatter->_zeroSym;
         formatter->_zeroSym = value ? (CFStringRef)CFRetain(value) : NULL;
         if (old) CFRelease(old);
-    } else if (kCFNumberFormatterNaNSymbol == key) {
+    } else if (kCFNumberFormatterNaNSymbolKey == key) {
        __CFGenericValidateType(value, CFStringGetTypeID());
        cnt = CFStringGetLength((CFStringRef)value);
        if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
        CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
        unum_setSymbol(formatter->_nf, UNUM_NAN_SYMBOL, ubuffer, cnt, &status);
-    } else if (kCFNumberFormatterInfinitySymbol == key) {
+    } else if (kCFNumberFormatterInfinitySymbolKey == key) {
        __CFGenericValidateType(value, CFStringGetTypeID());
        cnt = CFStringGetLength((CFStringRef)value);
        if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
        CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
        unum_setSymbol(formatter->_nf, UNUM_INFINITY_SYMBOL, ubuffer, cnt, &status);
-    } else if (kCFNumberFormatterMinusSign == key) {
+    } else if (kCFNumberFormatterMinusSignKey == key) {
        __CFGenericValidateType(value, CFStringGetTypeID());
        cnt = CFStringGetLength((CFStringRef)value);
        if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
        CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
        unum_setSymbol(formatter->_nf, UNUM_MINUS_SIGN_SYMBOL, ubuffer, cnt, &status);
-    } else if (kCFNumberFormatterPlusSign == key) {
+    } else if (kCFNumberFormatterPlusSignKey == key) {
        __CFGenericValidateType(value, CFStringGetTypeID());
        cnt = CFStringGetLength((CFStringRef)value);
        if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
        CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
        unum_setSymbol(formatter->_nf, UNUM_PLUS_SIGN_SYMBOL, ubuffer, cnt, &status);
-    } else if (kCFNumberFormatterCurrencySymbol == key) {
+    } else if (kCFNumberFormatterCurrencySymbolKey == key) {
        __CFGenericValidateType(value, CFStringGetTypeID());
        cnt = CFStringGetLength((CFStringRef)value);
        if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
        CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
        unum_setSymbol(formatter->_nf, UNUM_CURRENCY_SYMBOL, (const UChar *)ubuffer, cnt, &status);
-    } else if (kCFNumberFormatterExponentSymbol == key) {
+    } else if (kCFNumberFormatterExponentSymbolKey == key) {
        __CFGenericValidateType(value, CFStringGetTypeID());
        cnt = CFStringGetLength((CFStringRef)value);
        if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
        CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
        unum_setSymbol(formatter->_nf, UNUM_EXPONENTIAL_SYMBOL, ubuffer, cnt, &status);
-    } else if (kCFNumberFormatterMinIntegerDigits == key) {
+    } else if (kCFNumberFormatterMinIntegerDigitsKey == key) {
        __CFGenericValidateType(value, CFNumberGetTypeID());
        CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
        unum_setAttribute(formatter->_nf, UNUM_MIN_INTEGER_DIGITS, n);
-    } else if (kCFNumberFormatterMaxIntegerDigits == key) {
+    } else if (kCFNumberFormatterMaxIntegerDigitsKey == key) {
        __CFGenericValidateType(value, CFNumberGetTypeID());
        CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
        unum_setAttribute(formatter->_nf, UNUM_MAX_INTEGER_DIGITS, n);
-    } else if (kCFNumberFormatterMinFractionDigits == key) {
+    } else if (kCFNumberFormatterMinFractionDigitsKey == key) {
        __CFGenericValidateType(value, CFNumberGetTypeID());
        CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
        unum_setAttribute(formatter->_nf, UNUM_MIN_FRACTION_DIGITS, n);
-    } else if (kCFNumberFormatterMaxFractionDigits == key) {
+    } else if (kCFNumberFormatterMaxFractionDigitsKey == key) {
        __CFGenericValidateType(value, CFNumberGetTypeID());
        CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
        unum_setAttribute(formatter->_nf, UNUM_MAX_FRACTION_DIGITS, n);
-    } else if (kCFNumberFormatterGroupingSize == key) {
+    } else if (kCFNumberFormatterGroupingSizeKey == key) {
        __CFGenericValidateType(value, CFNumberGetTypeID());
        CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
        unum_setAttribute(formatter->_nf, UNUM_GROUPING_SIZE, n);
-    } else if (kCFNumberFormatterSecondaryGroupingSize == key) {
+    } else if (kCFNumberFormatterSecondaryGroupingSizeKey == key) {
        __CFGenericValidateType(value, CFNumberGetTypeID());
        CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
        unum_setAttribute(formatter->_nf, UNUM_SECONDARY_GROUPING_SIZE, n);
-    } else if (kCFNumberFormatterRoundingMode == key) {
+    } else if (kCFNumberFormatterRoundingModeKey == key) {
        __CFGenericValidateType(value, CFNumberGetTypeID());
        CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
        unum_setAttribute(formatter->_nf, UNUM_ROUNDING_MODE, n);
-    } else if (kCFNumberFormatterRoundingIncrement == key) {
+    } else if (kCFNumberFormatterRoundingIncrementKey == key) {
        __CFGenericValidateType(value, CFNumberGetTypeID());
        CFNumberGetValue((CFNumberRef)value, kCFNumberDoubleType, &d);
        unum_setDoubleAttribute(formatter->_nf, UNUM_ROUNDING_INCREMENT, d);
-    } else if (kCFNumberFormatterFormatWidth == key) {
+    } else if (kCFNumberFormatterFormatWidthKey == key) {
        __CFGenericValidateType(value, CFNumberGetTypeID());
        CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
        unum_setAttribute(formatter->_nf, UNUM_FORMAT_WIDTH, n);
-    } else if (kCFNumberFormatterPaddingPosition == key) {
+    } else if (kCFNumberFormatterPaddingPositionKey == key) {
        __CFGenericValidateType(value, CFNumberGetTypeID());
        CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
        unum_setAttribute(formatter->_nf, UNUM_PADDING_POSITION, n);
-    } else if (kCFNumberFormatterPaddingCharacter == key) {
+    } else if (kCFNumberFormatterPaddingCharacterKey == key) {
        __CFGenericValidateType(value, CFStringGetTypeID());
        cnt = CFStringGetLength((CFStringRef)value);
        if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
        CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
        unum_setTextAttribute(formatter->_nf, UNUM_PADDING_CHARACTER, ubuffer, cnt, &status);
-    } else if (kCFNumberFormatterDefaultFormat == key) {
+    } else if (kCFNumberFormatterDefaultFormatKey == key) {
        // read-only attribute
-    } else if (kCFNumberFormatterMultiplier == key) {
+    } else if (kCFNumberFormatterMultiplierKey == key) {
        __CFGenericValidateType(value, CFNumberGetTypeID());
         CFNumberRef old = formatter->_multiplier;
         formatter->_multiplier = value ? (CFNumberRef)CFRetain(value) : NULL;
+       formatter->_userSetMultiplier = value ? true : false;
         if (old) CFRelease(old);
-    } else if (kCFNumberFormatterPositivePrefix == key) {
+    } else if (kCFNumberFormatterPositivePrefixKey == key) {
        __CFGenericValidateType(value, CFStringGetTypeID());
        cnt = CFStringGetLength((CFStringRef)value);
        if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
        CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
        unum_setTextAttribute(formatter->_nf, UNUM_POSITIVE_PREFIX, ubuffer, cnt, &status);
-    } else if (kCFNumberFormatterPositiveSuffix == key) {
+    } else if (kCFNumberFormatterPositiveSuffixKey == key) {
        __CFGenericValidateType(value, CFStringGetTypeID());
        cnt = CFStringGetLength((CFStringRef)value);
        if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
        CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
        unum_setTextAttribute(formatter->_nf, UNUM_POSITIVE_SUFFIX, (const UChar *)ubuffer, cnt, &status);
-    } else if (kCFNumberFormatterNegativePrefix == key) {
+    } else if (kCFNumberFormatterNegativePrefixKey == key) {
        __CFGenericValidateType(value, CFStringGetTypeID());
        cnt = CFStringGetLength((CFStringRef)value);
        if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
        CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
        unum_setTextAttribute(formatter->_nf, UNUM_NEGATIVE_PREFIX, ubuffer, cnt, &status);
-    } else if (kCFNumberFormatterNegativeSuffix == key) {
+    } else if (kCFNumberFormatterNegativeSuffixKey == key) {
        __CFGenericValidateType(value, CFStringGetTypeID());
        cnt = CFStringGetLength((CFStringRef)value);
        if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
        CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
        unum_setTextAttribute(formatter->_nf, UNUM_NEGATIVE_SUFFIX, (const UChar *)ubuffer, cnt, &status);
-    } else if (kCFNumberFormatterPerMillSymbol == key) {
+    } else if (kCFNumberFormatterPerMillSymbolKey == key) {
        __CFGenericValidateType(value, CFStringGetTypeID());
         cnt = CFStringGetLength((CFStringRef)value);
         if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
         CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
         unum_setSymbol(formatter->_nf, UNUM_PERMILL_SYMBOL, ubuffer, cnt, &status);
-    } else if (kCFNumberFormatterInternationalCurrencySymbol == key) {
+    } else if (kCFNumberFormatterInternationalCurrencySymbolKey == key) {
        __CFGenericValidateType(value, CFStringGetTypeID());
         cnt = CFStringGetLength((CFStringRef)value);
         if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
         CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
         unum_setSymbol(formatter->_nf, UNUM_INTL_CURRENCY_SYMBOL, ubuffer, cnt, &status);
-    } else if (kCFNumberFormatterCurrencyGroupingSeparator == key) {
+    } else if (kCFNumberFormatterCurrencyGroupingSeparatorKey == key) {
        __CFGenericValidateType(value, CFStringGetTypeID());
         cnt = CFStringGetLength((CFStringRef)value);
         if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
         CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
         unum_setSymbol(formatter->_nf, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, ubuffer, cnt, &status);
-    } else if (kCFNumberFormatterIsLenient == key) {
+    } else if (kCFNumberFormatterIsLenientKey == key) {
        __CFGenericValidateType(value, CFBooleanGetTypeID());
+       formatter->_isLenient = (kCFBooleanTrue == value);
        unum_setAttribute(formatter->_nf, UNUM_LENIENT_PARSE, (kCFBooleanTrue == value));
-    } else if (kCFNumberFormatterUseSignificantDigits == key) {
+    } else if (kCFNumberFormatterUseSignificantDigitsKey == key) {
        __CFGenericValidateType(value, CFBooleanGetTypeID());
        unum_setAttribute(formatter->_nf, UNUM_SIGNIFICANT_DIGITS_USED, (kCFBooleanTrue == value));
-    } else if (kCFNumberFormatterMinSignificantDigits == key) {
+    } else if (kCFNumberFormatterMinSignificantDigitsKey == key) {
        __CFGenericValidateType(value, CFNumberGetTypeID());
        CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
        unum_setAttribute(formatter->_nf, UNUM_MIN_SIGNIFICANT_DIGITS, n);
-    } else if (kCFNumberFormatterMaxSignificantDigits == key) {
+    } else if (kCFNumberFormatterMaxSignificantDigitsKey == key) {
        __CFGenericValidateType(value, CFNumberGetTypeID());
        CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
        unum_setAttribute(formatter->_nf, UNUM_MAX_SIGNIFICANT_DIGITS, n);
     } else {
        CFAssert3(0, __kCFLogAssertion, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__, key, key);
     }
+    if (_CFExecutableLinkedOnOrAfter(CFSystemVersionSnowLeopard)) {
+        // do a dummy call to CFNumberFormatterGetFormat() after changing an attribute because
+        // ICU sometimes changes the pattern due to a property change, and we need to poke
+        // unum_toPattern() and also update our own variables
+        CFNumberFormatterGetFormat(formatter);
+    }
 }
 
 CFTypeRef CFNumberFormatterCopyProperty(CFNumberFormatterRef formatter, CFStringRef key) {
@@ -718,7 +828,7 @@ CFTypeRef CFNumberFormatterCopyProperty(CFNumberFormatterRef formatter, CFString
     CFIndex cnt;
     __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
     __CFGenericValidateType(key, CFStringGetTypeID());
-    if (kCFNumberFormatterCurrencyCode == key) {
+    if (kCFNumberFormatterCurrencyCodeKey == key) {
        cnt = unum_getTextAttribute(formatter->_nf, UNUM_CURRENCY_CODE, ubuffer, BUFFER_SIZE, &status);
        if (U_SUCCESS(status) && cnt == 0) {
            CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale);
@@ -740,178 +850,176 @@ CFTypeRef CFNumberFormatterCopyProperty(CFNumberFormatterRef formatter, CFString
        if (U_SUCCESS(status) && 0 < cnt && cnt <= BUFFER_SIZE) {
            return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
        }
-    } else if (kCFNumberFormatterDecimalSeparator == key) {
+    } else if (kCFNumberFormatterDecimalSeparatorKey == key) {
        cnt = unum_getSymbol(formatter->_nf, UNUM_DECIMAL_SEPARATOR_SYMBOL, ubuffer, BUFFER_SIZE, &status);
        if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
            return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
        }
-    } else if (kCFNumberFormatterCurrencyDecimalSeparator == key) {
+    } else if (kCFNumberFormatterCurrencyDecimalSeparatorKey == key) {
        cnt = unum_getSymbol(formatter->_nf, UNUM_MONETARY_SEPARATOR_SYMBOL, (UChar *)ubuffer, BUFFER_SIZE, &status);
        if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
            return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
        }
-    } else if (kCFNumberFormatterAlwaysShowDecimalSeparator == key) {
+    } else if (kCFNumberFormatterAlwaysShowDecimalSeparatorKey == key) {
        n = unum_getAttribute(formatter->_nf, UNUM_DECIMAL_ALWAYS_SHOWN);
        if (1) {
            return CFRetain(n ? kCFBooleanTrue : kCFBooleanFalse);
        }
-    } else if (kCFNumberFormatterGroupingSeparator == key) {
+    } else if (kCFNumberFormatterGroupingSeparatorKey == key) {
        cnt = unum_getSymbol(formatter->_nf, UNUM_GROUPING_SEPARATOR_SYMBOL, ubuffer, BUFFER_SIZE, &status);
        if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
            return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
        }
-    } else if (kCFNumberFormatterUseGroupingSeparator == key) {
+    } else if (kCFNumberFormatterUseGroupingSeparatorKey == key) {
        n = unum_getAttribute(formatter->_nf, UNUM_GROUPING_USED);
        if (1) {
            return CFRetain(n ? kCFBooleanTrue : kCFBooleanFalse);
        }
-   } else if (kCFNumberFormatterPercentSymbol == key) {
+   } else if (kCFNumberFormatterPercentSymbolKey == key) {
        cnt = unum_getSymbol(formatter->_nf, UNUM_PERCENT_SYMBOL, ubuffer, BUFFER_SIZE, &status);
        if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
            return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
        }
-    } else if (kCFNumberFormatterZeroSymbol == key) {
+    } else if (kCFNumberFormatterZeroSymbolKey == key) {
         return formatter->_zeroSym ? CFRetain(formatter->_zeroSym) : NULL;
-    } else if (kCFNumberFormatterNaNSymbol == key) {
+    } else if (kCFNumberFormatterNaNSymbolKey == key) {
        cnt = unum_getSymbol(formatter->_nf, UNUM_NAN_SYMBOL, ubuffer, BUFFER_SIZE, &status);
        if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
            return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
        }
-    } else if (kCFNumberFormatterInfinitySymbol == key) {
+    } else if (kCFNumberFormatterInfinitySymbolKey == key) {
        cnt = unum_getSymbol(formatter->_nf, UNUM_INFINITY_SYMBOL, ubuffer, BUFFER_SIZE, &status);
        if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
            return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
        }
-    } else if (kCFNumberFormatterMinusSign == key) {
+    } else if (kCFNumberFormatterMinusSignKey == key) {
        cnt = unum_getSymbol(formatter->_nf, UNUM_MINUS_SIGN_SYMBOL, ubuffer, BUFFER_SIZE, &status);
        if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
            return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
        }
-    } else if (kCFNumberFormatterPlusSign == key) {
+    } else if (kCFNumberFormatterPlusSignKey == key) {
        cnt = unum_getSymbol(formatter->_nf, UNUM_PLUS_SIGN_SYMBOL, ubuffer, BUFFER_SIZE, &status);
        if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
            return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
        }
-    } else if (kCFNumberFormatterCurrencySymbol == key) {
+    } else if (kCFNumberFormatterCurrencySymbolKey == key) {
        cnt = unum_getSymbol(formatter->_nf, UNUM_CURRENCY_SYMBOL, ubuffer, BUFFER_SIZE, &status);
        if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
            return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
        }
-    } else if (kCFNumberFormatterExponentSymbol == key) {
+    } else if (kCFNumberFormatterExponentSymbolKey == key) {
        cnt = unum_getSymbol(formatter->_nf, UNUM_EXPONENTIAL_SYMBOL, ubuffer, BUFFER_SIZE, &status);
        if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
            return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
        }
-    } else if (kCFNumberFormatterMinIntegerDigits == key) {
+    } else if (kCFNumberFormatterMinIntegerDigitsKey == key) {
        n = unum_getAttribute(formatter->_nf, UNUM_MIN_INTEGER_DIGITS);
        if (1) {
            return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
        }
-    } else if (kCFNumberFormatterMaxIntegerDigits == key) {
+    } else if (kCFNumberFormatterMaxIntegerDigitsKey == key) {
        n = unum_getAttribute(formatter->_nf, UNUM_MAX_INTEGER_DIGITS);
        if (1) {
            return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
        }
-    } else if (kCFNumberFormatterMinFractionDigits == key) {
+    } else if (kCFNumberFormatterMinFractionDigitsKey == key) {
        n = unum_getAttribute(formatter->_nf, UNUM_MIN_FRACTION_DIGITS);
        if (1) {
            return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
        }
-    } else if (kCFNumberFormatterMaxFractionDigits == key) {
+    } else if (kCFNumberFormatterMaxFractionDigitsKey == key) {
        n = unum_getAttribute(formatter->_nf, UNUM_MAX_FRACTION_DIGITS);
        if (1) {
            return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
        }
-    } else if (kCFNumberFormatterGroupingSize == key) {
+    } else if (kCFNumberFormatterGroupingSizeKey == key) {
        n = unum_getAttribute(formatter->_nf, UNUM_GROUPING_SIZE);
        if (1) {
            return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
        }
-    } else if (kCFNumberFormatterSecondaryGroupingSize == key) {
+    } else if (kCFNumberFormatterSecondaryGroupingSizeKey == key) {
        n = unum_getAttribute(formatter->_nf, UNUM_SECONDARY_GROUPING_SIZE);
        if (1) {
            return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
        }
-    } else if (kCFNumberFormatterRoundingMode == key) {
+    } else if (kCFNumberFormatterRoundingModeKey == key) {
        n = unum_getAttribute(formatter->_nf, UNUM_ROUNDING_MODE);
        if (1) {
            return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
        }
-    } else if (kCFNumberFormatterRoundingIncrement == key) {
+    } else if (kCFNumberFormatterRoundingIncrementKey == key) {
        d = unum_getDoubleAttribute(formatter->_nf, UNUM_ROUNDING_INCREMENT);
        if (1) {
            return CFNumberCreate(CFGetAllocator(formatter), kCFNumberDoubleType, &d);
        }
-    } else if (kCFNumberFormatterFormatWidth == key) {
+    } else if (kCFNumberFormatterFormatWidthKey == key) {
        n = unum_getAttribute(formatter->_nf, UNUM_FORMAT_WIDTH);
        if (1) {
            return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
        }
-    } else if (kCFNumberFormatterPaddingPosition == key) {
+    } else if (kCFNumberFormatterPaddingPositionKey == key) {
        n = unum_getAttribute(formatter->_nf, UNUM_PADDING_POSITION);
        if (1) {
            return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
        }
-    } else if (kCFNumberFormatterPaddingCharacter == key) {
+    } else if (kCFNumberFormatterPaddingCharacterKey == key) {
        cnt = unum_getTextAttribute(formatter->_nf, UNUM_PADDING_CHARACTER, ubuffer, BUFFER_SIZE, &status);
        if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
            return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
        }
-    } else if (kCFNumberFormatterDefaultFormat == key) {
+    } else if (kCFNumberFormatterDefaultFormatKey == key) {
        return formatter->_defformat ? CFRetain(formatter->_defformat) : NULL;
-    } else if (kCFNumberFormatterMultiplier == key) {
+    } else if (kCFNumberFormatterMultiplierKey == key) {
         return formatter->_multiplier ? CFRetain(formatter->_multiplier) : NULL;
-    } else if (kCFNumberFormatterPositivePrefix == key) {
+    } else if (kCFNumberFormatterPositivePrefixKey == key) {
         cnt = unum_getTextAttribute(formatter->_nf, UNUM_POSITIVE_PREFIX, ubuffer, BUFFER_SIZE, &status);
         if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
             return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
         }
-    } else if (kCFNumberFormatterPositiveSuffix == key) {
+    } else if (kCFNumberFormatterPositiveSuffixKey == key) {
         cnt = unum_getTextAttribute(formatter->_nf, UNUM_POSITIVE_SUFFIX, ubuffer, BUFFER_SIZE, &status);
         if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
             return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
         }
-    } else if (kCFNumberFormatterNegativePrefix == key) {
+    } else if (kCFNumberFormatterNegativePrefixKey == key) {
         cnt = unum_getTextAttribute(formatter->_nf, UNUM_NEGATIVE_PREFIX, ubuffer, BUFFER_SIZE, &status);
         if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
             return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
         }
-    } else if (kCFNumberFormatterNegativeSuffix == key) {
+    } else if (kCFNumberFormatterNegativeSuffixKey == key) {
         cnt = unum_getTextAttribute(formatter->_nf, UNUM_NEGATIVE_SUFFIX, ubuffer, BUFFER_SIZE, &status);
         if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
             return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
         }
-    } else if (kCFNumberFormatterPerMillSymbol == key) {
+    } else if (kCFNumberFormatterPerMillSymbolKey == key) {
         cnt = unum_getSymbol(formatter->_nf, UNUM_PERMILL_SYMBOL, ubuffer, BUFFER_SIZE, &status);
         if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
             return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
         }
-    } else if (kCFNumberFormatterInternationalCurrencySymbol == key) {
+    } else if (kCFNumberFormatterInternationalCurrencySymbolKey == key) {
         cnt = unum_getSymbol(formatter->_nf, UNUM_INTL_CURRENCY_SYMBOL, ubuffer, BUFFER_SIZE, &status);
         if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
             return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
         }
-    } else if (kCFNumberFormatterCurrencyGroupingSeparator == key) {
+    } else if (kCFNumberFormatterCurrencyGroupingSeparatorKey == key) {
         cnt = unum_getSymbol(formatter->_nf, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, ubuffer, BUFFER_SIZE, &status);
         if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
             return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
         }
-    } else if (kCFNumberFormatterIsLenient == key) {
-       n = unum_getAttribute(formatter->_nf, UNUM_LENIENT_PARSE);
-       if (1) {
-           return CFRetain(n ? kCFBooleanTrue : kCFBooleanFalse);
-       }
-    } else if (kCFNumberFormatterUseSignificantDigits == key) {
+    } else if (kCFNumberFormatterIsLenientKey == key) {
+       // unum_getAttribute(, UNUM_LENIENT_PARSE) is undefined.
+       return CFRetain(formatter->_isLenient ? kCFBooleanTrue : kCFBooleanFalse);
+    } else if (kCFNumberFormatterUseSignificantDigitsKey == key) {
        n = unum_getAttribute(formatter->_nf, UNUM_SIGNIFICANT_DIGITS_USED);
        if (1) {
            return CFRetain(n ? kCFBooleanTrue : kCFBooleanFalse);
        }
-    } else if (kCFNumberFormatterMinSignificantDigits == key) {
+    } else if (kCFNumberFormatterMinSignificantDigitsKey == key) {
        n = unum_getAttribute(formatter->_nf, UNUM_MIN_SIGNIFICANT_DIGITS);
        if (1) {
            return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
        }
-    } else if (kCFNumberFormatterMaxSignificantDigits == key) {
+    } else if (kCFNumberFormatterMaxSignificantDigitsKey == key) {
        n = unum_getAttribute(formatter->_nf, UNUM_MAX_SIGNIFICANT_DIGITS);
        if (1) {
            return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
@@ -922,46 +1030,6 @@ CFTypeRef CFNumberFormatterCopyProperty(CFNumberFormatterRef formatter, CFString
     return NULL;
 }
 
-CONST_STRING_DECL(kCFNumberFormatterCurrencyCode, "kCFNumberFormatterCurrencyCode")
-CONST_STRING_DECL(kCFNumberFormatterDecimalSeparator, "kCFNumberFormatterDecimalSeparator")
-CONST_STRING_DECL(kCFNumberFormatterCurrencyDecimalSeparator, "kCFNumberFormatterCurrencyDecimalSeparator")
-CONST_STRING_DECL(kCFNumberFormatterAlwaysShowDecimalSeparator, "kCFNumberFormatterAlwaysShowDecimalSeparator")
-CONST_STRING_DECL(kCFNumberFormatterGroupingSeparator, "kCFNumberFormatterGroupingSeparator")
-CONST_STRING_DECL(kCFNumberFormatterUseGroupingSeparator, "kCFNumberFormatterUseGroupingSeparator")
-CONST_STRING_DECL(kCFNumberFormatterPercentSymbol, "kCFNumberFormatterPercentSymbol")
-CONST_STRING_DECL(kCFNumberFormatterZeroSymbol, "kCFNumberFormatterZeroSymbol")
-CONST_STRING_DECL(kCFNumberFormatterNaNSymbol, "kCFNumberFormatterNaNSymbol")
-CONST_STRING_DECL(kCFNumberFormatterInfinitySymbol, "kCFNumberFormatterInfinitySymbol")
-CONST_STRING_DECL(kCFNumberFormatterMinusSign, "kCFNumberFormatterMinusSignSymbol")
-CONST_STRING_DECL(kCFNumberFormatterPlusSign, "kCFNumberFormatterPlusSignSymbol")
-CONST_STRING_DECL(kCFNumberFormatterCurrencySymbol, "kCFNumberFormatterCurrencySymbol")
-CONST_STRING_DECL(kCFNumberFormatterExponentSymbol, "kCFNumberFormatterExponentSymbol")
-CONST_STRING_DECL(kCFNumberFormatterMinIntegerDigits, "kCFNumberFormatterMinIntegerDigits")
-CONST_STRING_DECL(kCFNumberFormatterMaxIntegerDigits, "kCFNumberFormatterMaxIntegerDigits")
-CONST_STRING_DECL(kCFNumberFormatterMinFractionDigits, "kCFNumberFormatterMinFractionDigits")
-CONST_STRING_DECL(kCFNumberFormatterMaxFractionDigits, "kCFNumberFormatterMaxFractionDigits")
-CONST_STRING_DECL(kCFNumberFormatterGroupingSize, "kCFNumberFormatterGroupingSize")
-CONST_STRING_DECL(kCFNumberFormatterSecondaryGroupingSize, "kCFNumberFormatterSecondaryGroupingSize")
-CONST_STRING_DECL(kCFNumberFormatterRoundingMode, "kCFNumberFormatterRoundingMode")
-CONST_STRING_DECL(kCFNumberFormatterRoundingIncrement, "kCFNumberFormatterRoundingIncrement")
-CONST_STRING_DECL(kCFNumberFormatterFormatWidth, "kCFNumberFormatterFormatWidth")
-CONST_STRING_DECL(kCFNumberFormatterPaddingPosition, "kCFNumberFormatterPaddingPosition")
-CONST_STRING_DECL(kCFNumberFormatterPaddingCharacter, "kCFNumberFormatterPaddingCharacter")
-CONST_STRING_DECL(kCFNumberFormatterDefaultFormat, "kCFNumberFormatterDefaultFormat")
-
-CONST_STRING_DECL(kCFNumberFormatterMultiplier, "kCFNumberFormatterMultiplier")
-CONST_STRING_DECL(kCFNumberFormatterPositivePrefix, "kCFNumberFormatterPositivePrefix")
-CONST_STRING_DECL(kCFNumberFormatterPositiveSuffix, "kCFNumberFormatterPositiveSuffix")
-CONST_STRING_DECL(kCFNumberFormatterNegativePrefix, "kCFNumberFormatterNegativePrefix")
-CONST_STRING_DECL(kCFNumberFormatterNegativeSuffix, "kCFNumberFormatterNegativeSuffix")
-CONST_STRING_DECL(kCFNumberFormatterPerMillSymbol, "kCFNumberFormatterPerMillSymbol")
-CONST_STRING_DECL(kCFNumberFormatterInternationalCurrencySymbol, "kCFNumberFormatterInternationalCurrencySymbol")
-
-CONST_STRING_DECL(kCFNumberFormatterCurrencyGroupingSeparator, "kCFNumberFormatterCurrencyGroupingSeparator")
-CONST_STRING_DECL(kCFNumberFormatterIsLenient, "kCFNumberFormatterIsLenient")
-CONST_STRING_DECL(kCFNumberFormatterUseSignificantDigits, "kCFNumberFormatterUseSignificantDigits")
-CONST_STRING_DECL(kCFNumberFormatterMinSignificantDigits, "kCFNumberFormatterMinSignificantDigits")
-CONST_STRING_DECL(kCFNumberFormatterMaxSignificantDigits, "kCFNumberFormatterMaxSignificantDigits")
 
 Boolean CFNumberFormatterGetDecimalInfoForCurrencyCode(CFStringRef currencyCode, int32_t *defaultFractionDigits, double *roundingIncrement) {
     UChar ubuffer[4];