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>
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>
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"
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
120using namespace css;
121using namespace sw::util;
122using namespace sw::types;
123
127{
128 sal_uInt8* m_pFkp; // Fkp total ( first and only FCs and Sprms )
129 sal_uInt8* m_pOfs; // pointer to the offset area, later copied to pFkp
131 short m_nStartGrp; // from here on grpprls
134 sal_uInt8 m_nIMax; // number of entry pairs
136 bool m_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
143public:
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 !m_bCombined && m_nIMax && nEndFc == reinterpret_cast<sal_Int32*>(m_pFkp)[m_nIMax]; }
152 void MergeToNew( short& rVarLen, sal_uInt8 *& pNewSprms );
153 bool IsEmptySprm() const
154 { return !m_bCombined && m_nIMax && !m_nOldVarLen; }
155 void SetNewEnd( WW8_FC nEnd )
156 { reinterpret_cast<sal_Int32*>(m_pFkp)[m_nIMax] = nEnd; }
157
158 WW8_FC GetStartFc() const;
159 WW8_FC GetEndFc() const;
160
162};
163
164// class WW8_WrPc collects all piece entries for one piece
166{
167 WW8_CP m_nStartCp; // Starting character position of the text
168 WW8_FC m_nStartFc; // Starting file position of the text
169 sal_uInt16 m_nStatus; // End of paragraph inside the piece?
170
171public:
172 WW8_WrPc(WW8_FC nSFc, WW8_CP nSCp )
173 : m_nStartCp( nSCp ), m_nStartFc( nSFc ), m_nStatus( 0x0040 )
174 {}
175
176 void SetStatus() { m_nStatus = 0x0050; }
177 sal_uInt16 GetStatus() const { return m_nStatus; }
178 WW8_CP GetStartCp() const { return m_nStartCp; }
179 WW8_FC GetStartFc() const { return m_nStartFc; }
180};
181
182typedef std::map<OUString,tools::Long> BKMKNames;
183typedef std::pair<bool,OUString> BKMK;
184typedef std::pair<tools::Long,BKMK> BKMKCP;
185typedef std::multimap<tools::Long,BKMKCP*> BKMKCPs;
186typedef BKMKCPs::iterator CPItr;
187
189{
190private:
194
197
198public:
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 : maSttCps)
215 {
216 if (rEntry.second)
217 {
218 delete rEntry.second;
219 rEntry.second = nullptr;
220 }
221 }
222}
223
224void 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 maSttCps.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 = maSttCps.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 (maSttCps.empty())
253 return;
255 std::vector<OUString> aNames;
256 SvMemoryStream aTempStrm1(65535,65535);
257 SvMemoryStream aTempStrm2(65535,65535);
258
259 BKMKCPs aEndCps;
260 for (const auto& rEntry : maSttCps)
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.m_pFib->m_fcSttbfbkmk,rWrt.m_pFib->m_lcbSttbfbkmk);
284 SvStream& rStrm = *rWrt.m_pTableStrm;
285 rWrt.m_pFib->m_fcPlcfbkf = rStrm.Tell();
286 rStrm.WriteStream( aTempStrm1 );
287 SwWW8Writer::WriteLong(rStrm, rWrt.m_pFib->m_ccpText + rWrt.m_pFib->m_ccpTxbx);
288 for (const auto& rEntry : maSttCps)
289 {
290 if (rEntry.second)
291 {
292 SwWW8Writer::WriteLong(rStrm, rEntry.second->first);
293 }
294 }
295 rWrt.m_pFib->m_lcbPlcfbkf = rStrm.Tell() - rWrt.m_pFib->m_fcPlcfbkf;
296 rWrt.m_pFib->m_fcPlcfbkl = rStrm.Tell();
297 rStrm.WriteStream( aTempStrm2 );
298 SwWW8Writer::WriteLong(rStrm, rWrt.m_pFib->m_ccpText + rWrt.m_pFib->m_ccpTxbx);
299 rWrt.m_pFib->m_lcbPlcfbkl = rStrm.Tell() - rWrt.m_pFib->m_fcPlcfbkl;
300}
301
303{
304 std::pair<CPItr,CPItr> aRange = maSttCps.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 maSttCps.insert(std::pair<tools::Long,BKMKCP*>(nTo,aItr->second));
316 aItr->second = nullptr;
317 aRange = maSttCps.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
334
335public:
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
345void 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.m_pDop->fEmbedFactoids = true;
359
360 SvStream& rStream = *rExport.m_pTableStrm;
361
362 rExport.m_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.m_pFib->m_lcbSttbfBkmkFactoid = rStream.Tell() - rExport.m_pFib->m_fcSttbfBkmkFactoid;
378
379 rExport.m_pFib->m_fcPlcfBkfFactoid = rStream.Tell();
380 for (const WW8_CP& rCP : m_aStartCPs)
381 rStream.WriteInt32(rCP);
382 rStream.WriteInt32(rExport.m_pFib->m_ccpText + rExport.m_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.m_pFib->m_lcbPlcfBkfFactoid = rStream.Tell() - rExport.m_pFib->m_fcPlcfBkfFactoid;
393
394 rExport.m_pFib->m_fcPlcfBklFactoid = rStream.Tell();
395 for (const WW8_CP& rCP : m_aEndCPs)
396 rStream.WriteInt32(rCP);
397 rStream.WriteInt32(rExport.m_pFib->m_ccpText + rExport.m_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.m_pFib->m_lcbPlcfBklFactoid = rStream.Tell() - rExport.m_pFib->m_fcPlcfBklFactoid;
406
407 rExport.m_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.m_pFib->m_lcbFactoidData = rStream.Tell() - rExport.m_pFib->m_fcFactoidData;
443}
444
445#define DEFAULT_STYLES_COUNT 16
446
447// Names of the storage streams
448constexpr OUStringLiteral sMainStream = u"WordDocument";
449constexpr OUStringLiteral sCompObj = u"\1CompObj";
450
451static void WriteDop( WW8Export& rWrt )
452{
453 WW8Dop& rDop = *rWrt.m_pDop;
454
455 // i#78951#, store the value of unknown compatibility options
458
461
462 // write default TabStop
463 const SvxTabStopItem& rTabStop =
465 rDop.dxaTab = o3tl::narrowing<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.m_pSepx && rWrt.m_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.m_pTableStrm, *rWrt.m_pFib );
560}
561
562static 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/*
574Converts the OOo Asian Typography into a best fit match for Microsoft
575Asian typography. This structure is actually dumped to disk within the
576Dop 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()
758const 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
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
780const 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
789 OSL_ENSURE(nWhich != 0, "All broken, Impossible");
790 return m_pISet->Get(nWhich);
791 }
792 return m_pChpIter->GetItem( nWhich );
793}
794
795WW8_WrPlc1::WW8_WrPlc1( sal_uInt16 nStructSz )
796 : m_pData( new sal_uInt8[ 16 * nStructSz ] ),
797 m_nDataLen(16 * nStructSz),
798 m_nStructSiz( nStructSz )
799{
800}
801
803{
804}
805
807{
808 bool b = !m_aPos.empty();
809 OSL_ENSURE(b,"Prev called on empty list");
810 return b ? m_aPos.back() : 0;
811}
812
813void WW8_WrPlc1::Append( WW8_CP nCp, const void* pNewData )
814{
815 sal_uLong nInsPos = m_aPos.size() * m_nStructSiz;
816 m_aPos.push_back( nCp );
817 if( m_nDataLen < nInsPos + m_nStructSiz )
818 {
819 sal_uInt8* pNew = new sal_uInt8[ 2 * m_nDataLen ];
820 memcpy( pNew, m_pData.get(), m_nDataLen );
821 m_pData.reset(pNew);
822 m_nDataLen *= 2;
823 }
824 memcpy( m_pData.get() + nInsPos, pNewData, m_nStructSiz );
825}
826
828{
829 if( !m_aPos.empty() )
830 {
831 m_aPos.push_back( nLastCp );
832 if( nSttCp )
833 for(WW8_CP & rCp : m_aPos)
834 rCp -= nSttCp;
835 }
836}
837
839{
840 decltype(m_aPos)::size_type i;
841 for( i = 0; i < m_aPos.size(); ++i )
843 if( i )
844 rStrm.WriteBytes(m_pData.get(), (i-1) * m_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 (m_nTextTyp)
857 {
858 case TXT_MAINTEXT:
859 pfc = &rWrt.m_pFib->m_fcPlcffldMom;
860 plc = &rWrt.m_pFib->m_lcbPlcffldMom;
861 break;
862 case TXT_HDFT:
863 pfc = &rWrt.m_pFib->m_fcPlcffldHdr;
864 plc = &rWrt.m_pFib->m_lcbPlcffldHdr;
865 break;
866
867 case TXT_FTN:
868 pfc = &rWrt.m_pFib->m_fcPlcffldFootnote;
869 plc = &rWrt.m_pFib->m_lcbPlcffldFootnote;
870 break;
871
872 case TXT_EDN:
873 pfc = &rWrt.m_pFib->m_fcPlcffldEdn;
874 plc = &rWrt.m_pFib->m_lcbPlcffldEdn;
875 break;
876
877 case TXT_ATN:
878 pfc = &rWrt.m_pFib->m_fcPlcffldAtn;
879 plc = &rWrt.m_pFib->m_lcbPlcffldAtn;
880 break;
881
882 case TXT_TXTBOX:
883 pfc = &rWrt.m_pFib->m_fcPlcffldTxbx;
884 plc = &rWrt.m_pFib->m_lcbPlcffldTxbx;
885 break;
886
887 case TXT_HFTXTBOX:
888 pfc = &rWrt.m_pFib->m_fcPlcffldHdrTxbx;
889 plc = &rWrt.m_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.m_pTableStrm->Tell();
901 *pfc = nFcStart;
902 *plc = rWrt.m_pTableStrm->Tell() - nFcStart;
903 }
904}
905
907{
908 if( WW8_WrPlc1::Count() <= 1 )
909 return;
910 sal_uInt64 nFcStart = rWrt.m_pTableStrm->Tell();
912 rWrt.m_pFib->m_fcPlcfTch = nFcStart;
913 rWrt.m_pFib->m_lcbPlcfTch = rWrt.m_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 : m_rWrt(rWr)
963 , m_nFkpStartPage(0)
964 , m_ePlc(ePl)
965{
966 m_Fkps.push_back(std::make_unique<WW8_WrFkp>(m_ePlc, nStartFc));
967}
968
970{
971}
972
974{
975 WW8_WrFkp& rF = *m_Fkps.back();
976 return rF.CopyLastSprms(rLen);
977}
978
979void 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 == m_ePlc && 488 <= nVarLen)
987 {
988 sal_uInt8* p = aHugePapx;
989 *p++ = *pSprms++; // set style Id
990 *p++ = *pSprms++;
991 nVarLen -= 2;
992
993 sal_uInt64 nDataPos = m_rWrt.m_pDataStrm->Tell();
995 m_rWrt.m_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(m_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 m_nFkpStartPage = o3tl::narrowing<sal_uInt16>( SwWW8Writer::FillUntil( m_rWrt.Strm() ) >> 9 );
1033
1034 for(const std::unique_ptr<WW8_WrFkp> & rp : m_Fkps)
1035 {
1036 rp->Write( m_rWrt.Strm(), *m_rWrt.m_pGrf );
1037 }
1038
1039 if( CHP == m_ePlc )
1040 {
1041 m_rWrt.m_pFib->m_pnChpFirst = m_nFkpStartPage;
1042 m_rWrt.m_pFib->m_cpnBteChp = m_Fkps.size();
1043 }
1044 else
1045 {
1046 m_rWrt.m_pFib->m_pnPapFirst = m_nFkpStartPage;
1047 m_rWrt.m_pFib->m_cpnBtePap = m_Fkps.size();
1048 }
1049}
1050
1052{
1053 sal_uInt64 nFcStart = m_rWrt.m_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 == m_ePlc )
1072 {
1073 m_rWrt.m_pFib->m_fcPlcfbteChpx = nFcStart;
1074 m_rWrt.m_pFib->m_lcbPlcfbteChpx = m_rWrt.m_pTableStrm->Tell() - nFcStart;
1075 }
1076 else
1077 {
1078 m_rWrt.m_pFib->m_fcPlcfbtePapx = nFcStart;
1079 m_rWrt.m_pFib->m_lcbPlcfbtePapx = m_rWrt.m_pTableStrm->Tell() - nFcStart;
1080 }
1081}
1082
1084 : m_ePlc(ePl), m_nStartGrp(511), m_nOldStartGrp(511),
1085 m_nItemSize( ( CHP == ePl ) ? 1 : 13 ),
1086 m_nIMax(0), m_nOldVarLen(0), m_bCombined(false)
1087{
1088 m_pFkp = reinterpret_cast<sal_uInt8*>(new sal_Int32[128]); // 512 Byte
1089 m_pOfs = reinterpret_cast<sal_uInt8*>(new sal_Int32[128]); // 512 Byte
1090 memset( m_pFkp, 0, 4 * 128 );
1091 memset( m_pOfs, 0, 4 * 128 );
1092 reinterpret_cast<sal_Int32*>(m_pFkp)[0] = nStartFc; // 0th entry FC at nStartFc
1093}
1094
1096{
1097 delete[] reinterpret_cast<sal_Int32 *>(m_pFkp);
1098 delete[] reinterpret_cast<sal_Int32 *>(m_pOfs);
1099}
1100
1101sal_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 < m_nIMax; i++ )
1115 {
1116 sal_uInt8 nStart = m_pOfs[i * m_nItemSize];
1117 if( nStart )
1118 { // has Sprms
1119 const sal_uInt8* p = m_pFkp + ( o3tl::narrowing<sal_uInt16>(nStart) << 1 );
1120 if( ( CHP == m_ePlc
1121 ? (*p++ == nVarLen)
1122 : ((o3tl::narrowing<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 (!m_bCombined)
1136 pStart = m_pOfs;
1137 else
1138 pStart = m_pFkp + ( m_nIMax + 1 ) * 4;
1139
1140 sal_uInt8 nStart = *(pStart + (m_nIMax-1) * m_nItemSize);
1141
1142 const sal_uInt8* p = m_pFkp + ( o3tl::narrowing<sal_uInt16>(nStart) << 1 );
1143
1144 if (!*p)
1145 p++;
1146
1147 if (*p)
1148 {
1149 rLen = *p++;
1150 if (PAP == m_ePlc)
1151 rLen *= 2;
1152 pRet = new sal_uInt8[rLen];
1153 memcpy(pRet,p,rLen);
1154 }
1155 return pRet;
1156}
1157
1158bool 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 < ( ( m_ePlc == PAP ) ? 497U : 502U ), "Sprms too long !" );
1163
1164 if( m_bCombined )
1165 {
1166 OSL_ENSURE( false, "Fkp::Append: Fkp is already combined" );
1167 return false;
1168 }
1169 sal_Int32 n = reinterpret_cast<sal_Int32*>(m_pFkp)[m_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 = m_nStartGrp;
1183 if (nVarLen && !nOldP)
1184 {
1185 nPos = PAP == m_ePlc
1186 ? ( 13 == m_nItemSize // HACK: PAP and bWrtWW8 !!
1187 ? (m_nStartGrp & 0xFFFE ) - nVarLen - 1
1188 : (m_nStartGrp - (((nVarLen + 1) & 0xFFFE)+1)) & 0xFFFE )
1189 : ((m_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) <= ( m_nIMax + 2U ) * 4U + ( m_nIMax + 1U ) * m_nItemSize )
1197 // does it fits after the CPs and offsets?
1198 return false; // no
1199
1200 reinterpret_cast<sal_Int32*>(m_pFkp)[m_nIMax + 1] = nEndFc; // insert FC
1201
1202 m_nOldVarLen = static_cast<sal_uInt8>(nVarLen);
1203 if( nVarLen && !nOldP )
1204 { // insert it for real
1206
1207 m_nStartGrp = nPos;
1208 m_pOfs[m_nIMax * m_nItemSize] = static_cast<sal_uInt8>( m_nStartGrp >> 1 );
1209 // insert (start-of-data >> 1)
1210 sal_uInt8 nCnt = static_cast< sal_uInt8 >(CHP == m_ePlc
1211 ? ( nVarLen < 256 ) ? static_cast<sal_uInt8>(nVarLen) : 255
1212 : ( ( nVarLen + 1 ) >> 1 ));
1213
1214 m_pFkp[ nOffset ] = nCnt; // Enter data length
1215 memcpy( m_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 m_pOfs[m_nIMax * m_nItemSize] = nOldP;
1222 }
1223 m_nIMax++;
1224 return true;
1225}
1226
1228{
1229 if( m_bCombined )
1230 return;
1231 if( m_nIMax )
1232 memcpy( m_pFkp + ( m_nIMax + 1 ) * 4, m_pOfs, m_nIMax * m_nItemSize );
1233 delete[] m_pOfs;
1234 m_pOfs = nullptr;
1235 m_pFkp[511] = m_nIMax;
1236 m_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*)m_pFkp; i <= m_nIMax; i++, p++ )
1243 *p = OSL_SWAPDWORD( *p );
1244#endif // ifdef OSL_BIGENDIAN
1245}
1246
1248{
1249 Combine(); // If not already combined
1250
1251 sal_uInt8* p; // search magic for nPicLocFc
1252 sal_uInt8* pEnd = m_pFkp + m_nStartGrp;
1253 for( p = m_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(m_pFkp, 512);
1267}
1268
1269void WW8_WrFkp::MergeToNew( short& rVarLen, sal_uInt8 *& rpNewSprms )
1270{
1271 sal_uInt8 nStart = m_pOfs[ (m_nIMax-1) * m_nItemSize ];
1272 if( !nStart )
1273 return;
1274
1275// has Sprms
1276 sal_uInt8* p = m_pFkp + ( o3tl::narrowing<sal_uInt16>(nStart) << 1 );
1277
1278 // old and new equal? Then copy only one into the new sprms
1279 if( m_nOldVarLen == rVarLen && !memcmp( p+1, rpNewSprms, m_nOldVarLen ))
1280 {
1281 sal_uInt8* pNew = new sal_uInt8[ m_nOldVarLen ];
1282 memcpy( pNew, p+1, m_nOldVarLen );
1283 rpNewSprms = pNew;
1284 }
1285 else
1286 {
1287 sal_uInt8* pNew = new sal_uInt8[ m_nOldVarLen + rVarLen ];
1288 memcpy( pNew, p+1, m_nOldVarLen );
1289 memcpy( pNew + m_nOldVarLen, rpNewSprms, rVarLen );
1290
1291 rpNewSprms = pNew;
1292 rVarLen = rVarLen + m_nOldVarLen;
1293 }
1294 --m_nIMax;
1295 // if this Sprms don't used from others, remove it
1296 bool bFnd = false;
1297 for (sal_uInt16 n = 0; n < m_nIMax; ++n)
1298 {
1299 if (nStart == m_pOfs[n * m_nItemSize])
1300 {
1301 bFnd = true;
1302 break;
1303 }
1304 }
1305 if (!bFnd)
1306 {
1308 memset( p, 0, m_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( m_bCombined )
1318 return SVBT32ToUInt32( m_pFkp ); // 0. Element
1319 return reinterpret_cast<sal_Int32*>(m_pFkp)[0];
1320}
1321
1323{
1324 if( m_bCombined )
1325 return SVBT32ToUInt32( &(m_pFkp[m_nIMax*4]) ); // nIMax-th SVBT32-Element
1326 return reinterpret_cast<sal_Int32*>(m_pFkp)[m_nIMax];
1327}
1328
1329// Method for managing the piece table
1331 : m_nOldFc(nfcMin)
1332{
1334}
1335
1337{
1338}
1339
1340// Fill the piece and create a new one
1342{
1343 WW8_CP nStartCp = nStartFc - m_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 m_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.m_pTableStrm->Tell(); // Start piece table
1368 rWrt.m_pTableStrm->WriteChar( char(0x02) ); // Status byte PCT
1369 nOldPos = nPctStart + 1; // remember Position
1370 SwWW8Writer::WriteLong( *rWrt.m_pTableStrm, 0 ); // then the length
1371
1372 for (auto const& it : m_Pcts) // ranges
1373 {
1374 SwWW8Writer::WriteLong( *rWrt.m_pTableStrm, it->GetStartCp() );
1375 }
1376
1377 // calculate the last Pos
1378 sal_uLong nStartCp = rWrt.m_pFib->m_fcMac - m_nOldFc;
1379 nStartCp >>= 1; // For Unicode: number of characters / 2
1380 nStartCp += m_Pcts.back()->GetStartCp();
1381 SwWW8Writer::WriteLong( *rWrt.m_pTableStrm, nStartCp );
1382
1383 // piece references
1384 for (auto const& it : m_Pcts)
1385 {
1386 SwWW8Writer::WriteShort(*rWrt.m_pTableStrm, it->GetStatus());
1387 SwWW8Writer::WriteLong(*rWrt.m_pTableStrm, it->GetStartFc());
1388 SwWW8Writer::WriteShort( *rWrt.m_pTableStrm, 0); // PRM=0
1389 }
1390
1391 // entries in the FIB
1392 rWrt.m_pFib->m_fcClx = nPctStart;
1393 nEndPos = rWrt.m_pTableStrm->Tell();
1394 rWrt.m_pFib->m_lcbClx = nEndPos - nPctStart;
1395
1396 // and register the length as well
1397 SwWW8Writer::WriteLong( *rWrt.m_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(m_nOldFc), "FilePos lies in front of last piece" );
1411 OSL_ENSURE( ! m_Pcts.empty(), "Fc2Cp no piece available" );
1412
1413 nFc -= m_nOldFc;
1414 nFc /= 2; // Unicode
1415 return nFc + m_Pcts.back()->GetStartCp();
1416}
1417
1418void WW8Export::AppendBookmarks( const SwTextNode& rNd, sal_Int32 nCurrentPos, sal_Int32 nLen, const SwRedlineData* /*pRedlineData*/ )
1419{
1420 std::vector< const ::sw::mark::IMark* > aArr;
1421 sal_Int32 nContent;
1422 const sal_Int32 nCurrentEnd = nCurrentPos + nLen;
1423 if( !GetWriter().GetBookmarks( rNd, nCurrentPos, nCurrentEnd, aArr ))
1424 return;
1425
1426 SwNodeOffset nNd = rNd.GetIndex();
1427 sal_uLong nSttCP = Fc2Cp( Strm().Tell() );
1428 for(const ::sw::mark::IMark* p : aArr)
1429 {
1430 const ::sw::mark::IMark& rBkmk = *p;
1431 if(dynamic_cast< const ::sw::mark::IFieldmark *>(&rBkmk))
1432 continue;
1433
1434 const SwPosition* pPos = &rBkmk.GetMarkPos();
1435 const SwPosition* pOPos = nullptr;
1436 if(rBkmk.IsExpanded())
1437 pOPos = &rBkmk.GetOtherMarkPos();
1438 if( pOPos && pOPos->GetNode() == pPos->GetNode() &&
1439 pOPos->GetContentIndex() < pPos->GetContentIndex() )
1440 {
1441 pPos = pOPos;
1442 pOPos = &rBkmk.GetMarkPos();
1443 }
1444
1445 if( !pOPos || ( nNd == pPos->GetNodeIndex() &&
1446 ( nContent = pPos->GetContentIndex() ) >= nCurrentPos &&
1447 nContent < nCurrentEnd ) )
1448 {
1449 sal_uLong nCp = nSttCP + pPos->GetContentIndex() - nCurrentPos;
1450 m_pBkmks->Append(nCp, BookmarkToWord(rBkmk.GetName()));
1451 }
1452 if( pOPos && nNd == pOPos->GetNodeIndex() &&
1453 ( nContent = pOPos->GetContentIndex() ) >= nCurrentPos &&
1454 nContent < nCurrentEnd )
1455 {
1456 sal_uLong nCp = nSttCP + pOPos->GetContentIndex() - nCurrentPos;
1457 m_pBkmks->Append(nCp, BookmarkToWord(rBkmk.GetName()));
1458 }
1459 }
1460}
1461
1462void WW8Export::AppendAnnotationMarks(const SwWW8AttrIter& rAttrs, sal_Int32 nCurrentPos, sal_Int32 nLen)
1463{
1464 IMarkVector aMarks;
1465 if (GetAnnotationMarks(rAttrs, nCurrentPos, nCurrentPos + nLen, aMarks))
1466 {
1467 for (const sw::mark::IMark* pMark : aMarks)
1468 {
1469 const sal_Int32 nStart = pMark->GetMarkStart().GetContentIndex();
1470 if (nStart == nCurrentPos)
1471 {
1472 m_pAtn->AddRangeStartPosition(pMark->GetName(), Fc2Cp(Strm().Tell()),
1473 !rAttrs.HasFlysAt(nCurrentPos));
1474 }
1475 }
1476 }
1477}
1478
1480{
1481 std::map<OUString, OUString> aStatements = SwRDFHelper::getTextNodeStatements("urn:bails", rTextNode);
1482 if (!aStatements.empty())
1483 {
1484 WW8_CP nCP = Fc2Cp(Strm().Tell());
1485 m_pFactoids->Append(nCP, nCP, aStatements);
1486 }
1487}
1488
1490{
1491 m_pBkmks->MoveFieldMarks(nFrom, nTo);
1492}
1493
1494void WW8Export::AppendBookmark( const OUString& rName )
1495{
1496 sal_uInt64 nSttCP = Fc2Cp( Strm().Tell() );
1497 m_pBkmks->Append( nSttCP, rName );
1498}
1499
1501{
1502 sal_uInt64 nEndCP = Fc2Cp( Strm().Tell() );
1503 m_pBkmks->Append( nEndCP - 1, rName );
1504}
1505
1506std::unique_ptr<SvxBrushItem> MSWordExportBase::getBackground()
1507{
1508 const SwFrameFormat &rFormat = m_rDoc.GetPageDesc(0).GetMaster();
1509 std::unique_ptr<SvxBrushItem> aBrush = std::make_unique<SvxBrushItem>(RES_BACKGROUND);
1510 SfxItemState eState = rFormat.GetBackgroundState(aBrush);
1511
1512 if (SfxItemState::SET == eState)
1513 {
1514 // The 'color' is set for the first page style - take it and use it as the background color of the entire DOCX
1515 if (aBrush->GetColor() != COL_AUTO)
1516 return aBrush;
1517 }
1518 return nullptr;
1519}
1520
1521// #i120928 collect all the graphics of bullets applied to paragraphs
1523{
1524 m_vecBulletPic.clear();
1525
1526 size_t nCountRule = m_rDoc.GetNumRuleTable().size();
1527 for (size_t n = 0; n < nCountRule; ++n)
1528 {
1529 const SwNumRule &rRule = *( m_rDoc.GetNumRuleTable().at(n) );
1530 sal_uInt16 nLevels = rRule.IsContinusNum() ? 1 : 9;
1531 for (sal_uInt16 nLvl = 0; nLvl < nLevels; ++nLvl)
1532 {
1533 const SwNumFormat &rFormat = rRule.Get(nLvl);
1534 if (SVX_NUM_BITMAP != rFormat.GetNumberingType())
1535 {
1536 continue;
1537 }
1538 const Graphic *pGraf = rFormat.GetBrush()? rFormat.GetBrush()->GetGraphic():nullptr;
1539 if ( pGraf )
1540 {
1541 bool bHas = false;
1542 for (const Graphic* p : m_vecBulletPic)
1543 {
1544 if (p->GetChecksum() == pGraf->GetChecksum())
1545 {
1546 bHas = true;
1547 break;
1548 }
1549 }
1550 if (!bHas)
1551 {
1552 Size aSize(pGraf->GetPrefSize());
1553 if (0 != aSize.Height() && 0 != aSize.Width())
1554 m_vecBulletPic.push_back(pGraf);
1555 }
1556 }
1557 }
1558 }
1559
1560 return m_vecBulletPic.size();
1561}
1562
1564{
1565 for (size_t i = 0; i < m_vecBulletPic.size(); ++i)
1566 {
1567 const MapMode aMapMode(MapUnit::MapTwip);
1568 const Graphic& rGraphic = *m_vecBulletPic[i];
1569 Size aSize(rGraphic.GetPrefSize());
1570 if (MapUnit::MapPixel == rGraphic.GetPrefMapMode().GetMapUnit())
1571 aSize = Application::GetDefaultDevice()->PixelToLogic(aSize, aMapMode);
1572 else
1573 aSize = OutputDevice::LogicToLogic(aSize,rGraphic.GetPrefMapMode(), aMapMode);
1574
1575 if (0 != aSize.Height() && 0 != aSize.Width())
1576 AttrOutput().BulletDefinition(i, rGraphic, aSize);
1577 }
1578}
1579
1580//Export Graphic of Bullets
1582{
1584 if (nCount > 0)
1585 {
1586 SwPosition aPos(rNd);
1587 OUString aPicBullets("_PictureBullets");
1588 AppendBookmark(aPicBullets);
1589 for (int i = 0; i < nCount; i++)
1590 {
1591 ww8::Frame aFrame(*(m_vecBulletPic[i]), aPos);
1592 OutGrfBullets(aFrame);
1593 }
1594 AppendBookmark(aPicBullets);
1595 }
1596}
1597
1600{
1601 if ( !m_pGrf || !m_pChpPlc || !m_pO )
1602 return;
1603
1604 m_pGrf->Insert(rFrame);
1605 m_pChpPlc->AppendFkpEntry( Strm().Tell(), m_pO->size(), m_pO->data() );
1606 m_pO->clear();
1607 // if links...
1608 WriteChar( char(1) );
1609
1610 sal_uInt8 aArr[ 22 ];
1611 sal_uInt8* pArr = aArr;
1612
1613 // sprmCFSpec
1614 Set_UInt16( pArr, 0x855 );
1615 Set_UInt8( pArr, 1 );
1616
1617 Set_UInt16( pArr, 0x083c );
1618 Set_UInt8( pArr, 0x81 );
1619
1620 // sprmCPicLocation
1621 Set_UInt16( pArr, 0x6a03 );
1622 Set_UInt32( pArr, GRF_MAGIC_321 );
1623
1624 //extern nAttrMagicIdx;
1625 --pArr;
1626 Set_UInt8( pArr, nAttrMagicIdx++ );
1627 m_pChpPlc->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr - aArr), aArr );
1628}
1629
1631{
1632 int nIndex = -1;
1633
1634 const Graphic* pGraphic = rBrush.GetGraphic();
1635 if (pGraphic)
1636 {
1637 for (size_t i = 0; i < m_vecBulletPic.size(); ++i)
1638 {
1639 if (m_vecBulletPic[i]->GetChecksum() == pGraphic->GetChecksum())
1640 {
1641 nIndex = i;
1642 break;
1643 }
1644 }
1645 }
1646
1647 return nIndex;
1648}
1649
1651{
1652 WW8Export & rWW8Wrt = *(static_cast<SwWW8Writer&>(rWrt).m_pExport);
1653 rWW8Wrt.WriteAsStringTable(maAuthors, rWW8Wrt.m_pFib->m_fcSttbfRMark,
1654 rWW8Wrt.m_pFib->m_lcbSttbfRMark);
1655}
1656
1657sal_uInt16 WW8Export::AddRedlineAuthor( std::size_t nId )
1658{
1659 if( !m_pRedlAuthors )
1660 {
1662 m_pRedlAuthors->AddName("Unknown");
1663 }
1664 return m_pRedlAuthors->AddName( SW_MOD()->GetRedlineAuthor( nId ) );
1665}
1666
1667void WW8Export::WriteAsStringTable(const std::vector<OUString>& rStrings,
1668 sal_Int32& rfcSttbf, sal_Int32& rlcbSttbf)
1669{
1670 sal_uInt16 n, nCount = static_cast< sal_uInt16 >(rStrings.size());
1671 if( !nCount )
1672 return;
1673
1674 // we have some Redlines found in the document -> the
1675 // Author Name Stringtable
1677 rfcSttbf = rStrm.Tell();
1680 for( n = 0; n < nCount; ++n )
1681 {
1682 const OUString& rNm = rStrings[n];
1683 SwWW8Writer::WriteShort( rStrm, rNm.getLength() );
1684 SwWW8Writer::WriteString16(rStrm, rNm, false);
1685 }
1686 rlcbSttbf = rStrm.Tell() - rfcSttbf;
1687}
1688
1689// WriteShort() sets at FilePos nPos the value nVal and seeks to the old
1690// FilePos. Used to insert lengths after the fact.
1691void SwWW8Writer::WriteShort( SvStream& rStrm, sal_uLong nPos, sal_Int16 nVal )
1692{
1693 sal_uInt64 nOldPos = rStrm.Tell(); // remember Pos
1694 rStrm.Seek( nPos );
1696 rStrm.Seek( nOldPos );
1697}
1698
1699void SwWW8Writer::WriteLong( SvStream& rStrm, sal_uLong nPos, sal_Int32 nVal )
1700{
1701 sal_uInt64 nOldPos = rStrm.Tell(); // remember Pos
1702 rStrm.Seek( nPos );
1704 rStrm.Seek( nOldPos );
1705}
1706
1707void SwWW8Writer::InsUInt16(ww::bytes &rO, sal_uInt16 n)
1708{
1709 SVBT16 nL;
1710 ShortToSVBT16( n, nL );
1711 rO.push_back(nL[0]);
1712 rO.push_back(nL[1]);
1713}
1714
1715void SwWW8Writer::InsUInt32(ww::bytes &rO, sal_uInt32 n)
1716{
1717 SVBT32 nL;
1718 UInt32ToSVBT32( n, nL );
1719 rO.push_back(nL[0]);
1720 rO.push_back(nL[1]);
1721 rO.push_back(nL[2]);
1722 rO.push_back(nL[3]);
1723}
1724
1725void SwWW8Writer::InsAsString16(ww::bytes &rO, const OUString& rStr)
1726{
1727 const sal_Unicode* pStr = rStr.getStr();
1728 for (sal_Int32 n = 0, nLen = rStr.getLength(); n < nLen; ++n, ++pStr)
1729 SwWW8Writer::InsUInt16( rO, *pStr );
1730}
1731
1732void SwWW8Writer::InsAsString8(ww::bytes &rO, std::u16string_view rStr,
1733 rtl_TextEncoding eCodeSet)
1734{
1735 OString sTmp(OUStringToOString(rStr, eCodeSet));
1736 const char *pStart = sTmp.getStr();
1737 const char *pEnd = pStart + sTmp.getLength();
1738
1739 rO.insert( rO.end(), pStart, pEnd );
1740}
1741
1742void SwWW8Writer::WriteString16(SvStream& rStrm, const OUString& rStr,
1743 bool bAddZero)
1744{
1745 ww::bytes aBytes;
1746 SwWW8Writer::InsAsString16(aBytes, rStr);
1747 if (bAddZero)
1748 SwWW8Writer::InsUInt16(aBytes, 0);
1749 //vectors are guaranteed to have contiguous memory, so we can do
1750 //this while migrating away from WW8Bytes. Meyers Effective STL, item 16
1751 if (!aBytes.empty())
1752 rStrm.WriteBytes(aBytes.data(), aBytes.size());
1753}
1754
1755void SwWW8Writer::WriteString_xstz(SvStream& rStrm, const OUString& rStr, bool bAddZero)
1756{
1757 ww::bytes aBytes;
1758 SwWW8Writer::InsUInt16(aBytes, rStr.getLength());
1759 SwWW8Writer::InsAsString16(aBytes, rStr);
1760 if (bAddZero)
1761 SwWW8Writer::InsUInt16(aBytes, 0);
1762 rStrm.WriteBytes(aBytes.data(), aBytes.size());
1763}
1764
1765void SwWW8Writer::WriteString8(SvStream& rStrm, std::u16string_view rStr,
1766 bool bAddZero, rtl_TextEncoding eCodeSet)
1767{
1768 ww::bytes aBytes;
1769 SwWW8Writer::InsAsString8(aBytes, rStr, eCodeSet);
1770 if (bAddZero)
1771 aBytes.push_back(0);
1772 //vectors are guaranteed to have contiguous memory, so we can do
1774 if (!aBytes.empty())
1775 rStrm.WriteBytes(aBytes.data(), aBytes.size());
1776}
1777
1778void WW8Export::WriteStringAsPara( const OUString& rText )
1779{
1780 if( !rText.isEmpty() )
1781 OutSwString(rText, 0, rText.getLength());
1782 WriteCR(); // CR thereafter
1783
1785 SwWW8Writer::InsUInt16( aArr, 0/*nStyleId*/ );
1786 if( m_bOutTable )
1787 { // Tab-Attr
1788 // sprmPFInTable
1790 aArr.push_back( 1 );
1791 }
1792
1793 sal_uInt64 nPos = Strm().Tell();
1794 m_pPapPlc->AppendFkpEntry( nPos, aArr.size(), aArr.data() );
1795 m_pChpPlc->AppendFkpEntry( nPos );
1796}
1797
1799{
1800 sal_uInt8 nOldTyp = m_nTextTyp;
1801 m_nTextTyp = nTTyp;
1802 auto const pOldPam = m_pCurPam;
1803 SwNodeOffset nOldStart = m_nCurStart;
1804 SwNodeOffset nOldEnd = m_nCurEnd;
1805 SwPaM* pOldEnd = m_pOrigPam;
1806 bool bOldPageDescs = m_bOutPageDescs;
1807 m_bOutPageDescs = false;
1808 if ( nTTyp == TXT_FTN || nTTyp == TXT_EDN )
1809 m_bAddFootnoteTab = true; // enable one aesthetic tab for this footnote
1810
1811 SetCurPam(nStart, nEnd);
1812
1813 // clear linked textboxes since old ones can't be linked to frames in this section
1815
1816 // tdf#106261 Reset table infos, otherwise the depth of the cells will be
1817 // incorrect, in case the header/footer had table(s) and we try to export
1818 // the same table second time.
1820 m_pTableInfo = std::make_shared<ww8::WW8TableInfo>();
1821
1822 WriteText();
1823
1824 m_pTableInfo = pOldTableInfo;
1825
1826 m_bOutPageDescs = bOldPageDescs;
1827 m_pCurPam = pOldPam; // delete Pam
1828 m_nCurStart = nOldStart;
1829 m_nCurEnd = nOldEnd;
1830 m_pOrigPam = pOldEnd;
1831 m_nTextTyp = nOldTyp;
1832}
1833
1834void WW8Export::OutSwString(const OUString& rStr, sal_Int32 nStt,
1835 sal_Int32 const nLen)
1836
1837{
1838 SAL_INFO( "sw.ww8.level2", "<OutSwString>" );
1839
1840 if( nLen )
1841 {
1842 if( nStt || nLen != rStr.getLength() )
1843 {
1844 OUString sOut( rStr.copy( nStt, nLen ) );
1845
1846 SAL_INFO( "sw.ww8.level2", sOut );
1847
1848 SwWW8Writer::WriteString16(Strm(), sOut, false);
1849 }
1850 else
1851 {
1852 SAL_INFO( "sw.ww8.level2", rStr );
1853
1854 SwWW8Writer::WriteString16(Strm(), rStr, false);
1855 }
1856 }
1857
1858 SAL_INFO( "sw.ww8.level2", "</OutSwString>" );
1859}
1860
1862{
1863 if (pTableTextNodeInfoInner && pTableTextNodeInfoInner->getDepth() == 1 && pTableTextNodeInfoInner->isEndOfCell())
1864 WriteChar('\007');
1865 else
1866 WriteChar( '\015' );
1867
1868 m_pPiece->SetParaBreak();
1869}
1870
1872{
1873 Strm().WriteUInt16( c );
1874}
1875
1877{
1878 m_nCurStart = nStt;
1879 m_nCurEnd = nEnd;
1880 m_pCurPam = Writer::NewUnoCursor( m_rDoc, nStt, nEnd );
1881
1882 // Recognize tables in special cases
1883 if ( nStt != m_pCurPam->GetMark()->GetNodeIndex() &&
1884 m_rDoc.GetNodes()[ nStt ]->IsTableNode() )
1885 {
1886 m_pCurPam->GetMark()->Assign(nStt);
1887 }
1888
1889 m_pOrigPam = m_pCurPam.get(); // ???
1890 m_pCurPam->Exchange();
1891}
1892
1894{
1896
1897 // WW8Export only stuff - zeroed here not to issue warnings
1898 aData.pOOld = nullptr;
1899
1900 // Common stuff
1901 aData.pOldPam = m_pCurPam;
1902 aData.pOldEnd = m_pOrigPam;
1903 aData.pOldFlyFormat = m_pParentFrame;
1904 aData.pOldPageDesc = m_pCurrentPageDesc;
1905
1906 aData.pOldFlyOffset = m_pFlyOffset;
1907 aData.eOldAnchorType = m_eNewAnchorType;
1908
1909 aData.bOldOutTable = m_bOutTable;
1910 aData.bOldFlyFrameAttrs = m_bOutFlyFrameAttrs;
1911 aData.bOldStartTOX = m_bStartTOX;
1912 aData.bOldInWriteTOX = m_bInWriteTOX;
1913
1914 SetCurPam(nStt, nEnd);
1915
1916 m_bOutTable = false;
1917 // Caution: bIsInTable should not be set here
1918 m_bOutFlyFrameAttrs = false;
1919 m_bStartTOX = false;
1920 m_bInWriteTOX = false;
1921
1922 m_aSaveData.push( std::move(aData) );
1923}
1924
1926{
1927 MSWordSaveData &rData = m_aSaveData.top();
1928
1929 m_pCurPam = rData.pOldPam;
1930 m_nCurStart = rData.nOldStart;
1931 m_nCurEnd = rData.nOldEnd;
1932 m_pOrigPam = rData.pOldEnd;
1933
1934 m_bOutTable = rData.bOldOutTable;
1936 m_bStartTOX = rData.bOldStartTOX;
1938
1941
1944
1945 m_aSaveData.pop();
1946}
1947
1949{
1950 MSWordExportBase::SaveData( nStt, nEnd );
1951
1952 MSWordSaveData &rData = m_aSaveData.top();
1953
1954 if ( !m_pO->empty() )
1955 {
1956 rData.pOOld = std::move(m_pO);
1957 m_pO.reset(new ww::bytes);
1958 }
1959 else
1960 rData.pOOld = nullptr; // reuse pO
1961
1963 GetWriter().m_bWriteAll = true;
1964}
1965
1967{
1968 MSWordSaveData &rData = m_aSaveData.top();
1969
1971
1972 OSL_ENSURE( m_pO->empty(), "pO is not empty in WW8Export::RestoreData()" );
1973 if ( rData.pOOld )
1974 {
1975 m_pO = std::move(rData.pOOld);
1976 }
1977
1979}
1980
1982{
1983 sal_uInt32 nDepth = pTableTextNodeInfoInner->getDepth();
1984
1985 if ( nDepth <= 0 )
1986 return;
1987
1988 /* Cell */
1990 m_rWW8Export.m_pO->push_back( sal_uInt8(0x1) );
1992 m_rWW8Export.InsUInt32( nDepth );
1993
1994 if ( nDepth > 1 && pTableTextNodeInfoInner->isEndOfCell() )
1995 {
1997 m_rWW8Export.m_pO->push_back( sal_uInt8(0x1) );
1998 }
1999}
2000
2002{
2003 sal_uInt32 nDepth = pTableTextNodeInfoInner->getDepth();
2004
2005 if ( nDepth <= 0 )
2006 return;
2007
2008 /* Row */
2009 if ( !pTableTextNodeInfoInner->isEndOfLine() )
2010 return;
2011
2013 m_rWW8Export.m_pO->push_back( sal_uInt8(0x1) );
2014
2015 if ( nDepth == 1 )
2016 {
2018 m_rWW8Export.m_pO->push_back( sal_uInt8(0x1) );
2019 }
2020
2022 m_rWW8Export.InsUInt32( nDepth );
2023
2024 if ( nDepth > 1 )
2025 {
2027 m_rWW8Export.m_pO->push_back( sal_uInt8(0x1) );
2029 m_rWW8Export.m_pO->push_back( sal_uInt8(0x1) );
2030 }
2031
2032 // Most of these are per-row definitions, not per-table.
2033 // WW8 has no explicit table start/end markup,
2034 // simply rows with the same table properties that are grouped together as a table.
2035 TableBidi( pTableTextNodeInfoInner );
2036 TableOrientation( pTableTextNodeInfoInner );
2037 TableSpacing( pTableTextNodeInfoInner );
2038 TableDefinition( pTableTextNodeInfoInner ); //per row definitions
2039 TableHeight( pTableTextNodeInfoInner ); //per row definitions
2040 TableBackgrounds( pTableTextNodeInfoInner ); //per row definitions
2041 // Since this isEndOfLine, cell margin defaults for each row come from last column.
2042 TableDefaultBorders( pTableTextNodeInfoInner ); //per row definitions
2043 TableCanSplit( pTableTextNodeInfoInner ); //per row definitions
2044 TableVerticalCell( pTableTextNodeInfoInner ); //per row definitions
2045 TableCellBorders( pTableTextNodeInfoInner ); //per row definitions
2046}
2047
2048static sal_uInt16 lcl_TCFlags(SwDoc &rDoc, const SwTableBox * pBox, sal_Int32 nRowSpan)
2049{
2050 sal_uInt16 nFlags = 0;
2051
2052 if (nRowSpan > 1)
2053 nFlags |= (3 << 5);
2054 else if (nRowSpan < 0)
2055 nFlags |= (1 << 5);
2056
2057 if (pBox != nullptr)
2058 {
2059 const SwFrameFormat * pFormat = pBox->GetFrameFormat();
2060 switch (pFormat->GetVertOrient().GetVertOrient())
2061 {
2062 case text::VertOrientation::CENTER:
2063 nFlags |= (1 << 7);
2064 break;
2065 case text::VertOrientation::BOTTOM:
2066 nFlags |= (2 << 7);
2067 break;
2068 default:
2069 break;
2070 }
2071 const SwStartNode * pSttNd = pBox->GetSttNd();
2072 if(pSttNd)
2073 {
2074 SwNodeIndex aIdx( *pSttNd );
2075 const SwContentNode * pCNd = pSttNd->GetNodes().GoNext( &aIdx );
2076 if( pCNd && pCNd->IsTextNode())
2077 {
2079 static_cast<const SwTextNode*>(pCNd)->GetParaAttr(aCoreSet,
2080 0, static_cast<const SwTextNode*>(pCNd)->GetText().getLength());
2081 if ( const SvxCharRotateItem * pRotate = aCoreSet.GetItemIfSet(RES_CHRATR_ROTATE))
2082 {
2083 if(pRotate && pRotate->GetValue() == 900_deg10)
2084 {
2085 nFlags = nFlags | 0x0004 | 0x0008;
2086 }
2087 else if(pRotate && pRotate->GetValue() == 2700_deg10 )
2088 {
2089 nFlags = nFlags | 0x0004 | 0x0010;
2090 }
2091 }
2092 }
2093 }
2094 }
2095
2096 return nFlags;
2097}
2098
2100{
2101 const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
2102 const SwTableLine * pTabLine = pTabBox->GetUpper();
2103 const SwTableBoxes & rTableBoxes = pTabLine->GetTabBoxes();
2104
2105 sal_uInt8 nBoxes = rTableBoxes.size();
2106 for ( sal_uInt8 n = 0; n < nBoxes; n++ )
2107 {
2108 const SwTableBox * pTabBox1 = rTableBoxes[n];
2109 const SwFrameFormat * pFrameFormat = pTabBox1->GetFrameFormat();
2110
2111 // Map from our SvxFrameDirection to WW8 TextFlow.
2112 sal_uInt16 nTextFlow = 0;
2113 switch (m_rWW8Export.TrueFrameDirection(*pFrameFormat))
2114 {
2115 case SvxFrameDirection::Vertical_RL_TB:
2116 nTextFlow = 5;
2117 break;
2118 case SvxFrameDirection::Vertical_LR_BT:
2119 nTextFlow = 3;
2120 break;
2121 default:
2122 break;
2123 }
2124
2125 if (nTextFlow != 0)
2126 {
2128 m_rWW8Export.m_pO->push_back( n ); //start range
2129 m_rWW8Export.m_pO->push_back( sal_uInt8(n + 1) ); //end range
2130 m_rWW8Export.InsUInt16(nTextFlow);
2131 }
2132 }
2133}
2134
2136{
2137 const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
2138 const SwTableLine * pTabLine = pTabBox->GetUpper();
2139 const SwFrameFormat * pLineFormat = pTabLine->GetFrameFormat();
2140
2141 /*
2142 By default the row can be split in word, and now in writer we have a
2143 feature equivalent to this, Word stores 1 for fCantSplit if the row
2144 cannot be split, we set true if we can split it. An example is #i4569#
2145 */
2146
2147 const SwFormatRowSplit& rSplittable = pLineFormat->GetRowSplit();
2148 sal_uInt8 nCantSplit = (!rSplittable.GetValue()) ? 1 : 0;
2150 m_rWW8Export.m_pO->push_back( nCantSplit );
2151 m_rWW8Export.InsUInt16( NS_sprm::TFCantSplit90::val ); // also write fCantSplit90
2152 m_rWW8Export.m_pO->push_back( nCantSplit );
2153}
2154
2156{
2157 const SwTable * pTable = pTableTextNodeInfoInner->getTable();
2158 const SwFrameFormat * pFrameFormat = pTable->GetFrameFormat();
2159
2160 if ( m_rWW8Export.TrueFrameDirection(*pFrameFormat) == SvxFrameDirection::Horizontal_RL_TB )
2161 {
2164 }
2165}
2166
2168{
2169}
2170
2172{
2173}
2174
2176{
2177 const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
2178 const SwTableLine * pTabLine = pTabBox->GetUpper();
2179 const SwFrameFormat * pLineFormat = pTabLine->GetFrameFormat();
2180
2181 // output line height sprmTDyaRowHeight
2182 tools::Long nHeight = 0;
2183 const SwFormatFrameSize& rLSz = pLineFormat->GetFrameSize();
2184 if ( SwFrameSize::Variable != rLSz.GetHeightSizeType() && rLSz.GetHeight() )
2185 {
2187 nHeight = rLSz.GetHeight();
2188 else
2189 nHeight = -rLSz.GetHeight();
2190 }
2191
2192 if ( nHeight )
2193 {
2195 m_rWW8Export.InsUInt16( o3tl::narrowing<sal_uInt16>(nHeight) );
2196 }
2197
2198}
2199
2201{
2202 const SwTable * pTable = pTableTextNodeInfoInner->getTable();
2203
2204 const SwFrameFormat *pFormat = pTable->GetFrameFormat();
2205 if ( !pFormat )
2206 {
2207 SAL_WARN( "sw.ww8", "FrameFormat is nil" );
2208 return;
2209 }
2210
2211 const SwFormatHoriOrient &rHori = pFormat->GetHoriOrient();
2212 const SwFormatVertOrient &rVert = pFormat->GetVertOrient();
2213
2214 if (
2215 !((text::RelOrientation::PRINT_AREA == rHori.GetRelationOrient() ||
2216 text::RelOrientation::FRAME == rHori.GetRelationOrient())
2217 &&
2218 (text::RelOrientation::PRINT_AREA == rVert.GetRelationOrient() ||
2219 text::RelOrientation::FRAME == rVert.GetRelationOrient()))
2220 )
2221 return;
2222
2223 const bool bIsRTL = m_rWW8Export.TrueFrameDirection(*pFormat) == SvxFrameDirection::Horizontal_RL_TB;
2224 sal_Int16 eHOri = rHori.GetHoriOrient();
2225 switch (eHOri)
2226 {
2227 case text::HoriOrientation::CENTER:
2228 m_rWW8Export.InsUInt16( NS_sprm::TJc::val ); //logical orientation required for MSO
2230 m_rWW8Export.InsUInt16( NS_sprm::TJc90::val ); //physical orientation required for LO
2232 break;
2233 case text::HoriOrientation::RIGHT:
2234 m_rWW8Export.InsUInt16( NS_sprm::TJc90::val ); //required for LO
2236 if ( !bIsRTL )
2237 {
2238 m_rWW8Export.InsUInt16( NS_sprm::TJc::val ); //required for MSO
2240 }
2241 break;
2242 case text::HoriOrientation::LEFT:
2243 if ( bIsRTL )
2244 {
2245 m_rWW8Export.InsUInt16( NS_sprm::TJc::val ); //required for MSO
2247 }
2248 break;
2249 case text::HoriOrientation::LEFT_AND_WIDTH:
2250 // Width can only be specified for the LOGICAL left, so in RTL, that is always PHYSICAL right
2251 if ( bIsRTL )
2252 {
2253 m_rWW8Export.InsUInt16( NS_sprm::TJc90::val ); //required for LO
2255 }
2256 break;
2257 default:
2258 break;
2259 }
2260}
2261
2263{
2264 const SwTable * pTable = pTableTextNodeInfoInner->getTable();
2265 const SwTableFormat* pTableFormat = pTable->GetFrameFormat();
2266
2267
2268 // Writing these SPRM's will make the table a floating one, so only write
2269 // them in case the table is already inside a frame.
2270 if (!(pTableFormat != nullptr && pTable->GetTableNode()->GetFlyFormat()))
2271 return;
2272
2273 const SvxULSpaceItem & rUL = pTableFormat->GetULSpace();
2274
2275 if (rUL.GetUpper() > 0)
2276 {
2277 sal_uInt8 const nPadding = 2;
2278 sal_uInt8 const nPcVert = 0;
2279 sal_uInt8 const nPcHorz = 0;
2280
2281 sal_uInt8 const nTPc = (nPadding << 4) | (nPcVert << 2) | nPcHorz;
2282
2284 m_rWW8Export.m_pO->push_back( nTPc );
2285
2288
2291 }
2292
2293 if (rUL.GetLower() > 0)
2294 {
2297 }
2298}
2299
2301{
2302 const SwTable * pTable = pTableTextNodeInfoInner->getTable();
2303
2304 if ( pTable->GetRowsToRepeat() > pTableTextNodeInfoInner->getRow() )
2305 {
2307 m_rWW8Export.m_pO->push_back( 1 );
2308 }
2309
2310 ww8::TableBoxVectorPtr pTableBoxes =
2311 pTableTextNodeInfoInner->getTableBoxesOfRow();
2312 // number of cell written
2313 sal_uInt32 nBoxes = pTableBoxes->size();
2314 assert(nBoxes <= ww8::MAXTABLECELLS);
2315
2316 // sprm header
2318 sal_uInt16 nSprmSize = 2 + (nBoxes + 1) * 2 + nBoxes * 20;
2319 m_rWW8Export.InsUInt16( nSprmSize ); // length
2320
2321 // number of boxes
2322 m_rWW8Export.m_pO->push_back( static_cast<sal_uInt8>(nBoxes) );
2323
2324 /* cells */
2325 /*
2326 ALWAYS relative when text::HoriOrientation::NONE (nPageSize + ( nPageSize / 10 )) < nTableSz,
2327 in that case the cell width's and table width's are not real. The table
2328 width is maxed and cells relative, so we need the frame (generally page)
2329 width that the table is in to work out the true widths.
2330 */
2331 //const bool bNewTableModel = pTable->IsNewModel();
2332 const SwFrameFormat *pFormat = pTable->GetFrameFormat();
2333 if ( !pFormat )
2334 {
2335 SAL_WARN( "sw.ww8", "FrameFormat is nil" );
2336 return;
2337 }
2338
2339 const SwFormatHoriOrient &rHori = pFormat->GetHoriOrient();
2340 const SwFormatVertOrient &rVert = pFormat->GetVertOrient();
2341
2342 SwTwips nTableOffset = 0;
2343
2344 if (
2345 (text::RelOrientation::PRINT_AREA == rHori.GetRelationOrient() ||
2346 text::RelOrientation::FRAME == rHori.GetRelationOrient())
2347 &&
2348 (text::RelOrientation::PRINT_AREA == rVert.GetRelationOrient() ||
2349 text::RelOrientation::FRAME == rVert.GetRelationOrient())
2350 )
2351 {
2352 sal_Int16 eHOri = rHori.GetHoriOrient();
2353 switch ( eHOri )
2354 {
2355 case text::HoriOrientation::CENTER:
2356 case text::HoriOrientation::RIGHT:
2357 break;
2358
2359 default:
2360 nTableOffset = rHori.GetPos();
2361 const SvxLRSpaceItem& rLRSp = pFormat->GetLRSpace();
2362 nTableOffset += rLRSp.GetLeft();
2363
2364 // convert offset to be measured from right margin in right-to-left tables
2365 if ( nTableOffset && m_rWW8Export.TrueFrameDirection(*pFormat) == SvxFrameDirection::Horizontal_RL_TB )
2366 {
2367 SwTwips nLeftPageMargin, nRightPageMargin;
2368 const SwTwips nPageSize = m_rWW8Export.CurrentPageWidth(nLeftPageMargin, nRightPageMargin);
2369 const SwTwips nTableWidth = pFormat->GetFrameSize().GetWidth();
2370 nTableOffset = nPageSize - nLeftPageMargin - nRightPageMargin - nTableWidth - nTableOffset;
2371 }
2372 break;
2373 }
2374 }
2375
2376 m_rWW8Export.InsInt16( nTableOffset );
2377
2378 ww8::GridColsPtr pGridCols = GetGridCols( pTableTextNodeInfoInner );
2379 for ( const auto nCol : *pGridCols )
2380 {
2381 m_rWW8Export.InsUInt16( o3tl::narrowing<sal_uInt16>(nCol) + nTableOffset );
2382 }
2383
2384 /* TCs */
2385 ww8::RowSpansPtr pRowSpans = pTableTextNodeInfoInner->getRowSpansOfRow();
2386 ww8::RowSpans::const_iterator aItRowSpans = pRowSpans->begin();
2387
2388 for (const SwTableBox * pTabBox1 : *pTableBoxes)
2389 {
2390 sal_uInt16 npOCount = m_rWW8Export.m_pO->size();
2391
2392 const SwFrameFormat * pBoxFormat = nullptr;
2393 if (pTabBox1 != nullptr)
2394 pBoxFormat = pTabBox1->GetFrameFormat();
2395
2396 sal_uInt16 nFlags =
2397 lcl_TCFlags(m_rWW8Export.m_rDoc, pTabBox1, *aItRowSpans);
2398 m_rWW8Export.InsUInt16( nFlags );
2399
2400 static sal_uInt8 aNullBytes[] = { 0x0, 0x0 };
2401
2402 m_rWW8Export.m_pO->insert( m_rWW8Export.m_pO->end(), aNullBytes, aNullBytes+2 ); // dummy
2403 if (pBoxFormat != nullptr)
2404 {
2405 const SvxBoxItem & rBoxItem = pBoxFormat->GetBox();
2406
2408 }
2409 else
2410 WW8Export::Out_SwFormatTableBox( *m_rWW8Export.m_pO, nullptr); // 8/16 Byte
2411
2412 SAL_INFO( "sw.ww8.level2", "<tclength>" << ( m_rWW8Export.m_pO->size() - npOCount ) << "</tclength>" );
2413 ++aItRowSpans;
2414 }
2415
2416 int nWidthPercent = pFormat->GetFrameSize().GetWidthPercent();
2417
2418 // The best fit for "automatic" table placement is relative 100%
2419 if (!nWidthPercent && rHori.GetHoriOrient() == text::HoriOrientation::FULL)
2420 nWidthPercent = 100;
2421
2422 // Width is in fiftieths of a percent. For sprmTTableWidth, must be non-negative and 600% max
2423 if ( nWidthPercent > 0 && nWidthPercent <= 600 )
2424 {
2426 m_rWW8Export.m_pO->push_back( sal_uInt8/*ftsPercent*/ (2) );
2427 m_rWW8Export.InsUInt16( o3tl::narrowing<sal_uInt16>(nWidthPercent) * 50 );
2428 }
2429}
2430
2432{
2433 return pTableTextNodeInfoInner->getGridColsOfRow(*this);
2434}
2435
2437{
2438 // Get the column widths based on ALL the rows, not just the current row
2439 return pTableTextNodeInfoInner->getGridColsOfRow(*this, true);
2440}
2441
2442void AttributeOutputBase::GetTablePageSize( ww8::WW8TableNodeInfoInner const * pTableTextNodeInfoInner, tools::Long& rPageSize, bool& rRelBoxSize )
2443{
2444 tools::Long nPageSize = 0;
2445
2446 const SwNode *pTextNd = pTableTextNodeInfoInner->getNode( );
2447 const SwTable *pTable = pTableTextNodeInfoInner->getTable( );
2448
2449 const SwFrameFormat *pFormat = pTable->GetFrameFormat();
2450 if ( !pFormat )
2451 {
2452 SAL_WARN( "sw.ww8", "FrameFormat is nil" );
2453 return;
2454 }
2455
2456 const SwFormatFrameSize &rSize = pFormat->GetFrameSize();
2457 int nWidthPercent = rSize.GetWidthPercent();
2458 bool bManualAligned = pFormat->GetHoriOrient().GetHoriOrient() == text::HoriOrientation::NONE;
2459 if ( (pFormat->GetHoriOrient().GetHoriOrient() == text::HoriOrientation::FULL) || bManualAligned )
2460 nWidthPercent = 100;
2461 bool bRelBoxSize = nWidthPercent != 0;
2462 tools::ULong nTableSz = static_cast<tools::ULong>(rSize.GetWidth());
2463 if (nTableSz > USHRT_MAX/2 && !bRelBoxSize)
2464 {
2465 OSL_ENSURE(bRelBoxSize, "huge table width but not relative, suspicious");
2466 bRelBoxSize = true;
2467 }
2468
2469 if ( bRelBoxSize )
2470 {
2471 Point aPt;
2472 SwRect aRect( pFormat->FindLayoutRect( false, &aPt ) );
2473 if ( aRect.IsEmpty() )
2474 {
2475 // Then fetch the page width without margins!
2476 const SwFrameFormat* pParentFormat =
2479 GetExport().m_rDoc.GetPageDesc(0).GetPageFormatOfNode(*pTextNd, false);
2480 aRect = pParentFormat->FindLayoutRect(true);
2481 nPageSize = aRect.Width();
2482 if ( 0 == nPageSize )
2483 {
2484 const SvxLRSpaceItem& rLR = pParentFormat->GetLRSpace();
2485 nPageSize = pParentFormat->GetFrameSize().GetWidth() - rLR.GetLeft()
2486 - rLR.GetRight();
2487 }
2488 }
2489 else
2490 {
2491 nPageSize = aRect.Width();
2492 if ( bManualAligned )
2493 {
2494 // #i37571# For manually aligned tables
2495 const SvxLRSpaceItem &rLR = pFormat->GetLRSpace();
2496 nPageSize -= (rLR.GetLeft() + rLR.GetRight());
2497 }
2498
2499 }
2500
2501 if ( nWidthPercent )
2502 {
2503 nPageSize *= nWidthPercent;
2504 nPageSize /= 100;
2505 }
2506 else
2507 SAL_WARN( "sw.ww8", "nWidthPercent is zero" );
2508 }
2509 else
2510 {
2511 // As the table width is not relative, the TablePageSize equals its width
2512 nPageSize = nTableSz;
2513 }
2514
2515 rPageSize = nPageSize;
2516 rRelBoxSize = bRelBoxSize;
2517}
2518
2520{
2521 // This function name is misleading because it is not a table default, but a row default,
2522 // and it also only sets default cell margins (aka border padding).
2523 // The specs suggest there is no way to define default border lines/colors.
2524 const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
2525 const SwFrameFormat * pFrameFormat = pTabBox->GetFrameFormat();
2526
2527 static const SvxBoxItemLine aBorders[] =
2528 {
2529 SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
2530 SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT
2531 };
2532
2533 // Set row default cell margins using this last cell in the row
2534 for ( int i = 0; i < 4; ++i )
2535 {
2537 m_rWW8Export.m_pO->push_back( sal_uInt8(6) );
2538 m_rWW8Export.m_pO->push_back( sal_uInt8(0) );
2539 m_rWW8Export.m_pO->push_back( sal_uInt8(1) );
2540 m_rWW8Export.m_pO->push_back( sal_uInt8(1 << i) );
2541 m_rWW8Export.m_pO->push_back( sal_uInt8(3) );
2542
2544 pFrameFormat->GetBox().GetDistance( aBorders[i] ) );
2545 }
2546}
2547
2549 ww8::WW8TableNodeInfoInner::Pointer_t const & pTableTextNodeInfoInner )
2550{
2551 const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
2552 const SwTableLine * pTabLine = pTabBox->GetUpper();
2553 const SwTableBoxes & rTabBoxes = pTabLine->GetTabBoxes();
2554 sal_uInt8 nBoxes = std::min<size_t>(rTabBoxes.size(), 255);
2555 const SvxBoxItem * pLastBox = nullptr;
2556 sal_uInt8 nSeqStart = 0; // start of sequence of cells with same borders
2557
2558 static const SvxBoxItemLine aBorders[] =
2559 {
2560 SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
2561 SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT
2562 };
2563
2564 sal_uInt16 nDefaultMargin[4] = {31681, 31681, 31681, 31681}; // outside of documented valid range
2565 // last column in each row defines the row default in TableRowDefaultBorders()
2566 if ( nBoxes && rTabBoxes.size() == nBoxes )
2567 {
2568 const SvxBoxItem& rBox = rTabBoxes[ nBoxes-1 ]->GetFrameFormat()->GetBox();
2569 for ( int i = 0; i < 4; ++i )
2570 nDefaultMargin[i] = rBox.GetDistance( aBorders[i] );
2571 }
2572
2573 // Detect sequences of cells which have the same borders, and output
2574 // a border description for each such cell range.
2575 for ( unsigned n = 0; n <= nBoxes; ++n )
2576 {
2577 const SvxBoxItem * pBox = (n == nBoxes) ? nullptr :
2578 &rTabBoxes[n]->GetFrameFormat()->GetBox();
2579 if( !pLastBox )
2580 pLastBox = pBox;
2581 else if( !pBox || *pLastBox != *pBox )
2582 {
2583 // This cell has different borders than the previous cell,
2584 // so output the borders for the preceding cell range.
2585 m_rWW8Export.Out_CellRangeBorders(pLastBox, nSeqStart, n);
2586
2587 // The last column is used as the row default for margins, so we can ignore these matching ones
2588 if ( n == nBoxes )
2589 break;
2590
2591 // Output cell margins.
2592 // One CSSA can define up to all four margins if they are the same size value.
2593 sal_uInt16 nMargin[4];
2594 sal_uInt8 nSideBits[4] = {0, 0, 0, 0}; // 0001:top, 0010:left, 0100:bottom, 1000:right
2595 for ( int i = 0; i < 4; ++i ) // sides: top, left, bottom, right
2596 {
2597 nMargin[i] = std::min(sal_Int16(31680), pLastBox->GetDistance( aBorders[i] ));
2598 if ( nMargin[i] == nDefaultMargin[i] )
2599 continue;
2600
2601 // join a previous side's definition if it shares the same value
2602 for ( int p = 0; p < 4; ++p )
2603 {
2604 if ( nMargin[i] == nMargin[p] )
2605 {
2606 nSideBits[p] |= 1 << i;
2607 break;
2608 }
2609 }
2610 }
2611
2612 // write out the cell margins definitions that were used
2613 for ( int i = 0; i < 4; ++i )
2614 {
2615 if ( nSideBits[i] )
2616 {
2618 m_rWW8Export.m_pO->push_back( sal_uInt8(6) ); // 6 bytes
2619 m_rWW8Export.m_pO->push_back( sal_uInt8(nSeqStart) ); // first cell: apply margin
2620 m_rWW8Export.m_pO->push_back( sal_uInt8(n) ); // end cell: do not apply margin
2621 m_rWW8Export.m_pO->push_back( sal_uInt8(nSideBits[i]) );
2622 m_rWW8Export.m_pO->push_back( sal_uInt8(3) ); // FtsDxa: size in twips
2624 }
2625 }
2626
2627 nSeqStart = n;
2628 pLastBox = pBox;
2629 }
2630 }
2631}
2632
2634{
2635 const SwTable * pTab = pTableTextNodeInfoInner->getTable();
2636 const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
2637 const SwTableLine * pTabLine = pTabBox->GetUpper();
2638 const SwTableBoxes & rTabBoxes = pTabLine->GetTabBoxes();
2639
2640 sal_uInt8 nBoxes = rTabBoxes.size();
2642 m_rWW8Export.m_pO->push_back( static_cast<sal_uInt8>(nBoxes * 2) ); // Len
2643
2644 Color aRowColor = COL_AUTO;
2645 const SvxBrushItem *pTableColorProp = pTab->GetFrameFormat()->GetAttrSet().GetItem<SvxBrushItem>(RES_BACKGROUND);
2646 if ( pTableColorProp )
2647 aRowColor = pTableColorProp->GetColor();
2648
2649 const SvxBrushItem *pRowColorProp = pTabLine->GetFrameFormat()->GetAttrSet().GetItem<SvxBrushItem>(RES_BACKGROUND);
2650 if ( pRowColorProp && pRowColorProp->GetColor() != COL_AUTO )
2651 aRowColor = pRowColorProp->GetColor();
2652
2653 for ( sal_uInt8 n = 0; n < nBoxes; n++ )
2654 {
2655 const SwTableBox * pBox1 = rTabBoxes[n];
2656 const SwFrameFormat * pFrameFormat = pBox1->GetFrameFormat();
2657 Color aColor = aRowColor;
2658
2659 const SvxBrushItem *pCellColorProp = pFrameFormat->GetAttrSet().GetItem<SvxBrushItem>(RES_BACKGROUND);
2660 if ( pCellColorProp && pCellColorProp->GetColor() != COL_AUTO )
2661 aColor = pCellColorProp->GetColor();
2662
2663 WW8_SHD aShd;
2664 WW8Export::TransBrush( aColor, aShd );
2666 }
2667
2668/*sprmTDefTableShdRaw:
2669 * A DefTableShdOperand value that specifies the ... shading for cells 1 up to 22 in the row,
2670 * ... Cells 23 to 44 are shaded by sprmTDefTableShdRaw2nd,
2671 * and cells 45 to 63 are shaded by sprmTDefTableShdRaw3rd.
2672 */
2673 sal_uInt32 const aSprmIds[] { NS_sprm::TDefTableShd::val,
2680 for (sal_uInt32 m : aSprmIds)
2681 {
2682 sal_uInt8 nStart = 0;
2683 sal_uInt8 nStop = rTabBoxes.size();
2684 switch ( m )
2685 {
2688 if ( nStop > 21 )
2689 nStop = 22;
2690 break;
2693 nStart = 22;
2694 if ( nStop > 43 )
2695 nStop = 44;
2696 break;
2699 nStart = 44;
2700 if ( nStop > 62 )
2701 nStop = 63;
2702 break;
2703 }
2704 if ( nStart >= nStop )
2705 break;
2706
2708 m_rWW8Export.m_pO->push_back( static_cast<sal_uInt8>((nStop-nStart) * 10) );
2709
2710 for ( sal_uInt8 n = nStart; n < nStop; n++ )
2711 {
2712 const SwTableBox * pBox1 = rTabBoxes[n];
2713 const SwFrameFormat * pFrameFormat = pBox1->GetFrameFormat();
2714 Color aColor = aRowColor;
2715
2716 const SvxBrushItem *pCellColorProp = pFrameFormat->GetAttrSet().GetItem<SvxBrushItem>(RES_BACKGROUND);
2717 if ( pCellColorProp && pCellColorProp->GetColor() != COL_AUTO )
2718 aColor = pCellColorProp->GetColor();
2719
2720 WW8SHDLong aSHD;
2721 aSHD.setCvFore( 0xFF000000 );
2722
2723 if ( aColor == COL_AUTO )
2724 aSHD.setCvBack( 0xFF000000 );
2725 else
2726 aSHD.setCvBack( wwUtility::RGBToBGR( aColor ) );
2727
2728 aSHD.Write( m_rWW8Export );
2729 }
2730 }
2731}
2732
2734{
2735 // output page/section breaks
2736 OutputSectionBreaks( rNode.GetpSwAttrSet(), rNode );
2737}
2738
2739namespace {
2740
2741class TrackContentToExport
2742{
2743private:
2744 SwPaM *m_pCurPam;
2745 SwNodeOffset m_nStart, m_nEnd;
2746public:
2747 TrackContentToExport(SwPaM *pCurPam, SwNodeOffset nCurStart, SwNodeOffset nCurEnd)
2748 : m_pCurPam(pCurPam)
2749 , m_nStart(nCurStart)
2750 , m_nEnd(nCurEnd)
2751 {
2752 }
2753
2754 bool contentRemainsToExport(ww8::WW8TableInfo *pTableInfo)
2755 {
2756 bool bSimpleContentRemains = m_pCurPam->GetPoint()->GetNode() < m_pCurPam->GetMark()->GetNode() ||
2757 (m_pCurPam->GetPoint()->GetNode() == m_pCurPam->GetMark()->GetNode() &&
2758 m_pCurPam->GetPoint()->GetContentIndex() <= m_pCurPam->GetMark()->GetContentIndex());
2759 if (bSimpleContentRemains)
2760 return true;
2761
2762 if (!pTableInfo)
2763 return false;
2764
2765 //An old-school table where one cell may points back to a previous node as the next cell
2766 //so if this node is the last node in the range, we may need to jump back to a previously
2767 //skipped cell to output it in a sane sequence. See ooo47778-3.sxw for one of these
2768 //horrors. So if we are at the end of the selection, but this end point is a table
2769 //cell whose next cell is in the selection allow jumping back to it
2770 const SwNode* pCurrentNode = &m_pCurPam->GetPoint()->GetNode();
2771 const SwNode* pNextNode = pTableInfo->getNextNode(pCurrentNode);
2772
2773 if (pNextNode && pCurrentNode != pNextNode)
2774 {
2775 return pNextNode->GetIndex() >= m_nStart &&
2776 pNextNode->GetIndex() < m_nEnd;
2777 }
2778
2779 return false;
2780 }
2781};
2782
2783}
2784
2786{
2787 TrackContentToExport aContentTracking(m_pCurPam.get(), m_nCurStart, m_nCurEnd);
2788 while (aContentTracking.contentRemainsToExport(m_pTableInfo.get()))
2789 {
2790 SwNode& rNd = m_pCurPam->GetPointNode();
2791
2792 // no section breaks exported for Endnotes
2793 if ( rNd.IsTextNode() && m_nTextTyp != TXT_EDN && m_nTextTyp != TXT_FTN )
2794 {
2795 SwSoftPageBreakList breakList;
2796 // if paragraph need to be split than handle section break somewhere
2797 // else.
2798 if( !NeedTextNodeSplit( *rNd.GetTextNode(), breakList) )
2800 }
2801
2802
2803 // output the various types of nodes
2804 if ( rNd.IsContentNode() )
2805 {
2806 SwContentNode* pCNd = static_cast<SwContentNode*>(&rNd);
2807
2808 const SwPageDesc* pTemp = rNd.FindPageDesc();
2809 if ( pTemp )
2810 m_pCurrentPageDesc = pTemp;
2811
2812 m_pCurPam->GetPoint()->nContent.Assign( pCNd, 0 );
2813 OutputContentNode( *pCNd );
2814 }
2815 else if ( rNd.IsTableNode() )
2816 {
2817 m_pTableInfo->processSwTable( &rNd.GetTableNode()->GetTable() );
2818 }
2819 else if ( rNd.IsSectionNode() && TXT_MAINTEXT == m_nTextTyp )
2821 else if ( TXT_MAINTEXT == m_nTextTyp && rNd.IsEndNode() &&
2823 {
2824 const SwSection& rSect = rNd.StartOfSectionNode()->GetSectionNode()
2825 ->GetSection();
2826 if ( m_bStartTOX && SectionType::ToxContent == rSect.GetType() )
2827 m_bStartTOX = false;
2828
2829 SwNodeIndex aIdx( rNd, 1 );
2830 if ( aIdx.GetNode().IsEndNode() && aIdx.GetNode().StartOfSectionNode()->IsSectionNode() )
2831 ;
2832 else if ( aIdx.GetNode().IsSectionNode() )
2833 ;
2834 else if ( !IsInTable() ) //No sections in table
2835 {
2836 //#120140# Do not need to insert a page/section break after a section end. Check this case first
2837 bool bNeedExportBreakHere = true;
2838 if ( rSect.GetType() == SectionType::ToxContent || rSect.GetType() == SectionType::ToxHeader )
2839 bNeedExportBreakHere = false;
2840 else if ( aIdx.GetNode().IsTextNode() )
2841 {
2842 SwTextNode *pTempNext = aIdx.GetNode().GetTextNode();
2843 if ( pTempNext )
2844 {
2845 const SwFormatPageDesc * pTempItem = nullptr;
2846 if (pTempNext->GetpSwAttrSet()
2847 && (pTempItem = pTempNext->GetpSwAttrSet()->GetItemIfSet(RES_PAGEDESC, false))
2848 && pTempItem->GetRegisteredIn())
2849 {
2850 //Next node has a new page style which means this node is a section end. Do not insert another page/section break here
2851 bNeedExportBreakHere = false;
2852 }
2853 }
2854 }
2855 else
2856 {
2857 /* Do not export Section Break in case DOCX containing MultiColumn and
2858 * aIdx.GetNode().IsTextNode() is False i.e. Text node is NULL.
2859 */
2860 const SwFrameFormat* pPgFormat = rSect.GetFormat();
2861 const SwFormatCol& rCol = pPgFormat->GetCol();
2862 sal_uInt16 nColumnCount = rCol.GetNumCols();
2863 const SwFormatNoBalancedColumns& rNoBalanced = pPgFormat->GetBalancedColumns();
2864 // Prevent the additional section break only for non-balanced columns.
2865 if (nColumnCount > 1 && rNoBalanced.GetValue())
2866 {
2867 bNeedExportBreakHere = false;
2868 }
2869 // No need to create a "fake" section if this is the end of the document,
2870 // except to emulate balanced columns.
2871 else if ( nColumnCount < 2 && aIdx == m_rDoc.GetNodes().GetEndOfContent() )
2872 bNeedExportBreakHere = false;
2873 }
2874
2875 if (bNeedExportBreakHere) //#120140# End of check
2876 {
2877 ReplaceCr( char(0xc) ); // indicator for Page/Section-Break
2878
2879 const SwSectionFormat* pParentFormat = rSect.GetFormat()->GetParent();
2880 if ( !pParentFormat )
2881 pParentFormat = reinterpret_cast<SwSectionFormat*>(sal_IntPtr(-1));
2882
2883 sal_uLong nRstLnNum;
2884 if ( aIdx.GetNode().IsContentNode() )
2885 nRstLnNum = static_cast<SwContentNode&>(aIdx.GetNode()).GetSwAttrSet().
2886 GetLineNumber().GetStartValue();
2887 else
2888 nRstLnNum = 0;
2889
2890 AppendSection( m_pCurrentPageDesc, pParentFormat, nRstLnNum );
2891 }
2892 else
2893 {
2894 OutputEndNode( *rNd.GetEndNode() );
2895 }
2896 }
2897 }
2898 else if ( rNd.IsStartNode() )
2899 {
2900 OutputStartNode( *rNd.GetStartNode() );
2901 }
2902 else if ( rNd.IsEndNode() )
2903 {
2904 OutputEndNode( *rNd.GetEndNode() );
2905 }
2906
2907 if ( &rNd == &rNd.GetNodes().GetEndOfContent() )
2908 break;
2909
2910 const SwNode * pCurrentNode = &m_pCurPam->GetPoint()->GetNode();
2911 const SwNode * pNextNode = m_pTableInfo->getNextNode(pCurrentNode);
2912
2913 if (pCurrentNode == pNextNode)
2914 {
2915 SAL_WARN("sw.ww8", "loop in TableInfo");
2916 pNextNode = nullptr;
2917 }
2918
2919 if (pNextNode != nullptr)
2920 m_pCurPam->GetPoint()->Assign(*pNextNode);
2921 else
2922 m_pCurPam->GetPoint()->Adjust(SwNodeOffset(1));
2923
2924 SwNodeOffset nPos = m_pCurPam->GetPoint()->GetNodeIndex();
2925 ::SetProgressState( sal_Int32(nPos), m_pCurPam->GetDoc().GetDocShell() );
2926 }
2927
2928 SAL_INFO( "sw.ww8.level2", "</WriteText>" );
2929}
2930
2932{
2933 SAL_INFO( "sw.ww8.level2", "<WriteMainText>" );
2934
2935 m_pFib->m_fcMin = Strm().Tell();
2936
2937 m_pCurPam->GetPoint()->Assign(*m_rDoc.GetNodes().GetEndOfContent().StartOfSectionNode());
2938
2939 WriteText();
2940
2941 if( 0 == Strm().Tell() - m_pFib->m_fcMin ) // no text ?
2942 WriteCR(); // then CR at the end ( otherwise WW will complain )
2943
2944 m_pFib->m_ccpText = Fc2Cp( Strm().Tell() );
2945 m_pFieldMain->Finish( m_pFib->m_ccpText, 0 );
2946
2947 // ccpText includes Footnote and KF-text
2948 // therefore pFib->ccpText may get updated as well
2949 // save the StyleId of the last paragraph. Because WW97 take the style
2950 // from the last CR, that will be written after footer/Header/footnotes/
2951 // annotation etc.
2952 const SwTextNode* pLastNd = m_pCurPam->GetMark()->GetNode().GetTextNode();
2953 if( pLastNd )
2954 m_nLastFormatId = GetId( static_cast<SwTextFormatColl&>(pLastNd->GetAnyFormatColl()) );
2955
2956 SAL_INFO( "sw.ww8.level2", "</WriteMainText>" );
2957}
2958
2960{
2961 bool bResult = false;
2962
2963 if (m_pCurPam != nullptr)
2964 {
2965 SwNode& rNode = m_pCurPam->GetPointNode();
2966
2967 if (m_pTableInfo)
2968 {
2969 ww8::WW8TableNodeInfo::Pointer_t pTableNodeInfo = m_pTableInfo->getTableNodeInfo(&rNode);
2970
2971 if (pTableNodeInfo && pTableNodeInfo->getDepth() > 0)
2972 {
2973 bResult = true;
2974 }
2975 }
2976 }
2977
2978 return bResult;
2979}
2980
2982
2984{
2985 // Graphics in the data stream
2986 m_pGrf->Write(); // Graphics
2987
2988 // output into WordDocument stream
2989 m_pChpPlc->WriteFkps(); // Fkp.Chpx
2990 m_pPapPlc->WriteFkps(); // Fkp.Papx
2991 m_pSepx->WriteSepx( Strm() ); // Sepx
2992
2993 // output into Table stream
2994 m_pStyles->OutputStylesTable(); // for WW8 StyleTab
2995 m_pFootnote->WritePlc( *this ); // Footnote-Ref & Text Plc
2996 m_pEdn->WritePlc( *this ); // Endnote-Ref & Text Plc
2997 m_pTextBxs->WritePlc( *this ); // Textbox Text Plc
2998 m_pHFTextBxs->WritePlc( *this ); // Head/Foot-Textbox Text Plc
2999 m_pAtn->WritePlc( *this ); // Annotation-Ref & Text Plc
3000
3001 m_pSepx->WritePlcSed( *this ); // Slcx.PlcSed
3002 m_pSepx->WritePlcHdd( *this ); // Slcx.PlcHdd
3003
3004 m_pChpPlc->WritePlc(); // Plcx.Chpx
3005 m_pPapPlc->WritePlc(); // Plcx.Papx
3006
3007 if( m_pRedlAuthors )
3008 m_pRedlAuthors->Write( GetWriter() ); // sttbfRMark (RedlineAuthors)
3009 m_pFieldMain->Write( *this ); // Fields ( Main Text )
3010 m_pFieldHdFt->Write( *this ); // Fields ( Header/Footer )
3011 m_pFieldFootnote->Write( *this ); // Fields ( FootNotes )
3012 m_pFieldEdn->Write( *this ); // Fields ( EndNotes )
3013 m_pFieldAtn->Write( *this ); // Fields ( Annotations )
3014 m_pFieldTextBxs->Write( *this ); // Fields ( Textboxes )
3015 m_pFieldHFTextBxs->Write( *this ); // Fields ( Head/Foot-Textboxes )
3016
3018 {
3019 /*
3020 Every time MS 2000 creates an escher stream there is always
3021 an ObjectPool dir (even if empty). It turns out that if a copy of
3022 MS 2000 is used to open a document that contains escher graphics
3023 exported from StarOffice without this empty dir then *if* that
3024 copy of MS Office has never been used to open a MSOffice document
3025 that has escher graphics (and an ObjectPool dir of course) and
3026 that copy of office has not been used to draw escher graphics then
3027 our exported graphics do not appear. Once you do open a ms
3028 document with escher graphics or draw an escher graphic with that
3029 copy of word, then all documents from staroffice that contain
3030 escher work from then on. Tricky to track down, some sort of late
3031 binding trickery in MS where solely for first time initialization
3032 the existence of an ObjectPool dir is necessary for triggering
3033 some magic.
3034 */
3035 // avoid memory leak #i120098#, the unnamed obj will be released in destructor.
3037 }
3038
3039 // dggInfo - escher stream
3040 WriteEscher();
3041
3042 m_pSdrObjs->WritePlc( *this );
3043 m_pHFSdrObjs->WritePlc( *this );
3044 // spamom - office drawing table
3045 // spahdr - header office drawing table
3046
3047 m_pBkmks->Write( *this ); // Bookmarks - sttbfBkmk/
3048 // plcfBkmkf/plcfBkmkl
3049 m_pFactoids->Write(*this);
3050
3052
3054
3055 m_pMagicTable->Write( *this );
3056
3057 m_pPiece->WritePc( *this ); // Piece-Table
3059
3060 //Convert OOo asian typography into MS typography structure
3061 ExportDopTypography(m_pDop->doptypography);
3062
3063 WriteDop( *this ); // Document-Properties
3064
3065 // Write SttbfAssoc
3066 WW8SttbAssoc * pSttbfAssoc = dynamic_cast<WW8SttbAssoc *>
3067 (m_rDoc.getIDocumentExternalData().getExternalData(::sw::tExternalDataType::STTBF_ASSOC).get());
3068
3069 if ( pSttbfAssoc ) // #i106057#
3070 {
3071 std::vector<OUString> aStrings(pSttbfAssoc->getStrings());
3072 WriteAsStringTable(aStrings, m_pFib->m_fcSttbfAssoc,
3073 m_pFib->m_lcbSttbfAssoc);
3074 }
3075
3076 Strm().Seek( 0 );
3077
3078 // Reclaim stored FIB data from document.
3079 ::ww8::WW8FibData * pFibData = dynamic_cast<ww8::WW8FibData *>
3080 (m_rDoc.getIDocumentExternalData().getExternalData(::sw::tExternalDataType::FIB).get());
3081
3082 if ( pFibData )
3083 {
3084 m_pFib->m_fReadOnlyRecommended =
3085 pFibData->getReadOnlyRecommended();
3086 m_pFib->m_fWriteReservation =
3087 pFibData->getWriteReservation();
3088 }
3089
3090 m_pFib->Write( Strm() ); // FIB
3091}
3092
3094{
3095 bool bNeedsFinalPara = false;
3096 // Start of Text ( overwrite )
3097 SwWW8Writer::FillUntil( Strm(), m_pFib->m_fcMin );
3098
3099 WriteMainText(); // main text
3100 sal_uInt8 nSprmsLen;
3101 sal_uInt8 *pLastSprms = m_pPapPlc->CopyLastSprms(nSprmsLen);
3102
3103 bNeedsFinalPara |= m_pFootnote->WriteText( *this ); // Footnote-Text
3104 bNeedsFinalPara |= m_pSepx->WriteKFText( *this ); // K/F-Text
3105 bNeedsFinalPara |= m_pAtn->WriteText( *this ); // Annotation-Text
3106 bNeedsFinalPara |= m_pEdn->WriteText( *this ); // EndNote-Text
3107
3108 // create the escher streams
3109 CreateEscher();
3110
3111 bNeedsFinalPara |= m_pTextBxs->WriteText( *this ); //Textbox Text Plc
3112 bNeedsFinalPara |= m_pHFTextBxs->WriteText( *this );//Head/Foot-Textbox Text Plc
3113
3114 if (bNeedsFinalPara)
3115 {
3116 WriteCR();
3117 m_pPapPlc->AppendFkpEntry(Strm().Tell(), nSprmsLen, pLastSprms);
3118 }
3119 delete[] pLastSprms;
3120
3121 m_pSepx->Finish( Fc2Cp( Strm().Tell() ));// Text + Footnote + HdFt as section end
3122 m_pMagicTable->Finish( Fc2Cp( Strm().Tell() ),0);
3123
3124 m_pFib->m_fcMac = Strm().Tell(); // End of all texts
3125
3126 WriteFkpPlcUsw(); // FKP, PLC, ...
3127}
3128
3129void MSWordExportBase::AddLinkTarget(std::u16string_view rURL)
3130{
3131 if( rURL.empty() || rURL[0] != '#' )
3132 return;
3133
3134 OUString aURL( BookmarkToWriter( rURL.substr( 1 ) ) );
3135 sal_Int32 nPos = aURL.lastIndexOf( cMarkSeparator );
3136
3137 if( nPos < 2 )
3138 return;
3139
3140 OUString sCmp = aURL.copy(nPos+1).replaceAll(" ", "");
3141 if( sCmp.isEmpty() )
3142 return;
3143
3144 sCmp = sCmp.toAsciiLowerCase();
3145 SwNodeOffset nIdx(0);
3146 bool noBookmark = false;
3147
3148 if( sCmp == "outline" )
3149 {
3150 SwPosition aPos(*m_pCurPam->GetPoint());
3151 OUString aName(BookmarkToWriter(aURL.subView(0, nPos)));
3152 // If we can find the outline this bookmark refers to
3153 // save the name of the bookmark and the
3154 // node index number of where it points to
3155 if( m_rDoc.GotoOutline( aPos, aName ) )
3156 {
3157 nIdx = aPos.GetNodeIndex();
3158 noBookmark = true;
3159 }
3160 }
3161 else if( sCmp == "graphic" )
3162 {
3163 SwNodeIndex* pIdx;
3164 OUString aName(BookmarkToWriter(aURL.subView(0, nPos)));
3166 if (pFormat && nullptr != (pIdx = const_cast<SwNodeIndex*>(pFormat->GetContent().GetContentIdx())))
3167 {
3168 nIdx = pIdx->GetNext()->GetIndex();
3169 noBookmark = true;
3170 }
3171 }
3172 else if( sCmp == "frame" )
3173 {
3174 SwNodeIndex* pIdx;
3175 OUString aName(BookmarkToWriter(aURL.subView(0, nPos)));
3177 if (pFormat && nullptr != (pIdx = const_cast<SwNodeIndex*>(pFormat->GetContent().GetContentIdx())))
3178 {
3179 nIdx = pIdx->GetIndex() + 1;
3180 noBookmark = true;
3181 }
3182 }
3183 else if( sCmp == "ole" )
3184 {
3185 SwNodeIndex* pIdx;
3186 OUString aName(BookmarkToWriter(aURL.subView(0, nPos)));
3188 if (pFormat && nullptr != (pIdx = const_cast<SwNodeIndex*>(pFormat->GetContent().GetContentIdx())))
3189 {
3190 nIdx = pIdx->GetNext()->GetIndex();
3191 noBookmark = true;
3192 }
3193 }
3194 else if( sCmp == "region" )
3195 {
3196 SwNodeIndex* pIdx;
3197 OUString aName(BookmarkToWriter(aURL.subView(0, nPos)));
3198 for (const SwSectionFormat* pFormat : m_rDoc.GetSections())
3199 {
3200 if (aName == pFormat->GetSection()->GetSectionName()
3201 && nullptr != (pIdx = const_cast<SwNodeIndex*>(pFormat->GetContent().GetContentIdx())))
3202 {
3203 nIdx = pIdx->GetIndex() + 1;
3204 noBookmark = true;
3205 break;
3206 }
3207 }
3208 }
3209 else if( sCmp == "table" )
3210 {
3211 OUString aName(BookmarkToWriter(aURL.subView(0, nPos)));
3213 if (pTable)
3214 {
3215 SwTableNode* pTableNode = const_cast<SwTableNode*>(pTable->GetTabSortBoxes()[1]->GetSttNd()->FindTableNode());
3216 if (pTableNode)
3217 {
3218 nIdx = pTableNode->GetIndex() + 2;
3219 noBookmark = true;
3220 }
3221 }
3222 }
3223 else if (sCmp == "toxmark")
3224 {
3225 OUString const name(aURL.copy(0, nPos));
3226 OUString const nameDecoded(INetURLObject::decode(name,
3228 std::optional<std::pair<SwTOXMark, sal_Int32>> const tmp(
3229 sw::PrepareJumpToTOXMark(m_rDoc, nameDecoded));
3230 if (tmp)
3231 {
3232 SwTOXMark const* pMark(&tmp->first);
3233 for (sal_Int32 i = 0; i < tmp->second; ++i)
3234 {
3235 pMark = &m_rDoc.GotoTOXMark(*pMark, TOX_SAME_NXT, true);
3236 }
3237 if (pMark != &tmp->first)
3238 {
3240 m_TOXMarkBookmarksByTOXMark.emplace(pMark, nameDecoded);
3241 }
3242 }
3243 }
3244 if (noBookmark)
3245 {
3246 aBookmarkPair aImplicitBookmark;
3247 aImplicitBookmark.first = aURL;
3248 aImplicitBookmark.second = nIdx;
3249 m_aImplicitBookmarks.push_back(aImplicitBookmark);
3250 }
3251}
3252
3254{
3255 for (const SfxPoolItem* pItem : rDoc.GetAttrPool().GetItemSurrogates(RES_TXTATR_INETFMT))
3256 {
3257 auto pINetFormat = dynamic_cast<const SwFormatINetFormat*>(pItem);
3258 if (!pINetFormat)
3259 continue;
3260
3261 const SwTextINetFormat* pTextAttr = pINetFormat->GetTextINetFormat();
3262 if (!pTextAttr)
3263 continue;
3264
3265 const SwTextNode* pTextNd = pTextAttr->GetpTextNode();
3266 if (!pTextNd)
3267 continue;
3268
3269 if (!pTextNd->GetNodes().IsDocNodes())
3270 continue;
3271
3272 AddLinkTarget( pINetFormat->GetValue() );
3273 }
3274
3275 for (const SfxPoolItem* pItem : rDoc.GetAttrPool().GetItemSurrogates(RES_URL))
3276 {
3277 auto pURL = dynamic_cast<const SwFormatURL*>(pItem);
3278 if (!pURL)
3279 continue;
3280
3281 AddLinkTarget(pURL->GetURL());
3282 const ImageMap *pIMap = pURL->GetMap();
3283 if (!pIMap)
3284 continue;
3285
3286 for (size_t i=0; i < pIMap->GetIMapObjectCount(); ++i)
3287 {
3288 const IMapObject* pObj = pIMap->GetIMapObject(i);
3289 if (!pObj)
3290 continue;
3291 AddLinkTarget( pObj->GetURL() );
3292 }
3293 }
3294}
3295
3296namespace
3297{
3298 const sal_uInt64 WW_BLOCKSIZE = 0x200;
3299
3300 ErrCode EncryptRC4(msfilter::MSCodec_Std97& rCtx, SvStream &rIn, SvStream &rOut)
3301 {
3302 sal_uInt64 nLen = rIn.TellEnd();
3303 rIn.Seek(0);
3304
3306 for (std::size_t nI = 0, nBlock = 0; nI < nLen; nI += WW_BLOCKSIZE, ++nBlock)
3307 {
3308 std::size_t nBS = std::min(nLen - nI, WW_BLOCKSIZE);
3309 nBS = rIn.ReadBytes(in, nBS);
3310 if (!rCtx.InitCipher(nBlock)) {
3312 }
3313 rCtx.Encode(in, nBS, in, nBS);
3314 rOut.WriteBytes(in, nBS);
3315 }
3316 return ERRCODE_NONE;
3317 }
3318}
3319
3321{
3324
3328 m_bInWriteTOX = false;
3329
3331
3332 m_pParentFrame = nullptr;
3333 m_pFlyOffset = nullptr;
3334 m_eNewAnchorType = RndStdIds::FLY_AT_PAGE;
3337 m_pStyAttr = nullptr;
3338 m_pCurrentStyle = nullptr;
3339 m_pOutFormatNode = nullptr;
3340 m_pEscher = nullptr;
3341 m_pRedlAuthors = nullptr;
3342 m_aTOXArr.clear();
3343
3344 if ( !m_pOLEExp )
3345 {
3346 sal_uInt32 nSvxMSDffOLEConvFlags = 0;
3348 if ( rOpt.IsMath2MathType() )
3349 nSvxMSDffOLEConvFlags |= OLE_STARMATH_2_MATHTYPE;
3350 if ( rOpt.IsWriter2WinWord() )
3351 nSvxMSDffOLEConvFlags |= OLE_STARWRITER_2_WINWORD;
3352 if ( rOpt.IsCalc2Excel() )
3353 nSvxMSDffOLEConvFlags |= OLE_STARCALC_2_EXCEL;
3354 if ( rOpt.IsImpress2PowerPoint() )
3355 nSvxMSDffOLEConvFlags |= OLE_STARIMPRESS_2_POWERPOINT;
3356
3357 m_pOLEExp.reset(new SvxMSExportOLEObjects( nSvxMSDffOLEConvFlags ));
3358 }
3359
3360 if ( !m_pOCXExp && m_rDoc.GetDocShell() )
3362
3363 // #i81405# - Collect anchored objects before changing the redline mode.
3364 m_aFrames = GetFrames( m_rDoc, bWriteAll? nullptr : m_pOrigPam );
3365
3367
3369 m_bOrigShowChanges = pLayout == nullptr || !pLayout->IsHideRedlines();
3370
3372 {
3373 //restored to original state by SwWriter::Write
3377 }
3378
3379 // fix the SwPositions in m_aFrames after SetRedlineFlags
3381
3384
3386
3387 // make unique OrdNums (Z-Order) for all drawing-/fly Objects
3390
3392
3393 m_aFrames.clear();
3394
3395 // park m_pCurPam in a "safe place" now that document is fully exported
3396 // before toggling redline mode to avoid ~SwContentIndexReg assert e.g. export
3397 // ooo103014-1.odt to .doc
3398 // park m_pOrigPam as well, as needed for exporting abi9915-1.odt to doc
3401 static_cast<SwPaM&>(*m_pCurPam) = *m_pOrigPam;
3402
3404
3405 return err;
3406}
3407
3409{
3410 uno::Sequence< beans::NamedValue > aEncryptionData;
3411
3412 if ( mpMedium )
3413 {
3414 const SfxUnoAnyItem* pEncryptionDataItem = SfxItemSet::GetItem<SfxUnoAnyItem>(mpMedium->GetItemSet(), SID_ENCRYPTIONDATA, false);
3415 if ( pEncryptionDataItem && ( pEncryptionDataItem->GetValue() >>= aEncryptionData ) && !rCodec.InitCodec( aEncryptionData ) )
3416 {
3417 OSL_ENSURE( false, "Unexpected EncryptionData!" );
3418 aEncryptionData.realloc( 0 );
3419 }
3420
3421 if ( !aEncryptionData.hasElements() )
3422 {
3423 // try to generate the encryption data based on password
3424 const SfxStringItem* pPasswordItem = SfxItemSet::GetItem<SfxStringItem>(mpMedium->GetItemSet(), SID_PASSWORD, false);
3425 if ( pPasswordItem && !pPasswordItem->GetValue().isEmpty() && pPasswordItem->GetValue().getLength() <= 15 )
3426 {
3427 // Generate random number with a seed of time as salt.
3428 rtlRandomPool aRandomPool = rtl_random_createPool ();
3429 sal_uInt8 pDocId[ 16 ];
3430 rtl_random_getBytes( aRandomPool, pDocId, 16 );
3431
3432 rtl_random_destroyPool( aRandomPool );
3433
3434 sal_uInt16 aPassword[16] = {};
3435
3436 const OUString& sPassword(pPasswordItem->GetValue());
3437 for ( sal_Int32 nChar = 0; nChar < sPassword.getLength(); ++nChar )
3438 aPassword[nChar] = sPassword[nChar];
3439
3440 rCodec.InitKey( aPassword, pDocId );
3441 aEncryptionData = rCodec.GetEncryptionData();
3442
3443 mpMedium->GetItemSet()->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::Any( aEncryptionData ) ) );
3444 }
3445 }
3446
3447 if ( aEncryptionData.hasElements() )
3448 mpMedium->GetItemSet()->ClearItem( SID_PASSWORD );
3449 }
3450
3451 // nonempty encryption data means here that the codec was successfully initialized
3452 return aEncryptionData.hasElements();
3453}
3454
3456{
3458
3459 m_pFib.reset(new WW8Fib(8, m_bDot));
3460
3461 tools::SvRef<SotStorageStream> xWwStrm( GetWriter().GetStorage().OpenSotStream( m_aMainStg ) );
3462 tools::SvRef<SotStorageStream> xTableStrm( xWwStrm ), xDataStrm( xWwStrm );
3463 xWwStrm->SetBufferSize( 32768 );
3464
3465 m_pFib->m_fWhichTableStm = true;
3466 xTableStrm = GetWriter().GetStorage().OpenSotStream(SL::a1Table, StreamMode::STD_WRITE);
3467 xDataStrm = GetWriter().GetStorage().OpenSotStream(SL::aData, StreamMode::STD_WRITE);
3468
3469 xDataStrm->SetBufferSize( 32768 ); // for graphics
3470 xTableStrm->SetBufferSize( 16384 ); // for the Font-/Style-Table, etc.
3471
3472 xTableStrm->SetEndian( SvStreamEndian::LITTLE );
3473 xDataStrm->SetEndian( SvStreamEndian::LITTLE );
3474
3475 GetWriter().SetStream( xWwStrm.get() );
3476 m_pTableStrm = xTableStrm.get();
3477 m_pDataStrm = xDataStrm.get();
3478
3479 Strm().SetEndian( SvStreamEndian::LITTLE );
3480
3481 utl::TempFileFast aTempMain;
3482 utl::TempFileFast aTempTable;
3483 utl::TempFileFast aTempData;
3484
3486 bool bEncrypt = GetWriter().InitStd97CodecUpdateMedium(aCtx);
3487 if ( bEncrypt )
3488 {
3490 aTempMain.GetStream( StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE ) );
3491
3492 m_pTableStrm = aTempTable.GetStream( StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE );
3493
3494 m_pDataStrm = aTempData.GetStream( StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE );
3495
3496 sal_uInt8 const aRC4EncryptionHeader[ 52 ] = {0};
3497 m_pTableStrm->WriteBytes(aRC4EncryptionHeader, 52);
3498 }
3499
3500 // Default: "Standard"
3501 m_pSepx.reset(new WW8_WrPlcSepx( *this )); // Sections/headers/footers
3502
3503 m_pFootnote.reset(new WW8_WrPlcFootnoteEdn( TXT_FTN )); // Footnotes
3504 m_pEdn.reset(new WW8_WrPlcFootnoteEdn( TXT_EDN )); // Endnotes
3505 m_pAtn.reset(new WW8_WrPlcAnnotations); // PostIts
3506 m_pFactoids.reset(new WW8_WrtFactoids); // Smart tags.
3509
3510 m_pSdrObjs.reset(new MainTextPlcDrawObj); // Draw-/Fly-Objects for main text
3511 m_pHFSdrObjs.reset(new HdFtPlcDrawObj); // Draw-/Fly-Objects for header/footer
3512
3513 m_pBkmks.reset(new WW8_WrtBookmarks); // Bookmarks
3515
3516 m_pPapPlc.reset(new WW8_WrPlcPn( *this, PAP, m_pFib->m_fcMin ));
3517 m_pChpPlc.reset(new WW8_WrPlcPn( *this, CHP, m_pFib->m_fcMin ));
3518 m_pO.reset(new ww::bytes);
3519 m_pStyles.reset(new MSWordStyles( *this ));
3520 m_pFieldMain.reset(new WW8_WrPlcField( 2, TXT_MAINTEXT ));
3521 m_pFieldHdFt.reset(new WW8_WrPlcField( 2, TXT_HDFT ));
3522 m_pFieldFootnote.reset(new WW8_WrPlcField( 2, TXT_FTN ));
3523 m_pFieldEdn.reset(new WW8_WrPlcField( 2, TXT_EDN ));
3524 m_pFieldAtn.reset(new WW8_WrPlcField( 2, TXT_ATN ));
3525 m_pFieldTextBxs.reset(new WW8_WrPlcField( 2, TXT_TXTBOX ));
3527
3529
3530 m_pGrf.reset(new SwWW8WrGrf( *this ));
3531 m_pPiece.reset(new WW8_WrPct( m_pFib->m_fcMin ));
3532 m_pDop.reset(new WW8Dop);
3533
3534 m_pDop->fRevMarking = bool( RedlineFlags::On & m_nOrigRedlineFlags );
3536 m_pDop->fRMView = pLayout == nullptr || !pLayout->IsHideRedlines();
3537 m_pDop->fRMPrint = m_pDop->fRMView;
3538
3539 // set AutoHyphenation flag if found in default para style
3540 const SvxHyphenZoneItem* pItem;
3541 SwTextFormatColl* pStdTextFormatColl =
3543 if (pStdTextFormatColl && (pItem = pStdTextFormatColl->GetItemIfSet(
3544 RES_PARATR_HYPHENZONE, false)))
3545 {
3546 m_pDop->fAutoHyphen = pItem->IsHyphen();
3547 }
3548
3549 StoreDoc1();
3550
3552 if ( bEncrypt )
3553 {
3554 SvStream *pStrmTemp, *pTableStrmTemp, *pDataStrmTemp;
3555 pStrmTemp = xWwStrm.get();
3556 pTableStrmTemp = xTableStrm.get();
3557 pDataStrmTemp = xDataStrm.get();
3558
3559 if ( pDataStrmTemp && pDataStrmTemp != pStrmTemp) {
3560 err = EncryptRC4(aCtx, *m_pDataStrm, *pDataStrmTemp);
3561 if (err != ERRCODE_NONE) {
3562 goto done;
3563 }
3564 }
3565
3566 err = EncryptRC4(aCtx, *m_pTableStrm, *pTableStrmTemp);
3567 if (err != ERRCODE_NONE) {
3568 goto done;
3569 }
3570
3571 // Write Unencrypted Header 52 bytes to the start of the table stream
3572 // EncryptionVersionInfo (4 bytes): A Version structure where Version.vMajor MUST be 0x0001, and Version.vMinor MUST be 0x0001.
3573 pTableStrmTemp->Seek( 0 );
3574 pTableStrmTemp->WriteUInt32( 0x10001 ); // nEncType
3575
3576 sal_uInt8 pDocId[16];
3577 aCtx.GetDocId( pDocId );
3578
3579 sal_uInt8 pSaltData[16];
3580 sal_uInt8 pSaltDigest[16];
3581 aCtx.GetEncryptKey( pDocId, pSaltData, pSaltDigest );
3582
3583 pTableStrmTemp->WriteBytes(pDocId, 16);
3584 pTableStrmTemp->WriteBytes(pSaltData, 16);
3585 pTableStrmTemp->WriteBytes(pSaltDigest, 16);
3586
3587 err = EncryptRC4(aCtx, GetWriter().Strm(), *pStrmTemp);
3588 if (err != ERRCODE_NONE) {
3589 goto done;
3590 }
3591
3592 // Write Unencrypted Fib 68 bytes to the start of the workdocument stream
3593 m_pFib->m_fEncrypted = true; // fEncrypted indicates the document is encrypted.
3594 m_pFib->m_fObfuscated = false; // Must be 0 for RC4.
3595 m_pFib->m_nHash = 0x34; // encrypt header bytes count of table stream.
3596 m_pFib->m_nKey = 0; // lkey2 must be 0 for RC4.
3597
3598 pStrmTemp->Seek( 0 );
3599 m_pFib->WriteHeader( *pStrmTemp );
3600 done:;
3601 }
3602
3603 m_pGrf.reset();
3604 m_pMagicTable.reset();
3605 m_pFieldFootnote.reset();
3606 m_pFieldTextBxs.reset();
3607 m_pFieldHFTextBxs.reset();
3608 m_pFieldAtn.reset();
3609 m_pFieldEdn.reset();
3610 m_pFieldHdFt.reset();
3611 m_pFieldMain.reset();
3612 m_pStyles.reset();
3613 m_pO.reset();
3614 m_pChpPlc.reset();
3615 m_pPapPlc.reset();
3616 m_pSepx.reset();
3617
3618 m_pRedlAuthors.reset();
3619 m_pSdrObjs.reset();
3620 m_pHFSdrObjs.reset();
3621 m_pTextBxs.reset();
3622 m_pHFTextBxs.reset();
3623 m_pAtn.reset();
3624 m_pEdn.reset();
3625 m_pFootnote.reset();
3626 m_pBkmks.reset();
3627 m_pPiece.reset();
3628 m_pDop.reset();
3629 m_pFib.reset();
3630 GetWriter().SetStream( nullptr );
3631
3632 xWwStrm->SetBufferSize( 0 );
3633 xTableStrm->SetBufferSize( 0 );
3634 xDataStrm->SetBufferSize( 0 );
3635 if( 0 == m_pDataStrm->Seek( STREAM_SEEK_TO_END ))
3636 {
3637 xDataStrm.clear();
3638 m_pDataStrm = nullptr;
3640 }
3641
3642 return err;
3643}
3644
3646{
3647 static const sal_uInt8 pData[] =
3648 {
3649 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
3650 0xFF, 0xFF, 0xFF, 0xFF, 0x06, 0x09, 0x02, 0x00,
3651 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,
3652 0x00, 0x00, 0x00, 0x46,
3653
3654 0x18, 0x00, 0x00, 0x00,
3655 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f',
3656 't', ' ', 'W', 'o', 'r', 'd', '-', 'D',
3657 'o', 'k', 'u', 'm', 'e', 'n', 't', 0x0,
3658
3659 0x0A, 0x00, 0x00, 0x00,
3660 'M', 'S', 'W', 'o', 'r', 'd', 'D', 'o',
3661 'c', 0x0,
3662
3663 0x10, 0x00, 0x00, 0x00,
3664 'W', 'o', 'r', 'd', '.', 'D', 'o', 'c',
3665 'u', 'm', 'e', 'n', 't', '.', '8', 0x0,
3666
3667 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00,
3668 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
3669 };
3670
3673 aGName, SotClipboardFormatId::NONE, "Microsoft Word-Document");
3674 tools::SvRef<SotStorageStream> xStor( GetWriter().GetStorage().OpenSotStream(sCompObj) );
3675 xStor->WriteBytes(pData, sizeof(pData));
3676
3677 SwDocShell* pDocShell = m_rDoc.GetDocShell ();
3678 OSL_ENSURE(pDocShell, "no SwDocShell");
3679
3680 if (!pDocShell) return;
3681
3682 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
3683 pDocShell->GetModel(), uno::UNO_QUERY_THROW);
3684 uno::Reference<document::XDocumentProperties> xDocProps(
3685 xDPS->getDocumentProperties());
3686 OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
3687
3688 if (!xDocProps.is())
3689 return;
3690
3691 if ( SvtFilterOptions::Get().IsEnableWordPreview() )
3692 {
3693 std::shared_ptr<GDIMetaFile> xMetaFile =
3694 pDocShell->GetPreviewMetaFile();
3695 uno::Sequence<sal_Int8> metaFile(
3696 sfx2::convertMetaFile(xMetaFile.get()));
3697 sfx2::SaveOlePropertySet(xDocProps, &GetWriter().GetStorage(), &metaFile);
3698 }
3699 else
3700 sfx2::SaveOlePropertySet( xDocProps, &GetWriter().GetStorage() );
3701}
3702
3704{
3705 tools::SvRef<SotStorage> pOrigStg;
3706 uno::Reference< packages::XPackageEncryption > xPackageEncryption;
3707 std::shared_ptr<SvStream> pSotStorageStream;
3708 uno::Sequence< beans::NamedValue > aEncryptionData;
3709 if (mpMedium)
3710 {
3711 // Check for specific encryption requests
3712 const SfxUnoAnyItem* pEncryptionDataItem = SfxItemSet::GetItem<SfxUnoAnyItem>(mpMedium->GetItemSet(), SID_ENCRYPTIONDATA, false);
3713 if (pEncryptionDataItem && (pEncryptionDataItem->GetValue() >>= aEncryptionData))
3714 {
3715 ::comphelper::SequenceAsHashMap aHashData(aEncryptionData);
3716 OUString sCryptoType = aHashData.getUnpackedValueOrDefault("CryptoType", OUString());
3717
3718 if (sCryptoType.getLength())
3719 {
3720 uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext());
3721 uno::Sequence<uno::Any> aArguments{
3722 uno::Any(beans::NamedValue("Binary", uno::Any(true))) };
3723 xPackageEncryption.set(
3724 xComponentContext->getServiceManager()->createInstanceWithArgumentsAndContext(
3725 "com.sun.star.comp.oox.crypto." + sCryptoType, aArguments, xComponentContext), uno::UNO_QUERY);
3726
3727 if (xPackageEncryption)
3728 {
3729 // We have an encryptor
3730 // Create new temporary storage for content
3731 pOrigStg = m_pStg;
3732 pSotStorageStream = std::make_shared<SvMemoryStream>();
3733 m_pStg = new SotStorage(*pSotStorageStream);
3734 }
3735 }
3736 }
3737 }
3738
3739 ErrCode nErrorCode = WriteStorageImpl();
3740
3741 if (xPackageEncryption)
3742 {
3743 assert(pSotStorageStream && m_pStg && "because always set if xPackageEncryption was set");
3744
3745 m_pStg->Commit();
3746 pSotStorageStream->Seek(0);
3747
3748 // Encrypt data written into temporary storage
3749 xPackageEncryption->setupEncryption(aEncryptionData);
3750
3751 uno::Reference<io::XInputStream > xInputStream(new utl::OSeekableInputStreamWrapper(pSotStorageStream.get(), false));
3752 uno::Sequence<beans::NamedValue> aStreams = xPackageEncryption->encrypt(xInputStream);
3753
3754 m_pStg = pOrigStg;
3755 for (const beans::NamedValue & aStreamData : std::as_const(aStreams))
3756 {
3757 // To avoid long paths split and open substorages recursively
3758 // Splitting paths manually, since comphelper::string::split is trimming special characters like \0x01, \0x09
3759 tools::SvRef<SotStorage> pStorage = m_pStg.get();
3760 OUString sFileName;
3761 sal_Int32 idx = 0;
3762 while (pStorage && idx >= 0)
3763 {
3764 OUString sPathElem = aStreamData.Name.getToken(0, L'/', idx);
3765 if (!sPathElem.isEmpty())
3766 {
3767 if (idx < 0)
3768 {
3769 sFileName = sPathElem;
3770 }
3771 else
3772 {
3773 pStorage = pStorage->OpenSotStorage(sPathElem);
3774 if (!pStorage)
3775 break;
3776 }
3777 }
3778 };
3779
3780 if (!pStorage)
3781 {
3782 nErrorCode = ERRCODE_IO_GENERAL;
3783 break;
3784 }
3785
3786 tools::SvRef<SotStorageStream> pStream = pStorage->OpenSotStream(sFileName);
3787 if (!pStream)
3788 {
3789 nErrorCode = ERRCODE_IO_GENERAL;
3790 break;
3791 }
3792 uno::Sequence<sal_Int8> aStreamContent;
3793 aStreamData.Value >>= aStreamContent;
3794 size_t nBytesWritten = pStream->WriteBytes(aStreamContent.getArray(), aStreamContent.getLength());
3795 if (nBytesWritten != static_cast<size_t>(aStreamContent.getLength()))
3796 {
3797 nErrorCode = ERRCODE_IO_CANTWRITE;
3798 break;
3799 }
3800 }
3801 }
3802
3803 return nErrorCode;
3804}
3806{
3807 // #i34818# - update layout (if present), for SwWriteTable
3809 if( pViewShell != nullptr )
3810 pViewShell->CalcLayout();
3811
3812 SwNodeOffset nMaxNode = m_pDoc->GetNodes().Count();
3813 ::StartProgress( STR_STATSTR_W4WWRITE, 0, sal_Int32(nMaxNode), m_pDoc->GetDocShell() );
3814
3815 // Respect table at the beginning of the document
3816 {
3817 SwTableNode* pTNd = m_pCurrentPam->GetPointNode().FindTableNode();
3818 if( pTNd && m_bWriteAll )
3819 // start with the table node !!
3820 m_pCurrentPam->GetPoint()->Assign(*pTNd);
3821 }
3822
3823 // Do the actual export
3825 {
3826 bool bDot = mpMedium->GetFilter()->GetName().endsWith("Vorlage");
3827 WW8Export aExport(this, *m_pDoc, m_pCurrentPam, m_pOrigPam, bDot);
3828 m_pExport = &aExport;
3829 err = aExport.ExportDocument( m_bWriteAll );
3830 m_pExport = nullptr;
3831 }
3832
3834 return err;
3835}
3836
3838{
3839 return WriteStorage();
3840}
3841
3843 const OUString* pFileName )
3844{
3845 mpMedium = &rMed;
3846 ErrCode nRet = StgWriter::Write( rPaM, rMed, pFileName );
3847 mpMedium = nullptr;
3848 return nRet;
3849}
3850
3851MSWordExportBase::MSWordExportBase( SwDoc& rDocument, std::shared_ptr<SwUnoCursor> & pCurrentPam, SwPaM* pOriginalPam )
3852 : m_aMainStg(sMainStream)
3853 , m_pISet(nullptr)
3854 , m_pTopNodeOfHdFtPage(nullptr)
3855 , m_pTableInfo(std::make_shared<ww8::WW8TableInfo>())
3856 , m_nCharFormatStart(0)
3857 , m_nFormatCollStart(0)
3858 , m_nStyleBeforeFly(0)
3859 , m_nLastFormatId(0)
3860 , m_nUniqueList(0)
3861 , m_nHdFtIndex(0)
3862 , m_nOrigRedlineFlags(RedlineFlags::NONE)
3863 , m_bOrigShowChanges(true)
3864 , m_pCurrentPageDesc(nullptr)
3865 , m_pPreviousSectionPageDesc(nullptr)
3866 , m_bFirstTOCNodeWithSection(false)
3867 , m_pChpIter(nullptr)
3868 , m_pParentFrame(nullptr)
3869 , m_pFlyOffset(nullptr)
3870 , m_eNewAnchorType(RndStdIds::FLY_AS_CHAR)
3871 , m_pStyAttr(nullptr)
3872 , m_pOutFormatNode(nullptr)
3873 , m_pCurrentStyle(nullptr)
3874 , m_pEscher(nullptr)
3875 , m_nTextTyp(0)
3876 , m_bStyDef(false)
3877 , m_bBreakBefore(false)
3878 , m_bOutKF(false)
3879 , m_bOutFlyFrameAttrs(false)
3880 , m_bOutPageDescs(false)
3881 , m_bOutFirstPage(false)
3882 , m_bOutTable(false)
3883 , m_bOutGrf(false)
3884 , m_bInWriteEscher(false)
3885 , m_bStartTOX(false)
3886 , m_bInWriteTOX(false)
3887 , m_bFootnoteAtTextEnd(false)
3888 , m_bEndAtTextEnd(false)
3889 , m_bHasHdr(false)
3890 , m_bHasFtr(false)
3891 , m_bSubstituteBullets(true)
3892 , m_bTabInTOC(false)
3893 , m_bHideTabLeaderAndPageNumbers(false)
3894 , m_bExportModeRTF(false)
3895 , m_bFontSizeWritten(false)
3896 , m_bAddFootnoteTab(false)
3897 , m_rDoc(rDocument)
3898 , m_nCurStart(pCurrentPam->GetPoint()->GetNodeIndex())
3899 , m_nCurEnd(pCurrentPam->GetMark()->GetNodeIndex())
3900 , m_pCurPam(pCurrentPam)
3901 , m_pOrigPam(pOriginalPam)
3902{
3903}
3904
3906{
3907 if (m_pUsedNumTable) // all used NumRules
3908 {
3909 // clear the part of the list array that was copied from the document
3910 // - it's an auto delete array, so the rest of the array which are
3911 // duplicated lists that were added during the export will be deleted.
3912 m_pUsedNumTable->erase(m_pUsedNumTable->begin(), m_pUsedNumTable->begin() + m_pUsedNumTable->size() - m_nUniqueList);
3913 m_pUsedNumTable.reset();
3914 }
3915 m_pOLEExp.reset();
3916 m_pOCXExp.reset();
3917}
3918
3920 SwDoc& rDocument, std::shared_ptr<SwUnoCursor> & pCurrentPam, SwPaM* pOriginalPam,
3921 bool bDot )
3922 : MSWordExportBase( rDocument, pCurrentPam, pOriginalPam )
3923 , m_pTableStrm(nullptr)
3924 , m_pDataStrm(nullptr)
3925 , m_bDot(bDot)
3926 , m_pWriter(pWriter)
3927 , m_pAttrOutput(new WW8AttributeOutput(*this))
3928{
3929}
3930
3932{
3933}
3934
3936{
3937 return *m_pAttrOutput;
3938}
3939
3941{
3942 return *m_pSepx;
3943}
3944
3945SwWW8Writer::SwWW8Writer(std::u16string_view rFltName, const OUString& rBaseURL)
3946 : m_pExport( nullptr ),
3947 mpMedium( nullptr )
3948{
3949 assert(rFltName == FILTER_WW8); // WW6/7 export was removed
3950 (void)rFltName;
3951 SetBaseURL( rBaseURL );
3952}
3953
3955{
3956}
3957
3958extern "C" SAL_DLLPUBLIC_EXPORT sal_uInt32 SaveOrDelMSVBAStorage_ww8( SfxObjectShell& rDoc, SotStorage& rStor, sal_Bool bSaveInto, const OUString& rStorageName )
3959{
3960 SvxImportMSVBasic aTmp( rDoc, rStor );
3961 return sal_uInt32(aTmp.SaveOrDelMSVBAStorage( bSaveInto, rStorageName ));
3962}
3963
3964extern "C" SAL_DLLPUBLIC_EXPORT void ExportDOC( std::u16string_view rFltName, const OUString& rBaseURL, WriterRef& xRet )
3965{
3966 xRet = new SwWW8Writer( rFltName, rBaseURL );
3967}
3968
3969extern "C" SAL_DLLPUBLIC_EXPORT sal_uInt32 GetSaveWarningOfMSVBAStorage_ww8( SfxObjectShell &rDocS )
3970{
3971 return sal_uInt32(SvxImportMSVBasic::GetSaveWarningOfMSVBAStorage( rDocS ));
3972}
3973
3975{
3976 bool bRet = false;
3977 if (TXT_FTN == m_nTyp)
3978 {
3979 bRet = WriteGenericText( rWrt, TXT_FTN, rWrt.m_pFib->m_ccpFootnote );
3980 rWrt.m_pFieldFootnote->Finish( rWrt.Fc2Cp( rWrt.Strm().Tell() ),
3981 rWrt.m_pFib->m_ccpText );
3982 }
3983 else
3984 {
3985 bRet = WriteGenericText( rWrt, TXT_EDN, rWrt.m_pFib->m_ccpEdn );
3986 rWrt.m_pFieldEdn->Finish( rWrt.Fc2Cp( rWrt.Strm().Tell() ),
3987 rWrt.m_pFib->m_ccpText + rWrt.m_pFib->m_ccpFootnote
3988 + rWrt.m_pFib->m_ccpHdr + rWrt.m_pFib->m_ccpAtn );
3989 }
3990 return bRet;
3991}
3992
3994{
3995 if( TXT_FTN == m_nTyp )
3996 {
3997 WriteGenericPlc( rWrt, TXT_FTN, rWrt.m_pFib->m_fcPlcffndText,
3998 rWrt.m_pFib->m_lcbPlcffndText, rWrt.m_pFib->m_fcPlcffndRef,
3999 rWrt.m_pFib->m_lcbPlcffndRef );
4000 }
4001 else
4002 {
4003 WriteGenericPlc( rWrt, TXT_EDN, rWrt.m_pFib->m_fcPlcfendText,
4004 rWrt.m_pFib->m_lcbPlcfendText, rWrt.m_pFib->m_fcPlcfendRef,
4005 rWrt.m_pFib->m_lcbPlcfendRef );
4006 }
4007}
4008
4010{
4011 bool bRet = WriteGenericText( rWrt, TXT_ATN, rWrt.m_pFib->m_ccpAtn );
4012 rWrt.m_pFieldAtn->Finish( rWrt.Fc2Cp( rWrt.Strm().Tell() ),
4013 rWrt.m_pFib->m_ccpText + rWrt.m_pFib->m_ccpFootnote
4014 + rWrt.m_pFib->m_ccpHdr );
4015 return bRet;
4016}
4017
4019{
4020 WriteGenericPlc( rWrt, TXT_ATN, rWrt.m_pFib->m_fcPlcfandText,
4021 rWrt.m_pFib->m_lcbPlcfandText, rWrt.m_pFib->m_fcPlcfandRef,
4022 rWrt.m_pFib->m_lcbPlcfandRef );
4023}
4024
4026{
4027 if( TXT_TXTBOX == m_nTyp )
4028 {
4029 WriteGenericPlc( rWrt, m_nTyp, rWrt.m_pFib->m_fcPlcftxbxBkd,
4030 rWrt.m_pFib->m_lcbPlcftxbxBkd, rWrt.m_pFib->m_fcPlcftxbxText,
4031 rWrt.m_pFib->m_lcbPlcftxbxText );
4032 }
4033 else
4034 {
4035 WriteGenericPlc( rWrt, m_nTyp, rWrt.m_pFib->m_fcPlcfHdrtxbxBkd,
4036 rWrt.m_pFib->m_lcbPlcfHdrtxbxBkd, rWrt.m_pFib->m_fcPlcfHdrtxbxText,
4037 rWrt.m_pFib->m_lcbPlcfHdrtxbxText );
4038 }
4039}
4040
4042{
4043 m_pFib->m_fcCmds = m_pTableStrm->Tell();
4044
4045 uno::Reference < embed::XStorage > xSrcRoot(m_rDoc.GetDocShell()->GetStorage());
4046 try
4047 {
4048 uno::Reference < io::XStream > xSrcStream =
4049 xSrcRoot->openStreamElement( SL::aMSMacroCmds, embed::ElementModes::READ );
4050 std::unique_ptr<SvStream> pStream = ::utl::UcbStreamHelper::CreateStream( xSrcStream );
4051
4052 if ( pStream && ERRCODE_NONE == pStream->GetError())
4053 {
4054 m_pFib->m_lcbCmds = pStream->TellEnd();
4055 pStream->Seek(0);
4056
4057 std::unique_ptr<sal_uInt8[]> pBuffer( new sal_uInt8[m_pFib->m_lcbCmds] );
4058 bool bReadOk = checkRead(*pStream, pBuffer.get(), m_pFib->m_lcbCmds);
4059 if (bReadOk)
4060 m_pTableStrm->WriteBytes(pBuffer.get(), m_pFib->m_lcbCmds);
4061 }
4062 }
4063 catch ( const uno::Exception& )
4064 {
4065 }
4066
4067 // set len to FIB
4068 m_pFib->m_lcbCmds = m_pTableStrm->Tell() - m_pFib->m_fcCmds;
4069}
4070
4072{
4073 rExport.InsUInt32( m_cvFore );
4074 rExport.InsUInt32( m_cvBack );
4075 rExport.InsUInt16( 0 ); // ipat
4076}
4077
4078void WW8Export::WriteFormData( const ::sw::mark::IFieldmark& rFieldmark )
4079{
4080 const ::sw::mark::IFieldmark* pFieldmark = &rFieldmark;
4081 const ::sw::mark::ICheckboxFieldmark* pAsCheckbox = dynamic_cast< const ::sw::mark::ICheckboxFieldmark* >( pFieldmark );
4082
4083 if ( ! ( rFieldmark.GetFieldname() == ODF_FORMTEXT ||
4084 rFieldmark.GetFieldname() == ODF_FORMDROPDOWN ||
4085 rFieldmark.GetFieldname() == ODF_FORMCHECKBOX ) )
4086 {
4087 SAL_WARN( "sw.ww8", "unknown field type" );
4088 return;
4089 }
4090
4091 int type = 0; // TextFieldmark
4092 if ( pAsCheckbox )
4093 type = 1;
4094 if ( rFieldmark.GetFieldname() == ODF_FORMDROPDOWN )
4095 type=2;
4096
4097 ::sw::mark::IFieldmark::parameter_map_t::const_iterator pParameter = rFieldmark.GetParameters()->find("name");
4098 OUString ffname;
4099 if ( pParameter != rFieldmark.GetParameters()->end() )
4100 {
4101 OUString aName;
4102 pParameter->second >>= aName;
4103 const sal_Int32 nLen = std::min( sal_Int32(20), aName.getLength() );
4104 ffname = aName.copy(0, nLen);
4105 }
4106
4107 sal_uInt64 nDataStt = m_pDataStrm->Tell();
4108 m_pChpPlc->AppendFkpEntry(Strm().Tell());
4109
4110 WriteChar(0x01);
4111 static sal_uInt8 aArr1[] =
4112 {
4113 0x03, 0x6a, 0,0,0,0, // sprmCPicLocation
4114
4115 0x06, 0x08, 0x01, // sprmCFData
4116 0x55, 0x08, 0x01, // sprmCFSpec
4117 0x02, 0x08, 0x01 // sprmCFFieldVanish
4118 };
4119 sal_uInt8* pDataAdr = aArr1 + 2;
4120 Set_UInt32(pDataAdr, nDataStt);
4121
4122 m_pChpPlc->AppendFkpEntry( Strm().Tell(), sizeof( aArr1 ), aArr1 );
4123
4124 struct FFDataHeader
4125 {
4126 sal_uInt32 version;
4127 sal_uInt16 bits;
4128 sal_uInt16 cch;
4129 sal_uInt16 hps;
4130 FFDataHeader() : version( 0xFFFFFFFF ), bits(0), cch(0), hps(0) {}
4131 };
4132
4133 FFDataHeader aFieldHeader;
4134 aFieldHeader.bits |= (type & 0x03);
4135
4136 sal_Int32 ffres = 0; // rFieldmark.GetFFRes();
4137 if ( pAsCheckbox && pAsCheckbox->IsChecked() )
4138 ffres = 1;
4139 else if ( type == 2 )
4140 {
4141 ::sw::mark::IFieldmark::parameter_map_t::const_iterator pResParameter = rFieldmark.GetParameters()->find(ODF_FORMDROPDOWN_RESULT);
4142 if(pResParameter != rFieldmark.GetParameters()->end())
4143 pResParameter->second >>= ffres;
4144 else
4145 ffres = 0;
4146 }
4147 aFieldHeader.bits |= ( (ffres<<2) & 0x7C );
4148
4149 OUString ffdeftext;
4150 OUString ffformat;
4151 OUString ffhelptext = rFieldmark.GetFieldHelptext();
4152 if ( ffhelptext.getLength() > 255 )
4153 ffhelptext = ffhelptext.copy(0, 255);
4154 OUString ffstattext;
4155 OUString ffentrymcr;
4156 OUString ffexitmcr;
4157 if (type == 0) // iTypeText
4158 {
4159 sal_uInt16 nType = 0;
4160 pParameter = rFieldmark.GetParameters()->find("Type");
4161 if ( pParameter != rFieldmark.GetParameters()->end() )
4162 {
4163 OUString aType;
4164 pParameter->second >>= aType;
4165 if ( aType == "number" ) nType = 1;
4166 else if ( aType == "date" ) nType = 2;
4167 else if ( aType == "currentTime" ) nType = 3;
4168 else if ( aType == "currentDate" ) nType = 4;
4169 else if ( aType == "calculated" ) nType = 5;
4170 aFieldHeader.bits |= nType<<11; // FFDataBits-F 00111000 00000000
4171 }
4172
4173 if ( nType < 3 || nType == 5 ) // not currentTime or currentDate
4174 {
4175 pParameter = rFieldmark.GetParameters()->find("Content");
4176 if ( pParameter != rFieldmark.GetParameters()->end() )
4177 {
4178 OUString aDefaultText;
4179 pParameter->second >>= aDefaultText;
4180 const sal_Int32 nLen = std::min( sal_Int32(255), aDefaultText.getLength() );
4181 ffdeftext = aDefaultText.copy (0, nLen);
4182 }
4183 }
4184
4185 pParameter = rFieldmark.GetParameters()->find("MaxLength");
4186 if ( pParameter != rFieldmark.GetParameters()->end() )
4187 {
4188 sal_uInt16 nLength = 0;
4189 pParameter->second >>= nLength;
4190 nLength = std::min( sal_uInt16(32767), nLength );
4191 aFieldHeader.cch = nLength;
4192 }
4193
4194 pParameter = rFieldmark.GetParameters()->find("Format");
4195 if ( pParameter != rFieldmark.GetParameters()->end() )
4196 {
4197 OUString aFormat;
4198 pParameter->second >>= aFormat;
4199 const sal_Int32 nLen = std::min( sal_Int32(64), aFormat.getLength() );
4200 ffformat = aFormat.copy(0, nLen);
4201 }
4202 }
4203
4204 pParameter = rFieldmark.GetParameters()->find("Help"); //help
4205 if ( ffhelptext.isEmpty() && pParameter != rFieldmark.GetParameters()->end() )
4206 {
4207 OUString aHelpText;
4208 pParameter->second >>= aHelpText;
4209 const sal_Int32 nLen = std::min( sal_Int32(255), aHelpText.getLength() );
4210 ffhelptext = aHelpText.copy (0, nLen);
4211 }
4212 if ( !ffhelptext.isEmpty() )
4213 aFieldHeader.bits |= 0x1<<7;
4214
4215 pParameter = rFieldmark.GetParameters()->find("Description"); // doc tooltip
4216 if ( pParameter == rFieldmark.GetParameters()->end() )
4217 pParameter = rFieldmark.GetParameters()->find("Hint"); //docx tooltip
4218 if ( pParameter != rFieldmark.GetParameters()->end() )
4219 {
4220 OUString aStatusText;
4221 pParameter->second >>= aStatusText;
4222 const sal_Int32 nLen = std::min( sal_Int32(138), aStatusText.getLength() );
4223 ffstattext = aStatusText.copy (0, nLen);
4224 }
4225 if ( !ffstattext.isEmpty() )
4226 aFieldHeader.bits |= 0x1<<8;
4227
4228 pParameter = rFieldmark.GetParameters()->find("EntryMacro");
4229 if ( pParameter != rFieldmark.GetParameters()->end() )
4230 {
4231 OUString aEntryMacro;
4232 pParameter->second >>= aEntryMacro;
4233 const sal_Int32 nLen = std::min( sal_Int32(32), aEntryMacro.getLength() );
4234 ffentrymcr = aEntryMacro.copy (0, nLen);
4235 }
4236
4237 pParameter = rFieldmark.GetParameters()->find("ExitMacro");
4238 if ( pParameter != rFieldmark.GetParameters()->end() )
4239 {
4240 OUString aExitMacro;
4241 pParameter->second >>= aExitMacro;
4242 const sal_Int32 nLen = std::min( sal_Int32(32), aExitMacro.getLength() );
4243 ffexitmcr = aExitMacro.copy (0, nLen);
4244 }
4245
4246 std::vector< OUString > aListItems;
4247 if (type==2)
4248 {
4249 aFieldHeader.bits |= 0x8000; // ffhaslistbox
4250 const ::sw::mark::IFieldmark::parameter_map_t* const pParameters = rFieldmark.GetParameters();
4251 ::sw::mark::IFieldmark::parameter_map_t::const_iterator pListEntries = pParameters->find(ODF_FORMDROPDOWN_LISTENTRY);
4252 if(pListEntries != pParameters->end())
4253 {
4254 uno::Sequence< OUString > vListEntries;
4255 pListEntries->second >>= vListEntries;
4256 aListItems.reserve(vListEntries.getLength());
4257 copy(std::cbegin(vListEntries), std::cend(vListEntries), back_inserter(aListItems));
4258 }
4259 }
4260
4261 const sal_uInt8 aFieldData[] =
4262 {
4263 0x44,0, // the start of "next" data
4264 0,0,0,0,0,0,0,0,0,0, // PIC-Structure! /10
4265 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | /16
4266 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | /16
4267 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | /16
4268 0,0,0,0, // / /4
4269 };
4270 sal_uInt32 slen = sizeof(sal_uInt32)
4271 + sizeof(aFieldData)
4272 + sizeof( aFieldHeader.version ) + sizeof( aFieldHeader.bits ) + sizeof( aFieldHeader.cch ) + sizeof( aFieldHeader.hps )
4273 + 2*ffname.getLength() + 4
4274 + 2*ffformat.getLength() + 4
4275 + 2*ffhelptext.getLength() + 4
4276 + 2*ffstattext.getLength() + 4
4277 + 2*ffentrymcr.getLength() + 4
4278 + 2*ffexitmcr.getLength() + 4;
4279 if ( type )
4280 slen += 2; // wDef
4281 else
4282 slen += 2*ffdeftext.getLength() + 4; //xstzTextDef
4283 if ( type==2 ) {
4284 slen += 2; // sttb ( fExtend )
4285 slen += 4; // for num of list items
4286 const int items = aListItems.size();
4287 for( int i = 0; i < items; i++ ) {
4288 OUString item = aListItems[i];
4289 slen += 2 * item.getLength() + 2;
4290 }
4291 }
4292
4293 m_pDataStrm->WriteUInt32( slen );
4294
4295 int len = sizeof( aFieldData );
4296 OSL_ENSURE( len == 0x44-sizeof(sal_uInt32), "SwWW8Writer::WriteFormData(..) - wrong aFieldData length" );
4297 m_pDataStrm->WriteBytes( aFieldData, len );
4298
4299 m_pDataStrm->WriteUInt32( aFieldHeader.version ).WriteUInt16( aFieldHeader.bits ).WriteUInt16( aFieldHeader.cch ).WriteUInt16( aFieldHeader.hps );
4300
4301 SwWW8Writer::WriteString_xstz( *m_pDataStrm, ffname, true ); // Form field name
4302
4303 if ( !type )
4304 SwWW8Writer::WriteString_xstz( *m_pDataStrm, ffdeftext, true );
4305 if ( type )
4307
4308 SwWW8Writer::WriteString_xstz( *m_pDataStrm, ffformat, true );
4309 SwWW8Writer::WriteString_xstz( *m_pDataStrm, ffhelptext, true );
4310 SwWW8Writer::WriteString_xstz( *m_pDataStrm, ffstattext, true );
4311 SwWW8Writer::WriteString_xstz( *m_pDataStrm, ffentrymcr, true );
4312 SwWW8Writer::WriteString_xstz( *m_pDataStrm, ffexitmcr, true );
4313 if (type==2) {
4314 m_pDataStrm->WriteUInt16( 0xFFFF );
4315 const int items=aListItems.size();
4316 m_pDataStrm->WriteUInt32( items );
4317 for(int i=0;i<items;i++) {
4318 OUString item=aListItems[i];
4320 }
4321 }
4322}
4323
4325{
4326 //@TODO implement me !!!
4327}
4328
4330{
4331 SVBT16 nStyle;
4332 ShortToSVBT16( m_rWW8Export.m_nStyleBeforeFly, nStyle );
4333
4334#ifdef DBG_UTIL
4335 SAL_INFO( "sw.ww8", "<OutWW8_TableNodeInfoInner>" << pNodeInfoInner->toString());
4336#endif
4337
4338 m_rWW8Export.m_pO->clear();
4339
4340 sal_uInt32 nShadowsBefore = pNodeInfoInner->getShadowsBefore();
4341 if (nShadowsBefore > 0)
4342 {
4344 pTmpNodeInfoInner = std::make_shared<ww8::WW8TableNodeInfoInner>(nullptr);
4345
4346 pTmpNodeInfoInner->setDepth(pNodeInfoInner->getDepth());
4347 pTmpNodeInfoInner->setEndOfCell(true);
4348
4349 for (sal_uInt32 n = 0; n < nShadowsBefore; ++n)
4350 {
4351 m_rWW8Export.WriteCR(pTmpNodeInfoInner);
4352
4353 m_rWW8Export.m_pO->insert( m_rWW8Export.m_pO->end(), nStyle, nStyle+2 ); // Style #
4354 TableInfoCell(pTmpNodeInfoInner);
4355 m_rWW8Export.m_pPapPlc->AppendFkpEntry
4356 ( m_rWW8Export.Strm().Tell(), m_rWW8Export.m_pO->size(), m_rWW8Export.m_pO->data() );
4357
4358 m_rWW8Export.m_pO->clear();
4359 }
4360 }
4361
4362 if (pNodeInfoInner->isEndOfCell())
4363 {
4364 SAL_INFO( "sw.ww8", "<endOfCell/>" );
4365
4366 m_rWW8Export.WriteCR(pNodeInfoInner);
4367
4368 m_rWW8Export.m_pO->insert( m_rWW8Export.m_pO->end(), nStyle, nStyle+2 ); // Style #
4369 TableInfoCell(pNodeInfoInner);
4370 m_rWW8Export.m_pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.m_pO->size(), m_rWW8Export.m_pO->data() );
4371
4372 m_rWW8Export.m_pO->clear();
4373 }
4374
4375 sal_uInt32 nShadowsAfter = pNodeInfoInner->getShadowsAfter();
4376 if (nShadowsAfter > 0)
4377 {
4379 pTmpNodeInfoInner= std::make_shared<ww8::WW8TableNodeInfoInner>(nullptr);
4380
4381 pTmpNodeInfoInner->setDepth(pNodeInfoInner->getDepth());
4382 pTmpNodeInfoInner->setEndOfCell(true);
4383
4384 for (sal_uInt32 n = 0; n < nShadowsAfter; ++n)
4385 {
4386 m_rWW8Export.WriteCR(pTmpNodeInfoInner);
4387
4388 m_rWW8Export.m_pO->insert( m_rWW8Export.m_pO->end(), nStyle, nStyle+2 ); // Style #
4389 TableInfoCell(pTmpNodeInfoInner);
4390 m_rWW8Export.m_pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.m_pO->size(), m_rWW8Export.m_pO->data() );
4391
4392 m_rWW8Export.m_pO->clear();
4393 }
4394 }
4395
4396 if (pNodeInfoInner->isEndOfLine())
4397 {
4398 SAL_INFO( "sw.ww8", "<endOfLine/>" );
4399
4400 TableRowEnd(pNodeInfoInner->getDepth());
4401
4402 ShortToSVBT16(0, nStyle);
4403 m_rWW8Export.m_pO->insert( m_rWW8Export.m_pO->end(), nStyle, nStyle+2 ); // Style #
4404 TableInfoRow(pNodeInfoInner);
4405 m_rWW8Export.m_pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.m_pO->size(), m_rWW8Export.m_pO->data() );
4406
4407 m_rWW8Export.m_pO->clear();
4408 }
4409 SAL_INFO( "sw.ww8", "</OutWW8_TableNodeInfoInner>" );
4410}
4411
4413{
4414
4416 m_pTableInfo->getTableNodeInfo( &rNode );
4417
4418 if (pNodeInfo)
4419 {
4420#ifdef DBG_UTIL
4421 SAL_INFO( "sw.ww8", pNodeInfo->toString());
4422#endif
4423 const ww8::WW8TableNodeInfo::Inners_t aInners = pNodeInfo->getInners();
4424 ww8::WW8TableNodeInfo::Inners_t::const_reverse_iterator aIt(aInners.rbegin());
4425 ww8::WW8TableNodeInfo::Inners_t::const_reverse_iterator aEnd(aInners.rend());
4426 while (aIt != aEnd)
4427 {
4428 ww8::WW8TableNodeInfoInner::Pointer_t pInner = aIt->second;
4429
4431 ++aIt;
4432 }
4433 }
4434 SAL_INFO( "sw.ww8", "</OutWW8_SwStartNode>" );
4435}
4436
4438{
4439#ifdef DBG_UTIL
4440 SAL_INFO( "sw.ww8", "<OutWW8_SwEndNode>" << dbg_out(&rNode));
4441#endif
4442
4443 ww8::WW8TableNodeInfo::Pointer_t pNodeInfo = m_pTableInfo->getTableNodeInfo( &rNode );
4444
4445 if (pNodeInfo)
4446 {
4447#ifdef DBG_UTIL
4448 SAL_INFO( "sw.ww8", pNodeInfo->toString());
4449#endif
4450 const ww8::WW8TableNodeInfo::Inners_t aInners = pNodeInfo->getInners();
4451 for (const auto& rEntry : aInners)
4452 {
4453 ww8::WW8TableNodeInfoInner::Pointer_t pInner = rEntry.second;
4455 }
4456 }
4457 SAL_INFO( "sw.ww8", "</OutWW8_SwEndNode>" );
4458}
4459
4461{
4462 if (m_pKeyMap == nullptr)
4463 {
4464 m_pKeyMap = std::make_shared<NfKeywordTable>();
4465 NfKeywordTable & rKeywordTable = *m_pKeyMap;
4466 rKeywordTable[NF_KEY_D] = "d";
4467 rKeywordTable[NF_KEY_DD] = "dd";
4468 rKeywordTable[NF_KEY_DDD] = "ddd";
4469 rKeywordTable[NF_KEY_DDDD] = "dddd";
4470 rKeywordTable[NF_KEY_M] = "M";
4471 rKeywordTable[NF_KEY_MM] = "MM";
4472 rKeywordTable[NF_KEY_MMM] = "MMM";
4473 rKeywordTable[NF_KEY_MMMM] = "MMMM";
4474 rKeywordTable[NF_KEY_NN] = "ddd";
4475 rKeywordTable[NF_KEY_NNN] = "dddd";
4476 rKeywordTable[NF_KEY_NNNN] = "dddd";
4477 rKeywordTable[NF_KEY_YY] = "yy";
4478 rKeywordTable[NF_KEY_YYYY] = "yyyy";
4479 rKeywordTable[NF_KEY_H] = "H";
4480 rKeywordTable[NF_KEY_HH] = "HH";
4481 rKeywordTable[NF_KEY_MI] = "m";
4482 rKeywordTable[NF_KEY_MMI] = "mm";
4483 rKeywordTable[NF_KEY_S] = "s";
4484 rKeywordTable[NF_KEY_SS] = "ss";
4485 rKeywordTable[NF_KEY_AMPM] = "AM/PM";
4486 }
4487
4488 return *m_pKeyMap;
4489}
4490
4491/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
@ ShowDelete
show all deletes
@ On
RedlineFlags on.
@ ShowInsert
show all inserts
@ DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK
void * rtlRandomPool
SvxBoxItemLine
static OutputDevice * GetDefaultDevice()
virtual void BulletDefinition(int, const Graphic &, Size)
Exports the definition (image, size) of a single numbering picture bullet.
ww8::WidthsPtr GetColumnWidths(ww8::WW8TableNodeInfoInner::Pointer_t const &pTableTextNodeInfoInner)
Definition: wrtww8.cxx:2436
virtual MSWordExportBase & GetExport()=0
Return the right export class.
void GetTablePageSize(ww8::WW8TableNodeInfoInner const *pTableTextNodeInfoInner, tools::Long &rPageSize, bool &rRelBoxSize)
Definition: wrtww8.cxx:2442
ww8::GridColsPtr GetGridCols(ww8::WW8TableNodeInfoInner::Pointer_t const &pTableTextNodeInfoInner)
Definition: wrtww8.cxx:2431
virtual void TableNodeInfoInner(ww8::WW8TableNodeInfoInner::Pointer_t pNodeInfoInner)=0
const OUString & GetValue() const
Size GetPrefSize() const
BitmapChecksum GetChecksum() const
MapMode GetPrefMapMode() const
virtual const SwDrawModel * GetDrawModel() const =0
Draw Model and id accessors.
virtual sw::tExternalDataPointer getExternalData(sw::tExternalDataType eType)=0
virtual const SwRootFrame * GetCurrentLayout() const =0
virtual const SwViewShell * GetCurrentViewShell() const =0
Returns the layout set at the document.
virtual const SwRedlineTable & GetRedlineTable() const =0
virtual void SetRedlineFlags(RedlineFlags eMode)=0
Set a new redline mode.
virtual RedlineFlags GetRedlineFlags() const =0
Query the currently set redline mode.
Provides access to settings of a document.
virtual sal_uInt32 Getn32DummyCompatibilityOptions1() const =0
Get the n32DummyCompatibilityOptions1.
virtual bool get(DocumentSettingId id) const =0
Return the specified document setting.
virtual CharCompressType getCharacterCompressionType() const =0
Get the character compression type for Asian characters.
virtual const css::i18n::ForbiddenCharacters * getForbiddenCharacters(LanguageType nLang, bool bLocaleData) const =0
Return the forbidden characters.
virtual sal_uInt32 Getn32DummyCompatibilityOptions2() const =0
Get the n32DummyCompatibilityOptions2.
virtual const SwDocStat & GetDocStat() const =0
Document - Statistics.
virtual SwTextFormatColl * GetTextCollFromPool(sal_uInt16 nId, bool bRegardLanguage=true)=0
Return "Auto-Collection with ID.
const OUString & GetURL() const
static OUString decode(std::u16string_view rText, DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
IMapObject * GetIMapObject(size_t nPos) const
size_t GetIMapObjectCount() const
[MS-OSHARED] FactoidType: one smart tag type.
Definition: ww8struc.hxx:1097
OUString m_aUri
Definition: ww8struc.hxx:1104
OUString m_aTag
Definition: ww8struc.hxx:1105
sal_uInt32 m_nId
Definition: ww8struc.hxx:1103
std::vector< MSOFactoidType > m_aFactoidTypes
Definition: ww8struc.hxx:1115
std::vector< OUString > m_aStringTable
Definition: ww8struc.hxx:1116
[MS-OSHARED] PropertyBag: stores information about one smart tag.
Definition: ww8struc.hxx:1135
std::vector< MSOProperty > m_aProperties
Definition: ww8struc.hxx:1143
sal_uInt16 m_nId
Matches MSOFactoidType::m_nId in MSOPropertyBagStore::m_aFactoidTypes.
Definition: ww8struc.hxx:1142
[MS-OSHARED] Property: stores information about one smart-tag key/value.
Definition: ww8struc.hxx:1121
sal_uInt32 m_nValue
Index into MSOPropertyBagStore::m_aStringTable.
Definition: ww8struc.hxx:1130
sal_uInt32 m_nKey
Index into MSOPropertyBagStore::m_aStringTable.
Definition: ww8struc.hxx:1128
virtual const SfxPoolItem & GetItem(sal_uInt16 nWhich) const =0
virtual const SfxPoolItem * HasTextItem(sal_uInt16 nWhich) const =0
Base class for WW8Export and DocxExport.
Definition: wrtww8.hxx:451
std::unique_ptr< WW8_WrtRedlineAuthor > m_pRedlAuthors
Definition: wrtww8.hxx:473
bool m_bBreakBefore
Definition: wrtww8.hxx:552
bool m_bEndAtTextEnd
Definition: wrtww8.hxx:564
Point * m_pFlyOffset
Definition: wrtww8.hxx:523
void WriteText()
Iterate through the nodes and call the appropriate OutputNode() on them.
Definition: wrtww8.cxx:2785
SvxFrameDirection TrueFrameDirection(const SwFrameFormat &rFlyFormat) const
Right to left?
Definition: wrtw8nds.cxx:1662
RndStdIds m_eNewAnchorType
Definition: wrtww8.hxx:524
virtual void SectionBreaksAndFrames(const SwTextNode &rNode)=0
sal_uInt8 m_nTextTyp
Definition: wrtww8.hxx:549
std::stack< MSWordSaveData > m_aSaveData
Stack to remember the nesting (see MSWordSaveData for more)
Definition: wrtww8.hxx:582
std::unique_ptr< WW8_WrPlcField > m_pFieldAtn
Definition: wrtww8.hxx:530
virtual ErrCode ExportDocument_Impl()=0
Format-dependent part of the actual export.
void CollectOutlineBookmarks(const SwDoc &rDoc)
Definition: wrtww8.cxx:3253
sal_uInt16 m_nStyleBeforeFly
style number of the node
Definition: wrtww8.hxx:482
bool m_bInWriteEscher
Definition: wrtww8.hxx:560
bool m_bFootnoteAtTextEnd
Definition: wrtww8.hxx:563
int CollectGrfsOfBullets()
Populates m_vecBulletPic with all the bullet graphics used by numberings.
Definition: wrtww8.cxx:1522
bool IsInTable() const
Return whether currently exported node is in table.
Definition: wrtww8.cxx:2959
bool m_bOrigShowChanges
Remember the original Show Changes mode.
Definition: wrtww8.hxx:489
const sw::BroadcastingModify * m_pOutFormatNode
Definition: wrtww8.hxx:539
sal_uInt16 m_nUniqueList
current number for creating unique list names
Definition: wrtww8.hxx:485
virtual void OutputEndNode(const SwEndNode &)
Output SwEndNode.
Definition: wrtww8.cxx:4437
std::unique_ptr< MainTextPlcDrawObj > m_pSdrObjs
Definition: wrtww8.hxx:542
std::unique_ptr< WW8_WrPct > m_pPiece
Definition: wrtww8.hxx:459
std::unique_ptr< WW8_WrPlcTextBoxes > m_pHFTextBxs
Definition: wrtww8.hxx:506
SwEscherEx * m_pEscher
Definition: wrtww8.hxx:545
virtual void SaveData(SwNodeOffset nStt, SwNodeOffset nEnd)
Remember some of the members so that we can recurse in WriteText().
Definition: wrtww8.cxx:1893
RedlineFlags m_nOrigRedlineFlags
Remember the original redline mode.
Definition: wrtww8.hxx:488
std::vector< const Graphic * > m_vecBulletPic
Vector to record all the graphics of bullets.
Definition: wrtww8.hxx:920
std::unique_ptr< SvxBrushItem > getBackground()
Get background color of the document, if there is one.
Definition: wrtww8.cxx:1506
ErrCode ExportDocument(bool bWriteAll)
The main function to export the document.
Definition: wrtww8.cxx:3320
void OutputSectionNode(const SwSectionNode &)
Output SwSectionNode.
Definition: wrtw8nds.cxx:3245
std::vector< const SwTOXType * > m_aTOXArr
Definition: wrtww8.hxx:456
void WriteSpecialText(SwNodeOffset nStart, SwNodeOffset nEnd, sal_uInt8 nTTyp)
Set the pCurPam appropriately and call WriteText().
Definition: wrtww8.cxx:1798
std::unique_ptr< SwWW8WrGrf > m_pGrf
Definition: wrtww8.hxx:537
void OutputContentNode(SwContentNode &)
Call the right (virtual) function according to the type of the item.
Definition: wrtw8nds.cxx:3556
bool m_bAddFootnoteTab
Definition: wrtww8.hxx:574
std::unique_ptr< WW8_WrPlcField > m_pFieldTextBxs
Definition: wrtww8.hxx:531
std::unique_ptr< WW8_WrtBookmarks > m_pBkmks
Definition: wrtww8.hxx:472
std::shared_ptr< NfKeywordTable > m_pKeyMap
Definition: wrtww8.hxx:474
std::unique_ptr< MSWordStyles > m_pStyles
Definition: wrtww8.hxx:503
std::vector< aBookmarkPair > m_aImplicitBookmarks
Definition: wrtww8.hxx:493
ww8::WW8TableInfo::Pointer_t m_pTableInfo
Definition: wrtww8.hxx:478
const NfKeywordTable & GetNfKeywordTable()
Definition: wrtww8.cxx:4460
std::unique_ptr< SvxMSExportOLEObjects > m_pOLEExp
Definition: wrtww8.hxx:475
virtual void AppendSection(const SwPageDesc *pPageDesc, const SwSectionFormat *pFormat, sal_uLong nLnNum)=0
sal_uInt16 m_nCharFormatStart
Definition: wrtww8.hxx:480
std::vector< ::sw::mark::IMark * > IMarkVector
Used to split the runs according to the bookmarks start and ends.
Definition: wrtww8.hxx:585
const SfxPoolItem * HasItem(sal_uInt16 nWhich) const
Definition: wrtww8.cxx:758
SwNodeOffset m_nCurEnd
Definition: wrtww8.hxx:577
virtual void RestoreData()
Restore what was saved in SaveData().
Definition: wrtww8.cxx:1925
wwFontHelper m_aFontHelper
Definition: wrtww8.hxx:453
bool m_bInWriteTOX
Definition: wrtww8.hxx:562
void OutputStartNode(const SwStartNode &)
Output SwStartNode.
Definition: wrtww8.cxx:4412
const SfxPoolItem & GetItem(sal_uInt16 nWhich) const
Definition: wrtww8.cxx:780
OUString m_aMainStg
Definition: wrtww8.hxx:455
const SwAttrSet * m_pStyAttr
Definition: wrtww8.hxx:538
std::unique_ptr< WW8_WrMagicTable > m_pMagicTable
Definition: wrtww8.hxx:533
std::unique_ptr< WW8_WrPlcField > m_pFieldMain
Definition: wrtww8.hxx:526
int GetGrfIndex(const SvxBrushItem &rBrush)
Returns the index of a picture bullet, used in numberings.
Definition: wrtww8.cxx:1630
std::unique_ptr< WW8_WrPlcField > m_pFieldEdn
Definition: wrtww8.hxx:529
void AddLinkTarget(std::u16string_view rURL)
Definition: wrtww8.cxx:3129
void OutputSectionBreaks(const SfxItemSet *pSet, const SwNode &rNd, bool isCellOpen=false)
Start new section.
Definition: ww8atr.cxx:480
void GatherChapterFields()
Setup the chapter fields (maChapterFieldLocs).
Definition: ww8atr.cxx:402
bool m_bOutFirstPage
Definition: wrtww8.hxx:556
SwNodeOffset m_nCurStart
Definition: wrtww8.hxx:577
const SwPageDesc * m_pCurrentPageDesc
Definition: wrtww8.hxx:497
sal_uInt16 m_nFormatCollStart
Definition: wrtww8.hxx:481
std::unique_ptr< WW8_WrPlcField > m_pFieldHdFt
Definition: wrtww8.hxx:527
std::unique_ptr< SwMSConvertControls > m_pOCXExp
Definition: wrtww8.hxx:476
std::unique_ptr< WW8_WrtFactoids > m_pFactoids
Definition: wrtww8.hxx:505
bool GetBookmarks(const SwTextNode &rNd, sal_Int32 nStt, sal_Int32 nEnd, IMarkVector &rArr)
Definition: wrtw8nds.cxx:1941
bool NeedTextNodeSplit(const SwTextNode &rNd, SwSoftPageBreakList &pList) const
Definition: wrtw8nds.cxx:2196
const SfxItemSet * m_pISet
Definition: wrtww8.hxx:457
const SwFormat * m_pCurrentStyle
Definition: wrtww8.hxx:540
const ww8::Frame * m_pParentFrame
Definition: wrtww8.hxx:520
bool GetAnnotationMarks(const SwWW8AttrIter &rAttrs, sal_Int32 nStt, sal_Int32 nEnd, IMarkVector &rArr)
Definition: wrtw8nds.cxx:1988
std::unique_ptr< SwNumRuleTable > m_pUsedNumTable
Definition: wrtww8.hxx:460
sal_uInt16 m_nLastFormatId
Style of last TextNode in normal range.
Definition: wrtww8.hxx:484
bool m_bOutPageDescs
PageDescs (section properties) are being written.
Definition: wrtww8.hxx:555
std::unordered_map< OUString, OUString > m_TOXMarkBookmarksByURL
Definition: wrtww8.hxx:494
std::unique_ptr< WW8_WrPlcField > m_pFieldHFTextBxs
Definition: wrtww8.hxx:532
virtual AttributeOutputBase & AttrOutput() const =0
Access to the attribute output class.
std::unordered_map< SwTOXMark const *, OUString > m_TOXMarkBookmarksByTOXMark
Definition: wrtww8.hxx:495