]> git.saurik.com Git - apple/cf.git/blob - CFDateFormatter.c
ee6696b97c9f3087d4d3d5bc6198660c71d0c35b
[apple/cf.git] / CFDateFormatter.c
1 /*
2 * Copyright (c) 2009 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-2009, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
27 */
28
29 #include <CoreFoundation/CFDateFormatter.h>
30 #include <CoreFoundation/CFDate.h>
31 #include <CoreFoundation/CFTimeZone.h>
32 #include <CoreFoundation/CFCalendar.h>
33 #include <CoreFoundation/CFNumber.h>
34 #include "CFInternal.h"
35 #include "CFLocaleInternal.h"
36 #include <unicode/udat.h>
37 #include <unicode/udatpg.h>
38 #include <math.h>
39 #include <float.h>
40
41 extern UCalendar *__CFCalendarCreateUCalendar(CFStringRef calendarID, CFStringRef localeID, CFTimeZoneRef tz);
42 static void __CFDateFormatterCustomize(CFDateFormatterRef formatter);
43
44 CF_EXPORT const CFStringRef kCFDateFormatterCalendarIdentifierKey;
45
46 #undef CFReleaseIfNotNull
47 #define CFReleaseIfNotNull(X) if (X) CFRelease(X)
48
49 #define BUFFER_SIZE 768
50
51 CFStringRef CFDateFormatterCreateDateFormatFromTemplate(CFAllocatorRef allocator, CFStringRef tmplate, CFOptionFlags options, CFLocaleRef locale) {
52 if (allocator) __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
53 if (locale) __CFGenericValidateType(locale, CFLocaleGetTypeID());
54 __CFGenericValidateType(tmplate, CFStringGetTypeID());
55
56 CFStringRef localeName = locale ? CFLocaleGetIdentifier(locale) : CFSTR("");
57 char buffer[BUFFER_SIZE];
58 const char *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII);
59 if (NULL == cstr) {
60 if (CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer;
61 }
62 if (NULL == cstr) {
63 return NULL;
64 }
65
66 UErrorCode status = U_ZERO_ERROR;
67 UDateTimePatternGenerator *ptg = udatpg_open(cstr, &status);
68 if (NULL == ptg || U_FAILURE(status)) {
69 return NULL;
70 }
71
72 CFIndex jCount = 0; // the only interesting cases are 0, 1, and 2 (adjacent)
73 CFRange r = CFStringFind(tmplate, CFSTR("j"), 0);
74 if (kCFNotFound != r.location) {
75 jCount++;
76 if ((r.location + 1 < CFStringGetLength(tmplate)) && ('j' == CFStringGetCharacterAtIndex(tmplate, r.location + 1))) {
77 jCount++;
78 }
79 }
80
81 UChar pattern[BUFFER_SIZE], skel[BUFFER_SIZE], bpat[BUFFER_SIZE];
82 CFIndex cnt = CFStringGetLength(tmplate);
83 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
84 CFStringGetCharacters(tmplate, CFRangeMake(0, cnt), (UniChar *)pattern);
85 int32_t patlen = cnt;
86
87 status = U_ZERO_ERROR;
88 int32_t skellen = udatpg_getSkeleton(ptg, pattern, patlen, skel, sizeof(skel) / sizeof(skel[0]), &status);
89 if (U_FAILURE(status)) {
90 return NULL;
91 }
92
93 if ((0 < jCount) && (skellen + jCount < (sizeof(skel) / sizeof(skel[0])))) {
94 skel[skellen++] = 'j';
95 if (1 < jCount) skel[skellen++] = 'j';
96 }
97
98 status = U_ZERO_ERROR;
99 int32_t bpatlen = udatpg_getBestPattern(ptg, skel, skellen, bpat, sizeof(bpat) / sizeof(bpat[0]), &status);
100 if (U_FAILURE(status)) {
101 return NULL;
102 }
103 udatpg_close(ptg);
104
105 return CFStringCreateWithCharacters(allocator, (const UniChar *)bpat, bpatlen);
106 }
107
108 struct __CFDateFormatter {
109 CFRuntimeBase _base;
110 UDateFormat *_df;
111 CFLocaleRef _locale;
112 CFDateFormatterStyle _timeStyle;
113 CFDateFormatterStyle _dateStyle;
114 CFStringRef _format;
115 CFStringRef _defformat;
116 struct {
117 CFBooleanRef _IsLenient;
118 CFBooleanRef _DoesRelativeDateFormatting;
119 CFBooleanRef _HasCustomFormat;
120 CFTimeZoneRef _TimeZone;
121 CFCalendarRef _Calendar;
122 CFStringRef _CalendarName;
123 CFDateRef _TwoDigitStartDate;
124 CFDateRef _DefaultDate;
125 CFDateRef _GregorianStartDate;
126 CFArrayRef _EraSymbols;
127 CFArrayRef _LongEraSymbols;
128 CFArrayRef _MonthSymbols;
129 CFArrayRef _ShortMonthSymbols;
130 CFArrayRef _VeryShortMonthSymbols;
131 CFArrayRef _StandaloneMonthSymbols;
132 CFArrayRef _ShortStandaloneMonthSymbols;
133 CFArrayRef _VeryShortStandaloneMonthSymbols;
134 CFArrayRef _WeekdaySymbols;
135 CFArrayRef _ShortWeekdaySymbols;
136 CFArrayRef _VeryShortWeekdaySymbols;
137 CFArrayRef _StandaloneWeekdaySymbols;
138 CFArrayRef _ShortStandaloneWeekdaySymbols;
139 CFArrayRef _VeryShortStandaloneWeekdaySymbols;
140 CFArrayRef _QuarterSymbols;
141 CFArrayRef _ShortQuarterSymbols;
142 CFArrayRef _StandaloneQuarterSymbols;
143 CFArrayRef _ShortStandaloneQuarterSymbols;
144 CFStringRef _AMSymbol;
145 CFStringRef _PMSymbol;
146 } _property;
147 };
148
149 static CFStringRef __CFDateFormatterCopyDescription(CFTypeRef cf) {
150 CFDateFormatterRef formatter = (CFDateFormatterRef)cf;
151 return CFStringCreateWithFormat(CFGetAllocator(formatter), NULL, CFSTR("<CFDateFormatter %p [%p]>"), cf, CFGetAllocator(formatter));
152 }
153
154 static void __CFDateFormatterDeallocate(CFTypeRef cf) {
155 CFDateFormatterRef formatter = (CFDateFormatterRef)cf;
156 if (formatter->_df) udat_close(formatter->_df);
157 if (formatter->_locale) CFRelease(formatter->_locale);
158 if (formatter->_format) CFRelease(formatter->_format);
159 if (formatter->_defformat) CFRelease(formatter->_defformat);
160 CFReleaseIfNotNull(formatter->_property._IsLenient);
161 CFReleaseIfNotNull(formatter->_property._DoesRelativeDateFormatting);
162 CFReleaseIfNotNull(formatter->_property._TimeZone);
163 CFReleaseIfNotNull(formatter->_property._Calendar);
164 CFReleaseIfNotNull(formatter->_property._CalendarName);
165 CFReleaseIfNotNull(formatter->_property._TwoDigitStartDate);
166 CFReleaseIfNotNull(formatter->_property._DefaultDate);
167 CFReleaseIfNotNull(formatter->_property._GregorianStartDate);
168 CFReleaseIfNotNull(formatter->_property._EraSymbols);
169 CFReleaseIfNotNull(formatter->_property._LongEraSymbols);
170 CFReleaseIfNotNull(formatter->_property._MonthSymbols);
171 CFReleaseIfNotNull(formatter->_property._ShortMonthSymbols);
172 CFReleaseIfNotNull(formatter->_property._VeryShortMonthSymbols);
173 CFReleaseIfNotNull(formatter->_property._StandaloneMonthSymbols);
174 CFReleaseIfNotNull(formatter->_property._ShortStandaloneMonthSymbols);
175 CFReleaseIfNotNull(formatter->_property._VeryShortStandaloneMonthSymbols);
176 CFReleaseIfNotNull(formatter->_property._WeekdaySymbols);
177 CFReleaseIfNotNull(formatter->_property._ShortWeekdaySymbols);
178 CFReleaseIfNotNull(formatter->_property._VeryShortWeekdaySymbols);
179 CFReleaseIfNotNull(formatter->_property._StandaloneWeekdaySymbols);
180 CFReleaseIfNotNull(formatter->_property._ShortStandaloneWeekdaySymbols);
181 CFReleaseIfNotNull(formatter->_property._VeryShortStandaloneWeekdaySymbols);
182 CFReleaseIfNotNull(formatter->_property._QuarterSymbols);
183 CFReleaseIfNotNull(formatter->_property._ShortQuarterSymbols);
184 CFReleaseIfNotNull(formatter->_property._StandaloneQuarterSymbols);
185 CFReleaseIfNotNull(formatter->_property._ShortStandaloneQuarterSymbols);
186 CFReleaseIfNotNull(formatter->_property._AMSymbol);
187 CFReleaseIfNotNull(formatter->_property._PMSymbol);
188 }
189
190 static CFStringRef __CFDateFormatterCreateForcedString(CFDateFormatterRef formatter, CFStringRef inString);
191
192 static void __CFDateFormatterSetProperty(CFDateFormatterRef formatter, CFStringRef key, CFTypeRef value, Boolean directToICU);
193
194 #define RESET_PROPERTY(C, K) \
195 if (df->_property. C) __CFDateFormatterSetProperty(df, K, df->_property. C, true);
196
197 static void __ResetUDateFormat(CFDateFormatterRef df, Boolean goingToHaveCustomFormat) {
198 if (df->_df) udat_close(df->_df);
199 df->_df = NULL;
200
201 // uses _timeStyle, _dateStyle, _locale, _property._TimeZone; sets _df, _format, _defformat
202 char loc_buffer[BUFFER_SIZE];
203 loc_buffer[0] = 0;
204 CFStringRef tmpLocName = df->_locale ? CFLocaleGetIdentifier(df->_locale) : CFSTR("");
205 CFStringGetCString(tmpLocName, loc_buffer, BUFFER_SIZE, kCFStringEncodingASCII);
206
207 UChar tz_buffer[BUFFER_SIZE];
208 tz_buffer[0] = 0;
209 CFStringRef tmpTZName = df->_property._TimeZone ? CFTimeZoneGetName(df->_property._TimeZone) : CFSTR("GMT");
210 CFStringGetCharacters(tmpTZName, CFRangeMake(0, CFStringGetLength(tmpTZName)), (UniChar *)tz_buffer);
211
212 df->_property._HasCustomFormat = kCFBooleanFalse;
213
214 int32_t udstyle = 0, utstyle = 0;
215 switch (df->_dateStyle) {
216 case kCFDateFormatterNoStyle: udstyle = UDAT_NONE; break;
217 case kCFDateFormatterShortStyle: udstyle = UDAT_SHORT; break;
218 case kCFDateFormatterMediumStyle: udstyle = UDAT_MEDIUM; break;
219 case kCFDateFormatterLongStyle: udstyle = UDAT_LONG; break;
220 case kCFDateFormatterFullStyle: udstyle = UDAT_FULL; break;
221 }
222 switch (df->_timeStyle) {
223 case kCFDateFormatterNoStyle: utstyle = UDAT_NONE; break;
224 case kCFDateFormatterShortStyle: utstyle = UDAT_SHORT; break;
225 case kCFDateFormatterMediumStyle: utstyle = UDAT_MEDIUM; break;
226 case kCFDateFormatterLongStyle: utstyle = UDAT_LONG; break;
227 case kCFDateFormatterFullStyle: utstyle = UDAT_FULL; break;
228 }
229 Boolean wantRelative = (NULL != df->_property._DoesRelativeDateFormatting && df->_property._DoesRelativeDateFormatting == kCFBooleanTrue);
230 Boolean hasFormat = (NULL != df->_property._HasCustomFormat && df->_property._HasCustomFormat == kCFBooleanTrue) || goingToHaveCustomFormat;
231 if (wantRelative && !hasFormat) {
232 udstyle |= UDAT_RELATIVE;
233 }
234
235 UErrorCode status = U_ZERO_ERROR;
236 UDateFormat *icudf = udat_open((UDateFormatStyle)utstyle, (UDateFormatStyle)udstyle, loc_buffer, tz_buffer, CFStringGetLength(tmpTZName), NULL, 0, &status);
237 if (NULL == icudf || U_FAILURE(status)) {
238 return;
239 }
240 udat_setLenient(icudf, 0);
241 if (kCFDateFormatterNoStyle == df->_dateStyle && kCFDateFormatterNoStyle == df->_timeStyle) {
242 udat_applyPattern(icudf, false, NULL, 0);
243 }
244 CFStringRef calident = (CFStringRef)CFLocaleGetValue(df->_locale, kCFLocaleCalendarIdentifierKey);
245 if (calident && CFEqual(calident, kCFCalendarIdentifierGregorian)) {
246 status = U_ZERO_ERROR;
247 udat_set2DigitYearStart(icudf, -631152000000.0, &status); // 1950-01-01 00:00:00 GMT
248 }
249 df->_df = icudf;
250
251 __CFDateFormatterCustomize(df);
252
253 UChar ubuffer[BUFFER_SIZE];
254 status = U_ZERO_ERROR;
255 int32_t ret = udat_toPattern(icudf, false, ubuffer, BUFFER_SIZE, &status);
256 if (U_SUCCESS(status) && ret <= BUFFER_SIZE) {
257 CFStringRef newFormat = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)ubuffer, ret);
258 CFStringRef formatString = __CFDateFormatterCreateForcedString(df, newFormat);
259 CFIndex cnt = CFStringGetLength(formatString);
260 CFAssert1(cnt <= 1024, __kCFLogAssertion, "%s(): format string too long", __PRETTY_FUNCTION__);
261 if (df->_format != formatString && cnt <= 1024) {
262 STACK_BUFFER_DECL(UChar, ubuffer, cnt);
263 const UChar *ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)formatString);
264 if (NULL == ustr) {
265 CFStringGetCharacters(formatString, CFRangeMake(0, cnt), (UniChar *)ubuffer);
266 ustr = ubuffer;
267 }
268 UErrorCode status = U_ZERO_ERROR;
269 // udat_applyPattern(df->_df, false, ustr, cnt, &status);
270 udat_applyPattern(df->_df, false, ustr, cnt);
271 if (U_SUCCESS(status)) {
272 if (df->_format) CFRelease(df->_format);
273 df->_format = (CFStringRef)CFStringCreateCopy(CFGetAllocator(df), formatString);
274 }
275 }
276 CFRelease(formatString);
277 CFRelease(newFormat);
278 }
279 if (df->_defformat) CFRelease(df->_defformat);
280 df->_defformat = df->_format ? (CFStringRef)CFRetain(df->_format) : NULL;
281
282 RESET_PROPERTY(_IsLenient, kCFDateFormatterIsLenientKey);
283 RESET_PROPERTY(_DoesRelativeDateFormatting, kCFDateFormatterDoesRelativeDateFormattingKey);
284 RESET_PROPERTY(_Calendar, kCFDateFormatterCalendarKey);
285 RESET_PROPERTY(_CalendarName, kCFDateFormatterCalendarIdentifierKey);
286 RESET_PROPERTY(_TimeZone, kCFDateFormatterTimeZoneKey);
287 RESET_PROPERTY(_TwoDigitStartDate, kCFDateFormatterTwoDigitStartDateKey);
288 RESET_PROPERTY(_DefaultDate, kCFDateFormatterDefaultDateKey);
289 RESET_PROPERTY(_GregorianStartDate, kCFDateFormatterGregorianStartDateKey);
290 RESET_PROPERTY(_EraSymbols, kCFDateFormatterEraSymbolsKey);
291 RESET_PROPERTY(_LongEraSymbols, kCFDateFormatterLongEraSymbolsKey);
292 RESET_PROPERTY(_MonthSymbols, kCFDateFormatterMonthSymbolsKey);
293 RESET_PROPERTY(_ShortMonthSymbols, kCFDateFormatterShortMonthSymbolsKey);
294 RESET_PROPERTY(_VeryShortMonthSymbols, kCFDateFormatterVeryShortMonthSymbolsKey);
295 RESET_PROPERTY(_StandaloneMonthSymbols, kCFDateFormatterStandaloneMonthSymbolsKey);
296 RESET_PROPERTY(_ShortStandaloneMonthSymbols, kCFDateFormatterShortStandaloneMonthSymbolsKey);
297 RESET_PROPERTY(_VeryShortStandaloneMonthSymbols, kCFDateFormatterVeryShortStandaloneMonthSymbolsKey);
298 RESET_PROPERTY(_WeekdaySymbols, kCFDateFormatterWeekdaySymbolsKey);
299 RESET_PROPERTY(_ShortWeekdaySymbols, kCFDateFormatterShortWeekdaySymbolsKey);
300 RESET_PROPERTY(_VeryShortWeekdaySymbols, kCFDateFormatterVeryShortWeekdaySymbolsKey);
301 RESET_PROPERTY(_StandaloneWeekdaySymbols, kCFDateFormatterStandaloneWeekdaySymbolsKey);
302 RESET_PROPERTY(_ShortStandaloneWeekdaySymbols, kCFDateFormatterShortStandaloneWeekdaySymbolsKey);
303 RESET_PROPERTY(_VeryShortStandaloneWeekdaySymbols, kCFDateFormatterVeryShortStandaloneWeekdaySymbolsKey);
304 RESET_PROPERTY(_QuarterSymbols, kCFDateFormatterQuarterSymbolsKey);
305 RESET_PROPERTY(_ShortQuarterSymbols, kCFDateFormatterShortQuarterSymbolsKey);
306 RESET_PROPERTY(_StandaloneQuarterSymbols, kCFDateFormatterStandaloneQuarterSymbolsKey);
307 RESET_PROPERTY(_ShortStandaloneQuarterSymbols, kCFDateFormatterShortStandaloneQuarterSymbolsKey);
308 RESET_PROPERTY(_AMSymbol, kCFDateFormatterAMSymbolKey);
309 RESET_PROPERTY(_PMSymbol, kCFDateFormatterPMSymbolKey);
310 }
311
312 static CFTypeID __kCFDateFormatterTypeID = _kCFRuntimeNotATypeID;
313
314 static const CFRuntimeClass __CFDateFormatterClass = {
315 0,
316 "CFDateFormatter",
317 NULL, // init
318 NULL, // copy
319 __CFDateFormatterDeallocate,
320 NULL,
321 NULL,
322 NULL, //
323 __CFDateFormatterCopyDescription
324 };
325
326 static void __CFDateFormatterInitialize(void) {
327 __kCFDateFormatterTypeID = _CFRuntimeRegisterClass(&__CFDateFormatterClass);
328 }
329
330 CFTypeID CFDateFormatterGetTypeID(void) {
331 if (_kCFRuntimeNotATypeID == __kCFDateFormatterTypeID) __CFDateFormatterInitialize();
332 return __kCFDateFormatterTypeID;
333 }
334
335 CFDateFormatterRef CFDateFormatterCreate(CFAllocatorRef allocator, CFLocaleRef locale, CFDateFormatterStyle dateStyle, CFDateFormatterStyle timeStyle) {
336 struct __CFDateFormatter *memory;
337 uint32_t size = sizeof(struct __CFDateFormatter) - sizeof(CFRuntimeBase);
338 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
339 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
340 if (locale) __CFGenericValidateType(locale, CFLocaleGetTypeID());
341 memory = (struct __CFDateFormatter *)_CFRuntimeCreateInstance(allocator, CFDateFormatterGetTypeID(), size, NULL);
342 if (NULL == memory) {
343 return NULL;
344 }
345 memory->_df = NULL;
346 memory->_locale = NULL;
347 memory->_format = NULL;
348 memory->_defformat = NULL;
349 memory->_dateStyle = dateStyle;
350 memory->_timeStyle = timeStyle;
351 memory->_property._IsLenient = NULL;
352 memory->_property._DoesRelativeDateFormatting = NULL;
353 memory->_property._HasCustomFormat = NULL;
354 memory->_property._TimeZone = NULL;
355 memory->_property._Calendar = NULL;
356 memory->_property._CalendarName = NULL;
357 memory->_property._TwoDigitStartDate = NULL;
358 memory->_property._DefaultDate = NULL;
359 memory->_property._GregorianStartDate = NULL;
360 memory->_property._EraSymbols = NULL;
361 memory->_property._LongEraSymbols = NULL;
362 memory->_property._MonthSymbols = NULL;
363 memory->_property._ShortMonthSymbols = NULL;
364 memory->_property._VeryShortMonthSymbols = NULL;
365 memory->_property._StandaloneMonthSymbols = NULL;
366 memory->_property._ShortStandaloneMonthSymbols = NULL;
367 memory->_property._VeryShortStandaloneMonthSymbols = NULL;
368 memory->_property._WeekdaySymbols = NULL;
369 memory->_property._ShortWeekdaySymbols = NULL;
370 memory->_property._VeryShortWeekdaySymbols = NULL;
371 memory->_property._StandaloneWeekdaySymbols = NULL;
372 memory->_property._ShortStandaloneWeekdaySymbols = NULL;
373 memory->_property._VeryShortStandaloneWeekdaySymbols = NULL;
374 memory->_property._QuarterSymbols = NULL;
375 memory->_property._ShortQuarterSymbols = NULL;
376 memory->_property._StandaloneQuarterSymbols = NULL;
377 memory->_property._ShortStandaloneQuarterSymbols = NULL;
378 memory->_property._AMSymbol = NULL;
379 memory->_property._PMSymbol = NULL;
380
381 switch (dateStyle) {
382 case kCFDateFormatterNoStyle:
383 case kCFDateFormatterShortStyle:
384 case kCFDateFormatterMediumStyle:
385 case kCFDateFormatterLongStyle:
386 case kCFDateFormatterFullStyle: break;
387 default:
388 CFAssert2(0, __kCFLogAssertion, "%s(): unknown date style %d", __PRETTY_FUNCTION__, dateStyle);
389 memory->_dateStyle = kCFDateFormatterMediumStyle;
390 break;
391 }
392 switch (timeStyle) {
393 case kCFDateFormatterNoStyle:
394 case kCFDateFormatterShortStyle:
395 case kCFDateFormatterMediumStyle:
396 case kCFDateFormatterLongStyle:
397 case kCFDateFormatterFullStyle: break;
398 default:
399 CFAssert2(0, __kCFLogAssertion, "%s(): unknown time style %d", __PRETTY_FUNCTION__, timeStyle);
400 memory->_timeStyle = kCFDateFormatterMediumStyle;
401 break;
402 }
403
404 memory->_locale = locale ? CFLocaleCreateCopy(allocator, locale) : (CFLocaleRef)CFRetain(CFLocaleGetSystem());
405 memory->_property._TimeZone = CFTimeZoneCopyDefault();
406 __ResetUDateFormat(memory, false);
407 if (!memory->_df) {
408 CFRelease(memory);
409 return NULL;
410 }
411 return (CFDateFormatterRef)memory;
412 }
413
414 extern CFDictionaryRef __CFLocaleGetPrefs(CFLocaleRef locale);
415
416 static void __substituteFormatStringFromPrefsDFRelative(CFDateFormatterRef formatter) {
417 CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale);
418
419 CFIndex dateLen = -1;
420 UChar dateBuffer[BUFFER_SIZE];
421 if (kCFDateFormatterNoStyle != formatter->_dateStyle) {
422 CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUDateFormatStrings")) : NULL;
423 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) {
424 CFStringRef key;
425 switch (formatter->_dateStyle) {
426 case kCFDateFormatterShortStyle: key = CFSTR("1"); break;
427 case kCFDateFormatterMediumStyle: key = CFSTR("2"); break;
428 case kCFDateFormatterLongStyle: key = CFSTR("3"); break;
429 case kCFDateFormatterFullStyle: key = CFSTR("4"); break;
430 default: key = CFSTR("0"); break;
431 }
432 CFStringRef pref = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)metapref, key);
433 if (NULL != pref && CFGetTypeID(pref) == CFStringGetTypeID()) {
434 dateLen = __CFMin(CFStringGetLength(pref), BUFFER_SIZE);
435 CFStringGetCharacters(pref, CFRangeMake(0, dateLen), (UniChar *)dateBuffer);
436 }
437 }
438 }
439 if (-1 == dateLen) {
440 UErrorCode status = U_ZERO_ERROR;
441 int32_t ret = udat_toPatternRelativeDate(formatter->_df, dateBuffer, BUFFER_SIZE, &status);
442 if (!U_FAILURE(status)) {
443 dateLen = ret;
444 }
445 }
446
447 CFIndex timeLen = -1;
448 UChar timeBuffer[BUFFER_SIZE];
449 if (kCFDateFormatterNoStyle != formatter->_timeStyle) {
450 CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUTimeFormatStrings")) : NULL;
451 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) {
452 CFStringRef key;
453 switch (formatter->_timeStyle) {
454 case kCFDateFormatterShortStyle: key = CFSTR("1"); break;
455 case kCFDateFormatterMediumStyle: key = CFSTR("2"); break;
456 case kCFDateFormatterLongStyle: key = CFSTR("3"); break;
457 case kCFDateFormatterFullStyle: key = CFSTR("4"); break;
458 default: key = CFSTR("0"); break;
459 }
460 CFStringRef pref = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)metapref, key);
461 if (NULL != pref && CFGetTypeID(pref) == CFStringGetTypeID()) {
462 timeLen = __CFMin(CFStringGetLength(pref), BUFFER_SIZE);
463 CFStringGetCharacters(pref, CFRangeMake(0, timeLen), (UniChar *)timeBuffer);
464 }
465 }
466 }
467 if (-1 == timeLen) {
468 UErrorCode status = U_ZERO_ERROR;
469 int32_t ret = udat_toPatternRelativeTime(formatter->_df, timeBuffer, BUFFER_SIZE, &status);
470 if (!U_FAILURE(status)) {
471 timeLen = ret;
472 }
473 }
474
475 UErrorCode status = U_ZERO_ERROR;
476 udat_applyPatternRelative(formatter->_df, (0 <= dateLen) ? dateBuffer : NULL, (0 <= dateLen) ? dateLen : 0, (0 <= timeLen) ? timeBuffer : NULL, (0 <= timeLen) ? timeLen : 0, &status);
477 }
478
479 static void __substituteFormatStringFromPrefsDF(CFDateFormatterRef formatter, bool doTime) {
480 CFIndex formatStyle = doTime ? formatter->_timeStyle : formatter->_dateStyle;
481 CFStringRef prefName = doTime ? CFSTR("AppleICUTimeFormatStrings") : CFSTR("AppleICUDateFormatStrings");
482 if (kCFDateFormatterNoStyle != formatStyle) {
483 CFStringRef pref = NULL;
484 CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale);
485 CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, prefName) : NULL;
486 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) {
487 CFStringRef key;
488 switch (formatStyle) {
489 case kCFDateFormatterShortStyle: key = CFSTR("1"); break;
490 case kCFDateFormatterMediumStyle: key = CFSTR("2"); break;
491 case kCFDateFormatterLongStyle: key = CFSTR("3"); break;
492 case kCFDateFormatterFullStyle: key = CFSTR("4"); break;
493 default: key = CFSTR("0"); break;
494 }
495 pref = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)metapref, key);
496 }
497 if (NULL != pref && CFGetTypeID(pref) == CFStringGetTypeID()) {
498 int32_t icustyle = UDAT_NONE;
499 switch (formatStyle) {
500 case kCFDateFormatterShortStyle: icustyle = UDAT_SHORT; break;
501 case kCFDateFormatterMediumStyle: icustyle = UDAT_MEDIUM; break;
502 case kCFDateFormatterLongStyle: icustyle = UDAT_LONG; break;
503 case kCFDateFormatterFullStyle: icustyle = UDAT_FULL; break;
504 }
505 CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale);
506 char buffer[BUFFER_SIZE];
507 const char *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII);
508 if (NULL == cstr) {
509 if (CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer;
510 }
511 UErrorCode status = U_ZERO_ERROR;
512 UDateFormat *df = udat_open((UDateFormatStyle)(doTime ? icustyle : UDAT_NONE), (UDateFormatStyle)(doTime ? UDAT_NONE : icustyle), cstr, NULL, 0, NULL, 0, &status);
513 if (NULL != df) {
514 UChar ubuffer[BUFFER_SIZE];
515 status = U_ZERO_ERROR;
516 int32_t date_len = udat_toPattern(df, false, ubuffer, BUFFER_SIZE, &status);
517 if (U_SUCCESS(status) && date_len <= BUFFER_SIZE) {
518 CFStringRef dateString = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)ubuffer, date_len);
519 status = U_ZERO_ERROR;
520 int32_t formatter_len = udat_toPattern(formatter->_df, false, ubuffer, BUFFER_SIZE, &status);
521 if (U_SUCCESS(status) && formatter_len <= BUFFER_SIZE) {
522 CFMutableStringRef formatString = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
523 CFStringAppendCharacters(formatString, (UniChar *)ubuffer, formatter_len);
524 // find dateString inside formatString, substitute the pref in that range
525 CFRange result;
526 if (CFStringFindWithOptions(formatString, dateString, CFRangeMake(0, formatter_len), 0, &result)) {
527 CFStringReplace(formatString, result, pref);
528 int32_t new_len = CFStringGetLength(formatString);
529 STACK_BUFFER_DECL(UChar, new_buffer, new_len);
530 const UChar *new_ustr = (UChar *)CFStringGetCharactersPtr(formatString);
531 if (NULL == new_ustr) {
532 CFStringGetCharacters(formatString, CFRangeMake(0, new_len), (UniChar *)new_buffer);
533 new_ustr = new_buffer;
534 }
535 status = U_ZERO_ERROR;
536 // udat_applyPattern(formatter->_df, false, new_ustr, new_len, &status);
537 udat_applyPattern(formatter->_df, false, new_ustr, new_len);
538 }
539 CFRelease(formatString);
540 }
541 CFRelease(dateString);
542 }
543 udat_close(df);
544 }
545 }
546 }
547 }
548
549 static void __CFDateFormatterApplySymbolPrefs(const void *key, const void *value, void *context) {
550 if (CFGetTypeID(key) == CFStringGetTypeID() && CFGetTypeID(value) == CFArrayGetTypeID()) {
551 CFDateFormatterRef formatter = (CFDateFormatterRef)context;
552 UDateFormatSymbolType sym = (UDateFormatSymbolType)CFStringGetIntValue((CFStringRef)key);
553 CFArrayRef array = (CFArrayRef)value;
554 CFIndex idx, cnt = CFArrayGetCount(array);
555 for (idx = 0; idx < cnt; idx++) {
556 CFStringRef item = (CFStringRef)CFArrayGetValueAtIndex(array, idx);
557 if (CFGetTypeID(item) != CFStringGetTypeID()) continue;
558 CFIndex item_cnt = CFStringGetLength(item);
559 STACK_BUFFER_DECL(UChar, item_buffer, __CFMin(BUFFER_SIZE, item_cnt));
560 UChar *item_ustr = (UChar *)CFStringGetCharactersPtr(item);
561 if (NULL == item_ustr) {
562 item_cnt = __CFMin(BUFFER_SIZE, item_cnt);
563 CFStringGetCharacters(item, CFRangeMake(0, item_cnt), (UniChar *)item_buffer);
564 item_ustr = item_buffer;
565 }
566 UErrorCode status = U_ZERO_ERROR;
567 udat_setSymbols(formatter->_df, sym, idx, item_ustr, item_cnt, &status);
568 }
569 }
570 }
571
572 static CFStringRef __CFDateFormatterCreateForcedString(CFDateFormatterRef formatter, CFStringRef inString) {
573 if (!inString) return NULL;
574 Boolean doForce24 = false, doForce12 = false;
575 CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale);
576 CFPropertyListRef pref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUForce24HourTime")) : NULL;
577 if (NULL != pref && CFGetTypeID(pref) == CFBooleanGetTypeID()) {
578 doForce24 = CFBooleanGetValue((CFBooleanRef)pref);
579 }
580 pref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUForce12HourTime")) : NULL;
581 if (NULL != pref && CFGetTypeID(pref) == CFBooleanGetTypeID()) {
582 doForce12 = CFBooleanGetValue((CFBooleanRef)pref);
583 }
584 if (!doForce24 && !doForce12) return (CFStringRef)CFRetain(inString);
585 if (doForce24) doForce12 = false; // if both are set, Force24 wins, period
586 CFMutableStringRef outString = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
587 CFIndex cnt = CFStringGetLength(inString);
588 CFIndex lastSecond = -1, lastMinute = -1, firstHour = -1;
589 Boolean isInQuote = false, hasA = false, had12Hour = false, had24Hour = false;
590 for (CFIndex idx = 0; idx < cnt; idx++) {
591 Boolean emit = true;
592 UniChar ch = CFStringGetCharacterAtIndex(inString, idx);
593 switch (ch) {
594 case '\'': isInQuote = !isInQuote; break;
595 case 'h': if (!isInQuote) {if (-1 == firstHour) firstHour = CFStringGetLength(outString); had12Hour = true; if (doForce24) ch = 'H';} break; // switch 12-hour to 24-hour
596 case 'K': if (!isInQuote) {if (-1 == firstHour) firstHour = CFStringGetLength(outString); had12Hour = true; if (doForce24) ch = 'k';} break; // switch 12-hour to 24-hour
597 case 'H': if (!isInQuote) {if (-1 == firstHour) firstHour = CFStringGetLength(outString); had24Hour = true; if (doForce12) ch = 'h';} break; // switch 24-hour to 12-hour
598 case 'k': if (!isInQuote) {if (-1 == firstHour) firstHour = CFStringGetLength(outString); had24Hour = true; if (doForce12) ch = 'K';} break; // switch 24-hour to 12-hour
599 case 'm': if (!isInQuote) lastMinute = CFStringGetLength(outString); break;
600 case 's': if (!isInQuote) lastSecond = CFStringGetLength(outString); break;
601 case 'a': if (!isInQuote) hasA = true;
602 if (!isInQuote && doForce24) {
603 // skip 'a' and one optional trailing space
604 emit = false;
605 if (idx + 1 < cnt && ' ' == CFStringGetCharacterAtIndex(inString, idx + 1)) idx++;
606 }
607 break;
608 case ' ':
609 if (!isInQuote && doForce24) {
610 // if next character is 'a' AND we have seen the hour designator, skip space and 'a'
611 if (idx + 1 < cnt && 'a' == CFStringGetCharacterAtIndex(inString, idx + 1) && -1 != firstHour) {
612 emit = false;
613 idx++;
614 }
615 }
616 break;
617 }
618 if (emit) CFStringAppendCharacters(outString, &ch, 1);
619 }
620 if (doForce12 && !hasA && had24Hour) {
621 CFStringRef locName = CFLocaleGetIdentifier(formatter->_locale);
622 if (-1 != firstHour && (CFStringHasPrefix(locName, CFSTR("ko")) || CFEqual(locName, CFSTR("zh_SG")))) {
623 CFStringInsert(outString, firstHour, CFSTR("a "));
624 } else if (-1 != firstHour && (CFStringHasPrefix(locName, CFSTR("zh")) || CFStringHasPrefix(locName, CFSTR("ja")))) {
625 CFStringInsert(outString, firstHour, CFSTR("a"));
626 } else {
627 CFIndex lastPos = (-1 != lastSecond) ? lastSecond : ((-1 != lastMinute) ? lastMinute : -1);
628 if (-1 != lastPos) {
629 cnt = CFStringGetLength(outString);
630 lastPos++;
631 UniChar ch = (lastPos < cnt) ? CFStringGetCharacterAtIndex(outString, lastPos) : 0;
632 switch (ch) {
633 case '\"': lastPos++; break;
634 case '\'':;
635 again:;
636 do {
637 lastPos++;
638 ch = (lastPos < cnt) ? CFStringGetCharacterAtIndex(outString, lastPos) : 0;
639 } while ('\'' != ch && '\0' != ch);
640 if ('\'' == ch) lastPos++;
641 ch = (lastPos < cnt) ? CFStringGetCharacterAtIndex(outString, lastPos) : 0;
642 if ('\'' == ch) goto again;
643 break;
644 }
645 CFStringInsert(outString, lastPos, CFSTR(" a"));
646 }
647 }
648 }
649 return outString;
650 }
651
652 static void __CFDateFormatterCustomize(CFDateFormatterRef formatter) {
653 Boolean wantRelative = (NULL != formatter->_property._DoesRelativeDateFormatting && formatter->_property._DoesRelativeDateFormatting == kCFBooleanTrue);
654 Boolean hasFormat = (NULL != formatter->_property._HasCustomFormat && formatter->_property._HasCustomFormat == kCFBooleanTrue);
655 if (wantRelative && !hasFormat) {
656 __substituteFormatStringFromPrefsDFRelative(formatter);
657 } else {
658 __substituteFormatStringFromPrefsDF(formatter, false);
659 __substituteFormatStringFromPrefsDF(formatter, true);
660 }
661 CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale);
662 CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUDateTimeSymbols")) : NULL;
663 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) {
664 CFDictionaryApplyFunction((CFDictionaryRef)metapref, __CFDateFormatterApplySymbolPrefs, formatter);
665 }
666 metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleFirstWeekday")) : NULL;
667 CFStringRef calID = (CFStringRef)CFLocaleGetValue(formatter->_locale, kCFLocaleCalendarIdentifierKey);
668 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) {
669 metapref = (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)metapref, calID);
670 }
671 if (NULL != metapref && CFGetTypeID(metapref) == CFNumberGetTypeID()) {
672 CFIndex wkdy;
673 if (CFNumberGetValue((CFNumberRef)metapref, kCFNumberCFIndexType, &wkdy)) {
674 UCalendar *cal = (UCalendar *)udat_getCalendar(formatter->_df);
675 if (cal) ucal_setAttribute(cal, UCAL_FIRST_DAY_OF_WEEK, wkdy);
676 }
677 }
678 metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleMinDaysInFirstWeek")) : NULL;
679 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) {
680 metapref = (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)metapref, calID);
681 }
682 if (NULL != metapref && CFGetTypeID(metapref) == CFNumberGetTypeID()) {
683 CFIndex mwd;
684 if (CFNumberGetValue((CFNumberRef)metapref, kCFNumberCFIndexType, &mwd)) {
685 UCalendar *cal = (UCalendar *)udat_getCalendar(formatter->_df);
686 if (cal) ucal_setAttribute(cal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK, mwd);
687 }
688 }
689 }
690
691 CFLocaleRef CFDateFormatterGetLocale(CFDateFormatterRef formatter) {
692 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
693 return formatter->_locale;
694 }
695
696 CFDateFormatterStyle CFDateFormatterGetDateStyle(CFDateFormatterRef formatter) {
697 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
698 return formatter->_dateStyle;
699 }
700
701 CFDateFormatterStyle CFDateFormatterGetTimeStyle(CFDateFormatterRef formatter) {
702 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
703 return formatter->_timeStyle;
704 }
705
706 CFStringRef CFDateFormatterGetFormat(CFDateFormatterRef formatter) {
707 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
708 return formatter->_format;
709 }
710
711 void CFDateFormatterSetFormat(CFDateFormatterRef formatter, CFStringRef formatString) {
712 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
713 __CFGenericValidateType(formatString, CFStringGetTypeID());
714 formatString = __CFDateFormatterCreateForcedString(formatter, formatString);
715 CFIndex cnt = CFStringGetLength(formatString);
716 CFAssert1(cnt <= 1024, __kCFLogAssertion, "%s(): format string too long", __PRETTY_FUNCTION__);
717 if (formatter->_format != formatString && cnt <= 1024) {
718 __ResetUDateFormat(formatter, true);
719 STACK_BUFFER_DECL(UChar, ubuffer, cnt);
720 const UChar *ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)formatString);
721 if (NULL == ustr) {
722 CFStringGetCharacters(formatString, CFRangeMake(0, cnt), (UniChar *)ubuffer);
723 ustr = ubuffer;
724 }
725 UErrorCode status = U_ZERO_ERROR;
726 // udat_applyPattern(formatter->_df, false, ustr, cnt, &status);
727 udat_applyPattern(formatter->_df, false, ustr, cnt);
728 if (U_SUCCESS(status)) {
729 if (formatter->_format) CFRelease(formatter->_format);
730 formatter->_format = (CFStringRef)CFStringCreateCopy(CFGetAllocator(formatter), formatString);
731 }
732 }
733 if (formatString) CFRelease(formatString);
734 }
735
736 CFStringRef CFDateFormatterCreateStringWithDate(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFDateRef date) {
737 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
738 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
739 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
740 __CFGenericValidateType(date, CFDateGetTypeID());
741 return CFDateFormatterCreateStringWithAbsoluteTime(allocator, formatter, CFDateGetAbsoluteTime(date));
742 }
743
744 CFStringRef CFDateFormatterCreateStringWithAbsoluteTime(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFAbsoluteTime at) {
745 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
746 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
747 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
748 UChar *ustr = NULL, ubuffer[BUFFER_SIZE];
749 UErrorCode status = U_ZERO_ERROR;
750 CFIndex used, cnt = BUFFER_SIZE;
751 UDate ud = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0 + 0.5;
752 used = udat_format(formatter->_df, ud, ubuffer, cnt, NULL, &status);
753 if (status == U_BUFFER_OVERFLOW_ERROR || cnt < used) {
754 cnt = used + 1;
755 ustr = (UChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UChar) * cnt, 0);
756 status = U_ZERO_ERROR;
757 used = udat_format(formatter->_df, ud, ustr, cnt, NULL, &status);
758 }
759 CFStringRef string = NULL;
760 if (U_SUCCESS(status)) {
761 string = CFStringCreateWithCharacters(allocator, (const UniChar *)(ustr ? ustr : ubuffer), used);
762 }
763 if (ustr) CFAllocatorDeallocate(kCFAllocatorSystemDefault, ustr);
764 return string;
765 }
766
767 CFDateRef CFDateFormatterCreateDateFromString(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFStringRef string, CFRange *rangep) {
768 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
769 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
770 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
771 __CFGenericValidateType(string, CFStringGetTypeID());
772 CFAbsoluteTime at;
773 if (CFDateFormatterGetAbsoluteTimeFromString(formatter, string, rangep, &at)) {
774 return CFDateCreate(allocator, at);
775 }
776 return NULL;
777 }
778
779 Boolean CFDateFormatterGetAbsoluteTimeFromString(CFDateFormatterRef formatter, CFStringRef string, CFRange *rangep, CFAbsoluteTime *atp) {
780 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
781 __CFGenericValidateType(string, CFStringGetTypeID());
782 CFRange range = {0, 0};
783 if (rangep) {
784 range = *rangep;
785 } else {
786 range.length = CFStringGetLength(string);
787 }
788 if (1024 < range.length) range.length = 1024;
789 const UChar *ustr = (UChar *)CFStringGetCharactersPtr(string);
790 STACK_BUFFER_DECL(UChar, ubuffer, (NULL == ustr) ? range.length : 1);
791 if (NULL == ustr) {
792 CFStringGetCharacters(string, range, (UniChar *)ubuffer);
793 ustr = ubuffer;
794 } else {
795 ustr += range.location;
796 }
797 UDate udate;
798 int32_t dpos = 0;
799 UErrorCode status = U_ZERO_ERROR;
800 if (formatter->_property._DefaultDate) {
801 CFAbsoluteTime at = CFDateGetAbsoluteTime(formatter->_property._DefaultDate);
802 udate = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0;
803 UDateFormat *df2 = udat_clone(formatter->_df, &status);
804 UCalendar *cal2 = (UCalendar *)udat_getCalendar(df2);
805 ucal_setMillis(cal2, udate, &status);
806 udat_parseCalendar(formatter->_df, cal2, ustr, range.length, &dpos, &status);
807 udate = ucal_getMillis(cal2, &status);
808 udat_close(df2);
809 } else {
810 udate = udat_parse(formatter->_df, ustr, range.length, &dpos, &status);
811 }
812 if (rangep) rangep->length = dpos;
813 if (U_FAILURE(status)) {
814 return false;
815 }
816 if (atp) {
817 *atp = (double)udate / 1000.0 - kCFAbsoluteTimeIntervalSince1970;
818 }
819 return true;
820 }
821
822 static void __CFDateFormatterSetSymbolsArray(UDateFormat *icudf, int32_t icucode, int index_base, CFTypeRef value) {
823 UErrorCode status = U_ZERO_ERROR;
824 __CFGenericValidateType(value, CFArrayGetTypeID());
825 CFArrayRef array = (CFArrayRef)value;
826 CFIndex idx, cnt = CFArrayGetCount(array);
827 for (idx = 0; idx < cnt; idx++) {
828 CFStringRef item = (CFStringRef)CFArrayGetValueAtIndex(array, idx);
829 __CFGenericValidateType(item, CFStringGetTypeID());
830 CFIndex item_cnt = CFStringGetLength(item);
831 STACK_BUFFER_DECL(UChar, item_buffer, __CFMin(BUFFER_SIZE, item_cnt));
832 UChar *item_ustr = (UChar *)CFStringGetCharactersPtr(item);
833 if (NULL == item_ustr) {
834 item_cnt = __CFMin(BUFFER_SIZE, item_cnt);
835 CFStringGetCharacters(item, CFRangeMake(0, item_cnt), (UniChar *)item_buffer);
836 item_ustr = item_buffer;
837 }
838 status = U_ZERO_ERROR;
839 udat_setSymbols(icudf, (UDateFormatSymbolType)icucode, idx + index_base, item_ustr, item_cnt, &status);
840 }
841 }
842
843 static CFArrayRef __CFDateFormatterGetSymbolsArray(UDateFormat *icudf, int32_t icucode, int index_base) {
844 UErrorCode status = U_ZERO_ERROR;
845 CFIndex idx, cnt = udat_countSymbols(icudf, (UDateFormatSymbolType)icucode) - index_base;
846 STACK_BUFFER_DECL(CFStringRef, strings, cnt);
847 for (idx = 0; idx < cnt; idx++) {
848 UChar ubuffer[BUFFER_SIZE];
849 CFStringRef str = NULL;
850 status = U_ZERO_ERROR;
851 CFIndex ucnt = udat_getSymbols(icudf, (UDateFormatSymbolType)icucode, idx + index_base, ubuffer, BUFFER_SIZE, &status);
852 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
853 str = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)ubuffer, ucnt);
854 }
855 strings[idx] = !str ? (CFStringRef)CFRetain(CFSTR("<error>")) : str;
856 }
857 CFArrayRef array = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)strings, cnt, &kCFTypeArrayCallBacks);
858 while (cnt--) {
859 CFRelease(strings[cnt]);
860 }
861 return array;
862 }
863
864 #define SET_SYMBOLS_ARRAY(A, B, C) \
865 if (!directToICU) { \
866 oldProperty = formatter->_property. C; \
867 formatter->_property. C = NULL; \
868 } \
869 __CFDateFormatterSetSymbolsArray(formatter->_df, A, B, value); \
870 if (!directToICU) { \
871 formatter->_property. C = __CFDateFormatterGetSymbolsArray(formatter->_df, A, B); \
872 }
873
874 static void __CFDateFormatterSetProperty(CFDateFormatterRef formatter, CFStringRef key, CFTypeRef value, Boolean directToICU) {
875 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
876 __CFGenericValidateType(key, CFStringGetTypeID());
877 CFTypeRef oldProperty = NULL;
878 UErrorCode status = U_ZERO_ERROR;
879 UChar ubuffer[BUFFER_SIZE];
880
881 if (kCFDateFormatterIsLenientKey == key) {
882 if (!directToICU) {
883 oldProperty = formatter->_property. _IsLenient;
884 formatter->_property. _IsLenient = NULL;
885 }
886 __CFGenericValidateType(value, CFBooleanGetTypeID());
887 udat_setLenient(formatter->_df, (kCFBooleanTrue == value));
888 UCalendar *cal = (UCalendar *)udat_getCalendar(formatter->_df);
889 if (cal) ucal_setAttribute(cal, UCAL_LENIENT, (kCFBooleanTrue == value));
890 if (!directToICU) {
891 formatter->_property. _IsLenient = (CFBooleanRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterIsLenientKey);
892 }
893 } else if (kCFDateFormatterDoesRelativeDateFormattingKey == key) {
894 if (!directToICU) {
895 oldProperty = formatter->_property. _DoesRelativeDateFormatting;
896 formatter->_property. _DoesRelativeDateFormatting = NULL;
897 }
898 __CFGenericValidateType(value, CFBooleanGetTypeID());
899 if (!directToICU) {
900 if (kCFBooleanTrue != value) value = kCFBooleanFalse;
901 formatter->_property. _DoesRelativeDateFormatting = value ? (CFBooleanRef)CFRetain(value) : NULL;
902 __ResetUDateFormat(formatter, false);
903 }
904 } else if (kCFDateFormatterCalendarKey == key) {
905 if (!directToICU) {
906 oldProperty = formatter->_property. _Calendar;
907 formatter->_property. _Calendar = NULL;
908 }
909 __CFGenericValidateType(value, CFCalendarGetTypeID());
910 CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale);
911 CFDictionaryRef components = CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault, localeName);
912 CFMutableDictionaryRef mcomponents = CFDictionaryCreateMutableCopy(kCFAllocatorSystemDefault, 0, components);
913 CFDictionarySetValue(mcomponents, kCFLocaleCalendarIdentifierKey, CFCalendarGetIdentifier((CFCalendarRef)value));
914 localeName = CFLocaleCreateLocaleIdentifierFromComponents(kCFAllocatorSystemDefault, mcomponents);
915 CFRelease(mcomponents);
916 CFRelease(components);
917 CFLocaleRef newLocale = CFLocaleCreate(CFGetAllocator(formatter->_locale), localeName);
918 CFRelease(localeName);
919 CFRelease(formatter->_locale);
920 formatter->_locale = newLocale;
921 UCalendar *cal = __CFCalendarCreateUCalendar(NULL, CFLocaleGetIdentifier(formatter->_locale), formatter->_property._TimeZone);
922 if (cal) ucal_setAttribute(cal, UCAL_FIRST_DAY_OF_WEEK, CFCalendarGetFirstWeekday((CFCalendarRef)value));
923 if (cal) ucal_setAttribute(cal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK, CFCalendarGetMinimumDaysInFirstWeek((CFCalendarRef)value));
924 if (cal) udat_setCalendar(formatter->_df, cal);
925 if (cal) ucal_close(cal);
926 if (!directToICU) {
927 formatter->_property. _Calendar = (CFCalendarRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterCalendarKey);
928 }
929 } else if (kCFDateFormatterCalendarIdentifierKey == key) {
930 if (!directToICU) {
931 oldProperty = formatter->_property. _CalendarName;
932 formatter->_property. _CalendarName = NULL;
933 }
934 __CFGenericValidateType(value, CFStringGetTypeID());
935 CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale);
936 CFDictionaryRef components = CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault, localeName);
937 CFMutableDictionaryRef mcomponents = CFDictionaryCreateMutableCopy(kCFAllocatorSystemDefault, 0, components);
938 CFDictionarySetValue(mcomponents, kCFLocaleCalendarIdentifierKey, value);
939 localeName = CFLocaleCreateLocaleIdentifierFromComponents(kCFAllocatorSystemDefault, mcomponents);
940 CFRelease(mcomponents);
941 CFRelease(components);
942 CFLocaleRef newLocale = CFLocaleCreate(CFGetAllocator(formatter->_locale), localeName);
943 CFRelease(localeName);
944 CFRelease(formatter->_locale);
945 formatter->_locale = newLocale;
946 UCalendar *cal = __CFCalendarCreateUCalendar(NULL, CFLocaleGetIdentifier(formatter->_locale), formatter->_property._TimeZone);
947 if (cal) udat_setCalendar(formatter->_df, cal);
948 if (cal) ucal_close(cal);
949 if (!directToICU) {
950 formatter->_property. _CalendarName = (CFStringRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterCalendarIdentifierKey);
951 }
952 } else if (kCFDateFormatterTimeZoneKey == key) {
953 if (formatter->_property. _TimeZone != value) {
954 if (!directToICU) {
955 oldProperty = formatter->_property. _TimeZone;
956 formatter->_property. _TimeZone = NULL;
957 }
958 __CFGenericValidateType(value, CFTimeZoneGetTypeID());
959 CFTimeZoneRef old = formatter->_property._TimeZone;
960 formatter->_property._TimeZone = value ? (CFTimeZoneRef)CFRetain(value) : CFTimeZoneCopyDefault();
961 if (old) CFRelease(old);
962 CFStringRef tznam = CFTimeZoneGetName(formatter->_property._TimeZone);
963 UCalendar *cal = (UCalendar *)udat_getCalendar(formatter->_df);
964 CFIndex ucnt = CFStringGetLength(tznam);
965 if (BUFFER_SIZE < ucnt) ucnt = BUFFER_SIZE;
966 CFStringGetCharacters(tznam, CFRangeMake(0, ucnt), (UniChar *)ubuffer);
967 ucal_setTimeZone(cal, ubuffer, ucnt, &status);
968 if (!directToICU) {
969 old = formatter->_property._TimeZone;
970 formatter->_property. _TimeZone = (CFTimeZoneRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterTimeZoneKey);
971 if (old) CFRelease(old);
972 }
973 }
974 } else if (kCFDateFormatterDefaultFormatKey == key) {
975 // read-only attribute
976 } else if (kCFDateFormatterTwoDigitStartDateKey == key) {
977 if (!directToICU) {
978 oldProperty = formatter->_property. _TwoDigitStartDate;
979 formatter->_property. _TwoDigitStartDate = NULL;
980 }
981 __CFGenericValidateType(value, CFDateGetTypeID());
982 CFAbsoluteTime at = CFDateGetAbsoluteTime((CFDateRef)value);
983 UDate udate = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0;
984 udat_set2DigitYearStart(formatter->_df, udate, &status);
985 if (!directToICU) {
986 formatter->_property. _TwoDigitStartDate = (CFDateRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterTwoDigitStartDateKey);
987 }
988 } else if (kCFDateFormatterDefaultDateKey == key) {
989 if (!directToICU) {
990 oldProperty = formatter->_property. _DefaultDate;
991 formatter->_property. _DefaultDate = NULL;
992 }
993 __CFGenericValidateType(value, CFDateGetTypeID());
994 if (!directToICU) {
995 formatter->_property._DefaultDate = value ? (CFDateRef)CFRetain(value) : NULL;
996 }
997 } else if (kCFDateFormatterGregorianStartDateKey == key) {
998 if (!directToICU) {
999 oldProperty = formatter->_property. _GregorianStartDate;
1000 formatter->_property. _GregorianStartDate = NULL;
1001 }
1002 __CFGenericValidateType(value, CFDateGetTypeID());
1003 CFAbsoluteTime at = CFDateGetAbsoluteTime((CFDateRef)value);
1004 UDate udate = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0;
1005 UCalendar *cal = (UCalendar *)udat_getCalendar(formatter->_df);
1006 ucal_setGregorianChange(cal, udate, &status);
1007 if (!directToICU) {
1008 formatter->_property. _GregorianStartDate = (CFDateRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterGregorianStartDateKey);
1009 }
1010 } else if (kCFDateFormatterEraSymbolsKey == key) {
1011 SET_SYMBOLS_ARRAY(UDAT_ERAS, 0, _EraSymbols)
1012 } else if (kCFDateFormatterLongEraSymbolsKey == key) {
1013 SET_SYMBOLS_ARRAY(UDAT_ERA_NAMES, 0, _LongEraSymbols)
1014 } else if (kCFDateFormatterMonthSymbolsKey == key) {
1015 SET_SYMBOLS_ARRAY(UDAT_MONTHS, 0, _MonthSymbols)
1016 } else if (kCFDateFormatterShortMonthSymbolsKey == key) {
1017 SET_SYMBOLS_ARRAY(UDAT_SHORT_MONTHS, 0, _ShortMonthSymbols)
1018 } else if (kCFDateFormatterVeryShortMonthSymbolsKey == key) {
1019 SET_SYMBOLS_ARRAY(UDAT_NARROW_MONTHS, 0, _VeryShortMonthSymbols)
1020 } else if (kCFDateFormatterStandaloneMonthSymbolsKey == key) {
1021 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_MONTHS, 0, _StandaloneMonthSymbols)
1022 } else if (kCFDateFormatterShortStandaloneMonthSymbolsKey == key) {
1023 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_MONTHS, 0, _ShortStandaloneMonthSymbols)
1024 } else if (kCFDateFormatterVeryShortStandaloneMonthSymbolsKey == key) {
1025 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_NARROW_MONTHS, 0, _VeryShortStandaloneMonthSymbols)
1026 } else if (kCFDateFormatterWeekdaySymbolsKey == key) {
1027 SET_SYMBOLS_ARRAY(UDAT_WEEKDAYS, 1, _WeekdaySymbols)
1028 } else if (kCFDateFormatterShortWeekdaySymbolsKey == key) {
1029 SET_SYMBOLS_ARRAY(UDAT_SHORT_WEEKDAYS, 1, _ShortWeekdaySymbols)
1030 } else if (kCFDateFormatterVeryShortWeekdaySymbolsKey == key) {
1031 SET_SYMBOLS_ARRAY(UDAT_NARROW_WEEKDAYS, 1, _VeryShortWeekdaySymbols)
1032 } else if (kCFDateFormatterStandaloneWeekdaySymbolsKey == key) {
1033 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_WEEKDAYS, 1, _StandaloneWeekdaySymbols)
1034 } else if (kCFDateFormatterShortStandaloneWeekdaySymbolsKey == key) {
1035 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_WEEKDAYS, 1, _ShortStandaloneWeekdaySymbols)
1036 } else if (kCFDateFormatterVeryShortStandaloneWeekdaySymbolsKey == key) {
1037 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_NARROW_WEEKDAYS, 1, _VeryShortStandaloneWeekdaySymbols)
1038 } else if (kCFDateFormatterQuarterSymbolsKey == key) {
1039 SET_SYMBOLS_ARRAY(UDAT_QUARTERS, 0, _QuarterSymbols)
1040 } else if (kCFDateFormatterShortQuarterSymbolsKey == key) {
1041 SET_SYMBOLS_ARRAY(UDAT_SHORT_QUARTERS, 0, _ShortQuarterSymbols)
1042 } else if (kCFDateFormatterStandaloneQuarterSymbolsKey == key) {
1043 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_QUARTERS, 0, _StandaloneQuarterSymbols)
1044 } else if (kCFDateFormatterShortStandaloneQuarterSymbolsKey == key) {
1045 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_QUARTERS, 0, _ShortStandaloneQuarterSymbols)
1046 } else if (kCFDateFormatterAMSymbolKey == key) {
1047 if (!directToICU) {
1048 oldProperty = formatter->_property. _AMSymbol;
1049 formatter->_property. _AMSymbol = NULL;
1050 }
1051 __CFGenericValidateType(value, CFStringGetTypeID());
1052 CFIndex item_cnt = CFStringGetLength((CFStringRef)value);
1053 STACK_BUFFER_DECL(UChar, item_buffer, __CFMin(BUFFER_SIZE, item_cnt));
1054 UChar *item_ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)value);
1055 if (NULL == item_ustr) {
1056 item_cnt = __CFMin(BUFFER_SIZE, item_cnt);
1057 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, item_cnt), (UniChar *)item_buffer);
1058 item_ustr = item_buffer;
1059 }
1060 udat_setSymbols(formatter->_df, UDAT_AM_PMS, 0, item_ustr, item_cnt, &status);
1061 if (!directToICU) {
1062 formatter->_property. _AMSymbol = (CFStringRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterAMSymbolKey);
1063 }
1064 } else if (kCFDateFormatterPMSymbolKey == key) {
1065 if (!directToICU) {
1066 oldProperty = formatter->_property. _PMSymbol;
1067 formatter->_property. _PMSymbol = NULL;
1068 }
1069 __CFGenericValidateType(value, CFStringGetTypeID());
1070 CFIndex item_cnt = CFStringGetLength((CFStringRef)value);
1071 STACK_BUFFER_DECL(UChar, item_buffer, __CFMin(BUFFER_SIZE, item_cnt));
1072 UChar *item_ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)value);
1073 if (NULL == item_ustr) {
1074 item_cnt = __CFMin(BUFFER_SIZE, item_cnt);
1075 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, item_cnt), (UniChar *)item_buffer);
1076 item_ustr = item_buffer;
1077 }
1078 udat_setSymbols(formatter->_df, UDAT_AM_PMS, 1, item_ustr, item_cnt, &status);
1079 if (!directToICU) {
1080 formatter->_property. _PMSymbol = (CFStringRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterPMSymbolKey);
1081 }
1082 } else {
1083 CFAssert3(0, __kCFLogAssertion, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__, key, key);
1084 }
1085 if (oldProperty) CFRelease(oldProperty);
1086 }
1087
1088 void CFDateFormatterSetProperty(CFDateFormatterRef formatter, CFStringRef key, CFTypeRef value) {
1089 __CFDateFormatterSetProperty(formatter, key, value, false);
1090 }
1091
1092 CFTypeRef CFDateFormatterCopyProperty(CFDateFormatterRef formatter, CFStringRef key) {
1093 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
1094 __CFGenericValidateType(key, CFStringGetTypeID());
1095 UErrorCode status = U_ZERO_ERROR;
1096 UChar ubuffer[BUFFER_SIZE];
1097
1098 if (kCFDateFormatterIsLenientKey == key) {
1099 if (formatter->_property._IsLenient) return CFRetain(formatter->_property._IsLenient);
1100 return CFRetain(udat_isLenient(formatter->_df) ? kCFBooleanTrue : kCFBooleanFalse);
1101 } else if (kCFDateFormatterDoesRelativeDateFormattingKey == key) {
1102 if (formatter->_property._DoesRelativeDateFormatting) return CFRetain(formatter->_property._DoesRelativeDateFormatting);
1103 return CFRetain(kCFBooleanFalse);
1104 } else if (kCFDateFormatterCalendarKey == key) {
1105 if (formatter->_property._Calendar) return CFRetain(formatter->_property._Calendar);
1106 CFCalendarRef calendar = (CFCalendarRef)CFLocaleGetValue(formatter->_locale, kCFLocaleCalendarKey);
1107 return calendar ? CFRetain(calendar) : NULL;
1108 } else if (kCFDateFormatterCalendarIdentifierKey == key) {
1109 if (formatter->_property._CalendarName) return CFRetain(formatter->_property._CalendarName);
1110 CFStringRef ident = (CFStringRef)CFLocaleGetValue(formatter->_locale, kCFLocaleCalendarIdentifierKey);
1111 return ident ? CFRetain(ident) : NULL;
1112 } else if (kCFDateFormatterTimeZoneKey == key) {
1113 if (formatter->_property._TwoDigitStartDate) return CFRetain(formatter->_property._TwoDigitStartDate);
1114 return CFRetain(formatter->_property._TimeZone);
1115 } else if (kCFDateFormatterDefaultFormatKey == key) {
1116 return formatter->_defformat ? CFRetain(formatter->_defformat) : NULL;
1117 } else if (kCFDateFormatterTwoDigitStartDateKey == key) {
1118 if (formatter->_property._TwoDigitStartDate) return CFRetain(formatter->_property._TwoDigitStartDate);
1119 UDate udate = udat_get2DigitYearStart(formatter->_df, &status);
1120 if (U_SUCCESS(status)) {
1121 CFAbsoluteTime at = (double)udate / 1000.0 - kCFAbsoluteTimeIntervalSince1970;
1122 return CFDateCreate(CFGetAllocator(formatter), at);
1123 }
1124 } else if (kCFDateFormatterDefaultDateKey == key) {
1125 return formatter->_property._DefaultDate ? CFRetain(formatter->_property._DefaultDate) : NULL;
1126 } else if (kCFDateFormatterGregorianStartDateKey == key) {
1127 if (formatter->_property._GregorianStartDate) return CFRetain(formatter->_property._GregorianStartDate);
1128 UCalendar *cal = (UCalendar *)udat_getCalendar(formatter->_df);
1129 UDate udate = ucal_getGregorianChange(cal, &status);
1130 if (U_SUCCESS(status)) {
1131 CFAbsoluteTime at = (double)udate / 1000.0 - kCFAbsoluteTimeIntervalSince1970;
1132 return CFDateCreate(CFGetAllocator(formatter), at);
1133 }
1134 } else if (kCFDateFormatterEraSymbolsKey == key) {
1135 if (formatter->_property._EraSymbols) return CFRetain(formatter->_property._EraSymbols);
1136 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_ERAS, 0);
1137 } else if (kCFDateFormatterLongEraSymbolsKey == key) {
1138 if (formatter->_property._LongEraSymbols) return CFRetain(formatter->_property._LongEraSymbols);
1139 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_ERA_NAMES, 0);
1140 } else if (kCFDateFormatterMonthSymbolsKey == key) {
1141 if (formatter->_property._MonthSymbols) return CFRetain(formatter->_property._MonthSymbols);
1142 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_MONTHS, 0);
1143 } else if (kCFDateFormatterShortMonthSymbolsKey == key) {
1144 if (formatter->_property._ShortMonthSymbols) return CFRetain(formatter->_property._ShortMonthSymbols);
1145 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_SHORT_MONTHS, 0);
1146 } else if (kCFDateFormatterVeryShortMonthSymbolsKey == key) {
1147 if (formatter->_property._VeryShortMonthSymbols) return CFRetain(formatter->_property._VeryShortMonthSymbols);
1148 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_NARROW_MONTHS, 0);
1149 } else if (kCFDateFormatterStandaloneMonthSymbolsKey == key) {
1150 if (formatter->_property._StandaloneMonthSymbols) return CFRetain(formatter->_property._StandaloneMonthSymbols);
1151 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_MONTHS, 0);
1152 } else if (kCFDateFormatterShortStandaloneMonthSymbolsKey == key) {
1153 if (formatter->_property._ShortStandaloneMonthSymbols) return CFRetain(formatter->_property._ShortStandaloneMonthSymbols);
1154 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_SHORT_MONTHS, 0);
1155 } else if (kCFDateFormatterVeryShortStandaloneMonthSymbolsKey == key) {
1156 if (formatter->_property._VeryShortStandaloneMonthSymbols) return CFRetain(formatter->_property._VeryShortStandaloneMonthSymbols);
1157 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_NARROW_MONTHS, 0);
1158 } else if (kCFDateFormatterWeekdaySymbolsKey == key) {
1159 if (formatter->_property._WeekdaySymbols) return CFRetain(formatter->_property._WeekdaySymbols);
1160 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_WEEKDAYS, 1);
1161 } else if (kCFDateFormatterShortWeekdaySymbolsKey == key) {
1162 if (formatter->_property._ShortWeekdaySymbols) return CFRetain(formatter->_property._ShortWeekdaySymbols);
1163 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_SHORT_WEEKDAYS, 1);
1164 } else if (kCFDateFormatterVeryShortWeekdaySymbolsKey == key) {
1165 if (formatter->_property._VeryShortWeekdaySymbols) return CFRetain(formatter->_property._VeryShortWeekdaySymbols);
1166 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_NARROW_WEEKDAYS, 1);
1167 } else if (kCFDateFormatterStandaloneWeekdaySymbolsKey == key) {
1168 if (formatter->_property._StandaloneWeekdaySymbols) return CFRetain(formatter->_property._StandaloneWeekdaySymbols);
1169 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_WEEKDAYS, 1);
1170 } else if (kCFDateFormatterShortStandaloneWeekdaySymbolsKey == key) {
1171 if (formatter->_property._ShortStandaloneWeekdaySymbols) return CFRetain(formatter->_property._ShortStandaloneWeekdaySymbols);
1172 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_SHORT_WEEKDAYS, 1);
1173 } else if (kCFDateFormatterVeryShortStandaloneWeekdaySymbolsKey == key) {
1174 if (formatter->_property._VeryShortStandaloneWeekdaySymbols) return CFRetain(formatter->_property._VeryShortStandaloneWeekdaySymbols);
1175 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_NARROW_WEEKDAYS, 1);
1176 } else if (kCFDateFormatterQuarterSymbolsKey == key) {
1177 if (formatter->_property._QuarterSymbols) return CFRetain(formatter->_property._QuarterSymbols);
1178 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_QUARTERS, 0);
1179 } else if (kCFDateFormatterShortQuarterSymbolsKey == key) {
1180 if (formatter->_property._ShortQuarterSymbols) return CFRetain(formatter->_property._ShortQuarterSymbols);
1181 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_SHORT_QUARTERS, 0);
1182 } else if (kCFDateFormatterStandaloneQuarterSymbolsKey == key) {
1183 if (formatter->_property._StandaloneQuarterSymbols) return CFRetain(formatter->_property._StandaloneQuarterSymbols);
1184 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_QUARTERS, 0);
1185 } else if (kCFDateFormatterShortStandaloneQuarterSymbolsKey == key) {
1186 if (formatter->_property._ShortStandaloneQuarterSymbols) return CFRetain(formatter->_property._ShortStandaloneQuarterSymbols);
1187 return __CFDateFormatterGetSymbolsArray(formatter->_df, UDAT_STANDALONE_SHORT_QUARTERS, 0);
1188 } else if (kCFDateFormatterAMSymbolKey == key) {
1189 if (formatter->_property._AMSymbol) return CFRetain(formatter->_property._AMSymbol);
1190 CFIndex cnt = udat_countSymbols(formatter->_df, UDAT_AM_PMS);
1191 if (2 <= cnt) {
1192 CFIndex ucnt = udat_getSymbols(formatter->_df, UDAT_AM_PMS, 0, ubuffer, BUFFER_SIZE, &status);
1193 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1194 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (UniChar *)ubuffer, ucnt);
1195 }
1196 }
1197 } else if (kCFDateFormatterPMSymbolKey == key) {
1198 if (formatter->_property._PMSymbol) return CFRetain(formatter->_property._PMSymbol);
1199 CFIndex cnt = udat_countSymbols(formatter->_df, UDAT_AM_PMS);
1200 if (2 <= cnt) {
1201 CFIndex ucnt = udat_getSymbols(formatter->_df, UDAT_AM_PMS, 1, ubuffer, BUFFER_SIZE, &status);
1202 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1203 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (UniChar *)ubuffer, ucnt);
1204 }
1205 }
1206 } else {
1207 CFAssert3(0, __kCFLogAssertion, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__, key, key);
1208 }
1209 return NULL;
1210 }
1211
1212