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

Generated by: LCOV version 1.11