Fix potential UAF in ConcatInPlace.
[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         ConcatCopy(m_pData->m_nDataLength, m_pData->m_String, nSrcLen, lpszSrcData);
426     } else {
427         FXSYS_memcpy32(m_pData->m_String + m_pData->m_nDataLength, lpszSrcData, nSrcLen);
428         m_pData->m_nDataLength += nSrcLen;
429         m_pData->m_String[m_pData->m_nDataLength] = 0;
430     }
431 }
432 void CFX_ByteString::ConcatCopy(FX_STRSIZE nSrc1Len, FX_LPCSTR lpszSrc1Data,
433                                 FX_STRSIZE nSrc2Len, FX_LPCSTR lpszSrc2Data)
434 {
435     int nNewLen = nSrc1Len + nSrc2Len;
436     if (nNewLen <= 0) {
437         return;
438     }
439     // Don't release until done copying, might be one of the arguments.
440     StringData* pOldData = m_pData;
441     m_pData = StringData::Create(nNewLen);
442     if (m_pData) {
443         memcpy(m_pData->m_String, lpszSrc1Data, nSrc1Len);
444         memcpy(m_pData->m_String + nSrc1Len, lpszSrc2Data, nSrc2Len);
445     }
446     pOldData->Release();
447 }
448 CFX_ByteString CFX_ByteString::Mid(FX_STRSIZE nFirst) const
449 {
450     if (m_pData == NULL) {
451         return CFX_ByteString();
452     }
453     return Mid(nFirst, m_pData->m_nDataLength - nFirst);
454 }
455 CFX_ByteString CFX_ByteString::Mid(FX_STRSIZE nFirst, FX_STRSIZE nCount) const
456 {
457     if (nFirst < 0) {
458         nFirst = 0;
459     }
460     if (nCount < 0) {
461         nCount = 0;
462     }
463     if (nFirst + nCount > m_pData->m_nDataLength) {
464         nCount = m_pData->m_nDataLength - nFirst;
465     }
466     if (nFirst > m_pData->m_nDataLength) {
467         nCount = 0;
468     }
469     if (nFirst == 0 && nFirst + nCount == m_pData->m_nDataLength) {
470         return *this;
471     }
472     CFX_ByteString dest;
473     AllocCopy(dest, nCount, nFirst);
474     return dest;
475 }
476 void CFX_ByteString::AllocCopy(CFX_ByteString& dest, FX_STRSIZE nCopyLen, FX_STRSIZE nCopyIndex) const
477 {
478     // |FX_STRSIZE| is currently typedef'd as in |int|. TODO(palmer): It
479     // should be a |size_t|, or at least unsigned.
480     if (nCopyLen == 0 || nCopyLen < 0) {
481         return;
482     }
483     ASSERT(dest.m_pData == NULL);
484     dest.m_pData = StringData::Create(nCopyLen);
485     if (dest.m_pData) {
486         FXSYS_memcpy32(dest.m_pData->m_String, m_pData->m_String + nCopyIndex, nCopyLen);
487     }
488 }
489 #define FORCE_ANSI      0x10000
490 #define FORCE_UNICODE   0x20000
491 #define FORCE_INT64     0x40000
492 void CFX_ByteString::FormatV(FX_LPCSTR lpszFormat, va_list argList)
493 {
494     va_list argListSave;
495 #if defined(__ARMCC_VERSION) || (!defined(_MSC_VER) && (_FX_CPU_ == _FX_X64_ || _FX_CPU_ == _FX_IA64_ || _FX_CPU_ == _FX_ARM64_)) || defined(__native_client__)
496     va_copy(argListSave, argList);
497 #else
498     argListSave = argList;
499 #endif
500     int nMaxLen = 0;
501     for (FX_LPCSTR lpsz = lpszFormat; *lpsz != 0; lpsz ++) {
502         if (*lpsz != '%' || *(lpsz = lpsz + 1) == '%') {
503             nMaxLen += FXSYS_strlen(lpsz);
504             continue;
505         }
506         int nItemLen = 0;
507         int nWidth = 0;
508         for (; *lpsz != 0; lpsz ++) {
509             if (*lpsz == '#') {
510                 nMaxLen += 2;
511             } else if (*lpsz == '*') {
512                 nWidth = va_arg(argList, int);
513             } else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' ||
514                        *lpsz == ' ')
515                 ;
516             else {
517                 break;
518             }
519         }
520         if (nWidth == 0) {
521             nWidth = FXSYS_atoi(lpsz);
522             for (; (*lpsz) >= '0' && (*lpsz) <= '9'; lpsz ++)
523                 ;
524         }
525         if (nWidth < 0 || nWidth > 128 * 1024) {
526             lpszFormat = "Bad width";
527             nMaxLen = 10;
528             break;
529         }
530         int nPrecision = 0;
531         if (*lpsz == '.') {
532             lpsz ++;
533             if (*lpsz == '*') {
534                 nPrecision = va_arg(argList, int);
535                 lpsz ++;
536             } else {
537                 nPrecision = FXSYS_atoi(lpsz);
538                 for (; (*lpsz) >= '0' && (*lpsz) <= '9'; lpsz ++)
539                     ;
540             }
541         }
542         if (nPrecision < 0 || nPrecision > 128 * 1024) {
543             lpszFormat = "Bad precision";
544             nMaxLen = 14;
545             break;
546         }
547         int nModifier = 0;
548         if (FXSYS_strncmp(lpsz, "I64", 3) == 0) {
549             lpsz += 3;
550             nModifier = FORCE_INT64;
551         } else {
552             switch (*lpsz) {
553                 case 'h':
554                     nModifier = FORCE_ANSI;
555                     lpsz ++;
556                     break;
557                 case 'l':
558                     nModifier = FORCE_UNICODE;
559                     lpsz ++;
560                     break;
561                 case 'F':
562                 case 'N':
563                 case 'L':
564                     lpsz ++;
565                     break;
566             }
567         }
568         switch (*lpsz | nModifier) {
569             case 'c':
570             case 'C':
571                 nItemLen = 2;
572                 va_arg(argList, int);
573                 break;
574             case 'c'|FORCE_ANSI:
575             case 'C'|FORCE_ANSI:
576                 nItemLen = 2;
577                 va_arg(argList, int);
578                 break;
579             case 'c'|FORCE_UNICODE:
580             case 'C'|FORCE_UNICODE:
581                 nItemLen = 2;
582                 va_arg(argList, int);
583                 break;
584             case 's': {
585                     FX_LPCSTR pstrNextArg = va_arg(argList, FX_LPCSTR);
586                     if (pstrNextArg == NULL) {
587                         nItemLen = 6;
588                     } else {
589                         nItemLen = FXSYS_strlen(pstrNextArg);
590                         if (nItemLen < 1) {
591                             nItemLen = 1;
592                         }
593                     }
594                 }
595                 break;
596             case 'S': {
597                     FX_LPWSTR pstrNextArg = va_arg(argList, FX_LPWSTR);
598                     if (pstrNextArg == NULL) {
599                         nItemLen = 6;
600                     } else {
601                         nItemLen = FXSYS_wcslen(pstrNextArg);
602                         if (nItemLen < 1) {
603                             nItemLen = 1;
604                         }
605                     }
606                 }
607                 break;
608             case 's'|FORCE_ANSI:
609             case 'S'|FORCE_ANSI: {
610                     FX_LPCSTR pstrNextArg = va_arg(argList, FX_LPCSTR);
611                     if (pstrNextArg == NULL) {
612                         nItemLen = 6;
613                     } else {
614                         nItemLen = FXSYS_strlen(pstrNextArg);
615                         if (nItemLen < 1) {
616                             nItemLen = 1;
617                         }
618                     }
619                 }
620                 break;
621             case 's'|FORCE_UNICODE:
622             case 'S'|FORCE_UNICODE: {
623                     FX_LPWSTR pstrNextArg = va_arg(argList, FX_LPWSTR);
624                     if (pstrNextArg == NULL) {
625                         nItemLen = 6;
626                     } else {
627                         nItemLen = FXSYS_wcslen(pstrNextArg);
628                         if (nItemLen < 1) {
629                             nItemLen = 1;
630                         }
631                     }
632                 }
633                 break;
634         }
635         if (nItemLen != 0) {
636             if (nPrecision != 0 && nItemLen > nPrecision) {
637                 nItemLen = nPrecision;
638             }
639             if (nItemLen < nWidth) {
640                 nItemLen = nWidth;
641             }
642         } else {
643             switch (*lpsz) {
644                 case 'd':
645                 case 'i':
646                 case 'u':
647                 case 'x':
648                 case 'X':
649                 case 'o':
650                     if (nModifier & FORCE_INT64) {
651                         va_arg(argList, FX_INT64);
652                     } else {
653                         va_arg(argList, int);
654                     }
655                     nItemLen = 32;
656                     if (nItemLen < nWidth + nPrecision) {
657                         nItemLen = nWidth + nPrecision;
658                     }
659                     break;
660                 case 'a':
661                 case 'A':
662                 case 'e':
663                 case 'E':
664                 case 'g':
665                 case 'G':
666                     va_arg(argList, double);
667                     nItemLen = 128;
668                     if (nItemLen < nWidth + nPrecision) {
669                         nItemLen = nWidth + nPrecision;
670                     }
671                     break;
672                 case 'f':
673                     if (nWidth + nPrecision > 100) {
674                         nItemLen = nPrecision + nWidth + 128;
675                     } else {
676                         char pszTemp[256];
677                         double f = va_arg(argList, double);
678                         memset(pszTemp, 0, sizeof(pszTemp));
679                         FXSYS_snprintf(pszTemp, sizeof(pszTemp) - 1, "%*.*f", nWidth, nPrecision + 6, f);
680                         nItemLen = FXSYS_strlen(pszTemp);
681                     }
682                     break;
683                 case 'p':
684                     va_arg(argList, void*);
685                     nItemLen = 32;
686                     if (nItemLen < nWidth + nPrecision) {
687                         nItemLen = nWidth + nPrecision;
688                     }
689                     break;
690                 case 'n':
691                     va_arg(argList, int*);
692                     break;
693             }
694         }
695         nMaxLen += nItemLen;
696     }
697     nMaxLen += 32;  // Fudge factor.
698     GetBuffer(nMaxLen);
699     if (m_pData) {
700         memset(m_pData->m_String, 0, nMaxLen);
701         FXSYS_vsnprintf(m_pData->m_String, nMaxLen - 1, lpszFormat, argListSave);
702         ReleaseBuffer();
703     }
704     va_end(argListSave);
705 }
706 void CFX_ByteString::Format(FX_LPCSTR lpszFormat, ...)
707 {
708     va_list argList;
709     va_start(argList, lpszFormat);
710     FormatV(lpszFormat, argList);
711     va_end(argList);
712 }
713 FX_STRSIZE CFX_ByteString::Insert(FX_STRSIZE nIndex, FX_CHAR ch)
714 {
715     CopyBeforeWrite();
716     if (nIndex < 0) {
717         nIndex = 0;
718     }
719     FX_STRSIZE nNewLength = m_pData ? m_pData->m_nDataLength : 0;
720     if (nIndex > nNewLength) {
721         nIndex = nNewLength;
722     }
723     nNewLength++;
724     if (m_pData == NULL || m_pData->m_nAllocLength < nNewLength) {
725         StringData* pOldData = m_pData;
726         FX_LPCSTR pstr = m_pData->m_String;
727         m_pData = StringData::Create(nNewLength);
728         if (!m_pData) {
729             return 0;
730         }
731         if(pOldData != NULL) {
732             FXSYS_memmove32(m_pData->m_String, pstr, (pOldData->m_nDataLength + 1));
733             pOldData->Release();
734         } else {
735             m_pData->m_String[0] = 0;
736         }
737     }
738     FXSYS_memmove32(m_pData->m_String + nIndex + 1,
739                     m_pData->m_String + nIndex, (nNewLength - nIndex));
740     m_pData->m_String[nIndex] = ch;
741     m_pData->m_nDataLength = nNewLength;
742     return nNewLength;
743 }
744 CFX_ByteString CFX_ByteString::Right(FX_STRSIZE nCount) const
745 {
746     if (m_pData == NULL) {
747         return CFX_ByteString();
748     }
749     if (nCount < 0) {
750         nCount = 0;
751     }
752     if (nCount >= m_pData->m_nDataLength) {
753         return *this;
754     }
755     CFX_ByteString dest;
756     AllocCopy(dest, nCount, m_pData->m_nDataLength - nCount);
757     return dest;
758 }
759 CFX_ByteString CFX_ByteString::Left(FX_STRSIZE nCount) const
760 {
761     if (m_pData == NULL) {
762         return CFX_ByteString();
763     }
764     if (nCount < 0) {
765         nCount = 0;
766     }
767     if (nCount >= m_pData->m_nDataLength) {
768         return *this;
769     }
770     CFX_ByteString dest;
771     AllocCopy(dest, nCount, 0);
772     return dest;
773 }
774 FX_STRSIZE CFX_ByteString::Find(FX_CHAR ch, FX_STRSIZE nStart) const
775 {
776     if (m_pData == NULL) {
777         return -1;
778     }
779     FX_STRSIZE nLength = m_pData->m_nDataLength;
780     if (nStart >= nLength) {
781         return -1;
782     }
783     FX_LPCSTR lpsz = FXSYS_strchr(m_pData->m_String + nStart, ch);
784     return (lpsz == NULL) ? -1 : (int)(lpsz - m_pData->m_String);
785 }
786 FX_STRSIZE CFX_ByteString::ReverseFind(FX_CHAR ch) const
787 {
788     if (m_pData == NULL) {
789         return -1;
790     }
791     FX_STRSIZE nLength = m_pData->m_nDataLength;
792     while (nLength) {
793         if (m_pData->m_String[nLength - 1] == ch) {
794             return nLength - 1;
795         }
796         nLength --;
797     }
798     return -1;
799 }
800 FX_LPCSTR FX_strstr(FX_LPCSTR str1, int len1, FX_LPCSTR str2, int len2)
801 {
802     if (len2 > len1 || len2 == 0) {
803         return NULL;
804     }
805     FX_LPCSTR end_ptr = str1 + len1 - len2;
806     while (str1 <= end_ptr) {
807         int i = 0;
808         while (1) {
809             if (str1[i] != str2[i]) {
810                 break;
811             }
812             i ++;
813             if (i == len2) {
814                 return str1;
815             }
816         }
817         str1 ++;
818     }
819     return NULL;
820 }
821 FX_STRSIZE CFX_ByteString::Find(FX_BSTR lpszSub, FX_STRSIZE nStart) const
822 {
823     if (m_pData == NULL) {
824         return -1;
825     }
826     FX_STRSIZE nLength = m_pData->m_nDataLength;
827     if (nStart > nLength) {
828         return -1;
829     }
830     FX_LPCSTR lpsz = FX_strstr(m_pData->m_String + nStart, m_pData->m_nDataLength - nStart,
831                                lpszSub.GetCStr(), lpszSub.GetLength());
832     return (lpsz == NULL) ? -1 : (int)(lpsz - m_pData->m_String);
833 }
834 void CFX_ByteString::MakeLower()
835 {
836     if (m_pData == NULL) {
837         return;
838     }
839     CopyBeforeWrite();
840     if (GetLength() < 1) {
841         return;
842     }
843     FXSYS_strlwr(m_pData->m_String);
844 }
845 void CFX_ByteString::MakeUpper()
846 {
847     if (m_pData == NULL) {
848         return;
849     }
850     CopyBeforeWrite();
851     if (GetLength() < 1) {
852         return;
853     }
854     FXSYS_strupr(m_pData->m_String);
855 }
856 FX_STRSIZE CFX_ByteString::Remove(FX_CHAR chRemove)
857 {
858     if (m_pData == NULL) {
859         return 0;
860     }
861     CopyBeforeWrite();
862     if (GetLength() < 1) {
863         return 0;
864     }
865     FX_LPSTR pstrSource = m_pData->m_String;
866     FX_LPSTR pstrDest = m_pData->m_String;
867     FX_LPSTR pstrEnd = m_pData->m_String + m_pData->m_nDataLength;
868     while (pstrSource < pstrEnd) {
869         if (*pstrSource != chRemove) {
870             *pstrDest = *pstrSource;
871             pstrDest ++;
872         }
873         pstrSource ++;
874     }
875     *pstrDest = 0;
876     FX_STRSIZE nCount = (FX_STRSIZE)(pstrSource - pstrDest);
877     m_pData->m_nDataLength -= nCount;
878     return nCount;
879 }
880 FX_STRSIZE CFX_ByteString::Replace(FX_BSTR lpszOld, FX_BSTR lpszNew)
881 {
882     if (m_pData == NULL) {
883         return 0;
884     }
885     if (lpszOld.IsEmpty()) {
886         return 0;
887     }
888     FX_STRSIZE nSourceLen = lpszOld.GetLength();
889     FX_STRSIZE nReplacementLen = lpszNew.GetLength();
890     FX_STRSIZE nCount = 0;
891     FX_LPCSTR pStart = m_pData->m_String;
892     FX_LPSTR pEnd = m_pData->m_String + m_pData->m_nDataLength;
893     while (1) {
894         FX_LPCSTR pTarget = FX_strstr(pStart, (FX_STRSIZE)(pEnd - pStart), lpszOld.GetCStr(), nSourceLen);
895         if (pTarget == NULL) {
896             break;
897         }
898         nCount++;
899         pStart = pTarget + nSourceLen;
900     }
901     if (nCount == 0) {
902         return 0;
903     }
904     FX_STRSIZE nNewLength =  m_pData->m_nDataLength + (nReplacementLen - nSourceLen) * nCount;
905     if (nNewLength == 0) {
906         Empty();
907         return nCount;
908     }
909     StringData* pNewData = StringData::Create(nNewLength);
910     if (!pNewData) {
911         return 0;
912     }
913     pStart = m_pData->m_String;
914     FX_LPSTR pDest = pNewData->m_String;
915     for (FX_STRSIZE i = 0; i < nCount; i ++) {
916         FX_LPCSTR pTarget = FX_strstr(pStart, (FX_STRSIZE)(pEnd - pStart), lpszOld.GetCStr(), nSourceLen);
917         FXSYS_memcpy32(pDest, pStart, pTarget - pStart);
918         pDest += pTarget - pStart;
919         FXSYS_memcpy32(pDest, lpszNew.GetCStr(), lpszNew.GetLength());
920         pDest += lpszNew.GetLength();
921         pStart = pTarget + nSourceLen;
922     }
923     FXSYS_memcpy32(pDest, pStart, pEnd - pStart);
924     m_pData->Release();
925     m_pData = pNewData;
926     return nCount;
927 }
928 void CFX_ByteString::SetAt(FX_STRSIZE nIndex, FX_CHAR ch)
929 {
930     if (m_pData == NULL) {
931         return;
932     }
933     FXSYS_assert(nIndex >= 0);
934     FXSYS_assert(nIndex < m_pData->m_nDataLength);
935     CopyBeforeWrite();
936     m_pData->m_String[nIndex] = ch;
937 }
938 CFX_WideString CFX_ByteString::UTF8Decode() const
939 {
940     CFX_UTF8Decoder decoder;
941     for (FX_STRSIZE i = 0; i < GetLength(); i ++) {
942         decoder.Input((FX_BYTE)m_pData->m_String[i]);
943     }
944     return decoder.GetResult();
945 }
946 CFX_ByteString CFX_ByteString::FromUnicode(FX_LPCWSTR str, FX_STRSIZE len)
947 {
948     if (len < 0) {
949         len = FXSYS_wcslen(str);
950     }
951     CFX_ByteString bstr;
952     bstr.ConvertFrom(CFX_WideString(str, len));
953     return bstr;
954 }
955 CFX_ByteString CFX_ByteString::FromUnicode(const CFX_WideString& str)
956 {
957     return FromUnicode(str.c_str(), str.GetLength());
958 }
959 void CFX_ByteString::ConvertFrom(const CFX_WideString& str, CFX_CharMap* pCharMap)
960 {
961     if (pCharMap == NULL) {
962         pCharMap = CFX_CharMap::GetDefaultMapper();
963     }
964     *this = (*pCharMap->m_GetByteString)(pCharMap, str);
965 }
966 int CFX_ByteString::Compare(FX_BSTR str) const
967 {
968     if (m_pData == NULL) {
969         return str.IsEmpty() ? 0 : -1;
970     }
971     int this_len = m_pData->m_nDataLength;
972     int that_len = str.GetLength();
973     int min_len = this_len < that_len ? this_len : that_len;
974     for (int i = 0; i < min_len; i ++) {
975         if ((FX_BYTE)m_pData->m_String[i] < str.GetAt(i)) {
976             return -1;
977         } else if ((FX_BYTE)m_pData->m_String[i] > str.GetAt(i)) {
978             return 1;
979         }
980     }
981     if (this_len < that_len) {
982         return -1;
983     } else if (this_len > that_len) {
984         return 1;
985     }
986     return 0;
987 }
988 void CFX_ByteString::TrimRight(FX_BSTR lpszTargets)
989 {
990     if (m_pData == NULL || lpszTargets.IsEmpty()) {
991         return;
992     }
993     CopyBeforeWrite();
994     FX_STRSIZE pos = GetLength();
995     if (pos < 1) {
996         return;
997     }
998     while (pos) {
999         FX_STRSIZE i = 0;
1000         while (i < lpszTargets.GetLength() && lpszTargets[i] != m_pData->m_String[pos - 1]) {
1001             i ++;
1002         }
1003         if (i == lpszTargets.GetLength()) {
1004             break;
1005         }
1006         pos --;
1007     }
1008     if (pos < m_pData->m_nDataLength) {
1009         m_pData->m_String[pos] = 0;
1010         m_pData->m_nDataLength = pos;
1011     }
1012 }
1013 void CFX_ByteString::TrimRight(FX_CHAR chTarget)
1014 {
1015     TrimRight(CFX_ByteStringC(chTarget));
1016 }
1017 void CFX_ByteString::TrimRight()
1018 {
1019     TrimRight(FX_BSTRC("\x09\x0a\x0b\x0c\x0d\x20"));
1020 }
1021 void CFX_ByteString::TrimLeft(FX_BSTR lpszTargets)
1022 {
1023     if (m_pData == NULL) {
1024         return;
1025     }
1026     if (lpszTargets.IsEmpty()) {
1027         return;
1028     }
1029     CopyBeforeWrite();
1030     FX_STRSIZE len = GetLength();
1031     if (len < 1) {
1032         return;
1033     }
1034     FX_STRSIZE pos = 0;
1035     while (pos < len) {
1036         FX_STRSIZE i = 0;
1037         while (i < lpszTargets.GetLength() && lpszTargets[i] != m_pData->m_String[pos]) {
1038             i ++;
1039         }
1040         if (i == lpszTargets.GetLength()) {
1041             break;
1042         }
1043         pos ++;
1044     }
1045     if (pos) {
1046         FX_STRSIZE nDataLength = len - pos;
1047         FXSYS_memmove32(m_pData->m_String, m_pData->m_String + pos, (nDataLength + 1)*sizeof(FX_CHAR));
1048         m_pData->m_nDataLength = nDataLength;
1049     }
1050 }
1051 void CFX_ByteString::TrimLeft(FX_CHAR chTarget)
1052 {
1053     TrimLeft(CFX_ByteStringC(chTarget));
1054 }
1055 void CFX_ByteString::TrimLeft()
1056 {
1057     TrimLeft(FX_BSTRC("\x09\x0a\x0b\x0c\x0d\x20"));
1058 }
1059 FX_DWORD CFX_ByteString::GetID(FX_STRSIZE start_pos) const
1060 {
1061     return CFX_ByteStringC(*this).GetID(start_pos);
1062 }
1063 FX_DWORD CFX_ByteStringC::GetID(FX_STRSIZE start_pos) const
1064 {
1065     if (m_Length == 0) {
1066         return 0;
1067     }
1068     if (start_pos < 0 || start_pos >= m_Length) {
1069         return 0;
1070     }
1071     FX_DWORD strid = 0;
1072     if (start_pos + 4 > m_Length) {
1073         for (FX_STRSIZE i = 0; i < m_Length - start_pos; i ++) {
1074             strid = strid * 256 + m_Ptr[start_pos + i];
1075         }
1076         strid = strid << ((4 - m_Length + start_pos) * 8);
1077     } else {
1078         for (int i = 0; i < 4; i ++) {
1079             strid = strid * 256 + m_Ptr[start_pos + i];
1080         }
1081     }
1082     return strid;
1083 }
1084 FX_STRSIZE FX_ftoa(FX_FLOAT d, FX_LPSTR buf)
1085 {
1086     buf[0] = '0';
1087     buf[1] = '\0';
1088     if (d == 0.0f) {
1089         return 1;
1090     }
1091     FX_BOOL bNegative = FALSE;
1092     if (d < 0) {
1093         bNegative = TRUE;
1094         d = -d;
1095     }
1096     int scale = 1;
1097     int scaled = FXSYS_round(d);
1098     while (scaled < 100000) {
1099         if (scale == 1000000) {
1100             break;
1101         }
1102         scale *= 10;
1103         scaled = FXSYS_round(d * scale);
1104     }
1105     if (scaled == 0) {
1106         return 1;
1107     }
1108     char buf2[32];
1109     int buf_size = 0;
1110     if (bNegative) {
1111         buf[buf_size++] = '-';
1112     }
1113     int i = scaled / scale;
1114     FXSYS_itoa(i, buf2, 10);
1115     FX_STRSIZE len = FXSYS_strlen(buf2);
1116     FXSYS_memcpy32(buf + buf_size, buf2, len);
1117     buf_size += len;
1118     int fraction = scaled % scale;
1119     if (fraction == 0) {
1120         return buf_size;
1121     }
1122     buf[buf_size++] = '.';
1123     scale /= 10;
1124     while (fraction) {
1125         buf[buf_size++] = '0' + fraction / scale;
1126         fraction %= scale;
1127         scale /= 10;
1128     }
1129     return buf_size;
1130 }
1131 CFX_ByteString CFX_ByteString::FormatFloat(FX_FLOAT d, int precision)
1132 {
1133     FX_CHAR buf[32];
1134     FX_STRSIZE len = FX_ftoa(d, buf);
1135     return CFX_ByteString(buf, len);
1136 }