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