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.

2545 lines
83 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. nodefac.cpp
  5. Abstract:
  6. This file implements the CDavNodefactory class which is used to parse the
  7. XML responses we get from the DAV server.
  8. Author:
  9. Rohan Kumar [RohanK] 14-Sept-1999
  10. Revision History:
  11. --*/
  12. #include "pch.h"
  13. #pragma hdrstop
  14. #include <stdio.h>
  15. #include <windows.h>
  16. #include "usrmddav.h"
  17. #include "nodefac.h"
  18. #include "stdlib.h"
  19. #include "wininet.h"
  20. #include "UniUtf.h"
  21. //
  22. // WebDAV Properties - RFC 2518.
  23. //
  24. WCHAR rgCreationDate[]= L":creationdate";
  25. WCHAR rgDisplayName[]= L":displayname"; // Ignored for now - href will be used to get name
  26. WCHAR rgGetContentLanguage[]= L"getcontentlanguage"; // Ignored for now
  27. WCHAR rgGetContentLength[] = L":getcontentlength";
  28. WCHAR rgGetContentType[] = L":getcontenttype"; // Ignored for now
  29. WCHAR rgGetETag[] = L":getetag"; // Ignored for now
  30. WCHAR rgGetLastModified[] = L":getlastmodified";
  31. WCHAR rgLockDiscovery[]= L":lockdiscovery"; // Ignored for now
  32. WCHAR rgResourceType[]= L":resourcetype";
  33. WCHAR rgSource[]= L":source"; // Ignored for now
  34. WCHAR rgSupportedLock[]= L":supportedlock"; // Ignored for now
  35. WCHAR rgTimeout[] = L":timeout";
  36. WCHAR rgLockToken[] = L":locktoken";
  37. WCHAR rgOwner[] = L":owner";
  38. //
  39. // Properties which this client will set on DAV resources to improve performance.
  40. //
  41. WCHAR rgIsHidden[]= L":ishidden";
  42. WCHAR rgIsCollection[]= L":iscollection";
  43. WCHAR rgIsReadOnly[]= L":isreadonly";
  44. WCHAR rgHref[] = L":href";
  45. WCHAR rgStatus[] = L":status";
  46. WCHAR rgResponse[] = L":response";
  47. WCHAR rgWin32FileAttributes[] = L":Win32FileAttributes";
  48. WCHAR rgWin32CreationTime[] = L":Win32CreationTime";
  49. WCHAR rgWin32LastAccessTime[] = L":Win32LastAccessTime";
  50. WCHAR rgWin32LastModifiedTime[] = L":Win32LastModifiedTime";
  51. //
  52. // MSN specific properties.
  53. //
  54. WCHAR rgAvailableSpace[]= L":availablespace";
  55. WCHAR rgTotalSpace[]= L":totalspace";
  56. DWORD
  57. DavInternetTimeToFileTime(
  58. PWCHAR lpTimeString,
  59. FILETIME *lpft
  60. );
  61. VOID
  62. DavOverrideAttributes(
  63. PDAV_FILE_ATTRIBUTES pDavFileAttributes
  64. );
  65. STDMETHODIMP_(ULONG)
  66. CDavNodeFactory::AddRef(
  67. VOID
  68. )
  69. /*++
  70. Routine Description:
  71. The AddRef function of the IUnknown class.
  72. Arguments:
  73. none.
  74. Return Value:
  75. The new reference count of the object.
  76. --*/
  77. {
  78. return (ULONG)InterlockedIncrement((long *)&m_ulRefCount);
  79. }
  80. STDMETHODIMP_(ULONG)
  81. CDavNodeFactory::Release(
  82. VOID
  83. )
  84. /*++
  85. Routine Description:
  86. The Release function of the IUnknown class.
  87. Arguments:
  88. none.
  89. Return Value:
  90. The reference count remaining on the object.
  91. --*/
  92. {
  93. ULONG ulRefCount = InterlockedDecrement((long *)&m_ulRefCount);
  94. if (ulRefCount == 0) {
  95. delete this;
  96. }
  97. return ulRefCount;
  98. }
  99. STDMETHODIMP
  100. CDavNodeFactory::QueryInterface(
  101. REFIID riid,
  102. LPVOID *ppvObject
  103. )
  104. /*++
  105. Routine Description:
  106. The QueryInterface function of the IUnknown class.
  107. Arguments:
  108. Return Value:
  109. HRESULT.
  110. --*/
  111. {
  112. HRESULT hr = E_NOINTERFACE;
  113. if (ppvObject == NULL)
  114. return E_POINTER;
  115. *ppvObject = NULL;
  116. if (IsEqualIID(riid, IID_IUnknown)) {
  117. *ppvObject = (LPVOID) this;
  118. AddRef();
  119. hr = NOERROR;
  120. } else if (IsEqualIID(riid, IID_IXMLNodeFactory)) {
  121. *ppvObject = (LPVOID) this;
  122. AddRef();
  123. hr = NOERROR;
  124. }
  125. return hr;
  126. }
  127. STDMETHODIMP
  128. CDavNodeFactory::NotifyEvent(
  129. IN IXMLNodeSource* pSource,
  130. IN XML_NODEFACTORY_EVENT iEvt
  131. )
  132. /*++
  133. Routine Description:
  134. The NotifyEvent function of the NodeFactory API.
  135. Arguments:
  136. Return Value:
  137. HRESULT.
  138. --*/
  139. {
  140. // XmlDavDbgPrint(("Entered NotifyEvent. Event = %d.\n", iEvt));
  141. return S_OK;
  142. }
  143. STDMETHODIMP
  144. CDavNodeFactory::BeginChildren(
  145. IN IXMLNodeSource* pSource,
  146. IN XML_NODE_INFO* pNodeInfo
  147. )
  148. /*++
  149. Routine Description:
  150. The BeginChildren function of the NodeFactory API.
  151. Arguments:
  152. Return Value:
  153. HRESULT.
  154. --*/
  155. {
  156. // XmlDavDbgPrint(("%ld: BeginChildren: pwcText = %ws\n",
  157. // GetCurrentThreadId(), pNodeInfo->pwcText));
  158. // XmlDavDbgPrint(("%ld: BeginChildren: fTerminal = %d\n",
  159. // GetCurrentThreadId(), pNodeInfo->fTerminal));
  160. return S_OK;
  161. }
  162. STDMETHODIMP
  163. CDavNodeFactory::EndChildren(
  164. IN IXMLNodeSource* pSource,
  165. IN BOOL fEmpty,
  166. IN XML_NODE_INFO* pNodeInfo
  167. )
  168. /*++
  169. Routine Description:
  170. The EndChildren function of the NodeFactory API.
  171. Arguments:
  172. Return Value:
  173. HRESULT.
  174. --*/
  175. {
  176. HRESULT hResult = S_OK;
  177. IXMLParser *Xp = NULL;
  178. CDavNodeFactory *NodeFac = NULL;
  179. PWCHAR Temp = NULL, thirdWack = NULL, firstChar = NULL, lastChar = NULL;
  180. BOOL isAbsoluteName = FALSE, lastCharIsWack = FALSE, rootLevel = FALSE, freeTemp = TRUE;
  181. DWORD wackCount = 0;
  182. ULONG_PTR LengthInChars = 0;
  183. PDAV_FILE_ATTRIBUTES DFA = NULL;
  184. DWORD ConvertedLength = 0;
  185. DWORD fullFileNameLength = 0;
  186. // XmlDavDbgPrint(("%ld: EndChildren: fEmpty = %d\n",
  187. // GetCurrentThreadId(), fEmpty));
  188. // XmlDavDbgPrint(("%ld: EndChildren: pwcText = %ws\n",
  189. // GetCurrentThreadId(), pNodeInfo->pwcText));
  190. // XmlDavDbgPrint(("%ld: EndChildren: fTerminal = %d\n",
  191. // GetCurrentThreadId(), pNodeInfo->fTerminal));
  192. Xp = (IXMLParser *)pSource;
  193. hResult = Xp->GetFactory( (IXMLNodeFactory **)&(NodeFac) );
  194. if (!SUCCEEDED(hResult)) {
  195. NodeFac = NULL;
  196. XmlDavDbgPrint(("%ld: ERROR: EndChildren/GetFactory.\n", GetCurrentThreadId()));
  197. goto EXIT_THE_FUNCTION;
  198. }
  199. //
  200. // IMPORTANT!!!
  201. // If this was an empty node, then we should set the NodeFac->m_FoundEntry
  202. // to FALSE. This is because if we get a node like <foo>...</foo></bar><haha>...
  203. // then CreateNode would have been called for "bar". If we were interested
  204. // in the property "bar", we would have set NodeFac->m_FoundEntry to TRUE.
  205. // This is with the expectation that the next CreateNode will come with the
  206. // value of "bar". But in this case, "bar" does not have any value since its
  207. // empty. So, the next CreateNode will be called with pwcText == "haha" which
  208. // we will expect to be the value of "bar" and the parsing will screw up.
  209. // To avoid this we set NodeFac->m_FoundEntry to FALSE here since between
  210. // the two CreateNodes, we get an EndChildren for "bar" with fEmpty set to
  211. // TRUE. This is the indication that we should not be looking for the value
  212. // of "bar" since its empty. By doing this, the parsing will continue smoothly
  213. // in CreateNode for the next element "haha".
  214. //
  215. if (fEmpty == TRUE) {
  216. NodeFac->m_FoundEntry = FALSE;
  217. goto EXIT_THE_FUNCTION;
  218. }
  219. //
  220. // Since filename information can span over many CreateNode calls, so we collect
  221. // the complete filename information in CreateNode calls and then process them
  222. // here (EndChildren) to get the displayname.
  223. // Ex. <href>http://abc.com/AB&quot;123</href> has 3 CreateNode calls:
  224. // 1] http://abc.com//AB
  225. // 2] "
  226. // 3] 123
  227. // and complete name is http://abc.com/AB"123.
  228. //
  229. if ( (NodeFac->m_FoundEntry == TRUE) &&
  230. (NodeFac->m_CreateNodeAttribute == CreateNode_DisplayName) ) {
  231. DFA = NodeFac->m_DFAToUse;
  232. if(DFA->FileName == NULL || DFA->FileNameLength == 0) {
  233. XmlDavDbgPrint(("%ld: ERROR: EndChildren. Invalid FileName information. FileName=0x%x FileNameLength=%d.\n",
  234. GetCurrentThreadId(), DFA->FileName, DFA->FileNameLength));
  235. hResult = CO_E_ERRORINAPP;
  236. goto EXIT_THE_FUNCTION;
  237. }
  238. //
  239. // Store the FullFileName Length in a local variable. This will be used to
  240. // find "parent DAV collection".
  241. //
  242. fullFileNameLength = DFA->FileNameLength;
  243. //
  244. // DFA->FileName buffer has filename of length DFA->FileNameLength and a
  245. // NULL character in the end.
  246. //
  247. //
  248. // Names can be absoulte URLs or can be relative URLs.
  249. // Format of absolute URLs:: scheme ":" (some path)
  250. // Format of relative URLs::
  251. // "//" (some path)
  252. // "/" (some path)
  253. // (some name) ["/" (some path)]
  254. //
  255. //
  256. //
  257. // Note : We are supporting only HTTP URLs "http://" (somepath)
  258. // and relative path names
  259. //
  260. //
  261. // We need to parse the string NodeInfo->pwcText and get the
  262. // DisplayName out of it. Here are the 7 cases we handle.
  263. // 1. http://rohank-srv/ <===> DisplayName == NULL.
  264. // 2. http://rohank-srv/test <===> DisplayName == test.
  265. // 3. http://rohank-srv/test/ <===> DisplayName == test.
  266. // 4. /test/ <===> DisplayName == test
  267. // 5. /test <===> DisplayName == test
  268. // 6. /test/foo.txt <===> DisplayName == foo.txt
  269. // 7. / <===> DisplayName == NULL
  270. // In the above "test" could very well be a path like foo/bar.
  271. // http://rohank-srv/test/foo.txt <===> DisplayName == foo.txt.
  272. firstChar = (PWCHAR)(DFA->FileName);
  273. //
  274. // http://rohank-srv/test/foo.txt"
  275. // ^
  276. // |
  277. // lastChar
  278. //
  279. lastChar = (PWCHAR)(firstChar + DFA->FileNameLength);
  280. //
  281. // Need to find if the name is Absolute name or Relative name. For this
  282. // if we find 'http://' in the start of name then it is a absolute name.
  283. //
  284. isAbsoluteName = FALSE;
  285. if((DFA->FileNameLength >= (sizeof(L"http://")/sizeof(WCHAR)-1)) &&
  286. (_wcsnicmp(firstChar, L"http://", (sizeof(L"http://")/sizeof(WCHAR))-1) == 0) ) {
  287. isAbsoluteName = TRUE;
  288. }
  289. //
  290. // If DFA->pwcText = http://rohank-srv/foo/bar.txt,
  291. // http://rohank-srv/foo/bar.txt
  292. // ^
  293. // |
  294. // thirdWack
  295. //
  296. thirdWack = firstChar;
  297. wackCount = 0;
  298. while(thirdWack < lastChar) {
  299. if (*thirdWack == L'/') {
  300. wackCount++;
  301. if (wackCount == 3) {
  302. break;
  303. }
  304. }
  305. thirdWack++;
  306. }
  307. //
  308. // After this loop, either thirdWack == 3rd Wack or thirdWack = lastChar.
  309. //
  310. //
  311. // We need to deal with five special cases.
  312. // 1. http://rohank-srv/ and
  313. // 2. http://rohank-srv/test/
  314. // 3. /
  315. // 4. test/
  316. // 5. //
  317. //
  318. if ( *(lastChar - 1) == L'/' ) {
  319. lastCharIsWack = TRUE;
  320. //
  321. // If URL = http://rohank-srv/, the display name should be
  322. // NULL.
  323. // Same for URL = / and URL = //
  324. //
  325. if ( ((lastChar - 1) == thirdWack && isAbsoluteName==TRUE) ||
  326. (DFA->FileNameLength == 1) ||
  327. (DFA->FileNameLength == 2 && *(lastChar-2) == L'/')) {
  328. rootLevel = TRUE;
  329. } else {
  330. rootLevel = FALSE;
  331. //
  332. // We subtract 2 here because of the way we do the
  333. // parsing below.
  334. //
  335. lastChar -= 2;
  336. }
  337. } else {
  338. lastCharIsWack = FALSE;
  339. rootLevel = FALSE;
  340. }
  341. if (rootLevel == FALSE) {
  342. //
  343. // Becuase we check for L'/', we subtract 2 from the
  344. // lastChar pointer above if the URL was of the form
  345. // 1. http://rohank-srv/test/.
  346. // 2. test/
  347. // We add the check lastChar != firstChar
  348. // in the loop below to make sure that we never go beyond the
  349. // begenning of the string. This could happen when pwcText is of the
  350. // form test/. In this case we will end at the character 't'.
  351. //
  352. while(*lastChar != L'/' && lastChar != firstChar) {
  353. lastChar--;
  354. }
  355. //
  356. // As explained above the last char need not be a '/'. An example is
  357. // when pwcText is test/. In this case lastChar points to 't'.
  358. //
  359. if(*lastChar == L'/') {
  360. lastChar++;
  361. }
  362. //
  363. // lastChar now points to the first char of the name after the
  364. // last backslash. The extra 1 is for the final \0 char.
  365. // http://rohank-srv/test/foo.txt
  366. // ^
  367. // |
  368. // lastChar
  369. //
  370. // Note: If last char is a wack, then it is included here.
  371. //
  372. LengthInChars = (ULONG_PTR)( (firstChar + DFA->FileNameLength + 1) - lastChar );
  373. if (LengthInChars <= 1) {
  374. XmlDavDbgPrint(("%ld: ERROR: EndChildren. Displayname length is 0.\n",
  375. GetCurrentThreadId()));
  376. hResult = CO_E_ERRORINAPP;
  377. goto EXIT_THE_FUNCTION;
  378. }
  379. } else {
  380. //
  381. // rootLevel = TRUE => FileName = L"/"
  382. LengthInChars = 2;
  383. }
  384. //
  385. // Allocate memory to contain Actual Display Name.
  386. //
  387. Temp = (PWCHAR)LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT,
  388. LengthInChars * sizeof(WCHAR) );
  389. if(Temp == NULL) {
  390. ULONG WStatus;
  391. WStatus = GetLastError();
  392. XmlDavDbgPrint(("%ld: ERROR: EndChildren. LocalAlloc. Error Val = %d\n",
  393. GetCurrentThreadId(), WStatus));
  394. hResult = CO_E_ERRORINAPP;
  395. goto EXIT_THE_FUNCTION;
  396. }
  397. freeTemp = TRUE;
  398. if(rootLevel == FALSE) {
  399. //
  400. // Copy the element. Displayname can be a unicode
  401. // string, then server will send it as a UTF-8 format URL string
  402. // We need to convert such a display name to a Unicode string.
  403. // Assumption: The URL is UTF-8 format encoded URL string.
  404. // i.e. extended characters appear as %HH%HH... in URL string.
  405. //
  406. ConvertedLength = 0;
  407. hResult = UtfUrlStrToWideStr(lastChar, (DWORD)(LengthInChars-1), Temp,
  408. &ConvertedLength);
  409. if(hResult != ERROR_SUCCESS) {
  410. XmlDavDbgPrint(("%ld: ERROR: EndChildren/UtfUrlToWideStr = %u\n",
  411. GetCurrentThreadId(), hResult));
  412. goto EXIT_THE_FUNCTION;
  413. }
  414. //
  415. // If the last char was a "/" like in http://rohank-srv/test/,
  416. // we would have copied "test/" as the name. We need to strip
  417. // out the last wack and the display name should be "test". ConvertedLength
  418. // points to the char next to the last char.
  419. //
  420. if (lastCharIsWack) {
  421. Temp[(ConvertedLength - 1)] = L'\0';
  422. }
  423. } else {
  424. //
  425. // The displayname is root level name - hence return L"/" for
  426. // actual displayname.
  427. //
  428. Temp[0] = L'/';
  429. Temp[1] = L'\0';
  430. }
  431. //XmlDavDbgPrint(("%ld. EndChildren. Temp=%ws, LengthInChars=%d\n", Temp, LengthInChars ));
  432. if ( DFA->FileName != NULL ) {
  433. LocalFree((HLOCAL)DFA->FileName);
  434. DFA->FileName = NULL;
  435. }
  436. DFA->FileNameLength = 0;
  437. NodeFac->m_DFAToUse->FileName = Temp;
  438. NodeFac->m_DFAToUse->FileNameLength = wcslen(Temp);
  439. freeTemp = FALSE;
  440. //
  441. // Files / Collections properties can come in any order in
  442. // a XML response. We want to have the DavFileAtrributes entry which
  443. // corresponds to Collection which "contains" all the other DAV resources
  444. // present in this XML response ("parent DAV collection").
  445. //
  446. // NodeFac->m_CollectionDFA will point to DFA entry with smallest
  447. // Full-DisplayName (that comes in "<a:href>Full-DisplayName</a:href>")
  448. // in the response.
  449. //
  450. // If XML response contains the properties of the "parent DAV collection"
  451. // then it will have smallest Full-DisplayName and in that case
  452. // NodeFac->m_CollectionDFA will point to entry of "parent DAV
  453. // collection".
  454. //
  455. // Caller of this function should know whether to expect entry for
  456. // "parent DAV resource" in this XML response.
  457. //
  458. if(fullFileNameLength < NodeFac->m_MinDisplayNameLength) {
  459. NodeFac->m_CollectionDFA = DFA;
  460. NodeFac->m_MinDisplayNameLength = fullFileNameLength;
  461. }
  462. }
  463. EXIT_THE_FUNCTION:
  464. //
  465. // Assumption: (this is TRUE according to our current implementation)
  466. // The XML_ELEMENTs which we parse to get information have atmost 1 child.
  467. //
  468. // When we have parsed a XML_ELEMENT of our interest and has set NodeFac->m_FoundEntry
  469. // = TRUE, we should set NodeFac->m_FoundEntry=FALSE on "EndChildren call of either
  470. // this XML_ELEMENT" or the "EndChildren call of first child XML_ELEMENT".
  471. //
  472. // NodeFac->m_FoundEntry = TRUE => We are parsing a XML_ELEMENT of our interest
  473. // and EndChildren is called either on ending of this XML_ELEMENT or on ending of
  474. // a child-element of this XML_ELEMENT.
  475. //
  476. if(NodeFac != NULL) {
  477. NodeFac->m_FoundEntry = FALSE;
  478. }
  479. if(freeTemp == TRUE && Temp != NULL) {
  480. LocalFree((HLOCAL)Temp);
  481. Temp = NULL;
  482. }
  483. return hResult;
  484. }
  485. STDMETHODIMP
  486. CDavNodeFactory::Error(
  487. IN IXMLNodeSource* pSource,
  488. IN HRESULT hrErrorCode,
  489. IN USHORT cNumRecs,
  490. IN XML_NODE_INFO __RPC_FAR **aNodeInfo
  491. )
  492. /*++
  493. Routine Description:
  494. The Error function of the NodeFactory API.
  495. Arguments:
  496. Return Value:
  497. HRESULT.
  498. --*/
  499. {
  500. HRESULT hResult = S_OK;
  501. XML_NODE_INFO *NodeInfo = NULL;
  502. IXMLParser *Xp = NULL;
  503. BSTR ErrorStr = NULL;
  504. const WCHAR *LineBuffer = NULL;
  505. ULONG LineBuffLen = 0, ErrPos = 0, LineNumber = 0, LinePos = 0, AbsPos = 0;
  506. XmlDavDbgPrint(("%ld: Entered Error...\n", GetCurrentThreadId()));
  507. XmlDavDbgPrint(("%ld: Error: hrErrorCode = %08lx\n", GetCurrentThreadId(), hrErrorCode));
  508. XmlDavDbgPrint(("%ld: Error: cNumRecs = %d\n", GetCurrentThreadId(), cNumRecs));
  509. Xp = (IXMLParser *)pSource;
  510. LineNumber = Xp->GetLineNumber();
  511. XmlDavDbgPrint(("%ld: Error: LineNumber = %d\n", GetCurrentThreadId(), LineNumber));
  512. LinePos = Xp->GetLinePosition();
  513. XmlDavDbgPrint(("%ld: Error: LinePosition = %d\n", GetCurrentThreadId(), LinePos));
  514. AbsPos = Xp->GetAbsolutePosition();
  515. XmlDavDbgPrint(("%ld: Error: AbsPos = %d\n", GetCurrentThreadId(), AbsPos));
  516. hResult = Xp->GetErrorInfo( &(ErrorStr) );
  517. if (!SUCCEEDED(hResult)) {
  518. XmlDavDbgPrint(("%ld: ERROR: Error/GetErrorInfo. hResult = %08lx\n",
  519. GetCurrentThreadId(), hResult));
  520. goto EXIT_THE_FUNCTION;
  521. }
  522. XmlDavDbgPrint(("%ld: Error: ErrorStr = %ws\n", GetCurrentThreadId(), ErrorStr));
  523. hResult = Xp->GetLineBuffer( &(LineBuffer), &(LineBuffLen), &(ErrPos) );
  524. if (!SUCCEEDED(hResult)) {
  525. XmlDavDbgPrint(("%ld: ERROR: Error/GetErrorInfo. hResult = %08lx\n",
  526. GetCurrentThreadId(), hResult));
  527. goto EXIT_THE_FUNCTION;
  528. }
  529. XmlDavDbgPrint(("%ld: Error: LineBuffer = %ws\n", GetCurrentThreadId(), LineBuffer));
  530. XmlDavDbgPrint(("%ld: Error: LineBufferLen = %d\n", GetCurrentThreadId(), LineBuffLen));
  531. XmlDavDbgPrint(("%ld: Error: ErrorPos = %d\n", GetCurrentThreadId(), ErrPos));
  532. EXIT_THE_FUNCTION:
  533. return S_OK;
  534. }
  535. STDMETHODIMP
  536. CDavNodeFactory::CreateNode(
  537. IN IXMLNodeSource __RPC_FAR *pSource,
  538. IN PVOID pNodeParent,
  539. IN USHORT cNumRecs,
  540. IN XML_NODE_INFO __RPC_FAR **aNodeInfo
  541. )
  542. /*++
  543. Routine Description:
  544. The CreateNode function of the NodeFactory API.
  545. Arguments:
  546. pSource - The XMLNodeSource pointer.
  547. pNodeParent -
  548. cNumRecs - Number of NodeInfo pointers in the array.
  549. aNodeInfo - Array of NodeInfo pointers.
  550. Return Value:
  551. HRESULT.
  552. --*/
  553. {
  554. HRESULT hResult = S_OK;
  555. XML_NODE_INFO *NodeInfo = NULL;
  556. PWCHAR Temp = NULL;
  557. ULONG_PTR LengthInChars = 0;
  558. BOOL freeTemp = TRUE, fPassElement = FALSE, fCopyInEnd = FALSE;
  559. PDAV_FILE_ATTRIBUTES DavFileAttributes = NULL;
  560. CDavNodeFactory *NodeFac = NULL;
  561. IXMLParser *Xp = NULL;
  562. CREATE_NODE_ATTRIBUTES nextCreateNodeAttribute = CreateNode_Max;
  563. PWCHAR startTag = NULL;
  564. ULONG_PTR tagLength = 0;
  565. ULONG_PTR tagOffset = 0;
  566. USHORT i;
  567. Xp = (IXMLParser *)pSource;
  568. // XmlDavDbgPrint(("%ld: Entered CreateNode. cNumRecs = %d\n",
  569. // GetCurrentThreadId(), cNumRecs));
  570. hResult = Xp->GetFactory( (IXMLNodeFactory **)&(NodeFac) );
  571. if (!SUCCEEDED(hResult)) {
  572. XmlDavDbgPrint(("%ld: ERROR: CreateNode/GetFactory.\n", GetCurrentThreadId()));
  573. goto EXIT_THE_FUNCTION;
  574. }
  575. for (i = 0; i < cNumRecs; i++) {
  576. NodeInfo = aNodeInfo[i];
  577. // XmlDavDbgPrint(("%ld: CreateNode: NodeInfo->ulLen = %d, NodeInfo->ulNsPrefixLen = %d\n",
  578. // GetCurrentThreadId(), NodeInfo->ulLen, NodeInfo->ulNsPrefixLen));
  579. // XmlDavDbgPrint(("%ld: CreateNode: NodeInfo->pwcText = %ws\n",
  580. // GetCurrentThreadId(), NodeInfo->pwcText));
  581. // XmlDavDbgPrint(("%ld: CreateNode: NodeInfo->fTerminal = %d\n",
  582. // GetCurrentThreadId(), NodeInfo->fTerminal));
  583. //
  584. // If the NodeInfo->dwType is XML_WHITESPACE then we ignore this node
  585. // since we don't care about WhiteSpaces.
  586. //
  587. if (NodeInfo->dwType == XML_WHITESPACE) {
  588. break;
  589. }
  590. //
  591. // The tags can be of types: "a:response" or "dp0:response".
  592. // In these cases NodeInfo->pwcText will point to first character ('a' or 'd')
  593. // Actual tag in these cases is ":response", so we need to get a pointer to
  594. // start of Actual-tag, and re-compute the remaining string length.
  595. //
  596. // Ex. lp0:response
  597. // ^
  598. // |
  599. // startTag
  600. // tagOffset = NodeInfo->ulNsPrefixLen = 3
  601. // NodeInfo->ulLen = 12 (don't account for L'\0')
  602. // tagLength = 12 - 3 = 9 = Len(":response") (don't account for L'\0')
  603. //
  604. tagOffset = NodeInfo->ulNsPrefixLen;
  605. startTag = (PWCHAR)(&(NodeInfo->pwcText[0]) + tagOffset);
  606. tagLength = NodeInfo->ulLen - tagOffset;
  607. //
  608. // If startTag == L":response", then we need a new
  609. // DavFileAttributes entry. The first eNodeFac->m_CreateNodeAttributentry
  610. // is allocated by the caller of the parser.
  611. // :response is an indication that in (multi status)
  612. // response that a new entry is going to begin.
  613. //
  614. //
  615. // Note: use startTag which takes care of namespace prefix.
  616. // Length = (sizeof(rgCreationDate)/sizeof(WCHAR)) includes L'\0' (null terminator)
  617. // but NodeInfo->ulLen don't account for NULL terminator in NodeInfo->pwcText. So
  618. // add 1 to tagLength (to account for L'\0' in startTag) before comparing it
  619. // to Tags (rgCreationDate).
  620. //
  621. fPassElement = FALSE;
  622. if (NodeInfo->dwType == XML_ELEMENT) {
  623. if( (tagLength + 1 == (sizeof(rgResponse)/sizeof(WCHAR))) &&
  624. (_wcsicmp(startTag, rgResponse) == 0) ) {
  625. //
  626. // m_FileIndex = No of entries for which "<a:response...>" is found
  627. // in response and memory is allocated for its DAV_FILE_ATTRIBUTES
  628. // structure. First entry is allocated by caller of this function, and
  629. // now "<a:response...>" is detected for this entry in XML response,
  630. // so increase m_FileIndex by 1.
  631. //
  632. if (NodeFac->m_FileIndex == 0) {
  633. NodeFac->m_FileIndex = 1;
  634. }
  635. else {
  636. //
  637. // Since the first DavFileAttributes entry is allocated by the
  638. // caller, we need to allocate only from the second entry.
  639. //
  640. NodeFac->m_CreateNewEntry = TRUE;
  641. }
  642. //
  643. // Since this CreateNode call has XML_ELEMENT ":reponse", we are done
  644. // with this call. Rest of NodeInfo in array contains information about
  645. // this xml element.
  646. //
  647. break; // Out of Loop
  648. }
  649. if ( ( tagLength + 1 == (sizeof(rgCreationDate)/sizeof(WCHAR)) &&
  650. _wcsicmp(startTag, rgCreationDate) == 0 ) ) {
  651. nextCreateNodeAttribute = CreateNode_CreationTime;
  652. } else if ( ( tagLength + 1 == (sizeof(rgGetContentLength)/sizeof(WCHAR)) &&
  653. _wcsicmp(startTag, rgGetContentLength) == 0 ) ) {
  654. nextCreateNodeAttribute = CreateNode_ContentLength;
  655. } else if ( ( tagLength + 1 == (sizeof(rgGetLastModified)/sizeof(WCHAR)) &&
  656. _wcsicmp(startTag, rgGetLastModified) == 0 ) ) {
  657. nextCreateNodeAttribute = CreateNode_LastModifiedTime;
  658. } else if ( ( tagLength + 1 == (sizeof(rgResourceType)/sizeof(WCHAR)) &&
  659. _wcsicmp(startTag, rgResourceType) == 0 ) ) {
  660. nextCreateNodeAttribute = CreateNode_ResourceType;
  661. } else if ( ( tagLength + 1 == (sizeof(rgIsHidden)/sizeof(WCHAR)) &&
  662. _wcsicmp(startTag, rgIsHidden) == 0 ) ) {
  663. nextCreateNodeAttribute = CreateNode_isHidden;
  664. } else if ( ( tagLength + 1 == (sizeof(rgIsCollection)/sizeof(WCHAR)) &&
  665. _wcsicmp(startTag, rgIsCollection) == 0 ) ) {
  666. nextCreateNodeAttribute = CreateNode_isCollection;
  667. } else if ( ( tagLength + 1 == (sizeof(rgHref)/sizeof(WCHAR)) &&
  668. _wcsicmp(startTag, rgHref) == 0 ) ) {
  669. if (NodeFac->m_FoundEntry) {
  670. //
  671. // If NodeFac->m_FoundEntry is TRUE it means that one of
  672. // OpaqueLockToken or LockOwner strings is actually been
  673. // found. Even though we came here because we encountered
  674. // <a:href> we are not looking for a DisplayName. If we
  675. // come here and NodeFac->m_FoundEntry is FALSE, then we
  676. // have to look for the DisplayName.
  677. //
  678. // XmlDavDbgPrint(("%ld: CreateNode(href). NodeFac->m_CreateNodeAttribute = %d\n",
  679. // GetCurrentThreadId(), NodeFac->m_CreateNodeAttribute));
  680. break;
  681. }
  682. nextCreateNodeAttribute = CreateNode_DisplayName;
  683. } else if ( ( tagLength + 1 == (sizeof(rgStatus)/sizeof(WCHAR)) &&
  684. _wcsicmp(startTag, rgStatus) == 0 ) ) {
  685. nextCreateNodeAttribute = CreateNode_Status;
  686. } else if ( ( tagLength + 1 == (sizeof(rgWin32FileAttributes)/sizeof(WCHAR)) &&
  687. _wcsicmp(startTag, rgWin32FileAttributes) == 0 ) ) {
  688. nextCreateNodeAttribute = CreateNode_Win32FileAttributes;
  689. } else if ( ( tagLength + 1 == (sizeof(rgWin32CreationTime)/sizeof(WCHAR)) &&
  690. _wcsicmp(startTag, rgWin32CreationTime) == 0 ) ) {
  691. nextCreateNodeAttribute = CreateNode_Win32CreationTime;
  692. } else if ( ( tagLength + 1 == (sizeof(rgWin32LastAccessTime)/sizeof(WCHAR)) &&
  693. _wcsicmp(startTag, rgWin32LastAccessTime) == 0 ) ) {
  694. nextCreateNodeAttribute = CreateNode_Win32LastAccessTime;
  695. } else if ( ( tagLength + 1 == (sizeof(rgWin32LastModifiedTime)/sizeof(WCHAR)) &&
  696. _wcsicmp(startTag, rgWin32LastModifiedTime) == 0 ) ) {
  697. nextCreateNodeAttribute = CreateNode_Win32LastModifiedTime;
  698. } else if ( ( tagLength + 1 == (sizeof(rgAvailableSpace)/sizeof(WCHAR)) &&
  699. _wcsicmp(startTag, rgAvailableSpace) == 0 ) ) {
  700. nextCreateNodeAttribute = CreateNode_AvailableSpace;
  701. } else if ( ( tagLength + 1 == (sizeof(rgTotalSpace)/sizeof(WCHAR)) &&
  702. _wcsicmp(startTag, rgTotalSpace) == 0 ) ) {
  703. nextCreateNodeAttribute = CreateNode_TotalSpace;
  704. } else if ( ( tagLength + 1 == (sizeof(rgOwner)/sizeof(WCHAR)) &&
  705. _wcsicmp(startTag, rgOwner) == 0 ) ) {
  706. nextCreateNodeAttribute = CreateNode_Owner;
  707. } else if ( ( tagLength + 1 == (sizeof(rgTimeout)/sizeof(WCHAR)) &&
  708. _wcsicmp(startTag, rgTimeout) == 0 ) ) {
  709. nextCreateNodeAttribute = CreateNode_Timeout;
  710. } else if ( ( tagLength + 1 == (sizeof(rgLockToken)/sizeof(WCHAR)) &&
  711. _wcsicmp(startTag, rgLockToken) == 0 ) ) {
  712. nextCreateNodeAttribute = CreateNode_LockToken;
  713. } else {
  714. //
  715. // One CreateNode call can contain only one XML_ELEMENT information
  716. // and since this element is none of our concerned elements, so
  717. // we pass this element information downward.
  718. //
  719. fPassElement = TRUE;
  720. }
  721. if(fPassElement == FALSE) {
  722. //
  723. // Control comes here only if we have found an element of our
  724. // interest.
  725. //
  726. NodeFac->m_FoundEntry = TRUE;
  727. //
  728. // If we have to create a new DavFileAttribute entry, do it now.
  729. // This entry should be added to the list of this CDavNodeFactory
  730. // structure.
  731. //
  732. if (NodeFac->m_CreateNewEntry) {
  733. void *DFA = NULL;
  734. DavOverrideAttributes(NodeFac->m_DFAToUse);
  735. DFA = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, sizeof(DAV_FILE_ATTRIBUTES) );
  736. if (DFA == NULL) {
  737. ULONG WStatus;
  738. WStatus = GetLastError();
  739. XmlDavDbgPrint(("%ld: ERROR: CreateNode. LocalAlloc. Error Val = %d\n",
  740. GetCurrentThreadId(), WStatus));
  741. hResult = CO_E_ERRORINAPP;
  742. goto EXIT_THE_FUNCTION;
  743. }
  744. DavFileAttributes = (PDAV_FILE_ATTRIBUTES)DFA;
  745. //
  746. // m_FileIndex = No of entries for which "<a:response...>" is found
  747. // in response and memory is allocated for its DAV_FILE_ATTRIBUTES
  748. // structure. At this point: a new entry is allocated after
  749. // "<a:response...>" is detected in XML response, so increase
  750. // m_FileIndex by 1.
  751. //
  752. NodeFac->m_FileIndex++;
  753. //
  754. // DavFileAttributes->FileIndex starts from 0, so subtract 1 from total
  755. // number of entries allocated and detected in XML response to get
  756. // FileIndex of that entry.
  757. //
  758. DavFileAttributes->FileIndex = NodeFac->m_FileIndex - 1;
  759. InsertTailList( &(NodeFac->m_DavFileAttributes->NextEntry),
  760. &(DavFileAttributes->NextEntry) );
  761. NodeFac->m_DFAToUse = DavFileAttributes;
  762. NodeFac->m_CreateNewEntry = FALSE;
  763. }
  764. NodeFac->m_CreateNodeAttribute = nextCreateNodeAttribute;
  765. // XmlDavDbgPrint(("%ld: CreateNode. NodeFac->m_CreateNodeAttribute = %d\n",
  766. // GetCurrentThreadId(), nextCreateNodeAttribute));
  767. break; // Out of Loop
  768. } // fPassElement
  769. }
  770. if (NodeFac->m_FoundEntry) {
  771. if (NodeFac->m_CreateNodeAttribute != CreateNode_DisplayName) {
  772. //
  773. // The extra 1 is for the final \0 char.
  774. //
  775. LengthInChars = NodeInfo->ulLen + 1;
  776. //XmlDavDbgPrint(("%ld: CreateNode. Element=%d DataLen=%d Data=%ws\n",
  777. // GetCurrentThreadId(), NodeFac->m_CreateNodeAttribute,
  778. // NodeInfo->ulLen, NodeInfo->pwcText));
  779. //
  780. // Allocate memory for copying the parsed XML response element.
  781. //
  782. Temp = (PWCHAR) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
  783. (LengthInChars) * sizeof(WCHAR) );
  784. if (Temp == NULL) {
  785. DWORD WStatus = GetLastError();
  786. XmlDavDbgPrint(("%ld: ERROR: CreateNode. LocalAlloc failed.GLE=%u\n",
  787. GetCurrentThreadId(), WStatus));
  788. hResult = CO_E_ERRORINAPP;
  789. goto EXIT_THE_FUNCTION;
  790. }
  791. //
  792. // Copy the element.
  793. //
  794. wcsncpy(Temp, NodeInfo->pwcText, NodeInfo->ulLen);
  795. Temp[LengthInChars-1]=L'\0';
  796. // XmlDavDbgPrint(("%ld: CreateNode. Temp = %ws, LengthInChars=%d\n",
  797. // GetCurrentThreadId(), Temp, LengthInChars ));
  798. switch (NodeFac->m_CreateNodeAttribute) {
  799. case CreateNode_isHidden: {
  800. NodeFac->m_DFAToUse->isHidden = (BOOL)_wtoi(Temp);
  801. }
  802. break;
  803. case CreateNode_isCollection: {
  804. NodeFac->m_DFAToUse->isCollection = (BOOL)_wtoi(Temp);
  805. }
  806. break;
  807. case CreateNode_ContentLength: {
  808. *((LONGLONG *)&NodeFac->m_DFAToUse->FileSize) = _wtoi64(Temp);
  809. }
  810. break;
  811. case CreateNode_CreationTime: {
  812. ULONG WStatus;
  813. WStatus = DavInternetTimeToFileTime(Temp, (FILETIME *)&NodeFac->m_DFAToUse->DavCreationTime);
  814. if (WStatus != ERROR_SUCCESS) {
  815. XmlDavDbgPrint(("%ld: ERROR: CreateNode. DavInternetTimeToFileTime.\n",
  816. GetCurrentThreadId()));
  817. hResult = CO_E_ERRORINAPP;
  818. goto EXIT_THE_FUNCTION;
  819. }
  820. }
  821. break;
  822. case CreateNode_LastModifiedTime: {
  823. DWORD dwError;
  824. dwError = DavInternetTimeToFileTime(Temp, (FILETIME *)&NodeFac->m_DFAToUse->DavLastModifiedTime);
  825. if (dwError != ERROR_SUCCESS) {
  826. XmlDavDbgPrint(("%ld: ERROR: CreateNode. DavInternetTimeToFileTime\n",
  827. GetCurrentThreadId()));
  828. hResult = CO_E_ERRORINAPP;
  829. goto EXIT_THE_FUNCTION;
  830. }
  831. }
  832. break;
  833. case CreateNode_Status: {
  834. NodeFac->m_DFAToUse->Status = Temp;
  835. //
  836. // Don't free Temp now. This allocation will be freed
  837. // when this DavFileAttribute entry gets finalized.
  838. //
  839. freeTemp = FALSE;
  840. //
  841. // If the status is not 200 then this node is invalid. The Temp
  842. // is of the form "HTTP/1.1 200 OK".
  843. //
  844. if ( wcslen(Temp) >= 12 ) {
  845. if ( Temp[9] != L'2' || Temp[10] != L'0' || Temp[11] != L'0' ) {
  846. NodeFac->m_DFAToUse->InvalidNode = TRUE;
  847. } else{
  848. NodeFac->m_DFAToUse->InvalidNode = FALSE;
  849. }
  850. } else {
  851. NodeFac->m_DFAToUse->InvalidNode = TRUE;
  852. }
  853. }
  854. break;
  855. case CreateNode_LockToken: {
  856. NodeFac->m_DFAToUse->OpaqueLockToken = Temp;
  857. //
  858. // Don't free Temp now. This allocation will be freed
  859. // when this DavFileAttribute entry gets finalized.
  860. //
  861. freeTemp = FALSE;
  862. // XmlDavDbgPrint(("%ld: CreateNode. OpaqueLockToken = %ws\n",
  863. // GetCurrentThreadId(), Temp));
  864. }
  865. break;
  866. case CreateNode_Owner: {
  867. NodeFac->m_DFAToUse->LockOwner = Temp;
  868. //
  869. // Don't free Temp now. This allocation will be freed
  870. // when this DavFileAttribute entry gets finalized.
  871. //
  872. freeTemp = FALSE;
  873. // XmlDavDbgPrint(("%ld: CreateNode. LockOwner = %ws\n",
  874. // GetCurrentThreadId(), Temp));
  875. }
  876. break;
  877. case CreateNode_Timeout: {
  878. //
  879. // The timeout XML element in the repsonse to a LOCK
  880. // request has the following format:
  881. // <d:timeout>Second-604800</d:timeout>
  882. // ^
  883. // |
  884. // Temp[7]
  885. // The timeout value in this example is 604800.
  886. //
  887. NodeFac->m_DFAToUse->LockTimeout = _wtoi(&Temp[7]);
  888. // XmlDavDbgPrint(("%ld: CreateNode. LockTimeout = %d\n",
  889. // GetCurrentThreadId(), NodeFac->m_DFAToUse->LockTimeout));
  890. }
  891. break;
  892. case CreateNode_Win32FileAttributes : {
  893. DWORD dwFileAttributes = 0;
  894. swscanf(Temp, L"%x", &(dwFileAttributes));
  895. NodeFac->m_DFAToUse->dwFileAttributes |= dwFileAttributes;
  896. }
  897. break;
  898. case CreateNode_Win32CreationTime : {
  899. DWORD dwError;
  900. dwError = DavInternetTimeToFileTime(Temp, (FILETIME *)&NodeFac->m_DFAToUse->CreationTime);
  901. if (dwError != ERROR_SUCCESS) {
  902. XmlDavDbgPrint(("%ld: ERROR: CreateNode. DavInternetTimeToFileTime\n",
  903. GetCurrentThreadId()));
  904. hResult = CO_E_ERRORINAPP;
  905. goto EXIT_THE_FUNCTION;
  906. }
  907. }
  908. break;
  909. case CreateNode_Win32LastAccessTime : {
  910. DWORD dwError;
  911. dwError = DavInternetTimeToFileTime(Temp, (FILETIME *)&NodeFac->m_DFAToUse->LastAccessTime);
  912. if (dwError != ERROR_SUCCESS) {
  913. XmlDavDbgPrint(("%ld: ERROR: CreateNode. DavInternetTimeToFileTime\n",
  914. GetCurrentThreadId()));
  915. hResult = CO_E_ERRORINAPP;
  916. goto EXIT_THE_FUNCTION;
  917. }
  918. }
  919. break;
  920. case CreateNode_Win32LastModifiedTime : {
  921. DWORD dwError;
  922. dwError = DavInternetTimeToFileTime(Temp, (FILETIME *)&NodeFac->m_DFAToUse->LastModifiedTime);
  923. if (dwError != ERROR_SUCCESS) {
  924. XmlDavDbgPrint(("%ld: ERROR: CreateNode. DavInternetTimeToFileTime\n",
  925. GetCurrentThreadId()));
  926. hResult = CO_E_ERRORINAPP;
  927. goto EXIT_THE_FUNCTION;
  928. }
  929. }
  930. break;
  931. case CreateNode_ResourceType : {
  932. //
  933. // Since data for tag=":resourceType" comes in form
  934. // <d:resourcetype><lp0:collection/></d:resourcetype>, so
  935. // here Temp[] = "lp0:collection". Since current NodeInfo is for
  936. // tag=<lp0:collection/>, so use namespace-prefix length i.e.
  937. // tagOffset to get Actual-tag(":collection").
  938. //
  939. //XmlDavDbgPrint(("%ld:CreateNode. In resourceType. tagLength=%d, Temp=%ws.\n",
  940. // GetCurrentThreadId(), tagLength, Temp));
  941. if((wcslen(L":collection") <= tagLength) &&
  942. (_wcsnicmp(&(Temp[tagOffset]),L":collection",
  943. wcslen(L":collection")) == 0) )
  944. NodeFac->m_DFAToUse->isCollection = TRUE;
  945. }
  946. break;
  947. case CreateNode_AvailableSpace : {
  948. NodeFac->m_DFAToUse->fReportsAvailableSpace = TRUE;
  949. *((LONGLONG *)&NodeFac->m_DFAToUse->AvailableSpace) = _wtoi64(Temp);
  950. }
  951. break;
  952. case CreateNode_TotalSpace : {
  953. *((LONGLONG *)&NodeFac->m_DFAToUse->TotalSpace) = _wtoi64(Temp);
  954. }
  955. break;
  956. default: {
  957. XmlDavDbgPrint(("%ld: ERROR: CreateNode. CreateAttribute = %d\n",
  958. GetCurrentThreadId(), NodeFac->m_CreateNodeAttribute));
  959. }
  960. break; // Out of switch
  961. };
  962. //
  963. // The information in this CreateNode is extracted.
  964. // So we can quit this function now. After this, EndChildren should be
  965. // called. Since we do not expect more PCDATA to come for current ELEMENT
  966. // set NodeFac->m_FoundEntry to FALSE - so that our current information
  967. // in NodeInfo->m_DFAToUse is not overwritten by following calls of
  968. // CreateNode for same XML_ELEMENT.
  969. //
  970. NodeFac->m_FoundEntry = FALSE;
  971. break; // Out of Loop
  972. } else {
  973. //
  974. // NodeFac->m_CreateNodeAttribute = CreateNode_DisplayName. Since
  975. // DisplayName can span many consecutive CreateNode calls, each call
  976. // bring part of display name. So here we collect the parts of
  977. // displayname coming in each CreateNode call and join them to form
  978. // complete name.
  979. // After all parts are called, this EndChildren will be called. There
  980. // we process the name to get the actual display name.
  981. //
  982. PDAV_FILE_ATTRIBUTES CurrentDFA = NodeFac->m_DFAToUse;
  983. BOOL fReAlloc = FALSE;
  984. DWORD TotalNameLength = NodeInfo->ulLen + 1; // 1 is for ending NULL=L'\0'.
  985. PWCHAR newFileName = NULL;
  986. BOOL fCopyInEnd = FALSE;
  987. DWORD AllocLength = 0;
  988. // XmlDavDbgPrint(("%ld: CreateNode. InDisplayName FileNameLength=%d FileName=%ws\n",
  989. // GetCurrentThreadId(), CurrentDFA->FileNameLength,
  990. // CurrentDFA->FileName?CurrentDFA->FileName : L"NULL"));
  991. if (NodeInfo->ulLen == 0) {
  992. XmlDavDbgPrint(("%ld: ERROR: CreateNode. Displayname value is NULL, NodeInfo->ulLen = 0\n",
  993. GetCurrentThreadId()));
  994. hResult = CO_E_ERRORINAPP;
  995. goto EXIT_THE_FUNCTION;
  996. }
  997. //
  998. // If currentDFA has FileName = NULL, then this CreateNode call brings
  999. // first part of DisplayName. Allocate memory for holding this part.
  1000. //
  1001. // If CurrentDFA->FileName != NULL, then current CreateNode call has
  1002. // next-part of the displayname. Check if the buffer allocated for
  1003. // old-parts is enough to contain new part also. If it is, then
  1004. // copy new part in the end else allocate new buffer. Copy old-parts
  1005. // to new buffer and then copy new-part in the end of this buffer.
  1006. //
  1007. if (CurrentDFA->FileName != NULL) {
  1008. TotalNameLength += CurrentDFA->FileNameLength;
  1009. //XmlDavDbgPrint(("%ld: CreateNode. ReqLen=%d PresentLen=%d\n",
  1010. // GetCurrentThreadId(), TotalNameLength,
  1011. // LocalSize((HLOCAL)CurrentDFA->FileName)/sizeof(WCHAR)));
  1012. if(TotalNameLength > LocalSize((HLOCAL)CurrentDFA->FileName)/sizeof(WCHAR)) {
  1013. //
  1014. // Buffer allocated for old-parts is not long enough to
  1015. // contain new part also. Have to Reallocate new buffer.
  1016. //
  1017. fReAlloc = TRUE;
  1018. } else {
  1019. //
  1020. // Buffer allocated for old-parts is long enough to
  1021. // contain new part also. Copy new-part in the end.
  1022. //
  1023. fCopyInEnd = TRUE;
  1024. fReAlloc = FALSE;
  1025. }
  1026. } else {
  1027. fReAlloc = FALSE;
  1028. }
  1029. if (fReAlloc == TRUE) {
  1030. //
  1031. // Allocate maximum of {256 , TotalNameLength}. We want to
  1032. // allocate more first time to save possibility of re-allocation.
  1033. //
  1034. AllocLength = TotalNameLength > 256 ? TotalNameLength : 256 ;
  1035. //XmlDavDbgPrint(("%ld: CreateNode. AllocLen=%d\n",
  1036. // GetCurrentThreadId(), AllocLength));
  1037. newFileName = (PWCHAR)LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
  1038. AllocLength*sizeof(WCHAR));
  1039. if(newFileName == NULL) {
  1040. DWORD WStatus = GetLastError();
  1041. XmlDavDbgPrint(("%ld: ERROR: CreateNode. ReAllocLen = %d. LocalAlloc failed. GLE=%u\n",
  1042. GetCurrentThreadId(), AllocLength, WStatus));
  1043. hResult = CO_E_ERRORINAPP;
  1044. goto EXIT_THE_FUNCTION;
  1045. }
  1046. //
  1047. // Copy the old-parts in the new buffer.
  1048. //
  1049. wcsncpy(newFileName,CurrentDFA->FileName, CurrentDFA->FileNameLength);
  1050. //
  1051. // Free buffer allocated for old-parts and point it to new
  1052. // buffer allocated here.
  1053. //
  1054. if(CurrentDFA->FileName) {
  1055. LocalFree((HLOCAL)CurrentDFA->FileName);
  1056. CurrentDFA->FileName = NULL;
  1057. }
  1058. CurrentDFA->FileName = newFileName;
  1059. fReAlloc = FALSE;
  1060. //
  1061. // New buffer is allocated with enough length to contain old-parts
  1062. // with new part. old-parts are copied to the buffer, copy new
  1063. // part in the end.
  1064. //
  1065. fCopyInEnd = TRUE;
  1066. }
  1067. if (fCopyInEnd == FALSE) {
  1068. //
  1069. // Allocate maximum of {128 , TotalNameLength}. We want to
  1070. // allocate more first time to save possibility of re-allocation.
  1071. //
  1072. AllocLength = TotalNameLength > 128 ? TotalNameLength : 128;
  1073. //XmlDavDbgPrint(("%ld: CreateNode. AllocLen=%d\n",
  1074. // GetCurrentThreadId(), AllocLength));
  1075. newFileName = (PWCHAR)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
  1076. AllocLength*sizeof(WCHAR));
  1077. if(newFileName == NULL) {
  1078. DWORD WStatus = GetLastError();
  1079. XmlDavDbgPrint(("%ld: ERROR: CreateNode. AllocLen = %d LocalAlloc failed. GLE=%u\n",
  1080. GetCurrentThreadId(), AllocLength, WStatus));
  1081. hResult = CO_E_ERRORINAPP;
  1082. goto EXIT_THE_FUNCTION;
  1083. }
  1084. //
  1085. // Copy the element.
  1086. //
  1087. wcsncpy(newFileName, NodeInfo->pwcText, NodeInfo->ulLen);
  1088. newFileName[TotalNameLength - 1] = L'\0';
  1089. CurrentDFA->FileName = newFileName;
  1090. CurrentDFA->FileNameLength = NodeInfo->ulLen;
  1091. }
  1092. if (fCopyInEnd == TRUE) {
  1093. //
  1094. // Copy the element in the end of the already allocated buffer.
  1095. //
  1096. wcsncpy(&(CurrentDFA->FileName[CurrentDFA->FileNameLength]),
  1097. NodeInfo->pwcText, NodeInfo->ulLen);
  1098. CurrentDFA->FileName[TotalNameLength - 1] = L'\0';
  1099. CurrentDFA->FileNameLength = TotalNameLength - 1;
  1100. fCopyInEnd = FALSE;
  1101. }
  1102. //
  1103. // We have updated the DisplayName data in current DFA. Now following
  1104. // calls of CreateNode may contain more data for this field and same
  1105. // XML_ELEMENT.
  1106. // This will continue until EndChildren call is made - where
  1107. // data will be processed to generate filename and NodeFac->m_FoundEntry
  1108. // will be set FALSE.
  1109. // so we quit here WITHOUT setting NodeFac->m_FoundEntry to FALSE.
  1110. //
  1111. //XmlDavDbgPrint(("%ld. CreateNode. FileName=%ws, FileNameLength=%d\n",
  1112. // GetCurrentThreadId(), CurrentDFA->FileName,
  1113. // CurrentDFA->FileNameLength));
  1114. break; // Out of Loop
  1115. }
  1116. }
  1117. } // end of for loop.
  1118. EXIT_THE_FUNCTION:
  1119. // XmlDavDbgPrint(("%ld: CreateNode. Leaving!!!\n", GetCurrentThreadId()));
  1120. if (Temp && freeTemp) {
  1121. LocalFree(Temp);
  1122. Temp = NULL;
  1123. }
  1124. return hResult;
  1125. }
  1126. ULONG
  1127. DavPushData(
  1128. IN PCHAR DataBuff,
  1129. IN OUT PVOID *Context1,
  1130. IN OUT PVOID *Context2,
  1131. IN ULONG NumOfBytes,
  1132. IN BOOL isLast
  1133. )
  1134. /*++
  1135. Routine Description:
  1136. This routine pushes the XML (response) data received from the server to the
  1137. parser.
  1138. Arguments:
  1139. DataBuff - The data to be sent to the parser.
  1140. Context1 - The address of the CDavNodefactory object. This gets created
  1141. during the first call to this function.
  1142. Context2 - The address of the IXMLParser. This gets created during the
  1143. first call to this function.
  1144. NumOfBytes - Number of bytes being sent.
  1145. isLast - Is this the last buffer being sent.
  1146. Return Value:
  1147. ERROR_SUCCESS or ERROR_INVALID_PARAMETER.
  1148. --*/
  1149. {
  1150. ULONG WStatus = ERROR_SUCCESS;
  1151. HRESULT hResult;
  1152. CDavNodeFactory *NodeFac = (CDavNodeFactory *)*Context1;
  1153. IXMLParser *Xp = (IXMLParser *)*Context2;
  1154. //
  1155. // If this is the first call to push data, we need to associate a
  1156. // CDavNodeFactory and an XMLParser with it.
  1157. //
  1158. if (NodeFac == NULL) {
  1159. NodeFac = new CDavNodeFactory();
  1160. if (NodeFac == NULL) {
  1161. XmlDavDbgPrint(("%ld: ERROR: DavPushData/new()\n", GetCurrentThreadId()));
  1162. WStatus = ERROR_NO_SYSTEM_RESOURCES;
  1163. goto EXIT_THE_FUNCTION;
  1164. }
  1165. NodeFac->AddRef();
  1166. *Context1 = (PVOID)NodeFac;
  1167. hResult = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  1168. if (!SUCCEEDED(hResult)) {
  1169. XmlDavDbgPrint(("%ld: ERROR: DavPushData/CoInitializeEx: "
  1170. "hResult = %08lx\n",
  1171. GetCurrentThreadId(), hResult));
  1172. goto EXIT_THE_FUNCTION;
  1173. }
  1174. //
  1175. // Call CoCreateInstance again. We should succeed this time.
  1176. //
  1177. hResult = CoCreateInstance(CLSID_XMLParser,
  1178. NULL,
  1179. CLSCTX_INPROC_SERVER,
  1180. IID_IXMLParser,
  1181. (void **)&Xp);
  1182. if (!SUCCEEDED(hResult)) {
  1183. XmlDavDbgPrint(("%ld: ERROR: DavPushData/CoCreateInstance: %08lx\n",
  1184. GetCurrentThreadId(), hResult));
  1185. Xp = NULL;
  1186. goto EXIT_THE_FUNCTION;
  1187. }
  1188. *Context2 = (PVOID)Xp;
  1189. hResult = Xp->SetFactory(NodeFac);
  1190. if (!SUCCEEDED(hResult)) {
  1191. XmlDavDbgPrint(("%ld: ERROR: DavPushData: SetFactory.\n", GetCurrentThreadId()));
  1192. goto EXIT_THE_FUNCTION;
  1193. }
  1194. }
  1195. hResult = Xp->PushData(DataBuff, NumOfBytes, isLast);
  1196. if (!SUCCEEDED(hResult)) {
  1197. XmlDavDbgPrint(("%ld: ERROR: DavPushData: PushData.\n", GetCurrentThreadId()));
  1198. goto EXIT_THE_FUNCTION;
  1199. }
  1200. return WStatus;
  1201. EXIT_THE_FUNCTION:
  1202. //
  1203. // Ok, we failed.
  1204. //
  1205. DavCloseContext(*Context1, *Context2);
  1206. //
  1207. // If the WStatus was not sent, then set it to ERROR_INVALID_PARAMETER.
  1208. //
  1209. if (WStatus == ERROR_SUCCESS) {
  1210. WStatus = ERROR_INVALID_PARAMETER;
  1211. }
  1212. return WStatus;
  1213. }
  1214. ULONG
  1215. DavParseData(
  1216. IN OUT PDAV_FILE_ATTRIBUTES DavFileAttributes,
  1217. IN PVOID Context1,
  1218. IN PVOID Context2,
  1219. OUT ULONG *NumOfFileEntries
  1220. )
  1221. /*++
  1222. Routine Description:
  1223. This routine calls the Run function (of the IXMLParser) to parse the XML
  1224. data that has been sent to the parser.
  1225. Arguments:
  1226. DavFileAttributes - The structre wherein the parsed file attributes will
  1227. be stored.
  1228. Context1 - The address of the CDavNodeFactory API.
  1229. Context2 - The address of the IXMLParser interface.
  1230. NumOfFileEntries - Number of dav file attribute entries created during
  1231. parsing.
  1232. Return Value:
  1233. ERROR_SUCCESS or ERROR_INVALID_PARAMETER.
  1234. --*/
  1235. {
  1236. ULONG WStatus = ERROR_SUCCESS;
  1237. CDavNodeFactory *NodeFac = (CDavNodeFactory *)Context1;
  1238. IXMLParser *Xp = (IXMLParser *)Context2;
  1239. HRESULT hResult;
  1240. //
  1241. // We enclose the parsing code in a try/except just in case some random
  1242. // server response completely screws us. In such a case, we catch the
  1243. // exception here and return ERROR_INVALID_PARAMETER to the caller. This
  1244. // is also here to catch the STACK_OVERFLOW exception that can be thrown
  1245. // under low memory conditions.
  1246. //
  1247. __try {
  1248. NodeFac->m_DavFileAttributes = DavFileAttributes;
  1249. NodeFac->m_DFAToUse = DavFileAttributes;
  1250. //
  1251. // m_FileIndex = No of entries for which "<a:response...>" is found in
  1252. // XML response and memory is allocated for its DAV_FILE_ATTRIBUTES
  1253. // structure. Right now - first entry is allocated by caller of this
  1254. // function but no "<a:response...>" is detected yet in response - so
  1255. // NodeInfo->m_FileIndex = 0.
  1256. //
  1257. DavFileAttributes->FileIndex = NodeFac->m_FileIndex = 0;
  1258. //
  1259. // Call Run to parse the XML data sent.
  1260. //
  1261. hResult = Xp->Run(-1);
  1262. if (!SUCCEEDED(hResult)) {
  1263. XmlDavDbgPrint(("%ld: ERROR: DavParseData/Run: hResult = %08lx\n",
  1264. GetCurrentThreadId(), hResult));
  1265. goto EXIT_THE_FUNCTION;
  1266. }
  1267. //
  1268. // We need to call this function for the last node that got created. This
  1269. // is done becuase the DavOverrideAttributes in the CreateNode function
  1270. // above does not cover the last node.
  1271. //
  1272. DavOverrideAttributes(NodeFac->m_DFAToUse);
  1273. *NumOfFileEntries = NodeFac->m_FileIndex;
  1274. } __except (1) {
  1275. XmlDavDbgPrint(("%ld: ERROR: DavParseData: ExceptionCode = %d\n",
  1276. GetCurrentThreadId(), GetExceptionCode()));
  1277. goto EXIT_THE_FUNCTION;
  1278. }
  1279. return WStatus;
  1280. EXIT_THE_FUNCTION:
  1281. DavCloseContext(Context1, Context2);
  1282. WStatus = ERROR_INVALID_PARAMETER;
  1283. return WStatus;
  1284. }
  1285. ULONG
  1286. DavParseDataEx(
  1287. IN OUT PDAV_FILE_ATTRIBUTES DavFileAttributes,
  1288. IN PVOID Context1,
  1289. IN PVOID Context2,
  1290. OUT ULONG *NumOfFileEntries,
  1291. OUT DAV_FILE_ATTRIBUTES ** pCollectionDFA
  1292. )
  1293. /*++
  1294. Routine Description:
  1295. This routine calls the Run function (of the IXMLParser) to parse the XML
  1296. data that has been sent to the parser. In addition to calling DavParseData(...)
  1297. it returns the pointer to parent DAV collection resource being returned in XML response.
  1298. Arguments:
  1299. DavFileAttributes - The structre wherein the parsed file attributes will
  1300. be stored.
  1301. Context1 - The address of the CDavNodeFactory API.
  1302. Context2 - The address of the IXMLParser interface.
  1303. NumOfFileEntries - Number of dav file attribute entries created during
  1304. parsing.
  1305. pCollectionDFA - This pointer will set to DavFileAttribute that corresponds to
  1306. the DAV resource which has smallest Full-DisplayName (that comes in
  1307. "<a:href>Full-DisplayName</a:href>") in the response. If
  1308. XML response contains the properties of the parent DAV collection then
  1309. its entry should be the entry with smallest Full-DisplayName.
  1310. Return Value:
  1311. ERROR_SUCCESS or ERROR_INVALID_PARAMETER.
  1312. --*/
  1313. {
  1314. ULONG WStatus = ERROR_SUCCESS;
  1315. CDavNodeFactory *NodeFac = (CDavNodeFactory *)Context1;
  1316. if (pCollectionDFA != NULL) {
  1317. *pCollectionDFA = NULL;
  1318. }
  1319. //
  1320. // Call DavParseData(...) to parse the XML data sent.
  1321. //
  1322. WStatus = DavParseData(DavFileAttributes, Context1, Context2, NumOfFileEntries);
  1323. if (WStatus != ERROR_SUCCESS) {
  1324. XmlDavDbgPrint(("%ld: ERROR: DavParseDataEx/Run: WStatus = %08lx\n",
  1325. GetCurrentThreadId(), WStatus));
  1326. goto EXIT_THE_FUNCTION;
  1327. }
  1328. //
  1329. // Store location of DAV collection DFA in pCollectionDFA.
  1330. //
  1331. if (pCollectionDFA != NULL) {
  1332. *pCollectionDFA = NodeFac->m_CollectionDFA;
  1333. }
  1334. return WStatus;
  1335. EXIT_THE_FUNCTION:
  1336. return WStatus;
  1337. }
  1338. VOID
  1339. DavCloseContext(
  1340. PVOID Context1,
  1341. PVOID Context2
  1342. )
  1343. /*++
  1344. Routine Description:
  1345. This routine closes the XML parser and the CDavNodeFactory object.
  1346. Arguments:
  1347. Context1 - The address of the CDavNodeFactory API.
  1348. Context2 - The address of the IXMLParser interface.
  1349. Return Value:
  1350. none.
  1351. --*/
  1352. {
  1353. CDavNodeFactory *NodeFac = (CDavNodeFactory *)Context1;
  1354. IXMLParser *Xp = (IXMLParser *)Context2;
  1355. if (NodeFac != NULL) {
  1356. NodeFac->Release();
  1357. }
  1358. if (Xp != NULL) {
  1359. Xp->Release();
  1360. }
  1361. //
  1362. // This is to balance the CoInitializeEx call in the DavPushData function.
  1363. //
  1364. CoUninitialize();
  1365. return;
  1366. }
  1367. VOID
  1368. DavFinalizeFileAttributesList(
  1369. PDAV_FILE_ATTRIBUTES DavFileAttributes,
  1370. BOOL fFreeHeadDFA
  1371. )
  1372. /*++
  1373. Routine Description:
  1374. This routine finalizes (frees) a DavFileAttributes list.
  1375. Arguments:
  1376. DavFileAttributes - The DavFileAttributes list to be finalized.
  1377. Return Value:
  1378. none.
  1379. --*/
  1380. {
  1381. PDAV_FILE_ATTRIBUTES TempDFA;
  1382. PLIST_ENTRY listEntry, backEntry;
  1383. //
  1384. // If there is nothing to finalize then we return.
  1385. //
  1386. if (DavFileAttributes == NULL) {
  1387. return;
  1388. }
  1389. TempDFA = DavFileAttributes;
  1390. listEntry = TempDFA->NextEntry.Flink;
  1391. //
  1392. // Travel the list and free the resources allocated.
  1393. //
  1394. while ((listEntry != NULL) && (listEntry != &(DavFileAttributes->NextEntry)) ) {
  1395. TempDFA = CONTAINING_RECORD(listEntry,
  1396. DAV_FILE_ATTRIBUTES,
  1397. NextEntry);
  1398. backEntry = listEntry;
  1399. listEntry = listEntry->Flink;
  1400. RemoveEntryList(backEntry);
  1401. //
  1402. // Free the Status string that was allocated while parsing.
  1403. //
  1404. if (TempDFA->Status) {
  1405. LocalFree((HLOCAL)TempDFA->Status);
  1406. TempDFA->Status = NULL;
  1407. }
  1408. //
  1409. // Free the filename that was allocated while parsing.
  1410. //
  1411. if (TempDFA->FileName) {
  1412. LocalFree((HLOCAL)TempDFA->FileName);
  1413. TempDFA->FileName = NULL;
  1414. }
  1415. //
  1416. // Free the LockOwner string that was allocated while parsing.
  1417. //
  1418. if (TempDFA->LockOwner) {
  1419. LocalFree((HLOCAL)TempDFA->LockOwner);
  1420. TempDFA->LockOwner = NULL;
  1421. }
  1422. //
  1423. // Free the OpaqueLockToken string that was allocated while parsing.
  1424. //
  1425. if (TempDFA->OpaqueLockToken) {
  1426. LocalFree((HLOCAL)TempDFA->OpaqueLockToken);
  1427. TempDFA->OpaqueLockToken = NULL;
  1428. }
  1429. //
  1430. // Free the DavFileAttributes entry.
  1431. //
  1432. LocalFree((HLOCAL)TempDFA);
  1433. TempDFA = NULL;
  1434. }
  1435. //
  1436. // Need to free the first entry.
  1437. //
  1438. if (DavFileAttributes->Status) {
  1439. LocalFree((HLOCAL)DavFileAttributes->Status);
  1440. DavFileAttributes->Status = NULL;
  1441. }
  1442. if (DavFileAttributes->FileName) {
  1443. LocalFree((HLOCAL)DavFileAttributes->FileName);
  1444. DavFileAttributes->FileName = NULL;
  1445. }
  1446. if (DavFileAttributes->LockOwner) {
  1447. LocalFree((HLOCAL)DavFileAttributes->LockOwner);
  1448. DavFileAttributes->LockOwner = NULL;
  1449. }
  1450. if (DavFileAttributes->OpaqueLockToken) {
  1451. LocalFree((HLOCAL)DavFileAttributes->OpaqueLockToken);
  1452. DavFileAttributes->OpaqueLockToken = NULL;
  1453. }
  1454. if (fFreeHeadDFA == TRUE) {
  1455. LocalFree((HLOCAL)DavFileAttributes);
  1456. DavFileAttributes = NULL;
  1457. }
  1458. return;
  1459. }
  1460. DWORD
  1461. DavInternetTimeToFileTime(
  1462. PWCHAR lpTimeString,
  1463. FILETIME *lpft
  1464. )
  1465. {
  1466. SYSTEMTIME sSystemTime;
  1467. DWORD dwError = ERROR_SUCCESS;
  1468. if (!InternetTimeToSystemTimeW(lpTimeString, &sSystemTime, 0))
  1469. {
  1470. dwError = GetLastError();
  1471. if (dwError == ERROR_INVALID_PARAMETER)
  1472. {
  1473. dwError = DavParsedateTimetzTimeString(lpTimeString, (PLARGE_INTEGER)lpft);
  1474. }
  1475. }
  1476. else
  1477. {
  1478. SystemTimeToFileTime(&sSystemTime, lpft);
  1479. }
  1480. return dwError;
  1481. }
  1482. ULONG
  1483. DavParsedateTimetzTimeString(
  1484. PWCHAR TimeString,
  1485. LARGE_INTEGER *lpFileTime
  1486. )
  1487. /*++
  1488. Routine Description:
  1489. This routine parses a string in the dateTime.tz time format. It then sets
  1490. the last modified time attribute in the file attributes structure of the
  1491. node factory object.
  1492. Arguments:
  1493. TimeString - The string that needs to be parsed.
  1494. lpFileTime - Time to get
  1495. Return Value:
  1496. ERROR_SUCESS or the appropriate Win32 error code.
  1497. --*/
  1498. {
  1499. ULONG WStatus = ERROR_SUCCESS;
  1500. PWCHAR Head = NULL, Cp = NULL, Tail = NULL;
  1501. TIME_FIELDS TimeFields;
  1502. BOOL ReturnVal = FALSE;
  1503. DWORD TimeStrLen = 0;
  1504. WCHAR EndCharSet[]=L".+-zZ";
  1505. WCHAR OffsetCharSet[]=L"+-zZ";
  1506. WCHAR LastChar;
  1507. ZeroMemory(&TimeFields, sizeof(TIME_FIELDS));
  1508. //
  1509. // Head->1999-03-17T00:46:24.557Z
  1510. // ^
  1511. // |
  1512. // Tail
  1513. //
  1514. Head = TimeString;
  1515. Tail = (PWCHAR)(Head + wcslen(Head));
  1516. // XmlDavDbgPrint(("%ld: DavParsedateTimetzTimeString: TimeString = %ws.\n",
  1517. // GetCurrentThreadId(), TimeString));
  1518. //
  1519. // The string can be of the format "1999-03-17T00:46:24.557Z"
  1520. // The string can be of the format "1999-03-17T00:46:24Z"
  1521. // The string can be of the format "1999-03-17T00:46:24.557+12:02" - Ignored for now
  1522. // The string can be of the format "1999-03-17T00:46:24.557-12:02" - Ignored for now
  1523. // The string can be of the format "1999-03-17T00:46:24+12:02" - Ignored for now
  1524. // The string can be of the format "1999-03-17T00:46:24-12:02" - Ignored for now
  1525. //
  1526. //
  1527. // Head->1999-03-17T00:46:24.557Z
  1528. // ^
  1529. // |
  1530. // Cp
  1531. //
  1532. Cp = Head + 4;
  1533. //
  1534. // Head->"1999"03-17T00:46:24.557Z -- Head now points to the year.
  1535. // ^
  1536. // |
  1537. // Cp
  1538. //
  1539. if ((Cp > Tail) || (Cp[0] != L'-')) {
  1540. goto bailout;
  1541. }
  1542. LastChar = Cp[0];
  1543. *Cp = L'\0';
  1544. TimeFields.Year = (short)_wtoi(Head);
  1545. // XmlDavDbgPrint(("%ld: DavParsedateTimetzTimeString: Year = %d.\n",
  1546. // GetCurrentThreadId(), TimeFields.Year));
  1547. //
  1548. // Head->03-17T00:46:24.557Z
  1549. // ^
  1550. // |
  1551. // Cp
  1552. //
  1553. Cp++;
  1554. Head = Cp;
  1555. //
  1556. // Head->03-17T00:46:24.557Z
  1557. // ^
  1558. // |
  1559. // Cp
  1560. //
  1561. Cp = Head + 2;
  1562. //
  1563. // Head->"03"17T00:46:24.557Z -- Head now points to the month.
  1564. // ^
  1565. // |
  1566. // Cp
  1567. //
  1568. if ((Cp > Tail) || (Cp[0] != L'-')) {
  1569. goto bailout;
  1570. }
  1571. LastChar = Cp[0];
  1572. *Cp = L'\0';
  1573. TimeFields.Month = (short)_wtoi(Head);
  1574. // XmlDavDbgPrint(("%ld: DavParsedateTimetzTimeString: Month = %d.\n",
  1575. // GetCurrentThreadId(), TimeFields.Month));
  1576. //
  1577. // Head->17T00:46:24.557Z
  1578. // ^
  1579. // |
  1580. // Cp
  1581. //
  1582. Cp++;
  1583. Head = Cp;
  1584. //
  1585. // Head->17T00:46:24.557Z
  1586. // ^
  1587. // |
  1588. // Cp
  1589. //
  1590. Cp = Head + 2;
  1591. //
  1592. // Head->"17"00:46:24.557Z -- Head now points to the day.
  1593. // ^
  1594. // |
  1595. // Cp
  1596. //
  1597. if ((Cp > Tail) || (Cp[0] != L'T')) {
  1598. goto bailout;
  1599. }
  1600. LastChar = Cp[0];
  1601. *Cp = L'\0';
  1602. TimeFields.Day = (short)_wtoi(Head);
  1603. // XmlDavDbgPrint(("%ld: DavParsedateTimetzTimeString: Day = %d.\n",
  1604. // GetCurrentThreadId(), TimeFields.Day));
  1605. //
  1606. // Head->00:46:24.557Z
  1607. // ^
  1608. // |
  1609. // Cp
  1610. //
  1611. Cp++;
  1612. Head = Cp;
  1613. //
  1614. // Head->00:46:24.557Z
  1615. // ^
  1616. // |
  1617. // Cp
  1618. //
  1619. Cp = Head + 2;
  1620. //
  1621. // Head->"00"46:24.557Z -- Head now points to the hour.
  1622. // ^
  1623. // |
  1624. // Cp
  1625. //
  1626. if ((Cp > Tail) || (Cp[0] != L':')) {
  1627. goto bailout;
  1628. }
  1629. LastChar = Cp[0];
  1630. *Cp = L'\0';
  1631. TimeFields.Hour = (short)_wtoi(Head);
  1632. // XmlDavDbgPrint(("%ld: DavParsedateTimetzTimeString: Hour = %d.\n",
  1633. // GetCurrentThreadId(), TimeFields.Hour));
  1634. //
  1635. // Head->46:24.557Z
  1636. // ^
  1637. // |
  1638. // Cp
  1639. //
  1640. Cp++;
  1641. Head = Cp;
  1642. //
  1643. // Head->46:24.557Z
  1644. // ^
  1645. // |
  1646. // Cp
  1647. //
  1648. Cp = Head + 2;
  1649. //
  1650. // Head->"46"24.557Z -- Head now points to the minute.
  1651. // ^
  1652. // |
  1653. // Cp
  1654. //
  1655. if ((Cp > Tail) || (Cp[0] != L':')) {
  1656. goto bailout;
  1657. }
  1658. LastChar = Cp[0];
  1659. *Cp = L'\0';
  1660. TimeFields.Minute = (short)_wtoi(Head);
  1661. // XmlDavDbgPrint(("%ld: DavParsedateTimetzTimeString: Minute = %d.\n",
  1662. // GetCurrentThreadId(), TimeFields.Minute));
  1663. //
  1664. // Head->24.557Z
  1665. // ^
  1666. // |
  1667. // Cp
  1668. //
  1669. Cp++;
  1670. Head = Cp;
  1671. //
  1672. // Head->24.557Z
  1673. // ^
  1674. // |
  1675. // Cp
  1676. //
  1677. Cp = Head + 2;
  1678. //
  1679. // Head->"24"557Z -- Head now points to the second.
  1680. // ^
  1681. // |
  1682. // Cp = {.,z,Z,+,-}
  1683. //
  1684. if ((Cp > Tail) || (wcspbrk(Cp,EndCharSet) != Cp)) {
  1685. goto bailout;
  1686. }
  1687. LastChar = Cp[0];
  1688. *Cp = L'\0';
  1689. TimeFields.Second = (short)_wtoi(Head);
  1690. // XmlDavDbgPrint(("%ld: DavParsedateTimetzTimeString: Seconds = %d.\n",
  1691. // GetCurrentThreadId(), TimeFields.Second));
  1692. if(LastChar == L'.') {
  1693. //
  1694. // Head->557Z
  1695. // ^
  1696. // |
  1697. // Cp
  1698. //
  1699. Cp++;
  1700. Head = Cp;
  1701. while(Cp < Tail && Cp[0] >= L'0' && Cp[0] <= L'9')
  1702. Cp++;
  1703. if(Cp == Head || wcspbrk(Cp,OffsetCharSet) != Cp) {
  1704. goto bailout;
  1705. }
  1706. //
  1707. // Head->"557" -- Head now points to the Milliseconds.
  1708. // ^
  1709. // |
  1710. // Cp = {z,Z,+,-}
  1711. //
  1712. LastChar = Cp[0];
  1713. Cp[0] = L'\0';
  1714. TimeFields.Milliseconds = (short)_wtoi(Head);
  1715. // XmlDavDbgPrint(("%ld: DavParsedateTimetzTimeString: Milliseconds = %d.\n",
  1716. // GetCurrentThreadId(), TimeFields.Milliseconds));
  1717. }
  1718. //
  1719. // Head->"+DD:DD" or "-DD:DD" or "Z" or "z".
  1720. // ^
  1721. // |
  1722. // Cp = {z,Z,+,-}
  1723. //
  1724. if(LastChar == L'+' || LastChar == L'-') {
  1725. //
  1726. // Head->"+DD:DD" or "-DD:DD" -- Head now points to the Milliseconds.
  1727. // ^
  1728. // |
  1729. // Cp = {+,-}
  1730. //
  1731. // BUGBUG - Ignoring time zone adjustment settings for now
  1732. //
  1733. }
  1734. //
  1735. // We have set the time fields structure. Now its time to get the time
  1736. // value as a LARGE_INTEGER and store it in DavFileAttributes. The time
  1737. // we need to set could either be the creation time or the last modified
  1738. // time.
  1739. //
  1740. ReturnVal = RtlTimeFieldsToTime(&TimeFields, lpFileTime);
  1741. bailout:
  1742. if (!ReturnVal) {
  1743. XmlDavDbgPrint(("%ld: ERROR: DavParsedateTimetzTimeString/RtlTimeFieldsToTime.\n",
  1744. GetCurrentThreadId()));
  1745. WStatus = ERROR_INVALID_PARAMETER;
  1746. }
  1747. // XmlDavDbgPrint(("%ld: DavParsedateTimetzTimeString: LastModifiedTime = %d, %d.\n",
  1748. // GetCurrentThreadId(),
  1749. // DavFileAttributes->CreationTime.HighPart,
  1750. // DavFileAttributes->CreationTime.LowPart));
  1751. return WStatus;
  1752. }
  1753. #if 0
  1754. ULONG
  1755. DavParseRfc1123TimeString(
  1756. PWCHAR TimeString,
  1757. PDAV_FILE_ATTRIBUTES DavFileAttributes,
  1758. CREATE_NODE_ATTRIBUTES CreateNodeAttribute
  1759. )
  1760. /*++
  1761. Routine Description:
  1762. This routine parses a string in the RFC 1123 time format. It then sets the
  1763. last modified time attribute in the file attributes structure of the
  1764. node factory object.
  1765. Arguments:
  1766. TimeString - The string that needs to be parsed.
  1767. DavFileAttributes - The Dav File attributes structure which contains the
  1768. Time Value to be set.
  1769. CreateNodeAttribute - Could be either CreateNode_CreationTime_rfc1123 or
  1770. CreateNode_LastModifiedTime_rfc1123.
  1771. Return Value:
  1772. ERROR_SUCESS or the appropriate Win32 error code.
  1773. --*/
  1774. {
  1775. ULONG WStatus = ERROR_SUCCESS;
  1776. PWCHAR Head, Cp;
  1777. TIME_FIELDS TimeFields;
  1778. BOOL ReturnVal;
  1779. Head = TimeString;
  1780. // XmlDavDbgPrint(("%ld: DavParseRfc1123TimeString: TimeString = %ws.\n",
  1781. // GetCurrentThreadId(), TimeString));
  1782. //
  1783. // The string is of the format "Tue, 06 Apr 1999 00:10:40\nGMT"
  1784. //
  1785. //
  1786. // Head->Tue, 06 Apr 1999 00:10:40\nGMT
  1787. // ^
  1788. // |
  1789. // Cp
  1790. //
  1791. Cp = wcschr(Head, L',');
  1792. //
  1793. // Head->"Tue" 06 Apr 1999 00:10:40\nGMT -- Head points to weekday string.
  1794. // ^
  1795. // |
  1796. // Cp
  1797. //
  1798. *Cp = L'\0';
  1799. if ( _wcsicmp(Head, L"Sun") == 0 ) {
  1800. TimeFields.Weekday = 0;
  1801. } else if( _wcsicmp(Head, L"Mon") == 0 ) {
  1802. TimeFields.Weekday = 1;
  1803. } else if( _wcsicmp(Head, L"Tue") == 0 ) {
  1804. TimeFields.Weekday = 2;
  1805. } else if( _wcsicmp(Head, L"Wed") == 0 ) {
  1806. TimeFields.Weekday = 3;
  1807. } else if( _wcsicmp(Head, L"Thu") == 0 ) {
  1808. TimeFields.Weekday = 4;
  1809. } else if( _wcsicmp(Head, L"Fri") == 0 ) {
  1810. TimeFields.Weekday = 5;
  1811. } else if( _wcsicmp(Head, L"Sat") == 0 ) {
  1812. TimeFields.Weekday = 6;
  1813. } else {
  1814. XmlDavDbgPrint(("%ld: ERROR: DavParseRfc1123TimeString: WeekDay = %ws.\n", Head));
  1815. WStatus = ERROR_INVALID_PARAMETER;
  1816. return WStatus;
  1817. }
  1818. // XmlDavDbgPrint(("%ld: DavParseRfc1123TimeString: WeekDay = %d.\n",
  1819. // GetCurrentThreadId(), TimeFields.Weekday));
  1820. //
  1821. // Head->06 Apr 1999 00:10:40\nGMT
  1822. // ^
  1823. // |
  1824. // Cp
  1825. //
  1826. Cp++;
  1827. Cp++;
  1828. Head = Cp;
  1829. //
  1830. // Head->06 Apr 1999 00:10:40\nGMT
  1831. // ^
  1832. // |
  1833. // Cp
  1834. //
  1835. Cp = wcschr(Head, L' ');
  1836. //
  1837. // Head->"06"Apr 1999 00:10:40\nGMT -- Head points to Day string.
  1838. // ^
  1839. // |
  1840. // Cp
  1841. //
  1842. *Cp = L'\0';
  1843. TimeFields.Day = (short)_wtoi(Head);
  1844. // XmlDavDbgPrint(("%ld: DavParseRfc1123TimeString: Day = %d.\n",
  1845. // GetCurrentThreadId(), TimeFields.Day));
  1846. //
  1847. // Head->Apr 1999 00:10:40\nGMT
  1848. // ^
  1849. // |
  1850. // Cp
  1851. //
  1852. Cp++;
  1853. Head = Cp;
  1854. //
  1855. // Head->Apr 1999 00:10:40\nGMT
  1856. // ^
  1857. // |
  1858. // Cp
  1859. //
  1860. Cp = wcschr(Head, L' ');
  1861. //
  1862. // Head->"Apr"1999 00:10:40\nGMT -- Head now points ti the month string.
  1863. // ^
  1864. // |
  1865. // Cp
  1866. //
  1867. *Cp = L'\0';
  1868. if ( _wcsicmp(Head, L"Jan") == 0 ) {
  1869. TimeFields.Month = 1;
  1870. } else if( _wcsicmp(Head, L"Feb") == 0 ) {
  1871. TimeFields.Month = 2;
  1872. } else if( _wcsicmp(Head, L"Mar") == 0 ) {
  1873. TimeFields.Month = 3;
  1874. } else if( _wcsicmp(Head, L"Apr") == 0 ) {
  1875. TimeFields.Month = 4;
  1876. } else if( _wcsicmp(Head, L"May") == 0 ) {
  1877. TimeFields.Month = 5;
  1878. } else if( _wcsicmp(Head, L"Jun") == 0 ) {
  1879. TimeFields.Month = 6;
  1880. } else if( _wcsicmp(Head, L"Jul") == 0 ) {
  1881. TimeFields.Month = 7;
  1882. } else if( _wcsicmp(Head, L"Aug") == 0 ) {
  1883. TimeFields.Month = 8;
  1884. } else if( _wcsicmp(Head, L"Sep") == 0 ) {
  1885. TimeFields.Month = 9;
  1886. } else if( _wcsicmp(Head, L"Oct") == 0 ) {
  1887. TimeFields.Month = 10;
  1888. } else if( _wcsicmp(Head, L"Nov") == 0 ) {
  1889. TimeFields.Month = 11;
  1890. } else if( _wcsicmp(Head, L"Dec") == 0 ) {
  1891. TimeFields.Month = 12;
  1892. } else {
  1893. XmlDavDbgPrint(("%ld: ERROR: DavParseRfc1123TimeString: Month = %ws.\n", Head));
  1894. WStatus = ERROR_INVALID_PARAMETER;
  1895. return WStatus;
  1896. }
  1897. // XmlDavDbgPrint(("%ld: DavParseRfc1123TimeString: Month = %d.\n",
  1898. // GetCurrentThreadId(), TimeFields.Month));
  1899. //
  1900. // Head->1999 00:10:40\nGMT
  1901. // ^
  1902. // |
  1903. // Cp
  1904. //
  1905. Cp++;
  1906. Head = Cp;
  1907. //
  1908. // Head->1999 00:10:40\nGMT
  1909. // ^
  1910. // |
  1911. // Cp
  1912. //
  1913. Cp = wcschr(Head, L' ');
  1914. //
  1915. // Head->"1999"00:10:40\nGMT -- Head now points to the year string.
  1916. // ^
  1917. // |
  1918. // Cp
  1919. //
  1920. *Cp = L'\0';
  1921. TimeFields.Year = (short)_wtoi(Head);
  1922. // XmlDavDbgPrint(("%ld: DavParseRfc1123TimeString: Year = %d.\n",
  1923. // GetCurrentThreadId(), TimeFields.Year));
  1924. //
  1925. // Head->00:10:40\nGMT
  1926. // ^
  1927. // |
  1928. // Cp
  1929. //
  1930. Cp++;
  1931. Head = Cp;
  1932. //
  1933. // Head->00:10:40\nGMT
  1934. // ^
  1935. // |
  1936. // Cp
  1937. //
  1938. Cp = wcschr(Head, L':');
  1939. //
  1940. // Head->"00"10:40\nGMT -- Head now points to the hour string.
  1941. // ^
  1942. // |
  1943. // Cp
  1944. //
  1945. *Cp = L'\0';
  1946. TimeFields.Hour = (short)_wtoi(Head);
  1947. // XmlDavDbgPrint(("%ld: DavParseRfc1123TimeString: Hour = %d.\n",
  1948. // GetCurrentThreadId(), TimeFields.Hour));
  1949. //
  1950. // Head->10:40\nGMT
  1951. // ^
  1952. // |
  1953. // Cp
  1954. //
  1955. Cp++;
  1956. Head = Cp;
  1957. //
  1958. // Head->10:40\nGMT
  1959. // ^
  1960. // |
  1961. // Cp
  1962. //
  1963. Cp = wcschr(Head, L':');
  1964. //
  1965. // Head->"10"40\nGMT -- Head now points to the minute string.
  1966. // ^
  1967. // |
  1968. // Cp
  1969. //
  1970. *Cp = L'\0';
  1971. TimeFields.Minute = (short)_wtoi(Head);
  1972. // XmlDavDbgPrint(("%ld: DavParseRfc1123TimeString: Minute = %d.\n",
  1973. // GetCurrentThreadId(), TimeFields.Minute));
  1974. //
  1975. // Head->40\nGMT
  1976. // ^
  1977. // |
  1978. // Cp
  1979. //
  1980. Cp++;
  1981. Head = Cp;
  1982. //
  1983. // Head->40\nGMT
  1984. // ^
  1985. // |
  1986. // Cp
  1987. //
  1988. Cp = wcschr(Head, L' ');
  1989. //
  1990. // Head->"40"GMT -- Head now points to the seconds string.
  1991. // ^
  1992. // |
  1993. // Cp
  1994. //
  1995. *Cp = L'\0';
  1996. TimeFields.Second = (short)_wtoi(Head);
  1997. // XmlDavDbgPrint(("%ld: DavParseRfc1123TimeString: Second = %d.\n",
  1998. // GetCurrentThreadId(), TimeFields.Second));
  1999. //
  2000. // Since we don't know the millisec value, we set it to zero.
  2001. //
  2002. TimeFields.Milliseconds = 0;
  2003. // XmlDavDbgPrint(("%ld: DavParseRfc1123TimeString: MilliSec = %d.\n",
  2004. // GetCurrentThreadId(), TimeFields.Milliseconds));
  2005. //
  2006. // We have set the time fields structure. Now its time to get the time
  2007. // value as a LARGE_INTEGER and store it in DavFileAttributes. The time
  2008. // we need to set could either be the creation time or the last modified
  2009. // time.
  2010. //
  2011. if (CreateNodeAttribute == CreateNode_LastModifiedTime_rfc1123) {
  2012. ReturnVal = RtlTimeFieldsToTime(&(TimeFields),
  2013. &(DavFileAttributes->LastModifiedTime));
  2014. } else {
  2015. ReturnVal = RtlTimeFieldsToTime(&(TimeFields),
  2016. &(DavFileAttributes->CreationTime));
  2017. }
  2018. if (!ReturnVal) {
  2019. XmlDavDbgPrint(("%ld: ERROR: DavParseRfc1123TimeString/RtlTimeFieldsToTime.\n"));
  2020. WStatus = ERROR_INVALID_PARAMETER;
  2021. }
  2022. // XmlDavDbgPrint(("%ld: DavParseRfc1123TimeString: LastModifiedTime = %d, %d.\n",
  2023. // GetCurrentThreadId(),
  2024. // DavFileAttributes->LastModifiedTime.HighPart,
  2025. // DavFileAttributes->LastModifiedTime.LowPart));
  2026. return WStatus;
  2027. }
  2028. #endif
  2029. VOID
  2030. DavOverrideAttributes(
  2031. PDAV_FILE_ATTRIBUTES pDavFileAttributes
  2032. )
  2033. /*++
  2034. Routine Description:
  2035. If win32 timestamps are not set, then set them with DAV timestamps
  2036. Arguments:
  2037. DavFileAttributes - The Dav File attributes structure which contains the
  2038. Time Values
  2039. Return Value:
  2040. None
  2041. --*/
  2042. {
  2043. if (!pDavFileAttributes->CreationTime.HighPart)
  2044. {
  2045. pDavFileAttributes->CreationTime = pDavFileAttributes->DavCreationTime;
  2046. }
  2047. if (!pDavFileAttributes->LastModifiedTime.HighPart)
  2048. {
  2049. pDavFileAttributes->LastModifiedTime = pDavFileAttributes->DavLastModifiedTime;
  2050. }
  2051. if (pDavFileAttributes->isCollection)
  2052. {
  2053. pDavFileAttributes->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
  2054. }
  2055. else
  2056. {
  2057. pDavFileAttributes->dwFileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
  2058. }
  2059. if (!(pDavFileAttributes->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
  2060. {
  2061. if (pDavFileAttributes->isHidden)
  2062. {
  2063. pDavFileAttributes->dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
  2064. }
  2065. else
  2066. {
  2067. pDavFileAttributes->dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
  2068. }
  2069. }
  2070. }