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