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