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/LockEntry.hpp>
33 #include <com/sun/star/ucb/LockScope.hpp>
34 #include <com/sun/star/ucb/LockType.hpp>
35 #include <map>
36 #include <hash_map>
37 
38 //////////////////////////////////////////////////////////////////////////////
39 
40 using namespace com::sun::star;
41 
42 //////////////////////////////////////////////////////////////////////////////
43 // WebDAVNamespace enum and StringToEnum converter
44 
45 namespace
46 {
47     enum WebDAVNamespace
48     {
49         WebDAVNamespace_unknown = 0,
50         WebDAVNamespace_DAV,
51         WebDAVNamespace_ucb_openoffice_org_dav_props,
52 
53         WebDAVNamespace_last
54     };
55 
56     WebDAVNamespace StrToWebDAVNamespace(const rtl::OUString& rStr)
57     {
58         static ::rtl::OUString aStrDAV(::rtl::OUString::createFromAscii("DAV:"));
59         static ::rtl::OUString aStrUcbOpenofficeOrgDAVProps(::rtl::OUString::createFromAscii("http://ucb.openoffice.org/dav/props/"));
60 
61         if(rStr.equals(aStrDAV))
62         {
63             return WebDAVNamespace_DAV;
64         }
65         else if(rStr.equals(aStrUcbOpenofficeOrgDAVProps))
66         {
67             return WebDAVNamespace_ucb_openoffice_org_dav_props;
68         }
69 
70         return WebDAVNamespace_unknown;
71     }
72 } // end of anonymous namespace
73 
74 //////////////////////////////////////////////////////////////////////////////
75 // WebDAVName enum and StringToEnum converter using hash_map
76 
77 namespace
78 {
79     enum WebDAVName
80     {
81         WebDAVName_unknown = 0,
82         WebDAVName_multistatus,
83         WebDAVName_response,
84         WebDAVName_href,
85         WebDAVName_propstat,
86         WebDAVName_prop,
87         WebDAVName_resourcetype,
88         WebDAVName_collection,
89         WebDAVName_getcontenttype,
90         WebDAVName_supportedlock,
91         WebDAVName_lockentry,
92         WebDAVName_lockscope,
93         WebDAVName_exclusive,
94         WebDAVName_locktype,
95         WebDAVName_write,
96         WebDAVName_shared,
97         WebDAVName_status,
98         WebDAVName_getlastmodified,
99         WebDAVName_creationdate,
100         WebDAVName_getcontentlength,
101 
102         WebDAVName_last
103     };
104 
105     WebDAVName StrToWebDAVName(const rtl::OUString& rStr)
106     {
107         typedef std::hash_map< rtl::OUString, WebDAVName, rtl::OUStringHash > WebDAVNameMapper;
108         typedef std::pair< rtl::OUString, WebDAVName > WebDAVNameValueType;
109         static WebDAVNameMapper aWebDAVNameMapperList;
110 
111         if(aWebDAVNameMapperList.empty())
112         {
113             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("multistatus"), WebDAVName_multistatus));
114             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("response"), WebDAVName_response));
115             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("href"), WebDAVName_href));
116             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("propstat"), WebDAVName_propstat));
117             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("prop"), WebDAVName_prop));
118             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("resourcetype"), WebDAVName_resourcetype));
119             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("collection"), WebDAVName_collection));
120             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("getcontenttype"), WebDAVName_getcontenttype));
121             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("supportedlock"), WebDAVName_supportedlock));
122             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("lockentry"), WebDAVName_lockentry));
123             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("lockscope"), WebDAVName_lockscope));
124             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("exclusive"), WebDAVName_exclusive));
125             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("locktype"), WebDAVName_locktype));
126             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("write"), WebDAVName_write));
127             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("shared"), WebDAVName_shared));
128             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("status"), WebDAVName_status));
129             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("getlastmodified"), WebDAVName_getlastmodified));
130             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("creationdate"), WebDAVName_creationdate));
131             aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("getcontentlength"), WebDAVName_getcontentlength));
132         }
133 
134         const WebDAVNameMapper::const_iterator aResult(aWebDAVNameMapperList.find(rStr));
135 
136         if(aResult == aWebDAVNameMapperList.end())
137         {
138             return WebDAVName_unknown;
139         }
140         else
141         {
142             return aResult->second;
143         }
144     }
145 } // end of anonymous namespace
146 
147 //////////////////////////////////////////////////////////////////////////////
148 // WebDAVContext, holding information for each start/endElement pair
149 
150 namespace
151 {
152     typedef std::map< ::rtl::OUString, ::rtl::OUString > NamespaceMap;
153     typedef std::pair< const ::rtl::OUString, ::rtl::OUString > NamespaceValueType;
154 
155     class WebDAVContext
156     {
157     private:
158         WebDAVContext*              mpParent;
159         NamespaceMap                maNamespaceMap;
160         ::rtl::OUString             maWhiteSpace;
161 
162         ::rtl::OUString             maNamespace;
163         ::rtl::OUString             maName;
164 
165         WebDAVNamespace             maWebDAVNamespace;
166         WebDAVName                  maWebDAVName;
167 
168         // local helpers
169         void parseForNamespaceTokens(const uno::Reference< xml::sax::XAttributeList >& xAttribs);
170         ::rtl::OUString mapNamespaceToken(const ::rtl::OUString& rToken) const;
171         void splitName(const ::rtl::OUString& rSource);
172 
173     public:
174         WebDAVContext(WebDAVContext* pParent, const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs);
175         ~WebDAVContext();
176 
177         WebDAVContext* getParent() const { return mpParent; }
178         ::rtl::OUString& getWhiteSpace() { return maWhiteSpace; }
179         void setWhiteSpace(const ::rtl::OUString& rNew) { maWhiteSpace = rNew; }
180 
181         const ::rtl::OUString& getNamespace() const { return maNamespace; }
182         const ::rtl::OUString& getName() const { return maName; }
183         WebDAVNamespace getWebDAVNamespace() const { return maWebDAVNamespace; }
184         WebDAVName getWebDAVName() const { return maWebDAVName; }
185     };
186 
187     void WebDAVContext::parseForNamespaceTokens(const uno::Reference< xml::sax::XAttributeList >& xAttribs)
188     {
189         const sal_Int16 nAttributes(xAttribs->getLength());
190         static ::rtl::OUString aStrXmlns(::rtl::OUString::createFromAscii("xmlns"));
191 
192         for(sal_Int16 a(0); a < nAttributes; a++)
193         {
194             const ::rtl::OUString aName(xAttribs->getNameByIndex(a));
195             const sal_Int32 nLen(aName.getLength());
196 
197             if(nLen)
198             {
199                 if(aName.match(aStrXmlns, 0))
200                 {
201                     const sal_Int32 nIndex(aName.indexOf(sal_Unicode(':'), 0));
202 
203                     if(-1 != nIndex && nIndex + 1 < nLen)
204                     {
205                         const ::rtl::OUString aToken(aName.copy(nIndex + 1));
206 
207                         maNamespaceMap.insert(NamespaceValueType(aToken, xAttribs->getValueByIndex(a)));
208                     }
209                 }
210             }
211         }
212     }
213 
214     ::rtl::OUString WebDAVContext::mapNamespaceToken(const ::rtl::OUString& rToken) const
215     {
216         NamespaceMap::const_iterator iter = maNamespaceMap.find(rToken);
217 
218         if(maNamespaceMap.end() == iter)
219         {
220             if(getParent())
221             {
222                 return getParent()->mapNamespaceToken(rToken);
223             }
224             else
225             {
226                 return rToken;
227             }
228         }
229         else
230         {
231             return (*iter).second;
232         }
233     }
234 
235     void WebDAVContext::splitName(const ::rtl::OUString& rSource)
236     {
237         const sal_Int32 nLen(rSource.getLength());
238         maNamespace = ::rtl::OUString();
239         maName = rSource;
240 
241         if(nLen)
242         {
243             const sal_Int32 nIndex(rSource.indexOf(sal_Unicode(':'), 0));
244 
245             if(-1 != nIndex && nIndex > 0 && nIndex + 1 < nLen)
246             {
247                 maNamespace = mapNamespaceToken(rSource.copy(0, nIndex));
248                 maName = rSource.copy(nIndex + 1);
249             }
250         }
251     }
252 
253     WebDAVContext::WebDAVContext(WebDAVContext* pParent, const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs)
254     :   mpParent(pParent),
255         maNamespaceMap(),
256         maWhiteSpace(),
257         maNamespace(),
258         maName(),
259         maWebDAVNamespace(WebDAVNamespace_unknown),
260         maWebDAVName(WebDAVName_unknown)
261     {
262         const sal_Int16 nAttributes(xAttribs->getLength());
263 
264         if(nAttributes)
265         {
266             // parse evtl. namespace entries
267             parseForNamespaceTokens(xAttribs);
268         }
269 
270         // split name to namespace and name
271         splitName(aName);
272 
273         // evaluate enums for namespace and name
274         maWebDAVNamespace = StrToWebDAVNamespace(maNamespace);
275         maWebDAVName = StrToWebDAVName(maName);
276     }
277 
278     WebDAVContext::~WebDAVContext()
279     {
280     }
281 } // end of anonymous namespace
282 
283 //////////////////////////////////////////////////////////////////////////////
284 // the Xml parser itself
285 
286 namespace
287 {
288     enum WebDAVResponseParserMode
289     {
290         WebDAVResponseParserMode_PropFind = 0,
291         WebDAVResponseParserMode_PropName
292     };
293 
294     class WebDAVResponseParser : public cppu::WeakImplHelper1< com::sun::star::xml::sax::XDocumentHandler >
295     {
296     private:
297         std::vector< http_dav_ucp::DAVResource >      maResult_PropFind;
298         std::vector< http_dav_ucp::DAVResourceInfo >  maResult_PropName;
299 
300         WebDAVContext*                              mpContext;
301         ::rtl::OUString                             maHref;
302         ::rtl::OUString                             maStatus;
303         std::vector< http_dav_ucp::DAVPropertyValue > maResponseProperties;
304         std::vector< http_dav_ucp::DAVPropertyValue > maPropStatProperties;
305         std::vector< ::rtl::OUString >              maResponseNames;
306         std::vector< ::rtl::OUString >              maPropStatNames;
307         uno::Sequence< ucb::LockEntry >             maLockEntries;
308         ucb::LockScope                              maLockScope;
309         ucb::LockType                               maLockType;
310         WebDAVResponseParserMode                    meWebDAVResponseParserMode;
311 
312         // bitfield
313         bool                                        mbResourceTypeCollection : 1;
314         bool                                        mbLockScopeSet : 1;
315         bool                                        mbLockTypeSet : 1;
316 
317         // local helpers
318         bool whitespaceIsAvailable() const
319         {
320             return mpContext && mpContext->getWhiteSpace().getLength();
321         }
322         bool hasParent(WebDAVName aWebDAVName) const
323         {
324             return mpContext && mpContext->getParent() && aWebDAVName == mpContext->getParent()->getWebDAVName();
325         }
326         bool propertyIsReady() const
327         {
328             return hasParent(WebDAVName_prop) && whitespaceIsAvailable();
329         }
330         bool isCollectingProperties() const
331         {
332             return WebDAVResponseParserMode_PropFind == meWebDAVResponseParserMode;
333         }
334         bool isCollectingPropNames() const
335         {
336             return WebDAVResponseParserMode_PropName == meWebDAVResponseParserMode;
337         }
338         bool collectThisPropertyAsName() const
339         {
340             return isCollectingPropNames() && hasParent(WebDAVName_prop);
341         }
342         void pop_context()
343         {
344             if(mpContext)
345             {
346                 WebDAVContext* pTemp = mpContext;
347                 mpContext = mpContext->getParent();
348                 delete pTemp;
349             }
350             else
351             {
352                 OSL_ENSURE(false, "Parser context pop without context (!)");
353             }
354         }
355 
356     public:
357         WebDAVResponseParser(WebDAVResponseParserMode eWebDAVResponseParserMode);
358         ~WebDAVResponseParser();
359 
360         // Methods XDocumentHandler
361         virtual void SAL_CALL startDocument(  ) throw (xml::sax::SAXException, uno::RuntimeException);
362         virtual void SAL_CALL endDocument(  ) throw (xml::sax::SAXException, uno::RuntimeException);
363         virtual void SAL_CALL startElement( const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) throw (xml::sax::SAXException, uno::RuntimeException);
364         virtual void SAL_CALL endElement( const ::rtl::OUString& aName ) throw (xml::sax::SAXException, uno::RuntimeException);
365         virtual void SAL_CALL characters( const ::rtl::OUString& aChars ) throw (xml::sax::SAXException, uno::RuntimeException);
366         virtual void SAL_CALL ignorableWhitespace( const ::rtl::OUString& aWhitespaces ) throw (xml::sax::SAXException, uno::RuntimeException);
367         virtual void SAL_CALL processingInstruction( const ::rtl::OUString& aTarget, const ::rtl::OUString& aData ) throw (xml::sax::SAXException, uno::RuntimeException);
368         virtual void SAL_CALL setDocumentLocator( const uno::Reference< xml::sax::XLocator >& xLocator ) throw (xml::sax::SAXException, uno::RuntimeException);
369 
370         const std::vector< http_dav_ucp::DAVResource >& getResult_PropFind() const { return maResult_PropFind; }
371         const std::vector< http_dav_ucp::DAVResourceInfo >& getResult_PropName() const { return maResult_PropName; }
372     };
373 
374     WebDAVResponseParser::WebDAVResponseParser(WebDAVResponseParserMode eWebDAVResponseParserMode)
375     :   maResult_PropFind(),
376         maResult_PropName(),
377         mpContext(0),
378         maHref(),
379         maStatus(),
380         maResponseProperties(),
381         maPropStatProperties(),
382         maResponseNames(),
383         maPropStatNames(),
384         maLockEntries(),
385         maLockScope(ucb::LockScope_EXCLUSIVE),
386         maLockType(ucb::LockType_WRITE),
387         meWebDAVResponseParserMode(eWebDAVResponseParserMode),
388         mbResourceTypeCollection(false),
389         mbLockScopeSet(false),
390         mbLockTypeSet(false)
391     {
392     }
393 
394     WebDAVResponseParser::~WebDAVResponseParser()
395     {
396         OSL_ENSURE(!mpContext, "Parser destructed with existing content (!)");
397         while(mpContext)
398         {
399             pop_context();
400         }
401     }
402 
403     void SAL_CALL WebDAVResponseParser::startDocument(  ) throw (xml::sax::SAXException, uno::RuntimeException)
404     {
405         OSL_ENSURE(!mpContext, "Parser start with existing content (!)");
406     }
407 
408     void SAL_CALL WebDAVResponseParser::endDocument(  ) throw (xml::sax::SAXException, uno::RuntimeException)
409     {
410         OSL_ENSURE(!mpContext, "Parser end with existing content (!)");
411     }
412 
413     void SAL_CALL WebDAVResponseParser::startElement( const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) throw (xml::sax::SAXException, uno::RuntimeException)
414     {
415         const sal_Int32 nLen(aName.getLength());
416 
417         if(nLen)
418         {
419             // create new context (push)
420             mpContext = new WebDAVContext(mpContext, aName, xAttribs);
421 
422             if(collectThisPropertyAsName())
423             {
424                 // When collecting property names and parent is prop there is no need
425                 // to handle the content of this property deeper (evtl. preparations)
426             }
427             else
428             {
429                 switch(mpContext->getWebDAVNamespace())
430                 {
431                     default: // WebDAVNamespace_unknown, WebDAVNamespace_last or unhandled
432                     {
433                         break;
434                     }
435                     case WebDAVNamespace_DAV:
436                     {
437                         switch(mpContext->getWebDAVName())
438                         {
439                             default: // WebDAVName_unknown, WebDAVName_last or unhandled
440                             {
441                                 break;
442                             }
443                             case WebDAVName_propstat:
444                             {
445                                 // propstat start
446                                 if(isCollectingProperties())
447                                 {
448                                     // reset maPropStatProperties
449                                     maPropStatProperties.clear();
450                                 }
451                                 else
452                                 {
453                                     // when collecting properties reset maPropStatNames
454                                     maPropStatNames.clear();
455                                 }
456                                 break;
457                             }
458                             case WebDAVName_response:
459                             {
460                                 // response start, reset Href and status and maResponseProperties
461                                 maHref = maStatus = ::rtl::OUString();
462 
463                                 if(isCollectingProperties())
464                                 {
465                                     // reset maResponseProperties
466                                     maResponseProperties.clear();
467                                 }
468                                 else
469                                 {
470                                     // reset maResponseNames when collecting properties
471                                     maResponseNames.clear();
472                                 }
473                                 break;
474                             }
475                             case WebDAVName_resourcetype:
476                             {
477                                 // resourcetype start, reset collection
478                                 mbResourceTypeCollection = false;
479                                 break;
480                             }
481                             case WebDAVName_supportedlock:
482                             {
483                                 // supportedlock start, reset maLockEntries
484                                 maLockEntries.realloc(0);
485                                 break;
486                             }
487                             case WebDAVName_lockentry:
488                             {
489                                 // lockentry start, reset maLockEntries
490                                 mbLockScopeSet = false;
491                                 mbLockTypeSet = false;
492                                 break;
493                             }
494                         }
495                         break;
496                     }
497                     case WebDAVNamespace_ucb_openoffice_org_dav_props:
498                     {
499                         break;
500                     }
501                 }
502             }
503         }
504     }
505 
506     void SAL_CALL WebDAVResponseParser::endElement( const ::rtl::OUString& aName ) throw (xml::sax::SAXException, uno::RuntimeException)
507     {
508         const sal_Int32 nLen(aName.getLength());
509         OSL_ENSURE(mpContext, "Parser EndElement without content (!)");
510 
511         if(mpContext && nLen)
512         {
513             if(collectThisPropertyAsName())
514             {
515                 // When collecting property names and parent is prop, just append the prop name
516                 // to the collection, no need to parse deeper
517                 maPropStatNames.push_back(mpContext->getNamespace() + mpContext->getName());
518             }
519             else
520             {
521                 switch(mpContext->getWebDAVNamespace())
522                 {
523                     default: // WebDAVNamespace_unknown, WebDAVNamespace_last or unhandled
524                     {
525                         break;
526                     }
527                     case WebDAVNamespace_DAV:
528                     {
529                         switch(mpContext->getWebDAVName())
530                         {
531                             default: // WebDAVName_unknown, WebDAVName_last or unhandled
532                             {
533                                 break;
534                             }
535                             case WebDAVName_href:
536                             {
537                                 // href end, save it if we have whitespace
538                                 if(whitespaceIsAvailable())
539                                 {
540                                     maHref = mpContext->getWhiteSpace();
541                                 }
542                                 break;
543                             }
544                             case WebDAVName_status:
545                             {
546                                 // status end, save it if we have whitespace
547                                 if(whitespaceIsAvailable())
548                                 {
549                                     maStatus = mpContext->getWhiteSpace();
550                                 }
551                                 break;
552                             }
553                             case WebDAVName_getlastmodified:
554                             {
555                                 // getlastmodified end, safe if content is correct
556                                 if(propertyIsReady())
557                                 {
558                                     static rtl::OUString aStr(rtl::OUString::createFromAscii("DAV:getlastmodified"));
559                                     http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
560 
561                                     aDAVPropertyValue.Name = aStr;
562                                     aDAVPropertyValue.Value <<= mpContext->getWhiteSpace();
563                                     maPropStatProperties.push_back(aDAVPropertyValue);
564                                 }
565                                 break;
566                             }
567                             case WebDAVName_creationdate:
568                             {
569                                 // creationdate end, safe if content is correct
570                                 if(propertyIsReady())
571                                 {
572                                     static rtl::OUString aStr(rtl::OUString::createFromAscii("DAV:creationdate"));
573                                     http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
574 
575                                     aDAVPropertyValue.Name = aStr;
576                                     aDAVPropertyValue.Value <<= mpContext->getWhiteSpace();
577                                     maPropStatProperties.push_back(aDAVPropertyValue);
578                                 }
579                                 break;
580                             }
581                             case WebDAVName_collection:
582                             {
583                                 // collection end, check and set
584                                 if(hasParent(WebDAVName_resourcetype))
585                                 {
586                                     mbResourceTypeCollection = true;
587                                 }
588                                 break;
589                             }
590                             case WebDAVName_resourcetype:
591                             {
592                                 // resourcetype end, check for collection
593                                 if(hasParent(WebDAVName_prop))
594                                 {
595                                     static rtl::OUString aStrA(rtl::OUString::createFromAscii("DAV:resourcetype"));
596                                     static rtl::OUString aStrB(rtl::OUString::createFromAscii("collection"));
597                                     http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
598 
599                                     aDAVPropertyValue.Name = aStrA;
600                                     aDAVPropertyValue.Value <<= (mbResourceTypeCollection ? aStrB : rtl::OUString());
601                                     maPropStatProperties.push_back(aDAVPropertyValue);
602                                 }
603                                 break;
604                             }
605                             case WebDAVName_getcontentlength:
606                             {
607                                 // getcontentlength end, safe if content is correct
608                                 if(propertyIsReady())
609                                 {
610                                     static rtl::OUString aStr(rtl::OUString::createFromAscii("DAV:getcontentlength"));
611                                     http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
612 
613                                     aDAVPropertyValue.Name = aStr;
614                                     aDAVPropertyValue.Value <<= mpContext->getWhiteSpace();
615                                     maPropStatProperties.push_back(aDAVPropertyValue);
616                                 }
617                                 break;
618                             }
619                             case WebDAVName_getcontenttype:
620                             {
621                                 // getcontenttype end, safe if content is correct
622                                 if(propertyIsReady())
623                                 {
624                                     static rtl::OUString aStr(rtl::OUString::createFromAscii("DAV:getcontenttype"));
625                                     http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
626 
627                                     aDAVPropertyValue.Name = aStr;
628                                     aDAVPropertyValue.Value <<= mpContext->getWhiteSpace();
629                                     maPropStatProperties.push_back(aDAVPropertyValue);
630                                 }
631                                 break;
632                             }
633                             case WebDAVName_supportedlock:
634                             {
635                                 // supportedlock end
636                                 if(hasParent(WebDAVName_prop) && maLockEntries.hasElements())
637                                 {
638                                     static rtl::OUString aStr(rtl::OUString::createFromAscii("DAV:supportedlock"));
639                                     http_dav_ucp::DAVPropertyValue aDAVPropertyValue;
640 
641                                     aDAVPropertyValue.Name = aStr;
642                                     aDAVPropertyValue.Value <<= maLockEntries;
643                                     maPropStatProperties.push_back(aDAVPropertyValue);
644                                 }
645                                 break;
646                             }
647                             case WebDAVName_lockentry:
648                             {
649                                 // lockentry end
650                                 if(hasParent(WebDAVName_supportedlock) && (mbLockScopeSet && mbLockTypeSet))
651                                 {
652                                     const sal_Int32 nLength(maLockEntries.getLength());
653                                     ucb::LockEntry aEntry;
654 
655                                     aEntry.Scope = maLockScope;
656                                     aEntry.Type = maLockType;
657                                     maLockEntries.realloc(nLength + 1);
658                                     maLockEntries[nLength] = aEntry;
659                                 }
660                                 break;
661                             }
662                             case WebDAVName_exclusive:
663                             {
664                                 // exclusive lockscope end
665                                 if(hasParent(WebDAVName_lockscope))
666                                 {
667                                     maLockScope = ucb::LockScope_EXCLUSIVE;
668                                     mbLockScopeSet = true;
669                                 }
670                                 break;
671                             }
672                             case WebDAVName_shared:
673                             {
674                                 // shared lockscope end
675                                 if(hasParent(WebDAVName_lockscope))
676                                 {
677                                     maLockScope = ucb::LockScope_SHARED;
678                                     mbLockScopeSet = true;
679                                 }
680                                 break;
681                             }
682                             case WebDAVName_write:
683                             {
684                                 // write locktype end
685                                 if(hasParent(WebDAVName_locktype))
686                                 {
687                                     maLockType = ucb::LockType_WRITE;
688                                     mbLockTypeSet = true;
689                                 }
690                                 break;
691                             }
692                             case WebDAVName_propstat:
693                             {
694                                 // propstat end, check status
695                                 if(maStatus.getLength())
696                                 {
697                                     static ::rtl::OUString aStrStatusOkay(::rtl::OUString::createFromAscii("HTTP/1.1 200 OK"));
698 
699                                     if(maStatus.equals(aStrStatusOkay))
700                                     {
701                                         if(isCollectingProperties())
702                                         {
703                                             if(maPropStatProperties.size())
704                                             {
705                                                 // append to maResponseProperties if okay
706                                                 maResponseProperties.insert(maResponseProperties.end(), maPropStatProperties.begin(), maPropStatProperties.end());
707                                             }
708                                         }
709                                         else
710                                         {
711                                             if(maPropStatNames.size())
712                                             {
713                                                 // when collecting properties append to
714                                                 maResponseNames.insert(maResponseNames.end(), maPropStatNames.begin(), maPropStatNames.end());
715                                             }
716                                         }
717                                     }
718                                 }
719                                 break;
720                             }
721                             case WebDAVName_response:
722                             {
723                                 // respose end
724                                 if(maHref.getLength())
725                                 {
726                                     if(isCollectingProperties())
727                                     {
728                                         // create DAVResource when we have content
729                                         if(maResponseProperties.size())
730                                         {
731                                             http_dav_ucp::DAVResource aDAVResource;
732 
733                                             aDAVResource.uri = maHref;
734                                             aDAVResource.properties = maResponseProperties;
735                                             maResult_PropFind.push_back(aDAVResource);
736                                         }
737                                     }
738                                     else
739                                     {
740                                         // when collecting properties add them to result when there are some
741                                         if(maResponseNames.size())
742                                         {
743                                             http_dav_ucp::DAVResourceInfo aDAVResourceInfo(maHref);
744 
745                                             aDAVResourceInfo.properties = maResponseNames;
746                                             maResult_PropName.push_back(aDAVResourceInfo);
747                                         }
748                                     }
749                                 }
750                                 break;
751                             }
752                         }
753                         break;
754                     }
755                     case WebDAVNamespace_ucb_openoffice_org_dav_props:
756                     {
757                         break;
758                     }
759                 }
760             }
761 
762             // destroy last context (pop)
763             pop_context();
764         }
765     }
766 
767     void SAL_CALL WebDAVResponseParser::characters( const ::rtl::OUString& aChars ) throw (xml::sax::SAXException, uno::RuntimeException)
768     {
769         // collect whitespace over evtl. several calls in mpContext
770         OSL_ENSURE(mpContext, "Parser characters without content (!)");
771         const sal_Int32 nLen(aChars.getLength());
772 
773         if(mpContext && nLen)
774         {
775             // remove leading/trailing blanks and CRLF
776             const ::rtl::OUString aTrimmedChars(aChars.trim());
777 
778             if(aTrimmedChars.getLength())
779             {
780                 ::rtl::OUString aNew(mpContext->getWhiteSpace());
781 
782                 if(aNew.getLength())
783                 {
784                     // add one char when appending (see html1.1 spec)
785                     aNew += ::rtl::OUString(sal_Unicode(' '));
786                 }
787 
788                 aNew += aTrimmedChars;
789                 mpContext->setWhiteSpace(aNew);
790             }
791         }
792     }
793 
794     void SAL_CALL WebDAVResponseParser::ignorableWhitespace( const ::rtl::OUString& /*aWhitespaces*/ ) throw (xml::sax::SAXException, uno::RuntimeException)
795     {
796     }
797 
798     void SAL_CALL WebDAVResponseParser::processingInstruction( const ::rtl::OUString& /*aTarget*/, const ::rtl::OUString& /*aData*/ ) throw (xml::sax::SAXException, uno::RuntimeException)
799     {
800     }
801 
802     void SAL_CALL WebDAVResponseParser::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& /*xLocator*/ ) throw (xml::sax::SAXException, uno::RuntimeException)
803     {
804     }
805 } // end of anonymous namespace
806 
807 //////////////////////////////////////////////////////////////////////////////
808 // wrapper for various calls to the parser
809 
810 namespace
811 {
812     void parseWebDAVPropNameResponse(
813         const uno::Reference< io::XInputStream >& xInputStream,
814         std::vector< http_dav_ucp::DAVResource >& rPropFind,
815         std::vector< http_dav_ucp::DAVResourceInfo >& rPropName,
816         WebDAVResponseParserMode eWebDAVResponseParserMode)
817     {
818         if(xInputStream.is())
819         {
820             try
821             {
822                 // prepare ParserInputSrouce
823                 xml::sax::InputSource myInputSource;
824                 myInputSource.aInputStream = xInputStream;
825 
826                 // get parser
827                 uno::Reference< xml::sax::XParser > xParser(
828                     comphelper::getProcessServiceFactory()->createInstance(
829                         rtl::OUString::createFromAscii("com.sun.star.xml.sax.Parser") ),
830                     uno::UNO_QUERY_THROW );
831 
832                 // create parser; connect parser and filter
833                 WebDAVResponseParser* pWebDAVResponseParser = new WebDAVResponseParser(eWebDAVResponseParserMode);
834                 uno::Reference< xml::sax::XDocumentHandler > xWebDAVHdl(pWebDAVResponseParser);
835                 xParser->setDocumentHandler(xWebDAVHdl);
836 
837                 // finally, parse the stream
838                 xParser->parseStream(myInputSource);
839 
840                 // get result
841                 switch(eWebDAVResponseParserMode)
842                 {
843                     case WebDAVResponseParserMode_PropFind:
844                     {
845                         rPropFind = pWebDAVResponseParser->getResult_PropFind();
846                         break;
847                     }
848                     case WebDAVResponseParserMode_PropName:
849                     {
850                         rPropName = pWebDAVResponseParser->getResult_PropName();
851                         break;
852                     }
853                 }
854             }
855             catch(uno::Exception&)
856             {
857                 OSL_ENSURE(false, "WebDAV Parse error (!)");
858             }
859         }
860     }
861 } // end of anonymous namespace
862 
863 //////////////////////////////////////////////////////////////////////////////
864 // helper to parse a XML WebDAV response
865 
866 namespace http_dav_ucp
867 {
868     std::vector< DAVResource > parseWebDAVPropFindResponse(const uno::Reference< io::XInputStream >& xInputStream)
869     {
870         std::vector< DAVResource > aRetval;
871         std::vector< DAVResourceInfo > aFoo;
872 
873         parseWebDAVPropNameResponse(xInputStream, aRetval, aFoo, WebDAVResponseParserMode_PropFind);
874         return aRetval;
875     }
876 
877     std::vector< DAVResourceInfo > parseWebDAVPropNameResponse(const uno::Reference< io::XInputStream >& xInputStream)
878     {
879         std::vector< DAVResource > aFoo;
880         std::vector< DAVResourceInfo > aRetval;
881 
882         parseWebDAVPropNameResponse(xInputStream, aFoo, aRetval, WebDAVResponseParserMode_PropName);
883         return aRetval;
884     }
885 } // namespace http_dav_ucp
886 
887 //////////////////////////////////////////////////////////////////////////////
888 // eof
889