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