Getting rid of more (FX_LPCWSTR) casts and fixing two bugs revealed by this.
[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/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     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                         double f;
680                         char pszTemp[256];
681                         f = va_arg(argList, double);
682                         FXSYS_sprintf(pszTemp, "%*.*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     GetBuffer(nMaxLen);
701     if (m_pData) {
702         FXSYS_vsprintf(m_pData->m_String, lpszFormat, argListSave);
703         ReleaseBuffer();
704     }
705     va_end(argListSave);
706 }
707 void CFX_ByteString::Format(FX_LPCSTR lpszFormat, ...)
708 {
709     va_list argList;
710     va_start(argList, lpszFormat);
711     FormatV(lpszFormat, argList);
712     va_end(argList);
713 }
714 FX_STRSIZE CFX_ByteString::Insert(FX_STRSIZE nIndex, FX_CHAR ch)
715 {
716     CopyBeforeWrite();
717     if (nIndex < 0) {
718         nIndex = 0;
719     }
720     FX_STRSIZE nNewLength = m_pData ? m_pData->m_nDataLength : 0;
721     if (nIndex > nNewLength) {
722         nIndex = nNewLength;
723     }
724     nNewLength++;
725     if (m_pData == NULL || m_pData->m_nAllocLength < nNewLength) {
726         CFX_StringData* pOldData = m_pData;
727         FX_LPCSTR pstr = m_pData->m_String;
728         m_pData = FX_AllocString(nNewLength);
729         if (!m_pData) {
730             return 0;
731         }
732         if(pOldData != NULL) {
733             FXSYS_memmove32(m_pData->m_String, pstr, (pOldData->m_nDataLength + 1));
734             FX_ReleaseString(pOldData);
735         } else {
736             m_pData->m_String[0] = 0;
737         }
738     }
739     FXSYS_memmove32(m_pData->m_String + nIndex + 1,
740                     m_pData->m_String + nIndex, (nNewLength - nIndex));
741     m_pData->m_String[nIndex] = ch;
742     m_pData->m_nDataLength = nNewLength;
743     return nNewLength;
744 }
745 CFX_ByteString CFX_ByteString::Right(FX_STRSIZE nCount) const
746 {
747     if (m_pData == NULL) {
748         return CFX_ByteString();
749     }
750     if (nCount < 0) {
751         nCount = 0;
752     }
753     if (nCount >= m_pData->m_nDataLength) {
754         return *this;
755     }
756     CFX_ByteString dest;
757     AllocCopy(dest, nCount, m_pData->m_nDataLength - nCount);
758     return dest;
759 }
760 CFX_ByteString CFX_ByteString::Left(FX_STRSIZE nCount) const
761 {
762     if (m_pData == NULL) {
763         return CFX_ByteString();
764     }
765     if (nCount < 0) {
766         nCount = 0;
767     }
768     if (nCount >= m_pData->m_nDataLength) {
769         return *this;
770     }
771     CFX_ByteString dest;
772     AllocCopy(dest, nCount, 0);
773     return dest;
774 }
775 FX_STRSIZE CFX_ByteString::Find(FX_CHAR ch, FX_STRSIZE nStart) const
776 {
777     if (m_pData == NULL) {
778         return -1;
779     }
780     FX_STRSIZE nLength = m_pData->m_nDataLength;
781     if (nStart >= nLength) {
782         return -1;
783     }
784     FX_LPCSTR lpsz = FXSYS_strchr(m_pData->m_String + nStart, ch);
785     return (lpsz == NULL) ? -1 : (int)(lpsz - m_pData->m_String);
786 }
787 FX_STRSIZE CFX_ByteString::ReverseFind(FX_CHAR ch) const
788 {
789     if (m_pData == NULL) {
790         return -1;
791     }
792     FX_STRSIZE nLength = m_pData->m_nDataLength;
793     while (nLength) {
794         if (m_pData->m_String[nLength - 1] == ch) {
795             return nLength - 1;
796         }
797         nLength --;
798     }
799     return -1;
800 }
801 FX_LPCSTR FX_strstr(FX_LPCSTR str1, int len1, FX_LPCSTR str2, int len2)
802 {
803     if (len2 > len1 || len2 == 0) {
804         return NULL;
805     }
806     FX_LPCSTR end_ptr = str1 + len1 - len2;
807     while (str1 <= end_ptr) {
808         int i = 0;
809         while (1) {
810             if (str1[i] != str2[i]) {
811                 break;
812             }
813             i ++;
814             if (i == len2) {
815                 return str1;
816             }
817         }
818         str1 ++;
819     }
820     return NULL;
821 }
822 FX_STRSIZE CFX_ByteString::Find(FX_BSTR lpszSub, FX_STRSIZE nStart) const
823 {
824     if (m_pData == NULL) {
825         return -1;
826     }
827     FX_STRSIZE nLength = m_pData->m_nDataLength;
828     if (nStart > nLength) {
829         return -1;
830     }
831     FX_LPCSTR lpsz = FX_strstr(m_pData->m_String + nStart, m_pData->m_nDataLength - nStart,
832                                lpszSub.GetCStr(), lpszSub.GetLength());
833     return (lpsz == NULL) ? -1 : (int)(lpsz - m_pData->m_String);
834 }
835 void CFX_ByteString::MakeLower()
836 {
837     if (m_pData == NULL) {
838         return;
839     }
840     CopyBeforeWrite();
841     if (GetLength() < 1) {
842         return;
843     }
844     FXSYS_strlwr(m_pData->m_String);
845 }
846 void CFX_ByteString::MakeUpper()
847 {
848     if (m_pData == NULL) {
849         return;
850     }
851     CopyBeforeWrite();
852     if (GetLength() < 1) {
853         return;
854     }
855     FXSYS_strupr(m_pData->m_String);
856 }
857 FX_STRSIZE CFX_ByteString::Remove(FX_CHAR chRemove)
858 {
859     if (m_pData == NULL) {
860         return 0;
861     }
862     CopyBeforeWrite();
863     if (GetLength() < 1) {
864         return 0;
865     }
866     FX_LPSTR pstrSource = m_pData->m_String;
867     FX_LPSTR pstrDest = m_pData->m_String;
868     FX_LPSTR pstrEnd = m_pData->m_String + m_pData->m_nDataLength;
869     while (pstrSource < pstrEnd) {
870         if (*pstrSource != chRemove) {
871             *pstrDest = *pstrSource;
872             pstrDest ++;
873         }
874         pstrSource ++;
875     }
876     *pstrDest = 0;
877     FX_STRSIZE nCount = (FX_STRSIZE)(pstrSource - pstrDest);
878     m_pData->m_nDataLength -= nCount;
879     return nCount;
880 }
881 FX_STRSIZE CFX_ByteString::Replace(FX_BSTR lpszOld, FX_BSTR lpszNew)
882 {
883     if (m_pData == NULL) {
884         return 0;
885     }
886     if (lpszOld.IsEmpty()) {
887         return 0;
888     }
889     FX_STRSIZE nSourceLen = lpszOld.GetLength();
890     FX_STRSIZE nReplacementLen = lpszNew.GetLength();
891     FX_STRSIZE nCount = 0;
892     FX_LPCSTR pStart = m_pData->m_String;
893     FX_LPSTR pEnd = m_pData->m_String + m_pData->m_nDataLength;
894     while (1) {
895         FX_LPCSTR pTarget = FX_strstr(pStart, (FX_STRSIZE)(pEnd - pStart), lpszOld.GetCStr(), nSourceLen);
896         if (pTarget == NULL) {
897             break;
898         }
899         nCount++;
900         pStart = pTarget + nSourceLen;
901     }
902     if (nCount == 0) {
903         return 0;
904     }
905     FX_STRSIZE nNewLength =  m_pData->m_nDataLength + (nReplacementLen - nSourceLen) * nCount;
906     if (nNewLength == 0) {
907         Empty();
908         return nCount;
909     }
910     CFX_StringData* pNewData = FX_AllocString(nNewLength);
911     if (!pNewData) {
912         return 0;
913     }
914     pStart = m_pData->m_String;
915     FX_LPSTR pDest = pNewData->m_String;
916     for (FX_STRSIZE i = 0; i < nCount; i ++) {
917         FX_LPCSTR pTarget = FX_strstr(pStart, (FX_STRSIZE)(pEnd - pStart), lpszOld.GetCStr(), nSourceLen);
918         FXSYS_memcpy32(pDest, pStart, pTarget - pStart);
919         pDest += pTarget - pStart;
920         FXSYS_memcpy32(pDest, lpszNew.GetCStr(), lpszNew.GetLength());
921         pDest += lpszNew.GetLength();
922         pStart = pTarget + nSourceLen;
923     }
924     FXSYS_memcpy32(pDest, pStart, pEnd - pStart);
925     FX_ReleaseString(m_pData);
926     m_pData = pNewData;
927     return nCount;
928 }
929 void CFX_ByteString::SetAt(FX_STRSIZE nIndex, FX_CHAR ch)
930 {
931     if (m_pData == NULL) {
932         return;
933     }
934     FXSYS_assert(nIndex >= 0);
935     FXSYS_assert(nIndex < m_pData->m_nDataLength);
936     CopyBeforeWrite();
937     m_pData->m_String[nIndex] = ch;
938 }
939 CFX_ByteString CFX_ByteString::LoadFromFile(FX_BSTR filename)
940 {
941     FXSYS_FILE* file = FXSYS_fopen(CFX_ByteString(filename), "rb");
942     if (file == NULL) {
943         return CFX_ByteString();
944     }
945     FXSYS_fseek(file, 0, FXSYS_SEEK_END);
946     int len = FXSYS_ftell(file);
947     FXSYS_fseek(file, 0, FXSYS_SEEK_SET);
948     CFX_ByteString str;
949     FX_LPSTR buf = str.GetBuffer(len);
950     FXSYS_fread(buf, 1, len, file);
951     str.ReleaseBuffer(len);
952     FXSYS_fclose(file);
953     return str;
954 }
955 CFX_WideString CFX_ByteString::UTF8Decode() const
956 {
957     CFX_UTF8Decoder decoder;
958     for (FX_STRSIZE i = 0; i < GetLength(); i ++) {
959         decoder.Input((FX_BYTE)m_pData->m_String[i]);
960     }
961     return decoder.GetResult();
962 }
963 CFX_ByteString CFX_ByteString::FromUnicode(FX_LPCWSTR str, FX_STRSIZE len)
964 {
965     if (len < 0) {
966         len = (FX_STRSIZE)FXSYS_wcslen(str);
967     }
968     CFX_ByteString bstr;
969     bstr.ConvertFrom(CFX_WideString(str, len));
970     return bstr;
971 }
972 CFX_ByteString CFX_ByteString::FromUnicode(const CFX_WideString& str)
973 {
974     return FromUnicode(str.c_str(), str.GetLength());
975 }
976 void CFX_ByteString::ConvertFrom(const CFX_WideString& str, CFX_CharMap* pCharMap)
977 {
978     if (pCharMap == NULL) {
979         pCharMap = CFX_CharMap::GetDefaultMapper();
980     }
981     *this = (*pCharMap->m_GetByteString)(pCharMap, str);
982 }
983 int CFX_ByteString::Compare(FX_BSTR str) const
984 {
985     if (m_pData == NULL) {
986         return str.IsEmpty() ? 0 : -1;
987     }
988     int this_len = m_pData->m_nDataLength;
989     int that_len = str.GetLength();
990     int min_len = this_len < that_len ? this_len : that_len;
991     for (int i = 0; i < min_len; i ++) {
992         if ((FX_BYTE)m_pData->m_String[i] < str.GetAt(i)) {
993             return -1;
994         } else if ((FX_BYTE)m_pData->m_String[i] > str.GetAt(i)) {
995             return 1;
996         }
997     }
998     if (this_len < that_len) {
999         return -1;
1000     } else if (this_len > that_len) {
1001         return 1;
1002     }
1003     return 0;
1004 }
1005 void CFX_ByteString::TrimRight(FX_BSTR lpszTargets)
1006 {
1007     if (m_pData == NULL || lpszTargets.IsEmpty()) {
1008         return;
1009     }
1010     CopyBeforeWrite();
1011     FX_STRSIZE pos = GetLength();
1012     if (pos < 1) {
1013         return;
1014     }
1015     while (pos) {
1016         FX_STRSIZE i = 0;
1017         while (i < lpszTargets.GetLength() && lpszTargets[i] != m_pData->m_String[pos - 1]) {
1018             i ++;
1019         }
1020         if (i == lpszTargets.GetLength()) {
1021             break;
1022         }
1023         pos --;
1024     }
1025     if (pos < m_pData->m_nDataLength) {
1026         m_pData->m_String[pos] = 0;
1027         m_pData->m_nDataLength = pos;
1028     }
1029 }
1030 void CFX_ByteString::TrimRight(FX_CHAR chTarget)
1031 {
1032     TrimRight(CFX_ByteStringC(chTarget));
1033 }
1034 void CFX_ByteString::TrimRight()
1035 {
1036     TrimRight(FX_BSTRC("\x09\x0a\x0b\x0c\x0d\x20"));
1037 }
1038 void CFX_ByteString::TrimLeft(FX_BSTR lpszTargets)
1039 {
1040     if (m_pData == NULL) {
1041         return;
1042     }
1043     if (lpszTargets.IsEmpty()) {
1044         return;
1045     }
1046     CopyBeforeWrite();
1047     FX_STRSIZE len = GetLength();
1048     if (len < 1) {
1049         return;
1050     }
1051     FX_STRSIZE pos = 0;
1052     while (pos < len) {
1053         FX_STRSIZE i = 0;
1054         while (i < lpszTargets.GetLength() && lpszTargets[i] != m_pData->m_String[pos]) {
1055             i ++;
1056         }
1057         if (i == lpszTargets.GetLength()) {
1058             break;
1059         }
1060         pos ++;
1061     }
1062     if (pos) {
1063         FX_STRSIZE nDataLength = len - pos;
1064         FXSYS_memmove32(m_pData->m_String, m_pData->m_String + pos, (nDataLength + 1)*sizeof(FX_CHAR));
1065         m_pData->m_nDataLength = nDataLength;
1066     }
1067 }
1068 void CFX_ByteString::TrimLeft(FX_CHAR chTarget)
1069 {
1070     TrimLeft(CFX_ByteStringC(chTarget));
1071 }
1072 void CFX_ByteString::TrimLeft()
1073 {
1074     TrimLeft(FX_BSTRC("\x09\x0a\x0b\x0c\x0d\x20"));
1075 }
1076 FX_DWORD CFX_ByteString::GetID(FX_STRSIZE start_pos) const
1077 {
1078     return CFX_ByteStringC(*this).GetID(start_pos);
1079 }
1080 FX_DWORD CFX_ByteStringC::GetID(FX_STRSIZE start_pos) const
1081 {
1082     if (m_Length == 0) {
1083         return 0;
1084     }
1085     if (start_pos >= m_Length) {
1086         return 0;
1087     }
1088     FX_DWORD strid = 0;
1089     if (start_pos + 4 > m_Length) {
1090         for (FX_STRSIZE i = 0; i < m_Length - start_pos; i ++) {
1091             strid = strid * 256 + m_Ptr[start_pos + i];
1092         }
1093         strid = strid << ((4 - m_Length + start_pos) * 8);
1094     } else {
1095         for (int i = 0; i < 4; i ++) {
1096             strid = strid * 256 + m_Ptr[start_pos + i];
1097         }
1098     }
1099     return strid;
1100 }
1101 FX_STRSIZE FX_ftoa(FX_FLOAT d, FX_LPSTR buf)
1102 {
1103     buf[0] = '0';
1104     buf[1] = '\0';
1105     if (d == 0.0f) {
1106         return 1;
1107     }
1108     FX_BOOL bNegative = FALSE;
1109     if (d < 0) {
1110         bNegative = TRUE;
1111         d = -d;
1112     }
1113     int scale = 1;
1114     int scaled = FXSYS_round(d);
1115     while (scaled < 100000) {
1116         if (scale == 1000000) {
1117             break;
1118         }
1119         scale *= 10;
1120         scaled = FXSYS_round(d * scale);
1121     }
1122     if (scaled == 0) {
1123         return 1;
1124     }
1125     char buf2[32];
1126     int buf_size = 0;
1127     if (bNegative) {
1128         buf[buf_size++] = '-';
1129     }
1130     int i = scaled / scale;
1131     FXSYS_itoa(i, buf2, 10);
1132     FX_STRSIZE len = (FX_STRSIZE)FXSYS_strlen(buf2);
1133     FXSYS_memcpy32(buf + buf_size, buf2, len);
1134     buf_size += len;
1135     int fraction = scaled % scale;
1136     if (fraction == 0) {
1137         return buf_size;
1138     }
1139     buf[buf_size++] = '.';
1140     scale /= 10;
1141     while (fraction) {
1142         buf[buf_size++] = '0' + fraction / scale;
1143         fraction %= scale;
1144         scale /= 10;
1145     }
1146     return buf_size;
1147 }
1148 CFX_ByteString CFX_ByteString::FormatFloat(FX_FLOAT d, int precision)
1149 {
1150     FX_CHAR buf[32];
1151     FX_STRSIZE len = FX_ftoa(d, buf);
1152     return CFX_ByteString(buf, len);
1153 }
1154 void CFX_StringBufBase::Copy(FX_BSTR str)
1155 {
1156     m_Size = str.GetLength();
1157     if (m_Size > m_Limit) {
1158         m_Size = m_Limit;
1159     }
1160     FX_CHAR* pBuffer = (FX_CHAR*)(this + 1);
1161     FXSYS_memcpy32(pBuffer, str.GetPtr(), m_Size);
1162 }
1163 void CFX_StringBufBase::Append(FX_BSTR str)
1164 {
1165     int len = str.GetLength();
1166     if (len > m_Limit - m_Size) {
1167         len = m_Limit - m_Size;
1168     }
1169     FX_CHAR* pBuffer = (FX_CHAR*)(this + 1);
1170     FXSYS_memcpy32(pBuffer + m_Size, str.GetPtr(), len);
1171     m_Size += len;
1172 }
1173 void CFX_StringBufBase::Append(int i, FX_DWORD flags)
1174 {
1175     char buf[32];
1176     int len = _Buffer_itoa(buf, i, flags);
1177     Append(CFX_ByteStringC(buf, len));
1178 }