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