1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_ucb.hxx"
24 
25 #include "webdavresponseparser.hxx"
26 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
27 #include <cppuhelper/implbase2.hxx>
28 #include <com/sun/star/xml/sax/XParser.hpp>
29 #include <com/sun/star/xml/sax/InputSource.hpp>
30 #include <comphelper/processfactory.hxx>
31 #include <comphelper/seqstream.hxx>
32 #include <com/sun/star/ucb/Lock.hpp>
33 #include <com/sun/star/ucb/LockDepth.hpp>
34 #include <com/sun/star/ucb/LockEntry.hpp>
35 #include <com/sun/star/ucb/LockScope.hpp>
36 #include <com/sun/star/ucb/LockType.hpp>
37 #include <map>
38 #include <hash_map>
39 
40 //////////////////////////////////////////////////////////////////////////////
41 
42 using namespace com::sun::star;
43 
44 //////////////////////////////////////////////////////////////////////////////
45 // WebDAVNamespace enum and StringToEnum converter
46 
47 namespace
48 {
49     enum WebDAVNamespace
50     {
51         WebDAVNamespace_unknown = 0,
52         WebDAVNamespace_DAV,
53         WebDAVNamespace_ucb_openoffice_org_dav_props,
54 
55         WebDAVNamespace_last
56     };
57 
58     WebDAVNamespace StrToWebDAVNamespace(const rtl::OUString& rStr)
59     {
60         static ::rtl::OUString aStrDAV(::rtl::OUString::createFromAscii("DAV:"));
61         static ::rtl::OUString aStrUcbOpenofficeOrgDAVProps(::rtl::OUString::createFromAscii("http://ucb.openoffice.org/dav/props/"));
62 
63         if(rStr.equals(aStrDAV))
64         {
65             return WebDAVNamespace_DAV;
66         }
67         else if(rStr.equals(aStrUcbOpenofficeOrgDAVProps))
68         {
69             return WebDAVNamespace_ucb_openoffice_org_dav_props;
70         }
71 
72         return WebDAVNamespace_unknown;
73     }
74 } // end of anonymous namespace
75 
76 //////////////////////////////////////////////////////////////////////////////
77 // WebDAVName enum and StringToEnum converter using hash_map
78 
79 namespace
80 {
81     enum WebDAVName
82     {
83         WebDAVName_unknown = 0,
84         WebDAVName_multistatus,
85         WebDAVName_response,
86         WebDAVName_href,
87         WebDAVName_propstat,
88         WebDAVName_prop,
89         WebDAVName_resourcetype,
90         WebDAVName_collection,
91         WebDAVName_getcontenttype,
92         WebDAVName_supportedlock,
93         WebDAVName_lockentry,
94         WebDAVName_lockscope,
95         WebDAVName_exclusive,
96         WebDAVName_locktype,
97         WebDAVName_write,
98         WebDAVName_shared,
99         WebDAVName_lockdiscovery,
100         WebDAVName_activelock,
101         WebDAVName_depth,
102         WebDAVName_owner,
103         WebDAVName_timeout,
104         WebDAVName_locktoken,
105         WebDAVName_status,
106         WebDAVName_getlastmodified,
107         WebDAVName_creationdate,
108         WebDAVName_getcontentlength,
109 
110         WebDAVName_last
111     };
112 
113     WebDAVName StrToWebDAVName(const rtl::OUString& rStr)
114     {
115         typedef std::hash_map< rtl::OUString, WebDAVName, rtl::OUStringHash > WebDAVNameMapper;
116         typedef std::pair< rtl::OUString, WebDAVName > WebDAVNameValueType;
117         static WebDAVNameMapper aWebDAVNameMapperList;
118 
119         if(aWebDAVNameMapperList.empty())
120         {
121             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("multistatus"), WebDAVName_multistatus));
122             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("response"), WebDAVName_response));
123             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("href"), WebDAVName_href));
124             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("propstat"), WebDAVName_propstat));
125             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("prop"), WebDAVName_prop));
126             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("resourcetype"), WebDAVName_resourcetype));
127             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("collection"), WebDAVName_collection));
128             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("getcontenttype"), WebDAVName_getcontenttype));
129             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("supportedlock"), WebDAVName_supportedlock));
130             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("lockentry"), WebDAVName_lockentry));
131             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("lockscope"), WebDAVName_lockscope));
132             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("exclusive"), WebDAVName_exclusive));
133             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("locktype"), WebDAVName_locktype));
134             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("write"), WebDAVName_write));
135             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("shared"), WebDAVName_shared));
136             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("lockdiscovery"), WebDAVName_lockdiscovery));
137             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("activelock"), WebDAVName_activelock));
138             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("depth"), WebDAVName_depth));
139             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("owner"), WebDAVName_owner));
140             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("timeout"), WebDAVName_timeout));
141             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("locktoken"), WebDAVName_locktoken));
142             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("status"), WebDAVName_status));
143             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("getlastmodified"), WebDAVName_getlastmodified));
144             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("creationdate"), WebDAVName_creationdate));
145             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("getcontentlength"), WebDAVName_getcontentlength));
146         }
147 
148         const WebDAVNameMapper::const_iterator aResult(aWebDAVNameMapperList.find(rStr));
149 
150         if(aResult == aWebDAVNameMapperList.end())
151         {
152             return WebDAVName_unknown;
153         }
154         else
155         {
156             return aResult->second;
157         }
158     }
159 } // end of anonymous namespace
160 
161 //////////////////////////////////////////////////////////////////////////////
162 // WebDAVContext, holding information for each start/endElement pair
163 
164 namespace
165 {
166     typedef std::map< ::rtl::OUString, ::rtl::OUString > NamespaceMap;
167     typedef std::pair< const ::rtl::OUString, ::rtl::OUString > NamespaceValueType;
168 
169     class WebDAVContext
170     {
171     private:
172         WebDAVContext*              mpParent;
173         NamespaceMap                maNamespaceMap;
174         ::rtl::OUString             maWhiteSpace;
175 
176         ::rtl::OUString             maNamespace;
177         ::rtl::OUString             maName;
178 
179         WebDAVNamespace             maWebDAVNamespace;
180         WebDAVName                  maWebDAVName;
181 
182         // local helpers
183         void parseForNamespaceTokens(const uno::Reference< xml::sax::XAttributeList >& xAttribs);
184         ::rtl::OUString mapNamespaceToken(const ::rtl::OUString& rToken) const;
185         void splitName(const ::rtl::OUString& rSource);
186 
187     public:
188         WebDAVContext(WebDAVContext* pParent, const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs);
189         ~WebDAVContext();
190 
191         WebDAVContext* getParent() const { return mpParent; }
192         ::rtl::OUString& getWhiteSpace() { return maWhiteSpace; }
193         void setWhiteSpace(const ::rtl::OUString& rNew) { maWhiteSpace = rNew; }
194 
195         const ::rtl::OUString& getNamespace() const { return maNamespace; }
196         const ::rtl::OUString& getName() const { return maName; }
197         WebDAVNamespace getWebDAVNamespace() const { return maWebDAVNamespace; }
198         WebDAVName getWebDAVName() const { return maWebDAVName; }
199     };
200 
201     void WebDAVContext::parseForNamespaceTokens(const uno::Reference< xml::sax::XAttributeList >& xAttribs)
202     {
203         const sal_Int16 nAttributes(xAttribs->getLength());
204         static ::rtl::OUString aStrXmlns(::rtl::OUString::createFromAscii("xmlns"));
205 
206         for(sal_Int16 a(0); a < nAttributes; a++)
207         {
208             const ::rtl::OUString aName(xAttribs->getNameByIndex(a));
209             const sal_Int32 nLen(aName.getLength());
210 
211             if(nLen)
212             {
213                 if(aName.match(aStrXmlns, 0))
214                 {
215                     const sal_Int32 nIndex(aName.indexOf(sal_Unicode(':'), 0));
216 
217                     if(-1 != nIndex && nIndex + 1 < nLen)
218                     {
219                         const ::rtl::OUString aToken(aName.copy(nIndex + 1));
220 
221                         maNamespaceMap.insert(NamespaceValueType(aToken, xAttribs->getValueByIndex(a)));
222                     }
223                 }
224             }
225         }
226     }
227 
228     ::rtl::OUString WebDAVContext::mapNamespaceToken(const ::rtl::OUString& rToken) const
229     {
230         NamespaceMap::const_iterator iter = maNamespaceMap.find(rToken);
231 
232         if(maNamespaceMap.end() == iter)
233         {
234             if(getParent())
235             {
236                 return getParent()->mapNamespaceToken(rToken);
237             }
238             else
239             {
240                 return rToken;
241             }
242         }
243         else
244         {
245             return (*iter).second;
246         }
247     }
248 
249     void WebDAVContext::splitName(const ::rtl::OUString& rSource)
250     {
251         const sal_Int32 nLen(rSource.getLength());
252         maNamespace = ::rtl::OUString();
253         maName = rSource;
254 
255         if(nLen)
256         {
257             const sal_Int32 nIndex(rSource.indexOf(sal_Unicode(':'), 0));
258 
259             if(-1 != nIndex && nIndex > 0 && nIndex + 1 < nLen)
260             {
261                 maNamespace = mapNamespaceToken(rSource.copy(0, nIndex));
262                 maName = rSource.copy(nIndex + 1);
263             }
264         }
265     }
266 
267     WebDAVContext::WebDAVContext(WebDAVContext* pParent, const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs)
268     :   mpParent(pParent),
269         maNamespaceMap(),
270         maWhiteSpace(),
271         maNamespace(),
272         maName(),
273         maWebDAVNamespace(WebDAVNamespace_unknown),
274         maWebDAVName(WebDAVName_unknown)
275     {
276         const sal_Int16 nAttributes(xAttribs->getLength());
277 
278         if(nAttributes)
279         {
280             // parse evtl. namespace entries
281             parseForNamespaceTokens(xAttribs);
282         }
283 
284         // split name to namespace and name
285         splitName(aName);
286 
287         // evaluate enums for namespace and name
288         maWebDAVNamespace = StrToWebDAVNamespace(maNamespace);
289         maWebDAVName = StrToWebDAVName(maName);
290     }
291 
292     WebDAVContext::~WebDAVContext()
293     {
294     }
295 } // end of anonymous namespace
296 
297 //////////////////////////////////////////////////////////////////////////////
298 // the Xml parser itself
299 
300 namespace
301 {
302     enum WebDAVResponseParserMode
303     {
304         WebDAVResponseParserMode_PropFind = 0,
305         WebDAVResponseParserMode_PropName,
306         WebDAVResponseParserMode_LockResponse
307     };
308 
309     class WebDAVResponseParser : public cppu::WeakImplHelper1< com::sun::star::xml::sax::XDocumentHandler >
310     {
311     private:
312         std::vector< http_dav_ucp::DAVResource >      maResult_PropFind;
313         std::vector< http_dav_ucp::DAVResourceInfo >  maResult_PropName;
314         http_dav_ucp::DAVPropertyValue                maResult_Lock;
315 
316         WebDAVContext*                              mpContext;
317         ::rtl::OUString                             maHref;
318         ::rtl::OUString                             maHrefLocks; //this is used for locks, when lockdiscoveryactive
319 
320         ::rtl::OUString                             maStatus;
321         std::vector< http_dav_ucp::DAVPropertyValue > maResponseProperties;
322         std::vector< http_dav_ucp::DAVPropertyValue > maPropStatProperties;
323         std::vector< ::rtl::OUString >              maResponseNames;
324         std::vector< ::rtl::OUString >              maPropStatNames;
325         uno::Sequence< ::rtl::OUString >            maLockTokens;
326         uno::Sequence< ucb::LockEntry >             maLockEntries;
327         uno::Sequence< ucb::Lock >                  maLocks;    //the returned locks following a lockdiscovery request
328         ucb::LockScope                              maLockScope;
329         ucb::LockType                               maLockType;
330         ucb::LockDepth                              maLockDepth;
331         ::rtl::OUString                             maLockOwner;
332         sal_Int64                                   maLockTimeout;
333         ::rtl::OUString                             maLockToken;
334 
335       WebDAVResponseParserMode                    meWebDAVResponseParserMode;
336 
337         // bitfield
338         bool                                        mbResourceTypeCollection : 1;
339         bool                                        mbLockScopeSet : 1;
340         bool                                        mbLockTypeSet : 1;
341         bool                                        mbLockTokenSet : 1;
342         //TODO: add other flag to manage reading od token, depth, timeout, owner
343         bool                                        mbLockDiscoveryActive : 1;
344 
345         // local helpers
346         bool whitespaceIsAvailable() const
347         {
348             return mpContext && mpContext->getWhiteSpace().getLength();
349         }
350         bool hasParent(WebDAVName aWebDAVName) const
351         {
352             return mpContext && mpContext->getParent() && aWebDAVName == mpContext->getParent()->getWebDAVName();
353         }
354         bool propertyIsReady() const
355         {
356             return hasParent(WebDAVName_prop) && whitespaceIsAvailable();
357         }
358         bool isCollectingProperties() const
359         {
360             return WebDAVResponseParserMode_PropFind == meWebDAVResponseParserMode;
361         }
362         bool isCollectingPropNames() const
363         {
364             return WebDAVResponseParserMode_PropName == meWebDAVResponseParserMode;
365         }
366         bool isWaitingLockResponse() const
367         {
368             return WebDAVResponseParserMode_LockResponse == meWebDAVResponseParserMode;
369         }
370         bool collectThisPropertyAsName() const
371         {
372             return isCollectingPropNames() && hasParent(WebDAVName_prop);
373         }
374         void pop_context()
375         {
376             if(mpContext)
377             {
378                 WebDAVContext* pTemp = mpContext;
379                 mpContext = mpContext->getParent();
380                 delete pTemp;
381             }
382             else
383             {
384                 OSL_ENSURE(false, "Parser context pop without context (!)");
385             }
386         }
387 
388     public:
389         WebDAVResponseParser(WebDAVResponseParserMode eWebDAVResponseParserMode);
390         ~WebDAVResponseParser();
391 
392         // Methods XDocumentHandler
393         virtual void SAL_CALL startDocument(  ) throw (xml::sax::SAXException, uno::RuntimeException);
394         virtual void SAL_CALL endDocument(  ) throw (xml::sax::SAXException, uno::RuntimeException);
395         virtual void SAL_CALL startElement( const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs )
396             throw (xml::sax::SAXException, uno::RuntimeException);
397         virtual void SAL_CALL endElement( const ::rtl::OUString& aName ) throw (xml::sax::SAXException, uno::RuntimeException);
398         virtual void SAL_CALL characters( const ::rtl::OUString& aChars ) throw (xml::sax::SAXException, uno::RuntimeException);
399         virtual void SAL_CALL ignorableWhitespace( const ::rtl::OUString& aWhitespaces ) throw (xml::sax::SAXException, uno::RuntimeException);
400         virtual void SAL_CALL processingInstruction( const ::rtl::OUString& aTarget, const ::rtl::OUString& aData ) throw (xml::sax::SAXException, uno::RuntimeException);
401         virtual void SAL_CALL setDocumentLocator( const uno::Reference< xml::sax::XLocator >& xLocator ) throw (xml::sax::SAXException, uno::RuntimeException);
402 
403         const std::vector< http_dav_ucp::DAVResource >& getResult_PropFind() const { return maResult_PropFind; }
404         const std::vector< http_dav_ucp::DAVResourceInfo >& getResult_PropName() const { return maResult_PropName; }
405         const http_dav_ucp::DAVPropertyValue& getResult_Lock() const { return maResult_Lock; }
406     };
407 
408     WebDAVResponseParser::WebDAVResponseParser(WebDAVResponseParserMode eWebDAVResponseParserMode)
409     :   maResult_PropFind(),
410         maResult_PropName(),
411         maResult_Lock(),
412         mpContext(0),
413         maHref(),
414         maHrefLocks(),
415         maStatus(),
416         maResponseProperties(),
417         maPropStatProperties(),
418         maResponseNames(),
419         maPropStatNames(),
420         maLockTokens(),
421         maLockEntries(),
422         maLocks(),
423         maLockScope(ucb::LockScope_EXCLUSIVE),
424         maLockType(ucb::LockType_WRITE),
425         maLockDepth(ucb::LockDepth_ZERO),
426         maLockOwner(),
427         maLockTimeout(0),
428         meWebDAVResponseParserMode(eWebDAVResponseParserMode),
429         mbResourceTypeCollection(false),
430         mbLockScopeSet(false),
431         mbLockTypeSet(false),
432         mbLockDiscoveryActive(false)
433     {
434     }
435 
436     WebDAVResponseParser::~WebDAVResponseParser()
437     {
438         OSL_ENSURE(!mpContext, "Parser destructed with existing content (!)");
439         while(mpContext)
440         {
441             pop_context();
442         }
443     }
444 
445     void SAL_CALL WebDAVResponseParser::startDocument(  ) throw (xml::sax::SAXException, uno::RuntimeException)
446     {
447         OSL_ENSURE(!mpContext, "Parser start with existing content (!)");
448     }
449 
450     void SAL_CALL WebDAVResponseParser::endDocument(  ) throw (xml::sax::SAXException, uno::RuntimeException)
451     {
452         OSL_ENSURE(!mpContext, "Parser end with existing content (!)");
453     }
454 
455     void SAL_CALL WebDAVResponseParser::startElement( const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs )
456         throw (xml::sax::SAXException, uno::RuntimeException)
457     {
458         const sal_Int32 nLen(aName.getLength());
459 
460         if(nLen)
461         {
462             // create new context (push)
463             mpContext = new WebDAVContext(mpContext, aName, xAttribs);
464 
465             if(collectThisPropertyAsName())
466             {
467                 // When collecting property names and parent is prop there is no need
468                 // to handle the content of this property deeper (evtl. preparations)
469             }
470             else
471             {
472                 switch(mpContext->getWebDAVNamespace())
473                 {
474                     default: // WebDAVNamespace_unknown, WebDAVNamespace_last or unhandled
475                     {
476                         break;
477                     }
478                     case WebDAVNamespace_DAV:
479                     {
480                         switch(mpContext->getWebDAVName())
481                         {
482                             default: // WebDAVName_unknown, WebDAVName_last or unhandled
483                             {
484                                 break;
485                             }
486                             case WebDAVName_propstat:
487                             {
488                                 // propstat start
489                                 if(isCollectingProperties())
490                                 {
491                                     // reset maPropStatProperties
492                                     maPropStatProperties.clear();
493                                 }
494                                 else
495                                 {
496                                     // when collecting properties reset maPropStatNames
497                                     maPropStatNames.clear();
498                                 }
499                                 break;
500                             }
501                             case WebDAVName_response:
502                             {
503                                 // response start, reset Href and status and maResponseProperties
504                                 maHref = maStatus = ::rtl::OUString();
505 
506                                 if(isCollectingProperties())
507                                 {
508                                     // reset maResponseProperties
509                                     maResponseProperties.clear();
510                                 }
511                                 else
512                                 {
513                                     // reset maResponseNames when collecting properties
514                                     maResponseNames.clear();
515                                 }
516                                 break;
517                             }
518                             case WebDAVName_resourcetype:
519                             {
520                                 // resourcetype start, reset collection
521                                 mbResourceTypeCollection = false;
522                                 break;
523                             }
524                             case WebDAVName_supportedlock:
525                             {
526                                 // supportedlock start, reset maLockEntries
527                                 maLockEntries.realloc(0);
528                                 break;
529                             }
530                             case WebDAVName_lockentry:
531                             {
532                                 // lockentry start, reset maLockEntries
533                                 mbLockScopeSet = false;
534                                 mbLockTypeSet = false;
535                                 break;
536                             }
537                             case WebDAVName_lockdiscovery:
538                             {
539                                 // lockentry start, reset maLocks
540                                 maLocks.realloc(0);
541                                 mbLockDiscoveryActive = true;
542                                 break;
543                             }
544                             case WebDAVName_activelock:
545                             {
546                                 //  activelockstart, reset vars
547                                 mbLockScopeSet = false;
548                                 mbLockTypeSet = false;
549                                 mbLockTokenSet = false;
550                                 maLockTokens.realloc(0);
551                                 maHrefLocks = ::rtl::OUString();
552                                 break;
553                             }
554                             case WebDAVName_locktoken:
555                             {
556                                 mbLockTokenSet = true;
557                                 break;
558                             }
559                         }
560                         break;
561                     }
562                     case WebDAVNamespace_ucb_openoffice_org_dav_props:
563                     {
564                         break;
565                     }
566                 }
567             }
568         }
569     }
570 
571     void SAL_CALL WebDAVResponseParser::endElement( const ::rtl::OUString& aName ) throw (xml::sax::SAXException, uno::RuntimeException)
572     {
573         const sal_Int32 nLen(aName.getLength());
574         OSL_ENSURE(mpContext, "Parser EndElement without content (!)");
575 
576         if(mpContext && nLen)
577         {
578             if(collectThisPropertyAsName())
579             {
580                 // When collecting property names and parent is prop, just append the prop name
581                 // to the collection, no need to parse deeper
582                 maPropStatNames.push_back(mpContext->getNamespace() + mpContext->getName());
583             }
584             else
585             {
586                 switch(mpContext->getWebDAVNamespace())
587                 {
588                     default: // WebDAVNamespace_unknown, WebDAVNamespace_last or unhandled
589                     {
590                         break;
591                     }
592                     case WebDAVNamespace_DAV:
593                     {
594                         switch(mpContext->getWebDAVName())
595                         {
596                             default: // WebDAVName_unknown, WebDAVName_last or unhandled
597                             {
598                                 break;
599                             }
600                             case WebDAVName_href:
601                             {
602                                 // href end, save it if we have whitespace
603                                 if(whitespaceIsAvailable())
604                                 {
605                                     if(mbLockDiscoveryActive)
606                                     {
607                                         maHrefLocks = mpContext->getWhiteSpace();
608                                     }
609                                     else
610                                     {
611                                         maHref = mpContext->getWhiteSpace();
612                                     }
613                                 }
614                                 break;
615                             }
616                             case WebDAVName_status:
617                             {
618                                 // status end, save it if we have whitespace
619                                 if(whitespaceIsAvailable())
620                                 {
621                                     maStatus = mpContext->getWhiteSpace();
622                                 }
623                                 break;
624                             }
625                             case WebDAVName_getlastmodified:
626                             {
627                                 // getlastmodified end, safe if content is correct
628                                 if(propertyIsReady())
629                                 {
630                                     static rtl::OUString aStr(rtl::OUString::createFromAscii("DAV:getlastmodified"));
631                                     http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
632 
633                                     aDAVPropertyValue.Name = aStr;
634                                     aDAVPropertyValue.Value <<= mpContext->getWhiteSpace();
635                                     maPropStatProperties.push_back(aDAVPropertyValue);
636                                 }
637                                 break;
638                             }
639                             case WebDAVName_creationdate:
640                             {
641                                 // creationdate end, safe if content is correct
642                                 if(propertyIsReady())
643                                 {
644                                     static rtl::OUString aStr(rtl::OUString::createFromAscii("DAV:creationdate"));
645                                     http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
646 
647                                     aDAVPropertyValue.Name = aStr;
648                                     aDAVPropertyValue.Value <<= mpContext->getWhiteSpace();
649                                     maPropStatProperties.push_back(aDAVPropertyValue);
650                                 }
651                                 break;
652                             }
653                             case WebDAVName_collection:
654                             {
655                                 // collection end, check and set
656                                 if(hasParent(WebDAVName_resourcetype))
657                                 {
658                                     mbResourceTypeCollection = true;
659                                 }
660                                 break;
661                             }
662                             case WebDAVName_resourcetype:
663                             {
664                                 // resourcetype end, check for collection
665                                 if(hasParent(WebDAVName_prop))
666                                 {
667                                     static rtl::OUString aStrA(rtl::OUString::createFromAscii("DAV:resourcetype"));
668                                     static rtl::OUString aStrB(rtl::OUString::createFromAscii("collection"));
669                                     http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
670 
671                                     aDAVPropertyValue.Name = aStrA;
672                                     aDAVPropertyValue.Value <<= (mbResourceTypeCollection ? aStrB : rtl::OUString());
673                                     maPropStatProperties.push_back(aDAVPropertyValue);
674                                 }
675                                 break;
676                             }
677                             case WebDAVName_getcontentlength:
678                             {
679                                 // getcontentlength end, safe if content is correct
680                                 if(propertyIsReady())
681                                 {
682                                     static rtl::OUString aStr(rtl::OUString::createFromAscii("DAV:getcontentlength"));
683                                     http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
684 
685                                     aDAVPropertyValue.Name = aStr;
686                                     aDAVPropertyValue.Value <<= mpContext->getWhiteSpace();
687                                     maPropStatProperties.push_back(aDAVPropertyValue);
688                                 }
689                                 break;
690                             }
691                             case WebDAVName_getcontenttype:
692                             {
693                                 // getcontenttype end, safe if content is correct
694                                 if(propertyIsReady())
695                                 {
696                                     static rtl::OUString aStr(rtl::OUString::createFromAscii("DAV:getcontenttype"));
697                                     http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
698 
699                                     aDAVPropertyValue.Name = aStr;
700                                     aDAVPropertyValue.Value <<= mpContext->getWhiteSpace();
701                                     maPropStatProperties.push_back(aDAVPropertyValue);
702                                 }
703                                 break;
704                             }
705                             case WebDAVName_supportedlock:
706                             {
707                                 // supportedlock end
708                                 if(hasParent(WebDAVName_prop) && maLockEntries.hasElements())
709                                 {
710                                     static rtl::OUString aStr(rtl::OUString::createFromAscii("DAV:supportedlock"));
711                                     http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
712 
713                                     aDAVPropertyValue.Name = aStr;
714                                     aDAVPropertyValue.Value <<= maLockEntries;
715                                     maPropStatProperties.push_back(aDAVPropertyValue);
716                                 }
717                                 break;
718                             }
719                             case WebDAVName_lockentry:
720                             {
721                                 // lockentry end
722                                 if(hasParent(WebDAVName_supportedlock) && (mbLockScopeSet && mbLockTypeSet))
723                                 {
724                                     const sal_Int32 nLength(maLockEntries.getLength());
725                                     ucb::LockEntry aEntry;
726 
727                                     aEntry.Scope = maLockScope;
728                                     aEntry.Type = maLockType;
729                                     maLockEntries.realloc(nLength + 1);
730                                     maLockEntries[nLength] = aEntry;
731                                 }
732                                 break;
733                             }
734                             case WebDAVName_exclusive:
735                             {
736                                 // exclusive lockscope end
737                                 if(hasParent(WebDAVName_lockscope) || hasParent(WebDAVName_activelock))
738                                 {
739                                     maLockScope = ucb::LockScope_EXCLUSIVE;
740                                     mbLockScopeSet = true;
741                                 }
742                                 break;
743                             }
744                             case WebDAVName_shared:
745                             {
746                                 // shared lockscope end
747                                 if(hasParent(WebDAVName_lockscope) || hasParent(WebDAVName_activelock))
748                                 {
749                                     maLockScope = ucb::LockScope_SHARED;
750                                     mbLockScopeSet = true;
751                                 }
752                                 break;
753                             }
754                             case WebDAVName_write:
755                             {
756                                 // write locktype end
757                                 if(hasParent(WebDAVName_locktype) || hasParent(WebDAVName_activelock))
758                                 {
759                                     maLockType = ucb::LockType_WRITE;
760                                     mbLockTypeSet = true;
761                                 }
762                                 break;
763                             }
764                             case WebDAVName_lockdiscovery:
765                             {
766                                 // lockdiscovery end
767                                 if(hasParent(WebDAVName_prop))
768                                 {
769                                     static ::rtl::OUString aStr(rtl::OUString::createFromAscii("DAV:lockdiscovery"));
770                                     if(isWaitingLockResponse())
771                                     {
772                                         maResult_Lock.Name = aStr;
773                                         maResult_Lock.Value <<= maLocks;
774                                     }
775                                     else
776                                     {
777                                         ::http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
778 
779                                         aDAVPropertyValue.Name = aStr;
780                                         aDAVPropertyValue.Value <<= maLocks;
781                                         maPropStatProperties.push_back(aDAVPropertyValue);
782                                     }
783                                 }
784                                 mbLockDiscoveryActive = false;
785                                 break;
786                             }
787                             case WebDAVName_activelock:
788                             {
789                                 if(hasParent(WebDAVName_lockdiscovery) &&
790                                    mbLockScopeSet && mbLockTypeSet && mbLockTokenSet)
791                                 {
792                                     const sal_Int32 nLength(maLocks.getLength());
793                                     ucb::Lock aLock;
794 
795                                     aLock.Scope = maLockScope;
796                                     aLock.Type = maLockType;
797                                     //add tokens, depth, timeout, owner
798                                     aLock.LockTokens = maLockTokens;
799                                     aLock.Depth = maLockDepth;
800                                     aLock.Owner <<= maLockOwner;
801                                     aLock.Timeout = maLockTimeout;
802                                     maLocks.realloc(nLength + 1);
803                                     maLocks[nLength] = aLock;
804                                 }
805                                 break;
806                             }
807                             case WebDAVName_locktoken:
808                             {
809                                 if(hasParent(WebDAVName_activelock))
810                                 {
811                                     //add a token to the list of tokens
812                                     const sal_Int32 nLength(maLockTokens.getLength());
813                                     maLockTokens.realloc(nLength + 1);
814                                     maLockTokens[nLength] = maHrefLocks;
815                                     mbLockTokenSet = true;
816                                 }
817                                 break;
818                             }
819                             case WebDAVName_timeout:
820                             {
821                                 if(hasParent(WebDAVName_activelock))
822                                 {
823                                     ::rtl::OUString aStr( mpContext->getWhiteSpace().toAsciiLowerCase());
824                                     static ::rtl::OUString aInfinite( ::rtl::OUString::createFromAscii( "infinite" ) );
825                                     static ::rtl::OUString aSecond( ::rtl::OUString::createFromAscii( "second-" ) );
826                                     //look for infinity
827                                     sal_Int32 secondIndex;
828                                     if(aStr.indexOf(aInfinite) != -1)
829                                     {
830                                         maLockTimeout = -1;
831                                     }
832                                     else if((secondIndex = aStr.indexOf(aSecond)) != -1)
833                                     {
834                                         secondIndex += aSecond.getLength();
835                                         maLockTimeout = aStr.copy(secondIndex).toInt64();
836                                     }
837                                 }
838                                 break;
839                             }
840                             case WebDAVName_owner:
841                             {
842                                 if(whitespaceIsAvailable())
843                                 {
844                                     if(hasParent(WebDAVName_activelock))
845                                     {
846                                         maLockOwner = mpContext->getWhiteSpace();
847                                     }
848                                 }
849                                 break;
850                             }
851                             case WebDAVName_depth:
852                             {
853                                 if(hasParent(WebDAVName_activelock))
854                                 {
855                                     //set depth, one of three values
856                                     ::rtl::OUString aStr( mpContext->getWhiteSpace() );
857                                     //default to zero, if not found
858                                     maLockDepth = ucb::LockDepth_ZERO;
859                                     if(aStr.equalsIgnoreAsciiCase(::rtl::OUString::createFromAscii("0")))
860                                        maLockDepth = ucb::LockDepth_ZERO;
861                                     else if(aStr.equalsIgnoreAsciiCase(::rtl::OUString::createFromAscii("1")))
862                                        maLockDepth = ucb::LockDepth_ONE;
863                                     else if(aStr.equalsIgnoreAsciiCase(::rtl::OUString::createFromAscii("infinity")))
864                                        maLockDepth = ucb::LockDepth_INFINITY;
865                                 }
866                                 break;
867                             }
868                             case WebDAVName_propstat:
869                             {
870                                 // propstat end, check status
871                                 if(maStatus.getLength())
872                                 {
873                                     static ::rtl::OUString aStrStatusOkay(::rtl::OUString::createFromAscii("HTTP/1.1 200 OK"));
874 
875                                     if(maStatus.equals(aStrStatusOkay))
876                                     {
877                                         if(isCollectingProperties())
878                                         {
879                                             if(maPropStatProperties.size())
880                                             {
881                                                 // append to maResponseProperties if okay
882                                                 maResponseProperties.insert(maResponseProperties.end(), maPropStatProperties.begin(), maPropStatProperties.end());
883                                             }
884                                         }
885                                         else
886                                         {
887                                             if(maPropStatNames.size())
888                                             {
889                                                 // when collecting properties append to
890                                                 maResponseNames.insert(maResponseNames.end(), maPropStatNames.begin(), maPropStatNames.end());
891                                             }
892                                         }
893                                     }
894                                 }
895                                 break;
896                             }
897                             case WebDAVName_response:
898                             {
899                                 // response end
900                                 if(maHref.getLength())
901                                 {
902                                     if(isCollectingProperties())
903                                     {
904                                         // create DAVResource when we have content
905                                         if(maResponseProperties.size())
906                                         {
907                                             ::http_dav_ucp::DAVResource aDAVResource;
908 
909                                             aDAVResource.uri = maHref;
910                                             aDAVResource.properties = maResponseProperties;
911                                             maResult_PropFind.push_back(aDAVResource);
912                                         }
913                                     }
914                                     else
915                                     {
916                                         // when collecting properties add them to result when there are some
917                                         if(maResponseNames.size())
918                                         {
919                                             http_dav_ucp::DAVResourceInfo aDAVResourceInfo(maHref);
920 
921                                             aDAVResourceInfo.properties = maResponseNames;
922                                             maResult_PropName.push_back(aDAVResourceInfo);
923                                         }
924                                     }
925                                 }
926                                 break;
927                             }
928                         }
929                         break;
930                     }
931                     case WebDAVNamespace_ucb_openoffice_org_dav_props:
932                     {
933                         break;
934                     }
935                 }
936             }
937 
938             // destroy last context (pop)
939             pop_context();
940         }
941     }
942 
943     void SAL_CALL WebDAVResponseParser::characters( const ::rtl::OUString& aChars ) throw (xml::sax::SAXException, uno::RuntimeException)
944     {
945         // collect whitespace over evtl. several calls in mpContext
946         OSL_ENSURE(mpContext, "Parser characters without content (!)");
947         const sal_Int32 nLen(aChars.getLength());
948 
949         if(mpContext && nLen)
950         {
951             // remove leading/trailing blanks and CRLF
952             const ::rtl::OUString aTrimmedChars(aChars.trim());
953 
954             if(aTrimmedChars.getLength())
955             {
956                 ::rtl::OUString aNew(mpContext->getWhiteSpace());
957 
958                 if(aNew.getLength())
959                 {
960                     // add one char when appending (see html1.1 spec)
961                     aNew += ::rtl::OUString(sal_Unicode(' '));
962                 }
963 
964                 aNew += aTrimmedChars;
965                 mpContext->setWhiteSpace(aNew);
966             }
967         }
968     }
969 
970     void SAL_CALL WebDAVResponseParser::ignorableWhitespace( const ::rtl::OUString& /*aWhitespaces*/ ) throw (xml::sax::SAXException, uno::RuntimeException)
971     {
972     }
973 
974     void SAL_CALL WebDAVResponseParser::processingInstruction( const ::rtl::OUString& /*aTarget*/, const ::rtl::OUString& /*aData*/ )
975         throw (xml::sax::SAXException, uno::RuntimeException)
976     {
977     }
978 
979     void SAL_CALL WebDAVResponseParser::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& /*xLocator*/ ) throw (xml::sax::SAXException, uno::RuntimeException)
980     {
981     }
982 } // end of anonymous namespace
983 
984 //////////////////////////////////////////////////////////////////////////////
985 // wrapper for various calls to the parser
986 
987 namespace
988 {
989     void parseWebDAVPropNameResponse(
990         const uno::Reference< io::XInputStream >& xInputStream,
991         std::vector< http_dav_ucp::DAVResource >& rPropFind,
992         std::vector< http_dav_ucp::DAVResourceInfo >& rPropName,
993         http_dav_ucp::DAVPropertyValue&           rPropValue,
994         WebDAVResponseParserMode eWebDAVResponseParserMode)
995     {
996         if(xInputStream.is())
997         {
998             try
999             {
1000                 // prepare ParserInputSrouce
1001                 xml::sax::InputSource myInputSource;
1002                 myInputSource.aInputStream = xInputStream;
1003 
1004                 // get parser
1005                 uno::Reference< xml::sax::XParser > xParser(
1006                     comphelper::getProcessServiceFactory()->createInstance(
1007                         rtl::OUString::createFromAscii("com.sun.star.xml.sax.Parser") ),
1008                     uno::UNO_QUERY_THROW );
1009 
1010                 // create parser; connect parser and filter
1011                 WebDAVResponseParser* pWebDAVResponseParser = new WebDAVResponseParser(eWebDAVResponseParserMode);
1012                 uno::Reference< xml::sax::XDocumentHandler > xWebDAVHdl(pWebDAVResponseParser);
1013                 xParser->setDocumentHandler(xWebDAVHdl);
1014 
1015                 // finally, parse the stream
1016                 xParser->parseStream(myInputSource);
1017 
1018                 // get result
1019                 switch(eWebDAVResponseParserMode)
1020                 {
1021                     case WebDAVResponseParserMode_PropFind:
1022                     {
1023                         rPropFind = pWebDAVResponseParser->getResult_PropFind();
1024                         break;
1025                     }
1026                     case WebDAVResponseParserMode_PropName:
1027                     {
1028                         rPropName = pWebDAVResponseParser->getResult_PropName();
1029                         break;
1030                     }
1031                     case WebDAVResponseParserMode_LockResponse:
1032                     {
1033                         rPropValue = pWebDAVResponseParser->getResult_Lock();
1034                         break;
1035                     }
1036                 }
1037             }
1038             catch(uno::Exception&)
1039             {
1040                 OSL_ENSURE(false, "WebDAV Parse error (!)");
1041             }
1042         }
1043     }
1044 } // end of anonymous namespace
1045 
1046 //////////////////////////////////////////////////////////////////////////////
1047 // helper to parse a XML WebDAV response
1048 
1049 namespace http_dav_ucp
1050 {
1051     std::vector< DAVResource > parseWebDAVPropFindResponse(const uno::Reference< io::XInputStream >& xInputStream)
1052     {
1053         std::vector< DAVResource > aRetval;
1054         std::vector< DAVResourceInfo > aFoo;
1055         DAVPropertyValue               aFoo2;
1056 
1057         parseWebDAVPropNameResponse(xInputStream, aRetval, aFoo, aFoo2, WebDAVResponseParserMode_PropFind);
1058         return aRetval;
1059     }
1060 
1061     std::vector< DAVResourceInfo > parseWebDAVPropNameResponse(const uno::Reference< io::XInputStream >& xInputStream)
1062     {
1063         std::vector< DAVResource > aFoo;
1064         std::vector< DAVResourceInfo > aRetval;
1065         DAVPropertyValue               aFoo2;
1066 
1067         parseWebDAVPropNameResponse(xInputStream, aFoo, aRetval, aFoo2, WebDAVResponseParserMode_PropName);
1068         return aRetval;
1069     }
1070 
1071     http_dav_ucp::DAVPropertyValue parseWebDAVLockResponse(const uno::Reference< io::XInputStream >& xInputStream)
1072     {
1073         std::vector< DAVResource > aFoo2;
1074         std::vector< DAVResourceInfo > aFoo;
1075         http_dav_ucp::DAVPropertyValue               aRetval;
1076 
1077 
1078         parseWebDAVPropNameResponse(xInputStream, aFoo2, aFoo, aRetval, WebDAVResponseParserMode_LockResponse);
1079         return aRetval;
1080     }
1081 
1082 } // namespace http_dav_ucp
1083 
1084 //////////////////////////////////////////////////////////////////////////////
1085 // eof
1086