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