LibreOffice Module ucb (master)  1
pkgcontent.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 
21 /**************************************************************************
22  TODO
23  **************************************************************************
24  *************************************************************************/
25 #include <sal/config.h>
26 
27 #include <string_view>
28 
29 #include <osl/diagnose.h>
30 
31 #include <rtl/ustring.hxx>
32 #include <com/sun/star/beans/IllegalTypeException.hpp>
33 #include <com/sun/star/beans/PropertyAttribute.hpp>
34 #include <com/sun/star/beans/PropertyExistException.hpp>
35 #include <com/sun/star/beans/PropertyState.hpp>
36 #include <com/sun/star/container/XEnumerationAccess.hpp>
37 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
38 #include <com/sun/star/container/XNameContainer.hpp>
39 #include <com/sun/star/container/XNamed.hpp>
40 #include <com/sun/star/io/BufferSizeExceededException.hpp>
41 #include <com/sun/star/io/NotConnectedException.hpp>
42 #include <com/sun/star/io/XActiveDataSink.hpp>
43 #include <com/sun/star/io/XOutputStream.hpp>
44 #include <com/sun/star/lang/IllegalAccessException.hpp>
45 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
46 #include <com/sun/star/ucb/IllegalIdentifierException.hpp>
47 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
48 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
49 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
50 #include <com/sun/star/ucb/NameClash.hpp>
51 #include <com/sun/star/ucb/NameClashException.hpp>
52 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
53 #include <com/sun/star/ucb/OpenMode.hpp>
54 #include <com/sun/star/ucb/TransferInfo.hpp>
55 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
56 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
57 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
58 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
59 #include <com/sun/star/ucb/XCommandInfo.hpp>
60 #include <com/sun/star/ucb/XPersistentPropertySet.hpp>
61 #include <com/sun/star/util/XChangesBatch.hpp>
62 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
63 #include <com/sun/star/uno/Any.hxx>
64 #include <com/sun/star/uno/Sequence.hxx>
70 #include <ucbhelper/macros.hxx>
71 #include "pkgcontent.hxx"
72 #include "pkgprovider.hxx"
73 #include "pkgresultset.hxx"
74 
75 #include "../inc/urihelper.hxx"
76 
77 using namespace com::sun::star;
78 using namespace package_ucp;
79 
80 #define NONE_MODIFIED sal_uInt32( 0x00 )
81 #define MEDIATYPE_MODIFIED sal_uInt32( 0x01 )
82 #define COMPRESSED_MODIFIED sal_uInt32( 0x02 )
83 #define ENCRYPTED_MODIFIED sal_uInt32( 0x04 )
84 #define ENCRYPTIONKEY_MODIFIED sal_uInt32( 0x08 )
85 
86 
87 // ContentProperties Implementation.
88 
89 
90 ContentProperties::ContentProperties( const OUString& rContentType )
91 : aContentType( rContentType ),
92  nSize( 0 ),
93  bCompressed( true ),
94  bEncrypted( false ),
95  bHasEncryptedEntries( false )
96 {
97  bIsFolder = rContentType == PACKAGE_FOLDER_CONTENT_TYPE || rContentType == PACKAGE_ZIP_FOLDER_CONTENT_TYPE;
99 
100  OSL_ENSURE( bIsFolder || rContentType == PACKAGE_STREAM_CONTENT_TYPE || rContentType == PACKAGE_ZIP_STREAM_CONTENT_TYPE,
101  "ContentProperties::ContentProperties - Unknown type!" );
102 }
103 
104 
105 uno::Sequence< ucb::ContentInfo >
107 {
108  if ( bIsFolder )
109  {
110  uno::Sequence< beans::Property > aProps( 1 );
111  aProps.getArray()[ 0 ] = beans::Property(
112  "Title",
113  -1,
115  beans::PropertyAttribute::BOUND );
116 
117  uno::Sequence< ucb::ContentInfo > aSeq( 2 );
118 
119  // Folder.
120  aSeq.getArray()[ 0 ].Type
121  = Content::getContentType( rUri.getScheme(), true );
122  aSeq.getArray()[ 0 ].Attributes
123  = ucb::ContentInfoAttribute::KIND_FOLDER;
124  aSeq.getArray()[ 0 ].Properties = aProps;
125 
126  // Stream.
127  aSeq.getArray()[ 1 ].Type
129  aSeq.getArray()[ 1 ].Attributes
130  = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
131  | ucb::ContentInfoAttribute::KIND_DOCUMENT;
132  aSeq.getArray()[ 1 ].Properties = aProps;
133 
134  return aSeq;
135  }
136  else
137  {
138  return uno::Sequence< ucb::ContentInfo >( 0 );
139  }
140 }
141 
142 
143 // Content Implementation.
144 
145 
146 // static ( "virtual" ctor )
148  const uno::Reference< uno::XComponentContext >& rxContext,
149  ContentProvider* pProvider,
150  const uno::Reference< ucb::XContentIdentifier >& Identifier )
151 {
152  OUString aURL = Identifier->getContentIdentifier();
153  PackageUri aURI( aURL );
154  ContentProperties aProps;
155  uno::Reference< container::XHierarchicalNameAccess > xPackage;
156 
157  if ( loadData( pProvider, aURI, aProps, xPackage ) )
158  {
159  // resource exists
160 
161  sal_Int32 nLastSlash = aURL.lastIndexOf( '/' );
162  if ( ( nLastSlash + 1 ) == aURL.getLength() )
163  {
164  // Client explicitly requested a folder!
165  if ( !aProps.bIsFolder )
166  return nullptr;
167  }
168 
169  uno::Reference< ucb::XContentIdentifier > xId
170  = new ::ucbhelper::ContentIdentifier( aURI.getUri() );
171  return new Content( rxContext, pProvider, xId, xPackage, aURI, aProps );
172  }
173  else
174  {
175  // resource doesn't exist
176 
177  bool bFolder = false;
178 
179  // Guess type according to URI.
180  sal_Int32 nLastSlash = aURL.lastIndexOf( '/' );
181  if ( ( nLastSlash + 1 ) == aURL.getLength() )
182  bFolder = true;
183 
184  uno::Reference< ucb::XContentIdentifier > xId
185  = new ::ucbhelper::ContentIdentifier( aURI.getUri() );
186 
187  ucb::ContentInfo aInfo;
188  if ( bFolder || aURI.isRootFolder() )
189  aInfo.Type = getContentType( aURI.getScheme(), true );
190  else
191  aInfo.Type = getContentType( aURI.getScheme(), false );
192 
193  return new Content( rxContext, pProvider, xId, xPackage, aURI, aInfo );
194  }
195 }
196 
197 
198 // static ( "virtual" ctor )
200  const uno::Reference< uno::XComponentContext >& rxContext,
201  ContentProvider* pProvider,
202  const uno::Reference< ucb::XContentIdentifier >& Identifier,
203  const ucb::ContentInfo& Info )
204 {
205  if ( Info.Type.isEmpty() )
206  return nullptr;
207 
208  PackageUri aURI( Identifier->getContentIdentifier() );
209 
210  if ( !Info.Type.equalsIgnoreAsciiCase(
211  getContentType( aURI.getScheme(), true ) ) &&
212  !Info.Type.equalsIgnoreAsciiCase(
213  getContentType( aURI.getScheme(), false ) ) )
214  return nullptr;
215 
216  uno::Reference< container::XHierarchicalNameAccess > xPackage = pProvider->createPackage( aURI );
217 
218  uno::Reference< ucb::XContentIdentifier > xId
219  = new ::ucbhelper::ContentIdentifier( aURI.getUri() );
220  return new Content( rxContext, pProvider, xId, xPackage, aURI, Info );
221 }
222 
223 
224 // static
226  std::u16string_view aScheme, bool bFolder )
227 {
228  return ( OUString::Concat("application/")
229  + aScheme
230  + ( bFolder
231  ? std::u16string_view(u"-folder")
232  : std::u16string_view(u"-stream") ) );
233 }
234 
235 
237  const uno::Reference< uno::XComponentContext >& rxContext,
238  ContentProvider* pProvider,
239  const uno::Reference< ucb::XContentIdentifier >& Identifier,
240  const uno::Reference< container::XHierarchicalNameAccess > & Package,
241  const PackageUri& rUri,
242  const ContentProperties& rProps )
243 : ContentImplHelper( rxContext, pProvider, Identifier ),
244  m_aUri( rUri ),
245  m_aProps( rProps ),
246  m_eState( PERSISTENT ),
247  m_xPackage( Package ),
248  m_pProvider( pProvider ),
249  m_nModifiedProps( NONE_MODIFIED )
250 {
251 }
252 
253 
255  const uno::Reference< uno::XComponentContext >& rxContext,
256  ContentProvider* pProvider,
257  const uno::Reference< ucb::XContentIdentifier >& Identifier,
258  const uno::Reference< container::XHierarchicalNameAccess > & Package,
259  const PackageUri& rUri,
260  const ucb::ContentInfo& Info )
261  : ContentImplHelper( rxContext, pProvider, Identifier ),
262  m_aUri( rUri ),
263  m_aProps( Info.Type ),
264  m_eState( TRANSIENT ),
265  m_xPackage( Package ),
266  m_pProvider( pProvider ),
267  m_nModifiedProps( NONE_MODIFIED )
268 {
269 }
270 
271 
272 // virtual
274 {
275 }
276 
277 
278 // XInterface methods.
279 
280 
281 // virtual
282 void SAL_CALL Content::acquire()
283  noexcept
284 {
285  ContentImplHelper::acquire();
286 }
287 
288 
289 // virtual
290 void SAL_CALL Content::release()
291  noexcept
292 {
293  ContentImplHelper::release();
294 }
295 
296 
297 // virtual
298 uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType )
299 {
300  uno::Any aRet;
301 
302  if ( isFolder() )
303  aRet = cppu::queryInterface(
304  rType, static_cast< ucb::XContentCreator * >( this ) );
305 
306  return aRet.hasValue() ? aRet : ContentImplHelper::queryInterface( rType );
307 }
308 
309 
310 // XTypeProvider methods.
311 
312 
314 
315 
316 // virtual
317 uno::Sequence< uno::Type > SAL_CALL Content::getTypes()
318 {
319  if ( isFolder() )
320  {
321  static cppu::OTypeCollection s_aFolderTypes(
322  CPPU_TYPE_REF( lang::XTypeProvider ),
323  CPPU_TYPE_REF( lang::XServiceInfo ),
324  CPPU_TYPE_REF( lang::XComponent ),
325  CPPU_TYPE_REF( ucb::XContent ),
326  CPPU_TYPE_REF( ucb::XCommandProcessor ),
327  CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
328  CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
329  CPPU_TYPE_REF( beans::XPropertyContainer ),
330  CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
331  CPPU_TYPE_REF( container::XChild ),
332  CPPU_TYPE_REF( ucb::XContentCreator ) );
333 
334  return s_aFolderTypes.getTypes();
335 
336  }
337  else
338  {
339  static cppu::OTypeCollection s_aDocumentTypes(
340  CPPU_TYPE_REF( lang::XTypeProvider ),
341  CPPU_TYPE_REF( lang::XServiceInfo ),
342  CPPU_TYPE_REF( lang::XComponent ),
343  CPPU_TYPE_REF( ucb::XContent ),
344  CPPU_TYPE_REF( ucb::XCommandProcessor ),
345  CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
346  CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
347  CPPU_TYPE_REF( beans::XPropertyContainer ),
348  CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
349  CPPU_TYPE_REF( container::XChild ) );
350 
351  return s_aDocumentTypes.getTypes();
352  }
353 }
354 
355 
356 // XServiceInfo methods.
357 
358 
359 // virtual
361 {
362  return "com.sun.star.comp.ucb.PackageContent";
363 }
364 
365 
366 // virtual
367 uno::Sequence< OUString > SAL_CALL Content::getSupportedServiceNames()
368 {
369  return { isFolder()? OUString("com.sun.star.ucb.PackageFolderContent"):OUString("com.sun.star.ucb.PackageStreamContent") } ;
370 }
371 
372 
373 // XContent methods.
374 
375 
376 // virtual
377 OUString SAL_CALL Content::getContentType()
378 {
379  return m_aProps.aContentType;
380 }
381 
382 
383 // XCommandProcessor methods.
384 
385 
386 // virtual
387 uno::Any SAL_CALL Content::execute(
388  const ucb::Command& aCommand,
389  sal_Int32 /*CommandId*/,
390  const uno::Reference< ucb::XCommandEnvironment >& Environment )
391 {
392  uno::Any aRet;
393 
394  if ( aCommand.Name == "getPropertyValues" )
395  {
396 
397  // getPropertyValues
398 
399 
400  uno::Sequence< beans::Property > Properties;
401  if ( !( aCommand.Argument >>= Properties ) )
402  {
404  uno::Any( lang::IllegalArgumentException(
405  "Wrong argument type!",
406  static_cast< cppu::OWeakObject * >( this ),
407  -1 ) ),
408  Environment );
409  // Unreachable
410  }
411 
412  aRet <<= getPropertyValues( Properties );
413  }
414  else if ( aCommand.Name == "setPropertyValues" )
415  {
416 
417  // setPropertyValues
418 
419 
420  uno::Sequence< beans::PropertyValue > aProperties;
421  if ( !( aCommand.Argument >>= aProperties ) )
422  {
424  uno::Any( lang::IllegalArgumentException(
425  "Wrong argument type!",
426  static_cast< cppu::OWeakObject * >( this ),
427  -1 ) ),
428  Environment );
429  // Unreachable
430  }
431 
432  if ( !aProperties.hasElements() )
433  {
435  uno::Any( lang::IllegalArgumentException(
436  "No properties!",
437  static_cast< cppu::OWeakObject * >( this ),
438  -1 ) ),
439  Environment );
440  // Unreachable
441  }
442 
443  aRet <<= setPropertyValues( aProperties, Environment );
444  }
445  else if ( aCommand.Name == "getPropertySetInfo" )
446  {
447 
448  // getPropertySetInfo
449 
450 
451  // Note: Implemented by base class.
452  aRet <<= getPropertySetInfo( Environment );
453  }
454  else if ( aCommand.Name == "getCommandInfo" )
455  {
456 
457  // getCommandInfo
458 
459 
460  // Note: Implemented by base class.
461  aRet <<= getCommandInfo( Environment );
462  }
463  else if ( aCommand.Name == "open" )
464  {
465 
466  // open
467 
468 
469  ucb::OpenCommandArgument2 aOpenCommand;
470  if ( !( aCommand.Argument >>= aOpenCommand ) )
471  {
473  uno::Any( lang::IllegalArgumentException(
474  "Wrong argument type!",
475  static_cast< cppu::OWeakObject * >( this ),
476  -1 ) ),
477  Environment );
478  // Unreachable
479  }
480 
481  aRet = open( aOpenCommand, Environment );
482  }
483  else if ( !m_aUri.isRootFolder() && aCommand.Name == "insert" )
484  {
485 
486  // insert
487 
488 
489  ucb::InsertCommandArgument aArg;
490  if ( !( aCommand.Argument >>= aArg ) )
491  {
493  uno::Any( lang::IllegalArgumentException(
494  "Wrong argument type!",
495  static_cast< cppu::OWeakObject * >( this ),
496  -1 ) ),
497  Environment );
498  // Unreachable
499  }
500 
501  sal_Int32 nNameClash = aArg.ReplaceExisting
502  ? ucb::NameClash::OVERWRITE
503  : ucb::NameClash::ERROR;
504  insert( aArg.Data, nNameClash, Environment );
505  }
506  else if ( !m_aUri.isRootFolder() && aCommand.Name == "delete" )
507  {
508 
509  // delete
510 
511 
512  bool bDeletePhysical = false;
513  aCommand.Argument >>= bDeletePhysical;
514  destroy( bDeletePhysical, Environment );
515 
516  // Remove own and all children's persistent data.
517  if ( !removeData() )
518  {
519  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
520  {
521  {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
522  }));
524  ucb::IOErrorCode_CANT_WRITE,
525  aArgs,
526  Environment,
527  "Cannot remove persistent data!",
528  this );
529  // Unreachable
530  }
531 
532  // Remove own and all children's Additional Core Properties.
534  }
535  else if ( aCommand.Name == "transfer" )
536  {
537 
538  // transfer
539  // ( Not available at stream objects )
540 
541 
542  ucb::TransferInfo aInfo;
543  if ( !( aCommand.Argument >>= aInfo ) )
544  {
546  uno::Any( lang::IllegalArgumentException(
547  "Wrong argument type!",
548  static_cast< cppu::OWeakObject * >( this ),
549  -1 ) ),
550  Environment );
551  // Unreachable
552  }
553 
554  transfer( aInfo, Environment );
555  }
556  else if ( aCommand.Name == "createNewContent" && isFolder() )
557  {
558 
559  // createNewContent
560  // ( Not available at stream objects )
561 
562 
563  ucb::ContentInfo aInfo;
564  if ( !( aCommand.Argument >>= aInfo ) )
565  {
566  OSL_FAIL( "Wrong argument type!" );
568  uno::Any( lang::IllegalArgumentException(
569  "Wrong argument type!",
570  static_cast< cppu::OWeakObject * >( this ),
571  -1 ) ),
572  Environment );
573  // Unreachable
574  }
575 
576  aRet <<= createNewContent( aInfo );
577  }
578  else if ( aCommand.Name == "flush" )
579  {
580 
581  // flush
582  // ( Not available at stream objects )
583 
584 
585  if( !flushData() )
586  {
587  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
588  {
589  {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
590  }));
592  ucb::IOErrorCode_CANT_WRITE,
593  aArgs,
594  Environment,
595  "Cannot write file to disk!",
596  this );
597  // Unreachable
598  }
599  }
600  else
601  {
602 
603  // Unsupported command
604 
605 
607  uno::Any( ucb::UnsupportedCommandException(
608  OUString(),
609  static_cast< cppu::OWeakObject * >( this ) ) ),
610  Environment );
611  // Unreachable
612  }
613 
614  return aRet;
615 }
616 
617 
618 // virtual
619 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
620 {
621  // @@@ Implement logic to abort running commands, if this makes
622  // sense for your content.
623 }
624 
625 
626 // XContentCreator methods.
627 
628 
629 // virtual
630 uno::Sequence< ucb::ContentInfo > SAL_CALL
632 {
634 }
635 
636 
637 // virtual
638 uno::Reference< ucb::XContent > SAL_CALL
639 Content::createNewContent( const ucb::ContentInfo& Info )
640 {
641  if ( isFolder() )
642  {
643  osl::Guard< osl::Mutex > aGuard( m_aMutex );
644 
645  if ( Info.Type.isEmpty() )
646  return uno::Reference< ucb::XContent >();
647 
648  if ( !Info.Type.equalsIgnoreAsciiCase(
649  getContentType( m_aUri.getScheme(), true ) ) &&
650  !Info.Type.equalsIgnoreAsciiCase(
652  return uno::Reference< ucb::XContent >();
653 
654  OUString aURL = m_aUri.getUri() + "/";
655 
656  if ( Info.Type.equalsIgnoreAsciiCase(
657  getContentType( m_aUri.getScheme(), true ) ) )
658  aURL += "New_Folder";
659  else
660  aURL += "New_Stream";
661 
662  uno::Reference< ucb::XContentIdentifier > xId(
663  new ::ucbhelper::ContentIdentifier( aURL ) );
664 
665  return create( m_xContext, m_pProvider, xId, Info );
666  }
667  else
668  {
669  OSL_FAIL( "createNewContent called on non-folder object!" );
670  return uno::Reference< ucb::XContent >();
671  }
672 }
673 
674 
675 // Non-interface methods.
676 
677 
678 // virtual
680 {
681  return m_aUri.getParentUri();
682 }
683 
684 
685 // static
686 uno::Reference< sdbc::XRow > Content::getPropertyValues(
687  const uno::Reference< uno::XComponentContext >& rxContext,
688  const uno::Sequence< beans::Property >& rProperties,
689  ContentProvider* pProvider,
690  const OUString& rContentId )
691 {
693  uno::Reference< container::XHierarchicalNameAccess > xPackage;
694  if ( loadData( pProvider, PackageUri( rContentId ), aData, xPackage ) )
695  {
696  return getPropertyValues( rxContext,
697  rProperties,
698  aData,
701  pProvider ),
702  rContentId );
703  }
704  else
705  {
707  = new ::ucbhelper::PropertyValueSet( rxContext );
708 
709  for ( const beans::Property& rProp : rProperties )
710  xRow->appendVoid( rProp );
711 
712  return xRow;
713  }
714 }
715 
716 
717 // static
718 uno::Reference< sdbc::XRow > Content::getPropertyValues(
719  const uno::Reference< uno::XComponentContext >& rxContext,
720  const uno::Sequence< beans::Property >& rProperties,
721  const ContentProperties& rData,
723  rProvider,
724  const OUString& rContentId )
725 {
726  // Note: Empty sequence means "get values of all supported properties".
727 
729  = new ::ucbhelper::PropertyValueSet( rxContext );
730 
731  if ( rProperties.hasElements() )
732  {
733  uno::Reference< beans::XPropertySet > xAdditionalPropSet;
734  bool bTriedToGetAdditionalPropSet = false;
735 
736  for ( const beans::Property& rProp : rProperties )
737  {
738  // Process Core properties.
739 
740  if ( rProp.Name == "ContentType" )
741  {
742  xRow->appendString ( rProp, rData.aContentType );
743  }
744  else if ( rProp.Name == "Title" )
745  {
746  xRow->appendString ( rProp, rData.aTitle );
747  }
748  else if ( rProp.Name == "IsDocument" )
749  {
750  xRow->appendBoolean( rProp, rData.bIsDocument );
751  }
752  else if ( rProp.Name == "IsFolder" )
753  {
754  xRow->appendBoolean( rProp, rData.bIsFolder );
755  }
756  else if ( rProp.Name == "CreatableContentsInfo" )
757  {
758  xRow->appendObject(
759  rProp, uno::Any(
761  PackageUri( rContentId ) ) ) );
762  }
763  else if ( rProp.Name == "MediaType" )
764  {
765  xRow->appendString ( rProp, rData.aMediaType );
766  }
767  else if ( rProp.Name == "Size" )
768  {
769  // Property only available for streams.
770  if ( rData.bIsDocument )
771  xRow->appendLong( rProp, rData.nSize );
772  else
773  xRow->appendVoid( rProp );
774  }
775  else if ( rProp.Name == "Compressed" )
776  {
777  // Property only available for streams.
778  if ( rData.bIsDocument )
779  xRow->appendBoolean( rProp, rData.bCompressed );
780  else
781  xRow->appendVoid( rProp );
782  }
783  else if ( rProp.Name == "Encrypted" )
784  {
785  // Property only available for streams.
786  if ( rData.bIsDocument )
787  xRow->appendBoolean( rProp, rData.bEncrypted );
788  else
789  xRow->appendVoid( rProp );
790  }
791  else if ( rProp.Name == "HasEncryptedEntries" )
792  {
793  // Property only available for root folder.
794  PackageUri aURI( rContentId );
795  if ( aURI.isRootFolder() )
796  xRow->appendBoolean( rProp, rData.bHasEncryptedEntries );
797  else
798  xRow->appendVoid( rProp );
799  }
800  else
801  {
802  // Not a Core Property! Maybe it's an Additional Core Property?!
803 
804  if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
805  {
806  xAdditionalPropSet =
807  rProvider->getAdditionalPropertySet( rContentId,
808  false );
809  bTriedToGetAdditionalPropSet = true;
810  }
811 
812  if ( xAdditionalPropSet.is() )
813  {
814  if ( !xRow->appendPropertySetValue(
815  xAdditionalPropSet,
816  rProp ) )
817  {
818  // Append empty entry.
819  xRow->appendVoid( rProp );
820  }
821  }
822  else
823  {
824  // Append empty entry.
825  xRow->appendVoid( rProp );
826  }
827  }
828  }
829  }
830  else
831  {
832  // Append all Core Properties.
833  xRow->appendString (
834  beans::Property(
835  "ContentType",
836  -1,
838  beans::PropertyAttribute::BOUND
839  | beans::PropertyAttribute::READONLY ),
840  rData.aContentType );
841  xRow->appendString(
842  beans::Property(
843  "Title",
844  -1,
846  beans::PropertyAttribute::BOUND ),
847  rData.aTitle );
848  xRow->appendBoolean(
849  beans::Property(
850  "IsDocument",
851  -1,
853  beans::PropertyAttribute::BOUND
854  | beans::PropertyAttribute::READONLY ),
855  rData.bIsDocument );
856  xRow->appendBoolean(
857  beans::Property(
858  "IsFolder",
859  -1,
861  beans::PropertyAttribute::BOUND
862  | beans::PropertyAttribute::READONLY ),
863  rData.bIsFolder );
864  xRow->appendObject(
865  beans::Property(
866  "CreatableContentsInfo",
867  -1,
868  cppu::UnoType<uno::Sequence< ucb::ContentInfo >>::get(),
869  beans::PropertyAttribute::BOUND
870  | beans::PropertyAttribute::READONLY ),
871  uno::Any(
872  rData.getCreatableContentsInfo( PackageUri( rContentId ) ) ) );
873  xRow->appendString(
874  beans::Property(
875  "MediaType",
876  -1,
878  beans::PropertyAttribute::BOUND ),
879  rData.aMediaType );
880 
881  // Properties only available for streams.
882  if ( rData.bIsDocument )
883  {
884  xRow->appendLong(
885  beans::Property(
886  "Size",
887  -1,
889  beans::PropertyAttribute::BOUND
890  | beans::PropertyAttribute::READONLY ),
891  rData.nSize );
892 
893  xRow->appendBoolean(
894  beans::Property(
895  "Compressed",
896  -1,
898  beans::PropertyAttribute::BOUND ),
899  rData.bCompressed );
900 
901  xRow->appendBoolean(
902  beans::Property(
903  "Encrypted",
904  -1,
906  beans::PropertyAttribute::BOUND ),
907  rData.bEncrypted );
908  }
909 
910  // Properties only available for root folder.
911  PackageUri aURI( rContentId );
912  if ( aURI.isRootFolder() )
913  {
914  xRow->appendBoolean(
915  beans::Property(
916  "HasEncryptedEntries",
917  -1,
919  beans::PropertyAttribute::BOUND
920  | beans::PropertyAttribute::READONLY ),
921  rData.bHasEncryptedEntries );
922  }
923 
924  // Append all Additional Core Properties.
925 
926  uno::Reference< beans::XPropertySet > xSet =
927  rProvider->getAdditionalPropertySet( rContentId, false );
928  xRow->appendPropertySet( xSet );
929  }
930 
931  return xRow;
932 }
933 
934 
935 uno::Reference< sdbc::XRow > Content::getPropertyValues(
936  const uno::Sequence< beans::Property >& rProperties )
937 {
938  osl::Guard< osl::Mutex > aGuard( m_aMutex );
940  rProperties,
941  m_aProps,
942  m_xProvider,
943  m_xIdentifier->getContentIdentifier() );
944 }
945 
946 
947 uno::Sequence< uno::Any > Content::setPropertyValues(
948  const uno::Sequence< beans::PropertyValue >& rValues,
949  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
950 {
951  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
952 
953  uno::Sequence< uno::Any > aRet( rValues.getLength() );
954  auto aRetRange = asNonConstRange(aRet);
955  uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
956  sal_Int32 nChanged = 0;
957 
958  beans::PropertyChangeEvent aEvent;
959  aEvent.Source = static_cast< cppu::OWeakObject * >( this );
960  aEvent.Further = false;
961 // aEvent.PropertyName =
962  aEvent.PropertyHandle = -1;
963 // aEvent.OldValue =
964 // aEvent.NewValue =
965 
966  const beans::PropertyValue* pValues = rValues.getConstArray();
967  sal_Int32 nCount = rValues.getLength();
968 
969  uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
970  bool bTriedToGetAdditionalPropSet = false;
971  bool bExchange = false;
972  bool bStore = false;
973  OUString aNewTitle;
974  sal_Int32 nTitlePos = -1;
975 
976  for ( sal_Int32 n = 0; n < nCount; ++n )
977  {
978  const beans::PropertyValue& rValue = pValues[ n ];
979 
980  if ( rValue.Name == "ContentType" )
981  {
982  // Read-only property!
983  aRetRange[ n ] <<= lang::IllegalAccessException(
984  "Property is read-only!",
985  static_cast< cppu::OWeakObject * >( this ) );
986  }
987  else if ( rValue.Name == "IsDocument" )
988  {
989  // Read-only property!
990  aRetRange[ n ] <<= lang::IllegalAccessException(
991  "Property is read-only!",
992  static_cast< cppu::OWeakObject * >( this ) );
993  }
994  else if ( rValue.Name == "IsFolder" )
995  {
996  // Read-only property!
997  aRetRange[ n ] <<= lang::IllegalAccessException(
998  "Property is read-only!",
999  static_cast< cppu::OWeakObject * >( this ) );
1000  }
1001  else if ( rValue.Name == "CreatableContentsInfo" )
1002  {
1003  // Read-only property!
1004  aRetRange[ n ] <<= lang::IllegalAccessException(
1005  "Property is read-only!",
1006  static_cast< cppu::OWeakObject * >( this ) );
1007  }
1008  else if ( rValue.Name == "Title" )
1009  {
1010  if ( m_aUri.isRootFolder() )
1011  {
1012  // Read-only property!
1013  aRetRange[ n ] <<= lang::IllegalAccessException(
1014  "Property is read-only!",
1015  static_cast< cppu::OWeakObject * >( this ) );
1016  }
1017  else
1018  {
1019  OUString aNewValue;
1020  if ( rValue.Value >>= aNewValue )
1021  {
1022  // No empty titles!
1023  if ( !aNewValue.isEmpty() )
1024  {
1025  if ( aNewValue != m_aProps.aTitle )
1026  {
1027  // modified title -> modified URL -> exchange !
1028  if ( m_eState == PERSISTENT )
1029  bExchange = true;
1030 
1031  // new value will be set later...
1032  aNewTitle = aNewValue;
1033 
1034  // remember position within sequence of values
1035  // (for error handling).
1036  nTitlePos = n;
1037  }
1038  }
1039  else
1040  {
1041  aRetRange[ n ] <<=
1042  lang::IllegalArgumentException(
1043  "Empty title not allowed!",
1044  static_cast< cppu::OWeakObject * >( this ),
1045  -1 );
1046  }
1047  }
1048  else
1049  {
1050  aRetRange[ n ] <<=
1051  beans::IllegalTypeException(
1052  "Property value has wrong type!",
1053  static_cast< cppu::OWeakObject * >( this ) );
1054  }
1055  }
1056  }
1057  else if ( rValue.Name == "MediaType" )
1058  {
1059  OUString aNewValue;
1060  if ( rValue.Value >>= aNewValue )
1061  {
1062  if ( aNewValue != m_aProps.aMediaType )
1063  {
1064  aEvent.PropertyName = rValue.Name;
1065  aEvent.OldValue <<= m_aProps.aMediaType;
1066  aEvent.NewValue <<= aNewValue;
1067 
1068  m_aProps.aMediaType = aNewValue;
1069  nChanged++;
1070  bStore = true;
1072  }
1073  }
1074  else
1075  {
1076  aRetRange[ n ] <<= beans::IllegalTypeException(
1077  "Property value has wrong type!",
1078  static_cast< cppu::OWeakObject * >( this ) );
1079  }
1080  }
1081  else if ( rValue.Name == "Size" )
1082  {
1083  // Read-only property!
1084  aRetRange[ n ] <<= lang::IllegalAccessException(
1085  "Property is read-only!",
1086  static_cast< cppu::OWeakObject * >( this ) );
1087  }
1088  else if ( rValue.Name == "Compressed" )
1089  {
1090  // Property only available for streams.
1091  if ( m_aProps.bIsDocument )
1092  {
1093  bool bNewValue;
1094  if ( rValue.Value >>= bNewValue )
1095  {
1096  if ( bNewValue != m_aProps.bCompressed )
1097  {
1098  aEvent.PropertyName = rValue.Name;
1099  aEvent.OldValue <<= m_aProps.bCompressed;
1100  aEvent.NewValue <<= bNewValue;
1101 
1102  m_aProps.bCompressed = bNewValue;
1103  nChanged++;
1104  bStore = true;
1106  }
1107  }
1108  else
1109  {
1110  aRetRange[ n ] <<= beans::IllegalTypeException(
1111  "Property value has wrong type!",
1112  static_cast< cppu::OWeakObject * >( this ) );
1113  }
1114  }
1115  else
1116  {
1117  aRetRange[ n ] <<= beans::UnknownPropertyException(
1118  "Compressed only supported by streams!",
1119  static_cast< cppu::OWeakObject * >( this ) );
1120  }
1121  }
1122  else if ( rValue.Name == "Encrypted" )
1123  {
1124  // Property only available for streams.
1125  if ( m_aProps.bIsDocument )
1126  {
1127  bool bNewValue;
1128  if ( rValue.Value >>= bNewValue )
1129  {
1130  if ( bNewValue != m_aProps.bEncrypted )
1131  {
1132  aEvent.PropertyName = rValue.Name;
1133  aEvent.OldValue <<= m_aProps.bEncrypted;
1134  aEvent.NewValue <<= bNewValue;
1135 
1136  m_aProps.bEncrypted = bNewValue;
1137  nChanged++;
1138  bStore = true;
1140  }
1141  }
1142  else
1143  {
1144  aRetRange[ n ] <<= beans::IllegalTypeException(
1145  "Property value has wrong type!",
1146  static_cast< cppu::OWeakObject * >( this ) );
1147  }
1148  }
1149  else
1150  {
1151  aRetRange[ n ] <<= beans::UnknownPropertyException(
1152  "Encrypted only supported by streams!",
1153  static_cast< cppu::OWeakObject * >( this ) );
1154  }
1155  }
1156  else if ( rValue.Name == "HasEncryptedEntries" )
1157  {
1158  // Read-only property!
1159  aRetRange[ n ] <<= lang::IllegalAccessException(
1160  "Property is read-only!",
1161  static_cast< cppu::OWeakObject * >( this ) );
1162  }
1163  else if ( rValue.Name == "EncryptionKey" )
1164  {
1165  // @@@ This is a temporary solution. In the future submitting
1166  // the key should be done using an interaction handler!
1167 
1168  // Write-Only property. Only supported by root folder and streams
1169  // (all non-root folders of a package have the same encryption key).
1171  {
1172  uno::Sequence < sal_Int8 > aNewValue;
1173  if ( rValue.Value >>= aNewValue )
1174  {
1175  if ( aNewValue != m_aProps.aEncryptionKey )
1176  {
1177  aEvent.PropertyName = rValue.Name;
1178  aEvent.OldValue <<= m_aProps.aEncryptionKey;
1179  aEvent.NewValue <<= aNewValue;
1180 
1181  m_aProps.aEncryptionKey = aNewValue;
1182  nChanged++;
1183  bStore = true;
1185  }
1186  }
1187  else
1188  {
1189  aRetRange[ n ] <<= beans::IllegalTypeException(
1190  "Property value has wrong type!",
1191  static_cast< cppu::OWeakObject * >( this ) );
1192  }
1193  }
1194  else
1195  {
1196  aRetRange[ n ] <<= beans::UnknownPropertyException(
1197  "EncryptionKey not supported by non-root folder!",
1198  static_cast< cppu::OWeakObject * >( this ) );
1199  }
1200  }
1201  else
1202  {
1203  // Not a Core Property! Maybe it's an Additional Core Property?!
1204 
1205  if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
1206  {
1207  xAdditionalPropSet = getAdditionalPropertySet( false );
1208  bTriedToGetAdditionalPropSet = true;
1209  }
1210 
1211  if ( xAdditionalPropSet.is() )
1212  {
1213  try
1214  {
1215  uno::Any aOldValue
1216  = xAdditionalPropSet->getPropertyValue( rValue.Name );
1217  if ( aOldValue != rValue.Value )
1218  {
1219  xAdditionalPropSet->setPropertyValue(
1220  rValue.Name, rValue.Value );
1221 
1222  aEvent.PropertyName = rValue.Name;
1223  aEvent.OldValue = aOldValue;
1224  aEvent.NewValue = rValue.Value;
1225 
1226  aChanges.getArray()[ nChanged ] = aEvent;
1227  nChanged++;
1228  }
1229  }
1230  catch ( beans::UnknownPropertyException const & e )
1231  {
1232  aRetRange[ n ] <<= e;
1233  }
1234  catch ( lang::WrappedTargetException const & e )
1235  {
1236  aRetRange[ n ] <<= e;
1237  }
1238  catch ( beans::PropertyVetoException const & e )
1239  {
1240  aRetRange[ n ] <<= e;
1241  }
1242  catch ( lang::IllegalArgumentException const & e )
1243  {
1244  aRetRange[ n ] <<= e;
1245  }
1246  }
1247  else
1248  {
1249  aRetRange[ n ] <<= uno::Exception(
1250  "No property set for storing the value!",
1251  static_cast< cppu::OWeakObject * >( this ) );
1252  }
1253  }
1254  }
1255 
1256  if ( bExchange )
1257  {
1258  uno::Reference< ucb::XContentIdentifier > xOldId = m_xIdentifier;
1259 
1260  // Assemble new content identifier...
1261  OUString aNewURL = m_aUri.getParentUri() + "/";
1262  aNewURL += ::ucb_impl::urihelper::encodeSegment( aNewTitle );
1263  uno::Reference< ucb::XContentIdentifier > xNewId
1264  = new ::ucbhelper::ContentIdentifier( aNewURL );
1265 
1266  aGuard.clear();
1267  if ( exchangeIdentity( xNewId ) )
1268  {
1269  // Adapt persistent data.
1270  renameData( xOldId, xNewId );
1271 
1272  // Adapt Additional Core Properties.
1273  renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1274  xNewId->getContentIdentifier() );
1275  }
1276  else
1277  {
1278  // Do not set new title!
1279  aNewTitle.clear();
1280 
1281  // Set error .
1282  aRetRange[ nTitlePos ] <<= uno::Exception(
1283  "Exchange failed!",
1284  static_cast< cppu::OWeakObject * >( this ) );
1285  }
1286  }
1287 
1288  if ( !aNewTitle.isEmpty() )
1289  {
1290  aEvent.PropertyName = "Title";
1291  aEvent.OldValue <<= m_aProps.aTitle;
1292  aEvent.NewValue <<= aNewTitle;
1293 
1294  m_aProps.aTitle = aNewTitle;
1295 
1296  aChanges.getArray()[ nChanged ] = aEvent;
1297  nChanged++;
1298  }
1299 
1300  if ( nChanged > 0 )
1301  {
1302  // Save changes, if content was already made persistent.
1304  ( bStore && ( m_eState == PERSISTENT ) ) )
1305  {
1306  if ( !storeData( uno::Reference< io::XInputStream >() ) )
1307  {
1308  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1309  {
1310  {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1311  }));
1313  ucb::IOErrorCode_CANT_WRITE,
1314  aArgs,
1315  xEnv,
1316  "Cannot store persistent data!",
1317  this );
1318  // Unreachable
1319  }
1320  }
1321 
1322  aGuard.clear();
1323  aChanges.realloc( nChanged );
1324  notifyPropertiesChange( aChanges );
1325  }
1326 
1327  return aRet;
1328 }
1329 
1330 
1332  const ucb::OpenCommandArgument2& rArg,
1333  const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1334 {
1335  if ( rArg.Mode == ucb::OpenMode::ALL ||
1336  rArg.Mode == ucb::OpenMode::FOLDERS ||
1337  rArg.Mode == ucb::OpenMode::DOCUMENTS )
1338  {
1339 
1340  // open command for a folder content
1341 
1342 
1343  uno::Reference< ucb::XDynamicResultSet > xSet
1344  = new DynamicResultSet( m_xContext, this, rArg, xEnv );
1345  return uno::Any( xSet );
1346  }
1347  else
1348  {
1349 
1350  // open command for a document content
1351 
1352 
1353  if ( ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
1354  ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) )
1355  {
1356  // Currently(?) unsupported.
1358  uno::Any( ucb::UnsupportedOpenModeException(
1359  OUString(),
1360  static_cast< cppu::OWeakObject * >( this ),
1361  sal_Int16( rArg.Mode ) ) ),
1362  xEnv );
1363  // Unreachable
1364  }
1365 
1366  uno::Reference< io::XOutputStream > xOut( rArg.Sink, uno::UNO_QUERY );
1367  if ( xOut.is() )
1368  {
1369  // PUSH: write data into xOut
1370 
1371  uno::Reference< io::XInputStream > xIn = getInputStream();
1372  if ( !xIn.is() )
1373  {
1374  // No interaction if we are not persistent!
1375  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1376  {
1377  {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1378  }));
1380  ucb::IOErrorCode_CANT_READ,
1381  aArgs,
1382  m_eState == PERSISTENT
1383  ? xEnv
1384  : uno::Reference< ucb::XCommandEnvironment >(),
1385  "Got no data stream!",
1386  this );
1387  // Unreachable
1388  }
1389 
1390  try
1391  {
1392  uno::Sequence< sal_Int8 > aBuffer;
1393  while (true)
1394  {
1395  sal_Int32 nRead = xIn->readSomeBytes( aBuffer, 65536 );
1396  if (!nRead)
1397  break;
1398  aBuffer.realloc( nRead );
1399  xOut->writeBytes( aBuffer );
1400  }
1401 
1402  xOut->closeOutput();
1403  }
1404  catch ( io::NotConnectedException const & )
1405  {
1406  // closeOutput, readSomeBytes, writeBytes
1407  }
1408  catch ( io::BufferSizeExceededException const & )
1409  {
1410  // closeOutput, readSomeBytes, writeBytes
1411  }
1412  catch ( io::IOException const & )
1413  {
1414  // closeOutput, readSomeBytes, writeBytes
1415  }
1416  }
1417  else
1418  {
1419  uno::Reference< io::XActiveDataSink > xDataSink(
1420  rArg.Sink, uno::UNO_QUERY );
1421  if ( xDataSink.is() )
1422  {
1423  // PULL: wait for client read
1424 
1425  uno::Reference< io::XInputStream > xIn = getInputStream();
1426  if ( !xIn.is() )
1427  {
1428  // No interaction if we are not persistent!
1429  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1430  {
1431  {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1432  }));
1434  ucb::IOErrorCode_CANT_READ,
1435  aArgs,
1436  m_eState == PERSISTENT
1437  ? xEnv
1438  : uno::Reference<
1439  ucb::XCommandEnvironment >(),
1440  "Got no data stream!",
1441  this );
1442  // Unreachable
1443  }
1444 
1445  // Done.
1446  xDataSink->setInputStream( xIn );
1447  }
1448  else
1449  {
1450  // Note: aOpenCommand.Sink may contain an XStream
1451  // implementation. Support for this type of
1452  // sink is optional...
1454  uno::Any(
1455  ucb::UnsupportedDataSinkException(
1456  OUString(),
1457  static_cast< cppu::OWeakObject * >( this ),
1458  rArg.Sink ) ),
1459  xEnv );
1460  // Unreachable
1461  }
1462  }
1463  }
1464 
1465  return uno::Any();
1466 }
1467 
1468 
1469 void Content::insert(
1470  const uno::Reference< io::XInputStream >& xStream,
1471  sal_Int32 nNameClashResolve,
1472  const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1473 {
1474  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1475 
1476  // Check, if all required properties were set.
1477  if ( isFolder() )
1478  {
1479  // Required: Title
1480 
1481  if ( m_aProps.aTitle.isEmpty() )
1483  }
1484  else
1485  {
1486  // Required: rArg.Data
1487 
1488  if ( !xStream.is() )
1489  {
1491  uno::Any( ucb::MissingInputStreamException(
1492  OUString(),
1493  static_cast< cppu::OWeakObject * >( this ) ) ),
1494  xEnv );
1495  // Unreachable
1496  }
1497 
1498  // Required: Title
1499 
1500  if ( m_aProps.aTitle.isEmpty() )
1502  }
1503 
1504  OUString aNewURL = m_aUri.getParentUri();
1505  if (1 + aNewURL.lastIndexOf('/') != aNewURL.getLength())
1506  aNewURL += "/";
1508  PackageUri aNewUri( aNewURL );
1509 
1510  // Handle possible name clash...
1511  switch ( nNameClashResolve )
1512  {
1513  // fail.
1514  case ucb::NameClash::ERROR:
1515  if ( hasData( aNewUri ) )
1516  {
1518  uno::Any( ucb::NameClashException(
1519  OUString(),
1520  static_cast< cppu::OWeakObject * >( this ),
1521  task::InteractionClassification_ERROR,
1522  m_aProps.aTitle ) ),
1523  xEnv );
1524  // Unreachable
1525  }
1526  break;
1527 
1528  // replace (possibly) existing object.
1529  case ucb::NameClash::OVERWRITE:
1530  break;
1531 
1532  // "invent" a new valid title.
1533  case ucb::NameClash::RENAME:
1534  if ( hasData( aNewUri ) )
1535  {
1536  sal_Int32 nTry = 0;
1537 
1538  do
1539  {
1540  OUString aNew = aNewUri.getUri() + "_";
1541  aNew += OUString::number( ++nTry );
1542  aNewUri.setUri( aNew );
1543  }
1544  while ( hasData( aNewUri ) && ( nTry < 1000 ) );
1545 
1546  if ( nTry == 1000 )
1547  {
1549  uno::Any(
1550  ucb::UnsupportedNameClashException(
1551  "Unable to resolve name clash!",
1552  static_cast< cppu::OWeakObject * >( this ),
1553  nNameClashResolve ) ),
1554  xEnv );
1555  // Unreachable
1556  }
1557  else
1558  {
1559  m_aProps.aTitle += "_";
1560  m_aProps.aTitle += OUString::number( nTry );
1561  }
1562  }
1563  break;
1564 
1565  case ucb::NameClash::KEEP: // deprecated
1566  case ucb::NameClash::ASK:
1567  default:
1568  if ( hasData( aNewUri ) )
1569  {
1571  uno::Any(
1572  ucb::UnsupportedNameClashException(
1573  OUString(),
1574  static_cast< cppu::OWeakObject * >( this ),
1575  nNameClashResolve ) ),
1576  xEnv );
1577  // Unreachable
1578  }
1579  break;
1580  }
1581 
1582  // Identifier changed?
1583  bool bNewId = ( m_aUri.getUri() != aNewUri.getUri() );
1584 
1585  if ( bNewId )
1586  {
1587  m_xIdentifier = new ::ucbhelper::ContentIdentifier( aNewURL );
1588  m_aUri = aNewUri;
1589  }
1590 
1591  if ( !storeData( xStream ) )
1592  {
1593  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1594  {
1595  {"Uri", uno::Any(m_xIdentifier->getContentIdentifier())}
1596  }));
1598  ucb::IOErrorCode_CANT_WRITE,
1599  aArgs,
1600  xEnv,
1601  "Cannot store persistent data!",
1602  this );
1603  // Unreachable
1604  }
1605 
1606  m_eState = PERSISTENT;
1607 
1608  if ( bNewId )
1609  {
1610  // Take over correct default values from underlying packager...
1611  uno::Reference< container::XHierarchicalNameAccess > xXHierarchicalNameAccess;
1613  m_aUri,
1614  m_aProps,
1615  xXHierarchicalNameAccess );
1616 
1617  aGuard.clear();
1618  inserted();
1619  }
1620 }
1621 
1622 
1623 void Content::destroy(
1624  bool bDeletePhysical,
1625  const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1626 {
1627  // @@@ take care about bDeletePhysical -> trashcan support
1628 
1629  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1630 
1631  uno::Reference< ucb::XContent > xThis = this;
1632 
1633  // Persistent?
1634  if ( m_eState != PERSISTENT )
1635  {
1637  uno::Any( ucb::UnsupportedCommandException(
1638  "Not persistent!",
1639  static_cast< cppu::OWeakObject * >( this ) ) ),
1640  xEnv );
1641  // Unreachable
1642  }
1643 
1644  m_eState = DEAD;
1645 
1646  aGuard.clear();
1647  deleted();
1648 
1649  if ( isFolder() )
1650  {
1651  // Process instantiated children...
1652 
1653  ContentRefList aChildren;
1654  queryChildren( aChildren );
1655 
1656  for ( auto& rChild : aChildren )
1657  {
1658  rChild->destroy( bDeletePhysical, xEnv );
1659  }
1660  }
1661 }
1662 
1663 
1664 void Content::transfer(
1665  const ucb::TransferInfo& rInfo,
1666  const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1667 {
1668  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1669 
1670  // Persistent?
1671  if ( m_eState != PERSISTENT )
1672  {
1674  uno::Any( ucb::UnsupportedCommandException(
1675  "Not persistent!",
1676  static_cast< cppu::OWeakObject * >( this ) ) ),
1677  xEnv );
1678  // Unreachable
1679  }
1680 
1681  // Is source a package content?
1682  if ( ( rInfo.SourceURL.isEmpty() ) ||
1683  ( rInfo.SourceURL.compareTo(
1684  m_aUri.getUri(), PACKAGE_URL_SCHEME_LENGTH + 3 ) != 0 ) )
1685  {
1687  uno::Any( ucb::InteractiveBadTransferURLException(
1688  OUString(),
1689  static_cast< cppu::OWeakObject * >( this ) ) ),
1690  xEnv );
1691  // Unreachable
1692  }
1693 
1694  // Is source not a parent of me / not me?
1695  OUString aId = m_aUri.getParentUri() + "/";
1696 
1697  if ( rInfo.SourceURL.getLength() <= aId.getLength() )
1698  {
1699  if ( aId.startsWith( rInfo.SourceURL ) )
1700  {
1701  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1702  {
1703  {"Uri", uno::Any(rInfo.SourceURL)}
1704  }));
1706  ucb::IOErrorCode_RECURSIVE,
1707  aArgs,
1708  xEnv,
1709  "Target is equal to or is a child of source!",
1710  this );
1711  // Unreachable
1712  }
1713  }
1714 
1715 
1716  // 0) Obtain content object for source.
1717 
1718 
1719  uno::Reference< ucb::XContentIdentifier > xId
1720  = new ::ucbhelper::ContentIdentifier( rInfo.SourceURL );
1721 
1722  // Note: The static cast is okay here, because its sure that
1723  // m_xProvider is always the PackageContentProvider.
1724  rtl::Reference< Content > xSource;
1725 
1726  try
1727  {
1728  xSource = static_cast< Content * >(
1729  m_xProvider->queryContent( xId ).get() );
1730  }
1731  catch ( ucb::IllegalIdentifierException const & )
1732  {
1733  // queryContent
1734  }
1735 
1736  if ( !xSource.is() )
1737  {
1738  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1739  {
1740  {"Uri", uno::Any(xId->getContentIdentifier())}
1741  }));
1743  ucb::IOErrorCode_CANT_READ,
1744  aArgs,
1745  xEnv,
1746  "Cannot instantiate source object!",
1747  this );
1748  // Unreachable
1749  }
1750 
1751 
1752  // 1) Create new child content.
1753 
1754 
1755  OUString aType = xSource->isFolder()
1756  ? getContentType( m_aUri.getScheme(), true )
1758  ucb::ContentInfo aContentInfo;
1759  aContentInfo.Type = aType;
1760  aContentInfo.Attributes = 0;
1761 
1762  // Note: The static cast is okay here, because its sure that
1763  // createNewContent always creates a Content.
1765  = static_cast< Content * >( createNewContent( aContentInfo ).get() );
1766  if ( !xTarget.is() )
1767  {
1768  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1769  {
1770  {"Folder", uno::Any(aId)}
1771  }));
1773  ucb::IOErrorCode_CANT_CREATE,
1774  aArgs,
1775  xEnv,
1776  "XContentCreator::createNewContent failed!",
1777  this );
1778  // Unreachable
1779  }
1780 
1781 
1782  // 2) Copy data from source content to child content.
1783 
1784 
1785  uno::Sequence< beans::Property > aSourceProps
1786  = xSource->getPropertySetInfo( xEnv )->getProperties();
1787  sal_Int32 nCount = aSourceProps.getLength();
1788 
1789  if ( nCount )
1790  {
1791  bool bHadTitle = rInfo.NewTitle.isEmpty();
1792 
1793  // Get all source values.
1794  uno::Reference< sdbc::XRow > xRow
1795  = xSource->getPropertyValues( aSourceProps );
1796 
1797  uno::Sequence< beans::PropertyValue > aValues( nCount );
1798  beans::PropertyValue* pValues = aValues.getArray();
1799 
1800  const beans::Property* pProps = aSourceProps.getConstArray();
1801  for ( sal_Int32 n = 0; n < nCount; ++n )
1802  {
1803  const beans::Property& rProp = pProps[ n ];
1804  beans::PropertyValue& rValue = pValues[ n ];
1805 
1806  rValue.Name = rProp.Name;
1807  rValue.Handle = rProp.Handle;
1808 
1809  if ( !bHadTitle && rProp.Name == "Title" )
1810  {
1811  // Set new title instead of original.
1812  bHadTitle = true;
1813  rValue.Value <<= rInfo.NewTitle;
1814  }
1815  else
1816  rValue.Value
1817  = xRow->getObject( n + 1,
1818  uno::Reference<
1819  container::XNameAccess >() );
1820 
1821  rValue.State = beans::PropertyState_DIRECT_VALUE;
1822 
1823  if ( rProp.Attributes & beans::PropertyAttribute::REMOVABLE )
1824  {
1825  // Add Additional Core Property.
1826  try
1827  {
1828  xTarget->addProperty( rProp.Name,
1829  rProp.Attributes,
1830  rValue.Value );
1831  }
1832  catch ( beans::PropertyExistException const & )
1833  {
1834  }
1835  catch ( beans::IllegalTypeException const & )
1836  {
1837  }
1838  catch ( lang::IllegalArgumentException const & )
1839  {
1840  }
1841  }
1842  }
1843 
1844  // Set target values.
1845  xTarget->setPropertyValues( aValues, xEnv );
1846  }
1847 
1848 
1849  // 3) Commit (insert) child.
1850 
1851 
1852  xTarget->insert( xSource->getInputStream(), rInfo.NameClash, xEnv );
1853 
1854 
1855  // 4) Transfer (copy) children of source.
1856 
1857 
1858  if ( xSource->isFolder() )
1859  {
1860  uno::Reference< container::XEnumeration > xIter
1861  = xSource->getIterator();
1862  if ( xIter.is() )
1863  {
1864  while ( xIter->hasMoreElements() )
1865  {
1866  try
1867  {
1868  uno::Reference< container::XNamed > xNamed;
1869  xIter->nextElement() >>= xNamed;
1870 
1871  if ( !xNamed.is() )
1872  {
1873  OSL_FAIL( "Content::transfer - Got no XNamed!" );
1874  break;
1875  }
1876 
1877  OUString aName = xNamed->getName();
1878 
1879  if ( aName.isEmpty() )
1880  {
1881  OSL_FAIL( "Content::transfer - Empty name!" );
1882  break;
1883  }
1884 
1885  OUString aChildId = xId->getContentIdentifier();
1886  if ( ( aChildId.lastIndexOf( '/' ) + 1 )
1887  != aChildId.getLength() )
1888  aChildId += "/";
1889 
1890  aChildId += ::ucb_impl::urihelper::encodeSegment( aName );
1891 
1892  ucb::TransferInfo aInfo;
1893  aInfo.MoveData = false;
1894  aInfo.NewTitle.clear();
1895  aInfo.SourceURL = aChildId;
1896  aInfo.NameClash = rInfo.NameClash;
1897 
1898  // Transfer child to target.
1899  xTarget->transfer( aInfo, xEnv );
1900  }
1901  catch ( container::NoSuchElementException const & )
1902  {
1903  }
1904  catch ( lang::WrappedTargetException const & )
1905  {
1906  }
1907  }
1908  }
1909  }
1910 
1911 
1912  // 5) Destroy source ( when moving only ) .
1913 
1914 
1915  if ( !rInfo.MoveData )
1916  return;
1917 
1918  xSource->destroy( true, xEnv );
1919 
1920  // Remove all persistent data of source and its children.
1921  if ( !xSource->removeData() )
1922  {
1923  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
1924  {
1925  {"Uri", uno::Any(xSource->m_xIdentifier->getContentIdentifier())}
1926  }));
1928  ucb::IOErrorCode_CANT_WRITE,
1929  aArgs,
1930  xEnv,
1931  "Cannot remove persistent data of source object!",
1932  this );
1933  // Unreachable
1934  }
1935 
1936  // Remove own and all children's Additional Core Properties.
1937  xSource->removeAdditionalPropertySet();
1938 }
1939 
1940 
1942  const uno::Reference< ucb::XContentIdentifier >& xNewId )
1943 {
1944  if ( !xNewId.is() )
1945  return false;
1946 
1947  osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1948 
1949  uno::Reference< ucb::XContent > xThis = this;
1950 
1951  // Already persistent?
1952  if ( m_eState != PERSISTENT )
1953  {
1954  OSL_FAIL( "Content::exchangeIdentity - Not persistent!" );
1955  return false;
1956  }
1957 
1958  // Exchange own identity.
1959 
1960  // Fail, if a content with given id already exists.
1961  PackageUri aNewUri( xNewId->getContentIdentifier() );
1962  if ( !hasData( aNewUri ) )
1963  {
1964  OUString aOldURL = m_xIdentifier->getContentIdentifier();
1965 
1966  aGuard.clear();
1967  if ( exchange( xNewId ) )
1968  {
1969  m_aUri = aNewUri;
1970  if ( isFolder() )
1971  {
1972  // Process instantiated children...
1973 
1974  ContentRefList aChildren;
1975  queryChildren( aChildren );
1976 
1977  for ( const auto& rChild : aChildren )
1978  {
1979  ContentRef xChild = rChild;
1980 
1981  // Create new content identifier for the child...
1982  uno::Reference< ucb::XContentIdentifier > xOldChildId
1983  = xChild->getIdentifier();
1984  OUString aOldChildURL
1985  = xOldChildId->getContentIdentifier();
1986  OUString aNewChildURL
1987  = aOldChildURL.replaceAt(
1988  0,
1989  aOldURL.getLength(),
1990  xNewId->getContentIdentifier() );
1991  uno::Reference< ucb::XContentIdentifier > xNewChildId
1992  = new ::ucbhelper::ContentIdentifier( aNewChildURL );
1993 
1994  if ( !xChild->exchangeIdentity( xNewChildId ) )
1995  return false;
1996  }
1997  }
1998  return true;
1999  }
2000  }
2001 
2002  OSL_FAIL( "Content::exchangeIdentity - Panic! Cannot exchange identity!" );
2003  return false;
2004 }
2005 
2006 
2008 {
2009  // Obtain a list with a snapshot of all currently instantiated contents
2010  // from provider and extract the contents which are direct children
2011  // of this content.
2012 
2013  ::ucbhelper::ContentRefList aAllContents;
2014  m_xProvider->queryExistingContents( aAllContents );
2015 
2016  OUString aURL = m_xIdentifier->getContentIdentifier();
2017 
2018  OSL_ENSURE( aURL.lastIndexOf( '/' ) != ( aURL.getLength() - 1 ),
2019  "Content::queryChildren - Invalid URL!" );
2020 
2021  aURL += "/";
2022 
2023  sal_Int32 nLen = aURL.getLength();
2024 
2025  for ( const auto& rContent : aAllContents )
2026  {
2027  ::ucbhelper::ContentImplHelperRef xChild = rContent;
2028  OUString aChildURL
2029  = xChild->getIdentifier()->getContentIdentifier();
2030 
2031  // Is aURL a prefix of aChildURL?
2032  if ( ( aChildURL.getLength() > nLen ) &&
2033  ( aChildURL.startsWith( aURL ) ) )
2034  {
2035  if ( aChildURL.indexOf( '/', nLen ) == -1 )
2036  {
2037  // No further slashes. It's a child!
2038  rChildren.emplace_back(
2039  static_cast< Content * >( xChild.get() ) );
2040  }
2041  }
2042  }
2043 }
2044 
2045 
2046 uno::Reference< container::XHierarchicalNameAccess > Content::getPackage(
2047  const PackageUri& rURI )
2048 {
2049  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2050 
2051  if ( rURI.getPackage() == m_aUri.getPackage() )
2052  {
2053  if ( !m_xPackage.is() )
2055 
2056  return m_xPackage;
2057  }
2058 
2059  return m_pProvider->createPackage( rURI );
2060 }
2061 
2062 
2063 uno::Reference< container::XHierarchicalNameAccess > Content::getPackage()
2064 {
2065  return getPackage( m_aUri );
2066 }
2067 
2068 
2069 // static
2070 bool Content::hasData(
2071  ContentProvider* pProvider,
2072  const PackageUri& rURI,
2073  uno::Reference< container::XHierarchicalNameAccess > & rxPackage )
2074 {
2075  rxPackage = pProvider->createPackage( rURI );
2076  return rxPackage->hasByHierarchicalName( rURI.getPath() );
2077 }
2078 
2079 
2080 bool Content::hasData( const PackageUri& rURI )
2081 {
2082  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2083 
2084  uno::Reference< container::XHierarchicalNameAccess > xPackage;
2085  if ( rURI.getPackage() == m_aUri.getPackage() )
2086  {
2087  xPackage = getPackage();
2088  return xPackage->hasByHierarchicalName( rURI.getPath() );
2089  }
2090 
2091  return hasData( m_pProvider, rURI, xPackage );
2092 }
2093 
2094 
2095 //static
2096 bool Content::loadData(
2097  ContentProvider* pProvider,
2098  const PackageUri& rURI,
2099  ContentProperties& rProps,
2100  uno::Reference< container::XHierarchicalNameAccess > & rxPackage )
2101 {
2102  rxPackage = pProvider->createPackage( rURI );
2103 
2104  if ( rURI.isRootFolder() )
2105  {
2106  // Properties available only from package
2107  uno::Reference< beans::XPropertySet > xPackagePropSet(
2108  rxPackage, uno::UNO_QUERY );
2109 
2110  OSL_ENSURE( xPackagePropSet.is(),
2111  "Content::loadData - "
2112  "Got no XPropertySet interface from package!" );
2113 
2114  if ( xPackagePropSet.is() )
2115  {
2116  // HasEncryptedEntries (only available at root folder)
2117  try
2118  {
2119  uno::Any aHasEncryptedEntries
2120  = xPackagePropSet->getPropertyValue( "HasEncryptedEntries" );
2121  if ( !( aHasEncryptedEntries >>= rProps.bHasEncryptedEntries ) )
2122  {
2123  OSL_FAIL( "Content::loadData - "
2124  "Got no HasEncryptedEntries value!" );
2125  return false;
2126  }
2127  }
2128  catch ( beans::UnknownPropertyException const & )
2129  {
2130  OSL_FAIL( "Content::loadData - "
2131  "Got no HasEncryptedEntries value!" );
2132  return false;
2133  }
2134  catch ( lang::WrappedTargetException const & )
2135  {
2136  OSL_FAIL( "Content::loadData - "
2137  "Got no HasEncryptedEntries value!" );
2138  return false;
2139  }
2140  }
2141  }
2142 
2143  if ( !rxPackage->hasByHierarchicalName( rURI.getPath() ) )
2144  return false;
2145 
2146  try
2147  {
2148  uno::Any aEntry = rxPackage->getByHierarchicalName( rURI.getPath() );
2149  if ( aEntry.hasValue() )
2150  {
2151  uno::Reference< beans::XPropertySet > xPropSet;
2152  aEntry >>= xPropSet;
2153 
2154  if ( !xPropSet.is() )
2155  {
2156  OSL_FAIL( "Content::loadData - Got no XPropertySet interface!" );
2157  return false;
2158  }
2159 
2160  // Title
2161  rProps.aTitle = rURI.getName();
2162 
2163  // MediaType
2164  try
2165  {
2166  uno::Any aMediaType = xPropSet->getPropertyValue("MediaType");
2167  if ( !( aMediaType >>= rProps.aMediaType ) )
2168  {
2169  OSL_FAIL( "Content::loadData - Got no MediaType value!" );
2170  return false;
2171  }
2172  }
2173  catch ( beans::UnknownPropertyException const & )
2174  {
2175  OSL_FAIL( "Content::loadData - Got no MediaType value!" );
2176  return false;
2177  }
2178  catch ( lang::WrappedTargetException const & )
2179  {
2180  OSL_FAIL( "Content::loadData - Got no MediaType value!" );
2181  return false;
2182  }
2183 
2184  uno::Reference< container::XEnumerationAccess > xEnumAccess;
2185  aEntry >>= xEnumAccess;
2186 
2187  // ContentType / IsFolder / IsDocument
2188  if ( xEnumAccess.is() )
2189  {
2190  // folder
2191  rProps.aContentType = getContentType( rURI.getScheme(), true );
2192  rProps.bIsDocument = false;
2193  rProps.bIsFolder = true;
2194  }
2195  else
2196  {
2197  // stream
2198  rProps.aContentType = getContentType( rURI.getScheme(), false );
2199  rProps.bIsDocument = true;
2200  rProps.bIsFolder = false;
2201  }
2202 
2203  if ( rProps.bIsDocument )
2204  {
2205  // Size ( only available for streams )
2206  try
2207  {
2208  uno::Any aSize = xPropSet->getPropertyValue("Size");
2209  if ( !( aSize >>= rProps.nSize ) )
2210  {
2211  OSL_FAIL( "Content::loadData - Got no Size value!" );
2212  return false;
2213  }
2214  }
2215  catch ( beans::UnknownPropertyException const & )
2216  {
2217  OSL_FAIL( "Content::loadData - Got no Size value!" );
2218  return false;
2219  }
2220  catch ( lang::WrappedTargetException const & )
2221  {
2222  OSL_FAIL( "Content::loadData - Got no Size value!" );
2223  return false;
2224  }
2225 
2226  // Compressed ( only available for streams )
2227  try
2228  {
2229  uno::Any aCompressed = xPropSet->getPropertyValue("Compressed");
2230  if ( !( aCompressed >>= rProps.bCompressed ) )
2231  {
2232  OSL_FAIL( "Content::loadData - Got no Compressed value!" );
2233  return false;
2234  }
2235  }
2236  catch ( beans::UnknownPropertyException const & )
2237  {
2238  OSL_FAIL( "Content::loadData - Got no Compressed value!" );
2239  return false;
2240  }
2241  catch ( lang::WrappedTargetException const & )
2242  {
2243  OSL_FAIL( "Content::loadData - Got no Compressed value!" );
2244  return false;
2245  }
2246 
2247  // Encrypted ( only available for streams )
2248  try
2249  {
2250  uno::Any aEncrypted = xPropSet->getPropertyValue("Encrypted");
2251  if ( !( aEncrypted >>= rProps.bEncrypted ) )
2252  {
2253  OSL_FAIL( "Content::loadData - Got no Encrypted value!" );
2254  return false;
2255  }
2256  }
2257  catch ( beans::UnknownPropertyException const & )
2258  {
2259  OSL_FAIL( "Content::loadData - Got no Encrypted value!" );
2260  return false;
2261  }
2262  catch ( lang::WrappedTargetException const & )
2263  {
2264  OSL_FAIL( "Content::loadData - Got no Encrypted value!" );
2265  return false;
2266  }
2267  }
2268  return true;
2269  }
2270  }
2271  catch ( container::NoSuchElementException const & )
2272  {
2273  // getByHierarchicalName
2274  }
2275 
2276  return false;
2277 }
2278 
2279 
2280 void Content::renameData(
2281  const uno::Reference< ucb::XContentIdentifier >& xOldId,
2282  const uno::Reference< ucb::XContentIdentifier >& xNewId )
2283 {
2284  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2285 
2286  PackageUri aURI( xOldId->getContentIdentifier() );
2287  uno::Reference< container::XHierarchicalNameAccess > xNA = getPackage(
2288  aURI );
2289 
2290  if ( !xNA->hasByHierarchicalName( aURI.getPath() ) )
2291  return;
2292 
2293  try
2294  {
2295  uno::Any aEntry = xNA->getByHierarchicalName( aURI.getPath() );
2296  uno::Reference< container::XNamed > xNamed;
2297  aEntry >>= xNamed;
2298 
2299  if ( !xNamed.is() )
2300  {
2301  OSL_FAIL( "Content::renameData - Got no XNamed interface!" );
2302  return;
2303  }
2304 
2305  PackageUri aNewURI( xNewId->getContentIdentifier() );
2306 
2307  // No success indicator!? No return value / exceptions specified.
2308  xNamed->setName( aNewURI.getName() );
2309  }
2310  catch ( container::NoSuchElementException const & )
2311  {
2312  // getByHierarchicalName
2313  }
2314 }
2315 
2316 
2317 bool Content::storeData( const uno::Reference< io::XInputStream >& xStream )
2318 {
2319  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2320 
2321  uno::Reference< container::XHierarchicalNameAccess > xNA = getPackage();
2322 
2323  uno::Reference< beans::XPropertySet > xPackagePropSet(
2324  xNA, uno::UNO_QUERY );
2325  OSL_ENSURE( xPackagePropSet.is(),
2326  "Content::storeData - "
2327  "Got no XPropertySet interface from package!" );
2328 
2329  if ( !xPackagePropSet.is() )
2330  return false;
2331 
2332  if ( m_nModifiedProps & ENCRYPTIONKEY_MODIFIED )
2333  {
2334  if ( m_aUri.isRootFolder() )
2335  {
2336  // Property available only from package and from streams (see below)
2337  try
2338  {
2339  xPackagePropSet->setPropertyValue(
2340  "EncryptionKey",
2342  m_nModifiedProps &= ~ENCRYPTIONKEY_MODIFIED;
2343  }
2344  catch ( beans::UnknownPropertyException const & )
2345  {
2346  // setPropertyValue
2347  }
2348  catch ( beans::PropertyVetoException const & )
2349  {
2350  // setPropertyValue
2351  }
2352  catch ( lang::IllegalArgumentException const & )
2353  {
2354  // setPropertyValue
2355  }
2356  catch ( lang::WrappedTargetException const & )
2357  {
2358  // setPropertyValue
2359  }
2360  }
2361  }
2362 
2363  if ( !xNA->hasByHierarchicalName( m_aUri.getPath() ) )
2364  {
2365 // if ( !bCreate )
2366 // return sal_True;
2367 
2368  try
2369  {
2370  // Create new resource...
2371  uno::Reference< lang::XSingleServiceFactory > xFac(
2372  xNA, uno::UNO_QUERY );
2373  if ( !xFac.is() )
2374  {
2375  OSL_FAIL( "Content::storeData - "
2376  "Got no XSingleServiceFactory interface!" );
2377  return false;
2378  }
2379 
2380  uno::Sequence< uno::Any > aArgs{ uno::Any(isFolder()) };
2381 
2382  uno::Reference< uno::XInterface > xNew
2383  = xFac->createInstanceWithArguments( aArgs );
2384 
2385  if ( !xNew.is() )
2386  {
2387  OSL_FAIL( "Content::storeData - createInstance failed!" );
2388  return false;
2389  }
2390 
2391  PackageUri aParentUri( getParentURL() );
2392  uno::Any aEntry
2393  = xNA->getByHierarchicalName( aParentUri.getPath() );
2394  uno::Reference< container::XNameContainer > xParentContainer;
2395  aEntry >>= xParentContainer;
2396 
2397  if ( !xParentContainer.is() )
2398  {
2399  OSL_FAIL( "Content::storeData - "
2400  "Got no XNameContainer interface!" );
2401  return false;
2402  }
2403 
2404  xParentContainer->insertByName( m_aProps.aTitle,
2405  uno::Any( xNew ) );
2406  }
2407  catch ( lang::IllegalArgumentException const & )
2408  {
2409  // insertByName
2410  OSL_FAIL( "Content::storeData - insertByName failed!" );
2411  return false;
2412  }
2413  catch ( uno::RuntimeException const & )
2414  {
2415  throw;
2416  }
2417  catch ( container::ElementExistException const & )
2418  {
2419  // insertByName
2420  OSL_FAIL( "Content::storeData - insertByName failed!" );
2421  return false;
2422  }
2423  catch ( lang::WrappedTargetException const & )
2424  {
2425  // insertByName
2426  OSL_FAIL( "Content::storeData - insertByName failed!" );
2427  return false;
2428  }
2429  catch ( container::NoSuchElementException const & )
2430  {
2431  // getByHierarchicalName
2432  OSL_FAIL( "Content::storeData - getByHierarchicalName failed!" );
2433  return false;
2434  }
2435  catch ( uno::Exception const & )
2436  {
2437  // createInstanceWithArguments
2438  OSL_FAIL( "Content::storeData - Error!" );
2439  return false;
2440  }
2441  }
2442 
2443  if ( !xNA->hasByHierarchicalName( m_aUri.getPath() ) )
2444  return false;
2445 
2446  try
2447  {
2448  uno::Reference< beans::XPropertySet > xPropSet;
2449  xNA->getByHierarchicalName( m_aUri.getPath() ) >>= xPropSet;
2450 
2451  if ( !xPropSet.is() )
2452  {
2453  OSL_FAIL( "Content::storeData - Got no XPropertySet interface!" );
2454  return false;
2455  }
2456 
2457 
2458  // Store property values...
2459 
2460 
2462  {
2463  xPropSet->setPropertyValue(
2464  "MediaType",
2466  m_nModifiedProps &= ~MEDIATYPE_MODIFIED;
2467  }
2468 
2470  {
2471  if ( !isFolder() )
2472  xPropSet->setPropertyValue(
2473  "Compressed",
2475 
2476  m_nModifiedProps &= ~COMPRESSED_MODIFIED;
2477  }
2478 
2480  {
2481  if ( !isFolder() )
2482  xPropSet->setPropertyValue(
2483  "Encrypted",
2485 
2486  m_nModifiedProps &= ~ENCRYPTED_MODIFIED;
2487  }
2488 
2489  if ( m_nModifiedProps & ENCRYPTIONKEY_MODIFIED )
2490  {
2491  if ( !isFolder() )
2492  xPropSet->setPropertyValue(
2493  "EncryptionKey",
2495 
2496  m_nModifiedProps &= ~ENCRYPTIONKEY_MODIFIED;
2497  }
2498 
2499 
2500  // Store data stream...
2501 
2502 
2503  if ( xStream.is() && !isFolder() )
2504  {
2505  uno::Reference< io::XActiveDataSink > xSink(
2506  xPropSet, uno::UNO_QUERY );
2507 
2508  if ( !xSink.is() )
2509  {
2510  OSL_FAIL( "Content::storeData - "
2511  "Got no XActiveDataSink interface!" );
2512  return false;
2513  }
2514 
2515  xSink->setInputStream( xStream );
2516  }
2517 
2518  return true;
2519  }
2520  catch ( container::NoSuchElementException const & )
2521  {
2522  // getByHierarchicalName
2523  }
2524  catch ( beans::UnknownPropertyException const & )
2525  {
2526  // setPropertyValue
2527  }
2528  catch ( beans::PropertyVetoException const & )
2529  {
2530  // setPropertyValue
2531  }
2532  catch ( lang::IllegalArgumentException const & )
2533  {
2534  // setPropertyValue
2535  }
2536  catch ( lang::WrappedTargetException const & )
2537  {
2538  // setPropertyValue
2539  }
2540 
2541  OSL_FAIL( "Content::storeData - Error!" );
2542  return false;
2543 }
2544 
2545 
2547 {
2548  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2549 
2550  uno::Reference< container::XHierarchicalNameAccess > xNA = getPackage();
2551 
2552  PackageUri aParentUri( getParentURL() );
2553  if ( !xNA->hasByHierarchicalName( aParentUri.getPath() ) )
2554  return false;
2555 
2556  try
2557  {
2558  uno::Any aEntry = xNA->getByHierarchicalName( aParentUri.getPath() );
2559  uno::Reference< container::XNameContainer > xContainer;
2560  aEntry >>= xContainer;
2561 
2562  if ( !xContainer.is() )
2563  {
2564  OSL_FAIL( "Content::removeData - "
2565  "Got no XNameContainer interface!" );
2566  return false;
2567  }
2568 
2569  xContainer->removeByName( m_aUri.getName() );
2570  return true;
2571  }
2572  catch ( container::NoSuchElementException const & )
2573  {
2574  // getByHierarchicalName, removeByName
2575  }
2576  catch ( lang::WrappedTargetException const & )
2577  {
2578  // removeByName
2579  }
2580 
2581  OSL_FAIL( "Content::removeData - Error!" );
2582  return false;
2583 }
2584 
2585 
2587 {
2588  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2589 
2590  // Note: XChangesBatch is only implemented by the package itself, not
2591  // by the single entries. Maybe this has to change...
2592 
2593  uno::Reference< container::XHierarchicalNameAccess > xNA = getPackage();
2594 
2595  uno::Reference< util::XChangesBatch > xBatch( xNA, uno::UNO_QUERY );
2596  if ( !xBatch.is() )
2597  {
2598  OSL_FAIL( "Content::flushData - Got no XChangesBatch interface!" );
2599  return false;
2600  }
2601 
2602  try
2603  {
2604  xBatch->commitChanges();
2605  return true;
2606  }
2607  catch ( lang::WrappedTargetException const & )
2608  {
2609  }
2610 
2611  OSL_FAIL( "Content::flushData - Error!" );
2612  return false;
2613 }
2614 
2615 
2616 uno::Reference< io::XInputStream > Content::getInputStream()
2617 {
2618  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2619 
2620  uno::Reference< io::XInputStream > xStream;
2621  uno::Reference< container::XHierarchicalNameAccess > xNA = getPackage();
2622 
2623  if ( !xNA->hasByHierarchicalName( m_aUri.getPath() ) )
2624  return xStream;
2625 
2626  try
2627  {
2628  uno::Any aEntry = xNA->getByHierarchicalName( m_aUri.getPath() );
2629  uno::Reference< io::XActiveDataSink > xSink;
2630  aEntry >>= xSink;
2631 
2632  if ( !xSink.is() )
2633  {
2634  OSL_FAIL( "Content::getInputStream - "
2635  "Got no XActiveDataSink interface!" );
2636  return xStream;
2637  }
2638 
2639  xStream = xSink->getInputStream();
2640 
2641  OSL_ENSURE( xStream.is(),
2642  "Content::getInputStream - Got no stream!" );
2643  }
2644  catch ( container::NoSuchElementException const & )
2645  {
2646  // getByHierarchicalName
2647  }
2648 
2649  return xStream;
2650 }
2651 
2652 
2653 uno::Reference< container::XEnumeration > Content::getIterator()
2654 {
2655  osl::Guard< osl::Mutex > aGuard( m_aMutex );
2656 
2657  uno::Reference< container::XEnumeration > xIter;
2658  uno::Reference< container::XHierarchicalNameAccess > xNA = getPackage();
2659 
2660  if ( !xNA->hasByHierarchicalName( m_aUri.getPath() ) )
2661  return xIter;
2662 
2663  try
2664  {
2665  uno::Any aEntry = xNA->getByHierarchicalName( m_aUri.getPath() );
2666  uno::Reference< container::XEnumerationAccess > xIterFac;
2667  aEntry >>= xIterFac;
2668 
2669  if ( !xIterFac.is() )
2670  {
2671  OSL_FAIL( "Content::getIterator - "
2672  "Got no XEnumerationAccess interface!" );
2673  return xIter;
2674  }
2675 
2676  xIter = xIterFac->createEnumeration();
2677 
2678  OSL_ENSURE( xIter.is(),
2679  "Content::getIterator - Got no iterator!" );
2680  }
2681  catch ( container::NoSuchElementException const & )
2682  {
2683  // getByHierarchicalName
2684  }
2685 
2686  return xIter;
2687 }
2688 
2689 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
tools::SvRef< SvBaseLink > xSink
Type
css::uno::Sequence< sal_Int8 > aEncryptionKey
Definition: pkgcontent.hxx:69
css::uno::Reference< css::uno::XComponentContext > m_xContext
#define MEDIATYPE_MODIFIED
Definition: pkgcontent.cxx:81
URL aURL
bool hasValue()
std::vector< ContentImplHelperRef > ContentRefList
Reference< XRow > xRow
rtl::Reference< Content > ContentRef
Definition: pkgcontent.hxx:168
#define PACKAGE_ZIP_FOLDER_CONTENT_TYPE
Definition: pkgprovider.hxx:38
uno::Sequence< beans::Property > m_aProps
static css::uno::Reference< css::sdbc::XRow > getPropertyValues(const css::uno::Reference< css::uno::XComponentContext > &rxContext, const css::uno::Sequence< css::beans::Property > &rProperties, const ContentProperties &rData, const rtl::Reference< ::ucbhelper::ContentProviderImplHelper > &rProvider, const OUString &rContentId)
virtual OUString SAL_CALL getContentType() override
Definition: pkgcontent.cxx:377
virtual ~Content() override
Definition: pkgcontent.cxx:273
Reference< XInterface > xTarget
sal_Int64 n
std::vector< ContentRef > ContentRefList
Definition: pkgcontent.hxx:169
bool isRootFolder() const
Definition: pkguri.hxx:80
void transfer(const css::ucb::TransferInfo &rInfo, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override
Definition: pkgcontent.cxx:317
virtual OUString SAL_CALL getImplementationName() override
Definition: pkgcontent.cxx:360
virtual css::uno::Sequence< css::ucb::ContentInfo > SAL_CALL queryCreatableContentsInfo() override
Definition: pkgcontent.cxx:631
ContentState m_eState
Definition: pkgcontent.hxx:100
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType) override
virtual css::uno::Reference< css::ucb::XContent > SAL_CALL createNewContent(const css::ucb::ContentInfo &Info) override
void destroy(bool bDeletePhysical, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
OUString encodeSegment(const OUString &rSegment)
Definition: urihelper.hxx:29
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
Definition: pkgcontent.cxx:367
void renameData(const css::uno::Reference< css::ucb::XContentIdentifier > &xOldId, const css::uno::Reference< css::ucb::XContentIdentifier > &xNewId)
virtual void SAL_CALL abort(sal_Int32 CommandId) override
Definition: pkgcontent.cxx:619
css::uno::Reference< css::ucb::XPersistentPropertySet > getAdditionalPropertySet(bool bCreate)
PropertiesInfo aProperties
virtual void SAL_CALL release() noexcept override
Definition: pkgcontent.cxx:290
int nCount
static bool hasData(ContentProvider *pProvider, const PackageUri &rURI, css::uno::Reference< css::container::XHierarchicalNameAccess > &rxPackage)
const OUString & getPath() const
Definition: pkguri.hxx:65
void notifyPropertiesChange(const css::uno::Sequence< css::beans::PropertyChangeEvent > &evt) const
static rtl::Reference< Content > create(const css::uno::Reference< css::uno::XComponentContext > &rxContext, ContentProvider *pProvider, const css::uno::Reference< css::ucb::XContentIdentifier > &Identifier)
ContentProvider * m_pProvider
Definition: pkgcontent.hxx:103
bool renameAdditionalPropertySet(const OUString &rOldKey, const OUString &rNewKey)
#define PACKAGE_FOLDER_CONTENT_TYPE
Definition: pkgprovider.hxx:34
constexpr OUStringLiteral aData
virtual css::uno::Any SAL_CALL execute(const css::ucb::Command &aCommand, sal_Int32 CommandId, const css::uno::Reference< css::ucb::XCommandEnvironment > &Environment) override
sal_uInt32 m_nModifiedProps
Definition: pkgcontent.hxx:104
void queryChildren(ContentRefList &rChildren)
const OUString & getScheme() const
Definition: pkguri.hxx:74
#define COMPRESSED_MODIFIED
Definition: pkgcontent.cxx:82
const OUString & getPackage() const
Definition: pkguri.hxx:62
static bool loadData(ContentProvider *pProvider, const PackageUri &rURI, ContentProperties &rProps, css::uno::Reference< css::container::XHierarchicalNameAccess > &rxPackage)
css::uno::Reference< css::container::XHierarchicalNameAccess > getPackage()
XTYPEPROVIDER_COMMON_IMPL(Content)
void cancelCommandExecution(const uno::Any &rException, const uno::Reference< ucb::XCommandEnvironment > &xEnv)
css::uno::Sequence< css::uno::Any > InitAnyPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
css::uno::Reference< css::ucb::XContentIdentifier > m_xIdentifier
#define PACKAGE_URL_SCHEME_LENGTH
Definition: pkguri.hxx:29
css::uno::Sequence< css::uno::Any > setPropertyValues(const css::uno::Sequence< css::beans::PropertyValue > &rValues, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
css::uno::Any open(const css::ucb::OpenCommandArgument2 &rArg, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
void insert(const css::uno::Reference< css::io::XInputStream > &xStream, sal_Int32 nNameClashResolve, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv)
css::uno::Reference< css::beans::XPropertySetInfo > getPropertySetInfo(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv, bool bCache=true)
float u
Object Value
css::uno::Reference< css::ucb::XCommandInfo > getCommandInfo(const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv, bool bCache=true)
css::uno::Sequence< css::ucb::ContentInfo > getCreatableContentsInfo(PackageUri const &rUri) const
Definition: pkgcontent.cxx:106
css::uno::Reference< css::container::XHierarchicalNameAccess > m_xPackage
Definition: pkgcontent.hxx:102
const OUString & getName() const
Definition: pkguri.hxx:68
bool storeData(const css::uno::Reference< css::io::XInputStream > &xStream)
bool exchangeIdentity(const css::uno::Reference< css::ucb::XContentIdentifier > &xNewId)
rtl::Reference< ContentProviderImplHelper > m_xProvider
const PropertyValue * pValues
std::unique_ptr< char[]> aBuffer
css::uno::Reference< css::io::XInputStream > getInputStream()
ContentProperties m_aProps
Definition: pkgcontent.hxx:99
#define PACKAGE_STREAM_CONTENT_TYPE
Definition: pkgprovider.hxx:36
#define CPPU_TYPE_REF(T)
OUString aName
const OUString & getParentUri() const
Definition: pkguri.hxx:59
uno::Reference< deployment::XPackage > m_xPackage
virtual void SAL_CALL acquire() noexcept override
Definition: pkgcontent.cxx:282
Content(const css::uno::Reference< css::uno::XComponentContext > &rxContext, ContentProvider *pProvider, const css::uno::Reference< css::ucb::XContentIdentifier > &Identifier, const css::uno::Reference< css::container::XHierarchicalNameAccess > &Package, const PackageUri &rUri, const ContentProperties &rProps)
Sequence< sal_Int8 > aSeq
css::uno::Sequence< css::uno::Type > SAL_CALL getTypes()
virtual OUString getParentURL() override
Definition: pkgcontent.cxx:679
bool isFolder() const
Definition: pkgcontent.hxx:198
#define NONE_MODIFIED
Definition: pkgcontent.cxx:80
bool exchange(const css::uno::Reference< css::ucb::XContentIdentifier > &rNewId)
#define PACKAGE_ZIP_STREAM_CONTENT_TYPE
Definition: pkgprovider.hxx:40
css::uno::Reference< css::container::XHierarchicalNameAccess > createPackage(const PackageUri &rParam)
const OUString & getUri() const
Definition: pkguri.hxx:53
#define ENCRYPTED_MODIFIED
Definition: pkgcontent.cxx:83
css::uno::Reference< css::container::XEnumeration > getIterator()
css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType, Interface1 *p1)
AnyEventRef aEvent
Reference< XContentIdentifier > xId
bool m_bDetectedRangeSegmentation false
#define ENCRYPTIONKEY_MODIFIED
Definition: pkgcontent.cxx:84
OUString aId