• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 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 PANDA_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_STRING_H_
17 #define PANDA_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_STRING_H_
18 
19 #include "runtime/include/runtime.h"
20 #include "runtime/include/coretypes/string-inl.h"
21 #include "plugins/ets/runtime/types/ets_array.h"
22 #include "plugins/ets/runtime/types/ets_object.h"
23 #include "plugins/ets/runtime/napi/ets_napi.h"
24 
25 namespace ark::ets {
26 
27 // Private inheritance, because need to disallow implicit conversion to core type
28 class EtsString : private coretypes::String {
29 public:
CreateFromMUtf8(const char * mutf8)30     static EtsString *CreateFromMUtf8(const char *mutf8)
31     {
32         ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
33         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
34         if (mutf8 == nullptr) {
35             ThrowNullPointerException(ctx, ManagedThread::GetCurrent());
36             return nullptr;
37         }
38         const auto *data = reinterpret_cast<const uint8_t *>(mutf8);
39         coretypes::String *s = coretypes::String::CreateFromMUtf8(data, ctx, Runtime::GetCurrent()->GetPandaVM());
40         return reinterpret_cast<EtsString *>(s);
41     }
42 
CreateFromMUtf8(const char * mutf8,uint32_t utf16Length)43     static EtsString *CreateFromMUtf8(const char *mutf8, uint32_t utf16Length)
44     {
45         ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
46         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
47         if (utf16Length == 0) {
48             return reinterpret_cast<EtsString *>(
49                 coretypes::String::CreateEmptyString(ctx, Runtime::GetCurrent()->GetPandaVM()));
50         }
51         if (mutf8 == nullptr) {
52             ThrowNullPointerException(ctx, ManagedThread::GetCurrent());
53             return nullptr;
54         }
55         const auto *data = reinterpret_cast<const uint8_t *>(mutf8);
56         coretypes::String *s =
57             coretypes::String::CreateFromMUtf8(data, utf16Length, ctx, Runtime::GetCurrent()->GetPandaVM());
58         return reinterpret_cast<EtsString *>(s);
59     }
60 
CreateFromUtf8(const char * utf8,uint32_t length)61     static EtsString *CreateFromUtf8(const char *utf8, uint32_t length)
62     {
63         ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
64         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
65         if (length == 0) {
66             return reinterpret_cast<EtsString *>(
67                 coretypes::String::CreateEmptyString(ctx, Runtime::GetCurrent()->GetPandaVM()));
68         }
69         if (utf8 == nullptr) {
70             ThrowNullPointerException(ctx, ManagedThread::GetCurrent());
71             return nullptr;
72         }
73         const auto *data = reinterpret_cast<const uint8_t *>(utf8);
74         return reinterpret_cast<EtsString *>(
75             coretypes::String::CreateFromUtf8(data, length, ctx, Runtime::GetCurrent()->GetPandaVM()));
76     }
77 
CreateFromAscii(const char * str,uint32_t length)78     static EtsString *CreateFromAscii(const char *str, uint32_t length)
79     {
80         ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
81         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
82         const auto *data = reinterpret_cast<const uint8_t *>(str);
83         return reinterpret_cast<EtsString *>(
84             coretypes::String::CreateFromMUtf8(data, length, length, true, ctx, Runtime::GetCurrent()->GetPandaVM()));
85     }
86 
CreateFromUtf16(const ets_char * utf16,ets_int length)87     static EtsString *CreateFromUtf16(const ets_char *utf16, ets_int length)
88     {
89         ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
90         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
91         if (length == 0) {
92             return reinterpret_cast<EtsString *>(
93                 coretypes::String::CreateEmptyString(ctx, Runtime::GetCurrent()->GetPandaVM()));
94         }
95         if (utf16 == nullptr) {
96             ThrowNullPointerException(ctx, ManagedThread::GetCurrent());
97             return nullptr;
98         }
99         coretypes::String *s =
100             coretypes::String::CreateFromUtf16(utf16, length, ctx, Runtime::GetCurrent()->GetPandaVM());
101         return reinterpret_cast<EtsString *>(s);
102     }
103 
CreateNewStringFromChars(uint32_t offset,uint32_t length,EtsArray * chararray)104     static EtsString *CreateNewStringFromChars(uint32_t offset, uint32_t length, EtsArray *chararray)
105     {
106         ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
107         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
108         return reinterpret_cast<EtsString *>(coretypes::String::CreateNewStringFromChars(
109             offset, length, reinterpret_cast<coretypes::Array *>(chararray), ctx, Runtime::GetCurrent()->GetPandaVM()));
110     }
111 
CreateNewStringFromBytes(EtsArray * bytearray,ets_int high,ets_int offset,ets_int length)112     static EtsString *CreateNewStringFromBytes(EtsArray *bytearray, ets_int high, ets_int offset, ets_int length)
113     {
114         ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
115         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
116         if (length == 0) {
117             return reinterpret_cast<EtsString *>(
118                 coretypes::String::CreateEmptyString(ctx, Runtime::GetCurrent()->GetPandaVM()));
119         }
120         if (bytearray == nullptr) {
121             ThrowNullPointerException(ctx, ManagedThread::GetCurrent());
122             return nullptr;
123         }
124         if (offset < 0 || length < 0 || bytearray->GetLength() < static_cast<uint32_t>(offset + length)) {
125             ThrowArrayIndexOutOfBoundsException(static_cast<uint32_t>(offset + length), bytearray->GetLength(), ctx,
126                                                 ManagedThread::GetCurrent());
127             return nullptr;
128         }
129         return reinterpret_cast<EtsString *>(coretypes::String::CreateNewStringFromBytes(
130             offset, length, static_cast<uint32_t>(high), reinterpret_cast<coretypes::Array *>(bytearray), ctx,
131             Runtime::GetCurrent()->GetPandaVM()));
132     }
133 
CreateNewStringFromString(EtsString * etsString)134     static EtsString *CreateNewStringFromString(EtsString *etsString)
135     {
136         ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
137         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
138         if (etsString == nullptr) {
139             ThrowNullPointerException(ctx, ManagedThread::GetCurrent());
140             return nullptr;
141         }
142         coretypes::String *string = etsString->GetCoreType();
143         return reinterpret_cast<EtsString *>(
144             coretypes::String::CreateFromString(string, ctx, Runtime::GetCurrent()->GetPandaVM()));
145     }
146 
CreateNewEmptyString()147     static EtsString *CreateNewEmptyString()
148     {
149         ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
150         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
151         return reinterpret_cast<EtsString *>(
152             coretypes::String::CreateEmptyString(ctx, Runtime::GetCurrent()->GetPandaVM()));
153     }
154 
Resolve(const uint8_t * mutf8,uint32_t length)155     static EtsString *Resolve(const uint8_t *mutf8, uint32_t length)
156     {
157         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
158         return reinterpret_cast<EtsString *>(
159             Runtime::GetCurrent()->ResolveString(Runtime::GetCurrent()->GetPandaVM(), mutf8, length, ctx));
160     }
161 
Concat(EtsString * etsString1,EtsString * etsString2)162     static EtsString *Concat(EtsString *etsString1, EtsString *etsString2)
163     {
164         ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
165         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
166         coretypes::String *string3 = coretypes::String::Concat(etsString1->GetCoreType(), etsString2->GetCoreType(),
167                                                                ctx, Runtime::GetCurrent()->GetPandaVM());
168         return reinterpret_cast<EtsString *>(string3);
169     }
170 
TrimLeft()171     EtsString *TrimLeft()
172     {
173         if (IsEmpty() || !utf::IsWhiteSpaceChar(At(0))) {
174             return this;
175         }
176         const auto numChars = GetLength();
177         auto notWhiteSpaceIndex = numChars;
178         for (int i = 1; i < numChars; ++i) {
179             if (!utf::IsWhiteSpaceChar(At(i))) {
180                 notWhiteSpaceIndex = i;
181                 break;
182             }
183         }
184         auto len = numChars - notWhiteSpaceIndex;
185         return FastSubString(this, static_cast<uint32_t>(notWhiteSpaceIndex), static_cast<uint32_t>(len));
186     }
187 
TrimRight()188     EtsString *TrimRight()
189     {
190         if (IsEmpty()) {
191             return this;
192         }
193         auto last = GetLength() - 1;
194         if (!utf::IsWhiteSpaceChar(At(last))) {
195             return this;
196         }
197         int notWhiteSpaceIndex = -1;
198         for (int i = last - 1; i >= 0; --i) {
199             if (!utf::IsWhiteSpaceChar(At(i))) {
200                 notWhiteSpaceIndex = i;
201                 break;
202             }
203         }
204         auto len = notWhiteSpaceIndex + 1;
205         return EtsString::FastSubString(this, 0, static_cast<uint32_t>(len));
206     }
207 
Trim()208     EtsString *Trim()
209     {
210         if (IsEmpty()) {
211             return this;
212         }
213         int left = 0;
214         int right = GetLength() - 1;
215         while (utf::IsWhiteSpaceChar(At(right))) {
216             if (right == left) {
217                 return EtsString::CreateNewEmptyString();
218             }
219             --right;
220         }
221         while (left < right && utf::IsWhiteSpaceChar(At(left))) {
222             ++left;
223         }
224         return EtsString::FastSubString(this, left, static_cast<uint32_t>(right - left + 1));
225     }
226 
StartsWith(EtsString * prefix,EtsInt fromIndex)227     EtsBoolean StartsWith(EtsString *prefix, EtsInt fromIndex)
228     {
229         ASSERT(prefix != nullptr);
230         if (fromIndex < 0) {
231             fromIndex = 0;
232         }
233         auto prefixLen = prefix->GetLength();
234         if (fromIndex > GetLength() - prefixLen) {
235             return ToEtsBoolean(prefix->IsEmpty());
236         }
237         auto *thisCoreType = GetCoreType();
238         auto *prefCoreType = prefix->GetCoreType();
239         for (EtsInt i = 0; i < prefixLen; ++i) {
240             if (thisCoreType->At<false>(fromIndex + i) != prefCoreType->At<false>(i)) {
241                 return ToEtsBoolean(false);
242             }
243         }
244         return ToEtsBoolean(true);
245     }
246 
EndsWith(EtsString * suffix,EtsInt endIndex)247     EtsBoolean EndsWith(EtsString *suffix, EtsInt endIndex)
248     {
249         ASSERT(suffix != nullptr);
250         if (suffix->IsEmpty()) {
251             return ToEtsBoolean(true);
252         }
253         auto strLen = GetLength();
254         if (strLen == 0) {
255             return ToEtsBoolean(false);
256         }
257         if (endIndex <= 0) {
258             return ToEtsBoolean(false);
259         }
260         if (endIndex > strLen) {
261             endIndex = strLen;
262         }
263         ASSERT(endIndex > 0);
264         auto suffixLen = suffix->GetLength();
265         auto fromIndex = endIndex - suffixLen;
266         if (fromIndex < 0) {
267             return ToEtsBoolean(false);
268         }
269         auto *thisCoreType = GetCoreType();
270         auto *suffCoreType = suffix->GetCoreType();
271         for (EtsInt i = 0; i < suffixLen; ++i) {
272             if (thisCoreType->At<false>(fromIndex + i) != suffCoreType->At<false>(i)) {
273                 return ToEtsBoolean(false);
274             }
275         }
276         return ToEtsBoolean(true);
277     }
278 
Compare(EtsString * rhs)279     int32_t Compare(EtsString *rhs)
280     {
281         return GetCoreType()->Compare(rhs->GetCoreType());
282     }
283 
At(int32_t index)284     uint16_t At(int32_t index)
285     {
286         return GetCoreType()->At(index);
287     }
288 
DoReplace(EtsString * src,ets_char oldC,ets_char newC)289     static EtsString *DoReplace(EtsString *src, ets_char oldC, ets_char newC)
290     {
291         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
292         if (src->GetLength() == 0) {
293             return reinterpret_cast<EtsString *>(
294                 coretypes::String::CreateEmptyString(ctx, Runtime::GetCurrent()->GetPandaVM()));
295         }
296         coretypes::String *result = coretypes::String::DoReplace(reinterpret_cast<coretypes::String *>(src), oldC, newC,
297                                                                  ctx, Runtime::GetCurrent()->GetPandaVM());
298         return reinterpret_cast<EtsString *>(result);
299     }
300 
FastSubString(EtsString * src,uint32_t start,uint32_t length)301     static EtsString *FastSubString(EtsString *src, uint32_t start, uint32_t length)
302     {
303         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
304         coretypes::String *string1 = src->GetCoreType();
305         coretypes::String *string2 =
306             coretypes::String::FastSubString(string1, start, length, ctx, Runtime::GetCurrent()->GetPandaVM());
307         return reinterpret_cast<EtsString *>(string2);
308     }
309 
ToCharArray()310     EtsArray *ToCharArray()
311     {
312         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
313         auto *ret = GetCoreType()->ToCharArray(ctx);
314         if (UNLIKELY(ret == nullptr)) {
315             return nullptr;
316         }
317         return reinterpret_cast<EtsArray *>(ret);
318     }
319 
IsUtf16()320     bool IsUtf16()
321     {
322         return GetCoreType()->IsUtf16();
323     }
324 
GetLength()325     ets_int GetLength()
326     {
327         return GetCoreType()->GetLength();
328     }
329 
CopyDataMUtf8(void * buf,size_t maxLength,bool isCString)330     size_t CopyDataMUtf8(void *buf, size_t maxLength, bool isCString)
331     {
332         return GetCoreType()->CopyDataMUtf8(reinterpret_cast<uint8_t *>(buf), maxLength, isCString);
333     }
334 
CopyDataRegionMUtf8(void * buf,size_t start,size_t length,size_t maxLength)335     size_t CopyDataRegionMUtf8(void *buf, size_t start, size_t length, size_t maxLength)
336     {
337         return GetCoreType()->CopyDataRegionMUtf8(reinterpret_cast<uint8_t *>(buf), start, length, maxLength);
338     }
339 
CopyDataUtf16(void * buf,uint32_t maxLength)340     uint32_t CopyDataUtf16(void *buf, uint32_t maxLength)
341     {
342         return GetCoreType()->CopyDataUtf16(reinterpret_cast<uint16_t *>(buf), maxLength);
343     }
344 
CopyDataRegionUtf16(void * buf,uint32_t start,uint32_t length,uint32_t maxLength)345     uint32_t CopyDataRegionUtf16(void *buf, uint32_t start, uint32_t length, uint32_t maxLength)
346     {
347         return GetCoreType()->CopyDataRegionUtf16(reinterpret_cast<uint16_t *>(buf), start, length, maxLength);
348     }
349 
ConvertToStringView(PandaVector<uint8_t> * buf)350     std::string_view ConvertToStringView(PandaVector<uint8_t> *buf)
351     {
352         if (IsUtf16()) {
353             size_t len = utf::Utf16ToMUtf8Size(GetDataUtf16(), GetUtf16Length()) - 1;
354             buf->reserve(len);
355             utf::ConvertRegionUtf16ToMUtf8(GetDataUtf16(), buf->data(), GetUtf16Length(), len, 0);
356             return {utf::Mutf8AsCString(buf->data()), len};
357         }
358         return {utf::Mutf8AsCString(GetDataMUtf8()), static_cast<size_t>(GetLength())};
359     }
360 
GetMUtf8Length()361     uint32_t GetMUtf8Length()
362     {
363         return GetCoreType()->GetMUtf8Length();
364     }
365 
GetUtf16Length()366     uint32_t GetUtf16Length()
367     {
368         return GetCoreType()->GetUtf16Length();
369     }
370 
IsEqual(const char * str)371     bool IsEqual(const char *str)
372     {
373         auto *mutf8Str = utf::CStringAsMutf8(str);
374         return coretypes::String::StringsAreEqualMUtf8(GetCoreType(), mutf8Str, utf::MUtf8ToUtf16Size(mutf8Str));
375     }
376 
GetMutf8()377     PandaString GetMutf8()
378     {
379         size_t len = GetMUtf8Length() - 1;
380         PandaString out;
381         out.resize(len);
382         CopyDataMUtf8(out.data(), len, false);
383         return out;
384     }
385 
GetDataMUtf8()386     uint8_t *GetDataMUtf8()
387     {
388         return GetCoreType()->GetDataMUtf8();
389     }
390 
GetDataUtf16()391     uint16_t *GetDataUtf16()
392     {
393         return GetCoreType()->GetDataUtf16();
394     }
395 
IsEmpty()396     bool IsEmpty()
397     {
398         return GetCoreType()->IsEmpty();
399     }
400 
StringsAreEqual(EtsObject * obj)401     bool StringsAreEqual(EtsObject *obj)
402     {
403         return coretypes::String::StringsAreEqual(GetCoreType(), FromEtsObject(obj)->GetCoreType());
404     }
405 
GetCoreType()406     coretypes::String *GetCoreType()
407     {
408         ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
409         return reinterpret_cast<coretypes::String *>(this);
410     }
411 
AsObject()412     EtsObject *AsObject()
413     {
414         return reinterpret_cast<EtsObject *>(this);
415     }
416 
AsObject()417     const EtsObject *AsObject() const
418     {
419         return reinterpret_cast<const EtsObject *>(this);
420     }
421 
FromCoreType(coretypes::String * str)422     static EtsString *FromCoreType(coretypes::String *str)
423     {
424         return reinterpret_cast<EtsString *>(str);
425     }
426 
FromEtsObject(EtsObject * obj)427     static EtsString *FromEtsObject(EtsObject *obj)
428     {
429         ASSERT(obj->GetClass()->GetRuntimeClass() == Runtime::GetCurrent()
430                                                          ->GetClassLinker()
431                                                          ->GetExtension(panda_file::SourceLang::ETS)
432                                                          ->GetClassRoot(ClassRoot::STRING));
433         return reinterpret_cast<EtsString *>(obj);
434     }
435 
436     EtsString() = delete;
437     ~EtsString() = delete;
438 
439     NO_COPY_SEMANTIC(EtsString);
440     NO_MOVE_SEMANTIC(EtsString);
441 
442 private:
443     friend EtsString *StringBuilderToString(ObjectHeader *sb);
444 
AllocateNonInitializedString(uint32_t length,bool compressed)445     static EtsString *AllocateNonInitializedString(uint32_t length, bool compressed)
446     {
447         ASSERT(length != 0);
448         ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
449         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
450         return reinterpret_cast<EtsString *>(
451             coretypes::String::AllocStringObject(length, compressed, ctx, Runtime::GetCurrent()->GetPandaVM()));
452     }
453 };
454 
455 }  // namespace ark::ets
456 
457 #endif  // PANDA_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_STRING_H_
458