diff options
Diffstat (limited to 'sc/source/filter/oox/externallinkbuffer.cxx')
-rw-r--r-- | sc/source/filter/oox/externallinkbuffer.cxx | 694 |
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: */ |