vfs: check userland buffers before reading them.
[haiku.git] / src / kits / locale / DurationFormat.cpp
blobf00608a00b3498d2d1f0d0c9074277ea12b34133
1 /*
2 * Copyright 2010, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Oliver Tappe <zooey@hirschkaefer.de>
7 */
10 #include <unicode/uversion.h>
11 #include <DurationFormat.h>
13 #include <new>
15 #include <unicode/gregocal.h>
16 #include <unicode/utypes.h>
18 #include <Locale.h>
19 #include <LocaleRoster.h>
20 #include <TimeZone.h>
22 #include <TimeZonePrivate.h>
25 // maps our unit element to the corresponding ICU unit
26 static const UCalendarDateFields skUnitMap[] = {
27 UCAL_YEAR,
28 UCAL_MONTH,
29 UCAL_WEEK_OF_MONTH,
30 UCAL_DAY_OF_WEEK,
31 UCAL_HOUR_OF_DAY,
32 UCAL_MINUTE,
33 UCAL_SECOND,
37 BDurationFormat::BDurationFormat(const BLanguage& language,
38 const BFormattingConventions& conventions,
39 const BString& separator, const time_unit_style style)
41 Inherited(language, conventions),
42 fSeparator(separator),
43 fTimeUnitFormat(language, conventions, style)
45 UErrorCode icuStatus = U_ZERO_ERROR;
46 fCalendar = new GregorianCalendar(icuStatus);
47 if (fCalendar == NULL) {
48 fInitStatus = B_NO_MEMORY;
49 return;
54 BDurationFormat::BDurationFormat(const BString& separator,
55 const time_unit_style style)
57 Inherited(),
58 fSeparator(separator),
59 fTimeUnitFormat(style)
61 UErrorCode icuStatus = U_ZERO_ERROR;
62 fCalendar = new GregorianCalendar(icuStatus);
63 if (fCalendar == NULL) {
64 fInitStatus = B_NO_MEMORY;
65 return;
70 BDurationFormat::BDurationFormat(const BDurationFormat& other)
72 Inherited(other),
73 fSeparator(other.fSeparator),
74 fTimeUnitFormat(other.fTimeUnitFormat),
75 fCalendar(other.fCalendar != NULL
76 ? new GregorianCalendar(*other.fCalendar) : NULL)
78 if (fCalendar == NULL && other.fCalendar != NULL)
79 fInitStatus = B_NO_MEMORY;
83 BDurationFormat::~BDurationFormat()
85 delete fCalendar;
89 void
90 BDurationFormat::SetSeparator(const BString& separator)
92 fSeparator = separator;
96 status_t
97 BDurationFormat::SetTimeZone(const BTimeZone* timeZone)
99 if (fCalendar == NULL)
100 return B_NO_INIT;
102 BTimeZone::Private zonePrivate;
103 if (timeZone == NULL) {
104 BTimeZone defaultTimeZone;
105 status_t result
106 = BLocaleRoster::Default()->GetDefaultTimeZone(&defaultTimeZone);
107 if (result != B_OK)
108 return result;
109 zonePrivate.SetTo(&defaultTimeZone);
110 } else
111 zonePrivate.SetTo(timeZone);
113 TimeZone* icuTimeZone = zonePrivate.ICUTimeZone();
114 if (icuTimeZone != NULL)
115 fCalendar->setTimeZone(*icuTimeZone);
117 return B_OK;
121 status_t
122 BDurationFormat::Format(BString& buffer, const bigtime_t startValue,
123 const bigtime_t stopValue) const
125 UErrorCode icuStatus = U_ZERO_ERROR;
126 fCalendar->setTime((UDate)startValue / 1000, icuStatus);
127 if (!U_SUCCESS(icuStatus))
128 return B_ERROR;
130 UDate stop = (UDate)stopValue / 1000;
131 bool needSeparator = false;
132 for (int unit = 0; unit <= B_TIME_UNIT_LAST; ++unit) {
133 int delta
134 = fCalendar->fieldDifference(stop, skUnitMap[unit], icuStatus);
135 if (!U_SUCCESS(icuStatus))
136 return B_ERROR;
138 if (delta != 0) {
139 if (needSeparator)
140 buffer.Append(fSeparator);
141 else
142 needSeparator = true;
143 status_t status = fTimeUnitFormat.Format(buffer, delta,
144 (time_unit_element)unit);
145 if (status != B_OK)
146 return status;
150 return B_OK;