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 <config_gpgme.h>
22 #include <com/sun/star/embed/ElementModes.hpp>
23 #include <com/sun/star/embed/XEncryptionProtectedStorage.hpp>
24 #include <com/sun/star/embed/XStorage.hpp>
25 #include <com/sun/star/embed/XTransactedObject.hpp>
26 #include <com/sun/star/embed/StorageFactory.hpp>
27 #include <com/sun/star/embed/FileSystemStorageFactory.hpp>
28 #include <com/sun/star/io/IOException.hpp>
29 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
30 #include <com/sun/star/lang/XUnoTunnel.hpp>
31 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
32 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/beans/PropertyValue.hpp>
35 #include <com/sun/star/beans/NamedValue.hpp>
36 #include <com/sun/star/beans/IllegalTypeException.hpp>
37 #include <com/sun/star/xml/crypto/NSSInitializer.hpp>
38 #include <com/sun/star/xml/crypto/XDigestContext.hpp>
39 #include <com/sun/star/xml/crypto/DigestID.hpp>
40 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
41 #include <com/sun/star/security/XCertificate.hpp>
45 #include <rtl/digest.h>
46 #include <rtl/random.h>
47 #include <osl/diagnose.h>
48 #include <sal/log.hxx>
50 #include <ucbhelper/content.hxx>
52 #include <comphelper/bytereader.hxx>
53 #include <comphelper/diagnose_ex.hxx>
54 #include <comphelper/fileformat.h>
55 #include <comphelper/hash.hxx>
56 #include <comphelper/processfactory.hxx>
57 #include <comphelper/documentconstants.hxx>
58 #include <comphelper/propertyvalue.hxx>
59 #include <comphelper/storagehelper.hxx>
60 #include <comphelper/sequence.hxx>
61 #include <cppuhelper/exc_hlp.hxx>
62 #include <o3tl/string_view.hxx>
64 #if HAVE_FEATURE_GPGME
66 # include <encryptionresult.h>
71 using namespace ::com::sun::star
;
73 namespace comphelper
{
76 uno::Reference
< lang::XSingleServiceFactory
> OStorageHelper::GetStorageFactory(
77 const uno::Reference
< uno::XComponentContext
>& rxContext
)
79 uno::Reference
< uno::XComponentContext
> xContext
= rxContext
.is() ? rxContext
: ::comphelper::getProcessComponentContext();
81 return embed::StorageFactory::create( xContext
);
85 uno::Reference
< lang::XSingleServiceFactory
> OStorageHelper::GetFileSystemStorageFactory(
86 const uno::Reference
< uno::XComponentContext
>& rxContext
)
88 return embed::FileSystemStorageFactory::create(rxContext
);
92 uno::Reference
< embed::XStorage
> OStorageHelper::GetTemporaryStorage(
93 const uno::Reference
< uno::XComponentContext
>& rxContext
)
95 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstance(),
96 uno::UNO_QUERY_THROW
);
101 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageFromURL(
102 const OUString
& aURL
,
103 sal_Int32 nStorageMode
,
104 const uno::Reference
< uno::XComponentContext
>& rxContext
)
106 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(aURL
), uno::Any(nStorageMode
) };
107 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstanceWithArguments( aArgs
),
108 uno::UNO_QUERY_THROW
);
113 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageFromURL2(
114 const OUString
& aURL
,
115 sal_Int32 nStorageMode
,
116 const uno::Reference
< uno::XComponentContext
>& rxContext
)
118 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(aURL
), uno::Any(nStorageMode
) };
120 uno::Reference
< lang::XSingleServiceFactory
> xFact
;
123 ::ucbhelper::Content
aCntnt( aURL
,
124 uno::Reference
< css::ucb::XCommandEnvironment
> (),
125 getProcessComponentContext() );
126 if (aCntnt
.isDocument()) {
127 xFact
= GetStorageFactory( rxContext
);
129 xFact
= GetFileSystemStorageFactory( rxContext
);
131 } catch (uno::Exception
&)
133 anyEx
= cppu::getCaughtException();
138 if (anyEx
.hasValue())
139 throw css::lang::WrappedTargetRuntimeException( "", nullptr, anyEx
);
141 throw uno::RuntimeException();
144 uno::Reference
< embed::XStorage
> xTempStorage(
145 xFact
->createInstanceWithArguments( aArgs
), uno::UNO_QUERY_THROW
);
150 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageFromInputStream(
151 const uno::Reference
< io::XInputStream
>& xStream
,
152 const uno::Reference
< uno::XComponentContext
>& rxContext
)
154 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(xStream
), uno::Any(embed::ElementModes::READ
) };
155 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstanceWithArguments( aArgs
),
156 uno::UNO_QUERY_THROW
);
161 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageFromStream(
162 const uno::Reference
< io::XStream
>& xStream
,
163 sal_Int32 nStorageMode
,
164 const uno::Reference
< uno::XComponentContext
>& rxContext
)
166 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(xStream
), uno::Any(nStorageMode
) };
167 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstanceWithArguments( aArgs
),
168 uno::UNO_QUERY_THROW
);
173 void OStorageHelper::CopyInputToOutput(
174 const uno::Reference
< io::XInputStream
>& xInput
,
175 const uno::Reference
< io::XOutputStream
>& xOutput
)
177 static const sal_Int32 nConstBufferSize
= 32000;
179 if (auto pByteReader
= dynamic_cast< comphelper::ByteReader
* >( xInput
.get() ))
181 if (auto pByteWriter
= dynamic_cast< comphelper::ByteWriter
* >( xOutput
.get() ))
184 sal_Int8 aTempBuf
[ nConstBufferSize
];
187 nRead
= pByteReader
->readSomeBytes ( aTempBuf
, nConstBufferSize
);
188 pByteWriter
->writeBytes ( aTempBuf
, nRead
);
190 while ( nRead
== nConstBufferSize
);
196 uno::Sequence
< sal_Int8
> aSequence ( nConstBufferSize
);
199 nRead
= xInput
->readBytes ( aSequence
, nConstBufferSize
);
200 if ( nRead
< nConstBufferSize
)
201 aSequence
.realloc( nRead
);
202 xOutput
->writeBytes ( aSequence
);
204 while ( nRead
== nConstBufferSize
);
208 uno::Reference
< io::XInputStream
> OStorageHelper::GetInputStreamFromURL(
209 const OUString
& aURL
,
210 const uno::Reference
< uno::XComponentContext
>& context
)
212 uno::Reference
< io::XInputStream
> xInputStream
= ucb::SimpleFileAccess::create(context
)->openFileRead( aURL
);
213 if ( !xInputStream
.is() )
214 throw uno::RuntimeException();
220 void OStorageHelper::SetCommonStorageEncryptionData(
221 const uno::Reference
< embed::XStorage
>& xStorage
,
222 const uno::Sequence
< beans::NamedValue
>& aEncryptionData
)
224 uno::Reference
< embed::XEncryptionProtectedStorage
> xEncrSet( xStorage
, uno::UNO_QUERY
);
225 if ( !xEncrSet
.is() )
226 throw io::IOException("no XEncryptionProtectedStorage"); // TODO
228 if ( aEncryptionData
.getLength() == 2 &&
229 aEncryptionData
[0].Name
== "GpgInfos" &&
230 aEncryptionData
[1].Name
== "EncryptionKey" )
232 xEncrSet
->setGpgProperties(
233 aEncryptionData
[0].Value
.get
< uno::Sequence
< uno::Sequence
< beans::NamedValue
> > >() );
234 xEncrSet
->setEncryptionData(
235 aEncryptionData
[1].Value
.get
< uno::Sequence
< beans::NamedValue
> >() );
238 xEncrSet
->setEncryptionData( aEncryptionData
);
242 sal_Int32
OStorageHelper::GetXStorageFormat(
243 const uno::Reference
< embed::XStorage
>& xStorage
)
245 uno::Reference
< beans::XPropertySet
> xStorProps( xStorage
, uno::UNO_QUERY_THROW
);
248 xStorProps
->getPropertyValue("MediaType") >>= aMediaType
;
250 sal_Int32 nResult
= 0;
252 // TODO/LATER: the filter configuration could be used to detect it later, or better a special service
254 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_WRITER_ASCII
) ||
255 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_WRITER_WEB_ASCII
) ||
256 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_WRITER_GLOBAL_ASCII
) ||
257 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_DRAW_ASCII
) ||
258 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_IMPRESS_ASCII
) ||
259 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_CALC_ASCII
) ||
260 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_CHART_ASCII
) ||
261 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_MATH_ASCII
)
264 nResult
= SOFFICE_FILEFORMAT_60
;
267 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_ASCII
) ||
268 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_WEB_ASCII
) ||
269 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_ASCII
) ||
270 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_ASCII
) ||
271 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII
) ||
272 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_ASCII
) ||
273 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_CHART_ASCII
) ||
274 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_ASCII
) ||
275 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII
) ||
276 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_REPORT_ASCII
) ||
277 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_REPORT_CHART_ASCII
) ||
278 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_TEMPLATE_ASCII
) ||
279 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_TEMPLATE_ASCII
) ||
280 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_TEMPLATE_ASCII
) ||
281 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII
) ||
282 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_TEMPLATE_ASCII
) ||
283 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_CHART_TEMPLATE_ASCII
) ||
284 aMediaType
.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_TEMPLATE_ASCII
)
287 nResult
= SOFFICE_FILEFORMAT_8
;
291 // the mediatype is not known
292 OUString aMsg
= __func__
293 + OUString::Concat(u
":")
294 + OUString::number(__LINE__
)
295 + ": unknown media type '"
298 throw beans::IllegalTypeException(aMsg
);
305 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageOfFormatFromURL(
306 const OUString
& aFormat
,
307 const OUString
& aURL
,
308 sal_Int32 nStorageMode
,
309 const uno::Reference
< uno::XComponentContext
>& rxContext
)
311 uno::Sequence
< beans::PropertyValue
> aProps
{ comphelper::makePropertyValue("StorageFormat",
314 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(aURL
), uno::Any(nStorageMode
), uno::Any(aProps
) };
315 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstanceWithArguments( aArgs
),
316 uno::UNO_QUERY_THROW
);
321 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageOfFormatFromInputStream(
322 const OUString
& aFormat
,
323 const uno::Reference
< io::XInputStream
>& xStream
,
324 const uno::Reference
< uno::XComponentContext
>& rxContext
,
325 bool bRepairStorage
)
327 uno::Sequence
< beans::PropertyValue
> aProps( bRepairStorage
? 2 : 1 );
328 auto pProps
= aProps
.getArray();
329 pProps
[0].Name
= "StorageFormat";
330 pProps
[0].Value
<<= aFormat
;
331 if ( bRepairStorage
)
333 pProps
[1].Name
= "RepairPackage";
334 pProps
[1].Value
<<= bRepairStorage
;
337 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(xStream
), uno::Any(embed::ElementModes::READ
), uno::Any(aProps
) };
338 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstanceWithArguments( aArgs
),
339 uno::UNO_QUERY_THROW
);
344 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageOfFormatFromStream(
345 const OUString
& aFormat
,
346 const uno::Reference
< io::XStream
>& xStream
,
347 sal_Int32 nStorageMode
,
348 const uno::Reference
< uno::XComponentContext
>& rxContext
,
349 bool bRepairStorage
)
351 uno::Sequence
< beans::PropertyValue
> aProps( bRepairStorage
? 2 : 1 );
352 auto pProps
= aProps
.getArray();
353 pProps
[0].Name
= "StorageFormat";
354 pProps
[0].Value
<<= aFormat
;
355 if ( bRepairStorage
)
357 pProps
[1].Name
= "RepairPackage";
358 pProps
[1].Value
<<= bRepairStorage
;
361 uno::Sequence
< uno::Any
> aArgs
{ uno::Any(xStream
), uno::Any(nStorageMode
), uno::Any(aProps
) };
362 uno::Reference
< embed::XStorage
> xTempStorage( GetStorageFactory( rxContext
)->createInstanceWithArguments( aArgs
),
363 uno::UNO_QUERY_THROW
);
368 uno::Sequence
< beans::NamedValue
> OStorageHelper::CreatePackageEncryptionData( std::u16string_view aPassword
)
370 // TODO/LATER: Should not the method be part of DocPasswordHelper?
371 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
372 if ( !aPassword
.empty() )
374 sal_Int32 nSha1Ind
= 0;
375 // generate SHA256 start key
378 uno::Reference
< uno::XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
380 uno::Reference
< css::xml::crypto::XNSSInitializer
> xDigestContextSupplier
= css::xml::crypto::NSSInitializer::create(xContext
);
381 uno::Reference
< css::xml::crypto::XDigestContext
> xDigestContext( xDigestContextSupplier
->getDigestContext( css::xml::crypto::DigestID::SHA256
, uno::Sequence
< beans::NamedValue
>() ), uno::UNO_SET_THROW
);
383 OString
aUTF8Password( OUStringToOString( aPassword
, RTL_TEXTENCODING_UTF8
) );
384 xDigestContext
->updateDigest( uno::Sequence
< sal_Int8
>( reinterpret_cast< const sal_Int8
* >( aUTF8Password
.getStr() ), aUTF8Password
.getLength() ) );
385 uno::Sequence
< sal_Int8
> aDigest
= xDigestContext
->finalizeDigestAndDispose();
388 aEncryptionData
= { { PACKAGE_ENCRYPTIONDATA_SHA256UTF8
, uno::Any(aDigest
) } };
390 catch ( uno::Exception
& )
392 TOOLS_WARN_EXCEPTION("comphelper", "Can not create SHA256 digest!" );
395 // MS_1252 encoding was used for SO60 document format password encoding,
396 // this encoding supports only a minor subset of nonascii characters,
397 // but for compatibility reasons it has to be used for old document formats
398 aEncryptionData
.realloc( nSha1Ind
+ 3 );
399 auto pEncryptionData
= aEncryptionData
.getArray();
400 // these are StarOffice not-quite-SHA1
401 pEncryptionData
[nSha1Ind
].Name
= PACKAGE_ENCRYPTIONDATA_SHA1UTF8
;
402 pEncryptionData
[nSha1Ind
+ 1].Name
= PACKAGE_ENCRYPTIONDATA_SHA1MS1252
;
404 rtl_TextEncoding
const pEncoding
[2] = { RTL_TEXTENCODING_UTF8
, RTL_TEXTENCODING_MS_1252
};
406 for ( sal_Int32 nInd
= 0; nInd
< 2; nInd
++ )
408 OString aByteStrPass
= OUStringToOString( aPassword
, pEncoding
[nInd
] );
410 sal_uInt8 pBuffer
[RTL_DIGEST_LENGTH_SHA1
];
411 rtlDigestError nError
= rtl_digest_SHA1( aByteStrPass
.getStr(),
412 aByteStrPass
.getLength(),
414 RTL_DIGEST_LENGTH_SHA1
);
416 if ( nError
!= rtl_Digest_E_None
)
418 aEncryptionData
.realloc( nSha1Ind
);
419 return aEncryptionData
;
422 // coverity[overrun-buffer-arg : FALSE] - coverity has difficulty with css::uno::Sequence
423 pEncryptionData
[nSha1Ind
+nInd
].Value
<<= uno::Sequence
< sal_Int8
>( reinterpret_cast<sal_Int8
*>(pBuffer
), RTL_DIGEST_LENGTH_SHA1
);
427 pEncryptionData
[nSha1Ind
+ 2].Name
= PACKAGE_ENCRYPTIONDATA_SHA1CORRECT
;
428 OString aByteStrPass
= OUStringToOString(aPassword
, RTL_TEXTENCODING_UTF8
);
429 std::vector
<unsigned char> const sha1(::comphelper::Hash::calculateHash(
430 reinterpret_cast<unsigned char const*>(aByteStrPass
.getStr()), aByteStrPass
.getLength(),
431 ::comphelper::HashType::SHA1
));
432 pEncryptionData
[nSha1Ind
+ 2].Value
<<= uno::Sequence
<sal_Int8
>(
433 reinterpret_cast<sal_Int8
const*>(sha1
.data()), sha1
.size());
436 return aEncryptionData
;
439 uno::Sequence
< beans::NamedValue
> OStorageHelper::CreateGpgPackageEncryptionData()
441 #if HAVE_FEATURE_GPGME
442 // generate session key
443 // --------------------
445 rtlRandomPool aRandomPool
= rtl_random_createPool();
447 // get 32 random chars out of it
448 uno::Sequence
< sal_Int8
> aVector(32);
449 rtl_random_getBytes( aRandomPool
, aVector
.getArray(), aVector
.getLength() );
451 rtl_random_destroyPool(aRandomPool
);
453 std::vector
< uno::Sequence
< beans::NamedValue
> > aGpgEncryptions
;
455 uno::Reference
< security::XDocumentDigitalSignatures
> xSigner(
456 // here none of the version-dependent methods are called
457 security::DocumentDigitalSignatures::createDefault(
458 comphelper::getProcessComponentContext()));
460 // fire up certificate chooser dialog - user can multi-select!
461 const uno::Sequence
< uno::Reference
< security::XCertificate
> > xSignCertificates
=
462 xSigner
->chooseEncryptionCertificate();
464 if (!xSignCertificates
.hasElements())
465 return uno::Sequence
< beans::NamedValue
>(); // user cancelled
467 // generate one encrypted key entry for each recipient
468 // ---------------------------------------------------
470 std::unique_ptr
<GpgME::Context
> ctx
;
471 GpgME::Error err
= GpgME::checkEngine(GpgME::OpenPGP
);
473 throw uno::RuntimeException("The GpgME library failed to initialize for the OpenPGP protocol.");
475 ctx
.reset( GpgME::Context::createForProtocol(GpgME::OpenPGP
) );
477 throw uno::RuntimeException("The GpgME library failed to initialize for the OpenPGP protocol.");
478 ctx
->setArmor(false);
480 for (const auto & cert
: xSignCertificates
)
482 uno::Sequence
< sal_Int8
> aKeyID
;
484 aKeyID
= cert
->getSHA1Thumbprint();
486 std::vector
<GpgME::Key
> keys
489 reinterpret_cast<const char*>(aKeyID
.getConstArray()),
493 // ctx is setup now, let's encrypt the lot!
495 reinterpret_cast<const char*>(aVector
.getConstArray()),
496 size_t(aVector
.getLength()), false);
499 GpgME::EncryptionResult crypt_res
= ctx
->encrypt(
501 cipher
, GpgME::Context::NoCompress
);
503 off_t result
= cipher
.seek(0,SEEK_SET
);
506 int len
=0, curr
=0; char buf
;
507 while( (curr
=cipher
.read(&buf
, 1)) )
510 if(crypt_res
.error() || !len
)
511 throw lang::IllegalArgumentException(
512 "Not a suitable key, or failed to encrypt.",
513 css::uno::Reference
<css::uno::XInterface
>(), -1);
515 uno::Sequence
< sal_Int8
> aCipherValue(len
);
516 result
= cipher
.seek(0,SEEK_SET
);
518 if( cipher
.read(aCipherValue
.getArray(), len
) != len
)
519 throw uno::RuntimeException("The GpgME library failed to read the encrypted value.");
521 SAL_INFO("comphelper.crypto", "Generated gpg crypto of length: " << len
);
523 uno::Sequence
< beans::NamedValue
> aGpgEncryptionEntry
{
524 { "KeyId", uno::Any(aKeyID
) },
525 { "KeyPacket", uno::Any(aKeyID
) },
526 { "CipherValue", uno::Any(aCipherValue
) }
529 aGpgEncryptions
.push_back(aGpgEncryptionEntry
);
532 uno::Sequence
<beans::NamedValue
> aEncryptionData
533 = { { PACKAGE_ENCRYPTIONDATA_SHA256UTF8
, uno::Any(aVector
) } };
535 uno::Sequence
<beans::NamedValue
> aContainer
536 = { { "GpgInfos", uno::Any(comphelper::containerToSequence(aGpgEncryptions
)) },
537 { "EncryptionKey", uno::Any(aEncryptionData
) } };
541 return uno::Sequence
< beans::NamedValue
>();
545 bool OStorageHelper::IsValidZipEntryFileName( std::u16string_view aName
, bool bSlashAllowed
)
547 for ( size_t i
= 0; i
< aName
.size(); i
++ )
560 if ( !bSlashAllowed
)
564 if ( aName
[i
] < 32 || (aName
[i
] >= 0xD800 && aName
[i
] <= 0xDFFF) )
572 bool OStorageHelper::PathHasSegment( std::u16string_view aPath
, std::u16string_view aSegment
)
574 bool bResult
= false;
575 const size_t nPathLen
= aPath
.size();
576 const size_t nSegLen
= aSegment
.size();
578 if ( !aSegment
.empty() && nPathLen
>= nSegLen
)
580 OUString aEndSegment
= OUString::Concat("/") + aSegment
;
581 OUString aInternalSegment
= aEndSegment
+ "/";
583 if ( aPath
.find( aInternalSegment
) != std::u16string_view::npos
)
586 if ( !bResult
&& o3tl::starts_with(aPath
, aSegment
) )
588 if ( nPathLen
== nSegLen
|| aPath
[nSegLen
] == '/' )
592 if ( !bResult
&& nPathLen
> nSegLen
&& aPath
.substr( nPathLen
- nSegLen
- 1, nSegLen
+ 1 ) == aEndSegment
)
599 class LifecycleProxy::Impl
600 : public std::vector
< uno::Reference
< embed::XStorage
> > {};
601 LifecycleProxy::LifecycleProxy()
602 : m_xBadness( new Impl
) { }
603 LifecycleProxy::~LifecycleProxy() { }
605 void LifecycleProxy::commitStorages()
607 std::for_each(m_xBadness
->rbegin(), m_xBadness
->rend(), // reverse order (outwards)
608 [](Impl::reference rxItem
) {
609 uno::Reference
<embed::XTransactedObject
> const xTransaction(rxItem
, uno::UNO_QUERY
);
610 if (xTransaction
.is())
612 xTransaction
->commit();
617 static void splitPath( std::vector
<OUString
> &rElems
, std::u16string_view rPath
)
619 for (sal_Int32 i
= 0; i
>= 0;)
620 rElems
.push_back( OUString(o3tl::getToken(rPath
, 0, '/', i
)) );
623 static uno::Reference
< embed::XStorage
> LookupStorageAtPath(
624 const uno::Reference
< embed::XStorage
> &xParentStorage
,
625 std::vector
<OUString
> &rElems
, sal_uInt32 nOpenMode
,
626 LifecycleProxy
const &rNastiness
)
628 uno::Reference
< embed::XStorage
> xStorage( xParentStorage
);
629 rNastiness
.m_xBadness
->push_back( xStorage
);
630 for( size_t i
= 0; i
< rElems
.size() && xStorage
.is(); i
++ )
632 xStorage
= xStorage
->openStorageElement( rElems
[i
], nOpenMode
);
633 rNastiness
.m_xBadness
->push_back( xStorage
);
638 uno::Reference
< embed::XStorage
> OStorageHelper::GetStorageAtPath(
639 const uno::Reference
< embed::XStorage
> &xStorage
,
640 std::u16string_view rPath
, sal_uInt32 nOpenMode
,
641 LifecycleProxy
const &rNastiness
)
643 std::vector
<OUString
> aElems
;
644 splitPath( aElems
, rPath
);
645 return LookupStorageAtPath( xStorage
, aElems
, nOpenMode
, rNastiness
);
648 uno::Reference
< io::XStream
> OStorageHelper::GetStreamAtPath(
649 const uno::Reference
< embed::XStorage
> &xParentStorage
,
650 std::u16string_view rPath
, sal_uInt32 nOpenMode
,
651 LifecycleProxy
const &rNastiness
)
653 std::vector
<OUString
> aElems
;
654 splitPath( aElems
, rPath
);
655 OUString
aName( aElems
.back() );
657 sal_uInt32 nStorageMode
= nOpenMode
& ~embed::ElementModes::TRUNCATE
;
658 uno::Reference
< embed::XStorage
> xStorage(
659 LookupStorageAtPath( xParentStorage
, aElems
, nStorageMode
, rNastiness
),
660 uno::UNO_SET_THROW
);
661 return xStorage
->openStreamElement( aName
, nOpenMode
);
664 uno::Reference
< io::XStream
> OStorageHelper::GetStreamAtPackageURL(
665 uno::Reference
< embed::XStorage
> const& xParentStorage
,
666 const OUString
& rURL
, sal_uInt32
const nOpenMode
,
667 LifecycleProxy
const & rNastiness
)
670 if (rURL
.startsWithIgnoreAsciiCase("vnd.sun.star.Package:", &path
))
672 return GetStreamAtPath(xParentStorage
, path
, nOpenMode
, rNastiness
);
677 OUString
OStorageHelper::GetODFVersionFromStorage(const uno::Reference
<embed::XStorage
>& xStorage
)
679 OUString aODFVersion
;
682 uno::Reference
<beans::XPropertySet
> xPropSet(xStorage
, uno::UNO_QUERY_THROW
);
683 xPropSet
->getPropertyValue("Version") >>= aODFVersion
;
685 catch (uno::Exception
&)
692 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */