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.

595 lines
10 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. _pszString = (LPTSTR)AllocMem(
  118. ( lstrlen( pszTmp ) +
  119. lstrlen( psz ) +
  120. 1 ) *
  121. sizeof ( pszTmp[0] ) );
  122. //
  123. // If memory was not available.
  124. //
  125. if( !_pszString ){
  126. //
  127. // Release the original buffer.
  128. //
  129. vFree( pszTmp );
  130. //
  131. // Mark the string object as invalid.
  132. //
  133. _pszString = &TString::gszNullState[kInValid];
  134. } else {
  135. //
  136. // Copy the string and concatenate the passed string.
  137. //
  138. lstrcpy( _pszString, pszTmp );
  139. lstrcat( _pszString, psz );
  140. //
  141. // Release the original buffer.
  142. //
  143. vFree( pszTmp );
  144. //
  145. // Indicate success.
  146. //
  147. bStatus = TRUE;
  148. }
  149. //
  150. // Skip null pointers, not an error.
  151. //
  152. } else {
  153. bStatus = TRUE;
  154. }
  155. return bStatus;
  156. }
  157. BOOL
  158. TString::
  159. bUpdate(
  160. IN LPCTSTR psz
  161. )
  162. /*++
  163. Routine Description:
  164. Safe updating of string. If the allocation fails, return FALSE
  165. and leave the string as is.
  166. Arguments:
  167. psz - Input string, may be NULL.
  168. Return Value:
  169. TRUE = update successful
  170. FALSE = update failed
  171. --*/
  172. {
  173. //
  174. // Check if the null pointer is passed.
  175. //
  176. if( !psz ){
  177. //
  178. // If not pointing to the gszNullState
  179. //
  180. vFree( _pszString );
  181. //
  182. // Mark the object as valid.
  183. //
  184. _pszString = &TString::gszNullState[kValid];
  185. return TRUE;
  186. }
  187. //
  188. // Create temp pointer and allocate the new string.
  189. //
  190. LPTSTR pszTmp = _pszString;
  191. _pszString = (LPTSTR) AllocMem(( lstrlen(psz)+1 ) * sizeof( psz[0] ));
  192. //
  193. // If memory was not available.
  194. //
  195. if( !_pszString ){
  196. //
  197. // Ensure we free any previous string.
  198. //
  199. vFree( pszTmp );
  200. //
  201. // Mark the string object as invalid.
  202. //
  203. _pszString = &TString::gszNullState[kInValid];
  204. return FALSE;
  205. }
  206. //
  207. // Copy the string and
  208. //
  209. lstrcpy( _pszString, psz );
  210. //
  211. // If the old string object was not pointing to our
  212. // class specific gszNullStates then release the memory.
  213. //
  214. vFree( pszTmp );
  215. return TRUE;
  216. }
  217. BOOL
  218. TString::
  219. bLoadString(
  220. IN HINSTANCE hInst,
  221. IN UINT uID
  222. )
  223. /*++
  224. Routine Description:
  225. Safe load of a string from a resources file.
  226. Arguments:
  227. hInst - Instance handle of resource file.
  228. uId - Resource id to load.
  229. Return Value:
  230. TRUE = load successful
  231. FALSE = load failed
  232. --*/
  233. {
  234. LPTSTR pszString = NULL;
  235. BOOL bStatus = FALSE;
  236. INT iSize;
  237. INT iLen;
  238. //
  239. // Continue increasing the buffer until
  240. // the buffer is big enought to hold the entire string.
  241. //
  242. for( iSize = kStrMax; ; iSize += kStrMax ){
  243. //
  244. // Allocate string buffer.
  245. //
  246. pszString = (LPTSTR)AllocMem( iSize * sizeof( pszString[0] ) );
  247. if( pszString ){
  248. iLen = LoadString( hInst, uID, pszString, iSize );
  249. if( iLen == 0 ) {
  250. DBGMSG( DBG_ERROR, ( "String.vLoadString: failed to load IDS 0x%x, %d\n", uID, GetLastError() ));
  251. FreeMem( pszString );
  252. break;
  253. //
  254. // Since LoadString does not indicate if the string was truncated or it
  255. // just happened to fit. When we detect this ambiguous case we will
  256. // try one more time just to be sure.
  257. //
  258. } else if( iSize - iLen <= sizeof( pszString[0] ) ){
  259. FreeMem( pszString );
  260. //
  261. // LoadString was successful release original string buffer
  262. // and update new buffer pointer.
  263. //
  264. } else {
  265. vFree( _pszString );
  266. _pszString = pszString;
  267. bStatus = TRUE;
  268. break;
  269. }
  270. } else {
  271. DBGMSG( DBG_ERROR, ( "String.vLoadString: unable to allocate memory, %d\n", GetLastError() ));
  272. break;
  273. }
  274. }
  275. return bStatus;
  276. }
  277. VOID
  278. TString::
  279. vFree(
  280. IN LPTSTR pszString
  281. )
  282. /*++
  283. Routine Description:
  284. Safe free, frees the string memory. Ensures
  285. we do not try an free our global memory block.
  286. Arguments:
  287. pszString pointer to string meory to free.
  288. Return Value:
  289. Nothing.
  290. --*/
  291. {
  292. //
  293. // If this memory was not pointing to our
  294. // class specific gszNullStates then release the memory.
  295. //
  296. if( pszString != &TString::gszNullState[kValid] &&
  297. pszString != &TString::gszNullState[kInValid] ){
  298. FreeMem( pszString );
  299. }
  300. }
  301. BOOL
  302. TString::
  303. bFormat(
  304. IN LPCTSTR pszFmt,
  305. IN ...
  306. )
  307. {
  308. /*++
  309. Routine Description:
  310. Format the string opbject similar to sprintf.
  311. Arguments:
  312. pszFmt pointer format string.
  313. .. variable number of arguments similar to sprintf.
  314. Return Value:
  315. TRUE if string was format successfully. FALSE if error
  316. occurred creating the format string, string object will be
  317. invalid and the previous string lost.
  318. --*/
  319. BOOL bStatus = TRUE;
  320. va_list pArgs;
  321. va_start( pArgs, pszFmt );
  322. bStatus = bvFormat( pszFmt, pArgs );
  323. va_end( pArgs );
  324. return bStatus;
  325. }
  326. BOOL
  327. TString::
  328. bvFormat(
  329. IN LPCTSTR pszFmt,
  330. IN va_list avlist
  331. )
  332. /*++
  333. Routine Description:
  334. Format the string opbject similar to vsprintf.
  335. Arguments:
  336. pszFmt pointer format string.
  337. pointer to variable number of arguments similar to vsprintf.
  338. Return Value:
  339. TRUE if string was format successfully. FALSE if error
  340. occurred creating the format string, string object will be
  341. invalid and the previous string lost.
  342. --*/
  343. {
  344. BOOL bStatus;
  345. //
  346. // Save previous string value.
  347. //
  348. LPTSTR pszTemp = _pszString;
  349. //
  350. // Format the string.
  351. //
  352. _pszString = vsntprintf( pszFmt, avlist );
  353. //
  354. // If format failed mark object as invalid and
  355. // set the return value.
  356. //
  357. if( !_pszString )
  358. {
  359. _pszString = &TString::gszNullState[kInValid];
  360. bStatus = FALSE;
  361. }
  362. else
  363. {
  364. bStatus = TRUE;
  365. }
  366. //
  367. // Release near the end because the format string or arguments
  368. // may be referencing this string object.
  369. //
  370. vFree( pszTemp );
  371. return bStatus;
  372. }
  373. LPTSTR
  374. TString::
  375. vsntprintf(
  376. IN LPCTSTR szFmt,
  377. IN va_list pArgs
  378. )
  379. /*++
  380. Routine Description:
  381. //
  382. // Formats a string and returns a heap allocated string with the
  383. // formated data. This routine can be used to for extremely
  384. // long format strings. Note: If a valid pointer is returned
  385. // the callng functions must release the data with a call to delete.
  386. // Example:
  387. //
  388. // LPCTSTR p = vsntprintf("Test %s", pString );
  389. //
  390. // SetTitle( p );
  391. //
  392. // delete [] p;
  393. //
  394. Arguments:
  395. pszString pointer format string.
  396. pointer to a variable number of arguments.
  397. Return Value:
  398. Pointer to format string. NULL if error.
  399. --*/
  400. {
  401. LPTSTR pszBuff = NULL;
  402. INT iSize = kStrIncrement;
  403. for( ; ; )
  404. {
  405. //
  406. // Allocate the message buffer.
  407. //
  408. pszBuff = (LPTSTR)AllocMem( iSize * sizeof(TCHAR) );
  409. if( !pszBuff )
  410. {
  411. break;
  412. }
  413. //
  414. // Attempt to format the string. snprintf fails with a
  415. // negative number when the buffer is too small.
  416. //
  417. INT iReturn = _vsntprintf( pszBuff, iSize, szFmt, pArgs );
  418. //
  419. // If the return value positive and not equal to the buffer size
  420. // then the format succeeded. _vsntprintf will not null terminate
  421. // the string if the resultant string is exactly the lenght of the
  422. // provided buffer.
  423. //
  424. if( iReturn > 0 && iReturn != iSize )
  425. {
  426. break;
  427. }
  428. //
  429. // String did not fit release the current buffer.
  430. //
  431. if( pszBuff )
  432. {
  433. FreeMem( pszBuff );
  434. }
  435. //
  436. // Double the buffer size after each failure.
  437. //
  438. iSize *= 2;
  439. //
  440. // If the size is greater than 100k exit without formatting a string.
  441. //
  442. if( iSize > kStrMaxFormatSize )
  443. {
  444. DBGMSG( DBG_ERROR, ("TString::vsntprintf failed string too long.\n") );
  445. pszBuff = NULL;
  446. break;
  447. }
  448. }
  449. return pszBuff;
  450. }