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