]> git.saurik.com Git - apple/cf.git/blob - CFDateFormatter.c
CF-476.17.tar.gz
[apple/cf.git] / CFDateFormatter.c
1 /*
2 * Copyright (c) 2008 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 /* CFDateFormatter.c
24 Copyright 2002-2003, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
26 */
27
28 #include <CoreFoundation/CFDateFormatter.h>
29 #include <CoreFoundation/CFDate.h>
30 #include <CoreFoundation/CFTimeZone.h>
31 #include <CoreFoundation/CFCalendar.h>
32 #include <CoreFoundation/CFNumber.h>
33 #include "CFInternal.h"
34 #include <unicode/udat.h>
35 #include <math.h>
36 #include <float.h>
37
38 extern UCalendar *__CFCalendarCreateUCalendar(CFStringRef calendarID, CFStringRef localeID, CFTimeZoneRef tz);
39 static void __CFDateFormatterCustomize(CFDateFormatterRef formatter);
40
41 extern const CFStringRef kCFDateFormatterCalendarIdentifier;
42
43 #define BUFFER_SIZE 768
44
45 struct __CFDateFormatter {
46 CFRuntimeBase _base;
47 UDateFormat *_df;
48 CFLocaleRef _locale;
49 CFDateFormatterStyle _timeStyle;
50 CFDateFormatterStyle _dateStyle;
51 CFStringRef _format;
52 CFStringRef _defformat;
53 CFStringRef _calendarName;
54 CFTimeZoneRef _tz;
55 CFDateRef _defaultDate;
56 };
57
58 static CFStringRef __CFDateFormatterCopyDescription(CFTypeRef cf) {
59 CFDateFormatterRef formatter = (CFDateFormatterRef)cf;
60 return CFStringCreateWithFormat(CFGetAllocator(formatter), NULL, CFSTR("<CFDateFormatter %p [%p]>"), cf, CFGetAllocator(formatter));
61 }
62
63 static void __CFDateFormatterDeallocate(CFTypeRef cf) {
64 CFDateFormatterRef formatter = (CFDateFormatterRef)cf;
65 if (formatter->_df) udat_close(formatter->_df);
66 if (formatter->_locale) CFRelease(formatter->_locale);
67 if (formatter->_format) CFRelease(formatter->_format);
68 if (formatter->_defformat) CFRelease(formatter->_defformat);
69 if (formatter->_calendarName) CFRelease(formatter->_calendarName);
70 if (formatter->_tz) CFRelease(formatter->_tz);
71 if (formatter->_defaultDate) CFRelease(formatter->_defaultDate);
72 }
73
74 static CFTypeID __kCFDateFormatterTypeID = _kCFRuntimeNotATypeID;
75
76 static const CFRuntimeClass __CFDateFormatterClass = {
77 0,
78 "CFDateFormatter",
79 NULL, // init
80 NULL, // copy
81 __CFDateFormatterDeallocate,
82 NULL,
83 NULL,
84 NULL, //
85 __CFDateFormatterCopyDescription
86 };
87
88 static void __CFDateFormatterInitialize(void) {
89 __kCFDateFormatterTypeID = _CFRuntimeRegisterClass(&__CFDateFormatterClass);
90 }
91
92 CFTypeID CFDateFormatterGetTypeID(void) {
93 if (_kCFRuntimeNotATypeID == __kCFDateFormatterTypeID) __CFDateFormatterInitialize();
94 return __kCFDateFormatterTypeID;
95 }
96
97 CFDateFormatterRef CFDateFormatterCreate(CFAllocatorRef allocator, CFLocaleRef locale, CFDateFormatterStyle dateStyle, CFDateFormatterStyle timeStyle) {
98 struct __CFDateFormatter *memory;
99 uint32_t size = sizeof(struct __CFDateFormatter) - sizeof(CFRuntimeBase);
100 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
101 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
102 if (locale) __CFGenericValidateType(locale, CFLocaleGetTypeID());
103 memory = (struct __CFDateFormatter *)_CFRuntimeCreateInstance(allocator, CFDateFormatterGetTypeID(), size, NULL);
104 if (NULL == memory) {
105 return NULL;
106 }
107 memory->_df = NULL;
108 memory->_locale = NULL;
109 memory->_format = NULL;
110 memory->_defformat = NULL;
111 memory->_calendarName = NULL;
112 memory->_tz = NULL;
113 memory->_defaultDate = NULL;
114 if (NULL == locale) locale = CFLocaleGetSystem();
115 memory->_dateStyle = dateStyle;
116 memory->_timeStyle = timeStyle;
117 int32_t udstyle, utstyle;
118 switch (dateStyle) {
119 case kCFDateFormatterNoStyle: udstyle = UDAT_NONE; break;
120 case kCFDateFormatterShortStyle: udstyle = UDAT_SHORT; break;
121 case kCFDateFormatterMediumStyle: udstyle = UDAT_MEDIUM; break;
122 case kCFDateFormatterLongStyle: udstyle = UDAT_LONG; break;
123 case kCFDateFormatterFullStyle: udstyle = UDAT_FULL; break;
124 default:
125 CFAssert2(0, __kCFLogAssertion, "%s(): unknown date style %d", __PRETTY_FUNCTION__, dateStyle);
126 udstyle = UDAT_MEDIUM;
127 memory->_dateStyle = kCFDateFormatterMediumStyle;
128 break;
129 }
130 switch (timeStyle) {
131 case kCFDateFormatterNoStyle: utstyle = UDAT_NONE; break;
132 case kCFDateFormatterShortStyle: utstyle = UDAT_SHORT; break;
133 case kCFDateFormatterMediumStyle: utstyle = UDAT_MEDIUM; break;
134 case kCFDateFormatterLongStyle: utstyle = UDAT_LONG; break;
135 case kCFDateFormatterFullStyle: utstyle = UDAT_FULL; break;
136 default:
137 CFAssert2(0, __kCFLogAssertion, "%s(): unknown time style %d", __PRETTY_FUNCTION__, timeStyle);
138 utstyle = UDAT_MEDIUM;
139 memory->_timeStyle = kCFDateFormatterMediumStyle;
140 break;
141 }
142 CFStringRef localeName = locale ? CFLocaleGetIdentifier(locale) : CFSTR("");
143 char buffer[BUFFER_SIZE];
144 const char *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII);
145 if (NULL == cstr) {
146 if (CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer;
147 }
148 if (NULL == cstr) {
149 CFRelease(memory);
150 return NULL;
151 }
152 UChar ubuffer[BUFFER_SIZE];
153 memory->_tz = CFTimeZoneCopyDefault();
154 CFStringRef tznam = CFTimeZoneGetName(memory->_tz);
155 CFIndex cnt = CFStringGetLength(tznam);
156 if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE;
157 CFStringGetCharacters(tznam, CFRangeMake(0, cnt), (UniChar *)ubuffer);
158 UErrorCode status = U_ZERO_ERROR;
159 memory->_df = udat_open((UDateFormatStyle)utstyle, (UDateFormatStyle)udstyle, cstr, ubuffer, cnt, NULL, 0, &status);
160 CFAssert2(memory->_df, __kCFLogAssertion, "%s(): error (%d) creating date formatter", __PRETTY_FUNCTION__, status);
161 if (NULL == memory->_df) {
162 CFRelease(memory->_tz);
163 CFRelease(memory);
164 return NULL;
165 }
166 udat_setLenient(memory->_df, 0);
167 if (kCFDateFormatterNoStyle == dateStyle && kCFDateFormatterNoStyle == timeStyle) {
168 udat_applyPattern(memory->_df, false, NULL, 0);
169 }
170 CFTypeRef calident = CFLocaleGetValue(locale, kCFLocaleCalendarIdentifier);
171 if (calident && CFEqual(calident, kCFGregorianCalendar)) {
172 status = U_ZERO_ERROR;
173 udat_set2DigitYearStart(memory->_df, -631152000000.0, &status); // 1950-01-01 00:00:00 GMT
174 }
175 memory->_locale = locale ? CFLocaleCreateCopy(allocator, locale) : CFLocaleGetSystem();
176 __CFDateFormatterCustomize(memory);
177 status = U_ZERO_ERROR;
178 int32_t ret = udat_toPattern(memory->_df, false, ubuffer, BUFFER_SIZE, &status);
179 if (U_SUCCESS(status) && ret <= BUFFER_SIZE) {
180 memory->_format = CFStringCreateWithCharacters(allocator, (const UniChar *)ubuffer, ret);
181 }
182 memory->_defformat = memory->_format ? (CFStringRef)CFRetain(memory->_format) : NULL;
183 return (CFDateFormatterRef)memory;
184 }
185
186 extern CFDictionaryRef __CFLocaleGetPrefs(CFLocaleRef locale);
187
188 static void __substituteFormatStringFromPrefsDF(CFDateFormatterRef formatter, bool doTime) {
189 CFIndex formatStyle = doTime ? formatter->_timeStyle : formatter->_dateStyle;
190 CFStringRef prefName = doTime ? CFSTR("AppleICUTimeFormatStrings") : CFSTR("AppleICUDateFormatStrings");
191 if (kCFDateFormatterNoStyle != formatStyle) {
192 CFStringRef pref = NULL;
193 CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale);
194 CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, prefName) : NULL;
195 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) {
196 CFStringRef key;
197 switch (formatStyle) {
198 case kCFDateFormatterShortStyle: key = CFSTR("1"); break;
199 case kCFDateFormatterMediumStyle: key = CFSTR("2"); break;
200 case kCFDateFormatterLongStyle: key = CFSTR("3"); break;
201 case kCFDateFormatterFullStyle: key = CFSTR("4"); break;
202 default: key = CFSTR("0"); break;
203 }
204 pref = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)metapref, key);
205 }
206 if (NULL != pref && CFGetTypeID(pref) == CFStringGetTypeID()) {
207 int32_t icustyle = UDAT_NONE;
208 switch (formatStyle) {
209 case kCFDateFormatterShortStyle: icustyle = UDAT_SHORT; break;
210 case kCFDateFormatterMediumStyle: icustyle = UDAT_MEDIUM; break;
211 case kCFDateFormatterLongStyle: icustyle = UDAT_LONG; break;
212 case kCFDateFormatterFullStyle: icustyle = UDAT_FULL; break;
213 }
214 CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale);
215 char buffer[BUFFER_SIZE];
216 const char *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII);
217 if (NULL == cstr) {
218 if (CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer;
219 }
220 UErrorCode status = U_ZERO_ERROR;
221 UDateFormat *df = udat_open((UDateFormatStyle)(doTime ? icustyle : UDAT_NONE), (UDateFormatStyle)(doTime ? UDAT_NONE : icustyle), cstr, NULL, 0, NULL, 0, &status);
222 if (NULL != df) {
223 UChar ubuffer[BUFFER_SIZE];
224 status = U_ZERO_ERROR;
225 int32_t date_len = udat_toPattern(df, false, ubuffer, BUFFER_SIZE, &status);
226 if (U_SUCCESS(status) && date_len <= BUFFER_SIZE) {
227 CFStringRef dateString = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)ubuffer, date_len);
228 status = U_ZERO_ERROR;
229 int32_t formatter_len = udat_toPattern(formatter->_df, false, ubuffer, BUFFER_SIZE, &status);
230 if (U_SUCCESS(status) && formatter_len <= BUFFER_SIZE) {
231 CFMutableStringRef formatString = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
232 CFStringAppendCharacters(formatString, (UniChar *)ubuffer, formatter_len);
233 // find dateString inside formatString, substitute the pref in that range
234 CFRange result;
235 if (CFStringFindWithOptions(formatString, dateString, CFRangeMake(0, formatter_len), 0, &result)) {
236 CFStringReplace(formatString, result, pref);
237 int32_t new_len = CFStringGetLength(formatString);
238 STACK_BUFFER_DECL(UChar, new_buffer, new_len);
239 const UChar *new_ustr = (UChar *)CFStringGetCharactersPtr(formatString);
240 if (NULL == new_ustr) {
241 CFStringGetCharacters(formatString, CFRangeMake(0, new_len), (UniChar *)new_buffer);
242 new_ustr = new_buffer;
243 }
244 status = U_ZERO_ERROR;
245 // udat_applyPattern(formatter->_df, false, new_ustr, new_len, &status);
246 udat_applyPattern(formatter->_df, false, new_ustr, new_len);
247 }
248 CFRelease(formatString);
249 }
250 CFRelease(dateString);
251 }
252 udat_close(df);
253 }
254 }
255 }
256 }
257
258 static void __CFDateFormatterApplySymbolPrefs(const void *key, const void *value, void *context) {
259 if (CFGetTypeID(key) == CFStringGetTypeID() && CFGetTypeID(value) == CFArrayGetTypeID()) {
260 CFDateFormatterRef formatter = (CFDateFormatterRef)context;
261 UDateFormatSymbolType sym = (UDateFormatSymbolType)CFStringGetIntValue((CFStringRef)key);
262 CFArrayRef array = (CFArrayRef)value;
263 CFIndex idx, cnt = CFArrayGetCount(array);
264 for (idx = 0; idx < cnt; idx++) {
265 CFStringRef item = (CFStringRef)CFArrayGetValueAtIndex(array, idx);
266 if (CFGetTypeID(item) != CFStringGetTypeID()) continue;
267 CFIndex item_cnt = CFStringGetLength(item);
268 STACK_BUFFER_DECL(UChar, item_buffer, __CFMin(BUFFER_SIZE, item_cnt));
269 UChar *item_ustr = (UChar *)CFStringGetCharactersPtr(item);
270 if (NULL == item_ustr) {
271 item_cnt = __CFMin(BUFFER_SIZE, item_cnt);
272 CFStringGetCharacters(item, CFRangeMake(0, item_cnt), (UniChar *)item_buffer);
273 item_ustr = item_buffer;
274 }
275 UErrorCode status = U_ZERO_ERROR;
276 udat_setSymbols(formatter->_df, sym, idx, item_ustr, item_cnt, &status);
277 }
278 }
279 }
280
281 static void __CFDateFormatterCustomize(CFDateFormatterRef formatter) {
282 __substituteFormatStringFromPrefsDF(formatter, false);
283 __substituteFormatStringFromPrefsDF(formatter, true);
284 CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale);
285 CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUDateTimeSymbols")) : NULL;
286 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) {
287 CFDictionaryApplyFunction((CFDictionaryRef)metapref, __CFDateFormatterApplySymbolPrefs, formatter);
288 }
289 }
290
291 CFLocaleRef CFDateFormatterGetLocale(CFDateFormatterRef formatter) {
292 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
293 return formatter->_locale;
294 }
295
296 CFDateFormatterStyle CFDateFormatterGetDateStyle(CFDateFormatterRef formatter) {
297 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
298 return formatter->_dateStyle;
299 }
300
301 CFDateFormatterStyle CFDateFormatterGetTimeStyle(CFDateFormatterRef formatter) {
302 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
303 return formatter->_timeStyle;
304 }
305
306 CFStringRef CFDateFormatterGetFormat(CFDateFormatterRef formatter) {
307 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
308 return formatter->_format;
309 }
310
311 void CFDateFormatterSetFormat(CFDateFormatterRef formatter, CFStringRef formatString) {
312 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
313 __CFGenericValidateType(formatString, CFStringGetTypeID());
314 CFIndex cnt = CFStringGetLength(formatString);
315 CFAssert1(cnt <= 1024, __kCFLogAssertion, "%s(): format string too long", __PRETTY_FUNCTION__);
316 if (formatter->_format != formatString && cnt <= 1024) {
317 STACK_BUFFER_DECL(UChar, ubuffer, cnt);
318 const UChar *ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)formatString);
319 if (NULL == ustr) {
320 CFStringGetCharacters(formatString, CFRangeMake(0, cnt), (UniChar *)ubuffer);
321 ustr = ubuffer;
322 }
323 UErrorCode status = U_ZERO_ERROR;
324 // udat_applyPattern(formatter->_df, false, ustr, cnt, &status);
325 udat_applyPattern(formatter->_df, false, ustr, cnt);
326 if (U_SUCCESS(status)) {
327 if (formatter->_format) CFRelease(formatter->_format);
328 formatter->_format = (CFStringRef)CFStringCreateCopy(CFGetAllocator(formatter), formatString);
329 }
330 }
331 }
332
333 CFStringRef CFDateFormatterCreateStringWithDate(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFDateRef date) {
334 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
335 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
336 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
337 __CFGenericValidateType(date, CFDateGetTypeID());
338 return CFDateFormatterCreateStringWithAbsoluteTime(allocator, formatter, CFDateGetAbsoluteTime(date));
339 }
340
341 CFStringRef CFDateFormatterCreateStringWithAbsoluteTime(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFAbsoluteTime at) {
342 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
343 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
344 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
345 UChar *ustr = NULL, ubuffer[BUFFER_SIZE];
346 UErrorCode status = U_ZERO_ERROR;
347 CFIndex used, cnt = BUFFER_SIZE;
348 UDate ud = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0 + 0.5;
349 used = udat_format(formatter->_df, ud, ubuffer, cnt, NULL, &status);
350 if (status == U_BUFFER_OVERFLOW_ERROR || cnt < used) {
351 cnt = used + 1;
352 ustr = (UChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UChar) * cnt, 0);
353 status = U_ZERO_ERROR;
354 used = udat_format(formatter->_df, ud, ustr, cnt, NULL, &status);
355 }
356 CFStringRef string = NULL;
357 if (U_SUCCESS(status)) {
358 string = CFStringCreateWithCharacters(allocator, (const UniChar *)(ustr ? ustr : ubuffer), used);
359 }
360 if (ustr) CFAllocatorDeallocate(kCFAllocatorSystemDefault, ustr);
361 return string;
362 }
363
364 CFDateRef CFDateFormatterCreateDateFromString(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFStringRef string, CFRange *rangep) {
365 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
366 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
367 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
368 __CFGenericValidateType(string, CFStringGetTypeID());
369 CFAbsoluteTime at;
370 if (CFDateFormatterGetAbsoluteTimeFromString(formatter, string, rangep, &at)) {
371 return CFDateCreate(allocator, at);
372 }
373 return NULL;
374 }
375
376 Boolean CFDateFormatterGetAbsoluteTimeFromString(CFDateFormatterRef formatter, CFStringRef string, CFRange *rangep, CFAbsoluteTime *atp) {
377 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
378 __CFGenericValidateType(string, CFStringGetTypeID());
379 CFRange range = {0, 0};
380 if (rangep) {
381 range = *rangep;
382 } else {
383 range.length = CFStringGetLength(string);
384 }
385 if (1024 < range.length) range.length = 1024;
386 const UChar *ustr = (UChar *)CFStringGetCharactersPtr(string);
387 STACK_BUFFER_DECL(UChar, ubuffer, (NULL == ustr) ? range.length : 1);
388 if (NULL == ustr) {
389 CFStringGetCharacters(string, range, (UniChar *)ubuffer);
390 ustr = ubuffer;
391 } else {
392 ustr += range.location;
393 }
394 UDate udate;
395 int32_t dpos = 0;
396 UErrorCode status = U_ZERO_ERROR;
397 if (formatter->_defaultDate) {
398 CFAbsoluteTime at = CFDateGetAbsoluteTime(formatter->_defaultDate);
399 udate = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0;
400 UDateFormat *df2 = udat_clone(formatter->_df, &status);
401 UCalendar *cal2 = (UCalendar *)udat_getCalendar(df2);
402 ucal_setMillis(cal2, udate, &status);
403 udat_parseCalendar(formatter->_df, cal2, ustr, range.length, &dpos, &status);
404 udate = ucal_getMillis(cal2, &status);
405 udat_close(df2);
406 } else {
407 udate = udat_parse(formatter->_df, ustr, range.length, &dpos, &status);
408 }
409 if (rangep) rangep->length = dpos;
410 if (U_FAILURE(status)) {
411 return false;
412 }
413 if (atp) {
414 *atp = (double)udate / 1000.0 - kCFAbsoluteTimeIntervalSince1970;
415 }
416 return true;
417 }
418
419 #define SET_SYMBOLS_ARRAY(ICU_CODE, INDEX_BASE) \
420 __CFGenericValidateType(value, CFArrayGetTypeID()); \
421 CFArrayRef array = (CFArrayRef)value; \
422 CFIndex idx, cnt = CFArrayGetCount(array); \
423 for (idx = 0; idx < cnt; idx++) { \
424 CFStringRef item = (CFStringRef)CFArrayGetValueAtIndex(array, idx); \
425 __CFGenericValidateType(item, CFStringGetTypeID()); \
426 CFIndex item_cnt = CFStringGetLength(item); \
427 STACK_BUFFER_DECL(UChar, item_buffer, __CFMin(BUFFER_SIZE, item_cnt)); \
428 UChar *item_ustr = (UChar *)CFStringGetCharactersPtr(item); \
429 if (NULL == item_ustr) { \
430 item_cnt = __CFMin(BUFFER_SIZE, item_cnt); \
431 CFStringGetCharacters(item, CFRangeMake(0, item_cnt), (UniChar *)item_buffer); \
432 item_ustr = item_buffer; \
433 } \
434 status = U_ZERO_ERROR; \
435 udat_setSymbols(formatter->_df, ICU_CODE, idx + INDEX_BASE, item_ustr, item_cnt, &status); \
436 }
437
438 void CFDateFormatterSetProperty(CFDateFormatterRef formatter, CFStringRef key, CFTypeRef value) {
439 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
440 __CFGenericValidateType(key, CFStringGetTypeID());
441 UErrorCode status = U_ZERO_ERROR;
442 UChar ubuffer[BUFFER_SIZE];
443
444 if (kCFDateFormatterIsLenient == key) {
445 __CFGenericValidateType(value, CFBooleanGetTypeID());
446 udat_setLenient(formatter->_df, (kCFBooleanTrue == value));
447 } else if (kCFDateFormatterCalendar == key) {
448 __CFGenericValidateType(value, CFCalendarGetTypeID());
449 CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale);
450 CFDictionaryRef components = CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault, localeName);
451 CFMutableDictionaryRef mcomponents = CFDictionaryCreateMutableCopy(kCFAllocatorSystemDefault, 0, components);
452 CFDictionarySetValue(mcomponents, kCFLocaleCalendarIdentifier, CFCalendarGetIdentifier((CFCalendarRef)value));
453 localeName = CFLocaleCreateLocaleIdentifierFromComponents(kCFAllocatorSystemDefault, mcomponents);
454 CFRelease(mcomponents);
455 CFRelease(components);
456 CFLocaleRef newLocale = CFLocaleCreate(CFGetAllocator(formatter->_locale), localeName);
457 CFRelease(localeName);
458 CFRelease(formatter->_locale);
459 formatter->_locale = newLocale;
460 UCalendar *cal = __CFCalendarCreateUCalendar(NULL, CFLocaleGetIdentifier(formatter->_locale), formatter->_tz);
461 if (cal) udat_setCalendar(formatter->_df, cal);
462 if (cal) ucal_close(cal);
463 } else if (kCFDateFormatterCalendarIdentifier == key || kCFDateFormatterCalendarName == key) {
464 __CFGenericValidateType(value, CFStringGetTypeID());
465 CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale);
466 CFDictionaryRef components = CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault, localeName);
467 CFMutableDictionaryRef mcomponents = CFDictionaryCreateMutableCopy(kCFAllocatorSystemDefault, 0, components);
468 CFDictionarySetValue(mcomponents, kCFLocaleCalendarIdentifier, value);
469 localeName = CFLocaleCreateLocaleIdentifierFromComponents(kCFAllocatorSystemDefault, mcomponents);
470 CFRelease(mcomponents);
471 CFRelease(components);
472 CFLocaleRef newLocale = CFLocaleCreate(CFGetAllocator(formatter->_locale), localeName);
473 CFRelease(localeName);
474 CFRelease(formatter->_locale);
475 formatter->_locale = newLocale;
476 UCalendar *cal = __CFCalendarCreateUCalendar(NULL, CFLocaleGetIdentifier(formatter->_locale), formatter->_tz);
477 if (cal) udat_setCalendar(formatter->_df, cal);
478 if (cal) ucal_close(cal);
479 } else if (kCFDateFormatterTimeZone == key) {
480 __CFGenericValidateType(value, CFTimeZoneGetTypeID());
481 CFTimeZoneRef old = formatter->_tz;
482 formatter->_tz = value ? (CFTimeZoneRef)CFRetain(value) : CFTimeZoneCopyDefault();
483 if (old) CFRelease(old);
484 CFStringRef tznam = CFTimeZoneGetName(formatter->_tz);
485 UCalendar *cal = (UCalendar *)udat_getCalendar(formatter->_df);
486 CFIndex ucnt = CFStringGetLength(tznam);
487 if (BUFFER_SIZE < ucnt) ucnt = BUFFER_SIZE;
488 CFStringGetCharacters(tznam, CFRangeMake(0, ucnt), (UniChar *)ubuffer);
489 ucal_setTimeZone(cal, ubuffer, ucnt, &status);
490 } else if (kCFDateFormatterDefaultFormat == key) {
491 // read-only attribute
492 } else if (kCFDateFormatterTwoDigitStartDate == key) {
493 __CFGenericValidateType(value, CFDateGetTypeID());
494 CFAbsoluteTime at = CFDateGetAbsoluteTime((CFDateRef)value);
495 UDate udate = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0;
496 udat_set2DigitYearStart(formatter->_df, udate, &status);
497 } else if (kCFDateFormatterDefaultDate == key) {
498 __CFGenericValidateType(value, CFDateGetTypeID());
499 CFDateRef old = formatter->_defaultDate;
500 formatter->_defaultDate = value ? (CFDateRef)CFRetain(value) : NULL;
501 if (old) CFRelease(old);
502 } else if (kCFDateFormatterEraSymbols == key) {
503 SET_SYMBOLS_ARRAY(UDAT_ERAS, 0)
504 } else if (kCFDateFormatterMonthSymbols == key) {
505 SET_SYMBOLS_ARRAY(UDAT_MONTHS, 0)
506 } else if (kCFDateFormatterShortMonthSymbols == key) {
507 SET_SYMBOLS_ARRAY(UDAT_SHORT_MONTHS, 0)
508 } else if (kCFDateFormatterWeekdaySymbols == key) {
509 SET_SYMBOLS_ARRAY(UDAT_WEEKDAYS, 1)
510 } else if (kCFDateFormatterShortWeekdaySymbols == key) {
511 SET_SYMBOLS_ARRAY(UDAT_SHORT_WEEKDAYS, 1)
512 } else if (kCFDateFormatterAMSymbol == key) {
513 __CFGenericValidateType(value, CFStringGetTypeID());
514 CFIndex item_cnt = CFStringGetLength((CFStringRef)value);
515 STACK_BUFFER_DECL(UChar, item_buffer, __CFMin(BUFFER_SIZE, item_cnt));
516 UChar *item_ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)value);
517 if (NULL == item_ustr) {
518 item_cnt = __CFMin(BUFFER_SIZE, item_cnt);
519 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, item_cnt), (UniChar *)item_buffer);
520 item_ustr = item_buffer;
521 }
522 udat_setSymbols(formatter->_df, UDAT_AM_PMS, 0, item_ustr, item_cnt, &status);
523 } else if (kCFDateFormatterPMSymbol == key) {
524 __CFGenericValidateType(value, CFStringGetTypeID());
525 CFIndex item_cnt = CFStringGetLength((CFStringRef)value);
526 STACK_BUFFER_DECL(UChar, item_buffer, __CFMin(BUFFER_SIZE, item_cnt));
527 UChar *item_ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)value);
528 if (NULL == item_ustr) {
529 item_cnt = __CFMin(BUFFER_SIZE, item_cnt);
530 CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, item_cnt), (UniChar *)item_buffer);
531 item_ustr = item_buffer;
532 }
533 udat_setSymbols(formatter->_df, UDAT_AM_PMS, 1, item_ustr, item_cnt, &status);
534 } else if (kCFDateFormatterGregorianStartDate == key) {
535 __CFGenericValidateType(value, CFDateGetTypeID());
536 CFAbsoluteTime at = CFDateGetAbsoluteTime((CFDateRef)value);
537 UDate udate = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0;
538 UCalendar *cal = (UCalendar *)udat_getCalendar(formatter->_df);
539 ucal_setGregorianChange(cal, udate, &status);
540 } else if (kCFDateFormatterLongEraSymbols == key) {
541 SET_SYMBOLS_ARRAY(UDAT_ERA_NAMES, 0)
542 } else if (kCFDateFormatterVeryShortMonthSymbols == key) {
543 SET_SYMBOLS_ARRAY(UDAT_NARROW_MONTHS, 0)
544 } else if (kCFDateFormatterStandaloneMonthSymbols == key) {
545 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_MONTHS, 0)
546 } else if (kCFDateFormatterShortStandaloneMonthSymbols == key) {
547 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_MONTHS, 0)
548 } else if (kCFDateFormatterVeryShortStandaloneMonthSymbols == key) {
549 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_NARROW_MONTHS, 0)
550 } else if (kCFDateFormatterVeryShortWeekdaySymbols == key) {
551 SET_SYMBOLS_ARRAY(UDAT_NARROW_WEEKDAYS, 1)
552 } else if (kCFDateFormatterStandaloneWeekdaySymbols == key) {
553 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_WEEKDAYS, 1)
554 } else if (kCFDateFormatterShortStandaloneWeekdaySymbols == key) {
555 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_WEEKDAYS, 1)
556 } else if (kCFDateFormatterVeryShortStandaloneWeekdaySymbols == key) {
557 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_NARROW_WEEKDAYS, 1)
558 } else if (kCFDateFormatterQuarterSymbols == key) {
559 SET_SYMBOLS_ARRAY(UDAT_QUARTERS, 1)
560 } else if (kCFDateFormatterShortQuarterSymbols == key) {
561 SET_SYMBOLS_ARRAY(UDAT_SHORT_QUARTERS, 1)
562 } else if (kCFDateFormatterStandaloneQuarterSymbols == key) {
563 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_QUARTERS, 1)
564 } else if (kCFDateFormatterShortStandaloneQuarterSymbols == key) {
565 SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_QUARTERS, 1)
566 } else {
567 CFAssert3(0, __kCFLogAssertion, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__, key, key);
568 }
569 }
570
571 #define GET_SYMBOLS_ARRAY(ICU_CODE, INDEX_BASE) \
572 CFIndex idx, cnt = udat_countSymbols(formatter->_df, ICU_CODE) - INDEX_BASE; \
573 STACK_BUFFER_DECL(CFStringRef, strings, cnt); \
574 for (idx = 0; idx < cnt; idx++) { \
575 CFStringRef str = NULL; \
576 status = U_ZERO_ERROR; \
577 CFIndex ucnt = udat_getSymbols(formatter->_df, ICU_CODE, idx + INDEX_BASE, ubuffer, BUFFER_SIZE, &status); \
578 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { \
579 str = CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, ucnt); \
580 } \
581 strings[idx] = !str ? (CFStringRef)CFRetain(CFSTR("<error>")) : str; \
582 } \
583 CFArrayRef array = CFArrayCreate(CFGetAllocator(formatter), (const void **)strings, cnt, &kCFTypeArrayCallBacks); \
584 while (cnt--) { \
585 CFRelease(strings[cnt]); \
586 } \
587 return array;
588
589 CFTypeRef CFDateFormatterCopyProperty(CFDateFormatterRef formatter, CFStringRef key) {
590 __CFGenericValidateType(formatter, CFDateFormatterGetTypeID());
591 __CFGenericValidateType(key, CFStringGetTypeID());
592 UErrorCode status = U_ZERO_ERROR;
593 UChar ubuffer[BUFFER_SIZE];
594
595 if (kCFDateFormatterIsLenient == key) {
596 return CFRetain(udat_isLenient(formatter->_df) ? kCFBooleanTrue : kCFBooleanFalse);
597 } else if (kCFDateFormatterCalendar == key) {
598 CFCalendarRef calendar = (CFCalendarRef)CFLocaleGetValue(formatter->_locale, kCFLocaleCalendar);
599 return calendar ? CFRetain(calendar) : NULL;
600 } else if (kCFDateFormatterCalendarIdentifier == key || kCFDateFormatterCalendarName == key) {
601 CFStringRef ident = (CFStringRef)CFLocaleGetValue(formatter->_locale, kCFLocaleCalendarIdentifier);
602 return ident ? CFRetain(ident) : NULL;
603 } else if (kCFDateFormatterTimeZone == key) {
604 return CFRetain(formatter->_tz);
605 } else if (kCFDateFormatterDefaultFormat == key) {
606 return formatter->_defformat ? CFRetain(formatter->_defformat) : NULL;
607 } else if (kCFDateFormatterTwoDigitStartDate == key) {
608 UDate udate = udat_get2DigitYearStart(formatter->_df, &status);
609 if (U_SUCCESS(status)) {
610 CFAbsoluteTime at = (double)udate / 1000.0 - kCFAbsoluteTimeIntervalSince1970;
611 return CFDateCreate(CFGetAllocator(formatter), at);
612 }
613 } else if (kCFDateFormatterDefaultDate == key) {
614 return formatter->_defaultDate ? CFRetain(formatter->_defaultDate) : NULL;
615 } else if (kCFDateFormatterEraSymbols == key) {
616 GET_SYMBOLS_ARRAY(UDAT_ERAS, 0)
617 } else if (kCFDateFormatterMonthSymbols == key) {
618 GET_SYMBOLS_ARRAY(UDAT_MONTHS, 0)
619 } else if (kCFDateFormatterShortMonthSymbols == key) {
620 GET_SYMBOLS_ARRAY(UDAT_SHORT_MONTHS, 0)
621 } else if (kCFDateFormatterWeekdaySymbols == key) {
622 GET_SYMBOLS_ARRAY(UDAT_WEEKDAYS, 1)
623 } else if (kCFDateFormatterShortWeekdaySymbols == key) {
624 GET_SYMBOLS_ARRAY(UDAT_SHORT_WEEKDAYS, 1)
625 } else if (kCFDateFormatterAMSymbol == key) {
626 CFIndex cnt = udat_countSymbols(formatter->_df, UDAT_AM_PMS);
627 if (2 <= cnt) {
628 CFIndex ucnt = udat_getSymbols(formatter->_df, UDAT_AM_PMS, 0, ubuffer, BUFFER_SIZE, &status);
629 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
630 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (UniChar *)ubuffer, ucnt);
631 }
632 }
633 } else if (kCFDateFormatterPMSymbol == key) {
634 CFIndex cnt = udat_countSymbols(formatter->_df, UDAT_AM_PMS);
635 if (2 <= cnt) {
636 CFIndex ucnt = udat_getSymbols(formatter->_df, UDAT_AM_PMS, 1, ubuffer, BUFFER_SIZE, &status);
637 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
638 return CFStringCreateWithCharacters(CFGetAllocator(formatter), (UniChar *)ubuffer, ucnt);
639 }
640 }
641 } else if (kCFDateFormatterGregorianStartDate == key) {
642 UCalendar *cal = (UCalendar *)udat_getCalendar(formatter->_df);
643 UDate udate = ucal_getGregorianChange(cal, &status);
644 if (U_SUCCESS(status)) {
645 CFAbsoluteTime at = (double)udate / 1000.0 - kCFAbsoluteTimeIntervalSince1970;
646 return CFDateCreate(CFGetAllocator(formatter), at);
647 }
648 } else if (kCFDateFormatterLongEraSymbols == key) {
649 GET_SYMBOLS_ARRAY(UDAT_ERA_NAMES, 0)
650 } else if (kCFDateFormatterVeryShortMonthSymbols == key) {
651 GET_SYMBOLS_ARRAY(UDAT_NARROW_MONTHS, 0)
652 } else if (kCFDateFormatterStandaloneMonthSymbols == key) {
653 GET_SYMBOLS_ARRAY(UDAT_STANDALONE_MONTHS, 0)
654 } else if (kCFDateFormatterShortStandaloneMonthSymbols == key) {
655 GET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_MONTHS, 0)
656 } else if (kCFDateFormatterVeryShortStandaloneMonthSymbols == key) {
657 GET_SYMBOLS_ARRAY(UDAT_STANDALONE_NARROW_MONTHS, 0)
658 } else if (kCFDateFormatterVeryShortWeekdaySymbols == key) {
659 GET_SYMBOLS_ARRAY(UDAT_NARROW_WEEKDAYS, 1)
660 } else if (kCFDateFormatterStandaloneWeekdaySymbols == key) {
661 GET_SYMBOLS_ARRAY(UDAT_STANDALONE_WEEKDAYS, 1)
662 } else if (kCFDateFormatterShortStandaloneWeekdaySymbols == key) {
663 GET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_WEEKDAYS, 1)
664 } else if (kCFDateFormatterVeryShortStandaloneWeekdaySymbols == key) {
665 GET_SYMBOLS_ARRAY(UDAT_STANDALONE_NARROW_WEEKDAYS, 1)
666 } else if (kCFDateFormatterQuarterSymbols == key) {
667 GET_SYMBOLS_ARRAY(UDAT_QUARTERS, 1)
668 } else if (kCFDateFormatterShortQuarterSymbols == key) {
669 GET_SYMBOLS_ARRAY(UDAT_SHORT_QUARTERS, 1)
670 } else if (kCFDateFormatterStandaloneQuarterSymbols == key) {
671 GET_SYMBOLS_ARRAY(UDAT_STANDALONE_QUARTERS, 1)
672 } else if (kCFDateFormatterShortStandaloneQuarterSymbols == key) {
673 GET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_QUARTERS, 1)
674 } else {
675 CFAssert3(0, __kCFLogAssertion, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__, key, key);
676 }
677 return NULL;
678 }
679
680 CONST_STRING_DECL(kCFDateFormatterIsLenient, "kCFDateFormatterIsLenient")
681 CONST_STRING_DECL(kCFDateFormatterTimeZone, "kCFDateFormatterTimeZone")
682 CONST_STRING_DECL(kCFDateFormatterCalendarName, "kCFDateFormatterCalendarName")
683 CONST_STRING_DECL(kCFDateFormatterCalendarIdentifier, "kCFDateFormatterCalendarIdentifier")
684 CONST_STRING_DECL(kCFDateFormatterCalendar, "kCFDateFormatterCalendar")
685 CONST_STRING_DECL(kCFDateFormatterDefaultFormat, "kCFDateFormatterDefaultFormat")
686
687 CONST_STRING_DECL(kCFDateFormatterTwoDigitStartDate, "kCFDateFormatterTwoDigitStartDate")
688 CONST_STRING_DECL(kCFDateFormatterDefaultDate, "kCFDateFormatterDefaultDate")
689 CONST_STRING_DECL(kCFDateFormatterEraSymbols, "kCFDateFormatterEraSymbols")
690 CONST_STRING_DECL(kCFDateFormatterMonthSymbols, "kCFDateFormatterMonthSymbols")
691 CONST_STRING_DECL(kCFDateFormatterShortMonthSymbols, "kCFDateFormatterShortMonthSymbols")
692 CONST_STRING_DECL(kCFDateFormatterWeekdaySymbols, "kCFDateFormatterWeekdaySymbols")
693 CONST_STRING_DECL(kCFDateFormatterShortWeekdaySymbols, "kCFDateFormatterShortWeekdaySymbols")
694 CONST_STRING_DECL(kCFDateFormatterAMSymbol, "kCFDateFormatterAMSymbol")
695 CONST_STRING_DECL(kCFDateFormatterPMSymbol, "kCFDateFormatterPMSymbol")
696
697 CONST_STRING_DECL(kCFDateFormatterLongEraSymbols, "kCFDateFormatterLongEraSymbols")
698 CONST_STRING_DECL(kCFDateFormatterVeryShortMonthSymbols, "kCFDateFormatterVeryShortMonthSymbols")
699 CONST_STRING_DECL(kCFDateFormatterStandaloneMonthSymbols, "kCFDateFormatterStandaloneMonthSymbols")
700 CONST_STRING_DECL(kCFDateFormatterShortStandaloneMonthSymbols, "kCFDateFormatterShortStandaloneMonthSymbols")
701 CONST_STRING_DECL(kCFDateFormatterVeryShortStandaloneMonthSymbols, "kCFDateFormatterVeryShortStandaloneMonthSymbols")
702 CONST_STRING_DECL(kCFDateFormatterVeryShortWeekdaySymbols, "kCFDateFormatterVeryShortWeekdaySymbols")
703 CONST_STRING_DECL(kCFDateFormatterStandaloneWeekdaySymbols, "kCFDateFormatterStandaloneWeekdaySymbols")
704 CONST_STRING_DECL(kCFDateFormatterShortStandaloneWeekdaySymbols, "kCFDateFormatterShortStandaloneWeekdaySymbols")
705 CONST_STRING_DECL(kCFDateFormatterVeryShortStandaloneWeekdaySymbols, "kCFDateFormatterVeryShortStandaloneWeekdaySymbols")
706 CONST_STRING_DECL(kCFDateFormatterQuarterSymbols, "kCFDateFormatterQuarterSymbols")
707 CONST_STRING_DECL(kCFDateFormatterShortQuarterSymbols, "kCFDateFormatterShortQuarterSymbols")
708 CONST_STRING_DECL(kCFDateFormatterStandaloneQuarterSymbols, "kCFDateFormatterStandaloneQuarterSymbols")
709 CONST_STRING_DECL(kCFDateFormatterShortStandaloneQuarterSymbols, "kCFDateFormatterShortStandaloneQuarterSymbols")
710 CONST_STRING_DECL(kCFDateFormatterGregorianStartDate, "kCFDateFormatterGregorianStartDate")
711
712 #undef BUFFER_SIZE
713