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

Generated by: LCOV version 1.10