Update ooo320-m1
[ooovba.git] / oox / source / xls / externallinkbuffer.cxx
blobc756252161425c8a2d46e9cdb55290647e09f736
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: externallinkbuffer.cxx,v $
10 * $Revision: 1.5.4.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "oox/xls/externallinkbuffer.hxx"
32 #include <rtl/strbuf.hxx>
33 #include <com/sun/star/sheet/ComplexReference.hpp>
34 #include <com/sun/star/sheet/DDELinkInfo.hpp>
35 #include <com/sun/star/sheet/ExternalLinkType.hpp>
36 #include <com/sun/star/sheet/ExternalReference.hpp>
37 #include <com/sun/star/sheet/ReferenceFlags.hpp>
38 #include <com/sun/star/sheet/SingleReference.hpp>
39 #include <com/sun/star/sheet/XDDELinks.hpp>
40 #include <com/sun/star/sheet/XDDELink.hpp>
41 #include <com/sun/star/sheet/XDDELinkResults.hpp>
42 #include <com/sun/star/sheet/XExternalDocLink.hpp>
43 #include <com/sun/star/sheet/XExternalDocLinks.hpp>
44 #include "oox/helper/attributelist.hxx"
45 #include "oox/core/filterbase.hxx"
46 #include "oox/xls/addressconverter.hxx"
47 #include "oox/xls/biffinputstream.hxx"
48 #include "oox/xls/excelhandlers.hxx"
49 #include "oox/xls/formulaparser.hxx"
50 #include "oox/xls/worksheetbuffer.hxx"
52 using ::rtl::OString;
53 using ::rtl::OStringBuffer;
54 using ::rtl::OStringToOUString;
55 using ::rtl::OUString;
56 using ::com::sun::star::uno::Any;
57 using ::com::sun::star::uno::Reference;
58 using ::com::sun::star::uno::Sequence;
59 using ::com::sun::star::uno::Exception;
60 using ::com::sun::star::uno::UNO_QUERY_THROW;
61 using ::com::sun::star::table::CellAddress;
62 using ::com::sun::star::sheet::ComplexReference;
63 using ::com::sun::star::sheet::DDEItemInfo;
64 using ::com::sun::star::sheet::DDELinkInfo;
65 using ::com::sun::star::sheet::ExternalLinkInfo;
66 using ::com::sun::star::sheet::ExternalReference;
67 using ::com::sun::star::sheet::SingleReference;
68 using ::com::sun::star::sheet::XDDELinks;
69 using ::com::sun::star::sheet::XDDELinkResults;
70 using ::com::sun::star::sheet::XExternalDocLinks;
71 using ::com::sun::star::sheet::XExternalSheetCache;
72 using ::oox::core::Relation;
73 using ::oox::core::Relations;
75 namespace oox {
76 namespace xls {
78 // ============================================================================
80 namespace {
82 const sal_uInt16 OOBIN_EXTERNALBOOK_BOOK = 0;
83 const sal_uInt16 OOBIN_EXTERNALBOOK_DDE = 1;
84 const sal_uInt16 OOBIN_EXTERNALBOOK_OLE = 2;
86 const sal_uInt16 OOBIN_EXTNAME_AUTOMATIC = 0x0002;
87 const sal_uInt16 OOBIN_EXTNAME_PREFERPIC = 0x0004;
88 const sal_uInt16 OOBIN_EXTNAME_STDDOCNAME = 0x0008;
89 const sal_uInt16 OOBIN_EXTNAME_OLEOBJECT = 0x0010;
90 const sal_uInt16 OOBIN_EXTNAME_ICONIFIED = 0x0020;
92 const sal_uInt16 BIFF_EXTNAME_BUILTIN = 0x0001;
93 const sal_uInt16 BIFF_EXTNAME_AUTOMATIC = 0x0002;
94 const sal_uInt16 BIFF_EXTNAME_PREFERPIC = 0x0004;
95 const sal_uInt16 BIFF_EXTNAME_STDDOCNAME = 0x0008;
96 const sal_uInt16 BIFF_EXTNAME_OLEOBJECT = 0x0010;
97 const sal_uInt16 BIFF_EXTNAME_ICONIFIED = 0x8000;
99 } // namespace
101 // ============================================================================
103 ExternalNameModel::ExternalNameModel() :
104 mbBuiltIn( false ),
105 mbNotify( false ),
106 mbPreferPic( false ),
107 mbStdDocName( false ),
108 mbOleObj( false ),
109 mbIconified( false )
113 // ============================================================================
115 ExternalName::ExternalName( const ExternalLink& rParentLink ) :
116 DefinedNameBase( rParentLink ),
117 mrParentLink( rParentLink ),
118 mnStorageId( 0 ),
119 mbDdeLinkCreated( false )
123 void ExternalName::importDefinedName( const AttributeList& rAttribs )
125 maModel.maName = rAttribs.getXString( XML_name, OUString() );
126 OSL_ENSURE( maModel.maName.getLength() > 0, "ExternalName::importDefinedName - empty name" );
127 // zero-based index into sheet list of externalBook
128 maModel.mnSheet = rAttribs.getInteger( XML_sheetId, -1 );
131 void ExternalName::importDdeItem( const AttributeList& rAttribs )
133 maModel.maName = rAttribs.getXString( XML_name, OUString() );
134 OSL_ENSURE( maModel.maName.getLength() > 0, "ExternalName::importDdeItem - empty name" );
135 maExtNameModel.mbOleObj = false;
136 maExtNameModel.mbStdDocName = rAttribs.getBool( XML_ole, false );
137 maExtNameModel.mbNotify = rAttribs.getBool( XML_advise, false );
138 maExtNameModel.mbPreferPic = rAttribs.getBool( XML_preferPic, false );
141 void ExternalName::importValues( const AttributeList& rAttribs )
143 setResultSize( rAttribs.getInteger( XML_cols, 1 ), rAttribs.getInteger( XML_rows, 1 ) );
146 void ExternalName::importOleItem( const AttributeList& rAttribs )
148 maModel.maName = rAttribs.getXString( XML_name, OUString() );
149 OSL_ENSURE( maModel.maName.getLength() > 0, "ExternalName::importOleItem - empty name" );
150 maExtNameModel.mbOleObj = true;
151 maExtNameModel.mbNotify = rAttribs.getBool( XML_advise, false );
152 maExtNameModel.mbPreferPic = rAttribs.getBool( XML_preferPic, false );
153 maExtNameModel.mbIconified = rAttribs.getBool( XML_icon, false );
156 void ExternalName::importExternalName( RecordInputStream& rStrm )
158 rStrm >> maModel.maName;
159 OSL_ENSURE( maModel.maName.getLength() > 0, "ExternalName::importExternalName - empty name" );
162 void ExternalName::importExternalNameFlags( RecordInputStream& rStrm )
164 sal_uInt16 nFlags;
165 sal_Int32 nSheetId;
166 rStrm >> nFlags >> nSheetId;
167 // index into sheet list of EXTSHEETNAMES (one-based in OOBIN)
168 maModel.mnSheet = nSheetId - 1;
169 // no flag for built-in names, as in OOX...
170 maExtNameModel.mbNotify = getFlag( nFlags, OOBIN_EXTNAME_AUTOMATIC );
171 maExtNameModel.mbPreferPic = getFlag( nFlags, OOBIN_EXTNAME_PREFERPIC );
172 maExtNameModel.mbStdDocName = getFlag( nFlags, OOBIN_EXTNAME_STDDOCNAME );
173 maExtNameModel.mbOleObj = getFlag( nFlags, OOBIN_EXTNAME_OLEOBJECT );
174 maExtNameModel.mbIconified = getFlag( nFlags, OOBIN_EXTNAME_ICONIFIED );
175 OSL_ENSURE( (mrParentLink.getLinkType() == LINKTYPE_OLE) == maExtNameModel.mbOleObj,
176 "ExternalName::importExternalNameFlags - wrong OLE flag in external name" );
179 void ExternalName::importDdeItemValues( RecordInputStream& rStrm )
181 sal_Int32 nRows, nCols;
182 rStrm >> nRows >> nCols;
183 setResultSize( nCols, nRows );
186 void ExternalName::importDdeItemBool( RecordInputStream& rStrm )
188 appendResultValue< double >( (rStrm.readuInt8() == 0) ? 0.0 : 1.0 );
191 void ExternalName::importDdeItemDouble( RecordInputStream& rStrm )
193 appendResultValue( rStrm.readDouble() );
196 void ExternalName::importDdeItemError( RecordInputStream& rStrm )
198 appendResultValue( BiffHelper::calcDoubleFromError( rStrm.readuInt8() ) );
201 void ExternalName::importDdeItemString( RecordInputStream& rStrm )
203 appendResultValue( rStrm.readString() );
206 void ExternalName::importExternalName( BiffInputStream& rStrm )
208 sal_uInt16 nFlags = 0;
209 if( getBiff() >= BIFF3 )
211 rStrm >> nFlags;
212 maExtNameModel.mbBuiltIn = getFlag( nFlags, BIFF_EXTNAME_BUILTIN );
213 maExtNameModel.mbNotify = getFlag( nFlags, BIFF_EXTNAME_AUTOMATIC );
214 maExtNameModel.mbPreferPic = getFlag( nFlags, BIFF_EXTNAME_PREFERPIC );
216 // BIFF5-BIFF8: sheet index for sheet-local names, OLE settings
217 if( getBiff() >= BIFF5 )
219 maExtNameModel.mbStdDocName = getFlag( nFlags, BIFF_EXTNAME_STDDOCNAME );
220 maExtNameModel.mbOleObj = getFlag( nFlags, BIFF_EXTNAME_OLEOBJECT );
221 maExtNameModel.mbIconified = getFlag( nFlags, BIFF_EXTNAME_ICONIFIED );
223 if( maExtNameModel.mbOleObj )
225 rStrm >> mnStorageId;
227 else
229 /* Import the reference ID for names that are sheet-local in
230 the external document. This index will be resolved later to
231 the index of the external sheet cache which is able to
232 provide the name of the sheet related to this defined name.
233 - BIFF5: one-based index to EXTERNSHEET record containing
234 the document and sheet name
235 - BIFF8: one-based index into EXTERNALBOOK sheet name list
236 The value zero means this external name is a global name.
238 rStrm.skip( 2 );
239 maModel.mnSheet = rStrm.readuInt16();
244 maModel.maName = (getBiff() == BIFF8) ?
245 rStrm.readUniStringBody( rStrm.readuInt8() ) :
246 rStrm.readByteStringUC( false, getTextEncoding() );
247 OSL_ENSURE( maModel.maName.getLength() > 0, "ExternalName::importExternalName - empty name" );
249 // load cell references that are stored in hidden external names (seen in BIFF3-BIFF4)
250 bool bHiddenRef = (getBiff() <= BIFF4) && (maModel.maName.getLength() > 1) && (maModel.maName[ 0 ] == '\x01') && (rStrm.getRemaining() > 2);
251 switch( mrParentLink.getLinkType() )
253 case LINKTYPE_INTERNAL:
254 // cell references to other internal sheets are stored in hidden external names
255 if( bHiddenRef && (getBiff() == BIFF4) && isWorkbookFile() )
257 TokensFormulaContext aContext( true, true );
258 importBiffFormula( aContext, mrParentLink.getCalcSheetIndex(), rStrm );
259 extractReference( aContext.getTokens() );
261 break;
263 case LINKTYPE_EXTERNAL:
264 // cell references to other documents are stored in hidden external names
265 if( bHiddenRef )
267 TokensFormulaContext aContext( true, true );
268 importBiffFormula( aContext, 0, rStrm );
269 extractExternalReference( aContext.getTokens() );
271 break;
273 case LINKTYPE_DDE:
274 case LINKTYPE_OLE:
275 case LINKTYPE_MAYBE_DDE_OLE:
276 // DDE/OLE link results
277 if( rStrm.getRemaining() > 3 )
279 bool bBiff8 = getBiff() == BIFF8;
280 sal_Int32 nCols = rStrm.readuInt8();
281 sal_Int32 nRows = rStrm.readuInt16();
282 if( bBiff8 ) { ++nCols; ++nRows; } else if( nCols == 0 ) nCols = 256;
283 setResultSize( nCols, nRows );
285 bool bLoop = true;
286 while( bLoop && !rStrm.isEof() && (maCurrIt != maResults.end()) )
288 switch( rStrm.readuInt8() )
290 case BIFF_DATATYPE_EMPTY:
291 appendResultValue( OUString() );
292 rStrm.skip( 8 );
293 break;
294 case BIFF_DATATYPE_DOUBLE:
295 appendResultValue( rStrm.readDouble() );
296 break;
297 case BIFF_DATATYPE_STRING:
298 appendResultValue( bBiff8 ? rStrm.readUniString() : rStrm.readByteStringUC( false, getTextEncoding() ) );
299 break;
300 case BIFF_DATATYPE_BOOL:
301 appendResultValue< double >( (rStrm.readuInt8() == 0) ? 0.0 : 1.0 );
302 rStrm.skip( 7 );
303 break;
304 case BIFF_DATATYPE_ERROR:
305 appendResultValue( BiffHelper::calcDoubleFromError( rStrm.readuInt8() ) );
306 rStrm.skip( 7 );
307 break;
308 default:
309 bLoop = false;
312 OSL_ENSURE( bLoop && !rStrm.isEof() && (maCurrIt == maResults.end()),
313 "ExternalName::importExternalName - stream error in result set" );
315 break;
317 default:;
321 #if 0
322 sal_Int32 ExternalName::getSheetCacheIndex() const
324 OSL_ENSURE( mrParentLink.getLinkType() == LINKTYPE_DDE, "ExternalName::getSheetCacheIndex - unexpected link type" );
325 sal_Int32 nCacheIdx = -1;
326 switch( getFilterType() )
328 case FILTER_OOX:
329 // OOXML/OOBIN: zero-based index into sheet list, -1 means global name
330 if( maModel.mnSheet >= 0 )
331 nCacheIdx = mrParentLink.getSheetIndex( maModel.mnSheet );
332 break;
333 case FILTER_BIFF:
334 switch( getBiff() )
336 case BIFF2:
337 case BIFF3:
338 case BIFF4:
339 break;
340 case BIFF5:
341 if( maModel.mnSheet > 0 )
342 if( const ExternalLink* pExtLink = getExternalLinks().getExternalLink( maModel.mnSheet ).get() )
343 if( pExtLink->getLinkType() == LINKTYPE_EXTERNAL )
344 nCacheIdx = pExtLink->getSheetIndex();
345 break;
346 case BIFF8:
347 if( maModel.mnSheet > 0 )
348 nCacheIdx = mrParentLink.getSheetIndex( maModel.mnSheet - 1 );
349 break;
350 case BIFF_UNKNOWN:
351 break;
353 break;
354 case FILTER_UNKNOWN:
355 break;
357 return nCacheIdx;
359 #endif
361 bool ExternalName::getDdeItemInfo( DDEItemInfo& orItemInfo ) const
363 if( (mrParentLink.getLinkType() == LINKTYPE_DDE) && (maModel.maName.getLength() > 0) )
365 orItemInfo.Item = maModel.maName;
366 orItemInfo.Results = ContainerHelper::matrixToSequenceSequence( maResults );
367 return true;
369 return false;
372 bool ExternalName::getDdeLinkData( OUString& orDdeServer, OUString& orDdeTopic, OUString& orDdeItem )
374 if( (mrParentLink.getLinkType() == LINKTYPE_DDE) && (maModel.maName.getLength() > 0) )
376 // try to create a DDE link and to set the imported link results
377 if( !mbDdeLinkCreated ) try
379 Reference< XDDELinks > xDdeLinks( getDdeLinks(), UNO_QUERY_THROW );
380 mxDdeLink = xDdeLinks->addDDELink( mrParentLink.getClassName(), mrParentLink.getTargetUrl(), maModel.maName, ::com::sun::star::sheet::DDELinkMode_DEFAULT );
381 if( !maResults.empty() )
383 Reference< XDDELinkResults > xResults( mxDdeLink, UNO_QUERY_THROW );
384 xResults->setResults( ContainerHelper::matrixToSequenceSequence( maResults ) );
386 mbDdeLinkCreated = true;
388 catch( Exception& )
390 OSL_ENSURE( false, "ExternalName::getDdeLinkData - cannot create DDE link" );
392 // get link data from created DDE link
393 if( mxDdeLink.is() )
395 orDdeServer = mxDdeLink->getApplication();
396 orDdeTopic = mxDdeLink->getTopic();
397 orDdeItem = mxDdeLink->getItem();
398 return true;
401 return false;
404 // private --------------------------------------------------------------------
406 namespace {
408 void lclSetSheetCacheIndex( SingleReference& orApiRef, sal_Int32 nCacheIdx )
410 using namespace ::com::sun::star::sheet::ReferenceFlags;
411 setFlag( orApiRef.Flags, SHEET_RELATIVE, false );
412 setFlag( orApiRef.Flags, SHEET_3D, true );
413 orApiRef.Sheet = nCacheIdx;
416 } // namespace
418 void ExternalName::extractExternalReference( const ApiTokenSequence& rTokens )
420 OSL_ENSURE( (getFilterType() == FILTER_BIFF) && (getBiff() <= BIFF4), "ExternalName::setExternalReference - unexpected call" );
421 sal_Int32 nDocLinkIdx = mrParentLink.getDocumentLinkIndex();
422 sal_Int32 nCacheIdx = mrParentLink.getSheetCacheIndex();
423 if( (nDocLinkIdx >= 0) && (nCacheIdx >= 0) )
425 ExternalReference aExtApiRef;
426 aExtApiRef.Index = nDocLinkIdx;
428 Any aRefAny = getFormulaParser().extractReference( rTokens );
429 if( aRefAny.has< SingleReference >() )
431 SingleReference aApiRef;
432 aRefAny >>= aApiRef;
433 lclSetSheetCacheIndex( aApiRef, nCacheIdx );
434 aExtApiRef.Reference <<= aApiRef;
435 maRefAny <<= aExtApiRef;
437 else if( aRefAny.has< ComplexReference >() )
439 ComplexReference aApiRef;
440 aRefAny >>= aApiRef;
441 lclSetSheetCacheIndex( aApiRef.Reference1, nCacheIdx );
442 lclSetSheetCacheIndex( aApiRef.Reference2, nCacheIdx );
443 aExtApiRef.Reference <<= aApiRef;
444 maRefAny <<= aExtApiRef;
449 void ExternalName::setResultSize( sal_Int32 nColumns, sal_Int32 nRows )
451 OSL_ENSURE( (mrParentLink.getLinkType() == LINKTYPE_DDE) || (mrParentLink.getLinkType() == LINKTYPE_OLE) ||
452 (mrParentLink.getLinkType() == LINKTYPE_MAYBE_DDE_OLE), "ExternalName::setResultSize - wrong link type" );
453 OSL_ENSURE( (nRows > 0) && (nColumns > 0), "ExternalName::setResultSize - invalid matrix size" );
454 const CellAddress& rMaxPos = getAddressConverter().getMaxApiAddress();
455 if( (0 < nRows) && (nRows <= rMaxPos.Row + 1) && (0 < nColumns) && (nColumns <= rMaxPos.Column + 1) )
456 maResults.resize( static_cast< size_t >( nColumns ), static_cast< size_t >( nRows ), Any( BiffHelper::calcDoubleFromError( BIFF_ERR_NA ) ) );
457 else
458 maResults.clear();
459 maCurrIt = maResults.begin();
462 // ============================================================================
464 void LinkSheetRange::setDeleted()
466 meType = LINKSHEETRANGE_INTERNAL;
467 mnDocLink = mnFirst = mnLast = -1;
470 void LinkSheetRange::setSameSheet()
472 meType = LINKSHEETRANGE_SAMESHEET;
473 mnDocLink = -1;
474 mnFirst = mnLast = 0;
477 void LinkSheetRange::setRange( sal_Int32 nFirst, sal_Int32 nLast )
479 meType = LINKSHEETRANGE_INTERNAL;
480 mnDocLink = -1;
481 mnFirst = ::std::min( nFirst, nLast );
482 mnLast = ::std::max( nFirst, nLast );
485 void LinkSheetRange::setExternalRange( sal_Int32 nDocLink, sal_Int32 nFirst, sal_Int32 nLast )
487 if( nDocLink < 0 )
489 setDeleted();
491 else
493 meType = LINKSHEETRANGE_EXTERNAL;
494 mnDocLink = nDocLink;
495 mnFirst = ::std::min( nFirst, nLast );
496 mnLast = ::std::max( nFirst, nLast );
500 // ============================================================================
502 ExternalLink::ExternalLink( const WorkbookHelper& rHelper ) :
503 WorkbookHelper( rHelper ),
504 meLinkType( LINKTYPE_UNKNOWN ),
505 meFuncLibType( FUNCLIB_UNKNOWN )
509 void ExternalLink::importExternalReference( const AttributeList& rAttribs )
511 maRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
514 void ExternalLink::importExternalBook( const Relations& rRelations, const AttributeList& rAttribs )
516 parseExternalReference( rRelations, rAttribs.getString( R_TOKEN( id ), OUString() ) );
519 void ExternalLink::importSheetName( const AttributeList& rAttribs )
521 insertExternalSheet( rAttribs.getXString( XML_val, OUString() ) );
524 void ExternalLink::importDefinedName( const AttributeList& rAttribs )
526 createExternalName()->importDefinedName( rAttribs );
529 void ExternalLink::importDdeLink( const AttributeList& rAttribs )
531 OUString aDdeService = rAttribs.getXString( XML_ddeService, OUString() );
532 OUString aDdeTopic = rAttribs.getXString( XML_ddeTopic, OUString() );
533 setDdeOleTargetUrl( aDdeService, aDdeTopic, LINKTYPE_DDE );
536 ExternalNameRef ExternalLink::importDdeItem( const AttributeList& rAttribs )
538 ExternalNameRef xExtName = createExternalName();
539 xExtName->importDdeItem( rAttribs );
540 return xExtName;
543 void ExternalLink::importOleLink( const Relations& rRelations, const AttributeList& rAttribs )
545 OUString aProgId = rAttribs.getXString( XML_progId, OUString() );
546 OUString aTargetUrl = rRelations.getExternalTargetFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) );
547 setDdeOleTargetUrl( aProgId, aTargetUrl, LINKTYPE_OLE );
550 ExternalNameRef ExternalLink::importOleItem( const AttributeList& rAttribs )
552 ExternalNameRef xExtName = createExternalName();
553 xExtName->importOleItem( rAttribs );
554 return xExtName;
557 void ExternalLink::importExternalRef( RecordInputStream& rStrm )
559 rStrm >> maRelId;
562 void ExternalLink::importExternalSelf( RecordInputStream& )
564 meLinkType = LINKTYPE_SELF;
567 void ExternalLink::importExternalSame( RecordInputStream& )
569 meLinkType = LINKTYPE_SAME;
572 void ExternalLink::importExternalAddin( RecordInputStream& )
574 meLinkType = LINKTYPE_UNKNOWN;
577 void ExternalLink::importExternalBook( const Relations& rRelations, RecordInputStream& rStrm )
579 switch( rStrm.readuInt16() )
581 case OOBIN_EXTERNALBOOK_BOOK:
582 parseExternalReference( rRelations, rStrm.readString() );
583 break;
584 case OOBIN_EXTERNALBOOK_DDE:
586 OUString aDdeService, aDdeTopic;
587 rStrm >> aDdeService >> aDdeTopic;
588 setDdeOleTargetUrl( aDdeService, aDdeTopic, LINKTYPE_DDE );
590 break;
591 case OOBIN_EXTERNALBOOK_OLE:
593 OUString aTargetUrl = rRelations.getExternalTargetFromRelId( rStrm.readString() );
594 OUString aProgId = rStrm.readString();
595 setDdeOleTargetUrl( aProgId, aTargetUrl, LINKTYPE_OLE );
597 break;
598 default:
599 OSL_ENSURE( false, "ExternalLink::importExternalBook - unknown link type" );
603 void ExternalLink::importExtSheetNames( RecordInputStream& rStrm )
605 // load external sheet names and create the sheet caches in the Calc document
606 OSL_ENSURE( (meLinkType == LINKTYPE_EXTERNAL) || (meLinkType == LINKTYPE_LIBRARY),
607 "ExternalLink::importExtSheetNames - invalid link type" );
608 if( meLinkType == LINKTYPE_EXTERNAL ) // ignore sheets of external libraries
609 for( sal_Int32 nSheet = 0, nCount = rStrm.readInt32(); !rStrm.isEof() && (nSheet < nCount); ++nSheet )
610 insertExternalSheet( rStrm.readString() );
613 ExternalNameRef ExternalLink::importExternalName( RecordInputStream& rStrm )
615 ExternalNameRef xExtName = createExternalName();
616 xExtName->importExternalName( rStrm );
617 return xExtName;
620 void ExternalLink::importExternSheet( BiffInputStream& rStrm )
622 OStringBuffer aTargetBuffer( rStrm.readByteString( false, true ) );
623 // references to own sheets have wrong string length field (off by 1)
624 if( (aTargetBuffer.getLength() > 0) && (aTargetBuffer[ 0 ] == 3) )
625 aTargetBuffer.append( static_cast< sal_Char >( rStrm.readuInt8() ) );
626 // parse the encoded URL
627 OUString aBiffTarget = OStringToOUString( aTargetBuffer.makeStringAndClear(), getTextEncoding() );
628 OUString aSheetName = parseBiffTargetUrl( aBiffTarget );
629 switch( meLinkType )
631 case LINKTYPE_INTERNAL:
632 maCalcSheets.push_back( getWorksheets().getCalcSheetIndex( aSheetName ) );
633 break;
634 case LINKTYPE_EXTERNAL:
635 insertExternalSheet( (aSheetName.getLength() > 0) ? aSheetName : WorksheetBuffer::getBaseFileName( maTargetUrl ) );
636 break;
637 default:;
641 void ExternalLink::importExternalBook( BiffInputStream& rStrm )
643 OUString aTarget;
644 sal_uInt16 nSheetCount;
645 rStrm >> nSheetCount;
646 if( rStrm.getRemaining() == 2 )
648 if( rStrm.readuInt8() == 1 )
650 sal_Char cChar = static_cast< sal_Char >( rStrm.readuInt8() );
651 if( cChar != 0 )
652 aTarget = OStringToOUString( OString( cChar ), getTextEncoding() );
655 else if( rStrm.getRemaining() >= 3 )
657 // NUL characters may occur
658 aTarget = rStrm.readUniString( true );
661 // parse the encoded URL
662 OUString aDummySheetName = parseBiffTargetUrl( aTarget );
663 OSL_ENSURE( aDummySheetName.getLength() == 0, "ExternalLink::importExternalBook - sheet name in encoded URL" );
664 (void)aDummySheetName; // prevent compiler warning
666 // load external sheet names and create the sheet caches in the Calc document
667 if( meLinkType == LINKTYPE_EXTERNAL )
668 for( sal_uInt16 nSheet = 0; !rStrm.isEof() && (nSheet < nSheetCount); ++nSheet )
669 insertExternalSheet( rStrm.readUniString() );
672 void ExternalLink::importExternalName( BiffInputStream& rStrm )
674 ExternalNameRef xExtName = createExternalName();
675 xExtName->importExternalName( rStrm );
676 switch( meLinkType )
678 case LINKTYPE_DDE:
679 OSL_ENSURE( !xExtName->isOleObject(), "ExternalLink::importExternalName - OLE object in DDE link" );
680 break;
681 case LINKTYPE_OLE:
682 OSL_ENSURE( xExtName->isOleObject(), "ExternalLink::importExternalName - anything but OLE object in OLE link" );
683 break;
684 case LINKTYPE_MAYBE_DDE_OLE:
685 meLinkType = xExtName->isOleObject() ? LINKTYPE_OLE : LINKTYPE_DDE;
686 break;
687 default:
688 OSL_ENSURE( !xExtName->isOleObject(), "ExternalLink::importExternalName - OLE object in external name" );
692 ExternalLinkInfo ExternalLink::getLinkInfo() const
694 ExternalLinkInfo aLinkInfo;
695 switch( meLinkType )
697 case LINKTYPE_EXTERNAL:
698 aLinkInfo.Type = ::com::sun::star::sheet::ExternalLinkType::DOCUMENT;
699 aLinkInfo.Data <<= maTargetUrl;
700 break;
701 case LINKTYPE_DDE:
703 aLinkInfo.Type = ::com::sun::star::sheet::ExternalLinkType::DDE;
704 DDELinkInfo aDdeLinkInfo;
705 aDdeLinkInfo.Service = maClassName;
706 aDdeLinkInfo.Topic = maTargetUrl;
707 ::std::vector< DDEItemInfo > aItemInfos;
708 DDEItemInfo aItemInfo;
709 for( ExternalNameVector::const_iterator aIt = maExtNames.begin(), aEnd = maExtNames.end(); aIt != aEnd; ++aIt )
710 if( (*aIt)->getDdeItemInfo( aItemInfo ) )
711 aItemInfos.push_back( aItemInfo );
712 aDdeLinkInfo.Items = ContainerHelper::vectorToSequence( aItemInfos );
713 aLinkInfo.Data <<= aDdeLinkInfo;
715 break;
716 default:
717 aLinkInfo.Type = ::com::sun::star::sheet::ExternalLinkType::UNKNOWN;
719 return aLinkInfo;
722 FunctionLibraryType ExternalLink::getFuncLibraryType() const
724 return (meLinkType == LINKTYPE_LIBRARY) ? meFuncLibType : FUNCLIB_UNKNOWN;
727 sal_Int16 ExternalLink::getCalcSheetIndex( sal_Int32 nTabId ) const
729 OSL_ENSURE( meLinkType == LINKTYPE_INTERNAL, "ExternalLink::getCalcSheetIndex - invalid link type" );
730 OSL_ENSURE( (nTabId == 0) || (getFilterType() == FILTER_OOX) || (getBiff() == BIFF8),
731 "ExternalLink::getCalcSheetIndex - invalid sheet index" );
732 return ContainerHelper::getVectorElement< sal_Int16 >( maCalcSheets, nTabId, -1 );
735 sal_Int32 ExternalLink::getDocumentLinkIndex() const
737 OSL_ENSURE( meLinkType == LINKTYPE_EXTERNAL, "ExternalLink::getDocumentLinkIndex - invalid link type" );
738 return mxDocLink.is() ? mxDocLink->getTokenIndex() : -1;
741 sal_Int32 ExternalLink::getSheetCacheIndex( sal_Int32 nTabId ) const
743 OSL_ENSURE( meLinkType == LINKTYPE_EXTERNAL, "ExternalLink::getSheetCacheIndex - invalid link type" );
744 OSL_ENSURE( (nTabId == 0) || (getFilterType() == FILTER_OOX) || (getBiff() == BIFF8),
745 "ExternalLink::getSheetCacheIndex - invalid sheet index" );
746 return ContainerHelper::getVectorElement< sal_Int32 >( maSheetCaches, nTabId, -1 );
749 Reference< XExternalSheetCache > ExternalLink::getSheetCache( sal_Int32 nTabId ) const
751 sal_Int32 nCacheIdx = getSheetCacheIndex( nTabId );
752 if( mxDocLink.is() && (nCacheIdx >= 0) ) try
754 // existing mxDocLink implies that this is an external link
755 Reference< XExternalSheetCache > xSheetCache( mxDocLink->getByIndex( nCacheIdx ), UNO_QUERY_THROW );
756 return xSheetCache;
758 catch( Exception& )
761 return 0;
764 void ExternalLink::getSheetRange( LinkSheetRange& orSheetRange, sal_Int32 nTabId1, sal_Int32 nTabId2 ) const
766 switch( meLinkType )
768 case LINKTYPE_SAME:
769 orSheetRange.setSameSheet();
770 break;
772 case LINKTYPE_SELF:
773 case LINKTYPE_INTERNAL:
774 orSheetRange.setRange( nTabId1, nTabId2 );
775 break;
777 case LINKTYPE_EXTERNAL:
779 sal_Int32 nDocLinkIdx = getDocumentLinkIndex();
780 switch( getFilterType() )
782 case FILTER_OOX:
783 // OOBIN: passed indexes point into sheet list of EXTSHEETLIST
784 orSheetRange.setExternalRange( nDocLinkIdx, getSheetCacheIndex( nTabId1 ), getSheetCacheIndex( nTabId2 ) );
785 break;
786 case FILTER_BIFF:
787 switch( getBiff() )
789 case BIFF2:
790 case BIFF3:
791 case BIFF4:
792 orSheetRange.setExternalRange( nDocLinkIdx, getSheetCacheIndex( nTabId1 ), getSheetCacheIndex( nTabId2 ) );
793 break;
794 case BIFF5:
795 // BIFF5: first sheet from this external link, last sheet is passed in nTabId2
796 if( const ExternalLink* pExtLink2 = getExternalLinks().getExternalLink( nTabId2 ).get() )
797 if( (pExtLink2->getLinkType() == LINKTYPE_EXTERNAL) && (maTargetUrl == pExtLink2->getTargetUrl()) )
798 orSheetRange.setExternalRange( nDocLinkIdx, getSheetCacheIndex(), pExtLink2->getSheetCacheIndex() );
799 break;
800 case BIFF8:
801 // BIFF8: passed indexes point into sheet list of EXTERNALBOOK
802 orSheetRange.setExternalRange( nDocLinkIdx, getSheetCacheIndex( nTabId1 ), getSheetCacheIndex( nTabId2 ) );
803 break;
804 case BIFF_UNKNOWN: break;
806 break;
807 case FILTER_UNKNOWN: break;
810 break;
812 default:
813 // unsupported/unexpected link type: #REF! error
814 orSheetRange.setDeleted();
818 ExternalNameRef ExternalLink::getNameByIndex( sal_Int32 nIndex ) const
820 return maExtNames.get( nIndex );
823 // private --------------------------------------------------------------------
825 #define OOX_TARGETTYPE_EXTLINK CREATE_OFFICEDOC_RELATIONSTYPE( "externalLinkPath" )
826 #define OOX_TARGETTYPE_LIBRARY CREATE_MSOFFICE_RELATIONSTYPE( "xlExternalLinkPath/xlLibrary" )
828 void ExternalLink::setExternalTargetUrl( const OUString& rTargetUrl, const OUString& rTargetType )
830 meLinkType = LINKTYPE_UNKNOWN;
831 if( rTargetType == OOX_TARGETTYPE_EXTLINK )
833 maTargetUrl = getBaseFilter().getAbsoluteUrl( rTargetUrl );
834 if( maTargetUrl.getLength() > 0 )
835 meLinkType = LINKTYPE_EXTERNAL;
837 else if( rTargetType == OOX_TARGETTYPE_LIBRARY )
839 meLinkType = LINKTYPE_LIBRARY;
840 meFuncLibType = getFormulaParser().getFuncLibTypeFromLibraryName( rTargetUrl );
842 OSL_ENSURE( meLinkType != LINKTYPE_UNKNOWN, "ExternalLink::setExternalTargetUrl - empty target URL or unknown target type" );
844 // create the external document link API object that will contain the sheet caches
845 if( meLinkType == LINKTYPE_EXTERNAL )
847 Reference< XExternalDocLinks > xDocLinks = getExternalDocLinks();
848 if( xDocLinks.is() )
849 mxDocLink = xDocLinks->addDocLink( maTargetUrl );
853 void ExternalLink::setDdeOleTargetUrl( const OUString& rClassName, const OUString& rTargetUrl, ExternalLinkType eLinkType )
855 maClassName = rClassName;
856 maTargetUrl = rTargetUrl;
857 meLinkType = ((maClassName.getLength() > 0) && (maTargetUrl.getLength() > 0)) ? eLinkType : LINKTYPE_UNKNOWN;
858 OSL_ENSURE( meLinkType == eLinkType, "ExternalLink::setDdeOleTargetUrl - missing classname or target" );
861 void ExternalLink::parseExternalReference( const Relations& rRelations, const OUString& rRelId )
863 if( const Relation* pRelation = rRelations.getRelationFromRelId( rRelId ) )
864 setExternalTargetUrl( pRelation->maTarget, pRelation->maType );
867 OUString ExternalLink::parseBiffTargetUrl( const OUString& rBiffTargetUrl )
869 meLinkType = LINKTYPE_UNKNOWN;
871 OUString aClassName, aTargetUrl, aSheetName;
872 switch( getAddressConverter().parseBiffTargetUrl( aClassName, aTargetUrl, aSheetName, rBiffTargetUrl ) )
874 case BIFF_TARGETTYPE_URL:
875 if( aTargetUrl.getLength() == 0 )
877 meLinkType = (aSheetName.getLength() > 0) ? LINKTYPE_INTERNAL : LINKTYPE_SELF;
879 else if( (aTargetUrl.getLength() == 1) && (aTargetUrl[ 0 ] == ':') )
881 if( getBiff() >= BIFF4 )
882 meLinkType = LINKTYPE_ANALYSIS;
884 else if( (aTargetUrl.getLength() > 1) || (aTargetUrl[ 0 ] != ' ') )
886 setExternalTargetUrl( aTargetUrl, OOX_TARGETTYPE_EXTLINK );
888 break;
890 case BIFF_TARGETTYPE_SAMESHEET:
891 OSL_ENSURE( (aTargetUrl.getLength() == 0) && (aSheetName.getLength() == 0), "ExternalLink::parseBiffTargetUrl - unexpected target or sheet name" );
892 meLinkType = LINKTYPE_SAME;
893 break;
895 case BIFF_TARGETTYPE_LIBRARY:
896 OSL_ENSURE( aSheetName.getLength() == 0, "ExternalLink::parseBiffTargetUrl - unexpected sheet name" );
897 setExternalTargetUrl( aTargetUrl, OOX_TARGETTYPE_LIBRARY );
898 break;
900 case BIFF_TARGETTYPE_DDE_OLE:
901 setDdeOleTargetUrl( aClassName, aTargetUrl, LINKTYPE_MAYBE_DDE_OLE );
902 break;
904 case BIFF_TARGETTYPE_UNKNOWN:
905 break;
907 return aSheetName;
910 void ExternalLink::insertExternalSheet( const OUString& rSheetName )
912 OSL_ENSURE( rSheetName.getLength() > 0, "ExternalLink::insertExternalSheet - empty sheet name" );
913 if( mxDocLink.is() )
915 Reference< XExternalSheetCache > xSheetCache = mxDocLink->addSheetCache( rSheetName );
916 sal_Int32 nCacheIdx = xSheetCache.is() ? xSheetCache->getTokenIndex() : -1;
917 maSheetCaches.push_back( nCacheIdx );
921 ExternalNameRef ExternalLink::createExternalName()
923 ExternalNameRef xExtName( new ExternalName( *this ) );
924 maExtNames.push_back( xExtName );
925 return xExtName;
928 // ============================================================================
930 RefSheetsModel::RefSheetsModel() :
931 mnExtRefId( -1 ),
932 mnTabId1( -1 ),
933 mnTabId2( -1 )
937 void RefSheetsModel::readOobData( RecordInputStream& rStrm )
939 rStrm >> mnExtRefId >> mnTabId1 >> mnTabId2;
942 void RefSheetsModel::readBiff8Data( BiffInputStream& rStrm )
944 mnExtRefId = rStrm.readuInt16();
945 mnTabId1 = rStrm.readInt16();
946 mnTabId2 = rStrm.readInt16();
949 // ----------------------------------------------------------------------------
951 ExternalLinkBuffer::ExternalLinkBuffer( const WorkbookHelper& rHelper ) :
952 WorkbookHelper( rHelper ),
953 mbUseRefSheets( false )
957 ExternalLinkRef ExternalLinkBuffer::importExternalReference( const AttributeList& rAttribs )
959 ExternalLinkRef xExtLink = createExternalLink();
960 xExtLink->importExternalReference( rAttribs );
961 maExtLinks.push_back( xExtLink );
962 return xExtLink;
965 ExternalLinkRef ExternalLinkBuffer::importExternalRef( RecordInputStream& rStrm )
967 mbUseRefSheets = true;
968 ExternalLinkRef xExtLink = createExternalLink();
969 xExtLink->importExternalRef( rStrm );
970 maExtLinks.push_back( xExtLink );
971 return xExtLink;
974 void ExternalLinkBuffer::importExternalSelf( RecordInputStream& rStrm )
976 mbUseRefSheets = true;
977 createExternalLink()->importExternalSelf( rStrm );
980 void ExternalLinkBuffer::importExternalSame( RecordInputStream& rStrm )
982 mbUseRefSheets = true;
983 createExternalLink()->importExternalSame( rStrm );
986 void ExternalLinkBuffer::importExternalAddin( RecordInputStream& rStrm )
988 mbUseRefSheets = true;
989 createExternalLink()->importExternalAddin( rStrm );
992 void ExternalLinkBuffer::importExternalSheets( RecordInputStream& rStrm )
994 OSL_ENSURE( mbUseRefSheets, "ExternalLinkBuffer::importExternalSheets - missing EXTERNALREFS records" );
995 mbUseRefSheets = true;
996 OSL_ENSURE( maRefSheets.empty(), "ExternalLinkBuffer::importExternalSheets - multiple EXTERNALSHEETS records" );
997 maRefSheets.clear();
998 sal_Int32 nRefCount;
999 rStrm >> nRefCount;
1000 size_t nMaxCount = getLimitedValue< size_t, sal_Int64 >( nRefCount, 0, rStrm.getRemaining() / 12 );
1001 maRefSheets.reserve( nMaxCount );
1002 for( size_t nRefId = 0; !rStrm.isEof() && (nRefId < nMaxCount); ++nRefId )
1004 RefSheetsModel aRefSheets;
1005 aRefSheets.readOobData( rStrm );
1006 maRefSheets.push_back( aRefSheets );
1010 ExternalLinkRef ExternalLinkBuffer::importExternSheet( BiffInputStream& rStrm )
1012 OSL_ENSURE( getBiff() <= BIFF5, "ExternalLinkBuffer::importExternSheet - wrong BIFF version" );
1013 ExternalLinkRef xExtLink = createExternalLink();
1014 xExtLink->importExternSheet( rStrm );
1015 return xExtLink;
1018 ExternalLinkRef ExternalLinkBuffer::importExternalBook( BiffInputStream& rStrm )
1020 ExternalLinkRef xExtLink = createExternalLink();
1021 xExtLink->importExternalBook( rStrm );
1022 return xExtLink;
1025 void ExternalLinkBuffer::importExternalName( BiffInputStream& rStrm )
1027 if( !maLinks.empty() )
1028 maLinks.back()->importExternalName( rStrm );
1031 void ExternalLinkBuffer::importExternSheet8( BiffInputStream& rStrm )
1033 OSL_ENSURE( getBiff() == BIFF8, "ExternalLinkBuffer::importExternSheet8 - wrong BIFF version" );
1035 sal_uInt16 nRefCount;
1036 rStrm >> nRefCount;
1037 OSL_ENSURE( static_cast< sal_Int64 >( nRefCount * 6 ) == rStrm.getRemaining(), "ExternalLinkBuffer::importExternSheet8 - invalid count" );
1038 nRefCount = static_cast< sal_uInt16 >( ::std::min< sal_Int64 >( nRefCount, rStrm.getRemaining() / 6 ) );
1040 /* #i104057# A weird external XLS generator writes multiple EXTERNSHEET
1041 records instead of only one as expected. Surprisingly, Excel seems to
1042 insert the entries of the second record before the entries of the first
1043 record. */
1044 maRefSheets.insert( maRefSheets.begin(), nRefCount, RefSheetsModel() );
1045 for( RefSheetsModelVec::iterator aIt = maRefSheets.begin(); !rStrm.isEof() && (nRefCount > 0); --nRefCount )
1046 aIt->readBiff8Data( rStrm );
1049 Sequence< ExternalLinkInfo > ExternalLinkBuffer::getLinkInfos() const
1051 ::std::vector< ExternalLinkInfo > aLinkInfos;
1052 // dummy entry for index 0
1053 aLinkInfos.push_back( ExternalLinkInfo( ::com::sun::star::sheet::ExternalLinkType::UNKNOWN, Any() ) );
1054 for( ExternalLinkVec::const_iterator aIt = maExtLinks.begin(), aEnd = maExtLinks.end(); aIt != aEnd; ++aIt )
1055 aLinkInfos.push_back( (*aIt)->getLinkInfo() );
1056 return ContainerHelper::vectorToSequence( aLinkInfos );
1059 ExternalLinkRef ExternalLinkBuffer::getExternalLink( sal_Int32 nRefId ) const
1061 ExternalLinkRef xExtLink;
1062 switch( getFilterType() )
1064 case FILTER_OOX:
1065 // OOXML: one-based index
1066 if( !mbUseRefSheets )
1067 xExtLink = maLinks.get( nRefId - 1 );
1068 // OOBIN: zero-based index into ref-sheets list
1069 else if( const RefSheetsModel* pRefSheets = getRefSheets( nRefId ) )
1070 xExtLink = maLinks.get( pRefSheets->mnExtRefId );
1071 break;
1072 case FILTER_BIFF:
1073 switch( getBiff() )
1075 case BIFF2:
1076 case BIFF3:
1077 case BIFF4:
1078 // one-based index to EXTERNSHEET records
1079 xExtLink = maLinks.get( nRefId - 1 );
1080 break;
1081 case BIFF5:
1082 if( nRefId < 0 )
1084 // internal links in formula tokens have negative index
1085 xExtLink = maLinks.get( -nRefId - 1 );
1086 if( xExtLink.get() && !xExtLink->isInternalLink() )
1087 xExtLink.reset();
1089 else
1091 // one-based index to EXTERNSHEET records
1092 xExtLink = maLinks.get( nRefId - 1 );
1094 break;
1095 case BIFF8:
1096 // zero-based index into REF list in EXTERNSHEET record
1097 if( const RefSheetsModel* pRefSheets = getRefSheets( nRefId ) )
1098 xExtLink = maLinks.get( pRefSheets->mnExtRefId );
1099 break;
1100 case BIFF_UNKNOWN: break;
1102 break;
1103 case FILTER_UNKNOWN: break;
1105 return xExtLink;
1108 LinkSheetRange ExternalLinkBuffer::getSheetRange( sal_Int32 nRefId, sal_Int16 nTabId1, sal_Int16 nTabId2 ) const
1110 OSL_ENSURE( getBiff() <= BIFF5, "ExternalLinkBuffer::getSheetRange - wrong BIFF version" );
1111 LinkSheetRange aSheetRange;
1112 if( const ExternalLink* pExtLink = getExternalLink( nRefId ).get() )
1113 pExtLink->getSheetRange( aSheetRange, nTabId1, nTabId2 );
1114 return aSheetRange;
1117 LinkSheetRange ExternalLinkBuffer::getSheetRange( sal_Int32 nRefId ) const
1119 OSL_ENSURE( ((getFilterType() == FILTER_OOX) && mbUseRefSheets) || (getBiff() == BIFF8), "ExternalLinkBuffer::getSheetRange - wrong BIFF version" );
1120 LinkSheetRange aSheetRange;
1121 if( const ExternalLink* pExtLink = getExternalLink( nRefId ).get() )
1122 if( const RefSheetsModel* pRefSheets = getRefSheets( nRefId ) )
1123 pExtLink->getSheetRange( aSheetRange, pRefSheets->mnTabId1, pRefSheets->mnTabId2 );
1124 return aSheetRange;
1127 // private --------------------------------------------------------------------
1129 ExternalLinkRef ExternalLinkBuffer::createExternalLink()
1131 ExternalLinkRef xExtLink( new ExternalLink( *this ) );
1132 maLinks.push_back( xExtLink );
1133 return xExtLink;
1136 const RefSheetsModel* ExternalLinkBuffer::getRefSheets( sal_Int32 nRefId ) const
1138 return ((0 <= nRefId) && (static_cast< size_t >( nRefId ) < maRefSheets.size())) ?
1139 &maRefSheets[ static_cast< size_t >( nRefId ) ] : 0;
1142 // ============================================================================
1144 } // namespace xls
1145 } // namespace oox