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