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