1 /** 2 * Copyright (c) 2021-2022 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 panda::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 length)43 static EtsString *CreateFromMUtf8(const char *mutf8, uint32_t length) 44 { 45 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 46 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 47 if (length == 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, length, 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 CreateFromUtf16(const ets_char * utf16,ets_int length)78 static EtsString *CreateFromUtf16(const ets_char *utf16, ets_int length) 79 { 80 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 81 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 82 if (length == 0) { 83 return reinterpret_cast<EtsString *>( 84 coretypes::String::CreateEmptyString(ctx, Runtime::GetCurrent()->GetPandaVM())); 85 } 86 if (utf16 == nullptr) { 87 ThrowNullPointerException(ctx, ManagedThread::GetCurrent()); 88 return nullptr; 89 } 90 coretypes::String *s = 91 coretypes::String::CreateFromUtf16(utf16, length, ctx, Runtime::GetCurrent()->GetPandaVM()); 92 return reinterpret_cast<EtsString *>(s); 93 } 94 CreateNewStringFromChars(uint32_t offset,uint32_t length,EtsArray * chararray)95 static EtsString *CreateNewStringFromChars(uint32_t offset, uint32_t length, EtsArray *chararray) 96 { 97 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 98 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 99 return reinterpret_cast<EtsString *>(coretypes::String::CreateNewStringFromChars( 100 offset, length, reinterpret_cast<coretypes::Array *>(chararray), ctx, Runtime::GetCurrent()->GetPandaVM())); 101 } 102 CreateNewStringFromBytes(EtsArray * bytearray,ets_int high,ets_int offset,ets_int length)103 static EtsString *CreateNewStringFromBytes(EtsArray *bytearray, ets_int high, ets_int offset, ets_int length) 104 { 105 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 106 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 107 if (length == 0) { 108 return reinterpret_cast<EtsString *>( 109 coretypes::String::CreateEmptyString(ctx, Runtime::GetCurrent()->GetPandaVM())); 110 } 111 if (bytearray == nullptr) { 112 ThrowNullPointerException(ctx, ManagedThread::GetCurrent()); 113 return nullptr; 114 } 115 if (offset < 0 || length < 0 || bytearray->GetLength() < static_cast<uint32_t>(offset + length)) { 116 ThrowArrayIndexOutOfBoundsException(static_cast<uint32_t>(offset + length), bytearray->GetLength(), ctx, 117 ManagedThread::GetCurrent()); 118 return nullptr; 119 } 120 return reinterpret_cast<EtsString *>(coretypes::String::CreateNewStringFromBytes( 121 offset, length, static_cast<uint32_t>(high), reinterpret_cast<coretypes::Array *>(bytearray), ctx, 122 Runtime::GetCurrent()->GetPandaVM())); 123 } 124 CreateNewStringFromString(EtsString * etsString)125 static EtsString *CreateNewStringFromString(EtsString *etsString) 126 { 127 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 128 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 129 if (etsString == nullptr) { 130 ThrowNullPointerException(ctx, ManagedThread::GetCurrent()); 131 return nullptr; 132 } 133 coretypes::String *string = etsString->GetCoreType(); 134 return reinterpret_cast<EtsString *>( 135 coretypes::String::CreateFromString(string, ctx, Runtime::GetCurrent()->GetPandaVM())); 136 } 137 CreateNewEmptyString()138 static EtsString *CreateNewEmptyString() 139 { 140 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 141 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 142 return reinterpret_cast<EtsString *>( 143 coretypes::String::CreateEmptyString(ctx, Runtime::GetCurrent()->GetPandaVM())); 144 } 145 Resolve(const uint8_t * mutf8,uint32_t length)146 static EtsString *Resolve(const uint8_t *mutf8, uint32_t length) 147 { 148 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 149 return reinterpret_cast<EtsString *>( 150 Runtime::GetCurrent()->ResolveString(Runtime::GetCurrent()->GetPandaVM(), mutf8, length, ctx)); 151 } 152 Concat(EtsString * etsString1,EtsString * etsString2)153 static EtsString *Concat(EtsString *etsString1, EtsString *etsString2) 154 { 155 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 156 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 157 coretypes::String *string3 = coretypes::String::Concat(etsString1->GetCoreType(), etsString2->GetCoreType(), 158 ctx, Runtime::GetCurrent()->GetPandaVM()); 159 return reinterpret_cast<EtsString *>(string3); 160 } 161 Compare(EtsString * rhs)162 int32_t Compare(EtsString *rhs) 163 { 164 return GetCoreType()->Compare(rhs->GetCoreType()); 165 } 166 At(int32_t index)167 uint16_t At(int32_t index) 168 { 169 return GetCoreType()->At(index); 170 } 171 DoReplace(EtsString * src,ets_char oldC,ets_char newC)172 static EtsString *DoReplace(EtsString *src, ets_char oldC, ets_char newC) 173 { 174 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 175 if (src->GetLength() == 0) { 176 return reinterpret_cast<EtsString *>( 177 coretypes::String::CreateEmptyString(ctx, Runtime::GetCurrent()->GetPandaVM())); 178 } 179 coretypes::String *result = coretypes::String::DoReplace(reinterpret_cast<coretypes::String *>(src), oldC, newC, 180 ctx, Runtime::GetCurrent()->GetPandaVM()); 181 return reinterpret_cast<EtsString *>(result); 182 } 183 FastSubString(EtsString * src,uint32_t start,uint32_t length)184 static EtsString *FastSubString(EtsString *src, uint32_t start, uint32_t length) 185 { 186 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 187 coretypes::String *string1 = src->GetCoreType(); 188 coretypes::String *string2 = 189 coretypes::String::FastSubString(string1, start, length, ctx, Runtime::GetCurrent()->GetPandaVM()); 190 return reinterpret_cast<EtsString *>(string2); 191 } 192 ToCharArray()193 EtsArray *ToCharArray() 194 { 195 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 196 auto *ret = GetCoreType()->ToCharArray(ctx); 197 if (UNLIKELY(ret == nullptr)) { 198 return nullptr; 199 } 200 return reinterpret_cast<EtsArray *>(ret); 201 } 202 IsUtf16()203 bool IsUtf16() 204 { 205 return GetCoreType()->IsUtf16(); 206 } 207 GetLength()208 ets_int GetLength() 209 { 210 return GetCoreType()->GetLength(); 211 } 212 CopyDataMUtf8(void * buf,size_t maxLength,bool isCString)213 size_t CopyDataMUtf8(void *buf, size_t maxLength, bool isCString) 214 { 215 return GetCoreType()->CopyDataMUtf8(reinterpret_cast<uint8_t *>(buf), maxLength, isCString); 216 } 217 CopyDataRegionMUtf8(void * buf,size_t start,size_t length,size_t maxLength)218 size_t CopyDataRegionMUtf8(void *buf, size_t start, size_t length, size_t maxLength) 219 { 220 return GetCoreType()->CopyDataRegionMUtf8(reinterpret_cast<uint8_t *>(buf), start, length, maxLength); 221 } 222 CopyDataUtf16(void * buf,uint32_t maxLength)223 uint32_t CopyDataUtf16(void *buf, uint32_t maxLength) 224 { 225 return GetCoreType()->CopyDataUtf16(reinterpret_cast<uint16_t *>(buf), maxLength); 226 } 227 CopyDataRegionUtf16(void * buf,uint32_t start,uint32_t length,uint32_t maxLength)228 uint32_t CopyDataRegionUtf16(void *buf, uint32_t start, uint32_t length, uint32_t maxLength) 229 { 230 return GetCoreType()->CopyDataRegionUtf16(reinterpret_cast<uint16_t *>(buf), start, length, maxLength); 231 } 232 ConvertToStringView(PandaVector<uint8_t> * buf)233 std::string_view ConvertToStringView(PandaVector<uint8_t> *buf) 234 { 235 if (IsUtf16()) { 236 size_t len = utf::Utf16ToMUtf8Size(GetDataUtf16(), GetUtf16Length()) - 1; 237 buf->reserve(len); 238 utf::ConvertRegionUtf16ToMUtf8(GetDataUtf16(), buf->data(), GetUtf16Length(), len, 0); 239 return {utf::Mutf8AsCString(buf->data()), len}; 240 } 241 return {utf::Mutf8AsCString(GetDataMUtf8()), static_cast<size_t>(GetLength())}; 242 } 243 GetMUtf8Length()244 uint32_t GetMUtf8Length() 245 { 246 return GetCoreType()->GetMUtf8Length(); 247 } 248 GetUtf16Length()249 uint32_t GetUtf16Length() 250 { 251 return GetCoreType()->GetUtf16Length(); 252 } 253 IsEqual(const char * str)254 bool IsEqual(const char *str) 255 { 256 auto *mutf8Str = utf::CStringAsMutf8(str); 257 return coretypes::String::StringsAreEqualMUtf8(GetCoreType(), mutf8Str, utf::Mutf8Size(mutf8Str)); 258 } 259 GetMutf8()260 PandaString GetMutf8() 261 { 262 size_t len = GetMUtf8Length() - 1; 263 PandaString out; 264 out.resize(len); 265 CopyDataMUtf8(out.data(), len, false); 266 return out; 267 } 268 GetDataMUtf8()269 uint8_t *GetDataMUtf8() 270 { 271 return GetCoreType()->GetDataMUtf8(); 272 } 273 GetDataUtf16()274 uint16_t *GetDataUtf16() 275 { 276 return GetCoreType()->GetDataUtf16(); 277 } 278 IsEmpty()279 bool IsEmpty() 280 { 281 return GetCoreType()->IsEmpty(); 282 } 283 StringsAreEqual(EtsObject * obj)284 bool StringsAreEqual(EtsObject *obj) 285 { 286 return coretypes::String::StringsAreEqual(GetCoreType(), FromEtsObject(obj)->GetCoreType()); 287 } 288 GetCoreType()289 coretypes::String *GetCoreType() 290 { 291 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 292 return reinterpret_cast<coretypes::String *>(this); 293 } 294 AsObject()295 EtsObject *AsObject() 296 { 297 return reinterpret_cast<EtsObject *>(this); 298 } 299 AsObject()300 const EtsObject *AsObject() const 301 { 302 return reinterpret_cast<const EtsObject *>(this); 303 } 304 FromCoreType(coretypes::String * str)305 static EtsString *FromCoreType(coretypes::String *str) 306 { 307 return reinterpret_cast<EtsString *>(str); 308 } 309 FromEtsObject(EtsObject * obj)310 static EtsString *FromEtsObject(EtsObject *obj) 311 { 312 ASSERT(obj->GetClass()->GetRuntimeClass() == Runtime::GetCurrent() 313 ->GetClassLinker() 314 ->GetExtension(panda_file::SourceLang::ETS) 315 ->GetClassRoot(ClassRoot::STRING)); 316 return reinterpret_cast<EtsString *>(obj); 317 } 318 319 EtsString() = delete; 320 ~EtsString() = delete; 321 322 NO_COPY_SEMANTIC(EtsString); 323 NO_MOVE_SEMANTIC(EtsString); 324 325 private: 326 friend EtsString *StringBuilderToString(ObjectHeader *sb); 327 AllocateNonInitializedString(uint32_t length,bool compressed)328 static EtsString *AllocateNonInitializedString(uint32_t length, bool compressed) 329 { 330 ASSERT(length != 0); 331 ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); 332 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS); 333 return reinterpret_cast<EtsString *>( 334 coretypes::String::AllocStringObject(length, compressed, ctx, Runtime::GetCurrent()->GetPandaVM())); 335 } 336 }; 337 338 } // namespace panda::ets 339 340 #endif // PANDA_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_STRING_H 341