// -------------------------------------------------------------------------------- // propfind.cpp // Copyright (c)1998 Microsoft Corporation, All Rights Reserved // Greg Friedman // -------------------------------------------------------------------------------- #include #include "propfind.h" #include "strconst.h" #include "davstrs.h" #include #define FAIL_EXIT_STREAM_WRITE(stream, psz) \ if (FAILED(hr = stream.Write(psz, lstrlen(psz), NULL))) \ goto exit; \ else #define FAIL_EXIT(hr) \ if (FAILED(hr)) \ goto exit; \ else const ULONG c_ulGrowSize = 4; static const char *g_rgszNamespaces[] = { c_szDAVDavNamespace, c_szDAVHotMailNamespace, c_szDAVHTTPMailNamespace, c_szDAVMailNamespace, c_szDAVContactsNamespace }; // predefine the first 10 namespace prefixes. if custom namespaces // exceed the predefined set, additional prefixes are generated on // the fly. static const char *g_rgszNamespacePrefixes[] = { c_szDavNamespacePrefix, c_szHotMailNamespacePrefix, c_szHTTPMailNamespacePrefix, c_szMailNamespacePrefix, c_szContactsNamespacePrefix, "_5", "_6", "_7", "_8", "_9" }; const DWORD c_dwMaxDefinedNamespacePrefix = 10; CStringArray::CStringArray(void) : m_rgpszValues(NULL), m_ulLength(0), m_ulCapacity(0) { } CStringArray::~CStringArray(void) { for (ULONG i = 0; i < m_ulLength; ++i) { if (NULL != m_rgpszValues[i]) MemFree((void *)m_rgpszValues[i]); } SafeMemFree(m_rgpszValues); } HRESULT CStringArray::Add(LPCSTR psz) { if (NULL == psz) return E_INVALIDARG; if (m_ulLength == m_ulCapacity && !Expand()) return E_OUTOFMEMORY; m_rgpszValues[m_ulLength] = PszDupA(psz); if (NULL == m_rgpszValues) return E_OUTOFMEMORY; ++m_ulLength; return S_OK; } HRESULT CStringArray::Adopt(LPCSTR psz) { if (NULL == psz) return E_INVALIDARG; if (m_ulLength == m_ulCapacity && !Expand()) return E_OUTOFMEMORY; m_rgpszValues[m_ulLength] = psz; ++m_ulLength; return S_OK; } LPCSTR CStringArray::GetByIndex(ULONG ulIndex) { if (0 == m_ulLength || (ulIndex > m_ulLength - 1)) return NULL; return m_rgpszValues[ulIndex]; } // -------------------------------------------------------------------------------- // CStringArray::RemoveByIndex // -------------------------------------------------------------------------------- HRESULT CStringArray::RemoveByIndex(ULONG ulIndex) { if (ulIndex > m_ulLength - 1) return E_INVALIDARG; if (NULL != m_rgpszValues[ulIndex]) { MemFree(const_cast(m_rgpszValues[ulIndex])); m_rgpszValues[ulIndex] = NULL; } // shift down CopyMemory(&m_rgpszValues[ulIndex], m_rgpszValues[ulIndex + 1], (m_ulLength - ulIndex) * sizeof(LPSTR)); --m_ulLength; return S_OK; } // -------------------------------------------------------------------------------- // CStringArray::Expand // -------------------------------------------------------------------------------- BOOL CStringArray::Expand(void) { LPCSTR *rgpszNewValues = NULL; if (!MemAlloc((void **)&rgpszNewValues, sizeof(LPSTR) * (m_ulCapacity + c_ulGrowSize))) return FALSE; // clear the new slots ZeroMemory(rgpszNewValues,sizeof(LPSTR) * (m_ulCapacity + c_ulGrowSize)); // copy the old values over and swap in the new buffer CopyMemory(rgpszNewValues, m_rgpszValues, sizeof(LPSTR) * m_ulCapacity); SafeMemFree(m_rgpszValues); m_rgpszValues = rgpszNewValues; m_ulCapacity += c_ulGrowSize; return TRUE; } // -------------------------------------------------------------------------------- // CStringHash::~CStringHash // -------------------------------------------------------------------------------- CStringHash::~CStringHash(void) { PHASHENTRY phe; // data stored in the hash table // are strings that can need to // be deallocated. for (DWORD dw = 0; dw < m_cBins; dw++) { SafeMemFree(m_rgBins[dw].pv); phe = m_rgBins[dw].pheNext; while (phe) { SafeMemFree(phe->pv); phe = phe->pheNext; } } } // -------------------------------------------------------------------------------- // CDAVNamespaceArbiterImp::CDAVNamespaceArbiterImp // -------------------------------------------------------------------------------- CDAVNamespaceArbiterImp::CDAVNamespaceArbiterImp(void) { for (ULONG i = 0; i <= c_dwMaxNamespaceID; ++i) m_rgbNsUsed[i] = FALSE; // the DAV namespace is always included m_rgbNsUsed[DAVNAMESPACE_DAV] = TRUE; } // -------------------------------------------------------------------------------- // CDAVNamespaceArbiterImp::~CDAVNamespaceArbiterImp // -------------------------------------------------------------------------------- CDAVNamespaceArbiterImp::~CDAVNamespaceArbiterImp(void) { // nothing to do } // -------------------------------------------------------------------------------- // CDAVNamespaceArbiterImp::AddNamespace // -------------------------------------------------------------------------------- HRESULT CDAVNamespaceArbiterImp::AddNamespace(LPCSTR pszNamespace, DWORD *pdwNamespaceID) { HRESULT hr = S_OK; if (NULL == pszNamespace || NULL == pdwNamespaceID) { hr = E_INVALIDARG; goto exit; } if (FAILED(hr = m_saNamespaces.Add(pszNamespace))) goto exit; *pdwNamespaceID = m_saNamespaces.Length() + c_dwMaxNamespaceID; exit: return hr; } // -------------------------------------------------------------------------------- // CDAVNamespaceArbiterImp::GetNamespaceID // -------------------------------------------------------------------------------- HRESULT CDAVNamespaceArbiterImp::GetNamespaceID(LPCSTR pszNamespace, DWORD *pdwNamespaceID) { DWORD dwIndex; DWORD dwEntries; if (NULL == pszNamespace || NULL == pdwNamespaceID) return E_INVALIDARG; // look for a predefined namespace for (dwIndex = 0; dwIndex < c_dwMaxNamespaceID; ++dwIndex) { if (!lstrcmp(pszNamespace, g_rgszNamespaces[dwIndex])) { *pdwNamespaceID = dwIndex; return S_OK; } } // look for a user-defined prefix dwEntries = m_saNamespaces.Length(); for (dwIndex = 0; dwIndex < dwEntries; ++dwIndex) { if (!lstrcmp(pszNamespace, m_saNamespaces.GetByIndex(dwIndex))) { *pdwNamespaceID = (dwIndex + (c_dwMaxNamespaceID + 1)); return S_OK; } } // if it wasn't found, the namespace doesn't exist return E_INVALIDARG; } // -------------------------------------------------------------------------------- // CDAVNamespaceArbiterImp::GetNamespacePrefix // -------------------------------------------------------------------------------- HRESULT CDAVNamespaceArbiterImp::GetNamespacePrefix(DWORD dwNamespaceID, LPSTR *ppszNamespacePrefix) { HRESULT hr = S_OK; LPSTR pszTemp = NULL; if (NULL == ppszNamespacePrefix) return E_INVALIDARG; if (dwNamespaceID <= c_dwMaxDefinedNamespacePrefix) *ppszNamespacePrefix = PszDupA(g_rgszNamespacePrefixes[dwNamespaceID]); else { char szBuffer[12]; wnsprintf(szBuffer, ARRAYSIZE(szBuffer), "_%d", dwNamespaceID); *ppszNamespacePrefix = PszDupA(szBuffer); } if (NULL == *ppszNamespacePrefix) hr = E_OUTOFMEMORY; return hr; } // -------------------------------------------------------------------------------- // CDAVNamespaceArbiterImp::AllocExpandedName // -------------------------------------------------------------------------------- LPSTR CDAVNamespaceArbiterImp::AllocExpandedName(DWORD dwNamespaceID, LPCSTR pszPropertyName) { LPSTR pszPrefixedName = NULL; const DWORD c_dwMaxIntLength = 10; if (dwNamespaceID < c_dwMaxDefinedNamespacePrefix) { // allocate a buffer to hold the prefixed name. DWORD cchSize = (lstrlen(pszPropertyName) + lstrlen(g_rgszNamespacePrefixes[dwNamespaceID]) + 2); if (!MemAlloc((void **)&pszPrefixedName, cchSize * sizeof(pszPrefixedName[0]))) return NULL; // generate the prefixed name wnsprintf(pszPrefixedName, cchSize, "%s:%s", g_rgszNamespacePrefixes[dwNamespaceID], pszPropertyName); } else { // allocate a buffer to hold the prefixed name. the "2" is for the prefix char '_" , the delimiting // colon and the eos. DWORD cchSize = (lstrlen(pszPropertyName) + c_dwMaxIntLength + 3); if (!MemAlloc((void **)&pszPrefixedName, cchSize * sizeof(pszPrefixedName[0]))) return NULL; // generate the prefixed name. use an underscore as the first char, because // DAV explicitly disallows digits for the first char. wnsprintf(pszPrefixedName, cchSize, "_%d:%s", dwNamespaceID, pszPropertyName); } return pszPrefixedName; } // -------------------------------------------------------------------------------- // CDAVNamespaceArbiterImp::WriteNamespaces // -------------------------------------------------------------------------------- HRESULT CDAVNamespaceArbiterImp::WriteNamespaces(IStream *pStream) { HRESULT hr = S_OK; ULONG i; ULONG cEntries; BOOL fNeedSpacePrefix = FALSE; // write out the intrinsic namespaces for (i = 0; i <= c_dwMaxNamespaceID; ++i) { if (m_rgbNsUsed[i]) { if (FAILED(hr = _AppendXMLNamespace(pStream, g_rgszNamespaces[i], i, fNeedSpacePrefix))) goto exit; fNeedSpacePrefix = TRUE; } } // write out the installed namespaces cEntries = m_saNamespaces.Length(); for (i = 0; i < cEntries; ++i) { if (FAILED(hr = _AppendXMLNamespace(pStream, m_saNamespaces.GetByIndex(i), i + i + c_dwMaxNamespaceID + 1, fNeedSpacePrefix))) goto exit; fNeedSpacePrefix = TRUE; } exit: return hr; } // -------------------------------------------------------------------------------- // CDAVNamespaceArbiterImp::_AppendXMLNamespace // -------------------------------------------------------------------------------- HRESULT CDAVNamespaceArbiterImp::_AppendXMLNamespace(IStream *pStream, LPCSTR pszNamespace, DWORD dwNamespaceID, BOOL fWhitespacePrefix) { HRESULT hr = S_OK; TCHAR szPrefix[12]; if (fWhitespacePrefix) { IxpAssert(1 == lstrlen(c_szEqual)); if (FAILED(hr = pStream->Write(g_szSpace, 1, NULL))) goto exit; } if (FAILED(hr = pStream->Write(c_szXMLNsColon, lstrlen(c_szXMLNsColon), NULL))) goto exit; if (dwNamespaceID < c_dwMaxDefinedNamespacePrefix) { if (FAILED(hr = pStream->Write(g_rgszNamespacePrefixes[dwNamespaceID], lstrlen(g_rgszNamespacePrefixes[dwNamespaceID]), NULL))) goto exit; } else { wnsprintf(szPrefix, ARRAYSIZE(szPrefix), "_%d", dwNamespaceID); if (FAILED(hr = pStream->Write(szPrefix, lstrlen(szPrefix), NULL))) goto exit; } IxpAssert(1 == lstrlen(c_szEqual)); IxpAssert(1 == lstrlen(c_szDoubleQuote)); if (FAILED(hr = pStream->Write(c_szEqual, 1, NULL))) goto exit; if (FAILED(hr = pStream->Write(c_szDoubleQuote, 1, NULL))) goto exit; if (FAILED(hr = pStream->Write(pszNamespace, lstrlen(pszNamespace), NULL))) goto exit; hr = pStream->Write(c_szDoubleQuote, 1, NULL); exit: return hr; } // -------------------------------------------------------------------------------- // CPropPatchRequest::CPropPatchRequest // -------------------------------------------------------------------------------- CPropPatchRequest::CPropPatchRequest(void) : m_fSpecify1252(FALSE), m_cRef(1) { // nothing to do } // -------------------------------------------------------------------------------- // IUnknown Methods // -------------------------------------------------------------------------------- // -------------------------------------------------------------------------------- // CPropPatchRequest::QueryInterface // -------------------------------------------------------------------------------- STDMETHODIMP CPropPatchRequest::QueryInterface(REFIID riid, LPVOID *ppv) { // Locals HRESULT hr = S_OK; // Validate params if (NULL == ppv) { hr = TrapError(E_INVALIDARG); goto exit; } // Initialize params *ppv = NULL; // IID_IUnknown if (IID_IUnknown == riid) *ppv = ((IUnknown *)(IPropFindRequest *)this); else if (IID_IPropPatchRequest == riid) *ppv = ((IPropPatchRequest *)this); if (NULL != *ppv) { ((LPUNKNOWN)*ppv)->AddRef(); goto exit; } hr = TrapError(E_NOINTERFACE); exit: // Done return hr; } // -------------------------------------------------------------------------------- // CPropPatchRequest::AddRef // -------------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CPropPatchRequest::AddRef(void) { return ++m_cRef; } // -------------------------------------------------------------------------------- // CPropPatchRequest::Release // -------------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CPropPatchRequest::Release(void) { if (0 != --m_cRef) return m_cRef; delete this; return 0; } // ---------------------------------------------------------------------------- // IDAVNamespaceArbiter methods // ---------------------------------------------------------------------------- // -------------------------------------------------------------------------------- // CPropPatchRequest::CPropPatchRequest::AddNamespace // -------------------------------------------------------------------------------- STDMETHODIMP CPropPatchRequest::AddNamespace(LPCSTR pszNamespace, DWORD *pdwNamespaceID) { return m_dna.AddNamespace(pszNamespace, pdwNamespaceID); } // -------------------------------------------------------------------------------- // CPropPatchRequest::GetNamespaceID // -------------------------------------------------------------------------------- STDMETHODIMP CPropPatchRequest::GetNamespaceID(LPCSTR pszNamespace, DWORD *pdwNamespaceID) { return m_dna.GetNamespaceID(pszNamespace, pdwNamespaceID); } // -------------------------------------------------------------------------------- // CPropPatchRequest::GetNamespacePrefix // -------------------------------------------------------------------------------- STDMETHODIMP CPropPatchRequest::GetNamespacePrefix(DWORD dwNamespaceID, LPSTR *ppszNamespacePrefix) { return m_dna.GetNamespacePrefix(dwNamespaceID, ppszNamespacePrefix); } // -------------------------------------------------------------------------------- // IPropPatchRequest Methods // -------------------------------------------------------------------------------- // -------------------------------------------------------------------------------- // CPropPatchRequest::SetProperty // -------------------------------------------------------------------------------- STDMETHODIMP CPropPatchRequest::SetProperty( DWORD dwNamespaceID, LPCSTR pszPropertyName, LPCSTR pszNewValue) { LPSTR pszPrefixedName = NULL; HRESULT hr = S_OK; // Validate params if (NULL == pszPropertyName || NULL == pszNewValue || dwNamespaceID > c_dwMaxNamespaceID + m_dna.m_saNamespaces.Length()) { hr = E_INVALIDARG; goto exit; } pszPrefixedName = m_dna.AllocExpandedName(dwNamespaceID, pszPropertyName); if (NULL == pszPrefixedName) { hr = E_OUTOFMEMORY; goto exit; } // if the namespace is one of the known namespaces, mark it in // the array so that we can include the namespace directive in // the generated xml if (dwNamespaceID <= c_dwMaxNamespaceID) m_dna.m_rgbNsUsed[dwNamespaceID] = TRUE; if (FAILED(hr = m_saPropValues.Add(pszNewValue))) goto exit; if (FAILED(hr = m_saPropNames.Adopt(pszPrefixedName))) { MemFree(pszPrefixedName); m_saPropValues.RemoveByIndex(m_saPropValues.Length() - 1); } exit: return hr; } // -------------------------------------------------------------------------------- // CPropPatchRequest::RemoveProperty // -------------------------------------------------------------------------------- STDMETHODIMP CPropPatchRequest::RemoveProperty( DWORD dwNamespaceID, LPCSTR pszPropertyName) { LPSTR pszPrefixedName = NULL; HRESULT hr = S_OK; if (NULL == pszPropertyName || dwNamespaceID > c_dwMaxNamespaceID + m_dna.m_saNamespaces.Length()) { hr = E_INVALIDARG; goto exit; } pszPrefixedName = m_dna.AllocExpandedName(dwNamespaceID, pszPropertyName); if (NULL == pszPrefixedName) { hr = E_OUTOFMEMORY; goto exit; } // if the namespace is one of the known namespaces, mark it in // the array so that we can include the namespace directive in the // generated xml if (dwNamespaceID <= c_dwMaxNamespaceID) m_dna.m_rgbNsUsed[dwNamespaceID] = TRUE; hr = m_saRemovePropNames.Adopt(pszPrefixedName); exit: return hr; } // -------------------------------------------------------------------------------- // CPropPatchRequest::GenerateXML // -------------------------------------------------------------------------------- STDMETHODIMP CPropPatchRequest::GenerateXML(LPSTR *ppszXML) { return GenerateXML(NULL, ppszXML); } // -------------------------------------------------------------------------------- // CPropPatchRequest::GenerateXML // -------------------------------------------------------------------------------- STDMETHODIMP CPropPatchRequest::GenerateXML(LPHTTPTARGETLIST pTargets, LPSTR *ppszXML) { const DWORD c_dwLocalBufferSize = 256; HRESULT hr = S_OK; CByteStream stream; ULONG cEntries; LPCSTR pszName = NULL; LPCSTR pszValue = NULL; ULONG i; DWORD dwIndex; DWORD cbStr1, cbStr2; if (NULL == ppszXML) return E_INVALIDARG; *ppszXML= NULL; // write the DAV header if (m_fSpecify1252) FAIL_EXIT_STREAM_WRITE(stream, c_szXML1252Head); else FAIL_EXIT_STREAM_WRITE(stream, c_szXMLHead); // write out the proppatch header FAIL_EXIT_STREAM_WRITE(stream, c_szPropPatchHead); // write out namespace directives using the new form FAIL_EXIT(hr = m_dna.WriteNamespaces(&stream)); FAIL_EXIT_STREAM_WRITE(stream, c_szXMLCloseElement); // write out the targets if (NULL != pTargets && pTargets->cTarget > 0) { cbStr1 = lstrlen(c_szHrefHead); cbStr2 = lstrlen(c_szHrefTail); FAIL_EXIT_STREAM_WRITE(stream, c_szTargetHead); // write out the targets for (dwIndex = 0; dwIndex < pTargets->cTarget; dwIndex++) { FAIL_EXIT(hr = stream.Write(c_szHrefHead, cbStr1, NULL)); FAIL_EXIT_STREAM_WRITE(stream, pTargets->prgTarget[dwIndex]); FAIL_EXIT(hr = stream.Write(c_szHrefTail, cbStr2, NULL)); } FAIL_EXIT_STREAM_WRITE(stream, c_szTargetTail); } // write out the "set" properties cEntries = m_saPropNames.Length(); if (cEntries > 0) { // write the set header FAIL_EXIT_STREAM_WRITE(stream, c_szPropPatchSetHead); for (i = 0; i < cEntries; ++i) { FAIL_EXIT_STREAM_WRITE(stream, c_szCRLFTabTabTabOpenElement); pszName = m_saPropNames.GetByIndex(i); if (NULL == pszName) { hr = E_OUTOFMEMORY; goto exit; } FAIL_EXIT_STREAM_WRITE(stream, pszName); FAIL_EXIT_STREAM_WRITE(stream, c_szXMLCloseElement); pszValue = m_saPropValues.GetByIndex(i); if (NULL == pszValue) { hr = E_OUTOFMEMORY; goto exit; } FAIL_EXIT_STREAM_WRITE(stream, pszValue); FAIL_EXIT_STREAM_WRITE(stream, c_szXMLOpenTermElement); FAIL_EXIT_STREAM_WRITE(stream, pszName); FAIL_EXIT_STREAM_WRITE(stream, c_szXMLCloseElement); } FAIL_EXIT_STREAM_WRITE(stream, c_szPropPatchSetTail); } // write out the remove properties cEntries = m_saRemovePropNames.Length(); if (cEntries > 0) { // write the remove header FAIL_EXIT_STREAM_WRITE(stream, c_szPropPatchRemoveHead); for (i = 0; i < cEntries; ++i) { FAIL_EXIT_STREAM_WRITE(stream, c_szCRLFTabTabTabOpenElement); pszName = m_saRemovePropNames.GetByIndex(i); if (NULL == pszName) { hr = E_OUTOFMEMORY; goto exit; } FAIL_EXIT_STREAM_WRITE(stream, pszName); FAIL_EXIT_STREAM_WRITE(stream, c_szXMLCloseTermElement); } FAIL_EXIT_STREAM_WRITE(stream, c_szPropPatchRemoveTail); } FAIL_EXIT_STREAM_WRITE(stream, c_szPropPatchTailCRLF); hr = stream.HrAcquireStringA(NULL, ppszXML, ACQ_DISPLACE); exit: return hr; } // -------------------------------------------------------------------------------- // CPropFindRequest::CPropFindRequest // -------------------------------------------------------------------------------- CPropFindRequest::CPropFindRequest(void) : m_cRef(1) { } // -------------------------------------------------------------------------------- // IUnknown Methods // -------------------------------------------------------------------------------- // -------------------------------------------------------------------------------- // CPropFindRequest::QueryInterface // -------------------------------------------------------------------------------- STDMETHODIMP CPropFindRequest::QueryInterface(REFIID riid, LPVOID *ppv) { // Locals HRESULT hr = S_OK; // Validate params if (NULL == ppv) { hr = TrapError(E_INVALIDARG); goto exit; } // Initialize params *ppv = NULL; // IID_IUnknown if (IID_IUnknown == riid) *ppv = ((IUnknown *)(IPropFindRequest *)this); else if (IID_IPropFindRequest == riid) *ppv = ((IPropFindRequest *)this); if (NULL != *ppv) { ((LPUNKNOWN)*ppv)->AddRef(); goto exit; } hr = TrapError(E_NOINTERFACE); exit: // Done return hr; } // -------------------------------------------------------------------------------- // CPropFindRequest::AddRef // -------------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CPropFindRequest::AddRef(void) { return ++m_cRef; } // -------------------------------------------------------------------------------- // CPropFindRequest::Release // -------------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CPropFindRequest::Release(void) { if (0 != --m_cRef) return m_cRef; delete this; return 0; } // ---------------------------------------------------------------------------- // IDAVNamespaceArbiter methods // ---------------------------------------------------------------------------- // -------------------------------------------------------------------------------- // CPropFindRequest::CPropPatchRequest::AddNamespace // -------------------------------------------------------------------------------- STDMETHODIMP CPropFindRequest::AddNamespace(LPCSTR pszNamespace, DWORD *pdwNamespaceID) { return m_dna.AddNamespace(pszNamespace, pdwNamespaceID); } // -------------------------------------------------------------------------------- // CPropFindRequest::GetNamespaceID // -------------------------------------------------------------------------------- STDMETHODIMP CPropFindRequest::GetNamespaceID(LPCSTR pszNamespace, DWORD *pdwNamespaceID) { return m_dna.GetNamespaceID(pszNamespace, pdwNamespaceID); } // -------------------------------------------------------------------------------- // CPropFindRequest::GetNamespacePrefix // -------------------------------------------------------------------------------- STDMETHODIMP CPropFindRequest::GetNamespacePrefix(DWORD dwNamespaceID, LPSTR *ppszNamespacePrefix) { return m_dna.GetNamespacePrefix(dwNamespaceID, ppszNamespacePrefix); } // -------------------------------------------------------------------------------- // IPropFindRequest Methods // -------------------------------------------------------------------------------- // -------------------------------------------------------------------------------- // CPropFindRequest::AddProperty // -------------------------------------------------------------------------------- STDMETHODIMP CPropFindRequest::AddProperty(DWORD dwNamespaceID, LPCSTR pszPropertyName) { const DWORD c_dwMaxIntLength = 10; LPSTR pszPrefixedName = NULL; // Validate Params if (NULL == pszPropertyName || dwNamespaceID > c_dwMaxNamespaceID + m_dna.m_saNamespaces.Length()) return E_INVALIDARG; pszPrefixedName = m_dna.AllocExpandedName(dwNamespaceID, pszPropertyName); if (NULL == pszPrefixedName) return E_OUTOFMEMORY; // if the namespace is one of the known namespaces, mark // the array so that we can include the namespace directive // in the generated xml. if (dwNamespaceID <= c_dwMaxNamespaceID) m_dna.m_rgbNsUsed[dwNamespaceID] = TRUE; m_saProperties.Adopt(pszPrefixedName); return S_OK; } // -------------------------------------------------------------------------------- // CPropFindRequest::GenerateXML // -------------------------------------------------------------------------------- STDMETHODIMP CPropFindRequest::GenerateXML(LPSTR *ppszXML) { const DWORD c_dwLocalBufferSize = 256; HRESULT hr = S_OK; CByteStream stream; ULONG cbLength = 0; ULONG cEntries; ULONG i; LPCSTR pszProperty; if (NULL == ppszXML) return E_INVALIDARG; *ppszXML = NULL; // write the DAV header if (FAILED(hr = stream.Write(c_szXMLHead, lstrlen(c_szXMLHead), NULL))) goto exit; // write out the propfind header if (FAILED(hr = stream.Write(c_szPropFindHead1, lstrlen(c_szPropFindHead1), NULL))) goto exit; // write out namespaces using the new form if (FAILED(hr = m_dna.WriteNamespaces(&stream))) goto exit; if (FAILED(hr = stream.Write(c_szPropFindHead2, lstrlen(c_szPropFindHead2), NULL))) goto exit; // write out the properties cEntries = m_saProperties.Length(); for (i = 0; i < cEntries; ++i) { if (FAILED(hr = stream.Write(c_szCRLFTabTabOpenElement, lstrlen(c_szCRLFTabTabOpenElement), NULL))) goto exit; // properties are prefixed when they are added to the collection pszProperty = m_saProperties.GetByIndex(i); if (!pszProperty) { hr = E_OUTOFMEMORY; goto exit; } if (FAILED(hr = stream.Write(pszProperty, lstrlen(pszProperty), NULL))) goto exit; if (FAILED(hr = stream.Write(c_szXMLCloseTermElement, lstrlen(c_szXMLCloseTermElement), NULL))) goto exit; } if (FAILED(hr = stream.Write(c_szPropFindTail, lstrlen(c_szPropFindTail), NULL))) goto exit; hr = stream.HrAcquireStringA(NULL, ppszXML, ACQ_DISPLACE); exit: return hr; } // -------------------------------------------------------------------------------- // class CPropFindMultiResponse // -------------------------------------------------------------------------------- // -------------------------------------------------------------------------------- // CPropFindMultiResponse::CPropFindMultiResponse // -------------------------------------------------------------------------------- CPropFindMultiResponse::CPropFindMultiResponse(void) : m_cRef(1), m_bDone(FALSE), m_ulResponseCapacity(0), m_ulResponseLength(0), m_rgResponses(NULL) { } // -------------------------------------------------------------------------------- // CPropFindMultiResponse::~CPropFindMultiResponse // -------------------------------------------------------------------------------- CPropFindMultiResponse::~CPropFindMultiResponse(void) { for (ULONG i = 0; i < m_ulResponseLength; i++) SafeRelease(m_rgResponses[i]); SafeMemFree(m_rgResponses); } // -------------------------------------------------------------------------------- // CPropFindMultiResponse::QueryInterface // -------------------------------------------------------------------------------- STDMETHODIMP CPropFindMultiResponse::QueryInterface(REFIID riid, LPVOID *ppv) { // Locals HRESULT hr = S_OK; // Validate params if (NULL == ppv) { hr = TrapError(E_INVALIDARG); goto exit; } // Initialize params *ppv = NULL; // IID_IUnknown if (IID_IUnknown == riid) *ppv = ((IUnknown *)(IPropFindRequest *)this); else if (IID_IPropFindMultiResponse == riid) *ppv = ((IPropFindMultiResponse *)this); if (NULL != *ppv) { ((LPUNKNOWN)*ppv)->AddRef(); goto exit; } hr = TrapError(E_NOINTERFACE); exit: // Done return hr; } // -------------------------------------------------------------------------------- // CPropFindMultiResponse::AddRef // -------------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CPropFindMultiResponse::AddRef(void) { return ++m_cRef; } // -------------------------------------------------------------------------------- // CPropFindMultiResponse::Release // -------------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CPropFindMultiResponse::Release(void) { if (0 != --m_cRef) return m_cRef; delete this; return 0; } // -------------------------------------------------------------------------------- // CPropFindMultiResponse::IsComplete // -------------------------------------------------------------------------------- STDMETHODIMP_(BOOL) CPropFindMultiResponse::IsComplete(void) { return m_bDone; } // -------------------------------------------------------------------------------- // CPropFindMultiResponse::GetLength // -------------------------------------------------------------------------------- STDMETHODIMP CPropFindMultiResponse::GetLength(ULONG *pulLength) { if (NULL == pulLength) return E_INVALIDARG; *pulLength = m_ulResponseLength; return S_OK; } // -------------------------------------------------------------------------------- // CPropFindMultiResponse::GetResponse // -------------------------------------------------------------------------------- STDMETHODIMP CPropFindMultiResponse::GetResponse(ULONG ulIndex, IPropFindResponse **ppResponse) { if (ulIndex >= m_ulResponseLength || !ppResponse) return E_INVALIDARG; *ppResponse = m_rgResponses[ulIndex]; (*ppResponse)->AddRef(); return S_OK; } // -------------------------------------------------------------------------------- // CPropFindMultiResponse::HrAddResponse // -------------------------------------------------------------------------------- HRESULT CPropFindMultiResponse::HrAddResponse(IPropFindResponse *pResponse) { const ULONG c_dwInitialCapacity = 4; HRESULT hr = S_OK; IPropFindResponse **ppNewResponses = NULL; DWORD dwNewCapacity; if (!pResponse) return E_INVALIDARG; if (m_ulResponseLength == m_ulResponseCapacity) { dwNewCapacity = !m_ulResponseCapacity ? c_dwInitialCapacity : (m_ulResponseCapacity * 2); if (!MemAlloc((void **)&ppNewResponses, dwNewCapacity * sizeof(IPropFindResponse *))) { hr = E_OUTOFMEMORY; goto exit; } ZeroMemory(ppNewResponses, dwNewCapacity * sizeof(IPropFindResponse *)); // copy the old values over if (m_ulResponseCapacity) CopyMemory(ppNewResponses, m_rgResponses, min(dwNewCapacity, m_ulResponseCapacity) * sizeof(IPropFindResponse *)); // free the old buffer SafeMemFree(m_rgResponses); m_rgResponses = ppNewResponses; m_ulResponseCapacity = dwNewCapacity; } m_rgResponses[m_ulResponseLength++] = pResponse; pResponse->AddRef(); exit: return hr; } // -------------------------------------------------------------------------------- // Class CPropFindResponse // -------------------------------------------------------------------------------- // -------------------------------------------------------------------------------- // CPropFindResponse::CPropFindResponse // -------------------------------------------------------------------------------- CPropFindResponse::CPropFindResponse(void) : m_cRef(1), m_bDone(FALSE), m_pszHref(NULL), m_pRequest(NULL), m_shProperties(), m_dwCachedNamespaceID(0), m_pszCachedNamespacePrefix(NULL) { } // -------------------------------------------------------------------------------- // CPropFindResponse::~CPropFindResponse // -------------------------------------------------------------------------------- CPropFindResponse::~CPropFindResponse(void) { if (NULL != m_pszHref) MemFree(const_cast(m_pszHref)); SafeRelease(m_pRequest); SafeMemFree(m_pszCachedNamespacePrefix); } // -------------------------------------------------------------------------------- // CPropFindResponse::QueryInterface // -------------------------------------------------------------------------------- STDMETHODIMP CPropFindResponse::QueryInterface(REFIID riid, LPVOID *ppv) { // Locals HRESULT hr = S_OK; // Validate params if (NULL == ppv) { hr = TrapError(E_INVALIDARG); goto exit; } // Initialize params *ppv = NULL; // IID_IUnknown if (IID_IUnknown == riid) *ppv = ((IUnknown *)(IPropFindResponse *)this); else if (IID_IPropFindResponse == riid) *ppv = ((IPropFindResponse *)this); if (NULL != *ppv) { ((LPUNKNOWN)*ppv)->AddRef(); goto exit; } hr = TrapError(E_NOINTERFACE); exit: // Done return hr; } // -------------------------------------------------------------------------------- // CPropFindResponse::AddRef // -------------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CPropFindResponse::AddRef(void) { return ++m_cRef; } // -------------------------------------------------------------------------------- // CPropFindResponse::Release // -------------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CPropFindResponse::Release(void) { if (0 != --m_cRef) return m_cRef; delete this; return 0; } // -------------------------------------------------------------------------------- // CPropFindResponse::IsComplete // -------------------------------------------------------------------------------- STDMETHODIMP_(BOOL) CPropFindResponse::IsComplete(void) { return m_bDone; } // -------------------------------------------------------------------------------- // CPropFindResponse::GetHref // -------------------------------------------------------------------------------- STDMETHODIMP CPropFindResponse::GetHref(LPSTR *pszHref) { if (NULL == pszHref) return E_INVALIDARG; *pszHref = NULL; if (NULL == m_pszHref) return E_FAIL; *pszHref = PszDupA(m_pszHref); if (!*pszHref) return E_OUTOFMEMORY; return S_OK; } // -------------------------------------------------------------------------------- // CPropFindResponse::GetProperty // -------------------------------------------------------------------------------- STDMETHODIMP CPropFindResponse::GetProperty( DWORD dwNamespaceID, LPSTR pszPropertyName, LPSTR *ppszPropertyValue) { char szLocalPropBuffer[256]; LPSTR pszPropBuffer = NULL; BOOL bFreePropBuffer = FALSE; LPSTR pszPrefix = NULL; HRESULT hr = S_OK; ULONG ulPrefixLength; ULONG ulPropertyLength; LPSTR pszFoundValue = NULL; if (!pszPropertyName) return E_INVALIDARG; *ppszPropertyValue = NULL; // first convert the namespace id into a prefix. // to facilitate fast lookups, we cache the most recently // seen custom namespace if (dwNamespaceID < c_dwMaxDefinedNamespacePrefix) pszPrefix = const_cast(g_rgszNamespacePrefixes[dwNamespaceID]); else if (dwNamespaceID == m_dwCachedNamespaceID) pszPrefix = m_pszCachedNamespacePrefix; else if (m_pRequest) { if (FAILED(hr = m_pRequest->GetNamespacePrefix(dwNamespaceID, &pszPrefix))) goto exit; // free the one-deep cache and store the new // prefix and ID. SafeMemFree(m_pszCachedNamespacePrefix); m_dwCachedNamespaceID = dwNamespaceID; m_pszCachedNamespacePrefix = pszPrefix; } ulPrefixLength = lstrlen(pszPrefix); ulPropertyLength = lstrlen(pszPropertyName); DWORD cchSize = ARRAYSIZE(szLocalPropBuffer); if ((ulPrefixLength + ulPropertyLength + (2 * sizeof(TCHAR))) < 256) { // the combined length is small enough to use // the stack-based buffer pszPropBuffer = szLocalPropBuffer; } else { cchSize = (ulPrefixLength + ulPropertyLength + 2); if (!MemAlloc((void **)&pszPropBuffer, cchSize * sizeof(pszPropBuffer[0]))) { hr = E_OUTOFMEMORY; goto exit; } bFreePropBuffer = TRUE; } wnsprintf(pszPropBuffer, cchSize, "%s:%s", pszPrefix, pszPropertyName); // XML parser uppercases everything CharUpper(pszPropBuffer); // now that the property name has been created, look for the // value in the property hash table if (FAILED(hr = m_shProperties.Find(pszPropBuffer, FALSE, (void **)&pszFoundValue))) goto exit; *ppszPropertyValue = PszDupA(pszFoundValue); if (NULL == *ppszPropertyValue) hr = E_OUTOFMEMORY; exit: if (bFreePropBuffer) SafeMemFree(pszPropBuffer); return hr; } // -------------------------------------------------------------------------------- // CPropFindResponse::HrInitPropFindResponse // -------------------------------------------------------------------------------- HRESULT CPropFindResponse::HrInitPropFindResponse(IPropFindRequest *pRequest) { if (NULL == pRequest) return E_INVALIDARG; IxpAssert(!m_pRequest); HRESULT hr = S_OK; m_pRequest = pRequest; m_pRequest->AddRef(); hr = m_shProperties.Init(17, TRUE); return hr; } // -------------------------------------------------------------------------------- // CPropFindResponse::HrAdoptHref // -------------------------------------------------------------------------------- HRESULT CPropFindResponse::HrAdoptHref(LPCSTR pszHref) { if (NULL == pszHref) return E_INVALIDARG; IxpAssert(!m_pszHref); m_pszHref = pszHref; return S_OK; } // -------------------------------------------------------------------------------- // CPropFindResponse::HrAdoptProperty // -------------------------------------------------------------------------------- HRESULT CPropFindResponse::HrAdoptProperty(LPCSTR pszKey, LPCSTR pszValue) { if (!pszKey || !pszValue) return E_INVALIDARG; return m_shProperties.Insert(const_cast(pszKey), const_cast(pszValue), NOFLAGS); }