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