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
IsValidCodePage(uint16_t codepage)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 
FX_wcsstr(const FX_WCHAR * haystack,int haystack_len,const FX_WCHAR * needle,int needle_len)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 
CFX_WideString()69 CFX_WideString::CFX_WideString() {}
70 
CFX_WideString(const CFX_WideString & other)71 CFX_WideString::CFX_WideString(const CFX_WideString& other)
72     : m_pData(other.m_pData) {}
73 
CFX_WideString(CFX_WideString && other)74 CFX_WideString::CFX_WideString(CFX_WideString&& other) {
75   m_pData.Swap(other.m_pData);
76 }
77 
CFX_WideString(const FX_WCHAR * pStr,FX_STRSIZE nLen)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 
CFX_WideString(FX_WCHAR ch)86 CFX_WideString::CFX_WideString(FX_WCHAR ch) {
87   m_pData.Reset(StringData::Create(1));
88   m_pData->m_String[0] = ch;
89 }
90 
CFX_WideString(const FX_WCHAR * ptr)91 CFX_WideString::CFX_WideString(const FX_WCHAR* ptr)
92     : CFX_WideString(ptr, ptr ? FXSYS_wcslen(ptr) : 0) {}
93 
CFX_WideString(const CFX_WideStringC & stringSrc)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 
CFX_WideString(const CFX_WideStringC & str1,const CFX_WideStringC & str2)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 
~CFX_WideString()111 CFX_WideString::~CFX_WideString() {}
112 
operator =(const FX_WCHAR * pStr)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 
operator =(const CFX_WideStringC & stringSrc)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 
operator =(const CFX_WideString & stringSrc)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 
operator +=(const FX_WCHAR * pStr)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 
operator +=(FX_WCHAR ch)147 const CFX_WideString& CFX_WideString::operator+=(FX_WCHAR ch) {
148   Concat(&ch, 1);
149   return *this;
150 }
151 
operator +=(const CFX_WideString & str)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 
operator +=(const CFX_WideStringC & str)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 
operator ==(const wchar_t * ptr) const166 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 
operator ==(const CFX_WideStringC & str) const177 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 
operator ==(const CFX_WideString & other) const185 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 
operator <(const CFX_WideString & str) const200 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 
AssignCopy(const FX_WCHAR * pSrcData,FX_STRSIZE nSrcLen)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 
ReallocBeforeWrite(FX_STRSIZE nNewLength)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 
AllocBeforeWrite(FX_STRSIZE nNewLength)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 
ReleaseBuffer(FX_STRSIZE nNewLength)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 
Reserve(FX_STRSIZE len)272 void CFX_WideString::Reserve(FX_STRSIZE len) {
273   GetBuffer(len);
274 }
275 
GetBuffer(FX_STRSIZE nMinBufLength)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 
Delete(FX_STRSIZE nIndex,FX_STRSIZE nCount)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 
Concat(const FX_WCHAR * pSrcData,FX_STRSIZE nSrcLen)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 
UTF8Encode() const346 CFX_ByteString CFX_WideString::UTF8Encode() const {
347   return FX_UTF8Encode(AsStringC());
348 }
349 
UTF16LE_Encode() const350 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 
Mid(FX_STRSIZE nFirst) const367 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 
Mid(FX_STRSIZE nFirst,FX_STRSIZE nCount) const374 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 
AllocCopy(CFX_WideString & dest,FX_STRSIZE nCopyLen,FX_STRSIZE nCopyIndex) const391 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 
FormatV(const FX_WCHAR * pFormat,va_list argList)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 
Format(const FX_WCHAR * pFormat,...)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 
Insert(FX_STRSIZE nIndex,FX_WCHAR ch)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 
Right(FX_STRSIZE nCount) const637 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 
Left(FX_STRSIZE nCount) const650 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 
Find(FX_WCHAR ch,FX_STRSIZE nStart) const663 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 
Find(const CFX_WideStringC & pSub,FX_STRSIZE nStart) const675 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 
MakeLower()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 
MakeUpper()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 
Remove(FX_WCHAR chRemove)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 
Replace(const CFX_WideStringC & pOld,const CFX_WideStringC & pNew)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 
SetAt(FX_STRSIZE nIndex,FX_WCHAR ch)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
FromLocal(const CFX_ByteStringC & str)798 CFX_WideString CFX_WideString::FromLocal(const CFX_ByteStringC& str) {
799   return FromCodePage(str, 0);
800 }
801 
802 // static
FromCodePage(const CFX_ByteStringC & str,uint16_t codepage)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
FromUTF8(const CFX_ByteStringC & str)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
FromUTF16LE(const unsigned short * wstr,FX_STRSIZE wlen)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 
Compare(const FX_WCHAR * lpsz) const836 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 
Compare(const CFX_WideString & str) const842 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 
CompareNoCase(const FX_WCHAR * lpsz) const872 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 
WStringLength(const unsigned short * str)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 
TrimRight(const CFX_WideStringC & pTargets)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 
TrimRight(FX_WCHAR chTarget)902 void CFX_WideString::TrimRight(FX_WCHAR chTarget) {
903   FX_WCHAR str[2] = {chTarget, 0};
904   TrimRight(str);
905 }
906 
TrimRight()907 void CFX_WideString::TrimRight() {
908   TrimRight(L"\x09\x0a\x0b\x0c\x0d\x20");
909 }
910 
TrimLeft(const CFX_WideStringC & pTargets)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 
TrimLeft(FX_WCHAR chTarget)940 void CFX_WideString::TrimLeft(FX_WCHAR chTarget) {
941   FX_WCHAR str[2] = {chTarget, 0};
942   TrimLeft(str);
943 }
944 
TrimLeft()945 void CFX_WideString::TrimLeft() {
946   TrimLeft(L"\x09\x0a\x0b\x0c\x0d\x20");
947 }
FX_wtof(const FX_WCHAR * str,int len)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 
GetInteger() const982 int CFX_WideString::GetInteger() const {
983   return m_pData ? FXSYS_wtoi(m_pData->m_String) : 0;
984 }
985 
GetFloat() const986 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
GetByteString(uint16_t codepage,const CFX_WideStringC & wstr)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
GetWideString(uint16_t codepage,const CFX_ByteStringC & bstr)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