LCOV - code coverage report
Current view: top level - sfx2/source/doc - DocumentMetadataAccess.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 442 591 74.8 %
Date: 2014-04-11 Functions: 52 55 94.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : 
      21             : #include <sfx2/DocumentMetadataAccess.hxx>
      22             : 
      23             : #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
      24             : #include <com/sun/star/beans/XPropertySet.hpp>
      25             : #include <com/sun/star/embed/ElementModes.hpp>
      26             : #include <com/sun/star/embed/XStorage.hpp>
      27             : #include <com/sun/star/embed/XTransactedObject.hpp>
      28             : #include <com/sun/star/task/ErrorCodeIOException.hpp>
      29             : #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
      30             : #include <com/sun/star/rdf/FileFormat.hpp>
      31             : #include <com/sun/star/rdf/URIs.hpp>
      32             : #include <com/sun/star/rdf/Statement.hpp>
      33             : #include <com/sun/star/rdf/Literal.hpp>
      34             : #include <com/sun/star/rdf/URI.hpp>
      35             : #include <com/sun/star/rdf/Repository.hpp>
      36             : 
      37             : #include <rtl/ustrbuf.hxx>
      38             : #include <rtl/uri.hxx>
      39             : #include <rtl/bootstrap.hxx>
      40             : 
      41             : #include <comphelper/interaction.hxx>
      42             : #include <comphelper/makesequence.hxx>
      43             : #include <unotools/mediadescriptor.hxx>
      44             : #include <comphelper/sequenceasvector.hxx>
      45             : #include <comphelper/storagehelper.hxx>
      46             : 
      47             : #include <sfx2/docfile.hxx>
      48             : #include <sfx2/XmlIdRegistry.hxx>
      49             : 
      50             : #include <libxml/tree.h>
      51             : 
      52             : #include <boost/bind.hpp>
      53             : #include <boost/shared_array.hpp>
      54             : #include <boost/tuple/tuple.hpp>
      55             : 
      56             : #include <vector>
      57             : #include <set>
      58             : #include <map>
      59             : #include <functional>
      60             : #include <algorithm>
      61             : 
      62             : #include <unotools/ucbhelper.hxx>
      63             : #include <com/sun/star/uri/XUriReference.hpp>
      64             : #include <com/sun/star/uri/UriReferenceFactory.hpp>
      65             : #include <com/sun/star/uri/XVndSunStarPkgUrlReferenceFactory.hpp>
      66             : 
      67             : 
      68             : /*
      69             :  Note: in the context of this implementation, all rdf.QueryExceptions and
      70             :  rdf.RepositoryExceptions are RuntimeExceptions, and will be reported as such.
      71             : 
      72             :  This implementation assumes that it is only used with ODF documents, not mere
      73             :  ODF packages. In other words, we enforce that metadata files must not be
      74             :  called reserved names.
      75             :  */
      76             : 
      77             : using namespace ::com::sun::star;
      78             : 
      79             : namespace sfx2 {
      80             : 
      81             : 
      82         878 : bool isValidNCName(OUString const & i_rIdref)
      83             : {
      84             :     const OString id(
      85         878 :         OUStringToOString(i_rIdref, RTL_TEXTENCODING_UTF8) );
      86             :     return !(xmlValidateNCName(
      87         878 :         reinterpret_cast<const unsigned char*>(id.getStr()), 0));
      88             : }
      89             : 
      90             : 
      91             : static const char s_content [] = "content.xml";
      92             : static const char s_styles  [] = "styles.xml";
      93             : static const char s_meta    [] = "meta.xml";
      94             : static const char s_settings[] = "settings.xml";
      95             : static const char s_manifest[] = "manifest.rdf";
      96             : static const char s_rdfxml  [] = "application/rdf+xml";
      97             : static const char s_odfmime [] = "application/vnd.oasis.opendocument.";
      98             : 
      99             : 
     100        1159 : static bool isContentFile(OUString const & i_rPath)
     101             : {
     102        1159 :     return i_rPath == s_content;
     103             : }
     104             : 
     105         150 : static bool isStylesFile (OUString const & i_rPath)
     106             : {
     107         150 :     return i_rPath == s_styles;
     108             : }
     109             : 
     110         878 : bool isValidXmlId(OUString const & i_rStreamName,
     111             :     OUString const & i_rIdref)
     112             : {
     113         878 :     return isValidNCName(i_rIdref)
     114         878 :         && (isContentFile(i_rStreamName) || isStylesFile(i_rStreamName));
     115             : }
     116             : 
     117          14 : static bool isReservedFile(OUString const & i_rPath)
     118             : {
     119          14 :     return isContentFile(i_rPath) || isStylesFile(i_rPath) || i_rPath == s_meta || i_rPath == s_settings;
     120             : }
     121             : 
     122             : 
     123         221 : uno::Reference<rdf::XURI> createBaseURI(
     124             :     uno::Reference<uno::XComponentContext> const & i_xContext,
     125             :     uno::Reference<embed::XStorage> const & i_xStorage,
     126             :     OUString const & i_rPkgURI, OUString const & i_rSubDocument)
     127             : {
     128         221 :     if (!i_xContext.is() || !i_xStorage.is() || i_rPkgURI.isEmpty()) {
     129           3 :         throw uno::RuntimeException();
     130             :     }
     131             : 
     132             :     // #i108078# workaround non-hierarchical vnd.sun.star.expand URIs
     133             :     // this really should be done somewhere else, not here.
     134         218 :     OUString pkgURI(i_rPkgURI);
     135         218 :     if (pkgURI.matchIgnoreAsciiCase("vnd.sun.star.expand:"))
     136             :     {
     137             :         // expand it here (makeAbsolute requires hierarchical URI)
     138           0 :         pkgURI = pkgURI.copy( RTL_CONSTASCII_LENGTH("vnd.sun.star.expand:") );
     139           0 :         if (!pkgURI.isEmpty()) {
     140           0 :             pkgURI = ::rtl::Uri::decode(
     141           0 :                     pkgURI, rtl_UriDecodeStrict, RTL_TEXTENCODING_UTF8);
     142           0 :             if (pkgURI.isEmpty()) {
     143           0 :                 throw uno::RuntimeException();
     144             :             }
     145           0 :             ::rtl::Bootstrap::expandMacros(pkgURI);
     146             :         }
     147             :     }
     148             : 
     149             :     const uno::Reference<uri::XUriReferenceFactory> xUriFactory =
     150         436 :         uri::UriReferenceFactory::create( i_xContext);
     151         436 :     uno::Reference< uri::XUriReference > xBaseURI;
     152             : 
     153             :     const uno::Reference< uri::XUriReference > xPkgURI(
     154         436 :         xUriFactory->parse(pkgURI), uno::UNO_SET_THROW );
     155         218 :     xPkgURI->clearFragment();
     156             : 
     157             :     // need to know whether the storage is a FileSystemStorage
     158             :     // XServiceInfo would be better, but it is not implemented
     159             : //    if ( pkgURI.getLength() && ::utl::UCBContentHelper::IsFolder(pkgURI) )
     160             :     if (true) {
     161         218 :         xBaseURI.set( xPkgURI, uno::UNO_SET_THROW );
     162             :     }
     163         436 :     OUStringBuffer buf;
     164         218 :     if (!xBaseURI->getUriReference().endsWithAsciiL("/", 1))
     165             :     {
     166         218 :         const sal_Int32 count( xBaseURI->getPathSegmentCount() );
     167         218 :         if (count > 0)
     168             :         {
     169         218 :             const OUString last( xBaseURI->getPathSegment(count - 1) );
     170         218 :             buf.append(last);
     171             :         }
     172         218 :         buf.append('/');
     173             :     }
     174         218 :     if (!i_rSubDocument.isEmpty())
     175             :     {
     176           0 :         buf.append(i_rSubDocument);
     177           0 :         buf.append('/');
     178             :     }
     179         436 :     const OUString Path(buf.makeStringAndClear());
     180         218 :     if (!Path.isEmpty())
     181             :     {
     182             :         const uno::Reference< uri::XUriReference > xPathURI(
     183         218 :             xUriFactory->parse(Path), uno::UNO_SET_THROW );
     184             :         xBaseURI.set(
     185         218 :             xUriFactory->makeAbsolute(xBaseURI, xPathURI,
     186         218 :                 true, uri::RelativeUriExcessParentSegments_ERROR),
     187         218 :             uno::UNO_SET_THROW);
     188             :     }
     189             : 
     190         535 :     return rdf::URI::create(i_xContext, xBaseURI->getUriReference());
     191             : }
     192             : 
     193             : 
     194         128 : struct DocumentMetadataAccess_Impl
     195             : {
     196             :     // note: these are all initialized in constructor, and loadFromStorage
     197             :     const uno::Reference<uno::XComponentContext> m_xContext;
     198             :     const IXmlIdRegistrySupplier & m_rXmlIdRegistrySupplier;
     199             :     uno::Reference<rdf::XURI> m_xBaseURI;
     200             :     uno::Reference<rdf::XRepository> m_xRepository;
     201             :     uno::Reference<rdf::XNamedGraph> m_xManifest;
     202         134 :     DocumentMetadataAccess_Impl(
     203             :             uno::Reference<uno::XComponentContext> const& i_xContext,
     204             :             IXmlIdRegistrySupplier const & i_rRegistrySupplier)
     205             :       : m_xContext(i_xContext)
     206             :       , m_rXmlIdRegistrySupplier(i_rRegistrySupplier)
     207             :       , m_xBaseURI()
     208             :       , m_xRepository()
     209         134 :       , m_xManifest()
     210             :     {
     211             :         OSL_ENSURE(m_xContext.is(), "context null");
     212         134 :     }
     213             : };
     214             : 
     215             : // this is... a hack.
     216             : template<sal_Int16 Constant>
     217             : /*static*/ uno::Reference<rdf::XURI>
     218        1547 : getURI(uno::Reference< uno::XComponentContext > const & i_xContext)
     219             : {
     220             :     static uno::Reference< rdf::XURI > xURI(
     221        1547 :         rdf::URI::createKnown(i_xContext, Constant), uno::UNO_QUERY_THROW);
     222        1547 :     return xURI;
     223             : }
     224             : 
     225             : 
     226             : /** would storing the file to a XStorage succeed? */
     227          27 : static bool isFileNameValid(const OUString & i_rFileName)
     228             : {
     229          27 :     if (i_rFileName.isEmpty()) return false;
     230          23 :     if (i_rFileName[0] == '/')        return false; // no absolute paths!
     231          21 :     sal_Int32 idx(0);
     232          25 :     do {
     233             :       const OUString segment(
     234          29 :         i_rFileName.getToken(0, static_cast<sal_Unicode> ('/'), idx) );
     235          87 :       if (segment.isEmpty()      ||  // no empty segments
     236          57 :           segment == "."         ||  // no . segments
     237          83 :           segment == ".."        ||  // no .. segments
     238             :           !::comphelper::OStorageHelper::IsValidZipEntryFileName(
     239          26 :               segment, false))      // no invalid characters
     240           4 :                                       return false;
     241          25 :     } while (idx >= 0);
     242          17 :     return true;
     243             : }
     244             : 
     245             : /** split a uri hierarchy into first segment and rest */
     246             : static bool
     247         158 : splitPath(OUString const & i_rPath,
     248             :     OUString & o_rDir, OUString& o_rRest)
     249             : {
     250         158 :     const sal_Int32 idx(i_rPath.indexOf(static_cast<sal_Unicode>('/')));
     251         158 :     if (idx < 0 || idx >= i_rPath.getLength()) {
     252         150 :         o_rDir = OUString();
     253         150 :         o_rRest = i_rPath;
     254         150 :         return true;
     255           8 :     } else if (idx == 0 || idx == i_rPath.getLength() - 1) {
     256             :         // input must not start or end with '/'
     257           0 :         return false;
     258             :     } else {
     259           8 :         o_rDir  = (i_rPath.copy(0, idx));
     260           8 :         o_rRest = (i_rPath.copy(idx+1));
     261           8 :         return true;
     262             :     }
     263             : }
     264             : 
     265             : static bool
     266           1 : splitXmlId(OUString const & i_XmlId,
     267             :     OUString & o_StreamName, OUString& o_Idref )
     268             : {
     269           1 :     const sal_Int32 idx(i_XmlId.indexOf(static_cast<sal_Unicode>('#')));
     270           1 :     if ((idx <= 0) || (idx >= i_XmlId.getLength() - 1)) {
     271           0 :         return false;
     272             :     } else {
     273           1 :         o_StreamName = (i_XmlId.copy(0, idx));
     274           1 :         o_Idref      = (i_XmlId.copy(idx+1));
     275           1 :         return isValidXmlId(o_StreamName, o_Idref);
     276             :     }
     277             : }
     278             : 
     279             : 
     280             : static uno::Reference<rdf::XURI>
     281         310 : getURIForStream(struct DocumentMetadataAccess_Impl& i_rImpl,
     282             :     OUString const& i_rPath)
     283             : {
     284             :     const uno::Reference<rdf::XURI> xURI(
     285             :         rdf::URI::createNS( i_rImpl.m_xContext,
     286         620 :             i_rImpl.m_xBaseURI->getStringValue(), i_rPath),
     287         620 :         uno::UNO_SET_THROW);
     288         310 :     return xURI;
     289             : }
     290             : 
     291             : /** add statements declaring i_xResource to be a file of type i_xType with
     292             :     path i_rPath to manifest, with optional additional types i_pTypes */
     293             : static void
     294         144 : addFile(struct DocumentMetadataAccess_Impl & i_rImpl,
     295             :     uno::Reference<rdf::XURI> const& i_xType,
     296             :     OUString const & i_rPath,
     297             :     const uno::Sequence < uno::Reference< rdf::XURI > > * i_pTypes = 0)
     298             : {
     299             :     try {
     300             :         const uno::Reference<rdf::XURI> xURI( getURIForStream(
     301         144 :             i_rImpl, i_rPath) );
     302             : 
     303         288 :         i_rImpl.m_xManifest->addStatement(i_rImpl.m_xBaseURI.get(),
     304             :             getURI<rdf::URIs::PKG_HASPART>(i_rImpl.m_xContext),
     305         288 :             xURI.get());
     306         288 :         i_rImpl.m_xManifest->addStatement(xURI.get(),
     307             :             getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext),
     308         288 :             i_xType.get());
     309         144 :         if (i_pTypes) {
     310           3 :             for (sal_Int32 i = 0; i < i_pTypes->getLength(); ++i) {
     311           2 :                 i_rImpl.m_xManifest->addStatement(xURI.get(),
     312             :                     getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext),
     313           2 :                     (*i_pTypes)[i].get());
     314             :             }
     315         144 :         }
     316           0 :     } catch (const uno::RuntimeException &) {
     317           0 :         throw;
     318           0 :     } catch (const uno::Exception & e) {
     319             :         throw lang::WrappedTargetRuntimeException(
     320             :             OUString(
     321           0 :                 "addFile: exception"), /*this*/0, uno::makeAny(e));
     322             :     }
     323         144 : }
     324             : 
     325             : /** add content.xml or styles.xml to manifest */
     326             : static bool
     327         143 : addContentOrStylesFileImpl(struct DocumentMetadataAccess_Impl & i_rImpl,
     328             :     const OUString & i_rPath)
     329             : {
     330         143 :     uno::Reference<rdf::XURI> xType;
     331         143 :     if (isContentFile(i_rPath)) {
     332          71 :         xType.set(getURI<rdf::URIs::ODF_CONTENTFILE>(i_rImpl.m_xContext));
     333          72 :     } else if (isStylesFile(i_rPath)) {
     334          71 :         xType.set(getURI<rdf::URIs::ODF_STYLESFILE>(i_rImpl.m_xContext));
     335             :     } else {
     336           1 :         return false;
     337             :     }
     338         142 :     addFile(i_rImpl, xType.get(), i_rPath);
     339         142 :     return true;
     340             : }
     341             : 
     342             : /** add metadata file to manifest */
     343             : static void
     344           2 : addMetadataFileImpl(struct DocumentMetadataAccess_Impl & i_rImpl,
     345             :     const OUString & i_rPath,
     346             :     const uno::Sequence < uno::Reference< rdf::XURI > > & i_rTypes)
     347             : {
     348             :     addFile(i_rImpl,
     349             :             getURI<rdf::URIs::PKG_METADATAFILE>(i_rImpl.m_xContext),
     350           2 :             i_rPath, &i_rTypes);
     351           2 : }
     352             : 
     353             : /** remove a file from the manifest */
     354             : static void
     355           3 : removeFile(struct DocumentMetadataAccess_Impl & i_rImpl,
     356             :     uno::Reference<rdf::XURI> const& i_xPart)
     357             : {
     358           3 :     if (!i_xPart.is()) throw uno::RuntimeException();
     359             :     try {
     360           6 :         i_rImpl.m_xManifest->removeStatements(i_rImpl.m_xBaseURI.get(),
     361             :             getURI<rdf::URIs::PKG_HASPART>(i_rImpl.m_xContext),
     362           6 :             i_xPart.get());
     363           6 :         i_rImpl.m_xManifest->removeStatements(i_xPart.get(),
     364           6 :             getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), 0);
     365           0 :     } catch (const uno::RuntimeException &) {
     366           0 :         throw;
     367           0 :     } catch (const uno::Exception & e) {
     368             :         throw lang::WrappedTargetRuntimeException(
     369             :             OUString("removeFile: exception"),
     370           0 :             0, uno::makeAny(e));
     371             :     }
     372           3 : }
     373             : 
     374             : static ::std::vector< uno::Reference< rdf::XURI > >
     375         120 : getAllParts(struct DocumentMetadataAccess_Impl & i_rImpl)
     376             : {
     377         120 :     ::std::vector< uno::Reference< rdf::XURI > > ret;
     378             :     try {
     379             :         const uno::Reference<container::XEnumeration> xEnum(
     380         240 :             i_rImpl.m_xManifest->getStatements( i_rImpl.m_xBaseURI.get(),
     381         120 :                 getURI<rdf::URIs::PKG_HASPART>(i_rImpl.m_xContext), 0),
     382         240 :             uno::UNO_SET_THROW);
     383         367 :         while (xEnum->hasMoreElements()) {
     384         127 :             rdf::Statement stmt;
     385         127 :             if (!(xEnum->nextElement() >>= stmt)) {
     386           0 :                 throw uno::RuntimeException();
     387             :             }
     388             :             const uno::Reference<rdf::XURI> xPart(stmt.Object,
     389         254 :                 uno::UNO_QUERY);
     390         127 :             if (!xPart.is()) continue;
     391         127 :             ret.push_back(xPart);
     392         127 :         }
     393         120 :         return ret;
     394           0 :     } catch (const uno::RuntimeException &) {
     395           0 :         throw;
     396           0 :     } catch (const uno::Exception & e) {
     397             :         throw lang::WrappedTargetRuntimeException(
     398             :             OUString("getAllParts: exception"),
     399           0 :             0, uno::makeAny(e));
     400             :     }
     401             : }
     402             : 
     403             : static bool
     404         127 : isPartOfType(struct DocumentMetadataAccess_Impl & i_rImpl,
     405             :     uno::Reference<rdf::XURI> const & i_xPart,
     406             :     uno::Reference<rdf::XURI> const & i_xType)
     407             : {
     408         127 :     if (!i_xPart.is() || !i_xType.is()) throw uno::RuntimeException();
     409             :     try {
     410             :         const uno::Reference<container::XEnumeration> xEnum(
     411         254 :             i_rImpl.m_xManifest->getStatements(i_xPart.get(),
     412             :                 getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext),
     413         127 :                 i_xType.get()),
     414         254 :             uno::UNO_SET_THROW);
     415         127 :         return (xEnum->hasMoreElements());
     416           0 :     } catch (const uno::RuntimeException &) {
     417           0 :         throw;
     418           0 :     } catch (const uno::Exception & e) {
     419             :         throw lang::WrappedTargetRuntimeException(
     420             :             OUString("isPartOfType: exception"),
     421           0 :             0, uno::makeAny(e));
     422             :     }
     423             : }
     424             : 
     425             : 
     426             : static ucb::InteractiveAugmentedIOException
     427          58 : mkException( OUString const & i_rMessage,
     428             :     ucb::IOErrorCode const i_ErrorCode,
     429             :     OUString const & i_rUri, OUString const & i_rResource)
     430             : {
     431          58 :     ucb::InteractiveAugmentedIOException iaioe;
     432          58 :     iaioe.Message = i_rMessage;
     433          58 :     iaioe.Classification = task::InteractionClassification_ERROR;
     434          58 :     iaioe.Code = i_ErrorCode;
     435             : 
     436             :     const beans::PropertyValue uriProp(OUString("Uri"),
     437         116 :         -1, uno::makeAny(i_rUri), static_cast<beans::PropertyState>(0));
     438             :     const beans::PropertyValue rnProp(
     439             :         OUString("ResourceName"),
     440         116 :         -1, uno::makeAny(i_rResource), static_cast<beans::PropertyState>(0));
     441         116 :     iaioe.Arguments = ::comphelper::makeSequence(
     442          58 :         uno::makeAny(uriProp), uno::makeAny(rnProp));
     443         116 :     return iaioe;
     444             : }
     445             : 
     446             : /** error handling policy.
     447             :     <p>If a handler is given, ask it how to proceed:
     448             :     <ul><li>(default:) cancel import, raise exception</li>
     449             :         <li>ignore the error and continue</li>
     450             :         <li>retry the action that led to the error</li></ul></p>
     451             :     N.B.: must not be called before DMA is fully initalized!
     452             :     @returns true iff caller should retry
     453             :  */
     454             : static bool
     455           0 : handleError( ucb::InteractiveAugmentedIOException const & i_rException,
     456             :     const uno::Reference<task::XInteractionHandler> & i_xHandler)
     457             : {
     458           0 :     if (!i_xHandler.is()) {
     459             :         throw lang::WrappedTargetException(OUString(
     460             :             "DocumentMetadataAccess::loadMetadataFromStorage: exception"),
     461           0 :             /* *this*/ 0, uno::makeAny(i_rException));
     462             :     }
     463             : 
     464             :     ::rtl::Reference< ::comphelper::OInteractionRequest > pRequest(
     465           0 :         new ::comphelper::OInteractionRequest(uno::makeAny(i_rException)) );
     466             :     ::rtl::Reference< ::comphelper::OInteractionRetry > pRetry(
     467           0 :         new ::comphelper::OInteractionRetry );
     468             :     ::rtl::Reference< ::comphelper::OInteractionApprove > pApprove(
     469           0 :         new ::comphelper::OInteractionApprove );
     470             :     ::rtl::Reference< ::comphelper::OInteractionAbort > pAbort(
     471           0 :         new ::comphelper::OInteractionAbort );
     472             : 
     473           0 :     pRequest->addContinuation( pApprove.get() );
     474           0 :     pRequest->addContinuation( pAbort.get() );
     475             :     // actually call the handler
     476           0 :     i_xHandler->handle( pRequest.get() );
     477           0 :     if (pRetry->wasSelected()) {
     478           0 :         return true;
     479           0 :     } else if (pApprove->wasSelected()) {
     480           0 :         return false;
     481             :     } else {
     482             :         OSL_ENSURE(pAbort->wasSelected(), "no continuation selected?");
     483             :         throw lang::WrappedTargetException(OUString(
     484             :             "DocumentMetadataAccess::loadMetadataFromStorage: exception"),
     485           0 :             /* *this*/ 0, uno::makeAny(i_rException));
     486           0 :     }
     487             : }
     488             : 
     489             : /** check if storage has content.xml/styles.xml;
     490             :     e.g. ODB files seem to only have content.xml */
     491             : static void
     492         119 : collectFilesFromStorage(uno::Reference<embed::XStorage> const& i_xStorage,
     493             :     const OUString& i_Path,
     494             :     std::set< OUString > & o_rFiles)
     495             : {
     496         119 :     static OUString content(s_content);
     497         119 :     static OUString styles(s_styles );
     498             :     try {
     499         236 :         if (i_xStorage->hasByName(content) &&
     500         117 :             i_xStorage->isStreamElement(content))
     501             :         {
     502         117 :             o_rFiles.insert(i_Path + content);
     503             :         }
     504         236 :         if (i_xStorage->hasByName(styles) &&
     505         117 :             i_xStorage->isStreamElement(styles))
     506             :         {
     507         117 :             o_rFiles.insert(i_Path + styles);
     508             :         }
     509           0 :     } catch (const uno::Exception &) {
     510             :         OSL_TRACE("collectFilesFromStorage: exception?");
     511             :     }
     512         119 : }
     513             : 
     514             : /** import a metadata file into repository */
     515             : static void
     516         125 : readStream(struct DocumentMetadataAccess_Impl & i_rImpl,
     517             :     uno::Reference< embed::XStorage > const & i_xStorage,
     518             :     OUString const & i_rPath,
     519             :     OUString const & i_rBaseURI)
     520             : {
     521         125 :     OUString dir;
     522         250 :     OUString rest;
     523             :     try {
     524         125 :         if (!splitPath(i_rPath, dir, rest)) throw uno::RuntimeException();
     525         125 :         if (dir.isEmpty()) {
     526         121 :             if (i_xStorage->isStreamElement(i_rPath)) {
     527             :                 const uno::Reference<io::XStream> xStream(
     528          63 :                     i_xStorage->openStreamElement(i_rPath,
     529          63 :                         embed::ElementModes::READ), uno::UNO_SET_THROW);
     530             :                 const uno::Reference<io::XInputStream> xInStream(
     531         126 :                     xStream->getInputStream(), uno::UNO_SET_THROW );
     532             :                 const uno::Reference<rdf::XURI> xBaseURI(
     533         126 :                     rdf::URI::create(i_rImpl.m_xContext, i_rBaseURI));
     534             :                 const uno::Reference<rdf::XURI> xURI(
     535             :                     rdf::URI::createNS(i_rImpl.m_xContext,
     536         126 :                         i_rBaseURI, i_rPath));
     537          63 :                 i_rImpl.m_xRepository->importGraph(rdf::FileFormat::RDF_XML,
     538         126 :                     xInStream, xURI, xBaseURI);
     539             :             } else {
     540             :                 throw mkException(OUString(
     541             :                     "readStream: is not a stream"),
     542           0 :                     ucb::IOErrorCode_NO_FILE, i_rBaseURI + i_rPath, i_rPath);
     543             :             }
     544             :         } else {
     545           4 :             if (i_xStorage->isStorageElement(dir)) {
     546             :                 const uno::Reference<embed::XStorage> xDir(
     547           4 :                     i_xStorage->openStorageElement(dir,
     548           4 :                         embed::ElementModes::READ));
     549             :                 const uno::Reference< beans::XPropertySet > xDirProps(xDir,
     550           8 :                     uno::UNO_QUERY_THROW);
     551             :                 try {
     552           4 :                     OUString mimeType;
     553           4 :                     xDirProps->getPropertyValue(
     554           4 :                             utl::MediaDescriptor::PROP_MEDIATYPE() )
     555           4 :                         >>= mimeType;
     556           4 :                     if (mimeType.matchAsciiL(s_odfmime, sizeof(s_odfmime) - 1))
     557             :                     {
     558             :                         OSL_TRACE("readStream: "
     559             :                             "refusing to recurse into embedded document");
     560          67 :                         return;
     561           4 :                     }
     562           0 :                 } catch (const uno::Exception &) { }
     563           8 :                 OUStringBuffer buf(i_rBaseURI);
     564           4 :                 buf.append(dir).append('/');
     565           8 :                 readStream(i_rImpl, xDir, rest, buf.makeStringAndClear() );
     566             :             } else {
     567             :                 throw mkException(OUString(
     568             :                     "readStream: is not a directory"),
     569           0 :                     ucb::IOErrorCode_NO_DIRECTORY, i_rBaseURI + dir, dir);
     570             :             }
     571             :         }
     572         116 :     } catch (const container::NoSuchElementException & e) {
     573             :         throw mkException(e.Message, ucb::IOErrorCode_NOT_EXISTING_PATH,
     574          58 :             i_rBaseURI + i_rPath, i_rPath);
     575           0 :     } catch (const io::IOException & e) {
     576             :         throw mkException(e.Message, ucb::IOErrorCode_CANT_READ,
     577           0 :             i_rBaseURI + i_rPath, i_rPath);
     578           0 :     } catch (const rdf::ParseException & e) {
     579             :         throw mkException(e.Message, ucb::IOErrorCode_WRONG_FORMAT,
     580           0 :             i_rBaseURI + i_rPath, i_rPath);
     581         125 :     }
     582             : }
     583             : 
     584             : /** import a metadata file into repository */
     585             : static void
     586           2 : importFile(struct DocumentMetadataAccess_Impl & i_rImpl,
     587             :     uno::Reference<embed::XStorage> const & i_xStorage,
     588             :     OUString const & i_rBaseURI,
     589             :     uno::Reference<task::XInteractionHandler> const & i_xHandler,
     590             :     const OUString& i_rPath)
     591             : {
     592             : retry:
     593             :     try {
     594           2 :         readStream(i_rImpl, i_xStorage, i_rPath, i_rBaseURI);
     595           0 :     } catch (const ucb::InteractiveAugmentedIOException & e) {
     596           0 :         if (handleError(e, i_xHandler)) goto retry;
     597           0 :     } catch (const uno::RuntimeException &) {
     598           0 :         throw;
     599           0 :     } catch (const uno::Exception & e) {
     600             :         throw lang::WrappedTargetRuntimeException(
     601             :             OUString("importFile: exception"),
     602           0 :             0, uno::makeAny(e));
     603             :     }
     604           2 : }
     605             : 
     606             : /** actually write a metadata file to the storage */
     607             : static void
     608          29 : exportStream(struct DocumentMetadataAccess_Impl & i_rImpl,
     609             :     uno::Reference< embed::XStorage > const & i_xStorage,
     610             :     uno::Reference<rdf::XURI> const & i_xGraphName,
     611             :     OUString const & i_rFileName,
     612             :     OUString const & i_rBaseURI)
     613             : {
     614             :     const uno::Reference<io::XStream> xStream(
     615          29 :         i_xStorage->openStreamElement(i_rFileName,
     616          29 :             embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE),
     617          29 :         uno::UNO_SET_THROW);
     618             :     const uno::Reference< beans::XPropertySet > xStreamProps(xStream,
     619          58 :         uno::UNO_QUERY);
     620          29 :     if (xStreamProps.is()) { // this is NOT supported in FileSystemStorage
     621          29 :         xStreamProps->setPropertyValue(
     622             :             OUString("MediaType"),
     623          29 :             uno::makeAny(OUString(s_rdfxml)));
     624             :     }
     625             :     const uno::Reference<io::XOutputStream> xOutStream(
     626          58 :         xStream->getOutputStream(), uno::UNO_SET_THROW );
     627             :     const uno::Reference<rdf::XURI> xBaseURI(
     628          58 :         rdf::URI::create(i_rImpl.m_xContext, i_rBaseURI));
     629          29 :     i_rImpl.m_xRepository->exportGraph(rdf::FileFormat::RDF_XML,
     630          58 :         xOutStream, i_xGraphName, xBaseURI);
     631          29 : }
     632             : 
     633             : /** write a metadata file to the storage */
     634             : static void
     635          33 : writeStream(struct DocumentMetadataAccess_Impl & i_rImpl,
     636             :     uno::Reference< embed::XStorage > const & i_xStorage,
     637             :     uno::Reference<rdf::XURI> const & i_xGraphName,
     638             :     OUString const & i_rPath,
     639             :     OUString const & i_rBaseURI)
     640             : {
     641          33 :     OUString dir;
     642          66 :     OUString rest;
     643          33 :     if (!splitPath(i_rPath, dir, rest)) throw uno::RuntimeException();
     644             :     try {
     645          33 :         if (dir.isEmpty()) {
     646             :             exportStream(i_rImpl, i_xStorage, i_xGraphName, i_rPath,
     647          29 :                 i_rBaseURI);
     648             :         } else {
     649             :             const uno::Reference<embed::XStorage> xDir(
     650           4 :                 i_xStorage->openStorageElement(dir,
     651           4 :                     embed::ElementModes::WRITE));
     652             :             const uno::Reference< beans::XPropertySet > xDirProps(xDir,
     653           8 :                 uno::UNO_QUERY_THROW);
     654             :             try {
     655           4 :                 OUString mimeType;
     656           4 :                 xDirProps->getPropertyValue(
     657           4 :                         utl::MediaDescriptor::PROP_MEDIATYPE() )
     658           4 :                     >>= mimeType;
     659           4 :                 if (mimeType.matchAsciiL(s_odfmime, sizeof(s_odfmime) - 1)) {
     660             :                     OSL_TRACE("writeStream: "
     661             :                         "refusing to recurse into embedded document");
     662          33 :                     return;
     663           4 :                 }
     664           0 :             } catch (const uno::Exception &) { }
     665           8 :             OUStringBuffer buf(i_rBaseURI);
     666           4 :             buf.append(dir).append('/');
     667             :             writeStream(i_rImpl, xDir, i_xGraphName, rest,
     668           4 :                 buf.makeStringAndClear());
     669             :             uno::Reference<embed::XTransactedObject> const xTransaction(
     670           8 :                 xDir, uno::UNO_QUERY);
     671           4 :             if (xTransaction.is()) {
     672           4 :                 xTransaction->commit();
     673           4 :             }
     674             :         }
     675           0 :     } catch (const uno::RuntimeException &) {
     676           0 :         throw;
     677           0 :     } catch (const io::IOException &) {
     678           0 :         throw;
     679          33 :     }
     680             : }
     681             : 
     682             : static void
     683         119 : initLoading(struct DocumentMetadataAccess_Impl & i_rImpl,
     684             :     const uno::Reference< embed::XStorage > & i_xStorage,
     685             :     const uno::Reference<rdf::XURI> & i_xBaseURI,
     686             :     const uno::Reference<task::XInteractionHandler> & i_xHandler)
     687             : {
     688             : retry:
     689             :     // clear old data
     690         119 :     i_rImpl.m_xManifest.clear();
     691             :     // init BaseURI
     692         119 :     i_rImpl.m_xBaseURI = i_xBaseURI;
     693             : 
     694             :     // create repository
     695         119 :     i_rImpl.m_xRepository.clear();
     696             :     i_rImpl.m_xRepository.set(rdf::Repository::create(i_rImpl.m_xContext),
     697         119 :             uno::UNO_SET_THROW);
     698             : 
     699             :     const OUString manifest (
     700         119 :             OUString::createFromAscii(s_manifest));
     701         238 :     const OUString baseURI( i_xBaseURI->getStringValue() );
     702             :     // try to delay raising errors until after initialization is done
     703         238 :     uno::Any rterr;
     704         238 :     ucb::InteractiveAugmentedIOException iaioe;
     705         119 :     bool err(false);
     706             : 
     707             :     const uno::Reference <rdf::XURI> xManifest(
     708         238 :         getURIForStream(i_rImpl, manifest));
     709             :     try {
     710         119 :         readStream(i_rImpl, i_xStorage, manifest, baseURI);
     711         116 :     } catch (const ucb::InteractiveAugmentedIOException & e) {
     712             :         // no manifest.rdf: this is not an error in ODF < 1.2
     713          58 :         if (!(ucb::IOErrorCode_NOT_EXISTING_PATH == e.Code)) {
     714           0 :             iaioe = e;
     715           0 :             err = true;
     716             :         }
     717           0 :     } catch (const uno::Exception & e) {
     718           0 :         rterr <<= e;
     719             :     }
     720             : 
     721             :     // init manifest graph
     722             :     const uno::Reference<rdf::XNamedGraph> xManifestGraph(
     723         238 :         i_rImpl.m_xRepository->getGraph(xManifest));
     724         119 :     i_rImpl.m_xManifest.set(xManifestGraph.is() ? xManifestGraph :
     725         119 :         i_rImpl.m_xRepository->createGraph(xManifest), uno::UNO_SET_THROW);
     726             :     const uno::Reference<container::XEnumeration> xEnum(
     727         119 :         i_rImpl.m_xManifest->getStatements(0,
     728             :             getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext),
     729         238 :             getURI<rdf::URIs::PKG_DOCUMENT>(i_rImpl.m_xContext).get()));
     730             : 
     731             :     // document statement
     732         238 :     i_rImpl.m_xManifest->addStatement(i_rImpl.m_xBaseURI.get(),
     733             :         getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext),
     734         238 :         getURI<rdf::URIs::PKG_DOCUMENT>(i_rImpl.m_xContext).get());
     735             : 
     736             :     OSL_ENSURE(i_rImpl.m_xBaseURI.is(), "base URI is null");
     737             :     OSL_ENSURE(i_rImpl.m_xRepository.is(), "repository is null");
     738             :     OSL_ENSURE(i_rImpl.m_xManifest.is(), "manifest is null");
     739             : 
     740         119 :     if (rterr.hasValue()) {
     741             :         throw lang::WrappedTargetRuntimeException(
     742             :             OUString(
     743             :                 "DocumentMetadataAccess::loadMetadataFromStorage: "
     744           0 :                 "exception"), 0, rterr);
     745             :     }
     746             : 
     747         119 :     if (err) {
     748           0 :         if (handleError(iaioe, i_xHandler)) goto retry;
     749         119 :     }
     750         119 : }
     751             : 
     752             : /** init Impl struct */
     753          13 : static void init(struct DocumentMetadataAccess_Impl & i_rImpl)
     754             : {
     755             :     try {
     756             : 
     757          13 :         i_rImpl.m_xManifest.set(i_rImpl.m_xRepository->createGraph(
     758             :             getURIForStream(i_rImpl,
     759          13 :                 OUString::createFromAscii(s_manifest))),
     760          13 :             uno::UNO_SET_THROW);
     761             : 
     762             :         // insert the document statement
     763          26 :         i_rImpl.m_xManifest->addStatement(i_rImpl.m_xBaseURI.get(),
     764             :             getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext),
     765          26 :             getURI<rdf::URIs::PKG_DOCUMENT>(i_rImpl.m_xContext).get());
     766           0 :     } catch (const uno::Exception & e) {
     767             :         throw lang::WrappedTargetRuntimeException(
     768             :             OUString("init: unexpected exception"), 0,
     769           0 :             uno::makeAny(e));
     770             :     }
     771             : 
     772             :     // add top-level content files
     773          26 :     if (!addContentOrStylesFileImpl(i_rImpl,
     774          26 :             OUString::createFromAscii(s_content))) {
     775           0 :         throw uno::RuntimeException();
     776             :     }
     777          26 :     if (!addContentOrStylesFileImpl(i_rImpl,
     778          26 :             OUString::createFromAscii(s_styles))) {
     779           0 :         throw uno::RuntimeException();
     780             :     }
     781          13 : }
     782             : 
     783             : 
     784             : 
     785         121 : DocumentMetadataAccess::DocumentMetadataAccess(
     786             :         uno::Reference< uno::XComponentContext > const & i_xContext,
     787             :         const IXmlIdRegistrySupplier & i_rRegistrySupplier)
     788         121 :     : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext, i_rRegistrySupplier))
     789             : {
     790             :     // no initalization: must call loadFrom...
     791         121 : }
     792             : 
     793          13 : DocumentMetadataAccess::DocumentMetadataAccess(
     794             :         uno::Reference< uno::XComponentContext > const & i_xContext,
     795             :         const IXmlIdRegistrySupplier & i_rRegistrySupplier,
     796             :         OUString const & i_rURI)
     797          13 :     : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext, i_rRegistrySupplier))
     798             : {
     799             :     OSL_ENSURE(!i_rURI.isEmpty(), "DMA::DMA: no URI given!");
     800             :     OSL_ENSURE(i_rURI.endsWithAsciiL("/", 1), "DMA::DMA: URI without / given!");
     801          13 :     if (!i_rURI.endsWithAsciiL("/", 1)) throw uno::RuntimeException();
     802          13 :     m_pImpl->m_xBaseURI.set(rdf::URI::create(m_pImpl->m_xContext, i_rURI));
     803          26 :     m_pImpl->m_xRepository.set(rdf::Repository::create(m_pImpl->m_xContext),
     804          26 :             uno::UNO_SET_THROW);
     805             : 
     806             :     // init repository
     807          13 :     init(*m_pImpl);
     808             : 
     809             :     OSL_ENSURE(m_pImpl->m_xBaseURI.is(), "base URI is null");
     810             :     OSL_ENSURE(m_pImpl->m_xRepository.is(), "repository is null");
     811             :     OSL_ENSURE(m_pImpl->m_xManifest.is(), "manifest is null");
     812          13 : }
     813             : 
     814         256 : DocumentMetadataAccess::~DocumentMetadataAccess()
     815             : {
     816         256 : }
     817             : 
     818             : // ::com::sun::star::rdf::XRepositorySupplier:
     819             : uno::Reference< rdf::XRepository > SAL_CALL
     820          95 : DocumentMetadataAccess::getRDFRepository() throw (uno::RuntimeException, std::exception)
     821             : {
     822             :     OSL_ENSURE(m_pImpl->m_xRepository.is(), "repository not initialized");
     823          95 :     return m_pImpl->m_xRepository;
     824             : }
     825             : 
     826             : // ::com::sun::star::rdf::XNode:
     827             : OUString SAL_CALL
     828         335 : DocumentMetadataAccess::getStringValue() throw (uno::RuntimeException, std::exception)
     829             : {
     830         335 :     return m_pImpl->m_xBaseURI->getStringValue();
     831             : }
     832             : 
     833             : // ::com::sun::star::rdf::XURI:
     834             : OUString SAL_CALL
     835           0 : DocumentMetadataAccess::getNamespace() throw (uno::RuntimeException, std::exception)
     836             : {
     837           0 :     return m_pImpl->m_xBaseURI->getNamespace();
     838             : }
     839             : 
     840             : OUString SAL_CALL
     841           0 : DocumentMetadataAccess::getLocalName() throw (uno::RuntimeException, std::exception)
     842             : {
     843           0 :     return m_pImpl->m_xBaseURI->getLocalName();
     844             : }
     845             : 
     846             : // ::com::sun::star::rdf::XDocumentMetadataAccess:
     847             : uno::Reference< rdf::XMetadatable > SAL_CALL
     848           1 : DocumentMetadataAccess::getElementByMetadataReference(
     849             :     const ::com::sun::star::beans::StringPair & i_rReference)
     850             : throw (uno::RuntimeException, std::exception)
     851             : {
     852             :     const IXmlIdRegistry * pReg(
     853           1 :         m_pImpl->m_rXmlIdRegistrySupplier.GetXmlIdRegistry() );
     854           1 :     if (!pReg) {
     855             :         throw uno::RuntimeException(OUString(
     856           0 :             "DocumentMetadataAccess::getElementByXmlId: no registry"), *this);
     857             :     }
     858           1 :     return pReg->GetElementByMetadataReference(i_rReference);
     859             : }
     860             : 
     861             : uno::Reference< rdf::XMetadatable > SAL_CALL
     862           2 : DocumentMetadataAccess::getElementByURI(
     863             :     const uno::Reference< rdf::XURI > & i_xURI )
     864             : throw (uno::RuntimeException, lang::IllegalArgumentException, std::exception)
     865             : {
     866           2 :     if (!i_xURI.is()) {
     867             :         throw lang::IllegalArgumentException(OUString(
     868           1 :             "DocumentMetadataAccess::getElementByURI: URI is null"), *this, 0);
     869             :     }
     870             : 
     871           1 :     const OUString baseURI( m_pImpl->m_xBaseURI->getStringValue() );
     872           2 :     const OUString name( i_xURI->getStringValue() );
     873           1 :     if (!name.match(baseURI)) {
     874           0 :         return 0;
     875             :     }
     876           2 :     const OUString relName( name.copy(baseURI.getLength()) );
     877           2 :     OUString path;
     878           2 :     OUString idref;
     879           1 :     if (!splitXmlId(relName, path, idref)) {
     880           0 :         return 0;
     881             :     }
     882             : 
     883           2 :     return getElementByMetadataReference( beans::StringPair(path, idref) );
     884             : }
     885             : 
     886             : 
     887             : uno::Sequence< uno::Reference< rdf::XURI > > SAL_CALL
     888           2 : DocumentMetadataAccess::getMetadataGraphsWithType(
     889             :     const uno::Reference<rdf::XURI> & i_xType)
     890             : throw (uno::RuntimeException, lang::IllegalArgumentException, std::exception)
     891             : {
     892           2 :     if (!i_xType.is()) {
     893             :         throw lang::IllegalArgumentException(OUString(
     894             :             "DocumentMetadataAccess::getMetadataGraphsWithType: "
     895           1 :             "type is null"), *this, 0);
     896             :     }
     897             : 
     898           1 :     ::comphelper::SequenceAsVector< uno::Reference< rdf::XURI > > ret;
     899             :     const ::std::vector< uno::Reference< rdf::XURI > > parts(
     900           2 :         getAllParts(*m_pImpl) );
     901             :     ::std::remove_copy_if(parts.begin(), parts.end(),
     902             :         ::std::back_inserter(ret),
     903             :         ::boost::bind(
     904             :             ::std::logical_not<bool>(),
     905           1 :             ::boost::bind(&isPartOfType, ::boost::ref(*m_pImpl), _1, i_xType) ));
     906           2 :     return ret.getAsConstList();
     907             : }
     908             : 
     909             : uno::Reference<rdf::XURI> SAL_CALL
     910          12 : DocumentMetadataAccess::addMetadataFile(const OUString & i_rFileName,
     911             :     const uno::Sequence < uno::Reference< rdf::XURI > > & i_rTypes)
     912             : throw (uno::RuntimeException, lang::IllegalArgumentException,
     913             :     container::ElementExistException, std::exception)
     914             : {
     915          12 :     if (!isFileNameValid(i_rFileName)) {
     916             :         throw lang::IllegalArgumentException(OUString(
     917             :             "DocumentMetadataAccess::addMetadataFile: invalid FileName"),
     918           6 :             *this, 0);
     919             :     }
     920           6 :     if (isReservedFile(i_rFileName)) {
     921             :         throw lang::IllegalArgumentException(OUString(
     922             :             "DocumentMetadataAccess::addMetadataFile:"
     923           4 :             "invalid FileName: reserved"), *this, 0);
     924             :     }
     925           3 :     for (sal_Int32 i = 0; i < i_rTypes.getLength(); ++i) {
     926           1 :         if (!i_rTypes[i].is()) {
     927             :             throw lang::IllegalArgumentException(
     928             :                 OUString(
     929             :                     "DocumentMetadataAccess::addMetadataFile: "
     930           0 :                     "null type"), *this, 2);
     931             :         }
     932             :     }
     933             : 
     934             :     const uno::Reference<rdf::XURI> xGraphName(
     935           2 :         getURIForStream(*m_pImpl, i_rFileName) );
     936             : 
     937             :     try {
     938           2 :         m_pImpl->m_xRepository->createGraph(xGraphName);
     939           0 :     } catch (const rdf::RepositoryException & e) {
     940             :         throw lang::WrappedTargetRuntimeException(
     941             :             OUString(
     942             :                 "DocumentMetadataAccess::addMetadataFile: exception"),
     943           0 :             *this, uno::makeAny(e));
     944             :         // note: all other exceptions are propagated
     945             :     }
     946             : 
     947           2 :     addMetadataFileImpl(*m_pImpl, i_rFileName, i_rTypes);
     948           2 :     return xGraphName;
     949             : }
     950             : 
     951             : uno::Reference<rdf::XURI> SAL_CALL
     952           5 : DocumentMetadataAccess::importMetadataFile(::sal_Int16 i_Format,
     953             :     const uno::Reference< io::XInputStream > & i_xInStream,
     954             :     const OUString & i_rFileName,
     955             :     const uno::Reference< rdf::XURI > & i_xBaseURI,
     956             :     const uno::Sequence < uno::Reference< rdf::XURI > > & i_rTypes)
     957             : throw (uno::RuntimeException, lang::IllegalArgumentException,
     958             :     datatransfer::UnsupportedFlavorException,
     959             :     container::ElementExistException, rdf::ParseException, io::IOException, std::exception)
     960             : {
     961           5 :     if (!isFileNameValid(i_rFileName)) {
     962             :         throw lang::IllegalArgumentException(OUString(
     963             :             "DocumentMetadataAccess::importMetadataFile: invalid FileName"),
     964           1 :             *this, 0);
     965             :     }
     966           4 :     if (isReservedFile(i_rFileName)) {
     967             :         throw lang::IllegalArgumentException(OUString(
     968             :             "DocumentMetadataAccess::importMetadataFile:"
     969           1 :             "invalid FileName: reserved"), *this, 0);
     970             :     }
     971           3 :     for (sal_Int32 i = 0; i < i_rTypes.getLength(); ++i) {
     972           0 :         if (!i_rTypes[i].is()) {
     973             :             throw lang::IllegalArgumentException(
     974             :                 OUString(
     975             :                     "DocumentMetadataAccess::importMetadataFile: null type"),
     976           0 :                 *this, 5);
     977             :         }
     978             :     }
     979             : 
     980             :     const uno::Reference<rdf::XURI> xGraphName(
     981           3 :         getURIForStream(*m_pImpl, i_rFileName) );
     982             : 
     983             :     try {
     984           3 :         m_pImpl->m_xRepository->importGraph(
     985           3 :             i_Format, i_xInStream, xGraphName, i_xBaseURI);
     986           0 :     } catch (const rdf::RepositoryException & e) {
     987             :         throw lang::WrappedTargetRuntimeException(
     988             :             OUString(
     989             :                 "DocumentMetadataAccess::importMetadataFile: "
     990           0 :                 "RepositoryException"), *this, uno::makeAny(e));
     991             :         // note: all other exceptions are propagated
     992             :     }
     993             : 
     994             :     // add to manifest
     995           0 :     addMetadataFileImpl(*m_pImpl, i_rFileName, i_rTypes);
     996           0 :     return xGraphName;
     997             : }
     998             : 
     999             : void SAL_CALL
    1000           2 : DocumentMetadataAccess::removeMetadataFile(
    1001             :     const uno::Reference< rdf::XURI > & i_xGraphName)
    1002             : throw (uno::RuntimeException, lang::IllegalArgumentException,
    1003             :     container::NoSuchElementException, std::exception)
    1004             : {
    1005             :     try {
    1006           2 :         m_pImpl->m_xRepository->destroyGraph(i_xGraphName);
    1007           0 :     } catch (const rdf::RepositoryException & e) {
    1008             :         throw lang::WrappedTargetRuntimeException(
    1009             :             OUString(
    1010             :                 "DocumentMetadataAccess::removeMetadataFile: "
    1011           0 :                 "RepositoryException"), *this, uno::makeAny(e));
    1012             :         // note: all other exceptions are propagated
    1013             :     }
    1014             : 
    1015             :     // remove file from manifest
    1016           1 :     removeFile(*m_pImpl, i_xGraphName.get());
    1017           1 : }
    1018             : 
    1019             : void SAL_CALL
    1020           5 : DocumentMetadataAccess::addContentOrStylesFile(
    1021             :     const OUString & i_rFileName)
    1022             : throw (uno::RuntimeException, lang::IllegalArgumentException,
    1023             :     container::ElementExistException, std::exception)
    1024             : {
    1025           5 :     if (!isFileNameValid(i_rFileName)) {
    1026             :         throw lang::IllegalArgumentException(OUString(
    1027             :             "DocumentMetadataAccess::addContentOrStylesFile: "
    1028           2 :             "invalid FileName"), *this, 0);
    1029             :     }
    1030             : 
    1031           3 :     if (!addContentOrStylesFileImpl(*m_pImpl, i_rFileName)) {
    1032             :         throw lang::IllegalArgumentException(OUString(
    1033             :             "DocumentMetadataAccess::addContentOrStylesFile: "
    1034             :             "invalid FileName: must end with content.xml or styles.xml"),
    1035           1 :             *this, 0);
    1036             :     }
    1037           2 : }
    1038             : 
    1039             : void SAL_CALL
    1040           3 : DocumentMetadataAccess::removeContentOrStylesFile(
    1041             :     const OUString & i_rFileName)
    1042             : throw (uno::RuntimeException, lang::IllegalArgumentException,
    1043             :     container::NoSuchElementException, std::exception)
    1044             : {
    1045           3 :     if (!isFileNameValid(i_rFileName)) {
    1046             :         throw lang::IllegalArgumentException(OUString(
    1047             :             "DocumentMetadataAccess::removeContentOrStylesFile: "
    1048           1 :             "invalid FileName"), *this, 0);
    1049             :     }
    1050             : 
    1051             :     try {
    1052             :         const uno::Reference<rdf::XURI> xPart(
    1053           2 :             getURIForStream(*m_pImpl, i_rFileName) );
    1054             :         const uno::Reference<container::XEnumeration> xEnum(
    1055           4 :             m_pImpl->m_xManifest->getStatements( m_pImpl->m_xBaseURI.get(),
    1056           2 :                 getURI<rdf::URIs::PKG_HASPART>(m_pImpl->m_xContext),
    1057           2 :                 xPart.get()),
    1058           8 :             uno::UNO_SET_THROW);
    1059           2 :         if (!xEnum->hasMoreElements()) {
    1060             :             throw container::NoSuchElementException(
    1061             :                 OUString(
    1062             :                     "DocumentMetadataAccess::removeContentOrStylesFile: "
    1063           0 :                     "cannot find stream in manifest graph: ") + i_rFileName,
    1064           0 :                 *this);
    1065             :         }
    1066             : 
    1067             :         // remove file from manifest
    1068           4 :         removeFile(*m_pImpl, xPart);
    1069             : 
    1070           0 :     } catch (const uno::RuntimeException &) {
    1071           0 :         throw;
    1072           0 :     } catch (const uno::Exception & e) {
    1073             :         throw lang::WrappedTargetRuntimeException(
    1074             :             OUString(
    1075             :                 "DocumentMetadataAccess::removeContentOrStylesFile: exception"),
    1076           0 :             *this, uno::makeAny(e));
    1077             :     }
    1078           2 : }
    1079             : 
    1080         120 : void SAL_CALL DocumentMetadataAccess::loadMetadataFromStorage(
    1081             :     const uno::Reference< embed::XStorage > & i_xStorage,
    1082             :     const uno::Reference<rdf::XURI> & i_xBaseURI,
    1083             :     const uno::Reference<task::XInteractionHandler> & i_xHandler)
    1084             : throw (uno::RuntimeException, lang::IllegalArgumentException,
    1085             :     lang::WrappedTargetException, std::exception)
    1086             : {
    1087         120 :     if (!i_xStorage.is()) {
    1088             :         throw lang::IllegalArgumentException(OUString(
    1089             :             "DocumentMetadataAccess::loadMetadataFromStorage: "
    1090           1 :             "storage is null"), *this, 0);
    1091             :     }
    1092         119 :     if (!i_xBaseURI.is()) {
    1093             :         throw lang::IllegalArgumentException(OUString(
    1094             :             "DocumentMetadataAccess::loadMetadataFromStorage: "
    1095           0 :             "base URI is null"), *this, 1);
    1096             :     }
    1097         119 :     const OUString baseURI( i_xBaseURI->getStringValue());
    1098         119 :     if (baseURI.indexOf('#') >= 0) {
    1099             :         throw lang::IllegalArgumentException(OUString(
    1100             :             "DocumentMetadataAccess::loadMetadataFromStorage: "
    1101           0 :             "base URI not absolute"), *this, 1);
    1102             :     }
    1103         119 :     if (baseURI.isEmpty() || !baseURI.endsWithAsciiL("/", 1)) {
    1104             :         throw lang::IllegalArgumentException(OUString(
    1105             :             "DocumentMetadataAccess::loadMetadataFromStorage: "
    1106           0 :             "base URI does not end with slash"), *this, 1);
    1107             :     }
    1108             : 
    1109         119 :     initLoading(*m_pImpl, i_xStorage, i_xBaseURI, i_xHandler);
    1110             : 
    1111         238 :     std::set< OUString > StgFiles;
    1112             :     collectFilesFromStorage(i_xStorage,
    1113         119 :         OUString(""), StgFiles);
    1114             : 
    1115         238 :     std::vector< OUString > MfstMetadataFiles;
    1116             : 
    1117             :     try {
    1118             :         const ::std::vector< uno::Reference< rdf::XURI > > parts(
    1119         119 :             getAllParts(*m_pImpl) );
    1120             :         const uno::Reference<rdf::XURI> xContentFile(
    1121         238 :             getURI<rdf::URIs::ODF_CONTENTFILE>(m_pImpl->m_xContext));
    1122             :         const uno::Reference<rdf::XURI> xStylesFile(
    1123         238 :             getURI<rdf::URIs::ODF_STYLESFILE>(m_pImpl->m_xContext));
    1124             :         const uno::Reference<rdf::XURI> xMetadataFile(
    1125         238 :             getURI<rdf::URIs::PKG_METADATAFILE>(m_pImpl->m_xContext));
    1126         119 :         const sal_Int32 len( baseURI.getLength() );
    1127             :         const OUString manifest (
    1128         238 :                 OUString::createFromAscii(s_manifest));
    1129         729 :         for (::std::vector< uno::Reference< rdf::XURI > >::const_iterator it
    1130         119 :                 = parts.begin();
    1131         486 :                 it != parts.end(); ++it) {
    1132         124 :             const OUString name((*it)->getStringValue());
    1133         124 :             if (!name.match(baseURI)) {
    1134             :                 OSL_TRACE("loadMetadataFromStorage: graph not in document: %s",
    1135             :                     OUStringToOString(name, RTL_TEXTENCODING_UTF8)
    1136             :                     .getStr());
    1137           0 :                 continue;
    1138             :             }
    1139         248 :             const OUString relName( name.copy(len) );
    1140         124 :             if (relName == manifest) {
    1141             :                 OSL_TRACE("loadMetadataFromStorage: "
    1142             :                     "found ourselves a recursive manifest!");
    1143           0 :                 continue;
    1144             :             }
    1145             :             // remove found items from StgFiles
    1146         124 :             StgFiles.erase(relName);
    1147         124 :             if (isContentFile(relName)) {
    1148          61 :                 if (!isPartOfType(*m_pImpl, *it, xContentFile)) {
    1149             :                     const uno::Reference <rdf::XURI> xName(
    1150           0 :                         getURIForStream(*m_pImpl, relName) );
    1151             :                     // add missing type statement
    1152           0 :                     m_pImpl->m_xManifest->addStatement(xName.get(),
    1153           0 :                         getURI<rdf::URIs::RDF_TYPE>(m_pImpl->m_xContext),
    1154           0 :                         xContentFile.get());
    1155             :                 }
    1156          63 :             } else if (isStylesFile(relName)) {
    1157          61 :                 if (!isPartOfType(*m_pImpl, *it, xStylesFile)) {
    1158             :                     const uno::Reference <rdf::XURI> xName(
    1159           0 :                         getURIForStream(*m_pImpl, relName) );
    1160             :                     // add missing type statement
    1161           0 :                     m_pImpl->m_xManifest->addStatement(xName.get(),
    1162           0 :                         getURI<rdf::URIs::RDF_TYPE>(m_pImpl->m_xContext),
    1163           0 :                         xStylesFile.get());
    1164             :                 }
    1165           2 :             } else if (isReservedFile(relName)) {
    1166             :                 OSL_TRACE("loadMetadataFromStorage: "
    1167             :                     "reserved file name in manifest");
    1168             :             } else {
    1169           2 :                 if (isPartOfType(*m_pImpl, *it, xMetadataFile)) {
    1170           2 :                     MfstMetadataFiles.push_back(relName);
    1171             :                 }
    1172             :                 // do not add statement for MetadataFile; it could be
    1173             :                 // something else! just ignore it...
    1174             :             }
    1175         243 :         }
    1176           0 :     } catch (const uno::RuntimeException &) {
    1177           0 :         throw;
    1178           0 :     } catch (const uno::Exception & e) {
    1179             :         throw lang::WrappedTargetRuntimeException(
    1180             :             OUString(
    1181             :                 "DocumentMetadataAccess::loadMetadataFromStorage: "
    1182           0 :                 "exception"), *this, uno::makeAny(e));
    1183             :     }
    1184             : 
    1185             :     std::for_each(StgFiles.begin(), StgFiles.end(),
    1186         119 :         boost::bind(addContentOrStylesFileImpl, boost::ref(*m_pImpl), _1));
    1187             : 
    1188             :     std::for_each(MfstMetadataFiles.begin(), MfstMetadataFiles.end(),
    1189         119 :         boost::bind(importFile, boost::ref(*m_pImpl),
    1190         357 :             i_xStorage, baseURI, i_xHandler, _1));
    1191         119 : }
    1192             : 
    1193          28 : void SAL_CALL DocumentMetadataAccess::storeMetadataToStorage(
    1194             :     const uno::Reference< embed::XStorage > & i_xStorage)
    1195             : throw (uno::RuntimeException, lang::IllegalArgumentException,
    1196             :     lang::WrappedTargetException, std::exception)
    1197             : {
    1198          28 :     if (!i_xStorage.is()) {
    1199             :         throw lang::IllegalArgumentException(OUString(
    1200             :             "DocumentMetadataAccess::storeMetadataToStorage: "
    1201           1 :             "storage is null"), *this, 0);
    1202             :     }
    1203             : 
    1204             :     // export manifest
    1205             :     const OUString manifest (
    1206          27 :             OUString::createFromAscii(s_manifest));
    1207             :     const uno::Reference <rdf::XURI> xManifest(
    1208          54 :         getURIForStream(*m_pImpl, manifest) );
    1209          54 :     const OUString baseURI( m_pImpl->m_xBaseURI->getStringValue() );
    1210             :     try {
    1211          27 :         writeStream(*m_pImpl, i_xStorage, xManifest, manifest, baseURI);
    1212           0 :     } catch (const uno::RuntimeException &) {
    1213           0 :         throw;
    1214           0 :     } catch (const io::IOException & e) {
    1215             :         throw lang::WrappedTargetException( OUString(
    1216           0 :             "storeMetadataToStorage: IO exception"), *this, uno::makeAny(e));
    1217           0 :     } catch (const uno::Exception & e) {
    1218             :         throw lang::WrappedTargetRuntimeException(
    1219             :             OUString(
    1220           0 :                 "storeMetadataToStorage: exception"), *this, uno::makeAny(e));
    1221             :     }
    1222             : 
    1223             :     // export metadata streams
    1224             :     try {
    1225             :         const uno::Sequence<uno::Reference<rdf::XURI> > graphs(
    1226          27 :             m_pImpl->m_xRepository->getGraphNames());
    1227          27 :         const sal_Int32 len( baseURI.getLength() );
    1228          56 :         for (sal_Int32 i = 0; i < graphs.getLength(); ++i) {
    1229          29 :             const uno::Reference<rdf::XURI> xName(graphs[i]);
    1230          31 :             const OUString name(xName->getStringValue());
    1231          29 :             if (!name.match(baseURI)) {
    1232             :                 OSL_TRACE("storeMetadataToStorage: graph not in document: %s",
    1233             :                     OUStringToOString(name, RTL_TEXTENCODING_UTF8)
    1234             :                     .getStr());
    1235           0 :                 continue;
    1236             :             }
    1237          31 :             const OUString relName( name.copy(len) );
    1238          29 :             if (relName == manifest) {
    1239          27 :                 continue;
    1240             :             }
    1241           2 :             if (!isFileNameValid(relName) || isReservedFile(relName)) {
    1242             :                 OSL_TRACE("storeMetadataToStorage: invalid file name: %s",
    1243             :                     OUStringToOString(relName, RTL_TEXTENCODING_UTF8)
    1244             :                     .getStr());
    1245           0 :                 continue;
    1246             :             }
    1247             :             try {
    1248           2 :                 writeStream(*m_pImpl, i_xStorage, xName, relName, baseURI);
    1249           0 :             } catch (const uno::RuntimeException &) {
    1250           0 :                 throw;
    1251           0 :             } catch (const io::IOException & e) {
    1252             :                 throw lang::WrappedTargetException(
    1253             :                     OUString(
    1254             :                         "storeMetadataToStorage: IO exception"),
    1255           0 :                     *this, uno::makeAny(e));
    1256           0 :             } catch (const uno::Exception & e) {
    1257             :                 throw lang::WrappedTargetRuntimeException(
    1258             :                     OUString(
    1259             :                         "storeMetadataToStorage: exception"),
    1260           0 :                     *this, uno::makeAny(e));
    1261             :             }
    1262          29 :         }
    1263           0 :     } catch (const rdf::RepositoryException & e) {
    1264             :         throw lang::WrappedTargetRuntimeException(
    1265             :             OUString(
    1266           0 :                 "storeMetadataToStorage: exception"), *this, uno::makeAny(e));
    1267          27 :     }
    1268          27 : }
    1269             : 
    1270             : void SAL_CALL
    1271           4 : DocumentMetadataAccess::loadMetadataFromMedium(
    1272             :     const uno::Sequence< beans::PropertyValue > & i_rMedium)
    1273             : throw (uno::RuntimeException, lang::IllegalArgumentException,
    1274             :     lang::WrappedTargetException, std::exception)
    1275             : {
    1276           4 :     uno::Reference<io::XInputStream> xIn;
    1277           8 :     utl::MediaDescriptor md(i_rMedium);
    1278           8 :     OUString URL;
    1279           4 :     md[ utl::MediaDescriptor::PROP_URL() ] >>= URL;
    1280           8 :     OUString BaseURL;
    1281           4 :     md[ utl::MediaDescriptor::PROP_DOCUMENTBASEURL() ] >>= BaseURL;
    1282           4 :     if (md.addInputStream()) {
    1283           3 :         md[ utl::MediaDescriptor::PROP_INPUTSTREAM() ] >>= xIn;
    1284             :     }
    1285           4 :     if (!xIn.is() && URL.isEmpty()) {
    1286             :         throw lang::IllegalArgumentException(OUString(
    1287             :             "DocumentMetadataAccess::loadMetadataFromMedium: "
    1288           1 :             "inalid medium: no URL, no input stream"), *this, 0);
    1289             :     }
    1290           6 :     uno::Reference<embed::XStorage> xStorage;
    1291             :     try {
    1292           3 :         if (xIn.is()) {
    1293           6 :             xStorage = ::comphelper::OStorageHelper::GetStorageFromInputStream(
    1294           6 :                             xIn, m_pImpl->m_xContext);
    1295             :         } else { // fallback to url
    1296           0 :             xStorage = ::comphelper::OStorageHelper::GetStorageFromURL2(
    1297           0 :                             URL, embed::ElementModes::READ, m_pImpl->m_xContext);
    1298             :         }
    1299           0 :     } catch (const uno::RuntimeException &) {
    1300           0 :         throw;
    1301           0 :     } catch (const io::IOException &) {
    1302           0 :         throw;
    1303           0 :     } catch (const uno::Exception & e) {
    1304             :         throw lang::WrappedTargetException(
    1305             :                 OUString(
    1306             :                     "DocumentMetadataAccess::loadMetadataFromMedium: "
    1307           0 :                     "exception"), *this, uno::makeAny(e));
    1308             :     }
    1309           3 :     if (!xStorage.is()) {
    1310             :         throw uno::RuntimeException(OUString(
    1311             :             "DocumentMetadataAccess::loadMetadataFromMedium: "
    1312           0 :             "cannot get Storage"), *this);
    1313             :     }
    1314           6 :     uno::Reference<rdf::XURI> xBaseURI;
    1315             :     try {
    1316           3 :         xBaseURI = createBaseURI(m_pImpl->m_xContext, xStorage, BaseURL);
    1317           3 :     } catch (const uno::Exception &) {
    1318             :         // fall back to URL
    1319             :         try {
    1320           3 :             xBaseURI = createBaseURI(m_pImpl->m_xContext, xStorage, URL);
    1321           0 :         } catch (const uno::Exception &) {
    1322             :             OSL_FAIL("cannot create base URI");
    1323             :         }
    1324             :     }
    1325           6 :     uno::Reference<task::XInteractionHandler> xIH;
    1326           3 :     md[ utl::MediaDescriptor::PROP_INTERACTIONHANDLER() ] >>= xIH;
    1327           7 :     loadMetadataFromStorage(xStorage, xBaseURI, xIH);
    1328           3 : }
    1329             : 
    1330             : void SAL_CALL
    1331           2 : DocumentMetadataAccess::storeMetadataToMedium(
    1332             :     const uno::Sequence< beans::PropertyValue > & i_rMedium)
    1333             : throw (uno::RuntimeException, lang::IllegalArgumentException,
    1334             :     lang::WrappedTargetException, std::exception)
    1335             : {
    1336           2 :     utl::MediaDescriptor md(i_rMedium);
    1337           4 :     OUString URL;
    1338           2 :     md[ utl::MediaDescriptor::PROP_URL() ] >>= URL;
    1339           2 :     if (URL.isEmpty()) {
    1340             :         throw lang::IllegalArgumentException(OUString(
    1341             :             "DocumentMetadataAccess::storeMetadataToMedium: "
    1342           1 :             "invalid medium: no URL"), *this, 0);
    1343             :     }
    1344             : 
    1345           2 :     SfxMedium aMedium(i_rMedium);
    1346           2 :     uno::Reference<embed::XStorage> xStorage(aMedium.GetOutputStorage());
    1347             : 
    1348           1 :     bool sfx(false);
    1349           1 :     if (xStorage.is()) {
    1350           1 :         sfx = true;
    1351             :     } else {
    1352           0 :         xStorage = ::comphelper::OStorageHelper::GetStorageFromURL2(
    1353           0 :                         URL, embed::ElementModes::WRITE, m_pImpl->m_xContext);
    1354             :     }
    1355             : 
    1356           1 :     if (!xStorage.is()) {
    1357             :         throw uno::RuntimeException(OUString(
    1358             :             "DocumentMetadataAccess::storeMetadataToMedium: "
    1359           0 :             "cannot get Storage"), *this);
    1360             :     }
    1361             :     // set MIME type of the storage
    1362             :     utl::MediaDescriptor::const_iterator iter
    1363           1 :         = md.find(utl::MediaDescriptor::PROP_MEDIATYPE());
    1364           1 :     if (iter != md.end()) {
    1365             :         uno::Reference< beans::XPropertySet > xProps(xStorage,
    1366           1 :             uno::UNO_QUERY_THROW);
    1367             :         try {
    1368             :             // this is NOT supported in FileSystemStorage
    1369           1 :             xProps->setPropertyValue(
    1370           1 :                 utl::MediaDescriptor::PROP_MEDIATYPE(),
    1371           2 :                 iter->second);
    1372           1 :         } catch (const uno::Exception &) { }
    1373             :     }
    1374           1 :     storeMetadataToStorage(xStorage);
    1375             : 
    1376           1 :     if (sfx) {
    1377           1 :         const bool bOk = aMedium.Commit();
    1378           1 :         aMedium.Close();
    1379           1 :         if ( !bOk ) {
    1380           0 :             sal_uInt32 nError = aMedium.GetError();
    1381           0 :             if ( nError == ERRCODE_NONE ) {
    1382           0 :                 nError = ERRCODE_IO_GENERAL;
    1383             :             }
    1384             :             task::ErrorCodeIOException ex(
    1385             :                 ("DocumentMetadataAccess::storeMetadataToMedium Commit failed: "
    1386           0 :                  "0x" + OUString::number(nError, 16)),
    1387           0 :                 uno::Reference< uno::XInterface >(), nError);
    1388             :             throw lang::WrappedTargetException(OUString(), *this,
    1389           0 :                     uno::makeAny(ex));
    1390             :         }
    1391           2 :     }
    1392           1 : }
    1393             : 
    1394         447 : } // namespace sfx2
    1395             : 
    1396             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10