1 /* 2 * Copyright (c) 2021 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 ECMASCRIPT_STRING_H 17 #define ECMASCRIPT_STRING_H 18 19 #include <cstddef> 20 #include <cstdint> 21 #include <cstring> 22 23 #include "ecmascript/base/utf_helper.h" 24 #include "ecmascript/ecma_macros.h" 25 #include "ecmascript/js_tagged_value.h" 26 #include "ecmascript/mem/barriers.h" 27 #include "ecmascript/mem/space.h" 28 #include "ecmascript/mem/tagged_object.h" 29 30 #include "libpandabase/macros.h" 31 #include "securec.h" 32 #include "unicode/locid.h" 33 34 namespace panda { 35 namespace ecmascript { 36 template<typename T> 37 class JSHandle; 38 class EcmaVM; 39 class EcmaString : public TaggedObject { 40 public: 41 friend class EcmaStringAccessor; 42 43 CAST_CHECK(EcmaString, IsString); 44 45 static constexpr uint32_t STRING_COMPRESSED_BIT = 0x1; 46 static constexpr uint32_t STRING_INTERN_BIT = 0x2; 47 48 static constexpr size_t MIX_LENGTH_OFFSET = TaggedObjectSize(); 49 // In last bit of mix_length we store if this string is compressed or not. 50 ACCESSORS_PRIMITIVE_FIELD(MixLength, uint32_t, MIX_LENGTH_OFFSET, HASHCODE_OFFSET) 51 ACCESSORS_PRIMITIVE_FIELD(RawHashcode, uint32_t, HASHCODE_OFFSET, SIZE) 52 // DATA_OFFSET: the string data stored after the string header. 53 // Data can be stored in utf8 or utf16 form according to compressed bit. 54 static constexpr size_t DATA_OFFSET = SIZE; // DATA_OFFSET equal to Empty String size 55 56 enum CompressedStatus { 57 STRING_COMPRESSED, 58 STRING_UNCOMPRESSED, 59 }; 60 61 enum TrimMode : uint8_t { 62 TRIM, 63 TRIM_START, 64 TRIM_END, 65 }; 66 67 private: 68 static EcmaString *CreateEmptyString(const EcmaVM *vm); 69 static EcmaString *CreateFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress, 70 MemSpaceType type = MemSpaceType::SEMI_SPACE); 71 static EcmaString *CreateFromUtf16(const EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len, 72 bool canBeCompress, MemSpaceType type = MemSpaceType::SEMI_SPACE); 73 static EcmaString *Concat(const EcmaVM *vm, 74 const JSHandle<EcmaString> &str1Handle, const JSHandle<EcmaString> &str2Handle); 75 static EcmaString *FastSubString(const EcmaVM *vm, 76 const JSHandle<EcmaString> &src, uint32_t start, uint32_t length); 77 78 template<bool verify = true> 79 uint16_t At(int32_t index) const; 80 81 static int32_t Compare(EcmaString *lhs, EcmaString *rhs); 82 IsUtf16()83 bool IsUtf16() const 84 { 85 return (GetMixLength() & STRING_COMPRESSED_BIT) == STRING_UNCOMPRESSED; 86 } 87 IsUtf8()88 bool IsUtf8() const 89 { 90 return (GetMixLength() & STRING_COMPRESSED_BIT) == STRING_COMPRESSED; 91 } 92 ComputeDataSizeUtf16(uint32_t length)93 static size_t ComputeDataSizeUtf16(uint32_t length) 94 { 95 return length * sizeof(uint16_t); 96 } 97 98 /** 99 * Methods for uncompressed strings (UTF16): 100 */ ComputeSizeUtf16(uint32_t utf16Len)101 static size_t ComputeSizeUtf16(uint32_t utf16Len) 102 { 103 return DATA_OFFSET + ComputeDataSizeUtf16(utf16Len); 104 } 105 GetData()106 inline uint16_t *GetData() const 107 { 108 return reinterpret_cast<uint16_t *>(ToUintPtr(this) + DATA_OFFSET); 109 } 110 GetDataUtf16()111 const uint16_t *GetDataUtf16() const 112 { 113 LOG_ECMA_IF(!IsUtf16(), FATAL) << "EcmaString: Read data as utf16 for utf8 string"; 114 return GetData(); 115 } 116 117 /** 118 * Methods for compresses strings (UTF8 or LATIN1): 119 */ ComputeSizeUtf8(uint32_t utf8Len)120 static size_t ComputeSizeUtf8(uint32_t utf8Len) 121 { 122 return DATA_OFFSET + utf8Len; 123 } 124 125 /** 126 * It's Utf8 format, but without 0 in the end. 127 */ GetDataUtf8()128 const uint8_t *GetDataUtf8() const 129 { 130 ASSERT_PRINT(IsUtf8(), "EcmaString: Read data as utf8 for utf16 string"); 131 return reinterpret_cast<uint8_t *>(GetData()); 132 } 133 134 size_t GetUtf8Length(bool modify = true) const 135 { 136 if (!IsUtf16()) { 137 return GetLength() + 1; // add place for zero in the end 138 } 139 return base::utf_helper::Utf16ToUtf8Size(GetData(), GetLength(), modify); 140 } 141 GetUtf16Length()142 size_t GetUtf16Length() const 143 { 144 return GetLength(); 145 } 146 147 inline size_t CopyDataUtf8(uint8_t *buf, size_t maxLength, bool modify = true) const 148 { 149 if (maxLength == 0) { 150 return 1; // maxLength was -1 at napi 151 } 152 size_t length = GetLength(); 153 if (length > maxLength) { 154 return 0; 155 } 156 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 157 buf[maxLength - 1] = '\0'; 158 // Put comparison here so that internal usage and napi can use the same CopyDataRegionUtf8 159 return CopyDataRegionUtf8(buf, 0, length, maxLength, modify) + 1; // add place for zero in the end 160 } 161 162 // It allows user to copy into buffer even if maxLength < length WriteUtf8(uint8_t * buf,size_t maxLength)163 inline size_t WriteUtf8(uint8_t *buf, size_t maxLength) const 164 { 165 if (maxLength == 0) { 166 return 1; // maxLength was -1 at napi 167 } 168 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 169 buf[maxLength - 1] = '\0'; 170 return CopyDataRegionUtf8(buf, 0, GetLength(), maxLength) + 1; // add place for zero in the end 171 } 172 173 size_t CopyDataRegionUtf8(uint8_t *buf, size_t start, size_t length, size_t maxLength, bool modify = true) const 174 { 175 uint32_t len = GetLength(); 176 if (start + length > len) { 177 return 0; 178 } 179 if (!IsUtf16()) { 180 if (length > std::numeric_limits<size_t>::max() / 2 - 1) { // 2: half 181 LOG_FULL(FATAL) << " length is higher than half of size_t::max"; 182 UNREACHABLE(); 183 } 184 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 185 // Only memcpy_s maxLength number of chars into buffer if length > maxLength 186 if (length > maxLength) { 187 if (memcpy_s(buf, maxLength, GetDataUtf8() + start, maxLength) != EOK) { 188 LOG_FULL(FATAL) << "memcpy_s failed when length > maxlength"; 189 UNREACHABLE(); 190 } 191 return maxLength; 192 } 193 if (memcpy_s(buf, maxLength, GetDataUtf8() + start, length) != EOK) { 194 LOG_FULL(FATAL) << "memcpy_s failed when length <= maxlength"; 195 UNREACHABLE(); 196 } 197 return length; 198 } 199 if (length > maxLength) { 200 return base::utf_helper::ConvertRegionUtf16ToUtf8(GetDataUtf16(), buf, maxLength, maxLength, start, modify); 201 } 202 return base::utf_helper::ConvertRegionUtf16ToUtf8(GetDataUtf16(), buf, length, maxLength, start, modify); 203 } 204 CopyDataUtf16(uint16_t * buf,uint32_t maxLength)205 inline uint32_t CopyDataUtf16(uint16_t *buf, uint32_t maxLength) const 206 { 207 return CopyDataRegionUtf16(buf, 0, GetLength(), maxLength); 208 } 209 CopyDataRegionUtf16(uint16_t * buf,uint32_t start,uint32_t length,uint32_t maxLength)210 uint32_t CopyDataRegionUtf16(uint16_t *buf, uint32_t start, uint32_t length, uint32_t maxLength) const 211 { 212 if (length > maxLength) { 213 return 0; 214 } 215 uint32_t len = GetLength(); 216 if (start + length > len) { 217 return 0; 218 } 219 if (IsUtf16()) { 220 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 221 if (memcpy_s(buf, ComputeDataSizeUtf16(maxLength), GetDataUtf16() + start, ComputeDataSizeUtf16(length)) != 222 EOK) { 223 LOG_FULL(FATAL) << "memcpy_s failed"; 224 UNREACHABLE(); 225 } 226 return length; 227 } 228 return base::utf_helper::ConvertRegionUtf8ToUtf16(GetDataUtf8(), buf, len, maxLength, start); 229 } 230 231 std::u16string ToU16String(uint32_t len = 0); 232 ToOneByteDataForced()233 std::unique_ptr<uint8_t[]> ToOneByteDataForced() 234 { 235 uint8_t *buf = nullptr; 236 auto length = GetLength(); 237 if (IsUtf16()) { 238 auto size = ComputeDataSizeUtf16(length); 239 buf = new uint8_t[size](); 240 CopyDataUtf16(reinterpret_cast<uint16_t *>(buf), length); 241 } else { 242 buf = new uint8_t[length + 1](); 243 CopyDataUtf8(buf, length + 1); 244 } 245 return std::unique_ptr<uint8_t[]>(buf); 246 } 247 248 Span<const uint8_t> ToUtf8Span([[maybe_unused]] CVector<uint8_t> &buf, bool modify = true) 249 { 250 Span<const uint8_t> str; 251 uint32_t strLen = GetLength(); 252 if (UNLIKELY(IsUtf16())) { 253 size_t len = base::utf_helper::Utf16ToUtf8Size(GetDataUtf16(), strLen, modify) - 1; 254 buf.reserve(len); 255 len = base::utf_helper::ConvertRegionUtf16ToUtf8(GetDataUtf16(), buf.data(), strLen, len, 0, modify); 256 str = Span<const uint8_t>(buf.data(), len); 257 } else { 258 str = Span<const uint8_t>(GetDataUtf8(), strLen); 259 } 260 return str; 261 } 262 WriteData(EcmaString * src,uint32_t start,uint32_t destSize,uint32_t length)263 void WriteData(EcmaString *src, uint32_t start, uint32_t destSize, uint32_t length) 264 { 265 if (IsUtf8()) { 266 ASSERT(src->IsUtf8()); 267 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 268 if (length != 0 && memcpy_s(GetDataUtf8Writable() + start, destSize, src->GetDataUtf8(), length) != EOK) { 269 LOG_FULL(FATAL) << "memcpy_s failed"; 270 UNREACHABLE(); 271 } 272 } else if (src->IsUtf8()) { 273 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 274 Span<uint16_t> to(GetDataUtf16Writable() + start, length); 275 Span<const uint8_t> from(src->GetDataUtf8(), length); 276 for (uint32_t i = 0; i < length; i++) { 277 to[i] = from[i]; 278 } 279 } else { 280 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 281 if (length != 0 && memcpy_s(GetDataUtf16Writable() + start, 282 ComputeDataSizeUtf16(destSize), src->GetDataUtf16(), ComputeDataSizeUtf16(length)) != EOK) { 283 LOG_FULL(FATAL) << "memcpy_s failed"; 284 UNREACHABLE(); 285 } 286 } 287 } 288 WriteData(uint16_t src,uint32_t start)289 inline void WriteData(uint16_t src, uint32_t start) 290 { 291 if (IsUtf8()) { 292 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 293 *(GetDataUtf8Writable() + start) = static_cast<uint8_t>(src); 294 } else { 295 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 296 *(GetDataUtf16Writable() + start) = src; 297 } 298 } 299 GetLength()300 uint32_t GetLength() const 301 { 302 return GetMixLength() >> 2U; 303 } 304 SetIsInternString()305 void SetIsInternString() 306 { 307 SetMixLength(GetMixLength() | STRING_INTERN_BIT); 308 } 309 IsInternString()310 bool IsInternString() const 311 { 312 return (GetMixLength() & STRING_INTERN_BIT) != 0; 313 } 314 ClearInternStringFlag()315 void ClearInternStringFlag() 316 { 317 SetMixLength(GetMixLength() & ~STRING_INTERN_BIT); 318 } 319 ObjectSize()320 size_t ObjectSize() const 321 { 322 uint32_t length = GetLength(); 323 return IsUtf16() ? ComputeSizeUtf16(length) : ComputeSizeUtf8(length); 324 } 325 GetHashcode()326 uint32_t PUBLIC_API GetHashcode() 327 { 328 uint32_t hashcode = GetRawHashcode(); 329 // GetLength() == 0 means it's an empty array.No need to computeHashCode again when hashseed is 0. 330 if (hashcode == 0 && GetLength() != 0) { 331 hashcode = ComputeHashcode(0); 332 SetRawHashcode(hashcode); 333 } 334 return hashcode; 335 } 336 337 uint32_t PUBLIC_API ComputeHashcode(uint32_t hashSeed) const; 338 339 static int32_t IndexOf(EcmaString *lhs, EcmaString *rhs, int pos = 0); 340 341 static int32_t LastIndexOf(EcmaString *lhs, EcmaString *rhs, int pos = 0); 342 GetStringCompressionMask()343 static constexpr uint32_t GetStringCompressionMask() 344 { 345 return STRING_COMPRESSED_BIT; 346 } 347 348 /** 349 * Compares string1 + string2 by bytes, It doesn't check canonical unicode equivalence. 350 */ 351 bool EqualToSplicedString(const EcmaString *str1, const EcmaString *str2); 352 /** 353 * Compares strings by bytes, It doesn't check canonical unicode equivalence. 354 */ 355 static bool StringsAreEqual(EcmaString *str1, EcmaString *str2); 356 /** 357 * Two strings have the same type of utf encoding format. 358 */ 359 static bool StringsAreEqualSameUtfEncoding(EcmaString *str1, EcmaString *str2); 360 /** 361 * Compares strings by bytes, It doesn't check canonical unicode equivalence. 362 */ 363 static bool StringsAreEqualUtf8(const EcmaString *str1, const uint8_t *utf8Data, uint32_t utf8Len, 364 bool canBeCompress); 365 /** 366 * Compares strings by bytes, It doesn't check canonical unicode equivalence. 367 */ 368 static bool StringsAreEqualUtf16(const EcmaString *str1, const uint16_t *utf16Data, uint32_t utf16Len); 369 static uint32_t ComputeHashcodeUtf8(const uint8_t *utf8Data, size_t utf8Len, bool canBeCompress); 370 static uint32_t ComputeHashcodeUtf16(const uint16_t *utf16Data, uint32_t length); 371 372 static EcmaString *AllocStringObject(const EcmaVM *vm, size_t length, bool compressed); 373 static EcmaString *AllocStringObjectWithSpaceType(const EcmaVM *vm, size_t length, bool compressed, 374 MemSpaceType type); 375 376 static bool CanBeCompressed(const uint8_t *utf8Data, uint32_t utf8Len); 377 static bool CanBeCompressed(const uint16_t *utf16Data, uint32_t utf16Len); 378 static bool CanBeCompressed(const EcmaString *string); 379 380 static inline EcmaString *FastSubUtf8String(const EcmaVM *vm, const JSHandle<EcmaString> &src, uint32_t start, 381 uint32_t length); 382 static inline EcmaString *FastSubUtf16String(const EcmaVM *vm, const JSHandle<EcmaString> &src, uint32_t start, 383 uint32_t length); 384 385 bool ToElementIndex(uint32_t *index); 386 387 bool ToTypedArrayIndex(uint32_t *index); 388 389 static EcmaString *ToLower(const EcmaVM *vm, const JSHandle<EcmaString> &src); 390 391 static EcmaString *ToUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src); 392 393 static EcmaString *ToLocaleLower(const EcmaVM *vm, const JSHandle<EcmaString> &src, const icu::Locale &locale); 394 395 static EcmaString *ToLocaleUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src, const icu::Locale &locale); 396 397 template<typename T> 398 static EcmaString *TrimBody(const JSThread *thread, const JSHandle<EcmaString> &src, Span<T> &data, TrimMode mode); 399 400 static EcmaString *Trim(const JSThread *thread, const JSHandle<EcmaString> &src, TrimMode mode = TrimMode::TRIM); 401 402 void SetLength(uint32_t length, bool compressed = false) 403 { 404 ASSERT(length < 0x40000000U); 405 // Use 0u for compressed/utf8 expression 406 SetMixLength((length << 2U) | (compressed ? STRING_COMPRESSED : STRING_UNCOMPRESSED)); 407 } 408 GetDataUtf16Writable()409 uint16_t *GetDataUtf16Writable() 410 { 411 LOG_ECMA_IF(!IsUtf16(), FATAL) << "EcmaString: Read data as utf16 for utf8 string"; 412 return GetData(); 413 } 414 GetDataUtf8Writable()415 uint8_t *GetDataUtf8Writable() 416 { 417 ASSERT_PRINT(IsUtf8(), "EcmaString: Read data as utf8 for utf16 string"); 418 return reinterpret_cast<uint8_t *>(GetData()); 419 } 420 421 static void CopyUtf16AsUtf8(const uint16_t *utf16From, uint8_t *utf8To, uint32_t utf16Len); 422 IsASCIICharacter(uint16_t data)423 static bool IsASCIICharacter(uint16_t data) 424 { 425 // \0 is not considered ASCII in Ecma-Modified-UTF8 [only modify '\u0000'] 426 return data - 1U < base::utf_helper::UTF8_1B_MAX; 427 } 428 429 /** 430 * str1 should have the same length as utf16_data. 431 * Converts utf8Data to utf16 and compare it with given utf16_data. 432 */ 433 static bool IsUtf8EqualsUtf16(const uint8_t *utf8Data, size_t utf8Len, const uint16_t *utf16Data, 434 uint32_t utf16Len); 435 436 template<typename T> 437 /** 438 * Check that two spans are equal. Should have the same length. 439 */ 440 static bool StringsAreEquals(Span<const T> &str1, Span<const T> &str2); 441 442 template<typename T> 443 /** 444 * Copy String from src to dst 445 * */ 446 static bool StringCopy(Span<T> &dst, size_t dstMax, Span<const T> &src, size_t count); 447 448 template<typename T1, typename T2> 449 static int32_t IndexOf(Span<const T1> &lhsSp, Span<const T2> &rhsSp, int32_t pos, int32_t max); 450 451 template<typename T1, typename T2> 452 static int32_t LastIndexOf(Span<const T1> &lhsSp, Span<const T2> &rhsSp, int32_t pos); 453 }; 454 455 static_assert((EcmaString::DATA_OFFSET % static_cast<uint8_t>(MemAlignment::MEM_ALIGN_OBJECT)) == 0); 456 457 // if you want to use functions of EcmaString, please not use directly, 458 // and use functions of EcmaStringAccessor alternatively. 459 // eg: EcmaString *str = ***; str->GetLength() -----> EcmaStringAccessor(str).GetLength() 460 class PUBLIC_API EcmaStringAccessor { 461 public: 462 explicit EcmaStringAccessor(EcmaString *string); 463 464 explicit EcmaStringAccessor(TaggedObject *obj); 465 466 explicit EcmaStringAccessor(JSTaggedValue value); 467 468 explicit EcmaStringAccessor(const JSHandle<EcmaString> &strHandle); 469 AllocStringObject(const EcmaVM * vm,size_t length,bool compressed)470 static EcmaString *AllocStringObject(const EcmaVM *vm, size_t length, bool compressed) 471 { 472 return EcmaString::AllocStringObject(vm, length, compressed); 473 } 474 CreateEmptyString(const EcmaVM * vm)475 static EcmaString *CreateEmptyString(const EcmaVM *vm) 476 { 477 return EcmaString::CreateEmptyString(vm); 478 } 479 480 static EcmaString *CreateFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress, 481 MemSpaceType type = MemSpaceType::SEMI_SPACE) 482 { 483 return EcmaString::CreateFromUtf8(vm, utf8Data, utf8Len, canBeCompress, type); 484 } 485 486 static EcmaString *CreateFromUtf16(const EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len, 487 bool canBeCompress, MemSpaceType type = MemSpaceType::SEMI_SPACE) 488 { 489 return EcmaString::CreateFromUtf16(vm, utf16Data, utf16Len, canBeCompress, type); 490 } 491 Concat(const EcmaVM * vm,const JSHandle<EcmaString> & str1Handle,const JSHandle<EcmaString> & str2Handle)492 static EcmaString *Concat(const EcmaVM *vm, 493 const JSHandle<EcmaString> &str1Handle, const JSHandle<EcmaString> &str2Handle) 494 { 495 return EcmaString::Concat(vm, str1Handle, str2Handle); 496 } 497 FastSubString(const EcmaVM * vm,const JSHandle<EcmaString> & src,uint32_t start,uint32_t length)498 static EcmaString *FastSubString(const EcmaVM *vm, 499 const JSHandle<EcmaString> &src, uint32_t start, uint32_t length) 500 { 501 return EcmaString::FastSubString(vm, src, start, length); 502 } 503 IsUtf8()504 bool IsUtf8() const 505 { 506 return string_->IsUtf8(); 507 } 508 IsUtf16()509 bool IsUtf16() const 510 { 511 return string_->IsUtf16(); 512 } 513 GetLength()514 uint32_t GetLength() const 515 { 516 return string_->GetLength(); 517 } 518 GetUtf8Length()519 size_t GetUtf8Length() const 520 { 521 return string_->GetUtf8Length(); 522 } 523 ObjectSize()524 size_t ObjectSize() const 525 { 526 return string_->ObjectSize(); 527 } 528 IsInternString()529 bool IsInternString() const 530 { 531 return string_->IsInternString(); 532 } 533 SetInternString()534 void SetInternString() 535 { 536 string_->SetIsInternString(); 537 } 538 ClearInternString()539 void ClearInternString() 540 { 541 string_->ClearInternStringFlag(); 542 } 543 GetDataUtf8()544 const uint8_t *GetDataUtf8() 545 { 546 return string_->GetDataUtf8(); 547 } 548 GetDataUtf16()549 const uint16_t *GetDataUtf16() 550 { 551 return string_->GetDataUtf16(); 552 } 553 554 std::u16string ToU16String(uint32_t len = 0) 555 { 556 return string_->ToU16String(len); 557 } 558 ToOneByteDataForced()559 std::unique_ptr<uint8_t[]> ToOneByteDataForced() 560 { 561 return string_->ToOneByteDataForced(); 562 } 563 ToUtf8Span(CVector<uint8_t> & buf)564 Span<const uint8_t> ToUtf8Span([[maybe_unused]] CVector<uint8_t> &buf) 565 { 566 return string_->ToUtf8Span(buf); 567 } 568 569 std::string ToStdString(StringConvertedUsage usage = StringConvertedUsage::PRINT); 570 571 CString ToCString(StringConvertedUsage usage = StringConvertedUsage::LOGICOPERATION); 572 WriteToFlatUtf8(uint8_t * buf,uint32_t maxLength)573 uint32_t WriteToFlatUtf8(uint8_t *buf, uint32_t maxLength) 574 { 575 return string_->WriteUtf8(buf, maxLength); 576 } 577 WriteToFlatUtf16(uint16_t * buf,uint32_t maxLength)578 uint32_t WriteToFlatUtf16(uint16_t *buf, uint32_t maxLength) const 579 { 580 return string_->CopyDataUtf16(buf, maxLength); 581 } 582 ReadData(EcmaString * dst,EcmaString * src,uint32_t start,uint32_t destSize,uint32_t length)583 static void ReadData(EcmaString * dst, EcmaString *src, uint32_t start, uint32_t destSize, uint32_t length) 584 { 585 dst->WriteData(src, start, destSize, length); 586 } 587 588 template<bool verify = true> Get(uint32_t index)589 uint16_t Get(uint32_t index) const 590 { 591 return string_->At<verify>(index); 592 } 593 Set(uint32_t index,uint16_t src)594 void Set(uint32_t index, uint16_t src) 595 { 596 return string_->WriteData(src, index); 597 } 598 GetHashcode()599 uint32_t GetHashcode() 600 { 601 return string_->GetHashcode(); 602 } 603 ComputeHashcode(uint32_t hashSeed)604 uint32_t ComputeHashcode(uint32_t hashSeed) 605 { 606 return string_->ComputeHashcode(hashSeed); 607 } 608 ComputeHashcodeUtf8(const uint8_t * utf8Data,size_t utf8Len,bool canBeCompress)609 static uint32_t ComputeHashcodeUtf8(const uint8_t *utf8Data, size_t utf8Len, bool canBeCompress) 610 { 611 return EcmaString::ComputeHashcodeUtf8(utf8Data, utf8Len, canBeCompress); 612 } 613 ComputeHashcodeUtf16(const uint16_t * utf16Data,uint32_t length)614 static uint32_t ComputeHashcodeUtf16(const uint16_t *utf16Data, uint32_t length) 615 { 616 return EcmaString::ComputeHashcodeUtf16(utf16Data, length); 617 } 618 619 static int32_t IndexOf(EcmaString *lhs, EcmaString *rhs, int pos = 0) 620 { 621 return EcmaString::IndexOf(lhs, rhs, pos); 622 } 623 624 static int32_t LastIndexOf(EcmaString *lhs, EcmaString *rhs, int pos = 0) 625 { 626 return EcmaString::LastIndexOf(lhs, rhs, pos); 627 } 628 Compare(EcmaString * lhs,EcmaString * rhs)629 static int32_t Compare(EcmaString *lhs, EcmaString *rhs) 630 { 631 return EcmaString::Compare(lhs, rhs); 632 } 633 StringsAreEqual(EcmaString * str1,EcmaString * str2)634 static bool StringsAreEqual(EcmaString *str1, EcmaString *str2) 635 { 636 return EcmaString::StringsAreEqual(str1, str2); 637 } 638 StringsAreEqualSameUtfEncoding(EcmaString * str1,EcmaString * str2)639 static bool StringsAreEqualSameUtfEncoding(EcmaString *str1, EcmaString *str2) 640 { 641 return EcmaString::StringsAreEqualSameUtfEncoding(str1, str2); 642 } 643 StringsAreEqualUtf8(const EcmaString * str1,const uint8_t * utf8Data,uint32_t utf8Len,bool canBeCompress)644 static bool StringsAreEqualUtf8(const EcmaString *str1, const uint8_t *utf8Data, uint32_t utf8Len, 645 bool canBeCompress) 646 { 647 return EcmaString::StringsAreEqualUtf8(str1, utf8Data, utf8Len, canBeCompress); 648 } 649 StringsAreEqualUtf16(const EcmaString * str1,const uint16_t * utf16Data,uint32_t utf16Len)650 static bool StringsAreEqualUtf16(const EcmaString *str1, const uint16_t *utf16Data, uint32_t utf16Len) 651 { 652 return EcmaString::StringsAreEqualUtf16(str1, utf16Data, utf16Len); 653 } 654 EqualToSplicedString(const EcmaString * str1,const EcmaString * str2)655 bool EqualToSplicedString(const EcmaString *str1, const EcmaString *str2) 656 { 657 return string_->EqualToSplicedString(str1, str2); 658 } 659 CanBeCompressed(const uint8_t * utf8Data,uint32_t utf8Len)660 static bool CanBeCompressed(const uint8_t *utf8Data, uint32_t utf8Len) 661 { 662 return EcmaString::CanBeCompressed(utf8Data, utf8Len); 663 } 664 CanBeCompressed(const uint16_t * utf16Data,uint32_t utf16Len)665 static bool CanBeCompressed(const uint16_t *utf16Data, uint32_t utf16Len) 666 { 667 return EcmaString::CanBeCompressed(utf16Data, utf16Len); 668 } 669 CanBeCompressed(const EcmaString * string)670 static bool CanBeCompressed(const EcmaString *string) 671 { 672 return EcmaString::CanBeCompressed(string); 673 } 674 ToElementIndex(uint32_t * index)675 bool ToElementIndex(uint32_t *index) 676 { 677 return string_->ToElementIndex(index); 678 } 679 ToTypedArrayIndex(uint32_t * index)680 bool ToTypedArrayIndex(uint32_t *index) 681 { 682 return string_->ToTypedArrayIndex(index); 683 } 684 ToLower(const EcmaVM * vm,const JSHandle<EcmaString> & src)685 static EcmaString *ToLower(const EcmaVM *vm, const JSHandle<EcmaString> &src) 686 { 687 return EcmaString::ToLower(vm, src); 688 } 689 ToUpper(const EcmaVM * vm,const JSHandle<EcmaString> & src)690 static EcmaString *ToUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src) 691 { 692 return EcmaString::ToUpper(vm, src); 693 } 694 ToLocaleLower(const EcmaVM * vm,const JSHandle<EcmaString> & src,const icu::Locale & locale)695 static EcmaString *ToLocaleLower(const EcmaVM *vm, const JSHandle<EcmaString> &src, const icu::Locale &locale) 696 { 697 return EcmaString::ToLocaleLower(vm, src, locale); 698 } 699 ToLocaleUpper(const EcmaVM * vm,const JSHandle<EcmaString> & src,const icu::Locale & locale)700 static EcmaString *ToLocaleUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src, const icu::Locale &locale) 701 { 702 return EcmaString::ToLocaleUpper(vm, src, locale); 703 } 704 705 static EcmaString *Trim(const JSThread *thread, 706 const JSHandle<EcmaString> &src, EcmaString::TrimMode mode = EcmaString::TrimMode::TRIM) 707 { 708 return EcmaString::Trim(thread, src, mode); 709 } 710 711 private: 712 EcmaString *string_ {nullptr}; 713 }; 714 } // namespace ecmascript 715 } // namespace panda 716 #endif // ECMASCRIPT_STRING_H