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/mem/c_string.h"
17
18 #include "ecmascript/base/dtoa_helper.h"
19 #include "ecmascript/base/number_helper.h"
20 #include "ecmascript/base/json_helper.h"
21 #include "ecmascript/ecma_string-inl.h"
22 #include "ecmascript/js_symbol.h"
23
24 namespace panda::ecmascript {
CStringToL(const CString & str)25 long CStringToL(const CString &str)
26 {
27 char *endPtr = nullptr;
28 int64_t result = std::strtol(str.c_str(), &endPtr, DEC_BASE);
29 ASSERT(!(result == 0 && str.c_str() == endPtr) && "CString argument is not long int");
30 return result;
31 }
32
CStringToLL(const CString & str)33 int64_t CStringToLL(const CString &str)
34 {
35 char *endPtr = nullptr;
36 int64_t result = std::strtoll(str.c_str(), &endPtr, DEC_BASE);
37 ASSERT(!(result == 0 && str.c_str() == endPtr) && "CString argument is not long long int");
38 return result;
39 }
40
CStringToULL(const CString & str)41 uint64_t CStringToULL(const CString &str)
42 {
43 char *endPtr = nullptr;
44 uint64_t result = std::strtoull(str.c_str(), &endPtr, DEC_BASE);
45 ASSERT(!(result == 0 && str.c_str() == endPtr) && "CString argument is not unsigned long long int");
46 return result;
47 }
48
CStringToF(const CString & str)49 float CStringToF(const CString &str)
50 {
51 char *endPtr = nullptr;
52 float result = std::strtof(str.c_str(), &endPtr);
53 ASSERT(result != HUGE_VALF && "CString argument is not float");
54 ASSERT(!(result == 0 && str.c_str() == endPtr) && "CString argument is not float");
55 return result;
56 }
57
CStringToD(const CString & str)58 double CStringToD(const CString &str)
59 {
60 char *endPtr = nullptr;
61 double result = std::strtod(str.c_str(), &endPtr);
62 ASSERT(result != HUGE_VALF && "CString argument is not double");
63 ASSERT(!(result == 0 && str.c_str() == endPtr) && "CString argument is not double");
64 return result;
65 }
66
67 template<class T>
ConvertToString(T sp)68 CString ConvertToString(T sp)
69 {
70 CString res;
71 res.reserve(sp.size());
72
73 // Also support ascii that great than 127, so using unsigned char here
74 constexpr size_t maxChar = std::numeric_limits<unsigned char>::max();
75
76 for (const auto &c : sp) {
77 if (c > maxChar) {
78 return "";
79 }
80 res.push_back(c);
81 }
82
83 return res;
84 }
85
ConvertToString(const JSThread * thread,JSTaggedValue key)86 CString ConvertToString(const JSThread *thread, JSTaggedValue key)
87 {
88 ASSERT(key.IsStringOrSymbol());
89 if (key.IsString()) {
90 return ConvertToString(thread, EcmaString::ConstCast(key.GetTaggedObject()));
91 }
92
93 ecmascript::JSTaggedValue desc = JSSymbol::Cast(key.GetTaggedObject())->GetDescription(thread);
94 if (desc.IsUndefined()) {
95 return CString("Symbol()");
96 }
97
98 return ConvertToString(thread, EcmaString::ConstCast(desc.GetTaggedObject()));
99 }
100
101 // NB! the following function need additional mem allocation, don't use when unnecessary!
ConvertToString(const std::string & str)102 CString ConvertToString(const std::string &str)
103 {
104 CString res;
105 res.reserve(str.size());
106 for (auto c : str) {
107 res.push_back(c);
108 }
109 return res;
110 }
111
ConvertToString(const JSThread * thread,const EcmaString * s,StringConvertedUsage usage,bool cesu8)112 CString ConvertToString(const JSThread *thread, const EcmaString *s, StringConvertedUsage usage, bool cesu8)
113 {
114 if (s == nullptr) {
115 return CString("");
116 }
117 return EcmaStringAccessor(const_cast<EcmaString *>(s)).ToCString(thread, usage, cesu8);
118 }
119
ConvertToStdString(const CString & str)120 std::string ConvertToStdString(const CString &str)
121 {
122 std::string res;
123 res.reserve(str.size());
124 for (auto c : str) {
125 res.push_back(c);
126 }
127 return res;
128 }
129
130 #if ENABLE_NEXT_OPTIMIZATION
131 template <typename DstType>
AppendIntToCString(DstType & str,int number)132 void AppendIntToCString(DstType &str, int number)
133 {
134 using CharT = typename DstType::value_type;
135 int64_t n = static_cast<int64_t>(number);
136 uint32_t preSize = str.size();
137 bool isNeg = true;
138 if (n >= 0) {
139 n = -n;
140 isNeg = false;
141 }
142 do {
143 str.push_back(static_cast<CharT>('0' - (n % DEC_BASE)));
144 n /= DEC_BASE;
145 } while (n);
146 if (isNeg) {
147 str.push_back(static_cast<CharT>('-'));
148 }
149 std::reverse(str.begin() + preSize, str.end());
150 }
151
152 template void AppendIntToCString<CString>(CString &str, int number);
153 template void AppendIntToCString<C16String>(C16String &str, int number);
154
155 template <typename DstType>
AppendSpecialDouble(DstType & str,double d)156 bool AppendSpecialDouble(DstType &str, double d)
157 {
158 if (d == 0.0) {
159 AppendCString(str, base::NumberHelper::ZERO_STR);
160 return true;
161 }
162 if (std::isnan(d)) {
163 AppendCString(str, base::NumberHelper::NAN_STR);
164 return true;
165 }
166 if (std::isinf(d)) {
167 AppendCString(str, d < 0 ? base::NumberHelper::MINUS_INFINITY_STR : base::NumberHelper::INFINITY_STR);
168 return true;
169 }
170 return false;
171 }
172 template bool AppendSpecialDouble<CString>(CString &str, double d);
173 template bool AppendSpecialDouble<C16String>(C16String &str, double d);
174
175 template <typename DstType>
AppendDoubleToString(DstType & str,double d)176 void AppendDoubleToString(DstType &str, double d)
177 {
178 if (AppendSpecialDouble(str, d)) {
179 return;
180 }
181 bool isNeg = d < 0;
182 if (isNeg) {
183 d = -d;
184 }
185 ASSERT(d > 0);
186 constexpr int startIdx = 8; // when (isNeg and n = -5), result moves left for 8times
187 char buff[base::JS_DTOA_BUF_SIZE] = {0};
188 char *result = buff + startIdx;
189 ASSERT(startIdx < base::JS_DTOA_BUF_SIZE);
190 int n = 0;
191 int k = 0;
192 int len = 0;
193 base::DtoaHelper::Dtoa(d, result, &n, &k);
194 if (n > 0 && n <= base::MAX_DIGITS) {
195 if (k <= n) {
196 std::fill(result + k, result + n, '0');
197 len = n;
198 } else {
199 --result;
200 std::copy(result + 1, result + 1 + n, result);
201 result[n] = '.';
202 len = k + 1;
203 }
204 } else if (base::MIN_DIGITS < n && n <= 0) {
205 constexpr int prefixLen = 2;
206 result -= (-n + prefixLen);
207 ASSERT(result >= buff);
208 ASSERT(result + prefixLen - n <= buff + base::JS_DTOA_BUF_SIZE);
209 result[0] = '0';
210 result[1] = '.';
211 std::fill(result + prefixLen, result + prefixLen - n, '0');
212 len = -n + prefixLen + k;
213 } else {
214 int pos = k;
215 if (k != 1) {
216 --result;
217 result[0] = result[1];
218 result[1] = '.';
219 ++pos;
220 }
221 result[pos++] = 'e';
222 if (n >= 1) {
223 result[pos++] = '+';
224 }
225 auto expo = std::to_string(n - 1);
226 for (size_t i = 0; i < expo.length(); ++i) {
227 result[pos++] = expo[i];
228 }
229 len = pos;
230 }
231 if (isNeg) {
232 --result;
233 result[0] = '-';
234 len += 1;
235 }
236 AppendString(str, result, len);
237 }
238 template void AppendDoubleToString<CString>(CString &str, double d);
239 template void AppendDoubleToString<C16String>(C16String &str, double d);
240
241 template <typename DstType>
ConvertNumberToCStringAndAppend(DstType & str,JSTaggedValue num)242 void ConvertNumberToCStringAndAppend(DstType &str, JSTaggedValue num)
243 {
244 ASSERT(num.IsNumber());
245 if (num.IsInt()) {
246 int intVal = num.GetInt();
247 AppendIntToCString(str, intVal);
248 } else {
249 double d = num.GetDouble();
250 AppendDoubleToString(str, d);
251 }
252 }
253 template void ConvertNumberToCStringAndAppend<CString>(CString &str, JSTaggedValue num);
254 template void ConvertNumberToCStringAndAppend<C16String>(C16String &str, JSTaggedValue num);
255
ConvertQuotedAndAppendToCString(const JSThread * thread,CString & str,const EcmaString * s)256 void ConvertQuotedAndAppendToCString(const JSThread *thread, CString &str, const EcmaString *s)
257 {
258 ASSERT(s != nullptr);
259
260 uint32_t strLen = EcmaStringAccessor(const_cast<EcmaString *>(s)).GetLength();
261 CVector<uint8_t> buf;
262 const uint8_t *data = EcmaStringAccessor::GetUtf8DataFlat(thread, s, buf);
263 const Span<const uint8_t> dataSpan(data, strLen);
264 base::JsonHelper::AppendValueToQuotedString(dataSpan, str);
265 }
266
ConvertQuotedAndAppendToC16String(const JSThread * thread,C16String & str,const EcmaString * s)267 void ConvertQuotedAndAppendToC16String(const JSThread *thread, C16String &str, const EcmaString *s)
268 {
269 ASSERT(s != nullptr);
270
271 uint32_t strLen = EcmaStringAccessor(const_cast<EcmaString *>(s)).GetLength();
272 if (EcmaStringAccessor(const_cast<EcmaString *>(s)).IsUtf8()) {
273 CVector<uint8_t> buf;
274 const uint8_t *data = EcmaStringAccessor::GetUtf8DataFlat(thread, s, buf);
275 const Span<const uint8_t> dataSpan(data, strLen);
276 base::JsonHelper::AppendValueToQuotedString(dataSpan, str);
277 } else {
278 CVector<uint16_t> buf;
279 const uint16_t *data = EcmaStringAccessor::GetUtf16DataFlat(thread, s, buf);
280 const Span<const uint16_t> dataSpan(data, strLen);
281 base::JsonHelper::AppendValueToQuotedString(dataSpan, str);
282 }
283 }
284 #endif
285
286 } // namespace panda::ecmascript
287