• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "quickjs_native_string.h"
17 
18 #include "securec.h"
19 #include "utils/log.h"
20 
QuickJSNativeString(QuickJSNativeEngine * engine,JSValue value)21 QuickJSNativeString::QuickJSNativeString(QuickJSNativeEngine* engine, JSValue value) : QuickJSNativeValue(engine, value)
22 {
23 }
24 
QuickJSNativeString(QuickJSNativeEngine * engine,JSAtom value)25 QuickJSNativeString::QuickJSNativeString(QuickJSNativeEngine* engine, JSAtom value)
26     : QuickJSNativeString(engine, JS_AtomToString(engine->GetContext(), value))
27 {
28 }
29 
QuickJSNativeString(QuickJSNativeEngine * engine,const char * value,size_t length)30 QuickJSNativeString::QuickJSNativeString(QuickJSNativeEngine* engine, const char* value, size_t length)
31     : QuickJSNativeString(engine, JS_NewStringLen(engine->GetContext(), value, length))
32 {
33 }
34 
QuickJSNativeString(QuickJSNativeEngine * engine,const char16_t * value,size_t length)35 QuickJSNativeString::QuickJSNativeString(QuickJSNativeEngine* engine, const char16_t* value, size_t length)
36     : QuickJSNativeString(
37           engine, JS_NewString16(engine->GetContext(), reinterpret_cast<const uint16_t*>(value), length))
38 {
39 }
40 
~QuickJSNativeString()41 QuickJSNativeString::~QuickJSNativeString() {}
42 
GetInterface(int interfaceId)43 void* QuickJSNativeString::GetInterface(int interfaceId)
44 {
45     return (NativeString::INTERFACE_ID == interfaceId) ? (NativeString*)this : nullptr;
46 }
47 
GetCString(char * buffer,size_t size,size_t * length)48 void QuickJSNativeString::GetCString(char* buffer, size_t size, size_t* length)
49 {
50     const char* str = JS_ToCStringLen(engine_->GetContext(), length, value_);
51 
52     if (str == nullptr) {
53         HILOG_ERROR("JS_ToCStringLen return value is null");
54         return;
55     }
56 
57     if (buffer != nullptr && length != nullptr) {
58         int ret = strncpy_s(buffer, size, str, *length);
59         if (ret != EOK) {
60             HILOG_ERROR("strncpy_s failed");
61         }
62     }
63     JS_FreeCString(engine_->GetContext(), str);
64 }
GetCString16(char16_t * buffer,size_t size,size_t * length)65 void QuickJSNativeString::GetCString16(char16_t* buffer, size_t size, size_t* length)
66 {
67     const char* str = JS_ToCStringLen(engine_->GetContext(), length, value_);
68     if (str == nullptr) {
69         HILOG_ERROR("JS_ToCStringLen return value is null");
70         return;
71     }
72     if (length != nullptr) {
73         auto ret = Utf8ToUtf16Length(str, strlen(str));
74         if (ret == -1) {
75             HILOG_ERROR("JS_ToCStringLen length is invalid");
76             JS_FreeCString(engine_->GetContext(), str);
77             return;
78         }
79         *length = ret;
80         if (buffer != nullptr) {
81             memset_s(buffer, sizeof(char16_t) * size, 0x0, sizeof(char16_t) * size);
82             Utf8ToUtf16(str, strlen(str), buffer, size);
83         }
84     }
85     JS_FreeCString(engine_->GetContext(), str);
86 }
87 
GetLength()88 size_t QuickJSNativeString::GetLength()
89 {
90     size_t length = 0;
91     GetCString(nullptr, 0, &length);
92     return length;
93 }
94 
EncodeWriteUtf8(char * buffer,size_t bufferSize,int32_t * nchars)95 size_t QuickJSNativeString::EncodeWriteUtf8(char* buffer, size_t bufferSize, int32_t* nchars)
96 {
97     if (buffer == nullptr || nchars == nullptr) {
98         HILOG_ERROR("buffer is null or nchars is null");
99         return 0;
100     }
101 
102     JSContext* ctx = engine_->GetContext();
103     JSValue lengthVal = JS_GetPropertyStr(ctx, value_, "length");
104     if (JS_IsException(lengthVal)) {
105         HILOG_ERROR("Failed to obtain the length");
106         return 0;
107     }
108     uint32_t len = 0;
109     if (JS_ToUint32(ctx, &len, lengthVal)) {
110         JS_FreeValue(ctx, lengthVal);
111         HILOG_ERROR("Cannot convert length to uint32_t");
112         return 0;
113     }
114 
115     size_t pos = 0;
116     size_t writableSize = bufferSize;
117     uint32_t i = 0;
118     for (; i < len; i++) {
119         JSValue ch = JS_GetPropertyUint32(ctx, value_, i);
120         size_t chLen = 0;
121         const char* str = JS_ToCStringLen(ctx, &chLen, ch);
122         JS_FreeValue(ctx, ch);
123         if (chLen > writableSize) {
124             JS_FreeCString(ctx, str);
125             break;
126         }
127 
128         int ret = memcpy_s((buffer + pos), writableSize, str, chLen);
129         if (ret != EOK) {
130             HILOG_ERROR("memcpy_s failed");
131             JS_FreeCString(ctx, str);
132             break;
133         }
134 
135         writableSize -= chLen;
136         pos = bufferSize - writableSize;
137         JS_FreeCString(ctx, str);
138     }
139 
140     *nchars = i;
141     JS_FreeValue(ctx, lengthVal);
142     return pos;
143 }
144 
Utf8ToUtf16(const char * utf8Str,size_t u8len,char16_t * u16str,size_t u16len)145 char16_t* QuickJSNativeString::Utf8ToUtf16(const char* utf8Str, size_t u8len, char16_t* u16str, size_t u16len)
146 {
147     if (u16len == 0) {
148         return u16str;
149     }
150     const char* u8end = utf8Str + u8len;
151     const char* u8cur = utf8Str;
152     const char16_t* u16end = u16str + u16len - 1;
153     constexpr uint8_t  offset = 10;
154     char16_t* u16cur = u16str;
155 
156     while ((u8cur < u8end) && (u16cur < u16end)) {
157         size_t len = Utf8CodePointLen(*u8cur);
158         uint32_t codepoint = Utf8ToUtf32CodePoint(u8cur, len);
159         // Convert the UTF32 codepoint to one or more UTF16 codepoints
160         if (codepoint <= 0xFFFF) {
161             // Single UTF16 character
162             *u16cur++ = (char16_t)codepoint;
163         } else {
164             // Multiple UTF16 characters with surrogates
165             codepoint = codepoint - 0x10000;
166             *u16cur++ = (char16_t)((codepoint >> offset) + 0xD800);
167             if (u16cur >= u16end) {
168                 // Ooops...  not enough room for this surrogate pair.
169                 return u16cur - 1;
170             }
171             *u16cur++ = (char16_t)((codepoint & 0x3FF) + 0xDC00);
172         }
173 
174         u8cur += len;
175     }
176     return u16cur;
177 }
178 
Utf8CodePointLen(uint8_t ch)179 size_t QuickJSNativeString::Utf8CodePointLen(uint8_t ch)
180 {
181     constexpr uint8_t offset = 3;
182     return ((0xe5000000 >> ((ch >> offset) & 0x1e)) & offset) + 1;
183 }
184 
Utf8ToUtf32CodePoint(const char * src,size_t length)185 uint32_t QuickJSNativeString::Utf8ToUtf32CodePoint(const char* src, size_t length)
186 {
187     uint32_t unicode = 0;
188     constexpr size_t lengthSizeOne = 1;
189     constexpr size_t lengthSizeTwo = 2;
190     constexpr size_t lengthSizeThree = 3;
191     constexpr size_t lengthSizeFour = 4;
192     constexpr size_t offsetZero = 0;
193     constexpr size_t offsetOne = 1;
194     constexpr size_t offsetTwo = 2;
195     constexpr size_t offsetThree = 3;
196     switch (length) {
197         case lengthSizeOne:
198             return src[offsetZero];
199         case lengthSizeTwo:
200             unicode = src[offsetZero] & 0x1f;
201             Utf8ShiftAndMask(&unicode, src[offsetOne]);
202             return unicode;
203         case lengthSizeThree:
204             unicode = src[offsetZero] & 0x0f;
205             Utf8ShiftAndMask(&unicode, src[offsetOne]);
206             Utf8ShiftAndMask(&unicode, src[offsetTwo]);
207             return unicode;
208         case lengthSizeFour:
209             unicode = src[offsetZero] & 0x07;
210             Utf8ShiftAndMask(&unicode, src[offsetOne]);
211             Utf8ShiftAndMask(&unicode, src[offsetTwo]);
212             Utf8ShiftAndMask(&unicode, src[offsetThree]);
213             return unicode;
214         default:
215             return 0xffff;
216     }
217 }
218 
Utf8ShiftAndMask(uint32_t * codePoint,const uint8_t byte)219 void QuickJSNativeString::Utf8ShiftAndMask(uint32_t* codePoint, const uint8_t byte)
220 {
221     *codePoint <<= 6;
222     *codePoint |= 0x3F & byte;
223 }
224 
Utf8ToUtf16Length(const char * str8,size_t str8Len)225 int QuickJSNativeString::Utf8ToUtf16Length(const char* str8, size_t str8Len)
226 {
227     const char* str8end = str8 + str8Len;
228     int utf16len = 0;
229     while (str8 < str8end) {
230         utf16len++;
231         size_t u8charlen = Utf8CodePointLen(*str8);
232         if (str8 + u8charlen - 1 >= str8end) {
233             HILOG_ERROR("Get str16 length failed because str8 unicode is illegal!");
234             return -1;
235         }
236         uint32_t codepoint = Utf8ToUtf32CodePoint(str8, u8charlen);
237         if (codepoint > 0xFFFF) {
238             utf16len++; // this will be a surrogate pair in utf16
239         }
240         str8 += u8charlen;
241     }
242     if (str8 != str8end) {
243         HILOG_ERROR("Get str16 length failed because str8length is illegal!");
244         return -1;
245     }
246     return utf16len;
247 }
248