Leaked source code of windows server 2003
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.
 
 
 
 
 
 

705 lines
17 KiB

/*
* X P A T C H . C P P
*
* XML push model parsing for PROPPATCH requests
*
* Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
*/
#include "_xml.h"
// class CNFPatch -------------------------------------------------------------
//
SCODE
CNFPatch::ScCompleteAttribute (void)
{
SCODE sc = S_OK;
// Recording mode is only allowed when we are inside a property. There
// no support implemented for recording mode for multivalued properties.
//
Assert((ST_INPROP == m_state || ST_LEXTYPE == m_state) || VE_NOECHO == m_vestate);
// If we are value echoing, this is the point at which we much
// complete outputting the attribute (i.e. add the quotation mark
// after the value)
//
if (m_vestate == VE_INPROGRESS)
{
sc = m_xo.ScCompleteChildren ( FALSE, XML_ATTRIBUTE, L"", 0 );
if (FAILED(sc))
goto ret;
// Complete the current lextype
//
if (m_state == ST_LEXTYPE)
m_state = ST_INPROP;
}
// Normal processing -- values not being echoed
//
else if (m_state == ST_LEXTYPE)
{
// Complete the current lextype
//
// Note that m_ppctx is non-NULL if and only if
// ST_SET and the property to set is not a reserved
// property.
// (That means m_ppctx is NULL on ST_REMOVE, or if the impl
// didn't add a pctx, say because it's a reserved prop
// and they know the set of this prop will fail anyway....)
//
if ((m_sType == ST_SET) && m_ppctx.get())
{
m_sbValue.Append (sizeof(WCHAR), L"");
sc = m_ppctx->ScSetType (m_sbValue.PContents());
if (FAILED (sc))
goto ret;
m_sbValue.Reset();
}
m_state = ST_INPROP;
}
// Flags processing
//
else if (m_state == ST_FLAGS)
{
// Complete the current set of flags
//
// Note that m_ppctx is non-NULL if and only if
// ST_SET and the property to set is not a reserved
// property.
//
// That means m_ppctx is NULL on ST_REMOVE, or if the impl
// didn't add a pctx, say because it's a reserved prop
// and they know the set of this prop will fail anyway....
//
if ((m_sType == ST_SET) && m_ppctx.get())
{
m_sbValue.Append (sizeof(WCHAR), L"");
sc = m_ppctx->ScSetFlags (wcstol (m_sbValue.PContents(), NULL, 0));
if (FAILED (sc))
goto ret;
m_sbValue.Reset();
}
m_state = ST_INPROP;
}
else if (m_state == ST_SEARCHREQUEST)
{
sc = m_xo.ScCompleteChildren ( FALSE, XML_ATTRIBUTE, L"", 0 );
if (FAILED(sc))
goto ret;
}
ret:
return sc;
}
SCODE
CNFPatch::ScCompleteCreateNode (
/* [in] */ DWORD dwType)
{
// Recording mode is only allowed when we are inside a property. There
// no support implemented for recording mode for multivalued properties.
//
Assert((ST_INPROP == m_state || ST_LEXTYPE == m_state) || VE_NOECHO == m_vestate);
if (ST_SEARCHREQUEST == m_state || VE_INPROGRESS == m_vestate)
m_xo.CompleteCreateNode (dwType);
return S_OK;
}
SCODE
CNFPatch::ScCompleteChildren (
/* [in] */ BOOL fEmptyNode,
/* [in] */ DWORD dwType,
/* [in] */ const WCHAR __RPC_FAR *pwcText,
/* [in] */ ULONG ulLen)
{
SCODE sc = S_OK;
static const WCHAR wch = 0;
// Recording mode is only allowed when we are inside a property. There
// no support implemented for recording mode for multivalued properties.
//
Assert((ST_INPROP == m_state || ST_LEXTYPE == m_state) || VE_NOECHO == m_vestate);
switch (m_state)
{
case ST_UPDATE:
Assert (dwType == XML_ELEMENT);
m_state = ST_NODOC;
break;
case ST_SET:
case ST_DELETE:
Assert (dwType == XML_ELEMENT);
m_state = ST_UPDATE;
break;
case ST_PROPS:
Assert (dwType == XML_ELEMENT);
m_state = m_sType;
break;
case ST_SEARCHREQUEST:
// Do searchreqeust processing
//
Assert (dwType == XML_ELEMENT);
sc = m_xo.ScCompleteChildren (fEmptyNode,
dwType,
pwcText,
ulLen);
if (FAILED (sc))
goto ret;
// 26/NOV/99: MAXB
// REVIEW: if there are attributes will count really go to zero?
//
if (0 != m_xo.LDepth())
break;
// else fall through
case ST_INPROP:
// Complete the current property
//
// Note that m_ppctx is non-NULL if and only if
// ST_SET and the property to set is not a reserved
// property.
//
if (m_vestate != VE_NOECHO)
{
Assert (dwType == XML_ELEMENT);
sc = m_xo.ScCompleteChildren (fEmptyNode,
dwType,
pwcText,
ulLen);
if (FAILED (sc))
goto ret;
if (0 != m_xo.LDepth())
break;
m_vestate = VE_NOECHO;
}
Assert (dwType == XML_ELEMENT);
if ((m_sType == ST_SET) && m_ppctx.get())
{
m_sbValue.Append (sizeof(wch), &wch);
sc = m_ppctx->ScSetValue (!fEmptyNode
? m_sbValue.PContents()
: NULL,
m_cmvValues);
if (FAILED (sc))
goto ret;
sc = m_ppctx->ScComplete (fEmptyNode);
if (FAILED (sc))
goto ret;
m_cmvValues = 0;
m_sbValue.Reset();
m_ppctx.clear();
}
m_state = ST_PROPS;
break;
// When dealing with multivalued properties, we need this extra
// state such that each value gets added to the context via a single
// call to ScSetValue() with multiple values layed end-to-end.
//
case ST_INMVPROP:
Assert (dwType == XML_ELEMENT);
if ((m_sType == ST_SET) && m_ppctx.get())
{
// Terminate the current value.
//
m_sbValue.Append (sizeof(wch), &wch);
}
m_state = ST_INPROP;
break;
// We are finishing a <DAV:resourcetype> tag, reset state to ST_PROPS
//
case ST_RESOURCETYPE:
m_state = ST_PROPS;
break;
// We are inside a <DAV:resourcetype> tag, reset state to ST_RESOURCETYPE
//
case ST_STRUCTUREDDOCUMENT:
m_state = ST_RESOURCETYPE;
break;
}
ret:
return sc;
}
SCODE
CNFPatch::ScHandleNode (
/* [in] */ DWORD dwType,
/* [in] */ DWORD dwSubType,
/* [in] */ BOOL fTerminal,
/* [in] */ const WCHAR __RPC_FAR *pwcText,
/* [in] */ ULONG ulLen,
/* [in] */ ULONG ulNamespaceLen,
/* [in] */ const WCHAR __RPC_FAR *pwcNamespace,
/* [in] */ const ULONG ulNsPrefixLen)
{
CStackBuffer<WCHAR> wsz;
LPCWSTR pwszTag;
SCODE sc = S_FALSE;
UINT cch;
// Recording mode is only allowed when we are inside a property. There
// no support implemented for recording mode for multivalued properties.
//
Assert((ST_INPROP == m_state || ST_LEXTYPE == m_state) || VE_NOECHO == m_vestate);
// Forward to searchreqeust node handling
//
if (ST_SEARCHREQUEST == m_state)
{
sc = m_xo.ScHandleNode (dwType,
dwSubType,
fTerminal,
pwcText,
ulLen,
ulNamespaceLen,
pwcNamespace,
ulNsPrefixLen);
goto ret;
}
// If we are performing value echoing, do it now
// NOTE: that unlike ST_SEARCHREQUEST we *also*
// do other processing.
//
if (m_vestate == VE_INPROGRESS)
{
sc = m_xo.ScHandleNode (dwType,
dwSubType,
fTerminal,
pwcText,
ulLen,
ulNamespaceLen,
pwcNamespace,
ulNsPrefixLen);
if (FAILED(sc))
goto ret;
}
// Normal handling performed whether we are echoing
// values or not
//
switch (dwType)
{
case XML_ELEMENT:
// Handle any state changes based on element
// names
//
sc = ScHandleElementNode (dwType,
dwSubType,
fTerminal,
pwcText,
ulLen,
ulNamespaceLen,
pwcNamespace,
ulNsPrefixLen);
if (FAILED (sc))
goto ret;
break;
case XML_ATTRIBUTE:
if ((m_state == ST_INPROP) && (XML_NS != dwSubType))
{
cch = ulNamespaceLen + ulLen;
pwszTag = wsz.resize(CbSizeWsz(cch));
if (NULL == pwszTag)
{
sc = E_OUTOFMEMORY;
goto ret;
}
wcsncpy (wsz.get(), pwcNamespace, ulNamespaceLen);
wcsncpy (wsz.get() + ulNamespaceLen, pwcText, ulLen);
*(wsz.get() + cch) = 0;
// If this is a lextype attribute, make the
// appropriate transition
//
if (!_wcsnicmp (pwszTag, gc_wszLexType, cch) ||
!wcsncmp (pwszTag, gc_wszDataTypes, cch) ||
!wcsncmp (pwszTag, gc_wszLexTypeOfficial, cch))
{
m_state = ST_LEXTYPE;
sc = S_OK;
}
else if (!wcsncmp (pwszTag, gc_wszFlags, cch))
{
m_state = ST_FLAGS;
sc = S_OK;
}
}
break;
case XML_PCDATA:
case XML_WHITESPACE:
if (m_vestate != VE_INPROGRESS)
{
switch (m_state)
{
case ST_INPROP:
// If we are in the transition from outside, value to
// inside value -- and visa versa -- we do not want to
// add anything to the current buffer.
// Note that m_ppcxt may be NULL if we've encountered a
// reserved property in the request.
//
if ((XML_WHITESPACE == dwType) &&
(!m_ppctx.get() || m_ppctx->FMultiValued()))
break;
// !!! FALL THROUGH !!! */
case ST_INMVPROP:
// Note that m_ppctx is non-NULL if and only if
// ST_SET and the property to set is not a reserved
// property. If these are not set, then ignore the
// value.
//
if ((m_sType != ST_SET) || !m_ppctx.get())
break;
/* !!! FALL THROUGH !!! */
case ST_LEXTYPE:
case ST_FLAGS:
Assert (fTerminal);
// Build up the value for later use...
//
m_sbValue.Append (ulLen * sizeof(WCHAR), pwcText);
sc = S_OK;
}
}
}
ret:
return sc;
}
SCODE
CNFPatch::ScHandleElementNode (
/* [in] */ DWORD dwType,
/* [in] */ DWORD dwSubType,
/* [in] */ BOOL fTerminal,
/* [in] */ const WCHAR __RPC_FAR *pwcText,
/* [in] */ ULONG ulLen,
/* [in] */ ULONG ulNamespaceLen,
/* [in] */ const WCHAR __RPC_FAR *pwcNamespace,
/* [in] */ const ULONG ulNsPrefixLen)
{
CStackBuffer<WCHAR> wsz;
LPCWSTR pwszTag;
SCODE sc = S_FALSE;
UINT cch;
// Recording mode is only allowed when we are inside a property. There
// no support implemented for recording mode for multivalued properties.
//
Assert((ST_INPROP == m_state || ST_LEXTYPE == m_state) || VE_NOECHO == m_vestate);
// Construct the full name of the node
//
cch = ulNamespaceLen + ulLen;
pwszTag = wsz.resize(CbSizeWsz(cch));
if (NULL == pwszTag)
{
sc = E_OUTOFMEMORY;
goto ret;
}
wcsncpy (wsz.get(), pwcNamespace, ulNamespaceLen);
wcsncpy (wsz.get() + ulNamespaceLen, pwcText, ulLen);
*(wsz.get() + cch) = 0;
switch (m_state)
{
case ST_NODOC:
// If this is the topmost node in a propfind request,
// transition to the next state. Since there is no parent
// node to provide scoping, FIsTag() cannot be used here!
//
if (!wcscmp (pwszTag, gc_wszPropertyUpdate))
{
m_state = ST_UPDATE;
sc = S_OK;
}
break;
case ST_UPDATE:
// Look for our well know node types
//
if (FIsTag (pwszTag, gc_wszSet))
{
m_state = m_sType = ST_SET;
sc = S_OK;
}
else if (FIsTag (pwszTag, gc_wszRemove))
{
m_state = m_sType = ST_DELETE;
sc = S_OK;
}
break;
case ST_SET:
case ST_DELETE:
// Look for our well know node types
//
if (FIsTag (pwszTag, gc_wszProp))
{
m_state = ST_PROPS;
sc = S_OK;
}
break;
case ST_PROPS:
// Process the property as requested...
//
if (dwType == XML_ELEMENT)
{
m_state = ST_INPROP;
if (m_sType == ST_SET)
{
// Get a property context from the patch context
// that we can fill out and complete...
//
Assert (0 == m_cmvValues);
Assert (NULL == m_ppctx.get());
// If it's resourcetype request, change the state
// and don't set props
//
if (FIsTag (pwszTag, gc_wszResoucetype))
{
m_state = ST_RESOURCETYPE;
sc = S_OK;
}
else
{
sc = m_cpc.ScSetProp (NULL, pwszTag, m_ppctx);
if (FAILED (sc))
goto ret;
// Special handling for search requests, recording
// begins immediately
//
if (FIsTag (pwszTag, gc_wszSearchRequest))
{
CEmitNmspc cen(m_xo);
// Make the state transition and start recording
//
m_state = ST_SEARCHREQUEST;
sc = m_xo.ScHandleNode (dwType,
dwSubType,
fTerminal,
pwcText,
ulLen,
ulNamespaceLen,
pwcNamespace,
ulNsPrefixLen);
// Spit out the namespaces.
//
// Note that this will spit out any namespaces
// decl'd in the DAV:owner node itself. So we
// do not really want to emit these out to the
// owners comments until ScCompleteAttribute()
// is called.
//
Assert (!m_xo.FAddNamespaceDecl());
m_cache.ForEach(cen);
sc = S_OK;
}
// Special handling for case when we are PROPPATCH-ing
// XML valued properties. In this case we don't begin
// recording yet because we don't want the property
// node just the XML value inside
//
else if (FValueIsXML (pwszTag))
m_vestate = VE_NEEDNS;
}
}
else
{
// Queue the property for deletion with
// the patch context
//
Assert (m_sType == ST_DELETE);
sc = m_cpc.ScDeleteProp (NULL, pwszTag);
if (FAILED (sc))
goto ret;
}
}
break;
case ST_INPROP:
// Normal case -- value echoing is off. The work here is to
// deal with multivalued properties. In this case we need an extra
// state such that each value gets added to the context via a single
// call to ScSetValue() with multiple values layed end-to-end.
//
// NOTE: support for handling multivalued properties has not been
// added for echoing mode. If you add an XML valued multivalued
// property you need to do some work in the echo mode cases below
//
if (m_vestate == VE_NOECHO)
{
// m_ppctx is NULL when we have attempted to set a reserved
// (read only) property. when this happens, we need to continue
// parsing the request, but we don't actually set the properties.
// thus, we need to set the correct state as if this was a valid
// request.
//
if (NULL == m_ppctx.get())
{
m_state = ST_INMVPROP;
sc = S_OK;
}
else if (m_ppctx->FMultiValued() && FIsTag (pwszTag, gc_wszXml_V))
{
m_state = ST_INMVPROP;
m_cmvValues += 1;
sc = S_OK;
}
}
// We are echoing values or about to start echoing values
//
else
{
// If this is the first element seen that is part of an XML-valued
// property that we are PROPPATCH-ing, then we need to spit out
// the cached namespaces they are available to the EXOLEDB side
//
if (m_vestate == VE_NEEDNS)
{
CEmitNmspc cen(m_xo);
// Make the state transition and start recording
//
m_vestate = VE_INPROGRESS;
sc = m_xo.ScHandleNode (dwType,
dwSubType,
fTerminal,
pwcText,
ulLen,
ulNamespaceLen,
pwcNamespace,
ulNsPrefixLen);
// Spit out the namespaces.
//
// Note that this will spit out any namespaces
// decl'd in the DAV:owner node itself. So we
// do not really want to emit these out to the
// owners comments until ScCompleteAttribute()
// is called.
//
Assert (!m_xo.FAddNamespaceDecl());
m_cache.ForEach(cen);
}
// Indicate that additional namespace declarations
// should be echoed as we see them
//
m_xo.CompleteAttribute();
sc = S_OK;
}
break;
// We see a <DAV:resourcetype> tag. It should be in a MKCOL body.
//
case ST_RESOURCETYPE:
// If resourcetype is not structured doc, just ignore
//
if (FIsTag (pwszTag, gc_wszStructureddocument))
{
m_cpc.SetCreateStructureddocument();
m_state = ST_STRUCTUREDDOCUMENT;
sc = S_OK;
}
break;
}
ret:
return sc;
}
// Tags that have XML values that need to be shipped across epoxy
//
const WCHAR * gc_rgwszXMLValueTags[] =
{
L"http://schemas.microsoft.com/exchange/security/admindescriptor",
L"http://schemas.microsoft.com/exchange/security/descriptor",
L"http://schemas.microsoft.com/exchange/security/creator",
L"http://schemas.microsoft.com/exchange/security/lastmodifier",
L"http://schemas.microsoft.com/exchange/security/sender",
L"http://schemas.microsoft.com/exchange/security/sentrepresenting",
L"http://schemas.microsoft.com/exchange/security/originalsender",
L"http://schemas.microsoft.com/exchange/security/originalsentrepresenting",
L"http://schemas.microsoft.com/exchange/security/readreceiptfrom",
L"http://schemas.microsoft.com/exchange/security/reportfrom",
L"http://schemas.microsoft.com/exchange/security/originator",
L"http://schemas.microsoft.com/exchange/security/reportdestination",
L"http://schemas.microsoft.com/exchange/security/originalauthor",
L"http://schemas.microsoft.com/exchange/security/receivedby",
L"http://schemas.microsoft.com/exchange/security/receivedrepresenting",
};
//This function tests to see if a property has an XML value that must be
//shipped from DAVEX to EXOLEDB
//
BOOL
CNFPatch::FValueIsXML( const WCHAR *pwcTag )
{
BOOL f = FALSE;
ULONG iwsz;
for (iwsz = 0; iwsz < sizeof(gc_rgwszXMLValueTags)/sizeof(WCHAR *); iwsz ++)
{
if (wcscmp (pwcTag, gc_rgwszXMLValueTags[iwsz]) == 0)
{
f = TRUE;
break;
}
}
return f;
}