LibreOffice Module oox (master) 1
xmlfilterbase.cxx
Go to the documentation of this file.
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
21
22#include <cstdio>
23#include <string_view>
24
25#include <com/sun/star/beans/XPropertyAccess.hpp>
26#include <com/sun/star/beans/XPropertySet.hpp>
27#include <com/sun/star/beans/Pair.hpp>
28#include <com/sun/star/embed/XRelationshipAccess.hpp>
29#include <com/sun/star/frame/XModel.hpp>
30#include <com/sun/star/xml/sax/XFastSAXSerializable.hpp>
31#include <com/sun/star/xml/sax/XSAXSerializable.hpp>
32#include <com/sun/star/xml/sax/Writer.hpp>
33#include <o3tl/any.hxx>
36#include <sax/fshelper.hxx>
37#include <rtl/strbuf.hxx>
38#include <rtl/ustrbuf.hxx>
39#include <osl/diagnose.h>
40#include <sal/log.hxx>
49#include <oox/token/namespaces.hxx>
51#include <oox/token/properties.hxx>
52#include <oox/token/tokens.hxx>
53#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
54#include <com/sun/star/document/XOOXMLDocumentPropertiesImporter.hpp>
55#include <com/sun/star/xml/dom/DocumentBuilder.hpp>
62
64#include <tools/urlobj.hxx>
65#include <com/sun/star/util/Date.hpp>
66#include <com/sun/star/util/Duration.hpp>
69#include <editeng/unoprnms.hxx>
71
72using ::com::sun::star::xml::dom::DocumentBuilder;
73using ::com::sun::star::xml::dom::XDocument;
74using ::com::sun::star::xml::dom::XDocumentBuilder;
75
76namespace oox::core {
77
78using namespace ::com::sun::star;
79using namespace ::com::sun::star::beans;
80using namespace ::com::sun::star::container;
81using namespace ::com::sun::star::document;
82using namespace ::com::sun::star::embed;
83using namespace ::com::sun::star::io;
84using namespace ::com::sun::star::lang;
85using namespace ::com::sun::star::uno;
86using namespace ::com::sun::star::xml::sax;
87
89using ::sax_fastparser::FSHelperPtr;
90using ::sax_fastparser::FastSerializerHelper;
91
92namespace {
93
94const Sequence< beans::Pair< OUString, sal_Int32 > >& NamespaceIds()
95{
96 static const Sequence< beans::Pair< OUString, sal_Int32 > > SINGLETON
97 {
98 {"http://www.w3.org/XML/1998/namespace", NMSP_xml},
99 {"http://schemas.openxmlformats.org/package/2006/relationships",
100 NMSP_packageRel},
101 {"http://schemas.openxmlformats.org/officeDocument/2006/relationships",
102 NMSP_officeRel},
103 {"http://purl.oclc.org/ooxml/officeDocument/relationships",
104 NMSP_officeRel},
105 {"http://schemas.openxmlformats.org/drawingml/2006/main", NMSP_dml},
106 {"http://purl.oclc.org/ooxml/drawingml/main", NMSP_dml},
107 {"http://schemas.openxmlformats.org/drawingml/2006/diagram",
108 NMSP_dmlDiagram},
109 {"http://purl.oclc.org/ooxml/drawingml/diagram", NMSP_dmlDiagram},
110 {"http://schemas.openxmlformats.org/drawingml/2006/chart",
111 NMSP_dmlChart},
112 {"http://schemas.openxmlformats.org/drawingml/2006/chartDrawing",
113 NMSP_dmlChartDr},
114 {"urn:schemas-microsoft-com:vml", NMSP_vml},
115 {"urn:schemas-microsoft-com:office:office", NMSP_vmlOffice},
116 {"urn:schemas-microsoft-com:office:word", NMSP_vmlWord},
117 {"urn:schemas-microsoft-com:office:excel", NMSP_vmlExcel},
118 {"urn:schemas-microsoft-com:office:powerpoint", NMSP_vmlPowerpoint},
119 {"http://schemas.microsoft.com/office/2006/activeX", NMSP_ax},
120 {"http://schemas.openxmlformats.org/spreadsheetml/2006/main",
121 NMSP_xls},
122 {"http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing",
123 NMSP_xm},
124 {"http://schemas.microsoft.com/office/excel/2006/main",
125 NMSP_dmlSpreadDr},
126 {"http://schemas.openxmlformats.org/presentationml/2006/main",
127 NMSP_ppt},
128 {"http://schemas.openxmlformats.org/markup-compatibility/2006",
129 NMSP_mce},
130 {"http://schemas.openxmlformats.org/spreadsheetml/2006/main/v2",
131 NMSP_mceTest},
132 {"http://schemas.openxmlformats.org/officeDocument/2006/math",
133 NMSP_officeMath},
134 {"http://schemas.microsoft.com/office/drawing/2008/diagram",
135 NMSP_dsp},
136 {"http://schemas.microsoft.com/office/spreadsheetml/2009/9/main",
137 NMSP_xls14Lst},
138 {"http://schemas.libreoffice.org/", NMSP_loext},
139 {"http://schemas.microsoft.com/office/drawing/2010/main",
140 NMSP_a14},
141 {"http://schemas.microsoft.com/office/powerpoint/2010/main",
142 NMSP_p14},
143 {"http://schemas.microsoft.com/office/powerpoint/2012/main",
144 NMSP_p15},
145 {"http://schemas.microsoft.com/office/spreadsheetml/2011/1/ac",
146 NMSP_x12ac},
147 {"http://schemas.microsoft.com/office/drawing/2012/chart",
148 NMSP_c15},
149 {"http://schemas.microsoft.com/office/spreadsheetml/2015/revision2",
150 NMSP_xr2},
151 };
152 return SINGLETON;
153};
154
155void registerNamespaces( FastParser& rParser )
156{
157 const Sequence< beans::Pair<OUString, sal_Int32> >& ids = NamespaceIds();
158
159 // Filter out duplicates: a namespace can have multiple URLs, think of
160 // strict vs transitional.
162 aSet.reserve(ids.getLength());
163 for (const auto& rId : ids)
164 aSet.insert(rId.Second);
165
166 for (auto const& elem : aSet)
167 rParser.registerNamespace(elem);
168}
169
170} // namespace
171
173{
175
180
182 explicit XmlFilterBaseImpl();
183};
184
185constexpr OUStringLiteral gaBinSuffix( u".bin" );
186
188 mrNamespaceMap(StaticNamespaceMap())
189{
190 // register XML namespaces
191 registerNamespaces(maFastParser);
192}
193
194XmlFilterBase::XmlFilterBase( const Reference< XComponentContext >& rxContext ) :
195 FilterBase( rxContext ),
196 mxImpl( new XmlFilterBaseImpl ),
197 mnRelId( 1 ),
198 mnMaxDocId( 0 ),
199 mbMSO2007(false),
200 mbMSO(false),
201 mbMissingExtDrawing(false)
202{
203}
204
206{
207 // #i118640# Reset the DocumentHandler at the FastSaxParser manually; this is
208 // needed since the mechanism is that instances of FragmentHandler execute
209 // their stuff (creating objects, setting attributes, ...) on being destroyed.
210 // They get destroyed by setting a new DocumentHandler. This also happens in
211 // the following implicit destruction chain of ~XmlFilterBaseImpl, but in that
212 // case it's member RelationsMap maRelationsMap will be destroyed, but maybe
213 // still be used by ~FragmentHandler -> crash.
214 mxImpl->maFastParser.clearDocumentHandler();
215}
216
217std::shared_ptr<::oox::drawingml::Theme> XmlFilterBase::getCurrentThemePtr() const
218{
219 // default returns empty ptr
220 return std::shared_ptr<::oox::drawingml::Theme>();
221}
222
223void XmlFilterBase::checkDocumentProperties(const Reference<XDocumentProperties>& xDocProps)
224{
225 mbMSO2007 = mbMSO = false;
226 if (!xDocProps->getGenerator().startsWithIgnoreAsciiCase("Microsoft"))
227 return;
228 mbMSO = true;
229
230 uno::Reference<beans::XPropertyAccess> xUserDefProps(xDocProps->getUserDefinedProperties(), uno::UNO_QUERY);
231 if (!xUserDefProps.is())
232 return;
233
234 comphelper::SequenceAsHashMap aUserDefinedProperties(xUserDefProps->getPropertyValues());
235 comphelper::SequenceAsHashMap::iterator it = aUserDefinedProperties.find("AppVersion");
236 if (it == aUserDefinedProperties.end())
237 return;
238
239 OUString aValue;
240 if (!(it->second >>= aValue))
241 return;
242
243 if (!aValue.startsWithIgnoreAsciiCase("12."))
244 return;
245
246 SAL_INFO("oox", "a MSO 2007 document");
247 mbMSO2007 = true;
248}
249
250void XmlFilterBase::putPropertiesToDocumentGrabBag(const css::uno::Reference<css::lang::XComponent>& xDstDoc,
251 const comphelper::SequenceAsHashMap& rProperties)
252{
253 try
254 {
255 uno::Reference<beans::XPropertySet> xDocProps(xDstDoc, uno::UNO_QUERY);
256 if (xDocProps.is())
257 {
258 uno::Reference<beans::XPropertySetInfo> xPropsInfo = xDocProps->getPropertySetInfo();
259
260 static constexpr OUStringLiteral aGrabBagPropName = u"InteropGrabBag";
261 if (xPropsInfo.is() && xPropsInfo->hasPropertyByName(aGrabBagPropName))
262 {
263 // get existing grab bag
264 comphelper::SequenceAsHashMap aGrabBag(xDocProps->getPropertyValue(aGrabBagPropName));
265
266 // put the new items
267 aGrabBag.update(rProperties);
268
269 // put it back to the document
270 xDocProps->setPropertyValue(aGrabBagPropName, uno::Any(aGrabBag.getAsConstPropertyValueList()));
271 }
272 }
273 }
274 catch (const uno::Exception&)
275 {
276 SAL_WARN("oox","Failed to save documents grab bag");
277 }
278}
279
281{
282 MediaDescriptor aMediaDesc( getMediaDescriptor() );
283 Reference< XInputStream > xInputStream;
284 Reference< XComponentContext > xContext = getComponentContext();
285 rtl::Reference< ::oox::core::FilterDetect > xDetector( new ::oox::core::FilterDetect( xContext ) );
286 xInputStream = xDetector->extractUnencryptedPackage( aMediaDesc );
287 Reference< XComponent > xModel = getModel();
288 Reference< XStorage > xDocumentStorage (
290 Reference< XInterface > xTemp = xContext->getServiceManager()->createInstanceWithContext(
291 "com.sun.star.document.OOXMLDocumentPropertiesImporter",
292 xContext);
293 Reference< XOOXMLDocumentPropertiesImporter > xImporter( xTemp, UNO_QUERY );
294 Reference< XDocumentPropertiesSupplier > xPropSupplier( xModel, UNO_QUERY);
295 Reference< XDocumentProperties > xDocProps = xPropSupplier->getDocumentProperties();
296 xImporter->importProperties( xDocumentStorage, xDocProps );
297 checkDocumentProperties(xDocProps);
298
299 importCustomFragments(xDocumentStorage);
300}
301
303{
304 FastParser* pParser = new FastParser;
305 registerNamespaces(*pParser);
306 return pParser;
307}
308
309namespace {
310
311OUString getTransitionalRelationshipOfficeDocType(std::u16string_view rPart)
312{
313 return OUString::Concat("http://schemas.openxmlformats.org/officeDocument/2006/relationships/")
314 + rPart;
315}
316
317OUString getStrictRelationshipOfficeDocType(std::u16string_view rPart)
318{
319 return OUString::Concat("http://purl.oclc.org/ooxml/officeDocument/relationships/") + rPart;
320}
321
322}
323
325{
326 // importRelations() caches the relations map for subsequence calls
327 const OUString aTransitionalRelationshipType = getTransitionalRelationshipOfficeDocType(rPart);
328 OUString aFragment = importRelations( OUString() )->getFragmentPathFromFirstType( aTransitionalRelationshipType );
329 if(aFragment.isEmpty())
330 {
331 const OUString aStrictRelationshipType = getStrictRelationshipOfficeDocType(rPart);
332 aFragment = importRelations( OUString() )->getFragmentPathFromFirstType( aStrictRelationshipType );
333 }
334
335 return aFragment;
336}
337
339{
340 FastParser aParser;
341 registerNamespaces(aParser);
342 return importFragment(rxHandler, aParser);
343}
344
346{
347 OSL_ENSURE( rxHandler.is(), "XmlFilterBase::importFragment - missing fragment handler" );
348 if( !rxHandler.is() )
349 return false;
350
351 // fragment handler must contain path to fragment stream
352 OUString aFragmentPath = rxHandler->getFragmentPath();
353 OSL_ENSURE( !aFragmentPath.isEmpty(), "XmlFilterBase::importFragment - missing fragment path" );
354 if( aFragmentPath.isEmpty() )
355 return false;
356
357 // try to import binary streams (fragment extension must be '.bin')
358 if (aFragmentPath.endsWith(gaBinSuffix))
359 {
360 try
361 {
362 // try to open the fragment stream (this may fail - do not assert)
363 Reference< XInputStream > xInStrm( openInputStream( aFragmentPath ), UNO_SET_THROW );
364
365 // create the record parser
366 RecordParser aParser;
367 aParser.setFragmentHandler( rxHandler );
368
369 // create the input source and parse the stream
370 RecordInputSource aSource;
371 aSource.mxInStream = std::make_shared<BinaryXInputStream>( xInStrm, true );
372 aSource.maSystemId = aFragmentPath;
373 aParser.parseStream( aSource );
374 return true;
375 }
376 catch( Exception& )
377 {
378 }
379 return false;
380 }
381
382 // get the XFastDocumentHandler interface from the fragment handler
383 if( !rxHandler.is() )
384 return false;
385
386 // try to import XML stream
387 try
388 {
389 /* Try to open the fragment stream (may fail, do not throw/assert).
390 Using the virtual function openFragmentStream() allows a document
391 handler to create specialized input streams, e.g. VML streams that
392 have to preprocess the raw input data. */
393 Reference< XInputStream > xInStrm = rxHandler->openFragmentStream();
394 /* tdf#100084 Check again the aFragmentPath route with lowercase file name
395 TODO: complete handling of case-insensitive file paths */
396 if ( !xInStrm.is() )
397 {
398 sal_Int32 nPathLen = aFragmentPath.lastIndexOf('/') + 1;
399 OUString fileName = aFragmentPath.copy(nPathLen);
400 OUString sLowerCaseFileName = fileName.toAsciiLowerCase();
401 if ( fileName != sLowerCaseFileName )
402 {
403 aFragmentPath = aFragmentPath.subView(0, nPathLen) + sLowerCaseFileName;
404 xInStrm = openInputStream(aFragmentPath);
405 }
406 }
407
408 // own try/catch block for showing parser failure assertion with fragment path
409 if( xInStrm.is() ) try
410 {
411 rParser.setDocumentHandler(rxHandler);
412 rParser.parseStream(xInStrm, aFragmentPath);
413 return true;
414 }
415 catch( Exception& )
416 {
417 OSL_FAIL( OStringBuffer( "XmlFilterBase::importFragment - XML parser failed in fragment '" +
418 OUStringToOString( aFragmentPath, RTL_TEXTENCODING_ASCII_US ) + "'" ).getStr() );
419 }
420 }
421 catch( Exception& )
422 {
423 }
424 return false;
425}
426
427Reference<XDocument> XmlFilterBase::importFragment( const OUString& aFragmentPath )
428{
429 Reference<XDocument> xRet;
430
431 // path to fragment stream valid?
432 OSL_ENSURE( !aFragmentPath.isEmpty(), "XmlFilterBase::importFragment - empty fragment path" );
433 if( aFragmentPath.isEmpty() )
434 return xRet;
435
436 // try to open the fragment stream (this may fail - do not assert)
437 Reference< XInputStream > xInStrm = openInputStream( aFragmentPath );
438 if( !xInStrm.is() )
439 return xRet;
440
441 // binary streams (fragment extension is '.bin') currently not supported
442 if (aFragmentPath.endsWith(gaBinSuffix))
443 return xRet;
444
445 // try to import XML stream
446 try
447 {
448 // create the dom parser
449 Reference<XDocumentBuilder> xDomBuilder( DocumentBuilder::create( getComponentContext() ) );
450
451 // create DOM from fragment
452 xRet = xDomBuilder->parse(xInStrm);
453 }
454 catch( Exception& )
455 {
456 }
457
458 return xRet;
459}
460
461bool XmlFilterBase::importFragment( const ::rtl::Reference< FragmentHandler >& rxHandler,
462 const Reference< XFastSAXSerializable >& rxSerializer )
463{
464 if( !rxHandler.is() )
465 return false;
466
467 // try to import XML stream
468 try
469 {
470 rxSerializer->fastSerialize( rxHandler,
471 mxImpl->maFastParser.getTokenHandler(),
472 Sequence< StringPair >(),
473 NamespaceIds() );
474 return true;
475 }
476 catch( Exception& )
477 {}
478
479 return false;
480}
481
482RelationsRef XmlFilterBase::importRelations( const OUString& rFragmentPath )
483{
484 // try to find cached relations
485 RelationsRef& rxRelations = mxImpl->maRelationsMap[ rFragmentPath ];
486 if( !rxRelations )
487 {
488 // import and cache relations
489 rxRelations = std::make_shared<Relations>( rFragmentPath );
490 importFragment( new RelationsFragment( *this, rxRelations ) );
491 }
492 return rxRelations;
493}
494
495Reference< XOutputStream > XmlFilterBase::openFragmentStream( const OUString& rStreamName, const OUString& rMediaType )
496{
497 Reference< XOutputStream > xOutputStream = openOutputStream( rStreamName );
498 PropertySet aPropSet( xOutputStream );
499 aPropSet.setProperty( PROP_MediaType, rMediaType );
500 return xOutputStream;
501}
502
503FSHelperPtr XmlFilterBase::openFragmentStreamWithSerializer( const OUString& rStreamName, const OUString& rMediaType )
504{
505 const bool bWriteHeader = rMediaType.indexOf( "vml" ) < 0 || rMediaType.indexOf( "+xml" ) >= 0;
506 return std::make_shared<FastSerializerHelper>( openFragmentStream( rStreamName, rMediaType ), bWriteHeader );
507}
508
509namespace {
510
511OUString lclAddRelation( const Reference< XRelationshipAccess >& rRelations, sal_Int32 nId, const OUString& rType, std::u16string_view rTarget, bool bExternal )
512{
513 OUString sId = "rId" + OUString::number( nId );
514
515 Sequence< StringPair > aEntry( bExternal ? 3 : 2 );
516 auto pEntry = aEntry.getArray();
517 pEntry[0].First = "Type";
518 pEntry[0].Second = rType;
519 pEntry[1].First = "Target";
520 pEntry[1].Second = INetURLObject::decode(rTarget, INetURLObject::DecodeMechanism::ToIUri, RTL_TEXTENCODING_UTF8);
521 if( bExternal )
522 {
523 pEntry[2].First = "TargetMode";
524 pEntry[2].Second = "External";
525 }
526 rRelations->insertRelationshipByID( sId, aEntry, true );
527
528 return sId;
529}
530
531} // namespace
532
533OUString XmlFilterBase::addRelation( const OUString& rType, std::u16string_view rTarget )
534{
535 Reference< XRelationshipAccess > xRelations( getStorage()->getXStorage(), UNO_QUERY );
536 if( xRelations.is() )
537 return lclAddRelation( xRelations, mnRelId ++, rType, rTarget, false/*bExternal*/ );
538
539 return OUString();
540}
541
542OUString XmlFilterBase::addRelation( const Reference< XOutputStream >& rOutputStream, const OUString& rType, std::u16string_view rTarget, bool bExternal )
543{
544 sal_Int32 nId = 0;
545
546 PropertySet aPropSet( rOutputStream );
547 if( aPropSet.is() )
548 aPropSet.getProperty( nId, PROP_RelId );
549 else
550 nId = mnRelId++;
551
552 Reference< XRelationshipAccess > xRelations( rOutputStream, UNO_QUERY );
553 if( xRelations.is() )
554 return lclAddRelation( xRelations, nId, rType, rTarget, bExternal );
555
556 return OUString();
557}
558
559static void
560writeElement( const FSHelperPtr& pDoc, sal_Int32 nXmlElement, std::u16string_view sValue )
561{
562 pDoc->startElement(nXmlElement);
563 pDoc->writeEscaped( sValue );
564 pDoc->endElement( nXmlElement );
565}
566
567static void
568writeElement( const FSHelperPtr& pDoc, sal_Int32 nXmlElement, const sal_Int32 nValue )
569{
570 pDoc->startElement(nXmlElement);
571 pDoc->write( nValue );
572 pDoc->endElement( nXmlElement );
573}
574
575static void
576writeElement( const FSHelperPtr& pDoc, sal_Int32 nXmlElement, const util::DateTime& rTime )
577{
578 if( rTime.Year == 0 )
579 return;
580
581 if ( ( nXmlElement >> 16 ) != XML_dcterms )
582 pDoc->startElement(nXmlElement);
583 else
584 pDoc->startElement(nXmlElement, FSNS(XML_xsi, XML_type), "dcterms:W3CDTF");
585
586 char pStr[200];
587 snprintf( pStr, sizeof( pStr ), "%d-%02d-%02dT%02d:%02d:%02dZ",
588 rTime.Year, rTime.Month, rTime.Day,
589 rTime.Hours, rTime.Minutes, rTime.Seconds );
590
591 pDoc->write( pStr );
592
593 pDoc->endElement( nXmlElement );
594}
595
596static void
597writeElement( const FSHelperPtr& pDoc, sal_Int32 nXmlElement, const Sequence< OUString >& aItems )
598{
599 if( !aItems.hasElements() )
600 return;
601
602 OUStringBuffer sRep;
603 // tdf#143175 - join elements including a delimiter using a standard iterator
604 ::comphelper::intersperse(aItems.begin(), aItems.end(),
605 ::comphelper::OUStringBufferAppender(sRep), OUString(" "));
606
607 writeElement( pDoc, nXmlElement, sRep );
608}
609
610static void
611writeElement( const FSHelperPtr& pDoc, sal_Int32 nXmlElement, const LanguageTag& rLanguageTag )
612{
613 // dc:language, Dublin Core recommends "such as RFC 4646", which is BCP 47
614 // and obsoleted by RFC 5646, see
615 // http://dublincore.org/documents/dcmi-terms/#terms-language
616 // http://dublincore.org/documents/dcmi-terms/#elements-language
617 writeElement( pDoc, nXmlElement, rLanguageTag.getBcp47MS() );
618}
619
620static void
621writeCoreProperties( XmlFilterBase& rSelf, const Reference< XDocumentProperties >& xProperties )
622{
623 OUString sValue;
625 {
626 // The lowercase "officedocument" is intentional and according to the spec
627 // (although most other places are written "officeDocument")
628 sValue = "http://schemas.openxmlformats.org/officedocument/2006/relationships/metadata/core-properties";
629 }
630 else
631 sValue = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
632
633 rSelf.addRelation( sValue, u"docProps/core.xml" );
635 "docProps/core.xml",
636 "application/vnd.openxmlformats-package.core-properties+xml" );
637 pCoreProps->startElementNS( XML_cp, XML_coreProperties,
638 FSNS(XML_xmlns, XML_cp), rSelf.getNamespaceURL(OOX_NS(packageMetaCorePr)),
639 FSNS(XML_xmlns, XML_dc), rSelf.getNamespaceURL(OOX_NS(dc)),
640 FSNS(XML_xmlns, XML_dcterms), rSelf.getNamespaceURL(OOX_NS(dcTerms)),
641 FSNS(XML_xmlns, XML_dcmitype), rSelf.getNamespaceURL(OOX_NS(dcmiType)),
642 FSNS(XML_xmlns, XML_xsi), rSelf.getNamespaceURL(OOX_NS(xsi)));
643
644 uno::Reference<beans::XPropertyAccess> xUserDefinedProperties(xProperties->getUserDefinedProperties(), uno::UNO_QUERY);
645 comphelper::SequenceAsHashMap aUserDefinedProperties(xUserDefinedProperties->getPropertyValues());
647
648 it = aUserDefinedProperties.find("OOXMLCorePropertyCategory");
649 if (it != aUserDefinedProperties.end())
650 {
651 OUString aValue;
652 if (it->second >>= aValue)
653 writeElement( pCoreProps, FSNS( XML_cp, XML_category ), aValue );
654 }
655
656 it = aUserDefinedProperties.find("OOXMLCorePropertyContentStatus");
657 if (it != aUserDefinedProperties.end())
658 {
659 OUString aValue;
660 if (it->second >>= aValue)
661 writeElement( pCoreProps, FSNS( XML_cp, XML_contentStatus ), aValue );
662 }
663
664 it = aUserDefinedProperties.find("OOXMLCorePropertyContentType");
665 if (it != aUserDefinedProperties.end())
666 {
667 OUString aValue;
668 if (it->second >>= aValue)
669 writeElement( pCoreProps, FSNS( XML_cp, XML_contentType ), aValue );
670 }
671 writeElement( pCoreProps, FSNS( XML_dcterms, XML_created ), xProperties->getCreationDate() );
672 writeElement( pCoreProps, FSNS( XML_dc, XML_creator ), xProperties->getAuthor() );
673 writeElement( pCoreProps, FSNS( XML_dc, XML_description ), xProperties->getDescription() );
674
675 it = aUserDefinedProperties.find("OOXMLCorePropertyIdentifier");
676 if (it != aUserDefinedProperties.end())
677 {
678 OUString aValue;
679 if (it->second >>= aValue)
680 writeElement( pCoreProps, FSNS( XML_dc, XML_identifier ), aValue );
681 }
682 writeElement( pCoreProps, FSNS( XML_cp, XML_keywords ), xProperties->getKeywords() );
683 writeElement( pCoreProps, FSNS( XML_dc, XML_language ), LanguageTag( xProperties->getLanguage()) );
684 writeElement( pCoreProps, FSNS( XML_cp, XML_lastModifiedBy ), xProperties->getModifiedBy() );
685 writeElement( pCoreProps, FSNS( XML_cp, XML_lastPrinted ), xProperties->getPrintDate() );
686 writeElement( pCoreProps, FSNS( XML_dcterms, XML_modified ), xProperties->getModificationDate() );
687 writeElement( pCoreProps, FSNS( XML_cp, XML_revision ), xProperties->getEditingCycles() );
688 writeElement( pCoreProps, FSNS( XML_dc, XML_subject ), xProperties->getSubject() );
689 writeElement( pCoreProps, FSNS( XML_dc, XML_title ), xProperties->getTitle() );
690
691 it = aUserDefinedProperties.find("OOXMLCorePropertyVersion");
692 if (it != aUserDefinedProperties.end())
693 {
694 OUString aValue;
695 if (it->second >>= aValue)
696 writeElement( pCoreProps, FSNS( XML_cp, XML_version ), aValue );
697 }
698
699 pCoreProps->endElementNS( XML_cp, XML_coreProperties );
700}
701
702static void
703writeAppProperties( XmlFilterBase& rSelf, const Reference< XDocumentProperties >& xProperties )
704{
705 rSelf.addRelation(
706 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties",
707 u"docProps/app.xml" );
709 "docProps/app.xml",
710 "application/vnd.openxmlformats-officedocument.extended-properties+xml" );
711 pAppProps->startElement( XML_Properties,
712 XML_xmlns, rSelf.getNamespaceURL(OOX_NS(officeExtPr)),
713 FSNS(XML_xmlns, XML_vt), rSelf.getNamespaceURL(OOX_NS(officeDocPropsVT)));
714
715 uno::Reference<beans::XPropertyAccess> xUserDefinedProperties(xProperties->getUserDefinedProperties(), uno::UNO_QUERY);
716 comphelper::SequenceAsHashMap aUserDefinedProperties(xUserDefinedProperties->getPropertyValues());
718
719 writeElement( pAppProps, XML_Template, xProperties->getTemplateName() );
720
721 it = aUserDefinedProperties.find("Manager");
722 if (it != aUserDefinedProperties.end())
723 {
724 OUString aValue;
725 if (it->second >>= aValue)
726 writeElement( pAppProps, XML_Manager, aValue );
727 }
728
729#ifdef OOXTODO
730 writeElement( pAppProps, XML_PresentationFormat, "presentation format" );
731 writeElement( pAppProps, XML_Lines, "lines" );
732 writeElement( pAppProps, XML_Slides, "slides" );
733 writeElement( pAppProps, XML_Notes, "notes" );
734#endif /* def OOXTODO */
735 // EditingDuration is in seconds, TotalTime is in minutes.
736 writeElement( pAppProps, XML_TotalTime, xProperties->getEditingDuration() / 60 );
737#ifdef OOXTODO
738 writeElement( pAppProps, XML_HiddenSlides, "hidden slides" );
739 writeElement( pAppProps, XML_MMClips, "mm clips" );
740 writeElement( pAppProps, XML_ScaleCrop, "scale crop" );
741 writeElement( pAppProps, XML_HeadingPairs, "heading pairs" );
742 writeElement( pAppProps, XML_TitlesOfParts, "titles of parts" );
743 writeElement( pAppProps, XML_LinksUpToDate, "links up-to-date" );
744 writeElement( pAppProps, XML_SharedDoc, "shared doc" );
745 writeElement( pAppProps, XML_HLinks, "hlinks" );
746 writeElement( pAppProps, XML_HyperlinksChanged, "hyperlinks changed" );
747 writeElement( pAppProps, XML_DigSig, "digital signature" );
748#endif /* def OOXTODO */
749 writeElement( pAppProps, XML_Application, utl::DocInfoHelper::GetGeneratorString() );
750
751 it = aUserDefinedProperties.find("HyperlinkBase");
752 if (it != aUserDefinedProperties.end())
753 {
754 OUString aValue;
755 if (it->second >>= aValue)
756 writeElement( pAppProps, XML_HyperlinkBase, aValue );
757 }
758 // AppVersion specifies the version of the application which produced document
759 // It is strictly connected with MS Office versions:
760 // * 12: [Office 2007] [LO < 7.0]
761 // * 14: [Office 2010]
762 // * 15: [Office 2013/2016/2019] [LO >= 7.0]
763 // The LibreOffice is application on 2013/2016/2019 level
764 writeElement( pAppProps, XML_AppVersion, u"15.0000" );
765
766 // OOXTODO Calculate DocSecurity value based on security (password, read-only etc.)
767 it = aUserDefinedProperties.find("DocSecurity");
768 if (it != aUserDefinedProperties.end())
769 {
770 sal_Int32 nValue;
771 if (it->second >>= nValue)
772 writeElement( pAppProps, XML_DocSecurity, nValue );
773 }
774
775 comphelper::SequenceAsHashMap aStats = xProperties->getDocumentStatistics();
776 sal_Int32 nValue = 0;
777
778 it = aStats.find("PageCount");
779 if (it != aStats.end())
780 {
781 if (it->second >>= nValue)
782 writeElement(pAppProps, XML_Pages, nValue);
783 }
784
785 it = aStats.find("WordCount");
786 if (it != aStats.end())
787 {
788 if (it->second >>= nValue)
789 writeElement(pAppProps, XML_Words, nValue);
790 }
791
792 it = aStats.find("NonWhitespaceCharacterCount");
793 if (it != aStats.end())
794 {
795 if (it->second >>= nValue)
796 writeElement(pAppProps, XML_Characters, nValue);
797 }
798
799 it = aStats.find("CharacterCount");
800 if (it != aStats.end())
801 {
802 if (it->second >>= nValue)
803 writeElement(pAppProps, XML_CharactersWithSpaces, nValue);
804 }
805
806 it = aStats.find("ParagraphCount");
807 if (it != aStats.end())
808 {
809 if (it->second >>= nValue)
810 writeElement(pAppProps, XML_Paragraphs, nValue);
811 }
812
813 it = aUserDefinedProperties.find("Company");
814 if (it != aUserDefinedProperties.end())
815 {
816 OUString aValue;
817 if (it->second >>= aValue)
818 writeElement(pAppProps, XML_Company, aValue);
819 }
820
821 pAppProps->endElement( XML_Properties );
822}
823
824static void
825writeCustomProperties( XmlFilterBase& rSelf, const Reference< XDocumentProperties >& xProperties, bool bSecurityOptOpenReadOnly )
826{
827 uno::Reference<beans::XPropertyAccess> xUserDefinedProperties( xProperties->getUserDefinedProperties(), uno::UNO_QUERY );
828 auto aprop = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(xUserDefinedProperties->getPropertyValues());
829 sal_Int32 nbCustomProperties = aprop.size();
830 // tdf#89791 : if no custom properties, no need to add docProps/custom.x
831 // tdf#107690: except the case of read-only documents, because that
832 // is handled by the _MarkAsFinal custom property in MSO.
833 if (!nbCustomProperties && !bSecurityOptOpenReadOnly)
834 return;
835
836 if (bSecurityOptOpenReadOnly)
837 {
838 PropertyValue aPropertyValue;
839 // MSO custom property for read-only documents
840 aPropertyValue.Name = "_MarkAsFinal";
841 aPropertyValue.Value <<= true;
842 aprop.push_back(aPropertyValue);
843 }
844
845 rSelf.addRelation(
846 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties",
847 u"docProps/custom.xml" );
849 "docProps/custom.xml",
850 "application/vnd.openxmlformats-officedocument.custom-properties+xml" );
851 pAppProps->startElement( XML_Properties,
852 XML_xmlns, rSelf.getNamespaceURL(OOX_NS(officeCustomPr)),
853 FSNS(XML_xmlns, XML_vt), rSelf.getNamespaceURL(OOX_NS(officeDocPropsVT)));
854
855 size_t nIndex = 0;
856 for (const auto& rProp : aprop)
857 {
858 if ( !rProp.Name.isEmpty() )
859 {
860 // Skip storing these values in Custom Properties as it will be stored in Core/Extended Properties
861 if (( rProp.Name == "OOXMLCorePropertyCategory" ) || // stored in cp:category
862 ( rProp.Name == "OOXMLCorePropertyContentStatus" ) || // stored in cp:contentStatus
863 ( rProp.Name == "OOXMLCorePropertyContentType" ) || // stored in cp:contentType
864 ( rProp.Name == "OOXMLCorePropertyIdentifier" ) || // stored in dc:identifier
865 ( rProp.Name == "OOXMLCorePropertyVersion" ) || // stored in cp:version
866 ( rProp.Name == "HyperlinkBase" ) || // stored in Extended File Properties
867 ( rProp.Name == "AppVersion" ) || // stored in Extended File Properties
868 ( rProp.Name == "DocSecurity" ) || // stored in Extended File Properties
869 ( rProp.Name == "Manager" ) || // stored in Extended File Properties
870 ( rProp.Name == "Company" )) // stored in Extended File Properties
871 continue;
872
873 // pid starts from 2 not from 1 as MS supports pid from 2
874 pAppProps->startElement( XML_property ,
875 XML_fmtid, "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}",
876 XML_pid, OString::number(nIndex + 2),
877 XML_name, rProp.Name);
878
879 switch ( rProp.Value.getValueTypeClass() )
880 {
881 case TypeClass_STRING:
882 {
883 OUString aValue;
884 rProp.Value >>= aValue;
885 writeElement( pAppProps, FSNS( XML_vt, XML_lpwstr ), aValue );
886 }
887 break;
888 case TypeClass_BOOLEAN:
889 {
890 bool val = *o3tl::forceAccess<bool>(rProp.Value);
891 writeElement( pAppProps, FSNS( XML_vt, XML_bool ), val ? 1 : 0);
892 }
893 break;
894 case TypeClass_DOUBLE:
895 {
896 double num = {}; // spurious -Werror=maybe-uninitialized
897 if ( rProp.Value >>= num )
898 {
899 // r8 - 8-byte real number
900 writeElement( pAppProps, FSNS( XML_vt, XML_r8 ), OUString::number(num) );
901 }
902 }
903 break;
904 default:
905 {
906 double num = {}; // spurious -Werror=maybe-uninitialized
907 util::Date aDate;
908 util::Duration aDuration;
909 util::DateTime aDateTime;
910 if ( rProp.Value >>= num )
911 {
912 // i4 - 4-byte signed integer
913 writeElement( pAppProps, FSNS( XML_vt, XML_i4 ), num );
914 }
915 else if ( rProp.Value >>= aDate )
916 {
917 aDateTime = util::DateTime( 0, 0 , 0, 0, aDate.Day, aDate.Month, aDate.Year, true );
918 writeElement( pAppProps, FSNS( XML_vt, XML_filetime ), aDateTime);
919 }
920 else if ( rProp.Value >>= aDuration )
921 {
922 OUStringBuffer buf;
923 ::sax::Converter::convertDuration( buf, aDuration );
924 OUString aDurationStr = buf.makeStringAndClear();
925 writeElement( pAppProps, FSNS( XML_vt, XML_lpwstr ), aDurationStr );
926 }
927 else if ( rProp.Value >>= aDateTime )
928 writeElement( pAppProps, FSNS( XML_vt, XML_filetime ), aDateTime );
929 else
930 //no other options
931 OSL_FAIL( "XMLFilterBase::writeCustomProperties unsupported value type!" );
932 }
933 break;
934 }
935 pAppProps->endElement( XML_property );
936 }
937 ++nIndex;
938 }
939 pAppProps->endElement( XML_Properties );
940}
941
942void XmlFilterBase::exportDocumentProperties( const Reference< XDocumentProperties >& xProperties, bool bSecurityOptOpenReadOnly )
943{
944 if( xProperties.is() )
945 {
946 writeCoreProperties( *this, xProperties );
947 writeAppProperties( *this, xProperties );
948 writeCustomProperties( *this, xProperties, bSecurityOptOpenReadOnly );
949 }
950}
951
952// protected ------------------------------------------------------------------
953
954Reference< XInputStream > XmlFilterBase::implGetInputStream( MediaDescriptor& rMediaDesc ) const
955{
956 /* Get the input stream directly from the media descriptor, or decrypt the
957 package again. The latter is needed e.g. when the document is reloaded.
958 All this is implemented in the detector service. */
960 return xDetector->extractUnencryptedPackage( rMediaDesc );
961}
962
963Reference<XStream> XmlFilterBase::implGetOutputStream( MediaDescriptor& rMediaDescriptor ) const
964{
965 const Sequence< NamedValue > aMediaEncData = rMediaDescriptor.getUnpackedValueOrDefault(
967 Sequence< NamedValue >() );
968
969 if (aMediaEncData.getLength() == 0)
970 {
971 return FilterBase::implGetOutputStream( rMediaDescriptor );
972 }
973 else // We need to encrypt the stream so create a memory stream
974 {
975 Reference< XComponentContext > xContext = getComponentContext();
976 return Reference< XStream > (
977 xContext->getServiceManager()->createInstanceWithContext("com.sun.star.comp.MemoryStream", xContext),
978 uno::UNO_QUERY_THROW );
979 }
980}
981
983{
984 bool bRet = true;
985
986 const Sequence< NamedValue > aMediaEncData = rMediaDescriptor.getUnpackedValueOrDefault(
988 Sequence< NamedValue >() );
989
990 if (aMediaEncData.getLength())
991 {
993
994 Reference< XStream> xDocumentStream (FilterBase::implGetOutputStream(rMediaDescriptor));
995 oox::ole::OleStorage aOleStorage( getComponentContext(), xDocumentStream, true );
996 crypto::DocumentEncryption encryptor( getComponentContext(), getMainDocumentStream(), aOleStorage, aMediaEncData );
997 bRet = encryptor.encrypt();
998 if (bRet)
999 aOleStorage.commit();
1000 }
1001
1002 return bRet;
1003}
1004
1005// private --------------------------------------------------------------------
1006
1007StorageRef XmlFilterBase::implCreateStorage( const Reference< XInputStream >& rxInStream ) const
1008{
1009 return std::make_shared<ZipStorage>( getComponentContext(), rxInStream );
1010}
1011
1012StorageRef XmlFilterBase::implCreateStorage( const Reference< XStream >& rxOutStream ) const
1013{
1014 return std::make_shared<ZipStorage>( getComponentContext(), rxOutStream );
1015}
1016
1018{
1019 return mbMSO2007;
1020}
1021
1023{
1024 return mbMSO;
1025}
1026
1028{
1029 mbMissingExtDrawing = true;
1030}
1031
1033{
1034 mxImpl->mpDiagramFontHeights = pDiagramFontHeights;
1035}
1036
1038
1039OUString XmlFilterBase::getNamespaceURL(sal_Int32 nNSID) const
1040{
1041 auto itr = mxImpl->mrNamespaceMap.maTransitionalNamespaceMap.find(nNSID);
1042 if (itr == mxImpl->mrNamespaceMap.maTransitionalNamespaceMap.end())
1043 {
1044 SAL_WARN("oox", "missing namespace in the namespace map for : " << nNSID);
1045 return OUString();
1046 }
1047
1048 return itr->second;
1049}
1050
1051void XmlFilterBase::importCustomFragments(css::uno::Reference<css::embed::XStorage> const & xDocumentStorage)
1052{
1053 Reference<XRelationshipAccess> xRelations(xDocumentStorage, UNO_QUERY);
1054 if (!xRelations.is())
1055 return;
1056
1057 const uno::Sequence<uno::Sequence<beans::StringPair>> aSeqs = xRelations->getAllRelationships();
1058
1059 std::vector<StreamDataSequence> aCustomFragments;
1060 std::vector<OUString> aCustomFragmentTypes;
1061 std::vector<OUString> aCustomFragmentTargets;
1062 for (const uno::Sequence<beans::StringPair>& aSeq : aSeqs)
1063 {
1064 OUString sType;
1065 OUString sTarget;
1066 for (const beans::StringPair& aPair : aSeq)
1067 {
1068 if (aPair.First == "Target")
1069 sTarget = aPair.Second;
1070 else if (aPair.First == "Type")
1071 sType = aPair.Second;
1072 }
1073
1074 // Preserve non-standard (i.e. custom) entries.
1075 if (!sType.match("http://schemas.openxmlformats.org") // OOXML/ECMA Transitional
1076 && !sType.match("http://purl.oclc.org")) // OOXML Strict
1077 {
1078 StreamDataSequence aDataSeq;
1079 if (importBinaryData(aDataSeq, sTarget))
1080 {
1081 aCustomFragments.emplace_back(aDataSeq);
1082 aCustomFragmentTypes.emplace_back(sType);
1083 aCustomFragmentTargets.emplace_back(sTarget);
1084 }
1085 }
1086 }
1087
1088 // Adding the saved custom xml DOM
1089 comphelper::SequenceAsHashMap aGrabBagProperties;
1090 aGrabBagProperties["OOXCustomFragments"] <<= comphelper::containerToSequence(aCustomFragments);
1091 aGrabBagProperties["OOXCustomFragmentTypes"] <<= comphelper::containerToSequence(aCustomFragmentTypes);
1092 aGrabBagProperties["OOXCustomFragmentTargets"] <<= comphelper::containerToSequence(aCustomFragmentTargets);
1093
1094 std::vector<uno::Reference<xml::dom::XDocument>> aCustomXmlDomList;
1095 std::vector<uno::Reference<xml::dom::XDocument>> aCustomXmlDomPropsList;
1096 //FIXME: Ideally, we should get these the relations, but it seems that is not consistently set.
1097 // In some cases it's stored in the workbook relationships, which is unexpected. So we discover them directly.
1098 for (int i = 1; ; ++i)
1099 {
1100 Reference<XDocument> xCustDoc = importFragment("customXml/item" + OUString::number(i) + ".xml");
1101 Reference<XDocument> xCustDocProps = importFragment("customXml/itemProps" + OUString::number(i) + ".xml");
1102 if (xCustDoc && xCustDocProps)
1103 {
1104 aCustomXmlDomList.emplace_back(xCustDoc);
1105 aCustomXmlDomPropsList.emplace_back(xCustDocProps);
1106 }
1107 else
1108 break;
1109 }
1110
1111 // Adding the saved custom xml DOM
1112 aGrabBagProperties["OOXCustomXml"] <<= comphelper::containerToSequence(aCustomXmlDomList);
1113 aGrabBagProperties["OOXCustomXmlProps"] <<= comphelper::containerToSequence(aCustomXmlDomPropsList);
1114
1115 // Save the [Content_Types].xml after parsing.
1116 uno::Sequence<uno::Sequence<beans::StringPair>> aContentTypeInfo;
1117 uno::Reference<io::XInputStream> xInputStream = openInputStream("[Content_Types].xml");
1118 if (xInputStream.is())
1120
1121 aGrabBagProperties["OOXContentTypes"] <<= aContentTypeInfo;
1122
1123 Reference<XComponent> xModel = getModel();
1125}
1126
1128{
1129 Reference<XComponent> xModel = getModel();
1130 uno::Reference<beans::XPropertySet> xPropSet(xModel, uno::UNO_QUERY_THROW);
1131
1132 uno::Reference<beans::XPropertySetInfo> xPropSetInfo = xPropSet->getPropertySetInfo();
1133 if (!xPropSetInfo->hasPropertyByName(UNO_NAME_MISC_OBJ_INTEROPGRABBAG))
1134 return;
1135
1136 uno::Sequence<uno::Reference<xml::dom::XDocument>> customXmlDomlist;
1137 uno::Sequence<uno::Reference<xml::dom::XDocument>> customXmlDomPropslist;
1138 uno::Sequence<StreamDataSequence> customFragments;
1139 uno::Sequence<OUString> customFragmentTypes;
1140 uno::Sequence<OUString> customFragmentTargets;
1141 uno::Sequence<uno::Sequence<beans::StringPair>> aContentTypes;
1142
1143 uno::Sequence<beans::PropertyValue> propList;
1144 xPropSet->getPropertyValue(UNO_NAME_MISC_OBJ_INTEROPGRABBAG) >>= propList;
1145 for (const auto& rProp : std::as_const(propList))
1146 {
1147 const OUString propName = rProp.Name;
1148 if (propName == "OOXCustomXml")
1149 {
1150 rProp.Value >>= customXmlDomlist;
1151 }
1152 else if (propName == "OOXCustomXmlProps")
1153 {
1154 rProp.Value >>= customXmlDomPropslist;
1155 }
1156 else if (propName == "OOXCustomFragments")
1157 {
1158 rProp.Value >>= customFragments;
1159 }
1160 else if (propName == "OOXCustomFragmentTypes")
1161 {
1162 rProp.Value >>= customFragmentTypes;
1163 }
1164 else if (propName == "OOXCustomFragmentTargets")
1165 {
1166 rProp.Value >>= customFragmentTargets;
1167 }
1168 else if (propName == "OOXContentTypes")
1169 {
1170 rProp.Value >>= aContentTypes;
1171 }
1172 }
1173
1174 // Expect customXmlDomPropslist.getLength() == customXmlDomlist.getLength().
1175 for (sal_Int32 j = 0; j < customXmlDomlist.getLength(); j++)
1176 {
1177 uno::Reference<xml::dom::XDocument> customXmlDom = customXmlDomlist[j];
1178 uno::Reference<xml::dom::XDocument> customXmlDomProps = customXmlDomPropslist[j];
1179 const OUString fragmentPath = "customXml/item" + OUString::number(j+1) + ".xml";
1180 if (customXmlDom.is())
1181 {
1182 addRelation(oox::getRelationship(Relationship::CUSTOMXML), OUStringConcatenation("../" + fragmentPath));
1183
1184 uno::Reference<xml::sax::XSAXSerializable> serializer(customXmlDom, uno::UNO_QUERY);
1185 uno::Reference<xml::sax::XWriter> writer = xml::sax::Writer::create(comphelper::getProcessComponentContext());
1186 writer->setOutputStream(openFragmentStream(fragmentPath, "application/xml"));
1187 serializer->serialize(uno::Reference<xml::sax::XDocumentHandler>(writer, uno::UNO_QUERY_THROW),
1188 uno::Sequence<beans::StringPair>());
1189 }
1190
1191 if (customXmlDomProps.is())
1192 {
1193 uno::Reference<xml::sax::XSAXSerializable> serializer(customXmlDomProps, uno::UNO_QUERY);
1194 uno::Reference<xml::sax::XWriter> writer = xml::sax::Writer::create(comphelper::getProcessComponentContext());
1195 writer->setOutputStream(openFragmentStream("customXml/itemProps"+OUString::number(j+1)+".xml",
1196 "application/vnd.openxmlformats-officedocument.customXmlProperties+xml"));
1197 serializer->serialize(uno::Reference<xml::sax::XDocumentHandler>(writer, uno::UNO_QUERY_THROW),
1198 uno::Sequence<beans::StringPair>());
1199
1200 // Adding itemprops's relationship entry to item.xml.rels file
1201 addRelation(openFragmentStream(fragmentPath, "application/xml"),
1203 OUStringConcatenation("itemProps"+OUString::number(j+1)+".xml"));
1204 }
1205 }
1206
1207 // Expect customFragments.getLength() == customFragmentTypes.getLength() == customFragmentTargets.getLength().
1208 for (sal_Int32 j = 0; j < customFragments.getLength(); j++)
1209 {
1210 addRelation(customFragmentTypes[j], customFragmentTargets[j]);
1211 const OUString aFilename = customFragmentTargets[j];
1212 Reference<XOutputStream> xOutStream = openOutputStream(aFilename);
1213 if (xOutStream.is())
1214 {
1215 xOutStream->writeBytes(customFragments[j]);
1216 uno::Reference<XPropertySet> xProps(xOutStream, uno::UNO_QUERY);
1217 if (xProps.is())
1218 {
1219 const OUString aType = comphelper::OFOPXMLHelper::GetContentTypeByName(aContentTypes, aFilename);
1220 const OUString aContentType = (aType.getLength() ? aType : OUString("application/octet-stream"));
1221 xProps->setPropertyValue("MediaType", uno::Any(aContentType));
1222 }
1223 }
1224 }
1225}
1226
1227} // namespace oox::core
1228
1229/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OptionalString sType
static OUString decode(std::u16string_view rText, DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
OUString getBcp47MS() const
static css::uno::Reference< css::embed::XStorage > GetStorageOfFormatFromInputStream(const OUString &aFormat, const css::uno::Reference< css::io::XInputStream > &xStream, const css::uno::Reference< css::uno::XComponentContext > &rxContext=css::uno::Reference< css::uno::XComponentContext >(), bool bRepairStorage=false)
iterator find(const OUString &rKey)
SequenceAsHashMapBase::iterator iterator
css::uno::Sequence< css::beans::PropertyValue > getAsConstPropertyValueList() const
void update(const SequenceAsHashMap &rSource)
void reserve(size_type amount)
std::pair< const_iterator, bool > insert(Value &&x)
A wrapper for a UNO property set.
Definition: propertyset.hxx:58
bool setProperty(sal_Int32 nPropId, const Type &rValue)
Puts the passed value into the property set.
void commit()
Commits the changes to the storage and all substorages.
Wrapper for a fast SAX parser that works on automatically generated OOXML token and namespace identif...
Definition: fastparser.hxx:54
void parseStream(const css::xml::sax::InputSource &rInputSource, bool bCloseStream=false)
Parses the passed SAX input source.
void setDocumentHandler(const css::uno::Reference< css::xml::sax::XFastDocumentHandler > &rxDocHandler)
Sets the passed document handler that will receive the SAX parser events.
Definition: fastparser.cxx:101
bool importBinaryData(StreamDataSequence &orDataSeq, const OUString &rStreamName)
Imports the raw binary data from the specified stream.
Definition: filterbase.cxx:382
utl::MediaDescriptor & getMediaDescriptor() const
Returns the media descriptor.
Definition: filterbase.cxx:240
const css::uno::Reference< css::frame::XModel > & getModel() const
Returns the document model (always existing).
Definition: filterbase.cxx:220
OoxmlVersion getVersion() const
Definition: filterbase.cxx:210
void commitStorage() const
Commits changes to base storage (and substorages)
Definition: filterbase.cxx:339
css::uno::Reference< css::io::XInputStream > openInputStream(const OUString &rStreamName) const
Opens and returns the specified input stream from the base storage.
Definition: filterbase.cxx:327
virtual css::uno::Reference< css::io::XStream > implGetOutputStream(utl::MediaDescriptor &rMediaDesc) const
Definition: filterbase.cxx:514
const css::uno::Reference< css::uno::XComponentContext > & getComponentContext() const
Returns the component context passed in the filter constructor (always existing).
Definition: filterbase.cxx:215
css::uno::Reference< css::io::XStream > const & getMainDocumentStream() const
Definition: filterbase.cxx:524
css::uno::Reference< css::io::XOutputStream > openOutputStream(const OUString &rStreamName) const
Opens and returns the specified output stream from the base storage.
Definition: filterbase.cxx:334
StorageRef const & getStorage() const
Returns the base storage of the imported/exported file.
Definition: filterbase.cxx:322
void setFragmentHandler(const ::rtl::Reference< FragmentHandler > &rxHandler)
void parseStream(const RecordInputSource &rInputSource)
virtual ~XmlFilterBase() override
void setDiagramFontHeights(NamedShapePairs *pDiagramFontHeights)
RelationsRef importRelations(const OUString &rFragmentPath)
Imports the relations fragment associated with the specified fragment.
virtual css::uno::Reference< css::io::XStream > implGetOutputStream(utl::MediaDescriptor &rMediaDesc) const override
NamedShapePairs * getDiagramFontHeights()
void importDocumentProperties()
Read the document properties and also the customXml entries (xlsx and pptx only).
::sax_fastparser::FSHelperPtr openFragmentStreamWithSerializer(const OUString &rStreamName, const OUString &rMediaType)
Opens specified output stream from the base storage with specified media type and returns new fast se...
OUString addRelation(const OUString &rType, std::u16string_view rTarget)
Adds new relation.
static FastParser * createParser()
void setMissingExtDrawing()
Signal that an MSO 2007-created SmartArt was found, need to warn the user about it.
OUString getFragmentPathFromFirstTypeFromOfficeDoc(std::u16string_view rPart)
virtual std::shared_ptr<::oox::drawingml::Theme > getCurrentThemePtr() const
May be implemented by filters which handle Diagrams, default returns empty ptr.
bool importFragment(const rtl::Reference< FragmentHandler > &rxHandler)
Imports a fragment using the passed fragment handler, which contains the full path to the fragment st...
void checkDocumentProperties(const css::uno::Reference< css::document::XDocumentProperties > &xDocProps)
css::uno::Reference< css::io::XOutputStream > openFragmentStream(const OUString &rStreamName, const OUString &rMediaType)
Opens and returns the specified output stream from the base storage with specified media type.
XmlFilterBase(const css::uno::Reference< css::uno::XComponentContext > &rxContext)
OUString getNamespaceURL(sal_Int32 nNSID) const
void exportCustomFragments()
Write the customXml entries we are preserving (xlsx and pptx only).
::std::unique_ptr< XmlFilterBaseImpl > mxImpl
virtual bool implFinalizeExport(utl::MediaDescriptor &rMediaDescriptor) override
void importCustomFragments(css::uno::Reference< css::embed::XStorage > const &xDocumentStorage)
virtual css::uno::Reference< css::io::XInputStream > implGetInputStream(utl::MediaDescriptor &rMediaDesc) const override
virtual StorageRef implCreateStorage(const css::uno::Reference< css::io::XInputStream > &rxInStream) const override
static void putPropertiesToDocumentGrabBag(const css::uno::Reference< css::lang::XComponent > &xDstDoc, const comphelper::SequenceAsHashMap &rProperties)
void exportDocumentProperties(const css::uno::Reference< css::document::XDocumentProperties > &xProperties, bool bSecurityOptOpenReadOnly)
Write the document properties into into the current OPC package.
Implements stream access for binary OLE storages.
Definition: olestorage.hxx:44
static void convertDuration(OUStringBuffer &rBuffer, const double fTime)
static OUString GetGeneratorString()
static constexpr OUStringLiteral PROP_ENCRYPTIONDATA
float u
FilterGroup & rTarget
sal_Int16 nValue
constexpr sal_Int32 FSNS(sal_Int32 namespc, sal_Int32 element)
sal_Int32 nIndex
Sequence< sal_Int8 > aSeq
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
@ Exception
uno::Sequence< uno::Sequence< beans::StringPair > > ReadContentTypeSequence(const uno::Reference< io::XInputStream > &xInStream, const uno::Reference< uno::XComponentContext > &rContext)
OUString GetContentTypeByName(const css::uno::Sequence< css::uno::Sequence< css::beans::StringPair > > &rContentTypes, const OUString &rFilename)
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
Reference< XComponentContext > getProcessComponentContext()
constexpr OUStringLiteral gaBinSuffix(u".bin")
@ ISOIEC_29500_2008
Definition: filterbase.hxx:77
static void writeAppProperties(XmlFilterBase &rSelf, const Reference< XDocumentProperties > &xProperties)
static void writeElement(const FSHelperPtr &pDoc, sal_Int32 nXmlElement, std::u16string_view sValue)
std::shared_ptr< Relations > RelationsRef
Definition: relations.hxx:63
static void writeCoreProperties(XmlFilterBase &rSelf, const Reference< XDocumentProperties > &xProperties)
static void writeCustomProperties(XmlFilterBase &rSelf, const Reference< XDocumentProperties > &xProperties, bool bSecurityOptOpenReadOnly)
std::map< OUString, ShapePairs > NamedShapePairs
OUString getRelationship(Relationship eRelationship)
std::shared_ptr< StorageBase > StorageRef
Definition: storagebase.hxx:42
css::uno::Sequence< sal_Int8 > StreamDataSequence
NamespaceMap & StaticNamespaceMap()
Thread-safe singleton of a map of all supported XML namespace URLs.
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
std::shared_ptr< FastSerializerHelper > FSHelperPtr
XML_type
sal_Int16 nId
Definition: olehelper.cxx:98
constexpr OUStringLiteral OFOPXML_STORAGE_FORMAT_STRING
A map that contains all XML namespace URLs used in the filters.
BinaryInputStreamRef mxInStream
RefMap< OUString, Relations > RelationsMap
NamedShapePairs * mpDiagramFontHeights
const NamespaceMap & mrNamespaceMap
Reference< XModel > xModel
OUString sId
constexpr OUStringLiteral UNO_NAME_MISC_OBJ_INTEROPGRABBAG