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