2 * Copyright (c) 2008 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@
23 /* CFNumberFormatter.c
24 Copyright 2002-2003, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
28 #include <CoreFoundation/CFNumberFormatter.h>
29 #include "CFInternal.h"
30 #include <unicode/unum.h>
31 #include <unicode/ucurr.h>
35 static void __CFNumberFormatterCustomize(CFNumberFormatterRef formatter
);
37 #define BUFFER_SIZE 768
39 struct __CFNumberFormatter
{
43 CFNumberFormatterStyle _style
;
44 CFStringRef _format
; // NULL for RBNFs
45 CFStringRef _defformat
;
46 CFNumberRef _multiplier
;
50 static CFStringRef
__CFNumberFormatterCopyDescription(CFTypeRef cf
) {
51 CFNumberFormatterRef formatter
= (CFNumberFormatterRef
)cf
;
52 return CFStringCreateWithFormat(CFGetAllocator(formatter
), NULL
, CFSTR("<CFNumberFormatter %p [%p]>"), cf
, CFGetAllocator(formatter
));
55 static void __CFNumberFormatterDeallocate(CFTypeRef cf
) {
56 CFNumberFormatterRef formatter
= (CFNumberFormatterRef
)cf
;
57 if (formatter
->_nf
) unum_close(formatter
->_nf
);
58 if (formatter
->_locale
) CFRelease(formatter
->_locale
);
59 if (formatter
->_format
) CFRelease(formatter
->_format
);
60 if (formatter
->_defformat
) CFRelease(formatter
->_defformat
);
61 if (formatter
->_multiplier
) CFRelease(formatter
->_multiplier
);
62 if (formatter
->_zeroSym
) CFRelease(formatter
->_zeroSym
);
65 static CFTypeID __kCFNumberFormatterTypeID
= _kCFRuntimeNotATypeID
;
67 static const CFRuntimeClass __CFNumberFormatterClass
= {
72 __CFNumberFormatterDeallocate
,
76 __CFNumberFormatterCopyDescription
79 static void __CFNumberFormatterInitialize(void) {
80 __kCFNumberFormatterTypeID
= _CFRuntimeRegisterClass(&__CFNumberFormatterClass
);
83 CFTypeID
CFNumberFormatterGetTypeID(void) {
84 if (_kCFRuntimeNotATypeID
== __kCFNumberFormatterTypeID
) __CFNumberFormatterInitialize();
85 return __kCFNumberFormatterTypeID
;
88 CFNumberFormatterRef
CFNumberFormatterCreate(CFAllocatorRef allocator
, CFLocaleRef locale
, CFNumberFormatterStyle style
) {
89 struct __CFNumberFormatter
*memory
;
90 uint32_t size
= sizeof(struct __CFNumberFormatter
) - sizeof(CFRuntimeBase
);
91 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
92 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
93 __CFGenericValidateType(locale
, CFLocaleGetTypeID());
94 memory
= (struct __CFNumberFormatter
*)_CFRuntimeCreateInstance(allocator
, CFNumberFormatterGetTypeID(), size
, NULL
);
99 memory
->_locale
= NULL
;
100 memory
->_format
= NULL
;
101 memory
->_defformat
= NULL
;
102 memory
->_multiplier
= NULL
;
103 memory
->_zeroSym
= NULL
;
104 if (NULL
== locale
) locale
= CFLocaleGetSystem();
105 memory
->_style
= style
;
108 case kCFNumberFormatterNoStyle
: ustyle
= UNUM_IGNORE
; break;
109 case kCFNumberFormatterDecimalStyle
: ustyle
= UNUM_DECIMAL
; break;
110 case kCFNumberFormatterCurrencyStyle
: ustyle
= UNUM_CURRENCY
; break;
111 case kCFNumberFormatterPercentStyle
: ustyle
= UNUM_PERCENT
; break;
112 case kCFNumberFormatterScientificStyle
: ustyle
= UNUM_SCIENTIFIC
; break;
113 case kCFNumberFormatterSpellOutStyle
: ustyle
= UNUM_SPELLOUT
; break;
115 CFAssert2(0, __kCFLogAssertion
, "%s(): unknown style %d", __PRETTY_FUNCTION__
, style
);
116 ustyle
= UNUM_DECIMAL
;
117 memory
->_style
= kCFNumberFormatterDecimalStyle
;
120 CFStringRef localeName
= locale
? CFLocaleGetIdentifier(locale
) : CFSTR("");
121 char buffer
[BUFFER_SIZE
];
122 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
124 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
130 UErrorCode status
= U_ZERO_ERROR
;
131 memory
->_nf
= unum_open((UNumberFormatStyle
)ustyle
, NULL
, 0, cstr
, NULL
, &status
);
132 CFAssert2(memory
->_nf
, __kCFLogAssertion
, "%s(): error (%d) creating number formatter", __PRETTY_FUNCTION__
, status
);
133 if (NULL
== memory
->_nf
) {
138 if (kCFNumberFormatterNoStyle
== style
) {
139 status
= U_ZERO_ERROR
;
140 ubuff
[0] = '#'; ubuff
[1] = ';'; ubuff
[2] = '#';
141 unum_applyPattern(memory
->_nf
, false, ubuff
, 3, NULL
, &status
);
142 unum_setAttribute(memory
->_nf
, UNUM_MAX_INTEGER_DIGITS
, 42);
143 unum_setAttribute(memory
->_nf
, UNUM_MAX_FRACTION_DIGITS
, 0);
145 memory
->_locale
= locale
? CFLocaleCreateCopy(allocator
, locale
) : CFLocaleGetSystem();
146 __CFNumberFormatterCustomize(memory
);
147 if (kCFNumberFormatterSpellOutStyle
!= memory
->_style
) {
148 UChar ubuffer
[BUFFER_SIZE
];
149 status
= U_ZERO_ERROR
;
150 int32_t ret
= unum_toPattern(memory
->_nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
151 if (U_SUCCESS(status
) && ret
<= BUFFER_SIZE
) {
152 memory
->_format
= CFStringCreateWithCharacters(allocator
, (const UniChar
*)ubuffer
, ret
);
155 memory
->_defformat
= memory
->_format
? (CFStringRef
)CFRetain(memory
->_format
) : NULL
;
156 if (kCFNumberFormatterSpellOutStyle
!= memory
->_style
) {
157 int32_t n
= unum_getAttribute(memory
->_nf
, UNUM_MULTIPLIER
);
159 memory
->_multiplier
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, &n
);
160 unum_setAttribute(memory
->_nf
, UNUM_MULTIPLIER
, 1);
163 return (CFNumberFormatterRef
)memory
;
166 extern CFDictionaryRef
__CFLocaleGetPrefs(CFLocaleRef locale
);
168 static void __substituteFormatStringFromPrefsNF(CFNumberFormatterRef formatter
) {
169 CFIndex formatStyle
= formatter
->_style
;
170 if (kCFNumberFormatterSpellOutStyle
== formatStyle
) return;
171 CFStringRef prefName
= CFSTR("AppleICUNumberFormatStrings");
172 if (kCFNumberFormatterNoStyle
!= formatStyle
) {
173 CFStringRef pref
= NULL
;
174 CFDictionaryRef prefs
= __CFLocaleGetPrefs(formatter
->_locale
);
175 CFPropertyListRef metapref
= prefs
? CFDictionaryGetValue(prefs
, prefName
) : NULL
;
176 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
178 switch (formatStyle
) {
179 case kCFNumberFormatterDecimalStyle
: key
= CFSTR("1"); break;
180 case kCFNumberFormatterCurrencyStyle
: key
= CFSTR("2"); break;
181 case kCFNumberFormatterPercentStyle
: key
= CFSTR("3"); break;
182 case kCFNumberFormatterScientificStyle
: key
= CFSTR("4"); break;
183 case kCFNumberFormatterSpellOutStyle
: key
= CFSTR("5"); break;
184 default: key
= CFSTR("0"); break;
186 pref
= (CFStringRef
)CFDictionaryGetValue((CFDictionaryRef
)metapref
, key
);
188 if (NULL
!= pref
&& CFGetTypeID(pref
) == CFStringGetTypeID()) {
189 int32_t icustyle
= UNUM_IGNORE
;
190 switch (formatStyle
) {
191 case kCFNumberFormatterDecimalStyle
: icustyle
= UNUM_DECIMAL
; break;
192 case kCFNumberFormatterCurrencyStyle
: icustyle
= UNUM_CURRENCY
; break;
193 case kCFNumberFormatterPercentStyle
: icustyle
= UNUM_PERCENT
; break;
194 case kCFNumberFormatterScientificStyle
: icustyle
= UNUM_SCIENTIFIC
; break;
195 case kCFNumberFormatterSpellOutStyle
: icustyle
= UNUM_SPELLOUT
; break;
197 CFStringRef localeName
= CFLocaleGetIdentifier(formatter
->_locale
);
198 char buffer
[BUFFER_SIZE
];
199 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
201 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
203 UErrorCode status
= U_ZERO_ERROR
;
204 UNumberFormat
*nf
= unum_open((UNumberFormatStyle
)icustyle
, NULL
, 0, cstr
, NULL
, &status
);
206 UChar ubuffer
[BUFFER_SIZE
];
207 status
= U_ZERO_ERROR
;
208 int32_t number_len
= unum_toPattern(nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
209 if (U_SUCCESS(status
) && number_len
<= BUFFER_SIZE
) {
210 CFStringRef numberString
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)ubuffer
, number_len
);
211 status
= U_ZERO_ERROR
;
212 int32_t formatter_len
= unum_toPattern(formatter
->_nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
213 if (U_SUCCESS(status
) && formatter_len
<= BUFFER_SIZE
) {
214 CFMutableStringRef formatString
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
215 CFStringAppendCharacters(formatString
, (const UniChar
*)ubuffer
, formatter_len
);
216 // find numberString inside formatString, substitute the pref in that range
218 if (CFStringFindWithOptions(formatString
, numberString
, CFRangeMake(0, formatter_len
), 0, &result
)) {
219 CFStringReplace(formatString
, result
, pref
);
220 int32_t new_len
= CFStringGetLength(formatString
);
221 STACK_BUFFER_DECL(UChar
, new_buffer
, new_len
);
222 const UChar
*new_ustr
= (const UChar
*)CFStringGetCharactersPtr(formatString
);
223 if (NULL
== new_ustr
) {
224 CFStringGetCharacters(formatString
, CFRangeMake(0, new_len
), (UniChar
*)new_buffer
);
225 new_ustr
= new_buffer
;
227 status
= U_ZERO_ERROR
;
228 unum_applyPattern(formatter
->_nf
, false, new_ustr
, new_len
, NULL
, &status
);
230 CFRelease(formatString
);
232 CFRelease(numberString
);
240 static void __CFNumberFormatterApplySymbolPrefs(const void *key
, const void *value
, void *context
) {
241 if (CFGetTypeID(key
) == CFStringGetTypeID() && CFGetTypeID(value
) == CFStringGetTypeID()) {
242 CFNumberFormatterRef formatter
= (CFNumberFormatterRef
)context
;
243 UNumberFormatSymbol sym
= (UNumberFormatSymbol
)CFStringGetIntValue((CFStringRef
)key
);
244 CFStringRef item
= (CFStringRef
)value
;
245 CFIndex item_cnt
= CFStringGetLength(item
);
246 STACK_BUFFER_DECL(UChar
, item_buffer
, item_cnt
);
247 UChar
*item_ustr
= (UChar
*)CFStringGetCharactersPtr(item
);
248 if (NULL
== item_ustr
) {
249 CFStringGetCharacters(item
, CFRangeMake(0, __CFMin(BUFFER_SIZE
, item_cnt
)), (UniChar
*)item_buffer
);
250 item_ustr
= item_buffer
;
252 UErrorCode status
= U_ZERO_ERROR
;
253 unum_setSymbol(formatter
->_nf
, sym
, item_ustr
, item_cnt
, &status
);
257 static void __CFNumberFormatterCustomize(CFNumberFormatterRef formatter
) {
258 __substituteFormatStringFromPrefsNF(formatter
);
259 CFDictionaryRef prefs
= __CFLocaleGetPrefs(formatter
->_locale
);
260 CFPropertyListRef metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleICUNumberSymbols")) : NULL
;
261 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
262 CFDictionaryApplyFunction((CFDictionaryRef
)metapref
, __CFNumberFormatterApplySymbolPrefs
, formatter
);
266 CFLocaleRef
CFNumberFormatterGetLocale(CFNumberFormatterRef formatter
) {
267 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
268 return formatter
->_locale
;
271 CFNumberFormatterStyle
CFNumberFormatterGetStyle(CFNumberFormatterRef formatter
) {
272 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
273 return formatter
->_style
;
276 CFStringRef
CFNumberFormatterGetFormat(CFNumberFormatterRef formatter
) {
277 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
278 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
) return NULL
;
279 UChar ubuffer
[BUFFER_SIZE
];
280 CFStringRef newString
= NULL
;
281 UErrorCode status
= U_ZERO_ERROR
;
282 int32_t ret
= unum_toPattern(formatter
->_nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
283 if (U_SUCCESS(status
) && ret
<= BUFFER_SIZE
) {
284 newString
= CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, ret
);
286 if (newString
&& !formatter
->_format
) {
287 formatter
->_format
= newString
;
288 } else if (newString
&& !CFEqual(newString
, formatter
->_format
)) {
289 CFRelease(formatter
->_format
);
290 formatter
->_format
= newString
;
291 } else if (newString
) {
292 CFRelease(newString
);
294 return formatter
->_format
;
297 void CFNumberFormatterSetFormat(CFNumberFormatterRef formatter
, CFStringRef formatString
) {
298 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
299 __CFGenericValidateType(formatString
, CFStringGetTypeID());
300 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
) return;
301 CFIndex cnt
= CFStringGetLength(formatString
);
302 CFAssert1(cnt
<= 1024, __kCFLogAssertion
, "%s(): format string too long", __PRETTY_FUNCTION__
);
303 if ((!formatter
->_format
|| !CFEqual(formatter
->_format
, formatString
)) && cnt
<= 1024) {
304 STACK_BUFFER_DECL(UChar
, ubuffer
, cnt
);
305 const UChar
*ustr
= (const UChar
*)CFStringGetCharactersPtr(formatString
);
307 CFStringGetCharacters(formatString
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
310 UErrorCode status
= U_ZERO_ERROR
;
311 unum_applyPattern(formatter
->_nf
, false, ustr
, cnt
, NULL
, &status
);
312 if (U_SUCCESS(status
)) {
313 if (formatter
->_format
) CFRelease(formatter
->_format
);
314 UChar ubuffer2
[BUFFER_SIZE
];
315 status
= U_ZERO_ERROR
;
316 int32_t ret
= unum_toPattern(formatter
->_nf
, false, ubuffer2
, BUFFER_SIZE
, &status
);
317 if (U_SUCCESS(status
) && ret
<= BUFFER_SIZE
) {
318 formatter
->_format
= CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer2
, ret
);
324 CFStringRef
CFNumberFormatterCreateStringWithNumber(CFAllocatorRef allocator
, CFNumberFormatterRef formatter
, CFNumberRef number
) {
325 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
326 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
327 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
328 __CFGenericValidateType(number
, CFNumberGetTypeID());
329 CFNumberType type
= CFNumberGetType(number
);
331 CFNumberGetValue(number
, type
, buffer
);
332 return CFNumberFormatterCreateStringWithValue(allocator
, formatter
, type
, buffer
);
335 #define FORMAT(T, FUNC) \
336 T value = *(T *)valuePtr; \
337 if (0 == value && formatter->_zeroSym) { return (CFStringRef)CFRetain(formatter->_zeroSym); } \
338 if (1.0 != multiplier) value = (T)(value * multiplier); \
339 status = U_ZERO_ERROR; \
340 used = FUNC(formatter->_nf, value, ubuffer, cnt, NULL, &status); \
341 if (status == U_BUFFER_OVERFLOW_ERROR || cnt < used) { \
343 ustr = (UChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UChar) * cnt, 0); \
344 status = U_ZERO_ERROR; \
345 used = FUNC(formatter->_nf, value, ustr, cnt, NULL, &status); \
348 CFStringRef
CFNumberFormatterCreateStringWithValue(CFAllocatorRef allocator
, CFNumberFormatterRef formatter
, CFNumberType numberType
, const void *valuePtr
) {
349 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
350 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
351 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
352 double multiplier
= 1.0;
353 if (formatter
->_multiplier
) {
354 if (!CFNumberGetValue(formatter
->_multiplier
, kCFNumberFloat64Type
, &multiplier
)) {
358 UChar
*ustr
= NULL
, ubuffer
[BUFFER_SIZE
];
359 UErrorCode status
= U_ZERO_ERROR
;
360 CFIndex used
, cnt
= BUFFER_SIZE
;
361 if (numberType
== kCFNumberFloat64Type
|| numberType
== kCFNumberDoubleType
) {
362 FORMAT(double, unum_formatDouble
)
363 } else if (numberType
== kCFNumberFloat32Type
|| numberType
== kCFNumberFloatType
) {
364 FORMAT(float, unum_formatDouble
)
365 } else if (numberType
== kCFNumberSInt64Type
|| numberType
== kCFNumberLongLongType
) {
366 FORMAT(int64_t, unum_formatInt64
)
367 } else if (numberType
== kCFNumberLongType
|| numberType
== kCFNumberCFIndexType
) {
369 FORMAT(int64_t, unum_formatInt64
)
371 FORMAT(int32_t, unum_formatInt64
)
373 } else if (numberType
== kCFNumberSInt32Type
|| numberType
== kCFNumberIntType
) {
374 FORMAT(int32_t, unum_formatInt64
)
375 } else if (numberType
== kCFNumberSInt16Type
|| numberType
== kCFNumberShortType
) {
376 FORMAT(int16_t, unum_formatInt64
)
377 } else if (numberType
== kCFNumberSInt8Type
|| numberType
== kCFNumberCharType
) {
378 FORMAT(int8_t, unum_formatInt64
)
380 CFAssert2(0, __kCFLogAssertion
, "%s(): unknown CFNumberType (%d)", __PRETTY_FUNCTION__
, numberType
);
383 CFStringRef string
= NULL
;
384 if (U_SUCCESS(status
)) {
385 string
= CFStringCreateWithCharacters(allocator
, ustr
? (const UniChar
*)ustr
: (const UniChar
*)ubuffer
, used
);
387 if (ustr
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, ustr
);
393 CFNumberRef
CFNumberFormatterCreateNumberFromString(CFAllocatorRef allocator
, CFNumberFormatterRef formatter
, CFStringRef string
, CFRange
*rangep
, CFOptionFlags options
) {
394 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
395 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
396 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
397 __CFGenericValidateType(string
, CFStringGetTypeID());
398 CFNumberType type
= (options
& kCFNumberFormatterParseIntegersOnly
) ? kCFNumberSInt64Type
: kCFNumberFloat64Type
;
400 if (CFNumberFormatterGetValueFromString(formatter
, string
, rangep
, type
, buffer
)) {
401 return CFNumberCreate(allocator
, type
, buffer
);
406 Boolean
CFNumberFormatterGetValueFromString(CFNumberFormatterRef formatter
, CFStringRef string
, CFRange
*rangep
, CFNumberType numberType
, void *valuePtr
) {
407 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
408 __CFGenericValidateType(string
, CFStringGetTypeID());
409 Boolean isZero
= false;
410 CFRange range
= {0, 0};
414 range
.length
= CFStringGetLength(string
);
416 if (formatter
->_zeroSym
&& kCFCompareEqualTo
== CFStringCompareWithOptions(string
, formatter
->_zeroSym
, range
, 0)) {
419 if (1024 < range
.length
) range
.length
= 1024;
420 const UChar
*ustr
= (const UChar
*)CFStringGetCharactersPtr(string
);
421 STACK_BUFFER_DECL(UChar
, ubuffer
, (NULL
== ustr
) ? range
.length
: 1);
423 CFStringGetCharacters(string
, range
, (UniChar
*)ubuffer
);
426 ustr
+= range
.location
;
428 Boolean integerOnly
= 1;
429 switch (numberType
) {
430 case kCFNumberSInt8Type
: case kCFNumberCharType
:
431 case kCFNumberSInt16Type
: case kCFNumberShortType
:
432 case kCFNumberSInt32Type
: case kCFNumberIntType
:
433 case kCFNumberLongType
: case kCFNumberCFIndexType
:
434 case kCFNumberSInt64Type
: case kCFNumberLongLongType
:
435 unum_setAttribute(formatter
->_nf
, UNUM_PARSE_INT_ONLY
, 1);
438 unum_setAttribute(formatter
->_nf
, UNUM_PARSE_INT_ONLY
, 0);
443 UErrorCode status
= U_ZERO_ERROR
;
447 dpos
= rangep
? rangep
->length
: 0;
450 dreti
= unum_parseInt64(formatter
->_nf
, ustr
, range
.length
, &dpos
, &status
);
452 dretd
= unum_parseDouble(formatter
->_nf
, ustr
, range
.length
, &dpos
, &status
);
455 if (rangep
) rangep
->length
= dpos
;
456 if (U_FAILURE(status
)) {
459 if (formatter
->_multiplier
) {
460 double multiplier
= 1.0;
461 if (!CFNumberGetValue(formatter
->_multiplier
, kCFNumberFloat64Type
, &multiplier
)) {
464 dreti
= (int64_t)((double)dreti
/ multiplier
); // integer truncation
465 dretd
= dretd
/ multiplier
;
467 switch (numberType
) {
468 case kCFNumberSInt8Type
: case kCFNumberCharType
:
469 if (INT8_MIN
<= dreti
&& dreti
<= INT8_MAX
) {
470 *(int8_t *)valuePtr
= (int8_t)dreti
;
474 case kCFNumberSInt16Type
: case kCFNumberShortType
:
475 if (INT16_MIN
<= dreti
&& dreti
<= INT16_MAX
) {
476 *(int16_t *)valuePtr
= (int16_t)dreti
;
480 case kCFNumberSInt32Type
: case kCFNumberIntType
:
482 case kCFNumberLongType
: case kCFNumberCFIndexType
:
484 if (INT32_MIN
<= dreti
&& dreti
<= INT32_MAX
) {
485 *(int32_t *)valuePtr
= (int32_t)dreti
;
489 case kCFNumberSInt64Type
: case kCFNumberLongLongType
:
491 case kCFNumberLongType
: case kCFNumberCFIndexType
:
493 if (INT64_MIN
<= dreti
&& dreti
<= INT64_MAX
) {
494 *(int64_t *)valuePtr
= (int64_t)dreti
;
498 case kCFNumberFloat32Type
: case kCFNumberFloatType
:
499 if (-FLT_MAX
<= dretd
&& dretd
<= FLT_MAX
) {
500 *(float *)valuePtr
= (float)dretd
;
504 case kCFNumberFloat64Type
: case kCFNumberDoubleType
:
505 if (-DBL_MAX
<= dretd
&& dretd
<= DBL_MAX
) {
506 *(double *)valuePtr
= (double)dretd
;
514 void CFNumberFormatterSetProperty(CFNumberFormatterRef formatter
, CFStringRef key
, CFTypeRef value
) {
517 UErrorCode status
= U_ZERO_ERROR
;
518 UChar ubuffer
[BUFFER_SIZE
];
520 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
521 __CFGenericValidateType(key
, CFStringGetTypeID());
522 if (kCFNumberFormatterCurrencyCode
== key
) {
523 __CFGenericValidateType(value
, CFStringGetTypeID());
524 cnt
= CFStringGetLength((CFStringRef
)value
);
525 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
526 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
527 unum_setTextAttribute(formatter
->_nf
, UNUM_CURRENCY_CODE
, ubuffer
, cnt
, &status
);
528 } else if (kCFNumberFormatterDecimalSeparator
== key
) {
529 __CFGenericValidateType(value
, CFStringGetTypeID());
530 cnt
= CFStringGetLength((CFStringRef
)value
);
531 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
532 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
533 unum_setSymbol(formatter
->_nf
, UNUM_DECIMAL_SEPARATOR_SYMBOL
, ubuffer
, cnt
, &status
);
534 } else if (kCFNumberFormatterCurrencyDecimalSeparator
== key
) {
535 __CFGenericValidateType(value
, CFStringGetTypeID());
536 cnt
= CFStringGetLength((CFStringRef
)value
);
537 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
538 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
539 unum_setSymbol(formatter
->_nf
, UNUM_MONETARY_SEPARATOR_SYMBOL
, ubuffer
, cnt
, &status
);
540 } else if (kCFNumberFormatterAlwaysShowDecimalSeparator
== key
) {
541 __CFGenericValidateType(value
, CFBooleanGetTypeID());
542 unum_setAttribute(formatter
->_nf
, UNUM_DECIMAL_ALWAYS_SHOWN
, (kCFBooleanTrue
== value
));
543 } else if (kCFNumberFormatterGroupingSeparator
== key
) {
544 __CFGenericValidateType(value
, CFStringGetTypeID());
545 cnt
= CFStringGetLength((CFStringRef
)value
);
546 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
547 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
548 unum_setSymbol(formatter
->_nf
, UNUM_GROUPING_SEPARATOR_SYMBOL
, (const UChar
*)ubuffer
, cnt
, &status
);
549 } else if (kCFNumberFormatterUseGroupingSeparator
== key
) {
550 __CFGenericValidateType(value
, CFBooleanGetTypeID());
551 unum_setAttribute(formatter
->_nf
, UNUM_GROUPING_USED
, (kCFBooleanTrue
== value
));
552 } else if (kCFNumberFormatterPercentSymbol
== key
) {
553 __CFGenericValidateType(value
, CFStringGetTypeID());
554 cnt
= CFStringGetLength((CFStringRef
)value
);
555 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
556 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
557 unum_setSymbol(formatter
->_nf
, UNUM_PERCENT_SYMBOL
, ubuffer
, cnt
, &status
);
558 } else if (kCFNumberFormatterZeroSymbol
== key
) {
559 __CFGenericValidateType(value
, CFStringGetTypeID());
560 CFStringRef old
= formatter
->_zeroSym
;
561 formatter
->_zeroSym
= value
? (CFStringRef
)CFRetain(value
) : NULL
;
562 if (old
) CFRelease(old
);
563 } else if (kCFNumberFormatterNaNSymbol
== key
) {
564 __CFGenericValidateType(value
, CFStringGetTypeID());
565 cnt
= CFStringGetLength((CFStringRef
)value
);
566 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
567 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
568 unum_setSymbol(formatter
->_nf
, UNUM_NAN_SYMBOL
, ubuffer
, cnt
, &status
);
569 } else if (kCFNumberFormatterInfinitySymbol
== key
) {
570 __CFGenericValidateType(value
, CFStringGetTypeID());
571 cnt
= CFStringGetLength((CFStringRef
)value
);
572 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
573 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
574 unum_setSymbol(formatter
->_nf
, UNUM_INFINITY_SYMBOL
, ubuffer
, cnt
, &status
);
575 } else if (kCFNumberFormatterMinusSign
== key
) {
576 __CFGenericValidateType(value
, CFStringGetTypeID());
577 cnt
= CFStringGetLength((CFStringRef
)value
);
578 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
579 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
580 unum_setSymbol(formatter
->_nf
, UNUM_MINUS_SIGN_SYMBOL
, ubuffer
, cnt
, &status
);
581 } else if (kCFNumberFormatterPlusSign
== key
) {
582 __CFGenericValidateType(value
, CFStringGetTypeID());
583 cnt
= CFStringGetLength((CFStringRef
)value
);
584 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
585 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
586 unum_setSymbol(formatter
->_nf
, UNUM_PLUS_SIGN_SYMBOL
, ubuffer
, cnt
, &status
);
587 } else if (kCFNumberFormatterCurrencySymbol
== key
) {
588 __CFGenericValidateType(value
, CFStringGetTypeID());
589 cnt
= CFStringGetLength((CFStringRef
)value
);
590 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
591 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
592 unum_setSymbol(formatter
->_nf
, UNUM_CURRENCY_SYMBOL
, (const UChar
*)ubuffer
, cnt
, &status
);
593 } else if (kCFNumberFormatterExponentSymbol
== key
) {
594 __CFGenericValidateType(value
, CFStringGetTypeID());
595 cnt
= CFStringGetLength((CFStringRef
)value
);
596 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
597 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
598 unum_setSymbol(formatter
->_nf
, UNUM_EXPONENTIAL_SYMBOL
, ubuffer
, cnt
, &status
);
599 } else if (kCFNumberFormatterMinIntegerDigits
== key
) {
600 __CFGenericValidateType(value
, CFNumberGetTypeID());
601 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
602 unum_setAttribute(formatter
->_nf
, UNUM_MIN_INTEGER_DIGITS
, n
);
603 } else if (kCFNumberFormatterMaxIntegerDigits
== key
) {
604 __CFGenericValidateType(value
, CFNumberGetTypeID());
605 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
606 unum_setAttribute(formatter
->_nf
, UNUM_MAX_INTEGER_DIGITS
, n
);
607 } else if (kCFNumberFormatterMinFractionDigits
== key
) {
608 __CFGenericValidateType(value
, CFNumberGetTypeID());
609 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
610 unum_setAttribute(formatter
->_nf
, UNUM_MIN_FRACTION_DIGITS
, n
);
611 } else if (kCFNumberFormatterMaxFractionDigits
== key
) {
612 __CFGenericValidateType(value
, CFNumberGetTypeID());
613 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
614 unum_setAttribute(formatter
->_nf
, UNUM_MAX_FRACTION_DIGITS
, n
);
615 } else if (kCFNumberFormatterGroupingSize
== key
) {
616 __CFGenericValidateType(value
, CFNumberGetTypeID());
617 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
618 unum_setAttribute(formatter
->_nf
, UNUM_GROUPING_SIZE
, n
);
619 } else if (kCFNumberFormatterSecondaryGroupingSize
== key
) {
620 __CFGenericValidateType(value
, CFNumberGetTypeID());
621 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
622 unum_setAttribute(formatter
->_nf
, UNUM_SECONDARY_GROUPING_SIZE
, n
);
623 } else if (kCFNumberFormatterRoundingMode
== key
) {
624 __CFGenericValidateType(value
, CFNumberGetTypeID());
625 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
626 unum_setAttribute(formatter
->_nf
, UNUM_ROUNDING_MODE
, n
);
627 } else if (kCFNumberFormatterRoundingIncrement
== key
) {
628 __CFGenericValidateType(value
, CFNumberGetTypeID());
629 CFNumberGetValue((CFNumberRef
)value
, kCFNumberDoubleType
, &d
);
630 unum_setDoubleAttribute(formatter
->_nf
, UNUM_ROUNDING_INCREMENT
, d
);
631 } else if (kCFNumberFormatterFormatWidth
== key
) {
632 __CFGenericValidateType(value
, CFNumberGetTypeID());
633 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
634 unum_setAttribute(formatter
->_nf
, UNUM_FORMAT_WIDTH
, n
);
635 } else if (kCFNumberFormatterPaddingPosition
== key
) {
636 __CFGenericValidateType(value
, CFNumberGetTypeID());
637 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
638 unum_setAttribute(formatter
->_nf
, UNUM_PADDING_POSITION
, n
);
639 } else if (kCFNumberFormatterPaddingCharacter
== key
) {
640 __CFGenericValidateType(value
, CFStringGetTypeID());
641 cnt
= CFStringGetLength((CFStringRef
)value
);
642 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
643 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
644 unum_setTextAttribute(formatter
->_nf
, UNUM_PADDING_CHARACTER
, ubuffer
, cnt
, &status
);
645 } else if (kCFNumberFormatterDefaultFormat
== key
) {
646 // read-only attribute
647 } else if (kCFNumberFormatterMultiplier
== key
) {
648 __CFGenericValidateType(value
, CFNumberGetTypeID());
649 CFNumberRef old
= formatter
->_multiplier
;
650 formatter
->_multiplier
= value
? (CFNumberRef
)CFRetain(value
) : NULL
;
651 if (old
) CFRelease(old
);
652 } else if (kCFNumberFormatterPositivePrefix
== key
) {
653 __CFGenericValidateType(value
, CFStringGetTypeID());
654 cnt
= CFStringGetLength((CFStringRef
)value
);
655 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
656 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
657 unum_setTextAttribute(formatter
->_nf
, UNUM_POSITIVE_PREFIX
, ubuffer
, cnt
, &status
);
658 } else if (kCFNumberFormatterPositiveSuffix
== key
) {
659 __CFGenericValidateType(value
, CFStringGetTypeID());
660 cnt
= CFStringGetLength((CFStringRef
)value
);
661 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
662 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
663 unum_setTextAttribute(formatter
->_nf
, UNUM_POSITIVE_SUFFIX
, (const UChar
*)ubuffer
, cnt
, &status
);
664 } else if (kCFNumberFormatterNegativePrefix
== key
) {
665 __CFGenericValidateType(value
, CFStringGetTypeID());
666 cnt
= CFStringGetLength((CFStringRef
)value
);
667 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
668 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
669 unum_setTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, cnt
, &status
);
670 } else if (kCFNumberFormatterNegativeSuffix
== key
) {
671 __CFGenericValidateType(value
, CFStringGetTypeID());
672 cnt
= CFStringGetLength((CFStringRef
)value
);
673 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
674 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
675 unum_setTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_SUFFIX
, (const UChar
*)ubuffer
, cnt
, &status
);
676 } else if (kCFNumberFormatterPerMillSymbol
== key
) {
677 __CFGenericValidateType(value
, CFStringGetTypeID());
678 cnt
= CFStringGetLength((CFStringRef
)value
);
679 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
680 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
681 unum_setSymbol(formatter
->_nf
, UNUM_PERMILL_SYMBOL
, ubuffer
, cnt
, &status
);
682 } else if (kCFNumberFormatterInternationalCurrencySymbol
== key
) {
683 __CFGenericValidateType(value
, CFStringGetTypeID());
684 cnt
= CFStringGetLength((CFStringRef
)value
);
685 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
686 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
687 unum_setSymbol(formatter
->_nf
, UNUM_INTL_CURRENCY_SYMBOL
, ubuffer
, cnt
, &status
);
688 } else if (kCFNumberFormatterCurrencyGroupingSeparator
== key
) {
689 __CFGenericValidateType(value
, CFStringGetTypeID());
690 cnt
= CFStringGetLength((CFStringRef
)value
);
691 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
692 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
693 unum_setSymbol(formatter
->_nf
, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL
, ubuffer
, cnt
, &status
);
694 } else if (kCFNumberFormatterIsLenient
== key
) {
695 __CFGenericValidateType(value
, CFBooleanGetTypeID());
696 unum_setAttribute(formatter
->_nf
, UNUM_LENIENT_PARSE
, (kCFBooleanTrue
== value
));
697 } else if (kCFNumberFormatterUseSignificantDigits
== key
) {
698 __CFGenericValidateType(value
, CFBooleanGetTypeID());
699 unum_setAttribute(formatter
->_nf
, UNUM_SIGNIFICANT_DIGITS_USED
, (kCFBooleanTrue
== value
));
700 } else if (kCFNumberFormatterMinSignificantDigits
== key
) {
701 __CFGenericValidateType(value
, CFNumberGetTypeID());
702 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
703 unum_setAttribute(formatter
->_nf
, UNUM_MIN_SIGNIFICANT_DIGITS
, n
);
704 } else if (kCFNumberFormatterMaxSignificantDigits
== key
) {
705 __CFGenericValidateType(value
, CFNumberGetTypeID());
706 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
707 unum_setAttribute(formatter
->_nf
, UNUM_MAX_SIGNIFICANT_DIGITS
, n
);
709 CFAssert3(0, __kCFLogAssertion
, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__
, key
, key
);
713 CFTypeRef
CFNumberFormatterCopyProperty(CFNumberFormatterRef formatter
, CFStringRef key
) {
716 UErrorCode status
= U_ZERO_ERROR
;
717 UChar ubuffer
[BUFFER_SIZE
];
719 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
720 __CFGenericValidateType(key
, CFStringGetTypeID());
721 if (kCFNumberFormatterCurrencyCode
== key
) {
722 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_CURRENCY_CODE
, ubuffer
, BUFFER_SIZE
, &status
);
723 if (U_SUCCESS(status
) && cnt
== 0) {
724 CFStringRef localeName
= CFLocaleGetIdentifier(formatter
->_locale
);
725 char buffer
[BUFFER_SIZE
];
726 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
728 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
733 UErrorCode status
= U_ZERO_ERROR
;
734 UNumberFormat
*nf
= unum_open(UNUM_CURRENCY
, NULL
, 0, cstr
, NULL
, &status
);
736 cnt
= unum_getTextAttribute(nf
, UNUM_CURRENCY_CODE
, ubuffer
, BUFFER_SIZE
, &status
);
740 if (U_SUCCESS(status
) && 0 < cnt
&& cnt
<= BUFFER_SIZE
) {
741 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
743 } else if (kCFNumberFormatterDecimalSeparator
== key
) {
744 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_DECIMAL_SEPARATOR_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
745 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
746 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
748 } else if (kCFNumberFormatterCurrencyDecimalSeparator
== key
) {
749 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_MONETARY_SEPARATOR_SYMBOL
, (UChar
*)ubuffer
, BUFFER_SIZE
, &status
);
750 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
751 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
753 } else if (kCFNumberFormatterAlwaysShowDecimalSeparator
== key
) {
754 n
= unum_getAttribute(formatter
->_nf
, UNUM_DECIMAL_ALWAYS_SHOWN
);
756 return CFRetain(n
? kCFBooleanTrue
: kCFBooleanFalse
);
758 } else if (kCFNumberFormatterGroupingSeparator
== key
) {
759 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_GROUPING_SEPARATOR_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
760 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
761 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
763 } else if (kCFNumberFormatterUseGroupingSeparator
== key
) {
764 n
= unum_getAttribute(formatter
->_nf
, UNUM_GROUPING_USED
);
766 return CFRetain(n
? kCFBooleanTrue
: kCFBooleanFalse
);
768 } else if (kCFNumberFormatterPercentSymbol
== key
) {
769 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_PERCENT_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
770 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
771 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
773 } else if (kCFNumberFormatterZeroSymbol
== key
) {
774 return formatter
->_zeroSym
? CFRetain(formatter
->_zeroSym
) : NULL
;
775 } else if (kCFNumberFormatterNaNSymbol
== key
) {
776 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_NAN_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
777 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
778 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
780 } else if (kCFNumberFormatterInfinitySymbol
== key
) {
781 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_INFINITY_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
782 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
783 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
785 } else if (kCFNumberFormatterMinusSign
== key
) {
786 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_MINUS_SIGN_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
787 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
788 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
790 } else if (kCFNumberFormatterPlusSign
== key
) {
791 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_PLUS_SIGN_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
792 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
793 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
795 } else if (kCFNumberFormatterCurrencySymbol
== key
) {
796 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_CURRENCY_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
797 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
798 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
800 } else if (kCFNumberFormatterExponentSymbol
== key
) {
801 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_EXPONENTIAL_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
802 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
803 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
805 } else if (kCFNumberFormatterMinIntegerDigits
== key
) {
806 n
= unum_getAttribute(formatter
->_nf
, UNUM_MIN_INTEGER_DIGITS
);
808 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
810 } else if (kCFNumberFormatterMaxIntegerDigits
== key
) {
811 n
= unum_getAttribute(formatter
->_nf
, UNUM_MAX_INTEGER_DIGITS
);
813 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
815 } else if (kCFNumberFormatterMinFractionDigits
== key
) {
816 n
= unum_getAttribute(formatter
->_nf
, UNUM_MIN_FRACTION_DIGITS
);
818 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
820 } else if (kCFNumberFormatterMaxFractionDigits
== key
) {
821 n
= unum_getAttribute(formatter
->_nf
, UNUM_MAX_FRACTION_DIGITS
);
823 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
825 } else if (kCFNumberFormatterGroupingSize
== key
) {
826 n
= unum_getAttribute(formatter
->_nf
, UNUM_GROUPING_SIZE
);
828 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
830 } else if (kCFNumberFormatterSecondaryGroupingSize
== key
) {
831 n
= unum_getAttribute(formatter
->_nf
, UNUM_SECONDARY_GROUPING_SIZE
);
833 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
835 } else if (kCFNumberFormatterRoundingMode
== key
) {
836 n
= unum_getAttribute(formatter
->_nf
, UNUM_ROUNDING_MODE
);
838 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
840 } else if (kCFNumberFormatterRoundingIncrement
== key
) {
841 d
= unum_getDoubleAttribute(formatter
->_nf
, UNUM_ROUNDING_INCREMENT
);
843 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberDoubleType
, &d
);
845 } else if (kCFNumberFormatterFormatWidth
== key
) {
846 n
= unum_getAttribute(formatter
->_nf
, UNUM_FORMAT_WIDTH
);
848 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
850 } else if (kCFNumberFormatterPaddingPosition
== key
) {
851 n
= unum_getAttribute(formatter
->_nf
, UNUM_PADDING_POSITION
);
853 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
855 } else if (kCFNumberFormatterPaddingCharacter
== key
) {
856 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_PADDING_CHARACTER
, ubuffer
, BUFFER_SIZE
, &status
);
857 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
858 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
860 } else if (kCFNumberFormatterDefaultFormat
== key
) {
861 return formatter
->_defformat
? CFRetain(formatter
->_defformat
) : NULL
;
862 } else if (kCFNumberFormatterMultiplier
== key
) {
863 return formatter
->_multiplier
? CFRetain(formatter
->_multiplier
) : NULL
;
864 } else if (kCFNumberFormatterPositivePrefix
== key
) {
865 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_POSITIVE_PREFIX
, ubuffer
, BUFFER_SIZE
, &status
);
866 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
867 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
869 } else if (kCFNumberFormatterPositiveSuffix
== key
) {
870 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_POSITIVE_SUFFIX
, ubuffer
, BUFFER_SIZE
, &status
);
871 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
872 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
874 } else if (kCFNumberFormatterNegativePrefix
== key
) {
875 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, BUFFER_SIZE
, &status
);
876 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
877 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
879 } else if (kCFNumberFormatterNegativeSuffix
== key
) {
880 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_SUFFIX
, ubuffer
, BUFFER_SIZE
, &status
);
881 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
882 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
884 } else if (kCFNumberFormatterPerMillSymbol
== key
) {
885 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_PERMILL_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
886 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
887 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
889 } else if (kCFNumberFormatterInternationalCurrencySymbol
== key
) {
890 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_INTL_CURRENCY_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
891 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
892 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
894 } else if (kCFNumberFormatterCurrencyGroupingSeparator
== key
) {
895 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
896 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
897 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
899 } else if (kCFNumberFormatterIsLenient
== key
) {
900 n
= unum_getAttribute(formatter
->_nf
, UNUM_LENIENT_PARSE
);
902 return CFRetain(n
? kCFBooleanTrue
: kCFBooleanFalse
);
904 } else if (kCFNumberFormatterUseSignificantDigits
== key
) {
905 n
= unum_getAttribute(formatter
->_nf
, UNUM_SIGNIFICANT_DIGITS_USED
);
907 return CFRetain(n
? kCFBooleanTrue
: kCFBooleanFalse
);
909 } else if (kCFNumberFormatterMinSignificantDigits
== key
) {
910 n
= unum_getAttribute(formatter
->_nf
, UNUM_MIN_SIGNIFICANT_DIGITS
);
912 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
914 } else if (kCFNumberFormatterMaxSignificantDigits
== key
) {
915 n
= unum_getAttribute(formatter
->_nf
, UNUM_MAX_SIGNIFICANT_DIGITS
);
917 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
920 CFAssert3(0, __kCFLogAssertion
, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__
, key
, key
);
925 CONST_STRING_DECL(kCFNumberFormatterCurrencyCode
, "kCFNumberFormatterCurrencyCode")
926 CONST_STRING_DECL(kCFNumberFormatterDecimalSeparator
, "kCFNumberFormatterDecimalSeparator")
927 CONST_STRING_DECL(kCFNumberFormatterCurrencyDecimalSeparator
, "kCFNumberFormatterCurrencyDecimalSeparator")
928 CONST_STRING_DECL(kCFNumberFormatterAlwaysShowDecimalSeparator
, "kCFNumberFormatterAlwaysShowDecimalSeparator")
929 CONST_STRING_DECL(kCFNumberFormatterGroupingSeparator
, "kCFNumberFormatterGroupingSeparator")
930 CONST_STRING_DECL(kCFNumberFormatterUseGroupingSeparator
, "kCFNumberFormatterUseGroupingSeparator")
931 CONST_STRING_DECL(kCFNumberFormatterPercentSymbol
, "kCFNumberFormatterPercentSymbol")
932 CONST_STRING_DECL(kCFNumberFormatterZeroSymbol
, "kCFNumberFormatterZeroSymbol")
933 CONST_STRING_DECL(kCFNumberFormatterNaNSymbol
, "kCFNumberFormatterNaNSymbol")
934 CONST_STRING_DECL(kCFNumberFormatterInfinitySymbol
, "kCFNumberFormatterInfinitySymbol")
935 CONST_STRING_DECL(kCFNumberFormatterMinusSign
, "kCFNumberFormatterMinusSignSymbol")
936 CONST_STRING_DECL(kCFNumberFormatterPlusSign
, "kCFNumberFormatterPlusSignSymbol")
937 CONST_STRING_DECL(kCFNumberFormatterCurrencySymbol
, "kCFNumberFormatterCurrencySymbol")
938 CONST_STRING_DECL(kCFNumberFormatterExponentSymbol
, "kCFNumberFormatterExponentSymbol")
939 CONST_STRING_DECL(kCFNumberFormatterMinIntegerDigits
, "kCFNumberFormatterMinIntegerDigits")
940 CONST_STRING_DECL(kCFNumberFormatterMaxIntegerDigits
, "kCFNumberFormatterMaxIntegerDigits")
941 CONST_STRING_DECL(kCFNumberFormatterMinFractionDigits
, "kCFNumberFormatterMinFractionDigits")
942 CONST_STRING_DECL(kCFNumberFormatterMaxFractionDigits
, "kCFNumberFormatterMaxFractionDigits")
943 CONST_STRING_DECL(kCFNumberFormatterGroupingSize
, "kCFNumberFormatterGroupingSize")
944 CONST_STRING_DECL(kCFNumberFormatterSecondaryGroupingSize
, "kCFNumberFormatterSecondaryGroupingSize")
945 CONST_STRING_DECL(kCFNumberFormatterRoundingMode
, "kCFNumberFormatterRoundingMode")
946 CONST_STRING_DECL(kCFNumberFormatterRoundingIncrement
, "kCFNumberFormatterRoundingIncrement")
947 CONST_STRING_DECL(kCFNumberFormatterFormatWidth
, "kCFNumberFormatterFormatWidth")
948 CONST_STRING_DECL(kCFNumberFormatterPaddingPosition
, "kCFNumberFormatterPaddingPosition")
949 CONST_STRING_DECL(kCFNumberFormatterPaddingCharacter
, "kCFNumberFormatterPaddingCharacter")
950 CONST_STRING_DECL(kCFNumberFormatterDefaultFormat
, "kCFNumberFormatterDefaultFormat")
952 CONST_STRING_DECL(kCFNumberFormatterMultiplier
, "kCFNumberFormatterMultiplier")
953 CONST_STRING_DECL(kCFNumberFormatterPositivePrefix
, "kCFNumberFormatterPositivePrefix")
954 CONST_STRING_DECL(kCFNumberFormatterPositiveSuffix
, "kCFNumberFormatterPositiveSuffix")
955 CONST_STRING_DECL(kCFNumberFormatterNegativePrefix
, "kCFNumberFormatterNegativePrefix")
956 CONST_STRING_DECL(kCFNumberFormatterNegativeSuffix
, "kCFNumberFormatterNegativeSuffix")
957 CONST_STRING_DECL(kCFNumberFormatterPerMillSymbol
, "kCFNumberFormatterPerMillSymbol")
958 CONST_STRING_DECL(kCFNumberFormatterInternationalCurrencySymbol
, "kCFNumberFormatterInternationalCurrencySymbol")
960 CONST_STRING_DECL(kCFNumberFormatterCurrencyGroupingSeparator
, "kCFNumberFormatterCurrencyGroupingSeparator")
961 CONST_STRING_DECL(kCFNumberFormatterIsLenient
, "kCFNumberFormatterIsLenient")
962 CONST_STRING_DECL(kCFNumberFormatterUseSignificantDigits
, "kCFNumberFormatterUseSignificantDigits")
963 CONST_STRING_DECL(kCFNumberFormatterMinSignificantDigits
, "kCFNumberFormatterMinSignificantDigits")
964 CONST_STRING_DECL(kCFNumberFormatterMaxSignificantDigits
, "kCFNumberFormatterMaxSignificantDigits")
966 Boolean
CFNumberFormatterGetDecimalInfoForCurrencyCode(CFStringRef currencyCode
, int32_t *defaultFractionDigits
, double *roundingIncrement
) {
968 __CFGenericValidateType(currencyCode
, CFStringGetTypeID());
969 CFAssert1(3 == CFStringGetLength(currencyCode
), __kCFLogAssertion
, "%s(): currencyCode is not 3 characters", __PRETTY_FUNCTION__
);
970 CFStringGetCharacters(currencyCode
, CFRangeMake(0, 3), (UniChar
*)ubuffer
);
972 UErrorCode icuStatus
= U_ZERO_ERROR
;
973 if (defaultFractionDigits
) *defaultFractionDigits
= ucurr_getDefaultFractionDigits(ubuffer
, &icuStatus
);
974 if (roundingIncrement
) *roundingIncrement
= ucurr_getRoundingIncrement(ubuffer
, &icuStatus
);
975 if (U_FAILURE(icuStatus
))
977 return (!defaultFractionDigits
|| 0 <= *defaultFractionDigits
) && (!roundingIncrement
|| 0.0 <= *roundingIncrement
);