/* * X L O C K . C P P * * XML push model parsing for LOCK requests * * Copyright 1986-1997 Microsoft Corporation, All Rights Reserved */ #include "_xml.h" #include #include // Here are our LOCK XML elements // const WCHAR gc_wszLockActive[] = L"DAV:activelock"; const WCHAR gc_wszLockDepth[] = L"DAV:depth"; const WCHAR gc_wszLockDiscovery[] = L"DAV:lockdiscovery"; const WCHAR gc_wszLockEntry[] = L"DAV:lockentry"; const WCHAR gc_wszLockInfo[] = L"DAV:lockinfo"; const WCHAR gc_wszLockOwner[] = L"DAV:owner"; const WCHAR gc_wszLockScope[] = L"DAV:lockscope"; const WCHAR gc_wszLockScopeExclusive[] = L"DAV:exclusive"; const WCHAR gc_wszLockScopeShared[] = L"DAV:shared"; const WCHAR gc_wszLockSupportedlock[] = L"DAV:supportedlock"; const WCHAR gc_wszLockTimeout[] = L"DAV:timeout"; const WCHAR gc_wszLockToken[] = L"DAV:locktoken"; const WCHAR gc_wszLockType[] = L"DAV:locktype"; const WCHAR gc_wszLockTypeWrite[] = L"DAV:write"; const WCHAR gc_wszLockTypeCheckout[] = L"DAV:checkout"; const WCHAR gc_wszLockTypeTransaction[] = L"DAV:transaction"; const WCHAR gc_wszLockTypeTransactionGOP[] = L"DAV:groupoperation"; const WCHAR gc_wszLockScopeLocal[] = L"DAV:local"; // And one item from the rollback draft. // const WCHAR gc_wszLockRollback[] = L"http://www.iana.org/experimental/msrollback/rollback"; // UNLOCK xml elememts // const WCHAR gc_wszUnlockInfo[] = L"DAV:unlockinfo"; const WCHAR gc_wszCancelCheckout[] = L"DAV:cancelcheckout"; const WCHAR gc_wszComment[] = L"DAV:comment"; const WCHAR gc_wszTransactionInfo[] = L"DAV:transactioninfo"; const WCHAR gc_wszTransactionStatus[] = L"DAV:transactionstatus"; const WCHAR gc_wszCommit[] = L"DAV:commit"; const WCHAR gc_wszAbort[] = L"DAV:abort"; // class CNFLock ------------------------------------------------------------- // SCODE CNFLock::ScCompleteAttribute (void) { // When we have gotten here, we have started processing // owner node attributes and all cached namespaces have // been added. // if (m_state == ST_OWNER) return m_xo.ScCompleteChildren ( FALSE, XML_ATTRIBUTE, L"", 0 ); return S_OK; } SCODE CNFLock::ScCompleteChildren ( /* [in] */ BOOL fEmptyNode, /* [in] */ DWORD dwType, /* [in] */ const WCHAR __RPC_FAR *pwcText, /* [in] */ ULONG ulLen) { SCODE sc = S_OK; // Handle owner processing first.... // if (ST_OWNER == m_state) { sc = m_xo.ScCompleteChildren (fEmptyNode, dwType, pwcText, ulLen); if (FAILED (sc)) goto ret; } // Handle the rest... // switch (dwType) { case XML_ELEMENT: switch (m_state) { case ST_LOCKINFO: m_state = ST_NODOC; break; case ST_OWNER: if (0 == m_xo.LDepth()) { // Complete the owner comment buffer // m_state = ST_LOCKINFO; m_sbOwner.Append (sizeof(WCHAR), L"\0"); XmlTrace ("Xml: Lock: owner XML body:\n%ws\n", m_sbOwner.PContents()); } break; case ST_TYPE: m_state = ST_LOCKINFO; break; case ST_INTYPE: m_state = ST_TYPE; break; case ST_INTYPE_TRANS: m_state = ST_INTYPE; break; case ST_SCOPE: m_state = ST_LOCKINFO; break; case ST_INSCOPE: m_state = ST_SCOPE; break; case ST_ROLLBACK: m_state = ST_LOCKINFO; break; } } ret: return sc; } SCODE CNFLock::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 wsz; LPCWSTR pwszTag = NULL; SCODE sc = S_FALSE; UINT cch; switch (dwType) { case XML_ELEMENT: // Construct the full name of the node // cch = ulNamespaceLen + ulLen; pwszTag = wsz.resize(CbSizeWsz(cch)); if (NULL == pwszTag) { sc = E_OUTOFMEMORY; break; } 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_wszLockInfo)) { m_state = ST_LOCKINFO; sc = S_OK; } break; case ST_LOCKINFO: // Look for our well know node types // if (FIsTag (pwszTag, gc_wszLockOwner)) { CEmitNmspc cen(m_xo); // Make the state transition and start recording // m_sbOwner.Reset(); m_state = ST_OWNER; 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; } else if (FIsTag (pwszTag, gc_wszLockRollback)) { m_dwRollback = DAV_LOCKTYPE_ROLLBACK; m_state = ST_ROLLBACK; sc = S_OK; } else if (FIsTag (pwszTag, gc_wszLockType)) { m_state = ST_TYPE; sc = S_OK; } else if (FIsTag (pwszTag, gc_wszLockScope)) { m_state = ST_SCOPE; sc = S_OK; } break; case ST_TYPE: if (FIsTag (pwszTag, gc_wszLockTypeWrite)) { XmlTrace ("Xml: Lock: request is for a WRITE lock\n"); m_dwLockType |= GENERIC_WRITE; m_state = ST_INTYPE; sc = S_OK; } else if (FIsTag (pwszTag, gc_wszLockTypeCheckout)) { XmlTrace ("Xml: Lock: request is for a CHECKOUT lock\n"); m_dwLockType |= DAV_LOCKTYPE_CHECKOUT; m_state = ST_INTYPE; sc = S_OK; } else if (FIsTag (pwszTag, gc_wszLockTypeTransaction)) { XmlTrace ("Xml: Lock: request is for a TRANSACTION lock\n"); m_state = ST_INTYPE_TRANS; sc = S_OK; } #ifdef DBG if (!_wcsicmp (pwszTag, L"read")) { XmlTrace ("Xml: Lock: request is for a READ lock\n"); m_dwLockType |= GENERIC_READ; m_state = ST_INTYPE; sc = S_OK; } #endif // DBG break; case ST_SCOPE: if (FIsTag (pwszTag, gc_wszLockScopeExclusive)) { XmlTrace ("Xml: Lock: request is for an EXCLUSE lock\n"); m_dwScope = DAV_EXCLUSIVE_LOCK; m_state = ST_INSCOPE; sc = S_OK; } else if (FIsTag (pwszTag, gc_wszLockScopeShared)) { XmlTrace ("Xml: Lock: request is for a SHARED lock\n"); m_dwScope = DAV_SHARED_LOCK; m_state = ST_INSCOPE; sc = S_OK; } else if (FIsTag (pwszTag, gc_wszLockScopeLocal)) { XmlTrace ("Xml: Lock: request is for a LOCAL scope lock\n"); m_dwScope = DAV_LOCKSCOPE_LOCAL; m_state = ST_INSCOPE; sc = S_OK; } break; case ST_OWNER: sc = m_xo.ScHandleNode (dwType, dwSubType, fTerminal, pwcText, ulLen, ulNamespaceLen, pwcNamespace, ulNsPrefixLen); break; case ST_INTYPE_TRANS: if (FIsTag (pwszTag, gc_wszLockTypeTransactionGOP)) { XmlTrace ("Xml: Lock: request is for a TRANSACTION GOP lock\n"); m_dwLockType |= DAV_LOCKTYPE_TRANSACTION_GOP; m_state = ST_INTYPE_TRANS; sc = S_OK; } } break; default: // If we are processing the owner, continue // to do so... // if (ST_OWNER == m_state) { sc = m_xo.ScHandleNode (dwType, dwSubType, fTerminal, pwcText, ulLen, ulNamespaceLen, pwcNamespace, ulNsPrefixLen); } break; } return sc; } SCODE CNFLock::ScCompleteCreateNode ( /* [in] */ DWORD dwType) { if (ST_OWNER == m_state) m_xo.CompleteCreateNode (dwType); return S_OK; } // class CNFUnlock ------------------------------------------------------------- // SCODE CNFUnlock::ScCompleteAttribute (void) { return S_OK; } SCODE CNFUnlock::ScCompleteChildren ( /* [in] */ BOOL fEmptyNode, /* [in] */ DWORD dwType, /* [in] */ const WCHAR __RPC_FAR *pwcText, /* [in] */ ULONG ulLen) { // Handle the rest... // switch (m_state) { case ST_UNLOCKINFO: m_state = ST_NODOC; break; case ST_COMMENT: case ST_CANCELCHECKOUT: m_state = ST_UNLOCKINFO; break; } return S_OK; } SCODE CNFUnlock::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 wsz; LPCWSTR pwszTag = NULL; SCODE sc = S_FALSE; UINT cch; switch (dwType) { case XML_ELEMENT: // Construct the full name of the node // cch = ulNamespaceLen + ulLen; pwszTag = wsz.resize(CbSizeWsz(cch)); if (NULL == pwszTag) { sc = E_OUTOFMEMORY; break; } 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_wszUnlockInfo)) { m_state = ST_UNLOCKINFO; sc = S_OK; } else if (FIsTag (pwszTag, gc_wszTransactionInfo)) { m_state = ST_TRANSACTIONINFO; sc = S_OK; } break; case ST_UNLOCKINFO: // Look for our well know node types // if (FIsTag (pwszTag, gc_wszComment)) { m_state = ST_COMMENT; sc = S_OK; } else if (FIsTag (pwszTag, gc_wszCancelCheckout)) { m_fCancelCheckout = TRUE; m_state = ST_CANCELCHECKOUT; sc = S_OK; } break; case ST_TRANSACTIONINFO: // Look for our well know node types // if (FIsTag (pwszTag, gc_wszTransactionStatus)) { m_state = ST_TRANSACTIONSTATUS; sc = S_OK; } break; case ST_TRANSACTIONSTATUS: // Look for our well know node types // if (FIsTag (pwszTag, gc_wszCommit)) { m_fCommitTransaction = TRUE; m_state = ST_TRANSACTIONSTATUS_COMMIT; sc = S_OK; } else if (FIsTag (pwszTag, gc_wszAbort)) { m_fAbortTransaction = TRUE; m_state = ST_TRANSACTIONSTATUS_ABORT; sc = S_OK; } break; } break; case XML_PCDATA: // get unlock comment // if (m_state == ST_COMMENT) { // Keep the comment // It's a syntax error to have more than one comment // if (!m_wszComment.get()) { m_wszComment = reinterpret_cast(ExAlloc((ulLen + 1) * sizeof(WCHAR))); Assert (m_wszComment.get()); wcsncpy (m_wszComment.get(), pwcText, ulLen); m_wszComment[ulLen] = L'\0'; sc = S_OK; } // else it's an error else sc = E_DAV_XML_PARSE_ERROR; } break; } return sc; }