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