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