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