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.

612 lines
11 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. String.cxx
  6. Abstract:
  7. Short strings
  8. Author:
  9. Albert Ting (AlbertT) 9-June-1994
  10. Revision History:
  11. --*/
  12. #include "spllibp.hxx"
  13. #pragma hdrstop
  14. //
  15. // Class specific NULL state.
  16. //
  17. TCHAR TString::gszNullState[2] = {0,0};
  18. //
  19. // Default construction.
  20. //
  21. TString::
  22. TString(
  23. VOID
  24. ) : _pszString( &TString::gszNullState[kValid] )
  25. {
  26. }
  27. //
  28. // Construction using an existing LPCTSTR string.
  29. //
  30. TString::
  31. TString(
  32. IN LPCTSTR psz
  33. ) : _pszString( &TString::gszNullState[kValid] )
  34. {
  35. bUpdate( psz );
  36. }
  37. //
  38. // Destruction, ensure we don't free our NULL state.
  39. //
  40. TString::
  41. ~TString(
  42. VOID
  43. )
  44. {
  45. vFree( _pszString );
  46. }
  47. //
  48. // Copy constructor.
  49. //
  50. TString::
  51. TString(
  52. const TString &String
  53. ) : _pszString( &TString::gszNullState[kValid] )
  54. {
  55. bUpdate( String._pszString );
  56. }
  57. //
  58. // Indicates if a string has any usable data.
  59. //
  60. BOOL
  61. TString::
  62. bEmpty(
  63. VOID
  64. ) const
  65. {
  66. return _pszString[0] == 0;
  67. }
  68. //
  69. // Indicates if a string object is valid.
  70. //
  71. BOOL
  72. TString::
  73. bValid(
  74. VOID
  75. ) const
  76. {
  77. return _pszString != &TString::gszNullState[kInValid];
  78. }
  79. //
  80. // Return the length of the string.
  81. //
  82. UINT
  83. TString::
  84. uLen(
  85. VOID
  86. ) const
  87. {
  88. return lstrlen( _pszString );
  89. }
  90. BOOL
  91. TString::
  92. bCat(
  93. IN LPCTSTR psz
  94. )
  95. /*++
  96. Routine Description:
  97. Safe concatenation of the specified string to the string
  98. object. If the allocation fails, return FALSE and the
  99. original string is not modified.
  100. Arguments:
  101. psz - Input string, may be NULL.
  102. Return Value:
  103. TRUE = update successful
  104. FALSE = update failed
  105. --*/
  106. {
  107. BOOL bStatus = FALSE;
  108. //
  109. // If a valid string was passed.
  110. //
  111. if( psz ){
  112. LPTSTR pszTmp = _pszString;
  113. //
  114. // Allocate the new buffer consisting of the size of the orginal
  115. // string plus the sizeof of the new string plus the null terminator.
  116. //
  117. size_t cchSize = lstrlen( pszTmp ) + lstrlen( psz ) + 1;
  118. _pszString = (LPTSTR)AllocMem(cchSize * sizeof(pszTmp[0]));
  119. //
  120. // If memory was not available.
  121. //
  122. if( !_pszString ){
  123. //
  124. // Release the original buffer.
  125. //
  126. vFree( pszTmp );
  127. //
  128. // Mark the string object as invalid.
  129. //
  130. _pszString = &TString::gszNullState[kInValid];
  131. } else {
  132. //
  133. // Copy the string and concatenate the passed string.
  134. //
  135. StringCchCopy( _pszString, cchSize, pszTmp);
  136. StringCchCat(_pszString, cchSize, psz);
  137. //
  138. // Release the original buffer.
  139. //
  140. vFree( pszTmp );
  141. //
  142. // Indicate success.
  143. //
  144. bStatus = TRUE;
  145. }
  146. //
  147. // Skip null pointers, not an error.
  148. //
  149. } else {
  150. bStatus = TRUE;
  151. }
  152. return bStatus;
  153. }
  154. BOOL
  155. TString::
  156. bUpdate(
  157. IN LPCTSTR psz
  158. )
  159. /*++
  160. Routine Description:
  161. Safe updating of string. If the allocation fails, return FALSE
  162. and leave the string as is.
  163. Arguments:
  164. psz - Input string, may be NULL.
  165. Return Value:
  166. TRUE = update successful
  167. FALSE = update failed
  168. --*/
  169. {
  170. //
  171. // Check if the null pointer is passed.
  172. //
  173. if( !psz ){
  174. //
  175. // If not pointing to the gszNullState
  176. //
  177. vFree( _pszString );
  178. //
  179. // Mark the object as valid.
  180. //
  181. _pszString = &TString::gszNullState[kValid];
  182. return TRUE;
  183. }
  184. //
  185. // Create temp pointer and allocate the new string.
  186. //
  187. LPTSTR pszTmp = _pszString;
  188. SIZE_T cchLen = lstrlen(psz) + 1;
  189. _pszString = (LPTSTR) AllocMem(static_cast<DWORD>(cchLen * sizeof( psz[0] )));
  190. //
  191. // If memory was not available.
  192. //
  193. if( !_pszString ){
  194. //
  195. // Ensure we free any previous string.
  196. //
  197. vFree( pszTmp );
  198. //
  199. // Mark the string object as invalid.
  200. //
  201. _pszString = &TString::gszNullState[kInValid];
  202. return FALSE;
  203. }
  204. //
  205. // Copy the string and
  206. //
  207. StringCchCopy( _pszString, cchLen, psz);
  208. //
  209. // If the old string object was not pointing to our
  210. // class specific gszNullStates then release the memory.
  211. //
  212. vFree( pszTmp );
  213. return TRUE;
  214. }
  215. /*++
  216. Routine Name:
  217. Update
  218. Routine Description:
  219. Safe updating of string. If the allocation fails, return E_OUTOFMEMORY.
  220. Arguments:
  221. psz - Input string, may be NULL.
  222. Return Value:
  223. An HRESULT
  224. --*/
  225. HRESULT
  226. TString::
  227. Update(
  228. IN LPCTSTR psz
  229. )
  230. {
  231. return bUpdate(psz) ? S_OK : E_OUTOFMEMORY;
  232. }
  233. BOOL
  234. TString::
  235. bLoadString(
  236. IN HINSTANCE hInst,
  237. IN UINT uID
  238. )
  239. /*++
  240. Routine Description:
  241. Safe load of a string from a resources file.
  242. Arguments:
  243. hInst - Instance handle of resource file.
  244. uId - Resource id to load.
  245. Return Value:
  246. TRUE = load successful
  247. FALSE = load failed
  248. --*/
  249. {
  250. LPTSTR pszString = NULL;
  251. BOOL bStatus = FALSE;
  252. INT iSize;
  253. INT iLen;
  254. //
  255. // Continue increasing the buffer until
  256. // the buffer is big enought to hold the entire string.
  257. //
  258. for( iSize = kStrMax; ; iSize += kStrMax ){
  259. //
  260. // Allocate string buffer.
  261. //
  262. pszString = (LPTSTR)AllocMem( iSize * sizeof( pszString[0] ) );
  263. if( pszString ){
  264. iLen = LoadString( hInst, uID, pszString, iSize );
  265. if( iLen == 0 ) {
  266. DBGMSG( DBG_ERROR, ( "String.vLoadString: failed to load IDS 0x%x, %d\n", uID, GetLastError() ));
  267. FreeMem( pszString );
  268. break;
  269. //
  270. // Since LoadString does not indicate if the string was truncated or it
  271. // just happened to fit. When we detect this ambiguous case we will
  272. // try one more time just to be sure.
  273. //
  274. } else if( iSize - iLen <= sizeof( pszString[0] ) ){
  275. FreeMem( pszString );
  276. //
  277. // LoadString was successful release original string buffer
  278. // and update new buffer pointer.
  279. //
  280. } else {
  281. vFree( _pszString );
  282. _pszString = pszString;
  283. bStatus = TRUE;
  284. break;
  285. }
  286. } else {
  287. DBGMSG( DBG_ERROR, ( "String.vLoadString: unable to allocate memory, %d\n", GetLastError() ));
  288. break;
  289. }
  290. }
  291. return bStatus;
  292. }
  293. VOID
  294. TString::
  295. vFree(
  296. IN LPTSTR pszString
  297. )
  298. /*++
  299. Routine Description:
  300. Safe free, frees the string memory. Ensures
  301. we do not try an free our global memory block.
  302. Arguments:
  303. pszString pointer to string meory to free.
  304. Return Value:
  305. Nothing.
  306. --*/
  307. {
  308. //
  309. // If this memory was not pointing to our
  310. // class specific gszNullStates then release the memory.
  311. //
  312. if( pszString != &TString::gszNullState[kValid] &&
  313. pszString != &TString::gszNullState[kInValid] ){
  314. FreeMem( pszString );
  315. }
  316. }
  317. BOOL
  318. TString::
  319. bFormat(
  320. IN LPCTSTR pszFmt,
  321. IN ...
  322. )
  323. {
  324. /*++
  325. Routine Description:
  326. Format the string opbject similar to sprintf.
  327. Arguments:
  328. pszFmt pointer format string.
  329. .. variable number of arguments similar to sprintf.
  330. Return Value:
  331. TRUE if string was format successfully. FALSE if error
  332. occurred creating the format string, string object will be
  333. invalid and the previous string lost.
  334. --*/
  335. BOOL bStatus = TRUE;
  336. va_list pArgs;
  337. va_start( pArgs, pszFmt );
  338. bStatus = bvFormat( pszFmt, pArgs );
  339. va_end( pArgs );
  340. return bStatus;
  341. }
  342. BOOL
  343. TString::
  344. bvFormat(
  345. IN LPCTSTR pszFmt,
  346. IN va_list avlist
  347. )
  348. /*++
  349. Routine Description:
  350. Format the string opbject similar to vsprintf.
  351. Arguments:
  352. pszFmt pointer format string.
  353. pointer to variable number of arguments similar to vsprintf.
  354. Return Value:
  355. TRUE if string was format successfully. FALSE if error
  356. occurred creating the format string, string object will be
  357. invalid and the previous string lost.
  358. --*/
  359. {
  360. BOOL bStatus;
  361. //
  362. // Save previous string value.
  363. //
  364. LPTSTR pszTemp = _pszString;
  365. //
  366. // Format the string.
  367. //
  368. _pszString = vsntprintf( pszFmt, avlist );
  369. //
  370. // If format failed mark object as invalid and
  371. // set the return value.
  372. //
  373. if( !_pszString )
  374. {
  375. _pszString = &TString::gszNullState[kInValid];
  376. bStatus = FALSE;
  377. }
  378. else
  379. {
  380. bStatus = TRUE;
  381. }
  382. //
  383. // Release near the end because the format string or arguments
  384. // may be referencing this string object.
  385. //
  386. vFree( pszTemp );
  387. return bStatus;
  388. }
  389. LPTSTR
  390. TString::
  391. vsntprintf(
  392. IN LPCTSTR szFmt,
  393. IN va_list pArgs
  394. )
  395. /*++
  396. Routine Description:
  397. //
  398. // Formats a string and returns a heap allocated string with the
  399. // formated data. This routine can be used to for extremely
  400. // long format strings. Note: If a valid pointer is returned
  401. // the callng functions must release the data with a call to delete.
  402. // Example:
  403. //
  404. // LPCTSTR p = vsntprintf("Test %s", pString );
  405. //
  406. // SetTitle( p );
  407. //
  408. // delete [] p;
  409. //
  410. Arguments:
  411. pszString pointer format string.
  412. pointer to a variable number of arguments.
  413. Return Value:
  414. Pointer to format string. NULL if error.
  415. --*/
  416. {
  417. LPTSTR pszBuff = NULL;
  418. INT iSize = kStrIncrement;
  419. for( ; ; )
  420. {
  421. //
  422. // Allocate the message buffer.
  423. //
  424. pszBuff = (LPTSTR)AllocMem( iSize * sizeof(TCHAR) );
  425. if( !pszBuff )
  426. {
  427. break;
  428. }
  429. //
  430. // Attempt to format the string.
  431. if (SUCCEEDED(StringCchVPrintf( pszBuff, iSize, szFmt, pArgs )))
  432. {
  433. break;
  434. }
  435. //
  436. // String did not fit release the current buffer.
  437. //
  438. if( pszBuff )
  439. {
  440. FreeMem( pszBuff );
  441. }
  442. //
  443. // Double the buffer size after each failure.
  444. //
  445. iSize *= 2;
  446. //
  447. // If the size is greater than 100k exit without formatting a string.
  448. //
  449. if( iSize > kStrMaxFormatSize )
  450. {
  451. DBGMSG( DBG_ERROR, ("TString::vsntprintf failed string too long.\n") );
  452. pszBuff = NULL;
  453. break;
  454. }
  455. }
  456. return pszBuff;
  457. }