Home | History | Annotate | Download | only in fxcrt
      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 
     23 template class fxcrt::StringDataTemplate<wchar_t>;
     24 template class fxcrt::StringViewTemplate<wchar_t>;
     25 template class fxcrt::StringPoolTemplate<WideString>;
     26 template struct std::hash<WideString>;
     27 
     28 #define FORCE_ANSI 0x10000
     29 #define FORCE_UNICODE 0x20000
     30 #define FORCE_INT64 0x40000
     31 
     32 namespace {
     33 
     34 constexpr wchar_t kWideTrimChars[] = L"\x09\x0a\x0b\x0c\x0d\x20";
     35 
     36 const 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 
     60 Optional<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.
    252 Optional<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
    276 bool 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 
    290 WideString 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 
    311 namespace fxcrt {
    312 
    313 static_assert(sizeof(WideString) <= sizeof(wchar_t*),
    314               "Strings must not require more space than pointers");
    315 
    316 // static
    317 WideString 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
    347 WideString 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 
    355 WideString::WideString() {}
    356 
    357 WideString::WideString(const WideString& other) : m_pData(other.m_pData) {}
    358 
    359 WideString::WideString(WideString&& other) noexcept {
    360   m_pData.Swap(other.m_pData);
    361 }
    362 
    363 WideString::WideString(const wchar_t* pStr, size_t nLen) {
    364   if (nLen)
    365     m_pData.Reset(StringData::Create(pStr, nLen));
    366 }
    367 
    368 WideString::WideString(wchar_t ch) {
    369   m_pData.Reset(StringData::Create(1));
    370   m_pData->m_String[0] = ch;
    371 }
    372 
    373 WideString::WideString(const wchar_t* ptr)
    374     : WideString(ptr, ptr ? wcslen(ptr) : 0) {}
    375 
    376 WideString::WideString(const WideStringView& stringSrc) {
    377   if (!stringSrc.IsEmpty()) {
    378     m_pData.Reset(StringData::Create(stringSrc.unterminated_c_str(),
    379                                      stringSrc.GetLength()));
    380   }
    381 }
    382 
    383 WideString::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 
    397 WideString::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 
    416 WideString::~WideString() {}
    417 
    418 const 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 
    427 const 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 
    436 const 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 
    443 const WideString& WideString::operator+=(const wchar_t* pStr) {
    444   if (pStr)
    445     Concat(pStr, wcslen(pStr));
    446 
    447   return *this;
    448 }
    449 
    450 const WideString& WideString::operator+=(wchar_t ch) {
    451   Concat(&ch, 1);
    452   return *this;
    453 }
    454 
    455 const 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 
    462 const WideString& WideString::operator+=(const WideStringView& str) {
    463   if (!str.IsEmpty())
    464     Concat(str.unterminated_c_str(), str.GetLength());
    465 
    466   return *this;
    467 }
    468 
    469 bool 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 
    480 bool 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 
    489 bool 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 
    504 bool WideString::operator<(const wchar_t* ptr) const {
    505   return Compare(ptr) < 0;
    506 }
    507 
    508 bool 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 
    521 bool WideString::operator<(const WideString& other) const {
    522   return Compare(other) < 0;
    523 }
    524 
    525 void 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 
    531 void 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 
    552 void 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 
    564 void 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 
    585 void WideString::Reserve(size_t len) {
    586   GetBuffer(len);
    587 }
    588 
    589 wchar_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 
    614 size_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 
    635 void 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 
    657 ByteString WideString::UTF8Encode() const {
    658   return FX_UTF8Encode(AsStringView());
    659 }
    660 
    661 ByteString 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 
    678 WideString 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 
    699 WideString WideString::Left(size_t count) const {
    700   if (count == 0 || !IsValidLength(count))
    701     return WideString();
    702   return Mid(0, count);
    703 }
    704 
    705 WideString WideString::Right(size_t count) const {
    706   if (count == 0 || !IsValidLength(count))
    707     return WideString();
    708   return Mid(GetLength() - count, count);
    709 }
    710 
    711 void 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 
    722 size_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 
    736 Optional<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 
    749 Optional<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 
    764 void WideString::MakeLower() {
    765   if (!m_pData)
    766     return;
    767 
    768   ReallocBeforeWrite(m_pData->m_nDataLength);
    769   FXSYS_wcslwr(m_pData->m_String);
    770 }
    771 
    772 void WideString::MakeUpper() {
    773   if (!m_pData)
    774     return;
    775 
    776   ReallocBeforeWrite(m_pData->m_nDataLength);
    777   FXSYS_wcsupr(m_pData->m_String);
    778 }
    779 
    780 size_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 
    814 size_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
    864 WideString WideString::FromLocal(const ByteStringView& str) {
    865   return FromCodePage(str, 0);
    866 }
    867 
    868 // static
    869 WideString WideString::FromCodePage(const ByteStringView& str,
    870                                     uint16_t codepage) {
    871   return GetWideString(codepage, str);
    872 }
    873 
    874 // static
    875 WideString 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
    887 WideString 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 
    901 void 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 
    907 int 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 
    913 int 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 
    930 int 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 
    936 size_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 
    944 void WideString::Trim() {
    945   TrimRight(kWideTrimChars);
    946   TrimLeft(kWideTrimChars);
    947 }
    948 
    949 void WideString::Trim(wchar_t target) {
    950   wchar_t str[2] = {target, 0};
    951   TrimRight(str);
    952   TrimLeft(str);
    953 }
    954 
    955 void WideString::Trim(const WideStringView& targets) {
    956   TrimRight(targets);
    957   TrimLeft(targets);
    958 }
    959 
    960 void WideString::TrimLeft() {
    961   TrimLeft(kWideTrimChars);
    962 }
    963 
    964 void WideString::TrimLeft(wchar_t target) {
    965   wchar_t str[2] = {target, 0};
    966   TrimLeft(str);
    967 }
    968 
    969 void 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 
    998 void WideString::TrimRight() {
    999   TrimRight(kWideTrimChars);
   1000 }
   1001 
   1002 void WideString::TrimRight(wchar_t target) {
   1003   wchar_t str[2] = {target, 0};
   1004   TrimRight(str);
   1005 }
   1006 
   1007 void 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 
   1022 float 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 
   1056 int WideString::GetInteger() const {
   1057   return m_pData ? FXSYS_wtoi(m_pData->m_String) : 0;
   1058 }
   1059 
   1060 float WideString::GetFloat() const {
   1061   return m_pData ? FX_wtof(m_pData->m_String, m_pData->m_nDataLength) : 0.0f;
   1062 }
   1063 
   1064 std::wostream& operator<<(std::wostream& os, const WideString& str) {
   1065   return os.write(str.c_str(), str.GetLength());
   1066 }
   1067 
   1068 std::ostream& operator<<(std::ostream& os, const WideString& str) {
   1069   os << str.UTF8Encode();
   1070   return os;
   1071 }
   1072 
   1073 std::wostream& operator<<(std::wostream& os, const WideStringView& str) {
   1074   return os.write(str.unterminated_c_str(), str.GetLength());
   1075 }
   1076 
   1077 std::ostream& operator<<(std::ostream& os, const WideStringView& str) {
   1078   os << FX_UTF8Encode(str);
   1079   return os;
   1080 }
   1081 
   1082 }  // namespace fxcrt
   1083