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/sheetdatacontext.hxx" 29 30 #include <com/sun/star/table/CellContentType.hpp> 31 #include <com/sun/star/table/XCell.hpp> 32 #include <com/sun/star/table/XCellRange.hpp> 33 #include <com/sun/star/text/XText.hpp> 34 #include "oox/helper/attributelist.hxx" 35 #include "oox/helper/propertyset.hxx" 36 #include "oox/xls/addressconverter.hxx" 37 #include "oox/xls/biffinputstream.hxx" 38 #include "oox/xls/formulaparser.hxx" 39 #include "oox/xls/richstringcontext.hxx" 40 #include "oox/xls/unitconverter.hxx" 41 42 namespace oox { 43 namespace xls { 44 45 // ============================================================================ 46 47 using namespace ::com::sun::star::sheet; 48 using namespace ::com::sun::star::table; 49 using namespace ::com::sun::star::text; 50 using namespace ::com::sun::star::uno; 51 52 using ::oox::core::ContextHandlerRef; 53 using ::rtl::OUString; 54 55 // ============================================================================ 56 57 namespace { 58 59 // record constants ----------------------------------------------------------- 60 61 const sal_uInt32 BIFF12_CELL_SHOWPHONETIC = 0x01000000; 62 63 const sal_uInt8 BIFF12_DATATABLE_ROW = 0x01; 64 const sal_uInt8 BIFF12_DATATABLE_2D = 0x02; 65 const sal_uInt8 BIFF12_DATATABLE_REF1DEL = 0x04; 66 const sal_uInt8 BIFF12_DATATABLE_REF2DEL = 0x08; 67 68 const sal_uInt16 BIFF12_ROW_THICKTOP = 0x0001; 69 const sal_uInt16 BIFF12_ROW_THICKBOTTOM = 0x0002; 70 const sal_uInt16 BIFF12_ROW_COLLAPSED = 0x0800; 71 const sal_uInt16 BIFF12_ROW_HIDDEN = 0x1000; 72 const sal_uInt16 BIFF12_ROW_CUSTOMHEIGHT = 0x2000; 73 const sal_uInt16 BIFF12_ROW_CUSTOMFORMAT = 0x4000; 74 const sal_uInt8 BIFF12_ROW_SHOWPHONETIC = 0x01; 75 76 const sal_uInt16 BIFF_DATATABLE_ROW = 0x0004; 77 const sal_uInt16 BIFF_DATATABLE_2D = 0x0008; 78 const sal_uInt16 BIFF_DATATABLE_REF1DEL = 0x0010; 79 const sal_uInt16 BIFF_DATATABLE_REF2DEL = 0x0020; 80 81 const sal_uInt8 BIFF_FORMULA_RES_STRING = 0; /// Result is a string. 82 const sal_uInt8 BIFF_FORMULA_RES_BOOL = 1; /// Result is Boolean value. 83 const sal_uInt8 BIFF_FORMULA_RES_ERROR = 2; /// Result is error code. 84 const sal_uInt8 BIFF_FORMULA_RES_EMPTY = 3; /// Result is empty cell (BIFF8 only). 85 const sal_uInt16 BIFF_FORMULA_SHARED = 0x0008; /// Shared formula cell. 86 87 const sal_uInt8 BIFF2_ROW_CUSTOMFORMAT = 0x01; 88 const sal_uInt16 BIFF_ROW_DEFAULTHEIGHT = 0x8000; 89 const sal_uInt16 BIFF_ROW_HEIGHTMASK = 0x7FFF; 90 const sal_uInt32 BIFF_ROW_COLLAPSED = 0x00000010; 91 const sal_uInt32 BIFF_ROW_HIDDEN = 0x00000020; 92 const sal_uInt32 BIFF_ROW_CUSTOMHEIGHT = 0x00000040; 93 const sal_uInt32 BIFF_ROW_CUSTOMFORMAT = 0x00000080; 94 const sal_uInt32 BIFF_ROW_THICKTOP = 0x10000000; 95 const sal_uInt32 BIFF_ROW_THICKBOTTOM = 0x20000000; 96 const sal_uInt32 BIFF_ROW_SHOWPHONETIC = 0x40000000; 97 98 const sal_Int32 BIFF2_CELL_USEIXFE = 63; 99 100 } // namespace 101 102 // ============================================================================ 103 104 SheetDataContextBase::SheetDataContextBase( const WorksheetHelper& rHelper ) : 105 mrAddressConv( rHelper.getAddressConverter() ), 106 mrFormulaParser( rHelper.getFormulaParser() ), 107 mrSheetData( rHelper.getSheetData() ), 108 mnSheet( rHelper.getSheetIndex() ) 109 { 110 } 111 112 SheetDataContextBase::~SheetDataContextBase() 113 { 114 } 115 116 // ============================================================================ 117 118 SheetDataContext::SheetDataContext( WorksheetFragmentBase& rFragment ) : 119 WorksheetContextBase( rFragment ), 120 SheetDataContextBase( rFragment ), 121 mbHasFormula( false ), 122 mbValidRange( false ) 123 { 124 } 125 126 ContextHandlerRef SheetDataContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) 127 { 128 switch( getCurrentElement() ) 129 { 130 case XLS_TOKEN( sheetData ): 131 if( nElement == XLS_TOKEN( row ) ) { importRow( rAttribs ); return this; } 132 break; 133 134 case XLS_TOKEN( row ): 135 // do not process cell elements with invalid (out-of-range) address 136 if( nElement == XLS_TOKEN( c ) && importCell( rAttribs ) ) 137 return this; 138 break; 139 140 case XLS_TOKEN( c ): 141 switch( nElement ) 142 { 143 case XLS_TOKEN( is ): 144 mxInlineStr.reset( new RichString( *this ) ); 145 return new RichStringContext( *this, mxInlineStr ); 146 case XLS_TOKEN( v ): 147 return this; // characters contain cell value 148 case XLS_TOKEN( f ): 149 importFormula( rAttribs ); 150 return this; // characters contain formula string 151 } 152 break; 153 } 154 return 0; 155 } 156 157 void SheetDataContext::onCharacters( const OUString& rChars ) 158 { 159 switch( getCurrentElement() ) 160 { 161 case XLS_TOKEN( v ): 162 maCellValue = rChars; 163 break; 164 case XLS_TOKEN( f ): 165 if( maFmlaData.mnFormulaType != XML_TOKEN_INVALID ) 166 maTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, rChars ); 167 break; 168 } 169 } 170 171 void SheetDataContext::onEndElement() 172 { 173 if( getCurrentElement() == XLS_TOKEN( c ) ) 174 { 175 // try to create a formula cell 176 if( mbHasFormula ) switch( maFmlaData.mnFormulaType ) 177 { 178 case XML_normal: 179 mrSheetData.setFormulaCell( maCellData, maTokens ); 180 break; 181 case XML_shared: 182 if( maFmlaData.mnSharedId >= 0 ) 183 { 184 if( mbValidRange && maFmlaData.isValidSharedRef( maCellData.maCellAddr ) ) 185 mrSheetData.createSharedFormula( maFmlaData.mnSharedId, maTokens ); 186 mrSheetData.setFormulaCell( maCellData, maFmlaData.mnSharedId ); 187 } 188 else 189 // no success, set plain cell value and formatting below 190 mbHasFormula = false; 191 break; 192 case XML_array: 193 if( mbValidRange && maFmlaData.isValidArrayRef( maCellData.maCellAddr ) ) 194 mrSheetData.createArrayFormula( maFmlaData.maFormulaRef, maTokens ); 195 // set cell formatting, but do not set result as cell value 196 mrSheetData.setBlankCell( maCellData ); 197 break; 198 case XML_dataTable: 199 if( mbValidRange ) 200 mrSheetData.createTableOperation( maFmlaData.maFormulaRef, maTableData ); 201 // set cell formatting, but do not set result as cell value 202 mrSheetData.setBlankCell( maCellData ); 203 break; 204 default: 205 OSL_ENSURE( maFmlaData.mnFormulaType == XML_TOKEN_INVALID, "SheetDataContext::onEndElement - unknown formula type" ); 206 mbHasFormula = false; 207 } 208 209 if( !mbHasFormula ) 210 { 211 // no formula created: try to set the cell value 212 if( maCellValue.getLength() > 0 ) switch( maCellData.mnCellType ) 213 { 214 case XML_n: 215 mrSheetData.setValueCell( maCellData, maCellValue.toDouble() ); 216 break; 217 case XML_b: 218 mrSheetData.setBooleanCell( maCellData, maCellValue.toDouble() != 0.0 ); 219 break; 220 case XML_e: 221 mrSheetData.setErrorCell( maCellData, maCellValue ); 222 break; 223 case XML_str: 224 mrSheetData.setStringCell( maCellData, maCellValue ); 225 break; 226 case XML_s: 227 mrSheetData.setStringCell( maCellData, maCellValue.toInt32() ); 228 break; 229 } 230 else if( (maCellData.mnCellType == XML_inlineStr) && mxInlineStr.get() ) 231 { 232 mxInlineStr->finalizeImport(); 233 mrSheetData.setStringCell( maCellData, mxInlineStr ); 234 } 235 else 236 { 237 // empty cell, update cell type 238 maCellData.mnCellType = XML_TOKEN_INVALID; 239 mrSheetData.setBlankCell( maCellData ); 240 } 241 } 242 } 243 } 244 245 ContextHandlerRef SheetDataContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm ) 246 { 247 switch( getCurrentElement() ) 248 { 249 case BIFF12_ID_SHEETDATA: 250 if( nRecId == BIFF12_ID_ROW ) { importRow( rStrm ); return this; } 251 break; 252 253 case BIFF12_ID_ROW: 254 switch( nRecId ) 255 { 256 case BIFF12_ID_ARRAY: importArray( rStrm ); break; 257 case BIFF12_ID_CELL_BOOL: importCellBool( rStrm, CELLTYPE_VALUE ); break; 258 case BIFF12_ID_CELL_BLANK: importCellBlank( rStrm, CELLTYPE_VALUE ); break; 259 case BIFF12_ID_CELL_DOUBLE: importCellDouble( rStrm, CELLTYPE_VALUE ); break; 260 case BIFF12_ID_CELL_ERROR: importCellError( rStrm, CELLTYPE_VALUE ); break; 261 case BIFF12_ID_CELL_RK: importCellRk( rStrm, CELLTYPE_VALUE ); break; 262 case BIFF12_ID_CELL_RSTRING: importCellRString( rStrm, CELLTYPE_VALUE ); break; 263 case BIFF12_ID_CELL_SI: importCellSi( rStrm, CELLTYPE_VALUE ); break; 264 case BIFF12_ID_CELL_STRING: importCellString( rStrm, CELLTYPE_VALUE ); break; 265 case BIFF12_ID_DATATABLE: importDataTable( rStrm ); break; 266 case BIFF12_ID_FORMULA_BOOL: importCellBool( rStrm, CELLTYPE_FORMULA ); break; 267 case BIFF12_ID_FORMULA_DOUBLE: importCellDouble( rStrm, CELLTYPE_FORMULA ); break; 268 case BIFF12_ID_FORMULA_ERROR: importCellError( rStrm, CELLTYPE_FORMULA ); break; 269 case BIFF12_ID_FORMULA_STRING: importCellString( rStrm, CELLTYPE_FORMULA ); break; 270 case BIFF12_ID_MULTCELL_BOOL: importCellBool( rStrm, CELLTYPE_MULTI ); break; 271 case BIFF12_ID_MULTCELL_BLANK: importCellBlank( rStrm, CELLTYPE_MULTI ); break; 272 case BIFF12_ID_MULTCELL_DOUBLE: importCellDouble( rStrm, CELLTYPE_MULTI ); break; 273 case BIFF12_ID_MULTCELL_ERROR: importCellError( rStrm, CELLTYPE_MULTI ); break; 274 case BIFF12_ID_MULTCELL_RK: importCellRk( rStrm, CELLTYPE_MULTI ); break; 275 case BIFF12_ID_MULTCELL_RSTRING:importCellRString( rStrm, CELLTYPE_MULTI ); break; 276 case BIFF12_ID_MULTCELL_SI: importCellSi( rStrm, CELLTYPE_MULTI ); break; 277 case BIFF12_ID_MULTCELL_STRING: importCellString( rStrm, CELLTYPE_MULTI ); break; 278 case BIFF12_ID_SHAREDFMLA: importSharedFmla( rStrm ); break; 279 } 280 break; 281 } 282 return 0; 283 } 284 285 // private -------------------------------------------------------------------- 286 287 void SheetDataContext::importRow( const AttributeList& rAttribs ) 288 { 289 RowModel aModel; 290 aModel.mnRow = rAttribs.getInteger( XML_r, -1 ); 291 aModel.mfHeight = rAttribs.getDouble( XML_ht, -1.0 ); 292 aModel.mnXfId = rAttribs.getInteger( XML_s, -1 ); 293 aModel.mnLevel = rAttribs.getInteger( XML_outlineLevel, 0 ); 294 aModel.mbCustomHeight = rAttribs.getBool( XML_customHeight, false ); 295 aModel.mbCustomFormat = rAttribs.getBool( XML_customFormat, false ); 296 aModel.mbShowPhonetic = rAttribs.getBool( XML_ph, false ); 297 aModel.mbHidden = rAttribs.getBool( XML_hidden, false ); 298 aModel.mbCollapsed = rAttribs.getBool( XML_collapsed, false ); 299 aModel.mbThickTop = rAttribs.getBool( XML_thickTop, false ); 300 aModel.mbThickBottom = rAttribs.getBool( XML_thickBot, false ); 301 302 // decode the column spans (space-separated list of colon-separated integer pairs) 303 OUString aColSpansText = rAttribs.getString( XML_spans, OUString() ); 304 sal_Int32 nMaxCol = mrAddressConv.getMaxApiAddress().Column; 305 sal_Int32 nIndex = 0; 306 while( nIndex >= 0 ) 307 { 308 OUString aColSpanToken = aColSpansText.getToken( 0, ' ', nIndex ); 309 sal_Int32 nSepPos = aColSpanToken.indexOf( ':' ); 310 if( (0 < nSepPos) && (nSepPos + 1 < aColSpanToken.getLength()) ) 311 { 312 // OOXML uses 1-based integer column indexes, row model expects 0-based colspans 313 sal_Int32 nLastCol = ::std::min( aColSpanToken.copy( nSepPos + 1 ).toInt32() - 1, nMaxCol ); 314 aModel.insertColSpan( ValueRange( aColSpanToken.copy( 0, nSepPos ).toInt32() - 1, nLastCol ) ); 315 } 316 } 317 318 // set row properties in the current sheet 319 setRowModel( aModel ); 320 } 321 322 bool SheetDataContext::importCell( const AttributeList& rAttribs ) 323 { 324 bool bValidAddr = mrAddressConv.convertToCellAddress( maCellData.maCellAddr, rAttribs.getString( XML_r, OUString() ), mnSheet, true ); 325 if( bValidAddr ) 326 { 327 maCellData.mnCellType = rAttribs.getToken( XML_t, XML_n ); 328 maCellData.mnXfId = rAttribs.getInteger( XML_s, -1 ); 329 maCellData.mbShowPhonetic = rAttribs.getBool( XML_ph, false ); 330 331 // reset cell value, formula settings, and inline string 332 maCellValue = OUString(); 333 mxInlineStr.reset(); 334 mbHasFormula = false; 335 336 // update used area of the sheet 337 extendUsedArea( maCellData.maCellAddr ); 338 } 339 return bValidAddr; 340 } 341 342 void SheetDataContext::importFormula( const AttributeList& rAttribs ) 343 { 344 mbHasFormula = true; 345 mbValidRange = mrAddressConv.convertToCellRange( maFmlaData.maFormulaRef, rAttribs.getString( XML_ref, OUString() ), mnSheet, true, true ); 346 347 maFmlaData.mnFormulaType = rAttribs.getToken( XML_t, XML_normal ); 348 maFmlaData.mnSharedId = rAttribs.getInteger( XML_si, -1 ); 349 350 if( maFmlaData.mnFormulaType == XML_dataTable ) 351 { 352 maTableData.maRef1 = rAttribs.getString( XML_r1, OUString() ); 353 maTableData.maRef2 = rAttribs.getString( XML_r2, OUString() ); 354 maTableData.mb2dTable = rAttribs.getBool( XML_dt2D, false ); 355 maTableData.mbRowTable = rAttribs.getBool( XML_dtr, false ); 356 maTableData.mbRef1Deleted = rAttribs.getBool( XML_del1, false ); 357 maTableData.mbRef2Deleted = rAttribs.getBool( XML_del2, false ); 358 } 359 360 // clear token array, will be regenerated from element text 361 maTokens = ApiTokenSequence(); 362 } 363 364 void SheetDataContext::importRow( SequenceInputStream& rStrm ) 365 { 366 RowModel aModel; 367 sal_Int32 nSpanCount; 368 sal_uInt16 nHeight, nFlags1; 369 sal_uInt8 nFlags2; 370 rStrm >> maCurrPos.mnRow >> aModel.mnXfId >> nHeight >> nFlags1 >> nFlags2 >> nSpanCount; 371 maCurrPos.mnCol = 0; 372 373 // row index is 0-based in BIFF12, but RowModel expects 1-based 374 aModel.mnRow = maCurrPos.mnRow + 1; 375 // row height is in twips in BIFF12, convert to points 376 aModel.mfHeight = nHeight / 20.0; 377 aModel.mnLevel = extractValue< sal_Int32 >( nFlags1, 8, 3 ); 378 aModel.mbCustomHeight = getFlag( nFlags1, BIFF12_ROW_CUSTOMHEIGHT ); 379 aModel.mbCustomFormat = getFlag( nFlags1, BIFF12_ROW_CUSTOMFORMAT ); 380 aModel.mbShowPhonetic = getFlag( nFlags2, BIFF12_ROW_SHOWPHONETIC ); 381 aModel.mbHidden = getFlag( nFlags1, BIFF12_ROW_HIDDEN ); 382 aModel.mbCollapsed = getFlag( nFlags1, BIFF12_ROW_COLLAPSED ); 383 aModel.mbThickTop = getFlag( nFlags1, BIFF12_ROW_THICKTOP ); 384 aModel.mbThickBottom = getFlag( nFlags1, BIFF12_ROW_THICKBOTTOM ); 385 386 // read the column spans 387 sal_Int32 nMaxCol = mrAddressConv.getMaxApiAddress().Column; 388 for( sal_Int32 nSpanIdx = 0; (nSpanIdx < nSpanCount) && !rStrm.isEof(); ++nSpanIdx ) 389 { 390 sal_Int32 nFirstCol, nLastCol; 391 rStrm >> nFirstCol >> nLastCol; 392 aModel.insertColSpan( ValueRange( nFirstCol, ::std::min( nLastCol, nMaxCol ) ) ); 393 } 394 395 // set row properties in the current sheet 396 setRowModel( aModel ); 397 } 398 399 bool SheetDataContext::readCellHeader( SequenceInputStream& rStrm, CellType eCellType ) 400 { 401 switch( eCellType ) 402 { 403 case CELLTYPE_VALUE: 404 case CELLTYPE_FORMULA: rStrm >> maCurrPos.mnCol; break; 405 case CELLTYPE_MULTI: ++maCurrPos.mnCol; break; 406 } 407 408 sal_uInt32 nXfId; 409 rStrm >> nXfId; 410 411 bool bValidAddr = mrAddressConv.convertToCellAddress( maCellData.maCellAddr, maCurrPos, mnSheet, true ); 412 maCellData.mnXfId = extractValue< sal_Int32 >( nXfId, 0, 24 ); 413 maCellData.mbShowPhonetic = getFlag( nXfId, BIFF12_CELL_SHOWPHONETIC ); 414 415 // update used area of the sheet 416 if( bValidAddr ) 417 extendUsedArea( maCellData.maCellAddr ); 418 return bValidAddr; 419 } 420 421 ApiTokenSequence SheetDataContext::readCellFormula( SequenceInputStream& rStrm ) 422 { 423 rStrm.skip( 2 ); 424 return mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_CELL, rStrm ); 425 } 426 427 bool SheetDataContext::readFormulaRef( SequenceInputStream& rStrm ) 428 { 429 BinRange aRange; 430 rStrm >> aRange; 431 return mrAddressConv.convertToCellRange( maFmlaData.maFormulaRef, aRange, mnSheet, true, true ); 432 } 433 434 void SheetDataContext::importCellBool( SequenceInputStream& rStrm, CellType eCellType ) 435 { 436 if( readCellHeader( rStrm, eCellType ) ) 437 { 438 maCellData.mnCellType = XML_b; 439 bool bValue = rStrm.readuInt8() != 0; 440 if( eCellType == CELLTYPE_FORMULA ) 441 mrSheetData.setFormulaCell( maCellData, readCellFormula( rStrm ) ); 442 else 443 mrSheetData.setBooleanCell( maCellData, bValue ); 444 } 445 } 446 447 void SheetDataContext::importCellBlank( SequenceInputStream& rStrm, CellType eCellType ) 448 { 449 OSL_ENSURE( eCellType != CELLTYPE_FORMULA, "SheetDataContext::importCellBlank - no formula cells supported" ); 450 if( readCellHeader( rStrm, eCellType ) ) 451 mrSheetData.setBlankCell( maCellData ); 452 } 453 454 void SheetDataContext::importCellDouble( SequenceInputStream& rStrm, CellType eCellType ) 455 { 456 if( readCellHeader( rStrm, eCellType ) ) 457 { 458 maCellData.mnCellType = XML_n; 459 double fValue = rStrm.readDouble(); 460 if( eCellType == CELLTYPE_FORMULA ) 461 mrSheetData.setFormulaCell( maCellData, readCellFormula( rStrm ) ); 462 else 463 mrSheetData.setValueCell( maCellData, fValue ); 464 } 465 } 466 467 void SheetDataContext::importCellError( SequenceInputStream& rStrm, CellType eCellType ) 468 { 469 if( readCellHeader( rStrm, eCellType ) ) 470 { 471 maCellData.mnCellType = XML_e; 472 sal_uInt8 nErrorCode = rStrm.readuInt8(); 473 if( eCellType == CELLTYPE_FORMULA ) 474 mrSheetData.setFormulaCell( maCellData, readCellFormula( rStrm ) ); 475 else 476 mrSheetData.setErrorCell( maCellData, nErrorCode ); 477 } 478 } 479 480 void SheetDataContext::importCellRk( SequenceInputStream& rStrm, CellType eCellType ) 481 { 482 OSL_ENSURE( eCellType != CELLTYPE_FORMULA, "SheetDataContext::importCellRk - no formula cells supported" ); 483 if( readCellHeader( rStrm, eCellType ) ) 484 { 485 maCellData.mnCellType = XML_n; 486 mrSheetData.setValueCell( maCellData, BiffHelper::calcDoubleFromRk( rStrm.readInt32() ) ); 487 } 488 } 489 490 void SheetDataContext::importCellRString( SequenceInputStream& rStrm, CellType eCellType ) 491 { 492 OSL_ENSURE( eCellType != CELLTYPE_FORMULA, "SheetDataContext::importCellRString - no formula cells supported" ); 493 if( readCellHeader( rStrm, eCellType ) ) 494 { 495 maCellData.mnCellType = XML_inlineStr; 496 RichStringRef xString( new RichString( *this ) ); 497 xString->importString( rStrm, true ); 498 xString->finalizeImport(); 499 mrSheetData.setStringCell( maCellData, xString ); 500 } 501 } 502 503 void SheetDataContext::importCellSi( SequenceInputStream& rStrm, CellType eCellType ) 504 { 505 OSL_ENSURE( eCellType != CELLTYPE_FORMULA, "SheetDataContext::importCellSi - no formula cells supported" ); 506 if( readCellHeader( rStrm, eCellType ) ) 507 { 508 maCellData.mnCellType = XML_s; 509 mrSheetData.setStringCell( maCellData, rStrm.readInt32() ); 510 } 511 } 512 513 void SheetDataContext::importCellString( SequenceInputStream& rStrm, CellType eCellType ) 514 { 515 if( readCellHeader( rStrm, eCellType ) ) 516 { 517 maCellData.mnCellType = XML_inlineStr; 518 // always import the string, stream will point to formula afterwards, if existing 519 RichStringRef xString( new RichString( *this ) ); 520 xString->importString( rStrm, false ); 521 xString->finalizeImport(); 522 if( eCellType == CELLTYPE_FORMULA ) 523 mrSheetData.setFormulaCell( maCellData, readCellFormula( rStrm ) ); 524 else 525 mrSheetData.setStringCell( maCellData, xString ); 526 } 527 } 528 529 void SheetDataContext::importArray( SequenceInputStream& rStrm ) 530 { 531 if( readFormulaRef( rStrm ) && maFmlaData.isValidArrayRef( maCellData.maCellAddr ) ) 532 { 533 rStrm.skip( 1 ); 534 ApiTokenSequence aTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_ARRAY, rStrm ); 535 mrSheetData.createArrayFormula( maFmlaData.maFormulaRef, aTokens ); 536 } 537 } 538 539 void SheetDataContext::importDataTable( SequenceInputStream& rStrm ) 540 { 541 if( readFormulaRef( rStrm ) ) 542 { 543 BinAddress aRef1, aRef2; 544 sal_uInt8 nFlags; 545 rStrm >> aRef1 >> aRef2 >> nFlags; 546 maTableData.maRef1 = FormulaProcessorBase::generateAddress2dString( aRef1, false ); 547 maTableData.maRef2 = FormulaProcessorBase::generateAddress2dString( aRef2, false ); 548 maTableData.mbRowTable = getFlag( nFlags, BIFF12_DATATABLE_ROW ); 549 maTableData.mb2dTable = getFlag( nFlags, BIFF12_DATATABLE_2D ); 550 maTableData.mbRef1Deleted = getFlag( nFlags, BIFF12_DATATABLE_REF1DEL ); 551 maTableData.mbRef2Deleted = getFlag( nFlags, BIFF12_DATATABLE_REF2DEL ); 552 mrSheetData.createTableOperation( maFmlaData.maFormulaRef, maTableData ); 553 } 554 } 555 556 void SheetDataContext::importSharedFmla( SequenceInputStream& rStrm ) 557 { 558 if( readFormulaRef( rStrm ) && maFmlaData.isValidSharedRef( maCellData.maCellAddr ) ) 559 { 560 ApiTokenSequence aTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_SHAREDFORMULA, rStrm ); 561 mrSheetData.createSharedFormula( maCellData.maCellAddr, aTokens ); 562 } 563 } 564 565 // ============================================================================ 566 567 BiffSheetDataContext::BiffSheetDataContext( const WorksheetHelper& rHelper ) : 568 BiffWorksheetContextBase( rHelper ), 569 SheetDataContextBase( rHelper ), 570 mnBiff2XfId( 0 ) 571 { 572 switch( getBiff() ) 573 { 574 case BIFF2: 575 mnFormulaSkipSize = 9; // double formula result, 1 byte flags 576 mnArraySkipSize = 1; // recalc-always flag 577 break; 578 case BIFF3: 579 case BIFF4: 580 mnFormulaSkipSize = 10; // double formula result, 2 byte flags 581 mnArraySkipSize = 2; // 2 byte flags 582 break; 583 case BIFF5: 584 case BIFF8: 585 mnFormulaSkipSize = 14; // double formula result, 2 byte flags, 4 bytes nothing 586 mnArraySkipSize = 6; // 2 byte flags, 4 bytes nothing 587 break; 588 case BIFF_UNKNOWN: 589 break; 590 } 591 } 592 593 void BiffSheetDataContext::importRecord( BiffInputStream& rStrm ) 594 { 595 sal_uInt16 nRecId = rStrm.getRecId(); 596 switch( nRecId ) 597 { 598 // records in all BIFF versions 599 case BIFF2_ID_ARRAY: // #i72713# 600 case BIFF3_ID_ARRAY: importArray( rStrm ); break; 601 case BIFF2_ID_BLANK: 602 case BIFF3_ID_BLANK: importBlank( rStrm ); break; 603 case BIFF2_ID_BOOLERR: 604 case BIFF3_ID_BOOLERR: importBoolErr( rStrm ); break; 605 case BIFF2_ID_INTEGER: importInteger( rStrm ); break; 606 case BIFF_ID_IXFE: rStrm >> mnBiff2XfId; break; 607 case BIFF2_ID_LABEL: 608 case BIFF3_ID_LABEL: importLabel( rStrm ); break; 609 case BIFF2_ID_NUMBER: 610 case BIFF3_ID_NUMBER: importNumber( rStrm ); break; 611 case BIFF_ID_RK: importRk( rStrm ); break; 612 613 // BIFF specific records 614 default: switch( getBiff() ) 615 { 616 case BIFF2: switch( nRecId ) 617 { 618 case BIFF2_ID_DATATABLE: importDataTable( rStrm ); break; 619 case BIFF2_ID_DATATABLE2: importDataTable( rStrm ); break; 620 case BIFF2_ID_FORMULA: importFormula( rStrm ); break; 621 case BIFF2_ID_ROW: importRow( rStrm ); break; 622 } 623 break; 624 625 case BIFF3: switch( nRecId ) 626 { 627 case BIFF3_ID_DATATABLE: importDataTable( rStrm ); break; 628 case BIFF3_ID_FORMULA: importFormula( rStrm ); break; 629 case BIFF3_ID_ROW: importRow( rStrm ); break; 630 } 631 break; 632 633 case BIFF4: switch( nRecId ) 634 { 635 case BIFF3_ID_DATATABLE: importDataTable( rStrm ); break; 636 case BIFF4_ID_FORMULA: importFormula( rStrm ); break; 637 case BIFF3_ID_ROW: importRow( rStrm ); break; 638 } 639 break; 640 641 case BIFF5: switch( nRecId ) 642 { 643 case BIFF3_ID_DATATABLE: importDataTable( rStrm ); break; 644 case BIFF3_ID_FORMULA: 645 case BIFF4_ID_FORMULA: 646 case BIFF5_ID_FORMULA: importFormula( rStrm ); break; 647 case BIFF_ID_MULTBLANK: importMultBlank( rStrm ); break; 648 case BIFF_ID_MULTRK: importMultRk( rStrm ); break; 649 case BIFF3_ID_ROW: importRow( rStrm ); break; 650 case BIFF_ID_RSTRING: importLabel( rStrm ); break; 651 case BIFF_ID_SHAREDFMLA: importSharedFmla( rStrm ); break; 652 } 653 break; 654 655 case BIFF8: switch( nRecId ) 656 { 657 case BIFF3_ID_DATATABLE: importDataTable( rStrm ); break; 658 case BIFF3_ID_FORMULA: 659 case BIFF4_ID_FORMULA: 660 case BIFF5_ID_FORMULA: importFormula( rStrm ); break; 661 case BIFF_ID_LABELSST: importLabelSst( rStrm ); break; 662 case BIFF_ID_MULTBLANK: importMultBlank( rStrm ); break; 663 case BIFF_ID_MULTRK: importMultRk( rStrm ); break; 664 case BIFF3_ID_ROW: importRow( rStrm ); break; 665 case BIFF_ID_RSTRING: importLabel( rStrm ); break; 666 case BIFF_ID_SHAREDFMLA: importSharedFmla( rStrm ); break; 667 } 668 break; 669 670 case BIFF_UNKNOWN: 671 break; 672 } 673 } 674 } 675 676 // private -------------------------------------------------------------------- 677 678 void BiffSheetDataContext::importRow( BiffInputStream& rStrm ) 679 { 680 RowModel aModel; 681 sal_uInt16 nRow, nFirstUsedCol, nFirstFreeCol, nHeight; 682 rStrm >> nRow >> nFirstUsedCol >> nFirstFreeCol >> nHeight; 683 if( getBiff() == BIFF2 ) 684 { 685 rStrm.skip( 2 ); 686 aModel.mbCustomFormat = rStrm.readuInt8() == BIFF2_ROW_CUSTOMFORMAT; 687 if( aModel.mbCustomFormat ) 688 { 689 rStrm.skip( 5 ); 690 aModel.mnXfId = rStrm.readuInt16(); 691 } 692 } 693 else 694 { 695 rStrm.skip( 4 ); 696 sal_uInt32 nFlags = rStrm.readuInt32(); 697 aModel.mnXfId = extractValue< sal_Int32 >( nFlags, 16, 12 ); 698 aModel.mnLevel = extractValue< sal_Int32 >( nFlags, 0, 3 ); 699 aModel.mbCustomFormat = getFlag( nFlags, BIFF_ROW_CUSTOMFORMAT ); 700 aModel.mbCustomHeight = getFlag( nFlags, BIFF_ROW_CUSTOMHEIGHT ); 701 aModel.mbShowPhonetic = getFlag( nFlags, BIFF_ROW_SHOWPHONETIC ); 702 aModel.mbHidden = getFlag( nFlags, BIFF_ROW_HIDDEN ); 703 aModel.mbCollapsed = getFlag( nFlags, BIFF_ROW_COLLAPSED ); 704 aModel.mbThickTop = getFlag( nFlags, BIFF_ROW_THICKTOP ); 705 aModel.mbThickBottom = getFlag( nFlags, BIFF_ROW_THICKBOTTOM ); 706 } 707 708 // row index is 0-based in BIFF, but RowModel expects 1-based 709 aModel.mnRow = static_cast< sal_Int32 >( nRow ) + 1; 710 // row height is in twips in BIFF, convert to points 711 aModel.mfHeight = (nHeight & BIFF_ROW_HEIGHTMASK) / 20.0; 712 // set column spans 713 if( nFirstUsedCol < nFirstFreeCol ) 714 { 715 sal_Int32 nLastCol = ::std::min< sal_Int32 >( nFirstFreeCol - 1, mrAddressConv.getMaxApiAddress().Column ); 716 aModel.insertColSpan( ValueRange( nFirstUsedCol, nLastCol ) ); 717 } 718 719 // set row properties in the current sheet 720 setRowModel( aModel ); 721 } 722 723 bool BiffSheetDataContext::readCellXfId( BiffInputStream& rStrm, const BinAddress& rAddr, bool bBiff2 ) 724 { 725 bool bValidAddr = mrAddressConv.convertToCellAddress( maCellData.maCellAddr, rAddr, mnSheet, true ); 726 if( bValidAddr ) 727 { 728 // update used area of the sheet 729 extendUsedArea( maCellData.maCellAddr ); 730 731 // load the XF identifier according to current BIFF version 732 if( bBiff2 ) 733 { 734 /* #i71453# On first call, check if the file contains XF records 735 (by trying to access the first XF with index 0). If there are 736 no XFs, the explicit formatting information contained in each 737 cell record will be used instead. */ 738 if( !mobBiff2HasXfs ) 739 mobBiff2HasXfs = getStyles().getCellXf( 0 ).get() != 0; 740 // read formatting information (includes the XF identifier) 741 sal_uInt8 nFlags1, nFlags2, nFlags3; 742 rStrm >> nFlags1 >> nFlags2 >> nFlags3; 743 /* If the file contains XFs, extract and set the XF identifier, 744 otherwise get the explicit formatting. */ 745 if( mobBiff2HasXfs.get() ) 746 { 747 maCellData.mnXfId = extractValue< sal_Int32 >( nFlags1, 0, 6 ); 748 /* If the identifier is equal to 63, then the real identifier 749 is contained in the preceding IXFE record (stored in the 750 class member mnBiff2XfId). */ 751 if( maCellData.mnXfId == BIFF2_CELL_USEIXFE ) 752 maCellData.mnXfId = mnBiff2XfId; 753 } 754 else 755 { 756 /* Let the Xf class do the API conversion. Keeping the member 757 maCellData.mnXfId untouched will prevent to trigger the 758 usual XF formatting conversion later on. */ 759 PropertySet aPropSet( getCell( maCellData.maCellAddr ) ); 760 Xf::writeBiff2CellFormatToPropertySet( *this, aPropSet, nFlags1, nFlags2, nFlags3 ); 761 } 762 } 763 else 764 { 765 // BIFF3-BIFF8: 16-bit XF identifier 766 maCellData.mnXfId = rStrm.readuInt16(); 767 } 768 } 769 return bValidAddr; 770 } 771 772 bool BiffSheetDataContext::readCellHeader( BiffInputStream& rStrm, bool bBiff2 ) 773 { 774 BinAddress aAddr; 775 rStrm >> aAddr; 776 return readCellXfId( rStrm, aAddr, bBiff2 ); 777 } 778 779 bool BiffSheetDataContext::readFormulaRef( BiffInputStream& rStrm ) 780 { 781 BinRange aRange; 782 aRange.read( rStrm, false ); // columns always 8-bit 783 return mrAddressConv.convertToCellRange( maFmlaData.maFormulaRef, aRange, mnSheet, true, true ); 784 } 785 786 void BiffSheetDataContext::importBlank( BiffInputStream& rStrm ) 787 { 788 if( readCellHeader( rStrm, rStrm.getRecId() == BIFF2_ID_BLANK ) ) 789 mrSheetData.setBlankCell( maCellData ); 790 } 791 792 void BiffSheetDataContext::importBoolErr( BiffInputStream& rStrm ) 793 { 794 if( readCellHeader( rStrm, rStrm.getRecId() == BIFF2_ID_BOOLERR ) ) 795 { 796 sal_uInt8 nValue, nType; 797 rStrm >> nValue >> nType; 798 switch( nType ) 799 { 800 case BIFF_BOOLERR_BOOL: 801 maCellData.mnCellType = XML_b; 802 mrSheetData.setBooleanCell( maCellData, nValue != 0 ); 803 break; 804 case BIFF_BOOLERR_ERROR: 805 maCellData.mnCellType = XML_e; 806 mrSheetData.setErrorCell( maCellData, nValue ); 807 break; 808 default: 809 OSL_ENSURE( false, "BiffSheetDataContext::importBoolErr - unknown cell type" ); 810 maCellData.mnCellType = XML_TOKEN_INVALID; 811 mrSheetData.setBlankCell( maCellData ); 812 } 813 } 814 } 815 816 void BiffSheetDataContext::importFormula( BiffInputStream& rStrm ) 817 { 818 if( readCellHeader( rStrm, getBiff() == BIFF2 ) ) 819 { 820 maCellData.mnCellType = XML_n; 821 rStrm.skip( mnFormulaSkipSize ); 822 ApiTokenSequence aTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_CELL, rStrm ); 823 mrSheetData.setFormulaCell( maCellData, aTokens ); 824 } 825 } 826 827 void BiffSheetDataContext::importInteger( BiffInputStream& rStrm ) 828 { 829 if( readCellHeader( rStrm, true ) ) 830 { 831 maCellData.mnCellType = XML_n; 832 mrSheetData.setValueCell( maCellData, rStrm.readuInt16() ); 833 } 834 } 835 836 void BiffSheetDataContext::importLabel( BiffInputStream& rStrm ) 837 { 838 /* the deep secrets of BIFF type and record identifier... 839 record id BIFF -> XF type String type 840 0x0004 2-7 -> 3 byte 8-bit length, byte string 841 0x0004 8 -> 3 byte 16-bit length, unicode string 842 0x0204 2-7 -> 2 byte 16-bit length, byte string 843 0x0204 8 -> 2 byte 16-bit length, unicode string 844 */ 845 bool bBiff2Xf = rStrm.getRecId() == BIFF2_ID_LABEL; 846 if( readCellHeader( rStrm, bBiff2Xf ) ) 847 { 848 maCellData.mnCellType = XML_inlineStr; 849 if( getBiff() == BIFF8 ) 850 { 851 // string may contain rich-text formatting 852 RichStringRef xString( new RichString( *this ) ); 853 xString->importUniString( rStrm ); 854 xString->finalizeImport(); 855 mrSheetData.setStringCell( maCellData, xString ); 856 } 857 else 858 { 859 // #i63105# use text encoding from FONT record 860 rtl_TextEncoding eTextEnc = getTextEncoding(); 861 if( const Font* pFont = getStyles().getFontFromCellXf( maCellData.mnXfId ).get() ) 862 eTextEnc = pFont->getFontEncoding(); 863 // RSTRING record contains rich-text formatting 864 if( rStrm.getRecId() == BIFF_ID_RSTRING ) 865 { 866 BiffStringFlags nFlags = BIFF_STR_EXTRAFONTS; 867 // BIFF2 record identifier: 8-bit string length (see above) 868 setFlag( nFlags, BIFF_STR_8BITLENGTH, bBiff2Xf ); 869 RichStringRef xString( new RichString( *this ) ); 870 xString->importByteString( rStrm, eTextEnc, nFlags ); 871 xString->finalizeImport(); 872 mrSheetData.setStringCell( maCellData, xString ); 873 } 874 else 875 { 876 // BIFF2 record identifier: 8-bit string length (see above) 877 OUString aText = rStrm.readByteStringUC( !bBiff2Xf, eTextEnc ); 878 mrSheetData.setStringCell( maCellData, aText ); 879 } 880 } 881 } 882 } 883 884 void BiffSheetDataContext::importLabelSst( BiffInputStream& rStrm ) 885 { 886 if( readCellHeader( rStrm, false ) ) 887 { 888 maCellData.mnCellType = XML_s; 889 mrSheetData.setStringCell( maCellData, rStrm.readInt32() ); 890 } 891 } 892 893 void BiffSheetDataContext::importMultBlank( BiffInputStream& rStrm ) 894 { 895 BinAddress aAddr; 896 bool bValidAddr = true; 897 for( rStrm >> aAddr; bValidAddr && (rStrm.getRemaining() > 2); ++aAddr.mnCol ) 898 if( (bValidAddr = readCellXfId( rStrm, aAddr, false )) == true ) 899 mrSheetData.setBlankCell( maCellData ); 900 } 901 902 void BiffSheetDataContext::importMultRk( BiffInputStream& rStrm ) 903 { 904 BinAddress aAddr; 905 bool bValidAddr = true; 906 for( rStrm >> aAddr; bValidAddr && (rStrm.getRemaining() > 2); ++aAddr.mnCol ) 907 { 908 if( (bValidAddr = readCellXfId( rStrm, aAddr, false )) == true ) 909 { 910 maCellData.mnCellType = XML_n; 911 sal_Int32 nRkValue = rStrm.readInt32(); 912 mrSheetData.setValueCell( maCellData, BiffHelper::calcDoubleFromRk( nRkValue ) ); 913 } 914 } 915 } 916 917 void BiffSheetDataContext::importNumber( BiffInputStream& rStrm ) 918 { 919 if( readCellHeader( rStrm, rStrm.getRecId() == BIFF2_ID_NUMBER ) ) 920 { 921 maCellData.mnCellType = XML_n; 922 mrSheetData.setValueCell( maCellData, rStrm.readDouble() ); 923 } 924 } 925 926 void BiffSheetDataContext::importRk( BiffInputStream& rStrm ) 927 { 928 if( readCellHeader( rStrm, false ) ) 929 { 930 maCellData.mnCellType = XML_n; 931 mrSheetData.setValueCell( maCellData, BiffHelper::calcDoubleFromRk( rStrm.readInt32() ) ); 932 } 933 } 934 935 void BiffSheetDataContext::importArray( BiffInputStream& rStrm ) 936 { 937 if( readFormulaRef( rStrm ) && maFmlaData.isValidArrayRef( maCellData.maCellAddr ) ) 938 { 939 rStrm.skip( mnArraySkipSize ); 940 ApiTokenSequence aTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_ARRAY, rStrm ); 941 mrSheetData.createArrayFormula( maFmlaData.maFormulaRef, aTokens ); 942 } 943 } 944 945 void BiffSheetDataContext::importDataTable( BiffInputStream& rStrm ) 946 { 947 if( readFormulaRef( rStrm ) ) 948 { 949 DataTableModel aModel; 950 BinAddress aRef1, aRef2; 951 switch( rStrm.getRecId() ) 952 { 953 case BIFF2_ID_DATATABLE: 954 rStrm.skip( 1 ); 955 aModel.mbRowTable = rStrm.readuInt8() != 0; 956 aModel.mb2dTable = false; 957 rStrm >> aRef1; 958 break; 959 case BIFF2_ID_DATATABLE2: 960 rStrm.skip( 2 ); 961 aModel.mb2dTable = true; 962 rStrm >> aRef1 >> aRef2; 963 break; 964 case BIFF3_ID_DATATABLE: 965 { 966 sal_uInt16 nFlags; 967 rStrm >> nFlags >> aRef1 >> aRef2; 968 aModel.mbRowTable = getFlag( nFlags, BIFF_DATATABLE_ROW ); 969 aModel.mb2dTable = getFlag( nFlags, BIFF_DATATABLE_2D ); 970 aModel.mbRef1Deleted = getFlag( nFlags, BIFF_DATATABLE_REF1DEL ); 971 aModel.mbRef2Deleted = getFlag( nFlags, BIFF_DATATABLE_REF2DEL ); 972 } 973 break; 974 default: 975 OSL_ENSURE( false, "BiffSheetDataContext::importDataTable - unknown record id" ); 976 } 977 aModel.maRef1 = FormulaProcessorBase::generateAddress2dString( aRef1, false ); 978 aModel.maRef2 = FormulaProcessorBase::generateAddress2dString( aRef2, false ); 979 mrSheetData.createTableOperation( maFmlaData.maFormulaRef, aModel ); 980 } 981 } 982 983 void BiffSheetDataContext::importSharedFmla( BiffInputStream& rStrm ) 984 { 985 if( readFormulaRef( rStrm ) && maFmlaData.isValidSharedRef( maCellData.maCellAddr ) ) 986 { 987 rStrm.skip( 2 ); // flags 988 ApiTokenSequence aTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_SHAREDFORMULA, rStrm ); 989 mrSheetData.createSharedFormula( maCellData.maCellAddr, aTokens ); 990 } 991 } 992 993 // ============================================================================ 994 995 } // namespace xls 996 } // namespace oox 997