strcore.cpp 17 KB

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