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 
20 #include "docxexport.hxx"
21 #include "docxexportfilter.hxx"
22 #include "docxattributeoutput.hxx"
23 #include "docxsdrexport.hxx"
24 #include "docxhelper.hxx"
25 
26 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
27 #include <com/sun/star/document/XDocumentProperties.hpp>
28 #include <com/sun/star/document/XStorageBasedDocument.hpp>
29 #include <com/sun/star/drawing/XShape.hpp>
30 #include <com/sun/star/i18n/ScriptType.hpp>
31 #include <com/sun/star/frame/XModel.hpp>
32 #include <com/sun/star/xml/dom/XDocument.hpp>
33 #include <com/sun/star/xml/sax/XSAXSerializable.hpp>
34 #include <com/sun/star/xml/sax/Writer.hpp>
35 #include <com/sun/star/awt/XControlModel.hpp>
36 #include <com/sun/star/sdb/CommandType.hpp>
37 
38 #include <oox/token/namespaces.hxx>
39 #include <oox/token/tokens.hxx>
40 #include <oox/export/drawingml.hxx>
41 #include <oox/export/vmlexport.hxx>
42 #include <oox/export/chartexport.hxx>
43 #include <oox/export/shapes.hxx>
44 #include <oox/helper/propertyset.hxx>
45 #include <oox/token/relationship.hxx>
46 #include <oox/helper/binaryoutputstream.hxx>
47 #include <oox/ole/olestorage.hxx>
48 #include <oox/ole/olehelper.hxx>
49 
50 #include <map>
51 #include <algorithm>
52 
53 #include <IMark.hxx>
54 #include <IDocumentSettingAccess.hxx>
55 #include <IDocumentLayoutAccess.hxx>
56 #include <IDocumentStylePoolAccess.hxx>
57 #include <docsh.hxx>
58 #include <ndtxt.hxx>
59 #include "wrtww8.hxx"
60 #include <fltini.hxx>
61 #include <fmtline.hxx>
62 #include <fmtpdsc.hxx>
63 #include <frmfmt.hxx>
64 #include <section.hxx>
65 #include <ftninfo.hxx>
66 #include <pagedesc.hxx>
67 #include <poolfmt.hxx>
68 #include <swdbdata.hxx>
69 
70 #include <editeng/unoprnms.hxx>
71 #include <editeng/editobj.hxx>
72 #include <editeng/outlobj.hxx>
73 #include <editeng/brushitem.hxx>
74 #include <editeng/hyphenzoneitem.hxx>
75 
76 #include <docary.hxx>
77 #include <numrule.hxx>
78 #include <charfmt.hxx>
79 #include <viewsh.hxx>
80 #include <viewopt.hxx>
81 
82 #include "ww8par.hxx"
83 #include "ww8scan.hxx"
84 #include <oox/token/properties.hxx>
85 #include <comphelper/processfactory.hxx>
86 #include <comphelper/sequence.hxx>
87 #include <comphelper/storagehelper.hxx>
88 #include <rtl/ustrbuf.hxx>
89 #include <sal/log.hxx>
90 #include <vcl/font.hxx>
91 #include <unotools/ucbstreamhelper.hxx>
92 #include <tools/diagnose_ex.h>
93 
94 using namespace sax_fastparser;
95 using namespace ::comphelper;
96 using namespace ::com::sun::star;
97 using namespace ::oox;
98 
99 using oox::vml::VMLExport;
100 
101 using sw::mark::IMark;
102 
AttrOutput() const103 AttributeOutputBase& DocxExport::AttrOutput() const
104 {
105     return *m_pAttrOutput;
106 }
107 
DocxAttrOutput() const108 DocxAttributeOutput& DocxExport::DocxAttrOutput() const
109 {
110     return *m_pAttrOutput;
111 }
112 
Sections() const113 MSWordSections& DocxExport::Sections() const
114 {
115     return *m_pSections;
116 }
117 
CollapseScriptsforWordOk(sal_uInt16 nScript,sal_uInt16 nWhich)118 bool DocxExport::CollapseScriptsforWordOk( sal_uInt16 nScript, sal_uInt16 nWhich )
119 {
120     // TODO FIXME is this actually true for docx? - this is ~copied from WW8
121     if ( nScript == i18n::ScriptType::ASIAN )
122     {
123         // for asian in ww8, there is only one fontsize
124         // and one fontstyle (posture/weight)
125         switch ( nWhich )
126         {
127             case RES_CHRATR_FONTSIZE:
128             case RES_CHRATR_POSTURE:
129             case RES_CHRATR_WEIGHT:
130                 return false;
131             default:
132                 break;
133         }
134     }
135     else if ( nScript != i18n::ScriptType::COMPLEX )
136     {
137         // for western in ww8, there is only one fontsize
138         // and one fontstyle (posture/weight)
139         switch ( nWhich )
140         {
141             case RES_CHRATR_CJK_FONTSIZE:
142             case RES_CHRATR_CJK_POSTURE:
143             case RES_CHRATR_CJK_WEIGHT:
144                 return false;
145             default:
146                 break;
147         }
148     }
149     return true;
150 }
151 
AppendBookmarks(const SwTextNode & rNode,sal_Int32 nCurrentPos,sal_Int32 nLen)152 void DocxExport::AppendBookmarks( const SwTextNode& rNode, sal_Int32 nCurrentPos, sal_Int32 nLen )
153 {
154     std::vector< OUString > aStarts;
155     std::vector< OUString > aEnds;
156 
157     IMarkVector aMarks;
158     if ( GetBookmarks( rNode, nCurrentPos, nCurrentPos + nLen, aMarks ) )
159     {
160         for ( IMark* pMark : aMarks )
161         {
162             const sal_Int32 nStart = pMark->GetMarkStart().nContent.GetIndex();
163             const sal_Int32 nEnd = pMark->GetMarkEnd().nContent.GetIndex();
164 
165             if ( nStart == nCurrentPos )
166                 aStarts.push_back( pMark->GetName() );
167 
168             if ( nEnd == nCurrentPos )
169                 aEnds.push_back( pMark->GetName() );
170         }
171     }
172 
173     const OUString& aStr( rNode.GetText() );
174     const sal_Int32 nEnd = aStr.getLength();
175 
176     if ( nCurrentPos == nEnd )
177         m_pAttrOutput->WriteFinalBookmarks_Impl( aStarts, aEnds );
178     else
179         m_pAttrOutput->WriteBookmarks_Impl( aStarts, aEnds );
180 }
181 
AppendBookmark(const OUString & rName)182 void DocxExport::AppendBookmark( const OUString& rName )
183 {
184     std::vector< OUString > aStarts;
185     std::vector< OUString > aEnds;
186 
187     aStarts.push_back( rName );
188     aEnds.push_back( rName );
189 
190     m_pAttrOutput->WriteBookmarks_Impl( aStarts, aEnds );
191 }
192 
AppendAnnotationMarks(const SwWW8AttrIter & rAttrs,sal_Int32 nCurrentPos,sal_Int32 nLen)193 void DocxExport::AppendAnnotationMarks( const SwWW8AttrIter& rAttrs, sal_Int32 nCurrentPos, sal_Int32 nLen )
194 {
195     std::vector< OUString > aStarts;
196     std::vector< OUString > aEnds;
197 
198     IMarkVector aMarks;
199     if (GetAnnotationMarks(rAttrs, nCurrentPos, nCurrentPos + nLen, aMarks))
200     {
201         for ( IMark* pMark : aMarks )
202         {
203             const sal_Int32 nStart = pMark->GetMarkStart().nContent.GetIndex();
204             const sal_Int32 nEnd = pMark->GetMarkEnd().nContent.GetIndex();
205 
206             if ( nStart == nCurrentPos )
207                 aStarts.push_back( pMark->GetName() );
208 
209             if ( nEnd == nCurrentPos )
210                 aEnds.push_back( pMark->GetName() );
211         }
212     }
213 
214     m_pAttrOutput->WriteAnnotationMarks_Impl( aStarts, aEnds );
215 }
216 
ExportGrfBullet(const SwTextNode &)217 void DocxExport::ExportGrfBullet(const SwTextNode&)
218 {
219     // Just collect the bullets for now, numbering.xml is not yet started.
220     CollectGrfsOfBullets();
221 }
222 
AddRelation(const OUString & rType,const OUString & rTarget)223 OString DocxExport::AddRelation( const OUString& rType, const OUString& rTarget )
224 {
225     OUString sId = m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
226            rType, rTarget, true );
227 
228     return sId.toUtf8();
229 }
230 
DisallowInheritingOutlineNumbering(const SwFormat & rFormat)231 bool DocxExport::DisallowInheritingOutlineNumbering( const SwFormat& rFormat )
232 {
233     bool bRet( false );
234 
235     if (SfxItemState::SET != rFormat.GetItemState(RES_PARATR_NUMRULE, false))
236     {
237         if (const SwFormat *pParent = rFormat.DerivedFrom())
238         {
239             if (static_cast<const SwTextFormatColl*>(pParent)->IsAssignedToListLevelOfOutlineStyle())
240             {
241                 ::sax_fastparser::FSHelperPtr pSerializer = m_pAttrOutput->GetSerializer( );
242                 // Level 9 disables the outline
243                 pSerializer->singleElementNS(XML_w, XML_outlineLvl, FSNS(XML_w, XML_val), "9");
244 
245                 bRet = true;
246             }
247         }
248     }
249 
250     return bRet;
251 }
252 
WriteHeadersFooters(sal_uInt8 nHeadFootFlags,const SwFrameFormat & rFormat,const SwFrameFormat & rLeftFormat,const SwFrameFormat & rFirstPageFormat,sal_uInt8 nBreakCode)253 void DocxExport::WriteHeadersFooters( sal_uInt8 nHeadFootFlags,
254         const SwFrameFormat& rFormat, const SwFrameFormat& rLeftFormat, const SwFrameFormat& rFirstPageFormat, sal_uInt8 nBreakCode )
255 {
256     m_nHeadersFootersInSection = 1;
257 
258     // document setting indicating the requirement of EVEN and ODD for both headers and footers
259     if ( nHeadFootFlags & ( nsHdFtFlags::WW8_FOOTER_EVEN | nsHdFtFlags::WW8_HEADER_EVEN ))
260         m_aSettings.evenAndOddHeaders = true;
261 
262     // Turn ON flag for 'Writing Headers \ Footers'
263     m_pAttrOutput->SetWritingHeaderFooter( true );
264 
265     // headers
266     if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_EVEN )
267         WriteHeaderFooter( &rLeftFormat, true, "even" );
268     else if ( m_aSettings.evenAndOddHeaders )
269     {
270         if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_ODD )
271             WriteHeaderFooter( &rFormat, true, "even" );
272         else if ( m_bHasHdr && nBreakCode == 2 )
273             WriteHeaderFooter( nullptr, true, "even" );
274     }
275 
276     if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_ODD )
277         WriteHeaderFooter( &rFormat, true, "default" );
278 
279     if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_FIRST )
280         WriteHeaderFooter( &rFirstPageFormat, true, "first" );
281 
282     if( (nHeadFootFlags & (nsHdFtFlags::WW8_HEADER_EVEN
283                          | nsHdFtFlags::WW8_HEADER_ODD
284                          | nsHdFtFlags::WW8_HEADER_FIRST)) == 0
285             && m_bHasHdr && nBreakCode == 2 ) // 2: nexPage
286         WriteHeaderFooter( nullptr, true, "default" );
287 
288 
289     // footers
290     if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_EVEN )
291         WriteHeaderFooter( &rLeftFormat, false, "even" );
292     else if ( m_aSettings.evenAndOddHeaders )
293     {
294         if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_ODD )
295            WriteHeaderFooter( &rFormat, false, "even" );
296         else if ( m_bHasFtr && nBreakCode == 2 )
297             WriteHeaderFooter( nullptr, false, "even");
298     }
299 
300     if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_ODD )
301         WriteHeaderFooter( &rFormat, false, "default" );
302 
303     if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_FIRST )
304         WriteHeaderFooter( &rFirstPageFormat, false, "first" );
305 
306     if( (nHeadFootFlags & (nsHdFtFlags::WW8_FOOTER_EVEN
307                          | nsHdFtFlags::WW8_FOOTER_ODD
308                          | nsHdFtFlags::WW8_FOOTER_FIRST)) == 0
309             && m_bHasFtr && nBreakCode == 2 ) // 2: nexPage
310         WriteHeaderFooter( nullptr, false, "default");
311 
312     // Turn OFF flag for 'Writing Headers \ Footers'
313     m_pAttrOutput->SetWritingHeaderFooter( false );
314 }
315 
OutputField(const SwField * pField,ww::eField eFieldType,const OUString & rFieldCmd,FieldFlags nMode)316 void DocxExport::OutputField( const SwField* pField, ww::eField eFieldType, const OUString& rFieldCmd, FieldFlags nMode )
317 {
318     m_pAttrOutput->WriteField_Impl( pField, eFieldType, rFieldCmd, nMode );
319 }
320 
WriteFormData(const::sw::mark::IFieldmark & rFieldmark)321 void DocxExport::WriteFormData( const ::sw::mark::IFieldmark& rFieldmark )
322 {
323     m_pAttrOutput->WriteFormData_Impl( rFieldmark );
324 }
325 
WriteHyperlinkData(const::sw::mark::IFieldmark &)326 void DocxExport::WriteHyperlinkData( const ::sw::mark::IFieldmark& /*rFieldmark*/ )
327 {
328 #if OSL_DEBUG_LEVEL > 1
329     fprintf( stderr, "TODO DocxExport::WriteHyperlinkData()\n" );
330 #endif
331 }
332 
DoComboBox(const OUString & rName,const OUString & rHelp,const OUString & rToolTip,const OUString & rSelected,const uno::Sequence<OUString> & rListItems)333 void DocxExport::DoComboBox(const OUString& rName,
334                              const OUString& rHelp,
335                              const OUString& rToolTip,
336                              const OUString& rSelected,
337                              const uno::Sequence<OUString>& rListItems)
338 {
339     m_pDocumentFS->startElementNS(XML_w, XML_ffData);
340 
341     m_pDocumentFS->singleElementNS(XML_w, XML_name, FSNS(XML_w, XML_val), rName.toUtf8());
342 
343     m_pDocumentFS->singleElementNS(XML_w, XML_enabled);
344 
345     if ( !rHelp.isEmpty() )
346         m_pDocumentFS->singleElementNS(XML_w, XML_helpText, FSNS(XML_w, XML_val), rHelp.toUtf8());
347 
348     if ( !rToolTip.isEmpty() )
349         m_pDocumentFS->singleElementNS( XML_w, XML_statusText,
350             FSNS( XML_w, XML_val ), rToolTip.toUtf8() );
351 
352     m_pDocumentFS->startElementNS(XML_w, XML_ddList);
353 
354     // Output the 0-based index of the selected value
355     sal_Int32 nId = comphelper::findValue(rListItems, rSelected);
356     if (nId == -1)
357         nId = 0;
358 
359     m_pDocumentFS->singleElementNS(XML_w, XML_result, FSNS(XML_w, XML_val), OString::number(nId));
360 
361     // unfortunately Word 2013 refuses to load DOCX with more than 25 listEntry
362     SAL_WARN_IF(25 < rListItems.getLength(), "sw.ww8", "DocxExport::DoComboBox data loss with more than 25 entries");
363     auto const nSize(std::min(sal_Int32(25), rListItems.getLength()));
364     for (auto i = 0; i < nSize; ++i)
365     {
366         m_pDocumentFS->singleElementNS( XML_w, XML_listEntry,
367                 FSNS(XML_w, XML_val), rListItems[i].toUtf8() );
368     }
369 
370     m_pDocumentFS->endElementNS( XML_w, XML_ddList );
371 
372     m_pDocumentFS->endElementNS( XML_w, XML_ffData );
373 }
374 
DoFormText(const SwInputField * pField)375 void DocxExport::DoFormText(const SwInputField* pField)
376 {
377     assert(pField);
378     const OUString sStr = FieldString(ww::eFILLIN) + "\"" + pField->GetPar2() + "\"";
379     OutputField(pField, ww::eFILLIN, sStr);
380 }
381 
OutputChart(uno::Reference<frame::XModel> const & xModel,sal_Int32 nCount,::sax_fastparser::FSHelperPtr const & m_pSerializer)382 OString DocxExport::OutputChart( uno::Reference< frame::XModel > const & xModel, sal_Int32 nCount, ::sax_fastparser::FSHelperPtr const & m_pSerializer )
383 {
384     OUString aFileName = "charts/chart" + OUString::number(nCount) + ".xml";
385     OUString sId = m_pFilter->addRelation( m_pSerializer->getOutputStream(),
386                     oox::getRelationship(Relationship::CHART),
387                     aFileName );
388     aFileName = "word/charts/chart" + OUString::number(nCount) + ".xml";
389     ::sax_fastparser::FSHelperPtr pChartFS =
390         m_pFilter->openFragmentStreamWithSerializer( aFileName,
391             "application/vnd.openxmlformats-officedocument.drawingml.chart+xml" );
392 
393     oox::drawingml::ChartExport aChartExport(XML_w, pChartFS, xModel, m_pFilter, oox::drawingml::DOCUMENT_DOCX);
394     aChartExport.ExportContent();
395     return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 );
396 }
397 
WriteOLEObject(SwOLEObj & rObject,OUString & io_rProgID)398 OString DocxExport::WriteOLEObject(SwOLEObj& rObject, OUString & io_rProgID)
399 {
400     uno::Reference <embed::XEmbeddedObject> xObj( rObject.GetOleRef() );
401     uno::Reference<uno::XComponentContext> const xContext(
402         GetFilter().getComponentContext());
403 
404     OUString sMediaType;
405     OUString sRelationType;
406     OUString sSuffix;
407     const char * pProgID(nullptr);
408 
409     uno::Reference<io::XInputStream> const xInStream =
410         oox::GetOLEObjectStream(xContext, xObj, io_rProgID,
411             sMediaType, sRelationType, sSuffix, pProgID);
412 
413     if (!xInStream.is())
414     {
415         return OString();
416     }
417 
418     assert(!sMediaType.isEmpty());
419     assert(!sRelationType.isEmpty());
420     assert(!sSuffix.isEmpty());
421     OUString sFileName = "embeddings/oleObject" + OUString::number( ++m_nOLEObjects ) + "." + sSuffix;
422     uno::Reference<io::XOutputStream> const xOutStream =
423         GetFilter().openFragmentStream("word/" + sFileName, sMediaType);
424     assert(xOutStream.is()); // no reason why that could fail
425 
426     try
427     {
428         ::comphelper::OStorageHelper::CopyInputToOutput(xInStream, xOutStream);
429     }
430     catch (uno::Exception const&)
431     {
432         TOOLS_WARN_EXCEPTION("sw.ww8", "DocxExport::WriteOLEObject");
433         return OString();
434     }
435 
436     OUString const sId = m_pFilter->addRelation( GetFS()->getOutputStream(),
437                 sRelationType, sFileName );
438     if (pProgID)
439     {
440         io_rProgID = OUString::createFromAscii(pProgID);
441     }
442 
443     return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 );
444 }
445 
WriteActiveXObject(const uno::Reference<drawing::XShape> & rxShape,const uno::Reference<awt::XControlModel> & rxControlModel)446 std::pair<OString, OString> DocxExport::WriteActiveXObject(const uno::Reference<drawing::XShape>& rxShape,
447                                                            const uno::Reference<awt::XControlModel>& rxControlModel)
448 {
449     ++m_nActiveXControls;
450 
451     // Write out ActiveX binary
452     const OUString sBinaryFileName = "word/activeX/activeX" + OUString::number(m_nActiveXControls) + ".bin";
453 
454     OString sGUID;
455     OString sName;
456     uno::Reference<io::XStream> xOutStorage(m_pFilter->openFragmentStream(sBinaryFileName, "application/vnd.ms-office.activeX"), uno::UNO_QUERY);
457     if(xOutStorage.is())
458     {
459         oox::ole::OleStorage aOleStorage(m_pFilter->getComponentContext(), xOutStorage, false);
460         uno::Reference<io::XOutputStream> xOutputStream(aOleStorage.openOutputStream("contents"), uno::UNO_SET_THROW);
461         uno::Reference< css::frame::XModel > xModel( m_pDoc->GetDocShell() ? m_pDoc->GetDocShell()->GetModel() : nullptr );
462         oox::ole::OleFormCtrlExportHelper exportHelper(comphelper::getProcessComponentContext(), xModel, rxControlModel);
463         if ( !exportHelper.isValid() )
464             return std::make_pair<OString, OString>(OString(), OString());
465         sGUID = OUStringToOString(exportHelper.getGUID(), RTL_TEXTENCODING_UTF8);
466         sName = OUStringToOString(exportHelper.getName(), RTL_TEXTENCODING_UTF8);
467         exportHelper.exportControl(xOutputStream, rxShape->getSize(), true);
468         aOleStorage.commit();
469     }
470 
471     // Write out ActiveX fragment
472     const OUString sXMLFileName = "word/activeX/activeX" + OUString::number( m_nActiveXControls ) + ".xml";
473     ::sax_fastparser::FSHelperPtr pActiveXFS = m_pFilter->openFragmentStreamWithSerializer(sXMLFileName, "application/vnd.ms-office.activeX+xml" );
474 
475     const OUString sBinaryId = m_pFilter->addRelation( pActiveXFS->getOutputStream(),
476                                                        oox::getRelationship(Relationship::ACTIVEXCONTROLBINARY),
477                                                        sBinaryFileName.copy(sBinaryFileName.lastIndexOf("/") + 1) );
478 
479     pActiveXFS->singleElementNS(XML_ax, XML_ocx,
480                                 FSNS(XML_xmlns, XML_ax), m_pFilter->getNamespaceURL(OOX_NS(ax)).toUtf8(),
481                                 FSNS(XML_xmlns, XML_r), m_pFilter->getNamespaceURL(OOX_NS(officeRel)).toUtf8(),
482                                 FSNS(XML_ax, XML_classid), "{" + sGUID + "}",
483                                 FSNS(XML_ax, XML_persistence), "persistStorage",
484                                 FSNS(XML_r, XML_id), sBinaryId.toUtf8());
485 
486     OString sXMLId = OUStringToOString(m_pFilter->addRelation(m_pDocumentFS->getOutputStream(),
487                                                               oox::getRelationship(Relationship::CONTROL),
488                                                               sXMLFileName.copy(sBinaryFileName.indexOf("/") + 1)),
489                                        RTL_TEXTENCODING_UTF8);
490 
491     return std::pair<OString, OString>(sXMLId, sName);
492 }
493 
OutputDML(uno::Reference<drawing::XShape> const & xShape)494 void DocxExport::OutputDML(uno::Reference<drawing::XShape> const & xShape)
495 {
496     uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY_THROW);
497     sal_Int32 nNamespace = XML_wps;
498     if (xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
499         nNamespace = XML_wpg;
500     else if (xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape"))
501         nNamespace = XML_pic;
502     oox::drawingml::ShapeExport aExport(nNamespace, m_pAttrOutput->GetSerializer(), nullptr, m_pFilter, oox::drawingml::DOCUMENT_DOCX, m_pAttrOutput.get());
503     aExport.WriteShape(xShape);
504 }
505 
ExportDocument_Impl()506 ErrCode DocxExport::ExportDocument_Impl()
507 {
508     // Set the 'Reviewing' flags in the settings structure
509     m_aSettings.revisionView = m_bOrigShowChanges;
510     m_aSettings.trackRevisions = bool( RedlineFlags::On & m_nOrigRedlineFlags );
511 
512     InitStyles();
513 
514     // init sections
515     m_pSections.reset(new MSWordSections( *this ));
516 
517     // Make sure images are counted from one, even when exporting multiple documents.
518     oox::drawingml::DrawingML::ResetCounters();
519 
520     WriteMainText();
521 
522     WriteFootnotesEndnotes();
523 
524     WritePostitFields();
525 
526     WriteNumbering();
527 
528     WriteFonts();
529 
530     WriteSettings();
531 
532     WriteTheme();
533 
534     WriteGlossary();
535 
536     WriteCustomXml();
537 
538     WriteEmbeddings();
539 
540     WriteVBA();
541 
542     m_aLinkedTextboxesHelper.clear();   //final cleanup
543     m_pStyles.reset();
544     m_pSections.reset();
545 
546     return ERRCODE_NONE;
547 }
548 
AppendSection(const SwPageDesc * pPageDesc,const SwSectionFormat * pFormat,sal_uLong nLnNum)549 void DocxExport::AppendSection( const SwPageDesc *pPageDesc, const SwSectionFormat* pFormat, sal_uLong nLnNum )
550 {
551     AttrOutput().SectionBreak( msword::PageBreak, false, m_pSections->CurrentSectionInfo() );
552     m_pSections->AppendSection( pPageDesc, pFormat, nLnNum, m_pAttrOutput->IsFirstParagraph() );
553 }
554 
OutputEndNode(const SwEndNode & rEndNode)555 void DocxExport::OutputEndNode( const SwEndNode& rEndNode )
556 {
557     MSWordExportBase::OutputEndNode( rEndNode );
558 
559     if ( TXT_MAINTEXT == m_nTextTyp && rEndNode.StartOfSectionNode()->IsSectionNode() )
560     {
561         // this originally comes from WW8Export::WriteText(), and looks like it
562         // could have some code common with SectionNode()...
563 
564         const SwSection& rSect = rEndNode.StartOfSectionNode()->GetSectionNode()->GetSection();
565         if ( m_bStartTOX && TOX_CONTENT_SECTION == rSect.GetType() )
566             m_bStartTOX = false;
567 
568         SwNodeIndex aIdx( rEndNode, 1 );
569         const SwNode& rNd = aIdx.GetNode();
570         if ( rNd.IsEndNode() && rNd.StartOfSectionNode()->IsSectionNode() )
571             return;
572 
573         bool isInTable = IsInTable();
574         if ( !rNd.IsSectionNode() && isInTable ) // No sections in table
575         {
576             const SwSectionFormat* pParentFormat = rSect.GetFormat()->GetParent();
577             if( !pParentFormat )
578                 pParentFormat = reinterpret_cast<SwSectionFormat*>(sal_IntPtr(-1));
579 
580             sal_uLong nRstLnNum;
581             if( rNd.IsContentNode() )
582                 nRstLnNum = rNd.GetContentNode()->GetSwAttrSet().GetLineNumber().GetStartValue();
583             else
584                 nRstLnNum = 0;
585 
586             AppendSection( m_pCurrentPageDesc, pParentFormat, nRstLnNum );
587         }
588         else
589         {
590             AttrOutput().SectionBreaks( rEndNode );
591         }
592     }
593     else if (TXT_MAINTEXT == m_nTextTyp && rEndNode.StartOfSectionNode()->IsTableNode())
594         // End node of a table: see if a section break should be written after the table.
595         AttrOutput().SectionBreaks(rEndNode);
596 }
597 
OutputGrfNode(const SwGrfNode &)598 void DocxExport::OutputGrfNode( const SwGrfNode& )
599 {
600     SAL_INFO("sw.ww8", "TODO DocxExport::OutputGrfNode( const SwGrfNode& )" );
601 }
602 
OutputOLENode(const SwOLENode &)603 void DocxExport::OutputOLENode( const SwOLENode& )
604 {
605     SAL_INFO("sw.ww8", "TODO DocxExport::OutputOLENode( const SwOLENode& )" );
606 }
607 
OutputLinkedOLE(const OUString &)608 void DocxExport::OutputLinkedOLE( const OUString& )
609 {
610     // Nothing to implement here: WW8 only
611 }
612 
ReplaceCr(sal_uInt8)613 sal_uLong DocxExport::ReplaceCr( sal_uInt8 )
614 {
615     // Completely unused for Docx export... only here for code sharing
616     // purpose with binary export
617     return 0;
618 }
619 
PrepareNewPageDesc(const SfxItemSet * pSet,const SwNode & rNd,const SwFormatPageDesc * pNewPgDescFormat,const SwPageDesc * pNewPgDesc)620 void DocxExport::PrepareNewPageDesc( const SfxItemSet* pSet,
621         const SwNode& rNd, const SwFormatPageDesc* pNewPgDescFormat,
622         const SwPageDesc* pNewPgDesc )
623 {
624     // tell the attribute output that we are ready to write the section
625     // break [has to be output inside paragraph properties]
626     AttrOutput().SectionBreak( msword::PageBreak, false, m_pSections->CurrentSectionInfo() );
627 
628     const SwSectionFormat* pFormat = GetSectionFormat( rNd );
629     const sal_uLong nLnNm = GetSectionLineNo( pSet, rNd );
630 
631     OSL_ENSURE( pNewPgDescFormat || pNewPgDesc, "Neither page desc format nor page desc provided." );
632 
633     if ( pNewPgDescFormat )
634     {
635         m_pSections->AppendSection( *pNewPgDescFormat, rNd, pFormat, nLnNm );
636     }
637     else if ( pNewPgDesc )
638     {
639         m_pSections->AppendSection( pNewPgDesc, rNd, pFormat, nLnNm );
640     }
641 
642 }
643 
InitStyles()644 void DocxExport::InitStyles()
645 {
646     m_pStyles.reset(new MSWordStyles( *this, /*bListStyles =*/ true ));
647 
648     // setup word/styles.xml and the relations + content type
649     m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
650             oox::getRelationship(Relationship::STYLES),
651             "styles.xml" );
652 
653     ::sax_fastparser::FSHelperPtr pStylesFS =
654         m_pFilter->openFragmentStreamWithSerializer( "word/styles.xml",
655             "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml" );
656 
657     // switch the serializer to redirect the output to word/styles.xml
658     m_pAttrOutput->SetSerializer( pStylesFS );
659 
660     // do the work
661     m_pStyles->OutputStylesTable();
662 
663     // switch the serializer back
664     m_pAttrOutput->SetSerializer( m_pDocumentFS );
665 }
666 
WriteFootnotesEndnotes()667 void DocxExport::WriteFootnotesEndnotes()
668 {
669     if ( m_pAttrOutput->HasFootnotes() )
670     {
671         // setup word/styles.xml and the relations + content type
672         m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
673                 oox::getRelationship(Relationship::FOOTNOTES),
674                 "footnotes.xml" );
675 
676         ::sax_fastparser::FSHelperPtr pFootnotesFS =
677             m_pFilter->openFragmentStreamWithSerializer( "word/footnotes.xml",
678                     "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml" );
679 
680         // switch the serializer to redirect the output to word/footnotes.xml
681         m_pAttrOutput->SetSerializer( pFootnotesFS );
682         // tdf#99227
683         m_pSdrExport->setSerializer( pFootnotesFS );
684         // tdf#107969
685         m_pVMLExport->SetFS(pFootnotesFS);
686 
687         // do the work
688         m_pAttrOutput->FootnotesEndnotes( true );
689 
690         // switch the serializer back
691         m_pVMLExport->SetFS(m_pDocumentFS);
692         m_pSdrExport->setSerializer( m_pDocumentFS );
693         m_pAttrOutput->SetSerializer( m_pDocumentFS );
694     }
695 
696     if ( m_pAttrOutput->HasEndnotes() )
697     {
698         // setup word/styles.xml and the relations + content type
699         m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
700                 oox::getRelationship(Relationship::ENDNOTES),
701                 "endnotes.xml" );
702 
703         ::sax_fastparser::FSHelperPtr pEndnotesFS =
704             m_pFilter->openFragmentStreamWithSerializer( "word/endnotes.xml",
705                     "application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml" );
706 
707         // switch the serializer to redirect the output to word/endnotes.xml
708         m_pAttrOutput->SetSerializer( pEndnotesFS );
709         // tdf#99227
710         m_pSdrExport->setSerializer( pEndnotesFS );
711         // tdf#107969
712         m_pVMLExport->SetFS(pEndnotesFS);
713 
714         // do the work
715         m_pAttrOutput->FootnotesEndnotes( false );
716 
717         // switch the serializer back
718         m_pVMLExport->SetFS(m_pDocumentFS);
719         m_pSdrExport->setSerializer( m_pDocumentFS );
720         m_pAttrOutput->SetSerializer( m_pDocumentFS );
721     }
722 }
723 
WritePostitFields()724 void DocxExport::WritePostitFields()
725 {
726     if ( m_pAttrOutput->HasPostitFields() )
727     {
728         m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
729                 oox::getRelationship(Relationship::COMMENTS),
730                 "comments.xml" );
731 
732         ::sax_fastparser::FSHelperPtr pPostitFS =
733             m_pFilter->openFragmentStreamWithSerializer( "word/comments.xml",
734                     "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml" );
735 
736         pPostitFS->startElementNS( XML_w, XML_comments, MainXmlNamespaces());
737         m_pAttrOutput->SetSerializer( pPostitFS );
738         m_pAttrOutput->WritePostitFields();
739         m_pAttrOutput->SetSerializer( m_pDocumentFS );
740         pPostitFS->endElementNS( XML_w, XML_comments );
741     }
742 }
743 
WriteNumbering()744 void DocxExport::WriteNumbering()
745 {
746     if ( !m_pUsedNumTable )
747         return; // no numbering is used
748 
749     m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
750         oox::getRelationship(Relationship::NUMBERING),
751         "numbering.xml" );
752 
753     ::sax_fastparser::FSHelperPtr pNumberingFS = m_pFilter->openFragmentStreamWithSerializer( "word/numbering.xml",
754         "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml" );
755 
756     // switch the serializer to redirect the output to word/numbering.xml
757     m_pAttrOutput->SetSerializer( pNumberingFS );
758     m_pDrawingML->SetFS( pNumberingFS );
759 
760     pNumberingFS->startElementNS( XML_w, XML_numbering,
761             FSNS( XML_xmlns, XML_w ), m_pFilter->getNamespaceURL(OOX_NS(doc)).toUtf8(),
762             FSNS( XML_xmlns, XML_o ), m_pFilter->getNamespaceURL(OOX_NS(vmlOffice)).toUtf8(),
763             FSNS( XML_xmlns, XML_r ), m_pFilter->getNamespaceURL(OOX_NS(officeRel)).toUtf8(),
764             FSNS( XML_xmlns, XML_v ), m_pFilter->getNamespaceURL(OOX_NS(vml)).toUtf8() );
765 
766     BulletDefinitions();
767 
768     AbstractNumberingDefinitions();
769 
770     NumberingDefinitions();
771 
772     pNumberingFS->endElementNS( XML_w, XML_numbering );
773 
774     // switch the serializer back
775     m_pDrawingML->SetFS( m_pDocumentFS );
776     m_pAttrOutput->SetSerializer( m_pDocumentFS );
777 }
778 
WriteHeaderFooter(const SwFormat * pFormat,bool bHeader,const char * pType)779 void DocxExport::WriteHeaderFooter( const SwFormat* pFormat, bool bHeader, const char* pType )
780 {
781     // setup the xml stream
782     OUString aRelId;
783     ::sax_fastparser::FSHelperPtr pFS;
784     if ( bHeader )
785     {
786         OUString aName( "header" + OUString::number( ++m_nHeaders ) + ".xml" );
787 
788         aRelId = m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
789                 oox::getRelationship(Relationship::HEADER),
790                 aName );
791 
792         pFS = m_pFilter->openFragmentStreamWithSerializer( "word/" + aName,
793                     "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml" );
794 
795         pFS->startElementNS( XML_w, XML_hdr, MainXmlNamespaces());
796     }
797     else
798     {
799         OUString aName( "footer" + OUString::number( ++m_nFooters ) + ".xml" );
800 
801         aRelId = m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
802                 oox::getRelationship(Relationship::FOOTER),
803                 aName );
804 
805         pFS = m_pFilter->openFragmentStreamWithSerializer( "word/" + aName,
806                     "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml" );
807 
808         pFS->startElementNS( XML_w, XML_ftr, MainXmlNamespaces());
809     }
810 
811     // switch the serializer to redirect the output to word/styles.xml
812     m_pAttrOutput->SetSerializer( pFS );
813     m_pVMLExport->SetFS( pFS );
814     m_pSdrExport->setSerializer(pFS);
815     SetFS( pFS );
816     {
817         DocxTableExportContext aTableExportContext(*m_pAttrOutput);
818         //When the stream changes the cache which is maintained for the graphics in case of alternate content is not cleared.
819         //So clearing the alternate content graphic cache.
820         m_pAttrOutput->PushRelIdCache();
821         // do the work
822         if (pFormat == nullptr)
823             AttrOutput().EmptyParagraph();
824         else
825             WriteHeaderFooterText(*pFormat, bHeader);
826         m_pAttrOutput->PopRelIdCache();
827         m_pAttrOutput->EndParaSdtBlock();
828     }
829 
830     // switch the serializer back
831     m_pAttrOutput->SetSerializer( m_pDocumentFS );
832     m_pVMLExport->SetFS( m_pDocumentFS );
833     m_pSdrExport->setSerializer(m_pDocumentFS);
834     SetFS( m_pDocumentFS );
835 
836     // close the tag
837     sal_Int32 nReference;
838     if ( bHeader )
839     {
840         pFS->endElementNS( XML_w, XML_hdr );
841         nReference = XML_headerReference;
842     }
843     else
844     {
845         pFS->endElementNS( XML_w, XML_ftr );
846         nReference = XML_footerReference;
847     }
848 
849     // and write the reference
850     m_pDocumentFS->singleElementNS( XML_w, nReference,
851             FSNS( XML_w, XML_type ), pType,
852             FSNS( XML_r, XML_id ), aRelId.toUtf8() );
853 }
854 
WriteFonts()855 void DocxExport::WriteFonts()
856 {
857     m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
858             oox::getRelationship(Relationship::FONTTABLE),
859             "fontTable.xml" );
860 
861     ::sax_fastparser::FSHelperPtr pFS = m_pFilter->openFragmentStreamWithSerializer(
862             "word/fontTable.xml",
863             "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml" );
864 
865     pFS->startElementNS( XML_w, XML_fonts,
866             FSNS( XML_xmlns, XML_w ), m_pFilter->getNamespaceURL(OOX_NS(doc)).toUtf8(),
867             FSNS( XML_xmlns, XML_r ), m_pFilter->getNamespaceURL(OOX_NS(officeRel)).toUtf8() );
868 
869     // switch the serializer to redirect the output to word/styles.xml
870     m_pAttrOutput->SetSerializer( pFS );
871 
872     // do the work
873     m_aFontHelper.WriteFontTable( *m_pAttrOutput );
874 
875     // switch the serializer back
876     m_pAttrOutput->SetSerializer( m_pDocumentFS );
877 
878     pFS->endElementNS( XML_w, XML_fonts );
879 }
880 
WriteProperties()881 void DocxExport::WriteProperties( )
882 {
883     // Write the core properties
884     SwDocShell* pDocShell( m_pDoc->GetDocShell( ) );
885     uno::Reference<document::XDocumentProperties> xDocProps;
886     bool bSecurityOptOpenReadOnly = false;
887     if ( pDocShell )
888     {
889         uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
890                pDocShell->GetModel( ), uno::UNO_QUERY );
891         xDocProps = xDPS->getDocumentProperties();
892         bSecurityOptOpenReadOnly = pDocShell->IsSecurityOptOpenReadOnly();
893     }
894 
895     m_pFilter->exportDocumentProperties( xDocProps, bSecurityOptOpenReadOnly );
896 }
897 
WriteSettings()898 void DocxExport::WriteSettings()
899 {
900     SwViewShell *pViewShell(m_pDoc->getIDocumentLayoutAccess().GetCurrentViewShell());
901     if( !pViewShell && !m_aSettings.hasData() && !m_pAttrOutput->HasFootnotes() && !m_pAttrOutput->HasEndnotes())
902         return;
903 
904     m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
905             oox::getRelationship(Relationship::SETTINGS),
906             "settings.xml" );
907 
908     ::sax_fastparser::FSHelperPtr pFS = m_pFilter->openFragmentStreamWithSerializer(
909             "word/settings.xml",
910             "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml" );
911 
912     pFS->startElementNS( XML_w, XML_settings,
913             FSNS( XML_xmlns, XML_w ), m_pFilter->getNamespaceURL(OOX_NS(doc)).toUtf8() );
914 
915     // View
916     if (pViewShell && pViewShell->GetViewOptions()->getBrowseMode())
917     {
918         pFS->singleElementNS(XML_w, XML_view, FSNS(XML_w, XML_val), "web");
919     }
920 
921     // Zoom
922     if (pViewShell)
923     {
924         rtl::Reference<sax_fastparser::FastAttributeList> pAttributeList(
925             sax_fastparser::FastSerializerHelper::createAttrList());
926 
927         switch (pViewShell->GetViewOptions()->GetZoomType())
928         {
929             case SvxZoomType::WHOLEPAGE:
930                 pAttributeList->add(FSNS(XML_w, XML_val), "fullPage");
931                 break;
932             case SvxZoomType::PAGEWIDTH:
933                 pAttributeList->add(FSNS(XML_w, XML_val), "bestFit");
934                 break;
935             case SvxZoomType::OPTIMAL:
936                 pAttributeList->add(FSNS(XML_w, XML_val), "textFit");
937                 break;
938             default:
939                 break;
940         }
941 
942         OString aZoom(OString::number(pViewShell->GetViewOptions()->GetZoom()));
943         pAttributeList->add(FSNS(XML_w, XML_percent), aZoom);
944         sax_fastparser::XFastAttributeListRef xAttributeList(pAttributeList.get());
945         pFS->singleElementNS(XML_w, XML_zoom, xAttributeList);
946     }
947 
948     // Display Background Shape
949     if (std::shared_ptr<SvxBrushItem> oBrush = getBackground(); oBrush)
950     {
951         // Turn on the 'displayBackgroundShape'
952         pFS->singleElementNS(XML_w, XML_displayBackgroundShape);
953     }
954 
955     // Track Changes
956     if ( !m_aSettings.revisionView )
957         pFS->singleElementNS( XML_w, XML_revisionView,
958             FSNS( XML_w, XML_insDel ), "0",
959             FSNS( XML_w, XML_formatting ), "0" );
960 
961     if ( m_aSettings.trackRevisions )
962         pFS->singleElementNS(XML_w, XML_trackRevisions);
963 
964     // Mirror Margins
965     if(isMirroredMargin())
966         pFS->singleElementNS(XML_w, XML_mirrorMargins);
967 
968     // Embed Fonts
969     if( m_pDoc->getIDocumentSettingAccess().get( DocumentSettingId::EMBED_FONTS ))
970         pFS->singleElementNS(XML_w, XML_embedTrueTypeFonts);
971 
972     // Embed System Fonts
973     if( m_pDoc->getIDocumentSettingAccess().get( DocumentSettingId::EMBED_SYSTEM_FONTS ))
974         pFS->singleElementNS(XML_w, XML_embedSystemFonts);
975 
976     // Default Tab Stop
977     if( m_aSettings.defaultTabStop != 0 )
978         pFS->singleElementNS( XML_w, XML_defaultTabStop, FSNS( XML_w, XML_val ),
979             OString::number(m_aSettings.defaultTabStop) );
980 
981     // Do not justify lines with manual break
982     if( m_pDoc->getIDocumentSettingAccess().get( DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK ))
983     {
984         pFS->startElementNS(XML_w, XML_compat);
985         pFS->singleElementNS(XML_w, XML_doNotExpandShiftReturn);
986         pFS->endElementNS( XML_w, XML_compat );
987     }
988 
989     // export current mail merge database and table names
990     SwDBData aData = m_pDoc->GetDBData();
991     if ( !aData.sDataSource.isEmpty() && aData.nCommandType == css::sdb::CommandType::TABLE && !aData.sCommand.isEmpty() )
992     {
993         OUString sDataSource =
994             "SELECT * FROM " +
995             aData.sDataSource + // current database
996             ".dbo." + // default database owner
997             aData.sCommand + // sheet name
998             "$"; // sheet identifier
999         pFS->startElementNS( XML_w, XML_mailMerge );
1000         pFS->singleElementNS(XML_w, XML_mainDocumentType,
1001             FSNS( XML_w, XML_val ), "formLetters" );
1002         pFS->singleElementNS(XML_w, XML_dataType,
1003             FSNS( XML_w, XML_val ), "textFile" );
1004         pFS->singleElementNS( XML_w, XML_query,
1005             FSNS( XML_w, XML_val ), OUStringToOString( sDataSource, RTL_TEXTENCODING_UTF8 ).getStr() );
1006         pFS->endElementNS( XML_w, XML_mailMerge );
1007     }
1008 
1009     // Automatic hyphenation: it's a global setting in Word, it's a paragraph setting in Writer.
1010     // Set it's value to "auto" and disable on paragraph level, if no hyphenation is used there.
1011     pFS->singleElementNS(XML_w, XML_autoHyphenation, FSNS(XML_w, XML_val), "true");
1012 
1013     // Hyphenation details set depending on default style
1014     SwTextFormatColl* pColl = m_pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD, /*bRegardLanguage=*/false);
1015     const SfxPoolItem* pItem;
1016     if (pColl && SfxItemState::SET == pColl->GetItemState(RES_PARATR_HYPHENZONE, false, &pItem))
1017     {
1018         if (static_cast<const SvxHyphenZoneItem*>(pItem)->IsNoCapsHyphenation())
1019             pFS->singleElementNS(XML_w, XML_doNotHyphenateCaps);
1020     }
1021 
1022     // Even and Odd Headers
1023     if( m_aSettings.evenAndOddHeaders )
1024         pFS->singleElementNS(XML_w, XML_evenAndOddHeaders);
1025 
1026     // Has Footnotes
1027     if( m_pAttrOutput->HasFootnotes())
1028         DocxAttributeOutput::WriteFootnoteEndnotePr( pFS, XML_footnotePr, m_pDoc->GetFootnoteInfo(), XML_footnote );
1029 
1030     // Has Endnotes
1031     if( m_pAttrOutput->HasEndnotes())
1032         DocxAttributeOutput::WriteFootnoteEndnotePr( pFS, XML_endnotePr, m_pDoc->GetEndNoteInfo(), XML_endnote );
1033 
1034     // Has themeFontLang information
1035     uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
1036 
1037     bool hasProtectionProperties = false;
1038     bool bHasRedlineProtectionKey = false;
1039     bool bHasDummyRedlineProtectionKey = false;
1040     uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1041     if ( xPropSetInfo->hasPropertyByName( "RedlineProtectionKey" ) )
1042     {
1043         uno::Sequence<sal_Int8> aKey;
1044         xPropSet->getPropertyValue( "RedlineProtectionKey" ) >>= aKey;
1045         bHasRedlineProtectionKey = aKey.hasElements();
1046         bHasDummyRedlineProtectionKey = aKey.getLength() == 1 && aKey[0] == 1;
1047     }
1048     const OUString aGrabBagName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1049     if ( xPropSetInfo->hasPropertyByName( aGrabBagName ) )
1050     {
1051         uno::Sequence< beans::PropertyValue > propList;
1052         xPropSet->getPropertyValue( aGrabBagName ) >>= propList;
1053 
1054         for( const auto& rProp : std::as_const(propList) )
1055         {
1056             if ( rProp.Name == "ThemeFontLangProps" )
1057             {
1058                 uno::Sequence< beans::PropertyValue > themeFontLangProps;
1059                 rProp.Value >>= themeFontLangProps;
1060                 OUString aValues[3];
1061                 for( const auto& rThemeFontLangProp : std::as_const(themeFontLangProps) )
1062                 {
1063                     if( rThemeFontLangProp.Name == "val" )
1064                         rThemeFontLangProp.Value >>= aValues[0];
1065                     else if( rThemeFontLangProp.Name == "eastAsia" )
1066                         rThemeFontLangProp.Value >>= aValues[1];
1067                     else if( rThemeFontLangProp.Name == "bidi" )
1068                         rThemeFontLangProp.Value >>= aValues[2];
1069                 }
1070                 pFS->singleElementNS( XML_w, XML_themeFontLang,
1071                                       FSNS( XML_w, XML_val ), aValues[0].toUtf8(),
1072                                       FSNS( XML_w, XML_eastAsia ), aValues[1].toUtf8(),
1073                                       FSNS( XML_w, XML_bidi ), aValues[2].toUtf8() );
1074             }
1075             else if ( rProp.Name == "CompatSettings" )
1076             {
1077                 pFS->startElementNS(XML_w, XML_compat);
1078 
1079                 uno::Sequence< beans::PropertyValue > aCompatSettingsSequence;
1080                 rProp.Value >>= aCompatSettingsSequence;
1081 
1082                 for(const auto& rCompatSetting : std::as_const(aCompatSettingsSequence))
1083                 {
1084                     uno::Sequence< beans::PropertyValue > aCompatSetting;
1085                     rCompatSetting.Value >>= aCompatSetting;
1086                     OUString aName;
1087                     OUString aUri;
1088                     OUString aValue;
1089 
1090                     for(const auto& rPropVal : std::as_const(aCompatSetting))
1091                     {
1092                         if( rPropVal.Name == "name" )
1093                             rPropVal.Value >>= aName;
1094                         else if( rPropVal.Name == "uri" )
1095                             rPropVal.Value >>= aUri;
1096                         else if( rPropVal.Name == "val" )
1097                             rPropVal.Value >>= aValue;
1098                     }
1099                     pFS->singleElementNS( XML_w, XML_compatSetting,
1100                         FSNS( XML_w, XML_name ), aName.toUtf8(),
1101                         FSNS( XML_w, XML_uri ),  aUri.toUtf8(),
1102                         FSNS( XML_w, XML_val ),  aValue.toUtf8());
1103                 }
1104 
1105                 pFS->endElementNS( XML_w, XML_compat );
1106             }
1107             else if (rProp.Name == "DocumentProtection")
1108             {
1109 
1110                 uno::Sequence< beans::PropertyValue > rAttributeList;
1111                 rProp.Value >>= rAttributeList;
1112 
1113                 if (rAttributeList.hasElements())
1114                 {
1115                     sax_fastparser::FastAttributeList* pAttributeList = sax_fastparser::FastSerializerHelper::createAttrList();
1116                     bool bIsProtectionTrackChanges = false;
1117                     for (const auto& rAttribute : std::as_const(rAttributeList))
1118                     {
1119                         static DocxStringTokenMap const aTokens[] =
1120                         {
1121                             { "edit",                XML_edit },
1122                             { "enforcement",         XML_enforcement },
1123                             { "formatting",          XML_formatting },
1124                             { "cryptProviderType",   XML_cryptProviderType },
1125                             { "cryptAlgorithmClass", XML_cryptAlgorithmClass },
1126                             { "cryptAlgorithmType",  XML_cryptAlgorithmType },
1127                             { "cryptAlgorithmSid",   XML_cryptAlgorithmSid },
1128                             { "cryptSpinCount",      XML_cryptSpinCount },
1129                             { "hash",                XML_hash },
1130                             { "salt",                XML_salt },
1131                             { nullptr, 0 }
1132                         };
1133 
1134                         if (sal_Int32 nToken = DocxStringGetToken(aTokens, rAttribute.Name))
1135                         {
1136                             OUString sValue = rAttribute.Value.get<OUString>();
1137                             pAttributeList->add(FSNS(XML_w, nToken), sValue.toUtf8());
1138                             if ( nToken == XML_edit && sValue == "trackedChanges" )
1139                                 bIsProtectionTrackChanges = true;
1140                         }
1141                     }
1142 
1143                     // we have document protection from input DOCX file
1144                     // and in the case of change tracking protection, we didn't modify it
1145                     hasProtectionProperties = !bIsProtectionTrackChanges || bHasDummyRedlineProtectionKey;
1146                     if ( hasProtectionProperties )
1147                     {
1148                         sax_fastparser::XFastAttributeListRef xAttributeList(pAttributeList);
1149                         pFS->singleElementNS(XML_w, XML_documentProtection, xAttributeList);
1150                     }
1151 
1152                 }
1153             }
1154             else if (rProp.Name == "HyphenationZone")
1155             {
1156                 sal_Int16 nHyphenationZone;
1157                 rProp.Value >>= nHyphenationZone;
1158                 if (nHyphenationZone > 0)
1159                     pFS->singleElementNS(XML_w, XML_hyphenationZone, FSNS(XML_w, XML_val),
1160                                          OString::number(nHyphenationZone));
1161             }
1162         }
1163     }
1164 
1165     if (! hasProtectionProperties)
1166     {
1167         // Protect form - highest priority
1168         // Section-specific write protection
1169         if (m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_FORM) ||
1170             m_pSections->DocumentIsProtected())
1171         {
1172             // we have form protection from Writer or from input ODT file
1173 
1174             pFS->singleElementNS(XML_w, XML_documentProtection,
1175                 FSNS(XML_w, XML_edit), "forms",
1176                 FSNS(XML_w, XML_enforcement), "true");
1177         }
1178         // Protect Change Tracking - next priority
1179         else if ( bHasRedlineProtectionKey && !bHasDummyRedlineProtectionKey )
1180         {
1181             // we have change tracking protection from Writer or from input ODT file
1182 
1183             pFS->singleElementNS(XML_w, XML_documentProtection,
1184                 FSNS(XML_w, XML_edit), "trackedChanges",
1185                 FSNS(XML_w, XML_enforcement), "1");
1186         }
1187     }
1188 
1189     // finish settings.xml
1190     pFS->endElementNS( XML_w, XML_settings );
1191 }
1192 
WriteTheme()1193 void DocxExport::WriteTheme()
1194 {
1195     uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
1196 
1197     uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1198     OUString aName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1199     if ( !xPropSetInfo->hasPropertyByName( aName ) )
1200         return;
1201 
1202     uno::Reference<xml::dom::XDocument> themeDom;
1203     uno::Sequence< beans::PropertyValue > propList;
1204     xPropSet->getPropertyValue( aName ) >>= propList;
1205     auto pProp = std::find_if(propList.begin(), propList.end(),
1206         [](const beans::PropertyValue& rProp) { return rProp.Name == "OOXTheme"; });
1207     if (pProp != propList.end())
1208         pProp->Value >>= themeDom;
1209 
1210     // no theme dom to write
1211     if ( !themeDom.is() )
1212         return;
1213 
1214     m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
1215             oox::getRelationship(Relationship::THEME),
1216             "theme/theme1.xml" );
1217 
1218     uno::Reference< xml::sax::XSAXSerializable > serializer( themeDom, uno::UNO_QUERY );
1219     uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
1220     writer->setOutputStream( GetFilter().openFragmentStream( "word/theme/theme1.xml",
1221         "application/vnd.openxmlformats-officedocument.theme+xml" ) );
1222     serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
1223         uno::Sequence< beans::StringPair >() );
1224 }
1225 
WriteGlossary()1226 void DocxExport::WriteGlossary()
1227 {
1228     uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
1229 
1230     uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1231     OUString aName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1232     if ( !xPropSetInfo->hasPropertyByName( aName ) )
1233         return;
1234 
1235     uno::Reference<xml::dom::XDocument> glossaryDocDom;
1236     uno::Sequence< uno::Sequence< uno::Any> > glossaryDomList;
1237     uno::Sequence< beans::PropertyValue > propList;
1238     xPropSet->getPropertyValue( aName ) >>= propList;
1239     sal_Int32 collectedProperties = 0;
1240     for ( const auto& rProp : std::as_const(propList) )
1241     {
1242         OUString propName = rProp.Name;
1243         if ( propName == "OOXGlossary" )
1244         {
1245              rProp.Value >>= glossaryDocDom;
1246              collectedProperties++;
1247         }
1248         if (propName == "OOXGlossaryDom")
1249         {
1250             rProp.Value >>= glossaryDomList;
1251             collectedProperties++;
1252         }
1253         if (collectedProperties == 2)
1254             break;
1255     }
1256 
1257     // no glossary dom to write
1258     if ( !glossaryDocDom.is() )
1259         return;
1260 
1261     m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
1262             oox::getRelationship(Relationship::GLOSSARYDOCUMENT),
1263             "glossary/document.xml" );
1264 
1265     uno::Reference< io::XOutputStream > xOutputStream = GetFilter().openFragmentStream( "word/glossary/document.xml",
1266             "application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml" );
1267 
1268     uno::Reference< xml::sax::XSAXSerializable > serializer( glossaryDocDom, uno::UNO_QUERY );
1269     uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
1270     writer->setOutputStream( xOutputStream );
1271     serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
1272         uno::Sequence< beans::StringPair >() );
1273 
1274     for ( const uno::Sequence< uno::Any>& glossaryElement : std::as_const(glossaryDomList))
1275     {
1276         OUString gTarget, gType, gId, contentType;
1277         uno::Reference<xml::dom::XDocument> xDom;
1278         glossaryElement[0] >>= xDom;
1279         glossaryElement[1] >>= gId;
1280         glossaryElement[2] >>= gType;
1281         glossaryElement[3] >>= gTarget;
1282         glossaryElement[4] >>= contentType;
1283         gId = gId.copy(3); //"rId" only save the numeric value
1284 
1285         PropertySet aProps(xOutputStream);
1286         aProps.setAnyProperty( PROP_RelId, uno::makeAny( gId.toInt32() ));
1287         m_pFilter->addRelation( xOutputStream, gType, gTarget);
1288         uno::Reference< xml::sax::XSAXSerializable > gserializer( xDom, uno::UNO_QUERY );
1289         writer->setOutputStream(GetFilter().openFragmentStream( "word/glossary/" + gTarget, contentType ) );
1290         gserializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
1291                uno::Sequence< beans::StringPair >() );
1292     }
1293 }
1294 
WriteCustomXml()1295 void DocxExport::WriteCustomXml()
1296 {
1297     uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
1298 
1299     uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1300     static const OUString aName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1301     if ( !xPropSetInfo->hasPropertyByName( aName ) )
1302         return;
1303 
1304     uno::Sequence<uno::Reference<xml::dom::XDocument> > customXmlDomlist;
1305     uno::Sequence<uno::Reference<xml::dom::XDocument> > customXmlDomPropslist;
1306     uno::Sequence< beans::PropertyValue > propList;
1307     xPropSet->getPropertyValue( aName ) >>= propList;
1308     auto pProp = std::find_if(propList.begin(), propList.end(),
1309         [](const beans::PropertyValue& rProp) { return rProp.Name == "OOXCustomXml"; });
1310     if (pProp != propList.end())
1311         pProp->Value >>= customXmlDomlist;
1312 
1313     pProp = std::find_if(propList.begin(), propList.end(),
1314         [](const beans::PropertyValue& rProp) { return rProp.Name == "OOXCustomXmlProps"; });
1315     if (pProp != propList.end())
1316         pProp->Value >>= customXmlDomPropslist;
1317 
1318     for (sal_Int32 j = 0; j < customXmlDomlist.getLength(); j++)
1319     {
1320         uno::Reference<xml::dom::XDocument> customXmlDom = customXmlDomlist[j];
1321         uno::Reference<xml::dom::XDocument> customXmlDomProps = customXmlDomPropslist[j];
1322         if (customXmlDom.is())
1323         {
1324             m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
1325                     oox::getRelationship(Relationship::CUSTOMXML),
1326                     "../customXml/item"+OUString::number((j+1))+".xml" );
1327 
1328             uno::Reference< xml::sax::XSAXSerializable > serializer( customXmlDom, uno::UNO_QUERY );
1329             uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
1330             writer->setOutputStream( GetFilter().openFragmentStream( "customXml/item"+OUString::number((j+1))+".xml",
1331                 "application/xml" ) );
1332             serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
1333                 uno::Sequence< beans::StringPair >() );
1334         }
1335 
1336         if (customXmlDomProps.is())
1337         {
1338             uno::Reference< xml::sax::XSAXSerializable > serializer( customXmlDomProps, uno::UNO_QUERY );
1339             uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
1340             writer->setOutputStream( GetFilter().openFragmentStream( "customXml/itemProps"+OUString::number((j+1))+".xml",
1341                 "application/vnd.openxmlformats-officedocument.customXmlProperties+xml" ) );
1342             serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
1343                 uno::Sequence< beans::StringPair >() );
1344 
1345             // Adding itemprops's relationship entry to item.xml.rels file
1346             m_pFilter->addRelation( GetFilter().openFragmentStream( "customXml/item"+OUString::number((j+1))+".xml",
1347                     "application/xml" ) ,
1348                     oox::getRelationship(Relationship::CUSTOMXMLPROPS),
1349                     "itemProps"+OUString::number((j+1))+".xml" );
1350         }
1351     }
1352 }
1353 
WriteVBA()1354 void DocxExport::WriteVBA()
1355 {
1356     uno::Reference<document::XStorageBasedDocument> xStorageBasedDocument(m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY);
1357     if (!xStorageBasedDocument.is())
1358         return;
1359 
1360     uno::Reference<embed::XStorage> xDocumentStorage = xStorageBasedDocument->getDocumentStorage();
1361     OUString aMacrosName("_MS_VBA_Macros");
1362     if (!xDocumentStorage.is() || !xDocumentStorage->hasByName(aMacrosName))
1363         return;
1364 
1365     const sal_Int32 nOpenMode = embed::ElementModes::READ;
1366     uno::Reference<io::XStream> xMacrosStream = xDocumentStorage->openStreamElement(aMacrosName, nOpenMode);
1367     uno::Reference<io::XOutputStream> xProjectStream;
1368     if (xMacrosStream.is())
1369     {
1370         // First handle the project stream, this sets xProjectStream.
1371         std::unique_ptr<SvStream> pIn(utl::UcbStreamHelper::CreateStream(xMacrosStream));
1372 
1373         xProjectStream = GetFilter().openFragmentStream("word/vbaProject.bin", "application/vnd.ms-office.vbaProject");
1374         uno::Reference<io::XStream> xOutputStream(xProjectStream, uno::UNO_QUERY);
1375         if (!xOutputStream.is())
1376             return;
1377         std::unique_ptr<SvStream> pOut(utl::UcbStreamHelper::CreateStream(xOutputStream));
1378 
1379         // Write the stream.
1380         pOut->WriteStream(*pIn);
1381 
1382         // Write the relationship.
1383         m_pFilter->addRelation(m_pDocumentFS->getOutputStream(), oox::getRelationship(Relationship::VBAPROJECT), "vbaProject.bin");
1384     }
1385 
1386     OUString aDataName("_MS_VBA_Macros_XML");
1387     if (!xDocumentStorage.is() || !xDocumentStorage->hasByName(aDataName))
1388         return;
1389 
1390     uno::Reference<io::XStream> xDataStream = xDocumentStorage->openStreamElement(aDataName, nOpenMode);
1391     if (xDataStream.is())
1392     {
1393         // Then the data stream, which wants to work with an already set
1394         // xProjectStream.
1395         std::unique_ptr<SvStream> pIn(utl::UcbStreamHelper::CreateStream(xDataStream));
1396 
1397         uno::Reference<io::XStream> xOutputStream(GetFilter().openFragmentStream("word/vbaData.xml", "application/vnd.ms-word.vbaData+xml"), uno::UNO_QUERY);
1398         if (!xOutputStream.is())
1399             return;
1400         std::unique_ptr<SvStream> pOut(utl::UcbStreamHelper::CreateStream(xOutputStream));
1401 
1402         // Write the stream.
1403         pOut->WriteStream(*pIn);
1404 
1405         // Write the relationship.
1406         if (!xProjectStream.is())
1407             return;
1408 
1409         m_pFilter->addRelation(xProjectStream, oox::getRelationship(Relationship::WORDVBADATA), "vbaData.xml");
1410     }
1411 }
1412 
WriteEmbeddings()1413 void DocxExport::WriteEmbeddings()
1414 {
1415     uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
1416 
1417     uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1418     OUString aName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1419     if ( !xPropSetInfo->hasPropertyByName( aName ) )
1420         return;
1421 
1422     uno::Sequence< beans::PropertyValue > embeddingsList;
1423     uno::Sequence< beans::PropertyValue > propList;
1424     xPropSet->getPropertyValue( aName ) >>= propList;
1425     auto pProp = std::find_if(propList.begin(), propList.end(),
1426         [](const beans::PropertyValue& rProp) { return rProp.Name == "OOXEmbeddings"; });
1427     if (pProp != propList.end())
1428         pProp->Value >>= embeddingsList;
1429     for (const auto& rEmbedding : std::as_const(embeddingsList))
1430     {
1431         OUString embeddingPath = rEmbedding.Name;
1432         uno::Reference<io::XInputStream> embeddingsStream;
1433         rEmbedding.Value >>= embeddingsStream;
1434 
1435         OUString contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
1436         // FIXME: this .xlsm hack is silly - if anything the mime-type for an existing embedded object should be read from [Content_Types].xml
1437         if (embeddingPath.endsWith(".xlsm"))
1438             contentType = "application/vnd.ms-excel.sheet.macroEnabled.12";
1439         else if (embeddingPath.endsWith(".bin"))
1440             contentType = "application/vnd.openxmlformats-officedocument.oleObject";
1441 
1442         if ( embeddingsStream.is() )
1443         {
1444             uno::Reference< io::XOutputStream > xOutStream = GetFilter().openFragmentStream(embeddingPath,
1445                                     contentType);
1446             try
1447             {
1448                 sal_Int32 nBufferSize = 512;
1449                 uno::Sequence< sal_Int8 > aDataBuffer(nBufferSize);
1450                 sal_Int32 nRead;
1451                 do
1452                 {
1453                     nRead = embeddingsStream->readBytes( aDataBuffer, nBufferSize );
1454                     if( nRead )
1455                     {
1456                         if( nRead < nBufferSize )
1457                         {
1458                             nBufferSize = nRead;
1459                             aDataBuffer.realloc(nRead);
1460                         }
1461                         xOutStream->writeBytes( aDataBuffer );
1462                     }
1463                 }
1464                 while( nRead );
1465                 xOutStream->flush();
1466             }
1467             catch(const uno::Exception&)
1468             {
1469                 TOOLS_WARN_EXCEPTION("sw.ww8", "WriteEmbeddings() ::Failed to copy Inputstream to outputstream exception caught");
1470             }
1471             xOutStream->closeOutput();
1472         }
1473     }
1474 }
1475 
isMirroredMargin()1476 bool DocxExport::isMirroredMargin()
1477 {
1478     bool bMirroredMargins = false;
1479     if ( UseOnPage::Mirror == (UseOnPage::Mirror & m_pDoc->GetPageDesc(0).ReadUseOn()) )
1480     {
1481         bMirroredMargins = true;
1482     }
1483     return bMirroredMargins;
1484 }
1485 
WriteMainText()1486 void DocxExport::WriteMainText()
1487 {
1488     // setup the namespaces
1489     m_pDocumentFS->startElementNS( XML_w, XML_document, MainXmlNamespaces());
1490 
1491     if ( getenv("SW_DEBUG_DOM") )
1492     {
1493         m_pDoc->dumpAsXml();
1494     }
1495 
1496     // reset the incrementing linked-textboxes chain ID before re-saving.
1497     m_nLinkedTextboxesChainId=0;
1498     m_aLinkedTextboxesHelper.clear();
1499 
1500     // Write background page color
1501     if (std::shared_ptr<SvxBrushItem> oBrush = getBackground(); oBrush)
1502     {
1503         Color backgroundColor = oBrush->GetColor();
1504         OString aBackgroundColorStr = msfilter::util::ConvertColor(backgroundColor);
1505 
1506         m_pDocumentFS->singleElementNS(XML_w, XML_background, FSNS(XML_w, XML_color),
1507                                        aBackgroundColorStr);
1508     }
1509 
1510     // body
1511     m_pDocumentFS->startElementNS(XML_w, XML_body);
1512 
1513     m_pCurPam->GetPoint()->nNode = m_pDoc->GetNodes().GetEndOfContent().StartOfSectionNode()->GetIndex();
1514 
1515     // the text
1516     WriteText();
1517 
1518     // clear linked textboxes since old ones can't be linked to frames in a different section (correct?)
1519     m_aLinkedTextboxesHelper.clear();
1520 
1521     // the last section info
1522     m_pAttrOutput->EndParaSdtBlock();
1523     const WW8_SepInfo *pSectionInfo = m_pSections? m_pSections->CurrentSectionInfo(): nullptr;
1524     if ( pSectionInfo )
1525         SectionProperties( *pSectionInfo );
1526 
1527     // finish body and document
1528     m_pDocumentFS->endElementNS( XML_w, XML_body );
1529     m_pDocumentFS->endElementNS( XML_w, XML_document );
1530 }
1531 
MainXmlNamespaces()1532 XFastAttributeListRef DocxExport::MainXmlNamespaces()
1533 {
1534     FastAttributeList* pAttr = FastSerializerHelper::createAttrList();
1535     pAttr->add( FSNS( XML_xmlns, XML_o ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(vmlOffice)), RTL_TEXTENCODING_UTF8).getStr() );
1536     pAttr->add( FSNS( XML_xmlns, XML_r ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(officeRel)), RTL_TEXTENCODING_UTF8).getStr() );
1537     pAttr->add( FSNS( XML_xmlns, XML_v ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(vml)), RTL_TEXTENCODING_UTF8).getStr() );
1538     pAttr->add( FSNS( XML_xmlns, XML_w ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(doc)), RTL_TEXTENCODING_UTF8).getStr() );
1539     pAttr->add( FSNS( XML_xmlns, XML_w10 ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(vmlWord)), RTL_TEXTENCODING_UTF8).getStr() );
1540     pAttr->add( FSNS( XML_xmlns, XML_wp ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(dmlWordDr)), RTL_TEXTENCODING_UTF8).getStr() );
1541     pAttr->add( FSNS( XML_xmlns, XML_wps ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(wps)), RTL_TEXTENCODING_UTF8).getStr() );
1542     pAttr->add( FSNS( XML_xmlns, XML_wpg ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(wpg)), RTL_TEXTENCODING_UTF8).getStr() );
1543     pAttr->add( FSNS( XML_xmlns, XML_mc ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(mce)), RTL_TEXTENCODING_UTF8).getStr() );
1544     pAttr->add( FSNS( XML_xmlns, XML_wp14 ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(wp14)), RTL_TEXTENCODING_UTF8).getStr() );
1545     pAttr->add( FSNS( XML_xmlns, XML_w14 ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(w14)), RTL_TEXTENCODING_UTF8).getStr() );
1546     pAttr->add( FSNS( XML_mc, XML_Ignorable ), "w14 wp14" );
1547     return XFastAttributeListRef( pAttr );
1548 }
1549 
ignoreAttributeForStyleDefaults(sal_uInt16 nWhich) const1550 bool DocxExport::ignoreAttributeForStyleDefaults( sal_uInt16 nWhich ) const
1551 {
1552     if( nWhich == RES_TEXTGRID )
1553         return true; // w:docGrid is written only to document.xml, not to styles.xml
1554     if (nWhich == RES_PARATR_HYPHENZONE)
1555         return true; // w:suppressAutoHyphens is only a formatting exception, not a default
1556     return MSWordExportBase::ignoreAttributeForStyleDefaults( nWhich );
1557 }
1558 
WriteOutliner(const OutlinerParaObject & rParaObj,sal_uInt8 nTyp)1559 void DocxExport::WriteOutliner(const OutlinerParaObject& rParaObj, sal_uInt8 nTyp)
1560 {
1561     const EditTextObject& rEditObj = rParaObj.GetTextObject();
1562     MSWord_SdrAttrIter aAttrIter( *this, rEditObj, nTyp );
1563 
1564     sal_Int32 nPara = rEditObj.GetParagraphCount();
1565     for( sal_Int32 n = 0; n < nPara; ++n )
1566     {
1567         if( n )
1568             aAttrIter.NextPara( n );
1569 
1570         AttrOutput().StartParagraph( ww8::WW8TableNodeInfo::Pointer_t());
1571         rtl_TextEncoding eChrSet = aAttrIter.GetNodeCharSet();
1572         OUString aStr( rEditObj.GetText( n ));
1573         sal_Int32 nCurrentPos = 0;
1574         const sal_Int32 nEnd = aStr.getLength();
1575         do {
1576             AttrOutput().StartRun( nullptr, 0 );
1577             const sal_Int32 nNextAttr = std::min(aAttrIter.WhereNext(), nEnd);
1578             rtl_TextEncoding eNextChrSet = aAttrIter.GetNextCharSet();
1579 
1580             bool bTextAtr = aAttrIter.IsTextAttr( nCurrentPos );
1581             if( !bTextAtr )
1582             {
1583                 if( nCurrentPos == 0 && nNextAttr - nCurrentPos == aStr.getLength())
1584                     AttrOutput().RunText( aStr, eChrSet );
1585                 else
1586                 {
1587                     OUString tmp( aStr.copy( nCurrentPos, nNextAttr - nCurrentPos ));
1588                     AttrOutput().RunText( tmp, eChrSet );
1589                 }
1590             }
1591             AttrOutput().StartRunProperties();
1592             aAttrIter.OutAttr( nCurrentPos );
1593             AttrOutput().EndRunProperties( nullptr );
1594 
1595             nCurrentPos = nNextAttr;
1596             eChrSet = eNextChrSet;
1597             aAttrIter.NextPos();
1598 
1599             AttrOutput().EndRun( nullptr, 0 );
1600 
1601         } while( nCurrentPos < nEnd );
1602 //        aAttrIter.OutParaAttr(false);
1603         AttrOutput().EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t());
1604     }
1605 }
1606 
SetFS(::sax_fastparser::FSHelperPtr const & pFS)1607 void DocxExport::SetFS( ::sax_fastparser::FSHelperPtr const & pFS )
1608 {
1609     mpFS = pFS;
1610 }
1611 
DocxExport(DocxExportFilter * pFilter,SwDoc * pDocument,std::shared_ptr<SwUnoCursor> & pCurrentPam,SwPaM * pOriginalPam,bool bDocm,bool bTemplate)1612 DocxExport::DocxExport(DocxExportFilter* pFilter, SwDoc* pDocument,
1613         std::shared_ptr<SwUnoCursor> & pCurrentPam,
1614                        SwPaM* pOriginalPam, bool bDocm, bool bTemplate)
1615     : MSWordExportBase( pDocument, pCurrentPam, pOriginalPam ),
1616       m_pFilter( pFilter ),
1617       m_nHeaders( 0 ),
1618       m_nFooters( 0 ),
1619       m_nOLEObjects( 0 ),
1620       m_nActiveXControls( 0 ),
1621       m_nHeadersFootersInSection(0),
1622       m_bDocm(bDocm),
1623       m_bTemplate(bTemplate)
1624 {
1625     // Write the document properties
1626     WriteProperties( );
1627 
1628     // relations for the document
1629     m_pFilter->addRelation( oox::getRelationship(Relationship::OFFICEDOCUMENT),
1630             "word/document.xml" );
1631 
1632     // Set media type depending of document type
1633     OUString aMediaType;
1634     if (m_bDocm)
1635     {
1636         if (m_bTemplate)
1637         {
1638             aMediaType = "application/vnd.ms-word.template.macroEnabledTemplate.main+xml";
1639         }
1640         else
1641         {
1642             aMediaType = "application/vnd.ms-word.document.macroEnabled.main+xml";
1643         }
1644     }
1645     else
1646     {
1647         if (m_bTemplate)
1648         {
1649             aMediaType = "application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml";
1650         }
1651         else
1652         {
1653             aMediaType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml";
1654         }
1655     }
1656 
1657 
1658     // the actual document
1659     m_pDocumentFS = m_pFilter->openFragmentStreamWithSerializer( "word/document.xml", aMediaType );
1660 
1661     SetFS(m_pDocumentFS);
1662 
1663     // the DrawingML access
1664     m_pDrawingML.reset(new oox::drawingml::DrawingML(m_pDocumentFS, m_pFilter, oox::drawingml::DOCUMENT_DOCX));
1665 
1666     // the attribute output for the document
1667     m_pAttrOutput.reset(new DocxAttributeOutput( *this, m_pDocumentFS, m_pDrawingML.get() ));
1668 
1669     // the related VMLExport
1670     m_pVMLExport.reset(new VMLExport( m_pDocumentFS, m_pAttrOutput.get() ));
1671 
1672     // the related drawing export
1673     m_pSdrExport.reset(new DocxSdrExport( *this, m_pDocumentFS, m_pDrawingML.get() ));
1674 }
1675 
~DocxExport()1676 DocxExport::~DocxExport()
1677 {
1678 }
1679 
DocxSettingsData()1680 DocxSettingsData::DocxSettingsData()
1681 : evenAndOddHeaders( false )
1682 , defaultTabStop( 0 )
1683 , revisionView( true )
1684 , trackRevisions( false )
1685 {
1686 }
1687 
hasData() const1688 bool DocxSettingsData::hasData() const
1689 {
1690     if( evenAndOddHeaders )
1691         return true;
1692     if( defaultTabStop != 0 )
1693         return true;
1694     if ( !revisionView )
1695         return true;
1696     if ( trackRevisions )
1697         return true;
1698 
1699     return false;
1700 }
1701 
1702 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1703