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/* CFDateFormatter.c 25 Copyright (c) 2002-2013, Apple Inc. All rights reserved. 26 Responsibility: David Smith 27*/ 28 29#define U_SHOW_INTERNAL_API 1 30 31#include <CoreFoundation/CFDateFormatter.h> 32#include <CoreFoundation/CFDate.h> 33#include <CoreFoundation/CFTimeZone.h> 34#include <CoreFoundation/CFCalendar.h> 35#include <CoreFoundation/CFNumber.h> 36#include "CFPriv.h" 37#include "CFInternal.h" 38#include "CFLocaleInternal.h" 39#include "CFICULogging.h" 40#include <math.h> 41#include <float.h> 42 43 44typedef CF_ENUM(CFIndex, CFDateFormatterAmbiguousYearHandling) { 45 kCFDateFormatterAmbiguousYearFailToParse = 0, // fail the parse; the default formatter behavior 46 kCFDateFormatterAmbiguousYearAssumeToNone = 1, // default to assuming era 1, or the year 0-99 47 kCFDateFormatterAmbiguousYearAssumeToCurrent = 2, // default to assuming the current century or era 48 kCFDateFormatterAmbiguousYearAssumeToCenteredAroundCurrentDate = 3, 49 kCFDateFormatterAmbiguousYearAssumeToFuture = 4, 50 kCFDateFormatterAmbiguousYearAssumeToPast = 5, 51 kCFDateFormatterAmbiguousYearAssumeToLikelyFuture = 6, 52 kCFDateFormatterAmbiguousYearAssumeToLikelyPast = 7 53}; 54 55extern UCalendar *__CFCalendarCreateUCalendar(CFStringRef calendarID, CFStringRef localeID, CFTimeZoneRef tz); 56 57CF_EXPORT const CFStringRef kCFDateFormatterCalendarIdentifierKey; 58 59#undef CFReleaseIfNotNull 60#define CFReleaseIfNotNull(X) if (X) CFRelease(X) 61 62#define BUFFER_SIZE 768 63 64static CFStringRef __CFDateFormatterCreateForcedTemplate(CFLocaleRef locale, CFStringRef inString); 65 66// If you pass in a string in tmplate, you get back NULL (failure) or a CFStringRef. 67// If you pass in an array in tmplate, you get back NULL (global failure) or a CFArrayRef with CFStringRefs or kCFNulls (per-template failure) at each corresponding index. 68 69CFArrayRef CFDateFormatterCreateDateFormatsFromTemplates(CFAllocatorRef allocator, CFArrayRef tmplates, CFOptionFlags options, CFLocaleRef locale) { 70 return (CFArrayRef)CFDateFormatterCreateDateFormatFromTemplate(allocator, (CFStringRef)tmplates, options, locale); 71} 72 73static Boolean useTemplatePatternGenerator(const char *localeName, void(^work)(UDateTimePatternGenerator *ptg)) { 74 static UDateTimePatternGenerator *ptg; 75 static pthread_mutex_t ptgLock = PTHREAD_MUTEX_INITIALIZER; 76 static const char *ptgLocaleName; 77 78 static void (^flushCache)() = ^{ 79 __cficu_udatpg_close(ptg); 80 ptg = NULL; 81 free((void *)ptgLocaleName); 82 ptgLocaleName = NULL; 83 }; 84 pthread_mutex_lock(&ptgLock); 85 if (ptgLocaleName && strcmp(ptgLocaleName, localeName) != 0) { 86 flushCache(); 87 } 88 UErrorCode status = U_ZERO_ERROR; 89 if (!ptg) { 90 ptg = __cficu_udatpg_open(localeName, &status); 91 if (ptg && !U_FAILURE(status)) { 92 ptgLocaleName = strdup(localeName); 93 } 94 } 95 Boolean result = (NULL != ptg && !U_FAILURE(status)); 96 if (result && work) { 97 work(ptg); 98 } 99 pthread_mutex_unlock(&ptgLock); 100 return result; 101} 102 103 104CFStringRef CFDateFormatterCreateDateFormatFromTemplate(CFAllocatorRef allocator, CFStringRef tmplate, CFOptionFlags options, CFLocaleRef locale) { 105 if (allocator) __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); 106 if (locale) __CFGenericValidateType(locale, CFLocaleGetTypeID()); 107 Boolean tmplateIsString = (CFStringGetTypeID() == CFGetTypeID(tmplate)); 108 if (!tmplateIsString) { 109 __CFGenericValidateType(tmplate, CFArrayGetTypeID()); 110 } 111 112 CFStringRef localeName = locale ? CFLocaleGetIdentifier(locale) : CFSTR(""); 113 char buffer[BUFFER_SIZE]; 114 const char *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII); 115 if (NULL == cstr) { 116 if (CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer; 117 } 118 if (NULL == cstr) { 119 return NULL; 120 } 121 122 __block CFTypeRef result = tmplateIsString ? NULL : (CFTypeRef)CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks); 123 124 Boolean success = useTemplatePatternGenerator(cstr, ^(UDateTimePatternGenerator *ptg) { 125 126 127 for (CFIndex idx = 0, cnt = tmplateIsString ? 1 : CFArrayGetCount((CFArrayRef)tmplate); idx < cnt; idx++) { 128 CFStringRef tmplateString = tmplateIsString ? (CFStringRef)tmplate : (CFStringRef)CFArrayGetValueAtIndex((CFArrayRef)tmplate, idx); 129 CFStringRef resultString = NULL; 130 131 tmplateString = __CFDateFormatterCreateForcedTemplate(locale ? locale : CFLocaleGetSystem(), tmplateString); 132 133 CFIndex jCount = 0; // the only interesting cases are 0, 1, and 2 (adjacent) 134 CFRange r = CFStringFind(tmplateString, CFSTR("j"), 0); 135 if (kCFNotFound != r.location) { 136 jCount++; 137 if ((r.location + 1 < CFStringGetLength(tmplateString)) && ('j' == CFStringGetCharacterAtIndex(tmplateString, r.location + 1))) { 138 jCount++; 139 } 140 } 141 142 UChar pattern[BUFFER_SIZE], skel[BUFFER_SIZE], bpat[BUFFER_SIZE]; 143 CFIndex tmpltLen = CFStringGetLength(tmplateString); 144 if (BUFFER_SIZE < tmpltLen) tmpltLen = BUFFER_SIZE; 145 CFStringGetCharacters(tmplateString, CFRangeMake(0, tmpltLen), (UniChar *)pattern); 146 CFRelease(tmplateString); 147 148 int32_t patlen = tmpltLen; 149 UErrorCode status = U_ZERO_ERROR; 150 int32_t skellen = __cficu_udatpg_getSkeleton(ptg, pattern, patlen, skel, sizeof(skel) / sizeof(skel[0]), &status); 151 if (!U_FAILURE(status)) { 152 if ((0 < jCount) && (skellen + jCount < (sizeof(skel) / sizeof(skel[0])))) { 153 skel[skellen++] = 'j'; 154 if (1 < jCount) skel[skellen++] = 'j'; 155 } 156 157 status = U_ZERO_ERROR; 158 int32_t bpatlen = __cficu_udatpg_getBestPattern(ptg, skel, skellen, bpat, sizeof(bpat) / sizeof(bpat[0]), &status); 159 if (!U_FAILURE(status)) { 160 resultString = CFStringCreateWithCharacters(allocator, (const UniChar *)bpat, bpatlen); 161 } 162 } 163 164 if (tmplateIsString) { 165 result = (CFTypeRef)resultString; 166 } else { 167 CFArrayAppendValue((CFMutableArrayRef)result, resultString ? (CFTypeRef)resultString : (CFTypeRef)kCFNull); 168 if (resultString) CFRelease(resultString); 169 } 170 } 171 }); 172 173 if (!success) { 174 CFRelease(result); 175 result = NULL; 176 } 177 178 return (CFStringRef)result; 179} 180 181struct __CFDateFormatter { 182 CFRuntimeBase _base; 183 UDateFormat *_df; 184 CFLocaleRef _locale; 185 CFDateFormatterStyle _timeStyle; 186 CFDateFormatterStyle _dateStyle; 187 CFStringRef _format; 188 CFStringRef _defformat; 189 struct { 190 CFBooleanRef _IsLenient; 191 CFBooleanRef _DoesRelativeDateFormatting; 192 CFBooleanRef _HasCustomFormat; 193 CFTimeZoneRef _TimeZone; 194 CFCalendarRef _Calendar; 195 CFStringRef _CalendarName; 196 CFDateRef _TwoDigitStartDate; 197 CFDateRef _DefaultDate; 198 CFDateRef _GregorianStartDate; 199 CFArrayRef _EraSymbols; 200 CFArrayRef _LongEraSymbols; 201 CFArrayRef _MonthSymbols; 202 CFArrayRef _ShortMonthSymbols; 203 CFArrayRef _VeryShortMonthSymbols; 204 CFArrayRef _StandaloneMonthSymbols; 205 CFArrayRef _ShortStandaloneMonthSymbols; 206 CFArrayRef _VeryShortStandaloneMonthSymbols; 207 CFArrayRef _WeekdaySymbols; 208 CFArrayRef _ShortWeekdaySymbols; 209 CFArrayRef _VeryShortWeekdaySymbols; 210 CFArrayRef _StandaloneWeekdaySymbols; 211 CFArrayRef _ShortStandaloneWeekdaySymbols; 212 CFArrayRef _VeryShortStandaloneWeekdaySymbols; 213 CFArrayRef _QuarterSymbols; 214 CFArrayRef _ShortQuarterSymbols; 215 CFArrayRef _StandaloneQuarterSymbols; 216 CFArrayRef _ShortStandaloneQuarterSymbols; 217 CFStringRef _AMSymbol; 218 CFStringRef _PMSymbol; 219 CFNumberRef _AmbiguousYearStrategy; 220 CFBooleanRef _UsesCharacterDirection; 221 222 // the following are from preferences 223 CFArrayRef _CustomEraSymbols; 224 CFArrayRef _CustomLongEraSymbols; 225 CFArrayRef _CustomMonthSymbols; 226 CFArrayRef _CustomShortMonthSymbols; 227 CFArrayRef _CustomVeryShortMonthSymbols; 228 CFArrayRef _CustomStandaloneMonthSymbols; 229 CFArrayRef _CustomShortStandaloneMonthSymbols; 230 CFArrayRef _CustomVeryShortStandaloneMonthSymbols; 231 CFArrayRef _CustomWeekdaySymbols; 232 CFArrayRef _CustomShortWeekdaySymbols; 233 CFArrayRef _CustomVeryShortWeekdaySymbols; 234 CFArrayRef _CustomStandaloneWeekdaySymbols; 235 CFArrayRef _CustomShortStandaloneWeekdaySymbols; 236 CFArrayRef _CustomVeryShortStandaloneWeekdaySymbols; 237 CFArrayRef _CustomQuarterSymbols; 238 CFArrayRef _CustomShortQuarterSymbols; 239 CFArrayRef _CustomStandaloneQuarterSymbols; 240 CFArrayRef _CustomShortStandaloneQuarterSymbols; 241 CFStringRef _CustomDateFormat; 242 CFStringRef _CustomTimeFormat; 243 CFBooleanRef _Custom24Hour; 244 CFBooleanRef _Custom12Hour; 245 CFStringRef _CustomAMSymbol; 246 CFStringRef _CustomPMSymbol; 247 CFDictionaryRef _CustomFirstWeekday; 248 CFDictionaryRef _CustomMinDaysInFirstWeek; 249 250 } _property; 251}; 252 253static CFStringRef __CFDateFormatterCopyDescription(CFTypeRef cf) { 254 CFDateFormatterRef formatter = (CFDateFormatterRef)cf; 255 return CFStringCreateWithFormat(CFGetAllocator(formatter), NULL, CFSTR("<CFDateFormatter %p [%p]>"), cf, CFGetAllocator(formatter)); 256} 257 258static void __CFDateFormatterDeallocate(CFTypeRef cf) { 259 CFDateFormatterRef formatter = (CFDateFormatterRef)cf; 260 if (formatter->_df) __cficu_udat_close(formatter->_df); 261 if (formatter->_locale) CFRelease(formatter->_locale); 262 if (formatter->_format) CFRelease(formatter->_format); 263 if (formatter->_defformat) CFRelease(formatter->_defformat); 264 CFReleaseIfNotNull(formatter->_property._IsLenient); 265 CFReleaseIfNotNull(formatter->_property._DoesRelativeDateFormatting); 266 CFReleaseIfNotNull(formatter->_property._TimeZone); 267 CFReleaseIfNotNull(formatter->_property._Calendar); 268 CFReleaseIfNotNull(formatter->_property._CalendarName); 269 CFReleaseIfNotNull(formatter->_property._TwoDigitStartDate); 270 CFReleaseIfNotNull(formatter->_property._DefaultDate); 271 CFReleaseIfNotNull(formatter->_property._GregorianStartDate); 272 CFReleaseIfNotNull(formatter->_property._EraSymbols); 273 CFReleaseIfNotNull(formatter->_property._LongEraSymbols); 274 CFReleaseIfNotNull(formatter->_property._MonthSymbols); 275 CFReleaseIfNotNull(formatter->_property._ShortMonthSymbols); 276 CFReleaseIfNotNull(formatter->_property._VeryShortMonthSymbols); 277 CFReleaseIfNotNull(formatter->_property._StandaloneMonthSymbols); 278 CFReleaseIfNotNull(formatter->_property._ShortStandaloneMonthSymbols); 279 CFReleaseIfNotNull(formatter->_property._VeryShortStandaloneMonthSymbols); 280 CFReleaseIfNotNull(formatter->_property._WeekdaySymbols); 281 CFReleaseIfNotNull(formatter->_property._ShortWeekdaySymbols); 282 CFReleaseIfNotNull(formatter->_property._VeryShortWeekdaySymbols); 283 CFReleaseIfNotNull(formatter->_property._StandaloneWeekdaySymbols); 284 CFReleaseIfNotNull(formatter->_property._ShortStandaloneWeekdaySymbols); 285 CFReleaseIfNotNull(formatter->_property._VeryShortStandaloneWeekdaySymbols); 286 CFReleaseIfNotNull(formatter->_property._QuarterSymbols); 287 CFReleaseIfNotNull(formatter->_property._ShortQuarterSymbols); 288 CFReleaseIfNotNull(formatter->_property._StandaloneQuarterSymbols); 289 CFReleaseIfNotNull(formatter->_property._ShortStandaloneQuarterSymbols); 290 CFReleaseIfNotNull(formatter->_property._AMSymbol); 291 CFReleaseIfNotNull(formatter->_property._PMSymbol); 292 CFReleaseIfNotNull(formatter->_property._AmbiguousYearStrategy); 293 CFReleaseIfNotNull(formatter->_property._UsesCharacterDirection); 294 CFReleaseIfNotNull(formatter->_property._CustomEraSymbols); 295 CFReleaseIfNotNull(formatter->_property._CustomMonthSymbols); 296 CFReleaseIfNotNull(formatter->_property._CustomShortMonthSymbols); 297 CFReleaseIfNotNull(formatter->_property._CustomWeekdaySymbols); 298 CFReleaseIfNotNull(formatter->_property._CustomShortWeekdaySymbols); 299 CFReleaseIfNotNull(formatter->_property._CustomLongEraSymbols); 300 CFReleaseIfNotNull(formatter->_property._CustomVeryShortMonthSymbols); 301 CFReleaseIfNotNull(formatter->_property._CustomVeryShortWeekdaySymbols); 302 CFReleaseIfNotNull(formatter->_property._CustomStandaloneMonthSymbols); 303 CFReleaseIfNotNull(formatter->_property._CustomShortStandaloneMonthSymbols); 304 CFReleaseIfNotNull(formatter->_property._CustomVeryShortStandaloneMonthSymbols); 305 CFReleaseIfNotNull(formatter->_property._CustomStandaloneWeekdaySymbols); 306 CFReleaseIfNotNull(formatter->_property._CustomShortStandaloneWeekdaySymbols); 307 CFReleaseIfNotNull(formatter->_property._CustomVeryShortStandaloneWeekdaySymbols); 308 CFReleaseIfNotNull(formatter->_property._CustomQuarterSymbols); 309 CFReleaseIfNotNull(formatter->_property._CustomShortQuarterSymbols); 310 CFReleaseIfNotNull(formatter->_property._CustomShortStandaloneQuarterSymbols); 311 CFReleaseIfNotNull(formatter->_property._CustomDateFormat); 312 CFReleaseIfNotNull(formatter->_property._CustomTimeFormat); 313 CFReleaseIfNotNull(formatter->_property._Custom24Hour); 314 CFReleaseIfNotNull(formatter->_property._Custom12Hour); 315 CFReleaseIfNotNull(formatter->_property._CustomAMSymbol); 316 CFReleaseIfNotNull(formatter->_property._CustomPMSymbol); 317 CFReleaseIfNotNull(formatter->_property._CustomFirstWeekday); 318 CFReleaseIfNotNull(formatter->_property._CustomMinDaysInFirstWeek); 319} 320 321static CFStringRef __CFDateFormatterCreateForcedString(CFDateFormatterRef formatter, CFStringRef inString); 322 323static void __CFDateFormatterSetProperty(CFDateFormatterRef formatter, CFStringRef key, CFTypeRef value, Boolean directToICU); 324static void __CFDateFormatterStoreSymbolPrefs(const void *key, const void *value, void *context); 325extern CFDictionaryRef __CFLocaleGetPrefs(CFLocaleRef locale); 326static void __substituteFormatStringFromPrefsDFRelative(CFDateFormatterRef formatter); 327static void __substituteFormatStringFromPrefsDF(CFDateFormatterRef formatter, bool doTime); 328static void __CFDateFormatterSetSymbolsArray(UDateFormat *icudf, int32_t icucode, int index_base, CFTypeRef value); 329 330static void __ReadCustomUDateFormatProperty(CFDateFormatterRef formatter) { 331 CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale); 332 CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUDateTimeSymbols")) : NULL; 333 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) { 334 CFDictionaryApplyFunction((CFDictionaryRef)metapref, __CFDateFormatterStoreSymbolPrefs, formatter); 335 } 336 metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleFirstWeekday")) : NULL; 337 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) { 338 formatter->_property._CustomFirstWeekday = (CFDictionaryRef)CFRetain(metapref); 339 } 340 metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleMinDaysInFirstWeek")) : NULL; 341 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) { 342 formatter->_property._CustomMinDaysInFirstWeek = (CFDictionaryRef)CFRetain(metapref); 343 } 344 metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUForce24HourTime")) : NULL; 345 if (NULL != metapref && CFGetTypeID(metapref) == CFBooleanGetTypeID()) { 346 formatter->_property._Custom24Hour = (CFBooleanRef)CFRetain(metapref); 347 } 348 metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUForce12HourTime")) : NULL; 349 if (NULL != metapref && CFGetTypeID(metapref) == CFBooleanGetTypeID()) { 350 formatter->_property._Custom12Hour = (CFBooleanRef)CFRetain(metapref); 351 } 352 metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUDateFormatStrings")) : NULL; 353 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) { 354 CFStringRef key; 355 switch (formatter->_dateStyle) { 356 case kCFDateFormatterShortStyle: key = CFSTR("1"); break; 357 case kCFDateFormatterMediumStyle: key = CFSTR("2"); break; 358 case kCFDateFormatterLongStyle: key = CFSTR("3"); break; 359 case kCFDateFormatterFullStyle: key = CFSTR("4"); break; 360 default: key = CFSTR("0"); break; 361 } 362 CFStringRef dateFormat = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)metapref, key); 363 if (NULL != dateFormat && CFGetTypeID(dateFormat) == CFStringGetTypeID()) { 364 formatter->_property._CustomDateFormat = (CFStringRef)CFRetain(dateFormat); 365 } 366 } 367 metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUTimeFormatStrings")) : NULL; 368 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) { 369 CFStringRef key; 370 switch (formatter->_timeStyle) { 371 case kCFDateFormatterShortStyle: key = CFSTR("1"); break; 372 case kCFDateFormatterMediumStyle: key = CFSTR("2"); break; 373 case kCFDateFormatterLongStyle: key = CFSTR("3"); break; 374 case kCFDateFormatterFullStyle: key = CFSTR("4"); break; 375 default: key = CFSTR("0"); break; 376 } 377 CFStringRef timeFormat = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)metapref, key); 378 if (NULL != timeFormat && CFGetTypeID(timeFormat) == CFStringGetTypeID()) { 379 formatter->_property._CustomTimeFormat = (CFStringRef)CFRetain(timeFormat); 380 } 381 } 382} 383 384static void __ApplyUDateFormatSymbol(CFDateFormatterRef formatter) { 385 UDateFormatSymbolType types[18] = {UDAT_ERAS, 386 UDAT_ERA_NAMES, 387 UDAT_MONTHS, 388 UDAT_SHORT_MONTHS, 389 UDAT_NARROW_MONTHS, 390 UDAT_STANDALONE_MONTHS, 391 UDAT_STANDALONE_SHORT_MONTHS, 392 UDAT_STANDALONE_NARROW_MONTHS, 393 UDAT_WEEKDAYS, 394 UDAT_SHORT_WEEKDAYS, 395 UDAT_NARROW_WEEKDAYS, 396 UDAT_STANDALONE_WEEKDAYS, 397 UDAT_STANDALONE_SHORT_WEEKDAYS, 398 UDAT_STANDALONE_NARROW_WEEKDAYS, 399 UDAT_QUARTERS, 400 UDAT_SHORT_QUARTERS, 401 UDAT_STANDALONE_QUARTERS, 402 UDAT_STANDALONE_SHORT_QUARTERS}; 403 int offsets[18] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0}; 404 CFArrayRef symbols[18] = {formatter->_property._EraSymbols, 405 formatter->_property._LongEraSymbols, 406 formatter->_property._MonthSymbols, 407 formatter->_property._ShortMonthSymbols, 408 formatter->_property._VeryShortMonthSymbols, 409 formatter->_property._StandaloneMonthSymbols, 410 formatter->_property._ShortStandaloneMonthSymbols, 411 formatter->_property._VeryShortStandaloneMonthSymbols, 412 formatter->_property._WeekdaySymbols, 413 formatter->_property._ShortWeekdaySymbols, 414 formatter->_property._VeryShortWeekdaySymbols, 415 formatter->_property._StandaloneWeekdaySymbols, 416 formatter->_property._ShortStandaloneWeekdaySymbols, 417 formatter->_property._VeryShortStandaloneWeekdaySymbols, 418 formatter->_property._QuarterSymbols, 419 formatter->_property._ShortQuarterSymbols, 420 formatter->_property._StandaloneQuarterSymbols, 421 formatter->_property._ShortStandaloneQuarterSymbols 422 }; 423 CFArrayRef customSymbols[18] = {formatter->_property._CustomEraSymbols, 424 formatter->_property._CustomLongEraSymbols, 425 formatter->_property._CustomMonthSymbols, 426 formatter->_property._CustomShortMonthSymbols, 427 formatter->_property._CustomVeryShortMonthSymbols, 428 formatter->_property._CustomStandaloneMonthSymbols, 429 formatter->_property._CustomShortStandaloneMonthSymbols, 430 formatter->_property._CustomVeryShortStandaloneMonthSymbols, 431 formatter->_property._CustomWeekdaySymbols, 432 formatter->_property._CustomShortWeekdaySymbols, 433 formatter->_property._CustomVeryShortWeekdaySymbols, 434 formatter->_property._CustomStandaloneWeekdaySymbols, 435 formatter->_property._CustomShortStandaloneWeekdaySymbols, 436 formatter->_property._CustomVeryShortStandaloneWeekdaySymbols, 437 formatter->_property._CustomQuarterSymbols, 438 formatter->_property._CustomShortQuarterSymbols, 439 formatter->_property._CustomStandaloneQuarterSymbols, 440 formatter->_property._CustomShortStandaloneQuarterSymbols 441 }; 442 443 for (CFIndex i = 0; i < 18; i++) { 444 if (symbols[i] != NULL) { 445 __CFDateFormatterSetSymbolsArray(formatter->_df, types[i], offsets[i], symbols[i]); 446 } else if (customSymbols[i] != NULL) { 447 __CFDateFormatterSetSymbolsArray(formatter->_df, types[i], offsets[i], customSymbols[i]); 448 } 449 } 450 451 CFStringRef ampm[2]; 452 ampm[0] = NULL; 453 ampm[1] = NULL; 454 455 if (formatter->_property._AMSymbol != NULL) { 456 ampm[0] = formatter->_property._AMSymbol; 457 } else if (formatter->_property._CustomAMSymbol != NULL) { 458 ampm[0] = formatter->_property._CustomAMSymbol; 459 } 460 if (formatter->_property._PMSymbol != NULL) { 461 ampm[1] = formatter->_property._PMSymbol; 462 } else if (formatter->_property._CustomPMSymbol != NULL) { 463 ampm[1] = formatter->_property._CustomPMSymbol; 464 } 465 for (CFIndex i = 0; i < 2; i++) { 466 CFStringRef sym = ampm[i]; 467 if (sym != NULL) { 468 CFIndex item_cnt = CFStringGetLength(sym); 469 STACK_BUFFER_DECL(UChar, item_buffer, __CFMin(BUFFER_SIZE, item_cnt)); 470 UChar *item_ustr = (UChar *)CFStringGetCharactersPtr(sym); 471 if (NULL == item_ustr) { 472 item_cnt = __CFMin(BUFFER_SIZE, item_cnt); 473 CFStringGetCharacters(sym, CFRangeMake(0, item_cnt), (UniChar *)item_buffer); 474 item_ustr = item_buffer; 475 } 476 UErrorCode status = U_ZERO_ERROR; 477 __cficu_udat_setSymbols(formatter->_df, UDAT_AM_PMS, i, item_ustr, item_cnt, &status); 478 } 479 } 480} 481 482static void __SetCalendarProperties(CFDateFormatterRef df) { 483 CFStringRef calName = df->_property._CalendarName ? (df->_property._CalendarName) : NULL; 484 if (!calName) { 485 calName = (CFStringRef)CFLocaleGetValue(df->_locale, kCFLocaleCalendarIdentifierKey); 486 } 487 UErrorCode status = U_ZERO_ERROR; 488 const UCalendar *cal = __cficu_udat_getCalendar(df->_df); 489 UCalendar *new_cal = NULL; 490 491 if (df->_property._Calendar != NULL || df->_property._CalendarName != NULL) { 492 UCalendar *caltmp = __CFCalendarCreateUCalendar(NULL, CFLocaleGetIdentifier(df->_locale), df->_property._TimeZone); 493 if (caltmp) { 494 new_cal = caltmp; 495 } 496 } 497 if (new_cal == NULL) { 498 new_cal = __cficu_ucal_clone(cal, &status); 499 } 500 501 if (df->_property._IsLenient != NULL) { 502 status = U_ZERO_ERROR; 503 CFBooleanRef value = df->_property._IsLenient; 504 __cficu_ucal_setAttribute(new_cal, UCAL_LENIENT, (kCFBooleanTrue == value)); 505 } 506 if (df->_property._TimeZone != NULL) { 507 status = U_ZERO_ERROR; 508 UChar ubuffer[BUFFER_SIZE]; 509 CFStringRef tznam = CFTimeZoneGetName(df->_property._TimeZone); 510 CFIndex ucnt = CFStringGetLength(tznam); 511 if (BUFFER_SIZE < ucnt) ucnt = BUFFER_SIZE; 512 CFStringGetCharacters(tznam, CFRangeMake(0, ucnt), (UniChar *)ubuffer); 513 __cficu_ucal_setTimeZone(new_cal, ubuffer, ucnt, &status); 514 } 515 if (df->_property._GregorianStartDate != NULL) { 516 status = U_ZERO_ERROR; 517 CFAbsoluteTime at = CFDateGetAbsoluteTime((CFDateRef)df->_property._GregorianStartDate); 518 UDate udate = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0; 519 __cficu_ucal_setGregorianChange(new_cal, udate, &status); 520 } else if (calName && CFEqual(calName, kCFCalendarIdentifierGregorian)) { 521 status = U_ZERO_ERROR; 522 UDate udate = __cficu_ucal_getGregorianChange(cal, &status); 523 CFAbsoluteTime at = U_SUCCESS(status) ? (udate / 1000.0 - kCFAbsoluteTimeIntervalSince1970) : -13197600000.0; // Oct 15, 1582 524 udate = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0; 525 status = U_ZERO_ERROR; 526 __cficu_ucal_setGregorianChange(new_cal, udate, &status); 527 } 528 if (df->_property._Calendar != NULL) { 529 __cficu_ucal_setAttribute(new_cal, UCAL_FIRST_DAY_OF_WEEK, CFCalendarGetFirstWeekday((CFCalendarRef)df->_property._Calendar)); 530 } else if (df->_property._CustomFirstWeekday != NULL) { 531 CFNumberRef firstWeekday = (CFNumberRef)CFDictionaryGetValue(df->_property._CustomFirstWeekday, calName); 532 if (NULL != firstWeekday && CFGetTypeID(firstWeekday) == CFNumberGetTypeID()) { 533 CFIndex wkdy; 534 if (CFNumberGetValue((CFNumberRef)firstWeekday, kCFNumberCFIndexType, &wkdy)) { 535 status = U_ZERO_ERROR; 536 __cficu_ucal_setAttribute(new_cal, UCAL_FIRST_DAY_OF_WEEK, wkdy); 537 } 538 } 539 } 540 541 if (df->_property._Calendar != NULL) { 542 __cficu_ucal_setAttribute(new_cal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK, CFCalendarGetMinimumDaysInFirstWeek((CFCalendarRef)df->_property._Calendar)); 543 } else if (df->_property._CustomMinDaysInFirstWeek != NULL) { 544 CFNumberRef minDays = (CFNumberRef)CFDictionaryGetValue(df->_property._CustomMinDaysInFirstWeek, calName); 545 if (NULL != minDays && CFGetTypeID(minDays) == CFNumberGetTypeID()) { 546 CFIndex mwd; 547 if (CFNumberGetValue((CFNumberRef)minDays, kCFNumberCFIndexType, &mwd)) { 548 status = U_ZERO_ERROR; 549 __cficu_ucal_setAttribute(new_cal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK, mwd); 550 } 551 } 552 } 553 __cficu_udat_setCalendar(df->_df, new_cal); 554 __cficu_ucal_close(new_cal); 555} 556 557#define RESET_PROPERTY(C, K) \ 558 if (df->_property. C) __CFDateFormatterSetProperty(df, K, df->_property. C, true); 559 560static void __ResetUDateFormat(CFDateFormatterRef df, Boolean goingToHaveCustomFormat) { 561 if (df->_df) __cficu_udat_close(df->_df); 562 df->_df = NULL; 563 564 // uses _timeStyle, _dateStyle, _locale, _property._TimeZone; sets _df, _format, _defformat 565 char loc_buffer[BUFFER_SIZE]; 566 loc_buffer[0] = 0; 567 CFStringRef tmpLocName = df->_locale ? CFLocaleGetIdentifier(df->_locale) : CFSTR(""); 568 CFStringGetCString(tmpLocName, loc_buffer, BUFFER_SIZE, kCFStringEncodingASCII); 569 570 UChar tz_buffer[BUFFER_SIZE]; 571 tz_buffer[0] = 0; 572 CFStringRef tmpTZName = df->_property._TimeZone ? CFTimeZoneGetName(df->_property._TimeZone) : CFSTR("GMT"); 573 CFStringGetCharacters(tmpTZName, CFRangeMake(0, CFStringGetLength(tmpTZName)), (UniChar *)tz_buffer); 574 575 int32_t udstyle = 0, utstyle = 0; // effectively this makes UDAT_FULL the default for unknown dateStyle/timeStyle values 576 switch (df->_dateStyle) { 577 case kCFDateFormatterNoStyle: udstyle = UDAT_NONE; break; 578 case kCFDateFormatterShortStyle: udstyle = UDAT_SHORT; break; 579 case kCFDateFormatterMediumStyle: udstyle = UDAT_MEDIUM; break; 580 case kCFDateFormatterLongStyle: udstyle = UDAT_LONG; break; 581 case kCFDateFormatterFullStyle: udstyle = UDAT_FULL; break; 582 } 583 switch (df->_timeStyle) { 584 case kCFDateFormatterNoStyle: utstyle = UDAT_NONE; break; 585 case kCFDateFormatterShortStyle: utstyle = UDAT_SHORT; break; 586 case kCFDateFormatterMediumStyle: utstyle = UDAT_MEDIUM; break; 587 case kCFDateFormatterLongStyle: utstyle = UDAT_LONG; break; 588 case kCFDateFormatterFullStyle: utstyle = UDAT_FULL; break; 589 } 590 Boolean wantRelative = (NULL != df->_property._DoesRelativeDateFormatting && df->_property._DoesRelativeDateFormatting == kCFBooleanTrue); 591 Boolean hasFormat = (NULL != df->_property._HasCustomFormat && df->_property._HasCustomFormat == kCFBooleanTrue) || goingToHaveCustomFormat; 592 if (wantRelative && !hasFormat && kCFDateFormatterNoStyle != df->_dateStyle) { 593 udstyle |= UDAT_RELATIVE; 594 } 595 596 UErrorCode status = U_ZERO_ERROR; 597 UDateFormat *icudf = __cficu_udat_open((UDateFormatStyle)utstyle, (UDateFormatStyle)udstyle, loc_buffer, tz_buffer, CFStringGetLength(tmpTZName), NULL, 0, &status); 598 if (NULL == icudf || U_FAILURE(status)) { 599 return; 600 } 601 if (df->_property._IsLenient != NULL) { 602 __cficu_udat_setLenient(icudf, (kCFBooleanTrue == df->_property._IsLenient)); 603 } else { 604 __cficu_udat_setLenient(icudf, 0); 605 } 606 if (kCFDateFormatterNoStyle == df->_dateStyle && kCFDateFormatterNoStyle == df->_timeStyle) { 607 if (wantRelative && !hasFormat && kCFDateFormatterNoStyle != df->_dateStyle) { 608 UErrorCode s = U_ZERO_ERROR; 609 __cficu_udat_applyPatternRelative(icudf, NULL, 0, NULL, 0, &s); 610 } else { 611 __cficu_udat_applyPattern(icudf, false, NULL, 0); 612 } 613 } 614 if (!wantRelative && df->_property._HasCustomFormat == kCFBooleanTrue) { 615 CFIndex cnt = CFStringGetLength(df->_format); 616 STACK_BUFFER_DECL(UChar, ubuffer, cnt); 617 const UChar *ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)df->_format); 618 if (NULL == ustr) { 619 CFStringGetCharacters(df->_format, CFRangeMake(0, cnt), (UniChar *)ubuffer); 620 ustr = ubuffer; 621 } 622 __cficu_udat_applyPattern(icudf, false, ustr, cnt); 623 } 624 625 CFStringRef calident = (CFStringRef)CFLocaleGetValue(df->_locale, kCFLocaleCalendarIdentifierKey); 626 if (calident && CFEqual(calident, kCFCalendarIdentifierGregorian)) { 627 status = U_ZERO_ERROR; 628 __cficu_udat_set2DigitYearStart(icudf, -631152000000.0, &status); // 1950-01-01 00:00:00 GMT 629 } 630 df->_df = icudf; 631 632 __ReadCustomUDateFormatProperty(df); 633 634 __SetCalendarProperties(df); 635 636 if (wantRelative && !hasFormat && kCFDateFormatterNoStyle != df->_dateStyle) { 637 __substituteFormatStringFromPrefsDFRelative(df); 638 } else { 639 __substituteFormatStringFromPrefsDF(df, false); 640 __substituteFormatStringFromPrefsDF(df, true); 641 } 642 643 __ApplyUDateFormatSymbol(df); 644 645 646 if (wantRelative && !hasFormat && kCFDateFormatterNoStyle != df->_dateStyle) { 647 UChar dateBuffer[BUFFER_SIZE]; 648 UChar timeBuffer[BUFFER_SIZE]; 649 status = U_ZERO_ERROR; 650 CFIndex dateLen = __cficu_udat_toPatternRelativeDate(icudf, dateBuffer, BUFFER_SIZE, &status); 651 CFIndex timeLen = (utstyle != UDAT_NONE) ? __cficu_udat_toPatternRelativeTime(icudf, timeBuffer, BUFFER_SIZE, &status) : 0; 652 if (U_SUCCESS(status) && dateLen <= BUFFER_SIZE && timeLen <= BUFFER_SIZE) { 653 // We assume that the 12/24-hour forcing preferences only affect the Time component 654 CFStringRef newFormat = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)timeBuffer, timeLen); 655 CFStringRef formatString = __CFDateFormatterCreateForcedString(df, newFormat); 656 CFIndex cnt = CFStringGetLength(formatString); 657 CFAssert1(cnt <= BUFFER_SIZE, __kCFLogAssertion, "%s(): time format string too long", __PRETTY_FUNCTION__); 658 if (cnt <= BUFFER_SIZE) { 659 CFStringGetCharacters(formatString, CFRangeMake(0, cnt), (UniChar *)timeBuffer); 660 timeLen = cnt; 661 status = U_ZERO_ERROR; 662 __cficu_udat_applyPatternRelative(icudf, dateBuffer, dateLen, timeBuffer, timeLen, &status); 663 // ignore error and proceed anyway, what else can be done? 664 665 UChar ubuffer[BUFFER_SIZE]; 666 status = U_ZERO_ERROR; 667 int32_t ret = __cficu_udat_toPattern(icudf, false, ubuffer, BUFFER_SIZE, &status); // read out current pattern 668 if (U_SUCCESS(status) && ret <= BUFFER_SIZE) { 669 if (df->_format) CFRelease(df->_format); 670 df->_format = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)ubuffer, ret); 671 } 672 } 673 CFRelease(formatString); 674 CFRelease(newFormat); 675 } 676 } else { 677 UChar ubuffer[BUFFER_SIZE]; 678 status = U_ZERO_ERROR; 679 int32_t ret = __cficu_udat_toPattern(icudf, false, ubuffer, BUFFER_SIZE, &status); 680 if (U_SUCCESS(status) && ret <= BUFFER_SIZE) { 681 CFStringRef newFormat = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)ubuffer, ret); 682 CFStringRef formatString = __CFDateFormatterCreateForcedString(df, newFormat); 683 CFIndex cnt = CFStringGetLength(formatString); 684 CFAssert1(cnt <= 1024, __kCFLogAssertion, "%s(): format string too long", __PRETTY_FUNCTION__); 685 if (df->_format != formatString && cnt <= 1024) { 686 STACK_BUFFER_DECL(UChar, ubuffer, cnt); 687 const UChar *ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)formatString); 688 if (NULL == ustr) { 689 CFStringGetCharacters(formatString, CFRangeMake(0, cnt), (UniChar *)ubuffer); 690 ustr = ubuffer; 691 } 692 UErrorCode status = U_ZERO_ERROR; 693// __cficu_udat_applyPattern(df->_df, false, ustr, cnt, &status); 694 __cficu_udat_applyPattern(df->_df, false, ustr, cnt); 695 if (U_SUCCESS(status)) { 696 if (df->_format) CFRelease(df->_format); 697 df->_format = (CFStringRef)CFStringCreateCopy(CFGetAllocator(df), formatString); 698 } 699 } 700 CFRelease(formatString); 701 CFRelease(newFormat); 702 } 703 } 704 if (df->_defformat) CFRelease(df->_defformat); 705 df->_defformat = df->_format ? (CFStringRef)CFRetain(df->_format) : NULL; 706 707 RESET_PROPERTY(_IsLenient, kCFDateFormatterIsLenientKey); 708 RESET_PROPERTY(_DoesRelativeDateFormatting, kCFDateFormatterDoesRelativeDateFormattingKey); 709 RESET_PROPERTY(_Calendar, kCFDateFormatterCalendarKey); 710 RESET_PROPERTY(_CalendarName, kCFDateFormatterCalendarIdentifierKey); 711 RESET_PROPERTY(_TimeZone, kCFDateFormatterTimeZoneKey); 712 RESET_PROPERTY(_TwoDigitStartDate, kCFDateFormatterTwoDigitStartDateKey); 713 RESET_PROPERTY(_DefaultDate, kCFDateFormatterDefaultDateKey); 714 RESET_PROPERTY(_GregorianStartDate, kCFDateFormatterGregorianStartDateKey); 715 RESET_PROPERTY(_AmbiguousYearStrategy, kCFDateFormatterAmbiguousYearStrategyKey); 716 RESET_PROPERTY(_UsesCharacterDirection, kCFDateFormatterUsesCharacterDirectionKey); 717} 718 719static CFTypeID __kCFDateFormatterTypeID = _kCFRuntimeNotATypeID; 720 721static const CFRuntimeClass __CFDateFormatterClass = { 722 0, 723 "CFDateFormatter", 724 NULL, // init 725 NULL, // copy 726 __CFDateFormatterDeallocate, 727 NULL, 728 NULL, 729 NULL, // 730 __CFDateFormatterCopyDescription 731}; 732 733static void __CFDateFormatterInitialize(void) { 734 __kCFDateFormatterTypeID = _CFRuntimeRegisterClass(&__CFDateFormatterClass); 735} 736 737CFTypeID CFDateFormatterGetTypeID(void) { 738 if (_kCFRuntimeNotATypeID == __kCFDateFormatterTypeID) __CFDateFormatterInitialize(); 739 return __kCFDateFormatterTypeID; 740} 741 742CFDateFormatterRef CFDateFormatterCreate(CFAllocatorRef allocator, CFLocaleRef locale, CFDateFormatterStyle dateStyle, CFDateFormatterStyle timeStyle) { 743 struct __CFDateFormatter *memory; 744 uint32_t size = sizeof(struct __CFDateFormatter) - sizeof(CFRuntimeBase); 745 if (allocator == NULL) allocator = __CFGetDefaultAllocator(); 746 __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); 747 if (locale) __CFGenericValidateType(locale, CFLocaleGetTypeID()); 748 memory = (struct __CFDateFormatter *)_CFRuntimeCreateInstance(allocator, CFDateFormatterGetTypeID(), size, NULL); 749 if (NULL == memory) { 750 return NULL; 751 } 752 memory->_df = NULL; 753 memory->_locale = NULL; 754 memory->_format = NULL; 755 memory->_defformat = NULL; 756 memory->_dateStyle = dateStyle; 757 memory->_timeStyle = timeStyle; 758 memory->_property._IsLenient = NULL; 759 memory->_property._DoesRelativeDateFormatting = NULL; 760 memory->_property._HasCustomFormat = NULL; 761 memory->_property._TimeZone = NULL; 762 memory->_property._Calendar = NULL; 763 memory->_property._CalendarName = NULL; 764 memory->_property._TwoDigitStartDate = NULL; 765 memory->_property._DefaultDate = NULL; 766 memory->_property._GregorianStartDate = NULL; 767 memory->_property._EraSymbols = NULL; 768 memory->_property._LongEraSymbols = NULL; 769 memory->_property._MonthSymbols = NULL; 770 memory->_property._ShortMonthSymbols = NULL; 771 memory->_property._VeryShortMonthSymbols = NULL; 772 memory->_property._StandaloneMonthSymbols = NULL; 773 memory->_property._ShortStandaloneMonthSymbols = NULL; 774 memory->_property._VeryShortStandaloneMonthSymbols = NULL; 775 memory->_property._WeekdaySymbols = NULL; 776 memory->_property._ShortWeekdaySymbols = NULL; 777 memory->_property._VeryShortWeekdaySymbols = NULL; 778 memory->_property._StandaloneWeekdaySymbols = NULL; 779 memory->_property._ShortStandaloneWeekdaySymbols = NULL; 780 memory->_property._VeryShortStandaloneWeekdaySymbols = NULL; 781 memory->_property._QuarterSymbols = NULL; 782 memory->_property._ShortQuarterSymbols = NULL; 783 memory->_property._StandaloneQuarterSymbols = NULL; 784 memory->_property._ShortStandaloneQuarterSymbols = NULL; 785 memory->_property._AMSymbol = NULL; 786 memory->_property._PMSymbol = NULL; 787 memory->_property._AmbiguousYearStrategy = NULL; 788 memory->_property._UsesCharacterDirection = NULL; 789 memory->_property._CustomEraSymbols = NULL; 790 memory->_property._CustomMonthSymbols = NULL; 791 memory->_property._CustomShortMonthSymbols = NULL; 792 memory->_property._CustomWeekdaySymbols = NULL; 793 memory->_property._CustomShortWeekdaySymbols = NULL; 794 memory->_property._CustomLongEraSymbols = NULL; 795 memory->_property._CustomVeryShortMonthSymbols = NULL; 796 memory->_property._CustomVeryShortWeekdaySymbols = NULL; 797 memory->_property._CustomStandaloneMonthSymbols = NULL; 798 memory->_property._CustomShortStandaloneMonthSymbols = NULL; 799 memory->_property._CustomVeryShortStandaloneMonthSymbols = NULL; 800 memory->_property._CustomStandaloneWeekdaySymbols = NULL; 801 memory->_property._CustomShortStandaloneWeekdaySymbols = NULL; 802 memory->_property._CustomVeryShortStandaloneWeekdaySymbols = NULL; 803 memory->_property._CustomQuarterSymbols = NULL; 804 memory->_property._CustomShortQuarterSymbols = NULL; 805 memory->_property._CustomStandaloneQuarterSymbols = NULL; 806 memory->_property._CustomShortStandaloneQuarterSymbols = NULL; 807 memory->_property._CustomDateFormat = NULL; 808 memory->_property._CustomTimeFormat = NULL; 809 memory->_property._Custom24Hour = NULL; 810 memory->_property._Custom12Hour = NULL; 811 memory->_property._CustomAMSymbol = NULL; 812 memory->_property._CustomPMSymbol = NULL; 813 memory->_property._CustomFirstWeekday = NULL; 814 memory->_property._CustomMinDaysInFirstWeek = NULL; 815 816 switch (dateStyle) { 817 case kCFDateFormatterNoStyle: 818 case kCFDateFormatterShortStyle: 819 case kCFDateFormatterMediumStyle: 820 case kCFDateFormatterLongStyle: 821 case kCFDateFormatterFullStyle: break; 822 default: 823 CFAssert2(0, __kCFLogAssertion, "%s(): unknown date style %d", __PRETTY_FUNCTION__, dateStyle); 824 memory->_dateStyle = kCFDateFormatterMediumStyle; 825 break; 826 } 827 switch (timeStyle) { 828 case kCFDateFormatterNoStyle: 829 case kCFDateFormatterShortStyle: 830 case kCFDateFormatterMediumStyle: 831 case kCFDateFormatterLongStyle: 832 case kCFDateFormatterFullStyle: break; 833 default: 834 CFAssert2(0, __kCFLogAssertion, "%s(): unknown time style %d", __PRETTY_FUNCTION__, timeStyle); 835 memory->_timeStyle = kCFDateFormatterMediumStyle; 836 break; 837 } 838 839 memory->_locale = locale ? CFLocaleCreateCopy(allocator, locale) : (CFLocaleRef)CFRetain(CFLocaleGetSystem()); 840 memory->_property._TimeZone = CFTimeZoneCopyDefault(); 841 842 CFStringRef calident = (CFStringRef)CFLocaleGetValue(memory->_locale, kCFLocaleCalendarIdentifierKey); 843 if (calident && CFEqual(calident, kCFCalendarIdentifierGregorian)) { 844 memory->_property._TwoDigitStartDate = CFDateCreate(kCFAllocatorSystemDefault, -1609459200.0); // 1950-01-01 00:00:00 +0000 845 } 846 847 __ResetUDateFormat(memory, false); 848 if (!memory->_df) { 849 CFRelease(memory); 850 return NULL; 851 } 852 return (CFDateFormatterRef)memory; 853} 854 855static void __substituteFormatStringFromPrefsDFRelative(CFDateFormatterRef formatter) { 856 857 CFIndex dateLen = -1; 858 UChar dateBuffer[BUFFER_SIZE]; 859 if (kCFDateFormatterNoStyle != formatter->_dateStyle) { 860 if (formatter->_property._CustomDateFormat != NULL) { 861 dateLen = __CFMin(CFStringGetLength(formatter->_property._CustomDateFormat), BUFFER_SIZE); 862 CFStringGetCharacters(formatter->_property._CustomDateFormat, CFRangeMake(0, dateLen), (UniChar *)dateBuffer); 863 } 864 } 865 if (-1 == dateLen) { 866 UErrorCode status = U_ZERO_ERROR; 867 int32_t ret = __cficu_udat_toPatternRelativeDate(formatter->_df, dateBuffer, BUFFER_SIZE, &status); 868 if (!U_FAILURE(status)) { 869 dateLen = ret; 870 } 871 } 872 873 CFIndex timeLen = -1; 874 UChar timeBuffer[BUFFER_SIZE]; 875 if (kCFDateFormatterNoStyle != formatter->_timeStyle) { 876 if (formatter->_property._CustomTimeFormat != NULL) { 877 timeLen = __CFMin(CFStringGetLength(formatter->_property._CustomTimeFormat), BUFFER_SIZE); 878 CFStringGetCharacters(formatter->_property._CustomTimeFormat, CFRangeMake(0, timeLen), (UniChar *)timeBuffer); 879 } 880 } 881 if (-1 == timeLen) { 882 UErrorCode status = U_ZERO_ERROR; 883 int32_t ret = __cficu_udat_toPatternRelativeTime(formatter->_df, timeBuffer, BUFFER_SIZE, &status); 884 if (!U_FAILURE(status)) { 885 timeLen = ret; 886 } 887 } 888 889 UErrorCode status = U_ZERO_ERROR; 890 __cficu_udat_applyPatternRelative(formatter->_df, (0 <= dateLen) ? dateBuffer : NULL, (0 <= dateLen) ? dateLen : 0, (0 <= timeLen) ? timeBuffer : NULL, (0 <= timeLen) ? timeLen : 0, &status); 891} 892 893static void __substituteFormatStringFromPrefsDF(CFDateFormatterRef formatter, bool doTime) { 894 CFIndex formatStyle = doTime ? formatter->_timeStyle : formatter->_dateStyle; 895 CFStringRef pref = doTime ? formatter->_property._CustomTimeFormat : formatter->_property._CustomDateFormat; 896 if (kCFDateFormatterNoStyle != formatStyle) { 897 if (NULL != pref) { 898 int32_t icustyle = UDAT_NONE; 899 switch (formatStyle) { 900 case kCFDateFormatterShortStyle: icustyle = UDAT_SHORT; break; 901 case kCFDateFormatterMediumStyle: icustyle = UDAT_MEDIUM; break; 902 case kCFDateFormatterLongStyle: icustyle = UDAT_LONG; break; 903 case kCFDateFormatterFullStyle: icustyle = UDAT_FULL; break; 904 } 905 CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale); 906 char buffer[BUFFER_SIZE]; 907 const char *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII); 908 if (NULL == cstr) { 909 if (CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer; 910 } 911 UErrorCode status = U_ZERO_ERROR; 912 UDateFormat *df = __cficu_udat_open((UDateFormatStyle)(doTime ? icustyle : UDAT_NONE), (UDateFormatStyle)(doTime ? UDAT_NONE : icustyle), cstr, NULL, 0, NULL, 0, &status); 913 if (NULL != df) { 914 UChar ubuffer[BUFFER_SIZE]; 915 status = U_ZERO_ERROR; 916 int32_t date_len = __cficu_udat_toPattern(df, false, ubuffer, BUFFER_SIZE, &status); 917 if (U_SUCCESS(status) && date_len <= BUFFER_SIZE) { 918 CFStringRef dateString = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)ubuffer, date_len); 919 status = U_ZERO_ERROR; 920 int32_t formatter_len = __cficu_udat_toPattern(formatter->_df, false, ubuffer, BUFFER_SIZE, &status); 921 if (U_SUCCESS(status) && formatter_len <= BUFFER_SIZE) { 922 CFMutableStringRef formatString = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); 923 CFStringAppendCharacters(formatString, (UniChar *)ubuffer, formatter_len); 924 // find dateString inside formatString, substitute the pref in that range 925 CFRange result; 926 if (CFStringFindWithOptions(formatString, dateString, CFRangeMake(0, formatter_len), 0, &result)) { 927 CFStringReplace(formatString, result, pref); 928 int32_t new_len = CFStringGetLength(formatString); 929 STACK_BUFFER_DECL(UChar, new_buffer, new_len); 930 const UChar *new_ustr = (UChar *)CFStringGetCharactersPtr(formatString); 931 if (NULL == new_ustr) { 932 CFStringGetCharacters(formatString, CFRangeMake(0, new_len), (UniChar *)new_buffer); 933 new_ustr = new_buffer; 934 } 935 status = U_ZERO_ERROR; 936// __cficu_udat_applyPattern(formatter->_df, false, new_ustr, new_len, &status); 937 __cficu_udat_applyPattern(formatter->_df, false, new_ustr, new_len); 938 } 939 CFRelease(formatString); 940 } 941 CFRelease(dateString); 942 } 943 __cficu_udat_close(df); 944 } 945 } 946 } 947} 948 949static void __CFDateFormatterStoreSymbolPrefs(const void *key, const void *value, void *context) { 950 if (CFGetTypeID(key) == CFStringGetTypeID() && CFGetTypeID(value) == CFArrayGetTypeID()) { 951 CFDateFormatterRef formatter = (CFDateFormatterRef)context; 952 UDateFormatSymbolType sym = (UDateFormatSymbolType)CFStringGetIntValue((CFStringRef)key); 953 CFArrayRef array = (CFArrayRef)value; 954 CFIndex idx, cnt = CFArrayGetCount(array); 955 switch (sym) { 956 case UDAT_ERAS: 957 formatter->_property._CustomEraSymbols = (CFArrayRef)CFRetain(array); 958 break; 959 case UDAT_MONTHS: 960 formatter->_property._CustomMonthSymbols = (CFArrayRef)CFRetain(array); 961 break; 962 case UDAT_SHORT_MONTHS: 963 formatter->_property._CustomShortMonthSymbols = (CFArrayRef)CFRetain(array); 964 break; 965 case UDAT_WEEKDAYS: 966 formatter->_property._CustomWeekdaySymbols = (CFArrayRef)CFRetain(array); 967 break; 968 case UDAT_SHORT_WEEKDAYS: 969 formatter->_property._CustomShortWeekdaySymbols = (CFArrayRef)CFRetain(array); 970 break; 971 case UDAT_AM_PMS: 972 { 973 for (idx = 0; idx < cnt; idx++) { 974 CFStringRef item = (CFStringRef)CFArrayGetValueAtIndex(array, idx); 975 if (CFGetTypeID(item) != CFStringGetTypeID()) continue; 976 if (idx == 0) { 977 formatter->_property._CustomAMSymbol = (CFStringRef)CFRetain(item); 978 } else if (idx == 1) { 979 formatter->_property._CustomPMSymbol = (CFStringRef)CFRetain(item); 980 } 981 } 982 } 983 break; 984 case UDAT_ERA_NAMES: 985 formatter->_property._CustomLongEraSymbols = (CFArrayRef)CFRetain(array); 986 break; 987 case UDAT_NARROW_MONTHS: 988 formatter->_property._CustomVeryShortMonthSymbols = (CFArrayRef)CFRetain(array); 989 break; 990 case UDAT_NARROW_WEEKDAYS: 991 formatter->_property._CustomVeryShortWeekdaySymbols = (CFArrayRef)CFRetain(array); 992 break; 993 case UDAT_STANDALONE_MONTHS: 994 formatter->_property._CustomStandaloneMonthSymbols = (CFArrayRef)CFRetain(array); 995 break; 996 case UDAT_STANDALONE_SHORT_MONTHS: 997 formatter->_property._CustomShortStandaloneMonthSymbols = (CFArrayRef)CFRetain(array); 998 break; 999 case UDAT_STANDALONE_NARROW_MONTHS: 1000 formatter->_property._CustomVeryShortStandaloneMonthSymbols = (CFArrayRef)CFRetain(array); 1001 break; 1002 case UDAT_STANDALONE_WEEKDAYS: 1003 formatter->_property._CustomStandaloneWeekdaySymbols = (CFArrayRef)CFRetain(array); 1004 break; 1005 case UDAT_STANDALONE_SHORT_WEEKDAYS: 1006 formatter->_property._CustomShortStandaloneWeekdaySymbols = (CFArrayRef)CFRetain(array); 1007 break; 1008 case UDAT_STANDALONE_NARROW_WEEKDAYS: 1009 formatter->_property._CustomVeryShortStandaloneWeekdaySymbols = (CFArrayRef)CFRetain(array); 1010 break; 1011 case UDAT_QUARTERS: 1012 formatter->_property._CustomQuarterSymbols = (CFArrayRef)CFRetain(array); 1013 break; 1014 case UDAT_SHORT_QUARTERS: 1015 formatter->_property._CustomShortQuarterSymbols = (CFArrayRef)CFRetain(array); 1016 break; 1017 case UDAT_STANDALONE_QUARTERS: 1018 formatter->_property._CustomStandaloneQuarterSymbols = (CFArrayRef)CFRetain(array); 1019 break; 1020 case UDAT_STANDALONE_SHORT_QUARTERS: 1021 formatter->_property._CustomShortStandaloneQuarterSymbols = (CFArrayRef)CFRetain(array); 1022 break; 1023 default: 1024 break; 1025 } 1026 } 1027} 1028 1029static CFStringRef __CFDateFormatterCreateForcedTemplate(CFLocaleRef locale, CFStringRef inString) { 1030 if (!inString) return NULL; 1031 1032 Boolean doForce24 = false, doForce12 = false; 1033 CFDictionaryRef prefs = __CFLocaleGetPrefs(locale); 1034 CFPropertyListRef pref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUForce24HourTime")) : NULL; 1035 if (NULL != pref && CFGetTypeID(pref) == CFBooleanGetTypeID()) { 1036 doForce24 = CFBooleanGetValue((CFBooleanRef)pref); 1037 } 1038 pref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUForce12HourTime")) : NULL; 1039 if (NULL != pref && CFGetTypeID(pref) == CFBooleanGetTypeID()) { 1040 doForce12 = CFBooleanGetValue((CFBooleanRef)pref); 1041 } 1042 if (doForce24) doForce12 = false; // if both are set, Force24 wins, period 1043 if (!doForce24 && !doForce12) return (CFStringRef)CFRetain(inString); 1044 1045 CFMutableStringRef outString = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); 1046 CFIndex cnt = CFStringGetLength(inString); 1047 CFIndex lastSecond = -1, lastMinute = -1, firstHour = -1; 1048 Boolean isInQuote = false, hasA = false, had12Hour = false, had24Hour = false; 1049 for (CFIndex idx = 0; idx < cnt; idx++) { 1050 Boolean emit = true; 1051 UniChar ch = CFStringGetCharacterAtIndex(inString, idx); 1052 switch (ch) { 1053 case '\'': isInQuote = !isInQuote; break; 1054 case 'j': if (!isInQuote) {if (-1 == firstHour) firstHour = CFStringGetLength(outString); if (doForce24) ch = 'H'; else ch = 'h';} break; 1055 case 'h': if (!isInQuote) {if (-1 == firstHour) firstHour = CFStringGetLength(outString); had12Hour = true; if (doForce24) ch = 'H';} break; // switch 12-hour to 24-hour 1056 case 'K': if (!isInQuote) {if (-1 == firstHour) firstHour = CFStringGetLength(outString); had12Hour = true; if (doForce24) ch = 'k';} break; // switch 12-hour to 24-hour 1057 case 'H': if (!isInQuote) {if (-1 == firstHour) firstHour = CFStringGetLength(outString); had24Hour = true; if (doForce12) ch = 'h';} break; // switch 24-hour to 12-hour 1058 case 'k': if (!isInQuote) {if (-1 == firstHour) firstHour = CFStringGetLength(outString); had24Hour = true; if (doForce12) ch = 'K';} break; // switch 24-hour to 12-hour 1059 case 'm': if (!isInQuote) lastMinute = CFStringGetLength(outString); break; 1060 case 's': if (!isInQuote) lastSecond = CFStringGetLength(outString); break; 1061 case 'a': if (!isInQuote) {hasA = true; if (doForce24) emit = false;} break; 1062 break; 1063 } 1064 if (emit) CFStringAppendCharacters(outString, &ch, 1); 1065 } 1066 1067 return outString; 1068} 1069 1070/* 1071 Mapping H<->h and K<->k is not correct in all locales; Japanese 12 hour, for example, uses H<->k 1072 This gets an approximately correct replacement character for the locale and forcing direction in question 1073 <rdar://problem/14062096> [iCal] Incorrect time format is used for current time indicator line 1074 */ 1075static UChar __CFDateFormatterForcedHourCharacterForLocale(CFLocaleRef locale, Boolean doForce24, Boolean doForce12, Boolean *succeeded) { 1076 if (doForce24) doForce12 = false; // if both are set, Force24 wins, period 1077 if (!locale || (!doForce24 && !doForce12)) { 1078 *succeeded = false; 1079 return '\0'; 1080 } 1081 CFStringRef localeName = locale ? CFLocaleGetIdentifier(locale) : CFSTR(""); 1082 char buffer[BUFFER_SIZE] = {0}; 1083 const char *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII); 1084 if (NULL == cstr) { 1085 if (CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer; 1086 } 1087 1088 __block UChar hourPatternChar = '\0'; 1089 1090 useTemplatePatternGenerator(cstr, ^(UDateTimePatternGenerator *ptg) { 1091 UChar hourPattern[256] = {0}; 1092 int32_t patternLen = -1; 1093 if (ptg) { 1094 UErrorCode errorCode = U_ZERO_ERROR; 1095 patternLen = __cficu_udatpg_getBestPattern(ptg, (const UChar *)(doForce12 ? "h" : "H"), 1, hourPattern, sizeof(hourPattern) / sizeof(UChar), &errorCode); 1096 if (errorCode != U_ZERO_ERROR) { 1097 memset(hourPattern, 0, sizeof(hourPattern)); //make sure there's nothing there if we failed 1098 patternLen = -1; 1099 } 1100 } 1101 1102 /* 1103 Blindly replacing HHHH with four copies of the entire udatpg_getBestPattern result is not going to work. Search for the first [hHkK] in the result and use just that 1104 */ 1105 if (patternLen > 0) { 1106 for (CFIndex idx = 0; hourPattern[idx] != '\0' && idx < patternLen && idx < sizeof(hourPattern) / sizeof(UChar); idx++) { 1107 if (hourPattern[idx] == 'k' || hourPattern[idx] == 'K' || hourPattern[idx] == 'h' || hourPattern[idx] == 'H') { 1108 hourPatternChar = hourPattern[idx]; 1109 break; 1110 } 1111 } 1112 } 1113 }); 1114 1115 *succeeded = hourPatternChar != '\0'; 1116 return hourPatternChar; 1117} 1118 1119#define FORCE_CHAR(replacement, oldType, newType) do { \ 1120 if (!isInQuote) {\ 1121 if (-1 == firstHour) {\ 1122 firstHour = CFStringGetLength(outString);\ 1123 }\ 1124 had##oldType##Hour = true;\ 1125 if (doForce##newType) {\ 1126 ch = useSpecialHourChar ? hourPatternChar : replacement;\ 1127 }\ 1128 }\ 1129}while(0) 1130#define FORCE_CHAR_12(replacement) FORCE_CHAR(replacement, 12, 24) 1131#define FORCE_CHAR_24(replacement) FORCE_CHAR(replacement, 24, 12) 1132 1133static CFStringRef __CFDateFormatterCreateForcedString(CFDateFormatterRef formatter, CFStringRef inString) { 1134 if (!inString) return NULL; 1135 1136 Boolean doForce24 = false, doForce12 = false; 1137 if (formatter->_property._Custom24Hour != NULL) { 1138 doForce24 = CFBooleanGetValue((CFBooleanRef)formatter->_property._Custom24Hour); 1139 } 1140 if (formatter->_property._Custom12Hour != NULL) { 1141 doForce12 = CFBooleanGetValue((CFBooleanRef)formatter->_property._Custom12Hour); 1142 } 1143 if (doForce24) doForce12 = false; // if both are set, Force24 wins, period 1144 1145 static CFCharacterSetRef hourCharacters; 1146 static dispatch_once_t onceToken; 1147 dispatch_once(&onceToken, ^{ 1148 hourCharacters = CFCharacterSetCreateWithCharactersInString(kCFAllocatorSystemDefault, CFSTR("hHkK")); 1149 }); 1150 1151 CFRange hourRange = CFRangeMake(kCFNotFound, 0); 1152 if (!CFStringFindCharacterFromSet(inString, hourCharacters, CFRangeMake(0, CFStringGetLength(inString)), 0, &hourRange) || hourRange.location == kCFNotFound) { 1153 doForce12 = false; 1154 doForce24 = false; 1155 } 1156 1157 if (!doForce24 && !doForce12) return (CFStringRef)CFRetain(inString); 1158 1159 Boolean useSpecialHourChar = false; 1160 UChar hourPatternChar = __CFDateFormatterForcedHourCharacterForLocale(formatter->_locale, doForce24, doForce12, &useSpecialHourChar); 1161 1162 CFMutableStringRef outString = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); 1163 CFIndex cnt = CFStringGetLength(inString); 1164 CFIndex lastSecond = -1, lastMinute = -1, firstHour = -1; 1165 Boolean isInQuote = false, hasA = false, had12Hour = false, had24Hour = false; 1166 for (CFIndex idx = 0; idx < cnt; idx++) { 1167 Boolean emit = true; 1168 UniChar ch = CFStringGetCharacterAtIndex(inString, idx); 1169 switch (ch) { 1170 case '\'': isInQuote = !isInQuote; break; 1171 case 'h': FORCE_CHAR_12('H'); break; // switch 12-hour to 24-hour 1172 case 'k': FORCE_CHAR_24('K'); break; // switch 24-hour to 12-hour 1173 case 'H': FORCE_CHAR_24('h'); break; // switch 24-hour to 12-hour 1174 case 'K': FORCE_CHAR_12('k'); break; // switch 12-hour to 24-hour 1175 case 'm': if (!isInQuote) lastMinute = CFStringGetLength(outString); break; 1176 case 's': if (!isInQuote) lastSecond = CFStringGetLength(outString); break; 1177 case 'a': if (!isInQuote) hasA = true; 1178 if (!isInQuote && doForce24) { 1179 // skip 'a' and one optional trailing space 1180 emit = false; 1181 if (idx + 1 < cnt && ' ' == CFStringGetCharacterAtIndex(inString, idx + 1)) idx++; 1182 } 1183 break; 1184 case ' ': 1185 if (!isInQuote && doForce24) { 1186 // if next character is 'a' AND we have seen the hour designator, skip space and 'a' 1187 if (idx + 1 < cnt && 'a' == CFStringGetCharacterAtIndex(inString, idx + 1) && -1 != firstHour) { 1188 emit = false; 1189 idx++; 1190 } 1191 } 1192 break; 1193 } 1194 if (emit) CFStringAppendCharacters(outString, &ch, 1); 1195 } 1196 if (doForce12 && !hasA && had24Hour) { 1197 CFStringRef locName = CFLocaleGetIdentifier(formatter->_locale); 1198 if (-1 != firstHour && (CFStringHasPrefix(locName, CFSTR("ko")) || CFEqual(locName, CFSTR("zh_SG")))) { 1199 CFStringInsert(outString, firstHour, CFSTR("a ")); 1200 } else if (-1 != firstHour && (CFStringHasPrefix(locName, CFSTR("zh")) || CFStringHasPrefix(locName, CFSTR("ja")))) { 1201 CFStringInsert(outString, firstHour, CFSTR("a")); 1202 } else { 1203 CFIndex lastPos = (-1 != lastSecond) ? lastSecond : ((-1 != lastMinute) ? lastMinute : -1); 1204 if (-1 != lastPos) { 1205 cnt = CFStringGetLength(outString); 1206 lastPos++; 1207 UniChar ch = (lastPos < cnt) ? CFStringGetCharacterAtIndex(outString, lastPos) : 0; 1208 switch (ch) { 1209 case '\"': lastPos++; break; 1210 case '\'':; 1211 again:; 1212 do { 1213 lastPos++; 1214 ch = (lastPos < cnt) ? CFStringGetCharacterAtIndex(outString, lastPos) : 0; 1215 } while ('\'' != ch && '\0' != ch); 1216 if ('\'' == ch) lastPos++; 1217 ch = (lastPos < cnt) ? CFStringGetCharacterAtIndex(outString, lastPos) : 0; 1218 if ('\'' == ch) goto again; 1219 break; 1220 } 1221 CFStringInsert(outString, lastPos, CFSTR(" a")); 1222 } 1223 } 1224 } 1225 return outString; 1226} 1227 1228CFLocaleRef CFDateFormatterGetLocale(CFDateFormatterRef formatter) { 1229 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); 1230 return formatter->_locale; 1231} 1232 1233CFDateFormatterStyle CFDateFormatterGetDateStyle(CFDateFormatterRef formatter) { 1234 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); 1235 return formatter->_dateStyle; 1236} 1237 1238CFDateFormatterStyle CFDateFormatterGetTimeStyle(CFDateFormatterRef formatter) { 1239 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); 1240 return formatter->_timeStyle; 1241} 1242 1243CFStringRef CFDateFormatterGetFormat(CFDateFormatterRef formatter) { 1244 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); 1245 return formatter->_format; 1246} 1247 1248void CFDateFormatterSetFormat(CFDateFormatterRef formatter, CFStringRef formatString) { 1249 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); 1250 __CFGenericValidateType(formatString, CFStringGetTypeID()); 1251 formatString = __CFDateFormatterCreateForcedString(formatter, formatString); 1252 CFIndex cnt = CFStringGetLength(formatString); 1253 CFAssert1(cnt <= 1024, __kCFLogAssertion, "%s(): format string too long", __PRETTY_FUNCTION__); 1254 if (formatter->_format != formatString && cnt <= 1024) { 1255 // When going from a situation where there is no custom format already, 1256 // and the "relative date formatting" property is set, we need to reset 1257 // the whole UDateFormat. 1258 if (formatter->_property._HasCustomFormat != kCFBooleanTrue && formatter->_property._DoesRelativeDateFormatting == kCFBooleanTrue) { 1259 __ResetUDateFormat(formatter, true); 1260 // the "true" results in: if you set a custom format string, you don't get relative date formatting 1261 } 1262 STACK_BUFFER_DECL(UChar, ubuffer, cnt); 1263 const UChar *ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)formatString); 1264 if (NULL == ustr) { 1265 CFStringGetCharacters(formatString, CFRangeMake(0, cnt), (UniChar *)ubuffer); 1266 ustr = ubuffer; 1267 } 1268 UErrorCode status = U_ZERO_ERROR; 1269// __cficu_udat_applyPattern(formatter->_df, false, ustr, cnt, &status); 1270 __cficu_udat_applyPattern(formatter->_df, false, ustr, cnt); 1271 if (U_SUCCESS(status)) { 1272 if (formatter->_format) CFRelease(formatter->_format); 1273 formatter->_format = (CFStringRef)CFStringCreateCopy(CFGetAllocator(formatter), formatString); 1274 formatter->_property._HasCustomFormat = kCFBooleanTrue; 1275 } 1276 } 1277 if (formatString) CFRelease(formatString); 1278} 1279 1280CFStringRef CFDateFormatterCreateStringWithDate(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFDateRef date) { 1281 if (allocator == NULL) allocator = __CFGetDefaultAllocator(); 1282 __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); 1283 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); 1284 __CFGenericValidateType(date, CFDateGetTypeID()); 1285 return CFDateFormatterCreateStringWithAbsoluteTime(allocator, formatter, CFDateGetAbsoluteTime(date)); 1286} 1287 1288CFStringRef CFDateFormatterCreateStringWithAbsoluteTime(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFAbsoluteTime at) { 1289 if (allocator == NULL) allocator = __CFGetDefaultAllocator(); 1290 __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); 1291 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); 1292 UChar *ustr = NULL, ubuffer[BUFFER_SIZE + 1]; 1293 UErrorCode status = U_ZERO_ERROR; 1294 CFIndex used, cnt = BUFFER_SIZE; 1295 UDate ud = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0 + 0.5; 1296 used = __cficu_udat_format(formatter->_df, ud, ubuffer + 1, cnt, NULL, &status); 1297 if (status == U_BUFFER_OVERFLOW_ERROR || cnt < used) { 1298 cnt = used + 1 + 1; // leave room for RTL marker if needed 1299 ustr = (UChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UChar) * cnt, 0); 1300 status = U_ZERO_ERROR; 1301 used = __cficu_udat_format(formatter->_df, ud, ustr + 1, cnt, NULL, &status); 1302 } 1303 CFStringRef string = NULL; 1304 if (U_SUCCESS(status)) { 1305 UniChar *bufferToUse = ustr ? (UniChar *)ustr : (UniChar *)ubuffer; 1306 if (formatter->_property._UsesCharacterDirection == kCFBooleanTrue && CFLocaleGetLanguageCharacterDirection(CFLocaleGetIdentifier(formatter->_locale)) == kCFLocaleLanguageDirectionRightToLeft) { 1307 // Insert Unicode RTL marker 1308 bufferToUse[0] = 0x200F; 1309 used++; 1310 } else { 1311 // Move past direction marker 1312 bufferToUse++; 1313 } 1314 string = CFStringCreateWithCharacters(allocator, bufferToUse, used); 1315 } 1316 if (ustr) CFAllocatorDeallocate(kCFAllocatorSystemDefault, ustr); 1317 return string; 1318} 1319 1320static UDate __CFDateFormatterCorrectTimeWithTarget(UCalendar *calendar, UDate at, int32_t target, Boolean isEra, UErrorCode *status) { 1321 __cficu_ucal_setMillis(calendar, at, status); 1322 UCalendarDateFields field = isEra ? UCAL_ERA : UCAL_YEAR; 1323 __cficu_ucal_set(calendar, field, target); 1324 return __cficu_ucal_getMillis(calendar, status); 1325} 1326 1327static UDate __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(UCalendar *calendar, UDate at, CFIndex period, CFIndex pastYears, CFIndex futureYears, Boolean isEra, UErrorCode *status) { 1328 __cficu_ucal_setMillis(calendar, __cficu_ucal_getNow(), status); 1329 int32_t currYear = __cficu_ucal_get(calendar, UCAL_YEAR, status); 1330 UCalendarDateFields field = isEra ? UCAL_ERA : UCAL_YEAR; 1331 int32_t currEraOrCentury = __cficu_ucal_get(calendar, field, status); 1332 if (!isEra) { 1333 currYear %= 100; 1334 currEraOrCentury = currEraOrCentury / 100 * 100; // get century 1335 } 1336 1337 CFIndex futureMax = currYear + futureYears; 1338 CFIndex pastMin = currYear - pastYears; 1339 1340 CFRange currRange, futureRange, pastRange; 1341 currRange.location = futureRange.location = pastRange.location = kCFNotFound; 1342 currRange.length = futureRange.length = pastRange.length = 0; 1343 if (!isEra) { 1344 if (period < INT_MAX && futureMax >= period) { 1345 futureRange.location = 0; 1346 futureRange.length = futureMax - period + 1; 1347 } 1348 if (pastMin < 0) { 1349 pastRange.location = period + pastMin; 1350 pastRange.length = period - pastRange.location; 1351 } 1352 if (pastRange.location != kCFNotFound) { 1353 currRange.location = 0; 1354 } else { 1355 currRange.location = pastMin; 1356 } 1357 } else { 1358 if (period < INT_MAX && futureMax > period) { 1359 futureRange.location = 1, 1360 futureRange.length = futureMax - period; 1361 } 1362 if (pastMin <= 0) { 1363 pastRange.location = period + pastMin; 1364 pastRange.length = period - pastRange.location + 1; 1365 } 1366 if (pastRange.location != kCFNotFound) { 1367 currRange.location = 1; 1368 } else { 1369 currRange.location = pastMin; 1370 } 1371 1372 } 1373 currRange.length = period - pastRange.length - futureRange.length; 1374 1375 __cficu_ucal_setMillis(calendar, at, status); 1376 int32_t atYear = __cficu_ucal_get(calendar, UCAL_YEAR, status); 1377 if (!isEra) { 1378 atYear %= 100; 1379 currEraOrCentury += atYear; 1380 } 1381 1382 int32_t offset = 0; // current era or century 1383 if (pastRange.location != kCFNotFound && atYear >= pastRange.location && atYear - pastRange.location + 1 <= pastRange.length) { 1384 offset = -1; // past era or century 1385 } else if (futureRange.location != kCFNotFound && atYear >= futureRange.location && atYear - futureRange.location + 1 <= futureRange.length) { 1386 offset = 1; // next era or century 1387 } 1388 if (!isEra) offset *= 100; 1389 return __CFDateFormatterCorrectTimeWithTarget(calendar, at, currEraOrCentury+offset, isEra, status); 1390} 1391 1392#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS 1393static int32_t __CFDateFormatterGetMaxYearGivenJapaneseEra(UCalendar *calendar, int32_t era, UErrorCode *status) { 1394 int32_t years = 0; 1395 __cficu_ucal_clear(calendar); 1396 __cficu_ucal_set(calendar, UCAL_ERA, era+1); 1397 UDate target = __cficu_ucal_getMillis(calendar, status); 1398 __cficu_ucal_set(calendar, UCAL_ERA, era); 1399 years = __cficu_ucal_getFieldDifference(calendar, target, UCAL_YEAR, status); 1400 return years+1; 1401} 1402#endif 1403 1404static Boolean __CFDateFormatterHandleAmbiguousYear(CFDateFormatterRef formatter, CFStringRef calendar_id, UDateFormat *df, UCalendar *cal, UDate *at, const UChar *ustr, CFIndex length, UErrorCode *status) { 1405 Boolean success = true; 1406 int64_t ambigStrat = kCFDateFormatterAmbiguousYearAssumeToNone; 1407 if (formatter->_property._AmbiguousYearStrategy) { 1408 CFNumberGetValue(formatter->_property._AmbiguousYearStrategy, kCFNumberSInt64Type, &ambigStrat); 1409 } 1410 if (calendar_id == kCFCalendarIdentifierChinese) { 1411 // we default to era 1 if era is missing, however, we cannot just test if the era is 1 becuase we may get era 2 or larger if the year in the string is greater than 60 1412 // now I just assume that the year will not be greater than 600 in the string 1413 if (__cficu_ucal_get(cal, UCAL_ERA, status) < 10) { 1414 switch (ambigStrat) { 1415 case kCFDateFormatterAmbiguousYearFailToParse: 1416 success = false; 1417 break; 1418 case kCFDateFormatterAmbiguousYearAssumeToCurrent: { 1419 __cficu_ucal_setMillis(cal, __cficu_ucal_getNow(), status); 1420 int32_t currEra = __cficu_ucal_get(cal, UCAL_ERA, status); 1421 *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, currEra, true, status); 1422 break; 1423 } 1424 case kCFDateFormatterAmbiguousYearAssumeToCenteredAroundCurrentDate: 1425 *at = __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal, *at, 60, 29, 30, true, status); 1426 break; 1427 case kCFDateFormatterAmbiguousYearAssumeToFuture: 1428 *at = __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal, *at, 60, 0, 59, true, status); 1429 break; 1430 case kCFDateFormatterAmbiguousYearAssumeToPast: 1431 *at = __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal, *at, 60, 59, 0, true, status); 1432 break; 1433 case kCFDateFormatterAmbiguousYearAssumeToLikelyFuture: 1434 *at = __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal, *at, 60, 10, 49, true, status); 1435 break; 1436 case kCFDateFormatterAmbiguousYearAssumeToLikelyPast: 1437 *at = __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal, *at, 60, 49, 10, true, status); 1438 break; 1439 case kCFDateFormatterAmbiguousYearAssumeToNone: 1440 default: 1441 break; // do nothing 1442 } 1443 } 1444 } else if (calendar_id == kCFCalendarIdentifierJapanese) { // ??? need more work 1445#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS 1446 __cficu_ucal_clear(cal); 1447 __cficu_ucal_set(cal, UCAL_ERA, 1); 1448 __cficu_udat_parseCalendar(df, cal, ustr, length, NULL, status); 1449 UDate test = __cficu_ucal_getMillis(cal, status); 1450 if (test != *at) { // missing era 1451 __cficu_ucal_setMillis(cal, *at, status); 1452 int32_t givenYear = __cficu_ucal_get(cal, UCAL_YEAR, status); 1453 __cficu_ucal_setMillis(cal, __cficu_ucal_getNow(), status); 1454 int32_t currYear = __cficu_ucal_get(cal, UCAL_YEAR, status); 1455 int32_t currEra = __cficu_ucal_get(cal, UCAL_ERA, status); 1456 switch (ambigStrat) { 1457 case kCFDateFormatterAmbiguousYearFailToParse: 1458 success = false; 1459 break; 1460 case kCFDateFormatterAmbiguousYearAssumeToCurrent: 1461 *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, currEra, true, status); 1462 break; 1463 case kCFDateFormatterAmbiguousYearAssumeToFuture: 1464 if (givenYear < currYear) { // we only consider current or the future 1465 success = false; 1466 } else { // current era 1467 *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, currEra, true, status); 1468 } 1469 break; 1470 case kCFDateFormatterAmbiguousYearAssumeToPast: 1471 if (givenYear > currYear) { // past era 1472 success = false; 1473 // we find the closest era that has the given year 1474 // if no era has such given year, we fail the parse 1475 for (CFIndex era = currEra-1; era >= 234; era--) { // Showa era (234) is the longest era 1476 int32_t years = __CFDateFormatterGetMaxYearGivenJapaneseEra(cal, era, status); 1477 if (givenYear > years) { 1478 continue; 1479 } 1480 success = true; 1481 *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, era, true, status); 1482 break; 1483 } 1484 } else { // current era 1485 *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, currEra, true, status); 1486 } 1487 break; 1488 case kCFDateFormatterAmbiguousYearAssumeToLikelyFuture: 1489 if (givenYear < currYear - 10) { // we allow 10 years to the past 1490 success = false; 1491 } else { 1492 *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, currEra, true, status); 1493 } 1494 break; 1495 case kCFDateFormatterAmbiguousYearAssumeToLikelyPast: 1496 if (givenYear > currYear + 10) { 1497 success = false; 1498 // we find the closest era that has the given year 1499 // if no era has such given year, we fail the parse 1500 for (CFIndex era = currEra-1; era >= 234; era--) { // Showa era (234) is the longest era 1501 int32_t years = __CFDateFormatterGetMaxYearGivenJapaneseEra(cal, era, status); 1502 if (givenYear > years) { 1503 continue; 1504 } 1505 success = true; 1506 *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, era, true, status); 1507 break; 1508 } 1509 } else { // current era 1510 *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, currEra, true, status); 1511 } 1512 break; 1513 case kCFDateFormatterAmbiguousYearAssumeToNone: 1514 default: 1515 break; // do nothing 1516 } 1517 } 1518#else 1519 success = false; 1520#endif 1521 } else { // calenders other than chinese and japanese 1522 int32_t parsedYear = __cficu_ucal_get(cal, UCAL_YEAR, status); 1523 if (parsedYear >= 12000 && parsedYear <= 12099) { // most likely that the parsed string had a 2-digits year 1524 if (formatter->_property._TwoDigitStartDate != NULL) { 1525 UCalendar *tempCal = __cficu_ucal_clone(cal, status); 1526 __cficu_ucal_clear(tempCal); 1527 CFAbsoluteTime twoDigitAt = CFDateGetAbsoluteTime(formatter->_property._TwoDigitStartDate); 1528 UDate targetUdate = (twoDigitAt + kCFAbsoluteTimeIntervalSince1970) * 1000.0; 1529 __cficu_ucal_setMillis(tempCal, targetUdate, status); 1530 int targetYear = __cficu_ucal_get(tempCal, UCAL_YEAR, status); 1531 parsedYear -= 12000; 1532 int targetYearM100 = targetYear % 100; 1533 if (targetYearM100 < parsedYear) { 1534 parsedYear = ((targetYear / 100) * 100) + parsedYear; 1535 } else if (parsedYear < targetYearM100) { 1536 parsedYear = ((targetYear / 100) * 100) + 100 + parsedYear; 1537 } else { 1538 __cficu_ucal_set(cal, UCAL_YEAR, targetYear); 1539 UDate parseUdate = __cficu_ucal_getMillis(cal, status); 1540 if (parseUdate >= targetUdate) { 1541 parsedYear = targetYear; 1542 } else { 1543 parsedYear = targetYear + 100; 1544 } 1545 } 1546 __cficu_ucal_close(tempCal); 1547 __cficu_ucal_set(cal, UCAL_YEAR, parsedYear); 1548 *at = __cficu_ucal_getMillis(cal, status); 1549 } else { 1550 switch (ambigStrat) { 1551 case kCFDateFormatterAmbiguousYearFailToParse: 1552 success = false; 1553 break; 1554 case kCFDateFormatterAmbiguousYearAssumeToCurrent: 1555 { 1556 // we can modify cal here because cal is just a temp cal from the caller 1557 __cficu_ucal_setMillis(cal, __cficu_ucal_getNow(), status); 1558 int32_t currYear = __cficu_ucal_get(cal, UCAL_YEAR, status); 1559 *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, (currYear / 100 * 100) + parsedYear % 100, false, status); 1560 } 1561 break; 1562 case kCFDateFormatterAmbiguousYearAssumeToCenteredAroundCurrentDate: 1563 *at = __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal, *at, 100, 50, 49, false, status); 1564 break; 1565 case kCFDateFormatterAmbiguousYearAssumeToFuture: 1566 *at = __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal, *at, 100, 0, 99, false, status); 1567 break; 1568 case kCFDateFormatterAmbiguousYearAssumeToPast: 1569 *at = __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal, *at, 100, 99, 0, false, status); 1570 break; 1571 case kCFDateFormatterAmbiguousYearAssumeToLikelyFuture: 1572 *at = __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal, *at, 100, 9, 90, false, status); 1573 break; 1574 case kCFDateFormatterAmbiguousYearAssumeToLikelyPast: 1575 *at = __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal, *at, 100, 90, 9, false, status); 1576 break; 1577 case kCFDateFormatterAmbiguousYearAssumeToNone: 1578 default: 1579 if (calendar_id == kCFCalendarIdentifierGregorian) { // historical default behavior of 1950 - 2049 1580 int32_t twoDigits = parsedYear % 100; 1581 *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, ((twoDigits < 50) ? 2000 : 1900) + twoDigits, false, status); 1582 } 1583 break; // do nothing 1584 } 1585 } 1586 1587 } 1588 } 1589 return success; 1590} 1591 1592CFDateRef CFDateFormatterCreateDateFromString(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFStringRef string, CFRange *rangep) { 1593 if (allocator == NULL) allocator = __CFGetDefaultAllocator(); 1594 __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); 1595 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); 1596 __CFGenericValidateType(string, CFStringGetTypeID()); 1597 CFAbsoluteTime at; 1598 if (CFDateFormatterGetAbsoluteTimeFromString(formatter, string, rangep, &at)) { 1599 return CFDateCreate(allocator, at); 1600 } 1601 return NULL; 1602} 1603 1604Boolean CFDateFormatterGetAbsoluteTimeFromString(CFDateFormatterRef formatter, CFStringRef string, CFRange *rangep, CFAbsoluteTime *atp) { 1605 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); 1606 __CFGenericValidateType(string, CFStringGetTypeID()); 1607 CFRange range = {0, 0}; 1608 if (rangep) { 1609 range = *rangep; 1610 } else { 1611 range.length = CFStringGetLength(string); 1612 } 1613 if (1024 < range.length) range.length = 1024; 1614 const UChar *ustr = (UChar *)CFStringGetCharactersPtr(string); 1615 STACK_BUFFER_DECL(UChar, ubuffer, (NULL == ustr) ? range.length : 1); 1616 if (NULL == ustr) { 1617 CFStringGetCharacters(string, range, (UniChar *)ubuffer); 1618 ustr = ubuffer; 1619 } else { 1620 ustr += range.location; 1621 } 1622 UDate udate; 1623 int32_t dpos = 0; 1624 UErrorCode status = U_ZERO_ERROR; 1625 UDateFormat *df2 = __cficu_udat_clone(formatter->_df, &status); 1626 const UCalendar *ucal2 = __cficu_udat_getCalendar(df2); 1627 UCalendar *cal2 = __cficu_ucal_clone(ucal2, &status); 1628 CFStringRef calendar_id = (CFStringRef) CFDateFormatterCopyProperty(formatter, kCFDateFormatterCalendarIdentifierKey); 1629 if (calendar_id != kCFCalendarIdentifierChinese && calendar_id != kCFCalendarIdentifierJapanese) { 1630 __cficu_ucal_clear(cal2); 1631 // set both year, and 2DigitYearStart to year 12000 1632 __cficu_ucal_set(cal2, UCAL_YEAR, 12000); 1633 __cficu_udat_set2DigitYearStart(df2, 316516204800.0 * 1000.0, &status); 1634 } else if (calendar_id == kCFCalendarIdentifierChinese) { 1635 __cficu_ucal_clear(cal2); 1636 __cficu_ucal_set(cal2, UCAL_ERA, 1); // default to era 1 if no era info in the string for chinese 1637 } else if (calendar_id == kCFCalendarIdentifierJapanese) { // default to the current era 1638 __cficu_ucal_setMillis(cal2, __cficu_ucal_getNow(), &status); 1639 int32_t currEra = __cficu_ucal_get(cal2, UCAL_ERA, &status); 1640 __cficu_ucal_clear(cal2); 1641 __cficu_ucal_set(cal2, UCAL_ERA, currEra); 1642 } 1643 if (formatter->_property._DefaultDate) { 1644 CFAbsoluteTime at = CFDateGetAbsoluteTime(formatter->_property._DefaultDate); 1645 udate = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0; 1646 __cficu_ucal_setMillis(cal2, udate, &status); 1647 } 1648 __cficu_udat_parseCalendar(df2, cal2, ustr, range.length, &dpos, &status); 1649 udate = __cficu_ucal_getMillis(cal2, &status); 1650 if (rangep) rangep->length = dpos; 1651 Boolean success = false; 1652 // first status check is for parsing and the second status check is for the work done inside __CFDateFormatterHandleAmbiguousYear() 1653 if (!U_FAILURE(status) && (__CFDateFormatterHandleAmbiguousYear(formatter, calendar_id, df2, cal2, &udate, ustr, range.length, &status)) && !U_FAILURE(status)) { 1654 if (atp) { 1655 *atp = (double)udate / 1000.0 - kCFAbsoluteTimeIntervalSince1970; 1656 } 1657 success = true; 1658 } 1659 CFRelease(calendar_id); 1660 __cficu_udat_close(df2); 1661 __cficu_ucal_close(cal2); 1662 return success; 1663} 1664 1665static void __CFDateFormatterSetSymbolsArray(UDateFormat *icudf, int32_t icucode, int index_base, CFTypeRef value) { 1666 UErrorCode status = U_ZERO_ERROR; 1667 __CFGenericValidateType(value, CFArrayGetTypeID()); 1668 CFArrayRef array = (CFArrayRef)value; 1669 CFIndex idx, cnt = CFArrayGetCount(array); 1670 for (idx = 0; idx < cnt; idx++) { 1671 CFStringRef item = (CFStringRef)CFArrayGetValueAtIndex(array, idx); 1672 __CFGenericValidateType(item, CFStringGetTypeID()); 1673 CFIndex item_cnt = CFStringGetLength(item); 1674 STACK_BUFFER_DECL(UChar, item_buffer, __CFMin(BUFFER_SIZE, item_cnt)); 1675 UChar *item_ustr = (UChar *)CFStringGetCharactersPtr(item); 1676 if (NULL == item_ustr) { 1677 item_cnt = __CFMin(BUFFER_SIZE, item_cnt); 1678 CFStringGetCharacters(item, CFRangeMake(0, item_cnt), (UniChar *)item_buffer); 1679 item_ustr = item_buffer; 1680 } 1681 status = U_ZERO_ERROR; 1682 __cficu_udat_setSymbols(icudf, (UDateFormatSymbolType)icucode, idx + index_base, item_ustr, item_cnt, &status); 1683 } 1684} 1685 1686static CFArrayRef __CFDateFormatterGetSymbolsArray(UDateFormat *icudf, int32_t icucode, int index_base) { 1687 UErrorCode status = U_ZERO_ERROR; 1688 CFIndex idx, cnt = __cficu_udat_countSymbols(icudf, (UDateFormatSymbolType)icucode); 1689 if (cnt <= index_base) return CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks); 1690 cnt = cnt - index_base; 1691 STACK_BUFFER_DECL(CFStringRef, strings, cnt); 1692 for (idx = 0; idx < cnt; idx++) { 1693 UChar ubuffer[BUFFER_SIZE]; 1694 CFStringRef str = NULL; 1695 status = U_ZERO_ERROR; 1696 CFIndex ucnt = __cficu_udat_getSymbols(icudf, (UDateFormatSymbolType)icucode, idx + index_base, ubuffer, BUFFER_SIZE, &status); 1697 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { 1698 str = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)ubuffer, ucnt); 1699 } 1700 strings[idx] = !str ? (CFStringRef)CFRetain(CFSTR("<error>")) : str; 1701 } 1702 CFArrayRef array = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)strings, cnt, &kCFTypeArrayCallBacks); 1703 while (cnt--) { 1704 CFRelease(strings[cnt]); 1705 } 1706 return array; 1707} 1708 1709#define SET_SYMBOLS_ARRAY(A, B, C) \ 1710 if (!directToICU) { \ 1711 oldProperty = formatter->_property. C; \ 1712 formatter->_property. C = NULL; \ 1713 } \ 1714 __CFDateFormatterSetSymbolsArray(formatter->_df, A, B, value); \ 1715 if (!directToICU) { \ 1716 formatter->_property. C = __CFDateFormatterGetSymbolsArray(formatter->_df, A, B); \ 1717 } 1718 1719static void __CFDateFormatterSetProperty(CFDateFormatterRef formatter, CFStringRef key, CFTypeRef value, Boolean directToICU) { 1720 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); 1721 __CFGenericValidateType(key, CFStringGetTypeID()); 1722 CFTypeRef oldProperty = NULL; 1723 UErrorCode status = U_ZERO_ERROR; 1724 1725 if (kCFDateFormatterIsLenientKey == key) { 1726 if (!directToICU) { 1727 oldProperty = formatter->_property. _IsLenient; 1728 formatter->_property. _IsLenient = NULL; 1729 } 1730 __CFGenericValidateType(value, CFBooleanGetTypeID()); 1731 if (!directToICU) { 1732 formatter->_property. _IsLenient = value ? (CFBooleanRef)CFRetain(value) : NULL; 1733 __ResetUDateFormat(formatter, false); 1734 } 1735 } else if (kCFDateFormatterDoesRelativeDateFormattingKey == key) { 1736 if (!directToICU) { 1737 oldProperty = formatter->_property. _DoesRelativeDateFormatting; 1738 formatter->_property. _DoesRelativeDateFormatting = NULL; 1739 } 1740 __CFGenericValidateType(value, CFBooleanGetTypeID()); 1741 if (!directToICU) { 1742 if (kCFBooleanTrue != value) value = kCFBooleanFalse; 1743 formatter->_property. _DoesRelativeDateFormatting = value ? (CFBooleanRef)CFRetain(value) : NULL; 1744 __ResetUDateFormat(formatter, false); 1745 } 1746 } else if (kCFDateFormatterCalendarKey == key) { 1747 if (!directToICU) { 1748 oldProperty = formatter->_property. _Calendar; 1749 formatter->_property. _Calendar = NULL; 1750 } 1751 __CFGenericValidateType(value, CFCalendarGetTypeID()); 1752 CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale); 1753 CFDictionaryRef components = CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault, localeName); 1754 CFMutableDictionaryRef mcomponents = CFDictionaryCreateMutableCopy(kCFAllocatorSystemDefault, 0, components); 1755 CFDictionarySetValue(mcomponents, kCFLocaleCalendarIdentifierKey, CFCalendarGetIdentifier((CFCalendarRef)value)); 1756 localeName = CFLocaleCreateLocaleIdentifierFromComponents(kCFAllocatorSystemDefault, mcomponents); 1757 CFRelease(mcomponents); 1758 CFRelease(components); 1759 CFLocaleRef newLocale = CFLocaleCreate(CFGetAllocator(formatter->_locale), localeName); 1760 // at this point, we should be setting the preferences if any into this new locale 1761 CFRelease(localeName); 1762 CFRelease(formatter->_locale); 1763 formatter->_locale = newLocale; 1764 if (!directToICU) { 1765 formatter->_property. _Calendar = (CFCalendarRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterCalendarKey); 1766 __ResetUDateFormat(formatter, false); 1767 } 1768 } else if (kCFDateFormatterCalendarIdentifierKey == key) { 1769 if (!directToICU) { 1770 oldProperty = formatter->_property. _CalendarName; 1771 formatter->_property. _CalendarName = NULL; 1772 } 1773 __CFGenericValidateType(value, CFStringGetTypeID()); 1774 CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale); 1775 CFDictionaryRef components = CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault, localeName); 1776 CFMutableDictionaryRef mcomponents = CFDictionaryCreateMutableCopy(kCFAllocatorSystemDefault, 0, components); 1777 CFDictionarySetValue(mcomponents, kCFLocaleCalendarIdentifierKey, value); 1778 localeName = CFLocaleCreateLocaleIdentifierFromComponents(kCFAllocatorSystemDefault, mcomponents); 1779 CFRelease(mcomponents); 1780 CFRelease(components); 1781 CFLocaleRef newLocale = CFLocaleCreate(CFGetAllocator(formatter->_locale), localeName); 1782 // at this point, we should be setting the preferences if any into this new locale 1783 CFRelease(localeName); 1784 CFRelease(formatter->_locale); 1785 formatter->_locale = newLocale; 1786 if (!directToICU) { 1787 formatter->_property. _CalendarName = (CFStringRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterCalendarIdentifierKey); 1788 __ResetUDateFormat(formatter, false); 1789 } 1790 } else if (kCFDateFormatterTimeZoneKey == key) { 1791 if (formatter->_property. _TimeZone != value) { 1792 if (!directToICU) { 1793 oldProperty = formatter->_property. _TimeZone; 1794 formatter->_property. _TimeZone = NULL; 1795 } 1796 __CFGenericValidateType(value, CFTimeZoneGetTypeID()); 1797 CFTimeZoneRef old = formatter->_property._TimeZone; 1798 formatter->_property._TimeZone = value ? (CFTimeZoneRef)CFRetain(value) : CFTimeZoneCopyDefault(); 1799 if (old) CFRelease(old); 1800 if (!directToICU) { 1801 old = formatter->_property._TimeZone; 1802 formatter->_property. _TimeZone = (CFTimeZoneRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterTimeZoneKey); 1803 __ResetUDateFormat(formatter, false); 1804 if (old) CFRelease(old); 1805 } 1806 } 1807 } else if (kCFDateFormatterDefaultFormatKey == key) { 1808 // read-only attribute 1809 } else if (kCFDateFormatterTwoDigitStartDateKey == key) { 1810 if (!directToICU) { 1811 oldProperty = formatter->_property. _TwoDigitStartDate; 1812 formatter->_property. _TwoDigitStartDate = NULL; 1813 } 1814 __CFGenericValidateType(value, CFDateGetTypeID()); 1815 if (!directToICU) { 1816 formatter->_property. _TwoDigitStartDate = value ? (CFDateRef)CFRetain(value) : NULL; 1817 } 1818 } else if (kCFDateFormatterDefaultDateKey == key) { 1819 if (!directToICU) { 1820 oldProperty = formatter->_property. _DefaultDate; 1821 formatter->_property. _DefaultDate = NULL; 1822 } 1823 __CFGenericValidateType(value, CFDateGetTypeID()); 1824 if (!directToICU) { 1825 formatter->_property._DefaultDate = value ? (CFDateRef)CFRetain(value) : NULL; 1826 } 1827 } else if (kCFDateFormatterGregorianStartDateKey == key) { 1828 if (!directToICU) { 1829 oldProperty = formatter->_property. _GregorianStartDate; 1830 formatter->_property. _GregorianStartDate = NULL; 1831 } 1832 __CFGenericValidateType(value, CFDateGetTypeID()); 1833 if (!directToICU) { 1834 formatter->_property. _GregorianStartDate = value ? (CFDateRef)CFRetain(value) : NULL; 1835 __ResetUDateFormat(formatter, false); 1836 } 1837 } else if (kCFDateFormatterEraSymbolsKey == key) { 1838 SET_SYMBOLS_ARRAY(UDAT_ERAS, 0, _EraSymbols) 1839 } else if (kCFDateFormatterLongEraSymbolsKey == key) { 1840 SET_SYMBOLS_ARRAY(UDAT_ERA_NAMES, 0, _LongEraSymbols) 1841 } else if (kCFDateFormatterMonthSymbolsKey == key) { 1842 SET_SYMBOLS_ARRAY(UDAT_MONTHS, 0, _MonthSymbols) 1843 } else if (kCFDateFormatterShortMonthSymbolsKey == key) { 1844 SET_SYMBOLS_ARRAY(UDAT_SHORT_MONTHS, 0, _ShortMonthSymbols) 1845 } else if (kCFDateFormatterVeryShortMonthSymbolsKey == key) { 1846 SET_SYMBOLS_ARRAY(UDAT_NARROW_MONTHS, 0, _VeryShortMonthSymbols) 1847 } else if (kCFDateFormatterStandaloneMonthSymbolsKey == key) { 1848 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_MONTHS, 0, _StandaloneMonthSymbols) 1849 } else if (kCFDateFormatterShortStandaloneMonthSymbolsKey == key) { 1850 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_MONTHS, 0, _ShortStandaloneMonthSymbols) 1851 } else if (kCFDateFormatterVeryShortStandaloneMonthSymbolsKey == key) { 1852 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_NARROW_MONTHS, 0, _VeryShortStandaloneMonthSymbols) 1853 } else if (kCFDateFormatterWeekdaySymbolsKey == key) { 1854 SET_SYMBOLS_ARRAY(UDAT_WEEKDAYS, 1, _WeekdaySymbols) 1855 } else if (kCFDateFormatterShortWeekdaySymbolsKey == key) { 1856 SET_SYMBOLS_ARRAY(UDAT_SHORT_WEEKDAYS, 1, _ShortWeekdaySymbols) 1857 } else if (kCFDateFormatterVeryShortWeekdaySymbolsKey == key) { 1858 SET_SYMBOLS_ARRAY(UDAT_NARROW_WEEKDAYS, 1, _VeryShortWeekdaySymbols) 1859 } else if (kCFDateFormatterStandaloneWeekdaySymbolsKey == key) { 1860 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_WEEKDAYS, 1, _StandaloneWeekdaySymbols) 1861 } else if (kCFDateFormatterShortStandaloneWeekdaySymbolsKey == key) { 1862 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_WEEKDAYS, 1, _ShortStandaloneWeekdaySymbols) 1863 } else if (kCFDateFormatterVeryShortStandaloneWeekdaySymbolsKey == key) { 1864 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_NARROW_WEEKDAYS, 1, _VeryShortStandaloneWeekdaySymbols) 1865 } else if (kCFDateFormatterQuarterSymbolsKey == key) { 1866 SET_SYMBOLS_ARRAY(UDAT_QUARTERS, 0, _QuarterSymbols) 1867 } else if (kCFDateFormatterShortQuarterSymbolsKey == key) { 1868 SET_SYMBOLS_ARRAY(UDAT_SHORT_QUARTERS, 0, _ShortQuarterSymbols) 1869 } else if (kCFDateFormatterStandaloneQuarterSymbolsKey == key) { 1870 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_QUARTERS, 0, _StandaloneQuarterSymbols) 1871 } else if (kCFDateFormatterShortStandaloneQuarterSymbolsKey == key) { 1872 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_QUARTERS, 0, _ShortStandaloneQuarterSymbols) 1873 } else if (kCFDateFormatterAMSymbolKey == key) { 1874 if (!directToICU) { 1875 oldProperty = formatter->_property. _AMSymbol; 1876 formatter->_property. _AMSymbol = NULL; 1877 } 1878 __CFGenericValidateType(value, CFStringGetTypeID()); 1879 CFIndex item_cnt = CFStringGetLength((CFStringRef)value); 1880 STACK_BUFFER_DECL(UChar, item_buffer, __CFMin(BUFFER_SIZE, item_cnt)); 1881 UChar *item_ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)value); 1882 if (NULL == item_ustr) { 1883 item_cnt = __CFMin(BUFFER_SIZE, item_cnt); 1884 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, item_cnt), (UniChar *)item_buffer); 1885 item_ustr = item_buffer; 1886 } 1887 __cficu_udat_setSymbols(formatter->_df, UDAT_AM_PMS, 0, item_ustr, item_cnt, &status); 1888 if (!directToICU) { 1889 formatter->_property. _AMSymbol = value ? (CFStringRef)CFStringCreateCopy(NULL, value) : NULL; 1890 } 1891 } else if (kCFDateFormatterPMSymbolKey == key) { 1892 if (!directToICU) { 1893 oldProperty = formatter->_property. _PMSymbol; 1894 formatter->_property. _PMSymbol = NULL; 1895 } 1896 __CFGenericValidateType(value, CFStringGetTypeID()); 1897 CFIndex item_cnt = CFStringGetLength((CFStringRef)value); 1898 STACK_BUFFER_DECL(UChar, item_buffer, __CFMin(BUFFER_SIZE, item_cnt)); 1899 UChar *item_ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)value); 1900 if (NULL == item_ustr) { 1901 item_cnt = __CFMin(BUFFER_SIZE, item_cnt); 1902 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, item_cnt), (UniChar *)item_buffer); 1903 item_ustr = item_buffer; 1904 } 1905 __cficu_udat_setSymbols(formatter->_df, UDAT_AM_PMS, 1, item_ustr, item_cnt, &status); 1906 if (!directToICU) { 1907 formatter->_property. _PMSymbol = value ? (CFStringRef)CFStringCreateCopy(NULL, value) : NULL; 1908 } 1909 } else if (kCFDateFormatterAmbiguousYearStrategyKey == key) { 1910 oldProperty = formatter->_property._AmbiguousYearStrategy; 1911 formatter->_property._AmbiguousYearStrategy = NULL; 1912 __CFGenericValidateType(value, CFNumberGetTypeID()); 1913 formatter->_property._AmbiguousYearStrategy = (CFNumberRef)CFRetain(value); 1914 } else if (kCFDateFormatterUsesCharacterDirectionKey == key) { 1915 __CFGenericValidateType(value, CFBooleanGetTypeID()); 1916 oldProperty = formatter->_property._UsesCharacterDirection; 1917 formatter->_property._UsesCharacterDirection = (CFBooleanRef)CFRetain(value); 1918 } else { 1919 CFAssert3(0, __kCFLogAssertion, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__, key, key); 1920 } 1921 if (oldProperty) CFRelease(oldProperty); 1922} 1923 1924void CFDateFormatterSetProperty(CFDateFormatterRef formatter, CFStringRef key, CFTypeRef value) { 1925 __CFDateFormatterSetProperty(formatter, key, value, false); 1926} 1927 1928CFTypeRef CFDateFormatterCopyProperty(CFDateFormatterRef formatter, CFStringRef key) { 1929 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); 1930 __CFGenericValidateType(key, CFStringGetTypeID()); 1931 UErrorCode status = U_ZERO_ERROR; 1932 UChar ubuffer[BUFFER_SIZE]; 1933 1934 if (kCFDateFormatterIsLenientKey == key) { 1935 if (formatter->_property._IsLenient) return CFRetain(formatter->_property._IsLenient); 1936 return CFRetain(__cficu_udat_isLenient(formatter->_df) ? kCFBooleanTrue : kCFBooleanFalse); 1937 } else if (kCFDateFormatterDoesRelativeDateFormattingKey == key) { 1938 if (formatter->_property._DoesRelativeDateFormatting) return CFRetain(formatter->_property._DoesRelativeDateFormatting); 1939 return CFRetain(kCFBooleanFalse); 1940 } else if (kCFDateFormatterCalendarKey == key) { 1941 if (formatter->_property._Calendar) return CFRetain(formatter->_property._Calendar); 1942 CFCalendarRef calendar = (CFCalendarRef)CFLocaleGetValue(formatter->_locale, kCFLocaleCalendarKey); 1943 return calendar ? CFRetain(calendar) : NULL; 1944 } else if (kCFDateFormatterCalendarIdentifierKey == key) { 1945 if (formatter->_property._CalendarName) return CFRetain(formatter->_property._CalendarName); 1946 CFStringRef ident = (CFStringRef)CFLocaleGetValue(formatter->_locale, kCFLocaleCalendarIdentifierKey); 1947 return ident ? CFRetain(ident) : NULL; 1948 } else if (kCFDateFormatterTimeZoneKey == key) { 1949 return formatter->_property._TimeZone ? CFRetain(formatter->_property._TimeZone) : NULL; 1950 } else if (kCFDateFormatterDefaultFormatKey == key) { 1951 return formatter->_defformat ? CFRetain(formatter->_defformat) : NULL; 1952 } else if (kCFDateFormatterTwoDigitStartDateKey == key) { 1953 return formatter->_property._TwoDigitStartDate ? CFRetain(formatter->_property._TwoDigitStartDate) : NULL; 1954 } else if (kCFDateFormatterDefaultDateKey == key) { 1955 return formatter->_property._DefaultDate ? CFRetain(formatter->_property._DefaultDate) : NULL; 1956 } else if (kCFDateFormatterGregorianStartDateKey == key) { 1957 if (formatter->_property._GregorianStartDate) return CFRetain(formatter->_property._GregorianStartDate); 1958 const UCalendar *cal = __cficu_udat_getCalendar(formatter->_df); 1959 UDate udate = __cficu_ucal_getGregorianChange(cal, &status); 1960 if (U_SUCCESS(status)) { 1961 CFAbsoluteTime at = (double)udate / 1000.0 - kCFAbsoluteTimeIntervalSince1970; 1962 return CFDateCreate(CFGetAllocator(formatter), at); 1963 } 1964 } else if (kCFDateFormatterEraSymbolsKey == key) { 1965 if (formatter->_property._EraSymbols) return CFRetain(formatter->_property._EraSymbols); 1966 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_ERAS, 0); 1967 } else if (kCFDateFormatterLongEraSymbolsKey == key) { 1968 if (formatter->_property._LongEraSymbols) return CFRetain(formatter->_property._LongEraSymbols); 1969 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_ERA_NAMES, 0); 1970 } else if (kCFDateFormatterMonthSymbolsKey == key) { 1971 if (formatter->_property._MonthSymbols) return CFRetain(formatter->_property._MonthSymbols); 1972 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_MONTHS, 0); 1973 } else if (kCFDateFormatterShortMonthSymbolsKey == key) { 1974 if (formatter->_property._ShortMonthSymbols) return CFRetain(formatter->_property._ShortMonthSymbols); 1975 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_SHORT_MONTHS, 0); 1976 } else if (kCFDateFormatterVeryShortMonthSymbolsKey == key) { 1977 if (formatter->_property._VeryShortMonthSymbols) return CFRetain(formatter->_property._VeryShortMonthSymbols); 1978 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_NARROW_MONTHS, 0); 1979 } else if (kCFDateFormatterStandaloneMonthSymbolsKey == key) { 1980 if (formatter->_property._StandaloneMonthSymbols) return CFRetain(formatter->_property._StandaloneMonthSymbols); 1981 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_MONTHS, 0); 1982 } else if (kCFDateFormatterShortStandaloneMonthSymbolsKey == key) { 1983 if (formatter->_property._ShortStandaloneMonthSymbols) return CFRetain(formatter->_property._ShortStandaloneMonthSymbols); 1984 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_SHORT_MONTHS, 0); 1985 } else if (kCFDateFormatterVeryShortStandaloneMonthSymbolsKey == key) { 1986 if (formatter->_property._VeryShortStandaloneMonthSymbols) return CFRetain(formatter->_property._VeryShortStandaloneMonthSymbols); 1987 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_NARROW_MONTHS, 0); 1988 } else if (kCFDateFormatterWeekdaySymbolsKey == key) { 1989 if (formatter->_property._WeekdaySymbols) return CFRetain(formatter->_property._WeekdaySymbols); 1990 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_WEEKDAYS, 1); 1991 } else if (kCFDateFormatterShortWeekdaySymbolsKey == key) { 1992 if (formatter->_property._ShortWeekdaySymbols) return CFRetain(formatter->_property._ShortWeekdaySymbols); 1993 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_SHORT_WEEKDAYS, 1); 1994 } else if (kCFDateFormatterVeryShortWeekdaySymbolsKey == key) { 1995 if (formatter->_property._VeryShortWeekdaySymbols) return CFRetain(formatter->_property._VeryShortWeekdaySymbols); 1996 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_NARROW_WEEKDAYS, 1); 1997 } else if (kCFDateFormatterStandaloneWeekdaySymbolsKey == key) { 1998 if (formatter->_property._StandaloneWeekdaySymbols) return CFRetain(formatter->_property._StandaloneWeekdaySymbols); 1999 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_WEEKDAYS, 1); 2000 } else if (kCFDateFormatterShortStandaloneWeekdaySymbolsKey == key) { 2001 if (formatter->_property._ShortStandaloneWeekdaySymbols) return CFRetain(formatter->_property._ShortStandaloneWeekdaySymbols); 2002 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_SHORT_WEEKDAYS, 1); 2003 } else if (kCFDateFormatterVeryShortStandaloneWeekdaySymbolsKey == key) { 2004 if (formatter->_property._VeryShortStandaloneWeekdaySymbols) return CFRetain(formatter->_property._VeryShortStandaloneWeekdaySymbols); 2005 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_NARROW_WEEKDAYS, 1); 2006 } else if (kCFDateFormatterQuarterSymbolsKey == key) { 2007 if (formatter->_property._QuarterSymbols) return CFRetain(formatter->_property._QuarterSymbols); 2008 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_QUARTERS, 0); 2009 } else if (kCFDateFormatterShortQuarterSymbolsKey == key) { 2010 if (formatter->_property._ShortQuarterSymbols) return CFRetain(formatter->_property._ShortQuarterSymbols); 2011 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_SHORT_QUARTERS, 0); 2012 } else if (kCFDateFormatterStandaloneQuarterSymbolsKey == key) { 2013 if (formatter->_property._StandaloneQuarterSymbols) return CFRetain(formatter->_property._StandaloneQuarterSymbols); 2014 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_QUARTERS, 0); 2015 } else if (kCFDateFormatterShortStandaloneQuarterSymbolsKey == key) { 2016 if (formatter->_property._ShortStandaloneQuarterSymbols) return CFRetain(formatter->_property._ShortStandaloneQuarterSymbols); 2017 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_SHORT_QUARTERS, 0); 2018 } else if (kCFDateFormatterAMSymbolKey == key) { 2019 if (formatter->_property._AMSymbol) return CFRetain(formatter->_property._AMSymbol); 2020 CFIndex cnt = __cficu_udat_countSymbols(formatter->_df, UDAT_AM_PMS); 2021 if (2 <= cnt) { 2022 CFIndex ucnt = __cficu_udat_getSymbols(formatter->_df, UDAT_AM_PMS, 0, ubuffer, BUFFER_SIZE, &status); 2023 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { 2024 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (UniChar *)ubuffer, ucnt); 2025 } 2026 } 2027 } else if (kCFDateFormatterPMSymbolKey == key) { 2028 if (formatter->_property._PMSymbol) return CFRetain(formatter->_property._PMSymbol); 2029 CFIndex cnt = __cficu_udat_countSymbols(formatter->_df, UDAT_AM_PMS); 2030 if (2 <= cnt) { 2031 CFIndex ucnt = __cficu_udat_getSymbols(formatter->_df, UDAT_AM_PMS, 1, ubuffer, BUFFER_SIZE, &status); 2032 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { 2033 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (UniChar *)ubuffer, ucnt); 2034 } 2035 } 2036 } else if (kCFDateFormatterAmbiguousYearStrategyKey == key) { 2037 if (formatter->_property._AmbiguousYearStrategy) return CFRetain(formatter->_property._AmbiguousYearStrategy); 2038 } else if (kCFDateFormatterUsesCharacterDirectionKey == key) { 2039 return formatter->_property._UsesCharacterDirection ? CFRetain(formatter->_property._UsesCharacterDirection) : CFRetain(kCFBooleanFalse); 2040 } else { 2041 CFAssert3(0, __kCFLogAssertion, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__, key, key); 2042 } 2043 return NULL; 2044} 2045 2046 2047