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