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/externallinkbuffer.hxx"
25
26 #include <com/sun/star/sheet/ComplexReference.hpp>
27 #include <com/sun/star/sheet/DDELinkInfo.hpp>
28 #include <com/sun/star/sheet/ExternalLinkType.hpp>
29 #include <com/sun/star/sheet/ExternalReference.hpp>
30 #include <com/sun/star/sheet/ReferenceFlags.hpp>
31 #include <com/sun/star/sheet/SingleReference.hpp>
32 #include <com/sun/star/sheet/XDDELinks.hpp>
33 #include <com/sun/star/sheet/XDDELink.hpp>
34 #include <com/sun/star/sheet/XDDELinkResults.hpp>
35 #include <com/sun/star/sheet/XExternalDocLink.hpp>
36 #include <com/sun/star/sheet/XExternalDocLinks.hpp>
37 #include <rtl/strbuf.hxx>
38 #include "oox/core/filterbase.hxx"
39 #include "oox/helper/attributelist.hxx"
40 #include "oox/xls/addressconverter.hxx"
41 #include "oox/xls/biffinputstream.hxx"
42 #include "oox/xls/excelhandlers.hxx"
43 #include "oox/xls/formulaparser.hxx"
44 #include "oox/xls/worksheetbuffer.hxx"
45
46 namespace oox {
47 namespace xls {
48
49 // ============================================================================
50
51 using namespace ::com::sun::star::sheet;
52 using namespace ::com::sun::star::table;
53 using namespace ::com::sun::star::uno;
54
55 using ::oox::core::Relation;
56 using ::oox::core::Relations;
57 using ::rtl::OString;
58 using ::rtl::OStringBuffer;
59 using ::rtl::OStringToOUString;
60 using ::rtl::OUString;
61
62 // ============================================================================
63
64 namespace {
65
66 const sal_uInt16 BIFF12_EXTERNALBOOK_BOOK = 0;
67 const sal_uInt16 BIFF12_EXTERNALBOOK_DDE = 1;
68 const sal_uInt16 BIFF12_EXTERNALBOOK_OLE = 2;
69
70 const sal_uInt16 BIFF12_EXTNAME_AUTOMATIC = 0x0002;
71 const sal_uInt16 BIFF12_EXTNAME_PREFERPIC = 0x0004;
72 const sal_uInt16 BIFF12_EXTNAME_STDDOCNAME = 0x0008;
73 const sal_uInt16 BIFF12_EXTNAME_OLEOBJECT = 0x0010;
74 const sal_uInt16 BIFF12_EXTNAME_ICONIFIED = 0x0020;
75
76 const sal_uInt16 BIFF_EXTNAME_BUILTIN = 0x0001;
77 const sal_uInt16 BIFF_EXTNAME_AUTOMATIC = 0x0002;
78 const sal_uInt16 BIFF_EXTNAME_PREFERPIC = 0x0004;
79 const sal_uInt16 BIFF_EXTNAME_STDDOCNAME = 0x0008;
80 const sal_uInt16 BIFF_EXTNAME_OLEOBJECT = 0x0010;
81 const sal_uInt16 BIFF_EXTNAME_ICONIFIED = 0x8000;
82
83 } // namespace
84
85 // ============================================================================
86
ExternalNameModel()87 ExternalNameModel::ExternalNameModel() :
88 mbBuiltIn( false ),
89 mbNotify( false ),
90 mbPreferPic( false ),
91 mbStdDocName( false ),
92 mbOleObj( false ),
93 mbIconified( false )
94 {
95 }
96
97 // ============================================================================
98
ExternalName(const ExternalLink & rParentLink)99 ExternalName::ExternalName( const ExternalLink& rParentLink ) :
100 DefinedNameBase( rParentLink ),
101 mrParentLink( rParentLink ),
102 mnStorageId( 0 ),
103 mbDdeLinkCreated( false )
104 {
105 }
106
importDefinedName(const AttributeList & rAttribs)107 void ExternalName::importDefinedName( const AttributeList& rAttribs )
108 {
109 maModel.maName = rAttribs.getXString( XML_name, OUString() );
110 OSL_ENSURE( maModel.maName.getLength() > 0, "ExternalName::importDefinedName - empty name" );
111 // zero-based index into sheet list of externalBook
112 maModel.mnSheet = rAttribs.getInteger( XML_sheetId, -1 );
113 }
114
importDdeItem(const AttributeList & rAttribs)115 void ExternalName::importDdeItem( const AttributeList& rAttribs )
116 {
117 maModel.maName = rAttribs.getXString( XML_name, OUString() );
118 OSL_ENSURE( maModel.maName.getLength() > 0, "ExternalName::importDdeItem - empty name" );
119 maExtNameModel.mbOleObj = false;
120 maExtNameModel.mbStdDocName = rAttribs.getBool( XML_ole, false );
121 maExtNameModel.mbNotify = rAttribs.getBool( XML_advise, false );
122 maExtNameModel.mbPreferPic = rAttribs.getBool( XML_preferPic, false );
123 }
124
importValues(const AttributeList & rAttribs)125 void ExternalName::importValues( const AttributeList& rAttribs )
126 {
127 setResultSize( rAttribs.getInteger( XML_cols, 1 ), rAttribs.getInteger( XML_rows, 1 ) );
128 }
129
importOleItem(const AttributeList & rAttribs)130 void ExternalName::importOleItem( const AttributeList& rAttribs )
131 {
132 maModel.maName = rAttribs.getXString( XML_name, OUString() );
133 OSL_ENSURE( maModel.maName.getLength() > 0, "ExternalName::importOleItem - empty name" );
134 maExtNameModel.mbOleObj = true;
135 maExtNameModel.mbNotify = rAttribs.getBool( XML_advise, false );
136 maExtNameModel.mbPreferPic = rAttribs.getBool( XML_preferPic, false );
137 maExtNameModel.mbIconified = rAttribs.getBool( XML_icon, false );
138 }
139
importExternalName(SequenceInputStream & rStrm)140 void ExternalName::importExternalName( SequenceInputStream& rStrm )
141 {
142 rStrm >> maModel.maName;
143 OSL_ENSURE( maModel.maName.getLength() > 0, "ExternalName::importExternalName - empty name" );
144 }
145
importExternalNameFlags(SequenceInputStream & rStrm)146 void ExternalName::importExternalNameFlags( SequenceInputStream& rStrm )
147 {
148 sal_uInt16 nFlags;
149 sal_Int32 nSheetId;
150 rStrm >> nFlags >> nSheetId;
151 // index into sheet list of EXTSHEETNAMES (one-based in BIFF12)
152 maModel.mnSheet = nSheetId - 1;
153 // no flag for built-in names, as in OOXML...
154 maExtNameModel.mbNotify = getFlag( nFlags, BIFF12_EXTNAME_AUTOMATIC );
155 maExtNameModel.mbPreferPic = getFlag( nFlags, BIFF12_EXTNAME_PREFERPIC );
156 maExtNameModel.mbStdDocName = getFlag( nFlags, BIFF12_EXTNAME_STDDOCNAME );
157 maExtNameModel.mbOleObj = getFlag( nFlags, BIFF12_EXTNAME_OLEOBJECT );
158 maExtNameModel.mbIconified = getFlag( nFlags, BIFF12_EXTNAME_ICONIFIED );
159 OSL_ENSURE( (mrParentLink.getLinkType() == LINKTYPE_OLE) == maExtNameModel.mbOleObj,
160 "ExternalName::importExternalNameFlags - wrong OLE flag in external name" );
161 }
162
importDdeItemValues(SequenceInputStream & rStrm)163 void ExternalName::importDdeItemValues( SequenceInputStream& rStrm )
164 {
165 sal_Int32 nRows, nCols;
166 rStrm >> nRows >> nCols;
167 setResultSize( nCols, nRows );
168 }
169
importDdeItemBool(SequenceInputStream & rStrm)170 void ExternalName::importDdeItemBool( SequenceInputStream& rStrm )
171 {
172 appendResultValue< double >( (rStrm.readuInt8() == 0) ? 0.0 : 1.0 );
173 }
174
importDdeItemDouble(SequenceInputStream & rStrm)175 void ExternalName::importDdeItemDouble( SequenceInputStream& rStrm )
176 {
177 appendResultValue( rStrm.readDouble() );
178 }
179
importDdeItemError(SequenceInputStream & rStrm)180 void ExternalName::importDdeItemError( SequenceInputStream& rStrm )
181 {
182 appendResultValue( BiffHelper::calcDoubleFromError( rStrm.readuInt8() ) );
183 }
184
importDdeItemString(SequenceInputStream & rStrm)185 void ExternalName::importDdeItemString( SequenceInputStream& rStrm )
186 {
187 appendResultValue( BiffHelper::readString( rStrm ) );
188 }
189
importExternalName(BiffInputStream & rStrm)190 void ExternalName::importExternalName( BiffInputStream& rStrm )
191 {
192 sal_uInt16 nFlags = 0;
193 if( getBiff() >= BIFF3 )
194 {
195 rStrm >> nFlags;
196 maExtNameModel.mbBuiltIn = getFlag( nFlags, BIFF_EXTNAME_BUILTIN );
197 maExtNameModel.mbNotify = getFlag( nFlags, BIFF_EXTNAME_AUTOMATIC );
198 maExtNameModel.mbPreferPic = getFlag( nFlags, BIFF_EXTNAME_PREFERPIC );
199
200 // BIFF5-BIFF8: sheet index for sheet-local names, OLE settings
201 if( getBiff() >= BIFF5 )
202 {
203 maExtNameModel.mbStdDocName = getFlag( nFlags, BIFF_EXTNAME_STDDOCNAME );
204 maExtNameModel.mbOleObj = getFlag( nFlags, BIFF_EXTNAME_OLEOBJECT );
205 maExtNameModel.mbIconified = getFlag( nFlags, BIFF_EXTNAME_ICONIFIED );
206
207 if( maExtNameModel.mbOleObj )
208 {
209 rStrm >> mnStorageId;
210 }
211 else
212 {
213 /* Import the reference ID for names that are sheet-local in
214 the external document. This index will be resolved later to
215 the index of the external sheet cache which is able to
216 provide the name of the sheet related to this defined name.
217 - BIFF5: one-based index to EXTERNSHEET record containing
218 the document and sheet name
219 - BIFF8: one-based index into EXTERNALBOOK sheet name list
220 The value zero means this external name is a global name.
221 */
222 rStrm.skip( 2 );
223 maModel.mnSheet = rStrm.readuInt16();
224 }
225 }
226 }
227
228 maModel.maName = (getBiff() == BIFF8) ?
229 rStrm.readUniStringBody( rStrm.readuInt8() ) :
230 rStrm.readByteStringUC( false, getTextEncoding() );
231 OSL_ENSURE( maModel.maName.getLength() > 0, "ExternalName::importExternalName - empty name" );
232
233 // load cell references that are stored in hidden external names (seen in BIFF3-BIFF4)
234 bool bHiddenRef = (getBiff() <= BIFF4) && (maModel.maName.getLength() > 1) && (maModel.maName[ 0 ] == '\x01') && (rStrm.getRemaining() > 2);
235 switch( mrParentLink.getLinkType() )
236 {
237 case LINKTYPE_INTERNAL:
238 // cell references to other internal sheets are stored in hidden external names
239 if( bHiddenRef && (getBiff() == BIFF4) && isWorkbookFile() )
240 {
241 ApiTokenSequence aTokens = importBiffFormula( mrParentLink.getCalcSheetIndex(), rStrm );
242 extractReference( aTokens );
243 }
244 break;
245
246 case LINKTYPE_EXTERNAL:
247 // cell references to other documents are stored in hidden external names
248 if( bHiddenRef )
249 {
250 ApiTokenSequence aTokens = importBiffFormula( 0, rStrm );
251 extractExternalReference( aTokens );
252 }
253 break;
254
255 case LINKTYPE_DDE:
256 case LINKTYPE_OLE:
257 case LINKTYPE_MAYBE_DDE_OLE:
258 // DDE/OLE link results
259 if( rStrm.getRemaining() > 3 )
260 {
261 bool bBiff8 = getBiff() == BIFF8;
262 sal_Int32 nCols = rStrm.readuInt8();
263 sal_Int32 nRows = rStrm.readuInt16();
264 if( bBiff8 ) { ++nCols; ++nRows; } else if( nCols == 0 ) nCols = 256;
265 setResultSize( nCols, nRows );
266
267 bool bLoop = true;
268 while( bLoop && !rStrm.isEof() && (maCurrIt != maResults.end()) )
269 {
270 switch( rStrm.readuInt8() )
271 {
272 case BIFF_DATATYPE_EMPTY:
273 appendResultValue( OUString() );
274 rStrm.skip( 8 );
275 break;
276 case BIFF_DATATYPE_DOUBLE:
277 appendResultValue( rStrm.readDouble() );
278 break;
279 case BIFF_DATATYPE_STRING:
280 appendResultValue( bBiff8 ? rStrm.readUniString() : rStrm.readByteStringUC( false, getTextEncoding() ) );
281 break;
282 case BIFF_DATATYPE_BOOL:
283 appendResultValue< double >( (rStrm.readuInt8() == 0) ? 0.0 : 1.0 );
284 rStrm.skip( 7 );
285 break;
286 case BIFF_DATATYPE_ERROR:
287 appendResultValue( BiffHelper::calcDoubleFromError( rStrm.readuInt8() ) );
288 rStrm.skip( 7 );
289 break;
290 default:
291 bLoop = false;
292 }
293 }
294 OSL_ENSURE( bLoop && !rStrm.isEof() && (maCurrIt == maResults.end()),
295 "ExternalName::importExternalName - stream error in result set" );
296 }
297 break;
298
299 default:;
300 }
301 }
302
303 #if 0
304 sal_Int32 ExternalName::getSheetCacheIndex() const
305 {
306 OSL_ENSURE( mrParentLink.getLinkType() == LINKTYPE_DDE, "ExternalName::getSheetCacheIndex - unexpected link type" );
307 sal_Int32 nCacheIdx = -1;
308 switch( getFilterType() )
309 {
310 case FILTER_OOXML:
311 // OOXML/BIFF12: zero-based index into sheet list, -1 means global name
312 if( maModel.mnSheet >= 0 )
313 nCacheIdx = mrParentLink.getSheetIndex( maModel.mnSheet );
314 break;
315 case FILTER_BIFF:
316 switch( getBiff() )
317 {
318 case BIFF2:
319 case BIFF3:
320 case BIFF4:
321 break;
322 case BIFF5:
323 if( maModel.mnSheet > 0 )
324 if( const ExternalLink* pExtLink = getExternalLinks().getExternalLink( maModel.mnSheet ).get() )
325 if( pExtLink->getLinkType() == LINKTYPE_EXTERNAL )
326 nCacheIdx = pExtLink->getSheetIndex();
327 break;
328 case BIFF8:
329 if( maModel.mnSheet > 0 )
330 nCacheIdx = mrParentLink.getSheetIndex( maModel.mnSheet - 1 );
331 break;
332 case BIFF_UNKNOWN:
333 break;
334 }
335 break;
336 case FILTER_UNKNOWN:
337 break;
338 }
339 return nCacheIdx;
340 }
341 #endif
342
getDdeItemInfo(DDEItemInfo & orItemInfo) const343 bool ExternalName::getDdeItemInfo( DDEItemInfo& orItemInfo ) const
344 {
345 if( (mrParentLink.getLinkType() == LINKTYPE_DDE) && (maModel.maName.getLength() > 0) )
346 {
347 orItemInfo.Item = maModel.maName;
348 orItemInfo.Results = ContainerHelper::matrixToSequenceSequence( maResults );
349 return true;
350 }
351 return false;
352 }
353
getDdeLinkData(OUString & orDdeServer,OUString & orDdeTopic,OUString & orDdeItem)354 bool ExternalName::getDdeLinkData( OUString& orDdeServer, OUString& orDdeTopic, OUString& orDdeItem )
355 {
356 if( (mrParentLink.getLinkType() == LINKTYPE_DDE) && (maModel.maName.getLength() > 0) )
357 {
358 // try to create a DDE link and to set the imported link results
359 if( !mbDdeLinkCreated ) try
360 {
361 PropertySet aDocProps( getDocument() );
362 Reference< XDDELinks > xDdeLinks( aDocProps.getAnyProperty( PROP_DDELinks ), UNO_QUERY_THROW );
363 mxDdeLink = xDdeLinks->addDDELink( mrParentLink.getClassName(), mrParentLink.getTargetUrl(), maModel.maName, ::com::sun::star::sheet::DDELinkMode_DEFAULT );
364 mbDdeLinkCreated = true; // ignore if setting results fails
365 if( !maResults.empty() )
366 {
367 Reference< XDDELinkResults > xResults( mxDdeLink, UNO_QUERY_THROW );
368 xResults->setResults( ContainerHelper::matrixToSequenceSequence( maResults ) );
369 }
370 }
371 catch( Exception& )
372 {
373 OSL_ENSURE( false, "ExternalName::getDdeLinkData - cannot create DDE link" );
374 }
375 // get link data from created DDE link
376 if( mxDdeLink.is() )
377 {
378 orDdeServer = mxDdeLink->getApplication();
379 orDdeTopic = mxDdeLink->getTopic();
380 orDdeItem = mxDdeLink->getItem();
381 return true;
382 }
383 }
384 return false;
385 }
386
387 // private --------------------------------------------------------------------
388
389 namespace {
390
lclSetSheetCacheIndex(SingleReference & orApiRef,sal_Int32 nCacheIdx)391 void lclSetSheetCacheIndex( SingleReference& orApiRef, sal_Int32 nCacheIdx )
392 {
393 using namespace ::com::sun::star::sheet::ReferenceFlags;
394 setFlag( orApiRef.Flags, SHEET_RELATIVE, false );
395 setFlag( orApiRef.Flags, SHEET_3D, true );
396 orApiRef.Sheet = nCacheIdx;
397 }
398
399 } // namespace
400
extractExternalReference(const ApiTokenSequence & rTokens)401 void ExternalName::extractExternalReference( const ApiTokenSequence& rTokens )
402 {
403 OSL_ENSURE( (getFilterType() == FILTER_BIFF) && (getBiff() <= BIFF4), "ExternalName::setExternalReference - unexpected call" );
404 sal_Int32 nDocLinkIdx = mrParentLink.getDocumentLinkIndex();
405 sal_Int32 nCacheIdx = mrParentLink.getSheetCacheIndex();
406 if( (nDocLinkIdx >= 0) && (nCacheIdx >= 0) )
407 {
408 ExternalReference aExtApiRef;
409 aExtApiRef.Index = nDocLinkIdx;
410
411 Any aRefAny = getFormulaParser().extractReference( rTokens );
412 if( aRefAny.has< SingleReference >() )
413 {
414 SingleReference aApiRef;
415 aRefAny >>= aApiRef;
416 lclSetSheetCacheIndex( aApiRef, nCacheIdx );
417 aExtApiRef.Reference <<= aApiRef;
418 maRefAny <<= aExtApiRef;
419 }
420 else if( aRefAny.has< ComplexReference >() )
421 {
422 ComplexReference aApiRef;
423 aRefAny >>= aApiRef;
424 lclSetSheetCacheIndex( aApiRef.Reference1, nCacheIdx );
425 lclSetSheetCacheIndex( aApiRef.Reference2, nCacheIdx );
426 aExtApiRef.Reference <<= aApiRef;
427 maRefAny <<= aExtApiRef;
428 }
429 }
430 }
431
setResultSize(sal_Int32 nColumns,sal_Int32 nRows)432 void ExternalName::setResultSize( sal_Int32 nColumns, sal_Int32 nRows )
433 {
434 OSL_ENSURE( (mrParentLink.getLinkType() == LINKTYPE_DDE) || (mrParentLink.getLinkType() == LINKTYPE_OLE) ||
435 (mrParentLink.getLinkType() == LINKTYPE_MAYBE_DDE_OLE), "ExternalName::setResultSize - wrong link type" );
436 OSL_ENSURE( (nRows > 0) && (nColumns > 0), "ExternalName::setResultSize - invalid matrix size" );
437 const CellAddress& rMaxPos = getAddressConverter().getMaxApiAddress();
438 if( (0 < nRows) && (nRows <= rMaxPos.Row + 1) && (0 < nColumns) && (nColumns <= rMaxPos.Column + 1) )
439 maResults.resize( static_cast< size_t >( nColumns ), static_cast< size_t >( nRows ), Any( BiffHelper::calcDoubleFromError( BIFF_ERR_NA ) ) );
440 else
441 maResults.clear();
442 maCurrIt = maResults.begin();
443 }
444
445 // ============================================================================
446
setDeleted()447 void LinkSheetRange::setDeleted()
448 {
449 meType = LINKSHEETRANGE_INTERNAL;
450 mnDocLink = mnFirst = mnLast = -1;
451 }
452
setSameSheet()453 void LinkSheetRange::setSameSheet()
454 {
455 meType = LINKSHEETRANGE_SAMESHEET;
456 mnDocLink = -1;
457 mnFirst = mnLast = 0;
458 }
459
setRange(sal_Int32 nFirst,sal_Int32 nLast)460 void LinkSheetRange::setRange( sal_Int32 nFirst, sal_Int32 nLast )
461 {
462 meType = LINKSHEETRANGE_INTERNAL;
463 mnDocLink = -1;
464 mnFirst = ::std::min( nFirst, nLast );
465 mnLast = ::std::max( nFirst, nLast );
466 }
467
setExternalRange(sal_Int32 nDocLink,sal_Int32 nFirst,sal_Int32 nLast)468 void LinkSheetRange::setExternalRange( sal_Int32 nDocLink, sal_Int32 nFirst, sal_Int32 nLast )
469 {
470 if( nDocLink < 0 )
471 {
472 setDeleted();
473 }
474 else
475 {
476 meType = LINKSHEETRANGE_EXTERNAL;
477 mnDocLink = nDocLink;
478 mnFirst = ::std::min( nFirst, nLast );
479 mnLast = ::std::max( nFirst, nLast );
480 }
481 }
482
483 // ============================================================================
484
ExternalLink(const WorkbookHelper & rHelper)485 ExternalLink::ExternalLink( const WorkbookHelper& rHelper ) :
486 WorkbookHelper( rHelper ),
487 meLinkType( LINKTYPE_UNKNOWN ),
488 meFuncLibType( FUNCLIB_UNKNOWN )
489 {
490 }
491
importExternalReference(const AttributeList & rAttribs)492 void ExternalLink::importExternalReference( const AttributeList& rAttribs )
493 {
494 maRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
495 }
496
importExternalBook(const Relations & rRelations,const AttributeList & rAttribs)497 void ExternalLink::importExternalBook( const Relations& rRelations, const AttributeList& rAttribs )
498 {
499 parseExternalReference( rRelations, rAttribs.getString( R_TOKEN( id ), OUString() ) );
500 }
501
importSheetName(const AttributeList & rAttribs)502 void ExternalLink::importSheetName( const AttributeList& rAttribs )
503 {
504 insertExternalSheet( rAttribs.getXString( XML_val, OUString() ) );
505 }
506
importDefinedName(const AttributeList & rAttribs)507 void ExternalLink::importDefinedName( const AttributeList& rAttribs )
508 {
509 createExternalName()->importDefinedName( rAttribs );
510 }
511
importDdeLink(const AttributeList & rAttribs)512 void ExternalLink::importDdeLink( const AttributeList& rAttribs )
513 {
514 OUString aDdeService = rAttribs.getXString( XML_ddeService, OUString() );
515 OUString aDdeTopic = rAttribs.getXString( XML_ddeTopic, OUString() );
516 setDdeOleTargetUrl( aDdeService, aDdeTopic, LINKTYPE_DDE );
517 }
518
importDdeItem(const AttributeList & rAttribs)519 ExternalNameRef ExternalLink::importDdeItem( const AttributeList& rAttribs )
520 {
521 ExternalNameRef xExtName = createExternalName();
522 xExtName->importDdeItem( rAttribs );
523 return xExtName;
524 }
525
importOleLink(const Relations & rRelations,const AttributeList & rAttribs)526 void ExternalLink::importOleLink( const Relations& rRelations, const AttributeList& rAttribs )
527 {
528 OUString aProgId = rAttribs.getXString( XML_progId, OUString() );
529 OUString aTargetUrl = rRelations.getExternalTargetFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) );
530 setDdeOleTargetUrl( aProgId, aTargetUrl, LINKTYPE_OLE );
531 }
532
importOleItem(const AttributeList & rAttribs)533 ExternalNameRef ExternalLink::importOleItem( const AttributeList& rAttribs )
534 {
535 ExternalNameRef xExtName = createExternalName();
536 xExtName->importOleItem( rAttribs );
537 return xExtName;
538 }
539
importExternalRef(SequenceInputStream & rStrm)540 void ExternalLink::importExternalRef( SequenceInputStream& rStrm )
541 {
542 rStrm >> maRelId;
543 }
544
importExternalSelf(SequenceInputStream &)545 void ExternalLink::importExternalSelf( SequenceInputStream& )
546 {
547 meLinkType = LINKTYPE_SELF;
548 }
549
importExternalSame(SequenceInputStream &)550 void ExternalLink::importExternalSame( SequenceInputStream& )
551 {
552 meLinkType = LINKTYPE_SAME;
553 }
554
importExternalAddin(SequenceInputStream &)555 void ExternalLink::importExternalAddin( SequenceInputStream& )
556 {
557 meLinkType = LINKTYPE_UNKNOWN;
558 }
559
importExternalBook(const Relations & rRelations,SequenceInputStream & rStrm)560 void ExternalLink::importExternalBook( const Relations& rRelations, SequenceInputStream& rStrm )
561 {
562 switch( rStrm.readuInt16() )
563 {
564 case BIFF12_EXTERNALBOOK_BOOK:
565 parseExternalReference( rRelations, BiffHelper::readString( rStrm ) );
566 break;
567 case BIFF12_EXTERNALBOOK_DDE:
568 {
569 OUString aDdeService, aDdeTopic;
570 rStrm >> aDdeService >> aDdeTopic;
571 setDdeOleTargetUrl( aDdeService, aDdeTopic, LINKTYPE_DDE );
572 }
573 break;
574 case BIFF12_EXTERNALBOOK_OLE:
575 {
576 OUString aTargetUrl = rRelations.getExternalTargetFromRelId( BiffHelper::readString( rStrm ) );
577 OUString aProgId = BiffHelper::readString( rStrm );
578 setDdeOleTargetUrl( aProgId, aTargetUrl, LINKTYPE_OLE );
579 }
580 break;
581 default:
582 OSL_ENSURE( false, "ExternalLink::importExternalBook - unknown link type" );
583 }
584 }
585
importExtSheetNames(SequenceInputStream & rStrm)586 void ExternalLink::importExtSheetNames( SequenceInputStream& rStrm )
587 {
588 // load external sheet names and create the sheet caches in the Calc document
589 OSL_ENSURE( (meLinkType == LINKTYPE_EXTERNAL) || (meLinkType == LINKTYPE_LIBRARY),
590 "ExternalLink::importExtSheetNames - invalid link type" );
591 if( meLinkType == LINKTYPE_EXTERNAL ) // ignore sheets of external libraries
592 for( sal_Int32 nSheet = 0, nCount = rStrm.readInt32(); !rStrm.isEof() && (nSheet < nCount); ++nSheet )
593 insertExternalSheet( BiffHelper::readString( rStrm ) );
594 }
595
importExternalName(SequenceInputStream & rStrm)596 ExternalNameRef ExternalLink::importExternalName( SequenceInputStream& rStrm )
597 {
598 ExternalNameRef xExtName = createExternalName();
599 xExtName->importExternalName( rStrm );
600 return xExtName;
601 }
602
importExternSheet(BiffInputStream & rStrm)603 void ExternalLink::importExternSheet( BiffInputStream& rStrm )
604 {
605 OStringBuffer aTargetBuffer( rStrm.readByteString( false, true ) );
606 // references to own sheets have wrong string length field (off by 1)
607 if( (aTargetBuffer.getLength() > 0) && (aTargetBuffer[ 0 ] == 3) )
608 aTargetBuffer.append( static_cast< sal_Char >( rStrm.readuInt8() ) );
609 // parse the encoded URL
610 OUString aBiffTarget = OStringToOUString( aTargetBuffer.makeStringAndClear(), getTextEncoding() );
611 OUString aSheetName = parseBiffTargetUrl( aBiffTarget );
612 switch( meLinkType )
613 {
614 case LINKTYPE_INTERNAL:
615 maCalcSheets.push_back( getWorksheets().getCalcSheetIndex( aSheetName ) );
616 break;
617 case LINKTYPE_EXTERNAL:
618 insertExternalSheet( (aSheetName.getLength() > 0) ? aSheetName : WorksheetBuffer::getBaseFileName( maTargetUrl ) );
619 break;
620 default:;
621 }
622 }
623
importExternalBook(BiffInputStream & rStrm)624 void ExternalLink::importExternalBook( BiffInputStream& rStrm )
625 {
626 OUString aTarget;
627 sal_uInt16 nSheetCount;
628 rStrm >> nSheetCount;
629 if( rStrm.getRemaining() == 2 )
630 {
631 if( rStrm.readuInt8() == 1 )
632 {
633 sal_Char cChar = static_cast< sal_Char >( rStrm.readuInt8() );
634 if( cChar != 0 )
635 aTarget = OStringToOUString( OString( cChar ), getTextEncoding() );
636 }
637 }
638 else if( rStrm.getRemaining() >= 3 )
639 {
640 // NUL characters may occur
641 aTarget = rStrm.readUniString( true );
642 }
643
644 // parse the encoded URL
645 OUString aDummySheetName = parseBiffTargetUrl( aTarget );
646 OSL_ENSURE( aDummySheetName.getLength() == 0, "ExternalLink::importExternalBook - sheet name in encoded URL" );
647 (void)aDummySheetName; // prevent compiler warning
648
649 // load external sheet names and create the sheet caches in the Calc document
650 if( meLinkType == LINKTYPE_EXTERNAL )
651 for( sal_uInt16 nSheet = 0; !rStrm.isEof() && (nSheet < nSheetCount); ++nSheet )
652 insertExternalSheet( rStrm.readUniString() );
653 }
654
importExternalName(BiffInputStream & rStrm)655 void ExternalLink::importExternalName( BiffInputStream& rStrm )
656 {
657 ExternalNameRef xExtName = createExternalName();
658 xExtName->importExternalName( rStrm );
659 switch( meLinkType )
660 {
661 case LINKTYPE_DDE:
662 OSL_ENSURE( !xExtName->isOleObject(), "ExternalLink::importExternalName - OLE object in DDE link" );
663 break;
664 case LINKTYPE_OLE:
665 OSL_ENSURE( xExtName->isOleObject(), "ExternalLink::importExternalName - anything but OLE object in OLE link" );
666 break;
667 case LINKTYPE_MAYBE_DDE_OLE:
668 meLinkType = xExtName->isOleObject() ? LINKTYPE_OLE : LINKTYPE_DDE;
669 break;
670 default:
671 OSL_ENSURE( !xExtName->isOleObject(), "ExternalLink::importExternalName - OLE object in external name" );
672 }
673 }
674
getLinkInfo() const675 ExternalLinkInfo ExternalLink::getLinkInfo() const
676 {
677 ExternalLinkInfo aLinkInfo;
678 switch( meLinkType )
679 {
680 case LINKTYPE_SELF:
681 case LINKTYPE_SAME:
682 case LINKTYPE_INTERNAL:
683 aLinkInfo.Type = ::com::sun::star::sheet::ExternalLinkType::SELF;
684 break;
685 case LINKTYPE_EXTERNAL:
686 aLinkInfo.Type = ::com::sun::star::sheet::ExternalLinkType::DOCUMENT;
687 aLinkInfo.Data <<= maTargetUrl;
688 break;
689 case LINKTYPE_LIBRARY:
690 // parser will return library function names in OPCODE_BAD string tokens
691 aLinkInfo.Type = ::com::sun::star::sheet::ExternalLinkType::SPECIAL;
692 break;
693 case LINKTYPE_DDE:
694 {
695 aLinkInfo.Type = ::com::sun::star::sheet::ExternalLinkType::DDE;
696 DDELinkInfo aDdeLinkInfo;
697 aDdeLinkInfo.Service = maClassName;
698 aDdeLinkInfo.Topic = maTargetUrl;
699 ::std::vector< DDEItemInfo > aItemInfos;
700 DDEItemInfo aItemInfo;
701 for( ExternalNameVector::const_iterator aIt = maExtNames.begin(), aEnd = maExtNames.end(); aIt != aEnd; ++aIt )
702 if( (*aIt)->getDdeItemInfo( aItemInfo ) )
703 aItemInfos.push_back( aItemInfo );
704 aDdeLinkInfo.Items = ContainerHelper::vectorToSequence( aItemInfos );
705 aLinkInfo.Data <<= aDdeLinkInfo;
706 }
707 break;
708 default:
709 aLinkInfo.Type = ::com::sun::star::sheet::ExternalLinkType::UNKNOWN;
710 }
711 return aLinkInfo;
712 }
713
getFuncLibraryType() const714 FunctionLibraryType ExternalLink::getFuncLibraryType() const
715 {
716 return (meLinkType == LINKTYPE_LIBRARY) ? meFuncLibType : FUNCLIB_UNKNOWN;
717 }
718
getCalcSheetIndex(sal_Int32 nTabId) const719 sal_Int16 ExternalLink::getCalcSheetIndex( sal_Int32 nTabId ) const
720 {
721 OSL_ENSURE( meLinkType == LINKTYPE_INTERNAL, "ExternalLink::getCalcSheetIndex - invalid link type" );
722 OSL_ENSURE( (nTabId == 0) || (getFilterType() == FILTER_OOXML) || (getBiff() == BIFF8),
723 "ExternalLink::getCalcSheetIndex - invalid sheet index" );
724 return ContainerHelper::getVectorElement( maCalcSheets, nTabId, -1 );
725 }
726
getDocumentLinkIndex() const727 sal_Int32 ExternalLink::getDocumentLinkIndex() const
728 {
729 OSL_ENSURE( meLinkType == LINKTYPE_EXTERNAL, "ExternalLink::getDocumentLinkIndex - invalid link type" );
730 return mxDocLink.is() ? mxDocLink->getTokenIndex() : -1;
731 }
732
getSheetCacheIndex(sal_Int32 nTabId) const733 sal_Int32 ExternalLink::getSheetCacheIndex( sal_Int32 nTabId ) const
734 {
735 OSL_ENSURE( meLinkType == LINKTYPE_EXTERNAL, "ExternalLink::getSheetCacheIndex - invalid link type" );
736 OSL_ENSURE( (nTabId == 0) || (getFilterType() == FILTER_OOXML) || (getBiff() == BIFF8),
737 "ExternalLink::getSheetCacheIndex - invalid sheet index" );
738 return ContainerHelper::getVectorElement( maSheetCaches, nTabId, -1 );
739 }
740
getSheetCache(sal_Int32 nTabId) const741 Reference< XExternalSheetCache > ExternalLink::getSheetCache( sal_Int32 nTabId ) const
742 {
743 sal_Int32 nCacheIdx = getSheetCacheIndex( nTabId );
744 if( mxDocLink.is() && (nCacheIdx >= 0) ) try
745 {
746 // existing mxDocLink implies that this is an external link
747 Reference< XExternalSheetCache > xSheetCache( mxDocLink->getByIndex( nCacheIdx ), UNO_QUERY_THROW );
748 return xSheetCache;
749 }
750 catch( Exception& )
751 {
752 }
753 return 0;
754 }
755
getSheetRange(LinkSheetRange & orSheetRange,sal_Int32 nTabId1,sal_Int32 nTabId2) const756 void ExternalLink::getSheetRange( LinkSheetRange& orSheetRange, sal_Int32 nTabId1, sal_Int32 nTabId2 ) const
757 {
758 switch( meLinkType )
759 {
760 case LINKTYPE_SAME:
761 orSheetRange.setSameSheet();
762 break;
763
764 case LINKTYPE_SELF:
765 case LINKTYPE_INTERNAL:
766 orSheetRange.setRange( nTabId1, nTabId2 );
767 break;
768
769 case LINKTYPE_EXTERNAL:
770 {
771 sal_Int32 nDocLinkIdx = getDocumentLinkIndex();
772 switch( getFilterType() )
773 {
774 case FILTER_OOXML:
775 // BIFF12: passed indexes point into sheet list of EXTSHEETLIST
776 orSheetRange.setExternalRange( nDocLinkIdx, getSheetCacheIndex( nTabId1 ), getSheetCacheIndex( nTabId2 ) );
777 break;
778 case FILTER_BIFF:
779 switch( getBiff() )
780 {
781 case BIFF2:
782 case BIFF3:
783 case BIFF4:
784 orSheetRange.setExternalRange( nDocLinkIdx, getSheetCacheIndex( nTabId1 ), getSheetCacheIndex( nTabId2 ) );
785 break;
786 case BIFF5:
787 // BIFF5: first sheet from this external link, last sheet is passed in nTabId2
788 if( const ExternalLink* pExtLink2 = getExternalLinks().getExternalLink( nTabId2 ).get() )
789 if( (pExtLink2->getLinkType() == LINKTYPE_EXTERNAL) && (maTargetUrl == pExtLink2->getTargetUrl()) )
790 orSheetRange.setExternalRange( nDocLinkIdx, getSheetCacheIndex(), pExtLink2->getSheetCacheIndex() );
791 break;
792 case BIFF8:
793 // BIFF8: passed indexes point into sheet list of EXTERNALBOOK
794 orSheetRange.setExternalRange( nDocLinkIdx, getSheetCacheIndex( nTabId1 ), getSheetCacheIndex( nTabId2 ) );
795 break;
796 case BIFF_UNKNOWN: break;
797 }
798 break;
799 case FILTER_UNKNOWN: break;
800 }
801 }
802 break;
803
804 default:
805 // unsupported/unexpected link type: #REF! error
806 orSheetRange.setDeleted();
807 }
808 }
809
getNameByIndex(sal_Int32 nIndex) const810 ExternalNameRef ExternalLink::getNameByIndex( sal_Int32 nIndex ) const
811 {
812 return maExtNames.get( nIndex );
813 }
814
815 // private --------------------------------------------------------------------
816
817 #define OOX_TARGETTYPE_EXTLINK CREATE_OFFICEDOC_RELATION_TYPE( "externalLinkPath" )
818 #define OOX_TARGETTYPE_LIBRARY CREATE_MSOFFICE_RELATION_TYPE( "xlExternalLinkPath/xlLibrary" )
819
setExternalTargetUrl(const OUString & rTargetUrl,const OUString & rTargetType)820 void ExternalLink::setExternalTargetUrl( const OUString& rTargetUrl, const OUString& rTargetType )
821 {
822 meLinkType = LINKTYPE_UNKNOWN;
823 if( rTargetType == OOX_TARGETTYPE_EXTLINK )
824 {
825 maTargetUrl = getBaseFilter().getAbsoluteUrl( rTargetUrl );
826 if( maTargetUrl.getLength() > 0 )
827 meLinkType = LINKTYPE_EXTERNAL;
828 }
829 else if( rTargetType == OOX_TARGETTYPE_LIBRARY )
830 {
831 meLinkType = LINKTYPE_LIBRARY;
832 meFuncLibType = getFormulaParser().getFuncLibTypeFromLibraryName( rTargetUrl );
833 }
834 OSL_ENSURE( meLinkType != LINKTYPE_UNKNOWN, "ExternalLink::setExternalTargetUrl - empty target URL or unknown target type" );
835
836 // create the external document link API object that will contain the sheet caches
837 if( meLinkType == LINKTYPE_EXTERNAL ) try
838 {
839 PropertySet aDocProps( getDocument() );
840 Reference< XExternalDocLinks > xDocLinks( aDocProps.getAnyProperty( PROP_ExternalDocLinks ), UNO_QUERY_THROW );
841 mxDocLink = xDocLinks->addDocLink( maTargetUrl );
842 }
843 catch( Exception& )
844 {
845 }
846 }
847
setDdeOleTargetUrl(const OUString & rClassName,const OUString & rTargetUrl,ExternalLinkType eLinkType)848 void ExternalLink::setDdeOleTargetUrl( const OUString& rClassName, const OUString& rTargetUrl, ExternalLinkType eLinkType )
849 {
850 maClassName = rClassName;
851 maTargetUrl = rTargetUrl;
852 meLinkType = ((maClassName.getLength() > 0) && (maTargetUrl.getLength() > 0)) ? eLinkType : LINKTYPE_UNKNOWN;
853 OSL_ENSURE( meLinkType == eLinkType, "ExternalLink::setDdeOleTargetUrl - missing classname or target" );
854 }
855
parseExternalReference(const Relations & rRelations,const OUString & rRelId)856 void ExternalLink::parseExternalReference( const Relations& rRelations, const OUString& rRelId )
857 {
858 if( const Relation* pRelation = rRelations.getRelationFromRelId( rRelId ) )
859 setExternalTargetUrl( pRelation->maTarget, pRelation->maType );
860 }
861
parseBiffTargetUrl(const OUString & rBiffTargetUrl)862 OUString ExternalLink::parseBiffTargetUrl( const OUString& rBiffTargetUrl )
863 {
864 meLinkType = LINKTYPE_UNKNOWN;
865
866 OUString aClassName, aTargetUrl, aSheetName;
867 switch( getAddressConverter().parseBiffTargetUrl( aClassName, aTargetUrl, aSheetName, rBiffTargetUrl ) )
868 {
869 case BIFF_TARGETTYPE_URL:
870 if( aTargetUrl.getLength() == 0 )
871 {
872 meLinkType = (aSheetName.getLength() > 0) ? LINKTYPE_INTERNAL : LINKTYPE_SELF;
873 }
874 else if( (aTargetUrl.getLength() == 1) && (aTargetUrl[ 0 ] == ':') )
875 {
876 if( getBiff() >= BIFF4 )
877 meLinkType = LINKTYPE_ANALYSIS;
878 }
879 else if( (aTargetUrl.getLength() > 1) || (aTargetUrl[ 0 ] != ' ') )
880 {
881 setExternalTargetUrl( aTargetUrl, OOX_TARGETTYPE_EXTLINK );
882 }
883 break;
884
885 case BIFF_TARGETTYPE_SAMESHEET:
886 OSL_ENSURE( (aTargetUrl.getLength() == 0) && (aSheetName.getLength() == 0), "ExternalLink::parseBiffTargetUrl - unexpected target or sheet name" );
887 meLinkType = LINKTYPE_SAME;
888 break;
889
890 case BIFF_TARGETTYPE_LIBRARY:
891 OSL_ENSURE( aSheetName.getLength() == 0, "ExternalLink::parseBiffTargetUrl - unexpected sheet name" );
892 setExternalTargetUrl( aTargetUrl, OOX_TARGETTYPE_LIBRARY );
893 break;
894
895 case BIFF_TARGETTYPE_DDE_OLE:
896 setDdeOleTargetUrl( aClassName, aTargetUrl, LINKTYPE_MAYBE_DDE_OLE );
897 break;
898
899 case BIFF_TARGETTYPE_UNKNOWN:
900 break;
901 }
902 return aSheetName;
903 }
904
insertExternalSheet(const OUString & rSheetName)905 void ExternalLink::insertExternalSheet( const OUString& rSheetName )
906 {
907 OSL_ENSURE( rSheetName.getLength() > 0, "ExternalLink::insertExternalSheet - empty sheet name" );
908 if( mxDocLink.is() )
909 {
910 Reference< XExternalSheetCache > xSheetCache = mxDocLink->addSheetCache( rSheetName, false );
911 sal_Int32 nCacheIdx = xSheetCache.is() ? xSheetCache->getTokenIndex() : -1;
912 maSheetCaches.push_back( nCacheIdx );
913 }
914 }
915
createExternalName()916 ExternalNameRef ExternalLink::createExternalName()
917 {
918 ExternalNameRef xExtName( new ExternalName( *this ) );
919 maExtNames.push_back( xExtName );
920 return xExtName;
921 }
922
923 // ============================================================================
924
RefSheetsModel()925 RefSheetsModel::RefSheetsModel() :
926 mnExtRefId( -1 ),
927 mnTabId1( -1 ),
928 mnTabId2( -1 )
929 {
930 }
931
readBiff12Data(SequenceInputStream & rStrm)932 void RefSheetsModel::readBiff12Data( SequenceInputStream& rStrm )
933 {
934 rStrm >> mnExtRefId >> mnTabId1 >> mnTabId2;
935 }
936
readBiff8Data(BiffInputStream & rStrm)937 void RefSheetsModel::readBiff8Data( BiffInputStream& rStrm )
938 {
939 mnExtRefId = rStrm.readuInt16();
940 mnTabId1 = rStrm.readInt16();
941 mnTabId2 = rStrm.readInt16();
942 }
943
944 // ----------------------------------------------------------------------------
945
ExternalLinkBuffer(const WorkbookHelper & rHelper)946 ExternalLinkBuffer::ExternalLinkBuffer( const WorkbookHelper& rHelper ) :
947 WorkbookHelper( rHelper ),
948 mxSelfRef( new ExternalLink( rHelper ) ),
949 mbUseRefSheets( false )
950 {
951 mxSelfRef->setSelfLinkType();
952 }
953
importExternalReference(const AttributeList & rAttribs)954 ExternalLinkRef ExternalLinkBuffer::importExternalReference( const AttributeList& rAttribs )
955 {
956 ExternalLinkRef xExtLink = createExternalLink();
957 xExtLink->importExternalReference( rAttribs );
958 maExtLinks.push_back( xExtLink );
959 return xExtLink;
960 }
961
importExternalRef(SequenceInputStream & rStrm)962 ExternalLinkRef ExternalLinkBuffer::importExternalRef( SequenceInputStream& rStrm )
963 {
964 mbUseRefSheets = true;
965 ExternalLinkRef xExtLink = createExternalLink();
966 xExtLink->importExternalRef( rStrm );
967 maExtLinks.push_back( xExtLink );
968 return xExtLink;
969 }
970
importExternalSelf(SequenceInputStream & rStrm)971 void ExternalLinkBuffer::importExternalSelf( SequenceInputStream& rStrm )
972 {
973 mbUseRefSheets = true;
974 createExternalLink()->importExternalSelf( rStrm );
975 }
976
importExternalSame(SequenceInputStream & rStrm)977 void ExternalLinkBuffer::importExternalSame( SequenceInputStream& rStrm )
978 {
979 mbUseRefSheets = true;
980 createExternalLink()->importExternalSame( rStrm );
981 }
982
importExternalAddin(SequenceInputStream & rStrm)983 void ExternalLinkBuffer::importExternalAddin( SequenceInputStream& rStrm )
984 {
985 mbUseRefSheets = true;
986 createExternalLink()->importExternalAddin( rStrm );
987 }
988
importExternalSheets(SequenceInputStream & rStrm)989 void ExternalLinkBuffer::importExternalSheets( SequenceInputStream& rStrm )
990 {
991 OSL_ENSURE( mbUseRefSheets, "ExternalLinkBuffer::importExternalSheets - missing EXTERNALREFS records" );
992 mbUseRefSheets = true;
993 OSL_ENSURE( maRefSheets.empty(), "ExternalLinkBuffer::importExternalSheets - multiple EXTERNALSHEETS records" );
994 maRefSheets.clear();
995 sal_Int32 nRefCount;
996 rStrm >> nRefCount;
997 size_t nMaxCount = getLimitedValue< size_t, sal_Int64 >( nRefCount, 0, rStrm.getRemaining() / 12 );
998 maRefSheets.reserve( nMaxCount );
999 for( size_t nRefId = 0; !rStrm.isEof() && (nRefId < nMaxCount); ++nRefId )
1000 {
1001 RefSheetsModel aRefSheets;
1002 aRefSheets.readBiff12Data( rStrm );
1003 maRefSheets.push_back( aRefSheets );
1004 }
1005 }
1006
importExternSheet(BiffInputStream & rStrm)1007 ExternalLinkRef ExternalLinkBuffer::importExternSheet( BiffInputStream& rStrm )
1008 {
1009 OSL_ENSURE( getBiff() <= BIFF5, "ExternalLinkBuffer::importExternSheet - wrong BIFF version" );
1010 ExternalLinkRef xExtLink = createExternalLink();
1011 xExtLink->importExternSheet( rStrm );
1012 return xExtLink;
1013 }
1014
importExternalBook(BiffInputStream & rStrm)1015 ExternalLinkRef ExternalLinkBuffer::importExternalBook( BiffInputStream& rStrm )
1016 {
1017 ExternalLinkRef xExtLink = createExternalLink();
1018 xExtLink->importExternalBook( rStrm );
1019 return xExtLink;
1020 }
1021
importExternalName(BiffInputStream & rStrm)1022 void ExternalLinkBuffer::importExternalName( BiffInputStream& rStrm )
1023 {
1024 if( !maLinks.empty() )
1025 maLinks.back()->importExternalName( rStrm );
1026 }
1027
importExternSheet8(BiffInputStream & rStrm)1028 void ExternalLinkBuffer::importExternSheet8( BiffInputStream& rStrm )
1029 {
1030 OSL_ENSURE( getBiff() == BIFF8, "ExternalLinkBuffer::importExternSheet8 - wrong BIFF version" );
1031
1032 sal_uInt16 nRefCount;
1033 rStrm >> nRefCount;
1034 OSL_ENSURE( static_cast< sal_Int64 >( nRefCount * 6 ) == rStrm.getRemaining(), "ExternalLinkBuffer::importExternSheet8 - invalid count" );
1035 nRefCount = static_cast< sal_uInt16 >( ::std::min< sal_Int64 >( nRefCount, rStrm.getRemaining() / 6 ) );
1036
1037 /* #i104057# A weird external XLS generator writes multiple EXTERNSHEET
1038 records instead of only one as expected. Surprisingly, Excel seems to
1039 insert the entries of the second record before the entries of the first
1040 record. */
1041 maRefSheets.insert( maRefSheets.begin(), nRefCount, RefSheetsModel() );
1042 for( RefSheetsModelVec::iterator aIt = maRefSheets.begin(), aEnd = aIt + nRefCount; !rStrm.isEof() && (aIt != aEnd); ++aIt )
1043 aIt->readBiff8Data( rStrm );
1044 }
1045
getLinkInfos() const1046 Sequence< ExternalLinkInfo > ExternalLinkBuffer::getLinkInfos() const
1047 {
1048 ::std::vector< ExternalLinkInfo > aLinkInfos;
1049 // XML formula parser also used in BIFF12 documents, e.g. replacement formulas in unsupported conditional formattings
1050 OSL_ENSURE( getFilterType() == FILTER_OOXML, "ExternalLinkBuffer::getLinkInfos - unexpected file format" );
1051 // add entry for implicit index 0 (self reference to this document)
1052 aLinkInfos.push_back( mxSelfRef->getLinkInfo() );
1053 for( ExternalLinkVec::const_iterator aIt = maExtLinks.begin(), aEnd = maExtLinks.end(); aIt != aEnd; ++aIt )
1054 aLinkInfos.push_back( (*aIt)->getLinkInfo() );
1055 return ContainerHelper::vectorToSequence( aLinkInfos );
1056 }
1057
getExternalLink(sal_Int32 nRefId,bool bUseRefSheets) const1058 ExternalLinkRef ExternalLinkBuffer::getExternalLink( sal_Int32 nRefId, bool bUseRefSheets ) const
1059 {
1060 ExternalLinkRef xExtLink;
1061 switch( getFilterType() )
1062 {
1063 case FILTER_OOXML:
1064 // OOXML: 0 = this document, otherwise one-based index into link list
1065 if( !bUseRefSheets || !mbUseRefSheets )
1066 xExtLink = (nRefId == 0) ? mxSelfRef : maLinks.get( nRefId - 1 );
1067 // BIFF12: zero-based index into ref-sheets list
1068 else if( const RefSheetsModel* pRefSheets = getRefSheets( nRefId ) )
1069 xExtLink = maLinks.get( pRefSheets->mnExtRefId );
1070 break;
1071 case FILTER_BIFF:
1072 switch( getBiff() )
1073 {
1074 case BIFF2:
1075 case BIFF3:
1076 case BIFF4:
1077 // one-based index to EXTERNSHEET records
1078 xExtLink = maLinks.get( nRefId - 1 );
1079 break;
1080 case BIFF5:
1081 if( nRefId < 0 )
1082 {
1083 // internal links in formula tokens have negative index
1084 xExtLink = maLinks.get( -nRefId - 1 );
1085 if( xExtLink.get() && !xExtLink->isInternalLink() )
1086 xExtLink.reset();
1087 }
1088 else
1089 {
1090 // one-based index to EXTERNSHEET records
1091 xExtLink = maLinks.get( nRefId - 1 );
1092 }
1093 break;
1094 case BIFF8:
1095 // zero-based index into REF list in EXTERNSHEET record
1096 if( const RefSheetsModel* pRefSheets = getRefSheets( nRefId ) )
1097 xExtLink = maLinks.get( pRefSheets->mnExtRefId );
1098 break;
1099 case BIFF_UNKNOWN: break;
1100 }
1101 break;
1102 case FILTER_UNKNOWN: break;
1103 }
1104 return xExtLink;
1105 }
1106
getSheetRange(sal_Int32 nRefId,sal_Int16 nTabId1,sal_Int16 nTabId2) const1107 LinkSheetRange ExternalLinkBuffer::getSheetRange( sal_Int32 nRefId, sal_Int16 nTabId1, sal_Int16 nTabId2 ) const
1108 {
1109 OSL_ENSURE( getBiff() <= BIFF5, "ExternalLinkBuffer::getSheetRange - wrong BIFF version" );
1110 LinkSheetRange aSheetRange;
1111 if( const ExternalLink* pExtLink = getExternalLink( nRefId ).get() )
1112 pExtLink->getSheetRange( aSheetRange, nTabId1, nTabId2 );
1113 return aSheetRange;
1114 }
1115
getSheetRange(sal_Int32 nRefId) const1116 LinkSheetRange ExternalLinkBuffer::getSheetRange( sal_Int32 nRefId ) const
1117 {
1118 OSL_ENSURE( ((getFilterType() == FILTER_OOXML) && mbUseRefSheets) || (getBiff() == BIFF8), "ExternalLinkBuffer::getSheetRange - wrong BIFF version" );
1119 LinkSheetRange aSheetRange;
1120 if( const ExternalLink* pExtLink = getExternalLink( nRefId ).get() )
1121 if( const RefSheetsModel* pRefSheets = getRefSheets( nRefId ) )
1122 pExtLink->getSheetRange( aSheetRange, pRefSheets->mnTabId1, pRefSheets->mnTabId2 );
1123 return aSheetRange;
1124 }
1125
1126 // private --------------------------------------------------------------------
1127
createExternalLink()1128 ExternalLinkRef ExternalLinkBuffer::createExternalLink()
1129 {
1130 ExternalLinkRef xExtLink( new ExternalLink( *this ) );
1131 maLinks.push_back( xExtLink );
1132 return xExtLink;
1133 }
1134
getRefSheets(sal_Int32 nRefId) const1135 const RefSheetsModel* ExternalLinkBuffer::getRefSheets( sal_Int32 nRefId ) const
1136 {
1137 return ((0 <= nRefId) && (static_cast< size_t >( nRefId ) < maRefSheets.size())) ?
1138 &maRefSheets[ static_cast< size_t >( nRefId ) ] : 0;
1139 }
1140
1141 // ============================================================================
1142
1143 } // namespace xls
1144 } // namespace oox
1145