summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVasily Melenchuk <vasily.melenchuk@cib.de>2019-11-08 17:53:30 +0300
committerThorsten Behrens <Thorsten.Behrens@CIB.de>2019-12-04 17:13:37 +0100
commit31fdf71cb23c9c5c843ef88815a437fbaa979429 (patch)
tree0030227ff4366b0dd01fc10820c2836733e71aad
parent806973f3a8dee30cd67263fb6e59d0da3218028b (diff)
calc: support for reading DRM encrypted xls files
DRM encryption is implemented as an optional service, so just use it when available. Change-Id: Ie580e5c12c48ccf99f9a932b1c66eb35866b7ef4
-rw-r--r--sc/source/filter/excel/excel.cxx105
1 files changed, 105 insertions, 0 deletions
diff --git a/sc/source/filter/excel/excel.cxx b/sc/source/filter/excel/excel.cxx
index ca87efc2988c..56adce29a061 100644
--- a/sc/source/filter/excel/excel.cxx
+++ b/sc/source/filter/excel/excel.cxx
@@ -24,7 +24,9 @@
#include <sot/exchange.hxx>
#include <filter/msfilter/classids.hxx>
#include <tools/globname.hxx>
+#include <com/sun/star/packages/XPAckageEncryption.hpp>
#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
#include <unotools/streamwrap.hxx>
#include <osl/diagnose.h>
#include <filter.hxx>
@@ -32,6 +34,8 @@
#include <xistream.hxx>
#include <xltools.hxx>
#include <docoptio.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/processfactory.hxx>
#include <docsh.hxx>
#include <scerrors.hxx>
@@ -42,6 +46,99 @@
#include <memory>
+using namespace css;
+
+static void lcl_getListOfStreams(SotStorage * pStorage, comphelper::SequenceAsHashMap& aStreamsData, const OUString& sPrefix)
+{
+ SvStorageInfoList aElements;
+ pStorage->FillInfoList(&aElements);
+ for (const auto & aElement : aElements)
+ {
+ OUString sStreamFullName = sPrefix.getLength() ? sPrefix + "/" + aElement.GetName() : aElement.GetName();
+ if (aElement.IsStorage())
+ {
+ SotStorage * pSubStorage = pStorage->OpenSotStorage(aElement.GetName(), StreamMode::STD_READ | StreamMode::SHARE_DENYALL);
+ lcl_getListOfStreams(pSubStorage, aStreamsData, sStreamFullName);
+ }
+ else
+ {
+ // Read stream
+ tools::SvRef<SotStorageStream> rStream = pStorage->OpenSotStream(aElement.GetName(), StreamMode::READ | StreamMode::SHARE_DENYALL);
+ assert(rStream.is());
+
+ sal_Int32 nStreamSize = rStream->GetSize();
+ uno::Sequence< sal_Int8 > oData;
+ oData.realloc(nStreamSize);
+ sal_Int32 nReadBytes = rStream->ReadBytes(oData.getArray(), nStreamSize);
+ assert(nStreamSize == nReadBytes);
+ aStreamsData[sStreamFullName] <<= oData;
+ }
+ }
+}
+
+static tools::SvRef<SotStorage> lcl_DRMDecrypt(SfxMedium& rMedium, tools::SvRef<SotStorage>& rStorage, std::shared_ptr<SvStream>& rNewStorageStrm)
+{
+ tools::SvRef<SotStorage> aNewStorage;
+
+ // We have DRM encrypted storage. We should try to decrypt it first, if we can
+ uno::Sequence< uno::Any > aArguments;
+ uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext());
+ uno::Reference< packages::XPackageEncryption > xPackageEncryption(
+ xComponentContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ "com.sun.star.comp.oox.crypto.DRMDataSpace", aArguments, xComponentContext), uno::UNO_QUERY);
+
+ if (!xPackageEncryption.is())
+ {
+ // We do not know how to decrypt this
+ return aNewStorage;
+ }
+
+ std::vector<OUString> aStreamsList;
+ comphelper::SequenceAsHashMap aStreamsData;
+ lcl_getListOfStreams(rStorage.get(), aStreamsData, OUString(""));
+
+ try {
+ uno::Sequence<beans::NamedValue> aStreams = aStreamsData.getAsConstNamedValueList();
+ if (!xPackageEncryption->readEncryptionInfo(aStreams))
+ {
+ // We failed with decryption
+ return aNewStorage;
+ }
+
+ tools::SvRef<SotStorageStream> rContentStream = rStorage->OpenSotStream("\011DRMContent", StreamMode::READ | StreamMode::SHARE_DENYALL);
+ if (!rContentStream.is())
+ {
+ return aNewStorage;
+ }
+
+ rNewStorageStrm.reset(new SvMemoryStream());
+
+ uno::Reference<io::XInputStream > xInputStream(new utl::OSeekableInputStreamWrapper(rContentStream.get(), false));
+ uno::Reference<io::XOutputStream > xDecryptedStream(new utl::OSeekableOutputStreamWrapper(*rNewStorageStrm.get()));
+
+ if (!xPackageEncryption->decrypt(xInputStream, xDecryptedStream))
+ {
+ // We failed with decryption
+ return aNewStorage;
+ }
+
+ rNewStorageStrm->Seek(0);
+
+ // Further reading is done from new document
+ aNewStorage = new SotStorage(*rNewStorageStrm);
+
+ // Set the media descriptor data
+ uno::Sequence<beans::NamedValue> aEncryptionData = xPackageEncryption->createEncryptionData("");
+ rMedium.GetItemSet()->Put(SfxUnoAnyItem(SID_ENCRYPTIONDATA, uno::makeAny(aEncryptionData)));
+ }
+ catch (const std::exception&)
+ {
+ return aNewStorage;
+ }
+
+ return aNewStorage;
+}
+
ErrCode ScFormatFilterPluginImpl::ScImportExcel( SfxMedium& rMedium, ScDocument* pDocument, const EXCIMPFORMAT eFormat )
{
// check the passed Calc document
@@ -67,6 +164,7 @@ ErrCode ScFormatFilterPluginImpl::ScImportExcel( SfxMedium& rMedium, ScDocument*
// try to open an OLE storage
tools::SvRef<SotStorage> xRootStrg;
tools::SvRef<SotStorageStream> xStrgStrm;
+ std::shared_ptr<SvStream> aNewStorageStrm;
if( SotStorage::IsStorageFile( pMedStrm ) )
{
xRootStrg = new SotStorage( pMedStrm, false );
@@ -77,6 +175,13 @@ ErrCode ScFormatFilterPluginImpl::ScImportExcel( SfxMedium& rMedium, ScDocument*
// try to open "Book" or "Workbook" stream in OLE storage
if( xRootStrg.is() )
{
+ // Check if there is DRM encryption in storage
+ tools::SvRef<SotStorageStream> xDRMStrm = ScfTools::OpenStorageStreamRead(xRootStrg, "\011DRMContent");
+ if (xDRMStrm.is())
+ {
+ xRootStrg = lcl_DRMDecrypt(rMedium, xRootStrg, aNewStorageStrm);
+ }
+
// try to open the "Book" stream
tools::SvRef<SotStorageStream> xBookStrm = ScfTools::OpenStorageStreamRead( xRootStrg, EXC_STREAM_BOOK );
XclBiff eBookBiff = xBookStrm.is() ? XclImpStream::DetectBiffVersion( *xBookStrm ) : EXC_BIFF_UNKNOWN;