• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 "number_format_impl.h"
17 #include "i18n_memory_adapter.h"
18 #include "number_data.h"
19 #include "str_util.h"
20 
21 using namespace OHOS::I18N;
22 
ConvertSignAndNum(const char * content,int len,NumberData * data) const23 std::string NumberFormatImpl::ConvertSignAndNum(const char *content, int len, NumberData *data) const
24 {
25     if (content == nullptr) {
26         return "";
27     }
28     std::string strContent = content;
29     int off = 0;
30     for (int i = 0; i < len; i++) {
31         switch (content[i]) {
32             case NumberData::NUMBER_DECIMAL:
33                 off = ReplaceAndCountOff(strContent, i + off, data->decimal, off);
34                 break;
35             case NumberData::NUMBER_GROUPSIGN:
36                 off = ReplaceAndCountOff(strContent, i + off, data->group, off);
37                 break;
38             case NumberData::NUMBER_PERCENT:
39                 off = ReplaceAndCountOff(strContent, i + off, data->percent, off);
40                 break;
41             default:
42                 break;
43         }
44         if (defaultData->isNative) {
45             off = ConvertNum(strContent, content[i], data, i, off);
46         }
47     }
48     return strContent;
49 }
50 
ConvertNum(std::string & strContent,char currentChar,const NumberData * data,int index,int off) const51 int NumberFormatImpl::ConvertNum(std::string &strContent, char currentChar,
52     const NumberData *data, int index, int off) const
53 {
54     std::string numStr = "0123456789";
55     size_t charPos = numStr.find(currentChar);
56     return (charPos != std::string::npos) ?
57         ReplaceAndCountOff(strContent, index + off, data->nativeNums[charPos].c_str(), off) : off;
58 }
59 
NumberFormatImpl(LocaleInfo & locale,int & status)60 NumberFormatImpl::NumberFormatImpl(LocaleInfo &locale, int &status)
61 {
62     if (locale.GetId() == nullptr) {
63         status = IERROR;
64         return;
65     }
66     mLocale = locale;
67 }
68 
Init(const DataResource & resource)69 bool NumberFormatImpl::Init(const DataResource &resource)
70 {
71     std::string unprocessedNumberFormat;
72     resource.GetString(DataResourceType::NUMBER_FORMAT, unprocessedNumberFormat);
73     std::string unprocessedNumberDigit;
74     resource.GetString(DataResourceType::NUMBER_DIGIT, unprocessedNumberDigit);
75     std::string split[NUM_PATTERN_SIZE];
76     Split(unprocessedNumberFormat, split, NUM_PATTERN_SIZE, NUM_PATTERN_SEP);
77     std::string decSign = split[NUM_DEC_SIGN_INDEX];
78     std::string groupSign = split[NUM_GROUP_SIGN_INDEX];
79     std::string perSign = split[NUM_PERCENT_SIGN_INDEX];
80     const char *numberDigits = mLocale.GetExtension("nu");
81     if (numberDigits != nullptr) {
82         std::string numebrSystemFormat;
83         NumberData::GetNumberingSystem(numberDigits, numebrSystemFormat, unprocessedNumberDigit);
84         std::string temp[NUM_PATTERN_SIZE];
85         Split(numebrSystemFormat, temp, NUM_PATTERN_SIZE, NUM_PATTERN_SEP);
86         decSign = temp[NUM_DEC_SIGN_INDEX];
87         groupSign = temp[NUM_GROUP_SIGN_INDEX];
88         perSign = temp[NUM_PERCENT_SIGN_INDEX];
89     }
90     std::string origin = split[NUM_PERCENT_PAT_INDEX];
91     const char *pat = split[NUM_PAT_INDEX].c_str();
92     size_t size = origin.size();
93     std::string adjust = origin;
94     // strip "0x80 0xe2 0x8f" these three bytes in pat
95     if (size >= 3 && // check the last 3 character
96         (static_cast<unsigned char>(origin.at(size - 1)) == 0x8f) && // check whether the last one is 0x8f
97         (static_cast<unsigned char>(origin.at(size - 2)) == 0x80) && // check whether the index of size - 2 is 0x80
98         (static_cast<unsigned char>(origin.at(size - 3)) == 0xe2)) { // check whether the index of size - 3 is 0xe2
99         adjust = std::string(origin, 0, size - 3); // strip the last 3 chars
100     }
101     const char *percentPat = adjust.c_str();
102     defaultData = new (std::nothrow) NumberData(pat, percentPat, decSign, groupSign, perSign);
103     if (defaultData == nullptr) {
104         return false;
105     }
106     if (unprocessedNumberDigit != "") {
107         std::string splitDigit[NUM_DIGIT_SIZE];
108         Split(unprocessedNumberDigit, splitDigit, NUM_DIGIT_SIZE, NUM_DIGIT_SEP);
109         defaultData->SetNumSystem(splitDigit, NUM_DIGIT_SIZE);
110     }
111     // set minus sign
112     std::string minus;
113     resource.GetString(DataResourceType::MINUS_SIGN, minus);
114     defaultData->SetMinusSign(minus);
115     return true;
116 }
117 
118 
~NumberFormatImpl()119 NumberFormatImpl::~NumberFormatImpl()
120 {
121     if (defaultData != nullptr) {
122         delete defaultData;
123         defaultData = nullptr;
124     }
125 }
126 
InnerFormat(double num,bool hasDec,bool isShowGroup,bool isPercent,int & status) const127 std::string NumberFormatImpl::InnerFormat(double num, bool hasDec, bool isShowGroup, bool isPercent,
128     int &status) const
129 {
130     if (defaultData == nullptr) {
131         return "";
132     }
133     char buff[NUMBER_MAX] = { 0 };
134     bool isPercentDefault = isPercent && (defaultData->style.minDecimalLength < 0);
135     double adjustNum = (num < 0) ? (-1 * num) : num;
136     int len = isPercentDefault ? static_cast<int>(sprintf_s(buff, NUMBER_MAX, "%.f", adjustNum)) :
137         static_cast<int>(sprintf_s(buff, NUMBER_MAX, defaultData->style.numFormat, adjustNum));
138     // convert decimal to char and format
139     if (len < 0) {
140         status = IERROR;
141         return "";
142     }
143     char *decimalNum = strchr(buff, NumberData::NUMBER_DECIMAL);
144     int decLen = (decimalNum == nullptr) ? 0 : strlen(decimalNum);
145     int lastLen = isShowGroup ? (len + CountGroupNum(len - decLen, defaultData->style.isTwoGroup)) : len;
146     char *result = reinterpret_cast<char *>(I18nMalloc(lastLen + 1));
147     if (result == nullptr) {
148         status = IERROR;
149         return "";
150     }
151     result[lastLen] = '\0';
152     bool adjustHasDec = isPercentDefault ? false : hasDec;
153     if (isShowGroup) {
154         char *resultAndContent[] = { result, buff };
155         int lengths[] = { lastLen, len, defaultData->style.isTwoGroup };
156         AddGroup(resultAndContent, lengths, decimalNum, adjustHasDec, decLen);
157     } else {
158         errno_t rc = strcpy_s(result, lastLen + 1, buff);
159         if (rc != EOK) {
160             I18nFree(static_cast<void *>(result));
161             return "";
162         }
163     }
164     // del more zero
165     lastLen = DelMoreZero(decLen, lastLen, adjustHasDec, result);
166     // if percent
167     if (isPercent && !DealWithPercent(buff, result, status, defaultData->style, lastLen)) {
168         I18nFree(static_cast<void *>(result));
169         return "";
170     }
171     // if have native number to convert
172     std::string outStr = ConvertSignAndNum(result, lastLen, defaultData);
173     I18nFree(static_cast<void *>(result));
174     if (num < 0) {
175         outStr.insert(0, defaultData->GetMinusSign());
176     }
177     return outStr;
178 }
179 
DealWithPercent(char * buff,char * & result,int & status,StyleData & style,int & lastLen) const180 bool NumberFormatImpl::DealWithPercent(char *buff, char *&result, int &status, StyleData &style, int &lastLen) const
181 {
182     if (style.entireFormat != nullptr) {
183         bool cleanRet = CleanCharArray(buff, NUMBER_MAX);
184         if (!cleanRet) {
185             return false;
186         }
187         int len = static_cast<int>(sprintf_s(buff, NUMBER_MAX, style.entireFormat, result));
188         if (len < 0) {
189             status = IERROR;
190             I18nFree(static_cast<void *>(result));
191             return false;
192         }
193         char *perResult = reinterpret_cast<char *>(I18nMalloc(len + 1));
194         if (perResult == nullptr) {
195             return false;
196         }
197         errno_t rc = strcpy_s(perResult, len + 1, buff);
198         if (rc != EOK) {
199             I18nFree(static_cast<void *>(perResult));
200             return false;
201         }
202         perResult[len] = '\0';
203         lastLen = len;
204         I18nFree(static_cast<void *>(result));
205         result = perResult;
206         perResult = nullptr;
207     }
208     return true;
209 }
210 
211 
DelMoreZero(int decLen,int lastLen,bool hasDec,char * & result) const212 int NumberFormatImpl::DelMoreZero(int decLen, int lastLen, bool hasDec, char *&result) const
213 {
214     int num = 0;
215     if (decLen > 1) {
216         int delNum = decLen - 1;
217         num = DelZero(result, lastLen, delNum, true);
218     }
219     // delete more char
220     if ((maxDecimalLength != NO_SET) && (maxDecimalLength < decLen - 1 - num)) {
221         int delNum = decLen - 1 - num - maxDecimalLength;
222         num = num + DelZero(result, lastLen - num, delNum, false);
223     }
224     // fill zero to min
225     if (hasDec && (minDecimalLength != NO_SET) && (minDecimalLength > decLen - 1 - num)) {
226         if (decLen - 1 - num < 0) {
227             int add = minDecimalLength + 1;
228             char *tempResult = FillMinDecimal(result, lastLen - num, add, false);
229             if (result != nullptr) {
230 #ifdef I18N_PRODUCT
231                 (void)OhosFree(static_cast<void *>(result));
232 #else
233                 (void)free(result);
234 #endif
235             }
236             result = tempResult;
237             num = num - add;
238         } else {
239             int add = minDecimalLength - decLen + num + 1;
240             char *tempResult = FillMinDecimal(result, lastLen - num, add, true);
241             if (result != nullptr) {
242 #ifdef I18N_PRODUCT
243                 (void)OhosFree(static_cast<void *>(result));
244 #else
245                 (void)free(result);
246 #endif
247             }
248             result = tempResult;
249             num = num - add;
250         }
251     }
252     return lastLen - num;
253 }
254 
CheckStatus(const errno_t rc,int & status) const255 void NumberFormatImpl::CheckStatus(const errno_t rc, int &status) const
256 {
257     if (rc != EOK) {
258         status = IERROR;
259     }
260 }
261 
CountGroupNum(int intLength,bool isTwoGrouped) const262 int NumberFormatImpl::CountGroupNum(int intLength, bool isTwoGrouped) const
263 {
264     int groupNum;
265     if (!isTwoGrouped) {
266         groupNum = static_cast<int>(intLength / NumberData::NUMBER_GROUP);
267         if ((intLength % NumberData::NUMBER_GROUP) == 0) {
268             --groupNum;
269         }
270     } else {
271         if (intLength <= NumberData::NUMBER_GROUP) {
272             return 0;
273         }
274         intLength -= NumberData::NUMBER_GROUP;
275         groupNum = 1 + static_cast<int>(intLength / NumberData::TWO_GROUP);
276         if ((intLength % NumberData::TWO_GROUP) == 0) {
277             --groupNum;
278         }
279     }
280     return groupNum;
281 }
282 
AddGroup(char * targetAndSource[],const int len[],const char * decimal,bool hasDec,int decLen) const283 void NumberFormatImpl::AddGroup(char *targetAndSource[], const int len[], const char *decimal,
284     bool hasDec, int decLen) const
285 {
286     // The len array must have at least 3 elements and the targetAndSource array
287     // must have at least 2 elements.
288     if ((targetAndSource == nullptr) || (len == nullptr)) {
289         return;
290     }
291     char *target = targetAndSource[0]; // use array to store target and source string, first is target string
292     int targetLen = len[0]; // use array to store target length and source length, first is target length
293     char *source = targetAndSource[1]; // use array to store target and source string, second is source string
294     int sourceLen = len[1]; // use array to store target length and source length, second is source length
295     int isTwoGroup = len[2]; // 2 is the index of group info
296     int intLen = sourceLen - decLen;
297     int addIndex = 0;
298     for (int i = 0; (i < intLen) && (addIndex < targetLen); i++, addIndex++) {
299         int index = intLen - i;
300         // ADD GROUP SIGN
301         if (isTwoGroup == 0) {
302             if ((index % NumberData::NUMBER_GROUP == 0) && (i != 0)) {
303                 target[addIndex] = ',';
304                 addIndex++;
305             }
306             target[addIndex] = source[i];
307         } else {
308             if ((index == NumberData::NUMBER_GROUP) && (i != 0)) {
309                 target[addIndex] = ',';
310                 addIndex++;
311                 target[addIndex] = source[i];
312             } else if ((index > NumberData::NUMBER_GROUP) &&
313                 ((index - NumberData::NUMBER_GROUP) % NumberData::TWO_GROUP == 0) && (i != 0)) {
314                 target[addIndex] = ',';
315                 addIndex++;
316                 target[addIndex] = source[i];
317             } else {
318                 target[addIndex] = source[i];
319             }
320         }
321     }
322     if (decLen > 0) {
323         target[addIndex] = hasDec ? '.' : '\0';
324         for (int j = 1; (j < decLen) && (addIndex < targetLen); j++) {
325             target[addIndex + j] = hasDec ? decimal[j] : '\0';
326         }
327     }
328 }
329 
DelZero(char * target,int len,int delNum,bool onlyZero) const330 int NumberFormatImpl::DelZero(char *target, int len, int delNum, bool onlyZero) const
331 {
332     int num = 0;
333     for (int i = len - 1; (i > len - delNum - 1) && (i >= 0); i--) {
334         if ((target[i] != '0') && onlyZero) {
335             break;
336         }
337         target[i] = '\0';
338         num++;
339         if ((i - 1 > 0) && (target[i - 1] == '.')) {
340             target[i - 1] = '\0';
341             num++;
342             break;
343         }
344     }
345     return num;
346 }
347 
Format(double num,NumberFormatType type,int & status) const348 std::string NumberFormatImpl::Format(double num, NumberFormatType type, int &status) const
349 {
350     if (defaultData == nullptr) {
351         status = IERROR;
352         return "";
353     }
354     if (type == PERCENT) { // percent,the decimal needs to be multiplied by 100.
355         return InnerFormat(num * 100, true, true, true, status);
356     } else {
357         return InnerFormat(num, true, true, false, status);
358     }
359 }
360 
Format(int num,int & status) const361 std::string NumberFormatImpl::Format(int num, int &status) const
362 {
363     if (defaultData == nullptr) {
364         status = IERROR;
365         return "";
366     }
367     return InnerFormat(num, false, true, false, status);
368 }
369 
FormatNoGroup(double num,NumberFormatType type,int & status) const370 std::string NumberFormatImpl::FormatNoGroup(double num, NumberFormatType type, int &status) const
371 {
372     if (defaultData == nullptr) {
373         status = IERROR;
374         return "";
375     }
376     if (type == PERCENT) { // percent,the decimal needs to be multiplied by 100.
377         return InnerFormat(num * 100, true, false, true, status);
378     } else {
379         return InnerFormat(num, true, false, false, status);
380     }
381 }
382 
FormatNoGroup(int num,int & status) const383 std::string NumberFormatImpl::FormatNoGroup(int num, int &status) const
384 {
385     if (defaultData == nullptr) {
386         status = IERROR;
387         return "";
388     }
389     return InnerFormat(num, false, false, false, status);
390 }
391 
SetMaxDecimalLength(int length)392 bool NumberFormatImpl::SetMaxDecimalLength(int length)
393 {
394     if (defaultData == nullptr) {
395         return false;
396     }
397     int adjustValue = (length < 0) ? -1 : length;
398     if ((minDecimalLength >= 0) && (minDecimalLength > adjustValue)) {
399         minDecimalLength = adjustValue;
400         defaultData->SetMinDecimalLength(adjustValue);
401     }
402     maxDecimalLength = adjustValue;
403     defaultData->SetMaxDecimalLength(adjustValue);
404     defaultData->UpdateNumberFormat();
405     return true;
406 }
407 
SetMinDecimalLength(int length)408 bool NumberFormatImpl::SetMinDecimalLength(int length)
409 {
410     if (defaultData == nullptr) {
411         return false;
412     }
413     int adjustValue = (length < 0) ? -1 : length;
414     if ((maxDecimalLength >= 0) && (maxDecimalLength < adjustValue)) {
415         maxDecimalLength = adjustValue;
416         defaultData->SetMaxDecimalLength(maxDecimalLength);
417     }
418     minDecimalLength = adjustValue;
419     defaultData->SetMinDecimalLength(adjustValue);
420     defaultData->UpdateNumberFormat();
421     return true;
422 }
423 
FillMinDecimal(const char * target,int len,int addSize,bool isDec) const424 char *NumberFormatImpl::FillMinDecimal(const char *target, int len, int addSize, bool isDec) const
425 {
426     char *content = I18nNewCharString(target, len + addSize);
427     if (content == nullptr) {
428         return nullptr;
429     }
430     for (int i = 0; i < addSize; i++) {
431         if ((!isDec) && (i == 0)) {
432             content[len + i] = '.';
433             continue;
434         }
435         content[len + i] = '0';
436     }
437     return content;
438 }
439