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