home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / strcore.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  17KB  |  679 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12. #include "fixalloc.h"
  13.  
  14. #ifdef AFX_CORE1_SEG
  15. #pragma code_seg(AFX_CORE1_SEG)
  16. #endif
  17.  
  18. #ifdef _DEBUG
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22.  
  23. #define new DEBUG_NEW
  24.  
  25. /////////////////////////////////////////////////////////////////////////////
  26. // static class data, special inlines
  27.  
  28. // afxChNil is left for backward compatibility
  29. AFX_DATADEF TCHAR afxChNil = '\0';
  30.  
  31. // For an empty string, m_pchData will point here
  32. // (note: avoids special case of checking for NULL m_pchData)
  33. // empty string data (and locked)
  34. AFX_STATIC_DATA int _afxInitData[] = { -1, 0, 0, 0 };
  35. AFX_STATIC_DATA CStringData* _afxDataNil = (CStringData*)&_afxInitData;
  36. AFX_COMDAT LPCTSTR _afxPchNil = (LPCTSTR)(((BYTE*)&_afxInitData)+sizeof(CStringData));
  37. // special function to make afxEmptyString work even during initialization
  38. const CString& AFXAPI AfxGetEmptyString()
  39.     { return *(CString*)&_afxPchNil; }
  40.  
  41. //////////////////////////////////////////////////////////////////////////////
  42. // Construction/Destruction
  43.  
  44. #ifdef _AFXDLL
  45. CString::CString()
  46. {
  47.     Init();
  48. }
  49. #endif
  50.  
  51. CString::CString(const CString& stringSrc)
  52. {
  53.     ASSERT(stringSrc.GetData()->nRefs != 0);
  54.     if (stringSrc.GetData()->nRefs >= 0)
  55.     {
  56.         ASSERT(stringSrc.GetData() != _afxDataNil);
  57.         m_pchData = stringSrc.m_pchData;
  58.         InterlockedIncrement(&GetData()->nRefs);
  59.     }
  60.     else
  61.     {
  62.         Init();
  63.         *this = stringSrc.m_pchData;
  64.     }
  65. }
  66.  
  67. #ifndef _DEBUG
  68.  
  69. #pragma warning(disable: 4074)
  70. #pragma init_seg(compiler)
  71.  
  72. #define ROUND(x,y) (((x)+(y-1))&~(y-1))
  73. #define ROUND4(x) ROUND(x, 4)
  74. AFX_STATIC CFixedAlloc _afxAlloc64(ROUND4(65*sizeof(TCHAR)+sizeof(CStringData)));
  75. AFX_STATIC CFixedAlloc _afxAlloc128(ROUND4(129*sizeof(TCHAR)+sizeof(CStringData)));
  76. AFX_STATIC CFixedAlloc _afxAlloc256(ROUND4(257*sizeof(TCHAR)+sizeof(CStringData)));
  77. AFX_STATIC CFixedAlloc _afxAlloc512(ROUND4(513*sizeof(TCHAR)+sizeof(CStringData)));
  78.  
  79. #endif //!_DEBUG
  80.  
  81. void CString::AllocBuffer(int nLen)
  82. // always allocate one extra character for '\0' termination
  83. // assumes [optimistically] that data length will equal allocation length
  84. {
  85.     ASSERT(nLen >= 0);
  86.     ASSERT(nLen <= INT_MAX-1);    // max size (enough room for 1 extra)
  87.  
  88.     if (nLen == 0)
  89.         Init();
  90.     else
  91.     {
  92.         CStringData* pData;
  93. #ifndef _DEBUG
  94.         if (nLen <= 64)
  95.         {
  96.             pData = (CStringData*)_afxAlloc64.Alloc();
  97.             pData->nAllocLength = 64;
  98.         }
  99.         else if (nLen <= 128)
  100.         {
  101.             pData = (CStringData*)_afxAlloc128.Alloc();
  102.             pData->nAllocLength = 128;
  103.         }
  104.         else if (nLen <= 256)
  105.         {
  106.             pData = (CStringData*)_afxAlloc256.Alloc();
  107.             pData->nAllocLength = 256;
  108.         }
  109.         else if (nLen <= 512)
  110.         {
  111.             pData = (CStringData*)_afxAlloc512.Alloc();
  112.             pData->nAllocLength = 512;
  113.         }
  114.         else
  115. #endif
  116.         {
  117.             pData = (CStringData*)
  118.                 new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)];
  119.             pData->nAllocLength = nLen;
  120.         }
  121.         pData->nRefs = 1;
  122.         pData->data()[nLen] = '\0';
  123.         pData->nDataLength = nLen;
  124.         m_pchData = pData->data();
  125.     }
  126. }
  127.  
  128. void FASTCALL CString::FreeData(CStringData* pData)
  129. {
  130. #ifndef _DEBUG
  131.     int nLen = pData->nAllocLength;
  132.     if (nLen == 64)
  133.         _afxAlloc64.Free(pData);
  134.     else if (nLen == 128)
  135.         _afxAlloc128.Free(pData);
  136.     else if (nLen == 256)
  137.         _afxAlloc256.Free(pData);
  138.     else  if (nLen == 512)
  139.         _afxAlloc512.Free(pData);
  140.     else
  141.     {
  142.         ASSERT(nLen > 512);
  143.         delete[] (BYTE*)pData;
  144.     }
  145. #else
  146.     delete[] (BYTE*)pData;
  147. #endif
  148. }
  149.  
  150. void CString::Release()
  151. {
  152.     if (GetData() != _afxDataNil)
  153.     {
  154.         ASSERT(GetData()->nRefs != 0);
  155.         if (InterlockedDecrement(&GetData()->nRefs) <= 0)
  156.             FreeData(GetData());
  157.         Init();
  158.     }
  159. }
  160.  
  161. void PASCAL CString::Release(CStringData* pData)
  162. {
  163.     if (pData != _afxDataNil)
  164.     {
  165.         ASSERT(pData->nRefs != 0);
  166.         if (InterlockedDecrement(&pData->nRefs) <= 0)
  167.             FreeData(pData);
  168.     }
  169. }
  170.  
  171. void CString::Empty()
  172. {
  173.     if (GetData()->nDataLength == 0)
  174.         return;
  175.     if (GetData()->nRefs >= 0)
  176.         Release();
  177.     else
  178.         *this = &afxChNil;
  179.     ASSERT(GetData()->nDataLength == 0);
  180.     ASSERT(GetData()->nRefs < 0 || GetData()->nAllocLength == 0);
  181. }
  182.  
  183. void CString::CopyBeforeWrite()
  184. {
  185.     if (GetData()->nRefs > 1)
  186.     {
  187.         CStringData* pData = GetData();
  188.         Release();
  189.         AllocBuffer(pData->nDataLength);
  190.         memcpy(m_pchData, pData->data(), (pData->nDataLength+1)*sizeof(TCHAR));
  191.     }
  192.     ASSERT(GetData()->nRefs <= 1);
  193. }
  194.  
  195. void CString::AllocBeforeWrite(int nLen)
  196. {
  197.     if (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength)
  198.     {
  199.         Release();
  200.         AllocBuffer(nLen);
  201.     }
  202.     ASSERT(GetData()->nRefs <= 1);
  203. }
  204.  
  205. CString::~CString()
  206. //  free any attached data
  207. {
  208.     if (GetData() != _afxDataNil)
  209.     {
  210.         if (InterlockedDecrement(&GetData()->nRefs) <= 0)
  211.             FreeData(GetData());
  212.     }
  213. }
  214.  
  215. //////////////////////////////////////////////////////////////////////////////
  216. // Helpers for the rest of the implementation
  217.  
  218. void CString::AllocCopy(CString& dest, int nCopyLen, int nCopyIndex,
  219.      int nExtraLen) const
  220. {
  221.     // will clone the data attached to this string
  222.     // allocating 'nExtraLen' characters
  223.     // Places results in uninitialized string 'dest'
  224.     // Will copy the part or all of original data to start of new string
  225.  
  226.     int nNewLen = nCopyLen + nExtraLen;
  227.     if (nNewLen == 0)
  228.     {
  229.         dest.Init();
  230.     }
  231.     else
  232.     {
  233.         dest.AllocBuffer(nNewLen);
  234.         memcpy(dest.m_pchData, m_pchData+nCopyIndex, nCopyLen*sizeof(TCHAR));
  235.     }
  236. }
  237.  
  238. //////////////////////////////////////////////////////////////////////////////
  239. // More sophisticated construction
  240.  
  241. CString::CString(LPCTSTR lpsz)
  242. {
  243.     Init();
  244.     if (lpsz != NULL && HIWORD(lpsz) == NULL)
  245.     {
  246.         UINT nID = LOWORD((DWORD)lpsz);
  247.         if (!LoadString(nID))
  248.             TRACE1("Warning: implicit LoadString(%u) failed\n", nID);
  249.     }
  250.     else
  251.     {
  252.         int nLen = SafeStrlen(lpsz);
  253.         if (nLen != 0)
  254.         {
  255.             AllocBuffer(nLen);
  256.             memcpy(m_pchData, lpsz, nLen*sizeof(TCHAR));
  257.         }
  258.     }
  259. }
  260.  
  261. /////////////////////////////////////////////////////////////////////////////
  262. // Special conversion constructors
  263.  
  264. #ifdef _UNICODE
  265. CString::CString(LPCSTR lpsz)
  266. {
  267.     Init();
  268.     int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  269.     if (nSrcLen != 0)
  270.     {
  271.         AllocBuffer(nSrcLen);
  272.         _mbstowcsz(m_pchData, lpsz, nSrcLen+1);
  273.         ReleaseBuffer();
  274.     }
  275. }
  276. #else //_UNICODE
  277. CString::CString(LPCWSTR lpsz)
  278. {
  279.     Init();
  280.     int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
  281.     if (nSrcLen != 0)
  282.     {
  283.         AllocBuffer(nSrcLen*2);
  284.         _wcstombsz(m_pchData, lpsz, (nSrcLen*2)+1);
  285.         ReleaseBuffer();
  286.     }
  287. }
  288. #endif //!_UNICODE
  289.  
  290. //////////////////////////////////////////////////////////////////////////////
  291. // Diagnostic support
  292.  
  293. #ifdef _DEBUG
  294. CDumpContext& AFXAPI operator<<(CDumpContext& dc, const CString& string)
  295. {
  296.     dc << string.m_pchData;
  297.     return dc;
  298. }
  299. #endif //_DEBUG
  300.  
  301. //////////////////////////////////////////////////////////////////////////////
  302. // Assignment operators
  303. //  All assign a new value to the string
  304. //      (a) first see if the buffer is big enough
  305. //      (b) if enough room, copy on top of old buffer, set size and type
  306. //      (c) otherwise free old string data, and create a new one
  307. //
  308. //  All routines return the new string (but as a 'const CString&' so that
  309. //      assigning it again will cause a copy, eg: s1 = s2 = "hi there".
  310. //
  311.  
  312. void CString::AssignCopy(int nSrcLen, LPCTSTR lpszSrcData)
  313. {
  314.     AllocBeforeWrite(nSrcLen);
  315.     memcpy(m_pchData, lpszSrcData, nSrcLen*sizeof(TCHAR));
  316.     GetData()->nDataLength = nSrcLen;
  317.     m_pchData[nSrcLen] = '\0';
  318. }
  319.  
  320. const CString& CString::operator=(const CString& stringSrc)
  321. {
  322.     if (m_pchData != stringSrc.m_pchData)
  323.     {
  324.         if ((GetData()->nRefs < 0 && GetData() != _afxDataNil) ||
  325.             stringSrc.GetData()->nRefs < 0)
  326.         {
  327.             // actual copy necessary since one of the strings is locked
  328.             AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);
  329.         }
  330.         else
  331.         {
  332.             // can just copy references around
  333.             Release();
  334.             ASSERT(stringSrc.GetData() != _afxDataNil);
  335.             m_pchData = stringSrc.m_pchData;
  336.             InterlockedIncrement(&GetData()->nRefs);
  337.         }
  338.     }
  339.     return *this;
  340. }
  341.  
  342. const CString& CString::operator=(LPCTSTR lpsz)
  343. {
  344.     ASSERT(lpsz == NULL || AfxIsValidString(lpsz));
  345.     AssignCopy(SafeStrlen(lpsz), lpsz);
  346.     return *this;
  347. }
  348.  
  349. /////////////////////////////////////////////////////////////////////////////
  350. // Special conversion assignment
  351.  
  352. #ifdef _UNICODE
  353. const CString& CString::operator=(LPCSTR lpsz)
  354. {
  355.     int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  356.     AllocBeforeWrite(nSrcLen);
  357.     _mbstowcsz(m_pchData, lpsz, nSrcLen+1);
  358.     ReleaseBuffer();
  359.     return *this;
  360. }
  361. #else //!_UNICODE
  362. const CString& CString::operator=(LPCWSTR lpsz)
  363. {
  364.     int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
  365.     AllocBeforeWrite(nSrcLen*2);
  366.     _wcstombsz(m_pchData, lpsz, (nSrcLen*2)+1);
  367.     ReleaseBuffer();
  368.     return *this;
  369. }
  370. #endif  //!_UNICODE
  371.  
  372. //////////////////////////////////////////////////////////////////////////////
  373. // concatenation
  374.  
  375. // NOTE: "operator+" is done as friend functions for simplicity
  376. //      There are three variants:
  377. //          CString + CString
  378. // and for ? = TCHAR, LPCTSTR
  379. //          CString + ?
  380. //          ? + CString
  381.  
  382. void CString::ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,
  383.     int nSrc2Len, LPCTSTR lpszSrc2Data)
  384. {
  385.   // -- master concatenation routine
  386.   // Concatenate two sources
  387.   // -- assume that 'this' is a new CString object
  388.  
  389.     int nNewLen = nSrc1Len + nSrc2Len;
  390.     if (nNewLen != 0)
  391.     {
  392.         AllocBuffer(nNewLen);
  393.         memcpy(m_pchData, lpszSrc1Data, nSrc1Len*sizeof(TCHAR));
  394.         memcpy(m_pchData+nSrc1Len, lpszSrc2Data, nSrc2Len*sizeof(TCHAR));
  395.     }
  396. }
  397.  
  398. CString AFXAPI operator+(const CString& string1, const CString& string2)
  399. {
  400.     CString s;
  401.     s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData,
  402.         string2.GetData()->nDataLength, string2.m_pchData);
  403.     return s;
  404. }
  405.  
  406. CString AFXAPI operator+(const CString& string, LPCTSTR lpsz)
  407. {
  408.     ASSERT(lpsz == NULL || AfxIsValidString(lpsz));
  409.     CString s;
  410.     s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData,
  411.         CString::SafeStrlen(lpsz), lpsz);
  412.     return s;
  413. }
  414.  
  415. CString AFXAPI operator+(LPCTSTR lpsz, const CString& string)
  416. {
  417.     ASSERT(lpsz == NULL || AfxIsValidString(lpsz));
  418.     CString s;
  419.     s.ConcatCopy(CString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength,
  420.         string.m_pchData);
  421.     return s;
  422. }
  423.  
  424. //////////////////////////////////////////////////////////////////////////////
  425. // concatenate in place
  426.  
  427. void CString::ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData)
  428. {
  429.     //  -- the main routine for += operators
  430.  
  431.     // concatenating an empty string is a no-op!
  432.     if (nSrcLen == 0)
  433.         return;
  434.  
  435.     // if the buffer is too small, or we have a width mis-match, just
  436.     //   allocate a new buffer (slow but sure)
  437.     if (GetData()->nRefs > 1 || GetData()->nDataLength + nSrcLen > GetData()->nAllocLength)
  438.     {
  439.         // we have to grow the buffer, use the ConcatCopy routine
  440.         CStringData* pOldData = GetData();
  441.         ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData);
  442.         ASSERT(pOldData != NULL);
  443.         CString::Release(pOldData);
  444.     }
  445.     else
  446.     {
  447.         // fast concatenation when buffer big enough
  448.         memcpy(m_pchData+GetData()->nDataLength, lpszSrcData, nSrcLen*sizeof(TCHAR));
  449.         GetData()->nDataLength += nSrcLen;
  450.         ASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
  451.         m_pchData[GetData()->nDataLength] = '\0';
  452.     }
  453. }
  454.  
  455. const CString& CString::operator+=(LPCTSTR lpsz)
  456. {
  457.     ASSERT(lpsz == NULL || AfxIsValidString(lpsz));
  458.     ConcatInPlace(SafeStrlen(lpsz), lpsz);
  459.     return *this;
  460. }
  461.  
  462. const CString& CString::operator+=(TCHAR ch)
  463. {
  464.     ConcatInPlace(1, &ch);
  465.     return *this;
  466. }
  467.  
  468. const CString& CString::operator+=(const CString& string)
  469. {
  470.     ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
  471.     return *this;
  472. }
  473.  
  474. ///////////////////////////////////////////////////////////////////////////////
  475. // Advanced direct buffer access
  476.  
  477. LPTSTR CString::GetBuffer(int nMinBufLength)
  478. {
  479.     ASSERT(nMinBufLength >= 0);
  480.  
  481.     if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)
  482.     {
  483. #ifdef _DEBUG
  484.         // give a warning in case locked string becomes unlocked
  485.         if (GetData() != _afxDataNil && GetData()->nRefs < 0)
  486.             TRACE0("Warning: GetBuffer on locked CString creates unlocked CString!\n");
  487. #endif
  488.         // we have to grow the buffer
  489.         CStringData* pOldData = GetData();
  490.         int nOldLen = GetData()->nDataLength;   // AllocBuffer will tromp it
  491.         if (nMinBufLength < nOldLen)
  492.             nMinBufLength = nOldLen;
  493.         AllocBuffer(nMinBufLength);
  494.         memcpy(m_pchData, pOldData->data(), (nOldLen+1)*sizeof(TCHAR));
  495.         GetData()->nDataLength = nOldLen;
  496.         CString::Release(pOldData);
  497.     }
  498.     ASSERT(GetData()->nRefs <= 1);
  499.  
  500.     // return a pointer to the character storage for this string
  501.     ASSERT(m_pchData != NULL);
  502.     return m_pchData;
  503. }
  504.  
  505. void CString::ReleaseBuffer(int nNewLength)
  506. {
  507.     CopyBeforeWrite();  // just in case GetBuffer was not called
  508.  
  509.     if (nNewLength == -1)
  510.         nNewLength = lstrlen(m_pchData); // zero terminated
  511.  
  512.     ASSERT(nNewLength <= GetData()->nAllocLength);
  513.     GetData()->nDataLength = nNewLength;
  514.     m_pchData[nNewLength] = '\0';
  515. }
  516.  
  517. LPTSTR CString::GetBufferSetLength(int nNewLength)
  518. {
  519.     ASSERT(nNewLength >= 0);
  520.  
  521.     GetBuffer(nNewLength);
  522.     GetData()->nDataLength = nNewLength;
  523.     m_pchData[nNewLength] = '\0';
  524.     return m_pchData;
  525. }
  526.  
  527. void CString::FreeExtra()
  528. {
  529.     ASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
  530.     if (GetData()->nDataLength != GetData()->nAllocLength)
  531.     {
  532.         CStringData* pOldData = GetData();
  533.         AllocBuffer(GetData()->nDataLength);
  534.         memcpy(m_pchData, pOldData->data(), pOldData->nDataLength*sizeof(TCHAR));
  535.         ASSERT(m_pchData[GetData()->nDataLength] == '\0');
  536.         CString::Release(pOldData);
  537.     }
  538.     ASSERT(GetData() != NULL);
  539. }
  540.  
  541. LPTSTR CString::LockBuffer()
  542. {
  543.     LPTSTR lpsz = GetBuffer(0);
  544.     GetData()->nRefs = -1;
  545.     return lpsz;
  546. }
  547.  
  548. void CString::UnlockBuffer()
  549. {
  550.     ASSERT(GetData()->nRefs == -1);
  551.     if (GetData() != _afxDataNil)
  552.         GetData()->nRefs = 1;
  553. }
  554.  
  555. ///////////////////////////////////////////////////////////////////////////////
  556. // Commonly used routines (rarely used routines in STREX.CPP)
  557.  
  558. int CString::Find(TCHAR ch) const
  559. {
  560.     return Find(ch, 0);
  561. }
  562.  
  563. int CString::Find(TCHAR ch, int nStart) const
  564. {
  565.     int nLength = GetData()->nDataLength;
  566.     if (nStart >= nLength)
  567.         return -1;
  568.  
  569.     // find first single character
  570.     LPTSTR lpsz = _tcschr(m_pchData + nStart, (_TUCHAR)ch);
  571.  
  572.     // return -1 if not found and index otherwise
  573.     return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  574. }
  575.  
  576. int CString::FindOneOf(LPCTSTR lpszCharSet) const
  577. {
  578.     ASSERT(AfxIsValidString(lpszCharSet));
  579.     LPTSTR lpsz = _tcspbrk(m_pchData, lpszCharSet);
  580.     return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  581. }
  582.  
  583. void CString::MakeUpper()
  584. {
  585.     CopyBeforeWrite();
  586.     _tcsupr(m_pchData);
  587. }
  588.  
  589. void CString::MakeLower()
  590. {
  591.     CopyBeforeWrite();
  592.     _tcslwr(m_pchData);
  593. }
  594.  
  595. void CString::MakeReverse()
  596. {
  597.     CopyBeforeWrite();
  598.     _tcsrev(m_pchData);
  599. }
  600.  
  601. void CString::SetAt(int nIndex, TCHAR ch)
  602. {
  603.     ASSERT(nIndex >= 0);
  604.     ASSERT(nIndex < GetData()->nDataLength);
  605.  
  606.     CopyBeforeWrite();
  607.     m_pchData[nIndex] = ch;
  608. }
  609.  
  610. #ifndef _UNICODE
  611. void CString::AnsiToOem()
  612. {
  613.     CopyBeforeWrite();
  614.     ::AnsiToOem(m_pchData, m_pchData);
  615. }
  616. void CString::OemToAnsi()
  617. {
  618.     CopyBeforeWrite();
  619.     ::OemToAnsi(m_pchData, m_pchData);
  620. }
  621. #endif
  622.  
  623. ///////////////////////////////////////////////////////////////////////////////
  624. // CString conversion helpers (these use the current system locale)
  625.  
  626. int AFX_CDECL _wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count)
  627. {
  628.     if (count == 0 && mbstr != NULL)
  629.         return 0;
  630.  
  631.     int result = ::WideCharToMultiByte(CP_ACP, 0, wcstr, -1,
  632.         mbstr, count, NULL, NULL);
  633.     ASSERT(mbstr == NULL || result <= (int)count);
  634.     if (result > 0)
  635.         mbstr[result-1] = 0;
  636.     return result;
  637. }
  638.  
  639. int AFX_CDECL _mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count)
  640. {
  641.     if (count == 0 && wcstr != NULL)
  642.         return 0;
  643.  
  644.     int result = ::MultiByteToWideChar(CP_ACP, 0, mbstr, -1,
  645.         wcstr, count);
  646.     ASSERT(wcstr == NULL || result <= (int)count);
  647.     if (result > 0)
  648.         wcstr[result-1] = 0;
  649.     return result;
  650. }
  651.  
  652. LPWSTR AFXAPI AfxA2WHelper(LPWSTR lpw, LPCSTR lpa, int nChars)
  653. {
  654.     if (lpa == NULL)
  655.         return NULL;
  656.     ASSERT(lpw != NULL);
  657.     // verify that no illegal character present
  658.     // since lpw was allocated based on the size of lpa
  659.     // don't worry about the number of chars
  660.     lpw[0] = '\0';
  661.     VERIFY(MultiByteToWideChar(CP_ACP, 0, lpa, -1, lpw, nChars));
  662.     return lpw;
  663. }
  664.  
  665. LPSTR AFXAPI AfxW2AHelper(LPSTR lpa, LPCWSTR lpw, int nChars)
  666. {
  667.     if (lpw == NULL)
  668.         return NULL;
  669.     ASSERT(lpa != NULL);
  670.     // verify that no illegal character present
  671.     // since lpa was allocated based on the size of lpw
  672.     // don't worry about the number of chars
  673.     lpa[0] = '\0';
  674.     VERIFY(WideCharToMultiByte(CP_ACP, 0, lpw, -1, lpa, nChars, NULL, NULL));
  675.     return lpa;
  676. }
  677.  
  678. ///////////////////////////////////////////////////////////////////////////////
  679.