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.

348 lines
8.6 KiB

  1. /*--------------------------------------------------------------------------*
  2. *
  3. * Microsoft Windows
  4. * Copyright (C) Microsoft Corporation, 1992 - 1999
  5. *
  6. * File: tstring.h
  7. *
  8. * Contents: Implementation file for tstring
  9. *
  10. * History: 28-Oct-98 jeffro Created
  11. *
  12. *--------------------------------------------------------------------------*/
  13. #include "tstring.h"
  14. #include "stgio.h"
  15. #include <atlbase.h>
  16. #include <comutil.h>
  17. #include "macros.h"
  18. #include "countof.h"
  19. /*+-------------------------------------------------------------------------*
  20. * tstring::LoadString
  21. *
  22. *
  23. *--------------------------------------------------------------------------*/
  24. bool tstring::LoadString (HINSTANCE hInst, UINT nID)
  25. {
  26. #ifdef UNICODE
  27. #define CHAR_FUDGE 1 // one TCHAR unused is good enough
  28. #else
  29. #define CHAR_FUDGE 2 // two BYTES unused for case of DBC last char
  30. #endif
  31. // try fixed buffer first (to avoid wasting space in the heap)
  32. TCHAR szTemp[256];
  33. int nCount = sizeof(szTemp) / sizeof(szTemp[0]);
  34. int nLen = ::LoadString(hInst, nID, szTemp, nCount);
  35. if (nCount - nLen > CHAR_FUDGE)
  36. *this = szTemp;
  37. else
  38. {
  39. // try buffer size of 512, then larger size until entire string is retrieved
  40. LPTSTR pszBuffer = NULL;
  41. int nSize = 256;
  42. do
  43. {
  44. nSize += 256;
  45. delete[] pszBuffer;
  46. pszBuffer = new TCHAR[nSize];
  47. if (!pszBuffer)
  48. {
  49. return false; // Memory alloc failed.
  50. }
  51. nLen = ::LoadString(hInst, nID, pszBuffer, nSize);
  52. } while (nSize - nLen <= CHAR_FUDGE);
  53. *this = pszBuffer;
  54. delete[] pszBuffer;
  55. }
  56. return (nLen > 0);
  57. }
  58. #ifndef UNICODE
  59. /*+-------------------------------------------------------------------------*
  60. * operator>>
  61. *
  62. * ANSI only: Extracts a string from a stream in Unicode format, then
  63. * converts it to ANSI.
  64. *--------------------------------------------------------------------------*/
  65. IStream& operator>> (IStream& stm, tstring& str)
  66. {
  67. USES_CONVERSION;
  68. std::wstring wstr;
  69. stm >> wstr;
  70. str = W2CA (wstr.data());
  71. return (stm);
  72. }
  73. /*+-------------------------------------------------------------------------*
  74. * operator<<
  75. *
  76. * ANSI only: Inserts a tstring into a stream in Unicode format.
  77. *--------------------------------------------------------------------------*/
  78. IStream& operator<< (IStream& stm, const tstring& str)
  79. {
  80. USES_CONVERSION;
  81. return (stm << std::wstring (A2W (str.data())));
  82. }
  83. #endif // UNICODE
  84. /*+-------------------------------------------------------------------------*
  85. * CStringTableStringBase::CStringTableStringBase
  86. *
  87. *
  88. *--------------------------------------------------------------------------*/
  89. CStringTableStringBase::CStringTableStringBase (IStringTablePrivate* pstp)
  90. : m_spStringTable (pstp),
  91. m_id (eNoValue)
  92. {
  93. }
  94. CStringTableStringBase::CStringTableStringBase (const CStringTableStringBase& other)
  95. : m_spStringTable (other.m_spStringTable),
  96. m_id (eNoValue)
  97. {
  98. Assign (other);
  99. }
  100. CStringTableStringBase::CStringTableStringBase (
  101. IStringTablePrivate* pstp,
  102. const tstring& str)
  103. : m_spStringTable (pstp),
  104. m_id (eNoValue),
  105. m_str (str)
  106. {
  107. }
  108. /*+-------------------------------------------------------------------------*
  109. * CStringTableStringBase::operator=
  110. *
  111. *
  112. *--------------------------------------------------------------------------*/
  113. CStringTableStringBase& CStringTableStringBase::operator= (const CStringTableStringBase& other)
  114. {
  115. if (&other != this)
  116. {
  117. RemoveFromStringTable();
  118. Assign (other);
  119. }
  120. return (*this);
  121. }
  122. CStringTableStringBase& CStringTableStringBase::operator= (const tstring& str)
  123. {
  124. /*
  125. * string table operations are relatively expensive, so a string
  126. * comparision before we do any string table stuff is warranted
  127. */
  128. if (m_str != str)
  129. {
  130. RemoveFromStringTable();
  131. /*
  132. * copy the text, but delay committing to the string table
  133. */
  134. m_str = str;
  135. }
  136. return (*this);
  137. }
  138. CStringTableStringBase& CStringTableStringBase::operator= (LPCTSTR psz)
  139. {
  140. return (operator= (tstring (psz)));
  141. }
  142. /*+-------------------------------------------------------------------------*
  143. * CStringTableStringBase::Assign
  144. *
  145. *
  146. *--------------------------------------------------------------------------*/
  147. void CStringTableStringBase::Assign (const CStringTableStringBase& other)
  148. {
  149. ASSERT (m_id == eNoValue);
  150. /*
  151. * copy the other's value
  152. */
  153. m_str = other.m_str;
  154. /*
  155. * if the source string is already committed to
  156. * the string table, this one should be, too
  157. */
  158. if (other.m_id != eNoValue)
  159. CommitToStringTable ();
  160. }
  161. /*+-------------------------------------------------------------------------*
  162. * CStringTableStringBase::~CStringTableStringBase
  163. *
  164. *
  165. *--------------------------------------------------------------------------*/
  166. CStringTableStringBase::~CStringTableStringBase ()
  167. {
  168. RemoveFromStringTable();
  169. }
  170. /*+-------------------------------------------------------------------------*
  171. * CStringTableStringBase::CommitToStringTable
  172. *
  173. * Attaches the current string to the given string table
  174. *--------------------------------------------------------------------------*/
  175. MMC_STRING_ID CStringTableStringBase::CommitToStringTable () const
  176. {
  177. /*
  178. * Commit the string if:
  179. *
  180. * 1. the string's not already in the string table, and
  181. * 2. it's not empty, and
  182. * 3. we have a string table
  183. */
  184. if ((m_id == eNoValue) && !m_str.empty() && (m_spStringTable != NULL))
  185. {
  186. USES_CONVERSION;
  187. m_spStringTable->AddString (T2CW (m_str.data()), &m_id, NULL);
  188. }
  189. return (m_id);
  190. }
  191. /*+-------------------------------------------------------------------------*
  192. * CStringTableStringBase::RemoveFromStringTable
  193. *
  194. * Detaches the current string from the current string table.
  195. *--------------------------------------------------------------------------*/
  196. void CStringTableStringBase::RemoveFromStringTable () const
  197. {
  198. /*
  199. * if we have a string ID from the current string table, delete it
  200. */
  201. if (m_id != eNoValue)
  202. {
  203. /*
  204. * shouldn't be removing a string from a string table unless
  205. * we have already added it (and therefore obtained an interface)
  206. */
  207. ASSERT (m_spStringTable != NULL);
  208. m_spStringTable->DeleteString (m_id, NULL);
  209. m_id = eNoValue;
  210. }
  211. }
  212. /*+-------------------------------------------------------------------------*
  213. * operator>>
  214. *
  215. *
  216. *--------------------------------------------------------------------------*/
  217. IStream& operator>> (IStream& stm, CStringTableStringBase& str)
  218. {
  219. str.RemoveFromStringTable();
  220. stm >> str.m_id;
  221. if (str.m_id != CStringTableStringBase::eNoValue)
  222. {
  223. try
  224. {
  225. USES_CONVERSION;
  226. HRESULT hr;
  227. ULONG cch;
  228. if (str.m_spStringTable == NULL)
  229. _com_issue_error (E_NOINTERFACE);
  230. hr = str.m_spStringTable->GetStringLength (str.m_id, &cch, NULL);
  231. THROW_ON_FAIL (hr);
  232. // allow for NULL terminator
  233. cch++;
  234. std::auto_ptr<WCHAR> spszText (new (std::nothrow) WCHAR[cch]);
  235. LPWSTR pszText = spszText.get();
  236. if (pszText == NULL)
  237. _com_issue_error (E_OUTOFMEMORY);
  238. hr = str.m_spStringTable->GetString (str.m_id, cch, pszText, NULL, NULL);
  239. THROW_ON_FAIL (hr);
  240. str.m_str = W2T (pszText);
  241. }
  242. catch (_com_error& err)
  243. {
  244. ASSERT (false && "Caught _com_error");
  245. str.m_id = CStringTableStringBase::eNoValue;
  246. str.m_str.erase();
  247. throw;
  248. }
  249. }
  250. else
  251. str.m_str.erase();
  252. return (stm);
  253. }
  254. /*+-------------------------------------------------------------------------*
  255. * operator<<
  256. *
  257. *
  258. *--------------------------------------------------------------------------*/
  259. IStream& operator<< (IStream& stm, const CStringTableStringBase& str)
  260. {
  261. str.CommitToStringTable();
  262. #ifdef DBG
  263. /*
  264. * make sure CommitToStringTable really committed
  265. */
  266. if (str.m_id != CStringTableStringBase::eNoValue)
  267. {
  268. WCHAR sz[256];
  269. ASSERT (str.m_spStringTable != NULL);
  270. HRESULT hr = str.m_spStringTable->GetString (str.m_id, countof(sz), sz, NULL, NULL);
  271. ASSERT (SUCCEEDED(hr) && "Persisted a CStringTableString to a stream that's not in the string table");
  272. }
  273. #endif
  274. stm << str.m_id;
  275. return (stm);
  276. }