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 <memory>
21 #include <iostream>
22 
23 #include <com/sun/star/embed/ElementModes.hpp>
24 #include <com/sun/star/embed/XStorage.hpp>
25 #include <unotools/ucbstreamhelper.hxx>
26 #include <algorithm>
27 #include <map>
28 #include <set>
29 #include <hintids.hxx>
30 #include <string.h>
31 #include <osl/endian.h>
32 #include <sal/log.hxx>
33 #include <docsh.hxx>
34 #include <drawdoc.hxx>
35 
36 #include <unotools/fltrcfg.hxx>
37 #include <sot/storage.hxx>
38 #include <svl/zformat.hxx>
39 #include <sfx2/docinf.hxx>
40 #include <editeng/tstpitem.hxx>
41 #include <svx/svdmodel.hxx>
42 #include <svx/svdpage.hxx>
43 #include <editeng/hyphenzoneitem.hxx>
44 #include <editeng/langitem.hxx>
45 #include <filter/msfilter/classids.hxx>
46 #include <filter/msfilter/msoleexp.hxx>
47 #include <editeng/lrspitem.hxx>
48 #include <editeng/ulspitem.hxx>
49 #include <editeng/boxitem.hxx>
50 #include <editeng/brushitem.hxx>
51 #include <swtypes.hxx>
52 #include <swrect.hxx>
53 #include <swtblfmt.hxx>
54 #include <txatbase.hxx>
55 #include <fmtcntnt.hxx>
56 #include <fmtpdsc.hxx>
57 #include <fmtrowsplt.hxx>
58 #include <frmatr.hxx>
59 #include <../../core/inc/rootfrm.hxx>
60 #include <doc.hxx>
61 #include <IDocumentSettingAccess.hxx>
62 #include <IDocumentDrawModelAccess.hxx>
63 #include <IDocumentStylePoolAccess.hxx>
64 #include <IDocumentStatistics.hxx>
65 #include <IDocumentLayoutAccess.hxx>
66 #include <IDocumentExternalData.hxx>
67 #include <viewopt.hxx>
68 #include <docary.hxx>
69 #include <pam.hxx>
70 #include <ndtxt.hxx>
71 #include <shellio.hxx>
72 #include <docstat.hxx>
73 #include <pagedesc.hxx>
74 #include <poolfmt.hxx>
75 #include <IMark.hxx>
76 #include <swtable.hxx>
77 #include "wrtww8.hxx"
78 #include "ww8par.hxx"
79 #include <fltini.hxx>
80 #include <swmodule.hxx>
81 #include <section.hxx>
82 #include <swfltopt.hxx>
83 #include <fmtinfmt.hxx>
84 #include <txtinet.hxx>
85 #include <fmturl.hxx>
86 #include <fesh.hxx>
87 #include <vcl/imap.hxx>
88 #include <vcl/imapobj.hxx>
89 #include <tools/urlobj.hxx>
90 #include <mdiexp.hxx>
91 #include <strings.hrc>
92 #include <fmtline.hxx>
93 #include <fmtfsize.hxx>
94 #include "sprmids.hxx"
95 
96 #include <comphelper/sequenceashashmap.hxx>
97 #include "writerhelper.hxx"
98 #include "writerwordglue.hxx"
99 #include "ww8attributeoutput.hxx"
100 #include <IDocumentMarkAccess.hxx>
101 #include <xmloff/odffields.hxx>
102 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
103 #include <com/sun/star/document/XDocumentProperties.hpp>
104 #include <dbgoutsw.hxx>
105 #include <sfx2/docfile.hxx>
106 #include <sfx2/request.hxx>
107 #include <sfx2/frame.hxx>
108 #include <svl/stritem.hxx>
109 #include <unotools/tempfile.hxx>
110 #include <filter/msfilter/mscodec.hxx>
111 #include <filter/msfilter/svxmsbas.hxx>
112 #include <rtl/random.h>
113 #include <vcl/svapp.hxx>
114 #include <sfx2/docfilt.hxx>
115 #include "WW8Sttbf.hxx"
116 #include <editeng/charrotateitem.hxx>
117 #include <svx/swframetypes.hxx>
118 #include "WW8FibData.hxx"
119 #include <numrule.hxx>
120 #include <fmtclds.hxx>
121 #include <rdfhelper.hxx>
122 #include <fmtclbl.hxx>
123 #include <iodetect.hxx>
124 
125 using namespace css;
126 using namespace sw::util;
127 using namespace sw::types;
128 
129 /** FKP - Formatted disK Page
130 */
131 class WW8_WrFkp
132 {
133     sal_uInt8* pFkp;         // Fkp total ( first and only FCs and Sprms )
134     sal_uInt8* pOfs;         // pointer to the offset area, later copied to pFkp
135     ePLCFT ePlc;
136     short nStartGrp;    // from here on grpprls
137     short nOldStartGrp;
138     sal_uInt8 nItemSize;
139     sal_uInt8 nIMax;         // number of entry pairs
140     sal_uInt8 nOldVarLen;
141     bool bCombined;     // true : paste not allowed
142 
143     sal_uInt8 SearchSameSprm( sal_uInt16 nVarLen, const sal_uInt8* pSprms );
144 
145     WW8_WrFkp(const WW8_WrFkp&) = delete;
146     WW8_WrFkp& operator=(const WW8_WrFkp&) = delete;
147 
148 public:
149     WW8_WrFkp(ePLCFT ePl, WW8_FC nStartFc);
150     ~WW8_WrFkp();
151     bool Append( WW8_FC nEndFc, sal_uInt16 nVarLen, const sal_uInt8* pSprms );
152     void Combine();
153     void Write( SvStream& rStrm, SwWW8WrGrf& rGrf );
154 
IsEqualPos(WW8_FC nEndFc) const155     bool IsEqualPos(WW8_FC nEndFc) const
156     {   return !bCombined && nIMax && nEndFc == reinterpret_cast<sal_Int32*>(pFkp)[nIMax]; }
157     void MergeToNew( short& rVarLen, sal_uInt8 *& pNewSprms );
IsEmptySprm() const158     bool IsEmptySprm() const
159     {   return !bCombined && nIMax && !nOldVarLen;  }
SetNewEnd(WW8_FC nEnd)160     void SetNewEnd( WW8_FC nEnd )
161     {   reinterpret_cast<sal_Int32*>(pFkp)[nIMax] = nEnd; }
162 
163     WW8_FC GetStartFc() const;
164     WW8_FC GetEndFc() const;
165 
166     sal_uInt8 *CopyLastSprms(sal_uInt8 &rLen);
167 };
168 
169 // class WW8_WrPc collects all piece entries for one piece
170 class WW8_WrPc
171 {
172     WW8_CP nStartCp;                    // Starting character position of the text
173     WW8_FC nStartFc;                    // Starting file position of the text
174     sal_uInt16 nStatus;                     // End of paragraph inside the piece?
175 
176 public:
WW8_WrPc(WW8_FC nSFc,WW8_CP nSCp)177     WW8_WrPc(WW8_FC nSFc, WW8_CP nSCp )
178         : nStartCp( nSCp ), nStartFc( nSFc ), nStatus( 0x0040 )
179     {}
180 
SetStatus()181     void SetStatus()                { nStatus = 0x0050; }
GetStatus() const182     sal_uInt16 GetStatus()  const       { return nStatus; }
GetStartCp() const183     WW8_CP GetStartCp() const       { return nStartCp; }
GetStartFc() const184     WW8_FC GetStartFc() const       { return nStartFc; }
185 };
186 
187 typedef std::map<OUString,long> BKMKNames;
188 typedef std::pair<bool,OUString> BKMK;
189 typedef std::pair<long,BKMK> BKMKCP;
190 typedef std::multimap<long,BKMKCP*> BKMKCPs;
191 typedef BKMKCPs::iterator CPItr;
192 
193 class WW8_WrtBookmarks
194 {
195 private:
196     /// Structure of one item inside this map: (startPos, (endPos, (a bool value?, bookmarkName)))
197     BKMKCPs aSttCps;
198     BKMKNames maSwBkmkNms;
199 
200     WW8_WrtBookmarks(WW8_WrtBookmarks const&) = delete;
201     WW8_WrtBookmarks& operator=(WW8_WrtBookmarks const&) = delete;
202 
203 public:
204     WW8_WrtBookmarks();
205     ~WW8_WrtBookmarks();
206     //! Add a new bookmark to the list OR add an end position to an existing bookmark.
207     void Append( WW8_CP nStartCp, const OUString& rNm );
208     //! Write out bookmarks to file.
209     void Write( WW8Export& rWrt );
210     //! Move existing field marks from one position to another.
211     void MoveFieldMarks(WW8_CP nFrom, WW8_CP nTo);
212 };
213 
WW8_WrtBookmarks()214 WW8_WrtBookmarks::WW8_WrtBookmarks()
215 {}
216 
~WW8_WrtBookmarks()217 WW8_WrtBookmarks::~WW8_WrtBookmarks()
218 {
219     for (auto& rEntry : aSttCps)
220     {
221         if (rEntry.second)
222         {
223             delete rEntry.second;
224             rEntry.second = nullptr;
225         }
226     }
227 }
228 
Append(WW8_CP nStartCp,const OUString & rNm)229 void WW8_WrtBookmarks::Append( WW8_CP nStartCp, const OUString& rNm)
230 {
231     std::pair<BKMKNames::iterator, bool> aResult = maSwBkmkNms.insert(std::pair<OUString,long>(rNm,0L));
232     if (aResult.second)
233     {
234         BKMK aBK(false,rNm);
235         BKMKCP* pBKCP = new BKMKCP(static_cast<long>(nStartCp),aBK);
236         aSttCps.insert(std::pair<long,BKMKCP*>(nStartCp,pBKCP));
237         aResult.first->second = static_cast<long>(nStartCp);
238     }
239     else
240     {
241         std::pair<CPItr,CPItr> aRange = aSttCps.equal_range(aResult.first->second);
242         for (CPItr aItr = aRange.first;aItr != aRange.second;++aItr)
243         {
244             if (aItr->second && aItr->second->second.second == rNm)
245             {
246                 if (aItr->second->second.first)
247                     nStartCp--;
248                 aItr->second->first = static_cast<long>(nStartCp);
249                 break;
250             }
251         }
252     }
253 }
254 
Write(WW8Export & rWrt)255 void WW8_WrtBookmarks::Write( WW8Export& rWrt)
256 {
257     if (aSttCps.empty())
258         return;
259     long n;
260     std::vector<OUString> aNames;
261     SvMemoryStream aTempStrm1(65535,65535);
262     SvMemoryStream aTempStrm2(65535,65535);
263 
264     BKMKCPs aEndCps;
265     for (const auto& rEntry : aSttCps)
266     {
267         if (rEntry.second)
268         {
269             aEndCps.insert(std::pair<long,BKMKCP*>(rEntry.second->first, rEntry.second));
270             aNames.push_back(rEntry.second->second.second);
271             SwWW8Writer::WriteLong(aTempStrm1, rEntry.first);
272         }
273     }
274 
275     aTempStrm1.Seek(0);
276     n = 0;
277     for (const auto& rEntry : aEndCps)
278     {
279         if (rEntry.second)
280         {
281             rEntry.second->first = n;
282             SwWW8Writer::WriteLong( aTempStrm2, rEntry.first);
283         }
284         ++n;
285     }
286 
287     aTempStrm2.Seek(0);
288     rWrt.WriteAsStringTable(aNames, rWrt.pFib->m_fcSttbfbkmk,rWrt.pFib->m_lcbSttbfbkmk);
289     SvStream& rStrm = *rWrt.pTableStrm;
290     rWrt.pFib->m_fcPlcfbkf = rStrm.Tell();
291     rStrm.WriteStream( aTempStrm1 );
292     SwWW8Writer::WriteLong(rStrm, rWrt.pFib->m_ccpText + rWrt.pFib->m_ccpTxbx);
293     for (const auto& rEntry : aSttCps)
294     {
295         if (rEntry.second)
296         {
297             SwWW8Writer::WriteLong(rStrm, rEntry.second->first);
298         }
299     }
300     rWrt.pFib->m_lcbPlcfbkf = rStrm.Tell() - rWrt.pFib->m_fcPlcfbkf;
301     rWrt.pFib->m_fcPlcfbkl = rStrm.Tell();
302     rStrm.WriteStream( aTempStrm2 );
303     SwWW8Writer::WriteLong(rStrm, rWrt.pFib->m_ccpText + rWrt.pFib->m_ccpTxbx);
304     rWrt.pFib->m_lcbPlcfbkl = rStrm.Tell() - rWrt.pFib->m_fcPlcfbkl;
305 }
306 
MoveFieldMarks(WW8_CP nFrom,WW8_CP nTo)307 void WW8_WrtBookmarks::MoveFieldMarks(WW8_CP nFrom, WW8_CP nTo)
308 {
309     std::pair<CPItr,CPItr> aRange = aSttCps.equal_range(nFrom);
310     CPItr aItr = aRange.first;
311     while (aItr != aRange.second)
312     {
313         if (aItr->second)
314         {
315             if (aItr->second->first == static_cast<long>(nFrom))
316             {
317                 aItr->second->second.first = true;
318                 aItr->second->first = nTo;
319             }
320             aSttCps.insert(std::pair<long,BKMKCP*>(nTo,aItr->second));
321             aItr->second = nullptr;
322             aRange = aSttCps.equal_range(nFrom);
323             aItr = aRange.first;
324             continue;
325         }
326         ++aItr;
327     }
328 }
329 
330 /// Handles export of smart tags.
331 class WW8_WrtFactoids
332 {
333     std::vector<WW8_CP> m_aStartCPs;
334     std::vector<WW8_CP> m_aEndCPs;
335     std::vector< std::map<OUString, OUString> > m_aStatements;
336 
337     WW8_WrtFactoids(WW8_WrtFactoids const&) = delete;
338     WW8_WrtFactoids& operator=(WW8_WrtFactoids const&) = delete;
339 
340 public:
341     WW8_WrtFactoids();
342     void Append(WW8_CP nStartCp, WW8_CP nEndCp, const std::map<OUString, OUString>& rStatements);
343     void Write(WW8Export& rWrt);
344 };
345 
WW8_WrtFactoids()346 WW8_WrtFactoids::WW8_WrtFactoids()
347 {
348 }
349 
Append(WW8_CP nStartCp,WW8_CP nEndCp,const std::map<OUString,OUString> & rStatements)350 void WW8_WrtFactoids::Append(WW8_CP nStartCp, WW8_CP nEndCp, const std::map<OUString, OUString>& rStatements)
351 {
352     m_aStartCPs.push_back(nStartCp);
353     m_aEndCPs.push_back(nEndCp);
354     m_aStatements.push_back(rStatements);
355 }
356 
Write(WW8Export & rExport)357 void WW8_WrtFactoids::Write(WW8Export& rExport)
358 {
359     if (m_aStartCPs.empty())
360         return;
361 
362     // Smart tags are otherwise removed by Word on saving.
363     rExport.pDop->fEmbedFactoids = true;
364 
365     SvStream& rStream = *rExport.pTableStrm;
366 
367     rExport.pFib->m_fcSttbfBkmkFactoid = rStream.Tell();
368     // Write SttbfBkmkFactoid.
369     rStream.WriteUInt16(0xffff); // fExtend
370     rStream.WriteUInt16(m_aStartCPs.size()); // cData
371     rStream.WriteUInt16(0); // cbExtra
372 
373     for (size_t i = 0; i < m_aStartCPs.size(); ++i)
374     {
375         rStream.WriteUInt16(6); // cchData
376         // Write FACTOIDINFO.
377         rStream.WriteUInt32(i); // dwId
378         rStream.WriteUInt16(0); // fSubEntry
379         rStream.WriteUInt16(0); // fto
380         rStream.WriteUInt32(0); // pfpb
381     }
382     rExport.pFib->m_lcbSttbfBkmkFactoid = rStream.Tell() - rExport.pFib->m_fcSttbfBkmkFactoid;
383 
384     rExport.pFib->m_fcPlcfBkfFactoid = rStream.Tell();
385     for (const WW8_CP& rCP : m_aStartCPs)
386         rStream.WriteInt32(rCP);
387     rStream.WriteInt32(rExport.pFib->m_ccpText + rExport.pFib->m_ccpTxbx);
388 
389     // Write FBKFD.
390     for (size_t i = 0; i < m_aStartCPs.size(); ++i)
391     {
392         rStream.WriteInt16(i); // ibkl
393         rStream.WriteInt16(0); // bkc
394         rStream.WriteInt16(1); // cDepth, 1 as start and end is the same.
395     }
396 
397     rExport.pFib->m_lcbPlcfBkfFactoid = rStream.Tell() - rExport.pFib->m_fcPlcfBkfFactoid;
398 
399     rExport.pFib->m_fcPlcfBklFactoid = rStream.Tell();
400     for (const WW8_CP& rCP : m_aEndCPs)
401         rStream.WriteInt32(rCP);
402     rStream.WriteInt32(rExport.pFib->m_ccpText + rExport.pFib->m_ccpTxbx);
403 
404     // Write FBKLD.
405     for (size_t i = 0; i < m_aEndCPs.size(); ++i)
406     {
407         rStream.WriteInt16(i); // ibkf
408         rStream.WriteInt16(0); // cDepth, 0 as does not overlap with any other smart tag.
409     }
410     rExport.pFib->m_lcbPlcfBklFactoid = rStream.Tell() - rExport.pFib->m_fcPlcfBklFactoid;
411 
412     rExport.pFib->m_fcFactoidData = rStream.Tell();
413     // Write SmartTagData.
414     MSOFactoidType aFactoidType;
415     aFactoidType.m_nId = 1;
416     aFactoidType.m_aUri = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
417     aFactoidType.m_aTag = "RDF";
418     WW8SmartTagData aSmartTagData;
419     aSmartTagData.m_aPropBagStore.m_aFactoidTypes.push_back(aFactoidType);
420 
421     std::set<OUString> aSet;
422     for (const std::map<OUString, OUString>& rStatements : m_aStatements)
423     {
424         // Statements for a single text node.
425         for (const auto& rPair : rStatements)
426         {
427             aSet.insert(rPair.first);
428             aSet.insert(rPair.second);
429         }
430     }
431     aSmartTagData.m_aPropBagStore.m_aStringTable.assign(aSet.begin(), aSet.end());
432     for (const std::map<OUString, OUString>& rStatements : m_aStatements)
433     {
434         MSOPropertyBag aPropertyBag;
435         aPropertyBag.m_nId = 1;
436         for (const auto& rPair : rStatements)
437         {
438             MSOProperty aProperty;
439             aProperty.m_nKey = std::distance(aSet.begin(), aSet.find(rPair.first));
440             aProperty.m_nValue = std::distance(aSet.begin(), aSet.find(rPair.second));
441             aPropertyBag.m_aProperties.push_back(aProperty);
442         }
443         aSmartTagData.m_aPropBags.push_back(aPropertyBag);
444     }
445 
446     aSmartTagData.Write(rExport);
447     rExport.pFib->m_lcbFactoidData = rStream.Tell() - rExport.pFib->m_fcFactoidData;
448 }
449 
450 #define DEFAULT_STYLES_COUNT 16
451 
452 // Names of the storage streams
453 #define sMainStream OUString("WordDocument")
454 #define sCompObj "\1CompObj"
455 
WriteDop(WW8Export & rWrt)456 static void WriteDop( WW8Export& rWrt )
457 {
458     WW8Dop& rDop = *rWrt.pDop;
459 
460     // i#78951#, store the value of unknown compatibility options
461     rDop.SetCompatibilityOptions( rWrt.m_pDoc->getIDocumentSettingAccess().Getn32DummyCompatibilityOptions1());
462     rDop.SetCompatibilityOptions2( rWrt.m_pDoc->getIDocumentSettingAccess().Getn32DummyCompatibilityOptions2());
463 
464     rDop.fNoLeading = !rWrt.m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::ADD_EXT_LEADING);
465     rDop.fUsePrinterMetrics = !rWrt.m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::USE_VIRTUAL_DEVICE);
466 
467     // write default TabStop
468     const SvxTabStopItem& rTabStop =
469         DefaultItemGet<SvxTabStopItem>(*rWrt.m_pDoc, RES_PARATR_TABSTOP);
470     rDop.dxaTab = static_cast<sal_uInt16>(rTabStop[0].GetTabPos());
471 
472     // Zoom factor and type
473     SwViewShell *pViewShell(rWrt.m_pDoc->getIDocumentLayoutAccess().GetCurrentViewShell());
474     if (pViewShell)
475     {
476         switch ( pViewShell->GetViewOptions()->GetZoomType() )
477         {
478             case SvxZoomType::WHOLEPAGE: rDop.zkSaved = 1; break;
479             case SvxZoomType::PAGEWIDTH: rDop.zkSaved = 2; break;
480             case SvxZoomType::OPTIMAL:   rDop.zkSaved = 3; break;
481             default:                 rDop.zkSaved = 0;
482                 rDop.wScaleSaved = pViewShell->GetViewOptions()->GetZoom();
483                 break;
484         }
485     }
486 
487     // Values from the DocumentStatistics (are definitely needed
488     // for the DocStat fields)
489     rDop.fWCFootnoteEdn = true; // because they are included in StarWriter
490 
491     const SwDocStat& rDStat = rWrt.m_pDoc->getIDocumentStatistics().GetDocStat();
492     rDop.cWords = rDStat.nWord;
493     rDop.cCh = rDStat.nChar;
494     rDop.cPg = static_cast< sal_Int16 >(rDStat.nPage);
495     rDop.cParas = rDStat.nPara;
496     rDop.cLines = rDStat.nPara;
497 
498     SwDocShell *pDocShell(rWrt.m_pDoc->GetDocShell());
499     OSL_ENSURE(pDocShell, "no SwDocShell");
500     uno::Reference<document::XDocumentProperties> xDocProps;
501     uno::Reference<beans::XPropertySet> xProps;
502     if ( pDocShell )
503     {
504         xProps.set(pDocShell->GetModel(), uno::UNO_QUERY);
505 
506         rDop.lKeyProtDoc = pDocShell->GetModifyPasswordHash();
507     }
508 
509     if ((rWrt.pSepx && rWrt.pSepx->DocumentIsProtected()) ||
510         rWrt.m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_FORM ) ||
511         rDop.lKeyProtDoc != 0)
512     {
513         rDop.fProtEnabled =  true;
514         // The password was ignored at import if forms protection was enabled,
515         // so round-trip it since protection is still enabled.
516         if ( rDop.lKeyProtDoc == 0 && xProps.is() )
517         {
518             comphelper::SequenceAsHashMap aPropMap( xProps->getPropertyValue("InteropGrabBag"));
519             aPropMap.getValue("FormPasswordHash") >>= rDop.lKeyProtDoc;
520         }
521     }
522     else
523     {
524         rDop.fProtEnabled = false;
525     }
526 
527     if (!xDocProps.is())
528     {
529         rDop.dttmCreated = rDop.dttmRevised = rDop.dttmLastPrint = 0x45FBAC69;
530     }
531     else
532     {
533         ::util::DateTime uDT = xDocProps->getCreationDate();
534         rDop.dttmCreated = sw::ms::DateTime2DTTM(DateTime(uDT));
535         uDT = xDocProps->getModificationDate();
536         rDop.dttmRevised = sw::ms::DateTime2DTTM(DateTime(uDT));
537         uDT = xDocProps->getPrintDate();
538         rDop.dttmLastPrint = sw::ms::DateTime2DTTM(DateTime(uDT));
539     }
540 
541     // Also, the DocStat fields in headers, footers are not calculated correctly.
542     // ( we do not have this fields! )
543 
544     // and also for the Headers and Footers
545     rDop.cWordsFootnoteEnd   = rDStat.nWord;
546     rDop.cChFootnoteEdn      = rDStat.nChar;
547     rDop.cPgFootnoteEdn      = static_cast<sal_Int16>(rDStat.nPage);
548     rDop.cParasFootnoteEdn   = rDStat.nPara;
549     rDop.cLinesFootnoteEdn   = rDStat.nPara;
550 
551     rDop.fDontUseHTMLAutoSpacing = rWrt.m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::PARA_SPACE_MAX);
552 
553     rDop.fExpShRtn = !rWrt.m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK); // #i56856#
554 
555     rDop.Write( *rWrt.pTableStrm, *rWrt.pFib );
556 }
557 
GetJapanNotBeginLevel1()558 const sal_Unicode *WW8DopTypography::GetJapanNotBeginLevel1()
559 {
560     static const sal_Unicode aJapanNotBeginLevel1[nMaxFollowing] =
561     //Japanese Level 1
562     {
563         0x0021, 0x0025, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f,
564         0x005d, 0x007d, 0x00a2, 0x00b0, 0x2019, 0x201d, 0x2030, 0x2032,
565         0x2033, 0x2103, 0x3001, 0x3002, 0x3005, 0x3009, 0x300b, 0x300d,
566         0x300f, 0x3011, 0x3015, 0x309b, 0x309c, 0x309d, 0x309e, 0x30fb,
567         0x30fd, 0x30fe, 0xff01, 0xff05, 0xff09, 0xff0c, 0xff0e, 0xff1a,
568         0xff1b, 0xff1f, 0xff3d, 0xff5d, 0xff61, 0xff63, 0xff64, 0xff65,
569         0xff9e, 0xff9f, 0xffe0
570     };
571     return &aJapanNotBeginLevel1[0];
572 }
573 
GetJapanNotEndLevel1()574 const sal_Unicode *WW8DopTypography::GetJapanNotEndLevel1()
575 {
576     static const sal_Unicode aJapanNotEndLevel1[nMaxLeading] =
577     //Japanese Level 1
578     {
579         0x0024, 0x0028, 0x005b, 0x005c, 0x007b, 0x00a3, 0x00a5, 0x2018,
580         0x201c, 0x3008, 0x300a, 0x300c, 0x300e, 0x3010, 0x3014, 0xff04,
581         0xff08, 0xff3b, 0xff5b, 0xff62, 0xffe1, 0xffe5
582     };
583     return &aJapanNotEndLevel1[0];
584 }
585 
lcl_CmpBeginEndChars(const OUString & rSWStr,const sal_Unicode * pMSStr,int nMSStrByteLen)586 static int lcl_CmpBeginEndChars( const OUString& rSWStr,
587     const sal_Unicode* pMSStr, int nMSStrByteLen )
588 {
589     nMSStrByteLen /= sizeof( sal_Unicode );
590     if( nMSStrByteLen > rSWStr.getLength() )
591         nMSStrByteLen = rSWStr.getLength()+1;
592     nMSStrByteLen *= sizeof( sal_Unicode );
593 
594     return memcmp( rSWStr.getStr(), pMSStr, nMSStrByteLen );
595 }
596 
597 /*
598 Converts the OOo Asian Typography into a best fit match for Microsoft
599 Asian typography. This structure is actually dumped to disk within the
600 Dop Writer. Assumption is that rTypo is cleared to 0 on entry
601 */
ExportDopTypography(WW8DopTypography & rTypo)602 void WW8Export::ExportDopTypography(WW8DopTypography &rTypo)
603 {
604     static const sal_Unicode aLangNotBegin[4][WW8DopTypography::nMaxFollowing]=
605     {
606         //Japanese Level 1
607         {
608             0x0021, 0x0025, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f,
609             0x005d, 0x007d, 0x00a2, 0x00b0, 0x2019, 0x201d, 0x2030, 0x2032,
610             0x2033, 0x2103, 0x3001, 0x3002, 0x3005, 0x3009, 0x300b, 0x300d,
611             0x300f, 0x3011, 0x3015, 0x3041, 0x3043, 0x3045, 0x3047, 0x3049,
612             0x3063, 0x3083, 0x3085, 0x3087, 0x308e, 0x309b, 0x309c, 0x309d,
613             0x309e, 0x30a1, 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30c3, 0x30e3,
614             0x30e5, 0x30e7, 0x30ee, 0x30f5, 0x30f6, 0x30fb, 0x30fc, 0x30fd,
615             0x30fe, 0xff01, 0xff05, 0xff09, 0xff0c, 0xff0e, 0xff1a, 0xff1b,
616             0xff1f, 0xff3d, 0xff5d, 0xff61, 0xff63, 0xff64, 0xff65, 0xff67,
617             0xff68, 0xff69, 0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f,
618             0xff70, 0xff9e, 0xff9f, 0xffe0
619         },
620         //Simplified Chinese
621         {
622             0x0021, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f, 0x005d,
623             0x007d, 0x00a8, 0x00b7, 0x02c7, 0x02c9, 0x2015, 0x2016, 0x2019,
624             0x201d, 0x2026, 0x2236, 0x3001, 0x3002, 0x3003, 0x3005, 0x3009,
625             0x300b, 0x300d, 0x300f, 0x3011, 0x3015, 0x3017, 0xff01, 0xff02,
626             0xff07, 0xff09, 0xff0c, 0xff0e, 0xff1a, 0xff1b, 0xff1f, 0xff3d,
627             0xff40, 0xff5c, 0xff5d, 0xff5e, 0xffe0
628         },
629         //Korean
630         {
631             0x0021, 0x0025, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f,
632             0x005d, 0x007d, 0x00a2, 0x00b0, 0x2019, 0x201d, 0x2032, 0x2033,
633             0x2103, 0x3009, 0x300b, 0x300d, 0x300f, 0x3011, 0x3015, 0xff01,
634             0xff05, 0xff09, 0xff0c, 0xff0e, 0xff1a, 0xff1b, 0xff1f, 0xff3d,
635             0xff5d, 0xffe0
636         },
637         //Traditional Chinese
638         {
639             0x0021, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f, 0x005d,
640             0x007d, 0x00a2, 0x00b7, 0x2013, 0x2014, 0x2019, 0x201d, 0x2022,
641             0x2025, 0x2026, 0x2027, 0x2032, 0x2574, 0x3001, 0x3002, 0x3009,
642             0x300b, 0x300d, 0x300f, 0x3011, 0x3015, 0x301e, 0xfe30, 0xfe31,
643             0xfe33, 0xfe34, 0xfe36, 0xfe38, 0xfe3a, 0xfe3c, 0xfe3e, 0xfe40,
644             0xfe42, 0xfe44, 0xfe4f, 0xfe50, 0xfe51, 0xfe52, 0xfe54, 0xfe55,
645             0xfe56, 0xfe57, 0xfe5a, 0xfe5c, 0xfe5e, 0xff01, 0xff09, 0xff0c,
646             0xff0e, 0xff1a, 0xff1b, 0xff1f, 0xff5c, 0xff5d, 0xff64
647         },
648     };
649 
650     static const sal_Unicode aLangNotEnd[4][WW8DopTypography::nMaxLeading] =
651     {
652         //Japanese Level 1
653         {
654             0x0024, 0x0028, 0x005b, 0x005c, 0x007b, 0x00a3, 0x00a5, 0x2018,
655             0x201c, 0x3008, 0x300a, 0x300c, 0x300e, 0x3010, 0x3014, 0xff04,
656             0xff08, 0xff3b, 0xff5b, 0xff62, 0xffe1, 0xffe5
657         },
658         //Simplified Chinese
659         {
660             0x0028, 0x005b, 0x007b, 0x00b7, 0x2018, 0x201c, 0x3008, 0x300a,
661             0x300c, 0x300e, 0x3010, 0x3014, 0x3016, 0xff08, 0xff0e, 0xff3b,
662             0xff5b, 0xffe1, 0xffe5
663         },
664         //Korean
665         {
666             0x0028, 0x005b, 0x005c, 0x007b, 0x00a3, 0x00a5, 0x2018, 0x201c,
667             0x3008, 0x300a, 0x300c, 0x300e, 0x3010, 0x3014, 0xff04, 0xff08,
668             0xff3b, 0xff5b, 0xffe6
669         },
670         //Traditional Chinese
671         {
672             0x0028, 0x005b, 0x007b, 0x00a3, 0x00a5, 0x2018, 0x201c, 0x2035,
673             0x3008, 0x300a, 0x300c, 0x300e, 0x3010, 0x3014, 0x301d, 0xfe35,
674             0xfe37, 0xfe39, 0xfe3b, 0xfe3d, 0xfe3f, 0xfe41, 0xfe43, 0xfe59,
675             0xfe5b, 0xfe5d, 0xff08, 0xff5b
676         },
677     };
678 
679     const i18n::ForbiddenCharacters *pForbidden = nullptr;
680     const i18n::ForbiddenCharacters *pUseMe = nullptr;
681     sal_uInt8 nUseReserved=0;
682     int nNoNeeded=0;
683     /*
684     Now we have some minor difficult issues, to wit...
685     a. MicroSoft Office can only store one set of begin and end characters in
686     a given document, not one per language.
687     b. StarOffice has only a concept of one set of begin and end characters for
688     a given language, i.e. not the two levels of kinsoku in japanese
689 
690     What is unknown as yet is if our default begin and end chars for
691     japanese, chinese tradition, chinese simplified and korean are different
692     in Word and Writer. I already suspect that they are different between
693     different version of word itself.
694 
695     So what have come up with is to simply see if any of the four languages
696     in OOo have been changed away from OUR defaults, and if one has then
697     export that. If more than one has in the future we may hack in something
698     which examines our document properties to see which language is used the
699     most and choose that, for now we choose the first and throw an ASSERT
700     */
701 
702     /*Our default Japanese Level is 2, this is a special MS hack to set this*/
703     rTypo.m_reserved2 = 1;
704 
705     for (rTypo.m_reserved1=8;rTypo.m_reserved1>0;rTypo.m_reserved1-=2)
706     {
707         if (nullptr != (pForbidden = m_pDoc->getIDocumentSettingAccess().getForbiddenCharacters(rTypo.GetConvertedLang(),
708             false)))
709         {
710             int nIdx = (rTypo.m_reserved1-2)/2;
711             if( lcl_CmpBeginEndChars( pForbidden->endLine,
712                     aLangNotEnd[ nIdx ], sizeof(aLangNotEnd[ nIdx ]) ) ||
713                 lcl_CmpBeginEndChars( pForbidden->beginLine,
714                     aLangNotBegin[ nIdx ], sizeof(aLangNotBegin[ nIdx ]) ) )
715             {
716                 //One exception for Japanese, if it matches a level 1 we
717                 //can use one extra flag for that, rather than use a custom
718                 if (rTypo.GetConvertedLang() == LANGUAGE_JAPANESE)
719                 {
720                     if (
721                           !lcl_CmpBeginEndChars
722                             (
723                                 pForbidden->endLine,
724                                 WW8DopTypography::GetJapanNotEndLevel1(),
725                                 WW8DopTypography::nMaxLeading * sizeof(sal_Unicode)
726                             )
727                         &&
728                           !lcl_CmpBeginEndChars
729                             (
730                                 pForbidden->beginLine,
731                                 WW8DopTypography::GetJapanNotBeginLevel1(),
732                                 WW8DopTypography::nMaxFollowing * sizeof(sal_Unicode)
733                             )
734                         )
735                     {
736                         rTypo.m_reserved2 = 0;
737                         continue;
738                     }
739                 }
740 
741                 if (!pUseMe)
742                 {
743                     pUseMe = pForbidden;
744                     nUseReserved = rTypo.m_reserved1;
745                     rTypo.m_iLevelOfKinsoku = 2;
746                 }
747                 nNoNeeded++;
748             }
749         }
750     }
751 
752     OSL_ENSURE( nNoNeeded<=1, "Example of unexportable forbidden chars" );
753     rTypo.m_reserved1=nUseReserved;
754     if (rTypo.m_iLevelOfKinsoku && pUseMe)
755     {
756         rTypo.m_cchFollowingPunct = msword_cast<sal_Int16>
757             (pUseMe->beginLine.getLength());
758         if (rTypo.m_cchFollowingPunct > WW8DopTypography::nMaxFollowing - 1)
759             rTypo.m_cchFollowingPunct = WW8DopTypography::nMaxFollowing - 1;
760 
761         rTypo.m_cchLeadingPunct = msword_cast<sal_Int16>
762             (pUseMe->endLine.getLength());
763         if (rTypo.m_cchLeadingPunct > WW8DopTypography::nMaxLeading - 1)
764             rTypo.m_cchLeadingPunct = WW8DopTypography::nMaxLeading -1;
765 
766         memcpy(rTypo.m_rgxchFPunct,pUseMe->beginLine.getStr(),
767             (rTypo.m_cchFollowingPunct+1)*2);
768 
769         memcpy(rTypo.m_rgxchLPunct,pUseMe->endLine.getStr(),
770             (rTypo.m_cchLeadingPunct+1)*2);
771     }
772 
773     const IDocumentSettingAccess& rIDocumentSettingAccess = GetWriter().getIDocumentSettingAccess();
774 
775     rTypo.m_fKerningPunct = sal_uInt16(rIDocumentSettingAccess.get(DocumentSettingId::KERN_ASIAN_PUNCTUATION));
776     rTypo.m_iJustification = sal_uInt16(m_pDoc->getIDocumentSettingAccess().getCharacterCompressionType());
777 }
778 
779 // It can only be found something with this method, if it is used within
780 // WW8_SwAttrIter::OutAttr() and WW8Export::OutputItemSet()
HasItem(sal_uInt16 nWhich) const781 const SfxPoolItem* MSWordExportBase::HasItem( sal_uInt16 nWhich ) const
782 {
783     const SfxPoolItem* pItem=nullptr;
784     if (m_pISet)
785     {
786         // if write an EditEngine text, then the WhichIds are greater than
787         // our own Ids. So the Id have to translate from our into the
788         // EditEngine Range
789         nWhich = sw::hack::GetSetWhichFromSwDocWhich(*m_pISet, *m_pDoc, nWhich);
790         if (nWhich && SfxItemState::SET != m_pISet->GetItemState(nWhich, true, &pItem))
791             pItem = nullptr;
792     }
793     else if( m_pChpIter )
794         pItem = m_pChpIter->HasTextItem( nWhich );
795     else
796     {
797         OSL_ENSURE( false, "Where is my ItemSet / pChpIter ?" );
798         pItem = nullptr;
799     }
800     return pItem;
801 }
802 
GetItem(sal_uInt16 nWhich) const803 const SfxPoolItem& MSWordExportBase::GetItem(sal_uInt16 nWhich) const
804 {
805     assert((m_pISet || m_pChpIter) && "Where is my ItemSet / pChpIter ?");
806     if (m_pISet)
807     {
808         // if write an EditEngine text, then the WhichIds are greater than
809         // our own Ids. So the Id have to translate from our into the
810         // EditEngine Range
811         nWhich = sw::hack::GetSetWhichFromSwDocWhich(*m_pISet, *m_pDoc, nWhich);
812         OSL_ENSURE(nWhich != 0, "All broken, Impossible");
813         return m_pISet->Get(nWhich);
814     }
815     return m_pChpIter->GetItem( nWhich );
816 }
817 
WW8_WrPlc1(sal_uInt16 nStructSz)818 WW8_WrPlc1::WW8_WrPlc1( sal_uInt16 nStructSz )
819     : nStructSiz( nStructSz )
820 {
821     nDataLen = 16 * nStructSz;
822     pData.reset( new sal_uInt8[ nDataLen ] );
823 }
824 
~WW8_WrPlc1()825 WW8_WrPlc1::~WW8_WrPlc1()
826 {
827 }
828 
Prev() const829 WW8_CP WW8_WrPlc1::Prev() const
830 {
831     bool b = !aPos.empty();
832     OSL_ENSURE(b,"Prev called on empty list");
833     return b ? aPos.back() : 0;
834 }
835 
Append(WW8_CP nCp,const void * pNewData)836 void WW8_WrPlc1::Append( WW8_CP nCp, const void* pNewData )
837 {
838     sal_uLong nInsPos = aPos.size() * nStructSiz;
839     aPos.push_back( nCp );
840     if( nDataLen < nInsPos + nStructSiz )
841     {
842         sal_uInt8* pNew = new sal_uInt8[ 2 * nDataLen ];
843         memcpy( pNew, pData.get(), nDataLen );
844         pData.reset(pNew);
845         nDataLen *= 2;
846     }
847     memcpy( pData.get() + nInsPos, pNewData, nStructSiz );
848 }
849 
Finish(sal_uLong nLastCp,sal_uLong nSttCp)850 void WW8_WrPlc1::Finish( sal_uLong nLastCp, sal_uLong nSttCp )
851 {
852     if( !aPos.empty() )
853     {
854         aPos.push_back( nLastCp );
855         if( nSttCp )
856             for(WW8_CP & rCp : aPos)
857                 rCp -= nSttCp;
858     }
859 }
860 
Write(SvStream & rStrm)861 void WW8_WrPlc1::Write( SvStream& rStrm )
862 {
863     decltype(aPos)::size_type i;
864     for( i = 0; i < aPos.size(); ++i )
865         SwWW8Writer::WriteLong( rStrm, aPos[i] );
866     if( i )
867         rStrm.WriteBytes(pData.get(), (i-1) * nStructSiz);
868 }
869 
870 // Class WW8_WrPlcField for fields
871 
Write(WW8Export & rWrt)872 void WW8_WrPlcField::Write( WW8Export& rWrt )
873 {
874     if( WW8_WrPlc1::Count() <= 1 )
875         return;
876 
877     WW8_FC *pfc;
878     sal_Int32 *plc;
879     switch (nTextTyp)
880     {
881         case TXT_MAINTEXT:
882             pfc = &rWrt.pFib->m_fcPlcffldMom;
883             plc = &rWrt.pFib->m_lcbPlcffldMom;
884             break;
885         case TXT_HDFT:
886             pfc = &rWrt.pFib->m_fcPlcffldHdr;
887             plc = &rWrt.pFib->m_lcbPlcffldHdr;
888             break;
889 
890         case TXT_FTN:
891             pfc = &rWrt.pFib->m_fcPlcffldFootnote;
892             plc = &rWrt.pFib->m_lcbPlcffldFootnote;
893             break;
894 
895         case TXT_EDN:
896             pfc = &rWrt.pFib->m_fcPlcffldEdn;
897             plc = &rWrt.pFib->m_lcbPlcffldEdn;
898             break;
899 
900         case TXT_ATN:
901             pfc = &rWrt.pFib->m_fcPlcffldAtn;
902             plc = &rWrt.pFib->m_lcbPlcffldAtn;
903             break;
904 
905         case TXT_TXTBOX:
906             pfc = &rWrt.pFib->m_fcPlcffldTxbx;
907             plc = &rWrt.pFib->m_lcbPlcffldTxbx;
908             break;
909 
910         case TXT_HFTXTBOX:
911             pfc = &rWrt.pFib->m_fcPlcffldHdrTxbx;
912             plc = &rWrt.pFib->m_lcbPlcffldHdrTxbx;
913             break;
914 
915         default:
916             pfc = plc = nullptr;
917             break;
918     }
919 
920     if( pfc && plc )
921     {
922         sal_uInt64 nFcStart = rWrt.pTableStrm->Tell();
923         WW8_WrPlc1::Write( *rWrt.pTableStrm );
924         *pfc = nFcStart;
925         *plc = rWrt.pTableStrm->Tell() - nFcStart;
926     }
927 }
928 
Write(WW8Export & rWrt)929 void WW8_WrMagicTable::Write( WW8Export& rWrt )
930 {
931     if( WW8_WrPlc1::Count() <= 1 )
932         return;
933     sal_uLong nFcStart = rWrt.pTableStrm->Tell();
934     WW8_WrPlc1::Write( *rWrt.pTableStrm );
935     rWrt.pFib->m_fcPlcfTch = nFcStart;
936     rWrt.pFib->m_lcbPlcfTch = rWrt.pTableStrm->Tell() - nFcStart;
937 }
938 
Append(WW8_CP nCp,sal_uLong nData)939 void WW8_WrMagicTable::Append( WW8_CP nCp, sal_uLong nData)
940 {
941     /*
942     Tell the undocumented table hack that everything between here and the last
943     table position is non-table text, don't do it if the previous position is
944     the same as this one, as that would be a region of 0 length
945     */
946     if ((!Count()) || (Prev() != nCp))
947     {
948         SVBT32 nLittle;
949         UInt32ToSVBT32(nData,nLittle);
950         WW8_WrPlc1::Append(nCp, nLittle);
951     }
952 }
953 
FillCount(SvStream & rStrm,sal_uLong nCount)954 void SwWW8Writer::FillCount( SvStream& rStrm, sal_uLong nCount )
955 {
956     static const sal_uInt32 aNulls[16] =
957     {
958         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 // 64 Byte
959     };
960 
961     while (nCount > 64)
962     {
963         rStrm.WriteBytes(aNulls, 64); // in steps of 64-Byte
964         nCount -= 64;
965     }
966     rStrm.WriteBytes(aNulls, nCount); // write the rest (0 .. 64 Bytes)
967 }
968 
FillUntil(SvStream & rStrm,sal_uLong nEndPos)969 sal_uLong SwWW8Writer::FillUntil( SvStream& rStrm, sal_uLong nEndPos )
970 {
971     sal_uInt64 nCurPos = rStrm.Tell();
972     if( !nEndPos )                          // nEndPos == 0 -> next Page
973         nEndPos = (nCurPos + 0x1ff) & ~0x1ffUL;
974 
975     if( nEndPos > nCurPos )
976         SwWW8Writer::FillCount( rStrm, nEndPos - nCurPos );
977 #if OSL_DEBUG_LEVEL > 0
978     else
979         OSL_ENSURE( nEndPos == nCurPos, "Wrong FillUntil()" );
980 #endif
981     return rStrm.Tell();
982 }
983 
WW8_WrPlcPn(WW8Export & rWr,ePLCFT ePl,WW8_FC nStartFc)984 WW8_WrPlcPn::WW8_WrPlcPn(WW8Export& rWr, ePLCFT ePl, WW8_FC nStartFc)
985     : rWrt(rWr)
986     , nFkpStartPage(0)
987     , ePlc(ePl)
988 {
989     m_Fkps.push_back(std::make_unique<WW8_WrFkp>(ePlc, nStartFc));
990 }
991 
~WW8_WrPlcPn()992 WW8_WrPlcPn::~WW8_WrPlcPn()
993 {
994 }
995 
CopyLastSprms(sal_uInt8 & rLen)996 sal_uInt8 *WW8_WrPlcPn::CopyLastSprms(sal_uInt8 &rLen)
997 {
998     WW8_WrFkp& rF = *m_Fkps.back();
999     return rF.CopyLastSprms(rLen);
1000 }
1001 
AppendFkpEntry(WW8_FC nEndFc,short nVarLen,const sal_uInt8 * pSprms)1002 void WW8_WrPlcPn::AppendFkpEntry(WW8_FC nEndFc,short nVarLen,const sal_uInt8* pSprms)
1003 {
1004     WW8_WrFkp* pF = m_Fkps.back().get();
1005 
1006     // big sprm? build the sprmPHugePapx
1007     sal_uInt8* pNewSprms = const_cast<sal_uInt8*>(pSprms);
1008     sal_uInt8 aHugePapx[ 8 ];
1009     if (PAP == ePlc && 488 <= nVarLen)
1010     {
1011         sal_uInt8* p = aHugePapx;
1012         *p++ = *pSprms++;           // set style Id
1013         *p++ = *pSprms++;
1014         nVarLen -= 2;
1015 
1016         long nDataPos = rWrt.pDataStrm->Tell();
1017         SwWW8Writer::WriteShort( *rWrt.pDataStrm, nVarLen );
1018         rWrt.pDataStrm->WriteBytes(pSprms, nVarLen);
1019 
1020         Set_UInt16( p, 0x6646 );    // set SprmCode
1021         Set_UInt32( p, nDataPos );  // set startpos (FC) in the datastream
1022         nVarLen = static_cast< short >(p - aHugePapx);
1023         pSprms = pNewSprms = aHugePapx;
1024     }
1025     // if append at the same FC-EndPos and there are sprms, then get the old
1026     // sprms and erase it; they will append now with the new sprms
1027     else if( nVarLen && pF->IsEqualPos( nEndFc ))
1028         pF->MergeToNew( nVarLen, pNewSprms );
1029     // has the prev EndFC an empty sprm and the current is empty too, then
1030     // expand only the old EndFc to the new EndFc
1031     else if( !nVarLen && pF->IsEmptySprm() )
1032     {
1033         pF->SetNewEnd( nEndFc );
1034         return ;
1035     }
1036 
1037     bool bOk = pF->Append(nEndFc, nVarLen, pNewSprms);
1038     if( !bOk )
1039     {
1040         pF->Combine();
1041         pF = new WW8_WrFkp(ePlc, pF->GetEndFc()); // Start new Fkp == end of old Fkp
1042 
1043         m_Fkps.push_back(std::unique_ptr<WW8_WrFkp>(pF));
1044         if( !pF->Append( nEndFc, nVarLen, pNewSprms ) )
1045         {
1046             OSL_ENSURE( false, "Unable to insert Sprm" );
1047         }
1048     }
1049     if( pNewSprms != pSprms )   //Merge to new has created a new block
1050         delete[] pNewSprms;
1051 }
1052 
WriteFkps()1053 void WW8_WrPlcPn::WriteFkps()
1054 {
1055     nFkpStartPage = static_cast<sal_uInt16>( SwWW8Writer::FillUntil( rWrt.Strm() ) >> 9 );
1056 
1057     for(const std::unique_ptr<WW8_WrFkp> & rp : m_Fkps)
1058     {
1059         rp->Write( rWrt.Strm(), *rWrt.m_pGrf );
1060     }
1061 
1062     if( CHP == ePlc )
1063     {
1064         rWrt.pFib->m_pnChpFirst = nFkpStartPage;
1065         rWrt.pFib->m_cpnBteChp = m_Fkps.size();
1066     }
1067     else
1068     {
1069         rWrt.pFib->m_pnPapFirst = nFkpStartPage;
1070         rWrt.pFib->m_cpnBtePap = m_Fkps.size();
1071     }
1072 }
1073 
WritePlc()1074 void WW8_WrPlcPn::WritePlc()
1075 {
1076     sal_uInt64 nFcStart = rWrt.pTableStrm->Tell();
1077     decltype(m_Fkps)::size_type i;
1078 
1079     for (i = 0; i < m_Fkps.size(); ++i)
1080     {
1081         SwWW8Writer::WriteLong( *rWrt.pTableStrm,
1082                                 m_Fkps[ i ]->GetStartFc() );
1083     }
1084 
1085     SwWW8Writer::WriteLong( *rWrt.pTableStrm,
1086                                 m_Fkps[ i - 1 ]->GetEndFc() );
1087 
1088     // for every FKP output the page
1089     for (i = 0; i < m_Fkps.size(); ++i)
1090     {
1091         SwWW8Writer::WriteLong( *rWrt.pTableStrm, i + nFkpStartPage );
1092     }
1093 
1094     if( CHP == ePlc )
1095     {
1096         rWrt.pFib->m_fcPlcfbteChpx = nFcStart;
1097         rWrt.pFib->m_lcbPlcfbteChpx = rWrt.pTableStrm->Tell() - nFcStart;
1098     }
1099     else
1100     {
1101         rWrt.pFib->m_fcPlcfbtePapx = nFcStart;
1102         rWrt.pFib->m_lcbPlcfbtePapx = rWrt.pTableStrm->Tell() - nFcStart;
1103     }
1104 }
1105 
WW8_WrFkp(ePLCFT ePl,WW8_FC nStartFc)1106 WW8_WrFkp::WW8_WrFkp(ePLCFT ePl, WW8_FC nStartFc)
1107     : ePlc(ePl), nStartGrp(511), nOldStartGrp(511),
1108     nItemSize( ( CHP == ePl ) ? 1 : 13 ),
1109     nIMax(0), nOldVarLen(0), bCombined(false)
1110 {
1111     pFkp = reinterpret_cast<sal_uInt8*>(new sal_Int32[128]);           // 512 Byte
1112     pOfs = reinterpret_cast<sal_uInt8*>(new sal_Int32[128]);           // 512 Byte
1113     memset( pFkp, 0, 4 * 128 );
1114     memset( pOfs, 0, 4 * 128 );
1115     reinterpret_cast<sal_Int32*>(pFkp)[0] = nStartFc;         // 0th entry FC at nStartFc
1116 }
1117 
~WW8_WrFkp()1118 WW8_WrFkp::~WW8_WrFkp()
1119 {
1120     delete[] reinterpret_cast<sal_Int32 *>(pFkp);
1121     delete[] reinterpret_cast<sal_Int32 *>(pOfs);
1122 }
1123 
SearchSameSprm(sal_uInt16 nVarLen,const sal_uInt8 * pSprms)1124 sal_uInt8 WW8_WrFkp::SearchSameSprm( sal_uInt16 nVarLen, const sal_uInt8* pSprms )
1125 {
1126     if( 3 < nVarLen )
1127     {
1128         // if the sprms contained picture-references then never equal!
1129         for( sal_uInt8 n = static_cast< sal_uInt8 >(nVarLen - 1); 3 < n; --n )
1130             if( pSprms[ n ] == GRF_MAGIC_3 &&
1131                 pSprms[ n-1 ] == GRF_MAGIC_2 &&
1132                 pSprms[ n-2 ] == GRF_MAGIC_1 )
1133                     return 0;
1134     }
1135 
1136     short i;
1137     for( i = 0; i < nIMax; i++ )
1138     {
1139         sal_uInt8 nStart = pOfs[i * nItemSize];
1140         if( nStart )
1141         {                               // has Sprms
1142             const sal_uInt8* p = pFkp + ( static_cast<sal_uInt16>(nStart) << 1 );
1143             if( ( CHP == ePlc
1144                     ? (*p++ == nVarLen)
1145                     : ((static_cast<sal_uInt16>(*p++) << 1 ) == (( nVarLen+1) & 0xfffe)) )
1146                 && !memcmp( p, pSprms, nVarLen ) )
1147                     return nStart;                      // found it
1148         }
1149     }
1150     return 0;           // didn't found it
1151 }
1152 
CopyLastSprms(sal_uInt8 & rLen)1153 sal_uInt8 *WW8_WrFkp::CopyLastSprms(sal_uInt8 &rLen)
1154 {
1155     rLen=0;
1156     sal_uInt8 *pStart=nullptr,*pRet=nullptr;
1157 
1158     if (!bCombined)
1159         pStart = pOfs;
1160     else
1161         pStart = pFkp + ( nIMax + 1 ) * 4;
1162 
1163     sal_uInt8 nStart = *(pStart + (nIMax-1) * nItemSize);
1164 
1165     const sal_uInt8* p = pFkp + ( static_cast<sal_uInt16>(nStart) << 1 );
1166 
1167     if (!*p)
1168         p++;
1169 
1170     if (*p)
1171     {
1172         rLen = *p++;
1173         if (PAP == ePlc)
1174             rLen *= 2;
1175         pRet = new sal_uInt8[rLen];
1176         memcpy(pRet,p,rLen);
1177     }
1178     return pRet;
1179 }
1180 
Append(WW8_FC nEndFc,sal_uInt16 nVarLen,const sal_uInt8 * pSprms)1181 bool WW8_WrFkp::Append( WW8_FC nEndFc, sal_uInt16 nVarLen, const sal_uInt8* pSprms )
1182 {
1183     assert((!nVarLen || pSprms) && "Item pointer missing");
1184 
1185     OSL_ENSURE( nVarLen < ( ( ePlc == PAP ) ? 497U : 502U ), "Sprms too long !" );
1186 
1187     if( bCombined )
1188     {
1189         OSL_ENSURE( false, "Fkp::Append: Fkp is already combined" );
1190         return false;
1191     }
1192     sal_Int32 n = reinterpret_cast<sal_Int32*>(pFkp)[nIMax];        // last entry
1193     if( nEndFc <= n )
1194     {
1195         OSL_ENSURE( nEndFc >= n, "+Fkp: FC backwards" );
1196         OSL_ENSURE( !nVarLen || !pSprms || nEndFc != n,
1197                                     "+Fkp: used same FC multiple times" );
1198                         // same FC without Sprm is ignored without grumbling
1199 
1200         return true;    // ignore (do not create a new Fkp)
1201     }
1202 
1203     sal_uInt8 nOldP = nVarLen ? SearchSameSprm( nVarLen, pSprms ) : 0;
1204                                             // Combine equal entries
1205     short nOffset=0, nPos = nStartGrp;
1206     if (nVarLen && !nOldP)
1207     {
1208         nPos = PAP == ePlc
1209                 ? ( 13 == nItemSize     // HACK: PAP and bWrtWW8 !!
1210                      ? (nStartGrp & 0xFFFE ) - nVarLen - 1
1211                      : (nStartGrp - (((nVarLen + 1) & 0xFFFE)+1)) & 0xFFFE )
1212                 : ((nStartGrp - nVarLen - 1) & 0xFFFE);
1213         if( nPos < 0 )
1214             return false;           // doesn't fit at all
1215         nOffset = nPos;             // save offset (can also be uneven!)
1216         nPos &= 0xFFFE;             // Pos for Sprms ( gerade Pos )
1217     }
1218 
1219     if( static_cast<sal_uInt16>(nPos) <= ( nIMax + 2U ) * 4U + ( nIMax + 1U ) * nItemSize )
1220                                             // does it fits after the CPs and offsets?
1221         return false;                       // no
1222 
1223     reinterpret_cast<sal_Int32*>(pFkp)[nIMax + 1] = nEndFc;     // insert FC
1224 
1225     nOldVarLen = static_cast<sal_uInt8>(nVarLen);
1226     if( nVarLen && !nOldP )
1227     {               // insert it for real
1228         nOldStartGrp = nStartGrp;
1229 
1230         nStartGrp = nPos;
1231         pOfs[nIMax * nItemSize] = static_cast<sal_uInt8>( nStartGrp >> 1 );
1232                                             // insert (start-of-data >> 1)
1233         sal_uInt8 nCnt = static_cast< sal_uInt8 >(CHP == ePlc
1234                         ? ( nVarLen < 256 ) ? static_cast<sal_uInt8>(nVarLen) : 255
1235                         : ( ( nVarLen + 1 ) >> 1 ));
1236 
1237         pFkp[ nOffset ] = nCnt;                     // Enter data length
1238         memcpy( pFkp + nOffset + 1, pSprms, nVarLen );  // store Sprms
1239     }
1240     else
1241     {
1242         // do not enter for real ( no Sprms or recurrence )
1243         // start-of-data 0 ( no data ) or recurrence
1244         pOfs[nIMax * nItemSize] = nOldP;
1245     }
1246     nIMax++;
1247     return true;
1248 }
1249 
Combine()1250 void WW8_WrFkp::Combine()
1251 {
1252     if( bCombined )
1253         return;
1254     if( nIMax )
1255         memcpy( pFkp + ( nIMax + 1 ) * 4, pOfs, nIMax * nItemSize );
1256     delete[] pOfs;
1257     pOfs = nullptr;
1258     pFkp[511] = nIMax;
1259     bCombined = true;
1260 
1261 #if defined OSL_BIGENDIAN           // only the FCs will be rotated here
1262     sal_uInt16 i;                   // the Sprms must be rotated elsewhere
1263 
1264     sal_uInt32* p;
1265     for( i = 0, p = (sal_uInt32*)pFkp; i <= nIMax; i++, p++ )
1266         *p = OSL_SWAPDWORD( *p );
1267 #endif // ifdef OSL_BIGENDIAN
1268 }
1269 
Write(SvStream & rStrm,SwWW8WrGrf & rGrf)1270 void WW8_WrFkp::Write( SvStream& rStrm, SwWW8WrGrf& rGrf )
1271 {
1272     Combine();                      // If not already combined
1273 
1274     sal_uInt8* p;               //  search magic for nPicLocFc
1275     sal_uInt8* pEnd = pFkp + nStartGrp;
1276     for( p = pFkp + 511 - 4; p >= pEnd; p-- )
1277     {
1278         if( *p != GRF_MAGIC_1 )     // search for signature 0x12 0x34 0x56 0xXX
1279             continue;
1280         if( *(p+1) != GRF_MAGIC_2 )
1281             continue;
1282         if( *(p+2) != GRF_MAGIC_3 )
1283             continue;
1284 
1285         SVBT32 nPos;                // signature found
1286         UInt32ToSVBT32( rGrf.GetFPos(), nPos );   // FilePos the graphics
1287         memcpy( p, nPos, 4 );       // patch FilePos over the signature
1288     }
1289     rStrm.WriteBytes(pFkp, 512);
1290 }
1291 
MergeToNew(short & rVarLen,sal_uInt8 * & rpNewSprms)1292 void WW8_WrFkp::MergeToNew( short& rVarLen, sal_uInt8 *& rpNewSprms )
1293 {
1294     sal_uInt8 nStart = pOfs[ (nIMax-1) * nItemSize ];
1295     if( nStart )
1296     {   // has Sprms
1297         sal_uInt8* p = pFkp + ( static_cast<sal_uInt16>(nStart) << 1 );
1298 
1299         // old and new equal? Then copy only one into the new sprms
1300         if( nOldVarLen == rVarLen && !memcmp( p+1, rpNewSprms, nOldVarLen ))
1301         {
1302             sal_uInt8* pNew = new sal_uInt8[ nOldVarLen ];
1303             memcpy( pNew, p+1, nOldVarLen );
1304             rpNewSprms = pNew;
1305         }
1306         else
1307         {
1308             sal_uInt8* pNew = new sal_uInt8[ nOldVarLen + rVarLen ];
1309             memcpy( pNew, p+1, nOldVarLen );
1310             memcpy( pNew + nOldVarLen, rpNewSprms, rVarLen );
1311 
1312             rpNewSprms = pNew;
1313             rVarLen = rVarLen + nOldVarLen;
1314         }
1315         --nIMax;
1316         // if this Sprms don't used from others, remove it
1317         bool bFnd = false;
1318         for (sal_uInt16 n = 0; n < nIMax; ++n)
1319         {
1320             if (nStart == pOfs[n * nItemSize])
1321             {
1322                 bFnd = true;
1323                 break;
1324             }
1325         }
1326         if (!bFnd)
1327         {
1328             nStartGrp = nOldStartGrp;
1329             memset( p, 0, nOldVarLen+1 );
1330         }
1331     }
1332 }
1333 
GetStartFc() const1334 WW8_FC WW8_WrFkp::GetStartFc() const
1335 {
1336     // when bCombined, then the array beginning with pFkp is already byte-swapped
1337     // to LittleEndian, so to extract the start and end positions they must
1338     // be swapped back.
1339     if( bCombined )
1340         return SVBT32ToUInt32( pFkp );        // 0. Element
1341     return reinterpret_cast<sal_Int32*>(pFkp)[0];
1342 }
1343 
GetEndFc() const1344 WW8_FC WW8_WrFkp::GetEndFc() const
1345 {
1346     if( bCombined )
1347         return SVBT32ToUInt32( &(pFkp[nIMax*4]) );    // nIMax-th SVBT32-Element
1348     return reinterpret_cast<sal_Int32*>(pFkp)[nIMax];
1349 }
1350 
1351 // Method for managing the piece table
WW8_WrPct(WW8_FC nfcMin)1352 WW8_WrPct::WW8_WrPct(WW8_FC nfcMin)
1353     : nOldFc(nfcMin)
1354 {
1355     AppendPc(nOldFc);
1356 }
1357 
~WW8_WrPct()1358 WW8_WrPct::~WW8_WrPct()
1359 {
1360 }
1361 
1362 // Fill the piece and create a new one
AppendPc(WW8_FC nStartFc)1363 void WW8_WrPct::AppendPc(WW8_FC nStartFc)
1364 {
1365     WW8_CP nStartCp = nStartFc - nOldFc;    // subtract the beginning of the text
1366     if ( !nStartCp && !m_Pcts.empty())
1367     {
1368         OSL_ENSURE(1 == m_Pcts.size(), "empty Piece!");
1369         m_Pcts.pop_back();
1370     }
1371 
1372     nOldFc = nStartFc;                      // remember StartFc as old
1373 
1374     nStartCp >>= 1;     // for Unicode: number of characters / 2
1375 
1376     if (!m_Pcts.empty())
1377     {
1378         nStartCp += m_Pcts.back()->GetStartCp();
1379     }
1380 
1381     m_Pcts.push_back(std::make_unique<WW8_WrPc>(nStartFc, nStartCp));
1382 }
1383 
WritePc(WW8Export & rWrt)1384 void WW8_WrPct::WritePc( WW8Export& rWrt )
1385 {
1386     sal_uInt64 nPctStart;
1387     sal_uLong nOldPos, nEndPos;
1388 
1389     nPctStart = rWrt.pTableStrm->Tell();                    // Start piece table
1390     rWrt.pTableStrm->WriteChar( char(0x02) );                       // Status byte PCT
1391     nOldPos = nPctStart + 1;                                // remember Position
1392     SwWW8Writer::WriteLong( *rWrt.pTableStrm, 0 );          // then the length
1393 
1394     for (auto const& it : m_Pcts) // ranges
1395     {
1396         SwWW8Writer::WriteLong( *rWrt.pTableStrm, it->GetStartCp() );
1397     }
1398 
1399     // calculate the last Pos
1400     sal_uLong nStartCp = rWrt.pFib->m_fcMac - nOldFc;
1401     nStartCp >>= 1;             // For Unicode: number of characters / 2
1402     nStartCp += m_Pcts.back()->GetStartCp();
1403     SwWW8Writer::WriteLong( *rWrt.pTableStrm, nStartCp );
1404 
1405     // piece references
1406     for (auto const& it : m_Pcts)
1407     {
1408         SwWW8Writer::WriteShort(*rWrt.pTableStrm, it->GetStatus());
1409         SwWW8Writer::WriteLong(*rWrt.pTableStrm, it->GetStartFc());
1410         SwWW8Writer::WriteShort( *rWrt.pTableStrm, 0);          // PRM=0
1411     }
1412 
1413     // entries in the FIB
1414     rWrt.pFib->m_fcClx = nPctStart;
1415     nEndPos = rWrt.pTableStrm->Tell();
1416     rWrt.pFib->m_lcbClx = nEndPos - nPctStart;
1417 
1418     // and register the length as well
1419     SwWW8Writer::WriteLong( *rWrt.pTableStrm, nOldPos,
1420                             nEndPos - nPctStart-5 );
1421 
1422 }
1423 
SetParaBreak()1424 void WW8_WrPct::SetParaBreak()
1425 {
1426     OSL_ENSURE( !m_Pcts.empty(), "SetParaBreak : m_Pcts.empty()" );
1427     m_Pcts.back()->SetStatus();
1428 }
1429 
Fc2Cp(sal_uLong nFc) const1430 WW8_CP WW8_WrPct::Fc2Cp( sal_uLong nFc ) const
1431 {
1432     OSL_ENSURE( nFc >= static_cast<sal_uLong>(nOldFc), "FilePos lies in front of last piece" );
1433     OSL_ENSURE( ! m_Pcts.empty(), "Fc2Cp no piece available" );
1434 
1435     nFc -= nOldFc;
1436     nFc /= 2; // Unicode
1437     return nFc + m_Pcts.back()->GetStartCp();
1438 }
1439 
AppendBookmarks(const SwTextNode & rNd,sal_Int32 nCurrentPos,sal_Int32 nLen)1440 void WW8Export::AppendBookmarks( const SwTextNode& rNd, sal_Int32 nCurrentPos, sal_Int32 nLen )
1441 {
1442     std::vector< const ::sw::mark::IMark* > aArr;
1443     sal_uInt16 nContent;
1444     const sal_Int32 nCurrentEnd = nCurrentPos + nLen;
1445     if( GetWriter().GetBookmarks( rNd, nCurrentPos, nCurrentEnd, aArr ))
1446     {
1447         sal_uLong nNd = rNd.GetIndex(), nSttCP = Fc2Cp( Strm().Tell() );
1448         for(const ::sw::mark::IMark* p : aArr)
1449         {
1450             const ::sw::mark::IMark& rBkmk = *p;
1451             if(dynamic_cast< const ::sw::mark::IFieldmark *>(&rBkmk))
1452                 continue;
1453 
1454             const SwPosition* pPos = &rBkmk.GetMarkPos();
1455             const SwPosition* pOPos = nullptr;
1456             if(rBkmk.IsExpanded())
1457                 pOPos = &rBkmk.GetOtherMarkPos();
1458             if( pOPos && pOPos->nNode == pPos->nNode &&
1459                 pOPos->nContent < pPos->nContent )
1460             {
1461                 pPos = pOPos;
1462                 pOPos = &rBkmk.GetMarkPos();
1463             }
1464 
1465             if( !pOPos || ( nNd == pPos->nNode.GetIndex() &&
1466                 ( nContent = pPos->nContent.GetIndex() ) >= nCurrentPos &&
1467                 nContent < nCurrentEnd ) )
1468             {
1469                 sal_uLong nCp = nSttCP + pPos->nContent.GetIndex() - nCurrentPos;
1470                 m_pBkmks->Append(nCp, BookmarkToWord(rBkmk.GetName()));
1471             }
1472             if( pOPos && nNd == pOPos->nNode.GetIndex() &&
1473                 ( nContent = pOPos->nContent.GetIndex() ) >= nCurrentPos &&
1474                 nContent < nCurrentEnd )
1475             {
1476                 sal_uLong nCp = nSttCP + pOPos->nContent.GetIndex() - nCurrentPos;
1477                 m_pBkmks->Append(nCp, BookmarkToWord(rBkmk.GetName()));
1478             }
1479         }
1480     }
1481 }
1482 
AppendAnnotationMarks(const SwWW8AttrIter & rAttrs,sal_Int32 nCurrentPos,sal_Int32 nLen)1483 void WW8Export::AppendAnnotationMarks(const SwWW8AttrIter& rAttrs, sal_Int32 nCurrentPos, sal_Int32 nLen)
1484 {
1485     IMarkVector aMarks;
1486     if (GetAnnotationMarks(rAttrs, nCurrentPos, nCurrentPos + nLen, aMarks))
1487     {
1488         for (const sw::mark::IMark* pMark : aMarks)
1489         {
1490             const sal_Int32 nStart = pMark->GetMarkStart().nContent.GetIndex();
1491             if (nStart == nCurrentPos)
1492             {
1493                 m_pAtn->AddRangeStartPosition(pMark->GetName(), Fc2Cp(Strm().Tell()),
1494                                               !rAttrs.HasFlysAt(nCurrentPos));
1495             }
1496         }
1497     }
1498 }
1499 
AppendSmartTags(SwTextNode & rTextNode)1500 void WW8Export::AppendSmartTags(SwTextNode& rTextNode)
1501 {
1502     std::map<OUString, OUString> aStatements = SwRDFHelper::getTextNodeStatements("urn:bails", rTextNode);
1503     if (!aStatements.empty())
1504     {
1505         WW8_CP nCP = Fc2Cp(Strm().Tell());
1506         m_pFactoids->Append(nCP, nCP, aStatements);
1507     }
1508 }
1509 
MoveFieldMarks(WW8_CP nFrom,WW8_CP nTo)1510 void WW8Export::MoveFieldMarks(WW8_CP nFrom, WW8_CP nTo)
1511 {
1512     m_pBkmks->MoveFieldMarks(nFrom, nTo);
1513 }
1514 
AppendBookmark(const OUString & rName)1515 void WW8Export::AppendBookmark( const OUString& rName )
1516 {
1517     sal_uLong nSttCP = Fc2Cp( Strm().Tell() );
1518     m_pBkmks->Append( nSttCP, rName );
1519 }
1520 
AppendBookmarkEndWithCorrection(const OUString & rName)1521 void WW8Export::AppendBookmarkEndWithCorrection( const OUString& rName )
1522 {
1523     sal_uLong nEndCP = Fc2Cp( Strm().Tell() );
1524     m_pBkmks->Append( nEndCP - 1, rName );
1525 }
1526 
getBackground()1527 std::shared_ptr<SvxBrushItem> MSWordExportBase::getBackground()
1528 {
1529     std::shared_ptr<SvxBrushItem> oRet;
1530     const SwFrameFormat &rFormat = m_pDoc->GetPageDesc(0).GetMaster();
1531     std::shared_ptr<SvxBrushItem> aBrush(std::make_shared<SvxBrushItem>(RES_BACKGROUND));
1532     SfxItemState eState = rFormat.GetBackgroundState(aBrush);
1533 
1534     if (SfxItemState::SET == eState)
1535     {
1536         // The 'color' is set for the first page style - take it and use it as the background color of the entire DOCX
1537         if (aBrush->GetColor() != COL_AUTO)
1538             oRet = aBrush;
1539     }
1540     return oRet;
1541 }
1542 
1543 // #i120928 collect all the graphics of bullets applied to paragraphs
CollectGrfsOfBullets()1544 int MSWordExportBase::CollectGrfsOfBullets()
1545 {
1546     m_vecBulletPic.clear();
1547 
1548     if ( m_pDoc )
1549     {
1550         size_t nCountRule = m_pDoc->GetNumRuleTable().size();
1551         for (size_t n = 0; n < nCountRule; ++n)
1552         {
1553             const SwNumRule &rRule = *( m_pDoc->GetNumRuleTable().at(n) );
1554             sal_uInt16 nLevels = rRule.IsContinusNum() ? 1 : 9;
1555             for (sal_uInt16 nLvl = 0; nLvl < nLevels; ++nLvl)
1556             {
1557                 const SwNumFormat &rFormat = rRule.Get(nLvl);
1558                 if (SVX_NUM_BITMAP != rFormat.GetNumberingType())
1559                 {
1560                     continue;
1561                 }
1562                 const Graphic *pGraf = rFormat.GetBrush()? rFormat.GetBrush()->GetGraphic():nullptr;
1563                 if ( pGraf )
1564                 {
1565                     bool bHas = false;
1566                     for (const Graphic* p : m_vecBulletPic)
1567                     {
1568                         if (p->GetChecksum() == pGraf->GetChecksum())
1569                         {
1570                             bHas = true;
1571                             break;
1572                         }
1573                     }
1574                     if (!bHas)
1575                     {
1576                         Size aSize(pGraf->GetPrefSize());
1577                         if (0 != aSize.Height() && 0 != aSize.Width())
1578                            m_vecBulletPic.push_back(pGraf);
1579                     }
1580                 }
1581             }
1582         }
1583     }
1584 
1585     return m_vecBulletPic.size();
1586 }
1587 
BulletDefinitions()1588 void MSWordExportBase::BulletDefinitions()
1589 {
1590     for (size_t i = 0; i < m_vecBulletPic.size(); ++i)
1591     {
1592         const MapMode aMapMode(MapUnit::MapTwip);
1593         const Graphic& rGraphic = *m_vecBulletPic[i];
1594         Size aSize(rGraphic.GetPrefSize());
1595         if (MapUnit::MapPixel == rGraphic.GetPrefMapMode().GetMapUnit())
1596             aSize = Application::GetDefaultDevice()->PixelToLogic(aSize, aMapMode);
1597         else
1598             aSize = OutputDevice::LogicToLogic(aSize,rGraphic.GetPrefMapMode(), aMapMode);
1599 
1600         if (0 != aSize.Height() && 0 != aSize.Width())
1601             AttrOutput().BulletDefinition(i, rGraphic, aSize);
1602     }
1603 }
1604 
1605 //Export Graphic of Bullets
ExportGrfBullet(const SwTextNode & rNd)1606 void WW8Export::ExportGrfBullet(const SwTextNode& rNd)
1607 {
1608     int nCount = CollectGrfsOfBullets();
1609     if (nCount > 0)
1610     {
1611         SwPosition aPos(rNd);
1612         OUString aPicBullets("_PictureBullets");
1613         AppendBookmark(aPicBullets);
1614         for (int i = 0; i < nCount; i++)
1615         {
1616             ww8::Frame aFrame(*(m_vecBulletPic[i]), aPos);
1617             OutGrfBullets(aFrame);
1618         }
1619         AppendBookmark(aPicBullets);
1620     }
1621 }
1622 
1623 static sal_uInt8 nAttrMagicIdx = 0;
OutGrfBullets(const ww8::Frame & rFrame)1624 void WW8Export::OutGrfBullets(const ww8::Frame & rFrame)
1625 {
1626     if ( !m_pGrf || !m_pChpPlc || !pO )
1627         return;
1628 
1629     m_pGrf->Insert(rFrame);
1630     m_pChpPlc->AppendFkpEntry( Strm().Tell(), pO->size(), pO->data() );
1631     pO->clear();
1632     // if links...
1633     WriteChar( char(1) );
1634 
1635     sal_uInt8 aArr[ 22 ];
1636     sal_uInt8* pArr = aArr;
1637 
1638     // sprmCFSpec
1639     Set_UInt16( pArr, 0x855 );
1640     Set_UInt8( pArr, 1 );
1641 
1642     Set_UInt16( pArr, 0x083c );
1643     Set_UInt8( pArr, 0x81 );
1644 
1645     // sprmCPicLocation
1646     Set_UInt16( pArr, 0x6a03 );
1647     Set_UInt32( pArr, GRF_MAGIC_321 );
1648 
1649     //extern  nAttrMagicIdx;
1650     --pArr;
1651     Set_UInt8( pArr, nAttrMagicIdx++ );
1652     m_pChpPlc->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr - aArr), aArr );
1653 }
1654 
GetGrfIndex(const SvxBrushItem & rBrush)1655 int MSWordExportBase::GetGrfIndex(const SvxBrushItem& rBrush)
1656 {
1657     int nIndex = -1;
1658 
1659     const Graphic* pGraphic = rBrush.GetGraphic();
1660     if (pGraphic)
1661     {
1662         for (size_t i = 0; i < m_vecBulletPic.size(); ++i)
1663         {
1664             if (m_vecBulletPic[i]->GetChecksum() == pGraphic->GetChecksum())
1665             {
1666                 nIndex = i;
1667                 break;
1668             }
1669         }
1670     }
1671 
1672     return nIndex;
1673 }
1674 
Write(Writer & rWrt)1675 void WW8_WrtRedlineAuthor::Write( Writer& rWrt )
1676 {
1677     WW8Export & rWW8Wrt = *(static_cast<SwWW8Writer&>(rWrt).m_pExport);
1678     rWW8Wrt.WriteAsStringTable(maAuthors, rWW8Wrt.pFib->m_fcSttbfRMark,
1679         rWW8Wrt.pFib->m_lcbSttbfRMark);
1680 }
1681 
AddRedlineAuthor(std::size_t nId)1682 sal_uInt16 WW8Export::AddRedlineAuthor( std::size_t nId )
1683 {
1684     if( !m_pRedlAuthors )
1685     {
1686         m_pRedlAuthors = new WW8_WrtRedlineAuthor;
1687         m_pRedlAuthors->AddName("Unknown");
1688     }
1689     return m_pRedlAuthors->AddName( SW_MOD()->GetRedlineAuthor( nId ) );
1690 }
1691 
WriteAsStringTable(const std::vector<OUString> & rStrings,sal_Int32 & rfcSttbf,sal_Int32 & rlcbSttbf)1692 void WW8Export::WriteAsStringTable(const std::vector<OUString>& rStrings,
1693     sal_Int32& rfcSttbf, sal_Int32& rlcbSttbf)
1694 {
1695     sal_uInt16 n, nCount = static_cast< sal_uInt16 >(rStrings.size());
1696     if( nCount )
1697     {
1698         // we have some Redlines found in the document -> the
1699         // Author Name Stringtable
1700         SvStream& rStrm = *pTableStrm;
1701         rfcSttbf = rStrm.Tell();
1702         SwWW8Writer::WriteShort( rStrm, -1 );
1703         SwWW8Writer::WriteLong( rStrm, nCount );
1704         for( n = 0; n < nCount; ++n )
1705         {
1706             const OUString& rNm = rStrings[n];
1707             SwWW8Writer::WriteShort( rStrm, rNm.getLength() );
1708             SwWW8Writer::WriteString16(rStrm, rNm, false);
1709         }
1710         rlcbSttbf = rStrm.Tell() - rfcSttbf;
1711     }
1712 }
1713 
1714 // WriteShort() sets at FilePos nPos the value nVal and seeks to the old
1715 // FilePos. Used to insert lengths after the fact.
WriteShort(SvStream & rStrm,sal_uLong nPos,sal_Int16 nVal)1716 void SwWW8Writer::WriteShort( SvStream& rStrm, sal_uLong nPos, sal_Int16 nVal )
1717 {
1718     sal_uInt64 nOldPos = rStrm.Tell();       // remember Pos
1719     rStrm.Seek( nPos );
1720     SwWW8Writer::WriteShort( rStrm, nVal );
1721     rStrm.Seek( nOldPos );
1722 }
1723 
WriteLong(SvStream & rStrm,sal_uLong nPos,sal_Int32 nVal)1724 void SwWW8Writer::WriteLong( SvStream& rStrm, sal_uLong nPos, sal_Int32 nVal )
1725 {
1726     sal_uInt64 nOldPos = rStrm.Tell();       // remember Pos
1727     rStrm.Seek( nPos );
1728     SwWW8Writer::WriteLong( rStrm, nVal );
1729     rStrm.Seek( nOldPos );
1730 }
1731 
InsUInt16(ww::bytes & rO,sal_uInt16 n)1732 void SwWW8Writer::InsUInt16(ww::bytes &rO, sal_uInt16 n)
1733 {
1734     SVBT16 nL;
1735     ShortToSVBT16( n, nL );
1736     rO.push_back(nL[0]);
1737     rO.push_back(nL[1]);
1738 }
1739 
InsUInt32(ww::bytes & rO,sal_uInt32 n)1740 void SwWW8Writer::InsUInt32(ww::bytes &rO, sal_uInt32 n)
1741 {
1742     SVBT32 nL;
1743     UInt32ToSVBT32( n, nL );
1744     rO.push_back(nL[0]);
1745     rO.push_back(nL[1]);
1746     rO.push_back(nL[2]);
1747     rO.push_back(nL[3]);
1748 }
1749 
InsAsString16(ww::bytes & rO,const OUString & rStr)1750 void SwWW8Writer::InsAsString16(ww::bytes &rO, const OUString& rStr)
1751 {
1752     const sal_Unicode* pStr = rStr.getStr();
1753     for (sal_Int32 n = 0, nLen = rStr.getLength(); n < nLen; ++n, ++pStr)
1754         SwWW8Writer::InsUInt16( rO, *pStr );
1755 }
1756 
InsAsString8(ww::bytes & rO,const OUString & rStr,rtl_TextEncoding eCodeSet)1757 void SwWW8Writer::InsAsString8(ww::bytes &rO, const OUString& rStr,
1758         rtl_TextEncoding eCodeSet)
1759 {
1760     OString sTmp(OUStringToOString(rStr, eCodeSet));
1761     const sal_Char *pStart = sTmp.getStr();
1762     const sal_Char *pEnd = pStart + sTmp.getLength();
1763     rO.reserve(rO.size() + sTmp.getLength());
1764 
1765     std::copy(pStart, pEnd, std::inserter(rO, rO.end()));
1766 }
1767 
WriteString16(SvStream & rStrm,const OUString & rStr,bool bAddZero)1768 void SwWW8Writer::WriteString16(SvStream& rStrm, const OUString& rStr,
1769     bool bAddZero)
1770 {
1771     ww::bytes aBytes;
1772     SwWW8Writer::InsAsString16(aBytes, rStr);
1773     if (bAddZero)
1774         SwWW8Writer::InsUInt16(aBytes, 0);
1775     //vectors are guaranteed to have contiguous memory, so we can do
1776     //this while migrating away from WW8Bytes. Meyers Effective STL, item 16
1777     if (!aBytes.empty())
1778         rStrm.WriteBytes(aBytes.data(), aBytes.size());
1779 }
1780 
WriteString_xstz(SvStream & rStrm,const OUString & rStr,bool bAddZero)1781 void SwWW8Writer::WriteString_xstz(SvStream& rStrm, const OUString& rStr, bool bAddZero)
1782 {
1783     ww::bytes aBytes;
1784     SwWW8Writer::InsUInt16(aBytes, rStr.getLength());
1785     SwWW8Writer::InsAsString16(aBytes, rStr);
1786     if (bAddZero)
1787         SwWW8Writer::InsUInt16(aBytes, 0);
1788     rStrm.WriteBytes(aBytes.data(), aBytes.size());
1789 }
1790 
WriteString8(SvStream & rStrm,const OUString & rStr,bool bAddZero,rtl_TextEncoding eCodeSet)1791 void SwWW8Writer::WriteString8(SvStream& rStrm, const OUString& rStr,
1792     bool bAddZero, rtl_TextEncoding eCodeSet)
1793 {
1794     ww::bytes aBytes;
1795     SwWW8Writer::InsAsString8(aBytes, rStr, eCodeSet);
1796     if (bAddZero)
1797         aBytes.push_back(0);
1798     //vectors are guaranteed to have contiguous memory, so we can do
1799     ////this while migrating away from WW8Bytes. Meyers Effective STL, item 16
1800     if (!aBytes.empty())
1801         rStrm.WriteBytes(aBytes.data(), aBytes.size());
1802 }
1803 
WriteStringAsPara(const OUString & rText)1804 void WW8Export::WriteStringAsPara( const OUString& rText )
1805 {
1806     if( !rText.isEmpty() )
1807         OutSwString(rText, 0, rText.getLength());
1808     WriteCR();              // CR thereafter
1809 
1810     ww::bytes aArr;
1811     SwWW8Writer::InsUInt16( aArr, 0/*nStyleId*/ );
1812     if( m_bOutTable )
1813     {                                               // Tab-Attr
1814         // sprmPFInTable
1815         SwWW8Writer::InsUInt16( aArr, NS_sprm::sprmPFInTable );
1816         aArr.push_back( 1 );
1817     }
1818 
1819     sal_uInt64 nPos = Strm().Tell();
1820     m_pPapPlc->AppendFkpEntry( nPos, aArr.size(), aArr.data() );
1821     m_pChpPlc->AppendFkpEntry( nPos );
1822 }
1823 
WriteSpecialText(sal_uLong nStart,sal_uLong nEnd,sal_uInt8 nTTyp)1824 void MSWordExportBase::WriteSpecialText( sal_uLong nStart, sal_uLong nEnd, sal_uInt8 nTTyp )
1825 {
1826     sal_uInt8 nOldTyp = m_nTextTyp;
1827     m_nTextTyp = nTTyp;
1828     auto const pOldPam = m_pCurPam;       //!! Simply shifting the PaM without restoring should do the job too
1829     sal_uLong nOldStart = m_nCurStart;
1830     sal_uLong nOldEnd = m_nCurEnd;
1831     SwPaM* pOldEnd = m_pOrigPam;
1832     bool bOldPageDescs = m_bOutPageDescs;
1833     m_bOutPageDescs = false;
1834     if ( nTTyp == TXT_FTN || nTTyp == TXT_EDN )
1835         m_bAddFootnoteTab = true;   // enable one aesthetic tab for this footnote
1836 
1837     SetCurPam(nStart, nEnd);
1838 
1839     // clear linked textboxes since old ones can't be linked to frames in this section
1840     m_aLinkedTextboxesHelper.clear();
1841 
1842     // tdf#106261 Reset table infos, otherwise the depth of the cells will be
1843     // incorrect, in case the header/footer had table(s) and we try to export
1844     // the same table second time.
1845     ww8::WW8TableInfo::Pointer_t pOldTableInfo = m_pTableInfo;
1846     m_pTableInfo = std::make_shared<ww8::WW8TableInfo>();
1847 
1848     WriteText();
1849 
1850     m_pTableInfo = pOldTableInfo;
1851 
1852     m_bOutPageDescs = bOldPageDescs;
1853     m_pCurPam = pOldPam; // delete Pam
1854     m_nCurStart = nOldStart;
1855     m_nCurEnd = nOldEnd;
1856     m_pOrigPam = pOldEnd;
1857     m_nTextTyp = nOldTyp;
1858 }
1859 
OutSwString(const OUString & rStr,sal_Int32 nStt,sal_Int32 const nLen)1860 void WW8Export::OutSwString(const OUString& rStr, sal_Int32 nStt,
1861     sal_Int32 const nLen)
1862 
1863 {
1864     SAL_INFO( "sw.ww8.level2", "<OutSwString>" );
1865 
1866     if( nLen )
1867     {
1868         if( nStt || nLen != rStr.getLength() )
1869         {
1870             OUString sOut( rStr.copy( nStt, nLen ) );
1871 
1872             SAL_INFO( "sw.ww8.level2", sOut );
1873 
1874             SwWW8Writer::WriteString16(Strm(), sOut, false);
1875         }
1876         else
1877         {
1878             SAL_INFO( "sw.ww8.level2", rStr );
1879 
1880             SwWW8Writer::WriteString16(Strm(), rStr, false);
1881         }
1882     }
1883 
1884     SAL_INFO( "sw.ww8.level2", "</OutSwString>" );
1885 }
1886 
WriteCR(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)1887 void WW8Export::WriteCR(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
1888 {
1889     if (pTableTextNodeInfoInner.get() != nullptr && pTableTextNodeInfoInner->getDepth() == 1 && pTableTextNodeInfoInner->isEndOfCell())
1890         WriteChar('\007');
1891     else
1892         WriteChar( '\015' );
1893 
1894     m_pPiece->SetParaBreak();
1895 }
1896 
WriteChar(sal_Unicode c)1897 void WW8Export::WriteChar( sal_Unicode c )
1898 {
1899     Strm().WriteUInt16( c );
1900 }
1901 
SetCurPam(sal_uLong nStt,sal_uLong nEnd)1902 void MSWordExportBase::SetCurPam(sal_uLong nStt, sal_uLong nEnd)
1903 {
1904     m_nCurStart = nStt;
1905     m_nCurEnd = nEnd;
1906     m_pCurPam = Writer::NewUnoCursor( *m_pDoc, nStt, nEnd );
1907 
1908     // Recognize tables in special cases
1909     if ( nStt != m_pCurPam->GetMark()->nNode.GetIndex() &&
1910          m_pDoc->GetNodes()[ nStt ]->IsTableNode() )
1911     {
1912         m_pCurPam->GetMark()->nNode = nStt;
1913     }
1914 
1915     m_pOrigPam = m_pCurPam.get(); // ???
1916     m_pCurPam->Exchange();
1917 }
1918 
SaveData(sal_uLong nStt,sal_uLong nEnd)1919 void MSWordExportBase::SaveData( sal_uLong nStt, sal_uLong nEnd )
1920 {
1921     MSWordSaveData aData;
1922 
1923     // WW8Export only stuff - zeroed here not to issue warnings
1924     aData.pOOld = nullptr;
1925 
1926     // Common stuff
1927     aData.pOldPam = m_pCurPam;
1928     aData.pOldEnd = m_pOrigPam;
1929     aData.pOldFlyFormat = m_pParentFrame;
1930     aData.pOldPageDesc = m_pCurrentPageDesc;
1931 
1932     aData.pOldFlyOffset = m_pFlyOffset;
1933     aData.eOldAnchorType = m_eNewAnchorType;
1934 
1935     aData.bOldOutTable = m_bOutTable;
1936     aData.bOldFlyFrameAttrs = m_bOutFlyFrameAttrs;
1937     aData.bOldStartTOX = m_bStartTOX;
1938     aData.bOldInWriteTOX = m_bInWriteTOX;
1939 
1940     SetCurPam(nStt, nEnd);
1941 
1942     m_bOutTable = false;
1943     // Caution: bIsInTable should not be set here
1944     m_bOutFlyFrameAttrs = false;
1945     m_bStartTOX = false;
1946     m_bInWriteTOX = false;
1947 
1948     m_aSaveData.push( std::move(aData) );
1949 }
1950 
RestoreData()1951 void MSWordExportBase::RestoreData()
1952 {
1953     MSWordSaveData &rData = m_aSaveData.top();
1954 
1955     m_pCurPam = rData.pOldPam;
1956     m_nCurStart = rData.nOldStart;
1957     m_nCurEnd = rData.nOldEnd;
1958     m_pOrigPam = rData.pOldEnd;
1959 
1960     m_bOutTable = rData.bOldOutTable;
1961     m_bOutFlyFrameAttrs = rData.bOldFlyFrameAttrs;
1962     m_bStartTOX = rData.bOldStartTOX;
1963     m_bInWriteTOX = rData.bOldInWriteTOX;
1964 
1965     m_pParentFrame = rData.pOldFlyFormat;
1966     m_pCurrentPageDesc = rData.pOldPageDesc;
1967 
1968     m_eNewAnchorType = rData.eOldAnchorType;
1969     m_pFlyOffset = rData.pOldFlyOffset;
1970 
1971     m_aSaveData.pop();
1972 }
1973 
SaveData(sal_uLong nStt,sal_uLong nEnd)1974 void WW8Export::SaveData( sal_uLong nStt, sal_uLong nEnd )
1975 {
1976     MSWordExportBase::SaveData( nStt, nEnd );
1977 
1978     MSWordSaveData &rData = m_aSaveData.top();
1979 
1980     if ( !pO->empty() )
1981     {
1982         rData.pOOld = std::move(pO);
1983         pO.reset(new ww::bytes);
1984     }
1985     else
1986         rData.pOOld = nullptr; // reuse pO
1987 
1988     rData.bOldWriteAll = GetWriter().m_bWriteAll;
1989     GetWriter().m_bWriteAll = true;
1990 }
1991 
RestoreData()1992 void WW8Export::RestoreData()
1993 {
1994     MSWordSaveData &rData = m_aSaveData.top();
1995 
1996     GetWriter().m_bWriteAll = rData.bOldWriteAll;
1997 
1998     OSL_ENSURE( pO->empty(), "pO is not empty in WW8Export::RestoreData()" );
1999     if ( rData.pOOld )
2000     {
2001         pO = std::move(rData.pOOld);
2002     }
2003 
2004     MSWordExportBase::RestoreData();
2005 }
2006 
TableInfoCell(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)2007 void WW8AttributeOutput::TableInfoCell( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2008 {
2009     sal_uInt32 nDepth = pTableTextNodeInfoInner->getDepth();
2010 
2011     if ( nDepth > 0 )
2012     {
2013         /* Cell */
2014         m_rWW8Export.InsUInt16( NS_sprm::sprmPFInTable );
2015         m_rWW8Export.pO->push_back( sal_uInt8(0x1) );
2016         m_rWW8Export.InsUInt16( NS_sprm::sprmPItap );
2017         m_rWW8Export.InsUInt32( nDepth );
2018 
2019         if ( nDepth > 1 && pTableTextNodeInfoInner->isEndOfCell() )
2020         {
2021             m_rWW8Export.InsUInt16( NS_sprm::sprmPFInnerTableCell );
2022             m_rWW8Export.pO->push_back( sal_uInt8(0x1) );
2023         }
2024     }
2025 }
2026 
TableInfoRow(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)2027 void WW8AttributeOutput::TableInfoRow( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2028 {
2029     sal_uInt32 nDepth = pTableTextNodeInfoInner->getDepth();
2030 
2031     if ( nDepth > 0 )
2032     {
2033         /* Row */
2034         if ( pTableTextNodeInfoInner->isEndOfLine() )
2035         {
2036             m_rWW8Export.InsUInt16( NS_sprm::sprmPFInTable );
2037             m_rWW8Export.pO->push_back( sal_uInt8(0x1) );
2038 
2039             if ( nDepth == 1 )
2040             {
2041                 m_rWW8Export.InsUInt16( NS_sprm::sprmPFTtp );
2042                 m_rWW8Export.pO->push_back( sal_uInt8(0x1) );
2043             }
2044 
2045             m_rWW8Export.InsUInt16( NS_sprm::sprmPItap );
2046             m_rWW8Export.InsUInt32( nDepth );
2047 
2048             if ( nDepth > 1 )
2049             {
2050                 m_rWW8Export.InsUInt16( NS_sprm::sprmPFInnerTableCell );
2051                 m_rWW8Export.pO->push_back( sal_uInt8(0x1) );
2052                 m_rWW8Export.InsUInt16( NS_sprm::sprmPFInnerTtp );
2053                 m_rWW8Export.pO->push_back( sal_uInt8(0x1) );
2054             }
2055 
2056             TableDefinition( pTableTextNodeInfoInner );
2057             TableHeight( pTableTextNodeInfoInner );
2058             TableBackgrounds( pTableTextNodeInfoInner );
2059             TableDefaultBorders( pTableTextNodeInfoInner );
2060             TableCanSplit( pTableTextNodeInfoInner );
2061             TableBidi( pTableTextNodeInfoInner );
2062             TableVerticalCell( pTableTextNodeInfoInner );
2063             TableOrientation( pTableTextNodeInfoInner );
2064             TableSpacing( pTableTextNodeInfoInner );
2065             TableCellBorders( pTableTextNodeInfoInner );
2066         }
2067     }
2068 }
2069 
lcl_TCFlags(SwDoc & rDoc,const SwTableBox * pBox,sal_Int32 nRowSpan)2070 static sal_uInt16 lcl_TCFlags(SwDoc &rDoc, const SwTableBox * pBox, sal_Int32 nRowSpan)
2071 {
2072     sal_uInt16 nFlags = 0;
2073 
2074     if (nRowSpan > 1)
2075         nFlags |= (3 << 5);
2076     else if (nRowSpan < 0)
2077         nFlags |= (1 << 5);
2078 
2079     if (pBox != nullptr)
2080     {
2081         const SwFrameFormat * pFormat = pBox->GetFrameFormat();
2082         switch (pFormat->GetVertOrient().GetVertOrient())
2083         {
2084             case text::VertOrientation::CENTER:
2085                 nFlags |= (1 << 7);
2086                 break;
2087             case text::VertOrientation::BOTTOM:
2088                 nFlags |= (2 << 7);
2089                 break;
2090             default:
2091                 break;
2092         }
2093         const SwStartNode * pSttNd = pBox->GetSttNd();
2094         if(pSttNd)
2095         {
2096             SwNodeIndex aIdx( *pSttNd );
2097             const SwContentNode * pCNd = pSttNd->GetNodes().GoNext( &aIdx );
2098             if( pCNd && pCNd->IsTextNode())
2099             {
2100                 SfxItemSet aCoreSet(rDoc.GetAttrPool(), svl::Items<RES_CHRATR_ROTATE, RES_CHRATR_ROTATE>{});
2101                 static_cast<const SwTextNode*>(pCNd)->GetParaAttr(aCoreSet,
2102                     0, static_cast<const SwTextNode*>(pCNd)->GetText().getLength());
2103                 const SfxPoolItem * pRotItem;
2104                 if ( SfxItemState::SET == aCoreSet.GetItemState(RES_CHRATR_ROTATE, true, &pRotItem))
2105                 {
2106                     const SvxCharRotateItem * pRotate = static_cast<const SvxCharRotateItem*>(pRotItem);
2107                     if(pRotate && pRotate->GetValue() == 900)
2108                     {
2109                         nFlags = nFlags | 0x0004 | 0x0008;
2110                     }
2111                     else if(pRotate && pRotate->GetValue() == 2700 )
2112                     {
2113                         nFlags = nFlags | 0x0004 | 0x0010;
2114                     }
2115                 }
2116             }
2117         }
2118     }
2119 
2120     return nFlags;
2121 }
2122 
TableVerticalCell(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)2123 void WW8AttributeOutput::TableVerticalCell( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2124 {
2125     const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
2126     const SwTableLine * pTabLine = pTabBox->GetUpper();
2127     const SwTableBoxes & rTableBoxes = pTabLine->GetTabBoxes();
2128 
2129     sal_uInt8 nBoxes = rTableBoxes.size();
2130     for ( sal_uInt8 n = 0; n < nBoxes; n++ )
2131     {
2132         const SwTableBox * pTabBox1 = rTableBoxes[n];
2133         const SwFrameFormat * pFrameFormat = pTabBox1->GetFrameFormat();
2134 
2135         // Map from our SvxFrameDirection to WW8 TextFlow.
2136         sal_uInt16 nTextFlow = 0;
2137         switch (m_rWW8Export.TrueFrameDirection(*pFrameFormat))
2138         {
2139             case SvxFrameDirection::Vertical_RL_TB:
2140                 nTextFlow = 5;
2141                 break;
2142             case SvxFrameDirection::Vertical_LR_BT:
2143                 nTextFlow = 3;
2144                 break;
2145             default:
2146                 break;
2147         }
2148 
2149         if (nTextFlow != 0)
2150         {
2151             m_rWW8Export.InsUInt16( NS_sprm::sprmTTextFlow );
2152             m_rWW8Export.pO->push_back( n );                   //start range
2153             m_rWW8Export.pO->push_back( sal_uInt8(n + 1) );    //end range
2154             m_rWW8Export.InsUInt16(nTextFlow);
2155         }
2156     }
2157 }
2158 
TableCanSplit(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)2159 void WW8AttributeOutput::TableCanSplit( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2160 {
2161     const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
2162     const SwTableLine * pTabLine = pTabBox->GetUpper();
2163     const SwFrameFormat * pLineFormat = pTabLine->GetFrameFormat();
2164 
2165     /*
2166      By default the row can be split in word, and now in writer we have a
2167      feature equivalent to this, Word stores 1 for fCantSplit if the row
2168      cannot be split, we set true if we can split it. An example is #i4569#
2169      */
2170 
2171     const SwFormatRowSplit& rSplittable = pLineFormat->GetRowSplit();
2172     sal_uInt8 nCantSplit = (!rSplittable.GetValue()) ? 1 : 0;
2173     m_rWW8Export.InsUInt16( NS_sprm::sprmTFCantSplit );
2174     m_rWW8Export.pO->push_back( nCantSplit );
2175     m_rWW8Export.InsUInt16( NS_sprm::sprmTFCantSplit90 ); // also write fCantSplit90
2176     m_rWW8Export.pO->push_back( nCantSplit );
2177 }
2178 
TableBidi(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)2179 void WW8AttributeOutput::TableBidi( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2180 {
2181     const SwTable * pTable = pTableTextNodeInfoInner->getTable();
2182     const SwFrameFormat * pFrameFormat = pTable->GetFrameFormat();
2183 
2184     if ( m_rWW8Export.TrueFrameDirection(*pFrameFormat) == SvxFrameDirection::Horizontal_RL_TB )
2185     {
2186         m_rWW8Export.InsUInt16( NS_sprm::sprmTFBiDi );
2187         m_rWW8Export.InsUInt16( 1 );
2188     }
2189 }
2190 
TableRowRedline(ww8::WW8TableNodeInfoInner::Pointer_t)2191 void WW8AttributeOutput::TableRowRedline( ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/ )
2192 {
2193 }
2194 
TableCellRedline(ww8::WW8TableNodeInfoInner::Pointer_t)2195 void WW8AttributeOutput::TableCellRedline( ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/ )
2196 {
2197 }
2198 
TableHeight(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)2199 void WW8AttributeOutput::TableHeight( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2200 {
2201     const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
2202     const SwTableLine * pTabLine = pTabBox->GetUpper();
2203     const SwFrameFormat * pLineFormat = pTabLine->GetFrameFormat();
2204 
2205     // output line height   sprmTDyaRowHeight
2206     long nHeight = 0;
2207     const SwFormatFrameSize& rLSz = pLineFormat->GetFrameSize();
2208     if ( ATT_VAR_SIZE != rLSz.GetHeightSizeType() && rLSz.GetHeight() )
2209     {
2210         if ( ATT_MIN_SIZE == rLSz.GetHeightSizeType() )
2211             nHeight = rLSz.GetHeight();
2212         else
2213             nHeight = -rLSz.GetHeight();
2214     }
2215 
2216     if ( nHeight )
2217     {
2218         m_rWW8Export.InsUInt16( NS_sprm::sprmTDyaRowHeight );
2219         m_rWW8Export.InsUInt16( static_cast<sal_uInt16>(nHeight) );
2220     }
2221 
2222 }
2223 
TableOrientation(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)2224 void WW8AttributeOutput::TableOrientation( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2225 {
2226     const SwTable * pTable = pTableTextNodeInfoInner->getTable();
2227 
2228     const SwFrameFormat *pFormat = pTable->GetFrameFormat();
2229     if ( !pFormat )
2230     {
2231         SAL_WARN( "sw.ww8", "FrameFormat is nil" );
2232         return;
2233     }
2234 
2235     const SwFormatHoriOrient &rHori = pFormat->GetHoriOrient();
2236     const SwFormatVertOrient &rVert = pFormat->GetVertOrient();
2237 
2238     if (
2239         (text::RelOrientation::PRINT_AREA == rHori.GetRelationOrient() ||
2240          text::RelOrientation::FRAME == rHori.GetRelationOrient())
2241         &&
2242         (text::RelOrientation::PRINT_AREA == rVert.GetRelationOrient() ||
2243          text::RelOrientation::FRAME == rVert.GetRelationOrient())
2244         )
2245     {
2246         const bool bIsRTL = m_rWW8Export.TrueFrameDirection(*pFormat) == SvxFrameDirection::Horizontal_RL_TB;
2247         sal_Int16 eHOri = rHori.GetHoriOrient();
2248         switch (eHOri)
2249         {
2250             case text::HoriOrientation::CENTER:
2251                 m_rWW8Export.InsUInt16( NS_sprm::sprmTJc ); //logical orientation required for MSO
2252                 m_rWW8Export.InsUInt16( 1 );
2253                 m_rWW8Export.InsUInt16( NS_sprm::sprmTJc90 ); //physical orientation required for LO
2254                 m_rWW8Export.InsUInt16( 1 );
2255                 break;
2256             case text::HoriOrientation::RIGHT:
2257                 m_rWW8Export.InsUInt16( NS_sprm::sprmTJc90 ); //required for LO
2258                 m_rWW8Export.InsUInt16( 2 );
2259                 if ( !bIsRTL )
2260                 {
2261                     m_rWW8Export.InsUInt16( NS_sprm::sprmTJc ); //required for MSO
2262                     m_rWW8Export.InsUInt16( 2 );
2263                 }
2264                 break;
2265             case text::HoriOrientation::LEFT:
2266                 if ( bIsRTL )
2267                 {
2268                     m_rWW8Export.InsUInt16( NS_sprm::sprmTJc ); //required for MSO
2269                     m_rWW8Export.InsUInt16( 2 );
2270                 }
2271                 break;
2272             case text::HoriOrientation::LEFT_AND_WIDTH:
2273                 // Width can only be specified for the LOGICAL left, so in RTL, that is always PHYSICAL right
2274                 if ( bIsRTL )
2275                 {
2276                     m_rWW8Export.InsUInt16( NS_sprm::sprmTJc90 ); //required for LO
2277                     m_rWW8Export.InsUInt16( 2 );
2278                 }
2279                 break;
2280             default:
2281                 break;
2282         }
2283     }
2284 }
2285 
TableSpacing(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)2286 void WW8AttributeOutput::TableSpacing(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
2287 {
2288     const SwTable * pTable = pTableTextNodeInfoInner->getTable();
2289     const SwTableFormat* pTableFormat = pTable->GetFrameFormat();
2290 
2291 
2292     // Writing these SPRM's will make the table a floating one, so only write
2293     // them in case the table is already inside a frame.
2294     if (pTableFormat != nullptr && pTable->GetTableNode()->GetFlyFormat())
2295     {
2296         const SvxULSpaceItem & rUL = pTableFormat->GetULSpace();
2297 
2298         if (rUL.GetUpper() > 0)
2299         {
2300             sal_uInt8 const nPadding = 2;
2301             sal_uInt8 const nPcVert = 0;
2302             sal_uInt8 const nPcHorz = 0;
2303 
2304             sal_uInt8 const nTPc = (nPadding << 4) | (nPcVert << 2) | nPcHorz;
2305 
2306             m_rWW8Export.InsUInt16(NS_sprm::sprmTPc);
2307             m_rWW8Export.pO->push_back( nTPc );
2308 
2309             m_rWW8Export.InsUInt16(NS_sprm::sprmTDyaAbs);
2310             m_rWW8Export.InsUInt16(rUL.GetUpper());
2311 
2312             m_rWW8Export.InsUInt16(NS_sprm::sprmTDyaFromText);
2313             m_rWW8Export.InsUInt16(rUL.GetUpper());
2314         }
2315 
2316         if (rUL.GetLower() > 0)
2317         {
2318             m_rWW8Export.InsUInt16(NS_sprm::sprmTDyaFromTextBottom);
2319             m_rWW8Export.InsUInt16(rUL.GetLower());
2320         }
2321     }
2322 }
2323 
TableDefinition(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)2324 void WW8AttributeOutput::TableDefinition( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2325 {
2326     const SwTable * pTable = pTableTextNodeInfoInner->getTable();
2327 
2328     if ( pTable->GetRowsToRepeat() > pTableTextNodeInfoInner->getRow() )
2329     {
2330         m_rWW8Export.InsUInt16( NS_sprm::sprmTTableHeader );
2331         m_rWW8Export.pO->push_back( 1 );
2332     }
2333 
2334     ww8::TableBoxVectorPtr pTableBoxes =
2335         pTableTextNodeInfoInner->getTableBoxesOfRow();
2336     // number of cell written
2337     sal_uInt32 nBoxes = pTableBoxes->size();
2338     assert(nBoxes <= ww8::MAXTABLECELLS);
2339 
2340     // sprm header
2341     m_rWW8Export.InsUInt16( NS_sprm::sprmTDefTable );
2342     sal_uInt16 nSprmSize = 2 + (nBoxes + 1) * 2 + nBoxes * 20;
2343     m_rWW8Export.InsUInt16( nSprmSize ); // length
2344 
2345     // number of boxes
2346     m_rWW8Export.pO->push_back( static_cast<sal_uInt8>(nBoxes) );
2347 
2348     /* cells */
2349     /*
2350      ALWAYS relative when text::HoriOrientation::NONE (nPageSize + ( nPageSize / 10 )) < nTableSz,
2351      in that case the cell width's and table width's are not real. The table
2352      width is maxed and cells relative, so we need the frame (generally page)
2353      width that the table is in to work out the true widths.
2354      */
2355     //const bool bNewTableModel = pTable->IsNewModel();
2356     const SwFrameFormat *pFormat = pTable->GetFrameFormat();
2357     if ( !pFormat )
2358     {
2359         SAL_WARN( "sw.ww8", "FrameFormat is nil" );
2360         return;
2361     }
2362 
2363     const SwFormatHoriOrient &rHori = pFormat->GetHoriOrient();
2364     const SwFormatVertOrient &rVert = pFormat->GetVertOrient();
2365 
2366     SwTwips nTableOffset = 0;
2367 
2368     if (
2369         (text::RelOrientation::PRINT_AREA == rHori.GetRelationOrient() ||
2370          text::RelOrientation::FRAME == rHori.GetRelationOrient())
2371         &&
2372         (text::RelOrientation::PRINT_AREA == rVert.GetRelationOrient() ||
2373          text::RelOrientation::FRAME == rVert.GetRelationOrient())
2374         )
2375     {
2376         sal_Int16 eHOri = rHori.GetHoriOrient();
2377         switch ( eHOri )
2378         {
2379             case text::HoriOrientation::CENTER:
2380             case text::HoriOrientation::RIGHT:
2381                 break;
2382 
2383             default:
2384                 nTableOffset = rHori.GetPos();
2385                 const SvxLRSpaceItem& rLRSp = pFormat->GetLRSpace();
2386                 nTableOffset += rLRSp.GetLeft();
2387 
2388                 // convert offset to be measured from right margin in right-to-left tables
2389                 if ( nTableOffset && m_rWW8Export.TrueFrameDirection(*pFormat) == SvxFrameDirection::Horizontal_RL_TB )
2390                 {
2391                     SwTwips nLeftPageMargin, nRightPageMargin;
2392                     const SwTwips nPageSize = m_rWW8Export.CurrentPageWidth(nLeftPageMargin, nRightPageMargin);
2393                     const SwTwips nTableWidth = pFormat->GetFrameSize().GetWidth();
2394                     nTableOffset = nPageSize - nLeftPageMargin - nRightPageMargin - nTableWidth - nTableOffset;
2395                 }
2396                 break;
2397         }
2398     }
2399 
2400     m_rWW8Export.InsInt16( nTableOffset );
2401 
2402     ww8::GridColsPtr pGridCols = GetGridCols( pTableTextNodeInfoInner );
2403     for ( const auto nCol : *pGridCols )
2404      {
2405          m_rWW8Export.InsUInt16( static_cast<sal_uInt16>(nCol) + nTableOffset );
2406      }
2407 
2408      /* TCs */
2409     ww8::RowSpansPtr pRowSpans = pTableTextNodeInfoInner->getRowSpansOfRow();
2410     ww8::RowSpans::const_iterator aItRowSpans = pRowSpans->begin();
2411 
2412     for (const SwTableBox * pTabBox1 : *pTableBoxes)
2413     {
2414         sal_uInt16 npOCount = m_rWW8Export.pO->size();
2415 
2416         const SwFrameFormat * pBoxFormat = nullptr;
2417         if (pTabBox1 != nullptr)
2418             pBoxFormat = pTabBox1->GetFrameFormat();
2419 
2420         sal_uInt16 nFlags =
2421             lcl_TCFlags(*m_rWW8Export.m_pDoc, pTabBox1, *aItRowSpans);
2422         m_rWW8Export.InsUInt16( nFlags );
2423 
2424         static sal_uInt8 aNullBytes[] = { 0x0, 0x0 };
2425 
2426         m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), aNullBytes, aNullBytes+2 );   // dummy
2427         if (pBoxFormat != nullptr)
2428         {
2429             const SvxBoxItem & rBoxItem = pBoxFormat->GetBox();
2430 
2431             WW8Export::Out_SwFormatTableBox( *m_rWW8Export.pO, &rBoxItem ); // 8/16 Byte
2432         }
2433         else
2434             WW8Export::Out_SwFormatTableBox( *m_rWW8Export.pO, nullptr); // 8/16 Byte
2435 
2436         SAL_INFO( "sw.ww8.level2", "<tclength>" << ( m_rWW8Export.pO->size() - npOCount ) << "</tclength>" );
2437         ++aItRowSpans;
2438     }
2439 
2440     int nWidthPercent = pFormat->GetFrameSize().GetWidthPercent();
2441     // Width is in fiftieths of a percent. For sprmTTableWidth, must be non-negative and 600% max
2442     if ( nWidthPercent > 0 && nWidthPercent <= 600 )
2443     {
2444         m_rWW8Export.InsUInt16( NS_sprm::sprmTTableWidth );
2445         m_rWW8Export.pO->push_back( sal_uInt8/*ftsPercent*/ (2) );
2446         m_rWW8Export.InsUInt16( static_cast<sal_uInt16>(nWidthPercent) * 50 );
2447     }
2448 }
2449 
GetGridCols(ww8::WW8TableNodeInfoInner::Pointer_t const & pTableTextNodeInfoInner)2450 ww8::GridColsPtr AttributeOutputBase::GetGridCols( ww8::WW8TableNodeInfoInner::Pointer_t const & pTableTextNodeInfoInner )
2451 {
2452     return pTableTextNodeInfoInner->getGridColsOfRow(*this);
2453 }
2454 
GetColumnWidths(ww8::WW8TableNodeInfoInner::Pointer_t const & pTableTextNodeInfoInner)2455 ww8::WidthsPtr AttributeOutputBase::GetColumnWidths( ww8::WW8TableNodeInfoInner::Pointer_t const & pTableTextNodeInfoInner )
2456 {
2457     // Get the column widths based on ALL the rows, not just the current row
2458     return pTableTextNodeInfoInner->getGridColsOfRow(*this, true);
2459 }
2460 
GetTablePageSize(ww8::WW8TableNodeInfoInner const * pTableTextNodeInfoInner,long & rPageSize,bool & rRelBoxSize)2461 void AttributeOutputBase::GetTablePageSize( ww8::WW8TableNodeInfoInner const * pTableTextNodeInfoInner, long& rPageSize, bool& rRelBoxSize )
2462 {
2463     long nPageSize = 0;
2464 
2465     const SwNode *pTextNd = pTableTextNodeInfoInner->getNode( );
2466     const SwTable *pTable = pTableTextNodeInfoInner->getTable( );
2467 
2468     const SwFrameFormat *pFormat = pTable->GetFrameFormat();
2469     if ( !pFormat )
2470     {
2471         SAL_WARN( "sw.ww8", "FrameFormat is nil" );
2472         return;
2473     }
2474 
2475     const SwFormatFrameSize &rSize = pFormat->GetFrameSize();
2476     int nWidthPercent = rSize.GetWidthPercent();
2477     bool bManualAligned = pFormat->GetHoriOrient().GetHoriOrient() == text::HoriOrientation::NONE;
2478     if ( (pFormat->GetHoriOrient().GetHoriOrient() == text::HoriOrientation::FULL) || bManualAligned )
2479         nWidthPercent = 100;
2480     bool bRelBoxSize = nWidthPercent != 0;
2481     unsigned long nTableSz = static_cast<unsigned long>(rSize.GetWidth());
2482     if (nTableSz > USHRT_MAX/2 && !bRelBoxSize)
2483     {
2484         OSL_ENSURE(bRelBoxSize, "huge table width but not relative, suspicious");
2485         bRelBoxSize = true;
2486     }
2487 
2488     if ( bRelBoxSize )
2489     {
2490         Point aPt;
2491         SwRect aRect( pFormat->FindLayoutRect( false, &aPt ) );
2492         if ( aRect.IsEmpty() )
2493         {
2494             // Then fetch the page width without margins!
2495             const SwFrameFormat* pParentFormat =
2496                 GetExport().m_pParentFrame ?
2497                 &(GetExport().m_pParentFrame->GetFrameFormat()) :
2498                     GetExport().m_pDoc->GetPageDesc(0).GetPageFormatOfNode(*pTextNd, false);
2499             aRect = pParentFormat->FindLayoutRect(true);
2500             if ( 0 == ( nPageSize = aRect.Width() ) )
2501             {
2502                 const SvxLRSpaceItem& rLR = pParentFormat->GetLRSpace();
2503                 nPageSize = pParentFormat->GetFrameSize().GetWidth() - rLR.GetLeft()
2504                 - rLR.GetRight();
2505             }
2506         }
2507         else
2508         {
2509             nPageSize = aRect.Width();
2510             if ( bManualAligned )
2511             {
2512                 // #i37571# For manually aligned tables
2513                 const SvxLRSpaceItem &rLR = pFormat->GetLRSpace();
2514                 nPageSize -= (rLR.GetLeft() + rLR.GetRight());
2515             }
2516 
2517         }
2518 
2519         if ( nWidthPercent )
2520         {
2521             nPageSize *= nWidthPercent;
2522             nPageSize /= 100;
2523         }
2524         else
2525             SAL_WARN( "sw.ww8", "nWidthPercent is zero" );
2526     }
2527     else
2528     {
2529         // As the table width is not relative, the TablePageSize equals its width
2530         nPageSize = nTableSz;
2531     }
2532 
2533     rPageSize = nPageSize;
2534     rRelBoxSize = bRelBoxSize;
2535 }
2536 
TableDefaultBorders(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)2537 void WW8AttributeOutput::TableDefaultBorders( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2538 {
2539     const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
2540     const SwFrameFormat * pFrameFormat = pTabBox->GetFrameFormat();
2541 
2542     //Set Default, just taken from the first cell of the first
2543     //row
2544     static const SvxBoxItemLine aBorders[] =
2545     {
2546         SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
2547         SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT
2548     };
2549 
2550     for ( int i = 0; i < 4; ++i )
2551     {
2552         SwWW8Writer::InsUInt16( *m_rWW8Export.pO, 0xD634 );
2553         m_rWW8Export.pO->push_back( sal_uInt8(6) );
2554         m_rWW8Export.pO->push_back( sal_uInt8(0) );
2555         m_rWW8Export.pO->push_back( sal_uInt8(1) );
2556         m_rWW8Export.pO->push_back( sal_uInt8(1 << i) );
2557         m_rWW8Export.pO->push_back( sal_uInt8(3) );
2558 
2559         SwWW8Writer::InsUInt16( *m_rWW8Export.pO,
2560                 pFrameFormat->GetBox().GetDistance( aBorders[i] ) );
2561     }
2562 }
2563 
TableCellBorders(ww8::WW8TableNodeInfoInner::Pointer_t const & pTableTextNodeInfoInner)2564 void WW8AttributeOutput::TableCellBorders(
2565     ww8::WW8TableNodeInfoInner::Pointer_t const & pTableTextNodeInfoInner )
2566 {
2567     const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
2568     const SwTableLine * pTabLine = pTabBox->GetUpper();
2569     const SwTableBoxes & rTabBoxes = pTabLine->GetTabBoxes();
2570     sal_uInt8 nBoxes = std::min<size_t>(rTabBoxes.size(), 255);
2571     const SvxBoxItem * pLastBox = nullptr;
2572     sal_uInt8 nSeqStart = 0; // start of sequence of cells with same borders
2573 
2574     // Detect sequences of cells which have the same borders, and output
2575     // a border description for each such cell range.
2576     for ( unsigned n = 0; n <= nBoxes; ++n )
2577     {
2578         const SvxBoxItem * pBox = (n == nBoxes) ? nullptr :
2579             &rTabBoxes[n]->GetFrameFormat()->GetBox();
2580         if( !pLastBox )
2581             pLastBox = pBox;
2582         else if( !pBox || *pLastBox != *pBox )
2583         {
2584             // This cell has different borders than the previous cell,
2585             // so output the borders for the preceding cell range.
2586             m_rWW8Export.Out_CellRangeBorders(pLastBox, nSeqStart, n);
2587             nSeqStart = n;
2588             pLastBox = pBox;
2589         }
2590     }
2591 }
2592 
TableBackgrounds(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)2593 void WW8AttributeOutput::TableBackgrounds( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2594 {
2595     const SwTable * pTab = pTableTextNodeInfoInner->getTable();
2596     const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
2597     const SwTableLine * pTabLine = pTabBox->GetUpper();
2598     const SwTableBoxes & rTabBoxes = pTabLine->GetTabBoxes();
2599 
2600     sal_uInt8 nBoxes = rTabBoxes.size();
2601     m_rWW8Export.InsUInt16( NS_sprm::sprmTDefTableShd80 );
2602     m_rWW8Export.pO->push_back( static_cast<sal_uInt8>(nBoxes * 2) );  // Len
2603 
2604     Color aRowColor = COL_AUTO;
2605     const SvxBrushItem *pTableColorProp = pTab->GetFrameFormat()->GetAttrSet().GetItem<SvxBrushItem>(RES_BACKGROUND);
2606     if ( pTableColorProp )
2607         aRowColor = pTableColorProp->GetColor();
2608 
2609     const SvxBrushItem *pRowColorProp = pTabLine->GetFrameFormat()->GetAttrSet().GetItem<SvxBrushItem>(RES_BACKGROUND);
2610     if ( pRowColorProp && pRowColorProp->GetColor() != COL_AUTO )
2611         aRowColor = pRowColorProp->GetColor();
2612 
2613     for ( sal_uInt8 n = 0; n < nBoxes; n++ )
2614     {
2615         const SwTableBox * pBox1 = rTabBoxes[n];
2616         const SwFrameFormat * pFrameFormat = pBox1->GetFrameFormat();
2617         Color aColor = aRowColor;
2618 
2619         const SvxBrushItem *pCellColorProp = pFrameFormat->GetAttrSet().GetItem<SvxBrushItem>(RES_BACKGROUND);
2620         if ( pCellColorProp && pCellColorProp->GetColor() != COL_AUTO )
2621             aColor = pCellColorProp->GetColor();
2622 
2623         WW8_SHD aShd;
2624         WW8Export::TransBrush( aColor, aShd );
2625         m_rWW8Export.InsUInt16( aShd.GetValue() );
2626     }
2627 
2628     sal_uInt32 const aSprmIds[] { NS_sprm::sprmTDefTableShd,
2629                                   NS_sprm::sprmTDefTableShdRaw };
2630     sal_uInt8 nBoxes0 = rTabBoxes.size();
2631     if (nBoxes0 > 21)
2632         nBoxes0 = 21;
2633 
2634     for (sal_uInt32 m : aSprmIds)
2635     {
2636         m_rWW8Export.InsUInt16( m );
2637         m_rWW8Export.pO->push_back( static_cast<sal_uInt8>(nBoxes0 * 10) );
2638 
2639         for ( sal_uInt8 n = 0; n < nBoxes0; n++ )
2640         {
2641             const SwTableBox * pBox1 = rTabBoxes[n];
2642             const SwFrameFormat * pFrameFormat = pBox1->GetFrameFormat();
2643             Color aColor = aRowColor;
2644 
2645             const SvxBrushItem *pCellColorProp = pFrameFormat->GetAttrSet().GetItem<SvxBrushItem>(RES_BACKGROUND);
2646             if ( pCellColorProp && pCellColorProp->GetColor() != COL_AUTO )
2647                 aColor = pCellColorProp->GetColor();
2648 
2649             WW8SHDLong aSHD;
2650             aSHD.setCvFore( 0xFF000000 );
2651 
2652             if ( aColor == COL_AUTO )
2653                 aSHD.setCvBack( 0xFF000000 );
2654             else
2655                 aSHD.setCvBack( wwUtility::RGBToBGR( aColor ) );
2656 
2657             aSHD.Write( m_rWW8Export );
2658         }
2659     }
2660 }
2661 
SectionBreaksAndFrames(const SwTextNode & rNode)2662 void WW8Export::SectionBreaksAndFrames( const SwTextNode& rNode )
2663 {
2664     // output page/section breaks
2665     OutputSectionBreaks( rNode.GetpSwAttrSet(), rNode );
2666 }
2667 
2668 class TrackContentToExport
2669 {
2670 private:
2671     SwPaM *m_pCurPam;
2672     sal_uLong m_nStart, m_nEnd;
2673 public:
TrackContentToExport(SwPaM * pCurPam,sal_uLong nCurStart,sal_uLong nCurEnd)2674     TrackContentToExport(SwPaM *pCurPam, sal_uLong nCurStart, sal_uLong nCurEnd)
2675         : m_pCurPam(pCurPam)
2676         , m_nStart(nCurStart)
2677         , m_nEnd(nCurEnd)
2678     {
2679     }
2680 
contentRemainsToExport(ww8::WW8TableInfo * pTableInfo)2681     bool contentRemainsToExport(ww8::WW8TableInfo *pTableInfo)
2682     {
2683         bool bSimpleContentRemains = m_pCurPam->GetPoint()->nNode < m_pCurPam->GetMark()->nNode ||
2684             (m_pCurPam->GetPoint()->nNode == m_pCurPam->GetMark()->nNode &&
2685               m_pCurPam->GetPoint()->nContent.GetIndex() <= m_pCurPam->GetMark()->nContent.GetIndex());
2686         if (bSimpleContentRemains)
2687             return true;
2688 
2689         if (!pTableInfo)
2690             return false;
2691 
2692         //An old-school table where one cell may points back to a previous node as the next cell
2693         //so if this node is the last node in the range, we may need to jump back to a previously
2694         //skipped cell to output it in a sane sequence. See ooo47778-3.sxw for one of these
2695         //horrors. So if we are at the end of the selection, but this end point is a table
2696         //cell whose next cell is in the selection allow jumping back to it
2697         const SwNode* pCurrentNode = &m_pCurPam->GetPoint()->nNode.GetNode();
2698         const SwNode* pNextNode = pTableInfo->getNextNode(pCurrentNode);
2699 
2700         if (pNextNode && pCurrentNode != pNextNode)
2701         {
2702             return pNextNode->GetIndex() >= m_nStart &&
2703                    pNextNode->GetIndex() < m_nEnd;
2704         }
2705 
2706         return false;
2707     }
2708 };
2709 
WriteText()2710 void MSWordExportBase::WriteText()
2711 {
2712     TrackContentToExport aContentTracking(m_pCurPam.get(), m_nCurStart, m_nCurEnd);
2713     while (aContentTracking.contentRemainsToExport(m_pTableInfo.get()))
2714     {
2715         SwNode& rNd = m_pCurPam->GetNode();
2716 
2717         // no section breaks exported for Endnotes
2718         if ( rNd.IsTextNode() && m_nTextTyp != TXT_EDN && m_nTextTyp != TXT_FTN )
2719         {
2720             SwSoftPageBreakList breakList;
2721             // if paragraph need to be split than handle section break somewhere
2722             // else.
2723             if( !NeedTextNodeSplit( *rNd.GetTextNode(), breakList) )
2724                 SectionBreaksAndFrames( *rNd.GetTextNode() );
2725         }
2726 
2727 
2728         // output the various types of nodes
2729         if ( rNd.IsContentNode() )
2730         {
2731             SwContentNode* pCNd = static_cast<SwContentNode*>(&rNd);
2732 
2733             const SwPageDesc* pTemp = rNd.FindPageDesc();
2734             if ( pTemp )
2735                 m_pCurrentPageDesc = pTemp;
2736 
2737             m_pCurPam->GetPoint()->nContent.Assign( pCNd, 0 );
2738             OutputContentNode( *pCNd );
2739         }
2740         else if ( rNd.IsTableNode() )
2741         {
2742             m_pTableInfo->processSwTable( &rNd.GetTableNode()->GetTable() );
2743         }
2744         else if ( rNd.IsSectionNode() && TXT_MAINTEXT == m_nTextTyp )
2745             OutputSectionNode( *rNd.GetSectionNode() );
2746         else if ( TXT_MAINTEXT == m_nTextTyp && rNd.IsEndNode() &&
2747                   rNd.StartOfSectionNode()->IsSectionNode() )
2748         {
2749             const SwSection& rSect = rNd.StartOfSectionNode()->GetSectionNode()
2750                                         ->GetSection();
2751             if ( m_bStartTOX && TOX_CONTENT_SECTION == rSect.GetType() )
2752                 m_bStartTOX = false;
2753 
2754             SwNodeIndex aIdx( rNd, 1 );
2755             if ( aIdx.GetNode().IsEndNode() && aIdx.GetNode().StartOfSectionNode()->IsSectionNode() )
2756                 ;
2757             else if ( aIdx.GetNode().IsSectionNode() )
2758                 ;
2759             else if ( !IsInTable() )    //No sections in table
2760             {
2761                 //#120140# Do not need to insert a page/section break after a section end. Check this case first
2762                 bool bNeedExportBreakHere = true;
2763                 if ( rSect.GetType() == TOX_CONTENT_SECTION || rSect.GetType() == TOX_HEADER_SECTION )
2764                     bNeedExportBreakHere = false;
2765                 else if ( aIdx.GetNode().IsTextNode() )
2766                 {
2767                     SwTextNode *pTempNext = aIdx.GetNode().GetTextNode();
2768                     if ( pTempNext )
2769                     {
2770                         const SfxPoolItem * pTempItem = nullptr;
2771                         if (pTempNext->GetpSwAttrSet() && SfxItemState::SET == pTempNext->GetpSwAttrSet()->GetItemState(RES_PAGEDESC, false, &pTempItem)
2772                             && pTempItem && static_cast<const SwFormatPageDesc*>(pTempItem)->GetRegisteredIn())
2773                         {
2774                             //Next node has a new page style which means this node is a section end. Do not insert another page/section break here
2775                             bNeedExportBreakHere = false;
2776                         }
2777                     }
2778                 }
2779                 else
2780                 {
2781                     /* Do not export Section Break in case DOCX containing MultiColumn and
2782                      * aIdx.GetNode().IsTextNode() is False i.e. Text node is NULL.
2783                      */
2784                     const SwFrameFormat* pPgFormat = rSect.GetFormat();
2785                     const SwFormatCol& rCol = pPgFormat->GetCol();
2786                     sal_uInt16 nColumnCount = rCol.GetNumCols();
2787                     const SwFormatNoBalancedColumns& rNoBalanced = pPgFormat->GetBalancedColumns();
2788                     // Prevent the additional section break only for non-balanced columns.
2789                     if (nColumnCount > 1 && rNoBalanced.GetValue())
2790                     {
2791                         bNeedExportBreakHere = false;
2792                     }
2793                     // No need to create a "fake" section if this is the end of the document,
2794                     // except to emulate balanced columns.
2795                     else if ( nColumnCount < 2 && aIdx == m_pDoc->GetNodes().GetEndOfContent() )
2796                         bNeedExportBreakHere = false;
2797                 }
2798 
2799                 if (bNeedExportBreakHere)  //#120140# End of check
2800                 {
2801                     ReplaceCr( char(0xc) ); // indicator for Page/Section-Break
2802 
2803                     const SwSectionFormat* pParentFormat = rSect.GetFormat()->GetParent();
2804                     if ( !pParentFormat )
2805                         pParentFormat = reinterpret_cast<SwSectionFormat*>(sal_IntPtr(-1));
2806 
2807                     sal_uLong nRstLnNum;
2808                     if ( aIdx.GetNode().IsContentNode() )
2809                         nRstLnNum = static_cast<SwContentNode&>(aIdx.GetNode()).GetSwAttrSet().
2810                                                 GetLineNumber().GetStartValue();
2811                     else
2812                         nRstLnNum = 0;
2813 
2814                     AppendSection( m_pCurrentPageDesc, pParentFormat, nRstLnNum );
2815                 }
2816                 else
2817                 {
2818                     OutputEndNode( *rNd.GetEndNode() );
2819                 }
2820             }
2821         }
2822         else if ( rNd.IsStartNode() )
2823         {
2824             OutputStartNode( *rNd.GetStartNode() );
2825         }
2826         else if ( rNd.IsEndNode() )
2827         {
2828             OutputEndNode( *rNd.GetEndNode() );
2829         }
2830 
2831         if ( &rNd == &rNd.GetNodes().GetEndOfContent() )
2832             break;
2833 
2834         const SwNode * pCurrentNode = &m_pCurPam->GetPoint()->nNode.GetNode();
2835         const SwNode * pNextNode = m_pTableInfo->getNextNode(pCurrentNode);
2836 
2837         if (pCurrentNode == pNextNode)
2838         {
2839             SAL_WARN("sw.ww8", "loop in TableInfo");
2840             pNextNode = nullptr;
2841         }
2842 
2843         if (pNextNode != nullptr)
2844             m_pCurPam->GetPoint()->nNode.Assign(*pNextNode);
2845         else
2846             ++m_pCurPam->GetPoint()->nNode;
2847 
2848         sal_uLong nPos = m_pCurPam->GetPoint()->nNode.GetIndex();
2849         ::SetProgressState( nPos, m_pCurPam->GetDoc()->GetDocShell() );
2850     }
2851 
2852     SAL_INFO( "sw.ww8.level2", "</WriteText>" );
2853 }
2854 
WriteMainText()2855 void WW8Export::WriteMainText()
2856 {
2857     SAL_INFO( "sw.ww8.level2", "<WriteMainText>" );
2858 
2859     pFib->m_fcMin = Strm().Tell();
2860 
2861     m_pCurPam->GetPoint()->nNode = m_pDoc->GetNodes().GetEndOfContent().StartOfSectionNode()->GetIndex();
2862 
2863     WriteText();
2864 
2865     if( 0 == Strm().Tell() - pFib->m_fcMin )  // no text ?
2866         WriteCR();                  // then CR at the end ( otherwise WW will complain )
2867 
2868     pFib->m_ccpText = Fc2Cp( Strm().Tell() );
2869     m_pFieldMain->Finish( pFib->m_ccpText, 0 );
2870 
2871                     // ccpText includes Footnote and KF-text
2872                     // therefore pFib->ccpText may get updated as well
2873     // save the StyleId of the last paragraph. Because WW97 take the style
2874     // from the last CR, that will be written after footer/Header/footnotes/
2875     // annotation etc.
2876     const SwTextNode* pLastNd = m_pCurPam->GetMark()->nNode.GetNode().GetTextNode();
2877     if( pLastNd )
2878         m_nLastFormatId = GetId( static_cast<SwTextFormatColl&>(pLastNd->GetAnyFormatColl()) );
2879 
2880     SAL_INFO( "sw.ww8.level2", "</WriteMainText>" );
2881 }
2882 
IsInTable() const2883 bool MSWordExportBase::IsInTable() const
2884 {
2885     bool bResult = false;
2886 
2887     if (m_pCurPam != nullptr)
2888     {
2889         SwNode& rNode = m_pCurPam->GetNode();
2890 
2891         if (m_pTableInfo.get() != nullptr)
2892         {
2893             ww8::WW8TableNodeInfo::Pointer_t pTableNodeInfo = m_pTableInfo->getTableNodeInfo(&rNode);
2894 
2895             if (pTableNodeInfo.get() != nullptr && pTableNodeInfo->getDepth() > 0)
2896             {
2897                 bResult = true;
2898             }
2899         }
2900     }
2901 
2902     return bResult;
2903 }
2904 
2905 typedef ww8::WW8Sttb< ww8::WW8Struct >  WW8SttbAssoc;
2906 
WriteFkpPlcUsw()2907 void WW8Export::WriteFkpPlcUsw()
2908 {
2909     // Graphics in the data stream
2910     m_pGrf->Write();                          // Graphics
2911 
2912     // output into WordDocument stream
2913     m_pChpPlc->WriteFkps();                   // Fkp.Chpx
2914     m_pPapPlc->WriteFkps();                   // Fkp.Papx
2915     pSepx->WriteSepx( Strm() );             // Sepx
2916 
2917     // output into Table stream
2918     m_pStyles->OutputStylesTable();           // for WW8 StyleTab
2919     pFootnote->WritePlc( *this );                // Footnote-Ref & Text Plc
2920     pEdn->WritePlc( *this );                // Endnote-Ref & Text Plc
2921     m_pTextBxs->WritePlc( *this );             // Textbox Text Plc
2922     m_pHFTextBxs->WritePlc( *this );           // Head/Foot-Textbox Text Plc
2923     m_pAtn->WritePlc( *this );                // Annotation-Ref & Text Plc
2924 
2925     pSepx->WritePlcSed( *this );            // Slcx.PlcSed
2926     pSepx->WritePlcHdd( *this );            // Slcx.PlcHdd
2927 
2928     m_pChpPlc->WritePlc();                    // Plcx.Chpx
2929     m_pPapPlc->WritePlc();                    // Plcx.Papx
2930 
2931     if( m_pRedlAuthors )
2932         m_pRedlAuthors->Write( GetWriter() );       // sttbfRMark (RedlineAuthors)
2933     m_pFieldMain->Write( *this );               // Fields ( Main Text )
2934     m_pFieldHdFt->Write( *this );               // Fields ( Header/Footer )
2935     m_pFieldFootnote->Write( *this );                // Fields ( FootNotes )
2936     m_pFieldEdn->Write( *this );                // Fields ( EndNotes )
2937     m_pFieldAtn->Write( *this );                // Fields ( Annotations )
2938     m_pFieldTextBxs->Write( *this );             // Fields ( Textboxes )
2939     m_pFieldHFTextBxs->Write( *this );           // Fields ( Head/Foot-Textboxes )
2940 
2941     if (m_pEscher || m_pDoc->ContainsMSVBasic())
2942     {
2943         /*
2944          Every time MS 2000 creates an escher stream there is always
2945          an ObjectPool dir (even if empty). It turns out that if a copy of
2946          MS 2000 is used to open a document that contains escher graphics
2947          exported from StarOffice without this empty dir then *if* that
2948          copy of MS Office has never been used to open a MSOffice document
2949          that has escher graphics (and an ObjectPool dir of course) and
2950          that copy of office has not been used to draw escher graphics then
2951          our exported graphics do not appear. Once you do open a ms
2952          document with escher graphics or draw an escher graphic with that
2953          copy of word, then all documents from staroffice that contain
2954          escher work from then on. Tricky to track down, some sort of late
2955          binding trickery in MS where solely for first time initialization
2956          the existence of an ObjectPool dir is necessary for triggering
2957          some magic.
2958         */
2959         // avoid memory leak #i120098#, the unnamed obj will be released in destructor.
2960         xEscherStg = GetWriter().GetStorage().OpenSotStorage(SL::aObjectPool);
2961     }
2962 
2963     // dggInfo - escher stream
2964     WriteEscher();
2965 
2966     m_pSdrObjs->WritePlc( *this );
2967     m_pHFSdrObjs->WritePlc( *this );
2968     // spamom - office drawing table
2969     // spahdr - header office drawing table
2970 
2971     m_pBkmks->Write( *this );                 // Bookmarks - sttbfBkmk/
2972                                             // plcfBkmkf/plcfBkmkl
2973     m_pFactoids->Write(*this);
2974 
2975     WriteNumbering();
2976 
2977     RestoreMacroCmds();
2978 
2979     m_pMagicTable->Write( *this );
2980 
2981     m_pPiece->WritePc( *this );               // Piece-Table
2982     m_aFontHelper.WriteFontTable(pTableStrm, *pFib); // FFNs
2983 
2984     //Convert OOo asian typography into MS typography structure
2985     ExportDopTypography(pDop->doptypography);
2986 
2987     WriteDop( *this );                      // Document-Properties
2988 
2989     // Write SttbfAssoc
2990     WW8SttbAssoc * pSttbfAssoc = dynamic_cast<WW8SttbAssoc *>
2991         (m_pDoc->getIDocumentExternalData().getExternalData(::sw::tExternalDataType::STTBF_ASSOC).get());
2992 
2993     if ( pSttbfAssoc )                      // #i106057#
2994     {
2995         std::vector<OUString> aStrings(pSttbfAssoc->getStrings());
2996         WriteAsStringTable(aStrings, pFib->m_fcSttbfAssoc,
2997                            pFib->m_lcbSttbfAssoc);
2998     }
2999 
3000     Strm().Seek( 0 );
3001 
3002     // Reclaim stored FIB data from document.
3003     ::ww8::WW8FibData * pFibData = dynamic_cast<ww8::WW8FibData *>
3004           (m_pDoc->getIDocumentExternalData().getExternalData(::sw::tExternalDataType::FIB).get());
3005 
3006     if ( pFibData )
3007     {
3008     pFib->m_fReadOnlyRecommended =
3009         pFibData->getReadOnlyRecommended();
3010     pFib->m_fWriteReservation =
3011         pFibData->getWriteReservation();
3012     }
3013 
3014     pFib->Write( Strm() );  // FIB
3015 }
3016 
StoreDoc1()3017 void WW8Export::StoreDoc1()
3018 {
3019     bool bNeedsFinalPara = false;
3020     // Start of Text ( overwrite )
3021     SwWW8Writer::FillUntil( Strm(), pFib->m_fcMin );
3022 
3023     WriteMainText();                    // main text
3024     sal_uInt8 nSprmsLen;
3025     sal_uInt8 *pLastSprms = m_pPapPlc->CopyLastSprms(nSprmsLen);
3026 
3027     bNeedsFinalPara |= pFootnote->WriteText( *this );         // Footnote-Text
3028     bNeedsFinalPara |= pSepx->WriteKFText( *this );          // K/F-Text
3029     bNeedsFinalPara |= m_pAtn->WriteText( *this );         // Annotation-Text
3030     bNeedsFinalPara |= pEdn->WriteText( *this );         // EndNote-Text
3031 
3032     // create the escher streams
3033     CreateEscher();
3034 
3035     bNeedsFinalPara |= m_pTextBxs->WriteText( *this );  //Textbox Text Plc
3036     bNeedsFinalPara |= m_pHFTextBxs->WriteText( *this );//Head/Foot-Textbox Text Plc
3037 
3038     if (bNeedsFinalPara)
3039     {
3040         WriteCR();
3041         m_pPapPlc->AppendFkpEntry(Strm().Tell(), nSprmsLen, pLastSprms);
3042     }
3043     delete[] pLastSprms;
3044 
3045     pSepx->Finish( Fc2Cp( Strm().Tell() ));// Text + Footnote + HdFt as section end
3046     m_pMagicTable->Finish( Fc2Cp( Strm().Tell() ),0);
3047 
3048     pFib->m_fcMac = Strm().Tell();        // End of all texts
3049 
3050     WriteFkpPlcUsw();                   // FKP, PLC, ...
3051 }
3052 
AddLinkTarget(const OUString & rURL)3053 void MSWordExportBase::AddLinkTarget(const OUString& rURL)
3054 {
3055     if( rURL.isEmpty() || rURL[0] != '#' )
3056         return;
3057 
3058     OUString aURL( BookmarkToWriter( rURL.copy( 1 ) ) );
3059     sal_Int32 nPos = aURL.lastIndexOf( cMarkSeparator );
3060 
3061     if( nPos < 2 )
3062         return;
3063 
3064     OUString sCmp = aURL.copy(nPos+1).replaceAll(" ", "");
3065     if( sCmp.isEmpty() )
3066         return;
3067 
3068     sCmp = sCmp.toAsciiLowerCase();
3069     sal_uLong nIdx = 0;
3070     bool noBookmark = false;
3071 
3072     if( sCmp == "outline" )
3073     {
3074         SwPosition aPos(*m_pCurPam->GetPoint());
3075         OUString aName(BookmarkToWriter(aURL.copy(0, nPos)));
3076         // If we can find the outline this bookmark refers to
3077         // save the name of the bookmark and the
3078         // node index number of where it points to
3079         if( m_pDoc->GotoOutline( aPos, aName ) )
3080         {
3081             nIdx = aPos.nNode.GetIndex();
3082             noBookmark = true;
3083         }
3084     }
3085     else if( sCmp == "graphic" )
3086     {
3087         SwNodeIndex* pIdx;
3088         OUString aName(BookmarkToWriter(aURL.copy(0, nPos)));
3089         const SwFlyFrameFormat* pFormat = m_pDoc->FindFlyByName(aName, SwNodeType::Grf);
3090         if (pFormat && nullptr != (pIdx = const_cast<SwNodeIndex*>(pFormat->GetContent().GetContentIdx())))
3091         {
3092             nIdx = pIdx->GetNext()->GetIndex();
3093             noBookmark = true;
3094         }
3095     }
3096     else if( sCmp == "frame" )
3097     {
3098         SwNodeIndex* pIdx;
3099         OUString aName(BookmarkToWriter(aURL.copy(0, nPos)));
3100         const SwFlyFrameFormat* pFormat = m_pDoc->FindFlyByName(aName, SwNodeType::Text);
3101         if (pFormat && nullptr != (pIdx = const_cast<SwNodeIndex*>(pFormat->GetContent().GetContentIdx())))
3102         {
3103             nIdx = pIdx->GetIndex() + 1;
3104             noBookmark = true;
3105         }
3106     }
3107     else if( sCmp == "ole" )
3108     {
3109         SwNodeIndex* pIdx;
3110         OUString aName(BookmarkToWriter(aURL.copy(0, nPos)));
3111         const SwFlyFrameFormat* pFormat = m_pDoc->FindFlyByName(aName, SwNodeType::Ole);
3112         if (pFormat && nullptr != (pIdx = const_cast<SwNodeIndex*>(pFormat->GetContent().GetContentIdx())))
3113         {
3114             nIdx = pIdx->GetNext()->GetIndex();
3115             noBookmark = true;
3116         }
3117     }
3118     else if( sCmp == "region" )
3119     {
3120         SwNodeIndex* pIdx;
3121         OUString aName(BookmarkToWriter(aURL.copy(0, nPos)));
3122         for (const SwSectionFormat* pFormat : m_pDoc->GetSections())
3123         {
3124             if (aName == pFormat->GetSection()->GetSectionName()
3125                 && nullptr != (pIdx = const_cast<SwNodeIndex*>(pFormat->GetContent().GetContentIdx())))
3126             {
3127                 nIdx = pIdx->GetIndex() + 1;
3128                 noBookmark = true;
3129                 break;
3130             }
3131         }
3132     }
3133     else if( sCmp == "table" )
3134     {
3135         OUString aName(BookmarkToWriter(aURL.copy(0, nPos)));
3136         const SwTable* pTable = SwTable::FindTable(m_pDoc->FindTableFormatByName(aName));
3137         if (pTable)
3138         {
3139             SwTableNode* pTableNode = const_cast<SwTableNode*>(pTable->GetTabSortBoxes()[1]->GetSttNd()->FindTableNode());
3140             if (pTableNode)
3141             {
3142                 nIdx = pTableNode->GetIndex() + 2;
3143                 noBookmark = true;
3144             }
3145         }
3146     }
3147     if (noBookmark)
3148     {
3149         aBookmarkPair aImplicitBookmark;
3150         aImplicitBookmark.first = aURL;
3151         aImplicitBookmark.second = nIdx;
3152         m_aImplicitBookmarks.push_back(aImplicitBookmark);
3153     }
3154 }
3155 
CollectOutlineBookmarks(const SwDoc & rDoc)3156 void MSWordExportBase::CollectOutlineBookmarks(const SwDoc &rDoc)
3157 {
3158     for (const SfxPoolItem* pItem : rDoc.GetAttrPool().GetItemSurrogates(RES_TXTATR_INETFMT))
3159     {
3160         auto pINetFormat = dynamic_cast<const SwFormatINetFormat*>(pItem);
3161         if (!pINetFormat)
3162             continue;
3163 
3164         const SwTextINetFormat* pTextAttr = pINetFormat->GetTextINetFormat();
3165         if (!pTextAttr)
3166             continue;
3167 
3168         const SwTextNode* pTextNd = pTextAttr->GetpTextNode();
3169         if (!pTextNd)
3170             continue;
3171 
3172         if (!pTextNd->GetNodes().IsDocNodes())
3173             continue;
3174 
3175         AddLinkTarget( pINetFormat->GetValue() );
3176     }
3177 
3178     for (const SfxPoolItem* pItem : rDoc.GetAttrPool().GetItemSurrogates(RES_URL))
3179     {
3180         auto pURL = dynamic_cast<const SwFormatURL*>(pItem);
3181         if (!pURL)
3182             continue;
3183 
3184         AddLinkTarget(pURL->GetURL());
3185         const ImageMap *pIMap = pURL->GetMap();
3186         if (!pIMap)
3187             continue;
3188 
3189         for (size_t i=0; i < pIMap->GetIMapObjectCount(); ++i)
3190         {
3191             const IMapObject* pObj = pIMap->GetIMapObject(i);
3192             if (!pObj)
3193                 continue;
3194             AddLinkTarget( pObj->GetURL() );
3195         }
3196     }
3197 }
3198 
3199 namespace
3200 {
3201     const sal_uLong WW_BLOCKSIZE = 0x200;
3202 
EncryptRC4(msfilter::MSCodec_Std97 & rCtx,SvStream & rIn,SvStream & rOut)3203     ErrCode EncryptRC4(msfilter::MSCodec_Std97& rCtx, SvStream &rIn, SvStream &rOut)
3204     {
3205         sal_uLong nLen = rIn.TellEnd();
3206         rIn.Seek(0);
3207 
3208         sal_uInt8 in[WW_BLOCKSIZE];
3209         for (std::size_t nI = 0, nBlock = 0; nI < nLen; nI += WW_BLOCKSIZE, ++nBlock)
3210         {
3211             std::size_t nBS = std::min(nLen - nI, WW_BLOCKSIZE);
3212             nBS = rIn.ReadBytes(in, nBS);
3213             if (!rCtx.InitCipher(nBlock)) {
3214                 return ERRCODE_IO_NOTSUPPORTED;
3215             }
3216             rCtx.Encode(in, nBS, in, nBS);
3217             rOut.WriteBytes(in, nBS);
3218         }
3219         return ERRCODE_NONE;
3220     }
3221 }
3222 
ExportDocument(bool bWriteAll)3223 ErrCode MSWordExportBase::ExportDocument( bool bWriteAll )
3224 {
3225     m_nCharFormatStart = DEFAULT_STYLES_COUNT;
3226     m_nFormatCollStart = m_nCharFormatStart + m_pDoc->GetCharFormats()->size() - 1;
3227 
3228     m_bStyDef = m_bBreakBefore = m_bOutKF =
3229         m_bOutFlyFrameAttrs = m_bOutPageDescs = m_bOutTable = m_bOutFirstPage =
3230         m_bOutGrf = m_bInWriteEscher = m_bStartTOX =
3231         m_bInWriteTOX = false;
3232 
3233     m_bFootnoteAtTextEnd = m_bEndAtTextEnd = true;
3234 
3235     m_pParentFrame = nullptr;
3236     m_pFlyOffset = nullptr;
3237     m_eNewAnchorType = RndStdIds::FLY_AT_PAGE;
3238     m_nTextTyp = TXT_MAINTEXT;
3239     m_nStyleBeforeFly = m_nLastFormatId = 0;
3240     m_pStyAttr = nullptr;
3241     m_pCurrentStyle = nullptr;
3242     m_pOutFormatNode = nullptr;
3243     m_pEscher = nullptr;
3244     m_pRedlAuthors = nullptr;
3245     m_aTOXArr.clear();
3246 
3247     if ( !m_pOLEExp )
3248     {
3249         sal_uInt32 nSvxMSDffOLEConvFlags = 0;
3250         const SvtFilterOptions& rOpt = SvtFilterOptions::Get();
3251         if ( rOpt.IsMath2MathType() )
3252             nSvxMSDffOLEConvFlags |= OLE_STARMATH_2_MATHTYPE;
3253         if ( rOpt.IsWriter2WinWord() )
3254             nSvxMSDffOLEConvFlags |= OLE_STARWRITER_2_WINWORD;
3255         if ( rOpt.IsCalc2Excel() )
3256             nSvxMSDffOLEConvFlags |= OLE_STARCALC_2_EXCEL;
3257         if ( rOpt.IsImpress2PowerPoint() )
3258             nSvxMSDffOLEConvFlags |= OLE_STARIMPRESS_2_POWERPOINT;
3259 
3260         m_pOLEExp.reset(new SvxMSExportOLEObjects( nSvxMSDffOLEConvFlags ));
3261     }
3262 
3263     if ( !m_pOCXExp && m_pDoc->GetDocShell() )
3264         m_pOCXExp.reset(new SwMSConvertControls(m_pDoc->GetDocShell(), m_pCurPam.get()));
3265 
3266     // #i81405# - Collect anchored objects before changing the redline mode.
3267     m_aFrames = GetFrames( *m_pDoc, bWriteAll? nullptr : m_pOrigPam );
3268 
3269     m_nOrigRedlineFlags = m_pDoc->getIDocumentRedlineAccess().GetRedlineFlags();
3270 
3271     SwRootFrame const*const pLayout(m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout());
3272     m_bOrigShowChanges = pLayout == nullptr || !pLayout->IsHideRedlines();
3273 
3274     if ( !m_pDoc->getIDocumentRedlineAccess().GetRedlineTable().empty() )
3275     {
3276         //restored to original state by SwWriter::Write
3277         m_pDoc->getIDocumentRedlineAccess().SetRedlineFlags(m_nOrigRedlineFlags |
3278                                                          RedlineFlags::ShowDelete |
3279                                                          RedlineFlags::ShowInsert);
3280     }
3281 
3282     // fix the SwPositions in m_aFrames after SetRedlineFlags
3283     UpdateFramePositions(m_aFrames);
3284 
3285     m_aFontHelper.InitFontTable(*m_pDoc);
3286     GatherChapterFields();
3287 
3288     CollectOutlineBookmarks(*m_pDoc);
3289 
3290     // make unique OrdNums (Z-Order) for all drawing-/fly Objects
3291     if ( m_pDoc->getIDocumentDrawModelAccess().GetDrawModel() )
3292         m_pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage( 0 )->RecalcObjOrdNums();
3293 
3294     ErrCode err = ExportDocument_Impl();
3295 
3296     m_aFrames.clear();
3297 
3298     // park m_pCurPam in a "safe place" now that document is fully exported
3299     // before toggling redline mode to avoid ~SwIndexReg assert e.g. export
3300     // ooo103014-1.odt to .doc
3301     // park m_pOrigPam as well, as needed for exporting abi9915-1.odt to doc
3302     m_pOrigPam->DeleteMark();
3303     *m_pOrigPam->GetPoint() = SwPosition(m_pDoc->GetNodes().GetEndOfContent());
3304     static_cast<SwPaM&>(*m_pCurPam) = *m_pOrigPam;
3305 
3306     m_pDoc->getIDocumentRedlineAccess().SetRedlineFlags(m_nOrigRedlineFlags);
3307 
3308     return err;
3309 }
3310 
InitStd97CodecUpdateMedium(::msfilter::MSCodec_Std97 & rCodec)3311 bool SwWW8Writer::InitStd97CodecUpdateMedium( ::msfilter::MSCodec_Std97& rCodec )
3312 {
3313     uno::Sequence< beans::NamedValue > aEncryptionData;
3314 
3315     if ( mpMedium )
3316     {
3317         const SfxUnoAnyItem* pEncryptionDataItem = SfxItemSet::GetItem<SfxUnoAnyItem>(mpMedium->GetItemSet(), SID_ENCRYPTIONDATA, false);
3318         if ( pEncryptionDataItem && ( pEncryptionDataItem->GetValue() >>= aEncryptionData ) && !rCodec.InitCodec( aEncryptionData ) )
3319         {
3320             OSL_ENSURE( false, "Unexpected EncryptionData!" );
3321             aEncryptionData.realloc( 0 );
3322         }
3323 
3324         if ( !aEncryptionData.hasElements() )
3325         {
3326             // try to generate the encryption data based on password
3327             const SfxStringItem* pPasswordItem = SfxItemSet::GetItem<SfxStringItem>(mpMedium->GetItemSet(), SID_PASSWORD, false);
3328             if ( pPasswordItem && !pPasswordItem->GetValue().isEmpty() && pPasswordItem->GetValue().getLength() <= 15 )
3329             {
3330                 // Generate random number with a seed of time as salt.
3331                 rtlRandomPool aRandomPool = rtl_random_createPool ();
3332                 sal_uInt8 pDocId[ 16 ];
3333                 rtl_random_getBytes( aRandomPool, pDocId, 16 );
3334 
3335                 rtl_random_destroyPool( aRandomPool );
3336 
3337                 sal_uInt16 aPassword[16] = {};
3338 
3339                 const OUString& sPassword(pPasswordItem->GetValue());
3340                 for ( sal_Int32 nChar = 0; nChar < sPassword.getLength(); ++nChar )
3341                     aPassword[nChar] = sPassword[nChar];
3342 
3343                 rCodec.InitKey( aPassword, pDocId );
3344                 aEncryptionData = rCodec.GetEncryptionData();
3345 
3346                 mpMedium->GetItemSet()->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aEncryptionData ) ) );
3347             }
3348         }
3349 
3350         if ( aEncryptionData.hasElements() )
3351             mpMedium->GetItemSet()->ClearItem( SID_PASSWORD );
3352     }
3353 
3354     // nonempty encryption data means here that the codec was successfully initialized
3355     return aEncryptionData.hasElements();
3356 }
3357 
ExportDocument_Impl()3358 ErrCode WW8Export::ExportDocument_Impl()
3359 {
3360     PrepareStorage();
3361 
3362     pFib.reset(new WW8Fib(8, m_bDot));
3363 
3364     tools::SvRef<SotStorageStream> xWwStrm( GetWriter().GetStorage().OpenSotStream( m_aMainStg ) );
3365     tools::SvRef<SotStorageStream> xTableStrm( xWwStrm ), xDataStrm( xWwStrm );
3366     xWwStrm->SetBufferSize( 32768 );
3367 
3368     pFib->m_fWhichTableStm = true;
3369     xTableStrm = GetWriter().GetStorage().OpenSotStream(SL::a1Table, StreamMode::STD_WRITE);
3370     xDataStrm = GetWriter().GetStorage().OpenSotStream(SL::aData, StreamMode::STD_WRITE);
3371 
3372     xDataStrm->SetBufferSize( 32768 );  // for graphics
3373     xTableStrm->SetBufferSize( 16384 ); // for the Font-/Style-Table, etc.
3374 
3375     xTableStrm->SetEndian( SvStreamEndian::LITTLE );
3376     xDataStrm->SetEndian( SvStreamEndian::LITTLE );
3377 
3378     GetWriter().SetStream( xWwStrm.get() );
3379     pTableStrm = xTableStrm.get();
3380     pDataStrm = xDataStrm.get();
3381 
3382     Strm().SetEndian( SvStreamEndian::LITTLE );
3383 
3384     utl::TempFile aTempMain;
3385     aTempMain.EnableKillingFile();
3386     utl::TempFile aTempTable;
3387     aTempTable.EnableKillingFile();
3388     utl::TempFile aTempData;
3389     aTempData.EnableKillingFile();
3390 
3391     msfilter::MSCodec_Std97 aCtx;
3392     bool bEncrypt = GetWriter().InitStd97CodecUpdateMedium(aCtx);
3393     if ( bEncrypt )
3394     {
3395         GetWriter().SetStream(
3396             aTempMain.GetStream( StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE ) );
3397 
3398         pTableStrm = aTempTable.GetStream( StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE );
3399 
3400         pDataStrm = aTempData.GetStream( StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE );
3401 
3402         sal_uInt8 const aRC4EncryptionHeader[ 52 ] = {0};
3403         pTableStrm->WriteBytes(aRC4EncryptionHeader, 52);
3404     }
3405 
3406     // Default: "Standard"
3407     pSepx.reset(new WW8_WrPlcSepx( *this ));                         // Sections/headers/footers
3408 
3409     pFootnote.reset(new WW8_WrPlcFootnoteEdn( TXT_FTN ));                      // Footnotes
3410     pEdn.reset(new WW8_WrPlcFootnoteEdn( TXT_EDN ));                      // Endnotes
3411     m_pAtn = new WW8_WrPlcAnnotations;                                 // PostIts
3412     m_pFactoids.reset(new WW8_WrtFactoids); // Smart tags.
3413     m_pTextBxs = new WW8_WrPlcTextBoxes( TXT_TXTBOX );
3414     m_pHFTextBxs = new WW8_WrPlcTextBoxes( TXT_HFTXTBOX );
3415 
3416     m_pSdrObjs = new MainTextPlcDrawObj;   // Draw-/Fly-Objects for main text
3417     m_pHFSdrObjs = new HdFtPlcDrawObj;    // Draw-/Fly-Objects for header/footer
3418 
3419     m_pBkmks = new WW8_WrtBookmarks;                          // Bookmarks
3420     GetWriter().CreateBookmarkTable();
3421 
3422     m_pPapPlc.reset(new WW8_WrPlcPn( *this, PAP, pFib->m_fcMin ));
3423     m_pChpPlc.reset(new WW8_WrPlcPn( *this, CHP, pFib->m_fcMin ));
3424     pO.reset(new ww::bytes);
3425     m_pStyles.reset(new MSWordStyles( *this ));
3426     m_pFieldMain.reset(new WW8_WrPlcField( 2, TXT_MAINTEXT ));
3427     m_pFieldHdFt.reset(new WW8_WrPlcField( 2, TXT_HDFT ));
3428     m_pFieldFootnote.reset(new WW8_WrPlcField( 2, TXT_FTN ));
3429     m_pFieldEdn.reset(new WW8_WrPlcField( 2, TXT_EDN ));
3430     m_pFieldAtn.reset(new WW8_WrPlcField( 2, TXT_ATN ));
3431     m_pFieldTextBxs.reset(new WW8_WrPlcField( 2, TXT_TXTBOX ));
3432     m_pFieldHFTextBxs.reset(new WW8_WrPlcField( 2, TXT_HFTXTBOX ));
3433 
3434     m_pMagicTable.reset(new WW8_WrMagicTable);
3435 
3436     m_pGrf.reset(new SwWW8WrGrf( *this ));
3437     m_pPiece = new WW8_WrPct( pFib->m_fcMin );
3438     pDop.reset(new WW8Dop);
3439 
3440     pDop->fRevMarking = bool( RedlineFlags::On & m_nOrigRedlineFlags );
3441     SwRootFrame const*const pLayout(m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout());
3442     pDop->fRMView = pLayout == nullptr || !pLayout->IsHideRedlines();
3443     pDop->fRMPrint = pDop->fRMView;
3444 
3445     // set AutoHyphenation flag if found in default para style
3446     const SfxPoolItem* pItem;
3447     SwTextFormatColl* pStdTextFormatColl =
3448         m_pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD, false);
3449     if (pStdTextFormatColl && SfxItemState::SET == pStdTextFormatColl->GetItemState(
3450         RES_PARATR_HYPHENZONE, false, &pItem))
3451     {
3452         pDop->fAutoHyphen = static_cast<const SvxHyphenZoneItem*>(pItem)->IsHyphen();
3453     }
3454 
3455     StoreDoc1();
3456 
3457     ErrCode err = ERRCODE_NONE;
3458     if ( bEncrypt )
3459     {
3460         SvStream *pStrmTemp, *pTableStrmTemp, *pDataStrmTemp;
3461         pStrmTemp = xWwStrm.get();
3462         pTableStrmTemp = xTableStrm.get();
3463         pDataStrmTemp = xDataStrm.get();
3464 
3465         if ( pDataStrmTemp && pDataStrmTemp != pStrmTemp) {
3466             err = EncryptRC4(aCtx, *pDataStrm, *pDataStrmTemp);
3467             if (err != ERRCODE_NONE) {
3468                 goto done;
3469             }
3470         }
3471 
3472         err = EncryptRC4(aCtx, *pTableStrm, *pTableStrmTemp);
3473         if (err != ERRCODE_NONE) {
3474             goto done;
3475         }
3476 
3477         // Write Unencrypted Header 52 bytes to the start of the table stream
3478         // EncryptionVersionInfo (4 bytes): A Version structure where Version.vMajor MUST be 0x0001, and Version.vMinor MUST be 0x0001.
3479         pTableStrmTemp->Seek( 0 );
3480         pTableStrmTemp->WriteUInt32( 0x10001 ); // nEncType
3481 
3482         sal_uInt8 pDocId[16];
3483         aCtx.GetDocId( pDocId );
3484 
3485         sal_uInt8 pSaltData[16];
3486         sal_uInt8 pSaltDigest[16];
3487         aCtx.GetEncryptKey( pDocId, pSaltData, pSaltDigest );
3488 
3489         pTableStrmTemp->WriteBytes(pDocId, 16);
3490         pTableStrmTemp->WriteBytes(pSaltData, 16);
3491         pTableStrmTemp->WriteBytes(pSaltDigest, 16);
3492 
3493         err = EncryptRC4(aCtx, GetWriter().Strm(), *pStrmTemp);
3494         if (err != ERRCODE_NONE) {
3495             goto done;
3496         }
3497 
3498         // Write Unencrypted Fib 68 bytes to the start of the workdocument stream
3499         pFib->m_fEncrypted = true; // fEncrypted indicates the document is encrypted.
3500         pFib->m_fObfuscated = false; // Must be 0 for RC4.
3501         pFib->m_nHash = 0x34; // encrypt header bytes count of table stream.
3502         pFib->m_nKey = 0; // lkey2 must be 0 for RC4.
3503 
3504         pStrmTemp->Seek( 0 );
3505         pFib->WriteHeader( *pStrmTemp );
3506     done:;
3507     }
3508 
3509     m_pGrf.reset();
3510     m_pMagicTable.reset();;
3511     m_pFieldFootnote.reset();;
3512     m_pFieldTextBxs.reset();;
3513     m_pFieldHFTextBxs.reset();;
3514     m_pFieldAtn.reset();;
3515     m_pFieldEdn.reset();;
3516     m_pFieldHdFt.reset();;
3517     m_pFieldMain.reset();;
3518     m_pStyles.reset();;
3519     pO.reset();
3520     m_pChpPlc.reset();;
3521     m_pPapPlc.reset();;
3522     pSepx.reset();
3523 
3524     delete m_pRedlAuthors;
3525     delete m_pSdrObjs;
3526     delete m_pHFSdrObjs;
3527     delete m_pTextBxs;
3528     delete m_pHFTextBxs;
3529     delete m_pAtn;
3530     pEdn.reset();
3531     pFootnote.reset();
3532     delete m_pBkmks;
3533     delete m_pPiece;
3534     pDop.reset();
3535     pFib.reset();
3536     GetWriter().SetStream( nullptr );
3537 
3538     xWwStrm->SetBufferSize( 0 );
3539     xTableStrm->SetBufferSize( 0 );
3540     xDataStrm->SetBufferSize( 0 );
3541     if( 0 == pDataStrm->Seek( STREAM_SEEK_TO_END ))
3542     {
3543         xDataStrm.clear();
3544         pDataStrm = nullptr;
3545         GetWriter().GetStorage().Remove(SL::aData);
3546     }
3547 
3548     return err;
3549 }
3550 
PrepareStorage()3551 void WW8Export::PrepareStorage()
3552 {
3553     static const sal_uInt8 pData[] =
3554     {
3555         0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
3556         0xFF, 0xFF, 0xFF, 0xFF, 0x06, 0x09, 0x02, 0x00,
3557         0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,
3558         0x00, 0x00, 0x00, 0x46,
3559 
3560         0x18, 0x00, 0x00, 0x00,
3561         'M', 'i', 'c', 'r', 'o', 's', 'o', 'f',
3562         't', ' ', 'W', 'o', 'r', 'd', '-', 'D',
3563         'o', 'k', 'u', 'm', 'e', 'n', 't', 0x0,
3564 
3565         0x0A, 0x00, 0x00, 0x00,
3566         'M', 'S', 'W', 'o', 'r', 'd', 'D', 'o',
3567         'c', 0x0,
3568 
3569         0x10, 0x00, 0x00, 0x00,
3570         'W', 'o', 'r', 'd', '.', 'D', 'o', 'c',
3571         'u', 'm', 'e', 'n', 't', '.', '8', 0x0,
3572 
3573         0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00,
3574         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
3575     };
3576 
3577     SvGlobalName aGName(MSO_WW8_CLASSID);
3578     GetWriter().GetStorage().SetClass(
3579         aGName, SotClipboardFormatId::NONE, "Microsoft Word-Document");
3580     tools::SvRef<SotStorageStream> xStor( GetWriter().GetStorage().OpenSotStream(sCompObj) );
3581     xStor->WriteBytes(pData, sizeof(pData));
3582 
3583     SwDocShell* pDocShell = m_pDoc->GetDocShell ();
3584     OSL_ENSURE(pDocShell, "no SwDocShell");
3585 
3586     if (pDocShell) {
3587         uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
3588             pDocShell->GetModel(), uno::UNO_QUERY_THROW);
3589         uno::Reference<document::XDocumentProperties> xDocProps(
3590             xDPS->getDocumentProperties());
3591         OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
3592 
3593         if (xDocProps.is())
3594         {
3595             if ( SvtFilterOptions::Get().IsEnableWordPreview() )
3596             {
3597                 std::shared_ptr<GDIMetaFile> xMetaFile =
3598                     pDocShell->GetPreviewMetaFile();
3599                 uno::Sequence<sal_Int8> metaFile(
3600                     sfx2::convertMetaFile(xMetaFile.get()));
3601                 sfx2::SaveOlePropertySet(xDocProps, &GetWriter().GetStorage(), &metaFile);
3602             }
3603             else
3604                 sfx2::SaveOlePropertySet( xDocProps, &GetWriter().GetStorage() );
3605         }
3606     }
3607 }
3608 
WriteStorage()3609 ErrCode SwWW8Writer::WriteStorage()
3610 {
3611     // #i34818# - update layout (if present), for SwWriteTable
3612     SwViewShell* pViewShell = m_pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
3613     if( pViewShell != nullptr )
3614         pViewShell->CalcLayout();
3615 
3616     long nMaxNode = m_pDoc->GetNodes().Count();
3617     ::StartProgress( STR_STATSTR_W4WWRITE, 0, nMaxNode, m_pDoc->GetDocShell() );
3618 
3619     // Respect table at the beginning of the document
3620     {
3621         SwTableNode* pTNd = m_pCurrentPam->GetNode().FindTableNode();
3622         if( pTNd && m_bWriteAll )
3623             // start with the table node !!
3624             m_pCurrentPam->GetPoint()->nNode = *pTNd;
3625     }
3626 
3627     // Do the actual export
3628     ErrCode err = ERRCODE_NONE;
3629     {
3630         bool bDot = mpMedium->GetFilter()->GetName().endsWith("Vorlage");
3631         WW8Export aExport(this, m_pDoc, m_pCurrentPam, m_pOrigPam, bDot);
3632         m_pExport = &aExport;
3633         err = aExport.ExportDocument( m_bWriteAll );
3634         m_pExport = nullptr;
3635     }
3636 
3637     ::EndProgress( m_pDoc->GetDocShell() );
3638     return err;
3639 }
3640 
WriteMedium(SfxMedium &)3641 ErrCode SwWW8Writer::WriteMedium( SfxMedium& )
3642 {
3643     return WriteStorage();
3644 }
3645 
Write(SwPaM & rPaM,SfxMedium & rMed,const OUString * pFileName)3646 ErrCode SwWW8Writer::Write( SwPaM& rPaM, SfxMedium& rMed,
3647                           const OUString* pFileName )
3648 {
3649     mpMedium = &rMed;
3650     ErrCode nRet = StgWriter::Write( rPaM, rMed, pFileName );
3651     mpMedium = nullptr;
3652     return nRet;
3653 }
3654 
MSWordExportBase(SwDoc * pDocument,std::shared_ptr<SwUnoCursor> & pCurrentPam,SwPaM * pOriginalPam)3655 MSWordExportBase::MSWordExportBase( SwDoc *pDocument, std::shared_ptr<SwUnoCursor> & pCurrentPam, SwPaM *pOriginalPam )
3656     : m_aMainStg(sMainStream)
3657     , m_pISet(nullptr)
3658     , m_pPiece(nullptr)
3659     , m_pTopNodeOfHdFtPage(nullptr)
3660     , m_pBkmks(nullptr)
3661     , m_pRedlAuthors(nullptr)
3662     , m_pTableInfo(new ww8::WW8TableInfo())
3663     , m_nCharFormatStart(0)
3664     , m_nFormatCollStart(0)
3665     , m_nStyleBeforeFly(0)
3666     , m_nLastFormatId(0)
3667     , m_nUniqueList(0)
3668     , m_nHdFtIndex(0)
3669     , m_nOrigRedlineFlags(RedlineFlags::NONE)
3670     , m_bOrigShowChanges(true)
3671     , m_pCurrentPageDesc(nullptr)
3672     , m_bPrevTextNodeIsEmpty(false)
3673     , m_bFirstTOCNodeWithSection(false)
3674     , m_pChpIter(nullptr)
3675     , m_pAtn(nullptr)
3676     , m_pTextBxs(nullptr)
3677     , m_pHFTextBxs(nullptr)
3678     , m_pParentFrame(nullptr)
3679     , m_pFlyOffset(nullptr)
3680     , m_eNewAnchorType(RndStdIds::FLY_AS_CHAR)
3681     , m_pStyAttr(nullptr)
3682     , m_pOutFormatNode(nullptr)
3683     , m_pCurrentStyle(nullptr)
3684     , m_pSdrObjs(nullptr)
3685     , m_pHFSdrObjs(nullptr)
3686     , m_pEscher(nullptr)
3687     , m_nTextTyp(0)
3688     , m_bStyDef(false)
3689     , m_bBreakBefore(false)
3690     , m_bOutKF(false)
3691     , m_bOutFlyFrameAttrs(false)
3692     , m_bOutPageDescs(false)
3693     , m_bOutFirstPage(false)
3694     , m_bOutTable(false)
3695     , m_bOutGrf(false)
3696     , m_bInWriteEscher(false)
3697     , m_bStartTOX(false)
3698     , m_bInWriteTOX(false)
3699     , m_bFootnoteAtTextEnd(false)
3700     , m_bEndAtTextEnd(false)
3701     , m_bHasHdr(false)
3702     , m_bHasFtr(false)
3703     , m_bSubstituteBullets(true)
3704     , m_bTabInTOC(false)
3705     , m_bHideTabLeaderAndPageNumbers(false)
3706     , m_bExportModeRTF(false)
3707     , m_bFontSizeWritten(false)
3708     , m_bAddFootnoteTab(false)
3709     , m_pDoc(pDocument)
3710     , m_nCurStart(pCurrentPam->GetPoint()->nNode.GetIndex())
3711     , m_nCurEnd(pCurrentPam->GetMark()->nNode.GetIndex())
3712     , m_pCurPam(pCurrentPam)
3713     , m_pOrigPam(pOriginalPam)
3714 {
3715 }
3716 
~MSWordExportBase()3717 MSWordExportBase::~MSWordExportBase()
3718 {
3719     if (m_pUsedNumTable)           // all used NumRules
3720     {
3721         // clear the part of the list array that was copied from the document
3722         // - it's an auto delete array, so the rest of the array which are
3723         // duplicated lists that were added during the export will be deleted.
3724         m_pUsedNumTable->erase(m_pUsedNumTable->begin(), m_pUsedNumTable->begin() + m_pUsedNumTable->size() - m_nUniqueList);
3725         m_pUsedNumTable.reset();
3726     }
3727     m_pOLEExp.reset();
3728     m_pOCXExp.reset();
3729 }
3730 
WW8Export(SwWW8Writer * pWriter,SwDoc * pDocument,std::shared_ptr<SwUnoCursor> & pCurrentPam,SwPaM * pOriginalPam,bool bDot)3731 WW8Export::WW8Export( SwWW8Writer *pWriter,
3732         SwDoc *pDocument, std::shared_ptr<SwUnoCursor> & pCurrentPam, SwPaM *pOriginalPam,
3733         bool bDot )
3734     : MSWordExportBase( pDocument, pCurrentPam, pOriginalPam )
3735     , pTableStrm(nullptr)
3736     , pDataStrm(nullptr)
3737     , m_bDot(bDot)
3738     , m_pWriter(pWriter)
3739     , m_pAttrOutput(new WW8AttributeOutput(*this))
3740 {
3741 }
3742 
~WW8Export()3743 WW8Export::~WW8Export()
3744 {
3745 }
3746 
AttrOutput() const3747 AttributeOutputBase& WW8Export::AttrOutput() const
3748 {
3749     return *m_pAttrOutput;
3750 }
3751 
Sections() const3752 MSWordSections& WW8Export::Sections() const
3753 {
3754     return *pSepx;
3755 }
3756 
SwWW8Writer(const OUString & rFltName,const OUString & rBaseURL)3757 SwWW8Writer::SwWW8Writer(const OUString& rFltName, const OUString& rBaseURL)
3758     : StgWriter(),
3759       m_pExport( nullptr ),
3760       mpMedium( nullptr )
3761 {
3762     assert(rFltName == FILTER_WW8); // WW6/7 export was removed
3763     (void)rFltName;
3764     SetBaseURL( rBaseURL );
3765 }
3766 
~SwWW8Writer()3767 SwWW8Writer::~SwWW8Writer()
3768 {
3769 }
3770 
SaveOrDelMSVBAStorage_ww8(SfxObjectShell & rDoc,SotStorage & rStor,sal_Bool bSaveInto,const OUString & rStorageName)3771 extern "C" SAL_DLLPUBLIC_EXPORT sal_uInt32 SaveOrDelMSVBAStorage_ww8( SfxObjectShell& rDoc, SotStorage& rStor, sal_Bool bSaveInto, const OUString& rStorageName )
3772 {
3773     SvxImportMSVBasic aTmp( rDoc, rStor );
3774     return sal_uInt32(aTmp.SaveOrDelMSVBAStorage( bSaveInto, rStorageName ));
3775 }
3776 
ExportDOC(const OUString & rFltName,const OUString & rBaseURL,WriterRef & xRet)3777 extern "C" SAL_DLLPUBLIC_EXPORT void ExportDOC( const OUString& rFltName, const OUString& rBaseURL, WriterRef& xRet )
3778 {
3779     xRet = new SwWW8Writer( rFltName, rBaseURL );
3780 }
3781 
GetSaveWarningOfMSVBAStorage_ww8(SfxObjectShell & rDocS)3782 extern "C" SAL_DLLPUBLIC_EXPORT sal_uInt32 GetSaveWarningOfMSVBAStorage_ww8(  SfxObjectShell &rDocS )
3783 {
3784     return sal_uInt32(SvxImportMSVBasic::GetSaveWarningOfMSVBAStorage( rDocS ));
3785 }
3786 
WriteText(WW8Export & rWrt)3787 bool WW8_WrPlcFootnoteEdn::WriteText( WW8Export& rWrt )
3788 {
3789     bool bRet = false;
3790     if (TXT_FTN == nTyp)
3791     {
3792         bRet = WriteGenericText( rWrt, TXT_FTN, rWrt.pFib->m_ccpFootnote );
3793         rWrt.m_pFieldFootnote->Finish( rWrt.Fc2Cp( rWrt.Strm().Tell() ),
3794                             rWrt.pFib->m_ccpText );
3795     }
3796     else
3797     {
3798         bRet = WriteGenericText( rWrt, TXT_EDN, rWrt.pFib->m_ccpEdn );
3799         rWrt.m_pFieldEdn->Finish( rWrt.Fc2Cp( rWrt.Strm().Tell() ),
3800                             rWrt.pFib->m_ccpText + rWrt.pFib->m_ccpFootnote
3801                             + rWrt.pFib->m_ccpHdr + rWrt.pFib->m_ccpAtn );
3802     }
3803     return bRet;
3804 }
3805 
WritePlc(WW8Export & rWrt) const3806 void WW8_WrPlcFootnoteEdn::WritePlc( WW8Export& rWrt ) const
3807 {
3808     if( TXT_FTN == nTyp )
3809     {
3810         WriteGenericPlc( rWrt, TXT_FTN, rWrt.pFib->m_fcPlcffndText,
3811             rWrt.pFib->m_lcbPlcffndText, rWrt.pFib->m_fcPlcffndRef,
3812             rWrt.pFib->m_lcbPlcffndRef );
3813     }
3814     else
3815     {
3816         WriteGenericPlc( rWrt, TXT_EDN, rWrt.pFib->m_fcPlcfendText,
3817             rWrt.pFib->m_lcbPlcfendText, rWrt.pFib->m_fcPlcfendRef,
3818             rWrt.pFib->m_lcbPlcfendRef );
3819     }
3820 }
3821 
WriteText(WW8Export & rWrt)3822 bool WW8_WrPlcAnnotations::WriteText( WW8Export& rWrt )
3823 {
3824     bool bRet = WriteGenericText( rWrt, TXT_ATN, rWrt.pFib->m_ccpAtn );
3825     rWrt.m_pFieldAtn->Finish( rWrt.Fc2Cp( rWrt.Strm().Tell() ),
3826                         rWrt.pFib->m_ccpText + rWrt.pFib->m_ccpFootnote
3827                         + rWrt.pFib->m_ccpHdr );
3828     return bRet;
3829 }
3830 
WritePlc(WW8Export & rWrt) const3831 void WW8_WrPlcAnnotations::WritePlc( WW8Export& rWrt ) const
3832 {
3833     WriteGenericPlc( rWrt, TXT_ATN, rWrt.pFib->m_fcPlcfandText,
3834         rWrt.pFib->m_lcbPlcfandText, rWrt.pFib->m_fcPlcfandRef,
3835         rWrt.pFib->m_lcbPlcfandRef );
3836 }
3837 
WritePlc(WW8Export & rWrt) const3838 void WW8_WrPlcTextBoxes::WritePlc( WW8Export& rWrt ) const
3839 {
3840     if( TXT_TXTBOX == nTyp )
3841     {
3842         WriteGenericPlc( rWrt, nTyp, rWrt.pFib->m_fcPlcftxbxBkd,
3843             rWrt.pFib->m_lcbPlcftxbxBkd, rWrt.pFib->m_fcPlcftxbxText,
3844             rWrt.pFib->m_lcbPlcftxbxText );
3845     }
3846     else
3847     {
3848         WriteGenericPlc( rWrt, nTyp, rWrt.pFib->m_fcPlcfHdrtxbxBkd,
3849             rWrt.pFib->m_lcbPlcfHdrtxbxBkd, rWrt.pFib->m_fcPlcfHdrtxbxText,
3850             rWrt.pFib->m_lcbPlcfHdrtxbxText );
3851     }
3852 }
3853 
RestoreMacroCmds()3854 void WW8Export::RestoreMacroCmds()
3855 {
3856     pFib->m_fcCmds = pTableStrm->Tell();
3857 
3858     uno::Reference < embed::XStorage > xSrcRoot(m_pDoc->GetDocShell()->GetStorage());
3859     try
3860     {
3861         uno::Reference < io::XStream > xSrcStream =
3862                 xSrcRoot->openStreamElement( SL::aMSMacroCmds, embed::ElementModes::READ );
3863         std::unique_ptr<SvStream> pStream = ::utl::UcbStreamHelper::CreateStream( xSrcStream );
3864 
3865         if ( pStream && ERRCODE_NONE == pStream->GetError())
3866         {
3867             pFib->m_lcbCmds = pStream->TellEnd();
3868             pStream->Seek(0);
3869 
3870             std::unique_ptr<sal_uInt8[]> pBuffer( new sal_uInt8[pFib->m_lcbCmds] );
3871             bool bReadOk = checkRead(*pStream, pBuffer.get(), pFib->m_lcbCmds);
3872             if (bReadOk)
3873                 pTableStrm->WriteBytes(pBuffer.get(), pFib->m_lcbCmds);
3874         }
3875     }
3876     catch ( const uno::Exception& )
3877     {
3878     }
3879 
3880     // set len to FIB
3881     pFib->m_lcbCmds = pTableStrm->Tell() - pFib->m_fcCmds;
3882 }
3883 
Write(WW8Export & rExport)3884 void WW8SHDLong::Write( WW8Export& rExport )
3885 {
3886     rExport.InsUInt32( m_cvFore );
3887     rExport.InsUInt32( m_cvBack );
3888     rExport.InsUInt16( 0 ); // ipat
3889 }
3890 
WriteFormData(const::sw::mark::IFieldmark & rFieldmark)3891 void WW8Export::WriteFormData( const ::sw::mark::IFieldmark& rFieldmark )
3892 {
3893     const ::sw::mark::IFieldmark* pFieldmark = &rFieldmark;
3894     const ::sw::mark::ICheckboxFieldmark* pAsCheckbox = dynamic_cast< const ::sw::mark::ICheckboxFieldmark* >( pFieldmark );
3895 
3896     if ( ! ( rFieldmark.GetFieldname() == ODF_FORMTEXT ||
3897                 rFieldmark.GetFieldname() == ODF_FORMDROPDOWN ||
3898                 rFieldmark.GetFieldname() == ODF_FORMCHECKBOX ) )
3899     {
3900         SAL_WARN( "sw.ww8", "unknown field type" );
3901         return;
3902     }
3903 
3904     int type = 0; // TextFieldmark
3905     if ( pAsCheckbox )
3906         type = 1;
3907     if ( rFieldmark.GetFieldname() == ODF_FORMDROPDOWN )
3908         type=2;
3909 
3910     ::sw::mark::IFieldmark::parameter_map_t::const_iterator pParameter = rFieldmark.GetParameters()->find("name");
3911     OUString ffname;
3912     if ( pParameter != rFieldmark.GetParameters()->end() )
3913     {
3914         OUString aName;
3915         pParameter->second >>= aName;
3916         assert( aName.getLength() < 21 && "jluth seeing if following documentation will cause problems." );
3917         const sal_Int32 nLen = std::min( sal_Int32(20), aName.getLength() );
3918         ffname = aName.copy(0, nLen);
3919     }
3920 
3921     sal_uInt64 nDataStt = pDataStrm->Tell();
3922     m_pChpPlc->AppendFkpEntry(Strm().Tell());
3923 
3924     WriteChar(0x01);
3925     static sal_uInt8 aArr1[] =
3926     {
3927         0x03, 0x6a, 0,0,0,0,    // sprmCPicLocation
3928 
3929         0x06, 0x08, 0x01,       // sprmCFData
3930         0x55, 0x08, 0x01,       // sprmCFSpec
3931         0x02, 0x08, 0x01        // sprmCFFieldVanish
3932     };
3933     sal_uInt8* pDataAdr = aArr1 + 2;
3934     Set_UInt32(pDataAdr, nDataStt);
3935 
3936     m_pChpPlc->AppendFkpEntry( Strm().Tell(), sizeof( aArr1 ), aArr1 );
3937 
3938     struct FFDataHeader
3939     {
3940         sal_uInt32 version;
3941         sal_uInt16 bits;
3942         sal_uInt16 cch;
3943         sal_uInt16 hps;
3944         FFDataHeader() : version( 0xFFFFFFFF ), bits(0), cch(0), hps(0) {}
3945     };
3946 
3947     FFDataHeader aFieldHeader;
3948     aFieldHeader.bits |= (type & 0x03);
3949 
3950     sal_Int32 ffres = 0; // rFieldmark.GetFFRes();
3951     if ( pAsCheckbox && pAsCheckbox->IsChecked() )
3952         ffres = 1;
3953     else if ( type == 2 )
3954     {
3955         ::sw::mark::IFieldmark::parameter_map_t::const_iterator pResParameter = rFieldmark.GetParameters()->find(ODF_FORMDROPDOWN_RESULT);
3956         if(pResParameter != rFieldmark.GetParameters()->end())
3957             pResParameter->second >>= ffres;
3958         else
3959             ffres = 0;
3960     }
3961     aFieldHeader.bits |= ( (ffres<<2) & 0x7C );
3962 
3963     OUString ffdeftext;
3964     OUString ffformat;
3965     OUString ffhelptext = rFieldmark.GetFieldHelptext();
3966     if ( ffhelptext.getLength() > 255 )
3967         ffhelptext = ffhelptext.copy(0, 255);
3968     OUString ffstattext;
3969     OUString ffentrymcr;
3970     OUString ffexitmcr;
3971     if (type == 0) // iTypeText
3972     {
3973         sal_uInt16 nType = 0;
3974         pParameter = rFieldmark.GetParameters()->find("Type");
3975         if ( pParameter != rFieldmark.GetParameters()->end() )
3976         {
3977             OUString aType;
3978             pParameter->second >>= aType;
3979             if ( aType == "number" )            nType = 1;
3980             else if ( aType == "date" )         nType = 2;
3981             else if ( aType == "currentTime" )  nType = 3;
3982             else if ( aType == "currentDate" )  nType = 4;
3983             else if ( aType == "calculated" )   nType = 5;
3984             aFieldHeader.bits |= nType<<11; // FFDataBits-F  00111000 00000000
3985         }
3986 
3987         if ( nType < 3 || nType == 5 )  // not currentTime or currentDate
3988         {
3989             pParameter = rFieldmark.GetParameters()->find("Content");
3990             if ( pParameter != rFieldmark.GetParameters()->end() )
3991             {
3992                 OUString aDefaultText;
3993                 pParameter->second >>= aDefaultText;
3994                 assert( aDefaultText.getLength() < 256 && "jluth seeing if following documentation will cause problems." );
3995                 const sal_Int32 nLen = std::min( sal_Int32(255), aDefaultText.getLength() );
3996                 ffdeftext = aDefaultText.copy (0, nLen);
3997             }
3998         }
3999 
4000         pParameter = rFieldmark.GetParameters()->find("MaxLength");
4001         if ( pParameter != rFieldmark.GetParameters()->end() )
4002         {
4003             sal_uInt16 nLength = 0;
4004             pParameter->second >>= nLength;
4005             assert( nLength < 32768 && "jluth seeing if following documentation will cause problems." );
4006             nLength = std::min( sal_uInt16(32767), nLength );
4007             aFieldHeader.cch = nLength;
4008         }
4009 
4010         pParameter = rFieldmark.GetParameters()->find("Format");
4011         if ( pParameter != rFieldmark.GetParameters()->end() )
4012         {
4013             OUString aFormat;
4014             pParameter->second >>= aFormat;
4015             const sal_Int32 nLen = std::min( sal_Int32(64), aFormat.getLength() );
4016             assert( nLen < 65 && "jluth seeing if following documentation will cause problems." );
4017             ffformat = aFormat.copy(0, nLen);
4018         }
4019     }
4020 
4021     pParameter = rFieldmark.GetParameters()->find("Help"); //help
4022     if ( ffhelptext.isEmpty() && pParameter != rFieldmark.GetParameters()->end() )
4023     {
4024         OUString aHelpText;
4025         pParameter->second >>= aHelpText;
4026         const sal_Int32 nLen = std::min( sal_Int32(255), aHelpText.getLength() );
4027         ffhelptext = aHelpText.copy (0, nLen);
4028     }
4029     if ( !ffhelptext.isEmpty() )
4030         aFieldHeader.bits |= 0x1<<7;
4031 
4032     pParameter = rFieldmark.GetParameters()->find("Description"); // doc tooltip
4033     if ( pParameter == rFieldmark.GetParameters()->end() )
4034         pParameter = rFieldmark.GetParameters()->find("Hint"); //docx tooltip
4035     if ( pParameter != rFieldmark.GetParameters()->end() )
4036     {
4037         OUString aStatusText;
4038         pParameter->second >>= aStatusText;
4039         const sal_Int32 nLen = std::min( sal_Int32(138), aStatusText.getLength() );
4040         ffstattext = aStatusText.copy (0, nLen);
4041     }
4042     if ( !ffstattext.isEmpty() )
4043         aFieldHeader.bits |= 0x1<<8;
4044 
4045     pParameter = rFieldmark.GetParameters()->find("EntryMacro");
4046     if ( pParameter != rFieldmark.GetParameters()->end() )
4047     {
4048         OUString aEntryMacro;
4049         pParameter->second >>= aEntryMacro;
4050         assert( aEntryMacro.getLength() < 33 && "jluth seeing if following documentation will cause problems." );
4051         const sal_Int32 nLen = std::min( sal_Int32(32), aEntryMacro.getLength() );
4052         ffentrymcr = aEntryMacro.copy (0, nLen);
4053     }
4054 
4055     pParameter = rFieldmark.GetParameters()->find("ExitMacro");
4056     if ( pParameter != rFieldmark.GetParameters()->end() )
4057     {
4058         OUString aExitMacro;
4059         pParameter->second >>= aExitMacro;
4060         assert( aExitMacro.getLength() < 33 && "jluth seeing if following documentation will cause problems." );
4061         const sal_Int32 nLen = std::min( sal_Int32(32), aExitMacro.getLength() );
4062         ffexitmcr = aExitMacro.copy (0, nLen);
4063     }
4064 
4065     std::vector< OUString > aListItems;
4066     if (type==2)
4067     {
4068         aFieldHeader.bits |= 0x8000; // ffhaslistbox
4069         const ::sw::mark::IFieldmark::parameter_map_t* const pParameters = rFieldmark.GetParameters();
4070         ::sw::mark::IFieldmark::parameter_map_t::const_iterator pListEntries = pParameters->find(ODF_FORMDROPDOWN_LISTENTRY);
4071         if(pListEntries != pParameters->end())
4072         {
4073             uno::Sequence< OUString > vListEntries;
4074             pListEntries->second >>= vListEntries;
4075             copy(vListEntries.begin(), vListEntries.end(), back_inserter(aListItems));
4076         }
4077     }
4078 
4079     const sal_uInt8 aFieldData[] =
4080     {
4081         0x44,0,         // the start of "next" data
4082         0,0,0,0,0,0,0,0,0,0,                // PIC-Structure!  /10
4083         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,    //  |              /16
4084         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,    //  |              /16
4085         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,    //  |              /16
4086         0,0,0,0,                            // /               /4
4087     };
4088     sal_uInt32 slen = sizeof(sal_uInt32)
4089         + sizeof(aFieldData)
4090         + sizeof( aFieldHeader.version ) + sizeof( aFieldHeader.bits ) + sizeof( aFieldHeader.cch ) + sizeof( aFieldHeader.hps )
4091         + 2*ffname.getLength() + 4
4092         + 2*ffformat.getLength() + 4
4093         + 2*ffhelptext.getLength() + 4
4094         + 2*ffstattext.getLength() + 4
4095         + 2*ffentrymcr.getLength() + 4
4096         + 2*ffexitmcr.getLength() + 4;
4097     if ( type )
4098         slen += 2; // wDef
4099     else
4100         slen += 2*ffdeftext.getLength() + 4; //xstzTextDef
4101     if ( type==2 ) {
4102         slen += 2; // sttb ( fExtend )
4103         slen += 4; // for num of list items
4104         const int items = aListItems.size();
4105         for( int i = 0; i < items; i++ ) {
4106             OUString item = aListItems[i];
4107             slen += 2 * item.getLength() + 2;
4108         }
4109     }
4110 
4111     pDataStrm->WriteUInt32( slen );
4112 
4113     int len = sizeof( aFieldData );
4114     OSL_ENSURE( len == 0x44-sizeof(sal_uInt32), "SwWW8Writer::WriteFormData(..) - wrong aFieldData length" );
4115     pDataStrm->WriteBytes( aFieldData, len );
4116 
4117     pDataStrm->WriteUInt32( aFieldHeader.version ).WriteUInt16( aFieldHeader.bits ).WriteUInt16( aFieldHeader.cch ).WriteUInt16( aFieldHeader.hps );
4118 
4119     SwWW8Writer::WriteString_xstz( *pDataStrm, ffname, true ); // Form field name
4120 
4121     if ( !type )
4122         SwWW8Writer::WriteString_xstz( *pDataStrm, ffdeftext, true );
4123     if ( type )
4124         pDataStrm->WriteUInt16( 0 );
4125 
4126     SwWW8Writer::WriteString_xstz( *pDataStrm, ffformat, true );
4127     SwWW8Writer::WriteString_xstz( *pDataStrm, ffhelptext, true );
4128     SwWW8Writer::WriteString_xstz( *pDataStrm, ffstattext, true );
4129     SwWW8Writer::WriteString_xstz( *pDataStrm, ffentrymcr, true );
4130     SwWW8Writer::WriteString_xstz( *pDataStrm, ffexitmcr, true );
4131     if (type==2) {
4132         pDataStrm->WriteUInt16( 0xFFFF );
4133         const int items=aListItems.size();
4134         pDataStrm->WriteUInt32( items );
4135         for(int i=0;i<items;i++) {
4136             OUString item=aListItems[i];
4137             SwWW8Writer::WriteString_xstz( *pDataStrm, item, false );
4138         }
4139     }
4140 }
4141 
WriteHyperlinkData(const sw::mark::IFieldmark &)4142 void WW8Export::WriteHyperlinkData( const sw::mark::IFieldmark& /*rFieldmark*/ )
4143 {
4144     //@TODO implement me !!!
4145 }
4146 
TableNodeInfoInner(ww8::WW8TableNodeInfoInner::Pointer_t pNodeInfoInner)4147 void WW8AttributeOutput::TableNodeInfoInner( ww8::WW8TableNodeInfoInner::Pointer_t pNodeInfoInner )
4148 {
4149     SVBT16 nStyle;
4150     ShortToSVBT16( m_rWW8Export.m_nStyleBeforeFly, nStyle );
4151 
4152 #ifdef DBG_UTIL
4153     SAL_INFO( "sw.ww8", "<OutWW8_TableNodeInfoInner>" << pNodeInfoInner->toString());
4154 #endif
4155 
4156     m_rWW8Export.pO->clear();
4157 
4158     sal_uInt32 nShadowsBefore = pNodeInfoInner->getShadowsBefore();
4159     if (nShadowsBefore > 0)
4160     {
4161         ww8::WW8TableNodeInfoInner::Pointer_t
4162             pTmpNodeInfoInner(new ww8::WW8TableNodeInfoInner(nullptr));
4163 
4164         pTmpNodeInfoInner->setDepth(pNodeInfoInner->getDepth());
4165         pTmpNodeInfoInner->setEndOfCell(true);
4166 
4167         for (sal_uInt32 n = 0; n < nShadowsBefore; ++n)
4168         {
4169             m_rWW8Export.WriteCR(pTmpNodeInfoInner);
4170 
4171             m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), nStyle, nStyle+2 );     // Style #
4172             TableInfoCell(pTmpNodeInfoInner);
4173             m_rWW8Export.m_pPapPlc->AppendFkpEntry
4174                 ( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->size(), m_rWW8Export.pO->data() );
4175 
4176             m_rWW8Export.pO->clear();
4177         }
4178     }
4179 
4180     if (pNodeInfoInner->isEndOfCell())
4181     {
4182         SAL_INFO( "sw.ww8", "<endOfCell/>" );
4183 
4184         m_rWW8Export.WriteCR(pNodeInfoInner);
4185 
4186         m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), nStyle, nStyle+2 );     // Style #
4187         TableInfoCell(pNodeInfoInner);
4188         m_rWW8Export.m_pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->size(), m_rWW8Export.pO->data() );
4189 
4190         m_rWW8Export.pO->clear();
4191     }
4192 
4193     sal_uInt32 nShadowsAfter = pNodeInfoInner->getShadowsAfter();
4194     if (nShadowsAfter > 0)
4195     {
4196         ww8::WW8TableNodeInfoInner::Pointer_t
4197             pTmpNodeInfoInner(new ww8::WW8TableNodeInfoInner(nullptr));
4198 
4199         pTmpNodeInfoInner->setDepth(pNodeInfoInner->getDepth());
4200         pTmpNodeInfoInner->setEndOfCell(true);
4201 
4202         for (sal_uInt32 n = 0; n < nShadowsAfter; ++n)
4203         {
4204             m_rWW8Export.WriteCR(pTmpNodeInfoInner);
4205 
4206             m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), nStyle, nStyle+2 );     // Style #
4207             TableInfoCell(pTmpNodeInfoInner);
4208             m_rWW8Export.m_pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->size(), m_rWW8Export.pO->data() );
4209 
4210             m_rWW8Export.pO->clear();
4211         }
4212     }
4213 
4214     if (pNodeInfoInner->isEndOfLine())
4215     {
4216         SAL_INFO( "sw.ww8", "<endOfLine/>" );
4217 
4218         TableRowEnd(pNodeInfoInner->getDepth());
4219 
4220         ShortToSVBT16(0, nStyle);
4221         m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), nStyle, nStyle+2 );     // Style #
4222         TableInfoRow(pNodeInfoInner);
4223         m_rWW8Export.m_pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->size(), m_rWW8Export.pO->data() );
4224 
4225         m_rWW8Export.pO->clear();
4226     }
4227     SAL_INFO( "sw.ww8", "</OutWW8_TableNodeInfoInner>" );
4228 }
4229 
OutputStartNode(const SwStartNode & rNode)4230 void MSWordExportBase::OutputStartNode( const SwStartNode & rNode)
4231 {
4232 
4233     ww8::WW8TableNodeInfo::Pointer_t pNodeInfo =
4234         m_pTableInfo->getTableNodeInfo( &rNode );
4235 
4236     if (pNodeInfo.get() != nullptr)
4237     {
4238 #ifdef DBG_UTIL
4239         SAL_INFO( "sw.ww8", pNodeInfo->toString());
4240 #endif
4241         const ww8::WW8TableNodeInfo::Inners_t aInners = pNodeInfo->getInners();
4242         ww8::WW8TableNodeInfo::Inners_t::const_reverse_iterator aIt(aInners.rbegin());
4243         ww8::WW8TableNodeInfo::Inners_t::const_reverse_iterator aEnd(aInners.rend());
4244         while (aIt != aEnd)
4245         {
4246             ww8::WW8TableNodeInfoInner::Pointer_t pInner = aIt->second;
4247 
4248             AttrOutput().TableNodeInfoInner(pInner);
4249             ++aIt;
4250         }
4251     }
4252     SAL_INFO( "sw.ww8", "</OutWW8_SwStartNode>" );
4253 }
4254 
OutputEndNode(const SwEndNode & rNode)4255 void MSWordExportBase::OutputEndNode( const SwEndNode &rNode )
4256 {
4257 #ifdef DBG_UTIL
4258     SAL_INFO( "sw.ww8", "<OutWW8_SwEndNode>" << dbg_out(&rNode));
4259 #endif
4260 
4261     ww8::WW8TableNodeInfo::Pointer_t pNodeInfo = m_pTableInfo->getTableNodeInfo( &rNode );
4262 
4263     if (pNodeInfo.get() != nullptr)
4264     {
4265 #ifdef DBG_UTIL
4266         SAL_INFO( "sw.ww8", pNodeInfo->toString());
4267 #endif
4268         const ww8::WW8TableNodeInfo::Inners_t aInners = pNodeInfo->getInners();
4269         for (const auto& rEntry : aInners)
4270         {
4271             ww8::WW8TableNodeInfoInner::Pointer_t pInner = rEntry.second;
4272             AttrOutput().TableNodeInfoInner(pInner);
4273         }
4274     }
4275     SAL_INFO( "sw.ww8", "</OutWW8_SwEndNode>" );
4276 }
4277 
GetNfKeywordTable()4278 const NfKeywordTable & MSWordExportBase::GetNfKeywordTable()
4279 {
4280     if (m_pKeyMap == nullptr)
4281     {
4282         m_pKeyMap.reset(new NfKeywordTable);
4283         NfKeywordTable & rKeywordTable = *m_pKeyMap;
4284         rKeywordTable[NF_KEY_D] = "d";
4285         rKeywordTable[NF_KEY_DD] = "dd";
4286         rKeywordTable[NF_KEY_DDD] = "ddd";
4287         rKeywordTable[NF_KEY_DDDD] = "dddd";
4288         rKeywordTable[NF_KEY_M] = "M";
4289         rKeywordTable[NF_KEY_MM] = "MM";
4290         rKeywordTable[NF_KEY_MMM] = "MMM";
4291         rKeywordTable[NF_KEY_MMMM] = "MMMM";
4292         rKeywordTable[NF_KEY_NN] = "ddd";
4293         rKeywordTable[NF_KEY_NNN] = "dddd";
4294         rKeywordTable[NF_KEY_NNNN] = "dddd";
4295         rKeywordTable[NF_KEY_YY] = "yy";
4296         rKeywordTable[NF_KEY_YYYY] = "yyyy";
4297         rKeywordTable[NF_KEY_H] = "H";
4298         rKeywordTable[NF_KEY_HH] = "HH";
4299         rKeywordTable[NF_KEY_MI] = "m";
4300         rKeywordTable[NF_KEY_MMI] = "mm";
4301         rKeywordTable[NF_KEY_S] = "s";
4302         rKeywordTable[NF_KEY_SS] = "ss";
4303         rKeywordTable[NF_KEY_AMPM] = "AM/PM";
4304     }
4305 
4306     return *m_pKeyMap;
4307 }
4308 
4309 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
4310