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