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