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 pCoreProps->endDocument();
702}
703
704static void
705writeAppProperties( XmlFilterBase& rSelf, const Reference< XDocumentProperties >& xProperties )
706{
707 rSelf.addRelation(
708 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties",
709 u"docProps/app.xml" );
711 "docProps/app.xml",
712 "application/vnd.openxmlformats-officedocument.extended-properties+xml" );
713 pAppProps->startElement( XML_Properties,
714 XML_xmlns, rSelf.getNamespaceURL(OOX_NS(officeExtPr)),
715 FSNS(XML_xmlns, XML_vt), rSelf.getNamespaceURL(OOX_NS(officeDocPropsVT)));
716
717 uno::Reference<beans::XPropertyAccess> xUserDefinedProperties(xProperties->getUserDefinedProperties(), uno::UNO_QUERY);
718 comphelper::SequenceAsHashMap aUserDefinedProperties(xUserDefinedProperties->getPropertyValues());
720
721 writeElement( pAppProps, XML_Template, xProperties->getTemplateName() );
722
723 it = aUserDefinedProperties.find("Manager");
724 if (it != aUserDefinedProperties.end())
725 {
726 OUString aValue;
727 if (it->second >>= aValue)
728 writeElement( pAppProps, XML_Manager, aValue );
729 }
730
731#ifdef OOXTODO
732 writeElement( pAppProps, XML_PresentationFormat, "presentation format" );
733 writeElement( pAppProps, XML_Lines, "lines" );
734 writeElement( pAppProps, XML_Slides, "slides" );
735 writeElement( pAppProps, XML_Notes, "notes" );
736#endif /* def OOXTODO */
737 // EditingDuration is in seconds, TotalTime is in minutes.
738 writeElement( pAppProps, XML_TotalTime, xProperties->getEditingDuration() / 60 );
739#ifdef OOXTODO
740 writeElement( pAppProps, XML_HiddenSlides, "hidden slides" );
741 writeElement( pAppProps, XML_MMClips, "mm clips" );
742 writeElement( pAppProps, XML_ScaleCrop, "scale crop" );
743 writeElement( pAppProps, XML_HeadingPairs, "heading pairs" );
744 writeElement( pAppProps, XML_TitlesOfParts, "titles of parts" );
745 writeElement( pAppProps, XML_LinksUpToDate, "links up-to-date" );
746 writeElement( pAppProps, XML_SharedDoc, "shared doc" );
747 writeElement( pAppProps, XML_HLinks, "hlinks" );
748 writeElement( pAppProps, XML_HyperlinksChanged, "hyperlinks changed" );
749 writeElement( pAppProps, XML_DigSig, "digital signature" );
750#endif /* def OOXTODO */
751 writeElement( pAppProps, XML_Application, utl::DocInfoHelper::GetGeneratorString() );
752
753 it = aUserDefinedProperties.find("HyperlinkBase");
754 if (it != aUserDefinedProperties.end())
755 {
756 OUString aValue;
757 if (it->second >>= aValue)
758 writeElement( pAppProps, XML_HyperlinkBase, aValue );
759 }
760 // AppVersion specifies the version of the application which produced document
761 // It is strictly connected with MS Office versions:
762 // * 12: [Office 2007] [LO < 7.0]
763 // * 14: [Office 2010]
764 // * 15: [Office 2013/2016/2019] [LO >= 7.0]
765 // The LibreOffice is application on 2013/2016/2019 level
766 writeElement( pAppProps, XML_AppVersion, u"15.0000" );
767
768 // OOXTODO Calculate DocSecurity value based on security (password, read-only etc.)
769 it = aUserDefinedProperties.find("DocSecurity");
770 if (it != aUserDefinedProperties.end())
771 {
772 sal_Int32 nValue;
773 if (it->second >>= nValue)
774 writeElement( pAppProps, XML_DocSecurity, nValue );
775 }
776
777 comphelper::SequenceAsHashMap aStats = xProperties->getDocumentStatistics();
778 sal_Int32 nValue = 0;
779
780 it = aStats.find("PageCount");
781 if (it != aStats.end())
782 {
783 if (it->second >>= nValue)
784 writeElement(pAppProps, XML_Pages, nValue);
785 }
786
787 it = aStats.find("WordCount");
788 if (it != aStats.end())
789 {
790 if (it->second >>= nValue)
791 writeElement(pAppProps, XML_Words, nValue);
792 }
793
794 it = aStats.find("NonWhitespaceCharacterCount");
795 if (it != aStats.end())
796 {
797 if (it->second >>= nValue)
798 writeElement(pAppProps, XML_Characters, nValue);
799 }
800
801 it = aStats.find("CharacterCount");
802 if (it != aStats.end())
803 {
804 if (it->second >>= nValue)
805 writeElement(pAppProps, XML_CharactersWithSpaces, nValue);
806 }
807
808 it = aStats.find("ParagraphCount");
809 if (it != aStats.end())
810 {
811 if (it->second >>= nValue)
812 writeElement(pAppProps, XML_Paragraphs, nValue);
813 }
814
815 it = aUserDefinedProperties.find("Company");
816 if (it != aUserDefinedProperties.end())
817 {
818 OUString aValue;
819 if (it->second >>= aValue)
820 writeElement(pAppProps, XML_Company, aValue);
821 }
822
823 pAppProps->endElement( XML_Properties );
824
825 pAppProps->endDocument();
826}
827
828static void
829writeCustomProperties( XmlFilterBase& rSelf, const Reference< XDocumentProperties >& xProperties, bool bSecurityOptOpenReadOnly )
830{
831 uno::Reference<beans::XPropertyAccess> xUserDefinedProperties( xProperties->getUserDefinedProperties(), uno::UNO_QUERY );
832 auto aprop = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(xUserDefinedProperties->getPropertyValues());
833 sal_Int32 nbCustomProperties = aprop.size();
834 // tdf#89791 : if no custom properties, no need to add docProps/custom.x
835 // tdf#107690: except the case of read-only documents, because that
836 // is handled by the _MarkAsFinal custom property in MSO.
837 if (!nbCustomProperties && !bSecurityOptOpenReadOnly)
838 return;
839
840 if (bSecurityOptOpenReadOnly)
841 {
842 PropertyValue aPropertyValue;
843 // MSO custom property for read-only documents
844 aPropertyValue.Name = "_MarkAsFinal";
845 aPropertyValue.Value <<= true;
846 aprop.push_back(aPropertyValue);
847 }
848
849 rSelf.addRelation(
850 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties",
851 u"docProps/custom.xml" );
853 "docProps/custom.xml",
854 "application/vnd.openxmlformats-officedocument.custom-properties+xml" );
855 pAppProps->startElement( XML_Properties,
856 XML_xmlns, rSelf.getNamespaceURL(OOX_NS(officeCustomPr)),
857 FSNS(XML_xmlns, XML_vt), rSelf.getNamespaceURL(OOX_NS(officeDocPropsVT)));
858
859 size_t nIndex = 0;
860 for (const auto& rProp : aprop)
861 {
862 if ( !rProp.Name.isEmpty() )
863 {
864 // Skip storing these values in Custom Properties as it will be stored in Core/Extended Properties
865 if (( rProp.Name == "OOXMLCorePropertyCategory" ) || // stored in cp:category
866 ( rProp.Name == "OOXMLCorePropertyContentStatus" ) || // stored in cp:contentStatus
867 ( rProp.Name == "OOXMLCorePropertyContentType" ) || // stored in cp:contentType
868 ( rProp.Name == "OOXMLCorePropertyIdentifier" ) || // stored in dc:identifier
869 ( rProp.Name == "OOXMLCorePropertyVersion" ) || // stored in cp:version
870 ( rProp.Name == "HyperlinkBase" ) || // stored in Extended File Properties
871 ( rProp.Name == "AppVersion" ) || // stored in Extended File Properties
872 ( rProp.Name == "DocSecurity" ) || // stored in Extended File Properties
873 ( rProp.Name == "Manager" ) || // stored in Extended File Properties
874 ( rProp.Name == "Company" )) // stored in Extended File Properties
875 continue;
876
877 // pid starts from 2 not from 1 as MS supports pid from 2
878 pAppProps->startElement( XML_property ,
879 XML_fmtid, "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}",
880 XML_pid, OString::number(nIndex + 2),
881 XML_name, rProp.Name);
882
883 switch ( rProp.Value.getValueTypeClass() )
884 {
885 case TypeClass_STRING:
886 {
887 OUString aValue;
888 rProp.Value >>= aValue;
889 writeElement( pAppProps, FSNS( XML_vt, XML_lpwstr ), aValue );
890 }
891 break;
892 case TypeClass_BOOLEAN:
893 {
894 bool val = *o3tl::forceAccess<bool>(rProp.Value);
895 writeElement( pAppProps, FSNS( XML_vt, XML_bool ), val ? 1 : 0);
896 }
897 break;
898 case TypeClass_DOUBLE:
899 {
900 double num = {}; // spurious -Werror=maybe-uninitialized
901 if ( rProp.Value >>= num )
902 {
903 // r8 - 8-byte real number
904 writeElement( pAppProps, FSNS( XML_vt, XML_r8 ), OUString::number(num) );
905 }
906 }
907 break;
908 default:
909 {
910 double num = {}; // spurious -Werror=maybe-uninitialized
911 util::Date aDate;
912 util::Duration aDuration;
913 util::DateTime aDateTime;
914 if ( rProp.Value >>= num )
915 {
916 // i4 - 4-byte signed integer
917 writeElement( pAppProps, FSNS( XML_vt, XML_i4 ), num );
918 }
919 else if ( rProp.Value >>= aDate )
920 {
921 aDateTime = util::DateTime( 0, 0 , 0, 0, aDate.Day, aDate.Month, aDate.Year, true );
922 writeElement( pAppProps, FSNS( XML_vt, XML_filetime ), aDateTime);
923 }
924 else if ( rProp.Value >>= aDuration )
925 {
926 OUStringBuffer buf;
927 ::sax::Converter::convertDuration( buf, aDuration );
928 OUString aDurationStr = buf.makeStringAndClear();
929 writeElement( pAppProps, FSNS( XML_vt, XML_lpwstr ), aDurationStr );
930 }
931 else if ( rProp.Value >>= aDateTime )
932 writeElement( pAppProps, FSNS( XML_vt, XML_filetime ), aDateTime );
933 else
934 //no other options
935 OSL_FAIL( "XMLFilterBase::writeCustomProperties unsupported value type!" );
936 }
937 break;
938 }
939 pAppProps->endElement( XML_property );
940 }
941 ++nIndex;
942 }
943 pAppProps->endElement( XML_Properties );
944
945 pAppProps->endDocument();
946}
947
948void XmlFilterBase::exportDocumentProperties( const Reference< XDocumentProperties >& xProperties, bool bSecurityOptOpenReadOnly )
949{
950 if( xProperties.is() )
951 {
952 writeCoreProperties( *this, xProperties );
953 writeAppProperties( *this, xProperties );
954 writeCustomProperties( *this, xProperties, bSecurityOptOpenReadOnly );
955 }
956}
957
958// protected ------------------------------------------------------------------
959
960Reference< XInputStream > XmlFilterBase::implGetInputStream( MediaDescriptor& rMediaDesc ) const
961{
962 /* Get the input stream directly from the media descriptor, or decrypt the
963 package again. The latter is needed e.g. when the document is reloaded.
964 All this is implemented in the detector service. */
966 return xDetector->extractUnencryptedPackage( rMediaDesc );
967}
968
969Reference<XStream> XmlFilterBase::implGetOutputStream( MediaDescriptor& rMediaDescriptor ) const
970{
971 const Sequence< NamedValue > aMediaEncData = rMediaDescriptor.getUnpackedValueOrDefault(
973 Sequence< NamedValue >() );
974
975 if (aMediaEncData.getLength() == 0)
976 {
977 return FilterBase::implGetOutputStream( rMediaDescriptor );
978 }
979 else // We need to encrypt the stream so create a memory stream
980 {
981 Reference< XComponentContext > xContext = getComponentContext();
982 return Reference< XStream > (
983 xContext->getServiceManager()->createInstanceWithContext("com.sun.star.comp.MemoryStream", xContext),
984 uno::UNO_QUERY_THROW );
985 }
986}
987
989{
990 bool bRet = true;
991
992 const Sequence< NamedValue > aMediaEncData = rMediaDescriptor.getUnpackedValueOrDefault(
994 Sequence< NamedValue >() );
995
996 if (aMediaEncData.getLength())
997 {
999
1000 Reference< XStream> xDocumentStream (FilterBase::implGetOutputStream(rMediaDescriptor));
1001 oox::ole::OleStorage aOleStorage( getComponentContext(), xDocumentStream, true );
1002 crypto::DocumentEncryption encryptor( getComponentContext(), getMainDocumentStream(), aOleStorage, aMediaEncData );
1003 bRet = encryptor.encrypt();
1004 if (bRet)
1005 aOleStorage.commit();
1006 }
1007
1008 return bRet;
1009}
1010
1011// private --------------------------------------------------------------------
1012
1013StorageRef XmlFilterBase::implCreateStorage( const Reference< XInputStream >& rxInStream ) const
1014{
1015 return std::make_shared<ZipStorage>( getComponentContext(), rxInStream );
1016}
1017
1018StorageRef XmlFilterBase::implCreateStorage( const Reference< XStream >& rxOutStream ) const
1019{
1020 return std::make_shared<ZipStorage>( getComponentContext(), rxOutStream );
1021}
1022
1024{
1025 return mbMSO2007;
1026}
1027
1029{
1030 return mbMSO;
1031}
1032
1034{
1035 mbMissingExtDrawing = true;
1036}
1037
1039{
1040 mxImpl->mpDiagramFontHeights = pDiagramFontHeights;
1041}
1042
1044
1045OUString XmlFilterBase::getNamespaceURL(sal_Int32 nNSID) const
1046{
1047 auto itr = mxImpl->mrNamespaceMap.maTransitionalNamespaceMap.find(nNSID);
1048 if (itr == mxImpl->mrNamespaceMap.maTransitionalNamespaceMap.end())
1049 {
1050 SAL_WARN("oox", "missing namespace in the namespace map for : " << nNSID);
1051 return OUString();
1052 }
1053
1054 return itr->second;
1055}
1056
1057void XmlFilterBase::importCustomFragments(css::uno::Reference<css::embed::XStorage> const & xDocumentStorage)
1058{
1059 Reference<XRelationshipAccess> xRelations(xDocumentStorage, UNO_QUERY);
1060 if (!xRelations.is())
1061 return;
1062
1063 const uno::Sequence<uno::Sequence<beans::StringPair>> aSeqs = xRelations->getAllRelationships();
1064
1065 std::vector<StreamDataSequence> aCustomFragments;
1066 std::vector<OUString> aCustomFragmentTypes;
1067 std::vector<OUString> aCustomFragmentTargets;
1068 for (const uno::Sequence<beans::StringPair>& aSeq : aSeqs)
1069 {
1070 OUString sType;
1071 OUString sTarget;
1072 for (const beans::StringPair& aPair : aSeq)
1073 {
1074 if (aPair.First == "Target")
1075 sTarget = aPair.Second;
1076 else if (aPair.First == "Type")
1077 sType = aPair.Second;
1078 }
1079
1080 // Preserve non-standard (i.e. custom) entries.
1081 if (!sType.match("http://schemas.openxmlformats.org") // OOXML/ECMA Transitional
1082 && !sType.match("http://purl.oclc.org")) // OOXML Strict
1083 {
1084 StreamDataSequence aDataSeq;
1085 if (importBinaryData(aDataSeq, sTarget))
1086 {
1087 aCustomFragments.emplace_back(aDataSeq);
1088 aCustomFragmentTypes.emplace_back(sType);
1089 aCustomFragmentTargets.emplace_back(sTarget);
1090 }
1091 }
1092 }
1093
1094 // Adding the saved custom xml DOM
1095 comphelper::SequenceAsHashMap aGrabBagProperties;
1096 aGrabBagProperties["OOXCustomFragments"] <<= comphelper::containerToSequence(aCustomFragments);
1097 aGrabBagProperties["OOXCustomFragmentTypes"] <<= comphelper::containerToSequence(aCustomFragmentTypes);
1098 aGrabBagProperties["OOXCustomFragmentTargets"] <<= comphelper::containerToSequence(aCustomFragmentTargets);
1099
1100 std::vector<uno::Reference<xml::dom::XDocument>> aCustomXmlDomList;
1101 std::vector<uno::Reference<xml::dom::XDocument>> aCustomXmlDomPropsList;
1102 //FIXME: Ideally, we should get these the relations, but it seems that is not consistently set.
1103 // In some cases it's stored in the workbook relationships, which is unexpected. So we discover them directly.
1104 for (int i = 1; ; ++i)
1105 {
1106 Reference<XDocument> xCustDoc = importFragment("customXml/item" + OUString::number(i) + ".xml");
1107 Reference<XDocument> xCustDocProps = importFragment("customXml/itemProps" + OUString::number(i) + ".xml");
1108 if (xCustDoc && xCustDocProps)
1109 {
1110 aCustomXmlDomList.emplace_back(xCustDoc);
1111 aCustomXmlDomPropsList.emplace_back(xCustDocProps);
1112 }
1113 else
1114 break;
1115 }
1116
1117 // Adding the saved custom xml DOM
1118 aGrabBagProperties["OOXCustomXml"] <<= comphelper::containerToSequence(aCustomXmlDomList);
1119 aGrabBagProperties["OOXCustomXmlProps"] <<= comphelper::containerToSequence(aCustomXmlDomPropsList);
1120
1121 // Save the [Content_Types].xml after parsing.
1122 uno::Sequence<uno::Sequence<beans::StringPair>> aContentTypeInfo;
1123 uno::Reference<io::XInputStream> xInputStream = openInputStream("[Content_Types].xml");
1124 if (xInputStream.is())
1126
1127 aGrabBagProperties["OOXContentTypes"] <<= aContentTypeInfo;
1128
1129 Reference<XComponent> xModel = getModel();
1131}
1132
1134{
1135 Reference<XComponent> xModel = getModel();
1136 uno::Reference<beans::XPropertySet> xPropSet(xModel, uno::UNO_QUERY_THROW);
1137
1138 uno::Reference<beans::XPropertySetInfo> xPropSetInfo = xPropSet->getPropertySetInfo();
1139 if (!xPropSetInfo->hasPropertyByName(UNO_NAME_MISC_OBJ_INTEROPGRABBAG))
1140 return;
1141
1142 uno::Sequence<uno::Reference<xml::dom::XDocument>> customXmlDomlist;
1143 uno::Sequence<uno::Reference<xml::dom::XDocument>> customXmlDomPropslist;
1144 uno::Sequence<StreamDataSequence> customFragments;
1145 uno::Sequence<OUString> customFragmentTypes;
1146 uno::Sequence<OUString> customFragmentTargets;
1147 uno::Sequence<uno::Sequence<beans::StringPair>> aContentTypes;
1148
1149 uno::Sequence<beans::PropertyValue> propList;
1150 xPropSet->getPropertyValue(UNO_NAME_MISC_OBJ_INTEROPGRABBAG) >>= propList;
1151 for (const auto& rProp : std::as_const(propList))
1152 {
1153 const OUString propName = rProp.Name;
1154 if (propName == "OOXCustomXml")
1155 {
1156 rProp.Value >>= customXmlDomlist;
1157 }
1158 else if (propName == "OOXCustomXmlProps")
1159 {
1160 rProp.Value >>= customXmlDomPropslist;
1161 }
1162 else if (propName == "OOXCustomFragments")
1163 {
1164 rProp.Value >>= customFragments;
1165 }
1166 else if (propName == "OOXCustomFragmentTypes")
1167 {
1168 rProp.Value >>= customFragmentTypes;
1169 }
1170 else if (propName == "OOXCustomFragmentTargets")
1171 {
1172 rProp.Value >>= customFragmentTargets;
1173 }
1174 else if (propName == "OOXContentTypes")
1175 {
1176 rProp.Value >>= aContentTypes;
1177 }
1178 }
1179
1180 // Expect customXmlDomPropslist.getLength() == customXmlDomlist.getLength().
1181 for (sal_Int32 j = 0; j < customXmlDomlist.getLength(); j++)
1182 {
1183 uno::Reference<xml::dom::XDocument> customXmlDom = customXmlDomlist[j];
1184 uno::Reference<xml::dom::XDocument> customXmlDomProps = customXmlDomPropslist[j];
1185 const OUString fragmentPath = "customXml/item" + OUString::number(j+1) + ".xml";
1186 if (customXmlDom.is())
1187 {
1188 addRelation(oox::getRelationship(Relationship::CUSTOMXML), Concat2View("../" + fragmentPath));
1189
1190 uno::Reference<xml::sax::XSAXSerializable> serializer(customXmlDom, uno::UNO_QUERY);
1191 uno::Reference<xml::sax::XWriter> writer = xml::sax::Writer::create(comphelper::getProcessComponentContext());
1192 writer->setOutputStream(openFragmentStream(fragmentPath, "application/xml"));
1193 serializer->serialize(uno::Reference<xml::sax::XDocumentHandler>(writer, uno::UNO_QUERY_THROW),
1194 uno::Sequence<beans::StringPair>());
1195 }
1196
1197 if (customXmlDomProps.is())
1198 {
1199 uno::Reference<xml::sax::XSAXSerializable> serializer(customXmlDomProps, uno::UNO_QUERY);
1200 uno::Reference<xml::sax::XWriter> writer = xml::sax::Writer::create(comphelper::getProcessComponentContext());
1201 writer->setOutputStream(openFragmentStream("customXml/itemProps"+OUString::number(j+1)+".xml",
1202 "application/vnd.openxmlformats-officedocument.customXmlProperties+xml"));
1203 serializer->serialize(uno::Reference<xml::sax::XDocumentHandler>(writer, uno::UNO_QUERY_THROW),
1204 uno::Sequence<beans::StringPair>());
1205
1206 // Adding itemprops's relationship entry to item.xml.rels file
1207 addRelation(openFragmentStream(fragmentPath, "application/xml"),
1209 Concat2View("itemProps"+OUString::number(j+1)+".xml"));
1210 }
1211 }
1212
1213 // Expect customFragments.getLength() == customFragmentTypes.getLength() == customFragmentTargets.getLength().
1214 for (sal_Int32 j = 0; j < customFragments.getLength(); j++)
1215 {
1216 addRelation(customFragmentTypes[j], customFragmentTargets[j]);
1217 const OUString aFilename = customFragmentTargets[j];
1218 Reference<XOutputStream> xOutStream = openOutputStream(aFilename);
1219 if (xOutStream.is())
1220 {
1221 xOutStream->writeBytes(customFragments[j]);
1222 uno::Reference<XPropertySet> xProps(xOutStream, uno::UNO_QUERY);
1223 if (xProps.is())
1224 {
1225 const OUString aType = comphelper::OFOPXMLHelper::GetContentTypeByName(aContentTypes, aFilename);
1226 const OUString aContentType = (aType.getLength() ? aType : OUString("application/octet-stream"));
1227 xProps->setPropertyValue("MediaType", uno::Any(aContentType));
1228 }
1229 }
1230 }
1231}
1232
1233} // namespace oox::core
1234
1235/* 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:84
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