2 * Copyright (c) 2012 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-2012, 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 <unicode/unum.h>
35 #include <unicode/ucurr.h>
40 static void __CFNumberFormatterCustomize(CFNumberFormatterRef formatter
);
41 static CFStringRef
__CFNumberFormatterCreateCompressedString(CFStringRef inString
, Boolean isFormat
, CFRange
*rangep
);
42 static UErrorCode
__CFNumberFormatterApplyPattern(CFNumberFormatterRef formatter
, CFStringRef pattern
);
44 #define BUFFER_SIZE 768
46 struct __CFNumberFormatter
{
50 CFNumberFormatterStyle _style
;
51 CFStringRef _format
; // NULL for RBNFs
52 CFStringRef _defformat
;
53 CFStringRef _compformat
;
54 CFNumberRef _multiplier
;
57 Boolean _userSetMultiplier
;
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
) 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 if (NULL
== locale
) locale
= CFLocaleGetSystem();
119 memory
->_style
= style
;
122 case kCFNumberFormatterNoStyle
: ustyle
= UNUM_IGNORE
; break;
123 case kCFNumberFormatterDecimalStyle
: ustyle
= UNUM_DECIMAL
; break;
124 case kCFNumberFormatterCurrencyStyle
: ustyle
= UNUM_CURRENCY
; break;
125 case kCFNumberFormatterPercentStyle
: ustyle
= UNUM_PERCENT
; break;
126 case kCFNumberFormatterScientificStyle
: ustyle
= UNUM_SCIENTIFIC
; break;
127 case kCFNumberFormatterSpellOutStyle
: ustyle
= UNUM_SPELLOUT
; break;
128 case kCFNumberFormatterOrdinalStyle
: ustyle
= UNUM_ORDINAL
; break;
129 case kCFNumberFormatterDurationStyle
: ustyle
= UNUM_DURATION
; break;
131 CFAssert2(0, __kCFLogAssertion
, "%s(): unknown style %d", __PRETTY_FUNCTION__
, style
);
132 ustyle
= UNUM_DECIMAL
;
133 memory
->_style
= kCFNumberFormatterDecimalStyle
;
136 CFStringRef localeName
= locale
? CFLocaleGetIdentifier(locale
) : CFSTR("");
137 char buffer
[BUFFER_SIZE
];
138 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
140 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
146 UErrorCode status
= U_ZERO_ERROR
;
147 memory
->_nf
= unum_open((UNumberFormatStyle
)ustyle
, NULL
, 0, cstr
, NULL
, &status
);
148 CFAssert2(memory
->_nf
, __kCFLogAssertion
, "%s(): error (%d) creating number formatter", __PRETTY_FUNCTION__
, status
);
149 if (NULL
== memory
->_nf
) {
154 if (kCFNumberFormatterNoStyle
== style
) {
155 status
= U_ZERO_ERROR
;
156 ubuff
[0] = '#'; ubuff
[1] = ';'; ubuff
[2] = '#';
157 unum_applyPattern(memory
->_nf
, false, ubuff
, 3, NULL
, &status
);
158 unum_setAttribute(memory
->_nf
, UNUM_MAX_INTEGER_DIGITS
, 42);
159 unum_setAttribute(memory
->_nf
, UNUM_MAX_FRACTION_DIGITS
, 0);
161 memory
->_locale
= locale
? CFLocaleCreateCopy(allocator
, locale
) : CFLocaleGetSystem();
162 __CFNumberFormatterCustomize(memory
);
163 if (kCFNumberFormatterSpellOutStyle
!= memory
->_style
&& kCFNumberFormatterOrdinalStyle
!= memory
->_style
&& kCFNumberFormatterDurationStyle
!= memory
->_style
) {
164 UChar ubuffer
[BUFFER_SIZE
];
165 status
= U_ZERO_ERROR
;
166 int32_t ret
= unum_toPattern(memory
->_nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
167 if (U_SUCCESS(status
) && ret
<= BUFFER_SIZE
) {
168 memory
->_format
= CFStringCreateWithCharacters(allocator
, (const UniChar
*)ubuffer
, ret
);
171 memory
->_defformat
= memory
->_format
? (CFStringRef
)CFRetain(memory
->_format
) : NULL
;
172 memory
->_compformat
= memory
->_format
? __CFNumberFormatterCreateCompressedString(memory
->_format
, true, NULL
) : NULL
;
173 if (kCFNumberFormatterSpellOutStyle
!= memory
->_style
&& kCFNumberFormatterOrdinalStyle
!= memory
->_style
&& kCFNumberFormatterDurationStyle
!= memory
->_style
) {
174 int32_t n
= unum_getAttribute(memory
->_nf
, UNUM_MULTIPLIER
);
176 memory
->_multiplier
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, &n
);
177 unum_setAttribute(memory
->_nf
, UNUM_MULTIPLIER
, 1);
180 unum_setAttribute(memory
->_nf
, UNUM_LENIENT_PARSE
, 0);
181 return (CFNumberFormatterRef
)memory
;
184 extern CFDictionaryRef
__CFLocaleGetPrefs(CFLocaleRef locale
);
186 static void __substituteFormatStringFromPrefsNF(CFNumberFormatterRef formatter
) {
187 CFIndex formatStyle
= formatter
->_style
;
188 if (kCFNumberFormatterSpellOutStyle
== formatStyle
) return;
189 if (kCFNumberFormatterOrdinalStyle
== formatStyle
) return;
190 if (kCFNumberFormatterDurationStyle
== formatStyle
) return;
191 CFStringRef prefName
= CFSTR("AppleICUNumberFormatStrings");
192 if (kCFNumberFormatterNoStyle
!= formatStyle
) {
193 CFStringRef pref
= NULL
;
194 CFDictionaryRef prefs
= __CFLocaleGetPrefs(formatter
->_locale
);
195 CFPropertyListRef metapref
= prefs
? CFDictionaryGetValue(prefs
, prefName
) : NULL
;
196 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
198 switch (formatStyle
) {
199 case kCFNumberFormatterDecimalStyle
: key
= CFSTR("1"); break;
200 case kCFNumberFormatterCurrencyStyle
: key
= CFSTR("2"); break;
201 case kCFNumberFormatterPercentStyle
: key
= CFSTR("3"); break;
202 case kCFNumberFormatterScientificStyle
: key
= CFSTR("4"); break;
203 case kCFNumberFormatterSpellOutStyle
: key
= CFSTR("5"); break;
204 case kCFNumberFormatterOrdinalStyle
: key
= CFSTR("6"); break;
205 case kCFNumberFormatterDurationStyle
: key
= CFSTR("7"); break;
206 default: key
= CFSTR("0"); break;
208 pref
= (CFStringRef
)CFDictionaryGetValue((CFDictionaryRef
)metapref
, key
);
210 if (NULL
!= pref
&& CFGetTypeID(pref
) == CFStringGetTypeID()) {
211 int32_t icustyle
= UNUM_IGNORE
;
212 switch (formatStyle
) {
213 case kCFNumberFormatterDecimalStyle
: icustyle
= UNUM_DECIMAL
; break;
214 case kCFNumberFormatterCurrencyStyle
: icustyle
= UNUM_CURRENCY
; break;
215 case kCFNumberFormatterPercentStyle
: icustyle
= UNUM_PERCENT
; break;
216 case kCFNumberFormatterScientificStyle
: icustyle
= UNUM_SCIENTIFIC
; break;
217 case kCFNumberFormatterSpellOutStyle
: icustyle
= UNUM_SPELLOUT
; break;
218 case kCFNumberFormatterOrdinalStyle
: icustyle
= UNUM_ORDINAL
; break;
219 case kCFNumberFormatterDurationStyle
: icustyle
= UNUM_DURATION
; break;
221 CFStringRef localeName
= CFLocaleGetIdentifier(formatter
->_locale
);
222 char buffer
[BUFFER_SIZE
];
223 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
225 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
227 UErrorCode status
= U_ZERO_ERROR
;
228 UNumberFormat
*nf
= unum_open((UNumberFormatStyle
)icustyle
, NULL
, 0, cstr
, NULL
, &status
);
230 UChar ubuffer
[BUFFER_SIZE
];
231 status
= U_ZERO_ERROR
;
232 int32_t number_len
= unum_toPattern(nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
233 if (U_SUCCESS(status
) && number_len
<= BUFFER_SIZE
) {
234 CFStringRef numberString
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)ubuffer
, number_len
);
235 status
= U_ZERO_ERROR
;
236 int32_t formatter_len
= unum_toPattern(formatter
->_nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
237 if (U_SUCCESS(status
) && formatter_len
<= BUFFER_SIZE
) {
238 CFMutableStringRef formatString
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
239 CFStringAppendCharacters(formatString
, (const UniChar
*)ubuffer
, formatter_len
);
240 // find numberString inside formatString, substitute the pref in that range
242 if (CFStringFindWithOptions(formatString
, numberString
, CFRangeMake(0, formatter_len
), 0, &result
)) {
243 CFStringReplace(formatString
, result
, pref
);
244 __CFNumberFormatterApplyPattern(formatter
, formatString
);
246 CFRelease(formatString
);
248 CFRelease(numberString
);
256 static UniChar
__CFNumberFormatterNormalizeCharacter(UniChar c
) {
257 if (CFCharacterSetIsCharacterMember(CFCharacterSetGetPredefined(kCFCharacterSetWhitespace
), c
)) {
264 /* 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. */
265 static CFStringRef
__CFNumberFormatterCreateCompressedString(CFStringRef inString
, Boolean isFormat
, CFRange
*rangep
) {
266 if (!inString
) return NULL
;
267 CFRange range
= { 0, 0 };
271 range
.length
= CFStringGetLength(inString
);
273 CFMutableStringRef outString
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
274 CFCharacterSetRef letters
= CFCharacterSetGetPredefined(kCFCharacterSetLetter
);
275 CFCharacterSetRef numbers
= CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
);
276 UniChar prevCh
= 0, nextCh
= 0;
277 Boolean inQuote
= false;
278 for (CFIndex in_idx
= range
.location
; in_idx
< range
.location
+ range
.length
; in_idx
++) {
279 UniChar ch
= __CFNumberFormatterNormalizeCharacter(CFStringGetCharacterAtIndex(inString
, in_idx
));
280 nextCh
= (in_idx
+1 < range
.length
) ? CFStringGetCharacterAtIndex(inString
, in_idx
+1) : 0;
281 if (isFormat
&& ch
== '\'') inQuote
= !inQuote
;
282 if (inQuote
|| ch
!= ' ' || (CFCharacterSetIsCharacterMember(letters
, prevCh
) && CFCharacterSetIsCharacterMember(letters
, nextCh
)) || (CFCharacterSetIsCharacterMember(numbers
, prevCh
) && CFCharacterSetIsCharacterMember(numbers
, nextCh
))) {
283 CFStringAppendCharacters(outString
, &ch
, 1);
290 // Should not be called for rule-based ICU formatters; not supported
291 static void __CFNumberFormatterApplySymbolPrefs(const void *key
, const void *value
, void *context
) {
292 if (CFGetTypeID(key
) == CFStringGetTypeID() && CFGetTypeID(value
) == CFStringGetTypeID()) {
293 CFNumberFormatterRef formatter
= (CFNumberFormatterRef
)context
;
294 UNumberFormatSymbol sym
= (UNumberFormatSymbol
)CFStringGetIntValue((CFStringRef
)key
);
295 CFStringRef item
= (CFStringRef
)value
;
296 CFIndex item_cnt
= CFStringGetLength(item
);
297 STACK_BUFFER_DECL(UChar
, item_buffer
, item_cnt
);
298 UChar
*item_ustr
= (UChar
*)CFStringGetCharactersPtr(item
);
299 if (NULL
== item_ustr
) {
300 CFStringGetCharacters(item
, CFRangeMake(0, __CFMin(BUFFER_SIZE
, item_cnt
)), (UniChar
*)item_buffer
);
301 item_ustr
= item_buffer
;
303 UErrorCode status
= U_ZERO_ERROR
;
304 unum_setSymbol(formatter
->_nf
, sym
, item_ustr
, item_cnt
, &status
);
308 // Should not be called for rule-based ICU formatters
309 static UErrorCode
__CFNumberFormatterApplyPattern(CFNumberFormatterRef formatter
, CFStringRef pattern
) {
310 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
) return U_UNSUPPORTED_ERROR
;
311 if (kCFNumberFormatterOrdinalStyle
== formatter
->_style
) return U_UNSUPPORTED_ERROR
;
312 if (kCFNumberFormatterDurationStyle
== formatter
->_style
) return U_UNSUPPORTED_ERROR
;
313 CFIndex cnt
= CFStringGetLength(pattern
);
314 STACK_BUFFER_DECL(UChar
, ubuffer
, cnt
);
315 const UChar
*ustr
= (const UChar
*)CFStringGetCharactersPtr(pattern
);
317 CFStringGetCharacters(pattern
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
320 UErrorCode status
= U_ZERO_ERROR
;
321 unum_applyPattern(formatter
->_nf
, false, ustr
, cnt
, NULL
, &status
);
323 // unum_applyPattern() may have magically changed other attributes based on
324 // the contents of the format string; we simply expose that ICU behavior, except
325 // for UNUM_MULTIPLIER, which we re-read and reset, like we did at initialization
326 // time though any user-set multiplier state takes precedence.
327 if (formatter
->_userSetMultiplier
) {
328 unum_setAttribute(formatter
->_nf
, UNUM_MULTIPLIER
, 1);
330 if (formatter
->_multiplier
) CFRelease(formatter
->_multiplier
);
331 formatter
->_multiplier
= NULL
;
332 int32_t n
= unum_getAttribute(formatter
->_nf
, UNUM_MULTIPLIER
);
334 formatter
->_multiplier
= CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
335 unum_setAttribute(formatter
->_nf
, UNUM_MULTIPLIER
, 1);
341 static void __CFNumberFormatterCustomize(CFNumberFormatterRef formatter
) {
342 __substituteFormatStringFromPrefsNF(formatter
);
343 CFDictionaryRef prefs
= __CFLocaleGetPrefs(formatter
->_locale
);
344 CFPropertyListRef metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleICUNumberSymbols")) : NULL
;
345 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
346 CFDictionaryApplyFunction((CFDictionaryRef
)metapref
, __CFNumberFormatterApplySymbolPrefs
, formatter
);
350 CFLocaleRef
CFNumberFormatterGetLocale(CFNumberFormatterRef formatter
) {
351 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
352 return formatter
->_locale
;
355 CFNumberFormatterStyle
CFNumberFormatterGetStyle(CFNumberFormatterRef formatter
) {
356 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
357 return formatter
->_style
;
360 CFStringRef
CFNumberFormatterGetFormat(CFNumberFormatterRef formatter
) {
361 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
362 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
) return NULL
;
363 if (kCFNumberFormatterOrdinalStyle
== formatter
->_style
) return NULL
;
364 if (kCFNumberFormatterDurationStyle
== formatter
->_style
) return NULL
;
365 UChar ubuffer
[BUFFER_SIZE
];
366 CFStringRef newString
= NULL
;
367 UErrorCode status
= U_ZERO_ERROR
;
368 int32_t ret
= unum_toPattern(formatter
->_nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
369 if (U_SUCCESS(status
) && ret
<= BUFFER_SIZE
) {
370 newString
= CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, ret
);
372 if (newString
&& !formatter
->_format
) {
373 formatter
->_format
= newString
;
374 if (formatter
->_compformat
) CFRelease(formatter
->_compformat
);
375 formatter
->_compformat
= __CFNumberFormatterCreateCompressedString(formatter
->_format
, true, NULL
);
376 } else if (newString
&& !CFEqual(newString
, formatter
->_format
)) {
377 CFRelease(formatter
->_format
);
378 formatter
->_format
= newString
;
379 if (formatter
->_compformat
) CFRelease(formatter
->_compformat
);
380 formatter
->_compformat
= __CFNumberFormatterCreateCompressedString(formatter
->_format
, true, NULL
);
381 } else if (newString
) {
382 CFRelease(newString
);
384 return formatter
->_format
;
387 void CFNumberFormatterSetFormat(CFNumberFormatterRef formatter
, CFStringRef formatString
) {
388 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
389 __CFGenericValidateType(formatString
, CFStringGetTypeID());
390 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
) return;
391 if (kCFNumberFormatterOrdinalStyle
== formatter
->_style
) return;
392 if (kCFNumberFormatterDurationStyle
== formatter
->_style
) return;
393 CFIndex cnt
= CFStringGetLength(formatString
);
394 CFAssert1(cnt
<= 1024, __kCFLogAssertion
, "%s(): format string too long", __PRETTY_FUNCTION__
);
395 if ((!formatter
->_format
|| !CFEqual(formatter
->_format
, formatString
)) && cnt
<= 1024) {
396 UErrorCode status
= __CFNumberFormatterApplyPattern(formatter
, formatString
);
397 if (U_SUCCESS(status
)) {
398 UChar ubuffer2
[BUFFER_SIZE
];
399 status
= U_ZERO_ERROR
;
400 int32_t ret
= unum_toPattern(formatter
->_nf
, false, ubuffer2
, BUFFER_SIZE
, &status
);
401 if (U_SUCCESS(status
) && ret
<= BUFFER_SIZE
) {
402 if (formatter
->_format
) CFRelease(formatter
->_format
);
403 formatter
->_format
= CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer2
, ret
);
404 if (formatter
->_compformat
) CFRelease(formatter
->_compformat
);
405 formatter
->_compformat
= __CFNumberFormatterCreateCompressedString(formatter
->_format
, true, NULL
);
411 #define GET_MULTIPLIER \
412 double multiplier = 1.0; \
413 double dummy = 0.0; \
414 if (formatter->_multiplier) { \
415 if (!CFNumberGetValue(formatter->_multiplier, kCFNumberFloat64Type, &multiplier)) { \
419 if (modf(multiplier, &dummy) < FLT_EPSILON) { \
420 multiplier = floor(multiplier); \
423 CFStringRef
CFNumberFormatterCreateStringWithNumber(CFAllocatorRef allocator
, CFNumberFormatterRef formatter
, CFNumberRef number
) {
424 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
425 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
426 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
427 __CFGenericValidateType(number
, CFNumberGetTypeID());
428 CFNumberType type
= CFNumberGetType(number
);
430 CFNumberGetValue(number
, type
, buffer
);
431 return CFNumberFormatterCreateStringWithValue(allocator
, formatter
, type
, buffer
);
434 #define FORMAT_FLT(T, FUNC) \
435 T value = *(T *)valuePtr; \
436 if (0 == value && formatter->_zeroSym) { return (CFStringRef)CFRetain(formatter->_zeroSym); } \
437 if (1.0 != multiplier) { \
438 value = (T)(value * multiplier); \
440 status = U_ZERO_ERROR; \
441 used = FUNC(formatter->_nf, value, ubuffer, cnt, NULL, &status); \
442 if (status == U_BUFFER_OVERFLOW_ERROR || cnt < used) { \
444 ustr = (UChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UChar) * cnt, 0); \
445 status = U_ZERO_ERROR; \
446 used = FUNC(formatter->_nf, value, ustr, cnt, NULL, &status); \
449 #define FORMAT_INT(T, FUN) \
450 T value = *(T *)valuePtr; \
451 if (0 == value && formatter->_zeroSym) { return (CFStringRef)CFRetain(formatter->_zeroSym); } \
452 if (1.0 != multiplier) { \
453 value = (T)(value * multiplier); \
456 FUN(&bignum, value); \
457 char buffer[BUFFER_SIZE]; \
458 _CFBigNumToCString(&bignum, false, true, buffer, BUFFER_SIZE); \
459 status = U_ZERO_ERROR; \
460 used = unum_formatDecimal(formatter->_nf, buffer, strlen(buffer), ubuffer, BUFFER_SIZE, NULL, &status); \
461 if (status == U_BUFFER_OVERFLOW_ERROR || cnt < used) { \
463 ustr = (UChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UChar) * cnt, 0); \
464 status = U_ZERO_ERROR; \
465 used = unum_formatDecimal(formatter->_nf, buffer, strlen(buffer), ustr, cnt, NULL, &status); \
468 CFStringRef CFNumberFormatterCreateStringWithValue(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFNumberType numberType, const void *valuePtr) {
469 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
470 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
471 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
473 UChar
*ustr
= NULL
, ubuffer
[BUFFER_SIZE
];
474 UErrorCode status
= U_ZERO_ERROR
;
475 CFIndex used
, cnt
= BUFFER_SIZE
;
476 if (numberType
== kCFNumberFloat64Type
|| numberType
== kCFNumberDoubleType
) {
477 FORMAT_FLT(double, unum_formatDouble
)
478 } else if (numberType
== kCFNumberFloat32Type
|| numberType
== kCFNumberFloatType
) {
479 FORMAT_FLT(float, unum_formatDouble
)
480 } else if (numberType
== kCFNumberSInt64Type
|| numberType
== kCFNumberLongLongType
) {
481 FORMAT_INT(int64_t, _CFBigNumInitWithInt64
)
482 } else if (numberType
== kCFNumberLongType
|| numberType
== kCFNumberCFIndexType
) {
484 FORMAT_INT(int64_t, _CFBigNumInitWithInt64
)
486 FORMAT_INT(int32_t, _CFBigNumInitWithInt32
)
488 } else if (numberType
== kCFNumberSInt32Type
|| numberType
== kCFNumberIntType
) {
489 FORMAT_INT(int32_t, _CFBigNumInitWithInt32
)
490 } else if (numberType
== kCFNumberSInt16Type
|| numberType
== kCFNumberShortType
) {
491 FORMAT_INT(int16_t, _CFBigNumInitWithInt16
)
492 } else if (numberType
== kCFNumberSInt8Type
|| numberType
== kCFNumberCharType
) {
493 FORMAT_INT(int8_t, _CFBigNumInitWithInt8
)
495 CFAssert2(0, __kCFLogAssertion
, "%s(): unknown CFNumberType (%d)", __PRETTY_FUNCTION__
, numberType
);
498 CFStringRef string
= NULL
;
499 if (U_SUCCESS(status
)) {
500 string
= CFStringCreateWithCharacters(allocator
, ustr
? (const UniChar
*)ustr
: (const UniChar
*)ubuffer
, used
);
502 if (ustr
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, ustr
);
508 #undef GET_MULTIPLIER
510 CFNumberRef
CFNumberFormatterCreateNumberFromString(CFAllocatorRef allocator
, CFNumberFormatterRef formatter
, CFStringRef string
, CFRange
*rangep
, CFOptionFlags options
) {
511 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
512 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
513 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
514 __CFGenericValidateType(string
, CFStringGetTypeID());
515 char buffer
[16] __attribute__ ((aligned (8)));
516 CFRange r
= rangep
? *rangep
: CFRangeMake(0, CFStringGetLength(string
));
517 CFNumberRef multiplierRef
= formatter
->_multiplier
;
518 formatter
->_multiplier
= NULL
;
519 Boolean b
= CFNumberFormatterGetValueFromString(formatter
, string
, &r
, kCFNumberSInt64Type
, buffer
);
520 formatter
->_multiplier
= multiplierRef
;
522 Boolean passedMultiplier
= true;
523 // We handle the multiplier case here manually; the final
524 // result is supposed to be (parsed value) / (multiplier), but
525 // the int case here should only succeed if the parsed value
526 // is an exact multiple of the multiplier.
528 int64_t tmp
= *(int64_t *)buffer
;
529 double multiplier
= 1.0;
530 if (!CFNumberGetValue(multiplierRef
, kCFNumberFloat64Type
, &multiplier
)) {
534 if (llabs(tmp
) < fabs(multiplier
)) {
535 passedMultiplier
= false;
536 } else if (fabs(multiplier
) < 1.0) { // We can't handle this math yet
537 passedMultiplier
= false;
538 } else if (modf(multiplier
, &dummy
) == 0.0) { // multiplier is an integer
539 int64_t imult
= (int64_t)multiplier
;
540 int64_t rem
= tmp
% imult
;
541 if (rem
!= 0) passedMultiplier
= false;
542 if (passedMultiplier
) {
544 *(int64_t *)buffer
= tmp
;
546 } else if (multiplier
== -1.0) { // simple
548 *(int64_t *)buffer
= tmp
;
549 } else if (multiplier
!= 1.0) {
550 // First, throw away integer multiples of the multiplier to
551 // bring the value down to less than 2^53, so that we can
552 // cast it to double without losing any precision, important
553 // for the "remainder is zero" test.
554 // Find power of two which, when multiplier is multiplied by it,
555 // results in an integer value. pwr will be <= 52 since multiplier
559 while (modf(scalbn(multiplier
, pwr
), &intgrl
) != 0.0) pwr
++;
560 int64_t i2
= (int64_t)intgrl
;
561 // scale pwr and i2 up to a reasonably large value so the next loop doesn't take forever
562 while (llabs(i2
) < (1LL << 50)) { i2
*= 2; pwr
++; }
564 while ((1LL << 53) <= llabs(tmp
)) {
565 // subtract (multiplier * 2^pwr) each time
566 tmp
-= i2
; // move tmp toward zero
567 cnt
+= (1LL << pwr
); // remember how many 2^pwr we subtracted
569 // If the integer is less than 2^53, there is no loss
570 // in converting it to double, so we can just do the
571 // direct operation now.
572 double rem
= fmod((double)tmp
, multiplier
);
573 if (rem
!= 0.0) passedMultiplier
= false;
574 if (passedMultiplier
) {
575 // The original tmp, which we need to divide by multiplier, is at this point:
576 // tmp + k * 2^n * multiplier, where k is the number of loop iterations
577 // That original value needs to be divided by multiplier and put back in the
578 // buffer. Noting that k * 2^n == cnt, and after some algebra, we have:
579 tmp
= (int64_t)((double)tmp
/ multiplier
) + cnt
;
580 *(int64_t *)buffer
= tmp
;
584 if (passedMultiplier
&& ((r
.length
== CFStringGetLength(string
)) || (options
& kCFNumberFormatterParseIntegersOnly
))) {
585 if (rangep
) *rangep
= r
;
586 return CFNumberCreate(allocator
, kCFNumberSInt64Type
, buffer
);
589 if (options
& kCFNumberFormatterParseIntegersOnly
) return NULL
;
590 if (CFNumberFormatterGetValueFromString(formatter
, string
, rangep
, kCFNumberFloat64Type
, buffer
)) {
591 return CFNumberCreate(allocator
, kCFNumberFloat64Type
, buffer
);
596 Boolean
CFNumberFormatterGetValueFromString(CFNumberFormatterRef formatter
, CFStringRef string
, CFRange
*rangep
, CFNumberType numberType
, void *valuePtr
) {
597 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
598 __CFGenericValidateType(string
, CFStringGetTypeID());
599 CFStringRef stringToParse
= formatter
->_isLenient
? __CFNumberFormatterCreateCompressedString(string
, false, rangep
) : (CFStringRef
)CFRetain(string
);
600 CFRange range
= {0, 0};
601 if(formatter
->_isLenient
) {
602 range
.length
= CFStringGetLength(stringToParse
);
607 range
.length
= CFStringGetLength(stringToParse
);
609 // unum_parse chokes on leading whitespace
610 CFCharacterSetRef whitespace
= CFCharacterSetGetPredefined(kCFCharacterSetWhitespace
);
611 while(range
.length
> 0 && CFCharacterSetIsCharacterMember(whitespace
, CFStringGetCharacterAtIndex(stringToParse
, range
.location
))) {
616 Boolean isZero
= false;
617 if (formatter
->_zeroSym
) {
618 CFStringRef zeroSym
= formatter
->_isLenient
? __CFNumberFormatterCreateCompressedString(formatter
->_zeroSym
, false, NULL
) : (CFStringRef
)CFRetain(formatter
->_zeroSym
);
619 if (kCFCompareEqualTo
== CFStringCompare(stringToParse
, zeroSym
, 0)) {
624 if (1024 < range
.length
) range
.length
= 1024;
625 const UChar
*ustr
= (const UChar
*)CFStringGetCharactersPtr(stringToParse
);
626 STACK_BUFFER_DECL(UChar
, ubuffer
, (NULL
== ustr
) ? range
.length
: 1);
628 CFStringGetCharacters(stringToParse
, range
, (UniChar
*)ubuffer
);
630 } else if (!formatter
->_isLenient
) {
631 ustr
+= range
.location
;
633 CFNumberRef multiplierRef
= formatter
->_multiplier
;
634 formatter
->_multiplier
= NULL
;
635 if (formatter
->_isLenient
) {
636 __CFNumberFormatterApplyPattern(formatter
, formatter
->_compformat
);
637 if (formatter
->_multiplier
) CFRelease(formatter
->_multiplier
);
638 formatter
->_multiplier
= NULL
;
640 Boolean integerOnly
= 1;
641 switch (numberType
) {
642 case kCFNumberSInt8Type
: case kCFNumberCharType
:
643 case kCFNumberSInt16Type
: case kCFNumberShortType
:
644 case kCFNumberSInt32Type
: case kCFNumberIntType
:
645 case kCFNumberLongType
: case kCFNumberCFIndexType
:
646 case kCFNumberSInt64Type
: case kCFNumberLongLongType
:
647 unum_setAttribute(formatter
->_nf
, UNUM_PARSE_INT_ONLY
, 1); // ignored by ICU for rule-based formatters
650 unum_setAttribute(formatter
->_nf
, UNUM_PARSE_INT_ONLY
, 0); // ignored by ICU for rule-based formatters
655 UErrorCode status
= U_ZERO_ERROR
;
659 dpos
= rangep
? rangep
->length
: 0;
662 memset(buffer
, 0, sizeof(buffer
));
663 int32_t len
= unum_parseDecimal(formatter
->_nf
, ustr
, range
.length
, &dpos
, buffer
, sizeof(buffer
), &status
);
664 if (!U_FAILURE(status
) && 0 < len
&& integerOnly
) {
667 dreti
= strtoll_l(buffer
, &endptr
, 10, NULL
);
668 if (!(errno
== 0 && *endptr
== '\0')) status
= U_INVALID_FORMAT_ERROR
;
670 if (!U_FAILURE(status
) && 0 < len
) {
673 dretd
= strtod_l(buffer
, &endptr
, NULL
);
674 if (!(errno
== 0 && *endptr
== '\0')) status
= U_INVALID_FORMAT_ERROR
;
677 if (formatter
->_isLenient
) {
679 CFIndex uncompEnd
= rangep
->location
+ rangep
->length
;
680 CFIndex uncompIdx
= rangep
->location
;
681 for (CFIndex compIdx
= 0; compIdx
< dpos
&& uncompIdx
< uncompEnd
; compIdx
++, uncompIdx
++) {
682 while (uncompIdx
< uncompEnd
&& ustr
[compIdx
] != __CFNumberFormatterNormalizeCharacter(CFStringGetCharacterAtIndex(string
, uncompIdx
))) uncompIdx
++;
684 rangep
->length
= uncompIdx
- rangep
->location
;
686 __CFNumberFormatterApplyPattern(formatter
, formatter
->_format
);
687 if (formatter
->_multiplier
) CFRelease(formatter
->_multiplier
);
688 formatter
->_multiplier
= NULL
;
690 rangep
->length
= dpos
+ (range
.location
- rangep
->location
);
692 formatter
->_multiplier
= multiplierRef
;
693 CFRelease(stringToParse
);
694 if (U_FAILURE(status
)) {
697 if (formatter
->_multiplier
) {
698 double multiplier
= 1.0;
699 if (!CFNumberGetValue(formatter
->_multiplier
, kCFNumberFloat64Type
, &multiplier
)) {
702 dreti
= (int64_t)((double)dreti
/ multiplier
); // integer truncation, plus double cast can be lossy for dreti > 2^53
703 dretd
= dretd
/ multiplier
;
705 switch (numberType
) {
706 case kCFNumberSInt8Type
: case kCFNumberCharType
:
707 if (INT8_MIN
<= dreti
&& dreti
<= INT8_MAX
) {
708 *(int8_t *)valuePtr
= (int8_t)dreti
;
712 case kCFNumberSInt16Type
: case kCFNumberShortType
:
713 if (INT16_MIN
<= dreti
&& dreti
<= INT16_MAX
) {
714 *(int16_t *)valuePtr
= (int16_t)dreti
;
718 case kCFNumberSInt32Type
: case kCFNumberIntType
:
720 case kCFNumberLongType
: case kCFNumberCFIndexType
:
722 if (INT32_MIN
<= dreti
&& dreti
<= INT32_MAX
) {
723 *(int32_t *)valuePtr
= (int32_t)dreti
;
727 case kCFNumberSInt64Type
: case kCFNumberLongLongType
:
729 case kCFNumberLongType
: case kCFNumberCFIndexType
:
731 if (INT64_MIN
<= dreti
&& dreti
<= INT64_MAX
) {
732 *(int64_t *)valuePtr
= (int64_t)dreti
;
736 case kCFNumberFloat32Type
: case kCFNumberFloatType
:
737 if (-FLT_MAX
<= dretd
&& dretd
<= FLT_MAX
) {
738 *(float *)valuePtr
= (float)dretd
;
742 case kCFNumberFloat64Type
: case kCFNumberDoubleType
:
743 if (-DBL_MAX
<= dretd
&& dretd
<= DBL_MAX
) {
744 *(double *)valuePtr
= (double)dretd
;
752 void CFNumberFormatterSetProperty(CFNumberFormatterRef formatter
, CFStringRef key
, CFTypeRef value
) {
755 UErrorCode status
= U_ZERO_ERROR
;
756 UChar ubuffer
[BUFFER_SIZE
];
758 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
759 __CFGenericValidateType(key
, CFStringGetTypeID());
760 // rule-based formatters don't do attributes and symbols, except for one
761 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return;
762 if (kCFNumberFormatterOrdinalStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return;
763 if (kCFNumberFormatterDurationStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return;
764 if (kCFNumberFormatterCurrencyCodeKey
== key
) {
765 __CFGenericValidateType(value
, CFStringGetTypeID());
766 cnt
= CFStringGetLength((CFStringRef
)value
);
767 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
768 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
769 unum_setTextAttribute(formatter
->_nf
, UNUM_CURRENCY_CODE
, ubuffer
, cnt
, &status
);
770 } else if (kCFNumberFormatterDecimalSeparatorKey
== key
) {
771 __CFGenericValidateType(value
, CFStringGetTypeID());
772 cnt
= CFStringGetLength((CFStringRef
)value
);
773 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
774 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
775 unum_setSymbol(formatter
->_nf
, UNUM_DECIMAL_SEPARATOR_SYMBOL
, ubuffer
, cnt
, &status
);
776 } else if (kCFNumberFormatterCurrencyDecimalSeparatorKey
== key
) {
777 __CFGenericValidateType(value
, CFStringGetTypeID());
778 cnt
= CFStringGetLength((CFStringRef
)value
);
779 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
780 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
781 unum_setSymbol(formatter
->_nf
, UNUM_MONETARY_SEPARATOR_SYMBOL
, ubuffer
, cnt
, &status
);
782 } else if (kCFNumberFormatterAlwaysShowDecimalSeparatorKey
== key
) {
783 __CFGenericValidateType(value
, CFBooleanGetTypeID());
784 unum_setAttribute(formatter
->_nf
, UNUM_DECIMAL_ALWAYS_SHOWN
, (kCFBooleanTrue
== value
));
785 } else if (kCFNumberFormatterGroupingSeparatorKey
== key
) {
786 __CFGenericValidateType(value
, CFStringGetTypeID());
787 cnt
= CFStringGetLength((CFStringRef
)value
);
788 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
789 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
790 unum_setSymbol(formatter
->_nf
, UNUM_GROUPING_SEPARATOR_SYMBOL
, (const UChar
*)ubuffer
, cnt
, &status
);
791 } else if (kCFNumberFormatterUseGroupingSeparatorKey
== key
) {
792 __CFGenericValidateType(value
, CFBooleanGetTypeID());
793 unum_setAttribute(formatter
->_nf
, UNUM_GROUPING_USED
, (kCFBooleanTrue
== value
));
794 } else if (kCFNumberFormatterPercentSymbolKey
== key
) {
795 __CFGenericValidateType(value
, CFStringGetTypeID());
796 cnt
= CFStringGetLength((CFStringRef
)value
);
797 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
798 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
799 unum_setSymbol(formatter
->_nf
, UNUM_PERCENT_SYMBOL
, ubuffer
, cnt
, &status
);
800 } else if (kCFNumberFormatterZeroSymbolKey
== key
) {
801 __CFGenericValidateType(value
, CFStringGetTypeID());
802 CFStringRef old
= formatter
->_zeroSym
;
803 formatter
->_zeroSym
= value
? (CFStringRef
)CFRetain(value
) : NULL
;
804 if (old
) CFRelease(old
);
805 } else if (kCFNumberFormatterNaNSymbolKey
== 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 unum_setSymbol(formatter
->_nf
, UNUM_NAN_SYMBOL
, ubuffer
, cnt
, &status
);
811 } else if (kCFNumberFormatterInfinitySymbolKey
== key
) {
812 __CFGenericValidateType(value
, CFStringGetTypeID());
813 cnt
= CFStringGetLength((CFStringRef
)value
);
814 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
815 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
816 unum_setSymbol(formatter
->_nf
, UNUM_INFINITY_SYMBOL
, ubuffer
, cnt
, &status
);
817 } else if (kCFNumberFormatterMinusSignKey
== key
) {
818 __CFGenericValidateType(value
, CFStringGetTypeID());
819 cnt
= CFStringGetLength((CFStringRef
)value
);
820 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
821 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
822 unum_setSymbol(formatter
->_nf
, UNUM_MINUS_SIGN_SYMBOL
, ubuffer
, cnt
, &status
);
823 } else if (kCFNumberFormatterPlusSignKey
== key
) {
824 __CFGenericValidateType(value
, CFStringGetTypeID());
825 cnt
= CFStringGetLength((CFStringRef
)value
);
826 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
827 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
828 unum_setSymbol(formatter
->_nf
, UNUM_PLUS_SIGN_SYMBOL
, ubuffer
, cnt
, &status
);
829 } else if (kCFNumberFormatterCurrencySymbolKey
== key
) {
830 __CFGenericValidateType(value
, CFStringGetTypeID());
831 cnt
= CFStringGetLength((CFStringRef
)value
);
832 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
833 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
834 unum_setSymbol(formatter
->_nf
, UNUM_CURRENCY_SYMBOL
, (const UChar
*)ubuffer
, cnt
, &status
);
835 } else if (kCFNumberFormatterExponentSymbolKey
== key
) {
836 __CFGenericValidateType(value
, CFStringGetTypeID());
837 cnt
= CFStringGetLength((CFStringRef
)value
);
838 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
839 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
840 unum_setSymbol(formatter
->_nf
, UNUM_EXPONENTIAL_SYMBOL
, ubuffer
, cnt
, &status
);
841 } else if (kCFNumberFormatterMinIntegerDigitsKey
== key
) {
842 __CFGenericValidateType(value
, CFNumberGetTypeID());
843 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
844 unum_setAttribute(formatter
->_nf
, UNUM_MIN_INTEGER_DIGITS
, n
);
845 } else if (kCFNumberFormatterMaxIntegerDigitsKey
== key
) {
846 __CFGenericValidateType(value
, CFNumberGetTypeID());
847 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
848 unum_setAttribute(formatter
->_nf
, UNUM_MAX_INTEGER_DIGITS
, n
);
849 } else if (kCFNumberFormatterMinFractionDigitsKey
== key
) {
850 __CFGenericValidateType(value
, CFNumberGetTypeID());
851 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
852 unum_setAttribute(formatter
->_nf
, UNUM_MIN_FRACTION_DIGITS
, n
);
853 } else if (kCFNumberFormatterMaxFractionDigitsKey
== key
) {
854 __CFGenericValidateType(value
, CFNumberGetTypeID());
855 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
856 unum_setAttribute(formatter
->_nf
, UNUM_MAX_FRACTION_DIGITS
, n
);
857 } else if (kCFNumberFormatterGroupingSizeKey
== key
) {
858 __CFGenericValidateType(value
, CFNumberGetTypeID());
859 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
860 unum_setAttribute(formatter
->_nf
, UNUM_GROUPING_SIZE
, n
);
861 } else if (kCFNumberFormatterSecondaryGroupingSizeKey
== key
) {
862 __CFGenericValidateType(value
, CFNumberGetTypeID());
863 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
864 unum_setAttribute(formatter
->_nf
, UNUM_SECONDARY_GROUPING_SIZE
, n
);
865 } else if (kCFNumberFormatterRoundingModeKey
== key
) {
866 __CFGenericValidateType(value
, CFNumberGetTypeID());
867 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
868 unum_setAttribute(formatter
->_nf
, UNUM_ROUNDING_MODE
, n
);
869 } else if (kCFNumberFormatterRoundingIncrementKey
== key
) {
870 __CFGenericValidateType(value
, CFNumberGetTypeID());
871 CFNumberGetValue((CFNumberRef
)value
, kCFNumberDoubleType
, &d
);
872 unum_setDoubleAttribute(formatter
->_nf
, UNUM_ROUNDING_INCREMENT
, d
);
873 } else if (kCFNumberFormatterFormatWidthKey
== key
) {
874 __CFGenericValidateType(value
, CFNumberGetTypeID());
875 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
876 unum_setAttribute(formatter
->_nf
, UNUM_FORMAT_WIDTH
, n
);
877 } else if (kCFNumberFormatterPaddingPositionKey
== key
) {
878 __CFGenericValidateType(value
, CFNumberGetTypeID());
879 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
880 unum_setAttribute(formatter
->_nf
, UNUM_PADDING_POSITION
, n
);
881 } else if (kCFNumberFormatterPaddingCharacterKey
== key
) {
882 __CFGenericValidateType(value
, CFStringGetTypeID());
883 cnt
= CFStringGetLength((CFStringRef
)value
);
884 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
885 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
886 unum_setTextAttribute(formatter
->_nf
, UNUM_PADDING_CHARACTER
, ubuffer
, cnt
, &status
);
887 } else if (kCFNumberFormatterDefaultFormatKey
== key
) {
888 // read-only attribute
889 } else if (kCFNumberFormatterMultiplierKey
== key
) {
890 __CFGenericValidateType(value
, CFNumberGetTypeID());
891 CFNumberRef old
= formatter
->_multiplier
;
892 formatter
->_multiplier
= value
? (CFNumberRef
)CFRetain(value
) : NULL
;
893 formatter
->_userSetMultiplier
= value
? true : false;
894 if (old
) CFRelease(old
);
895 } else if (kCFNumberFormatterPositivePrefixKey
== key
) {
896 __CFGenericValidateType(value
, CFStringGetTypeID());
897 cnt
= CFStringGetLength((CFStringRef
)value
);
898 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
899 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
900 unum_setTextAttribute(formatter
->_nf
, UNUM_POSITIVE_PREFIX
, ubuffer
, cnt
, &status
);
901 } else if (kCFNumberFormatterPositiveSuffixKey
== key
) {
902 __CFGenericValidateType(value
, CFStringGetTypeID());
903 cnt
= CFStringGetLength((CFStringRef
)value
);
904 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
905 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
906 unum_setTextAttribute(formatter
->_nf
, UNUM_POSITIVE_SUFFIX
, (const UChar
*)ubuffer
, cnt
, &status
);
907 } else if (kCFNumberFormatterNegativePrefixKey
== key
) {
908 __CFGenericValidateType(value
, CFStringGetTypeID());
909 cnt
= CFStringGetLength((CFStringRef
)value
);
910 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
911 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
912 unum_setTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, cnt
, &status
);
913 } else if (kCFNumberFormatterNegativeSuffixKey
== key
) {
914 __CFGenericValidateType(value
, CFStringGetTypeID());
915 cnt
= CFStringGetLength((CFStringRef
)value
);
916 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
917 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
918 unum_setTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_SUFFIX
, (const UChar
*)ubuffer
, cnt
, &status
);
919 } else if (kCFNumberFormatterPerMillSymbolKey
== key
) {
920 __CFGenericValidateType(value
, CFStringGetTypeID());
921 cnt
= CFStringGetLength((CFStringRef
)value
);
922 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
923 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
924 unum_setSymbol(formatter
->_nf
, UNUM_PERMILL_SYMBOL
, ubuffer
, cnt
, &status
);
925 } else if (kCFNumberFormatterInternationalCurrencySymbolKey
== key
) {
926 __CFGenericValidateType(value
, CFStringGetTypeID());
927 cnt
= CFStringGetLength((CFStringRef
)value
);
928 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
929 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
930 unum_setSymbol(formatter
->_nf
, UNUM_INTL_CURRENCY_SYMBOL
, ubuffer
, cnt
, &status
);
931 } else if (kCFNumberFormatterCurrencyGroupingSeparatorKey
== key
) {
932 __CFGenericValidateType(value
, CFStringGetTypeID());
933 cnt
= CFStringGetLength((CFStringRef
)value
);
934 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
935 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
936 unum_setSymbol(formatter
->_nf
, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL
, ubuffer
, cnt
, &status
);
937 } else if (kCFNumberFormatterIsLenientKey
== key
) {
938 __CFGenericValidateType(value
, CFBooleanGetTypeID());
939 formatter
->_isLenient
= (kCFBooleanTrue
== value
);
940 unum_setAttribute(formatter
->_nf
, UNUM_LENIENT_PARSE
, (kCFBooleanTrue
== value
));
941 } else if (kCFNumberFormatterUseSignificantDigitsKey
== key
) {
942 __CFGenericValidateType(value
, CFBooleanGetTypeID());
943 unum_setAttribute(formatter
->_nf
, UNUM_SIGNIFICANT_DIGITS_USED
, (kCFBooleanTrue
== value
));
944 } else if (kCFNumberFormatterMinSignificantDigitsKey
== key
) {
945 __CFGenericValidateType(value
, CFNumberGetTypeID());
946 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
947 unum_setAttribute(formatter
->_nf
, UNUM_MIN_SIGNIFICANT_DIGITS
, n
);
948 } else if (kCFNumberFormatterMaxSignificantDigitsKey
== key
) {
949 __CFGenericValidateType(value
, CFNumberGetTypeID());
950 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
951 unum_setAttribute(formatter
->_nf
, UNUM_MAX_SIGNIFICANT_DIGITS
, n
);
953 CFAssert3(0, __kCFLogAssertion
, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__
, key
, key
);
955 if (_CFExecutableLinkedOnOrAfter(CFSystemVersionSnowLeopard
)) {
956 // do a dummy call to CFNumberFormatterGetFormat() after changing an attribute because
957 // ICU sometimes changes the pattern due to a property change, and we need to poke
958 // unum_toPattern() and also update our own variables
959 CFNumberFormatterGetFormat(formatter
);
963 CFTypeRef
CFNumberFormatterCopyProperty(CFNumberFormatterRef formatter
, CFStringRef key
) {
966 UErrorCode status
= U_ZERO_ERROR
;
967 UChar ubuffer
[BUFFER_SIZE
];
969 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
970 __CFGenericValidateType(key
, CFStringGetTypeID());
971 // rule-based formatters don't do attributes and symbols, except for one
972 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return NULL
;
973 if (kCFNumberFormatterOrdinalStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return NULL
;
974 if (kCFNumberFormatterDurationStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return NULL
;
975 if (kCFNumberFormatterCurrencyCodeKey
== key
) {
976 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_CURRENCY_CODE
, ubuffer
, BUFFER_SIZE
, &status
);
977 if (U_SUCCESS(status
) && cnt
== 0) {
978 CFStringRef localeName
= CFLocaleGetIdentifier(formatter
->_locale
);
979 char buffer
[BUFFER_SIZE
];
980 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
982 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
987 UErrorCode status
= U_ZERO_ERROR
;
988 UNumberFormat
*nf
= unum_open(UNUM_CURRENCY
, NULL
, 0, cstr
, NULL
, &status
);
990 cnt
= unum_getTextAttribute(nf
, UNUM_CURRENCY_CODE
, ubuffer
, BUFFER_SIZE
, &status
);
994 if (U_SUCCESS(status
) && 0 < cnt
&& cnt
<= BUFFER_SIZE
) {
995 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
997 } else if (kCFNumberFormatterDecimalSeparatorKey
== key
) {
998 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_DECIMAL_SEPARATOR_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
999 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1000 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1002 } else if (kCFNumberFormatterCurrencyDecimalSeparatorKey
== key
) {
1003 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_MONETARY_SEPARATOR_SYMBOL
, (UChar
*)ubuffer
, BUFFER_SIZE
, &status
);
1004 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1005 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1007 } else if (kCFNumberFormatterAlwaysShowDecimalSeparatorKey
== key
) {
1008 n
= unum_getAttribute(formatter
->_nf
, UNUM_DECIMAL_ALWAYS_SHOWN
);
1010 return CFRetain(n
? kCFBooleanTrue
: kCFBooleanFalse
);
1012 } else if (kCFNumberFormatterGroupingSeparatorKey
== key
) {
1013 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_GROUPING_SEPARATOR_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1014 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1015 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1017 } else if (kCFNumberFormatterUseGroupingSeparatorKey
== key
) {
1018 n
= unum_getAttribute(formatter
->_nf
, UNUM_GROUPING_USED
);
1020 return CFRetain(n
? kCFBooleanTrue
: kCFBooleanFalse
);
1022 } else if (kCFNumberFormatterPercentSymbolKey
== key
) {
1023 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_PERCENT_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1024 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1025 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1027 } else if (kCFNumberFormatterZeroSymbolKey
== key
) {
1028 return formatter
->_zeroSym
? CFRetain(formatter
->_zeroSym
) : NULL
;
1029 } else if (kCFNumberFormatterNaNSymbolKey
== key
) {
1030 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_NAN_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1031 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1032 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1034 } else if (kCFNumberFormatterInfinitySymbolKey
== key
) {
1035 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_INFINITY_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1036 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1037 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1039 } else if (kCFNumberFormatterMinusSignKey
== key
) {
1040 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_MINUS_SIGN_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1041 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1042 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1044 } else if (kCFNumberFormatterPlusSignKey
== key
) {
1045 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_PLUS_SIGN_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1046 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1047 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1049 } else if (kCFNumberFormatterCurrencySymbolKey
== key
) {
1050 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_CURRENCY_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1051 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1052 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1054 } else if (kCFNumberFormatterExponentSymbolKey
== key
) {
1055 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_EXPONENTIAL_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1056 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1057 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1059 } else if (kCFNumberFormatterMinIntegerDigitsKey
== key
) {
1060 n
= unum_getAttribute(formatter
->_nf
, UNUM_MIN_INTEGER_DIGITS
);
1062 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1064 } else if (kCFNumberFormatterMaxIntegerDigitsKey
== key
) {
1065 n
= unum_getAttribute(formatter
->_nf
, UNUM_MAX_INTEGER_DIGITS
);
1067 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1069 } else if (kCFNumberFormatterMinFractionDigitsKey
== key
) {
1070 n
= unum_getAttribute(formatter
->_nf
, UNUM_MIN_FRACTION_DIGITS
);
1072 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1074 } else if (kCFNumberFormatterMaxFractionDigitsKey
== key
) {
1075 n
= unum_getAttribute(formatter
->_nf
, UNUM_MAX_FRACTION_DIGITS
);
1077 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1079 } else if (kCFNumberFormatterGroupingSizeKey
== key
) {
1080 n
= unum_getAttribute(formatter
->_nf
, UNUM_GROUPING_SIZE
);
1082 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1084 } else if (kCFNumberFormatterSecondaryGroupingSizeKey
== key
) {
1085 n
= unum_getAttribute(formatter
->_nf
, UNUM_SECONDARY_GROUPING_SIZE
);
1087 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1089 } else if (kCFNumberFormatterRoundingModeKey
== key
) {
1090 n
= unum_getAttribute(formatter
->_nf
, UNUM_ROUNDING_MODE
);
1092 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1094 } else if (kCFNumberFormatterRoundingIncrementKey
== key
) {
1095 d
= unum_getDoubleAttribute(formatter
->_nf
, UNUM_ROUNDING_INCREMENT
);
1097 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberDoubleType
, &d
);
1099 } else if (kCFNumberFormatterFormatWidthKey
== key
) {
1100 n
= unum_getAttribute(formatter
->_nf
, UNUM_FORMAT_WIDTH
);
1102 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1104 } else if (kCFNumberFormatterPaddingPositionKey
== key
) {
1105 n
= unum_getAttribute(formatter
->_nf
, UNUM_PADDING_POSITION
);
1107 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1109 } else if (kCFNumberFormatterPaddingCharacterKey
== key
) {
1110 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_PADDING_CHARACTER
, ubuffer
, BUFFER_SIZE
, &status
);
1111 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1112 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1114 } else if (kCFNumberFormatterDefaultFormatKey
== key
) {
1115 return formatter
->_defformat
? CFRetain(formatter
->_defformat
) : NULL
;
1116 } else if (kCFNumberFormatterMultiplierKey
== key
) {
1117 return formatter
->_multiplier
? CFRetain(formatter
->_multiplier
) : NULL
;
1118 } else if (kCFNumberFormatterPositivePrefixKey
== key
) {
1119 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_POSITIVE_PREFIX
, ubuffer
, BUFFER_SIZE
, &status
);
1120 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1121 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1123 } else if (kCFNumberFormatterPositiveSuffixKey
== key
) {
1124 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_POSITIVE_SUFFIX
, ubuffer
, BUFFER_SIZE
, &status
);
1125 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1126 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1128 } else if (kCFNumberFormatterNegativePrefixKey
== key
) {
1129 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, BUFFER_SIZE
, &status
);
1130 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1131 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1133 } else if (kCFNumberFormatterNegativeSuffixKey
== key
) {
1134 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_SUFFIX
, ubuffer
, BUFFER_SIZE
, &status
);
1135 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1136 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1138 } else if (kCFNumberFormatterPerMillSymbolKey
== key
) {
1139 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_PERMILL_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1140 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1141 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1143 } else if (kCFNumberFormatterInternationalCurrencySymbolKey
== key
) {
1144 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_INTL_CURRENCY_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1145 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1146 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1148 } else if (kCFNumberFormatterCurrencyGroupingSeparatorKey
== key
) {
1149 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1150 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1151 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1153 } else if (kCFNumberFormatterIsLenientKey
== key
) {
1154 // unum_getAttribute(, UNUM_LENIENT_PARSE) is undefined.
1155 return CFRetain(formatter
->_isLenient
? kCFBooleanTrue
: kCFBooleanFalse
);
1156 } else if (kCFNumberFormatterUseSignificantDigitsKey
== key
) {
1157 n
= unum_getAttribute(formatter
->_nf
, UNUM_SIGNIFICANT_DIGITS_USED
);
1159 return CFRetain(n
? kCFBooleanTrue
: kCFBooleanFalse
);
1161 } else if (kCFNumberFormatterMinSignificantDigitsKey
== key
) {
1162 n
= unum_getAttribute(formatter
->_nf
, UNUM_MIN_SIGNIFICANT_DIGITS
);
1164 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1166 } else if (kCFNumberFormatterMaxSignificantDigitsKey
== key
) {
1167 n
= unum_getAttribute(formatter
->_nf
, UNUM_MAX_SIGNIFICANT_DIGITS
);
1169 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1172 CFAssert3(0, __kCFLogAssertion
, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__
, key
, key
);
1178 Boolean
CFNumberFormatterGetDecimalInfoForCurrencyCode(CFStringRef currencyCode
, int32_t *defaultFractionDigits
, double *roundingIncrement
) {
1180 __CFGenericValidateType(currencyCode
, CFStringGetTypeID());
1181 CFAssert1(3 == CFStringGetLength(currencyCode
), __kCFLogAssertion
, "%s(): currencyCode is not 3 characters", __PRETTY_FUNCTION__
);
1182 CFStringGetCharacters(currencyCode
, CFRangeMake(0, 3), (UniChar
*)ubuffer
);
1184 UErrorCode icuStatus
= U_ZERO_ERROR
;
1185 if (defaultFractionDigits
) *defaultFractionDigits
= ucurr_getDefaultFractionDigits(ubuffer
, &icuStatus
);
1186 if (roundingIncrement
) *roundingIncrement
= ucurr_getRoundingIncrement(ubuffer
, &icuStatus
);
1187 if (U_FAILURE(icuStatus
))
1189 return (!defaultFractionDigits
|| 0 <= *defaultFractionDigits
) && (!roundingIncrement
|| 0.0 <= *roundingIncrement
);