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