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