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
SheetDataContextBase(const WorksheetHelper & rHelper)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
~SheetDataContextBase()113 SheetDataContextBase::~SheetDataContextBase()
114 {
115 }
116
117 // ============================================================================
118
SheetDataContext(WorksheetFragmentBase & rFragment)119 SheetDataContext::SheetDataContext( WorksheetFragmentBase& rFragment ) :
120 WorksheetContextBase( rFragment ),
121 SheetDataContextBase( rFragment ),
122 mbHasFormula( false ),
123 mbValidRange( false )
124 {
125 }
126
onCreateContext(sal_Int32 nElement,const AttributeList & rAttribs)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
onCharacters(const OUString & rChars)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
onEndElement()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
onCreateRecordContext(sal_Int32 nRecId,SequenceInputStream & rStrm)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
importRow(const AttributeList & rAttribs)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
importCell(const AttributeList & rAttribs)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
importFormula(const AttributeList & rAttribs)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
importRow(SequenceInputStream & rStrm)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
readCellHeader(SequenceInputStream & rStrm,CellType eCellType)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
readCellFormula(SequenceInputStream & rStrm)449 ApiTokenSequence SheetDataContext::readCellFormula( SequenceInputStream& rStrm )
450 {
451 rStrm.skip( 2 );
452 return mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_CELL, rStrm );
453 }
454
readFormulaRef(SequenceInputStream & rStrm)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
importCellBool(SequenceInputStream & rStrm,CellType eCellType)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
importCellBlank(SequenceInputStream & rStrm,CellType eCellType)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
importCellDouble(SequenceInputStream & rStrm,CellType eCellType)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
importCellError(SequenceInputStream & rStrm,CellType eCellType)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
importCellRk(SequenceInputStream & rStrm,CellType eCellType)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
importCellRString(SequenceInputStream & rStrm,CellType eCellType)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
importCellSi(SequenceInputStream & rStrm,CellType eCellType)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
importCellString(SequenceInputStream & rStrm,CellType eCellType)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
importArray(SequenceInputStream & rStrm)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
importDataTable(SequenceInputStream & rStrm)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
importSharedFmla(SequenceInputStream & rStrm)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
BiffSheetDataContext(const WorksheetHelper & rHelper)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
importRecord(BiffInputStream & rStrm)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
importRow(BiffInputStream & rStrm)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
readCellXfId(BiffInputStream & rStrm,const BinAddress & rAddr,bool bBiff2)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
readCellHeader(BiffInputStream & rStrm,bool bBiff2)800 bool BiffSheetDataContext::readCellHeader( BiffInputStream& rStrm, bool bBiff2 )
801 {
802 BinAddress aAddr;
803 rStrm >> aAddr;
804 return readCellXfId( rStrm, aAddr, bBiff2 );
805 }
806
readFormulaRef(BiffInputStream & rStrm)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
importBlank(BiffInputStream & rStrm)814 void BiffSheetDataContext::importBlank( BiffInputStream& rStrm )
815 {
816 if( readCellHeader( rStrm, rStrm.getRecId() == BIFF2_ID_BLANK ) )
817 mrSheetData.setBlankCell( maCellData );
818 }
819
importBoolErr(BiffInputStream & rStrm)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
importFormula(BiffInputStream & rStrm)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
importInteger(BiffInputStream & rStrm)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
importLabel(BiffInputStream & rStrm)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
importLabelSst(BiffInputStream & rStrm)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
importMultBlank(BiffInputStream & rStrm)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
importMultRk(BiffInputStream & rStrm)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
importNumber(BiffInputStream & rStrm)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
importRk(BiffInputStream & rStrm)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
importArray(BiffInputStream & rStrm)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
importDataTable(BiffInputStream & rStrm)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
importSharedFmla(BiffInputStream & rStrm)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