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/externallinkfragment.hxx" 29 30 #include <com/sun/star/sheet/XExternalSheetCache.hpp> 31 #include "oox/helper/attributelist.hxx" 32 #include "oox/xls/biffinputstream.hxx" 33 #include "oox/xls/defnamesbuffer.hxx" 34 #include "oox/xls/sheetdatacontext.hxx" 35 #include "oox/xls/unitconverter.hxx" 36 37 namespace oox { 38 namespace xls { 39 40 // ============================================================================ 41 42 using namespace ::com::sun::star::sheet; 43 using namespace ::com::sun::star::table; 44 using namespace ::com::sun::star::uno; 45 using namespace ::oox::core; 46 47 using ::rtl::OUString; 48 49 // ============================================================================ 50 // ============================================================================ 51 52 ExternalSheetDataContext::ExternalSheetDataContext( 53 WorkbookFragmentBase& rFragment, const Reference< XExternalSheetCache >& rxSheetCache ) : 54 WorkbookContextBase( rFragment ), 55 mxSheetCache( rxSheetCache ) 56 { 57 OSL_ENSURE( mxSheetCache.is(), "ExternalSheetDataContext::ExternalSheetDataContext - missing sheet cache" ); 58 } 59 60 ContextHandlerRef ExternalSheetDataContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) 61 { 62 switch( getCurrentElement() ) 63 { 64 case XLS_TOKEN( sheetData ): 65 if( nElement == XLS_TOKEN( row ) ) return this; 66 break; 67 case XLS_TOKEN( row ): 68 if( nElement == XLS_TOKEN( cell ) ) { importCell( rAttribs ); return this; } 69 break; 70 case XLS_TOKEN( cell ): 71 if( nElement == XLS_TOKEN( v ) ) return this; // collect characters in onCharacters() 72 break; 73 } 74 return 0; 75 } 76 77 void ExternalSheetDataContext::onCharacters( const OUString& rChars ) 78 { 79 if( isCurrentElement( XLS_TOKEN( v ) ) ) 80 { 81 switch( mnCurrType ) 82 { 83 case XML_b: 84 case XML_n: 85 setCellValue( Any( rChars.toDouble() ) ); 86 break; 87 case XML_e: 88 setCellValue( Any( BiffHelper::calcDoubleFromError( getUnitConverter().calcBiffErrorCode( rChars ) ) ) ); 89 break; 90 case XML_str: 91 setCellValue( Any( rChars ) ); 92 break; 93 } 94 mnCurrType = XML_TOKEN_INVALID; 95 } 96 } 97 98 ContextHandlerRef ExternalSheetDataContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm ) 99 { 100 switch( getCurrentElement() ) 101 { 102 case BIFF12_ID_EXTSHEETDATA: 103 if( nRecId == BIFF12_ID_EXTROW ) { maCurrPos.Row = rStrm.readInt32(); return this; } 104 break; 105 case BIFF12_ID_EXTROW: 106 switch( nRecId ) 107 { 108 case BIFF12_ID_EXTCELL_BLANK: importExtCellBlank( rStrm ); break; 109 case BIFF12_ID_EXTCELL_BOOL: importExtCellBool( rStrm ); break; 110 case BIFF12_ID_EXTCELL_DOUBLE: importExtCellDouble( rStrm ); break; 111 case BIFF12_ID_EXTCELL_ERROR: importExtCellError( rStrm ); break; 112 case BIFF12_ID_EXTCELL_STRING: importExtCellString( rStrm ); break; 113 } 114 break; 115 } 116 return 0; 117 } 118 119 // private -------------------------------------------------------------------- 120 121 void ExternalSheetDataContext::importCell( const AttributeList& rAttribs ) 122 { 123 if( getAddressConverter().convertToCellAddress( maCurrPos, rAttribs.getString( XML_r, OUString() ), 0, false ) ) 124 mnCurrType = rAttribs.getToken( XML_t, XML_n ); 125 else 126 mnCurrType = XML_TOKEN_INVALID; 127 } 128 129 void ExternalSheetDataContext::importExtCellBlank( SequenceInputStream& rStrm ) 130 { 131 maCurrPos.Column = rStrm.readInt32(); 132 setCellValue( Any( OUString() ) ); 133 } 134 135 void ExternalSheetDataContext::importExtCellBool( SequenceInputStream& rStrm ) 136 { 137 maCurrPos.Column = rStrm.readInt32(); 138 double fValue = (rStrm.readuInt8() == 0) ? 0.0 : 1.0; 139 setCellValue( Any( fValue ) ); 140 } 141 142 void ExternalSheetDataContext::importExtCellDouble( SequenceInputStream& rStrm ) 143 { 144 maCurrPos.Column = rStrm.readInt32(); 145 setCellValue( Any( rStrm.readDouble() ) ); 146 } 147 148 void ExternalSheetDataContext::importExtCellError( SequenceInputStream& rStrm ) 149 { 150 maCurrPos.Column = rStrm.readInt32(); 151 setCellValue( Any( BiffHelper::calcDoubleFromError( rStrm.readuInt8() ) ) ); 152 } 153 154 void ExternalSheetDataContext::importExtCellString( SequenceInputStream& rStrm ) 155 { 156 maCurrPos.Column = rStrm.readInt32(); 157 setCellValue( Any( BiffHelper::readString( rStrm ) ) ); 158 } 159 160 void ExternalSheetDataContext::setCellValue( const Any& rValue ) 161 { 162 if( mxSheetCache.is() && getAddressConverter().checkCellAddress( maCurrPos, false ) ) try 163 { 164 mxSheetCache->setCellValue( maCurrPos.Column, maCurrPos.Row, rValue ); 165 } 166 catch( Exception& ) 167 { 168 } 169 } 170 171 // ============================================================================ 172 173 ExternalLinkFragment::ExternalLinkFragment( const WorkbookHelper& rHelper, 174 const OUString& rFragmentPath, ExternalLink& rExtLink ) : 175 WorkbookFragmentBase( rHelper, rFragmentPath ), 176 mrExtLink( rExtLink ), 177 mnResultType( XML_TOKEN_INVALID ) 178 { 179 } 180 181 ContextHandlerRef ExternalLinkFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) 182 { 183 switch( getCurrentElement() ) 184 { 185 case XML_ROOT_CONTEXT: 186 if( nElement == XLS_TOKEN( externalLink ) ) return this; 187 break; 188 189 case XLS_TOKEN( externalLink ): 190 switch( nElement ) 191 { 192 case XLS_TOKEN( externalBook ): mrExtLink.importExternalBook( getRelations(), rAttribs ); return this; 193 case XLS_TOKEN( ddeLink ): mrExtLink.importDdeLink( rAttribs ); return this; 194 case XLS_TOKEN( oleLink ): mrExtLink.importOleLink( getRelations(), rAttribs ); return this; 195 } 196 break; 197 198 case XLS_TOKEN( externalBook ): 199 switch( nElement ) 200 { 201 case XLS_TOKEN( sheetNames ): 202 case XLS_TOKEN( definedNames ): 203 case XLS_TOKEN( sheetDataSet ): return this; 204 } 205 break; 206 207 case XLS_TOKEN( sheetNames ): 208 if( nElement == XLS_TOKEN( sheetName ) ) mrExtLink.importSheetName( rAttribs ); 209 break; 210 case XLS_TOKEN( definedNames ): 211 if( nElement == XLS_TOKEN( definedName ) ) mrExtLink.importDefinedName( rAttribs ); 212 break; 213 case XLS_TOKEN( sheetDataSet ): 214 if( (nElement == XLS_TOKEN( sheetData )) && (mrExtLink.getLinkType() == LINKTYPE_EXTERNAL) ) 215 return createSheetDataContext( rAttribs.getInteger( XML_sheetId, -1 ) ); 216 break; 217 218 case XLS_TOKEN( ddeLink ): 219 if( nElement == XLS_TOKEN( ddeItems ) ) return this; 220 break; 221 case XLS_TOKEN( ddeItems ): 222 if( nElement == XLS_TOKEN( ddeItem ) ) 223 { 224 mxExtName = mrExtLink.importDdeItem( rAttribs ); 225 return this; 226 } 227 break; 228 case XLS_TOKEN( ddeItem ): 229 if( nElement == XLS_TOKEN( values ) ) 230 { 231 if( mxExtName.get() ) mxExtName->importValues( rAttribs ); 232 return this; 233 } 234 break; 235 case XLS_TOKEN( values ): 236 if( nElement == XLS_TOKEN( value ) ) 237 { 238 mnResultType = rAttribs.getToken( XML_t, XML_n ); 239 return this; 240 } 241 break; 242 case XLS_TOKEN( value ): 243 if( nElement == XLS_TOKEN( val ) ) return this; // collect value in onCharacters() 244 break; 245 246 case XLS_TOKEN( oleLink ): 247 if( nElement == XLS_TOKEN( oleItems ) ) return this; 248 break; 249 case XLS_TOKEN( oleItems ): 250 if( nElement == XLS_TOKEN( oleItem ) ) mxExtName = mrExtLink.importOleItem( rAttribs ); 251 break; 252 } 253 return 0; 254 } 255 256 void ExternalLinkFragment::onCharacters( const OUString& rChars ) 257 { 258 if( isCurrentElement( XLS_TOKEN( val ) ) ) 259 maResultValue = rChars; 260 } 261 262 void ExternalLinkFragment::onEndElement() 263 { 264 if( isCurrentElement( XLS_TOKEN( value ) ) && mxExtName.get() ) switch( mnResultType ) 265 { 266 case XML_b: 267 mxExtName->appendResultValue( maResultValue.toDouble() ); 268 break; 269 case XML_e: 270 mxExtName->appendResultValue( BiffHelper::calcDoubleFromError( getUnitConverter().calcBiffErrorCode( maResultValue ) ) ); 271 break; 272 case XML_n: 273 mxExtName->appendResultValue( maResultValue.toDouble() ); 274 break; 275 case XML_str: 276 mxExtName->appendResultValue( maResultValue ); 277 break; 278 default: 279 mxExtName->appendResultValue( BiffHelper::calcDoubleFromError( BIFF_ERR_NA ) ); 280 } 281 } 282 283 ContextHandlerRef ExternalLinkFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm ) 284 { 285 switch( getCurrentElement() ) 286 { 287 case XML_ROOT_CONTEXT: 288 if( nRecId == BIFF12_ID_EXTERNALBOOK ) 289 { 290 mrExtLink.importExternalBook( getRelations(), rStrm ); 291 return this; 292 } 293 break; 294 295 case BIFF12_ID_EXTERNALBOOK: 296 switch( nRecId ) 297 { 298 case BIFF12_ID_EXTSHEETDATA: 299 if( mrExtLink.getLinkType() == LINKTYPE_EXTERNAL ) 300 return createSheetDataContext( rStrm.readInt32() ); 301 break; 302 303 case BIFF12_ID_EXTSHEETNAMES: mrExtLink.importExtSheetNames( rStrm ); break; 304 case BIFF12_ID_EXTERNALNAME: mxExtName = mrExtLink.importExternalName( rStrm ); return this; 305 } 306 break; 307 308 case BIFF12_ID_EXTERNALNAME: 309 switch( nRecId ) 310 { 311 case BIFF12_ID_EXTERNALNAMEFLAGS: if( mxExtName.get() ) mxExtName->importExternalNameFlags( rStrm ); break; 312 case BIFF12_ID_DDEITEMVALUES: if( mxExtName.get() ) mxExtName->importDdeItemValues( rStrm ); return this; 313 } 314 break; 315 316 case BIFF12_ID_DDEITEMVALUES: 317 switch( nRecId ) 318 { 319 case BIFF12_ID_DDEITEM_BOOL: if( mxExtName.get() ) mxExtName->importDdeItemBool( rStrm ); break; 320 case BIFF12_ID_DDEITEM_DOUBLE: if( mxExtName.get() ) mxExtName->importDdeItemDouble( rStrm ); break; 321 case BIFF12_ID_DDEITEM_ERROR: if( mxExtName.get() ) mxExtName->importDdeItemError( rStrm ); break; 322 case BIFF12_ID_DDEITEM_STRING: if( mxExtName.get() ) mxExtName->importDdeItemString( rStrm ); break; 323 } 324 break; 325 } 326 return 0; 327 } 328 329 ContextHandlerRef ExternalLinkFragment::createSheetDataContext( sal_Int32 nSheetId ) 330 { 331 return new ExternalSheetDataContext( *this, mrExtLink.getSheetCache( nSheetId ) ); 332 } 333 334 const RecordInfo* ExternalLinkFragment::getRecordInfos() const 335 { 336 static const RecordInfo spRecInfos[] = 337 { 338 { BIFF12_ID_DDEITEMVALUES, BIFF12_ID_DDEITEMVALUES + 1 }, 339 { BIFF12_ID_EXTERNALBOOK, BIFF12_ID_EXTERNALBOOK + 228 }, 340 { BIFF12_ID_EXTERNALNAME, BIFF12_ID_EXTERNALNAME + 10 }, 341 { BIFF12_ID_EXTROW, -1 }, 342 { BIFF12_ID_EXTSHEETDATA, BIFF12_ID_EXTSHEETDATA + 1 }, 343 { -1, -1 } 344 }; 345 return spRecInfos; 346 } 347 348 // ============================================================================ 349 // ============================================================================ 350 351 BiffExternalSheetDataContext::BiffExternalSheetDataContext( const WorkbookHelper& rHelper, bool bImportDefNames ) : 352 BiffWorkbookContextBase( rHelper ), 353 mbImportDefNames( bImportDefNames ) 354 { 355 } 356 357 BiffExternalSheetDataContext::~BiffExternalSheetDataContext() 358 { 359 } 360 361 void BiffExternalSheetDataContext::importRecord( BiffInputStream& rStrm ) 362 { 363 sal_uInt16 nRecId = rStrm.getRecId(); 364 switch( getBiff() ) 365 { 366 case BIFF2: switch( nRecId ) 367 { 368 case BIFF2_ID_EXTERNALNAME: importExternalName( rStrm ); break; 369 case BIFF_ID_EXTERNSHEET: importExternSheet( rStrm ); break; 370 case BIFF2_ID_DEFINEDNAME: importDefinedName( rStrm ); break; 371 } 372 break; 373 case BIFF3: switch( nRecId ) 374 { 375 case BIFF_ID_CRN: importCrn( rStrm ); break; 376 case BIFF3_ID_EXTERNALNAME: importExternalName( rStrm ); break; 377 case BIFF_ID_EXTERNSHEET: importExternSheet( rStrm ); break; 378 case BIFF3_ID_DEFINEDNAME: importDefinedName( rStrm ); break; 379 case BIFF_ID_XCT: importXct( rStrm ); break; 380 } 381 break; 382 case BIFF4: switch( nRecId ) 383 { 384 case BIFF_ID_CRN: importCrn( rStrm ); break; 385 case BIFF3_ID_EXTERNALNAME: importExternalName( rStrm ); break; 386 case BIFF_ID_EXTERNSHEET: importExternSheet( rStrm ); break; 387 case BIFF3_ID_DEFINEDNAME: importDefinedName( rStrm ); break; 388 case BIFF_ID_XCT: importXct( rStrm ); break; 389 } 390 break; 391 case BIFF5: switch( nRecId ) 392 { 393 case BIFF_ID_CRN: importCrn( rStrm ); break; 394 case BIFF5_ID_EXTERNALNAME: importExternalName( rStrm ); break; 395 case BIFF_ID_EXTERNSHEET: importExternSheet( rStrm ); break; 396 case BIFF5_ID_DEFINEDNAME: importDefinedName( rStrm ); break; 397 case BIFF_ID_XCT: importXct( rStrm ); break; 398 } 399 break; 400 case BIFF8: switch( nRecId ) 401 { 402 case BIFF_ID_CRN: importCrn( rStrm ); break; 403 case BIFF_ID_EXTERNALBOOK: importExternalBook( rStrm ); break; 404 case BIFF5_ID_EXTERNALNAME: importExternalName( rStrm ); break; 405 case BIFF_ID_EXTERNSHEET: importExternSheet( rStrm ); break; 406 case BIFF5_ID_DEFINEDNAME: importDefinedName( rStrm ); break; 407 case BIFF_ID_XCT: importXct( rStrm ); break; 408 } 409 break; 410 case BIFF_UNKNOWN: break; 411 } 412 } 413 414 // private -------------------------------------------------------------------- 415 416 void BiffExternalSheetDataContext::importExternSheet( BiffInputStream& rStrm ) 417 { 418 mxSheetCache.clear(); 419 if( getBiff() == BIFF8 ) 420 getExternalLinks().importExternSheet8( rStrm ); 421 else 422 mxExtLink = getExternalLinks().importExternSheet( rStrm ); 423 } 424 425 void BiffExternalSheetDataContext::importExternalBook( BiffInputStream& rStrm ) 426 { 427 mxSheetCache.clear(); 428 mxExtLink = getExternalLinks().importExternalBook( rStrm ); 429 } 430 431 void BiffExternalSheetDataContext::importExternalName( BiffInputStream& rStrm ) 432 { 433 if( mxExtLink.get() ) 434 mxExtLink->importExternalName( rStrm ); 435 } 436 437 void BiffExternalSheetDataContext::importXct( BiffInputStream& rStrm ) 438 { 439 mxSheetCache.clear(); 440 if( mxExtLink.get() && (mxExtLink->getLinkType() == LINKTYPE_EXTERNAL) ) 441 { 442 switch( getBiff() ) 443 { 444 case BIFF2: 445 break; 446 case BIFF3: 447 case BIFF4: 448 case BIFF5: 449 mxSheetCache = mxExtLink->getSheetCache( 0 ); 450 break; 451 case BIFF8: 452 rStrm.skip( 2 ); 453 mxSheetCache = mxExtLink->getSheetCache( rStrm.readInt16() ); 454 break; 455 case BIFF_UNKNOWN: 456 break; 457 } 458 } 459 } 460 461 void BiffExternalSheetDataContext::importCrn( BiffInputStream& rStrm ) 462 { 463 if( !mxSheetCache.is() ) return; 464 465 sal_uInt8 nCol2, nCol1; 466 sal_uInt16 nRow; 467 rStrm >> nCol2 >> nCol1 >> nRow; 468 bool bLoop = true; 469 for( BinAddress aBinAddr( nCol1, nRow ); bLoop && !rStrm.isEof() && (aBinAddr.mnCol <= nCol2); ++aBinAddr.mnCol ) 470 { 471 switch( rStrm.readuInt8() ) 472 { 473 case BIFF_DATATYPE_EMPTY: 474 rStrm.skip( 8 ); 475 setCellValue( aBinAddr, Any( OUString() ) ); 476 break; 477 case BIFF_DATATYPE_DOUBLE: 478 setCellValue( aBinAddr, Any( rStrm.readDouble() ) ); 479 break; 480 case BIFF_DATATYPE_STRING: 481 { 482 OUString aText = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( false, getTextEncoding() ); 483 setCellValue( aBinAddr, Any( aText ) ); 484 } 485 break; 486 case BIFF_DATATYPE_BOOL: 487 { 488 double fValue = (rStrm.readuInt8() == 0) ? 0.0 : 1.0; 489 setCellValue( aBinAddr, Any( fValue ) ); 490 rStrm.skip( 7 ); 491 } 492 break; 493 case BIFF_DATATYPE_ERROR: 494 setCellValue( aBinAddr, Any( BiffHelper::calcDoubleFromError( rStrm.readuInt8() ) ) ); 495 rStrm.skip( 7 ); 496 break; 497 default: 498 OSL_ENSURE( false, "BiffExternalSheetDataContext::importCrn - unknown data type" ); 499 bLoop = false; 500 } 501 } 502 } 503 504 void BiffExternalSheetDataContext::importDefinedName( BiffInputStream& rStrm ) 505 { 506 if( mbImportDefNames ) 507 getDefinedNames().importDefinedName( rStrm ); 508 } 509 510 void BiffExternalSheetDataContext::setCellValue( const BinAddress& rBinAddr, const Any& rValue ) 511 { 512 CellAddress aCellPos; 513 if( mxSheetCache.is() && getAddressConverter().convertToCellAddress( aCellPos, rBinAddr, 0, false ) ) try 514 { 515 mxSheetCache->setCellValue( aCellPos.Column, aCellPos.Row, rValue ); 516 } 517 catch( Exception& ) 518 { 519 } 520 } 521 522 // ============================================================================ 523 524 BiffExternalLinkFragment::BiffExternalLinkFragment( const BiffWorkbookFragmentBase& rParent ) : 525 BiffWorkbookFragmentBase( rParent ) 526 { 527 } 528 529 bool BiffExternalLinkFragment::importFragment() 530 { 531 // process all record in this sheet fragment 532 BiffExternalSheetDataContext aSheetContext( *this, false ); 533 BiffInputStream& rStrm = getInputStream(); 534 while( rStrm.startNextRecord() && (rStrm.getRecId() != BIFF_ID_EOF) ) 535 { 536 if( BiffHelper::isBofRecord( rStrm ) ) 537 skipFragment(); // skip unknown embedded fragments 538 else 539 aSheetContext.importRecord( rStrm ); 540 } 541 return !rStrm.isEof() && (rStrm.getRecId() == BIFF_ID_EOF); 542 } 543 544 // ============================================================================ 545 // ============================================================================ 546 547 } // namespace xls 548 } // namespace oox 549