1 /*
2 * Copyright (c) 2021 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 "ecmascript/intl/global_intl_helper.h"
17
18 #include "ecmascript/intl/locale_helper.h"
19 #include "ecmascript/ecma_macros.h"
20 #include "ecmascript/ecma_vm.h"
21 #include "ecmascript/global_env.h"
22 #include "ecmascript/object_factory.h"
23 #include "ecmascript/js_object.h"
24 #include "ecmascript/mem/c_string.h"
25
26 namespace panda::ecmascript::intl {
GlobalIntlHelper(JSThread * thread,const GlobalFormatterType matterType)27 GlobalIntlHelper::GlobalIntlHelper(JSThread *thread,
28 const GlobalFormatterType matterType)
29 {
30 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
31 auto iter = optionMaps.find(matterType);
32 if (iter == optionMaps.end()) {
33 switch (matterType) {
34 case GlobalFormatterType::Collator:
35 InitCollatorData(globalConst);
36 break;
37 case GlobalFormatterType::SimpleDateFormatDate:
38 case GlobalFormatterType::SimpleDateFormatTime:
39 case GlobalFormatterType::DateFormatter:
40 InitDateData(globalConst);
41 break;
42 case GlobalFormatterType::NumberFormatter:
43 InitNumberData(globalConst);
44 break;
45 }
46 }
47 }
48
ConvertDateToUnit(uint64_t timestamp)49 uint64_t *GlobalIntlHelper::ConvertDateToUnit(uint64_t timestamp)
50 {
51 const uint64_t baseYear = 1900;
52 const uint64_t baseTimeSec = 60;
53 const uint64_t baseTimeUTC = 8;
54 const uint64_t baseTime = 1000;
55 auto milli = timestamp + static_cast<uint64_t>(baseTimeUTC *
56 baseTimeSec * baseTimeSec * baseTime);
57 auto mTime = std::chrono::milliseconds(milli);
58 auto tp = std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>(mTime);
59 auto tt = std::chrono::system_clock::to_time_t(tp);
60 std::tm *now = std::gmtime(&tt);
61 dateUnitArr = new uint64_t[6] {
62 static_cast<uint64_t>(now->tm_year + baseYear),
63 static_cast<uint64_t>(now->tm_mon + 1),
64 static_cast<uint64_t>(now->tm_mday),
65 static_cast<uint64_t>(now->tm_hour),
66 static_cast<uint64_t>(now->tm_min),
67 static_cast<uint64_t>(now->tm_sec)
68 };
69 return dateUnitArr;
70 }
71
InitCollatorData(const GlobalEnvConstants * globalConst)72 void GlobalIntlHelper::InitCollatorData(const GlobalEnvConstants *globalConst)
73 {
74 std::map<std::string, JSHandle<JSTaggedValue>> collatorMap;
75 collatorMap["localeMatcher"] = globalConst->GetHandledLocaleMatcherString();
76 collatorMap["usage"] = globalConst->GetHandledUsageString();
77 collatorMap["sensitivity"] = globalConst->GetHandledSensitivityString();
78 collatorMap["ignorePunctuation"] = globalConst->GetHandledIgnorePunctuationString();
79 collatorMap["numeric"] = globalConst->GetHandledNumericString();
80 collatorMap["caseFirst"] = globalConst->GetHandledCaseFirstString();
81 collatorMap["collation"] = globalConst->GetHandledCollationString();
82 optionMaps.insert(make_pair(GlobalFormatterType::Collator, collatorMap));
83 }
84
InitDateData(const GlobalEnvConstants * globalConst)85 void GlobalIntlHelper::InitDateData(const GlobalEnvConstants *globalConst)
86 {
87 std::map<std::string, JSHandle<JSTaggedValue>> collatorMap;
88 collatorMap["dateStyle"] = globalConst->GetHandledDateStyleString();
89 collatorMap["timeStyle"] = globalConst->GetHandledTimeStyleString();
90 collatorMap["calendar"] = globalConst->GetHandledCalendarString();
91 collatorMap["numberingSystem"] = globalConst->GetHandledNumberingSystemString();
92 collatorMap["localeMatcher"] = globalConst->GetHandledLocaleMatcherString();
93 collatorMap["timeZone"] = globalConst->GetHandledTimeZoneString();
94 collatorMap["hour12"] = globalConst->GetHandledHour12String();
95 collatorMap["hourCycle"] = globalConst->GetHandledHourCycleString();
96 collatorMap["formatMatcher"] = globalConst->GetHandledFormatMatcherString();
97 collatorMap["weekday"] = globalConst->GetHandledWeekdayString();
98 collatorMap["era"] = globalConst->GetHandledEraString();
99 collatorMap["year"] = globalConst->GetHandledYearString();
100 collatorMap["month"] = globalConst->GetHandledMonthString();
101 collatorMap["day"] = globalConst->GetHandledDayString();
102 collatorMap["hour"] = globalConst->GetHandledHourString();
103 collatorMap["minute"] = globalConst->GetHandledMinuteString();
104 collatorMap["second"] = globalConst->GetHandledSecondString();
105 collatorMap["fractionalSecondDigits"] = globalConst->GetHandledFractionalSecondDigitsString();
106 collatorMap["timeZoneName"] = globalConst->GetHandledTimeZoneNameString();
107 optionMaps.insert(make_pair(GlobalFormatterType::DateFormatter, collatorMap));
108 }
109
InitNumberData(const GlobalEnvConstants * globalConst)110 void GlobalIntlHelper::InitNumberData(const GlobalEnvConstants *globalConst)
111 {
112 std::map<std::string, JSHandle<JSTaggedValue>> collatorMap;
113 collatorMap["localeMatcher"] = globalConst->GetHandledLocaleMatcherString();
114 collatorMap["numberingSystem"] = globalConst->GetHandledNumberingSystemString();
115 collatorMap["notation"] = globalConst->GetHandledNotationString();
116 collatorMap["compactDisplay"] = globalConst->GetHandledCompactDisplayString();
117 collatorMap["useGrouping"] = globalConst->GetHandledUserGroupingString();
118 collatorMap["signDisplay"] = globalConst->GetHandledSignDisplayString();
119 collatorMap["style"] = globalConst->GetHandledStyleString();
120 collatorMap["currency"] = globalConst->GetHandledCurrencyString();
121 collatorMap["currencySign"] = globalConst->GetHandledCurrencySignString();
122 collatorMap["currencyDisplay"] = globalConst->GetHandledCurrencyDisplayString();
123 collatorMap["unit"] = globalConst->GetHandledUnitString();
124 collatorMap["unitDisplay"] = globalConst->GetHandledUnitDisplayString();
125 collatorMap["minimumIntegerDigits"] = globalConst->GetHandledMinimumIntegerDigitsString();
126 collatorMap["minimumFractionDigits"] = globalConst->GetHandledMinimumFractionDigitsString();
127 collatorMap["maximumFractionDigits"] = globalConst->GetHandledMaximumFractionDigitsString();
128 collatorMap["minimumSignificantDigits"] = globalConst->GetHandledMinimumSignificantDigitsString();
129 collatorMap["maximumSignificantDigits"] = globalConst->GetHandledMaximumSignificantDigitsString();
130 optionMaps.insert(make_pair(GlobalFormatterType::NumberFormatter, collatorMap));
131 }
132
OptionsToMap(JSThread * thread,const JSHandle<JSTaggedValue> & options,GlobalFormatterType types)133 std::map<std::string, std::string> GlobalIntlHelper::OptionsToMap(JSThread *thread,
134 const JSHandle<JSTaggedValue> &options, GlobalFormatterType types)
135 {
136 std::map<std::string, std::string> inputOptions;
137 JSHandle<JSObject> optionsObject;
138 if (options->IsUndefined()) {
139 return inputOptions;
140 } else {
141 optionsObject = JSTaggedValue::ToObject(thread, options);
142 }
143 if (optionMaps.size() == 0) {
144 LOG_ECMA(ERROR) << "GlobalIntlHelper::OptionsToMap size is zero";
145 return inputOptions;
146 }
147
148 auto matterType = types;
149 if (types == GlobalFormatterType::SimpleDateFormatDate ||
150 types == GlobalFormatterType::SimpleDateFormatTime) {
151 matterType = GlobalFormatterType::DateFormatter;
152 }
153
154 auto iter = optionMaps.find(matterType);
155 if (iter != optionMaps.end()) {
156 for (auto &opt : optionMaps[matterType]) {
157 OperationResult operationResult = JSObject::GetProperty(thread, optionsObject, opt.second);
158 if (!operationResult.GetValue()->IsUndefined()) {
159 std::string valueStr = std::string(EcmaConvertToStr(JSTaggedValue::ToString(thread,
160 operationResult.GetValue())));
161 auto inOpt = inputOptions.find(opt.first);
162 if (inOpt != inputOptions.end()) {
163 inputOptions[opt.first] = valueStr;
164 } else {
165 inputOptions.insert(make_pair(opt.first, valueStr));
166 }
167 }
168 }
169 }
170 return OptionsWithDataFormatter(inputOptions, types);
171 }
172
OptionsWithDataFormatter(std::map<std::string,std::string> & options,GlobalFormatterType & types)173 std::map<std::string, std::string> GlobalIntlHelper::OptionsWithDataFormatter(std::map<std::string,
174 std::string> &options, GlobalFormatterType &types)
175 {
176 std::vector<std::string> all;
177 if (types == GlobalFormatterType::DateFormatter) {
178 all = {"year", "month", "day", "hour", "minute", "second"};
179 }
180 if (types == GlobalFormatterType::SimpleDateFormatDate) {
181 all = {"year", "month", "day"};
182 }
183 if (types == GlobalFormatterType::SimpleDateFormatTime) {
184 all = {"hour", "minute", "second"};
185 }
186 for (auto &item : all) {
187 auto iter = options.find(item);
188 if (iter == options.end()) {
189 options[item] = "numeric";
190 }
191 }
192 return options;
193 }
194
DoubleToInt64(double value)195 int64_t GlobalIntlHelper::DoubleToInt64(double value)
196 {
197 return static_cast<int64_t>(round(value));
198 }
199
EcmaConvertToStr(const JSHandle<EcmaString> & string)200 std::string GlobalIntlHelper::EcmaConvertToStr(const JSHandle<EcmaString> &string)
201 {
202 return std::string(ConvertToString(*string, StringConvertedUsage::LOGICOPERATION));
203 }
204
LocalesToVector(JSThread * thread,const JSHandle<JSTaggedValue> & locales)205 std::vector<std::string> GlobalIntlHelper::LocalesToVector(JSThread *thread,
206 const JSHandle<JSTaggedValue> &locales)
207 {
208 JSHandle<TaggedArray> tArray = intl::LocaleHelper::CanonicalizeLocaleList(thread, locales);
209 return TaggedArrayToVector(thread, tArray);
210 }
211
TaggedArrayToVector(JSThread * thread,JSHandle<TaggedArray> & taggedarray)212 std::vector<std::string> GlobalIntlHelper::TaggedArrayToVector(JSThread *thread,
213 JSHandle<TaggedArray> &taggedarray)
214 {
215 std::vector<std::string> availableStringLocales;
216 JSMutableHandle<EcmaString> availableItem(thread, JSTaggedValue::Undefined());
217 uint32_t availablecalesLength = taggedarray->GetLength();
218 for (uint32_t i = 0; i < availablecalesLength; i++) {
219 availableItem.Update(taggedarray->Get(thread, i));
220 availableStringLocales.emplace_back(intl::LocaleHelper::ConvertToStdString(availableItem));
221 }
222 return availableStringLocales;
223 }
224 } // panda::ecmascript::base
225