LCOV - code coverage report
Current view: top level - oox/source/core - xmlfilterbase.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 241 289 83.4 %
Date: 2014-04-11 Functions: 40 42 95.2 %
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             : #include "oox/core/xmlfilterbase.hxx"
      21             : 
      22             : #include <cstdio>
      23             : #include <set>
      24             : #include <com/sun/star/container/XNameContainer.hpp>
      25             : #include <com/sun/star/embed/XRelationshipAccess.hpp>
      26             : #include <com/sun/star/xml/sax/InputSource.hpp>
      27             : #include <com/sun/star/xml/sax/XFastParser.hpp>
      28             : #include <com/sun/star/xml/sax/XFastSAXSerializable.hpp>
      29             : #include <com/sun/star/document/XDocumentProperties.hpp>
      30             : #include <unotools/mediadescriptor.hxx>
      31             : #include <sax/fshelper.hxx>
      32             : #include <rtl/strbuf.hxx>
      33             : #include <rtl/ustrbuf.hxx>
      34             : #include <rtl/instance.hxx>
      35             : #include <i18nlangtag/languagetag.hxx>
      36             : #include "oox/core/fastparser.hxx"
      37             : #include "oox/core/filterdetect.hxx"
      38             : #include "oox/core/fragmenthandler.hxx"
      39             : #include "oox/core/recordparser.hxx"
      40             : #include "oox/core/relationshandler.hxx"
      41             : #include "oox/helper/containerhelper.hxx"
      42             : #include "oox/helper/propertyset.hxx"
      43             : #include "oox/helper/zipstorage.hxx"
      44             : #include "oox/token/properties.hxx"
      45             : #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
      46             : #include <com/sun/star/document/XOOXMLDocumentPropertiesImporter.hpp>
      47             : #include <com/sun/star/xml/dom/XDocument.hpp>
      48             : #include <com/sun/star/xml/dom/DocumentBuilder.hpp>
      49             : #include <comphelper/processfactory.hxx>
      50             : #include <oox/core/filterdetect.hxx>
      51             : #include <comphelper/storagehelper.hxx>
      52             : 
      53             : #include <oox/crypto/DocumentEncryption.hxx>
      54             : 
      55             : using ::com::sun::star::xml::dom::DocumentBuilder;
      56             : using ::com::sun::star::xml::dom::XDocument;
      57             : using ::com::sun::star::xml::dom::XDocumentBuilder;
      58             : 
      59             : namespace oox {
      60             : namespace core {
      61             : 
      62             : using namespace ::com::sun::star;
      63             : using namespace ::com::sun::star::beans;
      64             : using namespace ::com::sun::star::container;
      65             : using namespace ::com::sun::star::document;
      66             : using namespace ::com::sun::star::embed;
      67             : using namespace ::com::sun::star::io;
      68             : using namespace ::com::sun::star::lang;
      69             : using namespace ::com::sun::star::uno;
      70             : using namespace ::com::sun::star::xml::sax;
      71             : 
      72             : using utl::MediaDescriptor;
      73             : using ::sax_fastparser::FSHelperPtr;
      74             : using ::sax_fastparser::FastSerializerHelper;
      75             : 
      76             : namespace {
      77             : 
      78        1703 : bool lclHasSuffix( const OUString& rFragmentPath, const OUString& rSuffix )
      79             : {
      80        1703 :     sal_Int32 nSuffixPos = rFragmentPath.getLength() - rSuffix.getLength();
      81        1703 :     return (nSuffixPos >= 0) && rFragmentPath.match( rSuffix, nSuffixPos );
      82             : }
      83             : 
      84             : struct NamespaceIds: public rtl::StaticWithInit<
      85             :     Sequence< beans::Pair< OUString, sal_Int32 > >,
      86             :     NamespaceIds>
      87             : {
      88          14 :     Sequence< beans::Pair< OUString, sal_Int32 > > operator()()
      89             :     {
      90             :         static const char* const namespaceURIs[] = {
      91             :             "http://www.w3.org/XML/1998/namespace",
      92             :             "http://schemas.openxmlformats.org/package/2006/relationships",
      93             :             "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
      94             :             "http://purl.oclc.org/ooxml/officeDocument/relationships",
      95             :             "http://schemas.openxmlformats.org/drawingml/2006/main",
      96             :             "http://purl.oclc.org/ooxml/drawingml/main",
      97             :             "http://schemas.openxmlformats.org/drawingml/2006/diagram",
      98             :             "http://purl.oclc.org/ooxml/drawingml/diagram",
      99             :             "http://schemas.openxmlformats.org/drawingml/2006/chart",
     100             :             "http://schemas.openxmlformats.org/drawingml/2006/chartDrawing",
     101             :             "urn:schemas-microsoft-com:vml",
     102             :             "urn:schemas-microsoft-com:office:office",
     103             :             "urn:schemas-microsoft-com:office:word",
     104             :             "urn:schemas-microsoft-com:office:excel",
     105             :             "urn:schemas-microsoft-com:office:powerpoint",
     106             :             "http://schemas.microsoft.com/office/2006/activeX",
     107             :             "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
     108             :             "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing",
     109             :             "http://schemas.microsoft.com/office/excel/2006/main",
     110             :             "http://schemas.openxmlformats.org/presentationml/2006/main",
     111             :             "http://schemas.openxmlformats.org/markup-compatibility/2006",
     112             :             "http://schemas.openxmlformats.org/spreadsheetml/2006/main/v2",
     113             :             "http://schemas.microsoft.com/office/drawing/2008/diagram",
     114             :             "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"
     115             :         };
     116             : 
     117             :         static const sal_Int32 namespaceIds[] = {
     118             :             NMSP_xml,
     119             :             NMSP_packageRel,
     120             :             NMSP_officeRel,
     121             :             NMSP_officeRel,
     122             :             NMSP_dml,
     123             :             NMSP_dml,
     124             :             NMSP_dmlDiagram,
     125             :             NMSP_dmlDiagram,
     126             :             NMSP_dmlChart,
     127             :             NMSP_dmlChartDr,
     128             :             NMSP_vml,
     129             :             NMSP_vmlOffice,
     130             :             NMSP_vmlWord,
     131             :             NMSP_vmlExcel,
     132             :             NMSP_vmlPowerpoint,
     133             :             NMSP_ax,
     134             :             NMSP_xls,
     135             :             NMSP_xm,
     136             :             NMSP_dmlSpreadDr,
     137             :             NMSP_ppt,
     138             :             NMSP_mce,
     139             :             NMSP_mceTest,
     140             :             NMSP_dsp,
     141             :             NMSP_xlsExtLst
     142             :         };
     143             : 
     144          14 :         Sequence< beans::Pair< OUString, sal_Int32 > > aRet(STATIC_ARRAY_SIZE(namespaceIds));
     145         350 :         for( sal_Int32 i=0; i<aRet.getLength(); ++i )
     146        1008 :             aRet[i] = make_Pair(
     147         336 :                 OUString::createFromAscii(namespaceURIs[i]),
     148         336 :                 namespaceIds[i]);
     149          14 :         return aRet;
     150             :     }
     151             : };
     152             : 
     153         809 : void registerNamespaces( FastParser& rParser )
     154             : {
     155         809 :     const Sequence< beans::Pair<OUString, sal_Int32> > ids = NamespaceIds::get();
     156             : 
     157             :     // Filter out duplicates: a namespace can have multiple URL's, think of
     158             :     // strict vs trasitional.
     159        1618 :     std::set<sal_Int32> aSet;
     160       20225 :     for (sal_Int32 i = 0; i < ids.getLength(); ++i)
     161       19416 :         aSet.insert(ids[i].Second);
     162             : 
     163       17798 :     for (std::set<sal_Int32>::iterator it = aSet.begin(); it != aSet.end(); ++it)
     164       17798 :         rParser.registerNamespace(*it);
     165         809 : }
     166             : 
     167             : } // namespace
     168             : 
     169             : struct XmlFilterBaseImpl
     170             : {
     171             :     typedef RefMap< OUString, Relations > RelationsMap;
     172             : 
     173             :     FastParser                     maFastParser;
     174             :     const OUString                 maBinSuffix;
     175             :     const OUString                 maVmlSuffix;
     176             :     RelationsMap                   maRelationsMap;
     177             :     TextFieldStack                 maTextFieldStack;
     178             : 
     179             :     explicit            XmlFilterBaseImpl( const Reference< XComponentContext >& rxContext ) throw( RuntimeException );
     180             :     ~XmlFilterBaseImpl();
     181             : };
     182             : 
     183         809 : XmlFilterBaseImpl::XmlFilterBaseImpl( const Reference< XComponentContext >& rxContext ) throw( RuntimeException ) :
     184             :     maFastParser( rxContext ),
     185             :     maBinSuffix( ".bin" ),
     186         809 :     maVmlSuffix( ".vml" )
     187             : {
     188             :     // register XML namespaces
     189         809 :     registerNamespaces(maFastParser);
     190         809 : }
     191             : 
     192         809 : XmlFilterBaseImpl::~XmlFilterBaseImpl()
     193             : {
     194         809 : }
     195             : 
     196         809 : XmlFilterBase::XmlFilterBase( const Reference< XComponentContext >& rxContext ) throw( RuntimeException ) :
     197             :     FilterBase( rxContext ),
     198         809 :     mxImpl( new XmlFilterBaseImpl( rxContext ) ),
     199             :     mnRelId( 1 ),
     200        1618 :     mnMaxDocId( 0 )
     201             : {
     202         809 : }
     203             : 
     204        1618 : XmlFilterBase::~XmlFilterBase()
     205             : {
     206             :     // #i118640# Reset the DocumentHandler at the FastSaxParser manually; this is
     207             :     // needed since the mechanism is that instances of FragmentHandler execute
     208             :     // their stuff (creating objects, setting attributes, ...) on being destroyed.
     209             :     // They get destroyed by setting a new DocumentHandler. This also happens in
     210             :     // the following implicit destruction chain of ~XmlFilterBaseImpl, but in that
     211             :     // case it's member RelationsMap maRelationsMap will be destroyed, but maybe
     212             :     // still be used by ~FragmentHandler -> crash.
     213         809 :     mxImpl->maFastParser.setDocumentHandler( 0 );
     214         809 : }
     215             : 
     216             : 
     217             : 
     218          44 : void XmlFilterBase::importDocumentProperties()
     219             : {
     220          44 :     Reference< XMultiServiceFactory > xFactory( getComponentContext()->getServiceManager(), UNO_QUERY );
     221          88 :     MediaDescriptor aMediaDesc( getMediaDescriptor() );
     222          88 :     Reference< XInputStream > xInputStream;
     223          88 :     Reference< XComponentContext > xContext = getComponentContext();
     224          88 :     ::oox::core::FilterDetect aDetector( xContext );
     225          44 :     xInputStream = aDetector.extractUnencryptedPackage( aMediaDesc );
     226          88 :     Reference< XComponent > xModel( getModel(), UNO_QUERY );
     227             :     Reference< XStorage > xDocumentStorage (
     228          88 :             ::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream( OFOPXML_STORAGE_FORMAT_STRING, xInputStream ) );
     229          88 :     Reference< XInterface > xTemp = xContext->getServiceManager()->createInstanceWithContext(
     230             :             "com.sun.star.document.OOXMLDocumentPropertiesImporter",
     231          88 :             xContext);
     232          88 :     Reference< XOOXMLDocumentPropertiesImporter > xImporter( xTemp, UNO_QUERY );
     233          88 :     Reference< XDocumentPropertiesSupplier > xPropSupplier( xModel, UNO_QUERY);
     234          88 :     xImporter->importProperties( xDocumentStorage, xPropSupplier->getDocumentProperties() );
     235          44 : }
     236             : 
     237           0 : FastParser* XmlFilterBase::createParser() const
     238             : {
     239           0 :     FastParser* pParser = new FastParser(getComponentContext());
     240           0 :     registerNamespaces(*pParser);
     241           0 :     return pParser;
     242             : }
     243             : 
     244             : namespace {
     245             : 
     246          69 : OUString getTransitionalRelationshipOfficeDocType(const OUString& rPart)
     247             : {
     248          69 :     static const OUString aBase("http://schemas.openxmlformats.org/officeDocument/2006/relationships/");
     249          69 :     return aBase + rPart;
     250             : }
     251             : 
     252           1 : OUString getStrictRelationshipOfficeDocType(const OUString& rPart)
     253             : {
     254           1 :     static const OUString aBase("http://purl.oclc.org/ooxml/officeDocument/relationships/");
     255           1 :     return aBase + rPart;
     256             : }
     257             : 
     258             : }
     259             : 
     260          69 : OUString XmlFilterBase::getFragmentPathFromFirstTypeFromOfficeDoc( const OUString& rPart )
     261             : {
     262             :     // importRelations() caches the relations map for subsequence calls
     263          69 :     const OUString aTransitionalRelationshipType = getTransitionalRelationshipOfficeDocType(rPart);
     264          69 :     OUString aFragment = importRelations( OUString() )->getFragmentPathFromFirstType( aTransitionalRelationshipType );
     265          69 :     if(aFragment.isEmpty())
     266             :     {
     267           1 :         const OUString aStrictRelationshipType = getStrictRelationshipOfficeDocType(rPart);
     268           1 :         aFragment = importRelations( OUString() )->getFragmentPathFromFirstType( aStrictRelationshipType );
     269             :     }
     270             : 
     271          69 :     return aFragment;
     272             : }
     273             : 
     274        1703 : bool XmlFilterBase::importFragment( const rtl::Reference<FragmentHandler>& rxHandler )
     275             : {
     276        1703 :     return importFragment(rxHandler, mxImpl->maFastParser);
     277             : }
     278             : 
     279        1703 : bool XmlFilterBase::importFragment( const rtl::Reference<FragmentHandler>& rxHandler, FastParser& rParser )
     280             : {
     281             :     OSL_ENSURE( rxHandler.is(), "XmlFilterBase::importFragment - missing fragment handler" );
     282        1703 :     if( !rxHandler.is() )
     283           0 :         return false;
     284             : 
     285             :     // fragment handler must contain path to fragment stream
     286        1703 :     OUString aFragmentPath = rxHandler->getFragmentPath();
     287             :     OSL_ENSURE( !aFragmentPath.isEmpty(), "XmlFilterBase::importFragment - missing fragment path" );
     288        1703 :     if( aFragmentPath.isEmpty() )
     289           0 :         return false;
     290             : 
     291             :     // try to import binary streams (fragment extension must be '.bin')
     292        1703 :     if( lclHasSuffix( aFragmentPath, mxImpl->maBinSuffix ) )
     293             :     {
     294             :         try
     295             :         {
     296             :             // try to open the fragment stream (this may fail - do not assert)
     297           0 :             Reference< XInputStream > xInStrm( openInputStream( aFragmentPath ), UNO_SET_THROW );
     298             : 
     299             :             // create the record parser
     300           0 :             RecordParser aParser;
     301           0 :             aParser.setFragmentHandler( rxHandler );
     302             : 
     303             :             // create the input source and parse the stream
     304           0 :             RecordInputSource aSource;
     305           0 :             aSource.mxInStream.reset( new BinaryXInputStream( xInStrm, true ) );
     306           0 :             aSource.maSystemId = aFragmentPath;
     307           0 :             aParser.parseStream( aSource );
     308           0 :             return true;
     309             :         }
     310           0 :         catch( Exception& )
     311             :         {
     312             :         }
     313           0 :         return false;
     314             :     }
     315             : 
     316             :     // get the XFastDocumentHandler interface from the fragment handler
     317        3406 :     Reference< XFastDocumentHandler > xDocHandler( rxHandler.get() );
     318        1703 :     if( !xDocHandler.is() )
     319           0 :         return false;
     320             : 
     321             :     // try to import XML stream
     322             :     try
     323             :     {
     324             :         /*  Try to open the fragment stream (may fail, do not throw/assert).
     325             :             Using the virtual function openFragmentStream() allows a document
     326             :             handler to create specialized input streams, e.g. VML streams that
     327             :             have to preprocess the raw input data. */
     328        1703 :         Reference< XInputStream > xInStrm = rxHandler->openFragmentStream();
     329             : 
     330             :         // own try/catch block for showing parser failure assertion with fragment path
     331        1703 :         if( xInStrm.is() ) try
     332             :         {
     333        1180 :             rParser.setDocumentHandler(xDocHandler);
     334        1180 :             rParser.parseStream(xInStrm, aFragmentPath);
     335        1180 :             return true;
     336             :         }
     337           0 :         catch( Exception& )
     338             :         {
     339             :             OSL_FAIL( OStringBuffer( "XmlFilterBase::importFragment - XML parser failed in fragment '" ).
     340             :                 append( OUStringToOString( aFragmentPath, RTL_TEXTENCODING_ASCII_US ) ).append( '\'' ).getStr() );
     341         523 :         }
     342             :     }
     343           0 :     catch( Exception& )
     344             :     {
     345             :     }
     346        2226 :     return false;
     347             : }
     348             : 
     349          37 : OUString XmlFilterBase::getNamespaceURL( const OUString& rPrefix )
     350             : {
     351          37 :     return mxImpl->maFastParser.getNamespaceURL( rPrefix );
     352             : }
     353             : 
     354          38 : bool XmlFilterBase::hasNamespaceURL( const OUString& rPrefix ) const
     355             : {
     356          38 :     return mxImpl->maFastParser.hasNamespaceURL(rPrefix);
     357             : }
     358             : 
     359          37 : sal_Int32 XmlFilterBase::getNamespaceId( const OUString& rUrl )
     360             : {
     361          37 :      return mxImpl->maFastParser.getNamespaceId( rUrl );
     362             : }
     363             : 
     364         894 : Reference<XDocument> XmlFilterBase::importFragment( const OUString& aFragmentPath )
     365             : {
     366         894 :     Reference<XDocument> xRet;
     367             : 
     368             :     // path to fragment stream valid?
     369             :     OSL_ENSURE( !aFragmentPath.isEmpty(), "XmlFilterBase::importFragment - empty fragment path" );
     370         894 :     if( aFragmentPath.isEmpty() )
     371           0 :         return xRet;
     372             : 
     373             :     // try to open the fragment stream (this may fail - do not assert)
     374        1788 :     Reference< XInputStream > xInStrm = openInputStream( aFragmentPath );
     375         894 :     if( !xInStrm.is() )
     376           0 :         return xRet;
     377             : 
     378             :     // binary streams (fragment extension is '.bin') currently not supported
     379         894 :     sal_Int32 nBinSuffixPos = aFragmentPath.getLength() - mxImpl->maBinSuffix.getLength();
     380         894 :     if( (nBinSuffixPos >= 0) && aFragmentPath.match( mxImpl->maBinSuffix, nBinSuffixPos ) )
     381           0 :         return xRet;
     382             : 
     383             :     // try to import XML stream
     384             :     try
     385             :     {
     386             :         // create the dom parser
     387         894 :         Reference<XDocumentBuilder> xDomBuilder( DocumentBuilder::create( getComponentContext() ) );
     388             : 
     389             :         // create DOM from fragment
     390         894 :         xRet = xDomBuilder->parse(xInStrm);
     391             :     }
     392           0 :     catch( Exception& )
     393             :     {
     394             :     }
     395             : 
     396         894 :     return xRet;
     397             : }
     398             : 
     399         817 : bool XmlFilterBase::importFragment( const ::rtl::Reference< FragmentHandler >& rxHandler,
     400             :                                     const Reference< XFastSAXSerializable >& rxSerializer )
     401             : {
     402         817 :     Reference< XFastDocumentHandler > xDocHandler( rxHandler.get() );
     403         817 :     if( !xDocHandler.is() )
     404           0 :         return false;
     405             : 
     406             :     // try to import XML stream
     407             :     try
     408             :     {
     409         817 :         rxSerializer->fastSerialize( xDocHandler,
     410         817 :                                      mxImpl->maFastParser.getTokenHandler(),
     411             :                                      Sequence< StringPair >(),
     412        1634 :                                      NamespaceIds::get() );
     413         817 :         return true;
     414             :     }
     415           0 :     catch( Exception& )
     416             :     {}
     417             : 
     418         817 :     return false;
     419             : }
     420             : 
     421        3878 : RelationsRef XmlFilterBase::importRelations( const OUString& rFragmentPath )
     422             : {
     423             :     // try to find cached relations
     424        3878 :     RelationsRef& rxRelations = mxImpl->maRelationsMap[ rFragmentPath ];
     425        3878 :     if( !rxRelations )
     426             :     {
     427             :         // import and cache relations
     428        1256 :         rxRelations.reset( new Relations( rFragmentPath ) );
     429        1256 :         importFragment( new RelationsFragment( *this, rxRelations ) );
     430             :     }
     431        3878 :     return rxRelations;
     432             : }
     433             : 
     434        4073 : Reference< XOutputStream > XmlFilterBase::openFragmentStream( const OUString& rStreamName, const OUString& rMediaType )
     435             : {
     436        4073 :     Reference< XOutputStream > xOutputStream = openOutputStream( rStreamName );
     437        8146 :     PropertySet aPropSet( xOutputStream );
     438        4073 :     aPropSet.setProperty( PROP_MediaType, rMediaType );
     439        8146 :     return xOutputStream;
     440             : }
     441             : 
     442        2014 : FSHelperPtr XmlFilterBase::openFragmentStreamWithSerializer( const OUString& rStreamName, const OUString& rMediaType )
     443             : {
     444        2014 :     bool bWriteHeader = true;
     445        2014 :     if( rMediaType.indexOfAsciiL( "vml", 3 ) >= 0 &&
     446           0 :         rMediaType.indexOfAsciiL( "+xml", 4 ) < 0 )
     447           0 :         bWriteHeader = false;
     448        2014 :     return FSHelperPtr( new FastSerializerHelper( openFragmentStream( rStreamName, rMediaType ), bWriteHeader ) );
     449             : }
     450             : 
     451          25 : TextFieldStack& XmlFilterBase::getTextFieldStack() const
     452             : {
     453          25 :     return mxImpl->maTextFieldStack;
     454             : }
     455             : 
     456             : namespace {
     457             : 
     458        3788 : OUString lclAddRelation( const Reference< XRelationshipAccess > xRelations, sal_Int32 nId, const OUString& rType, const OUString& rTarget, bool bExternal )
     459             : {
     460        3788 :     OUString sId = OUStringBuffer().appendAscii( "rId" ).append( nId ).makeStringAndClear();
     461             : 
     462        7576 :     Sequence< StringPair > aEntry( bExternal ? 3 : 2 );
     463        3788 :     aEntry[0].First = "Type";
     464        3788 :     aEntry[0].Second = rType;
     465        3788 :     aEntry[1].First = "Target";
     466        3788 :     aEntry[1].Second = rTarget;
     467        3788 :     if( bExternal )
     468             :     {
     469         199 :         aEntry[2].First = "TargetMode";
     470         199 :         aEntry[2].Second = "External";
     471             :     }
     472        3788 :     xRelations->insertRelationshipByID( sId, aEntry, sal_True );
     473             : 
     474        7576 :     return sId;
     475             : }
     476             : 
     477             : } // namespace
     478             : 
     479         862 : OUString XmlFilterBase::addRelation( const OUString& rType, const OUString& rTarget, bool bExternal )
     480             : {
     481         862 :     Reference< XRelationshipAccess > xRelations( getStorage()->getXStorage(), UNO_QUERY );
     482         862 :     if( xRelations.is() )
     483         862 :         return lclAddRelation( xRelations, mnRelId ++, rType, rTarget, bExternal );
     484             : 
     485           0 :     return OUString();
     486             : }
     487             : 
     488        2926 : OUString XmlFilterBase::addRelation( const Reference< XOutputStream > xOutputStream, const OUString& rType, const OUString& rTarget, bool bExternal )
     489             : {
     490        2926 :     sal_Int32 nId = 0;
     491             : 
     492        2926 :     PropertySet aPropSet( xOutputStream );
     493        2926 :     if( aPropSet.is() )
     494        2926 :         aPropSet.getProperty( nId, PROP_RelId );
     495             :     else
     496           0 :         nId = mnRelId++;
     497             : 
     498        5852 :     Reference< XRelationshipAccess > xRelations( xOutputStream, UNO_QUERY );
     499        2926 :     if( xRelations.is() )
     500        2926 :         return lclAddRelation( xRelations, nId, rType, rTarget, bExternal );
     501             : 
     502        2926 :     return OUString();
     503             : }
     504             : 
     505             : static void
     506        2532 : writeElement( FSHelperPtr pDoc, sal_Int32 nXmlElement, const OUString& sValue )
     507             : {
     508        2532 :     if( sValue.isEmpty() )
     509        3559 :         return;
     510        1505 :     pDoc->startElement( nXmlElement, FSEND );
     511        1505 :     pDoc->writeEscaped( sValue );
     512        1505 :     pDoc->endElement( nXmlElement );
     513             : }
     514             : 
     515             : static void
     516         572 : writeElement( FSHelperPtr pDoc, sal_Int32 nXmlElement, const sal_Int32 nValue )
     517             : {
     518         572 :     pDoc->startElement( nXmlElement, FSEND );
     519         572 :     pDoc->write( OUString::number( nValue ) );
     520         572 :     pDoc->endElement( nXmlElement );
     521         572 : }
     522             : 
     523             : static void
     524         858 : writeElement( FSHelperPtr pDoc, sal_Int32 nXmlElement, const util::DateTime& rTime )
     525             : {
     526         858 :     if( rTime.Year == 0 )
     527        1136 :         return;
     528             : 
     529         580 :     if ( ( nXmlElement >> 16 ) != XML_dcterms )
     530          30 :         pDoc->startElement( nXmlElement, FSEND );
     531             :     else
     532             :         pDoc->startElement( nXmlElement,
     533             :                 FSNS( XML_xsi, XML_type ), "dcterms:W3CDTF",
     534         550 :                 FSEND );
     535             : 
     536             :     char pStr[200];
     537             :     snprintf( pStr, sizeof( pStr ), "%d-%02d-%02dT%02d:%02d:%02dZ",
     538             :             rTime.Year, rTime.Month, rTime.Day,
     539         580 :             rTime.Hours, rTime.Minutes, rTime.Seconds );
     540             : 
     541         580 :     pDoc->write( pStr );
     542             : 
     543         580 :     pDoc->endElement( nXmlElement );
     544             : }
     545             : 
     546             : static void
     547         286 : writeElement( FSHelperPtr pDoc, sal_Int32 nXmlElement, Sequence< OUString > aItems )
     548             : {
     549         286 :     if( aItems.getLength() == 0 )
     550         570 :         return;
     551             : 
     552           2 :     OUStringBuffer sRep;
     553           2 :     sRep.append( aItems[ 0 ] );
     554             : 
     555           3 :     for( sal_Int32 i = 1, end = aItems.getLength(); i < end; ++i )
     556             :     {
     557           1 :         sRep.appendAscii( " " ).append( aItems[ i ] );
     558             :     }
     559             : 
     560           2 :     writeElement( pDoc, nXmlElement, sRep.makeStringAndClear() );
     561             : }
     562             : 
     563             : static void
     564         286 : writeElement( FSHelperPtr pDoc, sal_Int32 nXmlElement, const LanguageTag& rLanguageTag )
     565             : {
     566             :     // dc:language, Dublin Core recommends "such as RFC 4646", which is BCP 47
     567             :     // and obsoleted by RFC 5646, see
     568             :     // http://dublincore.org/documents/dcmi-terms/#terms-language
     569             :     // http://dublincore.org/documents/dcmi-terms/#elements-language
     570         286 :     writeElement( pDoc, nXmlElement, rLanguageTag.getBcp47() );
     571         286 : }
     572             : 
     573             : static void
     574         286 : writeCoreProperties( XmlFilterBase& rSelf, Reference< XDocumentProperties > xProperties )
     575             : {
     576         286 :     OUString sValue;
     577         286 :     if( rSelf.getVersion() == oox::core::ISOIEC_29500_2008  )
     578         286 :         sValue = "http://schemas.openxmlformats.org/officedocument/2006/relationships/metadata/core-properties";
     579             :     else
     580           0 :         sValue = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
     581             : 
     582         286 :     rSelf.addRelation( sValue, "docProps/core.xml" );
     583             :     FSHelperPtr pCoreProps = rSelf.openFragmentStreamWithSerializer(
     584             :             "docProps/core.xml",
     585         572 :             "application/vnd.openxmlformats-package.core-properties+xml" );
     586             :     pCoreProps->startElementNS( XML_cp, XML_coreProperties,
     587             :             FSNS( XML_xmlns, XML_cp ),          "http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
     588             :             FSNS( XML_xmlns, XML_dc ),          "http://purl.org/dc/elements/1.1/",
     589             :             FSNS( XML_xmlns, XML_dcterms ),     "http://purl.org/dc/terms/",
     590             :             FSNS( XML_xmlns, XML_dcmitype ),    "http://purl.org/dc/dcmitype/",
     591             :             FSNS( XML_xmlns, XML_xsi ),         "http://www.w3.org/2001/XMLSchema-instance",
     592         286 :             FSEND );
     593             : 
     594             : #ifdef OOXTODO
     595             :     writeElement( pCoreProps, FSNS( XML_cp, XML_category ),         "category" );
     596             :     writeElement( pCoreProps, FSNS( XML_cp, XML_contentStatus ),    "status" );
     597             :     writeElement( pCoreProps, FSNS( XML_cp, XML_contentType ),      "contentType" );
     598             : #endif  /* def OOXTODO */
     599         286 :     writeElement( pCoreProps, FSNS( XML_dcterms, XML_created ),     xProperties->getCreationDate() );
     600         286 :     writeElement( pCoreProps, FSNS( XML_dc, XML_creator ),          xProperties->getAuthor() );
     601         286 :     writeElement( pCoreProps, FSNS( XML_dc, XML_description ),      xProperties->getDescription() );
     602             : #ifdef OOXTODO
     603             :     writeElement( pCoreProps, FSNS( XML_dc, XML_identifier ),       "ident" );
     604             : #endif  /* def OOXTODO */
     605         286 :     writeElement( pCoreProps, FSNS( XML_cp, XML_keywords ),         xProperties->getKeywords() );
     606         286 :     writeElement( pCoreProps, FSNS( XML_dc, XML_language ),         LanguageTag( xProperties->getLanguage()) );
     607         286 :     writeElement( pCoreProps, FSNS( XML_cp, XML_lastModifiedBy ),   xProperties->getModifiedBy() );
     608         286 :     writeElement( pCoreProps, FSNS( XML_cp, XML_lastPrinted ),      xProperties->getPrintDate() );
     609         286 :     writeElement( pCoreProps, FSNS( XML_dcterms, XML_modified ),    xProperties->getModificationDate() );
     610         286 :     writeElement( pCoreProps, FSNS( XML_cp, XML_revision ),         xProperties->getEditingCycles() );
     611         286 :     writeElement( pCoreProps, FSNS( XML_dc, XML_subject ),          xProperties->getSubject() );
     612         286 :     writeElement( pCoreProps, FSNS( XML_dc, XML_title ),            xProperties->getTitle() );
     613             : #ifdef OOXTODO
     614             :     writeElement( pCoreProps, FSNS( XML_cp, XML_version ),          "version" );
     615             : #endif  /* def OOXTODO */
     616             : 
     617         572 :     pCoreProps->endElementNS( XML_cp, XML_coreProperties );
     618         286 : }
     619             : 
     620             : static void
     621         286 : writeAppProperties( XmlFilterBase& rSelf, Reference< XDocumentProperties > xProperties )
     622             : {
     623             :     rSelf.addRelation(
     624             :             "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties",
     625         286 :             "docProps/app.xml" );
     626             :     FSHelperPtr pAppProps = rSelf.openFragmentStreamWithSerializer(
     627             :             "docProps/app.xml",
     628         286 :             "application/vnd.openxmlformats-officedocument.extended-properties+xml" );
     629             :     pAppProps->startElement( XML_Properties,
     630             :             XML_xmlns,                  "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties",
     631             :             FSNS( XML_xmlns, XML_vt ),  "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes",
     632         286 :             FSEND );
     633             : 
     634         286 :     writeElement( pAppProps, XML_Template,              xProperties->getTemplateName() );
     635             : #ifdef OOXTODO
     636             :     writeElement( pAppProps, XML_Manager,               "manager" );
     637             :     writeElement( pAppProps, XML_Company,               "company" );
     638             :     writeElement( pAppProps, XML_Pages,                 "pages" );
     639             :     writeElement( pAppProps, XML_Words,                 "words" );
     640             :     writeElement( pAppProps, XML_Characters,            "characters" );
     641             :     writeElement( pAppProps, XML_PresentationFormat,    "presentation format" );
     642             :     writeElement( pAppProps, XML_Lines,                 "lines" );
     643             :     writeElement( pAppProps, XML_Slides,                "slides" );
     644             :     writeElement( pAppProps, XML_Notes,                 "notes" );
     645             : #endif  /* def OOXTODO */
     646         286 :     writeElement( pAppProps, XML_TotalTime,             xProperties->getEditingDuration() );
     647             : #ifdef OOXTODO
     648             :     writeElement( pAppProps, XML_HiddenSlides,          "hidden slides" );
     649             :     writeElement( pAppProps, XML_MMClips,               "mm clips" );
     650             :     writeElement( pAppProps, XML_ScaleCrop,             "scale crop" );
     651             :     writeElement( pAppProps, XML_HeadingPairs,          "heading pairs" );
     652             :     writeElement( pAppProps, XML_TitlesOfParts,         "titles of parts" );
     653             :     writeElement( pAppProps, XML_LinksUpToDate,         "links up-to-date" );
     654             :     writeElement( pAppProps, XML_CharactersWithSpaces,  "characters with spaces" );
     655             :     writeElement( pAppProps, XML_SharedDoc,             "shared doc" );
     656             :     writeElement( pAppProps, XML_HyperlinkBase,         "hyperlink base" );
     657             :     writeElement( pAppProps, XML_HLinks,                "hlinks" );
     658             :     writeElement( pAppProps, XML_HyperlinksChanged,     "hyperlinks changed" );
     659             :     writeElement( pAppProps, XML_DigSig,                "digital signature" );
     660             : #endif  /* def OOXTODO */
     661         286 :     writeElement( pAppProps, XML_Application,           xProperties->getGenerator() );
     662             : #ifdef OOXTODO
     663             :     writeElement( pAppProps, XML_AppVersion,            "app version" );
     664             :     writeElement( pAppProps, XML_DocSecurity,           "doc security" );
     665             : #endif  /* def OOXTODO */
     666             : 
     667         572 :     uno::Sequence<beans::NamedValue> aStats = xProperties->getDocumentStatistics();
     668         594 :     for (sal_Int32 i = 0; i < aStats.getLength(); ++i)
     669             :     {
     670         550 :         if (aStats[i].Name == "ParagraphCount")
     671             :         {
     672         242 :             sal_Int32 nValue = 0;
     673         242 :             if (aStats[i].Value >>= nValue)
     674             :             {
     675         242 :                 writeElement(pAppProps, XML_Paragraphs, OUString::number(nValue));
     676         242 :                 break;
     677             :             }
     678             :         }
     679             :     }
     680             : 
     681         572 :     pAppProps->endElement( XML_Properties );
     682         286 : }
     683             : 
     684         286 : XmlFilterBase& XmlFilterBase::exportDocumentProperties( Reference< XDocumentProperties > xProperties )
     685             : {
     686         286 :     if( xProperties.is() )
     687             :     {
     688         286 :         writeCoreProperties( *this, xProperties );
     689         286 :         writeAppProperties( *this, xProperties );
     690             :     }
     691         286 :     return *this;
     692             : }
     693             : 
     694             : // protected ------------------------------------------------------------------
     695             : 
     696        1157 : Reference< XInputStream > XmlFilterBase::implGetInputStream( MediaDescriptor& rMediaDesc ) const
     697             : {
     698             :     /*  Get the input stream directly from the media descriptor, or decrypt the
     699             :         package again. The latter is needed e.g. when the document is reloaded.
     700             :         All this is implemented in the detector service. */
     701        1157 :     FilterDetect aDetector( getComponentContext() );
     702        1157 :     return aDetector.extractUnencryptedPackage( rMediaDesc );
     703             : }
     704             : 
     705         308 : Reference<XStream> XmlFilterBase::implGetOutputStream( MediaDescriptor& rMediaDescriptor ) const
     706             : {
     707         308 :     Sequence< NamedValue > aMediaEncData;
     708         924 :     aMediaEncData = rMediaDescriptor.getUnpackedValueOrDefault(
     709         308 :                                         MediaDescriptor::PROP_ENCRYPTIONDATA(),
     710         308 :                                         Sequence< NamedValue >() );
     711             : 
     712         616 :     OUString aPassword;
     713         308 :     for (int i=0; i<aMediaEncData.getLength(); i++)
     714             :     {
     715           0 :         if (aMediaEncData[i].Name == "OOXPassword")
     716             :         {
     717           0 :             Any& any = aMediaEncData[i].Value;
     718           0 :             any >>= aPassword;
     719           0 :             break;
     720             :         }
     721             :     }
     722         308 :     if (aPassword.isEmpty())
     723             :     {
     724         308 :         return FilterBase::implGetOutputStream( rMediaDescriptor );
     725             :     }
     726             :     else // We need to encrypt the stream so create a memory stream
     727             :     {
     728           0 :         Reference< XComponentContext > xContext = getComponentContext();
     729             :         return Reference< XStream > (
     730           0 :                     xContext->getServiceManager()->createInstanceWithContext("com.sun.star.comp.MemoryStream", xContext),
     731           0 :                     uno::UNO_QUERY_THROW );
     732         308 :     }
     733             : }
     734             : 
     735         290 : bool XmlFilterBase::implFinalizeExport( MediaDescriptor& rMediaDescriptor )
     736             : {
     737         290 :     bool bRet = true;
     738             : 
     739         290 :     Sequence< NamedValue > aMediaEncData;
     740         870 :     aMediaEncData = rMediaDescriptor.getUnpackedValueOrDefault(
     741         290 :                                         MediaDescriptor::PROP_ENCRYPTIONDATA(),
     742         290 :                                         Sequence< NamedValue >() );
     743             : 
     744         580 :     OUString aPassword;
     745             : 
     746         290 :     for (int i=0; i<aMediaEncData.getLength(); i++)
     747             :     {
     748           0 :         if (aMediaEncData[i].Name == "OOXPassword")
     749             :         {
     750           0 :             Any& any = aMediaEncData[i].Value;
     751           0 :             any >>= aPassword;
     752           0 :             break;
     753             :         }
     754             :     }
     755             : 
     756         290 :     if (!aPassword.isEmpty())
     757             :     {
     758           0 :         commitStorage();
     759             : 
     760           0 :         Reference< XStream> xDocumentStream (FilterBase::implGetOutputStream(rMediaDescriptor));
     761           0 :         oox::ole::OleStorage aOleStorage( getComponentContext(), xDocumentStream, true );
     762           0 :         DocumentEncryption encryptor(getMainDocumentStream(), aOleStorage, aPassword);
     763           0 :         bRet = encryptor.encrypt();
     764           0 :         if (bRet)
     765           0 :             aOleStorage.commit();
     766             :     }
     767             : 
     768         580 :     return bRet;
     769             : }
     770             : 
     771             : // private --------------------------------------------------------------------
     772             : 
     773        1157 : StorageRef XmlFilterBase::implCreateStorage( const Reference< XInputStream >& rxInStream ) const
     774             : {
     775        1157 :     return StorageRef( new ZipStorage( getComponentContext(), rxInStream ) );
     776             : }
     777             : 
     778         308 : StorageRef XmlFilterBase::implCreateStorage( const Reference< XStream >& rxOutStream ) const
     779             : {
     780         308 :     return StorageRef( new ZipStorage( getComponentContext(), rxOutStream ) );
     781             : }
     782             : 
     783             : 
     784             : 
     785             : } // namespace core
     786         177 : } // namespace oox
     787             : 
     788             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10