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.

482 lines
14 KiB

  1. /*--------------------------------------------------------------------------*
  2. *
  3. * Microsoft Windows
  4. * Copyright (C) Microsoft Corporation, 1999 - 1999
  5. *
  6. * File: bookmark.inl
  7. *
  8. * Contents: Implementation file for CBookmark
  9. *
  10. * History: 25-Oct-99 vivekj Created
  11. *
  12. *--------------------------------------------------------------------------*/
  13. #include "uastrfnc.h" // from $(SHELL_INC_PATH), for unaligned string functions
  14. /*+-------------------------------------------------------------------------*
  15. * UnalignedValueAt
  16. *
  17. * Returns the value at a potentially unaligned address.
  18. *--------------------------------------------------------------------------*/
  19. template<typename T>
  20. T UnalignedValueAt (UNALIGNED T* pT)
  21. {
  22. return (*pT);
  23. }
  24. //############################################################################
  25. //############################################################################
  26. //
  27. // Implementation of class CDynamicPathEntry
  28. //
  29. //############################################################################
  30. //############################################################################
  31. /*+-------------------------------------------------------------------------*
  32. *
  33. * CDynamicPathEntry::ScInitialize
  34. *
  35. * PURPOSE: Initializes the entry from a byte array read in from a console file.
  36. *
  37. * PARAMETERS:
  38. * bool bIs10Path : true if the path entry format is that of MMC1.0.
  39. * I iter: The byte array.
  40. *
  41. * RETURNS:
  42. * inline SC
  43. *
  44. *+-------------------------------------------------------------------------*/
  45. inline SC
  46. CDynamicPathEntry::ScInitialize(bool bIs10Path, /*[IN,OUT]*/ByteVector::iterator &iter)
  47. {
  48. DECLARE_SC(sc, TEXT("CDynamicPathEntry::ScInitialize"));
  49. if(bIs10Path) // an MMC1.0 path entry. Just the display name
  50. {
  51. m_type = NDTYP_STRING;
  52. m_strEntry = reinterpret_cast<LPCWSTR>(iter);
  53. iter += (m_strEntry.length() + 1) *sizeof(WCHAR); // bump up the iterator.
  54. }
  55. else // a 1.1 or 1.2 path. The first byte contains the type.
  56. {
  57. m_type = *iter++; // either NDTYP_STRING or NDTYP_CUSTOM
  58. switch(m_type)
  59. {
  60. default:
  61. sc = E_UNEXPECTED;
  62. break;
  63. case NDTYP_STRING:
  64. {
  65. LPCWSTR pszEntry = reinterpret_cast<LPCWSTR>(iter);
  66. #ifdef ALIGNMENT_MACHINE
  67. /*
  68. * Bug 128010: if our target machine requires data alignment and
  69. * the source is unaligned, make an aligned copy that we can
  70. * pass to std::wstring::operator=, which calls wcs* functions
  71. * expect aligned data
  72. */
  73. if (!IS_ALIGNED (pszEntry))
  74. {
  75. LPWSTR pszNew = (LPWSTR) alloca ((ualstrlenW(pszEntry) + 1) * sizeof(WCHAR));
  76. ualstrcpyW (pszNew, pszEntry);
  77. pszEntry = pszNew;
  78. }
  79. #endif
  80. m_strEntry = pszEntry;
  81. // bump the input pointer to the next element
  82. iter += (m_strEntry.length() + 1) * sizeof (WCHAR);
  83. break;
  84. }
  85. case NDTYP_CUSTOM:
  86. const SNodeID* pNodeID = reinterpret_cast<const SNodeID*>(iter); // same binary layout as a SNodeID.
  87. if(!pNodeID)
  88. return (sc = E_UNEXPECTED);
  89. /*
  90. * Bug 177492: pNodeID->cBytes may be unaligned, so make an aligned copy of it
  91. */
  92. const DWORD cBytes = UnalignedValueAt (&pNodeID->cBytes);
  93. m_byteVector.insert(m_byteVector.end(), pNodeID->id, pNodeID->id + cBytes);
  94. /*if(pNodeID->cBytes==0)
  95. m_dwFlags = MMC_NODEID_SLOW_RETRIEVAL; */ // shouldn't need this; should not be able to save such a bookmark.
  96. iter += sizeof (pNodeID->cBytes) + cBytes; // bump up the pointer.
  97. break;
  98. }
  99. }
  100. return sc;
  101. }
  102. inline bool
  103. CDynamicPathEntry::operator ==(const CDynamicPathEntry &rhs) const
  104. {
  105. // check the types
  106. if(m_type != rhs.m_type)
  107. return false;
  108. if(m_type == NDTYP_CUSTOM)
  109. return (m_byteVector == rhs.m_byteVector);
  110. else
  111. return (m_strEntry == rhs.m_strEntry);
  112. }
  113. inline bool
  114. CDynamicPathEntry::operator < (const CDynamicPathEntry &rhs) const
  115. {
  116. // first order on basis of type - this is arbitrary, but establishes some
  117. // needed separation.
  118. if(m_type != rhs.m_type)
  119. return (m_type < rhs.m_type);
  120. if(m_type == NDTYP_CUSTOM)
  121. return std::lexicographical_compare(m_byteVector.begin(),
  122. m_byteVector.end(),
  123. rhs.m_byteVector.begin(),
  124. rhs.m_byteVector.end());
  125. else
  126. return m_strEntry < rhs.m_strEntry;
  127. }
  128. /*--------------------------------------------------------------------------*
  129. * InsertScalar
  130. *
  131. * Inserts a scalar value of type T into an output stream as a series of
  132. * the output stream's value_type.
  133. *--------------------------------------------------------------------------*/
  134. template<typename Container, typename T>
  135. void InsertScalar (Container& c, const T& t)
  136. {
  137. Container::const_iterator itFrom = reinterpret_cast<Container::const_iterator>(&t);
  138. std::copy (itFrom, itFrom + sizeof (t), std::back_inserter(c));
  139. }
  140. /*+-------------------------------------------------------------------------*
  141. *
  142. * CDynamicPathEntry::Write
  143. *
  144. * PURPOSE: Writes the contents of the object to a byte vector.
  145. *
  146. * PARAMETERS:
  147. * ByteVector& v :
  148. *
  149. * RETURNS:
  150. * void
  151. *
  152. *+-------------------------------------------------------------------------*/
  153. inline void
  154. CDynamicPathEntry::Write (ByteVector& v) const
  155. {
  156. // insert the type of the entry.
  157. v.push_back(m_type);
  158. if(m_type == NDTYP_STRING)
  159. {
  160. typedef const BYTE * LPCBYTE;
  161. // use byte pointers as parameters to copy so the WCHARs don't
  162. // get truncated to BYTEs as they're inserted into v
  163. LPCBYTE pbFirst = reinterpret_cast<LPCBYTE>(m_strEntry.begin());
  164. LPCBYTE pbLast = reinterpret_cast<LPCBYTE>(m_strEntry.end());
  165. // copy the text of the string (no NULL terminator)
  166. std::copy (pbFirst, pbLast, std::back_inserter (v));
  167. // append the (Unicode) terminator
  168. v.push_back (0);
  169. v.push_back (0);
  170. }
  171. else
  172. {
  173. // write the size of the byte vector
  174. SNodeID id;
  175. id.cBytes = m_byteVector.size();
  176. InsertScalar (v, id.cBytes);
  177. // write the bytes
  178. std::copy (m_byteVector.begin(), m_byteVector.end(), std::back_inserter (v));
  179. }
  180. }
  181. //############################################################################
  182. //############################################################################
  183. //
  184. // Implementation of class CBookmark
  185. //
  186. //############################################################################
  187. //############################################################################
  188. inline bool
  189. CBookmark::operator ==(const CBookmark& other) const
  190. {
  191. return ((m_idStatic == other.m_idStatic) &&
  192. (m_dynamicPath == other.m_dynamicPath));
  193. }
  194. inline bool
  195. CBookmark::operator!=(const CBookmark& other) const
  196. {
  197. return (!(*this == other));
  198. }
  199. inline bool
  200. CBookmark::operator<(const CBookmark& other) const
  201. {
  202. if (m_idStatic < other.m_idStatic)
  203. return true;
  204. if (m_idStatic == other.m_idStatic)
  205. {
  206. return std::lexicographical_compare( m_dynamicPath.begin(),
  207. m_dynamicPath.end(),
  208. other.m_dynamicPath.begin(),
  209. other.m_dynamicPath.end() );
  210. }
  211. return false;
  212. }
  213. /*+-------------------------------------------------------------------------*
  214. *
  215. * CBookmark::HBOOKMARK
  216. *
  217. * PURPOSE: Casts a bookmark into an HBOOKMARK
  218. *
  219. * RETURNS:
  220. * operator
  221. *
  222. *+-------------------------------------------------------------------------*/
  223. inline
  224. CBookmark:: operator HBOOKMARK() const
  225. {
  226. return reinterpret_cast<HBOOKMARK>(this);
  227. }
  228. /*+-------------------------------------------------------------------------*
  229. *
  230. * CBookmark::GetBookmark
  231. *
  232. * PURPOSE: Converts an HBOOKMARK to a CBookmark.
  233. *
  234. * PARAMETERS:
  235. * HBOOKMARK hbm :
  236. *
  237. * RETURNS:
  238. * CBookmark *
  239. *
  240. *+-------------------------------------------------------------------------*/
  241. inline CBookmark *
  242. CBookmark::GetBookmark(HBOOKMARK hbm)
  243. {
  244. return reinterpret_cast<CBookmark *>(hbm);
  245. }
  246. /*+-------------------------------------------------------------------------*
  247. *
  248. * CBookmark::Load
  249. *
  250. * PURPOSE:
  251. *
  252. * PARAMETERS:
  253. * IStream& stm :
  254. *
  255. * RETURNS:
  256. * inline IStream&
  257. *
  258. *+-------------------------------------------------------------------------*/
  259. inline IStream&
  260. CBookmark::Load(IStream& stm)
  261. {
  262. // loading from a stream. Convert from one of the legacy formats.
  263. // 1. Read the static node ID
  264. stm >> m_idStatic;
  265. m_dynamicPath.clear();
  266. // 2. Read the dynamic path
  267. ByteVector vDynamicPath;
  268. ByteVector::iterator iter;
  269. stm >> vDynamicPath;
  270. // 2a. If the dynamic path is empty, we're done.
  271. if(vDynamicPath.empty())
  272. return (stm);
  273. // 3. Strip out the unnecessary details like the signature, etc.
  274. // 3a. Check for a signature
  275. iter = vDynamicPath.begin();
  276. bool bIs10Path = true;
  277. if(memcmp (iter, BOOKMARK_CUSTOMSTREAMSIGNATURE,
  278. sizeof(BOOKMARK_CUSTOMSTREAMSIGNATURE)) == 0)
  279. {
  280. // throw away the signature and the following version bytes
  281. iter += (sizeof(BOOKMARK_CUSTOMSTREAMSIGNATURE) + sizeof(DWORD));
  282. bIs10Path = false; //is a post-MMC1.0 path.
  283. }
  284. // create new entries for each piece.
  285. while(iter != vDynamicPath.end())
  286. {
  287. CDynamicPathEntry entry;
  288. entry.ScInitialize(bIs10Path, iter); //NOTE: iter is an in/out parameter.
  289. m_dynamicPath.push_back(entry);
  290. }
  291. return (stm);
  292. }
  293. /*+-------------------------------------------------------------------------*
  294. *
  295. * CBookmark::Save
  296. *
  297. * PURPOSE: This function will be obsolete once XML takes over.
  298. *
  299. * PARAMETERS:
  300. * IStream& stm :
  301. *
  302. * RETURNS:
  303. * inline IStream&
  304. *
  305. *+-------------------------------------------------------------------------*/
  306. inline IStream&
  307. CBookmark::Save(IStream& stm) const
  308. {
  309. // 1. Save the static node ID
  310. stm << m_idStatic;
  311. ByteVector vDynamicPath; // used to build up the old-style bookmark structure.
  312. vDynamicPath.clear(); // initialize - probably not needed, but defensive.
  313. // Build up the dynamic path if there is one.
  314. if(!m_dynamicPath.empty())
  315. {
  316. // 2. Save the signature
  317. InsertScalar(vDynamicPath, BOOKMARK_CUSTOMSTREAMSIGNATURE);
  318. // high word = major version number, low word = minor version number
  319. const WORD wMajorVersion = 1;
  320. const WORD wMinorVersion = 0;
  321. const DWORD dwCurrentCustomStreamVersion = MAKELONG (wMinorVersion, wMajorVersion);
  322. // 3. copy the version number out.
  323. InsertScalar(vDynamicPath, dwCurrentCustomStreamVersion);
  324. // 4. Write out all the path entries into the byte vector
  325. CDynamicPath::iterator iter;
  326. for(iter = m_dynamicPath.begin(); iter != m_dynamicPath.end(); iter++)
  327. {
  328. iter->Write(vDynamicPath);
  329. }
  330. }
  331. // 5. Finally, write out the byte vector.
  332. stm << vDynamicPath;
  333. return (stm);
  334. }
  335. /*+-------------------------------------------------------------------------*
  336. *
  337. * CBookmark::Persist
  338. *
  339. * PURPOSE: Persists the bookmark
  340. *
  341. * PARAMETERS:
  342. * CPersistor & persistor :
  343. *
  344. * RETURNS:
  345. * void
  346. *
  347. *+-------------------------------------------------------------------------*/
  348. inline void
  349. CBookmark::Persist(CPersistor &persistor)
  350. {
  351. DECLARE_SC(sc, TEXT("CBookmark::Persist"));
  352. // check and persist only valid node ids
  353. if (persistor.IsStoring() && (m_idStatic == ID_Unknown))
  354. sc.Throw(E_UNEXPECTED);
  355. persistor.PersistAttribute(XML_ATTR_BOOKMARK_STATIC, m_idStatic);
  356. bool bPersistList = persistor.IsLoading() ? (persistor.HasElement(XML_ATTR_BOOKMARK_DYNAMIC_PATH, NULL)) :
  357. (m_dynamicPath.size() > 0);
  358. if (bPersistList)
  359. persistor.PersistList(XML_ATTR_BOOKMARK_DYNAMIC_PATH, NULL, m_dynamicPath);
  360. }
  361. /*+-------------------------------------------------------------------------*
  362. *
  363. * CDynamicPathEntry::Persist
  364. *
  365. * PURPOSE: Persists the dynamic path entry of the bookmark
  366. *
  367. * PARAMETERS:
  368. * CPersistor & persistor :
  369. *
  370. * RETURNS:
  371. * void
  372. *
  373. *+-------------------------------------------------------------------------*/
  374. inline void
  375. CDynamicPathEntry::Persist(CPersistor &persistor)
  376. {
  377. DECLARE_SC(sc, TEXT("CDynamicPathEntry::Persist"));
  378. if (m_type == NDTYP_STRING || persistor.IsLoading())
  379. persistor.PersistAttribute(XML_ATTR_BOOKMARK_DYN_STRING, m_strEntry, attr_optional);
  380. if (m_type == NDTYP_CUSTOM || persistor.IsLoading())
  381. {
  382. CXMLAutoBinary binData;
  383. if (persistor.IsStoring())
  384. {
  385. if (m_byteVector.size())
  386. {
  387. sc = binData.ScAlloc(m_byteVector.size());
  388. if (sc)
  389. sc.Throw();
  390. CXMLBinaryLock sLock(binData); // unlocks on destructor
  391. LPBYTE pData = NULL;
  392. sc = sLock.ScLock(&pData);
  393. if (sc)
  394. sc.Throw();
  395. std::copy(m_byteVector.begin(), m_byteVector.end(), pData);
  396. }
  397. }
  398. persistor.PersistAttribute(XML_ATTR_BOOKMARK_DYN_CUSTOM, binData, attr_optional);
  399. if (persistor.IsLoading())
  400. {
  401. m_byteVector.clear();
  402. if (binData.GetSize()) // if there is nothing to read it won't be allocated
  403. {
  404. CXMLBinaryLock sLock(binData); // unlocks on destructor
  405. LPBYTE pData = NULL;
  406. sc = sLock.ScLock(&pData);
  407. if (sc)
  408. sc.Throw();
  409. m_byteVector.assign( pData, pData + binData.GetSize() );
  410. }
  411. }
  412. }
  413. if (persistor.IsLoading())
  414. m_type = (m_strEntry.size() > 0) ? NDTYP_STRING : NDTYP_CUSTOM;
  415. }