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 "ark_native_string.h"
17 #if !defined(PREVIEW) && !defined(IOS_PLATFORM)
18 #include "ohos/init_data.h"
19 #else
20 #include "unicode/putil.h"
21 #endif
22 #include "securec.h"
23 #include "unicode/ucnv.h"
24 #include "utils/log.h"
25
26 using panda::StringRef;
27 using panda::ObjectRef;
ArkNativeString(ArkNativeEngine * engine,const char * value,size_t length)28 ArkNativeString::ArkNativeString(ArkNativeEngine* engine, const char* value, size_t length)
29 : ArkNativeString(engine, JSValueRef::Undefined(engine->GetEcmaVm()))
30 {
31 auto vm = engine->GetEcmaVm();
32 LocalScope scope(vm);
33 Local<StringRef> object = StringRef::NewFromUtf8(vm, value, length);
34 value_ = Global<StringRef>(vm, object);
35 }
ArkNativeString(ArkNativeEngine * engine,const char16_t * value,size_t length)36 ArkNativeString::ArkNativeString(ArkNativeEngine* engine, const char16_t* value, size_t length)
37 : ArkNativeString(engine, JSValueRef::Undefined(engine->GetEcmaVm()))
38 {
39 auto vm = engine->GetEcmaVm();
40 LocalScope scope(vm);
41 Local<StringRef> object = StringRef::NewFromUtf16(vm, value, length);
42 value_ = Global<StringRef>(vm, object);
43 }
ArkNativeString(ArkNativeEngine * engine,Local<JSValueRef> value)44 ArkNativeString::ArkNativeString(ArkNativeEngine* engine, Local<JSValueRef> value) : ArkNativeValue(engine, value) {}
45
~ArkNativeString()46 ArkNativeString::~ArkNativeString() {}
47
GetInterface(int interfaceId)48 void* ArkNativeString::GetInterface(int interfaceId)
49 {
50 return (NativeString::INTERFACE_ID == interfaceId) ? (NativeString*)this : nullptr;
51 }
52
GetCString(char * buffer,size_t size,size_t * length)53 void ArkNativeString::GetCString(char* buffer, size_t size, size_t* length)
54 {
55 if (length == nullptr) {
56 return;
57 }
58 auto vm = engine_->GetEcmaVm();
59 LocalScope scope(vm);
60 Global<StringRef> val = value_;
61 if (buffer == nullptr) {
62 *length = val->Utf8Length(vm) - 1;
63 } else if (size != 0) {
64 int copied = val->WriteUtf8(buffer, size - 1, true) - 1;
65 buffer[copied] = '\0';
66 *length = copied;
67 } else {
68 *length = 0;
69 }
70 }
71
GetCStringLatin1(char * buffer,size_t size,size_t * length)72 void ArkNativeString::GetCStringLatin1(char* buffer, size_t size, size_t* length)
73 {
74 if (length == nullptr) {
75 return;
76 }
77 auto vm = engine_->GetEcmaVm();
78 LocalScope scope(vm);
79 Global<StringRef> val = value_;
80 if (buffer == nullptr) {
81 *length = val->Length();
82 } else if (size != 0) {
83 int copied = val->WriteLatin1(buffer, size);
84 buffer[copied] = '\0';
85 *length = copied;
86 } else {
87 *length = 0;
88 }
89 }
90
GetCString16(char16_t * buffer,size_t bufSize,size_t * copyLength)91 void ArkNativeString::GetCString16(char16_t* buffer, size_t bufSize, size_t* copyLength)
92 {
93 if (copyLength == nullptr) {
94 return;
95 }
96 auto vm = engine_->GetEcmaVm();
97 LocalScope scope(vm);
98 Global<StringRef> val = value_;
99 if (buffer == nullptr) {
100 *copyLength = val->Length();
101 } else if (bufSize == 1) {
102 buffer[0] = '\0';
103 *copyLength = 0;
104 } else if (bufSize != 0) {
105 int copied = val->WriteUtf16(buffer, bufSize - 1); // bufSize - 1 :reserve the position of buffer "\0"
106 buffer[copied] = '\0';
107 *copyLength = copied;
108 } else {
109 *copyLength = 0;
110 }
111 }
112
GetLength()113 size_t ArkNativeString::GetLength()
114 {
115 auto vm = engine_->GetEcmaVm();
116 LocalScope scope(vm);
117 Global<StringRef> value = value_;
118 return value->Utf8Length(vm) - 1;
119 }
120
EncodeWriteUtf8(char * buffer,size_t bufferSize,int32_t * nchars)121 size_t ArkNativeString::EncodeWriteUtf8(char* buffer, size_t bufferSize, int32_t* nchars)
122 {
123 if (buffer == nullptr || nchars == nullptr) {
124 HILOG_ERROR("buffer is null or nchars is null");
125 return 0;
126 }
127
128 auto vm = engine_->GetEcmaVm();
129 LocalScope scope(vm);
130 Global<StringRef> val = value_;
131 int32_t length = val->Length();
132
133 int32_t pos = 0;
134 int32_t writableSize = static_cast<int32_t>(bufferSize);
135 int32_t i = 0;
136 Local<ObjectRef> strObj = Local<ObjectRef>(val.ToLocal(vm));
137 for (; i < length; i++) {
138 Local<StringRef> str = Local<StringRef>(strObj->Get(vm, i));
139 int32_t len = str->Utf8Length(vm) - 1;
140 if (len > writableSize) {
141 break;
142 }
143
144 str->WriteUtf8((buffer + pos), writableSize);
145 writableSize -= len;
146 pos += len;
147 }
148
149 *nchars = i;
150 HILOG_DEBUG("EncodeWriteUtf8 the result of buffer: %{public}s", buffer);
151 return pos;
152 }
153
EncodeWriteChinese(std::string & buffer,const char * encoding)154 void ArkNativeString::EncodeWriteChinese(std::string& buffer, const char* encoding)
155 {
156 if (encoding == nullptr) {
157 HILOG_ERROR("encoding is nullptr");
158 return;
159 }
160 auto vm = engine_->GetEcmaVm();
161 LocalScope scope(vm);
162 Global<StringRef> val = value_;
163 int32_t length = val->Length();
164 Local<ObjectRef> strObj = Local<ObjectRef>(val.ToLocal(vm));
165
166 int32_t pos = 0;
167 const int32_t writableSize = 22; // 22 : encode max bytes of the ucnv_convent function;
168
169 std::string tempBuf = "";
170 tempBuf.resize(writableSize + 1);
171
172 UErrorCode ErrorCode = U_ZERO_ERROR;
173 const char* encFrom = "utf8";
174 for (int32_t i = 0; i < length; i++) {
175 Local<StringRef> str = Local<StringRef>(strObj->Get(vm, i));
176 int32_t len = str->Utf8Length(vm) - 1;
177 if ((pos + len) >= writableSize) {
178 char outBuf[writableSize] = {0};
179 ucnv_convert(encoding, encFrom, outBuf, writableSize, tempBuf.c_str(), pos, &ErrorCode);
180 if (ErrorCode != U_ZERO_ERROR) {
181 HILOG_ERROR("ucnv_convert is failed : ErrorCode = %{public}d", static_cast<int32_t>(ErrorCode));
182 return;
183 }
184 buffer += outBuf;
185 tempBuf.clear();
186 pos = 0;
187 }
188 str->WriteUtf8((tempBuf.data() + pos), writableSize);
189 pos += len;
190 }
191 if (pos > 0) {
192 char outBuf[writableSize] = {0};
193 ucnv_convert(encoding, encFrom, outBuf, writableSize, tempBuf.c_str(), pos, &ErrorCode);
194 if (ErrorCode != U_ZERO_ERROR) {
195 HILOG_ERROR("ucnv_convert is failed : ErrorCode = %{public}d", static_cast<int32_t>(ErrorCode));
196 return;
197 }
198 buffer += outBuf;
199 }
200 }
201