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