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