fx_basic_bstring.cpp revision ee451cb395940862dad63c85adfe8f2fd55e864c
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 "../../include/fxcrt/fx_basic.h"
8static int _Buffer_itoa(char* buf, int i, FX_DWORD flags)
9{
10    if (i == 0) {
11        buf[0] = '0';
12        return 1;
13    }
14    char buf1[32];
15    int buf_pos = 31;
16    FX_DWORD u = i;
17    if ((flags & FXFORMAT_SIGNED) && i < 0) {
18        u = -i;
19    }
20    int base = 10;
21    FX_LPCSTR string = "0123456789abcdef";
22    if (flags & FXFORMAT_HEX) {
23        base = 16;
24        if (flags & FXFORMAT_CAPITAL) {
25            string = "0123456789ABCDEF";
26        }
27    }
28    while (u != 0) {
29        buf1[buf_pos--] = string[u % base];
30        u = u / base;
31    }
32    if ((flags & FXFORMAT_SIGNED) && i < 0) {
33        buf1[buf_pos--] = '-';
34    }
35    int len = 31 - buf_pos;
36    for (int ii = 0; ii < len; ii ++) {
37        buf[ii] = buf1[ii + buf_pos + 1];
38    }
39    return len;
40}
41CFX_ByteString CFX_ByteString::FormatInteger(int i, FX_DWORD flags)
42{
43    char buf[32];
44    return CFX_ByteStringC(buf, _Buffer_itoa(buf, i, flags));
45}
46static CFX_StringData* FX_AllocString(int nLen)
47{
48    if (nLen == 0) {
49        return NULL;
50    }
51    CFX_StringData* pData = (CFX_StringData*)FX_Alloc(FX_BYTE, sizeof(long) * 3 + (nLen + 1) * sizeof(char));
52    if (!pData) {
53        return NULL;
54    }
55    pData->m_nAllocLength = nLen;
56    pData->m_nDataLength = nLen;
57    pData->m_nRefs = 1;
58    pData->m_String[nLen] = 0;
59    return pData;
60}
61static void FX_ReleaseString(CFX_StringData* pData)
62{
63    if (pData == NULL) {
64        return;
65    }
66    pData->m_nRefs --;
67    if (pData->m_nRefs <= 0) {
68        FX_Free(pData);
69    }
70}
71CFX_ByteString::~CFX_ByteString()
72{
73    if (m_pData == NULL) {
74        return;
75    }
76    m_pData->m_nRefs --;
77    if (m_pData->m_nRefs < 1) {
78        FX_Free(m_pData);
79    }
80}
81CFX_ByteString::CFX_ByteString(FX_LPCSTR lpsz, FX_STRSIZE nLen)
82{
83    if (nLen < 0) {
84        nLen = lpsz ? (FX_STRSIZE)FXSYS_strlen(lpsz) : 0;
85    }
86    if (nLen) {
87        m_pData = FX_AllocString(nLen);
88        if (m_pData) {
89            FXSYS_memcpy32(m_pData->m_String, lpsz, nLen * sizeof(char));
90        }
91    } else {
92        m_pData = NULL;
93    }
94}
95CFX_ByteString::CFX_ByteString(FX_LPCBYTE lpsz, FX_STRSIZE nLen)
96{
97    if (nLen > 0) {
98        m_pData = FX_AllocString(nLen);
99        if (m_pData) {
100            FXSYS_memcpy32(m_pData->m_String, lpsz, nLen * sizeof(char));
101        }
102    } else {
103        m_pData = NULL;
104    }
105}
106CFX_ByteString::CFX_ByteString(char ch)
107{
108    m_pData = FX_AllocString(1);
109    if (m_pData) {
110        m_pData->m_String[0] = ch;
111    }
112}
113CFX_ByteString::CFX_ByteString(const CFX_ByteString& stringSrc)
114{
115    if (stringSrc.m_pData == NULL) {
116        m_pData = NULL;
117        return;
118    }
119    if (stringSrc.m_pData->m_nRefs >= 0) {
120        m_pData = stringSrc.m_pData;
121        m_pData->m_nRefs ++;
122    } else {
123        m_pData = NULL;
124        *this = stringSrc;
125    }
126}
127CFX_ByteString::CFX_ByteString(FX_BSTR stringSrc)
128{
129    if (stringSrc.IsEmpty()) {
130        m_pData = NULL;
131        return;
132    } else {
133        m_pData = NULL;
134        *this = stringSrc;
135    }
136}
137CFX_ByteString::CFX_ByteString(FX_BSTR str1, FX_BSTR str2)
138{
139    m_pData = NULL;
140    int nNewLen = str1.GetLength() + str2.GetLength();
141    if (nNewLen == 0) {
142        return;
143    }
144    m_pData = FX_AllocString(nNewLen);
145    if (m_pData) {
146        FXSYS_memcpy32(m_pData->m_String, str1.GetCStr(), str1.GetLength());
147        FXSYS_memcpy32(m_pData->m_String + str1.GetLength(), str2.GetCStr(), str2.GetLength());
148    }
149}
150const CFX_ByteString& CFX_ByteString::operator=(FX_LPCSTR lpsz)
151{
152    if (lpsz == NULL || lpsz[0] == 0) {
153        Empty();
154    } else {
155        AssignCopy((FX_STRSIZE)FXSYS_strlen(lpsz), lpsz);
156    }
157    return *this;
158}
159const CFX_ByteString& CFX_ByteString::operator=(FX_BSTR str)
160{
161    if (str.IsEmpty()) {
162        Empty();
163    } else {
164        AssignCopy(str.GetLength(), str.GetCStr());
165    }
166    return *this;
167}
168const CFX_ByteString& CFX_ByteString::operator=(const CFX_ByteString& stringSrc)
169{
170    if (m_pData == stringSrc.m_pData) {
171        return *this;
172    }
173    if (stringSrc.IsEmpty()) {
174        Empty();
175    } else if ((m_pData && m_pData->m_nRefs < 0) ||
176               (stringSrc.m_pData && stringSrc.m_pData->m_nRefs < 0)) {
177        AssignCopy(stringSrc.m_pData->m_nDataLength, stringSrc.m_pData->m_String);
178    } else {
179        Empty();
180        m_pData = stringSrc.m_pData;
181        if (m_pData) {
182            m_pData->m_nRefs ++;
183        }
184    }
185    return *this;
186}
187const CFX_ByteString& CFX_ByteString::operator=(const CFX_BinaryBuf& buf)
188{
189    Load(buf.GetBuffer(), buf.GetSize());
190    return *this;
191}
192void CFX_ByteString::Load(FX_LPCBYTE buf, FX_STRSIZE len)
193{
194    Empty();
195    if (len) {
196        m_pData = FX_AllocString(len);
197        if (m_pData) {
198            FXSYS_memcpy32(m_pData->m_String, buf, len * sizeof(char));
199        }
200    } else {
201        m_pData = NULL;
202    }
203}
204const CFX_ByteString& CFX_ByteString::operator+=(FX_LPCSTR lpsz)
205{
206    if (lpsz) {
207        ConcatInPlace((FX_STRSIZE)FXSYS_strlen(lpsz), lpsz);
208    }
209    return *this;
210}
211const CFX_ByteString& CFX_ByteString::operator+=(char ch)
212{
213    ConcatInPlace(1, &ch);
214    return *this;
215}
216const CFX_ByteString& CFX_ByteString::operator+=(const CFX_ByteString& string)
217{
218    if (string.m_pData == NULL) {
219        return *this;
220    }
221    ConcatInPlace(string.m_pData->m_nDataLength, string.m_pData->m_String);
222    return *this;
223}
224const CFX_ByteString& CFX_ByteString::operator+=(FX_BSTR string)
225{
226    if (string.IsEmpty()) {
227        return *this;
228    }
229    ConcatInPlace(string.GetLength(), string.GetCStr());
230    return *this;
231}
232bool CFX_ByteString::Equal(FX_BSTR str) const
233{
234    if (m_pData == NULL) {
235        return str.IsEmpty();
236    }
237    return m_pData->m_nDataLength == str.GetLength() &&
238           FXSYS_memcmp32(m_pData->m_String, str.GetCStr(), str.GetLength()) == 0;
239}
240bool CFX_ByteString::operator ==(const CFX_ByteString& s2) const
241{
242    if (m_pData == NULL) {
243        return s2.IsEmpty();
244    }
245    if (s2.m_pData == NULL) {
246        return false;
247    }
248    return m_pData->m_nDataLength == s2.m_pData->m_nDataLength &&
249           FXSYS_memcmp32(m_pData->m_String, s2.m_pData->m_String, m_pData->m_nDataLength) == 0;
250}
251void CFX_ByteString::Empty()
252{
253    if (m_pData == NULL) {
254        return;
255    }
256    if (m_pData->m_nRefs > 1) {
257        m_pData->m_nRefs --;
258    } else {
259        FX_Free(m_pData);
260    }
261    m_pData = NULL;
262}
263bool CFX_ByteString::EqualNoCase(FX_BSTR str) const
264{
265    if (m_pData == NULL) {
266        return str.IsEmpty();
267    }
268    FX_STRSIZE len = str.GetLength();
269    if (m_pData->m_nDataLength != len) {
270        return false;
271    }
272    FX_LPCBYTE pThis = (FX_LPCBYTE)m_pData->m_String;
273    FX_LPCBYTE pThat = (FX_LPCBYTE)str;
274    for (FX_STRSIZE i = 0; i < len; i ++) {
275        if ((*pThis) != (*pThat)) {
276            FX_BYTE bThis = *pThis;
277            if (bThis >= 'A' && bThis <= 'Z') {
278                bThis += 'a' - 'A';
279            }
280            FX_BYTE bThat = *pThat;
281            if (bThat >= 'A' && bThat <= 'Z') {
282                bThat += 'a' - 'A';
283            }
284            if (bThis != bThat) {
285                return false;
286            }
287        }
288        pThis ++;
289        pThat ++;
290    }
291    return true;
292}
293void CFX_ByteString::AssignCopy(FX_STRSIZE nSrcLen, FX_LPCSTR lpszSrcData)
294{
295    AllocBeforeWrite(nSrcLen);
296    FXSYS_memcpy32(m_pData->m_String, lpszSrcData, nSrcLen * sizeof(char));
297    m_pData->m_nDataLength = nSrcLen;
298    m_pData->m_String[nSrcLen] = 0;
299}
300void CFX_ByteString::CopyBeforeWrite()
301{
302    if (m_pData == NULL || m_pData->m_nRefs <= 1) {
303        return;
304    }
305    CFX_StringData* pData = m_pData;
306    m_pData->m_nRefs --;
307    FX_STRSIZE nDataLength = pData->m_nDataLength;
308    m_pData = FX_AllocString(nDataLength);
309    if (m_pData != NULL) {
310        FXSYS_memcpy32(m_pData->m_String, pData->m_String, (nDataLength + 1) * sizeof(char));
311    }
312}
313void CFX_ByteString::AllocBeforeWrite(FX_STRSIZE nLen)
314{
315    if (m_pData && m_pData->m_nRefs <= 1 && m_pData->m_nAllocLength >= nLen) {
316        return;
317    }
318    Empty();
319    m_pData = FX_AllocString(nLen);
320}
321void CFX_ByteString::ReleaseBuffer(FX_STRSIZE nNewLength)
322{
323    if (m_pData == NULL) {
324        return;
325    }
326    CopyBeforeWrite();
327    if (nNewLength == -1) {
328        nNewLength = (FX_STRSIZE)FXSYS_strlen((FX_LPCSTR)m_pData->m_String);
329    }
330    if (nNewLength == 0) {
331        Empty();
332        return;
333    }
334    FXSYS_assert(nNewLength <= m_pData->m_nAllocLength);
335    m_pData->m_nDataLength = nNewLength;
336    m_pData->m_String[nNewLength] = 0;
337}
338FX_LPSTR CFX_ByteString::LockBuffer()
339{
340    if (m_pData == NULL) {
341        return NULL;
342    }
343    FX_LPSTR lpsz = GetBuffer(0);
344    m_pData->m_nRefs = -1;
345    return lpsz;
346}
347void CFX_ByteString::Reserve(FX_STRSIZE len)
348{
349    GetBuffer(len);
350    ReleaseBuffer(GetLength());
351}
352FX_LPSTR CFX_ByteString::GetBuffer(FX_STRSIZE nMinBufLength)
353{
354    if (m_pData == NULL && nMinBufLength == 0) {
355        return NULL;
356    }
357    if (m_pData && m_pData->m_nRefs <= 1 && m_pData->m_nAllocLength >= nMinBufLength) {
358        return m_pData->m_String;
359    }
360    if (m_pData == NULL) {
361        m_pData = FX_AllocString(nMinBufLength);
362        if (!m_pData) {
363            return NULL;
364        }
365        m_pData->m_nDataLength = 0;
366        m_pData->m_String[0] = 0;
367        return m_pData->m_String;
368    }
369    CFX_StringData* pOldData = m_pData;
370    FX_STRSIZE nOldLen = pOldData->m_nDataLength;
371    if (nMinBufLength < nOldLen) {
372        nMinBufLength = nOldLen;
373    }
374    m_pData = FX_AllocString(nMinBufLength);
375    if (!m_pData) {
376        return NULL;
377    }
378    FXSYS_memcpy32(m_pData->m_String, pOldData->m_String, (nOldLen + 1)*sizeof(char));
379    m_pData->m_nDataLength = nOldLen;
380    pOldData->m_nRefs --;
381    if (pOldData->m_nRefs <= 0) {
382        FX_Free(pOldData);
383    }
384    return m_pData->m_String;
385}
386FX_STRSIZE CFX_ByteString::Delete(FX_STRSIZE nIndex, FX_STRSIZE nCount)
387{
388    if (m_pData == NULL) {
389        return 0;
390    }
391    if (nIndex < 0) {
392        nIndex = 0;
393    }
394    FX_STRSIZE nOldLength = m_pData->m_nDataLength;
395    if (nCount > 0 && nIndex < nOldLength) {
396        FX_STRSIZE mLength = nIndex + nCount;
397        if (mLength >= nOldLength) {
398            m_pData->m_nDataLength = nIndex;
399            return m_pData->m_nDataLength;
400        }
401        CopyBeforeWrite();
402        int nBytesToCopy = nOldLength - mLength + 1;
403        FXSYS_memmove32(m_pData->m_String + nIndex,
404                        m_pData->m_String + mLength, nBytesToCopy * sizeof(char));
405        m_pData->m_nDataLength = nOldLength - nCount;
406    }
407    return m_pData->m_nDataLength;
408}
409void CFX_ByteString::ConcatInPlace(FX_STRSIZE nSrcLen, FX_LPCSTR lpszSrcData)
410{
411    if (nSrcLen == 0 || lpszSrcData == NULL) {
412        return;
413    }
414    if (m_pData == NULL) {
415        m_pData = FX_AllocString(nSrcLen);
416        if (!m_pData) {
417            return;
418        }
419        FXSYS_memcpy32(m_pData->m_String, lpszSrcData, nSrcLen * sizeof(char));
420        return;
421    }
422    if (m_pData->m_nRefs > 1 || m_pData->m_nDataLength + nSrcLen > m_pData->m_nAllocLength) {
423        CFX_StringData* pOldData = m_pData;
424        ConcatCopy(m_pData->m_nDataLength, m_pData->m_String, nSrcLen, lpszSrcData);
425        FX_ReleaseString(pOldData);
426    } else {
427        FXSYS_memcpy32(m_pData->m_String + m_pData->m_nDataLength, lpszSrcData, nSrcLen * sizeof(char));
428        m_pData->m_nDataLength += nSrcLen;
429        m_pData->m_String[m_pData->m_nDataLength] = 0;
430    }
431}
432void CFX_ByteString::ConcatCopy(FX_STRSIZE nSrc1Len, FX_LPCSTR lpszSrc1Data,
433                                FX_STRSIZE nSrc2Len, FX_LPCSTR lpszSrc2Data)
434{
435    int nNewLen = nSrc1Len + nSrc2Len;
436    if (nNewLen == 0) {
437        return;
438    }
439    m_pData = FX_AllocString(nNewLen);
440    if (m_pData) {
441        FXSYS_memcpy32(m_pData->m_String, lpszSrc1Data, nSrc1Len * sizeof(char));
442        FXSYS_memcpy32(m_pData->m_String + nSrc1Len, lpszSrc2Data, nSrc2Len * sizeof(char));
443    }
444}
445CFX_ByteString CFX_ByteString::Mid(FX_STRSIZE nFirst) const
446{
447    if (m_pData == NULL) {
448        return CFX_ByteString();
449    }
450    return Mid(nFirst, m_pData->m_nDataLength - nFirst);
451}
452CFX_ByteString CFX_ByteString::Mid(FX_STRSIZE nFirst, FX_STRSIZE nCount) const
453{
454    if (nFirst < 0) {
455        nFirst = 0;
456    }
457    if (nCount < 0) {
458        nCount = 0;
459    }
460    if (nFirst + nCount > m_pData->m_nDataLength) {
461        nCount = m_pData->m_nDataLength - nFirst;
462    }
463    if (nFirst > m_pData->m_nDataLength) {
464        nCount = 0;
465    }
466    if (nFirst == 0 && nFirst + nCount == m_pData->m_nDataLength) {
467        return *this;
468    }
469    CFX_ByteString dest;
470    AllocCopy(dest, nCount, nFirst, 0);
471    return dest;
472}
473void CFX_ByteString::AllocCopy(CFX_ByteString& dest, FX_STRSIZE nCopyLen, FX_STRSIZE nCopyIndex,
474                               FX_STRSIZE nExtraLen) const
475{
476    FX_STRSIZE nNewLen = nCopyLen + nExtraLen;
477    if (nNewLen == 0) {
478        return;
479    }
480    ASSERT(dest.m_pData == NULL);
481    dest.m_pData = FX_AllocString(nNewLen);
482    if (dest.m_pData) {
483        FXSYS_memcpy32(dest.m_pData->m_String, m_pData->m_String + nCopyIndex, nCopyLen * sizeof(char));
484    }
485}
486#define FORCE_ANSI      0x10000
487#define FORCE_UNICODE   0x20000
488#define FORCE_INT64     0x40000
489void CFX_ByteString::FormatV(FX_LPCSTR lpszFormat, va_list argList)
490{
491    va_list argListSave;
492#if defined(__ARMCC_VERSION) || (!defined(_MSC_VER) && (_FX_CPU_ == _FX_X64_ || _FX_CPU_ == _FX_IA64_ || _FX_CPU_ == _FX_ARM64_)) || defined(__native_client__)
493    va_copy(argListSave, argList);
494#else
495    argListSave = argList;
496#endif
497    int nMaxLen = 0;
498    for (FX_LPCSTR lpsz = lpszFormat; *lpsz != 0; lpsz ++) {
499        if (*lpsz != '%' || *(lpsz = lpsz + 1) == '%') {
500            nMaxLen += (FX_STRSIZE)FXSYS_strlen(lpsz);
501            continue;
502        }
503        int nItemLen = 0;
504        int nWidth = 0;
505        for (; *lpsz != 0; lpsz ++) {
506            if (*lpsz == '#') {
507                nMaxLen += 2;
508            } else if (*lpsz == '*') {
509                nWidth = va_arg(argList, int);
510            } else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' ||
511                       *lpsz == ' ')
512                ;
513            else {
514                break;
515            }
516        }
517        if (nWidth == 0) {
518            nWidth = FXSYS_atoi(lpsz);
519            for (; (*lpsz) >= '0' && (*lpsz) <= '9'; lpsz ++)
520                ;
521        }
522        if (nWidth < 0 || nWidth > 128 * 1024) {
523            lpszFormat = "Bad width";
524            nMaxLen = 10;
525            break;
526        }
527        int nPrecision = 0;
528        if (*lpsz == '.') {
529            lpsz ++;
530            if (*lpsz == '*') {
531                nPrecision = va_arg(argList, int);
532                lpsz ++;
533            } else {
534                nPrecision = FXSYS_atoi(lpsz);
535                for (; (*lpsz) >= '0' && (*lpsz) <= '9'; lpsz ++)
536                    ;
537            }
538        }
539        if (nPrecision < 0 || nPrecision > 128 * 1024) {
540            lpszFormat = "Bad precision";
541            nMaxLen = 14;
542            break;
543        }
544        int nModifier = 0;
545        if (FXSYS_strncmp(lpsz, "I64", 3) == 0) {
546            lpsz += 3;
547            nModifier = FORCE_INT64;
548        } else {
549            switch (*lpsz) {
550                case 'h':
551                    nModifier = FORCE_ANSI;
552                    lpsz ++;
553                    break;
554                case 'l':
555                    nModifier = FORCE_UNICODE;
556                    lpsz ++;
557                    break;
558                case 'F':
559                case 'N':
560                case 'L':
561                    lpsz ++;
562                    break;
563            }
564        }
565        switch (*lpsz | nModifier) {
566            case 'c':
567            case 'C':
568                nItemLen = 2;
569                va_arg(argList, int);
570                break;
571            case 'c'|FORCE_ANSI:
572            case 'C'|FORCE_ANSI:
573                nItemLen = 2;
574                va_arg(argList, int);
575                break;
576            case 'c'|FORCE_UNICODE:
577            case 'C'|FORCE_UNICODE:
578                nItemLen = 2;
579                va_arg(argList, int);
580                break;
581            case 's': {
582                    FX_LPCSTR pstrNextArg = va_arg(argList, FX_LPCSTR);
583                    if (pstrNextArg == NULL) {
584                        nItemLen = 6;
585                    } else {
586                        nItemLen = (FX_STRSIZE)FXSYS_strlen(pstrNextArg);
587                        if (nItemLen < 1) {
588                            nItemLen = 1;
589                        }
590                    }
591                }
592                break;
593            case 'S': {
594                    FX_LPWSTR pstrNextArg = va_arg(argList, FX_LPWSTR);
595                    if (pstrNextArg == NULL) {
596                        nItemLen = 6;
597                    } else {
598                        nItemLen = (FX_STRSIZE)FXSYS_wcslen(pstrNextArg);
599                        if (nItemLen < 1) {
600                            nItemLen = 1;
601                        }
602                    }
603                }
604                break;
605            case 's'|FORCE_ANSI:
606            case 'S'|FORCE_ANSI: {
607                    FX_LPCSTR pstrNextArg = va_arg(argList, FX_LPCSTR);
608                    if (pstrNextArg == NULL) {
609                        nItemLen = 6;
610                    } else {
611                        nItemLen = (FX_STRSIZE)FXSYS_strlen(pstrNextArg);
612                        if (nItemLen < 1) {
613                            nItemLen = 1;
614                        }
615                    }
616                }
617                break;
618            case 's'|FORCE_UNICODE:
619            case 'S'|FORCE_UNICODE: {
620                    FX_LPWSTR pstrNextArg = va_arg(argList, FX_LPWSTR);
621                    if (pstrNextArg == NULL) {
622                        nItemLen = 6;
623                    } else {
624                        nItemLen = (FX_STRSIZE)FXSYS_wcslen(pstrNextArg);
625                        if (nItemLen < 1) {
626                            nItemLen = 1;
627                        }
628                    }
629                }
630                break;
631        }
632        if (nItemLen != 0) {
633            if (nPrecision != 0 && nItemLen > nPrecision) {
634                nItemLen = nPrecision;
635            }
636            if (nItemLen < nWidth) {
637                nItemLen = nWidth;
638            }
639        } else {
640            switch (*lpsz) {
641                case 'd':
642                case 'i':
643                case 'u':
644                case 'x':
645                case 'X':
646                case 'o':
647                    if (nModifier & FORCE_INT64) {
648                        va_arg(argList, FX_INT64);
649                    } else {
650                        va_arg(argList, int);
651                    }
652                    nItemLen = 32;
653                    if (nItemLen < nWidth + nPrecision) {
654                        nItemLen = nWidth + nPrecision;
655                    }
656                    break;
657                case 'a':
658                case 'A':
659                case 'e':
660                case 'E':
661                case 'g':
662                case 'G':
663                    va_arg(argList, double);
664                    nItemLen = 128;
665                    if (nItemLen < nWidth + nPrecision) {
666                        nItemLen = nWidth + nPrecision;
667                    }
668                    break;
669                case 'f':
670                    if (nWidth + nPrecision > 100) {
671                        nItemLen = nPrecision + nWidth + 128;
672                    } else {
673                        double f;
674                        char pszTemp[256];
675                        f = va_arg(argList, double);
676                        FXSYS_sprintf(pszTemp, "%*.*f", nWidth, nPrecision + 6, f );
677                        nItemLen = (FX_STRSIZE)FXSYS_strlen(pszTemp);
678                    }
679                    break;
680                case 'p':
681                    va_arg(argList, void*);
682                    nItemLen = 32;
683                    if (nItemLen < nWidth + nPrecision) {
684                        nItemLen = nWidth + nPrecision;
685                    }
686                    break;
687                case 'n':
688                    va_arg(argList, int*);
689                    break;
690            }
691        }
692        nMaxLen += nItemLen;
693    }
694    GetBuffer(nMaxLen);
695    if (m_pData) {
696        FXSYS_vsprintf(m_pData->m_String, lpszFormat, argListSave);
697        ReleaseBuffer();
698    }
699    va_end(argListSave);
700}
701void CFX_ByteString::Format(FX_LPCSTR lpszFormat, ...)
702{
703    va_list argList;
704    va_start(argList, lpszFormat);
705    FormatV(lpszFormat, argList);
706    va_end(argList);
707}
708FX_STRSIZE CFX_ByteString::Insert(FX_STRSIZE nIndex, FX_CHAR ch)
709{
710    CopyBeforeWrite();
711    if (nIndex < 0) {
712        nIndex = 0;
713    }
714    FX_STRSIZE nNewLength = m_pData ? m_pData->m_nDataLength : 0;
715    if (nIndex > nNewLength) {
716        nIndex = nNewLength;
717    }
718    nNewLength++;
719    if (m_pData == NULL || m_pData->m_nAllocLength < nNewLength) {
720        CFX_StringData* pOldData = m_pData;
721        FX_LPCSTR pstr = m_pData->m_String;
722        m_pData = FX_AllocString(nNewLength);
723        if (!m_pData) {
724            return 0;
725        }
726        if(pOldData != NULL) {
727            FXSYS_memmove32(m_pData->m_String, pstr, (pOldData->m_nDataLength + 1)*sizeof(char));
728            FX_ReleaseString(pOldData);
729        } else {
730            m_pData->m_String[0] = 0;
731        }
732    }
733    FXSYS_memmove32(m_pData->m_String + nIndex + 1,
734                    m_pData->m_String + nIndex, (nNewLength - nIndex)*sizeof(char));
735    m_pData->m_String[nIndex] = ch;
736    m_pData->m_nDataLength = nNewLength;
737    return nNewLength;
738}
739CFX_ByteString CFX_ByteString::Right(FX_STRSIZE nCount) const
740{
741    if (m_pData == NULL) {
742        return CFX_ByteString();
743    }
744    if (nCount < 0) {
745        nCount = 0;
746    }
747    if (nCount >= m_pData->m_nDataLength) {
748        return *this;
749    }
750    CFX_ByteString dest;
751    AllocCopy(dest, nCount, m_pData->m_nDataLength - nCount, 0);
752    return dest;
753}
754CFX_ByteString CFX_ByteString::Left(FX_STRSIZE nCount) const
755{
756    if (m_pData == NULL) {
757        return CFX_ByteString();
758    }
759    if (nCount < 0) {
760        nCount = 0;
761    }
762    if (nCount >= m_pData->m_nDataLength) {
763        return *this;
764    }
765    CFX_ByteString dest;
766    AllocCopy(dest, nCount, 0, 0);
767    return dest;
768}
769FX_STRSIZE CFX_ByteString::Find(FX_CHAR ch, FX_STRSIZE nStart) const
770{
771    if (m_pData == NULL) {
772        return -1;
773    }
774    FX_STRSIZE nLength = m_pData->m_nDataLength;
775    if (nStart >= nLength) {
776        return -1;
777    }
778    FX_LPCSTR lpsz = FXSYS_strchr(m_pData->m_String + nStart, ch);
779    return (lpsz == NULL) ? -1 : (int)(lpsz - m_pData->m_String);
780}
781FX_STRSIZE CFX_ByteString::ReverseFind(FX_CHAR ch) const
782{
783    if (m_pData == NULL) {
784        return -1;
785    }
786    FX_STRSIZE nLength = m_pData->m_nDataLength;
787    while (nLength) {
788        if (m_pData->m_String[nLength - 1] == ch) {
789            return nLength - 1;
790        }
791        nLength --;
792    }
793    return -1;
794}
795FX_LPCSTR FX_strstr(FX_LPCSTR str1, int len1, FX_LPCSTR str2, int len2)
796{
797    if (len2 > len1 || len2 == 0) {
798        return NULL;
799    }
800    FX_LPCSTR end_ptr = str1 + len1 - len2;
801    while (str1 <= end_ptr) {
802        int i = 0;
803        while (1) {
804            if (str1[i] != str2[i]) {
805                break;
806            }
807            i ++;
808            if (i == len2) {
809                return str1;
810            }
811        }
812        str1 ++;
813    }
814    return NULL;
815}
816FX_STRSIZE CFX_ByteString::Find(FX_BSTR lpszSub, FX_STRSIZE nStart) const
817{
818    if (m_pData == NULL) {
819        return -1;
820    }
821    FX_STRSIZE nLength = m_pData->m_nDataLength;
822    if (nStart > nLength) {
823        return -1;
824    }
825    FX_LPCSTR lpsz = FX_strstr(m_pData->m_String + nStart, m_pData->m_nDataLength - nStart,
826                               lpszSub.GetCStr(), lpszSub.GetLength());
827    return (lpsz == NULL) ? -1 : (int)(lpsz - m_pData->m_String);
828}
829void CFX_ByteString::MakeLower()
830{
831    if (m_pData == NULL) {
832        return;
833    }
834    CopyBeforeWrite();
835    if (GetLength() < 1) {
836        return;
837    }
838    FXSYS_strlwr(m_pData->m_String);
839}
840void CFX_ByteString::MakeUpper()
841{
842    if (m_pData == NULL) {
843        return;
844    }
845    CopyBeforeWrite();
846    if (GetLength() < 1) {
847        return;
848    }
849    FXSYS_strupr(m_pData->m_String);
850}
851FX_STRSIZE CFX_ByteString::Remove(FX_CHAR chRemove)
852{
853    if (m_pData == NULL) {
854        return 0;
855    }
856    CopyBeforeWrite();
857    if (GetLength() < 1) {
858        return 0;
859    }
860    FX_LPSTR pstrSource = m_pData->m_String;
861    FX_LPSTR pstrDest = m_pData->m_String;
862    FX_LPSTR pstrEnd = m_pData->m_String + m_pData->m_nDataLength;
863    while (pstrSource < pstrEnd) {
864        if (*pstrSource != chRemove) {
865            *pstrDest = *pstrSource;
866            pstrDest ++;
867        }
868        pstrSource ++;
869    }
870    *pstrDest = 0;
871    FX_STRSIZE nCount = (FX_STRSIZE)(pstrSource - pstrDest);
872    m_pData->m_nDataLength -= nCount;
873    return nCount;
874}
875FX_STRSIZE CFX_ByteString::Replace(FX_BSTR lpszOld, FX_BSTR lpszNew)
876{
877    if (m_pData == NULL) {
878        return 0;
879    }
880    if (lpszOld.IsEmpty()) {
881        return 0;
882    }
883    FX_STRSIZE nSourceLen = lpszOld.GetLength();
884    FX_STRSIZE nReplacementLen = lpszNew.GetLength();
885    FX_STRSIZE nCount = 0;
886    FX_LPCSTR pStart = m_pData->m_String;
887    FX_LPSTR pEnd = m_pData->m_String + m_pData->m_nDataLength;
888    while (1) {
889        FX_LPCSTR pTarget = FX_strstr(pStart, (FX_STRSIZE)(pEnd - pStart), lpszOld.GetCStr(), nSourceLen);
890        if (pTarget == NULL) {
891            break;
892        }
893        nCount++;
894        pStart = pTarget + nSourceLen;
895    }
896    if (nCount == 0) {
897        return 0;
898    }
899    FX_STRSIZE nNewLength =  m_pData->m_nDataLength + (nReplacementLen - nSourceLen) * nCount;
900    if (nNewLength == 0) {
901        Empty();
902        return nCount;
903    }
904    CFX_StringData* pNewData = FX_AllocString(nNewLength);
905    if (!pNewData) {
906        return 0;
907    }
908    pStart = m_pData->m_String;
909    FX_LPSTR pDest = pNewData->m_String;
910    for (FX_STRSIZE i = 0; i < nCount; i ++) {
911        FX_LPCSTR pTarget = FX_strstr(pStart, (FX_STRSIZE)(pEnd - pStart), lpszOld.GetCStr(), nSourceLen);
912        FXSYS_memcpy32(pDest, pStart, pTarget - pStart);
913        pDest += pTarget - pStart;
914        FXSYS_memcpy32(pDest, lpszNew.GetCStr(), lpszNew.GetLength());
915        pDest += lpszNew.GetLength();
916        pStart = pTarget + nSourceLen;
917    }
918    FXSYS_memcpy32(pDest, pStart, pEnd - pStart);
919    FX_ReleaseString(m_pData);
920    m_pData = pNewData;
921    return nCount;
922}
923void CFX_ByteString::SetAt(FX_STRSIZE nIndex, FX_CHAR ch)
924{
925    if (m_pData == NULL) {
926        return;
927    }
928    FXSYS_assert(nIndex >= 0);
929    FXSYS_assert(nIndex < m_pData->m_nDataLength);
930    CopyBeforeWrite();
931    m_pData->m_String[nIndex] = ch;
932}
933CFX_ByteString CFX_ByteString::LoadFromFile(FX_BSTR filename)
934{
935    FXSYS_FILE* file = FXSYS_fopen(CFX_ByteString(filename), "rb");
936    if (file == NULL) {
937        return CFX_ByteString();
938    }
939    FXSYS_fseek(file, 0, FXSYS_SEEK_END);
940    int len = FXSYS_ftell(file);
941    FXSYS_fseek(file, 0, FXSYS_SEEK_SET);
942    CFX_ByteString str;
943    FX_LPSTR buf = str.GetBuffer(len);
944    size_t readCnt = FXSYS_fread(buf, 1, len, file);
945    str.ReleaseBuffer(len);
946    FXSYS_fclose(file);
947    return str;
948}
949CFX_WideString CFX_ByteString::UTF8Decode() const
950{
951    CFX_UTF8Decoder decoder;
952    for (FX_STRSIZE i = 0; i < GetLength(); i ++) {
953        decoder.Input((FX_BYTE)m_pData->m_String[i]);
954    }
955    return decoder.GetResult();
956}
957CFX_ByteString CFX_ByteString::FromUnicode(FX_LPCWSTR str, FX_STRSIZE len)
958{
959    if (len < 0) {
960        len = (FX_STRSIZE)FXSYS_wcslen(str);
961    }
962    CFX_ByteString bstr;
963    bstr.ConvertFrom(CFX_WideString(str, len));
964    return bstr;
965}
966CFX_ByteString CFX_ByteString::FromUnicode(const CFX_WideString& str)
967{
968    return FromUnicode((FX_LPCWSTR)str, str.GetLength());
969}
970void CFX_ByteString::ConvertFrom(const CFX_WideString& str, CFX_CharMap* pCharMap)
971{
972    if (pCharMap == NULL) {
973        pCharMap = CFX_CharMap::GetDefaultMapper();
974    }
975    *this = (*pCharMap->m_GetByteString)(pCharMap, str);
976}
977int CFX_ByteString::Compare(FX_BSTR str) const
978{
979    if (m_pData == NULL) {
980        return str.IsEmpty() ? 0 : -1;
981    }
982    int this_len = m_pData->m_nDataLength;
983    int that_len = str.GetLength();
984    int min_len = this_len < that_len ? this_len : that_len;
985    for (int i = 0; i < min_len; i ++) {
986        if ((FX_BYTE)m_pData->m_String[i] < str.GetAt(i)) {
987            return -1;
988        } else if ((FX_BYTE)m_pData->m_String[i] > str.GetAt(i)) {
989            return 1;
990        }
991    }
992    if (this_len < that_len) {
993        return -1;
994    } else if (this_len > that_len) {
995        return 1;
996    }
997    return 0;
998}
999void CFX_ByteString::TrimRight(FX_BSTR lpszTargets)
1000{
1001    if (m_pData == NULL || lpszTargets.IsEmpty()) {
1002        return;
1003    }
1004    CopyBeforeWrite();
1005    FX_STRSIZE pos = GetLength();
1006    if (pos < 1) {
1007        return;
1008    }
1009    while (pos) {
1010        FX_STRSIZE i = 0;
1011        while (i < lpszTargets.GetLength() && lpszTargets[i] != m_pData->m_String[pos - 1]) {
1012            i ++;
1013        }
1014        if (i == lpszTargets.GetLength()) {
1015            break;
1016        }
1017        pos --;
1018    }
1019    if (pos < m_pData->m_nDataLength) {
1020        m_pData->m_String[pos] = 0;
1021        m_pData->m_nDataLength = pos;
1022    }
1023}
1024void CFX_ByteString::TrimRight(FX_CHAR chTarget)
1025{
1026    TrimRight(CFX_ByteStringC(chTarget));
1027}
1028void CFX_ByteString::TrimRight()
1029{
1030    TrimRight(FX_BSTRC("\x09\x0a\x0b\x0c\x0d\x20"));
1031}
1032void CFX_ByteString::TrimLeft(FX_BSTR lpszTargets)
1033{
1034    if (m_pData == NULL) {
1035        return;
1036    }
1037    if (lpszTargets.IsEmpty()) {
1038        return;
1039    }
1040    CopyBeforeWrite();
1041    FX_STRSIZE len = GetLength();
1042    if (len < 1) {
1043        return;
1044    }
1045    FX_STRSIZE pos = 0;
1046    while (pos < len) {
1047        FX_STRSIZE i = 0;
1048        while (i < lpszTargets.GetLength() && lpszTargets[i] != m_pData->m_String[pos]) {
1049            i ++;
1050        }
1051        if (i == lpszTargets.GetLength()) {
1052            break;
1053        }
1054        pos ++;
1055    }
1056    if (pos) {
1057        FX_STRSIZE nDataLength = len - pos;
1058        FXSYS_memmove32(m_pData->m_String, m_pData->m_String + pos, (nDataLength + 1)*sizeof(FX_CHAR));
1059        m_pData->m_nDataLength = nDataLength;
1060    }
1061}
1062void CFX_ByteString::TrimLeft(FX_CHAR chTarget)
1063{
1064    TrimLeft(CFX_ByteStringC(chTarget));
1065}
1066void CFX_ByteString::TrimLeft()
1067{
1068    TrimLeft(FX_BSTRC("\x09\x0a\x0b\x0c\x0d\x20"));
1069}
1070FX_DWORD CFX_ByteString::GetID(FX_STRSIZE start_pos) const
1071{
1072    return CFX_ByteStringC(*this).GetID(start_pos);
1073}
1074FX_DWORD CFX_ByteStringC::GetID(FX_STRSIZE start_pos) const
1075{
1076    if (m_Length == 0) {
1077        return 0;
1078    }
1079    if (start_pos >= m_Length) {
1080        return 0;
1081    }
1082    FX_DWORD strid = 0;
1083    if (start_pos + 4 > m_Length) {
1084        for (FX_STRSIZE i = 0; i < m_Length - start_pos; i ++) {
1085            strid = strid * 256 + m_Ptr[start_pos + i];
1086        }
1087        strid = strid << ((4 - m_Length + start_pos) * 8);
1088    } else {
1089        for (int i = 0; i < 4; i ++) {
1090            strid = strid * 256 + m_Ptr[start_pos + i];
1091        }
1092    }
1093    return strid;
1094}
1095FX_STRSIZE FX_ftoa(FX_FLOAT d, FX_LPSTR buf)
1096{
1097    buf[0] = '0';
1098    buf[1] = '\0';
1099    if (d == 0.0f) {
1100        return 1;
1101    }
1102    FX_BOOL bNegative = FALSE;
1103    if (d < 0) {
1104        bNegative = TRUE;
1105        d = -d;
1106    }
1107    int scale = 1;
1108    int scaled = FXSYS_round(d);
1109    while (scaled < 100000) {
1110        if (scale == 1000000) {
1111            break;
1112        }
1113        scale *= 10;
1114        scaled = FXSYS_round(d * scale);
1115    }
1116    if (scaled == 0) {
1117        return 1;
1118    }
1119    char buf2[32];
1120    int buf_size = 0;
1121    if (bNegative) {
1122        buf[buf_size++] = '-';
1123    }
1124    int i = scaled / scale;
1125    FXSYS_itoa(i, buf2, 10);
1126    FX_STRSIZE len = (FX_STRSIZE)FXSYS_strlen(buf2);
1127    FXSYS_memcpy32(buf + buf_size, buf2, len);
1128    buf_size += len;
1129    int fraction = scaled % scale;
1130    if (fraction == 0) {
1131        return buf_size;
1132    }
1133    buf[buf_size++] = '.';
1134    scale /= 10;
1135    while (fraction) {
1136        buf[buf_size++] = '0' + fraction / scale;
1137        fraction %= scale;
1138        scale /= 10;
1139    }
1140    return buf_size;
1141}
1142CFX_ByteString CFX_ByteString::FormatFloat(FX_FLOAT d, int precision)
1143{
1144    FX_CHAR buf[32];
1145    FX_STRSIZE len = FX_ftoa(d, buf);
1146    return CFX_ByteString(buf, len);
1147}
1148void CFX_StringBufBase::Copy(FX_BSTR str)
1149{
1150    m_Size = str.GetLength();
1151    if (m_Size > m_Limit) {
1152        m_Size = m_Limit;
1153    }
1154    FX_CHAR* pBuffer = (FX_CHAR*)(this + 1);
1155    FXSYS_memcpy32(pBuffer, str.GetPtr(), m_Size);
1156}
1157void CFX_StringBufBase::Append(FX_BSTR str)
1158{
1159    int len = str.GetLength();
1160    if (len > m_Limit - m_Size) {
1161        len = m_Limit - m_Size;
1162    }
1163    FX_CHAR* pBuffer = (FX_CHAR*)(this + 1);
1164    FXSYS_memcpy32(pBuffer + m_Size, str.GetPtr(), len);
1165    m_Size += len;
1166}
1167void CFX_StringBufBase::Append(int i, FX_DWORD flags)
1168{
1169    char buf[32];
1170    int len = _Buffer_itoa(buf, i, flags);
1171    Append(CFX_ByteStringC(buf, len));
1172}
1173void CFX_ByteStringL::Empty(IFX_Allocator* pAllocator)
1174{
1175    if (m_Ptr) {
1176        FX_Allocator_Free(pAllocator, (FX_LPVOID)m_Ptr);
1177    }
1178    m_Ptr = NULL, m_Length = 0;
1179}
1180FX_LPSTR CFX_ByteStringL::AllocBuffer(FX_STRSIZE length, IFX_Allocator* pAllocator)
1181{
1182    Empty(pAllocator);
1183    FX_LPSTR str = FX_Allocator_Alloc(pAllocator, FX_CHAR, length + 1);
1184    if (!str) {
1185        return NULL;
1186    }
1187    *(FX_LPSTR*)(&m_Ptr) = str;
1188    m_Length = length;
1189    return str;
1190}
1191void CFX_ByteStringL::Set(FX_BSTR src, IFX_Allocator* pAllocator)
1192{
1193    Empty(pAllocator);
1194    if (src.GetCStr() != NULL && src.GetLength() > 0) {
1195        FX_LPSTR str = FX_Allocator_Alloc(pAllocator, FX_CHAR, src.GetLength() + 1);
1196        if (!str) {
1197            return;
1198        }
1199        FXSYS_memcpy32(str, src, src.GetLength());
1200        str[src.GetLength()] = '\0';
1201        *(FX_LPSTR*)(&m_Ptr) = str;
1202        m_Length = src.GetLength();
1203    }
1204}
1205