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