• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }