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 #include "oox/xls/workbookfragment.hxx"
25
26 #include <com/sun/star/table/CellAddress.hpp>
27 #include "oox/core/filterbase.hxx"
28 #include "oox/drawingml/themefragmenthandler.hxx"
29 #include "oox/helper/attributelist.hxx"
30 #include "oox/helper/progressbar.hxx"
31 #include "oox/helper/propertyset.hxx"
32 #include "oox/ole/olestorage.hxx"
33 #include "oox/xls/biffinputstream.hxx"
34 #include "oox/xls/chartsheetfragment.hxx"
35 #include "oox/xls/connectionsfragment.hxx"
36 #include "oox/xls/externallinkbuffer.hxx"
37 #include "oox/xls/externallinkfragment.hxx"
38 #include "oox/xls/pivotcachebuffer.hxx"
39 #include "oox/xls/sharedstringsbuffer.hxx"
40 #include "oox/xls/sharedstringsfragment.hxx"
41 #include "oox/xls/stylesfragment.hxx"
42 #include "oox/xls/tablebuffer.hxx"
43 #include "oox/xls/themebuffer.hxx"
44 #include "oox/xls/viewsettings.hxx"
45 #include "oox/xls/workbooksettings.hxx"
46 #include "oox/xls/worksheetbuffer.hxx"
47 #include "oox/xls/worksheetfragment.hxx"
48
49 namespace oox {
50 namespace xls {
51
52 // ============================================================================
53
54 using namespace ::com::sun::star::io;
55 using namespace ::com::sun::star::table;
56 using namespace ::com::sun::star::uno;
57 using namespace ::oox::core;
58
59 using ::oox::drawingml::ThemeFragmentHandler;
60 using ::rtl::OUString;
61
62 // ============================================================================
63
64 namespace {
65
66 const double PROGRESS_LENGTH_GLOBALS = 0.1; /// 10% of progress bar for globals import.
67
68 } // namespace
69
70 // ============================================================================
71
WorkbookFragment(const WorkbookHelper & rHelper,const OUString & rFragmentPath)72 WorkbookFragment::WorkbookFragment( const WorkbookHelper& rHelper, const OUString& rFragmentPath ) :
73 WorkbookFragmentBase( rHelper, rFragmentPath )
74 {
75 }
76
onCreateContext(sal_Int32 nElement,const AttributeList & rAttribs)77 ContextHandlerRef WorkbookFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
78 {
79 switch( getCurrentElement() )
80 {
81 case XML_ROOT_CONTEXT:
82 if( nElement == XLS_TOKEN( workbook ) ) return this;
83 break;
84
85 case XLS_TOKEN( workbook ):
86 switch( nElement )
87 {
88 case XLS_TOKEN( sheets ):
89 case XLS_TOKEN( bookViews ):
90 case XLS_TOKEN( externalReferences ):
91 case XLS_TOKEN( definedNames ):
92 case XLS_TOKEN( pivotCaches ): return this;
93
94 case XLS_TOKEN( fileSharing ): getWorkbookSettings().importFileSharing( rAttribs ); break;
95 case XLS_TOKEN( workbookPr ): getWorkbookSettings().importWorkbookPr( rAttribs ); break;
96 case XLS_TOKEN( calcPr ): getWorkbookSettings().importCalcPr( rAttribs ); break;
97 case XLS_TOKEN( oleSize ): getViewSettings().importOleSize( rAttribs ); break;
98 }
99 break;
100
101 case XLS_TOKEN( sheets ):
102 if( nElement == XLS_TOKEN( sheet ) ) getWorksheets().importSheet( rAttribs );
103 break;
104 case XLS_TOKEN( bookViews ):
105 if( nElement == XLS_TOKEN( workbookView ) ) getViewSettings().importWorkbookView( rAttribs );
106 break;
107 case XLS_TOKEN( externalReferences ):
108 if( nElement == XLS_TOKEN( externalReference ) ) importExternalReference( rAttribs );
109 break;
110 case XLS_TOKEN( definedNames ):
111 if( nElement == XLS_TOKEN( definedName ) ) { importDefinedName( rAttribs ); return this; } // collect formula
112 break;
113 case XLS_TOKEN( pivotCaches ):
114 if( nElement == XLS_TOKEN( pivotCache ) ) importPivotCache( rAttribs );
115 break;
116 }
117 return 0;
118 }
119
onCharacters(const OUString & rChars)120 void WorkbookFragment::onCharacters( const OUString& rChars )
121 {
122 if( isCurrentElement( XLS_TOKEN( definedName ) ) && mxCurrName.get() )
123 mxCurrName->setFormula( rChars );
124 }
125
onCreateRecordContext(sal_Int32 nRecId,SequenceInputStream & rStrm)126 ContextHandlerRef WorkbookFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
127 {
128 switch( getCurrentElement() )
129 {
130 case XML_ROOT_CONTEXT:
131 if( nRecId == BIFF12_ID_WORKBOOK ) return this;
132 break;
133
134 case BIFF12_ID_WORKBOOK:
135 switch( nRecId )
136 {
137 case BIFF12_ID_SHEETS:
138 case BIFF12_ID_BOOKVIEWS:
139 case BIFF12_ID_EXTERNALREFS:
140 case BIFF12_ID_PIVOTCACHES: return this;
141
142 case BIFF12_ID_FILESHARING: getWorkbookSettings().importFileSharing( rStrm ); break;
143 case BIFF12_ID_WORKBOOKPR: getWorkbookSettings().importWorkbookPr( rStrm ); break;
144 case BIFF12_ID_CALCPR: getWorkbookSettings().importCalcPr( rStrm ); break;
145 case BIFF12_ID_OLESIZE: getViewSettings().importOleSize( rStrm ); break;
146 case BIFF12_ID_DEFINEDNAME: getDefinedNames().importDefinedName( rStrm ); break;
147 }
148 break;
149
150 case BIFF12_ID_SHEETS:
151 if( nRecId == BIFF12_ID_SHEET ) getWorksheets().importSheet( rStrm );
152 break;
153 case BIFF12_ID_BOOKVIEWS:
154 if( nRecId == BIFF12_ID_WORKBOOKVIEW ) getViewSettings().importWorkbookView( rStrm );
155 break;
156
157 case BIFF12_ID_EXTERNALREFS:
158 switch( nRecId )
159 {
160 case BIFF12_ID_EXTERNALREF: importExternalRef( rStrm ); break;
161 case BIFF12_ID_EXTERNALSELF: getExternalLinks().importExternalSelf( rStrm ); break;
162 case BIFF12_ID_EXTERNALSAME: getExternalLinks().importExternalSame( rStrm ); break;
163 case BIFF12_ID_EXTERNALADDIN: getExternalLinks().importExternalAddin( rStrm ); break;
164 case BIFF12_ID_EXTERNALSHEETS: getExternalLinks().importExternalSheets( rStrm ); break;
165 }
166 break;
167
168 case BIFF12_ID_PIVOTCACHES:
169 if( nRecId == BIFF12_ID_PIVOTCACHE ) importPivotCache( rStrm );
170 }
171 return 0;
172 }
173
getRecordInfos() const174 const RecordInfo* WorkbookFragment::getRecordInfos() const
175 {
176 static const RecordInfo spRecInfos[] =
177 {
178 { BIFF12_ID_BOOKVIEWS, BIFF12_ID_BOOKVIEWS + 1 },
179 { BIFF12_ID_EXTERNALREFS, BIFF12_ID_EXTERNALREFS + 1 },
180 { BIFF12_ID_FUNCTIONGROUPS, BIFF12_ID_FUNCTIONGROUPS + 2 },
181 { BIFF12_ID_PIVOTCACHE, BIFF12_ID_PIVOTCACHE + 1 },
182 { BIFF12_ID_PIVOTCACHES, BIFF12_ID_PIVOTCACHES + 1 },
183 { BIFF12_ID_SHEETS, BIFF12_ID_SHEETS + 1 },
184 { BIFF12_ID_WORKBOOK, BIFF12_ID_WORKBOOK + 1 },
185 { -1, -1 }
186 };
187 return spRecInfos;
188 }
189
finalizeImport()190 void WorkbookFragment::finalizeImport()
191 {
192 ISegmentProgressBarRef xGlobalSegment = getProgressBar().createSegment( PROGRESS_LENGTH_GLOBALS );
193
194 // read the theme substream
195 OUString aThemeFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "theme" ) );
196 if( aThemeFragmentPath.getLength() > 0 )
197 importOoxFragment( new ThemeFragmentHandler( getFilter(), aThemeFragmentPath, getTheme() ) );
198 xGlobalSegment->setPosition( 0.25 );
199
200 // read the styles substream (requires finalized theme buffer)
201 OUString aStylesFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "styles" ) );
202 if( aStylesFragmentPath.getLength() > 0 )
203 importOoxFragment( new StylesFragment( *this, aStylesFragmentPath ) );
204 xGlobalSegment->setPosition( 0.5 );
205
206 // read the shared string table substream (requires finalized styles buffer)
207 OUString aSstFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "sharedStrings" ) );
208 if( aSstFragmentPath.getLength() > 0 )
209 importOoxFragment( new SharedStringsFragment( *this, aSstFragmentPath ) );
210 xGlobalSegment->setPosition( 0.75 );
211
212 // read the connections substream
213 OUString aConnFragmentPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "connections" ) );
214 if( aConnFragmentPath.getLength() > 0 )
215 importOoxFragment( new ConnectionsFragment( *this, aConnFragmentPath ) );
216 xGlobalSegment->setPosition( 1.0 );
217
218 /* Create fragments for all sheets, before importing them. Needed to do
219 some preprocessing in the fragment constructors, e.g. loading the table
220 fragments for all sheets that are needed before the cell formulas are
221 loaded. Additionally, the instances of the WorkbookGlobals structures
222 have to be stored for every sheet. */
223 typedef ::std::pair< WorksheetGlobalsRef, FragmentHandlerRef > SheetFragmentHandler;
224 typedef ::std::vector< SheetFragmentHandler > SheetFragmentVector;
225 SheetFragmentVector aSheetFragments;
226 WorksheetBuffer& rWorksheets = getWorksheets();
227 sal_Int32 nWorksheetCount = rWorksheets.getWorksheetCount();
228 for( sal_Int32 nWorksheet = 0; nWorksheet < nWorksheetCount; ++nWorksheet )
229 {
230 sal_Int16 nCalcSheet = rWorksheets.getCalcSheetIndex( nWorksheet );
231 const Relation* pRelation = getRelations().getRelationFromRelId( rWorksheets.getWorksheetRelId( nWorksheet ) );
232 if( (nCalcSheet >= 0) && pRelation )
233 {
234 // get fragment path of the sheet
235 OUString aFragmentPath = getFragmentPathFromRelation( *pRelation );
236 OSL_ENSURE( aFragmentPath.getLength() > 0, "WorkbookFragment::finalizeImport - cannot access sheet fragment" );
237 if( aFragmentPath.getLength() > 0 )
238 {
239 double fSegmentLength = getProgressBar().getFreeLength() / (nWorksheetCount - nWorksheet);
240 ISegmentProgressBarRef xSheetSegment = getProgressBar().createSegment( fSegmentLength );
241
242 // get the sheet type according to the relations type
243 WorksheetType eSheetType = SHEETTYPE_EMPTYSHEET;
244 if( pRelation->maType == CREATE_OFFICEDOC_RELATION_TYPE( "worksheet" ) )
245 eSheetType = SHEETTYPE_WORKSHEET;
246 else if( pRelation->maType == CREATE_OFFICEDOC_RELATION_TYPE( "chartsheet" ) )
247 eSheetType = SHEETTYPE_CHARTSHEET;
248 else if( (pRelation->maType == CREATE_MSOFFICE_RELATION_TYPE( "xlMacrosheet" )) ||
249 (pRelation->maType == CREATE_MSOFFICE_RELATION_TYPE( "xlIntlMacrosheet" )) )
250 eSheetType = SHEETTYPE_MACROSHEET;
251 else if( pRelation->maType == CREATE_OFFICEDOC_RELATION_TYPE( "dialogsheet" ) )
252 eSheetType = SHEETTYPE_DIALOGSHEET;
253 OSL_ENSURE( eSheetType != SHEETTYPE_EMPTYSHEET, "WorkbookFragment::finalizeImport - unknown sheet type" );
254 if( eSheetType != SHEETTYPE_EMPTYSHEET )
255 {
256 // create the WorksheetGlobals object
257 WorksheetGlobalsRef xSheetGlob = WorksheetHelper::constructGlobals( *this, xSheetSegment, eSheetType, nCalcSheet );
258 OSL_ENSURE( xSheetGlob.get(), "WorkbookFragment::finalizeImport - missing sheet in document" );
259 if( xSheetGlob.get() )
260 {
261 // create the sheet fragment handler
262 ::rtl::Reference< WorksheetFragmentBase > xFragment;
263 switch( eSheetType )
264 {
265 case SHEETTYPE_WORKSHEET:
266 case SHEETTYPE_MACROSHEET:
267 case SHEETTYPE_DIALOGSHEET:
268 xFragment.set( new WorksheetFragment( *xSheetGlob, aFragmentPath ) );
269 break;
270 case SHEETTYPE_CHARTSHEET:
271 xFragment.set( new ChartsheetFragment( *xSheetGlob, aFragmentPath ) );
272 break;
273 default:
274 OSL_ENSURE( false, "WorkbookFragment::finalizeImport - unexpected sheet type" );
275 }
276
277 // insert the fragment into the map
278 if( xFragment.is() )
279 aSheetFragments.push_back( SheetFragmentHandler( xSheetGlob, xFragment.get() ) );
280 }
281 }
282 }
283 }
284 }
285
286 // create all defined names and database ranges
287 getDefinedNames().finalizeImport();
288 getTables().finalizeImport();
289
290 // load all worksheets
291 for( SheetFragmentVector::iterator aIt = aSheetFragments.begin(), aEnd = aSheetFragments.end(); aIt != aEnd; ++aIt )
292 {
293 // import the sheet fragment
294 importOoxFragment( aIt->second );
295 // delete fragment object and WorkbookGlobals object, will free all allocated sheet buffers
296 aIt->second.clear();
297 aIt->first.reset();
298 }
299
300 // open the VBA project storage
301 OUString aVbaFragmentPath = getFragmentPathFromFirstType( CREATE_MSOFFICE_RELATION_TYPE( "vbaProject" ) );
302 if( aVbaFragmentPath.getLength() > 0 )
303 {
304 Reference< XInputStream > xInStrm = getBaseFilter().openInputStream( aVbaFragmentPath );
305 if( xInStrm.is() )
306 setVbaProjectStorage( StorageRef( new ::oox::ole::OleStorage( getBaseFilter().getComponentContext(), xInStrm, false ) ) );
307 }
308
309 // final conversions, e.g. calculation settings and view settings
310 finalizeWorkbookImport();
311 }
312
313 // private --------------------------------------------------------------------
314
importExternalReference(const AttributeList & rAttribs)315 void WorkbookFragment::importExternalReference( const AttributeList& rAttribs )
316 {
317 if( ExternalLink* pExtLink = getExternalLinks().importExternalReference( rAttribs ).get() )
318 importExternalLinkFragment( *pExtLink );
319 }
320
importDefinedName(const AttributeList & rAttribs)321 void WorkbookFragment::importDefinedName( const AttributeList& rAttribs )
322 {
323 mxCurrName = getDefinedNames().importDefinedName( rAttribs );
324 }
325
importPivotCache(const AttributeList & rAttribs)326 void WorkbookFragment::importPivotCache( const AttributeList& rAttribs )
327 {
328 sal_Int32 nCacheId = rAttribs.getInteger( XML_cacheId, -1 );
329 OUString aRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
330 importPivotCacheDefFragment( aRelId, nCacheId );
331 }
332
importExternalRef(SequenceInputStream & rStrm)333 void WorkbookFragment::importExternalRef( SequenceInputStream& rStrm )
334 {
335 if( ExternalLink* pExtLink = getExternalLinks().importExternalRef( rStrm ).get() )
336 importExternalLinkFragment( *pExtLink );
337 }
338
importPivotCache(SequenceInputStream & rStrm)339 void WorkbookFragment::importPivotCache( SequenceInputStream& rStrm )
340 {
341 sal_Int32 nCacheId = rStrm.readInt32();
342 OUString aRelId = BiffHelper::readString( rStrm );
343 importPivotCacheDefFragment( aRelId, nCacheId );
344 }
345
importExternalLinkFragment(ExternalLink & rExtLink)346 void WorkbookFragment::importExternalLinkFragment( ExternalLink& rExtLink )
347 {
348 OUString aFragmentPath = getFragmentPathFromRelId( rExtLink.getRelId() );
349 if( aFragmentPath.getLength() > 0 )
350 importOoxFragment( new ExternalLinkFragment( *this, aFragmentPath, rExtLink ) );
351 }
352
importPivotCacheDefFragment(const OUString & rRelId,sal_Int32 nCacheId)353 void WorkbookFragment::importPivotCacheDefFragment( const OUString& rRelId, sal_Int32 nCacheId )
354 {
355 // pivot caches will be imported on demand, here we just store the fragment path in the buffer
356 getPivotCaches().registerPivotCacheFragment( nCacheId, getFragmentPathFromRelId( rRelId ) );
357 }
358
359 // ============================================================================
360
BiffWorkbookFragment(const WorkbookHelper & rHelper,const OUString & rStrmName)361 BiffWorkbookFragment::BiffWorkbookFragment( const WorkbookHelper& rHelper, const OUString& rStrmName ) :
362 BiffWorkbookFragmentBase( rHelper, rStrmName )
363 {
364 }
365
importFragment()366 bool BiffWorkbookFragment::importFragment()
367 {
368 bool bRet = false;
369
370 BiffFragmentType eFragment = startFragment( getBiff() );
371 switch( eFragment )
372 {
373 case BIFF_FRAGMENT_GLOBALS:
374 {
375 BiffInputStream& rStrm = getInputStream();
376 // import workbook globals fragment and create sheets in document
377 ISegmentProgressBarRef xGlobalsProgress = getProgressBar().createSegment( PROGRESS_LENGTH_GLOBALS );
378 bRet = importGlobalsFragment( *xGlobalsProgress );
379 // load sheet fragments (do not return false in bRet on missing/broken sheets)
380 WorksheetBuffer& rWorksheets = getWorksheets();
381 bool bNextSheet = bRet;
382 for( sal_Int32 nWorksheet = 0, nWorksheetCount = rWorksheets.getWorksheetCount(); bNextSheet && (nWorksheet < nWorksheetCount); ++nWorksheet )
383 {
384 // calculate progress size for the sheet
385 double fSegmentLength = getProgressBar().getFreeLength() / (nWorksheetCount - nWorksheet);
386 ISegmentProgressBarRef xSheetProgress = getProgressBar().createSegment( fSegmentLength );
387 /* Try to start a new sheet fragment. The SHEET records point to the
388 first record of the sheet fragment which is usually a BOF record. */
389 BiffFragmentType eSheetFragment = BIFF_FRAGMENT_UNKNOWN;
390 sal_Int64 nRecHandle = rWorksheets.getBiffRecordHandle( nWorksheet );
391 if( rStrm.startRecordByHandle( nRecHandle ) )
392 {
393 /* #i109800# Stream may point to any record of the sheet fragment.
394 Check the record identifier before calling startFragment(). */
395 bool bIsBofRec = BiffHelper::isBofRecord( rStrm );
396 /* Rewind the record. If it is the BOF record, it will be read in
397 startFragment(). In every case, stream will point before the
398 first available non-BOF record. */
399 rStrm.rewindRecord();
400 // if the BOF record is missing, a regular worksheet will be assumed
401 eSheetFragment = bIsBofRec ? startFragment( getBiff() ) : BIFF_FRAGMENT_WORKSHEET;
402 }
403 sal_Int16 nCalcSheet = rWorksheets.getCalcSheetIndex( nWorksheet );
404 bNextSheet = importSheetFragment( *xSheetProgress, eSheetFragment, nCalcSheet );
405 }
406 }
407 break;
408
409 case BIFF_FRAGMENT_WORKSPACE:
410 {
411 bRet = importWorkspaceFragment();
412 // sheets are embedded in workspace fragment, nothing to do here
413 }
414 break;
415
416 case BIFF_FRAGMENT_WORKSHEET:
417 case BIFF_FRAGMENT_CHARTSHEET:
418 case BIFF_FRAGMENT_MACROSHEET:
419 {
420 /* Single sheet without globals
421 - #i62752# possible in all BIFF versions
422 - do not return false in bRet on missing/broken sheets. */
423 getWorksheets().initializeSingleSheet();
424 importSheetFragment( getProgressBar(), eFragment, 0 );
425 // success, even if stream is broken
426 bRet = true;
427 }
428 break;
429
430 default:;
431 }
432
433 // final conversions, e.g. calculation settings and view settings
434 if( bRet )
435 finalizeWorkbookImport();
436
437 return bRet;
438 }
439
importWorkspaceFragment()440 bool BiffWorkbookFragment::importWorkspaceFragment()
441 {
442 // enable workbook mode, has not been set yet in BIFF4 workspace files
443 setIsWorkbookFile();
444
445 WorksheetBuffer& rWorksheets = getWorksheets();
446 bool bRet = true;
447
448 // import the workspace globals
449 ISegmentProgressBarRef xGlobalsProgress = getProgressBar().createSegment( PROGRESS_LENGTH_GLOBALS );
450 bool bLoop = true;
451 BiffInputStream& rStrm = getInputStream();
452 while( bRet && bLoop && rStrm.startNextRecord() && (rStrm.getRecId() != BIFF_ID_EOF) )
453 {
454 switch( rStrm.getRecId() )
455 {
456 case BIFF_ID_SHEET: rWorksheets.importSheet( rStrm ); break;
457 case BIFF_ID_CODEPAGE: setCodePage( rStrm.readuInt16() ); break;
458 case BIFF_ID_FILEPASS: bRet = getCodecHelper().importFilePass( rStrm ); break;
459 case BIFF_ID_SHEETHEADER: rStrm.rewindRecord(); bLoop = false; break;
460 }
461 }
462 xGlobalsProgress->setPosition( 1.0 );
463
464 // load sheet fragments (do not return false in bRet on missing/broken sheets)
465 bool bNextSheet = bRet;
466 for( sal_Int32 nWorksheet = 0, nWorksheetCount = rWorksheets.getWorksheetCount(); bNextSheet && (nWorksheet < nWorksheetCount); ++nWorksheet )
467 {
468 // try to start a new sheet fragment (with leading SHEETHEADER record)
469 bNextSheet = rStrm.startNextRecord() && (rStrm.getRecId() == BIFF_ID_SHEETHEADER);
470 if( bNextSheet )
471 {
472 double fSegmentLength = getProgressBar().getFreeLength() / (nWorksheetCount - nWorksheet);
473 ISegmentProgressBarRef xSheetProgress = getProgressBar().createSegment( fSegmentLength );
474 /* Read current sheet name (sheet substreams may not be in the
475 same order as SHEET records are). */
476 rStrm.skip( 4 );
477 OUString aSheetName = rStrm.readByteStringUC( false, getTextEncoding() );
478 sal_Int16 nCurrSheet = rWorksheets.getCalcSheetIndex( aSheetName );
479 // load the sheet fragment records
480 BiffFragmentType eSheetFragment = startFragment( getBiff() );
481 bNextSheet = importSheetFragment( *xSheetProgress, eSheetFragment, nCurrSheet );
482 // do not return false in bRet on missing/broken sheets
483 }
484 }
485
486 return bRet;
487 }
488
importGlobalsFragment(ISegmentProgressBar & rProgressBar)489 bool BiffWorkbookFragment::importGlobalsFragment( ISegmentProgressBar& rProgressBar )
490 {
491 WorkbookSettings& rWorkbookSett = getWorkbookSettings();
492 ViewSettings& rViewSett = getViewSettings();
493 SharedStringsBuffer& rSharedStrings = getSharedStrings();
494 StylesBuffer& rStyles = getStyles();
495 WorksheetBuffer& rWorksheets = getWorksheets();
496 PivotCacheBuffer& rPivotCaches = getPivotCaches();
497 bool bHasVbaProject = false;
498 bool bEmptyVbaProject = false;
499
500 // collect records that need to be loaded in a second pass
501 typedef ::std::vector< sal_Int64 > RecordHandleVec;
502 RecordHandleVec aExtLinkRecs;
503
504 bool bRet = true;
505 bool bLoop = true;
506 BiffInputStream& rStrm = getInputStream();
507 while( bRet && bLoop && rStrm.startNextRecord() )
508 {
509 sal_uInt16 nRecId = rStrm.getRecId();
510 bool bExtLinkRec = false;
511
512 /* #i56376# BIFF5-BIFF8: If an EOF record for globals is missing,
513 simulate it. The issue is about a document where the sheet fragment
514 starts directly after the EXTSST record, without terminating the
515 globals fragment with an EOF record. */
516 if( BiffHelper::isBofRecord( rStrm ) || (nRecId == BIFF_ID_EOF) )
517 {
518 bLoop = false;
519 }
520 else switch( nRecId )
521 {
522 // records in all BIFF versions
523 case BIFF_ID_CODEPAGE: setCodePage( rStrm.readuInt16() ); break;
524 case BIFF_ID_DATEMODE: rWorkbookSett.importDateMode( rStrm ); break;
525 case BIFF_ID_FILEPASS: bRet = getCodecHelper().importFilePass( rStrm ); break;
526 case BIFF_ID_PRECISION: rWorkbookSett.importPrecision( rStrm ); break;
527 case BIFF_ID_WINDOW1: rViewSett.importWindow1( rStrm ); break;
528
529 // BIFF specific records
530 default: switch( getBiff() )
531 {
532 case BIFF2: switch( nRecId )
533 {
534 case BIFF2_ID_DEFINEDNAME: bExtLinkRec = true; break;
535 case BIFF2_ID_EXTERNALNAME: bExtLinkRec = true; break;
536 case BIFF_ID_EXTERNSHEET: bExtLinkRec = true; break;
537 case BIFF2_ID_FONT: rStyles.importFont( rStrm ); break;
538 case BIFF_ID_FONTCOLOR: rStyles.importFontColor( rStrm ); break;
539 case BIFF2_ID_FORMAT: rStyles.importFormat( rStrm ); break;
540 case BIFF2_ID_XF: rStyles.importXf( rStrm ); break;
541 }
542 break;
543
544 case BIFF3: switch( nRecId )
545 {
546 case BIFF_ID_CRN: bExtLinkRec = true; break;
547 case BIFF3_ID_DEFINEDNAME: bExtLinkRec = true; break;
548 case BIFF3_ID_EXTERNALNAME: bExtLinkRec = true; break;
549 case BIFF_ID_EXTERNSHEET: bExtLinkRec = true; break;
550 case BIFF_ID_FILESHARING: rWorkbookSett.importFileSharing( rStrm ); break;
551 case BIFF3_ID_FONT: rStyles.importFont( rStrm ); break;
552 case BIFF2_ID_FORMAT: rStyles.importFormat( rStrm ); break;
553 case BIFF_ID_HIDEOBJ: rWorkbookSett.importHideObj( rStrm ); break;
554 case BIFF_ID_PALETTE: rStyles.importPalette( rStrm ); break;
555 case BIFF_ID_STYLE: rStyles.importStyle( rStrm ); break;
556 case BIFF_ID_XCT: bExtLinkRec = true; break;
557 case BIFF3_ID_XF: rStyles.importXf( rStrm ); break;
558 }
559 break;
560
561 case BIFF4: switch( nRecId )
562 {
563 case BIFF_ID_CRN: bExtLinkRec = true; break;
564 case BIFF3_ID_DEFINEDNAME: bExtLinkRec = true; break;
565 case BIFF3_ID_EXTERNALNAME: bExtLinkRec = true; break;
566 case BIFF_ID_EXTERNSHEET: bExtLinkRec = true; break;
567 case BIFF_ID_FILESHARING: rWorkbookSett.importFileSharing( rStrm ); break;
568 case BIFF3_ID_FONT: rStyles.importFont( rStrm ); break;
569 case BIFF4_ID_FORMAT: rStyles.importFormat( rStrm ); break;
570 case BIFF_ID_HIDEOBJ: rWorkbookSett.importHideObj( rStrm ); break;
571 case BIFF_ID_PALETTE: rStyles.importPalette( rStrm ); break;
572 case BIFF_ID_STYLE: rStyles.importStyle( rStrm ); break;
573 case BIFF_ID_XCT: bExtLinkRec = true; break;
574 case BIFF4_ID_XF: rStyles.importXf( rStrm ); break;
575 }
576 break;
577
578 case BIFF5: switch( nRecId )
579 {
580 case BIFF_ID_BOOKBOOL: rWorkbookSett.importBookBool( rStrm ); break;
581 case BIFF_ID_CRN: bExtLinkRec = true; break;
582 case BIFF5_ID_DEFINEDNAME: bExtLinkRec = true; break;
583 case BIFF5_ID_EXTERNALNAME: bExtLinkRec = true; break;
584 case BIFF_ID_EXTERNSHEET: bExtLinkRec = true; break;
585 case BIFF_ID_FILESHARING: rWorkbookSett.importFileSharing( rStrm ); break;
586 case BIFF5_ID_FONT: rStyles.importFont( rStrm ); break;
587 case BIFF4_ID_FORMAT: rStyles.importFormat( rStrm ); break;
588 case BIFF_ID_HIDEOBJ: rWorkbookSett.importHideObj( rStrm ); break;
589 case BIFF_ID_OLESIZE: rViewSett.importOleSize( rStrm ); break;
590 case BIFF_ID_PALETTE: rStyles.importPalette( rStrm ); break;
591 case BIFF_ID_PIVOTCACHE: rPivotCaches.importPivotCacheRef( rStrm ); break;
592 case BIFF_ID_SHEET: rWorksheets.importSheet( rStrm ); break;
593 case BIFF_ID_STYLE: rStyles.importStyle( rStrm ); break;
594 case BIFF_ID_XCT: bExtLinkRec = true; break;
595 case BIFF5_ID_XF: rStyles.importXf( rStrm ); break;
596 }
597 break;
598
599 case BIFF8: switch( nRecId )
600 {
601 case BIFF_ID_BOOKBOOL: rWorkbookSett.importBookBool( rStrm ); break;
602 case BIFF_ID_CODENAME: rWorkbookSett.importCodeName( rStrm ); break;
603 case BIFF_ID_CRN: bExtLinkRec = true; break;
604 case BIFF5_ID_DEFINEDNAME: bExtLinkRec = true; break;
605 case BIFF_ID_EXTERNALBOOK: bExtLinkRec = true; break;
606 case BIFF5_ID_EXTERNALNAME: bExtLinkRec = true; break;
607 case BIFF_ID_EXTERNSHEET: bExtLinkRec = true; break;
608 case BIFF_ID_FILESHARING: rWorkbookSett.importFileSharing( rStrm ); break;
609 case BIFF5_ID_FONT: rStyles.importFont( rStrm ); break;
610 case BIFF4_ID_FORMAT: rStyles.importFormat( rStrm ); break;
611 case BIFF_ID_HIDEOBJ: rWorkbookSett.importHideObj( rStrm ); break;
612 case BIFF_ID_OLESIZE: rViewSett.importOleSize( rStrm ); break;
613 case BIFF_ID_PALETTE: rStyles.importPalette( rStrm ); break;
614 case BIFF_ID_PIVOTCACHE: rPivotCaches.importPivotCacheRef( rStrm ); break;
615 case BIFF_ID_SHEET: rWorksheets.importSheet( rStrm ); break;
616 case BIFF_ID_SST: rSharedStrings.importSst( rStrm ); break;
617 case BIFF_ID_STYLE: rStyles.importStyle( rStrm ); break;
618 case BIFF_ID_USESELFS: rWorkbookSett.importUsesElfs( rStrm ); break;
619 case BIFF_ID_VBAPROJECT: bHasVbaProject = true; break;
620 case BIFF_ID_VBAPROJECTEMPTY: bEmptyVbaProject = true; break;
621 case BIFF_ID_XCT: bExtLinkRec = true; break;
622 case BIFF5_ID_XF: rStyles.importXf( rStrm ); break;
623 }
624 break;
625
626 case BIFF_UNKNOWN: break;
627 }
628 }
629
630 if( bExtLinkRec )
631 aExtLinkRecs.push_back( rStrm.getRecHandle() );
632 }
633
634 // finalize global buffers
635 rProgressBar.setPosition( 0.5 );
636 if( bRet )
637 {
638 rSharedStrings.finalizeImport();
639 rStyles.finalizeImport();
640 }
641
642 /* Import external link data (EXTERNSHEET, EXTERNALNAME, DEFINEDNAME)
643 which need existing internal sheets (SHEET records). The SHEET records
644 may follow the external links records in some BIFF versions. */
645 if( bRet && !aExtLinkRecs.empty() )
646 {
647 // remember current stream position (the EOF record)
648 sal_Int64 nEofHandle = rStrm.getRecHandle();
649 // context handler implementing import of external link records
650 BiffExternalSheetDataContext aSheetContext( *this, true );
651 // import all records by using their cached record handle
652 for( RecordHandleVec::const_iterator aIt = aExtLinkRecs.begin(), aEnd = aExtLinkRecs.end(); (aIt != aEnd) && rStrm.startRecordByHandle( *aIt ); ++aIt )
653 aSheetContext.importRecord( rStrm );
654 // finalize global buffers
655 getDefinedNames().finalizeImport();
656 // seek back to the EOF record of the workbook globals fragment
657 bRet = rStrm.startRecordByHandle( nEofHandle );
658 }
659
660 // open the VBA project storage
661 if( bHasVbaProject && !bEmptyVbaProject )
662 setVbaProjectStorage( getBaseFilter().openSubStorage( CREATE_OUSTRING( "_VBA_PROJECT_CUR" ), false ) );
663
664 // #i56376# missing EOF - rewind before worksheet BOF record (see above)
665 if( bRet && BiffHelper::isBofRecord( rStrm ) )
666 rStrm.rewindRecord();
667
668 rProgressBar.setPosition( 1.0 );
669 return bRet;
670 }
671
importSheetFragment(ISegmentProgressBar & rProgressBar,BiffFragmentType eFragment,sal_Int16 nCalcSheet)672 bool BiffWorkbookFragment::importSheetFragment( ISegmentProgressBar& rProgressBar, BiffFragmentType eFragment, sal_Int16 nCalcSheet )
673 {
674 // no Calc sheet - skip the fragment
675 if( nCalcSheet < 0 )
676 return skipFragment();
677
678 // find the sheet type for this fragment
679 WorksheetType eSheetType = SHEETTYPE_EMPTYSHEET;
680 switch( eFragment )
681 {
682 case BIFF_FRAGMENT_WORKSHEET: eSheetType = SHEETTYPE_WORKSHEET; break;
683 case BIFF_FRAGMENT_CHARTSHEET: eSheetType = SHEETTYPE_CHARTSHEET; break;
684 case BIFF_FRAGMENT_MACROSHEET: eSheetType = SHEETTYPE_MACROSHEET; break;
685 case BIFF_FRAGMENT_MODULESHEET: eSheetType = SHEETTYPE_MODULESHEET; break;
686 case BIFF_FRAGMENT_EMPTYSHEET: eSheetType = SHEETTYPE_EMPTYSHEET; break;
687 default: return false;
688 }
689
690 /* #i11183# Clear buffers that are used per-sheet, e.g. external links in
691 BIFF4W and BIFF5 files, or defined names in BIFF4W files. */
692 createBuffersPerSheet( nCalcSheet );
693
694 // preprocess some records
695 BiffInputStream& rStrm = getInputStream();
696 switch( getBiff() )
697 {
698 // load the workbook globals fragment records in BIFF2-BIFF4
699 case BIFF2:
700 case BIFF3:
701 case BIFF4:
702 {
703 // remember current record to seek back below
704 sal_Int64 nRecHandle = rStrm.getRecHandle();
705 // import the global records
706 ISegmentProgressBarRef xGlobalsProgress = rProgressBar.createSegment( PROGRESS_LENGTH_GLOBALS );
707 importGlobalsFragment( *xGlobalsProgress );
708 // rewind stream to fragment BOF record
709 rStrm.startRecordByHandle( nRecHandle );
710 }
711 break;
712
713 // load the external link records for this sheet in BIFF5
714 case BIFF5:
715 {
716 // remember current record to seek back below
717 sal_Int64 nRecHandle = rStrm.getRecHandle();
718 // fragment implementing import of external link records
719 BiffExternalLinkFragment( *this ).importFragment();
720 // rewind stream to fragment BOF record
721 rStrm.startRecordByHandle( nRecHandle );
722 }
723 break;
724
725 case BIFF8:
726 break;
727
728 case BIFF_UNKNOWN:
729 break;
730 }
731
732 // create the WorksheetGlobals object
733 ISegmentProgressBarRef xSheetProgress = rProgressBar.createSegment( rProgressBar.getFreeLength() );
734 WorksheetGlobalsRef xSheetGlob = WorksheetHelper::constructGlobals( *this, xSheetProgress, eSheetType, nCalcSheet );
735 OSL_ENSURE( xSheetGlob.get(), "BiffWorkbookFragment::importSheetFragment - missing sheet in document" );
736 if( !xSheetGlob.get() )
737 return false;
738
739 // create the worksheet fragment
740 ::boost::shared_ptr< BiffWorksheetFragmentBase > xFragment;
741 switch( eSheetType )
742 {
743 case SHEETTYPE_WORKSHEET:
744 case SHEETTYPE_MACROSHEET:
745 case SHEETTYPE_DIALOGSHEET:
746 xFragment.reset( new BiffWorksheetFragment( *xSheetGlob, *this ) );
747 break;
748 case SHEETTYPE_CHARTSHEET:
749 xFragment.reset( new BiffChartsheetFragment( *xSheetGlob, *this ) );
750 break;
751 case SHEETTYPE_MODULESHEET:
752 case SHEETTYPE_EMPTYSHEET:
753 xFragment.reset( new BiffSkipWorksheetFragment( *xSheetGlob, *this ) );
754 break;
755 }
756 // load the sheet fragment records
757 return xFragment.get() && xFragment->importFragment();
758 }
759
760 // ============================================================================
761
762 } // namespace xls
763 } // namespace oox
764