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