Convert all line endings to LF.
[pdfium.git] / core / src / fxcrt / fx_basic_bstring.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4  
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "../../include/fxcrt/fx_basic.h"
8 static int _Buffer_itoa(char* buf, int i, FX_DWORD flags)
9 {
10     if (i == 0) {
11         buf[0] = '0';
12         return 1;
13     }
14     char buf1[32];
15     int buf_pos = 31;
16     FX_DWORD u = i;
17     if ((flags & FXFORMAT_SIGNED) && i < 0) {
18         u = -i;
19     }
20     int base = 10;
21     FX_LPCSTR string = "0123456789abcdef";
22     if (flags & FXFORMAT_HEX) {
23         base = 16;
24         if (flags & FXFORMAT_CAPITAL) {
25             string = "0123456789ABCDEF";
26         }
27     }
28     while (u != 0) {
29         buf1[buf_pos--] = string[u % base];
30         u = u / base;
31     }
32     if ((flags & FXFORMAT_SIGNED) && i < 0) {
33         buf1[buf_pos--] = '-';
34     }
35     int len = 31 - buf_pos;
36     for (int ii = 0; ii < len; ii ++) {
37         buf[ii] = buf1[ii + buf_pos + 1];
38     }
39     return len;
40 }
41 CFX_ByteString CFX_ByteString::FormatInteger(int i, FX_DWORD flags)
42 {
43     char buf[32];
44     return CFX_ByteStringC(buf, _Buffer_itoa(buf, i, flags));
45 }
46 static CFX_StringData* FX_AllocString(int nLen)
47 {
48     if (nLen == 0) {
49         return NULL;
50     }
51     CFX_StringData* pData = (CFX_StringData*)FX_Alloc(FX_BYTE, sizeof(long) * 3 + (nLen + 1) * sizeof(char));
52     if (!pData) {
53         return NULL;
54     }
55     pData->m_nAllocLength = nLen;
56     pData->m_nDataLength = nLen;
57     pData->m_nRefs = 1;
58     pData->m_String[nLen] = 0;
59     return pData;
60 }
61 static void FX_ReleaseString(CFX_StringData* pData)
62 {
63     if (pData == NULL) {
64         return;
65     }
66     pData->m_nRefs --;
67     if (pData->m_nRefs <= 0) {
68         FX_Free(pData);
69     }
70 }
71 CFX_ByteString::~CFX_ByteString()
72 {
73     if (m_pData == NULL) {
74         return;
75     }
76     m_pData->m_nRefs --;
77     if (m_pData->m_nRefs < 1) {
78         FX_Free(m_pData);
79     }
80 }
81 CFX_ByteString::CFX_ByteString(FX_LPCSTR lpsz, FX_STRSIZE nLen)
82 {
83     if (nLen < 0) {
84         nLen = lpsz ? (FX_STRSIZE)FXSYS_strlen(lpsz) : 0;
85     }
86     if (nLen) {
87         m_pData = FX_AllocString(nLen);
88         if (m_pData) {
89             FXSYS_memcpy32(m_pData->m_String, lpsz, nLen * sizeof(char));
90         }
91     } else {
92         m_pData = NULL;
93     }
94 }
95 CFX_ByteString::CFX_ByteString(FX_LPCBYTE lpsz, FX_STRSIZE nLen)
96 {
97     if (nLen > 0) {
98         m_pData = FX_AllocString(nLen);
99         if (m_pData) {
100             FXSYS_memcpy32(m_pData->m_String, lpsz, nLen * sizeof(char));
101         }
102     } else {
103         m_pData = NULL;
104     }
105 }
106 CFX_ByteString::CFX_ByteString(char ch)
107 {
108     m_pData = FX_AllocString(1);
109     if (m_pData) {
110         m_pData->m_String[0] = ch;
111     }
112 }
113 CFX_ByteString::CFX_ByteString(const CFX_ByteString& stringSrc)
114 {
115     if (stringSrc.m_pData == NULL) {
116         m_pData = NULL;
117         return;
118     }
119     if (stringSrc.m_pData->m_nRefs >= 0) {
120         m_pData = stringSrc.m_pData;
121         m_pData->m_nRefs ++;
122     } else {
123         m_pData = NULL;
124         *this = stringSrc;
125     }
126 }
127 CFX_ByteString::CFX_ByteString(FX_BSTR stringSrc)
128 {
129     if (stringSrc.IsEmpty()) {
130         m_pData = NULL;
131         return;
132     } else {
133         m_pData = NULL;
134         *this = stringSrc;
135     }
136 }
137 CFX_ByteString::CFX_ByteString(FX_BSTR str1, FX_BSTR str2)
138 {
139     m_pData = NULL;
140     int nNewLen = str1.GetLength() + str2.GetLength();
141     if (nNewLen == 0) {
142         return;
143     }
144     m_pData = FX_AllocString(nNewLen);
145     if (m_pData) {
146         FXSYS_memcpy32(m_pData->m_String, str1.GetCStr(), str1.GetLength());
147         FXSYS_memcpy32(m_pData->m_String + str1.GetLength(), str2.GetCStr(), str2.GetLength());
148     }
149 }
150 const CFX_ByteString& CFX_ByteString::operator=(FX_LPCSTR lpsz)
151 {
152     if (lpsz == NULL || lpsz[0] == 0) {
153         Empty();
154     } else {
155         AssignCopy((FX_STRSIZE)FXSYS_strlen(lpsz), lpsz);
156     }
157     return *this;
158 }
159 const CFX_ByteString& CFX_ByteString::operator=(FX_BSTR str)
160 {
161     if (str.IsEmpty()) {
162         Empty();
163     } else {
164         AssignCopy(str.GetLength(), str.GetCStr());
165     }
166     return *this;
167 }
168 const CFX_ByteString& CFX_ByteString::operator=(const CFX_ByteString& stringSrc)
169 {
170     if (m_pData == stringSrc.m_pData) {
171         return *this;
172     }
173     if (stringSrc.IsEmpty()) {
174         Empty();
175     } else if ((m_pData && m_pData->m_nRefs < 0) ||
176                (stringSrc.m_pData && stringSrc.m_pData->m_nRefs < 0)) {
177         AssignCopy(stringSrc.m_pData->m_nDataLength, stringSrc.m_pData->m_String);
178     } else {
179         Empty();
180         m_pData = stringSrc.m_pData;
181         if (m_pData) {
182             m_pData->m_nRefs ++;
183         }
184     }
185     return *this;
186 }
187 const CFX_ByteString& CFX_ByteString::operator=(const CFX_BinaryBuf& buf)
188 {
189     Load(buf.GetBuffer(), buf.GetSize());
190     return *this;
191 }
192 void CFX_ByteString::Load(FX_LPCBYTE buf, FX_STRSIZE len)
193 {
194     Empty();
195     if (len) {
196         m_pData = FX_AllocString(len);
197         if (m_pData) {
198             FXSYS_memcpy32(m_pData->m_String, buf, len * sizeof(char));
199         }
200     } else {
201         m_pData = NULL;
202     }
203 }
204 const CFX_ByteString& CFX_ByteString::operator+=(FX_LPCSTR lpsz)
205 {
206     if (lpsz) {
207         ConcatInPlace((FX_STRSIZE)FXSYS_strlen(lpsz), lpsz);
208     }
209     return *this;
210 }
211 const CFX_ByteString& CFX_ByteString::operator+=(char ch)
212 {
213     ConcatInPlace(1, &ch);
214     return *this;
215 }
216 const CFX_ByteString& CFX_ByteString::operator+=(const CFX_ByteString& string)
217 {
218     if (string.m_pData == NULL) {
219         return *this;
220     }
221     ConcatInPlace(string.m_pData->m_nDataLength, string.m_pData->m_String);
222     return *this;
223 }
224 const CFX_ByteString& CFX_ByteString::operator+=(FX_BSTR string)
225 {
226     if (string.IsEmpty()) {
227         return *this;
228     }
229     ConcatInPlace(string.GetLength(), string.GetCStr());
230     return *this;
231 }
232 bool CFX_ByteString::Equal(FX_BSTR str) const
233 {
234     if (m_pData == NULL) {
235         return str.IsEmpty();
236     }
237     return m_pData->m_nDataLength == str.GetLength() &&
238            FXSYS_memcmp32(m_pData->m_String, str.GetCStr(), str.GetLength()) == 0;
239 }
240 bool CFX_ByteString::operator ==(const CFX_ByteString& s2) const
241 {
242     if (m_pData == NULL) {
243         return s2.IsEmpty();
244     }
245     if (s2.m_pData == NULL) {
246         return false;
247     }
248     return m_pData->m_nDataLength == s2.m_pData->m_nDataLength &&
249            FXSYS_memcmp32(m_pData->m_String, s2.m_pData->m_String, m_pData->m_nDataLength) == 0;
250 }
251 void CFX_ByteString::Empty()
252 {
253     if (m_pData == NULL) {
254         return;
255     }
256     if (m_pData->m_nRefs > 1) {
257         m_pData->m_nRefs --;
258     } else {
259         FX_Free(m_pData);
260     }
261     m_pData = NULL;
262 }
263 bool CFX_ByteString::EqualNoCase(FX_BSTR str) const
264 {
265     if (m_pData == NULL) {
266         return str.IsEmpty();
267     }
268     FX_STRSIZE len = str.GetLength();
269     if (m_pData->m_nDataLength != len) {
270         return false;
271     }
272     FX_LPCBYTE pThis = (FX_LPCBYTE)m_pData->m_String;
273     FX_LPCBYTE pThat = (FX_LPCBYTE)str;
274     for (FX_STRSIZE i = 0; i < len; i ++) {
275         if ((*pThis) != (*pThat)) {
276             FX_BYTE bThis = *pThis;
277             if (bThis >= 'A' && bThis <= 'Z') {
278                 bThis += 'a' - 'A';
279             }
280             FX_BYTE bThat = *pThat;
281             if (bThat >= 'A' && bThat <= 'Z') {
282                 bThat += 'a' - 'A';
283             }
284             if (bThis != bThat) {
285                 return false;
286             }
287         }
288         pThis ++;
289         pThat ++;
290     }
291     return true;
292 }
293 void CFX_ByteString::AssignCopy(FX_STRSIZE nSrcLen, FX_LPCSTR lpszSrcData)
294 {
295     AllocBeforeWrite(nSrcLen);
296     FXSYS_memcpy32(m_pData->m_String, lpszSrcData, nSrcLen * sizeof(char));
297     m_pData->m_nDataLength = nSrcLen;
298     m_pData->m_String[nSrcLen] = 0;
299 }
300 void CFX_ByteString::CopyBeforeWrite()
301 {
302     if (m_pData == NULL || m_pData->m_nRefs <= 1) {
303         return;
304     }
305     CFX_StringData* pData = m_pData;
306     m_pData->m_nRefs --;
307     FX_STRSIZE nDataLength = pData->m_nDataLength;
308     m_pData = FX_AllocString(nDataLength);
309     if (m_pData != NULL) {
310         FXSYS_memcpy32(m_pData->m_String, pData->m_String, (nDataLength + 1) * sizeof(char));
311     }
312 }
313 void CFX_ByteString::AllocBeforeWrite(FX_STRSIZE nLen)
314 {
315     if (m_pData && m_pData->m_nRefs <= 1 && m_pData->m_nAllocLength >= nLen) {
316         return;
317     }
318     Empty();
319     m_pData = FX_AllocString(nLen);
320 }
321 void CFX_ByteString::ReleaseBuffer(FX_STRSIZE nNewLength)
322 {
323     if (m_pData == NULL) {
324         return;
325     }
326     CopyBeforeWrite();
327     if (nNewLength == -1) {
328         nNewLength = (FX_STRSIZE)FXSYS_strlen((FX_LPCSTR)m_pData->m_String);
329     }
330     if (nNewLength == 0) {
331         Empty();
332         return;
333     }
334     FXSYS_assert(nNewLength <= m_pData->m_nAllocLength);
335     m_pData->m_nDataLength = nNewLength;
336     m_pData->m_String[nNewLength] = 0;
337 }
338 FX_LPSTR CFX_ByteString::LockBuffer()
339 {
340     if (m_pData == NULL) {
341         return NULL;
342     }
343     FX_LPSTR lpsz = GetBuffer(0);
344     m_pData->m_nRefs = -1;
345     return lpsz;
346 }
347 void CFX_ByteString::Reserve(FX_STRSIZE len)
348 {
349     GetBuffer(len);
350     ReleaseBuffer(GetLength());
351 }
352 FX_LPSTR CFX_ByteString::GetBuffer(FX_STRSIZE nMinBufLength)
353 {
354     if (m_pData == NULL && nMinBufLength == 0) {
355         return NULL;
356     }
357     if (m_pData && m_pData->m_nRefs <= 1 && m_pData->m_nAllocLength >= nMinBufLength) {
358         return m_pData->m_String;
359     }
360     if (m_pData == NULL) {
361         m_pData = FX_AllocString(nMinBufLength);
362         if (!m_pData) {
363             return NULL;
364         }
365         m_pData->m_nDataLength = 0;
366         m_pData->m_String[0] = 0;
367         return m_pData->m_String;
368     }
369     CFX_StringData* pOldData = m_pData;
370     FX_STRSIZE nOldLen = pOldData->m_nDataLength;
371     if (nMinBufLength < nOldLen) {
372         nMinBufLength = nOldLen;
373     }
374     m_pData = FX_AllocString(nMinBufLength);
375     if (!m_pData) {
376         return NULL;
377     }
378     FXSYS_memcpy32(m_pData->m_String, pOldData->m_String, (nOldLen + 1)*sizeof(char));
379     m_pData->m_nDataLength = nOldLen;
380     pOldData->m_nRefs --;
381     if (pOldData->m_nRefs <= 0) {
382         FX_Free(pOldData);
383     }
384     return m_pData->m_String;
385 }
386 FX_STRSIZE CFX_ByteString::Delete(FX_STRSIZE nIndex, FX_STRSIZE nCount)
387 {
388     if (m_pData == NULL) {
389         return 0;
390     }
391     if (nIndex < 0) {
392         nIndex = 0;
393     }
394     FX_STRSIZE nOldLength = m_pData->m_nDataLength;
395     if (nCount > 0 && nIndex < nOldLength) {
396         FX_STRSIZE mLength = nIndex + nCount;
397         if (mLength >= nOldLength) {
398             m_pData->m_nDataLength = nIndex;
399             return m_pData->m_nDataLength;
400         }
401         CopyBeforeWrite();
402         int nBytesToCopy = nOldLength - mLength + 1;
403         FXSYS_memmove32(m_pData->m_String + nIndex,
404                         m_pData->m_String + mLength, nBytesToCopy * sizeof(char));
405         m_pData->m_nDataLength = nOldLength - nCount;
406     }
407     return m_pData->m_nDataLength;
408 }
409 void CFX_ByteString::ConcatInPlace(FX_STRSIZE nSrcLen, FX_LPCSTR lpszSrcData)
410 {
411     if (nSrcLen == 0 || lpszSrcData == NULL) {
412         return;
413     }
414     if (m_pData == NULL) {
415         m_pData = FX_AllocString(nSrcLen);
416         if (!m_pData) {
417             return;
418         }
419         FXSYS_memcpy32(m_pData->m_String, lpszSrcData, nSrcLen * sizeof(char));
420         return;
421     }
422     if (m_pData->m_nRefs > 1 || m_pData->m_nDataLength + nSrcLen > m_pData->m_nAllocLength) {
423         CFX_StringData* pOldData = m_pData;
424         ConcatCopy(m_pData->m_nDataLength, m_pData->m_String, nSrcLen, lpszSrcData);
425         FX_ReleaseString(pOldData);
426     } else {
427         FXSYS_memcpy32(m_pData->m_String + m_pData->m_nDataLength, lpszSrcData, nSrcLen * sizeof(char));
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     m_pData = FX_AllocString(nNewLen);
440     if (m_pData) {
441         FXSYS_memcpy32(m_pData->m_String, lpszSrc1Data, nSrc1Len * sizeof(char));
442         FXSYS_memcpy32(m_pData->m_String + nSrc1Len, lpszSrc2Data, nSrc2Len * sizeof(char));
443     }
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, 0);
471     return dest;
472 }
473 void CFX_ByteString::AllocCopy(CFX_ByteString& dest, FX_STRSIZE nCopyLen, FX_STRSIZE nCopyIndex,
474                                FX_STRSIZE nExtraLen) const
475 {
476     FX_STRSIZE nNewLen = nCopyLen + nExtraLen;
477     if (nNewLen == 0) {
478         return;
479     }
480     ASSERT(dest.m_pData == NULL);
481     dest.m_pData = FX_AllocString(nNewLen);
482     if (dest.m_pData) {
483         FXSYS_memcpy32(dest.m_pData->m_String, m_pData->m_String + nCopyIndex, nCopyLen * sizeof(char));
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 += (FX_STRSIZE)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 = (FX_STRSIZE)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 = (FX_STRSIZE)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 = (FX_STRSIZE)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 = (FX_STRSIZE)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, FX_INT64);
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                         double f;
674                         char pszTemp[256];
675                         f = va_arg(argList, double);
676                         FXSYS_sprintf(pszTemp, "%*.*f", nWidth, nPrecision + 6, f );
677                         nItemLen = (FX_STRSIZE)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     GetBuffer(nMaxLen);
695     if (m_pData) {
696         FXSYS_vsprintf(m_pData->m_String, lpszFormat, argListSave);
697         ReleaseBuffer();
698     }
699     va_end(argListSave);
700 }
701 void CFX_ByteString::Format(FX_LPCSTR lpszFormat, ...)
702 {
703     va_list argList;
704     va_start(argList, lpszFormat);
705     FormatV(lpszFormat, argList);
706     va_end(argList);
707 }
708 FX_STRSIZE CFX_ByteString::Insert(FX_STRSIZE nIndex, FX_CHAR ch)
709 {
710     CopyBeforeWrite();
711     if (nIndex < 0) {
712         nIndex = 0;
713     }
714     FX_STRSIZE nNewLength = m_pData ? m_pData->m_nDataLength : 0;
715     if (nIndex > nNewLength) {
716         nIndex = nNewLength;
717     }
718     nNewLength++;
719     if (m_pData == NULL || m_pData->m_nAllocLength < nNewLength) {
720         CFX_StringData* pOldData = m_pData;
721         FX_LPCSTR pstr = m_pData->m_String;
722         m_pData = FX_AllocString(nNewLength);
723         if (!m_pData) {
724             return 0;
725         }
726         if(pOldData != NULL) {
727             FXSYS_memmove32(m_pData->m_String, pstr, (pOldData->m_nDataLength + 1)*sizeof(char));
728             FX_ReleaseString(pOldData);
729         } else {
730             m_pData->m_String[0] = 0;
731         }
732     }
733     FXSYS_memmove32(m_pData->m_String + nIndex + 1,
734                     m_pData->m_String + nIndex, (nNewLength - nIndex)*sizeof(char));
735     m_pData->m_String[nIndex] = ch;
736     m_pData->m_nDataLength = nNewLength;
737     return nNewLength;
738 }
739 CFX_ByteString CFX_ByteString::Right(FX_STRSIZE nCount) const
740 {
741     if (m_pData == NULL) {
742         return CFX_ByteString();
743     }
744     if (nCount < 0) {
745         nCount = 0;
746     }
747     if (nCount >= m_pData->m_nDataLength) {
748         return *this;
749     }
750     CFX_ByteString dest;
751     AllocCopy(dest, nCount, m_pData->m_nDataLength - nCount, 0);
752     return dest;
753 }
754 CFX_ByteString CFX_ByteString::Left(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, 0, 0);
767     return dest;
768 }
769 FX_STRSIZE CFX_ByteString::Find(FX_CHAR ch, FX_STRSIZE nStart) const
770 {
771     if (m_pData == NULL) {
772         return -1;
773     }
774     FX_STRSIZE nLength = m_pData->m_nDataLength;
775     if (nStart >= nLength) {
776         return -1;
777     }
778     FX_LPCSTR lpsz = FXSYS_strchr(m_pData->m_String + nStart, ch);
779     return (lpsz == NULL) ? -1 : (int)(lpsz - m_pData->m_String);
780 }
781 FX_STRSIZE CFX_ByteString::ReverseFind(FX_CHAR ch) const
782 {
783     if (m_pData == NULL) {
784         return -1;
785     }
786     FX_STRSIZE nLength = m_pData->m_nDataLength;
787     while (nLength) {
788         if (m_pData->m_String[nLength - 1] == ch) {
789             return nLength - 1;
790         }
791         nLength --;
792     }
793     return -1;
794 }
795 FX_LPCSTR FX_strstr(FX_LPCSTR str1, int len1, FX_LPCSTR str2, int len2)
796 {
797     if (len2 > len1 || len2 == 0) {
798         return NULL;
799     }
800     FX_LPCSTR end_ptr = str1 + len1 - len2;
801     while (str1 <= end_ptr) {
802         int i = 0;
803         while (1) {
804             if (str1[i] != str2[i]) {
805                 break;
806             }
807             i ++;
808             if (i == len2) {
809                 return str1;
810             }
811         }
812         str1 ++;
813     }
814     return NULL;
815 }
816 FX_STRSIZE CFX_ByteString::Find(FX_BSTR lpszSub, FX_STRSIZE nStart) const
817 {
818     if (m_pData == NULL) {
819         return -1;
820     }
821     FX_STRSIZE nLength = m_pData->m_nDataLength;
822     if (nStart > nLength) {
823         return -1;
824     }
825     FX_LPCSTR lpsz = FX_strstr(m_pData->m_String + nStart, m_pData->m_nDataLength - nStart,
826                                lpszSub.GetCStr(), lpszSub.GetLength());
827     return (lpsz == NULL) ? -1 : (int)(lpsz - m_pData->m_String);
828 }
829 void CFX_ByteString::MakeLower()
830 {
831     if (m_pData == NULL) {
832         return;
833     }
834     CopyBeforeWrite();
835     if (GetLength() < 1) {
836         return;
837     }
838     FXSYS_strlwr(m_pData->m_String);
839 }
840 void CFX_ByteString::MakeUpper()
841 {
842     if (m_pData == NULL) {
843         return;
844     }
845     CopyBeforeWrite();
846     if (GetLength() < 1) {
847         return;
848     }
849     FXSYS_strupr(m_pData->m_String);
850 }
851 FX_STRSIZE CFX_ByteString::Remove(FX_CHAR chRemove)
852 {
853     if (m_pData == NULL) {
854         return 0;
855     }
856     CopyBeforeWrite();
857     if (GetLength() < 1) {
858         return 0;
859     }
860     FX_LPSTR pstrSource = m_pData->m_String;
861     FX_LPSTR pstrDest = m_pData->m_String;
862     FX_LPSTR pstrEnd = m_pData->m_String + m_pData->m_nDataLength;
863     while (pstrSource < pstrEnd) {
864         if (*pstrSource != chRemove) {
865             *pstrDest = *pstrSource;
866             pstrDest ++;
867         }
868         pstrSource ++;
869     }
870     *pstrDest = 0;
871     FX_STRSIZE nCount = (FX_STRSIZE)(pstrSource - pstrDest);
872     m_pData->m_nDataLength -= nCount;
873     return nCount;
874 }
875 FX_STRSIZE CFX_ByteString::Replace(FX_BSTR lpszOld, FX_BSTR lpszNew)
876 {
877     if (m_pData == NULL) {
878         return 0;
879     }
880     if (lpszOld.IsEmpty()) {
881         return 0;
882     }
883     FX_STRSIZE nSourceLen = lpszOld.GetLength();
884     FX_STRSIZE nReplacementLen = lpszNew.GetLength();
885     FX_STRSIZE nCount = 0;
886     FX_LPCSTR pStart = m_pData->m_String;
887     FX_LPSTR pEnd = m_pData->m_String + m_pData->m_nDataLength;
888     while (1) {
889         FX_LPCSTR pTarget = FX_strstr(pStart, (FX_STRSIZE)(pEnd - pStart), lpszOld.GetCStr(), nSourceLen);
890         if (pTarget == NULL) {
891             break;
892         }
893         nCount++;
894         pStart = pTarget + nSourceLen;
895     }
896     if (nCount == 0) {
897         return 0;
898     }
899     FX_STRSIZE nNewLength =  m_pData->m_nDataLength + (nReplacementLen - nSourceLen) * nCount;
900     if (nNewLength == 0) {
901         Empty();
902         return nCount;
903     }
904     CFX_StringData* pNewData = FX_AllocString(nNewLength);
905     if (!pNewData) {
906         return 0;
907     }
908     pStart = m_pData->m_String;
909     FX_LPSTR pDest = pNewData->m_String;
910     for (FX_STRSIZE i = 0; i < nCount; i ++) {
911         FX_LPCSTR pTarget = FX_strstr(pStart, (FX_STRSIZE)(pEnd - pStart), lpszOld.GetCStr(), nSourceLen);
912         FXSYS_memcpy32(pDest, pStart, pTarget - pStart);
913         pDest += pTarget - pStart;
914         FXSYS_memcpy32(pDest, lpszNew.GetCStr(), lpszNew.GetLength());
915         pDest += lpszNew.GetLength();
916         pStart = pTarget + nSourceLen;
917     }
918     FXSYS_memcpy32(pDest, pStart, pEnd - pStart);
919     FX_ReleaseString(m_pData);
920     m_pData = pNewData;
921     return nCount;
922 }
923 void CFX_ByteString::SetAt(FX_STRSIZE nIndex, FX_CHAR ch)
924 {
925     if (m_pData == NULL) {
926         return;
927     }
928     FXSYS_assert(nIndex >= 0);
929     FXSYS_assert(nIndex < m_pData->m_nDataLength);
930     CopyBeforeWrite();
931     m_pData->m_String[nIndex] = ch;
932 }
933 CFX_ByteString CFX_ByteString::LoadFromFile(FX_BSTR filename)
934 {
935     FXSYS_FILE* file = FXSYS_fopen(CFX_ByteString(filename), "rb");
936     if (file == NULL) {
937         return CFX_ByteString();
938     }
939     FXSYS_fseek(file, 0, FXSYS_SEEK_END);
940     int len = FXSYS_ftell(file);
941     FXSYS_fseek(file, 0, FXSYS_SEEK_SET);
942     CFX_ByteString str;
943     FX_LPSTR buf = str.GetBuffer(len);
944     size_t readCnt = FXSYS_fread(buf, 1, len, file);
945     str.ReleaseBuffer(len);
946     FXSYS_fclose(file);
947     return str;
948 }
949 CFX_WideString CFX_ByteString::UTF8Decode() const
950 {
951     CFX_UTF8Decoder decoder;
952     for (FX_STRSIZE i = 0; i < GetLength(); i ++) {
953         decoder.Input((FX_BYTE)m_pData->m_String[i]);
954     }
955     return decoder.GetResult();
956 }
957 CFX_ByteString CFX_ByteString::FromUnicode(FX_LPCWSTR str, FX_STRSIZE len)
958 {
959     if (len < 0) {
960         len = (FX_STRSIZE)FXSYS_wcslen(str);
961     }
962     CFX_ByteString bstr;
963     bstr.ConvertFrom(CFX_WideString(str, len));
964     return bstr;
965 }
966 CFX_ByteString CFX_ByteString::FromUnicode(const CFX_WideString& str)
967 {
968     return FromUnicode((FX_LPCWSTR)str, str.GetLength());
969 }
970 void CFX_ByteString::ConvertFrom(const CFX_WideString& str, CFX_CharMap* pCharMap)
971 {
972     if (pCharMap == NULL) {
973         pCharMap = CFX_CharMap::GetDefaultMapper();
974     }
975     *this = (*pCharMap->m_GetByteString)(pCharMap, str);
976 }
977 int CFX_ByteString::Compare(FX_BSTR str) const
978 {
979     if (m_pData == NULL) {
980         return str.IsEmpty() ? 0 : -1;
981     }
982     int this_len = m_pData->m_nDataLength;
983     int that_len = str.GetLength();
984     int min_len = this_len < that_len ? this_len : that_len;
985     for (int i = 0; i < min_len; i ++) {
986         if ((FX_BYTE)m_pData->m_String[i] < str.GetAt(i)) {
987             return -1;
988         } else if ((FX_BYTE)m_pData->m_String[i] > str.GetAt(i)) {
989             return 1;
990         }
991     }
992     if (this_len < that_len) {
993         return -1;
994     } else if (this_len > that_len) {
995         return 1;
996     }
997     return 0;
998 }
999 void CFX_ByteString::TrimRight(FX_BSTR lpszTargets)
1000 {
1001     if (m_pData == NULL || lpszTargets.IsEmpty()) {
1002         return;
1003     }
1004     CopyBeforeWrite();
1005     FX_STRSIZE pos = GetLength();
1006     if (pos < 1) {
1007         return;
1008     }
1009     while (pos) {
1010         FX_STRSIZE i = 0;
1011         while (i < lpszTargets.GetLength() && lpszTargets[i] != m_pData->m_String[pos - 1]) {
1012             i ++;
1013         }
1014         if (i == lpszTargets.GetLength()) {
1015             break;
1016         }
1017         pos --;
1018     }
1019     if (pos < m_pData->m_nDataLength) {
1020         m_pData->m_String[pos] = 0;
1021         m_pData->m_nDataLength = pos;
1022     }
1023 }
1024 void CFX_ByteString::TrimRight(FX_CHAR chTarget)
1025 {
1026     TrimRight(CFX_ByteStringC(chTarget));
1027 }
1028 void CFX_ByteString::TrimRight()
1029 {
1030     TrimRight(FX_BSTRC("\x09\x0a\x0b\x0c\x0d\x20"));
1031 }
1032 void CFX_ByteString::TrimLeft(FX_BSTR lpszTargets)
1033 {
1034     if (m_pData == NULL) {
1035         return;
1036     }
1037     if (lpszTargets.IsEmpty()) {
1038         return;
1039     }
1040     CopyBeforeWrite();
1041     FX_STRSIZE len = GetLength();
1042     if (len < 1) {
1043         return;
1044     }
1045     FX_STRSIZE pos = 0;
1046     while (pos < len) {
1047         FX_STRSIZE i = 0;
1048         while (i < lpszTargets.GetLength() && lpszTargets[i] != m_pData->m_String[pos]) {
1049             i ++;
1050         }
1051         if (i == lpszTargets.GetLength()) {
1052             break;
1053         }
1054         pos ++;
1055     }
1056     if (pos) {
1057         FX_STRSIZE nDataLength = len - pos;
1058         FXSYS_memmove32(m_pData->m_String, m_pData->m_String + pos, (nDataLength + 1)*sizeof(FX_CHAR));
1059         m_pData->m_nDataLength = nDataLength;
1060     }
1061 }
1062 void CFX_ByteString::TrimLeft(FX_CHAR chTarget)
1063 {
1064     TrimLeft(CFX_ByteStringC(chTarget));
1065 }
1066 void CFX_ByteString::TrimLeft()
1067 {
1068     TrimLeft(FX_BSTRC("\x09\x0a\x0b\x0c\x0d\x20"));
1069 }
1070 FX_DWORD CFX_ByteString::GetID(FX_STRSIZE start_pos) const
1071 {
1072     return CFX_ByteStringC(*this).GetID(start_pos);
1073 }
1074 FX_DWORD CFX_ByteStringC::GetID(FX_STRSIZE start_pos) const
1075 {
1076     if (m_Length == 0) {
1077         return 0;
1078     }
1079     if (start_pos >= m_Length) {
1080         return 0;
1081     }
1082     FX_DWORD strid = 0;
1083     if (start_pos + 4 > m_Length) {
1084         for (FX_STRSIZE i = 0; i < m_Length - start_pos; i ++) {
1085             strid = strid * 256 + m_Ptr[start_pos + i];
1086         }
1087         strid = strid << ((4 - m_Length + start_pos) * 8);
1088     } else {
1089         for (int i = 0; i < 4; i ++) {
1090             strid = strid * 256 + m_Ptr[start_pos + i];
1091         }
1092     }
1093     return strid;
1094 }
1095 FX_STRSIZE FX_ftoa(FX_FLOAT d, FX_LPSTR buf)
1096 {
1097     buf[0] = '0';
1098     buf[1] = '\0';
1099     if (d == 0.0f) {
1100         return 1;
1101     }
1102     FX_BOOL bNegative = FALSE;
1103     if (d < 0) {
1104         bNegative = TRUE;
1105         d = -d;
1106     }
1107     int scale = 1;
1108     int scaled = FXSYS_round(d);
1109     while (scaled < 100000) {
1110         if (scale == 1000000) {
1111             break;
1112         }
1113         scale *= 10;
1114         scaled = FXSYS_round(d * scale);
1115     }
1116     if (scaled == 0) {
1117         return 1;
1118     }
1119     char buf2[32];
1120     int buf_size = 0;
1121     if (bNegative) {
1122         buf[buf_size++] = '-';
1123     }
1124     int i = scaled / scale;
1125     FXSYS_itoa(i, buf2, 10);
1126     FX_STRSIZE len = (FX_STRSIZE)FXSYS_strlen(buf2);
1127     FXSYS_memcpy32(buf + buf_size, buf2, len);
1128     buf_size += len;
1129     int fraction = scaled % scale;
1130     if (fraction == 0) {
1131         return buf_size;
1132     }
1133     buf[buf_size++] = '.';
1134     scale /= 10;
1135     while (fraction) {
1136         buf[buf_size++] = '0' + fraction / scale;
1137         fraction %= scale;
1138         scale /= 10;
1139     }
1140     return buf_size;
1141 }
1142 CFX_ByteString CFX_ByteString::FormatFloat(FX_FLOAT d, int precision)
1143 {
1144     FX_CHAR buf[32];
1145     FX_STRSIZE len = FX_ftoa(d, buf);
1146     return CFX_ByteString(buf, len);
1147 }
1148 void CFX_StringBufBase::Copy(FX_BSTR str)
1149 {
1150     m_Size = str.GetLength();
1151     if (m_Size > m_Limit) {
1152         m_Size = m_Limit;
1153     }
1154     FX_CHAR* pBuffer = (FX_CHAR*)(this + 1);
1155     FXSYS_memcpy32(pBuffer, str.GetPtr(), m_Size);
1156 }
1157 void CFX_StringBufBase::Append(FX_BSTR str)
1158 {
1159     int len = str.GetLength();
1160     if (len > m_Limit - m_Size) {
1161         len = m_Limit - m_Size;
1162     }
1163     FX_CHAR* pBuffer = (FX_CHAR*)(this + 1);
1164     FXSYS_memcpy32(pBuffer + m_Size, str.GetPtr(), len);
1165     m_Size += len;
1166 }
1167 void CFX_StringBufBase::Append(int i, FX_DWORD flags)
1168 {
1169     char buf[32];
1170     int len = _Buffer_itoa(buf, i, flags);
1171     Append(CFX_ByteStringC(buf, len));
1172 }
1173 void CFX_ByteStringL::Empty(IFX_Allocator* pAllocator)
1174 {
1175     if (m_Ptr) {
1176         FX_Allocator_Free(pAllocator, (FX_LPVOID)m_Ptr);
1177     }
1178     m_Ptr = NULL, m_Length = 0;
1179 }
1180 FX_LPSTR CFX_ByteStringL::AllocBuffer(FX_STRSIZE length, IFX_Allocator* pAllocator)
1181 {
1182     Empty(pAllocator);
1183     FX_LPSTR str = FX_Allocator_Alloc(pAllocator, FX_CHAR, length + 1);
1184     if (!str) {
1185         return NULL;
1186     }
1187     *(FX_LPSTR*)(&m_Ptr) = str;
1188     m_Length = length;
1189     return str;
1190 }
1191 void CFX_ByteStringL::Set(FX_BSTR src, IFX_Allocator* pAllocator)
1192 {
1193     Empty(pAllocator);
1194     if (src.GetCStr() != NULL && src.GetLength() > 0) {
1195         FX_LPSTR str = FX_Allocator_Alloc(pAllocator, FX_CHAR, src.GetLength() + 1);
1196         if (!str) {
1197             return;
1198         }
1199         FXSYS_memcpy32(str, src, src.GetLength());
1200         str[src.GetLength()] = '\0';
1201         *(FX_LPSTR*)(&m_Ptr) = str;
1202         m_Length = src.GetLength();
1203     }
1204 }