Leaked source code of windows server 2003
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.

870 lines
15 KiB

  1. /*++
  2. Copyright (C) 2000 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. string.cxx
  6. Abstract:
  7. String class
  8. Author:
  9. Steve Kiraly (SteveKi) 03-Mar-2000
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include "string.hxx"
  15. //
  16. // Class specific NULL state.
  17. //
  18. TCHAR TString::gszNullState[2] = {0,0};
  19. /*++
  20. Routine Name:
  21. Default constructor
  22. Routine Description:
  23. Initialize the string class to a valid state.
  24. Arguments:
  25. None
  26. Return Value:
  27. None, Use IsValid to determine success or failure.
  28. --*/
  29. TString::
  30. TString(
  31. VOID
  32. ) : m_pszString(&TString::gszNullState[kValid])
  33. {
  34. }
  35. /*++
  36. Routine Name:
  37. Non trivial constructor
  38. Routine Description:
  39. Construction using an existing LPCTSTR string.
  40. Arguments:
  41. psz - pointer to string
  42. Return Value:
  43. None, Use IsValid to determine success or failure.
  44. --*/
  45. TString::
  46. TString(
  47. IN LPCTSTR psz
  48. ) : m_pszString(&TString::gszNullState[kValid])
  49. {
  50. if (FAILED(Update(psz)))
  51. {
  52. m_pszString = &TString::gszNullState[kInValid];
  53. }
  54. }
  55. /*++
  56. Routine Name:
  57. Copy constructor.
  58. Routine Description:
  59. Creates a copy of a string from another string object
  60. Arguments:
  61. String - refrence to existing string
  62. Return Value:
  63. None, Use IsValid to determine success or failure.
  64. --*/
  65. TString::
  66. TString(
  67. IN const TString &String
  68. ) : m_pszString(&TString::gszNullState[kValid])
  69. {
  70. if (FAILED(Update(String.m_pszString)))
  71. {
  72. m_pszString = &TString::gszNullState[kInValid];
  73. }
  74. }
  75. /*++
  76. Routine Name:
  77. Destructor
  78. Routine Description:
  79. Destruction, ensure we don't free our NULL state.
  80. Arguments:
  81. None.
  82. Return Value:
  83. None.
  84. --*/
  85. TString::
  86. ~TString(
  87. VOID
  88. )
  89. {
  90. vFree(m_pszString);
  91. }
  92. /*++
  93. Routine Name:
  94. bEmpty
  95. Routine Description:
  96. Indicates if a string has any usable data.
  97. Arguments:
  98. None.
  99. Return Value:
  100. TRUE string has data, FALSE string has no data.
  101. --*/
  102. BOOL
  103. TString::
  104. bEmpty(
  105. VOID
  106. ) const
  107. {
  108. return m_pszString[0] == 0;
  109. }
  110. /*++
  111. Routine Name:
  112. IsValid
  113. Routine Description:
  114. Indicates if a string object is valid.
  115. Arguments:
  116. None.
  117. Return Value:
  118. An HRESULT
  119. --*/
  120. HRESULT
  121. TString::
  122. IsValid(
  123. VOID
  124. ) const
  125. {
  126. return m_pszString != &TString::gszNullState[kInValid] ? S_OK : E_OUTOFMEMORY;
  127. }
  128. /*++
  129. Routine Name:
  130. uLen
  131. Routine Description:
  132. Return the length of the string in characters not including
  133. the NULL terminator.
  134. Arguments:
  135. None.
  136. Return Value:
  137. Length of the string in characters not including the NULL terminator.
  138. --*/
  139. UINT
  140. TString::
  141. uLen(
  142. VOID
  143. ) const
  144. {
  145. return _tcslen(m_pszString);
  146. }
  147. /*++
  148. Routine Name:
  149. Cat
  150. Routine Description:
  151. Safe concatenation of the specified string to the string
  152. object. If the allocation fails this routine will return a
  153. failure and the orginal string will be un touched. If the
  154. passed in string pointer is null or the passed in string
  155. points to the null string the function succeeds and does
  156. not update the string.
  157. Arguments:
  158. psz - Input string, may be NULL.
  159. Return Value:
  160. An HRESULT
  161. --*/
  162. HRESULT
  163. TString::
  164. Cat(
  165. IN LPCTSTR psz
  166. )
  167. {
  168. HRESULT hStatus = S_OK;
  169. size_t cchSize = 0;
  170. LPTSTR pszDst = NULL;
  171. LPTSTR pszTmp = NULL;
  172. size_t cchRemaining = 0;
  173. //
  174. // Silently ignore a null string pointer or the empty string.
  175. //
  176. if (psz && *psz)
  177. {
  178. //
  179. // Calculate new buffer size consisting of the size of the orginal
  180. // string plus the sizeof of the new string plus the null terminator.
  181. //
  182. cchSize = _tcslen(m_pszString) + _tcslen(psz) + 1;
  183. //
  184. // Allocate the new buffer.
  185. //
  186. pszTmp = new TCHAR[cchSize];
  187. //
  188. // If memory was not available.
  189. //
  190. hStatus = pszTmp ? S_OK : E_OUTOFMEMORY;
  191. //
  192. // Copy the current string to the temp buffer.
  193. //
  194. if (SUCCEEDED(hStatus))
  195. {
  196. hStatus = StringCchCopyEx(pszTmp, cchSize, m_pszString, &pszDst, &cchRemaining, 0);
  197. }
  198. //
  199. // Concatenate the new string on the end of the temp buffer.
  200. //
  201. if (SUCCEEDED(hStatus))
  202. {
  203. hStatus = StringCchCopy(pszDst, cchRemaining, psz);
  204. }
  205. //
  206. // Release the current string buffer and assign the new concatenated
  207. // string to the internal string pointer.
  208. //
  209. if (SUCCEEDED(hStatus))
  210. {
  211. vFree(m_pszString);
  212. m_pszString = pszTmp;
  213. pszTmp = NULL;
  214. }
  215. vFree(pszTmp);
  216. }
  217. return hStatus;
  218. }
  219. /*++
  220. Routine Name:
  221. Update
  222. Routine Description:
  223. Safe updating of string. If the allocation fails, return FALSE
  224. and it leaves the original string untouched. If the new string is
  225. NULL the current string is released and the class is put into a
  226. valid state.
  227. Arguments:
  228. psz - Input string, may be NULL.
  229. Return Value:
  230. An HRESULT
  231. --*/
  232. HRESULT
  233. TString::
  234. Update(
  235. IN LPCTSTR psz
  236. )
  237. {
  238. HRESULT hRetval = S_OK;
  239. LPTSTR pszTmp = NULL;
  240. size_t cchSize = 0;
  241. //
  242. // Validate the passed in pointer.
  243. //
  244. if (psz)
  245. {
  246. //
  247. // Calculate the new string size including the null terminator.
  248. //
  249. cchSize = _tcslen(psz) + 1;
  250. //
  251. // Create temp pointer and allocate the new string.
  252. //
  253. pszTmp = new TCHAR [cchSize];
  254. hRetval = pszTmp ? S_OK : E_OUTOFMEMORY;
  255. //
  256. // Copy the string
  257. //
  258. if (SUCCEEDED(hRetval))
  259. {
  260. hRetval = StringCchCopy(pszTmp, cchSize, psz);
  261. }
  262. //
  263. // Release the old string and save the new string in the class pointer.
  264. //
  265. if (SUCCEEDED(hRetval))
  266. {
  267. vFree(m_pszString);
  268. m_pszString = pszTmp;
  269. pszTmp = NULL;
  270. }
  271. vFree(pszTmp);
  272. }
  273. else
  274. {
  275. //
  276. // Release the current string.
  277. //
  278. vFree(m_pszString);
  279. //
  280. // Mark the object as valid.
  281. //
  282. m_pszString = &TString::gszNullState[kValid];
  283. }
  284. return hRetval;
  285. }
  286. /*++
  287. Routine Name:
  288. LoadStringFromRC
  289. Routine Description:
  290. Safe load of a string from a resources file.
  291. Arguments:
  292. hInst - Instance handle of resource file.
  293. uId - Resource id to load.
  294. Return Value:
  295. An HRESULT
  296. --*/
  297. HRESULT
  298. TString::
  299. LoadStringFromRC(
  300. IN HINSTANCE hInst,
  301. IN UINT uID
  302. )
  303. {
  304. LPTSTR pszString = NULL;
  305. INT iSize = 0;
  306. INT iLen = 0;
  307. HRESULT hResult = E_FAIL;
  308. //
  309. // Continue increasing the buffer until
  310. // the buffer is big enough to hold the entire string.
  311. //
  312. for (iSize = kStrMax; ; iSize += kStrMax)
  313. {
  314. //
  315. // Allocate string buffer.
  316. //
  317. pszString = new TCHAR [iSize];
  318. if (pszString)
  319. {
  320. iLen = ::LoadString(hInst, uID, pszString, iSize);
  321. if(iLen == 0)
  322. {
  323. delete [] pszString;
  324. hResult = E_FAIL;
  325. break;
  326. }
  327. //
  328. // Since LoadString does not indicate if the string was truncated or it
  329. // just happened to fit. When we detect this ambiguous case we will
  330. // try one more time just to be sure.
  331. //
  332. else if (iSize - iLen <= 1)
  333. {
  334. delete [] pszString;
  335. }
  336. //
  337. // LoadString was successful release original string buffer
  338. // and update new buffer pointer.
  339. //
  340. else
  341. {
  342. vFree(m_pszString);
  343. m_pszString = pszString;
  344. hResult = S_OK;
  345. break;
  346. }
  347. }
  348. else
  349. {
  350. hResult = E_OUTOFMEMORY;
  351. break;
  352. }
  353. }
  354. return hResult;
  355. }
  356. /*++
  357. Routine Name:
  358. vFree
  359. Routine Description:
  360. Safe free, frees the string memory. Ensures
  361. we do not try an free our global memory block.
  362. Arguments:
  363. pszString - pointer to string meory to free.
  364. Return Value:
  365. Nothing.
  366. --*/
  367. VOID
  368. TString::
  369. vFree(
  370. IN LPTSTR pszString
  371. )
  372. {
  373. //
  374. // If this memory was not pointing to our
  375. // class specific gszNullStates then release the memory.
  376. //
  377. if (pszString != &TString::gszNullState[kValid] &&
  378. pszString != &TString::gszNullState[kInValid])
  379. {
  380. delete [] pszString;
  381. }
  382. }
  383. /*++
  384. Routine Name:
  385. Format
  386. Routine Description:
  387. Format the string opbject similar to sprintf.
  388. Arguments:
  389. pszFmt - pointer format string.
  390. .. - variable number of arguments similar to sprintf.
  391. Return Value:
  392. An HRESULT S_OK if string was format successfully. E_XXX if error
  393. occurred creating the format string.
  394. --*/
  395. HRESULT
  396. WINAPIV
  397. TString::
  398. Format(
  399. IN LPCTSTR pszFmt,
  400. IN ...
  401. )
  402. {
  403. HRESULT hStatus = E_FAIL;
  404. va_list pArgs;
  405. va_start(pArgs, pszFmt);
  406. hStatus = vFormat(pszFmt, pArgs);
  407. va_end(pArgs);
  408. return hStatus;
  409. }
  410. /*++
  411. Routine Name:
  412. vFormat
  413. Routine Description:
  414. Format the string opbject similar to vsprintf.
  415. Arguments:
  416. pszFmt pointer format string.
  417. pointer to variable number of arguments similar to vsprintf.
  418. Return Value:
  419. An HRESULT - S_OK if string was format successfully. E_XXX if error
  420. occurred creating the format string.
  421. --*/
  422. HRESULT
  423. TString::
  424. vFormat(
  425. IN LPCTSTR pszFmt,
  426. IN va_list avlist
  427. )
  428. {
  429. //
  430. // Format the string.
  431. //
  432. LPTSTR pszTemp = vsntprintf(pszFmt, avlist);
  433. //
  434. // If format succeeded, release the old string and save the
  435. // new formated string.
  436. //
  437. HRESULT hStatus = pszTemp ? S_OK : E_OUTOFMEMORY;
  438. if (SUCCEEDED(hStatus))
  439. {
  440. //
  441. // Release the old string.
  442. //
  443. vFree(m_pszString);
  444. //
  445. // Save pointer to new string.
  446. //
  447. m_pszString = pszTemp;
  448. }
  449. return hStatus;
  450. }
  451. /*++
  452. Routine Name:
  453. vsntprintf
  454. Routine Description:
  455. //
  456. // Formats a string and returns a heap allocated string with the
  457. // formated data. This routine can be used to for extremely
  458. // long format strings. Note: If a valid pointer is returned
  459. // the callng functions must release the data with a call to delete.
  460. // Example:
  461. //
  462. // LPCTSTR p = vsntprintf("Test %s", pString );
  463. //
  464. // SetTitle( p );
  465. //
  466. // delete [] p;
  467. //
  468. Arguments:
  469. pszString pointer format string.
  470. pointer to a variable number of arguments.
  471. Return Value:
  472. Pointer to format string. NULL if error.
  473. --*/
  474. LPTSTR
  475. TString::
  476. vsntprintf(
  477. IN LPCTSTR szFmt,
  478. IN va_list pArgs
  479. )
  480. {
  481. LPTSTR pszBuff = NULL;
  482. INT iSize = kStrIncrement;
  483. for( ; ; )
  484. {
  485. //
  486. // Allocate the message buffer.
  487. //
  488. pszBuff = new TCHAR [iSize];
  489. if (!pszBuff)
  490. {
  491. break;
  492. }
  493. //
  494. // If the string was formatted then exit.
  495. //
  496. if (SUCCEEDED(StringCchVPrintf(pszBuff, iSize, szFmt, pArgs)))
  497. {
  498. break;
  499. }
  500. //
  501. // String did not fit release the current buffer.
  502. //
  503. if (pszBuff)
  504. {
  505. delete [] pszBuff;
  506. }
  507. //
  508. // Double the buffer size after each failure.
  509. //
  510. iSize *= 2;
  511. //
  512. // If the size is greater than 100k exit without formatting a string.
  513. //
  514. if (iSize > kStrMaxFormatSize)
  515. {
  516. pszBuff = NULL;
  517. break;
  518. }
  519. }
  520. return pszBuff;
  521. }
  522. /*++
  523. Routine Name:
  524. FormatMsg
  525. Routine Description:
  526. This function formats a message string using the windows
  527. api FormatMessage, hence it will deal with the %1 %2 insertion
  528. specifiers.
  529. Arguments:
  530. pszFmt - Pointer to format string, see the SDK under FormatMessage for
  531. all possible format specifiers.
  532. .. - variable number of arguments
  533. Return Value:
  534. An HRESULT
  535. --*/
  536. HRESULT
  537. WINAPIV
  538. TString::
  539. FormatMsg(
  540. IN LPCTSTR pszFmt,
  541. IN ...
  542. )
  543. {
  544. LPTSTR pszRet = NULL;
  545. DWORD dwBytes = 0;
  546. HRESULT hRetval = E_FAIL;
  547. va_list pArgs;
  548. //
  549. // Point to the first un-named argument.
  550. //
  551. va_start(pArgs, pszFmt);
  552. //
  553. // Format the message.
  554. //
  555. dwBytes = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  556. pszFmt,
  557. 0,
  558. 0,
  559. reinterpret_cast<LPWSTR>(&pszRet),
  560. 0,
  561. &pArgs);
  562. va_end(pArgs);
  563. //
  564. // If the number of bytes is non zero the API formatted the
  565. // string.
  566. //
  567. if (dwBytes)
  568. {
  569. //
  570. // Update the return string object.
  571. //
  572. hRetval = Update(pszRet);
  573. //
  574. // Release the formated string.
  575. //
  576. if (pszRet)
  577. {
  578. LocalFree(pszRet);
  579. }
  580. }
  581. else
  582. {
  583. hRetval = HRESULT_FROM_WIN32(GetLastError());
  584. }
  585. return hRetval;
  586. }
  587. /*++
  588. Routine Name:
  589. ToUpper
  590. Routine Description:
  591. modifies the current string to be all uppercase
  592. Arguments:
  593. none
  594. Return Value:
  595. none
  596. --*/
  597. VOID
  598. TString::
  599. ToUpper(
  600. VOID
  601. )
  602. {
  603. if (m_pszString != &TString::gszNullState[kValid] &&
  604. m_pszString != &TString::gszNullState[kInValid])
  605. {
  606. UINT Len = _tcslen(m_pszString);
  607. for (UINT i = 0; i < Len; i++)
  608. {
  609. m_pszString[i] = towupper(m_pszString[i]);
  610. }
  611. }
  612. }
  613. /*++
  614. Routine Name:
  615. ToLower
  616. Routine Description:
  617. modifies the current string to be all lowercase
  618. Arguments:
  619. none
  620. Return Value:
  621. none
  622. --*/
  623. VOID
  624. TString::
  625. ToLower(
  626. VOID
  627. )
  628. {
  629. if (m_pszString != &TString::gszNullState[kValid] &&
  630. m_pszString != &TString::gszNullState[kInValid])
  631. {
  632. UINT Len = _tcslen(m_pszString);
  633. for (UINT i = 0; i < Len; i++)
  634. {
  635. m_pszString[i] = towlower(m_pszString[i]);
  636. }
  637. }
  638. }