1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <ZipPackage.hxx>
21 #include "ZipPackageSink.hxx"
22 #include <ZipEnumeration.hxx>
23 #include <ZipPackageStream.hxx>
24 #include <ZipPackageFolder.hxx>
25 #include <ZipOutputEntry.hxx>
26 #include <ZipOutputStream.hxx>
27 #include <ZipPackageBuffer.hxx>
28 #include <ZipFile.hxx>
29 #include <PackageConstants.hxx>
30 #include <com/sun/star/beans/PropertyValue.hpp>
31 #include <com/sun/star/packages/zip/ZipConstants.hpp>
32 #include <com/sun/star/packages/zip/ZipException.hpp>
33 #include <com/sun/star/packages/zip/ZipIOException.hpp>
34 #include <com/sun/star/packages/manifest/ManifestReader.hpp>
35 #include <com/sun/star/packages/manifest/ManifestWriter.hpp>
36 #include <com/sun/star/io/TempFile.hpp>
37 #include <com/sun/star/io/XStream.hpp>
38 #include <com/sun/star/io/XInputStream.hpp>
39 #include <com/sun/star/io/XOutputStream.hpp>
40 #include <com/sun/star/io/XTruncate.hpp>
41 #include <com/sun/star/io/XSeekable.hpp>
42 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
43 #include <com/sun/star/container/XNameContainer.hpp>
44 #include <officecfg/Office/Common.hxx>
45 #include <comphelper/fileurl.hxx>
46 #include <comphelper/processfactory.hxx>
47 #include <ucbhelper/content.hxx>
48 #include <cppuhelper/exc_hlp.hxx>
49 #include <com/sun/star/ucb/ContentCreationException.hpp>
50 #include <com/sun/star/ucb/TransferInfo.hpp>
51 #include <com/sun/star/ucb/NameClash.hpp>
52 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
53 #include <com/sun/star/ucb/OpenMode.hpp>
54 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
55 #include <com/sun/star/io/XActiveDataStreamer.hpp>
56 #include <com/sun/star/embed/UseBackupException.hpp>
57 #include <com/sun/star/embed/StorageFormats.hpp>
58 #include <com/sun/star/beans/NamedValue.hpp>
59 #include <com/sun/star/xml/crypto/DigestID.hpp>
60 #include <com/sun/star/xml/crypto/KDFID.hpp>
61 #include <cppuhelper/implbase.hxx>
62 #include <rtl/uri.hxx>
63 #include <rtl/random.h>
64 #include <o3tl/string_view.hxx>
65 #include <osl/diagnose.h>
66 #include <sal/log.hxx>
67 #include <unotools/streamwrap.hxx>
68 #include <unotools/tempfile.hxx>
69 #include <com/sun/star/io/XAsyncOutputMonitor.hpp>
71 #include <string_view>
73 #include <comphelper/seekableinput.hxx>
74 #include <comphelper/storagehelper.hxx>
75 #include <comphelper/ofopxmlhelper.hxx>
76 #include <comphelper/documentconstants.hxx>
77 #include <comphelper/sequenceashashmap.hxx>
78 #include <cppuhelper/supportsservice.hxx>
79 #include <comphelper/sequence.hxx>
80 #include <comphelper/servicehelper.hxx>
85 using namespace ucbhelper
;
86 using namespace com::sun::star
;
87 using namespace com::sun::star::io
;
88 using namespace com::sun::star::uno
;
89 using namespace com::sun::star::ucb
;
90 using namespace com::sun::star::util
;
91 using namespace com::sun::star::lang
;
92 using namespace com::sun::star::task
;
93 using namespace com::sun::star::beans
;
94 using namespace com::sun::star::packages
;
95 using namespace com::sun::star::container
;
96 using namespace com::sun::star::packages::zip
;
97 using namespace com::sun::star::packages::manifest
;
98 using namespace com::sun::star::packages::zip::ZipConstants
;
100 #if OSL_DEBUG_LEVEL > 0
101 #define THROW_WHERE SAL_WHERE
103 #define THROW_WHERE ""
108 class ActiveDataStreamer
: public ::cppu::WeakImplHelper
< XActiveDataStreamer
>
110 uno::Reference
< XStream
> mStream
;
113 virtual uno::Reference
< XStream
> SAL_CALL
getStream() override
116 virtual void SAL_CALL
setStream( const uno::Reference
< XStream
>& stream
) override
117 { mStream
= stream
; }
120 class DummyInputStream
: public ::cppu::WeakImplHelper
< XInputStream
>
122 virtual sal_Int32 SAL_CALL
readBytes( uno::Sequence
< sal_Int8
>&, sal_Int32
) override
125 virtual sal_Int32 SAL_CALL
readSomeBytes( uno::Sequence
< sal_Int8
>&, sal_Int32
) override
128 virtual void SAL_CALL
skipBytes( sal_Int32
) override
131 virtual sal_Int32 SAL_CALL
available() override
134 virtual void SAL_CALL
closeInput() override
140 sal_Int32
GetDefaultDerivedKeySize(sal_Int32
const nCipherID
)
144 case css::xml::crypto::CipherID::BLOWFISH_CFB_8
:
146 case css::xml::crypto::CipherID::AES_CBC_W3C_PADDING
:
147 case css::xml::crypto::CipherID::AES_GCM_W3C
:
154 ZipPackage::ZipPackage ( uno::Reference
< XComponentContext
> xContext
)
155 : m_aMutexHolder( new comphelper::RefCountedMutex
)
156 , m_nStartKeyGenerationID( xml::crypto::DigestID::SHA1
)
157 , m_oChecksumDigestID( xml::crypto::DigestID::SHA1_1K
)
158 , m_nKeyDerivationFunctionID(xml::crypto::KDFID::PBKDF2
)
159 , m_nCommonEncryptionID( xml::crypto::CipherID::BLOWFISH_CFB_8
)
160 , m_bHasEncryptedEntries ( false )
161 , m_bHasNonEncryptedEntries ( false )
162 , m_bInconsistent ( false )
163 , m_bForceRecovery ( false )
164 , m_bMediaTypeFallbackUsed ( false )
165 , m_nFormat( embed::StorageFormats::PACKAGE
) // package is the default format
166 , m_bAllowRemoveOnInsert( true )
167 , m_eMode ( e_IMode_None
)
168 , m_xContext(std::move( xContext
))
170 m_xRootFolder
= new ZipPackageFolder( m_xContext
, m_nFormat
, m_bAllowRemoveOnInsert
);
173 ZipPackage::~ZipPackage()
177 bool ZipPackage::isLocalFile() const
179 return comphelper::isFileUrl(m_aURL
);
182 // note: don't check for StorageFormats::ZIP, it breaks signing!
183 void ZipPackage::checkZipEntriesWithDD()
185 if (!m_bForceRecovery
)
187 ZipEnumeration entries
{m_pZipFile
->entries()};
188 while (entries
.hasMoreElements())
190 ZipEntry
const& rEntry
{*entries
.nextElement()};
191 if ((rEntry
.nFlag
& 0x08) != 0 && rEntry
.nMethod
== STORED
)
193 uno::Reference
<XPropertySet
> xStream
;
194 getByHierarchicalName(rEntry
.sPath
) >>= xStream
;
195 uno::Reference
<XServiceInfo
> const xStreamSI
{xStream
, uno::UNO_QUERY_THROW
};
196 if (!xStreamSI
->supportsService("com.sun.star.packages.PackageStream"))
198 SAL_INFO("package", "entry STORED with data descriptor is folder: \"" << rEntry
.sPath
<< "\"");
199 throw ZipIOException(
201 "entry STORED with data descriptor is folder");
203 if (!xStream
->getPropertyValue("WasEncrypted").get
<bool>())
205 SAL_INFO("package", "entry STORED with data descriptor but not encrypted: \"" << rEntry
.sPath
<< "\"");
206 throw ZipIOException(
208 "entry STORED with data descriptor but not encrypted");
215 void ZipPackage::parseManifest()
217 if ( m_nFormat
!= embed::StorageFormats::PACKAGE
)
220 bool bManifestParsed
= false;
221 ::std::optional
<OUString
> oFirstVersion
;
222 static constexpr OUString
sMeta (u
"META-INF"_ustr
);
223 if ( m_xRootFolder
->hasByName( sMeta
) )
226 static constexpr OUString
sManifest (u
"manifest.xml"_ustr
);
227 Any aAny
= m_xRootFolder
->getByName( sMeta
);
228 uno::Reference
< XNameContainer
> xMetaInfFolder
;
229 aAny
>>= xMetaInfFolder
;
230 if ( xMetaInfFolder
.is() && xMetaInfFolder
->hasByName( sManifest
) )
232 uno::Reference
< XActiveDataSink
> xSink
;
233 aAny
= xMetaInfFolder
->getByName( sManifest
);
237 uno::Reference
< XManifestReader
> xReader
= ManifestReader::create( m_xContext
);
239 const uno::Sequence
< uno::Sequence
< PropertyValue
> > aManifestSequence
= xReader
->readManifestSequence ( xSink
->getInputStream() );
240 const Any
*pKeyInfo
= nullptr;
242 for ( const uno::Sequence
<PropertyValue
>& rSequence
: aManifestSequence
)
244 OUString sPath
, sMediaType
, sVersion
;
245 const Any
*pSalt
= nullptr, *pVector
= nullptr, *pCount
= nullptr, *pSize
= nullptr, *pDigest
= nullptr, *pDigestAlg
= nullptr, *pEncryptionAlg
= nullptr, *pStartKeyAlg
= nullptr, *pDerivedKeySize
= nullptr;
246 uno::Any
const* pKDF
= nullptr;
247 uno::Any
const* pArgon2Args
= nullptr;
248 for ( const PropertyValue
& rValue
: rSequence
)
250 if ( rValue
.Name
== u
"FullPath" )
251 rValue
.Value
>>= sPath
;
252 else if ( rValue
.Name
== u
"Version" )
254 rValue
.Value
>>= sVersion
;
257 oFirstVersion
.emplace(sVersion
);
260 else if ( rValue
.Name
== u
"MediaType" )
261 rValue
.Value
>>= sMediaType
;
262 else if ( rValue
.Name
== u
"Salt" )
263 pSalt
= &( rValue
.Value
);
264 else if ( rValue
.Name
== u
"InitialisationVector" )
265 pVector
= &( rValue
.Value
);
266 else if ( rValue
.Name
== u
"IterationCount" )
267 pCount
= &( rValue
.Value
);
268 else if ( rValue
.Name
== u
"Size" )
269 pSize
= &( rValue
.Value
);
270 else if ( rValue
.Name
== u
"Digest" )
271 pDigest
= &( rValue
.Value
);
272 else if ( rValue
.Name
== u
"DigestAlgorithm" )
273 pDigestAlg
= &( rValue
.Value
);
274 else if ( rValue
.Name
== u
"EncryptionAlgorithm" )
275 pEncryptionAlg
= &( rValue
.Value
);
276 else if ( rValue
.Name
== u
"StartKeyAlgorithm" )
277 pStartKeyAlg
= &( rValue
.Value
);
278 else if ( rValue
.Name
== u
"DerivedKeySize" )
279 pDerivedKeySize
= &( rValue
.Value
);
280 else if ( rValue
.Name
== u
"KeyInfo" )
281 pKeyInfo
= &( rValue
.Value
);
282 else if (rValue
.Name
== u
"KeyDerivationFunction") {
283 pKDF
= &rValue
.Value
;
284 } else if (rValue
.Name
== u
"Argon2Args") {
285 pArgon2Args
= &rValue
.Value
;
289 if ( !sPath
.isEmpty() && hasByHierarchicalName ( sPath
) )
291 aAny
= getByHierarchicalName( sPath
);
292 uno::Reference
< XInterface
> xTmp
;
294 if (auto pFolder
= dynamic_cast<ZipPackageFolder
*>(xTmp
.get()))
296 pFolder
->SetMediaType ( sMediaType
);
297 pFolder
->SetVersion ( sVersion
);
299 else if (auto pStream
= dynamic_cast<ZipPackageStream
*>(xTmp
.get()))
301 pStream
->SetMediaType ( sMediaType
);
302 pStream
->SetFromManifest( true );
305 && pVector
&& pSize
&& pEncryptionAlg
306 && pKDF
&& pKDF
->has
<sal_Int32
>() && pKDF
->get
<sal_Int32
>() == xml::crypto::KDFID::PGP_RSA_OAEP_MGF1P
307 && ((pEncryptionAlg
->has
<sal_Int32
>()
308 && pEncryptionAlg
->get
<sal_Int32
>() == xml::crypto::CipherID::AES_GCM_W3C
)
309 || (pDigest
&& pDigestAlg
)))
311 uno::Sequence
< sal_Int8
> aSequence
;
313 ::std::optional
<sal_Int32
> oDigestAlg
;
314 sal_Int32 nEncryptionAlg
= 0;
316 pStream
->SetToBeEncrypted ( true );
318 *pVector
>>= aSequence
;
319 pStream
->setInitialisationVector ( aSequence
);
322 pStream
->setSize ( nSize
);
324 if (pDigest
&& pDigestAlg
)
326 *pDigest
>>= aSequence
;
327 pStream
->setDigest(aSequence
);
329 assert(pDigestAlg
->has
<sal_Int32
>());
330 oDigestAlg
.emplace(pDigestAlg
->get
<sal_Int32
>());
333 *pEncryptionAlg
>>= nEncryptionAlg
;
335 *pKeyInfo
>>= m_aGpgProps
;
337 pStream
->SetToBeCompressed ( true );
338 pStream
->SetToBeEncrypted ( true );
339 pStream
->SetIsEncrypted ( true );
340 pStream
->setIterationCount(::std::optional
<sal_Int32
>());
341 pStream
->setArgon2Args(::std::optional
<::std::tuple
<sal_Int32
, sal_Int32
, sal_Int32
>>());
343 // clamp to default SHA256 start key magic value,
344 // c.f. ZipPackageStream::GetEncryptionKey()
345 // trying to get key value from properties
346 const sal_Int32 nStartKeyAlg
= xml::crypto::DigestID::SHA256
;
348 pStream
->SetImportedAlgorithms({
349 .nImportedStartKeyAlgorithm
= nStartKeyAlg
,
350 .nImportedEncryptionAlgorithm
= nEncryptionAlg
,
351 .oImportedChecksumAlgorithm
= oDigestAlg
,
352 // note m_nCommonEncryptionID is not inited yet here
353 .nImportedDerivedKeySize
= ::GetDefaultDerivedKeySize(nEncryptionAlg
),
356 if (!m_bHasEncryptedEntries
357 && (pStream
->getName() == "content.xml"
358 || pStream
->getName() == "encrypted-package"))
360 m_bHasEncryptedEntries
= true;
361 m_oChecksumDigestID
= oDigestAlg
;
362 m_nKeyDerivationFunctionID
= xml::crypto::KDFID::PGP_RSA_OAEP_MGF1P
;
363 m_nCommonEncryptionID
= nEncryptionAlg
;
364 m_nStartKeyGenerationID
= nStartKeyAlg
;
368 && pVector
&& pSize
&& pEncryptionAlg
369 && pKDF
&& pKDF
->has
<sal_Int32
>()
370 && ((pKDF
->get
<sal_Int32
>() == xml::crypto::KDFID::PBKDF2
&& pCount
)
371 || (pKDF
->get
<sal_Int32
>() == xml::crypto::KDFID::Argon2id
&& pArgon2Args
))
372 && ((pEncryptionAlg
->has
<sal_Int32
>()
373 && pEncryptionAlg
->get
<sal_Int32
>() == xml::crypto::CipherID::AES_GCM_W3C
)
374 || (pDigest
&& pDigestAlg
)))
377 uno::Sequence
< sal_Int8
> aSequence
;
379 ::std::optional
<sal_Int32
> oDigestAlg
;
381 sal_Int32 nEncryptionAlg
= 0;
382 sal_Int32 nCount
= 0;
383 sal_Int32 nDerivedKeySize
= 16, nStartKeyAlg
= xml::crypto::DigestID::SHA1
;
385 pStream
->SetToBeEncrypted ( true );
387 *pSalt
>>= aSequence
;
388 pStream
->setSalt ( aSequence
);
390 *pVector
>>= aSequence
;
391 pStream
->setInitialisationVector ( aSequence
);
398 pStream
->setIterationCount(::std::optional
<sal_Int32
>(nCount
));
403 uno::Sequence
<sal_Int32
> args
;
404 *pArgon2Args
>>= args
;
405 assert(args
.getLength() == 3);
406 ::std::optional
<::std::tuple
<sal_Int32
, sal_Int32
, sal_Int32
>> oArgs
;
407 oArgs
.emplace(args
[0], args
[1], args
[2]);
408 pStream
->setArgon2Args(oArgs
);
412 pStream
->setSize ( nSize
);
414 if (pDigest
&& pDigestAlg
)
416 *pDigest
>>= aSequence
;
417 pStream
->setDigest(aSequence
);
419 assert(pDigestAlg
->has
<sal_Int32
>());
420 oDigestAlg
.emplace(pDigestAlg
->get
<sal_Int32
>());
423 *pEncryptionAlg
>>= nEncryptionAlg
;
425 if ( pDerivedKeySize
)
426 *pDerivedKeySize
>>= nDerivedKeySize
;
429 *pStartKeyAlg
>>= nStartKeyAlg
;
431 pStream
->SetImportedAlgorithms({
432 .nImportedStartKeyAlgorithm
= nStartKeyAlg
,
433 .nImportedEncryptionAlgorithm
= nEncryptionAlg
,
434 .oImportedChecksumAlgorithm
= oDigestAlg
,
435 .nImportedDerivedKeySize
= nDerivedKeySize
,
438 pStream
->SetToBeCompressed ( true );
439 pStream
->SetToBeEncrypted ( true );
440 pStream
->SetIsEncrypted ( true );
441 if (!m_bHasEncryptedEntries
442 && (pStream
->getName() == "content.xml"
443 || pStream
->getName() == "encrypted-package"))
445 m_bHasEncryptedEntries
= true;
446 m_nStartKeyGenerationID
= nStartKeyAlg
;
447 m_nKeyDerivationFunctionID
= nKDF
;
448 m_oChecksumDigestID
= oDigestAlg
;
449 m_nCommonEncryptionID
= nEncryptionAlg
;
453 m_bHasNonEncryptedEntries
= true;
456 throw ZipIOException(THROW_WHERE
"Wrong content");
460 bManifestParsed
= true;
463 checkZipEntriesWithDD(); // check before removing entries!
465 // now hide the manifest.xml file from user
466 xMetaInfFolder
->removeByName( sManifest
);
471 if ( !m_bForceRecovery
)
476 if ( !bManifestParsed
&& !m_bForceRecovery
)
477 throw ZipIOException(
478 THROW_WHERE
"Could not parse manifest.xml" );
480 static constexpr OUString
sMimetype (u
"mimetype"_ustr
);
481 if ( m_xRootFolder
->hasByName( sMimetype
) )
483 // get mediatype from the "mimetype" stream
484 OUString aPackageMediatype
;
485 uno::Reference
< io::XActiveDataSink
> xMimeSink
;
486 m_xRootFolder
->getByName( sMimetype
) >>= xMimeSink
;
487 if ( xMimeSink
.is() )
489 uno::Reference
< io::XInputStream
> xMimeInStream
= xMimeSink
->getInputStream();
490 if ( xMimeInStream
.is() )
492 // Mediatypes longer than 1024 symbols should not appear here
493 uno::Sequence
< sal_Int8
> aData( 1024 );
494 sal_Int32 nRead
= xMimeInStream
->readBytes( aData
, 1024 );
495 if ( nRead
> aData
.getLength() )
496 nRead
= aData
.getLength();
499 aPackageMediatype
= OUString( reinterpret_cast<char const *>(aData
.getConstArray()), nRead
, RTL_TEXTENCODING_ASCII_US
);
503 if (!bManifestParsed
|| m_xRootFolder
->GetMediaType().isEmpty())
505 // the manifest.xml could not be successfully parsed, this is an inconsistent package
506 if ( aPackageMediatype
.startsWith("application/vnd.") )
508 // accept only types that look similar to own mediatypes
509 m_xRootFolder
->SetMediaType( aPackageMediatype
);
510 // also set version explicitly
511 if (oFirstVersion
&& m_xRootFolder
->GetVersion().isEmpty())
513 m_xRootFolder
->SetVersion(*oFirstVersion
);
515 // if there is an encrypted inner package, there is no root
516 // document, because instead there is a package, and it is not
518 if (!m_xRootFolder
->hasByName(u
"encrypted-package"_ustr
))
520 m_bMediaTypeFallbackUsed
= true;
524 else if ( !m_bForceRecovery
)
526 // the mimetype stream should contain the same information as manifest.xml
527 OUString
const mediaTypeXML(m_xRootFolder
->hasByName(u
"encrypted-package"_ustr
)
528 ? m_xRootFolder
->doGetByName(u
"encrypted-package"_ustr
).xPackageEntry
->GetMediaType()
529 : m_xRootFolder
->GetMediaType());
530 if (mediaTypeXML
!= aPackageMediatype
)
532 throw ZipIOException(
534 "mimetype conflicts with manifest.xml, \""
535 + mediaTypeXML
+ "\" vs. \""
536 + aPackageMediatype
+ "\"" );
540 m_xRootFolder
->removeByName( sMimetype
);
543 m_bInconsistent
= m_xRootFolder
->LookForUnexpectedODF12Streams(
544 std::u16string_view(), m_xRootFolder
->hasByName(u
"encrypted-package"_ustr
));
546 bool bODF12AndNewer
= ( m_xRootFolder
->GetVersion().compareTo( ODFVER_012_TEXT
) >= 0 );
547 if ( !m_bForceRecovery
&& bODF12AndNewer
)
549 if ( m_bInconsistent
)
551 // this is an ODF1.2 document that contains streams not referred in the manifest.xml;
552 // in case of ODF1.2 documents without version in manifest.xml the property IsInconsistent
553 // should be checked later
554 throw ZipIOException(
555 THROW_WHERE
"there are streams not referred in manifest.xml" );
557 // all the streams should be encrypted with the same StartKey in ODF1.2
558 // TODO/LATER: in future the exception should be thrown
559 // throw ZipIOException( THROW_WHERE "More than one Start Key Generation algorithm is specified!" );
562 // in case it is a correct ODF1.2 document, the version must be set
563 // and the META-INF folder is reserved for package format
564 if ( bODF12AndNewer
)
565 m_xRootFolder
->removeByName( sMeta
);
568 void ZipPackage::parseContentType()
570 if ( m_nFormat
!= embed::StorageFormats::OFOPXML
)
574 static constexpr OUString
aContentTypes(u
"[Content_Types].xml"_ustr
);
575 // the content type must exist in OFOPXML format!
576 if ( !m_xRootFolder
->hasByName( aContentTypes
) )
577 throw io::IOException(THROW_WHERE
"Wrong format!" );
579 uno::Reference
< io::XActiveDataSink
> xSink
;
580 uno::Any aAny
= m_xRootFolder
->getByName( aContentTypes
);
584 uno::Reference
< io::XInputStream
> xInStream
= xSink
->getInputStream();
585 if ( xInStream
.is() )
587 // here aContentTypeInfo[0] - Defaults, and aContentTypeInfo[1] - Overrides
588 const uno::Sequence
< uno::Sequence
< beans::StringPair
> > aContentTypeInfo
=
589 ::comphelper::OFOPXMLHelper::ReadContentTypeSequence( xInStream
, m_xContext
);
591 if ( aContentTypeInfo
.getLength() != 2 )
592 throw io::IOException(THROW_WHERE
);
594 // set the implicit types first
595 for ( const auto& rPair
: aContentTypeInfo
[0] )
596 m_xRootFolder
->setChildStreamsTypeByExtension( rPair
);
598 // now set the explicit types
599 for ( const auto& rPair
: aContentTypeInfo
[1] )
602 if ( rPair
.First
.toChar() == '/' )
603 aPath
= rPair
.First
.copy( 1 );
607 if ( !aPath
.isEmpty() && hasByHierarchicalName( aPath
) )
609 uno::Any aIterAny
= getByHierarchicalName( aPath
);
610 uno::Reference
< XInterface
> xIterTmp
;
611 aIterAny
>>= xIterTmp
;
612 if (auto pStream
= dynamic_cast<ZipPackageStream
*>(xIterTmp
.get()))
614 // this is a package stream, in OFOPXML format only streams can have mediatype
615 pStream
->SetMediaType( rPair
.Second
);
622 m_xRootFolder
->removeByName( aContentTypes
);
624 catch( uno::Exception
& )
626 if ( !m_bForceRecovery
)
631 void ZipPackage::getZipFileContents()
633 ZipEnumeration aEnum
= m_pZipFile
->entries();
636 while (aEnum
.hasMoreElements())
638 ZipPackageFolder
* pCurrent
= m_xRootFolder
.get();
639 const ZipEntry
& rEntry
= *aEnum
.nextElement();
640 OUString rName
= rEntry
.sPath
;
642 if ( m_bForceRecovery
)
644 // the PKZIP Application note version 6.2 does not allows to use '\' as separator
645 // unfortunately it is used by some implementations, so we have to support it in recovery mode
646 rName
= rName
.replace( '\\', '/' );
649 sal_Int32 nStreamIndex
= rName
.lastIndexOf ( '/' );
650 if ( nStreamIndex
!= -1 )
652 sDirName
= rName
.copy ( 0, nStreamIndex
);
653 FolderHash::iterator aIter
= m_aRecent
.find ( sDirName
);
654 if ( aIter
!= m_aRecent
.end() )
655 pCurrent
= ( *aIter
).second
;
658 if ( pCurrent
== m_xRootFolder
.get() )
661 sal_Int32 nOldIndex
= 0;
662 while ( ( nIndex
= rName
.indexOf( '/', nOldIndex
) ) != -1 )
664 OUString sTemp
= rName
.copy ( nOldIndex
, nIndex
- nOldIndex
);
665 if ( nIndex
== nOldIndex
)
667 if ( !pCurrent
->hasByName( sTemp
) )
669 rtl::Reference
<ZipPackageFolder
> pPkgFolder
= new ZipPackageFolder(m_xContext
, m_nFormat
, m_bAllowRemoveOnInsert
);
671 pPkgFolder
->setName( sTemp
);
672 } catch (uno::RuntimeException
const& e
) {
673 throw css::packages::zip::ZipIOException(e
.Message
);
675 pPkgFolder
->doSetParent( pCurrent
);
676 pCurrent
= pPkgFolder
.get();
680 ZipContentInfo
& rInfo
= pCurrent
->doGetByName(sTemp
);
682 throw css::packages::zip::ZipIOException(u
"Bad Zip File, stream as folder"_ustr
);
683 pCurrent
= rInfo
.pFolder
;
685 nOldIndex
= nIndex
+1;
687 if ( nStreamIndex
!= -1 && !sDirName
.isEmpty() )
688 m_aRecent
[ sDirName
] = pCurrent
;
690 if ( rName
.getLength() -1 != nStreamIndex
)
693 OUString sTemp
= rName
.copy( nStreamIndex
);
695 if (!pCurrent
->hasByName(sTemp
))
697 rtl::Reference
<ZipPackageStream
> pPkgStream
= new ZipPackageStream(*this, m_xContext
, m_nFormat
, m_bAllowRemoveOnInsert
);
698 pPkgStream
->SetPackageMember(true);
699 pPkgStream
->setZipEntryOnLoading(rEntry
);
700 pPkgStream
->setName(sTemp
);
701 pPkgStream
->doSetParent(pCurrent
);
706 if ( m_nFormat
== embed::StorageFormats::PACKAGE
)
708 else if ( m_nFormat
== embed::StorageFormats::OFOPXML
)
711 checkZipEntriesWithDD();
715 void SAL_CALL
ZipPackage::initialize( const uno::Sequence
< Any
>& aArguments
)
717 beans::NamedValue aNamedValue
;
719 if ( !aArguments
.hasElements() )
722 bool bHaveZipFile
= true;
724 for( const auto& rArgument
: aArguments
)
727 if ( rArgument
>>= aParamUrl
)
729 m_eMode
= e_IMode_URL
;
732 sal_Int32 nParam
= aParamUrl
.indexOf( '?' );
735 m_aURL
= aParamUrl
.copy( 0, nParam
);
736 std::u16string_view aParam
= aParamUrl
.subView( nParam
+ 1 );
738 sal_Int32 nIndex
= 0;
741 std::u16string_view aCommand
= o3tl::getToken(aParam
, 0, '&', nIndex
);
742 if ( aCommand
== u
"repairpackage" )
744 m_bForceRecovery
= true;
747 else if ( aCommand
== u
"purezip" )
749 m_nFormat
= embed::StorageFormats::ZIP
;
750 m_xRootFolder
->setPackageFormat_Impl( m_nFormat
);
753 else if ( aCommand
== u
"ofopxml" )
755 m_nFormat
= embed::StorageFormats::OFOPXML
;
756 m_xRootFolder
->setPackageFormat_Impl( m_nFormat
);
760 while ( nIndex
>= 0 );
766 m_aURL
, uno::Reference
< XCommandEnvironment
>(),
768 Any aAny
= aContent
.getPropertyValue(u
"Size"_ustr
);
769 sal_uInt64 aSize
= 0;
770 // kind of optimization: treat empty files as nonexistent files
771 // and write to such files directly. Note that "Size" property is optional.
772 bool bHasSizeProperty
= aAny
>>= aSize
;
773 if( !bHasSizeProperty
|| aSize
)
775 uno::Reference
< XActiveDataSink
> xSink
= new ZipPackageSink
;
776 if ( aContent
.openStream ( xSink
) )
777 m_xContentStream
= xSink
->getInputStream();
780 bHaveZipFile
= false;
782 catch ( css::uno::Exception
& )
784 // Exception derived from uno::Exception thrown. This probably
785 // means the file doesn't exist...we'll create it at
786 // commitChanges time
787 bHaveZipFile
= false;
790 else if ( rArgument
>>= m_xStream
)
792 // a writable stream can implement both XStream & XInputStream
793 m_eMode
= e_IMode_XStream
;
794 m_xContentStream
= m_xStream
->getInputStream();
796 else if ( rArgument
>>= m_xContentStream
)
798 m_eMode
= e_IMode_XInputStream
;
800 else if ( rArgument
>>= aNamedValue
)
802 if ( aNamedValue
.Name
== "RepairPackage" )
803 aNamedValue
.Value
>>= m_bForceRecovery
;
804 else if ( aNamedValue
.Name
== "PackageFormat" )
806 // setting this argument to true means Package format
807 // setting it to false means plain Zip format
809 bool bPackFormat
= true;
810 aNamedValue
.Value
>>= bPackFormat
;
812 m_nFormat
= embed::StorageFormats::ZIP
;
814 m_xRootFolder
->setPackageFormat_Impl( m_nFormat
);
816 else if ( aNamedValue
.Name
== "StorageFormat" )
818 OUString aFormatName
;
819 sal_Int32 nFormatID
= 0;
820 if ( aNamedValue
.Value
>>= aFormatName
)
822 if ( aFormatName
== PACKAGE_STORAGE_FORMAT_STRING
)
823 m_nFormat
= embed::StorageFormats::PACKAGE
;
824 else if ( aFormatName
== ZIP_STORAGE_FORMAT_STRING
)
825 m_nFormat
= embed::StorageFormats::ZIP
;
826 else if ( aFormatName
== OFOPXML_STORAGE_FORMAT_STRING
)
827 m_nFormat
= embed::StorageFormats::OFOPXML
;
829 throw lang::IllegalArgumentException(THROW_WHERE
, uno::Reference
< uno::XInterface
>(), 1 );
831 else if ( aNamedValue
.Value
>>= nFormatID
)
833 if (nFormatID
!= embed::StorageFormats::PACKAGE
834 && nFormatID
!= embed::StorageFormats::ZIP
835 && nFormatID
!= embed::StorageFormats::OFOPXML
)
836 throw lang::IllegalArgumentException(THROW_WHERE
, uno::Reference
< uno::XInterface
>(), 1 );
838 m_nFormat
= nFormatID
;
841 throw lang::IllegalArgumentException(THROW_WHERE
, uno::Reference
< uno::XInterface
>(), 1 );
843 m_xRootFolder
->setPackageFormat_Impl( m_nFormat
);
845 else if ( aNamedValue
.Name
== "AllowRemoveOnInsert" )
847 aNamedValue
.Value
>>= m_bAllowRemoveOnInsert
;
848 m_xRootFolder
->setRemoveOnInsertMode_Impl( m_bAllowRemoveOnInsert
);
850 else if (aNamedValue
.Name
== "NoFileSync")
851 aNamedValue
.Value
>>= m_bDisableFileSync
;
853 // for now the progress handler is not used, probably it will never be
854 // if ( aNamedValue.Name == "ProgressHandler" )
858 // The URL is not acceptable
859 throw css::uno::Exception (THROW_WHERE
"Bad arguments.",
866 if ( m_xContentStream
.is() )
868 // the stream must be seekable, if it is not it will be wrapped
869 m_xContentStream
= ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( m_xContentStream
, m_xContext
);
870 m_xContentSeek
.set( m_xContentStream
, UNO_QUERY_THROW
);
871 if ( !m_xContentSeek
->getLength() )
872 bHaveZipFile
= false;
875 bHaveZipFile
= false;
877 catch ( css::uno::Exception
& )
879 // Exception derived from uno::Exception thrown. This probably
880 // means the file doesn't exist...we'll create it at
881 // commitChanges time
882 bHaveZipFile
= false;
887 bool bBadZipFile
= false;
891 m_pZipFile
.emplace(m_aMutexHolder
, m_xContentStream
, m_xContext
, true,
893 m_nFormat
== embed::StorageFormats::ZIP
894 ? ZipFile::Checks::Default
895 : m_nFormat
== embed::StorageFormats::OFOPXML
896 ? ZipFile::Checks::CheckInsensitive
897 : ZipFile::Checks::TryCheckInsensitive
);
898 getZipFileContents();
900 catch ( IOException
& e
)
903 message
= "IOException: " + e
.Message
;
905 catch ( ZipException
& e
)
908 message
= "ZipException: " + e
.Message
;
910 catch ( Exception
& )
918 // clean up the memory, and tell the UCB about the error
921 throw css::packages::zip::ZipIOException (
922 THROW_WHERE
"Bad Zip File, " + message
,
927 Any SAL_CALL
ZipPackage::getByHierarchicalName( const OUString
& aName
)
930 sal_Int32 nOldIndex
, nStreamIndex
;
934 return Any ( uno::Reference( cppu::getXWeak(m_xRootFolder
.get()) ) );
936 sal_Int32 nIndex
= aName
.getLength();
938 nStreamIndex
= aName
.lastIndexOf ( '/' );
939 bool bFolder
= nStreamIndex
== nIndex
-1; // last character is '/'.
941 if ( nStreamIndex
!= -1 )
943 // The name contains '/'.
944 sDirName
= aName
.copy ( 0, nStreamIndex
);
945 FolderHash::iterator aIter
= m_aRecent
.find ( sDirName
);
946 if ( aIter
!= m_aRecent
.end() )
948 // There is a cached entry for this name.
950 ZipPackageFolder
* pFolder
= aIter
->second
;
954 // Determine the directory name.
955 sal_Int32 nDirIndex
= aName
.lastIndexOf ( '/', nStreamIndex
);
956 std::u16string_view sTemp
= aName
.subView ( nDirIndex
== -1 ? 0 : nDirIndex
+1, nStreamIndex
-nDirIndex
-1 );
958 if (pFolder
&& sTemp
== pFolder
->getName())
959 return Any(uno::Reference(cppu::getXWeak(pFolder
)));
963 // Determine the file name.
964 OUString sTemp
= aName
.copy ( nStreamIndex
+ 1 );
966 if (pFolder
&& pFolder
->hasByName(sTemp
))
967 return pFolder
->getByName(sTemp
);
970 m_aRecent
.erase( aIter
);
973 else if ( m_xRootFolder
->hasByName ( aName
) )
974 // top-level element.
975 return m_xRootFolder
->getByName ( aName
);
977 // Not in the cache. Search normally.
980 ZipPackageFolder
* pCurrent
= m_xRootFolder
.get();
981 ZipPackageFolder
* pPrevious
= nullptr;
983 // Find the right directory for the given path.
985 while ( ( nIndex
= aName
.indexOf( '/', nOldIndex
)) != -1 )
987 OUString sTemp
= aName
.copy ( nOldIndex
, nIndex
- nOldIndex
);
988 if ( nIndex
== nOldIndex
)
990 if ( !pCurrent
->hasByName( sTemp
) )
991 throw NoSuchElementException(THROW_WHERE
);
993 pPrevious
= pCurrent
;
994 ZipContentInfo
& rInfo
= pCurrent
->doGetByName(sTemp
);
996 throw css::packages::zip::ZipIOException(u
"Bad Zip File, stream as folder"_ustr
);
997 pCurrent
= rInfo
.pFolder
;
998 nOldIndex
= nIndex
+1;
1003 if ( nStreamIndex
!= -1 )
1004 m_aRecent
[sDirName
] = pPrevious
; // cache it.
1005 return Any ( uno::Reference( cppu::getXWeak(pCurrent
) ) );
1008 OUString sTemp
= aName
.copy( nOldIndex
);
1010 if ( pCurrent
->hasByName ( sTemp
) )
1012 if ( nStreamIndex
!= -1 )
1013 m_aRecent
[sDirName
] = pCurrent
; // cache it.
1014 return pCurrent
->getByName( sTemp
);
1017 throw NoSuchElementException(THROW_WHERE
);
1020 sal_Bool SAL_CALL
ZipPackage::hasByHierarchicalName( const OUString
& aName
)
1029 sal_Int32 nStreamIndex
;
1030 nStreamIndex
= aName
.lastIndexOf ( '/' );
1031 bool bFolder
= nStreamIndex
== aName
.getLength()-1;
1032 if ( nStreamIndex
!= -1 )
1034 sDirName
= aName
.copy ( 0, nStreamIndex
);
1035 FolderHash::iterator aIter
= m_aRecent
.find ( sDirName
);
1036 if ( aIter
!= m_aRecent
.end() )
1040 sal_Int32 nDirIndex
= aName
.lastIndexOf ( '/', nStreamIndex
);
1041 std::u16string_view sTemp
= aName
.subView ( nDirIndex
== -1 ? 0 : nDirIndex
+1, nStreamIndex
-nDirIndex
-1 );
1042 if ( sTemp
== ( *aIter
).second
->getName() )
1045 m_aRecent
.erase ( aIter
);
1049 OUString sTemp
= aName
.copy ( nStreamIndex
+ 1 );
1050 if ( ( *aIter
).second
->hasByName( sTemp
) )
1053 m_aRecent
.erase( aIter
);
1059 if ( m_xRootFolder
->hasByName ( aName
) )
1062 ZipPackageFolder
* pCurrent
= m_xRootFolder
.get();
1063 ZipPackageFolder
* pPrevious
= nullptr;
1064 sal_Int32 nOldIndex
= 0;
1066 while ( ( nIndex
= aName
.indexOf( '/', nOldIndex
)) != -1 )
1068 if ( nIndex
== nOldIndex
)
1071 OUString sTemp
= aName
.copy ( nOldIndex
, nIndex
- nOldIndex
);
1073 if ( pCurrent
->hasByName( sTemp
) )
1075 pPrevious
= pCurrent
;
1076 ZipContentInfo
& rInfo
= pCurrent
->doGetByName(sTemp
);
1078 throw css::packages::zip::ZipIOException(u
"Bad Zip File, stream as folder"_ustr
);
1079 pCurrent
= rInfo
.pFolder
;
1083 nOldIndex
= nIndex
+1;
1087 m_aRecent
[sDirName
] = pPrevious
;
1092 OUString sTemp
= aName
.copy( nOldIndex
);
1094 if ( pCurrent
->hasByName( sTemp
) )
1096 m_aRecent
[sDirName
] = pCurrent
;
1101 catch (const uno::RuntimeException
&)
1105 catch (const uno::Exception
&)
1107 uno::Any
e(::cppu::getCaughtException());
1108 throw lang::WrappedTargetRuntimeException(u
"ZipPackage::hasByHierarchicalName"_ustr
, nullptr, e
);
1113 uno::Reference
< XInterface
> SAL_CALL
ZipPackage::createInstance()
1115 uno::Reference
< XInterface
> xRef
= *( new ZipPackageStream( *this, m_xContext
, m_nFormat
, m_bAllowRemoveOnInsert
) );
1119 uno::Reference
< XInterface
> SAL_CALL
ZipPackage::createInstanceWithArguments( const uno::Sequence
< Any
>& aArguments
)
1122 uno::Reference
< XInterface
> xRef
;
1123 if ( aArguments
.hasElements() )
1124 aArguments
[0] >>= bArg
;
1126 xRef
= *new ZipPackageFolder( m_xContext
, m_nFormat
, m_bAllowRemoveOnInsert
);
1128 xRef
= *new ZipPackageStream( *this, m_xContext
, m_nFormat
, m_bAllowRemoveOnInsert
);
1133 void ZipPackage::WriteMimetypeMagicFile( ZipOutputStream
& aZipOut
)
1135 static constexpr OUString
sMime (u
"mimetype"_ustr
);
1136 if ( m_xRootFolder
->hasByName( sMime
) )
1137 m_xRootFolder
->removeByName( sMime
);
1139 auto pEntry
= std::make_unique
<ZipEntry
>();
1140 sal_Int32 nBufferLength
= m_xRootFolder
->GetMediaType().getLength();
1141 OString sMediaType
= OUStringToOString( m_xRootFolder
->GetMediaType(), RTL_TEXTENCODING_ASCII_US
);
1142 const uno::Sequence
< sal_Int8
> aType( reinterpret_cast<sal_Int8
const *>(sMediaType
.getStr()),
1145 pEntry
->sPath
= sMime
;
1146 pEntry
->nMethod
= STORED
;
1147 pEntry
->nSize
= pEntry
->nCompressedSize
= nBufferLength
;
1148 pEntry
->nTime
= ZipOutputStream::getCurrentDosTime();
1151 aCRC32
.update( aType
);
1152 pEntry
->nCrc
= aCRC32
.getValue();
1156 ZipOutputStream::setEntry(*pEntry
);
1157 aZipOut
.writeLOC(std::move(pEntry
));
1158 aZipOut
.rawWrite(aType
);
1159 aZipOut
.rawCloseEntry();
1161 catch ( const css::io::IOException
& )
1163 css::uno::Any anyEx
= cppu::getCaughtException();
1164 throw WrappedTargetException(
1165 THROW_WHERE
"Error adding mimetype to the ZipOutputStream!",
1171 void ZipPackage::WriteManifest( ZipOutputStream
& aZipOut
, const std::vector
< uno::Sequence
< PropertyValue
> >& aManList
)
1173 // Write the manifest
1174 uno::Reference
< XManifestWriter
> xWriter
= ManifestWriter::create( m_xContext
);
1175 auto pEntry
= std::make_unique
<ZipEntry
>();
1176 rtl::Reference
<ZipPackageBuffer
> pBuffer
= new ZipPackageBuffer
;
1178 pEntry
->sPath
= "META-INF/manifest.xml";
1179 pEntry
->nMethod
= DEFLATED
;
1181 pEntry
->nSize
= pEntry
->nCompressedSize
= -1;
1182 pEntry
->nTime
= ZipOutputStream::getCurrentDosTime();
1184 xWriter
->writeManifestSequence ( pBuffer
, comphelper::containerToSequence(aManList
) );
1186 sal_Int32 nBufferLength
= static_cast < sal_Int32
> ( pBuffer
->getPosition() );
1187 pBuffer
->realloc( nBufferLength
);
1189 // the manifest.xml is never encrypted - so pass an empty reference
1190 ZipOutputStream::setEntry(*pEntry
);
1191 auto p
= pEntry
.get();
1192 aZipOut
.writeLOC(std::move(pEntry
));
1193 ZipOutputEntry
aZipEntry(aZipOut
.getStream(), m_xContext
, p
, nullptr, /*bEncrypt*/false);
1194 aZipEntry
.write(pBuffer
->getSequence());
1195 aZipEntry
.closeEntry();
1196 aZipOut
.rawCloseEntry();
1199 void ZipPackage::WriteContentTypes( ZipOutputStream
& aZipOut
, const std::vector
< uno::Sequence
< PropertyValue
> >& aManList
)
1201 auto pEntry
= std::make_unique
<ZipEntry
>();
1202 rtl::Reference
<ZipPackageBuffer
> pBuffer
= new ZipPackageBuffer
;
1204 pEntry
->sPath
= "[Content_Types].xml";
1205 pEntry
->nMethod
= DEFLATED
;
1207 pEntry
->nSize
= pEntry
->nCompressedSize
= -1;
1208 pEntry
->nTime
= ZipOutputStream::getCurrentDosTime();
1210 // Add default entries, the count must be updated manually when appending.
1211 // Add at least the standard default entries.
1212 uno::Sequence
< beans::StringPair
> aDefaultsSequence
1214 { u
"xml"_ustr
, u
"application/xml"_ustr
},
1215 { u
"rels"_ustr
, u
"application/vnd.openxmlformats-package.relationships+xml"_ustr
},
1216 { u
"png"_ustr
, u
"image/png"_ustr
},
1217 { u
"jpeg"_ustr
, u
"image/jpeg"_ustr
}
1220 uno::Sequence
< beans::StringPair
> aOverridesSequence(aManList
.size());
1221 auto aOverridesSequenceRange
= asNonConstRange(aOverridesSequence
);
1222 sal_Int32 nOverSeqLength
= 0;
1223 for (const auto& rMan
: aManList
)
1226 OSL_ENSURE( rMan
[PKG_MNFST_MEDIATYPE
].Name
== "MediaType" && rMan
[PKG_MNFST_FULLPATH
].Name
== "FullPath",
1227 "The mediatype sequence format is wrong!" );
1228 rMan
[PKG_MNFST_MEDIATYPE
].Value
>>= aType
;
1229 if ( !aType
.isEmpty() )
1232 // only nonempty type makes sense here
1233 rMan
[PKG_MNFST_FULLPATH
].Value
>>= aPath
;
1234 //FIXME: For now we have no way of differentiating defaults from others.
1235 aOverridesSequenceRange
[nOverSeqLength
].First
= "/" + aPath
;
1236 aOverridesSequenceRange
[nOverSeqLength
].Second
= aType
;
1240 aOverridesSequence
.realloc(nOverSeqLength
);
1242 ::comphelper::OFOPXMLHelper::WriteContentSequence(
1243 pBuffer
, aDefaultsSequence
, aOverridesSequence
, m_xContext
);
1245 sal_Int32 nBufferLength
= static_cast < sal_Int32
> ( pBuffer
->getPosition() );
1246 pBuffer
->realloc( nBufferLength
);
1248 // there is no encryption in this format currently
1249 ZipOutputStream::setEntry(*pEntry
);
1250 auto p
= pEntry
.get();
1251 aZipOut
.writeLOC(std::move(pEntry
));
1252 ZipOutputEntry
aZipEntry(aZipOut
.getStream(), m_xContext
, p
, nullptr, /*bEncrypt*/false);
1253 aZipEntry
.write(pBuffer
->getSequence());
1254 aZipEntry
.closeEntry();
1255 aZipOut
.rawCloseEntry();
1258 void ZipPackage::ConnectTo( const uno::Reference
< io::XInputStream
>& xInStream
)
1260 assert(dynamic_cast<comphelper::ByteReader
*>(xInStream
.get()));
1261 m_xContentSeek
.set( xInStream
, uno::UNO_QUERY_THROW
);
1262 m_xContentStream
= xInStream
;
1264 // seek back to the beginning of the temp file so we can read segments from it
1265 m_xContentSeek
->seek( 0 );
1267 m_pZipFile
->setInputStream( m_xContentStream
);
1269 m_pZipFile
.emplace(m_aMutexHolder
, m_xContentStream
, m_xContext
, false,
1271 m_nFormat
== embed::StorageFormats::ZIP
1272 ? ZipFile::Checks::Default
1273 : m_nFormat
== embed::StorageFormats::OFOPXML
1274 ? ZipFile::Checks::CheckInsensitive
1275 : ZipFile::Checks::TryCheckInsensitive
);
1278 uno::Reference
< io::XInputStream
> ZipPackage::writeTempFile()
1280 // In case the target local file does not exist or empty
1281 // write directly to it otherwise create a temporary file to write to.
1282 // If a temporary file is created it is returned back by the method.
1283 // If the data written directly, xComponentStream will be switched here
1285 bool bUseTemp
= true;
1286 uno::Reference
< io::XInputStream
> xResult
;
1287 uno::Reference
< io::XInputStream
> xTempIn
;
1289 uno::Reference
< io::XOutputStream
> xTempOut
;
1290 uno::Reference
< io::XActiveDataStreamer
> xSink
;
1292 if ( m_eMode
== e_IMode_URL
&& !m_pZipFile
&& isLocalFile() )
1294 xSink
= openOriginalForOutput();
1297 uno::Reference
< io::XStream
> xStr
= xSink
->getStream();
1300 xTempOut
= xStr
->getOutputStream();
1306 else if ( m_eMode
== e_IMode_XStream
&& !m_pZipFile
)
1308 // write directly to an empty stream
1309 xTempOut
= m_xStream
->getOutputStream();
1316 // create temporary file
1317 rtl::Reference
< utl::TempFileFastService
> xTempFile( new utl::TempFileFastService
);
1318 xTempOut
.set( xTempFile
);
1319 xTempIn
.set( xTempFile
);
1322 // Hand it to the ZipOutputStream:
1323 ZipOutputStream
aZipOut( xTempOut
);
1326 if ( m_nFormat
== embed::StorageFormats::PACKAGE
)
1328 // Remove the old manifest.xml file as the
1329 // manifest will be re-generated and the
1330 // META-INF directory implicitly created if does not exist
1331 static constexpr OUString
sMeta (u
"META-INF"_ustr
);
1333 if ( m_xRootFolder
->hasByName( sMeta
) )
1335 static constexpr OUString
sManifest (u
"manifest.xml"_ustr
);
1337 uno::Reference
< XNameContainer
> xMetaInfFolder
;
1338 Any aAny
= m_xRootFolder
->getByName( sMeta
);
1339 aAny
>>= xMetaInfFolder
;
1340 if ( xMetaInfFolder
.is() && xMetaInfFolder
->hasByName( sManifest
) )
1341 xMetaInfFolder
->removeByName( sManifest
);
1344 // Write a magic file with mimetype
1345 WriteMimetypeMagicFile( aZipOut
);
1347 else if ( m_nFormat
== embed::StorageFormats::OFOPXML
)
1349 // Remove the old [Content_Types].xml file as the
1350 // file will be re-generated
1352 static constexpr OUString
aContentTypes(u
"[Content_Types].xml"_ustr
);
1354 if ( m_xRootFolder
->hasByName( aContentTypes
) )
1355 m_xRootFolder
->removeByName( aContentTypes
);
1358 // Create a vector to store data for the manifest.xml file
1359 std::vector
< uno::Sequence
< PropertyValue
> > aManList
;
1361 static constexpr OUStringLiteral
sMediaType(u
"MediaType");
1362 static constexpr OUStringLiteral
sVersion(u
"Version");
1363 static constexpr OUStringLiteral
sFullPath(u
"FullPath");
1364 const bool bIsGpgEncrypt
= m_aGpgProps
.hasElements();
1366 // note: this is always created here (needed for GPG), possibly
1367 // filtered out later in ManifestExport
1368 if ( m_nFormat
== embed::StorageFormats::PACKAGE
)
1370 uno::Sequence
< PropertyValue
> aPropSeq(
1371 bIsGpgEncrypt
? PKG_SIZE_NOENCR_MNFST
+1 : PKG_SIZE_NOENCR_MNFST
);
1372 auto pPropSeq
= aPropSeq
.getArray();
1373 pPropSeq
[PKG_MNFST_MEDIATYPE
].Name
= sMediaType
;
1374 pPropSeq
[PKG_MNFST_MEDIATYPE
].Value
<<= m_xRootFolder
->GetMediaType();
1375 pPropSeq
[PKG_MNFST_VERSION
].Name
= sVersion
;
1376 pPropSeq
[PKG_MNFST_VERSION
].Value
<<= m_xRootFolder
->GetVersion();
1377 pPropSeq
[PKG_MNFST_FULLPATH
].Name
= sFullPath
;
1378 pPropSeq
[PKG_MNFST_FULLPATH
].Value
<<= u
"/"_ustr
;
1382 pPropSeq
[PKG_SIZE_NOENCR_MNFST
].Name
= "KeyInfo";
1383 pPropSeq
[PKG_SIZE_NOENCR_MNFST
].Value
<<= m_aGpgProps
;
1385 aManList
.push_back( aPropSeq
);
1389 ::std::optional
<sal_Int32
> oPBKDF2IterationCount
;
1390 ::std::optional
<::std::tuple
<sal_Int32
, sal_Int32
, sal_Int32
>> oArgon2Args
;
1394 if (m_nKeyDerivationFunctionID
== xml::crypto::KDFID::PBKDF2
)
1395 { // if there is only one KDF invocation, increase the safety margin
1396 oPBKDF2IterationCount
.emplace(m_xRootFolder
->hasByName(u
"encrypted-package"_ustr
) ? 600000 : 100000);
1400 assert(m_nKeyDerivationFunctionID
== xml::crypto::KDFID::Argon2id
);
1401 oArgon2Args
.emplace(3, (1<<16), 4);
1405 // call saveContents - it will recursively save sub-directories
1406 m_xRootFolder
->saveContents(u
""_ustr
, aManList
, aZipOut
, GetEncryptionKey(),
1407 oPBKDF2IterationCount
, oArgon2Args
);
1410 if( m_nFormat
== embed::StorageFormats::PACKAGE
)
1412 WriteManifest( aZipOut
, aManList
);
1414 else if( m_nFormat
== embed::StorageFormats::OFOPXML
)
1416 WriteContentTypes( aZipOut
, aManList
);
1422 xResult
= std::move(xTempIn
);
1424 // Update our References to point to the new temp file
1427 // the case when the original contents were written directly
1430 // in case the stream is based on a file it will implement the following interface
1431 // the call should be used to be sure that the contents are written to the file system
1432 uno::Reference
< io::XAsyncOutputMonitor
> asyncOutputMonitor( xTempOut
, uno::UNO_QUERY
);
1433 if (asyncOutputMonitor
.is() && !m_bDisableFileSync
)
1434 asyncOutputMonitor
->waitForCompletion();
1436 // no need to postpone switching to the new stream since the target was written directly
1437 uno::Reference
< io::XInputStream
> xNewStream
;
1438 if ( m_eMode
== e_IMode_URL
)
1439 xNewStream
= xSink
->getStream()->getInputStream();
1440 else if ( m_eMode
== e_IMode_XStream
&& m_xStream
.is() )
1441 xNewStream
= m_xStream
->getInputStream();
1443 if ( xNewStream
.is() )
1444 ConnectTo( xNewStream
);
1447 catch ( uno::Exception
& )
1451 // no information loss appears, thus no special handling is required
1452 uno::Any
aCaught( ::cppu::getCaughtException() );
1454 // it is allowed to throw WrappedTargetException
1455 WrappedTargetException aException
;
1456 if ( aCaught
>>= aException
)
1459 throw WrappedTargetException(
1460 THROW_WHERE
"Problem writing the original content!",
1466 // the document is written directly, although it was empty it is important to notify that the writing has failed
1467 // TODO/LATER: let the package be able to recover in this situation
1468 OUString
aErrTxt(THROW_WHERE
"This package is unusable!");
1469 embed::UseBackupException
aException( aErrTxt
, uno::Reference
< uno::XInterface
>(), OUString() );
1470 throw WrappedTargetException( aErrTxt
,
1472 Any ( aException
) );
1479 uno::Reference
< XActiveDataStreamer
> ZipPackage::openOriginalForOutput()
1481 // open and truncate the original file
1482 Content
aOriginalContent(
1483 m_aURL
, uno::Reference
< XCommandEnvironment
>(),
1485 uno::Reference
< XActiveDataStreamer
> xSink
= new ActiveDataStreamer
;
1487 if ( m_eMode
== e_IMode_URL
)
1491 bool bTruncSuccess
= false;
1496 Any aAny
= aOriginalContent
.setPropertyValue(u
"Size"_ustr
, Any( sal_Int64(0) ) );
1497 if( !( aAny
>>= aDetect
) )
1498 bTruncSuccess
= true;
1504 if( !bTruncSuccess
)
1506 // the file is not accessible
1507 // just try to write an empty stream to it
1509 uno::Reference
< XInputStream
> xTempIn
= new DummyInputStream
; //uno::Reference< XInputStream >( xTempOut, UNO_QUERY );
1510 aOriginalContent
.writeStream( xTempIn
, true );
1513 OpenCommandArgument2 aArg
;
1514 aArg
.Mode
= OpenMode::DOCUMENT
;
1515 aArg
.Priority
= 0; // unused
1517 aArg
.Properties
= uno::Sequence
< Property
>( 0 ); // unused
1519 aOriginalContent
.executeCommand(u
"open"_ustr
, Any( aArg
) );
1523 // seems to be nonlocal file
1524 // temporary file mechanics should be used
1531 void SAL_CALL
ZipPackage::commitChanges()
1533 // lock the component for the time of committing
1534 ::osl::MutexGuard
aGuard( m_aMutexHolder
->GetMutex() );
1536 if ( m_eMode
== e_IMode_XInputStream
)
1538 IOException aException
;
1539 throw WrappedTargetException(THROW_WHERE
"This package is read only!",
1540 getXWeak(), Any ( aException
) );
1542 // first the writeTempFile is called, if it returns a stream the stream should be written to the target
1543 // if no stream was returned, the file was written directly, nothing should be done
1544 uno::Reference
< io::XInputStream
> xTempInStream
;
1547 xTempInStream
= writeTempFile();
1549 catch (const ucb::ContentCreationException
&)
1551 css::uno::Any anyEx
= cppu::getCaughtException();
1552 throw WrappedTargetException(THROW_WHERE
"Temporary file should be creatable!",
1553 getXWeak(), anyEx
);
1555 if ( xTempInStream
.is() )
1557 uno::Reference
< io::XSeekable
> xTempSeek( xTempInStream
, uno::UNO_QUERY_THROW
);
1561 xTempSeek
->seek( 0 );
1563 catch( const uno::Exception
& )
1565 css::uno::Any anyEx
= cppu::getCaughtException();
1566 throw WrappedTargetException(THROW_WHERE
"Temporary file should be seekable!",
1567 getXWeak(), anyEx
);
1572 // connect to the temporary stream
1573 ConnectTo( xTempInStream
);
1575 catch( const io::IOException
& )
1577 css::uno::Any anyEx
= cppu::getCaughtException();
1578 throw WrappedTargetException(THROW_WHERE
"Temporary file should be connectable!",
1579 getXWeak(), anyEx
);
1582 if ( m_eMode
== e_IMode_XStream
)
1584 // First truncate our output stream
1585 uno::Reference
< XOutputStream
> xOutputStream
;
1587 // preparation for copy step
1590 xOutputStream
= m_xStream
->getOutputStream();
1592 // Make sure we avoid a situation where the current position is
1593 // not zero, but the underlying file is truncated in the
1595 uno::Reference
<io::XSeekable
> xSeekable(xOutputStream
, uno::UNO_QUERY
);
1599 uno::Reference
< XTruncate
> xTruncate ( xOutputStream
, UNO_QUERY_THROW
);
1601 // after successful truncation the original file contents are already lost
1602 xTruncate
->truncate();
1604 catch( const uno::Exception
& )
1606 css::uno::Any anyEx
= cppu::getCaughtException();
1607 throw WrappedTargetException(THROW_WHERE
"This package is read only!",
1608 getXWeak(), anyEx
);
1613 // then copy the contents of the tempfile to our output stream
1614 ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream
, xOutputStream
);
1615 xOutputStream
->flush();
1616 uno::Reference
< io::XAsyncOutputMonitor
> asyncOutputMonitor(
1617 xOutputStream
, uno::UNO_QUERY
);
1618 if ( asyncOutputMonitor
.is() ) {
1619 asyncOutputMonitor
->waitForCompletion();
1622 catch( uno::Exception
& )
1624 // if anything goes wrong in this block the target file becomes corrupted
1625 // so an exception should be thrown as a notification about it
1626 // and the package must disconnect from the stream
1627 DisconnectFromTargetAndThrowException_Impl( xTempInStream
);
1630 else if ( m_eMode
== e_IMode_URL
)
1632 uno::Reference
< XOutputStream
> aOrigFileStream
;
1633 bool bCanBeCorrupted
= false;
1637 // write directly in case of local file
1638 uno::Reference
< css::ucb::XSimpleFileAccess3
> xSimpleAccess(
1639 SimpleFileAccess::create( m_xContext
) );
1640 OSL_ENSURE( xSimpleAccess
.is(), "Can't instantiate SimpleFileAccess service!" );
1641 uno::Reference
< io::XTruncate
> xOrigTruncate
;
1642 if ( xSimpleAccess
.is() )
1646 aOrigFileStream
= xSimpleAccess
->openFileWrite( m_aURL
);
1647 xOrigTruncate
.set( aOrigFileStream
, uno::UNO_QUERY_THROW
);
1648 // after successful truncation the file is already corrupted
1649 xOrigTruncate
->truncate();
1651 catch( uno::Exception
& )
1655 if( xOrigTruncate
.is() )
1659 ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream
, aOrigFileStream
);
1660 aOrigFileStream
->closeOutput();
1662 catch( uno::Exception
& )
1665 aOrigFileStream
->closeOutput();
1666 } catch ( uno::Exception
& ) {}
1668 aOrigFileStream
.clear();
1669 // the original file can already be corrupted
1670 bCanBeCorrupted
= true;
1675 if( !aOrigFileStream
.is() )
1679 uno::Reference
< XPropertySet
> xPropSet ( xTempInStream
, UNO_QUERY_THROW
);
1681 OUString sTargetFolder
= m_aURL
.copy ( 0, m_aURL
.lastIndexOf ( u
'/' ) );
1683 sTargetFolder
, uno::Reference
< XCommandEnvironment
>(),
1687 Any aAny
= xPropSet
->getPropertyValue (u
"Uri"_ustr
);
1691 aInfo
.NameClash
= NameClash::OVERWRITE
;
1692 aInfo
.MoveData
= false;
1693 aInfo
.SourceURL
= sTempURL
;
1694 aInfo
.NewTitle
= rtl::Uri::decode ( m_aURL
.copy ( 1 + m_aURL
.lastIndexOf ( u
'/' ) ),
1695 rtl_UriDecodeWithCharset
,
1696 RTL_TEXTENCODING_UTF8
);
1697 // if the file is still not corrupted, it can become after the next step
1698 aContent
.executeCommand (u
"transfer"_ustr
, Any(aInfo
) );
1700 catch ( const css::uno::Exception
& )
1702 if ( bCanBeCorrupted
)
1703 DisconnectFromTargetAndThrowException_Impl( xTempInStream
);
1705 css::uno::Any anyEx
= cppu::getCaughtException();
1706 throw WrappedTargetException(
1707 THROW_WHERE
"This package may be read only!",
1715 // after successful storing it can be set to false
1716 m_bMediaTypeFallbackUsed
= false;
1719 void ZipPackage::DisconnectFromTargetAndThrowException_Impl( const uno::Reference
< io::XInputStream
>& xTempStream
)
1721 m_xStream
.set( xTempStream
, uno::UNO_QUERY
);
1722 if ( m_xStream
.is() )
1723 m_eMode
= e_IMode_XStream
;
1725 m_eMode
= e_IMode_XInputStream
;
1729 uno::Reference
< beans::XPropertySet
> xTempFile( xTempStream
, uno::UNO_QUERY_THROW
);
1730 uno::Any aUrl
= xTempFile
->getPropertyValue(u
"Uri"_ustr
);
1732 xTempFile
->setPropertyValue(u
"RemoveFile"_ustr
,
1733 uno::Any( false ) );
1735 catch ( uno::Exception
& )
1737 OSL_FAIL( "These calls are pretty simple, they should not fail!" );
1740 OUString
aErrTxt(THROW_WHERE
"This package is read only!");
1741 embed::UseBackupException
aException( aErrTxt
, uno::Reference
< uno::XInterface
>(), aTempURL
);
1742 throw WrappedTargetException( aErrTxt
,
1744 Any ( aException
) );
1747 uno::Sequence
< sal_Int8
> ZipPackage::GetEncryptionKey()
1749 uno::Sequence
< sal_Int8
> aResult
;
1751 if ( m_aStorageEncryptionKeys
.hasElements() )
1753 OUString aNameToFind
;
1754 if ( m_nStartKeyGenerationID
== xml::crypto::DigestID::SHA256
)
1755 aNameToFind
= PACKAGE_ENCRYPTIONDATA_SHA256UTF8
;
1756 else if ( m_nStartKeyGenerationID
== xml::crypto::DigestID::SHA1
)
1757 aNameToFind
= PACKAGE_ENCRYPTIONDATA_SHA1CORRECT
;
1759 throw uno::RuntimeException(THROW_WHERE
"No expected key is provided!" );
1761 for (const auto& rKey
: m_aStorageEncryptionKeys
)
1762 if ( rKey
.Name
== aNameToFind
)
1763 rKey
.Value
>>= aResult
;
1765 if (!aResult
.hasElements() && m_aStorageEncryptionKeys
.hasElements())
1766 { // tdf#159519 sanity check
1767 throw uno::RuntimeException(THROW_WHERE
"Expected key is missing!");
1771 aResult
= m_aEncryptionKey
;
1776 sal_Bool SAL_CALL
ZipPackage::hasPendingChanges()
1780 Sequence
< ElementChange
> SAL_CALL
ZipPackage::getPendingChanges()
1782 return uno::Sequence
< ElementChange
> ();
1786 OUString
ZipPackage::getImplementationName()
1788 return u
"com.sun.star.packages.comp.ZipPackage"_ustr
;
1791 Sequence
< OUString
> ZipPackage::getSupportedServiceNames()
1793 return { u
"com.sun.star.packages.Package"_ustr
};
1796 sal_Bool SAL_CALL
ZipPackage::supportsService( OUString
const & rServiceName
)
1798 return cppu::supportsService(this, rServiceName
);
1801 uno::Reference
< XPropertySetInfo
> SAL_CALL
ZipPackage::getPropertySetInfo()
1803 return uno::Reference
< XPropertySetInfo
> ();
1806 void SAL_CALL
ZipPackage::setPropertyValue( const OUString
& aPropertyName
, const Any
& aValue
)
1808 if ( m_nFormat
!= embed::StorageFormats::PACKAGE
)
1809 throw UnknownPropertyException(aPropertyName
);
1811 if (aPropertyName
== HAS_ENCRYPTED_ENTRIES_PROPERTY
1812 ||aPropertyName
== HAS_NONENCRYPTED_ENTRIES_PROPERTY
1813 ||aPropertyName
== IS_INCONSISTENT_PROPERTY
1814 ||aPropertyName
== MEDIATYPE_FALLBACK_USED_PROPERTY
)
1815 throw PropertyVetoException(THROW_WHERE
);
1816 else if ( aPropertyName
== ENCRYPTION_KEY_PROPERTY
)
1818 if ( !( aValue
>>= m_aEncryptionKey
) )
1819 throw IllegalArgumentException(THROW_WHERE
, uno::Reference
< uno::XInterface
>(), 2 );
1821 m_aStorageEncryptionKeys
.realloc( 0 );
1823 else if ( aPropertyName
== STORAGE_ENCRYPTION_KEYS_PROPERTY
)
1825 // this property is only necessary to support raw passwords in storage API;
1826 // because of this support the storage has to operate with more than one key dependent on storage generation algorithm;
1827 // when this support is removed, the storage will get only one key from outside
1828 if ( !( aValue
>>= m_aStorageEncryptionKeys
) )
1829 throw IllegalArgumentException(THROW_WHERE
, uno::Reference
< uno::XInterface
>(), 2 );
1831 m_aEncryptionKey
.realloc( 0 );
1833 else if ( aPropertyName
== ENCRYPTION_ALGORITHMS_PROPERTY
)
1835 uno::Sequence
< beans::NamedValue
> aAlgorithms
;
1836 if ( m_pZipFile
|| !( aValue
>>= aAlgorithms
) || !aAlgorithms
.hasElements() )
1838 // the algorithms can not be changed if the file has a persistence based on the algorithms ( m_pZipFile )
1839 throw IllegalArgumentException(THROW_WHERE
"unexpected algorithms list is provided.", uno::Reference
< uno::XInterface
>(), 2 );
1842 for (const auto& rAlgorithm
: aAlgorithms
)
1844 if ( rAlgorithm
.Name
== "StartKeyGenerationAlgorithm" )
1847 if ( !( rAlgorithm
.Value
>>= nID
)
1848 || ( nID
!= xml::crypto::DigestID::SHA256
&& nID
!= xml::crypto::DigestID::SHA1
) )
1850 throw IllegalArgumentException(THROW_WHERE
"Unexpected start key generation algorithm is provided!", uno::Reference
<uno::XInterface
>(), 2);
1853 m_nStartKeyGenerationID
= nID
;
1855 else if (rAlgorithm
.Name
== "KeyDerivationFunction")
1858 if (!(rAlgorithm
.Value
>>= nID
)
1859 || (nID
!= xml::crypto::KDFID::PBKDF2
1860 && nID
!= xml::crypto::KDFID::PGP_RSA_OAEP_MGF1P
1861 && nID
!= xml::crypto::KDFID::Argon2id
))
1863 throw IllegalArgumentException(THROW_WHERE
"Unexpected key derivation function provided!", uno::Reference
<uno::XInterface
>(), 2);
1865 m_nKeyDerivationFunctionID
= nID
;
1867 else if ( rAlgorithm
.Name
== "EncryptionAlgorithm" )
1870 if ( !( rAlgorithm
.Value
>>= nID
)
1871 || (nID
!= xml::crypto::CipherID::AES_GCM_W3C
1872 && nID
!= xml::crypto::CipherID::AES_CBC_W3C_PADDING
1873 && nID
!= xml::crypto::CipherID::BLOWFISH_CFB_8
))
1875 throw IllegalArgumentException(THROW_WHERE
"Unexpected encryption algorithm is provided!", uno::Reference
<uno::XInterface
>(), 2);
1878 m_nCommonEncryptionID
= nID
;
1880 else if ( rAlgorithm
.Name
== "ChecksumAlgorithm" )
1883 if (!rAlgorithm
.Value
.hasValue())
1885 m_oChecksumDigestID
.reset();
1888 if ( !( rAlgorithm
.Value
>>= nID
)
1889 || ( nID
!= xml::crypto::DigestID::SHA1_1K
&& nID
!= xml::crypto::DigestID::SHA256_1K
) )
1891 throw IllegalArgumentException(THROW_WHERE
"Unexpected checksum algorithm is provided!", uno::Reference
<uno::XInterface
>(), 2);
1894 m_oChecksumDigestID
.emplace(nID
);
1898 OSL_ENSURE( false, "Unexpected encryption algorithm is provided!" );
1899 throw IllegalArgumentException(THROW_WHERE
"unexpected algorithms list is provided.", uno::Reference
< uno::XInterface
>(), 2 );
1903 else if ( aPropertyName
== ENCRYPTION_GPG_PROPERTIES
)
1905 uno::Sequence
< uno::Sequence
< beans::NamedValue
> > aGpgProps
;
1906 if ( !( aValue
>>= aGpgProps
) || !aGpgProps
.hasElements() )
1908 throw IllegalArgumentException(THROW_WHERE
"unexpected Gpg properties are provided.", uno::Reference
< uno::XInterface
>(), 2 );
1911 m_aGpgProps
= std::move(aGpgProps
);
1913 // override algorithm defaults (which are some legacy ODF
1914 // defaults) with reasonable values
1915 // note: these should be overridden by SfxObjectShell::SetupStorage()
1916 m_nStartKeyGenerationID
= 0; // this is unused for PGP
1917 m_nKeyDerivationFunctionID
= xml::crypto::KDFID::PGP_RSA_OAEP_MGF1P
;
1918 m_nCommonEncryptionID
= xml::crypto::CipherID::AES_CBC_W3C_PADDING
;
1919 m_oChecksumDigestID
.emplace(xml::crypto::DigestID::SHA512_1K
);
1922 throw UnknownPropertyException(aPropertyName
);
1925 Any SAL_CALL
ZipPackage::getPropertyValue( const OUString
& PropertyName
)
1927 // TODO/LATER: Activate the check when zip-ucp is ready
1928 // if ( m_nFormat != embed::StorageFormats::PACKAGE )
1929 // throw UnknownPropertyException(THROW_WHERE );
1931 if ( PropertyName
== ENCRYPTION_KEY_PROPERTY
)
1933 return Any(m_aEncryptionKey
);
1935 else if ( PropertyName
== ENCRYPTION_ALGORITHMS_PROPERTY
)
1937 ::comphelper::SequenceAsHashMap aAlgorithms
;
1938 aAlgorithms
[u
"StartKeyGenerationAlgorithm"_ustr
] <<= m_nStartKeyGenerationID
;
1939 aAlgorithms
[u
"KeyDerivationFunction"_ustr
] <<= m_nKeyDerivationFunctionID
;
1940 aAlgorithms
[u
"EncryptionAlgorithm"_ustr
] <<= m_nCommonEncryptionID
;
1941 if (m_oChecksumDigestID
)
1943 aAlgorithms
[u
"ChecksumAlgorithm"_ustr
] <<= *m_oChecksumDigestID
;
1947 aAlgorithms
[u
"ChecksumAlgorithm"_ustr
];
1949 return Any(aAlgorithms
.getAsConstNamedValueList());
1951 if ( PropertyName
== STORAGE_ENCRYPTION_KEYS_PROPERTY
)
1953 return Any(m_aStorageEncryptionKeys
);
1955 else if ( PropertyName
== HAS_ENCRYPTED_ENTRIES_PROPERTY
)
1957 return Any(m_bHasEncryptedEntries
);
1959 else if ( PropertyName
== ENCRYPTION_GPG_PROPERTIES
)
1961 return Any(m_aGpgProps
);
1963 else if ( PropertyName
== HAS_NONENCRYPTED_ENTRIES_PROPERTY
)
1965 return Any(m_bHasNonEncryptedEntries
);
1967 else if ( PropertyName
== IS_INCONSISTENT_PROPERTY
)
1969 return Any(m_bInconsistent
);
1971 else if ( PropertyName
== MEDIATYPE_FALLBACK_USED_PROPERTY
)
1973 return Any(m_bMediaTypeFallbackUsed
);
1975 else if (PropertyName
== "HasElements")
1977 return Any(m_pZipFile
&& m_pZipFile
->entries().hasMoreElements());
1979 throw UnknownPropertyException(PropertyName
);
1981 void SAL_CALL
ZipPackage::addPropertyChangeListener( const OUString
& /*aPropertyName*/, const uno::Reference
< XPropertyChangeListener
>& /*xListener*/ )
1984 void SAL_CALL
ZipPackage::removePropertyChangeListener( const OUString
& /*aPropertyName*/, const uno::Reference
< XPropertyChangeListener
>& /*aListener*/ )
1987 void SAL_CALL
ZipPackage::addVetoableChangeListener( const OUString
& /*PropertyName*/, const uno::Reference
< XVetoableChangeListener
>& /*aListener*/ )
1990 void SAL_CALL
ZipPackage::removeVetoableChangeListener( const OUString
& /*PropertyName*/, const uno::Reference
< XVetoableChangeListener
>& /*aListener*/ )
1994 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
1995 package_ZipPackage_get_implementation(
1996 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
1998 return cppu::acquire(new ZipPackage(context
));
2001 extern "C" bool TestImportZip(SvStream
& rStream
)
2003 // explicitly tests the "RepairPackage" recovery mode
2004 rtl::Reference
<ZipPackage
> xPackage(new ZipPackage(comphelper::getProcessComponentContext()));
2005 css::uno::Reference
<css::io::XInputStream
> xStream(new utl::OInputStreamWrapper(rStream
));
2006 css::uno::Sequence
<Any
> aArgs
{ Any(xStream
), Any(NamedValue(u
"RepairPackage"_ustr
, Any(true))) };
2007 xPackage
->initialize(aArgs
);
2011 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */