2 * Copyright (c) 2015 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-2014, 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
);
42 static CONST_STRING_DECL(kCFNumberFormatterFormattingContextKey
, "kCFNumberFormatterFormattingContextKey");
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
;
58 Boolean _usesCharacterDirection
;
61 static CFStringRef
__CFNumberFormatterCopyDescription(CFTypeRef cf
) {
62 CFNumberFormatterRef formatter
= (CFNumberFormatterRef
)cf
;
63 return CFStringCreateWithFormat(CFGetAllocator(formatter
), NULL
, CFSTR("<CFNumberFormatter %p [%p]>"), cf
, CFGetAllocator(formatter
));
66 static void __CFNumberFormatterDeallocate(CFTypeRef cf
) {
67 CFNumberFormatterRef formatter
= (CFNumberFormatterRef
)cf
;
68 if (formatter
->_nf
) __cficu_unum_close(formatter
->_nf
);
69 if (formatter
->_locale
) CFRelease(formatter
->_locale
);
70 if (formatter
->_format
) CFRelease(formatter
->_format
);
71 if (formatter
->_defformat
) CFRelease(formatter
->_defformat
);
72 if (formatter
->_compformat
) CFRelease(formatter
->_compformat
);
73 if (formatter
->_multiplier
) CFRelease(formatter
->_multiplier
);
74 if (formatter
->_zeroSym
) CFRelease(formatter
->_zeroSym
);
77 static CFTypeID __kCFNumberFormatterTypeID
= _kCFRuntimeNotATypeID
;
79 static const CFRuntimeClass __CFNumberFormatterClass
= {
84 __CFNumberFormatterDeallocate
,
88 __CFNumberFormatterCopyDescription
91 CFTypeID
CFNumberFormatterGetTypeID(void) {
92 static dispatch_once_t initOnce
;
93 dispatch_once(&initOnce
, ^{ __kCFNumberFormatterTypeID
= _CFRuntimeRegisterClass(&__CFNumberFormatterClass
); });
94 return __kCFNumberFormatterTypeID
;
97 CFNumberFormatterRef
CFNumberFormatterCreate(CFAllocatorRef allocator
, CFLocaleRef locale
, CFNumberFormatterStyle style
) {
98 struct __CFNumberFormatter
*memory
;
99 uint32_t size
= sizeof(struct __CFNumberFormatter
) - sizeof(CFRuntimeBase
);
100 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
101 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
102 __CFGenericValidateType(locale
, CFLocaleGetTypeID());
103 memory
= (struct __CFNumberFormatter
*)_CFRuntimeCreateInstance(allocator
, CFNumberFormatterGetTypeID(), size
, NULL
);
104 if (NULL
== memory
) {
108 memory
->_locale
= NULL
;
109 memory
->_format
= NULL
;
110 memory
->_defformat
= NULL
;
111 memory
->_compformat
= NULL
;
112 memory
->_multiplier
= NULL
;
113 memory
->_zeroSym
= NULL
;
114 memory
->_isLenient
= false;
115 memory
->_userSetMultiplier
= false;
116 memory
->_usesCharacterDirection
= false;
117 if (NULL
== locale
) locale
= CFLocaleGetSystem();
118 memory
->_style
= style
;
121 case kCFNumberFormatterNoStyle
: ustyle
= UNUM_IGNORE
; break;
122 case kCFNumberFormatterDecimalStyle
: ustyle
= UNUM_DECIMAL
; break;
123 case kCFNumberFormatterCurrencyStyle
: ustyle
= UNUM_CURRENCY
; break;
124 case kCFNumberFormatterPercentStyle
: ustyle
= UNUM_PERCENT
; break;
125 case kCFNumberFormatterScientificStyle
: ustyle
= UNUM_SCIENTIFIC
; break;
126 case kCFNumberFormatterSpellOutStyle
: ustyle
= UNUM_SPELLOUT
; break;
127 case kCFNumberFormatterOrdinalStyle
: ustyle
= UNUM_ORDINAL
; break;
128 case kCFNumberFormatterDurationStyle
: ustyle
= UNUM_DURATION
; break;
130 CFAssert2(0, __kCFLogAssertion
, "%s(): unknown style %d", __PRETTY_FUNCTION__
, style
);
131 ustyle
= UNUM_DECIMAL
;
132 memory
->_style
= kCFNumberFormatterDecimalStyle
;
135 CFStringRef localeName
= locale
? CFLocaleGetIdentifier(locale
) : CFSTR("");
136 char buffer
[BUFFER_SIZE
];
137 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
139 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
145 UErrorCode status
= U_ZERO_ERROR
;
146 memory
->_nf
= __cficu_unum_open((UNumberFormatStyle
)ustyle
, NULL
, 0, cstr
, NULL
, &status
);
147 CFAssert2(memory
->_nf
, __kCFLogAssertion
, "%s(): error (%d) creating number formatter", __PRETTY_FUNCTION__
, status
);
148 if (NULL
== memory
->_nf
) {
153 if (kCFNumberFormatterNoStyle
== style
) {
154 status
= U_ZERO_ERROR
;
155 ubuff
[0] = '#'; ubuff
[1] = ';'; ubuff
[2] = '#';
156 __cficu_unum_applyPattern(memory
->_nf
, false, ubuff
, 3, NULL
, &status
);
157 __cficu_unum_setAttribute(memory
->_nf
, UNUM_MAX_INTEGER_DIGITS
, 42);
158 __cficu_unum_setAttribute(memory
->_nf
, UNUM_MAX_FRACTION_DIGITS
, 0);
160 memory
->_locale
= locale
? CFLocaleCreateCopy(allocator
, locale
) : CFLocaleGetSystem();
161 __CFNumberFormatterCustomize(memory
);
162 if (kCFNumberFormatterSpellOutStyle
!= memory
->_style
&& kCFNumberFormatterOrdinalStyle
!= memory
->_style
&& kCFNumberFormatterDurationStyle
!= memory
->_style
) {
163 UChar ubuffer
[BUFFER_SIZE
];
164 status
= U_ZERO_ERROR
;
165 int32_t ret
= __cficu_unum_toPattern(memory
->_nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
166 if (U_SUCCESS(status
) && ret
<= BUFFER_SIZE
) {
167 memory
->_format
= CFStringCreateWithCharacters(allocator
, (const UniChar
*)ubuffer
, ret
);
170 memory
->_defformat
= memory
->_format
? (CFStringRef
)CFRetain(memory
->_format
) : NULL
;
171 memory
->_compformat
= memory
->_format
? __CFNumberFormatterCreateCompressedString(memory
->_format
, true, NULL
) : NULL
;
172 if (kCFNumberFormatterSpellOutStyle
!= memory
->_style
&& kCFNumberFormatterOrdinalStyle
!= memory
->_style
&& kCFNumberFormatterDurationStyle
!= memory
->_style
) {
173 int32_t n
= __cficu_unum_getAttribute(memory
->_nf
, UNUM_MULTIPLIER
);
175 memory
->_multiplier
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, &n
);
176 __cficu_unum_setAttribute(memory
->_nf
, UNUM_MULTIPLIER
, 1);
179 __cficu_unum_setAttribute(memory
->_nf
, UNUM_LENIENT_PARSE
, 0);
180 __cficu_unum_setContext(memory
->_nf
, UDISPCTX_CAPITALIZATION_NONE
, &status
);
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
= __cficu_unum_open((UNumberFormatStyle
)icustyle
, NULL
, 0, cstr
, NULL
, &status
);
230 UChar ubuffer
[BUFFER_SIZE
];
231 status
= U_ZERO_ERROR
;
232 int32_t number_len
= __cficu_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
= __cficu_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
);
250 __cficu_unum_close(nf
);
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 __cficu_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 __cficu_unum_applyPattern(formatter
->_nf
, false, ustr
, cnt
, NULL
, &status
);
323 // __cficu_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 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_MULTIPLIER
, 1);
330 if (formatter
->_multiplier
) CFRelease(formatter
->_multiplier
);
331 formatter
->_multiplier
= NULL
;
332 int32_t n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_MULTIPLIER
);
334 formatter
->_multiplier
= CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
335 __cficu_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
= __cficu_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
= __cficu_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 // The values of CFNumbers with large unsigned 64-bit ints don't survive well through this
429 CFNumberType type
= CFNumberGetType(number
);
431 CFNumberGetValue(number
, type
, buffer
);
432 return CFNumberFormatterCreateStringWithValue(allocator
, formatter
, type
, buffer
);
435 #define FORMAT_FLT(T, FUNC) \
436 T value = *(T *)valuePtr; \
437 if (0 == value && formatter->_zeroSym) { return (CFStringRef)CFRetain(formatter->_zeroSym); } \
438 if (1.0 != multiplier) { \
439 value = (T)(value * multiplier); \
441 status = U_ZERO_ERROR; \
442 used = FUNC(formatter->_nf, value, ubuffer + 1, cnt, NULL, &status); \
443 if (status == U_BUFFER_OVERFLOW_ERROR || cnt < used) { \
444 cnt = used + 1 + 1; \
445 ustr = (UChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UChar) * cnt, 0); \
446 status = U_ZERO_ERROR; \
447 used = FUNC(formatter->_nf, value, ustr + 1, cnt, NULL, &status); \
450 #define FORMAT_INT(T, FUN) \
451 T value = *(T *)valuePtr; \
452 if (0 == value && formatter->_zeroSym) { return (CFStringRef)CFRetain(formatter->_zeroSym); } \
453 if (1.0 != multiplier) { \
454 value = (T)(value * multiplier); \
457 FUN(&bignum, value); \
458 char buffer[BUFFER_SIZE + 1]; \
459 _CFBigNumToCString(&bignum, false, true, buffer, BUFFER_SIZE); \
460 status = U_ZERO_ERROR; \
461 used = __cficu_unum_formatDecimal(formatter->_nf, buffer, strlen(buffer), ubuffer + 1, BUFFER_SIZE, NULL, &status); \
462 if (status == U_BUFFER_OVERFLOW_ERROR || cnt < used) { \
463 cnt = used + 1 + 1; \
464 ustr = (UChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UChar) * cnt, 0); \
465 status = U_ZERO_ERROR; \
466 used = __cficu_unum_formatDecimal(formatter->_nf, buffer, strlen(buffer), ustr + 1, cnt, NULL, &status); \
469 CFStringRef CFNumberFormatterCreateStringWithValue(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFNumberType numberType, const void *valuePtr) {
470 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
471 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
472 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
474 UChar
*ustr
= NULL
, ubuffer
[BUFFER_SIZE
+ 1];
475 UErrorCode status
= U_ZERO_ERROR
;
476 CFIndex used
, cnt
= BUFFER_SIZE
;
477 if (numberType
== kCFNumberFloat64Type
|| numberType
== kCFNumberDoubleType
) {
478 FORMAT_FLT(double, __cficu_unum_formatDouble
)
479 } else if (numberType
== kCFNumberFloat32Type
|| numberType
== kCFNumberFloatType
) {
480 FORMAT_FLT(float, __cficu_unum_formatDouble
)
481 } else if (numberType
== kCFNumberSInt64Type
|| numberType
== kCFNumberLongLongType
) {
482 FORMAT_INT(int64_t, _CFBigNumInitWithInt64
)
483 } else if (numberType
== kCFNumberLongType
|| numberType
== kCFNumberCFIndexType
) {
485 FORMAT_INT(int64_t, _CFBigNumInitWithInt64
)
487 FORMAT_INT(int32_t, _CFBigNumInitWithInt32
)
489 } else if (numberType
== kCFNumberSInt32Type
|| numberType
== kCFNumberIntType
) {
490 FORMAT_INT(int32_t, _CFBigNumInitWithInt32
)
491 } else if (numberType
== kCFNumberSInt16Type
|| numberType
== kCFNumberShortType
) {
492 FORMAT_INT(int16_t, _CFBigNumInitWithInt16
)
493 } else if (numberType
== kCFNumberSInt8Type
|| numberType
== kCFNumberCharType
) {
494 FORMAT_INT(int8_t, _CFBigNumInitWithInt8
)
496 CFAssert2(0, __kCFLogAssertion
, "%s(): unknown CFNumberType (%d)", __PRETTY_FUNCTION__
, numberType
);
499 CFStringRef string
= NULL
;
500 if (U_SUCCESS(status
)) {
501 UniChar
*bufferToUse
= ustr
? (UniChar
*)ustr
: (UniChar
*)ubuffer
;
502 if (formatter
->_usesCharacterDirection
&& CFLocaleGetLanguageCharacterDirection(CFLocaleGetIdentifier(formatter
->_locale
)) == kCFLocaleLanguageDirectionRightToLeft
) {
503 // Insert Unicode RTL marker
504 bufferToUse
[0] = 0x200F;
507 // Move past direction marker
510 string
= CFStringCreateWithCharacters(allocator
, bufferToUse
, used
);
512 if (ustr
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, ustr
);
518 #undef GET_MULTIPLIER
520 CFNumberRef
CFNumberFormatterCreateNumberFromString(CFAllocatorRef allocator
, CFNumberFormatterRef formatter
, CFStringRef string
, CFRange
*rangep
, CFOptionFlags options
) {
521 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
522 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
523 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
524 __CFGenericValidateType(string
, CFStringGetTypeID());
525 char buffer
[16] __attribute__ ((aligned (8)));
526 CFRange r
= rangep
? *rangep
: CFRangeMake(0, CFStringGetLength(string
));
527 CFNumberRef multiplierRef
= formatter
->_multiplier
;
528 formatter
->_multiplier
= NULL
;
529 Boolean b
= CFNumberFormatterGetValueFromString(formatter
, string
, &r
, kCFNumberSInt64Type
, buffer
);
530 formatter
->_multiplier
= multiplierRef
;
532 Boolean passedMultiplier
= true;
533 // We handle the multiplier case here manually; the final
534 // result is supposed to be (parsed value) / (multiplier), but
535 // the int case here should only succeed if the parsed value
536 // is an exact multiple of the multiplier.
538 int64_t tmp
= *(int64_t *)buffer
;
539 double multiplier
= 1.0;
540 if (!CFNumberGetValue(multiplierRef
, kCFNumberFloat64Type
, &multiplier
)) {
544 if (llabs(tmp
) < fabs(multiplier
)) {
545 passedMultiplier
= false;
546 } else if (fabs(multiplier
) < 1.0) { // We can't handle this math yet
547 passedMultiplier
= false;
548 } else if (modf(multiplier
, &dummy
) == 0.0) { // multiplier is an integer
549 int64_t imult
= (int64_t)multiplier
;
550 int64_t rem
= tmp
% imult
;
551 if (rem
!= 0) passedMultiplier
= false;
552 if (passedMultiplier
) {
554 *(int64_t *)buffer
= tmp
;
556 } else if (multiplier
== -1.0) { // simple
558 *(int64_t *)buffer
= tmp
;
559 } else if (multiplier
!= 1.0) {
560 // First, throw away integer multiples of the multiplier to
561 // bring the value down to less than 2^53, so that we can
562 // cast it to double without losing any precision, important
563 // for the "remainder is zero" test.
564 // Find power of two which, when multiplier is multiplied by it,
565 // results in an integer value. pwr will be <= 52 since multiplier
569 while (modf(scalbn(multiplier
, pwr
), &intgrl
) != 0.0) pwr
++;
570 int64_t i2
= (int64_t)intgrl
;
571 // scale pwr and i2 up to a reasonably large value so the next loop doesn't take forever
572 while (llabs(i2
) < (1LL << 50)) { i2
*= 2; pwr
++; }
574 while ((1LL << 53) <= llabs(tmp
)) {
575 // subtract (multiplier * 2^pwr) each time
576 tmp
-= i2
; // move tmp toward zero
577 cnt
+= (1LL << pwr
); // remember how many 2^pwr we subtracted
579 // If the integer is less than 2^53, there is no loss
580 // in converting it to double, so we can just do the
581 // direct operation now.
582 double rem
= fmod((double)tmp
, multiplier
);
583 if (rem
!= 0.0) passedMultiplier
= false;
584 if (passedMultiplier
) {
585 // The original tmp, which we need to divide by multiplier, is at this point:
586 // tmp + k * 2^n * multiplier, where k is the number of loop iterations
587 // That original value needs to be divided by multiplier and put back in the
588 // buffer. Noting that k * 2^n == cnt, and after some algebra, we have:
589 tmp
= (int64_t)((double)tmp
/ multiplier
) + cnt
;
590 *(int64_t *)buffer
= tmp
;
594 if (passedMultiplier
&& ((r
.length
== CFStringGetLength(string
)) || (options
& kCFNumberFormatterParseIntegersOnly
))) {
595 if (rangep
) *rangep
= r
;
596 return CFNumberCreate(allocator
, kCFNumberSInt64Type
, buffer
);
599 if (options
& kCFNumberFormatterParseIntegersOnly
) return NULL
;
600 if (CFNumberFormatterGetValueFromString(formatter
, string
, rangep
, kCFNumberFloat64Type
, buffer
)) {
601 return CFNumberCreate(allocator
, kCFNumberFloat64Type
, buffer
);
606 Boolean
CFNumberFormatterGetValueFromString(CFNumberFormatterRef formatter
, CFStringRef string
, CFRange
*rangep
, CFNumberType numberType
, void *valuePtr
) {
607 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
608 __CFGenericValidateType(string
, CFStringGetTypeID());
609 CFStringRef stringToParse
= formatter
->_isLenient
? __CFNumberFormatterCreateCompressedString(string
, false, rangep
) : (CFStringRef
)CFRetain(string
);
610 CFRange range
= {0, 0};
611 if(formatter
->_isLenient
) {
612 range
.length
= CFStringGetLength(stringToParse
);
617 range
.length
= CFStringGetLength(stringToParse
);
619 // __cficu_unum_parse chokes on leading whitespace
620 CFCharacterSetRef whitespace
= CFCharacterSetGetPredefined(kCFCharacterSetWhitespace
);
621 while(range
.length
> 0 && CFCharacterSetIsCharacterMember(whitespace
, CFStringGetCharacterAtIndex(stringToParse
, range
.location
))) {
626 Boolean isZero
= false;
627 if (formatter
->_zeroSym
) {
628 CFStringRef zeroSym
= formatter
->_isLenient
? __CFNumberFormatterCreateCompressedString(formatter
->_zeroSym
, false, NULL
) : (CFStringRef
)CFRetain(formatter
->_zeroSym
);
629 if (kCFCompareEqualTo
== CFStringCompare(stringToParse
, zeroSym
, 0)) {
634 if (1024 < range
.length
) range
.length
= 1024;
635 const UChar
*ustr
= (const UChar
*)CFStringGetCharactersPtr(stringToParse
);
636 STACK_BUFFER_DECL(UChar
, ubuffer
, (NULL
== ustr
) ? range
.length
: 1);
638 CFStringGetCharacters(stringToParse
, range
, (UniChar
*)ubuffer
);
640 } else if (!formatter
->_isLenient
) {
641 ustr
+= range
.location
;
643 CFNumberRef multiplierRef
= formatter
->_multiplier
;
644 formatter
->_multiplier
= NULL
;
645 if (formatter
->_isLenient
) {
646 __CFNumberFormatterApplyPattern(formatter
, formatter
->_compformat
);
647 if (formatter
->_multiplier
) CFRelease(formatter
->_multiplier
);
648 formatter
->_multiplier
= NULL
;
650 Boolean integerOnly
= 1;
651 switch (numberType
) {
652 case kCFNumberSInt8Type
: case kCFNumberCharType
:
653 case kCFNumberSInt16Type
: case kCFNumberShortType
:
654 case kCFNumberSInt32Type
: case kCFNumberIntType
:
655 case kCFNumberLongType
: case kCFNumberCFIndexType
:
656 case kCFNumberSInt64Type
: case kCFNumberLongLongType
:
657 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_PARSE_INT_ONLY
, 1); // ignored by ICU for rule-based formatters
660 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_PARSE_INT_ONLY
, 0); // ignored by ICU for rule-based formatters
665 UErrorCode status
= U_ZERO_ERROR
;
669 dpos
= rangep
? rangep
->length
: 0;
672 memset(buffer
, 0, sizeof(buffer
));
673 int32_t len
= __cficu_unum_parseDecimal(formatter
->_nf
, ustr
, range
.length
, &dpos
, buffer
, sizeof(buffer
), &status
);
674 if (!U_FAILURE(status
) && 0 < len
&& integerOnly
) {
677 dreti
= strtoll_l(buffer
, &endptr
, 10, NULL
);
678 if (!(errno
== 0 && *endptr
== '\0')) status
= U_INVALID_FORMAT_ERROR
;
680 if (!U_FAILURE(status
) && 0 < len
) {
683 dretd
= strtod_l(buffer
, &endptr
, NULL
);
684 if (!(errno
== 0 && *endptr
== '\0')) status
= U_INVALID_FORMAT_ERROR
;
687 if (formatter
->_isLenient
) {
689 CFIndex uncompEnd
= rangep
->location
+ rangep
->length
;
690 CFIndex uncompIdx
= rangep
->location
;
691 for (CFIndex compIdx
= 0; compIdx
< dpos
&& uncompIdx
< uncompEnd
; compIdx
++, uncompIdx
++) {
692 while (uncompIdx
< uncompEnd
&& ustr
[compIdx
] != __CFNumberFormatterNormalizeCharacter(CFStringGetCharacterAtIndex(string
, uncompIdx
))) uncompIdx
++;
694 rangep
->length
= uncompIdx
- rangep
->location
;
696 __CFNumberFormatterApplyPattern(formatter
, formatter
->_format
);
697 if (formatter
->_multiplier
) CFRelease(formatter
->_multiplier
);
698 formatter
->_multiplier
= NULL
;
700 rangep
->length
= dpos
+ (range
.location
- rangep
->location
);
702 formatter
->_multiplier
= multiplierRef
;
703 CFRelease(stringToParse
);
704 if (U_FAILURE(status
)) {
707 if (formatter
->_multiplier
) {
708 double multiplier
= 1.0;
709 if (!CFNumberGetValue(formatter
->_multiplier
, kCFNumberFloat64Type
, &multiplier
)) {
712 dreti
= (int64_t)((double)dreti
/ multiplier
); // integer truncation, plus double cast can be lossy for dreti > 2^53
713 dretd
= dretd
/ multiplier
;
715 switch (numberType
) {
716 case kCFNumberSInt8Type
: case kCFNumberCharType
:
717 if (INT8_MIN
<= dreti
&& dreti
<= INT8_MAX
) {
718 *(int8_t *)valuePtr
= (int8_t)dreti
;
722 case kCFNumberSInt16Type
: case kCFNumberShortType
:
723 if (INT16_MIN
<= dreti
&& dreti
<= INT16_MAX
) {
724 *(int16_t *)valuePtr
= (int16_t)dreti
;
728 case kCFNumberSInt32Type
: case kCFNumberIntType
:
730 case kCFNumberLongType
: case kCFNumberCFIndexType
:
732 if (INT32_MIN
<= dreti
&& dreti
<= INT32_MAX
) {
733 *(int32_t *)valuePtr
= (int32_t)dreti
;
737 case kCFNumberSInt64Type
: case kCFNumberLongLongType
:
739 case kCFNumberLongType
: case kCFNumberCFIndexType
:
741 if (INT64_MIN
<= dreti
&& dreti
<= INT64_MAX
) {
742 *(int64_t *)valuePtr
= (int64_t)dreti
;
746 case kCFNumberFloat32Type
: case kCFNumberFloatType
:
747 if (-FLT_MAX
<= dretd
&& dretd
<= FLT_MAX
) {
748 *(float *)valuePtr
= (float)dretd
;
752 case kCFNumberFloat64Type
: case kCFNumberDoubleType
:
753 if (-DBL_MAX
<= dretd
&& dretd
<= DBL_MAX
) {
754 *(double *)valuePtr
= (double)dretd
;
762 void CFNumberFormatterSetProperty(CFNumberFormatterRef formatter
, CFStringRef key
, CFTypeRef value
) {
765 UErrorCode status
= U_ZERO_ERROR
;
766 UChar ubuffer
[BUFFER_SIZE
];
768 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
769 __CFGenericValidateType(key
, CFStringGetTypeID());
770 // rule-based formatters don't do attributes and symbols, except for one
771 if (CFEqual(kCFNumberFormatterFormattingContextKey
, key
)) {
772 __CFGenericValidateType(value
, CFNumberGetTypeID());
773 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
774 __cficu_unum_setContext(formatter
->_nf
, n
, &status
);
776 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return;
777 if (kCFNumberFormatterOrdinalStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return;
778 if (kCFNumberFormatterDurationStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return;
779 if (kCFNumberFormatterCurrencyCodeKey
== key
) {
780 __CFGenericValidateType(value
, CFStringGetTypeID());
781 cnt
= CFStringGetLength((CFStringRef
)value
);
782 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
783 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
784 __cficu_unum_setTextAttribute(formatter
->_nf
, UNUM_CURRENCY_CODE
, ubuffer
, cnt
, &status
);
785 } else if (kCFNumberFormatterDecimalSeparatorKey
== 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 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_DECIMAL_SEPARATOR_SYMBOL
, ubuffer
, cnt
, &status
);
791 } else if (kCFNumberFormatterCurrencyDecimalSeparatorKey
== key
) {
792 __CFGenericValidateType(value
, CFStringGetTypeID());
793 cnt
= CFStringGetLength((CFStringRef
)value
);
794 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
795 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
796 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_MONETARY_SEPARATOR_SYMBOL
, ubuffer
, cnt
, &status
);
797 } else if (kCFNumberFormatterAlwaysShowDecimalSeparatorKey
== key
) {
798 __CFGenericValidateType(value
, CFBooleanGetTypeID());
799 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_DECIMAL_ALWAYS_SHOWN
, (kCFBooleanTrue
== value
));
800 } else if (kCFNumberFormatterGroupingSeparatorKey
== key
) {
801 __CFGenericValidateType(value
, CFStringGetTypeID());
802 cnt
= CFStringGetLength((CFStringRef
)value
);
803 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
804 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
805 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_GROUPING_SEPARATOR_SYMBOL
, (const UChar
*)ubuffer
, cnt
, &status
);
806 } else if (kCFNumberFormatterUseGroupingSeparatorKey
== key
) {
807 __CFGenericValidateType(value
, CFBooleanGetTypeID());
808 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_GROUPING_USED
, (kCFBooleanTrue
== value
));
809 } else if (kCFNumberFormatterPercentSymbolKey
== key
) {
810 __CFGenericValidateType(value
, CFStringGetTypeID());
811 cnt
= CFStringGetLength((CFStringRef
)value
);
812 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
813 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
814 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_PERCENT_SYMBOL
, ubuffer
, cnt
, &status
);
815 } else if (kCFNumberFormatterZeroSymbolKey
== key
) {
816 __CFGenericValidateType(value
, CFStringGetTypeID());
817 CFStringRef old
= formatter
->_zeroSym
;
818 formatter
->_zeroSym
= value
? (CFStringRef
)CFRetain(value
) : NULL
;
819 if (old
) CFRelease(old
);
820 } else if (kCFNumberFormatterNaNSymbolKey
== key
) {
821 __CFGenericValidateType(value
, CFStringGetTypeID());
822 cnt
= CFStringGetLength((CFStringRef
)value
);
823 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
824 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
825 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_NAN_SYMBOL
, ubuffer
, cnt
, &status
);
826 } else if (kCFNumberFormatterInfinitySymbolKey
== key
) {
827 __CFGenericValidateType(value
, CFStringGetTypeID());
828 cnt
= CFStringGetLength((CFStringRef
)value
);
829 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
830 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
831 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_INFINITY_SYMBOL
, ubuffer
, cnt
, &status
);
832 } else if (kCFNumberFormatterMinusSignKey
== key
) {
833 __CFGenericValidateType(value
, CFStringGetTypeID());
834 cnt
= CFStringGetLength((CFStringRef
)value
);
835 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
836 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
837 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_MINUS_SIGN_SYMBOL
, ubuffer
, cnt
, &status
);
838 } else if (kCFNumberFormatterPlusSignKey
== key
) {
839 __CFGenericValidateType(value
, CFStringGetTypeID());
840 cnt
= CFStringGetLength((CFStringRef
)value
);
841 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
842 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
843 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_PLUS_SIGN_SYMBOL
, ubuffer
, cnt
, &status
);
844 } else if (kCFNumberFormatterCurrencySymbolKey
== key
) {
845 __CFGenericValidateType(value
, CFStringGetTypeID());
846 cnt
= CFStringGetLength((CFStringRef
)value
);
847 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
848 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
849 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_CURRENCY_SYMBOL
, (const UChar
*)ubuffer
, cnt
, &status
);
850 } else if (kCFNumberFormatterExponentSymbolKey
== key
) {
851 __CFGenericValidateType(value
, CFStringGetTypeID());
852 cnt
= CFStringGetLength((CFStringRef
)value
);
853 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
854 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
855 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_EXPONENTIAL_SYMBOL
, ubuffer
, cnt
, &status
);
856 } else if (kCFNumberFormatterMinIntegerDigitsKey
== key
) {
857 __CFGenericValidateType(value
, CFNumberGetTypeID());
858 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
859 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_MIN_INTEGER_DIGITS
, n
);
860 } else if (kCFNumberFormatterMaxIntegerDigitsKey
== key
) {
861 __CFGenericValidateType(value
, CFNumberGetTypeID());
862 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
863 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_MAX_INTEGER_DIGITS
, n
);
864 } else if (kCFNumberFormatterMinFractionDigitsKey
== key
) {
865 __CFGenericValidateType(value
, CFNumberGetTypeID());
866 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
867 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_MIN_FRACTION_DIGITS
, n
);
868 } else if (kCFNumberFormatterMaxFractionDigitsKey
== key
) {
869 __CFGenericValidateType(value
, CFNumberGetTypeID());
870 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
871 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_MAX_FRACTION_DIGITS
, n
);
872 } else if (kCFNumberFormatterGroupingSizeKey
== key
) {
873 __CFGenericValidateType(value
, CFNumberGetTypeID());
874 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
875 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_GROUPING_SIZE
, n
);
876 } else if (kCFNumberFormatterSecondaryGroupingSizeKey
== key
) {
877 __CFGenericValidateType(value
, CFNumberGetTypeID());
878 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
879 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_SECONDARY_GROUPING_SIZE
, n
);
880 } else if (kCFNumberFormatterRoundingModeKey
== key
) {
881 __CFGenericValidateType(value
, CFNumberGetTypeID());
882 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
883 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_ROUNDING_MODE
, n
);
884 } else if (kCFNumberFormatterRoundingIncrementKey
== key
) {
885 __CFGenericValidateType(value
, CFNumberGetTypeID());
886 CFNumberGetValue((CFNumberRef
)value
, kCFNumberDoubleType
, &d
);
887 __cficu_unum_setDoubleAttribute(formatter
->_nf
, UNUM_ROUNDING_INCREMENT
, d
);
888 } else if (kCFNumberFormatterFormatWidthKey
== key
) {
889 __CFGenericValidateType(value
, CFNumberGetTypeID());
890 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
891 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_FORMAT_WIDTH
, n
);
892 } else if (kCFNumberFormatterPaddingPositionKey
== key
) {
893 __CFGenericValidateType(value
, CFNumberGetTypeID());
894 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
895 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_PADDING_POSITION
, n
);
896 } else if (kCFNumberFormatterPaddingCharacterKey
== key
) {
897 __CFGenericValidateType(value
, CFStringGetTypeID());
898 cnt
= CFStringGetLength((CFStringRef
)value
);
899 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
900 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
901 __cficu_unum_setTextAttribute(formatter
->_nf
, UNUM_PADDING_CHARACTER
, ubuffer
, cnt
, &status
);
902 } else if (kCFNumberFormatterDefaultFormatKey
== key
) {
903 // read-only attribute
904 } else if (kCFNumberFormatterMultiplierKey
== key
) {
905 __CFGenericValidateType(value
, CFNumberGetTypeID());
906 CFNumberRef old
= formatter
->_multiplier
;
907 formatter
->_multiplier
= value
? (CFNumberRef
)CFRetain(value
) : NULL
;
908 formatter
->_userSetMultiplier
= value
? true : false;
909 if (old
) CFRelease(old
);
910 } else if (kCFNumberFormatterPositivePrefixKey
== key
) {
911 __CFGenericValidateType(value
, CFStringGetTypeID());
912 cnt
= CFStringGetLength((CFStringRef
)value
);
913 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
914 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
915 __cficu_unum_setTextAttribute(formatter
->_nf
, UNUM_POSITIVE_PREFIX
, ubuffer
, cnt
, &status
);
916 } else if (kCFNumberFormatterPositiveSuffixKey
== key
) {
917 __CFGenericValidateType(value
, CFStringGetTypeID());
918 cnt
= CFStringGetLength((CFStringRef
)value
);
919 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
920 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
921 __cficu_unum_setTextAttribute(formatter
->_nf
, UNUM_POSITIVE_SUFFIX
, (const UChar
*)ubuffer
, cnt
, &status
);
922 } else if (kCFNumberFormatterNegativePrefixKey
== key
) {
923 __CFGenericValidateType(value
, CFStringGetTypeID());
924 cnt
= CFStringGetLength((CFStringRef
)value
);
925 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
926 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
927 __cficu_unum_setTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, cnt
, &status
);
928 } else if (kCFNumberFormatterNegativeSuffixKey
== key
) {
929 __CFGenericValidateType(value
, CFStringGetTypeID());
930 cnt
= CFStringGetLength((CFStringRef
)value
);
931 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
932 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
933 __cficu_unum_setTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_SUFFIX
, (const UChar
*)ubuffer
, cnt
, &status
);
934 } else if (kCFNumberFormatterPerMillSymbolKey
== key
) {
935 __CFGenericValidateType(value
, CFStringGetTypeID());
936 cnt
= CFStringGetLength((CFStringRef
)value
);
937 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
938 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
939 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_PERMILL_SYMBOL
, ubuffer
, cnt
, &status
);
940 } else if (kCFNumberFormatterInternationalCurrencySymbolKey
== key
) {
941 __CFGenericValidateType(value
, CFStringGetTypeID());
942 cnt
= CFStringGetLength((CFStringRef
)value
);
943 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
944 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
945 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_INTL_CURRENCY_SYMBOL
, ubuffer
, cnt
, &status
);
946 } else if (kCFNumberFormatterCurrencyGroupingSeparatorKey
== key
) {
947 __CFGenericValidateType(value
, CFStringGetTypeID());
948 cnt
= CFStringGetLength((CFStringRef
)value
);
949 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
950 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
951 __cficu_unum_setSymbol(formatter
->_nf
, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL
, ubuffer
, cnt
, &status
);
952 } else if (kCFNumberFormatterIsLenientKey
== key
) {
953 __CFGenericValidateType(value
, CFBooleanGetTypeID());
954 formatter
->_isLenient
= (kCFBooleanTrue
== value
);
955 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_LENIENT_PARSE
, (kCFBooleanTrue
== value
));
956 } else if (kCFNumberFormatterUseSignificantDigitsKey
== key
) {
957 __CFGenericValidateType(value
, CFBooleanGetTypeID());
958 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_SIGNIFICANT_DIGITS_USED
, (kCFBooleanTrue
== value
));
959 } else if (kCFNumberFormatterMinSignificantDigitsKey
== key
) {
960 __CFGenericValidateType(value
, CFNumberGetTypeID());
961 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
962 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_MIN_SIGNIFICANT_DIGITS
, n
);
963 } else if (kCFNumberFormatterMaxSignificantDigitsKey
== key
) {
964 __CFGenericValidateType(value
, CFNumberGetTypeID());
965 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
966 __cficu_unum_setAttribute(formatter
->_nf
, UNUM_MAX_SIGNIFICANT_DIGITS
, n
);
967 } else if (kCFNumberFormatterUsesCharacterDirectionKey
== key
) {
968 __CFGenericValidateType(value
, CFBooleanGetTypeID());
969 formatter
->_usesCharacterDirection
= value
== kCFBooleanTrue
;
971 CFAssert3(0, __kCFLogAssertion
, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__
, key
, key
);
973 if (_CFExecutableLinkedOnOrAfter(CFSystemVersionSnowLeopard
)) {
974 // do a dummy call to CFNumberFormatterGetFormat() after changing an attribute because
975 // ICU sometimes changes the pattern due to a property change, and we need to poke
976 // __cficu_unum_toPattern() and also update our own variables
977 CFNumberFormatterGetFormat(formatter
);
981 CFTypeRef
CFNumberFormatterCopyProperty(CFNumberFormatterRef formatter
, CFStringRef key
) {
984 UErrorCode status
= U_ZERO_ERROR
;
985 UChar ubuffer
[BUFFER_SIZE
];
987 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
988 __CFGenericValidateType(key
, CFStringGetTypeID());
989 // rule-based formatters don't do attributes and symbols, except for one
990 if (CFEqual(kCFNumberFormatterFormattingContextKey
, key
)) {
991 n
= __cficu_unum_getContext(formatter
->_nf
, UDISPCTX_TYPE_CAPITALIZATION
, &status
);
993 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
996 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return NULL
;
997 if (kCFNumberFormatterOrdinalStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return NULL
;
998 if (kCFNumberFormatterDurationStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return NULL
;
999 if (kCFNumberFormatterCurrencyCodeKey
== key
) {
1000 cnt
= __cficu_unum_getTextAttribute(formatter
->_nf
, UNUM_CURRENCY_CODE
, ubuffer
, BUFFER_SIZE
, &status
);
1001 if (U_SUCCESS(status
) && cnt
== 0) {
1002 CFStringRef localeName
= CFLocaleGetIdentifier(formatter
->_locale
);
1003 char buffer
[BUFFER_SIZE
];
1004 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
1006 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
1011 UErrorCode status
= U_ZERO_ERROR
;
1012 UNumberFormat
*nf
= __cficu_unum_open(UNUM_CURRENCY
, NULL
, 0, cstr
, NULL
, &status
);
1014 cnt
= __cficu_unum_getTextAttribute(nf
, UNUM_CURRENCY_CODE
, ubuffer
, BUFFER_SIZE
, &status
);
1015 __cficu_unum_close(nf
);
1018 if (U_SUCCESS(status
) && 0 < cnt
&& cnt
<= BUFFER_SIZE
) {
1019 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1021 } else if (kCFNumberFormatterDecimalSeparatorKey
== key
) {
1022 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_DECIMAL_SEPARATOR_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1023 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1024 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1026 } else if (kCFNumberFormatterCurrencyDecimalSeparatorKey
== key
) {
1027 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_MONETARY_SEPARATOR_SYMBOL
, (UChar
*)ubuffer
, BUFFER_SIZE
, &status
);
1028 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1029 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1031 } else if (kCFNumberFormatterAlwaysShowDecimalSeparatorKey
== key
) {
1032 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_DECIMAL_ALWAYS_SHOWN
);
1034 return CFRetain(n
? kCFBooleanTrue
: kCFBooleanFalse
);
1036 } else if (kCFNumberFormatterGroupingSeparatorKey
== key
) {
1037 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_GROUPING_SEPARATOR_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 (kCFNumberFormatterUseGroupingSeparatorKey
== key
) {
1042 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_GROUPING_USED
);
1044 return CFRetain(n
? kCFBooleanTrue
: kCFBooleanFalse
);
1046 } else if (kCFNumberFormatterPercentSymbolKey
== key
) {
1047 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_PERCENT_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1048 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1049 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1051 } else if (kCFNumberFormatterZeroSymbolKey
== key
) {
1052 return formatter
->_zeroSym
? CFRetain(formatter
->_zeroSym
) : NULL
;
1053 } else if (kCFNumberFormatterNaNSymbolKey
== key
) {
1054 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_NAN_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 (kCFNumberFormatterInfinitySymbolKey
== key
) {
1059 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_INFINITY_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 (kCFNumberFormatterMinusSignKey
== key
) {
1064 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_MINUS_SIGN_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 (kCFNumberFormatterPlusSignKey
== key
) {
1069 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_PLUS_SIGN_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 (kCFNumberFormatterCurrencySymbolKey
== key
) {
1074 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_CURRENCY_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1075 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1076 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1078 } else if (kCFNumberFormatterExponentSymbolKey
== key
) {
1079 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_EXPONENTIAL_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1080 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1081 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1083 } else if (kCFNumberFormatterMinIntegerDigitsKey
== key
) {
1084 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_MIN_INTEGER_DIGITS
);
1086 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1088 } else if (kCFNumberFormatterMaxIntegerDigitsKey
== key
) {
1089 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_MAX_INTEGER_DIGITS
);
1091 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1093 } else if (kCFNumberFormatterMinFractionDigitsKey
== key
) {
1094 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_MIN_FRACTION_DIGITS
);
1096 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1098 } else if (kCFNumberFormatterMaxFractionDigitsKey
== key
) {
1099 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_MAX_FRACTION_DIGITS
);
1101 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1103 } else if (kCFNumberFormatterGroupingSizeKey
== key
) {
1104 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_GROUPING_SIZE
);
1106 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1108 } else if (kCFNumberFormatterSecondaryGroupingSizeKey
== key
) {
1109 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_SECONDARY_GROUPING_SIZE
);
1111 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1113 } else if (kCFNumberFormatterRoundingModeKey
== key
) {
1114 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_ROUNDING_MODE
);
1116 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1118 } else if (kCFNumberFormatterRoundingIncrementKey
== key
) {
1119 d
= __cficu_unum_getDoubleAttribute(formatter
->_nf
, UNUM_ROUNDING_INCREMENT
);
1121 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberDoubleType
, &d
);
1123 } else if (kCFNumberFormatterFormatWidthKey
== key
) {
1124 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_FORMAT_WIDTH
);
1126 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1128 } else if (kCFNumberFormatterPaddingPositionKey
== key
) {
1129 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_PADDING_POSITION
);
1131 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1133 } else if (kCFNumberFormatterPaddingCharacterKey
== key
) {
1134 cnt
= __cficu_unum_getTextAttribute(formatter
->_nf
, UNUM_PADDING_CHARACTER
, ubuffer
, BUFFER_SIZE
, &status
);
1135 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1136 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1138 } else if (kCFNumberFormatterDefaultFormatKey
== key
) {
1139 return formatter
->_defformat
? CFRetain(formatter
->_defformat
) : NULL
;
1140 } else if (kCFNumberFormatterMultiplierKey
== key
) {
1141 return formatter
->_multiplier
? CFRetain(formatter
->_multiplier
) : NULL
;
1142 } else if (kCFNumberFormatterPositivePrefixKey
== key
) {
1143 cnt
= __cficu_unum_getTextAttribute(formatter
->_nf
, UNUM_POSITIVE_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 (kCFNumberFormatterPositiveSuffixKey
== key
) {
1148 cnt
= __cficu_unum_getTextAttribute(formatter
->_nf
, UNUM_POSITIVE_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 (kCFNumberFormatterNegativePrefixKey
== key
) {
1153 cnt
= __cficu_unum_getTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, BUFFER_SIZE
, &status
);
1154 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1155 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1157 } else if (kCFNumberFormatterNegativeSuffixKey
== key
) {
1158 cnt
= __cficu_unum_getTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_SUFFIX
, ubuffer
, BUFFER_SIZE
, &status
);
1159 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1160 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1162 } else if (kCFNumberFormatterPerMillSymbolKey
== key
) {
1163 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_PERMILL_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 (kCFNumberFormatterInternationalCurrencySymbolKey
== key
) {
1168 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_INTL_CURRENCY_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1169 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1170 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1172 } else if (kCFNumberFormatterCurrencyGroupingSeparatorKey
== key
) {
1173 cnt
= __cficu_unum_getSymbol(formatter
->_nf
, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1174 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1175 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1177 } else if (kCFNumberFormatterIsLenientKey
== key
) {
1178 // __cficu_unum_getAttribute(, UNUM_LENIENT_PARSE) is undefined.
1179 return CFRetain(formatter
->_isLenient
? kCFBooleanTrue
: kCFBooleanFalse
);
1180 } else if (kCFNumberFormatterUseSignificantDigitsKey
== key
) {
1181 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_SIGNIFICANT_DIGITS_USED
);
1183 return CFRetain(n
? kCFBooleanTrue
: kCFBooleanFalse
);
1185 } else if (kCFNumberFormatterMinSignificantDigitsKey
== key
) {
1186 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_MIN_SIGNIFICANT_DIGITS
);
1188 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1190 } else if (kCFNumberFormatterMaxSignificantDigitsKey
== key
) {
1191 n
= __cficu_unum_getAttribute(formatter
->_nf
, UNUM_MAX_SIGNIFICANT_DIGITS
);
1193 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1196 CFAssert3(0, __kCFLogAssertion
, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__
, key
, key
);
1202 Boolean
CFNumberFormatterGetDecimalInfoForCurrencyCode(CFStringRef currencyCode
, int32_t *defaultFractionDigits
, double *roundingIncrement
) {
1204 __CFGenericValidateType(currencyCode
, CFStringGetTypeID());
1205 CFAssert1(3 == CFStringGetLength(currencyCode
), __kCFLogAssertion
, "%s(): currencyCode is not 3 characters", __PRETTY_FUNCTION__
);
1206 CFStringGetCharacters(currencyCode
, CFRangeMake(0, 3), (UniChar
*)ubuffer
);
1208 UErrorCode icuStatus
= U_ZERO_ERROR
;
1209 if (defaultFractionDigits
) *defaultFractionDigits
= __cficu_ucurr_getDefaultFractionDigits(ubuffer
, &icuStatus
);
1210 if (roundingIncrement
) *roundingIncrement
= __cficu_ucurr_getRoundingIncrement(ubuffer
, &icuStatus
);
1211 if (U_FAILURE(icuStatus
))
1213 return (!defaultFractionDigits
|| 0 <= *defaultFractionDigits
) && (!roundingIncrement
|| 0.0 <= *roundingIncrement
);
1216 // This is for NSNumberFormatter use only!
1217 void *_CFNumberFormatterGetFormatter(CFNumberFormatterRef formatter
) {
1218 return (void *)formatter
->_nf
;