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