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