]> git.saurik.com Git - apple/cf.git/blob - CFNumberFormatter.c
CF-744.12.tar.gz
[apple/cf.git] / CFNumberFormatter.c
1 /*
2 * Copyright (c) 2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /* CFNumberFormatter.c
25 Copyright (c) 2002-2012, Apple Inc. All rights reserved.
26 Responsibility: David Smith
27 */
28
29 #include <CoreFoundation/CFNumberFormatter.h>
30 #include <CoreFoundation/ForFoundationOnly.h>
31 #include <CoreFoundation/CFBigNumber.h>
32 #include "CFInternal.h"
33 #include "CFLocaleInternal.h"
34 #include <unicode/unum.h>
35 #include <unicode/ucurr.h>
36 #include <math.h>
37 #include <float.h>
38
39
40 static void __CFNumberFormatterCustomize(CFNumberFormatterRef formatter);
41 static CFStringRef __CFNumberFormatterCreateCompressedString(CFStringRef inString, Boolean isFormat, CFRange *rangep);
42 static UErrorCode __CFNumberFormatterApplyPattern(CFNumberFormatterRef formatter, CFStringRef pattern);
43
44 #define BUFFER_SIZE 768
45
46 struct __CFNumberFormatter {
47 CFRuntimeBase _base;
48 UNumberFormat *_nf;
49 CFLocaleRef _locale;
50 CFNumberFormatterStyle _style;
51 CFStringRef _format; // NULL for RBNFs
52 CFStringRef _defformat;
53 CFStringRef _compformat;
54 CFNumberRef _multiplier;
55 CFStringRef _zeroSym;
56 Boolean _isLenient;
57 Boolean _userSetMultiplier;
58 };
59
60 static CFStringRef __CFNumberFormatterCopyDescription(CFTypeRef cf) {
61 CFNumberFormatterRef formatter = (CFNumberFormatterRef)cf;
62 return CFStringCreateWithFormat(CFGetAllocator(formatter), NULL, CFSTR("<CFNumberFormatter %p [%p]>"), cf, CFGetAllocator(formatter));
63 }
64
65 static void __CFNumberFormatterDeallocate(CFTypeRef cf) {
66 CFNumberFormatterRef formatter = (CFNumberFormatterRef)cf;
67 if (formatter->_nf) unum_close(formatter->_nf);
68 if (formatter->_locale) CFRelease(formatter->_locale);
69 if (formatter->_format) CFRelease(formatter->_format);
70 if (formatter->_defformat) CFRelease(formatter->_defformat);
71 if (formatter->_compformat) CFRelease(formatter->_compformat);
72 if (formatter->_multiplier) CFRelease(formatter->_multiplier);
73 if (formatter->_zeroSym) CFRelease(formatter->_zeroSym);
74 }
75
76 static CFTypeID __kCFNumberFormatterTypeID = _kCFRuntimeNotATypeID;
77
78 static const CFRuntimeClass __CFNumberFormatterClass = {
79 0,
80 "CFNumberFormatter",
81 NULL, // init
82 NULL, // copy
83 __CFNumberFormatterDeallocate,
84 NULL,
85 NULL,
86 NULL, //
87 __CFNumberFormatterCopyDescription
88 };
89
90 static void __CFNumberFormatterInitialize(void) {
91 __kCFNumberFormatterTypeID = _CFRuntimeRegisterClass(&__CFNumberFormatterClass);
92 }
93
94 CFTypeID CFNumberFormatterGetTypeID(void) {
95 if (_kCFRuntimeNotATypeID == __kCFNumberFormatterTypeID) __CFNumberFormatterInitialize();
96 return __kCFNumberFormatterTypeID;
97 }
98
99 CFNumberFormatterRef CFNumberFormatterCreate(CFAllocatorRef allocator, CFLocaleRef locale, CFNumberFormatterStyle style) {
100 struct __CFNumberFormatter *memory;
101 uint32_t size = sizeof(struct __CFNumberFormatter) - sizeof(CFRuntimeBase);
102 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
103 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
104 __CFGenericValidateType(locale, CFLocaleGetTypeID());
105 memory = (struct __CFNumberFormatter *)_CFRuntimeCreateInstance(allocator, CFNumberFormatterGetTypeID(), size, NULL);
106 if (NULL == memory) {
107 return NULL;
108 }
109 memory->_nf = NULL;
110 memory->_locale = NULL;
111 memory->_format = NULL;
112 memory->_defformat = NULL;
113 memory->_compformat = NULL;
114 memory->_multiplier = NULL;
115 memory->_zeroSym = NULL;
116 memory->_isLenient = false;
117 memory->_userSetMultiplier = false;
118 if (NULL == locale) locale = CFLocaleGetSystem();
119 memory->_style = style;
120 uint32_t ustyle;
121 switch (style) {
122 case kCFNumberFormatterNoStyle: ustyle = UNUM_IGNORE; break;
123 case kCFNumberFormatterDecimalStyle: ustyle = UNUM_DECIMAL; break;
124 case kCFNumberFormatterCurrencyStyle: ustyle = UNUM_CURRENCY; break;
125 case kCFNumberFormatterPercentStyle: ustyle = UNUM_PERCENT; break;
126 case kCFNumberFormatterScientificStyle: ustyle = UNUM_SCIENTIFIC; break;
127 case kCFNumberFormatterSpellOutStyle: ustyle = UNUM_SPELLOUT; break;
128 case kCFNumberFormatterOrdinalStyle: ustyle = UNUM_ORDINAL; break;
129 case kCFNumberFormatterDurationStyle: ustyle = UNUM_DURATION; break;
130 default:
131 CFAssert2(0, __kCFLogAssertion, "%s(): unknown style %d", __PRETTY_FUNCTION__, style);
132 ustyle = UNUM_DECIMAL;
133 memory->_style = kCFNumberFormatterDecimalStyle;
134 break;
135 }
136 CFStringRef localeName = locale ? CFLocaleGetIdentifier(locale) : CFSTR("");
137 char buffer[BUFFER_SIZE];
138 const char *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII);
139 if (NULL == cstr) {
140 if (CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer;
141 }
142 if (NULL == cstr) {
143 CFRelease(memory);
144 return NULL;
145 }
146 UErrorCode status = U_ZERO_ERROR;
147 memory->_nf = unum_open((UNumberFormatStyle)ustyle, NULL, 0, cstr, NULL, &status);
148 CFAssert2(memory->_nf, __kCFLogAssertion, "%s(): error (%d) creating number formatter", __PRETTY_FUNCTION__, status);
149 if (NULL == memory->_nf) {
150 CFRelease(memory);
151 return NULL;
152 }
153 UChar ubuff[4];
154 if (kCFNumberFormatterNoStyle == style) {
155 status = U_ZERO_ERROR;
156 ubuff[0] = '#'; ubuff[1] = ';'; ubuff[2] = '#';
157 unum_applyPattern(memory->_nf, false, ubuff, 3, NULL, &status);
158 unum_setAttribute(memory->_nf, UNUM_MAX_INTEGER_DIGITS, 42);
159 unum_setAttribute(memory->_nf, UNUM_MAX_FRACTION_DIGITS, 0);
160 }
161 memory->_locale = locale ? CFLocaleCreateCopy(allocator, locale) : CFLocaleGetSystem();
162 __CFNumberFormatterCustomize(memory);
163 if (kCFNumberFormatterSpellOutStyle != memory->_style && kCFNumberFormatterOrdinalStyle != memory->_style && kCFNumberFormatterDurationStyle != memory->_style) {
164 UChar ubuffer[BUFFER_SIZE];
165 status = U_ZERO_ERROR;
166 int32_t ret = unum_toPattern(memory->_nf, false, ubuffer, BUFFER_SIZE, &status);
167 if (U_SUCCESS(status) && ret <= BUFFER_SIZE) {
168 memory->_format = CFStringCreateWithCharacters(allocator, (const UniChar *)ubuffer, ret);
169 }
170 }
171 memory->_defformat = memory->_format ? (CFStringRef)CFRetain(memory->_format) : NULL;
172 memory->_compformat = memory->_format ? __CFNumberFormatterCreateCompressedString(memory->_format, true, NULL) : NULL;
173 if (kCFNumberFormatterSpellOutStyle != memory->_style && kCFNumberFormatterOrdinalStyle != memory->_style && kCFNumberFormatterDurationStyle != memory->_style) {
174 int32_t n = unum_getAttribute(memory->_nf, UNUM_MULTIPLIER);
175 if (1 != n) {
176 memory->_multiplier = CFNumberCreate(allocator, kCFNumberSInt32Type, &n);
177 unum_setAttribute(memory->_nf, UNUM_MULTIPLIER, 1);
178 }
179 }
180 unum_setAttribute(memory->_nf, UNUM_LENIENT_PARSE, 0);
181 return (CFNumberFormatterRef)memory;
182 }
183
184 extern CFDictionaryRef __CFLocaleGetPrefs(CFLocaleRef locale);
185
186 static void __substituteFormatStringFromPrefsNF(CFNumberFormatterRef formatter) {
187 CFIndex formatStyle = formatter->_style;
188 if (kCFNumberFormatterSpellOutStyle == formatStyle) return;
189 if (kCFNumberFormatterOrdinalStyle == formatStyle) return;
190 if (kCFNumberFormatterDurationStyle == formatStyle) return;
191 CFStringRef prefName = CFSTR("AppleICUNumberFormatStrings");
192 if (kCFNumberFormatterNoStyle != formatStyle) {
193 CFStringRef pref = NULL;
194 CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale);
195 CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, prefName) : NULL;
196 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) {
197 CFStringRef key;
198 switch (formatStyle) {
199 case kCFNumberFormatterDecimalStyle: key = CFSTR("1"); break;
200 case kCFNumberFormatterCurrencyStyle: key = CFSTR("2"); break;
201 case kCFNumberFormatterPercentStyle: key = CFSTR("3"); break;
202 case kCFNumberFormatterScientificStyle: key = CFSTR("4"); break;
203 case kCFNumberFormatterSpellOutStyle: key = CFSTR("5"); break;
204 case kCFNumberFormatterOrdinalStyle: key = CFSTR("6"); break;
205 case kCFNumberFormatterDurationStyle: key = CFSTR("7"); break;
206 default: key = CFSTR("0"); break;
207 }
208 pref = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)metapref, key);
209 }
210 if (NULL != pref && CFGetTypeID(pref) == CFStringGetTypeID()) {
211 int32_t icustyle = UNUM_IGNORE;
212 switch (formatStyle) {
213 case kCFNumberFormatterDecimalStyle: icustyle = UNUM_DECIMAL; break;
214 case kCFNumberFormatterCurrencyStyle: icustyle = UNUM_CURRENCY; break;
215 case kCFNumberFormatterPercentStyle: icustyle = UNUM_PERCENT; break;
216 case kCFNumberFormatterScientificStyle: icustyle = UNUM_SCIENTIFIC; break;
217 case kCFNumberFormatterSpellOutStyle: icustyle = UNUM_SPELLOUT; break;
218 case kCFNumberFormatterOrdinalStyle: icustyle = UNUM_ORDINAL; break;
219 case kCFNumberFormatterDurationStyle: icustyle = UNUM_DURATION; break;
220 }
221 CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale);
222 char buffer[BUFFER_SIZE];
223 const char *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII);
224 if (NULL == cstr) {
225 if (CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer;
226 }
227 UErrorCode status = U_ZERO_ERROR;
228 UNumberFormat *nf = unum_open((UNumberFormatStyle)icustyle, NULL, 0, cstr, NULL, &status);
229 if (NULL != nf) {
230 UChar ubuffer[BUFFER_SIZE];
231 status = U_ZERO_ERROR;
232 int32_t number_len = unum_toPattern(nf, false, ubuffer, BUFFER_SIZE, &status);
233 if (U_SUCCESS(status) && number_len <= BUFFER_SIZE) {
234 CFStringRef numberString = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)ubuffer, number_len);
235 status = U_ZERO_ERROR;
236 int32_t formatter_len = unum_toPattern(formatter->_nf, false, ubuffer, BUFFER_SIZE, &status);
237 if (U_SUCCESS(status) && formatter_len <= BUFFER_SIZE) {
238 CFMutableStringRef formatString = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
239 CFStringAppendCharacters(formatString, (const UniChar *)ubuffer, formatter_len);
240 // find numberString inside formatString, substitute the pref in that range
241 CFRange result;
242 if (CFStringFindWithOptions(formatString, numberString, CFRangeMake(0, formatter_len), 0, &result)) {
243 CFStringReplace(formatString, result, pref);
244 __CFNumberFormatterApplyPattern(formatter, formatString);
245 }
246 CFRelease(formatString);
247 }
248 CFRelease(numberString);
249 }
250 unum_close(nf);
251 }
252 }
253 }
254 }
255
256 static UniChar __CFNumberFormatterNormalizeCharacter(UniChar c) {
257 if (CFCharacterSetIsCharacterMember(CFCharacterSetGetPredefined(kCFCharacterSetWhitespace), c)) {
258 return ' ';
259 } else {
260 return c;
261 }
262 }
263
264 /* Attempt to match the unimplemented lenient parsing behavior described at http://www.unicode.org/reports/tr35/#Lenient_Parsing -- specifically any whitespace is ignored that does not exist between two letters or two numbers, and no-break spaces map to spaces. */
265 static CFStringRef __CFNumberFormatterCreateCompressedString(CFStringRef inString, Boolean isFormat, CFRange *rangep) {
266 if (!inString) return NULL;
267 CFRange range = { 0, 0 };
268 if (rangep) {
269 range = *rangep;
270 } else {
271 range.length = CFStringGetLength(inString);
272 }
273 CFMutableStringRef outString = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
274 CFCharacterSetRef letters = CFCharacterSetGetPredefined(kCFCharacterSetLetter);
275 CFCharacterSetRef numbers = CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit);
276 UniChar prevCh = 0, nextCh = 0;
277 Boolean inQuote = false;
278 for (CFIndex in_idx = range.location; in_idx < range.location + range.length; in_idx++) {
279 UniChar ch = __CFNumberFormatterNormalizeCharacter(CFStringGetCharacterAtIndex(inString, in_idx));
280 nextCh = (in_idx+1 < range.length) ? CFStringGetCharacterAtIndex(inString, in_idx+1) : 0;
281 if (isFormat && ch == '\'') inQuote = !inQuote;
282 if (inQuote || ch != ' ' || (CFCharacterSetIsCharacterMember(letters, prevCh) && CFCharacterSetIsCharacterMember(letters, nextCh)) || (CFCharacterSetIsCharacterMember(numbers, prevCh) && CFCharacterSetIsCharacterMember(numbers, nextCh))) {
283 CFStringAppendCharacters(outString, &ch, 1);
284 prevCh = ch;
285 }
286 }
287 return outString;
288 }
289
290 // Should not be called for rule-based ICU formatters; not supported
291 static void __CFNumberFormatterApplySymbolPrefs(const void *key, const void *value, void *context) {
292 if (CFGetTypeID(key) == CFStringGetTypeID() && CFGetTypeID(value) == CFStringGetTypeID()) {
293 CFNumberFormatterRef formatter = (CFNumberFormatterRef)context;
294 UNumberFormatSymbol sym = (UNumberFormatSymbol)CFStringGetIntValue((CFStringRef)key);
295 CFStringRef item = (CFStringRef)value;
296 CFIndex item_cnt = CFStringGetLength(item);
297 STACK_BUFFER_DECL(UChar, item_buffer, item_cnt);
298 UChar *item_ustr = (UChar *)CFStringGetCharactersPtr(item);
299 if (NULL == item_ustr) {
300 CFStringGetCharacters(item, CFRangeMake(0, __CFMin(BUFFER_SIZE, item_cnt)), (UniChar *)item_buffer);
301 item_ustr = item_buffer;
302 }
303 UErrorCode status = U_ZERO_ERROR;
304 unum_setSymbol(formatter->_nf, sym, item_ustr, item_cnt, &status);
305 }
306 }
307
308 // Should not be called for rule-based ICU formatters
309 static UErrorCode __CFNumberFormatterApplyPattern(CFNumberFormatterRef formatter, CFStringRef pattern) {
310 if (kCFNumberFormatterSpellOutStyle == formatter->_style) return U_UNSUPPORTED_ERROR;
311 if (kCFNumberFormatterOrdinalStyle == formatter->_style) return U_UNSUPPORTED_ERROR;
312 if (kCFNumberFormatterDurationStyle == formatter->_style) return U_UNSUPPORTED_ERROR;
313 CFIndex cnt = CFStringGetLength(pattern);
314 STACK_BUFFER_DECL(UChar, ubuffer, cnt);
315 const UChar *ustr = (const UChar *)CFStringGetCharactersPtr(pattern);
316 if (NULL == ustr) {
317 CFStringGetCharacters(pattern, CFRangeMake(0, cnt), (UniChar *)ubuffer);
318 ustr = ubuffer;
319 }
320 UErrorCode status = U_ZERO_ERROR;
321 unum_applyPattern(formatter->_nf, false, ustr, cnt, NULL, &status);
322
323 // unum_applyPattern() may have magically changed other attributes based on
324 // the contents of the format string; we simply expose that ICU behavior, except
325 // for UNUM_MULTIPLIER, which we re-read and reset, like we did at initialization
326 // time though any user-set multiplier state takes precedence.
327 if (formatter->_userSetMultiplier) {
328 unum_setAttribute(formatter->_nf, UNUM_MULTIPLIER, 1);
329 } else {
330 if (formatter->_multiplier) CFRelease(formatter->_multiplier);
331 formatter->_multiplier = NULL;
332 int32_t n = unum_getAttribute(formatter->_nf, UNUM_MULTIPLIER);
333 if (1 != n) {
334 formatter->_multiplier = CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
335 unum_setAttribute(formatter->_nf, UNUM_MULTIPLIER, 1);
336 }
337 }
338 return status;
339 }
340
341 static void __CFNumberFormatterCustomize(CFNumberFormatterRef formatter) {
342 __substituteFormatStringFromPrefsNF(formatter);
343 CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale);
344 CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUNumberSymbols")) : NULL;
345 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) {
346 CFDictionaryApplyFunction((CFDictionaryRef)metapref, __CFNumberFormatterApplySymbolPrefs, formatter);
347 }
348 }
349
350 CFLocaleRef CFNumberFormatterGetLocale(CFNumberFormatterRef formatter) {
351 __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
352 return formatter->_locale;
353 }
354
355 CFNumberFormatterStyle CFNumberFormatterGetStyle(CFNumberFormatterRef formatter) {
356 __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
357 return formatter->_style;
358 }
359
360 CFStringRef CFNumberFormatterGetFormat(CFNumberFormatterRef formatter) {
361 __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
362 if (kCFNumberFormatterSpellOutStyle == formatter->_style) return NULL;
363 if (kCFNumberFormatterOrdinalStyle == formatter->_style) return NULL;
364 if (kCFNumberFormatterDurationStyle == formatter->_style) return NULL;
365 UChar ubuffer[BUFFER_SIZE];
366 CFStringRef newString = NULL;
367 UErrorCode status = U_ZERO_ERROR;
368 int32_t ret = unum_toPattern(formatter->_nf, false, ubuffer, BUFFER_SIZE, &status);
369 if (U_SUCCESS(status) && ret <= BUFFER_SIZE) {
370 newString = CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, ret);
371 }
372 if (newString && !formatter->_format) {
373 formatter->_format = newString;
374 if (formatter->_compformat) CFRelease(formatter->_compformat);
375 formatter->_compformat = __CFNumberFormatterCreateCompressedString(formatter->_format, true, NULL);
376 } else if (newString && !CFEqual(newString, formatter->_format)) {
377 CFRelease(formatter->_format);
378 formatter->_format = newString;
379 if (formatter->_compformat) CFRelease(formatter->_compformat);
380 formatter->_compformat = __CFNumberFormatterCreateCompressedString(formatter->_format, true, NULL);
381 } else if (newString) {
382 CFRelease(newString);
383 }
384 return formatter->_format;
385 }
386
387 void CFNumberFormatterSetFormat(CFNumberFormatterRef formatter, CFStringRef formatString) {
388 __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
389 __CFGenericValidateType(formatString, CFStringGetTypeID());
390 if (kCFNumberFormatterSpellOutStyle == formatter->_style) return;
391 if (kCFNumberFormatterOrdinalStyle == formatter->_style) return;
392 if (kCFNumberFormatterDurationStyle == formatter->_style) return;
393 CFIndex cnt = CFStringGetLength(formatString);
394 CFAssert1(cnt <= 1024, __kCFLogAssertion, "%s(): format string too long", __PRETTY_FUNCTION__);
395 if ((!formatter->_format || !CFEqual(formatter->_format, formatString)) && cnt <= 1024) {
396 UErrorCode status = __CFNumberFormatterApplyPattern(formatter, formatString);
397 if (U_SUCCESS(status)) {
398 UChar ubuffer2[BUFFER_SIZE];
399 status = U_ZERO_ERROR;
400 int32_t ret = unum_toPattern(formatter->_nf, false, ubuffer2, BUFFER_SIZE, &status);
401 if (U_SUCCESS(status) && ret <= BUFFER_SIZE) {
402 if (formatter->_format) CFRelease(formatter->_format);
403 formatter->_format = CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer2, ret);
404 if (formatter->_compformat) CFRelease(formatter->_compformat);
405 formatter->_compformat = __CFNumberFormatterCreateCompressedString(formatter->_format, true, NULL);
406 }
407 }
408 }
409 }
410
411 #define GET_MULTIPLIER \
412 double multiplier = 1.0; \
413 double dummy = 0.0; \
414 if (formatter->_multiplier) { \
415 if (!CFNumberGetValue(formatter->_multiplier, kCFNumberFloat64Type, &multiplier)) { \
416 multiplier = 1.0; \
417 } \
418 } \
419 if (modf(multiplier, &dummy) < FLT_EPSILON) { \
420 multiplier = floor(multiplier); \
421 }
422
423 CFStringRef CFNumberFormatterCreateStringWithNumber(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFNumberRef number) {
424 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
425 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
426 __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
427 __CFGenericValidateType(number, CFNumberGetTypeID());
428 CFNumberType type = CFNumberGetType(number);
429 char buffer[64];
430 CFNumberGetValue(number, type, buffer);
431 return CFNumberFormatterCreateStringWithValue(allocator, formatter, type, buffer);
432 }
433
434 #define FORMAT_FLT(T, FUNC) \
435 T value = *(T *)valuePtr; \
436 if (0 == value && formatter->_zeroSym) { return (CFStringRef)CFRetain(formatter->_zeroSym); } \
437 if (1.0 != multiplier) { \
438 value = (T)(value * multiplier); \
439 } \
440 status = U_ZERO_ERROR; \
441 used = FUNC(formatter->_nf, value, ubuffer, cnt, NULL, &status); \
442 if (status == U_BUFFER_OVERFLOW_ERROR || cnt < used) { \
443 cnt = used + 1; \
444 ustr = (UChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UChar) * cnt, 0); \
445 status = U_ZERO_ERROR; \
446 used = FUNC(formatter->_nf, value, ustr, cnt, NULL, &status); \
447 }
448
449 #define FORMAT_INT(T, FUN) \
450 T value = *(T *)valuePtr; \
451 if (0 == value && formatter->_zeroSym) { return (CFStringRef)CFRetain(formatter->_zeroSym); } \
452 if (1.0 != multiplier) { \
453 value = (T)(value * multiplier); \
454 } \
455 _CFBigNum bignum; \
456 FUN(&bignum, value); \
457 char buffer[BUFFER_SIZE]; \
458 _CFBigNumToCString(&bignum, false, true, buffer, BUFFER_SIZE); \
459 status = U_ZERO_ERROR; \
460 used = unum_formatDecimal(formatter->_nf, buffer, strlen(buffer), ubuffer, BUFFER_SIZE, NULL, &status); \
461 if (status == U_BUFFER_OVERFLOW_ERROR || cnt < used) { \
462 cnt = used + 1; \
463 ustr = (UChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UChar) * cnt, 0); \
464 status = U_ZERO_ERROR; \
465 used = unum_formatDecimal(formatter->_nf, buffer, strlen(buffer), ustr, cnt, NULL, &status); \
466 } \
467
468 CFStringRef CFNumberFormatterCreateStringWithValue(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFNumberType numberType, const void *valuePtr) {
469 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
470 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
471 __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
472 GET_MULTIPLIER;
473 UChar *ustr = NULL, ubuffer[BUFFER_SIZE];
474 UErrorCode status = U_ZERO_ERROR;
475 CFIndex used, cnt = BUFFER_SIZE;
476 if (numberType == kCFNumberFloat64Type || numberType == kCFNumberDoubleType) {
477 FORMAT_FLT(double, unum_formatDouble)
478 } else if (numberType == kCFNumberFloat32Type || numberType == kCFNumberFloatType) {
479 FORMAT_FLT(float, unum_formatDouble)
480 } else if (numberType == kCFNumberSInt64Type || numberType == kCFNumberLongLongType) {
481 FORMAT_INT(int64_t, _CFBigNumInitWithInt64)
482 } else if (numberType == kCFNumberLongType || numberType == kCFNumberCFIndexType) {
483 #if __LP64__
484 FORMAT_INT(int64_t, _CFBigNumInitWithInt64)
485 #else
486 FORMAT_INT(int32_t, _CFBigNumInitWithInt32)
487 #endif
488 } else if (numberType == kCFNumberSInt32Type || numberType == kCFNumberIntType) {
489 FORMAT_INT(int32_t, _CFBigNumInitWithInt32)
490 } else if (numberType == kCFNumberSInt16Type || numberType == kCFNumberShortType) {
491 FORMAT_INT(int16_t, _CFBigNumInitWithInt16)
492 } else if (numberType == kCFNumberSInt8Type || numberType == kCFNumberCharType) {
493 FORMAT_INT(int8_t, _CFBigNumInitWithInt8)
494 } else {
495 CFAssert2(0, __kCFLogAssertion, "%s(): unknown CFNumberType (%d)", __PRETTY_FUNCTION__, numberType);
496 return NULL;
497 }
498 CFStringRef string = NULL;
499 if (U_SUCCESS(status)) {
500 string = CFStringCreateWithCharacters(allocator, ustr ? (const UniChar *)ustr : (const UniChar *)ubuffer, used);
501 }
502 if (ustr) CFAllocatorDeallocate(kCFAllocatorSystemDefault, ustr);
503 return string;
504 }
505
506 #undef FORMAT_FLT
507 #undef FORMAT_INT
508 #undef GET_MULTIPLIER
509
510 CFNumberRef CFNumberFormatterCreateNumberFromString(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFStringRef string, CFRange *rangep, CFOptionFlags options) {
511 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
512 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
513 __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
514 __CFGenericValidateType(string, CFStringGetTypeID());
515 char buffer[16] __attribute__ ((aligned (8)));
516 CFRange r = rangep ? *rangep : CFRangeMake(0, CFStringGetLength(string));
517 CFNumberRef multiplierRef = formatter->_multiplier;
518 formatter->_multiplier = NULL;
519 Boolean b = CFNumberFormatterGetValueFromString(formatter, string, &r, kCFNumberSInt64Type, buffer);
520 formatter->_multiplier = multiplierRef;
521 if (b) {
522 Boolean passedMultiplier = true;
523 // We handle the multiplier case here manually; the final
524 // result is supposed to be (parsed value) / (multiplier), but
525 // the int case here should only succeed if the parsed value
526 // is an exact multiple of the multiplier.
527 if (multiplierRef) {
528 int64_t tmp = *(int64_t *)buffer;
529 double multiplier = 1.0;
530 if (!CFNumberGetValue(multiplierRef, kCFNumberFloat64Type, &multiplier)) {
531 multiplier = 1.0;
532 }
533 double dummy;
534 if (llabs(tmp) < fabs(multiplier)) {
535 passedMultiplier = false;
536 } else if (fabs(multiplier) < 1.0) { // We can't handle this math yet
537 passedMultiplier = false;
538 } else if (modf(multiplier, &dummy) == 0.0) { // multiplier is an integer
539 int64_t imult = (int64_t)multiplier;
540 int64_t rem = tmp % imult;
541 if (rem != 0) passedMultiplier = false;
542 if (passedMultiplier) {
543 tmp = tmp / imult;
544 *(int64_t *)buffer = tmp;
545 }
546 } else if (multiplier == -1.0) { // simple
547 tmp = tmp * -1;
548 *(int64_t *)buffer = tmp;
549 } else if (multiplier != 1.0) {
550 // First, throw away integer multiples of the multiplier to
551 // bring the value down to less than 2^53, so that we can
552 // cast it to double without losing any precision, important
553 // for the "remainder is zero" test.
554 // Find power of two which, when multiplier is multiplied by it,
555 // results in an integer value. pwr will be <= 52 since multiplier
556 // is at least 1.
557 int pwr = 0;
558 double intgrl;
559 while (modf(scalbn(multiplier, pwr), &intgrl) != 0.0) pwr++;
560 int64_t i2 = (int64_t)intgrl;
561 // scale pwr and i2 up to a reasonably large value so the next loop doesn't take forever
562 while (llabs(i2) < (1LL << 50)) { i2 *= 2; pwr++; }
563 int64_t cnt = 0;
564 while ((1LL << 53) <= llabs(tmp)) {
565 // subtract (multiplier * 2^pwr) each time
566 tmp -= i2; // move tmp toward zero
567 cnt += (1LL << pwr); // remember how many 2^pwr we subtracted
568 }
569 // If the integer is less than 2^53, there is no loss
570 // in converting it to double, so we can just do the
571 // direct operation now.
572 double rem = fmod((double)tmp, multiplier);
573 if (rem != 0.0) passedMultiplier = false;
574 if (passedMultiplier) {
575 // The original tmp, which we need to divide by multiplier, is at this point:
576 // tmp + k * 2^n * multiplier, where k is the number of loop iterations
577 // That original value needs to be divided by multiplier and put back in the
578 // buffer. Noting that k * 2^n == cnt, and after some algebra, we have:
579 tmp = (int64_t)((double)tmp / multiplier) + cnt;
580 *(int64_t *)buffer = tmp;
581 }
582 }
583 }
584 if (passedMultiplier && ((r.length == CFStringGetLength(string)) || (options & kCFNumberFormatterParseIntegersOnly))) {
585 if (rangep) *rangep = r;
586 return CFNumberCreate(allocator, kCFNumberSInt64Type, buffer);
587 }
588 }
589 if (options & kCFNumberFormatterParseIntegersOnly) return NULL;
590 if (CFNumberFormatterGetValueFromString(formatter, string, rangep, kCFNumberFloat64Type, buffer)) {
591 return CFNumberCreate(allocator, kCFNumberFloat64Type, buffer);
592 }
593 return NULL;
594 }
595
596 Boolean CFNumberFormatterGetValueFromString(CFNumberFormatterRef formatter, CFStringRef string, CFRange *rangep, CFNumberType numberType, void *valuePtr) {
597 __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
598 __CFGenericValidateType(string, CFStringGetTypeID());
599 CFStringRef stringToParse = formatter->_isLenient ? __CFNumberFormatterCreateCompressedString(string, false, rangep) : (CFStringRef)CFRetain(string);
600 CFRange range = {0, 0};
601 if(formatter->_isLenient) {
602 range.length = CFStringGetLength(stringToParse);
603 } else {
604 if (rangep) {
605 range = *rangep;
606 } else {
607 range.length = CFStringGetLength(stringToParse);
608 }
609 // unum_parse chokes on leading whitespace
610 CFCharacterSetRef whitespace = CFCharacterSetGetPredefined(kCFCharacterSetWhitespace);
611 while(range.length > 0 && CFCharacterSetIsCharacterMember(whitespace, CFStringGetCharacterAtIndex(stringToParse, range.location))) {
612 range.location++;
613 range.length--;
614 }
615 }
616 Boolean isZero = false;
617 if (formatter->_zeroSym) {
618 CFStringRef zeroSym = formatter->_isLenient ? __CFNumberFormatterCreateCompressedString(formatter->_zeroSym, false, NULL) : (CFStringRef)CFRetain(formatter->_zeroSym);
619 if (kCFCompareEqualTo == CFStringCompare(stringToParse, zeroSym, 0)) {
620 isZero = true;
621 }
622 CFRelease(zeroSym);
623 }
624 if (1024 < range.length) range.length = 1024;
625 const UChar *ustr = (const UChar *)CFStringGetCharactersPtr(stringToParse);
626 STACK_BUFFER_DECL(UChar, ubuffer, (NULL == ustr) ? range.length : 1);
627 if (NULL == ustr) {
628 CFStringGetCharacters(stringToParse, range, (UniChar *)ubuffer);
629 ustr = ubuffer;
630 } else if (!formatter->_isLenient) {
631 ustr += range.location;
632 }
633 CFNumberRef multiplierRef = formatter->_multiplier;
634 formatter->_multiplier = NULL;
635 if (formatter->_isLenient) {
636 __CFNumberFormatterApplyPattern(formatter, formatter->_compformat);
637 if (formatter->_multiplier) CFRelease(formatter->_multiplier);
638 formatter->_multiplier = NULL;
639 }
640 Boolean integerOnly = 1;
641 switch (numberType) {
642 case kCFNumberSInt8Type: case kCFNumberCharType:
643 case kCFNumberSInt16Type: case kCFNumberShortType:
644 case kCFNumberSInt32Type: case kCFNumberIntType:
645 case kCFNumberLongType: case kCFNumberCFIndexType:
646 case kCFNumberSInt64Type: case kCFNumberLongLongType:
647 unum_setAttribute(formatter->_nf, UNUM_PARSE_INT_ONLY, 1); // ignored by ICU for rule-based formatters
648 break;
649 default:
650 unum_setAttribute(formatter->_nf, UNUM_PARSE_INT_ONLY, 0); // ignored by ICU for rule-based formatters
651 integerOnly = 0;
652 break;
653 }
654 int32_t dpos = 0;
655 UErrorCode status = U_ZERO_ERROR;
656 int64_t dreti = 0;
657 double dretd = 0.0;
658 if (isZero) {
659 dpos = rangep ? rangep->length : 0;
660 } else {
661 char buffer[1024];
662 memset(buffer, 0, sizeof(buffer));
663 int32_t len = unum_parseDecimal(formatter->_nf, ustr, range.length, &dpos, buffer, sizeof(buffer), &status);
664 if (!U_FAILURE(status) && 0 < len && integerOnly) {
665 char *endptr = NULL;
666 errno = 0;
667 dreti = strtoll_l(buffer, &endptr, 10, NULL);
668 if (!(errno == 0 && *endptr == '\0')) status = U_INVALID_FORMAT_ERROR;
669 }
670 if (!U_FAILURE(status) && 0 < len) {
671 char *endptr = NULL;
672 errno = 0;
673 dretd = strtod_l(buffer, &endptr, NULL);
674 if (!(errno == 0 && *endptr == '\0')) status = U_INVALID_FORMAT_ERROR;
675 }
676 }
677 if (formatter->_isLenient) {
678 if (rangep) {
679 CFIndex uncompEnd = rangep->location + rangep->length;
680 CFIndex uncompIdx = rangep->location;
681 for (CFIndex compIdx = 0; compIdx < dpos && uncompIdx < uncompEnd; compIdx++, uncompIdx++) {
682 while (uncompIdx < uncompEnd && ustr[compIdx] != __CFNumberFormatterNormalizeCharacter(CFStringGetCharacterAtIndex(string, uncompIdx))) uncompIdx++;
683 }
684 rangep->length = uncompIdx - rangep->location;
685 }
686 __CFNumberFormatterApplyPattern(formatter, formatter->_format);
687 if (formatter->_multiplier) CFRelease(formatter->_multiplier);
688 formatter->_multiplier = NULL;
689 } else if (rangep) {
690 rangep->length = dpos + (range.location - rangep->location);
691 }
692 formatter->_multiplier = multiplierRef;
693 CFRelease(stringToParse);
694 if (U_FAILURE(status)) {
695 return false;
696 }
697 if (formatter->_multiplier) {
698 double multiplier = 1.0;
699 if (!CFNumberGetValue(formatter->_multiplier, kCFNumberFloat64Type, &multiplier)) {
700 multiplier = 1.0;
701 }
702 dreti = (int64_t)((double)dreti / multiplier); // integer truncation, plus double cast can be lossy for dreti > 2^53
703 dretd = dretd / multiplier;
704 }
705 switch (numberType) {
706 case kCFNumberSInt8Type: case kCFNumberCharType:
707 if (INT8_MIN <= dreti && dreti <= INT8_MAX) {
708 *(int8_t *)valuePtr = (int8_t)dreti;
709 return true;
710 }
711 break;
712 case kCFNumberSInt16Type: case kCFNumberShortType:
713 if (INT16_MIN <= dreti && dreti <= INT16_MAX) {
714 *(int16_t *)valuePtr = (int16_t)dreti;
715 return true;
716 }
717 break;
718 case kCFNumberSInt32Type: case kCFNumberIntType:
719 #if !__LP64__
720 case kCFNumberLongType: case kCFNumberCFIndexType:
721 #endif
722 if (INT32_MIN <= dreti && dreti <= INT32_MAX) {
723 *(int32_t *)valuePtr = (int32_t)dreti;
724 return true;
725 }
726 break;
727 case kCFNumberSInt64Type: case kCFNumberLongLongType:
728 #if __LP64__
729 case kCFNumberLongType: case kCFNumberCFIndexType:
730 #endif
731 if (INT64_MIN <= dreti && dreti <= INT64_MAX) {
732 *(int64_t *)valuePtr = (int64_t)dreti;
733 return true;
734 }
735 break;
736 case kCFNumberFloat32Type: case kCFNumberFloatType:
737 if (-FLT_MAX <= dretd && dretd <= FLT_MAX) {
738 *(float *)valuePtr = (float)dretd;
739 return true;
740 }
741 break;
742 case kCFNumberFloat64Type: case kCFNumberDoubleType:
743 if (-DBL_MAX <= dretd && dretd <= DBL_MAX) {
744 *(double *)valuePtr = (double)dretd;
745 return true;
746 }
747 break;
748 }
749 return false;
750 }
751
752 void CFNumberFormatterSetProperty(CFNumberFormatterRef formatter, CFStringRef key, CFTypeRef value) {
753 int32_t n;
754 double d;
755 UErrorCode status = U_ZERO_ERROR;
756 UChar ubuffer[BUFFER_SIZE];
757 CFIndex cnt;
758 __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
759 __CFGenericValidateType(key, CFStringGetTypeID());
760 // rule-based formatters don't do attributes and symbols, except for one
761 if (kCFNumberFormatterSpellOutStyle == formatter->_style && kCFNumberFormatterIsLenientKey != key) return;
762 if (kCFNumberFormatterOrdinalStyle == formatter->_style && kCFNumberFormatterIsLenientKey != key) return;
763 if (kCFNumberFormatterDurationStyle == formatter->_style && kCFNumberFormatterIsLenientKey != key) return;
764 if (kCFNumberFormatterCurrencyCodeKey == key) {
765 __CFGenericValidateType(value, CFStringGetTypeID());
766 cnt = CFStringGetLength((CFStringRef)value);
767 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
768 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
769 unum_setTextAttribute(formatter->_nf, UNUM_CURRENCY_CODE, ubuffer, cnt, &status);
770 } else if (kCFNumberFormatterDecimalSeparatorKey == key) {
771 __CFGenericValidateType(value, CFStringGetTypeID());
772 cnt = CFStringGetLength((CFStringRef)value);
773 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
774 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
775 unum_setSymbol(formatter->_nf, UNUM_DECIMAL_SEPARATOR_SYMBOL, ubuffer, cnt, &status);
776 } else if (kCFNumberFormatterCurrencyDecimalSeparatorKey == key) {
777 __CFGenericValidateType(value, CFStringGetTypeID());
778 cnt = CFStringGetLength((CFStringRef)value);
779 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
780 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
781 unum_setSymbol(formatter->_nf, UNUM_MONETARY_SEPARATOR_SYMBOL, ubuffer, cnt, &status);
782 } else if (kCFNumberFormatterAlwaysShowDecimalSeparatorKey == key) {
783 __CFGenericValidateType(value, CFBooleanGetTypeID());
784 unum_setAttribute(formatter->_nf, UNUM_DECIMAL_ALWAYS_SHOWN, (kCFBooleanTrue == value));
785 } else if (kCFNumberFormatterGroupingSeparatorKey == key) {
786 __CFGenericValidateType(value, CFStringGetTypeID());
787 cnt = CFStringGetLength((CFStringRef)value);
788 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
789 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
790 unum_setSymbol(formatter->_nf, UNUM_GROUPING_SEPARATOR_SYMBOL, (const UChar *)ubuffer, cnt, &status);
791 } else if (kCFNumberFormatterUseGroupingSeparatorKey == key) {
792 __CFGenericValidateType(value, CFBooleanGetTypeID());
793 unum_setAttribute(formatter->_nf, UNUM_GROUPING_USED, (kCFBooleanTrue == value));
794 } else if (kCFNumberFormatterPercentSymbolKey == key) {
795 __CFGenericValidateType(value, CFStringGetTypeID());
796 cnt = CFStringGetLength((CFStringRef)value);
797 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
798 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
799 unum_setSymbol(formatter->_nf, UNUM_PERCENT_SYMBOL, ubuffer, cnt, &status);
800 } else if (kCFNumberFormatterZeroSymbolKey == key) {
801 __CFGenericValidateType(value, CFStringGetTypeID());
802 CFStringRef old = formatter->_zeroSym;
803 formatter->_zeroSym = value ? (CFStringRef)CFRetain(value) : NULL;
804 if (old) CFRelease(old);
805 } else if (kCFNumberFormatterNaNSymbolKey == key) {
806 __CFGenericValidateType(value, CFStringGetTypeID());
807 cnt = CFStringGetLength((CFStringRef)value);
808 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
809 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
810 unum_setSymbol(formatter->_nf, UNUM_NAN_SYMBOL, ubuffer, cnt, &status);
811 } else if (kCFNumberFormatterInfinitySymbolKey == key) {
812 __CFGenericValidateType(value, CFStringGetTypeID());
813 cnt = CFStringGetLength((CFStringRef)value);
814 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
815 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
816 unum_setSymbol(formatter->_nf, UNUM_INFINITY_SYMBOL, ubuffer, cnt, &status);
817 } else if (kCFNumberFormatterMinusSignKey == key) {
818 __CFGenericValidateType(value, CFStringGetTypeID());
819 cnt = CFStringGetLength((CFStringRef)value);
820 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
821 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
822 unum_setSymbol(formatter->_nf, UNUM_MINUS_SIGN_SYMBOL, ubuffer, cnt, &status);
823 } else if (kCFNumberFormatterPlusSignKey == key) {
824 __CFGenericValidateType(value, CFStringGetTypeID());
825 cnt = CFStringGetLength((CFStringRef)value);
826 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
827 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
828 unum_setSymbol(formatter->_nf, UNUM_PLUS_SIGN_SYMBOL, ubuffer, cnt, &status);
829 } else if (kCFNumberFormatterCurrencySymbolKey == key) {
830 __CFGenericValidateType(value, CFStringGetTypeID());
831 cnt = CFStringGetLength((CFStringRef)value);
832 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
833 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
834 unum_setSymbol(formatter->_nf, UNUM_CURRENCY_SYMBOL, (const UChar *)ubuffer, cnt, &status);
835 } else if (kCFNumberFormatterExponentSymbolKey == key) {
836 __CFGenericValidateType(value, CFStringGetTypeID());
837 cnt = CFStringGetLength((CFStringRef)value);
838 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
839 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
840 unum_setSymbol(formatter->_nf, UNUM_EXPONENTIAL_SYMBOL, ubuffer, cnt, &status);
841 } else if (kCFNumberFormatterMinIntegerDigitsKey == key) {
842 __CFGenericValidateType(value, CFNumberGetTypeID());
843 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
844 unum_setAttribute(formatter->_nf, UNUM_MIN_INTEGER_DIGITS, n);
845 } else if (kCFNumberFormatterMaxIntegerDigitsKey == key) {
846 __CFGenericValidateType(value, CFNumberGetTypeID());
847 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
848 unum_setAttribute(formatter->_nf, UNUM_MAX_INTEGER_DIGITS, n);
849 } else if (kCFNumberFormatterMinFractionDigitsKey == key) {
850 __CFGenericValidateType(value, CFNumberGetTypeID());
851 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
852 unum_setAttribute(formatter->_nf, UNUM_MIN_FRACTION_DIGITS, n);
853 } else if (kCFNumberFormatterMaxFractionDigitsKey == key) {
854 __CFGenericValidateType(value, CFNumberGetTypeID());
855 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
856 unum_setAttribute(formatter->_nf, UNUM_MAX_FRACTION_DIGITS, n);
857 } else if (kCFNumberFormatterGroupingSizeKey == key) {
858 __CFGenericValidateType(value, CFNumberGetTypeID());
859 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
860 unum_setAttribute(formatter->_nf, UNUM_GROUPING_SIZE, n);
861 } else if (kCFNumberFormatterSecondaryGroupingSizeKey == key) {
862 __CFGenericValidateType(value, CFNumberGetTypeID());
863 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
864 unum_setAttribute(formatter->_nf, UNUM_SECONDARY_GROUPING_SIZE, n);
865 } else if (kCFNumberFormatterRoundingModeKey == key) {
866 __CFGenericValidateType(value, CFNumberGetTypeID());
867 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
868 unum_setAttribute(formatter->_nf, UNUM_ROUNDING_MODE, n);
869 } else if (kCFNumberFormatterRoundingIncrementKey == key) {
870 __CFGenericValidateType(value, CFNumberGetTypeID());
871 CFNumberGetValue((CFNumberRef)value, kCFNumberDoubleType, &d);
872 unum_setDoubleAttribute(formatter->_nf, UNUM_ROUNDING_INCREMENT, d);
873 } else if (kCFNumberFormatterFormatWidthKey == key) {
874 __CFGenericValidateType(value, CFNumberGetTypeID());
875 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
876 unum_setAttribute(formatter->_nf, UNUM_FORMAT_WIDTH, n);
877 } else if (kCFNumberFormatterPaddingPositionKey == key) {
878 __CFGenericValidateType(value, CFNumberGetTypeID());
879 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
880 unum_setAttribute(formatter->_nf, UNUM_PADDING_POSITION, n);
881 } else if (kCFNumberFormatterPaddingCharacterKey == key) {
882 __CFGenericValidateType(value, CFStringGetTypeID());
883 cnt = CFStringGetLength((CFStringRef)value);
884 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
885 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
886 unum_setTextAttribute(formatter->_nf, UNUM_PADDING_CHARACTER, ubuffer, cnt, &status);
887 } else if (kCFNumberFormatterDefaultFormatKey == key) {
888 // read-only attribute
889 } else if (kCFNumberFormatterMultiplierKey == key) {
890 __CFGenericValidateType(value, CFNumberGetTypeID());
891 CFNumberRef old = formatter->_multiplier;
892 formatter->_multiplier = value ? (CFNumberRef)CFRetain(value) : NULL;
893 formatter->_userSetMultiplier = value ? true : false;
894 if (old) CFRelease(old);
895 } else if (kCFNumberFormatterPositivePrefixKey == key) {
896 __CFGenericValidateType(value, CFStringGetTypeID());
897 cnt = CFStringGetLength((CFStringRef)value);
898 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
899 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
900 unum_setTextAttribute(formatter->_nf, UNUM_POSITIVE_PREFIX, ubuffer, cnt, &status);
901 } else if (kCFNumberFormatterPositiveSuffixKey == key) {
902 __CFGenericValidateType(value, CFStringGetTypeID());
903 cnt = CFStringGetLength((CFStringRef)value);
904 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
905 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
906 unum_setTextAttribute(formatter->_nf, UNUM_POSITIVE_SUFFIX, (const UChar *)ubuffer, cnt, &status);
907 } else if (kCFNumberFormatterNegativePrefixKey == key) {
908 __CFGenericValidateType(value, CFStringGetTypeID());
909 cnt = CFStringGetLength((CFStringRef)value);
910 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
911 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
912 unum_setTextAttribute(formatter->_nf, UNUM_NEGATIVE_PREFIX, ubuffer, cnt, &status);
913 } else if (kCFNumberFormatterNegativeSuffixKey == key) {
914 __CFGenericValidateType(value, CFStringGetTypeID());
915 cnt = CFStringGetLength((CFStringRef)value);
916 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
917 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
918 unum_setTextAttribute(formatter->_nf, UNUM_NEGATIVE_SUFFIX, (const UChar *)ubuffer, cnt, &status);
919 } else if (kCFNumberFormatterPerMillSymbolKey == key) {
920 __CFGenericValidateType(value, CFStringGetTypeID());
921 cnt = CFStringGetLength((CFStringRef)value);
922 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
923 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
924 unum_setSymbol(formatter->_nf, UNUM_PERMILL_SYMBOL, ubuffer, cnt, &status);
925 } else if (kCFNumberFormatterInternationalCurrencySymbolKey == key) {
926 __CFGenericValidateType(value, CFStringGetTypeID());
927 cnt = CFStringGetLength((CFStringRef)value);
928 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
929 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
930 unum_setSymbol(formatter->_nf, UNUM_INTL_CURRENCY_SYMBOL, ubuffer, cnt, &status);
931 } else if (kCFNumberFormatterCurrencyGroupingSeparatorKey == key) {
932 __CFGenericValidateType(value, CFStringGetTypeID());
933 cnt = CFStringGetLength((CFStringRef)value);
934 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
935 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
936 unum_setSymbol(formatter->_nf, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, ubuffer, cnt, &status);
937 } else if (kCFNumberFormatterIsLenientKey == key) {
938 __CFGenericValidateType(value, CFBooleanGetTypeID());
939 formatter->_isLenient = (kCFBooleanTrue == value);
940 unum_setAttribute(formatter->_nf, UNUM_LENIENT_PARSE, (kCFBooleanTrue == value));
941 } else if (kCFNumberFormatterUseSignificantDigitsKey == key) {
942 __CFGenericValidateType(value, CFBooleanGetTypeID());
943 unum_setAttribute(formatter->_nf, UNUM_SIGNIFICANT_DIGITS_USED, (kCFBooleanTrue == value));
944 } else if (kCFNumberFormatterMinSignificantDigitsKey == key) {
945 __CFGenericValidateType(value, CFNumberGetTypeID());
946 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
947 unum_setAttribute(formatter->_nf, UNUM_MIN_SIGNIFICANT_DIGITS, n);
948 } else if (kCFNumberFormatterMaxSignificantDigitsKey == key) {
949 __CFGenericValidateType(value, CFNumberGetTypeID());
950 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
951 unum_setAttribute(formatter->_nf, UNUM_MAX_SIGNIFICANT_DIGITS, n);
952 } else {
953 CFAssert3(0, __kCFLogAssertion, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__, key, key);
954 }
955 if (_CFExecutableLinkedOnOrAfter(CFSystemVersionSnowLeopard)) {
956 // do a dummy call to CFNumberFormatterGetFormat() after changing an attribute because
957 // ICU sometimes changes the pattern due to a property change, and we need to poke
958 // unum_toPattern() and also update our own variables
959 CFNumberFormatterGetFormat(formatter);
960 }
961 }
962
963 CFTypeRef CFNumberFormatterCopyProperty(CFNumberFormatterRef formatter, CFStringRef key) {
964 int32_t n;
965 double d;
966 UErrorCode status = U_ZERO_ERROR;
967 UChar ubuffer[BUFFER_SIZE];
968 CFIndex cnt;
969 __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
970 __CFGenericValidateType(key, CFStringGetTypeID());
971 // rule-based formatters don't do attributes and symbols, except for one
972 if (kCFNumberFormatterSpellOutStyle == formatter->_style && kCFNumberFormatterIsLenientKey != key) return NULL;
973 if (kCFNumberFormatterOrdinalStyle == formatter->_style && kCFNumberFormatterIsLenientKey != key) return NULL;
974 if (kCFNumberFormatterDurationStyle == formatter->_style && kCFNumberFormatterIsLenientKey != key) return NULL;
975 if (kCFNumberFormatterCurrencyCodeKey == key) {
976 cnt = unum_getTextAttribute(formatter->_nf, UNUM_CURRENCY_CODE, ubuffer, BUFFER_SIZE, &status);
977 if (U_SUCCESS(status) && cnt == 0) {
978 CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale);
979 char buffer[BUFFER_SIZE];
980 const char *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII);
981 if (NULL == cstr) {
982 if (CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer;
983 }
984 if (NULL == cstr) {
985 return NULL;
986 }
987 UErrorCode status = U_ZERO_ERROR;
988 UNumberFormat *nf = unum_open(UNUM_CURRENCY, NULL, 0, cstr, NULL, &status);
989 if (NULL != nf) {
990 cnt = unum_getTextAttribute(nf, UNUM_CURRENCY_CODE, ubuffer, BUFFER_SIZE, &status);
991 unum_close(nf);
992 }
993 }
994 if (U_SUCCESS(status) && 0 < cnt && cnt <= BUFFER_SIZE) {
995 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
996 }
997 } else if (kCFNumberFormatterDecimalSeparatorKey == key) {
998 cnt = unum_getSymbol(formatter->_nf, UNUM_DECIMAL_SEPARATOR_SYMBOL, ubuffer, BUFFER_SIZE, &status);
999 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1000 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
1001 }
1002 } else if (kCFNumberFormatterCurrencyDecimalSeparatorKey == key) {
1003 cnt = unum_getSymbol(formatter->_nf, UNUM_MONETARY_SEPARATOR_SYMBOL, (UChar *)ubuffer, BUFFER_SIZE, &status);
1004 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1005 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
1006 }
1007 } else if (kCFNumberFormatterAlwaysShowDecimalSeparatorKey == key) {
1008 n = unum_getAttribute(formatter->_nf, UNUM_DECIMAL_ALWAYS_SHOWN);
1009 if (1) {
1010 return CFRetain(n ? kCFBooleanTrue : kCFBooleanFalse);
1011 }
1012 } else if (kCFNumberFormatterGroupingSeparatorKey == key) {
1013 cnt = unum_getSymbol(formatter->_nf, UNUM_GROUPING_SEPARATOR_SYMBOL, ubuffer, BUFFER_SIZE, &status);
1014 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1015 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
1016 }
1017 } else if (kCFNumberFormatterUseGroupingSeparatorKey == key) {
1018 n = unum_getAttribute(formatter->_nf, UNUM_GROUPING_USED);
1019 if (1) {
1020 return CFRetain(n ? kCFBooleanTrue : kCFBooleanFalse);
1021 }
1022 } else if (kCFNumberFormatterPercentSymbolKey == key) {
1023 cnt = unum_getSymbol(formatter->_nf, UNUM_PERCENT_SYMBOL, ubuffer, BUFFER_SIZE, &status);
1024 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1025 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
1026 }
1027 } else if (kCFNumberFormatterZeroSymbolKey == key) {
1028 return formatter->_zeroSym ? CFRetain(formatter->_zeroSym) : NULL;
1029 } else if (kCFNumberFormatterNaNSymbolKey == key) {
1030 cnt = unum_getSymbol(formatter->_nf, UNUM_NAN_SYMBOL, ubuffer, BUFFER_SIZE, &status);
1031 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1032 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
1033 }
1034 } else if (kCFNumberFormatterInfinitySymbolKey == key) {
1035 cnt = unum_getSymbol(formatter->_nf, UNUM_INFINITY_SYMBOL, ubuffer, BUFFER_SIZE, &status);
1036 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1037 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
1038 }
1039 } else if (kCFNumberFormatterMinusSignKey == key) {
1040 cnt = unum_getSymbol(formatter->_nf, UNUM_MINUS_SIGN_SYMBOL, ubuffer, BUFFER_SIZE, &status);
1041 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1042 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
1043 }
1044 } else if (kCFNumberFormatterPlusSignKey == key) {
1045 cnt = unum_getSymbol(formatter->_nf, UNUM_PLUS_SIGN_SYMBOL, ubuffer, BUFFER_SIZE, &status);
1046 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1047 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
1048 }
1049 } else if (kCFNumberFormatterCurrencySymbolKey == key) {
1050 cnt = unum_getSymbol(formatter->_nf, UNUM_CURRENCY_SYMBOL, ubuffer, BUFFER_SIZE, &status);
1051 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1052 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
1053 }
1054 } else if (kCFNumberFormatterExponentSymbolKey == key) {
1055 cnt = unum_getSymbol(formatter->_nf, UNUM_EXPONENTIAL_SYMBOL, ubuffer, BUFFER_SIZE, &status);
1056 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1057 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
1058 }
1059 } else if (kCFNumberFormatterMinIntegerDigitsKey == key) {
1060 n = unum_getAttribute(formatter->_nf, UNUM_MIN_INTEGER_DIGITS);
1061 if (1) {
1062 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
1063 }
1064 } else if (kCFNumberFormatterMaxIntegerDigitsKey == key) {
1065 n = unum_getAttribute(formatter->_nf, UNUM_MAX_INTEGER_DIGITS);
1066 if (1) {
1067 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
1068 }
1069 } else if (kCFNumberFormatterMinFractionDigitsKey == key) {
1070 n = unum_getAttribute(formatter->_nf, UNUM_MIN_FRACTION_DIGITS);
1071 if (1) {
1072 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
1073 }
1074 } else if (kCFNumberFormatterMaxFractionDigitsKey == key) {
1075 n = unum_getAttribute(formatter->_nf, UNUM_MAX_FRACTION_DIGITS);
1076 if (1) {
1077 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
1078 }
1079 } else if (kCFNumberFormatterGroupingSizeKey == key) {
1080 n = unum_getAttribute(formatter->_nf, UNUM_GROUPING_SIZE);
1081 if (1) {
1082 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
1083 }
1084 } else if (kCFNumberFormatterSecondaryGroupingSizeKey == key) {
1085 n = unum_getAttribute(formatter->_nf, UNUM_SECONDARY_GROUPING_SIZE);
1086 if (1) {
1087 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
1088 }
1089 } else if (kCFNumberFormatterRoundingModeKey == key) {
1090 n = unum_getAttribute(formatter->_nf, UNUM_ROUNDING_MODE);
1091 if (1) {
1092 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
1093 }
1094 } else if (kCFNumberFormatterRoundingIncrementKey == key) {
1095 d = unum_getDoubleAttribute(formatter->_nf, UNUM_ROUNDING_INCREMENT);
1096 if (1) {
1097 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberDoubleType, &d);
1098 }
1099 } else if (kCFNumberFormatterFormatWidthKey == key) {
1100 n = unum_getAttribute(formatter->_nf, UNUM_FORMAT_WIDTH);
1101 if (1) {
1102 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
1103 }
1104 } else if (kCFNumberFormatterPaddingPositionKey == key) {
1105 n = unum_getAttribute(formatter->_nf, UNUM_PADDING_POSITION);
1106 if (1) {
1107 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
1108 }
1109 } else if (kCFNumberFormatterPaddingCharacterKey == key) {
1110 cnt = unum_getTextAttribute(formatter->_nf, UNUM_PADDING_CHARACTER, ubuffer, BUFFER_SIZE, &status);
1111 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1112 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
1113 }
1114 } else if (kCFNumberFormatterDefaultFormatKey == key) {
1115 return formatter->_defformat ? CFRetain(formatter->_defformat) : NULL;
1116 } else if (kCFNumberFormatterMultiplierKey == key) {
1117 return formatter->_multiplier ? CFRetain(formatter->_multiplier) : NULL;
1118 } else if (kCFNumberFormatterPositivePrefixKey == key) {
1119 cnt = unum_getTextAttribute(formatter->_nf, UNUM_POSITIVE_PREFIX, ubuffer, BUFFER_SIZE, &status);
1120 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1121 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
1122 }
1123 } else if (kCFNumberFormatterPositiveSuffixKey == key) {
1124 cnt = unum_getTextAttribute(formatter->_nf, UNUM_POSITIVE_SUFFIX, ubuffer, BUFFER_SIZE, &status);
1125 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1126 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
1127 }
1128 } else if (kCFNumberFormatterNegativePrefixKey == key) {
1129 cnt = unum_getTextAttribute(formatter->_nf, UNUM_NEGATIVE_PREFIX, ubuffer, BUFFER_SIZE, &status);
1130 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1131 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
1132 }
1133 } else if (kCFNumberFormatterNegativeSuffixKey == key) {
1134 cnt = unum_getTextAttribute(formatter->_nf, UNUM_NEGATIVE_SUFFIX, ubuffer, BUFFER_SIZE, &status);
1135 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1136 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
1137 }
1138 } else if (kCFNumberFormatterPerMillSymbolKey == key) {
1139 cnt = unum_getSymbol(formatter->_nf, UNUM_PERMILL_SYMBOL, ubuffer, BUFFER_SIZE, &status);
1140 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1141 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
1142 }
1143 } else if (kCFNumberFormatterInternationalCurrencySymbolKey == key) {
1144 cnt = unum_getSymbol(formatter->_nf, UNUM_INTL_CURRENCY_SYMBOL, ubuffer, BUFFER_SIZE, &status);
1145 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1146 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
1147 }
1148 } else if (kCFNumberFormatterCurrencyGroupingSeparatorKey == key) {
1149 cnt = unum_getSymbol(formatter->_nf, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, ubuffer, BUFFER_SIZE, &status);
1150 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1151 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
1152 }
1153 } else if (kCFNumberFormatterIsLenientKey == key) {
1154 // unum_getAttribute(, UNUM_LENIENT_PARSE) is undefined.
1155 return CFRetain(formatter->_isLenient ? kCFBooleanTrue : kCFBooleanFalse);
1156 } else if (kCFNumberFormatterUseSignificantDigitsKey == key) {
1157 n = unum_getAttribute(formatter->_nf, UNUM_SIGNIFICANT_DIGITS_USED);
1158 if (1) {
1159 return CFRetain(n ? kCFBooleanTrue : kCFBooleanFalse);
1160 }
1161 } else if (kCFNumberFormatterMinSignificantDigitsKey == key) {
1162 n = unum_getAttribute(formatter->_nf, UNUM_MIN_SIGNIFICANT_DIGITS);
1163 if (1) {
1164 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
1165 }
1166 } else if (kCFNumberFormatterMaxSignificantDigitsKey == key) {
1167 n = unum_getAttribute(formatter->_nf, UNUM_MAX_SIGNIFICANT_DIGITS);
1168 if (1) {
1169 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
1170 }
1171 } else {
1172 CFAssert3(0, __kCFLogAssertion, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__, key, key);
1173 }
1174 return NULL;
1175 }
1176
1177
1178 Boolean CFNumberFormatterGetDecimalInfoForCurrencyCode(CFStringRef currencyCode, int32_t *defaultFractionDigits, double *roundingIncrement) {
1179 UChar ubuffer[4];
1180 __CFGenericValidateType(currencyCode, CFStringGetTypeID());
1181 CFAssert1(3 == CFStringGetLength(currencyCode), __kCFLogAssertion, "%s(): currencyCode is not 3 characters", __PRETTY_FUNCTION__);
1182 CFStringGetCharacters(currencyCode, CFRangeMake(0, 3), (UniChar *)ubuffer);
1183 ubuffer[3] = 0;
1184 UErrorCode icuStatus = U_ZERO_ERROR;
1185 if (defaultFractionDigits) *defaultFractionDigits = ucurr_getDefaultFractionDigits(ubuffer, &icuStatus);
1186 if (roundingIncrement) *roundingIncrement = ucurr_getRoundingIncrement(ubuffer, &icuStatus);
1187 if (U_FAILURE(icuStatus))
1188 return false;
1189 return (!defaultFractionDigits || 0 <= *defaultFractionDigits) && (!roundingIncrement || 0.0 <= *roundingIncrement);
1190 }
1191
1192 #undef BUFFER_SIZE
1193