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.

1619 lines
32 KiB

  1. /*++
  2. Copyright (c) 1989-2001 Microsoft Corporation
  3. Module Name:
  4. CSTRING.cpp
  5. Abstract:
  6. The code for the CSTRING and the CSTRINGLIST
  7. Author:
  8. kinshu created December 12, 2001
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. ///////////////////////////////////////////////////////////////////////////////
  13. //
  14. // The string class
  15. //
  16. //
  17. CSTRING::CSTRING()
  18. /*++
  19. CSTRING::CSTRING()
  20. Desc: Constructor
  21. --*/
  22. {
  23. Init();
  24. }
  25. CSTRING::CSTRING(CSTRING& Str)
  26. /*++
  27. CSTRING::CSTRING(CSTRING& Str)
  28. Desc: Constructor
  29. Params:
  30. CSTRING& Str: Another string.
  31. --*/
  32. {
  33. Init();
  34. SetString(Str.pszString);
  35. }
  36. CSTRING::CSTRING(IN LPCTSTR szString)
  37. /*++
  38. CSTRING::CSTRING(IN LPCTSTR szString)
  39. Desc: Constructor
  40. Params:
  41. IN LPCTSTR szString: The CSTRING should have this as its value
  42. --*/
  43. {
  44. Init();
  45. SetString(szString);
  46. }
  47. CSTRING::CSTRING(IN UINT uID)
  48. /*++
  49. CSTRING::CSTRING(IN UINT uID)
  50. Desc: Constructor. Loads the string resource with resource id uID
  51. and sets that to this string
  52. Params:
  53. IN UINT uID: The resource id for the string that we want to load
  54. --*/
  55. {
  56. Init();
  57. SetString(uID);
  58. }
  59. CSTRING::~CSTRING()
  60. /*++
  61. CSTRING::~CSTRING()
  62. Desc: Destructor
  63. --*/
  64. {
  65. Release();
  66. }
  67. void
  68. CSTRING::Init(
  69. void
  70. )
  71. /*++
  72. CSTRING::Init
  73. Desc: Does some initialisation stuff
  74. --*/
  75. {
  76. pszString = NULL;
  77. pszANSI = NULL;
  78. }
  79. inline void
  80. CSTRING::Release(
  81. void
  82. )
  83. /*++
  84. CSTRING::Release
  85. Desc: Frees the data associated with this string
  86. --*/
  87. {
  88. if (NULL != pszString) {
  89. delete[] pszString;
  90. }
  91. if (NULL != pszANSI) {
  92. delete[] pszANSI;
  93. }
  94. pszString = NULL;
  95. pszANSI = NULL;
  96. }
  97. inline BOOL
  98. CSTRING::SetString(
  99. IN UINT uID
  100. )
  101. /*++
  102. Desc: Loads the string resource with resource id uId
  103. and sets that to this string
  104. Params:
  105. IN UINT uID: The resource id for the string that we want to load
  106. Return:
  107. TRUE: String value set successfully
  108. FALSE: Otherwise
  109. --*/
  110. {
  111. TCHAR szString[1024];
  112. if (0 != LoadString(GetModuleHandle(NULL), uID, szString, ARRAYSIZE(szString))) {
  113. return SetString(szString);
  114. }
  115. return FALSE;
  116. }
  117. inline BOOL
  118. CSTRING::SetString(
  119. IN LPCTSTR pszStringIn
  120. )
  121. /*++
  122. CSTRING::SetString
  123. Desc: Frees the current data for this string and assigns a new string
  124. value to it
  125. Params:
  126. IN LPCTSTR pszStringIn: Pointer to the new string
  127. Return:
  128. TRUE: Successful
  129. FALSE: Otherwise
  130. --*/
  131. {
  132. UINT uLen = 0;
  133. if (pszString == pszStringIn) {
  134. return TRUE;
  135. }
  136. Release();
  137. if (NULL == pszStringIn) {
  138. return TRUE;
  139. }
  140. uLen = lstrlen(pszStringIn) + 1;
  141. try {
  142. pszString = new TCHAR[uLen];
  143. } catch(...) {
  144. pszString = NULL;
  145. }
  146. if (NULL != pszString) {
  147. SafeCpyN(pszString, pszStringIn, uLen);
  148. } else {
  149. MEM_ERR;
  150. return FALSE;
  151. }
  152. return TRUE;
  153. }
  154. void __cdecl
  155. CSTRING::Sprintf(
  156. IN LPCTSTR szFormat, ...
  157. )
  158. /*++
  159. CSTRING::Sprintf
  160. Desc: Please see _vsntprintf
  161. Params: Please see _vsntprintf
  162. Return:
  163. void
  164. --*/
  165. {
  166. K_SIZE k_pszTemp = MAX_STRING_SIZE;
  167. PTSTR pszTemp = new TCHAR[k_pszTemp];
  168. INT cch = 0;
  169. va_list list;
  170. HRESULT hr;
  171. if (pszTemp == NULL) {
  172. MEM_ERR;
  173. goto End;
  174. }
  175. if (szFormat == NULL) {
  176. ASSERT(FALSE);
  177. goto End;
  178. }
  179. va_start(list, szFormat);
  180. hr = StringCchVPrintf(pszTemp, k_pszTemp, szFormat, list);
  181. if (hr != S_OK) {
  182. DBGPRINT((sdlError,("CSTRING::Sprintf"), ("%s"), TEXT("Too long for StringCchVPrintf()")));
  183. goto End;
  184. }
  185. pszTemp[k_pszTemp - 1] = 0;
  186. SetString(pszTemp);
  187. End:
  188. if (pszTemp) {
  189. delete[] pszTemp;
  190. pszTemp = NULL;
  191. }
  192. }
  193. UINT
  194. CSTRING::Trim(
  195. void
  196. )
  197. /*++
  198. CSTRING::Trim
  199. Desc: Removes white spaces tabs from the left and right of this string
  200. Params:
  201. void
  202. Return:
  203. The length of the final string
  204. --*/
  205. {
  206. CSTRING szTemp = *this;
  207. UINT uOrig_length = Length();
  208. WCHAR* pStart = szTemp.pszString;
  209. WCHAR* pEnd = szTemp.pszString + uOrig_length - 1;
  210. UINT nLength = 0;
  211. if (pStart == NULL) {
  212. nLength = 0;
  213. goto End;
  214. }
  215. while (*pStart == TEXT(' ') || *pStart == TEXT('\t')) {
  216. ++pStart;
  217. }
  218. while ((pEnd >= pStart) && (*pEnd == TEXT(' ') || *pEnd == TEXT('\t'))) {
  219. --pEnd;
  220. }
  221. *(pEnd + 1) = TEXT('\0');
  222. nLength = pEnd - pStart + 1;
  223. //
  224. // If no trimming has been done, return right away
  225. //
  226. if (uOrig_length == nLength || pStart == szTemp.pszString) {
  227. return nLength;
  228. }
  229. SetString(pStart);
  230. End:
  231. return(nLength);
  232. }
  233. BOOL
  234. CSTRING::SetChar(
  235. IN int nPos,
  236. IN TCHAR chValue
  237. )
  238. /*++
  239. CSTRING::SetChar
  240. Desc: Sets the character at position nPos of the string to chValue
  241. Pos is 0 based
  242. Params:
  243. IN int nPos: The position
  244. IN TCHAR chValue: The new value
  245. Return:
  246. TRUE: Successful
  247. FALSE: Otherwise
  248. --*/
  249. {
  250. int length = Length();
  251. if (nPos >= length || nPos < 0 || length <= 0) {
  252. return FALSE;
  253. }
  254. pszString[nPos] = chValue;
  255. return TRUE;
  256. }
  257. BOOL
  258. CSTRING::GetChar(
  259. IN int nPos,
  260. OUT TCHAR* pchReturn
  261. )
  262. /*++
  263. CSTRING::GetChar
  264. Desc: Gets the character at position nPos in the string
  265. Params:
  266. IN int nPos: The position of the character
  267. OUT TCHAR* pchReturn: This will store the character
  268. Return:
  269. void
  270. --*/
  271. {
  272. int length = Length();
  273. if (nPos >= length || length <= 0 || pchReturn == NULL) {
  274. return FALSE;
  275. }
  276. *pchReturn = pszString[nPos];
  277. return TRUE;
  278. }
  279. CSTRING
  280. CSTRING::SpecialCharToXML(
  281. IN BOOL bApphelpMessage
  282. )
  283. /*++
  284. CSTRING::SpecialCharToXML
  285. Desc: Substitutes the special chars such as & with the correct XML string
  286. Please note that this function returns a new string and DOES NOT
  287. modify the existing string
  288. Params:
  289. IN BOOL bApphelpMessage: Whether this is an apphelp message. For apphelp messages
  290. we should NOT check for <, > but check for &, "
  291. Return:
  292. The new string if we made some changes, otherwise the present string
  293. --*/
  294. {
  295. TCHAR* pszBuffer = NULL;
  296. TCHAR* pszIndex = pszString;
  297. TCHAR* pszIndexBuffer = NULL;
  298. BOOL bFound = FALSE;
  299. CSTRING strTemp;
  300. INT iRemainingsize;
  301. INT iBuffSize = 0;
  302. strTemp = GetString(IDS_UNKNOWN);
  303. //
  304. // Some vendor names might be NULL.
  305. //
  306. if (pszString == NULL) {
  307. return strTemp;
  308. }
  309. iBuffSize = max((Length() + 1) * sizeof(TCHAR) * 2, MAX_STRING_SIZE); // 2 at the end because some special chars may need to be expanded
  310. pszBuffer = new TCHAR[iBuffSize];
  311. if (pszBuffer == NULL) {
  312. MEM_ERR;
  313. return *this;
  314. }
  315. pszIndexBuffer = pszBuffer;
  316. iRemainingsize = iBuffSize / sizeof(TCHAR);
  317. INT iCount = sizeof(g_rgSpecialCharMap) / sizeof(g_rgSpecialCharMap[0]);
  318. while (*pszIndex) {
  319. INT iArrayIndex = 0;
  320. for (iArrayIndex = 0; iArrayIndex < iCount; ++iArrayIndex) {
  321. if (bApphelpMessage && (*pszIndex == TEXT('>') || *pszIndex == TEXT('<'))) {
  322. //
  323. // Apphelp messages can have <P/> and <BR/>, so we should not change them
  324. //
  325. continue;
  326. }
  327. if (g_rgSpecialCharMap[iArrayIndex][0].szString[0] == *pszIndex) {
  328. bFound = TRUE;
  329. SafeCpyN(pszIndexBuffer, g_rgSpecialCharMap[iArrayIndex][1].szString, iRemainingsize);
  330. iRemainingsize = iRemainingsize - g_rgSpecialCharMap[iArrayIndex][1].iLength;
  331. if (iRemainingsize <= 1) {
  332. //
  333. // No space in buffer now
  334. //
  335. //
  336. // If we did not manage to copy the entire substring, make sure that we do not copy a part. This will
  337. // be an invalid XML
  338. //
  339. *pszIndexBuffer = 0;
  340. goto End;
  341. }
  342. pszIndexBuffer += g_rgSpecialCharMap[iArrayIndex][1].iLength;
  343. break;
  344. }
  345. }
  346. if (iArrayIndex == iCount) {
  347. //
  348. // This is not a special char
  349. //
  350. *pszIndexBuffer = *pszIndex;
  351. iRemainingsize = iRemainingsize - 1;
  352. if (iRemainingsize <= 1) {
  353. //
  354. // No space in buffer now
  355. //
  356. //
  357. // Point to the end of the buffer, we will be nulling it at the end
  358. //
  359. pszIndexBuffer = pszBuffer + (iBuffSize / sizeof(TCHAR)) - 1;
  360. goto End;
  361. }
  362. ++pszIndexBuffer;
  363. }
  364. pszIndex++;
  365. }
  366. End:
  367. if (pszIndexBuffer) {
  368. *pszIndexBuffer = 0;
  369. }
  370. if (bFound) {
  371. //
  372. // Some special chars were found
  373. //
  374. strTemp = pszBuffer;
  375. if (pszBuffer) {
  376. delete[] pszBuffer;
  377. pszBuffer = NULL;
  378. }
  379. return strTemp;
  380. }
  381. //
  382. // Free the allocated buffer
  383. //
  384. if (pszBuffer) {
  385. delete[] pszBuffer;
  386. pszBuffer = NULL;
  387. }
  388. return *this;
  389. }
  390. TCHAR*
  391. CSTRING::XMLToSpecialChar(
  392. void
  393. )
  394. /*++
  395. CSTRING::XMLToSpecialChar
  396. Desc: Substitutes the strings such as &amp; with the normals characters such as &
  397. Please note that this function DOES modify the existing string
  398. Params:
  399. void
  400. Return:
  401. The pointer to the pszString member of this string
  402. --*/
  403. {
  404. if (pszString == NULL) {
  405. assert(FALSE);
  406. Dbg(dlError, "CSTRING::XMLToSpecialChar - Invalid value of memeber pszString");
  407. return NULL;
  408. }
  409. TCHAR* pszBuffer = NULL;
  410. TCHAR* pszIndex = pszString;
  411. TCHAR* pszEnd = pszString + Length() - 1;
  412. TCHAR* pszIndexBuffer = NULL;
  413. BOOL bFound = FALSE;
  414. INT iRemainingsize;
  415. INT iBuffSize = 0;
  416. iBuffSize = (Length() + 1) * sizeof(TCHAR);
  417. pszBuffer = new TCHAR[iBuffSize];
  418. if (pszBuffer == NULL) {
  419. MEM_ERR;
  420. return *this;
  421. }
  422. pszIndexBuffer = pszBuffer;
  423. iRemainingsize = iBuffSize / sizeof(TCHAR);
  424. const INT iCount = sizeof(g_rgSpecialCharMap) / sizeof(g_rgSpecialCharMap[0]);
  425. while (*pszIndex) {
  426. INT iArrayIndex = 0;
  427. for (iArrayIndex = 0; iArrayIndex < iCount; ++iArrayIndex) {
  428. if (pszIndex + g_rgSpecialCharMap[iArrayIndex][1].iLength > pszEnd) {
  429. continue;
  430. }
  431. if (StrCmpNI(pszIndex,
  432. g_rgSpecialCharMap[iArrayIndex][1].szString,
  433. g_rgSpecialCharMap[iArrayIndex][1].iLength) == 0) {
  434. bFound = TRUE;
  435. SafeCpyN(pszIndexBuffer, g_rgSpecialCharMap[iArrayIndex][0].szString, iRemainingsize);
  436. iRemainingsize = iRemainingsize - g_rgSpecialCharMap[iArrayIndex][0].iLength;
  437. if (iRemainingsize <= 1) {
  438. //
  439. // No space in buffer now
  440. //
  441. //
  442. // Point to the end of the buffer, we will be nulling it at the end
  443. //
  444. pszIndexBuffer = pszBuffer + (iBuffSize / sizeof(TCHAR)) - 1;
  445. goto End;
  446. }
  447. pszIndexBuffer += g_rgSpecialCharMap[iArrayIndex][0].iLength;
  448. pszIndex += g_rgSpecialCharMap[iArrayIndex][1].iLength;
  449. break;
  450. }
  451. }
  452. if (iArrayIndex == iCount) {
  453. //
  454. // This is not XML for any special char
  455. //
  456. *pszIndexBuffer = *pszIndex++;
  457. iRemainingsize = iRemainingsize - 1;
  458. if (iRemainingsize <= 1) {
  459. //
  460. // No space in buffer now
  461. //
  462. //
  463. // Point to the end of the buffer, we will be nulling it at the end
  464. //
  465. pszIndexBuffer = pszBuffer + (iBuffSize / sizeof(TCHAR)) - 1;
  466. goto End;
  467. }
  468. ++pszIndexBuffer;
  469. }
  470. }
  471. End:
  472. if (pszIndexBuffer) {
  473. *pszIndexBuffer = 0;
  474. }
  475. if (bFound) {
  476. *this = pszBuffer;
  477. }
  478. //
  479. // Free the allocated buffer
  480. //
  481. if (pszBuffer) {
  482. delete[] pszBuffer;
  483. pszBuffer = NULL;
  484. }
  485. return this->pszString;
  486. }
  487. BOOL
  488. CSTRING::BeginsWith(
  489. IN LPCTSTR pszPrefix
  490. )
  491. /*++
  492. CSTRING::BeginsWith
  493. Desc: Checks if the string begins with a prefix
  494. Comparison is case insensitive
  495. Params:
  496. IN LPCTSTR pszPrefix: The prefix that we want to check for
  497. Return:
  498. TRUE: The string begins with the prefix
  499. FALSE: Otherwise
  500. --*/
  501. {
  502. if (StrStrI(this->pszString, pszPrefix) == this->pszString) {
  503. return TRUE;
  504. }
  505. return FALSE;
  506. }
  507. BOOL
  508. CSTRING::EndsWith(
  509. IN LPCTSTR pszPrefix
  510. )
  511. /*++
  512. CSTRING::EndsWith
  513. Desc: Checks if the string ends with some suffix
  514. Params:
  515. IN LPCTSTR pszPrefix: The suffix that we want to check for
  516. Return:
  517. TRUE: The string ends with the suffix
  518. FALSE: Otherwise
  519. --*/
  520. {
  521. return EndsWith(pszString, pszPrefix);
  522. }
  523. BOOL
  524. CSTRING::EndsWith(
  525. IN LPCTSTR pszString,
  526. IN LPCTSTR pszSuffix
  527. )
  528. /*++
  529. CSTRING::EndsWith
  530. Desc: Checks if the string ends with some suffix
  531. Params:
  532. IN LPCTSTR pszString: The string for which we want to make this check
  533. IN LPCTSTR pszSuffix: The suffix that we want to check for
  534. Return:
  535. TRUE: The string ends with the suffix
  536. FALSE: Otherwise
  537. --*/
  538. {
  539. INT iLengthStr = lstrlen(pszString);
  540. INT iLengthSuffix = lstrlen(pszSuffix);
  541. if (iLengthSuffix > iLengthStr) {
  542. return FALSE;
  543. }
  544. return((lstrcmpi(pszString + (iLengthStr - iLengthSuffix), pszSuffix) == 0) ? TRUE: FALSE);
  545. }
  546. LPCTSTR
  547. CSTRING::Strcat(
  548. IN CSTRING& szStr
  549. )
  550. /*++
  551. CSTRING::Strcat
  552. Desc: String concatenations
  553. Params:
  554. IN CSTRING& szStr: The string to concatenate
  555. Return:
  556. The resultant string
  557. --*/
  558. {
  559. return Strcat((LPCTSTR)szStr);
  560. }
  561. LPCTSTR
  562. CSTRING::Strcat(
  563. IN LPCTSTR pString
  564. )
  565. /*++
  566. CSTRING::Strcat
  567. Desc: String concatenations
  568. Params:
  569. IN CSTRING& szStr: The string to concatenate
  570. Return:
  571. The resultant string
  572. --*/
  573. {
  574. if (pString == NULL) {
  575. return pszString;
  576. }
  577. int nLengthCat = lstrlen(pString);
  578. int nLengthStr = Length();
  579. TCHAR *szTemp = new TCHAR [nLengthStr + nLengthCat + 1];
  580. if (szTemp == NULL) {
  581. MEM_ERR;
  582. return NULL;
  583. }
  584. szTemp[0] = 0;
  585. //
  586. // Copy only if pszString != NULL. Otherwise we will get mem exception/garbage value
  587. //
  588. if (nLengthStr) {
  589. SafeCpyN(szTemp, pszString, nLengthStr + 1);
  590. }
  591. SafeCpyN(szTemp + nLengthStr, pString, nLengthCat + 1);
  592. szTemp[nLengthStr + nLengthCat] = TEXT('\0');
  593. Release();
  594. pszString = szTemp;
  595. return pszString;
  596. }
  597. BOOL
  598. CSTRING::isNULL(
  599. void
  600. )
  601. /*++
  602. CSTRING::isNULL
  603. Desc: Checks if the pszString parameter is NULL
  604. Params:
  605. void
  606. Return:
  607. TRUE: The pszString parameter is NULL
  608. FALSE: Otherwise
  609. --*/
  610. {
  611. return(this->pszString == NULL);
  612. }
  613. inline int
  614. CSTRING::Length(
  615. void
  616. )
  617. /*++
  618. CSTRING::Length
  619. Desc: Gets the length of the string in TCHARS
  620. Params:
  621. void
  622. Return:
  623. The length of the string in TCHARS
  624. --*/
  625. {
  626. if (NULL == pszString) {
  627. return 0;
  628. }
  629. return lstrlen(pszString);
  630. }
  631. CSTRING&
  632. CSTRING::ShortFilename(
  633. void
  634. )
  635. /*++
  636. CSTRING::ShortFilename
  637. Desc: Gets the filename and the exe part from a path
  638. Modifies the string
  639. Params:
  640. void
  641. Return:
  642. Filename and the exe part of the path
  643. --*/
  644. {
  645. TCHAR szTemp[MAX_PATH_BUFFSIZE];
  646. LPTSTR pszHold = NULL;
  647. if (pszString == NULL) {
  648. goto End;
  649. }
  650. *szTemp = 0;
  651. SafeCpyN(szTemp, pszString, ARRAYSIZE(szTemp));
  652. LPTSTR szWalk = szTemp;
  653. pszHold = szWalk;
  654. while (0 != *szWalk) {
  655. if (TEXT('\\') == *szWalk) {
  656. pszHold = szWalk + 1;
  657. }
  658. ++szWalk;
  659. }
  660. SetString(pszHold);
  661. End:
  662. return *this;
  663. }
  664. BOOL
  665. CSTRING::RelativeFile(
  666. CSTRING& szPath
  667. )
  668. /*++
  669. CSTRING::RelativeFile
  670. Desc: If this string contains a complete path, gets the relative path w.r.t to some
  671. other complete path. Modifies this string
  672. Params:
  673. CSTRING& szPath: The other path w.r.t to which we have to get the relative path
  674. Return:
  675. --*/
  676. {
  677. return RelativeFile((LPCTSTR)szPath);
  678. }
  679. //
  680. // BUGBUG : consider using shlwapi PathRelativePathTo
  681. //
  682. BOOL
  683. CSTRING::RelativeFile(
  684. LPCTSTR pExeFile
  685. )
  686. /*++
  687. CSTRING::RelativeFile
  688. Desc: If this string contains a complete path, gets the relative path w.r.t to some
  689. other complete path. Modifies this string
  690. Params:
  691. CSTRING& szPath: The other path w.r.t to which we have to get the relative path
  692. Return:
  693. --*/
  694. {
  695. if (pExeFile == NULL) {
  696. assert(FALSE);
  697. return FALSE;
  698. }
  699. LPCTSTR pMatchFile = pszString;
  700. int nLenExe = 0;
  701. int nLenMatch = 0;
  702. LPCTSTR pExe = NULL;
  703. LPCTSTR pMatch = NULL;
  704. LPTSTR pReturn = NULL;
  705. BOOL bCommonBegin = FALSE; // Indicates if the paths have a common beginning
  706. LPTSTR resultIdx = NULL;
  707. TCHAR result[MAX_PATH * 2];
  708. INT iLength = 0;
  709. resultIdx = result;
  710. *result = TEXT('\0');
  711. iLength = lstrlen(pExeFile);
  712. if (iLength > min(MAX_PATH, ARRAYSIZE(result) - 1)) {
  713. assert(FALSE);
  714. Dbg(dlError, "CSTRING::RelativeFile", "Length of passed file name greater than size of buffer");
  715. return FALSE;
  716. }
  717. //
  718. // Ensure that the beginning of the path matches between the two files
  719. //
  720. // BUGBUG this code has to go -- look into replacing this with Shlwapi PathStripPath
  721. //
  722. //
  723. pExe = _tcschr(pExeFile, TEXT('\\'));
  724. pMatch = _tcschr(pMatchFile, TEXT('\\'));
  725. while (pExe && pMatch) {
  726. nLenExe = pExe - pExeFile;
  727. nLenMatch = pMatch - pMatchFile;
  728. if (nLenExe != nLenMatch) {
  729. break;
  730. }
  731. if (!(_tcsnicmp(pExeFile, pMatchFile, nLenExe) == 0)) {
  732. break;
  733. }
  734. bCommonBegin = TRUE;
  735. pExeFile = pExe + 1;
  736. pMatchFile = pMatch + 1;
  737. pExe = _tcschr(pExeFile, TEXT('\\'));
  738. pMatch = _tcschr(pMatchFile, TEXT('\\'));
  739. }
  740. //
  741. // Walk the path and put '..\' where necessary
  742. //
  743. if (bCommonBegin) {
  744. while (pExe) {
  745. //_tcsncpy(resultIdx, TEXT("..\\"), ARRAYSIZE(result) - (resultIdx - result));
  746. SafeCpyN(resultIdx, TEXT("..\\"), ARRAYSIZE(result) - (resultIdx - result));
  747. resultIdx = resultIdx + 3;
  748. pExeFile = pExe + 1;
  749. pExe = _tcschr(pExeFile, TEXT('\\'));
  750. }
  751. //_tcsncpy(resultIdx, pMatchFile, ARRAYSIZE(result) - (resultIdx - result));
  752. SafeCpyN(resultIdx, pMatchFile, ARRAYSIZE(result) - (resultIdx - result));
  753. SetString(result);
  754. } else {
  755. return FALSE;
  756. }
  757. return TRUE;
  758. }
  759. inline TCHAR*
  760. CSTRING::Replace(
  761. IN PCTSTR pszToFind,
  762. IN PCTSTR pszWith
  763. )
  764. /*++
  765. CSTRING::Replace
  766. Desc: Replace a substring with another string.
  767. As almost all others this function is also case insensitive
  768. Params:
  769. IN PCTSTR pszToFind: The sub string to find
  770. IN PCTSTR pszWith: Replace the above sub-string by this
  771. Return:
  772. The pszString member
  773. --*/
  774. {
  775. TCHAR* pszPtr = pszString;
  776. TCHAR* pszFoundPos = NULL;
  777. INT iLength = lstrlen(pszToFind);
  778. CSTRING strTemp;
  779. while (pszFoundPos = StrStrI(pszPtr, pszToFind)) {
  780. *pszFoundPos = 0;
  781. strTemp.Strcat(pszPtr);
  782. pszPtr = pszFoundPos + iLength;
  783. }
  784. if (strTemp.Length()) {
  785. *this = strTemp;
  786. }
  787. return pszString;
  788. }
  789. ///////////////////////////////////////////////////////////////////////////////
  790. //
  791. // Static Member Functions for CSTRING
  792. //
  793. //
  794. //
  795. TCHAR*
  796. CSTRING::StrStrI(
  797. IN PCTSTR pszString,
  798. IN PCTSTR pszMatch
  799. )
  800. /*++
  801. CSTRING::StrStrI
  802. Desc:
  803. Finds a substring in this string. Not case sensitive
  804. Params:
  805. IN PCTSTR pszString: The string in which we want to search
  806. IN PCTSTR pszMatch: The string to search
  807. Return:
  808. If found pointer to the substring
  809. NULL: Otherwise
  810. --*/
  811. {
  812. INT iLenghtStr = lstrlen(pszString);
  813. INT iLengthMatch = lstrlen(pszMatch);
  814. for (INT iIndex = 0; iIndex <= iLenghtStr - iLengthMatch; ++iIndex) {
  815. if (StrCmpNI(pszString + iIndex, pszMatch, iLengthMatch) == 0) {
  816. return (TCHAR*)(pszString + iIndex);
  817. }
  818. }
  819. return NULL;
  820. }
  821. INT
  822. CSTRING::Trim(
  823. IN OUT LPTSTR str
  824. )
  825. /*++
  826. CSTRING::Trim
  827. Desc: Removes white spaces tabs from the left and right of this string
  828. Params:
  829. IN OUT LPTSTR str: The string to trim
  830. Return:
  831. The length of the final string
  832. --*/
  833. {
  834. UINT nLength = 0;
  835. UINT uOrig_length = lstrlen(str); // Original length
  836. TCHAR* pStart = str;
  837. TCHAR* pEnd = str + uOrig_length - 1;
  838. if (str == NULL) {
  839. return 0;
  840. }
  841. while (*pStart == TEXT(' ') || *pStart == TEXT('\t')) {
  842. ++pStart;
  843. }
  844. while ((pEnd >= pStart) && (*pEnd == TEXT(' ') || *pEnd == TEXT('\t'))) {
  845. --pEnd;
  846. }
  847. *(pEnd + 1) = TEXT('\0');
  848. nLength = pEnd - pStart + 1;
  849. //
  850. // If no trimming has been done, return right away
  851. //
  852. if (uOrig_length == nLength || pStart == str) {
  853. //
  854. // In case of RTRIM we are putting in the NULL char appropriately
  855. //
  856. return nLength;
  857. }
  858. wmemmove(str, pStart, (nLength + 1)); // + 1 for the 0 character.
  859. return(nLength);
  860. }
  861. ///////////////////////////////////////////////////////////////////////////////
  862. //
  863. // The CSTRINGLIST member functions
  864. //
  865. //
  866. CSTRINGLIST::CSTRINGLIST()
  867. /*++
  868. CSTRINGLIST::CSTRINGLIST
  869. Desc: Constructor
  870. --*/
  871. {
  872. m_pHead = NULL;
  873. m_pTail = NULL;
  874. m_uCount = 0;
  875. }
  876. CSTRINGLIST::~CSTRINGLIST()
  877. /*++
  878. CSTRINGLIST::~CSTRINGLIST
  879. Desc: Destructor
  880. --*/
  881. {
  882. DeleteAll();
  883. }
  884. BOOL
  885. CSTRINGLIST::IsEmpty(
  886. void
  887. )
  888. /*++
  889. CSTRINGLIST::IsEmpty
  890. Desc: Checks if there are elements in the string list
  891. Params:
  892. void
  893. Return:
  894. TRUE: There are no elements in the string list
  895. FALSE: Otherwise
  896. --*/
  897. {
  898. if (m_pHead == NULL) {
  899. assert (m_pTail == NULL);
  900. return TRUE;
  901. } else {
  902. assert(m_pTail != NULL);
  903. }
  904. return FALSE;
  905. }
  906. void
  907. CSTRINGLIST::DeleteAll(
  908. void
  909. )
  910. /*++
  911. CSTRINGLIST::DeleteAll
  912. Desc: Removes all the elements in this string list
  913. --*/
  914. {
  915. while (NULL != m_pHead) {
  916. PSTRLIST pHold = m_pHead->pNext;
  917. delete m_pHead;
  918. m_pHead = pHold;
  919. }
  920. m_pTail = NULL;
  921. m_uCount = 0;
  922. }
  923. BOOL
  924. CSTRINGLIST::AddString(
  925. IN CSTRING& Str,
  926. IN int data // (0)
  927. )
  928. /*++
  929. CSTRINGLIST::AddString
  930. Desc: Adds a CSTRING to the end of this string list
  931. Params:
  932. IN CSTRING& Str: The CSTRING to add
  933. IN int data (0): The data member. Please see STRLIST in CSTRING.H
  934. Return:
  935. TRUE: Successful
  936. FALSE: Otherwise
  937. --*/
  938. {
  939. return AddString((LPCTSTR)Str, data);
  940. }
  941. BOOL
  942. CSTRINGLIST::AddStringAtBeg(
  943. IN LPCTSTR lpszStr,
  944. IN int data // (0)
  945. )
  946. /*++
  947. CSTRINGLIST::AddStringAtBeg
  948. Desc: Adds a CSTRING to the beginning of this string list
  949. Params:
  950. IN CSTRING& Str: The CSTRING to add
  951. IN int data (0): The data member. Please see STRLIST in CSTRING.H
  952. Return:
  953. TRUE: Successful
  954. FALSE: Otherwise
  955. --*/
  956. {
  957. PSTRLIST pNew = new STRLIST;
  958. if (NULL == pNew) {
  959. MEM_ERR;
  960. return FALSE;
  961. }
  962. pNew->data = data;
  963. pNew->szStr = lpszStr;
  964. pNew->pNext = m_pHead;
  965. m_pHead = pNew;
  966. if (m_pTail == NULL) {
  967. m_pTail = m_pHead;
  968. }
  969. ++m_uCount;
  970. return TRUE;
  971. }
  972. BOOL
  973. CSTRINGLIST::AddStringInOrder(
  974. IN LPCTSTR pStr,
  975. IN int data // (0)
  976. )
  977. /*++
  978. CSTRINGLIST::AddStringInOrder
  979. Desc: Adds a string in a sorted fashion, sorted by the data member.
  980. Please see STRLIST in CSTRING.H
  981. Params:
  982. IN LPCTSTR pStr: The string to add
  983. IN int data (0): The data member. Please see STRLIST in CSTRING.H
  984. Return:
  985. TRUE: Successful
  986. FALSE: Otherwise
  987. --*/
  988. {
  989. PSTRLIST pTemp, pPrev;
  990. PSTRLIST pNew = new STRLIST;
  991. if (NULL == pNew) {
  992. MEM_ERR;
  993. return FALSE;
  994. }
  995. pNew->data = data;
  996. pNew->szStr = pStr;
  997. pTemp = m_pHead;
  998. pPrev = NULL;
  999. while (pTemp) {
  1000. if (data < pTemp->data && (pPrev == NULL || data >= pPrev->data)) {
  1001. break;
  1002. }
  1003. pPrev = pTemp;
  1004. pTemp = pTemp->pNext;
  1005. }
  1006. if (pPrev == NULL) {
  1007. //
  1008. // Add it to the beg, smallest number
  1009. //
  1010. pNew->pNext = m_pHead;
  1011. m_pHead = pNew;
  1012. } else {
  1013. //
  1014. // Add somewhere in the middle or end
  1015. //
  1016. pNew->pNext = pTemp;
  1017. pPrev->pNext = pNew;
  1018. }
  1019. if (pTemp == NULL) {
  1020. //
  1021. // largest number.
  1022. //
  1023. m_pTail = pNew;
  1024. }
  1025. if (m_pTail == NULL) {
  1026. //
  1027. // Added first element
  1028. //
  1029. m_pTail = m_pHead;
  1030. }
  1031. ++m_uCount;
  1032. return TRUE;
  1033. }
  1034. BOOL
  1035. CSTRINGLIST::GetElement(
  1036. IN UINT uPos,
  1037. OUT CSTRING& str
  1038. )
  1039. /*++
  1040. CSTRINGLIST::GetElement
  1041. Desc: Gets the element at a given position in the string list
  1042. The position of the first string is 0
  1043. Params:
  1044. IN UINT uPos: The position
  1045. OUT CSTRING& str: This will contain the CSTRING at that position
  1046. Return:
  1047. TRUE: Successful
  1048. FALSE: Otherwise
  1049. --*/
  1050. {
  1051. PSTRLIST pHead = m_pHead;
  1052. UINT uIndex = 0;
  1053. while (pHead && uIndex != uPos) {
  1054. pHead = pHead->pNext;
  1055. ++uIndex;
  1056. }
  1057. if (uIndex == uPos) {
  1058. str = pHead->szStr;
  1059. return TRUE;
  1060. } else {
  1061. return FALSE;
  1062. }
  1063. }
  1064. BOOL
  1065. CSTRINGLIST::AddString(
  1066. IN LPCTSTR pStr,
  1067. IN int data // (0)
  1068. )
  1069. /*++
  1070. CSTRINGLIST::AddString
  1071. Desc: Adds a string to the end of this string list
  1072. Params:
  1073. IN LPCTSTR pStr: The string to add
  1074. IN int data (0): The data member. Please see STRLIST in CSTRING.H
  1075. Return:
  1076. TRUE: Successful
  1077. FALSE: Otherwise
  1078. --*/
  1079. {
  1080. PSTRLIST pNew = new STRLIST;
  1081. if (NULL == pNew) {
  1082. MEM_ERR;
  1083. return FALSE;
  1084. }
  1085. pNew->data = data;
  1086. pNew->szStr = pStr;
  1087. pNew->pNext = NULL;
  1088. if (NULL == m_pTail) {
  1089. m_pHead = m_pTail = pNew;
  1090. } else {
  1091. m_pTail->pNext = pNew;
  1092. m_pTail = pNew;
  1093. }
  1094. ++m_uCount;
  1095. return TRUE;
  1096. }
  1097. CSTRINGLIST&
  1098. CSTRINGLIST::operator = (
  1099. IN CSTRINGLIST& strlTemp
  1100. )
  1101. /*++
  1102. CSTRINGLIST::operator =
  1103. Desc: Assigns one string list to another
  1104. Params:
  1105. CSTRINGLIST& strlTemp: The right hand side of the = operator
  1106. Return:
  1107. This string list
  1108. --*/
  1109. {
  1110. PSTRLIST tempHead = NULL;
  1111. DeleteAll();
  1112. tempHead = strlTemp.m_pHead;
  1113. while (tempHead) {
  1114. AddString(tempHead->szStr, tempHead->data);
  1115. tempHead = tempHead->pNext;
  1116. }
  1117. return *this;
  1118. }
  1119. BOOL
  1120. CSTRINGLIST::operator != (
  1121. IN CSTRINGLIST &strlTemp
  1122. )
  1123. /*++
  1124. CSTRINGLIST::operator !=
  1125. Desc: Cheks if two string lists are different
  1126. Params:
  1127. CSTRINGLIST& strlTemp: The right hand side of the != operator
  1128. Return:
  1129. TRUE: The string lists are different
  1130. FALSE: The two string lists are similar
  1131. --*/
  1132. {
  1133. return(! (*this == strlTemp));
  1134. }
  1135. BOOL
  1136. CSTRINGLIST::operator == (
  1137. IN CSTRINGLIST &strlTemp
  1138. )
  1139. /*++
  1140. CSTRINGLIST::operator ==
  1141. Desc: Presently we check that the two stringlists are in the exact order.
  1142. e.g if string A = {x, y} and string B = {x, y} this function will return TRUE
  1143. but if string B = {y, x} then this function will return FALSE.
  1144. Their corresponding data members should also match
  1145. Params:
  1146. CSTRINGLIST& strlTemp: The right hand side of the == operator
  1147. Return:
  1148. TRUE: The string lists are similar
  1149. FALSE: The two string lists are different
  1150. --*/
  1151. {
  1152. PSTRLIST tempHeadOne = m_pHead;
  1153. PSTRLIST tempHeadTwo = strlTemp.m_pHead;
  1154. if (m_uCount != strlTemp.m_uCount) {
  1155. Dbg(dlInfo, "CSTRINGLIST::operator == ", "Lengths are different for the two stringlists so we will return FALSE");
  1156. return FALSE;
  1157. }
  1158. while (tempHeadOne && tempHeadTwo) {
  1159. if (!(tempHeadOne->szStr == tempHeadTwo->szStr
  1160. && tempHeadOne->data == tempHeadTwo->data)) {
  1161. return FALSE;
  1162. }
  1163. tempHeadOne = tempHeadOne->pNext;
  1164. tempHeadTwo = tempHeadTwo->pNext;
  1165. }
  1166. return TRUE;
  1167. }
  1168. BOOL
  1169. CSTRINGLIST::Remove(
  1170. IN CSTRING &str
  1171. )
  1172. /*++
  1173. CSTRINGLIST::Remove
  1174. Desc: Removes the element with CSTRING value of str from this string list
  1175. Params:
  1176. IN CSTRING &str: The CSTRING to remove
  1177. Return:
  1178. --*/
  1179. {
  1180. PSTRLIST pHead = m_pHead, pPrev = NULL;
  1181. while (pHead) {
  1182. if (pHead->szStr == str) {
  1183. break;
  1184. }
  1185. pPrev = pHead;
  1186. pHead = pHead->pNext;
  1187. }
  1188. if (pHead) {
  1189. if (pPrev == NULL) {
  1190. //
  1191. // First element.
  1192. //
  1193. m_pHead = pHead->pNext;
  1194. } else {
  1195. pPrev->pNext = pHead->pNext;
  1196. }
  1197. if (pHead == m_pTail) {
  1198. //
  1199. // Last element
  1200. //
  1201. m_pTail = pPrev;
  1202. }
  1203. delete pHead;
  1204. pHead = NULL;
  1205. --m_uCount;
  1206. return TRUE;
  1207. }
  1208. return FALSE;
  1209. }
  1210. void
  1211. CSTRINGLIST::RemoveLast(
  1212. void
  1213. )
  1214. /*++
  1215. CSTRINGLIST::RemoveLast
  1216. Desc: Removes the last element from this string list
  1217. Params:
  1218. void
  1219. Return:
  1220. void
  1221. --*/
  1222. {
  1223. if (m_pTail) {
  1224. Remove(m_pTail->szStr);
  1225. }
  1226. }