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