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