vfs: check userland buffers before reading them.
[haiku.git] / src / system / libroot / add-ons / icu / ICUTimeData.cpp
bloba0bfcfdbf12397c7ef1f1e55a6dfb7cd8a2a15f2
1 /*
2 * Copyright 2010-2011, Oliver Tappe, zooey@hirschkaefer.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "ICUTimeData.h"
9 #include <langinfo.h>
10 #include <string.h>
11 #include <strings.h>
13 #include <unicode/dtfmtsym.h>
14 #include <unicode/gregocal.h>
15 #include <unicode/smpdtfmt.h>
17 #include <AutoDeleter.h>
19 #include "ICUMessagesData.h"
21 namespace BPrivate {
22 namespace Libroot {
25 ICUTimeData::ICUTimeData(pthread_key_t tlsKey, struct lc_time_t& lcTimeInfo,
26 const ICUMessagesData& messagesData)
28 inherited(tlsKey),
29 fLCTimeInfo(lcTimeInfo),
30 fDataBridge(NULL),
31 fMessagesData(messagesData)
33 for (int i = 0; i < 12; ++i) {
34 fLCTimeInfo.mon[i] = fMon[i];
35 fLCTimeInfo.month[i] = fMonth[i];
36 fLCTimeInfo.alt_month[i] = fAltMonth[i];
38 for (int i = 0; i < 7; ++i) {
39 fLCTimeInfo.wday[i] = fWday[i];
40 fLCTimeInfo.weekday[i] = fWeekday[i];
42 fLCTimeInfo.X_fmt = fTimeFormat;
43 fLCTimeInfo.x_fmt = fDateFormat;
44 fLCTimeInfo.c_fmt = fDateTimeFormat;
45 fLCTimeInfo.am = fAm;
46 fLCTimeInfo.pm = fPm;
47 fLCTimeInfo.date_fmt = fDateTimeZoneFormat;
48 fLCTimeInfo.md_order = fMonthDayOrder;
49 fLCTimeInfo.ampm_fmt = fAmPmFormat;
53 ICUTimeData::~ICUTimeData()
58 void
59 ICUTimeData::Initialize(LocaleTimeDataBridge* dataBridge)
61 fDataBridge = dataBridge;
65 status_t
66 ICUTimeData::SetTo(const Locale& locale, const char* posixLocaleName)
68 status_t result = inherited::SetTo(locale, posixLocaleName);
69 if (result != B_OK)
70 return result;
72 UErrorCode icuStatus = U_ZERO_ERROR;
73 DateFormatSymbols formatSymbols(ICULocaleForStrings(), icuStatus);
74 if (!U_SUCCESS(icuStatus))
75 return B_UNSUPPORTED;
77 int count = 0;
78 const UnicodeString* strings = formatSymbols.getShortMonths(count);
79 result = _SetLCTimeEntries(strings, fMon[0], sizeof(fMon[0]), count, 12);
81 if (result == B_OK) {
82 strings = formatSymbols.getMonths(count);
83 result = _SetLCTimeEntries(strings, fMonth[0], sizeof(fMonth[0]), count,
84 12);
87 if (result == B_OK) {
88 strings = formatSymbols.getShortWeekdays(count);
89 if (count == 8 && strings[0].length() == 0) {
90 // ICUs weekday arrays are 1-based
91 strings++;
92 count = 7;
94 result
95 = _SetLCTimeEntries(strings, fWday[0], sizeof(fWday[0]), count, 7);
98 if (result == B_OK) {
99 strings = formatSymbols.getWeekdays(count);
100 if (count == 8 && strings[0].length() == 0) {
101 // ICUs weekday arrays are 1-based
102 strings++;
103 count = 7;
105 result = _SetLCTimeEntries(strings, fWeekday[0], sizeof(fWeekday[0]),
106 count, 7);
109 if (result == B_OK) {
110 try {
111 DateFormat* format = DateFormat::createTimeInstance(
112 DateFormat::kDefault, fLocale);
113 result = _SetLCTimePattern(format, fTimeFormat, sizeof(fTimeFormat));
114 delete format;
115 } catch(...) {
116 result = B_NO_MEMORY;
120 if (result == B_OK) {
121 try {
122 DateFormat* format = DateFormat::createDateInstance(
123 DateFormat::kDefault, fLocale);
124 result = _SetLCTimePattern(format, fDateFormat, sizeof(fDateFormat));
125 delete format;
126 } catch(...) {
127 result = B_NO_MEMORY;
131 if (result == B_OK) {
132 try {
133 DateFormat* format = DateFormat::createDateTimeInstance(
134 DateFormat::kFull, DateFormat::kFull, fLocale);
135 result = _SetLCTimePattern(format, fDateTimeFormat,
136 sizeof(fDateTimeFormat));
137 delete format;
138 } catch(...) {
139 result = B_NO_MEMORY;
143 if (result == B_OK) {
144 strings = formatSymbols.getAmPmStrings(count);
145 result = _SetLCTimeEntries(strings, fAm, sizeof(fAm), 1, 1);
146 if (result == B_OK)
147 result = _SetLCTimeEntries(&strings[1], fPm, sizeof(fPm), 1, 1);
150 if (result == B_OK) {
151 strings = formatSymbols.getMonths(count, DateFormatSymbols::STANDALONE,
152 DateFormatSymbols::WIDE);
153 result = _SetLCTimeEntries(strings, fAltMonth[0], sizeof(fAltMonth[0]),
154 count, 12);
157 strcpy(fAmPmFormat, fDataBridge->posixLCTimeInfo->ampm_fmt);
158 // ICU does not provide anything for this (and that makes sense, too)
160 return result;
164 status_t
165 ICUTimeData::SetToPosix()
167 status_t result = inherited::SetToPosix();
169 if (result == B_OK) {
170 for (int i = 0; i < 12; ++i) {
171 strcpy(fMon[i], fDataBridge->posixLCTimeInfo->mon[i]);
172 strcpy(fMonth[i], fDataBridge->posixLCTimeInfo->month[i]);
173 strcpy(fAltMonth[i], fDataBridge->posixLCTimeInfo->alt_month[i]);
175 for (int i = 0; i < 7; ++i) {
176 strcpy(fWday[i], fDataBridge->posixLCTimeInfo->wday[i]);
177 strcpy(fWeekday[i], fDataBridge->posixLCTimeInfo->weekday[i]);
179 strcpy(fTimeFormat, fDataBridge->posixLCTimeInfo->X_fmt);
180 strcpy(fDateFormat, fDataBridge->posixLCTimeInfo->x_fmt);
181 strcpy(fDateTimeFormat, fDataBridge->posixLCTimeInfo->c_fmt);
182 strcpy(fAm, fDataBridge->posixLCTimeInfo->am);
183 strcpy(fPm, fDataBridge->posixLCTimeInfo->pm);
184 strcpy(fDateTimeZoneFormat, fDataBridge->posixLCTimeInfo->date_fmt);
185 strcpy(fMonthDayOrder, fDataBridge->posixLCTimeInfo->md_order);
186 strcpy(fAmPmFormat, fDataBridge->posixLCTimeInfo->ampm_fmt);
189 return result;
193 const char*
194 ICUTimeData::GetLanginfo(int index)
196 switch(index) {
197 case D_T_FMT:
198 return fDateTimeFormat;
199 case D_FMT:
200 return fDateFormat;
201 case T_FMT:
202 return fTimeFormat;
203 case T_FMT_AMPM:
204 return fAmPmFormat;
205 case AM_STR:
206 return fAm;
207 case PM_STR:
208 return fPm;
210 case DAY_1:
211 case DAY_2:
212 case DAY_3:
213 case DAY_4:
214 case DAY_5:
215 case DAY_6:
216 case DAY_7:
217 return fWeekday[index - DAY_1];
219 case ABDAY_1:
220 case ABDAY_2:
221 case ABDAY_3:
222 case ABDAY_4:
223 case ABDAY_5:
224 case ABDAY_6:
225 case ABDAY_7:
226 return fWday[index - ABDAY_1];
228 case MON_1:
229 case MON_2:
230 case MON_3:
231 case MON_4:
232 case MON_5:
233 case MON_6:
234 case MON_7:
235 case MON_8:
236 case MON_9:
237 case MON_10:
238 case MON_11:
239 case MON_12:
240 return fMonth[index - MON_1];
242 case ABMON_1:
243 case ABMON_2:
244 case ABMON_3:
245 case ABMON_4:
246 case ABMON_5:
247 case ABMON_6:
248 case ABMON_7:
249 case ABMON_8:
250 case ABMON_9:
251 case ABMON_10:
252 case ABMON_11:
253 case ABMON_12:
254 return fMon[index - ABMON_1];
256 default:
257 return "";
262 const Locale&
263 ICUTimeData::ICULocaleForStrings() const
265 // check if the date strings should be taken from the messages-locale
266 // or from the time-locale (default)
267 UErrorCode icuStatus = U_ZERO_ERROR;
268 char stringsValue[16];
269 fLocale.getKeywordValue("strings", stringsValue, sizeof(stringsValue),
270 icuStatus);
271 if (U_SUCCESS(icuStatus) && strcasecmp(stringsValue, "messages") == 0)
272 return fMessagesData.ICULocale();
273 else
274 return fLocale;
278 status_t
279 ICUTimeData::_SetLCTimeEntries(const UnicodeString* strings, char* destination,
280 int entrySize, int count, int maxCount)
282 if (strings == NULL)
283 return B_ERROR;
285 status_t result = B_OK;
286 if (count > maxCount)
287 count = maxCount;
288 for (int32 i = 0; result == B_OK && i < count; ++i) {
289 result = _ConvertUnicodeStringToLocaleconvEntry(strings[i], destination,
290 entrySize);
291 destination += entrySize;
294 return result;
298 status_t
299 ICUTimeData::_SetLCTimePattern(DateFormat* format, char* destination,
300 int destinationSize)
302 SimpleDateFormat* simpleFormat = dynamic_cast<SimpleDateFormat*>(format);
303 if (!simpleFormat)
304 return B_BAD_TYPE;
306 // convert ICU-type pattern to posix (i.e. strftime()) format string
307 UnicodeString icuPattern;
308 simpleFormat->toPattern(icuPattern);
309 UnicodeString posixPattern;
310 if (icuPattern.length() > 0) {
311 UChar lastCharSeen = 0;
312 int lastCharCount = 1;
313 bool inSingleQuotes = false;
314 bool inDoubleQuotes = false;
315 // we loop one character past the end on purpose, which will result in a
316 // final -1 char to be processed, which in turn will let us handle the
317 // last character (via lastCharSeen)
318 for (int i = 0; i <= icuPattern.length(); ++i) {
319 UChar currChar = icuPattern.charAt(i);
320 if (lastCharSeen != 0 && currChar == lastCharSeen) {
321 lastCharCount++;
322 continue;
325 if (!inSingleQuotes && !inDoubleQuotes) {
326 switch (lastCharSeen) {
327 case L'a':
328 posixPattern.append(UnicodeString("%p", ""));
329 break;
330 case L'd':
331 if (lastCharCount == 2)
332 posixPattern.append(UnicodeString("%d", ""));
333 else
334 posixPattern.append(UnicodeString("%e", ""));
335 break;
336 case L'D':
337 posixPattern.append(UnicodeString("%j", ""));
338 break;
339 case L'c':
340 // fall through, to handle 'c' the same as 'e'
341 case L'e':
342 if (lastCharCount == 4)
343 posixPattern.append(UnicodeString("%A", ""));
344 else if (lastCharCount <= 2)
345 posixPattern.append(UnicodeString("%u", ""));
346 else
347 posixPattern.append(UnicodeString("%a", ""));
348 break;
349 case L'E':
350 if (lastCharCount == 4)
351 posixPattern.append(UnicodeString("%A", ""));
352 else
353 posixPattern.append(UnicodeString("%a", ""));
354 break;
355 case L'k':
356 // fall through, to handle 'k' the same as 'h'
357 case L'h':
358 if (lastCharCount == 2)
359 posixPattern.append(UnicodeString("%I", ""));
360 else
361 posixPattern.append(UnicodeString("%l", ""));
362 break;
363 case L'H':
364 if (lastCharCount == 2)
365 posixPattern.append(UnicodeString("%H", ""));
366 else
367 posixPattern.append(UnicodeString("%k", ""));
368 break;
369 case L'm':
370 posixPattern.append(UnicodeString("%M", ""));
371 break;
372 case L'L':
373 // fall through, to handle 'L' the same as 'M'
374 case L'M':
375 if (lastCharCount == 4)
376 posixPattern.append(UnicodeString("%B", ""));
377 else if (lastCharCount == 3)
378 posixPattern.append(UnicodeString("%b", ""));
379 else
380 posixPattern.append(UnicodeString("%m", ""));
381 break;
382 case L's':
383 posixPattern.append(UnicodeString("%S", ""));
384 break;
385 case L'w':
386 posixPattern.append(UnicodeString("%V", ""));
387 break;
388 case L'y':
389 if (lastCharCount == 2)
390 posixPattern.append(UnicodeString("%y", ""));
391 else
392 posixPattern.append(UnicodeString("%Y", ""));
393 break;
394 case L'Y':
395 posixPattern.append(UnicodeString("%G", ""));
396 break;
397 case L'z':
398 posixPattern.append(UnicodeString("%Z", ""));
399 break;
400 case L'Z':
401 posixPattern.append(UnicodeString("%z", ""));
402 break;
403 default:
404 if (lastCharSeen != 0)
405 posixPattern.append(lastCharSeen);
407 } else {
408 if (lastCharSeen != 0)
409 posixPattern.append(lastCharSeen);
412 if (currChar == L'"') {
413 inDoubleQuotes = !inDoubleQuotes;
414 lastCharSeen = 0;
415 } else if (currChar == L'\'') {
416 inSingleQuotes = !inSingleQuotes;
417 lastCharSeen = 0;
418 } else
419 lastCharSeen = currChar;
421 lastCharCount = 1;
425 return _ConvertUnicodeStringToLocaleconvEntry(posixPattern, destination,
426 destinationSize);
430 } // namespace Libroot
431 } // namespace BPrivate