]> git.saurik.com Git - apple/cf.git/blob - CFNumberFormatter.c
CF-476.15.tar.gz
[apple/cf.git] / CFNumberFormatter.c
1 /*
2 * Copyright (c) 2008 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 /* CFNumberFormatter.c
24 Copyright 2002-2003, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
26 */
27
28 #include <CoreFoundation/CFNumberFormatter.h>
29 #include "CFInternal.h"
30 #include <unicode/unum.h>
31 #include <unicode/ucurr.h>
32 #include <math.h>
33 #include <float.h>
34
35 static void __CFNumberFormatterCustomize(CFNumberFormatterRef formatter);
36
37 #define BUFFER_SIZE 768
38
39 struct __CFNumberFormatter {
40 CFRuntimeBase _base;
41 UNumberFormat *_nf;
42 CFLocaleRef _locale;
43 CFNumberFormatterStyle _style;
44 CFStringRef _format; // NULL for RBNFs
45 CFStringRef _defformat;
46 CFNumberRef _multiplier;
47 CFStringRef _zeroSym;
48 };
49
50 static CFStringRef __CFNumberFormatterCopyDescription(CFTypeRef cf) {
51 CFNumberFormatterRef formatter = (CFNumberFormatterRef)cf;
52 return CFStringCreateWithFormat(CFGetAllocator(formatter), NULL, CFSTR("<CFNumberFormatter %p [%p]>"), cf, CFGetAllocator(formatter));
53 }
54
55 static void __CFNumberFormatterDeallocate(CFTypeRef cf) {
56 CFNumberFormatterRef formatter = (CFNumberFormatterRef)cf;
57 if (formatter->_nf) unum_close(formatter->_nf);
58 if (formatter->_locale) CFRelease(formatter->_locale);
59 if (formatter->_format) CFRelease(formatter->_format);
60 if (formatter->_defformat) CFRelease(formatter->_defformat);
61 if (formatter->_multiplier) CFRelease(formatter->_multiplier);
62 if (formatter->_zeroSym) CFRelease(formatter->_zeroSym);
63 }
64
65 static CFTypeID __kCFNumberFormatterTypeID = _kCFRuntimeNotATypeID;
66
67 static const CFRuntimeClass __CFNumberFormatterClass = {
68 0,
69 "CFNumberFormatter",
70 NULL, // init
71 NULL, // copy
72 __CFNumberFormatterDeallocate,
73 NULL,
74 NULL,
75 NULL, //
76 __CFNumberFormatterCopyDescription
77 };
78
79 static void __CFNumberFormatterInitialize(void) {
80 __kCFNumberFormatterTypeID = _CFRuntimeRegisterClass(&__CFNumberFormatterClass);
81 }
82
83 CFTypeID CFNumberFormatterGetTypeID(void) {
84 if (_kCFRuntimeNotATypeID == __kCFNumberFormatterTypeID) __CFNumberFormatterInitialize();
85 return __kCFNumberFormatterTypeID;
86 }
87
88 CFNumberFormatterRef CFNumberFormatterCreate(CFAllocatorRef allocator, CFLocaleRef locale, CFNumberFormatterStyle style) {
89 struct __CFNumberFormatter *memory;
90 uint32_t size = sizeof(struct __CFNumberFormatter) - sizeof(CFRuntimeBase);
91 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
92 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
93 __CFGenericValidateType(locale, CFLocaleGetTypeID());
94 memory = (struct __CFNumberFormatter *)_CFRuntimeCreateInstance(allocator, CFNumberFormatterGetTypeID(), size, NULL);
95 if (NULL == memory) {
96 return NULL;
97 }
98 memory->_nf = NULL;
99 memory->_locale = NULL;
100 memory->_format = NULL;
101 memory->_defformat = NULL;
102 memory->_multiplier = NULL;
103 memory->_zeroSym = NULL;
104 if (NULL == locale) locale = CFLocaleGetSystem();
105 memory->_style = style;
106 uint32_t ustyle;
107 switch (style) {
108 case kCFNumberFormatterNoStyle: ustyle = UNUM_IGNORE; break;
109 case kCFNumberFormatterDecimalStyle: ustyle = UNUM_DECIMAL; break;
110 case kCFNumberFormatterCurrencyStyle: ustyle = UNUM_CURRENCY; break;
111 case kCFNumberFormatterPercentStyle: ustyle = UNUM_PERCENT; break;
112 case kCFNumberFormatterScientificStyle: ustyle = UNUM_SCIENTIFIC; break;
113 case kCFNumberFormatterSpellOutStyle: ustyle = UNUM_SPELLOUT; break;
114 default:
115 CFAssert2(0, __kCFLogAssertion, "%s(): unknown style %d", __PRETTY_FUNCTION__, style);
116 ustyle = UNUM_DECIMAL;
117 memory->_style = kCFNumberFormatterDecimalStyle;
118 break;
119 }
120 CFStringRef localeName = locale ? CFLocaleGetIdentifier(locale) : CFSTR("");
121 char buffer[BUFFER_SIZE];
122 const char *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII);
123 if (NULL == cstr) {
124 if (CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer;
125 }
126 if (NULL == cstr) {
127 CFRelease(memory);
128 return NULL;
129 }
130 UErrorCode status = U_ZERO_ERROR;
131 memory->_nf = unum_open((UNumberFormatStyle)ustyle, NULL, 0, cstr, NULL, &status);
132 CFAssert2(memory->_nf, __kCFLogAssertion, "%s(): error (%d) creating number formatter", __PRETTY_FUNCTION__, status);
133 if (NULL == memory->_nf) {
134 CFRelease(memory);
135 return NULL;
136 }
137 UChar ubuff[4];
138 if (kCFNumberFormatterNoStyle == style) {
139 status = U_ZERO_ERROR;
140 ubuff[0] = '#'; ubuff[1] = ';'; ubuff[2] = '#';
141 unum_applyPattern(memory->_nf, false, ubuff, 3, NULL, &status);
142 unum_setAttribute(memory->_nf, UNUM_MAX_INTEGER_DIGITS, 42);
143 unum_setAttribute(memory->_nf, UNUM_MAX_FRACTION_DIGITS, 0);
144 }
145 memory->_locale = locale ? CFLocaleCreateCopy(allocator, locale) : CFLocaleGetSystem();
146 __CFNumberFormatterCustomize(memory);
147 if (kCFNumberFormatterSpellOutStyle != memory->_style) {
148 UChar ubuffer[BUFFER_SIZE];
149 status = U_ZERO_ERROR;
150 int32_t ret = unum_toPattern(memory->_nf, false, ubuffer, BUFFER_SIZE, &status);
151 if (U_SUCCESS(status) && ret <= BUFFER_SIZE) {
152 memory->_format = CFStringCreateWithCharacters(allocator, (const UniChar *)ubuffer, ret);
153 }
154 }
155 memory->_defformat = memory->_format ? (CFStringRef)CFRetain(memory->_format) : NULL;
156 if (kCFNumberFormatterSpellOutStyle != memory->_style) {
157 int32_t n = unum_getAttribute(memory->_nf, UNUM_MULTIPLIER);
158 if (1 != n) {
159 memory->_multiplier = CFNumberCreate(allocator, kCFNumberSInt32Type, &n);
160 unum_setAttribute(memory->_nf, UNUM_MULTIPLIER, 1);
161 }
162 }
163 return (CFNumberFormatterRef)memory;
164 }
165
166 extern CFDictionaryRef __CFLocaleGetPrefs(CFLocaleRef locale);
167
168 static void __substituteFormatStringFromPrefsNF(CFNumberFormatterRef formatter) {
169 CFIndex formatStyle = formatter->_style;
170 if (kCFNumberFormatterSpellOutStyle == formatStyle) return;
171 CFStringRef prefName = CFSTR("AppleICUNumberFormatStrings");
172 if (kCFNumberFormatterNoStyle != formatStyle) {
173 CFStringRef pref = NULL;
174 CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale);
175 CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, prefName) : NULL;
176 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) {
177 CFStringRef key;
178 switch (formatStyle) {
179 case kCFNumberFormatterDecimalStyle: key = CFSTR("1"); break;
180 case kCFNumberFormatterCurrencyStyle: key = CFSTR("2"); break;
181 case kCFNumberFormatterPercentStyle: key = CFSTR("3"); break;
182 case kCFNumberFormatterScientificStyle: key = CFSTR("4"); break;
183 case kCFNumberFormatterSpellOutStyle: key = CFSTR("5"); break;
184 default: key = CFSTR("0"); break;
185 }
186 pref = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)metapref, key);
187 }
188 if (NULL != pref && CFGetTypeID(pref) == CFStringGetTypeID()) {
189 int32_t icustyle = UNUM_IGNORE;
190 switch (formatStyle) {
191 case kCFNumberFormatterDecimalStyle: icustyle = UNUM_DECIMAL; break;
192 case kCFNumberFormatterCurrencyStyle: icustyle = UNUM_CURRENCY; break;
193 case kCFNumberFormatterPercentStyle: icustyle = UNUM_PERCENT; break;
194 case kCFNumberFormatterScientificStyle: icustyle = UNUM_SCIENTIFIC; break;
195 case kCFNumberFormatterSpellOutStyle: icustyle = UNUM_SPELLOUT; break;
196 }
197 CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale);
198 char buffer[BUFFER_SIZE];
199 const char *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII);
200 if (NULL == cstr) {
201 if (CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer;
202 }
203 UErrorCode status = U_ZERO_ERROR;
204 UNumberFormat *nf = unum_open((UNumberFormatStyle)icustyle, NULL, 0, cstr, NULL, &status);
205 if (NULL != nf) {
206 UChar ubuffer[BUFFER_SIZE];
207 status = U_ZERO_ERROR;
208 int32_t number_len = unum_toPattern(nf, false, ubuffer, BUFFER_SIZE, &status);
209 if (U_SUCCESS(status) && number_len <= BUFFER_SIZE) {
210 CFStringRef numberString = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)ubuffer, number_len);
211 status = U_ZERO_ERROR;
212 int32_t formatter_len = unum_toPattern(formatter->_nf, false, ubuffer, BUFFER_SIZE, &status);
213 if (U_SUCCESS(status) && formatter_len <= BUFFER_SIZE) {
214 CFMutableStringRef formatString = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
215 CFStringAppendCharacters(formatString, (const UniChar *)ubuffer, formatter_len);
216 // find numberString inside formatString, substitute the pref in that range
217 CFRange result;
218 if (CFStringFindWithOptions(formatString, numberString, CFRangeMake(0, formatter_len), 0, &result)) {
219 CFStringReplace(formatString, result, pref);
220 int32_t new_len = CFStringGetLength(formatString);
221 STACK_BUFFER_DECL(UChar, new_buffer, new_len);
222 const UChar *new_ustr = (const UChar *)CFStringGetCharactersPtr(formatString);
223 if (NULL == new_ustr) {
224 CFStringGetCharacters(formatString, CFRangeMake(0, new_len), (UniChar *)new_buffer);
225 new_ustr = new_buffer;
226 }
227 status = U_ZERO_ERROR;
228 unum_applyPattern(formatter->_nf, false, new_ustr, new_len, NULL, &status);
229 }
230 CFRelease(formatString);
231 }
232 CFRelease(numberString);
233 }
234 unum_close(nf);
235 }
236 }
237 }
238 }
239
240 static void __CFNumberFormatterApplySymbolPrefs(const void *key, const void *value, void *context) {
241 if (CFGetTypeID(key) == CFStringGetTypeID() && CFGetTypeID(value) == CFStringGetTypeID()) {
242 CFNumberFormatterRef formatter = (CFNumberFormatterRef)context;
243 UNumberFormatSymbol sym = (UNumberFormatSymbol)CFStringGetIntValue((CFStringRef)key);
244 CFStringRef item = (CFStringRef)value;
245 CFIndex item_cnt = CFStringGetLength(item);
246 STACK_BUFFER_DECL(UChar, item_buffer, item_cnt);
247 UChar *item_ustr = (UChar *)CFStringGetCharactersPtr(item);
248 if (NULL == item_ustr) {
249 CFStringGetCharacters(item, CFRangeMake(0, __CFMin(BUFFER_SIZE, item_cnt)), (UniChar *)item_buffer);
250 item_ustr = item_buffer;
251 }
252 UErrorCode status = U_ZERO_ERROR;
253 unum_setSymbol(formatter->_nf, sym, item_ustr, item_cnt, &status);
254 }
255 }
256
257 static void __CFNumberFormatterCustomize(CFNumberFormatterRef formatter) {
258 __substituteFormatStringFromPrefsNF(formatter);
259 CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale);
260 CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUNumberSymbols")) : NULL;
261 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) {
262 CFDictionaryApplyFunction((CFDictionaryRef)metapref, __CFNumberFormatterApplySymbolPrefs, formatter);
263 }
264 }
265
266 CFLocaleRef CFNumberFormatterGetLocale(CFNumberFormatterRef formatter) {
267 __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
268 return formatter->_locale;
269 }
270
271 CFNumberFormatterStyle CFNumberFormatterGetStyle(CFNumberFormatterRef formatter) {
272 __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
273 return formatter->_style;
274 }
275
276 CFStringRef CFNumberFormatterGetFormat(CFNumberFormatterRef formatter) {
277 __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
278 if (kCFNumberFormatterSpellOutStyle == formatter->_style) return NULL;
279 UChar ubuffer[BUFFER_SIZE];
280 CFStringRef newString = NULL;
281 UErrorCode status = U_ZERO_ERROR;
282 int32_t ret = unum_toPattern(formatter->_nf, false, ubuffer, BUFFER_SIZE, &status);
283 if (U_SUCCESS(status) && ret <= BUFFER_SIZE) {
284 newString = CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, ret);
285 }
286 if (newString && !formatter->_format) {
287 formatter->_format = newString;
288 } else if (newString && !CFEqual(newString, formatter->_format)) {
289 CFRelease(formatter->_format);
290 formatter->_format = newString;
291 } else if (newString) {
292 CFRelease(newString);
293 }
294 return formatter->_format;
295 }
296
297 void CFNumberFormatterSetFormat(CFNumberFormatterRef formatter, CFStringRef formatString) {
298 __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
299 __CFGenericValidateType(formatString, CFStringGetTypeID());
300 if (kCFNumberFormatterSpellOutStyle == formatter->_style) return;
301 CFIndex cnt = CFStringGetLength(formatString);
302 CFAssert1(cnt <= 1024, __kCFLogAssertion, "%s(): format string too long", __PRETTY_FUNCTION__);
303 if ((!formatter->_format || !CFEqual(formatter->_format, formatString)) && cnt <= 1024) {
304 STACK_BUFFER_DECL(UChar, ubuffer, cnt);
305 const UChar *ustr = (const UChar *)CFStringGetCharactersPtr(formatString);
306 if (NULL == ustr) {
307 CFStringGetCharacters(formatString, CFRangeMake(0, cnt), (UniChar *)ubuffer);
308 ustr = ubuffer;
309 }
310 UErrorCode status = U_ZERO_ERROR;
311 unum_applyPattern(formatter->_nf, false, ustr, cnt, NULL, &status);
312 if (U_SUCCESS(status)) {
313 if (formatter->_format) CFRelease(formatter->_format);
314 UChar ubuffer2[BUFFER_SIZE];
315 status = U_ZERO_ERROR;
316 int32_t ret = unum_toPattern(formatter->_nf, false, ubuffer2, BUFFER_SIZE, &status);
317 if (U_SUCCESS(status) && ret <= BUFFER_SIZE) {
318 formatter->_format = CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer2, ret);
319 }
320 }
321 }
322 }
323
324 CFStringRef CFNumberFormatterCreateStringWithNumber(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFNumberRef number) {
325 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
326 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
327 __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
328 __CFGenericValidateType(number, CFNumberGetTypeID());
329 CFNumberType type = CFNumberGetType(number);
330 char buffer[64];
331 CFNumberGetValue(number, type, buffer);
332 return CFNumberFormatterCreateStringWithValue(allocator, formatter, type, buffer);
333 }
334
335 #define FORMAT(T, FUNC) \
336 T value = *(T *)valuePtr; \
337 if (0 == value && formatter->_zeroSym) { return (CFStringRef)CFRetain(formatter->_zeroSym); } \
338 if (1.0 != multiplier) value = (T)(value * multiplier); \
339 status = U_ZERO_ERROR; \
340 used = FUNC(formatter->_nf, value, ubuffer, cnt, NULL, &status); \
341 if (status == U_BUFFER_OVERFLOW_ERROR || cnt < used) { \
342 cnt = used + 1; \
343 ustr = (UChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UChar) * cnt, 0); \
344 status = U_ZERO_ERROR; \
345 used = FUNC(formatter->_nf, value, ustr, cnt, NULL, &status); \
346 }
347
348 CFStringRef CFNumberFormatterCreateStringWithValue(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFNumberType numberType, const void *valuePtr) {
349 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
350 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
351 __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
352 double multiplier = 1.0;
353 if (formatter->_multiplier) {
354 if (!CFNumberGetValue(formatter->_multiplier, kCFNumberFloat64Type, &multiplier)) {
355 multiplier = 1.0;
356 }
357 }
358 UChar *ustr = NULL, ubuffer[BUFFER_SIZE];
359 UErrorCode status = U_ZERO_ERROR;
360 CFIndex used, cnt = BUFFER_SIZE;
361 if (numberType == kCFNumberFloat64Type || numberType == kCFNumberDoubleType) {
362 FORMAT(double, unum_formatDouble)
363 } else if (numberType == kCFNumberFloat32Type || numberType == kCFNumberFloatType) {
364 FORMAT(float, unum_formatDouble)
365 } else if (numberType == kCFNumberSInt64Type || numberType == kCFNumberLongLongType) {
366 FORMAT(int64_t, unum_formatInt64)
367 } else if (numberType == kCFNumberLongType || numberType == kCFNumberCFIndexType) {
368 #if __LP64__
369 FORMAT(int64_t, unum_formatInt64)
370 #else
371 FORMAT(int32_t, unum_formatInt64)
372 #endif
373 } else if (numberType == kCFNumberSInt32Type || numberType == kCFNumberIntType) {
374 FORMAT(int32_t, unum_formatInt64)
375 } else if (numberType == kCFNumberSInt16Type || numberType == kCFNumberShortType) {
376 FORMAT(int16_t, unum_formatInt64)
377 } else if (numberType == kCFNumberSInt8Type || numberType == kCFNumberCharType) {
378 FORMAT(int8_t, unum_formatInt64)
379 } else {
380 CFAssert2(0, __kCFLogAssertion, "%s(): unknown CFNumberType (%d)", __PRETTY_FUNCTION__, numberType);
381 return NULL;
382 }
383 CFStringRef string = NULL;
384 if (U_SUCCESS(status)) {
385 string = CFStringCreateWithCharacters(allocator, ustr ? (const UniChar *)ustr : (const UniChar *)ubuffer, used);
386 }
387 if (ustr) CFAllocatorDeallocate(kCFAllocatorSystemDefault, ustr);
388 return string;
389 }
390
391 #undef FORMAT
392
393 CFNumberRef CFNumberFormatterCreateNumberFromString(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFStringRef string, CFRange *rangep, CFOptionFlags options) {
394 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
395 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
396 __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
397 __CFGenericValidateType(string, CFStringGetTypeID());
398 CFNumberType type = (options & kCFNumberFormatterParseIntegersOnly) ? kCFNumberSInt64Type : kCFNumberFloat64Type;
399 char buffer[16];
400 if (CFNumberFormatterGetValueFromString(formatter, string, rangep, type, buffer)) {
401 return CFNumberCreate(allocator, type, buffer);
402 }
403 return NULL;
404 }
405
406 Boolean CFNumberFormatterGetValueFromString(CFNumberFormatterRef formatter, CFStringRef string, CFRange *rangep, CFNumberType numberType, void *valuePtr) {
407 __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
408 __CFGenericValidateType(string, CFStringGetTypeID());
409 Boolean isZero = false;
410 CFRange range = {0, 0};
411 if (rangep) {
412 range = *rangep;
413 } else {
414 range.length = CFStringGetLength(string);
415 }
416 if (formatter->_zeroSym && kCFCompareEqualTo == CFStringCompareWithOptions(string, formatter->_zeroSym, range, 0)) {
417 isZero = true;
418 }
419 if (1024 < range.length) range.length = 1024;
420 const UChar *ustr = (const UChar *)CFStringGetCharactersPtr(string);
421 STACK_BUFFER_DECL(UChar, ubuffer, (NULL == ustr) ? range.length : 1);
422 if (NULL == ustr) {
423 CFStringGetCharacters(string, range, (UniChar *)ubuffer);
424 ustr = ubuffer;
425 } else {
426 ustr += range.location;
427 }
428 Boolean integerOnly = 1;
429 switch (numberType) {
430 case kCFNumberSInt8Type: case kCFNumberCharType:
431 case kCFNumberSInt16Type: case kCFNumberShortType:
432 case kCFNumberSInt32Type: case kCFNumberIntType:
433 case kCFNumberLongType: case kCFNumberCFIndexType:
434 case kCFNumberSInt64Type: case kCFNumberLongLongType:
435 unum_setAttribute(formatter->_nf, UNUM_PARSE_INT_ONLY, 1);
436 break;
437 default:
438 unum_setAttribute(formatter->_nf, UNUM_PARSE_INT_ONLY, 0);
439 integerOnly = 0;
440 break;
441 }
442 int32_t dpos = 0;
443 UErrorCode status = U_ZERO_ERROR;
444 int64_t dreti = 0;
445 double dretd = 0.0;
446 if (isZero) {
447 dpos = rangep ? rangep->length : 0;
448 } else {
449 if (integerOnly) {
450 dreti = unum_parseInt64(formatter->_nf, ustr, range.length, &dpos, &status);
451 } else {
452 dretd = unum_parseDouble(formatter->_nf, ustr, range.length, &dpos, &status);
453 }
454 }
455 if (rangep) rangep->length = dpos;
456 if (U_FAILURE(status)) {
457 return false;
458 }
459 if (formatter->_multiplier) {
460 double multiplier = 1.0;
461 if (!CFNumberGetValue(formatter->_multiplier, kCFNumberFloat64Type, &multiplier)) {
462 multiplier = 1.0;
463 }
464 dreti = (int64_t)((double)dreti / multiplier); // integer truncation
465 dretd = dretd / multiplier;
466 }
467 switch (numberType) {
468 case kCFNumberSInt8Type: case kCFNumberCharType:
469 if (INT8_MIN <= dreti && dreti <= INT8_MAX) {
470 *(int8_t *)valuePtr = (int8_t)dreti;
471 return true;
472 }
473 break;
474 case kCFNumberSInt16Type: case kCFNumberShortType:
475 if (INT16_MIN <= dreti && dreti <= INT16_MAX) {
476 *(int16_t *)valuePtr = (int16_t)dreti;
477 return true;
478 }
479 break;
480 case kCFNumberSInt32Type: case kCFNumberIntType:
481 #if !__LP64__
482 case kCFNumberLongType: case kCFNumberCFIndexType:
483 #endif
484 if (INT32_MIN <= dreti && dreti <= INT32_MAX) {
485 *(int32_t *)valuePtr = (int32_t)dreti;
486 return true;
487 }
488 break;
489 case kCFNumberSInt64Type: case kCFNumberLongLongType:
490 #if __LP64__
491 case kCFNumberLongType: case kCFNumberCFIndexType:
492 #endif
493 if (INT64_MIN <= dreti && dreti <= INT64_MAX) {
494 *(int64_t *)valuePtr = (int64_t)dreti;
495 return true;
496 }
497 break;
498 case kCFNumberFloat32Type: case kCFNumberFloatType:
499 if (-FLT_MAX <= dretd && dretd <= FLT_MAX) {
500 *(float *)valuePtr = (float)dretd;
501 return true;
502 }
503 break;
504 case kCFNumberFloat64Type: case kCFNumberDoubleType:
505 if (-DBL_MAX <= dretd && dretd <= DBL_MAX) {
506 *(double *)valuePtr = (double)dretd;
507 return true;
508 }
509 break;
510 }
511 return false;
512 }
513
514 void CFNumberFormatterSetProperty(CFNumberFormatterRef formatter, CFStringRef key, CFTypeRef value) {
515 int32_t n;
516 double d;
517 UErrorCode status = U_ZERO_ERROR;
518 UChar ubuffer[BUFFER_SIZE];
519 CFIndex cnt;
520 __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
521 __CFGenericValidateType(key, CFStringGetTypeID());
522 if (kCFNumberFormatterCurrencyCode == key) {
523 __CFGenericValidateType(value, CFStringGetTypeID());
524 cnt = CFStringGetLength((CFStringRef)value);
525 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
526 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
527 unum_setTextAttribute(formatter->_nf, UNUM_CURRENCY_CODE, ubuffer, cnt, &status);
528 } else if (kCFNumberFormatterDecimalSeparator == key) {
529 __CFGenericValidateType(value, CFStringGetTypeID());
530 cnt = CFStringGetLength((CFStringRef)value);
531 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
532 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
533 unum_setSymbol(formatter->_nf, UNUM_DECIMAL_SEPARATOR_SYMBOL, ubuffer, cnt, &status);
534 } else if (kCFNumberFormatterCurrencyDecimalSeparator == key) {
535 __CFGenericValidateType(value, CFStringGetTypeID());
536 cnt = CFStringGetLength((CFStringRef)value);
537 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
538 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
539 unum_setSymbol(formatter->_nf, UNUM_MONETARY_SEPARATOR_SYMBOL, ubuffer, cnt, &status);
540 } else if (kCFNumberFormatterAlwaysShowDecimalSeparator == key) {
541 __CFGenericValidateType(value, CFBooleanGetTypeID());
542 unum_setAttribute(formatter->_nf, UNUM_DECIMAL_ALWAYS_SHOWN, (kCFBooleanTrue == value));
543 } else if (kCFNumberFormatterGroupingSeparator == key) {
544 __CFGenericValidateType(value, CFStringGetTypeID());
545 cnt = CFStringGetLength((CFStringRef)value);
546 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
547 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
548 unum_setSymbol(formatter->_nf, UNUM_GROUPING_SEPARATOR_SYMBOL, (const UChar *)ubuffer, cnt, &status);
549 } else if (kCFNumberFormatterUseGroupingSeparator == key) {
550 __CFGenericValidateType(value, CFBooleanGetTypeID());
551 unum_setAttribute(formatter->_nf, UNUM_GROUPING_USED, (kCFBooleanTrue == value));
552 } else if (kCFNumberFormatterPercentSymbol == key) {
553 __CFGenericValidateType(value, CFStringGetTypeID());
554 cnt = CFStringGetLength((CFStringRef)value);
555 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
556 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
557 unum_setSymbol(formatter->_nf, UNUM_PERCENT_SYMBOL, ubuffer, cnt, &status);
558 } else if (kCFNumberFormatterZeroSymbol == key) {
559 __CFGenericValidateType(value, CFStringGetTypeID());
560 CFStringRef old = formatter->_zeroSym;
561 formatter->_zeroSym = value ? (CFStringRef)CFRetain(value) : NULL;
562 if (old) CFRelease(old);
563 } else if (kCFNumberFormatterNaNSymbol == key) {
564 __CFGenericValidateType(value, CFStringGetTypeID());
565 cnt = CFStringGetLength((CFStringRef)value);
566 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
567 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
568 unum_setSymbol(formatter->_nf, UNUM_NAN_SYMBOL, ubuffer, cnt, &status);
569 } else if (kCFNumberFormatterInfinitySymbol == key) {
570 __CFGenericValidateType(value, CFStringGetTypeID());
571 cnt = CFStringGetLength((CFStringRef)value);
572 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
573 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
574 unum_setSymbol(formatter->_nf, UNUM_INFINITY_SYMBOL, ubuffer, cnt, &status);
575 } else if (kCFNumberFormatterMinusSign == key) {
576 __CFGenericValidateType(value, CFStringGetTypeID());
577 cnt = CFStringGetLength((CFStringRef)value);
578 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
579 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
580 unum_setSymbol(formatter->_nf, UNUM_MINUS_SIGN_SYMBOL, ubuffer, cnt, &status);
581 } else if (kCFNumberFormatterPlusSign == key) {
582 __CFGenericValidateType(value, CFStringGetTypeID());
583 cnt = CFStringGetLength((CFStringRef)value);
584 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
585 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
586 unum_setSymbol(formatter->_nf, UNUM_PLUS_SIGN_SYMBOL, ubuffer, cnt, &status);
587 } else if (kCFNumberFormatterCurrencySymbol == key) {
588 __CFGenericValidateType(value, CFStringGetTypeID());
589 cnt = CFStringGetLength((CFStringRef)value);
590 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
591 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
592 unum_setSymbol(formatter->_nf, UNUM_CURRENCY_SYMBOL, (const UChar *)ubuffer, cnt, &status);
593 } else if (kCFNumberFormatterExponentSymbol == key) {
594 __CFGenericValidateType(value, CFStringGetTypeID());
595 cnt = CFStringGetLength((CFStringRef)value);
596 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
597 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
598 unum_setSymbol(formatter->_nf, UNUM_EXPONENTIAL_SYMBOL, ubuffer, cnt, &status);
599 } else if (kCFNumberFormatterMinIntegerDigits == key) {
600 __CFGenericValidateType(value, CFNumberGetTypeID());
601 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
602 unum_setAttribute(formatter->_nf, UNUM_MIN_INTEGER_DIGITS, n);
603 } else if (kCFNumberFormatterMaxIntegerDigits == key) {
604 __CFGenericValidateType(value, CFNumberGetTypeID());
605 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
606 unum_setAttribute(formatter->_nf, UNUM_MAX_INTEGER_DIGITS, n);
607 } else if (kCFNumberFormatterMinFractionDigits == key) {
608 __CFGenericValidateType(value, CFNumberGetTypeID());
609 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
610 unum_setAttribute(formatter->_nf, UNUM_MIN_FRACTION_DIGITS, n);
611 } else if (kCFNumberFormatterMaxFractionDigits == key) {
612 __CFGenericValidateType(value, CFNumberGetTypeID());
613 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
614 unum_setAttribute(formatter->_nf, UNUM_MAX_FRACTION_DIGITS, n);
615 } else if (kCFNumberFormatterGroupingSize == key) {
616 __CFGenericValidateType(value, CFNumberGetTypeID());
617 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
618 unum_setAttribute(formatter->_nf, UNUM_GROUPING_SIZE, n);
619 } else if (kCFNumberFormatterSecondaryGroupingSize == key) {
620 __CFGenericValidateType(value, CFNumberGetTypeID());
621 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
622 unum_setAttribute(formatter->_nf, UNUM_SECONDARY_GROUPING_SIZE, n);
623 } else if (kCFNumberFormatterRoundingMode == key) {
624 __CFGenericValidateType(value, CFNumberGetTypeID());
625 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
626 unum_setAttribute(formatter->_nf, UNUM_ROUNDING_MODE, n);
627 } else if (kCFNumberFormatterRoundingIncrement == key) {
628 __CFGenericValidateType(value, CFNumberGetTypeID());
629 CFNumberGetValue((CFNumberRef)value, kCFNumberDoubleType, &d);
630 unum_setDoubleAttribute(formatter->_nf, UNUM_ROUNDING_INCREMENT, d);
631 } else if (kCFNumberFormatterFormatWidth == key) {
632 __CFGenericValidateType(value, CFNumberGetTypeID());
633 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
634 unum_setAttribute(formatter->_nf, UNUM_FORMAT_WIDTH, n);
635 } else if (kCFNumberFormatterPaddingPosition == key) {
636 __CFGenericValidateType(value, CFNumberGetTypeID());
637 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
638 unum_setAttribute(formatter->_nf, UNUM_PADDING_POSITION, n);
639 } else if (kCFNumberFormatterPaddingCharacter == key) {
640 __CFGenericValidateType(value, CFStringGetTypeID());
641 cnt = CFStringGetLength((CFStringRef)value);
642 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
643 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
644 unum_setTextAttribute(formatter->_nf, UNUM_PADDING_CHARACTER, ubuffer, cnt, &status);
645 } else if (kCFNumberFormatterDefaultFormat == key) {
646 // read-only attribute
647 } else if (kCFNumberFormatterMultiplier == key) {
648 __CFGenericValidateType(value, CFNumberGetTypeID());
649 CFNumberRef old = formatter->_multiplier;
650 formatter->_multiplier = value ? (CFNumberRef)CFRetain(value) : NULL;
651 if (old) CFRelease(old);
652 } else if (kCFNumberFormatterPositivePrefix == key) {
653 __CFGenericValidateType(value, CFStringGetTypeID());
654 cnt = CFStringGetLength((CFStringRef)value);
655 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
656 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
657 unum_setTextAttribute(formatter->_nf, UNUM_POSITIVE_PREFIX, ubuffer, cnt, &status);
658 } else if (kCFNumberFormatterPositiveSuffix == key) {
659 __CFGenericValidateType(value, CFStringGetTypeID());
660 cnt = CFStringGetLength((CFStringRef)value);
661 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
662 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
663 unum_setTextAttribute(formatter->_nf, UNUM_POSITIVE_SUFFIX, (const UChar *)ubuffer, cnt, &status);
664 } else if (kCFNumberFormatterNegativePrefix == key) {
665 __CFGenericValidateType(value, CFStringGetTypeID());
666 cnt = CFStringGetLength((CFStringRef)value);
667 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
668 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
669 unum_setTextAttribute(formatter->_nf, UNUM_NEGATIVE_PREFIX, ubuffer, cnt, &status);
670 } else if (kCFNumberFormatterNegativeSuffix == key) {
671 __CFGenericValidateType(value, CFStringGetTypeID());
672 cnt = CFStringGetLength((CFStringRef)value);
673 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
674 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
675 unum_setTextAttribute(formatter->_nf, UNUM_NEGATIVE_SUFFIX, (const UChar *)ubuffer, cnt, &status);
676 } else if (kCFNumberFormatterPerMillSymbol == key) {
677 __CFGenericValidateType(value, CFStringGetTypeID());
678 cnt = CFStringGetLength((CFStringRef)value);
679 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
680 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
681 unum_setSymbol(formatter->_nf, UNUM_PERMILL_SYMBOL, ubuffer, cnt, &status);
682 } else if (kCFNumberFormatterInternationalCurrencySymbol == key) {
683 __CFGenericValidateType(value, CFStringGetTypeID());
684 cnt = CFStringGetLength((CFStringRef)value);
685 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
686 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
687 unum_setSymbol(formatter->_nf, UNUM_INTL_CURRENCY_SYMBOL, ubuffer, cnt, &status);
688 } else if (kCFNumberFormatterCurrencyGroupingSeparator == key) {
689 __CFGenericValidateType(value, CFStringGetTypeID());
690 cnt = CFStringGetLength((CFStringRef)value);
691 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
692 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer);
693 unum_setSymbol(formatter->_nf, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, ubuffer, cnt, &status);
694 } else if (kCFNumberFormatterIsLenient == key) {
695 __CFGenericValidateType(value, CFBooleanGetTypeID());
696 unum_setAttribute(formatter->_nf, UNUM_LENIENT_PARSE, (kCFBooleanTrue == value));
697 } else if (kCFNumberFormatterUseSignificantDigits == key) {
698 __CFGenericValidateType(value, CFBooleanGetTypeID());
699 unum_setAttribute(formatter->_nf, UNUM_SIGNIFICANT_DIGITS_USED, (kCFBooleanTrue == value));
700 } else if (kCFNumberFormatterMinSignificantDigits == key) {
701 __CFGenericValidateType(value, CFNumberGetTypeID());
702 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
703 unum_setAttribute(formatter->_nf, UNUM_MIN_SIGNIFICANT_DIGITS, n);
704 } else if (kCFNumberFormatterMaxSignificantDigits == key) {
705 __CFGenericValidateType(value, CFNumberGetTypeID());
706 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n);
707 unum_setAttribute(formatter->_nf, UNUM_MAX_SIGNIFICANT_DIGITS, n);
708 } else {
709 CFAssert3(0, __kCFLogAssertion, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__, key, key);
710 }
711 }
712
713 CFTypeRef CFNumberFormatterCopyProperty(CFNumberFormatterRef formatter, CFStringRef key) {
714 int32_t n;
715 double d;
716 UErrorCode status = U_ZERO_ERROR;
717 UChar ubuffer[BUFFER_SIZE];
718 CFIndex cnt;
719 __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID());
720 __CFGenericValidateType(key, CFStringGetTypeID());
721 if (kCFNumberFormatterCurrencyCode == key) {
722 cnt = unum_getTextAttribute(formatter->_nf, UNUM_CURRENCY_CODE, ubuffer, BUFFER_SIZE, &status);
723 if (U_SUCCESS(status) && cnt == 0) {
724 CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale);
725 char buffer[BUFFER_SIZE];
726 const char *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII);
727 if (NULL == cstr) {
728 if (CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer;
729 }
730 if (NULL == cstr) {
731 return NULL;
732 }
733 UErrorCode status = U_ZERO_ERROR;
734 UNumberFormat *nf = unum_open(UNUM_CURRENCY, NULL, 0, cstr, NULL, &status);
735 if (NULL != nf) {
736 cnt = unum_getTextAttribute(nf, UNUM_CURRENCY_CODE, ubuffer, BUFFER_SIZE, &status);
737 unum_close(nf);
738 }
739 }
740 if (U_SUCCESS(status) && 0 < cnt && cnt <= BUFFER_SIZE) {
741 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
742 }
743 } else if (kCFNumberFormatterDecimalSeparator == key) {
744 cnt = unum_getSymbol(formatter->_nf, UNUM_DECIMAL_SEPARATOR_SYMBOL, ubuffer, BUFFER_SIZE, &status);
745 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
746 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
747 }
748 } else if (kCFNumberFormatterCurrencyDecimalSeparator == key) {
749 cnt = unum_getSymbol(formatter->_nf, UNUM_MONETARY_SEPARATOR_SYMBOL, (UChar *)ubuffer, BUFFER_SIZE, &status);
750 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
751 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
752 }
753 } else if (kCFNumberFormatterAlwaysShowDecimalSeparator == key) {
754 n = unum_getAttribute(formatter->_nf, UNUM_DECIMAL_ALWAYS_SHOWN);
755 if (1) {
756 return CFRetain(n ? kCFBooleanTrue : kCFBooleanFalse);
757 }
758 } else if (kCFNumberFormatterGroupingSeparator == key) {
759 cnt = unum_getSymbol(formatter->_nf, UNUM_GROUPING_SEPARATOR_SYMBOL, ubuffer, BUFFER_SIZE, &status);
760 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
761 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
762 }
763 } else if (kCFNumberFormatterUseGroupingSeparator == key) {
764 n = unum_getAttribute(formatter->_nf, UNUM_GROUPING_USED);
765 if (1) {
766 return CFRetain(n ? kCFBooleanTrue : kCFBooleanFalse);
767 }
768 } else if (kCFNumberFormatterPercentSymbol == key) {
769 cnt = unum_getSymbol(formatter->_nf, UNUM_PERCENT_SYMBOL, ubuffer, BUFFER_SIZE, &status);
770 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
771 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
772 }
773 } else if (kCFNumberFormatterZeroSymbol == key) {
774 return formatter->_zeroSym ? CFRetain(formatter->_zeroSym) : NULL;
775 } else if (kCFNumberFormatterNaNSymbol == key) {
776 cnt = unum_getSymbol(formatter->_nf, UNUM_NAN_SYMBOL, ubuffer, BUFFER_SIZE, &status);
777 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
778 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
779 }
780 } else if (kCFNumberFormatterInfinitySymbol == key) {
781 cnt = unum_getSymbol(formatter->_nf, UNUM_INFINITY_SYMBOL, ubuffer, BUFFER_SIZE, &status);
782 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
783 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
784 }
785 } else if (kCFNumberFormatterMinusSign == key) {
786 cnt = unum_getSymbol(formatter->_nf, UNUM_MINUS_SIGN_SYMBOL, ubuffer, BUFFER_SIZE, &status);
787 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
788 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
789 }
790 } else if (kCFNumberFormatterPlusSign == key) {
791 cnt = unum_getSymbol(formatter->_nf, UNUM_PLUS_SIGN_SYMBOL, ubuffer, BUFFER_SIZE, &status);
792 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
793 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
794 }
795 } else if (kCFNumberFormatterCurrencySymbol == key) {
796 cnt = unum_getSymbol(formatter->_nf, UNUM_CURRENCY_SYMBOL, ubuffer, BUFFER_SIZE, &status);
797 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
798 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
799 }
800 } else if (kCFNumberFormatterExponentSymbol == key) {
801 cnt = unum_getSymbol(formatter->_nf, UNUM_EXPONENTIAL_SYMBOL, ubuffer, BUFFER_SIZE, &status);
802 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
803 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
804 }
805 } else if (kCFNumberFormatterMinIntegerDigits == key) {
806 n = unum_getAttribute(formatter->_nf, UNUM_MIN_INTEGER_DIGITS);
807 if (1) {
808 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
809 }
810 } else if (kCFNumberFormatterMaxIntegerDigits == key) {
811 n = unum_getAttribute(formatter->_nf, UNUM_MAX_INTEGER_DIGITS);
812 if (1) {
813 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
814 }
815 } else if (kCFNumberFormatterMinFractionDigits == key) {
816 n = unum_getAttribute(formatter->_nf, UNUM_MIN_FRACTION_DIGITS);
817 if (1) {
818 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
819 }
820 } else if (kCFNumberFormatterMaxFractionDigits == key) {
821 n = unum_getAttribute(formatter->_nf, UNUM_MAX_FRACTION_DIGITS);
822 if (1) {
823 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
824 }
825 } else if (kCFNumberFormatterGroupingSize == key) {
826 n = unum_getAttribute(formatter->_nf, UNUM_GROUPING_SIZE);
827 if (1) {
828 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
829 }
830 } else if (kCFNumberFormatterSecondaryGroupingSize == key) {
831 n = unum_getAttribute(formatter->_nf, UNUM_SECONDARY_GROUPING_SIZE);
832 if (1) {
833 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
834 }
835 } else if (kCFNumberFormatterRoundingMode == key) {
836 n = unum_getAttribute(formatter->_nf, UNUM_ROUNDING_MODE);
837 if (1) {
838 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
839 }
840 } else if (kCFNumberFormatterRoundingIncrement == key) {
841 d = unum_getDoubleAttribute(formatter->_nf, UNUM_ROUNDING_INCREMENT);
842 if (1) {
843 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberDoubleType, &d);
844 }
845 } else if (kCFNumberFormatterFormatWidth == key) {
846 n = unum_getAttribute(formatter->_nf, UNUM_FORMAT_WIDTH);
847 if (1) {
848 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
849 }
850 } else if (kCFNumberFormatterPaddingPosition == key) {
851 n = unum_getAttribute(formatter->_nf, UNUM_PADDING_POSITION);
852 if (1) {
853 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
854 }
855 } else if (kCFNumberFormatterPaddingCharacter == key) {
856 cnt = unum_getTextAttribute(formatter->_nf, UNUM_PADDING_CHARACTER, ubuffer, BUFFER_SIZE, &status);
857 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
858 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
859 }
860 } else if (kCFNumberFormatterDefaultFormat == key) {
861 return formatter->_defformat ? CFRetain(formatter->_defformat) : NULL;
862 } else if (kCFNumberFormatterMultiplier == key) {
863 return formatter->_multiplier ? CFRetain(formatter->_multiplier) : NULL;
864 } else if (kCFNumberFormatterPositivePrefix == key) {
865 cnt = unum_getTextAttribute(formatter->_nf, UNUM_POSITIVE_PREFIX, ubuffer, BUFFER_SIZE, &status);
866 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
867 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
868 }
869 } else if (kCFNumberFormatterPositiveSuffix == key) {
870 cnt = unum_getTextAttribute(formatter->_nf, UNUM_POSITIVE_SUFFIX, ubuffer, BUFFER_SIZE, &status);
871 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
872 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
873 }
874 } else if (kCFNumberFormatterNegativePrefix == key) {
875 cnt = unum_getTextAttribute(formatter->_nf, UNUM_NEGATIVE_PREFIX, ubuffer, BUFFER_SIZE, &status);
876 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
877 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
878 }
879 } else if (kCFNumberFormatterNegativeSuffix == key) {
880 cnt = unum_getTextAttribute(formatter->_nf, UNUM_NEGATIVE_SUFFIX, ubuffer, BUFFER_SIZE, &status);
881 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
882 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
883 }
884 } else if (kCFNumberFormatterPerMillSymbol == key) {
885 cnt = unum_getSymbol(formatter->_nf, UNUM_PERMILL_SYMBOL, ubuffer, BUFFER_SIZE, &status);
886 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
887 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
888 }
889 } else if (kCFNumberFormatterInternationalCurrencySymbol == key) {
890 cnt = unum_getSymbol(formatter->_nf, UNUM_INTL_CURRENCY_SYMBOL, ubuffer, BUFFER_SIZE, &status);
891 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
892 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
893 }
894 } else if (kCFNumberFormatterCurrencyGroupingSeparator == key) {
895 cnt = unum_getSymbol(formatter->_nf, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, ubuffer, BUFFER_SIZE, &status);
896 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
897 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt);
898 }
899 } else if (kCFNumberFormatterIsLenient == key) {
900 n = unum_getAttribute(formatter->_nf, UNUM_LENIENT_PARSE);
901 if (1) {
902 return CFRetain(n ? kCFBooleanTrue : kCFBooleanFalse);
903 }
904 } else if (kCFNumberFormatterUseSignificantDigits == key) {
905 n = unum_getAttribute(formatter->_nf, UNUM_SIGNIFICANT_DIGITS_USED);
906 if (1) {
907 return CFRetain(n ? kCFBooleanTrue : kCFBooleanFalse);
908 }
909 } else if (kCFNumberFormatterMinSignificantDigits == key) {
910 n = unum_getAttribute(formatter->_nf, UNUM_MIN_SIGNIFICANT_DIGITS);
911 if (1) {
912 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
913 }
914 } else if (kCFNumberFormatterMaxSignificantDigits == key) {
915 n = unum_getAttribute(formatter->_nf, UNUM_MAX_SIGNIFICANT_DIGITS);
916 if (1) {
917 return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n);
918 }
919 } else {
920 CFAssert3(0, __kCFLogAssertion, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__, key, key);
921 }
922 return NULL;
923 }
924
925 CONST_STRING_DECL(kCFNumberFormatterCurrencyCode, "kCFNumberFormatterCurrencyCode")
926 CONST_STRING_DECL(kCFNumberFormatterDecimalSeparator, "kCFNumberFormatterDecimalSeparator")
927 CONST_STRING_DECL(kCFNumberFormatterCurrencyDecimalSeparator, "kCFNumberFormatterCurrencyDecimalSeparator")
928 CONST_STRING_DECL(kCFNumberFormatterAlwaysShowDecimalSeparator, "kCFNumberFormatterAlwaysShowDecimalSeparator")
929 CONST_STRING_DECL(kCFNumberFormatterGroupingSeparator, "kCFNumberFormatterGroupingSeparator")
930 CONST_STRING_DECL(kCFNumberFormatterUseGroupingSeparator, "kCFNumberFormatterUseGroupingSeparator")
931 CONST_STRING_DECL(kCFNumberFormatterPercentSymbol, "kCFNumberFormatterPercentSymbol")
932 CONST_STRING_DECL(kCFNumberFormatterZeroSymbol, "kCFNumberFormatterZeroSymbol")
933 CONST_STRING_DECL(kCFNumberFormatterNaNSymbol, "kCFNumberFormatterNaNSymbol")
934 CONST_STRING_DECL(kCFNumberFormatterInfinitySymbol, "kCFNumberFormatterInfinitySymbol")
935 CONST_STRING_DECL(kCFNumberFormatterMinusSign, "kCFNumberFormatterMinusSignSymbol")
936 CONST_STRING_DECL(kCFNumberFormatterPlusSign, "kCFNumberFormatterPlusSignSymbol")
937 CONST_STRING_DECL(kCFNumberFormatterCurrencySymbol, "kCFNumberFormatterCurrencySymbol")
938 CONST_STRING_DECL(kCFNumberFormatterExponentSymbol, "kCFNumberFormatterExponentSymbol")
939 CONST_STRING_DECL(kCFNumberFormatterMinIntegerDigits, "kCFNumberFormatterMinIntegerDigits")
940 CONST_STRING_DECL(kCFNumberFormatterMaxIntegerDigits, "kCFNumberFormatterMaxIntegerDigits")
941 CONST_STRING_DECL(kCFNumberFormatterMinFractionDigits, "kCFNumberFormatterMinFractionDigits")
942 CONST_STRING_DECL(kCFNumberFormatterMaxFractionDigits, "kCFNumberFormatterMaxFractionDigits")
943 CONST_STRING_DECL(kCFNumberFormatterGroupingSize, "kCFNumberFormatterGroupingSize")
944 CONST_STRING_DECL(kCFNumberFormatterSecondaryGroupingSize, "kCFNumberFormatterSecondaryGroupingSize")
945 CONST_STRING_DECL(kCFNumberFormatterRoundingMode, "kCFNumberFormatterRoundingMode")
946 CONST_STRING_DECL(kCFNumberFormatterRoundingIncrement, "kCFNumberFormatterRoundingIncrement")
947 CONST_STRING_DECL(kCFNumberFormatterFormatWidth, "kCFNumberFormatterFormatWidth")
948 CONST_STRING_DECL(kCFNumberFormatterPaddingPosition, "kCFNumberFormatterPaddingPosition")
949 CONST_STRING_DECL(kCFNumberFormatterPaddingCharacter, "kCFNumberFormatterPaddingCharacter")
950 CONST_STRING_DECL(kCFNumberFormatterDefaultFormat, "kCFNumberFormatterDefaultFormat")
951
952 CONST_STRING_DECL(kCFNumberFormatterMultiplier, "kCFNumberFormatterMultiplier")
953 CONST_STRING_DECL(kCFNumberFormatterPositivePrefix, "kCFNumberFormatterPositivePrefix")
954 CONST_STRING_DECL(kCFNumberFormatterPositiveSuffix, "kCFNumberFormatterPositiveSuffix")
955 CONST_STRING_DECL(kCFNumberFormatterNegativePrefix, "kCFNumberFormatterNegativePrefix")
956 CONST_STRING_DECL(kCFNumberFormatterNegativeSuffix, "kCFNumberFormatterNegativeSuffix")
957 CONST_STRING_DECL(kCFNumberFormatterPerMillSymbol, "kCFNumberFormatterPerMillSymbol")
958 CONST_STRING_DECL(kCFNumberFormatterInternationalCurrencySymbol, "kCFNumberFormatterInternationalCurrencySymbol")
959
960 CONST_STRING_DECL(kCFNumberFormatterCurrencyGroupingSeparator, "kCFNumberFormatterCurrencyGroupingSeparator")
961 CONST_STRING_DECL(kCFNumberFormatterIsLenient, "kCFNumberFormatterIsLenient")
962 CONST_STRING_DECL(kCFNumberFormatterUseSignificantDigits, "kCFNumberFormatterUseSignificantDigits")
963 CONST_STRING_DECL(kCFNumberFormatterMinSignificantDigits, "kCFNumberFormatterMinSignificantDigits")
964 CONST_STRING_DECL(kCFNumberFormatterMaxSignificantDigits, "kCFNumberFormatterMaxSignificantDigits")
965
966 Boolean CFNumberFormatterGetDecimalInfoForCurrencyCode(CFStringRef currencyCode, int32_t *defaultFractionDigits, double *roundingIncrement) {
967 UChar ubuffer[4];
968 __CFGenericValidateType(currencyCode, CFStringGetTypeID());
969 CFAssert1(3 == CFStringGetLength(currencyCode), __kCFLogAssertion, "%s(): currencyCode is not 3 characters", __PRETTY_FUNCTION__);
970 CFStringGetCharacters(currencyCode, CFRangeMake(0, 3), (UniChar *)ubuffer);
971 ubuffer[3] = 0;
972 UErrorCode icuStatus = U_ZERO_ERROR;
973 if (defaultFractionDigits) *defaultFractionDigits = ucurr_getDefaultFractionDigits(ubuffer, &icuStatus);
974 if (roundingIncrement) *roundingIncrement = ucurr_getRoundingIncrement(ubuffer, &icuStatus);
975 if (U_FAILURE(icuStatus))
976 return false;
977 return (!defaultFractionDigits || 0 <= *defaultFractionDigits) && (!roundingIncrement || 0.0 <= *roundingIncrement);
978 }
979
980 #undef BUFFER_SIZE
981