LibreOffice Module ucb (master) 1
ContentProperties.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <memory>
21#include <com/sun/star/util/DateTime.hpp>
22#include "CurlUri.hxx"
23#include "DAVResource.hxx"
24#include "DAVProperties.hxx"
25#include "DateTimeHelper.hxx"
26#include "webdavprovider.hxx"
27#include "ContentProperties.hxx"
28#include <o3tl/string_view.hxx>
29
30using namespace com::sun::star;
31using namespace http_dav_ucp;
32
33/*
34=============================================================================
35
36 Property Mapping
37
38=============================================================================
39HTTP (entity header) WebDAV (property) UCB (property)
40=============================================================================
41
42Allow
43Content-Encoding
44Content-Language getcontentlanguage
45Content-Length getcontentlength Size
46Content-Location
47Content-MD5
48Content-Range
49Content-Type getcontenttype MediaType
50Expires
51Last-Modified getlastmodified DateModified
52 creationdate DateCreated
53 resourcetype IsFolder,IsDocument,ContentType
54 displayname
55ETag (actually getetag
56a response header )
57 lockdiscovery
58 supportedlock
59 source
60 Title (always taken from URI)
61
62=============================================================================
63
64Important: HTTP headers will not be mapped to DAV properties; only to UCB
65 properties. (Content-Length,Content-Type,Last-Modified)
66*/
67
68
69// ContentProperties Implementation.
70
71
72// static member!
73uno::Any ContentProperties::m_aEmptyAny;
74
75ContentProperties::ContentProperties( const DAVResource& rResource )
77 m_bTrailingSlash( false )
78{
79 assert(!rResource.uri.isEmpty() &&
80 "ContentProperties ctor - Empty resource URI!");
81
82 // Title
83 try
84 {
85 CurlUri const aURI( rResource.uri );
87
88 (*m_xProps)[ OUString( "Title" ) ]
90 uno::Any( aURI.GetPathBaseNameUnescaped() ), true );
91 }
92 catch ( DAVException const & )
93 {
94 (*m_xProps)[ OUString( "Title" ) ]
97 OUString( "*** unknown ***" ) ),
98 true );
99 }
100
101 for ( const auto& rProp : rResource.properties )
102 {
103 addProperty( rProp );
104 }
105
106 if ( rResource.uri.endsWith("/") )
107 m_bTrailingSlash = true;
108}
109
110
112 const OUString & rTitle, bool bFolder )
114 m_bTrailingSlash( false )
115{
116 (*m_xProps)[ OUString( "Title" ) ]
117 = PropertyValue( uno::Any( rTitle ), true );
118 (*m_xProps)[ OUString( "IsFolder" ) ]
119 = PropertyValue( uno::Any( bFolder ), true );
120 (*m_xProps)[ OUString( "IsDocument" ) ]
121 = PropertyValue( uno::Any( bool( !bFolder ) ), true );
122}
123
124
125ContentProperties::ContentProperties( const OUString & rTitle )
127 m_bTrailingSlash( false )
128{
129 (*m_xProps)[ OUString( "Title" ) ]
130 = PropertyValue( uno::Any( rTitle ), true );
131}
132
133
136 m_bTrailingSlash( false )
137{
138}
139
140
142: m_aEscapedTitle( rOther.m_aEscapedTitle ),
143 m_xProps( rOther.m_xProps
144 ? new PropertyValueMap( *rOther.m_xProps )
145 : new PropertyValueMap ),
146 m_bTrailingSlash( rOther.m_bTrailingSlash )
147{
148}
149
150
151bool ContentProperties::contains( const OUString & rName ) const
152{
153 if ( get( rName ) )
154 return true;
155 else
156 return false;
157}
158
159
161 const OUString & rName ) const
162{
163 const PropertyValue * pProp = get( rName );
164 if ( pProp )
165 return pProp->value();
166 else
167 return m_aEmptyAny;
168}
169
170
172 const OUString & rName ) const
173{
174 PropertyValueMap::const_iterator it = m_xProps->find( rName );
175 const PropertyValueMap::const_iterator end = m_xProps->end();
176
177 if ( it == end )
178 {
179 it = std::find_if(m_xProps->cbegin(), end,
180 [&rName](const PropertyValueMap::value_type& rEntry) {
181 return rEntry.first.equalsIgnoreAsciiCase( rName );
182 });
183 if ( it != end )
184 return &(*it).second;
185
186 return nullptr;
187 }
188 else
189 return &(*it).second;
190}
191
192
193// static
195 const uno::Sequence< beans::Property > & rProps,
196 std::vector< OUString > & propertyNames )
197{
198
199 // Assemble list of DAV properties to obtain from server.
200 // Append DAV properties needed to obtain requested UCB props.
201
202
203 // DAV UCB
204 // creationdate <- DateCreated
205 // getlastmodified <- DateModified
206 // getcontenttype <- MediaType
207 // getcontentlength <- Size
208 // resourcetype <- IsFolder, IsDocument, ContentType
209 // (taken from URI) <- Title
210
211 bool bCreationDate = false;
212 bool bLastModified = false;
213 bool bContentType = false;
214 bool bContentLength = false;
215 bool bResourceType = false;
216
217 sal_Int32 nCount = rProps.getLength();
218 for ( sal_Int32 n = 0; n < nCount; ++n )
219 {
220 const beans::Property & rProp = rProps[ n ];
221
222 if ( rProp.Name == "Title" )
223 {
224 // Title is always obtained from resource's URI.
225 continue;
226 }
227 else if ( rProp.Name == "DateCreated" ||
228 ( rProp.Name == DAVProperties::CREATIONDATE ) )
229 {
230 if ( !bCreationDate )
231 {
232 propertyNames.push_back( DAVProperties::CREATIONDATE );
233 bCreationDate = true;
234 }
235 }
236 else if ( rProp.Name == "DateModified" ||
237 ( rProp.Name == DAVProperties::GETLASTMODIFIED ) )
238 {
239 if ( !bLastModified )
240 {
241 propertyNames.push_back(
243 bLastModified = true;
244 }
245 }
246 else if ( rProp.Name == "MediaType" ||
247 ( rProp.Name == DAVProperties::GETCONTENTTYPE ) )
248 {
249 if ( !bContentType )
250 {
251 propertyNames.push_back(
253 bContentType = true;
254 }
255 }
256 else if ( rProp.Name == "Size" ||
257 ( rProp.Name == DAVProperties::GETCONTENTLENGTH ) )
258 {
259 if ( !bContentLength )
260 {
261 propertyNames.push_back(
263 bContentLength = true;
264 }
265 }
266 else if ( rProp.Name == "ContentType" ||
267 rProp.Name == "IsDocument" ||
268 rProp.Name == "IsFolder" ||
269 ( rProp.Name == DAVProperties::RESOURCETYPE ) )
270 {
271 if ( !bResourceType )
272 {
273 propertyNames.push_back( DAVProperties::RESOURCETYPE );
274 bResourceType = true;
275 }
276 }
277 else
278 {
279 propertyNames.push_back( rProp.Name );
280 }
281 }
282}
283
284
285// static
287 const uno::Sequence< beans::Property > & rProps,
288 std::vector< OUString > & propertyNames )
289{
290
291 // Assemble list of HTTP header names to obtain from server.
292 // Append HTTP headers needed to obtain requested UCB props.
293
294
295 // HTTP UCB
296 // Last-Modified <- DateModified
297 // Content-Type <- MediaType
298 // Content-Length <- Size
299
300 sal_Int32 nCount = rProps.getLength();
301 for ( sal_Int32 n = 0; n < nCount; ++n )
302 {
303 const beans::Property & rProp = rProps[ n ];
304
305 if ( rProp.Name == "DateModified" )
306 {
307 propertyNames.push_back( OUString( "Last-Modified" ) );
308 }
309 else if ( rProp.Name == "MediaType" )
310 {
311 propertyNames.push_back( OUString( "Content-Type" ) );
312 }
313 else if ( rProp.Name == "Size" )
314 {
315 propertyNames.push_back( OUString( "Content-Length" ) );
316 }
317 else
318 {
319 propertyNames.push_back( rProp.Name );
320 }
321 }
322}
323
324
326 const uno::Sequence< beans::Property >& rProps,
327 std::vector< OUString > & rNamesNotContained ) const
328{
329 rNamesNotContained.clear();
330
331 sal_Int32 nCount = rProps.getLength();
332 for ( sal_Int32 n = 0; n < nCount; ++n )
333 {
334 const OUString & rName = rProps[ n ].Name;
335 if ( !contains( rName ) )
336 {
337 // Not found.
338 rNamesNotContained.push_back( rName );
339 }
340 }
341
342 return ( rNamesNotContained.size() == 0 );
343}
344
345
347 const std::vector< OUString > & rProps,
348 const ContentProperties & rContentProps )
349{
350 for ( const OUString & rName : rProps )
351 {
352 if ( !contains( rName ) ) // ignore duplicates
353 {
354 const PropertyValue * pProp = rContentProps.get( rName );
355 if ( pProp )
356 {
357 // Add it.
358 addProperty( rName, pProp->value(), pProp->isCaseSensitive() );
359 }
360 else
361 {
362 addProperty( rName, uno::Any(), false );
363 }
364 }
365 }
366}
367
369{
370 addProperty( rProp.Name, rProp.Value, rProp.IsCaseSensitive );
371}
372
373
374void ContentProperties::addProperty( const OUString & rName,
375 const css::uno::Any & rValue,
376 bool bIsCaseSensitive )
377{
378 if ( rName == DAVProperties::CREATIONDATE )
379 {
380 // Map DAV:creationdate to UCP:DateCreated
381 OUString aValue;
382 rValue >>= aValue;
383 util::DateTime aDate;
384 DateTimeHelper::convert( aValue, aDate );
385
386 (*m_xProps)[ OUString( "DateCreated" ) ]
387 = PropertyValue( uno::Any( aDate ), true );
388 }
389 // else if ( rName.equals( DAVProperties::DISPLAYNAME ) )
390 // {
391 // }
392 // else if ( rName.equals( DAVProperties::GETCONTENTLANGUAGE ) )
393 // {
394 // }
395 else if ( rName == DAVProperties::GETCONTENTLENGTH )
396 {
397 // Map DAV:getcontentlength to UCP:Size
398 OUString aValue;
399 rValue >>= aValue;
400
401 (*m_xProps)[ OUString( "Size" ) ]
402 = PropertyValue( uno::Any( aValue.toInt64() ), true );
403 }
404 else if ( rName.equalsIgnoreAsciiCase( "Content-Length" ) )
405 {
406 // Do NOT map Content-Length entity header to DAV:getcontentlength!
407 // Only DAV resources have this property.
408
409 // Map Content-Length entity header to UCP:Size
410 OUString aValue;
411 rValue >>= aValue;
412
413 (*m_xProps)[ OUString( "Size" ) ]
414 = PropertyValue( uno::Any( aValue.toInt64() ), true );
415 }
416 else if ( rName == DAVProperties::GETCONTENTTYPE )
417 {
418 // Map DAV:getcontenttype to UCP:MediaType (1:1)
419 (*m_xProps)[ OUString( "MediaType" ) ]
420 = PropertyValue( rValue, true );
421 }
422 else if ( rName.equalsIgnoreAsciiCase( "Content-Type" ) )
423 {
424 // Do NOT map Content-Type entity header to DAV:getcontenttype!
425 // Only DAV resources have this property.
426
427 // Map DAV:getcontenttype to UCP:MediaType (1:1)
428 (*m_xProps)[ OUString( "MediaType" ) ]
429 = PropertyValue( rValue, true );
430 }
431 // else if ( rName.equals( DAVProperties::GETETAG ) )
432 // {
433 // }
434 else if ( rName == DAVProperties::GETLASTMODIFIED )
435 {
436 // Map the DAV:getlastmodified entity header to UCP:DateModified
437 OUString aValue;
438 rValue >>= aValue;
439 util::DateTime aDate;
440 DateTimeHelper::convert( aValue, aDate );
441
442 (*m_xProps)[ OUString( "DateModified" ) ]
443 = PropertyValue( uno::Any( aDate ), true );
444 }
445 else if ( rName.equalsIgnoreAsciiCase( "Last-Modified" ) )
446 {
447 // Do not map Last-Modified entity header to DAV:getlastmodified!
448 // Only DAV resources have this property.
449
450 // Map the Last-Modified entity header to UCP:DateModified
451 OUString aValue;
452 rValue >>= aValue;
453 util::DateTime aDate;
454 DateTimeHelper::convert( aValue, aDate );
455
456 (*m_xProps)[ OUString( "DateModified" ) ]
457 = PropertyValue( uno::Any( aDate ), true );
458 }
459 // else if ( rName.equals( DAVProperties::LOCKDISCOVERY ) )
460 // {
461 // }
462 else if ( rName == DAVProperties::RESOURCETYPE )
463 {
464 OUString aValue;
465 rValue >>= aValue;
466
467 // Map DAV:resourcetype to UCP:IsFolder, UCP:IsDocument, UCP:ContentType
468 bool bFolder =
469 aValue.equalsIgnoreAsciiCase( "collection" );
470
471 (*m_xProps)[ OUString( "IsFolder" ) ]
472 = PropertyValue( uno::Any( bFolder ), true );
473 (*m_xProps)[ OUString( "IsDocument" ) ]
474 = PropertyValue( uno::Any( bool( !bFolder ) ), true );
475 (*m_xProps)[ OUString( "ContentType" ) ]
476 = PropertyValue( uno::Any( bFolder
477 ? OUString( WEBDAV_COLLECTION_TYPE )
478 : OUString( WEBDAV_CONTENT_TYPE ) ), true );
479 }
480 // else if ( rName.equals( DAVProperties::SUPPORTEDLOCK ) )
481 // {
482 // }
483
484 // Save property.
485 (*m_xProps)[ rName ] = PropertyValue( rValue, bIsCaseSensitive );
486}
487
488
489// CachableContentProperties Implementation.
490
491
492namespace
493{
494 bool isCachable( std::u16string_view rName, bool isCaseSensitive )
495 {
496 const OUString aNonCachableProps [] =
497 {
499
501 OUString( "ETag" ),
502
503 OUString( "DateModified" ),
504 OUString( "Last-Modified" ),
506
507 OUString( "Size" ),
508 OUString( "Content-Length" ),
510
511 OUString( "Date" )
512 };
513
514 for ( sal_uInt32 n = 0;
515 n < ( sizeof( aNonCachableProps )
516 / sizeof( aNonCachableProps[ 0 ] ) );
517 ++n )
518 {
519 if ( isCaseSensitive )
520 {
521 if ( rName == aNonCachableProps[ n ] )
522 return false;
523 }
524 else
525 if ( o3tl::equalsIgnoreAsciiCase( rName, aNonCachableProps[ n ] ) )
526 return false;
527 }
528 return true;
529 }
530
531} // namespace
532
533
535 const ContentProperties & rProps )
536{
537 addProperties( rProps );
538}
539
540
542 const ContentProperties & rProps )
543{
544 const std::unique_ptr< PropertyValueMap > & props = rProps.getProperties();
545
546 for ( const auto& rProp : *props )
547 {
548 if ( isCachable( rProp.first, rProp.second.isCaseSensitive() ) )
549 m_aProps.addProperty( rProp.first,
550 rProp.second.value(),
551 rProp.second.isCaseSensitive() );
552 }
553}
554
555
557 const std::vector< DAVPropertyValue > & rProps )
558{
559 for ( const auto& rProp : rProps )
560 {
561 if ( isCachable( rProp.Name, rProp.IsCaseSensitive ) )
562 m_aProps.addProperty( rProp );
563 }
564}
565
566/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XPropertySet > m_xProps
CachableContentProperties(const CachableContentProperties &)
void addProperties(const ContentProperties &rProps)
void addProperty(const OUString &rName, const css::uno::Any &rValue, bool bIsCaseSensitive)
bool contains(const OUString &rName) const
const std::unique_ptr< PropertyValueMap > & getProperties() const
const PropertyValue * get(const OUString &rName) const
void addProperties(const std::vector< OUString > &rProps, const ContentProperties &rContentProps)
std::unique_ptr< PropertyValueMap > m_xProps
bool containsAllNames(const css::uno::Sequence< css::beans::Property > &rProps, std::vector< OUString > &rNamesNotContained) const
static void UCBNamesToDAVNames(const css::uno::Sequence< css::beans::Property > &rProps, std::vector< OUString > &resources)
const css::uno::Any & getValue(const OUString &rName) const
static void UCBNamesToHTTPNames(const css::uno::Sequence< css::beans::Property > &rProps, std::vector< OUString > &resources)
OUString GetPathBaseName() const
Definition: CurlUri.cxx:182
OUString GetPathBaseNameUnescaped() const
Definition: CurlUri.cxx:199
static bool convert(std::u16string_view, css::util::DateTime &)
const css::uno::Any & value() const
int nCount
sal_Int64 n
std::unordered_map< OUString, PropertyValue > PropertyValueMap
constexpr OUStringLiteral WEBDAV_COLLECTION_TYPE
bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
end
dictionary props
static constexpr OUStringLiteral GETCONTENTTYPE
static constexpr OUStringLiteral CREATIONDATE
static constexpr OUStringLiteral GETETAG
static constexpr OUStringLiteral LOCKDISCOVERY
static constexpr OUStringLiteral RESOURCETYPE
static constexpr OUStringLiteral GETCONTENTLENGTH
static constexpr OUStringLiteral GETLASTMODIFIED
std::vector< DAVPropertyValue > properties
Definition: DAVResource.hxx:43
#define WEBDAV_CONTENT_TYPE