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.

1403 lines
54 KiB

  1. #ifndef XMLBASE_H
  2. #define XMLBASE_H
  3. #pragma once
  4. #include <atlbase.h>
  5. #include <list>
  6. #include <map>
  7. #include "mmcerror.h"
  8. #include "macros.h"
  9. #include "tstring.h"
  10. #include "strings.h"
  11. #include "cstr.h"
  12. /*+-------------------------------------------------------------------------*
  13. This file contains code required to persist data using XML format.
  14. The classes defined here fall into following categories:
  15. Main persistence process engine
  16. CPersistor
  17. | this class is the working horse for XML persistence
  18. | every class supporting persistence gets the reference to
  19. | CPersistor to it's Persist method, where it implements
  20. | persisting ot their own code. Class' own code is persisted
  21. | by calling Persist* methods on persistor and passing internal
  22. | variables to them. The tree of CPersist objects is created during
  23. | persist operation (load or save) and lives only during this operation.
  24. MSXML interface wrappers:
  25. CXMLElement (wraps IXMLDOMNode interface)
  26. CXMLElementCollection (wraps IXMLDOMNodeList interface)
  27. CXMLDocument (wraps IXMLDOMDocument interface)
  28. | these wrappers add very little to the interfaces wrapped
  29. | - the throw SC type of exception instead of returning the error code
  30. | - maintain internal smart pointer to wrapped interfaces
  31. | - return error from methods if the interface has not be set
  32. base classes for classes supporting XML persistence
  33. CXMLObject - generic persistence support
  34. XMLListCollectionBase - persistence support for std::list
  35. XMLListCollectionImp - persistence support for std::list
  36. XMLMapCollectionBase - persistence support for std::map
  37. XMLMapCollection - persistence support for std::map
  38. XMLMapCollectionImp - persistence support for std::map
  39. | for object to support persistence it needs to derive from any of listed
  40. | classes (at least from CXMLObject). Other classes add some more functionality
  41. | to the derived class.
  42. Generic value persistece support
  43. CXMLValue - support for set of generic types (like int, string, etc)
  44. CXMLBoolean - support for BOOL and bool types
  45. | CXMLValue mostly used by implicit cast of the object given to
  46. | CPersistor::PersistAttribute or CPersistor::PersistContents
  47. Wrappers, adding persistence to regular types
  48. XMLPoint - persistence for POINT type
  49. XMLRect - persistence for RECT type
  50. XMLListCollectionWrap - persistence for std::list type
  51. XMLMapCollectionWrap - persistence for std::map type
  52. CXML_IStorage - persistence thru IStorage
  53. CXML_IStream - persistence thru IStream
  54. CXMLPersistableIcon - persistence for console icon
  55. CXMLVariant - persistence for CComVariant
  56. CXMLEnumeration - persistence for enumerations by literals
  57. CXMLBitFlags - persistence for bit-flags by literals
  58. | these classes usually take the reference to object they persist as
  59. | a parameter to the constructor and usually are constructed
  60. | on stack solely to persist the object and die afterwards
  61. SEE THE SAMPLE BELOW
  62. ----------------------------------------------------------------------------
  63. SAMPLE:
  64. say we have classes A, B what need to be persisted (access specifiers ommited)
  65. class A { int i; };
  66. class B { int j; A a; };
  67. and we would want to persist them in format (assume A::i = 1, B::j = 2) :
  68. <BT INDEX = "2"><AT>1</AT></BT>
  69. we need to change the classes to support persistence:
  70. class A : public CXMLObject // to inherit persistence capability
  71. { int i;
  72. DEFINE_XML_TYPE("AT") // to define the tag name
  73. virtual void
  74. Persist(CPersistor &persistor) // to implement persistence for own staff
  75. {
  76. persistor.PersistContents(i); // persist i as AT element contents
  77. }
  78. };
  79. class B : public CXMLObject // to inherit persistence capability
  80. { int j; A a;
  81. DEFINE_XML_TYPE("BT") // to define the tag name
  82. virtual void
  83. Persist(CPersistor &persistor) // to implement persistence for own staff
  84. {
  85. persistor.PersistAttribute(_T("INDEX"), j); // persist j
  86. persistor.Persist(a); // persist a
  87. }
  88. };
  89. to have it in the string we may use:
  90. B b; std::wstring xml_text;
  91. b.ScSaveToString(&xml_text);
  92. ---------------------------------------------------------------------------- */
  93. // forward declarations
  94. class CPersistor;
  95. class CXMLObject;
  96. class CXMLElement;
  97. class CXMLDocument;
  98. class CXMLValueExtension;
  99. enum XMLAttributeType
  100. {
  101. attr_required,
  102. attr_optional
  103. };
  104. // special modes for certain persistors. These can be used to pass in information about
  105. // how to persist. Not as scalable as a class hierarchy, but useful nonetheless.
  106. enum PersistorMode
  107. {
  108. persistorModeNone = 0x0000,
  109. persistorModeValueSplitEnabled = 0x0001, // used for StringTableStrings, indicates that all strings should be persisted by value
  110. persistorModeDefault = persistorModeValueSplitEnabled // the default setting
  111. };
  112. /*+-------------------------------------------------------------------------*
  113. * CONCEPT OF BINARY STORAGE
  114. *
  115. * To make xml documents more readable, a part of it (containing base64 - encoded
  116. * binary data) is stored at separate element located at the end of document.
  117. * the following sample illustrates this
  118. *
  119. * NOT_USING_BINARY_STROAGE USING_BINARY_STROAGE
  120. *
  121. * <ROOT> <ROOT>
  122. * <ELEMENT1> <ELEMENT1 BINARY_REF_INDEX="0" />
  123. * very_long_bin_data <ELEMENT2 BINARY_REF_INDEX="1" />
  124. * </ELEMENT1> .....
  125. * <ELEMENT2> <BINARY_STORAGE>
  126. * other_long_bin_data <BINARY>
  127. * </ELEMENT2> very_long_bin_data
  128. * </ROOT> </BINARY>
  129. * <BINARY>
  130. * very_long_bin_data
  131. * </BINARY>
  132. * </BINARY_STORAGE>
  133. * </ROOT>
  134. *
  135. * The decision to be saved at binary storage is made by the CXMLObject.
  136. * It informs the persistor by returning "true" from UsesBinaryStorage() method;
  137. *
  138. * In addition ( to make it locatable ) <BINARY> elements may have 'Name' attribute.
  139. * CXMLObject may supply it by returning non-NULL pointer to 'Name' attribute value
  140. * from virtual method GetBinaryEntryName().
  141. *
  142. * Storage is created / commited by methods provided in CXMLDocument
  143. *
  144. * NOTE: all mentioned methods, as well as GetXMLType() MUST return 'static' values.
  145. * To make XML document consistent, values need to be fixed [hardcoded].
  146. *+-------------------------------------------------------------------------*/
  147. /*+-------------------------------------------------------------------------*
  148. * class CXMLObject
  149. *
  150. *
  151. * PURPOSE: The basic XML persistent object. has a name and a Persist function.
  152. * When the object is persisted, an element with the name of the
  153. * object is created. The Persist function is then called with
  154. * a persistor created on the element.
  155. *
  156. *+-------------------------------------------------------------------------*/
  157. class CXMLObject
  158. {
  159. // this is overridden
  160. public:
  161. virtual LPCTSTR GetXMLType() = 0;
  162. virtual void Persist(CPersistor &persistor) = 0;
  163. // following methods are implemented by binary elements only.
  164. // leave it to this base class for most CXMLObject-derived classes.
  165. // see comment "CONCEPT OF BINARY STORAGE" above
  166. virtual bool UsesBinaryStorage() { return false; }
  167. // this is optional. Overwrite only if you REALLY NEED the name
  168. virtual LPCTSTR GetBinaryEntryName() { return NULL; }
  169. public: // implemented by CXMLObject. Do not override
  170. SC ScSaveToString(std::wstring *pString, bool bPutHeader = false); // set bPutHeader = true to write out the "?xml" tag
  171. SC ScSaveToDocument( CXMLDocument& xmlDocument );
  172. SC ScLoadFromString(LPCWSTR lpcwstrSource, PersistorMode mode = persistorModeNone);
  173. SC ScLoadFromDocument( CXMLDocument& xmlDocument );
  174. };
  175. /*+-------------------------------------------------------------------------*
  176. * MACRO DEFINE_XML_TYPE
  177. *
  178. *
  179. * PURPOSE: puts must-to-define methods to XCMLObject derived class implementation
  180. * Since xml tag is rather class attribute than object, static method
  181. * is provided to retrieve the type when object is not available
  182. * Virtual method is provided for tag to be available from gen. purpose
  183. * functions using the pointer to the base class.
  184. *
  185. * USAGE: add DEFINE_XML_TYPE(pointer_to_string)
  186. *
  187. * NOTE: 'public' access qualifier will be applied for lines following the macro
  188. *+-------------------------------------------------------------------------*/
  189. #define DEFINE_XML_TYPE(name) \
  190. public: \
  191. virtual LPCTSTR GetXMLType() { return name; } \
  192. static LPCTSTR _GetXMLType() { return name; }
  193. /*+-------------------------------------------------------------------------*
  194. * class CXMLElementCollection
  195. *
  196. *
  197. * PURPOSE: Wrapper around IXMLDOMNodeList.
  198. *
  199. * NOTE: Throws exceptions!
  200. *+-------------------------------------------------------------------------*/
  201. class CXMLElementCollection
  202. {
  203. CComQIPtr<IXMLDOMNodeList, &IID_IXMLDOMNodeList> m_sp;
  204. public:
  205. CXMLElementCollection(const CXMLElementCollection &other) { m_sp = other.m_sp; }
  206. CXMLElementCollection(IXMLDOMNodeList *ptr = NULL) { m_sp = ptr; }
  207. bool IsNull() { return m_sp == NULL; }
  208. void get_count(long *plCount);
  209. void item(LONG lIndex, CXMLElement *pElem);
  210. };
  211. /*+-------------------------------------------------------------------------*
  212. * class CXMLElement
  213. *
  214. *
  215. * PURPOSE: Wrapper around IXMLDOMNode
  216. *+-------------------------------------------------------------------------*/
  217. class CXMLElement
  218. {
  219. CComQIPtr<IXMLDOMNode, &IID_IXMLDOMNode> m_sp;
  220. public:
  221. CXMLElement(LPUNKNOWN pElem = NULL) { m_sp = pElem; }
  222. CXMLElement(const CXMLElement& elem) { m_sp = elem.m_sp; }
  223. bool IsNull() { return m_sp == NULL; }
  224. // returns indentation to ad to child element or closing tag
  225. // to have nice-looking document. indentation depends on element depth
  226. bool GetTextIndent(CComBSTR& bstrIndent, bool bForAChild);
  227. void get_tagName(CStr &strTagName);
  228. void get_parent(CXMLElement * pParent);
  229. void setAttribute(const CStr &strPropertyName, const CComBSTR &bstrPropertyValue);
  230. bool getAttribute(const CStr &strPropertyName, CComBSTR &bstrPropertyValue);
  231. void removeAttribute(const CStr &strPropertyName);
  232. void get_children(CXMLElementCollection *pChildren);
  233. void get_type(DOMNodeType *pType);
  234. void get_text(CComBSTR &bstrContent);
  235. void addChild(CXMLElement& rChildElem);
  236. void removeChild(CXMLElement& rChildElem);
  237. void replaceChild(CXMLElement& rNewChildElem, CXMLElement& rOldChildElem);
  238. void getNextSibling(CXMLElement * pNext);
  239. void getChildrenByName(LPCTSTR strTagName, CXMLElementCollection *pChildren);
  240. void put_text(BSTR bstrValue);
  241. };
  242. /*+-------------------------------------------------------------------------*
  243. * class CXMLDocument
  244. *
  245. *
  246. * PURPOSE: Wrapper class for IXMLDOMDocument
  247. *
  248. *+-------------------------------------------------------------------------*/
  249. class CXMLDocument
  250. {
  251. CComQIPtr<IXMLDOMDocument, &IID_IXMLDOMDocument> m_sp;
  252. public:
  253. CXMLDocument& operator = (IXMLDOMDocument *pDoc) { m_sp = pDoc; return *this; }
  254. bool IsNull() { return m_sp == NULL; }
  255. operator CXMLElement() { return CXMLElement(m_sp); }
  256. void get_root(CXMLElement *pElem);
  257. void createElement(DOMNodeType type, BSTR bstrTag, CXMLElement *pElem);
  258. // members to maintain the binary storage
  259. // see comment "CONCEPT OF BINARY STORAGE" above
  260. // used on storing (at top level, prior to persisting)
  261. // - creates an element for storing binary stuff
  262. void CreateBinaryStorage();
  263. // used on loading (at top level, prior to persisting)
  264. // - locates an element to be used for loading binary stuff
  265. void LocateBinaryStorage();
  266. // used on storing (at top level, after persisting the main staff)
  267. // - attaches the binary strage as the last child element of elemParent
  268. void CommitBinaryStorage();
  269. // returns element representing binary storage. Used from CPersistor
  270. CXMLElement GetBinaryStorage() { return m_XMLElemBinaryStorage; }
  271. SC ScCoCreate(bool bPutHeader);
  272. SC ScLoad(LPCWSTR strSource);
  273. SC ScLoad(IStream *pStream, bool bSilentOnErrors = false );
  274. SC ScSaveToFile(LPCTSTR lpcstrFileName);
  275. SC ScSave(CComBSTR &bstrResult);
  276. private:
  277. // element representing binary storage
  278. CXMLElement m_XMLElemBinaryStorage;
  279. };
  280. /*+-------------------------------------------------------------------------*
  281. * class CXMLBinary
  282. *
  283. *
  284. * PURPOSE: GetGlobalSize() is alway rounded to allocation units,
  285. * so to know the actual size of the memory blob, we need to
  286. * carry the size information with HGLOBAL.
  287. * This struct is solely to bind these guys
  288. *+-------------------------------------------------------------------------*/
  289. class CXMLBinary
  290. {
  291. public:
  292. CXMLBinary();
  293. CXMLBinary(HGLOBAL handle, size_t size);
  294. ~CXMLBinary() { Detach(); }
  295. void Attach(HGLOBAL handle, size_t size);
  296. HGLOBAL Detach();
  297. size_t GetSize() const;
  298. HGLOBAL GetHandle() const;
  299. SC ScAlloc(size_t size, bool fZeroInit = false);
  300. SC ScRealloc(size_t new_size, bool fZeroInit = false);
  301. SC ScFree();
  302. SC ScLockData(const void **ppData) const;
  303. SC ScLockData(void **ppData) { return ScLockData(const_cast<const void **>(ppData)); }
  304. SC ScUnlockData() const;
  305. protected:
  306. // implementation helpers
  307. private: // not implemented
  308. CXMLBinary(const CXMLBinary&); // not implemented; not allowed;
  309. operator = (CXMLBinary&); // not implemented; not allowed;
  310. private:
  311. HGLOBAL m_Handle;
  312. size_t m_Size;
  313. mutable unsigned m_Locks;
  314. };
  315. /*+-------------------------------------------------------------------------*
  316. * class CXMLAutoBinary
  317. *
  318. *
  319. * PURPOSE: same as CXMLAutoBinary, but frees the memory on destruction
  320. *+-------------------------------------------------------------------------*/
  321. class CXMLAutoBinary : public CXMLBinary
  322. {
  323. public:
  324. CXMLAutoBinary() : CXMLBinary() {}
  325. CXMLAutoBinary(HGLOBAL handle, size_t size) : CXMLBinary(handle, size) {}
  326. ~CXMLAutoBinary() { ScFree(); }
  327. };
  328. /*+-------------------------------------------------------------------------*
  329. * class CXMLBinaryLock
  330. *
  331. *
  332. * PURPOSE: provides data locking functionality which is automatically removed
  333. * in destructor
  334. *+-------------------------------------------------------------------------*/
  335. class CXMLBinaryLock
  336. {
  337. public:
  338. CXMLBinaryLock(CXMLBinary& binary);
  339. ~CXMLBinaryLock();
  340. template<typename T>
  341. SC ScLock(T **ppData)
  342. {
  343. return ScLockWorker(reinterpret_cast<void**>(ppData));
  344. }
  345. SC ScUnlock();
  346. private: // not implemented
  347. CXMLBinaryLock(const CXMLBinaryLock&); // not implemented; not allowed;
  348. operator = (CXMLBinaryLock&); // not implemented; not allowed;
  349. private:
  350. SC ScLockWorker(void **ppData);
  351. bool m_bLocked;
  352. CXMLBinary& m_rBinary;
  353. };
  354. /*+-------------------------------------------------------------------------*
  355. * class CXMLValue
  356. *
  357. *
  358. * PURPOSE: Holds any type of value, in the spirit of a variant, except
  359. * that a pointer to the original object is kept. This allows
  360. * reading as well as writing to occur on the original object.
  361. *
  362. *+-------------------------------------------------------------------------*/
  363. class CXMLValue
  364. {
  365. friend class CXMLBoolean;
  366. enum XMLType
  367. {
  368. XT_I4, //LONG
  369. XT_UI4, //ULONG
  370. XT_UI1, //BYTE
  371. XT_I2, //SHORT
  372. XT_DW, //DWORD
  373. XT_BOOL,//BOOL
  374. XT_CPP_BOOL,//bool
  375. XT_UINT,//UINT
  376. XT_INT, //INT
  377. XT_STR, //CStr
  378. XT_WSTR, // std::wstr
  379. XT_TSTR, // tstring
  380. XT_GUID, // GUID
  381. XT_BINARY, //HGLOBAL - unparsable data
  382. XT_EXTENSION
  383. };
  384. const XMLType m_type;
  385. union
  386. {
  387. LONG * pL;
  388. ULONG * pUl;
  389. BYTE * pByte;
  390. SHORT * pS;
  391. DWORD * pDw;
  392. UINT * pUint;
  393. INT * pInt;
  394. CStr * pStr;
  395. std::wstring * pWStr;
  396. tstring * pTStr;
  397. GUID * pGuid;
  398. CXMLBinary * pXmlBinary;
  399. bool * pbool;
  400. BOOL * pBOOL;
  401. CXMLValueExtension * pExtension;
  402. } m_val;
  403. // private constructor. used by friend class CXMLBoolean
  404. CXMLValue(XMLType type) : m_type(type) { }
  405. public:
  406. CXMLValue(const CXMLValue &v) : m_type(v.m_type), m_val(v.m_val) { }
  407. CXMLValue(LONG &l) : m_type(XT_I4) { m_val.pL=&l; }
  408. CXMLValue(ULONG &ul) : m_type(XT_UI4) { m_val.pUl=&ul; }
  409. CXMLValue(BYTE &b) : m_type(XT_UI1) { m_val.pByte=&b; }
  410. CXMLValue(SHORT &s) : m_type(XT_I2) { m_val.pS=&s; }
  411. CXMLValue(UINT &u) : m_type(XT_UINT) { m_val.pUint=&u; }
  412. CXMLValue(INT &i) : m_type(XT_INT) { m_val.pInt=&i; }
  413. CXMLValue(CStr &str) : m_type(XT_STR) { m_val.pStr=&str; }
  414. CXMLValue(std::wstring &str) : m_type(XT_WSTR) { m_val.pWStr=&str; }
  415. CXMLValue(GUID &guid) : m_type(XT_GUID) { m_val.pGuid = &guid; }
  416. CXMLValue(CXMLBinary &binary) : m_type(XT_BINARY) { m_val.pXmlBinary = &binary; }
  417. CXMLValue(tstring &tstr) : m_type(XT_TSTR) { m_val.pTStr = &tstr; }
  418. CXMLValue(CXMLValueExtension& ext) : m_type(XT_EXTENSION) { m_val.pExtension = &ext; }
  419. SC ScReadFromBSTR(const BSTR bstr); // read input into the underlying variable.
  420. SC ScWriteToBSTR (BSTR * pbstr ) const; // writes the value into provided string
  421. LPCTSTR GetTypeName() const;
  422. // The following method is called when value is persisted as stand-alone element.
  423. // Depending on the result returned the contents may go to Binary Storage
  424. // see comment "CONCEPT OF BINARY STORAGE" above
  425. bool UsesBinaryStorage() const { return m_type == XT_BINARY; }
  426. };
  427. /*+-------------------------------------------------------------------------*
  428. * CXMLBoolean
  429. *
  430. *
  431. * PURPOSE: special case: booleans. Need to be printed as true/false, NOT as integer.
  432. *
  433. *+-------------------------------------------------------------------------*/
  434. class CXMLBoolean : public CXMLValue
  435. {
  436. public:
  437. CXMLBoolean(BOOL &b) : CXMLValue(XT_BOOL) { m_val.pBOOL = &b;}
  438. CXMLBoolean(bool &b) : CXMLValue(XT_CPP_BOOL) { m_val.pbool = &b;}
  439. };
  440. /*+-------------------------------------------------------------------------*
  441. * CXMLValueExtension
  442. *
  443. *
  444. * PURPOSE: interface to extend CXMLValue by more sophisticated types
  445. *
  446. *+-------------------------------------------------------------------------*/
  447. class CXMLValueExtension
  448. {
  449. public:
  450. virtual SC ScReadFromBSTR(const BSTR bstr) = 0; // read input into the underlying variable.
  451. virtual SC ScWriteToBSTR (BSTR * pbstr ) const = 0; // writes the value into provided string
  452. virtual LPCTSTR GetTypeName() const = 0;
  453. };
  454. /*+-------------------------------------------------------------------------*
  455. * class EnumLiteral
  456. *
  457. *
  458. * PURPOSE: to define enum-to-literal mapping arrays (used by CXMLEnumeration)
  459. *
  460. *+-------------------------------------------------------------------------*/
  461. struct EnumLiteral
  462. {
  463. UINT m_enum;
  464. LPCTSTR m_literal;
  465. };
  466. /*+-------------------------------------------------------------------------*
  467. * class CXMLEnumeration
  468. *
  469. *
  470. * PURPOSE: to persist enumeration as string literal
  471. * using array of enum-to-literal mappings
  472. *
  473. *+-------------------------------------------------------------------------*/
  474. class CXMLEnumeration : public CXMLValueExtension
  475. {
  476. // just an enum sized type to hold reference
  477. // while many enum types will be used, internally they
  478. // will be cast to this type
  479. enum enum_t { JUST_ENUM_SIZE_VALUE };
  480. public:
  481. // template constructor to allow different enums to be persisted
  482. template<typename _ENUM>
  483. CXMLEnumeration(_ENUM& en, const EnumLiteral * const etols, size_t count)
  484. : m_pMaps(etols) , m_count(count), m_rVal((enum_t&)(en))
  485. {
  486. // folowing lines won't compile in case you are trying to pass
  487. // type other than enum or int
  488. COMPILETIME_ASSERT( sizeof(en) == sizeof(enum_t) );
  489. UINT testit = en;
  490. }
  491. // CXMLValueExtension metods required to implement
  492. SC ScReadFromBSTR(const BSTR bstr); // read input into the underlying variable.
  493. SC ScWriteToBSTR (BSTR * pbstr ) const; // writes the value into provided string
  494. LPCTSTR GetTypeName() const { return _T("Enumerations"); }
  495. // to enable passing itself as CMLValue
  496. operator CXMLValue ()
  497. {
  498. return CXMLValue (*this);
  499. }
  500. private:
  501. enum_t &m_rVal;
  502. const EnumLiteral * const m_pMaps;
  503. const size_t m_count;
  504. };
  505. /*+-------------------------------------------------------------------------*
  506. * class CXMLBitFlags
  507. *
  508. *
  509. * PURPOSE: to persist bit flags as string literals
  510. * using array of enum-to-literal mappings
  511. *
  512. *+-------------------------------------------------------------------------*/
  513. class CXMLBitFlags
  514. {
  515. public:
  516. // template constructor to allow different enums to be persisted
  517. template<typename _integer>
  518. CXMLBitFlags(_integer& flags, const EnumLiteral * const etols, size_t count)
  519. : m_pMaps(etols) , m_count(count), m_rVal((UINT&)flags)
  520. {
  521. // folowing lines won't compile in case you are trying to pass
  522. // type other than enum or int
  523. COMPILETIME_ASSERT( sizeof(flags) == sizeof(UINT) );
  524. UINT testit = flags;
  525. }
  526. void PersistMultipleAttributes(LPCTSTR name, CPersistor &persistor);
  527. private:
  528. UINT &m_rVal;
  529. const EnumLiteral * const m_pMaps;
  530. const size_t m_count;
  531. };
  532. /*+-------------------------------------------------------------------------*
  533. * class XMLPoint
  534. *
  535. *
  536. * PURPOSE: Holds the name and value of a point object
  537. *
  538. *+-------------------------------------------------------------------------*/
  539. class XMLPoint : public CXMLObject
  540. {
  541. CStr m_strObjectName;
  542. POINT & m_point;
  543. public:
  544. XMLPoint(const CStr& strObjectName, POINT &point);
  545. DEFINE_XML_TYPE(XML_TAG_POINT);
  546. virtual void Persist(CPersistor &persistor);
  547. };
  548. /*+-------------------------------------------------------------------------*
  549. * class XMLRect
  550. *
  551. *
  552. * PURPOSE: Holds the name and value of a rectangle object
  553. *
  554. *+-------------------------------------------------------------------------*/
  555. class XMLRect : public CXMLObject
  556. {
  557. CStr m_strObjectName;
  558. RECT & m_rect;
  559. public:
  560. XMLRect(const CStr strObjectName, RECT &rect);
  561. DEFINE_XML_TYPE(XML_TAG_RECTANGLE);
  562. virtual void Persist(CPersistor &persistor);
  563. };
  564. /*+-------------------------------------------------------------------------*
  565. * class XMLListCollectionBase
  566. *
  567. *
  568. * PURPOSE: Defines the base list collection class for persisting stl:list's
  569. * It's intended to be used as a base for deriving list persitence classes
  570. * Persist method implements "load" by iterating thru xml elements
  571. * and calling OnNewElement for each, and can be reused by derived classes.
  572. *
  573. * USAGE: Probably the better idea is to use XMLListColLectionImp
  574. * as a base to your collection instead of this class (it is richer). Use this class
  575. * only if your class has special items which does not allow you to use that class.
  576. *
  577. *+-------------------------------------------------------------------------*/
  578. class XMLListCollectionBase: public CXMLObject
  579. {
  580. public:
  581. // function called when new element is to be created and loaded
  582. virtual void OnNewElement(CPersistor& persistor) = 0;
  583. virtual void Persist(CPersistor& persistor);
  584. };
  585. /*+-------------------------------------------------------------------------*
  586. * class XMLListCollectionImp
  587. *
  588. * PURPOSE: A base class for stl::list derived collections implementing persitence of
  589. * the list items as linear sequence of xml items.
  590. * The items kept in the list must be either CXMLObject-derived or be
  591. * of the simple type (one accepted by CXMLVBalue constructors)
  592. *
  593. * USAGE: Derive your class from XMLListCollectionImp parametrized by the list,
  594. * instead of deriving from stl::list directly. use DEFINE_XML_TYPE
  595. * to define tag name for collections element.
  596. *
  597. * NOTE: Your class should implement: GetXMLType() to be functional.
  598. * you can use DEFINE_XML_TYPE macro to do it for you
  599. *
  600. * NOTE: if provided implementation does not fit for you - f.i. your elements need
  601. * a parameter to the constructor, or special initialization,
  602. * use XMLListCollectionBase instead and provide your own methods
  603. *+-------------------------------------------------------------------------*/
  604. template<class LT>
  605. class XMLListCollectionImp: public XMLListCollectionBase , public LT
  606. {
  607. typedef LT::iterator iter_t;
  608. public:
  609. virtual void Persist(CPersistor& persistor)
  610. {
  611. if (persistor.IsStoring())
  612. {
  613. for(iter_t it = begin(); it != end(); ++it)
  614. persistor.Persist(*it);
  615. }
  616. else
  617. {
  618. clear();
  619. // let the base class do the job
  620. // it will call OnNewElement for every element found
  621. XMLListCollectionBase::Persist(persistor);
  622. }
  623. }
  624. // method called to create and load new element
  625. virtual void OnNewElement(CPersistor& persistor)
  626. {
  627. iter_t it = insert(end());
  628. persistor.Persist(*it);
  629. }
  630. };
  631. /*+-------------------------------------------------------------------------*
  632. * class XMLListCollectionWrap
  633. *
  634. * PURPOSE: A wrapper around stl::list to support persisting
  635. * To be used to persist stl::list objects "from outside" - i.e. without
  636. * deriving the list class from persistence-enabled classes.
  637. *
  638. * USAGE: If you have list m_l to persist, create the object XMLListCollectionWrap wrap(m_l,"tag")
  639. * on the stack and persist that object (f.i. Persistor.Persist(wrap)
  640. *
  641. * NOTE: if provided implementation does not fit for you - see if you can use
  642. * XMLListCollectionImp or XMLListCollectionBase as a base for your list.
  643. *+-------------------------------------------------------------------------*/
  644. template<class LT>
  645. class XMLListCollectionWrap: public XMLListCollectionBase
  646. {
  647. typedef LT::iterator iter_t;
  648. LT & m_l;
  649. CStr m_strListType;
  650. public:
  651. XMLListCollectionWrap(LT &l, const CStr &strListType)
  652. : m_l(l), m_strListType(strListType) {}
  653. virtual void Persist(CPersistor& persistor)
  654. {
  655. if (persistor.IsStoring())
  656. {
  657. for(iter_t it = m_l.begin(); it != m_l.end(); ++it)
  658. persistor.Persist(*it);
  659. }
  660. else
  661. {
  662. m_l.clear();
  663. // let the base class do the job
  664. // it will call OnNewElement for every element found
  665. XMLListCollectionBase::Persist(persistor);
  666. }
  667. }
  668. // method called to create and load new element
  669. virtual void OnNewElement(CPersistor& persistor)
  670. {
  671. iter_t it = m_l.insert(m_l.end());
  672. persistor.Persist(*it);
  673. }
  674. virtual LPCTSTR GetXMLType() {return m_strListType;}
  675. private:
  676. // to prevent ivalid actions on object
  677. XMLListCollectionWrap(const XMLListCollectionWrap& other);
  678. XMLListCollectionWrap& operator = ( const XMLListCollectionWrap& other ) { return *this; }
  679. };
  680. /*+-------------------------------------------------------------------------*
  681. * class XMLMapCollectionBase
  682. *
  683. *
  684. * PURPOSE: Defines the base map collection class for persisting stl:map's
  685. * It's intended to be used as a base for deriving map persitence classes.
  686. * Persist method implements "load" by iterating thru xml elements
  687. * and calling OnNewElement for each pair, and can be reused by derived classes.
  688. *
  689. * USAGE: Probably the better idea is to use XMLMapCollection or XMLMapColLectionImp
  690. * as a base to your collection instead of this class (they are richer). Use this class
  691. * only if your class has special items which does not allow you to use those classes.
  692. *
  693. *+-------------------------------------------------------------------------*/
  694. class XMLMapCollectionBase: public CXMLObject
  695. {
  696. public:
  697. // function called when new element is to be created and loaded
  698. virtual void OnNewElement(CPersistor& persistKey,CPersistor& persistVal) = 0;
  699. // base implementation [loading only!] enumerates elements calling OnNewElement for each
  700. virtual void Persist(CPersistor& persistor);
  701. };
  702. /*+-------------------------------------------------------------------------*
  703. * class XMLMapCollection
  704. *
  705. * PURPOSE: Use this class only when you cannot use XMLMapCollectionImp due to
  706. * special requirements on construction of the elements kept in the map
  707. * (see also purpose of XMLMapCollectionImp)
  708. *
  709. * USAGE: Derive your class from XMLMapCollection parametrized by the map,
  710. * instead of deriving from stl::map directly. use DEFINE_XML_TYPE
  711. * to define tag name for collections element. Define OnNewElement
  712. *
  713. * NOTE: Your class should implement: GetXMLType() to be functional.
  714. * you can use DEFINE_XML_TYPE macro to do it for you
  715. *
  716. * NOTE: Your class should implement: OnNewElement to be functional.
  717. *
  718. * NOTE: if provided implementation does not fit for you -
  719. * use XMLMapCollectionBase instead and provide your own methods
  720. *+-------------------------------------------------------------------------*/
  721. template<class MT>
  722. class XMLMapCollection: public XMLMapCollectionBase, public MT
  723. {
  724. typedef MT::iterator iter_t;
  725. public:
  726. virtual void Persist(CPersistor& persistor)
  727. {
  728. if (persistor.IsStoring())
  729. {
  730. for(iter_t it = begin(); it != end(); ++it)
  731. {
  732. MT::key_type *pKey = const_cast<MT::key_type*>(&it->first);
  733. persistor.Persist(*pKey);
  734. persistor.Persist(it->second);
  735. }
  736. }
  737. else
  738. {
  739. clear();
  740. XMLMapCollectionBase::Persist(persistor);
  741. }
  742. }
  743. };
  744. /*+-------------------------------------------------------------------------*
  745. * class XMLMapCollectionImp
  746. *
  747. * PURPOSE: A base class for stl::map derived collections implementing persitence of
  748. * the map items as linear sequence of xml items.
  749. * The items kept in the map must be either CXMLObject-derived or be
  750. * of the simple type (one accepted by CXMLVBalue constructors)
  751. *
  752. * USAGE: Derive your class from XMLMapCollectionImp parametrized by the map,
  753. * instead of deriving from stl::map directly. use DEFINE_XML_TYPE
  754. * to define tag name for collections element.
  755. *
  756. * NOTE: Your class should implement: GetXMLType() to be functional.
  757. * you can use DEFINE_XML_TYPE macro to do it for you
  758. *
  759. * NOTE: if provided implementation does not fit for you - f.i. your elements need
  760. * a parameter to the constructor, or special initialization,
  761. * use XMLMapCollection or XMLMapCollectionBase instead and provide your own methods
  762. *+-------------------------------------------------------------------------*/
  763. template<class MT>
  764. class XMLMapCollectionImp: public XMLMapCollection<MT>
  765. {
  766. public:
  767. virtual void OnNewElement(CPersistor& persistKey,CPersistor& persistVal)
  768. {
  769. MT::key_type key;
  770. persistKey.Persist(key);
  771. MT::referent_type val;
  772. persistVal.Persist(val);
  773. insert(MT::value_type(key,val));
  774. }
  775. };
  776. /*+-------------------------------------------------------------------------*
  777. * class XMLListCollectionWrap
  778. *
  779. * PURPOSE: A wrapper around stl::map to support persisting
  780. * To be used to persist stl::map objects "from outside" - i.e. without
  781. * deriving the map class from persistence-enabled classes.
  782. *
  783. * USAGE: If you have map m_m to persist, create the object XMLMapCollectionWrap wrap(m_m,"tag")
  784. * on the stack and persist that object (f.i. Persistor.Persist(wrap)
  785. *
  786. * NOTE: if provided implementation does not fit for you - see if you can use
  787. * XMLMapCollection or XMLMapCollectionImp or XMLMapCollectionBase as a base for your map
  788. *+-------------------------------------------------------------------------*/
  789. template<class MT>
  790. class XMLMapCollectionWrap: public XMLMapCollectionBase
  791. {
  792. typedef MT::iterator iter_t;
  793. MT & m_m;
  794. CStr m_strMapType;
  795. public:
  796. XMLMapCollectionWrap(MT &m, const CStr &strMapType) : m_m(m), m_strMapType(strMapType) {}
  797. virtual void OnNewElement(CPersistor& persistKey,CPersistor& persistVal)
  798. {
  799. MT::key_type key;
  800. persistKey.Persist(key);
  801. MT::referent_type val;
  802. persistVal.Persist(val);
  803. m_m.insert(MT::value_type(key,val));
  804. }
  805. virtual void Persist(CPersistor& persistor)
  806. {
  807. if (persistor.IsStoring())
  808. {
  809. for(iter_t it = m_m.begin(); it != m_m.end(); ++it)
  810. {
  811. MT::key_type *pKey = const_cast<MT::key_type*>(&it->first);
  812. persistor.Persist(*pKey);
  813. persistor.Persist(it->second);
  814. }
  815. }
  816. else
  817. {
  818. m_m.clear();
  819. XMLMapCollectionBase::Persist(persistor);
  820. }
  821. }
  822. virtual LPCTSTR GetXMLType() {return m_strMapType;}
  823. private:
  824. // to prevent ivalid actions on object
  825. XMLMapCollectionWrap(const XMLMapCollectionWrap& other);
  826. XMLMapCollectionWrap& operator = ( const XMLMapCollectionWrap& other ) { return *this; }
  827. };
  828. /*+-------------------------------------------------------------------------*
  829. * class CPersistor
  830. *
  831. *
  832. * PURPOSE: Defines the Persistor class used for XML serialization
  833. * Persistors are aware if the file is being loaded or saved. Thus,
  834. * methods like Persist work for both directions, and
  835. * uses references to the data being persisted.
  836. *
  837. * USAGE: 1) a persistor can be created "underneath" another persistor, using
  838. * the appropriate constructor.
  839. * 2) To make an object persistable, derive it from CXMLObject, and
  840. * implement the abstract methods. The syntax persistor.Persits(object)
  841. * will then automatically work correctly.
  842. * 3) To persist an element use Pesist method. It will create new / locate
  843. * CPersist object for an element (under this persistor's element)
  844. * 4) Collection classes when persisting their members specify "bLockedOnChild"
  845. * constructors parameter as "true". This technique changes persistor's
  846. * behavior. Insted of loacting the element (#3), constructor of new
  847. * persistor will only check if element pointed by parent is of required type.
  848. *
  849. * NOTES: 1) StringTableStrings can be saved with either the ID inline or the
  850. * actual string value inline. The latter is useful when loading/saving
  851. * XML to/from a string instead of a file. This is controlled by the
  852. * EnableValueSplit method.
  853. * Binary storage usage is also controlled by it
  854. *+-------------------------------------------------------------------------*/
  855. class CPersistor
  856. {
  857. // NOTE: if member variable is to be inherited by child persistors,
  858. // don't forget to add it to CPersistor::BecomeAChildOf method
  859. CXMLDocument m_XMLDocument;
  860. CXMLElement m_XMLElemCurrent;
  861. bool m_bIsLoading;
  862. bool m_bLockedOnChild;
  863. DWORD m_dwModeFlags; // any special modes
  864. private:
  865. void SetMode(PersistorMode mode, bool bEnable) {m_dwModeFlags = (m_dwModeFlags & ~mode) | (bEnable ? mode : 0);}
  866. bool IsModeSet(PersistorMode mode) {return (m_dwModeFlags & mode);}
  867. public:
  868. void SetMode(PersistorMode mode) {m_dwModeFlags = mode;}
  869. public:
  870. // construct a persistor from a parent persistor.
  871. // this creates a new XML element with the given name,
  872. // and everything persisted to the new persistor
  873. // is persisted under this element.
  874. CPersistor(CPersistor &persistorParent, const CStr &strElementType, LPCTSTR szElementName = NULL);
  875. // construct a new persistor for given document and root element
  876. // everything persisted to the new persistor
  877. // is persisted under this element.
  878. CPersistor(CXMLDocument &document, CXMLElement& rElemRoot);
  879. // used to create child persistor on particular element
  880. // bLockedOnChild is used to create a "fake parent" persistor, which
  881. // will always return the child without trying to locate it (pElemCurrent)
  882. CPersistor(CPersistor &other, CXMLElement& rElemCurrent, bool bLockedOnChild = false);
  883. CXMLDocument & GetDocument() {return (m_XMLDocument);}
  884. CXMLElement & GetCurrentElement() {return (m_XMLElemCurrent);}
  885. bool HasElement(const CStr &strElementType, LPCTSTR szstrElementName);
  886. void EnableValueSplit (bool bEnable) { SetMode(persistorModeValueSplitEnabled, bEnable); }
  887. // the various modes
  888. bool FEnableValueSplit() {return IsModeSet(persistorModeValueSplitEnabled);}
  889. // Load/Store mode related functions.
  890. bool IsLoading() {return m_bIsLoading;}
  891. bool IsStoring() {return !m_bIsLoading;}
  892. void SetLoading(bool b) {m_bIsLoading = b;}
  893. // special methods to set/get the Name attribute of a persistor
  894. void SetName(const CStr & strName);
  895. CStr GetName();
  896. // Canned persistence methods:
  897. // .. to persist CXMLObject-derived object under own sub-element
  898. // <this><object_tag>object_body</object_tag></this>
  899. void Persist(CXMLObject &object, LPCTSTR lpstrName = NULL);
  900. // .. to persist value of the simple type under own sub-element
  901. // <this><value_type value="value"/></this>
  902. void Persist(CXMLValue xval, LPCTSTR name = NULL);
  903. // .. to persist value as named attribute of this element
  904. // <this name="value"/>
  905. void PersistAttribute(LPCTSTR name,CXMLValue xval,const XMLAttributeType type = attr_required);
  906. // .. to persist value as contents of this element
  907. // <this>value</this>
  908. // NOTE: xml element cannot have both value-as-contents and sub-elements
  909. void PersistContents(CXMLValue xval);
  910. // .. to persist flags as separate attributes
  911. void PersistAttribute( LPCTSTR name, CXMLBitFlags& flags );
  912. /***************************************************************************\
  913. *
  914. * METHOD: CPersistor::PersistList
  915. *
  916. * PURPOSE: it is designated for persisting std::list type of collections
  917. * as a subelement of the persistor.
  918. * NOTE: list elements need to be either CXMLObject-derived or be
  919. * of the simple type (one accepted by CXMLVBalue constructors)
  920. * NOTE2: list elements must have default constuctor available
  921. *
  922. * PARAMETERS:
  923. * const CStr &strListType - [in] tag of new subelement
  924. * LPCTSTR name - [in] name attr. of new subelement (NULL == none)
  925. * std::list<T,Al>& val - [in] list to be persisted
  926. *
  927. * RETURNS:
  928. * void
  929. *
  930. \***************************************************************************/
  931. template<class T, class Al>
  932. void PersistList(const CStr &strListType, LPCTSTR name,std::list<T,Al>& val)
  933. {
  934. typedef std::list<T,Al> LT;
  935. XMLListCollectionWrap<LT> lcol(val,strListType);
  936. Persist(lcol, name);
  937. }
  938. /***************************************************************************\
  939. *
  940. * METHOD: PersistMap
  941. *
  942. * PURPOSE: it is designated for persisting std::map type of collections
  943. * as a subelement of the persistor.
  944. * NOTE: map elements (both key and val) need to be either CXMLObject-derived
  945. * or be of the simple type (one accepted by CXMLVBalue constructors)
  946. * NOTE2: map elements must have default constuctor available
  947. *
  948. * PARAMETERS:
  949. * const CStr &strListType - [in] tag of new subelement
  950. * LPCTSTR name - [in] name attr. of new subelement (NULL == none)
  951. * std::map<K,T,Pr,Al>& val - [in] map to be persisted
  952. *
  953. * RETURNS:
  954. * void
  955. *
  956. \***************************************************************************/
  957. template<class K, class T, class Pr, class Al>
  958. void PersistMap(const CStr &strMapType, LPCTSTR name, std::map<K, T, Pr, Al>& val)
  959. {
  960. typedef std::map<K, T, Pr, Al> MT;
  961. XMLMapCollectionWrap<MT> mcol(val,strMapType);
  962. Persist(mcol, name);
  963. }
  964. void PersistString(LPCTSTR lpstrName, CStringTableStringBase &str);
  965. private: // private implementation helpers
  966. // common constructor, not to be used from outside.
  967. // provided as common place for member initialization
  968. // all the constructors should call it prior to doing anything specific.
  969. void CommonConstruct();
  970. // element creation / locating
  971. CXMLElement AddElement(const CStr &strElementType, LPCTSTR szElementName);
  972. CXMLElement GetElement(const CStr &strElementType, LPCTSTR szstrElementName, int iIndex = -1);
  973. void AddTextElement(BSTR bstrData);
  974. void GetTextElement(CComBSTR &bstrData);
  975. CXMLElement CheckCurrentElement(const CStr &strElementType, LPCTSTR szstrElementName);
  976. void BecomeAChildOf(CPersistor &persistorParent, CXMLElement elem);
  977. };
  978. /*+-------------------------------------------------------------------------*
  979. * class CXML_IStorage
  980. *
  981. * PURPOSE: This class provides memory-based implementation of IStorage plus
  982. * it supports persisting the data on the storage to/from XML.
  983. * Mostly used to create IStorage for snapin data to be saved
  984. * to console file as XML binary blob
  985. *
  986. * USAGE: You will create the object whenever you need a memory-based IStorage
  987. * implementation. To access IStorage interface use GetIStorage() method.
  988. * It will create a storage if does not have one under control already.
  989. * You will use returned pointer for Read and Write operations.
  990. * Whenever required you will pass the object to CPersistor::Persist method
  991. * to have it persisted using XML persistence model.
  992. *
  993. * NOTE: You are encoureged to use GetIStorage() for accessing the undelying IStorage.
  994. * Do not cache returned pointer, since the storage may change when persisted
  995. * from XML, and this invalidates the pointer. However if you AddRef,
  996. * the pointer will be valid as long as the last reference is released.
  997. * That means it may outlive CXML_IStorage object itself - nothing wrong with that.
  998. * You only must be aware that once persistence (loading) from XML is completed,
  999. * CXML_IStorage will switch to the new storage and it will not be in sync with
  1000. * the pointer you have. Always use GetIStorage() to get the current pointer.
  1001. *
  1002. *+-------------------------------------------------------------------------*/
  1003. class CXML_IStorage : public CXMLObject
  1004. {
  1005. public: // interface methods not throwing any exceptions
  1006. SC ScInitializeFrom( IStorage *pSource );
  1007. SC ScInitialize(bool& bCreatedNewOne);
  1008. SC ScGetIStorage( IStorage **ppStorage );
  1009. SC ScRequestSave(IPersistStorage * pPersistStorage);
  1010. // instruct to persist to binary storage
  1011. virtual bool UsesBinaryStorage() { return true; }
  1012. DEFINE_XML_TYPE(XML_TAG_ISTORAGE);
  1013. public: // interface methods throwing SC's
  1014. virtual void Persist(CPersistor &persistor);
  1015. private:
  1016. IStoragePtr m_Storage;
  1017. ILockBytesPtr m_LockBytes;
  1018. // following methods\data is for trace support in CHK builds
  1019. #ifdef DBG
  1020. public:
  1021. DBG_PersistTraceData m_dbg_Data;
  1022. #endif // #ifdef DBG
  1023. }; // class CXML_IStorage
  1024. /*+-------------------------------------------------------------------------*
  1025. * class CXML_IStream
  1026. *
  1027. * PURPOSE: This class provides memory-based implementation of IStream plus
  1028. * it supports persisting the data on the stream to/from XML.
  1029. * Mostly used to create IStream for snapin data to be saved
  1030. * to console file as XML binary blob
  1031. *
  1032. * USAGE: You will create the object whenever you need a memory-based IStream
  1033. * implementation. To access IStream interface use GetIStream() method.
  1034. * It will create a stream if does not have one under control already.
  1035. * You will use returned pointer for Read and Write operations.
  1036. * Whenever required you will pass the object to CPersistor::Persist method
  1037. * to have it persisted using XML persistence model.
  1038. *
  1039. * NOTE: You are encoureged to use GetIStream() for accessing the undelying IStream.
  1040. * Do not cache returned pointer, since the stream may change when persisted
  1041. * from XML, and this invalidates the pointer. However if you AddRef,
  1042. * the pointer will be valid as long as the last reference is released.
  1043. * That means it may outlive CXML_IStream object itself - nothing wrong with that.
  1044. * You only must be aware that once persistence (loading) from XML is completed,
  1045. * CXML_IStream will switch to the new stream and it will not be in sync with
  1046. * the pointer you have. Always use GetIStream() to get the current pointer.
  1047. *
  1048. * NOTE: Every call to GetIStream() moves stream cursor to the begining of the stream
  1049. *
  1050. *+-------------------------------------------------------------------------*/
  1051. class CXML_IStream : public CXMLObject
  1052. {
  1053. public: // interface methods not throwing any exceptions
  1054. SC ScInitializeFrom( IStream *pSource );
  1055. SC ScInitialize(bool& bCreatedNewOne);
  1056. SC ScSeekBeginning();
  1057. SC ScGetIStream( IStream **ppStream );
  1058. SC ScRequestSave(IPersistStorage * pPersistStream);
  1059. inline SC ScRequestSave(IPersistStream * pPersistStream)
  1060. {
  1061. return ScRequestSaveX(pPersistStream);
  1062. }
  1063. inline SC ScRequestSave(IPersistStreamInit * pPersistStreamInit)
  1064. {
  1065. return ScRequestSaveX(pPersistStreamInit);
  1066. }
  1067. // instruct to persist to binary storage
  1068. virtual bool UsesBinaryStorage() { return true; }
  1069. DEFINE_XML_TYPE(XML_TAG_ISTREAM);
  1070. public:
  1071. virtual void Persist(CPersistor &persistor);
  1072. private:
  1073. template<class TIPS>
  1074. SC ScRequestSaveX(TIPS * pPersistStream)
  1075. {
  1076. DECLARE_SC(sc, TEXT("CXML_IStream::ScRequestSaveX"));
  1077. // initialize
  1078. bool bCreatedNewOne = false; // unused here
  1079. sc = ScInitialize(bCreatedNewOne);
  1080. if (sc)
  1081. return sc;
  1082. // recheck pointers
  1083. sc = ScCheckPointers( m_Stream, E_UNEXPECTED );
  1084. if (sc)
  1085. return sc;
  1086. ULARGE_INTEGER null_size = { 0, 0 };
  1087. sc = m_Stream->SetSize( null_size );
  1088. if(sc)
  1089. return sc;
  1090. sc = ScSeekBeginning();
  1091. if(sc)
  1092. return sc;
  1093. sc = pPersistStream->Save( m_Stream, TRUE );
  1094. if(sc)
  1095. return sc;
  1096. // commit the changes - this ensures everything is in HGLOBAL
  1097. sc = m_Stream->Commit( STGC_DEFAULT );
  1098. if(sc)
  1099. return sc;
  1100. #ifdef DBG
  1101. if (S_FALSE != pPersistStream->IsDirty())
  1102. DBG_TraceNotResettingDirty(typeid(TIPS).name());
  1103. #endif // #ifdef DBG
  1104. return sc;
  1105. }
  1106. private:
  1107. IStreamPtr m_Stream;
  1108. #ifdef DBG // tracing support
  1109. public:
  1110. DBG_PersistTraceData m_dbg_Data;
  1111. void DBG_TraceNotResettingDirty(LPCSTR strIntfName);
  1112. #endif // #ifdef DBG
  1113. }; // class CXML_IStream
  1114. /*+-------------------------------------------------------------------------*
  1115. * class CXMLPersistableIcon
  1116. *
  1117. * PURPOSE: Persists wraps for persisting CPersistableIcon
  1118. *
  1119. * USAGE: Create object whenever you need to persist to CPersistableIcon
  1120. *
  1121. *+-------------------------------------------------------------------------*/
  1122. class CPersistableIcon;
  1123. class CXMLPersistableIcon : public CXMLObject
  1124. {
  1125. CPersistableIcon& m_Icon;
  1126. public:
  1127. CXMLPersistableIcon(CPersistableIcon& Icon) : m_Icon(Icon) {}
  1128. DEFINE_XML_TYPE(XML_TAG_ICON);
  1129. virtual void Persist(CPersistor &persistor);
  1130. };
  1131. /*+-------------------------------------------------------------------------*
  1132. * CXMLVariant
  1133. *
  1134. * This class implements a CComVariant that can persist itself to/from an
  1135. * XML persistor.
  1136. *--------------------------------------------------------------------------*/
  1137. class CXMLVariant :
  1138. public CComVariant,
  1139. public CXMLObject
  1140. {
  1141. public:
  1142. // construction and assignment forwarders
  1143. CXMLVariant() {}
  1144. CXMLVariant(const VARIANT& varSrc) : CComVariant(varSrc) {}
  1145. CXMLVariant(const CComVariant& varSrc) : CComVariant(varSrc) {}
  1146. CXMLVariant(const CXMLVariant& varSrc) : CComVariant(varSrc) {}
  1147. CXMLVariant(BSTR bstrSrc) : CComVariant(bstrSrc) {}
  1148. CXMLVariant(LPCOLESTR lpszSrc) : CComVariant(lpszSrc) {}
  1149. #ifndef OLE2ANSI
  1150. CXMLVariant(LPCSTR lpszSrc) : CComVariant(lpszSrc) {}
  1151. #endif
  1152. CXMLVariant(bool bSrc) : CComVariant(bSrc) {}
  1153. CXMLVariant(int nSrc) : CComVariant(nSrc) {}
  1154. CXMLVariant(BYTE nSrc) : CComVariant(nSrc) {}
  1155. CXMLVariant(short nSrc) : CComVariant(nSrc) {}
  1156. CXMLVariant(float fltSrc) : CComVariant(fltSrc) {}
  1157. CXMLVariant(double dblSrc) : CComVariant(dblSrc) {}
  1158. CXMLVariant(CY cySrc) : CComVariant(cySrc) {}
  1159. CXMLVariant(long nSrc, VARTYPE vtSrc = VT_I4) : CComVariant(nSrc, vtSrc) {}
  1160. CXMLVariant& operator=(const CXMLVariant& varSrc) { CComVariant::operator=(varSrc); return (*this); }
  1161. CXMLVariant& operator=(const CComVariant& varSrc) { CComVariant::operator=(varSrc); return (*this); }
  1162. CXMLVariant& operator=(const VARIANT& varSrc) { CComVariant::operator=(varSrc); return (*this); }
  1163. CXMLVariant& operator=(BSTR bstrSrc) { CComVariant::operator=(bstrSrc); return (*this); }
  1164. CXMLVariant& operator=(LPCOLESTR lpszSrc) { CComVariant::operator=(lpszSrc); return (*this); }
  1165. #ifndef OLE2ANSI
  1166. CXMLVariant& operator=(LPCSTR lpszSrc) { CComVariant::operator=(lpszSrc); return (*this); }
  1167. #endif
  1168. CXMLVariant& operator=(bool bSrc) { CComVariant::operator=(bSrc); return (*this); }
  1169. CXMLVariant& operator=(int nSrc) { CComVariant::operator=(nSrc); return (*this); }
  1170. CXMLVariant& operator=(BYTE nSrc) { CComVariant::operator=(nSrc); return (*this); }
  1171. CXMLVariant& operator=(short nSrc) { CComVariant::operator=(nSrc); return (*this); }
  1172. CXMLVariant& operator=(long nSrc) { CComVariant::operator=(nSrc); return (*this); }
  1173. CXMLVariant& operator=(float fltSrc) { CComVariant::operator=(fltSrc); return (*this); }
  1174. CXMLVariant& operator=(double dblSrc) { CComVariant::operator=(dblSrc); return (*this); }
  1175. CXMLVariant& operator=(CY cySrc) { CComVariant::operator=(cySrc); return (*this); }
  1176. public:
  1177. DEFINE_XML_TYPE(XML_TAG_VARIANT);
  1178. virtual void Persist(CPersistor &persistor);
  1179. bool IsPersistable() const
  1180. { return (IsPersistable(this)); }
  1181. static bool IsPersistable(const VARIANT* pvar)
  1182. {
  1183. if (pvar == NULL)
  1184. return (false);
  1185. /*
  1186. * we can only store variants that are "simple" (i.e. not by-ref,
  1187. * array, etc.)
  1188. */
  1189. return ((V_VT(pvar) & ~VT_TYPEMASK) == 0);
  1190. }
  1191. };
  1192. /***************************************************************************\
  1193. *
  1194. * CLASS: CConsoleFilePersistor
  1195. *
  1196. * PURPOSE: File persistence black box. all console file - user data logic
  1197. * is hiden under this class
  1198. *
  1199. * USAGE: Use instance of this class to load and save console file,
  1200. * NOTE - saving should be done with the same instance the console
  1201. * was loaded.
  1202. * Good idea for your class maintaning console (such as AMCDocument)
  1203. * to either derive of contain instance of this class
  1204. *
  1205. \***************************************************************************/
  1206. class CConsoleFilePersistor
  1207. {
  1208. public: // public interface
  1209. CConsoleFilePersistor() : m_bCRCValid(false) {}
  1210. SC ScSaveConsole(LPCTSTR lpstrConsolePath, bool bForAuthorMode, const CXMLDocument& xmlDocument);
  1211. SC ScLoadConsole(LPCTSTR lpstrConsolePath, bool& bXmlBased, CXMLDocument& xmlDocument,
  1212. IStorage **ppStorage);
  1213. static SC ScGetUserDataFolder(tstring& strUserDataFolder);
  1214. private: // implementation helpers
  1215. static SC ScGetUserDataPath(LPCTSTR lpstrOriginalPath, tstring& strUserDataPath);
  1216. static SC ScGetUserData(const tstring& strUserDataConsolePath,
  1217. const tstring& strFileCRC,
  1218. bool& bValid, CXMLDocument& xmlDocument);
  1219. static SC ScOpenDocAsStructuredStorage(LPCTSTR lpszPathName, IStorage **ppStorage);
  1220. static SC ScLoadXMLDocumentFromFile(CXMLDocument& xmlDocument, LPCTSTR strFileName, bool bSilentOnErrors = false);
  1221. private: // compress/uncompress the file
  1222. static void GetBinaryCollection(CXMLDocument& xmlDocument, CXMLElementCollection& colBinary);
  1223. static SC ScCompressUserStateFile(LPCTSTR szConsoleFilePath, CXMLDocument & xmlDocument);
  1224. static SC ScUncompressUserStateFile(CXMLDocument &xmlDocumentOriginal, CXMLDocument& xmlDocument);
  1225. private: // internal data
  1226. tstring m_strFileCRC;
  1227. bool m_bCRCValid;
  1228. };
  1229. #endif // XMLBASE_H