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>
8 
9 #include <algorithm>
10 #include <cctype>
11 
12 #include "core/fxcrt/cfx_string_pool_template.h"
13 #include "core/fxcrt/fx_basic.h"
14 #include "third_party/base/numerics/safe_math.h"
15 
16 template class CFX_StringDataTemplate<FX_CHAR>;
17 template class CFX_StringCTemplate<FX_CHAR>;
18 template class CFX_StringPoolTemplate<CFX_ByteString>;
19 template struct std::hash<CFX_ByteString>;
20 
21 namespace {
22 
Buffer_itoa(char * buf,int i,uint32_t flags)23 int Buffer_itoa(char* buf, int i, uint32_t flags) {
24   if (i == 0) {
25     buf[0] = '0';
26     return 1;
27   }
28   char buf1[32];
29   int buf_pos = 31;
30   uint32_t u = i;
31   if ((flags & FXFORMAT_SIGNED) && i < 0) {
32     u = -i;
33   }
34   int base = 10;
35   const FX_CHAR* str = "0123456789abcdef";
36   if (flags & FXFORMAT_HEX) {
37     base = 16;
38     if (flags & FXFORMAT_CAPITAL) {
39       str = "0123456789ABCDEF";
40     }
41   }
42   while (u != 0) {
43     buf1[buf_pos--] = str[u % base];
44     u = u / base;
45   }
46   if ((flags & FXFORMAT_SIGNED) && i < 0) {
47     buf1[buf_pos--] = '-';
48   }
49   int len = 31 - buf_pos;
50   for (int ii = 0; ii < len; ii++) {
51     buf[ii] = buf1[ii + buf_pos + 1];
52   }
53   return len;
54 }
55 
FX_strstr(const FX_CHAR * haystack,int haystack_len,const FX_CHAR * needle,int needle_len)56 const FX_CHAR* FX_strstr(const FX_CHAR* haystack,
57                          int haystack_len,
58                          const FX_CHAR* needle,
59                          int needle_len) {
60   if (needle_len > haystack_len || needle_len == 0) {
61     return nullptr;
62   }
63   const FX_CHAR* end_ptr = haystack + haystack_len - needle_len;
64   while (haystack <= end_ptr) {
65     int i = 0;
66     while (1) {
67       if (haystack[i] != needle[i]) {
68         break;
69       }
70       i++;
71       if (i == needle_len) {
72         return haystack;
73       }
74     }
75     haystack++;
76   }
77   return nullptr;
78 }
79 
80 }  // namespace
81 
82 static_assert(sizeof(CFX_ByteString) <= sizeof(FX_CHAR*),
83               "Strings must not require more space than pointers");
84 
CFX_ByteString(const FX_CHAR * pStr,FX_STRSIZE nLen)85 CFX_ByteString::CFX_ByteString(const FX_CHAR* pStr, FX_STRSIZE nLen) {
86   if (nLen < 0)
87     nLen = pStr ? FXSYS_strlen(pStr) : 0;
88 
89   if (nLen)
90     m_pData.Reset(StringData::Create(pStr, nLen));
91 }
92 
CFX_ByteString(const uint8_t * pStr,FX_STRSIZE nLen)93 CFX_ByteString::CFX_ByteString(const uint8_t* pStr, FX_STRSIZE nLen) {
94   if (nLen > 0) {
95     m_pData.Reset(
96         StringData::Create(reinterpret_cast<const FX_CHAR*>(pStr), nLen));
97   }
98 }
99 
CFX_ByteString()100 CFX_ByteString::CFX_ByteString() {}
101 
CFX_ByteString(const CFX_ByteString & other)102 CFX_ByteString::CFX_ByteString(const CFX_ByteString& other)
103     : m_pData(other.m_pData) {}
104 
CFX_ByteString(CFX_ByteString && other)105 CFX_ByteString::CFX_ByteString(CFX_ByteString&& other) {
106   m_pData.Swap(other.m_pData);
107 }
108 
CFX_ByteString(char ch)109 CFX_ByteString::CFX_ByteString(char ch) {
110   m_pData.Reset(StringData::Create(1));
111   m_pData->m_String[0] = ch;
112 }
113 
CFX_ByteString(const FX_CHAR * ptr)114 CFX_ByteString::CFX_ByteString(const FX_CHAR* ptr)
115     : CFX_ByteString(ptr, ptr ? FXSYS_strlen(ptr) : 0) {}
116 
CFX_ByteString(const CFX_ByteStringC & stringSrc)117 CFX_ByteString::CFX_ByteString(const CFX_ByteStringC& stringSrc) {
118   if (!stringSrc.IsEmpty())
119     m_pData.Reset(StringData::Create(stringSrc.c_str(), stringSrc.GetLength()));
120 }
121 
CFX_ByteString(const CFX_ByteStringC & str1,const CFX_ByteStringC & str2)122 CFX_ByteString::CFX_ByteString(const CFX_ByteStringC& str1,
123                                const CFX_ByteStringC& str2) {
124   int nNewLen = str1.GetLength() + str2.GetLength();
125   if (nNewLen == 0)
126     return;
127 
128   m_pData.Reset(StringData::Create(nNewLen));
129   m_pData->CopyContents(str1.c_str(), str1.GetLength());
130   m_pData->CopyContentsAt(str1.GetLength(), str2.c_str(), str2.GetLength());
131 }
132 
~CFX_ByteString()133 CFX_ByteString::~CFX_ByteString() {}
134 
operator =(const FX_CHAR * pStr)135 const CFX_ByteString& CFX_ByteString::operator=(const FX_CHAR* pStr) {
136   if (!pStr || !pStr[0])
137     clear();
138   else
139     AssignCopy(pStr, FXSYS_strlen(pStr));
140 
141   return *this;
142 }
143 
operator =(const CFX_ByteStringC & stringSrc)144 const CFX_ByteString& CFX_ByteString::operator=(
145     const CFX_ByteStringC& stringSrc) {
146   if (stringSrc.IsEmpty())
147     clear();
148   else
149     AssignCopy(stringSrc.c_str(), stringSrc.GetLength());
150 
151   return *this;
152 }
153 
operator =(const CFX_ByteString & stringSrc)154 const CFX_ByteString& CFX_ByteString::operator=(
155     const CFX_ByteString& stringSrc) {
156   if (m_pData != stringSrc.m_pData)
157     m_pData = stringSrc.m_pData;
158 
159   return *this;
160 }
161 
operator +=(const FX_CHAR * pStr)162 const CFX_ByteString& CFX_ByteString::operator+=(const FX_CHAR* pStr) {
163   if (pStr)
164     Concat(pStr, FXSYS_strlen(pStr));
165 
166   return *this;
167 }
168 
operator +=(char ch)169 const CFX_ByteString& CFX_ByteString::operator+=(char ch) {
170   Concat(&ch, 1);
171   return *this;
172 }
173 
operator +=(const CFX_ByteString & str)174 const CFX_ByteString& CFX_ByteString::operator+=(const CFX_ByteString& str) {
175   if (str.m_pData)
176     Concat(str.m_pData->m_String, str.m_pData->m_nDataLength);
177 
178   return *this;
179 }
180 
operator +=(const CFX_ByteStringC & str)181 const CFX_ByteString& CFX_ByteString::operator+=(const CFX_ByteStringC& str) {
182   if (!str.IsEmpty())
183     Concat(str.c_str(), str.GetLength());
184 
185   return *this;
186 }
187 
operator ==(const char * ptr) const188 bool CFX_ByteString::operator==(const char* ptr) const {
189   if (!m_pData)
190     return !ptr || !ptr[0];
191 
192   if (!ptr)
193     return m_pData->m_nDataLength == 0;
194 
195   return FXSYS_strlen(ptr) == m_pData->m_nDataLength &&
196          FXSYS_memcmp(ptr, m_pData->m_String, m_pData->m_nDataLength) == 0;
197 }
198 
operator ==(const CFX_ByteStringC & str) const199 bool CFX_ByteString::operator==(const CFX_ByteStringC& str) const {
200   if (!m_pData)
201     return str.IsEmpty();
202 
203   return m_pData->m_nDataLength == str.GetLength() &&
204          FXSYS_memcmp(m_pData->m_String, str.c_str(), str.GetLength()) == 0;
205 }
206 
operator ==(const CFX_ByteString & other) const207 bool CFX_ByteString::operator==(const CFX_ByteString& other) const {
208   if (m_pData == other.m_pData)
209     return true;
210 
211   if (IsEmpty())
212     return other.IsEmpty();
213 
214   if (other.IsEmpty())
215     return false;
216 
217   return other.m_pData->m_nDataLength == m_pData->m_nDataLength &&
218          FXSYS_memcmp(other.m_pData->m_String, m_pData->m_String,
219                       m_pData->m_nDataLength) == 0;
220 }
221 
operator <(const CFX_ByteString & str) const222 bool CFX_ByteString::operator<(const CFX_ByteString& str) const {
223   if (m_pData == str.m_pData)
224     return false;
225 
226   int result = FXSYS_memcmp(c_str(), str.c_str(),
227                             std::min(GetLength(), str.GetLength()));
228   return result < 0 || (result == 0 && GetLength() < str.GetLength());
229 }
230 
EqualNoCase(const CFX_ByteStringC & str) const231 bool CFX_ByteString::EqualNoCase(const CFX_ByteStringC& str) const {
232   if (!m_pData)
233     return str.IsEmpty();
234 
235   FX_STRSIZE len = str.GetLength();
236   if (m_pData->m_nDataLength != len)
237     return false;
238 
239   const uint8_t* pThis = (const uint8_t*)m_pData->m_String;
240   const uint8_t* pThat = str.raw_str();
241   for (FX_STRSIZE i = 0; i < len; i++) {
242     if ((*pThis) != (*pThat)) {
243       uint8_t bThis = *pThis;
244       if (bThis >= 'A' && bThis <= 'Z')
245         bThis += 'a' - 'A';
246 
247       uint8_t bThat = *pThat;
248       if (bThat >= 'A' && bThat <= 'Z')
249         bThat += 'a' - 'A';
250 
251       if (bThis != bThat)
252         return false;
253     }
254     pThis++;
255     pThat++;
256   }
257   return true;
258 }
259 
AssignCopy(const FX_CHAR * pSrcData,FX_STRSIZE nSrcLen)260 void CFX_ByteString::AssignCopy(const FX_CHAR* pSrcData, FX_STRSIZE nSrcLen) {
261   AllocBeforeWrite(nSrcLen);
262   m_pData->CopyContents(pSrcData, nSrcLen);
263   m_pData->m_nDataLength = nSrcLen;
264 }
265 
ReallocBeforeWrite(FX_STRSIZE nNewLength)266 void CFX_ByteString::ReallocBeforeWrite(FX_STRSIZE nNewLength) {
267   if (m_pData && m_pData->CanOperateInPlace(nNewLength))
268     return;
269 
270   if (nNewLength <= 0) {
271     clear();
272     return;
273   }
274 
275   CFX_RetainPtr<StringData> pNewData(StringData::Create(nNewLength));
276   if (m_pData) {
277     FX_STRSIZE nCopyLength = std::min(m_pData->m_nDataLength, nNewLength);
278     pNewData->CopyContents(m_pData->m_String, nCopyLength);
279     pNewData->m_nDataLength = nCopyLength;
280   } else {
281     pNewData->m_nDataLength = 0;
282   }
283   pNewData->m_String[pNewData->m_nDataLength] = 0;
284   m_pData.Swap(pNewData);
285 }
286 
AllocBeforeWrite(FX_STRSIZE nNewLength)287 void CFX_ByteString::AllocBeforeWrite(FX_STRSIZE nNewLength) {
288   if (m_pData && m_pData->CanOperateInPlace(nNewLength))
289     return;
290 
291   if (nNewLength <= 0) {
292     clear();
293     return;
294   }
295 
296   m_pData.Reset(StringData::Create(nNewLength));
297 }
298 
ReleaseBuffer(FX_STRSIZE nNewLength)299 void CFX_ByteString::ReleaseBuffer(FX_STRSIZE nNewLength) {
300   if (!m_pData)
301     return;
302 
303   if (nNewLength == -1)
304     nNewLength = FXSYS_strlen(m_pData->m_String);
305 
306   nNewLength = std::min(nNewLength, m_pData->m_nAllocLength);
307   if (nNewLength == 0) {
308     clear();
309     return;
310   }
311 
312   ASSERT(m_pData->m_nRefs == 1);
313   m_pData->m_nDataLength = nNewLength;
314   m_pData->m_String[nNewLength] = 0;
315   if (m_pData->m_nAllocLength - nNewLength >= 32) {
316     // Over arbitrary threshold, so pay the price to relocate.  Force copy to
317     // always occur by holding a second reference to the string.
318     CFX_ByteString preserve(*this);
319     ReallocBeforeWrite(nNewLength);
320   }
321 }
322 
Reserve(FX_STRSIZE len)323 void CFX_ByteString::Reserve(FX_STRSIZE len) {
324   GetBuffer(len);
325 }
326 
GetBuffer(FX_STRSIZE nMinBufLength)327 FX_CHAR* CFX_ByteString::GetBuffer(FX_STRSIZE nMinBufLength) {
328   if (!m_pData) {
329     if (nMinBufLength == 0)
330       return nullptr;
331 
332     m_pData.Reset(StringData::Create(nMinBufLength));
333     m_pData->m_nDataLength = 0;
334     m_pData->m_String[0] = 0;
335     return m_pData->m_String;
336   }
337 
338   if (m_pData->CanOperateInPlace(nMinBufLength))
339     return m_pData->m_String;
340 
341   nMinBufLength = std::max(nMinBufLength, m_pData->m_nDataLength);
342   if (nMinBufLength == 0)
343     return nullptr;
344 
345   CFX_RetainPtr<StringData> pNewData(StringData::Create(nMinBufLength));
346   pNewData->CopyContents(*m_pData);
347   pNewData->m_nDataLength = m_pData->m_nDataLength;
348   m_pData.Swap(pNewData);
349   return m_pData->m_String;
350 }
351 
Delete(FX_STRSIZE nIndex,FX_STRSIZE nCount)352 FX_STRSIZE CFX_ByteString::Delete(FX_STRSIZE nIndex, FX_STRSIZE nCount) {
353   if (!m_pData)
354     return 0;
355 
356   if (nIndex < 0)
357     nIndex = 0;
358 
359   FX_STRSIZE nOldLength = m_pData->m_nDataLength;
360   if (nCount > 0 && nIndex < nOldLength) {
361     FX_STRSIZE mLength = nIndex + nCount;
362     if (mLength >= nOldLength) {
363       m_pData->m_nDataLength = nIndex;
364       return m_pData->m_nDataLength;
365     }
366     ReallocBeforeWrite(nOldLength);
367     int nCharsToCopy = nOldLength - mLength + 1;
368     FXSYS_memmove(m_pData->m_String + nIndex, m_pData->m_String + mLength,
369                   nCharsToCopy);
370     m_pData->m_nDataLength = nOldLength - nCount;
371   }
372   return m_pData->m_nDataLength;
373 }
374 
Concat(const FX_CHAR * pSrcData,FX_STRSIZE nSrcLen)375 void CFX_ByteString::Concat(const FX_CHAR* pSrcData, FX_STRSIZE nSrcLen) {
376   if (!pSrcData || nSrcLen <= 0)
377     return;
378 
379   if (!m_pData) {
380     m_pData.Reset(StringData::Create(pSrcData, nSrcLen));
381     return;
382   }
383 
384   if (m_pData->CanOperateInPlace(m_pData->m_nDataLength + nSrcLen)) {
385     m_pData->CopyContentsAt(m_pData->m_nDataLength, pSrcData, nSrcLen);
386     m_pData->m_nDataLength += nSrcLen;
387     return;
388   }
389 
390   CFX_RetainPtr<StringData> pNewData(
391       StringData::Create(m_pData->m_nDataLength + nSrcLen));
392   pNewData->CopyContents(*m_pData);
393   pNewData->CopyContentsAt(m_pData->m_nDataLength, pSrcData, nSrcLen);
394   m_pData.Swap(pNewData);
395 }
396 
Mid(FX_STRSIZE nFirst) const397 CFX_ByteString CFX_ByteString::Mid(FX_STRSIZE nFirst) const {
398   if (!m_pData)
399     return CFX_ByteString();
400 
401   return Mid(nFirst, m_pData->m_nDataLength - nFirst);
402 }
403 
Mid(FX_STRSIZE nFirst,FX_STRSIZE nCount) const404 CFX_ByteString CFX_ByteString::Mid(FX_STRSIZE nFirst, FX_STRSIZE nCount) const {
405   if (!m_pData)
406     return CFX_ByteString();
407 
408   nFirst = std::min(std::max(nFirst, 0), m_pData->m_nDataLength);
409   nCount = std::min(std::max(nCount, 0), m_pData->m_nDataLength - nFirst);
410   if (nCount == 0)
411     return CFX_ByteString();
412 
413   if (nFirst == 0 && nCount == m_pData->m_nDataLength)
414     return *this;
415 
416   CFX_ByteString dest;
417   AllocCopy(dest, nCount, nFirst);
418   return dest;
419 }
420 
AllocCopy(CFX_ByteString & dest,FX_STRSIZE nCopyLen,FX_STRSIZE nCopyIndex) const421 void CFX_ByteString::AllocCopy(CFX_ByteString& dest,
422                                FX_STRSIZE nCopyLen,
423                                FX_STRSIZE nCopyIndex) const {
424   if (nCopyLen <= 0)
425     return;
426 
427   CFX_RetainPtr<StringData> pNewData(
428       StringData::Create(m_pData->m_String + nCopyIndex, nCopyLen));
429   dest.m_pData.Swap(pNewData);
430 }
431 
432 #define FORCE_ANSI 0x10000
433 #define FORCE_UNICODE 0x20000
434 #define FORCE_INT64 0x40000
435 
FormatInteger(int i,uint32_t flags)436 CFX_ByteString CFX_ByteString::FormatInteger(int i, uint32_t flags) {
437   char buf[32];
438   return CFX_ByteString(buf, Buffer_itoa(buf, i, flags));
439 }
440 
FormatV(const FX_CHAR * pFormat,va_list argList)441 void CFX_ByteString::FormatV(const FX_CHAR* pFormat, va_list argList) {
442   va_list argListSave;
443 #if defined(__ARMCC_VERSION) ||                                              \
444     (!defined(_MSC_VER) && (_FX_CPU_ == _FX_X64_ || _FX_CPU_ == _FX_IA64_ || \
445                             _FX_CPU_ == _FX_ARM64_)) ||                      \
446     defined(__native_client__)
447   va_copy(argListSave, argList);
448 #else
449   argListSave = argList;
450 #endif
451   int nMaxLen = 0;
452   for (const FX_CHAR* pStr = pFormat; *pStr != 0; pStr++) {
453     if (*pStr != '%' || *(pStr = pStr + 1) == '%') {
454       nMaxLen += FXSYS_strlen(pStr);
455       continue;
456     }
457     int nItemLen = 0;
458     int nWidth = 0;
459     for (; *pStr != 0; pStr++) {
460       if (*pStr == '#') {
461         nMaxLen += 2;
462       } else if (*pStr == '*') {
463         nWidth = va_arg(argList, int);
464       } else if (*pStr != '-' && *pStr != '+' && *pStr != '0' && *pStr != ' ') {
465         break;
466       }
467     }
468     if (nWidth == 0) {
469       nWidth = FXSYS_atoi(pStr);
470       while (std::isdigit(*pStr))
471         pStr++;
472     }
473     if (nWidth < 0 || nWidth > 128 * 1024) {
474       pFormat = "Bad width";
475       nMaxLen = 10;
476       break;
477     }
478     int nPrecision = 0;
479     if (*pStr == '.') {
480       pStr++;
481       if (*pStr == '*') {
482         nPrecision = va_arg(argList, int);
483         pStr++;
484       } else {
485         nPrecision = FXSYS_atoi(pStr);
486         while (std::isdigit(*pStr))
487           pStr++;
488       }
489     }
490     if (nPrecision < 0 || nPrecision > 128 * 1024) {
491       pFormat = "Bad precision";
492       nMaxLen = 14;
493       break;
494     }
495     int nModifier = 0;
496     if (FXSYS_strncmp(pStr, "I64", 3) == 0) {
497       pStr += 3;
498       nModifier = FORCE_INT64;
499     } else {
500       switch (*pStr) {
501         case 'h':
502           nModifier = FORCE_ANSI;
503           pStr++;
504           break;
505         case 'l':
506           nModifier = FORCE_UNICODE;
507           pStr++;
508           break;
509         case 'F':
510         case 'N':
511         case 'L':
512           pStr++;
513           break;
514       }
515     }
516     switch (*pStr | nModifier) {
517       case 'c':
518       case 'C':
519         nItemLen = 2;
520         va_arg(argList, int);
521         break;
522       case 'c' | FORCE_ANSI:
523       case 'C' | FORCE_ANSI:
524         nItemLen = 2;
525         va_arg(argList, int);
526         break;
527       case 'c' | FORCE_UNICODE:
528       case 'C' | FORCE_UNICODE:
529         nItemLen = 2;
530         va_arg(argList, int);
531         break;
532       case 's': {
533         const FX_CHAR* pstrNextArg = va_arg(argList, const FX_CHAR*);
534         if (pstrNextArg) {
535           nItemLen = FXSYS_strlen(pstrNextArg);
536           if (nItemLen < 1) {
537             nItemLen = 1;
538           }
539         } else {
540           nItemLen = 6;
541         }
542       } break;
543       case 'S': {
544         FX_WCHAR* pstrNextArg = va_arg(argList, FX_WCHAR*);
545         if (pstrNextArg) {
546           nItemLen = FXSYS_wcslen(pstrNextArg);
547           if (nItemLen < 1) {
548             nItemLen = 1;
549           }
550         } else {
551           nItemLen = 6;
552         }
553       } break;
554       case 's' | FORCE_ANSI:
555       case 'S' | FORCE_ANSI: {
556         const FX_CHAR* pstrNextArg = va_arg(argList, const FX_CHAR*);
557         if (pstrNextArg) {
558           nItemLen = FXSYS_strlen(pstrNextArg);
559           if (nItemLen < 1) {
560             nItemLen = 1;
561           }
562         } else {
563           nItemLen = 6;
564         }
565       } break;
566       case 's' | FORCE_UNICODE:
567       case 'S' | FORCE_UNICODE: {
568         FX_WCHAR* pstrNextArg = va_arg(argList, FX_WCHAR*);
569         if (pstrNextArg) {
570           nItemLen = FXSYS_wcslen(pstrNextArg);
571           if (nItemLen < 1) {
572             nItemLen = 1;
573           }
574         } else {
575           nItemLen = 6;
576         }
577       } break;
578     }
579     if (nItemLen != 0) {
580       if (nPrecision != 0 && nItemLen > nPrecision) {
581         nItemLen = nPrecision;
582       }
583       if (nItemLen < nWidth) {
584         nItemLen = nWidth;
585       }
586     } else {
587       switch (*pStr) {
588         case 'd':
589         case 'i':
590         case 'u':
591         case 'x':
592         case 'X':
593         case 'o':
594           if (nModifier & FORCE_INT64) {
595             va_arg(argList, int64_t);
596           } else {
597             va_arg(argList, int);
598           }
599           nItemLen = 32;
600           if (nItemLen < nWidth + nPrecision) {
601             nItemLen = nWidth + nPrecision;
602           }
603           break;
604         case 'a':
605         case 'A':
606         case 'e':
607         case 'E':
608         case 'g':
609         case 'G':
610           va_arg(argList, double);
611           nItemLen = 128;
612           if (nItemLen < nWidth + nPrecision) {
613             nItemLen = nWidth + nPrecision;
614           }
615           break;
616         case 'f':
617           if (nWidth + nPrecision > 100) {
618             nItemLen = nPrecision + nWidth + 128;
619           } else {
620             char pszTemp[256];
621             double f = va_arg(argList, double);
622             memset(pszTemp, 0, sizeof(pszTemp));
623             FXSYS_snprintf(pszTemp, sizeof(pszTemp) - 1, "%*.*f", nWidth,
624                            nPrecision + 6, f);
625             nItemLen = FXSYS_strlen(pszTemp);
626           }
627           break;
628         case 'p':
629           va_arg(argList, void*);
630           nItemLen = 32;
631           if (nItemLen < nWidth + nPrecision) {
632             nItemLen = nWidth + nPrecision;
633           }
634           break;
635         case 'n':
636           va_arg(argList, int*);
637           break;
638       }
639     }
640     nMaxLen += nItemLen;
641   }
642   nMaxLen += 32;  // Fudge factor.
643   GetBuffer(nMaxLen);
644   if (m_pData) {
645     memset(m_pData->m_String, 0, nMaxLen);
646     FXSYS_vsnprintf(m_pData->m_String, nMaxLen - 1, pFormat, argListSave);
647     ReleaseBuffer();
648   }
649   va_end(argListSave);
650 }
651 
Format(const FX_CHAR * pFormat,...)652 void CFX_ByteString::Format(const FX_CHAR* pFormat, ...) {
653   va_list argList;
654   va_start(argList, pFormat);
655   FormatV(pFormat, argList);
656   va_end(argList);
657 }
658 
Insert(FX_STRSIZE nIndex,FX_CHAR ch)659 FX_STRSIZE CFX_ByteString::Insert(FX_STRSIZE nIndex, FX_CHAR ch) {
660   FX_STRSIZE nNewLength = m_pData ? m_pData->m_nDataLength : 0;
661   nIndex = std::max(nIndex, 0);
662   nIndex = std::min(nIndex, nNewLength);
663   nNewLength++;
664 
665   ReallocBeforeWrite(nNewLength);
666   FXSYS_memmove(m_pData->m_String + nIndex + 1, m_pData->m_String + nIndex,
667                 nNewLength - nIndex);
668   m_pData->m_String[nIndex] = ch;
669   m_pData->m_nDataLength = nNewLength;
670   return nNewLength;
671 }
672 
Right(FX_STRSIZE nCount) const673 CFX_ByteString CFX_ByteString::Right(FX_STRSIZE nCount) const {
674   if (!m_pData)
675     return CFX_ByteString();
676 
677   nCount = std::max(nCount, 0);
678   if (nCount >= m_pData->m_nDataLength)
679     return *this;
680 
681   CFX_ByteString dest;
682   AllocCopy(dest, nCount, m_pData->m_nDataLength - nCount);
683   return dest;
684 }
685 
Left(FX_STRSIZE nCount) const686 CFX_ByteString CFX_ByteString::Left(FX_STRSIZE nCount) const {
687   if (!m_pData)
688     return CFX_ByteString();
689 
690   nCount = std::max(nCount, 0);
691   if (nCount >= m_pData->m_nDataLength)
692     return *this;
693 
694   CFX_ByteString dest;
695   AllocCopy(dest, nCount, 0);
696   return dest;
697 }
698 
Find(FX_CHAR ch,FX_STRSIZE nStart) const699 FX_STRSIZE CFX_ByteString::Find(FX_CHAR ch, FX_STRSIZE nStart) const {
700   if (!m_pData)
701     return -1;
702 
703   if (nStart < 0 || nStart >= m_pData->m_nDataLength)
704     return -1;
705 
706   const FX_CHAR* pStr = static_cast<const FX_CHAR*>(
707       memchr(m_pData->m_String + nStart, ch, m_pData->m_nDataLength - nStart));
708   return pStr ? pStr - m_pData->m_String : -1;
709 }
710 
ReverseFind(FX_CHAR ch) const711 FX_STRSIZE CFX_ByteString::ReverseFind(FX_CHAR ch) const {
712   if (!m_pData)
713     return -1;
714 
715   FX_STRSIZE nLength = m_pData->m_nDataLength;
716   while (nLength--) {
717     if (m_pData->m_String[nLength] == ch)
718       return nLength;
719   }
720   return -1;
721 }
722 
Find(const CFX_ByteStringC & pSub,FX_STRSIZE nStart) const723 FX_STRSIZE CFX_ByteString::Find(const CFX_ByteStringC& pSub,
724                                 FX_STRSIZE nStart) const {
725   if (!m_pData)
726     return -1;
727 
728   FX_STRSIZE nLength = m_pData->m_nDataLength;
729   if (nStart > nLength)
730     return -1;
731 
732   const FX_CHAR* pStr =
733       FX_strstr(m_pData->m_String + nStart, m_pData->m_nDataLength - nStart,
734                 pSub.c_str(), pSub.GetLength());
735   return pStr ? (int)(pStr - m_pData->m_String) : -1;
736 }
737 
MakeLower()738 void CFX_ByteString::MakeLower() {
739   if (!m_pData)
740     return;
741 
742   ReallocBeforeWrite(m_pData->m_nDataLength);
743   FXSYS_strlwr(m_pData->m_String);
744 }
745 
MakeUpper()746 void CFX_ByteString::MakeUpper() {
747   if (!m_pData)
748     return;
749 
750   ReallocBeforeWrite(m_pData->m_nDataLength);
751   FXSYS_strupr(m_pData->m_String);
752 }
753 
Remove(FX_CHAR chRemove)754 FX_STRSIZE CFX_ByteString::Remove(FX_CHAR chRemove) {
755   if (!m_pData || m_pData->m_nDataLength < 1)
756     return 0;
757 
758   FX_CHAR* pstrSource = m_pData->m_String;
759   FX_CHAR* pstrEnd = m_pData->m_String + m_pData->m_nDataLength;
760   while (pstrSource < pstrEnd) {
761     if (*pstrSource == chRemove)
762       break;
763     pstrSource++;
764   }
765   if (pstrSource == pstrEnd)
766     return 0;
767 
768   ptrdiff_t copied = pstrSource - m_pData->m_String;
769   ReallocBeforeWrite(m_pData->m_nDataLength);
770   pstrSource = m_pData->m_String + copied;
771   pstrEnd = m_pData->m_String + m_pData->m_nDataLength;
772 
773   FX_CHAR* pstrDest = pstrSource;
774   while (pstrSource < pstrEnd) {
775     if (*pstrSource != chRemove) {
776       *pstrDest = *pstrSource;
777       pstrDest++;
778     }
779     pstrSource++;
780   }
781 
782   *pstrDest = 0;
783   FX_STRSIZE nCount = (FX_STRSIZE)(pstrSource - pstrDest);
784   m_pData->m_nDataLength -= nCount;
785   return nCount;
786 }
787 
Replace(const CFX_ByteStringC & pOld,const CFX_ByteStringC & pNew)788 FX_STRSIZE CFX_ByteString::Replace(const CFX_ByteStringC& pOld,
789                                    const CFX_ByteStringC& pNew) {
790   if (!m_pData || pOld.IsEmpty())
791     return 0;
792 
793   FX_STRSIZE nSourceLen = pOld.GetLength();
794   FX_STRSIZE nReplacementLen = pNew.GetLength();
795   FX_STRSIZE nCount = 0;
796   const FX_CHAR* pStart = m_pData->m_String;
797   FX_CHAR* pEnd = m_pData->m_String + m_pData->m_nDataLength;
798   while (1) {
799     const FX_CHAR* pTarget = FX_strstr(pStart, (FX_STRSIZE)(pEnd - pStart),
800                                        pOld.c_str(), nSourceLen);
801     if (!pTarget)
802       break;
803 
804     nCount++;
805     pStart = pTarget + nSourceLen;
806   }
807   if (nCount == 0)
808     return 0;
809 
810   FX_STRSIZE nNewLength =
811       m_pData->m_nDataLength + (nReplacementLen - nSourceLen) * nCount;
812 
813   if (nNewLength == 0) {
814     clear();
815     return nCount;
816   }
817 
818   CFX_RetainPtr<StringData> pNewData(StringData::Create(nNewLength));
819   pStart = m_pData->m_String;
820   FX_CHAR* pDest = pNewData->m_String;
821   for (FX_STRSIZE i = 0; i < nCount; i++) {
822     const FX_CHAR* pTarget = FX_strstr(pStart, (FX_STRSIZE)(pEnd - pStart),
823                                        pOld.c_str(), nSourceLen);
824     FXSYS_memcpy(pDest, pStart, pTarget - pStart);
825     pDest += pTarget - pStart;
826     FXSYS_memcpy(pDest, pNew.c_str(), pNew.GetLength());
827     pDest += pNew.GetLength();
828     pStart = pTarget + nSourceLen;
829   }
830   FXSYS_memcpy(pDest, pStart, pEnd - pStart);
831   m_pData.Swap(pNewData);
832   return nCount;
833 }
834 
SetAt(FX_STRSIZE nIndex,FX_CHAR ch)835 void CFX_ByteString::SetAt(FX_STRSIZE nIndex, FX_CHAR ch) {
836   if (!m_pData) {
837     return;
838   }
839   ASSERT(nIndex >= 0);
840   ASSERT(nIndex < m_pData->m_nDataLength);
841   ReallocBeforeWrite(m_pData->m_nDataLength);
842   m_pData->m_String[nIndex] = ch;
843 }
844 
UTF8Decode() const845 CFX_WideString CFX_ByteString::UTF8Decode() const {
846   CFX_UTF8Decoder decoder;
847   for (FX_STRSIZE i = 0; i < GetLength(); i++) {
848     decoder.Input((uint8_t)m_pData->m_String[i]);
849   }
850   return CFX_WideString(decoder.GetResult());
851 }
852 
853 // static
FromUnicode(const FX_WCHAR * str,FX_STRSIZE len)854 CFX_ByteString CFX_ByteString::FromUnicode(const FX_WCHAR* str,
855                                            FX_STRSIZE len) {
856   FX_STRSIZE str_len = len >= 0 ? len : FXSYS_wcslen(str);
857   return FromUnicode(CFX_WideString(str, str_len));
858 }
859 
860 // static
FromUnicode(const CFX_WideString & str)861 CFX_ByteString CFX_ByteString::FromUnicode(const CFX_WideString& str) {
862   return CFX_CharMap::GetByteString(0, str.AsStringC());
863 }
864 
Compare(const CFX_ByteStringC & str) const865 int CFX_ByteString::Compare(const CFX_ByteStringC& str) const {
866   if (!m_pData) {
867     return str.IsEmpty() ? 0 : -1;
868   }
869   int this_len = m_pData->m_nDataLength;
870   int that_len = str.GetLength();
871   int min_len = this_len < that_len ? this_len : that_len;
872   for (int i = 0; i < min_len; i++) {
873     if ((uint8_t)m_pData->m_String[i] < str.GetAt(i)) {
874       return -1;
875     }
876     if ((uint8_t)m_pData->m_String[i] > str.GetAt(i)) {
877       return 1;
878     }
879   }
880   if (this_len < that_len) {
881     return -1;
882   }
883   if (this_len > that_len) {
884     return 1;
885   }
886   return 0;
887 }
888 
TrimRight(const CFX_ByteStringC & pTargets)889 void CFX_ByteString::TrimRight(const CFX_ByteStringC& pTargets) {
890   if (!m_pData || pTargets.IsEmpty()) {
891     return;
892   }
893   FX_STRSIZE pos = GetLength();
894   if (pos < 1) {
895     return;
896   }
897   while (pos) {
898     FX_STRSIZE i = 0;
899     while (i < pTargets.GetLength() &&
900            pTargets[i] != m_pData->m_String[pos - 1]) {
901       i++;
902     }
903     if (i == pTargets.GetLength()) {
904       break;
905     }
906     pos--;
907   }
908   if (pos < m_pData->m_nDataLength) {
909     ReallocBeforeWrite(m_pData->m_nDataLength);
910     m_pData->m_String[pos] = 0;
911     m_pData->m_nDataLength = pos;
912   }
913 }
914 
TrimRight(FX_CHAR chTarget)915 void CFX_ByteString::TrimRight(FX_CHAR chTarget) {
916   TrimRight(CFX_ByteStringC(chTarget));
917 }
918 
TrimRight()919 void CFX_ByteString::TrimRight() {
920   TrimRight("\x09\x0a\x0b\x0c\x0d\x20");
921 }
922 
TrimLeft(const CFX_ByteStringC & pTargets)923 void CFX_ByteString::TrimLeft(const CFX_ByteStringC& pTargets) {
924   if (!m_pData || pTargets.IsEmpty())
925     return;
926 
927   FX_STRSIZE len = GetLength();
928   if (len < 1)
929     return;
930 
931   FX_STRSIZE pos = 0;
932   while (pos < len) {
933     FX_STRSIZE i = 0;
934     while (i < pTargets.GetLength() && pTargets[i] != m_pData->m_String[pos]) {
935       i++;
936     }
937     if (i == pTargets.GetLength()) {
938       break;
939     }
940     pos++;
941   }
942   if (pos) {
943     ReallocBeforeWrite(len);
944     FX_STRSIZE nDataLength = len - pos;
945     FXSYS_memmove(m_pData->m_String, m_pData->m_String + pos,
946                   (nDataLength + 1) * sizeof(FX_CHAR));
947     m_pData->m_nDataLength = nDataLength;
948   }
949 }
950 
TrimLeft(FX_CHAR chTarget)951 void CFX_ByteString::TrimLeft(FX_CHAR chTarget) {
952   TrimLeft(CFX_ByteStringC(chTarget));
953 }
954 
TrimLeft()955 void CFX_ByteString::TrimLeft() {
956   TrimLeft("\x09\x0a\x0b\x0c\x0d\x20");
957 }
958 
GetID(FX_STRSIZE start_pos) const959 uint32_t CFX_ByteString::GetID(FX_STRSIZE start_pos) const {
960   return AsStringC().GetID(start_pos);
961 }
FX_ftoa(FX_FLOAT d,FX_CHAR * buf)962 FX_STRSIZE FX_ftoa(FX_FLOAT d, FX_CHAR* buf) {
963   buf[0] = '0';
964   buf[1] = '\0';
965   if (d == 0.0f) {
966     return 1;
967   }
968   bool bNegative = false;
969   if (d < 0) {
970     bNegative = true;
971     d = -d;
972   }
973   int scale = 1;
974   int scaled = FXSYS_round(d);
975   while (scaled < 100000) {
976     if (scale == 1000000) {
977       break;
978     }
979     scale *= 10;
980     scaled = FXSYS_round(d * scale);
981   }
982   if (scaled == 0) {
983     return 1;
984   }
985   char buf2[32];
986   int buf_size = 0;
987   if (bNegative) {
988     buf[buf_size++] = '-';
989   }
990   int i = scaled / scale;
991   FXSYS_itoa(i, buf2, 10);
992   FX_STRSIZE len = FXSYS_strlen(buf2);
993   FXSYS_memcpy(buf + buf_size, buf2, len);
994   buf_size += len;
995   int fraction = scaled % scale;
996   if (fraction == 0) {
997     return buf_size;
998   }
999   buf[buf_size++] = '.';
1000   scale /= 10;
1001   while (fraction) {
1002     buf[buf_size++] = '0' + fraction / scale;
1003     fraction %= scale;
1004     scale /= 10;
1005   }
1006   return buf_size;
1007 }
FormatFloat(FX_FLOAT d,int precision)1008 CFX_ByteString CFX_ByteString::FormatFloat(FX_FLOAT d, int precision) {
1009   FX_CHAR buf[32];
1010   FX_STRSIZE len = FX_ftoa(d, buf);
1011   return CFX_ByteString(buf, len);
1012 }
1013