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"
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
;
78 // ============================================================================
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;
101 // ============================================================================
103 ExternalNameModel::ExternalNameModel() :
106 mbPreferPic( false ),
107 mbStdDocName( false ),
113 // ============================================================================
115 ExternalName::ExternalName( const ExternalLink
& rParentLink
) :
116 DefinedNameBase( rParentLink
),
117 mrParentLink( rParentLink
),
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
)
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
)
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
;
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.
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() );
263 case LINKTYPE_EXTERNAL
:
264 // cell references to other documents are stored in hidden external names
267 TokensFormulaContext
aContext( true, true );
268 importBiffFormula( aContext
, 0, rStrm
);
269 extractExternalReference( aContext
.getTokens() );
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
);
286 while( bLoop
&& !rStrm
.isEof() && (maCurrIt
!= maResults
.end()) )
288 switch( rStrm
.readuInt8() )
290 case BIFF_DATATYPE_EMPTY
:
291 appendResultValue( OUString() );
294 case BIFF_DATATYPE_DOUBLE
:
295 appendResultValue( rStrm
.readDouble() );
297 case BIFF_DATATYPE_STRING
:
298 appendResultValue( bBiff8
? rStrm
.readUniString() : rStrm
.readByteStringUC( false, getTextEncoding() ) );
300 case BIFF_DATATYPE_BOOL
:
301 appendResultValue
< double >( (rStrm
.readuInt8() == 0) ? 0.0 : 1.0 );
304 case BIFF_DATATYPE_ERROR
:
305 appendResultValue( BiffHelper::calcDoubleFromError( rStrm
.readuInt8() ) );
312 OSL_ENSURE( bLoop
&& !rStrm
.isEof() && (maCurrIt
== maResults
.end()),
313 "ExternalName::importExternalName - stream error in result set" );
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() )
329 // OOXML/OOBIN: zero-based index into sheet list, -1 means global name
330 if( maModel
.mnSheet
>= 0 )
331 nCacheIdx
= mrParentLink
.getSheetIndex( maModel
.mnSheet
);
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();
347 if( maModel
.mnSheet
> 0 )
348 nCacheIdx
= mrParentLink
.getSheetIndex( maModel
.mnSheet
- 1 );
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
);
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;
390 OSL_ENSURE( false, "ExternalName::getDdeLinkData - cannot create DDE link" );
392 // get link data from created DDE link
395 orDdeServer
= mxDdeLink
->getApplication();
396 orDdeTopic
= mxDdeLink
->getTopic();
397 orDdeItem
= mxDdeLink
->getItem();
404 // private --------------------------------------------------------------------
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
;
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
;
433 lclSetSheetCacheIndex( aApiRef
, nCacheIdx
);
434 aExtApiRef
.Reference
<<= aApiRef
;
435 maRefAny
<<= aExtApiRef
;
437 else if( aRefAny
.has
< ComplexReference
>() )
439 ComplexReference 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
) ) );
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
;
474 mnFirst
= mnLast
= 0;
477 void LinkSheetRange::setRange( sal_Int32 nFirst
, sal_Int32 nLast
)
479 meType
= LINKSHEETRANGE_INTERNAL
;
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
)
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
);
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
);
557 void ExternalLink::importExternalRef( RecordInputStream
& rStrm
)
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() );
584 case OOBIN_EXTERNALBOOK_DDE
:
586 OUString aDdeService
, aDdeTopic
;
587 rStrm
>> aDdeService
>> aDdeTopic
;
588 setDdeOleTargetUrl( aDdeService
, aDdeTopic
, LINKTYPE_DDE
);
591 case OOBIN_EXTERNALBOOK_OLE
:
593 OUString aTargetUrl
= rRelations
.getExternalTargetFromRelId( rStrm
.readString() );
594 OUString aProgId
= rStrm
.readString();
595 setDdeOleTargetUrl( aProgId
, aTargetUrl
, LINKTYPE_OLE
);
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
);
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
);
631 case LINKTYPE_INTERNAL
:
632 maCalcSheets
.push_back( getWorksheets().getCalcSheetIndex( aSheetName
) );
634 case LINKTYPE_EXTERNAL
:
635 insertExternalSheet( (aSheetName
.getLength() > 0) ? aSheetName
: WorksheetBuffer::getBaseFileName( maTargetUrl
) );
641 void ExternalLink::importExternalBook( BiffInputStream
& rStrm
)
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() );
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
);
679 OSL_ENSURE( !xExtName
->isOleObject(), "ExternalLink::importExternalName - OLE object in DDE link" );
682 OSL_ENSURE( xExtName
->isOleObject(), "ExternalLink::importExternalName - anything but OLE object in OLE link" );
684 case LINKTYPE_MAYBE_DDE_OLE
:
685 meLinkType
= xExtName
->isOleObject() ? LINKTYPE_OLE
: LINKTYPE_DDE
;
688 OSL_ENSURE( !xExtName
->isOleObject(), "ExternalLink::importExternalName - OLE object in external name" );
692 ExternalLinkInfo
ExternalLink::getLinkInfo() const
694 ExternalLinkInfo aLinkInfo
;
697 case LINKTYPE_EXTERNAL
:
698 aLinkInfo
.Type
= ::com::sun::star::sheet::ExternalLinkType::DOCUMENT
;
699 aLinkInfo
.Data
<<= maTargetUrl
;
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
;
717 aLinkInfo
.Type
= ::com::sun::star::sheet::ExternalLinkType::UNKNOWN
;
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
);
764 void ExternalLink::getSheetRange( LinkSheetRange
& orSheetRange
, sal_Int32 nTabId1
, sal_Int32 nTabId2
) const
769 orSheetRange
.setSameSheet();
773 case LINKTYPE_INTERNAL
:
774 orSheetRange
.setRange( nTabId1
, nTabId2
);
777 case LINKTYPE_EXTERNAL
:
779 sal_Int32 nDocLinkIdx
= getDocumentLinkIndex();
780 switch( getFilterType() )
783 // OOBIN: passed indexes point into sheet list of EXTSHEETLIST
784 orSheetRange
.setExternalRange( nDocLinkIdx
, getSheetCacheIndex( nTabId1
), getSheetCacheIndex( nTabId2
) );
792 orSheetRange
.setExternalRange( nDocLinkIdx
, getSheetCacheIndex( nTabId1
), getSheetCacheIndex( nTabId2
) );
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() );
801 // BIFF8: passed indexes point into sheet list of EXTERNALBOOK
802 orSheetRange
.setExternalRange( nDocLinkIdx
, getSheetCacheIndex( nTabId1
), getSheetCacheIndex( nTabId2
) );
804 case BIFF_UNKNOWN
: break;
807 case FILTER_UNKNOWN
: break;
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();
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
);
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
;
895 case BIFF_TARGETTYPE_LIBRARY
:
896 OSL_ENSURE( aSheetName
.getLength() == 0, "ExternalLink::parseBiffTargetUrl - unexpected sheet name" );
897 setExternalTargetUrl( aTargetUrl
, OOX_TARGETTYPE_LIBRARY
);
900 case BIFF_TARGETTYPE_DDE_OLE
:
901 setDdeOleTargetUrl( aClassName
, aTargetUrl
, LINKTYPE_MAYBE_DDE_OLE
);
904 case BIFF_TARGETTYPE_UNKNOWN
:
910 void ExternalLink::insertExternalSheet( const OUString
& rSheetName
)
912 OSL_ENSURE( rSheetName
.getLength() > 0, "ExternalLink::insertExternalSheet - empty sheet name" );
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
);
928 // ============================================================================
930 RefSheetsModel::RefSheetsModel() :
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
);
965 ExternalLinkRef
ExternalLinkBuffer::importExternalRef( RecordInputStream
& rStrm
)
967 mbUseRefSheets
= true;
968 ExternalLinkRef xExtLink
= createExternalLink();
969 xExtLink
->importExternalRef( rStrm
);
970 maExtLinks
.push_back( 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" );
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
);
1018 ExternalLinkRef
ExternalLinkBuffer::importExternalBook( BiffInputStream
& rStrm
)
1020 ExternalLinkRef xExtLink
= createExternalLink();
1021 xExtLink
->importExternalBook( rStrm
);
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
;
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
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() )
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
);
1078 // one-based index to EXTERNSHEET records
1079 xExtLink
= maLinks
.get( nRefId
- 1 );
1084 // internal links in formula tokens have negative index
1085 xExtLink
= maLinks
.get( -nRefId
- 1 );
1086 if( xExtLink
.get() && !xExtLink
->isInternalLink() )
1091 // one-based index to EXTERNSHEET records
1092 xExtLink
= maLinks
.get( nRefId
- 1 );
1096 // zero-based index into REF list in EXTERNSHEET record
1097 if( const RefSheetsModel
* pRefSheets
= getRefSheets( nRefId
) )
1098 xExtLink
= maLinks
.get( pRefSheets
->mnExtRefId
);
1100 case BIFF_UNKNOWN
: break;
1103 case FILTER_UNKNOWN
: break;
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
);
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
);
1127 // private --------------------------------------------------------------------
1129 ExternalLinkRef
ExternalLinkBuffer::createExternalLink()
1131 ExternalLinkRef
xExtLink( new ExternalLink( *this ) );
1132 maLinks
.push_back( 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 // ============================================================================