LibreOffice Module package (master) 1
owriteablestream.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 <sal/config.h>
21
22#include <cassert>
23#include <memory>
24#include <sal/log.hxx>
25
26#include <com/sun/star/packages/NoEncryptionException.hpp>
27#include <com/sun/star/packages/WrongPasswordException.hpp>
28#include <com/sun/star/uno/XComponentContext.hpp>
29#include <com/sun/star/ucb/SimpleFileAccess.hpp>
30#include <com/sun/star/lang/DisposedException.hpp>
31#include <com/sun/star/lang/XTypeProvider.hpp>
32#include <com/sun/star/io/NotConnectedException.hpp>
33#include <com/sun/star/io/TempFile.hpp>
34#include <com/sun/star/io/XInputStream.hpp>
35#include <com/sun/star/io/IOException.hpp>
36#include <com/sun/star/embed/ElementModes.hpp>
37#include <com/sun/star/embed/StorageFormats.hpp>
38#include <com/sun/star/embed/StorageWrappedTargetException.hpp>
39#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
43#include <osl/diagnose.h>
44
51
53
54#include <PackageConstants.hxx>
55#include <utility>
56
58#include "owriteablestream.hxx"
59#include "oseekinstream.hxx"
60#include "xstorage.hxx"
61
62// since the copying uses 32000 blocks usually, it makes sense to have a smaller size
63#define MAX_STORCACHE_SIZE 30000
64
65using namespace ::com::sun::star;
66
67namespace package
68{
69
71 const css::uno::Reference< css::io::XInputStream >& xInput,
72 SvStream& rOutput )
73{
74 static const sal_Int32 nConstBufferSize = 32000;
75
76 if (auto pByteReader = dynamic_cast< comphelper::ByteReader* >( xInput.get() ))
77 {
78 sal_Int32 nRead;
79 sal_Int8 aTempBuf[ nConstBufferSize ];
80 do
81 {
82 nRead = pByteReader->readSomeBytes ( aTempBuf, nConstBufferSize );
83 rOutput.WriteBytes ( aTempBuf, nRead );
84 }
85 while ( nRead == nConstBufferSize );
86 }
87 else
88 {
89 sal_Int32 nRead;
90 uno::Sequence < sal_Int8 > aSequence ( nConstBufferSize );
91
92 do
93 {
94 nRead = xInput->readBytes ( aSequence, nConstBufferSize );
95 rOutput.WriteBytes ( aSequence.getConstArray(), nRead );
96 }
97 while ( nRead == nConstBufferSize );
98 }
99}
100
101bool PackageEncryptionDataLessOrEqual( const ::comphelper::SequenceAsHashMap& aHash1, const ::comphelper::SequenceAsHashMap& aHash2 )
102{
103 // tdf#93389: aHash2 may contain more than in aHash1, if it contains also data for other package
104 // formats (as in case of autorecovery)
105 bool bResult = !aHash1.empty() && aHash1.size() <= aHash2.size();
106 for ( ::comphelper::SequenceAsHashMap::const_iterator aIter = aHash1.begin();
107 bResult && aIter != aHash1.end();
108 ++aIter )
109 {
110 uno::Sequence< sal_Int8 > aKey1;
111 bResult = ( ( aIter->second >>= aKey1 ) && aKey1.hasElements() );
112 if ( bResult )
113 {
114 const uno::Sequence< sal_Int8 > aKey2 = aHash2.getUnpackedValueOrDefault( aIter->first.maString, uno::Sequence< sal_Int8 >() );
115 bResult = aKey1.getLength() == aKey2.getLength()
116 && std::equal(std::cbegin(aKey1), std::cend(aKey1), aKey2.begin(), aKey2.end());
117 }
118 }
119
120 return bResult;
121}
122
123} // namespace package
124
125namespace
126{
127
128void SetEncryptionKeyProperty_Impl( const uno::Reference< beans::XPropertySet >& xPropertySet,
129 const uno::Sequence< beans::NamedValue >& aKey )
130{
131 SAL_WARN_IF( !xPropertySet.is(), "package.xstor", "No property set is provided!" );
132 if ( !xPropertySet.is() )
133 throw uno::RuntimeException();
134
135 try {
136 xPropertySet->setPropertyValue( STORAGE_ENCRYPTION_KEYS_PROPERTY, uno::Any( aKey ) );
137 }
138 catch ( const uno::Exception& ex )
139 {
140 TOOLS_WARN_EXCEPTION( "package.xstor", "Can't write encryption related properties");
141 throw io::IOException(ex.Message); // TODO
142 }
143}
144
145uno::Any GetEncryptionKeyProperty_Impl( const uno::Reference< beans::XPropertySet >& xPropertySet )
146{
147 SAL_WARN_IF( !xPropertySet.is(), "package.xstor", "No property set is provided!" );
148 if ( !xPropertySet.is() )
149 throw uno::RuntimeException();
150
151 try {
152 return xPropertySet->getPropertyValue(STORAGE_ENCRYPTION_KEYS_PROPERTY);
153 }
154 catch ( const uno::Exception& ex )
155 {
156 TOOLS_WARN_EXCEPTION( "package.xstor", "Can't get encryption related properties");
157 throw io::IOException(ex.Message); // TODO
158 }
159}
160
161bool SequencesEqual( const uno::Sequence< sal_Int8 >& aSequence1, const uno::Sequence< sal_Int8 >& aSequence2 )
162{
163 return aSequence1.getLength() == aSequence2.getLength()
164 && std::equal(aSequence1.begin(), aSequence1.end(), aSequence2.begin(), aSequence2.end());
165}
166
167bool SequencesEqual( const uno::Sequence< beans::NamedValue >& aSequence1, const uno::Sequence< beans::NamedValue >& aSequence2 )
168{
169 if ( aSequence1.getLength() != aSequence2.getLength() )
170 return false;
171
172 for ( const auto& rProp1 : aSequence1 )
173 {
174 bool bHasMember = false;
175 uno::Sequence< sal_Int8 > aMember1;
176 sal_Int32 nMember1 = 0;
177 if ( rProp1.Value >>= aMember1 )
178 {
179 for ( const auto& rProp2 : aSequence2 )
180 {
181 if ( rProp1.Name == rProp2.Name )
182 {
183 bHasMember = true;
184
185 uno::Sequence< sal_Int8 > aMember2;
186 if ( !( rProp2.Value >>= aMember2 ) || !SequencesEqual( aMember1, aMember2 ) )
187 return false;
188 }
189 }
190 }
191 else if ( rProp1.Value >>= nMember1 )
192 {
193 for ( const auto& rProp2 : aSequence2 )
194 {
195 if ( rProp1.Name == rProp2.Name )
196 {
197 bHasMember = true;
198
199 sal_Int32 nMember2 = 0;
200 if ( !( rProp2.Value >>= nMember2 ) || nMember1 != nMember2 )
201 return false;
202 }
203 }
204 }
205 else
206 return false;
207
208 if ( !bHasMember )
209 return false;
210 }
211
212 return true;
213}
214
215uno::Reference< io::XStream > CreateMemoryStream( const uno::Reference< uno::XComponentContext >& rContext )
216{
217 static constexpr OUStringLiteral sName(u"com.sun.star.comp.MemoryStream");
218 return uno::Reference< io::XStream >(
219 rContext->getServiceManager()->createInstanceWithContext(sName, rContext),
220 uno::UNO_QUERY_THROW);
221}
222
223const beans::StringPair* lcl_findPairByName(const uno::Sequence<beans::StringPair>& rSeq, const OUString& rName)
224{
225 return std::find_if(rSeq.begin(), rSeq.end(),
226 [&rName](const beans::StringPair& rPair) { return rPair.First == rName; });
227}
228
229} // anonymous namespace
230
232 const uno::Reference< packages::XDataSinkEncrSupport >& xPackageStream,
233 const uno::Reference< lang::XSingleServiceFactory >& xPackage,
234 uno::Reference< uno::XComponentContext > xContext,
235 bool bForceEncrypted,
236 sal_Int32 nStorageType,
237 bool bDefaultCompress,
238 uno::Reference< io::XInputStream > xRelInfoStream )
239: m_xMutex( new comphelper::RefCountedMutex )
240, m_pAntiImpl( nullptr )
241, m_bHasDataToFlush( false )
242, m_bFlushed( false )
243, m_xPackageStream( xPackageStream )
244, m_xContext(std::move( xContext ))
245, m_pParent( pParent )
246, m_bForceEncrypted( bForceEncrypted )
247, m_bUseCommonEncryption( !bForceEncrypted && nStorageType == embed::StorageFormats::PACKAGE )
248, m_bHasCachedEncryptionData( false )
249, m_bCompressedSetExplicit( !bDefaultCompress )
250, m_xPackage( xPackage )
251, m_bHasInsertedStreamOptimization( false )
252, m_nStorageType( nStorageType )
253, m_xOrigRelInfoStream(std::move( xRelInfoStream ))
254, m_bOrigRelInfoBroken( false )
255, m_nRelInfoStatus( RELINFO_NO_INIT )
256, m_nRelId( 1 )
257{
258 SAL_WARN_IF( !xPackageStream.is(), "package.xstor", "No package stream is provided!" );
259 SAL_WARN_IF( !xPackage.is(), "package.xstor", "No package component is provided!" );
260 SAL_WARN_IF( !m_xContext.is(), "package.xstor", "No package stream is provided!" );
261 OSL_ENSURE( pParent, "No parent storage is provided!" );
262 OSL_ENSURE( m_nStorageType == embed::StorageFormats::OFOPXML || !m_xOrigRelInfoStream.is(), "The Relations info makes sense only for OFOPXML format!" );
263}
264
266{
268
269 m_oTempFile.reset();
270
272}
273
275{
276 if ( !m_xCacheStream.is() )
277 return;
278
279 try
280 {
281 uno::Reference< io::XInputStream > xInputCache = m_xCacheStream->getInputStream();
282 if ( xInputCache.is() )
283 xInputCache->closeInput();
284 }
285 catch( const uno::Exception& )
286 {}
287
288 try
289 {
290 uno::Reference< io::XOutputStream > xOutputCache = m_xCacheStream->getOutputStream();
291 if ( xOutputCache.is() )
292 xOutputCache->closeOutput();
293 }
294 catch( const uno::Exception& )
295 {}
296
297 m_xCacheStream.clear();
298 m_xCacheSeek.clear();
299}
300
302 const uno::Reference< container::XNameContainer >& xParentPackageFolder )
303{
304 ::osl::MutexGuard aGuard( m_xMutex->GetMutex() );
305
306 SAL_WARN_IF( !m_bFlushed, "package.xstor", "This method must not be called for nonflushed streams!" );
307 if ( m_bFlushed )
308 {
309 SAL_WARN_IF( !m_xPackageStream.is(), "package.xstor", "An inserted stream is incomplete!" );
310 uno::Reference< uno::XInterface > xTmp( m_xPackageStream, uno::UNO_QUERY_THROW );
311 xParentPackageFolder->insertByName( aName, uno::Any( xTmp ) );
312
313 m_bFlushed = false;
315 }
316}
318{
319 if ( m_nStorageType != embed::StorageFormats::PACKAGE )
320 return false;
321
323 return true;
324
325 if ( m_oTempFile.has_value() || m_xCacheStream.is() )
326 return false;
327
329
330 // the following value can not be cached since it can change after root commit
331 bool bWasEncr = false;
332 uno::Reference< beans::XPropertySet > xPropSet( m_xPackageStream, uno::UNO_QUERY );
333 if ( xPropSet.is() )
334 {
335 uno::Any aValue = xPropSet->getPropertyValue("WasEncrypted");
336 if ( !( aValue >>= bWasEncr ) )
337 {
338 SAL_WARN( "package.xstor", "The property WasEncrypted has wrong type!" );
339 }
340 }
341
342 bool bToBeEncr = false;
343 for ( const auto& rProp : std::as_const(m_aProps) )
344 {
345 if ( rProp.Name == "Encrypted" )
346 {
347 if ( !( rProp.Value >>= bToBeEncr ) )
348 {
349 SAL_WARN( "package.xstor", "The property has wrong type!" );
350 }
351 }
352 }
353
354 // since a new key set to the package stream it should not be removed except the case when
355 // the stream becomes nonencrypted
356 uno::Sequence< beans::NamedValue > aKey;
357 if ( bToBeEncr )
358 GetEncryptionKeyProperty_Impl( xPropSet ) >>= aKey;
359
360 // If the properties must be investigated the stream is either
361 // was never changed or was changed, the parent was committed
362 // and the stream was closed.
363 // That means that if it is intended to use common storage key
364 // it is already has no encryption but is marked to be stored
365 // encrypted and the key is empty.
366 if ( !bWasEncr && bToBeEncr && !aKey.hasElements() )
367 {
368 // the stream is intended to use common storage password
370 return false;
371 }
372 else
373 return bToBeEncr;
374}
375
377{
378 SAL_WARN_IF( m_nStorageType != embed::StorageFormats::PACKAGE, "package.xstor", "The encryption is supported only for package storages!" );
379 if ( m_nStorageType != embed::StorageFormats::PACKAGE )
380 throw uno::RuntimeException();
381
383
384 // let the stream be modified
386 m_bHasDataToFlush = true;
387
388 // remove encryption
389 m_bForceEncrypted = false;
392
393 for ( auto& rProp : asNonConstRange(m_aProps) )
394 {
395 if ( rProp.Name == "Encrypted" )
396 rProp.Value <<= false;
397 }
398}
399
400void OWriteStream_Impl::SetEncrypted( const ::comphelper::SequenceAsHashMap& aEncryptionData )
401{
402 SAL_WARN_IF( m_nStorageType != embed::StorageFormats::PACKAGE, "package.xstor", "The encryption is supported only for package storages!" );
403 if ( m_nStorageType != embed::StorageFormats::PACKAGE )
404 throw uno::RuntimeException();
405
406 if ( aEncryptionData.empty() )
407 throw uno::RuntimeException();
408
410
411 // let the stream be modified
413 m_bHasDataToFlush = true;
414
415 // introduce encryption info
416 for ( auto& rProp : asNonConstRange(m_aProps) )
417 {
418 if ( rProp.Name == "Encrypted" )
419 rProp.Value <<= true;
420 }
421
422 m_bUseCommonEncryption = false; // very important to set it to false
423
425 m_aEncryptionData = aEncryptionData;
426}
427
429{
430 ::osl::MutexGuard aGuard( m_xMutex->GetMutex() );
431 if ( m_pAntiImpl )
432 {
433 try {
435 }
436 catch ( const uno::RuntimeException& )
437 {
438 TOOLS_INFO_EXCEPTION("package.xstor", "Quiet exception");
439 }
440
441 m_pAntiImpl = nullptr;
442 }
443 m_pParent = nullptr;
444
445 if ( m_aInputStreamsVector.empty() )
446 return;
447
448 for ( auto& pStream : m_aInputStreamsVector )
449 {
450 if ( pStream )
451 {
452 pStream->InternalDispose();
453 pStream = nullptr;
454 }
455 }
456
457 m_aInputStreamsVector.clear();
458}
459
460void OWriteStream_Impl::GetFilledTempFileIfNo( const uno::Reference< io::XInputStream >& xStream )
461{
462 if ( !m_oTempFile.has_value() )
463 {
464 m_oTempFile.emplace();
465
466 try {
467 if ( xStream.is() )
468 {
469 // the current position of the original stream should be still OK, copy further
470 package::CopyInputToOutput( xStream, *m_oTempFile->GetStream(StreamMode::READWRITE) );
471 }
472 }
473 catch( const packages::WrongPasswordException& )
474 {
475 TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
476 m_oTempFile.reset();
477 throw;
478 }
479 catch( const uno::Exception& )
480 {
481 TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
482 m_oTempFile.reset();
483 throw;
484 }
485
486 if ( m_oTempFile.has_value() )
488 }
489}
490
492{
493 // should try to create cache first, if the amount of contents is too big, the temp file should be taken
494 if ( !m_xCacheStream.is() && !m_oTempFile.has_value() )
495 {
496 uno::Reference< io::XInputStream > xOrigStream = m_xPackageStream->getDataStream();
497 if ( !xOrigStream.is() )
498 {
499 // in case of new inserted package stream it is possible that input stream still was not set
500 uno::Reference< io::XStream > xCacheStream = CreateMemoryStream( m_xContext );
501 SAL_WARN_IF( !xCacheStream.is(), "package.xstor", "If the stream can not be created an exception must be thrown!" );
502 m_xCacheSeek.set( xCacheStream, uno::UNO_QUERY_THROW );
503 m_xCacheStream = xCacheStream;
504 }
505 else
506 {
507 sal_Int32 nRead = 0;
508 uno::Sequence< sal_Int8 > aData( MAX_STORCACHE_SIZE + 1 );
509 nRead = xOrigStream->readBytes( aData, MAX_STORCACHE_SIZE + 1 );
510 if ( aData.getLength() > nRead )
511 aData.realloc( nRead );
512
513 if ( nRead <= MAX_STORCACHE_SIZE )
514 {
515 uno::Reference< io::XStream > xCacheStream = CreateMemoryStream( m_xContext );
516 SAL_WARN_IF( !xCacheStream.is(), "package.xstor", "If the stream can not be created an exception must be thrown!" );
517
518 if ( nRead )
519 {
520 uno::Reference< io::XOutputStream > xOutStream( xCacheStream->getOutputStream(), uno::UNO_SET_THROW );
521 xOutStream->writeBytes( aData );
522 }
523 m_xCacheSeek.set( xCacheStream, uno::UNO_QUERY_THROW );
524 m_xCacheStream = xCacheStream;
525 m_xCacheSeek->seek( 0 );
526 }
527 else if ( !m_oTempFile.has_value() )
528 {
529 m_oTempFile.emplace();
530
531 try {
532 // copy stream contents to the file
533 SvStream* pStream = m_oTempFile->GetStream(StreamMode::READWRITE);
534 pStream->WriteBytes( aData.getConstArray(), aData.getLength() );
535
536 // the current position of the original stream should be still OK, copy further
537 package::CopyInputToOutput( xOrigStream, *pStream );
538 }
539 catch( const packages::WrongPasswordException& )
540 {
541 m_oTempFile.reset();
542 throw;
543 }
544 catch( const uno::Exception& )
545 {
546 m_oTempFile.reset();
547 }
548 }
549 }
550 }
551}
552
553uno::Reference< io::XStream > OWriteStream_Impl::GetTempFileAsStream()
554{
555 uno::Reference< io::XStream > xTempStream;
556
557 if ( !m_xCacheStream.is() )
558 {
559 if ( !m_oTempFile.has_value() )
561
562 if ( m_oTempFile.has_value() )
563 {
564 // the temporary file is not used if the cache is used
565 try
566 {
567 SvStream* pStream = m_oTempFile->GetStream(StreamMode::READWRITE);
568 pStream->Seek(0);
569 xTempStream = new utl::OStreamWrapper(pStream, /*bOwner*/false);
570 }
571 catch( const uno::Exception& )
572 {
573 TOOLS_INFO_EXCEPTION("package.xstor", "Quiet exception");
574 }
575 }
576 }
577
578 if ( m_xCacheStream.is() )
579 xTempStream = m_xCacheStream;
580
581 // the method must always return a stream
582 // in case the stream can not be open
583 // an exception should be thrown
584 if ( !xTempStream.is() )
585 throw io::IOException("no temp stream"); //TODO:
586
587 return xTempStream;
588}
589
590uno::Reference< io::XInputStream > OWriteStream_Impl::GetTempFileAsInputStream()
591{
592 uno::Reference< io::XInputStream > xInputStream;
593
594 if ( !m_xCacheStream.is() )
595 {
596 if ( !m_oTempFile.has_value() )
598
599 if ( m_oTempFile.has_value() )
600 {
601 // the temporary file is not used if the cache is used
602 try
603 {
604 SvStream* pStream = m_oTempFile->GetStream(StreamMode::READWRITE);
605 pStream->Seek(0);
606 xInputStream = new utl::OStreamWrapper(pStream, /*bOwner*/false);
607 }
608 catch( const uno::Exception& )
609 {
610 TOOLS_INFO_EXCEPTION("package.xstor", "Quiet exception");
611 }
612 }
613 }
614
615 if ( m_xCacheStream.is() )
616 xInputStream = m_xCacheStream->getInputStream();
617
618 // the method must always return a stream
619 // in case the stream can not be open
620 // an exception should be thrown
621 if ( !xInputStream.is() )
622 throw io::IOException(); // TODO:
623
624 return xInputStream;
625}
626
627void OWriteStream_Impl::InsertStreamDirectly( const uno::Reference< io::XInputStream >& xInStream,
628 const uno::Sequence< beans::PropertyValue >& aProps )
629{
630 ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
631
632 // this call can be made only during parent storage commit
633 // the parent storage is responsible for the correct handling
634 // of deleted and renamed contents
635
636 SAL_WARN_IF( !m_xPackageStream.is(), "package.xstor", "No package stream is set!" );
637
638 if ( m_bHasDataToFlush )
639 throw io::IOException("m_bHasDataToFlush==true");
640
641 OSL_ENSURE( !m_oTempFile.has_value() && !m_xCacheStream.is(), "The temporary must not exist!" );
642
643 // use new file as current persistent representation
644 // the new file will be removed after it's stream is closed
645 m_xPackageStream->setDataStream( xInStream );
646
647 // copy properties to the package stream
648 uno::Reference< beans::XPropertySet > xPropertySet( m_xPackageStream, uno::UNO_QUERY_THROW );
649
650 // The storage-package communication has a problem
651 // the storage caches properties, thus if the package changes one of them itself
652 // the storage does not know about it
653
654 // Depending from MediaType value the package can change the compressed property itself
655 // Thus if Compressed property is provided it must be set as the latest one
656 bool bCompressedIsSet = false;
657 bool bCompressed = false;
658 OUString aComprPropName( "Compressed" );
659 OUString aMedTypePropName( "MediaType" );
660 for ( const auto& rProp : aProps )
661 {
662 if ( rProp.Name == aComprPropName )
663 {
664 bCompressedIsSet = true;
665 rProp.Value >>= bCompressed;
666 }
667 else if ( ( m_nStorageType == embed::StorageFormats::OFOPXML || m_nStorageType == embed::StorageFormats::PACKAGE )
668 && rProp.Name == aMedTypePropName )
669 {
670 xPropertySet->setPropertyValue( rProp.Name, rProp.Value );
671 }
672 else if ( m_nStorageType == embed::StorageFormats::PACKAGE && rProp.Name == "UseCommonStoragePasswordEncryption" )
673 rProp.Value >>= m_bUseCommonEncryption;
674 else
675 throw lang::IllegalArgumentException();
676
677 // if there are cached properties update them
678 if ( rProp.Name == aMedTypePropName || rProp.Name == aComprPropName )
679 for ( auto& rMemProp : asNonConstRange(m_aProps) )
680 {
681 if ( rProp.Name == rMemProp.Name )
682 rMemProp.Value = rProp.Value;
683 }
684 }
685
686 if ( bCompressedIsSet )
687 {
688 xPropertySet->setPropertyValue( aComprPropName, uno::Any( bCompressed ) );
690 }
691
693 {
694 if ( m_nStorageType != embed::StorageFormats::PACKAGE )
695 throw uno::RuntimeException();
696
697 // set to be encrypted but do not use encryption key
698 xPropertySet->setPropertyValue( STORAGE_ENCRYPTION_KEYS_PROPERTY,
699 uno::Any( uno::Sequence< beans::NamedValue >() ) );
700 xPropertySet->setPropertyValue( "Encrypted", uno::Any( true ) );
701 }
702
703 // the stream should be free soon, after package is stored
704 m_bHasDataToFlush = false;
705 m_bFlushed = true; // will allow to use transaction on stream level if will need it
707}
708
710{
711 ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
712
713 SAL_WARN_IF( !m_xPackageStream.is(), "package.xstor", "No package stream is set!" );
714
715 if ( !m_bHasDataToFlush )
716 return;
717
718 uno::Reference< packages::XDataSinkEncrSupport > xNewPackageStream;
719 uno::Sequence< uno::Any > aSeq{ uno::Any(false) };
720
721 if ( m_xCacheStream.is() )
722 {
723 if ( m_pAntiImpl )
725
726 uno::Reference< io::XInputStream > xInStream( m_xCacheStream->getInputStream(), uno::UNO_SET_THROW );
727
728 xNewPackageStream.set( m_xPackage->createInstanceWithArguments( aSeq ), uno::UNO_QUERY_THROW );
729
730 xNewPackageStream->setDataStream( xInStream );
731
732 m_xCacheStream.clear();
733 m_xCacheSeek.clear();
734
735 }
736 else if ( m_oTempFile.has_value() )
737 {
738 if ( m_pAntiImpl )
740
741 uno::Reference< io::XInputStream > xInStream;
742 try
743 {
744 xInStream = new OSelfTerminateFileStream(m_xContext, std::move(*m_oTempFile));
745 }
746 catch( const uno::Exception& )
747 {
748 TOOLS_WARN_EXCEPTION("package", "");
749 }
750
751 if ( !xInStream.is() )
752 throw io::IOException();
753
754 xNewPackageStream.set( m_xPackage->createInstanceWithArguments( aSeq ), uno::UNO_QUERY_THROW );
755
756 // TODO/NEW: Let the temporary file be removed after commit
757 xNewPackageStream->setDataStream( xInStream );
758 m_oTempFile.reset();
759 }
760 else // if ( m_bHasInsertedStreamOptimization )
761 {
762 // if the optimization is used the stream can be accessed directly
763 xNewPackageStream = m_xPackageStream;
764 }
765
766 // copy properties to the package stream
767 uno::Reference< beans::XPropertySet > xPropertySet( xNewPackageStream, uno::UNO_QUERY_THROW );
768
769 for ( auto& rProp : asNonConstRange(m_aProps) )
770 {
771 if ( rProp.Name == "Size" )
772 {
774 {
775 rProp.Value <<= m_pAntiImpl->m_xSeekable->getLength();
776 xPropertySet->setPropertyValue( rProp.Name, rProp.Value );
777 }
778 }
779 else
780 xPropertySet->setPropertyValue( rProp.Name, rProp.Value );
781 }
782
784 {
785 if ( m_nStorageType != embed::StorageFormats::PACKAGE )
786 throw uno::RuntimeException();
787
788 // set to be encrypted but do not use encryption key
789 xPropertySet->setPropertyValue( STORAGE_ENCRYPTION_KEYS_PROPERTY,
790 uno::Any( uno::Sequence< beans::NamedValue >() ) );
791 xPropertySet->setPropertyValue( "Encrypted",
792 uno::Any( true ) );
793 }
795 {
796 if ( m_nStorageType != embed::StorageFormats::PACKAGE )
797 throw uno::RuntimeException();
798
799 xPropertySet->setPropertyValue( STORAGE_ENCRYPTION_KEYS_PROPERTY,
801 }
802
803 // the stream should be free soon, after package is stored
804 m_xPackageStream = xNewPackageStream;
805 m_bHasDataToFlush = false;
806 m_bFlushed = true; // will allow to use transaction on stream level if will need it
807}
808
810{
811 // can be called only from parent storage
812 // means complete reload of the stream
813
814 ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
815
816 if ( !m_bHasDataToFlush )
817 return; // nothing to do
818
819 OSL_ENSURE( m_oTempFile.has_value() || m_xCacheStream.is(), "The temporary must exist!" );
820
821 if ( m_xCacheStream.is() )
822 {
823 m_xCacheStream.clear();
824 m_xCacheSeek.clear();
825 }
826
827 m_oTempFile.reset();
828
829 m_aProps.realloc( 0 );
830
831 m_bHasDataToFlush = false;
832
836
837 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
838 return;
839
840 // currently the relations storage is changed only on commit
841 m_xNewRelInfoStream.clear();
842 m_aNewRelInfo = uno::Sequence< uno::Sequence< beans::StringPair > >();
843 if ( m_xOrigRelInfoStream.is() )
844 {
845 // the original stream is still here, that means that it was not parsed
846 m_aOrigRelInfo = uno::Sequence< uno::Sequence< beans::StringPair > >();
848 }
849 else
850 {
851 // the original stream was already parsed
854 else
856 }
857}
858
859uno::Sequence< beans::PropertyValue > const & OWriteStream_Impl::GetStreamProperties()
860{
861 if ( !m_aProps.hasElements() )
863
864 return m_aProps;
865}
866
867uno::Sequence< beans::PropertyValue > OWriteStream_Impl::InsertOwnProps(
868 const uno::Sequence< beans::PropertyValue >& aProps,
869 bool bUseCommonEncryption )
870{
871 uno::Sequence< beans::PropertyValue > aResult( aProps );
872 beans::PropertyValue aPropVal;
873
874 if ( m_nStorageType == embed::StorageFormats::PACKAGE )
875 {
876 aPropVal.Name = "UseCommonStoragePasswordEncryption";
877 aPropVal.Value <<= bUseCommonEncryption;
878 }
879 else if ( m_nStorageType == embed::StorageFormats::OFOPXML )
880 {
882
883 aPropVal.Name = "RelationsInfo";
885 aPropVal.Value <<= m_aOrigRelInfo;
887 aPropVal.Value <<= m_aNewRelInfo;
888 else // m_nRelInfoStatus == RELINFO_CHANGED_BROKEN || m_nRelInfoStatus == RELINFO_BROKEN
889 throw io::IOException( "Wrong relinfo stream!" );
890 }
891 if (!aPropVal.Name.isEmpty())
892 {
893 sal_Int32 i = 0;
894 for (auto p = aResult.getConstArray(); i < aResult.getLength(); ++i)
895 if (p[i].Name == aPropVal.Name)
896 break;
897 if (i == aResult.getLength())
898 aResult.realloc(i + 1);
899 aResult.getArray()[i] = aPropVal;
900 }
901
902 return aResult;
903}
904
906{
907 ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
909}
910
912{
913 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
914 return;
915
917 {
918 try
919 {
920 // Init from original stream
921 if ( m_xOrigRelInfoStream.is() )
922 m_aOrigRelInfo = ::comphelper::OFOPXMLHelper::ReadRelationsInfoSequence(
924 u"_rels/*.rels",
925 m_xContext );
926
927 // in case of success the stream must be thrown away, that means that the OrigRelInfo is initialized
928 // the reason for this is that the original stream might not be seekable ( at the same time the new
929 // provided stream must be seekable ), so it must be read only once
930 m_xOrigRelInfoStream.clear();
932 }
933 catch( const uno::Exception& )
934 {
935 TOOLS_INFO_EXCEPTION("package.xstor", "Quiet exception");
936
939 }
940 }
942 {
943 // Init from the new stream
944 try
945 {
946 if ( m_xNewRelInfoStream.is() )
947 m_aNewRelInfo = ::comphelper::OFOPXMLHelper::ReadRelationsInfoSequence(
949 u"_rels/*.rels",
950 m_xContext );
951
953 }
954 catch( const uno::Exception& )
955 {
957 }
958 }
959}
960
961uno::Sequence< beans::PropertyValue > OWriteStream_Impl::ReadPackageStreamProperties()
962{
963 sal_Int32 nPropNum = 0;
964 if ( m_nStorageType == embed::StorageFormats::ZIP )
965 nPropNum = 2;
966 else if ( m_nStorageType == embed::StorageFormats::OFOPXML )
967 nPropNum = 3;
968 else if ( m_nStorageType == embed::StorageFormats::PACKAGE )
969 nPropNum = 4;
970 assert(nPropNum >= 2);
971 uno::Sequence< beans::PropertyValue > aResult( nPropNum );
972 auto aResultRange = asNonConstRange(aResult);
973
974 // The "Compressed" property must be set after "MediaType" property,
975 // since the setting of the last one can change the value of the first one
976 static constexpr OUStringLiteral sMediaType = u"MediaType";
977 static constexpr OUStringLiteral sCompressed = u"Compressed";
978 static constexpr OUStringLiteral sSize = u"Size";
979 static constexpr OUStringLiteral sEncrypted = u"Encrypted";
980 if ( m_nStorageType == embed::StorageFormats::OFOPXML || m_nStorageType == embed::StorageFormats::PACKAGE )
981 {
982 aResultRange[0].Name = sMediaType;
983 aResultRange[1].Name = sCompressed;
984 aResultRange[2].Name = sSize;
985
986 if ( m_nStorageType == embed::StorageFormats::PACKAGE )
987 aResultRange[3].Name = sEncrypted;
988 }
989 else
990 {
991 aResultRange[0].Name = sCompressed;
992 aResultRange[1].Name = sSize;
993 }
994
995 // TODO: may be also raw stream should be marked
996
997 uno::Reference< beans::XPropertySet > xPropSet( m_xPackageStream, uno::UNO_QUERY_THROW );
998 for ( auto& rProp : aResultRange )
999 {
1000 try {
1001 rProp.Value = xPropSet->getPropertyValue( rProp.Name );
1002 }
1003 catch( const uno::Exception& )
1004 {
1005 TOOLS_WARN_EXCEPTION( "package.xstor", "A property can't be retrieved" );
1006 }
1007 }
1008
1009 return aResult;
1010}
1011
1012void OWriteStream_Impl::CopyInternallyTo_Impl( const uno::Reference< io::XStream >& xDestStream,
1013 const ::comphelper::SequenceAsHashMap& aEncryptionData )
1014{
1015 ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
1016
1017 SAL_WARN_IF( m_bUseCommonEncryption, "package.xstor", "The stream can not be encrypted!" );
1018
1019 if ( m_nStorageType != embed::StorageFormats::PACKAGE )
1020 throw packages::NoEncryptionException();
1021
1022 if ( m_pAntiImpl )
1023 {
1025 }
1026 else
1027 {
1028 uno::Reference< io::XStream > xOwnStream = GetStream( embed::ElementModes::READ, aEncryptionData, false );
1029 if ( !xOwnStream.is() )
1030 throw io::IOException(); // TODO
1031
1033 }
1034
1035 uno::Reference< embed::XEncryptionProtectedSource2 > xEncr( xDestStream, uno::UNO_QUERY );
1036 if ( xEncr.is() )
1037 xEncr->setEncryptionData( aEncryptionData.getAsConstNamedValueList() );
1038}
1039
1040uno::Sequence< uno::Sequence< beans::StringPair > > OWriteStream_Impl::GetAllRelationshipsIfAny()
1041{
1042 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
1043 return uno::Sequence< uno::Sequence< beans::StringPair > >();
1044
1046
1048 return m_aOrigRelInfo;
1050 return m_aNewRelInfo;
1051 else // m_nRelInfoStatus == RELINFO_CHANGED_BROKEN || m_nRelInfoStatus == RELINFO_BROKEN
1052 throw io::IOException( "Wrong relinfo stream!" );
1053}
1054
1055void OWriteStream_Impl::CopyInternallyTo_Impl( const uno::Reference< io::XStream >& xDestStream )
1056{
1057 ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
1058
1059 if ( m_pAntiImpl )
1060 {
1062 }
1063 else
1064 {
1065 uno::Reference< io::XStream > xOwnStream = GetStream( embed::ElementModes::READ, false );
1066 if ( !xOwnStream.is() )
1067 throw io::IOException(); // TODO
1068
1070 }
1071}
1072
1073uno::Reference< io::XStream > OWriteStream_Impl::GetStream( sal_Int32 nStreamMode, const ::comphelper::SequenceAsHashMap& aEncryptionData, bool bHierarchyAccess )
1074{
1075 ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
1076
1077 SAL_WARN_IF( !m_xPackageStream.is(), "package.xstor", "No package stream is set!" );
1078
1079 if ( m_pAntiImpl )
1080 throw io::IOException(); // TODO:
1081
1082 if ( !IsEncrypted() )
1083 throw packages::NoEncryptionException();
1084
1085 uno::Reference< io::XStream > xResultStream;
1086
1087 uno::Reference< beans::XPropertySet > xPropertySet( m_xPackageStream, uno::UNO_QUERY_THROW );
1088
1090 {
1092 throw packages::WrongPasswordException();
1093
1094 // the correct key must be set already
1095 xResultStream = GetStream_Impl( nStreamMode, bHierarchyAccess );
1096 }
1097 else
1098 {
1099 SetEncryptionKeyProperty_Impl( xPropertySet, aEncryptionData.getAsConstNamedValueList() );
1100
1101 try {
1102 xResultStream = GetStream_Impl( nStreamMode, bHierarchyAccess );
1103
1104 m_bUseCommonEncryption = false; // very important to set it to false
1106 m_aEncryptionData = aEncryptionData;
1107 }
1108 catch( const packages::WrongPasswordException& )
1109 {
1110 TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
1111 SetEncryptionKeyProperty_Impl( xPropertySet, uno::Sequence< beans::NamedValue >() );
1112 throw;
1113 }
1114 catch ( const uno::Exception& ex )
1115 {
1116 TOOLS_WARN_EXCEPTION( "package.xstor", "Can't write encryption related properties");
1117 SetEncryptionKeyProperty_Impl( xPropertySet, uno::Sequence< beans::NamedValue >() );
1118 throw io::IOException(ex.Message); // TODO:
1119 }
1120 }
1121
1122 SAL_WARN_IF( !xResultStream.is(), "package.xstor", "In case stream can not be retrieved an exception must be thrown!" );
1123
1124 return xResultStream;
1125}
1126
1127uno::Reference< io::XStream > OWriteStream_Impl::GetStream( sal_Int32 nStreamMode, bool bHierarchyAccess )
1128{
1129 ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
1130
1131 SAL_WARN_IF( !m_xPackageStream.is(), "package.xstor", "No package stream is set!" );
1132
1133 if ( m_pAntiImpl )
1134 throw io::IOException(); // TODO:
1135
1136 uno::Reference< io::XStream > xResultStream;
1137
1138 if ( IsEncrypted() )
1139 {
1140 ::comphelper::SequenceAsHashMap aGlobalEncryptionData;
1141 try
1142 {
1143 aGlobalEncryptionData = GetCommonRootEncryptionData();
1144 }
1145 catch( const packages::NoEncryptionException& )
1146 {
1147 TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
1148 throw packages::WrongPasswordException();
1149 }
1150
1151 xResultStream = GetStream( nStreamMode, aGlobalEncryptionData, bHierarchyAccess );
1152 }
1153 else
1154 xResultStream = GetStream_Impl( nStreamMode, bHierarchyAccess );
1155
1156 return xResultStream;
1157}
1158
1159uno::Reference< io::XStream > OWriteStream_Impl::GetStream_Impl( sal_Int32 nStreamMode, bool bHierarchyAccess )
1160{
1161 // private method, no mutex is used
1163
1164 // TODO/LATER: this info might be read later, on demand in future
1166
1167 if ( ( nStreamMode & embed::ElementModes::READWRITE ) == embed::ElementModes::READ )
1168 {
1169 uno::Reference< io::XInputStream > xInStream;
1170 if ( m_xCacheStream.is() || m_oTempFile.has_value() )
1171 xInStream = GetTempFileAsInputStream(); //TODO:
1172 else
1173 xInStream = m_xPackageStream->getDataStream();
1174
1175 // The stream does not exist in the storage
1176 if ( !xInStream.is() )
1177 throw io::IOException();
1178
1180 m_aInputStreamsVector.push_back( pStream.get() );
1181 return pStream;
1182 }
1183 else if ( ( nStreamMode & embed::ElementModes::READWRITE ) == embed::ElementModes::SEEKABLEREAD )
1184 {
1185 if ( !m_xCacheStream.is() && !m_oTempFile.has_value() && !( m_xPackageStream->getDataStream().is() ) )
1186 {
1187 // The stream does not exist in the storage
1188 throw io::IOException();
1189 }
1190
1191 uno::Reference< io::XInputStream > xInStream = GetTempFileAsInputStream(); //TODO:
1192
1193 if ( !xInStream.is() )
1194 throw io::IOException();
1195
1197 m_aInputStreamsVector.push_back( pStream.get() );
1198 return pStream;
1199 }
1200 else if ( ( nStreamMode & embed::ElementModes::WRITE ) == embed::ElementModes::WRITE )
1201 {
1202 if ( !m_aInputStreamsVector.empty() )
1203 throw io::IOException(); // TODO:
1204
1205 uno::Reference< io::XStream > xStream;
1206 if ( ( nStreamMode & embed::ElementModes::TRUNCATE ) == embed::ElementModes::TRUNCATE )
1207 {
1208 m_oTempFile.reset();
1209 if ( m_xCacheStream.is() )
1211
1212 m_bHasDataToFlush = true;
1213
1214 // this call is triggered by the parent and it will recognize the change of the state
1215 if ( m_pParent )
1216 m_pParent->m_bIsModified = true;
1217
1218 xStream = CreateMemoryStream( m_xContext );
1219 m_xCacheSeek.set( xStream, uno::UNO_QUERY_THROW );
1221 }
1223 {
1224 if ( !m_oTempFile.has_value() && !m_xCacheStream.is() && !( m_xPackageStream->getDataStream().is() ) )
1225 {
1226 // The stream does not exist in the storage
1227 m_bHasDataToFlush = true;
1228
1229 // this call is triggered by the parent and it will recognize the change of the state
1230 if ( m_pParent )
1231 m_pParent->m_bIsModified = true;
1233 }
1234
1235 // if the stream exists the temporary file is created on demand
1236 // xStream = GetTempFileAsStream();
1237 }
1238
1240 assert(m_xMutex.is() && "No mutex!");
1241 if ( !xStream.is() )
1242 tmp = new OWriteStream( *this, bHierarchyAccess );
1243 else
1244 tmp = new OWriteStream( *this, xStream, bHierarchyAccess );
1245
1246 m_pAntiImpl = tmp.get();
1247 return tmp;
1248 }
1249
1250 throw lang::IllegalArgumentException(); // TODO
1251}
1252
1253uno::Reference< io::XInputStream > OWriteStream_Impl::GetPlainRawInStream()
1254{
1255 ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
1256
1257 SAL_WARN_IF( !m_xPackageStream.is(), "package.xstor", "No package stream is set!" );
1258
1259 // this method is used only internally, this stream object should not go outside of this implementation
1260 // if ( m_pAntiImpl )
1261 // throw io::IOException(); // TODO:
1262
1263 return m_xPackageStream->getPlainRawStream();
1264}
1265
1266uno::Reference< io::XInputStream > OWriteStream_Impl::GetRawInStream()
1267{
1268 ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
1269
1270 SAL_WARN_IF( !m_xPackageStream.is(), "package.xstor", "No package stream is set!" );
1271
1272 if ( m_pAntiImpl )
1273 throw io::IOException(); // TODO:
1274
1275 SAL_WARN_IF( !IsEncrypted(), "package.xstor", "Impossible to get raw representation for nonencrypted stream!" );
1276 if ( !IsEncrypted() )
1277 throw packages::NoEncryptionException();
1278
1279 return m_xPackageStream->getRawStream();
1280}
1281
1283{
1284 ::osl::MutexGuard aGuard( m_xMutex->GetMutex() ) ;
1285
1286 if ( m_nStorageType != embed::StorageFormats::PACKAGE || !m_pParent )
1287 throw packages::NoEncryptionException();
1288
1290}
1291
1293{
1294 ::osl::MutexGuard aGuard( m_xMutex->GetMutex() );
1295 m_aInputStreamsVector.erase(std::remove(m_aInputStreamsVector.begin(), m_aInputStreamsVector.end(), pStream ));
1296}
1297
1298void OWriteStream_Impl::CreateReadonlyCopyBasedOnData( const uno::Reference< io::XInputStream >& xDataToCopy, const uno::Sequence< beans::PropertyValue >& aProps, uno::Reference< io::XStream >& xTargetStream )
1299{
1300 uno::Reference < io::XStream > xTempFile;
1301 if ( !xTargetStream.is() )
1302 xTempFile = new utl::TempFileFastService;
1303 else
1304 xTempFile = xTargetStream;
1305
1306 uno::Reference < io::XSeekable > xTempSeek( xTempFile, uno::UNO_QUERY_THROW );
1307
1308 uno::Reference < io::XOutputStream > xTempOut(xTempFile->getOutputStream(), uno::UNO_SET_THROW);
1309
1310 if ( xDataToCopy.is() )
1311 ::comphelper::OStorageHelper::CopyInputToOutput( xDataToCopy, xTempOut );
1312
1313 xTempOut->closeOutput();
1314 xTempSeek->seek( 0 );
1315
1316 uno::Reference< io::XInputStream > xInStream = xTempFile->getInputStream();
1317 if ( !xInStream.is() )
1318 throw io::IOException();
1319
1320 // TODO: remember last state of m_bUseCommonEncryption
1321 if ( !xTargetStream.is() )
1322 xTargetStream.set(
1324}
1325
1326void OWriteStream_Impl::GetCopyOfLastCommit( uno::Reference< io::XStream >& xTargetStream )
1327{
1328 ::osl::MutexGuard aGuard( m_xMutex->GetMutex() );
1329
1330 SAL_WARN_IF( !m_xPackageStream.is(), "package.xstor", "The source stream for copying is incomplete!" );
1331 if ( !m_xPackageStream.is() )
1332 throw uno::RuntimeException();
1333
1334 uno::Reference< io::XInputStream > xDataToCopy;
1335 if ( IsEncrypted() )
1336 {
1337 // an encrypted stream must contain input stream
1338 ::comphelper::SequenceAsHashMap aGlobalEncryptionData;
1339 try
1340 {
1341 aGlobalEncryptionData = GetCommonRootEncryptionData();
1342 }
1343 catch( const packages::NoEncryptionException& )
1344 {
1345 TOOLS_INFO_EXCEPTION("package.xstor", "No Element");
1346 throw packages::WrongPasswordException();
1347 }
1348
1349 GetCopyOfLastCommit( xTargetStream, aGlobalEncryptionData );
1350 }
1351 else
1352 {
1353 xDataToCopy = m_xPackageStream->getDataStream();
1354
1355 // in case of new inserted package stream it is possible that input stream still was not set
1357
1358 CreateReadonlyCopyBasedOnData( xDataToCopy, m_aProps, xTargetStream );
1359 }
1360}
1361
1362void OWriteStream_Impl::GetCopyOfLastCommit( uno::Reference< io::XStream >& xTargetStream, const ::comphelper::SequenceAsHashMap& aEncryptionData )
1363{
1364 ::osl::MutexGuard aGuard( m_xMutex->GetMutex() );
1365
1366 SAL_WARN_IF( !m_xPackageStream.is(), "package.xstor", "The source stream for copying is incomplete!" );
1367 if ( !m_xPackageStream.is() )
1368 throw uno::RuntimeException();
1369
1370 if ( !IsEncrypted() )
1371 throw packages::NoEncryptionException();
1372
1373 uno::Reference< io::XInputStream > xDataToCopy;
1374
1376 {
1377 // TODO: introduce last committed cashed password information and use it here
1378 // that means "use common pass" also should be remembered on flash
1379 uno::Sequence< beans::NamedValue > aKey = aEncryptionData.getAsConstNamedValueList();
1380
1381 uno::Reference< beans::XPropertySet > xProps( m_xPackageStream, uno::UNO_QUERY_THROW );
1382
1383 bool bEncr = false;
1384 xProps->getPropertyValue( "Encrypted" ) >>= bEncr;
1385 if ( !bEncr )
1386 throw packages::NoEncryptionException();
1387
1388 uno::Sequence< beans::NamedValue > aPackKey;
1389 xProps->getPropertyValue( STORAGE_ENCRYPTION_KEYS_PROPERTY ) >>= aPackKey;
1390 if ( !SequencesEqual( aKey, aPackKey ) )
1391 throw packages::WrongPasswordException();
1392
1393 // the correct key must be set already
1394 xDataToCopy = m_xPackageStream->getDataStream();
1395 }
1396 else
1397 {
1398 uno::Reference< beans::XPropertySet > xPropertySet( m_xPackageStream, uno::UNO_QUERY );
1399 SetEncryptionKeyProperty_Impl( xPropertySet, aEncryptionData.getAsConstNamedValueList() );
1400
1401 try {
1402 xDataToCopy = m_xPackageStream->getDataStream();
1403
1404 if ( !xDataToCopy.is() )
1405 {
1406 SAL_WARN( "package.xstor", "Encrypted ZipStream must already have input stream inside!" );
1407 SetEncryptionKeyProperty_Impl( xPropertySet, uno::Sequence< beans::NamedValue >() );
1408 }
1409 }
1410 catch( const uno::Exception& )
1411 {
1412 TOOLS_WARN_EXCEPTION( "package.xstor", "Can't open encrypted stream");
1413 SetEncryptionKeyProperty_Impl( xPropertySet, uno::Sequence< beans::NamedValue >() );
1414 throw;
1415 }
1416
1417 SetEncryptionKeyProperty_Impl( xPropertySet, uno::Sequence< beans::NamedValue >() );
1418 }
1419
1420 // in case of new inserted package stream it is possible that input stream still was not set
1422
1423 CreateReadonlyCopyBasedOnData( xDataToCopy, m_aProps, xTargetStream );
1424}
1425
1426void OWriteStream_Impl::CommitStreamRelInfo( const uno::Reference< embed::XStorage >& xRelStorage, std::u16string_view aOrigStreamName, std::u16string_view aNewStreamName )
1427{
1428 // at this point of time the old stream must be already cleaned
1429 OSL_ENSURE( m_nStorageType == embed::StorageFormats::OFOPXML, "The method should be used only with OFOPXML format!" );
1430
1431 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
1432 return;
1433
1434 OSL_ENSURE( !aOrigStreamName.empty() && !aNewStreamName.empty() && xRelStorage.is(),
1435 "Wrong relation persistence information is provided!" );
1436
1437 if ( !xRelStorage.is() || aOrigStreamName.empty() || aNewStreamName.empty() )
1438 throw uno::RuntimeException();
1439
1441 throw io::IOException(); // TODO:
1442
1443 OUString aOrigRelStreamName = OUString::Concat(aOrigStreamName) + ".rels";
1444 OUString aNewRelStreamName = OUString::Concat(aNewStreamName) + ".rels";
1445
1446 bool bRenamed = aOrigRelStreamName != aNewRelStreamName;
1450 {
1451 if ( bRenamed && xRelStorage->hasByName( aOrigRelStreamName ) )
1452 xRelStorage->removeElement( aOrigRelStreamName );
1453
1455 {
1456 if ( m_aNewRelInfo.hasElements() )
1457 {
1458 uno::Reference< io::XStream > xRelsStream =
1459 xRelStorage->openStreamElement( aNewRelStreamName,
1460 embed::ElementModes::TRUNCATE | embed::ElementModes::READWRITE );
1461
1462 uno::Reference< io::XOutputStream > xOutStream = xRelsStream->getOutputStream();
1463 if ( !xOutStream.is() )
1464 throw uno::RuntimeException();
1465
1466 ::comphelper::OFOPXMLHelper::WriteRelationsInfoSequence( xOutStream, m_aNewRelInfo, m_xContext );
1467
1468 // set the mediatype
1469 uno::Reference< beans::XPropertySet > xPropSet( xRelsStream, uno::UNO_QUERY_THROW );
1470 xPropSet->setPropertyValue(
1471 "MediaType",
1472 uno::Any( OUString("application/vnd.openxmlformats-package.relationships+xml" ) ) );
1473
1475 }
1476 }
1479 {
1480 uno::Reference< io::XStream > xRelsStream =
1481 xRelStorage->openStreamElement( aNewRelStreamName,
1482 embed::ElementModes::TRUNCATE | embed::ElementModes::READWRITE );
1483
1484 uno::Reference< io::XOutputStream > xOutputStream = xRelsStream->getOutputStream();
1485 if ( !xOutputStream.is() )
1486 throw uno::RuntimeException();
1487
1488 uno::Reference< io::XSeekable > xSeek( m_xNewRelInfoStream, uno::UNO_QUERY_THROW );
1489 xSeek->seek( 0 );
1491 xSeek->seek( 0 );
1492
1493 // set the mediatype
1494 uno::Reference< beans::XPropertySet > xPropSet( xRelsStream, uno::UNO_QUERY_THROW );
1495 xPropSet->setPropertyValue("MediaType",
1496 uno::Any( OUString("application/vnd.openxmlformats-package.relationships+xml" ) ) );
1497
1500 else
1501 {
1502 // the information is already parsed and the stream is stored, no need in temporary stream any more
1503 m_xNewRelInfoStream.clear();
1505 }
1506 }
1507
1508 // the original stream makes no sense after this step
1511 m_bOrigRelInfoBroken = false;
1512 m_aNewRelInfo = uno::Sequence< uno::Sequence< beans::StringPair > >();
1513 m_xNewRelInfoStream.clear();
1514 }
1515 else
1516 {
1517 // the stream is not changed but it might be renamed
1518 if ( bRenamed && xRelStorage->hasByName( aOrigRelStreamName ) )
1519 xRelStorage->renameElement( aOrigRelStreamName, aNewRelStreamName );
1520 }
1521}
1522
1523// OWriteStream implementation
1524
1526: m_pImpl( &rImpl )
1527, m_xSharedMutex( rImpl.m_xMutex )
1528, m_aListenersContainer( rImpl.m_xMutex->GetMutex() )
1529, m_nStorageType( m_pImpl->m_nStorageType )
1530, m_bInStreamDisconnected( false )
1531, m_bInitOnDemand( true )
1532, m_nInitPosition( 0 )
1533, m_bTransacted( bTransacted )
1534{
1535}
1536
1537OWriteStream::OWriteStream( OWriteStream_Impl& rImpl, uno::Reference< io::XStream > const & xStream, bool bTransacted )
1538: m_pImpl( &rImpl )
1539, m_xSharedMutex( rImpl.m_xMutex )
1540, m_aListenersContainer( rImpl.m_xMutex->GetMutex() )
1541, m_nStorageType( m_pImpl->m_nStorageType )
1542, m_bInStreamDisconnected( false )
1543, m_bInitOnDemand( false )
1544, m_nInitPosition( 0 )
1545, m_bTransacted( bTransacted )
1546{
1547 if ( xStream.is() )
1548 {
1549 m_xInStream = xStream->getInputStream();
1550 m_xOutStream = xStream->getOutputStream();
1551 m_xSeekable.set( xStream, uno::UNO_QUERY );
1552 OSL_ENSURE( m_xInStream.is() && m_xOutStream.is() && m_xSeekable.is(), "Stream implementation is incomplete!" );
1553 }
1554}
1555
1557{
1558 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1559 if ( m_pImpl )
1560 {
1561 osl_atomic_increment(&m_refCount);
1562 try {
1563 dispose();
1564 }
1565 catch( const uno::RuntimeException& )
1566 {
1567 TOOLS_INFO_EXCEPTION("package.xstor", "Quiet exception");
1568 }
1569 }
1570}
1571
1573{
1574 if ( !m_pImpl )
1575 return; // do nothing
1576
1577 if ( m_xSeekable.is() )
1578 m_nInitPosition = m_xSeekable->getPosition();
1579
1580 m_xInStream.clear();
1581 m_xOutStream.clear();
1582 m_xSeekable.clear();
1583 m_bInitOnDemand = true;
1584}
1585
1587{
1588 if ( !m_pImpl )
1589 {
1590 SAL_INFO("package.xstor", "Disposed!");
1591 throw lang::DisposedException();
1592 }
1593
1594 if ( !m_bInitOnDemand )
1595 return;
1596
1597 SAL_INFO( "package.xstor", "package (mv76033) OWriteStream::CheckInitOnDemand, initializing" );
1598 uno::Reference< io::XStream > xStream = m_pImpl->GetTempFileAsStream();
1599 if ( xStream.is() )
1600 {
1601 m_xInStream.set( xStream->getInputStream(), uno::UNO_SET_THROW );
1602 m_xOutStream.set( xStream->getOutputStream(), uno::UNO_SET_THROW );
1603 m_xSeekable.set( xStream, uno::UNO_QUERY_THROW );
1605
1606 m_nInitPosition = 0;
1607 m_bInitOnDemand = false;
1608 }
1609}
1610
1611void OWriteStream::CopyToStreamInternally_Impl( const uno::Reference< io::XStream >& xDest )
1612{
1613 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1614
1616
1617 if ( !m_xInStream.is() )
1618 throw uno::RuntimeException();
1619
1620 if ( !m_xSeekable.is() )
1621 throw uno::RuntimeException();
1622
1623 uno::Reference< beans::XPropertySet > xDestProps( xDest, uno::UNO_QUERY_THROW );
1624
1625 uno::Reference< io::XOutputStream > xDestOutStream = xDest->getOutputStream();
1626 if ( !xDestOutStream.is() )
1627 throw io::IOException(); // TODO
1628
1629 sal_Int64 nCurPos = m_xSeekable->getPosition();
1630 m_xSeekable->seek( 0 );
1631
1632 uno::Exception eThrown;
1633 bool bThrown = false;
1634 try {
1636 }
1637 catch ( const uno::Exception& e )
1638 {
1639 eThrown = e;
1640 bThrown = true;
1641 }
1642
1643 // position-related section below is critical
1644 // if it fails the stream will become invalid
1645 try {
1646 m_xSeekable->seek( nCurPos );
1647 }
1648 catch ( const uno::Exception& )
1649 {
1650 // TODO: set the stream in invalid state or dispose
1651 TOOLS_WARN_EXCEPTION( "package.xstor", "The stream become invalid during copying" );
1652 throw uno::RuntimeException();
1653 }
1654
1655 if ( bThrown )
1656 throw eThrown;
1657
1658 // now the properties can be copied
1659 // the order of the properties setting is not important for StorageStream API
1660 OUString aPropName ("Compressed");
1661 xDestProps->setPropertyValue( aPropName, getPropertyValue( aPropName ) );
1662 if ( m_nStorageType == embed::StorageFormats::PACKAGE || m_nStorageType == embed::StorageFormats::OFOPXML )
1663 {
1664 aPropName = "MediaType";
1665 xDestProps->setPropertyValue( aPropName, getPropertyValue( aPropName ) );
1666
1667 if ( m_nStorageType == embed::StorageFormats::PACKAGE )
1668 {
1669 aPropName = "UseCommonStoragePasswordEncryption";
1670 xDestProps->setPropertyValue( aPropName, getPropertyValue( aPropName ) );
1671 }
1672 }
1673}
1674
1675void OWriteStream::ModifyParentUnlockMutex_Impl(osl::ClearableMutexGuard& aGuard)
1676{
1677 if ( m_pImpl->m_pParent )
1678 {
1680 {
1681 uno::Reference< util::XModifiable > xParentModif( static_cast<util::XModifiable*>(m_pImpl->m_pParent->m_pAntiImpl) );
1682 aGuard.clear();
1683 xParentModif->setModified( true );
1684 }
1685 else
1687 }
1688}
1689
1691{
1692 // common interfaces
1693 uno::Any aReturn = ::cppu::queryInterface
1694 ( rType
1695 , static_cast<lang::XTypeProvider*> ( this )
1696 , static_cast<io::XInputStream*> ( this )
1697 , static_cast<io::XOutputStream*> ( this )
1698 , static_cast<io::XStream*> ( this )
1699 , static_cast<embed::XExtendedStorageStream*> ( this )
1700 , static_cast<io::XSeekable*> ( this )
1701 , static_cast<io::XTruncate*> ( this )
1702 , static_cast<lang::XComponent*> ( this )
1703 , static_cast<beans::XPropertySet*> ( this ) );
1704
1705 if ( aReturn.hasValue() )
1706 return aReturn ;
1707
1708 if ( m_nStorageType == embed::StorageFormats::PACKAGE )
1709 {
1710 aReturn = ::cppu::queryInterface
1711 ( rType
1712 , static_cast<embed::XEncryptionProtectedSource2*> ( this )
1713 , static_cast<embed::XEncryptionProtectedSource*> ( this ) );
1714 }
1715 else if ( m_nStorageType == embed::StorageFormats::OFOPXML )
1716 {
1717 aReturn = ::cppu::queryInterface
1718 ( rType
1719 , static_cast<embed::XRelationshipAccess*> ( this ) );
1720 }
1721
1722 if ( aReturn.hasValue() )
1723 return aReturn ;
1724
1725 if ( m_bTransacted )
1726 {
1727 aReturn = ::cppu::queryInterface
1728 ( rType
1729 , static_cast<embed::XTransactedObject*> ( this )
1730 , static_cast<embed::XTransactionBroadcaster*> ( this ) );
1731
1732 if ( aReturn.hasValue() )
1733 return aReturn ;
1734 }
1735
1736 return OWeakObject::queryInterface( rType );
1737}
1738
1739void SAL_CALL OWriteStream::acquire() noexcept
1740{
1741 OWeakObject::acquire();
1742}
1743
1744void SAL_CALL OWriteStream::release() noexcept
1745{
1746 OWeakObject::release();
1747}
1748
1749uno::Sequence< uno::Type > SAL_CALL OWriteStream::getTypes()
1750{
1751 if (! m_oTypeCollection)
1752 {
1753 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1754
1755 if (! m_oTypeCollection)
1756 {
1757 if ( m_bTransacted )
1758 {
1759 if ( m_nStorageType == embed::StorageFormats::PACKAGE )
1760 {
1761 ::cppu::OTypeCollection aTmpCollection
1774
1775 m_oTypeCollection.emplace(
1777 , aTmpCollection.getTypes());
1778 }
1779 else if ( m_nStorageType == embed::StorageFormats::OFOPXML )
1780 {
1781 m_oTypeCollection.emplace(
1794 }
1795 else // if ( m_pData->m_nStorageType == embed::StorageFormats::ZIP )
1796 {
1797 m_oTypeCollection.emplace(
1809 }
1810 }
1811 else
1812 {
1813 if ( m_nStorageType == embed::StorageFormats::PACKAGE )
1814 {
1815 m_oTypeCollection.emplace(
1826 }
1827 else if ( m_nStorageType == embed::StorageFormats::OFOPXML )
1828 {
1829 m_oTypeCollection.emplace(
1839 }
1840 else // if ( m_pData->m_nStorageType == embed::StorageFormats::ZIP )
1841 {
1842 m_oTypeCollection.emplace(
1851 }
1852 }
1853 }
1854 }
1855
1856 return m_oTypeCollection->getTypes() ;
1857}
1858
1859uno::Sequence< sal_Int8 > SAL_CALL OWriteStream::getImplementationId()
1860{
1861 static const comphelper::UnoIdInit lcl_ImplId;
1862 return lcl_ImplId.getSeq();
1863}
1864
1865sal_Int32 SAL_CALL OWriteStream::readBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
1866{
1867 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1868
1870
1871 if ( !m_pImpl )
1872 {
1873 SAL_INFO("package.xstor", "Disposed!");
1874 throw lang::DisposedException();
1875 }
1876
1877 if ( !m_xInStream.is() )
1878 throw io::NotConnectedException();
1879
1880 return m_xInStream->readBytes( aData, nBytesToRead );
1881}
1882
1883sal_Int32 SAL_CALL OWriteStream::readSomeBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
1884{
1885 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1886
1888
1889 if ( !m_pImpl )
1890 {
1891 SAL_INFO("package.xstor", "Disposed!");
1892 throw lang::DisposedException();
1893 }
1894
1895 if ( !m_xInStream.is() )
1896 throw io::NotConnectedException();
1897
1898 return m_xInStream->readSomeBytes( aData, nMaxBytesToRead );
1899}
1900
1901void SAL_CALL OWriteStream::skipBytes( sal_Int32 nBytesToSkip )
1902{
1903 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1904
1906
1907 if ( !m_pImpl )
1908 {
1909 SAL_INFO("package.xstor", "Disposed!");
1910 throw lang::DisposedException();
1911 }
1912
1913 if ( !m_xInStream.is() )
1914 throw io::NotConnectedException();
1915
1916 m_xInStream->skipBytes( nBytesToSkip );
1917}
1918
1919sal_Int32 SAL_CALL OWriteStream::available( )
1920{
1921 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1922
1924
1925 if ( !m_pImpl )
1926 {
1927 SAL_INFO("package.xstor", "Disposed!");
1928 throw lang::DisposedException();
1929 }
1930
1931 if ( !m_xInStream.is() )
1932 throw io::NotConnectedException();
1933
1934 return m_xInStream->available();
1935
1936}
1937
1939{
1940 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1941
1942 if ( !m_pImpl )
1943 {
1944 SAL_INFO("package.xstor", "Disposed!");
1945 throw lang::DisposedException();
1946 }
1947
1949 throw io::NotConnectedException();
1950
1951 // the input part of the stream stays open for internal purposes (to allow reading during copying)
1952 // since it can not be reopened until output part is closed, it will be closed with output part.
1954 // m_xInStream->closeInput();
1955 // m_xInStream.clear();
1956
1957 if ( !m_xOutStream.is() )
1958 dispose();
1959}
1960
1961uno::Reference< io::XInputStream > SAL_CALL OWriteStream::getInputStream()
1962{
1963 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1964
1965 if ( !m_pImpl )
1966 {
1967 SAL_INFO("package.xstor", "Disposed!");
1968 throw lang::DisposedException();
1969 }
1970
1972 return uno::Reference< io::XInputStream >();
1973
1974 return this;
1975}
1976
1977uno::Reference< io::XOutputStream > SAL_CALL OWriteStream::getOutputStream()
1978{
1979 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
1980
1981 try
1982 {
1984 }
1985 catch( const io::IOException& r )
1986 {
1987 throw lang::WrappedTargetRuntimeException("OWriteStream::getOutputStream: Could not create backing temp file",
1988 getXWeak(), css::uno::Any ( r ) );
1989 }
1990
1991 if ( !m_pImpl )
1992 {
1993 SAL_INFO("package.xstor", "Disposed!");
1994 throw lang::DisposedException();
1995 }
1996
1997 if ( !m_xOutStream.is() )
1998 return uno::Reference< io::XOutputStream >();
1999
2000 return this;
2001}
2002
2003void SAL_CALL OWriteStream::writeBytes( const uno::Sequence< sal_Int8 >& aData )
2004{
2005 osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
2006
2007 // the write method makes initialization itself, since it depends from the aData length
2008 // NO CheckInitOnDemand()!
2009
2010 if ( !m_pImpl )
2011 {
2012 SAL_INFO("package.xstor", "Disposed!");
2013 throw lang::DisposedException();
2014 }
2015
2016 if ( !m_bInitOnDemand )
2017 {
2018 if ( !m_xOutStream.is() || !m_xSeekable.is())
2019 throw io::NotConnectedException();
2020
2021 if ( m_pImpl->m_xCacheStream.is() )
2022 {
2023 // check whether the cache should be turned off
2024 sal_Int64 nPos = m_xSeekable->getPosition();
2025 if ( nPos + aData.getLength() > MAX_STORCACHE_SIZE )
2026 {
2027 // disconnect the cache and copy the data to the temporary file
2028 m_xSeekable->seek( 0 );
2029
2030 // it is enough to copy the cached stream, the cache should already contain everything
2032 if ( m_pImpl->m_oTempFile.has_value() )
2033 {
2034 DeInit();
2035 // the last position is known and it is differs from the current stream position
2037 }
2038 }
2039 }
2040 }
2041
2042 if ( m_bInitOnDemand )
2043 {
2044 SAL_INFO( "package.xstor", "package (mv76033) OWriteStream::CheckInitOnDemand, initializing" );
2045 uno::Reference< io::XStream > xStream = m_pImpl->GetTempFileAsStream();
2046 if ( xStream.is() )
2047 {
2048 m_xInStream.set( xStream->getInputStream(), uno::UNO_SET_THROW );
2049 m_xOutStream.set( xStream->getOutputStream(), uno::UNO_SET_THROW );
2050 m_xSeekable.set( xStream, uno::UNO_QUERY_THROW );
2052
2053 m_nInitPosition = 0;
2054 m_bInitOnDemand = false;
2055 }
2056 }
2057
2058 if ( !m_xOutStream.is() )
2059 throw io::NotConnectedException();
2060
2061 m_xOutStream->writeBytes( aData );
2062 m_pImpl->m_bHasDataToFlush = true;
2063
2065}
2066
2067void OWriteStream::writeBytes( const sal_Int8* pData, sal_Int32 nBytesToWrite )
2068{
2069 assert(nBytesToWrite >= 0);
2070
2071 osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
2072
2073 // the write method makes initialization itself, since it depends from the aData length
2074 // NO CheckInitOnDemand()!
2075
2076 if ( !m_pImpl )
2077 {
2078 SAL_INFO("package.xstor", "Disposed!");
2079 throw lang::DisposedException();
2080 }
2081
2082 if ( !m_bInitOnDemand )
2083 {
2084 if ( !m_xOutStream.is() || !m_xSeekable.is())
2085 throw io::NotConnectedException();
2086
2087 if ( m_pImpl->m_xCacheStream.is() )
2088 {
2089 // check whether the cache should be turned off
2090 sal_Int64 nPos = m_xSeekable->getPosition();
2091 if ( nPos + nBytesToWrite > MAX_STORCACHE_SIZE )
2092 {
2093 // disconnect the cache and copy the data to the temporary file
2094 m_xSeekable->seek( 0 );
2095
2096 // it is enough to copy the cached stream, the cache should already contain everything
2098 if ( m_pImpl->m_oTempFile.has_value() )
2099 {
2100 DeInit();
2101 // the last position is known and it is differs from the current stream position
2103 }
2104 }
2105 }
2106 }
2107
2108 if ( m_bInitOnDemand )
2109 {
2110 SAL_INFO( "package.xstor", "package (mv76033) OWriteStream::CheckInitOnDemand, initializing" );
2111 uno::Reference< io::XStream > xStream = m_pImpl->GetTempFileAsStream();
2112 if ( xStream.is() )
2113 {
2114 m_xInStream.set( xStream->getInputStream(), uno::UNO_SET_THROW );
2115 m_xOutStream.set( xStream->getOutputStream(), uno::UNO_SET_THROW );
2116 m_xSeekable.set( xStream, uno::UNO_QUERY_THROW );
2118
2119 m_nInitPosition = 0;
2120 m_bInitOnDemand = false;
2121 }
2122 }
2123
2124 if ( !m_xOutStream.is() )
2125 throw io::NotConnectedException();
2126
2127 if (auto pByteWriter = dynamic_cast< comphelper::ByteWriter* >( m_xOutStream.get() ))
2128 pByteWriter->writeBytes(pData, nBytesToWrite);
2129 else
2130 {
2131 uno::Sequence<sal_Int8> aData(pData, nBytesToWrite);
2132 m_xOutStream->writeBytes( aData );
2133 }
2134 m_pImpl->m_bHasDataToFlush = true;
2135
2137}
2138
2139void SAL_CALL OWriteStream::flush()
2140{
2141 // In case stream is flushed its current version becomes visible
2142 // to the parent storage. Usually parent storage flushes the stream
2143 // during own commit but a user can explicitly flush the stream
2144 // so the changes will be available through cloning functionality.
2145
2146 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2147
2148 if ( !m_pImpl )
2149 {
2150 SAL_INFO("package.xstor", "Disposed!");
2151 throw lang::DisposedException();
2152 }
2153
2154 if ( !m_bInitOnDemand )
2155 {
2156 if ( !m_xOutStream.is() )
2157 throw io::NotConnectedException();
2158
2159 m_xOutStream->flush();
2160 m_pImpl->Commit();
2161 }
2162}
2163
2165{
2166 // all the checks must be done in calling method
2167
2168 m_xOutStream->closeOutput();
2169 m_xOutStream.clear();
2170
2171 if ( m_bInitOnDemand )
2172 return;
2173
2174 // after the stream is disposed it can be committed
2175 // so transport correct size property
2176 if ( !m_xSeekable.is() )
2177 throw uno::RuntimeException();
2178
2179 for ( auto& rProp : asNonConstRange(m_pImpl->m_aProps) )
2180 {
2181 if ( rProp.Name == "Size" )
2182 rProp.Value <<= m_xSeekable->getLength();
2183 }
2184}
2185
2187{
2188 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2189
2191
2192 if ( !m_pImpl )
2193 {
2194 SAL_INFO("package.xstor", "Disposed!");
2195 throw lang::DisposedException();
2196 }
2197
2198 if ( !m_xOutStream.is() )
2199 throw io::NotConnectedException();
2200
2202
2203 if ( m_bInStreamDisconnected || !m_xInStream.is() )
2204 dispose();
2205}
2206
2207void SAL_CALL OWriteStream::seek( sal_Int64 location )
2208{
2209 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2210
2212
2213 if ( !m_pImpl )
2214 {
2215 SAL_INFO("package.xstor", "Disposed!");
2216 throw lang::DisposedException();
2217 }
2218
2219 if ( !m_xSeekable.is() )
2220 throw uno::RuntimeException();
2221
2222 m_xSeekable->seek( location );
2223}
2224
2225sal_Int64 SAL_CALL OWriteStream::getPosition()
2226{
2227 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2228
2230
2231 if ( !m_pImpl )
2232 {
2233 SAL_INFO("package.xstor", "Disposed!");
2234 throw lang::DisposedException();
2235 }
2236
2237 if ( !m_xSeekable.is() )
2238 throw uno::RuntimeException();
2239
2240 return m_xSeekable->getPosition();
2241}
2242
2243sal_Int64 SAL_CALL OWriteStream::getLength()
2244{
2245 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2246
2248
2249 if ( !m_pImpl )
2250 {
2251 SAL_INFO("package.xstor", "Disposed!");
2252 throw lang::DisposedException();
2253 }
2254
2255 if ( !m_xSeekable.is() )
2256 throw uno::RuntimeException();
2257
2258 return m_xSeekable->getLength();
2259}
2260
2262{
2263 osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
2264
2266
2267 if ( !m_pImpl )
2268 {
2269 SAL_INFO("package.xstor", "Disposed!");
2270 throw lang::DisposedException();
2271 }
2272
2273 if ( !m_xOutStream.is() )
2274 throw uno::RuntimeException();
2275
2276 uno::Reference< io::XTruncate > xTruncate( m_xOutStream, uno::UNO_QUERY_THROW );
2277 xTruncate->truncate();
2278
2279 m_pImpl->m_bHasDataToFlush = true;
2280
2282}
2283
2285{
2286 // should be an internal method since it can be called only from parent storage
2287 {
2288 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2289
2290 if ( !m_pImpl )
2291 {
2292 SAL_INFO("package.xstor", "Disposed!");
2293 throw lang::DisposedException();
2294 }
2295
2296 if ( m_xOutStream.is() )
2298
2299 if ( m_xInStream.is() )
2300 {
2301 m_xInStream->closeInput();
2302 m_xInStream.clear();
2303 }
2304
2305 m_xSeekable.clear();
2306
2307 m_pImpl->m_pAntiImpl = nullptr;
2308
2309 if ( !m_bInitOnDemand )
2310 {
2311 try
2312 {
2313 if ( !m_bTransacted )
2314 {
2315 m_pImpl->Commit();
2316 }
2317 else
2318 {
2319 // throw away all the changes
2320 m_pImpl->Revert();
2321 }
2322 }
2323 catch( const uno::Exception& )
2324 {
2325 uno::Any aCaught( ::cppu::getCaughtException() );
2326 SAL_INFO("package.xstor", "Rethrow: " << exceptionToString(aCaught));
2327 throw lang::WrappedTargetRuntimeException("Can not commit/revert the storage!",
2328 getXWeak(),
2329 aCaught );
2330 }
2331 }
2332
2333 m_pImpl = nullptr;
2334 }
2335
2336 // the listener might try to get rid of parent storage, and the storage would delete this object;
2337 // for now the listener is just notified at the end of the method to workaround the problem
2338 // in future a more elegant way should be found
2339
2340 lang::EventObject aSource( getXWeak() );
2342}
2343
2345 const uno::Reference< lang::XEventListener >& xListener )
2346{
2347 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2348
2349 if ( !m_pImpl )
2350 {
2351 SAL_INFO("package.xstor", "Disposed!");
2352 throw lang::DisposedException();
2353 }
2354
2356 xListener );
2357}
2358
2360 const uno::Reference< lang::XEventListener >& xListener )
2361{
2362 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2363
2364 if ( !m_pImpl )
2365 {
2366 SAL_INFO("package.xstor", "Disposed!");
2367 throw lang::DisposedException();
2368 }
2369
2371 xListener );
2372}
2373
2374void SAL_CALL OWriteStream::setEncryptionPassword( const OUString& aPass )
2375{
2376 osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
2377
2379
2380 if ( !m_pImpl )
2381 {
2382 SAL_INFO("package.xstor", "Disposed!");
2383 throw lang::DisposedException();
2384 }
2385
2386 OSL_ENSURE( m_pImpl->m_xPackageStream.is(), "No package stream is set!" );
2387
2389
2391}
2392
2394{
2395 osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
2396
2398
2399 if ( !m_pImpl )
2400 {
2401 SAL_INFO("package.xstor", "Disposed!");
2402 throw lang::DisposedException();
2403 }
2404
2405 OSL_ENSURE( m_pImpl->m_xPackageStream.is(), "No package stream is set!" );
2406
2408
2410}
2411
2412void SAL_CALL OWriteStream::setEncryptionData( const uno::Sequence< beans::NamedValue >& aEncryptionData )
2413{
2414 osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
2415
2417
2418 if ( !m_pImpl )
2419 {
2420 SAL_INFO("package.xstor", "Disposed!");
2421 throw lang::DisposedException();
2422 }
2423
2424 OSL_ENSURE( m_pImpl->m_xPackageStream.is(), "No package stream is set!" );
2425
2426 m_pImpl->SetEncrypted( aEncryptionData );
2427
2429}
2430
2432{
2433 osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
2434
2435 if (!m_pImpl)
2436 return false;
2437
2438 bool bRet = false;
2439
2440 try
2441 {
2442 bRet = m_pImpl->IsEncrypted();
2443
2446 }
2447 catch( const uno::RuntimeException& )
2448 {
2449 TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
2450 throw;
2451 }
2452 catch( const uno::Exception& )
2453 {
2454 uno::Any aCaught( ::cppu::getCaughtException() );
2455 SAL_INFO("package.xstor", "Rethrow: " << exceptionToString(aCaught));
2456 throw lang::WrappedTargetRuntimeException( "Problems on hasEncryptionData!",
2457 getXWeak(),
2458 aCaught );
2459 }
2460
2461 return bRet;
2462}
2463
2464sal_Bool SAL_CALL OWriteStream::hasByID( const OUString& sID )
2465{
2466 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2467
2468 if ( !m_pImpl )
2469 {
2470 SAL_INFO("package.xstor", "Disposed!");
2471 throw lang::DisposedException();
2472 }
2473
2474 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
2475 throw uno::RuntimeException();
2476
2477 try
2478 {
2479 getRelationshipByID( sID );
2480 return true;
2481 }
2482 catch( const container::NoSuchElementException& )
2483 {
2484 TOOLS_INFO_EXCEPTION("package.xstor", "No Element");
2485 }
2486
2487 return false;
2488}
2489
2490OUString SAL_CALL OWriteStream::getTargetByID( const OUString& sID )
2491{
2492 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2493
2494 if ( !m_pImpl )
2495 {
2496 SAL_INFO("package.xstor", "Disposed!");
2497 throw lang::DisposedException();
2498 }
2499
2500 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
2501 throw uno::RuntimeException();
2502
2503 const uno::Sequence< beans::StringPair > aSeq = getRelationshipByID( sID );
2504 auto pRel = lcl_findPairByName(aSeq, "Target");
2505 if (pRel != aSeq.end())
2506 return pRel->Second;
2507
2508 return OUString();
2509}
2510
2511OUString SAL_CALL OWriteStream::getTypeByID( const OUString& sID )
2512{
2513 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2514
2515 if ( !m_pImpl )
2516 {
2517 SAL_INFO("package.xstor", "Disposed!");
2518 throw lang::DisposedException();
2519 }
2520
2521 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
2522 throw uno::RuntimeException();
2523
2524 const uno::Sequence< beans::StringPair > aSeq = getRelationshipByID( sID );
2525 auto pRel = lcl_findPairByName(aSeq, "Type");
2526 if (pRel != aSeq.end())
2527 return pRel->Second;
2528
2529 return OUString();
2530}
2531
2532uno::Sequence< beans::StringPair > SAL_CALL OWriteStream::getRelationshipByID( const OUString& sID )
2533{
2534 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2535
2536 if ( !m_pImpl )
2537 {
2538 SAL_INFO("package.xstor", "Disposed!");
2539 throw lang::DisposedException();
2540 }
2541
2542 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
2543 throw uno::RuntimeException();
2544
2545 // TODO/LATER: in future the unification of the ID could be checked
2546 const uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships();
2547 const beans::StringPair aIDRel("Id", sID);
2548 auto pRel = std::find_if(aSeq.begin(), aSeq.end(),
2549 [&aIDRel](const uno::Sequence<beans::StringPair>& rRel) {
2550 return std::find(rRel.begin(), rRel.end(), aIDRel) != rRel.end(); });
2551 if (pRel != aSeq.end())
2552 return *pRel;
2553
2554 throw container::NoSuchElementException();
2555}
2556
2557uno::Sequence< uno::Sequence< beans::StringPair > > SAL_CALL OWriteStream::getRelationshipsByType( const OUString& sType )
2558{
2559 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2560
2561 if ( !m_pImpl )
2562 {
2563 SAL_INFO("package.xstor", "Disposed!");
2564 throw lang::DisposedException();
2565 }
2566
2567 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
2568 throw uno::RuntimeException();
2569
2570 // TODO/LATER: in future the unification of the ID could be checked
2571 const uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships();
2572 const beans::StringPair aTypeRel("Type", sType);
2573 std::vector< uno::Sequence<beans::StringPair> > aResult;
2574 aResult.reserve(aSeq.getLength());
2575
2576 std::copy_if(aSeq.begin(), aSeq.end(), std::back_inserter(aResult),
2577 [&aTypeRel](const uno::Sequence<beans::StringPair>& rRel) {
2578 return std::find(rRel.begin(), rRel.end(), aTypeRel) != rRel.end(); });
2579
2580 return comphelper::containerToSequence(aResult);
2581}
2582
2583uno::Sequence< uno::Sequence< beans::StringPair > > SAL_CALL OWriteStream::getAllRelationships()
2584{
2585 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2586
2587 if ( !m_pImpl )
2588 {
2589 SAL_INFO("package.xstor", "Disposed!");
2590 throw lang::DisposedException();
2591 }
2592
2593 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
2594 throw uno::RuntimeException();
2595
2597}
2598
2599void SAL_CALL OWriteStream::insertRelationshipByID( const OUString& sID, const uno::Sequence< beans::StringPair >& aEntry, sal_Bool bReplace )
2600{
2601 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2602
2603 if ( !m_pImpl )
2604 {
2605 SAL_INFO("package.xstor", "Disposed!");
2606 throw lang::DisposedException();
2607 }
2608
2609 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
2610 throw uno::RuntimeException();
2611
2612 const beans::StringPair aIDRel("Id", sID);
2613
2614 uno::Sequence<beans::StringPair>* pPair = nullptr;
2615
2616 // TODO/LATER: in future the unification of the ID could be checked
2617 uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships();
2618 for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ )
2619 {
2620 const auto& rRel = aSeq[nInd];
2621 if (std::find(rRel.begin(), rRel.end(), aIDRel) != rRel.end())
2622 pPair = &aSeq.getArray()[nInd];
2623 }
2624
2625 if ( pPair && !bReplace )
2626 throw container::ElementExistException(); // TODO
2627
2628 if ( !pPair )
2629 {
2630 sal_Int32 nIDInd = aSeq.getLength();
2631 aSeq.realloc( nIDInd + 1 );
2632 pPair = &aSeq.getArray()[nIDInd];
2633 }
2634
2635 std::vector<beans::StringPair> aResult;
2636 aResult.reserve(aEntry.getLength() + 1);
2637
2638 aResult.push_back(aIDRel);
2639 std::copy_if(aEntry.begin(), aEntry.end(), std::back_inserter(aResult),
2640 [](const beans::StringPair& rRel) { return rRel.First != "Id"; });
2641
2642 *pPair = comphelper::containerToSequence(aResult);
2643
2647}
2648
2649void SAL_CALL OWriteStream::removeRelationshipByID( const OUString& sID )
2650{
2651 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2652
2653 if ( !m_pImpl )
2654 {
2655 SAL_INFO("package.xstor", "Disposed!");
2656 throw lang::DisposedException();
2657 }
2658
2659 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
2660 throw uno::RuntimeException();
2661
2662 uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships();
2663 const beans::StringPair aIDRel("Id", sID);
2664 auto pRel = std::find_if(std::cbegin(aSeq), std::cend(aSeq),
2665 [&aIDRel](const uno::Sequence< beans::StringPair >& rRel) {
2666 return std::find(rRel.begin(), rRel.end(), aIDRel) != rRel.end(); });
2667 if (pRel != std::cend(aSeq))
2668 {
2669 auto nInd = static_cast<sal_Int32>(std::distance(std::cbegin(aSeq), pRel));
2671
2675
2676 // TODO/LATER: in future the unification of the ID could be checked
2677 return;
2678 }
2679
2680 throw container::NoSuchElementException();
2681}
2682
2683void SAL_CALL OWriteStream::insertRelationships( const uno::Sequence< uno::Sequence< beans::StringPair > >& aEntries, sal_Bool bReplace )
2684{
2685 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2686
2687 if ( !m_pImpl )
2688 {
2689 SAL_INFO("package.xstor", "Disposed!");
2690 throw lang::DisposedException();
2691 }
2692
2693 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
2694 throw uno::RuntimeException();
2695
2696 OUString aIDTag( "Id" );
2697 const uno::Sequence< uno::Sequence< beans::StringPair > > aSeq = getAllRelationships();
2698 std::vector< uno::Sequence<beans::StringPair> > aResultVec;
2699 aResultVec.reserve(aSeq.getLength() + aEntries.getLength());
2700
2701 std::copy_if(aSeq.begin(), aSeq.end(), std::back_inserter(aResultVec),
2702 [&aIDTag, &aEntries, bReplace](const uno::Sequence<beans::StringPair>& rTargetRel) {
2703 auto pTargetPair = lcl_findPairByName(rTargetRel, aIDTag);
2704 if (pTargetPair == rTargetRel.end())
2705 return false;
2706
2707 bool bIsSourceSame = std::any_of(aEntries.begin(), aEntries.end(),
2708 [&pTargetPair](const uno::Sequence<beans::StringPair>& rSourceEntry) {
2709 return std::find(rSourceEntry.begin(), rSourceEntry.end(), *pTargetPair) != rSourceEntry.end(); });
2710
2711 if ( bIsSourceSame && !bReplace )
2712 throw container::ElementExistException();
2713
2714 // if no such element in the provided sequence
2715 return !bIsSourceSame;
2716 });
2717
2718 std::transform(aEntries.begin(), aEntries.end(), std::back_inserter(aResultVec),
2719 [&aIDTag](const uno::Sequence<beans::StringPair>& rEntry) -> uno::Sequence<beans::StringPair> {
2720 auto pPair = lcl_findPairByName(rEntry, aIDTag);
2721 if (pPair == rEntry.end())
2722 throw io::IOException(); // TODO: illegal relation ( no ID )
2723
2724 auto aResult = comphelper::sequenceToContainer<std::vector<beans::StringPair>>(rEntry);
2725 auto nIDInd = std::distance(rEntry.begin(), pPair);
2726 std::rotate(aResult.begin(), std::next(aResult.begin(), nIDInd), std::next(aResult.begin(), nIDInd + 1));
2727
2728 return comphelper::containerToSequence(aResult);
2729 });
2730
2731 m_pImpl->m_aNewRelInfo = comphelper::containerToSequence(aResultVec);
2732 m_pImpl->m_xNewRelInfoStream.clear();
2733 m_pImpl->m_nRelInfoStatus = RELINFO_CHANGED;
2734}
2735
2737{
2738 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2739
2740 if ( !m_pImpl )
2741 {
2742 SAL_INFO("package.xstor", "Disposed!");
2743 throw lang::DisposedException();
2744 }
2745
2746 if ( m_nStorageType != embed::StorageFormats::OFOPXML )
2747 throw uno::RuntimeException();
2748
2749 m_pImpl->m_aNewRelInfo.realloc( 0 );
2752}
2753
2754uno::Reference< beans::XPropertySetInfo > SAL_CALL OWriteStream::getPropertySetInfo()
2755{
2756 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2757
2758 //TODO:
2759 return uno::Reference< beans::XPropertySetInfo >();
2760}
2761
2762void SAL_CALL OWriteStream::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
2763{
2764 osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
2765
2766 if ( !m_pImpl )
2767 {
2768 SAL_INFO("package.xstor", "Disposed!");
2769 throw lang::DisposedException();
2770 }
2771
2773 static constexpr OUStringLiteral aCompressedString( u"Compressed" );
2774 static constexpr OUStringLiteral aMediaTypeString( u"MediaType" );
2775 if ( m_nStorageType == embed::StorageFormats::PACKAGE && aPropertyName == aMediaTypeString )
2776 {
2777 // if the "Compressed" property is not set explicitly, the MediaType can change the default value
2778 bool bCompressedValueFromType = true;
2779 OUString aType;
2780 aValue >>= aType;
2781
2783 {
2784 if ( aType == "image/jpeg" || aType == "image/png" || aType == "image/gif" )
2785 bCompressedValueFromType = false;
2786 }
2787
2788 for ( auto& rProp : asNonConstRange(m_pImpl->m_aProps) )
2789 {
2790 if ( aPropertyName == rProp.Name )
2791 rProp.Value = aValue;
2792 else if ( !m_pImpl->m_bCompressedSetExplicit && aCompressedString == rProp.Name )
2793 rProp.Value <<= bCompressedValueFromType;
2794 }
2795 }
2796 else if ( aPropertyName == aCompressedString )
2797 {
2798 // if the "Compressed" property is not set explicitly, the MediaType can change the default value
2800 for ( auto& rProp : asNonConstRange(m_pImpl->m_aProps) )
2801 {
2802 if ( aPropertyName == rProp.Name )
2803 rProp.Value = aValue;
2804 }
2805 }
2806 else if ( m_nStorageType == embed::StorageFormats::PACKAGE
2807 && aPropertyName == "UseCommonStoragePasswordEncryption" )
2808 {
2809 bool bUseCommonEncryption = false;
2810 if ( !(aValue >>= bUseCommonEncryption) )
2811 throw lang::IllegalArgumentException(); //TODO
2812
2814 {
2815 // the data stream is provided to the packagestream directly
2816 m_pImpl->m_bUseCommonEncryption = bUseCommonEncryption;
2817 }
2818 else if ( bUseCommonEncryption )
2819 {
2821 {
2824 }
2825 }
2826 else
2828 }
2829 else if ( m_nStorageType == embed::StorageFormats::OFOPXML && aPropertyName == aMediaTypeString )
2830 {
2831 for ( auto& rProp : asNonConstRange(m_pImpl->m_aProps) )
2832 {
2833 if ( aPropertyName == rProp.Name )
2834 rProp.Value = aValue;
2835 }
2836 }
2837 else if ( m_nStorageType == embed::StorageFormats::OFOPXML && aPropertyName == "RelationsInfoStream" )
2838 {
2839 uno::Reference< io::XInputStream > xInRelStream;
2840 if ( !( aValue >>= xInRelStream ) || !xInRelStream.is() )
2841 throw lang::IllegalArgumentException(); // TODO
2842
2843 uno::Reference< io::XSeekable > xSeek( xInRelStream, uno::UNO_QUERY );
2844 if ( !xSeek.is() )
2845 {
2846 // currently this is an internal property that is used for optimization
2847 // and the stream must support XSeekable interface
2848 // TODO/LATER: in future it can be changed if property is used from outside
2849 throw lang::IllegalArgumentException(); // TODO
2850 }
2851
2852 m_pImpl->m_xNewRelInfoStream = xInRelStream;
2853 m_pImpl->m_aNewRelInfo = uno::Sequence< uno::Sequence< beans::StringPair > >();
2855 }
2856 else if ( m_nStorageType == embed::StorageFormats::OFOPXML && aPropertyName == "RelationsInfo" )
2857 {
2858 if ( !(aValue >>= m_pImpl->m_aNewRelInfo) )
2859 throw lang::IllegalArgumentException(); // TODO
2860 }
2861 else if ( aPropertyName == "Size" )
2862 throw beans::PropertyVetoException(); // TODO
2863 else if ( m_nStorageType == embed::StorageFormats::PACKAGE
2864 && ( aPropertyName == "IsEncrypted" || aPropertyName == "Encrypted" ) )
2865 throw beans::PropertyVetoException(); // TODO
2866 else if ( aPropertyName == "RelId" )
2867 {
2868 aValue >>= m_pImpl->m_nRelId;
2869 }
2870 else
2871 throw beans::UnknownPropertyException(aPropertyName); // TODO
2872
2873 m_pImpl->m_bHasDataToFlush = true;
2875}
2876
2877uno::Any SAL_CALL OWriteStream::getPropertyValue( const OUString& aProp )
2878{
2879 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2880
2881 if ( !m_pImpl )
2882 {
2883 SAL_INFO("package.xstor", "Disposed!");
2884 throw lang::DisposedException();
2885 }
2886
2887 if ( aProp == "RelId" )
2888 {
2889 return uno::Any( m_pImpl->GetNewRelId() );
2890 }
2891
2892 OUString aPropertyName;
2893 if ( aProp == "IsEncrypted" )
2894 aPropertyName = "Encrypted";
2895 else
2896 aPropertyName = aProp;
2897
2898 if ( ( ( m_nStorageType == embed::StorageFormats::PACKAGE || m_nStorageType == embed::StorageFormats::OFOPXML )
2899 && aPropertyName == "MediaType" )
2900 || ( m_nStorageType == embed::StorageFormats::PACKAGE && aPropertyName == "Encrypted" )
2901 || aPropertyName == "Compressed" )
2902 {
2904
2905 auto pProp = std::find_if(std::cbegin(m_pImpl->m_aProps), std::cend(m_pImpl->m_aProps),
2906 [&aPropertyName](const css::beans::PropertyValue& rProp){ return aPropertyName == rProp.Name; });
2907 if (pProp != std::cend(m_pImpl->m_aProps))
2908 return pProp->Value;
2909 }
2910 else if ( m_nStorageType == embed::StorageFormats::PACKAGE
2911 && aPropertyName == "UseCommonStoragePasswordEncryption" )
2913 else if ( aPropertyName == "Size" )
2914 {
2915 bool bThrow = false;
2916 try
2917 {
2919 }
2920 catch (const io::IOException&)
2921 {
2922 bThrow = true;
2923 }
2924 if (bThrow || !m_xSeekable.is())
2925 throw uno::RuntimeException();
2926
2927 return uno::Any( m_xSeekable->getLength() );
2928 }
2929
2930 throw beans::UnknownPropertyException(aPropertyName); // TODO
2931}
2932
2934 const OUString& /*aPropertyName*/,
2935 const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ )
2936{
2937 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2938
2939 if ( !m_pImpl )
2940 {
2941 SAL_INFO("package.xstor", "Disposed!");
2942 throw lang::DisposedException();
2943 }
2944
2945 //TODO:
2946}
2947
2949 const OUString& /*aPropertyName*/,
2950 const uno::Reference< beans::XPropertyChangeListener >& /*aListener*/ )
2951{
2952 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2953
2954 if ( !m_pImpl )
2955 {
2956 SAL_INFO("package.xstor", "Disposed!");
2957 throw lang::DisposedException();
2958 }
2959
2960 //TODO:
2961}
2962
2964 const OUString& /*PropertyName*/,
2965 const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ )
2966{
2967 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2968
2969 if ( !m_pImpl )
2970 {
2971 SAL_INFO("package.xstor", "Disposed!");
2972 throw lang::DisposedException();
2973 }
2974
2975 //TODO:
2976}
2977
2979 const OUString& /*PropertyName*/,
2980 const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ )
2981{
2982 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
2983
2984 if ( !m_pImpl )
2985 {
2986 SAL_INFO("package.xstor", "Disposed!");
2987 throw lang::DisposedException();
2988 }
2989
2990 //TODO:
2991}
2992
2993// XTransactedObject
2994
2996/*
2997 1 - preCommit
2998 2 - committed
2999 3 - preRevert
3000 4 - reverted
3001*/
3002{
3003 // no need to lock mutex here for the checking of m_pImpl, and m_pData is alive until the object is destructed
3004 if ( !m_pImpl )
3005 {
3006 SAL_INFO("package.xstor", "Disposed!");
3007 throw lang::DisposedException();
3008 }
3009
3010 lang::EventObject aSource( getXWeak() );
3011
3015 if ( !pContainer )
3016 return;
3017
3018 comphelper::OInterfaceIteratorHelper2 pIterator( *pContainer );
3019 while ( pIterator.hasMoreElements( ) )
3020 {
3021 OSL_ENSURE( nMessage >= 1 && nMessage <= 4, "Wrong internal notification code is used!" );
3022
3023 switch( nMessage )
3024 {
3026 static_cast<embed::XTransactionListener*>( pIterator.next( ) )->preCommit( aSource );
3027 break;
3029 static_cast<embed::XTransactionListener*>( pIterator.next( ) )->commited( aSource );
3030 break;
3032 static_cast<embed::XTransactionListener*>( pIterator.next( ) )->preRevert( aSource );
3033 break;
3034 case STOR_MESS_REVERTED:
3035 static_cast< embed::XTransactionListener*>( pIterator.next( ) )->reverted( aSource );
3036 break;
3037 }
3038 }
3039}
3041{
3042 SAL_INFO( "package.xstor", "package (mv76033) OWriteStream::commit" );
3043
3044 if ( !m_pImpl )
3045 {
3046 SAL_INFO("package.xstor", "Disposed!");
3047 throw lang::DisposedException();
3048 }
3049
3050 if ( !m_bTransacted )
3051 throw uno::RuntimeException();
3052
3053 try {
3055
3056 osl::ClearableMutexGuard aGuard(m_xSharedMutex->GetMutex());
3057
3058 if ( !m_pImpl )
3059 {
3060 SAL_INFO("package.xstor", "Disposed!");
3061 throw lang::DisposedException();
3062 }
3063
3064 m_pImpl->Commit();
3065
3066 // when the storage is committed the parent is modified
3068 }
3069 catch( const io::IOException& )
3070 {
3071 TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
3072 throw;
3073 }
3074 catch( const embed::StorageWrappedTargetException& )
3075 {
3076 TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
3077 throw;
3078 }
3079 catch( const uno::RuntimeException& )
3080 {
3081 TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
3082 throw;
3083 }
3084 catch( const uno::Exception& )
3085 {
3086 uno::Any aCaught( ::cppu::getCaughtException() );
3087 SAL_INFO("package.xstor", "Rethrow: " << exceptionToString(aCaught));
3088 throw embed::StorageWrappedTargetException( "Problems on commit!",
3089 getXWeak(),
3090 aCaught );
3091 }
3092
3094}
3095
3097{
3098 SAL_INFO( "package.xstor", "package (mv76033) OWriteStream::revert" );
3099
3100 // the method removes all the changes done after last commit
3101
3102 if ( !m_pImpl )
3103 {
3104 SAL_INFO("package.xstor", "Disposed!");
3105 throw lang::DisposedException();
3106 }
3107
3108 if ( !m_bTransacted )
3109 throw uno::RuntimeException();
3110
3112
3113 {
3114 osl::MutexGuard aGuard(m_xSharedMutex->GetMutex());
3115
3116 if (!m_pImpl)
3117 {
3118 SAL_INFO("package.xstor", "Disposed!");
3119 throw lang::DisposedException();
3120 }
3121
3122 try {
3123 m_pImpl->Revert();
3124 }
3125 catch (const io::IOException&)
3126 {
3127 TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
3128 throw;
3129 }
3130 catch (const embed::StorageWrappedTargetException&)
3131 {
3132 TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
3133 throw;
3134 }
3135 catch (const uno::RuntimeException&)
3136 {
3137 TOOLS_INFO_EXCEPTION("package.xstor", "Rethrow");
3138 throw;
3139 }
3140 catch (const uno::Exception&)
3141 {
3142 uno::Any aCaught(::cppu::getCaughtException());
3143 SAL_INFO("package.xstor", "Rethrow: " << exceptionToString(aCaught));
3144 throw embed::StorageWrappedTargetException("Problems on revert!",
3145 getXWeak(),
3146 aCaught);
3147 }
3148 }
3149
3151}
3152
3153// XTransactionBroadcaster
3154
3155void SAL_CALL OWriteStream::addTransactionListener( const uno::Reference< embed::XTransactionListener >& aListener )
3156{
3157 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
3158
3159 if ( !m_pImpl )
3160 {
3161 SAL_INFO("package.xstor", "Disposed!");
3162 throw lang::DisposedException();
3163 }
3164
3165 if ( !m_bTransacted )
3166 throw uno::RuntimeException();
3167
3169 aListener );
3170}
3171
3172void SAL_CALL OWriteStream::removeTransactionListener( const uno::Reference< embed::XTransactionListener >& aListener )
3173{
3174 ::osl::MutexGuard aGuard( m_xSharedMutex->GetMutex() );
3175
3176 if ( !m_pImpl )
3177 {
3178 SAL_INFO("package.xstor", "Disposed!");
3179 throw lang::DisposedException();
3180 }
3181
3182 if ( !m_bTransacted )
3183 throw uno::RuntimeException();
3184
3186 aListener );
3187}
3188
3189/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OptionalString sType
::std::unique_ptr< XmlIdRegistry_Impl > m_pImpl
Reference< XComponentContext > m_xContext
constexpr OUStringLiteral STORAGE_ENCRYPTION_KEYS_PROPERTY
Reference< XInputStream > xStream
constexpr OUStringLiteral sMediaType
void ModifyParentUnlockMutex_Impl(osl::ClearableMutexGuard &aGuard)
virtual sal_Int32 SAL_CALL available() override
virtual sal_Int32 SAL_CALL readSomeBytes(css::uno::Sequence< sal_Int8 > &aData, sal_Int32 nMaxBytesToRead) override
virtual void SAL_CALL addPropertyChangeListener(const OUString &aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &xListener) override
OWriteStream_Impl * m_pImpl
rtl::Reference< comphelper::RefCountedMutex > m_xSharedMutex
virtual void SAL_CALL revert() override
virtual void SAL_CALL addVetoableChangeListener(const OUString &PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &aListener) override
virtual sal_Int64 SAL_CALL getLength() override
virtual void SAL_CALL writeBytes(const css::uno::Sequence< sal_Int8 > &aData) override
virtual void SAL_CALL setEncryptionPassword(const OUString &aPass) override
virtual void SAL_CALL dispose() override
virtual void SAL_CALL setPropertyValue(const OUString &aPropertyName, const css::uno::Any &aValue) override
virtual sal_Bool SAL_CALL hasEncryptionData() override
virtual css::uno::Sequence< css::beans::StringPair > SAL_CALL getRelationshipByID(const OUString &sID) override
virtual css::uno::Reference< css::io::XOutputStream > SAL_CALL getOutputStream() override
sal_Int32 m_nStorageType
comphelper::OMultiTypeInterfaceContainerHelper2 m_aListenersContainer
virtual void SAL_CALL removeRelationshipByID(const OUString &sID) override
virtual void SAL_CALL addTransactionListener(const css::uno::Reference< css::embed::XTransactionListener > &aListener) override
void CopyToStreamInternally_Impl(const css::uno::Reference< css::io::XStream > &xStream)
virtual void SAL_CALL seek(sal_Int64 location) override
virtual void SAL_CALL insertRelationshipByID(const OUString &sID, const css::uno::Sequence< css::beans::StringPair > &aEntry, sal_Bool bReplace) override
virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override
virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getInputStream() override
::std::optional< ::cppu::OTypeCollection > m_oTypeCollection
css::uno::Reference< css::io::XSeekable > m_xSeekable
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &rType) override
virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override
void BroadcastTransaction(sal_Int8 nMessage)
virtual void SAL_CALL truncate() override
virtual sal_Int32 SAL_CALL readBytes(css::uno::Sequence< sal_Int8 > &aData, sal_Int32 nBytesToRead) override
virtual void SAL_CALL release() noexcept override
virtual css::uno::Sequence< css::uno::Sequence< css::beans::StringPair > > SAL_CALL getAllRelationships() override
virtual void SAL_CALL removeEncryption() override
sal_Int64 m_nInitPosition
virtual void SAL_CALL commit() override
virtual void SAL_CALL closeOutput() override
virtual void SAL_CALL removeTransactionListener(const css::uno::Reference< css::embed::XTransactionListener > &aListener) override
OWriteStream(OWriteStream_Impl &rImpl, bool bTransacted)
virtual css::uno::Sequence< css::uno::Sequence< css::beans::StringPair > > SAL_CALL getRelationshipsByType(const OUString &sType) override
css::uno::Reference< css::io::XOutputStream > m_xOutStream
virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override
virtual void SAL_CALL acquire() noexcept override
virtual void SAL_CALL removePropertyChangeListener(const OUString &aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &aListener) override
virtual sal_Int64 SAL_CALL getPosition() override
virtual void SAL_CALL setEncryptionData(const css::uno::Sequence< css::beans::NamedValue > &aEncryptionData) override
virtual OUString SAL_CALL getTypeByID(const OUString &sID) override
virtual void SAL_CALL removeEventListener(const css::uno::Reference< css::lang::XEventListener > &aListener) override
css::uno::Reference< css::io::XInputStream > m_xInStream
virtual sal_Bool SAL_CALL hasByID(const OUString &sID) override
virtual OUString SAL_CALL getTargetByID(const OUString &sID) override
virtual css::uno::Any SAL_CALL getPropertyValue(const OUString &PropertyName) override
virtual void SAL_CALL flush() override
virtual void SAL_CALL clearRelationships() override
virtual void SAL_CALL insertRelationships(const css::uno::Sequence< css::uno::Sequence< css::beans::StringPair > > &aEntries, sal_Bool bReplace) override
virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) override
virtual ~OWriteStream() override
virtual void SAL_CALL closeInput() override
virtual void SAL_CALL removeVetoableChangeListener(const OUString &PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &aListener) override
virtual void SAL_CALL addEventListener(const css::uno::Reference< css::lang::XEventListener > &xListener) override
std::size_t WriteBytes(const void *pData, std::size_t nSize)
sal_uInt64 Seek(sal_uInt64 nPos)
css::uno::XInterface * next()
OInterfaceContainerHelper2 * getContainer(const css::uno::Type &rKey) const
sal_Int32 removeInterface(const css::uno::Type &rKey, const css::uno::Reference< css::uno::XInterface > &rxIFace)
sal_Int32 addInterface(const css::uno::Type &rKey, const css::uno::Reference< css::uno::XInterface > &r)
void disposeAndClear(const css::lang::EventObject &rEvt)
static css::uno::Sequence< css::beans::NamedValue > CreatePackageEncryptionData(std::u16string_view aPassword)
static void CopyInputToOutput(const css::uno::Reference< css::io::XInputStream > &xInput, const css::uno::Reference< css::io::XOutputStream > &xOutput)
SequenceAsHashMapBase::const_iterator const_iterator
css::uno::Sequence< css::beans::NamedValue > getAsConstNamedValueList() const
const css::uno::Sequence< sal_Int8 > & getSeq() const
css::uno::Sequence< css::uno::Type > SAL_CALL getTypes()
oslInterlockedCount m_refCount
OString exceptionToString(const css::uno::Any &caught)
#define TOOLS_WARN_EXCEPTION(area, stream)
#define TOOLS_INFO_EXCEPTION(area, stream)
uno::Reference< deployment::XPackage > m_xPackage
float u
ScXMLEditAttributeMap::Entry const aEntries[]
OUString sName
OUString aName
void * p
sal_uInt16 nPos
Sequence< sal_Int8 > aSeq
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
std::unique_ptr< sal_Int32[]> pData
constexpr OUStringLiteral aData
const sal_Int32 nConstBufferSize
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
void removeElementAt(css::uno::Sequence< T > &_rSeq, sal_Int32 _nPos)
int i
OUString aPropName
static void CopyInputToOutput(const css::uno::Reference< css::io::XInputStream > &xInput, SvStream &rOutput)
bool PackageEncryptionDataLessOrEqual(const ::comphelper::SequenceAsHashMap &aHash1, const ::comphelper::SequenceAsHashMap &aHash2)
#define MAX_STORCACHE_SIZE
bool HasModifiedListener() const
Definition: xstorage.hxx:128
bool m_bIsModified
Definition: xstorage.hxx:118
static void completeStorageStreamCopy_Impl(const css::uno::Reference< css::io::XStream > &xSource, const css::uno::Reference< css::io::XStream > &xDest, sal_Int32 nStorageType, const css::uno::Sequence< css::uno::Sequence< css::beans::StringPair > > &aRelInfo)
Definition: xstorage.cxx:73
::comphelper::SequenceAsHashMap GetCommonRootEncryptionData()
Definition: xstorage.cxx:1235
bool m_bHasCommonEncryptionData
Definition: xstorage.hxx:145
OStorage * m_pAntiImpl
Definition: xstorage.hxx:114
css::uno::Sequence< css::uno::Sequence< css::beans::StringPair > > m_aNewRelInfo
void CopyInternallyTo_Impl(const css::uno::Reference< css::io::XStream > &xDestStream, const ::comphelper::SequenceAsHashMap &aEncryptionData)
rtl::Reference< comphelper::RefCountedMutex > m_xMutex
css::uno::Reference< css::io::XStream > m_xCacheStream
friend class OWriteStream
css::uno::Sequence< css::uno::Sequence< css::beans::StringPair > > m_aOrigRelInfo
void SetEncrypted(const ::comphelper::SequenceAsHashMap &aEncryptionData)
css::uno::Reference< css::io::XSeekable > m_xCacheSeek
::comphelper::SequenceAsHashMap GetCommonRootEncryptionData()
css::uno::Reference< css::io::XInputStream > m_xNewRelInfoStream
void GetCopyOfLastCommit(css::uno::Reference< css::io::XStream > &xTargetStream)
css::uno::Reference< css::packages::XDataSinkEncrSupport > m_xPackageStream
::comphelper::SequenceAsHashMap m_aEncryptionData
css::uno::Sequence< css::uno::Sequence< css::beans::StringPair > > GetAllRelationshipsIfAny()
void CreateReadonlyCopyBasedOnData(const css::uno::Reference< css::io::XInputStream > &xDataToCopy, const css::uno::Sequence< css::beans::PropertyValue > &aProps, css::uno::Reference< css::io::XStream > &xTargetStream)
css::uno::Reference< css::io::XInputStream > GetPlainRawInStream()
OWriteStream * m_pAntiImpl
css::uno::Reference< css::io::XInputStream > m_xOrigRelInfoStream
css::uno::Reference< css::io::XInputStream > GetTempFileAsInputStream()
void GetFilledTempFileIfNo(const css::uno::Reference< css::io::XInputStream > &xStream)
std::optional< utl::TempFileFast > m_oTempFile
css::uno::Reference< css::uno::XComponentContext > m_xContext
void CommitStreamRelInfo(const css::uno::Reference< css::embed::XStorage > &xRelStorage, std::u16string_view aOrigStreamName, std::u16string_view aNewStreamName)
css::uno::Sequence< css::beans::PropertyValue > const & GetStreamProperties()
OStorage_Impl * m_pParent
css::uno::Reference< css::io::XStream > GetStream(sal_Int32 nStreamMode, const ::comphelper::SequenceAsHashMap &aEncryptionData, bool bHierarchyAccess)
css::uno::Reference< css::io::XInputStream > GetRawInStream()
void InsertIntoPackageFolder(const OUString &aName, const css::uno::Reference< css::container::XNameContainer > &xParentPackageFolder)
css::uno::Sequence< css::beans::PropertyValue > m_aProps
friend class OInputCompStream
void InputStreamDisposed(OInputCompStream *pStream)
void InsertStreamDirectly(const css::uno::Reference< css::io::XInputStream > &xInStream, const css::uno::Sequence< css::beans::PropertyValue > &aProps)
css::uno::Reference< css::lang::XSingleServiceFactory > m_xPackage
css::uno::Reference< css::io::XStream > GetStream_Impl(sal_Int32 nStreamMode, bool bHierarchyAccess)
css::uno::Reference< css::io::XStream > GetTempFileAsStream()
css::uno::Sequence< css::beans::PropertyValue > ReadPackageStreamProperties()
std::vector< OInputCompStream * > m_aInputStreamsVector
css::uno::Sequence< css::beans::PropertyValue > InsertOwnProps(const css::uno::Sequence< css::beans::PropertyValue > &aProps, bool bUseCommonEncryption)
OWriteStream_Impl(OStorage_Impl *pParent, const css::uno::Reference< css::packages::XDataSinkEncrSupport > &xPackageStream, const css::uno::Reference< css::lang::XSingleServiceFactory > &xPackage, css::uno::Reference< css::uno::XComponentContext > xContext, bool bForceEncrypted, sal_Int32 nStorageType, bool bDefaultCompress, css::uno::Reference< css::io::XInputStream > xRelInfoStream=css::uno::Reference< css::io::XInputStream >())
bool hasValue()
Object Value
OUString Name
unsigned char sal_Bool
signed char sal_Int8
#define RELINFO_CHANGED
Definition: xstorage.hxx:65
#define STOR_MESS_PREREVERT
Definition: xstorage.hxx:73
#define RELINFO_NO_INIT
Definition: xstorage.hxx:63
#define STOR_MESS_COMMITTED
Definition: xstorage.hxx:72
#define STOR_MESS_REVERTED
Definition: xstorage.hxx:74
#define RELINFO_CHANGED_STREAM_READ
Definition: xstorage.hxx:67
#define RELINFO_BROKEN
Definition: xstorage.hxx:68
#define RELINFO_CHANGED_BROKEN
Definition: xstorage.hxx:69
#define STOR_MESS_PRECOMMIT
Definition: xstorage.hxx:71
#define RELINFO_READ
Definition: xstorage.hxx:64
#define RELINFO_CHANGED_STREAM
Definition: xstorage.hxx:66