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.

1319 lines
41 KiB

  1. // --------------------------------------------------------------------------------
  2. // propfind.cpp
  3. // Copyright (c)1998 Microsoft Corporation, All Rights Reserved
  4. // Greg Friedman
  5. // --------------------------------------------------------------------------------
  6. #include <pch.hxx>
  7. #include "propfind.h"
  8. #include "strconst.h"
  9. #include "davstrs.h"
  10. #include <shlwapi.h>
  11. #define FAIL_EXIT_STREAM_WRITE(stream, psz) \
  12. if (FAILED(hr = stream.Write(psz, lstrlen(psz), NULL))) \
  13. goto exit; \
  14. else
  15. #define FAIL_EXIT(hr) \
  16. if (FAILED(hr)) \
  17. goto exit; \
  18. else
  19. const ULONG c_ulGrowSize = 4;
  20. static const char *g_rgszNamespaces[] =
  21. {
  22. c_szDAVDavNamespace,
  23. c_szDAVHotMailNamespace,
  24. c_szDAVHTTPMailNamespace,
  25. c_szDAVMailNamespace,
  26. c_szDAVContactsNamespace
  27. };
  28. // predefine the first 10 namespace prefixes. if custom namespaces
  29. // exceed the predefined set, additional prefixes are generated on
  30. // the fly.
  31. static const char *g_rgszNamespacePrefixes[] =
  32. {
  33. c_szDavNamespacePrefix,
  34. c_szHotMailNamespacePrefix,
  35. c_szHTTPMailNamespacePrefix,
  36. c_szMailNamespacePrefix,
  37. c_szContactsNamespacePrefix,
  38. "_5",
  39. "_6",
  40. "_7",
  41. "_8",
  42. "_9"
  43. };
  44. const DWORD c_dwMaxDefinedNamespacePrefix = 10;
  45. CStringArray::CStringArray(void) :
  46. m_rgpszValues(NULL),
  47. m_ulLength(0),
  48. m_ulCapacity(0)
  49. {
  50. }
  51. CStringArray::~CStringArray(void)
  52. {
  53. for (ULONG i = 0; i < m_ulLength; ++i)
  54. {
  55. if (NULL != m_rgpszValues[i])
  56. MemFree((void *)m_rgpszValues[i]);
  57. }
  58. SafeMemFree(m_rgpszValues);
  59. }
  60. HRESULT CStringArray::Add(LPCSTR psz)
  61. {
  62. if (NULL == psz)
  63. return E_INVALIDARG;
  64. if (m_ulLength == m_ulCapacity && !Expand())
  65. return E_OUTOFMEMORY;
  66. m_rgpszValues[m_ulLength] = PszDupA(psz);
  67. if (NULL == m_rgpszValues)
  68. return E_OUTOFMEMORY;
  69. ++m_ulLength;
  70. return S_OK;
  71. }
  72. HRESULT CStringArray::Adopt(LPCSTR psz)
  73. {
  74. if (NULL == psz)
  75. return E_INVALIDARG;
  76. if (m_ulLength == m_ulCapacity && !Expand())
  77. return E_OUTOFMEMORY;
  78. m_rgpszValues[m_ulLength] = psz;
  79. ++m_ulLength;
  80. return S_OK;
  81. }
  82. LPCSTR CStringArray::GetByIndex(ULONG ulIndex)
  83. {
  84. if (0 == m_ulLength || (ulIndex > m_ulLength - 1))
  85. return NULL;
  86. return m_rgpszValues[ulIndex];
  87. }
  88. // --------------------------------------------------------------------------------
  89. // CStringArray::RemoveByIndex
  90. // --------------------------------------------------------------------------------
  91. HRESULT CStringArray::RemoveByIndex(ULONG ulIndex)
  92. {
  93. if (ulIndex > m_ulLength - 1)
  94. return E_INVALIDARG;
  95. if (NULL != m_rgpszValues[ulIndex])
  96. {
  97. MemFree(const_cast<char *>(m_rgpszValues[ulIndex]));
  98. m_rgpszValues[ulIndex] = NULL;
  99. }
  100. // shift down
  101. CopyMemory(&m_rgpszValues[ulIndex], m_rgpszValues[ulIndex + 1], (m_ulLength - ulIndex) * sizeof(LPSTR));
  102. --m_ulLength;
  103. return S_OK;
  104. }
  105. // --------------------------------------------------------------------------------
  106. // CStringArray::Expand
  107. // --------------------------------------------------------------------------------
  108. BOOL CStringArray::Expand(void)
  109. {
  110. LPCSTR *rgpszNewValues = NULL;
  111. if (!MemAlloc((void **)&rgpszNewValues, sizeof(LPSTR) * (m_ulCapacity + c_ulGrowSize)))
  112. return FALSE;
  113. // clear the new slots
  114. ZeroMemory(rgpszNewValues,sizeof(LPSTR) * (m_ulCapacity + c_ulGrowSize));
  115. // copy the old values over and swap in the new buffer
  116. CopyMemory(rgpszNewValues, m_rgpszValues, sizeof(LPSTR) * m_ulCapacity);
  117. SafeMemFree(m_rgpszValues);
  118. m_rgpszValues = rgpszNewValues;
  119. m_ulCapacity += c_ulGrowSize;
  120. return TRUE;
  121. }
  122. // --------------------------------------------------------------------------------
  123. // CStringHash::~CStringHash
  124. // --------------------------------------------------------------------------------
  125. CStringHash::~CStringHash(void)
  126. {
  127. PHASHENTRY phe;
  128. // data stored in the hash table
  129. // are strings that can need to
  130. // be deallocated.
  131. for (DWORD dw = 0; dw < m_cBins; dw++)
  132. {
  133. SafeMemFree(m_rgBins[dw].pv);
  134. phe = m_rgBins[dw].pheNext;
  135. while (phe)
  136. {
  137. SafeMemFree(phe->pv);
  138. phe = phe->pheNext;
  139. }
  140. }
  141. }
  142. // --------------------------------------------------------------------------------
  143. // CDAVNamespaceArbiterImp::CDAVNamespaceArbiterImp
  144. // --------------------------------------------------------------------------------
  145. CDAVNamespaceArbiterImp::CDAVNamespaceArbiterImp(void)
  146. {
  147. for (ULONG i = 0; i <= c_dwMaxNamespaceID; ++i)
  148. m_rgbNsUsed[i] = FALSE;
  149. // the DAV namespace is always included
  150. m_rgbNsUsed[DAVNAMESPACE_DAV] = TRUE;
  151. }
  152. // --------------------------------------------------------------------------------
  153. // CDAVNamespaceArbiterImp::~CDAVNamespaceArbiterImp
  154. // --------------------------------------------------------------------------------
  155. CDAVNamespaceArbiterImp::~CDAVNamespaceArbiterImp(void)
  156. {
  157. // nothing to do
  158. }
  159. // --------------------------------------------------------------------------------
  160. // CDAVNamespaceArbiterImp::AddNamespace
  161. // --------------------------------------------------------------------------------
  162. HRESULT CDAVNamespaceArbiterImp::AddNamespace(LPCSTR pszNamespace, DWORD *pdwNamespaceID)
  163. {
  164. HRESULT hr = S_OK;
  165. if (NULL == pszNamespace || NULL == pdwNamespaceID)
  166. {
  167. hr = E_INVALIDARG;
  168. goto exit;
  169. }
  170. if (FAILED(hr = m_saNamespaces.Add(pszNamespace)))
  171. goto exit;
  172. *pdwNamespaceID = m_saNamespaces.Length() + c_dwMaxNamespaceID;
  173. exit:
  174. return hr;
  175. }
  176. // --------------------------------------------------------------------------------
  177. // CDAVNamespaceArbiterImp::GetNamespaceID
  178. // --------------------------------------------------------------------------------
  179. HRESULT CDAVNamespaceArbiterImp::GetNamespaceID(LPCSTR pszNamespace, DWORD *pdwNamespaceID)
  180. {
  181. DWORD dwIndex;
  182. DWORD dwEntries;
  183. if (NULL == pszNamespace || NULL == pdwNamespaceID)
  184. return E_INVALIDARG;
  185. // look for a predefined namespace
  186. for (dwIndex = 0; dwIndex < c_dwMaxNamespaceID; ++dwIndex)
  187. {
  188. if (!lstrcmp(pszNamespace, g_rgszNamespaces[dwIndex]))
  189. {
  190. *pdwNamespaceID = dwIndex;
  191. return S_OK;
  192. }
  193. }
  194. // look for a user-defined prefix
  195. dwEntries = m_saNamespaces.Length();
  196. for (dwIndex = 0; dwIndex < dwEntries; ++dwIndex)
  197. {
  198. if (!lstrcmp(pszNamespace, m_saNamespaces.GetByIndex(dwIndex)))
  199. {
  200. *pdwNamespaceID = (dwIndex + (c_dwMaxNamespaceID + 1));
  201. return S_OK;
  202. }
  203. }
  204. // if it wasn't found, the namespace doesn't exist
  205. return E_INVALIDARG;
  206. }
  207. // --------------------------------------------------------------------------------
  208. // CDAVNamespaceArbiterImp::GetNamespacePrefix
  209. // --------------------------------------------------------------------------------
  210. HRESULT CDAVNamespaceArbiterImp::GetNamespacePrefix(DWORD dwNamespaceID, LPSTR *ppszNamespacePrefix)
  211. {
  212. HRESULT hr = S_OK;
  213. LPSTR pszTemp = NULL;
  214. if (NULL == ppszNamespacePrefix)
  215. return E_INVALIDARG;
  216. if (dwNamespaceID <= c_dwMaxDefinedNamespacePrefix)
  217. *ppszNamespacePrefix = PszDupA(g_rgszNamespacePrefixes[dwNamespaceID]);
  218. else
  219. {
  220. char szBuffer[12];
  221. wnsprintf(szBuffer, ARRAYSIZE(szBuffer), "_%d", dwNamespaceID);
  222. *ppszNamespacePrefix = PszDupA(szBuffer);
  223. }
  224. if (NULL == *ppszNamespacePrefix)
  225. hr = E_OUTOFMEMORY;
  226. return hr;
  227. }
  228. // --------------------------------------------------------------------------------
  229. // CDAVNamespaceArbiterImp::AllocExpandedName
  230. // --------------------------------------------------------------------------------
  231. LPSTR CDAVNamespaceArbiterImp::AllocExpandedName(DWORD dwNamespaceID, LPCSTR pszPropertyName)
  232. {
  233. LPSTR pszPrefixedName = NULL;
  234. const DWORD c_dwMaxIntLength = 10;
  235. if (dwNamespaceID < c_dwMaxDefinedNamespacePrefix)
  236. {
  237. // allocate a buffer to hold the prefixed name.
  238. DWORD cchSize = (lstrlen(pszPropertyName) + lstrlen(g_rgszNamespacePrefixes[dwNamespaceID]) + 2);
  239. if (!MemAlloc((void **)&pszPrefixedName, cchSize * sizeof(pszPrefixedName[0])))
  240. return NULL;
  241. // generate the prefixed name
  242. wnsprintf(pszPrefixedName, cchSize, "%s:%s", g_rgszNamespacePrefixes[dwNamespaceID], pszPropertyName);
  243. }
  244. else
  245. {
  246. // allocate a buffer to hold the prefixed name. the "2" is for the prefix char '_" , the delimiting
  247. // colon and the eos.
  248. DWORD cchSize = (lstrlen(pszPropertyName) + c_dwMaxIntLength + 3);
  249. if (!MemAlloc((void **)&pszPrefixedName, cchSize * sizeof(pszPrefixedName[0])))
  250. return NULL;
  251. // generate the prefixed name. use an underscore as the first char, because
  252. // DAV explicitly disallows digits for the first char.
  253. wnsprintf(pszPrefixedName, cchSize, "_%d:%s", dwNamespaceID, pszPropertyName);
  254. }
  255. return pszPrefixedName;
  256. }
  257. // --------------------------------------------------------------------------------
  258. // CDAVNamespaceArbiterImp::WriteNamespaces
  259. // --------------------------------------------------------------------------------
  260. HRESULT CDAVNamespaceArbiterImp::WriteNamespaces(IStream *pStream)
  261. {
  262. HRESULT hr = S_OK;
  263. ULONG i;
  264. ULONG cEntries;
  265. BOOL fNeedSpacePrefix = FALSE;
  266. // write out the intrinsic namespaces
  267. for (i = 0; i <= c_dwMaxNamespaceID; ++i)
  268. {
  269. if (m_rgbNsUsed[i])
  270. {
  271. if (FAILED(hr = _AppendXMLNamespace(pStream, g_rgszNamespaces[i], i, fNeedSpacePrefix)))
  272. goto exit;
  273. fNeedSpacePrefix = TRUE;
  274. }
  275. }
  276. // write out the installed namespaces
  277. cEntries = m_saNamespaces.Length();
  278. for (i = 0; i < cEntries; ++i)
  279. {
  280. if (FAILED(hr = _AppendXMLNamespace(pStream, m_saNamespaces.GetByIndex(i), i + i + c_dwMaxNamespaceID + 1, fNeedSpacePrefix)))
  281. goto exit;
  282. fNeedSpacePrefix = TRUE;
  283. }
  284. exit:
  285. return hr;
  286. }
  287. // --------------------------------------------------------------------------------
  288. // CDAVNamespaceArbiterImp::_AppendXMLNamespace
  289. // --------------------------------------------------------------------------------
  290. HRESULT CDAVNamespaceArbiterImp::_AppendXMLNamespace(IStream *pStream,
  291. LPCSTR pszNamespace,
  292. DWORD dwNamespaceID,
  293. BOOL fWhitespacePrefix)
  294. {
  295. HRESULT hr = S_OK;
  296. TCHAR szPrefix[12];
  297. if (fWhitespacePrefix)
  298. {
  299. IxpAssert(1 == lstrlen(c_szEqual));
  300. if (FAILED(hr = pStream->Write(g_szSpace, 1, NULL)))
  301. goto exit;
  302. }
  303. if (FAILED(hr = pStream->Write(c_szXMLNsColon, lstrlen(c_szXMLNsColon), NULL)))
  304. goto exit;
  305. if (dwNamespaceID < c_dwMaxDefinedNamespacePrefix)
  306. {
  307. if (FAILED(hr = pStream->Write(g_rgszNamespacePrefixes[dwNamespaceID], lstrlen(g_rgszNamespacePrefixes[dwNamespaceID]), NULL)))
  308. goto exit;
  309. }
  310. else
  311. {
  312. wnsprintf(szPrefix, ARRAYSIZE(szPrefix), "_%d", dwNamespaceID);
  313. if (FAILED(hr = pStream->Write(szPrefix, lstrlen(szPrefix), NULL)))
  314. goto exit;
  315. }
  316. IxpAssert(1 == lstrlen(c_szEqual));
  317. IxpAssert(1 == lstrlen(c_szDoubleQuote));
  318. if (FAILED(hr = pStream->Write(c_szEqual, 1, NULL)))
  319. goto exit;
  320. if (FAILED(hr = pStream->Write(c_szDoubleQuote, 1, NULL)))
  321. goto exit;
  322. if (FAILED(hr = pStream->Write(pszNamespace, lstrlen(pszNamespace), NULL)))
  323. goto exit;
  324. hr = pStream->Write(c_szDoubleQuote, 1, NULL);
  325. exit:
  326. return hr;
  327. }
  328. // --------------------------------------------------------------------------------
  329. // CPropPatchRequest::CPropPatchRequest
  330. // --------------------------------------------------------------------------------
  331. CPropPatchRequest::CPropPatchRequest(void) :
  332. m_fSpecify1252(FALSE),
  333. m_cRef(1)
  334. {
  335. // nothing to do
  336. }
  337. // --------------------------------------------------------------------------------
  338. // IUnknown Methods
  339. // --------------------------------------------------------------------------------
  340. // --------------------------------------------------------------------------------
  341. // CPropPatchRequest::QueryInterface
  342. // --------------------------------------------------------------------------------
  343. STDMETHODIMP CPropPatchRequest::QueryInterface(REFIID riid, LPVOID *ppv)
  344. {
  345. // Locals
  346. HRESULT hr = S_OK;
  347. // Validate params
  348. if (NULL == ppv)
  349. {
  350. hr = TrapError(E_INVALIDARG);
  351. goto exit;
  352. }
  353. // Initialize params
  354. *ppv = NULL;
  355. // IID_IUnknown
  356. if (IID_IUnknown == riid)
  357. *ppv = ((IUnknown *)(IPropFindRequest *)this);
  358. else if (IID_IPropPatchRequest == riid)
  359. *ppv = ((IPropPatchRequest *)this);
  360. if (NULL != *ppv)
  361. {
  362. ((LPUNKNOWN)*ppv)->AddRef();
  363. goto exit;
  364. }
  365. hr = TrapError(E_NOINTERFACE);
  366. exit:
  367. // Done
  368. return hr;
  369. }
  370. // --------------------------------------------------------------------------------
  371. // CPropPatchRequest::AddRef
  372. // --------------------------------------------------------------------------------
  373. STDMETHODIMP_(ULONG) CPropPatchRequest::AddRef(void)
  374. {
  375. return ++m_cRef;
  376. }
  377. // --------------------------------------------------------------------------------
  378. // CPropPatchRequest::Release
  379. // --------------------------------------------------------------------------------
  380. STDMETHODIMP_(ULONG) CPropPatchRequest::Release(void)
  381. {
  382. if (0 != --m_cRef)
  383. return m_cRef;
  384. delete this;
  385. return 0;
  386. }
  387. // ----------------------------------------------------------------------------
  388. // IDAVNamespaceArbiter methods
  389. // ----------------------------------------------------------------------------
  390. // --------------------------------------------------------------------------------
  391. // CPropPatchRequest::CPropPatchRequest::AddNamespace
  392. // --------------------------------------------------------------------------------
  393. STDMETHODIMP CPropPatchRequest::AddNamespace(LPCSTR pszNamespace, DWORD *pdwNamespaceID)
  394. {
  395. return m_dna.AddNamespace(pszNamespace, pdwNamespaceID);
  396. }
  397. // --------------------------------------------------------------------------------
  398. // CPropPatchRequest::GetNamespaceID
  399. // --------------------------------------------------------------------------------
  400. STDMETHODIMP CPropPatchRequest::GetNamespaceID(LPCSTR pszNamespace, DWORD *pdwNamespaceID)
  401. {
  402. return m_dna.GetNamespaceID(pszNamespace, pdwNamespaceID);
  403. }
  404. // --------------------------------------------------------------------------------
  405. // CPropPatchRequest::GetNamespacePrefix
  406. // --------------------------------------------------------------------------------
  407. STDMETHODIMP CPropPatchRequest::GetNamespacePrefix(DWORD dwNamespaceID, LPSTR *ppszNamespacePrefix)
  408. {
  409. return m_dna.GetNamespacePrefix(dwNamespaceID, ppszNamespacePrefix);
  410. }
  411. // --------------------------------------------------------------------------------
  412. // IPropPatchRequest Methods
  413. // --------------------------------------------------------------------------------
  414. // --------------------------------------------------------------------------------
  415. // CPropPatchRequest::SetProperty
  416. // --------------------------------------------------------------------------------
  417. STDMETHODIMP CPropPatchRequest::SetProperty(
  418. DWORD dwNamespaceID,
  419. LPCSTR pszPropertyName,
  420. LPCSTR pszNewValue)
  421. {
  422. LPSTR pszPrefixedName = NULL;
  423. HRESULT hr = S_OK;
  424. // Validate params
  425. if (NULL == pszPropertyName || NULL == pszNewValue || dwNamespaceID > c_dwMaxNamespaceID + m_dna.m_saNamespaces.Length())
  426. {
  427. hr = E_INVALIDARG;
  428. goto exit;
  429. }
  430. pszPrefixedName = m_dna.AllocExpandedName(dwNamespaceID, pszPropertyName);
  431. if (NULL == pszPrefixedName)
  432. {
  433. hr = E_OUTOFMEMORY;
  434. goto exit;
  435. }
  436. // if the namespace is one of the known namespaces, mark it in
  437. // the array so that we can include the namespace directive in
  438. // the generated xml
  439. if (dwNamespaceID <= c_dwMaxNamespaceID)
  440. m_dna.m_rgbNsUsed[dwNamespaceID] = TRUE;
  441. if (FAILED(hr = m_saPropValues.Add(pszNewValue)))
  442. goto exit;
  443. if (FAILED(hr = m_saPropNames.Adopt(pszPrefixedName)))
  444. {
  445. MemFree(pszPrefixedName);
  446. m_saPropValues.RemoveByIndex(m_saPropValues.Length() - 1);
  447. }
  448. exit:
  449. return hr;
  450. }
  451. // --------------------------------------------------------------------------------
  452. // CPropPatchRequest::RemoveProperty
  453. // --------------------------------------------------------------------------------
  454. STDMETHODIMP CPropPatchRequest::RemoveProperty(
  455. DWORD dwNamespaceID,
  456. LPCSTR pszPropertyName)
  457. {
  458. LPSTR pszPrefixedName = NULL;
  459. HRESULT hr = S_OK;
  460. if (NULL == pszPropertyName || dwNamespaceID > c_dwMaxNamespaceID + m_dna.m_saNamespaces.Length())
  461. {
  462. hr = E_INVALIDARG;
  463. goto exit;
  464. }
  465. pszPrefixedName = m_dna.AllocExpandedName(dwNamespaceID, pszPropertyName);
  466. if (NULL == pszPrefixedName)
  467. {
  468. hr = E_OUTOFMEMORY;
  469. goto exit;
  470. }
  471. // if the namespace is one of the known namespaces, mark it in
  472. // the array so that we can include the namespace directive in the
  473. // generated xml
  474. if (dwNamespaceID <= c_dwMaxNamespaceID)
  475. m_dna.m_rgbNsUsed[dwNamespaceID] = TRUE;
  476. hr = m_saRemovePropNames.Adopt(pszPrefixedName);
  477. exit:
  478. return hr;
  479. }
  480. // --------------------------------------------------------------------------------
  481. // CPropPatchRequest::GenerateXML
  482. // --------------------------------------------------------------------------------
  483. STDMETHODIMP CPropPatchRequest::GenerateXML(LPSTR *ppszXML)
  484. {
  485. return GenerateXML(NULL, ppszXML);
  486. }
  487. // --------------------------------------------------------------------------------
  488. // CPropPatchRequest::GenerateXML
  489. // --------------------------------------------------------------------------------
  490. STDMETHODIMP CPropPatchRequest::GenerateXML(LPHTTPTARGETLIST pTargets, LPSTR *ppszXML)
  491. {
  492. const DWORD c_dwLocalBufferSize = 256;
  493. HRESULT hr = S_OK;
  494. CByteStream stream;
  495. ULONG cEntries;
  496. LPCSTR pszName = NULL;
  497. LPCSTR pszValue = NULL;
  498. ULONG i;
  499. DWORD dwIndex;
  500. DWORD cbStr1, cbStr2;
  501. if (NULL == ppszXML)
  502. return E_INVALIDARG;
  503. *ppszXML= NULL;
  504. // write the DAV header
  505. if (m_fSpecify1252)
  506. FAIL_EXIT_STREAM_WRITE(stream, c_szXML1252Head);
  507. else
  508. FAIL_EXIT_STREAM_WRITE(stream, c_szXMLHead);
  509. // write out the proppatch header
  510. FAIL_EXIT_STREAM_WRITE(stream, c_szPropPatchHead);
  511. // write out namespace directives using the new form
  512. FAIL_EXIT(hr = m_dna.WriteNamespaces(&stream));
  513. FAIL_EXIT_STREAM_WRITE(stream, c_szXMLCloseElement);
  514. // write out the targets
  515. if (NULL != pTargets && pTargets->cTarget > 0)
  516. {
  517. cbStr1 = lstrlen(c_szHrefHead);
  518. cbStr2 = lstrlen(c_szHrefTail);
  519. FAIL_EXIT_STREAM_WRITE(stream, c_szTargetHead);
  520. // write out the targets
  521. for (dwIndex = 0; dwIndex < pTargets->cTarget; dwIndex++)
  522. {
  523. FAIL_EXIT(hr = stream.Write(c_szHrefHead, cbStr1, NULL));
  524. FAIL_EXIT_STREAM_WRITE(stream, pTargets->prgTarget[dwIndex]);
  525. FAIL_EXIT(hr = stream.Write(c_szHrefTail, cbStr2, NULL));
  526. }
  527. FAIL_EXIT_STREAM_WRITE(stream, c_szTargetTail);
  528. }
  529. // write out the "set" properties
  530. cEntries = m_saPropNames.Length();
  531. if (cEntries > 0)
  532. {
  533. // write the set header
  534. FAIL_EXIT_STREAM_WRITE(stream, c_szPropPatchSetHead);
  535. for (i = 0; i < cEntries; ++i)
  536. {
  537. FAIL_EXIT_STREAM_WRITE(stream, c_szCRLFTabTabTabOpenElement);
  538. pszName = m_saPropNames.GetByIndex(i);
  539. if (NULL == pszName)
  540. {
  541. hr = E_OUTOFMEMORY;
  542. goto exit;
  543. }
  544. FAIL_EXIT_STREAM_WRITE(stream, pszName);
  545. FAIL_EXIT_STREAM_WRITE(stream, c_szXMLCloseElement);
  546. pszValue = m_saPropValues.GetByIndex(i);
  547. if (NULL == pszValue)
  548. {
  549. hr = E_OUTOFMEMORY;
  550. goto exit;
  551. }
  552. FAIL_EXIT_STREAM_WRITE(stream, pszValue);
  553. FAIL_EXIT_STREAM_WRITE(stream, c_szXMLOpenTermElement);
  554. FAIL_EXIT_STREAM_WRITE(stream, pszName);
  555. FAIL_EXIT_STREAM_WRITE(stream, c_szXMLCloseElement);
  556. }
  557. FAIL_EXIT_STREAM_WRITE(stream, c_szPropPatchSetTail);
  558. }
  559. // write out the remove properties
  560. cEntries = m_saRemovePropNames.Length();
  561. if (cEntries > 0)
  562. {
  563. // write the remove header
  564. FAIL_EXIT_STREAM_WRITE(stream, c_szPropPatchRemoveHead);
  565. for (i = 0; i < cEntries; ++i)
  566. {
  567. FAIL_EXIT_STREAM_WRITE(stream, c_szCRLFTabTabTabOpenElement);
  568. pszName = m_saRemovePropNames.GetByIndex(i);
  569. if (NULL == pszName)
  570. {
  571. hr = E_OUTOFMEMORY;
  572. goto exit;
  573. }
  574. FAIL_EXIT_STREAM_WRITE(stream, pszName);
  575. FAIL_EXIT_STREAM_WRITE(stream, c_szXMLCloseTermElement);
  576. }
  577. FAIL_EXIT_STREAM_WRITE(stream, c_szPropPatchRemoveTail);
  578. }
  579. FAIL_EXIT_STREAM_WRITE(stream, c_szPropPatchTailCRLF);
  580. hr = stream.HrAcquireStringA(NULL, ppszXML, ACQ_DISPLACE);
  581. exit:
  582. return hr;
  583. }
  584. // --------------------------------------------------------------------------------
  585. // CPropFindRequest::CPropFindRequest
  586. // --------------------------------------------------------------------------------
  587. CPropFindRequest::CPropFindRequest(void) :
  588. m_cRef(1)
  589. {
  590. }
  591. // --------------------------------------------------------------------------------
  592. // IUnknown Methods
  593. // --------------------------------------------------------------------------------
  594. // --------------------------------------------------------------------------------
  595. // CPropFindRequest::QueryInterface
  596. // --------------------------------------------------------------------------------
  597. STDMETHODIMP CPropFindRequest::QueryInterface(REFIID riid, LPVOID *ppv)
  598. {
  599. // Locals
  600. HRESULT hr = S_OK;
  601. // Validate params
  602. if (NULL == ppv)
  603. {
  604. hr = TrapError(E_INVALIDARG);
  605. goto exit;
  606. }
  607. // Initialize params
  608. *ppv = NULL;
  609. // IID_IUnknown
  610. if (IID_IUnknown == riid)
  611. *ppv = ((IUnknown *)(IPropFindRequest *)this);
  612. else if (IID_IPropFindRequest == riid)
  613. *ppv = ((IPropFindRequest *)this);
  614. if (NULL != *ppv)
  615. {
  616. ((LPUNKNOWN)*ppv)->AddRef();
  617. goto exit;
  618. }
  619. hr = TrapError(E_NOINTERFACE);
  620. exit:
  621. // Done
  622. return hr;
  623. }
  624. // --------------------------------------------------------------------------------
  625. // CPropFindRequest::AddRef
  626. // --------------------------------------------------------------------------------
  627. STDMETHODIMP_(ULONG) CPropFindRequest::AddRef(void)
  628. {
  629. return ++m_cRef;
  630. }
  631. // --------------------------------------------------------------------------------
  632. // CPropFindRequest::Release
  633. // --------------------------------------------------------------------------------
  634. STDMETHODIMP_(ULONG) CPropFindRequest::Release(void)
  635. {
  636. if (0 != --m_cRef)
  637. return m_cRef;
  638. delete this;
  639. return 0;
  640. }
  641. // ----------------------------------------------------------------------------
  642. // IDAVNamespaceArbiter methods
  643. // ----------------------------------------------------------------------------
  644. // --------------------------------------------------------------------------------
  645. // CPropFindRequest::CPropPatchRequest::AddNamespace
  646. // --------------------------------------------------------------------------------
  647. STDMETHODIMP CPropFindRequest::AddNamespace(LPCSTR pszNamespace, DWORD *pdwNamespaceID)
  648. {
  649. return m_dna.AddNamespace(pszNamespace, pdwNamespaceID);
  650. }
  651. // --------------------------------------------------------------------------------
  652. // CPropFindRequest::GetNamespaceID
  653. // --------------------------------------------------------------------------------
  654. STDMETHODIMP CPropFindRequest::GetNamespaceID(LPCSTR pszNamespace, DWORD *pdwNamespaceID)
  655. {
  656. return m_dna.GetNamespaceID(pszNamespace, pdwNamespaceID);
  657. }
  658. // --------------------------------------------------------------------------------
  659. // CPropFindRequest::GetNamespacePrefix
  660. // --------------------------------------------------------------------------------
  661. STDMETHODIMP CPropFindRequest::GetNamespacePrefix(DWORD dwNamespaceID, LPSTR *ppszNamespacePrefix)
  662. {
  663. return m_dna.GetNamespacePrefix(dwNamespaceID, ppszNamespacePrefix);
  664. }
  665. // --------------------------------------------------------------------------------
  666. // IPropFindRequest Methods
  667. // --------------------------------------------------------------------------------
  668. // --------------------------------------------------------------------------------
  669. // CPropFindRequest::AddProperty
  670. // --------------------------------------------------------------------------------
  671. STDMETHODIMP CPropFindRequest::AddProperty(DWORD dwNamespaceID, LPCSTR pszPropertyName)
  672. {
  673. const DWORD c_dwMaxIntLength = 10;
  674. LPSTR pszPrefixedName = NULL;
  675. // Validate Params
  676. if (NULL == pszPropertyName || dwNamespaceID > c_dwMaxNamespaceID + m_dna.m_saNamespaces.Length())
  677. return E_INVALIDARG;
  678. pszPrefixedName = m_dna.AllocExpandedName(dwNamespaceID, pszPropertyName);
  679. if (NULL == pszPrefixedName)
  680. return E_OUTOFMEMORY;
  681. // if the namespace is one of the known namespaces, mark
  682. // the array so that we can include the namespace directive
  683. // in the generated xml.
  684. if (dwNamespaceID <= c_dwMaxNamespaceID)
  685. m_dna.m_rgbNsUsed[dwNamespaceID] = TRUE;
  686. m_saProperties.Adopt(pszPrefixedName);
  687. return S_OK;
  688. }
  689. // --------------------------------------------------------------------------------
  690. // CPropFindRequest::GenerateXML
  691. // --------------------------------------------------------------------------------
  692. STDMETHODIMP CPropFindRequest::GenerateXML(LPSTR *ppszXML)
  693. {
  694. const DWORD c_dwLocalBufferSize = 256;
  695. HRESULT hr = S_OK;
  696. CByteStream stream;
  697. ULONG cbLength = 0;
  698. ULONG cEntries;
  699. ULONG i;
  700. LPCSTR pszProperty;
  701. if (NULL == ppszXML)
  702. return E_INVALIDARG;
  703. *ppszXML = NULL;
  704. // write the DAV header
  705. if (FAILED(hr = stream.Write(c_szXMLHead, lstrlen(c_szXMLHead), NULL)))
  706. goto exit;
  707. // write out the propfind header
  708. if (FAILED(hr = stream.Write(c_szPropFindHead1, lstrlen(c_szPropFindHead1), NULL)))
  709. goto exit;
  710. // write out namespaces using the new form
  711. if (FAILED(hr = m_dna.WriteNamespaces(&stream)))
  712. goto exit;
  713. if (FAILED(hr = stream.Write(c_szPropFindHead2, lstrlen(c_szPropFindHead2), NULL)))
  714. goto exit;
  715. // write out the properties
  716. cEntries = m_saProperties.Length();
  717. for (i = 0; i < cEntries; ++i)
  718. {
  719. if (FAILED(hr = stream.Write(c_szCRLFTabTabOpenElement, lstrlen(c_szCRLFTabTabOpenElement), NULL)))
  720. goto exit;
  721. // properties are prefixed when they are added to the collection
  722. pszProperty = m_saProperties.GetByIndex(i);
  723. if (!pszProperty)
  724. {
  725. hr = E_OUTOFMEMORY;
  726. goto exit;
  727. }
  728. if (FAILED(hr = stream.Write(pszProperty, lstrlen(pszProperty), NULL)))
  729. goto exit;
  730. if (FAILED(hr = stream.Write(c_szXMLCloseTermElement, lstrlen(c_szXMLCloseTermElement), NULL)))
  731. goto exit;
  732. }
  733. if (FAILED(hr = stream.Write(c_szPropFindTail, lstrlen(c_szPropFindTail), NULL)))
  734. goto exit;
  735. hr = stream.HrAcquireStringA(NULL, ppszXML, ACQ_DISPLACE);
  736. exit:
  737. return hr;
  738. }
  739. // --------------------------------------------------------------------------------
  740. // class CPropFindMultiResponse
  741. // --------------------------------------------------------------------------------
  742. // --------------------------------------------------------------------------------
  743. // CPropFindMultiResponse::CPropFindMultiResponse
  744. // --------------------------------------------------------------------------------
  745. CPropFindMultiResponse::CPropFindMultiResponse(void) :
  746. m_cRef(1),
  747. m_bDone(FALSE),
  748. m_ulResponseCapacity(0),
  749. m_ulResponseLength(0),
  750. m_rgResponses(NULL)
  751. {
  752. }
  753. // --------------------------------------------------------------------------------
  754. // CPropFindMultiResponse::~CPropFindMultiResponse
  755. // --------------------------------------------------------------------------------
  756. CPropFindMultiResponse::~CPropFindMultiResponse(void)
  757. {
  758. for (ULONG i = 0; i < m_ulResponseLength; i++)
  759. SafeRelease(m_rgResponses[i]);
  760. SafeMemFree(m_rgResponses);
  761. }
  762. // --------------------------------------------------------------------------------
  763. // CPropFindMultiResponse::QueryInterface
  764. // --------------------------------------------------------------------------------
  765. STDMETHODIMP CPropFindMultiResponse::QueryInterface(REFIID riid, LPVOID *ppv)
  766. {
  767. // Locals
  768. HRESULT hr = S_OK;
  769. // Validate params
  770. if (NULL == ppv)
  771. {
  772. hr = TrapError(E_INVALIDARG);
  773. goto exit;
  774. }
  775. // Initialize params
  776. *ppv = NULL;
  777. // IID_IUnknown
  778. if (IID_IUnknown == riid)
  779. *ppv = ((IUnknown *)(IPropFindRequest *)this);
  780. else if (IID_IPropFindMultiResponse == riid)
  781. *ppv = ((IPropFindMultiResponse *)this);
  782. if (NULL != *ppv)
  783. {
  784. ((LPUNKNOWN)*ppv)->AddRef();
  785. goto exit;
  786. }
  787. hr = TrapError(E_NOINTERFACE);
  788. exit:
  789. // Done
  790. return hr;
  791. }
  792. // --------------------------------------------------------------------------------
  793. // CPropFindMultiResponse::AddRef
  794. // --------------------------------------------------------------------------------
  795. STDMETHODIMP_(ULONG) CPropFindMultiResponse::AddRef(void)
  796. {
  797. return ++m_cRef;
  798. }
  799. // --------------------------------------------------------------------------------
  800. // CPropFindMultiResponse::Release
  801. // --------------------------------------------------------------------------------
  802. STDMETHODIMP_(ULONG) CPropFindMultiResponse::Release(void)
  803. {
  804. if (0 != --m_cRef)
  805. return m_cRef;
  806. delete this;
  807. return 0;
  808. }
  809. // --------------------------------------------------------------------------------
  810. // CPropFindMultiResponse::IsComplete
  811. // --------------------------------------------------------------------------------
  812. STDMETHODIMP_(BOOL) CPropFindMultiResponse::IsComplete(void)
  813. {
  814. return m_bDone;
  815. }
  816. // --------------------------------------------------------------------------------
  817. // CPropFindMultiResponse::GetLength
  818. // --------------------------------------------------------------------------------
  819. STDMETHODIMP CPropFindMultiResponse::GetLength(ULONG *pulLength)
  820. {
  821. if (NULL == pulLength)
  822. return E_INVALIDARG;
  823. *pulLength = m_ulResponseLength;
  824. return S_OK;
  825. }
  826. // --------------------------------------------------------------------------------
  827. // CPropFindMultiResponse::GetResponse
  828. // --------------------------------------------------------------------------------
  829. STDMETHODIMP CPropFindMultiResponse::GetResponse(ULONG ulIndex,
  830. IPropFindResponse **ppResponse)
  831. {
  832. if (ulIndex >= m_ulResponseLength || !ppResponse)
  833. return E_INVALIDARG;
  834. *ppResponse = m_rgResponses[ulIndex];
  835. (*ppResponse)->AddRef();
  836. return S_OK;
  837. }
  838. // --------------------------------------------------------------------------------
  839. // CPropFindMultiResponse::HrAddResponse
  840. // --------------------------------------------------------------------------------
  841. HRESULT CPropFindMultiResponse::HrAddResponse(IPropFindResponse *pResponse)
  842. {
  843. const ULONG c_dwInitialCapacity = 4;
  844. HRESULT hr = S_OK;
  845. IPropFindResponse **ppNewResponses = NULL;
  846. DWORD dwNewCapacity;
  847. if (!pResponse)
  848. return E_INVALIDARG;
  849. if (m_ulResponseLength == m_ulResponseCapacity)
  850. {
  851. dwNewCapacity = !m_ulResponseCapacity ? c_dwInitialCapacity : (m_ulResponseCapacity * 2);
  852. if (!MemAlloc((void **)&ppNewResponses, dwNewCapacity * sizeof(IPropFindResponse *)))
  853. {
  854. hr = E_OUTOFMEMORY;
  855. goto exit;
  856. }
  857. ZeroMemory(ppNewResponses, dwNewCapacity * sizeof(IPropFindResponse *));
  858. // copy the old values over
  859. if (m_ulResponseCapacity)
  860. CopyMemory(ppNewResponses, m_rgResponses, min(dwNewCapacity, m_ulResponseCapacity) * sizeof(IPropFindResponse *));
  861. // free the old buffer
  862. SafeMemFree(m_rgResponses);
  863. m_rgResponses = ppNewResponses;
  864. m_ulResponseCapacity = dwNewCapacity;
  865. }
  866. m_rgResponses[m_ulResponseLength++] = pResponse;
  867. pResponse->AddRef();
  868. exit:
  869. return hr;
  870. }
  871. // --------------------------------------------------------------------------------
  872. // Class CPropFindResponse
  873. // --------------------------------------------------------------------------------
  874. // --------------------------------------------------------------------------------
  875. // CPropFindResponse::CPropFindResponse
  876. // --------------------------------------------------------------------------------
  877. CPropFindResponse::CPropFindResponse(void) :
  878. m_cRef(1),
  879. m_bDone(FALSE),
  880. m_pszHref(NULL),
  881. m_pRequest(NULL),
  882. m_shProperties(),
  883. m_dwCachedNamespaceID(0),
  884. m_pszCachedNamespacePrefix(NULL)
  885. {
  886. }
  887. // --------------------------------------------------------------------------------
  888. // CPropFindResponse::~CPropFindResponse
  889. // --------------------------------------------------------------------------------
  890. CPropFindResponse::~CPropFindResponse(void)
  891. {
  892. if (NULL != m_pszHref)
  893. MemFree(const_cast<char*>(m_pszHref));
  894. SafeRelease(m_pRequest);
  895. SafeMemFree(m_pszCachedNamespacePrefix);
  896. }
  897. // --------------------------------------------------------------------------------
  898. // CPropFindResponse::QueryInterface
  899. // --------------------------------------------------------------------------------
  900. STDMETHODIMP CPropFindResponse::QueryInterface(REFIID riid, LPVOID *ppv)
  901. {
  902. // Locals
  903. HRESULT hr = S_OK;
  904. // Validate params
  905. if (NULL == ppv)
  906. {
  907. hr = TrapError(E_INVALIDARG);
  908. goto exit;
  909. }
  910. // Initialize params
  911. *ppv = NULL;
  912. // IID_IUnknown
  913. if (IID_IUnknown == riid)
  914. *ppv = ((IUnknown *)(IPropFindResponse *)this);
  915. else if (IID_IPropFindResponse == riid)
  916. *ppv = ((IPropFindResponse *)this);
  917. if (NULL != *ppv)
  918. {
  919. ((LPUNKNOWN)*ppv)->AddRef();
  920. goto exit;
  921. }
  922. hr = TrapError(E_NOINTERFACE);
  923. exit:
  924. // Done
  925. return hr;
  926. }
  927. // --------------------------------------------------------------------------------
  928. // CPropFindResponse::AddRef
  929. // --------------------------------------------------------------------------------
  930. STDMETHODIMP_(ULONG) CPropFindResponse::AddRef(void)
  931. {
  932. return ++m_cRef;
  933. }
  934. // --------------------------------------------------------------------------------
  935. // CPropFindResponse::Release
  936. // --------------------------------------------------------------------------------
  937. STDMETHODIMP_(ULONG) CPropFindResponse::Release(void)
  938. {
  939. if (0 != --m_cRef)
  940. return m_cRef;
  941. delete this;
  942. return 0;
  943. }
  944. // --------------------------------------------------------------------------------
  945. // CPropFindResponse::IsComplete
  946. // --------------------------------------------------------------------------------
  947. STDMETHODIMP_(BOOL) CPropFindResponse::IsComplete(void)
  948. {
  949. return m_bDone;
  950. }
  951. // --------------------------------------------------------------------------------
  952. // CPropFindResponse::GetHref
  953. // --------------------------------------------------------------------------------
  954. STDMETHODIMP CPropFindResponse::GetHref(LPSTR *pszHref)
  955. {
  956. if (NULL == pszHref)
  957. return E_INVALIDARG;
  958. *pszHref = NULL;
  959. if (NULL == m_pszHref)
  960. return E_FAIL;
  961. *pszHref = PszDupA(m_pszHref);
  962. if (!*pszHref)
  963. return E_OUTOFMEMORY;
  964. return S_OK;
  965. }
  966. // --------------------------------------------------------------------------------
  967. // CPropFindResponse::GetProperty
  968. // --------------------------------------------------------------------------------
  969. STDMETHODIMP CPropFindResponse::GetProperty(
  970. DWORD dwNamespaceID,
  971. LPSTR pszPropertyName,
  972. LPSTR *ppszPropertyValue)
  973. {
  974. char szLocalPropBuffer[256];
  975. LPSTR pszPropBuffer = NULL;
  976. BOOL bFreePropBuffer = FALSE;
  977. LPSTR pszPrefix = NULL;
  978. HRESULT hr = S_OK;
  979. ULONG ulPrefixLength;
  980. ULONG ulPropertyLength;
  981. LPSTR pszFoundValue = NULL;
  982. if (!pszPropertyName)
  983. return E_INVALIDARG;
  984. *ppszPropertyValue = NULL;
  985. // first convert the namespace id into a prefix.
  986. // to facilitate fast lookups, we cache the most recently
  987. // seen custom namespace
  988. if (dwNamespaceID < c_dwMaxDefinedNamespacePrefix)
  989. pszPrefix = const_cast<char *>(g_rgszNamespacePrefixes[dwNamespaceID]);
  990. else if (dwNamespaceID == m_dwCachedNamespaceID)
  991. pszPrefix = m_pszCachedNamespacePrefix;
  992. else if (m_pRequest)
  993. {
  994. if (FAILED(hr = m_pRequest->GetNamespacePrefix(dwNamespaceID, &pszPrefix)))
  995. goto exit;
  996. // free the one-deep cache and store the new
  997. // prefix and ID.
  998. SafeMemFree(m_pszCachedNamespacePrefix);
  999. m_dwCachedNamespaceID = dwNamespaceID;
  1000. m_pszCachedNamespacePrefix = pszPrefix;
  1001. }
  1002. ulPrefixLength = lstrlen(pszPrefix);
  1003. ulPropertyLength = lstrlen(pszPropertyName);
  1004. DWORD cchSize = ARRAYSIZE(szLocalPropBuffer);
  1005. if ((ulPrefixLength + ulPropertyLength + (2 * sizeof(TCHAR))) < 256)
  1006. {
  1007. // the combined length is small enough to use
  1008. // the stack-based buffer
  1009. pszPropBuffer = szLocalPropBuffer;
  1010. }
  1011. else
  1012. {
  1013. cchSize = (ulPrefixLength + ulPropertyLength + 2);
  1014. if (!MemAlloc((void **)&pszPropBuffer, cchSize * sizeof(pszPropBuffer[0])))
  1015. {
  1016. hr = E_OUTOFMEMORY;
  1017. goto exit;
  1018. }
  1019. bFreePropBuffer = TRUE;
  1020. }
  1021. wnsprintf(pszPropBuffer, cchSize, "%s:%s", pszPrefix, pszPropertyName);
  1022. // XML parser uppercases everything
  1023. CharUpper(pszPropBuffer);
  1024. // now that the property name has been created, look for the
  1025. // value in the property hash table
  1026. if (FAILED(hr = m_shProperties.Find(pszPropBuffer, FALSE, (void **)&pszFoundValue)))
  1027. goto exit;
  1028. *ppszPropertyValue = PszDupA(pszFoundValue);
  1029. if (NULL == *ppszPropertyValue)
  1030. hr = E_OUTOFMEMORY;
  1031. exit:
  1032. if (bFreePropBuffer)
  1033. SafeMemFree(pszPropBuffer);
  1034. return hr;
  1035. }
  1036. // --------------------------------------------------------------------------------
  1037. // CPropFindResponse::HrInitPropFindResponse
  1038. // --------------------------------------------------------------------------------
  1039. HRESULT CPropFindResponse::HrInitPropFindResponse(IPropFindRequest *pRequest)
  1040. {
  1041. if (NULL == pRequest)
  1042. return E_INVALIDARG;
  1043. IxpAssert(!m_pRequest);
  1044. HRESULT hr = S_OK;
  1045. m_pRequest = pRequest;
  1046. m_pRequest->AddRef();
  1047. hr = m_shProperties.Init(17, TRUE);
  1048. return hr;
  1049. }
  1050. // --------------------------------------------------------------------------------
  1051. // CPropFindResponse::HrAdoptHref
  1052. // --------------------------------------------------------------------------------
  1053. HRESULT CPropFindResponse::HrAdoptHref(LPCSTR pszHref)
  1054. {
  1055. if (NULL == pszHref)
  1056. return E_INVALIDARG;
  1057. IxpAssert(!m_pszHref);
  1058. m_pszHref = pszHref;
  1059. return S_OK;
  1060. }
  1061. // --------------------------------------------------------------------------------
  1062. // CPropFindResponse::HrAdoptProperty
  1063. // --------------------------------------------------------------------------------
  1064. HRESULT CPropFindResponse::HrAdoptProperty(LPCSTR pszKey, LPCSTR pszValue)
  1065. {
  1066. if (!pszKey || !pszValue)
  1067. return E_INVALIDARG;
  1068. return m_shProperties.Insert(const_cast<char *>(pszKey), const_cast<char *>(pszValue), NOFLAGS);
  1069. }