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/externallinkfragment.hxx"
25
26 #include <com/sun/star/sheet/XExternalSheetCache.hpp>
27 #include "oox/helper/attributelist.hxx"
28 #include "oox/xls/biffinputstream.hxx"
29 #include "oox/xls/defnamesbuffer.hxx"
30 #include "oox/xls/sheetdatacontext.hxx"
31 #include "oox/xls/unitconverter.hxx"
32
33 namespace oox {
34 namespace xls {
35
36 // ============================================================================
37
38 using namespace ::com::sun::star::sheet;
39 using namespace ::com::sun::star::table;
40 using namespace ::com::sun::star::uno;
41 using namespace ::oox::core;
42
43 using ::rtl::OUString;
44
45 // ============================================================================
46 // ============================================================================
47
ExternalSheetDataContext(WorkbookFragmentBase & rFragment,const Reference<XExternalSheetCache> & rxSheetCache)48 ExternalSheetDataContext::ExternalSheetDataContext(
49 WorkbookFragmentBase& rFragment, const Reference< XExternalSheetCache >& rxSheetCache ) :
50 WorkbookContextBase( rFragment ),
51 mxSheetCache( rxSheetCache )
52 {
53 OSL_ENSURE( mxSheetCache.is(), "ExternalSheetDataContext::ExternalSheetDataContext - missing sheet cache" );
54 }
55
onCreateContext(sal_Int32 nElement,const AttributeList & rAttribs)56 ContextHandlerRef ExternalSheetDataContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
57 {
58 switch( getCurrentElement() )
59 {
60 case XLS_TOKEN( sheetData ):
61 if( nElement == XLS_TOKEN( row ) ) return this;
62 break;
63 case XLS_TOKEN( row ):
64 if( nElement == XLS_TOKEN( cell ) ) { importCell( rAttribs ); return this; }
65 break;
66 case XLS_TOKEN( cell ):
67 if( nElement == XLS_TOKEN( v ) ) return this; // collect characters in onCharacters()
68 break;
69 }
70 return 0;
71 }
72
onCharacters(const OUString & rChars)73 void ExternalSheetDataContext::onCharacters( const OUString& rChars )
74 {
75 if( isCurrentElement( XLS_TOKEN( v ) ) )
76 {
77 switch( mnCurrType )
78 {
79 case XML_b:
80 case XML_n:
81 setCellValue( Any( rChars.toDouble() ) );
82 break;
83 case XML_e:
84 setCellValue( Any( BiffHelper::calcDoubleFromError( getUnitConverter().calcBiffErrorCode( rChars ) ) ) );
85 break;
86 case XML_str:
87 setCellValue( Any( rChars ) );
88 break;
89 }
90 mnCurrType = XML_TOKEN_INVALID;
91 }
92 }
93
onCreateRecordContext(sal_Int32 nRecId,SequenceInputStream & rStrm)94 ContextHandlerRef ExternalSheetDataContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
95 {
96 switch( getCurrentElement() )
97 {
98 case BIFF12_ID_EXTSHEETDATA:
99 if( nRecId == BIFF12_ID_EXTROW ) { maCurrPos.Row = rStrm.readInt32(); return this; }
100 break;
101 case BIFF12_ID_EXTROW:
102 switch( nRecId )
103 {
104 case BIFF12_ID_EXTCELL_BLANK: importExtCellBlank( rStrm ); break;
105 case BIFF12_ID_EXTCELL_BOOL: importExtCellBool( rStrm ); break;
106 case BIFF12_ID_EXTCELL_DOUBLE: importExtCellDouble( rStrm ); break;
107 case BIFF12_ID_EXTCELL_ERROR: importExtCellError( rStrm ); break;
108 case BIFF12_ID_EXTCELL_STRING: importExtCellString( rStrm ); break;
109 }
110 break;
111 }
112 return 0;
113 }
114
115 // private --------------------------------------------------------------------
116
importCell(const AttributeList & rAttribs)117 void ExternalSheetDataContext::importCell( const AttributeList& rAttribs )
118 {
119 if( getAddressConverter().convertToCellAddress( maCurrPos, rAttribs.getString( XML_r, OUString() ), 0, false ) )
120 mnCurrType = rAttribs.getToken( XML_t, XML_n );
121 else
122 mnCurrType = XML_TOKEN_INVALID;
123 }
124
importExtCellBlank(SequenceInputStream & rStrm)125 void ExternalSheetDataContext::importExtCellBlank( SequenceInputStream& rStrm )
126 {
127 maCurrPos.Column = rStrm.readInt32();
128 setCellValue( Any( OUString() ) );
129 }
130
importExtCellBool(SequenceInputStream & rStrm)131 void ExternalSheetDataContext::importExtCellBool( SequenceInputStream& rStrm )
132 {
133 maCurrPos.Column = rStrm.readInt32();
134 double fValue = (rStrm.readuInt8() == 0) ? 0.0 : 1.0;
135 setCellValue( Any( fValue ) );
136 }
137
importExtCellDouble(SequenceInputStream & rStrm)138 void ExternalSheetDataContext::importExtCellDouble( SequenceInputStream& rStrm )
139 {
140 maCurrPos.Column = rStrm.readInt32();
141 setCellValue( Any( rStrm.readDouble() ) );
142 }
143
importExtCellError(SequenceInputStream & rStrm)144 void ExternalSheetDataContext::importExtCellError( SequenceInputStream& rStrm )
145 {
146 maCurrPos.Column = rStrm.readInt32();
147 setCellValue( Any( BiffHelper::calcDoubleFromError( rStrm.readuInt8() ) ) );
148 }
149
importExtCellString(SequenceInputStream & rStrm)150 void ExternalSheetDataContext::importExtCellString( SequenceInputStream& rStrm )
151 {
152 maCurrPos.Column = rStrm.readInt32();
153 setCellValue( Any( BiffHelper::readString( rStrm ) ) );
154 }
155
setCellValue(const Any & rValue)156 void ExternalSheetDataContext::setCellValue( const Any& rValue )
157 {
158 if( mxSheetCache.is() && getAddressConverter().checkCellAddress( maCurrPos, false ) ) try
159 {
160 mxSheetCache->setCellValue( maCurrPos.Column, maCurrPos.Row, rValue );
161 }
162 catch( Exception& )
163 {
164 }
165 }
166
167 // ============================================================================
168
ExternalLinkFragment(const WorkbookHelper & rHelper,const OUString & rFragmentPath,ExternalLink & rExtLink)169 ExternalLinkFragment::ExternalLinkFragment( const WorkbookHelper& rHelper,
170 const OUString& rFragmentPath, ExternalLink& rExtLink ) :
171 WorkbookFragmentBase( rHelper, rFragmentPath ),
172 mrExtLink( rExtLink ),
173 mnResultType( XML_TOKEN_INVALID )
174 {
175 }
176
onCreateContext(sal_Int32 nElement,const AttributeList & rAttribs)177 ContextHandlerRef ExternalLinkFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
178 {
179 switch( getCurrentElement() )
180 {
181 case XML_ROOT_CONTEXT:
182 if( nElement == XLS_TOKEN( externalLink ) ) return this;
183 break;
184
185 case XLS_TOKEN( externalLink ):
186 switch( nElement )
187 {
188 case XLS_TOKEN( externalBook ): mrExtLink.importExternalBook( getRelations(), rAttribs ); return this;
189 case XLS_TOKEN( ddeLink ): mrExtLink.importDdeLink( rAttribs ); return this;
190 case XLS_TOKEN( oleLink ): mrExtLink.importOleLink( getRelations(), rAttribs ); return this;
191 }
192 break;
193
194 case XLS_TOKEN( externalBook ):
195 switch( nElement )
196 {
197 case XLS_TOKEN( sheetNames ):
198 case XLS_TOKEN( definedNames ):
199 case XLS_TOKEN( sheetDataSet ): return this;
200 }
201 break;
202
203 case XLS_TOKEN( sheetNames ):
204 if( nElement == XLS_TOKEN( sheetName ) ) mrExtLink.importSheetName( rAttribs );
205 break;
206 case XLS_TOKEN( definedNames ):
207 if( nElement == XLS_TOKEN( definedName ) ) mrExtLink.importDefinedName( rAttribs );
208 break;
209 case XLS_TOKEN( sheetDataSet ):
210 if( (nElement == XLS_TOKEN( sheetData )) && (mrExtLink.getLinkType() == LINKTYPE_EXTERNAL) )
211 return createSheetDataContext( rAttribs.getInteger( XML_sheetId, -1 ) );
212 break;
213
214 case XLS_TOKEN( ddeLink ):
215 if( nElement == XLS_TOKEN( ddeItems ) ) return this;
216 break;
217 case XLS_TOKEN( ddeItems ):
218 if( nElement == XLS_TOKEN( ddeItem ) )
219 {
220 mxExtName = mrExtLink.importDdeItem( rAttribs );
221 return this;
222 }
223 break;
224 case XLS_TOKEN( ddeItem ):
225 if( nElement == XLS_TOKEN( values ) )
226 {
227 if( mxExtName.get() ) mxExtName->importValues( rAttribs );
228 return this;
229 }
230 break;
231 case XLS_TOKEN( values ):
232 if( nElement == XLS_TOKEN( value ) )
233 {
234 mnResultType = rAttribs.getToken( XML_t, XML_n );
235 return this;
236 }
237 break;
238 case XLS_TOKEN( value ):
239 if( nElement == XLS_TOKEN( val ) ) return this; // collect value in onCharacters()
240 break;
241
242 case XLS_TOKEN( oleLink ):
243 if( nElement == XLS_TOKEN( oleItems ) ) return this;
244 break;
245 case XLS_TOKEN( oleItems ):
246 if( nElement == XLS_TOKEN( oleItem ) ) mxExtName = mrExtLink.importOleItem( rAttribs );
247 break;
248 }
249 return 0;
250 }
251
onCharacters(const OUString & rChars)252 void ExternalLinkFragment::onCharacters( const OUString& rChars )
253 {
254 if( isCurrentElement( XLS_TOKEN( val ) ) )
255 maResultValue = rChars;
256 }
257
onEndElement()258 void ExternalLinkFragment::onEndElement()
259 {
260 if( isCurrentElement( XLS_TOKEN( value ) ) && mxExtName.get() ) switch( mnResultType )
261 {
262 case XML_b:
263 mxExtName->appendResultValue( maResultValue.toDouble() );
264 break;
265 case XML_e:
266 mxExtName->appendResultValue( BiffHelper::calcDoubleFromError( getUnitConverter().calcBiffErrorCode( maResultValue ) ) );
267 break;
268 case XML_n:
269 mxExtName->appendResultValue( maResultValue.toDouble() );
270 break;
271 case XML_str:
272 mxExtName->appendResultValue( maResultValue );
273 break;
274 default:
275 mxExtName->appendResultValue( BiffHelper::calcDoubleFromError( BIFF_ERR_NA ) );
276 }
277 }
278
onCreateRecordContext(sal_Int32 nRecId,SequenceInputStream & rStrm)279 ContextHandlerRef ExternalLinkFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
280 {
281 switch( getCurrentElement() )
282 {
283 case XML_ROOT_CONTEXT:
284 if( nRecId == BIFF12_ID_EXTERNALBOOK )
285 {
286 mrExtLink.importExternalBook( getRelations(), rStrm );
287 return this;
288 }
289 break;
290
291 case BIFF12_ID_EXTERNALBOOK:
292 switch( nRecId )
293 {
294 case BIFF12_ID_EXTSHEETDATA:
295 if( mrExtLink.getLinkType() == LINKTYPE_EXTERNAL )
296 return createSheetDataContext( rStrm.readInt32() );
297 break;
298
299 case BIFF12_ID_EXTSHEETNAMES: mrExtLink.importExtSheetNames( rStrm ); break;
300 case BIFF12_ID_EXTERNALNAME: mxExtName = mrExtLink.importExternalName( rStrm ); return this;
301 }
302 break;
303
304 case BIFF12_ID_EXTERNALNAME:
305 switch( nRecId )
306 {
307 case BIFF12_ID_EXTERNALNAMEFLAGS: if( mxExtName.get() ) mxExtName->importExternalNameFlags( rStrm ); break;
308 case BIFF12_ID_DDEITEMVALUES: if( mxExtName.get() ) mxExtName->importDdeItemValues( rStrm ); return this;
309 }
310 break;
311
312 case BIFF12_ID_DDEITEMVALUES:
313 switch( nRecId )
314 {
315 case BIFF12_ID_DDEITEM_BOOL: if( mxExtName.get() ) mxExtName->importDdeItemBool( rStrm ); break;
316 case BIFF12_ID_DDEITEM_DOUBLE: if( mxExtName.get() ) mxExtName->importDdeItemDouble( rStrm ); break;
317 case BIFF12_ID_DDEITEM_ERROR: if( mxExtName.get() ) mxExtName->importDdeItemError( rStrm ); break;
318 case BIFF12_ID_DDEITEM_STRING: if( mxExtName.get() ) mxExtName->importDdeItemString( rStrm ); break;
319 }
320 break;
321 }
322 return 0;
323 }
324
createSheetDataContext(sal_Int32 nSheetId)325 ContextHandlerRef ExternalLinkFragment::createSheetDataContext( sal_Int32 nSheetId )
326 {
327 return new ExternalSheetDataContext( *this, mrExtLink.getSheetCache( nSheetId ) );
328 }
329
getRecordInfos() const330 const RecordInfo* ExternalLinkFragment::getRecordInfos() const
331 {
332 static const RecordInfo spRecInfos[] =
333 {
334 { BIFF12_ID_DDEITEMVALUES, BIFF12_ID_DDEITEMVALUES + 1 },
335 { BIFF12_ID_EXTERNALBOOK, BIFF12_ID_EXTERNALBOOK + 228 },
336 { BIFF12_ID_EXTERNALNAME, BIFF12_ID_EXTERNALNAME + 10 },
337 { BIFF12_ID_EXTROW, -1 },
338 { BIFF12_ID_EXTSHEETDATA, BIFF12_ID_EXTSHEETDATA + 1 },
339 { -1, -1 }
340 };
341 return spRecInfos;
342 }
343
344 // ============================================================================
345 // ============================================================================
346
BiffExternalSheetDataContext(const WorkbookHelper & rHelper,bool bImportDefNames)347 BiffExternalSheetDataContext::BiffExternalSheetDataContext( const WorkbookHelper& rHelper, bool bImportDefNames ) :
348 BiffWorkbookContextBase( rHelper ),
349 mbImportDefNames( bImportDefNames )
350 {
351 }
352
~BiffExternalSheetDataContext()353 BiffExternalSheetDataContext::~BiffExternalSheetDataContext()
354 {
355 }
356
importRecord(BiffInputStream & rStrm)357 void BiffExternalSheetDataContext::importRecord( BiffInputStream& rStrm )
358 {
359 sal_uInt16 nRecId = rStrm.getRecId();
360 switch( getBiff() )
361 {
362 case BIFF2: switch( nRecId )
363 {
364 case BIFF2_ID_EXTERNALNAME: importExternalName( rStrm ); break;
365 case BIFF_ID_EXTERNSHEET: importExternSheet( rStrm ); break;
366 case BIFF2_ID_DEFINEDNAME: importDefinedName( rStrm ); break;
367 }
368 break;
369 case BIFF3: switch( nRecId )
370 {
371 case BIFF_ID_CRN: importCrn( rStrm ); break;
372 case BIFF3_ID_EXTERNALNAME: importExternalName( rStrm ); break;
373 case BIFF_ID_EXTERNSHEET: importExternSheet( rStrm ); break;
374 case BIFF3_ID_DEFINEDNAME: importDefinedName( rStrm ); break;
375 case BIFF_ID_XCT: importXct( rStrm ); break;
376 }
377 break;
378 case BIFF4: switch( nRecId )
379 {
380 case BIFF_ID_CRN: importCrn( rStrm ); break;
381 case BIFF3_ID_EXTERNALNAME: importExternalName( rStrm ); break;
382 case BIFF_ID_EXTERNSHEET: importExternSheet( rStrm ); break;
383 case BIFF3_ID_DEFINEDNAME: importDefinedName( rStrm ); break;
384 case BIFF_ID_XCT: importXct( rStrm ); break;
385 }
386 break;
387 case BIFF5: switch( nRecId )
388 {
389 case BIFF_ID_CRN: importCrn( rStrm ); break;
390 case BIFF5_ID_EXTERNALNAME: importExternalName( rStrm ); break;
391 case BIFF_ID_EXTERNSHEET: importExternSheet( rStrm ); break;
392 case BIFF5_ID_DEFINEDNAME: importDefinedName( rStrm ); break;
393 case BIFF_ID_XCT: importXct( rStrm ); break;
394 }
395 break;
396 case BIFF8: switch( nRecId )
397 {
398 case BIFF_ID_CRN: importCrn( rStrm ); break;
399 case BIFF_ID_EXTERNALBOOK: importExternalBook( rStrm ); break;
400 case BIFF5_ID_EXTERNALNAME: importExternalName( rStrm ); break;
401 case BIFF_ID_EXTERNSHEET: importExternSheet( rStrm ); break;
402 case BIFF5_ID_DEFINEDNAME: importDefinedName( rStrm ); break;
403 case BIFF_ID_XCT: importXct( rStrm ); break;
404 }
405 break;
406 case BIFF_UNKNOWN: break;
407 }
408 }
409
410 // private --------------------------------------------------------------------
411
importExternSheet(BiffInputStream & rStrm)412 void BiffExternalSheetDataContext::importExternSheet( BiffInputStream& rStrm )
413 {
414 mxSheetCache.clear();
415 if( getBiff() == BIFF8 )
416 getExternalLinks().importExternSheet8( rStrm );
417 else
418 mxExtLink = getExternalLinks().importExternSheet( rStrm );
419 }
420
importExternalBook(BiffInputStream & rStrm)421 void BiffExternalSheetDataContext::importExternalBook( BiffInputStream& rStrm )
422 {
423 mxSheetCache.clear();
424 mxExtLink = getExternalLinks().importExternalBook( rStrm );
425 }
426
importExternalName(BiffInputStream & rStrm)427 void BiffExternalSheetDataContext::importExternalName( BiffInputStream& rStrm )
428 {
429 if( mxExtLink.get() )
430 mxExtLink->importExternalName( rStrm );
431 }
432
importXct(BiffInputStream & rStrm)433 void BiffExternalSheetDataContext::importXct( BiffInputStream& rStrm )
434 {
435 mxSheetCache.clear();
436 if( mxExtLink.get() && (mxExtLink->getLinkType() == LINKTYPE_EXTERNAL) )
437 {
438 switch( getBiff() )
439 {
440 case BIFF2:
441 break;
442 case BIFF3:
443 case BIFF4:
444 case BIFF5:
445 mxSheetCache = mxExtLink->getSheetCache( 0 );
446 break;
447 case BIFF8:
448 rStrm.skip( 2 );
449 mxSheetCache = mxExtLink->getSheetCache( rStrm.readInt16() );
450 break;
451 case BIFF_UNKNOWN:
452 break;
453 }
454 }
455 }
456
importCrn(BiffInputStream & rStrm)457 void BiffExternalSheetDataContext::importCrn( BiffInputStream& rStrm )
458 {
459 if( !mxSheetCache.is() ) return;
460
461 sal_uInt8 nCol2, nCol1;
462 sal_uInt16 nRow;
463 rStrm >> nCol2 >> nCol1 >> nRow;
464 bool bLoop = true;
465 for( BinAddress aBinAddr( nCol1, nRow ); bLoop && !rStrm.isEof() && (aBinAddr.mnCol <= nCol2); ++aBinAddr.mnCol )
466 {
467 switch( rStrm.readuInt8() )
468 {
469 case BIFF_DATATYPE_EMPTY:
470 rStrm.skip( 8 );
471 setCellValue( aBinAddr, Any( OUString() ) );
472 break;
473 case BIFF_DATATYPE_DOUBLE:
474 setCellValue( aBinAddr, Any( rStrm.readDouble() ) );
475 break;
476 case BIFF_DATATYPE_STRING:
477 {
478 OUString aText = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( false, getTextEncoding() );
479 setCellValue( aBinAddr, Any( aText ) );
480 }
481 break;
482 case BIFF_DATATYPE_BOOL:
483 {
484 double fValue = (rStrm.readuInt8() == 0) ? 0.0 : 1.0;
485 setCellValue( aBinAddr, Any( fValue ) );
486 rStrm.skip( 7 );
487 }
488 break;
489 case BIFF_DATATYPE_ERROR:
490 setCellValue( aBinAddr, Any( BiffHelper::calcDoubleFromError( rStrm.readuInt8() ) ) );
491 rStrm.skip( 7 );
492 break;
493 default:
494 OSL_ENSURE( false, "BiffExternalSheetDataContext::importCrn - unknown data type" );
495 bLoop = false;
496 }
497 }
498 }
499
importDefinedName(BiffInputStream & rStrm)500 void BiffExternalSheetDataContext::importDefinedName( BiffInputStream& rStrm )
501 {
502 if( mbImportDefNames )
503 getDefinedNames().importDefinedName( rStrm );
504 }
505
setCellValue(const BinAddress & rBinAddr,const Any & rValue)506 void BiffExternalSheetDataContext::setCellValue( const BinAddress& rBinAddr, const Any& rValue )
507 {
508 CellAddress aCellPos;
509 if( mxSheetCache.is() && getAddressConverter().convertToCellAddress( aCellPos, rBinAddr, 0, false ) ) try
510 {
511 mxSheetCache->setCellValue( aCellPos.Column, aCellPos.Row, rValue );
512 }
513 catch( Exception& )
514 {
515 }
516 }
517
518 // ============================================================================
519
BiffExternalLinkFragment(const BiffWorkbookFragmentBase & rParent)520 BiffExternalLinkFragment::BiffExternalLinkFragment( const BiffWorkbookFragmentBase& rParent ) :
521 BiffWorkbookFragmentBase( rParent )
522 {
523 }
524
importFragment()525 bool BiffExternalLinkFragment::importFragment()
526 {
527 // process all record in this sheet fragment
528 BiffExternalSheetDataContext aSheetContext( *this, false );
529 BiffInputStream& rStrm = getInputStream();
530 while( rStrm.startNextRecord() && (rStrm.getRecId() != BIFF_ID_EOF) )
531 {
532 if( BiffHelper::isBofRecord( rStrm ) )
533 skipFragment(); // skip unknown embedded fragments
534 else
535 aSheetContext.importRecord( rStrm );
536 }
537 return !rStrm.isEof() && (rStrm.getRecId() == BIFF_ID_EOF);
538 }
539
540 // ============================================================================
541 // ============================================================================
542
543 } // namespace xls
544 } // namespace oox
545