2 * Copyright (c) 2013 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 /* CFNumberFormatter.c
25 Copyright (c) 2002-2013, Apple Inc. All rights reserved.
26 Responsibility: David Smith
29 #include <CoreFoundation/CFNumberFormatter.h>
30 #include <CoreFoundation/ForFoundationOnly.h>
31 #include <CoreFoundation/CFBigNumber.h>
32 #include "CFInternal.h"
33 #include "CFLocaleInternal.h"
34 #include "CFICULogging.h"
39 static void __CFNumberFormatterCustomize(CFNumberFormatterRef formatter
);
40 static CFStringRef
__CFNumberFormatterCreateCompressedString(CFStringRef inString
, Boolean isFormat
, CFRange
*rangep
);
41 static UErrorCode
__CFNumberFormatterApplyPattern(CFNumberFormatterRef formatter
, CFStringRef pattern
);
43 #define BUFFER_SIZE 768
45 struct __CFNumberFormatter
{
49 CFNumberFormatterStyle _style
;
50 CFStringRef _format
; // NULL for RBNFs
51 CFStringRef _defformat
;
52 CFStringRef _compformat
;
53 CFNumberRef _multiplier
;
56 Boolean _userSetMultiplier
;
57 Boolean _usesCharacterDirection
;
60 static CFStringRef
__CFNumberFormatterCopyDescription(CFTypeRef cf
) {
61 CFNumberFormatterRef formatter
= (CFNumberFormatterRef
)cf
;
62 return CFStringCreateWithFormat(CFGetAllocator(formatter
), NULL
, CFSTR("<CFNumberFormatter %p [%p]>"), cf
, CFGetAllocator(formatter
));
65 static void __CFNumberFormatterDeallocate(CFTypeRef cf
) {
66 CFNumberFormatterRef formatter
= (CFNumberFormatterRef
)cf
;
67 if (formatter
->_nf
) __cficu_unum_close(formatter
->_nf
);
68 if (formatter
->_locale
) CFRelease(formatter
->_locale
);
69 if (formatter
->_format
) CFRelease(formatter
->_format
);
70 if (formatter
->_defformat
) CFRelease(formatter
->_defformat
);
71 if (formatter
->_compformat
) CFRelease(formatter
->_compformat
);
72 if (formatter
->_multiplier
) CFRelease(formatter
->_multiplier
);
73 if (formatter
->_zeroSym
) CFRelease(formatter
->_zeroSym
);
76 static CFTypeID __kCFNumberFormatterTypeID
= _kCFRuntimeNotATypeID
;
78 static const CFRuntimeClass __CFNumberFormatterClass
= {
83 __CFNumberFormatterDeallocate
,
87 __CFNumberFormatterCopyDescription
90 static void __CFNumberFormatterInitialize(void) {
91 __kCFNumberFormatterTypeID
= _CFRuntimeRegisterClass(&__CFNumberFormatterClass
);
94 CFTypeID
CFNumberFormatterGetTypeID(void) {
95 if (_kCFRuntimeNotATypeID
== __kCFNumberFormatterTypeID
) __CFNumberFormatterInitialize();
96 return __kCFNumberFormatterTypeID
;
99 CFNumberFormatterRef
CFNumberFormatterCreate(CFAllocatorRef allocator
, CFLocaleRef locale
, CFNumberFormatterStyle style
) {
100 struct __CFNumberFormatter
*memory
;
101 uint32_t size
= sizeof(struct __CFNumberFormatter
) - sizeof(CFRuntimeBase
);
102 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
103 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
104 __CFGenericValidateType(locale
, CFLocaleGetTypeID());
105 memory
= (struct __CFNumberFormatter
*)_CFRuntimeCreateInstance(allocator
, CFNumberFormatterGetTypeID(), size
, NULL
);
106 if (NULL
== memory
) {
110 memory
->_locale
= NULL
;
111 memory
->_format
= NULL
;
112 memory
->_defformat
= NULL
;
113 memory
->_compformat
= NULL
;
114 memory
->_multiplier
= NULL
;
115 memory
->_zeroSym
= NULL
;
116 memory
->_isLenient
= false;
117 memory
->_userSetMultiplier
= false;
118 memory
->_usesCharacterDirection
= false;
119 if (NULL
== locale
) locale
= CFLocaleGetSystem();
120 memory
->_style
= style
;
123 case kCFNumberFormatterNoStyle
: ustyle
= UNUM_IGNORE
; break;
124 case kCFNumberFormatterDecimalStyle
: ustyle
= UNUM_DECIMAL
; break;
125 case kCFNumberFormatterCurrencyStyle
: ustyle
= UNUM_CURRENCY
; break;
126 case kCFNumberFormatterPercentStyle
: ustyle
= UNUM_PERCENT
; break;
127 case kCFNumberFormatterScientificStyle
: ustyle
= UNUM_SCIENTIFIC
; break;
128 case kCFNumberFormatterSpellOutStyle
: ustyle
= UNUM_SPELLOUT
; break;
129 case kCFNumberFormatterOrdinalStyle
: ustyle
= UNUM_ORDINAL
; break;
130 case kCFNumberFormatterDurationStyle
: ustyle
= UNUM_DURATION
; break;
132 CFAssert2(0, __kCFLogAssertion
, "%s(): unknown style %d", __PRETTY_FUNCTION__
, style
);
133 ustyle
= UNUM_DECIMAL
;
134 memory
->_style
= kCFNumberFormatterDecimalStyle
;
137 CFStringRef localeName
= locale
? CFLocaleGetIdentifier(locale
) : CFSTR("");
138 char buffer
[BUFFER_SIZE
];
139 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
141 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
147 UErrorCode status
= U_ZERO_ERROR
;
148 memory
->_nf
= __cficu_unum_open((UNumberFormatStyle
)ustyle
, NULL
, 0, cstr
, NULL
, &status
);
149 CFAssert2(memory
->_nf
, __kCFLogAssertion
, "%s(): error (%d) creating number formatter", __PRETTY_FUNCTION__
, status
);
150 if (NULL
== memory
->_nf
) {
155 if (kCFNumberFormatterNoStyle
== style
) {
156 status
= U_ZERO_ERROR
;
157 ubuff
[0] = '#'; ubuff
[1] = ';'; ubuff
[2] = '#';
158 __cficu_unum_applyPattern(memory
->_nf
, false, ubuff
, 3, NULL
, &status
);
159 __cficu_unum_setAttribute(memory
->_nf
, UNUM_MAX_INTEGER_DIGITS
, 42);
160 __cficu_unum_setAttribute(memory
->_nf
, UNUM_MAX_FRACTION_DIGITS
, 0);
162 memory
->_locale
= locale
? CFLocaleCreateCopy(allocator
, locale
) : CFLocaleGetSystem();
163 __CFNumberFormatterCustomize(memory
);
164 if (kCFNumberFormatterSpellOutStyle
!= memory
->_style
&& kCFNumberFormatterOrdinalStyle
!= memory
->_style
&& kCFNumberFormatterDurationStyle
!= memory
->_style
) {
165 UChar ubuffer
[BUFFER_SIZE
];
166 status
= U_ZERO_ERROR
;
167 int32_t ret
= __cficu_unum_toPattern(memory
->_nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
168 if (U_SUCCESS(status
) && ret
<= BUFFER_SIZE
) {
169 memory
->_format
= CFStringCreateWithCharacters(allocator
, (const UniChar
*)ubuffer
, ret
);
172 memory
->_defformat
= memory
->_format
? (CFStringRef
)CFRetain(memory
->_format
) : NULL
;
173 memory
->_compformat
= memory
->_format
? __CFNumberFormatterCreateCompressedString(memory
->_format
, true, NULL
) : NULL
;
174 if (kCFNumberFormatterSpellOutStyle
!= memory
->_style
&& kCFNumberFormatterOrdinalStyle
!= memory
->_style
&& kCFNumberFormatterDurationStyle
!= memory
->_style
) {
175 int32_t n
= __cficu_unum_getAttribute(memory
->_nf
, UNUM_MULTIPLIER
);
177 memory
->_multiplier
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, &n
);
178 __cficu_unum_setAttribute(memory
->_nf
, UNUM_MULTIPLIER
, 1);
181 __cficu_unum_setAttribute(memory
->_nf
, UNUM_LENIENT_PARSE
, 0);
182 return (CFNumberFormatterRef
)memory
;
185 extern CFDictionaryRef
__CFLocaleGetPrefs(CFLocaleRef locale
);
187 static void __substituteFormatStringFromPrefsNF(CFNumberFormatterRef formatter
) {
188 CFIndex formatStyle
= formatter
->_style
;
189 if (kCFNumberFormatterSpellOutStyle
== formatStyle
) return;
190 if (kCFNumberFormatterOrdinalStyle
== formatStyle
) return;
191 if (kCFNumberFormatterDurationStyle
== formatStyle
) return;
192 CFStringRef prefName
= CFSTR("AppleICUNumberFormatStrings");
193 if (kCFNumberFormatterNoStyle
!= formatStyle
) {
194 CFStringRef pref
= NULL
;
195 CFDictionaryRef prefs
= __CFLocaleGetPrefs(formatter
->_locale
);
196 CFPropertyListRef metapref
= prefs
? CFDictionaryGetValue(prefs
, prefName
) : NULL
;
197 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
199 switch (formatStyle
) {
200 case kCFNumberFormatterDecimalStyle
: key
= CFSTR("1"); break;
201 case kCFNumberFormatterCurrencyStyle
: key
= CFSTR("2"); break;
202 case kCFNumberFormatterPercentStyle
: key
= CFSTR("3"); break;
203 case kCFNumberFormatterScientificStyle
: key
= CFSTR("4"); break;
204 case kCFNumberFormatterSpellOutStyle
: key
= CFSTR("5"); break;
205 case kCFNumberFormatterOrdinalStyle
: key
= CFSTR("6"); break;
206 case kCFNumberFormatterDurationStyle
: key
= CFSTR("7"); break;
207 default: key
= CFSTR("0"); break;
209 pref
= (CFStringRef
)CFDictionaryGetValue((CFDictionaryRef
)metapref
, key
);
211 if (NULL
!= pref
&& CFGetTypeID(pref
) == CFStringGetTypeID()) {
212 int32_t icustyle
= UNUM_IGNORE
;
213 switch (formatStyle
) {
214 case kCFNumberFormatterDecimalStyle
: icustyle
= UNUM_DECIMAL
; break;
215 case kCFNumberFormatterCurrencyStyle
: icustyle
= UNUM_CURRENCY
; break;
216 case kCFNumberFormatterPercentStyle
: icustyle
= UNUM_PERCENT
; break;
217 case kCFNumberFormatterScientificStyle
: icustyle
= UNUM_SCIENTIFIC
; break;
218 case kCFNumberFormatterSpellOutStyle
: icustyle
= UNUM_SPELLOUT
; break;
219 case kCFNumberFormatterOrdinalStyle
: icustyle
= UNUM_ORDINAL
; break;
220 case kCFNumberFormatterDurationStyle
: icustyle
= UNUM_DURATION
; break;
222 CFStringRef localeName
= CFLocaleGetIdentifier(formatter
->_locale
);
223 char buffer
[BUFFER_SIZE
];
224 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
226 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
228 UErrorCode status
= U_ZERO_ERROR
;
229 UNumberFormat
*nf
= __cficu_unum_open((UNumberFormatStyle
)icustyle
, NULL
, 0, cstr
, NULL
, &status
);
231 UChar ubuffer
[BUFFER_SIZE
];
232 status
= U_ZERO_ERROR
;
233 int32_t number_len
= __cficu_unum_toPattern(nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
234 if (U_SUCCESS(status
) && number_len
<= BUFFER_SIZE
) {
235 CFStringRef numberString
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)ubuffer
, number_len
);
236 status
= U_ZERO_ERROR
;
237 int32_t formatter_len
= __cficu_unum_toPattern(formatter
->_nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
238 if (U_SUCCESS(status
) && formatter_len
<= BUFFER_SIZE
) {
239 CFMutableStringRef formatString
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
240 CFStringAppendCharacters(formatString
, (const UniChar
*)ubuffer
, formatter_len
);
241 // find numberString inside formatString, substitute the pref in that range
243 if (CFStringFindWithOptions(formatString
, numberString
, CFRangeMake(0, formatter_len
), 0, &result
)) {
244 CFStringReplace(formatString
, result
, pref
);
245 __CFNumberFormatterApplyPattern(formatter
, formatString
);
247 CFRelease(formatString
);
249 CFRelease(numberString
);
251 __cficu_unum_close(nf
);
257 static UniChar
__CFNumberFormatterNormalizeCharacter(UniChar c
) {
258 if (CFCharacterSetIsCharacterMember(CFCharacterSetGetPredefined(kCFCharacterSetWhitespace
), c
)) {
265 /* 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. */
266 static CFStringRef
__CFNumberFormatterCreateCompressedString(CFStringRef inString
, Boolean isFormat
, CFRange
*rangep
) {
267 if (!inString
) return NULL
;
268 CFRange range
= { 0, 0 };
272 range
.length
= CFStringGetLength(inString
);
274 CFMutableStringRef outString
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
275 CFCharacterSetRef letters
= CFCharacterSetGetPredefined(kCFCharacterSetLetter
);
276 CFCharacterSetRef numbers
= CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
);
277 UniChar prevCh
= 0, nextCh
= 0;
278 Boolean inQuote
= false;
279 for (CFIndex in_idx
= range
.location
; in_idx
< range
.location
+ range
.length
; in_idx
++) {
280 UniChar ch
= __CFNumberFormatterNormalizeCharacter(CFStringGetCharacterAtIndex(inString
, in_idx
));
281 nextCh
= (in_idx
+1 < range
.length
) ? CFStringGetCharacterAtIndex(inString
, in_idx
+1) : 0;
282 if (isFormat
&& ch
== '\'') inQuote
= !inQuote
;
283 if (inQuote
|| ch
!= ' ' || (CFCharacterSetIsCharacterMember(letters
, prevCh
) && CFCharacterSetIsCharacterMember(letters
, nextCh
)) || (CFCharacterSetIsCharacterMember(numbers
, prevCh
) && CFCharacterSetIsCharacterMember(numbers
, nextCh
))) {
284 CFStringAppendCharacters(outString
, &ch
, 1);
291 // Should not be called for rule-based ICU formatters; not supported
292 static void __CFNumberFormatterApplySymbolPrefs(const void *key
, const void *value
, void *context
) {
293 if (CFGetTypeID(key
) == CFStringGetTypeID() && CFGetTypeID(value
) == CFStringGetTypeID()) {
294 CFNumberFormatterRef formatter
= (CFNumberFormatterRef
)context
;
295 UNumberFormatSymbol sym
= (UNumberFormatSymbol
)CFStringGetIntValue((CFStringRef
)key
);
296 CFStringRef item
= (CFStringRef
)value
;
297 CFIndex item_cnt
= CFStringGetLength(item
);
298 STACK_BUFFER_DECL(UChar
, item_buffer
, item_cnt
);
299 UChar
*item_ustr
= (UChar
*)CFStringGetCharactersPtr(item
);
300 if (NULL
== item_ustr
) {
301 CFStringGetCharacters(item
, CFRangeMake(0, __CFMin(BUFFER_SIZE
, item_cnt
)), (UniChar
*)item_buffer
);
302 item_ustr
= item_buffer
;
304 UErrorCode status
= U_ZERO_ERROR
;
305 __cficu_unum_setSymbol(formatter
->_nf
, sym
, item_ustr
, item_cnt
, &status
);
309 // Should not be called for rule-based ICU formatters
310 static UErrorCode
__CFNumberFormatterApplyPattern(CFNumberFormatterRef formatter
, CFStringRef pattern
) {
311 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
) return U_UNSUPPORTED_ERROR
;
312 if (kCFNumberFormatterOrdinalStyle
== formatter
->_style
) return U_UNSUPPORTED_ERROR
;
313 if (kCFNumberFormatterDurationStyle
== formatter
->_style
) return U_UNSUPPORTED_ERROR
;
314 CFIndex cnt
= CFStringGetLength(pattern
);
315 STACK_BUFFER_DECL(UChar
, ubuffer
, cnt
);
316 const UChar
*ustr
= (const UChar
*)CFStringGetCharactersPtr(pattern
);
318 CFStringGetCharacters(pattern
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
321 UErrorCode status
= U_ZERO_ERROR
;
322 __cficu_unum_applyPattern(formatter
->_nf
, false, ustr
, cnt
, NULL
, &status
);
324 // __cficu_unum_applyPattern() may have magically changed other attributes based on
325 // the contents of the format string; we simply expose that ICU behavior, except
326 // for UNUM_MULTIPLIER, which we re-read and reset, like we did at initialization
327 // time though any user-set multiplier state takes precedence.
328 if (formatter
->_userSetMultiplier
) {
329 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_MULTIPLIER
, 1);
331 if (formatter
->_multiplier
) CFRelease(formatter
->_multiplier
);
332 formatter
->_multiplier
= NULL
;
333 int32_t n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_MULTIPLIER
);
335 formatter
->_multiplier
= CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
336 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_MULTIPLIER
, 1);
342 static void __CFNumberFormatterCustomize(CFNumberFormatterRef formatter
) {
343 __substituteFormatStringFromPrefsNF(formatter
);
344 CFDictionaryRef prefs
= __CFLocaleGetPrefs(formatter
->_locale
);
345 CFPropertyListRef metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleICUNumberSymbols")) : NULL
;
346 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
347 CFDictionaryApplyFunction((CFDictionaryRef
)metapref
, __CFNumberFormatterApplySymbolPrefs
, formatter
);
351 CFLocaleRef
CFNumberFormatterGetLocale(CFNumberFormatterRef formatter
) {
352 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
353 return formatter
->_locale
;
356 CFNumberFormatterStyle
CFNumberFormatterGetStyle(CFNumberFormatterRef formatter
) {
357 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
358 return formatter
->_style
;
361 CFStringRef
CFNumberFormatterGetFormat(CFNumberFormatterRef formatter
) {
362 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
363 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
) return NULL
;
364 if (kCFNumberFormatterOrdinalStyle
== formatter
->_style
) return NULL
;
365 if (kCFNumberFormatterDurationStyle
== formatter
->_style
) return NULL
;
366 UChar ubuffer
[BUFFER_SIZE
];
367 CFStringRef newString
= NULL
;
368 UErrorCode status
= U_ZERO_ERROR
;
369 int32_t ret
= __cficu_unum_toPattern(formatter
->_nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
370 if (U_SUCCESS(status
) && ret
<= BUFFER_SIZE
) {
371 newString
= CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, ret
);
373 if (newString
&& !formatter
->_format
) {
374 formatter
->_format
= newString
;
375 if (formatter
->_compformat
) CFRelease(formatter
->_compformat
);
376 formatter
->_compformat
= __CFNumberFormatterCreateCompressedString(formatter
->_format
, true, NULL
);
377 } else if (newString
&& !CFEqual(newString
, formatter
->_format
)) {
378 CFRelease(formatter
->_format
);
379 formatter
->_format
= newString
;
380 if (formatter
->_compformat
) CFRelease(formatter
->_compformat
);
381 formatter
->_compformat
= __CFNumberFormatterCreateCompressedString(formatter
->_format
, true, NULL
);
382 } else if (newString
) {
383 CFRelease(newString
);
385 return formatter
->_format
;
388 void CFNumberFormatterSetFormat(CFNumberFormatterRef formatter
, CFStringRef formatString
) {
389 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
390 __CFGenericValidateType(formatString
, CFStringGetTypeID());
391 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
) return;
392 if (kCFNumberFormatterOrdinalStyle
== formatter
->_style
) return;
393 if (kCFNumberFormatterDurationStyle
== formatter
->_style
) return;
394 CFIndex cnt
= CFStringGetLength(formatString
);
395 CFAssert1(cnt
<= 1024, __kCFLogAssertion
, "%s(): format string too long", __PRETTY_FUNCTION__
);
396 if ((!formatter
->_format
|| !CFEqual(formatter
->_format
, formatString
)) && cnt
<= 1024) {
397 UErrorCode status
= __CFNumberFormatterApplyPattern(formatter
, formatString
);
398 if (U_SUCCESS(status
)) {
399 UChar ubuffer2
[BUFFER_SIZE
];
400 status
= U_ZERO_ERROR
;
401 int32_t ret
= __cficu_unum_toPattern(formatter
->_nf
, false, ubuffer2
, BUFFER_SIZE
, &status
);
402 if (U_SUCCESS(status
) && ret
<= BUFFER_SIZE
) {
403 if (formatter
->_format
) CFRelease(formatter
->_format
);
404 formatter
->_format
= CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer2
, ret
);
405 if (formatter
->_compformat
) CFRelease(formatter
->_compformat
);
406 formatter
->_compformat
= __CFNumberFormatterCreateCompressedString(formatter
->_format
, true, NULL
);
412 #define GET_MULTIPLIER \
413 double multiplier = 1.0; \
414 double dummy = 0.0; \
415 if (formatter->_multiplier) { \
416 if (!CFNumberGetValue(formatter->_multiplier, kCFNumberFloat64Type, &multiplier)) { \
420 if (modf(multiplier, &dummy) < FLT_EPSILON) { \
421 multiplier = floor(multiplier); \
424 CFStringRef
CFNumberFormatterCreateStringWithNumber(CFAllocatorRef allocator
, CFNumberFormatterRef formatter
, CFNumberRef number
) {
425 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
426 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
427 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
428 __CFGenericValidateType(number
, CFNumberGetTypeID());
429 // The values of CFNumbers with large unsigned 64-bit ints don't survive well through this
430 CFNumberType type
= CFNumberGetType(number
);
432 CFNumberGetValue(number
, type
, buffer
);
433 return CFNumberFormatterCreateStringWithValue(allocator
, formatter
, type
, buffer
);
436 #define FORMAT_FLT(T, FUNC) \
437 T value = *(T *)valuePtr; \
438 if (0 == value && formatter->_zeroSym) { return (CFStringRef)CFRetain(formatter->_zeroSym); } \
439 if (1.0 != multiplier) { \
440 value = (T)(value * multiplier); \
442 status = U_ZERO_ERROR; \
443 used = FUNC(formatter->_nf, value, ubuffer + 1, cnt, NULL, &status); \
444 if (status == U_BUFFER_OVERFLOW_ERROR || cnt < used) { \
445 cnt = used + 1 + 1; \
446 ustr = (UChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UChar) * cnt, 0); \
447 status = U_ZERO_ERROR; \
448 used = FUNC(formatter->_nf, value, ustr + 1, cnt, NULL, &status); \
451 #define FORMAT_INT(T, FUN) \
452 T value = *(T *)valuePtr; \
453 if (0 == value && formatter->_zeroSym) { return (CFStringRef)CFRetain(formatter->_zeroSym); } \
454 if (1.0 != multiplier) { \
455 value = (T)(value * multiplier); \
458 FUN(&bignum, value); \
459 char buffer[BUFFER_SIZE + 1]; \
460 _CFBigNumToCString(&bignum, false, true, buffer, BUFFER_SIZE); \
461 status = U_ZERO_ERROR; \
462 used = __cficu_unum_formatDecimal(formatter->_nf, buffer, strlen(buffer), ubuffer + 1, BUFFER_SIZE, NULL, &status); \
463 if (status == U_BUFFER_OVERFLOW_ERROR || cnt < used) { \
464 cnt = used + 1 + 1; \
465 ustr = (UChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UChar) * cnt, 0); \
466 status = U_ZERO_ERROR; \
467 used = __cficu_unum_formatDecimal(formatter->_nf, buffer, strlen(buffer), ustr + 1, cnt, NULL, &status); \
470 CFStringRef CFNumberFormatterCreateStringWithValue(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFNumberType numberType, const void *valuePtr) {
471 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
472 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
473 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
475 UChar
*ustr
= NULL
, ubuffer
[BUFFER_SIZE
+ 1];
476 UErrorCode status
= U_ZERO_ERROR
;
477 CFIndex used
, cnt
= BUFFER_SIZE
;
478 if (numberType
== kCFNumberFloat64Type
|| numberType
== kCFNumberDoubleType
) {
479 FORMAT_FLT(double, __cficu_unum_formatDouble
)
480 } else if (numberType
== kCFNumberFloat32Type
|| numberType
== kCFNumberFloatType
) {
481 FORMAT_FLT(float, __cficu_unum_formatDouble
)
482 } else if (numberType
== kCFNumberSInt64Type
|| numberType
== kCFNumberLongLongType
) {
483 FORMAT_INT(int64_t, _CFBigNumInitWithInt64
)
484 } else if (numberType
== kCFNumberLongType
|| numberType
== kCFNumberCFIndexType
) {
486 FORMAT_INT(int64_t, _CFBigNumInitWithInt64
)
488 FORMAT_INT(int32_t, _CFBigNumInitWithInt32
)
490 } else if (numberType
== kCFNumberSInt32Type
|| numberType
== kCFNumberIntType
) {
491 FORMAT_INT(int32_t, _CFBigNumInitWithInt32
)
492 } else if (numberType
== kCFNumberSInt16Type
|| numberType
== kCFNumberShortType
) {
493 FORMAT_INT(int16_t, _CFBigNumInitWithInt16
)
494 } else if (numberType
== kCFNumberSInt8Type
|| numberType
== kCFNumberCharType
) {
495 FORMAT_INT(int8_t, _CFBigNumInitWithInt8
)
497 CFAssert2(0, __kCFLogAssertion
, "%s(): unknown CFNumberType (%d)", __PRETTY_FUNCTION__
, numberType
);
500 CFStringRef string
= NULL
;
501 if (U_SUCCESS(status
)) {
502 UniChar
*bufferToUse
= ustr
? (UniChar
*)ustr
: (UniChar
*)ubuffer
;
503 if (formatter
->_usesCharacterDirection
&& CFLocaleGetLanguageCharacterDirection(CFLocaleGetIdentifier(formatter
->_locale
)) == kCFLocaleLanguageDirectionRightToLeft
) {
504 // Insert Unicode RTL marker
505 bufferToUse
[0] = 0x200F;
508 // Move past direction marker
511 string
= CFStringCreateWithCharacters(allocator
, bufferToUse
, used
);
513 if (ustr
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, ustr
);
519 #undef GET_MULTIPLIER
521 CFNumberRef
CFNumberFormatterCreateNumberFromString(CFAllocatorRef allocator
, CFNumberFormatterRef formatter
, CFStringRef string
, CFRange
*rangep
, CFOptionFlags options
) {
522 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
523 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
524 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
525 __CFGenericValidateType(string
, CFStringGetTypeID());
526 char buffer
[16] __attribute__ ((aligned (8)));
527 CFRange r
= rangep
? *rangep
: CFRangeMake(0, CFStringGetLength(string
));
528 CFNumberRef multiplierRef
= formatter
->_multiplier
;
529 formatter
->_multiplier
= NULL
;
530 Boolean b
= CFNumberFormatterGetValueFromString(formatter
, string
, &r
, kCFNumberSInt64Type
, buffer
);
531 formatter
->_multiplier
= multiplierRef
;
533 Boolean passedMultiplier
= true;
534 // We handle the multiplier case here manually; the final
535 // result is supposed to be (parsed value) / (multiplier), but
536 // the int case here should only succeed if the parsed value
537 // is an exact multiple of the multiplier.
539 int64_t tmp
= *(int64_t *)buffer
;
540 double multiplier
= 1.0;
541 if (!CFNumberGetValue(multiplierRef
, kCFNumberFloat64Type
, &multiplier
)) {
545 if (llabs(tmp
) < fabs(multiplier
)) {
546 passedMultiplier
= false;
547 } else if (fabs(multiplier
) < 1.0) { // We can't handle this math yet
548 passedMultiplier
= false;
549 } else if (modf(multiplier
, &dummy
) == 0.0) { // multiplier is an integer
550 int64_t imult
= (int64_t)multiplier
;
551 int64_t rem
= tmp
% imult
;
552 if (rem
!= 0) passedMultiplier
= false;
553 if (passedMultiplier
) {
555 *(int64_t *)buffer
= tmp
;
557 } else if (multiplier
== -1.0) { // simple
559 *(int64_t *)buffer
= tmp
;
560 } else if (multiplier
!= 1.0) {
561 // First, throw away integer multiples of the multiplier to
562 // bring the value down to less than 2^53, so that we can
563 // cast it to double without losing any precision, important
564 // for the "remainder is zero" test.
565 // Find power of two which, when multiplier is multiplied by it,
566 // results in an integer value. pwr will be <= 52 since multiplier
570 while (modf(scalbn(multiplier
, pwr
), &intgrl
) != 0.0) pwr
++;
571 int64_t i2
= (int64_t)intgrl
;
572 // scale pwr and i2 up to a reasonably large value so the next loop doesn't take forever
573 while (llabs(i2
) < (1LL << 50)) { i2
*= 2; pwr
++; }
575 while ((1LL << 53) <= llabs(tmp
)) {
576 // subtract (multiplier * 2^pwr) each time
577 tmp
-= i2
; // move tmp toward zero
578 cnt
+= (1LL << pwr
); // remember how many 2^pwr we subtracted
580 // If the integer is less than 2^53, there is no loss
581 // in converting it to double, so we can just do the
582 // direct operation now.
583 double rem
= fmod((double)tmp
, multiplier
);
584 if (rem
!= 0.0) passedMultiplier
= false;
585 if (passedMultiplier
) {
586 // The original tmp, which we need to divide by multiplier, is at this point:
587 // tmp + k * 2^n * multiplier, where k is the number of loop iterations
588 // That original value needs to be divided by multiplier and put back in the
589 // buffer. Noting that k * 2^n == cnt, and after some algebra, we have:
590 tmp
= (int64_t)((double)tmp
/ multiplier
) + cnt
;
591 *(int64_t *)buffer
= tmp
;
595 if (passedMultiplier
&& ((r
.length
== CFStringGetLength(string
)) || (options
& kCFNumberFormatterParseIntegersOnly
))) {
596 if (rangep
) *rangep
= r
;
597 return CFNumberCreate(allocator
, kCFNumberSInt64Type
, buffer
);
600 if (options
& kCFNumberFormatterParseIntegersOnly
) return NULL
;
601 if (CFNumberFormatterGetValueFromString(formatter
, string
, rangep
, kCFNumberFloat64Type
, buffer
)) {
602 return CFNumberCreate(allocator
, kCFNumberFloat64Type
, buffer
);
607 Boolean
CFNumberFormatterGetValueFromString(CFNumberFormatterRef formatter
, CFStringRef string
, CFRange
*rangep
, CFNumberType numberType
, void *valuePtr
) {
608 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
609 __CFGenericValidateType(string
, CFStringGetTypeID());
610 CFStringRef stringToParse
= formatter
->_isLenient
? __CFNumberFormatterCreateCompressedString(string
, false, rangep
) : (CFStringRef
)CFRetain(string
);
611 CFRange range
= {0, 0};
612 if(formatter
->_isLenient
) {
613 range
.length
= CFStringGetLength(stringToParse
);
618 range
.length
= CFStringGetLength(stringToParse
);
620 // __cficu_unum_parse chokes on leading whitespace
621 CFCharacterSetRef whitespace
= CFCharacterSetGetPredefined(kCFCharacterSetWhitespace
);
622 while(range
.length
> 0 && CFCharacterSetIsCharacterMember(whitespace
, CFStringGetCharacterAtIndex(stringToParse
, range
.location
))) {
627 Boolean isZero
= false;
628 if (formatter
->_zeroSym
) {
629 CFStringRef zeroSym
= formatter
->_isLenient
? __CFNumberFormatterCreateCompressedString(formatter
->_zeroSym
, false, NULL
) : (CFStringRef
)CFRetain(formatter
->_zeroSym
);
630 if (kCFCompareEqualTo
== CFStringCompare(stringToParse
, zeroSym
, 0)) {
635 if (1024 < range
.length
) range
.length
= 1024;
636 const UChar
*ustr
= (const UChar
*)CFStringGetCharactersPtr(stringToParse
);
637 STACK_BUFFER_DECL(UChar
, ubuffer
, (NULL
== ustr
) ? range
.length
: 1);
639 CFStringGetCharacters(stringToParse
, range
, (UniChar
*)ubuffer
);
641 } else if (!formatter
->_isLenient
) {
642 ustr
+= range
.location
;
644 CFNumberRef multiplierRef
= formatter
->_multiplier
;
645 formatter
->_multiplier
= NULL
;
646 if (formatter
->_isLenient
) {
647 __CFNumberFormatterApplyPattern(formatter
, formatter
->_compformat
);
648 if (formatter
->_multiplier
) CFRelease(formatter
->_multiplier
);
649 formatter
->_multiplier
= NULL
;
651 Boolean integerOnly
= 1;
652 switch (numberType
) {
653 case kCFNumberSInt8Type
: case kCFNumberCharType
:
654 case kCFNumberSInt16Type
: case kCFNumberShortType
:
655 case kCFNumberSInt32Type
: case kCFNumberIntType
:
656 case kCFNumberLongType
: case kCFNumberCFIndexType
:
657 case kCFNumberSInt64Type
: case kCFNumberLongLongType
:
658 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_PARSE_INT_ONLY
, 1); // ignored by ICU for rule-based formatters
661 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_PARSE_INT_ONLY
, 0); // ignored by ICU for rule-based formatters
666 UErrorCode status
= U_ZERO_ERROR
;
670 dpos
= rangep
? rangep
->length
: 0;
673 memset(buffer
, 0, sizeof(buffer
));
674 int32_t len
= __cficu_unum_parseDecimal(formatter
->_nf
, ustr
, range
.length
, &dpos
, buffer
, sizeof(buffer
), &status
);
675 if (!U_FAILURE(status
) && 0 < len
&& integerOnly
) {
678 dreti
= strtoll_l(buffer
, &endptr
, 10, NULL
);
679 if (!(errno
== 0 && *endptr
== '\0')) status
= U_INVALID_FORMAT_ERROR
;
681 if (!U_FAILURE(status
) && 0 < len
) {
684 dretd
= strtod_l(buffer
, &endptr
, NULL
);
685 if (!(errno
== 0 && *endptr
== '\0')) status
= U_INVALID_FORMAT_ERROR
;
688 if (formatter
->_isLenient
) {
690 CFIndex uncompEnd
= rangep
->location
+ rangep
->length
;
691 CFIndex uncompIdx
= rangep
->location
;
692 for (CFIndex compIdx
= 0; compIdx
< dpos
&& uncompIdx
< uncompEnd
; compIdx
++, uncompIdx
++) {
693 while (uncompIdx
< uncompEnd
&& ustr
[compIdx
] != __CFNumberFormatterNormalizeCharacter(CFStringGetCharacterAtIndex(string
, uncompIdx
))) uncompIdx
++;
695 rangep
->length
= uncompIdx
- rangep
->location
;
697 __CFNumberFormatterApplyPattern(formatter
, formatter
->_format
);
698 if (formatter
->_multiplier
) CFRelease(formatter
->_multiplier
);
699 formatter
->_multiplier
= NULL
;
701 rangep
->length
= dpos
+ (range
.location
- rangep
->location
);
703 formatter
->_multiplier
= multiplierRef
;
704 CFRelease(stringToParse
);
705 if (U_FAILURE(status
)) {
708 if (formatter
->_multiplier
) {
709 double multiplier
= 1.0;
710 if (!CFNumberGetValue(formatter
->_multiplier
, kCFNumberFloat64Type
, &multiplier
)) {
713 dreti
= (int64_t)((double)dreti
/ multiplier
); // integer truncation, plus double cast can be lossy for dreti > 2^53
714 dretd
= dretd
/ multiplier
;
716 switch (numberType
) {
717 case kCFNumberSInt8Type
: case kCFNumberCharType
:
718 if (INT8_MIN
<= dreti
&& dreti
<= INT8_MAX
) {
719 *(int8_t *)valuePtr
= (int8_t)dreti
;
723 case kCFNumberSInt16Type
: case kCFNumberShortType
:
724 if (INT16_MIN
<= dreti
&& dreti
<= INT16_MAX
) {
725 *(int16_t *)valuePtr
= (int16_t)dreti
;
729 case kCFNumberSInt32Type
: case kCFNumberIntType
:
731 case kCFNumberLongType
: case kCFNumberCFIndexType
:
733 if (INT32_MIN
<= dreti
&& dreti
<= INT32_MAX
) {
734 *(int32_t *)valuePtr
= (int32_t)dreti
;
738 case kCFNumberSInt64Type
: case kCFNumberLongLongType
:
740 case kCFNumberLongType
: case kCFNumberCFIndexType
:
742 if (INT64_MIN
<= dreti
&& dreti
<= INT64_MAX
) {
743 *(int64_t *)valuePtr
= (int64_t)dreti
;
747 case kCFNumberFloat32Type
: case kCFNumberFloatType
:
748 if (-FLT_MAX
<= dretd
&& dretd
<= FLT_MAX
) {
749 *(float *)valuePtr
= (float)dretd
;
753 case kCFNumberFloat64Type
: case kCFNumberDoubleType
:
754 if (-DBL_MAX
<= dretd
&& dretd
<= DBL_MAX
) {
755 *(double *)valuePtr
= (double)dretd
;
763 void CFNumberFormatterSetProperty(CFNumberFormatterRef formatter
, CFStringRef key
, CFTypeRef value
) {
766 UErrorCode status
= U_ZERO_ERROR
;
767 UChar ubuffer
[BUFFER_SIZE
];
769 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
770 __CFGenericValidateType(key
, CFStringGetTypeID());
771 // rule-based formatters don't do attributes and symbols, except for one
772 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return;
773 if (kCFNumberFormatterOrdinalStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return;
774 if (kCFNumberFormatterDurationStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return;
775 if (kCFNumberFormatterCurrencyCodeKey
== key
) {
776 __CFGenericValidateType(value
, CFStringGetTypeID());
777 cnt
= CFStringGetLength((CFStringRef
)value
);
778 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
779 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
780 __cficu_unum_setTextAttribute(formatter
->_nf
, UNUM_CURRENCY_CODE
, ubuffer
, cnt
, &status
);
781 } else if (kCFNumberFormatterDecimalSeparatorKey
== key
) {
782 __CFGenericValidateType(value
, CFStringGetTypeID());
783 cnt
= CFStringGetLength((CFStringRef
)value
);
784 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
785 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
786 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_DECIMAL_SEPARATOR_SYMBOL
, ubuffer
, cnt
, &status
);
787 } else if (kCFNumberFormatterCurrencyDecimalSeparatorKey
== key
) {
788 __CFGenericValidateType(value
, CFStringGetTypeID());
789 cnt
= CFStringGetLength((CFStringRef
)value
);
790 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
791 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
792 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_MONETARY_SEPARATOR_SYMBOL
, ubuffer
, cnt
, &status
);
793 } else if (kCFNumberFormatterAlwaysShowDecimalSeparatorKey
== key
) {
794 __CFGenericValidateType(value
, CFBooleanGetTypeID());
795 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_DECIMAL_ALWAYS_SHOWN
, (kCFBooleanTrue
== value
));
796 } else if (kCFNumberFormatterGroupingSeparatorKey
== key
) {
797 __CFGenericValidateType(value
, CFStringGetTypeID());
798 cnt
= CFStringGetLength((CFStringRef
)value
);
799 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
800 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
801 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_GROUPING_SEPARATOR_SYMBOL
, (const UChar
*)ubuffer
, cnt
, &status
);
802 } else if (kCFNumberFormatterUseGroupingSeparatorKey
== key
) {
803 __CFGenericValidateType(value
, CFBooleanGetTypeID());
804 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_GROUPING_USED
, (kCFBooleanTrue
== value
));
805 } else if (kCFNumberFormatterPercentSymbolKey
== key
) {
806 __CFGenericValidateType(value
, CFStringGetTypeID());
807 cnt
= CFStringGetLength((CFStringRef
)value
);
808 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
809 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
810 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_PERCENT_SYMBOL
, ubuffer
, cnt
, &status
);
811 } else if (kCFNumberFormatterZeroSymbolKey
== key
) {
812 __CFGenericValidateType(value
, CFStringGetTypeID());
813 CFStringRef old
= formatter
->_zeroSym
;
814 formatter
->_zeroSym
= value
? (CFStringRef
)CFRetain(value
) : NULL
;
815 if (old
) CFRelease(old
);
816 } else if (kCFNumberFormatterNaNSymbolKey
== key
) {
817 __CFGenericValidateType(value
, CFStringGetTypeID());
818 cnt
= CFStringGetLength((CFStringRef
)value
);
819 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
820 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
821 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_NAN_SYMBOL
, ubuffer
, cnt
, &status
);
822 } else if (kCFNumberFormatterInfinitySymbolKey
== key
) {
823 __CFGenericValidateType(value
, CFStringGetTypeID());
824 cnt
= CFStringGetLength((CFStringRef
)value
);
825 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
826 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
827 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_INFINITY_SYMBOL
, ubuffer
, cnt
, &status
);
828 } else if (kCFNumberFormatterMinusSignKey
== key
) {
829 __CFGenericValidateType(value
, CFStringGetTypeID());
830 cnt
= CFStringGetLength((CFStringRef
)value
);
831 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
832 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
833 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_MINUS_SIGN_SYMBOL
, ubuffer
, cnt
, &status
);
834 } else if (kCFNumberFormatterPlusSignKey
== key
) {
835 __CFGenericValidateType(value
, CFStringGetTypeID());
836 cnt
= CFStringGetLength((CFStringRef
)value
);
837 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
838 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
839 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_PLUS_SIGN_SYMBOL
, ubuffer
, cnt
, &status
);
840 } else if (kCFNumberFormatterCurrencySymbolKey
== key
) {
841 __CFGenericValidateType(value
, CFStringGetTypeID());
842 cnt
= CFStringGetLength((CFStringRef
)value
);
843 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
844 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
845 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_CURRENCY_SYMBOL
, (const UChar
*)ubuffer
, cnt
, &status
);
846 } else if (kCFNumberFormatterExponentSymbolKey
== key
) {
847 __CFGenericValidateType(value
, CFStringGetTypeID());
848 cnt
= CFStringGetLength((CFStringRef
)value
);
849 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
850 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
851 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_EXPONENTIAL_SYMBOL
, ubuffer
, cnt
, &status
);
852 } else if (kCFNumberFormatterMinIntegerDigitsKey
== key
) {
853 __CFGenericValidateType(value
, CFNumberGetTypeID());
854 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
855 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_MIN_INTEGER_DIGITS
, n
);
856 } else if (kCFNumberFormatterMaxIntegerDigitsKey
== key
) {
857 __CFGenericValidateType(value
, CFNumberGetTypeID());
858 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
859 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_MAX_INTEGER_DIGITS
, n
);
860 } else if (kCFNumberFormatterMinFractionDigitsKey
== key
) {
861 __CFGenericValidateType(value
, CFNumberGetTypeID());
862 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
863 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_MIN_FRACTION_DIGITS
, n
);
864 } else if (kCFNumberFormatterMaxFractionDigitsKey
== key
) {
865 __CFGenericValidateType(value
, CFNumberGetTypeID());
866 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
867 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_MAX_FRACTION_DIGITS
, n
);
868 } else if (kCFNumberFormatterGroupingSizeKey
== key
) {
869 __CFGenericValidateType(value
, CFNumberGetTypeID());
870 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
871 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_GROUPING_SIZE
, n
);
872 } else if (kCFNumberFormatterSecondaryGroupingSizeKey
== key
) {
873 __CFGenericValidateType(value
, CFNumberGetTypeID());
874 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
875 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_SECONDARY_GROUPING_SIZE
, n
);
876 } else if (kCFNumberFormatterRoundingModeKey
== key
) {
877 __CFGenericValidateType(value
, CFNumberGetTypeID());
878 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
879 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_ROUNDING_MODE
, n
);
880 } else if (kCFNumberFormatterRoundingIncrementKey
== key
) {
881 __CFGenericValidateType(value
, CFNumberGetTypeID());
882 CFNumberGetValue((CFNumberRef
)value
, kCFNumberDoubleType
, &d
);
883 __cficu_unum_setDoubleAttribute(formatter
->_nf
, UNUM_ROUNDING_INCREMENT
, d
);
884 } else if (kCFNumberFormatterFormatWidthKey
== key
) {
885 __CFGenericValidateType(value
, CFNumberGetTypeID());
886 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
887 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_FORMAT_WIDTH
, n
);
888 } else if (kCFNumberFormatterPaddingPositionKey
== key
) {
889 __CFGenericValidateType(value
, CFNumberGetTypeID());
890 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
891 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_PADDING_POSITION
, n
);
892 } else if (kCFNumberFormatterPaddingCharacterKey
== key
) {
893 __CFGenericValidateType(value
, CFStringGetTypeID());
894 cnt
= CFStringGetLength((CFStringRef
)value
);
895 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
896 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
897 __cficu_unum_setTextAttribute(formatter
->_nf
, UNUM_PADDING_CHARACTER
, ubuffer
, cnt
, &status
);
898 } else if (kCFNumberFormatterDefaultFormatKey
== key
) {
899 // read-only attribute
900 } else if (kCFNumberFormatterMultiplierKey
== key
) {
901 __CFGenericValidateType(value
, CFNumberGetTypeID());
902 CFNumberRef old
= formatter
->_multiplier
;
903 formatter
->_multiplier
= value
? (CFNumberRef
)CFRetain(value
) : NULL
;
904 formatter
->_userSetMultiplier
= value
? true : false;
905 if (old
) CFRelease(old
);
906 } else if (kCFNumberFormatterPositivePrefixKey
== key
) {
907 __CFGenericValidateType(value
, CFStringGetTypeID());
908 cnt
= CFStringGetLength((CFStringRef
)value
);
909 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
910 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
911 __cficu_unum_setTextAttribute(formatter
->_nf
, UNUM_POSITIVE_PREFIX
, ubuffer
, cnt
, &status
);
912 } else if (kCFNumberFormatterPositiveSuffixKey
== key
) {
913 __CFGenericValidateType(value
, CFStringGetTypeID());
914 cnt
= CFStringGetLength((CFStringRef
)value
);
915 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
916 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
917 __cficu_unum_setTextAttribute(formatter
->_nf
, UNUM_POSITIVE_SUFFIX
, (const UChar
*)ubuffer
, cnt
, &status
);
918 } else if (kCFNumberFormatterNegativePrefixKey
== key
) {
919 __CFGenericValidateType(value
, CFStringGetTypeID());
920 cnt
= CFStringGetLength((CFStringRef
)value
);
921 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
922 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
923 __cficu_unum_setTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, cnt
, &status
);
924 } else if (kCFNumberFormatterNegativeSuffixKey
== key
) {
925 __CFGenericValidateType(value
, CFStringGetTypeID());
926 cnt
= CFStringGetLength((CFStringRef
)value
);
927 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
928 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
929 __cficu_unum_setTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_SUFFIX
, (const UChar
*)ubuffer
, cnt
, &status
);
930 } else if (kCFNumberFormatterPerMillSymbolKey
== key
) {
931 __CFGenericValidateType(value
, CFStringGetTypeID());
932 cnt
= CFStringGetLength((CFStringRef
)value
);
933 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
934 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
935 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_PERMILL_SYMBOL
, ubuffer
, cnt
, &status
);
936 } else if (kCFNumberFormatterInternationalCurrencySymbolKey
== key
) {
937 __CFGenericValidateType(value
, CFStringGetTypeID());
938 cnt
= CFStringGetLength((CFStringRef
)value
);
939 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
940 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
941 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_INTL_CURRENCY_SYMBOL
, ubuffer
, cnt
, &status
);
942 } else if (kCFNumberFormatterCurrencyGroupingSeparatorKey
== key
) {
943 __CFGenericValidateType(value
, CFStringGetTypeID());
944 cnt
= CFStringGetLength((CFStringRef
)value
);
945 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
946 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
947 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL
, ubuffer
, cnt
, &status
);
948 } else if (kCFNumberFormatterIsLenientKey
== key
) {
949 __CFGenericValidateType(value
, CFBooleanGetTypeID());
950 formatter
->_isLenient
= (kCFBooleanTrue
== value
);
951 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_LENIENT_PARSE
, (kCFBooleanTrue
== value
));
952 } else if (kCFNumberFormatterUseSignificantDigitsKey
== key
) {
953 __CFGenericValidateType(value
, CFBooleanGetTypeID());
954 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_SIGNIFICANT_DIGITS_USED
, (kCFBooleanTrue
== value
));
955 } else if (kCFNumberFormatterMinSignificantDigitsKey
== key
) {
956 __CFGenericValidateType(value
, CFNumberGetTypeID());
957 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
958 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_MIN_SIGNIFICANT_DIGITS
, n
);
959 } else if (kCFNumberFormatterMaxSignificantDigitsKey
== key
) {
960 __CFGenericValidateType(value
, CFNumberGetTypeID());
961 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
962 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_MAX_SIGNIFICANT_DIGITS
, n
);
963 } else if (kCFNumberFormatterUsesCharacterDirectionKey
== key
) {
964 __CFGenericValidateType(value
, CFBooleanGetTypeID());
965 formatter
->_usesCharacterDirection
= value
== kCFBooleanTrue
;
967 CFAssert3(0, __kCFLogAssertion
, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__
, key
, key
);
969 if (_CFExecutableLinkedOnOrAfter(CFSystemVersionSnowLeopard
)) {
970 // do a dummy call to CFNumberFormatterGetFormat() after changing an attribute because
971 // ICU sometimes changes the pattern due to a property change, and we need to poke
972 // __cficu_unum_toPattern() and also update our own variables
973 CFNumberFormatterGetFormat(formatter
);
977 CFTypeRef
CFNumberFormatterCopyProperty(CFNumberFormatterRef formatter
, CFStringRef key
) {
980 UErrorCode status
= U_ZERO_ERROR
;
981 UChar ubuffer
[BUFFER_SIZE
];
983 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
984 __CFGenericValidateType(key
, CFStringGetTypeID());
985 // rule-based formatters don't do attributes and symbols, except for one
986 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return NULL
;
987 if (kCFNumberFormatterOrdinalStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return NULL
;
988 if (kCFNumberFormatterDurationStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return NULL
;
989 if (kCFNumberFormatterCurrencyCodeKey
== key
) {
990 cnt
= __cficu_unum_getTextAttribute(formatter
->_nf
, UNUM_CURRENCY_CODE
, ubuffer
, BUFFER_SIZE
, &status
);
991 if (U_SUCCESS(status
) && cnt
== 0) {
992 CFStringRef localeName
= CFLocaleGetIdentifier(formatter
->_locale
);
993 char buffer
[BUFFER_SIZE
];
994 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
996 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
1001 UErrorCode status
= U_ZERO_ERROR
;
1002 UNumberFormat
*nf
= __cficu_unum_open(UNUM_CURRENCY
, NULL
, 0, cstr
, NULL
, &status
);
1004 cnt
= __cficu_unum_getTextAttribute(nf
, UNUM_CURRENCY_CODE
, ubuffer
, BUFFER_SIZE
, &status
);
1005 __cficu_unum_close(nf
);
1008 if (U_SUCCESS(status
) && 0 < cnt
&& cnt
<= BUFFER_SIZE
) {
1009 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1011 } else if (kCFNumberFormatterDecimalSeparatorKey
== key
) {
1012 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_DECIMAL_SEPARATOR_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1013 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1014 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1016 } else if (kCFNumberFormatterCurrencyDecimalSeparatorKey
== key
) {
1017 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_MONETARY_SEPARATOR_SYMBOL
, (UChar
*)ubuffer
, BUFFER_SIZE
, &status
);
1018 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1019 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1021 } else if (kCFNumberFormatterAlwaysShowDecimalSeparatorKey
== key
) {
1022 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_DECIMAL_ALWAYS_SHOWN
);
1024 return CFRetain(n
? kCFBooleanTrue
: kCFBooleanFalse
);
1026 } else if (kCFNumberFormatterGroupingSeparatorKey
== key
) {
1027 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_GROUPING_SEPARATOR_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1028 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1029 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1031 } else if (kCFNumberFormatterUseGroupingSeparatorKey
== key
) {
1032 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_GROUPING_USED
);
1034 return CFRetain(n
? kCFBooleanTrue
: kCFBooleanFalse
);
1036 } else if (kCFNumberFormatterPercentSymbolKey
== key
) {
1037 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_PERCENT_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1038 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1039 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1041 } else if (kCFNumberFormatterZeroSymbolKey
== key
) {
1042 return formatter
->_zeroSym
? CFRetain(formatter
->_zeroSym
) : NULL
;
1043 } else if (kCFNumberFormatterNaNSymbolKey
== key
) {
1044 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_NAN_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1045 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1046 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1048 } else if (kCFNumberFormatterInfinitySymbolKey
== key
) {
1049 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_INFINITY_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1050 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1051 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1053 } else if (kCFNumberFormatterMinusSignKey
== key
) {
1054 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_MINUS_SIGN_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1055 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1056 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1058 } else if (kCFNumberFormatterPlusSignKey
== key
) {
1059 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_PLUS_SIGN_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1060 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1061 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1063 } else if (kCFNumberFormatterCurrencySymbolKey
== key
) {
1064 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_CURRENCY_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1065 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1066 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1068 } else if (kCFNumberFormatterExponentSymbolKey
== key
) {
1069 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_EXPONENTIAL_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1070 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1071 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1073 } else if (kCFNumberFormatterMinIntegerDigitsKey
== key
) {
1074 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_MIN_INTEGER_DIGITS
);
1076 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1078 } else if (kCFNumberFormatterMaxIntegerDigitsKey
== key
) {
1079 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_MAX_INTEGER_DIGITS
);
1081 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1083 } else if (kCFNumberFormatterMinFractionDigitsKey
== key
) {
1084 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_MIN_FRACTION_DIGITS
);
1086 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1088 } else if (kCFNumberFormatterMaxFractionDigitsKey
== key
) {
1089 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_MAX_FRACTION_DIGITS
);
1091 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1093 } else if (kCFNumberFormatterGroupingSizeKey
== key
) {
1094 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_GROUPING_SIZE
);
1096 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1098 } else if (kCFNumberFormatterSecondaryGroupingSizeKey
== key
) {
1099 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_SECONDARY_GROUPING_SIZE
);
1101 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1103 } else if (kCFNumberFormatterRoundingModeKey
== key
) {
1104 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_ROUNDING_MODE
);
1106 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1108 } else if (kCFNumberFormatterRoundingIncrementKey
== key
) {
1109 d
= __cficu_unum_getDoubleAttribute(formatter
->_nf
, UNUM_ROUNDING_INCREMENT
);
1111 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberDoubleType
, &d
);
1113 } else if (kCFNumberFormatterFormatWidthKey
== key
) {
1114 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_FORMAT_WIDTH
);
1116 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1118 } else if (kCFNumberFormatterPaddingPositionKey
== key
) {
1119 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_PADDING_POSITION
);
1121 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1123 } else if (kCFNumberFormatterPaddingCharacterKey
== key
) {
1124 cnt
= __cficu_unum_getTextAttribute(formatter
->_nf
, UNUM_PADDING_CHARACTER
, ubuffer
, BUFFER_SIZE
, &status
);
1125 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1126 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1128 } else if (kCFNumberFormatterDefaultFormatKey
== key
) {
1129 return formatter
->_defformat
? CFRetain(formatter
->_defformat
) : NULL
;
1130 } else if (kCFNumberFormatterMultiplierKey
== key
) {
1131 return formatter
->_multiplier
? CFRetain(formatter
->_multiplier
) : NULL
;
1132 } else if (kCFNumberFormatterPositivePrefixKey
== key
) {
1133 cnt
= __cficu_unum_getTextAttribute(formatter
->_nf
, UNUM_POSITIVE_PREFIX
, ubuffer
, BUFFER_SIZE
, &status
);
1134 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1135 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1137 } else if (kCFNumberFormatterPositiveSuffixKey
== key
) {
1138 cnt
= __cficu_unum_getTextAttribute(formatter
->_nf
, UNUM_POSITIVE_SUFFIX
, ubuffer
, BUFFER_SIZE
, &status
);
1139 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1140 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1142 } else if (kCFNumberFormatterNegativePrefixKey
== key
) {
1143 cnt
= __cficu_unum_getTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, BUFFER_SIZE
, &status
);
1144 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1145 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1147 } else if (kCFNumberFormatterNegativeSuffixKey
== key
) {
1148 cnt
= __cficu_unum_getTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_SUFFIX
, ubuffer
, BUFFER_SIZE
, &status
);
1149 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1150 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1152 } else if (kCFNumberFormatterPerMillSymbolKey
== key
) {
1153 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_PERMILL_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1154 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1155 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1157 } else if (kCFNumberFormatterInternationalCurrencySymbolKey
== key
) {
1158 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_INTL_CURRENCY_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1159 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1160 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1162 } else if (kCFNumberFormatterCurrencyGroupingSeparatorKey
== key
) {
1163 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1164 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1165 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1167 } else if (kCFNumberFormatterIsLenientKey
== key
) {
1168 // __cficu_unum_getAttribute(, UNUM_LENIENT_PARSE) is undefined.
1169 return CFRetain(formatter
->_isLenient
? kCFBooleanTrue
: kCFBooleanFalse
);
1170 } else if (kCFNumberFormatterUseSignificantDigitsKey
== key
) {
1171 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_SIGNIFICANT_DIGITS_USED
);
1173 return CFRetain(n
? kCFBooleanTrue
: kCFBooleanFalse
);
1175 } else if (kCFNumberFormatterMinSignificantDigitsKey
== key
) {
1176 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_MIN_SIGNIFICANT_DIGITS
);
1178 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1180 } else if (kCFNumberFormatterMaxSignificantDigitsKey
== key
) {
1181 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_MAX_SIGNIFICANT_DIGITS
);
1183 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1186 CFAssert3(0, __kCFLogAssertion
, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__
, key
, key
);
1192 Boolean
CFNumberFormatterGetDecimalInfoForCurrencyCode(CFStringRef currencyCode
, int32_t *defaultFractionDigits
, double *roundingIncrement
) {
1194 __CFGenericValidateType(currencyCode
, CFStringGetTypeID());
1195 CFAssert1(3 == CFStringGetLength(currencyCode
), __kCFLogAssertion
, "%s(): currencyCode is not 3 characters", __PRETTY_FUNCTION__
);
1196 CFStringGetCharacters(currencyCode
, CFRangeMake(0, 3), (UniChar
*)ubuffer
);
1198 UErrorCode icuStatus
= U_ZERO_ERROR
;
1199 if (defaultFractionDigits
) *defaultFractionDigits
= __cficu_ucurr_getDefaultFractionDigits(ubuffer
, &icuStatus
);
1200 if (roundingIncrement
) *roundingIncrement
= __cficu_ucurr_getRoundingIncrement(ubuffer
, &icuStatus
);
1201 if (U_FAILURE(icuStatus
))
1203 return (!defaultFractionDigits
|| 0 <= *defaultFractionDigits
) && (!roundingIncrement
|| 0.0 <= *roundingIncrement
);