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