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