• 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 
Compare(EtsString * rhs)227     int32_t Compare(EtsString *rhs)
228     {
229         return GetCoreType()->Compare(rhs->GetCoreType());
230     }
231 
At(int32_t index)232     uint16_t At(int32_t index)
233     {
234         return GetCoreType()->At(index);
235     }
236 
DoReplace(EtsString * src,ets_char oldC,ets_char newC)237     static EtsString *DoReplace(EtsString *src, ets_char oldC, ets_char newC)
238     {
239         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
240         if (src->GetLength() == 0) {
241             return reinterpret_cast<EtsString *>(
242                 coretypes::String::CreateEmptyString(ctx, Runtime::GetCurrent()->GetPandaVM()));
243         }
244         coretypes::String *result = coretypes::String::DoReplace(reinterpret_cast<coretypes::String *>(src), oldC, newC,
245                                                                  ctx, Runtime::GetCurrent()->GetPandaVM());
246         return reinterpret_cast<EtsString *>(result);
247     }
248 
FastSubString(EtsString * src,uint32_t start,uint32_t length)249     static EtsString *FastSubString(EtsString *src, uint32_t start, uint32_t length)
250     {
251         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
252         coretypes::String *string1 = src->GetCoreType();
253         coretypes::String *string2 =
254             coretypes::String::FastSubString(string1, start, length, ctx, Runtime::GetCurrent()->GetPandaVM());
255         return reinterpret_cast<EtsString *>(string2);
256     }
257 
ToCharArray()258     EtsArray *ToCharArray()
259     {
260         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
261         auto *ret = GetCoreType()->ToCharArray(ctx);
262         if (UNLIKELY(ret == nullptr)) {
263             return nullptr;
264         }
265         return reinterpret_cast<EtsArray *>(ret);
266     }
267 
IsUtf16()268     bool IsUtf16()
269     {
270         return GetCoreType()->IsUtf16();
271     }
272 
GetLength()273     ets_int GetLength()
274     {
275         return GetCoreType()->GetLength();
276     }
277 
CopyDataMUtf8(void * buf,size_t maxLength,bool isCString)278     size_t CopyDataMUtf8(void *buf, size_t maxLength, bool isCString)
279     {
280         return GetCoreType()->CopyDataMUtf8(reinterpret_cast<uint8_t *>(buf), maxLength, isCString);
281     }
282 
CopyDataRegionMUtf8(void * buf,size_t start,size_t length,size_t maxLength)283     size_t CopyDataRegionMUtf8(void *buf, size_t start, size_t length, size_t maxLength)
284     {
285         return GetCoreType()->CopyDataRegionMUtf8(reinterpret_cast<uint8_t *>(buf), start, length, maxLength);
286     }
287 
CopyDataUtf16(void * buf,uint32_t maxLength)288     uint32_t CopyDataUtf16(void *buf, uint32_t maxLength)
289     {
290         return GetCoreType()->CopyDataUtf16(reinterpret_cast<uint16_t *>(buf), maxLength);
291     }
292 
CopyDataRegionUtf16(void * buf,uint32_t start,uint32_t length,uint32_t maxLength)293     uint32_t CopyDataRegionUtf16(void *buf, uint32_t start, uint32_t length, uint32_t maxLength)
294     {
295         return GetCoreType()->CopyDataRegionUtf16(reinterpret_cast<uint16_t *>(buf), start, length, maxLength);
296     }
297 
ConvertToStringView(PandaVector<uint8_t> * buf)298     std::string_view ConvertToStringView(PandaVector<uint8_t> *buf)
299     {
300         if (IsUtf16()) {
301             size_t len = utf::Utf16ToMUtf8Size(GetDataUtf16(), GetUtf16Length()) - 1;
302             buf->reserve(len);
303             utf::ConvertRegionUtf16ToMUtf8(GetDataUtf16(), buf->data(), GetUtf16Length(), len, 0);
304             return {utf::Mutf8AsCString(buf->data()), len};
305         }
306         return {utf::Mutf8AsCString(GetDataMUtf8()), static_cast<size_t>(GetLength())};
307     }
308 
GetMUtf8Length()309     uint32_t GetMUtf8Length()
310     {
311         return GetCoreType()->GetMUtf8Length();
312     }
313 
GetUtf16Length()314     uint32_t GetUtf16Length()
315     {
316         return GetCoreType()->GetUtf16Length();
317     }
318 
IsEqual(const char * str)319     bool IsEqual(const char *str)
320     {
321         auto *mutf8Str = utf::CStringAsMutf8(str);
322         return coretypes::String::StringsAreEqualMUtf8(GetCoreType(), mutf8Str, utf::MUtf8ToUtf16Size(mutf8Str));
323     }
324 
GetMutf8()325     PandaString GetMutf8()
326     {
327         size_t len = GetMUtf8Length() - 1;
328         PandaString out;
329         out.resize(len);
330         CopyDataMUtf8(out.data(), len, false);
331         return out;
332     }
333 
GetDataMUtf8()334     uint8_t *GetDataMUtf8()
335     {
336         return GetCoreType()->GetDataMUtf8();
337     }
338 
GetDataUtf16()339     uint16_t *GetDataUtf16()
340     {
341         return GetCoreType()->GetDataUtf16();
342     }
343 
IsEmpty()344     bool IsEmpty()
345     {
346         return GetCoreType()->IsEmpty();
347     }
348 
StringsAreEqual(EtsObject * obj)349     bool StringsAreEqual(EtsObject *obj)
350     {
351         return coretypes::String::StringsAreEqual(GetCoreType(), FromEtsObject(obj)->GetCoreType());
352     }
353 
GetCoreType()354     coretypes::String *GetCoreType()
355     {
356         ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
357         return reinterpret_cast<coretypes::String *>(this);
358     }
359 
AsObject()360     EtsObject *AsObject()
361     {
362         return reinterpret_cast<EtsObject *>(this);
363     }
364 
AsObject()365     const EtsObject *AsObject() const
366     {
367         return reinterpret_cast<const EtsObject *>(this);
368     }
369 
FromCoreType(coretypes::String * str)370     static EtsString *FromCoreType(coretypes::String *str)
371     {
372         return reinterpret_cast<EtsString *>(str);
373     }
374 
FromEtsObject(EtsObject * obj)375     static EtsString *FromEtsObject(EtsObject *obj)
376     {
377         ASSERT(obj->GetClass()->GetRuntimeClass() == Runtime::GetCurrent()
378                                                          ->GetClassLinker()
379                                                          ->GetExtension(panda_file::SourceLang::ETS)
380                                                          ->GetClassRoot(ClassRoot::STRING));
381         return reinterpret_cast<EtsString *>(obj);
382     }
383 
384     EtsString() = delete;
385     ~EtsString() = delete;
386 
387     NO_COPY_SEMANTIC(EtsString);
388     NO_MOVE_SEMANTIC(EtsString);
389 
390 private:
391     friend EtsString *StringBuilderToString(ObjectHeader *sb);
392 
AllocateNonInitializedString(uint32_t length,bool compressed)393     static EtsString *AllocateNonInitializedString(uint32_t length, bool compressed)
394     {
395         ASSERT(length != 0);
396         ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
397         LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
398         return reinterpret_cast<EtsString *>(
399             coretypes::String::AllocStringObject(length, compressed, ctx, Runtime::GetCurrent()->GetPandaVM()));
400     }
401 };
402 
403 }  // namespace ark::ets
404 
405 #endif  // PANDA_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_STRING_H_
406