Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

652 lines
16 KiB

  1. //-----------------------------------------------------------------------------
  2. //
  3. // Microsoft Forms
  4. // Copyright: (c) 1994-1995, Microsoft Corporation
  5. // All rights Reserved.
  6. // Information contained herein is Proprietary and Confidential.
  7. //
  8. // File CSTR.CXX
  9. //
  10. // Contents Class implementation for length prefix string class
  11. //
  12. // Classes CStr
  13. //
  14. // Maintained by Istvanc
  15. //
  16. //
  17. // History:
  18. // 5-22-95 kfl converted WCHAR to TCHAR
  19. //-----------------------------------------------------------------------------
  20. #include "headers.hxx"
  21. ANSIString::ANSIString(WCHAR *pchWide)
  22. {
  23. _pch = NULL;
  24. Set(pchWide);
  25. }
  26. void
  27. ANSIString::Set(WCHAR *pchWide)
  28. {
  29. int cch = wcslen(pchWide) + 1;
  30. if (_pch)
  31. delete _pch;
  32. if (cch > 0)
  33. {
  34. _pch = new char[cch];
  35. MemSetName(_pch, "ANSIString");
  36. if (_pch)
  37. {
  38. WideCharToMultiByte(CP_ACP,
  39. 0,
  40. pchWide,
  41. -1,
  42. _pch,
  43. cch,
  44. NULL,
  45. NULL);
  46. }
  47. }
  48. else
  49. _pch = NULL;
  50. }
  51. //+---------------------------------------------------------------------------
  52. //
  53. // Member: CStr::Set, public
  54. //
  55. // Synopsis: Allocates memory for a string and initializes it from a given
  56. // string.
  57. //
  58. // Arguments: [pch] -- String to initialize with. Can be NULL
  59. // [uc] -- Number of characters to allocate.
  60. //
  61. // Returns: HRESULT
  62. //
  63. // Notes: The total number of characters allocated is uc+1, to allow
  64. // for a NULL terminator. If [pch] is NULL, then the string is
  65. // uninitialized except for the NULL terminator, which is at
  66. // character position [uc].
  67. //
  68. //----------------------------------------------------------------------------
  69. HRESULT
  70. CStr::Set(LPCTSTR pch, UINT uc)
  71. {
  72. if (pch == _pch)
  73. {
  74. if (uc == Length())
  75. return S_OK;
  76. // when the ptrs are the same the length can only be
  77. // different if the ptrs are NULL. this is a hack used
  78. // internally to implement realloc type expansion
  79. Assert(pch == NULL && _pch == NULL);
  80. }
  81. Free();
  82. BYTE * p = new BYTE [sizeof(TCHAR) + sizeof(TCHAR) * uc + sizeof(UINT)];
  83. if (p)
  84. {
  85. MemSetName(p, "CStr String");
  86. *(UINT *)(p) = uc * sizeof(TCHAR);
  87. _pch = (TCHAR *)(p + sizeof(UINT));
  88. if (pch)
  89. {
  90. _tcsncpy(_pch, pch, uc);
  91. }
  92. ((TCHAR *)_pch) [uc] = 0;
  93. }
  94. else
  95. {
  96. return E_OUTOFMEMORY;
  97. }
  98. return S_OK;
  99. }
  100. //+---------------------------------------------------------------------------
  101. //
  102. // Member: CStr::Set, public
  103. //
  104. // Synopsis: Allocates a string and initializes it
  105. //
  106. // Arguments: [pch] -- String to initialize from
  107. //
  108. //----------------------------------------------------------------------------
  109. HRESULT
  110. CStr::Set(LPCTSTR pch)
  111. {
  112. RRETURN(Set(pch, pch ? _tcsclen(pch) : 0));
  113. }
  114. //+---------------------------------------------------------------------------
  115. //
  116. // Member: CStr::Set, public
  117. //
  118. // Synopsis: Allocates a string and initializes it
  119. //
  120. // Arguments: [cstr] -- String to initialize from
  121. //
  122. //----------------------------------------------------------------------------
  123. HRESULT
  124. CStr::Set(const CStr &cstr)
  125. {
  126. RRETURN(Set(cstr, cstr.Length()));
  127. }
  128. //+---------------------------------------------------------------------------
  129. //
  130. // Member: CStr::TakeOwnership, public
  131. //
  132. // Synopsis: Takes the ownership of a string from another CStr class.
  133. //
  134. // Arguments: [cstr] -- Class to take string from
  135. //
  136. // Notes: This method just transfers a string from one CStr class to
  137. // another. The class which is the source of the transfer has
  138. // a NULL value at the end of the operation.
  139. //
  140. //----------------------------------------------------------------------------
  141. void
  142. CStr::TakeOwnership(CStr &cstr)
  143. {
  144. _Free();
  145. _pch = cstr._pch;
  146. cstr._pch = NULL;
  147. }
  148. //+---------------------------------------------------------------------------
  149. //
  150. // Member: CStr::SetBSTR, public
  151. //
  152. // Synopsis: Allocates a string and initializes it from a BSTR
  153. //
  154. // Arguments: [bstr] -- Initialization string
  155. //
  156. // Notes: This method is more efficient than Set(LPCWSTR pch) because
  157. // of the length-prefix on BSTRs.
  158. //
  159. //----------------------------------------------------------------------------
  160. HRESULT
  161. CStr::SetBSTR(const BSTR bstr)
  162. {
  163. RRETURN(Set(bstr, bstr ? SysStringLen(bstr) : 0));
  164. }
  165. //+---------------------------------------------------------------------------
  166. //
  167. // Member: CStr::SetMultiByte, public
  168. //
  169. // Synopsis: Sets the string value from an MultiByte string
  170. //
  171. // Arguments: [pch] -- MultiByte string to convert to UNICODE
  172. //
  173. //----------------------------------------------------------------------------
  174. HRESULT
  175. CStr::SetMultiByte(LPCSTR pch)
  176. {
  177. HRESULT hr;
  178. DWORD dwLen;
  179. dwLen = strlen(pch);
  180. hr = Set(NULL, dwLen);
  181. if (hr)
  182. RRETURN(hr);
  183. dwLen = MultiByteToWideChar(CP_ACP,
  184. 0,
  185. pch,
  186. dwLen,
  187. _pch,
  188. dwLen + 1);
  189. if (dwLen == 0)
  190. {
  191. hr = HRESULT_FROM_WIN32(GetLastError());
  192. }
  193. RRETURN(hr);
  194. }
  195. //+---------------------------------------------------------------------------
  196. //
  197. // Member: CStr::GetMultiByte, public
  198. //
  199. // Synopsis: Gets the string value in MultiByte format
  200. //
  201. // Arguments: [pch] -- Place to put MultiByte string
  202. // [cch] -- Size of buffer pch points to
  203. //
  204. //----------------------------------------------------------------------------
  205. HRESULT
  206. CStr::GetMultiByte(LPSTR pch, UINT cch)
  207. {
  208. HRESULT hr = S_OK;
  209. DWORD dwLen = WideCharToMultiByte(CP_ACP,
  210. 0,
  211. _pch,
  212. -1,
  213. pch,
  214. cch,
  215. NULL,
  216. NULL);
  217. if (dwLen == 0)
  218. {
  219. hr = HRESULT_FROM_WIN32(GetLastError());
  220. }
  221. RRETURN(hr);
  222. }
  223. //+---------------------------------------------------------------------------
  224. //
  225. // Member: CStr::Length, public
  226. //
  227. // Synopsis: Returns the length of the string associated with this class
  228. //
  229. //----------------------------------------------------------------------------
  230. UINT
  231. CStr::Length() const
  232. {
  233. if (_pch)
  234. return (((UINT *)_pch) [-1]) / sizeof(TCHAR);
  235. else
  236. return 0;
  237. }
  238. //+---------------------------------------------------------------------------
  239. //
  240. // Member: CStr::ReAlloc, public
  241. //
  242. // Synopsis: Reallocate the string to a different size buffer.
  243. // The length of the string is not affected, but it is allocated
  244. // within a larger (or maybe smaller) memory allocation.
  245. //
  246. //----------------------------------------------------------------------------
  247. HRESULT
  248. CStr::ReAlloc( UINT uc )
  249. {
  250. HRESULT hr;
  251. TCHAR * pchOld;
  252. UINT ubOld;
  253. Assert(uc >= Length()); // Disallowed to allocate a too-short buffer.
  254. if (uc)
  255. {
  256. pchOld = _pch; // Save pointer to old string.
  257. _pch = 0; // Prevent Set from Freeing the string.
  258. ubOld = pchOld ? // Save old length
  259. *(UINT *) (((BYTE *)pchOld) - sizeof(UINT))
  260. : 0;
  261. hr = Set(pchOld, uc); // Alloc new; Copy old string.
  262. if (hr)
  263. {
  264. _pch = pchOld;
  265. RRETURN(hr);
  266. }
  267. *(UINT *)(((BYTE *)_pch) - sizeof(UINT)) = ubOld; // Restore length.
  268. if (pchOld )
  269. {
  270. delete [] (((BYTE *)pchOld) - sizeof(UINT));
  271. }
  272. }
  273. // else if uc == 0, then, since we have already checked that uc >= Length,
  274. // length must == 0.
  275. return S_OK;
  276. }
  277. //+---------------------------------------------------------------------------
  278. //
  279. // Member: CStr::Append
  280. //
  281. // Synopsis: Append chars to the end of the string, reallocating & updating
  282. // its length.
  283. //
  284. //----------------------------------------------------------------------------
  285. HRESULT
  286. CStr::Append(LPCTSTR pch, UINT uc)
  287. {
  288. HRESULT hr = S_OK;
  289. UINT ucOld, ucNew;
  290. BYTE *p;
  291. if (uc)
  292. {
  293. ucOld = Length();
  294. ucNew = ucOld + uc;
  295. hr = ReAlloc(ucNew);
  296. if (hr)
  297. goto Cleanup;
  298. _tcsncpy(_pch + ucOld, pch, uc);
  299. ((TCHAR *)_pch) [ucNew] = 0;
  300. p = ((BYTE*)_pch - sizeof(UINT));
  301. *(UINT *)p = ucNew * sizeof(TCHAR);
  302. }
  303. Cleanup:
  304. RRETURN(hr);
  305. }
  306. HRESULT
  307. CStr::Append(LPCTSTR pch)
  308. {
  309. RRETURN(Append(pch, pch ? _tcsclen(pch) : 0));
  310. }
  311. //+---------------------------------------------------------------------------
  312. //
  313. // Member: CStr::AppendMultiByte, public
  314. //
  315. // Synopsis: Append a multibyte string to the end,
  316. //
  317. //----------------------------------------------------------------------------
  318. HRESULT
  319. CStr::AppendMultiByte(LPCSTR pch)
  320. {
  321. HRESULT hr = S_OK;
  322. UINT ucOld, ucNew, uc;
  323. BYTE *p;
  324. uc = strlen(pch);
  325. if (uc)
  326. {
  327. ucOld = Length();
  328. ucNew = ucOld + uc;
  329. hr = ReAlloc(ucNew);
  330. if (hr)
  331. goto Cleanup;
  332. uc = MultiByteToWideChar(CP_ACP,
  333. 0,
  334. pch,
  335. uc,
  336. _pch + ucOld,
  337. uc + 1);
  338. if (uc == 0)
  339. {
  340. hr = HRESULT_FROM_WIN32(GetLastError());
  341. TraceTag((tagError, "CSTR: Fatal string conversion error %x", hr));
  342. goto Cleanup;
  343. }
  344. ((TCHAR *)_pch) [ucNew] = 0;
  345. p = ((BYTE*)_pch - sizeof(UINT));
  346. *(UINT *)p = ucNew * sizeof(TCHAR);
  347. }
  348. Cleanup:
  349. RRETURN(hr);
  350. }
  351. //+---------------------------------------------------------------------------
  352. //
  353. // Member: CStr::SetLengthNoAlloc, public
  354. //
  355. // Synopsis: Sets the internal length of the string. Note. There is no
  356. // verification that the length that is set is within the allocated
  357. // range of the string. If the caller sets the length too large,
  358. // this blasts a null byte into memory.
  359. //
  360. //----------------------------------------------------------------------------
  361. HRESULT
  362. CStr::SetLengthNoAlloc( UINT uc )
  363. {
  364. if (_pch)
  365. {
  366. BYTE * p = ( (BYTE *)_pch - sizeof(UINT));
  367. *(UINT *)p = uc * sizeof(TCHAR); // Set the length prefix.
  368. ((TCHAR *)_pch) [uc] = 0; // Set null terminator
  369. return S_OK;
  370. }
  371. else
  372. return E_POINTER;
  373. }
  374. //+---------------------------------------------------------------------------
  375. //
  376. // Member: CStr::AllocBSTR, public
  377. //
  378. // Synopsis: Allocates a BSTR and initializes it with the string that is
  379. // associated with this class.
  380. //
  381. // Arguments: [pBSTR] -- Place to put new BSTR. This pointer should not
  382. // be pointing to an existing BSTR.
  383. //
  384. //----------------------------------------------------------------------------
  385. HRESULT
  386. CStr::AllocBSTR(BSTR *pBSTR) const
  387. {
  388. if (!_pch)
  389. {
  390. *pBSTR = 0;
  391. return S_OK;
  392. }
  393. *pBSTR = SysAllocStringLen(*this, Length());
  394. RRETURN(*pBSTR ? S_OK: E_OUTOFMEMORY);
  395. }
  396. //+---------------------------------------------------------------------------
  397. //
  398. // Member: CStr::TrimTrailingWhitespace, public
  399. //
  400. // Synopsis: Removes any trailing whitespace in the string that is
  401. // associated with this class.
  402. //
  403. // Arguments: None.
  404. //
  405. //----------------------------------------------------------------------------
  406. HRESULT CStr::TrimTrailingWhitespace()
  407. {
  408. if (!_pch)
  409. return S_OK;
  410. UINT ucNewLength = Length();
  411. for ( ; ucNewLength > 0; ucNewLength-- )
  412. {
  413. if ( !_istspace( ((TCHAR *)_pch)[ ucNewLength - 1 ] ) )
  414. break;
  415. ((TCHAR *)_pch)[ ucNewLength - 1 ] = (TCHAR) 0;
  416. }
  417. BYTE *p = ((BYTE*)_pch - sizeof(UINT));
  418. *(UINT *)p = ucNewLength * sizeof(TCHAR);
  419. return S_OK;
  420. }
  421. //+---------------------------------------------------------------------------
  422. //
  423. // Member: CStr::_Free, private
  424. //
  425. // Synopsis: Frees any memory held onto by this class.
  426. //
  427. //----------------------------------------------------------------------------
  428. void
  429. CStr::_Free()
  430. {
  431. if (_pch )
  432. {
  433. delete [] (((BYTE *)_pch) - sizeof(UINT));
  434. }
  435. _pch=0;
  436. }
  437. //+---------------------------------------------------------------------------
  438. //
  439. // Member: CStr::Clone
  440. //
  441. // Synopsis: Make copy of current string
  442. //
  443. //----------------------------------------------------------------------------
  444. HRESULT
  445. CStr::Clone(CStr **ppCStr) const
  446. {
  447. HRESULT hr;
  448. Assert(ppCStr);
  449. *ppCStr = new CStr;
  450. hr = *ppCStr?S_OK:E_OUTOFMEMORY;
  451. if (hr)
  452. goto Cleanup;
  453. hr = THR( (*ppCStr)->Set(*this) );
  454. Cleanup:
  455. RRETURN(hr);
  456. }
  457. //+---------------------------------------------------------------------------
  458. //
  459. // Member: CStr::Compare
  460. //
  461. // Synopsis: Case insensitive comparison of 2 strings
  462. //
  463. //----------------------------------------------------------------------------
  464. BOOL
  465. CStr::Compare (const CStr *pCStr) const
  466. {
  467. return (!_tcsicmp(*pCStr, *this));
  468. }
  469. //+---------------------------------------------------------------------------
  470. //
  471. // Member: CStr::ComputeCrc
  472. //
  473. // Synopsis: Computes a hash of the string.
  474. //
  475. //----------------------------------------------------------------------------
  476. #pragma warning(disable:4305)
  477. WORD
  478. CStr::ComputeCrc() const
  479. {
  480. WORD wHash=0;
  481. const TCHAR* pch;
  482. int i;
  483. pch=*this;
  484. for(i = Length();i > 0;i--, pch++)
  485. {
  486. wHash = wHash << 7 ^ wHash >> (16-7) ^ (TCHAR)CharUpper((LPTSTR)((DWORD)(*pch)));
  487. }
  488. return wHash;
  489. }
  490. #pragma warning(default:4305)
  491. //+---------------------------------------------------------------------------
  492. //
  493. // Member: CStr::Load
  494. //
  495. // Synopsis: Initializes the CStr from a stream
  496. //
  497. //----------------------------------------------------------------------------
  498. HRESULT
  499. CStr::Load(IStream * pstm)
  500. {
  501. DWORD cch;
  502. HRESULT hr;
  503. hr = THR(pstm->Read(&cch, sizeof(DWORD), NULL));
  504. if (hr)
  505. goto Cleanup;
  506. if (cch == 0xFFFFFFFF)
  507. {
  508. Free();
  509. }
  510. else
  511. {
  512. hr = THR(Set(NULL, cch));
  513. if (hr)
  514. goto Cleanup;
  515. if (cch)
  516. {
  517. hr = THR(pstm->Read(_pch, cch * sizeof(TCHAR), NULL));
  518. if (hr)
  519. goto Cleanup;
  520. }
  521. }
  522. Cleanup:
  523. RRETURN(hr);
  524. }
  525. //+---------------------------------------------------------------------------
  526. //
  527. // Member: CStr::Save
  528. //
  529. // Synopsis: Writes the contents of the CStr to a stream
  530. //
  531. //----------------------------------------------------------------------------
  532. HRESULT
  533. CStr::Save(IStream * pstm) const
  534. {
  535. DWORD cch = _pch ? Length() : 0xFFFFFFFF;
  536. HRESULT hr;
  537. hr = THR(pstm->Write(&cch, sizeof(DWORD), NULL));
  538. if (hr)
  539. goto Cleanup;
  540. if (cch && cch != 0xFFFFFFFF)
  541. {
  542. hr = THR(pstm->Write(_pch, cch * sizeof(TCHAR), NULL));
  543. if (hr)
  544. goto Cleanup;
  545. }
  546. Cleanup:
  547. RRETURN(hr);
  548. }
  549. //+---------------------------------------------------------------------------
  550. //
  551. // Member: CStr::GetSaveSize
  552. //
  553. // Synopsis: Returns the number of bytes which will be written by
  554. // CStr::Save
  555. //
  556. //----------------------------------------------------------------------------
  557. ULONG
  558. CStr::GetSaveSize() const
  559. {
  560. return(sizeof(DWORD) + (_pch ? (Length() * sizeof(TCHAR)) : 0));
  561. }