1404 lines
54 KiB
C
1404 lines
54 KiB
C
|
|
||
|
#ifndef XMLBASE_H
|
||
|
#define XMLBASE_H
|
||
|
#pragma once
|
||
|
|
||
|
#include <atlbase.h>
|
||
|
#include <list>
|
||
|
#include <map>
|
||
|
#include "mmcerror.h"
|
||
|
#include "macros.h"
|
||
|
#include "tstring.h"
|
||
|
#include "strings.h"
|
||
|
#include "cstr.h"
|
||
|
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
This file contains code required to persist data using XML format.
|
||
|
The classes defined here fall into following categories:
|
||
|
|
||
|
Main persistence process engine
|
||
|
CPersistor
|
||
|
| this class is the working horse for XML persistence
|
||
|
| every class supporting persistence gets the reference to
|
||
|
| CPersistor to it's Persist method, where it implements
|
||
|
| persisting ot their own code. Class' own code is persisted
|
||
|
| by calling Persist* methods on persistor and passing internal
|
||
|
| variables to them. The tree of CPersist objects is created during
|
||
|
| persist operation (load or save) and lives only during this operation.
|
||
|
|
||
|
MSXML interface wrappers:
|
||
|
CXMLElement (wraps IXMLDOMNode interface)
|
||
|
CXMLElementCollection (wraps IXMLDOMNodeList interface)
|
||
|
CXMLDocument (wraps IXMLDOMDocument interface)
|
||
|
| these wrappers add very little to the interfaces wrapped
|
||
|
| - the throw SC type of exception instead of returning the error code
|
||
|
| - maintain internal smart pointer to wrapped interfaces
|
||
|
| - return error from methods if the interface has not be set
|
||
|
|
||
|
base classes for classes supporting XML persistence
|
||
|
CXMLObject - generic persistence support
|
||
|
XMLListCollectionBase - persistence support for std::list
|
||
|
XMLListCollectionImp - persistence support for std::list
|
||
|
XMLMapCollectionBase - persistence support for std::map
|
||
|
XMLMapCollection - persistence support for std::map
|
||
|
XMLMapCollectionImp - persistence support for std::map
|
||
|
| for object to support persistence it needs to derive from any of listed
|
||
|
| classes (at least from CXMLObject). Other classes add some more functionality
|
||
|
| to the derived class.
|
||
|
|
||
|
Generic value persistece support
|
||
|
CXMLValue - support for set of generic types (like int, string, etc)
|
||
|
CXMLBoolean - support for BOOL and bool types
|
||
|
| CXMLValue mostly used by implicit cast of the object given to
|
||
|
| CPersistor::PersistAttribute or CPersistor::PersistContents
|
||
|
|
||
|
Wrappers, adding persistence to regular types
|
||
|
XMLPoint - persistence for POINT type
|
||
|
XMLRect - persistence for RECT type
|
||
|
XMLListCollectionWrap - persistence for std::list type
|
||
|
XMLMapCollectionWrap - persistence for std::map type
|
||
|
CXML_IStorage - persistence thru IStorage
|
||
|
CXML_IStream - persistence thru IStream
|
||
|
CXMLPersistableIcon - persistence for console icon
|
||
|
CXMLVariant - persistence for CComVariant
|
||
|
CXMLEnumeration - persistence for enumerations by literals
|
||
|
CXMLBitFlags - persistence for bit-flags by literals
|
||
|
| these classes usually take the reference to object they persist as
|
||
|
| a parameter to the constructor and usually are constructed
|
||
|
| on stack solely to persist the object and die afterwards
|
||
|
|
||
|
SEE THE SAMPLE BELOW
|
||
|
----------------------------------------------------------------------------
|
||
|
SAMPLE:
|
||
|
say we have classes A, B what need to be persisted (access specifiers ommited)
|
||
|
|
||
|
class A { int i; };
|
||
|
class B { int j; A a; };
|
||
|
|
||
|
and we would want to persist them in format (assume A::i = 1, B::j = 2) :
|
||
|
<BT INDEX = "2"><AT>1</AT></BT>
|
||
|
|
||
|
we need to change the classes to support persistence:
|
||
|
|
||
|
class A : public CXMLObject // to inherit persistence capability
|
||
|
{ int i;
|
||
|
|
||
|
DEFINE_XML_TYPE("AT") // to define the tag name
|
||
|
|
||
|
virtual void
|
||
|
Persist(CPersistor &persistor) // to implement persistence for own staff
|
||
|
{
|
||
|
persistor.PersistContents(i); // persist i as AT element contents
|
||
|
}
|
||
|
};
|
||
|
class B : public CXMLObject // to inherit persistence capability
|
||
|
{ int j; A a;
|
||
|
|
||
|
DEFINE_XML_TYPE("BT") // to define the tag name
|
||
|
|
||
|
virtual void
|
||
|
Persist(CPersistor &persistor) // to implement persistence for own staff
|
||
|
{
|
||
|
persistor.PersistAttribute(_T("INDEX"), j); // persist j
|
||
|
persistor.Persist(a); // persist a
|
||
|
}
|
||
|
};
|
||
|
|
||
|
to have it in the string we may use:
|
||
|
|
||
|
B b; std::wstring xml_text;
|
||
|
b.ScSaveToString(&xml_text);
|
||
|
|
||
|
---------------------------------------------------------------------------- */
|
||
|
|
||
|
// forward declarations
|
||
|
|
||
|
class CPersistor;
|
||
|
class CXMLObject;
|
||
|
class CXMLElement;
|
||
|
class CXMLDocument;
|
||
|
class CXMLValueExtension;
|
||
|
|
||
|
enum XMLAttributeType
|
||
|
{
|
||
|
attr_required,
|
||
|
attr_optional
|
||
|
};
|
||
|
|
||
|
// special modes for certain persistors. These can be used to pass in information about
|
||
|
// how to persist. Not as scalable as a class hierarchy, but useful nonetheless.
|
||
|
enum PersistorMode
|
||
|
{
|
||
|
persistorModeNone = 0x0000,
|
||
|
|
||
|
persistorModeValueSplitEnabled = 0x0001, // used for StringTableStrings, indicates that all strings should be persisted by value
|
||
|
|
||
|
persistorModeDefault = persistorModeValueSplitEnabled // the default setting
|
||
|
};
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* CONCEPT OF BINARY STORAGE
|
||
|
*
|
||
|
* To make xml documents more readable, a part of it (containing base64 - encoded
|
||
|
* binary data) is stored at separate element located at the end of document.
|
||
|
* the following sample illustrates this
|
||
|
*
|
||
|
* NOT_USING_BINARY_STROAGE USING_BINARY_STROAGE
|
||
|
*
|
||
|
* <ROOT> <ROOT>
|
||
|
* <ELEMENT1> <ELEMENT1 BINARY_REF_INDEX="0" />
|
||
|
* very_long_bin_data <ELEMENT2 BINARY_REF_INDEX="1" />
|
||
|
* </ELEMENT1> .....
|
||
|
* <ELEMENT2> <BINARY_STORAGE>
|
||
|
* other_long_bin_data <BINARY>
|
||
|
* </ELEMENT2> very_long_bin_data
|
||
|
* </ROOT> </BINARY>
|
||
|
* <BINARY>
|
||
|
* very_long_bin_data
|
||
|
* </BINARY>
|
||
|
* </BINARY_STORAGE>
|
||
|
* </ROOT>
|
||
|
*
|
||
|
* The decision to be saved at binary storage is made by the CXMLObject.
|
||
|
* It informs the persistor by returning "true" from UsesBinaryStorage() method;
|
||
|
*
|
||
|
* In addition ( to make it locatable ) <BINARY> elements may have 'Name' attribute.
|
||
|
* CXMLObject may supply it by returning non-NULL pointer to 'Name' attribute value
|
||
|
* from virtual method GetBinaryEntryName().
|
||
|
*
|
||
|
* Storage is created / commited by methods provided in CXMLDocument
|
||
|
*
|
||
|
* NOTE: all mentioned methods, as well as GetXMLType() MUST return 'static' values.
|
||
|
* To make XML document consistent, values need to be fixed [hardcoded].
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class CXMLObject
|
||
|
*
|
||
|
*
|
||
|
* PURPOSE: The basic XML persistent object. has a name and a Persist function.
|
||
|
* When the object is persisted, an element with the name of the
|
||
|
* object is created. The Persist function is then called with
|
||
|
* a persistor created on the element.
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
class CXMLObject
|
||
|
{
|
||
|
// this is overridden
|
||
|
public:
|
||
|
|
||
|
virtual LPCTSTR GetXMLType() = 0;
|
||
|
virtual void Persist(CPersistor &persistor) = 0;
|
||
|
|
||
|
// following methods are implemented by binary elements only.
|
||
|
// leave it to this base class for most CXMLObject-derived classes.
|
||
|
// see comment "CONCEPT OF BINARY STORAGE" above
|
||
|
|
||
|
virtual bool UsesBinaryStorage() { return false; }
|
||
|
|
||
|
// this is optional. Overwrite only if you REALLY NEED the name
|
||
|
virtual LPCTSTR GetBinaryEntryName() { return NULL; }
|
||
|
|
||
|
public: // implemented by CXMLObject. Do not override
|
||
|
|
||
|
SC ScSaveToString(std::wstring *pString, bool bPutHeader = false); // set bPutHeader = true to write out the "?xml" tag
|
||
|
SC ScSaveToDocument( CXMLDocument& xmlDocument );
|
||
|
SC ScLoadFromString(LPCWSTR lpcwstrSource, PersistorMode mode = persistorModeNone);
|
||
|
SC ScLoadFromDocument( CXMLDocument& xmlDocument );
|
||
|
};
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* MACRO DEFINE_XML_TYPE
|
||
|
*
|
||
|
*
|
||
|
* PURPOSE: puts must-to-define methods to XCMLObject derived class implementation
|
||
|
* Since xml tag is rather class attribute than object, static method
|
||
|
* is provided to retrieve the type when object is not available
|
||
|
* Virtual method is provided for tag to be available from gen. purpose
|
||
|
* functions using the pointer to the base class.
|
||
|
*
|
||
|
* USAGE: add DEFINE_XML_TYPE(pointer_to_string)
|
||
|
*
|
||
|
* NOTE: 'public' access qualifier will be applied for lines following the macro
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
|
||
|
#define DEFINE_XML_TYPE(name) \
|
||
|
public: \
|
||
|
virtual LPCTSTR GetXMLType() { return name; } \
|
||
|
static LPCTSTR _GetXMLType() { return name; }
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class CXMLElementCollection
|
||
|
*
|
||
|
*
|
||
|
* PURPOSE: Wrapper around IXMLDOMNodeList.
|
||
|
*
|
||
|
* NOTE: Throws exceptions!
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
class CXMLElementCollection
|
||
|
{
|
||
|
CComQIPtr<IXMLDOMNodeList, &IID_IXMLDOMNodeList> m_sp;
|
||
|
|
||
|
public:
|
||
|
CXMLElementCollection(const CXMLElementCollection &other) { m_sp = other.m_sp; }
|
||
|
CXMLElementCollection(IXMLDOMNodeList *ptr = NULL) { m_sp = ptr; }
|
||
|
|
||
|
bool IsNull() { return m_sp == NULL; }
|
||
|
|
||
|
void get_count(long *plCount);
|
||
|
void item(LONG lIndex, CXMLElement *pElem);
|
||
|
};
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class CXMLElement
|
||
|
*
|
||
|
*
|
||
|
* PURPOSE: Wrapper around IXMLDOMNode
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
class CXMLElement
|
||
|
{
|
||
|
CComQIPtr<IXMLDOMNode, &IID_IXMLDOMNode> m_sp;
|
||
|
|
||
|
public:
|
||
|
CXMLElement(LPUNKNOWN pElem = NULL) { m_sp = pElem; }
|
||
|
CXMLElement(const CXMLElement& elem) { m_sp = elem.m_sp; }
|
||
|
|
||
|
bool IsNull() { return m_sp == NULL; }
|
||
|
|
||
|
// returns indentation to ad to child element or closing tag
|
||
|
// to have nice-looking document. indentation depends on element depth
|
||
|
bool GetTextIndent(CComBSTR& bstrIndent, bool bForAChild);
|
||
|
|
||
|
void get_tagName(CStr &strTagName);
|
||
|
void get_parent(CXMLElement * pParent);
|
||
|
void setAttribute(const CStr &strPropertyName, const CComBSTR &bstrPropertyValue);
|
||
|
bool getAttribute(const CStr &strPropertyName, CComBSTR &bstrPropertyValue);
|
||
|
void removeAttribute(const CStr &strPropertyName);
|
||
|
void get_children(CXMLElementCollection *pChildren);
|
||
|
void get_type(DOMNodeType *pType);
|
||
|
void get_text(CComBSTR &bstrContent);
|
||
|
void addChild(CXMLElement& rChildElem);
|
||
|
void removeChild(CXMLElement& rChildElem);
|
||
|
void replaceChild(CXMLElement& rNewChildElem, CXMLElement& rOldChildElem);
|
||
|
void getNextSibling(CXMLElement * pNext);
|
||
|
void getChildrenByName(LPCTSTR strTagName, CXMLElementCollection *pChildren);
|
||
|
void put_text(BSTR bstrValue);
|
||
|
};
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class CXMLDocument
|
||
|
*
|
||
|
*
|
||
|
* PURPOSE: Wrapper class for IXMLDOMDocument
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
class CXMLDocument
|
||
|
{
|
||
|
CComQIPtr<IXMLDOMDocument, &IID_IXMLDOMDocument> m_sp;
|
||
|
|
||
|
public:
|
||
|
CXMLDocument& operator = (IXMLDOMDocument *pDoc) { m_sp = pDoc; return *this; }
|
||
|
|
||
|
bool IsNull() { return m_sp == NULL; }
|
||
|
|
||
|
operator CXMLElement() { return CXMLElement(m_sp); }
|
||
|
|
||
|
void get_root(CXMLElement *pElem);
|
||
|
void createElement(DOMNodeType type, BSTR bstrTag, CXMLElement *pElem);
|
||
|
|
||
|
// members to maintain the binary storage
|
||
|
// see comment "CONCEPT OF BINARY STORAGE" above
|
||
|
|
||
|
// used on storing (at top level, prior to persisting)
|
||
|
// - creates an element for storing binary stuff
|
||
|
void CreateBinaryStorage();
|
||
|
// used on loading (at top level, prior to persisting)
|
||
|
// - locates an element to be used for loading binary stuff
|
||
|
void LocateBinaryStorage();
|
||
|
// used on storing (at top level, after persisting the main staff)
|
||
|
// - attaches the binary strage as the last child element of elemParent
|
||
|
void CommitBinaryStorage();
|
||
|
// returns element representing binary storage. Used from CPersistor
|
||
|
CXMLElement GetBinaryStorage() { return m_XMLElemBinaryStorage; }
|
||
|
|
||
|
SC ScCoCreate(bool bPutHeader);
|
||
|
|
||
|
SC ScLoad(LPCWSTR strSource);
|
||
|
SC ScLoad(IStream *pStream, bool bSilentOnErrors = false );
|
||
|
SC ScSaveToFile(LPCTSTR lpcstrFileName);
|
||
|
SC ScSave(CComBSTR &bstrResult);
|
||
|
|
||
|
private:
|
||
|
// element representing binary storage
|
||
|
CXMLElement m_XMLElemBinaryStorage;
|
||
|
};
|
||
|
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class CXMLBinary
|
||
|
*
|
||
|
*
|
||
|
* PURPOSE: GetGlobalSize() is alway rounded to allocation units,
|
||
|
* so to know the actual size of the memory blob, we need to
|
||
|
* carry the size information with HGLOBAL.
|
||
|
* This struct is solely to bind these guys
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
class CXMLBinary
|
||
|
{
|
||
|
public:
|
||
|
CXMLBinary();
|
||
|
CXMLBinary(HGLOBAL handle, size_t size);
|
||
|
~CXMLBinary() { Detach(); }
|
||
|
|
||
|
void Attach(HGLOBAL handle, size_t size);
|
||
|
HGLOBAL Detach();
|
||
|
size_t GetSize() const;
|
||
|
HGLOBAL GetHandle() const;
|
||
|
SC ScAlloc(size_t size, bool fZeroInit = false);
|
||
|
SC ScRealloc(size_t new_size, bool fZeroInit = false);
|
||
|
SC ScFree();
|
||
|
|
||
|
SC ScLockData(const void **ppData) const;
|
||
|
SC ScLockData(void **ppData) { return ScLockData(const_cast<const void **>(ppData)); }
|
||
|
SC ScUnlockData() const;
|
||
|
|
||
|
protected:
|
||
|
// implementation helpers
|
||
|
|
||
|
private: // not implemented
|
||
|
|
||
|
CXMLBinary(const CXMLBinary&); // not implemented; not allowed;
|
||
|
operator = (CXMLBinary&); // not implemented; not allowed;
|
||
|
|
||
|
private:
|
||
|
HGLOBAL m_Handle;
|
||
|
size_t m_Size;
|
||
|
mutable unsigned m_Locks;
|
||
|
};
|
||
|
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class CXMLAutoBinary
|
||
|
*
|
||
|
*
|
||
|
* PURPOSE: same as CXMLAutoBinary, but frees the memory on destruction
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
class CXMLAutoBinary : public CXMLBinary
|
||
|
{
|
||
|
public:
|
||
|
CXMLAutoBinary() : CXMLBinary() {}
|
||
|
CXMLAutoBinary(HGLOBAL handle, size_t size) : CXMLBinary(handle, size) {}
|
||
|
~CXMLAutoBinary() { ScFree(); }
|
||
|
};
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class CXMLBinaryLock
|
||
|
*
|
||
|
*
|
||
|
* PURPOSE: provides data locking functionality which is automatically removed
|
||
|
* in destructor
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
class CXMLBinaryLock
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
CXMLBinaryLock(CXMLBinary& binary);
|
||
|
~CXMLBinaryLock();
|
||
|
|
||
|
template<typename T>
|
||
|
SC ScLock(T **ppData)
|
||
|
{
|
||
|
return ScLockWorker(reinterpret_cast<void**>(ppData));
|
||
|
}
|
||
|
|
||
|
SC ScUnlock();
|
||
|
|
||
|
private: // not implemented
|
||
|
|
||
|
CXMLBinaryLock(const CXMLBinaryLock&); // not implemented; not allowed;
|
||
|
operator = (CXMLBinaryLock&); // not implemented; not allowed;
|
||
|
|
||
|
private:
|
||
|
|
||
|
SC ScLockWorker(void **ppData);
|
||
|
|
||
|
bool m_bLocked;
|
||
|
CXMLBinary& m_rBinary;
|
||
|
};
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class CXMLValue
|
||
|
*
|
||
|
*
|
||
|
* PURPOSE: Holds any type of value, in the spirit of a variant, except
|
||
|
* that a pointer to the original object is kept. This allows
|
||
|
* reading as well as writing to occur on the original object.
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
class CXMLValue
|
||
|
{
|
||
|
friend class CXMLBoolean;
|
||
|
enum XMLType
|
||
|
{
|
||
|
XT_I4, //LONG
|
||
|
XT_UI4, //ULONG
|
||
|
XT_UI1, //BYTE
|
||
|
XT_I2, //SHORT
|
||
|
XT_DW, //DWORD
|
||
|
XT_BOOL,//BOOL
|
||
|
XT_CPP_BOOL,//bool
|
||
|
XT_UINT,//UINT
|
||
|
XT_INT, //INT
|
||
|
XT_STR, //CStr
|
||
|
XT_WSTR, // std::wstr
|
||
|
XT_TSTR, // tstring
|
||
|
XT_GUID, // GUID
|
||
|
XT_BINARY, //HGLOBAL - unparsable data
|
||
|
XT_EXTENSION
|
||
|
};
|
||
|
|
||
|
const XMLType m_type;
|
||
|
union
|
||
|
{
|
||
|
LONG * pL;
|
||
|
ULONG * pUl;
|
||
|
BYTE * pByte;
|
||
|
SHORT * pS;
|
||
|
DWORD * pDw;
|
||
|
UINT * pUint;
|
||
|
INT * pInt;
|
||
|
CStr * pStr;
|
||
|
std::wstring * pWStr;
|
||
|
tstring * pTStr;
|
||
|
GUID * pGuid;
|
||
|
CXMLBinary * pXmlBinary;
|
||
|
bool * pbool;
|
||
|
BOOL * pBOOL;
|
||
|
CXMLValueExtension * pExtension;
|
||
|
} m_val;
|
||
|
|
||
|
// private constructor. used by friend class CXMLBoolean
|
||
|
CXMLValue(XMLType type) : m_type(type) { }
|
||
|
public:
|
||
|
CXMLValue(const CXMLValue &v) : m_type(v.m_type), m_val(v.m_val) { }
|
||
|
CXMLValue(LONG &l) : m_type(XT_I4) { m_val.pL=&l; }
|
||
|
CXMLValue(ULONG &ul) : m_type(XT_UI4) { m_val.pUl=&ul; }
|
||
|
CXMLValue(BYTE &b) : m_type(XT_UI1) { m_val.pByte=&b; }
|
||
|
CXMLValue(SHORT &s) : m_type(XT_I2) { m_val.pS=&s; }
|
||
|
CXMLValue(UINT &u) : m_type(XT_UINT) { m_val.pUint=&u; }
|
||
|
CXMLValue(INT &i) : m_type(XT_INT) { m_val.pInt=&i; }
|
||
|
CXMLValue(CStr &str) : m_type(XT_STR) { m_val.pStr=&str; }
|
||
|
CXMLValue(std::wstring &str) : m_type(XT_WSTR) { m_val.pWStr=&str; }
|
||
|
CXMLValue(GUID &guid) : m_type(XT_GUID) { m_val.pGuid = &guid; }
|
||
|
CXMLValue(CXMLBinary &binary) : m_type(XT_BINARY) { m_val.pXmlBinary = &binary; }
|
||
|
CXMLValue(tstring &tstr) : m_type(XT_TSTR) { m_val.pTStr = &tstr; }
|
||
|
CXMLValue(CXMLValueExtension& ext) : m_type(XT_EXTENSION) { m_val.pExtension = &ext; }
|
||
|
SC ScReadFromBSTR(const BSTR bstr); // read input into the underlying variable.
|
||
|
SC ScWriteToBSTR (BSTR * pbstr ) const; // writes the value into provided string
|
||
|
LPCTSTR GetTypeName() const;
|
||
|
// The following method is called when value is persisted as stand-alone element.
|
||
|
// Depending on the result returned the contents may go to Binary Storage
|
||
|
// see comment "CONCEPT OF BINARY STORAGE" above
|
||
|
bool UsesBinaryStorage() const { return m_type == XT_BINARY; }
|
||
|
};
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* CXMLBoolean
|
||
|
*
|
||
|
*
|
||
|
* PURPOSE: special case: booleans. Need to be printed as true/false, NOT as integer.
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
class CXMLBoolean : public CXMLValue
|
||
|
{
|
||
|
public:
|
||
|
CXMLBoolean(BOOL &b) : CXMLValue(XT_BOOL) { m_val.pBOOL = &b;}
|
||
|
CXMLBoolean(bool &b) : CXMLValue(XT_CPP_BOOL) { m_val.pbool = &b;}
|
||
|
};
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* CXMLValueExtension
|
||
|
*
|
||
|
*
|
||
|
* PURPOSE: interface to extend CXMLValue by more sophisticated types
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
class CXMLValueExtension
|
||
|
{
|
||
|
public:
|
||
|
virtual SC ScReadFromBSTR(const BSTR bstr) = 0; // read input into the underlying variable.
|
||
|
virtual SC ScWriteToBSTR (BSTR * pbstr ) const = 0; // writes the value into provided string
|
||
|
virtual LPCTSTR GetTypeName() const = 0;
|
||
|
};
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class EnumLiteral
|
||
|
*
|
||
|
*
|
||
|
* PURPOSE: to define enum-to-literal mapping arrays (used by CXMLEnumeration)
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
|
||
|
struct EnumLiteral
|
||
|
{
|
||
|
UINT m_enum;
|
||
|
LPCTSTR m_literal;
|
||
|
};
|
||
|
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class CXMLEnumeration
|
||
|
*
|
||
|
*
|
||
|
* PURPOSE: to persist enumeration as string literal
|
||
|
* using array of enum-to-literal mappings
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
|
||
|
class CXMLEnumeration : public CXMLValueExtension
|
||
|
{
|
||
|
// just an enum sized type to hold reference
|
||
|
// while many enum types will be used, internally they
|
||
|
// will be cast to this type
|
||
|
enum enum_t { JUST_ENUM_SIZE_VALUE };
|
||
|
public:
|
||
|
|
||
|
// template constructor to allow different enums to be persisted
|
||
|
template<typename _ENUM>
|
||
|
CXMLEnumeration(_ENUM& en, const EnumLiteral * const etols, size_t count)
|
||
|
: m_pMaps(etols) , m_count(count), m_rVal((enum_t&)(en))
|
||
|
{
|
||
|
// folowing lines won't compile in case you are trying to pass
|
||
|
// type other than enum or int
|
||
|
COMPILETIME_ASSERT( sizeof(en) == sizeof(enum_t) );
|
||
|
UINT testit = en;
|
||
|
}
|
||
|
|
||
|
// CXMLValueExtension metods required to implement
|
||
|
SC ScReadFromBSTR(const BSTR bstr); // read input into the underlying variable.
|
||
|
SC ScWriteToBSTR (BSTR * pbstr ) const; // writes the value into provided string
|
||
|
LPCTSTR GetTypeName() const { return _T("Enumerations"); }
|
||
|
|
||
|
// to enable passing itself as CMLValue
|
||
|
operator CXMLValue ()
|
||
|
{
|
||
|
return CXMLValue (*this);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
enum_t &m_rVal;
|
||
|
const EnumLiteral * const m_pMaps;
|
||
|
const size_t m_count;
|
||
|
};
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class CXMLBitFlags
|
||
|
*
|
||
|
*
|
||
|
* PURPOSE: to persist bit flags as string literals
|
||
|
* using array of enum-to-literal mappings
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
|
||
|
class CXMLBitFlags
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
// template constructor to allow different enums to be persisted
|
||
|
template<typename _integer>
|
||
|
CXMLBitFlags(_integer& flags, const EnumLiteral * const etols, size_t count)
|
||
|
: m_pMaps(etols) , m_count(count), m_rVal((UINT&)flags)
|
||
|
{
|
||
|
// folowing lines won't compile in case you are trying to pass
|
||
|
// type other than enum or int
|
||
|
COMPILETIME_ASSERT( sizeof(flags) == sizeof(UINT) );
|
||
|
UINT testit = flags;
|
||
|
}
|
||
|
|
||
|
void PersistMultipleAttributes(LPCTSTR name, CPersistor &persistor);
|
||
|
|
||
|
private:
|
||
|
UINT &m_rVal;
|
||
|
const EnumLiteral * const m_pMaps;
|
||
|
const size_t m_count;
|
||
|
};
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class XMLPoint
|
||
|
*
|
||
|
*
|
||
|
* PURPOSE: Holds the name and value of a point object
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
class XMLPoint : public CXMLObject
|
||
|
{
|
||
|
CStr m_strObjectName;
|
||
|
POINT & m_point;
|
||
|
public:
|
||
|
XMLPoint(const CStr& strObjectName, POINT &point);
|
||
|
|
||
|
DEFINE_XML_TYPE(XML_TAG_POINT);
|
||
|
virtual void Persist(CPersistor &persistor);
|
||
|
};
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class XMLRect
|
||
|
*
|
||
|
*
|
||
|
* PURPOSE: Holds the name and value of a rectangle object
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
class XMLRect : public CXMLObject
|
||
|
{
|
||
|
CStr m_strObjectName;
|
||
|
RECT & m_rect;
|
||
|
public:
|
||
|
XMLRect(const CStr strObjectName, RECT &rect);
|
||
|
|
||
|
DEFINE_XML_TYPE(XML_TAG_RECTANGLE);
|
||
|
virtual void Persist(CPersistor &persistor);
|
||
|
};
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class XMLListCollectionBase
|
||
|
*
|
||
|
*
|
||
|
* PURPOSE: Defines the base list collection class for persisting stl:list's
|
||
|
* It's intended to be used as a base for deriving list persitence classes
|
||
|
* Persist method implements "load" by iterating thru xml elements
|
||
|
* and calling OnNewElement for each, and can be reused by derived classes.
|
||
|
*
|
||
|
* USAGE: Probably the better idea is to use XMLListColLectionImp
|
||
|
* as a base to your collection instead of this class (it is richer). Use this class
|
||
|
* only if your class has special items which does not allow you to use that class.
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
class XMLListCollectionBase: public CXMLObject
|
||
|
{
|
||
|
public:
|
||
|
// function called when new element is to be created and loaded
|
||
|
virtual void OnNewElement(CPersistor& persistor) = 0;
|
||
|
virtual void Persist(CPersistor& persistor);
|
||
|
};
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class XMLListCollectionImp
|
||
|
*
|
||
|
* PURPOSE: A base class for stl::list derived collections implementing persitence of
|
||
|
* the list items as linear sequence of xml items.
|
||
|
* The items kept in the list must be either CXMLObject-derived or be
|
||
|
* of the simple type (one accepted by CXMLVBalue constructors)
|
||
|
*
|
||
|
* USAGE: Derive your class from XMLListCollectionImp parametrized by the list,
|
||
|
* instead of deriving from stl::list directly. use DEFINE_XML_TYPE
|
||
|
* to define tag name for collections element.
|
||
|
*
|
||
|
* NOTE: Your class should implement: GetXMLType() to be functional.
|
||
|
* you can use DEFINE_XML_TYPE macro to do it for you
|
||
|
*
|
||
|
* NOTE: if provided implementation does not fit for you - f.i. your elements need
|
||
|
* a parameter to the constructor, or special initialization,
|
||
|
* use XMLListCollectionBase instead and provide your own methods
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
template<class LT>
|
||
|
class XMLListCollectionImp: public XMLListCollectionBase , public LT
|
||
|
{
|
||
|
typedef LT::iterator iter_t;
|
||
|
public:
|
||
|
virtual void Persist(CPersistor& persistor)
|
||
|
{
|
||
|
if (persistor.IsStoring())
|
||
|
{
|
||
|
for(iter_t it = begin(); it != end(); ++it)
|
||
|
persistor.Persist(*it);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
clear();
|
||
|
// let the base class do the job
|
||
|
// it will call OnNewElement for every element found
|
||
|
XMLListCollectionBase::Persist(persistor);
|
||
|
}
|
||
|
}
|
||
|
// method called to create and load new element
|
||
|
virtual void OnNewElement(CPersistor& persistor)
|
||
|
{
|
||
|
iter_t it = insert(end());
|
||
|
persistor.Persist(*it);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class XMLListCollectionWrap
|
||
|
*
|
||
|
* PURPOSE: A wrapper around stl::list to support persisting
|
||
|
* To be used to persist stl::list objects "from outside" - i.e. without
|
||
|
* deriving the list class from persistence-enabled classes.
|
||
|
*
|
||
|
* USAGE: If you have list m_l to persist, create the object XMLListCollectionWrap wrap(m_l,"tag")
|
||
|
* on the stack and persist that object (f.i. Persistor.Persist(wrap)
|
||
|
*
|
||
|
* NOTE: if provided implementation does not fit for you - see if you can use
|
||
|
* XMLListCollectionImp or XMLListCollectionBase as a base for your list.
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
template<class LT>
|
||
|
class XMLListCollectionWrap: public XMLListCollectionBase
|
||
|
{
|
||
|
typedef LT::iterator iter_t;
|
||
|
LT & m_l;
|
||
|
CStr m_strListType;
|
||
|
public:
|
||
|
XMLListCollectionWrap(LT &l, const CStr &strListType)
|
||
|
: m_l(l), m_strListType(strListType) {}
|
||
|
virtual void Persist(CPersistor& persistor)
|
||
|
{
|
||
|
if (persistor.IsStoring())
|
||
|
{
|
||
|
for(iter_t it = m_l.begin(); it != m_l.end(); ++it)
|
||
|
persistor.Persist(*it);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_l.clear();
|
||
|
// let the base class do the job
|
||
|
// it will call OnNewElement for every element found
|
||
|
XMLListCollectionBase::Persist(persistor);
|
||
|
}
|
||
|
}
|
||
|
// method called to create and load new element
|
||
|
virtual void OnNewElement(CPersistor& persistor)
|
||
|
{
|
||
|
iter_t it = m_l.insert(m_l.end());
|
||
|
persistor.Persist(*it);
|
||
|
}
|
||
|
virtual LPCTSTR GetXMLType() {return m_strListType;}
|
||
|
private:
|
||
|
// to prevent ivalid actions on object
|
||
|
XMLListCollectionWrap(const XMLListCollectionWrap& other);
|
||
|
XMLListCollectionWrap& operator = ( const XMLListCollectionWrap& other ) { return *this; }
|
||
|
};
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class XMLMapCollectionBase
|
||
|
*
|
||
|
*
|
||
|
* PURPOSE: Defines the base map collection class for persisting stl:map's
|
||
|
* It's intended to be used as a base for deriving map persitence classes.
|
||
|
* Persist method implements "load" by iterating thru xml elements
|
||
|
* and calling OnNewElement for each pair, and can be reused by derived classes.
|
||
|
*
|
||
|
* USAGE: Probably the better idea is to use XMLMapCollection or XMLMapColLectionImp
|
||
|
* as a base to your collection instead of this class (they are richer). Use this class
|
||
|
* only if your class has special items which does not allow you to use those classes.
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
class XMLMapCollectionBase: public CXMLObject
|
||
|
{
|
||
|
public:
|
||
|
// function called when new element is to be created and loaded
|
||
|
virtual void OnNewElement(CPersistor& persistKey,CPersistor& persistVal) = 0;
|
||
|
// base implementation [loading only!] enumerates elements calling OnNewElement for each
|
||
|
virtual void Persist(CPersistor& persistor);
|
||
|
};
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class XMLMapCollection
|
||
|
*
|
||
|
* PURPOSE: Use this class only when you cannot use XMLMapCollectionImp due to
|
||
|
* special requirements on construction of the elements kept in the map
|
||
|
* (see also purpose of XMLMapCollectionImp)
|
||
|
*
|
||
|
* USAGE: Derive your class from XMLMapCollection parametrized by the map,
|
||
|
* instead of deriving from stl::map directly. use DEFINE_XML_TYPE
|
||
|
* to define tag name for collections element. Define OnNewElement
|
||
|
*
|
||
|
* NOTE: Your class should implement: GetXMLType() to be functional.
|
||
|
* you can use DEFINE_XML_TYPE macro to do it for you
|
||
|
*
|
||
|
* NOTE: Your class should implement: OnNewElement to be functional.
|
||
|
*
|
||
|
* NOTE: if provided implementation does not fit for you -
|
||
|
* use XMLMapCollectionBase instead and provide your own methods
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
template<class MT>
|
||
|
class XMLMapCollection: public XMLMapCollectionBase, public MT
|
||
|
{
|
||
|
typedef MT::iterator iter_t;
|
||
|
public:
|
||
|
virtual void Persist(CPersistor& persistor)
|
||
|
{
|
||
|
if (persistor.IsStoring())
|
||
|
{
|
||
|
for(iter_t it = begin(); it != end(); ++it)
|
||
|
{
|
||
|
MT::key_type *pKey = const_cast<MT::key_type*>(&it->first);
|
||
|
persistor.Persist(*pKey);
|
||
|
persistor.Persist(it->second);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
clear();
|
||
|
XMLMapCollectionBase::Persist(persistor);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class XMLMapCollectionImp
|
||
|
*
|
||
|
* PURPOSE: A base class for stl::map derived collections implementing persitence of
|
||
|
* the map items as linear sequence of xml items.
|
||
|
* The items kept in the map must be either CXMLObject-derived or be
|
||
|
* of the simple type (one accepted by CXMLVBalue constructors)
|
||
|
*
|
||
|
* USAGE: Derive your class from XMLMapCollectionImp parametrized by the map,
|
||
|
* instead of deriving from stl::map directly. use DEFINE_XML_TYPE
|
||
|
* to define tag name for collections element.
|
||
|
*
|
||
|
* NOTE: Your class should implement: GetXMLType() to be functional.
|
||
|
* you can use DEFINE_XML_TYPE macro to do it for you
|
||
|
*
|
||
|
* NOTE: if provided implementation does not fit for you - f.i. your elements need
|
||
|
* a parameter to the constructor, or special initialization,
|
||
|
* use XMLMapCollection or XMLMapCollectionBase instead and provide your own methods
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
template<class MT>
|
||
|
class XMLMapCollectionImp: public XMLMapCollection<MT>
|
||
|
{
|
||
|
public:
|
||
|
virtual void OnNewElement(CPersistor& persistKey,CPersistor& persistVal)
|
||
|
{
|
||
|
MT::key_type key;
|
||
|
persistKey.Persist(key);
|
||
|
|
||
|
MT::referent_type val;
|
||
|
persistVal.Persist(val);
|
||
|
|
||
|
insert(MT::value_type(key,val));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class XMLListCollectionWrap
|
||
|
*
|
||
|
* PURPOSE: A wrapper around stl::map to support persisting
|
||
|
* To be used to persist stl::map objects "from outside" - i.e. without
|
||
|
* deriving the map class from persistence-enabled classes.
|
||
|
*
|
||
|
* USAGE: If you have map m_m to persist, create the object XMLMapCollectionWrap wrap(m_m,"tag")
|
||
|
* on the stack and persist that object (f.i. Persistor.Persist(wrap)
|
||
|
*
|
||
|
* NOTE: if provided implementation does not fit for you - see if you can use
|
||
|
* XMLMapCollection or XMLMapCollectionImp or XMLMapCollectionBase as a base for your map
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
template<class MT>
|
||
|
class XMLMapCollectionWrap: public XMLMapCollectionBase
|
||
|
{
|
||
|
typedef MT::iterator iter_t;
|
||
|
MT & m_m;
|
||
|
CStr m_strMapType;
|
||
|
public:
|
||
|
XMLMapCollectionWrap(MT &m, const CStr &strMapType) : m_m(m), m_strMapType(strMapType) {}
|
||
|
virtual void OnNewElement(CPersistor& persistKey,CPersistor& persistVal)
|
||
|
{
|
||
|
MT::key_type key;
|
||
|
persistKey.Persist(key);
|
||
|
|
||
|
MT::referent_type val;
|
||
|
persistVal.Persist(val);
|
||
|
|
||
|
m_m.insert(MT::value_type(key,val));
|
||
|
}
|
||
|
virtual void Persist(CPersistor& persistor)
|
||
|
{
|
||
|
if (persistor.IsStoring())
|
||
|
{
|
||
|
for(iter_t it = m_m.begin(); it != m_m.end(); ++it)
|
||
|
{
|
||
|
MT::key_type *pKey = const_cast<MT::key_type*>(&it->first);
|
||
|
persistor.Persist(*pKey);
|
||
|
persistor.Persist(it->second);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_m.clear();
|
||
|
XMLMapCollectionBase::Persist(persistor);
|
||
|
}
|
||
|
}
|
||
|
virtual LPCTSTR GetXMLType() {return m_strMapType;}
|
||
|
private:
|
||
|
// to prevent ivalid actions on object
|
||
|
XMLMapCollectionWrap(const XMLMapCollectionWrap& other);
|
||
|
XMLMapCollectionWrap& operator = ( const XMLMapCollectionWrap& other ) { return *this; }
|
||
|
};
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class CPersistor
|
||
|
*
|
||
|
*
|
||
|
* PURPOSE: Defines the Persistor class used for XML serialization
|
||
|
* Persistors are aware if the file is being loaded or saved. Thus,
|
||
|
* methods like Persist work for both directions, and
|
||
|
* uses references to the data being persisted.
|
||
|
*
|
||
|
* USAGE: 1) a persistor can be created "underneath" another persistor, using
|
||
|
* the appropriate constructor.
|
||
|
* 2) To make an object persistable, derive it from CXMLObject, and
|
||
|
* implement the abstract methods. The syntax persistor.Persits(object)
|
||
|
* will then automatically work correctly.
|
||
|
* 3) To persist an element use Pesist method. It will create new / locate
|
||
|
* CPersist object for an element (under this persistor's element)
|
||
|
* 4) Collection classes when persisting their members specify "bLockedOnChild"
|
||
|
* constructors parameter as "true". This technique changes persistor's
|
||
|
* behavior. Insted of loacting the element (#3), constructor of new
|
||
|
* persistor will only check if element pointed by parent is of required type.
|
||
|
*
|
||
|
* NOTES: 1) StringTableStrings can be saved with either the ID inline or the
|
||
|
* actual string value inline. The latter is useful when loading/saving
|
||
|
* XML to/from a string instead of a file. This is controlled by the
|
||
|
* EnableValueSplit method.
|
||
|
* Binary storage usage is also controlled by it
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
class CPersistor
|
||
|
{
|
||
|
// NOTE: if member variable is to be inherited by child persistors,
|
||
|
// don't forget to add it to CPersistor::BecomeAChildOf method
|
||
|
CXMLDocument m_XMLDocument;
|
||
|
CXMLElement m_XMLElemCurrent;
|
||
|
bool m_bIsLoading;
|
||
|
bool m_bLockedOnChild;
|
||
|
DWORD m_dwModeFlags; // any special modes
|
||
|
|
||
|
private:
|
||
|
void SetMode(PersistorMode mode, bool bEnable) {m_dwModeFlags = (m_dwModeFlags & ~mode) | (bEnable ? mode : 0);}
|
||
|
bool IsModeSet(PersistorMode mode) {return (m_dwModeFlags & mode);}
|
||
|
public:
|
||
|
void SetMode(PersistorMode mode) {m_dwModeFlags = mode;}
|
||
|
|
||
|
|
||
|
public:
|
||
|
// construct a persistor from a parent persistor.
|
||
|
// this creates a new XML element with the given name,
|
||
|
// and everything persisted to the new persistor
|
||
|
// is persisted under this element.
|
||
|
CPersistor(CPersistor &persistorParent, const CStr &strElementType, LPCTSTR szElementName = NULL);
|
||
|
// construct a new persistor for given document and root element
|
||
|
// everything persisted to the new persistor
|
||
|
// is persisted under this element.
|
||
|
CPersistor(CXMLDocument &document, CXMLElement& rElemRoot);
|
||
|
// used to create child persistor on particular element
|
||
|
// bLockedOnChild is used to create a "fake parent" persistor, which
|
||
|
// will always return the child without trying to locate it (pElemCurrent)
|
||
|
CPersistor(CPersistor &other, CXMLElement& rElemCurrent, bool bLockedOnChild = false);
|
||
|
|
||
|
CXMLDocument & GetDocument() {return (m_XMLDocument);}
|
||
|
CXMLElement & GetCurrentElement() {return (m_XMLElemCurrent);}
|
||
|
bool HasElement(const CStr &strElementType, LPCTSTR szstrElementName);
|
||
|
void EnableValueSplit (bool bEnable) { SetMode(persistorModeValueSplitEnabled, bEnable); }
|
||
|
|
||
|
// the various modes
|
||
|
bool FEnableValueSplit() {return IsModeSet(persistorModeValueSplitEnabled);}
|
||
|
|
||
|
// Load/Store mode related functions.
|
||
|
bool IsLoading() {return m_bIsLoading;}
|
||
|
bool IsStoring() {return !m_bIsLoading;}
|
||
|
void SetLoading(bool b) {m_bIsLoading = b;}
|
||
|
|
||
|
// special methods to set/get the Name attribute of a persistor
|
||
|
void SetName(const CStr & strName);
|
||
|
CStr GetName();
|
||
|
|
||
|
// Canned persistence methods:
|
||
|
|
||
|
// .. to persist CXMLObject-derived object under own sub-element
|
||
|
// <this><object_tag>object_body</object_tag></this>
|
||
|
void Persist(CXMLObject &object, LPCTSTR lpstrName = NULL);
|
||
|
|
||
|
// .. to persist value of the simple type under own sub-element
|
||
|
// <this><value_type value="value"/></this>
|
||
|
void Persist(CXMLValue xval, LPCTSTR name = NULL);
|
||
|
|
||
|
// .. to persist value as named attribute of this element
|
||
|
// <this name="value"/>
|
||
|
void PersistAttribute(LPCTSTR name,CXMLValue xval,const XMLAttributeType type = attr_required);
|
||
|
|
||
|
// .. to persist value as contents of this element
|
||
|
// <this>value</this>
|
||
|
// NOTE: xml element cannot have both value-as-contents and sub-elements
|
||
|
void PersistContents(CXMLValue xval);
|
||
|
|
||
|
// .. to persist flags as separate attributes
|
||
|
void PersistAttribute( LPCTSTR name, CXMLBitFlags& flags );
|
||
|
|
||
|
/***************************************************************************\
|
||
|
*
|
||
|
* METHOD: CPersistor::PersistList
|
||
|
*
|
||
|
* PURPOSE: it is designated for persisting std::list type of collections
|
||
|
* as a subelement of the persistor.
|
||
|
* NOTE: list elements need to be either CXMLObject-derived or be
|
||
|
* of the simple type (one accepted by CXMLVBalue constructors)
|
||
|
* NOTE2: list elements must have default constuctor available
|
||
|
*
|
||
|
* PARAMETERS:
|
||
|
* const CStr &strListType - [in] tag of new subelement
|
||
|
* LPCTSTR name - [in] name attr. of new subelement (NULL == none)
|
||
|
* std::list<T,Al>& val - [in] list to be persisted
|
||
|
*
|
||
|
* RETURNS:
|
||
|
* void
|
||
|
*
|
||
|
\***************************************************************************/
|
||
|
template<class T, class Al>
|
||
|
void PersistList(const CStr &strListType, LPCTSTR name,std::list<T,Al>& val)
|
||
|
{
|
||
|
typedef std::list<T,Al> LT;
|
||
|
XMLListCollectionWrap<LT> lcol(val,strListType);
|
||
|
Persist(lcol, name);
|
||
|
}
|
||
|
|
||
|
/***************************************************************************\
|
||
|
*
|
||
|
* METHOD: PersistMap
|
||
|
*
|
||
|
* PURPOSE: it is designated for persisting std::map type of collections
|
||
|
* as a subelement of the persistor.
|
||
|
* NOTE: map elements (both key and val) need to be either CXMLObject-derived
|
||
|
* or be of the simple type (one accepted by CXMLVBalue constructors)
|
||
|
* NOTE2: map elements must have default constuctor available
|
||
|
*
|
||
|
* PARAMETERS:
|
||
|
* const CStr &strListType - [in] tag of new subelement
|
||
|
* LPCTSTR name - [in] name attr. of new subelement (NULL == none)
|
||
|
* std::map<K,T,Pr,Al>& val - [in] map to be persisted
|
||
|
*
|
||
|
* RETURNS:
|
||
|
* void
|
||
|
*
|
||
|
\***************************************************************************/
|
||
|
template<class K, class T, class Pr, class Al>
|
||
|
void PersistMap(const CStr &strMapType, LPCTSTR name, std::map<K, T, Pr, Al>& val)
|
||
|
{
|
||
|
typedef std::map<K, T, Pr, Al> MT;
|
||
|
XMLMapCollectionWrap<MT> mcol(val,strMapType);
|
||
|
Persist(mcol, name);
|
||
|
}
|
||
|
|
||
|
void PersistString(LPCTSTR lpstrName, CStringTableStringBase &str);
|
||
|
|
||
|
private: // private implementation helpers
|
||
|
// common constructor, not to be used from outside.
|
||
|
// provided as common place for member initialization
|
||
|
// all the constructors should call it prior to doing anything specific.
|
||
|
void CommonConstruct();
|
||
|
// element creation / locating
|
||
|
CXMLElement AddElement(const CStr &strElementType, LPCTSTR szElementName);
|
||
|
CXMLElement GetElement(const CStr &strElementType, LPCTSTR szstrElementName, int iIndex = -1);
|
||
|
void AddTextElement(BSTR bstrData);
|
||
|
void GetTextElement(CComBSTR &bstrData);
|
||
|
CXMLElement CheckCurrentElement(const CStr &strElementType, LPCTSTR szstrElementName);
|
||
|
void BecomeAChildOf(CPersistor &persistorParent, CXMLElement elem);
|
||
|
};
|
||
|
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class CXML_IStorage
|
||
|
*
|
||
|
* PURPOSE: This class provides memory-based implementation of IStorage plus
|
||
|
* it supports persisting the data on the storage to/from XML.
|
||
|
* Mostly used to create IStorage for snapin data to be saved
|
||
|
* to console file as XML binary blob
|
||
|
*
|
||
|
* USAGE: You will create the object whenever you need a memory-based IStorage
|
||
|
* implementation. To access IStorage interface use GetIStorage() method.
|
||
|
* It will create a storage if does not have one under control already.
|
||
|
* You will use returned pointer for Read and Write operations.
|
||
|
* Whenever required you will pass the object to CPersistor::Persist method
|
||
|
* to have it persisted using XML persistence model.
|
||
|
*
|
||
|
* NOTE: You are encoureged to use GetIStorage() for accessing the undelying IStorage.
|
||
|
* Do not cache returned pointer, since the storage may change when persisted
|
||
|
* from XML, and this invalidates the pointer. However if you AddRef,
|
||
|
* the pointer will be valid as long as the last reference is released.
|
||
|
* That means it may outlive CXML_IStorage object itself - nothing wrong with that.
|
||
|
* You only must be aware that once persistence (loading) from XML is completed,
|
||
|
* CXML_IStorage will switch to the new storage and it will not be in sync with
|
||
|
* the pointer you have. Always use GetIStorage() to get the current pointer.
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
class CXML_IStorage : public CXMLObject
|
||
|
{
|
||
|
public: // interface methods not throwing any exceptions
|
||
|
|
||
|
SC ScInitializeFrom( IStorage *pSource );
|
||
|
SC ScInitialize(bool& bCreatedNewOne);
|
||
|
SC ScGetIStorage( IStorage **ppStorage );
|
||
|
SC ScRequestSave(IPersistStorage * pPersistStorage);
|
||
|
|
||
|
// instruct to persist to binary storage
|
||
|
virtual bool UsesBinaryStorage() { return true; }
|
||
|
|
||
|
DEFINE_XML_TYPE(XML_TAG_ISTORAGE);
|
||
|
|
||
|
public: // interface methods throwing SC's
|
||
|
|
||
|
virtual void Persist(CPersistor &persistor);
|
||
|
|
||
|
private:
|
||
|
IStoragePtr m_Storage;
|
||
|
ILockBytesPtr m_LockBytes;
|
||
|
// following methods\data is for trace support in CHK builds
|
||
|
#ifdef DBG
|
||
|
public:
|
||
|
DBG_PersistTraceData m_dbg_Data;
|
||
|
#endif // #ifdef DBG
|
||
|
}; // class CXML_IStorage
|
||
|
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class CXML_IStream
|
||
|
*
|
||
|
* PURPOSE: This class provides memory-based implementation of IStream plus
|
||
|
* it supports persisting the data on the stream to/from XML.
|
||
|
* Mostly used to create IStream for snapin data to be saved
|
||
|
* to console file as XML binary blob
|
||
|
*
|
||
|
* USAGE: You will create the object whenever you need a memory-based IStream
|
||
|
* implementation. To access IStream interface use GetIStream() method.
|
||
|
* It will create a stream if does not have one under control already.
|
||
|
* You will use returned pointer for Read and Write operations.
|
||
|
* Whenever required you will pass the object to CPersistor::Persist method
|
||
|
* to have it persisted using XML persistence model.
|
||
|
*
|
||
|
* NOTE: You are encoureged to use GetIStream() for accessing the undelying IStream.
|
||
|
* Do not cache returned pointer, since the stream may change when persisted
|
||
|
* from XML, and this invalidates the pointer. However if you AddRef,
|
||
|
* the pointer will be valid as long as the last reference is released.
|
||
|
* That means it may outlive CXML_IStream object itself - nothing wrong with that.
|
||
|
* You only must be aware that once persistence (loading) from XML is completed,
|
||
|
* CXML_IStream will switch to the new stream and it will not be in sync with
|
||
|
* the pointer you have. Always use GetIStream() to get the current pointer.
|
||
|
*
|
||
|
* NOTE: Every call to GetIStream() moves stream cursor to the begining of the stream
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
class CXML_IStream : public CXMLObject
|
||
|
{
|
||
|
public: // interface methods not throwing any exceptions
|
||
|
|
||
|
SC ScInitializeFrom( IStream *pSource );
|
||
|
SC ScInitialize(bool& bCreatedNewOne);
|
||
|
SC ScSeekBeginning();
|
||
|
SC ScGetIStream( IStream **ppStream );
|
||
|
SC ScRequestSave(IPersistStorage * pPersistStream);
|
||
|
inline SC ScRequestSave(IPersistStream * pPersistStream)
|
||
|
{
|
||
|
return ScRequestSaveX(pPersistStream);
|
||
|
}
|
||
|
inline SC ScRequestSave(IPersistStreamInit * pPersistStreamInit)
|
||
|
{
|
||
|
return ScRequestSaveX(pPersistStreamInit);
|
||
|
}
|
||
|
|
||
|
// instruct to persist to binary storage
|
||
|
virtual bool UsesBinaryStorage() { return true; }
|
||
|
|
||
|
DEFINE_XML_TYPE(XML_TAG_ISTREAM);
|
||
|
|
||
|
public:
|
||
|
virtual void Persist(CPersistor &persistor);
|
||
|
|
||
|
private:
|
||
|
template<class TIPS>
|
||
|
SC ScRequestSaveX(TIPS * pPersistStream)
|
||
|
{
|
||
|
DECLARE_SC(sc, TEXT("CXML_IStream::ScRequestSaveX"));
|
||
|
|
||
|
// initialize
|
||
|
bool bCreatedNewOne = false; // unused here
|
||
|
sc = ScInitialize(bCreatedNewOne);
|
||
|
if (sc)
|
||
|
return sc;
|
||
|
|
||
|
// recheck pointers
|
||
|
sc = ScCheckPointers( m_Stream, E_UNEXPECTED );
|
||
|
if (sc)
|
||
|
return sc;
|
||
|
|
||
|
ULARGE_INTEGER null_size = { 0, 0 };
|
||
|
sc = m_Stream->SetSize( null_size );
|
||
|
if(sc)
|
||
|
return sc;
|
||
|
|
||
|
sc = ScSeekBeginning();
|
||
|
if(sc)
|
||
|
return sc;
|
||
|
|
||
|
sc = pPersistStream->Save( m_Stream, TRUE );
|
||
|
if(sc)
|
||
|
return sc;
|
||
|
|
||
|
// commit the changes - this ensures everything is in HGLOBAL
|
||
|
sc = m_Stream->Commit( STGC_DEFAULT );
|
||
|
if(sc)
|
||
|
return sc;
|
||
|
|
||
|
#ifdef DBG
|
||
|
if (S_FALSE != pPersistStream->IsDirty())
|
||
|
DBG_TraceNotResettingDirty(typeid(TIPS).name());
|
||
|
#endif // #ifdef DBG
|
||
|
|
||
|
return sc;
|
||
|
}
|
||
|
private:
|
||
|
IStreamPtr m_Stream;
|
||
|
#ifdef DBG // tracing support
|
||
|
public:
|
||
|
DBG_PersistTraceData m_dbg_Data;
|
||
|
void DBG_TraceNotResettingDirty(LPCSTR strIntfName);
|
||
|
#endif // #ifdef DBG
|
||
|
}; // class CXML_IStream
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* class CXMLPersistableIcon
|
||
|
*
|
||
|
* PURPOSE: Persists wraps for persisting CPersistableIcon
|
||
|
*
|
||
|
* USAGE: Create object whenever you need to persist to CPersistableIcon
|
||
|
*
|
||
|
*+-------------------------------------------------------------------------*/
|
||
|
|
||
|
class CPersistableIcon;
|
||
|
|
||
|
class CXMLPersistableIcon : public CXMLObject
|
||
|
{
|
||
|
CPersistableIcon& m_Icon;
|
||
|
public:
|
||
|
CXMLPersistableIcon(CPersistableIcon& Icon) : m_Icon(Icon) {}
|
||
|
DEFINE_XML_TYPE(XML_TAG_ICON);
|
||
|
virtual void Persist(CPersistor &persistor);
|
||
|
};
|
||
|
|
||
|
|
||
|
/*+-------------------------------------------------------------------------*
|
||
|
* CXMLVariant
|
||
|
*
|
||
|
* This class implements a CComVariant that can persist itself to/from an
|
||
|
* XML persistor.
|
||
|
*--------------------------------------------------------------------------*/
|
||
|
|
||
|
class CXMLVariant :
|
||
|
public CComVariant,
|
||
|
public CXMLObject
|
||
|
{
|
||
|
public:
|
||
|
// construction and assignment forwarders
|
||
|
CXMLVariant() {}
|
||
|
CXMLVariant(const VARIANT& varSrc) : CComVariant(varSrc) {}
|
||
|
CXMLVariant(const CComVariant& varSrc) : CComVariant(varSrc) {}
|
||
|
CXMLVariant(const CXMLVariant& varSrc) : CComVariant(varSrc) {}
|
||
|
CXMLVariant(BSTR bstrSrc) : CComVariant(bstrSrc) {}
|
||
|
CXMLVariant(LPCOLESTR lpszSrc) : CComVariant(lpszSrc) {}
|
||
|
#ifndef OLE2ANSI
|
||
|
CXMLVariant(LPCSTR lpszSrc) : CComVariant(lpszSrc) {}
|
||
|
#endif
|
||
|
CXMLVariant(bool bSrc) : CComVariant(bSrc) {}
|
||
|
CXMLVariant(int nSrc) : CComVariant(nSrc) {}
|
||
|
CXMLVariant(BYTE nSrc) : CComVariant(nSrc) {}
|
||
|
CXMLVariant(short nSrc) : CComVariant(nSrc) {}
|
||
|
CXMLVariant(float fltSrc) : CComVariant(fltSrc) {}
|
||
|
CXMLVariant(double dblSrc) : CComVariant(dblSrc) {}
|
||
|
CXMLVariant(CY cySrc) : CComVariant(cySrc) {}
|
||
|
CXMLVariant(long nSrc, VARTYPE vtSrc = VT_I4) : CComVariant(nSrc, vtSrc) {}
|
||
|
|
||
|
CXMLVariant& operator=(const CXMLVariant& varSrc) { CComVariant::operator=(varSrc); return (*this); }
|
||
|
CXMLVariant& operator=(const CComVariant& varSrc) { CComVariant::operator=(varSrc); return (*this); }
|
||
|
CXMLVariant& operator=(const VARIANT& varSrc) { CComVariant::operator=(varSrc); return (*this); }
|
||
|
CXMLVariant& operator=(BSTR bstrSrc) { CComVariant::operator=(bstrSrc); return (*this); }
|
||
|
CXMLVariant& operator=(LPCOLESTR lpszSrc) { CComVariant::operator=(lpszSrc); return (*this); }
|
||
|
#ifndef OLE2ANSI
|
||
|
CXMLVariant& operator=(LPCSTR lpszSrc) { CComVariant::operator=(lpszSrc); return (*this); }
|
||
|
#endif
|
||
|
CXMLVariant& operator=(bool bSrc) { CComVariant::operator=(bSrc); return (*this); }
|
||
|
CXMLVariant& operator=(int nSrc) { CComVariant::operator=(nSrc); return (*this); }
|
||
|
CXMLVariant& operator=(BYTE nSrc) { CComVariant::operator=(nSrc); return (*this); }
|
||
|
CXMLVariant& operator=(short nSrc) { CComVariant::operator=(nSrc); return (*this); }
|
||
|
CXMLVariant& operator=(long nSrc) { CComVariant::operator=(nSrc); return (*this); }
|
||
|
CXMLVariant& operator=(float fltSrc) { CComVariant::operator=(fltSrc); return (*this); }
|
||
|
CXMLVariant& operator=(double dblSrc) { CComVariant::operator=(dblSrc); return (*this); }
|
||
|
CXMLVariant& operator=(CY cySrc) { CComVariant::operator=(cySrc); return (*this); }
|
||
|
|
||
|
public:
|
||
|
DEFINE_XML_TYPE(XML_TAG_VARIANT);
|
||
|
virtual void Persist(CPersistor &persistor);
|
||
|
|
||
|
bool IsPersistable() const
|
||
|
{ return (IsPersistable(this)); }
|
||
|
|
||
|
static bool IsPersistable(const VARIANT* pvar)
|
||
|
{
|
||
|
if (pvar == NULL)
|
||
|
return (false);
|
||
|
|
||
|
/*
|
||
|
* we can only store variants that are "simple" (i.e. not by-ref,
|
||
|
* array, etc.)
|
||
|
*/
|
||
|
return ((V_VT(pvar) & ~VT_TYPEMASK) == 0);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/***************************************************************************\
|
||
|
*
|
||
|
* CLASS: CConsoleFilePersistor
|
||
|
*
|
||
|
* PURPOSE: File persistence black box. all console file - user data logic
|
||
|
* is hiden under this class
|
||
|
*
|
||
|
* USAGE: Use instance of this class to load and save console file,
|
||
|
* NOTE - saving should be done with the same instance the console
|
||
|
* was loaded.
|
||
|
* Good idea for your class maintaning console (such as AMCDocument)
|
||
|
* to either derive of contain instance of this class
|
||
|
*
|
||
|
\***************************************************************************/
|
||
|
class CConsoleFilePersistor
|
||
|
{
|
||
|
public: // public interface
|
||
|
|
||
|
CConsoleFilePersistor() : m_bCRCValid(false) {}
|
||
|
|
||
|
SC ScSaveConsole(LPCTSTR lpstrConsolePath, bool bForAuthorMode, const CXMLDocument& xmlDocument);
|
||
|
SC ScLoadConsole(LPCTSTR lpstrConsolePath, bool& bXmlBased, CXMLDocument& xmlDocument,
|
||
|
IStorage **ppStorage);
|
||
|
|
||
|
static SC ScGetUserDataFolder(tstring& strUserDataFolder);
|
||
|
|
||
|
private: // implementation helpers
|
||
|
|
||
|
static SC ScGetUserDataPath(LPCTSTR lpstrOriginalPath, tstring& strUserDataPath);
|
||
|
static SC ScGetUserData(const tstring& strUserDataConsolePath,
|
||
|
const tstring& strFileCRC,
|
||
|
bool& bValid, CXMLDocument& xmlDocument);
|
||
|
|
||
|
static SC ScOpenDocAsStructuredStorage(LPCTSTR lpszPathName, IStorage **ppStorage);
|
||
|
static SC ScLoadXMLDocumentFromFile(CXMLDocument& xmlDocument, LPCTSTR strFileName, bool bSilentOnErrors = false);
|
||
|
|
||
|
private: // compress/uncompress the file
|
||
|
static void GetBinaryCollection(CXMLDocument& xmlDocument, CXMLElementCollection& colBinary);
|
||
|
static SC ScCompressUserStateFile(LPCTSTR szConsoleFilePath, CXMLDocument & xmlDocument);
|
||
|
static SC ScUncompressUserStateFile(CXMLDocument &xmlDocumentOriginal, CXMLDocument& xmlDocument);
|
||
|
|
||
|
private: // internal data
|
||
|
|
||
|
tstring m_strFileCRC;
|
||
|
bool m_bCRCValid;
|
||
|
};
|
||
|
|
||
|
#endif // XMLBASE_H
|
||
|
|
||
|
|