xref: /aoo42x/main/sc/source/filter/excel/excel.cxx (revision b77af630)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_scfilt.hxx"
26 
27 #include <sfx2/docfile.hxx>
28 #include <sfx2/objsh.hxx>
29 #include <sfx2/app.hxx>
30 #include <sfx2/frame.hxx>
31 #include <sfx2/request.hxx>
32 #include <sot/storage.hxx>
33 #include <sot/exchange.hxx>
34 #include <tools/globname.hxx>
35 #include <comphelper/mediadescriptor.hxx>
36 #include <comphelper/processfactory.hxx>
37 #include <com/sun/star/beans/NamedValue.hpp>
38 #include <com/sun/star/document/XFilter.hpp>
39 #include <com/sun/star/document/XImporter.hpp>
40 #include "scitems.hxx"
41 #include <svl/stritem.hxx>
42 #include "filter.hxx"
43 #include "document.hxx"
44 #include "xistream.hxx"
45 
46 #include "scerrors.hxx"
47 #include "root.hxx"
48 #include "imp_op.hxx"
49 #include "excimp8.hxx"
50 #include "exp_op.hxx"
51 
52 
ScImportExcel(SfxMedium & rMedium,ScDocument * pDocument,const EXCIMPFORMAT eFormat)53 FltError ScFormatFilterPluginImpl::ScImportExcel( SfxMedium& rMedium, ScDocument* pDocument, const EXCIMPFORMAT eFormat )
54 {
55     // check the passed Calc document
56     DBG_ASSERT( pDocument, "::ScImportExcel - no document" );
57     if( !pDocument ) return eERR_INTERN;        // should not happen
58 
59     /*  Import all BIFF versions regardless on eFormat, needed for import of
60         external cells (file type detection returns Excel4.0). */
61     if( (eFormat != EIF_AUTO) && (eFormat != EIF_BIFF_LE4) && (eFormat != EIF_BIFF5) && (eFormat != EIF_BIFF8) )
62     {
63         DBG_ERRORFILE( "::ScImportExcel - wrong file format specification" );
64         return eERR_FORMAT;
65     }
66 
67     // check the input stream from medium
68     SvStream* pMedStrm = rMedium.GetInStream();
69     DBG_ASSERT( pMedStrm, "::ScImportExcel - medium without input stream" );
70     if( !pMedStrm ) return eERR_OPEN;           // should not happen
71 
72 #if OSL_DEBUG_LEVEL > 0
73     using namespace ::com::sun::star;
74     using namespace ::comphelper;
75 
76     /*  Environment variable "OOO_OOXBIFFFILTER":
77         - "1" = use new OOX filter for import;
78         - undef/other = use old sc filter for import (OOX only as file dumper). */
79     const sal_Char* pcFileName = ::getenv( "OOO_OOXBIFFFILTER" );
80     bool bUseOoxFilter = pcFileName && (*pcFileName == '1') && (*(pcFileName + 1) == 0);
81     if( SfxObjectShell* pDocShell = pDocument->GetDocumentShell() ) try
82     {
83         uno::Reference< lang::XComponent > xComponent( pDocShell->GetModel(), uno::UNO_QUERY_THROW );
84 
85         uno::Sequence< beans::NamedValue > aArgSeq( 1 );
86         aArgSeq[ 0 ].Name = CREATE_OUSTRING( "UseBiffFilter" );
87         aArgSeq[ 0 ].Value <<= bUseOoxFilter;
88 
89         uno::Sequence< uno::Any > aArgs( 2 );
90         aArgs[ 0 ] <<= getProcessServiceFactory();
91         aArgs[ 1 ] <<= aArgSeq;
92         uno::Reference< document::XImporter > xImporter( ScfApiHelper::CreateInstanceWithArgs(
93             CREATE_OUSTRING( "com.sun.star.comp.oox.xls.ExcelBiffFilter" ), aArgs ), uno::UNO_QUERY_THROW );
94         xImporter->setTargetDocument( xComponent );
95 
96         MediaDescriptor aMediaDesc;
97         SfxItemSet* pItemSet = rMedium.GetItemSet();
98         if( pItemSet )
99         {
100             SFX_ITEMSET_ARG( pItemSet, pFileNameItem, SfxStringItem, SID_FILE_NAME, sal_False);
101             if( pFileNameItem )
102                 aMediaDesc[ MediaDescriptor::PROP_URL() ] <<= ::rtl::OUString( pFileNameItem->GetValue() );
103 
104             SFX_ITEMSET_ARG( pItemSet, pPasswordItem, SfxStringItem, SID_PASSWORD, sal_False);
105             if( pPasswordItem )
106                 aMediaDesc[ MediaDescriptor::PROP_PASSWORD() ] <<= ::rtl::OUString( pPasswordItem->GetValue() );
107 
108             SFX_ITEMSET_ARG( pItemSet, pEncryptionDataItem, SfxUnoAnyItem, SID_ENCRYPTIONDATA, sal_False);
109             if( pEncryptionDataItem )
110                 aMediaDesc[ MediaDescriptor::PROP_ENCRYPTIONDATA() ] = pEncryptionDataItem->GetValue();
111         }
112         aMediaDesc[ MediaDescriptor::PROP_INPUTSTREAM() ] <<= rMedium.GetInputStream();
113         aMediaDesc[ MediaDescriptor::PROP_INTERACTIONHANDLER() ] <<= rMedium.GetInteractionHandler();
114 
115         // call the filter
116         uno::Reference< document::XFilter > xFilter( xImporter, uno::UNO_QUERY_THROW );
117         bool bResult = xFilter->filter( aMediaDesc.getAsConstPropertyValueList() );
118 
119         // if filter returns false, document is invalid, or dumper has disabled import -> exit here
120         if( !bResult )
121             return ERRCODE_ABORT;
122 
123         // if OOX filter has been used, exit with OK code
124         if( bUseOoxFilter )
125             return eERR_OK;
126     }
127     catch( uno::Exception& )
128     {
129         if( bUseOoxFilter )
130             return ERRCODE_ABORT;
131         // else ignore exception and import the document with this filter
132     }
133 #endif
134 
135     SvStream* pBookStrm = 0;            // The "Book"/"Workbook" stream containing main data.
136     XclBiff eBiff = EXC_BIFF_UNKNOWN;   // The BIFF version of the main stream.
137 
138     // try to open an OLE storage
139     SotStorageRef xRootStrg;
140     SotStorageStreamRef xStrgStrm;
141     if( SotStorage::IsStorageFile( pMedStrm ) )
142     {
143         xRootStrg = new SotStorage( pMedStrm, sal_False );
144         if( xRootStrg->GetError() )
145             xRootStrg = 0;
146     }
147 
148     // try to open "Book" or "Workbook" stream in OLE storage
149     if( xRootStrg.Is() )
150     {
151         // try to open the "Book" stream
152         SotStorageStreamRef xBookStrm = ScfTools::OpenStorageStreamRead( xRootStrg, EXC_STREAM_BOOK );
153         XclBiff eBookBiff = xBookStrm.Is() ?  XclImpStream::DetectBiffVersion( *xBookStrm ) : EXC_BIFF_UNKNOWN;
154 
155         // try to open the "Workbook" stream
156         SotStorageStreamRef xWorkbookStrm = ScfTools::OpenStorageStreamRead( xRootStrg, EXC_STREAM_WORKBOOK );
157         XclBiff eWorkbookBiff = xWorkbookStrm.Is() ?  XclImpStream::DetectBiffVersion( *xWorkbookStrm ) : EXC_BIFF_UNKNOWN;
158 
159         // decide which stream to use
160         if( (eWorkbookBiff != EXC_BIFF_UNKNOWN) && ((eBookBiff == EXC_BIFF_UNKNOWN) || (eWorkbookBiff > eBookBiff)) )
161         {
162             /*  Only "Workbook" stream exists; or both streams exist,
163                 and "Workbook" has higher BIFF version than "Book" stream. */
164             xStrgStrm = xWorkbookStrm;
165             eBiff = eWorkbookBiff;
166         }
167         else if( eBookBiff != EXC_BIFF_UNKNOWN )
168         {
169             /*  Only "Book" stream exists; or both streams exist,
170                 and "Book" has higher BIFF version than "Workbook" stream. */
171             xStrgStrm = xBookStrm;
172             eBiff = eBookBiff;
173         }
174 
175         pBookStrm = xStrgStrm;
176     }
177 
178     // no "Book" or "Workbook" stream found, try plain input stream from medium (even for BIFF5+)
179     if( !pBookStrm )
180     {
181         eBiff = XclImpStream::DetectBiffVersion( *pMedStrm );
182         if( eBiff != EXC_BIFF_UNKNOWN )
183             pBookStrm = pMedStrm;
184     }
185 
186     // try to import the file
187     FltError eRet = eERR_UNKN_BIFF;
188     if( pBookStrm )
189     {
190         pBookStrm->SetBufferSize( 0x8000 );     // still needed?
191 
192         XclImpRootData aImpData( eBiff, rMedium, xRootStrg, *pDocument, RTL_TEXTENCODING_MS_1252 );
193         ::std::auto_ptr< ImportExcel > xFilter;
194         switch( eBiff )
195         {
196             case EXC_BIFF2:
197             case EXC_BIFF3:
198             case EXC_BIFF4:
199             case EXC_BIFF5:
200                 xFilter.reset( new ImportExcel( aImpData, *pBookStrm ) );
201             break;
202             case EXC_BIFF8:
203                 xFilter.reset( new ImportExcel8( aImpData, *pBookStrm ) );
204             break;
205             default:    DBG_ERROR_BIFF();
206         }
207 
208         eRet = xFilter.get() ? xFilter->Read() : eERR_INTERN;
209     }
210 
211     return eRet;
212 }
213 
214 
lcl_ExportExcelBiff(SfxMedium & rMedium,ScDocument * pDocument,SvStream * pMedStrm,sal_Bool bBiff8,CharSet eNach)215 static FltError lcl_ExportExcelBiff( SfxMedium& rMedium, ScDocument *pDocument,
216         SvStream* pMedStrm, sal_Bool bBiff8, CharSet eNach )
217 {
218     // try to open an OLE storage
219     SotStorageRef xRootStrg = new SotStorage( pMedStrm, sal_False );
220     if( xRootStrg->GetError() ) return eERR_OPEN;
221 
222     // create BIFF dependent strings
223     String aStrmName, aClipName, aClassName;
224 	if( bBiff8 )
225 	{
226         aStrmName = EXC_STREAM_WORKBOOK;
227         aClipName = CREATE_STRING( "Biff8" );
228         aClassName = CREATE_STRING( "Microsoft Excel 97-Tabelle" );
229 	}
230 	else
231 	{
232         aStrmName = EXC_STREAM_BOOK;
233         aClipName = CREATE_STRING( "Biff5" );
234         aClassName = CREATE_STRING( "Microsoft Excel 5.0-Tabelle" );
235 	}
236 
237     // open the "Book"/"Workbook" stream
238     SotStorageStreamRef xStrgStrm = ScfTools::OpenStorageStreamWrite( xRootStrg, aStrmName );
239     if( !xStrgStrm.Is() || xStrgStrm->GetError() ) return eERR_OPEN;
240 
241     xStrgStrm->SetBufferSize( 0x8000 );     // still needed?
242 
243     FltError eRet = eERR_UNKN_BIFF;
244     XclExpRootData aExpData( bBiff8 ? EXC_BIFF8 : EXC_BIFF5, rMedium, xRootStrg, *pDocument, eNach );
245     if ( bBiff8 )
246     {
247         ExportBiff8 aFilter( aExpData, *xStrgStrm );
248         eRet = aFilter.Write();
249     }
250     else
251     {
252         ExportBiff5 aFilter( aExpData, *xStrgStrm );
253         eRet = aFilter.Write();
254     }
255 
256     if( eRet == eERR_RNGOVRFLW )
257         eRet = SCWARN_EXPORT_MAXROW;
258 
259     SvGlobalName aGlobName( 0x00020810, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 );
260     sal_uInt32 nClip = SotExchange::RegisterFormatName( aClipName );
261     xRootStrg->SetClass( aGlobName, nClip, aClassName );
262 
263     xStrgStrm->Commit();
264     xRootStrg->Commit();
265 
266     return eRet;
267 }
268 
lcl_ExportExcel2007Xml(SfxMedium & rMedium,ScDocument * pDocument,SvStream * pMedStrm,CharSet eNach)269 static FltError lcl_ExportExcel2007Xml( SfxMedium& rMedium, ScDocument *pDocument,
270         SvStream* pMedStrm, CharSet eNach )
271 {
272     SotStorageRef xRootStrg = (SotStorage*) 0;
273 
274     XclExpRootData aExpData( EXC_BIFF8, rMedium, xRootStrg, *pDocument, eNach );
275     aExpData.meOutput = EXC_OUTPUT_XML_2007;
276 
277     ExportXml2007 aFilter( aExpData, *pMedStrm );
278 
279     FltError eRet = aFilter.Write();
280 
281     return eRet;
282 }
283 
ScExportExcel5(SfxMedium & rMedium,ScDocument * pDocument,ExportFormatExcel eFormat,CharSet eNach)284 FltError ScFormatFilterPluginImpl::ScExportExcel5( SfxMedium& rMedium, ScDocument *pDocument,
285     ExportFormatExcel eFormat, CharSet eNach )
286 {
287     if( eFormat != ExpBiff5 && eFormat != ExpBiff8 && eFormat != Exp2007Xml )
288         return eERR_NI;
289 
290     // check the passed Calc document
291     DBG_ASSERT( pDocument, "::ScImportExcel - no document" );
292     if( !pDocument ) return eERR_INTERN;        // should not happen
293 
294     // check the output stream from medium
295     SvStream* pMedStrm = rMedium.GetOutStream();
296     DBG_ASSERT( pMedStrm, "::ScExportExcel5 - medium without output stream" );
297     if( !pMedStrm ) return eERR_OPEN;           // should not happen
298 
299     FltError eRet = eERR_UNKN_BIFF;
300     if( eFormat == ExpBiff5 || eFormat == ExpBiff8 )
301         eRet = lcl_ExportExcelBiff( rMedium, pDocument, pMedStrm, eFormat == ExpBiff8, eNach );
302     else if( eFormat == Exp2007Xml )
303         eRet = lcl_ExportExcel2007Xml( rMedium, pDocument, pMedStrm, eNach );
304 
305 	return eRet;
306 }
307 
308 
309 
310