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.
514 lines
12 KiB
514 lines
12 KiB
/*
|
|
* X E M I T . H
|
|
*
|
|
* XML emitting
|
|
*
|
|
* Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
|
|
*/
|
|
|
|
#ifndef _EX_XEMIT_H_
|
|
#define _EX_XEMIT_H_
|
|
|
|
#include <ex\sz.h>
|
|
#include <ex\autoptr.h>
|
|
#include <ex\cnvt.h>
|
|
#include <ex\nmspc.h>
|
|
#include <ex\xmldata.h>
|
|
#include <ex\atomcache.h>
|
|
|
|
typedef UINT XNT;
|
|
|
|
// Interface IPreloadNamespaces
|
|
//
|
|
// This is a virtual class which is to be implemented by everyone
|
|
// that emits XML.
|
|
//
|
|
class CXMLEmitter;
|
|
class IPreloadNamespaces
|
|
{
|
|
// NOT IMPLEMENTED
|
|
//
|
|
IPreloadNamespaces& operator=( const IPreloadNamespaces& );
|
|
|
|
public:
|
|
// CREATORS
|
|
//
|
|
virtual ~IPreloadNamespaces() = 0 {};
|
|
|
|
// MANIPULATORS
|
|
//
|
|
virtual SCODE ScLoadNamespaces(CXMLEmitter* pxe) = 0;
|
|
};
|
|
|
|
// class CXMLEmitter ---------------------------------------------------------
|
|
//
|
|
class CXNode;
|
|
class CEmitterNode;
|
|
class CXMLEmitter : public CEmitterNmspcCache
|
|
{
|
|
private:
|
|
|
|
// Ref' counting.
|
|
//
|
|
// !!! Please note that this is NON-THREADSAFE !!!
|
|
//
|
|
// CXNodes should be operated on a single thread at
|
|
// any given time.
|
|
//
|
|
LONG m_cRef;
|
|
|
|
public:
|
|
|
|
void AddRef() { m_cRef++; }
|
|
void Release() { if (0 == --m_cRef) delete this; }
|
|
|
|
private:
|
|
// Other important bits
|
|
//
|
|
|
|
// Because CXNode::ScDone (which references IXMLBody * m_pxb) is called in CXNode
|
|
// dtor, so we must have m_pxb defined befor m_pxnRoot, so that it will be destroyed
|
|
// after CXNode is destroyed
|
|
//
|
|
auto_ref_ptr<IXMLBody> m_pxb;
|
|
|
|
auto_ref_ptr<CXNode> m_pxnRoot;
|
|
IPreloadNamespaces* m_pNmspcLoader;
|
|
NmspcCache m_cacheLocal;
|
|
|
|
class NmspcEmittingOp : public CNmspcCache::NmspcCache::IOp
|
|
{
|
|
private:
|
|
|
|
auto_ref_ptr<CXMLEmitter> m_emitter;
|
|
auto_ref_ptr<CXNode> m_pxnParent;
|
|
|
|
// NOT IMPLEMENTED
|
|
//
|
|
NmspcEmittingOp( const NmspcEmittingOp& );
|
|
NmspcEmittingOp& operator=( const NmspcEmittingOp& );
|
|
|
|
public:
|
|
|
|
NmspcEmittingOp (CXMLEmitter * pemitter,
|
|
CXNode * pxnParent)
|
|
:m_emitter (pemitter),
|
|
m_pxnParent (pxnParent)
|
|
{
|
|
}
|
|
|
|
BOOL operator()( const CRCWszN&,
|
|
const auto_ref_ptr<CNmspc>& nmspc );
|
|
};
|
|
|
|
// non-implemented
|
|
//
|
|
CXMLEmitter(const CXMLEmitter& p);
|
|
CXMLEmitter& operator=(const CXMLEmitter& p);
|
|
|
|
public:
|
|
|
|
~CXMLEmitter()
|
|
{
|
|
// According to standard C++, There's no garantee on the order of member
|
|
// being deleted. so delete explicitly.
|
|
//
|
|
m_pxnRoot.clear();
|
|
m_pxb.clear();
|
|
}
|
|
CXMLEmitter(IXMLBody * pxb, IPreloadNamespaces * pNmspcLoader = NULL)
|
|
: m_cRef(1),
|
|
m_pxb(pxb),
|
|
m_pNmspcLoader(pNmspcLoader)
|
|
{
|
|
INIT_TRACE(Xml);
|
|
}
|
|
|
|
CXNode* PxnRoot() { return m_pxnRoot.get(); }
|
|
|
|
// Find the appropriate namespace for the given name
|
|
//
|
|
SCODE ScFindNmspc (LPCWSTR, UINT, auto_ref_ptr<CNmspc>&);
|
|
|
|
// Attach the namespace to a given node
|
|
//
|
|
inline SCODE ScAddNmspc(const auto_ref_ptr<CNmspc>&, CXNode *);
|
|
|
|
SCODE ScAddAttribute (
|
|
/* [in] */ CXNode * pxn,
|
|
/* [in] */ LPCWSTR pwszTag,
|
|
/* [in] */ UINT cchTag,
|
|
/* [in] */ LPCWSTR pwszValue,
|
|
/* [in] */ UINT cchValue);
|
|
|
|
SCODE ScNewNode (
|
|
/* [in] */ XNT xnt,
|
|
/* [in] */ LPCWSTR pwszTag,
|
|
/* [in] */ CXNode* pxnParent,
|
|
/* [out] */ auto_ref_ptr<CXNode>& pxnOut);
|
|
|
|
// Create a root node for this document
|
|
// including prologue.
|
|
//
|
|
SCODE ScSetRoot (LPCWSTR);
|
|
|
|
// Create a root node with NO prologue, this node can be
|
|
// used to build XML piece.
|
|
//
|
|
// This function should not be used directly in IIS side. it may
|
|
// be used directly in store side to build XML chunks
|
|
//
|
|
SCODE ScNewRootNode (LPCWSTR);
|
|
SCODE ScPreloadNamespace (LPCWSTR pwszTag);
|
|
SCODE ScPreloadLocalNamespace (CXNode * pxn, LPCWSTR pwszTag);
|
|
VOID DoneWithLocalNamespace ()
|
|
{
|
|
// Reuse the namespace alises
|
|
//
|
|
//$ NOTE: we can do this by simply deducting the the number of aliases
|
|
//$ NOTE: in the local cache. because all local aliases are added
|
|
//$ NOTE: after root level aliases is added. so this way do cleanup
|
|
//$ NOTE: only those aliases taken the by the local cache.
|
|
//$ NOTE: Note that this is based on the fact that at any time, we
|
|
//$ NOTE: we have only one <response> node under contruction
|
|
//
|
|
AdjustAliasNumber (0 - m_cacheLocal.CItems());
|
|
|
|
// Cleanup all the entries in the local cache
|
|
//
|
|
m_cacheLocal.Clear();
|
|
}
|
|
|
|
VOID Done()
|
|
{
|
|
// Close the root node
|
|
//
|
|
m_pxnRoot.clear();
|
|
|
|
// Emit the body part;
|
|
//
|
|
m_pxb->Done();
|
|
}
|
|
};
|
|
|
|
// class CXNode --------------------------------------------------------------
|
|
//
|
|
class CXNode
|
|
{
|
|
private:
|
|
|
|
// Ref' counting.
|
|
//
|
|
// !!! Please note that this is NON-THREADSAFE !!!
|
|
//
|
|
// CXNodes should be operated on a single thread at
|
|
// any given time.
|
|
//
|
|
LONG m_cRef;
|
|
|
|
public:
|
|
|
|
void AddRef() { m_cRef++; }
|
|
void Release() { if (0 == --m_cRef) delete this; }
|
|
|
|
private:
|
|
|
|
// Node type
|
|
//
|
|
const XNT m_xnt;
|
|
|
|
// The body part manager
|
|
//
|
|
IXMLBody * m_pxb;
|
|
|
|
|
|
// The namespace that applies to this node
|
|
//
|
|
auto_ref_ptr<CNmspc> m_pns;
|
|
|
|
// The escaped property tag of the node.
|
|
//
|
|
auto_heap_ptr<WCHAR> m_pwszTagEscaped;
|
|
UINT m_cchTagEscaped;
|
|
|
|
// Whether or not the propertyname has an empty namespace (no namespace).
|
|
//
|
|
BOOL m_fHasEmptyNamespace;
|
|
|
|
// If an open node. i.e. <tag>, not <tag/>, Used for element node only
|
|
//
|
|
UINT m_fNodeOpen;
|
|
|
|
// Whether this node is done emitting
|
|
//
|
|
BOOL m_fDone;
|
|
|
|
// The CXMLEmitter from which we persist the pilot namespace
|
|
//
|
|
CXMLEmitter * m_pmsr;
|
|
|
|
// Emitting --------------------------------------------------------------
|
|
//
|
|
SCODE ScAddUnicodeResponseBytes (UINT cch, LPCWSTR pwsz);
|
|
SCODE ScAddEscapedValueBytes (UINT cch, LPCSTR psz);
|
|
SCODE ScAddEscapedAttributeBytes (UINT cch, LPCSTR psz);
|
|
SCODE ScWriteTagName ();
|
|
|
|
// non-implemented
|
|
//
|
|
CXNode(const CXNode& p);
|
|
CXNode& operator=(const CXNode& p);
|
|
|
|
public:
|
|
|
|
CXNode(XNT xnt, IXMLBody* pxb) :
|
|
m_cRef(1),
|
|
m_fDone(FALSE),
|
|
m_pmsr(NULL),
|
|
m_xnt(xnt),
|
|
m_fNodeOpen(FALSE),
|
|
m_cchTagEscaped(0),
|
|
m_pxb(pxb),
|
|
m_fHasEmptyNamespace(FALSE)
|
|
{
|
|
}
|
|
|
|
~CXNode()
|
|
{
|
|
if (!m_fDone)
|
|
{
|
|
// Close the node
|
|
//
|
|
//$REVIEW: ScDone() could only fail for E_OUTMEMORY. Yes, we cannot
|
|
//$REVIEW: return the failure from dtor. but how much better can be done
|
|
//$REVIEW: when run out of memory?
|
|
//$REVIEW: This does help to relievate the dependence on client to
|
|
//$REVIEW: call ScDone correctly. (Of course, they still need to declare
|
|
//$REVIEW: the nodes in correct order
|
|
//
|
|
(void)ScDone();
|
|
}
|
|
}
|
|
|
|
// CXNode types ----------------------------------------------------------
|
|
//
|
|
typedef enum {
|
|
|
|
XN_ELEMENT = 0,
|
|
XN_ATTRIBUTE,
|
|
XN_NAMESPACE
|
|
};
|
|
|
|
// Construction ----------------------------------------------------------
|
|
//
|
|
// Set the name of the node
|
|
//
|
|
SCODE ScSetTag (CXMLEmitter* pmsr, UINT cch, LPCWSTR pwszTag);
|
|
|
|
// Sets the value of a node.
|
|
//
|
|
// IMPORTANT: setting the value of a node appends the value of the node
|
|
// to the child.
|
|
//
|
|
SCODE ScSetValue (LPCSTR pszValue, UINT cch);
|
|
SCODE ScSetValue (LPCWSTR pwszValue, UINT cch);
|
|
SCODE ScSetValue (LPCWSTR pwszValue)
|
|
{
|
|
return ScSetValue (pwszValue, static_cast<UINT>(wcslen(pwszValue)));
|
|
}
|
|
SCODE ScSetUTF8Value (LPCSTR pszValue, UINT cch);
|
|
SCODE ScSetFormatedXML (LPCSTR pszValue, UINT cchValue);
|
|
SCODE ScSetFormatedXML (LPCWSTR pwszValue, UINT cchValue);
|
|
|
|
// Adds an child to the this node
|
|
//
|
|
SCODE ScGetChildNode (XNT xntType, CXNode ** ppxnChild);
|
|
SCODE ScDone();
|
|
};
|
|
|
|
// class CEmitterNode --------------------------------------------------------
|
|
//
|
|
class CEmitterNode
|
|
{
|
|
auto_ref_ptr<CXMLEmitter> m_emitter;
|
|
auto_ref_ptr<CXNode> m_pxn;
|
|
|
|
// non-implemented
|
|
//
|
|
CEmitterNode(const CEmitterNode& p);
|
|
CEmitterNode& operator=(const CEmitterNode& p);
|
|
|
|
public:
|
|
|
|
CEmitterNode ()
|
|
{
|
|
}
|
|
|
|
// Pass back a reference to the Emitter
|
|
//
|
|
CXMLEmitter* PEmitter() const { return m_emitter.get(); }
|
|
VOID SetEmitter (CXMLEmitter* pmsr) { m_emitter = pmsr; }
|
|
|
|
// Pass back a reference to the CXNode
|
|
//
|
|
CXNode* Pxn() const { return m_pxn.get(); }
|
|
VOID SetPxn (CXNode* pxn) { m_pxn = pxn; }
|
|
|
|
// New node construction -------------------------------------------------
|
|
//
|
|
SCODE ScConstructNode (CXMLEmitter& emitter,
|
|
CXNode * pxnParent,
|
|
LPCWSTR pwszTag,
|
|
LPCWSTR pwszValue = NULL,
|
|
LPCWSTR pwszType = NULL);
|
|
|
|
// Add a child node to this node. This API is the heart of the emitter
|
|
// processing and all other AddXXX() methods are written in terms of
|
|
// this method.
|
|
//
|
|
SCODE ScAddNode (LPCWSTR pwszTag,
|
|
CEmitterNode& en,
|
|
LPCWSTR pwszValue = NULL,
|
|
LPCWSTR pwszType = NULL);
|
|
|
|
// Non-wide char nodes
|
|
//
|
|
SCODE ScAddMultiByteNode (LPCWSTR pwszTag,
|
|
CEmitterNode& en,
|
|
LPCSTR pszValue,
|
|
LPCWSTR pwszType = NULL);
|
|
SCODE ScAddUTF8Node (LPCWSTR pwszTag,
|
|
CEmitterNode& en,
|
|
LPCSTR pszValue,
|
|
LPCWSTR pwszType = NULL);
|
|
|
|
|
|
// "date.iso8601"
|
|
//
|
|
SCODE ScAddDateNode (LPCWSTR pwszTag,
|
|
FILETIME * pft,
|
|
CEmitterNode& en);
|
|
// "int"
|
|
//
|
|
SCODE ScAddInt64Node (LPCWSTR pwszTag,
|
|
LARGE_INTEGER * pli,
|
|
CEmitterNode& en);
|
|
// "boolean"
|
|
//
|
|
SCODE ScAddBoolNode (LPCWSTR pwszTag,
|
|
BOOL f,
|
|
CEmitterNode& en);
|
|
// "bin.base64"
|
|
//
|
|
SCODE ScAddBase64Node (LPCWSTR pwszTag,
|
|
ULONG cb,
|
|
LPVOID pv,
|
|
CEmitterNode& en,
|
|
BOOL fSupressTypeAttr = FALSE,
|
|
// For WebFolders, we need to emit zero length
|
|
// binary properties as bin.hex instead of bin.base64.
|
|
//
|
|
BOOL fUseBinHexIfNoValue = FALSE);
|
|
|
|
// Multi-Status ----------------------------------------------------------
|
|
//
|
|
SCODE ScDone ()
|
|
{
|
|
SCODE sc = S_OK;
|
|
if (m_pxn.get())
|
|
{
|
|
sc = m_pxn->ScDone();
|
|
m_pxn.clear();
|
|
}
|
|
m_emitter.clear();
|
|
return sc;
|
|
}
|
|
};
|
|
|
|
// String constants ----------------------------------------------------------
|
|
//
|
|
DEC_CONST CHAR gc_chAmp = '&';
|
|
DEC_CONST CHAR gc_chBang = '!';
|
|
DEC_CONST CHAR gc_chColon = ':';
|
|
DEC_CONST CHAR gc_chDash = '-';
|
|
DEC_CONST CHAR gc_chEquals = '=';
|
|
DEC_CONST CHAR gc_chForwardSlash = '/';
|
|
DEC_CONST CHAR gc_chBackSlash = '\\';
|
|
DEC_CONST CHAR gc_chGreaterThan = '>';
|
|
DEC_CONST CHAR gc_chLessThan = '<';
|
|
DEC_CONST CHAR gc_chApos = '\'';
|
|
DEC_CONST CHAR gc_chQuestionMark = '?';
|
|
DEC_CONST CHAR gc_chQuote = '"';
|
|
DEC_CONST CHAR gc_chSpace = ' ';
|
|
DEC_CONST CHAR gc_szAmp[] = "&";
|
|
DEC_CONST CHAR gc_szGreaterThan[] = ">";
|
|
DEC_CONST CHAR gc_szLessThan[] = "<";
|
|
DEC_CONST CHAR gc_szApos[] = "'";
|
|
DEC_CONST CHAR gc_szQuote[] = """;
|
|
|
|
DEC_CONST WCHAR gc_wszAmp[] = L"&";
|
|
DEC_CONST WCHAR gc_wszGreaterThan[] = L">";
|
|
DEC_CONST WCHAR gc_wszLessThan[] = L"<";
|
|
DEC_CONST WCHAR gc_wszApos[] = L"'";
|
|
DEC_CONST WCHAR gc_wszQuote[] = L""";
|
|
|
|
// XML property emitting helpers ---------------------------------------------
|
|
//
|
|
SCODE __fastcall
|
|
ScEmitPropToXml (
|
|
/* [in] */ CEmitterNode* penProp,
|
|
/* [in] */ const BOOL fFilterValues,
|
|
/* [in] */ const USHORT usPt,
|
|
/* [in] */ const LPCWSTR wszTag,
|
|
/* [in] */ const BYTE* pb);
|
|
|
|
SCODE __fastcall
|
|
ScEmitStringPropToXml (
|
|
/* [in] */ CEmitterNode* penProp,
|
|
/* [in] */ const BOOL fFilterValues,
|
|
/* [in] */ const USHORT usPt,
|
|
/* [in] */ const LPCWSTR wszTag,
|
|
/* [in] */ const ULONG cpid,
|
|
/* [in] */ const UINT cch,
|
|
/* [in] */ const VOID* pv);
|
|
|
|
SCODE __fastcall
|
|
ScEmitBinaryPropToXml (
|
|
/* [in] */ CEmitterNode* penProp,
|
|
/* [in] */ const BOOL fFilterValues,
|
|
/* [in] */ const USHORT usPt,
|
|
/* [in] */ const LPCWSTR wszTag,
|
|
/* [in] */ const UINT cb,
|
|
/* [in] */ const BYTE* pb);
|
|
|
|
SCODE __fastcall
|
|
ScEmitMultiValuedAtomicToXml (
|
|
/* [in] */ CEmitterNode* penProp,
|
|
/* [in] */ const BOOL fFilterValues,
|
|
/* [in] */ const USHORT usPt,
|
|
/* [in] */ const UINT cbItem,
|
|
/* [in] */ const LPCWSTR wszTag,
|
|
/* [in] */ const ULONG cValues,
|
|
/* [in] */ const BYTE* pb);
|
|
|
|
SCODE __fastcall
|
|
ScEmitMutliValuedStringToXml (
|
|
/* [in] */ CEmitterNode* penProp,
|
|
/* [in] */ const BOOL fFilterValues,
|
|
/* [in] */ const USHORT usPt,
|
|
/* [in] */ const LPCWSTR wszTag,
|
|
/* [in] */ const ULONG cpid,
|
|
/* [in] */ const UINT cchMax,
|
|
/* [in] */ const LPVOID* pv);
|
|
|
|
SCODE __fastcall
|
|
ScEmitMutliValuedBinaryToXml (
|
|
/* [in] */ CEmitterNode* penProp,
|
|
/* [in] */ const BOOL fFilterValues,
|
|
/* [in] */ const USHORT usPt,
|
|
/* [in] */ const LPCWSTR wszTag,
|
|
/* [in] */ const BYTE** ppb,
|
|
/* [in] */ const DWORD* pcb,
|
|
/* [in] */ const DWORD cbMax);
|
|
|
|
#endif // _EX_XEMIT_H_
|