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 "SerfUri.hxx"
23 #include "DAVResource.hxx"
24 #include "DAVProperties.hxx"
25 #include "DateTimeHelper.hxx"
26 #include "webdavprovider.hxx"
27 #include "ContentProperties.hxx"
28 
29 #include <sal/log.hxx>
30 
31 using namespace com::sun::star;
32 using namespace http_dav_ucp;
33 
34 /*
35 =============================================================================
36 
37  Property Mapping
38 
39 =============================================================================
40 HTTP (entity header) WebDAV (property) UCB (property)
41 =============================================================================
42 
43 Allow
44 Content-Encoding
45 Content-Language getcontentlanguage
46 Content-Length getcontentlength Size
47 Content-Location
48 Content-MD5
49 Content-Range
50 Content-Type getcontenttype MediaType
51 Expires
52 Last-Modified getlastmodified DateModified
53  creationdate DateCreated
54  resourcetype IsFolder,IsDocument,ContentType
55  displayname
56 ETag (actually getetag
57 a response header )
58  lockdiscovery
59  supportedlock
60  source
61  Title (always taken from URI)
62 
63 =============================================================================
64 
65 Important: HTTP headers will not be mapped to DAV properties; only to UCB
66  properties. (Content-Length,Content-Type,Last-Modified)
67 */
68 
69 
70 // ContentProperties Implementation.
71 
72 
73 // static member!
74 uno::Any ContentProperties::m_aEmptyAny;
75 
76 ContentProperties::ContentProperties( const DAVResource& rResource )
77 : m_xProps( new PropertyValueMap ),
78  m_bTrailingSlash( false )
79 {
80  SAL_WARN_IF( !rResource.uri.getLength(), "ucb.ucp.webdav",
81  "ContentProperties ctor - Empty resource URI!" );
82 
83  // Title
84  try
85  {
86  SerfUri aURI( rResource.uri );
88 
89  (*m_xProps)[ OUString( "Title" ) ]
90  = PropertyValue(
91  uno::makeAny( aURI.GetPathBaseNameUnescaped() ), true );
92  }
93  catch ( DAVException const & )
94  {
95  (*m_xProps)[ OUString( "Title" ) ]
96  = PropertyValue(
97  uno::makeAny(
98  OUString( "*** unknown ***" ) ),
99  true );
100  }
101 
102  for ( const auto& rProp : rResource.properties )
103  {
104  addProperty( rProp );
105  }
106 
107  if ( rResource.uri.endsWith("/") )
108  m_bTrailingSlash = true;
109 }
110 
111 
113  const OUString & rTitle, bool bFolder )
114 : m_xProps( new PropertyValueMap ),
115  m_bTrailingSlash( false )
116 {
117  (*m_xProps)[ OUString( "Title" ) ]
118  = PropertyValue( uno::makeAny( rTitle ), true );
119  (*m_xProps)[ OUString( "IsFolder" ) ]
120  = PropertyValue( uno::makeAny( bFolder ), true );
121  (*m_xProps)[ OUString( "IsDocument" ) ]
122  = PropertyValue( uno::makeAny( bool( !bFolder ) ), true );
123 }
124 
125 
126 ContentProperties::ContentProperties( const OUString & rTitle )
127 : m_xProps( new PropertyValueMap ),
128  m_bTrailingSlash( false )
129 {
130  (*m_xProps)[ OUString( "Title" ) ]
131  = PropertyValue( uno::makeAny( rTitle ), true );
132 }
133 
134 
136 : m_xProps( new PropertyValueMap ),
137  m_bTrailingSlash( false )
138 {
139 }
140 
141 
143 : m_aEscapedTitle( rOther.m_aEscapedTitle ),
144  m_xProps( rOther.m_xProps.get()
145  ? new PropertyValueMap( *rOther.m_xProps )
146  : new PropertyValueMap ),
147  m_bTrailingSlash( rOther.m_bTrailingSlash )
148 {
149 }
150 
151 
152 bool ContentProperties::contains( const OUString & rName ) const
153 {
154  if ( get( rName ) )
155  return true;
156  else
157  return false;
158 }
159 
160 
162  const OUString & rName ) const
163 {
164  const PropertyValue * pProp = get( rName );
165  if ( pProp )
166  return pProp->value();
167  else
168  return m_aEmptyAny;
169 }
170 
171 
173  const OUString & rName ) const
174 {
175  PropertyValueMap::const_iterator it = m_xProps->find( rName );
176  const PropertyValueMap::const_iterator end = m_xProps->end();
177 
178  if ( it == end )
179  {
180  it = std::find_if(m_xProps->cbegin(), end,
181  [&rName](const PropertyValueMap::value_type& rEntry) {
182  return rEntry.first.equalsIgnoreAsciiCase( rName );
183  });
184  if ( it != end )
185  return &(*it).second;
186 
187  return nullptr;
188  }
189  else
190  return &(*it).second;
191 }
192 
193 
194 // static
196  const uno::Sequence< beans::Property > & rProps,
197  std::vector< OUString > & propertyNames,
198  bool bIncludeUnmatched /* = true */ )
199 {
200 
201  // Assemble list of DAV properties to obtain from server.
202  // Append DAV properties needed to obtain requested UCB props.
203 
204 
205  // DAV UCB
206  // creationdate <- DateCreated
207  // getlastmodified <- DateModified
208  // getcontenttype <- MediaType
209  // getcontentlength <- Size
210  // resourcetype <- IsFolder, IsDocument, ContentType
211  // (taken from URI) <- Title
212 
213  bool bCreationDate = false;
214  bool bLastModified = false;
215  bool bContentType = false;
216  bool bContentLength = false;
217  bool bResourceType = false;
218 
219  sal_Int32 nCount = rProps.getLength();
220  for ( sal_Int32 n = 0; n < nCount; ++n )
221  {
222  const beans::Property & rProp = rProps[ n ];
223 
224  if ( rProp.Name == "Title" )
225  {
226  // Title is always obtained from resource's URI.
227  continue;
228  }
229  else if ( rProp.Name == "DateCreated" ||
230  ( rProp.Name == DAVProperties::CREATIONDATE ) )
231  {
232  if ( !bCreationDate )
233  {
234  propertyNames.push_back( DAVProperties::CREATIONDATE );
235  bCreationDate = true;
236  }
237  }
238  else if ( rProp.Name == "DateModified" ||
239  ( rProp.Name == DAVProperties::GETLASTMODIFIED ) )
240  {
241  if ( !bLastModified )
242  {
243  propertyNames.push_back(
245  bLastModified = true;
246  }
247  }
248  else if ( rProp.Name == "MediaType" ||
249  ( rProp.Name == DAVProperties::GETCONTENTTYPE ) )
250  {
251  if ( !bContentType )
252  {
253  propertyNames.push_back(
255  bContentType = true;
256  }
257  }
258  else if ( rProp.Name == "Size" ||
259  ( rProp.Name == DAVProperties::GETCONTENTLENGTH ) )
260  {
261  if ( !bContentLength )
262  {
263  propertyNames.push_back(
265  bContentLength = true;
266  }
267  }
268  else if ( rProp.Name == "ContentType" ||
269  rProp.Name == "IsDocument" ||
270  rProp.Name == "IsFolder" ||
271  ( rProp.Name == DAVProperties::RESOURCETYPE ) )
272  {
273  if ( !bResourceType )
274  {
275  propertyNames.push_back( DAVProperties::RESOURCETYPE );
276  bResourceType = true;
277  }
278  }
279  else
280  {
281  if ( bIncludeUnmatched )
282  propertyNames.push_back( rProp.Name );
283  }
284  }
285 }
286 
287 
288 // static
290  const uno::Sequence< beans::Property > & rProps,
291  std::vector< OUString > & propertyNames,
292  bool bIncludeUnmatched /* = true */ )
293 {
294 
295  // Assemble list of HTTP header names to obtain from server.
296  // Append HTTP headers needed to obtain requested UCB props.
297 
298 
299  // HTTP UCB
300  // Last-Modified <- DateModified
301  // Content-Type <- MediaType
302  // Content-Length <- Size
303 
304  sal_Int32 nCount = rProps.getLength();
305  for ( sal_Int32 n = 0; n < nCount; ++n )
306  {
307  const beans::Property & rProp = rProps[ n ];
308 
309  if ( rProp.Name == "DateModified" )
310  {
311  propertyNames.push_back( OUString( "Last-Modified" ) );
312  }
313  else if ( rProp.Name == "MediaType" )
314  {
315  propertyNames.push_back( OUString( "Content-Type" ) );
316  }
317  else if ( rProp.Name == "Size" )
318  {
319  propertyNames.push_back( OUString( "Content-Length" ) );
320  }
321  else
322  {
323  if ( bIncludeUnmatched )
324  propertyNames.push_back( rProp.Name );
325  }
326  }
327 }
328 
329 
331  const uno::Sequence< beans::Property >& rProps,
332  std::vector< OUString > & rNamesNotContained ) const
333 {
334  rNamesNotContained.clear();
335 
336  sal_Int32 nCount = rProps.getLength();
337  for ( sal_Int32 n = 0; n < nCount; ++n )
338  {
339  const OUString & rName = rProps[ n ].Name;
340  if ( !contains( rName ) )
341  {
342  // Not found.
343  rNamesNotContained.push_back( rName );
344  }
345  }
346 
347  return ( rNamesNotContained.size() == 0 );
348 }
349 
350 
352  const std::vector< OUString > & rProps,
353  const ContentProperties & rContentProps )
354 {
355  for ( const OUString & rName : rProps )
356  {
357  if ( !contains( rName ) ) // ignore duplicates
358  {
359  const PropertyValue * pProp = rContentProps.get( rName );
360  if ( pProp )
361  {
362  // Add it.
363  addProperty( rName, pProp->value(), pProp->isCaseSensitive() );
364  }
365  else
366  {
367  addProperty( rName, uno::Any(), false );
368  }
369  }
370  }
371 }
372 
373 
375 {
376  for ( const auto& rProp : *rProps.m_xProps )
377  {
378  addProperty(
379  rProp.first, rProp.second.value(), rProp.second.isCaseSensitive() );
380  }
381 }
382 
383 
385  const std::vector< DAVPropertyValue > & rProps )
386 {
387  for ( const auto& rProp : rProps )
388  {
389  addProperty( rProp );
390  }
391 }
392 
393 
395 {
396  addProperty( rProp.Name, rProp.Value, rProp.IsCaseSensitive );
397 }
398 
399 
400 void ContentProperties::addProperty( const OUString & rName,
401  const css::uno::Any & rValue,
402  bool bIsCaseSensitive )
403 {
404  if ( rName == DAVProperties::CREATIONDATE )
405  {
406  // Map DAV:creationdate to UCP:DateCreated
407  OUString aValue;
408  rValue >>= aValue;
409  util::DateTime aDate;
410  DateTimeHelper::convert( aValue, aDate );
411 
412  (*m_xProps)[ OUString( "DateCreated" ) ]
413  = PropertyValue( uno::makeAny( aDate ), true );
414  }
415  // else if ( rName.equals( DAVProperties::DISPLAYNAME ) )
416  // {
417  // }
418  // else if ( rName.equals( DAVProperties::GETCONTENTLANGUAGE ) )
419  // {
420  // }
421  else if ( rName == DAVProperties::GETCONTENTLENGTH )
422  {
423  // Map DAV:getcontentlength to UCP:Size
424  OUString aValue;
425  rValue >>= aValue;
426 
427  (*m_xProps)[ OUString( "Size" ) ]
428  = PropertyValue( uno::makeAny( aValue.toInt64() ), true );
429  }
430  else if ( rName == "Content-Length" )
431  {
432  // Do NOT map Content-Length entity header to DAV:getcontentlength!
433  // Only DAV resources have this property.
434 
435  // Map Content-Length entity header to UCP:Size
436  OUString aValue;
437  rValue >>= aValue;
438 
439  (*m_xProps)[ OUString( "Size" ) ]
440  = PropertyValue( uno::makeAny( aValue.toInt64() ), true );
441  }
442  else if ( rName == DAVProperties::GETCONTENTTYPE )
443  {
444  // Map DAV:getcontenttype to UCP:MediaType (1:1)
445  (*m_xProps)[ OUString( "MediaType" ) ]
446  = PropertyValue( rValue, true );
447  }
448  else if ( rName == "Content-Type" )
449  {
450  // Do NOT map Content-Type entity header to DAV:getcontenttype!
451  // Only DAV resources have this property.
452 
453  // Map DAV:getcontenttype to UCP:MediaType (1:1)
454  (*m_xProps)[ OUString( "MediaType" ) ]
455  = PropertyValue( rValue, true );
456  }
457  // else if ( rName.equals( DAVProperties::GETETAG ) )
458  // {
459  // }
460  else if ( rName == DAVProperties::GETLASTMODIFIED )
461  {
462  // Map the DAV:getlastmodified entity header to UCP:DateModified
463  OUString aValue;
464  rValue >>= aValue;
465  util::DateTime aDate;
466  DateTimeHelper::convert( aValue, aDate );
467 
468  (*m_xProps)[ OUString( "DateModified" ) ]
469  = PropertyValue( uno::makeAny( aDate ), true );
470  }
471  else if ( rName == "Last-Modified" )
472  {
473  // Do not map Last-Modified entity header to DAV:getlastmodified!
474  // Only DAV resources have this property.
475 
476  // Map the Last-Modified entity header to UCP:DateModified
477  OUString aValue;
478  rValue >>= aValue;
479  util::DateTime aDate;
480  DateTimeHelper::convert( aValue, aDate );
481 
482  (*m_xProps)[ OUString( "DateModified" ) ]
483  = PropertyValue( uno::makeAny( aDate ), true );
484  }
485  // else if ( rName.equals( DAVProperties::LOCKDISCOVERY ) )
486  // {
487  // }
488  else if ( rName == DAVProperties::RESOURCETYPE )
489  {
490  OUString aValue;
491  rValue >>= aValue;
492 
493  // Map DAV:resourcetype to UCP:IsFolder, UCP:IsDocument, UCP:ContentType
494  bool bFolder =
495  aValue.equalsIgnoreAsciiCase( "collection" );
496 
497  (*m_xProps)[ OUString( "IsFolder" ) ]
498  = PropertyValue( uno::makeAny( bFolder ), true );
499  (*m_xProps)[ OUString( "IsDocument" ) ]
500  = PropertyValue( uno::makeAny( bool( !bFolder ) ), true );
501  (*m_xProps)[ OUString( "ContentType" ) ]
502  = PropertyValue( uno::makeAny( bFolder
503  ? OUString( WEBDAV_COLLECTION_TYPE )
504  : OUString( WEBDAV_CONTENT_TYPE ) ), true );
505  }
506  // else if ( rName.equals( DAVProperties::SUPPORTEDLOCK ) )
507  // {
508  // }
509 
510  // Save property.
511  (*m_xProps)[ rName ] = PropertyValue( rValue, bIsCaseSensitive );
512 }
513 
514 
515 // CachableContentProperties Implementation.
516 
517 
518 namespace
519 {
520  bool isCachable( OUString const & rName,
521  bool isCaseSensitive )
522  {
523  const OUString aNonCachableProps [] =
524  {
526 
528  OUString( "ETag" ),
529 
530  OUString( "DateModified" ),
531  OUString( "Last-Modified" ),
533 
534  OUString( "Size" ),
535  OUString( "Content-Length" ),
537 
538  OUString( "Date" )
539  };
540 
541  for ( sal_uInt32 n = 0;
542  n < ( sizeof( aNonCachableProps )
543  / sizeof( aNonCachableProps[ 0 ] ) );
544  ++n )
545  {
546  if ( isCaseSensitive )
547  {
548  if ( rName.equals( aNonCachableProps[ n ] ) )
549  return false;
550  }
551  else
552  if ( rName.equalsIgnoreAsciiCase( aNonCachableProps[ n ] ) )
553  return false;
554  }
555  return true;
556  }
557 
558 } // namespace
559 
560 
562  const ContentProperties & rProps )
563 {
564  addProperties( rProps );
565 }
566 
567 
569  const ContentProperties & rProps )
570 {
571  const std::unique_ptr< PropertyValueMap > & props = rProps.getProperties();
572 
573  for ( const auto& rProp : *props )
574  {
575  if ( isCachable( rProp.first, rProp.second.isCaseSensitive() ) )
576  m_aProps.addProperty( rProp.first,
577  rProp.second.value(),
578  rProp.second.isCaseSensitive() );
579  }
580 }
581 
582 
584  const std::vector< DAVPropertyValue > & rProps )
585 {
586  for ( const auto& rProp : rProps )
587  {
588  if ( isCachable( rProp.Name, rProp.IsCaseSensitive ) )
589  m_aProps.addProperty( rProp );
590  }
591 }
592 
593 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
#define WEBDAV_COLLECTION_TYPE
CachableContentProperties(const CachableContentProperties &)
static const OUString GETCONTENTTYPE
static const OUString RESOURCETYPE
OUString GetPathBaseName() const
Definition: SerfUri.cxx:160
void addProperties(const ContentProperties &rProps)
static void UCBNamesToHTTPNames(const css::uno::Sequence< css::beans::Property > &rProps, std::vector< OUString > &resources, bool bIncludeUnmatched=true)
static const OUString GETLASTMODIFIED
static const OUString CREATIONDATE
void addProperty(const OUString &rName, const css::uno::Any &rValue, bool bIsCaseSensitive)
std::unordered_map< OUString, PropertyValue > PropertyValueMap
static void UCBNamesToDAVNames(const css::uno::Sequence< css::beans::Property > &rProps, std::vector< OUString > &resources, bool bIncludeUnmatched=true)
void addProperties(const std::vector< OUString > &rProps, const ContentProperties &rContentProps)
#define WEBDAV_CONTENT_TYPE
std::unique_ptr< PropertyValueMap > m_xProps
const css::uno::Any & getValue(const OUString &rName) const
static const OUString GETETAG
bool containsAllNames(const css::uno::Sequence< css::beans::Property > &rProps, std::vector< OUString > &rNamesNotContained) const
static const OUString LOCKDISCOVERY
static bool convert(const OUString &, css::util::DateTime &)
static const OUString GETCONTENTLENGTH
enumrange< T >::Iterator end(enumrange< T >)
#define SAL_WARN_IF(condition, area, stream)
const PropertyValue * get(const OUString &rName) const
std::vector< DAVPropertyValue > properties
Definition: DAVResource.hxx:44
const std::unique_ptr< PropertyValueMap > & getProperties() const
OUString GetPathBaseNameUnescaped() const
Definition: SerfUri.cxx:194
bool contains(const OUString &rName) const
const css::uno::Any & value() const