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 72 WorkbookFragment::WorkbookFragment( const WorkbookHelper& rHelper, const OUString& rFragmentPath ) : 73 WorkbookFragmentBase( rHelper, rFragmentPath ) 74 { 75 } 76 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 120 void WorkbookFragment::onCharacters( const OUString& rChars ) 121 { 122 if( isCurrentElement( XLS_TOKEN( definedName ) ) && mxCurrName.get() ) 123 mxCurrName->setFormula( rChars ); 124 } 125 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 174 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 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 315 void WorkbookFragment::importExternalReference( const AttributeList& rAttribs ) 316 { 317 if( ExternalLink* pExtLink = getExternalLinks().importExternalReference( rAttribs ).get() ) 318 importExternalLinkFragment( *pExtLink ); 319 } 320 321 void WorkbookFragment::importDefinedName( const AttributeList& rAttribs ) 322 { 323 mxCurrName = getDefinedNames().importDefinedName( rAttribs ); 324 } 325 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 333 void WorkbookFragment::importExternalRef( SequenceInputStream& rStrm ) 334 { 335 if( ExternalLink* pExtLink = getExternalLinks().importExternalRef( rStrm ).get() ) 336 importExternalLinkFragment( *pExtLink ); 337 } 338 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 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 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 361 BiffWorkbookFragment::BiffWorkbookFragment( const WorkbookHelper& rHelper, const OUString& rStrmName ) : 362 BiffWorkbookFragmentBase( rHelper, rStrmName ) 363 { 364 } 365 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 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 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 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