Home | History | Annotate | Download | only in fxcrt
      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 
     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 }
     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
     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 }
     76 CFX_ByteString::~CFX_ByteString() {
     77   if (m_pData) {
     78     m_pData->Release();
     79   }
     80 }
     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 }
     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 }
    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 }
    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 }
    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 }
    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 }
    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 }
    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 }
    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 }
    180 const CFX_ByteString& CFX_ByteString::operator=(const CFX_BinaryBuf& buf) {
    181   Load(buf.GetBuffer(), buf.GetSize());
    182   return *this;
    183 }
    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 }
    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 }
    201 const CFX_ByteString& CFX_ByteString::operator+=(char ch) {
    202   ConcatInPlace(1, &ch);
    203   return *this;
    204 }
    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 }
    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 }
    220 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 }
    230 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 }
    237 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 }
    248 void CFX_ByteString::Empty() {
    249   if (m_pData) {
    250     m_pData->Release();
    251     m_pData = NULL;
    252   }
    253 }
    254 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 }
    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 }
    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 }
    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 }
    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 }
    325 void CFX_ByteString::Reserve(FX_STRSIZE len) {
    326   GetBuffer(len);
    327   ReleaseBuffer(GetLength());
    328 }
    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 }
    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 }
    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 }
    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 }
    422 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 }
    428 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 }
    448 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
    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 }
    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 }
    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 }
    714 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 }
    728 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 }
    742 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 }
    753 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 }
    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 }
    789 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 }
    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 }
    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 }
    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 }
    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 }
    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 }
    906 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 }
    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 }
    922 CFX_ByteString CFX_ByteString::FromUnicode(const CFX_WideString& str) {
    923   return FromUnicode(str.c_str(), str.GetLength());
    924 }
    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 }
    932 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 }
    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 }
    980 void CFX_ByteString::TrimRight(FX_CHAR chTarget) {
    981   TrimRight(CFX_ByteStringC(chTarget));
    982 }
    983 void CFX_ByteString::TrimRight() {
    984   TrimRight("\x09\x0a\x0b\x0c\x0d\x20");
    985 }
    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 }
   1017 void CFX_ByteString::TrimLeft(FX_CHAR chTarget) {
   1018   TrimLeft(CFX_ByteStringC(chTarget));
   1019 }
   1020 void CFX_ByteString::TrimLeft() {
   1021   TrimLeft("\x09\x0a\x0b\x0c\x0d\x20");
   1022 }
   1023 FX_DWORD CFX_ByteString::GetID(FX_STRSIZE start_pos) const {
   1024   return CFX_ByteStringC(*this).GetID(start_pos);
   1025 }
   1026 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 }
   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 }
   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