1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "i18n_memory_adapter.h"
17 #include "str_util.h"
18 #include "measure_format_impl.h"
19
20 using namespace OHOS::I18N;
21
MeasureFormatImpl(LocaleInfo & localeinfo,I18nStatus & status)22 MeasureFormatImpl::MeasureFormatImpl(LocaleInfo &localeinfo, I18nStatus &status)
23 {
24 if (localeinfo.GetId() == nullptr) {
25 status = I18nStatus::IERROR;
26 return;
27 }
28 locale = localeinfo;
29 pluralFormat = new (std::nothrow) PluralFormat(localeinfo, status);
30 if (status != I18nStatus::ISUCCESS || pluralFormat == nullptr) {
31 status = I18nStatus::IERROR;
32 return;
33 }
34 int numberFormatStatus = 0;
35 numberFormat = new (std::nothrow) NumberFormat(localeinfo, numberFormatStatus);
36 if (numberFormatStatus || numberFormat == nullptr) {
37 status = I18nStatus::IERROR;
38 return;
39 }
40 }
41
~MeasureFormatImpl()42 MeasureFormatImpl::~MeasureFormatImpl()
43 {
44 DeallocateMemory();
45 if (pluralFormat != nullptr) {
46 delete pluralFormat;
47 pluralFormat = nullptr;
48 }
49 if (numberFormat != nullptr) {
50 delete numberFormat;
51 numberFormat = nullptr;
52 }
53 }
54
Format(double num,std::string & unit,MeasureFormatType type,I18nStatus & status)55 std::string MeasureFormatImpl::Format(double num, std::string &unit, MeasureFormatType type, I18nStatus &status)
56 {
57 formattedDouble = num;
58 return FormatInner(false, unit, type, status);
59 }
60
Format(int num,std::string & unit,MeasureFormatType type,I18nStatus & status)61 std::string MeasureFormatImpl::Format(int num, std::string &unit, MeasureFormatType type, I18nStatus &status)
62 {
63 formattedInteger = num;
64 return FormatInner(true, unit, type, status);
65 }
66
FormatInner(bool isInteger,std::string & unit,MeasureFormatType type,I18nStatus & status)67 std::string MeasureFormatImpl::FormatInner(bool isInteger, std::string &unit, MeasureFormatType type,
68 I18nStatus &status)
69 {
70 int unitIndex = SearchUnits(unit, status);
71 if (status != I18nStatus::ISUCCESS) {
72 return "";
73 }
74 int pluralIndex = ComputePluralIndex(isInteger, status);
75 if (status != I18nStatus::ISUCCESS) {
76 return "";
77 }
78 std::string formattedUnit = ComputeFormattedUnit(unitIndex, pluralIndex, type, status);
79 if (status != I18nStatus::ISUCCESS) {
80 return "";
81 }
82 std::string formattedNumber = ComputeFormattedNumber(isInteger, status);
83 if (status != I18nStatus::ISUCCESS) {
84 return "";
85 }
86
87 char result[MAX_MEASURE_FORMAT_LENGTH];
88 int concatenate = 0;
89 if (isNumberFirst) {
90 concatenate = sprintf_s(result, MAX_MEASURE_FORMAT_LENGTH, pattern.c_str(), formattedNumber.c_str(),
91 formattedUnit.c_str());
92 } else {
93 concatenate = sprintf_s(result, MAX_MEASURE_FORMAT_LENGTH, pattern.c_str(), formattedUnit.c_str(),
94 formattedNumber.c_str());
95 }
96 if (concatenate < 0) {
97 status = I18nStatus::IERROR;
98 return "";
99 }
100 return result;
101 }
102
SearchUnits(std::string & target,I18nStatus & status)103 int MeasureFormatImpl::SearchUnits(std::string &target, I18nStatus &status)
104 {
105 for (int i = 0; i < unitCount; i++) {
106 if (target.compare(units[i]) == 0) {
107 return i;
108 }
109 }
110 status = I18nStatus::IERROR;
111 return -1;
112 }
113
ComputePluralIndex(bool isInteger,I18nStatus & status)114 int MeasureFormatImpl::ComputePluralIndex(bool isInteger, I18nStatus &status)
115 {
116 if (isInteger) {
117 return pluralFormat->GetPluralRuleIndex(formattedInteger, status);
118 } else {
119 return pluralFormat->GetPluralRuleIndex(formattedDouble, status);
120 }
121 }
122
ComputeFormattedUnit(int unitIndex,int pluralIndex,MeasureFormatType type,I18nStatus & status)123 std::string MeasureFormatImpl::ComputeFormattedUnit(int unitIndex, int pluralIndex, MeasureFormatType type,
124 I18nStatus &status)
125 {
126 int index = unitIndex * MEASURE_FORMAT_TYPE_NUM + (int)type;
127 std::string formattedUnit = formattedUnits[index][pluralIndex];
128 if (formattedUnit.length() != 0) {
129 return formattedUnit;
130 }
131 formattedUnit = formattedUnits[index][MEASURE_PLURAL_NUM - 1];
132 if (formattedUnit.length() != 0) {
133 return formattedUnit;
134 }
135 type = ConvertType(type, status);
136 if (status != I18nStatus::ISUCCESS) {
137 return "";
138 }
139 formattedUnit = ComputeFormattedUnit(unitIndex, pluralIndex, type, status);
140 if (status != I18nStatus::ISUCCESS) {
141 return "";
142 }
143 return formattedUnit;
144 }
145
ConvertType(MeasureFormatType type,I18nStatus & status)146 MeasureFormatType MeasureFormatImpl::ConvertType(MeasureFormatType type, I18nStatus &status)
147 {
148 if (type == MeasureFormatType::MEASURE_SHORT) {
149 return MeasureFormatType::MEASURE_MEDIUM;
150 } else if (type == MeasureFormatType::MEASURE_FULL) {
151 return MeasureFormatType::MEASURE_LONG;
152 } else if (type == MeasureFormatType::MEASURE_LONG) {
153 return MeasureFormatType::MEASURE_MEDIUM;
154 } else {
155 status = I18nStatus::IERROR;
156 return MeasureFormatType::MEASURE_MEDIUM;
157 }
158 }
159
ComputeFormattedNumber(bool isInteger,I18nStatus & status)160 std::string MeasureFormatImpl::ComputeFormattedNumber(bool isInteger, I18nStatus &status)
161 {
162 std::string formattedNumber;
163 int numberFormatStatus = 0;
164 if (isInteger) {
165 formattedNumber = numberFormat->Format(formattedInteger, NumberFormatType::DECIMAL, numberFormatStatus);
166 } else {
167 formattedNumber = numberFormat->Format(formattedDouble, NumberFormatType::DECIMAL, numberFormatStatus);
168 }
169 if (numberFormatStatus) {
170 status = I18nStatus::IERROR;
171 return "";
172 }
173 return formattedNumber;
174 }
175
Init(const DataResource & resource)176 bool MeasureFormatImpl::Init(const DataResource &resource)
177 {
178 if (units != nullptr || formattedUnits != nullptr) {
179 DeallocateMemory();
180 }
181 std::string unprocessedMeasureData = resource.GetString(DataResourceType::MEASURE_FORMAT_PATTERNS);
182 bool status = InitMeasureFormat(unprocessedMeasureData);
183 if (!status) {
184 return false;
185 }
186 return true;
187 }
188
InitMeasureFormat(std::string & unprocessedMeasureData)189 bool MeasureFormatImpl::InitMeasureFormat(std::string &unprocessedMeasureData)
190 {
191 int end = 0;
192 while (end < static_cast<int>(unprocessedMeasureData.length()) && unprocessedMeasureData[end] != PLURAL_SEP) {
193 end++;
194 }
195 unitCount = std::atoi(std::string(unprocessedMeasureData, 0, end).c_str());
196 int itemCount = MEASURE_BASE_ITEM_COUNT + unitCount * MEASURE_SINGLE_UNIT_COUNT;
197 std::string *items = new std::string[itemCount];
198 if (items == nullptr) {
199 return false;
200 }
201 Split(unprocessedMeasureData, items, itemCount, PLURAL_SEP);
202 // items[1] is unit list, such as h|min|kcal|time...
203 if (!ParseUnits(items[1])) {
204 delete[] items;
205 return false;
206 }
207 // items[2] is pattern
208 pattern = items[2];
209 // items[3] represent number and unit which comes first.
210 if (strcmp(items[3].c_str(), "#") == 0) {
211 isNumberFirst = true;
212 } else {
213 isNumberFirst = false;
214 }
215 formattedUnitCount = unitCount * MEASURE_FORMAT_TYPE_NUM;
216 if (!AllocaFormattedUnits()) {
217 delete[] items;
218 return false;
219 }
220 int itemStartIndex = MEASURE_BASE_ITEM_COUNT;
221 for (int i = 0; i < unitCount; i++) {
222 for (int j = 0; j < MEASURE_FORMAT_TYPE_NUM; j++) {
223 FillFormattedUnits(i, j, items, itemStartIndex);
224 itemStartIndex += MEASURE_PLURAL_NUM;
225 }
226 }
227 if (items != nullptr) {
228 delete[] items;
229 items = nullptr;
230 }
231 return true;
232 }
233
ParseUnits(std::string & unitsList)234 bool MeasureFormatImpl::ParseUnits(std::string &unitsList)
235 {
236 units = new std::string[unitCount];
237 if (units == nullptr) {
238 return false;
239 }
240 int begin = 0;
241 int end = 0;
242 int unitsLength = static_cast<int>(unitsList.length());
243 int count = 0;
244 while (count < unitCount) {
245 while (end < unitsLength && unitsList[end] != MEASURE_UNIT_SEP) {
246 end++;
247 }
248 if (end >= unitsLength) {
249 break;
250 }
251 units[count] = std::string(unitsList, begin, end - begin);
252 count++;
253 end++;
254 begin = end;
255 }
256 if (count < unitCount && end > begin) {
257 units[count] = std::string(unitsList, begin, end - begin);
258 }
259 if ((count + 1 != unitCount) || end < unitsLength) {
260 return false;
261 }
262 return true;
263 }
264
AllocaFormattedUnits()265 bool MeasureFormatImpl::AllocaFormattedUnits()
266 {
267 formattedUnits = new std::string *[formattedUnitCount];
268 if (formattedUnits == nullptr) {
269 return false;
270 }
271 for (int i = 0; i < formattedUnitCount; i++) {
272 formattedUnits[i] = new std::string[MEASURE_PLURAL_NUM];
273 if (formattedUnits[i] == nullptr) {
274 return false;
275 }
276 }
277 return true;
278 }
279
FillFormattedUnits(int unitIndex,int typeIndex,std::string * items,int itemStartIndex)280 void MeasureFormatImpl::FillFormattedUnits(int unitIndex, int typeIndex, std::string *items, int itemStartIndex)
281 {
282 for (int i = 0; i < MEASURE_PLURAL_NUM; i++) {
283 int index = unitIndex * MEASURE_FORMAT_TYPE_NUM + typeIndex;
284 formattedUnits[index][i] = items[itemStartIndex + i];
285 }
286 }
287
DeallocateMemory()288 void MeasureFormatImpl::DeallocateMemory()
289 {
290 if (units != nullptr) {
291 delete[] units;
292 units = nullptr;
293 }
294 if (formattedUnits != nullptr) {
295 for (int i = 0; i < formattedUnitCount; i++) {
296 if (formattedUnits[i] != nullptr) {
297 delete[] formattedUnits[i];
298 }
299 }
300 delete[] formattedUnits;
301 }
302 }