Kaydet (Commit) 0a5ca576 authored tarafından Michael Stahl's avatar Michael Stahl Kaydeden (comit) Samuel Mehrbrodt

tdf#123293 sfx2: fix metadata loss when loading from stream

The problem is that when loading from a stream, there is no BaseURL and
also no storage for the document.

Due to the lack of BaseURL, the sfx2::createBaseURI() throws and loading
RDF metadata fails, which also pops up an annoying warning dialog.

Try to handle this in a similar way than a newly created document (see
GetDMA()), by using the vnd.sun.star.tdoc scheme URL for the document;
this however currently requires that the document has a XStorage, which
is also not the case here.

So add another UNO method to tdoc UCP's tdoc_ucp::ContentProvider,
to split out the creation of the tdoc schema URL from the creation of
the ucb Content, to get rid of the XStorage requirement.

Change-Id: Ica62743f9d21db0b1464b70db1a62ebc61989ef8
Reviewed-on: https://gerrit.libreoffice.org/67882
Tested-by: Jenkins
Reviewed-by: 's avatarSamuel Mehrbrodt <Samuel.Mehrbrodt@cib.de>
üst b95fa852
...@@ -44,6 +44,9 @@ ...@@ -44,6 +44,9 @@
namespace com { namespace sun { namespace star { namespace embed { namespace com { namespace sun { namespace star { namespace embed {
class XStorage; class XStorage;
} } } } } } } }
namespace com { namespace sun { namespace star { namespace frame {
class XModel;
} } } }
class SfxObjectShell; class SfxObjectShell;
namespace sfx2 { namespace sfx2 {
...@@ -52,7 +55,7 @@ namespace sfx2 { ...@@ -52,7 +55,7 @@ namespace sfx2 {
/** create a base URI for loading metadata from an ODF (sub)document. /** create a base URI for loading metadata from an ODF (sub)document.
@param i_xContext component context @param i_xContext component context
@param i_xStorage storage for the document; FileSystemStorage is allowed @param i_xModel model of the document (required if no URI is provided)
@param i_rPkgURI the URI for the package @param i_rPkgURI the URI for the package
@param i_rSubDocument (optional) path of the subdocument in package @param i_rSubDocument (optional) path of the subdocument in package
...@@ -60,8 +63,8 @@ namespace sfx2 { ...@@ -60,8 +63,8 @@ namespace sfx2 {
*/ */
css::uno::Reference< css::rdf::XURI> SFX2_DLLPUBLIC css::uno::Reference< css::rdf::XURI> SFX2_DLLPUBLIC
createBaseURI( createBaseURI(
css::uno::Reference< css::uno::XComponentContext> const & i_xContext, css::uno::Reference<css::uno::XComponentContext> const & i_xContext,
css::uno::Reference< css::embed::XStorage> const & i_xStorage, css::uno::Reference<css::frame::XModel> const & i_xModel,
OUString const & i_rPkgURI, OUString const & i_rPkgURI,
OUString const & i_rSubDocument = OUString()); OUString const & i_rSubDocument = OUString());
......
...@@ -2656,6 +2656,7 @@ $(eval $(call gb_UnoApi_add_idlfiles,offapi,com/sun/star/frame,\ ...@@ -2656,6 +2656,7 @@ $(eval $(call gb_UnoApi_add_idlfiles,offapi,com/sun/star/frame,\
XToolbarController \ XToolbarController \
XToolbarControllerListener \ XToolbarControllerListener \
XTransientDocumentsDocumentContentFactory \ XTransientDocumentsDocumentContentFactory \
XTransientDocumentsDocumentContentIdentifierFactory \
XUIControllerFactory \ XUIControllerFactory \
XUIControllerRegistration \ XUIControllerRegistration \
XUntitledNumbers \ XUntitledNumbers \
......
/* -*- 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/.
*
*/
#ifndef __com_sun_star_frame_XTransientDocumentsDocumentContentIdentifierFactory_idl__
#define __com_sun_star_frame_XTransientDocumentsDocumentContentIdentifierFactory_idl__
#include <com/sun/star/uno/XInterface.idl>
#include <com/sun/star/ucb/XContentIdentifier.idl>
#include <com/sun/star/frame/XModel.idl>
#include <com/sun/star/lang/IllegalArgumentException.idl>
module com { module sun { module star { module frame {
/** a factory for identifiers of
com::sun::star::ucb::TransientDocumentsDocumentContents.
@see com::sun::star::document::OfficeDocument
@see com::sun::star::ucb::XContentIdentifier
@since LibreOffice 6.3
*/
interface XTransientDocumentsDocumentContentIdentifierFactory
: com::sun::star::uno::XInterface
{
/** creates a com::sun::star::ucb::XContentIdentifier
based on a given com::sun::star::document::OfficeDocument.
@param Model
the document model for which a
com::sun::star::ucb::XContentIdentifier
is requested. The model must be an implementation of service
com::sun::star::document::OfficeDocument.
@returns
a content identifier based on the given document model.
@throws com::sun::star::lang::IllegalArgumentException
if the document model cannot be associated with content for any reason.
*/
com::sun::star::ucb::XContentIdentifier
createDocumentContentIdentifier(
[in] com::sun::star::frame::XModel Model )
raises ( com::sun::star::lang::IllegalArgumentException );
};
}; }; }; };
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <sfx2/sfxsids.hrc> #include <sfx2/sfxsids.hrc>
#include <com/sun/star/container/XChild.hpp> #include <com/sun/star/container/XChild.hpp>
#include <com/sun/star/beans/XPropertySetInfo.hpp> #include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/frame/XTransientDocumentsDocumentContentFactory.hpp>
#include <com/sun/star/xml/sax/InputSource.hpp> #include <com/sun/star/xml/sax/InputSource.hpp>
#include <com/sun/star/xml/sax/Parser.hpp> #include <com/sun/star/xml/sax/Parser.hpp>
#include <com/sun/star/xml/sax/XFastParser.hpp> #include <com/sun/star/xml/sax/XFastParser.hpp>
...@@ -74,6 +75,7 @@ ...@@ -74,6 +75,7 @@
#include <unonames.hxx> #include <unonames.hxx>
using namespace com::sun::star; using namespace com::sun::star;
using namespace css::uno;
ScXMLImportWrapper::ScXMLImportWrapper( ScDocShell& rDocSh, SfxMedium* pM, const uno::Reference < embed::XStorage >& xStor ) : ScXMLImportWrapper::ScXMLImportWrapper( ScDocShell& rDocSh, SfxMedium* pM, const uno::Reference < embed::XStorage >& xStor ) :
mrDocShell(rDocSh), mrDocShell(rDocSh),
...@@ -393,7 +395,7 @@ bool ScXMLImportWrapper::Import( ImportFlags nMode, ErrCode& rError ) ...@@ -393,7 +395,7 @@ bool ScXMLImportWrapper::Import( ImportFlags nMode, ErrCode& rError )
const uno::Reference< rdf::XDocumentMetadataAccess > xDMA( const uno::Reference< rdf::XDocumentMetadataAccess > xDMA(
xModel, uno::UNO_QUERY_THROW ); xModel, uno::UNO_QUERY_THROW );
const uno::Reference< rdf::XURI > xBaseURI( const uno::Reference< rdf::XURI > xBaseURI(
::sfx2::createBaseURI( xContext, xStorage, aBaseURL, aName ) ); ::sfx2::createBaseURI( xContext, xModel, aBaseURL, aName ) );
uno::Reference<task::XInteractionHandler> xHandler = uno::Reference<task::XInteractionHandler> xHandler =
mrDocShell.GetMedium()->GetInteractionHandler(); mrDocShell.GetMedium()->GetInteractionHandler();
xDMA->loadMetadataFromStorage( xStorage, xBaseURI, xHandler ); xDMA->loadMetadataFromStorage( xStorage, xBaseURI, xHandler );
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <com/sun/star/embed/ElementModes.hpp> #include <com/sun/star/embed/ElementModes.hpp>
#include <com/sun/star/embed/XStorage.hpp> #include <com/sun/star/embed/XStorage.hpp>
#include <com/sun/star/embed/XTransactedObject.hpp> #include <com/sun/star/embed/XTransactedObject.hpp>
#include <com/sun/star/frame/XTransientDocumentsDocumentContentIdentifierFactory.hpp>
#include <com/sun/star/task/ErrorCodeIOException.hpp> #include <com/sun/star/task/ErrorCodeIOException.hpp>
#include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp> #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
#include <com/sun/star/rdf/FileFormat.hpp> #include <com/sun/star/rdf/FileFormat.hpp>
...@@ -116,16 +117,44 @@ static bool isReservedFile(OUString const & i_rPath) ...@@ -116,16 +117,44 @@ static bool isReservedFile(OUString const & i_rPath)
uno::Reference<rdf::XURI> createBaseURI( uno::Reference<rdf::XURI> createBaseURI(
uno::Reference<uno::XComponentContext> const & i_xContext, uno::Reference<uno::XComponentContext> const & i_xContext,
uno::Reference<embed::XStorage> const & i_xStorage, uno::Reference<frame::XModel> const & i_xModel,
OUString const & i_rPkgURI, OUString const & i_rSubDocument) OUString const & i_rPkgURI, OUString const & i_rSubDocument)
{ {
if (!i_xContext.is() || !i_xStorage.is() || i_rPkgURI.isEmpty()) { if (!i_xContext.is() || (!i_xModel.is() && i_rPkgURI.isEmpty())) {
throw uno::RuntimeException(); throw uno::RuntimeException();
} }
OUString pkgURI(i_rPkgURI);
// tdf#123293 chicken/egg problem when loading from stream: there is no URI,
// and also the model doesn't have a storage yet, so we need to get the
// tdoc URI without a storage...
if (pkgURI.isEmpty())
{
assert(i_xModel.is());
uno::Reference<frame::XTransientDocumentsDocumentContentIdentifierFactory>
const xTDDCIF(
i_xContext->getServiceManager()->createInstanceWithContext(
"com.sun.star.ucb.TransientDocumentsContentProvider",
i_xContext),
uno::UNO_QUERY_THROW);
uno::Reference<ucb::XContentIdentifier> const xContentId(
xTDDCIF->createDocumentContentIdentifier(i_xModel));
SAL_WARN_IF(!xContentId.is(), "sfx", "createBaseURI: cannot create ContentIdentifier");
if (!xContentId.is())
{
throw uno::RuntimeException("createBaseURI: cannot create ContentIdentifier");
}
pkgURI = xContentId->getContentIdentifier();
assert(!pkgURI.isEmpty());
if (!pkgURI.isEmpty() && !pkgURI.endsWith("/"))
{
pkgURI = pkgURI + "/";
}
}
// #i108078# workaround non-hierarchical vnd.sun.star.expand URIs // #i108078# workaround non-hierarchical vnd.sun.star.expand URIs
// this really should be done somewhere else, not here. // this really should be done somewhere else, not here.
OUString pkgURI(i_rPkgURI);
if (pkgURI.matchIgnoreAsciiCase("vnd.sun.star.expand:")) if (pkgURI.matchIgnoreAsciiCase("vnd.sun.star.expand:"))
{ {
// expand it here (makeAbsolute requires hierarchical URI) // expand it here (makeAbsolute requires hierarchical URI)
...@@ -1283,11 +1312,11 @@ DocumentMetadataAccess::loadMetadataFromMedium( ...@@ -1283,11 +1312,11 @@ DocumentMetadataAccess::loadMetadataFromMedium(
} }
uno::Reference<rdf::XURI> xBaseURI; uno::Reference<rdf::XURI> xBaseURI;
try { try {
xBaseURI = createBaseURI(m_pImpl->m_xContext, xStorage, BaseURL); xBaseURI = createBaseURI(m_pImpl->m_xContext, nullptr, BaseURL);
} catch (const uno::Exception &) { } catch (const uno::Exception &) {
// fall back to URL // fall back to URL
try { try {
xBaseURI = createBaseURI(m_pImpl->m_xContext, xStorage, URL); xBaseURI = createBaseURI(m_pImpl->m_xContext, nullptr, URL);
} catch (const uno::Exception &) { } catch (const uno::Exception &) {
OSL_FAIL("cannot create base URI"); OSL_FAIL("cannot create base URI");
} }
......
...@@ -4921,10 +4921,11 @@ ErrCode SwWW8ImplReader::CoreLoad(WW8Glossary const *pGloss) ...@@ -4921,10 +4921,11 @@ ErrCode SwWW8ImplReader::CoreLoad(WW8Glossary const *pGloss)
// Initialize RDF metadata, to be able to add statements during the import. // Initialize RDF metadata, to be able to add statements during the import.
try try
{ {
uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(m_rDoc.GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW); uno::Reference<frame::XModel> const xModel(m_rDoc.GetDocShell()->GetBaseModel());
uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, uno::UNO_QUERY_THROW);
uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext()); uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext());
uno::Reference<embed::XStorage> xStorage = comphelper::OStorageHelper::GetTemporaryStorage(); uno::Reference<embed::XStorage> xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
const uno::Reference<rdf::XURI> xBaseURI(sfx2::createBaseURI(xComponentContext, xStorage, m_sBaseURL)); const uno::Reference<rdf::XURI> xBaseURI(sfx2::createBaseURI(xComponentContext, xModel, m_sBaseURL));
uno::Reference<task::XInteractionHandler> xHandler; uno::Reference<task::XInteractionHandler> xHandler;
xDocumentMetadataAccess->loadMetadataFromStorage(xStorage, xBaseURI, xHandler); xDocumentMetadataAccess->loadMetadataFromStorage(xStorage, xBaseURI, xHandler);
} }
......
...@@ -796,8 +796,10 @@ ErrCode XMLReader::Read( SwDoc &rDoc, const OUString& rBaseURL, SwPaM &rPaM, con ...@@ -796,8 +796,10 @@ ErrCode XMLReader::Read( SwDoc &rDoc, const OUString& rBaseURL, SwPaM &rPaM, con
{ {
const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(xModelComp, const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(xModelComp,
uno::UNO_QUERY_THROW); uno::UNO_QUERY_THROW);
const uno::Reference<frame::XModel> xModel(xModelComp,
uno::UNO_QUERY_THROW);
const uno::Reference<rdf::XURI> xBaseURI( ::sfx2::createBaseURI( const uno::Reference<rdf::XURI> xBaseURI( ::sfx2::createBaseURI(
xContext, xStorage, rBaseURL, StreamPath) ); xContext, xModel, rBaseURL, StreamPath) );
const uno::Reference<task::XInteractionHandler> xHandler( const uno::Reference<task::XInteractionHandler> xHandler(
pDocSh->GetMedium()->GetInteractionHandler() ); pDocSh->GetMedium()->GetInteractionHandler() );
xDMA->loadMetadataFromStorage(xStorage, xBaseURI, xHandler); xDMA->loadMetadataFromStorage(xStorage, xBaseURI, xHandler);
......
...@@ -88,6 +88,7 @@ css::uno::Any SAL_CALL ContentProvider::queryInterface( const css::uno::Type & r ...@@ -88,6 +88,7 @@ css::uno::Any SAL_CALL ContentProvider::queryInterface( const css::uno::Type & r
static_cast< lang::XTypeProvider* >(this), static_cast< lang::XTypeProvider* >(this),
static_cast< lang::XServiceInfo* >(this), static_cast< lang::XServiceInfo* >(this),
static_cast< ucb::XContentProvider* >(this), static_cast< ucb::XContentProvider* >(this),
static_cast< frame::XTransientDocumentsDocumentContentIdentifierFactory* >(this),
static_cast< frame::XTransientDocumentsDocumentContentFactory* >(this) static_cast< frame::XTransientDocumentsDocumentContentFactory* >(this)
); );
return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
...@@ -96,10 +97,11 @@ css::uno::Any SAL_CALL ContentProvider::queryInterface( const css::uno::Type & r ...@@ -96,10 +97,11 @@ css::uno::Any SAL_CALL ContentProvider::queryInterface( const css::uno::Type & r
// XTypeProvider methods. // XTypeProvider methods.
XTYPEPROVIDER_IMPL_4( ContentProvider, XTYPEPROVIDER_IMPL_5( ContentProvider,
lang::XTypeProvider, lang::XTypeProvider,
lang::XServiceInfo, lang::XServiceInfo,
ucb::XContentProvider, ucb::XContentProvider,
frame::XTransientDocumentsDocumentContentIdentifierFactory,
frame::XTransientDocumentsDocumentContentFactory ); frame::XTransientDocumentsDocumentContentFactory );
...@@ -164,13 +166,11 @@ ContentProvider::queryContent( ...@@ -164,13 +166,11 @@ ContentProvider::queryContent(
} }
// XTransientDocumentsDocumentContentFactory methods. // XTransientDocumentsDocumentContentIdentifierFactory methods.
// virtual uno::Reference<ucb::XContentIdentifier> SAL_CALL
uno::Reference< ucb::XContent > SAL_CALL ContentProvider::createDocumentContentIdentifier(
ContentProvider::createDocumentContent( uno::Reference<frame::XModel> const& xModel)
const uno::Reference< frame::XModel >& Model )
{ {
// model -> id -> content identifier -> queryContent // model -> id -> content identifier -> queryContent
if ( !m_xDocsMgr.is() ) if ( !m_xDocsMgr.is() )
...@@ -181,7 +181,7 @@ ContentProvider::createDocumentContent( ...@@ -181,7 +181,7 @@ ContentProvider::createDocumentContent(
1 ); 1 );
} }
OUString aDocId = tdoc_ucp::OfficeDocumentsManager::queryDocumentId( Model ); OUString aDocId = tdoc_ucp::OfficeDocumentsManager::queryDocumentId(xModel);
if ( aDocId.isEmpty() ) if ( aDocId.isEmpty() )
{ {
throw lang::IllegalArgumentException( throw lang::IllegalArgumentException(
...@@ -196,6 +196,17 @@ ContentProvider::createDocumentContent( ...@@ -196,6 +196,17 @@ ContentProvider::createDocumentContent(
uno::Reference< ucb::XContentIdentifier > xId uno::Reference< ucb::XContentIdentifier > xId
= new ::ucbhelper::ContentIdentifier( aBuffer.makeStringAndClear() ); = new ::ucbhelper::ContentIdentifier( aBuffer.makeStringAndClear() );
return xId;
}
// XTransientDocumentsDocumentContentFactory methods.
uno::Reference< ucb::XContent > SAL_CALL
ContentProvider::createDocumentContent(
uno::Reference<frame::XModel> const& xModel)
{
uno::Reference<ucb::XContentIdentifier> const xId(
createDocumentContentIdentifier(xModel));
osl::MutexGuard aGuard( m_aMutex ); osl::MutexGuard aGuard( m_aMutex );
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <rtl/ref.hxx> #include <rtl/ref.hxx>
#include <com/sun/star/frame/XTransientDocumentsDocumentContentFactory.hpp> #include <com/sun/star/frame/XTransientDocumentsDocumentContentFactory.hpp>
#include <com/sun/star/frame/XTransientDocumentsDocumentContentIdentifierFactory.hpp>
#include <com/sun/star/packages/WrongPasswordException.hpp> #include <com/sun/star/packages/WrongPasswordException.hpp>
#include <com/sun/star/lang/XSingleServiceFactory.hpp> #include <com/sun/star/lang/XSingleServiceFactory.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp> #include <com/sun/star/lang/XMultiServiceFactory.hpp>
...@@ -53,9 +54,10 @@ namespace tdoc_ucp { ...@@ -53,9 +54,10 @@ namespace tdoc_ucp {
class StorageElementFactory; class StorageElementFactory;
class ContentProvider : class ContentProvider
public ::ucbhelper::ContentProviderImplHelper, : public ::ucbhelper::ContentProviderImplHelper
public css::frame::XTransientDocumentsDocumentContentFactory , public css::frame::XTransientDocumentsDocumentContentIdentifierFactory
, public css::frame::XTransientDocumentsDocumentContentFactory
{ {
public: public:
explicit ContentProvider( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); explicit ContentProvider( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
...@@ -88,6 +90,11 @@ public: ...@@ -88,6 +90,11 @@ public:
virtual css::uno::Reference< css::ucb::XContent > SAL_CALL virtual css::uno::Reference< css::ucb::XContent > SAL_CALL
queryContent( const css::uno::Reference< css::ucb::XContentIdentifier >& Identifier ) override; queryContent( const css::uno::Reference< css::ucb::XContentIdentifier >& Identifier ) override;
// XTransientDocumentsDocumentContentIdentifierFactory
virtual css::uno::Reference<css::ucb::XContentIdentifier> SAL_CALL
createDocumentContentIdentifier(
css::uno::Reference<css::frame::XModel> const& xModel) override;
// XTransientDocumentsDocumentContentFactory // XTransientDocumentsDocumentContentFactory
virtual css::uno::Reference< css::ucb::XContent > SAL_CALL virtual css::uno::Reference< css::ucb::XContent > SAL_CALL
createDocumentContent( const css::uno::Reference< createDocumentContent( const css::uno::Reference<
......
...@@ -128,7 +128,9 @@ DomainMapper::DomainMapper( const uno::Reference< uno::XComponentContext >& xCon ...@@ -128,7 +128,9 @@ DomainMapper::DomainMapper( const uno::Reference< uno::XComponentContext >& xCon
uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, uno::UNO_QUERY_THROW); uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, uno::UNO_QUERY_THROW);
uno::Reference<embed::XStorage> xStorage = comphelper::OStorageHelper::GetTemporaryStorage(); uno::Reference<embed::XStorage> xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
OUString aBaseURL = rMediaDesc.getUnpackedValueOrDefault("URL", OUString()); OUString aBaseURL = rMediaDesc.getUnpackedValueOrDefault("URL", OUString());
const uno::Reference<rdf::XURI> xBaseURI(sfx2::createBaseURI(xContext, xStorage, aBaseURL, OUString())); const uno::Reference<frame::XModel> xModel_(xModel,
uno::UNO_QUERY_THROW);
const uno::Reference<rdf::XURI> xBaseURI(sfx2::createBaseURI(xContext, xModel_, aBaseURL, OUString()));
const uno::Reference<task::XInteractionHandler> xHandler; const uno::Reference<task::XInteractionHandler> xHandler;
xDocumentMetadataAccess->loadMetadataFromStorage(xStorage, xBaseURI, xHandler); xDocumentMetadataAccess->loadMetadataFromStorage(xStorage, xBaseURI, xHandler);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment