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