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#ifndef FOUNDATION_ACE_FRAMEWORKS_BRIDGE_COMMON_UTILS_UTILS_H
17#define FOUNDATION_ACE_FRAMEWORKS_BRIDGE_COMMON_UTILS_UTILS_H
18
19#include <algorithm>
20#include <cctype>
21#include <climits>
22#include <cmath>
23#include <cstring>
24#include <iomanip>
25#include <map>
26#include <optional>
27#include <sstream>
28#include <string>
29#include <unordered_map>
30#include <unordered_set>
31
32#include "base/error/error_code.h"
33#include "base/geometry/axis.h"
34#include "base/json/json_util.h"
35#include "base/log/log.h"
36#include "base/resource/asset_manager.h"
37#include "base/utils/linear_map.h"
38#include "base/utils/string_utils.h"
39#include "base/utils/utils.h"
40#include "core/animation/animation_pub.h"
41#include "core/animation/curve.h"
42#include "core/animation/curves.h"
43#include "core/animation/spring_curve.h"
44#include "core/common/ime/text_input_action.h"
45#include "core/common/ime/text_input_type.h"
46#include "core/components/common/layout/constants.h"
47#include "core/components/common/properties/clip_path.h"
48#include "core/components/common/properties/decoration.h"
49#include "core/components/common/properties/text_style.h"
50#include "frameworks/bridge/common/dom/dom_type.h"
51
52namespace OHOS::Ace::Framework {
53
54constexpr int32_t OFFSET_VALUE_NUMBER = 2;
55constexpr uint8_t UTF8_CHARATER_HEAD = 0xc0;
56constexpr uint8_t UTF8_CHARATER_BODY = 0x80;
57constexpr int32_t UNICODE_LENGTH = 4;
58constexpr int32_t STRTOL_BASE = 10;
59constexpr int32_t INVALID_PARAM = -1;
60constexpr int32_t PLACE_HOLDER_LENGTH = 3;
61
62constexpr char INPUT_ACTION_NEXT[] = "next";
63constexpr char INPUT_ACTION_GO[] = "go";
64constexpr char INPUT_ACTION_DONE[] = "done";
65constexpr char INPUT_ACTION_SEND[] = "send";
66constexpr char INPUT_ACTION_SEARCH[] = "search";
67constexpr char PLURAL_COUNT_POS[] = "{count}";
68constexpr char DEFAULT_PLURAL_CHOICE[] = "other";
69
70const char DOUBLE_QUOTATION = '"';
71const char BACKSLASH = '\\';
72const char ESCAPE_CHARATER_START = '\x00';
73const char ESCAPE_CHARATER_END = '\x1f';
74const char UNICODE_BODY = '0';
75const char UNICODE_HEAD[] = "\\u";
76const char LEFT_CURLY_BRACES = '{';
77const char RIGHT_CURLY_BRACES = '}';
78
79template<class T>
80bool GetAssetContentImpl(const RefPtr<AssetManager>& assetManager, const std::string& url, T& content)
81{
82    if (!assetManager) {
83        return false;
84    }
85    auto jsAsset = assetManager->GetAsset(url);
86    if (jsAsset == nullptr) {
87        return false;
88    }
89    auto bufLen = jsAsset->GetSize();
90    auto buffer = jsAsset->GetData();
91    if ((buffer == nullptr) || (bufLen <= 0)) {
92        return false;
93    }
94    content.assign(buffer, buffer + bufLen);
95    return true;
96}
97
98template<class T>
99bool GetAssetContentAllowEmpty(const RefPtr<AssetManager>& assetManager, const std::string& url, T& content)
100{
101    if (!assetManager) {
102        return false;
103    }
104    auto jsAsset = assetManager->GetAsset(url);
105    if (jsAsset == nullptr) {
106        return false;
107    }
108    auto bufLen = jsAsset->GetSize();
109    auto buffer = jsAsset->GetData();
110    content.assign(buffer, buffer + bufLen);
111    return true;
112}
113
114inline std::string GetAssetPathImpl(const RefPtr<AssetManager>& assetManager, const std::string& url)
115{
116    if (!assetManager) {
117        return {};
118    }
119    return assetManager->GetAssetPath(url, true);
120}
121
122inline std::unique_ptr<JsonValue> ParseFileData(const std::string& data)
123{
124    const char* endMsg = nullptr;
125    auto fileData = JsonUtil::ParseJsonString(data, &endMsg);
126    if (!fileData) {
127        return nullptr;
128    }
129    return fileData;
130}
131
132inline double StringToDouble(const std::string& value)
133{
134    return StringUtils::StringToDouble(value);
135}
136
137inline Dimension StringToDimension(const std::string& value)
138{
139    return StringUtils::StringToDimension(value);
140}
141
142inline Dimension StringToDimensionWithUnit(const std::string& value, DimensionUnit defaultUnit = DimensionUnit::PX)
143{
144    return StringUtils::StringToDimensionWithUnit(value, defaultUnit);
145}
146
147inline int32_t StringToInt(const std::string& value)
148{
149    return StringUtils::StringToInt(value);
150}
151
152inline bool StringToBool(const std::string& value)
153{
154    return value == "true";
155}
156
157inline BorderStyle ConvertStrToBorderStyle(const std::string& style)
158{
159    static const LinearMapNode<BorderStyle> borderStyleTable[] = {
160        { "dashed", BorderStyle::DASHED },
161        { "dotted", BorderStyle::DOTTED },
162        { "solid", BorderStyle::SOLID },
163    };
164
165    auto index = BinarySearchFindIndex(borderStyleTable, ArraySize(borderStyleTable), style.c_str());
166    return index < 0 ? BorderStyle::NONE : borderStyleTable[index].value;
167}
168
169inline BorderImageRepeat ConvertStrToBorderImageRepeat(const std::string& repeat)
170{
171    static const LinearMapNode<BorderImageRepeat> borderImageRepeatTable[] = {
172        { "repeat", BorderImageRepeat::REPEAT },
173        { "round", BorderImageRepeat::ROUND },
174        { "space", BorderImageRepeat::SPACE },
175        { "stretch", BorderImageRepeat::STRETCH },
176    };
177
178    auto index = BinarySearchFindIndex(borderImageRepeatTable, ArraySize(borderImageRepeatTable), repeat.c_str());
179    return index < 0 ? BorderImageRepeat::STRETCH : borderImageRepeatTable[index].value;
180}
181
182inline BadgePosition ConvertStrToBadgePosition(const std::string& badgePosition)
183{
184    static const LinearMapNode<BadgePosition> badgePositionTable[] = {
185        { "left", BadgePosition::LEFT },
186        { "right", BadgePosition::RIGHT },
187        { "rightTop", BadgePosition::RIGHT_TOP },
188    };
189    auto index = BinarySearchFindIndex(badgePositionTable, ArraySize(badgePositionTable), badgePosition.c_str());
190    return index < 0 ? BadgePosition::RIGHT_TOP : badgePositionTable[index].value;
191}
192
193inline BoxSizing ConvertStrToBoxSizing(const std::string& value)
194{
195    static const LinearMapNode<BoxSizing> boxSizingTable[] = {
196        { "border-box", BoxSizing::BORDER_BOX },
197        { "content-box", BoxSizing::CONTENT_BOX },
198    };
199    auto index = BinarySearchFindIndex(boxSizingTable, ArraySize(boxSizingTable), value.c_str());
200    return index < 0 ? BoxSizing::BORDER_BOX : boxSizingTable[index].value;
201}
202
203inline ImageRepeat ConvertStrToImageRepeat(const std::string& repeat)
204{
205    static const LinearMapNode<ImageRepeat> imageRepeatTable[] = {
206        { "no-repeat", ImageRepeat::NO_REPEAT },
207        { "repeat", ImageRepeat::REPEAT },
208        { "repeat-x", ImageRepeat::REPEAT_X },
209        { "repeat-y", ImageRepeat::REPEAT_Y },
210    };
211
212    auto index = BinarySearchFindIndex(imageRepeatTable, ArraySize(imageRepeatTable), repeat.c_str());
213    return index < 0 ? ImageRepeat::NO_REPEAT : imageRepeatTable[index].value;
214}
215
216inline std::pair<bool, FontWeight> ParseFontWeight(
217    const std::string& weight, FontWeight defaultFontWeight = FontWeight::NORMAL)
218{
219    return StringUtils::ParseFontWeight(weight, defaultFontWeight);
220}
221
222inline FontWeight ConvertStrToFontWeight(const std::string& weight, FontWeight defaultFontWeight = FontWeight::NORMAL)
223{
224    return StringUtils::StringToFontWeight(weight, defaultFontWeight);
225}
226
227inline TextDecoration ConvertStrToTextDecoration(const std::string& textDecoration)
228{
229    // this map should be sorted by key.
230    static const LinearMapNode<TextDecoration> textDecorationTable[] = {
231        { DOM_TEXT_DECORATION_INHERIT, TextDecoration::INHERIT },
232        { DOM_TEXT_DECORATION_LINETHROUGH, TextDecoration::LINE_THROUGH },
233        { DOM_TEXT_DECORATION_NONE, TextDecoration::NONE },
234        { DOM_TEXT_DECORATION_OVERLINE, TextDecoration::OVERLINE },
235        { DOM_TEXT_DECORATION_UNDERLINE, TextDecoration::UNDERLINE },
236    };
237
238    auto index = BinarySearchFindIndex(textDecorationTable, ArraySize(textDecorationTable), textDecoration.c_str());
239    return index < 0 ? TextDecoration::NONE : textDecorationTable[index].value;
240}
241
242inline TextDecorationStyle ConvertStrToTextDecorationStyle(const std::string& textDecorationStyle)
243{
244    // this map should be sorted by key.
245    static const LinearMapNode<TextDecorationStyle> textDecorationStyleTable[] = {
246        { DOM_TEXT_DECORATION_STYLE_DASHED, TextDecorationStyle::DASHED },
247        { DOM_TEXT_DECORATION_STYLE_DOTTED, TextDecorationStyle::DOTTED },
248        { DOM_TEXT_DECORATION_STYLE_DOUBLE, TextDecorationStyle::DOUBLE },
249        { DOM_TEXT_DECORATION_STYLE_SOLID, TextDecorationStyle::SOLID },
250        { DOM_TEXT_DECORATION_STYLE_WAVY, TextDecorationStyle::WAVY },
251    };
252
253    auto index = BinarySearchFindIndex(
254        textDecorationStyleTable, ArraySize(textDecorationStyleTable), textDecorationStyle.c_str());
255    return index < 0 ? TextDecorationStyle::SOLID : textDecorationStyleTable[index].value;
256}
257
258inline WhiteSpace ConvertStrToWhiteSpace(const std::string& whiteSpace)
259{
260    // this map should be sorted by key.
261    static const LinearMapNode<WhiteSpace> whiteSpaceTable[] = {
262        { DOM_WHITE_SPACE_INHERIT, WhiteSpace::INHERIT },
263        { DOM_WHITE_SPACE_NORMAL, WhiteSpace::NORMAL },
264        { DOM_WHITE_SPACE_NOWRAP, WhiteSpace::NOWRAP },
265        { DOM_WHITE_SPACE_PRE, WhiteSpace::PRE },
266        { DOM_WHITE_SPACE_PRELINE, WhiteSpace::PRE_LINE },
267        { DOM_WHITE_SPACE_PREWRAP, WhiteSpace::PRE_WRAP },
268    };
269
270    auto index = BinarySearchFindIndex(whiteSpaceTable, ArraySize(whiteSpaceTable), whiteSpace.c_str());
271    return index < 0 ? WhiteSpace::NORMAL : whiteSpaceTable[index].value;
272}
273
274inline VerticalAlign ConvertStrToTextVerticalAlign(const std::string& align)
275{
276    static const LinearMapNode<VerticalAlign> textVerticalAlignTable[] = {
277        { DOM_BOTTOM, VerticalAlign::BOTTOM },
278        { DOM_MIDDLE, VerticalAlign::CENTER },
279        { DOM_TOP, VerticalAlign::TOP },
280    };
281    auto index = BinarySearchFindIndex(textVerticalAlignTable, ArraySize(textVerticalAlignTable), align.c_str());
282    return index < 0 ? VerticalAlign::NONE : textVerticalAlignTable[index].value;
283}
284
285inline FontStyle ConvertStrToFontStyle(const std::string& fontStyle)
286{
287    return fontStyle == DOM_TEXT_FONT_STYLE_ITALIC ? FontStyle::ITALIC : FontStyle::NORMAL;
288}
289
290inline TextAlign ConvertStrToTextAlign(const std::string& align)
291{
292    static const LinearMapNode<TextAlign> textAlignTable[] = {
293        { DOM_CENTER, TextAlign::CENTER },
294        { DOM_END, TextAlign::END },
295        { DOM_LEFT, TextAlign::LEFT },
296        { DOM_RIGHT, TextAlign::RIGHT },
297        { DOM_START, TextAlign::START },
298    };
299
300    auto index = BinarySearchFindIndex(textAlignTable, ArraySize(textAlignTable), align.c_str());
301    return index < 0 ? TextAlign::CENTER : textAlignTable[index].value;
302}
303
304inline TextOverflow ConvertStrToTextOverflow(const std::string& overflow)
305{
306    return overflow == DOM_ELLIPSIS ? TextOverflow::ELLIPSIS : TextOverflow::CLIP;
307}
308
309inline Overflow ConvertStrToOverflow(const std::string& val)
310{
311    const LinearMapNode<Overflow> overflowTable[] = {
312        { "auto", Overflow::SCROLL },
313        { "hidden", Overflow::FORCE_CLIP },
314        { "scroll", Overflow::SCROLL },
315        { "visible", Overflow::OBSERVABLE },
316    };
317    auto index = BinarySearchFindIndex(overflowTable, ArraySize(overflowTable), val.c_str());
318    return index < 0 ? Overflow::CLIP : overflowTable[index].value;
319}
320
321inline TextDirection ConvertStrToTextDirection(const std::string& val)
322{
323    const LinearMapNode<TextDirection> textDirectionTable[] = {
324        { "inherit", TextDirection::INHERIT },
325        { "ltr", TextDirection::LTR },
326        { "rtl", TextDirection::RTL },
327    };
328    auto index = BinarySearchFindIndex(textDirectionTable, ArraySize(textDirectionTable), val.c_str());
329    return index < 0 ? TextDirection::LTR : textDirectionTable[index].value;
330}
331
332inline TextFieldOverflowX ConvertStrToTextFieldOverflowX(const std::string& val)
333{
334    const LinearMapNode<TextFieldOverflowX> textFieldOverflowXTable[] = {
335        { "auto", TextFieldOverflowX::AUTO },
336        { "hidden", TextFieldOverflowX::HIDDEN },
337        { "scroll", TextFieldOverflowX::SCROLL },
338    };
339    auto index = BinarySearchFindIndex(textFieldOverflowXTable, ArraySize(textFieldOverflowXTable), val.c_str());
340    return index < 0 ? TextFieldOverflowX::HIDDEN : textFieldOverflowXTable[index].value;
341}
342
343inline std::vector<std::string> ConvertStrToFontFamilies(const std::string& family)
344{
345    std::vector<std::string> fontFamilies;
346    std::stringstream stream(family);
347    std::string fontFamily;
348    while (getline(stream, fontFamily, ',')) {
349        fontFamilies.emplace_back(fontFamily);
350    }
351    return fontFamilies;
352}
353
354inline FlexDirection ConvertStrToFlexDirection(const std::string& flexKey)
355{
356    return flexKey == DOM_FLEX_COLUMN ? FlexDirection::COLUMN : FlexDirection::ROW;
357}
358
359inline FlexAlign ConvertStrToFlexAlign(const std::string& flexKey)
360{
361    static const LinearMapNode<FlexAlign> flexMap[] = {
362        { DOM_ALIGN_ITEMS_BASELINE, FlexAlign::BASELINE },
363        { DOM_JUSTIFY_CONTENT_CENTER, FlexAlign::CENTER },
364        { DOM_JUSTIFY_CONTENT_END, FlexAlign::FLEX_END },
365        { DOM_JUSTIFY_CONTENT_START, FlexAlign::FLEX_START },
366        { DOM_JUSTIFY_CONTENT_AROUND, FlexAlign::SPACE_AROUND },
367        { DOM_JUSTIFY_CONTENT_BETWEEN, FlexAlign::SPACE_BETWEEN },
368        { DOM_JUSTIFY_CONTENT_EVENLY, FlexAlign::SPACE_EVENLY },
369        { DOM_ALIGN_ITEMS_STRETCH, FlexAlign::STRETCH },
370    };
371    auto index = BinarySearchFindIndex(flexMap, ArraySize(flexMap), flexKey.c_str());
372    return index < 0 ? FlexAlign::FLEX_START : flexMap[index].value;
373}
374
375inline Offset ConvertStrToOffset(const std::string& value)
376{
377    Offset offset;
378    std::vector<std::string> offsetValues;
379    std::stringstream stream(value);
380    std::string offsetValue;
381    while (getline(stream, offsetValue, ' ')) {
382        offsetValues.emplace_back(offsetValue);
383    }
384    // To avoid illegal input, such as "100px ".
385    offsetValues.resize(OFFSET_VALUE_NUMBER);
386    offset.SetX(StringToDouble(offsetValues[0]));
387    offset.SetY(StringToDouble(offsetValues[1]));
388    return offset;
389}
390
391inline QrcodeType ConvertStrToQrcodeType(const std::string& value)
392{
393    return value == "circle" ? QrcodeType::CIRCLE : QrcodeType::RECT;
394}
395
396inline AnimationCurve ConvertStrToAnimationCurve(const std::string& value)
397{
398    return value == "standard" ? AnimationCurve::STANDARD : AnimationCurve::FRICTION;
399}
400
401inline TextInputAction ConvertStrToTextInputAction(const std::string& action)
402{
403    TextInputAction inputAction;
404    if (action == INPUT_ACTION_NEXT) {
405        inputAction = TextInputAction::NEXT;
406    } else if (action == INPUT_ACTION_GO) {
407        inputAction = TextInputAction::GO;
408    } else if (action == INPUT_ACTION_DONE) {
409        inputAction = TextInputAction::DONE;
410    } else if (action == INPUT_ACTION_SEND) {
411        inputAction = TextInputAction::SEND;
412    } else if (action == INPUT_ACTION_SEARCH) {
413        inputAction = TextInputAction::SEARCH;
414    } else {
415        inputAction = TextInputAction::UNSPECIFIED;
416    }
417    return inputAction;
418}
419
420inline TextInputType ConvertStrToTextInputType(const std::string& type)
421{
422    TextInputType inputType;
423    if (type == DOM_INPUT_TYPE_NUMBER) {
424        inputType = TextInputType::NUMBER;
425    } else if (type == DOM_INPUT_TYPE_DATE || type == DOM_INPUT_TYPE_TIME) {
426        inputType = TextInputType::DATETIME;
427    } else if (type == DOM_INPUT_TYPE_EMAIL) {
428        inputType = TextInputType::EMAIL_ADDRESS;
429    } else if (type == DOM_INPUT_TYPE_PASSWORD) {
430        inputType = TextInputType::VISIBLE_PASSWORD;
431    } else {
432        inputType = TextInputType::TEXT;
433    }
434    return inputType;
435}
436
437inline TabBarMode ConvertStrToTabBarMode(const std::string& value)
438{
439    std::string temp = value;
440    transform(temp.begin(), temp.end(), temp.begin(), tolower);
441    return temp == "fixed" ? TabBarMode::FIXED : TabBarMode::SCROLLABLE;
442}
443
444ACE_FORCE_EXPORT RefPtr<Curve> CreateBuiltinCurve(const std::string& aniTimFunc);
445
446ACE_FORCE_EXPORT RefPtr<Curve> CreateCustomCurve(const std::string& aniTimFunc);
447
448ACE_FORCE_EXPORT RefPtr<Curve> CreateCurve(const std::function<float(float)>& jsFunc);
449
450ACE_FORCE_EXPORT RefPtr<Curve> CreateCurve(const std::string& aniTimFunc, bool useDefault = true);
451
452ACE_FORCE_EXPORT bool ParseCurveParam(
453    const std::string& aniTimFunc, std::string& curveName, std::vector<std::string>& paramsVector);
454
455ACE_FORCE_EXPORT RefPtr<Curve> CreateCurveExceptSpring(
456    const std::string& aniTimFunc, const std::function<float(float)>& jsFunc = nullptr);
457
458ACE_EXPORT TransitionType ParseTransitionType(const std::string& transitionType);
459
460ACE_EXPORT RefPtr<ClipPath> CreateClipPath(const std::string& value);
461
462inline FillMode StringToFillMode(const std::string& fillMode)
463{
464    if (fillMode == DOM_ANIMATION_FILL_MODE_FORWARDS) {
465        return FillMode::FORWARDS;
466    } else if (fillMode == DOM_ANIMATION_FILL_MODE_BACKWARDS) {
467        return FillMode::BACKWARDS;
468    } else if (fillMode == DOM_ANIMATION_FILL_MODE_BOTH) {
469        return FillMode::BOTH;
470    } else {
471        return FillMode::NONE;
472    }
473}
474
475inline AnimationDirection StringToAnimationDirection(const std::string& direction)
476{
477    if (direction == DOM_ANIMATION_DIRECTION_ALTERNATE) {
478        return AnimationDirection::ALTERNATE;
479    } else if (direction == DOM_ANIMATION_DIRECTION_REVERSE) {
480        return AnimationDirection::REVERSE;
481    } else if (direction == DOM_ANIMATION_DIRECTION_ALTERNATE_REVERSE) {
482        return AnimationDirection::ALTERNATE_REVERSE;
483    } else {
484        return AnimationDirection::NORMAL;
485    }
486}
487
488inline AnimationOperation StringToAnimationOperation(const std::string& direction)
489{
490    if (direction == DOM_ANIMATION_PLAY_STATE_IDLE) {
491        return AnimationOperation::CANCEL;
492    } else if (direction == DOM_ANIMATION_PLAY_STATE_RUNNING) {
493        return AnimationOperation::RUNNING;
494    } else if (direction == DOM_ANIMATION_PLAY_STATE_PAUSED) {
495        return AnimationOperation::PAUSE;
496    } else if (direction == DOM_ANIMATION_PLAY_STATE_FINISHED) {
497        return AnimationOperation::FINISH;
498    } else {
499        return AnimationOperation::NONE;
500    }
501}
502
503inline void RemoveHeadTailSpace(std::string& value)
504{
505    if (!value.empty()) {
506        auto start = value.find_first_not_of(' ');
507        if (start == std::string::npos) {
508            value.clear();
509        } else {
510            value = value.substr(start, value.find_last_not_of(' ') - start + 1);
511        }
512    }
513}
514
515inline GradientDirection StrToGradientDirection(const std::string& direction)
516{
517    static const LinearMapNode<GradientDirection> gradientDirectionTable[] = {
518        { DOM_GRADIENT_DIRECTION_LEFT, GradientDirection::LEFT },
519        { DOM_GRADIENT_DIRECTION_RIGHT, GradientDirection::RIGHT },
520        { DOM_GRADIENT_DIRECTION_TOP, GradientDirection::TOP },
521        { DOM_GRADIENT_DIRECTION_BOTTOM, GradientDirection::BOTTOM },
522    };
523
524    auto index = BinarySearchFindIndex(gradientDirectionTable, ArraySize(gradientDirectionTable), direction.c_str());
525    return index < 0 ? GradientDirection::BOTTOM : gradientDirectionTable[index].value;
526}
527
528std::string CurveIntToString(int curve);
529
530bool ParseBackgroundImagePosition(const std::string& value, BackgroundImagePosition& backgroundImagePosition);
531
532bool ParseBackgroundImageSize(const std::string& value, BackgroundImageSize& backgroundImageSize);
533
534ImageObjectPosition ParseImageObjectPosition(const std::string& value);
535
536std::optional<RadialSizeType> ParseRadialGradientSize(const std::string& value);
537
538inline bool StartWith(const std::string& dst, const std::string& prefix)
539{
540    return dst.compare(0, prefix.size(), prefix) == 0;
541}
542
543inline bool EndWith(const std::string& dst, const std::string& suffix)
544{
545    return dst.size() >= suffix.size() && dst.compare(dst.size() - suffix.size(), suffix.size(), suffix) == 0;
546}
547
548inline double ConvertTimeStr(const std::string& str)
549{
550    std::string time(str);
551    StringUtils::TrimStr(time);
552    double result = 0.0;
553    if (EndWith(time, "ms")) {
554        // remove 2 char "ms"
555        result = StringToDouble(std::string(time.begin(), time.end() - 2.0));
556    } else if (EndWith(time, "s")) {
557        // transform s to ms
558        result = StringToDouble(std::string(time.begin(), time.end() - 1.0)) * 1000.0;
559    } else if (EndWith(time, "m")) {
560        // transform m to ms
561        result = StringToDouble(std::string(time.begin(), time.end() - 1.0)) * 60.0 * 1000.0;
562    } else {
563        result = StringToDouble(str);
564    }
565    return result;
566}
567
568inline WordBreak ConvertStrToWordBreak(const std::string& wordBreak)
569{
570    return StringUtils::StringToWordBreak(wordBreak);
571}
572
573inline bool CheckTransformEnum(const std::string& str)
574{
575    const static std::unordered_set<std::string> offsetKeywords = { "left", "right", "center", "top", "bottom" };
576
577    return offsetKeywords.find(str) != offsetKeywords.end();
578}
579
580inline std::pair<bool, Dimension> ConvertStrToTransformOrigin(const std::string& str, Axis axis)
581{
582    const static std::unordered_map<std::string, Dimension> xOffsetKeywords = {
583        { "left", 0.0_pct },
584        { "right", 1.0_pct },
585        { "center", 0.5_pct },
586    };
587    const static std::unordered_map<std::string, Dimension> yOffsetKeywords = {
588        { "top", 0.0_pct },
589        { "bottom", 1.0_pct },
590        { "center", 0.5_pct },
591    };
592
593    if (axis == Axis::HORIZONTAL) {
594        auto pos = xOffsetKeywords.find(str);
595        if (pos != xOffsetKeywords.end()) {
596            return std::make_pair(true, pos->second);
597        }
598    } else if (axis == Axis::VERTICAL) {
599        auto pos = yOffsetKeywords.find(str);
600        if (pos != yOffsetKeywords.end()) {
601            return std::make_pair(true, pos->second);
602        }
603    }
604
605    return std::make_pair(false, Dimension {});
606}
607
608inline int32_t ParseUtf8TextLength(std::string& text)
609{
610    int32_t trueLength = 0;
611    int32_t stringLength = 0;
612    while (stringLength < static_cast<int32_t>(text.length())) {
613        uint8_t stringChar = static_cast<uint8_t>(text[stringLength++]);
614        if ((stringChar & UTF8_CHARATER_HEAD) != UTF8_CHARATER_BODY) {
615            trueLength++;
616        }
617    }
618    return trueLength;
619}
620
621inline int32_t ParseUtf8TextSubstrStartPos(std::string& text, int32_t targetPos)
622{
623    int32_t truePos = 0;
624    int32_t stringPos = 0;
625    while ((stringPos < static_cast<int32_t>(text.length())) && (truePos < targetPos)) {
626        uint8_t stringChar = static_cast<uint8_t>(text[stringPos++]);
627        if ((stringChar & UTF8_CHARATER_HEAD) != UTF8_CHARATER_BODY) {
628            truePos++;
629        }
630    }
631    return stringPos;
632}
633
634inline int32_t ParseUtf8TextSubstrEndPos(std::string& text, int32_t targetPos)
635{
636    auto stringPos = ParseUtf8TextSubstrStartPos(text, targetPos);
637    while (stringPos < static_cast<int32_t>(text.length())) {
638        uint8_t stringChar = static_cast<uint8_t>(text[stringPos]);
639        if ((stringChar & UTF8_CHARATER_HEAD) != UTF8_CHARATER_BODY) {
640            break;
641        }
642        stringPos++;
643    }
644    return stringPos;
645}
646
647inline void HandleEscapeCharaterInUtf8TextForJson(std::string& text)
648{
649    for (size_t pos = 0; pos < text.size(); pos++) {
650        if ((text.at(pos) == DOUBLE_QUOTATION) || (text.at(pos) == BACKSLASH) ||
651            ((text.at(pos) >= ESCAPE_CHARATER_START) && (text.at(pos) <= ESCAPE_CHARATER_END))) {
652            std::ostringstream is;
653            is << UNICODE_HEAD << std::hex << std::setw(UNICODE_LENGTH) << std::setfill(UNICODE_BODY)
654               << int(text.at(pos));
655            text.replace(pos, 1, is.str());
656        }
657    }
658}
659
660inline int32_t ParseResourceInputNumberParam(const std::string& param)
661{
662    if (!StringUtils::IsNumber(param) || param.empty()) {
663        return INVALID_PARAM;
664    } else {
665        errno = 0;
666        char* pEnd = nullptr;
667        int64_t result = std::strtol(param.c_str(), &pEnd, STRTOL_BASE);
668        return ((result < INT_MIN || result > INT_MAX) || errno == ERANGE) ? INT_MAX : static_cast<int32_t>(result);
669    }
670}
671
672inline void ReplacePlaceHolderArray(std::string& resultStr, const std::vector<std::string>& arrayResult)
673{
674    auto size = arrayResult.size();
675    size_t startPos = 0;
676    for (size_t i = 0; i < size; i++) {
677        std::string placeHolder;
678        placeHolder += LEFT_CURLY_BRACES;
679        placeHolder += (i + '0');
680        placeHolder += RIGHT_CURLY_BRACES;
681        if (startPos < resultStr.length()) {
682            auto pos = resultStr.find(placeHolder, startPos);
683            if (pos != std::string::npos) {
684                resultStr.replace(pos, PLACE_HOLDER_LENGTH, arrayResult[i]);
685                startPos = pos + arrayResult[i].length();
686            }
687        }
688    }
689}
690
691inline void ReplacePlaceHolder(std::string& resultStr, const std::unique_ptr<JsonValue>& argsPtr)
692{
693    auto placeHolderKey = argsPtr->GetChild()->GetKey();
694    std::string placeHolder;
695    placeHolder += LEFT_CURLY_BRACES;
696    placeHolder += placeHolderKey;
697    placeHolder += RIGHT_CURLY_BRACES;
698    auto pos = resultStr.find(placeHolder);
699    if (pos != std::string::npos) {
700        resultStr.replace(pos, placeHolder.length(), argsPtr->GetChild()->GetString());
701    }
702}
703
704inline std::string ParserPluralResource(
705    const std::unique_ptr<JsonValue>& argsPtr, const std::string& choice, const std::string& count)
706{
707    std::string valueStr;
708    std::string defaultPluralStr(DEFAULT_PLURAL_CHOICE);
709    if (argsPtr->Contains(choice)) {
710        valueStr = argsPtr->GetValue(choice)->GetString();
711    } else if (argsPtr->Contains(defaultPluralStr)) {
712        valueStr = argsPtr->GetValue(defaultPluralStr)->GetString();
713    } else {
714        return std::string();
715    }
716
717    std::string pluralStr(PLURAL_COUNT_POS);
718    auto pos = valueStr.find(pluralStr);
719    if (pos != std::string::npos) {
720        valueStr.replace(pos, pluralStr.length(), count);
721    }
722    return valueStr;
723}
724
725} // namespace OHOS::Ace::Framework
726
727#endif // FOUNDATION_ACE_FRAMEWORKS_BRIDGE_COMMON_UTILS_UTILS_H
728