1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
28 #include <unotools/ucbstreamhelper.hxx>
29 #include <unotools/streamwrap.hxx>
30 #include <unotools/securityoptions.hxx>
33 #include <hintids.hxx>
35 #include <o3tl/safeint.hxx>
36 #include <osl/endian.h>
37 #include <sal/log.hxx>
39 #include <drawdoc.hxx>
41 #include <sot/storage.hxx>
42 #include <sfx2/docinf.hxx>
43 #include <editeng/tstpitem.hxx>
44 #include <svx/svdpage.hxx>
45 #include <editeng/hyphenzoneitem.hxx>
46 #include <filter/msfilter/classids.hxx>
47 #include <filter/msfilter/msoleexp.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>
54 #include <swtblfmt.hxx>
55 #include <fmtcntnt.hxx>
56 #include <fmtpdsc.hxx>
57 #include <fmtrowsplt.hxx>
59 #include <../../core/inc/rootfrm.hxx>
61 #include <IDocumentSettingAccess.hxx>
62 #include <IDocumentDrawModelAccess.hxx>
63 #include <IDocumentStylePoolAccess.hxx>
64 #include <IDocumentStatistics.hxx>
65 #include <IDocumentLayoutAccess.hxx>
66 #include <IDocumentExternalData.hxx>
67 #include <viewopt.hxx>
71 #include <shellio.hxx>
72 #include <docstat.hxx>
73 #include <pagedesc.hxx>
74 #include <poolfmt.hxx>
76 #include <swtable.hxx>
79 #include <swmodule.hxx>
80 #include <section.hxx>
81 #include <fmtinfmt.hxx>
82 #include <txtinet.hxx>
84 #include <vcl/imap.hxx>
85 #include <vcl/imapobj.hxx>
87 #include <strings.hrc>
88 #include <fmtline.hxx>
89 #include <fmtfsize.hxx>
90 #include <formatflysplit.hxx>
91 #include <fmtftntx.hxx>
92 #include "sprmids.hxx"
94 #include <comphelper/sequenceashashmap.hxx>
95 #include <comphelper/processfactory.hxx>
96 #include "writerhelper.hxx"
97 #include "writerwordglue.hxx"
98 #include "ww8attributeoutput.hxx"
99 #include <xmloff/odffields.hxx>
100 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
101 #include <com/sun/star/document/XDocumentProperties.hpp>
102 #include <dbgoutsw.hxx>
103 #include <sfx2/docfile.hxx>
104 #include <sfx2/frame.hxx>
105 #include <svl/stritem.hxx>
106 #include <unotools/tempfile.hxx>
107 #include <filter/msfilter/mscodec.hxx>
108 #include <filter/msfilter/svxmsbas.hxx>
109 #include <rtl/random.h>
110 #include <vcl/svapp.hxx>
111 #include <sfx2/docfilt.hxx>
112 #include "WW8Sttbf.hxx"
113 #include <editeng/charrotateitem.hxx>
114 #include <svx/swframetypes.hxx>
115 #include "WW8FibData.hxx"
116 #include <numrule.hxx>
117 #include <fmtclds.hxx>
118 #include <rdfhelper.hxx>
119 #include <fmtclbl.hxx>
120 #include <iodetect.hxx>
121 #include <fmtwrapinfluenceonobjpos.hxx>
122 #include <officecfg/Office/Common.hxx>
123 #include <fmtanchr.hxx>
126 using namespace sw::util
;
127 using namespace sw::types
;
129 /** FKP - Formatted disK Page
133 sal_uInt8
* m_pFkp
; // Fkp total ( first and only FCs and Sprms )
134 sal_uInt8
* m_pOfs
; // pointer to the offset area, later copied to pFkp
136 short m_nStartGrp
; // from here on grpprls
137 short m_nOldStartGrp
;
138 sal_uInt8 m_nItemSize
;
139 sal_uInt8 m_nIMax
; // number of entry pairs
140 sal_uInt8 m_nOldVarLen
;
141 bool m_bCombined
; // true : paste not allowed
143 sal_uInt8
SearchSameSprm( sal_uInt16 nVarLen
, const sal_uInt8
* pSprms
);
145 WW8_WrFkp(const WW8_WrFkp
&) = delete;
146 WW8_WrFkp
& operator=(const WW8_WrFkp
&) = delete;
149 WW8_WrFkp(ePLCFT ePl
, WW8_FC nStartFc
);
151 bool Append( WW8_FC nEndFc
, sal_uInt16 nVarLen
, const sal_uInt8
* pSprms
);
153 void Write( SvStream
& rStrm
, SwWW8WrGrf
& rGrf
);
155 bool IsEqualPos(WW8_FC nEndFc
) const
156 { return !m_bCombined
&& m_nIMax
&& nEndFc
== reinterpret_cast<sal_Int32
*>(m_pFkp
)[m_nIMax
]; }
157 void MergeToNew( short& rVarLen
, sal_uInt8
*& pNewSprms
);
158 bool IsEmptySprm() const
159 { return !m_bCombined
&& m_nIMax
&& !m_nOldVarLen
; }
160 void SetNewEnd( WW8_FC nEnd
)
161 { reinterpret_cast<sal_Int32
*>(m_pFkp
)[m_nIMax
] = nEnd
; }
163 WW8_FC
GetStartFc() const;
164 WW8_FC
GetEndFc() const;
166 sal_uInt8
*CopyLastSprms(sal_uInt8
&rLen
);
169 // class WW8_WrPc collects all piece entries for one piece
172 WW8_CP m_nStartCp
; // Starting character position of the text
173 WW8_FC m_nStartFc
; // Starting file position of the text
174 sal_uInt16 m_nStatus
; // End of paragraph inside the piece?
177 WW8_WrPc(WW8_FC nSFc
, WW8_CP nSCp
)
178 : m_nStartCp( nSCp
), m_nStartFc( nSFc
), m_nStatus( 0x0040 )
181 void SetStatus() { m_nStatus
= 0x0050; }
182 sal_uInt16
GetStatus() const { return m_nStatus
; }
183 WW8_CP
GetStartCp() const { return m_nStartCp
; }
184 WW8_FC
GetStartFc() const { return m_nStartFc
; }
187 typedef std::map
<OUString
,tools::Long
> BKMKNames
;
188 typedef std::pair
<bool,OUString
> BKMK
;
189 typedef std::pair
<tools::Long
,BKMK
> BKMKCP
;
190 typedef std::multimap
<tools::Long
,BKMKCP
*> BKMKCPs
;
191 typedef BKMKCPs::iterator CPItr
;
193 class WW8_WrtBookmarks
196 /// Structure of one item inside this map: (startPos, (endPos, (a bool value?, bookmarkName)))
198 BKMKNames maSwBkmkNms
;
200 WW8_WrtBookmarks(WW8_WrtBookmarks
const&) = delete;
201 WW8_WrtBookmarks
& operator=(WW8_WrtBookmarks
const&) = delete;
206 //! Add a new bookmark to the list OR add an end position to an existing bookmark.
207 void Append( WW8_CP nStartCp
, const OUString
& rNm
);
208 //! Write out bookmarks to file.
209 void Write( WW8Export
& rWrt
);
210 //! Move existing field marks from one position to another.
211 void MoveFieldMarks(WW8_CP nFrom
, WW8_CP nTo
);
214 WW8_WrtBookmarks::WW8_WrtBookmarks()
217 WW8_WrtBookmarks::~WW8_WrtBookmarks()
219 for (auto& rEntry
: maSttCps
)
223 delete rEntry
.second
;
224 rEntry
.second
= nullptr;
229 void WW8_WrtBookmarks::Append( WW8_CP nStartCp
, const OUString
& rNm
)
231 std::pair
<BKMKNames::iterator
, bool> aResult
= maSwBkmkNms
.insert(std::pair
<OUString
,tools::Long
>(rNm
,0L));
235 BKMKCP
* pBKCP
= new BKMKCP(static_cast<tools::Long
>(nStartCp
),aBK
);
236 maSttCps
.insert(std::pair
<tools::Long
,BKMKCP
*>(nStartCp
,pBKCP
));
237 aResult
.first
->second
= static_cast<tools::Long
>(nStartCp
);
241 std::pair
<CPItr
,CPItr
> aRange
= maSttCps
.equal_range(aResult
.first
->second
);
242 for (CPItr aItr
= aRange
.first
;aItr
!= aRange
.second
;++aItr
)
244 if (aItr
->second
&& aItr
->second
->second
.second
== rNm
)
246 if (aItr
->second
->second
.first
)
248 aItr
->second
->first
= static_cast<tools::Long
>(nStartCp
);
255 void WW8_WrtBookmarks::Write( WW8Export
& rWrt
)
257 if (maSttCps
.empty())
260 std::vector
<OUString
> aNames
;
261 SvMemoryStream
aTempStrm1(65535,65535);
262 SvMemoryStream
aTempStrm2(65535,65535);
265 for (const auto& rEntry
: maSttCps
)
269 aEndCps
.insert(std::pair
<tools::Long
,BKMKCP
*>(rEntry
.second
->first
, rEntry
.second
));
270 aNames
.push_back(rEntry
.second
->second
.second
);
271 SwWW8Writer::WriteLong(aTempStrm1
, rEntry
.first
);
277 for (const auto& rEntry
: aEndCps
)
281 rEntry
.second
->first
= n
;
282 SwWW8Writer::WriteLong( aTempStrm2
, rEntry
.first
);
288 rWrt
.WriteAsStringTable(aNames
, rWrt
.m_pFib
->m_fcSttbfbkmk
,rWrt
.m_pFib
->m_lcbSttbfbkmk
);
289 SvStream
& rStrm
= *rWrt
.m_pTableStrm
;
290 rWrt
.m_pFib
->m_fcPlcfbkf
= rStrm
.Tell();
291 rStrm
.WriteStream( aTempStrm1
);
292 SwWW8Writer::WriteLong(rStrm
, rWrt
.m_pFib
->m_ccpText
+ rWrt
.m_pFib
->m_ccpTxbx
);
293 for (const auto& rEntry
: maSttCps
)
297 SwWW8Writer::WriteLong(rStrm
, rEntry
.second
->first
);
300 rWrt
.m_pFib
->m_lcbPlcfbkf
= rStrm
.Tell() - rWrt
.m_pFib
->m_fcPlcfbkf
;
301 rWrt
.m_pFib
->m_fcPlcfbkl
= rStrm
.Tell();
302 rStrm
.WriteStream( aTempStrm2
);
303 SwWW8Writer::WriteLong(rStrm
, rWrt
.m_pFib
->m_ccpText
+ rWrt
.m_pFib
->m_ccpTxbx
);
304 rWrt
.m_pFib
->m_lcbPlcfbkl
= rStrm
.Tell() - rWrt
.m_pFib
->m_fcPlcfbkl
;
307 void WW8_WrtBookmarks::MoveFieldMarks(WW8_CP nFrom
, WW8_CP nTo
)
309 std::pair
<CPItr
,CPItr
> aRange
= maSttCps
.equal_range(nFrom
);
310 CPItr aItr
= aRange
.first
;
311 while (aItr
!= aRange
.second
)
315 if (aItr
->second
->first
== static_cast<tools::Long
>(nFrom
))
317 aItr
->second
->second
.first
= true;
318 aItr
->second
->first
= nTo
;
320 maSttCps
.insert(std::pair
<tools::Long
,BKMKCP
*>(nTo
,aItr
->second
));
321 aItr
->second
= nullptr;
322 aRange
= maSttCps
.equal_range(nFrom
);
330 /// Handles export of smart tags.
331 class WW8_WrtFactoids
333 std::vector
<WW8_CP
> m_aStartCPs
;
334 std::vector
<WW8_CP
> m_aEndCPs
;
335 std::vector
< std::map
<OUString
, OUString
> > m_aStatements
;
337 WW8_WrtFactoids(WW8_WrtFactoids
const&) = delete;
338 WW8_WrtFactoids
& operator=(WW8_WrtFactoids
const&) = delete;
342 void Append(WW8_CP nStartCp
, WW8_CP nEndCp
, const std::map
<OUString
, OUString
>& rStatements
);
343 void Write(WW8Export
& rWrt
);
346 WW8_WrtFactoids::WW8_WrtFactoids()
350 void WW8_WrtFactoids::Append(WW8_CP nStartCp
, WW8_CP nEndCp
, const std::map
<OUString
, OUString
>& rStatements
)
352 m_aStartCPs
.push_back(nStartCp
);
353 m_aEndCPs
.push_back(nEndCp
);
354 m_aStatements
.push_back(rStatements
);
357 void WW8_WrtFactoids::Write(WW8Export
& rExport
)
359 if (m_aStartCPs
.empty())
362 // Smart tags are otherwise removed by Word on saving.
363 rExport
.m_pDop
->fEmbedFactoids
= true;
365 SvStream
& rStream
= *rExport
.m_pTableStrm
;
367 rExport
.m_pFib
->m_fcSttbfBkmkFactoid
= rStream
.Tell();
368 // Write SttbfBkmkFactoid.
369 rStream
.WriteUInt16(0xffff); // fExtend
370 rStream
.WriteUInt16(m_aStartCPs
.size()); // cData
371 rStream
.WriteUInt16(0); // cbExtra
373 for (size_t i
= 0; i
< m_aStartCPs
.size(); ++i
)
375 rStream
.WriteUInt16(6); // cchData
376 // Write FACTOIDINFO.
377 rStream
.WriteUInt32(i
); // dwId
378 rStream
.WriteUInt16(0); // fSubEntry
379 rStream
.WriteUInt16(0); // fto
380 rStream
.WriteUInt32(0); // pfpb
382 rExport
.m_pFib
->m_lcbSttbfBkmkFactoid
= rStream
.Tell() - rExport
.m_pFib
->m_fcSttbfBkmkFactoid
;
384 rExport
.m_pFib
->m_fcPlcfBkfFactoid
= rStream
.Tell();
385 for (const WW8_CP
& rCP
: m_aStartCPs
)
386 rStream
.WriteInt32(rCP
);
387 rStream
.WriteInt32(rExport
.m_pFib
->m_ccpText
+ rExport
.m_pFib
->m_ccpTxbx
);
390 for (size_t i
= 0; i
< m_aStartCPs
.size(); ++i
)
392 rStream
.WriteInt16(i
); // ibkl
393 rStream
.WriteInt16(0); // bkc
394 rStream
.WriteInt16(1); // cDepth, 1 as start and end is the same.
397 rExport
.m_pFib
->m_lcbPlcfBkfFactoid
= rStream
.Tell() - rExport
.m_pFib
->m_fcPlcfBkfFactoid
;
399 rExport
.m_pFib
->m_fcPlcfBklFactoid
= rStream
.Tell();
400 for (const WW8_CP
& rCP
: m_aEndCPs
)
401 rStream
.WriteInt32(rCP
);
402 rStream
.WriteInt32(rExport
.m_pFib
->m_ccpText
+ rExport
.m_pFib
->m_ccpTxbx
);
405 for (size_t i
= 0; i
< m_aEndCPs
.size(); ++i
)
407 rStream
.WriteInt16(i
); // ibkf
408 rStream
.WriteInt16(0); // cDepth, 0 as does not overlap with any other smart tag.
410 rExport
.m_pFib
->m_lcbPlcfBklFactoid
= rStream
.Tell() - rExport
.m_pFib
->m_fcPlcfBklFactoid
;
412 rExport
.m_pFib
->m_fcFactoidData
= rStream
.Tell();
413 // Write SmartTagData.
414 MSOFactoidType aFactoidType
;
415 aFactoidType
.m_nId
= 1;
416 aFactoidType
.m_aUri
= "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
417 aFactoidType
.m_aTag
= "RDF";
418 WW8SmartTagData aSmartTagData
;
419 aSmartTagData
.m_aPropBagStore
.m_aFactoidTypes
.push_back(aFactoidType
);
421 std::set
<OUString
> aSet
;
422 for (const std::map
<OUString
, OUString
>& rStatements
: m_aStatements
)
424 // Statements for a single text node.
425 for (const auto& rPair
: rStatements
)
427 aSet
.insert(rPair
.first
);
428 aSet
.insert(rPair
.second
);
431 aSmartTagData
.m_aPropBagStore
.m_aStringTable
.assign(aSet
.begin(), aSet
.end());
432 for (const std::map
<OUString
, OUString
>& rStatements
: m_aStatements
)
434 MSOPropertyBag aPropertyBag
;
435 aPropertyBag
.m_nId
= 1;
436 for (const auto& rPair
: rStatements
)
438 MSOProperty aProperty
;
439 aProperty
.m_nKey
= std::distance(aSet
.begin(), aSet
.find(rPair
.first
));
440 aProperty
.m_nValue
= std::distance(aSet
.begin(), aSet
.find(rPair
.second
));
441 aPropertyBag
.m_aProperties
.push_back(aProperty
);
443 aSmartTagData
.m_aPropBags
.push_back(aPropertyBag
);
446 aSmartTagData
.Write(rExport
);
447 rExport
.m_pFib
->m_lcbFactoidData
= rStream
.Tell() - rExport
.m_pFib
->m_fcFactoidData
;
450 #define DEFAULT_STYLES_COUNT 16
452 // Names of the storage streams
453 constexpr OUStringLiteral sMainStream
= u
"WordDocument";
454 constexpr OUStringLiteral sCompObj
= u
"\1CompObj";
456 static void WriteDop( WW8Export
& rWrt
)
458 WW8Dop
& rDop
= *rWrt
.m_pDop
;
460 // i#78951#, store the value of unknown compatibility options
461 rDop
.SetCompatibilityOptions( rWrt
.m_rDoc
.getIDocumentSettingAccess().Getn32DummyCompatibilityOptions1());
462 rDop
.SetCompatibilityOptions2( rWrt
.m_rDoc
.getIDocumentSettingAccess().Getn32DummyCompatibilityOptions2());
464 rDop
.fNoLeading
= !rWrt
.m_rDoc
.getIDocumentSettingAccess().get(DocumentSettingId::ADD_EXT_LEADING
);
465 rDop
.fUsePrinterMetrics
= !rWrt
.m_rDoc
.getIDocumentSettingAccess().get(DocumentSettingId::USE_VIRTUAL_DEVICE
);
467 // write default TabStop
468 const SvxTabStopItem
& rTabStop
=
469 rWrt
.m_rDoc
.GetAttrPool().GetUserOrPoolDefaultItem(RES_PARATR_TABSTOP
);
470 rDop
.dxaTab
= o3tl::narrowing
<sal_uInt16
>(rTabStop
[0].GetTabPos());
472 // Zoom factor and type
473 SwViewShell
*pViewShell(rWrt
.m_rDoc
.getIDocumentLayoutAccess().GetCurrentViewShell());
476 switch ( pViewShell
->GetViewOptions()->GetZoomType() )
478 case SvxZoomType::WHOLEPAGE
: rDop
.zkSaved
= 1; break;
479 case SvxZoomType::PAGEWIDTH
: rDop
.zkSaved
= 2; break;
480 case SvxZoomType::OPTIMAL
: rDop
.zkSaved
= 3; break;
481 default: rDop
.zkSaved
= 0;
482 rDop
.wScaleSaved
= pViewShell
->GetViewOptions()->GetZoom();
487 // Values from the DocumentStatistics (are definitely needed
488 // for the DocStat fields)
489 rDop
.fWCFootnoteEdn
= true; // because they are included in StarWriter
491 const SwDocStat
& rDStat
= rWrt
.m_rDoc
.getIDocumentStatistics().GetDocStat();
492 rDop
.cWords
= rDStat
.nWord
;
493 rDop
.cCh
= rDStat
.nChar
;
494 rDop
.cPg
= static_cast< sal_Int16
>(rDStat
.nPage
);
495 rDop
.cParas
= rDStat
.nPara
;
496 rDop
.cLines
= rDStat
.nPara
;
498 SwSectionFormats
& rSections
= rWrt
.m_rDoc
.GetSections();
499 if (!rSections
.empty())
501 SwSectionFormat
* pFormat
= rSections
[0];
502 bool bEndnAtEnd
= pFormat
->GetEndAtTextEnd().IsAtEnd();
505 // DopBase.epc: this is normally 3 (end of document), change this to end of section.
510 SwDocShell
*pDocShell(rWrt
.m_rDoc
.GetDocShell());
511 OSL_ENSURE(pDocShell
, "no SwDocShell");
512 uno::Reference
<document::XDocumentProperties
> xDocProps
;
513 uno::Reference
<beans::XPropertySet
> xProps
;
516 uno::Reference
<lang::XComponent
> xModelComp
= pDocShell
->GetModel();
517 xProps
.set(xModelComp
, uno::UNO_QUERY
);
518 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(xModelComp
, uno::UNO_QUERY_THROW
);
519 xDocProps
= xDPS
->getDocumentProperties();
520 OSL_ENSURE(xDocProps
.is(), "DocumentProperties is null");
522 rDop
.lKeyProtDoc
= pDocShell
->GetModifyPasswordHash();
525 if ((rWrt
.m_pSepx
&& rWrt
.m_pSepx
->DocumentIsProtected()) ||
526 rWrt
.m_rDoc
.getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_FORM
) ||
527 rDop
.lKeyProtDoc
!= 0)
529 rDop
.fProtEnabled
= true;
530 // The password was ignored at import if forms protection was enabled,
531 // so round-trip it since protection is still enabled.
532 if ( rDop
.lKeyProtDoc
== 0 && xProps
.is() )
534 comphelper::SequenceAsHashMap
aPropMap( xProps
->getPropertyValue(u
"InteropGrabBag"_ustr
));
535 aPropMap
.getValue(u
"FormPasswordHash"_ustr
) >>= rDop
.lKeyProtDoc
;
540 rDop
.fProtEnabled
= false;
543 if (rWrt
.m_rDoc
.getIDocumentSettingAccess().get(DocumentSettingId::GUTTER_AT_TOP
))
545 rDop
.iGutterPos
= true;
550 rDop
.dttmCreated
= rDop
.dttmRevised
= rDop
.dttmLastPrint
= 0x45FBAC69;
554 ::util::DateTime uDT
= xDocProps
->getCreationDate();
555 rDop
.dttmCreated
= sw::ms::DateTime2DTTM(DateTime(uDT
));
556 uDT
= xDocProps
->getModificationDate();
557 rDop
.dttmRevised
= sw::ms::DateTime2DTTM(DateTime(uDT
));
558 uDT
= xDocProps
->getPrintDate();
559 rDop
.dttmLastPrint
= sw::ms::DateTime2DTTM(DateTime(uDT
));
562 // Also, the DocStat fields in headers, footers are not calculated correctly.
563 // ( we do not have this fields! )
565 // and also for the Headers and Footers
566 rDop
.cWordsFootnoteEnd
= rDStat
.nWord
;
567 rDop
.cChFootnoteEdn
= rDStat
.nChar
;
568 rDop
.cPgFootnoteEdn
= static_cast<sal_Int16
>(rDStat
.nPage
);
569 rDop
.cParasFootnoteEdn
= rDStat
.nPara
;
570 rDop
.cLinesFootnoteEdn
= rDStat
.nPara
;
572 rDop
.fDontUseHTMLAutoSpacing
= rWrt
.m_rDoc
.getIDocumentSettingAccess().get(DocumentSettingId::PARA_SPACE_MAX
);
574 rDop
.fExpShRtn
= !rWrt
.m_rDoc
.getIDocumentSettingAccess().get(DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK
); // #i56856#
576 IDocumentSettingAccess
& rIDSA
= rWrt
.m_rDoc
.getIDocumentSettingAccess();
577 rDop
.fDontBreakWrappedTables
= rIDSA
.get(DocumentSettingId::DO_NOT_BREAK_WRAPPED_TABLES
);
579 rDop
.Write( *rWrt
.m_pTableStrm
, *rWrt
.m_pFib
);
582 static int lcl_CmpBeginEndChars( const OUString
& rSWStr
,
583 const sal_Unicode
* pMSStr
, int nMSStrByteLen
)
585 nMSStrByteLen
/= sizeof( sal_Unicode
);
586 if( nMSStrByteLen
> rSWStr
.getLength() )
587 nMSStrByteLen
= rSWStr
.getLength()+1;
588 nMSStrByteLen
*= sizeof( sal_Unicode
);
590 return memcmp( rSWStr
.getStr(), pMSStr
, nMSStrByteLen
);
594 Converts the OOo Asian Typography into a best fit match for Microsoft
595 Asian typography. This structure is actually dumped to disk within the
596 Dop Writer. Assumption is that rTypo is cleared to 0 on entry
598 void WW8Export::ExportDopTypography(WW8DopTypography
&rTypo
)
600 static const sal_Unicode aLangNotBegin
[4][WW8DopTypography::nMaxFollowing
]=
604 0x0021, 0x0025, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f,
605 0x005d, 0x007d, 0x00a2, 0x00b0, 0x2019, 0x201d, 0x2030, 0x2032,
606 0x2033, 0x2103, 0x3001, 0x3002, 0x3005, 0x3009, 0x300b, 0x300d,
607 0x300f, 0x3011, 0x3015, 0x3041, 0x3043, 0x3045, 0x3047, 0x3049,
608 0x3063, 0x3083, 0x3085, 0x3087, 0x308e, 0x309b, 0x309c, 0x309d,
609 0x309e, 0x30a1, 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30c3, 0x30e3,
610 0x30e5, 0x30e7, 0x30ee, 0x30f5, 0x30f6, 0x30fb, 0x30fc, 0x30fd,
611 0x30fe, 0xff01, 0xff05, 0xff09, 0xff0c, 0xff0e, 0xff1a, 0xff1b,
612 0xff1f, 0xff3d, 0xff5d, 0xff61, 0xff63, 0xff64, 0xff65, 0xff67,
613 0xff68, 0xff69, 0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f,
614 0xff70, 0xff9e, 0xff9f, 0xffe0
618 0x0021, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f, 0x005d,
619 0x007d, 0x00a8, 0x00b7, 0x02c7, 0x02c9, 0x2015, 0x2016, 0x2019,
620 0x201d, 0x2026, 0x2236, 0x3001, 0x3002, 0x3003, 0x3005, 0x3009,
621 0x300b, 0x300d, 0x300f, 0x3011, 0x3015, 0x3017, 0xff01, 0xff02,
622 0xff07, 0xff09, 0xff0c, 0xff0e, 0xff1a, 0xff1b, 0xff1f, 0xff3d,
623 0xff40, 0xff5c, 0xff5d, 0xff5e, 0xffe0
627 0x0021, 0x0025, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f,
628 0x005d, 0x007d, 0x00a2, 0x00b0, 0x2019, 0x201d, 0x2032, 0x2033,
629 0x2103, 0x3009, 0x300b, 0x300d, 0x300f, 0x3011, 0x3015, 0xff01,
630 0xff05, 0xff09, 0xff0c, 0xff0e, 0xff1a, 0xff1b, 0xff1f, 0xff3d,
633 //Traditional Chinese
635 0x0021, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f, 0x005d,
636 0x007d, 0x00a2, 0x00b7, 0x2013, 0x2014, 0x2019, 0x201d, 0x2022,
637 0x2025, 0x2026, 0x2027, 0x2032, 0x2574, 0x3001, 0x3002, 0x3009,
638 0x300b, 0x300d, 0x300f, 0x3011, 0x3015, 0x301e, 0xfe30, 0xfe31,
639 0xfe33, 0xfe34, 0xfe36, 0xfe38, 0xfe3a, 0xfe3c, 0xfe3e, 0xfe40,
640 0xfe42, 0xfe44, 0xfe4f, 0xfe50, 0xfe51, 0xfe52, 0xfe54, 0xfe55,
641 0xfe56, 0xfe57, 0xfe5a, 0xfe5c, 0xfe5e, 0xff01, 0xff09, 0xff0c,
642 0xff0e, 0xff1a, 0xff1b, 0xff1f, 0xff5c, 0xff5d, 0xff64
646 static const sal_Unicode aLangNotEnd
[4][WW8DopTypography::nMaxLeading
] =
650 0x0024, 0x0028, 0x005b, 0x005c, 0x007b, 0x00a3, 0x00a5, 0x2018,
651 0x201c, 0x3008, 0x300a, 0x300c, 0x300e, 0x3010, 0x3014, 0xff04,
652 0xff08, 0xff3b, 0xff5b, 0xff62, 0xffe1, 0xffe5
656 0x0028, 0x005b, 0x007b, 0x00b7, 0x2018, 0x201c, 0x3008, 0x300a,
657 0x300c, 0x300e, 0x3010, 0x3014, 0x3016, 0xff08, 0xff0e, 0xff3b,
658 0xff5b, 0xffe1, 0xffe5
662 0x0028, 0x005b, 0x005c, 0x007b, 0x00a3, 0x00a5, 0x2018, 0x201c,
663 0x3008, 0x300a, 0x300c, 0x300e, 0x3010, 0x3014, 0xff04, 0xff08,
664 0xff3b, 0xff5b, 0xffe6
666 //Traditional Chinese
668 0x0028, 0x005b, 0x007b, 0x00a3, 0x00a5, 0x2018, 0x201c, 0x2035,
669 0x3008, 0x300a, 0x300c, 0x300e, 0x3010, 0x3014, 0x301d, 0xfe35,
670 0xfe37, 0xfe39, 0xfe3b, 0xfe3d, 0xfe3f, 0xfe41, 0xfe43, 0xfe59,
671 0xfe5b, 0xfe5d, 0xff08, 0xff5b
675 const i18n::ForbiddenCharacters
*pForbidden
= nullptr;
676 const i18n::ForbiddenCharacters
*pUseMe
= nullptr;
677 sal_uInt8 nUseReserved
=0;
680 Now we have some minor difficult issues, to wit...
681 a. MicroSoft Office can only store one set of begin and end characters in
682 a given document, not one per language.
683 b. StarOffice has only a concept of one set of begin and end characters for
684 a given language, i.e. not the two levels of kinsoku in japanese
686 What is unknown as yet is if our default begin and end chars for
687 japanese, chinese tradition, chinese simplified and korean are different
688 in Word and Writer. I already suspect that they are different between
689 different version of word itself.
691 So what have come up with is to simply see if any of the four languages
692 in OOo have been changed away from OUR defaults, and if one has then
693 export that. If more than one has in the future we may hack in something
694 which examines our document properties to see which language is used the
695 most and choose that, for now we choose the first and throw an ASSERT
698 /*Our default Japanese Level is 2, this is a special MS hack to set this*/
699 rTypo
.m_reserved2
= 1;
701 for (rTypo
.m_reserved1
=8;rTypo
.m_reserved1
>0;rTypo
.m_reserved1
-=2)
703 pForbidden
= m_rDoc
.getIDocumentSettingAccess().getForbiddenCharacters(rTypo
.GetConvertedLang(),
705 if (nullptr != pForbidden
)
707 int nIdx
= (rTypo
.m_reserved1
-2)/2;
708 if( lcl_CmpBeginEndChars( pForbidden
->endLine
,
709 aLangNotEnd
[ nIdx
], sizeof(aLangNotEnd
[ nIdx
]) ) ||
710 lcl_CmpBeginEndChars( pForbidden
->beginLine
,
711 aLangNotBegin
[ nIdx
], sizeof(aLangNotBegin
[ nIdx
]) ) )
713 //One exception for Japanese, if it matches a level 1 we
714 //can use one extra flag for that, rather than use a custom
715 if (rTypo
.GetConvertedLang() == LANGUAGE_JAPANESE
)
718 !lcl_CmpBeginEndChars
721 WW8DopTypography::JapanNotEndLevel1
.getStr(),
722 WW8DopTypography::nMaxLeading
* sizeof(sal_Unicode
)
725 !lcl_CmpBeginEndChars
727 pForbidden
->beginLine
,
728 WW8DopTypography::JapanNotBeginLevel1
.getStr(),
729 WW8DopTypography::nMaxFollowing
* sizeof(sal_Unicode
)
733 rTypo
.m_reserved2
= 0;
741 nUseReserved
= rTypo
.m_reserved1
;
742 rTypo
.m_iLevelOfKinsoku
= 2;
749 OSL_ENSURE( nNoNeeded
<=1, "Example of unexportable forbidden chars" );
750 rTypo
.m_reserved1
=nUseReserved
;
751 if (rTypo
.m_iLevelOfKinsoku
&& pUseMe
)
753 rTypo
.m_cchFollowingPunct
= msword_cast
<sal_Int16
>
754 (pUseMe
->beginLine
.getLength());
755 if (rTypo
.m_cchFollowingPunct
> WW8DopTypography::nMaxFollowing
- 1)
756 rTypo
.m_cchFollowingPunct
= WW8DopTypography::nMaxFollowing
- 1;
758 rTypo
.m_cchLeadingPunct
= msword_cast
<sal_Int16
>
759 (pUseMe
->endLine
.getLength());
760 if (rTypo
.m_cchLeadingPunct
> WW8DopTypography::nMaxLeading
- 1)
761 rTypo
.m_cchLeadingPunct
= WW8DopTypography::nMaxLeading
-1;
763 memcpy(rTypo
.m_rgxchFPunct
,pUseMe
->beginLine
.getStr(),
764 (rTypo
.m_cchFollowingPunct
+1)*2);
766 memcpy(rTypo
.m_rgxchLPunct
,pUseMe
->endLine
.getStr(),
767 (rTypo
.m_cchLeadingPunct
+1)*2);
770 const IDocumentSettingAccess
& rIDocumentSettingAccess
= GetWriter().getIDocumentSettingAccess();
772 rTypo
.m_fKerningPunct
= sal_uInt16(rIDocumentSettingAccess
.get(DocumentSettingId::KERN_ASIAN_PUNCTUATION
));
773 rTypo
.m_iJustification
= sal_uInt16(m_rDoc
.getIDocumentSettingAccess().getCharacterCompressionType());
776 // It can only be found something with this method, if it is used within
777 // WW8_SwAttrIter::OutAttr() and WW8Export::OutputItemSet()
778 const SfxPoolItem
* MSWordExportBase::HasItem( sal_uInt16 nWhich
) const
780 const SfxPoolItem
* pItem
=nullptr;
783 // if write an EditEngine text, then the WhichIds are greater than
784 // our own Ids. So the Id have to translate from our into the
786 nWhich
= sw::hack::GetSetWhichFromSwDocWhich(*m_pISet
, m_rDoc
, nWhich
);
787 if (nWhich
&& SfxItemState::SET
!= m_pISet
->GetItemState(nWhich
, true, &pItem
))
790 else if( m_pChpIter
)
791 pItem
= m_pChpIter
->HasTextItem( nWhich
);
794 OSL_ENSURE( false, "Where is my ItemSet / pChpIter ?" );
800 const SfxPoolItem
& MSWordExportBase::GetItem(sal_uInt16 nWhich
) const
802 assert((m_pISet
|| m_pChpIter
) && "Where is my ItemSet / pChpIter ?");
805 // if write an EditEngine text, then the WhichIds are greater than
806 // our own Ids. So the Id have to translate from our into the
808 nWhich
= sw::hack::GetSetWhichFromSwDocWhich(*m_pISet
, m_rDoc
, nWhich
);
809 OSL_ENSURE(nWhich
!= 0, "All broken, Impossible");
810 return m_pISet
->Get(nWhich
);
812 return m_pChpIter
->GetItem( nWhich
);
815 WW8_WrPlc1::WW8_WrPlc1( sal_uInt16 nStructSz
)
816 : m_pData( new sal_uInt8
[ 16 * nStructSz
] ),
817 m_nDataLen(16 * nStructSz
),
818 m_nStructSiz( nStructSz
)
822 WW8_WrPlc1::~WW8_WrPlc1()
826 WW8_CP
WW8_WrPlc1::Prev() const
828 bool b
= !m_aPos
.empty();
829 OSL_ENSURE(b
,"Prev called on empty list");
830 return b
? m_aPos
.back() : 0;
833 void WW8_WrPlc1::Append( WW8_CP nCp
, const void* pNewData
)
835 sal_uLong nInsPos
= m_aPos
.size() * m_nStructSiz
;
836 m_aPos
.push_back( nCp
);
837 if( m_nDataLen
< nInsPos
+ m_nStructSiz
)
839 sal_uInt8
* pNew
= new sal_uInt8
[ 2 * m_nDataLen
];
840 memcpy( pNew
, m_pData
.get(), m_nDataLen
);
844 memcpy( m_pData
.get() + nInsPos
, pNewData
, m_nStructSiz
);
847 void WW8_WrPlc1::Finish( sal_uLong nLastCp
, sal_uLong nSttCp
)
849 if( !m_aPos
.empty() )
851 m_aPos
.push_back( nLastCp
);
853 for(WW8_CP
& rCp
: m_aPos
)
858 void WW8_WrPlc1::Write( SvStream
& rStrm
)
860 decltype(m_aPos
)::size_type i
;
861 for( i
= 0; i
< m_aPos
.size(); ++i
)
862 SwWW8Writer::WriteLong( rStrm
, m_aPos
[i
] );
864 rStrm
.WriteBytes(m_pData
.get(), (i
-1) * m_nStructSiz
);
867 // Class WW8_WrPlcField for fields
869 void WW8_WrPlcField::Write( WW8Export
& rWrt
)
871 if( WW8_WrPlc1::Count() <= 1 )
879 pfc
= &rWrt
.m_pFib
->m_fcPlcffldMom
;
880 plc
= &rWrt
.m_pFib
->m_lcbPlcffldMom
;
883 pfc
= &rWrt
.m_pFib
->m_fcPlcffldHdr
;
884 plc
= &rWrt
.m_pFib
->m_lcbPlcffldHdr
;
888 pfc
= &rWrt
.m_pFib
->m_fcPlcffldFootnote
;
889 plc
= &rWrt
.m_pFib
->m_lcbPlcffldFootnote
;
893 pfc
= &rWrt
.m_pFib
->m_fcPlcffldEdn
;
894 plc
= &rWrt
.m_pFib
->m_lcbPlcffldEdn
;
898 pfc
= &rWrt
.m_pFib
->m_fcPlcffldAtn
;
899 plc
= &rWrt
.m_pFib
->m_lcbPlcffldAtn
;
903 pfc
= &rWrt
.m_pFib
->m_fcPlcffldTxbx
;
904 plc
= &rWrt
.m_pFib
->m_lcbPlcffldTxbx
;
908 pfc
= &rWrt
.m_pFib
->m_fcPlcffldHdrTxbx
;
909 plc
= &rWrt
.m_pFib
->m_lcbPlcffldHdrTxbx
;
919 sal_uInt64 nFcStart
= rWrt
.m_pTableStrm
->Tell();
920 WW8_WrPlc1::Write( *rWrt
.m_pTableStrm
);
922 *plc
= rWrt
.m_pTableStrm
->Tell() - nFcStart
;
926 void WW8_WrMagicTable::Write( WW8Export
& rWrt
)
928 if( WW8_WrPlc1::Count() <= 1 )
930 sal_uInt64 nFcStart
= rWrt
.m_pTableStrm
->Tell();
931 WW8_WrPlc1::Write( *rWrt
.m_pTableStrm
);
932 rWrt
.m_pFib
->m_fcPlcfTch
= nFcStart
;
933 rWrt
.m_pFib
->m_lcbPlcfTch
= rWrt
.m_pTableStrm
->Tell() - nFcStart
;
936 void WW8_WrMagicTable::Append( WW8_CP nCp
, sal_uLong nData
)
939 Tell the undocumented table hack that everything between here and the last
940 table position is non-table text, don't do it if the previous position is
941 the same as this one, as that would be a region of 0 length
943 if ((!Count()) || (Prev() != nCp
))
946 UInt32ToSVBT32(nData
,nLittle
);
947 WW8_WrPlc1::Append(nCp
, nLittle
);
951 void SwWW8Writer::FillCount( SvStream
& rStrm
, sal_uLong nCount
)
953 static const sal_uInt32 aNulls
[16] =
955 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 // 64 Byte
960 rStrm
.WriteBytes(aNulls
, 64); // in steps of 64-Byte
963 rStrm
.WriteBytes(aNulls
, nCount
); // write the rest (0 .. 64 Bytes)
966 sal_uLong
SwWW8Writer::FillUntil( SvStream
& rStrm
, sal_uLong nEndPos
)
968 sal_uInt64 nCurPos
= rStrm
.Tell();
969 if( !nEndPos
) // nEndPos == 0 -> next Page
970 nEndPos
= (nCurPos
+ 0x1ff) & ~0x1ffUL
;
972 if( nEndPos
> nCurPos
)
973 SwWW8Writer::FillCount( rStrm
, nEndPos
- nCurPos
);
974 #if OSL_DEBUG_LEVEL > 0
976 OSL_ENSURE( nEndPos
== nCurPos
, "Wrong FillUntil()" );
981 WW8_WrPlcPn::WW8_WrPlcPn(WW8Export
& rWr
, ePLCFT ePl
, WW8_FC nStartFc
)
986 m_Fkps
.push_back(std::make_unique
<WW8_WrFkp
>(m_ePlc
, nStartFc
));
989 WW8_WrPlcPn::~WW8_WrPlcPn()
993 sal_uInt8
*WW8_WrPlcPn::CopyLastSprms(sal_uInt8
&rLen
)
995 WW8_WrFkp
& rF
= *m_Fkps
.back();
996 return rF
.CopyLastSprms(rLen
);
999 void WW8_WrPlcPn::AppendFkpEntry(WW8_FC nEndFc
,short nVarLen
,const sal_uInt8
* pSprms
)
1001 WW8_WrFkp
* pF
= m_Fkps
.back().get();
1003 // big sprm? build the sprmPHugePapx
1004 sal_uInt8
* pNewSprms
= const_cast<sal_uInt8
*>(pSprms
);
1005 sal_uInt8 aHugePapx
[ 8 ];
1006 if (PAP
== m_ePlc
&& 488 <= nVarLen
)
1008 sal_uInt8
* p
= aHugePapx
;
1009 *p
++ = *pSprms
++; // set style Id
1013 sal_uInt64 nDataPos
= m_rWrt
.m_pDataStrm
->Tell();
1014 SwWW8Writer::WriteShort( *m_rWrt
.m_pDataStrm
, nVarLen
);
1015 m_rWrt
.m_pDataStrm
->WriteBytes(pSprms
, nVarLen
);
1017 Set_UInt16( p
, 0x6646 ); // set SprmCode
1018 Set_UInt32( p
, nDataPos
); // set startpos (FC) in the datastream
1019 nVarLen
= static_cast< short >(p
- aHugePapx
);
1020 pSprms
= pNewSprms
= aHugePapx
;
1022 // if append at the same FC-EndPos and there are sprms, then get the old
1023 // sprms and erase it; they will append now with the new sprms
1024 else if( nVarLen
&& pF
->IsEqualPos( nEndFc
))
1025 pF
->MergeToNew( nVarLen
, pNewSprms
);
1026 // has the prev EndFC an empty sprm and the current is empty too, then
1027 // expand only the old EndFc to the new EndFc
1028 else if( !nVarLen
&& pF
->IsEmptySprm() )
1030 pF
->SetNewEnd( nEndFc
);
1034 bool bOk
= pF
->Append(nEndFc
, nVarLen
, pNewSprms
);
1038 pF
= new WW8_WrFkp(m_ePlc
, pF
->GetEndFc()); // Start new Fkp == end of old Fkp
1040 m_Fkps
.push_back(std::unique_ptr
<WW8_WrFkp
>(pF
));
1041 if( !pF
->Append( nEndFc
, nVarLen
, pNewSprms
) )
1043 OSL_ENSURE( false, "Unable to insert Sprm" );
1046 if( pNewSprms
!= pSprms
) //Merge to new has created a new block
1050 void WW8_WrPlcPn::WriteFkps()
1052 m_nFkpStartPage
= o3tl::narrowing
<sal_uInt16
>( SwWW8Writer::FillUntil( m_rWrt
.Strm() ) >> 9 );
1054 for(const std::unique_ptr
<WW8_WrFkp
> & rp
: m_Fkps
)
1056 rp
->Write( m_rWrt
.Strm(), *m_rWrt
.m_pGrf
);
1061 m_rWrt
.m_pFib
->m_pnChpFirst
= m_nFkpStartPage
;
1062 m_rWrt
.m_pFib
->m_cpnBteChp
= m_Fkps
.size();
1066 m_rWrt
.m_pFib
->m_pnPapFirst
= m_nFkpStartPage
;
1067 m_rWrt
.m_pFib
->m_cpnBtePap
= m_Fkps
.size();
1071 void WW8_WrPlcPn::WritePlc()
1073 sal_uInt64 nFcStart
= m_rWrt
.m_pTableStrm
->Tell();
1074 decltype(m_Fkps
)::size_type i
;
1076 for (i
= 0; i
< m_Fkps
.size(); ++i
)
1078 SwWW8Writer::WriteLong( *m_rWrt
.m_pTableStrm
,
1079 m_Fkps
[ i
]->GetStartFc() );
1082 WW8_FC nEndFc
= i
> 0 ? m_Fkps
[i
- 1]->GetEndFc() : 0;
1083 SwWW8Writer::WriteLong(*m_rWrt
.m_pTableStrm
, nEndFc
);
1085 // for every FKP output the page
1086 for (i
= 0; i
< m_Fkps
.size(); ++i
)
1088 SwWW8Writer::WriteLong( *m_rWrt
.m_pTableStrm
, i
+ m_nFkpStartPage
);
1093 m_rWrt
.m_pFib
->m_fcPlcfbteChpx
= nFcStart
;
1094 m_rWrt
.m_pFib
->m_lcbPlcfbteChpx
= m_rWrt
.m_pTableStrm
->Tell() - nFcStart
;
1098 m_rWrt
.m_pFib
->m_fcPlcfbtePapx
= nFcStart
;
1099 m_rWrt
.m_pFib
->m_lcbPlcfbtePapx
= m_rWrt
.m_pTableStrm
->Tell() - nFcStart
;
1103 WW8_WrFkp::WW8_WrFkp(ePLCFT ePl
, WW8_FC nStartFc
)
1104 : m_ePlc(ePl
), m_nStartGrp(511), m_nOldStartGrp(511),
1105 m_nItemSize( ( CHP
== ePl
) ? 1 : 13 ),
1106 m_nIMax(0), m_nOldVarLen(0), m_bCombined(false)
1108 m_pFkp
= reinterpret_cast<sal_uInt8
*>(new sal_Int32
[128]); // 512 Byte
1109 m_pOfs
= reinterpret_cast<sal_uInt8
*>(new sal_Int32
[128]); // 512 Byte
1110 memset( m_pFkp
, 0, 4 * 128 );
1111 memset( m_pOfs
, 0, 4 * 128 );
1112 reinterpret_cast<sal_Int32
*>(m_pFkp
)[0] = nStartFc
; // 0th entry FC at nStartFc
1115 WW8_WrFkp::~WW8_WrFkp()
1117 delete[] reinterpret_cast<sal_Int32
*>(m_pFkp
);
1118 delete[] reinterpret_cast<sal_Int32
*>(m_pOfs
);
1121 sal_uInt8
WW8_WrFkp::SearchSameSprm( sal_uInt16 nVarLen
, const sal_uInt8
* pSprms
)
1125 // if the sprms contained picture-references then never equal!
1126 for( sal_uInt8 n
= static_cast< sal_uInt8
>(nVarLen
- 1); 3 < n
; --n
)
1127 if( pSprms
[ n
] == GRF_MAGIC_3
&&
1128 pSprms
[ n
-1 ] == GRF_MAGIC_2
&&
1129 pSprms
[ n
-2 ] == GRF_MAGIC_1
)
1134 for( i
= 0; i
< m_nIMax
; i
++ )
1136 sal_uInt8 nStart
= m_pOfs
[i
* m_nItemSize
];
1139 const sal_uInt8
* p
= m_pFkp
+ ( o3tl::narrowing
<sal_uInt16
>(nStart
) << 1 );
1142 : ((o3tl::narrowing
<sal_uInt16
>(*p
++) << 1 ) == (( nVarLen
+1) & 0xfffe)) )
1143 && !memcmp( p
, pSprms
, nVarLen
) )
1144 return nStart
; // found it
1147 return 0; // didn't found it
1150 sal_uInt8
*WW8_WrFkp::CopyLastSprms(sal_uInt8
&rLen
)
1153 sal_uInt8
*pStart
=nullptr,*pRet
=nullptr;
1158 pStart
= m_pFkp
+ ( m_nIMax
+ 1 ) * 4;
1160 sal_uInt8 nStart
= *(pStart
+ (m_nIMax
-1) * m_nItemSize
);
1162 const sal_uInt8
* p
= m_pFkp
+ ( o3tl::narrowing
<sal_uInt16
>(nStart
) << 1 );
1172 pRet
= new sal_uInt8
[rLen
];
1173 memcpy(pRet
,p
,rLen
);
1178 bool WW8_WrFkp::Append( WW8_FC nEndFc
, sal_uInt16 nVarLen
, const sal_uInt8
* pSprms
)
1180 assert((!nVarLen
|| pSprms
) && "Item pointer missing");
1182 OSL_ENSURE( nVarLen
< ( ( m_ePlc
== PAP
) ? 497U : 502U ), "Sprms too long !" );
1186 OSL_ENSURE( false, "Fkp::Append: Fkp is already combined" );
1189 sal_Int32 n
= reinterpret_cast<sal_Int32
*>(m_pFkp
)[m_nIMax
]; // last entry
1192 OSL_ENSURE( nEndFc
>= n
, "+Fkp: FC backwards" );
1193 OSL_ENSURE( !nVarLen
|| !pSprms
|| nEndFc
!= n
,
1194 "+Fkp: used same FC multiple times" );
1195 // same FC without Sprm is ignored without grumbling
1197 return true; // ignore (do not create a new Fkp)
1200 sal_uInt8 nOldP
= nVarLen
? SearchSameSprm( nVarLen
, pSprms
) : 0;
1201 // Combine equal entries
1202 short nOffset
=0, nPos
= m_nStartGrp
;
1203 if (nVarLen
&& !nOldP
)
1205 nPos
= PAP
== m_ePlc
1206 ? ( 13 == m_nItemSize
// HACK: PAP and bWrtWW8 !!
1207 ? (m_nStartGrp
& 0xFFFE ) - nVarLen
- 1
1208 : (m_nStartGrp
- (((nVarLen
+ 1) & 0xFFFE)+1)) & 0xFFFE )
1209 : ((m_nStartGrp
- nVarLen
- 1) & 0xFFFE);
1211 return false; // doesn't fit at all
1212 nOffset
= nPos
; // save offset (can also be uneven!)
1213 nPos
&= 0xFFFE; // Pos for Sprms ( gerade Pos )
1216 if( o3tl::make_unsigned(nPos
) <= ( m_nIMax
+ 2U ) * 4U + ( m_nIMax
+ 1U ) * m_nItemSize
)
1217 // does it fits after the CPs and offsets?
1220 reinterpret_cast<sal_Int32
*>(m_pFkp
)[m_nIMax
+ 1] = nEndFc
; // insert FC
1222 m_nOldVarLen
= static_cast<sal_uInt8
>(nVarLen
);
1223 if( nVarLen
&& !nOldP
)
1224 { // insert it for real
1225 m_nOldStartGrp
= m_nStartGrp
;
1228 m_pOfs
[m_nIMax
* m_nItemSize
] = static_cast<sal_uInt8
>( m_nStartGrp
>> 1 );
1229 // insert (start-of-data >> 1)
1230 sal_uInt8 nCnt
= static_cast< sal_uInt8
>(CHP
== m_ePlc
1231 ? ( nVarLen
< 256 ) ? static_cast<sal_uInt8
>(nVarLen
) : 255
1232 : ( ( nVarLen
+ 1 ) >> 1 ));
1234 m_pFkp
[ nOffset
] = nCnt
; // Enter data length
1235 memcpy( m_pFkp
+ nOffset
+ 1, pSprms
, nVarLen
); // store Sprms
1239 // do not enter for real ( no Sprms or recurrence )
1240 // start-of-data 0 ( no data ) or recurrence
1241 m_pOfs
[m_nIMax
* m_nItemSize
] = nOldP
;
1247 void WW8_WrFkp::Combine()
1252 memcpy( m_pFkp
+ ( m_nIMax
+ 1 ) * 4, m_pOfs
, m_nIMax
* m_nItemSize
);
1255 m_pFkp
[511] = m_nIMax
;
1258 #if defined OSL_BIGENDIAN // only the FCs will be rotated here
1259 sal_uInt16 i
; // the Sprms must be rotated elsewhere
1262 for( i
= 0, p
= (sal_uInt32
*)m_pFkp
; i
<= m_nIMax
; i
++, p
++ )
1263 *p
= OSL_SWAPDWORD( *p
);
1264 #endif // ifdef OSL_BIGENDIAN
1267 void WW8_WrFkp::Write( SvStream
& rStrm
, SwWW8WrGrf
& rGrf
)
1269 Combine(); // If not already combined
1271 sal_uInt8
* p
; // search magic for nPicLocFc
1272 sal_uInt8
* pEnd
= m_pFkp
+ m_nStartGrp
;
1273 for( p
= m_pFkp
+ 511 - 4; p
>= pEnd
; p
-- )
1275 if( *p
!= GRF_MAGIC_1
) // search for signature 0x12 0x34 0x56 0xXX
1277 if( *(p
+1) != GRF_MAGIC_2
)
1279 if( *(p
+2) != GRF_MAGIC_3
)
1282 SVBT32 nPos
; // signature found
1283 UInt32ToSVBT32( rGrf
.GetFPos(), nPos
); // FilePos the graphics
1284 memcpy( p
, nPos
, 4 ); // patch FilePos over the signature
1286 rStrm
.WriteBytes(m_pFkp
, 512);
1289 void WW8_WrFkp::MergeToNew( short& rVarLen
, sal_uInt8
*& rpNewSprms
)
1291 sal_uInt8 nStart
= m_pOfs
[ (m_nIMax
-1) * m_nItemSize
];
1296 sal_uInt8
* p
= m_pFkp
+ ( o3tl::narrowing
<sal_uInt16
>(nStart
) << 1 );
1298 // old and new equal? Then copy only one into the new sprms
1299 if( m_nOldVarLen
== rVarLen
&& !memcmp( p
+1, rpNewSprms
, m_nOldVarLen
))
1301 sal_uInt8
* pNew
= new sal_uInt8
[ m_nOldVarLen
];
1302 memcpy( pNew
, p
+1, m_nOldVarLen
);
1307 sal_uInt8
* pNew
= new sal_uInt8
[ m_nOldVarLen
+ rVarLen
];
1308 memcpy( pNew
, p
+1, m_nOldVarLen
);
1309 memcpy( pNew
+ m_nOldVarLen
, rpNewSprms
, rVarLen
);
1312 rVarLen
= rVarLen
+ m_nOldVarLen
;
1315 // if this Sprms don't used from others, remove it
1317 for (sal_uInt16 n
= 0; n
< m_nIMax
; ++n
)
1319 if (nStart
== m_pOfs
[n
* m_nItemSize
])
1327 m_nStartGrp
= m_nOldStartGrp
;
1328 memset( p
, 0, m_nOldVarLen
+1 );
1332 WW8_FC
WW8_WrFkp::GetStartFc() const
1334 // when bCombined, then the array beginning with pFkp is already byte-swapped
1335 // to LittleEndian, so to extract the start and end positions they must
1338 return SVBT32ToUInt32( m_pFkp
); // 0. Element
1339 return reinterpret_cast<sal_Int32
*>(m_pFkp
)[0];
1342 WW8_FC
WW8_WrFkp::GetEndFc() const
1345 return SVBT32ToUInt32( &(m_pFkp
[m_nIMax
*4]) ); // nIMax-th SVBT32-Element
1346 return reinterpret_cast<sal_Int32
*>(m_pFkp
)[m_nIMax
];
1349 // Method for managing the piece table
1350 WW8_WrPct::WW8_WrPct(WW8_FC nfcMin
)
1356 WW8_WrPct::~WW8_WrPct()
1360 // Fill the piece and create a new one
1361 void WW8_WrPct::AppendPc(WW8_FC nStartFc
)
1363 WW8_CP nStartCp
= nStartFc
- m_nOldFc
; // subtract the beginning of the text
1364 if ( !nStartCp
&& !m_Pcts
.empty())
1366 OSL_ENSURE(1 == m_Pcts
.size(), "empty Piece!");
1370 m_nOldFc
= nStartFc
; // remember StartFc as old
1372 nStartCp
>>= 1; // for Unicode: number of characters / 2
1374 if (!m_Pcts
.empty())
1376 nStartCp
+= m_Pcts
.back()->GetStartCp();
1379 m_Pcts
.push_back(std::make_unique
<WW8_WrPc
>(nStartFc
, nStartCp
));
1382 void WW8_WrPct::WritePc( WW8Export
& rWrt
)
1384 sal_uInt64 nPctStart
;
1385 sal_uLong nOldPos
, nEndPos
;
1387 nPctStart
= rWrt
.m_pTableStrm
->Tell(); // Start piece table
1388 rWrt
.m_pTableStrm
->WriteChar( char(0x02) ); // Status byte PCT
1389 nOldPos
= nPctStart
+ 1; // remember Position
1390 SwWW8Writer::WriteLong( *rWrt
.m_pTableStrm
, 0 ); // then the length
1392 for (auto const& it
: m_Pcts
) // ranges
1394 SwWW8Writer::WriteLong( *rWrt
.m_pTableStrm
, it
->GetStartCp() );
1397 // calculate the last Pos
1398 sal_uLong nStartCp
= rWrt
.m_pFib
->m_fcMac
- m_nOldFc
;
1399 nStartCp
>>= 1; // For Unicode: number of characters / 2
1400 nStartCp
+= m_Pcts
.back()->GetStartCp();
1401 SwWW8Writer::WriteLong( *rWrt
.m_pTableStrm
, nStartCp
);
1404 for (auto const& it
: m_Pcts
)
1406 SwWW8Writer::WriteShort(*rWrt
.m_pTableStrm
, it
->GetStatus());
1407 SwWW8Writer::WriteLong(*rWrt
.m_pTableStrm
, it
->GetStartFc());
1408 SwWW8Writer::WriteShort( *rWrt
.m_pTableStrm
, 0); // PRM=0
1411 // entries in the FIB
1412 rWrt
.m_pFib
->m_fcClx
= nPctStart
;
1413 nEndPos
= rWrt
.m_pTableStrm
->Tell();
1414 rWrt
.m_pFib
->m_lcbClx
= nEndPos
- nPctStart
;
1416 // and register the length as well
1417 SwWW8Writer::WriteLong( *rWrt
.m_pTableStrm
, nOldPos
,
1418 nEndPos
- nPctStart
-5 );
1422 void WW8_WrPct::SetParaBreak()
1424 OSL_ENSURE( !m_Pcts
.empty(), "SetParaBreak : m_Pcts.empty()" );
1425 m_Pcts
.back()->SetStatus();
1428 WW8_CP
WW8_WrPct::Fc2Cp( sal_uLong nFc
) const
1430 OSL_ENSURE( nFc
>= o3tl::make_unsigned(m_nOldFc
), "FilePos lies in front of last piece" );
1431 OSL_ENSURE( ! m_Pcts
.empty(), "Fc2Cp no piece available" );
1434 nFc
/= 2; // Unicode
1435 return nFc
+ m_Pcts
.back()->GetStartCp();
1438 void WW8Export::AppendBookmarks( const SwTextNode
& rNd
, sal_Int32 nCurrentPos
, sal_Int32 nLen
, const SwRedlineData
* /*pRedlineData*/ )
1440 std::vector
< const ::sw::mark::MarkBase
* > aArr
;
1442 const sal_Int32 nCurrentEnd
= nCurrentPos
+ nLen
;
1443 if( !GetWriter().GetBookmarks( rNd
, nCurrentPos
, nCurrentEnd
, aArr
))
1446 SwNodeOffset nNd
= rNd
.GetIndex();
1447 sal_uLong nSttCP
= Fc2Cp( Strm().Tell() );
1448 for(const ::sw::mark::MarkBase
* p
: aArr
)
1450 const ::sw::mark::MarkBase
& rBkmk
= *p
;
1451 if(dynamic_cast< const ::sw::mark::Fieldmark
*>(&rBkmk
))
1454 const SwPosition
* pPos
= &rBkmk
.GetMarkPos();
1455 const SwPosition
* pOPos
= nullptr;
1456 if(rBkmk
.IsExpanded())
1457 pOPos
= &rBkmk
.GetOtherMarkPos();
1458 if( pOPos
&& pOPos
->GetNode() == pPos
->GetNode() &&
1459 pOPos
->GetContentIndex() < pPos
->GetContentIndex() )
1462 pOPos
= &rBkmk
.GetMarkPos();
1465 if( !pOPos
|| ( nNd
== pPos
->GetNodeIndex() &&
1466 ( nContent
= pPos
->GetContentIndex() ) >= nCurrentPos
&&
1467 nContent
< nCurrentEnd
) )
1469 sal_uLong nCp
= nSttCP
+ pPos
->GetContentIndex() - nCurrentPos
;
1470 m_pBkmks
->Append(nCp
, BookmarkToWord(rBkmk
.GetName()));
1472 if( pOPos
&& nNd
== pOPos
->GetNodeIndex() &&
1473 ( nContent
= pOPos
->GetContentIndex() ) >= nCurrentPos
&&
1474 nContent
< nCurrentEnd
)
1476 sal_uLong nCp
= nSttCP
+ pOPos
->GetContentIndex() - nCurrentPos
;
1477 m_pBkmks
->Append(nCp
, BookmarkToWord(rBkmk
.GetName()));
1482 void WW8Export::AppendAnnotationMarks(const SwWW8AttrIter
& rAttrs
, sal_Int32 nCurrentPos
, sal_Int32 nLen
)
1485 if (GetAnnotationMarks(rAttrs
, nCurrentPos
, nCurrentPos
+ nLen
, aMarks
))
1487 for (const sw::mark::MarkBase
* pMark
: aMarks
)
1489 const sal_Int32 nStart
= pMark
->GetMarkStart().GetContentIndex();
1490 if (nStart
== nCurrentPos
)
1492 m_pAtn
->AddRangeStartPosition(pMark
->GetName(), Fc2Cp(Strm().Tell()),
1493 !rAttrs
.HasFlysAt(nCurrentPos
));
1499 void WW8Export::AppendSmartTags(SwTextNode
& rTextNode
)
1501 std::map
<OUString
, OUString
> aStatements
= SwRDFHelper::getTextNodeStatements(u
"urn:bails"_ustr
, rTextNode
);
1502 if (!aStatements
.empty())
1504 WW8_CP nCP
= Fc2Cp(Strm().Tell());
1505 m_pFactoids
->Append(nCP
, nCP
, aStatements
);
1509 void WW8Export::MoveFieldMarks(WW8_CP nFrom
, WW8_CP nTo
)
1511 m_pBkmks
->MoveFieldMarks(nFrom
, nTo
);
1514 void WW8Export::AppendBookmark( const OUString
& rName
)
1516 sal_uInt64 nSttCP
= Fc2Cp( Strm().Tell() );
1517 m_pBkmks
->Append( nSttCP
, rName
);
1520 void WW8Export::AppendBookmarkEndWithCorrection( const OUString
& rName
)
1522 sal_uInt64 nEndCP
= Fc2Cp( Strm().Tell() );
1523 m_pBkmks
->Append( nEndCP
- 1, rName
);
1526 std::unique_ptr
<SvxBrushItem
> MSWordExportBase::getBackground()
1528 const SwFrameFormat
&rFormat
= m_rDoc
.GetPageDesc(0).GetMaster();
1529 std::unique_ptr
<SvxBrushItem
> aBrush
= std::make_unique
<SvxBrushItem
>(RES_BACKGROUND
);
1530 SfxItemState eState
= rFormat
.GetBackgroundState(aBrush
);
1532 if (SfxItemState::SET
== eState
)
1534 // The 'color' is set for the first page style - take it and use it as the background color of the entire DOCX
1535 if (aBrush
->GetColor() != COL_AUTO
|| aBrush
->GetGraphicObject())
1541 // #i120928 collect all the graphics of bullets applied to paragraphs
1542 int MSWordExportBase::CollectGrfsOfBullets()
1544 m_vecBulletPic
.clear();
1546 size_t nCountRule
= m_rDoc
.GetNumRuleTable().size();
1547 for (size_t n
= 0; n
< nCountRule
; ++n
)
1549 const SwNumRule
&rRule
= *( m_rDoc
.GetNumRuleTable().at(n
) );
1550 sal_uInt16 nLevels
= rRule
.IsContinusNum() ? 1 : 9;
1551 for (sal_uInt16 nLvl
= 0; nLvl
< nLevels
; ++nLvl
)
1553 const SwNumFormat
&rFormat
= rRule
.Get(nLvl
);
1554 if (SVX_NUM_BITMAP
!= rFormat
.GetNumberingType())
1558 const Graphic
*pGraf
= rFormat
.GetBrush()? rFormat
.GetBrush()->GetGraphic():nullptr;
1562 for (const Graphic
* p
: m_vecBulletPic
)
1564 if (p
->GetChecksum() == pGraf
->GetChecksum())
1572 Size
aSize(pGraf
->GetPrefSize());
1573 if (0 != aSize
.Height() && 0 != aSize
.Width())
1574 m_vecBulletPic
.push_back(pGraf
);
1580 return m_vecBulletPic
.size();
1583 void MSWordExportBase::BulletDefinitions()
1585 for (size_t i
= 0; i
< m_vecBulletPic
.size(); ++i
)
1587 const MapMode
aMapMode(MapUnit::MapTwip
);
1588 const Graphic
& rGraphic
= *m_vecBulletPic
[i
];
1589 Size
aSize(rGraphic
.GetPrefSize());
1590 if (MapUnit::MapPixel
== rGraphic
.GetPrefMapMode().GetMapUnit())
1591 aSize
= Application::GetDefaultDevice()->PixelToLogic(aSize
, aMapMode
);
1593 aSize
= OutputDevice::LogicToLogic(aSize
,rGraphic
.GetPrefMapMode(), aMapMode
);
1595 if (0 != aSize
.Height() && 0 != aSize
.Width())
1596 AttrOutput().BulletDefinition(i
, rGraphic
, aSize
);
1600 //Export Graphic of Bullets
1601 void WW8Export::ExportGrfBullet(const SwTextNode
& rNd
)
1603 int nCount
= CollectGrfsOfBullets();
1606 SwPosition
aPos(rNd
);
1607 OUString
aPicBullets(u
"_PictureBullets"_ustr
);
1608 AppendBookmark(aPicBullets
);
1609 for (int i
= 0; i
< nCount
; i
++)
1611 ww8::Frame
aFrame(*(m_vecBulletPic
[i
]), aPos
);
1612 OutGrfBullets(aFrame
);
1614 AppendBookmark(aPicBullets
);
1618 static sal_uInt8 nAttrMagicIdx
= 0;
1619 void WW8Export::OutGrfBullets(const ww8::Frame
& rFrame
)
1621 if ( !m_pGrf
|| !m_pChpPlc
|| !m_pO
)
1624 m_pGrf
->Insert(rFrame
);
1625 m_pChpPlc
->AppendFkpEntry( Strm().Tell(), m_pO
->size(), m_pO
->data() );
1628 WriteChar( char(1) );
1630 sal_uInt8 aArr
[ 22 ];
1631 sal_uInt8
* pArr
= aArr
;
1634 Set_UInt16( pArr
, 0x855 );
1635 Set_UInt8( pArr
, 1 );
1637 Set_UInt16( pArr
, 0x083c );
1638 Set_UInt8( pArr
, 0x81 );
1641 Set_UInt16( pArr
, 0x6a03 );
1642 Set_UInt32( pArr
, GRF_MAGIC_321
);
1644 //extern nAttrMagicIdx;
1646 Set_UInt8( pArr
, nAttrMagicIdx
++ );
1647 m_pChpPlc
->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr
- aArr
), aArr
);
1650 int MSWordExportBase::GetGrfIndex(const SvxBrushItem
& rBrush
)
1654 const Graphic
* pGraphic
= rBrush
.GetGraphic();
1657 for (size_t i
= 0; i
< m_vecBulletPic
.size(); ++i
)
1659 if (m_vecBulletPic
[i
]->GetChecksum() == pGraphic
->GetChecksum())
1670 void WW8_WrtRedlineAuthor::Write( Writer
& rWrt
)
1672 WW8Export
& rWW8Wrt
= *(static_cast<SwWW8Writer
&>(rWrt
).m_pExport
);
1673 rWW8Wrt
.WriteAsStringTable(maAuthors
, rWW8Wrt
.m_pFib
->m_fcSttbfRMark
,
1674 rWW8Wrt
.m_pFib
->m_lcbSttbfRMark
);
1677 sal_uInt16
WW8Export::AddRedlineAuthor( std::size_t nId
)
1679 if( !m_pRedlAuthors
)
1681 m_pRedlAuthors
.reset(new WW8_WrtRedlineAuthor
);
1682 m_pRedlAuthors
->AddName(u
"Unknown"_ustr
);
1684 bool bRemovePersonalInfo
1685 = SvtSecurityOptions::IsOptionSet(SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo
)
1686 && !SvtSecurityOptions::IsOptionSet(SvtSecurityOptions::EOption::DocWarnKeepRedlineInfo
);
1687 OUString
sName(SwModule::get()->GetRedlineAuthor(nId
));
1688 return m_pRedlAuthors
->AddName(
1689 bRemovePersonalInfo
? "Author" + OUString::number(mpAuthorIDs
->GetInfoID(sName
)) : sName
);
1692 void WW8Export::WriteAsStringTable(const std::vector
<OUString
>& rStrings
,
1693 sal_Int32
& rfcSttbf
, sal_Int32
& rlcbSttbf
)
1695 sal_uInt16 n
, nCount
= static_cast< sal_uInt16
>(rStrings
.size());
1699 // we have some Redlines found in the document -> the
1700 // Author Name Stringtable
1701 SvStream
& rStrm
= *m_pTableStrm
;
1702 rfcSttbf
= rStrm
.Tell();
1703 SwWW8Writer::WriteShort( rStrm
, -1 );
1704 SwWW8Writer::WriteLong( rStrm
, nCount
);
1705 for( n
= 0; n
< nCount
; ++n
)
1707 const OUString
& rNm
= rStrings
[n
];
1708 SwWW8Writer::WriteShort( rStrm
, rNm
.getLength() );
1709 SwWW8Writer::WriteString16(rStrm
, rNm
, false);
1711 rlcbSttbf
= rStrm
.Tell() - rfcSttbf
;
1714 // WriteShort() sets at FilePos nPos the value nVal and seeks to the old
1715 // FilePos. Used to insert lengths after the fact.
1716 void SwWW8Writer::WriteShort( SvStream
& rStrm
, sal_uLong nPos
, sal_Int16 nVal
)
1718 sal_uInt64 nOldPos
= rStrm
.Tell(); // remember Pos
1720 SwWW8Writer::WriteShort( rStrm
, nVal
);
1721 rStrm
.Seek( nOldPos
);
1724 void SwWW8Writer::WriteLong( SvStream
& rStrm
, sal_uLong nPos
, sal_Int32 nVal
)
1726 sal_uInt64 nOldPos
= rStrm
.Tell(); // remember Pos
1728 SwWW8Writer::WriteLong( rStrm
, nVal
);
1729 rStrm
.Seek( nOldPos
);
1732 void SwWW8Writer::InsUInt16(ww::bytes
&rO
, sal_uInt16 n
)
1735 ShortToSVBT16( n
, nL
);
1736 rO
.push_back(nL
[0]);
1737 rO
.push_back(nL
[1]);
1740 void SwWW8Writer::InsUInt32(ww::bytes
&rO
, sal_uInt32 n
)
1743 UInt32ToSVBT32( n
, nL
);
1744 rO
.push_back(nL
[0]);
1745 rO
.push_back(nL
[1]);
1746 rO
.push_back(nL
[2]);
1747 rO
.push_back(nL
[3]);
1750 void SwWW8Writer::InsAsString16(ww::bytes
&rO
, const OUString
& rStr
)
1752 const sal_Unicode
* pStr
= rStr
.getStr();
1753 for (sal_Int32 n
= 0, nLen
= rStr
.getLength(); n
< nLen
; ++n
, ++pStr
)
1754 SwWW8Writer::InsUInt16( rO
, *pStr
);
1757 void SwWW8Writer::InsAsString8(ww::bytes
&rO
, std::u16string_view rStr
,
1758 rtl_TextEncoding eCodeSet
)
1760 OString
sTmp(OUStringToOString(rStr
, eCodeSet
));
1761 const char *pStart
= sTmp
.getStr();
1762 const char *pEnd
= pStart
+ sTmp
.getLength();
1764 rO
.insert( rO
.end(), pStart
, pEnd
);
1767 void SwWW8Writer::WriteString16(SvStream
& rStrm
, const OUString
& rStr
,
1771 SwWW8Writer::InsAsString16(aBytes
, rStr
);
1773 SwWW8Writer::InsUInt16(aBytes
, 0);
1774 //vectors are guaranteed to have contiguous memory, so we can do
1775 //this while migrating away from WW8Bytes. Meyers Effective STL, item 16
1776 if (!aBytes
.empty())
1777 rStrm
.WriteBytes(aBytes
.data(), aBytes
.size());
1780 void SwWW8Writer::WriteString_xstz(SvStream
& rStrm
, const OUString
& rStr
, bool bAddZero
)
1783 SwWW8Writer::InsUInt16(aBytes
, rStr
.getLength());
1784 SwWW8Writer::InsAsString16(aBytes
, rStr
);
1786 SwWW8Writer::InsUInt16(aBytes
, 0);
1787 rStrm
.WriteBytes(aBytes
.data(), aBytes
.size());
1790 void SwWW8Writer::WriteString8(SvStream
& rStrm
, std::u16string_view rStr
,
1791 bool bAddZero
, rtl_TextEncoding eCodeSet
)
1794 SwWW8Writer::InsAsString8(aBytes
, rStr
, eCodeSet
);
1796 aBytes
.push_back(0);
1797 //vectors are guaranteed to have contiguous memory, so we can do
1798 ////this while migrating away from WW8Bytes. Meyers Effective STL, item 16
1799 if (!aBytes
.empty())
1800 rStrm
.WriteBytes(aBytes
.data(), aBytes
.size());
1803 void WW8Export::WriteStringAsPara( const OUString
& rText
)
1805 if( !rText
.isEmpty() )
1806 OutSwString(rText
, 0, rText
.getLength());
1807 WriteCR(); // CR thereafter
1810 SwWW8Writer::InsUInt16( aArr
, 0/*nStyleId*/ );
1814 SwWW8Writer::InsUInt16( aArr
, NS_sprm::PFInTable::val
);
1815 aArr
.push_back( 1 );
1818 sal_uInt64 nPos
= Strm().Tell();
1819 m_pPapPlc
->AppendFkpEntry( nPos
, aArr
.size(), aArr
.data() );
1820 m_pChpPlc
->AppendFkpEntry( nPos
);
1823 void MSWordExportBase::WriteSpecialText( SwNodeOffset nStart
, SwNodeOffset nEnd
, sal_uInt8 nTTyp
)
1825 sal_uInt8 nOldTyp
= m_nTextTyp
;
1827 auto const pOldPam
= m_pCurPam
; //!! Simply shifting the PaM without restoring should do the job too
1828 SwNodeOffset nOldStart
= m_nCurStart
;
1829 SwNodeOffset nOldEnd
= m_nCurEnd
;
1830 SwPaM
* pOldEnd
= m_pOrigPam
;
1831 bool bOldPageDescs
= m_bOutPageDescs
;
1832 m_bOutPageDescs
= false;
1833 if ( nTTyp
== TXT_FTN
|| nTTyp
== TXT_EDN
)
1834 m_bAddFootnoteTab
= true; // enable one aesthetic tab for this footnote
1836 SetCurPam(nStart
, nEnd
);
1838 // clear linked textboxes since old ones can't be linked to frames in this section
1839 m_aLinkedTextboxesHelper
.clear();
1841 // tdf#106261 Reset table infos, otherwise the depth of the cells will be
1842 // incorrect, in case the header/footer had table(s) and we try to export
1843 // the same table second time.
1844 ww8::WW8TableInfo::Pointer_t
xOldTableInfo(m_pTableInfo
);
1845 m_pTableInfo
= std::make_shared
<ww8::WW8TableInfo
>();
1849 m_pTableInfo
= std::move(xOldTableInfo
);
1851 m_bOutPageDescs
= bOldPageDescs
;
1852 m_pCurPam
= pOldPam
; // delete Pam
1853 m_nCurStart
= nOldStart
;
1854 m_nCurEnd
= nOldEnd
;
1855 m_pOrigPam
= pOldEnd
;
1856 m_nTextTyp
= nOldTyp
;
1859 void WW8Export::OutSwString(const OUString
& rStr
, sal_Int32 nStt
,
1860 sal_Int32
const nLen
)
1863 SAL_INFO( "sw.ww8.level2", "<OutSwString>" );
1867 if( nStt
|| nLen
!= rStr
.getLength() )
1869 OUString
sOut( rStr
.copy( nStt
, nLen
) );
1871 SAL_INFO( "sw.ww8.level2", sOut
);
1873 SwWW8Writer::WriteString16(Strm(), sOut
, false);
1877 SAL_INFO( "sw.ww8.level2", rStr
);
1879 SwWW8Writer::WriteString16(Strm(), rStr
, false);
1883 SAL_INFO( "sw.ww8.level2", "</OutSwString>" );
1886 void WW8Export::WriteCR(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
1888 if (pTableTextNodeInfoInner
&& pTableTextNodeInfoInner
->getDepth() == 1 && pTableTextNodeInfoInner
->isEndOfCell())
1891 WriteChar( '\015' );
1893 m_pPiece
->SetParaBreak();
1896 void WW8Export::WriteChar( sal_Unicode c
)
1898 Strm().WriteUInt16( c
);
1901 void MSWordExportBase::SetCurPam(SwNodeOffset nStt
, SwNodeOffset nEnd
)
1905 m_pCurPam
= Writer::NewUnoCursor( m_rDoc
, nStt
, nEnd
);
1907 // Recognize tables in special cases
1908 if ( nStt
!= m_pCurPam
->GetMark()->GetNodeIndex() &&
1909 m_rDoc
.GetNodes()[ nStt
]->IsTableNode() )
1911 m_pCurPam
->GetMark()->Assign(nStt
);
1914 m_pOrigPam
= m_pCurPam
.get(); // ???
1915 m_pCurPam
->Exchange();
1918 void MSWordExportBase::SaveData( SwNodeOffset nStt
, SwNodeOffset nEnd
)
1920 MSWordSaveData aData
;
1922 // WW8Export only stuff - zeroed here not to issue warnings
1923 aData
.pOOld
= nullptr;
1926 aData
.pOldPam
= m_pCurPam
;
1927 aData
.pOldEnd
= m_pOrigPam
;
1928 aData
.pOldFlyFormat
= m_pParentFrame
;
1929 aData
.pOldPageDesc
= m_pCurrentPageDesc
;
1931 aData
.pOldFlyOffset
= m_pFlyOffset
;
1932 aData
.eOldAnchorType
= m_eNewAnchorType
;
1934 aData
.bOldWriteAll
= false;
1935 aData
.bOldOutTable
= m_bOutTable
;
1936 aData
.bOldFlyFrameAttrs
= m_bOutFlyFrameAttrs
;
1937 aData
.bOldStartTOX
= m_bStartTOX
;
1938 aData
.bOldInWriteTOX
= m_bInWriteTOX
;
1940 SetCurPam(nStt
, nEnd
);
1942 m_bOutTable
= false;
1943 // Caution: bIsInTable should not be set here
1944 m_bOutFlyFrameAttrs
= false;
1945 m_bStartTOX
= false;
1946 m_bInWriteTOX
= false;
1948 m_aSaveData
.push( std::move(aData
) );
1951 void MSWordExportBase::RestoreData()
1953 MSWordSaveData
&rData
= m_aSaveData
.top();
1955 m_pCurPam
= rData
.pOldPam
;
1956 m_nCurStart
= rData
.nOldStart
;
1957 m_nCurEnd
= rData
.nOldEnd
;
1958 m_pOrigPam
= rData
.pOldEnd
;
1960 m_bOutTable
= rData
.bOldOutTable
;
1961 m_bOutFlyFrameAttrs
= rData
.bOldFlyFrameAttrs
;
1962 m_bStartTOX
= rData
.bOldStartTOX
;
1963 m_bInWriteTOX
= rData
.bOldInWriteTOX
;
1965 m_pParentFrame
= rData
.pOldFlyFormat
;
1966 m_pCurrentPageDesc
= rData
.pOldPageDesc
;
1968 m_eNewAnchorType
= rData
.eOldAnchorType
;
1969 m_pFlyOffset
= rData
.pOldFlyOffset
;
1974 void WW8Export::SaveData( SwNodeOffset nStt
, SwNodeOffset nEnd
)
1976 MSWordExportBase::SaveData( nStt
, nEnd
);
1978 MSWordSaveData
&rData
= m_aSaveData
.top();
1980 if ( !m_pO
->empty() )
1982 rData
.pOOld
= std::move(m_pO
);
1983 m_pO
.reset(new ww::bytes
);
1986 rData
.pOOld
= nullptr; // reuse pO
1988 rData
.bOldWriteAll
= GetWriter().m_bWriteAll
;
1989 GetWriter().m_bWriteAll
= true;
1992 void WW8Export::RestoreData()
1994 MSWordSaveData
&rData
= m_aSaveData
.top();
1996 GetWriter().m_bWriteAll
= rData
.bOldWriteAll
;
1998 OSL_ENSURE( m_pO
->empty(), "pO is not empty in WW8Export::RestoreData()" );
2001 m_pO
= std::move(rData
.pOOld
);
2004 MSWordExportBase::RestoreData();
2007 void WW8AttributeOutput::TableInfoCell(const ww8::WW8TableNodeInfoInner::Pointer_t
& pTableTextNodeInfoInner
)
2009 sal_uInt32 nDepth
= pTableTextNodeInfoInner
->getDepth();
2015 m_rWW8Export
.InsUInt16( NS_sprm::PFInTable::val
);
2016 m_rWW8Export
.m_pO
->push_back( sal_uInt8(0x1) );
2017 m_rWW8Export
.InsUInt16( NS_sprm::PItap::val
);
2018 m_rWW8Export
.InsUInt32( nDepth
);
2020 if ( nDepth
> 1 && pTableTextNodeInfoInner
->isEndOfCell() )
2022 m_rWW8Export
.InsUInt16( NS_sprm::PFInnerTableCell::val
);
2023 m_rWW8Export
.m_pO
->push_back( sal_uInt8(0x1) );
2027 void WW8AttributeOutput::TableInfoRow(const ww8::WW8TableNodeInfoInner::Pointer_t
& pTableTextNodeInfoInner
)
2029 sal_uInt32 nDepth
= pTableTextNodeInfoInner
->getDepth();
2035 if ( !pTableTextNodeInfoInner
->isEndOfLine() )
2038 m_rWW8Export
.InsUInt16( NS_sprm::PFInTable::val
);
2039 m_rWW8Export
.m_pO
->push_back( sal_uInt8(0x1) );
2043 m_rWW8Export
.InsUInt16( NS_sprm::PFTtp::val
);
2044 m_rWW8Export
.m_pO
->push_back( sal_uInt8(0x1) );
2047 m_rWW8Export
.InsUInt16( NS_sprm::PItap::val
);
2048 m_rWW8Export
.InsUInt32( nDepth
);
2052 m_rWW8Export
.InsUInt16( NS_sprm::PFInnerTableCell::val
);
2053 m_rWW8Export
.m_pO
->push_back( sal_uInt8(0x1) );
2054 m_rWW8Export
.InsUInt16( NS_sprm::PFInnerTtp::val
);
2055 m_rWW8Export
.m_pO
->push_back( sal_uInt8(0x1) );
2058 // Most of these are per-row definitions, not per-table.
2059 // WW8 has no explicit table start/end markup,
2060 // simply rows with the same table properties that are grouped together as a table.
2061 TableBidi( pTableTextNodeInfoInner
);
2062 TableOrientation( pTableTextNodeInfoInner
);
2063 TableSpacing( pTableTextNodeInfoInner
);
2064 TableDefinition( pTableTextNodeInfoInner
); //per row definitions
2065 TableHeight( pTableTextNodeInfoInner
); //per row definitions
2066 TableBackgrounds( pTableTextNodeInfoInner
); //per row definitions
2067 // Since this isEndOfLine, cell margin defaults for each row come from last column.
2068 TableDefaultBorders( pTableTextNodeInfoInner
); //per row definitions
2069 TableCanSplit( pTableTextNodeInfoInner
); //per row definitions
2070 TableVerticalCell( pTableTextNodeInfoInner
); //per row definitions
2071 TableCellBorders( pTableTextNodeInfoInner
); //per row definitions
2074 static sal_uInt16
lcl_TCFlags(SwDoc
&rDoc
, const SwTableBox
* pBox
, sal_Int32 nRowSpan
)
2076 sal_uInt16 nFlags
= 0;
2080 else if (nRowSpan
< 0)
2083 if (pBox
!= nullptr)
2085 const SwFrameFormat
* pFormat
= pBox
->GetFrameFormat();
2086 switch (pFormat
->GetVertOrient().GetVertOrient())
2088 case text::VertOrientation::CENTER
:
2091 case text::VertOrientation::BOTTOM
:
2097 const SwStartNode
* pSttNd
= pBox
->GetSttNd();
2100 SwNodeIndex
aIdx( *pSttNd
);
2101 const SwContentNode
* pCNd
= SwNodes::GoNext(&aIdx
);
2102 if( pCNd
&& pCNd
->IsTextNode())
2104 SfxItemSetFixed
<RES_CHRATR_ROTATE
, RES_CHRATR_ROTATE
> aCoreSet(rDoc
.GetAttrPool());
2105 static_cast<const SwTextNode
*>(pCNd
)->GetParaAttr(aCoreSet
,
2106 0, static_cast<const SwTextNode
*>(pCNd
)->GetText().getLength());
2107 if ( const SvxCharRotateItem
* pRotate
= aCoreSet
.GetItemIfSet(RES_CHRATR_ROTATE
))
2109 if(pRotate
->GetValue() == 900_deg10
)
2111 nFlags
= nFlags
| 0x0004 | 0x0008;
2113 else if(pRotate
->GetValue() == 2700_deg10
)
2115 nFlags
= nFlags
| 0x0004 | 0x0010;
2125 void WW8AttributeOutput::TableVerticalCell(const ww8::WW8TableNodeInfoInner::Pointer_t
& pTableTextNodeInfoInner
)
2127 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
2128 const SwTableLine
* pTabLine
= pTabBox
->GetUpper();
2129 const SwTableBoxes
& rTableBoxes
= pTabLine
->GetTabBoxes();
2131 sal_uInt8 nBoxes
= rTableBoxes
.size();
2132 for ( sal_uInt8 n
= 0; n
< nBoxes
; n
++ )
2134 const SwTableBox
* pTabBox1
= rTableBoxes
[n
];
2135 const SwFrameFormat
* pFrameFormat
= pTabBox1
->GetFrameFormat();
2137 // Map from our SvxFrameDirection to WW8 TextFlow.
2138 sal_uInt16 nTextFlow
= 0;
2139 switch (m_rWW8Export
.TrueFrameDirection(*pFrameFormat
))
2141 case SvxFrameDirection::Vertical_RL_TB
:
2144 case SvxFrameDirection::Vertical_LR_BT
:
2153 m_rWW8Export
.InsUInt16( NS_sprm::TTextFlow::val
);
2154 m_rWW8Export
.m_pO
->push_back( n
); //start range
2155 m_rWW8Export
.m_pO
->push_back( sal_uInt8(n
+ 1) ); //end range
2156 m_rWW8Export
.InsUInt16(nTextFlow
);
2161 void WW8AttributeOutput::TableCanSplit(const ww8::WW8TableNodeInfoInner::Pointer_t
& pTableTextNodeInfoInner
)
2163 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
2164 const SwTableLine
* pTabLine
= pTabBox
->GetUpper();
2165 const SwFrameFormat
* pLineFormat
= pTabLine
->GetFrameFormat();
2168 By default the row can be split in word, and now in writer we have a
2169 feature equivalent to this, Word stores 1 for fCantSplit if the row
2170 cannot be split, we set true if we can split it. An example is #i4569#
2173 const SwFormatRowSplit
& rSplittable
= pLineFormat
->GetRowSplit();
2174 sal_uInt8 nCantSplit
= (!rSplittable
.GetValue()) ? 1 : 0;
2175 m_rWW8Export
.InsUInt16( NS_sprm::TFCantSplit::val
);
2176 m_rWW8Export
.m_pO
->push_back( nCantSplit
);
2177 m_rWW8Export
.InsUInt16( NS_sprm::TFCantSplit90::val
); // also write fCantSplit90
2178 m_rWW8Export
.m_pO
->push_back( nCantSplit
);
2181 void WW8AttributeOutput::TableBidi(const ww8::WW8TableNodeInfoInner::Pointer_t
& pTableTextNodeInfoInner
)
2183 const SwTable
* pTable
= pTableTextNodeInfoInner
->getTable();
2184 const SwFrameFormat
* pFrameFormat
= pTable
->GetFrameFormat();
2186 if ( m_rWW8Export
.TrueFrameDirection(*pFrameFormat
) == SvxFrameDirection::Horizontal_RL_TB
)
2188 m_rWW8Export
.InsUInt16( NS_sprm::TFBiDi::val
);
2189 m_rWW8Export
.InsUInt16( 1 );
2193 void WW8AttributeOutput::TableRowRedline(const ww8::WW8TableNodeInfoInner::Pointer_t
& /*pTableTextNodeInfoInner*/)
2197 void WW8AttributeOutput::TableCellRedline(const ww8::WW8TableNodeInfoInner::Pointer_t
& /*pTableTextNodeInfoInner*/)
2201 void WW8AttributeOutput::TableHeight(const ww8::WW8TableNodeInfoInner::Pointer_t
& pTableTextNodeInfoInner
)
2203 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
2204 const SwTableLine
* pTabLine
= pTabBox
->GetUpper();
2205 const SwFrameFormat
* pLineFormat
= pTabLine
->GetFrameFormat();
2207 // output line height sprmTDyaRowHeight
2208 tools::Long nHeight
= 0;
2209 const SwFormatFrameSize
& rLSz
= pLineFormat
->GetFrameSize();
2210 if ( SwFrameSize::Variable
!= rLSz
.GetHeightSizeType() && rLSz
.GetHeight() )
2212 if ( SwFrameSize::Minimum
== rLSz
.GetHeightSizeType() )
2213 nHeight
= rLSz
.GetHeight();
2215 nHeight
= -rLSz
.GetHeight();
2220 m_rWW8Export
.InsUInt16( NS_sprm::TDyaRowHeight::val
);
2221 m_rWW8Export
.InsUInt16( o3tl::narrowing
<sal_uInt16
>(nHeight
) );
2226 void WW8AttributeOutput::TableOrientation(const ww8::WW8TableNodeInfoInner::Pointer_t
& pTableTextNodeInfoInner
)
2228 const SwTable
* pTable
= pTableTextNodeInfoInner
->getTable();
2230 const SwFrameFormat
*pFormat
= pTable
->GetFrameFormat();
2233 SAL_WARN( "sw.ww8", "FrameFormat is nil" );
2237 const SwFormatHoriOrient
&rHori
= pFormat
->GetHoriOrient();
2238 const SwFormatVertOrient
&rVert
= pFormat
->GetVertOrient();
2241 !((text::RelOrientation::PRINT_AREA
== rHori
.GetRelationOrient() ||
2242 text::RelOrientation::FRAME
== rHori
.GetRelationOrient())
2244 (text::RelOrientation::PRINT_AREA
== rVert
.GetRelationOrient() ||
2245 text::RelOrientation::FRAME
== rVert
.GetRelationOrient()))
2249 const bool bIsRTL
= m_rWW8Export
.TrueFrameDirection(*pFormat
) == SvxFrameDirection::Horizontal_RL_TB
;
2250 sal_Int16 eHOri
= rHori
.GetHoriOrient();
2253 case text::HoriOrientation::CENTER
:
2254 m_rWW8Export
.InsUInt16( NS_sprm::TJc::val
); //logical orientation required for MSO
2255 m_rWW8Export
.InsUInt16( 1 );
2256 m_rWW8Export
.InsUInt16( NS_sprm::TJc90::val
); //physical orientation required for LO
2257 m_rWW8Export
.InsUInt16( 1 );
2259 case text::HoriOrientation::RIGHT
:
2260 m_rWW8Export
.InsUInt16( NS_sprm::TJc90::val
); //required for LO
2261 m_rWW8Export
.InsUInt16( 2 );
2264 m_rWW8Export
.InsUInt16( NS_sprm::TJc::val
); //required for MSO
2265 m_rWW8Export
.InsUInt16( 2 );
2268 case text::HoriOrientation::LEFT
:
2271 m_rWW8Export
.InsUInt16( NS_sprm::TJc::val
); //required for MSO
2272 m_rWW8Export
.InsUInt16( 2 );
2275 case text::HoriOrientation::LEFT_AND_WIDTH
:
2276 // Width can only be specified for the LOGICAL left, so in RTL, that is always PHYSICAL right
2279 m_rWW8Export
.InsUInt16( NS_sprm::TJc90::val
); //required for LO
2280 m_rWW8Export
.InsUInt16( 2 );
2288 void WW8AttributeOutput::TableSpacing(const ww8::WW8TableNodeInfoInner::Pointer_t
& pTableTextNodeInfoInner
)
2290 const SwTable
* pTable
= pTableTextNodeInfoInner
->getTable();
2291 const SwTableFormat
* pTableFormat
= pTable
->GetFrameFormat();
2294 // Writing these SPRM's will make the table a floating one, so only write
2295 // them in case the table is already inside a frame.
2296 if (!(pTableFormat
!= nullptr && pTable
->GetTableNode()->GetFlyFormat()))
2299 const SvxULSpaceItem
& rUL
= pTableFormat
->GetULSpace();
2301 if (rUL
.GetUpper() > 0)
2303 sal_uInt8
const nPadding
= 2;
2304 sal_uInt8
const nPcVert
= 0;
2305 sal_uInt8
const nPcHorz
= 0;
2307 sal_uInt8
const nTPc
= (nPadding
<< 4) | (nPcVert
<< 2) | nPcHorz
;
2309 m_rWW8Export
.InsUInt16(NS_sprm::TPc::val
);
2310 m_rWW8Export
.m_pO
->push_back( nTPc
);
2312 m_rWW8Export
.InsUInt16(NS_sprm::TDyaAbs::val
);
2313 m_rWW8Export
.InsUInt16(rUL
.GetUpper());
2315 m_rWW8Export
.InsUInt16(NS_sprm::TDyaFromText::val
);
2316 m_rWW8Export
.InsUInt16(rUL
.GetUpper());
2319 if (rUL
.GetLower() > 0)
2321 m_rWW8Export
.InsUInt16(NS_sprm::TDyaFromTextBottom::val
);
2322 m_rWW8Export
.InsUInt16(rUL
.GetLower());
2326 void WW8AttributeOutput::TablePositioning(SwFrameFormat
* pFlyFormat
)
2328 if (!pFlyFormat
|| !pFlyFormat
->GetFlySplit().GetValue())
2333 sal_uInt8 nPcVert
= 0;
2334 switch (pFlyFormat
->GetVertOrient().GetRelationOrient())
2336 case text::RelOrientation::PAGE_PRINT_AREA
:
2337 // relative to margin
2340 case text::RelOrientation::PAGE_FRAME
:
2345 // text::RelOrientation::FRAME
2350 sal_uInt8 nPcHorz
= 0;
2351 switch (pFlyFormat
->GetHoriOrient().GetRelationOrient())
2353 case text::RelOrientation::FRAME
:
2354 // relative to column
2357 case text::RelOrientation::PAGE_PRINT_AREA
:
2358 // relative to margin
2362 // text::RelOrientation::PAGE_FRAME
2367 sal_uInt8 nTPc
= (nPcVert
<< 4) | (nPcHorz
<< 6);
2368 m_rWW8Export
.InsUInt16(NS_sprm::TPc::val
);
2369 m_rWW8Export
.m_pO
->push_back(nTPc
);
2371 // Similar to WW8AttributeOutput::FormatHorizOrientation(), but for tables.
2372 sal_Int16 nTDxaAbs
= 0;
2373 switch (pFlyFormat
->GetHoriOrient().GetHoriOrient())
2375 case text::HoriOrientation::LEFT
:
2379 case text::HoriOrientation::CENTER
:
2383 case text::HoriOrientation::RIGHT
:
2388 nTDxaAbs
= pFlyFormat
->GetHoriOrient().GetPos();
2391 m_rWW8Export
.InsUInt16(NS_sprm::TDxaAbs::val
);
2392 m_rWW8Export
.InsInt16(nTDxaAbs
);
2394 // Similar to WW8AttributeOutput::FormatVertOrientation(), but for tables.
2395 sal_Int16 nTDyaAbs
= 0;
2396 switch (pFlyFormat
->GetVertOrient().GetVertOrient())
2398 case text::VertOrientation::TOP
:
2402 case text::VertOrientation::CENTER
:
2406 case text::VertOrientation::BOTTOM
:
2411 nTDyaAbs
= pFlyFormat
->GetVertOrient().GetPos();
2414 m_rWW8Export
.InsUInt16(NS_sprm::TDyaAbs::val
);
2415 m_rWW8Export
.InsInt16(nTDyaAbs
);
2417 // Similar to WW8AttributeOutput::FormatULSpace(), but for tables.
2418 sal_uInt16 nDyaFromText
= pFlyFormat
->GetULSpace().GetUpper();
2419 m_rWW8Export
.InsUInt16(NS_sprm::TDyaFromText::val
);
2420 m_rWW8Export
.InsUInt16(nDyaFromText
);
2421 sal_uInt16 nDyaFromTextBottom
= pFlyFormat
->GetULSpace().GetLower();
2422 m_rWW8Export
.InsUInt16(NS_sprm::TDyaFromTextBottom::val
);
2423 m_rWW8Export
.InsUInt16(nDyaFromTextBottom
);
2425 // Similar to WW8AttributeOutput::FormatLRSpace(), but for tables.
2426 sal_uInt16 nDxaFromText
= pFlyFormat
->GetLRSpace().ResolveLeft({});
2427 m_rWW8Export
.InsUInt16(NS_sprm::TDxaFromText::val
);
2428 m_rWW8Export
.InsUInt16(nDxaFromText
);
2429 sal_uInt16 nDxaFromTextRight
= pFlyFormat
->GetLRSpace().ResolveRight({});
2430 m_rWW8Export
.InsUInt16(NS_sprm::TDxaFromTextRight::val
);
2431 m_rWW8Export
.InsUInt16(nDxaFromTextRight
);
2433 if (!pFlyFormat
->GetWrapInfluenceOnObjPos().GetAllowOverlap())
2435 // Allowing overlap is the default in both Writer and in WW8.
2436 m_rWW8Export
.InsUInt16(NS_sprm::TFNoAllowOverlap::val
);
2437 m_rWW8Export
.m_pO
->push_back(1);
2441 void WW8AttributeOutput::TableDefinition(const ww8::WW8TableNodeInfoInner::Pointer_t
& pTableTextNodeInfoInner
)
2443 const SwTable
* pTable
= pTableTextNodeInfoInner
->getTable();
2445 if ( pTable
->GetRowsToRepeat() > pTableTextNodeInfoInner
->getRow() )
2447 m_rWW8Export
.InsUInt16( NS_sprm::TTableHeader::val
);
2448 m_rWW8Export
.m_pO
->push_back( 1 );
2451 ww8::TableBoxVectorPtr pTableBoxes
=
2452 pTableTextNodeInfoInner
->getTableBoxesOfRow();
2453 // number of cell written
2454 sal_uInt32 nBoxes
= pTableBoxes
->size();
2455 assert(nBoxes
<= ww8::MAXTABLECELLS
);
2458 m_rWW8Export
.InsUInt16( NS_sprm::TDefTable::val
);
2459 sal_uInt16 nSprmSize
= 2 + (nBoxes
+ 1) * 2 + nBoxes
* 20;
2460 m_rWW8Export
.InsUInt16( nSprmSize
); // length
2463 m_rWW8Export
.m_pO
->push_back( static_cast<sal_uInt8
>(nBoxes
) );
2467 ALWAYS relative when text::HoriOrientation::NONE (nPageSize + ( nPageSize / 10 )) < nTableSz,
2468 in that case the cell width's and table width's are not real. The table
2469 width is maxed and cells relative, so we need the frame (generally page)
2470 width that the table is in to work out the true widths.
2472 //const bool bNewTableModel = pTable->IsNewModel();
2473 const SwFrameFormat
*pFormat
= pTable
->GetFrameFormat();
2476 SAL_WARN( "sw.ww8", "FrameFormat is nil" );
2480 const SwFormatHoriOrient
&rHori
= pFormat
->GetHoriOrient();
2481 const SwFormatVertOrient
&rVert
= pFormat
->GetVertOrient();
2483 SwTwips nTableOffset
= 0;
2486 (text::RelOrientation::PRINT_AREA
== rHori
.GetRelationOrient() ||
2487 text::RelOrientation::FRAME
== rHori
.GetRelationOrient())
2489 (text::RelOrientation::PRINT_AREA
== rVert
.GetRelationOrient() ||
2490 text::RelOrientation::FRAME
== rVert
.GetRelationOrient())
2493 sal_Int16 eHOri
= rHori
.GetHoriOrient();
2496 case text::HoriOrientation::CENTER
:
2497 case text::HoriOrientation::RIGHT
:
2501 nTableOffset
= rHori
.GetPos();
2502 const SvxLRSpaceItem
& rLRSp
= pFormat
->GetLRSpace();
2503 nTableOffset
+= rLRSp
.ResolveLeft({});
2505 // convert offset to be measured from right margin in right-to-left tables
2506 if ( nTableOffset
&& m_rWW8Export
.TrueFrameDirection(*pFormat
) == SvxFrameDirection::Horizontal_RL_TB
)
2508 SwTwips nLeftPageMargin
, nRightPageMargin
;
2509 const SwTwips nPageSize
= m_rWW8Export
.CurrentPageWidth(nLeftPageMargin
, nRightPageMargin
);
2510 const SwTwips nTableWidth
= pFormat
->GetFrameSize().GetWidth();
2511 nTableOffset
= nPageSize
- nLeftPageMargin
- nRightPageMargin
- nTableWidth
- nTableOffset
;
2517 m_rWW8Export
.InsInt16( nTableOffset
);
2519 ww8::GridColsPtr pGridCols
= GetGridCols( pTableTextNodeInfoInner
);
2520 for ( const auto nCol
: *pGridCols
)
2522 m_rWW8Export
.InsUInt16( o3tl::narrowing
<sal_uInt16
>(nCol
) + nTableOffset
);
2526 ww8::RowSpansPtr pRowSpans
= pTableTextNodeInfoInner
->getRowSpansOfRow();
2527 ww8::RowSpans::const_iterator aItRowSpans
= pRowSpans
->begin();
2529 for (const SwTableBox
* pTabBox1
: *pTableBoxes
)
2531 sal_uInt16 npOCount
= m_rWW8Export
.m_pO
->size();
2533 const SwFrameFormat
* pBoxFormat
= nullptr;
2534 if (pTabBox1
!= nullptr)
2535 pBoxFormat
= pTabBox1
->GetFrameFormat();
2538 lcl_TCFlags(m_rWW8Export
.m_rDoc
, pTabBox1
, *aItRowSpans
);
2539 m_rWW8Export
.InsUInt16( nFlags
);
2541 static sal_uInt8 aNullBytes
[] = { 0x0, 0x0 };
2543 m_rWW8Export
.m_pO
->insert( m_rWW8Export
.m_pO
->end(), aNullBytes
, aNullBytes
+2 ); // dummy
2544 if (pBoxFormat
!= nullptr)
2546 const SvxBoxItem
& rBoxItem
= pBoxFormat
->GetBox();
2548 WW8Export::Out_SwFormatTableBox( *m_rWW8Export
.m_pO
, &rBoxItem
); // 8/16 Byte
2551 WW8Export::Out_SwFormatTableBox( *m_rWW8Export
.m_pO
, nullptr); // 8/16 Byte
2553 SAL_INFO( "sw.ww8.level2", "<tclength>" << ( m_rWW8Export
.m_pO
->size() - npOCount
) << "</tclength>" );
2557 int nWidthPercent
= pFormat
->GetFrameSize().GetWidthPercent();
2559 // The best fit for "automatic" table placement is relative 100%
2560 if (!nWidthPercent
&& rHori
.GetHoriOrient() == text::HoriOrientation::FULL
)
2561 nWidthPercent
= 100;
2563 // Width is in fiftieths of a percent. For sprmTTableWidth, must be non-negative and 600% max
2564 if ( nWidthPercent
> 0 && nWidthPercent
<= 600 )
2566 m_rWW8Export
.InsUInt16( NS_sprm::TTableWidth::val
);
2567 m_rWW8Export
.m_pO
->push_back( sal_uInt8
/*ftsPercent*/ (2) );
2568 m_rWW8Export
.InsUInt16( o3tl::narrowing
<sal_uInt16
>(nWidthPercent
) * 50 );
2571 // Write table positioning properties in case this is a floating table.
2572 TablePositioning(pTable
->GetTableNode()->GetFlyFormat());
2575 ww8::GridColsPtr
AttributeOutputBase::GetGridCols( ww8::WW8TableNodeInfoInner::Pointer_t
const & pTableTextNodeInfoInner
)
2577 return pTableTextNodeInfoInner
->getGridColsOfRow(*this);
2580 ww8::WidthsPtr
AttributeOutputBase::GetColumnWidths( ww8::WW8TableNodeInfoInner::Pointer_t
const & pTableTextNodeInfoInner
)
2582 // Get the column widths based on ALL the rows, not just the current row
2583 return pTableTextNodeInfoInner
->getGridColsOfRow(*this, true);
2586 void AttributeOutputBase::GetTablePageSize( ww8::WW8TableNodeInfoInner
const * pTableTextNodeInfoInner
, tools::Long
& rPageSize
, bool& rRelBoxSize
)
2588 tools::Long nPageSize
= 0;
2590 const SwNode
*pTextNd
= pTableTextNodeInfoInner
->getNode( );
2591 const SwTable
*pTable
= pTableTextNodeInfoInner
->getTable( );
2593 const SwFrameFormat
*pFormat
= pTable
->GetFrameFormat();
2596 SAL_WARN( "sw.ww8", "FrameFormat is nil" );
2600 const SwFormatFrameSize
&rSize
= pFormat
->GetFrameSize();
2601 int nWidthPercent
= rSize
.GetWidthPercent();
2602 bool bManualAligned
= pFormat
->GetHoriOrient().GetHoriOrient() == text::HoriOrientation::NONE
;
2603 if ( (pFormat
->GetHoriOrient().GetHoriOrient() == text::HoriOrientation::FULL
) || bManualAligned
)
2604 nWidthPercent
= 100;
2605 bool bRelBoxSize
= nWidthPercent
!= 0;
2606 tools::ULong nTableSz
= static_cast<tools::ULong
>(rSize
.GetWidth());
2607 if (nTableSz
> USHRT_MAX
/2 && !bRelBoxSize
)
2609 OSL_ENSURE(bRelBoxSize
, "huge table width but not relative, suspicious");
2616 SwRect
aRect( pFormat
->FindLayoutRect( false, &aPt
) );
2617 if ( aRect
.IsEmpty() )
2619 // Then fetch the page width without margins!
2620 const SwFrameFormat
* pParentFormat
=
2621 GetExport().m_pParentFrame
?
2622 &(GetExport().m_pParentFrame
->GetFrameFormat()) :
2623 GetExport().m_rDoc
.GetPageDesc(0).GetPageFormatOfNode(*pTextNd
, false);
2624 aRect
= pParentFormat
->FindLayoutRect(true);
2625 nPageSize
= aRect
.Width();
2626 if ( 0 == nPageSize
)
2628 const SvxLRSpaceItem
& rLR
= pParentFormat
->GetLRSpace();
2629 nPageSize
= pParentFormat
->GetFrameSize().GetWidth() - rLR
.ResolveLeft({})
2630 - rLR
.ResolveRight({});
2635 nPageSize
= aRect
.Width();
2636 if ( bManualAligned
)
2638 // #i37571# For manually aligned tables
2639 const SvxLRSpaceItem
&rLR
= pFormat
->GetLRSpace();
2640 nPageSize
-= (rLR
.ResolveLeft({}) + rLR
.ResolveRight({}));
2645 if ( nWidthPercent
)
2647 nPageSize
*= nWidthPercent
;
2651 SAL_WARN( "sw.ww8", "nWidthPercent is zero" );
2655 // As the table width is not relative, the TablePageSize equals its width
2656 nPageSize
= nTableSz
;
2659 rPageSize
= nPageSize
;
2660 rRelBoxSize
= bRelBoxSize
;
2663 void WW8AttributeOutput::TableDefaultBorders( const ww8::WW8TableNodeInfoInner::Pointer_t
& pTableTextNodeInfoInner
)
2665 // This function name is misleading because it is not a table default, but a row default,
2666 // and it also only sets default cell margins (aka border padding).
2667 // The specs suggest there is no way to define default border lines/colors.
2668 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
2669 const SwFrameFormat
* pFrameFormat
= pTabBox
->GetFrameFormat();
2671 static const SvxBoxItemLine aBorders
[] =
2673 SvxBoxItemLine::TOP
, SvxBoxItemLine::LEFT
,
2674 SvxBoxItemLine::BOTTOM
, SvxBoxItemLine::RIGHT
2677 // Set row default cell margins using this last cell in the row
2678 for ( int i
= 0; i
< 4; ++i
)
2680 SwWW8Writer::InsUInt16( *m_rWW8Export
.m_pO
, NS_sprm::TCellPaddingDefault::val
);
2681 m_rWW8Export
.m_pO
->push_back( sal_uInt8(6) );
2682 m_rWW8Export
.m_pO
->push_back( sal_uInt8(0) );
2683 m_rWW8Export
.m_pO
->push_back( sal_uInt8(1) );
2684 m_rWW8Export
.m_pO
->push_back( sal_uInt8(1 << i
) );
2685 m_rWW8Export
.m_pO
->push_back( sal_uInt8(3) );
2687 SwWW8Writer::InsUInt16( *m_rWW8Export
.m_pO
,
2688 pFrameFormat
->GetBox().GetDistance( aBorders
[i
] ) );
2692 void WW8AttributeOutput::TableCellBorders(
2693 ww8::WW8TableNodeInfoInner::Pointer_t
const & pTableTextNodeInfoInner
)
2695 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
2696 const SwTableLine
* pTabLine
= pTabBox
->GetUpper();
2697 const SwTableBoxes
& rTabBoxes
= pTabLine
->GetTabBoxes();
2698 sal_uInt8 nBoxes
= std::min
<size_t>(rTabBoxes
.size(), 255);
2699 const SvxBoxItem
* pLastBox
= nullptr;
2700 sal_uInt8 nSeqStart
= 0; // start of sequence of cells with same borders
2702 static const SvxBoxItemLine aBorders
[] =
2704 SvxBoxItemLine::TOP
, SvxBoxItemLine::LEFT
,
2705 SvxBoxItemLine::BOTTOM
, SvxBoxItemLine::RIGHT
2708 sal_uInt16 nDefaultMargin
[4] = {31681, 31681, 31681, 31681}; // outside of documented valid range
2709 // last column in each row defines the row default in TableRowDefaultBorders()
2710 if ( nBoxes
&& rTabBoxes
.size() == nBoxes
)
2712 const SvxBoxItem
& rBox
= rTabBoxes
[ nBoxes
-1 ]->GetFrameFormat()->GetBox();
2713 for ( int i
= 0; i
< 4; ++i
)
2714 nDefaultMargin
[i
] = rBox
.GetDistance( aBorders
[i
] );
2717 // Detect sequences of cells which have the same borders, and output
2718 // a border description for each such cell range.
2719 for ( unsigned n
= 0; n
<= nBoxes
; ++n
)
2721 const SvxBoxItem
* pBox
= (n
== nBoxes
) ? nullptr :
2722 &rTabBoxes
[n
]->GetFrameFormat()->GetBox();
2725 else if( !pBox
|| *pLastBox
!= *pBox
)
2727 // This cell has different borders than the previous cell,
2728 // so output the borders for the preceding cell range.
2729 m_rWW8Export
.Out_CellRangeBorders(pLastBox
, nSeqStart
, n
);
2731 // The last column is used as the row default for margins, so we can ignore these matching ones
2735 // Output cell margins.
2736 // One CSSA can define up to all four margins if they are the same size value.
2737 sal_uInt16 nMargin
[4];
2738 sal_uInt8 nSideBits
[4] = {0, 0, 0, 0}; // 0001:top, 0010:left, 0100:bottom, 1000:right
2739 for ( int i
= 0; i
< 4; ++i
) // sides: top, left, bottom, right
2741 nMargin
[i
] = std::min(sal_Int16(31680), pLastBox
->GetDistance( aBorders
[i
] ));
2742 if ( nMargin
[i
] == nDefaultMargin
[i
] )
2745 // join a previous side's definition if it shares the same value
2746 for ( int p
= 0; p
< 4; ++p
)
2748 if ( nMargin
[i
] == nMargin
[p
] )
2750 nSideBits
[p
] |= 1 << i
;
2756 // write out the cell margins definitions that were used
2757 for ( int i
= 0; i
< 4; ++i
)
2761 SwWW8Writer::InsUInt16( *m_rWW8Export
.m_pO
, NS_sprm::TCellPadding::val
);
2762 m_rWW8Export
.m_pO
->push_back( sal_uInt8(6) ); // 6 bytes
2763 m_rWW8Export
.m_pO
->push_back( sal_uInt8(nSeqStart
) ); // first cell: apply margin
2764 m_rWW8Export
.m_pO
->push_back( sal_uInt8(n
) ); // end cell: do not apply margin
2765 m_rWW8Export
.m_pO
->push_back( sal_uInt8(nSideBits
[i
]) );
2766 m_rWW8Export
.m_pO
->push_back( sal_uInt8(3) ); // FtsDxa: size in twips
2767 SwWW8Writer::InsUInt16( *m_rWW8Export
.m_pO
, nMargin
[i
] );
2777 void WW8AttributeOutput::TableBackgrounds(const ww8::WW8TableNodeInfoInner::Pointer_t
& pTableTextNodeInfoInner
)
2779 const SwTable
* pTab
= pTableTextNodeInfoInner
->getTable();
2780 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
2781 const SwTableLine
* pTabLine
= pTabBox
->GetUpper();
2782 const SwTableBoxes
& rTabBoxes
= pTabLine
->GetTabBoxes();
2784 sal_uInt8 nBoxes
= rTabBoxes
.size();
2785 m_rWW8Export
.InsUInt16( NS_sprm::TDefTableShd80::val
);
2786 m_rWW8Export
.m_pO
->push_back( static_cast<sal_uInt8
>(nBoxes
* 2) ); // Len
2788 Color aRowColor
= COL_AUTO
;
2789 const SvxBrushItem
*pTableColorProp
= pTab
->GetFrameFormat()->GetAttrSet().GetItem
<SvxBrushItem
>(RES_BACKGROUND
);
2790 if ( pTableColorProp
)
2791 aRowColor
= pTableColorProp
->GetColor();
2793 const SvxBrushItem
*pRowColorProp
= pTabLine
->GetFrameFormat()->GetAttrSet().GetItem
<SvxBrushItem
>(RES_BACKGROUND
);
2794 if ( pRowColorProp
&& pRowColorProp
->GetColor() != COL_AUTO
)
2795 aRowColor
= pRowColorProp
->GetColor();
2797 for ( sal_uInt8 n
= 0; n
< nBoxes
; n
++ )
2799 const SwTableBox
* pBox1
= rTabBoxes
[n
];
2800 const SwFrameFormat
* pFrameFormat
= pBox1
->GetFrameFormat();
2801 Color aColor
= aRowColor
;
2803 const SvxBrushItem
*pCellColorProp
= pFrameFormat
->GetAttrSet().GetItem
<SvxBrushItem
>(RES_BACKGROUND
);
2804 if ( pCellColorProp
&& pCellColorProp
->GetColor() != COL_AUTO
)
2805 aColor
= pCellColorProp
->GetColor();
2808 WW8Export::TransBrush( aColor
, aShd
);
2809 m_rWW8Export
.InsUInt16( aShd
.GetValue() );
2812 /*sprmTDefTableShdRaw:
2813 * A DefTableShdOperand value that specifies the ... shading for cells 1 up to 22 in the row,
2814 * ... Cells 23 to 44 are shaded by sprmTDefTableShdRaw2nd,
2815 * and cells 45 to 63 are shaded by sprmTDefTableShdRaw3rd.
2817 sal_uInt32
const aSprmIds
[] { NS_sprm::TDefTableShd::val
,
2818 NS_sprm::TDefTableShdRaw::val
,
2819 NS_sprm::TDefTableShdRaw::val
,
2820 NS_sprm::TDefTableShd2nd::val
,
2821 NS_sprm::TDefTableShdRaw2nd::val
,
2822 NS_sprm::TDefTableShd3rd::val
,
2823 NS_sprm::TDefTableShdRaw3rd::val
};
2824 for (sal_uInt32 m
: aSprmIds
)
2826 sal_uInt8 nStart
= 0;
2827 sal_uInt8 nStop
= rTabBoxes
.size();
2830 case NS_sprm::TDefTableShd::val
:
2831 case NS_sprm::TDefTableShdRaw::val
:
2835 case NS_sprm::TDefTableShd2nd::val
:
2836 case NS_sprm::TDefTableShdRaw2nd::val
:
2841 case NS_sprm::TDefTableShd3rd::val
:
2842 case NS_sprm::TDefTableShdRaw3rd::val
:
2848 if ( nStart
>= nStop
)
2851 m_rWW8Export
.InsUInt16( m
);
2852 m_rWW8Export
.m_pO
->push_back( static_cast<sal_uInt8
>((nStop
-nStart
) * 10) );
2854 for ( sal_uInt8 n
= nStart
; n
< nStop
; n
++ )
2856 const SwTableBox
* pBox1
= rTabBoxes
[n
];
2857 const SwFrameFormat
* pFrameFormat
= pBox1
->GetFrameFormat();
2858 Color aColor
= aRowColor
;
2860 const SvxBrushItem
*pCellColorProp
= pFrameFormat
->GetAttrSet().GetItem
<SvxBrushItem
>(RES_BACKGROUND
);
2861 if ( pCellColorProp
&& pCellColorProp
->GetColor() != COL_AUTO
)
2862 aColor
= pCellColorProp
->GetColor();
2865 aSHD
.setCvFore( 0xFF000000 );
2867 if ( aColor
== COL_AUTO
)
2868 aSHD
.setCvBack( 0xFF000000 );
2870 aSHD
.setCvBack( wwUtility::RGBToBGR( aColor
) );
2872 aSHD
.Write( m_rWW8Export
);
2877 void WW8Export::SectionBreaksAndFrames( const SwTextNode
& rNode
)
2879 // output page/section breaks
2880 OutputSectionBreaks( rNode
.GetpSwAttrSet(), rNode
);
2885 class TrackContentToExport
2889 SwNodeOffset m_nStart
, m_nEnd
;
2891 TrackContentToExport(SwPaM
*pCurPam
, SwNodeOffset nCurStart
, SwNodeOffset nCurEnd
)
2892 : m_pCurPam(pCurPam
)
2893 , m_nStart(nCurStart
)
2898 bool contentRemainsToExport(ww8::WW8TableInfo
*pTableInfo
)
2900 bool bSimpleContentRemains
= m_pCurPam
->GetPoint()->GetNode() < m_pCurPam
->GetMark()->GetNode() ||
2901 (m_pCurPam
->GetPoint()->GetNode() == m_pCurPam
->GetMark()->GetNode() &&
2902 m_pCurPam
->GetPoint()->GetContentIndex() <= m_pCurPam
->GetMark()->GetContentIndex());
2903 if (bSimpleContentRemains
)
2909 //An old-school table where one cell may points back to a previous node as the next cell
2910 //so if this node is the last node in the range, we may need to jump back to a previously
2911 //skipped cell to output it in a sane sequence. See ooo47778-3.sxw for one of these
2912 //horrors. So if we are at the end of the selection, but this end point is a table
2913 //cell whose next cell is in the selection allow jumping back to it
2914 const SwNode
* pCurrentNode
= &m_pCurPam
->GetPoint()->GetNode();
2915 const SwNode
* pNextNode
= pTableInfo
->getNextNode(pCurrentNode
);
2917 if (pNextNode
&& pCurrentNode
!= pNextNode
)
2919 return pNextNode
->GetIndex() >= m_nStart
&&
2920 pNextNode
->GetIndex() < m_nEnd
;
2929 void MSWordExportBase::WriteText()
2931 TrackContentToExport
aContentTracking(m_pCurPam
.get(), m_nCurStart
, m_nCurEnd
);
2932 while (aContentTracking
.contentRemainsToExport(m_pTableInfo
.get()))
2934 SwNode
& rNd
= m_pCurPam
->GetPointNode();
2936 // no section breaks exported for Endnotes
2937 if ( rNd
.IsTextNode() && m_nTextTyp
!= TXT_EDN
&& m_nTextTyp
!= TXT_FTN
)
2939 SwSoftPageBreakList breakList
;
2940 // if paragraph need to be split than handle section break somewhere
2942 if( !NeedTextNodeSplit( *rNd
.GetTextNode(), breakList
) )
2943 SectionBreaksAndFrames( *rNd
.GetTextNode() );
2947 // output the various types of nodes
2948 if ( rNd
.IsContentNode() )
2950 SwContentNode
* pCNd
= static_cast<SwContentNode
*>(&rNd
);
2952 const SwPageDesc
* pTemp
= rNd
.FindPageDesc();
2954 m_pCurrentPageDesc
= pTemp
;
2956 m_pCurPam
->GetPoint()->SetContent( 0 );
2957 OutputContentNode( *pCNd
);
2959 else if ( rNd
.IsTableNode() )
2961 m_pTableInfo
->processSwTable( &rNd
.GetTableNode()->GetTable() );
2963 else if ( rNd
.IsSectionNode() && TXT_MAINTEXT
== m_nTextTyp
)
2964 OutputSectionNode( *rNd
.GetSectionNode() );
2965 else if ( TXT_MAINTEXT
== m_nTextTyp
&& rNd
.IsEndNode() &&
2966 rNd
.StartOfSectionNode()->IsSectionNode() )
2968 const SwSection
& rSect
= rNd
.StartOfSectionNode()->GetSectionNode()
2970 if ( m_bStartTOX
&& SectionType::ToxContent
== rSect
.GetType() )
2971 m_bStartTOX
= false;
2973 SwNodeIndex
aIdx( rNd
, 1 );
2974 if ( aIdx
.GetNode().IsEndNode() && aIdx
.GetNode().StartOfSectionNode()->IsSectionNode() )
2976 else if ( aIdx
.GetNode().IsSectionNode() )
2978 else if ( !IsInTable() ) //No sections in table
2980 //#120140# Do not need to insert a page/section break after a section end. Check this case first
2981 bool bNeedExportBreakHere
= true;
2982 if ( rSect
.GetType() == SectionType::ToxContent
|| rSect
.GetType() == SectionType::ToxHeader
)
2983 bNeedExportBreakHere
= false;
2984 else if ( aIdx
.GetNode().IsTextNode() )
2986 SwTextNode
*pTempNext
= aIdx
.GetNode().GetTextNode();
2989 const SwFormatPageDesc
* pTempItem
= nullptr;
2990 if (pTempNext
->GetpSwAttrSet()
2991 && (pTempItem
= pTempNext
->GetpSwAttrSet()->GetItemIfSet(RES_PAGEDESC
, false))
2992 && pTempItem
->GetRegisteredIn())
2994 //Next node has a new page style which means this node is a section end. Do not insert another page/section break here
2995 bNeedExportBreakHere
= false;
3001 /* Do not export Section Break in case DOCX containing MultiColumn and
3002 * aIdx.GetNode().IsTextNode() is False i.e. Text node is NULL.
3004 const SwFrameFormat
* pPgFormat
= rSect
.GetFormat();
3005 const SwFormatCol
& rCol
= pPgFormat
->GetCol();
3006 sal_uInt16 nColumnCount
= rCol
.GetNumCols();
3007 const SwFormatNoBalancedColumns
& rNoBalanced
= pPgFormat
->GetBalancedColumns();
3008 // Prevent the additional section break only for non-balanced columns.
3009 if (nColumnCount
> 1 && rNoBalanced
.GetValue())
3011 bNeedExportBreakHere
= false;
3013 // No need to create a "fake" section if this is the end of the document,
3014 // except to emulate balanced columns.
3015 else if ( nColumnCount
< 2 && aIdx
== m_rDoc
.GetNodes().GetEndOfContent() )
3016 bNeedExportBreakHere
= false;
3019 if (bNeedExportBreakHere
) //#120140# End of check
3021 ReplaceCr( char(0xc) ); // indicator for Page/Section-Break
3023 const SwSectionFormat
* pParentFormat
= rSect
.GetFormat()->GetParent();
3024 if ( !pParentFormat
)
3025 pParentFormat
= reinterpret_cast<SwSectionFormat
*>(sal_IntPtr(-1));
3027 sal_uLong nRstLnNum
;
3028 if ( aIdx
.GetNode().IsContentNode() )
3029 nRstLnNum
= static_cast<SwContentNode
&>(aIdx
.GetNode()).GetSwAttrSet().
3030 GetLineNumber().GetStartValue();
3034 AppendSection( m_pCurrentPageDesc
, pParentFormat
, nRstLnNum
);
3038 OutputEndNode( *rNd
.GetEndNode() );
3042 else if ( rNd
.IsStartNode() )
3044 OutputStartNode( *rNd
.GetStartNode() );
3046 else if ( rNd
.IsEndNode() )
3048 OutputEndNode( *rNd
.GetEndNode() );
3051 if ( &rNd
== &rNd
.GetNodes().GetEndOfContent() )
3054 const SwNode
* pCurrentNode
= &m_pCurPam
->GetPoint()->GetNode();
3055 const SwNode
* pNextNode
= m_pTableInfo
->getNextNode(pCurrentNode
);
3057 if (pCurrentNode
== pNextNode
)
3059 SAL_WARN("sw.ww8", "loop in TableInfo");
3060 pNextNode
= nullptr;
3063 if (pNextNode
!= nullptr)
3064 m_pCurPam
->GetPoint()->Assign(*pNextNode
);
3066 m_pCurPam
->GetPoint()->Adjust(SwNodeOffset(1));
3068 SwNodeOffset nPos
= m_pCurPam
->GetPoint()->GetNodeIndex();
3069 ::SetProgressState( sal_Int32(nPos
), m_pCurPam
->GetDoc().GetDocShell() );
3072 SAL_INFO( "sw.ww8.level2", "</WriteText>" );
3075 void WW8Export::WriteMainText()
3077 SAL_INFO( "sw.ww8.level2", "<WriteMainText>" );
3079 m_pFib
->m_fcMin
= Strm().Tell();
3081 m_pCurPam
->GetPoint()->Assign(*m_rDoc
.GetNodes().GetEndOfContent().StartOfSectionNode());
3085 if( 0 == Strm().Tell() - m_pFib
->m_fcMin
) // no text ?
3086 WriteCR(); // then CR at the end ( otherwise WW will complain )
3088 m_pFib
->m_ccpText
= Fc2Cp( Strm().Tell() );
3089 m_pFieldMain
->Finish( m_pFib
->m_ccpText
, 0 );
3091 // ccpText includes Footnote and KF-text
3092 // therefore pFib->ccpText may get updated as well
3093 // save the StyleId of the last paragraph. Because WW97 take the style
3094 // from the last CR, that will be written after footer/Header/footnotes/
3096 const SwTextNode
* pLastNd
= m_pCurPam
->GetMark()->GetNode().GetTextNode();
3098 m_nLastFormatId
= GetId( static_cast<SwTextFormatColl
&>(pLastNd
->GetAnyFormatColl()) );
3100 SAL_INFO( "sw.ww8.level2", "</WriteMainText>" );
3103 bool MSWordExportBase::IsInTable() const
3105 bool bResult
= false;
3107 if (m_pCurPam
!= nullptr)
3109 SwNode
& rNode
= m_pCurPam
->GetPointNode();
3113 ww8::WW8TableNodeInfo::Pointer_t pTableNodeInfo
= m_pTableInfo
->getTableNodeInfo(&rNode
);
3115 if (pTableNodeInfo
&& pTableNodeInfo
->getDepth() > 0)
3125 typedef ww8::WW8Sttb
< ww8::WW8Struct
> WW8SttbAssoc
;
3127 void WW8Export::WriteFkpPlcUsw()
3129 // Graphics in the data stream
3130 m_pGrf
->Write(); // Graphics
3132 // output into WordDocument stream
3133 m_pChpPlc
->WriteFkps(); // Fkp.Chpx
3134 m_pPapPlc
->WriteFkps(); // Fkp.Papx
3135 m_pSepx
->WriteSepx( Strm() ); // Sepx
3137 // output into Table stream
3138 m_pStyles
->OutputStylesTable(); // for WW8 StyleTab
3139 m_pFootnote
->WritePlc( *this ); // Footnote-Ref & Text Plc
3140 m_pEdn
->WritePlc( *this ); // Endnote-Ref & Text Plc
3141 m_pTextBxs
->WritePlc( *this ); // Textbox Text Plc
3142 m_pHFTextBxs
->WritePlc( *this ); // Head/Foot-Textbox Text Plc
3143 m_pAtn
->WritePlc( *this ); // Annotation-Ref & Text Plc
3145 m_pSepx
->WritePlcSed( *this ); // Slcx.PlcSed
3146 m_pSepx
->WritePlcHdd( *this ); // Slcx.PlcHdd
3148 m_pChpPlc
->WritePlc(); // Plcx.Chpx
3149 m_pPapPlc
->WritePlc(); // Plcx.Papx
3151 if( m_pRedlAuthors
)
3152 m_pRedlAuthors
->Write( GetWriter() ); // sttbfRMark (RedlineAuthors)
3153 m_pFieldMain
->Write( *this ); // Fields ( Main Text )
3154 m_pFieldHdFt
->Write( *this ); // Fields ( Header/Footer )
3155 m_pFieldFootnote
->Write( *this ); // Fields ( FootNotes )
3156 m_pFieldEdn
->Write( *this ); // Fields ( EndNotes )
3157 m_pFieldAtn
->Write( *this ); // Fields ( Annotations )
3158 m_pFieldTextBxs
->Write( *this ); // Fields ( Textboxes )
3159 m_pFieldHFTextBxs
->Write( *this ); // Fields ( Head/Foot-Textboxes )
3161 if (m_pEscher
|| m_rDoc
.ContainsMSVBasic())
3164 Every time MS 2000 creates an escher stream there is always
3165 an ObjectPool dir (even if empty). It turns out that if a copy of
3166 MS 2000 is used to open a document that contains escher graphics
3167 exported from StarOffice without this empty dir then *if* that
3168 copy of MS Office has never been used to open a MSOffice document
3169 that has escher graphics (and an ObjectPool dir of course) and
3170 that copy of office has not been used to draw escher graphics then
3171 our exported graphics do not appear. Once you do open a ms
3172 document with escher graphics or draw an escher graphic with that
3173 copy of word, then all documents from staroffice that contain
3174 escher work from then on. Tricky to track down, some sort of late
3175 binding trickery in MS where solely for first time initialization
3176 the existence of an ObjectPool dir is necessary for triggering
3179 // avoid memory leak #i120098#, the unnamed obj will be released in destructor.
3180 m_xEscherStg
= GetWriter().GetStorage().OpenSotStorage(SL::aObjectPool
);
3183 // dggInfo - escher stream
3186 m_pSdrObjs
->WritePlc( *this );
3187 m_pHFSdrObjs
->WritePlc( *this );
3188 // spamom - office drawing table
3189 // spahdr - header office drawing table
3191 m_pBkmks
->Write( *this ); // Bookmarks - sttbfBkmk/
3192 // plcfBkmkf/plcfBkmkl
3193 m_pFactoids
->Write(*this);
3199 m_pMagicTable
->Write( *this );
3201 m_pPiece
->WritePc( *this ); // Piece-Table
3202 m_aFontHelper
.WriteFontTable(m_pTableStrm
, *m_pFib
); // FFNs
3204 //Convert OOo asian typography into MS typography structure
3205 ExportDopTypography(m_pDop
->doptypography
);
3207 WriteDop( *this ); // Document-Properties
3210 WW8SttbAssoc
* pSttbfAssoc
= dynamic_cast<WW8SttbAssoc
*>
3211 (m_rDoc
.getIDocumentExternalData().getExternalData(::sw::tExternalDataType::STTBF_ASSOC
).get());
3213 if ( pSttbfAssoc
) // #i106057#
3215 std::vector
<OUString
> aStrings(pSttbfAssoc
->getStrings());
3216 WriteAsStringTable(aStrings
, m_pFib
->m_fcSttbfAssoc
,
3217 m_pFib
->m_lcbSttbfAssoc
);
3222 // Reclaim stored FIB data from document.
3223 ::ww8::WW8FibData
* pFibData
= dynamic_cast<ww8::WW8FibData
*>
3224 (m_rDoc
.getIDocumentExternalData().getExternalData(::sw::tExternalDataType::FIB
).get());
3228 m_pFib
->m_fReadOnlyRecommended
=
3229 pFibData
->getReadOnlyRecommended();
3230 m_pFib
->m_fWriteReservation
=
3231 pFibData
->getWriteReservation();
3234 m_pFib
->Write( Strm() ); // FIB
3237 void WW8Export::StoreDoc1()
3239 bool bNeedsFinalPara
= false;
3240 // Start of Text ( overwrite )
3241 SwWW8Writer::FillUntil( Strm(), m_pFib
->m_fcMin
);
3243 WriteMainText(); // main text
3244 sal_uInt8 nSprmsLen
;
3245 sal_uInt8
*pLastSprms
= m_pPapPlc
->CopyLastSprms(nSprmsLen
);
3247 bNeedsFinalPara
|= m_pFootnote
->WriteText( *this ); // Footnote-Text
3248 bNeedsFinalPara
|= m_pSepx
->WriteKFText( *this ); // K/F-Text
3249 bNeedsFinalPara
|= m_pAtn
->WriteText( *this ); // Annotation-Text
3250 bNeedsFinalPara
|= m_pEdn
->WriteText( *this ); // EndNote-Text
3252 // create the escher streams
3255 bNeedsFinalPara
|= m_pTextBxs
->WriteText( *this ); //Textbox Text Plc
3256 bNeedsFinalPara
|= m_pHFTextBxs
->WriteText( *this );//Head/Foot-Textbox Text Plc
3258 if (bNeedsFinalPara
)
3261 m_pPapPlc
->AppendFkpEntry(Strm().Tell(), nSprmsLen
, pLastSprms
);
3263 delete[] pLastSprms
;
3265 m_pSepx
->Finish( Fc2Cp( Strm().Tell() ));// Text + Footnote + HdFt as section end
3266 m_pMagicTable
->Finish( Fc2Cp( Strm().Tell() ),0);
3268 m_pFib
->m_fcMac
= Strm().Tell(); // End of all texts
3270 WriteFkpPlcUsw(); // FKP, PLC, ...
3273 void MSWordExportBase::AddLinkTarget(std::u16string_view rURL
)
3275 if( rURL
.empty() || rURL
[0] != '#' )
3278 OUString
aURL( BookmarkToWriter( rURL
.substr( 1 ) ) );
3279 sal_Int32 nPos
= aURL
.lastIndexOf( cMarkSeparator
);
3284 OUString sCmp
= aURL
.copy(nPos
+1).replaceAll(" ", "");
3285 if( sCmp
.isEmpty() )
3288 sCmp
= sCmp
.toAsciiLowerCase();
3289 if( sCmp
== "outline" )
3291 SwPosition
aPos(*m_pCurPam
->GetPoint());
3292 OUString
aName(BookmarkToWriter(aURL
.subView(0, nPos
)));
3293 // If we can find the outline this bookmark refers to
3294 // save the name of the bookmark and the
3295 // node index number of where it points to
3296 if( m_rDoc
.GotoOutline( aPos
, aName
) )
3297 m_aImplicitBookmarks
.emplace_back(aURL
, aPos
.GetNodeIndex());
3299 else if( sCmp
== "graphic" )
3301 OUString
aName(BookmarkToWriter(aURL
.subView(0, nPos
)));
3302 if (const SwFlyFrameFormat
* pFormat
= m_rDoc
.FindFlyByName(aName
, SwNodeType::Grf
))
3304 const SwFormatAnchor
& rFormatAnchor
= pFormat
->GetAnchor();
3305 if (SwNode
* pAnchorNode
= rFormatAnchor
.GetAnchorNode())
3306 m_aImplicitBookmarks
.emplace_back(aURL
, pAnchorNode
->GetIndex());
3309 else if( sCmp
== "frame" )
3311 OUString
aName(BookmarkToWriter(aURL
.subView(0, nPos
)));
3312 if (const SwFlyFrameFormat
* pFormat
= m_rDoc
.FindFlyByName(aName
, SwNodeType::Text
))
3313 if (const SwNodeIndex
* pIdx
= pFormat
->GetContent().GetContentIdx())
3314 m_aImplicitBookmarks
.emplace_back(aURL
, pIdx
->GetIndex() + 1);
3316 else if( sCmp
== "ole" )
3318 OUString
aName(BookmarkToWriter(aURL
.subView(0, nPos
)));
3319 if (const SwFlyFrameFormat
* pFormat
= m_rDoc
.FindFlyByName(aName
, SwNodeType::Ole
))
3321 const SwFormatAnchor
& rFormatAnchor
= pFormat
->GetAnchor();
3322 if (SwNode
* pAnchorNode
= rFormatAnchor
.GetAnchorNode())
3323 m_aImplicitBookmarks
.emplace_back(aURL
, pAnchorNode
->GetIndex());
3326 else if( sCmp
== "region" )
3328 OUString
aName(BookmarkToWriter(aURL
.subView(0, nPos
)));
3329 for (const SwSectionFormat
* pFormat
: m_rDoc
.GetSections())
3331 if (aName
== pFormat
->GetSection()->GetSectionName())
3333 if (const SwNodeIndex
* pIdx
= pFormat
->GetContent().GetContentIdx())
3335 m_aImplicitBookmarks
.emplace_back(aURL
, pIdx
->GetIndex() + 1);
3341 else if( sCmp
== "table" )
3343 OUString
aName(BookmarkToWriter(aURL
.subView(0, nPos
)));
3344 if (const SwTable
* pTable
= SwTable::FindTable(m_rDoc
.FindTableFormatByName(aName
)))
3345 if (const SwTableNode
* pTableNode
= pTable
->GetTabSortBoxes()[1]->GetSttNd()->FindTableNode())
3346 m_aImplicitBookmarks
.emplace_back(aURL
, pTableNode
->GetIndex() + 2);
3348 else if (sCmp
== "toxmark")
3350 OUString
const name(aURL
.copy(0, nPos
));
3351 OUString
const nameDecoded(INetURLObject::decode(name
,
3352 INetURLObject::DecodeMechanism::WithCharset
));
3353 if (const auto tmp
= sw::PrepareJumpToTOXMark(m_rDoc
, nameDecoded
))
3355 SwTOXMark
const* pMark(&tmp
->first
);
3356 for (sal_Int32 i
= 0; i
< tmp
->second
; ++i
)
3358 pMark
= &m_rDoc
.GotoTOXMark(*pMark
, TOX_SAME_NXT
, true);
3360 if (!SfxPoolItem::areSame(pMark
, &tmp
->first
))
3362 m_TOXMarkBookmarksByURL
.emplace(aURL
, name
);
3363 m_TOXMarkBookmarksByTOXMark
.emplace(pMark
, nameDecoded
);
3369 void MSWordExportBase::CollectOutlineBookmarks(const SwDoc
&rDoc
)
3371 rDoc
.ForEachINetFormat(
3372 [this] (const SwFormatINetFormat
& rINetFormat
) -> bool
3374 AddLinkTarget( rINetFormat
.GetValue() );
3378 rDoc
.ForEachFormatURL(
3379 [this] (const SwFormatURL
& rURL
) -> bool
3381 AddLinkTarget(rURL
.GetURL());
3382 const ImageMap
*pIMap
= rURL
.GetMap();
3386 for (size_t i
=0; i
< pIMap
->GetIMapObjectCount(); ++i
)
3388 const IMapObject
* pObj
= pIMap
->GetIMapObject(i
);
3391 AddLinkTarget( pObj
->GetURL() );
3399 const sal_uInt64 WW_BLOCKSIZE
= 0x200;
3401 ErrCode
EncryptRC4(msfilter::MSCodec_Std97
& rCtx
, SvStream
&rIn
, SvStream
&rOut
)
3403 sal_uInt64 nLen
= rIn
.TellEnd();
3406 sal_uInt8 in
[WW_BLOCKSIZE
];
3407 for (std::size_t nI
= 0, nBlock
= 0; nI
< nLen
; nI
+= WW_BLOCKSIZE
, ++nBlock
)
3409 std::size_t nBS
= std::min(nLen
- nI
, WW_BLOCKSIZE
);
3410 nBS
= rIn
.ReadBytes(in
, nBS
);
3411 if (!rCtx
.InitCipher(nBlock
)) {
3412 return ERRCODE_IO_NOTSUPPORTED
;
3414 rCtx
.Encode(in
, nBS
, in
, nBS
);
3415 rOut
.WriteBytes(in
, nBS
);
3417 return ERRCODE_NONE
;
3421 ErrCode
MSWordExportBase::ExportDocument( bool bWriteAll
)
3423 m_nCharFormatStart
= DEFAULT_STYLES_COUNT
;
3424 m_nFormatCollStart
= m_nCharFormatStart
+ m_rDoc
.GetCharFormats()->size() - 1;
3426 m_bStyDef
= m_bBreakBefore
= m_bOutKF
=
3427 m_bOutFlyFrameAttrs
= m_bOutPageDescs
= m_bOutTable
= m_bOutFirstPage
=
3428 m_bOutGrf
= m_bInWriteEscher
= m_bStartTOX
=
3429 m_bInWriteTOX
= false;
3431 m_bFootnoteAtTextEnd
= m_bEndAtTextEnd
= true;
3433 m_pParentFrame
= nullptr;
3434 m_bParaInlineHeading
= false;
3435 m_pFlyOffset
= nullptr;
3436 m_eNewAnchorType
= RndStdIds::FLY_AT_PAGE
;
3437 m_nTextTyp
= TXT_MAINTEXT
;
3438 m_nStyleBeforeFly
= m_nLastFormatId
= 0;
3439 m_pStyAttr
= nullptr;
3440 m_pCurrentStyle
= nullptr;
3441 m_pOutFormatNode
= nullptr;
3442 m_pEscher
= nullptr;
3443 m_pRedlAuthors
= nullptr;
3448 sal_uInt32 nSvxMSDffOLEConvFlags
= 0;
3449 if (officecfg::Office::Common::Filter::Microsoft::Export::MathToMathType::get())
3450 nSvxMSDffOLEConvFlags
|= OLE_STARMATH_2_MATHTYPE
;
3451 if (officecfg::Office::Common::Filter::Microsoft::Export::WriterToWinWord::get())
3452 nSvxMSDffOLEConvFlags
|= OLE_STARWRITER_2_WINWORD
;
3453 if (officecfg::Office::Common::Filter::Microsoft::Export::CalcToExcel::get())
3454 nSvxMSDffOLEConvFlags
|= OLE_STARCALC_2_EXCEL
;
3455 if (officecfg::Office::Common::Filter::Microsoft::Export::ImpressToPowerPoint::get())
3456 nSvxMSDffOLEConvFlags
|= OLE_STARIMPRESS_2_POWERPOINT
;
3458 m_oOLEExp
.emplace( nSvxMSDffOLEConvFlags
);
3461 if ( !m_pOCXExp
&& m_rDoc
.GetDocShell() )
3462 m_pOCXExp
.reset(new SwMSConvertControls(m_rDoc
.GetDocShell(), m_pCurPam
.get()));
3464 // #i81405# - Collect anchored objects before changing the redline mode.
3465 m_aFrames
= GetFrames( m_rDoc
, bWriteAll
? nullptr : m_pOrigPam
);
3467 m_nOrigRedlineFlags
= m_rDoc
.getIDocumentRedlineAccess().GetRedlineFlags();
3469 SwRootFrame
const*const pLayout(m_rDoc
.getIDocumentLayoutAccess().GetCurrentLayout());
3470 m_bOrigShowChanges
= pLayout
== nullptr || !pLayout
->IsHideRedlines();
3472 if ( !m_rDoc
.getIDocumentRedlineAccess().GetRedlineTable().empty() )
3474 //restored to original state by SwWriter::Write
3475 m_rDoc
.getIDocumentRedlineAccess().SetRedlineFlags(m_nOrigRedlineFlags
|
3476 RedlineFlags::ShowDelete
|
3477 RedlineFlags::ShowInsert
);
3480 // fix the SwPositions in m_aFrames after SetRedlineFlags
3481 UpdateFramePositions(m_aFrames
);
3483 m_aFontHelper
.InitFontTable(m_rDoc
);
3484 GatherChapterFields();
3486 CollectOutlineBookmarks(m_rDoc
);
3488 // make unique OrdNums (Z-Order) for all drawing-/fly Objects
3489 if ( m_rDoc
.getIDocumentDrawModelAccess().GetDrawModel() )
3490 m_rDoc
.getIDocumentDrawModelAccess().GetDrawModel()->GetPage( 0 )->RecalcObjOrdNums();
3492 ErrCode err
= ExportDocument_Impl();
3496 // park m_pCurPam in a "safe place" now that document is fully exported
3497 // before toggling redline mode to avoid ~SwContentIndexReg assert e.g. export
3498 // ooo103014-1.odt to .doc
3499 // park m_pOrigPam as well, as needed for exporting abi9915-1.odt to doc
3500 m_pOrigPam
->DeleteMark();
3501 m_pOrigPam
->GetPoint()->Assign(m_rDoc
.GetNodes().GetEndOfContent());
3502 static_cast<SwPaM
&>(*m_pCurPam
) = *m_pOrigPam
;
3504 m_rDoc
.getIDocumentRedlineAccess().SetRedlineFlags(m_nOrigRedlineFlags
);
3509 bool SwWW8Writer::InitStd97CodecUpdateMedium( ::msfilter::MSCodec_Std97
& rCodec
)
3511 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
3515 const SfxUnoAnyItem
* pEncryptionDataItem
= mpMedium
->GetItemSet().GetItem(SID_ENCRYPTIONDATA
, false);
3516 if ( pEncryptionDataItem
&& ( pEncryptionDataItem
->GetValue() >>= aEncryptionData
) && !rCodec
.InitCodec( aEncryptionData
) )
3518 OSL_ENSURE( false, "Unexpected EncryptionData!" );
3519 aEncryptionData
.realloc( 0 );
3522 if ( !aEncryptionData
.hasElements() )
3524 // try to generate the encryption data based on password
3525 const SfxStringItem
* pPasswordItem
= mpMedium
->GetItemSet().GetItem(SID_PASSWORD
, false);
3526 if ( pPasswordItem
&& !pPasswordItem
->GetValue().isEmpty() && pPasswordItem
->GetValue().getLength() <= 15 )
3528 // Generate random number with a seed of time as salt.
3529 sal_uInt8 pDocId
[ 16 ];
3530 if (rtl_random_getBytes(nullptr, pDocId
, 16) != rtl_Random_E_None
)
3532 throw uno::RuntimeException(u
"rtl_random_getBytes failed"_ustr
);
3535 sal_uInt16 aPassword
[16] = {};
3537 const OUString
& sPassword(pPasswordItem
->GetValue());
3538 for ( sal_Int32 nChar
= 0; nChar
< sPassword
.getLength(); ++nChar
)
3539 aPassword
[nChar
] = sPassword
[nChar
];
3541 rCodec
.InitKey( aPassword
, pDocId
);
3542 aEncryptionData
= rCodec
.GetEncryptionData();
3544 mpMedium
->GetItemSet().Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA
, uno::Any( aEncryptionData
) ) );
3548 if ( aEncryptionData
.hasElements() )
3549 mpMedium
->GetItemSet().ClearItem( SID_PASSWORD
);
3552 // nonempty encryption data means here that the codec was successfully initialized
3553 return aEncryptionData
.hasElements();
3556 ErrCode
WW8Export::ExportDocument_Impl()
3560 m_pFib
.reset(new WW8Fib(8, m_bDot
));
3562 rtl::Reference
<SotStorageStream
> xWwStrm(GetWriter().GetStorage().OpenSotStream(m_aMainStg
));
3563 if (!xWwStrm
->IsWritable())
3564 return ERRCODE_IO_ACCESSDENIED
;
3566 rtl::Reference
<SotStorageStream
> xTableStrm(xWwStrm
), xDataStrm(xWwStrm
);
3567 xWwStrm
->SetBufferSize( 32768 );
3569 m_pFib
->m_fWhichTableStm
= true;
3570 xTableStrm
= GetWriter().GetStorage().OpenSotStream(SL::a1Table
, StreamMode::STD_WRITE
);
3571 xDataStrm
= GetWriter().GetStorage().OpenSotStream(SL::aData
, StreamMode::STD_WRITE
);
3573 xDataStrm
->SetBufferSize( 32768 ); // for graphics
3574 xTableStrm
->SetBufferSize( 16384 ); // for the Font-/Style-Table, etc.
3576 xTableStrm
->SetEndian( SvStreamEndian::LITTLE
);
3577 xDataStrm
->SetEndian( SvStreamEndian::LITTLE
);
3579 GetWriter().SetStream( xWwStrm
.get() );
3580 m_pTableStrm
= xTableStrm
.get();
3581 m_pDataStrm
= xDataStrm
.get();
3583 Strm().SetEndian( SvStreamEndian::LITTLE
);
3585 utl::TempFileFast aTempMain
;
3586 utl::TempFileFast aTempTable
;
3587 utl::TempFileFast aTempData
;
3589 msfilter::MSCodec_Std97 aCtx
;
3590 bool bEncrypt
= GetWriter().InitStd97CodecUpdateMedium(aCtx
);
3593 GetWriter().SetStream(
3594 aTempMain
.GetStream( StreamMode::READWRITE
| StreamMode::SHARE_DENYWRITE
) );
3596 m_pTableStrm
= aTempTable
.GetStream( StreamMode::READWRITE
| StreamMode::SHARE_DENYWRITE
);
3598 m_pDataStrm
= aTempData
.GetStream( StreamMode::READWRITE
| StreamMode::SHARE_DENYWRITE
);
3600 sal_uInt8
const aRC4EncryptionHeader
[ 52 ] = {0};
3601 m_pTableStrm
->WriteBytes(aRC4EncryptionHeader
, 52);
3604 // Default: "Standard"
3605 m_pSepx
.reset(new WW8_WrPlcSepx( *this )); // Sections/headers/footers
3607 m_pFootnote
.reset(new WW8_WrPlcFootnoteEdn( TXT_FTN
)); // Footnotes
3608 m_pEdn
.reset(new WW8_WrPlcFootnoteEdn( TXT_EDN
)); // Endnotes
3609 m_pAtn
.reset(new WW8_WrPlcAnnotations
); // PostIts
3610 m_pFactoids
.reset(new WW8_WrtFactoids
); // Smart tags.
3611 m_pTextBxs
.reset(new WW8_WrPlcTextBoxes( TXT_TXTBOX
));
3612 m_pHFTextBxs
.reset(new WW8_WrPlcTextBoxes( TXT_HFTXTBOX
));
3614 m_pSdrObjs
.reset(new MainTextPlcDrawObj
); // Draw-/Fly-Objects for main text
3615 m_pHFSdrObjs
.reset(new HdFtPlcDrawObj
); // Draw-/Fly-Objects for header/footer
3617 m_pBkmks
.reset(new WW8_WrtBookmarks
); // Bookmarks
3618 GetWriter().CreateBookmarkTable();
3620 m_pPapPlc
.reset(new WW8_WrPlcPn( *this, PAP
, m_pFib
->m_fcMin
));
3621 m_pChpPlc
.reset(new WW8_WrPlcPn( *this, CHP
, m_pFib
->m_fcMin
));
3622 m_pO
.reset(new ww::bytes
);
3623 m_pStyles
.reset(new MSWordStyles( *this ));
3624 m_pFieldMain
.reset(new WW8_WrPlcField( 2, TXT_MAINTEXT
));
3625 m_pFieldHdFt
.reset(new WW8_WrPlcField( 2, TXT_HDFT
));
3626 m_pFieldFootnote
.reset(new WW8_WrPlcField( 2, TXT_FTN
));
3627 m_pFieldEdn
.reset(new WW8_WrPlcField( 2, TXT_EDN
));
3628 m_pFieldAtn
.reset(new WW8_WrPlcField( 2, TXT_ATN
));
3629 m_pFieldTextBxs
.reset(new WW8_WrPlcField( 2, TXT_TXTBOX
));
3630 m_pFieldHFTextBxs
.reset(new WW8_WrPlcField( 2, TXT_HFTXTBOX
));
3632 m_pMagicTable
.reset(new WW8_WrMagicTable
);
3634 m_pGrf
.reset(new SwWW8WrGrf( *this ));
3635 m_pPiece
.reset(new WW8_WrPct( m_pFib
->m_fcMin
));
3636 m_pDop
.reset(new WW8Dop
);
3638 m_pDop
->fRevMarking
= bool( RedlineFlags::On
& m_nOrigRedlineFlags
);
3639 SwRootFrame
const*const pLayout(m_rDoc
.getIDocumentLayoutAccess().GetCurrentLayout());
3640 m_pDop
->fRMView
= pLayout
== nullptr || !pLayout
->IsHideRedlines();
3641 m_pDop
->fRMPrint
= m_pDop
->fRMView
;
3643 // set AutoHyphenation flag if found in default para style
3644 const SvxHyphenZoneItem
* pItem
;
3645 SwTextFormatColl
* pStdTextFormatColl
=
3646 m_rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD
, false);
3647 if (pStdTextFormatColl
&& (pItem
= pStdTextFormatColl
->GetItemIfSet(
3648 RES_PARATR_HYPHENZONE
, false)))
3650 m_pDop
->fAutoHyphen
= pItem
->IsHyphen();
3655 ErrCode err
= ERRCODE_NONE
;
3658 SvStream
*pStrmTemp
, *pTableStrmTemp
, *pDataStrmTemp
;
3659 pStrmTemp
= xWwStrm
.get();
3660 pTableStrmTemp
= xTableStrm
.get();
3661 pDataStrmTemp
= xDataStrm
.get();
3663 if ( pDataStrmTemp
&& pDataStrmTemp
!= pStrmTemp
) {
3664 err
= EncryptRC4(aCtx
, *m_pDataStrm
, *pDataStrmTemp
);
3665 if (err
!= ERRCODE_NONE
) {
3670 err
= EncryptRC4(aCtx
, *m_pTableStrm
, *pTableStrmTemp
);
3671 if (err
!= ERRCODE_NONE
) {
3675 // Write Unencrypted Header 52 bytes to the start of the table stream
3676 // EncryptionVersionInfo (4 bytes): A Version structure where Version.vMajor MUST be 0x0001, and Version.vMinor MUST be 0x0001.
3677 pTableStrmTemp
->Seek( 0 );
3678 pTableStrmTemp
->WriteUInt32( 0x10001 ); // nEncType
3680 sal_uInt8 pDocId
[16];
3681 aCtx
.GetDocId( pDocId
);
3683 sal_uInt8 pSaltData
[16];
3684 sal_uInt8 pSaltDigest
[16];
3685 aCtx
.GetEncryptKey( pDocId
, pSaltData
, pSaltDigest
);
3687 pTableStrmTemp
->WriteBytes(pDocId
, 16);
3688 pTableStrmTemp
->WriteBytes(pSaltData
, 16);
3689 pTableStrmTemp
->WriteBytes(pSaltDigest
, 16);
3691 err
= EncryptRC4(aCtx
, GetWriter().Strm(), *pStrmTemp
);
3692 if (err
!= ERRCODE_NONE
) {
3696 // Write Unencrypted Fib 68 bytes to the start of the workdocument stream
3697 m_pFib
->m_fEncrypted
= true; // fEncrypted indicates the document is encrypted.
3698 m_pFib
->m_fObfuscated
= false; // Must be 0 for RC4.
3699 m_pFib
->m_nHash
= 0x34; // encrypt header bytes count of table stream.
3700 m_pFib
->m_nKey
= 0; // lkey2 must be 0 for RC4.
3702 pStrmTemp
->Seek( 0 );
3703 m_pFib
->WriteHeader( *pStrmTemp
);
3708 m_pMagicTable
.reset();
3709 m_pFieldFootnote
.reset();
3710 m_pFieldTextBxs
.reset();
3711 m_pFieldHFTextBxs
.reset();
3712 m_pFieldAtn
.reset();
3713 m_pFieldEdn
.reset();
3714 m_pFieldHdFt
.reset();
3715 m_pFieldMain
.reset();
3722 m_pRedlAuthors
.reset();
3724 m_pHFSdrObjs
.reset();
3726 m_pHFTextBxs
.reset();
3729 m_pFootnote
.reset();
3734 GetWriter().SetStream( nullptr );
3736 xWwStrm
->SetBufferSize( 0 );
3737 xTableStrm
->SetBufferSize( 0 );
3738 xDataStrm
->SetBufferSize( 0 );
3739 if( 0 == m_pDataStrm
->Seek( STREAM_SEEK_TO_END
))
3742 m_pDataStrm
= nullptr;
3743 GetWriter().GetStorage().Remove(SL::aData
);
3749 void WW8Export::PrepareStorage()
3751 static const sal_uInt8 pData
[] =
3753 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
3754 0xFF, 0xFF, 0xFF, 0xFF, 0x06, 0x09, 0x02, 0x00,
3755 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,
3756 0x00, 0x00, 0x00, 0x46,
3758 0x18, 0x00, 0x00, 0x00,
3759 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f',
3760 't', ' ', 'W', 'o', 'r', 'd', '-', 'D',
3761 'o', 'k', 'u', 'm', 'e', 'n', 't', 0x0,
3763 0x0A, 0x00, 0x00, 0x00,
3764 'M', 'S', 'W', 'o', 'r', 'd', 'D', 'o',
3767 0x10, 0x00, 0x00, 0x00,
3768 'W', 'o', 'r', 'd', '.', 'D', 'o', 'c',
3769 'u', 'm', 'e', 'n', 't', '.', '8', 0x0,
3771 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00,
3772 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
3775 SvGlobalName
aGName(MSO_WW8_CLASSID
);
3776 GetWriter().GetStorage().SetClass(
3777 aGName
, SotClipboardFormatId::NONE
, u
"Microsoft Word-Document"_ustr
);
3778 rtl::Reference
<SotStorageStream
> xStor(GetWriter().GetStorage().OpenSotStream(sCompObj
));
3779 xStor
->WriteBytes(pData
, sizeof(pData
));
3781 SwDocShell
* pDocShell
= m_rDoc
.GetDocShell ();
3782 OSL_ENSURE(pDocShell
, "no SwDocShell");
3784 if (!pDocShell
) return;
3786 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
3787 pDocShell
->GetModel(), uno::UNO_QUERY_THROW
);
3788 uno::Reference
<document::XDocumentProperties
> xDocProps(
3789 xDPS
->getDocumentProperties());
3790 OSL_ENSURE(xDocProps
.is(), "DocumentProperties is null");
3792 if (!xDocProps
.is())
3795 if (officecfg::Office::Common::Filter::Microsoft::Export::EnableWordPreview::get())
3797 std::shared_ptr
<GDIMetaFile
> xMetaFile
=
3798 pDocShell
->GetPreviewMetaFile();
3799 uno::Sequence
<sal_Int8
> metaFile(
3800 sfx2::convertMetaFile(xMetaFile
.get()));
3801 sfx2::SaveOlePropertySet(xDocProps
, &GetWriter().GetStorage(), &metaFile
);
3804 sfx2::SaveOlePropertySet( xDocProps
, &GetWriter().GetStorage() );
3807 ErrCodeMsg
SwWW8Writer::WriteStorage()
3809 rtl::Reference
<SotStorage
> xOrigStg
;
3810 uno::Reference
< packages::XPackageEncryption
> xPackageEncryption
;
3811 std::shared_ptr
<SvStream
> pSotStorageStream
;
3812 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
3815 // Check for specific encryption requests
3816 const SfxUnoAnyItem
* pEncryptionDataItem
= mpMedium
->GetItemSet().GetItem(SID_ENCRYPTIONDATA
, false);
3817 if (pEncryptionDataItem
&& (pEncryptionDataItem
->GetValue() >>= aEncryptionData
))
3819 ::comphelper::SequenceAsHashMap
aHashData(aEncryptionData
);
3820 OUString sCryptoType
= aHashData
.getUnpackedValueOrDefault(u
"CryptoType"_ustr
, OUString());
3822 if (sCryptoType
.getLength())
3824 const uno::Reference
<uno::XComponentContext
>& xComponentContext(comphelper::getProcessComponentContext());
3825 uno::Sequence
<uno::Any
> aArguments
{
3826 uno::Any(beans::NamedValue(u
"Binary"_ustr
, uno::Any(true))) };
3827 xPackageEncryption
.set(
3828 xComponentContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
3829 "com.sun.star.comp.oox.crypto." + sCryptoType
, aArguments
, xComponentContext
), uno::UNO_QUERY
);
3831 if (xPackageEncryption
)
3833 // We have an encryptor
3834 // Create new temporary storage for content
3836 pSotStorageStream
= std::make_shared
<SvMemoryStream
>();
3837 m_pStg
= new SotStorage(*pSotStorageStream
);
3843 ErrCode nErrorCode
= WriteStorageImpl();
3845 if (xPackageEncryption
)
3847 assert(pSotStorageStream
&& m_pStg
&& "because always set if xPackageEncryption was set");
3850 pSotStorageStream
->Seek(0);
3852 // Encrypt data written into temporary storage
3853 xPackageEncryption
->setupEncryption(aEncryptionData
);
3855 uno::Reference
<io::XInputStream
> xInputStream(new utl::OSeekableInputStreamWrapper(pSotStorageStream
.get(), false));
3856 uno::Sequence
<beans::NamedValue
> aStreams
= xPackageEncryption
->encrypt(xInputStream
);
3858 m_pStg
= std::move(xOrigStg
);
3859 for (const beans::NamedValue
& aStreamData
: aStreams
)
3861 // To avoid long paths split and open substorages recursively
3862 // Splitting paths manually, since comphelper::string::split is trimming special characters like \0x01, \0x09
3863 rtl::Reference
<SotStorage
> pStorage
= m_pStg
;
3866 while (pStorage
&& idx
>= 0)
3868 OUString sPathElem
= aStreamData
.Name
.getToken(0, L
'/', idx
);
3869 if (!sPathElem
.isEmpty())
3873 sFileName
= sPathElem
;
3877 pStorage
= pStorage
->OpenSotStorage(sPathElem
);
3886 nErrorCode
= ERRCODE_IO_GENERAL
;
3890 rtl::Reference
<SotStorageStream
> pStream
= pStorage
->OpenSotStream(sFileName
);
3893 nErrorCode
= ERRCODE_IO_GENERAL
;
3896 uno::Sequence
<sal_Int8
> aStreamContent
;
3897 aStreamData
.Value
>>= aStreamContent
;
3898 size_t nBytesWritten
= pStream
->WriteBytes(aStreamContent
.getArray(), aStreamContent
.getLength());
3899 if (nBytesWritten
!= static_cast<size_t>(aStreamContent
.getLength()))
3901 nErrorCode
= ERRCODE_IO_CANTWRITE
;
3909 ErrCode
SwWW8Writer::WriteStorageImpl()
3911 // #i34818# - update layout (if present), for SwWriteTable
3912 SwViewShell
* pViewShell
= m_pDoc
->getIDocumentLayoutAccess().GetCurrentViewShell();
3913 if( pViewShell
!= nullptr )
3914 pViewShell
->CalcLayout();
3916 SwNodeOffset nMaxNode
= m_pDoc
->GetNodes().Count();
3917 ::StartProgress( STR_STATSTR_W4WWRITE
, 0, sal_Int32(nMaxNode
), m_pDoc
->GetDocShell() );
3919 // Respect table at the beginning of the document
3921 SwTableNode
* pTNd
= m_pCurrentPam
->GetPointNode().FindTableNode();
3922 if( pTNd
&& m_bWriteAll
)
3923 // start with the table node !!
3924 m_pCurrentPam
->GetPoint()->Assign(*pTNd
);
3927 // Do the actual export
3928 ErrCode err
= ERRCODE_NONE
;
3930 bool bDot
= mpMedium
->GetFilter()->GetName().endsWith("Vorlage");
3931 WW8Export
aExport(this, *m_pDoc
, m_pCurrentPam
, m_pOrigPam
, bDot
);
3932 m_pExport
= &aExport
;
3933 err
= aExport
.ExportDocument( m_bWriteAll
);
3934 m_pExport
= nullptr;
3937 ::EndProgress( m_pDoc
->GetDocShell() );
3941 ErrCodeMsg
SwWW8Writer::WriteMedium( SfxMedium
& )
3943 return WriteStorage();
3946 ErrCodeMsg
SwWW8Writer::Write( SwPaM
& rPaM
, SfxMedium
& rMed
,
3947 const OUString
* pFileName
)
3950 ErrCodeMsg nRet
= StgWriter::Write( rPaM
, rMed
, pFileName
);
3955 MSWordExportBase::MSWordExportBase( SwDoc
& rDocument
, std::shared_ptr
<SwUnoCursor
> & pCurrentPam
, SwPaM
* pOriginalPam
)
3956 : m_aMainStg(sMainStream
)
3958 , m_pTopNodeOfHdFtPage(nullptr)
3959 , m_pTableInfo(std::make_shared
<ww8::WW8TableInfo
>())
3960 , m_nCharFormatStart(0)
3961 , m_nFormatCollStart(0)
3962 , m_nStyleBeforeFly(0)
3963 , m_nLastFormatId(0)
3966 , m_nOrigRedlineFlags(RedlineFlags::NONE
)
3967 , m_bOrigShowChanges(true)
3968 , m_pCurrentPageDesc(nullptr)
3969 , m_pPreviousSectionPageDesc(nullptr)
3970 , m_bFirstTOCNodeWithSection(false)
3971 , m_pChpIter(nullptr)
3972 , m_pParentFrame(nullptr)
3973 , m_bParaInlineHeading(false)
3974 , m_pFlyOffset(nullptr)
3975 , m_eNewAnchorType(RndStdIds::FLY_AS_CHAR
)
3976 , m_pStyAttr(nullptr)
3977 , m_pOutFormatNode(nullptr)
3978 , m_pCurrentStyle(nullptr)
3979 , m_pEscher(nullptr)
3982 , m_bBreakBefore(false)
3984 , m_bOutFlyFrameAttrs(false)
3985 , m_bOutPageDescs(false)
3986 , m_bOutFirstPage(false)
3987 , m_bOutTable(false)
3989 , m_bInWriteEscher(false)
3990 , m_bStartTOX(false)
3991 , m_bInWriteTOX(false)
3992 , m_bFootnoteAtTextEnd(false)
3993 , m_bEndAtTextEnd(false)
3996 , m_bSubstituteBullets(true)
3997 , m_bTabInTOC(false)
3998 , m_bHideTabLeaderAndPageNumbers(false)
3999 , m_bExportModeRTF(false)
4000 , m_bFontSizeWritten(false)
4001 , m_bAddFootnoteTab(false)
4003 , m_nCurStart(pCurrentPam
->GetPoint()->GetNodeIndex())
4004 , m_nCurEnd(pCurrentPam
->GetMark()->GetNodeIndex())
4005 , m_pCurPam(pCurrentPam
)
4006 , m_pOrigPam(pOriginalPam
)
4010 MSWordExportBase::~MSWordExportBase()
4012 if (m_pUsedNumTable
) // all used NumRules
4014 // clear the part of the list array that was copied from the document
4015 // - it's an auto delete array, so the rest of the array which are
4016 // duplicated lists that were added during the export will be deleted.
4017 m_pUsedNumTable
->erase(m_pUsedNumTable
->begin(), m_pUsedNumTable
->begin() + m_pUsedNumTable
->size() - m_nUniqueList
);
4018 m_pUsedNumTable
.reset();
4024 WW8Export::WW8Export( SwWW8Writer
*pWriter
,
4025 SwDoc
& rDocument
, std::shared_ptr
<SwUnoCursor
> & pCurrentPam
, SwPaM
* pOriginalPam
,
4027 : MSWordExportBase( rDocument
, pCurrentPam
, pOriginalPam
)
4028 , m_pTableStrm(nullptr)
4029 , m_pDataStrm(nullptr)
4031 , m_pWriter(pWriter
)
4032 , m_pAttrOutput(new WW8AttributeOutput(*this))
4033 , mpAuthorIDs(new SvtSecurityMapPersonalInfo
)
4037 WW8Export::~WW8Export()
4041 AttributeOutputBase
& WW8Export::AttrOutput() const
4043 return *m_pAttrOutput
;
4046 MSWordSections
& WW8Export::Sections() const
4051 SwWW8Writer::SwWW8Writer(std::u16string_view rFltName
, const OUString
& rBaseURL
)
4052 : m_pExport( nullptr ),
4055 assert(rFltName
== FILTER_WW8
); // WW6/7 export was removed
4057 SetBaseURL( rBaseURL
);
4060 SwWW8Writer::~SwWW8Writer()
4064 extern "C" SAL_DLLPUBLIC_EXPORT sal_uInt32
SaveOrDelMSVBAStorage_ww8( SfxObjectShell
& rDoc
, SotStorage
& rStor
, sal_Bool bSaveInto
, const OUString
& rStorageName
)
4066 SvxImportMSVBasic
aTmp( rDoc
, rStor
);
4067 return sal_uInt32(aTmp
.SaveOrDelMSVBAStorage( bSaveInto
, rStorageName
));
4070 extern "C" SAL_DLLPUBLIC_EXPORT
void ExportDOC( std::u16string_view rFltName
, const OUString
& rBaseURL
, WriterRef
& xRet
)
4072 xRet
= new SwWW8Writer( rFltName
, rBaseURL
);
4075 extern "C" SAL_DLLPUBLIC_EXPORT sal_uInt32
GetSaveWarningOfMSVBAStorage_ww8( SfxObjectShell
&rDocS
)
4077 return sal_uInt32(SvxImportMSVBasic::GetSaveWarningOfMSVBAStorage( rDocS
));
4080 bool WW8_WrPlcFootnoteEdn::WriteText( WW8Export
& rWrt
)
4083 if (TXT_FTN
== m_nTyp
)
4085 bRet
= WriteGenericText( rWrt
, TXT_FTN
, rWrt
.m_pFib
->m_ccpFootnote
);
4086 rWrt
.m_pFieldFootnote
->Finish( rWrt
.Fc2Cp( rWrt
.Strm().Tell() ),
4087 rWrt
.m_pFib
->m_ccpText
);
4091 bRet
= WriteGenericText( rWrt
, TXT_EDN
, rWrt
.m_pFib
->m_ccpEdn
);
4092 rWrt
.m_pFieldEdn
->Finish( rWrt
.Fc2Cp( rWrt
.Strm().Tell() ),
4093 rWrt
.m_pFib
->m_ccpText
+ rWrt
.m_pFib
->m_ccpFootnote
4094 + rWrt
.m_pFib
->m_ccpHdr
+ rWrt
.m_pFib
->m_ccpAtn
);
4099 void WW8_WrPlcFootnoteEdn::WritePlc( WW8Export
& rWrt
) const
4101 if( TXT_FTN
== m_nTyp
)
4103 WriteGenericPlc( rWrt
, TXT_FTN
, rWrt
.m_pFib
->m_fcPlcffndText
,
4104 rWrt
.m_pFib
->m_lcbPlcffndText
, rWrt
.m_pFib
->m_fcPlcffndRef
,
4105 rWrt
.m_pFib
->m_lcbPlcffndRef
);
4109 WriteGenericPlc( rWrt
, TXT_EDN
, rWrt
.m_pFib
->m_fcPlcfendText
,
4110 rWrt
.m_pFib
->m_lcbPlcfendText
, rWrt
.m_pFib
->m_fcPlcfendRef
,
4111 rWrt
.m_pFib
->m_lcbPlcfendRef
);
4115 bool WW8_WrPlcAnnotations::WriteText( WW8Export
& rWrt
)
4117 bool bRet
= WriteGenericText( rWrt
, TXT_ATN
, rWrt
.m_pFib
->m_ccpAtn
);
4118 rWrt
.m_pFieldAtn
->Finish( rWrt
.Fc2Cp( rWrt
.Strm().Tell() ),
4119 rWrt
.m_pFib
->m_ccpText
+ rWrt
.m_pFib
->m_ccpFootnote
4120 + rWrt
.m_pFib
->m_ccpHdr
);
4124 void WW8_WrPlcAnnotations::WritePlc( WW8Export
& rWrt
) const
4126 WriteGenericPlc( rWrt
, TXT_ATN
, rWrt
.m_pFib
->m_fcPlcfandText
,
4127 rWrt
.m_pFib
->m_lcbPlcfandText
, rWrt
.m_pFib
->m_fcPlcfandRef
,
4128 rWrt
.m_pFib
->m_lcbPlcfandRef
);
4131 void WW8_WrPlcTextBoxes::WritePlc( WW8Export
& rWrt
) const
4133 if( TXT_TXTBOX
== m_nTyp
)
4135 WriteGenericPlc( rWrt
, m_nTyp
, rWrt
.m_pFib
->m_fcPlcftxbxBkd
,
4136 rWrt
.m_pFib
->m_lcbPlcftxbxBkd
, rWrt
.m_pFib
->m_fcPlcftxbxText
,
4137 rWrt
.m_pFib
->m_lcbPlcftxbxText
);
4141 WriteGenericPlc( rWrt
, m_nTyp
, rWrt
.m_pFib
->m_fcPlcfHdrtxbxBkd
,
4142 rWrt
.m_pFib
->m_lcbPlcfHdrtxbxBkd
, rWrt
.m_pFib
->m_fcPlcfHdrtxbxText
,
4143 rWrt
.m_pFib
->m_lcbPlcfHdrtxbxText
);
4147 void WW8Export::RestoreMacroCmds()
4149 m_pFib
->m_fcCmds
= m_pTableStrm
->Tell();
4151 uno::Reference
< embed::XStorage
> xSrcRoot(m_rDoc
.GetDocShell()->GetStorage());
4154 uno::Reference
< io::XStream
> xSrcStream
=
4155 xSrcRoot
->openStreamElement( SL::aMSMacroCmds
, embed::ElementModes::READ
);
4156 std::unique_ptr
<SvStream
> pStream
= ::utl::UcbStreamHelper::CreateStream( xSrcStream
);
4158 if ( pStream
&& ERRCODE_NONE
== pStream
->GetError())
4160 m_pFib
->m_lcbCmds
= pStream
->TellEnd();
4163 std::unique_ptr
<sal_uInt8
[]> pBuffer( new sal_uInt8
[m_pFib
->m_lcbCmds
] );
4164 bool bReadOk
= checkRead(*pStream
, pBuffer
.get(), m_pFib
->m_lcbCmds
);
4166 m_pTableStrm
->WriteBytes(pBuffer
.get(), m_pFib
->m_lcbCmds
);
4169 catch ( const uno::Exception
& )
4174 m_pFib
->m_lcbCmds
= m_pTableStrm
->Tell() - m_pFib
->m_fcCmds
;
4177 void WW8SHDLong::Write( WW8Export
& rExport
)
4179 rExport
.InsUInt32( m_cvFore
);
4180 rExport
.InsUInt32( m_cvBack
);
4181 rExport
.InsUInt16( 0 ); // ipat
4184 void WW8Export::WriteFormData( const ::sw::mark::Fieldmark
& rFieldmark
)
4186 const ::sw::mark::Fieldmark
* pFieldmark
= &rFieldmark
;
4187 const ::sw::mark::CheckboxFieldmark
* pAsCheckbox
= dynamic_cast< const ::sw::mark::CheckboxFieldmark
* >( pFieldmark
);
4189 if ( ! ( rFieldmark
.GetFieldname() == ODF_FORMTEXT
||
4190 rFieldmark
.GetFieldname() == ODF_FORMDROPDOWN
||
4191 rFieldmark
.GetFieldname() == ODF_FORMCHECKBOX
) )
4193 SAL_WARN( "sw.ww8", "unknown field type" );
4197 int type
= 0; // TextFieldmark
4200 if ( rFieldmark
.GetFieldname() == ODF_FORMDROPDOWN
)
4203 OUString ffname
= rFieldmark
.GetName();
4204 if (ffname
.getLength() > 20)
4205 ffname
= ffname
.copy(0, 20);
4207 sal_uInt64 nDataStt
= m_pDataStrm
->Tell();
4208 m_pChpPlc
->AppendFkpEntry(Strm().Tell());
4211 static sal_uInt8 aArr1
[] =
4213 0x03, 0x6a, 0,0,0,0, // sprmCPicLocation
4215 0x06, 0x08, 0x01, // sprmCFData
4216 0x55, 0x08, 0x01, // sprmCFSpec
4217 0x02, 0x08, 0x01 // sprmCFFieldVanish
4219 sal_uInt8
* pDataAdr
= aArr1
+ 2;
4220 Set_UInt32(pDataAdr
, nDataStt
);
4222 m_pChpPlc
->AppendFkpEntry( Strm().Tell(), sizeof( aArr1
), aArr1
);
4230 FFDataHeader() : version( 0xFFFFFFFF ), bits(0), cch(0), hps(0) {}
4233 FFDataHeader aFieldHeader
;
4234 aFieldHeader
.bits
|= (type
& 0x03);
4236 sal_Int32 ffres
= 0; // rFieldmark.GetFFRes();
4237 if ( pAsCheckbox
&& pAsCheckbox
->IsChecked() )
4239 else if ( type
== 2 )
4241 ::sw::mark::Fieldmark::parameter_map_t::const_iterator pResParameter
= rFieldmark
.GetParameters()->find(ODF_FORMDROPDOWN_RESULT
);
4242 if(pResParameter
!= rFieldmark
.GetParameters()->end())
4243 pResParameter
->second
>>= ffres
;
4247 aFieldHeader
.bits
|= ( (ffres
<<2) & 0x7C );
4251 OUString ffhelptext
= rFieldmark
.GetFieldHelptext();
4252 if ( ffhelptext
.getLength() > 255 )
4253 ffhelptext
= ffhelptext
.copy(0, 255);
4254 OUString ffstattext
;
4255 OUString ffentrymcr
;
4258 ::sw::mark::Fieldmark::parameter_map_t::const_iterator pParameter
4259 = rFieldmark
.GetParameters()->find(u
"Type"_ustr
);
4260 if (type
== 0) // iTypeText
4262 sal_uInt16 nType
= 0;
4263 if ( pParameter
!= rFieldmark
.GetParameters()->end() )
4266 pParameter
->second
>>= aType
;
4267 if ( aType
== "number" ) nType
= 1;
4268 else if ( aType
== "date" ) nType
= 2;
4269 else if ( aType
== "currentTime" ) nType
= 3;
4270 else if ( aType
== "currentDate" ) nType
= 4;
4271 else if ( aType
== "calculated" ) nType
= 5;
4272 aFieldHeader
.bits
|= nType
<<11; // FFDataBits-F 00111000 00000000
4275 if ( nType
< 3 || nType
== 5 ) // not currentTime or currentDate
4277 pParameter
= rFieldmark
.GetParameters()->find(u
"Content"_ustr
);
4278 if ( pParameter
!= rFieldmark
.GetParameters()->end() )
4280 OUString aDefaultText
;
4281 pParameter
->second
>>= aDefaultText
;
4282 const sal_Int32 nLen
= std::min( sal_Int32(255), aDefaultText
.getLength() );
4283 ffdeftext
= aDefaultText
.copy (0, nLen
);
4287 pParameter
= rFieldmark
.GetParameters()->find(u
"MaxLength"_ustr
);
4288 if ( pParameter
!= rFieldmark
.GetParameters()->end() )
4290 sal_uInt16 nLength
= 0;
4291 pParameter
->second
>>= nLength
;
4292 nLength
= std::min( sal_uInt16(32767), nLength
);
4293 aFieldHeader
.cch
= nLength
;
4296 pParameter
= rFieldmark
.GetParameters()->find(u
"Format"_ustr
);
4297 if ( pParameter
!= rFieldmark
.GetParameters()->end() )
4300 pParameter
->second
>>= aFormat
;
4301 const sal_Int32 nLen
= std::min( sal_Int32(64), aFormat
.getLength() );
4302 ffformat
= aFormat
.copy(0, nLen
);
4306 pParameter
= rFieldmark
.GetParameters()->find(u
"Help"_ustr
); //help
4307 if ( ffhelptext
.isEmpty() && pParameter
!= rFieldmark
.GetParameters()->end() )
4310 pParameter
->second
>>= aHelpText
;
4311 const sal_Int32 nLen
= std::min( sal_Int32(255), aHelpText
.getLength() );
4312 ffhelptext
= aHelpText
.copy (0, nLen
);
4314 if ( !ffhelptext
.isEmpty() )
4315 aFieldHeader
.bits
|= 0x1<<7;
4317 pParameter
= rFieldmark
.GetParameters()->find(u
"Description"_ustr
); // doc tooltip
4318 if ( pParameter
== rFieldmark
.GetParameters()->end() )
4319 pParameter
= rFieldmark
.GetParameters()->find(u
"Hint"_ustr
); //docx tooltip
4320 if ( pParameter
!= rFieldmark
.GetParameters()->end() )
4322 OUString aStatusText
;
4323 pParameter
->second
>>= aStatusText
;
4324 const sal_Int32 nLen
= std::min( sal_Int32(138), aStatusText
.getLength() );
4325 ffstattext
= aStatusText
.copy (0, nLen
);
4327 if ( !ffstattext
.isEmpty() )
4328 aFieldHeader
.bits
|= 0x1<<8;
4330 pParameter
= rFieldmark
.GetParameters()->find(u
"EntryMacro"_ustr
);
4331 if ( pParameter
!= rFieldmark
.GetParameters()->end() )
4333 OUString aEntryMacro
;
4334 pParameter
->second
>>= aEntryMacro
;
4335 const sal_Int32 nLen
= std::min( sal_Int32(32), aEntryMacro
.getLength() );
4336 ffentrymcr
= aEntryMacro
.copy (0, nLen
);
4339 pParameter
= rFieldmark
.GetParameters()->find(u
"ExitMacro"_ustr
);
4340 if ( pParameter
!= rFieldmark
.GetParameters()->end() )
4342 OUString aExitMacro
;
4343 pParameter
->second
>>= aExitMacro
;
4344 const sal_Int32 nLen
= std::min( sal_Int32(32), aExitMacro
.getLength() );
4345 ffexitmcr
= aExitMacro
.copy (0, nLen
);
4348 std::vector
< OUString
> aListItems
;
4351 aFieldHeader
.bits
|= 0x8000; // ffhaslistbox
4352 const ::sw::mark::Fieldmark::parameter_map_t
* const pParameters
= rFieldmark
.GetParameters();
4353 ::sw::mark::Fieldmark::parameter_map_t::const_iterator pListEntries
= pParameters
->find(ODF_FORMDROPDOWN_LISTENTRY
);
4354 if(pListEntries
!= pParameters
->end())
4356 uno::Sequence
< OUString
> vListEntries
;
4357 pListEntries
->second
>>= vListEntries
;
4358 aListItems
.reserve(vListEntries
.getLength());
4359 copy(std::cbegin(vListEntries
), std::cend(vListEntries
), back_inserter(aListItems
));
4363 const sal_uInt8 aFieldData
[] =
4365 0x44,0, // the start of "next" data
4366 0,0,0,0,0,0,0,0,0,0, // PIC-Structure! /10
4367 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | /16
4368 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | /16
4369 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | /16
4372 sal_uInt32 slen
= sizeof(sal_uInt32
)
4373 + sizeof(aFieldData
)
4374 + sizeof( aFieldHeader
.version
) + sizeof( aFieldHeader
.bits
) + sizeof( aFieldHeader
.cch
) + sizeof( aFieldHeader
.hps
)
4375 + 2*ffname
.getLength() + 4
4376 + 2*ffformat
.getLength() + 4
4377 + 2*ffhelptext
.getLength() + 4
4378 + 2*ffstattext
.getLength() + 4
4379 + 2*ffentrymcr
.getLength() + 4
4380 + 2*ffexitmcr
.getLength() + 4;
4384 slen
+= 2*ffdeftext
.getLength() + 4; //xstzTextDef
4386 slen
+= 2; // sttb ( fExtend )
4387 slen
+= 4; // for num of list items
4388 const int items
= aListItems
.size();
4389 for( int i
= 0; i
< items
; i
++ ) {
4390 const OUString
& item
= aListItems
[i
];
4391 slen
+= 2 * item
.getLength() + 2;
4395 m_pDataStrm
->WriteUInt32( slen
);
4397 int len
= sizeof( aFieldData
);
4398 OSL_ENSURE( len
== 0x44-sizeof(sal_uInt32
), "SwWW8Writer::WriteFormData(..) - wrong aFieldData length" );
4399 m_pDataStrm
->WriteBytes( aFieldData
, len
);
4401 m_pDataStrm
->WriteUInt32( aFieldHeader
.version
).WriteUInt16( aFieldHeader
.bits
).WriteUInt16( aFieldHeader
.cch
).WriteUInt16( aFieldHeader
.hps
);
4403 SwWW8Writer::WriteString_xstz( *m_pDataStrm
, ffname
, true ); // Form field name
4406 SwWW8Writer::WriteString_xstz( *m_pDataStrm
, ffdeftext
, true );
4408 m_pDataStrm
->WriteUInt16( 0 );
4410 SwWW8Writer::WriteString_xstz( *m_pDataStrm
, ffformat
, true );
4411 SwWW8Writer::WriteString_xstz( *m_pDataStrm
, ffhelptext
, true );
4412 SwWW8Writer::WriteString_xstz( *m_pDataStrm
, ffstattext
, true );
4413 SwWW8Writer::WriteString_xstz( *m_pDataStrm
, ffentrymcr
, true );
4414 SwWW8Writer::WriteString_xstz( *m_pDataStrm
, ffexitmcr
, true );
4416 m_pDataStrm
->WriteUInt16( 0xFFFF );
4417 const int items
=aListItems
.size();
4418 m_pDataStrm
->WriteUInt32( items
);
4419 for(int i
=0;i
<items
;i
++) {
4420 const OUString
& item
=aListItems
[i
];
4421 SwWW8Writer::WriteString_xstz( *m_pDataStrm
, item
, false );
4426 void WW8Export::WriteHyperlinkData( const sw::mark::Fieldmark
& /*rFieldmark*/ )
4428 //@TODO implement me !!!
4431 void WW8AttributeOutput::TableNodeInfoInner(const ww8::WW8TableNodeInfoInner::Pointer_t
& pNodeInfoInner
)
4434 ShortToSVBT16( m_rWW8Export
.m_nStyleBeforeFly
, nStyle
);
4437 SAL_INFO( "sw.ww8", "<OutWW8_TableNodeInfoInner>" << pNodeInfoInner
->toString());
4440 m_rWW8Export
.m_pO
->clear();
4442 sal_uInt32 nShadowsBefore
= pNodeInfoInner
->getShadowsBefore();
4443 if (nShadowsBefore
> 0)
4445 ww8::WW8TableNodeInfoInner::Pointer_t
4446 pTmpNodeInfoInner
= std::make_shared
<ww8::WW8TableNodeInfoInner
>(nullptr);
4448 pTmpNodeInfoInner
->setDepth(pNodeInfoInner
->getDepth());
4449 pTmpNodeInfoInner
->setEndOfCell(true);
4451 for (sal_uInt32 n
= 0; n
< nShadowsBefore
; ++n
)
4453 m_rWW8Export
.WriteCR(pTmpNodeInfoInner
);
4455 m_rWW8Export
.m_pO
->insert( m_rWW8Export
.m_pO
->end(), nStyle
, nStyle
+2 ); // Style #
4456 TableInfoCell(pTmpNodeInfoInner
);
4457 m_rWW8Export
.m_pPapPlc
->AppendFkpEntry
4458 ( m_rWW8Export
.Strm().Tell(), m_rWW8Export
.m_pO
->size(), m_rWW8Export
.m_pO
->data() );
4460 m_rWW8Export
.m_pO
->clear();
4464 if (pNodeInfoInner
->isEndOfCell())
4466 SAL_INFO( "sw.ww8", "<endOfCell/>" );
4468 m_rWW8Export
.WriteCR(pNodeInfoInner
);
4470 m_rWW8Export
.m_pO
->insert( m_rWW8Export
.m_pO
->end(), nStyle
, nStyle
+2 ); // Style #
4471 TableInfoCell(pNodeInfoInner
);
4472 m_rWW8Export
.m_pPapPlc
->AppendFkpEntry( m_rWW8Export
.Strm().Tell(), m_rWW8Export
.m_pO
->size(), m_rWW8Export
.m_pO
->data() );
4474 m_rWW8Export
.m_pO
->clear();
4477 sal_uInt32 nShadowsAfter
= pNodeInfoInner
->getShadowsAfter();
4478 if (nShadowsAfter
> 0)
4480 ww8::WW8TableNodeInfoInner::Pointer_t
4481 pTmpNodeInfoInner
= std::make_shared
<ww8::WW8TableNodeInfoInner
>(nullptr);
4483 pTmpNodeInfoInner
->setDepth(pNodeInfoInner
->getDepth());
4484 pTmpNodeInfoInner
->setEndOfCell(true);
4486 for (sal_uInt32 n
= 0; n
< nShadowsAfter
; ++n
)
4488 m_rWW8Export
.WriteCR(pTmpNodeInfoInner
);
4490 m_rWW8Export
.m_pO
->insert( m_rWW8Export
.m_pO
->end(), nStyle
, nStyle
+2 ); // Style #
4491 TableInfoCell(pTmpNodeInfoInner
);
4492 m_rWW8Export
.m_pPapPlc
->AppendFkpEntry( m_rWW8Export
.Strm().Tell(), m_rWW8Export
.m_pO
->size(), m_rWW8Export
.m_pO
->data() );
4494 m_rWW8Export
.m_pO
->clear();
4498 if (pNodeInfoInner
->isEndOfLine())
4500 SAL_INFO( "sw.ww8", "<endOfLine/>" );
4502 TableRowEnd(pNodeInfoInner
->getDepth());
4504 ShortToSVBT16(0, nStyle
);
4505 m_rWW8Export
.m_pO
->insert( m_rWW8Export
.m_pO
->end(), nStyle
, nStyle
+2 ); // Style #
4506 TableInfoRow(pNodeInfoInner
);
4507 m_rWW8Export
.m_pPapPlc
->AppendFkpEntry( m_rWW8Export
.Strm().Tell(), m_rWW8Export
.m_pO
->size(), m_rWW8Export
.m_pO
->data() );
4509 m_rWW8Export
.m_pO
->clear();
4511 SAL_INFO( "sw.ww8", "</OutWW8_TableNodeInfoInner>" );
4514 void MSWordExportBase::OutputStartNode( const SwStartNode
& rNode
)
4517 ww8::WW8TableNodeInfo::Pointer_t pNodeInfo
=
4518 m_pTableInfo
->getTableNodeInfo( &rNode
);
4523 SAL_INFO( "sw.ww8", pNodeInfo
->toString());
4525 const ww8::WW8TableNodeInfo::Inners_t aInners
= pNodeInfo
->getInners();
4526 ww8::WW8TableNodeInfo::Inners_t::const_reverse_iterator
aIt(aInners
.rbegin());
4527 ww8::WW8TableNodeInfo::Inners_t::const_reverse_iterator
aEnd(aInners
.rend());
4530 ww8::WW8TableNodeInfoInner::Pointer_t pInner
= aIt
->second
;
4532 AttrOutput().TableNodeInfoInner(pInner
);
4536 SAL_INFO( "sw.ww8", "</OutWW8_SwStartNode>" );
4539 void MSWordExportBase::OutputEndNode( const SwEndNode
&rNode
)
4542 SAL_INFO( "sw.ww8", "<OutWW8_SwEndNode>" << dbg_out(&rNode
));
4545 ww8::WW8TableNodeInfo::Pointer_t pNodeInfo
= m_pTableInfo
->getTableNodeInfo( &rNode
);
4550 SAL_INFO( "sw.ww8", pNodeInfo
->toString());
4552 const ww8::WW8TableNodeInfo::Inners_t aInners
= pNodeInfo
->getInners();
4553 for (const auto& rEntry
: aInners
)
4555 ww8::WW8TableNodeInfoInner::Pointer_t pInner
= rEntry
.second
;
4556 AttrOutput().TableNodeInfoInner(pInner
);
4559 SAL_INFO( "sw.ww8", "</OutWW8_SwEndNode>" );
4562 const NfKeywordTable
& MSWordExportBase::GetNfKeywordTable()
4564 if (m_pKeyMap
== nullptr)
4566 m_pKeyMap
= std::make_shared
<NfKeywordTable
>();
4567 NfKeywordTable
& rKeywordTable
= *m_pKeyMap
;
4568 rKeywordTable
[NF_KEY_D
] = "d";
4569 rKeywordTable
[NF_KEY_DD
] = "dd";
4570 rKeywordTable
[NF_KEY_DDD
] = "ddd";
4571 rKeywordTable
[NF_KEY_DDDD
] = "dddd";
4572 rKeywordTable
[NF_KEY_M
] = "M";
4573 rKeywordTable
[NF_KEY_MM
] = "MM";
4574 rKeywordTable
[NF_KEY_MMM
] = "MMM";
4575 rKeywordTable
[NF_KEY_MMMM
] = "MMMM";
4576 rKeywordTable
[NF_KEY_NN
] = "ddd";
4577 rKeywordTable
[NF_KEY_NNN
] = "dddd";
4578 rKeywordTable
[NF_KEY_NNNN
] = "dddd";
4579 rKeywordTable
[NF_KEY_YY
] = "yy";
4580 rKeywordTable
[NF_KEY_YYYY
] = "yyyy";
4581 rKeywordTable
[NF_KEY_H
] = "H";
4582 rKeywordTable
[NF_KEY_HH
] = "HH";
4583 rKeywordTable
[NF_KEY_MI
] = "m";
4584 rKeywordTable
[NF_KEY_MMI
] = "mm";
4585 rKeywordTable
[NF_KEY_S
] = "s";
4586 rKeywordTable
[NF_KEY_SS
] = "ss";
4587 rKeywordTable
[NF_KEY_AMPM
] = "AM/PM";
4593 OUString
MSWordExportBase::BookmarkToWord(const OUString
& rBookmark
, bool* pIsMove
, bool* pIsFrom
)
4595 OUString sLookup
= rBookmark
;
4598 static constexpr OUStringLiteral MoveFrom_Bookmark_NamePrefix
= u
"__RefMoveFrom__";
4599 static constexpr OUStringLiteral MoveTo_Bookmark_NamePrefix
= u
"__RefMoveTo__";
4600 if (rBookmark
.startsWith(MoveFrom_Bookmark_NamePrefix
, &sLookup
))
4605 else if (rBookmark
.startsWith(MoveTo_Bookmark_NamePrefix
, &sLookup
))
4611 if (auto it
= m_aBookmarkToWord
.find(sLookup
); it
!= m_aBookmarkToWord
.end())
4615 = INetURLObject::encode(sLookup
.replace(' ', '_'), // Spaces are prohibited in bookmark name
4616 INetURLObject::PART_REL_SEGMENT_EXTRA
,
4617 INetURLObject::EncodeMechanism::All
, RTL_TEXTENCODING_ASCII_US
);
4618 // Unicode letters are allowed
4619 sRet
= INetURLObject::decode(sRet
, INetURLObject::DecodeMechanism::Unambiguous
,
4620 RTL_TEXTENCODING_UTF8
);
4623 // Word has 40 character limit for bookmarks: [MS-OE376] Part 4 Sect. 2.13.6.2, bookmarkStart
4624 if (sRet
.getLength() > 40)
4626 // Generate a unique bookmark name
4627 sRet
= sRet
.copy(0, 40);
4628 for (sal_uInt32 n
= 1; n
; ++n
)
4630 if (m_aWordBookmarks
.find(sRet
) == m_aWordBookmarks
.end())
4632 auto num
= OUString::number(n
, 36);
4633 sRet
= sRet
.subView(0, 40 - num
.length
) + num
;
4637 m_aBookmarkToWord
[sLookup
] = sRet
;
4638 m_aWordBookmarks
.insert(sRet
);
4642 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */