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 <sfx2/docfile.hxx>
21 #include <sfx2/frame.hxx>
22 #include <sfx2/sfxsids.hrc>
23 #include <sot/storage.hxx>
24 #include <sot/exchange.hxx>
25 #include <filter/msfilter/classids.hxx>
26 #include <tools/globname.hxx>
27 #include <com/sun/star/packages/XPackageEncryption.hpp>
28 #include <com/sun/star/ucb/ContentCreationException.hpp>
29 #include <com/sun/star/uno/XComponentContext.hpp>
30 #include <unotools/streamwrap.hxx>
31 #include <unotools/defaultencoding.hxx>
32 #include <unotools/wincodepage.hxx>
33 #include <osl/diagnose.h>
35 #include <document.hxx>
36 #include <xistream.hxx>
37 #include <xltools.hxx>
38 #include <docoptio.hxx>
39 #include <comphelper/sequenceashashmap.hxx>
40 #include <comphelper/processfactory.hxx>
43 #include <scerrors.hxx>
45 #include <excimp8.hxx>
53 static void lcl_getListOfStreams(SotStorage
* pStorage
, comphelper::SequenceAsHashMap
& aStreamsData
, const OUString
& sPrefix
)
55 SvStorageInfoList aElements
;
56 pStorage
->FillInfoList(&aElements
);
57 for (const auto & aElement
: aElements
)
59 OUString sStreamFullName
= sPrefix
.getLength() ? sPrefix
+ "/" + aElement
.GetName() : aElement
.GetName();
60 if (aElement
.IsStorage())
62 tools::SvRef
<SotStorage
> xSubStorage
= pStorage
->OpenSotStorage(aElement
.GetName(), StreamMode::STD_READ
| StreamMode::SHARE_DENYALL
);
63 lcl_getListOfStreams(xSubStorage
.get(), aStreamsData
, sStreamFullName
);
68 tools::SvRef
<SotStorageStream
> rStream
= pStorage
->OpenSotStream(aElement
.GetName(), StreamMode::READ
| StreamMode::SHARE_DENYALL
);
71 sal_Int32 nStreamSize
= rStream
->GetSize();
72 uno::Sequence
< sal_Int8
> oData
;
73 oData
.realloc(nStreamSize
);
74 sal_Int32 nReadBytes
= rStream
->ReadBytes(oData
.getArray(), nStreamSize
);
75 if (nStreamSize
== nReadBytes
)
76 aStreamsData
[sStreamFullName
] <<= oData
;
82 static tools::SvRef
<SotStorage
> lcl_DRMDecrypt(const SfxMedium
& rMedium
, const tools::SvRef
<SotStorage
>& rStorage
, std::shared_ptr
<SvStream
>& rNewStorageStrm
)
84 tools::SvRef
<SotStorage
> aNewStorage
;
86 // We have DRM encrypted storage. We should try to decrypt it first, if we can
87 uno::Sequence
< uno::Any
> aArguments
;
88 uno::Reference
<uno::XComponentContext
> xComponentContext(comphelper::getProcessComponentContext());
89 uno::Reference
< packages::XPackageEncryption
> xPackageEncryption(
90 xComponentContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
91 "com.sun.star.comp.oox.crypto.DRMDataSpace", aArguments
, xComponentContext
), uno::UNO_QUERY
);
93 if (!xPackageEncryption
.is())
95 // We do not know how to decrypt this
99 comphelper::SequenceAsHashMap aStreamsData
;
100 lcl_getListOfStreams(rStorage
.get(), aStreamsData
, "");
103 uno::Sequence
<beans::NamedValue
> aStreams
= aStreamsData
.getAsConstNamedValueList();
104 if (!xPackageEncryption
->readEncryptionInfo(aStreams
))
106 // We failed with decryption
110 tools::SvRef
<SotStorageStream
> rContentStream
= rStorage
->OpenSotStream("\011DRMContent", StreamMode::READ
| StreamMode::SHARE_DENYALL
);
111 if (!rContentStream
.is())
116 rNewStorageStrm
= std::make_shared
<SvMemoryStream
>();
118 uno::Reference
<io::XInputStream
> xInputStream(new utl::OSeekableInputStreamWrapper(rContentStream
.get(), false));
119 uno::Reference
<io::XOutputStream
> xDecryptedStream(new utl::OSeekableOutputStreamWrapper(*rNewStorageStrm
));
121 if (!xPackageEncryption
->decrypt(xInputStream
, xDecryptedStream
))
123 // We failed with decryption
127 rNewStorageStrm
->Seek(0);
129 // Further reading is done from new document
130 aNewStorage
= new SotStorage(*rNewStorageStrm
);
132 // Set the media descriptor data
133 uno::Sequence
<beans::NamedValue
> aEncryptionData
= xPackageEncryption
->createEncryptionData("");
134 rMedium
.GetItemSet()->Put(SfxUnoAnyItem(SID_ENCRYPTIONDATA
, uno::makeAny(aEncryptionData
)));
136 catch (const std::exception
&)
144 ErrCode
ScFormatFilterPluginImpl::ScImportExcel( SfxMedium
& rMedium
, ScDocument
* pDocument
, const EXCIMPFORMAT eFormat
)
146 // check the passed Calc document
147 OSL_ENSURE( pDocument
, "::ScImportExcel - no document" );
148 if( !pDocument
) return SCERR_IMPORT_INTERNAL
; // should not happen
150 /* Import all BIFF versions regardless on eFormat, needed for import of
151 external cells (file type detection returns Excel4.0). */
152 if( (eFormat
!= EIF_AUTO
) && (eFormat
!= EIF_BIFF_LE4
) && (eFormat
!= EIF_BIFF5
) && (eFormat
!= EIF_BIFF8
) )
154 OSL_FAIL( "::ScImportExcel - wrong file format specification" );
155 return SCERR_IMPORT_FORMAT
;
158 // check the input stream from medium
159 SvStream
* pMedStrm
= rMedium
.GetInStream();
160 OSL_ENSURE( pMedStrm
, "::ScImportExcel - medium without input stream" );
161 if( !pMedStrm
) return SCERR_IMPORT_OPEN
; // should not happen
163 SvStream
* pBookStrm
= nullptr; // The "Book"/"Workbook" stream containing main data.
164 XclBiff eBiff
= EXC_BIFF_UNKNOWN
; // The BIFF version of the main stream.
166 // try to open an OLE storage
167 tools::SvRef
<SotStorage
> xRootStrg
;
168 tools::SvRef
<SotStorageStream
> xStrgStrm
;
169 std::shared_ptr
<SvStream
> aNewStorageStrm
;
170 if( SotStorage::IsStorageFile( pMedStrm
) )
172 xRootStrg
= new SotStorage( pMedStrm
, false );
173 if( xRootStrg
->GetError() )
177 // try to open "Book" or "Workbook" stream in OLE storage
180 // Check if there is DRM encryption in storage
181 tools::SvRef
<SotStorageStream
> xDRMStrm
= ScfTools::OpenStorageStreamRead(xRootStrg
, "\011DRMContent");
184 xRootStrg
= lcl_DRMDecrypt(rMedium
, xRootStrg
, aNewStorageStrm
);
187 // try to open the "Book" stream
188 tools::SvRef
<SotStorageStream
> xBookStrm
= ScfTools::OpenStorageStreamRead( xRootStrg
, EXC_STREAM_BOOK
);
189 XclBiff eBookBiff
= xBookStrm
.is() ? XclImpStream::DetectBiffVersion( *xBookStrm
) : EXC_BIFF_UNKNOWN
;
191 // try to open the "Workbook" stream
192 tools::SvRef
<SotStorageStream
> xWorkbookStrm
= ScfTools::OpenStorageStreamRead( xRootStrg
, EXC_STREAM_WORKBOOK
);
193 XclBiff eWorkbookBiff
= xWorkbookStrm
.is() ? XclImpStream::DetectBiffVersion( *xWorkbookStrm
) : EXC_BIFF_UNKNOWN
;
195 // decide which stream to use
196 if( (eWorkbookBiff
!= EXC_BIFF_UNKNOWN
) && ((eBookBiff
== EXC_BIFF_UNKNOWN
) || (eWorkbookBiff
> eBookBiff
)) )
198 /* Only "Workbook" stream exists; or both streams exist,
199 and "Workbook" has higher BIFF version than "Book" stream. */
200 xStrgStrm
= xWorkbookStrm
;
201 eBiff
= eWorkbookBiff
;
203 else if( eBookBiff
!= EXC_BIFF_UNKNOWN
)
205 /* Only "Book" stream exists; or both streams exist,
206 and "Book" has higher BIFF version than "Workbook" stream. */
207 xStrgStrm
= xBookStrm
;
211 pBookStrm
= xStrgStrm
.get();
214 // no "Book" or "Workbook" stream found, try plain input stream from medium (even for BIFF5+)
217 eBiff
= XclImpStream::DetectBiffVersion( *pMedStrm
);
218 if( eBiff
!= EXC_BIFF_UNKNOWN
)
219 pBookStrm
= pMedStrm
;
222 // try to import the file
223 ErrCode eRet
= SCERR_IMPORT_UNKNOWN_BIFF
;
226 pBookStrm
->SetBufferSize( 0x8000 ); // still needed?
228 XclImpRootData
aImpData(
229 eBiff
, rMedium
, xRootStrg
, *pDocument
,
230 utl_getWinTextEncodingFromLangStr(utl_getLocaleForGlobalDefaultEncoding()));
231 std::unique_ptr
< ImportExcel
> xFilter
;
238 xFilter
.reset( new ImportExcel( aImpData
, *pBookStrm
) );
241 xFilter
.reset( new ImportExcel8( aImpData
, *pBookStrm
) );
243 default: DBG_ERROR_BIFF();
246 eRet
= xFilter
? xFilter
->Read() : SCERR_IMPORT_INTERNAL
;
252 static ErrCode
lcl_ExportExcelBiff( SfxMedium
& rMedium
, ScDocument
*pDocument
,
253 SvStream
* pMedStrm
, bool bBiff8
, rtl_TextEncoding eNach
)
255 uno::Reference
< packages::XPackageEncryption
> xPackageEncryption
;
256 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
257 const SfxUnoAnyItem
* pEncryptionDataItem
= SfxItemSet::GetItem
<SfxUnoAnyItem
>(rMedium
.GetItemSet(), SID_ENCRYPTIONDATA
, false);
258 SvStream
* pOriginalMediaStrm
= pMedStrm
;
259 std::shared_ptr
<SvStream
> pMediaStrm
;
260 if (pEncryptionDataItem
&& (pEncryptionDataItem
->GetValue() >>= aEncryptionData
))
262 ::comphelper::SequenceAsHashMap
aHashData(aEncryptionData
);
263 OUString sCryptoType
= aHashData
.getUnpackedValueOrDefault("CryptoType", OUString());
265 if (sCryptoType
.getLength())
267 uno::Reference
<uno::XComponentContext
> xComponentContext(comphelper::getProcessComponentContext());
268 uno::Sequence
<uno::Any
> aArguments
{
269 uno::makeAny(beans::NamedValue("Binary", uno::makeAny(true))) };
270 xPackageEncryption
.set(
271 xComponentContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
272 "com.sun.star.comp.oox.crypto." + sCryptoType
, aArguments
, xComponentContext
), uno::UNO_QUERY
);
274 if (xPackageEncryption
.is())
276 // We have an encryptor. Export document into memory stream and encrypt it later
277 pMediaStrm
= std::make_shared
<SvMemoryStream
>();
278 pMedStrm
= pMediaStrm
.get();
280 // Temp removal of EncryptionData to avoid password protection triggering
281 rMedium
.GetItemSet()->ClearItem(SID_ENCRYPTIONDATA
);
286 // try to open an OLE storage
287 tools::SvRef
<SotStorage
> xRootStrg
= new SotStorage( pMedStrm
, false );
288 if( xRootStrg
->GetError() ) return SCERR_IMPORT_OPEN
;
290 // create BIFF dependent strings
291 OUString aStrmName
, aClipName
, aClassName
;
294 aStrmName
= EXC_STREAM_WORKBOOK
;
296 aClassName
= "Microsoft Excel 97-Tabelle";
300 aStrmName
= EXC_STREAM_BOOK
;
302 aClassName
= "Microsoft Excel 5.0-Tabelle";
305 // open the "Book"/"Workbook" stream
306 tools::SvRef
<SotStorageStream
> xStrgStrm
= ScfTools::OpenStorageStreamWrite( xRootStrg
, aStrmName
);
307 if( !xStrgStrm
.is() || xStrgStrm
->GetError() ) return SCERR_IMPORT_OPEN
;
309 xStrgStrm
->SetBufferSize( 0x8000 ); // still needed?
311 ErrCode eRet
= SCERR_IMPORT_UNKNOWN_BIFF
;
312 XclExpRootData
aExpData( bBiff8
? EXC_BIFF8
: EXC_BIFF5
, rMedium
, xRootStrg
, *pDocument
, eNach
);
315 ExportBiff8
aFilter( aExpData
, *xStrgStrm
);
316 eRet
= aFilter
.Write();
320 ExportBiff5
aFilter( aExpData
, *xStrgStrm
);
321 eRet
= aFilter
.Write();
324 if( eRet
== SCWARN_IMPORT_RANGE_OVERFLOW
)
325 eRet
= SCWARN_EXPORT_MAXROW
;
327 SvGlobalName
aGlobName(MSO_EXCEL5_CLASSID
);
328 SotClipboardFormatId nClip
= SotExchange::RegisterFormatName( aClipName
);
329 xRootStrg
->SetClass( aGlobName
, nClip
, aClassName
);
334 if (xPackageEncryption
.is())
336 // Perform DRM encryption
339 xPackageEncryption
->setupEncryption(aEncryptionData
);
341 uno::Reference
<io::XInputStream
> xInputStream(new utl::OSeekableInputStreamWrapper(pMedStrm
, false));
342 uno::Sequence
<beans::NamedValue
> aStreams
= xPackageEncryption
->encrypt(xInputStream
);
344 tools::SvRef
<SotStorage
> xEncryptedRootStrg
= new SotStorage(pOriginalMediaStrm
, false);
345 for (const beans::NamedValue
& aStreamData
: std::as_const(aStreams
))
347 // To avoid long paths split and open substorages recursively
348 // Splitting paths manually, since comphelper::string::split is trimming special characters like \0x01, \0x09
349 tools::SvRef
<SotStorage
> pStorage
= xEncryptedRootStrg
.get();
354 OUString sPathElem
= aStreamData
.Name
.getToken(0, L
'/', idx
);
355 if (!sPathElem
.isEmpty())
359 sFileName
= sPathElem
;
363 pStorage
= pStorage
->OpenSotStorage(sPathElem
);
366 } while (pStorage
&& idx
>= 0);
370 eRet
= ERRCODE_IO_GENERAL
;
374 tools::SvRef
<SotStorageStream
> pStream
= pStorage
->OpenSotStream(sFileName
);
377 eRet
= ERRCODE_IO_GENERAL
;
380 uno::Sequence
<sal_Int8
> aStreamContent
;
381 aStreamData
.Value
>>= aStreamContent
;
382 size_t nBytesWritten
= pStream
->WriteBytes(aStreamContent
.getConstArray(), aStreamContent
.getLength());
383 if (nBytesWritten
!= static_cast<size_t>(aStreamContent
.getLength()))
385 eRet
= ERRCODE_IO_CANTWRITE
;
389 xEncryptedRootStrg
->Commit();
391 // Restore encryption data
392 rMedium
.GetItemSet()->Put(SfxUnoAnyItem(SID_ENCRYPTIONDATA
, uno::makeAny(aEncryptionData
)));
398 ErrCode
ScFormatFilterPluginImpl::ScExportExcel5( SfxMedium
& rMedium
, ScDocument
*pDocument
,
399 ExportFormatExcel eFormat
, rtl_TextEncoding eNach
)
401 if( eFormat
!= ExpBiff5
&& eFormat
!= ExpBiff8
)
402 return SCERR_IMPORT_NI
;
404 // check the passed Calc document
405 OSL_ENSURE( pDocument
, "::ScExportExcel5 - no document" );
406 if( !pDocument
) return SCERR_IMPORT_INTERNAL
; // should not happen
408 // check the output stream from medium
409 SvStream
* pMedStrm
= rMedium
.GetOutStream();
410 OSL_ENSURE( pMedStrm
, "::ScExportExcel5 - medium without output stream" );
411 if( !pMedStrm
) return SCERR_IMPORT_OPEN
; // should not happen
413 ErrCode eRet
= lcl_ExportExcelBiff(rMedium
, pDocument
, pMedStrm
, eFormat
== ExpBiff8
, eNach
);
417 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportCalcRTF(SvStream
&rStream
)
420 ScDocument aDocument
;
421 ScDocOptions aDocOpt
= aDocument
.GetDocOptions();
422 aDocOpt
.SetLookUpColRowNames(false);
423 aDocument
.SetDocOptions(aDocOpt
);
424 aDocument
.MakeTable(0);
425 aDocument
.EnableExecuteLink(false);
426 aDocument
.SetInsertingFromOtherDoc(true);
433 bRet
= ScFormatFilter::Get().ScImportRTF(rStream
, OUString(), &aDocument
, aRange
) == ERRCODE_NONE
;
435 catch (const std::range_error
&)
443 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportXLS(SvStream
& rStream
)
447 css::uno::Reference
<css::io::XInputStream
> xStm(new utl::OInputStreamWrapper(rStream
));
448 aMedium
.GetItemSet()->Put(SfxUnoAnyItem(SID_INPUTSTREAM
, css::uno::makeAny(xStm
)));
450 ScDocShellRef xDocShell
= new ScDocShell(SfxModelFlags::EMBEDDED_OBJECT
|
451 SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS
|
452 SfxModelFlags::DISABLE_DOCUMENT_RECOVERY
);
454 xDocShell
->DoInitNew();
456 ScDocument
& rDoc
= xDocShell
->GetDocument();
458 ScDocOptions aDocOpt
= rDoc
.GetDocOptions();
459 aDocOpt
.SetLookUpColRowNames(false);
460 rDoc
.SetDocOptions(aDocOpt
);
462 rDoc
.EnableExecuteLink(false);
463 rDoc
.SetInsertingFromOtherDoc(true);
464 rDoc
.InitDrawLayer(xDocShell
.get());
468 bRet
= ScFormatFilter::Get().ScImportExcel(aMedium
, &rDoc
, EIF_AUTO
) == ERRCODE_NONE
;
470 catch (const css::ucb::ContentCreationException
&)
473 catch (const std::out_of_range
&)
476 xDocShell
->DoClose();
481 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportDIF(SvStream
&rStream
)
484 ScDocument aDocument
;
485 ScDocOptions aDocOpt
= aDocument
.GetDocOptions();
486 aDocOpt
.SetLookUpColRowNames(false);
487 aDocument
.SetDocOptions(aDocOpt
);
488 aDocument
.MakeTable(0);
489 aDocument
.EnableExecuteLink(false);
490 aDocument
.SetInsertingFromOtherDoc(true);
491 return ScFormatFilter::Get().ScImportDif(rStream
, &aDocument
, ScAddress(0, 0, 0), RTL_TEXTENCODING_IBM_850
) == ERRCODE_NONE
;
494 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */