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
13static 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}
45CFX_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
51CFX_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}
76CFX_ByteString::~CFX_ByteString() {
77  if (m_pData) {
78    m_pData->Release();
79  }
80}
81CFX_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}
94CFX_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}
104CFX_ByteString::CFX_ByteString(char ch) {
105  m_pData = StringData::Create(1);
106  if (m_pData) {
107    m_pData->m_String[0] = ch;
108  }
109}
110CFX_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}
123CFX_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}
131CFX_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}
145const 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}
153const 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}
161const 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}
180const CFX_ByteString& CFX_ByteString::operator=(const CFX_BinaryBuf& buf) {
181  Load(buf.GetBuffer(), buf.GetSize());
182  return *this;
183}
184void 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}
195const CFX_ByteString& CFX_ByteString::operator+=(const FX_CHAR* lpsz) {
196  if (lpsz) {
197    ConcatInPlace(FXSYS_strlen(lpsz), lpsz);
198  }
199  return *this;
200}
201const CFX_ByteString& CFX_ByteString::operator+=(char ch) {
202  ConcatInPlace(1, &ch);
203  return *this;
204}
205const 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}
212const 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}
220bool 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}
230bool 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}
237bool 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}
248void CFX_ByteString::Empty() {
249  if (m_pData) {
250    m_pData->Release();
251    m_pData = NULL;
252  }
253}
254bool 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}
283void 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}
290void 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}
302void 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}
309void 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}
325void CFX_ByteString::Reserve(FX_STRSIZE len) {
326  GetBuffer(len);
327  ReleaseBuffer(GetLength());
328}
329FX_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}
360FX_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}
382void 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}
405void 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}
422CFX_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}
428CFX_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}
448void 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
466void 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}
678void 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}
684FX_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}
714CFX_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}
728CFX_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}
742FX_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}
753FX_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}
766const 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}
789FX_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}
803void 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}
813void 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}
823FX_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}
846FX_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}
897void 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}
906CFX_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}
913CFX_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}
922CFX_ByteString CFX_ByteString::FromUnicode(const CFX_WideString& str) {
923  return FromUnicode(str.c_str(), str.GetLength());
924}
925void 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}
932int 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}
955void 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}
980void CFX_ByteString::TrimRight(FX_CHAR chTarget) {
981  TrimRight(CFX_ByteStringC(chTarget));
982}
983void CFX_ByteString::TrimRight() {
984  TrimRight("\x09\x0a\x0b\x0c\x0d\x20");
985}
986void 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}
1017void CFX_ByteString::TrimLeft(FX_CHAR chTarget) {
1018  TrimLeft(CFX_ByteStringC(chTarget));
1019}
1020void CFX_ByteString::TrimLeft() {
1021  TrimLeft("\x09\x0a\x0b\x0c\x0d\x20");
1022}
1023FX_DWORD CFX_ByteString::GetID(FX_STRSIZE start_pos) const {
1024  return CFX_ByteStringC(*this).GetID(start_pos);
1025}
1026FX_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}
1046FX_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}
1092CFX_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