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