/* -*- 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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
N.B.: must not be called before DMA is fully initalized!
@returns true iff caller should retry
*/
static bool
handleError( ucb::InteractiveAugmentedIOException const & i_rException,
const uno::Reference & i_xHandler)
{
if (!i_xHandler.is()) {
throw lang::WrappedTargetException(
"DocumentMetadataAccess::loadMetadataFromStorage: exception",
/* *this*/ nullptr, uno::makeAny(i_rException));
}
::rtl::Reference< ::comphelper::OInteractionRequest > pRequest(
new ::comphelper::OInteractionRequest(uno::makeAny(i_rException)) );
::rtl::Reference< ::comphelper::OInteractionRetry > pRetry(
new ::comphelper::OInteractionRetry );
::rtl::Reference< ::comphelper::OInteractionApprove > pApprove(
new ::comphelper::OInteractionApprove );
::rtl::Reference< ::comphelper::OInteractionAbort > pAbort(
new ::comphelper::OInteractionAbort );
pRequest->addContinuation( pApprove.get() );
pRequest->addContinuation( pAbort.get() );
// actually call the handler
i_xHandler->handle( pRequest.get() );
if (pRetry->wasSelected()) {
return true;
} else if (pApprove->wasSelected()) {
return false;
} else {
OSL_ENSURE(pAbort->wasSelected(), "no continuation selected?");
throw lang::WrappedTargetException(
"DocumentMetadataAccess::loadMetadataFromStorage: exception",
/* *this*/ nullptr, uno::makeAny(i_rException));
}
}
/** check if storage has content.xml/styles.xml;
e.g. ODB files seem to only have content.xml */
static void
collectFilesFromStorage(uno::Reference const& i_xStorage,
const OUString& i_Path,
std::set< OUString > & o_rFiles)
{
static OUString content(s_content);
static OUString styles(s_styles );
try {
if (i_xStorage->hasByName(content) &&
i_xStorage->isStreamElement(content))
{
o_rFiles.insert(i_Path + content);
}
if (i_xStorage->hasByName(styles) &&
i_xStorage->isStreamElement(styles))
{
o_rFiles.insert(i_Path + styles);
}
} catch (const uno::Exception &) {
OSL_TRACE("collectFilesFromStorage: exception?");
}
}
/** import a metadata file into repository */
static void
readStream(struct DocumentMetadataAccess_Impl & i_rImpl,
uno::Reference< embed::XStorage > const & i_xStorage,
OUString const & i_rPath,
OUString const & i_rBaseURI)
{
OUString dir;
OUString rest;
try {
if (!splitPath(i_rPath, dir, rest)) throw uno::RuntimeException();
if (dir.isEmpty()) {
if (i_xStorage->isStreamElement(i_rPath)) {
const uno::Reference xStream(
i_xStorage->openStreamElement(i_rPath,
embed::ElementModes::READ), uno::UNO_SET_THROW);
const uno::Reference xInStream(
xStream->getInputStream(), uno::UNO_SET_THROW );
const uno::Reference xBaseURI(
rdf::URI::create(i_rImpl.m_xContext, i_rBaseURI));
const uno::Reference xURI(
rdf::URI::createNS(i_rImpl.m_xContext,
i_rBaseURI, i_rPath));
i_rImpl.m_xRepository->importGraph(rdf::FileFormat::RDF_XML,
xInStream, xURI, xBaseURI);
} else {
throw mkException(
"readStream: is not a stream",
ucb::IOErrorCode_NO_FILE, i_rBaseURI + i_rPath, i_rPath);
}
} else {
if (i_xStorage->isStorageElement(dir)) {
const uno::Reference xDir(
i_xStorage->openStorageElement(dir,
embed::ElementModes::READ));
const uno::Reference< beans::XPropertySet > xDirProps(xDir,
uno::UNO_QUERY_THROW);
try {
OUString mimeType;
xDirProps->getPropertyValue(
utl::MediaDescriptor::PROP_MEDIATYPE() )
>>= mimeType;
if (mimeType.startsWith(s_odfmime)) {
OSL_TRACE("readStream: "
"refusing to recurse into embedded document");
return;
}
} catch (const uno::Exception &) { }
OUStringBuffer buf(i_rBaseURI);
buf.append(dir).append('/');
readStream(i_rImpl, xDir, rest, buf.makeStringAndClear() );
} else {
throw mkException(
"readStream: is not a directory",
ucb::IOErrorCode_NO_DIRECTORY, i_rBaseURI + dir, dir);
}
}
} catch (const container::NoSuchElementException & e) {
throw mkException(e.Message, ucb::IOErrorCode_NOT_EXISTING_PATH,
i_rBaseURI + i_rPath, i_rPath);
} catch (const io::IOException & e) {
throw mkException(e.Message, ucb::IOErrorCode_CANT_READ,
i_rBaseURI + i_rPath, i_rPath);
} catch (const rdf::ParseException & e) {
throw mkException(e.Message, ucb::IOErrorCode_WRONG_FORMAT,
i_rBaseURI + i_rPath, i_rPath);
}
}
/** import a metadata file into repository */
static void
importFile(struct DocumentMetadataAccess_Impl & i_rImpl,
uno::Reference const & i_xStorage,
OUString const & i_rBaseURI,
uno::Reference const & i_xHandler,
const OUString& i_rPath)
{
retry:
try {
readStream(i_rImpl, i_xStorage, i_rPath, i_rBaseURI);
} catch (const ucb::InteractiveAugmentedIOException & e) {
if (handleError(e, i_xHandler)) goto retry;
} catch (const uno::RuntimeException &) {
throw;
} catch (const uno::Exception & e) {
throw lang::WrappedTargetRuntimeException(
"importFile: exception",
nullptr, uno::makeAny(e));
}
}
/** actually write a metadata file to the storage */
static void
exportStream(struct DocumentMetadataAccess_Impl & i_rImpl,
uno::Reference< embed::XStorage > const & i_xStorage,
uno::Reference const & i_xGraphName,
OUString const & i_rFileName,
OUString const & i_rBaseURI)
{
const uno::Reference xStream(
i_xStorage->openStreamElement(i_rFileName,
embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE),
uno::UNO_SET_THROW);
const uno::Reference< beans::XPropertySet > xStreamProps(xStream,
uno::UNO_QUERY);
if (xStreamProps.is()) { // this is NOT supported in FileSystemStorage
xStreamProps->setPropertyValue(
"MediaType",
uno::makeAny(OUString(s_rdfxml)));
}
const uno::Reference xOutStream(
xStream->getOutputStream(), uno::UNO_SET_THROW );
const uno::Reference xBaseURI(
rdf::URI::create(i_rImpl.m_xContext, i_rBaseURI));
i_rImpl.m_xRepository->exportGraph(rdf::FileFormat::RDF_XML,
xOutStream, i_xGraphName, xBaseURI);
}
/** write a metadata file to the storage */
static void
writeStream(struct DocumentMetadataAccess_Impl & i_rImpl,
uno::Reference< embed::XStorage > const & i_xStorage,
uno::Reference const & i_xGraphName,
OUString const & i_rPath,
OUString const & i_rBaseURI)
{
OUString dir;
OUString rest;
if (!splitPath(i_rPath, dir, rest)) throw uno::RuntimeException();
try {
if (dir.isEmpty()) {
exportStream(i_rImpl, i_xStorage, i_xGraphName, i_rPath,
i_rBaseURI);
} else {
const uno::Reference xDir(
i_xStorage->openStorageElement(dir,
embed::ElementModes::WRITE));
const uno::Reference< beans::XPropertySet > xDirProps(xDir,
uno::UNO_QUERY_THROW);
try {
OUString mimeType;
xDirProps->getPropertyValue(
utl::MediaDescriptor::PROP_MEDIATYPE() )
>>= mimeType;
if (mimeType.startsWith(s_odfmime)) {
OSL_TRACE("writeStream: "
"refusing to recurse into embedded document");
return;
}
} catch (const uno::Exception &) { }
OUStringBuffer buf(i_rBaseURI);
buf.append(dir).append('/');
writeStream(i_rImpl, xDir, i_xGraphName, rest,
buf.makeStringAndClear());
uno::Reference const xTransaction(
xDir, uno::UNO_QUERY);
if (xTransaction.is()) {
xTransaction->commit();
}
}
} catch (const uno::RuntimeException &) {
throw;
} catch (const io::IOException &) {
throw;
}
}
static void
initLoading(struct DocumentMetadataAccess_Impl & i_rImpl,
const uno::Reference< embed::XStorage > & i_xStorage,
const uno::Reference & i_xBaseURI,
const uno::Reference & i_xHandler)
{
retry:
// clear old data
i_rImpl.m_xManifest.clear();
// init BaseURI
i_rImpl.m_xBaseURI = i_xBaseURI;
// create repository
i_rImpl.m_xRepository.clear();
i_rImpl.m_xRepository.set(rdf::Repository::create(i_rImpl.m_xContext),
uno::UNO_SET_THROW);
const OUString baseURI( i_xBaseURI->getStringValue() );
// try to delay raising errors until after initialization is done
uno::Any rterr;
ucb::InteractiveAugmentedIOException iaioe;
bool err(false);
const uno::Reference xManifest(
getURIForStream(i_rImpl, s_manifest));
try {
readStream(i_rImpl, i_xStorage, s_manifest, baseURI);
} catch (const ucb::InteractiveAugmentedIOException & e) {
// no manifest.rdf: this is not an error in ODF < 1.2
if (!(ucb::IOErrorCode_NOT_EXISTING_PATH == e.Code)) {
iaioe = e;
err = true;
}
} catch (const uno::Exception & e) {
rterr <<= e;
}
// init manifest graph
const uno::Reference xManifestGraph(
i_rImpl.m_xRepository->getGraph(xManifest));
i_rImpl.m_xManifest.set(xManifestGraph.is() ? xManifestGraph :
i_rImpl.m_xRepository->createGraph(xManifest), uno::UNO_SET_THROW);
const uno::Reference xEnum(
i_rImpl.m_xManifest->getStatements(nullptr,
getURI(i_rImpl.m_xContext),
getURI(i_rImpl.m_xContext).get()));
// document statement
i_rImpl.m_xManifest->addStatement(i_rImpl.m_xBaseURI.get(),
getURI(i_rImpl.m_xContext),
getURI(i_rImpl.m_xContext).get());
OSL_ENSURE(i_rImpl.m_xBaseURI.is(), "base URI is null");
OSL_ENSURE(i_rImpl.m_xRepository.is(), "repository is null");
OSL_ENSURE(i_rImpl.m_xManifest.is(), "manifest is null");
if (rterr.hasValue()) {
throw lang::WrappedTargetRuntimeException(
OUString(
"DocumentMetadataAccess::loadMetadataFromStorage: "
"exception"), nullptr, rterr);
}
if (err) {
if (handleError(iaioe, i_xHandler)) goto retry;
}
}
/** init Impl struct */
static void init(struct DocumentMetadataAccess_Impl & i_rImpl)
{
try {
i_rImpl.m_xManifest.set(i_rImpl.m_xRepository->createGraph(
getURIForStream(i_rImpl, s_manifest)),
uno::UNO_SET_THROW);
// insert the document statement
i_rImpl.m_xManifest->addStatement(i_rImpl.m_xBaseURI.get(),
getURI(i_rImpl.m_xContext),
getURI(i_rImpl.m_xContext).get());
} catch (const uno::Exception & e) {
throw lang::WrappedTargetRuntimeException(
"init: unexpected exception", nullptr,
uno::makeAny(e));
}
// add top-level content files
if (!addContentOrStylesFileImpl(i_rImpl, s_content)) {
throw uno::RuntimeException();
}
if (!addContentOrStylesFileImpl(i_rImpl, s_styles)) {
throw uno::RuntimeException();
}
}
DocumentMetadataAccess::DocumentMetadataAccess(
uno::Reference< uno::XComponentContext > const & i_xContext,
const IXmlIdRegistrySupplier & i_rRegistrySupplier)
: m_pImpl(new DocumentMetadataAccess_Impl(i_xContext, i_rRegistrySupplier))
{
// no initalization: must call loadFrom...
}
DocumentMetadataAccess::DocumentMetadataAccess(
uno::Reference< uno::XComponentContext > const & i_xContext,
const IXmlIdRegistrySupplier & i_rRegistrySupplier,
OUString const & i_rURI)
: m_pImpl(new DocumentMetadataAccess_Impl(i_xContext, i_rRegistrySupplier))
{
OSL_ENSURE(!i_rURI.isEmpty(), "DMA::DMA: no URI given!");
OSL_ENSURE(i_rURI.endsWith("/"), "DMA::DMA: URI without / given!");
if (!i_rURI.endsWith("/")) throw uno::RuntimeException();
m_pImpl->m_xBaseURI.set(rdf::URI::create(m_pImpl->m_xContext, i_rURI));
m_pImpl->m_xRepository.set(rdf::Repository::create(m_pImpl->m_xContext),
uno::UNO_SET_THROW);
// init repository
init(*m_pImpl);
OSL_ENSURE(m_pImpl->m_xBaseURI.is(), "base URI is null");
OSL_ENSURE(m_pImpl->m_xRepository.is(), "repository is null");
OSL_ENSURE(m_pImpl->m_xManifest.is(), "manifest is null");
}
DocumentMetadataAccess::~DocumentMetadataAccess()
{
}
// css::rdf::XRepositorySupplier:
uno::Reference< rdf::XRepository > SAL_CALL
DocumentMetadataAccess::getRDFRepository() throw (uno::RuntimeException, std::exception)
{
OSL_ENSURE(m_pImpl->m_xRepository.is(), "repository not initialized");
return m_pImpl->m_xRepository;
}
// css::rdf::XNode:
OUString SAL_CALL
DocumentMetadataAccess::getStringValue() throw (uno::RuntimeException, std::exception)
{
return m_pImpl->m_xBaseURI->getStringValue();
}
// css::rdf::XURI:
OUString SAL_CALL
DocumentMetadataAccess::getNamespace() throw (uno::RuntimeException, std::exception)
{
return m_pImpl->m_xBaseURI->getNamespace();
}
OUString SAL_CALL
DocumentMetadataAccess::getLocalName() throw (uno::RuntimeException, std::exception)
{
return m_pImpl->m_xBaseURI->getLocalName();
}
// css::rdf::XDocumentMetadataAccess:
uno::Reference< rdf::XMetadatable > SAL_CALL
DocumentMetadataAccess::getElementByMetadataReference(
const css::beans::StringPair & i_rReference)
throw (uno::RuntimeException, std::exception)
{
const IXmlIdRegistry * pReg(
m_pImpl->m_rXmlIdRegistrySupplier.GetXmlIdRegistry() );
if (!pReg) {
throw uno::RuntimeException(
"DocumentMetadataAccess::getElementByXmlId: no registry", *this);
}
return pReg->GetElementByMetadataReference(i_rReference);
}
uno::Reference< rdf::XMetadatable > SAL_CALL
DocumentMetadataAccess::getElementByURI(
const uno::Reference< rdf::XURI > & i_xURI )
throw (uno::RuntimeException, lang::IllegalArgumentException, std::exception)
{
if (!i_xURI.is()) {
throw lang::IllegalArgumentException(
"DocumentMetadataAccess::getElementByURI: URI is null", *this, 0);
}
const OUString baseURI( m_pImpl->m_xBaseURI->getStringValue() );
const OUString name( i_xURI->getStringValue() );
if (!name.match(baseURI)) {
return nullptr;
}
const OUString relName( name.copy(baseURI.getLength()) );
OUString path;
OUString idref;
if (!splitXmlId(relName, path, idref)) {
return nullptr;
}
return getElementByMetadataReference( beans::StringPair(path, idref) );
}
uno::Sequence< uno::Reference< rdf::XURI > > SAL_CALL
DocumentMetadataAccess::getMetadataGraphsWithType(
const uno::Reference & i_xType)
throw (uno::RuntimeException, lang::IllegalArgumentException, std::exception)
{
if (!i_xType.is()) {
throw lang::IllegalArgumentException(
"DocumentMetadataAccess::getMetadataGraphsWithType: "
"type is null", *this, 0);
}
::std::vector< uno::Reference< rdf::XURI > > ret;
const ::std::vector< uno::Reference< rdf::XURI > > parts(
getAllParts(*m_pImpl) );
::std::remove_copy_if(parts.begin(), parts.end(),
::std::back_inserter(ret),
[this, &i_xType](uno::Reference< rdf::XURI > aPart) {
return !isPartOfType(*m_pImpl, aPart, i_xType);
} );
return ::comphelper::containerToSequence(ret);
}
uno::Reference SAL_CALL
DocumentMetadataAccess::addMetadataFile(const OUString & i_rFileName,
const uno::Sequence < uno::Reference< rdf::XURI > > & i_rTypes)
throw (uno::RuntimeException, lang::IllegalArgumentException,
container::ElementExistException, std::exception)
{
if (!isFileNameValid(i_rFileName)) {
throw lang::IllegalArgumentException(
"DocumentMetadataAccess::addMetadataFile: invalid FileName",
*this, 0);
}
if (isReservedFile(i_rFileName)) {
throw lang::IllegalArgumentException(
"DocumentMetadataAccess::addMetadataFile:"
"invalid FileName: reserved", *this, 0);
}
for (sal_Int32 i = 0; i < i_rTypes.getLength(); ++i) {
if (!i_rTypes[i].is()) {
throw lang::IllegalArgumentException(
"DocumentMetadataAccess::addMetadataFile: "
"null type", *this, 2);
}
}
const uno::Reference xGraphName(
getURIForStream(*m_pImpl, i_rFileName) );
try {
m_pImpl->m_xRepository->createGraph(xGraphName);
} catch (const rdf::RepositoryException & e) {
throw lang::WrappedTargetRuntimeException(
"DocumentMetadataAccess::addMetadataFile: exception",
*this, uno::makeAny(e));
// note: all other exceptions are propagated
}
addMetadataFileImpl(*m_pImpl, i_rFileName, i_rTypes);
return xGraphName;
}
uno::Reference SAL_CALL
DocumentMetadataAccess::importMetadataFile(::sal_Int16 i_Format,
const uno::Reference< io::XInputStream > & i_xInStream,
const OUString & i_rFileName,
const uno::Reference< rdf::XURI > & i_xBaseURI,
const uno::Sequence < uno::Reference< rdf::XURI > > & i_rTypes)
throw (uno::RuntimeException, lang::IllegalArgumentException,
datatransfer::UnsupportedFlavorException,
container::ElementExistException, rdf::ParseException, io::IOException, std::exception)
{
if (!isFileNameValid(i_rFileName)) {
throw lang::IllegalArgumentException(
"DocumentMetadataAccess::importMetadataFile: invalid FileName",
*this, 0);
}
if (isReservedFile(i_rFileName)) {
throw lang::IllegalArgumentException(
"DocumentMetadataAccess::importMetadataFile:"
"invalid FileName: reserved", *this, 0);
}
for (sal_Int32 i = 0; i < i_rTypes.getLength(); ++i) {
if (!i_rTypes[i].is()) {
throw lang::IllegalArgumentException(
"DocumentMetadataAccess::importMetadataFile: null type",
*this, 5);
}
}
const uno::Reference xGraphName(
getURIForStream(*m_pImpl, i_rFileName) );
try {
m_pImpl->m_xRepository->importGraph(
i_Format, i_xInStream, xGraphName, i_xBaseURI);
} catch (const rdf::RepositoryException & e) {
throw lang::WrappedTargetRuntimeException(
"DocumentMetadataAccess::importMetadataFile: "
"RepositoryException", *this, uno::makeAny(e));
// note: all other exceptions are propagated
}
// add to manifest
addMetadataFileImpl(*m_pImpl, i_rFileName, i_rTypes);
return xGraphName;
}
void SAL_CALL
DocumentMetadataAccess::removeMetadataFile(
const uno::Reference< rdf::XURI > & i_xGraphName)
throw (uno::RuntimeException, lang::IllegalArgumentException,
container::NoSuchElementException, std::exception)
{
try {
m_pImpl->m_xRepository->destroyGraph(i_xGraphName);
} catch (const rdf::RepositoryException & e) {
throw lang::WrappedTargetRuntimeException(
"DocumentMetadataAccess::removeMetadataFile: "
"RepositoryException", *this, uno::makeAny(e));
// note: all other exceptions are propagated
}
// remove file from manifest
removeFile(*m_pImpl, i_xGraphName.get());
}
void SAL_CALL
DocumentMetadataAccess::addContentOrStylesFile(
const OUString & i_rFileName)
throw (uno::RuntimeException, lang::IllegalArgumentException,
container::ElementExistException, std::exception)
{
if (!isFileNameValid(i_rFileName)) {
throw lang::IllegalArgumentException(
"DocumentMetadataAccess::addContentOrStylesFile: "
"invalid FileName", *this, 0);
}
if (!addContentOrStylesFileImpl(*m_pImpl, i_rFileName)) {
throw lang::IllegalArgumentException(
"DocumentMetadataAccess::addContentOrStylesFile: "
"invalid FileName: must end with content.xml or styles.xml",
*this, 0);
}
}
void SAL_CALL
DocumentMetadataAccess::removeContentOrStylesFile(
const OUString & i_rFileName)
throw (uno::RuntimeException, lang::IllegalArgumentException,
container::NoSuchElementException, std::exception)
{
if (!isFileNameValid(i_rFileName)) {
throw lang::IllegalArgumentException(
"DocumentMetadataAccess::removeContentOrStylesFile: "
"invalid FileName", *this, 0);
}
try {
const uno::Reference xPart(
getURIForStream(*m_pImpl, i_rFileName) );
const uno::Reference xEnum(
m_pImpl->m_xManifest->getStatements( m_pImpl->m_xBaseURI.get(),
getURI(m_pImpl->m_xContext),
xPart.get()),
uno::UNO_SET_THROW);
if (!xEnum->hasMoreElements()) {
throw container::NoSuchElementException(
"DocumentMetadataAccess::removeContentOrStylesFile: "
"cannot find stream in manifest graph: " + i_rFileName,
*this);
}
// remove file from manifest
removeFile(*m_pImpl, xPart);
} catch (const uno::RuntimeException &) {
throw;
} catch (const uno::Exception & e) {
throw lang::WrappedTargetRuntimeException(
"DocumentMetadataAccess::removeContentOrStylesFile: exception",
*this, uno::makeAny(e));
}
}
void SAL_CALL DocumentMetadataAccess::loadMetadataFromStorage(
const uno::Reference< embed::XStorage > & i_xStorage,
const uno::Reference & i_xBaseURI,
const uno::Reference & i_xHandler)
throw (uno::RuntimeException, lang::IllegalArgumentException,
lang::WrappedTargetException, std::exception)
{
if (!i_xStorage.is()) {
throw lang::IllegalArgumentException(
"DocumentMetadataAccess::loadMetadataFromStorage: "
"storage is null", *this, 0);
}
if (!i_xBaseURI.is()) {
throw lang::IllegalArgumentException(
"DocumentMetadataAccess::loadMetadataFromStorage: "
"base URI is null", *this, 1);
}
const OUString baseURI( i_xBaseURI->getStringValue());
if (baseURI.indexOf('#') >= 0) {
throw lang::IllegalArgumentException(
"DocumentMetadataAccess::loadMetadataFromStorage: "
"base URI not absolute", *this, 1);
}
if (!baseURI.endsWith("/")) {
throw lang::IllegalArgumentException(
"DocumentMetadataAccess::loadMetadataFromStorage: "
"base URI does not end with slash", *this, 1);
}
initLoading(*m_pImpl, i_xStorage, i_xBaseURI, i_xHandler);
std::set< OUString > StgFiles;
collectFilesFromStorage(i_xStorage,
"", StgFiles);
std::vector< OUString > MfstMetadataFiles;
try {
const ::std::vector< uno::Reference< rdf::XURI > > parts(
getAllParts(*m_pImpl) );
const uno::Reference xContentFile(
getURI(m_pImpl->m_xContext));
const uno::Reference xStylesFile(
getURI(m_pImpl->m_xContext));
const uno::Reference xMetadataFile(
getURI(m_pImpl->m_xContext));
const sal_Int32 len( baseURI.getLength() );
for (::std::vector< uno::Reference< rdf::XURI > >::const_iterator it
= parts.begin();
it != parts.end(); ++it) {
const OUString name((*it)->getStringValue());
if (!name.match(baseURI)) {
OSL_TRACE("loadMetadataFromStorage: graph not in document: %s",
OUStringToOString(name, RTL_TEXTENCODING_UTF8)
.getStr());
continue;
}
const OUString relName( name.copy(len) );
if (relName == s_manifest) {
OSL_TRACE("loadMetadataFromStorage: "
"found ourselves a recursive manifest!");
continue;
}
// remove found items from StgFiles
StgFiles.erase(relName);
if (isContentFile(relName)) {
if (!isPartOfType(*m_pImpl, *it, xContentFile)) {
const uno::Reference xName(
getURIForStream(*m_pImpl, relName) );
// add missing type statement
m_pImpl->m_xManifest->addStatement(xName.get(),
getURI(m_pImpl->m_xContext),
xContentFile.get());
}
} else if (isStylesFile(relName)) {
if (!isPartOfType(*m_pImpl, *it, xStylesFile)) {
const uno::Reference xName(
getURIForStream(*m_pImpl, relName) );
// add missing type statement
m_pImpl->m_xManifest->addStatement(xName.get(),
getURI(m_pImpl->m_xContext),
xStylesFile.get());
}
} else if (isReservedFile(relName)) {
OSL_TRACE("loadMetadataFromStorage: "
"reserved file name in manifest");
} else {
if (isPartOfType(*m_pImpl, *it, xMetadataFile)) {
MfstMetadataFiles.push_back(relName);
}
// do not add statement for MetadataFile; it could be
// something else! just ignore it...
}
}
} catch (const uno::RuntimeException &) {
throw;
} catch (const uno::Exception & e) {
throw lang::WrappedTargetRuntimeException(
"DocumentMetadataAccess::loadMetadataFromStorage: "
"exception", *this, uno::makeAny(e));
}
for (const auto& aStgFile : StgFiles)
addContentOrStylesFileImpl(*m_pImpl, aStgFile);
for (const auto& aMfstMetadataFile : MfstMetadataFiles)
importFile(*m_pImpl, i_xStorage, baseURI, i_xHandler, aMfstMetadataFile);
}
void SAL_CALL DocumentMetadataAccess::storeMetadataToStorage(
const uno::Reference< embed::XStorage > & i_xStorage)
throw (uno::RuntimeException, lang::IllegalArgumentException,
lang::WrappedTargetException, std::exception)
{
if (!i_xStorage.is()) {
throw lang::IllegalArgumentException(
"DocumentMetadataAccess::storeMetadataToStorage: "
"storage is null", *this, 0);
}
// export manifest
const uno::Reference xManifest(
getURIForStream(*m_pImpl, s_manifest) );
const OUString baseURI( m_pImpl->m_xBaseURI->getStringValue() );
try {
writeStream(*m_pImpl, i_xStorage, xManifest, s_manifest, baseURI);
} catch (const uno::RuntimeException &) {
throw;
} catch (const io::IOException & e) {
throw lang::WrappedTargetException(
"storeMetadataToStorage: IO exception", *this, uno::makeAny(e));
} catch (const uno::Exception & e) {
throw lang::WrappedTargetRuntimeException(
"storeMetadataToStorage: exception", *this, uno::makeAny(e));
}
// export metadata streams
try {
const uno::Sequence > graphs(
m_pImpl->m_xRepository->getGraphNames());
const sal_Int32 len( baseURI.getLength() );
for (sal_Int32 i = 0; i < graphs.getLength(); ++i) {
const uno::Reference xName(graphs[i]);
const OUString name(xName->getStringValue());
if (!name.match(baseURI)) {
OSL_TRACE("storeMetadataToStorage: graph not in document: %s",
OUStringToOString(name, RTL_TEXTENCODING_UTF8)
.getStr());
continue;
}
const OUString relName( name.copy(len) );
if (relName == s_manifest) {
continue;
}
if (!isFileNameValid(relName) || isReservedFile(relName)) {
OSL_TRACE("storeMetadataToStorage: invalid file name: %s",
OUStringToOString(relName, RTL_TEXTENCODING_UTF8)
.getStr());
continue;
}
try {
writeStream(*m_pImpl, i_xStorage, xName, relName, baseURI);
} catch (const uno::RuntimeException &) {
throw;
} catch (const io::IOException & e) {
throw lang::WrappedTargetException(
"storeMetadataToStorage: IO exception",
*this, uno::makeAny(e));
} catch (const uno::Exception & e) {
throw lang::WrappedTargetRuntimeException(
"storeMetadataToStorage: exception",
*this, uno::makeAny(e));
}
}
} catch (const rdf::RepositoryException & e) {
throw lang::WrappedTargetRuntimeException(
"storeMetadataToStorage: exception", *this, uno::makeAny(e));
}
}
void SAL_CALL
DocumentMetadataAccess::loadMetadataFromMedium(
const uno::Sequence< beans::PropertyValue > & i_rMedium)
throw (uno::RuntimeException, lang::IllegalArgumentException,
lang::WrappedTargetException, std::exception)
{
uno::Reference xIn;
utl::MediaDescriptor md(i_rMedium);
OUString URL;
md[ utl::MediaDescriptor::PROP_URL() ] >>= URL;
OUString BaseURL;
md[ utl::MediaDescriptor::PROP_DOCUMENTBASEURL() ] >>= BaseURL;
if (md.addInputStream()) {
md[ utl::MediaDescriptor::PROP_INPUTSTREAM() ] >>= xIn;
}
if (!xIn.is() && URL.isEmpty()) {
throw lang::IllegalArgumentException(
"DocumentMetadataAccess::loadMetadataFromMedium: "
"invalid medium: no URL, no input stream", *this, 0);
}
uno::Reference xStorage;
try {
if (xIn.is()) {
xStorage = ::comphelper::OStorageHelper::GetStorageFromInputStream(
xIn, m_pImpl->m_xContext);
} else { // fallback to url
xStorage = ::comphelper::OStorageHelper::GetStorageFromURL2(
URL, embed::ElementModes::READ, m_pImpl->m_xContext);
}
} catch (const uno::RuntimeException &) {
throw;
} catch (const io::IOException &) {
throw;
} catch (const uno::Exception & e) {
throw lang::WrappedTargetException(
"DocumentMetadataAccess::loadMetadataFromMedium: "
"exception", *this, uno::makeAny(e));
}
if (!xStorage.is()) {
throw uno::RuntimeException(
"DocumentMetadataAccess::loadMetadataFromMedium: "
"cannot get Storage", *this);
}
uno::Reference xBaseURI;
try {
xBaseURI = createBaseURI(m_pImpl->m_xContext, xStorage, BaseURL);
} catch (const uno::Exception &) {
// fall back to URL
try {
xBaseURI = createBaseURI(m_pImpl->m_xContext, xStorage, URL);
} catch (const uno::Exception &) {
OSL_FAIL("cannot create base URI");
}
}
uno::Reference xIH;
md[ utl::MediaDescriptor::PROP_INTERACTIONHANDLER() ] >>= xIH;
loadMetadataFromStorage(xStorage, xBaseURI, xIH);
}
void SAL_CALL
DocumentMetadataAccess::storeMetadataToMedium(
const uno::Sequence< beans::PropertyValue > & i_rMedium)
throw (uno::RuntimeException, lang::IllegalArgumentException,
lang::WrappedTargetException, std::exception)
{
utl::MediaDescriptor md(i_rMedium);
OUString URL;
md[ utl::MediaDescriptor::PROP_URL() ] >>= URL;
if (URL.isEmpty()) {
throw lang::IllegalArgumentException(
"DocumentMetadataAccess::storeMetadataToMedium: "
"invalid medium: no URL", *this, 0);
}
SfxMedium aMedium(i_rMedium);
uno::Reference xStorage(aMedium.GetOutputStorage());
bool sfx(false);
if (xStorage.is()) {
sfx = true;
} else {
xStorage = ::comphelper::OStorageHelper::GetStorageFromURL2(
URL, embed::ElementModes::WRITE, m_pImpl->m_xContext);
}
if (!xStorage.is()) {
throw uno::RuntimeException(
"DocumentMetadataAccess::storeMetadataToMedium: "
"cannot get Storage", *this);
}
// set MIME type of the storage
utl::MediaDescriptor::const_iterator iter
= md.find(utl::MediaDescriptor::PROP_MEDIATYPE());
if (iter != md.end()) {
uno::Reference< beans::XPropertySet > xProps(xStorage,
uno::UNO_QUERY_THROW);
try {
// this is NOT supported in FileSystemStorage
xProps->setPropertyValue(
utl::MediaDescriptor::PROP_MEDIATYPE(),
iter->second);
} catch (const uno::Exception &) { }
}
storeMetadataToStorage(xStorage);
if (sfx) {
const bool bOk = aMedium.Commit();
aMedium.Close();
if ( !bOk ) {
sal_uInt32 nError = aMedium.GetError();
if ( nError == ERRCODE_NONE ) {
nError = ERRCODE_IO_GENERAL;
}
task::ErrorCodeIOException ex(
("DocumentMetadataAccess::storeMetadataToMedium Commit failed: "
"0x" + OUString::number(nError, 16)),
uno::Reference< uno::XInterface >(), nError);
throw lang::WrappedTargetException(OUString(), *this,
uno::makeAny(ex));
}
}
}
} // namespace sfx2
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */