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