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 PluralFormat(localeinfo, status);
30 if (status != I18nStatus::ISUCCESS || pluralFormat == nullptr) {
31 status = I18nStatus::IERROR;
32 return;
33 }
34 int numberFormatStatus = 0;
35 numberFormat = new 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 < unprocessedMeasureData.length() && unprocessedMeasureData[end] != PLURAL_SEP) {
193 end++;
194 }
195 unitCount = std::stoi(std::string(unprocessedMeasureData, 0, end));
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 return false;
205 }
206 // items[2] is pattern
207 pattern = items[2];
208 // items[3] represent number and unit which comes first.
209 if (strcmp(items[3].c_str(), "#") == 0) {
210 isNumberFirst = true;
211 } else {
212 isNumberFirst = false;
213 }
214 formattedUnitCount = unitCount * MEASURE_FORMAT_TYPE_NUM;
215 if (!AllocaFormattedUnits()) {
216 return false;
217 }
218 int itemStartIndex = MEASURE_BASE_ITEM_COUNT;
219 for (int i = 0; i < unitCount; i++) {
220 for (int j = 0; j < MEASURE_FORMAT_TYPE_NUM; j++) {
221 FillFormattedUnits(i, j, items, itemStartIndex);
222 itemStartIndex += MEASURE_PLURAL_NUM;
223 }
224 }
225 if (items != nullptr) {
226 delete[] items;
227 items = nullptr;
228 }
229 return true;
230 }
231
ParseUnits(std::string & unitsList)232 bool MeasureFormatImpl::ParseUnits(std::string &unitsList)
233 {
234 units = new std::string[unitCount];
235 if (units == nullptr) {
236 return false;
237 }
238 int begin = 0;
239 int end = 0;
240 int unitsLength = unitsList.length();
241 int count = 0;
242 while (count < unitCount) {
243 while (end < unitsLength && unitsList[end] != MEASURE_UNIT_SEP) {
244 end++;
245 }
246 if (end >= unitsLength) {
247 break;
248 }
249 units[count] = std::string(unitsList, begin, end - begin);
250 count++;
251 end++;
252 begin = end;
253 }
254 if (count < unitCount && end > begin) {
255 units[count] = std::string(unitsList, begin, end - begin);
256 }
257 if ((count + 1 != unitCount) || end < unitsLength) {
258 return false;
259 }
260 return true;
261 }
262
AllocaFormattedUnits()263 bool MeasureFormatImpl::AllocaFormattedUnits()
264 {
265 formattedUnits = new std::string *[formattedUnitCount];
266 if (formattedUnits == nullptr) {
267 return false;
268 }
269 for (int i = 0; i < formattedUnitCount; i++) {
270 formattedUnits[i] = new std::string[MEASURE_PLURAL_NUM];
271 if (formattedUnits[i] == nullptr) {
272 return false;
273 }
274 }
275 return true;
276 }
277
FillFormattedUnits(int unitIndex,int typeIndex,std::string * items,int itemStartIndex)278 void MeasureFormatImpl::FillFormattedUnits(int unitIndex, int typeIndex, std::string *items, int itemStartIndex)
279 {
280 for (int i = 0; i < MEASURE_PLURAL_NUM; i++) {
281 int index = unitIndex * MEASURE_FORMAT_TYPE_NUM + typeIndex;
282 formattedUnits[index][i] = items[itemStartIndex + i];
283 }
284 }
285
DeallocateMemory()286 void MeasureFormatImpl::DeallocateMemory()
287 {
288 if (units != nullptr) {
289 delete[] units;
290 units = nullptr;
291 }
292 if (formattedUnits != nullptr) {
293 for (int i = 0; i < formattedUnitCount; i++) {
294 if (formattedUnits[i] != nullptr) {
295 delete[] formattedUnits[i];
296 }
297 }
298 delete[] formattedUnits;
299 }
300 }