2 * Copyright (c) 2010 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-2009, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
29 #include <CoreFoundation/CFNumberFormatter.h>
30 #include "CFInternal.h"
31 #include "CFLocaleInternal.h"
32 #include <unicode/unum.h>
33 #include <unicode/ucurr.h>
37 static void __CFNumberFormatterCustomize(CFNumberFormatterRef formatter
);
38 static CFStringRef
__CFNumberFormatterCreateCompressedString(CFStringRef inString
, Boolean isFormat
, CFRange
*rangep
);
39 static UErrorCode
__CFNumberFormatterApplyPattern(CFNumberFormatterRef formatter
, CFStringRef pattern
);
41 #define BUFFER_SIZE 768
43 struct __CFNumberFormatter
{
47 CFNumberFormatterStyle _style
;
48 CFStringRef _format
; // NULL for RBNFs
49 CFStringRef _defformat
;
50 CFStringRef _compformat
;
51 CFNumberRef _multiplier
;
54 Boolean _userSetMultiplier
;
57 static CFStringRef
__CFNumberFormatterCopyDescription(CFTypeRef cf
) {
58 CFNumberFormatterRef formatter
= (CFNumberFormatterRef
)cf
;
59 return CFStringCreateWithFormat(CFGetAllocator(formatter
), NULL
, CFSTR("<CFNumberFormatter %p [%p]>"), cf
, CFGetAllocator(formatter
));
62 static void __CFNumberFormatterDeallocate(CFTypeRef cf
) {
63 CFNumberFormatterRef formatter
= (CFNumberFormatterRef
)cf
;
64 if (formatter
->_nf
) unum_close(formatter
->_nf
);
65 if (formatter
->_locale
) CFRelease(formatter
->_locale
);
66 if (formatter
->_format
) CFRelease(formatter
->_format
);
67 if (formatter
->_defformat
) CFRelease(formatter
->_defformat
);
68 if (formatter
->_compformat
) CFRelease(formatter
->_compformat
);
69 if (formatter
->_multiplier
) CFRelease(formatter
->_multiplier
);
70 if (formatter
->_zeroSym
) CFRelease(formatter
->_zeroSym
);
73 static CFTypeID __kCFNumberFormatterTypeID
= _kCFRuntimeNotATypeID
;
75 static const CFRuntimeClass __CFNumberFormatterClass
= {
80 __CFNumberFormatterDeallocate
,
84 __CFNumberFormatterCopyDescription
87 static void __CFNumberFormatterInitialize(void) {
88 __kCFNumberFormatterTypeID
= _CFRuntimeRegisterClass(&__CFNumberFormatterClass
);
91 CFTypeID
CFNumberFormatterGetTypeID(void) {
92 if (_kCFRuntimeNotATypeID
== __kCFNumberFormatterTypeID
) __CFNumberFormatterInitialize();
93 return __kCFNumberFormatterTypeID
;
96 CFNumberFormatterRef
CFNumberFormatterCreate(CFAllocatorRef allocator
, CFLocaleRef locale
, CFNumberFormatterStyle style
) {
97 struct __CFNumberFormatter
*memory
;
98 uint32_t size
= sizeof(struct __CFNumberFormatter
) - sizeof(CFRuntimeBase
);
99 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
100 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
101 __CFGenericValidateType(locale
, CFLocaleGetTypeID());
102 memory
= (struct __CFNumberFormatter
*)_CFRuntimeCreateInstance(allocator
, CFNumberFormatterGetTypeID(), size
, NULL
);
103 if (NULL
== memory
) {
107 memory
->_locale
= NULL
;
108 memory
->_format
= NULL
;
109 memory
->_defformat
= NULL
;
110 memory
->_compformat
= NULL
;
111 memory
->_multiplier
= NULL
;
112 memory
->_zeroSym
= NULL
;
113 memory
->_isLenient
= false;
114 memory
->_userSetMultiplier
= false;
115 if (NULL
== locale
) locale
= CFLocaleGetSystem();
116 memory
->_style
= style
;
119 case kCFNumberFormatterNoStyle
: ustyle
= UNUM_IGNORE
; break;
120 case kCFNumberFormatterDecimalStyle
: ustyle
= UNUM_DECIMAL
; break;
121 case kCFNumberFormatterCurrencyStyle
: ustyle
= UNUM_CURRENCY
; break;
122 case kCFNumberFormatterPercentStyle
: ustyle
= UNUM_PERCENT
; break;
123 case kCFNumberFormatterScientificStyle
: ustyle
= UNUM_SCIENTIFIC
; break;
124 case kCFNumberFormatterSpellOutStyle
: ustyle
= UNUM_SPELLOUT
; break;
126 CFAssert2(0, __kCFLogAssertion
, "%s(): unknown style %d", __PRETTY_FUNCTION__
, style
);
127 ustyle
= UNUM_DECIMAL
;
128 memory
->_style
= kCFNumberFormatterDecimalStyle
;
131 CFStringRef localeName
= locale
? CFLocaleGetIdentifier(locale
) : CFSTR("");
132 char buffer
[BUFFER_SIZE
];
133 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
135 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
141 UErrorCode status
= U_ZERO_ERROR
;
142 memory
->_nf
= unum_open((UNumberFormatStyle
)ustyle
, NULL
, 0, cstr
, NULL
, &status
);
143 CFAssert2(memory
->_nf
, __kCFLogAssertion
, "%s(): error (%d) creating number formatter", __PRETTY_FUNCTION__
, status
);
144 if (NULL
== memory
->_nf
) {
149 if (kCFNumberFormatterNoStyle
== style
) {
150 status
= U_ZERO_ERROR
;
151 ubuff
[0] = '#'; ubuff
[1] = ';'; ubuff
[2] = '#';
152 unum_applyPattern(memory
->_nf
, false, ubuff
, 3, NULL
, &status
);
153 unum_setAttribute(memory
->_nf
, UNUM_MAX_INTEGER_DIGITS
, 42);
154 unum_setAttribute(memory
->_nf
, UNUM_MAX_FRACTION_DIGITS
, 0);
156 memory
->_locale
= locale
? CFLocaleCreateCopy(allocator
, locale
) : CFLocaleGetSystem();
157 __CFNumberFormatterCustomize(memory
);
158 if (kCFNumberFormatterSpellOutStyle
!= memory
->_style
) {
159 UChar ubuffer
[BUFFER_SIZE
];
160 status
= U_ZERO_ERROR
;
161 int32_t ret
= unum_toPattern(memory
->_nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
162 if (U_SUCCESS(status
) && ret
<= BUFFER_SIZE
) {
163 memory
->_format
= CFStringCreateWithCharacters(allocator
, (const UniChar
*)ubuffer
, ret
);
166 memory
->_defformat
= memory
->_format
? (CFStringRef
)CFRetain(memory
->_format
) : NULL
;
167 memory
->_compformat
= memory
->_format
? __CFNumberFormatterCreateCompressedString(memory
->_format
, true, NULL
) : NULL
;
168 if (kCFNumberFormatterSpellOutStyle
!= memory
->_style
) {
169 int32_t n
= unum_getAttribute(memory
->_nf
, UNUM_MULTIPLIER
);
171 memory
->_multiplier
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, &n
);
172 unum_setAttribute(memory
->_nf
, UNUM_MULTIPLIER
, 1);
175 unum_setAttribute(memory
->_nf
, UNUM_LENIENT_PARSE
, 0);
176 return (CFNumberFormatterRef
)memory
;
179 extern CFDictionaryRef
__CFLocaleGetPrefs(CFLocaleRef locale
);
181 static void __substituteFormatStringFromPrefsNF(CFNumberFormatterRef formatter
) {
182 CFIndex formatStyle
= formatter
->_style
;
183 if (kCFNumberFormatterSpellOutStyle
== formatStyle
) return;
184 CFStringRef prefName
= CFSTR("AppleICUNumberFormatStrings");
185 if (kCFNumberFormatterNoStyle
!= formatStyle
) {
186 CFStringRef pref
= NULL
;
187 CFDictionaryRef prefs
= __CFLocaleGetPrefs(formatter
->_locale
);
188 CFPropertyListRef metapref
= prefs
? CFDictionaryGetValue(prefs
, prefName
) : NULL
;
189 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
191 switch (formatStyle
) {
192 case kCFNumberFormatterDecimalStyle
: key
= CFSTR("1"); break;
193 case kCFNumberFormatterCurrencyStyle
: key
= CFSTR("2"); break;
194 case kCFNumberFormatterPercentStyle
: key
= CFSTR("3"); break;
195 case kCFNumberFormatterScientificStyle
: key
= CFSTR("4"); break;
196 case kCFNumberFormatterSpellOutStyle
: key
= CFSTR("5"); break;
197 default: key
= CFSTR("0"); break;
199 pref
= (CFStringRef
)CFDictionaryGetValue((CFDictionaryRef
)metapref
, key
);
201 if (NULL
!= pref
&& CFGetTypeID(pref
) == CFStringGetTypeID()) {
202 int32_t icustyle
= UNUM_IGNORE
;
203 switch (formatStyle
) {
204 case kCFNumberFormatterDecimalStyle
: icustyle
= UNUM_DECIMAL
; break;
205 case kCFNumberFormatterCurrencyStyle
: icustyle
= UNUM_CURRENCY
; break;
206 case kCFNumberFormatterPercentStyle
: icustyle
= UNUM_PERCENT
; break;
207 case kCFNumberFormatterScientificStyle
: icustyle
= UNUM_SCIENTIFIC
; break;
208 case kCFNumberFormatterSpellOutStyle
: icustyle
= UNUM_SPELLOUT
; break;
210 CFStringRef localeName
= CFLocaleGetIdentifier(formatter
->_locale
);
211 char buffer
[BUFFER_SIZE
];
212 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
214 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
216 UErrorCode status
= U_ZERO_ERROR
;
217 UNumberFormat
*nf
= unum_open((UNumberFormatStyle
)icustyle
, NULL
, 0, cstr
, NULL
, &status
);
219 UChar ubuffer
[BUFFER_SIZE
];
220 status
= U_ZERO_ERROR
;
221 int32_t number_len
= unum_toPattern(nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
222 if (U_SUCCESS(status
) && number_len
<= BUFFER_SIZE
) {
223 CFStringRef numberString
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)ubuffer
, number_len
);
224 status
= U_ZERO_ERROR
;
225 int32_t formatter_len
= unum_toPattern(formatter
->_nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
226 if (U_SUCCESS(status
) && formatter_len
<= BUFFER_SIZE
) {
227 CFMutableStringRef formatString
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
228 CFStringAppendCharacters(formatString
, (const UniChar
*)ubuffer
, formatter_len
);
229 // find numberString inside formatString, substitute the pref in that range
231 if (CFStringFindWithOptions(formatString
, numberString
, CFRangeMake(0, formatter_len
), 0, &result
)) {
232 CFStringReplace(formatString
, result
, pref
);
233 __CFNumberFormatterApplyPattern(formatter
, formatString
);
235 CFRelease(formatString
);
237 CFRelease(numberString
);
245 static UniChar
__CFNumberFormatterNormalizeCharacter(UniChar c
) {
246 if (CFCharacterSetIsCharacterMember(CFCharacterSetGetPredefined(kCFCharacterSetWhitespace
), c
)) {
253 /* 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. */
254 static CFStringRef
__CFNumberFormatterCreateCompressedString(CFStringRef inString
, Boolean isFormat
, CFRange
*rangep
) {
255 if (!inString
) return NULL
;
256 CFRange range
= { 0, 0 };
260 range
.length
= CFStringGetLength(inString
);
262 CFMutableStringRef outString
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
263 CFCharacterSetRef letters
= CFCharacterSetGetPredefined(kCFCharacterSetLetter
);
264 CFCharacterSetRef numbers
= CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
);
265 UniChar prevCh
= 0, nextCh
= 0;
266 Boolean inQuote
= false;
267 for (CFIndex in_idx
= range
.location
; in_idx
< range
.location
+ range
.length
; in_idx
++) {
268 UniChar ch
= __CFNumberFormatterNormalizeCharacter(CFStringGetCharacterAtIndex(inString
, in_idx
));
269 nextCh
= (in_idx
+1 < range
.length
) ? CFStringGetCharacterAtIndex(inString
, in_idx
+1) : 0;
270 if (isFormat
&& ch
== '\'') inQuote
= !inQuote
;
271 if (inQuote
|| ch
!= ' ' || (CFCharacterSetIsCharacterMember(letters
, prevCh
) && CFCharacterSetIsCharacterMember(letters
, nextCh
)) || (CFCharacterSetIsCharacterMember(numbers
, prevCh
) && CFCharacterSetIsCharacterMember(numbers
, nextCh
))) {
272 CFStringAppendCharacters(outString
, &ch
, 1);
279 static void __CFNumberFormatterApplySymbolPrefs(const void *key
, const void *value
, void *context
) {
280 if (CFGetTypeID(key
) == CFStringGetTypeID() && CFGetTypeID(value
) == CFStringGetTypeID()) {
281 CFNumberFormatterRef formatter
= (CFNumberFormatterRef
)context
;
282 UNumberFormatSymbol sym
= (UNumberFormatSymbol
)CFStringGetIntValue((CFStringRef
)key
);
283 CFStringRef item
= (CFStringRef
)value
;
284 CFIndex item_cnt
= CFStringGetLength(item
);
285 STACK_BUFFER_DECL(UChar
, item_buffer
, item_cnt
);
286 UChar
*item_ustr
= (UChar
*)CFStringGetCharactersPtr(item
);
287 if (NULL
== item_ustr
) {
288 CFStringGetCharacters(item
, CFRangeMake(0, __CFMin(BUFFER_SIZE
, item_cnt
)), (UniChar
*)item_buffer
);
289 item_ustr
= item_buffer
;
291 UErrorCode status
= U_ZERO_ERROR
;
292 unum_setSymbol(formatter
->_nf
, sym
, item_ustr
, item_cnt
, &status
);
296 static UErrorCode
__CFNumberFormatterApplyPattern(CFNumberFormatterRef formatter
, CFStringRef pattern
) {
297 CFIndex cnt
= CFStringGetLength(pattern
);
298 STACK_BUFFER_DECL(UChar
, ubuffer
, cnt
);
299 const UChar
*ustr
= (const UChar
*)CFStringGetCharactersPtr(pattern
);
301 CFStringGetCharacters(pattern
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
304 UErrorCode status
= U_ZERO_ERROR
;
305 unum_applyPattern(formatter
->_nf
, false, ustr
, cnt
, NULL
, &status
);
307 // unum_applyPattern() may have magically changed other attributes based on
308 // the contents of the format string; we simply expose that ICU behavior, except
309 // for UNUM_MULTIPLIER, which we re-read and reset, like we did at initialization
310 // time though any user-set multiplier state takes precedence.
311 if (formatter
->_userSetMultiplier
) {
312 unum_setAttribute(formatter
->_nf
, UNUM_MULTIPLIER
, 1);
314 if (formatter
->_multiplier
) CFRelease(formatter
->_multiplier
);
315 formatter
->_multiplier
= NULL
;
316 int32_t n
= unum_getAttribute(formatter
->_nf
, UNUM_MULTIPLIER
);
318 formatter
->_multiplier
= CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
319 unum_setAttribute(formatter
->_nf
, UNUM_MULTIPLIER
, 1);
325 static void __CFNumberFormatterCustomize(CFNumberFormatterRef formatter
) {
326 __substituteFormatStringFromPrefsNF(formatter
);
327 CFDictionaryRef prefs
= __CFLocaleGetPrefs(formatter
->_locale
);
328 CFPropertyListRef metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleICUNumberSymbols")) : NULL
;
329 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
330 CFDictionaryApplyFunction((CFDictionaryRef
)metapref
, __CFNumberFormatterApplySymbolPrefs
, formatter
);
334 CFLocaleRef
CFNumberFormatterGetLocale(CFNumberFormatterRef formatter
) {
335 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
336 return formatter
->_locale
;
339 CFNumberFormatterStyle
CFNumberFormatterGetStyle(CFNumberFormatterRef formatter
) {
340 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
341 return formatter
->_style
;
344 CFStringRef
CFNumberFormatterGetFormat(CFNumberFormatterRef formatter
) {
345 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
346 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
) return NULL
;
347 UChar ubuffer
[BUFFER_SIZE
];
348 CFStringRef newString
= NULL
;
349 UErrorCode status
= U_ZERO_ERROR
;
350 int32_t ret
= unum_toPattern(formatter
->_nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
351 if (U_SUCCESS(status
) && ret
<= BUFFER_SIZE
) {
352 newString
= CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, ret
);
354 if (newString
&& !formatter
->_format
) {
355 formatter
->_format
= newString
;
356 if (formatter
->_compformat
) CFRelease(formatter
->_compformat
);
357 formatter
->_compformat
= __CFNumberFormatterCreateCompressedString(formatter
->_format
, true, NULL
);
358 } else if (newString
&& !CFEqual(newString
, formatter
->_format
)) {
359 CFRelease(formatter
->_format
);
360 formatter
->_format
= newString
;
361 if (formatter
->_compformat
) CFRelease(formatter
->_compformat
);
362 formatter
->_compformat
= __CFNumberFormatterCreateCompressedString(formatter
->_format
, true, NULL
);
363 } else if (newString
) {
364 CFRelease(newString
);
366 return formatter
->_format
;
369 void CFNumberFormatterSetFormat(CFNumberFormatterRef formatter
, CFStringRef formatString
) {
370 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
371 __CFGenericValidateType(formatString
, CFStringGetTypeID());
372 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
) return;
373 CFIndex cnt
= CFStringGetLength(formatString
);
374 CFAssert1(cnt
<= 1024, __kCFLogAssertion
, "%s(): format string too long", __PRETTY_FUNCTION__
);
375 if ((!formatter
->_format
|| !CFEqual(formatter
->_format
, formatString
)) && cnt
<= 1024) {
376 UErrorCode status
= __CFNumberFormatterApplyPattern(formatter
, formatString
);
377 if (U_SUCCESS(status
)) {
378 UChar ubuffer2
[BUFFER_SIZE
];
379 status
= U_ZERO_ERROR
;
380 int32_t ret
= unum_toPattern(formatter
->_nf
, false, ubuffer2
, BUFFER_SIZE
, &status
);
381 if (U_SUCCESS(status
) && ret
<= BUFFER_SIZE
) {
382 if (formatter
->_format
) CFRelease(formatter
->_format
);
383 formatter
->_format
= CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer2
, ret
);
384 if (formatter
->_compformat
) CFRelease(formatter
->_compformat
);
385 formatter
->_compformat
= __CFNumberFormatterCreateCompressedString(formatter
->_format
, true, NULL
);
391 CFStringRef
CFNumberFormatterCreateStringWithNumber(CFAllocatorRef allocator
, CFNumberFormatterRef formatter
, CFNumberRef number
) {
392 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
393 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
394 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
395 __CFGenericValidateType(number
, CFNumberGetTypeID());
396 CFNumberType type
= CFNumberGetType(number
);
398 CFNumberGetValue(number
, type
, buffer
);
399 return CFNumberFormatterCreateStringWithValue(allocator
, formatter
, type
, buffer
);
402 #define FORMAT(T, FUNC) \
403 T value = *(T *)valuePtr; \
404 if (0 == value && formatter->_zeroSym) { return (CFStringRef)CFRetain(formatter->_zeroSym); } \
405 if (1.0 != multiplier) { \
407 if (modf(multiplier, &dummy) < FLT_EPSILON) { /* float epsilon specifically chosen cuz it is a bit bigger */ \
408 value = value * (T)floor(multiplier); \
410 value = (T)(value * multiplier); \
413 status = U_ZERO_ERROR; \
414 used = FUNC(formatter->_nf, value, ubuffer, cnt, NULL, &status); \
415 if (status == U_BUFFER_OVERFLOW_ERROR || cnt < used) { \
417 ustr = (UChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UChar) * cnt, 0); \
418 status = U_ZERO_ERROR; \
419 used = FUNC(formatter->_nf, value, ustr, cnt, NULL, &status); \
422 CFStringRef
CFNumberFormatterCreateStringWithValue(CFAllocatorRef allocator
, CFNumberFormatterRef formatter
, CFNumberType numberType
, const void *valuePtr
) {
423 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
424 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
425 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
426 double multiplier
= 1.0;
427 if (formatter
->_multiplier
) {
428 if (!CFNumberGetValue(formatter
->_multiplier
, kCFNumberFloat64Type
, &multiplier
)) {
432 UChar
*ustr
= NULL
, ubuffer
[BUFFER_SIZE
];
433 UErrorCode status
= U_ZERO_ERROR
;
434 CFIndex used
, cnt
= BUFFER_SIZE
;
435 if (numberType
== kCFNumberFloat64Type
|| numberType
== kCFNumberDoubleType
) {
436 FORMAT(double, unum_formatDouble
)
437 } else if (numberType
== kCFNumberFloat32Type
|| numberType
== kCFNumberFloatType
) {
438 FORMAT(float, unum_formatDouble
)
439 } else if (numberType
== kCFNumberSInt64Type
|| numberType
== kCFNumberLongLongType
) {
440 FORMAT(int64_t, unum_formatInt64
)
441 } else if (numberType
== kCFNumberLongType
|| numberType
== kCFNumberCFIndexType
) {
443 FORMAT(int64_t, unum_formatInt64
)
445 FORMAT(int32_t, unum_formatInt64
)
447 } else if (numberType
== kCFNumberSInt32Type
|| numberType
== kCFNumberIntType
) {
448 FORMAT(int32_t, unum_formatInt64
)
449 } else if (numberType
== kCFNumberSInt16Type
|| numberType
== kCFNumberShortType
) {
450 FORMAT(int16_t, unum_formatInt64
)
451 } else if (numberType
== kCFNumberSInt8Type
|| numberType
== kCFNumberCharType
) {
452 FORMAT(int8_t, unum_formatInt64
)
454 CFAssert2(0, __kCFLogAssertion
, "%s(): unknown CFNumberType (%d)", __PRETTY_FUNCTION__
, numberType
);
457 CFStringRef string
= NULL
;
458 if (U_SUCCESS(status
)) {
459 string
= CFStringCreateWithCharacters(allocator
, ustr
? (const UniChar
*)ustr
: (const UniChar
*)ubuffer
, used
);
461 if (ustr
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, ustr
);
467 CFNumberRef
CFNumberFormatterCreateNumberFromString(CFAllocatorRef allocator
, CFNumberFormatterRef formatter
, CFStringRef string
, CFRange
*rangep
, CFOptionFlags options
) {
468 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
469 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
470 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
471 __CFGenericValidateType(string
, CFStringGetTypeID());
472 CFNumberType type
= (options
& kCFNumberFormatterParseIntegersOnly
) ? kCFNumberSInt64Type
: kCFNumberFloat64Type
;
474 if (CFNumberFormatterGetValueFromString(formatter
, string
, rangep
, type
, buffer
)) {
475 return CFNumberCreate(allocator
, type
, buffer
);
480 Boolean
CFNumberFormatterGetValueFromString(CFNumberFormatterRef formatter
, CFStringRef string
, CFRange
*rangep
, CFNumberType numberType
, void *valuePtr
) {
481 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
482 __CFGenericValidateType(string
, CFStringGetTypeID());
483 CFStringRef stringToParse
= formatter
->_isLenient
? __CFNumberFormatterCreateCompressedString(string
, false, rangep
) : (CFStringRef
)CFRetain(string
);
484 CFRange range
= {0, 0};
485 if(formatter
->_isLenient
) {
486 range
.length
= CFStringGetLength(stringToParse
);
491 range
.length
= CFStringGetLength(stringToParse
);
493 // unum_parse chokes on leading whitespace
494 CFCharacterSetRef whitespace
= CFCharacterSetGetPredefined(kCFCharacterSetWhitespace
);
495 while(range
.length
> 0 && CFCharacterSetIsCharacterMember(whitespace
, CFStringGetCharacterAtIndex(stringToParse
, range
.location
))) {
500 Boolean isZero
= false;
501 if (formatter
->_zeroSym
) {
502 CFStringRef zeroSym
= formatter
->_isLenient
? __CFNumberFormatterCreateCompressedString(formatter
->_zeroSym
, false, NULL
) : (CFStringRef
)CFRetain(formatter
->_zeroSym
);
503 if (kCFCompareEqualTo
== CFStringCompare(stringToParse
, zeroSym
, 0)) {
508 if (1024 < range
.length
) range
.length
= 1024;
509 const UChar
*ustr
= (const UChar
*)CFStringGetCharactersPtr(stringToParse
);
510 STACK_BUFFER_DECL(UChar
, ubuffer
, (NULL
== ustr
) ? range
.length
: 1);
512 CFStringGetCharacters(stringToParse
, range
, (UniChar
*)ubuffer
);
514 } else if (!formatter
->_isLenient
) {
515 ustr
+= range
.location
;
517 if (formatter
->_isLenient
) __CFNumberFormatterApplyPattern(formatter
, formatter
->_compformat
);
518 Boolean integerOnly
= 1;
519 switch (numberType
) {
520 case kCFNumberSInt8Type
: case kCFNumberCharType
:
521 case kCFNumberSInt16Type
: case kCFNumberShortType
:
522 case kCFNumberSInt32Type
: case kCFNumberIntType
:
523 case kCFNumberLongType
: case kCFNumberCFIndexType
:
524 case kCFNumberSInt64Type
: case kCFNumberLongLongType
:
525 unum_setAttribute(formatter
->_nf
, UNUM_PARSE_INT_ONLY
, 1);
528 unum_setAttribute(formatter
->_nf
, UNUM_PARSE_INT_ONLY
, 0);
533 UErrorCode status
= U_ZERO_ERROR
;
537 dpos
= rangep
? rangep
->length
: 0;
540 dreti
= unum_parseInt64(formatter
->_nf
, ustr
, range
.length
, &dpos
, &status
);
542 dretd
= unum_parseDouble(formatter
->_nf
, ustr
, range
.length
, &dpos
, &status
);
545 if (formatter
->_isLenient
) {
547 CFIndex uncompEnd
= rangep
->location
+ rangep
->length
;
548 CFIndex uncompIdx
= rangep
->location
;
549 for (CFIndex compIdx
= 0; compIdx
< dpos
&& uncompIdx
< uncompEnd
; compIdx
++, uncompIdx
++) {
550 while (uncompIdx
< uncompEnd
&& ustr
[compIdx
] != __CFNumberFormatterNormalizeCharacter(CFStringGetCharacterAtIndex(string
, uncompIdx
))) uncompIdx
++;
552 rangep
->length
= uncompIdx
- rangep
->location
;
554 __CFNumberFormatterApplyPattern(formatter
, formatter
->_format
);
556 rangep
->length
= dpos
+ (range
.location
- rangep
->location
);
558 CFRelease(stringToParse
);
559 if (U_FAILURE(status
)) {
562 if (formatter
->_multiplier
) {
563 double multiplier
= 1.0;
564 if (!CFNumberGetValue(formatter
->_multiplier
, kCFNumberFloat64Type
, &multiplier
)) {
567 dreti
= (int64_t)((double)dreti
/ multiplier
); // integer truncation
568 dretd
= dretd
/ multiplier
;
570 switch (numberType
) {
571 case kCFNumberSInt8Type
: case kCFNumberCharType
:
572 if (INT8_MIN
<= dreti
&& dreti
<= INT8_MAX
) {
573 *(int8_t *)valuePtr
= (int8_t)dreti
;
577 case kCFNumberSInt16Type
: case kCFNumberShortType
:
578 if (INT16_MIN
<= dreti
&& dreti
<= INT16_MAX
) {
579 *(int16_t *)valuePtr
= (int16_t)dreti
;
583 case kCFNumberSInt32Type
: case kCFNumberIntType
:
585 case kCFNumberLongType
: case kCFNumberCFIndexType
:
587 if (INT32_MIN
<= dreti
&& dreti
<= INT32_MAX
) {
588 *(int32_t *)valuePtr
= (int32_t)dreti
;
592 case kCFNumberSInt64Type
: case kCFNumberLongLongType
:
594 case kCFNumberLongType
: case kCFNumberCFIndexType
:
596 if (INT64_MIN
<= dreti
&& dreti
<= INT64_MAX
) {
597 *(int64_t *)valuePtr
= (int64_t)dreti
;
601 case kCFNumberFloat32Type
: case kCFNumberFloatType
:
602 if (-FLT_MAX
<= dretd
&& dretd
<= FLT_MAX
) {
603 *(float *)valuePtr
= (float)dretd
;
607 case kCFNumberFloat64Type
: case kCFNumberDoubleType
:
608 if (-DBL_MAX
<= dretd
&& dretd
<= DBL_MAX
) {
609 *(double *)valuePtr
= (double)dretd
;
617 void CFNumberFormatterSetProperty(CFNumberFormatterRef formatter
, CFStringRef key
, CFTypeRef value
) {
620 UErrorCode status
= U_ZERO_ERROR
;
621 UChar ubuffer
[BUFFER_SIZE
];
623 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
624 __CFGenericValidateType(key
, CFStringGetTypeID());
625 if (kCFNumberFormatterCurrencyCodeKey
== key
) {
626 __CFGenericValidateType(value
, CFStringGetTypeID());
627 cnt
= CFStringGetLength((CFStringRef
)value
);
628 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
629 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
630 unum_setTextAttribute(formatter
->_nf
, UNUM_CURRENCY_CODE
, ubuffer
, cnt
, &status
);
631 } else if (kCFNumberFormatterDecimalSeparatorKey
== key
) {
632 __CFGenericValidateType(value
, CFStringGetTypeID());
633 cnt
= CFStringGetLength((CFStringRef
)value
);
634 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
635 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
636 unum_setSymbol(formatter
->_nf
, UNUM_DECIMAL_SEPARATOR_SYMBOL
, ubuffer
, cnt
, &status
);
637 } else if (kCFNumberFormatterCurrencyDecimalSeparatorKey
== key
) {
638 __CFGenericValidateType(value
, CFStringGetTypeID());
639 cnt
= CFStringGetLength((CFStringRef
)value
);
640 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
641 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
642 unum_setSymbol(formatter
->_nf
, UNUM_MONETARY_SEPARATOR_SYMBOL
, ubuffer
, cnt
, &status
);
643 } else if (kCFNumberFormatterAlwaysShowDecimalSeparatorKey
== key
) {
644 __CFGenericValidateType(value
, CFBooleanGetTypeID());
645 unum_setAttribute(formatter
->_nf
, UNUM_DECIMAL_ALWAYS_SHOWN
, (kCFBooleanTrue
== value
));
646 } else if (kCFNumberFormatterGroupingSeparatorKey
== key
) {
647 __CFGenericValidateType(value
, CFStringGetTypeID());
648 cnt
= CFStringGetLength((CFStringRef
)value
);
649 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
650 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
651 unum_setSymbol(formatter
->_nf
, UNUM_GROUPING_SEPARATOR_SYMBOL
, (const UChar
*)ubuffer
, cnt
, &status
);
652 } else if (kCFNumberFormatterUseGroupingSeparatorKey
== key
) {
653 __CFGenericValidateType(value
, CFBooleanGetTypeID());
654 unum_setAttribute(formatter
->_nf
, UNUM_GROUPING_USED
, (kCFBooleanTrue
== value
));
655 } else if (kCFNumberFormatterPercentSymbolKey
== key
) {
656 __CFGenericValidateType(value
, CFStringGetTypeID());
657 cnt
= CFStringGetLength((CFStringRef
)value
);
658 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
659 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
660 unum_setSymbol(formatter
->_nf
, UNUM_PERCENT_SYMBOL
, ubuffer
, cnt
, &status
);
661 } else if (kCFNumberFormatterZeroSymbolKey
== key
) {
662 __CFGenericValidateType(value
, CFStringGetTypeID());
663 CFStringRef old
= formatter
->_zeroSym
;
664 formatter
->_zeroSym
= value
? (CFStringRef
)CFRetain(value
) : NULL
;
665 if (old
) CFRelease(old
);
666 } else if (kCFNumberFormatterNaNSymbolKey
== key
) {
667 __CFGenericValidateType(value
, CFStringGetTypeID());
668 cnt
= CFStringGetLength((CFStringRef
)value
);
669 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
670 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
671 unum_setSymbol(formatter
->_nf
, UNUM_NAN_SYMBOL
, ubuffer
, cnt
, &status
);
672 } else if (kCFNumberFormatterInfinitySymbolKey
== key
) {
673 __CFGenericValidateType(value
, CFStringGetTypeID());
674 cnt
= CFStringGetLength((CFStringRef
)value
);
675 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
676 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
677 unum_setSymbol(formatter
->_nf
, UNUM_INFINITY_SYMBOL
, ubuffer
, cnt
, &status
);
678 } else if (kCFNumberFormatterMinusSignKey
== key
) {
679 __CFGenericValidateType(value
, CFStringGetTypeID());
680 cnt
= CFStringGetLength((CFStringRef
)value
);
681 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
682 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
683 unum_setSymbol(formatter
->_nf
, UNUM_MINUS_SIGN_SYMBOL
, ubuffer
, cnt
, &status
);
684 } else if (kCFNumberFormatterPlusSignKey
== key
) {
685 __CFGenericValidateType(value
, CFStringGetTypeID());
686 cnt
= CFStringGetLength((CFStringRef
)value
);
687 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
688 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
689 unum_setSymbol(formatter
->_nf
, UNUM_PLUS_SIGN_SYMBOL
, ubuffer
, cnt
, &status
);
690 } else if (kCFNumberFormatterCurrencySymbolKey
== key
) {
691 __CFGenericValidateType(value
, CFStringGetTypeID());
692 cnt
= CFStringGetLength((CFStringRef
)value
);
693 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
694 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
695 unum_setSymbol(formatter
->_nf
, UNUM_CURRENCY_SYMBOL
, (const UChar
*)ubuffer
, cnt
, &status
);
696 } else if (kCFNumberFormatterExponentSymbolKey
== key
) {
697 __CFGenericValidateType(value
, CFStringGetTypeID());
698 cnt
= CFStringGetLength((CFStringRef
)value
);
699 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
700 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
701 unum_setSymbol(formatter
->_nf
, UNUM_EXPONENTIAL_SYMBOL
, ubuffer
, cnt
, &status
);
702 } else if (kCFNumberFormatterMinIntegerDigitsKey
== key
) {
703 __CFGenericValidateType(value
, CFNumberGetTypeID());
704 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
705 unum_setAttribute(formatter
->_nf
, UNUM_MIN_INTEGER_DIGITS
, n
);
706 } else if (kCFNumberFormatterMaxIntegerDigitsKey
== key
) {
707 __CFGenericValidateType(value
, CFNumberGetTypeID());
708 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
709 unum_setAttribute(formatter
->_nf
, UNUM_MAX_INTEGER_DIGITS
, n
);
710 } else if (kCFNumberFormatterMinFractionDigitsKey
== key
) {
711 __CFGenericValidateType(value
, CFNumberGetTypeID());
712 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
713 unum_setAttribute(formatter
->_nf
, UNUM_MIN_FRACTION_DIGITS
, n
);
714 } else if (kCFNumberFormatterMaxFractionDigitsKey
== key
) {
715 __CFGenericValidateType(value
, CFNumberGetTypeID());
716 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
717 unum_setAttribute(formatter
->_nf
, UNUM_MAX_FRACTION_DIGITS
, n
);
718 } else if (kCFNumberFormatterGroupingSizeKey
== key
) {
719 __CFGenericValidateType(value
, CFNumberGetTypeID());
720 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
721 unum_setAttribute(formatter
->_nf
, UNUM_GROUPING_SIZE
, n
);
722 } else if (kCFNumberFormatterSecondaryGroupingSizeKey
== key
) {
723 __CFGenericValidateType(value
, CFNumberGetTypeID());
724 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
725 unum_setAttribute(formatter
->_nf
, UNUM_SECONDARY_GROUPING_SIZE
, n
);
726 } else if (kCFNumberFormatterRoundingModeKey
== key
) {
727 __CFGenericValidateType(value
, CFNumberGetTypeID());
728 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
729 unum_setAttribute(formatter
->_nf
, UNUM_ROUNDING_MODE
, n
);
730 } else if (kCFNumberFormatterRoundingIncrementKey
== key
) {
731 __CFGenericValidateType(value
, CFNumberGetTypeID());
732 CFNumberGetValue((CFNumberRef
)value
, kCFNumberDoubleType
, &d
);
733 unum_setDoubleAttribute(formatter
->_nf
, UNUM_ROUNDING_INCREMENT
, d
);
734 } else if (kCFNumberFormatterFormatWidthKey
== key
) {
735 __CFGenericValidateType(value
, CFNumberGetTypeID());
736 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
737 unum_setAttribute(formatter
->_nf
, UNUM_FORMAT_WIDTH
, n
);
738 } else if (kCFNumberFormatterPaddingPositionKey
== key
) {
739 __CFGenericValidateType(value
, CFNumberGetTypeID());
740 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
741 unum_setAttribute(formatter
->_nf
, UNUM_PADDING_POSITION
, n
);
742 } else if (kCFNumberFormatterPaddingCharacterKey
== key
) {
743 __CFGenericValidateType(value
, CFStringGetTypeID());
744 cnt
= CFStringGetLength((CFStringRef
)value
);
745 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
746 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
747 unum_setTextAttribute(formatter
->_nf
, UNUM_PADDING_CHARACTER
, ubuffer
, cnt
, &status
);
748 } else if (kCFNumberFormatterDefaultFormatKey
== key
) {
749 // read-only attribute
750 } else if (kCFNumberFormatterMultiplierKey
== key
) {
751 __CFGenericValidateType(value
, CFNumberGetTypeID());
752 CFNumberRef old
= formatter
->_multiplier
;
753 formatter
->_multiplier
= value
? (CFNumberRef
)CFRetain(value
) : NULL
;
754 formatter
->_userSetMultiplier
= value
? true : false;
755 if (old
) CFRelease(old
);
756 } else if (kCFNumberFormatterPositivePrefixKey
== key
) {
757 __CFGenericValidateType(value
, CFStringGetTypeID());
758 cnt
= CFStringGetLength((CFStringRef
)value
);
759 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
760 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
761 unum_setTextAttribute(formatter
->_nf
, UNUM_POSITIVE_PREFIX
, ubuffer
, cnt
, &status
);
762 } else if (kCFNumberFormatterPositiveSuffixKey
== key
) {
763 __CFGenericValidateType(value
, CFStringGetTypeID());
764 cnt
= CFStringGetLength((CFStringRef
)value
);
765 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
766 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
767 unum_setTextAttribute(formatter
->_nf
, UNUM_POSITIVE_SUFFIX
, (const UChar
*)ubuffer
, cnt
, &status
);
768 } else if (kCFNumberFormatterNegativePrefixKey
== key
) {
769 __CFGenericValidateType(value
, CFStringGetTypeID());
770 cnt
= CFStringGetLength((CFStringRef
)value
);
771 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
772 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
773 unum_setTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, cnt
, &status
);
774 } else if (kCFNumberFormatterNegativeSuffixKey
== key
) {
775 __CFGenericValidateType(value
, CFStringGetTypeID());
776 cnt
= CFStringGetLength((CFStringRef
)value
);
777 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
778 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
779 unum_setTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_SUFFIX
, (const UChar
*)ubuffer
, cnt
, &status
);
780 } else if (kCFNumberFormatterPerMillSymbolKey
== key
) {
781 __CFGenericValidateType(value
, CFStringGetTypeID());
782 cnt
= CFStringGetLength((CFStringRef
)value
);
783 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
784 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
785 unum_setSymbol(formatter
->_nf
, UNUM_PERMILL_SYMBOL
, ubuffer
, cnt
, &status
);
786 } else if (kCFNumberFormatterInternationalCurrencySymbolKey
== key
) {
787 __CFGenericValidateType(value
, CFStringGetTypeID());
788 cnt
= CFStringGetLength((CFStringRef
)value
);
789 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
790 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
791 unum_setSymbol(formatter
->_nf
, UNUM_INTL_CURRENCY_SYMBOL
, ubuffer
, cnt
, &status
);
792 } else if (kCFNumberFormatterCurrencyGroupingSeparatorKey
== key
) {
793 __CFGenericValidateType(value
, CFStringGetTypeID());
794 cnt
= CFStringGetLength((CFStringRef
)value
);
795 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
796 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
797 unum_setSymbol(formatter
->_nf
, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL
, ubuffer
, cnt
, &status
);
798 } else if (kCFNumberFormatterIsLenientKey
== key
) {
799 __CFGenericValidateType(value
, CFBooleanGetTypeID());
800 formatter
->_isLenient
= (kCFBooleanTrue
== value
);
801 unum_setAttribute(formatter
->_nf
, UNUM_LENIENT_PARSE
, (kCFBooleanTrue
== value
));
802 } else if (kCFNumberFormatterUseSignificantDigitsKey
== key
) {
803 __CFGenericValidateType(value
, CFBooleanGetTypeID());
804 unum_setAttribute(formatter
->_nf
, UNUM_SIGNIFICANT_DIGITS_USED
, (kCFBooleanTrue
== value
));
805 } else if (kCFNumberFormatterMinSignificantDigitsKey
== key
) {
806 __CFGenericValidateType(value
, CFNumberGetTypeID());
807 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
808 unum_setAttribute(formatter
->_nf
, UNUM_MIN_SIGNIFICANT_DIGITS
, n
);
809 } else if (kCFNumberFormatterMaxSignificantDigitsKey
== key
) {
810 __CFGenericValidateType(value
, CFNumberGetTypeID());
811 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
812 unum_setAttribute(formatter
->_nf
, UNUM_MAX_SIGNIFICANT_DIGITS
, n
);
814 CFAssert3(0, __kCFLogAssertion
, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__
, key
, key
);
816 if (_CFExecutableLinkedOnOrAfter(CFSystemVersionSnowLeopard
)) {
817 // do a dummy call to CFNumberFormatterGetFormat() after changing an attribute because
818 // ICU sometimes changes the pattern due to a property change, and we need to poke
819 // unum_toPattern() and also update our own variables
820 CFNumberFormatterGetFormat(formatter
);
824 CFTypeRef
CFNumberFormatterCopyProperty(CFNumberFormatterRef formatter
, CFStringRef key
) {
827 UErrorCode status
= U_ZERO_ERROR
;
828 UChar ubuffer
[BUFFER_SIZE
];
830 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
831 __CFGenericValidateType(key
, CFStringGetTypeID());
832 if (kCFNumberFormatterCurrencyCodeKey
== key
) {
833 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_CURRENCY_CODE
, ubuffer
, BUFFER_SIZE
, &status
);
834 if (U_SUCCESS(status
) && cnt
== 0) {
835 CFStringRef localeName
= CFLocaleGetIdentifier(formatter
->_locale
);
836 char buffer
[BUFFER_SIZE
];
837 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
839 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
844 UErrorCode status
= U_ZERO_ERROR
;
845 UNumberFormat
*nf
= unum_open(UNUM_CURRENCY
, NULL
, 0, cstr
, NULL
, &status
);
847 cnt
= unum_getTextAttribute(nf
, UNUM_CURRENCY_CODE
, ubuffer
, BUFFER_SIZE
, &status
);
851 if (U_SUCCESS(status
) && 0 < cnt
&& cnt
<= BUFFER_SIZE
) {
852 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
854 } else if (kCFNumberFormatterDecimalSeparatorKey
== key
) {
855 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_DECIMAL_SEPARATOR_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
856 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
857 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
859 } else if (kCFNumberFormatterCurrencyDecimalSeparatorKey
== key
) {
860 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_MONETARY_SEPARATOR_SYMBOL
, (UChar
*)ubuffer
, BUFFER_SIZE
, &status
);
861 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
862 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
864 } else if (kCFNumberFormatterAlwaysShowDecimalSeparatorKey
== key
) {
865 n
= unum_getAttribute(formatter
->_nf
, UNUM_DECIMAL_ALWAYS_SHOWN
);
867 return CFRetain(n
? kCFBooleanTrue
: kCFBooleanFalse
);
869 } else if (kCFNumberFormatterGroupingSeparatorKey
== key
) {
870 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_GROUPING_SEPARATOR_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
871 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
872 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
874 } else if (kCFNumberFormatterUseGroupingSeparatorKey
== key
) {
875 n
= unum_getAttribute(formatter
->_nf
, UNUM_GROUPING_USED
);
877 return CFRetain(n
? kCFBooleanTrue
: kCFBooleanFalse
);
879 } else if (kCFNumberFormatterPercentSymbolKey
== key
) {
880 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_PERCENT_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
881 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
882 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
884 } else if (kCFNumberFormatterZeroSymbolKey
== key
) {
885 return formatter
->_zeroSym
? CFRetain(formatter
->_zeroSym
) : NULL
;
886 } else if (kCFNumberFormatterNaNSymbolKey
== key
) {
887 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_NAN_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
888 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
889 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
891 } else if (kCFNumberFormatterInfinitySymbolKey
== key
) {
892 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_INFINITY_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
893 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
894 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
896 } else if (kCFNumberFormatterMinusSignKey
== key
) {
897 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_MINUS_SIGN_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
898 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
899 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
901 } else if (kCFNumberFormatterPlusSignKey
== key
) {
902 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_PLUS_SIGN_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
903 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
904 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
906 } else if (kCFNumberFormatterCurrencySymbolKey
== key
) {
907 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_CURRENCY_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
908 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
909 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
911 } else if (kCFNumberFormatterExponentSymbolKey
== key
) {
912 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_EXPONENTIAL_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
913 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
914 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
916 } else if (kCFNumberFormatterMinIntegerDigitsKey
== key
) {
917 n
= unum_getAttribute(formatter
->_nf
, UNUM_MIN_INTEGER_DIGITS
);
919 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
921 } else if (kCFNumberFormatterMaxIntegerDigitsKey
== key
) {
922 n
= unum_getAttribute(formatter
->_nf
, UNUM_MAX_INTEGER_DIGITS
);
924 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
926 } else if (kCFNumberFormatterMinFractionDigitsKey
== key
) {
927 n
= unum_getAttribute(formatter
->_nf
, UNUM_MIN_FRACTION_DIGITS
);
929 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
931 } else if (kCFNumberFormatterMaxFractionDigitsKey
== key
) {
932 n
= unum_getAttribute(formatter
->_nf
, UNUM_MAX_FRACTION_DIGITS
);
934 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
936 } else if (kCFNumberFormatterGroupingSizeKey
== key
) {
937 n
= unum_getAttribute(formatter
->_nf
, UNUM_GROUPING_SIZE
);
939 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
941 } else if (kCFNumberFormatterSecondaryGroupingSizeKey
== key
) {
942 n
= unum_getAttribute(formatter
->_nf
, UNUM_SECONDARY_GROUPING_SIZE
);
944 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
946 } else if (kCFNumberFormatterRoundingModeKey
== key
) {
947 n
= unum_getAttribute(formatter
->_nf
, UNUM_ROUNDING_MODE
);
949 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
951 } else if (kCFNumberFormatterRoundingIncrementKey
== key
) {
952 d
= unum_getDoubleAttribute(formatter
->_nf
, UNUM_ROUNDING_INCREMENT
);
954 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberDoubleType
, &d
);
956 } else if (kCFNumberFormatterFormatWidthKey
== key
) {
957 n
= unum_getAttribute(formatter
->_nf
, UNUM_FORMAT_WIDTH
);
959 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
961 } else if (kCFNumberFormatterPaddingPositionKey
== key
) {
962 n
= unum_getAttribute(formatter
->_nf
, UNUM_PADDING_POSITION
);
964 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
966 } else if (kCFNumberFormatterPaddingCharacterKey
== key
) {
967 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_PADDING_CHARACTER
, ubuffer
, BUFFER_SIZE
, &status
);
968 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
969 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
971 } else if (kCFNumberFormatterDefaultFormatKey
== key
) {
972 return formatter
->_defformat
? CFRetain(formatter
->_defformat
) : NULL
;
973 } else if (kCFNumberFormatterMultiplierKey
== key
) {
974 return formatter
->_multiplier
? CFRetain(formatter
->_multiplier
) : NULL
;
975 } else if (kCFNumberFormatterPositivePrefixKey
== key
) {
976 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_POSITIVE_PREFIX
, ubuffer
, BUFFER_SIZE
, &status
);
977 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
978 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
980 } else if (kCFNumberFormatterPositiveSuffixKey
== key
) {
981 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_POSITIVE_SUFFIX
, ubuffer
, BUFFER_SIZE
, &status
);
982 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
983 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
985 } else if (kCFNumberFormatterNegativePrefixKey
== key
) {
986 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, BUFFER_SIZE
, &status
);
987 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
988 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
990 } else if (kCFNumberFormatterNegativeSuffixKey
== key
) {
991 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_SUFFIX
, ubuffer
, BUFFER_SIZE
, &status
);
992 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
993 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
995 } else if (kCFNumberFormatterPerMillSymbolKey
== key
) {
996 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_PERMILL_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
997 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
998 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1000 } else if (kCFNumberFormatterInternationalCurrencySymbolKey
== key
) {
1001 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_INTL_CURRENCY_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1002 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1003 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1005 } else if (kCFNumberFormatterCurrencyGroupingSeparatorKey
== key
) {
1006 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1007 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1008 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1010 } else if (kCFNumberFormatterIsLenientKey
== key
) {
1011 // unum_getAttribute(, UNUM_LENIENT_PARSE) is undefined.
1012 return CFRetain(formatter
->_isLenient
? kCFBooleanTrue
: kCFBooleanFalse
);
1013 } else if (kCFNumberFormatterUseSignificantDigitsKey
== key
) {
1014 n
= unum_getAttribute(formatter
->_nf
, UNUM_SIGNIFICANT_DIGITS_USED
);
1016 return CFRetain(n
? kCFBooleanTrue
: kCFBooleanFalse
);
1018 } else if (kCFNumberFormatterMinSignificantDigitsKey
== key
) {
1019 n
= unum_getAttribute(formatter
->_nf
, UNUM_MIN_SIGNIFICANT_DIGITS
);
1021 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1023 } else if (kCFNumberFormatterMaxSignificantDigitsKey
== key
) {
1024 n
= unum_getAttribute(formatter
->_nf
, UNUM_MAX_SIGNIFICANT_DIGITS
);
1026 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1029 CFAssert3(0, __kCFLogAssertion
, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__
, key
, key
);
1035 Boolean
CFNumberFormatterGetDecimalInfoForCurrencyCode(CFStringRef currencyCode
, int32_t *defaultFractionDigits
, double *roundingIncrement
) {
1037 __CFGenericValidateType(currencyCode
, CFStringGetTypeID());
1038 CFAssert1(3 == CFStringGetLength(currencyCode
), __kCFLogAssertion
, "%s(): currencyCode is not 3 characters", __PRETTY_FUNCTION__
);
1039 CFStringGetCharacters(currencyCode
, CFRangeMake(0, 3), (UniChar
*)ubuffer
);
1041 UErrorCode icuStatus
= U_ZERO_ERROR
;
1042 if (defaultFractionDigits
) *defaultFractionDigits
= ucurr_getDefaultFractionDigits(ubuffer
, &icuStatus
);
1043 if (roundingIncrement
) *roundingIncrement
= ucurr_getRoundingIncrement(ubuffer
, &icuStatus
);
1044 if (U_FAILURE(icuStatus
))
1046 return (!defaultFractionDigits
|| 0 <= *defaultFractionDigits
) && (!roundingIncrement
|| 0.0 <= *roundingIncrement
);