• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            tqsheng

            go.....
            隨筆 - 366, 文章 - 18, 評論 - 101, 引用 - 0
            數(shù)據(jù)加載中……

            CString源碼

            CString使用的是引用技術(shù),可以共享數(shù)據(jù)(這個大家都知道),另外空的CStirng是指向一個固定的地址的(_afxInitData).
            另外CStirng是有長度限制的2147483647(無符號int 的最大值).
            數(shù)據(jù)格式
            struct CStringData
            {
             long nRefs; //引用記數(shù)
             int nDataLength; //字符使用長度
             int nAllocLength; //分配長度
             TCHAR* data() { return (TCHAR*)(this+1); } //存放字符串的地方
             //this+1 相當(dāng)與是CStringData[1];所以TCHAR* data()指的是CStringData[1]的地址
            };
            基本和網(wǎng)絡(luò)通訊的數(shù)據(jù)包差不多
            typedef struct tagAnsMarketData //統(tǒng)一的應(yīng)答結(jié)構(gòu)
            {
             WORD wStkNum; //數(shù)目
             char iData[1]; //數(shù)據(jù)
            }ANS_MARKET_DATA,*PANS_MARKET_DATA;

            下面是代碼了
            #include <windows.h>
            #include <assert.h>
            #include <stdlib.h>
            #include <malloc.h>
            #include <tchar.h>

            string.h

            #ifndef __JONES__STRING__
            #define __JONES__STRING__

            struct CStringData
            {
             long nRefs; //引用記數(shù)
             int nDataLength; //字符使用長度
             int nAllocLength; //分配長度
             TCHAR* data() { return (TCHAR*)(this+1); } //存放字符串的地方
             //this+1 相當(dāng)與是CStringData[1];所以TCHAR* data()指的是CStringData[1]的地址
            };

            class CString
            {
            public:
             //構(gòu)造函數(shù)
             CString();
             CString(const CString& stringSrc);
             CString(TCHAR ch, int nLength =1);
             CString(LPCTSTR lpsz); // CString(LPCSTR lpsz); ANSI下版本
                   //CString(LPCWSTR lpsz);UNICODE下版本
             CString(LPCTSTR lpch, int nLength); //CString(LPCSTR lpch, int nLength);ANSI下版本
                      //CString(LPCWSTR lpch, int nLength);//UNICODE下版本
             CString(const unsigned char* psz);
             ~CString();
             //CStringData的屬性
             int GetLength() const; //得到字符長度
             int GetAllocLength() const; //得到分配的內(nèi)存長度
             BOOL IsEmpty() const; //判斷字符長度是否為0
             operator LPCTSTR() const; //類型轉(zhuǎn)換
             void Empty(); //清空CStringData
             //操作符重載
             const CString& operator=(const CString& stringSrc);
             const CString& operator=(LPCTSTR lpsz);
             const CString& operator=(TCHAR ch);
             const CString& operator+=(const CString& string);
             const CString& operator+=(TCHAR ch);
             const CString& operator+=(LPCTSTR lpsz);
             TCHAR operator[](int nIndex) const;

             friend CString operator+(const CString& string1,const CString& string2);
             friend CString operator+(const CString& string, TCHAR ch);
             friend CString operator+(TCHAR ch, const CString& string);
             friend CString operator+(const CString& string, LPCTSTR lpsz);
             friend CString operator+(LPCTSTR lpsz, const CString& string);

             //操作,脫離共享數(shù)據(jù)塊
             int Delete(int nIndex, int nCount = 1);//刪除從nIndex開始長度為nCount的數(shù)據(jù)
             int Insert(int nIndex, TCHAR ch); //插入一個字符
             int Insert(int nIndex, LPCTSTR pstr); //插入一個字符串
             int Replace(LPCTSTR lpszOld, LPCTSTR lpszNew); //替換數(shù)據(jù)
             int Replace(TCHAR chOld, TCHAR chNew); //替換數(shù)據(jù)
             int Remove(TCHAR chRemove); //移除一個字符
             void TrimRight(LPCTSTR lpszTargetList);
             void TrimRight(TCHAR chTarget);//去掉右邊chTarget
             void TrimRight(); //去掉右邊空格
             void TrimLeft(LPCTSTR lpszTargets);
             void TrimLeft(TCHAR chTarget); //去掉左邊chTarget
             void TrimLeft(); //去掉左邊空格
             //取某段字符串
             void SetAt(int nIndex, TCHAR ch);
             TCHAR GetAt(int nIndex) const;
             CString Mid(int nFirst) const; //取某段字符串
             CString Mid(int nFirst, int nCount) const; //取某段字符串
             CString Right(int nCount) const; //取右邊字符串
             CString Left(int nCount) const; //取左邊字符串
             void CString::MakeUpper(); //大寫
             void CString::MakeLower(); //小寫
             void CString::MakeReverse(); //????不知道干什么的 strrev
             //查找
             int Find(TCHAR ch) const;
             int Find(TCHAR ch, int nStart) const;
             int ReverseFind(TCHAR ch) const;
             int Find(LPCTSTR lpszSub) const;
             int Find(LPCTSTR lpszSub, int nStart) const;
             int FindOneOf(LPCTSTR lpszCharSet) const;//得到第一個匹配lpszCharSet中其中一個字符的位置 調(diào)用_tcspbrk
             //高級操作
             LPTSTR GetBuffer(int nMinBufLength); //重新分配內(nèi)存,在拷貝原來的數(shù)據(jù)
             void ReleaseBuffer(int nNewLength=-1); //在[nNewLength]='\0',對內(nèi)存大小沒有改變
             LPTSTR GetBufferSetLength(int nNewLength); //重新分配內(nèi)存,在拷貝原來的數(shù)據(jù)
             void FreeExtra(); //深拷貝自己,然后--原來的引用記數(shù)器
             LPTSTR LockBuffer(); //引用計數(shù)器=-1,加鎖
             void UnlockBuffer(); //解鎖,引用計數(shù)器=1
             //比較
             int Compare(LPCTSTR lpsz) const; //區(qū)分大小寫比較
             int CompareNoCase(LPCTSTR lpsz) const; //不區(qū)分大小寫比較
             //比較速度沒有Compare快
             int Collate(LPCTSTR lpsz) const; //區(qū)分大小寫比較
             int CollateNoCase(LPCTSTR lpsz) const; //不區(qū)分大小寫比較
             //格式化字符串
             void Format(LPCTSTR lpszFormat, ...);//CSting中最長的函數(shù)了,完全是自己分析的(牛啊)

            private:
             void Init();
             CStringData* GetData() const; //通過m_pchData-1 得到CStringData
             void AllocBuffer(int nLen); //給CStringData分配內(nèi)存,不帶記數(shù)器
             void CopyBeforeWrite(); //帶引用記數(shù)的復(fù)制自己深拷貝
             void AllocBeforeWrite(int nLen); //給CStringData分配內(nèi)存,帶記數(shù)器
             void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData);//分配內(nèi)存,并拷貝lpszSrcData內(nèi)容
             //把nCopyIndex開始的nCopyLen長度的數(shù)據(jù)拷貝給dest,nExtraLen擴充的長度,次函數(shù)好像沒下面用
             void AllocCopy(CString& dest, int nCopyLen, int nCopyIndex,int nExtraLen) const;
             void Release(); //--引用記數(shù)器并判斷是否刪除內(nèi)存,如刪除并初始化
             void FormatV(LPCTSTR lpszFormat, va_list argList);//格式化字符串
             void ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,
              int nSrc2Len, LPCTSTR lpszSrc2Data);//連接數(shù)據(jù)lpszSrc1Data+lpszSrc2Data
             void ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData); //連接字符串

             static void  Release(CStringData* pData); //--引用記數(shù)器并判斷是否刪除內(nèi)存
             static void FreeData(CStringData* pData); //釋放內(nèi)存
             static int SafeStrlen(LPCTSTR lpsz); //得到長度
             LPTSTR m_pchData; //指向CStringData的數(shù)據(jù)區(qū)
            };

            /*調(diào)用CString::Compare比較大小,如果比較中有CStirng的話用
            調(diào)用operator LPCTSTR()轉(zhuǎn)化類型為LPCTSTR
            */
            bool operator==(const CString& s1, const CString& s2);
            bool operator==(const CString& s1, LPCTSTR s2);
            bool operator==(LPCTSTR s1, const CString& s2);
            bool operator!=(const CString& s1, const CString& s2);
            bool operator!=(const CString& s1, LPCTSTR s2);
            bool operator!=(LPCTSTR s1, const CString& s2);
            bool operator<(const CString& s1, const CString& s2);
            bool operator<(const CString& s1, LPCTSTR s2);
            bool operator<(LPCTSTR s1, const CString& s2);
            bool operator>(const CString& s1, const CString& s2);
            bool operator>(const CString& s1, LPCTSTR s2);
            bool operator>(LPCTSTR s1, const CString& s2);
            bool operator<=(const CString& s1, const CString& s2);
            bool operator<=(const CString& s1, LPCTSTR s2);
            bool operator<=(LPCTSTR s1, const CString& s2);
            bool operator>=(const CString& s1, const CString& s2);
            bool operator>=(const CString& s1, LPCTSTR s2);
            bool operator>=(LPCTSTR s1, const CString& s2);

            //////////////////////////////////////////////////////////////////////
            //檢測lpsz是否有效,調(diào)用了IsBadStringPtr
            BOOL AfxIsValidString(LPCTSTR lpsz, int nLength = -1);
            //檢測lp是否能讀寫權(quán)限,調(diào)用了IsBadReadPtr,IsBadStringPtr
            BOOL AfxIsValidAddress(const void* lp,UINT nBytes, BOOL bReadWrite = TRUE);

            //CStirng數(shù)組操作
            void ConstructElements(CString* pElements, int nCount); //初始化CStirng數(shù)組
            void DestructElements(CString* pElements, int nCount); //刪除CStirng數(shù)組
            void CopyElements(CString* pDest, const CString* pSrc, int nCount); //CString數(shù)組拷貝

            #endif

            string.cpp

            #include "stdafx.h"
            #include "string.h"

            TCHAR afxChNil = '\0';
            int _afxInitData[] = { -1, 0, 0, 0 }; //初始化CStringData的地址
            CStringData* _afxDataNil = (CStringData*)&_afxInitData; //地址轉(zhuǎn)化為CStringData*
            LPCTSTR _afxPchNil = (LPCTSTR)(((BYTE*)&_afxInitData)+sizeof(CStringData));
            const CString&  AfxGetEmptyString()  //建立一個空的CString
            { return *(CString*)&_afxPchNil; }

            BOOL AfxIsValidString(LPCTSTR lpsz, int nLength /* = -1 */)
            {
             if (lpsz == NULL)
              return FALSE;
             return ::IsBadStringPtr(lpsz, nLength) == 0;
            }

            BOOL AfxIsValidAddress(const void* lp, UINT nBytes,BOOL bReadWrite /* = TRUE */)
            {
             return (lp != NULL && !IsBadReadPtr(lp, nBytes) &&
              (!bReadWrite !IsBadWritePtr((LPVOID)lp, nBytes)));
            }

            void CString::Init()
            { m_pchData=AfxGetEmptyString().m_pchData; }


            CString::CString()
            { Init(); }

            int CString::GetLength() const
            { return GetData()->nDataLength; }

            int CString::GetAllocLength() const
            { return GetData()->nAllocLength; }

            BOOL CString::IsEmpty() const
            { return GetData()->nDataLength == 0; }

            CStringData* CString::GetData() const
            {
             assert(m_pchData != NULL);
             return ((CStringData*)m_pchData)-1;
            }

            CString::operator LPCTSTR() const
            { return m_pchData; }

            int CString::SafeStrlen(LPCTSTR lpsz)
            { return (lpsz == NULL) ? 0 : lstrlen(lpsz); }

            void CString::AllocBuffer(int nLen)
            {
             assert(nLen >= 0);
             assert(nLen <= 2147483647-1);    // (signed) int 的最大值

             if (nLen == 0)
              Init();
             else
             {
              CStringData* pData;
              {
               pData = (CStringData*)
                new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)];
               pData->nAllocLength = nLen;
              }
              pData->nRefs = 1;
              pData->data()[nLen] = '\0';
              pData->nDataLength = nLen;
              m_pchData = pData->data();
             }
            }

            void CString::FreeData(CStringData* pData)
            {
             delete[] (BYTE*)pData;
            }

            void CString::CopyBeforeWrite()
            {
             if (GetData()->nRefs > 1)
             {
              CStringData* pData = GetData();
              Release();
              AllocBuffer(pData->nDataLength);
              memcpy(m_pchData, pData->data(), (pData->nDataLength+1)*sizeof(TCHAR));
             }
             assert(GetData()->nRefs <= 1);
            }

            void CString::AllocBeforeWrite(int nLen)
            {
             if (GetData()->nRefs > 1 nLen > GetData()->nAllocLength)
             {
              Release();
              AllocBuffer(nLen);
             }
             assert(GetData()->nRefs <= 1);
            }

            void CString::AssignCopy(int nSrcLen, LPCTSTR lpszSrcData)
            {
             AllocBeforeWrite(nSrcLen);
             memcpy(m_pchData, lpszSrcData, nSrcLen*sizeof(TCHAR));
             GetData()->nDataLength = nSrcLen;
             m_pchData[nSrcLen] = '\0';
            }

            void CString::AllocCopy(CString& dest, int nCopyLen, int nCopyIndex,
              int nExtraLen) const
            {
             int nNewLen = nCopyLen + nExtraLen;
             if (nNewLen == 0)
             {
              dest.Init();
             }
             else
             {
              dest.AllocBuffer(nNewLen);
              memcpy(dest.m_pchData, m_pchData+nCopyIndex, nCopyLen*sizeof(TCHAR));
             }
            }


            CString::~CString()
            {
             if (GetData() != _afxDataNil)
             {
              if (InterlockedDecrement(&GetData()->nRefs) <= 0)
               FreeData(GetData());
             }
            }


            CString::CString(const CString& stringSrc)
            {
             assert(stringSrc.GetData()->nRefs != 0);
             if (stringSrc.GetData()->nRefs >= 0)
             {
              assert(stringSrc.GetData() != _afxDataNil);
              m_pchData = stringSrc.m_pchData;
              InterlockedIncrement(&GetData()->nRefs);
             }
             else
             {
              Init();
              *this = stringSrc.m_pchData;
             }
            }

            CString::CString(LPCTSTR lpsz)
            {
             Init();
             int nLen = SafeStrlen(lpsz);
             if (nLen != 0)
             {
              AllocBuffer(nLen);
              memcpy(m_pchData, lpsz, nLen*sizeof(TCHAR));
             }
            }

            CString::CString(LPCTSTR lpch, int nLength)
            {
             Init();
             if (nLength != 0)
             {
              assert(AfxIsValidAddress(lpch, nLength, FALSE));
              AllocBuffer(nLength);
              memcpy(m_pchData, lpch, nLength*sizeof(TCHAR));
             }
            }


            void CString::Release()
            {
             if (GetData() != _afxDataNil)
             {
              assert(GetData()->nRefs != 0);
              if (InterlockedDecrement(&GetData()->nRefs) <= 0)
               FreeData(GetData());
              Init();
             }
            }

            void CString::Release(CStringData* pData)
            {
             if (pData != _afxDataNil)
             {
              assert(pData->nRefs != 0);
              if (InterlockedDecrement(&pData->nRefs) <= 0)
               FreeData(pData);
             }
            }

            void CString::Empty()
            {
             if (GetData()->nDataLength == 0)
              return;
             if (GetData()->nRefs >= 0)
              Release();
             else
              *this = &afxChNil;
             assert(GetData()->nDataLength == 0);
             assert(GetData()->nRefs < 0 GetData()->nAllocLength == 0);
            }


            const CString& CString::operator=(const CString& stringSrc)
            {
             if (m_pchData != stringSrc.m_pchData)
             {
              if ((GetData()->nRefs < 0 && GetData() != _afxDataNil)
               stringSrc.GetData()->nRefs < 0)
              {
               //新建一快數(shù)據(jù)
               AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);
              }
              else
              {
               //只拷貝指針
               Release();
               assert(stringSrc.GetData() != _afxDataNil);
               m_pchData = stringSrc.m_pchData;
               InterlockedIncrement(&GetData()->nRefs);
              }
             }
             return *this;
            }

            const CString& CString::operator=(LPCTSTR lpsz)
            {
             assert(lpsz == NULL AfxIsValidString(lpsz));
             AssignCopy(SafeStrlen(lpsz), lpsz);
             return *this;
            }

            const CString& CString::operator=(TCHAR ch)
            {
             AssignCopy(1, &ch);
             return *this;
            }


            int CString::Delete(int nIndex, int nCount /* = 1 */)
            {
             if (nIndex < 0)
              nIndex = 0;
             int nNewLength = GetData()->nDataLength;
             if (nCount > 0 && nIndex < nNewLength)
             {
              CopyBeforeWrite(); //脫離共享數(shù)據(jù)塊,
              int nBytesToCopy = nNewLength - (nIndex + nCount) + 1;
              //移動數(shù)據(jù)
              memcpy(m_pchData + nIndex,
               m_pchData + nIndex + nCount, nBytesToCopy * sizeof(TCHAR));
              GetData()->nDataLength = nNewLength - nCount;
             }
             return nNewLength;
            }


            int CString::Insert(int nIndex, TCHAR ch)
            {
             CopyBeforeWrite(); //脫離共享數(shù)據(jù)

             if (nIndex < 0)
              nIndex = 0;

             int nNewLength = GetData()->nDataLength;
             if (nIndex > nNewLength)
              nIndex = nNewLength;
             nNewLength++;

             if (GetData()->nAllocLength < nNewLength)
             { //動態(tài)分配內(nèi)存,并拷貝原來的數(shù)據(jù)
              CStringData* pOldData = GetData();
              LPTSTR pstr = m_pchData;
              AllocBuffer(nNewLength);
              memcpy(m_pchData, pstr, (pOldData->nDataLength+1)*sizeof(TCHAR));
              CString::Release(pOldData);
             }
             //插入數(shù)據(jù)
             memcpy(m_pchData + nIndex + 1,
              m_pchData + nIndex, (nNewLength-nIndex)*sizeof(TCHAR));
             m_pchData[nIndex] = ch;
             GetData()->nDataLength = nNewLength;

             return nNewLength;
            }


            int CString::Insert(int nIndex, LPCTSTR pstr)
            {
             if (nIndex < 0)
              nIndex = 0;

             int nInsertLength = SafeStrlen(pstr);
             int nNewLength = GetData()->nDataLength;
             if (nInsertLength > 0)
             {
              CopyBeforeWrite(); //脫離共享數(shù)據(jù)
              if (nIndex > nNewLength)
               nIndex = nNewLength;
              nNewLength += nInsertLength;

              if (GetData()->nAllocLength < nNewLength)
              { //動態(tài)分配內(nèi)存,并拷貝原來的數(shù)據(jù)
               CStringData* pOldData = GetData();
               LPTSTR pstr = m_pchData;
               AllocBuffer(nNewLength);
               memcpy(m_pchData, pstr, (pOldData->nDataLength+1)*sizeof(TCHAR));
               CString::Release(pOldData);
              }

              //移動數(shù)據(jù),留出插入的位酒move也可以
              memcpy(m_pchData + nIndex + nInsertLength,
               m_pchData + nIndex,
               (nNewLength-nIndex-nInsertLength+1)*sizeof(TCHAR));
              //插入數(shù)據(jù)
              memcpy(m_pchData + nIndex,
               pstr, nInsertLength*sizeof(TCHAR));
              GetData()->nDataLength = nNewLength;
             }

             return nNewLength;
            }

            int CString::Replace(TCHAR chOld, TCHAR chNew)
            {
             int nCount = 0;
             if (chOld != chNew) //替換的不能相同
             {
              CopyBeforeWrite();
              LPTSTR psz = m_pchData;
              LPTSTR pszEnd = psz + GetData()->nDataLength;
              while (psz < pszEnd)
              {
               if (*psz == chOld) //替換
               {
                *psz = chNew;
                nCount++;
               }
               psz = _tcsinc(psz); //相當(dāng)于++psz,考慮要UNICODE下版本才用的
              }
             }
             return nCount;
            }

            int CString::Replace(LPCTSTR lpszOld, LPCTSTR lpszNew)
            {
             int nSourceLen = SafeStrlen(lpszOld);
             if (nSourceLen == 0) //要替換的不能為空
              return 0;
             int nReplacementLen = SafeStrlen(lpszNew);

             int nCount = 0;
             LPTSTR lpszStart = m_pchData;
             LPTSTR lpszEnd = m_pchData + GetData()->nDataLength;
             LPTSTR lpszTarget;
             while (lpszStart < lpszEnd) //檢索要替換的個數(shù)
             {
              while ((lpszTarget = _tcsstr(lpszStart, lpszOld)) != NULL)
              {
               nCount++;
               lpszStart = lpszTarget + nSourceLen;
              }
              lpszStart += lstrlen(lpszStart) + 1;
             }

             
             if (nCount > 0)
             {
              CopyBeforeWrite();
              int nOldLength = GetData()->nDataLength;
              int nNewLength =  nOldLength + (nReplacementLen-nSourceLen)*nCount; //替換以后的長度
              if (GetData()->nAllocLength < nNewLength GetData()->nRefs > 1)
              { //超出原來的內(nèi)存長度動態(tài)分配
               CStringData* pOldData = GetData();
               LPTSTR pstr = m_pchData;
               AllocBuffer(nNewLength);
               memcpy(m_pchData, pstr, pOldData->nDataLength*sizeof(TCHAR));
               CString::Release(pOldData);
              }
             
              lpszStart = m_pchData;
              lpszEnd = m_pchData + GetData()->nDataLength;

             
              while (lpszStart < lpszEnd) //這個循環(huán)好象沒什么用
              {
               while ( (lpszTarget = _tcsstr(lpszStart, lpszOld)) != NULL) //開始替換
               {
                int nBalance = nOldLength - (lpszTarget - m_pchData + nSourceLen); //要往后移的長度
                //移動數(shù)據(jù),留出插入的位酒
                memmove(lpszTarget + nReplacementLen, lpszTarget + nSourceLen,
                 nBalance * sizeof(TCHAR));
                //插入替換數(shù)據(jù)
                memcpy(lpszTarget, lpszNew, nReplacementLen*sizeof(TCHAR));
                lpszStart = lpszTarget + nReplacementLen;
                lpszStart[nBalance] = '\0';
                nOldLength += (nReplacementLen - nSourceLen); //現(xiàn)有數(shù)據(jù)長度
               }
               lpszStart += lstrlen(lpszStart) + 1;
              }
              assert(m_pchData[nNewLength] == '\0');
              GetData()->nDataLength = nNewLength;
             }

             return nCount;
            }


            int CString::Remove(TCHAR chRemove)
            {
             CopyBeforeWrite();

             LPTSTR pstrSource = m_pchData;
             LPTSTR pstrDest = m_pchData;
             LPTSTR pstrEnd = m_pchData + GetData()->nDataLength;

             while (pstrSource < pstrEnd)
             {
              if (*pstrSource != chRemove)
              {
               *pstrDest = *pstrSource; //把不移除的數(shù)據(jù)拷貝
               pstrDest = _tcsinc(pstrDest);
              }
              pstrSource = _tcsinc(pstrSource);//++pstrSource
             }
             *pstrDest = '\0';
             int nCount = pstrSource - pstrDest; //比較變態(tài)的計算替換個數(shù),
             GetData()->nDataLength -= nCount;

             return nCount;
            }


            CString CString::Mid(int nFirst) const
            {
             return Mid(nFirst, GetData()->nDataLength - nFirst);
            }

            CString CString::Mid(int nFirst, int nCount) const
            {
             if (nFirst < 0)
              nFirst = 0;
             if (nCount < 0)
              nCount = 0;

             if (nFirst + nCount > GetData()->nDataLength)
              nCount = GetData()->nDataLength - nFirst;
             if (nFirst > GetData()->nDataLength)
              nCount = 0;

             assert(nFirst >= 0);
             assert(nFirst + nCount <= GetData()->nDataLength);

             //取去整個數(shù)據(jù)
             if (nFirst == 0 && nFirst + nCount == GetData()->nDataLength)
              return *this;
             
             CString dest;
             AllocCopy(dest, nCount, nFirst, 0);
             return dest;
            }


            CString CString::Right(int nCount) const
            {
             if (nCount < 0)
              nCount = 0;
             if (nCount >= GetData()->nDataLength)
              return *this;

             CString dest;
             AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);
             return dest;
            }

            CString CString::Left(int nCount) const
            {
             if (nCount < 0)
              nCount = 0;
             if (nCount >= GetData()->nDataLength)
              return *this;

             CString dest;
             AllocCopy(dest, nCount, 0, 0);
             return dest;
            }


            int CString::ReverseFind(TCHAR ch) const
            {
             //從最后查找
             LPTSTR lpsz = _tcsrchr(m_pchData, (_TUCHAR) ch);
             return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
            }

            int CString::Find(TCHAR ch) const
            {
             return Find(ch, 0);
            }

            int CString::Find(TCHAR ch, int nStart) const
            {
             int nLength = GetData()->nDataLength;
             if (nStart >= nLength)
              return -1;

             LPTSTR lpsz = _tcschr(m_pchData + nStart, (_TUCHAR)ch);
             return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
            }

            int CString::Find(LPCTSTR lpszSub) const
            {
             return Find(lpszSub, 0);
            }

            int CString::Find(LPCTSTR lpszSub, int nStart) const
            {
             assert(AfxIsValidString(lpszSub));

             int nLength = GetData()->nDataLength;
             if (nStart > nLength)
              return -1;

             LPTSTR lpsz = _tcsstr(m_pchData + nStart, lpszSub);

             return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
            }

            int CString::FindOneOf(LPCTSTR lpszCharSet) const
            {
             assert(AfxIsValidString(lpszCharSet));
             LPTSTR lpsz = _tcspbrk(m_pchData, lpszCharSet);
             return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
            }

            void CString::MakeUpper()
            {
             CopyBeforeWrite();
             _tcsupr(m_pchData);
            }

            void CString::MakeLower()
            {
             CopyBeforeWrite();
             _tcslwr(m_pchData);
            }

            void CString::MakeReverse()
            {
             CopyBeforeWrite();
             _tcsrev(m_pchData);
            }

            void CString::SetAt(int nIndex, TCHAR ch)
            {
             assert(nIndex >= 0);
             assert(nIndex < GetData()->nDataLength);

             CopyBeforeWrite();
             m_pchData[nIndex] = ch;
            }

            void CString::TrimRight(LPCTSTR lpszTargetList)
            {
             CopyBeforeWrite();
             LPTSTR lpsz = m_pchData;
             LPTSTR lpszLast = NULL;

             while (*lpsz != '\0')
             {
              if (_tcschr(lpszTargetList, *lpsz) != NULL)
              {
               if (lpszLast == NULL)
                lpszLast = lpsz;
              }
              else
               lpszLast = NULL;
              lpsz = _tcsinc(lpsz);
             }

             if (lpszLast != NULL)
             {
              *lpszLast = '\0';
              GetData()->nDataLength = lpszLast - m_pchData;
             }
            }

            void CString::TrimRight(TCHAR chTarget)
            {
             CopyBeforeWrite();
             LPTSTR lpsz = m_pchData;
             LPTSTR lpszLast = NULL;

             while (*lpsz != '\0')
             {
              if (*lpsz == chTarget)
              {
               if (lpszLast == NULL)
                lpszLast = lpsz;
              }
              else
               lpszLast = NULL;
              lpsz = _tcsinc(lpsz);
             }

             if (lpszLast != NULL)
             {
              *lpszLast = '\0';
              GetData()->nDataLength = lpszLast - m_pchData;
             }
            }

            void CString::TrimRight()
            {
             CopyBeforeWrite();
             LPTSTR lpsz = m_pchData;
             LPTSTR lpszLast = NULL;

             while (*lpsz != '\0')
             {
              if (_istspace(*lpsz))
              {
               if (lpszLast == NULL)
                lpszLast = lpsz;
              }
              else
               lpszLast = NULL;
              lpsz = _tcsinc(lpsz);
             }

             if (lpszLast != NULL)
             {
              // truncate at trailing space start
              *lpszLast = '\0';
              GetData()->nDataLength = lpszLast - m_pchData;
             }
            }

            void CString::TrimLeft(LPCTSTR lpszTargets)
            {
             // if we're not trimming anything, we're not doing any work
             if (SafeStrlen(lpszTargets) == 0)
              return;

             CopyBeforeWrite();
             LPCTSTR lpsz = m_pchData;

             while (*lpsz != '\0')
             {
              if (_tcschr(lpszTargets, *lpsz) == NULL)
               break;
              lpsz = _tcsinc(lpsz);
             }

             if (lpsz != m_pchData)
             {
              // fix up data and length
              int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
              memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
              GetData()->nDataLength = nDataLength;
             }
            }

            void CString::TrimLeft(TCHAR chTarget)
            {
             CopyBeforeWrite();
             LPCTSTR lpsz = m_pchData;

             while (chTarget == *lpsz)
              lpsz = _tcsinc(lpsz);

             if (lpsz != m_pchData)
             {
              int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
              memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
              GetData()->nDataLength = nDataLength;
             }
            }

            void CString::TrimLeft()
            {
             CopyBeforeWrite();
             LPCTSTR lpsz = m_pchData;

             while (_istspace(*lpsz))
              lpsz = _tcsinc(lpsz);

             if (lpsz != m_pchData)
             {
              int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
              memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
              GetData()->nDataLength = nDataLength;
             }
            }

            #define TCHAR_ARG   TCHAR
            #define WCHAR_ARG   WCHAR
            #define CHAR_ARG    char

            struct _AFX_DOUBLE  { BYTE doubleBits[sizeof(double)]; };

            #ifdef _X86_
             #define DOUBLE_ARG  _AFX_DOUBLE
            #else
             #define DOUBLE_ARG  double
            #endif

            #define FORCE_ANSI      0x10000
            #define FORCE_UNICODE   0x20000
            #define FORCE_INT64     0x40000

            void CString::FormatV(LPCTSTR lpszFormat, va_list argList)
            {
             assert(AfxIsValidString(lpszFormat));

             va_list argListSave = argList;

             // make a guess at the maximum length of the resulting string
             int nMaxLen = 0;
             for (LPCTSTR lpsz = lpszFormat; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
             {
              //查找%,對%%不在查找范圍
              if (*lpsz != '%' *(lpsz = _tcsinc(lpsz)) == '%')
              {
               nMaxLen += _tclen(lpsz);
               continue;
              }

              int nItemLen = 0;

              //%后面的格式判斷
              int nWidth = 0;
              for (; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
              {
               if (*lpsz == '#')
                nMaxLen += 2;   // 16進制 '0x'
               else if (*lpsz == '*')
                nWidth = va_arg(argList, int);
               else if (*lpsz == '-' *lpsz == '+' *lpsz == '0'
                *lpsz == ' ')
                ;
               else // hit non-flag character
                break;
              }
              // get width and skip it
              if (nWidth == 0)
              {
               // width indicated by
               nWidth = _ttoi(lpsz);
               for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
                ;
              }
              assert(nWidth >= 0);

              int nPrecision = 0;
              if (*lpsz == '.')
              {
               // skip past '.' separator (width.precision)
               lpsz = _tcsinc(lpsz);

               // get precision and skip it
               if (*lpsz == '*')
               {
                nPrecision = va_arg(argList, int);
                lpsz = _tcsinc(lpsz);
               }
               else
               {
                nPrecision = _ttoi(lpsz);
                for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
                 ;
               }
               assert(nPrecision >= 0);
              }

              // should be on type modifier or specifier
              int nModifier = 0;
              if (_tcsncmp(lpsz, _T("I64"), 3) == 0)
              {
               lpsz += 3;
               nModifier = FORCE_INT64;
            #if !defined(_X86_) && !defined(_ALPHA_)
               // __int64 is only available on X86 and ALPHA platforms
               ASSERT(FALSE);
            #endif
              }
              else
              {
               switch (*lpsz)
               {
               // modifiers that affect size
               case 'h':
                nModifier = FORCE_ANSI;
                lpsz = _tcsinc(lpsz);
                break;
               case 'l':
                nModifier = FORCE_UNICODE;
                lpsz = _tcsinc(lpsz);
                break;

               // modifiers that do not affect size
               case 'F':
               case 'N':
               case 'L':
                lpsz = _tcsinc(lpsz);
                break;
               }
              }

              // now should be on specifier
              switch (*lpsz | nModifier)
              {
              // single characters
              case 'c':
              case 'C':
               nItemLen = 2;
               va_arg(argList, TCHAR_ARG);
               break;
              case 'c'|FORCE_ANSI:
              case 'C'|FORCE_ANSI:
               nItemLen = 2;
               va_arg(argList, CHAR_ARG);
               break;
              case 'c'|FORCE_UNICODE:
              case 'C'|FORCE_UNICODE:
               nItemLen = 2;
               va_arg(argList, WCHAR_ARG);
               break;

              // strings
              case 's':
               {
                LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR);
                if (pstrNextArg == NULL)
                   nItemLen = 6;  // "(null)"
                else
                {
                   nItemLen = lstrlen(pstrNextArg);
                   nItemLen = max(1, nItemLen);
                }
               }
               break;

              case 'S':
               {
            #ifndef _UNICODE
                LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
                if (pstrNextArg == NULL)
                   nItemLen = 6;  // "(null)"
                else
                {
                   nItemLen = wcslen(pstrNextArg);
                   nItemLen = max(1, nItemLen);
                }
            #else
                LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
                if (pstrNextArg == NULL)
                   nItemLen = 6; // "(null)"
                else
                {
                   nItemLen = lstrlenA(pstrNextArg);
                   nItemLen = max(1, nItemLen);
                }
            #endif
               }
               break;

              case 's'|FORCE_ANSI:
              case 'S'|FORCE_ANSI:
               {
                LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
                if (pstrNextArg == NULL)
                   nItemLen = 6; // "(null)"
                else
                {
                   nItemLen = lstrlenA(pstrNextArg);
                   nItemLen = max(1, nItemLen);
                }
               }
               break;

              case 's'|FORCE_UNICODE:
              case 'S'|FORCE_UNICODE:
               {
                LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
                if (pstrNextArg == NULL)
                   nItemLen = 6; // "(null)"
                else
                {
                   nItemLen = wcslen(pstrNextArg);
                   nItemLen = max(1, nItemLen);
                }
               }
               break;
              }

              // adjust nItemLen for strings
              if (nItemLen != 0)
              {
               if (nPrecision != 0)
                nItemLen = min(nItemLen, nPrecision);
               nItemLen = max(nItemLen, nWidth);
              }
              else
              {
               switch (*lpsz)
               {
               // integers
               case 'd':
               case 'i':
               case 'u':
               case 'x':
               case 'X':
               case 'o':
                if (nModifier & FORCE_INT64)
                 va_arg(argList, __int64);
                else
                 va_arg(argList, int);
                nItemLen = 32;
                nItemLen = max(nItemLen, nWidth+nPrecision);
                break;

               case 'e':
               case 'g':
               case 'G':
                va_arg(argList, DOUBLE_ARG);
                nItemLen = 128;
                nItemLen = max(nItemLen, nWidth+nPrecision);
                break;

               case 'f':
                {
                 double f;
                 LPTSTR pszTemp;

                 // 312 == strlen("-1+(309 zeroes).")
                 // 309 zeroes == max precision of a double
                 // 6 == adjustment in case precision is not specified,
                 //   which means that the precision defaults to 6
                 pszTemp = (LPTSTR)_alloca(max(nWidth, 312+nPrecision+6));

                 f = va_arg(argList, double);
                 _stprintf( pszTemp, _T( "%*.*f" ), nWidth, nPrecision+6, f );
                 nItemLen = _tcslen(pszTemp);
                }
                break;

               case 'p':
                va_arg(argList, void*);
                nItemLen = 32;
                nItemLen = max(nItemLen, nWidth+nPrecision);
                break;

               // no output
               case 'n':
                va_arg(argList, int*);
                break;

               default:
                assert(FALSE);  // unknown formatting option
               }
              }

              // adjust nMaxLen for output nItemLen
              nMaxLen += nItemLen;
             }

             GetBuffer(nMaxLen);
             //VERIFY(_vstprintf(m_pchData, lpszFormat, argListSave) <= GetAllocLength());
             _vstprintf(m_pchData, lpszFormat, argListSave);
             ReleaseBuffer();

             va_end(argListSave);
            }

            void CString::Format(LPCTSTR lpszFormat, ...)
            {
             assert(AfxIsValidString(lpszFormat));

             va_list argList;
             va_start(argList, lpszFormat);
             FormatV(lpszFormat, argList);
             va_end(argList);
            }

            void CString::ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,int nSrc2Len, LPCTSTR lpszSrc2Data)
            {
             int nNewLen = nSrc1Len + nSrc2Len;
             if (nNewLen != 0)
             {
              AllocBuffer(nNewLen);
              memcpy(m_pchData, lpszSrc1Data, nSrc1Len*sizeof(TCHAR));
              memcpy(m_pchData+nSrc1Len, lpszSrc2Data, nSrc2Len*sizeof(TCHAR));
             }
            }

            void CString::ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData)
            {
             if (nSrcLen == 0)
              return;
             
             if (GetData()->nRefs > 1 GetData()->nDataLength + nSrcLen > GetData()->nAllocLength)
             {//動態(tài)分配
              CStringData* pOldData = GetData();
              ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData);
              assert(pOldData != NULL);
              CString::Release(pOldData);
             }
             else
             {//直接往后添加
              memcpy(m_pchData+GetData()->nDataLength, lpszSrcData, nSrcLen*sizeof(TCHAR));
              GetData()->nDataLength += nSrcLen;
              assert(GetData()->nDataLength <= GetData()->nAllocLength);
              m_pchData[GetData()->nDataLength] = '\0';
             }
            }

            const CString& CString::operator+=(LPCTSTR lpsz)
            {
             assert(lpsz == NULL AfxIsValidString(lpsz));
             ConcatInPlace(SafeStrlen(lpsz), lpsz);
             return *this;
            }

            const CString& CString::operator+=(TCHAR ch)
            {
             ConcatInPlace(1, &ch);
             return *this;
            }

            const CString& CString::operator+=(const CString& string)
            {
             ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
             return *this;
            }


            LPTSTR CString::GetBuffer(int nMinBufLength)
            {
             assert(nMinBufLength >= 0);
             if (GetData()->nRefs > 1 nMinBufLength > GetData()->nAllocLength)
             { //重新動態(tài)分配
              CStringData* pOldData = GetData();
              int nOldLen = GetData()->nDataLength;   // AllocBuffer will tromp it
              if (nMinBufLength < nOldLen)
               nMinBufLength = nOldLen;
              AllocBuffer(nMinBufLength);
              memcpy(m_pchData, pOldData->data(), (nOldLen+1)*sizeof(TCHAR));
              GetData()->nDataLength = nOldLen;
              CString::Release(pOldData);
             }
             assert(GetData()->nRefs <= 1);
             assert(m_pchData != NULL);
             return m_pchData;
            }

            void CString::ReleaseBuffer(int nNewLength)
            {
             CopyBeforeWrite();  //脫離共享數(shù)據(jù)塊,

             if (nNewLength == -1)
              nNewLength = lstrlen(m_pchData); // zero terminated

             assert(nNewLength <= GetData()->nAllocLength);
             GetData()->nDataLength = nNewLength;
             m_pchData[nNewLength] = '\0';
            }

            LPTSTR CString::GetBufferSetLength(int nNewLength)
            {
             assert(nNewLength >= 0);

             GetBuffer(nNewLength);
             GetData()->nDataLength = nNewLength;
             m_pchData[nNewLength] = '\0';
             return m_pchData;
            }

            void CString::FreeExtra()
            {
             assert(GetData()->nDataLength <= GetData()->nAllocLength);
             if (GetData()->nDataLength != GetData()->nAllocLength)
             {
              CStringData* pOldData = GetData();
              AllocBuffer(GetData()->nDataLength);
              memcpy(m_pchData, pOldData->data(), pOldData->nDataLength*sizeof(TCHAR));
              assert(m_pchData[GetData()->nDataLength] == '\0');
              CString::Release(pOldData);
             }
             assert(GetData() != NULL);
            }

            LPTSTR CString::LockBuffer()
            {
             LPTSTR lpsz = GetBuffer(0);
             GetData()->nRefs = -1;
             return lpsz;
            }

            void CString::UnlockBuffer()
            {
             assert(GetData()->nRefs == -1);
             if (GetData() != _afxDataNil)
              GetData()->nRefs = 1;
            }


            int CString::Compare(LPCTSTR lpsz) const
            {
             assert(AfxIsValidString(lpsz));
             return _tcscmp(m_pchData, lpsz);
            }

            int CString::CompareNoCase(LPCTSTR lpsz) const
            {
             assert(AfxIsValidString(lpsz));
             return _tcsicmp(m_pchData, lpsz);
            }
             
            // CString::Collate is often slower than Compare but is MBSC/Unicode
            //  aware as well as locale-sensitive with respect to sort order.
            int CString::Collate(LPCTSTR lpsz) const
            {
             assert(AfxIsValidString(lpsz));
             return _tcscoll(m_pchData, lpsz);


            int CString::CollateNoCase(LPCTSTR lpsz) const
            {
             assert(AfxIsValidString(lpsz));
             return _tcsicoll(m_pchData, lpsz);


            TCHAR CString::GetAt(int nIndex) const
            {
             assert(nIndex >= 0);
             assert(nIndex < GetData()->nDataLength);
             return m_pchData[nIndex];
            }


            TCHAR CString::operator[](int nIndex) const
            {
             assert(nIndex >= 0);
             assert(nIndex < GetData()->nDataLength);
             return m_pchData[nIndex];
            }

            ////////////////////////////////////////////////////////////////////////////////
            CString operator+(const CString& string1, const CString& string2)
            {
             CString s;
             s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData,
              string2.GetData()->nDataLength, string2.m_pchData);
             return s;
            }

            CString operator+(const CString& string, LPCTSTR lpsz)
            {
             assert(lpsz == NULL AfxIsValidString(lpsz));
             CString s;
             s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData,
              CString::SafeStrlen(lpsz), lpsz);
             return s;
            }

            CString operator+(LPCTSTR lpsz, const CString& string)
            {
             assert(lpsz == NULL AfxIsValidString(lpsz));
             CString s;
             s.ConcatCopy(CString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength,
              string.m_pchData);
             return s;
            }

            bool operator==(const CString& s1, const CString& s2)
            { return s1.Compare(s2) == 0; }

            bool operator==(const CString& s1, LPCTSTR s2)
            { return s1.Compare(s2) == 0; }

            bool operator==(LPCTSTR s1, const CString& s2)
            { return s2.Compare(s1) == 0; }

            bool operator!=(const CString& s1, const CString& s2)
            { return s1.Compare(s2) != 0; }

            bool operator!=(const CString& s1, LPCTSTR s2)
            { return s1.Compare(s2) != 0; }

            bool operator!=(LPCTSTR s1, const CString& s2)
            { return s2.Compare(s1) != 0; }

            bool operator<(const CString& s1, const CString& s2)
            { return s1.Compare(s2) < 0; }

            bool operator<(const CString& s1, LPCTSTR s2)
            { return s1.Compare(s2) < 0; }

            bool operator<(LPCTSTR s1, const CString& s2)
            { return s2.Compare(s1) > 0; }

            bool operator>(const CString& s1, const CString& s2)
            { return s1.Compare(s2) > 0; }

            bool operator>(const CString& s1, LPCTSTR s2)
            { return s1.Compare(s2) > 0; }

            bool operator>(LPCTSTR s1, const CString& s2)
            { return s2.Compare(s1) < 0; }

            bool operator<=(const CString& s1, const CString& s2)
            { return s1.Compare(s2) <= 0; }

            bool operator<=(const CString& s1, LPCTSTR s2)
            { return s1.Compare(s2) <= 0; }

            bool operator<=(LPCTSTR s1, const CString& s2)
            { return s2.Compare(s1) >= 0; }

            bool operator>=(const CString& s1, const CString& s2)
            { return s1.Compare(s2) >= 0; }

            bool operator>=(const CString& s1, LPCTSTR s2)
            { return s1.Compare(s2) >= 0; }

            bool operator>=(LPCTSTR s1, const CString& s2)
            { return s2.Compare(s1) <= 0; }

            ////////////////////////////////////////////////////////////////////////////////

            void ConstructElements(CString* pElements, int nCount)
            {
             assert(nCount == 0
              AfxIsValidAddress(pElements, nCount * sizeof(CString)));

             for (; nCount--; ++pElements)
              memcpy(pElements, &AfxGetEmptyString(), sizeof(*pElements));
            }


            void DestructElements(CString* pElements, int nCount)
            {
             assert(nCount == 0
              AfxIsValidAddress(pElements, nCount * sizeof(CString)));

             for (; nCount--; ++pElements)
              pElements->~CString();
            }

            void CopyElements(CString* pDest, const CString* pSrc, int nCount)
            {
             assert(nCount == 0
              AfxIsValidAddress(pDest, nCount * sizeof(CString)));
             assert(nCount == 0
              AfxIsValidAddress(pSrc, nCount * sizeof(CString)));

             for (; nCount--; ++pDest, ++pSrc)
              *pDest = *pSrc;
            }

             

            分類: C/C++

            posted on 2011-12-28 22:58 tqsheng 閱讀(372) 評論(0)  編輯 收藏 引用


            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            99久久免费国产精品| 久久精品国产亚洲AV香蕉| 久久本道综合久久伊人| 精品国产日韩久久亚洲| 亚洲AV无码1区2区久久| 精品久久久久久国产三级| 久久久亚洲AV波多野结衣| 国产福利电影一区二区三区久久老子无码午夜伦不 | 一本一本久久A久久综合精品 | 久久国产福利免费| 午夜人妻久久久久久久久| 九九久久精品国产| 久久午夜羞羞影院免费观看| 久久久久97国产精华液好用吗| 欧美噜噜久久久XXX| 亚洲国产成人久久综合碰| 久久综合九色综合精品| 亚洲AV日韩精品久久久久久| 久久丝袜精品中文字幕| 2021久久国自产拍精品| 欧美亚洲国产精品久久| 久久97久久97精品免视看| 99久久人妻无码精品系列蜜桃| 亚洲欧美日韩精品久久亚洲区 | 久久夜色精品国产噜噜亚洲a | www.久久热.com| 老色鬼久久亚洲AV综合| 亚洲欧美日韩久久精品第一区 | 久久成人精品视频| www性久久久com| 久久99国产综合精品免费| 婷婷久久久亚洲欧洲日产国码AV| 亚洲精品成人网久久久久久| 国产真实乱对白精彩久久| 97久久精品人人做人人爽| 久久无码av三级| 亚洲综合精品香蕉久久网97| 亚洲午夜久久久精品影院| 久久青青草原综合伊人| 中文字幕亚洲综合久久2| 91久久精品国产91性色也|