1// Copyright 2014 PDFium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7#include "core/fxcrt/widestring.h" 8 9#include <stddef.h> 10 11#include <algorithm> 12#include <cctype> 13#include <cwctype> 14 15#include "core/fxcrt/cfx_utf8decoder.h" 16#include "core/fxcrt/fx_codepage.h" 17#include "core/fxcrt/fx_extension.h" 18#include "core/fxcrt/fx_safe_types.h" 19#include "core/fxcrt/string_pool_template.h" 20#include "third_party/base/numerics/safe_math.h" 21#include "third_party/base/stl_util.h" 22 23template class fxcrt::StringDataTemplate<wchar_t>; 24template class fxcrt::StringViewTemplate<wchar_t>; 25template class fxcrt::StringPoolTemplate<WideString>; 26template struct std::hash<WideString>; 27 28#define FORCE_ANSI 0x10000 29#define FORCE_UNICODE 0x20000 30#define FORCE_INT64 0x40000 31 32namespace { 33 34constexpr wchar_t kWideTrimChars[] = L"\x09\x0a\x0b\x0c\x0d\x20"; 35 36const wchar_t* FX_wcsstr(const wchar_t* haystack, 37 int haystack_len, 38 const wchar_t* needle, 39 int needle_len) { 40 if (needle_len > haystack_len || needle_len == 0) { 41 return nullptr; 42 } 43 const wchar_t* end_ptr = haystack + haystack_len - needle_len; 44 while (haystack <= end_ptr) { 45 int i = 0; 46 while (1) { 47 if (haystack[i] != needle[i]) { 48 break; 49 } 50 i++; 51 if (i == needle_len) { 52 return haystack; 53 } 54 } 55 haystack++; 56 } 57 return nullptr; 58} 59 60Optional<size_t> GuessSizeForVSWPrintf(const wchar_t* pFormat, 61 va_list argList) { 62 size_t nMaxLen = 0; 63 for (const wchar_t* pStr = pFormat; *pStr != 0; pStr++) { 64 if (*pStr != '%' || *(pStr = pStr + 1) == '%') { 65 ++nMaxLen; 66 continue; 67 } 68 int nItemLen = 0; 69 int nWidth = 0; 70 for (; *pStr != 0; pStr++) { 71 if (*pStr == '#') { 72 nMaxLen += 2; 73 } else if (*pStr == '*') { 74 nWidth = va_arg(argList, int); 75 } else if (*pStr != '-' && *pStr != '+' && *pStr != '0' && *pStr != ' ') { 76 break; 77 } 78 } 79 if (nWidth == 0) { 80 nWidth = FXSYS_wtoi(pStr); 81 while (std::iswdigit(*pStr)) 82 ++pStr; 83 } 84 if (nWidth < 0 || nWidth > 128 * 1024) 85 return Optional<size_t>(); 86 int nPrecision = 0; 87 if (*pStr == '.') { 88 pStr++; 89 if (*pStr == '*') { 90 nPrecision = va_arg(argList, int); 91 pStr++; 92 } else { 93 nPrecision = FXSYS_wtoi(pStr); 94 while (std::iswdigit(*pStr)) 95 ++pStr; 96 } 97 } 98 if (nPrecision < 0 || nPrecision > 128 * 1024) 99 return Optional<size_t>(); 100 int nModifier = 0; 101 if (*pStr == L'I' && *(pStr + 1) == L'6' && *(pStr + 2) == L'4') { 102 pStr += 3; 103 nModifier = FORCE_INT64; 104 } else { 105 switch (*pStr) { 106 case 'h': 107 nModifier = FORCE_ANSI; 108 pStr++; 109 break; 110 case 'l': 111 nModifier = FORCE_UNICODE; 112 pStr++; 113 break; 114 case 'F': 115 case 'N': 116 case 'L': 117 pStr++; 118 break; 119 } 120 } 121 switch (*pStr | nModifier) { 122 case 'c': 123 case 'C': 124 nItemLen = 2; 125 va_arg(argList, int); 126 break; 127 case 'c' | FORCE_ANSI: 128 case 'C' | FORCE_ANSI: 129 nItemLen = 2; 130 va_arg(argList, int); 131 break; 132 case 'c' | FORCE_UNICODE: 133 case 'C' | FORCE_UNICODE: 134 nItemLen = 2; 135 va_arg(argList, int); 136 break; 137 case 's': { 138 const wchar_t* pstrNextArg = va_arg(argList, const wchar_t*); 139 if (pstrNextArg) { 140 nItemLen = wcslen(pstrNextArg); 141 if (nItemLen < 1) { 142 nItemLen = 1; 143 } 144 } else { 145 nItemLen = 6; 146 } 147 } break; 148 case 'S': { 149 const char* pstrNextArg = va_arg(argList, const char*); 150 if (pstrNextArg) { 151 nItemLen = strlen(pstrNextArg); 152 if (nItemLen < 1) { 153 nItemLen = 1; 154 } 155 } else { 156 nItemLen = 6; 157 } 158 } break; 159 case 's' | FORCE_ANSI: 160 case 'S' | FORCE_ANSI: { 161 const char* pstrNextArg = va_arg(argList, const char*); 162 if (pstrNextArg) { 163 nItemLen = strlen(pstrNextArg); 164 if (nItemLen < 1) { 165 nItemLen = 1; 166 } 167 } else { 168 nItemLen = 6; 169 } 170 } break; 171 case 's' | FORCE_UNICODE: 172 case 'S' | FORCE_UNICODE: { 173 const wchar_t* pstrNextArg = va_arg(argList, wchar_t*); 174 if (pstrNextArg) { 175 nItemLen = wcslen(pstrNextArg); 176 if (nItemLen < 1) { 177 nItemLen = 1; 178 } 179 } else { 180 nItemLen = 6; 181 } 182 } break; 183 } 184 if (nItemLen != 0) { 185 if (nPrecision != 0 && nItemLen > nPrecision) { 186 nItemLen = nPrecision; 187 } 188 if (nItemLen < nWidth) { 189 nItemLen = nWidth; 190 } 191 } else { 192 switch (*pStr) { 193 case 'd': 194 case 'i': 195 case 'u': 196 case 'x': 197 case 'X': 198 case 'o': 199 if (nModifier & FORCE_INT64) { 200 va_arg(argList, int64_t); 201 } else { 202 va_arg(argList, int); 203 } 204 nItemLen = 32; 205 if (nItemLen < nWidth + nPrecision) { 206 nItemLen = nWidth + nPrecision; 207 } 208 break; 209 case 'a': 210 case 'A': 211 case 'e': 212 case 'E': 213 case 'g': 214 case 'G': 215 va_arg(argList, double); 216 nItemLen = 128; 217 if (nItemLen < nWidth + nPrecision) { 218 nItemLen = nWidth + nPrecision; 219 } 220 break; 221 case 'f': 222 if (nWidth + nPrecision > 100) { 223 nItemLen = nPrecision + nWidth + 128; 224 } else { 225 double f; 226 char pszTemp[256]; 227 f = va_arg(argList, double); 228 FXSYS_snprintf(pszTemp, sizeof(pszTemp), "%*.*f", nWidth, 229 nPrecision + 6, f); 230 nItemLen = strlen(pszTemp); 231 } 232 break; 233 case 'p': 234 va_arg(argList, void*); 235 nItemLen = 32; 236 if (nItemLen < nWidth + nPrecision) { 237 nItemLen = nWidth + nPrecision; 238 } 239 break; 240 case 'n': 241 va_arg(argList, int*); 242 break; 243 } 244 } 245 nMaxLen += nItemLen; 246 } 247 nMaxLen += 32; // Fudge factor. 248 return Optional<size_t>(nMaxLen); 249} 250 251// Returns string unless we ran out of space. 252Optional<WideString> TryVSWPrintf(size_t size, 253 const wchar_t* pFormat, 254 va_list argList) { 255 WideString str; 256 wchar_t* buffer = str.GetBuffer(size); 257 258 // In the following two calls, there's always space in the buffer for 259 // a terminating NUL that's not included in nMaxLen. 260 // For vswprintf(), MSAN won't untaint the buffer on a truncated write's 261 // -1 return code even though the buffer is written. Probably just as well 262 // not to trust the vendor's implementation to write anything anyways. 263 // See https://crbug.com/705912. 264 memset(buffer, 0, (size + 1) * sizeof(wchar_t)); 265 int ret = vswprintf(buffer, size + 1, pFormat, argList); 266 267 bool bSufficientBuffer = ret >= 0 || buffer[size - 1] == 0; 268 if (!bSufficientBuffer) 269 return {}; 270 271 str.ReleaseBuffer(str.GetStringLength()); 272 return {str}; 273} 274 275#ifndef NDEBUG 276bool IsValidWideCodePage(uint16_t codepage) { 277 switch (codepage) { 278 case FX_CODEPAGE_DefANSI: 279 case FX_CODEPAGE_ShiftJIS: 280 case FX_CODEPAGE_ChineseSimplified: 281 case FX_CODEPAGE_Hangul: 282 case FX_CODEPAGE_ChineseTraditional: 283 return true; 284 default: 285 return false; 286 } 287} 288#endif 289 290WideString GetWideString(uint16_t codepage, const ByteStringView& bstr) { 291#ifndef NDEBUG 292 ASSERT(IsValidWideCodePage(codepage)); 293#endif 294 295 int src_len = bstr.GetLength(); 296 int dest_len = FXSYS_MultiByteToWideChar( 297 codepage, 0, bstr.unterminated_c_str(), src_len, nullptr, 0); 298 if (!dest_len) 299 return WideString(); 300 301 WideString wstr; 302 wchar_t* dest_buf = wstr.GetBuffer(dest_len); 303 FXSYS_MultiByteToWideChar(codepage, 0, bstr.unterminated_c_str(), src_len, 304 dest_buf, dest_len); 305 wstr.ReleaseBuffer(dest_len); 306 return wstr; 307} 308 309} // namespace 310 311namespace fxcrt { 312 313static_assert(sizeof(WideString) <= sizeof(wchar_t*), 314 "Strings must not require more space than pointers"); 315 316// static 317WideString WideString::FormatV(const wchar_t* format, va_list argList) { 318 va_list argListCopy; 319 va_copy(argListCopy, argList); 320 int maxLen = vswprintf(nullptr, 0, format, argListCopy); 321 va_end(argListCopy); 322 323 if (maxLen <= 0) { 324 va_copy(argListCopy, argList); 325 auto guess = GuessSizeForVSWPrintf(format, argListCopy); 326 va_end(argListCopy); 327 328 if (!guess.has_value()) 329 return L""; 330 maxLen = pdfium::base::checked_cast<int>(guess.value()); 331 } 332 333 while (maxLen < 32 * 1024) { 334 va_copy(argListCopy, argList); 335 Optional<WideString> ret = 336 TryVSWPrintf(static_cast<size_t>(maxLen), format, argListCopy); 337 va_end(argListCopy); 338 339 if (ret) 340 return *ret; 341 maxLen *= 2; 342 } 343 return L""; 344} 345 346// static 347WideString WideString::Format(const wchar_t* pFormat, ...) { 348 va_list argList; 349 va_start(argList, pFormat); 350 WideString ret = FormatV(pFormat, argList); 351 va_end(argList); 352 return ret; 353} 354 355WideString::WideString() {} 356 357WideString::WideString(const WideString& other) : m_pData(other.m_pData) {} 358 359WideString::WideString(WideString&& other) noexcept { 360 m_pData.Swap(other.m_pData); 361} 362 363WideString::WideString(const wchar_t* pStr, size_t nLen) { 364 if (nLen) 365 m_pData.Reset(StringData::Create(pStr, nLen)); 366} 367 368WideString::WideString(wchar_t ch) { 369 m_pData.Reset(StringData::Create(1)); 370 m_pData->m_String[0] = ch; 371} 372 373WideString::WideString(const wchar_t* ptr) 374 : WideString(ptr, ptr ? wcslen(ptr) : 0) {} 375 376WideString::WideString(const WideStringView& stringSrc) { 377 if (!stringSrc.IsEmpty()) { 378 m_pData.Reset(StringData::Create(stringSrc.unterminated_c_str(), 379 stringSrc.GetLength())); 380 } 381} 382 383WideString::WideString(const WideStringView& str1, const WideStringView& str2) { 384 FX_SAFE_SIZE_T nSafeLen = str1.GetLength(); 385 nSafeLen += str2.GetLength(); 386 387 size_t nNewLen = nSafeLen.ValueOrDie(); 388 if (nNewLen == 0) 389 return; 390 391 m_pData.Reset(StringData::Create(nNewLen)); 392 m_pData->CopyContents(str1.unterminated_c_str(), str1.GetLength()); 393 m_pData->CopyContentsAt(str1.GetLength(), str2.unterminated_c_str(), 394 str2.GetLength()); 395} 396 397WideString::WideString(const std::initializer_list<WideStringView>& list) { 398 FX_SAFE_SIZE_T nSafeLen = 0; 399 for (const auto& item : list) 400 nSafeLen += item.GetLength(); 401 402 size_t nNewLen = nSafeLen.ValueOrDie(); 403 if (nNewLen == 0) 404 return; 405 406 m_pData.Reset(StringData::Create(nNewLen)); 407 408 size_t nOffset = 0; 409 for (const auto& item : list) { 410 m_pData->CopyContentsAt(nOffset, item.unterminated_c_str(), 411 item.GetLength()); 412 nOffset += item.GetLength(); 413 } 414} 415 416WideString::~WideString() {} 417 418const WideString& WideString::operator=(const wchar_t* pStr) { 419 if (!pStr || !pStr[0]) 420 clear(); 421 else 422 AssignCopy(pStr, wcslen(pStr)); 423 424 return *this; 425} 426 427const WideString& WideString::operator=(const WideStringView& stringSrc) { 428 if (stringSrc.IsEmpty()) 429 clear(); 430 else 431 AssignCopy(stringSrc.unterminated_c_str(), stringSrc.GetLength()); 432 433 return *this; 434} 435 436const WideString& WideString::operator=(const WideString& stringSrc) { 437 if (m_pData != stringSrc.m_pData) 438 m_pData = stringSrc.m_pData; 439 440 return *this; 441} 442 443const WideString& WideString::operator+=(const wchar_t* pStr) { 444 if (pStr) 445 Concat(pStr, wcslen(pStr)); 446 447 return *this; 448} 449 450const WideString& WideString::operator+=(wchar_t ch) { 451 Concat(&ch, 1); 452 return *this; 453} 454 455const WideString& WideString::operator+=(const WideString& str) { 456 if (str.m_pData) 457 Concat(str.m_pData->m_String, str.m_pData->m_nDataLength); 458 459 return *this; 460} 461 462const WideString& WideString::operator+=(const WideStringView& str) { 463 if (!str.IsEmpty()) 464 Concat(str.unterminated_c_str(), str.GetLength()); 465 466 return *this; 467} 468 469bool WideString::operator==(const wchar_t* ptr) const { 470 if (!m_pData) 471 return !ptr || !ptr[0]; 472 473 if (!ptr) 474 return m_pData->m_nDataLength == 0; 475 476 return wcslen(ptr) == m_pData->m_nDataLength && 477 wmemcmp(ptr, m_pData->m_String, m_pData->m_nDataLength) == 0; 478} 479 480bool WideString::operator==(const WideStringView& str) const { 481 if (!m_pData) 482 return str.IsEmpty(); 483 484 return m_pData->m_nDataLength == str.GetLength() && 485 wmemcmp(m_pData->m_String, str.unterminated_c_str(), 486 str.GetLength()) == 0; 487} 488 489bool WideString::operator==(const WideString& other) const { 490 if (m_pData == other.m_pData) 491 return true; 492 493 if (IsEmpty()) 494 return other.IsEmpty(); 495 496 if (other.IsEmpty()) 497 return false; 498 499 return other.m_pData->m_nDataLength == m_pData->m_nDataLength && 500 wmemcmp(other.m_pData->m_String, m_pData->m_String, 501 m_pData->m_nDataLength) == 0; 502} 503 504bool WideString::operator<(const wchar_t* ptr) const { 505 return Compare(ptr) < 0; 506} 507 508bool WideString::operator<(const WideStringView& str) const { 509 if (!m_pData && !str.unterminated_c_str()) 510 return false; 511 if (c_str() == str.unterminated_c_str()) 512 return false; 513 514 size_t len = GetLength(); 515 size_t other_len = str.GetLength(); 516 int result = 517 wmemcmp(c_str(), str.unterminated_c_str(), std::min(len, other_len)); 518 return result < 0 || (result == 0 && len < other_len); 519} 520 521bool WideString::operator<(const WideString& other) const { 522 return Compare(other) < 0; 523} 524 525void WideString::AssignCopy(const wchar_t* pSrcData, size_t nSrcLen) { 526 AllocBeforeWrite(nSrcLen); 527 m_pData->CopyContents(pSrcData, nSrcLen); 528 m_pData->m_nDataLength = nSrcLen; 529} 530 531void WideString::ReallocBeforeWrite(size_t nNewLength) { 532 if (m_pData && m_pData->CanOperateInPlace(nNewLength)) 533 return; 534 535 if (nNewLength == 0) { 536 clear(); 537 return; 538 } 539 540 RetainPtr<StringData> pNewData(StringData::Create(nNewLength)); 541 if (m_pData) { 542 size_t nCopyLength = std::min(m_pData->m_nDataLength, nNewLength); 543 pNewData->CopyContents(m_pData->m_String, nCopyLength); 544 pNewData->m_nDataLength = nCopyLength; 545 } else { 546 pNewData->m_nDataLength = 0; 547 } 548 pNewData->m_String[pNewData->m_nDataLength] = 0; 549 m_pData.Swap(pNewData); 550} 551 552void WideString::AllocBeforeWrite(size_t nNewLength) { 553 if (m_pData && m_pData->CanOperateInPlace(nNewLength)) 554 return; 555 556 if (nNewLength == 0) { 557 clear(); 558 return; 559 } 560 561 m_pData.Reset(StringData::Create(nNewLength)); 562} 563 564void WideString::ReleaseBuffer(size_t nNewLength) { 565 if (!m_pData) 566 return; 567 568 nNewLength = std::min(nNewLength, m_pData->m_nAllocLength); 569 if (nNewLength == 0) { 570 clear(); 571 return; 572 } 573 574 ASSERT(m_pData->m_nRefs == 1); 575 m_pData->m_nDataLength = nNewLength; 576 m_pData->m_String[nNewLength] = 0; 577 if (m_pData->m_nAllocLength - nNewLength >= 32) { 578 // Over arbitrary threshold, so pay the price to relocate. Force copy to 579 // always occur by holding a second reference to the string. 580 WideString preserve(*this); 581 ReallocBeforeWrite(nNewLength); 582 } 583} 584 585void WideString::Reserve(size_t len) { 586 GetBuffer(len); 587} 588 589wchar_t* WideString::GetBuffer(size_t nMinBufLength) { 590 if (!m_pData) { 591 if (nMinBufLength == 0) 592 return nullptr; 593 594 m_pData.Reset(StringData::Create(nMinBufLength)); 595 m_pData->m_nDataLength = 0; 596 m_pData->m_String[0] = 0; 597 return m_pData->m_String; 598 } 599 600 if (m_pData->CanOperateInPlace(nMinBufLength)) 601 return m_pData->m_String; 602 603 nMinBufLength = std::max(nMinBufLength, m_pData->m_nDataLength); 604 if (nMinBufLength == 0) 605 return nullptr; 606 607 RetainPtr<StringData> pNewData(StringData::Create(nMinBufLength)); 608 pNewData->CopyContents(*m_pData); 609 pNewData->m_nDataLength = m_pData->m_nDataLength; 610 m_pData.Swap(pNewData); 611 return m_pData->m_String; 612} 613 614size_t WideString::Delete(size_t index, size_t count) { 615 if (!m_pData) 616 return 0; 617 618 size_t old_length = m_pData->m_nDataLength; 619 if (count == 0 || 620 index != pdfium::clamp(index, static_cast<size_t>(0), old_length)) 621 return old_length; 622 623 size_t removal_length = index + count; 624 if (removal_length > old_length) 625 return old_length; 626 627 ReallocBeforeWrite(old_length); 628 size_t chars_to_copy = old_length - removal_length + 1; 629 wmemmove(m_pData->m_String + index, m_pData->m_String + removal_length, 630 chars_to_copy); 631 m_pData->m_nDataLength = old_length - count; 632 return m_pData->m_nDataLength; 633} 634 635void WideString::Concat(const wchar_t* pSrcData, size_t nSrcLen) { 636 if (!pSrcData || nSrcLen == 0) 637 return; 638 639 if (!m_pData) { 640 m_pData.Reset(StringData::Create(pSrcData, nSrcLen)); 641 return; 642 } 643 644 if (m_pData->CanOperateInPlace(m_pData->m_nDataLength + nSrcLen)) { 645 m_pData->CopyContentsAt(m_pData->m_nDataLength, pSrcData, nSrcLen); 646 m_pData->m_nDataLength += nSrcLen; 647 return; 648 } 649 650 RetainPtr<StringData> pNewData( 651 StringData::Create(m_pData->m_nDataLength + nSrcLen)); 652 pNewData->CopyContents(*m_pData); 653 pNewData->CopyContentsAt(m_pData->m_nDataLength, pSrcData, nSrcLen); 654 m_pData.Swap(pNewData); 655} 656 657ByteString WideString::UTF8Encode() const { 658 return FX_UTF8Encode(AsStringView()); 659} 660 661ByteString WideString::UTF16LE_Encode() const { 662 if (!m_pData) { 663 return ByteString("\0\0", 2); 664 } 665 int len = m_pData->m_nDataLength; 666 ByteString result; 667 char* buffer = result.GetBuffer(len * 2 + 2); 668 for (int i = 0; i < len; i++) { 669 buffer[i * 2] = m_pData->m_String[i] & 0xff; 670 buffer[i * 2 + 1] = m_pData->m_String[i] >> 8; 671 } 672 buffer[len * 2] = 0; 673 buffer[len * 2 + 1] = 0; 674 result.ReleaseBuffer(len * 2 + 2); 675 return result; 676} 677 678WideString WideString::Mid(size_t first, size_t count) const { 679 if (!m_pData) 680 return WideString(); 681 682 if (!IsValidIndex(first)) 683 return WideString(); 684 685 if (count == 0 || !IsValidLength(count)) 686 return WideString(); 687 688 if (!IsValidIndex(first + count - 1)) 689 return WideString(); 690 691 if (first == 0 && count == GetLength()) 692 return *this; 693 694 WideString dest; 695 AllocCopy(dest, count, first); 696 return dest; 697} 698 699WideString WideString::Left(size_t count) const { 700 if (count == 0 || !IsValidLength(count)) 701 return WideString(); 702 return Mid(0, count); 703} 704 705WideString WideString::Right(size_t count) const { 706 if (count == 0 || !IsValidLength(count)) 707 return WideString(); 708 return Mid(GetLength() - count, count); 709} 710 711void WideString::AllocCopy(WideString& dest, 712 size_t nCopyLen, 713 size_t nCopyIndex) const { 714 if (nCopyLen == 0) 715 return; 716 717 RetainPtr<StringData> pNewData( 718 StringData::Create(m_pData->m_String + nCopyIndex, nCopyLen)); 719 dest.m_pData.Swap(pNewData); 720} 721 722size_t WideString::Insert(size_t location, wchar_t ch) { 723 const size_t cur_length = m_pData ? m_pData->m_nDataLength : 0; 724 if (!IsValidLength(location)) 725 return cur_length; 726 727 const size_t new_length = cur_length + 1; 728 ReallocBeforeWrite(new_length); 729 wmemmove(m_pData->m_String + location + 1, m_pData->m_String + location, 730 new_length - location); 731 m_pData->m_String[location] = ch; 732 m_pData->m_nDataLength = new_length; 733 return new_length; 734} 735 736Optional<size_t> WideString::Find(wchar_t ch, size_t start) const { 737 if (!m_pData) 738 return Optional<size_t>(); 739 740 if (!IsValidIndex(start)) 741 return Optional<size_t>(); 742 743 const wchar_t* pStr = 744 wmemchr(m_pData->m_String + start, ch, m_pData->m_nDataLength - start); 745 return pStr ? Optional<size_t>(static_cast<size_t>(pStr - m_pData->m_String)) 746 : Optional<size_t>(); 747} 748 749Optional<size_t> WideString::Find(const WideStringView& subStr, 750 size_t start) const { 751 if (!m_pData) 752 return Optional<size_t>(); 753 754 if (!IsValidIndex(start)) 755 return Optional<size_t>(); 756 757 const wchar_t* pStr = 758 FX_wcsstr(m_pData->m_String + start, m_pData->m_nDataLength - start, 759 subStr.unterminated_c_str(), subStr.GetLength()); 760 return pStr ? Optional<size_t>(static_cast<size_t>(pStr - m_pData->m_String)) 761 : Optional<size_t>(); 762} 763 764void WideString::MakeLower() { 765 if (!m_pData) 766 return; 767 768 ReallocBeforeWrite(m_pData->m_nDataLength); 769 FXSYS_wcslwr(m_pData->m_String); 770} 771 772void WideString::MakeUpper() { 773 if (!m_pData) 774 return; 775 776 ReallocBeforeWrite(m_pData->m_nDataLength); 777 FXSYS_wcsupr(m_pData->m_String); 778} 779 780size_t WideString::Remove(wchar_t chRemove) { 781 if (!m_pData || m_pData->m_nDataLength < 1) 782 return 0; 783 784 wchar_t* pstrSource = m_pData->m_String; 785 wchar_t* pstrEnd = m_pData->m_String + m_pData->m_nDataLength; 786 while (pstrSource < pstrEnd) { 787 if (*pstrSource == chRemove) 788 break; 789 pstrSource++; 790 } 791 if (pstrSource == pstrEnd) 792 return 0; 793 794 ptrdiff_t copied = pstrSource - m_pData->m_String; 795 ReallocBeforeWrite(m_pData->m_nDataLength); 796 pstrSource = m_pData->m_String + copied; 797 pstrEnd = m_pData->m_String + m_pData->m_nDataLength; 798 799 wchar_t* pstrDest = pstrSource; 800 while (pstrSource < pstrEnd) { 801 if (*pstrSource != chRemove) { 802 *pstrDest = *pstrSource; 803 pstrDest++; 804 } 805 pstrSource++; 806 } 807 808 *pstrDest = 0; 809 size_t count = static_cast<size_t>(pstrSource - pstrDest); 810 m_pData->m_nDataLength -= count; 811 return count; 812} 813 814size_t WideString::Replace(const WideStringView& pOld, 815 const WideStringView& pNew) { 816 if (!m_pData || pOld.IsEmpty()) 817 return 0; 818 819 size_t nSourceLen = pOld.GetLength(); 820 size_t nReplacementLen = pNew.GetLength(); 821 size_t count = 0; 822 const wchar_t* pStart = m_pData->m_String; 823 wchar_t* pEnd = m_pData->m_String + m_pData->m_nDataLength; 824 while (1) { 825 const wchar_t* pTarget = 826 FX_wcsstr(pStart, static_cast<size_t>(pEnd - pStart), 827 pOld.unterminated_c_str(), nSourceLen); 828 if (!pTarget) 829 break; 830 831 count++; 832 pStart = pTarget + nSourceLen; 833 } 834 if (count == 0) 835 return 0; 836 837 size_t nNewLength = 838 m_pData->m_nDataLength + (nReplacementLen - nSourceLen) * count; 839 840 if (nNewLength == 0) { 841 clear(); 842 return count; 843 } 844 845 RetainPtr<StringData> pNewData(StringData::Create(nNewLength)); 846 pStart = m_pData->m_String; 847 wchar_t* pDest = pNewData->m_String; 848 for (size_t i = 0; i < count; i++) { 849 const wchar_t* pTarget = 850 FX_wcsstr(pStart, static_cast<size_t>(pEnd - pStart), 851 pOld.unterminated_c_str(), nSourceLen); 852 wmemcpy(pDest, pStart, pTarget - pStart); 853 pDest += pTarget - pStart; 854 wmemcpy(pDest, pNew.unterminated_c_str(), pNew.GetLength()); 855 pDest += pNew.GetLength(); 856 pStart = pTarget + nSourceLen; 857 } 858 wmemcpy(pDest, pStart, pEnd - pStart); 859 m_pData.Swap(pNewData); 860 return count; 861} 862 863// static 864WideString WideString::FromLocal(const ByteStringView& str) { 865 return FromCodePage(str, 0); 866} 867 868// static 869WideString WideString::FromCodePage(const ByteStringView& str, 870 uint16_t codepage) { 871 return GetWideString(codepage, str); 872} 873 874// static 875WideString WideString::FromUTF8(const ByteStringView& str) { 876 if (str.IsEmpty()) 877 return WideString(); 878 879 CFX_UTF8Decoder decoder; 880 for (size_t i = 0; i < str.GetLength(); i++) 881 decoder.Input(str[i]); 882 883 return WideString(decoder.GetResult()); 884} 885 886// static 887WideString WideString::FromUTF16LE(const unsigned short* wstr, size_t wlen) { 888 if (!wstr || wlen == 0) { 889 return WideString(); 890 } 891 892 WideString result; 893 wchar_t* buf = result.GetBuffer(wlen); 894 for (size_t i = 0; i < wlen; i++) { 895 buf[i] = wstr[i]; 896 } 897 result.ReleaseBuffer(wlen); 898 return result; 899} 900 901void WideString::SetAt(size_t index, wchar_t c) { 902 ASSERT(IsValidIndex(index)); 903 ReallocBeforeWrite(m_pData->m_nDataLength); 904 m_pData->m_String[index] = c; 905} 906 907int WideString::Compare(const wchar_t* lpsz) const { 908 if (m_pData) 909 return lpsz ? wcscmp(m_pData->m_String, lpsz) : 1; 910 return (!lpsz || lpsz[0] == 0) ? 0 : -1; 911} 912 913int WideString::Compare(const WideString& str) const { 914 if (!m_pData) 915 return str.m_pData ? -1 : 0; 916 if (!str.m_pData) 917 return 1; 918 919 size_t this_len = m_pData->m_nDataLength; 920 size_t that_len = str.m_pData->m_nDataLength; 921 size_t min_len = std::min(this_len, that_len); 922 int result = wmemcmp(m_pData->m_String, str.m_pData->m_String, min_len); 923 if (result != 0) 924 return result; 925 if (this_len == that_len) 926 return 0; 927 return this_len < that_len; 928} 929 930int WideString::CompareNoCase(const wchar_t* lpsz) const { 931 if (m_pData) 932 return lpsz ? FXSYS_wcsicmp(m_pData->m_String, lpsz) : 1; 933 return (!lpsz || lpsz[0] == 0) ? 0 : -1; 934} 935 936size_t WideString::WStringLength(const unsigned short* str) { 937 size_t len = 0; 938 if (str) 939 while (str[len]) 940 len++; 941 return len; 942} 943 944void WideString::Trim() { 945 TrimRight(kWideTrimChars); 946 TrimLeft(kWideTrimChars); 947} 948 949void WideString::Trim(wchar_t target) { 950 wchar_t str[2] = {target, 0}; 951 TrimRight(str); 952 TrimLeft(str); 953} 954 955void WideString::Trim(const WideStringView& targets) { 956 TrimRight(targets); 957 TrimLeft(targets); 958} 959 960void WideString::TrimLeft() { 961 TrimLeft(kWideTrimChars); 962} 963 964void WideString::TrimLeft(wchar_t target) { 965 wchar_t str[2] = {target, 0}; 966 TrimLeft(str); 967} 968 969void WideString::TrimLeft(const WideStringView& targets) { 970 if (!m_pData || targets.IsEmpty()) 971 return; 972 973 size_t len = GetLength(); 974 if (len == 0) 975 return; 976 977 size_t pos = 0; 978 while (pos < len) { 979 size_t i = 0; 980 while (i < targets.GetLength() && 981 targets.CharAt(i) != m_pData->m_String[pos]) { 982 i++; 983 } 984 if (i == targets.GetLength()) 985 break; 986 pos++; 987 } 988 if (!pos) 989 return; 990 991 ReallocBeforeWrite(len); 992 size_t nDataLength = len - pos; 993 memmove(m_pData->m_String, m_pData->m_String + pos, 994 (nDataLength + 1) * sizeof(wchar_t)); 995 m_pData->m_nDataLength = nDataLength; 996} 997 998void WideString::TrimRight() { 999 TrimRight(kWideTrimChars); 1000} 1001 1002void WideString::TrimRight(wchar_t target) { 1003 wchar_t str[2] = {target, 0}; 1004 TrimRight(str); 1005} 1006 1007void WideString::TrimRight(const WideStringView& targets) { 1008 if (IsEmpty() || targets.IsEmpty()) 1009 return; 1010 1011 size_t pos = GetLength(); 1012 while (pos && targets.Contains(m_pData->m_String[pos - 1])) 1013 pos--; 1014 1015 if (pos < m_pData->m_nDataLength) { 1016 ReallocBeforeWrite(m_pData->m_nDataLength); 1017 m_pData->m_String[pos] = 0; 1018 m_pData->m_nDataLength = pos; 1019 } 1020} 1021 1022float FX_wtof(const wchar_t* str, int len) { 1023 if (len == 0) { 1024 return 0.0; 1025 } 1026 int cc = 0; 1027 bool bNegative = false; 1028 if (str[0] == '+') { 1029 cc++; 1030 } else if (str[0] == '-') { 1031 bNegative = true; 1032 cc++; 1033 } 1034 int integer = 0; 1035 while (cc < len) { 1036 if (str[cc] == '.') { 1037 break; 1038 } 1039 integer = integer * 10 + FXSYS_DecimalCharToInt(str[cc]); 1040 cc++; 1041 } 1042 float fraction = 0; 1043 if (str[cc] == '.') { 1044 cc++; 1045 float scale = 0.1f; 1046 while (cc < len) { 1047 fraction += scale * FXSYS_DecimalCharToInt(str[cc]); 1048 scale *= 0.1f; 1049 cc++; 1050 } 1051 } 1052 fraction += static_cast<float>(integer); 1053 return bNegative ? -fraction : fraction; 1054} 1055 1056int WideString::GetInteger() const { 1057 return m_pData ? FXSYS_wtoi(m_pData->m_String) : 0; 1058} 1059 1060float WideString::GetFloat() const { 1061 return m_pData ? FX_wtof(m_pData->m_String, m_pData->m_nDataLength) : 0.0f; 1062} 1063 1064std::wostream& operator<<(std::wostream& os, const WideString& str) { 1065 return os.write(str.c_str(), str.GetLength()); 1066} 1067 1068std::ostream& operator<<(std::ostream& os, const WideString& str) { 1069 os << str.UTF8Encode(); 1070 return os; 1071} 1072 1073std::wostream& operator<<(std::wostream& os, const WideStringView& str) { 1074 return os.write(str.unterminated_c_str(), str.GetLength()); 1075} 1076 1077std::ostream& operator<<(std::ostream& os, const WideStringView& str) { 1078 os << FX_UTF8Encode(str); 1079 return os; 1080} 1081 1082} // namespace fxcrt 1083