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