strcore.cpp 17 KB

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