2 * Copyright (c) 2012 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 /* CFNumberFormatter.c
25 Copyright (c) 2002-2011, Apple Inc. All rights reserved.
26 Responsibility: David Smith
29 #include <CoreFoundation/CFNumberFormatter.h>
30 #include <CoreFoundation/ForFoundationOnly.h>
31 #include "CFInternal.h"
32 #include "CFLocaleInternal.h"
33 #include <unicode/unum.h>
34 #include <unicode/ucurr.h>
38 static void __CFNumberFormatterCustomize(CFNumberFormatterRef formatter
);
39 static CFStringRef
__CFNumberFormatterCreateCompressedString(CFStringRef inString
, Boolean isFormat
, CFRange
*rangep
);
40 static UErrorCode
__CFNumberFormatterApplyPattern(CFNumberFormatterRef formatter
, CFStringRef pattern
);
42 #define BUFFER_SIZE 768
44 struct __CFNumberFormatter
{
48 CFNumberFormatterStyle _style
;
49 CFStringRef _format
; // NULL for RBNFs
50 CFStringRef _defformat
;
51 CFStringRef _compformat
;
52 CFNumberRef _multiplier
;
55 Boolean _userSetMultiplier
;
58 static CFStringRef
__CFNumberFormatterCopyDescription(CFTypeRef cf
) {
59 CFNumberFormatterRef formatter
= (CFNumberFormatterRef
)cf
;
60 return CFStringCreateWithFormat(CFGetAllocator(formatter
), NULL
, CFSTR("<CFNumberFormatter %p [%p]>"), cf
, CFGetAllocator(formatter
));
63 static void __CFNumberFormatterDeallocate(CFTypeRef cf
) {
64 CFNumberFormatterRef formatter
= (CFNumberFormatterRef
)cf
;
65 if (formatter
->_nf
) unum_close(formatter
->_nf
);
66 if (formatter
->_locale
) CFRelease(formatter
->_locale
);
67 if (formatter
->_format
) CFRelease(formatter
->_format
);
68 if (formatter
->_defformat
) CFRelease(formatter
->_defformat
);
69 if (formatter
->_compformat
) CFRelease(formatter
->_compformat
);
70 if (formatter
->_multiplier
) CFRelease(formatter
->_multiplier
);
71 if (formatter
->_zeroSym
) CFRelease(formatter
->_zeroSym
);
74 static CFTypeID __kCFNumberFormatterTypeID
= _kCFRuntimeNotATypeID
;
76 static const CFRuntimeClass __CFNumberFormatterClass
= {
81 __CFNumberFormatterDeallocate
,
85 __CFNumberFormatterCopyDescription
88 static void __CFNumberFormatterInitialize(void) {
89 __kCFNumberFormatterTypeID
= _CFRuntimeRegisterClass(&__CFNumberFormatterClass
);
92 CFTypeID
CFNumberFormatterGetTypeID(void) {
93 if (_kCFRuntimeNotATypeID
== __kCFNumberFormatterTypeID
) __CFNumberFormatterInitialize();
94 return __kCFNumberFormatterTypeID
;
97 CFNumberFormatterRef
CFNumberFormatterCreate(CFAllocatorRef allocator
, CFLocaleRef locale
, CFNumberFormatterStyle style
) {
98 struct __CFNumberFormatter
*memory
;
99 uint32_t size
= sizeof(struct __CFNumberFormatter
) - sizeof(CFRuntimeBase
);
100 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
101 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
102 __CFGenericValidateType(locale
, CFLocaleGetTypeID());
103 memory
= (struct __CFNumberFormatter
*)_CFRuntimeCreateInstance(allocator
, CFNumberFormatterGetTypeID(), size
, NULL
);
104 if (NULL
== memory
) {
108 memory
->_locale
= NULL
;
109 memory
->_format
= NULL
;
110 memory
->_defformat
= NULL
;
111 memory
->_compformat
= NULL
;
112 memory
->_multiplier
= NULL
;
113 memory
->_zeroSym
= NULL
;
114 memory
->_isLenient
= false;
115 memory
->_userSetMultiplier
= false;
116 if (NULL
== locale
) locale
= CFLocaleGetSystem();
117 memory
->_style
= style
;
120 case kCFNumberFormatterNoStyle
: ustyle
= UNUM_IGNORE
; break;
121 case kCFNumberFormatterDecimalStyle
: ustyle
= UNUM_DECIMAL
; break;
122 case kCFNumberFormatterCurrencyStyle
: ustyle
= UNUM_CURRENCY
; break;
123 case kCFNumberFormatterPercentStyle
: ustyle
= UNUM_PERCENT
; break;
124 case kCFNumberFormatterScientificStyle
: ustyle
= UNUM_SCIENTIFIC
; break;
125 case kCFNumberFormatterSpellOutStyle
: ustyle
= UNUM_SPELLOUT
; break;
126 case kCFNumberFormatterOrdinalStyle
: ustyle
= UNUM_ORDINAL
; break;
127 case kCFNumberFormatterDurationStyle
: ustyle
= UNUM_DURATION
; break;
129 CFAssert2(0, __kCFLogAssertion
, "%s(): unknown style %d", __PRETTY_FUNCTION__
, style
);
130 ustyle
= UNUM_DECIMAL
;
131 memory
->_style
= kCFNumberFormatterDecimalStyle
;
134 CFStringRef localeName
= locale
? CFLocaleGetIdentifier(locale
) : CFSTR("");
135 char buffer
[BUFFER_SIZE
];
136 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
138 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
144 UErrorCode status
= U_ZERO_ERROR
;
145 memory
->_nf
= unum_open((UNumberFormatStyle
)ustyle
, NULL
, 0, cstr
, NULL
, &status
);
146 CFAssert2(memory
->_nf
, __kCFLogAssertion
, "%s(): error (%d) creating number formatter", __PRETTY_FUNCTION__
, status
);
147 if (NULL
== memory
->_nf
) {
152 if (kCFNumberFormatterNoStyle
== style
) {
153 status
= U_ZERO_ERROR
;
154 ubuff
[0] = '#'; ubuff
[1] = ';'; ubuff
[2] = '#';
155 unum_applyPattern(memory
->_nf
, false, ubuff
, 3, NULL
, &status
);
156 unum_setAttribute(memory
->_nf
, UNUM_MAX_INTEGER_DIGITS
, 42);
157 unum_setAttribute(memory
->_nf
, UNUM_MAX_FRACTION_DIGITS
, 0);
159 memory
->_locale
= locale
? CFLocaleCreateCopy(allocator
, locale
) : CFLocaleGetSystem();
160 __CFNumberFormatterCustomize(memory
);
161 if (kCFNumberFormatterSpellOutStyle
!= memory
->_style
&& kCFNumberFormatterOrdinalStyle
!= memory
->_style
&& kCFNumberFormatterDurationStyle
!= memory
->_style
) {
162 UChar ubuffer
[BUFFER_SIZE
];
163 status
= U_ZERO_ERROR
;
164 int32_t ret
= unum_toPattern(memory
->_nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
165 if (U_SUCCESS(status
) && ret
<= BUFFER_SIZE
) {
166 memory
->_format
= CFStringCreateWithCharacters(allocator
, (const UniChar
*)ubuffer
, ret
);
169 memory
->_defformat
= memory
->_format
? (CFStringRef
)CFRetain(memory
->_format
) : NULL
;
170 memory
->_compformat
= memory
->_format
? __CFNumberFormatterCreateCompressedString(memory
->_format
, true, NULL
) : NULL
;
171 if (kCFNumberFormatterSpellOutStyle
!= memory
->_style
&& kCFNumberFormatterOrdinalStyle
!= memory
->_style
&& kCFNumberFormatterDurationStyle
!= memory
->_style
) {
172 int32_t n
= unum_getAttribute(memory
->_nf
, UNUM_MULTIPLIER
);
174 memory
->_multiplier
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, &n
);
175 unum_setAttribute(memory
->_nf
, UNUM_MULTIPLIER
, 1);
178 unum_setAttribute(memory
->_nf
, UNUM_LENIENT_PARSE
, 0);
179 return (CFNumberFormatterRef
)memory
;
182 extern CFDictionaryRef
__CFLocaleGetPrefs(CFLocaleRef locale
);
184 static void __substituteFormatStringFromPrefsNF(CFNumberFormatterRef formatter
) {
185 CFIndex formatStyle
= formatter
->_style
;
186 if (kCFNumberFormatterSpellOutStyle
== formatStyle
) return;
187 if (kCFNumberFormatterOrdinalStyle
== formatStyle
) return;
188 if (kCFNumberFormatterDurationStyle
== formatStyle
) return;
189 CFStringRef prefName
= CFSTR("AppleICUNumberFormatStrings");
190 if (kCFNumberFormatterNoStyle
!= formatStyle
) {
191 CFStringRef pref
= NULL
;
192 CFDictionaryRef prefs
= __CFLocaleGetPrefs(formatter
->_locale
);
193 CFPropertyListRef metapref
= prefs
? CFDictionaryGetValue(prefs
, prefName
) : NULL
;
194 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
196 switch (formatStyle
) {
197 case kCFNumberFormatterDecimalStyle
: key
= CFSTR("1"); break;
198 case kCFNumberFormatterCurrencyStyle
: key
= CFSTR("2"); break;
199 case kCFNumberFormatterPercentStyle
: key
= CFSTR("3"); break;
200 case kCFNumberFormatterScientificStyle
: key
= CFSTR("4"); break;
201 case kCFNumberFormatterSpellOutStyle
: key
= CFSTR("5"); break;
202 case kCFNumberFormatterOrdinalStyle
: key
= CFSTR("6"); break;
203 case kCFNumberFormatterDurationStyle
: key
= CFSTR("7"); break;
204 default: key
= CFSTR("0"); break;
206 pref
= (CFStringRef
)CFDictionaryGetValue((CFDictionaryRef
)metapref
, key
);
208 if (NULL
!= pref
&& CFGetTypeID(pref
) == CFStringGetTypeID()) {
209 int32_t icustyle
= UNUM_IGNORE
;
210 switch (formatStyle
) {
211 case kCFNumberFormatterDecimalStyle
: icustyle
= UNUM_DECIMAL
; break;
212 case kCFNumberFormatterCurrencyStyle
: icustyle
= UNUM_CURRENCY
; break;
213 case kCFNumberFormatterPercentStyle
: icustyle
= UNUM_PERCENT
; break;
214 case kCFNumberFormatterScientificStyle
: icustyle
= UNUM_SCIENTIFIC
; break;
215 case kCFNumberFormatterSpellOutStyle
: icustyle
= UNUM_SPELLOUT
; break;
216 case kCFNumberFormatterOrdinalStyle
: icustyle
= UNUM_ORDINAL
; break;
217 case kCFNumberFormatterDurationStyle
: icustyle
= UNUM_DURATION
; break;
219 CFStringRef localeName
= CFLocaleGetIdentifier(formatter
->_locale
);
220 char buffer
[BUFFER_SIZE
];
221 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
223 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
225 UErrorCode status
= U_ZERO_ERROR
;
226 UNumberFormat
*nf
= unum_open((UNumberFormatStyle
)icustyle
, NULL
, 0, cstr
, NULL
, &status
);
228 UChar ubuffer
[BUFFER_SIZE
];
229 status
= U_ZERO_ERROR
;
230 int32_t number_len
= unum_toPattern(nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
231 if (U_SUCCESS(status
) && number_len
<= BUFFER_SIZE
) {
232 CFStringRef numberString
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)ubuffer
, number_len
);
233 status
= U_ZERO_ERROR
;
234 int32_t formatter_len
= unum_toPattern(formatter
->_nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
235 if (U_SUCCESS(status
) && formatter_len
<= BUFFER_SIZE
) {
236 CFMutableStringRef formatString
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
237 CFStringAppendCharacters(formatString
, (const UniChar
*)ubuffer
, formatter_len
);
238 // find numberString inside formatString, substitute the pref in that range
240 if (CFStringFindWithOptions(formatString
, numberString
, CFRangeMake(0, formatter_len
), 0, &result
)) {
241 CFStringReplace(formatString
, result
, pref
);
242 __CFNumberFormatterApplyPattern(formatter
, formatString
);
244 CFRelease(formatString
);
246 CFRelease(numberString
);
254 static UniChar
__CFNumberFormatterNormalizeCharacter(UniChar c
) {
255 if (CFCharacterSetIsCharacterMember(CFCharacterSetGetPredefined(kCFCharacterSetWhitespace
), c
)) {
262 /* 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. */
263 static CFStringRef
__CFNumberFormatterCreateCompressedString(CFStringRef inString
, Boolean isFormat
, CFRange
*rangep
) {
264 if (!inString
) return NULL
;
265 CFRange range
= { 0, 0 };
269 range
.length
= CFStringGetLength(inString
);
271 CFMutableStringRef outString
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
272 CFCharacterSetRef letters
= CFCharacterSetGetPredefined(kCFCharacterSetLetter
);
273 CFCharacterSetRef numbers
= CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
);
274 UniChar prevCh
= 0, nextCh
= 0;
275 Boolean inQuote
= false;
276 for (CFIndex in_idx
= range
.location
; in_idx
< range
.location
+ range
.length
; in_idx
++) {
277 UniChar ch
= __CFNumberFormatterNormalizeCharacter(CFStringGetCharacterAtIndex(inString
, in_idx
));
278 nextCh
= (in_idx
+1 < range
.length
) ? CFStringGetCharacterAtIndex(inString
, in_idx
+1) : 0;
279 if (isFormat
&& ch
== '\'') inQuote
= !inQuote
;
280 if (inQuote
|| ch
!= ' ' || (CFCharacterSetIsCharacterMember(letters
, prevCh
) && CFCharacterSetIsCharacterMember(letters
, nextCh
)) || (CFCharacterSetIsCharacterMember(numbers
, prevCh
) && CFCharacterSetIsCharacterMember(numbers
, nextCh
))) {
281 CFStringAppendCharacters(outString
, &ch
, 1);
288 // Should not be called for rule-based ICU formatters; not supported
289 static void __CFNumberFormatterApplySymbolPrefs(const void *key
, const void *value
, void *context
) {
290 if (CFGetTypeID(key
) == CFStringGetTypeID() && CFGetTypeID(value
) == CFStringGetTypeID()) {
291 CFNumberFormatterRef formatter
= (CFNumberFormatterRef
)context
;
292 UNumberFormatSymbol sym
= (UNumberFormatSymbol
)CFStringGetIntValue((CFStringRef
)key
);
293 CFStringRef item
= (CFStringRef
)value
;
294 CFIndex item_cnt
= CFStringGetLength(item
);
295 STACK_BUFFER_DECL(UChar
, item_buffer
, item_cnt
);
296 UChar
*item_ustr
= (UChar
*)CFStringGetCharactersPtr(item
);
297 if (NULL
== item_ustr
) {
298 CFStringGetCharacters(item
, CFRangeMake(0, __CFMin(BUFFER_SIZE
, item_cnt
)), (UniChar
*)item_buffer
);
299 item_ustr
= item_buffer
;
301 UErrorCode status
= U_ZERO_ERROR
;
302 unum_setSymbol(formatter
->_nf
, sym
, item_ustr
, item_cnt
, &status
);
306 // Should not be called for rule-based ICU formatters
307 static UErrorCode
__CFNumberFormatterApplyPattern(CFNumberFormatterRef formatter
, CFStringRef pattern
) {
308 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
) return U_UNSUPPORTED_ERROR
;
309 if (kCFNumberFormatterOrdinalStyle
== formatter
->_style
) return U_UNSUPPORTED_ERROR
;
310 if (kCFNumberFormatterDurationStyle
== formatter
->_style
) return U_UNSUPPORTED_ERROR
;
311 CFIndex cnt
= CFStringGetLength(pattern
);
312 STACK_BUFFER_DECL(UChar
, ubuffer
, cnt
);
313 const UChar
*ustr
= (const UChar
*)CFStringGetCharactersPtr(pattern
);
315 CFStringGetCharacters(pattern
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
318 UErrorCode status
= U_ZERO_ERROR
;
319 unum_applyPattern(formatter
->_nf
, false, ustr
, cnt
, NULL
, &status
);
321 // unum_applyPattern() may have magically changed other attributes based on
322 // the contents of the format string; we simply expose that ICU behavior, except
323 // for UNUM_MULTIPLIER, which we re-read and reset, like we did at initialization
324 // time though any user-set multiplier state takes precedence.
325 if (formatter
->_userSetMultiplier
) {
326 unum_setAttribute(formatter
->_nf
, UNUM_MULTIPLIER
, 1);
328 if (formatter
->_multiplier
) CFRelease(formatter
->_multiplier
);
329 formatter
->_multiplier
= NULL
;
330 int32_t n
= unum_getAttribute(formatter
->_nf
, UNUM_MULTIPLIER
);
332 formatter
->_multiplier
= CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
333 unum_setAttribute(formatter
->_nf
, UNUM_MULTIPLIER
, 1);
339 static void __CFNumberFormatterCustomize(CFNumberFormatterRef formatter
) {
340 __substituteFormatStringFromPrefsNF(formatter
);
341 CFDictionaryRef prefs
= __CFLocaleGetPrefs(formatter
->_locale
);
342 CFPropertyListRef metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleICUNumberSymbols")) : NULL
;
343 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
344 CFDictionaryApplyFunction((CFDictionaryRef
)metapref
, __CFNumberFormatterApplySymbolPrefs
, formatter
);
348 CFLocaleRef
CFNumberFormatterGetLocale(CFNumberFormatterRef formatter
) {
349 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
350 return formatter
->_locale
;
353 CFNumberFormatterStyle
CFNumberFormatterGetStyle(CFNumberFormatterRef formatter
) {
354 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
355 return formatter
->_style
;
358 CFStringRef
CFNumberFormatterGetFormat(CFNumberFormatterRef formatter
) {
359 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
360 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
) return NULL
;
361 if (kCFNumberFormatterOrdinalStyle
== formatter
->_style
) return NULL
;
362 if (kCFNumberFormatterDurationStyle
== formatter
->_style
) return NULL
;
363 UChar ubuffer
[BUFFER_SIZE
];
364 CFStringRef newString
= NULL
;
365 UErrorCode status
= U_ZERO_ERROR
;
366 int32_t ret
= unum_toPattern(formatter
->_nf
, false, ubuffer
, BUFFER_SIZE
, &status
);
367 if (U_SUCCESS(status
) && ret
<= BUFFER_SIZE
) {
368 newString
= CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, ret
);
370 if (newString
&& !formatter
->_format
) {
371 formatter
->_format
= newString
;
372 if (formatter
->_compformat
) CFRelease(formatter
->_compformat
);
373 formatter
->_compformat
= __CFNumberFormatterCreateCompressedString(formatter
->_format
, true, NULL
);
374 } else if (newString
&& !CFEqual(newString
, formatter
->_format
)) {
375 CFRelease(formatter
->_format
);
376 formatter
->_format
= newString
;
377 if (formatter
->_compformat
) CFRelease(formatter
->_compformat
);
378 formatter
->_compformat
= __CFNumberFormatterCreateCompressedString(formatter
->_format
, true, NULL
);
379 } else if (newString
) {
380 CFRelease(newString
);
382 return formatter
->_format
;
385 void CFNumberFormatterSetFormat(CFNumberFormatterRef formatter
, CFStringRef formatString
) {
386 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
387 __CFGenericValidateType(formatString
, CFStringGetTypeID());
388 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
) return;
389 if (kCFNumberFormatterOrdinalStyle
== formatter
->_style
) return;
390 if (kCFNumberFormatterDurationStyle
== formatter
->_style
) return;
391 CFIndex cnt
= CFStringGetLength(formatString
);
392 CFAssert1(cnt
<= 1024, __kCFLogAssertion
, "%s(): format string too long", __PRETTY_FUNCTION__
);
393 if ((!formatter
->_format
|| !CFEqual(formatter
->_format
, formatString
)) && cnt
<= 1024) {
394 UErrorCode status
= __CFNumberFormatterApplyPattern(formatter
, formatString
);
395 if (U_SUCCESS(status
)) {
396 UChar ubuffer2
[BUFFER_SIZE
];
397 status
= U_ZERO_ERROR
;
398 int32_t ret
= unum_toPattern(formatter
->_nf
, false, ubuffer2
, BUFFER_SIZE
, &status
);
399 if (U_SUCCESS(status
) && ret
<= BUFFER_SIZE
) {
400 if (formatter
->_format
) CFRelease(formatter
->_format
);
401 formatter
->_format
= CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer2
, ret
);
402 if (formatter
->_compformat
) CFRelease(formatter
->_compformat
);
403 formatter
->_compformat
= __CFNumberFormatterCreateCompressedString(formatter
->_format
, true, NULL
);
409 CFStringRef
CFNumberFormatterCreateStringWithNumber(CFAllocatorRef allocator
, CFNumberFormatterRef formatter
, CFNumberRef number
) {
410 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
411 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
412 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
413 __CFGenericValidateType(number
, CFNumberGetTypeID());
414 CFNumberType type
= CFNumberGetType(number
);
416 CFNumberGetValue(number
, type
, buffer
);
417 return CFNumberFormatterCreateStringWithValue(allocator
, formatter
, type
, buffer
);
420 #define FORMAT(T, FUNC) \
421 T value = *(T *)valuePtr; \
422 if (0 == value && formatter->_zeroSym) { return (CFStringRef)CFRetain(formatter->_zeroSym); } \
423 if (1.0 != multiplier) { \
425 if (modf(multiplier, &dummy) < FLT_EPSILON) { /* float epsilon specifically chosen cuz it is a bit bigger */ \
426 value = value * (T)floor(multiplier); \
428 value = (T)(value * multiplier); \
431 status = U_ZERO_ERROR; \
432 used = FUNC(formatter->_nf, value, ubuffer, cnt, NULL, &status); \
433 if (status == U_BUFFER_OVERFLOW_ERROR || cnt < used) { \
435 ustr = (UChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UChar) * cnt, 0); \
436 status = U_ZERO_ERROR; \
437 used = FUNC(formatter->_nf, value, ustr, cnt, NULL, &status); \
440 CFStringRef
CFNumberFormatterCreateStringWithValue(CFAllocatorRef allocator
, CFNumberFormatterRef formatter
, CFNumberType numberType
, const void *valuePtr
) {
441 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
442 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
443 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
444 double multiplier
= 1.0;
445 if (formatter
->_multiplier
) {
446 if (!CFNumberGetValue(formatter
->_multiplier
, kCFNumberFloat64Type
, &multiplier
)) {
450 UChar
*ustr
= NULL
, ubuffer
[BUFFER_SIZE
];
451 UErrorCode status
= U_ZERO_ERROR
;
452 CFIndex used
, cnt
= BUFFER_SIZE
;
453 if (numberType
== kCFNumberFloat64Type
|| numberType
== kCFNumberDoubleType
) {
454 FORMAT(double, unum_formatDouble
)
455 } else if (numberType
== kCFNumberFloat32Type
|| numberType
== kCFNumberFloatType
) {
456 FORMAT(float, unum_formatDouble
)
457 } else if (numberType
== kCFNumberSInt64Type
|| numberType
== kCFNumberLongLongType
) {
458 FORMAT(int64_t, unum_formatInt64
)
459 } else if (numberType
== kCFNumberLongType
|| numberType
== kCFNumberCFIndexType
) {
461 FORMAT(int64_t, unum_formatInt64
)
463 FORMAT(int32_t, unum_formatInt64
)
465 } else if (numberType
== kCFNumberSInt32Type
|| numberType
== kCFNumberIntType
) {
466 FORMAT(int32_t, unum_formatInt64
)
467 } else if (numberType
== kCFNumberSInt16Type
|| numberType
== kCFNumberShortType
) {
468 FORMAT(int16_t, unum_formatInt64
)
469 } else if (numberType
== kCFNumberSInt8Type
|| numberType
== kCFNumberCharType
) {
470 FORMAT(int8_t, unum_formatInt64
)
472 CFAssert2(0, __kCFLogAssertion
, "%s(): unknown CFNumberType (%d)", __PRETTY_FUNCTION__
, numberType
);
475 CFStringRef string
= NULL
;
476 if (U_SUCCESS(status
)) {
477 string
= CFStringCreateWithCharacters(allocator
, ustr
? (const UniChar
*)ustr
: (const UniChar
*)ubuffer
, used
);
479 if (ustr
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, ustr
);
485 CFNumberRef
CFNumberFormatterCreateNumberFromString(CFAllocatorRef allocator
, CFNumberFormatterRef formatter
, CFStringRef string
, CFRange
*rangep
, CFOptionFlags options
) {
486 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
487 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
488 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
489 __CFGenericValidateType(string
, CFStringGetTypeID());
490 CFNumberType type
= (options
& kCFNumberFormatterParseIntegersOnly
) ? kCFNumberSInt64Type
: kCFNumberFloat64Type
;
492 if (CFNumberFormatterGetValueFromString(formatter
, string
, rangep
, type
, buffer
)) {
493 return CFNumberCreate(allocator
, type
, buffer
);
498 Boolean
CFNumberFormatterGetValueFromString(CFNumberFormatterRef formatter
, CFStringRef string
, CFRange
*rangep
, CFNumberType numberType
, void *valuePtr
) {
499 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
500 __CFGenericValidateType(string
, CFStringGetTypeID());
501 CFStringRef stringToParse
= formatter
->_isLenient
? __CFNumberFormatterCreateCompressedString(string
, false, rangep
) : (CFStringRef
)CFRetain(string
);
502 CFRange range
= {0, 0};
503 if(formatter
->_isLenient
) {
504 range
.length
= CFStringGetLength(stringToParse
);
509 range
.length
= CFStringGetLength(stringToParse
);
511 // unum_parse chokes on leading whitespace
512 CFCharacterSetRef whitespace
= CFCharacterSetGetPredefined(kCFCharacterSetWhitespace
);
513 while(range
.length
> 0 && CFCharacterSetIsCharacterMember(whitespace
, CFStringGetCharacterAtIndex(stringToParse
, range
.location
))) {
518 Boolean isZero
= false;
519 if (formatter
->_zeroSym
) {
520 CFStringRef zeroSym
= formatter
->_isLenient
? __CFNumberFormatterCreateCompressedString(formatter
->_zeroSym
, false, NULL
) : (CFStringRef
)CFRetain(formatter
->_zeroSym
);
521 if (kCFCompareEqualTo
== CFStringCompare(stringToParse
, zeroSym
, 0)) {
526 if (1024 < range
.length
) range
.length
= 1024;
527 const UChar
*ustr
= (const UChar
*)CFStringGetCharactersPtr(stringToParse
);
528 STACK_BUFFER_DECL(UChar
, ubuffer
, (NULL
== ustr
) ? range
.length
: 1);
530 CFStringGetCharacters(stringToParse
, range
, (UniChar
*)ubuffer
);
532 } else if (!formatter
->_isLenient
) {
533 ustr
+= range
.location
;
535 if (formatter
->_isLenient
) __CFNumberFormatterApplyPattern(formatter
, formatter
->_compformat
);
536 Boolean integerOnly
= 1;
537 switch (numberType
) {
538 case kCFNumberSInt8Type
: case kCFNumberCharType
:
539 case kCFNumberSInt16Type
: case kCFNumberShortType
:
540 case kCFNumberSInt32Type
: case kCFNumberIntType
:
541 case kCFNumberLongType
: case kCFNumberCFIndexType
:
542 case kCFNumberSInt64Type
: case kCFNumberLongLongType
:
543 unum_setAttribute(formatter
->_nf
, UNUM_PARSE_INT_ONLY
, 1); // ignored by ICU for rule-based formatters
546 unum_setAttribute(formatter
->_nf
, UNUM_PARSE_INT_ONLY
, 0); // ignored by ICU for rule-based formatters
551 UErrorCode status
= U_ZERO_ERROR
;
555 dpos
= rangep
? rangep
->length
: 0;
558 dreti
= unum_parseInt64(formatter
->_nf
, ustr
, range
.length
, &dpos
, &status
);
560 dretd
= unum_parseDouble(formatter
->_nf
, ustr
, range
.length
, &dpos
, &status
);
563 if (formatter
->_isLenient
) {
565 CFIndex uncompEnd
= rangep
->location
+ rangep
->length
;
566 CFIndex uncompIdx
= rangep
->location
;
567 for (CFIndex compIdx
= 0; compIdx
< dpos
&& uncompIdx
< uncompEnd
; compIdx
++, uncompIdx
++) {
568 while (uncompIdx
< uncompEnd
&& ustr
[compIdx
] != __CFNumberFormatterNormalizeCharacter(CFStringGetCharacterAtIndex(string
, uncompIdx
))) uncompIdx
++;
570 rangep
->length
= uncompIdx
- rangep
->location
;
572 __CFNumberFormatterApplyPattern(formatter
, formatter
->_format
);
574 rangep
->length
= dpos
+ (range
.location
- rangep
->location
);
576 CFRelease(stringToParse
);
577 if (U_FAILURE(status
)) {
580 if (formatter
->_multiplier
) {
581 double multiplier
= 1.0;
582 if (!CFNumberGetValue(formatter
->_multiplier
, kCFNumberFloat64Type
, &multiplier
)) {
585 dreti
= (int64_t)((double)dreti
/ multiplier
); // integer truncation
586 dretd
= dretd
/ multiplier
;
588 switch (numberType
) {
589 case kCFNumberSInt8Type
: case kCFNumberCharType
:
590 if (INT8_MIN
<= dreti
&& dreti
<= INT8_MAX
) {
591 *(int8_t *)valuePtr
= (int8_t)dreti
;
595 case kCFNumberSInt16Type
: case kCFNumberShortType
:
596 if (INT16_MIN
<= dreti
&& dreti
<= INT16_MAX
) {
597 *(int16_t *)valuePtr
= (int16_t)dreti
;
601 case kCFNumberSInt32Type
: case kCFNumberIntType
:
603 case kCFNumberLongType
: case kCFNumberCFIndexType
:
605 if (INT32_MIN
<= dreti
&& dreti
<= INT32_MAX
) {
606 *(int32_t *)valuePtr
= (int32_t)dreti
;
610 case kCFNumberSInt64Type
: case kCFNumberLongLongType
:
612 case kCFNumberLongType
: case kCFNumberCFIndexType
:
614 if (INT64_MIN
<= dreti
&& dreti
<= INT64_MAX
) {
615 *(int64_t *)valuePtr
= (int64_t)dreti
;
619 case kCFNumberFloat32Type
: case kCFNumberFloatType
:
620 if (-FLT_MAX
<= dretd
&& dretd
<= FLT_MAX
) {
621 *(float *)valuePtr
= (float)dretd
;
625 case kCFNumberFloat64Type
: case kCFNumberDoubleType
:
626 if (-DBL_MAX
<= dretd
&& dretd
<= DBL_MAX
) {
627 *(double *)valuePtr
= (double)dretd
;
635 void CFNumberFormatterSetProperty(CFNumberFormatterRef formatter
, CFStringRef key
, CFTypeRef value
) {
638 UErrorCode status
= U_ZERO_ERROR
;
639 UChar ubuffer
[BUFFER_SIZE
];
641 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
642 __CFGenericValidateType(key
, CFStringGetTypeID());
643 // rule-based formatters don't do attributes and symbols, except for one
644 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return;
645 if (kCFNumberFormatterOrdinalStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return;
646 if (kCFNumberFormatterDurationStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return;
647 if (kCFNumberFormatterCurrencyCodeKey
== key
) {
648 __CFGenericValidateType(value
, CFStringGetTypeID());
649 cnt
= CFStringGetLength((CFStringRef
)value
);
650 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
651 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
652 unum_setTextAttribute(formatter
->_nf
, UNUM_CURRENCY_CODE
, ubuffer
, cnt
, &status
);
653 } else if (kCFNumberFormatterDecimalSeparatorKey
== key
) {
654 __CFGenericValidateType(value
, CFStringGetTypeID());
655 cnt
= CFStringGetLength((CFStringRef
)value
);
656 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
657 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
658 unum_setSymbol(formatter
->_nf
, UNUM_DECIMAL_SEPARATOR_SYMBOL
, ubuffer
, cnt
, &status
);
659 } else if (kCFNumberFormatterCurrencyDecimalSeparatorKey
== key
) {
660 __CFGenericValidateType(value
, CFStringGetTypeID());
661 cnt
= CFStringGetLength((CFStringRef
)value
);
662 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
663 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
664 unum_setSymbol(formatter
->_nf
, UNUM_MONETARY_SEPARATOR_SYMBOL
, ubuffer
, cnt
, &status
);
665 } else if (kCFNumberFormatterAlwaysShowDecimalSeparatorKey
== key
) {
666 __CFGenericValidateType(value
, CFBooleanGetTypeID());
667 unum_setAttribute(formatter
->_nf
, UNUM_DECIMAL_ALWAYS_SHOWN
, (kCFBooleanTrue
== value
));
668 } else if (kCFNumberFormatterGroupingSeparatorKey
== key
) {
669 __CFGenericValidateType(value
, CFStringGetTypeID());
670 cnt
= CFStringGetLength((CFStringRef
)value
);
671 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
672 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
673 unum_setSymbol(formatter
->_nf
, UNUM_GROUPING_SEPARATOR_SYMBOL
, (const UChar
*)ubuffer
, cnt
, &status
);
674 } else if (kCFNumberFormatterUseGroupingSeparatorKey
== key
) {
675 __CFGenericValidateType(value
, CFBooleanGetTypeID());
676 unum_setAttribute(formatter
->_nf
, UNUM_GROUPING_USED
, (kCFBooleanTrue
== value
));
677 } else if (kCFNumberFormatterPercentSymbolKey
== key
) {
678 __CFGenericValidateType(value
, CFStringGetTypeID());
679 cnt
= CFStringGetLength((CFStringRef
)value
);
680 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
681 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
682 unum_setSymbol(formatter
->_nf
, UNUM_PERCENT_SYMBOL
, ubuffer
, cnt
, &status
);
683 } else if (kCFNumberFormatterZeroSymbolKey
== key
) {
684 __CFGenericValidateType(value
, CFStringGetTypeID());
685 CFStringRef old
= formatter
->_zeroSym
;
686 formatter
->_zeroSym
= value
? (CFStringRef
)CFRetain(value
) : NULL
;
687 if (old
) CFRelease(old
);
688 } else if (kCFNumberFormatterNaNSymbolKey
== 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_NAN_SYMBOL
, ubuffer
, cnt
, &status
);
694 } else if (kCFNumberFormatterInfinitySymbolKey
== key
) {
695 __CFGenericValidateType(value
, CFStringGetTypeID());
696 cnt
= CFStringGetLength((CFStringRef
)value
);
697 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
698 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
699 unum_setSymbol(formatter
->_nf
, UNUM_INFINITY_SYMBOL
, ubuffer
, cnt
, &status
);
700 } else if (kCFNumberFormatterMinusSignKey
== key
) {
701 __CFGenericValidateType(value
, CFStringGetTypeID());
702 cnt
= CFStringGetLength((CFStringRef
)value
);
703 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
704 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
705 unum_setSymbol(formatter
->_nf
, UNUM_MINUS_SIGN_SYMBOL
, ubuffer
, cnt
, &status
);
706 } else if (kCFNumberFormatterPlusSignKey
== key
) {
707 __CFGenericValidateType(value
, CFStringGetTypeID());
708 cnt
= CFStringGetLength((CFStringRef
)value
);
709 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
710 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
711 unum_setSymbol(formatter
->_nf
, UNUM_PLUS_SIGN_SYMBOL
, ubuffer
, cnt
, &status
);
712 } else if (kCFNumberFormatterCurrencySymbolKey
== key
) {
713 __CFGenericValidateType(value
, CFStringGetTypeID());
714 cnt
= CFStringGetLength((CFStringRef
)value
);
715 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
716 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
717 unum_setSymbol(formatter
->_nf
, UNUM_CURRENCY_SYMBOL
, (const UChar
*)ubuffer
, cnt
, &status
);
718 } else if (kCFNumberFormatterExponentSymbolKey
== key
) {
719 __CFGenericValidateType(value
, CFStringGetTypeID());
720 cnt
= CFStringGetLength((CFStringRef
)value
);
721 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
722 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
723 unum_setSymbol(formatter
->_nf
, UNUM_EXPONENTIAL_SYMBOL
, ubuffer
, cnt
, &status
);
724 } else if (kCFNumberFormatterMinIntegerDigitsKey
== key
) {
725 __CFGenericValidateType(value
, CFNumberGetTypeID());
726 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
727 unum_setAttribute(formatter
->_nf
, UNUM_MIN_INTEGER_DIGITS
, n
);
728 } else if (kCFNumberFormatterMaxIntegerDigitsKey
== key
) {
729 __CFGenericValidateType(value
, CFNumberGetTypeID());
730 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
731 unum_setAttribute(formatter
->_nf
, UNUM_MAX_INTEGER_DIGITS
, n
);
732 } else if (kCFNumberFormatterMinFractionDigitsKey
== key
) {
733 __CFGenericValidateType(value
, CFNumberGetTypeID());
734 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
735 unum_setAttribute(formatter
->_nf
, UNUM_MIN_FRACTION_DIGITS
, n
);
736 } else if (kCFNumberFormatterMaxFractionDigitsKey
== key
) {
737 __CFGenericValidateType(value
, CFNumberGetTypeID());
738 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
739 unum_setAttribute(formatter
->_nf
, UNUM_MAX_FRACTION_DIGITS
, n
);
740 } else if (kCFNumberFormatterGroupingSizeKey
== key
) {
741 __CFGenericValidateType(value
, CFNumberGetTypeID());
742 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
743 unum_setAttribute(formatter
->_nf
, UNUM_GROUPING_SIZE
, n
);
744 } else if (kCFNumberFormatterSecondaryGroupingSizeKey
== key
) {
745 __CFGenericValidateType(value
, CFNumberGetTypeID());
746 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
747 unum_setAttribute(formatter
->_nf
, UNUM_SECONDARY_GROUPING_SIZE
, n
);
748 } else if (kCFNumberFormatterRoundingModeKey
== key
) {
749 __CFGenericValidateType(value
, CFNumberGetTypeID());
750 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
751 unum_setAttribute(formatter
->_nf
, UNUM_ROUNDING_MODE
, n
);
752 } else if (kCFNumberFormatterRoundingIncrementKey
== key
) {
753 __CFGenericValidateType(value
, CFNumberGetTypeID());
754 CFNumberGetValue((CFNumberRef
)value
, kCFNumberDoubleType
, &d
);
755 unum_setDoubleAttribute(formatter
->_nf
, UNUM_ROUNDING_INCREMENT
, d
);
756 } else if (kCFNumberFormatterFormatWidthKey
== key
) {
757 __CFGenericValidateType(value
, CFNumberGetTypeID());
758 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
759 unum_setAttribute(formatter
->_nf
, UNUM_FORMAT_WIDTH
, n
);
760 } else if (kCFNumberFormatterPaddingPositionKey
== key
) {
761 __CFGenericValidateType(value
, CFNumberGetTypeID());
762 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
763 unum_setAttribute(formatter
->_nf
, UNUM_PADDING_POSITION
, n
);
764 } else if (kCFNumberFormatterPaddingCharacterKey
== key
) {
765 __CFGenericValidateType(value
, CFStringGetTypeID());
766 cnt
= CFStringGetLength((CFStringRef
)value
);
767 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
768 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
769 unum_setTextAttribute(formatter
->_nf
, UNUM_PADDING_CHARACTER
, ubuffer
, cnt
, &status
);
770 } else if (kCFNumberFormatterDefaultFormatKey
== key
) {
771 // read-only attribute
772 } else if (kCFNumberFormatterMultiplierKey
== key
) {
773 __CFGenericValidateType(value
, CFNumberGetTypeID());
774 CFNumberRef old
= formatter
->_multiplier
;
775 formatter
->_multiplier
= value
? (CFNumberRef
)CFRetain(value
) : NULL
;
776 formatter
->_userSetMultiplier
= value
? true : false;
777 if (old
) CFRelease(old
);
778 } else if (kCFNumberFormatterPositivePrefixKey
== key
) {
779 __CFGenericValidateType(value
, CFStringGetTypeID());
780 cnt
= CFStringGetLength((CFStringRef
)value
);
781 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
782 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
783 unum_setTextAttribute(formatter
->_nf
, UNUM_POSITIVE_PREFIX
, ubuffer
, cnt
, &status
);
784 } else if (kCFNumberFormatterPositiveSuffixKey
== key
) {
785 __CFGenericValidateType(value
, CFStringGetTypeID());
786 cnt
= CFStringGetLength((CFStringRef
)value
);
787 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
788 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
789 unum_setTextAttribute(formatter
->_nf
, UNUM_POSITIVE_SUFFIX
, (const UChar
*)ubuffer
, cnt
, &status
);
790 } else if (kCFNumberFormatterNegativePrefixKey
== key
) {
791 __CFGenericValidateType(value
, CFStringGetTypeID());
792 cnt
= CFStringGetLength((CFStringRef
)value
);
793 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
794 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
795 unum_setTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, cnt
, &status
);
796 } else if (kCFNumberFormatterNegativeSuffixKey
== key
) {
797 __CFGenericValidateType(value
, CFStringGetTypeID());
798 cnt
= CFStringGetLength((CFStringRef
)value
);
799 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
800 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
801 unum_setTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_SUFFIX
, (const UChar
*)ubuffer
, cnt
, &status
);
802 } else if (kCFNumberFormatterPerMillSymbolKey
== key
) {
803 __CFGenericValidateType(value
, CFStringGetTypeID());
804 cnt
= CFStringGetLength((CFStringRef
)value
);
805 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
806 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
807 unum_setSymbol(formatter
->_nf
, UNUM_PERMILL_SYMBOL
, ubuffer
, cnt
, &status
);
808 } else if (kCFNumberFormatterInternationalCurrencySymbolKey
== key
) {
809 __CFGenericValidateType(value
, CFStringGetTypeID());
810 cnt
= CFStringGetLength((CFStringRef
)value
);
811 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
812 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
813 unum_setSymbol(formatter
->_nf
, UNUM_INTL_CURRENCY_SYMBOL
, ubuffer
, cnt
, &status
);
814 } else if (kCFNumberFormatterCurrencyGroupingSeparatorKey
== key
) {
815 __CFGenericValidateType(value
, CFStringGetTypeID());
816 cnt
= CFStringGetLength((CFStringRef
)value
);
817 if (BUFFER_SIZE
< cnt
) cnt
= BUFFER_SIZE
;
818 CFStringGetCharacters((CFStringRef
)value
, CFRangeMake(0, cnt
), (UniChar
*)ubuffer
);
819 unum_setSymbol(formatter
->_nf
, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL
, ubuffer
, cnt
, &status
);
820 } else if (kCFNumberFormatterIsLenientKey
== key
) {
821 __CFGenericValidateType(value
, CFBooleanGetTypeID());
822 formatter
->_isLenient
= (kCFBooleanTrue
== value
);
823 unum_setAttribute(formatter
->_nf
, UNUM_LENIENT_PARSE
, (kCFBooleanTrue
== value
));
824 } else if (kCFNumberFormatterUseSignificantDigitsKey
== key
) {
825 __CFGenericValidateType(value
, CFBooleanGetTypeID());
826 unum_setAttribute(formatter
->_nf
, UNUM_SIGNIFICANT_DIGITS_USED
, (kCFBooleanTrue
== value
));
827 } else if (kCFNumberFormatterMinSignificantDigitsKey
== key
) {
828 __CFGenericValidateType(value
, CFNumberGetTypeID());
829 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
830 unum_setAttribute(formatter
->_nf
, UNUM_MIN_SIGNIFICANT_DIGITS
, n
);
831 } else if (kCFNumberFormatterMaxSignificantDigitsKey
== key
) {
832 __CFGenericValidateType(value
, CFNumberGetTypeID());
833 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, &n
);
834 unum_setAttribute(formatter
->_nf
, UNUM_MAX_SIGNIFICANT_DIGITS
, n
);
836 CFAssert3(0, __kCFLogAssertion
, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__
, key
, key
);
838 if (_CFExecutableLinkedOnOrAfter(CFSystemVersionSnowLeopard
)) {
839 // do a dummy call to CFNumberFormatterGetFormat() after changing an attribute because
840 // ICU sometimes changes the pattern due to a property change, and we need to poke
841 // unum_toPattern() and also update our own variables
842 CFNumberFormatterGetFormat(formatter
);
846 CFTypeRef
CFNumberFormatterCopyProperty(CFNumberFormatterRef formatter
, CFStringRef key
) {
849 UErrorCode status
= U_ZERO_ERROR
;
850 UChar ubuffer
[BUFFER_SIZE
];
852 __CFGenericValidateType(formatter
, CFNumberFormatterGetTypeID());
853 __CFGenericValidateType(key
, CFStringGetTypeID());
854 // rule-based formatters don't do attributes and symbols, except for one
855 if (kCFNumberFormatterSpellOutStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return NULL
;
856 if (kCFNumberFormatterOrdinalStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return NULL
;
857 if (kCFNumberFormatterDurationStyle
== formatter
->_style
&& kCFNumberFormatterIsLenientKey
!= key
) return NULL
;
858 if (kCFNumberFormatterCurrencyCodeKey
== key
) {
859 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_CURRENCY_CODE
, ubuffer
, BUFFER_SIZE
, &status
);
860 if (U_SUCCESS(status
) && cnt
== 0) {
861 CFStringRef localeName
= CFLocaleGetIdentifier(formatter
->_locale
);
862 char buffer
[BUFFER_SIZE
];
863 const char *cstr
= CFStringGetCStringPtr(localeName
, kCFStringEncodingASCII
);
865 if (CFStringGetCString(localeName
, buffer
, BUFFER_SIZE
, kCFStringEncodingASCII
)) cstr
= buffer
;
870 UErrorCode status
= U_ZERO_ERROR
;
871 UNumberFormat
*nf
= unum_open(UNUM_CURRENCY
, NULL
, 0, cstr
, NULL
, &status
);
873 cnt
= unum_getTextAttribute(nf
, UNUM_CURRENCY_CODE
, ubuffer
, BUFFER_SIZE
, &status
);
877 if (U_SUCCESS(status
) && 0 < cnt
&& cnt
<= BUFFER_SIZE
) {
878 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
880 } else if (kCFNumberFormatterDecimalSeparatorKey
== key
) {
881 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_DECIMAL_SEPARATOR_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
882 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
883 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
885 } else if (kCFNumberFormatterCurrencyDecimalSeparatorKey
== key
) {
886 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_MONETARY_SEPARATOR_SYMBOL
, (UChar
*)ubuffer
, BUFFER_SIZE
, &status
);
887 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
888 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
890 } else if (kCFNumberFormatterAlwaysShowDecimalSeparatorKey
== key
) {
891 n
= unum_getAttribute(formatter
->_nf
, UNUM_DECIMAL_ALWAYS_SHOWN
);
893 return CFRetain(n
? kCFBooleanTrue
: kCFBooleanFalse
);
895 } else if (kCFNumberFormatterGroupingSeparatorKey
== key
) {
896 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_GROUPING_SEPARATOR_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
897 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
898 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
900 } else if (kCFNumberFormatterUseGroupingSeparatorKey
== key
) {
901 n
= unum_getAttribute(formatter
->_nf
, UNUM_GROUPING_USED
);
903 return CFRetain(n
? kCFBooleanTrue
: kCFBooleanFalse
);
905 } else if (kCFNumberFormatterPercentSymbolKey
== key
) {
906 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_PERCENT_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
907 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
908 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
910 } else if (kCFNumberFormatterZeroSymbolKey
== key
) {
911 return formatter
->_zeroSym
? CFRetain(formatter
->_zeroSym
) : NULL
;
912 } else if (kCFNumberFormatterNaNSymbolKey
== key
) {
913 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_NAN_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
914 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
915 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
917 } else if (kCFNumberFormatterInfinitySymbolKey
== key
) {
918 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_INFINITY_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
919 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
920 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
922 } else if (kCFNumberFormatterMinusSignKey
== key
) {
923 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_MINUS_SIGN_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
924 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
925 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
927 } else if (kCFNumberFormatterPlusSignKey
== key
) {
928 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_PLUS_SIGN_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
929 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
930 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
932 } else if (kCFNumberFormatterCurrencySymbolKey
== key
) {
933 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_CURRENCY_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
934 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
935 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
937 } else if (kCFNumberFormatterExponentSymbolKey
== key
) {
938 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_EXPONENTIAL_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
939 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
940 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
942 } else if (kCFNumberFormatterMinIntegerDigitsKey
== key
) {
943 n
= unum_getAttribute(formatter
->_nf
, UNUM_MIN_INTEGER_DIGITS
);
945 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
947 } else if (kCFNumberFormatterMaxIntegerDigitsKey
== key
) {
948 n
= unum_getAttribute(formatter
->_nf
, UNUM_MAX_INTEGER_DIGITS
);
950 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
952 } else if (kCFNumberFormatterMinFractionDigitsKey
== key
) {
953 n
= unum_getAttribute(formatter
->_nf
, UNUM_MIN_FRACTION_DIGITS
);
955 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
957 } else if (kCFNumberFormatterMaxFractionDigitsKey
== key
) {
958 n
= unum_getAttribute(formatter
->_nf
, UNUM_MAX_FRACTION_DIGITS
);
960 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
962 } else if (kCFNumberFormatterGroupingSizeKey
== key
) {
963 n
= unum_getAttribute(formatter
->_nf
, UNUM_GROUPING_SIZE
);
965 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
967 } else if (kCFNumberFormatterSecondaryGroupingSizeKey
== key
) {
968 n
= unum_getAttribute(formatter
->_nf
, UNUM_SECONDARY_GROUPING_SIZE
);
970 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
972 } else if (kCFNumberFormatterRoundingModeKey
== key
) {
973 n
= unum_getAttribute(formatter
->_nf
, UNUM_ROUNDING_MODE
);
975 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
977 } else if (kCFNumberFormatterRoundingIncrementKey
== key
) {
978 d
= unum_getDoubleAttribute(formatter
->_nf
, UNUM_ROUNDING_INCREMENT
);
980 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberDoubleType
, &d
);
982 } else if (kCFNumberFormatterFormatWidthKey
== key
) {
983 n
= unum_getAttribute(formatter
->_nf
, UNUM_FORMAT_WIDTH
);
985 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
987 } else if (kCFNumberFormatterPaddingPositionKey
== key
) {
988 n
= unum_getAttribute(formatter
->_nf
, UNUM_PADDING_POSITION
);
990 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
992 } else if (kCFNumberFormatterPaddingCharacterKey
== key
) {
993 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_PADDING_CHARACTER
, ubuffer
, BUFFER_SIZE
, &status
);
994 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
995 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
997 } else if (kCFNumberFormatterDefaultFormatKey
== key
) {
998 return formatter
->_defformat
? CFRetain(formatter
->_defformat
) : NULL
;
999 } else if (kCFNumberFormatterMultiplierKey
== key
) {
1000 return formatter
->_multiplier
? CFRetain(formatter
->_multiplier
) : NULL
;
1001 } else if (kCFNumberFormatterPositivePrefixKey
== key
) {
1002 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_POSITIVE_PREFIX
, ubuffer
, BUFFER_SIZE
, &status
);
1003 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1004 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1006 } else if (kCFNumberFormatterPositiveSuffixKey
== key
) {
1007 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_POSITIVE_SUFFIX
, ubuffer
, BUFFER_SIZE
, &status
);
1008 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1009 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1011 } else if (kCFNumberFormatterNegativePrefixKey
== key
) {
1012 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_PREFIX
, ubuffer
, BUFFER_SIZE
, &status
);
1013 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1014 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1016 } else if (kCFNumberFormatterNegativeSuffixKey
== key
) {
1017 cnt
= unum_getTextAttribute(formatter
->_nf
, UNUM_NEGATIVE_SUFFIX
, ubuffer
, BUFFER_SIZE
, &status
);
1018 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1019 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1021 } else if (kCFNumberFormatterPerMillSymbolKey
== key
) {
1022 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_PERMILL_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1023 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1024 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1026 } else if (kCFNumberFormatterInternationalCurrencySymbolKey
== key
) {
1027 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_INTL_CURRENCY_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1028 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1029 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1031 } else if (kCFNumberFormatterCurrencyGroupingSeparatorKey
== key
) {
1032 cnt
= unum_getSymbol(formatter
->_nf
, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL
, ubuffer
, BUFFER_SIZE
, &status
);
1033 if (U_SUCCESS(status
) && cnt
<= BUFFER_SIZE
) {
1034 return CFStringCreateWithCharacters(CFGetAllocator(formatter
), (const UniChar
*)ubuffer
, cnt
);
1036 } else if (kCFNumberFormatterIsLenientKey
== key
) {
1037 // unum_getAttribute(, UNUM_LENIENT_PARSE) is undefined.
1038 return CFRetain(formatter
->_isLenient
? kCFBooleanTrue
: kCFBooleanFalse
);
1039 } else if (kCFNumberFormatterUseSignificantDigitsKey
== key
) {
1040 n
= unum_getAttribute(formatter
->_nf
, UNUM_SIGNIFICANT_DIGITS_USED
);
1042 return CFRetain(n
? kCFBooleanTrue
: kCFBooleanFalse
);
1044 } else if (kCFNumberFormatterMinSignificantDigitsKey
== key
) {
1045 n
= unum_getAttribute(formatter
->_nf
, UNUM_MIN_SIGNIFICANT_DIGITS
);
1047 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1049 } else if (kCFNumberFormatterMaxSignificantDigitsKey
== key
) {
1050 n
= unum_getAttribute(formatter
->_nf
, UNUM_MAX_SIGNIFICANT_DIGITS
);
1052 return CFNumberCreate(CFGetAllocator(formatter
), kCFNumberSInt32Type
, &n
);
1055 CFAssert3(0, __kCFLogAssertion
, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__
, key
, key
);
1061 Boolean
CFNumberFormatterGetDecimalInfoForCurrencyCode(CFStringRef currencyCode
, int32_t *defaultFractionDigits
, double *roundingIncrement
) {
1063 __CFGenericValidateType(currencyCode
, CFStringGetTypeID());
1064 CFAssert1(3 == CFStringGetLength(currencyCode
), __kCFLogAssertion
, "%s(): currencyCode is not 3 characters", __PRETTY_FUNCTION__
);
1065 CFStringGetCharacters(currencyCode
, CFRangeMake(0, 3), (UniChar
*)ubuffer
);
1067 UErrorCode icuStatus
= U_ZERO_ERROR
;
1068 if (defaultFractionDigits
) *defaultFractionDigits
= ucurr_getDefaultFractionDigits(ubuffer
, &icuStatus
);
1069 if (roundingIncrement
) *roundingIncrement
= ucurr_getRoundingIncrement(ubuffer
, &icuStatus
);
1070 if (U_FAILURE(icuStatus
))
1072 return (!defaultFractionDigits
|| 0 <= *defaultFractionDigits
) && (!roundingIncrement
|| 0.0 <= *roundingIncrement
);