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.
262 lines
9.0 KiB
262 lines
9.0 KiB
// marsfact.h
|
|
// header file for class CMarsXMLFactory,
|
|
// a callback class for the XML Push model parser
|
|
// CMarsXMLFactory is used to construct a MARS its file from the xml
|
|
#pragma once
|
|
|
|
#include "stack.h"
|
|
#include <xmlparser.h>
|
|
|
|
// forward declarations of data structures
|
|
class CXMLElement;
|
|
struct TagInformation;
|
|
|
|
class CMarsXMLFactory : public CMarsComObject,
|
|
public IXMLNodeFactory
|
|
{
|
|
public:
|
|
CMarsXMLFactory();
|
|
virtual ~CMarsXMLFactory();
|
|
|
|
// IUnknown
|
|
STDMETHOD_(ULONG,AddRef)();
|
|
STDMETHOD_(ULONG,Release)();
|
|
STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject);
|
|
|
|
// CMarsComObject
|
|
// This class has no back references so the passivate stuff is a noop
|
|
virtual HRESULT DoPassivate() { return S_OK; }
|
|
|
|
// IXMLNodeFactory - used to communicate with the IXMLParser
|
|
virtual HRESULT STDMETHODCALLTYPE NotifyEvent(
|
|
IXMLNodeSource *pSource, XML_NODEFACTORY_EVENT iEvt);
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE BeginChildren(
|
|
IXMLNodeSource *pSource, XML_NODE_INFO *pNodeInfo);
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE EndChildren(
|
|
IXMLNodeSource *pSource, BOOL fEmpty,
|
|
XML_NODE_INFO *pNodeInfo);
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE Error(
|
|
IXMLNodeSource *pSource, HRESULT hrErrorCode,
|
|
USHORT cNumRecs, XML_NODE_INFO **apNodeInfo);
|
|
|
|
virtual HRESULT STDMETHODCALLTYPE CreateNode(
|
|
IXMLNodeSource *pSource, PVOID pNodeParent,
|
|
USHORT cNumRecs, XML_NODE_INFO **apNodeInfo);
|
|
|
|
|
|
// CMarsXMLFactory
|
|
|
|
// Call "Run" when you want to start parsing...
|
|
// Note: pisDoc must be a synchronous stream (not E_PENDING) -- so there!
|
|
HRESULT Run(IStream *pisDoc);
|
|
|
|
// Set the TagInformation* array used to create nodes. These
|
|
// arrays should be const and live past the lifetime of the
|
|
// parsing; they are not copied
|
|
void SetTagInformation(TagInformation **ptiaTags);
|
|
|
|
// Sets the LONG parameter passed as the last argument to all of
|
|
// the nodes created in CreateNode. (See the definition of
|
|
// CreationFunction below) This parameter is the way to provide
|
|
// your run-time pointer/reference or whatever to the objects that
|
|
// the xml is supposed to be initializing
|
|
void SetLParam(LONG lParamNew);
|
|
|
|
|
|
protected:
|
|
HRESULT SetElementAttributes(CXMLElement *pxElem,
|
|
XML_NODE_INFO **apNodeInfo, ULONG cInfoLen);
|
|
HRESULT CreateElement(LPCWSTR wzTagName, ULONG cLen, CXMLElement **ppxElem);
|
|
|
|
|
|
CStack<CXMLElement *> m_elemStack;
|
|
TagInformation **m_ptiaTags;
|
|
LONG m_lParamArgument;
|
|
};
|
|
|
|
|
|
|
|
|
|
// The AttributeInformation and TagInformation structs, which are used to determine syntax: what
|
|
// element creation function is called for what tag name
|
|
struct AttributeInformation
|
|
{
|
|
LPWSTR wzAttName;
|
|
VARTYPE vt;
|
|
};
|
|
|
|
typedef CXMLElement * (*CreationFunction)(LPCWSTR, VARTYPE, TagInformation **, AttributeInformation **, LONG lParam);
|
|
|
|
struct TagInformation
|
|
{
|
|
LPWSTR wzTagName;
|
|
CreationFunction funcCreate;
|
|
VARTYPE vt;
|
|
TagInformation **ptiaChildren;
|
|
AttributeInformation **paiaAttributes;
|
|
};
|
|
|
|
// The CXMLElement class, from which all the elements used by the
|
|
// CMarsXMLFactory must be derived. The methods can be pick and chose
|
|
// implemented; the base class implementations spew a TraceMsg error
|
|
// and return S_FALSE or E_NOTIMPL as appropriate
|
|
class CXMLElement
|
|
{
|
|
private:
|
|
ULONG m_cRef;
|
|
|
|
public:
|
|
|
|
// CXMLElement is NOT a COM object, so these methods are
|
|
// given wierd names to prevent confusion...
|
|
|
|
ULONG Add_Ref() { return ++m_cRef; }
|
|
|
|
ULONG Release_Ref()
|
|
{
|
|
if (--m_cRef == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
else return m_cRef;
|
|
}
|
|
|
|
// these methods are used by the CMarsXMLFactory and should return S_FALSE on not impl
|
|
// (to indicate an unexpected operation due to unexpected xml)
|
|
virtual HRESULT OnNodeComplete();
|
|
// Addchild takes ownership of the element on S_OK; otherwise CMarsXMLFactory deletes pxeChild
|
|
virtual HRESULT AddChild(CXMLElement *pxeChild);
|
|
|
|
virtual HRESULT SetAttribute(LPCWSTR wzName, ULONG cLenName,
|
|
LPCWSTR pwzValue, ULONG cLenValue);
|
|
|
|
//
|
|
// HACKHACK paddywack:
|
|
// The implementer of this function should be aware of the strange
|
|
// semantics here: SetInnerXMLText is sometimes called multiple times
|
|
// due to issues with the Push-model parser. If SetInnerXMLText is called
|
|
// more than once, the subsequent called mean "AppendInnerXMLText". :)
|
|
//
|
|
virtual HRESULT SetInnerXMLText(LPCWSTR pwzText, ULONG cLen);
|
|
|
|
// GetName can return NULL
|
|
virtual LPCWSTR GetName();
|
|
|
|
// The rest of these methods are generalized methods to access CXMLElements.
|
|
// They should generally return E_whatever on failure or not impl.
|
|
// This interface can be changed, as long as whoever changes it also makes sure
|
|
// to serve up the changes in CXMLGenericElement
|
|
// These methods are not used by any of the code in marsfact.cpp
|
|
|
|
// The GetContent and GetAttribute methods return pointers to existing variants;
|
|
// these variants should be considered const
|
|
|
|
// TODO: No procedure should take VARIANT**: we need to make all of these
|
|
// VARIANT*
|
|
virtual HRESULT GetContent(VARIANT *pvarOut);
|
|
virtual HRESULT GetAttribute(LPCWSTR wzName, VARIANT *pvarOut);
|
|
virtual void FirstChild();
|
|
virtual void NextChild();
|
|
virtual CXMLElement *CurrentChild();
|
|
virtual CXMLElement *DetachCurrentChild();
|
|
virtual BOOL IsDoneChild();
|
|
|
|
protected:
|
|
CXMLElement() { m_cRef = 1; }
|
|
virtual ~CXMLElement() { ATLASSERT(0 == m_cRef); }
|
|
};
|
|
|
|
|
|
struct CSimpleNode
|
|
{
|
|
CSimpleNode *m_psnodeNext;
|
|
void *m_pvData;
|
|
};
|
|
|
|
// Generic implementation of the CXMLElement class.
|
|
class CXMLGenericElement : public CXMLElement
|
|
{
|
|
public:
|
|
virtual ~CXMLGenericElement();
|
|
|
|
virtual HRESULT OnNodeComplete();
|
|
|
|
virtual HRESULT AddChild(CXMLElement *pxeChild);
|
|
|
|
virtual HRESULT SetAttribute(LPCWSTR wzName, ULONG cLenName,
|
|
LPCWSTR pwzValue, ULONG cLenValue);
|
|
|
|
virtual HRESULT SetInnerXMLText(LPCWSTR pwzText, ULONG cLen);
|
|
virtual LPCWSTR GetName();
|
|
|
|
virtual HRESULT GetContent(VARIANT *pvarOut);
|
|
virtual HRESULT GetAttribute(LPCWSTR wzName, VARIANT *pvarOut);
|
|
|
|
|
|
virtual void FirstChild();
|
|
virtual void NextChild();
|
|
|
|
// These methods return NULL if invalid
|
|
// DetachCurrentChild does the same as CurrentChild, but also removes the child from the
|
|
// list
|
|
virtual CXMLElement *CurrentChild();
|
|
virtual CXMLElement *DetachCurrentChild();
|
|
|
|
virtual BOOL IsDoneChild();
|
|
|
|
static CXMLElement *CreateInstance(LPCWSTR wzName,
|
|
VARTYPE vt,
|
|
TagInformation **ptiaChildren,
|
|
AttributeInformation **paiaAttributes,
|
|
LONG lParam);
|
|
protected:
|
|
CXMLGenericElement(LPCWSTR wzName, VARTYPE vt,
|
|
TagInformation **ptiaChildren, AttributeInformation **paiaAttributes);
|
|
CXMLGenericElement() {}
|
|
|
|
VARTYPE m_vtData;
|
|
CComVariant m_varData;
|
|
CSimpleNode *m_psnodeAttributes;
|
|
// The header node is a member variable.
|
|
CSimpleNode m_snodeChildrenFirst;
|
|
CSimpleNode *m_psnodeChildrenFirst;
|
|
CSimpleNode *m_psnodeChildrenEnd;
|
|
CSimpleNode *m_psnodeChildrenIter;
|
|
|
|
TagInformation **m_ptiaChildren;
|
|
AttributeInformation **m_paiaAttributes;
|
|
|
|
CComBSTR m_bstrName;
|
|
};
|
|
|
|
|
|
// Some helpful functions for handling explicit length strings
|
|
|
|
// Returns true if the strings are the same up to the nth char,
|
|
// and the zero terminated string (third param) has a null character after that
|
|
// position
|
|
BOOL StrEqlNToSZ(const WCHAR *wzN, int n, const WCHAR *wzSZ);
|
|
|
|
// Retunrs true if wz is L"true" or L"TRUE" and cLen is 4
|
|
// Must be "bool" for CComVariant to become VT_BOOL
|
|
bool StrToIsTrueNW(const WCHAR *wz, ULONG cLen);
|
|
|
|
// Converts the first cLen chars to a long, returning a E_FAIL if there is a non-digit
|
|
// If L'\0' is encountered, the conversion stops at that point
|
|
HRESULT StrToLongNW(const WCHAR *wzString, ULONG cLen, LONG *plong);
|
|
|
|
// SpewTraceMessage copies the cLen wchars to a bstr and then
|
|
// calls TraceMsg(TF_XMLPARSING | TF_WARNING, L"%sstring=%s", wzDesc, wzBstr)
|
|
#ifdef DEBUG
|
|
void SpewUnrecognizedString(const WCHAR *wzString, ULONG cLen, const WCHAR *wzDesc);
|
|
#else
|
|
#define SpewUnrecognizedString(strByLength, len, strDesc)
|
|
#endif
|
|
|
|
// I used TraceMst(..., L"...%s...", string) all over the place without checking string;
|
|
// As everyone knows (except me!) printf faults on NULL for a %s arg, hence this macro
|
|
#define NULL_STRING_PROTECT(str) str ? str : L""
|