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