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