summaryrefslogtreecommitdiffstats
path: root/sc/source/filter/oox/externallinkbuffer.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/filter/oox/externallinkbuffer.cxx')
-rw-r--r--sc/source/filter/oox/externallinkbuffer.cxx694
1 files changed, 694 insertions, 0 deletions
diff --git a/sc/source/filter/oox/externallinkbuffer.cxx b/sc/source/filter/oox/externallinkbuffer.cxx
new file mode 100644
index 000000000..595d6e3dd
--- /dev/null
+++ b/sc/source/filter/oox/externallinkbuffer.cxx
@@ -0,0 +1,694 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <externallinkbuffer.hxx>
+#include <externalrefmgr.hxx>
+#include <compiler.hxx>
+#include <tokenarray.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sheet/DDELinkInfo.hpp>
+#include <com/sun/star/sheet/ExternalLinkType.hpp>
+#include <com/sun/star/sheet/XDDELinks.hpp>
+#include <com/sun/star/sheet/XDDELinkResults.hpp>
+#include <com/sun/star/sheet/XExternalDocLinks.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+
+#include <comphelper/sequence.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <oox/core/filterbase.hxx>
+#include <oox/helper/attributelist.hxx>
+#include <oox/helper/binaryinputstream.hxx>
+#include <oox/token/namespaces.hxx>
+#include <oox/token/properties.hxx>
+#include <oox/core/relations.hxx>
+#include <oox/token/tokens.hxx>
+#include <addressconverter.hxx>
+#include <biffhelper.hxx>
+
+namespace oox::xls {
+
+using namespace ::com::sun::star::sheet;
+using namespace ::com::sun::star::uno;
+
+using ::oox::core::Relation;
+using ::oox::core::Relations;
+
+namespace {
+
+const sal_uInt16 BIFF12_EXTERNALBOOK_BOOK = 0;
+const sal_uInt16 BIFF12_EXTERNALBOOK_DDE = 1;
+const sal_uInt16 BIFF12_EXTERNALBOOK_OLE = 2;
+
+const sal_uInt16 BIFF12_EXTNAME_AUTOMATIC = 0x0002;
+const sal_uInt16 BIFF12_EXTNAME_PREFERPIC = 0x0004;
+const sal_uInt16 BIFF12_EXTNAME_STDDOCNAME = 0x0008;
+const sal_uInt16 BIFF12_EXTNAME_OLEOBJECT = 0x0010;
+const sal_uInt16 BIFF12_EXTNAME_ICONIFIED = 0x0020;
+
+} // namespace
+
+ExternalNameModel::ExternalNameModel() :
+ mbNotify( false ),
+ mbPreferPic( false ),
+ mbStdDocName( false ),
+ mbOleObj( false ),
+ mbIconified( false )
+{
+}
+
+ExternalName::ExternalName( const ExternalLink& rParentLink ) :
+ DefinedNameBase( rParentLink ),
+ mrParentLink( rParentLink ),
+ mbDdeLinkCreated( false )
+{
+}
+
+void ExternalName::importDefinedName( const AttributeList& rAttribs )
+{
+ maModel.maName = rAttribs.getXString( XML_name, OUString() );
+ OSL_ENSURE( !maModel.maName.isEmpty(), "ExternalName::importDefinedName - empty name" );
+ maModel.maFormula = rAttribs.getXString(XML_refersTo, OUString());
+ OSL_ENSURE( !maModel.maFormula.isEmpty(), "ExternalName::importDefinedName - empty formula" );
+ // zero-based index into sheet list of externalBook
+ maModel.mnSheet = rAttribs.getInteger( XML_sheetId, -1 );
+ // cache external defined names and formulas
+ ScCompiler aComp(getScDocument(), ScAddress(0, 0, maModel.mnSheet), formula::FormulaGrammar::GRAM_OOXML);
+ aComp.SetExternalLinks(getExternalLinks().getLinkInfos());
+ std::unique_ptr<ScTokenArray> pArray = aComp.CompileString(maModel.maFormula);
+ FormulaError nErr = pArray->GetCodeError();
+ aComp.CompileTokenArray();
+ getScDocument().CheckLinkFormulaNeedingCheck(*pArray);
+ pArray->DelRPN();
+ pArray->SetCodeError(nErr);
+
+ if (pArray->HasReferences())
+ {
+ ScExternalRefManager* pRefMgr = getScDocument().GetExternalRefManager();
+ sal_uInt16 nFileId = pRefMgr->getExternalFileId(mrParentLink.getTargetUrl());
+ pRefMgr->storeRangeNameTokens(nFileId, maModel.maName, *pArray);
+ }
+}
+
+void ExternalName::importDdeItem( const AttributeList& rAttribs )
+{
+ maModel.maName = rAttribs.getXString( XML_name, OUString() );
+ OSL_ENSURE( !maModel.maName.isEmpty(), "ExternalName::importDdeItem - empty name" );
+ maExtNameModel.mbOleObj = false;
+ maExtNameModel.mbStdDocName = rAttribs.getBool( XML_ole, false );
+ maExtNameModel.mbNotify = rAttribs.getBool( XML_advise, false );
+ maExtNameModel.mbPreferPic = rAttribs.getBool( XML_preferPic, false );
+}
+
+void ExternalName::importValues( const AttributeList& rAttribs )
+{
+ setResultSize( rAttribs.getInteger( XML_cols, 1 ), rAttribs.getInteger( XML_rows, 1 ) );
+}
+
+void ExternalName::importOleItem( const AttributeList& rAttribs )
+{
+ maModel.maName = rAttribs.getXString( XML_name, OUString() );
+ OSL_ENSURE( !maModel.maName.isEmpty(), "ExternalName::importOleItem - empty name" );
+ maExtNameModel.mbOleObj = true;
+ maExtNameModel.mbNotify = rAttribs.getBool( XML_advise, false );
+ maExtNameModel.mbPreferPic = rAttribs.getBool( XML_preferPic, false );
+ maExtNameModel.mbIconified = rAttribs.getBool( XML_icon, false );
+}
+
+void ExternalName::importExternalName( SequenceInputStream& rStrm )
+{
+ rStrm >> maModel.maName;
+ OSL_ENSURE( !maModel.maName.isEmpty(), "ExternalName::importExternalName - empty name" );
+}
+
+void ExternalName::importExternalNameFlags( SequenceInputStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ sal_Int32 nSheetId;
+ nFlags = rStrm.readuInt16();
+ nSheetId = rStrm.readInt32();
+ // index into sheet list of EXTSHEETNAMES (one-based in BIFF12)
+ maModel.mnSheet = nSheetId - 1;
+ // no flag for built-in names, as in OOXML...
+ maExtNameModel.mbNotify = getFlag( nFlags, BIFF12_EXTNAME_AUTOMATIC );
+ maExtNameModel.mbPreferPic = getFlag( nFlags, BIFF12_EXTNAME_PREFERPIC );
+ maExtNameModel.mbStdDocName = getFlag( nFlags, BIFF12_EXTNAME_STDDOCNAME );
+ maExtNameModel.mbOleObj = getFlag( nFlags, BIFF12_EXTNAME_OLEOBJECT );
+ maExtNameModel.mbIconified = getFlag( nFlags, BIFF12_EXTNAME_ICONIFIED );
+ OSL_ENSURE( (mrParentLink.getLinkType() == ExternalLinkType::OLE) == maExtNameModel.mbOleObj,
+ "ExternalName::importExternalNameFlags - wrong OLE flag in external name" );
+}
+
+void ExternalName::importDdeItemValues( SequenceInputStream& rStrm )
+{
+ sal_Int32 nRows, nCols;
+ nRows = rStrm.readInt32();
+ nCols = rStrm.readInt32();
+ setResultSize( nCols, nRows );
+}
+
+void ExternalName::importDdeItemBool( SequenceInputStream& rStrm )
+{
+ appendResultValue< double >( (rStrm.readuInt8() == 0) ? 0.0 : 1.0 );
+}
+
+void ExternalName::importDdeItemDouble( SequenceInputStream& rStrm )
+{
+ appendResultValue( rStrm.readDouble() );
+}
+
+void ExternalName::importDdeItemError( SequenceInputStream& rStrm )
+{
+ appendResultValue( BiffHelper::calcDoubleFromError( rStrm.readuInt8() ) );
+}
+
+void ExternalName::importDdeItemString( SequenceInputStream& rStrm )
+{
+ appendResultValue( BiffHelper::readString( rStrm ) );
+}
+
+bool ExternalName::getDdeItemInfo( DDEItemInfo& orItemInfo ) const
+{
+ if( (mrParentLink.getLinkType() == ExternalLinkType::DDE) && !maModel.maName.isEmpty() )
+ {
+ orItemInfo.Item = maModel.maName;
+ orItemInfo.Results = ContainerHelper::matrixToSequenceSequence( maResults );
+ return true;
+ }
+ return false;
+}
+
+bool ExternalName::getDdeLinkData( OUString& orDdeServer, OUString& orDdeTopic, OUString& orDdeItem )
+{
+ if( (mrParentLink.getLinkType() == ExternalLinkType::DDE) && !maModel.maName.isEmpty() )
+ {
+ // try to create a DDE link and to set the imported link results
+ if( !mbDdeLinkCreated ) try
+ {
+ PropertySet aDocProps( getDocument() );
+ Reference< XDDELinks > xDdeLinks( aDocProps.getAnyProperty( PROP_DDELinks ), UNO_QUERY_THROW );
+ mxDdeLink = xDdeLinks->addDDELink( mrParentLink.getClassName(), mrParentLink.getTargetUrl(), maModel.maName, css::sheet::DDELinkMode_DEFAULT );
+ mbDdeLinkCreated = true; // ignore if setting results fails
+ if( !maResults.empty() )
+ {
+ Reference< XDDELinkResults > xResults( mxDdeLink, UNO_QUERY_THROW );
+ xResults->setResults( ContainerHelper::matrixToSequenceSequence( maResults ) );
+ }
+ }
+ catch( Exception& )
+ {
+ OSL_FAIL( "ExternalName::getDdeLinkData - cannot create DDE link" );
+ }
+ // get link data from created DDE link
+ if( mxDdeLink.is() )
+ {
+ orDdeServer = mxDdeLink->getApplication();
+ orDdeTopic = mxDdeLink->getTopic();
+ orDdeItem = mxDdeLink->getItem();
+ return true;
+ }
+ }
+ return false;
+}
+
+// private --------------------------------------------------------------------
+
+void ExternalName::setResultSize( sal_Int32 nColumns, sal_Int32 nRows )
+{
+ OSL_ENSURE( (mrParentLink.getLinkType() == ExternalLinkType::DDE) || (mrParentLink.getLinkType() == ExternalLinkType::OLE),
+ "ExternalName::setResultSize - wrong link type" );
+ OSL_ENSURE( (nRows > 0) && (nColumns > 0), "ExternalName::setResultSize - invalid matrix size" );
+ const ScAddress& rMaxPos = getAddressConverter().getMaxApiAddress();
+ if( (0 < nRows) && (nRows <= rMaxPos.Row() + 1) && (0 < nColumns) && (nColumns <= rMaxPos.Col() + 1) )
+ maResults.resize( static_cast< size_t >( nColumns ), static_cast< size_t >( nRows ), Any( BiffHelper::calcDoubleFromError( BIFF_ERR_NA ) ) );
+ else
+ maResults.clear();
+ maCurrIt = maResults.begin();
+}
+
+void LinkSheetRange::setDeleted()
+{
+ meType = LINKSHEETRANGE_INTERNAL;
+ mnDocLink = mnFirst = mnLast = -1;
+}
+
+void LinkSheetRange::setSameSheet()
+{
+ meType = LINKSHEETRANGE_SAMESHEET;
+ mnDocLink = -1;
+ mnFirst = mnLast = 0;
+}
+
+void LinkSheetRange::setRange( sal_Int32 nFirst, sal_Int32 nLast )
+{
+ meType = LINKSHEETRANGE_INTERNAL;
+ mnDocLink = -1;
+ mnFirst = ::std::min( nFirst, nLast );
+ mnLast = ::std::max( nFirst, nLast );
+}
+
+void LinkSheetRange::setExternalRange( sal_Int32 nDocLink, sal_Int32 nFirst, sal_Int32 nLast )
+{
+ if( nDocLink < 0 )
+ {
+ setDeleted();
+ }
+ else
+ {
+ meType = LINKSHEETRANGE_EXTERNAL;
+ mnDocLink = nDocLink;
+ mnFirst = ::std::min( nFirst, nLast );
+ mnLast = ::std::max( nFirst, nLast );
+ }
+}
+
+ExternalLink::ExternalLink( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ meLinkType( ExternalLinkType::Unknown ),
+ meFuncLibType( FUNCLIB_UNKNOWN )
+{
+}
+
+void ExternalLink::importExternalReference( const AttributeList& rAttribs )
+{
+ maRelId = rAttribs.getString( R_TOKEN( id ), OUString() );
+}
+
+void ExternalLink::importExternalBook( const Relations& rRelations, const AttributeList& rAttribs )
+{
+ parseExternalReference( rRelations, rAttribs.getString( R_TOKEN( id ), OUString() ) );
+}
+
+void ExternalLink::importSheetName( const AttributeList& rAttribs )
+{
+ insertExternalSheet( rAttribs.getXString( XML_val, OUString() ) );
+}
+
+void ExternalLink::importDefinedName( const AttributeList& rAttribs )
+{
+ createExternalName()->importDefinedName( rAttribs );
+}
+
+void ExternalLink::importDdeLink( const AttributeList& rAttribs )
+{
+ OUString aDdeService = rAttribs.getXString( XML_ddeService, OUString() );
+ OUString aDdeTopic = rAttribs.getXString( XML_ddeTopic, OUString() );
+ setDdeOleTargetUrl( aDdeService, aDdeTopic, ExternalLinkType::DDE );
+}
+
+ExternalNameRef ExternalLink::importDdeItem( const AttributeList& rAttribs )
+{
+ ExternalNameRef xExtName = createExternalName();
+ xExtName->importDdeItem( rAttribs );
+ return xExtName;
+}
+
+void ExternalLink::importOleLink( const Relations& rRelations, const AttributeList& rAttribs )
+{
+ OUString aProgId = rAttribs.getXString( XML_progId, OUString() );
+ OUString aTargetUrl = rRelations.getExternalTargetFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) );
+ setDdeOleTargetUrl( aProgId, aTargetUrl, ExternalLinkType::OLE );
+}
+
+ExternalNameRef ExternalLink::importOleItem( const AttributeList& rAttribs )
+{
+ ExternalNameRef xExtName = createExternalName();
+ xExtName->importOleItem( rAttribs );
+ return xExtName;
+}
+
+void ExternalLink::importExternalRef( SequenceInputStream& rStrm )
+{
+ rStrm >> maRelId;
+}
+
+void ExternalLink::importExternalSelf( SequenceInputStream& )
+{
+ meLinkType = ExternalLinkType::Self;
+}
+
+void ExternalLink::importExternalSame( SequenceInputStream& )
+{
+ meLinkType = ExternalLinkType::Same;
+}
+
+void ExternalLink::importExternalAddin( SequenceInputStream& )
+{
+ meLinkType = ExternalLinkType::Unknown;
+}
+
+void ExternalLink::importExternalBook( const Relations& rRelations, SequenceInputStream& rStrm )
+{
+ switch( rStrm.readuInt16() )
+ {
+ case BIFF12_EXTERNALBOOK_BOOK:
+ parseExternalReference( rRelations, BiffHelper::readString( rStrm ) );
+ break;
+ case BIFF12_EXTERNALBOOK_DDE:
+ {
+ OUString aDdeService, aDdeTopic;
+ rStrm >> aDdeService >> aDdeTopic;
+ setDdeOleTargetUrl( aDdeService, aDdeTopic, ExternalLinkType::DDE );
+ }
+ break;
+ case BIFF12_EXTERNALBOOK_OLE:
+ {
+ OUString aTargetUrl = rRelations.getExternalTargetFromRelId( BiffHelper::readString( rStrm ) );
+ OUString aProgId = BiffHelper::readString( rStrm );
+ setDdeOleTargetUrl( aProgId, aTargetUrl, ExternalLinkType::OLE );
+ }
+ break;
+ default:
+ OSL_FAIL( "ExternalLink::importExternalBook - unknown link type" );
+ }
+}
+
+void ExternalLink::importExtSheetNames( SequenceInputStream& rStrm )
+{
+ // load external sheet names and create the sheet caches in the Calc document
+ SAL_WARN_IF( (meLinkType != ExternalLinkType::External) && (meLinkType != ExternalLinkType::Library),
+ "sc.filter",
+ "Invalid link type: " << meLinkType );
+ if( meLinkType == ExternalLinkType::External ) // ignore sheets of external libraries
+ for( sal_Int32 nSheet = 0, nCount = rStrm.readInt32(); !rStrm.isEof() && (nSheet < nCount); ++nSheet )
+ insertExternalSheet( BiffHelper::readString( rStrm ) );
+}
+
+ExternalNameRef ExternalLink::importExternalName( SequenceInputStream& rStrm )
+{
+ ExternalNameRef xExtName = createExternalName();
+ xExtName->importExternalName( rStrm );
+ return xExtName;
+}
+
+ExternalLinkInfo ExternalLink::getLinkInfo() const
+{
+ ExternalLinkInfo aLinkInfo;
+ switch( meLinkType )
+ {
+ case ExternalLinkType::Self:
+ case ExternalLinkType::Same:
+ aLinkInfo.Type = css::sheet::ExternalLinkType::SELF;
+ break;
+ case ExternalLinkType::External:
+ aLinkInfo.Type = css::sheet::ExternalLinkType::DOCUMENT;
+ aLinkInfo.Data <<= maTargetUrl;
+ break;
+ case ExternalLinkType::Library:
+ // parser will return library function names in OPCODE_BAD string tokens
+ aLinkInfo.Type = css::sheet::ExternalLinkType::SPECIAL;
+ break;
+ case ExternalLinkType::DDE:
+ {
+ aLinkInfo.Type = css::sheet::ExternalLinkType::DDE;
+ DDELinkInfo aDdeLinkInfo;
+ aDdeLinkInfo.Service = maClassName;
+ aDdeLinkInfo.Topic = maTargetUrl;
+ ::std::vector< DDEItemInfo > aItemInfos;
+ DDEItemInfo aItemInfo;
+ for( const auto& rxExtName : maExtNames )
+ if( rxExtName->getDdeItemInfo( aItemInfo ) )
+ aItemInfos.push_back( aItemInfo );
+ aDdeLinkInfo.Items = comphelper::containerToSequence( aItemInfos );
+ aLinkInfo.Data <<= aDdeLinkInfo;
+ }
+ break;
+ default:
+ aLinkInfo.Type = css::sheet::ExternalLinkType::UNKNOWN;
+ }
+ return aLinkInfo;
+}
+
+FunctionLibraryType ExternalLink::getFuncLibraryType() const
+{
+ return (meLinkType == ExternalLinkType::Library) ? meFuncLibType : FUNCLIB_UNKNOWN;
+}
+
+sal_Int32 ExternalLink::getDocumentLinkIndex() const
+{
+ OSL_ENSURE( meLinkType == ExternalLinkType::External, "ExternalLink::getDocumentLinkIndex - invalid link type" );
+ return mxDocLink.is() ? mxDocLink->getTokenIndex() : -1;
+}
+
+sal_Int32 ExternalLink::getSheetCacheIndex( sal_Int32 nTabId ) const
+{
+ OSL_ENSURE( meLinkType == ExternalLinkType::External, "ExternalLink::getSheetCacheIndex - invalid link type" );
+ return ContainerHelper::getVectorElement( maSheetCaches, nTabId, -1 );
+}
+
+Reference< XExternalSheetCache > ExternalLink::getSheetCache( sal_Int32 nTabId ) const
+{
+ sal_Int32 nCacheIdx = getSheetCacheIndex( nTabId );
+ if( mxDocLink.is() && (nCacheIdx >= 0) ) try
+ {
+ // existing mxDocLink implies that this is an external link
+ Reference< XExternalSheetCache > xSheetCache( mxDocLink->getByIndex( nCacheIdx ), UNO_QUERY_THROW );
+ return xSheetCache;
+ }
+ catch( Exception& )
+ {
+ }
+ return nullptr;
+}
+
+void ExternalLink::getSheetRange( LinkSheetRange& orSheetRange, sal_Int32 nTabId1, sal_Int32 nTabId2 ) const
+{
+ switch( meLinkType )
+ {
+ case ExternalLinkType::Same:
+ orSheetRange.setSameSheet();
+ break;
+
+ case ExternalLinkType::Self:
+ orSheetRange.setRange( nTabId1, nTabId2 );
+ break;
+
+ case ExternalLinkType::External:
+ {
+ sal_Int32 nDocLinkIdx = getDocumentLinkIndex();
+ // BIFF12: passed indexes point into sheet list of EXTSHEETLIST
+ orSheetRange.setExternalRange( nDocLinkIdx, getSheetCacheIndex( nTabId1 ), getSheetCacheIndex( nTabId2 ) );
+ }
+ break;
+
+ default:
+ // unsupported/unexpected link type: #REF! error
+ orSheetRange.setDeleted();
+ }
+}
+
+ExternalNameRef ExternalLink::getNameByIndex( sal_Int32 nIndex ) const
+{
+ return maExtNames.get( nIndex );
+}
+
+// private --------------------------------------------------------------------
+
+void ExternalLink::setExternalTargetUrl( const OUString& rTargetUrl, const OUString& rTargetType )
+{
+ meLinkType = ExternalLinkType::Unknown;
+ if( rTargetType == CREATE_OFFICEDOC_RELATION_TYPE( "externalLinkPath" ) ||
+ rTargetType == CREATE_OFFICEDOC_RELATION_TYPE_STRICT( "externalLinkPath" ) )
+ {
+ maTargetUrl = getBaseFilter().getAbsoluteUrl( rTargetUrl );
+ if( !maTargetUrl.isEmpty() )
+ meLinkType = ExternalLinkType::External;
+ }
+ else if( rTargetType == CREATE_MSOFFICE_RELATION_TYPE( "xlExternalLinkPath/xlPathMissing" ) )
+ {
+ meLinkType = ExternalLinkType::PathMissing;
+ }
+ else if( rTargetType == CREATE_MSOFFICE_RELATION_TYPE( "xlExternalLinkPath/xlLibrary" ) )
+ {
+ meLinkType = ExternalLinkType::Library;
+ meFuncLibType = FunctionProvider::getFuncLibTypeFromLibraryName( rTargetUrl );
+ }
+ SAL_WARN_IF( meLinkType == ExternalLinkType::Unknown, "sc.filter", "Empty target URL or unknown target type, URL='" << rTargetUrl << "', type='" << rTargetType << "'" );
+
+ // create the external document link API object that will contain the sheet caches
+ if( meLinkType == ExternalLinkType::External ) try
+ {
+ PropertySet aDocProps( getDocument() );
+ Reference< XExternalDocLinks > xDocLinks( aDocProps.getAnyProperty( PROP_ExternalDocLinks ), UNO_QUERY_THROW );
+ mxDocLink = xDocLinks->addDocLink( maTargetUrl );
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+void ExternalLink::setDdeOleTargetUrl( const OUString& rClassName, const OUString& rTargetUrl, ExternalLinkType eLinkType )
+{
+ maClassName = rClassName;
+ maTargetUrl = rTargetUrl;
+ meLinkType = (maClassName.isEmpty() || maTargetUrl.isEmpty()) ? ExternalLinkType::Unknown : eLinkType;
+ OSL_ENSURE( meLinkType == eLinkType, "ExternalLink::setDdeOleTargetUrl - missing classname or target" );
+}
+
+void ExternalLink::parseExternalReference( const Relations& rRelations, const OUString& rRelId )
+{
+ if( const Relation* pRelation = rRelations.getRelationFromRelId( rRelId ) )
+ setExternalTargetUrl( pRelation->maTarget, pRelation->maType );
+}
+
+void ExternalLink::insertExternalSheet( const OUString& rSheetName )
+{
+ OSL_ENSURE( !rSheetName.isEmpty(), "ExternalLink::insertExternalSheet - empty sheet name" );
+ if( mxDocLink.is() )
+ {
+ Reference< XExternalSheetCache > xSheetCache = mxDocLink->addSheetCache( rSheetName, false );
+ sal_Int32 nCacheIdx = xSheetCache.is() ? xSheetCache->getTokenIndex() : -1;
+ maSheetCaches.push_back( nCacheIdx );
+ }
+}
+
+ExternalNameRef ExternalLink::createExternalName()
+{
+ ExternalNameRef xExtName = std::make_shared<ExternalName>( *this );
+ maExtNames.push_back( xExtName );
+ return xExtName;
+}
+
+RefSheetsModel::RefSheetsModel() :
+ mnExtRefId( -1 ),
+ mnTabId1( -1 ),
+ mnTabId2( -1 )
+{
+}
+
+void RefSheetsModel::readBiff12Data( SequenceInputStream& rStrm )
+{
+ mnExtRefId = rStrm.readInt32();
+ mnTabId1 = rStrm.readInt32();
+ mnTabId2 = rStrm.readInt32();
+}
+
+ExternalLinkBuffer::ExternalLinkBuffer( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ mxSelfRef( std::make_shared<ExternalLink>( rHelper ) ),
+ mbUseRefSheets( false )
+{
+ mxSelfRef->setSelfLinkType();
+}
+
+ExternalLinkRef ExternalLinkBuffer::importExternalReference( const AttributeList& rAttribs )
+{
+ ExternalLinkRef xExtLink = createExternalLink();
+ xExtLink->importExternalReference( rAttribs );
+ maExtLinks.push_back( xExtLink );
+ return xExtLink;
+}
+
+ExternalLinkRef ExternalLinkBuffer::importExternalRef( SequenceInputStream& rStrm )
+{
+ mbUseRefSheets = true;
+ ExternalLinkRef xExtLink = createExternalLink();
+ xExtLink->importExternalRef( rStrm );
+ maExtLinks.push_back( xExtLink );
+ return xExtLink;
+}
+
+void ExternalLinkBuffer::importExternalSelf( SequenceInputStream& rStrm )
+{
+ mbUseRefSheets = true;
+ createExternalLink()->importExternalSelf( rStrm );
+}
+
+void ExternalLinkBuffer::importExternalSame( SequenceInputStream& rStrm )
+{
+ mbUseRefSheets = true;
+ createExternalLink()->importExternalSame( rStrm );
+}
+
+void ExternalLinkBuffer::importExternalAddin( SequenceInputStream& rStrm )
+{
+ mbUseRefSheets = true;
+ createExternalLink()->importExternalAddin( rStrm );
+}
+
+void ExternalLinkBuffer::importExternalSheets( SequenceInputStream& rStrm )
+{
+ OSL_ENSURE( mbUseRefSheets, "ExternalLinkBuffer::importExternalSheets - missing EXTERNALREFS records" );
+ mbUseRefSheets = true;
+ OSL_ENSURE( maRefSheets.empty(), "ExternalLinkBuffer::importExternalSheets - multiple EXTERNALSHEETS records" );
+ maRefSheets.clear();
+ sal_Int32 nRefCount;
+ nRefCount = rStrm.readInt32();
+ size_t nMaxCount = getLimitedValue< size_t, sal_Int64 >( nRefCount, 0, rStrm.getRemaining() / 12 );
+ maRefSheets.reserve( nMaxCount );
+ for( size_t nRefId = 0; !rStrm.isEof() && (nRefId < nMaxCount); ++nRefId )
+ {
+ RefSheetsModel aRefSheets;
+ aRefSheets.readBiff12Data( rStrm );
+ maRefSheets.push_back( aRefSheets );
+ }
+}
+
+Sequence< ExternalLinkInfo > ExternalLinkBuffer::getLinkInfos() const
+{
+ ::std::vector< ExternalLinkInfo > aLinkInfos;
+ // add entry for implicit index 0 (self reference to this document)
+ aLinkInfos.push_back( mxSelfRef->getLinkInfo() );
+ for( const auto& rxExtLink : maExtLinks )
+ aLinkInfos.push_back( rxExtLink->getLinkInfo() );
+ return comphelper::containerToSequence( aLinkInfos );
+}
+
+ExternalLinkRef ExternalLinkBuffer::getExternalLink( sal_Int32 nRefId, bool bUseRefSheets ) const
+{
+ ExternalLinkRef xExtLink;
+ // OOXML: 0 = this document, otherwise one-based index into link list
+ if( !bUseRefSheets || !mbUseRefSheets )
+ xExtLink = (nRefId == 0) ? mxSelfRef : maLinks.get( nRefId - 1 );
+ // BIFF12: zero-based index into ref-sheets list
+ else if( const RefSheetsModel* pRefSheets = getRefSheets( nRefId ) )
+ xExtLink = maLinks.get( pRefSheets->mnExtRefId );
+ return xExtLink;
+}
+
+LinkSheetRange ExternalLinkBuffer::getSheetRange( sal_Int32 nRefId ) const
+{
+ OSL_ENSURE( mbUseRefSheets, "ExternalLinkBuffer::getSheetRange - wrong BIFF version" );
+ LinkSheetRange aSheetRange;
+ if( const ExternalLink* pExtLink = getExternalLink( nRefId ).get() )
+ if( const RefSheetsModel* pRefSheets = getRefSheets( nRefId ) )
+ pExtLink->getSheetRange( aSheetRange, pRefSheets->mnTabId1, pRefSheets->mnTabId2 );
+ return aSheetRange;
+}
+
+// private --------------------------------------------------------------------
+
+ExternalLinkRef ExternalLinkBuffer::createExternalLink()
+{
+ ExternalLinkRef xExtLink = std::make_shared<ExternalLink>( *this );
+ maLinks.push_back( xExtLink );
+ return xExtLink;
+}
+
+const RefSheetsModel* ExternalLinkBuffer::getRefSheets( sal_Int32 nRefId ) const
+{
+ return ((0 <= nRefId) && (o3tl::make_unsigned( nRefId ) < maRefSheets.size())) ?
+ &maRefSheets[ static_cast< size_t >( nRefId ) ] : nullptr;
+}
+
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */