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>
32 #include <hintids.hxx>
34 #include <o3tl/safeint.hxx>
35 #include <osl/endian.h>
36 #include <sal/log.hxx>
38 #include <drawdoc.hxx>
40 #include <unotools/fltrcfg.hxx>
41 #include <sot/storage.hxx>
42 #include <sfx2/docinf.hxx>
43 #include <editeng/tstpitem.hxx>
44 #include <svx/svdpage.hxx>
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 "sprmids.hxx"
93 #include <comphelper/sequenceashashmap.hxx>
94 #include <comphelper/processfactory.hxx>
95 #include "writerhelper.hxx"
96 #include "writerwordglue.hxx"
97 #include "ww8attributeoutput.hxx"
98 #include <xmloff/odffields.hxx>
99 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
100 #include <com/sun/star/document/XDocumentProperties.hpp>
101 #include <dbgoutsw.hxx>
102 #include <sfx2/docfile.hxx>
103 #include <sfx2/frame.hxx>
104 #include <svl/stritem.hxx>
105 #include <unotools/tempfile.hxx>
106 #include <filter/msfilter/mscodec.hxx>
107 #include <filter/msfilter/svxmsbas.hxx>
108 #include <rtl/random.h>
109 #include <vcl/svapp.hxx>
110 #include <sfx2/docfilt.hxx>
111 #include "WW8Sttbf.hxx"
112 #include <editeng/charrotateitem.hxx>
113 #include <svx/swframetypes.hxx>
114 #include "WW8FibData.hxx"
115 #include <numrule.hxx>
116 #include <fmtclds.hxx>
117 #include <rdfhelper.hxx>
118 #include <fmtclbl.hxx>
119 #include <iodetect.hxx>
120 #include <fmtwrapinfluenceonobjpos.hxx>
123 using namespace sw::util
;
124 using namespace sw::types
;
126 /** FKP - Formatted disK Page
130 sal_uInt8
* m_pFkp
; // Fkp total ( first and only FCs and Sprms )
131 sal_uInt8
* m_pOfs
; // pointer to the offset area, later copied to pFkp
133 short m_nStartGrp
; // from here on grpprls
134 short m_nOldStartGrp
;
135 sal_uInt8 m_nItemSize
;
136 sal_uInt8 m_nIMax
; // number of entry pairs
137 sal_uInt8 m_nOldVarLen
;
138 bool m_bCombined
; // true : paste not allowed
140 sal_uInt8
SearchSameSprm( sal_uInt16 nVarLen
, const sal_uInt8
* pSprms
);
142 WW8_WrFkp(const WW8_WrFkp
&) = delete;
143 WW8_WrFkp
& operator=(const WW8_WrFkp
&) = delete;
146 WW8_WrFkp(ePLCFT ePl
, WW8_FC nStartFc
);
148 bool Append( WW8_FC nEndFc
, sal_uInt16 nVarLen
, const sal_uInt8
* pSprms
);
150 void Write( SvStream
& rStrm
, SwWW8WrGrf
& rGrf
);
152 bool IsEqualPos(WW8_FC nEndFc
) const
153 { return !m_bCombined
&& m_nIMax
&& nEndFc
== reinterpret_cast<sal_Int32
*>(m_pFkp
)[m_nIMax
]; }
154 void MergeToNew( short& rVarLen
, sal_uInt8
*& pNewSprms
);
155 bool IsEmptySprm() const
156 { return !m_bCombined
&& m_nIMax
&& !m_nOldVarLen
; }
157 void SetNewEnd( WW8_FC nEnd
)
158 { reinterpret_cast<sal_Int32
*>(m_pFkp
)[m_nIMax
] = nEnd
; }
160 WW8_FC
GetStartFc() const;
161 WW8_FC
GetEndFc() const;
163 sal_uInt8
*CopyLastSprms(sal_uInt8
&rLen
);
166 // class WW8_WrPc collects all piece entries for one piece
169 WW8_CP m_nStartCp
; // Starting character position of the text
170 WW8_FC m_nStartFc
; // Starting file position of the text
171 sal_uInt16 m_nStatus
; // End of paragraph inside the piece?
174 WW8_WrPc(WW8_FC nSFc
, WW8_CP nSCp
)
175 : m_nStartCp( nSCp
), m_nStartFc( nSFc
), m_nStatus( 0x0040 )
178 void SetStatus() { m_nStatus
= 0x0050; }
179 sal_uInt16
GetStatus() const { return m_nStatus
; }
180 WW8_CP
GetStartCp() const { return m_nStartCp
; }
181 WW8_FC
GetStartFc() const { return m_nStartFc
; }
184 typedef std::map
<OUString
,tools::Long
> BKMKNames
;
185 typedef std::pair
<bool,OUString
> BKMK
;
186 typedef std::pair
<tools::Long
,BKMK
> BKMKCP
;
187 typedef std::multimap
<tools::Long
,BKMKCP
*> BKMKCPs
;
188 typedef BKMKCPs::iterator CPItr
;
190 class WW8_WrtBookmarks
193 /// Structure of one item inside this map: (startPos, (endPos, (a bool value?, bookmarkName)))
195 BKMKNames maSwBkmkNms
;
197 WW8_WrtBookmarks(WW8_WrtBookmarks
const&) = delete;
198 WW8_WrtBookmarks
& operator=(WW8_WrtBookmarks
const&) = delete;
203 //! Add a new bookmark to the list OR add an end position to an existing bookmark.
204 void Append( WW8_CP nStartCp
, const OUString
& rNm
);
205 //! Write out bookmarks to file.
206 void Write( WW8Export
& rWrt
);
207 //! Move existing field marks from one position to another.
208 void MoveFieldMarks(WW8_CP nFrom
, WW8_CP nTo
);
211 WW8_WrtBookmarks::WW8_WrtBookmarks()
214 WW8_WrtBookmarks::~WW8_WrtBookmarks()
216 for (auto& rEntry
: maSttCps
)
220 delete rEntry
.second
;
221 rEntry
.second
= nullptr;
226 void WW8_WrtBookmarks::Append( WW8_CP nStartCp
, const OUString
& rNm
)
228 std::pair
<BKMKNames::iterator
, bool> aResult
= maSwBkmkNms
.insert(std::pair
<OUString
,tools::Long
>(rNm
,0L));
232 BKMKCP
* pBKCP
= new BKMKCP(static_cast<tools::Long
>(nStartCp
),aBK
);
233 maSttCps
.insert(std::pair
<tools::Long
,BKMKCP
*>(nStartCp
,pBKCP
));
234 aResult
.first
->second
= static_cast<tools::Long
>(nStartCp
);
238 std::pair
<CPItr
,CPItr
> aRange
= maSttCps
.equal_range(aResult
.first
->second
);
239 for (CPItr aItr
= aRange
.first
;aItr
!= aRange
.second
;++aItr
)
241 if (aItr
->second
&& aItr
->second
->second
.second
== rNm
)
243 if (aItr
->second
->second
.first
)
245 aItr
->second
->first
= static_cast<tools::Long
>(nStartCp
);
252 void WW8_WrtBookmarks::Write( WW8Export
& rWrt
)
254 if (maSttCps
.empty())
257 std::vector
<OUString
> aNames
;
258 SvMemoryStream
aTempStrm1(65535,65535);
259 SvMemoryStream
aTempStrm2(65535,65535);
262 for (const auto& rEntry
: maSttCps
)
266 aEndCps
.insert(std::pair
<tools::Long
,BKMKCP
*>(rEntry
.second
->first
, rEntry
.second
));
267 aNames
.push_back(rEntry
.second
->second
.second
);
268 SwWW8Writer::WriteLong(aTempStrm1
, rEntry
.first
);
274 for (const auto& rEntry
: aEndCps
)
278 rEntry
.second
->first
= n
;
279 SwWW8Writer::WriteLong( aTempStrm2
, rEntry
.first
);
285 rWrt
.WriteAsStringTable(aNames
, rWrt
.m_pFib
->m_fcSttbfbkmk
,rWrt
.m_pFib
->m_lcbSttbfbkmk
);
286 SvStream
& rStrm
= *rWrt
.m_pTableStrm
;
287 rWrt
.m_pFib
->m_fcPlcfbkf
= rStrm
.Tell();
288 rStrm
.WriteStream( aTempStrm1
);
289 SwWW8Writer::WriteLong(rStrm
, rWrt
.m_pFib
->m_ccpText
+ rWrt
.m_pFib
->m_ccpTxbx
);
290 for (const auto& rEntry
: maSttCps
)
294 SwWW8Writer::WriteLong(rStrm
, rEntry
.second
->first
);
297 rWrt
.m_pFib
->m_lcbPlcfbkf
= rStrm
.Tell() - rWrt
.m_pFib
->m_fcPlcfbkf
;
298 rWrt
.m_pFib
->m_fcPlcfbkl
= rStrm
.Tell();
299 rStrm
.WriteStream( aTempStrm2
);
300 SwWW8Writer::WriteLong(rStrm
, rWrt
.m_pFib
->m_ccpText
+ rWrt
.m_pFib
->m_ccpTxbx
);
301 rWrt
.m_pFib
->m_lcbPlcfbkl
= rStrm
.Tell() - rWrt
.m_pFib
->m_fcPlcfbkl
;
304 void WW8_WrtBookmarks::MoveFieldMarks(WW8_CP nFrom
, WW8_CP nTo
)
306 std::pair
<CPItr
,CPItr
> aRange
= maSttCps
.equal_range(nFrom
);
307 CPItr aItr
= aRange
.first
;
308 while (aItr
!= aRange
.second
)
312 if (aItr
->second
->first
== static_cast<tools::Long
>(nFrom
))
314 aItr
->second
->second
.first
= true;
315 aItr
->second
->first
= nTo
;
317 maSttCps
.insert(std::pair
<tools::Long
,BKMKCP
*>(nTo
,aItr
->second
));
318 aItr
->second
= nullptr;
319 aRange
= maSttCps
.equal_range(nFrom
);
327 /// Handles export of smart tags.
328 class WW8_WrtFactoids
330 std::vector
<WW8_CP
> m_aStartCPs
;
331 std::vector
<WW8_CP
> m_aEndCPs
;
332 std::vector
< std::map
<OUString
, OUString
> > m_aStatements
;
334 WW8_WrtFactoids(WW8_WrtFactoids
const&) = delete;
335 WW8_WrtFactoids
& operator=(WW8_WrtFactoids
const&) = delete;
339 void Append(WW8_CP nStartCp
, WW8_CP nEndCp
, const std::map
<OUString
, OUString
>& rStatements
);
340 void Write(WW8Export
& rWrt
);
343 WW8_WrtFactoids::WW8_WrtFactoids()
347 void WW8_WrtFactoids::Append(WW8_CP nStartCp
, WW8_CP nEndCp
, const std::map
<OUString
, OUString
>& rStatements
)
349 m_aStartCPs
.push_back(nStartCp
);
350 m_aEndCPs
.push_back(nEndCp
);
351 m_aStatements
.push_back(rStatements
);
354 void WW8_WrtFactoids::Write(WW8Export
& rExport
)
356 if (m_aStartCPs
.empty())
359 // Smart tags are otherwise removed by Word on saving.
360 rExport
.m_pDop
->fEmbedFactoids
= true;
362 SvStream
& rStream
= *rExport
.m_pTableStrm
;
364 rExport
.m_pFib
->m_fcSttbfBkmkFactoid
= rStream
.Tell();
365 // Write SttbfBkmkFactoid.
366 rStream
.WriteUInt16(0xffff); // fExtend
367 rStream
.WriteUInt16(m_aStartCPs
.size()); // cData
368 rStream
.WriteUInt16(0); // cbExtra
370 for (size_t i
= 0; i
< m_aStartCPs
.size(); ++i
)
372 rStream
.WriteUInt16(6); // cchData
373 // Write FACTOIDINFO.
374 rStream
.WriteUInt32(i
); // dwId
375 rStream
.WriteUInt16(0); // fSubEntry
376 rStream
.WriteUInt16(0); // fto
377 rStream
.WriteUInt32(0); // pfpb
379 rExport
.m_pFib
->m_lcbSttbfBkmkFactoid
= rStream
.Tell() - rExport
.m_pFib
->m_fcSttbfBkmkFactoid
;
381 rExport
.m_pFib
->m_fcPlcfBkfFactoid
= rStream
.Tell();
382 for (const WW8_CP
& rCP
: m_aStartCPs
)
383 rStream
.WriteInt32(rCP
);
384 rStream
.WriteInt32(rExport
.m_pFib
->m_ccpText
+ rExport
.m_pFib
->m_ccpTxbx
);
387 for (size_t i
= 0; i
< m_aStartCPs
.size(); ++i
)
389 rStream
.WriteInt16(i
); // ibkl
390 rStream
.WriteInt16(0); // bkc
391 rStream
.WriteInt16(1); // cDepth, 1 as start and end is the same.
394 rExport
.m_pFib
->m_lcbPlcfBkfFactoid
= rStream
.Tell() - rExport
.m_pFib
->m_fcPlcfBkfFactoid
;
396 rExport
.m_pFib
->m_fcPlcfBklFactoid
= rStream
.Tell();
397 for (const WW8_CP
& rCP
: m_aEndCPs
)
398 rStream
.WriteInt32(rCP
);
399 rStream
.WriteInt32(rExport
.m_pFib
->m_ccpText
+ rExport
.m_pFib
->m_ccpTxbx
);
402 for (size_t i
= 0; i
< m_aEndCPs
.size(); ++i
)
404 rStream
.WriteInt16(i
); // ibkf
405 rStream
.WriteInt16(0); // cDepth, 0 as does not overlap with any other smart tag.
407 rExport
.m_pFib
->m_lcbPlcfBklFactoid
= rStream
.Tell() - rExport
.m_pFib
->m_fcPlcfBklFactoid
;
409 rExport
.m_pFib
->m_fcFactoidData
= rStream
.Tell();
410 // Write SmartTagData.
411 MSOFactoidType aFactoidType
;
412 aFactoidType
.m_nId
= 1;
413 aFactoidType
.m_aUri
= "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
414 aFactoidType
.m_aTag
= "RDF";
415 WW8SmartTagData aSmartTagData
;
416 aSmartTagData
.m_aPropBagStore
.m_aFactoidTypes
.push_back(aFactoidType
);
418 std::set
<OUString
> aSet
;
419 for (const std::map
<OUString
, OUString
>& rStatements
: m_aStatements
)
421 // Statements for a single text node.
422 for (const auto& rPair
: rStatements
)
424 aSet
.insert(rPair
.first
);
425 aSet
.insert(rPair
.second
);
428 aSmartTagData
.m_aPropBagStore
.m_aStringTable
.assign(aSet
.begin(), aSet
.end());
429 for (const std::map
<OUString
, OUString
>& rStatements
: m_aStatements
)
431 MSOPropertyBag aPropertyBag
;
432 aPropertyBag
.m_nId
= 1;
433 for (const auto& rPair
: rStatements
)
435 MSOProperty aProperty
;
436 aProperty
.m_nKey
= std::distance(aSet
.begin(), aSet
.find(rPair
.first
));
437 aProperty
.m_nValue
= std::distance(aSet
.begin(), aSet
.find(rPair
.second
));
438 aPropertyBag
.m_aProperties
.push_back(aProperty
);
440 aSmartTagData
.m_aPropBags
.push_back(aPropertyBag
);
443 aSmartTagData
.Write(rExport
);
444 rExport
.m_pFib
->m_lcbFactoidData
= rStream
.Tell() - rExport
.m_pFib
->m_fcFactoidData
;
447 #define DEFAULT_STYLES_COUNT 16
449 // Names of the storage streams
450 constexpr OUStringLiteral sMainStream
= u
"WordDocument";
451 constexpr OUStringLiteral sCompObj
= u
"\1CompObj";
453 static void WriteDop( WW8Export
& rWrt
)
455 WW8Dop
& rDop
= *rWrt
.m_pDop
;
457 // i#78951#, store the value of unknown compatibility options
458 rDop
.SetCompatibilityOptions( rWrt
.m_rDoc
.getIDocumentSettingAccess().Getn32DummyCompatibilityOptions1());
459 rDop
.SetCompatibilityOptions2( rWrt
.m_rDoc
.getIDocumentSettingAccess().Getn32DummyCompatibilityOptions2());
461 rDop
.fNoLeading
= !rWrt
.m_rDoc
.getIDocumentSettingAccess().get(DocumentSettingId::ADD_EXT_LEADING
);
462 rDop
.fUsePrinterMetrics
= !rWrt
.m_rDoc
.getIDocumentSettingAccess().get(DocumentSettingId::USE_VIRTUAL_DEVICE
);
464 // write default TabStop
465 const SvxTabStopItem
& rTabStop
=
466 rWrt
.m_rDoc
.GetAttrPool().GetDefaultItem(RES_PARATR_TABSTOP
);
467 rDop
.dxaTab
= o3tl::narrowing
<sal_uInt16
>(rTabStop
[0].GetTabPos());
469 // Zoom factor and type
470 SwViewShell
*pViewShell(rWrt
.m_rDoc
.getIDocumentLayoutAccess().GetCurrentViewShell());
473 switch ( pViewShell
->GetViewOptions()->GetZoomType() )
475 case SvxZoomType::WHOLEPAGE
: rDop
.zkSaved
= 1; break;
476 case SvxZoomType::PAGEWIDTH
: rDop
.zkSaved
= 2; break;
477 case SvxZoomType::OPTIMAL
: rDop
.zkSaved
= 3; break;
478 default: rDop
.zkSaved
= 0;
479 rDop
.wScaleSaved
= pViewShell
->GetViewOptions()->GetZoom();
484 // Values from the DocumentStatistics (are definitely needed
485 // for the DocStat fields)
486 rDop
.fWCFootnoteEdn
= true; // because they are included in StarWriter
488 const SwDocStat
& rDStat
= rWrt
.m_rDoc
.getIDocumentStatistics().GetDocStat();
489 rDop
.cWords
= rDStat
.nWord
;
490 rDop
.cCh
= rDStat
.nChar
;
491 rDop
.cPg
= static_cast< sal_Int16
>(rDStat
.nPage
);
492 rDop
.cParas
= rDStat
.nPara
;
493 rDop
.cLines
= rDStat
.nPara
;
495 SwDocShell
*pDocShell(rWrt
.m_rDoc
.GetDocShell());
496 OSL_ENSURE(pDocShell
, "no SwDocShell");
497 uno::Reference
<document::XDocumentProperties
> xDocProps
;
498 uno::Reference
<beans::XPropertySet
> xProps
;
501 uno::Reference
<lang::XComponent
> xModelComp
= pDocShell
->GetModel();
502 xProps
.set(xModelComp
, uno::UNO_QUERY
);
503 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(xModelComp
, uno::UNO_QUERY_THROW
);
504 xDocProps
= xDPS
->getDocumentProperties();
505 OSL_ENSURE(xDocProps
.is(), "DocumentProperties is null");
507 rDop
.lKeyProtDoc
= pDocShell
->GetModifyPasswordHash();
510 if ((rWrt
.m_pSepx
&& rWrt
.m_pSepx
->DocumentIsProtected()) ||
511 rWrt
.m_rDoc
.getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_FORM
) ||
512 rDop
.lKeyProtDoc
!= 0)
514 rDop
.fProtEnabled
= true;
515 // The password was ignored at import if forms protection was enabled,
516 // so round-trip it since protection is still enabled.
517 if ( rDop
.lKeyProtDoc
== 0 && xProps
.is() )
519 comphelper::SequenceAsHashMap
aPropMap( xProps
->getPropertyValue("InteropGrabBag"));
520 aPropMap
.getValue("FormPasswordHash") >>= rDop
.lKeyProtDoc
;
525 rDop
.fProtEnabled
= false;
528 if (rWrt
.m_rDoc
.getIDocumentSettingAccess().get(DocumentSettingId::GUTTER_AT_TOP
))
530 rDop
.iGutterPos
= true;
535 rDop
.dttmCreated
= rDop
.dttmRevised
= rDop
.dttmLastPrint
= 0x45FBAC69;
539 ::util::DateTime uDT
= xDocProps
->getCreationDate();
540 rDop
.dttmCreated
= sw::ms::DateTime2DTTM(DateTime(uDT
));
541 uDT
= xDocProps
->getModificationDate();
542 rDop
.dttmRevised
= sw::ms::DateTime2DTTM(DateTime(uDT
));
543 uDT
= xDocProps
->getPrintDate();
544 rDop
.dttmLastPrint
= sw::ms::DateTime2DTTM(DateTime(uDT
));
547 // Also, the DocStat fields in headers, footers are not calculated correctly.
548 // ( we do not have this fields! )
550 // and also for the Headers and Footers
551 rDop
.cWordsFootnoteEnd
= rDStat
.nWord
;
552 rDop
.cChFootnoteEdn
= rDStat
.nChar
;
553 rDop
.cPgFootnoteEdn
= static_cast<sal_Int16
>(rDStat
.nPage
);
554 rDop
.cParasFootnoteEdn
= rDStat
.nPara
;
555 rDop
.cLinesFootnoteEdn
= rDStat
.nPara
;
557 rDop
.fDontUseHTMLAutoSpacing
= rWrt
.m_rDoc
.getIDocumentSettingAccess().get(DocumentSettingId::PARA_SPACE_MAX
);
559 rDop
.fExpShRtn
= !rWrt
.m_rDoc
.getIDocumentSettingAccess().get(DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK
); // #i56856#
561 IDocumentSettingAccess
& rIDSA
= rWrt
.m_rDoc
.getIDocumentSettingAccess();
562 rDop
.fDontBreakWrappedTables
= rIDSA
.get(DocumentSettingId::DO_NOT_BREAK_WRAPPED_TABLES
);
564 rDop
.Write( *rWrt
.m_pTableStrm
, *rWrt
.m_pFib
);
567 static int lcl_CmpBeginEndChars( const OUString
& rSWStr
,
568 const sal_Unicode
* pMSStr
, int nMSStrByteLen
)
570 nMSStrByteLen
/= sizeof( sal_Unicode
);
571 if( nMSStrByteLen
> rSWStr
.getLength() )
572 nMSStrByteLen
= rSWStr
.getLength()+1;
573 nMSStrByteLen
*= sizeof( sal_Unicode
);
575 return memcmp( rSWStr
.getStr(), pMSStr
, nMSStrByteLen
);
579 Converts the OOo Asian Typography into a best fit match for Microsoft
580 Asian typography. This structure is actually dumped to disk within the
581 Dop Writer. Assumption is that rTypo is cleared to 0 on entry
583 void WW8Export::ExportDopTypography(WW8DopTypography
&rTypo
)
585 static const sal_Unicode aLangNotBegin
[4][WW8DopTypography::nMaxFollowing
]=
589 0x0021, 0x0025, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f,
590 0x005d, 0x007d, 0x00a2, 0x00b0, 0x2019, 0x201d, 0x2030, 0x2032,
591 0x2033, 0x2103, 0x3001, 0x3002, 0x3005, 0x3009, 0x300b, 0x300d,
592 0x300f, 0x3011, 0x3015, 0x3041, 0x3043, 0x3045, 0x3047, 0x3049,
593 0x3063, 0x3083, 0x3085, 0x3087, 0x308e, 0x309b, 0x309c, 0x309d,
594 0x309e, 0x30a1, 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30c3, 0x30e3,
595 0x30e5, 0x30e7, 0x30ee, 0x30f5, 0x30f6, 0x30fb, 0x30fc, 0x30fd,
596 0x30fe, 0xff01, 0xff05, 0xff09, 0xff0c, 0xff0e, 0xff1a, 0xff1b,
597 0xff1f, 0xff3d, 0xff5d, 0xff61, 0xff63, 0xff64, 0xff65, 0xff67,
598 0xff68, 0xff69, 0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f,
599 0xff70, 0xff9e, 0xff9f, 0xffe0
603 0x0021, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f, 0x005d,
604 0x007d, 0x00a8, 0x00b7, 0x02c7, 0x02c9, 0x2015, 0x2016, 0x2019,
605 0x201d, 0x2026, 0x2236, 0x3001, 0x3002, 0x3003, 0x3005, 0x3009,
606 0x300b, 0x300d, 0x300f, 0x3011, 0x3015, 0x3017, 0xff01, 0xff02,
607 0xff07, 0xff09, 0xff0c, 0xff0e, 0xff1a, 0xff1b, 0xff1f, 0xff3d,
608 0xff40, 0xff5c, 0xff5d, 0xff5e, 0xffe0
612 0x0021, 0x0025, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f,
613 0x005d, 0x007d, 0x00a2, 0x00b0, 0x2019, 0x201d, 0x2032, 0x2033,
614 0x2103, 0x3009, 0x300b, 0x300d, 0x300f, 0x3011, 0x3015, 0xff01,
615 0xff05, 0xff09, 0xff0c, 0xff0e, 0xff1a, 0xff1b, 0xff1f, 0xff3d,
618 //Traditional Chinese
620 0x0021, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f, 0x005d,
621 0x007d, 0x00a2, 0x00b7, 0x2013, 0x2014, 0x2019, 0x201d, 0x2022,
622 0x2025, 0x2026, 0x2027, 0x2032, 0x2574, 0x3001, 0x3002, 0x3009,
623 0x300b, 0x300d, 0x300f, 0x3011, 0x3015, 0x301e, 0xfe30, 0xfe31,
624 0xfe33, 0xfe34, 0xfe36, 0xfe38, 0xfe3a, 0xfe3c, 0xfe3e, 0xfe40,
625 0xfe42, 0xfe44, 0xfe4f, 0xfe50, 0xfe51, 0xfe52, 0xfe54, 0xfe55,
626 0xfe56, 0xfe57, 0xfe5a, 0xfe5c, 0xfe5e, 0xff01, 0xff09, 0xff0c,
627 0xff0e, 0xff1a, 0xff1b, 0xff1f, 0xff5c, 0xff5d, 0xff64
631 static const sal_Unicode aLangNotEnd
[4][WW8DopTypography::nMaxLeading
] =
635 0x0024, 0x0028, 0x005b, 0x005c, 0x007b, 0x00a3, 0x00a5, 0x2018,
636 0x201c, 0x3008, 0x300a, 0x300c, 0x300e, 0x3010, 0x3014, 0xff04,
637 0xff08, 0xff3b, 0xff5b, 0xff62, 0xffe1, 0xffe5
641 0x0028, 0x005b, 0x007b, 0x00b7, 0x2018, 0x201c, 0x3008, 0x300a,
642 0x300c, 0x300e, 0x3010, 0x3014, 0x3016, 0xff08, 0xff0e, 0xff3b,
643 0xff5b, 0xffe1, 0xffe5
647 0x0028, 0x005b, 0x005c, 0x007b, 0x00a3, 0x00a5, 0x2018, 0x201c,
648 0x3008, 0x300a, 0x300c, 0x300e, 0x3010, 0x3014, 0xff04, 0xff08,
649 0xff3b, 0xff5b, 0xffe6
651 //Traditional Chinese
653 0x0028, 0x005b, 0x007b, 0x00a3, 0x00a5, 0x2018, 0x201c, 0x2035,
654 0x3008, 0x300a, 0x300c, 0x300e, 0x3010, 0x3014, 0x301d, 0xfe35,
655 0xfe37, 0xfe39, 0xfe3b, 0xfe3d, 0xfe3f, 0xfe41, 0xfe43, 0xfe59,
656 0xfe5b, 0xfe5d, 0xff08, 0xff5b
660 const i18n::ForbiddenCharacters
*pForbidden
= nullptr;
661 const i18n::ForbiddenCharacters
*pUseMe
= nullptr;
662 sal_uInt8 nUseReserved
=0;
665 Now we have some minor difficult issues, to wit...
666 a. MicroSoft Office can only store one set of begin and end characters in
667 a given document, not one per language.
668 b. StarOffice has only a concept of one set of begin and end characters for
669 a given language, i.e. not the two levels of kinsoku in japanese
671 What is unknown as yet is if our default begin and end chars for
672 japanese, chinese tradition, chinese simplified and korean are different
673 in Word and Writer. I already suspect that they are different between
674 different version of word itself.
676 So what have come up with is to simply see if any of the four languages
677 in OOo have been changed away from OUR defaults, and if one has then
678 export that. If more than one has in the future we may hack in something
679 which examines our document properties to see which language is used the
680 most and choose that, for now we choose the first and throw an ASSERT
683 /*Our default Japanese Level is 2, this is a special MS hack to set this*/
684 rTypo
.m_reserved2
= 1;
686 for (rTypo
.m_reserved1
=8;rTypo
.m_reserved1
>0;rTypo
.m_reserved1
-=2)
688 pForbidden
= m_rDoc
.getIDocumentSettingAccess().getForbiddenCharacters(rTypo
.GetConvertedLang(),
690 if (nullptr != pForbidden
)
692 int nIdx
= (rTypo
.m_reserved1
-2)/2;
693 if( lcl_CmpBeginEndChars( pForbidden
->endLine
,
694 aLangNotEnd
[ nIdx
], sizeof(aLangNotEnd
[ nIdx
]) ) ||
695 lcl_CmpBeginEndChars( pForbidden
->beginLine
,
696 aLangNotBegin
[ nIdx
], sizeof(aLangNotBegin
[ nIdx
]) ) )
698 //One exception for Japanese, if it matches a level 1 we
699 //can use one extra flag for that, rather than use a custom
700 if (rTypo
.GetConvertedLang() == LANGUAGE_JAPANESE
)
703 !lcl_CmpBeginEndChars
706 OUString(WW8DopTypography::JapanNotEndLevel1
).getStr(),
707 WW8DopTypography::nMaxLeading
* sizeof(sal_Unicode
)
710 !lcl_CmpBeginEndChars
712 pForbidden
->beginLine
,
713 OUString(WW8DopTypography::JapanNotBeginLevel1
).getStr(),
714 WW8DopTypography::nMaxFollowing
* sizeof(sal_Unicode
)
718 rTypo
.m_reserved2
= 0;
726 nUseReserved
= rTypo
.m_reserved1
;
727 rTypo
.m_iLevelOfKinsoku
= 2;
734 OSL_ENSURE( nNoNeeded
<=1, "Example of unexportable forbidden chars" );
735 rTypo
.m_reserved1
=nUseReserved
;
736 if (rTypo
.m_iLevelOfKinsoku
&& pUseMe
)
738 rTypo
.m_cchFollowingPunct
= msword_cast
<sal_Int16
>
739 (pUseMe
->beginLine
.getLength());
740 if (rTypo
.m_cchFollowingPunct
> WW8DopTypography::nMaxFollowing
- 1)
741 rTypo
.m_cchFollowingPunct
= WW8DopTypography::nMaxFollowing
- 1;
743 rTypo
.m_cchLeadingPunct
= msword_cast
<sal_Int16
>
744 (pUseMe
->endLine
.getLength());
745 if (rTypo
.m_cchLeadingPunct
> WW8DopTypography::nMaxLeading
- 1)
746 rTypo
.m_cchLeadingPunct
= WW8DopTypography::nMaxLeading
-1;
748 memcpy(rTypo
.m_rgxchFPunct
,pUseMe
->beginLine
.getStr(),
749 (rTypo
.m_cchFollowingPunct
+1)*2);
751 memcpy(rTypo
.m_rgxchLPunct
,pUseMe
->endLine
.getStr(),
752 (rTypo
.m_cchLeadingPunct
+1)*2);
755 const IDocumentSettingAccess
& rIDocumentSettingAccess
= GetWriter().getIDocumentSettingAccess();
757 rTypo
.m_fKerningPunct
= sal_uInt16(rIDocumentSettingAccess
.get(DocumentSettingId::KERN_ASIAN_PUNCTUATION
));
758 rTypo
.m_iJustification
= sal_uInt16(m_rDoc
.getIDocumentSettingAccess().getCharacterCompressionType());
761 // It can only be found something with this method, if it is used within
762 // WW8_SwAttrIter::OutAttr() and WW8Export::OutputItemSet()
763 const SfxPoolItem
* MSWordExportBase::HasItem( sal_uInt16 nWhich
) const
765 const SfxPoolItem
* pItem
=nullptr;
768 // if write an EditEngine text, then the WhichIds are greater than
769 // our own Ids. So the Id have to translate from our into the
771 nWhich
= sw::hack::GetSetWhichFromSwDocWhich(*m_pISet
, m_rDoc
, nWhich
);
772 if (nWhich
&& SfxItemState::SET
!= m_pISet
->GetItemState(nWhich
, true, &pItem
))
775 else if( m_pChpIter
)
776 pItem
= m_pChpIter
->HasTextItem( nWhich
);
779 OSL_ENSURE( false, "Where is my ItemSet / pChpIter ?" );
785 const SfxPoolItem
& MSWordExportBase::GetItem(sal_uInt16 nWhich
) const
787 assert((m_pISet
|| m_pChpIter
) && "Where is my ItemSet / pChpIter ?");
790 // if write an EditEngine text, then the WhichIds are greater than
791 // our own Ids. So the Id have to translate from our into the
793 nWhich
= sw::hack::GetSetWhichFromSwDocWhich(*m_pISet
, m_rDoc
, nWhich
);
794 OSL_ENSURE(nWhich
!= 0, "All broken, Impossible");
795 return m_pISet
->Get(nWhich
);
797 return m_pChpIter
->GetItem( nWhich
);
800 WW8_WrPlc1::WW8_WrPlc1( sal_uInt16 nStructSz
)
801 : m_pData( new sal_uInt8
[ 16 * nStructSz
] ),
802 m_nDataLen(16 * nStructSz
),
803 m_nStructSiz( nStructSz
)
807 WW8_WrPlc1::~WW8_WrPlc1()
811 WW8_CP
WW8_WrPlc1::Prev() const
813 bool b
= !m_aPos
.empty();
814 OSL_ENSURE(b
,"Prev called on empty list");
815 return b
? m_aPos
.back() : 0;
818 void WW8_WrPlc1::Append( WW8_CP nCp
, const void* pNewData
)
820 sal_uLong nInsPos
= m_aPos
.size() * m_nStructSiz
;
821 m_aPos
.push_back( nCp
);
822 if( m_nDataLen
< nInsPos
+ m_nStructSiz
)
824 sal_uInt8
* pNew
= new sal_uInt8
[ 2 * m_nDataLen
];
825 memcpy( pNew
, m_pData
.get(), m_nDataLen
);
829 memcpy( m_pData
.get() + nInsPos
, pNewData
, m_nStructSiz
);
832 void WW8_WrPlc1::Finish( sal_uLong nLastCp
, sal_uLong nSttCp
)
834 if( !m_aPos
.empty() )
836 m_aPos
.push_back( nLastCp
);
838 for(WW8_CP
& rCp
: m_aPos
)
843 void WW8_WrPlc1::Write( SvStream
& rStrm
)
845 decltype(m_aPos
)::size_type i
;
846 for( i
= 0; i
< m_aPos
.size(); ++i
)
847 SwWW8Writer::WriteLong( rStrm
, m_aPos
[i
] );
849 rStrm
.WriteBytes(m_pData
.get(), (i
-1) * m_nStructSiz
);
852 // Class WW8_WrPlcField for fields
854 void WW8_WrPlcField::Write( WW8Export
& rWrt
)
856 if( WW8_WrPlc1::Count() <= 1 )
864 pfc
= &rWrt
.m_pFib
->m_fcPlcffldMom
;
865 plc
= &rWrt
.m_pFib
->m_lcbPlcffldMom
;
868 pfc
= &rWrt
.m_pFib
->m_fcPlcffldHdr
;
869 plc
= &rWrt
.m_pFib
->m_lcbPlcffldHdr
;
873 pfc
= &rWrt
.m_pFib
->m_fcPlcffldFootnote
;
874 plc
= &rWrt
.m_pFib
->m_lcbPlcffldFootnote
;
878 pfc
= &rWrt
.m_pFib
->m_fcPlcffldEdn
;
879 plc
= &rWrt
.m_pFib
->m_lcbPlcffldEdn
;
883 pfc
= &rWrt
.m_pFib
->m_fcPlcffldAtn
;
884 plc
= &rWrt
.m_pFib
->m_lcbPlcffldAtn
;
888 pfc
= &rWrt
.m_pFib
->m_fcPlcffldTxbx
;
889 plc
= &rWrt
.m_pFib
->m_lcbPlcffldTxbx
;
893 pfc
= &rWrt
.m_pFib
->m_fcPlcffldHdrTxbx
;
894 plc
= &rWrt
.m_pFib
->m_lcbPlcffldHdrTxbx
;
904 sal_uInt64 nFcStart
= rWrt
.m_pTableStrm
->Tell();
905 WW8_WrPlc1::Write( *rWrt
.m_pTableStrm
);
907 *plc
= rWrt
.m_pTableStrm
->Tell() - nFcStart
;
911 void WW8_WrMagicTable::Write( WW8Export
& rWrt
)
913 if( WW8_WrPlc1::Count() <= 1 )
915 sal_uInt64 nFcStart
= rWrt
.m_pTableStrm
->Tell();
916 WW8_WrPlc1::Write( *rWrt
.m_pTableStrm
);
917 rWrt
.m_pFib
->m_fcPlcfTch
= nFcStart
;
918 rWrt
.m_pFib
->m_lcbPlcfTch
= rWrt
.m_pTableStrm
->Tell() - nFcStart
;
921 void WW8_WrMagicTable::Append( WW8_CP nCp
, sal_uLong nData
)
924 Tell the undocumented table hack that everything between here and the last
925 table position is non-table text, don't do it if the previous position is
926 the same as this one, as that would be a region of 0 length
928 if ((!Count()) || (Prev() != nCp
))
931 UInt32ToSVBT32(nData
,nLittle
);
932 WW8_WrPlc1::Append(nCp
, nLittle
);
936 void SwWW8Writer::FillCount( SvStream
& rStrm
, sal_uLong nCount
)
938 static const sal_uInt32 aNulls
[16] =
940 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 // 64 Byte
945 rStrm
.WriteBytes(aNulls
, 64); // in steps of 64-Byte
948 rStrm
.WriteBytes(aNulls
, nCount
); // write the rest (0 .. 64 Bytes)
951 sal_uLong
SwWW8Writer::FillUntil( SvStream
& rStrm
, sal_uLong nEndPos
)
953 sal_uInt64 nCurPos
= rStrm
.Tell();
954 if( !nEndPos
) // nEndPos == 0 -> next Page
955 nEndPos
= (nCurPos
+ 0x1ff) & ~0x1ffUL
;
957 if( nEndPos
> nCurPos
)
958 SwWW8Writer::FillCount( rStrm
, nEndPos
- nCurPos
);
959 #if OSL_DEBUG_LEVEL > 0
961 OSL_ENSURE( nEndPos
== nCurPos
, "Wrong FillUntil()" );
966 WW8_WrPlcPn::WW8_WrPlcPn(WW8Export
& rWr
, ePLCFT ePl
, WW8_FC nStartFc
)
971 m_Fkps
.push_back(std::make_unique
<WW8_WrFkp
>(m_ePlc
, nStartFc
));
974 WW8_WrPlcPn::~WW8_WrPlcPn()
978 sal_uInt8
*WW8_WrPlcPn::CopyLastSprms(sal_uInt8
&rLen
)
980 WW8_WrFkp
& rF
= *m_Fkps
.back();
981 return rF
.CopyLastSprms(rLen
);
984 void WW8_WrPlcPn::AppendFkpEntry(WW8_FC nEndFc
,short nVarLen
,const sal_uInt8
* pSprms
)
986 WW8_WrFkp
* pF
= m_Fkps
.back().get();
988 // big sprm? build the sprmPHugePapx
989 sal_uInt8
* pNewSprms
= const_cast<sal_uInt8
*>(pSprms
);
990 sal_uInt8 aHugePapx
[ 8 ];
991 if (PAP
== m_ePlc
&& 488 <= nVarLen
)
993 sal_uInt8
* p
= aHugePapx
;
994 *p
++ = *pSprms
++; // set style Id
998 sal_uInt64 nDataPos
= m_rWrt
.m_pDataStrm
->Tell();
999 SwWW8Writer::WriteShort( *m_rWrt
.m_pDataStrm
, nVarLen
);
1000 m_rWrt
.m_pDataStrm
->WriteBytes(pSprms
, nVarLen
);
1002 Set_UInt16( p
, 0x6646 ); // set SprmCode
1003 Set_UInt32( p
, nDataPos
); // set startpos (FC) in the datastream
1004 nVarLen
= static_cast< short >(p
- aHugePapx
);
1005 pSprms
= pNewSprms
= aHugePapx
;
1007 // if append at the same FC-EndPos and there are sprms, then get the old
1008 // sprms and erase it; they will append now with the new sprms
1009 else if( nVarLen
&& pF
->IsEqualPos( nEndFc
))
1010 pF
->MergeToNew( nVarLen
, pNewSprms
);
1011 // has the prev EndFC an empty sprm and the current is empty too, then
1012 // expand only the old EndFc to the new EndFc
1013 else if( !nVarLen
&& pF
->IsEmptySprm() )
1015 pF
->SetNewEnd( nEndFc
);
1019 bool bOk
= pF
->Append(nEndFc
, nVarLen
, pNewSprms
);
1023 pF
= new WW8_WrFkp(m_ePlc
, pF
->GetEndFc()); // Start new Fkp == end of old Fkp
1025 m_Fkps
.push_back(std::unique_ptr
<WW8_WrFkp
>(pF
));
1026 if( !pF
->Append( nEndFc
, nVarLen
, pNewSprms
) )
1028 OSL_ENSURE( false, "Unable to insert Sprm" );
1031 if( pNewSprms
!= pSprms
) //Merge to new has created a new block
1035 void WW8_WrPlcPn::WriteFkps()
1037 m_nFkpStartPage
= o3tl::narrowing
<sal_uInt16
>( SwWW8Writer::FillUntil( m_rWrt
.Strm() ) >> 9 );
1039 for(const std::unique_ptr
<WW8_WrFkp
> & rp
: m_Fkps
)
1041 rp
->Write( m_rWrt
.Strm(), *m_rWrt
.m_pGrf
);
1046 m_rWrt
.m_pFib
->m_pnChpFirst
= m_nFkpStartPage
;
1047 m_rWrt
.m_pFib
->m_cpnBteChp
= m_Fkps
.size();
1051 m_rWrt
.m_pFib
->m_pnPapFirst
= m_nFkpStartPage
;
1052 m_rWrt
.m_pFib
->m_cpnBtePap
= m_Fkps
.size();
1056 void WW8_WrPlcPn::WritePlc()
1058 sal_uInt64 nFcStart
= m_rWrt
.m_pTableStrm
->Tell();
1059 decltype(m_Fkps
)::size_type i
;
1061 for (i
= 0; i
< m_Fkps
.size(); ++i
)
1063 SwWW8Writer::WriteLong( *m_rWrt
.m_pTableStrm
,
1064 m_Fkps
[ i
]->GetStartFc() );
1067 SwWW8Writer::WriteLong( *m_rWrt
.m_pTableStrm
,
1068 m_Fkps
[ i
- 1 ]->GetEndFc() );
1070 // for every FKP output the page
1071 for (i
= 0; i
< m_Fkps
.size(); ++i
)
1073 SwWW8Writer::WriteLong( *m_rWrt
.m_pTableStrm
, i
+ m_nFkpStartPage
);
1078 m_rWrt
.m_pFib
->m_fcPlcfbteChpx
= nFcStart
;
1079 m_rWrt
.m_pFib
->m_lcbPlcfbteChpx
= m_rWrt
.m_pTableStrm
->Tell() - nFcStart
;
1083 m_rWrt
.m_pFib
->m_fcPlcfbtePapx
= nFcStart
;
1084 m_rWrt
.m_pFib
->m_lcbPlcfbtePapx
= m_rWrt
.m_pTableStrm
->Tell() - nFcStart
;
1088 WW8_WrFkp::WW8_WrFkp(ePLCFT ePl
, WW8_FC nStartFc
)
1089 : m_ePlc(ePl
), m_nStartGrp(511), m_nOldStartGrp(511),
1090 m_nItemSize( ( CHP
== ePl
) ? 1 : 13 ),
1091 m_nIMax(0), m_nOldVarLen(0), m_bCombined(false)
1093 m_pFkp
= reinterpret_cast<sal_uInt8
*>(new sal_Int32
[128]); // 512 Byte
1094 m_pOfs
= reinterpret_cast<sal_uInt8
*>(new sal_Int32
[128]); // 512 Byte
1095 memset( m_pFkp
, 0, 4 * 128 );
1096 memset( m_pOfs
, 0, 4 * 128 );
1097 reinterpret_cast<sal_Int32
*>(m_pFkp
)[0] = nStartFc
; // 0th entry FC at nStartFc
1100 WW8_WrFkp::~WW8_WrFkp()
1102 delete[] reinterpret_cast<sal_Int32
*>(m_pFkp
);
1103 delete[] reinterpret_cast<sal_Int32
*>(m_pOfs
);
1106 sal_uInt8
WW8_WrFkp::SearchSameSprm( sal_uInt16 nVarLen
, const sal_uInt8
* pSprms
)
1110 // if the sprms contained picture-references then never equal!
1111 for( sal_uInt8 n
= static_cast< sal_uInt8
>(nVarLen
- 1); 3 < n
; --n
)
1112 if( pSprms
[ n
] == GRF_MAGIC_3
&&
1113 pSprms
[ n
-1 ] == GRF_MAGIC_2
&&
1114 pSprms
[ n
-2 ] == GRF_MAGIC_1
)
1119 for( i
= 0; i
< m_nIMax
; i
++ )
1121 sal_uInt8 nStart
= m_pOfs
[i
* m_nItemSize
];
1124 const sal_uInt8
* p
= m_pFkp
+ ( o3tl::narrowing
<sal_uInt16
>(nStart
) << 1 );
1127 : ((o3tl::narrowing
<sal_uInt16
>(*p
++) << 1 ) == (( nVarLen
+1) & 0xfffe)) )
1128 && !memcmp( p
, pSprms
, nVarLen
) )
1129 return nStart
; // found it
1132 return 0; // didn't found it
1135 sal_uInt8
*WW8_WrFkp::CopyLastSprms(sal_uInt8
&rLen
)
1138 sal_uInt8
*pStart
=nullptr,*pRet
=nullptr;
1143 pStart
= m_pFkp
+ ( m_nIMax
+ 1 ) * 4;
1145 sal_uInt8 nStart
= *(pStart
+ (m_nIMax
-1) * m_nItemSize
);
1147 const sal_uInt8
* p
= m_pFkp
+ ( o3tl::narrowing
<sal_uInt16
>(nStart
) << 1 );
1157 pRet
= new sal_uInt8
[rLen
];
1158 memcpy(pRet
,p
,rLen
);
1163 bool WW8_WrFkp::Append( WW8_FC nEndFc
, sal_uInt16 nVarLen
, const sal_uInt8
* pSprms
)
1165 assert((!nVarLen
|| pSprms
) && "Item pointer missing");
1167 OSL_ENSURE( nVarLen
< ( ( m_ePlc
== PAP
) ? 497U : 502U ), "Sprms too long !" );
1171 OSL_ENSURE( false, "Fkp::Append: Fkp is already combined" );
1174 sal_Int32 n
= reinterpret_cast<sal_Int32
*>(m_pFkp
)[m_nIMax
]; // last entry
1177 OSL_ENSURE( nEndFc
>= n
, "+Fkp: FC backwards" );
1178 OSL_ENSURE( !nVarLen
|| !pSprms
|| nEndFc
!= n
,
1179 "+Fkp: used same FC multiple times" );
1180 // same FC without Sprm is ignored without grumbling
1182 return true; // ignore (do not create a new Fkp)
1185 sal_uInt8 nOldP
= nVarLen
? SearchSameSprm( nVarLen
, pSprms
) : 0;
1186 // Combine equal entries
1187 short nOffset
=0, nPos
= m_nStartGrp
;
1188 if (nVarLen
&& !nOldP
)
1190 nPos
= PAP
== m_ePlc
1191 ? ( 13 == m_nItemSize
// HACK: PAP and bWrtWW8 !!
1192 ? (m_nStartGrp
& 0xFFFE ) - nVarLen
- 1
1193 : (m_nStartGrp
- (((nVarLen
+ 1) & 0xFFFE)+1)) & 0xFFFE )
1194 : ((m_nStartGrp
- nVarLen
- 1) & 0xFFFE);
1196 return false; // doesn't fit at all
1197 nOffset
= nPos
; // save offset (can also be uneven!)
1198 nPos
&= 0xFFFE; // Pos for Sprms ( gerade Pos )
1201 if( o3tl::make_unsigned(nPos
) <= ( m_nIMax
+ 2U ) * 4U + ( m_nIMax
+ 1U ) * m_nItemSize
)
1202 // does it fits after the CPs and offsets?
1205 reinterpret_cast<sal_Int32
*>(m_pFkp
)[m_nIMax
+ 1] = nEndFc
; // insert FC
1207 m_nOldVarLen
= static_cast<sal_uInt8
>(nVarLen
);
1208 if( nVarLen
&& !nOldP
)
1209 { // insert it for real
1210 m_nOldStartGrp
= m_nStartGrp
;
1213 m_pOfs
[m_nIMax
* m_nItemSize
] = static_cast<sal_uInt8
>( m_nStartGrp
>> 1 );
1214 // insert (start-of-data >> 1)
1215 sal_uInt8 nCnt
= static_cast< sal_uInt8
>(CHP
== m_ePlc
1216 ? ( nVarLen
< 256 ) ? static_cast<sal_uInt8
>(nVarLen
) : 255
1217 : ( ( nVarLen
+ 1 ) >> 1 ));
1219 m_pFkp
[ nOffset
] = nCnt
; // Enter data length
1220 memcpy( m_pFkp
+ nOffset
+ 1, pSprms
, nVarLen
); // store Sprms
1224 // do not enter for real ( no Sprms or recurrence )
1225 // start-of-data 0 ( no data ) or recurrence
1226 m_pOfs
[m_nIMax
* m_nItemSize
] = nOldP
;
1232 void WW8_WrFkp::Combine()
1237 memcpy( m_pFkp
+ ( m_nIMax
+ 1 ) * 4, m_pOfs
, m_nIMax
* m_nItemSize
);
1240 m_pFkp
[511] = m_nIMax
;
1243 #if defined OSL_BIGENDIAN // only the FCs will be rotated here
1244 sal_uInt16 i
; // the Sprms must be rotated elsewhere
1247 for( i
= 0, p
= (sal_uInt32
*)m_pFkp
; i
<= m_nIMax
; i
++, p
++ )
1248 *p
= OSL_SWAPDWORD( *p
);
1249 #endif // ifdef OSL_BIGENDIAN
1252 void WW8_WrFkp::Write( SvStream
& rStrm
, SwWW8WrGrf
& rGrf
)
1254 Combine(); // If not already combined
1256 sal_uInt8
* p
; // search magic for nPicLocFc
1257 sal_uInt8
* pEnd
= m_pFkp
+ m_nStartGrp
;
1258 for( p
= m_pFkp
+ 511 - 4; p
>= pEnd
; p
-- )
1260 if( *p
!= GRF_MAGIC_1
) // search for signature 0x12 0x34 0x56 0xXX
1262 if( *(p
+1) != GRF_MAGIC_2
)
1264 if( *(p
+2) != GRF_MAGIC_3
)
1267 SVBT32 nPos
; // signature found
1268 UInt32ToSVBT32( rGrf
.GetFPos(), nPos
); // FilePos the graphics
1269 memcpy( p
, nPos
, 4 ); // patch FilePos over the signature
1271 rStrm
.WriteBytes(m_pFkp
, 512);
1274 void WW8_WrFkp::MergeToNew( short& rVarLen
, sal_uInt8
*& rpNewSprms
)
1276 sal_uInt8 nStart
= m_pOfs
[ (m_nIMax
-1) * m_nItemSize
];
1281 sal_uInt8
* p
= m_pFkp
+ ( o3tl::narrowing
<sal_uInt16
>(nStart
) << 1 );
1283 // old and new equal? Then copy only one into the new sprms
1284 if( m_nOldVarLen
== rVarLen
&& !memcmp( p
+1, rpNewSprms
, m_nOldVarLen
))
1286 sal_uInt8
* pNew
= new sal_uInt8
[ m_nOldVarLen
];
1287 memcpy( pNew
, p
+1, m_nOldVarLen
);
1292 sal_uInt8
* pNew
= new sal_uInt8
[ m_nOldVarLen
+ rVarLen
];
1293 memcpy( pNew
, p
+1, m_nOldVarLen
);
1294 memcpy( pNew
+ m_nOldVarLen
, rpNewSprms
, rVarLen
);
1297 rVarLen
= rVarLen
+ m_nOldVarLen
;
1300 // if this Sprms don't used from others, remove it
1302 for (sal_uInt16 n
= 0; n
< m_nIMax
; ++n
)
1304 if (nStart
== m_pOfs
[n
* m_nItemSize
])
1312 m_nStartGrp
= m_nOldStartGrp
;
1313 memset( p
, 0, m_nOldVarLen
+1 );
1317 WW8_FC
WW8_WrFkp::GetStartFc() const
1319 // when bCombined, then the array beginning with pFkp is already byte-swapped
1320 // to LittleEndian, so to extract the start and end positions they must
1323 return SVBT32ToUInt32( m_pFkp
); // 0. Element
1324 return reinterpret_cast<sal_Int32
*>(m_pFkp
)[0];
1327 WW8_FC
WW8_WrFkp::GetEndFc() const
1330 return SVBT32ToUInt32( &(m_pFkp
[m_nIMax
*4]) ); // nIMax-th SVBT32-Element
1331 return reinterpret_cast<sal_Int32
*>(m_pFkp
)[m_nIMax
];
1334 // Method for managing the piece table
1335 WW8_WrPct::WW8_WrPct(WW8_FC nfcMin
)
1341 WW8_WrPct::~WW8_WrPct()
1345 // Fill the piece and create a new one
1346 void WW8_WrPct::AppendPc(WW8_FC nStartFc
)
1348 WW8_CP nStartCp
= nStartFc
- m_nOldFc
; // subtract the beginning of the text
1349 if ( !nStartCp
&& !m_Pcts
.empty())
1351 OSL_ENSURE(1 == m_Pcts
.size(), "empty Piece!");
1355 m_nOldFc
= nStartFc
; // remember StartFc as old
1357 nStartCp
>>= 1; // for Unicode: number of characters / 2
1359 if (!m_Pcts
.empty())
1361 nStartCp
+= m_Pcts
.back()->GetStartCp();
1364 m_Pcts
.push_back(std::make_unique
<WW8_WrPc
>(nStartFc
, nStartCp
));
1367 void WW8_WrPct::WritePc( WW8Export
& rWrt
)
1369 sal_uInt64 nPctStart
;
1370 sal_uLong nOldPos
, nEndPos
;
1372 nPctStart
= rWrt
.m_pTableStrm
->Tell(); // Start piece table
1373 rWrt
.m_pTableStrm
->WriteChar( char(0x02) ); // Status byte PCT
1374 nOldPos
= nPctStart
+ 1; // remember Position
1375 SwWW8Writer::WriteLong( *rWrt
.m_pTableStrm
, 0 ); // then the length
1377 for (auto const& it
: m_Pcts
) // ranges
1379 SwWW8Writer::WriteLong( *rWrt
.m_pTableStrm
, it
->GetStartCp() );
1382 // calculate the last Pos
1383 sal_uLong nStartCp
= rWrt
.m_pFib
->m_fcMac
- m_nOldFc
;
1384 nStartCp
>>= 1; // For Unicode: number of characters / 2
1385 nStartCp
+= m_Pcts
.back()->GetStartCp();
1386 SwWW8Writer::WriteLong( *rWrt
.m_pTableStrm
, nStartCp
);
1389 for (auto const& it
: m_Pcts
)
1391 SwWW8Writer::WriteShort(*rWrt
.m_pTableStrm
, it
->GetStatus());
1392 SwWW8Writer::WriteLong(*rWrt
.m_pTableStrm
, it
->GetStartFc());
1393 SwWW8Writer::WriteShort( *rWrt
.m_pTableStrm
, 0); // PRM=0
1396 // entries in the FIB
1397 rWrt
.m_pFib
->m_fcClx
= nPctStart
;
1398 nEndPos
= rWrt
.m_pTableStrm
->Tell();
1399 rWrt
.m_pFib
->m_lcbClx
= nEndPos
- nPctStart
;
1401 // and register the length as well
1402 SwWW8Writer::WriteLong( *rWrt
.m_pTableStrm
, nOldPos
,
1403 nEndPos
- nPctStart
-5 );
1407 void WW8_WrPct::SetParaBreak()
1409 OSL_ENSURE( !m_Pcts
.empty(), "SetParaBreak : m_Pcts.empty()" );
1410 m_Pcts
.back()->SetStatus();
1413 WW8_CP
WW8_WrPct::Fc2Cp( sal_uLong nFc
) const
1415 OSL_ENSURE( nFc
>= o3tl::make_unsigned(m_nOldFc
), "FilePos lies in front of last piece" );
1416 OSL_ENSURE( ! m_Pcts
.empty(), "Fc2Cp no piece available" );
1419 nFc
/= 2; // Unicode
1420 return nFc
+ m_Pcts
.back()->GetStartCp();
1423 void WW8Export::AppendBookmarks( const SwTextNode
& rNd
, sal_Int32 nCurrentPos
, sal_Int32 nLen
, const SwRedlineData
* /*pRedlineData*/ )
1425 std::vector
< const ::sw::mark::IMark
* > aArr
;
1427 const sal_Int32 nCurrentEnd
= nCurrentPos
+ nLen
;
1428 if( !GetWriter().GetBookmarks( rNd
, nCurrentPos
, nCurrentEnd
, aArr
))
1431 SwNodeOffset nNd
= rNd
.GetIndex();
1432 sal_uLong nSttCP
= Fc2Cp( Strm().Tell() );
1433 for(const ::sw::mark::IMark
* p
: aArr
)
1435 const ::sw::mark::IMark
& rBkmk
= *p
;
1436 if(dynamic_cast< const ::sw::mark::IFieldmark
*>(&rBkmk
))
1439 const SwPosition
* pPos
= &rBkmk
.GetMarkPos();
1440 const SwPosition
* pOPos
= nullptr;
1441 if(rBkmk
.IsExpanded())
1442 pOPos
= &rBkmk
.GetOtherMarkPos();
1443 if( pOPos
&& pOPos
->GetNode() == pPos
->GetNode() &&
1444 pOPos
->GetContentIndex() < pPos
->GetContentIndex() )
1447 pOPos
= &rBkmk
.GetMarkPos();
1450 if( !pOPos
|| ( nNd
== pPos
->GetNodeIndex() &&
1451 ( nContent
= pPos
->GetContentIndex() ) >= nCurrentPos
&&
1452 nContent
< nCurrentEnd
) )
1454 sal_uLong nCp
= nSttCP
+ pPos
->GetContentIndex() - nCurrentPos
;
1455 m_pBkmks
->Append(nCp
, BookmarkToWord(rBkmk
.GetName()));
1457 if( pOPos
&& nNd
== pOPos
->GetNodeIndex() &&
1458 ( nContent
= pOPos
->GetContentIndex() ) >= nCurrentPos
&&
1459 nContent
< nCurrentEnd
)
1461 sal_uLong nCp
= nSttCP
+ pOPos
->GetContentIndex() - nCurrentPos
;
1462 m_pBkmks
->Append(nCp
, BookmarkToWord(rBkmk
.GetName()));
1467 void WW8Export::AppendAnnotationMarks(const SwWW8AttrIter
& rAttrs
, sal_Int32 nCurrentPos
, sal_Int32 nLen
)
1470 if (GetAnnotationMarks(rAttrs
, nCurrentPos
, nCurrentPos
+ nLen
, aMarks
))
1472 for (const sw::mark::IMark
* pMark
: aMarks
)
1474 const sal_Int32 nStart
= pMark
->GetMarkStart().GetContentIndex();
1475 if (nStart
== nCurrentPos
)
1477 m_pAtn
->AddRangeStartPosition(pMark
->GetName(), Fc2Cp(Strm().Tell()),
1478 !rAttrs
.HasFlysAt(nCurrentPos
));
1484 void WW8Export::AppendSmartTags(SwTextNode
& rTextNode
)
1486 std::map
<OUString
, OUString
> aStatements
= SwRDFHelper::getTextNodeStatements("urn:bails", rTextNode
);
1487 if (!aStatements
.empty())
1489 WW8_CP nCP
= Fc2Cp(Strm().Tell());
1490 m_pFactoids
->Append(nCP
, nCP
, aStatements
);
1494 void WW8Export::MoveFieldMarks(WW8_CP nFrom
, WW8_CP nTo
)
1496 m_pBkmks
->MoveFieldMarks(nFrom
, nTo
);
1499 void WW8Export::AppendBookmark( const OUString
& rName
)
1501 sal_uInt64 nSttCP
= Fc2Cp( Strm().Tell() );
1502 m_pBkmks
->Append( nSttCP
, rName
);
1505 void WW8Export::AppendBookmarkEndWithCorrection( const OUString
& rName
)
1507 sal_uInt64 nEndCP
= Fc2Cp( Strm().Tell() );
1508 m_pBkmks
->Append( nEndCP
- 1, rName
);
1511 std::unique_ptr
<SvxBrushItem
> MSWordExportBase::getBackground()
1513 const SwFrameFormat
&rFormat
= m_rDoc
.GetPageDesc(0).GetMaster();
1514 std::unique_ptr
<SvxBrushItem
> aBrush
= std::make_unique
<SvxBrushItem
>(RES_BACKGROUND
);
1515 SfxItemState eState
= rFormat
.GetBackgroundState(aBrush
);
1517 if (SfxItemState::SET
== eState
)
1519 // The 'color' is set for the first page style - take it and use it as the background color of the entire DOCX
1520 if (aBrush
->GetColor() != COL_AUTO
)
1526 // #i120928 collect all the graphics of bullets applied to paragraphs
1527 int MSWordExportBase::CollectGrfsOfBullets()
1529 m_vecBulletPic
.clear();
1531 size_t nCountRule
= m_rDoc
.GetNumRuleTable().size();
1532 for (size_t n
= 0; n
< nCountRule
; ++n
)
1534 const SwNumRule
&rRule
= *( m_rDoc
.GetNumRuleTable().at(n
) );
1535 sal_uInt16 nLevels
= rRule
.IsContinusNum() ? 1 : 9;
1536 for (sal_uInt16 nLvl
= 0; nLvl
< nLevels
; ++nLvl
)
1538 const SwNumFormat
&rFormat
= rRule
.Get(nLvl
);
1539 if (SVX_NUM_BITMAP
!= rFormat
.GetNumberingType())
1543 const Graphic
*pGraf
= rFormat
.GetBrush()? rFormat
.GetBrush()->GetGraphic():nullptr;
1547 for (const Graphic
* p
: m_vecBulletPic
)
1549 if (p
->GetChecksum() == pGraf
->GetChecksum())
1557 Size
aSize(pGraf
->GetPrefSize());
1558 if (0 != aSize
.Height() && 0 != aSize
.Width())
1559 m_vecBulletPic
.push_back(pGraf
);
1565 return m_vecBulletPic
.size();
1568 void MSWordExportBase::BulletDefinitions()
1570 for (size_t i
= 0; i
< m_vecBulletPic
.size(); ++i
)
1572 const MapMode
aMapMode(MapUnit::MapTwip
);
1573 const Graphic
& rGraphic
= *m_vecBulletPic
[i
];
1574 Size
aSize(rGraphic
.GetPrefSize());
1575 if (MapUnit::MapPixel
== rGraphic
.GetPrefMapMode().GetMapUnit())
1576 aSize
= Application::GetDefaultDevice()->PixelToLogic(aSize
, aMapMode
);
1578 aSize
= OutputDevice::LogicToLogic(aSize
,rGraphic
.GetPrefMapMode(), aMapMode
);
1580 if (0 != aSize
.Height() && 0 != aSize
.Width())
1581 AttrOutput().BulletDefinition(i
, rGraphic
, aSize
);
1585 //Export Graphic of Bullets
1586 void WW8Export::ExportGrfBullet(const SwTextNode
& rNd
)
1588 int nCount
= CollectGrfsOfBullets();
1591 SwPosition
aPos(rNd
);
1592 OUString
aPicBullets("_PictureBullets");
1593 AppendBookmark(aPicBullets
);
1594 for (int i
= 0; i
< nCount
; i
++)
1596 ww8::Frame
aFrame(*(m_vecBulletPic
[i
]), aPos
);
1597 OutGrfBullets(aFrame
);
1599 AppendBookmark(aPicBullets
);
1603 static sal_uInt8 nAttrMagicIdx
= 0;
1604 void WW8Export::OutGrfBullets(const ww8::Frame
& rFrame
)
1606 if ( !m_pGrf
|| !m_pChpPlc
|| !m_pO
)
1609 m_pGrf
->Insert(rFrame
);
1610 m_pChpPlc
->AppendFkpEntry( Strm().Tell(), m_pO
->size(), m_pO
->data() );
1613 WriteChar( char(1) );
1615 sal_uInt8 aArr
[ 22 ];
1616 sal_uInt8
* pArr
= aArr
;
1619 Set_UInt16( pArr
, 0x855 );
1620 Set_UInt8( pArr
, 1 );
1622 Set_UInt16( pArr
, 0x083c );
1623 Set_UInt8( pArr
, 0x81 );
1626 Set_UInt16( pArr
, 0x6a03 );
1627 Set_UInt32( pArr
, GRF_MAGIC_321
);
1629 //extern nAttrMagicIdx;
1631 Set_UInt8( pArr
, nAttrMagicIdx
++ );
1632 m_pChpPlc
->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr
- aArr
), aArr
);
1635 int MSWordExportBase::GetGrfIndex(const SvxBrushItem
& rBrush
)
1639 const Graphic
* pGraphic
= rBrush
.GetGraphic();
1642 for (size_t i
= 0; i
< m_vecBulletPic
.size(); ++i
)
1644 if (m_vecBulletPic
[i
]->GetChecksum() == pGraphic
->GetChecksum())
1655 void WW8_WrtRedlineAuthor::Write( Writer
& rWrt
)
1657 WW8Export
& rWW8Wrt
= *(static_cast<SwWW8Writer
&>(rWrt
).m_pExport
);
1658 rWW8Wrt
.WriteAsStringTable(maAuthors
, rWW8Wrt
.m_pFib
->m_fcSttbfRMark
,
1659 rWW8Wrt
.m_pFib
->m_lcbSttbfRMark
);
1662 sal_uInt16
WW8Export::AddRedlineAuthor( std::size_t nId
)
1664 if( !m_pRedlAuthors
)
1666 m_pRedlAuthors
.reset(new WW8_WrtRedlineAuthor
);
1667 m_pRedlAuthors
->AddName("Unknown");
1669 return m_pRedlAuthors
->AddName( SW_MOD()->GetRedlineAuthor( nId
) );
1672 void WW8Export::WriteAsStringTable(const std::vector
<OUString
>& rStrings
,
1673 sal_Int32
& rfcSttbf
, sal_Int32
& rlcbSttbf
)
1675 sal_uInt16 n
, nCount
= static_cast< sal_uInt16
>(rStrings
.size());
1679 // we have some Redlines found in the document -> the
1680 // Author Name Stringtable
1681 SvStream
& rStrm
= *m_pTableStrm
;
1682 rfcSttbf
= rStrm
.Tell();
1683 SwWW8Writer::WriteShort( rStrm
, -1 );
1684 SwWW8Writer::WriteLong( rStrm
, nCount
);
1685 for( n
= 0; n
< nCount
; ++n
)
1687 const OUString
& rNm
= rStrings
[n
];
1688 SwWW8Writer::WriteShort( rStrm
, rNm
.getLength() );
1689 SwWW8Writer::WriteString16(rStrm
, rNm
, false);
1691 rlcbSttbf
= rStrm
.Tell() - rfcSttbf
;
1694 // WriteShort() sets at FilePos nPos the value nVal and seeks to the old
1695 // FilePos. Used to insert lengths after the fact.
1696 void SwWW8Writer::WriteShort( SvStream
& rStrm
, sal_uLong nPos
, sal_Int16 nVal
)
1698 sal_uInt64 nOldPos
= rStrm
.Tell(); // remember Pos
1700 SwWW8Writer::WriteShort( rStrm
, nVal
);
1701 rStrm
.Seek( nOldPos
);
1704 void SwWW8Writer::WriteLong( SvStream
& rStrm
, sal_uLong nPos
, sal_Int32 nVal
)
1706 sal_uInt64 nOldPos
= rStrm
.Tell(); // remember Pos
1708 SwWW8Writer::WriteLong( rStrm
, nVal
);
1709 rStrm
.Seek( nOldPos
);
1712 void SwWW8Writer::InsUInt16(ww::bytes
&rO
, sal_uInt16 n
)
1715 ShortToSVBT16( n
, nL
);
1716 rO
.push_back(nL
[0]);
1717 rO
.push_back(nL
[1]);
1720 void SwWW8Writer::InsUInt32(ww::bytes
&rO
, sal_uInt32 n
)
1723 UInt32ToSVBT32( n
, nL
);
1724 rO
.push_back(nL
[0]);
1725 rO
.push_back(nL
[1]);
1726 rO
.push_back(nL
[2]);
1727 rO
.push_back(nL
[3]);
1730 void SwWW8Writer::InsAsString16(ww::bytes
&rO
, const OUString
& rStr
)
1732 const sal_Unicode
* pStr
= rStr
.getStr();
1733 for (sal_Int32 n
= 0, nLen
= rStr
.getLength(); n
< nLen
; ++n
, ++pStr
)
1734 SwWW8Writer::InsUInt16( rO
, *pStr
);
1737 void SwWW8Writer::InsAsString8(ww::bytes
&rO
, std::u16string_view rStr
,
1738 rtl_TextEncoding eCodeSet
)
1740 OString
sTmp(OUStringToOString(rStr
, eCodeSet
));
1741 const char *pStart
= sTmp
.getStr();
1742 const char *pEnd
= pStart
+ sTmp
.getLength();
1744 rO
.insert( rO
.end(), pStart
, pEnd
);
1747 void SwWW8Writer::WriteString16(SvStream
& rStrm
, const OUString
& rStr
,
1751 SwWW8Writer::InsAsString16(aBytes
, rStr
);
1753 SwWW8Writer::InsUInt16(aBytes
, 0);
1754 //vectors are guaranteed to have contiguous memory, so we can do
1755 //this while migrating away from WW8Bytes. Meyers Effective STL, item 16
1756 if (!aBytes
.empty())
1757 rStrm
.WriteBytes(aBytes
.data(), aBytes
.size());
1760 void SwWW8Writer::WriteString_xstz(SvStream
& rStrm
, const OUString
& rStr
, bool bAddZero
)
1763 SwWW8Writer::InsUInt16(aBytes
, rStr
.getLength());
1764 SwWW8Writer::InsAsString16(aBytes
, rStr
);
1766 SwWW8Writer::InsUInt16(aBytes
, 0);
1767 rStrm
.WriteBytes(aBytes
.data(), aBytes
.size());
1770 void SwWW8Writer::WriteString8(SvStream
& rStrm
, std::u16string_view rStr
,
1771 bool bAddZero
, rtl_TextEncoding eCodeSet
)
1774 SwWW8Writer::InsAsString8(aBytes
, rStr
, eCodeSet
);
1776 aBytes
.push_back(0);
1777 //vectors are guaranteed to have contiguous memory, so we can do
1778 ////this while migrating away from WW8Bytes. Meyers Effective STL, item 16
1779 if (!aBytes
.empty())
1780 rStrm
.WriteBytes(aBytes
.data(), aBytes
.size());
1783 void WW8Export::WriteStringAsPara( const OUString
& rText
)
1785 if( !rText
.isEmpty() )
1786 OutSwString(rText
, 0, rText
.getLength());
1787 WriteCR(); // CR thereafter
1790 SwWW8Writer::InsUInt16( aArr
, 0/*nStyleId*/ );
1794 SwWW8Writer::InsUInt16( aArr
, NS_sprm::PFInTable::val
);
1795 aArr
.push_back( 1 );
1798 sal_uInt64 nPos
= Strm().Tell();
1799 m_pPapPlc
->AppendFkpEntry( nPos
, aArr
.size(), aArr
.data() );
1800 m_pChpPlc
->AppendFkpEntry( nPos
);
1803 void MSWordExportBase::WriteSpecialText( SwNodeOffset nStart
, SwNodeOffset nEnd
, sal_uInt8 nTTyp
)
1805 sal_uInt8 nOldTyp
= m_nTextTyp
;
1807 auto const pOldPam
= m_pCurPam
; //!! Simply shifting the PaM without restoring should do the job too
1808 SwNodeOffset nOldStart
= m_nCurStart
;
1809 SwNodeOffset nOldEnd
= m_nCurEnd
;
1810 SwPaM
* pOldEnd
= m_pOrigPam
;
1811 bool bOldPageDescs
= m_bOutPageDescs
;
1812 m_bOutPageDescs
= false;
1813 if ( nTTyp
== TXT_FTN
|| nTTyp
== TXT_EDN
)
1814 m_bAddFootnoteTab
= true; // enable one aesthetic tab for this footnote
1816 SetCurPam(nStart
, nEnd
);
1818 // clear linked textboxes since old ones can't be linked to frames in this section
1819 m_aLinkedTextboxesHelper
.clear();
1821 // tdf#106261 Reset table infos, otherwise the depth of the cells will be
1822 // incorrect, in case the header/footer had table(s) and we try to export
1823 // the same table second time.
1824 ww8::WW8TableInfo::Pointer_t pOldTableInfo
= m_pTableInfo
;
1825 m_pTableInfo
= std::make_shared
<ww8::WW8TableInfo
>();
1829 m_pTableInfo
= pOldTableInfo
;
1831 m_bOutPageDescs
= bOldPageDescs
;
1832 m_pCurPam
= pOldPam
; // delete Pam
1833 m_nCurStart
= nOldStart
;
1834 m_nCurEnd
= nOldEnd
;
1835 m_pOrigPam
= pOldEnd
;
1836 m_nTextTyp
= nOldTyp
;
1839 void WW8Export::OutSwString(const OUString
& rStr
, sal_Int32 nStt
,
1840 sal_Int32
const nLen
)
1843 SAL_INFO( "sw.ww8.level2", "<OutSwString>" );
1847 if( nStt
|| nLen
!= rStr
.getLength() )
1849 OUString
sOut( rStr
.copy( nStt
, nLen
) );
1851 SAL_INFO( "sw.ww8.level2", sOut
);
1853 SwWW8Writer::WriteString16(Strm(), sOut
, false);
1857 SAL_INFO( "sw.ww8.level2", rStr
);
1859 SwWW8Writer::WriteString16(Strm(), rStr
, false);
1863 SAL_INFO( "sw.ww8.level2", "</OutSwString>" );
1866 void WW8Export::WriteCR(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
1868 if (pTableTextNodeInfoInner
&& pTableTextNodeInfoInner
->getDepth() == 1 && pTableTextNodeInfoInner
->isEndOfCell())
1871 WriteChar( '\015' );
1873 m_pPiece
->SetParaBreak();
1876 void WW8Export::WriteChar( sal_Unicode c
)
1878 Strm().WriteUInt16( c
);
1881 void MSWordExportBase::SetCurPam(SwNodeOffset nStt
, SwNodeOffset nEnd
)
1885 m_pCurPam
= Writer::NewUnoCursor( m_rDoc
, nStt
, nEnd
);
1887 // Recognize tables in special cases
1888 if ( nStt
!= m_pCurPam
->GetMark()->GetNodeIndex() &&
1889 m_rDoc
.GetNodes()[ nStt
]->IsTableNode() )
1891 m_pCurPam
->GetMark()->Assign(nStt
);
1894 m_pOrigPam
= m_pCurPam
.get(); // ???
1895 m_pCurPam
->Exchange();
1898 void MSWordExportBase::SaveData( SwNodeOffset nStt
, SwNodeOffset nEnd
)
1900 MSWordSaveData aData
;
1902 // WW8Export only stuff - zeroed here not to issue warnings
1903 aData
.pOOld
= nullptr;
1906 aData
.pOldPam
= m_pCurPam
;
1907 aData
.pOldEnd
= m_pOrigPam
;
1908 aData
.pOldFlyFormat
= m_pParentFrame
;
1909 aData
.pOldPageDesc
= m_pCurrentPageDesc
;
1911 aData
.pOldFlyOffset
= m_pFlyOffset
;
1912 aData
.eOldAnchorType
= m_eNewAnchorType
;
1914 aData
.bOldOutTable
= m_bOutTable
;
1915 aData
.bOldFlyFrameAttrs
= m_bOutFlyFrameAttrs
;
1916 aData
.bOldStartTOX
= m_bStartTOX
;
1917 aData
.bOldInWriteTOX
= m_bInWriteTOX
;
1919 SetCurPam(nStt
, nEnd
);
1921 m_bOutTable
= false;
1922 // Caution: bIsInTable should not be set here
1923 m_bOutFlyFrameAttrs
= false;
1924 m_bStartTOX
= false;
1925 m_bInWriteTOX
= false;
1927 m_aSaveData
.push( std::move(aData
) );
1930 void MSWordExportBase::RestoreData()
1932 MSWordSaveData
&rData
= m_aSaveData
.top();
1934 m_pCurPam
= rData
.pOldPam
;
1935 m_nCurStart
= rData
.nOldStart
;
1936 m_nCurEnd
= rData
.nOldEnd
;
1937 m_pOrigPam
= rData
.pOldEnd
;
1939 m_bOutTable
= rData
.bOldOutTable
;
1940 m_bOutFlyFrameAttrs
= rData
.bOldFlyFrameAttrs
;
1941 m_bStartTOX
= rData
.bOldStartTOX
;
1942 m_bInWriteTOX
= rData
.bOldInWriteTOX
;
1944 m_pParentFrame
= rData
.pOldFlyFormat
;
1945 m_pCurrentPageDesc
= rData
.pOldPageDesc
;
1947 m_eNewAnchorType
= rData
.eOldAnchorType
;
1948 m_pFlyOffset
= rData
.pOldFlyOffset
;
1953 void WW8Export::SaveData( SwNodeOffset nStt
, SwNodeOffset nEnd
)
1955 MSWordExportBase::SaveData( nStt
, nEnd
);
1957 MSWordSaveData
&rData
= m_aSaveData
.top();
1959 if ( !m_pO
->empty() )
1961 rData
.pOOld
= std::move(m_pO
);
1962 m_pO
.reset(new ww::bytes
);
1965 rData
.pOOld
= nullptr; // reuse pO
1967 rData
.bOldWriteAll
= GetWriter().m_bWriteAll
;
1968 GetWriter().m_bWriteAll
= true;
1971 void WW8Export::RestoreData()
1973 MSWordSaveData
&rData
= m_aSaveData
.top();
1975 GetWriter().m_bWriteAll
= rData
.bOldWriteAll
;
1977 OSL_ENSURE( m_pO
->empty(), "pO is not empty in WW8Export::RestoreData()" );
1980 m_pO
= std::move(rData
.pOOld
);
1983 MSWordExportBase::RestoreData();
1986 void WW8AttributeOutput::TableInfoCell( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
1988 sal_uInt32 nDepth
= pTableTextNodeInfoInner
->getDepth();
1994 m_rWW8Export
.InsUInt16( NS_sprm::PFInTable::val
);
1995 m_rWW8Export
.m_pO
->push_back( sal_uInt8(0x1) );
1996 m_rWW8Export
.InsUInt16( NS_sprm::PItap::val
);
1997 m_rWW8Export
.InsUInt32( nDepth
);
1999 if ( nDepth
> 1 && pTableTextNodeInfoInner
->isEndOfCell() )
2001 m_rWW8Export
.InsUInt16( NS_sprm::PFInnerTableCell::val
);
2002 m_rWW8Export
.m_pO
->push_back( sal_uInt8(0x1) );
2006 void WW8AttributeOutput::TableInfoRow( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2008 sal_uInt32 nDepth
= pTableTextNodeInfoInner
->getDepth();
2014 if ( !pTableTextNodeInfoInner
->isEndOfLine() )
2017 m_rWW8Export
.InsUInt16( NS_sprm::PFInTable::val
);
2018 m_rWW8Export
.m_pO
->push_back( sal_uInt8(0x1) );
2022 m_rWW8Export
.InsUInt16( NS_sprm::PFTtp::val
);
2023 m_rWW8Export
.m_pO
->push_back( sal_uInt8(0x1) );
2026 m_rWW8Export
.InsUInt16( NS_sprm::PItap::val
);
2027 m_rWW8Export
.InsUInt32( nDepth
);
2031 m_rWW8Export
.InsUInt16( NS_sprm::PFInnerTableCell::val
);
2032 m_rWW8Export
.m_pO
->push_back( sal_uInt8(0x1) );
2033 m_rWW8Export
.InsUInt16( NS_sprm::PFInnerTtp::val
);
2034 m_rWW8Export
.m_pO
->push_back( sal_uInt8(0x1) );
2037 // Most of these are per-row definitions, not per-table.
2038 // WW8 has no explicit table start/end markup,
2039 // simply rows with the same table properties that are grouped together as a table.
2040 TableBidi( pTableTextNodeInfoInner
);
2041 TableOrientation( pTableTextNodeInfoInner
);
2042 TableSpacing( pTableTextNodeInfoInner
);
2043 TableDefinition( pTableTextNodeInfoInner
); //per row definitions
2044 TableHeight( pTableTextNodeInfoInner
); //per row definitions
2045 TableBackgrounds( pTableTextNodeInfoInner
); //per row definitions
2046 // Since this isEndOfLine, cell margin defaults for each row come from last column.
2047 TableDefaultBorders( pTableTextNodeInfoInner
); //per row definitions
2048 TableCanSplit( pTableTextNodeInfoInner
); //per row definitions
2049 TableVerticalCell( pTableTextNodeInfoInner
); //per row definitions
2050 TableCellBorders( pTableTextNodeInfoInner
); //per row definitions
2053 static sal_uInt16
lcl_TCFlags(SwDoc
&rDoc
, const SwTableBox
* pBox
, sal_Int32 nRowSpan
)
2055 sal_uInt16 nFlags
= 0;
2059 else if (nRowSpan
< 0)
2062 if (pBox
!= nullptr)
2064 const SwFrameFormat
* pFormat
= pBox
->GetFrameFormat();
2065 switch (pFormat
->GetVertOrient().GetVertOrient())
2067 case text::VertOrientation::CENTER
:
2070 case text::VertOrientation::BOTTOM
:
2076 const SwStartNode
* pSttNd
= pBox
->GetSttNd();
2079 SwNodeIndex
aIdx( *pSttNd
);
2080 const SwContentNode
* pCNd
= pSttNd
->GetNodes().GoNext( &aIdx
);
2081 if( pCNd
&& pCNd
->IsTextNode())
2083 SfxItemSetFixed
<RES_CHRATR_ROTATE
, RES_CHRATR_ROTATE
> aCoreSet(rDoc
.GetAttrPool());
2084 static_cast<const SwTextNode
*>(pCNd
)->GetParaAttr(aCoreSet
,
2085 0, static_cast<const SwTextNode
*>(pCNd
)->GetText().getLength());
2086 if ( const SvxCharRotateItem
* pRotate
= aCoreSet
.GetItemIfSet(RES_CHRATR_ROTATE
))
2088 if(pRotate
&& pRotate
->GetValue() == 900_deg10
)
2090 nFlags
= nFlags
| 0x0004 | 0x0008;
2092 else if(pRotate
&& pRotate
->GetValue() == 2700_deg10
)
2094 nFlags
= nFlags
| 0x0004 | 0x0010;
2104 void WW8AttributeOutput::TableVerticalCell( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2106 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
2107 const SwTableLine
* pTabLine
= pTabBox
->GetUpper();
2108 const SwTableBoxes
& rTableBoxes
= pTabLine
->GetTabBoxes();
2110 sal_uInt8 nBoxes
= rTableBoxes
.size();
2111 for ( sal_uInt8 n
= 0; n
< nBoxes
; n
++ )
2113 const SwTableBox
* pTabBox1
= rTableBoxes
[n
];
2114 const SwFrameFormat
* pFrameFormat
= pTabBox1
->GetFrameFormat();
2116 // Map from our SvxFrameDirection to WW8 TextFlow.
2117 sal_uInt16 nTextFlow
= 0;
2118 switch (m_rWW8Export
.TrueFrameDirection(*pFrameFormat
))
2120 case SvxFrameDirection::Vertical_RL_TB
:
2123 case SvxFrameDirection::Vertical_LR_BT
:
2132 m_rWW8Export
.InsUInt16( NS_sprm::TTextFlow::val
);
2133 m_rWW8Export
.m_pO
->push_back( n
); //start range
2134 m_rWW8Export
.m_pO
->push_back( sal_uInt8(n
+ 1) ); //end range
2135 m_rWW8Export
.InsUInt16(nTextFlow
);
2140 void WW8AttributeOutput::TableCanSplit( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2142 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
2143 const SwTableLine
* pTabLine
= pTabBox
->GetUpper();
2144 const SwFrameFormat
* pLineFormat
= pTabLine
->GetFrameFormat();
2147 By default the row can be split in word, and now in writer we have a
2148 feature equivalent to this, Word stores 1 for fCantSplit if the row
2149 cannot be split, we set true if we can split it. An example is #i4569#
2152 const SwFormatRowSplit
& rSplittable
= pLineFormat
->GetRowSplit();
2153 sal_uInt8 nCantSplit
= (!rSplittable
.GetValue()) ? 1 : 0;
2154 m_rWW8Export
.InsUInt16( NS_sprm::TFCantSplit::val
);
2155 m_rWW8Export
.m_pO
->push_back( nCantSplit
);
2156 m_rWW8Export
.InsUInt16( NS_sprm::TFCantSplit90::val
); // also write fCantSplit90
2157 m_rWW8Export
.m_pO
->push_back( nCantSplit
);
2160 void WW8AttributeOutput::TableBidi( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2162 const SwTable
* pTable
= pTableTextNodeInfoInner
->getTable();
2163 const SwFrameFormat
* pFrameFormat
= pTable
->GetFrameFormat();
2165 if ( m_rWW8Export
.TrueFrameDirection(*pFrameFormat
) == SvxFrameDirection::Horizontal_RL_TB
)
2167 m_rWW8Export
.InsUInt16( NS_sprm::TFBiDi::val
);
2168 m_rWW8Export
.InsUInt16( 1 );
2172 void WW8AttributeOutput::TableRowRedline( ww8::WW8TableNodeInfoInner::Pointer_t
/*pTableTextNodeInfoInner*/ )
2176 void WW8AttributeOutput::TableCellRedline( ww8::WW8TableNodeInfoInner::Pointer_t
/*pTableTextNodeInfoInner*/ )
2180 void WW8AttributeOutput::TableHeight( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2182 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
2183 const SwTableLine
* pTabLine
= pTabBox
->GetUpper();
2184 const SwFrameFormat
* pLineFormat
= pTabLine
->GetFrameFormat();
2186 // output line height sprmTDyaRowHeight
2187 tools::Long nHeight
= 0;
2188 const SwFormatFrameSize
& rLSz
= pLineFormat
->GetFrameSize();
2189 if ( SwFrameSize::Variable
!= rLSz
.GetHeightSizeType() && rLSz
.GetHeight() )
2191 if ( SwFrameSize::Minimum
== rLSz
.GetHeightSizeType() )
2192 nHeight
= rLSz
.GetHeight();
2194 nHeight
= -rLSz
.GetHeight();
2199 m_rWW8Export
.InsUInt16( NS_sprm::TDyaRowHeight::val
);
2200 m_rWW8Export
.InsUInt16( o3tl::narrowing
<sal_uInt16
>(nHeight
) );
2205 void WW8AttributeOutput::TableOrientation( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2207 const SwTable
* pTable
= pTableTextNodeInfoInner
->getTable();
2209 const SwFrameFormat
*pFormat
= pTable
->GetFrameFormat();
2212 SAL_WARN( "sw.ww8", "FrameFormat is nil" );
2216 const SwFormatHoriOrient
&rHori
= pFormat
->GetHoriOrient();
2217 const SwFormatVertOrient
&rVert
= pFormat
->GetVertOrient();
2220 !((text::RelOrientation::PRINT_AREA
== rHori
.GetRelationOrient() ||
2221 text::RelOrientation::FRAME
== rHori
.GetRelationOrient())
2223 (text::RelOrientation::PRINT_AREA
== rVert
.GetRelationOrient() ||
2224 text::RelOrientation::FRAME
== rVert
.GetRelationOrient()))
2228 const bool bIsRTL
= m_rWW8Export
.TrueFrameDirection(*pFormat
) == SvxFrameDirection::Horizontal_RL_TB
;
2229 sal_Int16 eHOri
= rHori
.GetHoriOrient();
2232 case text::HoriOrientation::CENTER
:
2233 m_rWW8Export
.InsUInt16( NS_sprm::TJc::val
); //logical orientation required for MSO
2234 m_rWW8Export
.InsUInt16( 1 );
2235 m_rWW8Export
.InsUInt16( NS_sprm::TJc90::val
); //physical orientation required for LO
2236 m_rWW8Export
.InsUInt16( 1 );
2238 case text::HoriOrientation::RIGHT
:
2239 m_rWW8Export
.InsUInt16( NS_sprm::TJc90::val
); //required for LO
2240 m_rWW8Export
.InsUInt16( 2 );
2243 m_rWW8Export
.InsUInt16( NS_sprm::TJc::val
); //required for MSO
2244 m_rWW8Export
.InsUInt16( 2 );
2247 case text::HoriOrientation::LEFT
:
2250 m_rWW8Export
.InsUInt16( NS_sprm::TJc::val
); //required for MSO
2251 m_rWW8Export
.InsUInt16( 2 );
2254 case text::HoriOrientation::LEFT_AND_WIDTH
:
2255 // Width can only be specified for the LOGICAL left, so in RTL, that is always PHYSICAL right
2258 m_rWW8Export
.InsUInt16( NS_sprm::TJc90::val
); //required for LO
2259 m_rWW8Export
.InsUInt16( 2 );
2267 void WW8AttributeOutput::TableSpacing(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2269 const SwTable
* pTable
= pTableTextNodeInfoInner
->getTable();
2270 const SwTableFormat
* pTableFormat
= pTable
->GetFrameFormat();
2273 // Writing these SPRM's will make the table a floating one, so only write
2274 // them in case the table is already inside a frame.
2275 if (!(pTableFormat
!= nullptr && pTable
->GetTableNode()->GetFlyFormat()))
2278 const SvxULSpaceItem
& rUL
= pTableFormat
->GetULSpace();
2280 if (rUL
.GetUpper() > 0)
2282 sal_uInt8
const nPadding
= 2;
2283 sal_uInt8
const nPcVert
= 0;
2284 sal_uInt8
const nPcHorz
= 0;
2286 sal_uInt8
const nTPc
= (nPadding
<< 4) | (nPcVert
<< 2) | nPcHorz
;
2288 m_rWW8Export
.InsUInt16(NS_sprm::TPc::val
);
2289 m_rWW8Export
.m_pO
->push_back( nTPc
);
2291 m_rWW8Export
.InsUInt16(NS_sprm::TDyaAbs::val
);
2292 m_rWW8Export
.InsUInt16(rUL
.GetUpper());
2294 m_rWW8Export
.InsUInt16(NS_sprm::TDyaFromText::val
);
2295 m_rWW8Export
.InsUInt16(rUL
.GetUpper());
2298 if (rUL
.GetLower() > 0)
2300 m_rWW8Export
.InsUInt16(NS_sprm::TDyaFromTextBottom::val
);
2301 m_rWW8Export
.InsUInt16(rUL
.GetLower());
2305 void WW8AttributeOutput::TablePositioning(SwFrameFormat
* pFlyFormat
)
2307 if (!pFlyFormat
|| !pFlyFormat
->GetFlySplit().GetValue())
2312 sal_uInt8 nPcVert
= 0;
2313 switch (pFlyFormat
->GetVertOrient().GetRelationOrient())
2315 case text::RelOrientation::PAGE_PRINT_AREA
:
2316 // relative to margin
2319 case text::RelOrientation::PAGE_FRAME
:
2324 // text::RelOrientation::FRAME
2329 sal_uInt8 nPcHorz
= 0;
2330 switch (pFlyFormat
->GetHoriOrient().GetRelationOrient())
2332 case text::RelOrientation::FRAME
:
2333 // relative to column
2336 case text::RelOrientation::PAGE_PRINT_AREA
:
2337 // relative to margin
2341 // text::RelOrientation::PAGE_FRAME
2346 sal_uInt8 nTPc
= (nPcVert
<< 4) | (nPcHorz
<< 6);
2347 m_rWW8Export
.InsUInt16(NS_sprm::TPc::val
);
2348 m_rWW8Export
.m_pO
->push_back(nTPc
);
2350 // Similar to WW8AttributeOutput::FormatHorizOrientation(), but for tables.
2351 sal_Int16 nTDxaAbs
= 0;
2352 switch (pFlyFormat
->GetHoriOrient().GetHoriOrient())
2354 case text::HoriOrientation::LEFT
:
2358 case text::HoriOrientation::CENTER
:
2362 case text::HoriOrientation::RIGHT
:
2367 nTDxaAbs
= pFlyFormat
->GetHoriOrient().GetPos();
2370 m_rWW8Export
.InsUInt16(NS_sprm::TDxaAbs::val
);
2371 m_rWW8Export
.InsInt16(nTDxaAbs
);
2373 // Similar to WW8AttributeOutput::FormatVertOrientation(), but for tables.
2374 sal_Int16 nTDyaAbs
= 0;
2375 switch (pFlyFormat
->GetVertOrient().GetVertOrient())
2377 case text::VertOrientation::TOP
:
2381 case text::VertOrientation::CENTER
:
2385 case text::VertOrientation::BOTTOM
:
2390 nTDyaAbs
= pFlyFormat
->GetVertOrient().GetPos();
2393 m_rWW8Export
.InsUInt16(NS_sprm::TDyaAbs::val
);
2394 m_rWW8Export
.InsInt16(nTDyaAbs
);
2396 // Similar to WW8AttributeOutput::FormatULSpace(), but for tables.
2397 sal_uInt16 nDyaFromText
= pFlyFormat
->GetULSpace().GetUpper();
2398 m_rWW8Export
.InsUInt16(NS_sprm::TDyaFromText::val
);
2399 m_rWW8Export
.InsUInt16(nDyaFromText
);
2400 sal_uInt16 nDyaFromTextBottom
= pFlyFormat
->GetULSpace().GetLower();
2401 m_rWW8Export
.InsUInt16(NS_sprm::TDyaFromTextBottom::val
);
2402 m_rWW8Export
.InsUInt16(nDyaFromTextBottom
);
2404 // Similar to WW8AttributeOutput::FormatLRSpace(), but for tables.
2405 sal_uInt16 nDxaFromText
= pFlyFormat
->GetLRSpace().GetLeft();
2406 m_rWW8Export
.InsUInt16(NS_sprm::TDxaFromText::val
);
2407 m_rWW8Export
.InsUInt16(nDxaFromText
);
2408 sal_uInt16 nDxaFromTextRight
= pFlyFormat
->GetLRSpace().GetRight();
2409 m_rWW8Export
.InsUInt16(NS_sprm::TDxaFromTextRight::val
);
2410 m_rWW8Export
.InsUInt16(nDxaFromTextRight
);
2412 if (!pFlyFormat
->GetWrapInfluenceOnObjPos().GetAllowOverlap())
2414 // Allowing overlap is the default in both Writer and in WW8.
2415 m_rWW8Export
.InsUInt16(NS_sprm::TFNoAllowOverlap::val
);
2416 m_rWW8Export
.m_pO
->push_back(1);
2420 void WW8AttributeOutput::TableDefinition( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2422 const SwTable
* pTable
= pTableTextNodeInfoInner
->getTable();
2424 if ( pTable
->GetRowsToRepeat() > pTableTextNodeInfoInner
->getRow() )
2426 m_rWW8Export
.InsUInt16( NS_sprm::TTableHeader::val
);
2427 m_rWW8Export
.m_pO
->push_back( 1 );
2430 ww8::TableBoxVectorPtr pTableBoxes
=
2431 pTableTextNodeInfoInner
->getTableBoxesOfRow();
2432 // number of cell written
2433 sal_uInt32 nBoxes
= pTableBoxes
->size();
2434 assert(nBoxes
<= ww8::MAXTABLECELLS
);
2437 m_rWW8Export
.InsUInt16( NS_sprm::TDefTable::val
);
2438 sal_uInt16 nSprmSize
= 2 + (nBoxes
+ 1) * 2 + nBoxes
* 20;
2439 m_rWW8Export
.InsUInt16( nSprmSize
); // length
2442 m_rWW8Export
.m_pO
->push_back( static_cast<sal_uInt8
>(nBoxes
) );
2446 ALWAYS relative when text::HoriOrientation::NONE (nPageSize + ( nPageSize / 10 )) < nTableSz,
2447 in that case the cell width's and table width's are not real. The table
2448 width is maxed and cells relative, so we need the frame (generally page)
2449 width that the table is in to work out the true widths.
2451 //const bool bNewTableModel = pTable->IsNewModel();
2452 const SwFrameFormat
*pFormat
= pTable
->GetFrameFormat();
2455 SAL_WARN( "sw.ww8", "FrameFormat is nil" );
2459 const SwFormatHoriOrient
&rHori
= pFormat
->GetHoriOrient();
2460 const SwFormatVertOrient
&rVert
= pFormat
->GetVertOrient();
2462 SwTwips nTableOffset
= 0;
2465 (text::RelOrientation::PRINT_AREA
== rHori
.GetRelationOrient() ||
2466 text::RelOrientation::FRAME
== rHori
.GetRelationOrient())
2468 (text::RelOrientation::PRINT_AREA
== rVert
.GetRelationOrient() ||
2469 text::RelOrientation::FRAME
== rVert
.GetRelationOrient())
2472 sal_Int16 eHOri
= rHori
.GetHoriOrient();
2475 case text::HoriOrientation::CENTER
:
2476 case text::HoriOrientation::RIGHT
:
2480 nTableOffset
= rHori
.GetPos();
2481 const SvxLRSpaceItem
& rLRSp
= pFormat
->GetLRSpace();
2482 nTableOffset
+= rLRSp
.GetLeft();
2484 // convert offset to be measured from right margin in right-to-left tables
2485 if ( nTableOffset
&& m_rWW8Export
.TrueFrameDirection(*pFormat
) == SvxFrameDirection::Horizontal_RL_TB
)
2487 SwTwips nLeftPageMargin
, nRightPageMargin
;
2488 const SwTwips nPageSize
= m_rWW8Export
.CurrentPageWidth(nLeftPageMargin
, nRightPageMargin
);
2489 const SwTwips nTableWidth
= pFormat
->GetFrameSize().GetWidth();
2490 nTableOffset
= nPageSize
- nLeftPageMargin
- nRightPageMargin
- nTableWidth
- nTableOffset
;
2496 m_rWW8Export
.InsInt16( nTableOffset
);
2498 ww8::GridColsPtr pGridCols
= GetGridCols( pTableTextNodeInfoInner
);
2499 for ( const auto nCol
: *pGridCols
)
2501 m_rWW8Export
.InsUInt16( o3tl::narrowing
<sal_uInt16
>(nCol
) + nTableOffset
);
2505 ww8::RowSpansPtr pRowSpans
= pTableTextNodeInfoInner
->getRowSpansOfRow();
2506 ww8::RowSpans::const_iterator aItRowSpans
= pRowSpans
->begin();
2508 for (const SwTableBox
* pTabBox1
: *pTableBoxes
)
2510 sal_uInt16 npOCount
= m_rWW8Export
.m_pO
->size();
2512 const SwFrameFormat
* pBoxFormat
= nullptr;
2513 if (pTabBox1
!= nullptr)
2514 pBoxFormat
= pTabBox1
->GetFrameFormat();
2517 lcl_TCFlags(m_rWW8Export
.m_rDoc
, pTabBox1
, *aItRowSpans
);
2518 m_rWW8Export
.InsUInt16( nFlags
);
2520 static sal_uInt8 aNullBytes
[] = { 0x0, 0x0 };
2522 m_rWW8Export
.m_pO
->insert( m_rWW8Export
.m_pO
->end(), aNullBytes
, aNullBytes
+2 ); // dummy
2523 if (pBoxFormat
!= nullptr)
2525 const SvxBoxItem
& rBoxItem
= pBoxFormat
->GetBox();
2527 WW8Export::Out_SwFormatTableBox( *m_rWW8Export
.m_pO
, &rBoxItem
); // 8/16 Byte
2530 WW8Export::Out_SwFormatTableBox( *m_rWW8Export
.m_pO
, nullptr); // 8/16 Byte
2532 SAL_INFO( "sw.ww8.level2", "<tclength>" << ( m_rWW8Export
.m_pO
->size() - npOCount
) << "</tclength>" );
2536 int nWidthPercent
= pFormat
->GetFrameSize().GetWidthPercent();
2538 // The best fit for "automatic" table placement is relative 100%
2539 if (!nWidthPercent
&& rHori
.GetHoriOrient() == text::HoriOrientation::FULL
)
2540 nWidthPercent
= 100;
2542 // Width is in fiftieths of a percent. For sprmTTableWidth, must be non-negative and 600% max
2543 if ( nWidthPercent
> 0 && nWidthPercent
<= 600 )
2545 m_rWW8Export
.InsUInt16( NS_sprm::TTableWidth::val
);
2546 m_rWW8Export
.m_pO
->push_back( sal_uInt8
/*ftsPercent*/ (2) );
2547 m_rWW8Export
.InsUInt16( o3tl::narrowing
<sal_uInt16
>(nWidthPercent
) * 50 );
2550 // Write table positioning properties in case this is a floating table.
2551 TablePositioning(pTable
->GetTableNode()->GetFlyFormat());
2554 ww8::GridColsPtr
AttributeOutputBase::GetGridCols( ww8::WW8TableNodeInfoInner::Pointer_t
const & pTableTextNodeInfoInner
)
2556 return pTableTextNodeInfoInner
->getGridColsOfRow(*this);
2559 ww8::WidthsPtr
AttributeOutputBase::GetColumnWidths( ww8::WW8TableNodeInfoInner::Pointer_t
const & pTableTextNodeInfoInner
)
2561 // Get the column widths based on ALL the rows, not just the current row
2562 return pTableTextNodeInfoInner
->getGridColsOfRow(*this, true);
2565 void AttributeOutputBase::GetTablePageSize( ww8::WW8TableNodeInfoInner
const * pTableTextNodeInfoInner
, tools::Long
& rPageSize
, bool& rRelBoxSize
)
2567 tools::Long nPageSize
= 0;
2569 const SwNode
*pTextNd
= pTableTextNodeInfoInner
->getNode( );
2570 const SwTable
*pTable
= pTableTextNodeInfoInner
->getTable( );
2572 const SwFrameFormat
*pFormat
= pTable
->GetFrameFormat();
2575 SAL_WARN( "sw.ww8", "FrameFormat is nil" );
2579 const SwFormatFrameSize
&rSize
= pFormat
->GetFrameSize();
2580 int nWidthPercent
= rSize
.GetWidthPercent();
2581 bool bManualAligned
= pFormat
->GetHoriOrient().GetHoriOrient() == text::HoriOrientation::NONE
;
2582 if ( (pFormat
->GetHoriOrient().GetHoriOrient() == text::HoriOrientation::FULL
) || bManualAligned
)
2583 nWidthPercent
= 100;
2584 bool bRelBoxSize
= nWidthPercent
!= 0;
2585 tools::ULong nTableSz
= static_cast<tools::ULong
>(rSize
.GetWidth());
2586 if (nTableSz
> USHRT_MAX
/2 && !bRelBoxSize
)
2588 OSL_ENSURE(bRelBoxSize
, "huge table width but not relative, suspicious");
2595 SwRect
aRect( pFormat
->FindLayoutRect( false, &aPt
) );
2596 if ( aRect
.IsEmpty() )
2598 // Then fetch the page width without margins!
2599 const SwFrameFormat
* pParentFormat
=
2600 GetExport().m_pParentFrame
?
2601 &(GetExport().m_pParentFrame
->GetFrameFormat()) :
2602 GetExport().m_rDoc
.GetPageDesc(0).GetPageFormatOfNode(*pTextNd
, false);
2603 aRect
= pParentFormat
->FindLayoutRect(true);
2604 nPageSize
= aRect
.Width();
2605 if ( 0 == nPageSize
)
2607 const SvxLRSpaceItem
& rLR
= pParentFormat
->GetLRSpace();
2608 nPageSize
= pParentFormat
->GetFrameSize().GetWidth() - rLR
.GetLeft()
2614 nPageSize
= aRect
.Width();
2615 if ( bManualAligned
)
2617 // #i37571# For manually aligned tables
2618 const SvxLRSpaceItem
&rLR
= pFormat
->GetLRSpace();
2619 nPageSize
-= (rLR
.GetLeft() + rLR
.GetRight());
2624 if ( nWidthPercent
)
2626 nPageSize
*= nWidthPercent
;
2630 SAL_WARN( "sw.ww8", "nWidthPercent is zero" );
2634 // As the table width is not relative, the TablePageSize equals its width
2635 nPageSize
= nTableSz
;
2638 rPageSize
= nPageSize
;
2639 rRelBoxSize
= bRelBoxSize
;
2642 void WW8AttributeOutput::TableDefaultBorders( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2644 // This function name is misleading because it is not a table default, but a row default,
2645 // and it also only sets default cell margins (aka border padding).
2646 // The specs suggest there is no way to define default border lines/colors.
2647 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
2648 const SwFrameFormat
* pFrameFormat
= pTabBox
->GetFrameFormat();
2650 static const SvxBoxItemLine aBorders
[] =
2652 SvxBoxItemLine::TOP
, SvxBoxItemLine::LEFT
,
2653 SvxBoxItemLine::BOTTOM
, SvxBoxItemLine::RIGHT
2656 // Set row default cell margins using this last cell in the row
2657 for ( int i
= 0; i
< 4; ++i
)
2659 SwWW8Writer::InsUInt16( *m_rWW8Export
.m_pO
, NS_sprm::TCellPaddingDefault::val
);
2660 m_rWW8Export
.m_pO
->push_back( sal_uInt8(6) );
2661 m_rWW8Export
.m_pO
->push_back( sal_uInt8(0) );
2662 m_rWW8Export
.m_pO
->push_back( sal_uInt8(1) );
2663 m_rWW8Export
.m_pO
->push_back( sal_uInt8(1 << i
) );
2664 m_rWW8Export
.m_pO
->push_back( sal_uInt8(3) );
2666 SwWW8Writer::InsUInt16( *m_rWW8Export
.m_pO
,
2667 pFrameFormat
->GetBox().GetDistance( aBorders
[i
] ) );
2671 void WW8AttributeOutput::TableCellBorders(
2672 ww8::WW8TableNodeInfoInner::Pointer_t
const & pTableTextNodeInfoInner
)
2674 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
2675 const SwTableLine
* pTabLine
= pTabBox
->GetUpper();
2676 const SwTableBoxes
& rTabBoxes
= pTabLine
->GetTabBoxes();
2677 sal_uInt8 nBoxes
= std::min
<size_t>(rTabBoxes
.size(), 255);
2678 const SvxBoxItem
* pLastBox
= nullptr;
2679 sal_uInt8 nSeqStart
= 0; // start of sequence of cells with same borders
2681 static const SvxBoxItemLine aBorders
[] =
2683 SvxBoxItemLine::TOP
, SvxBoxItemLine::LEFT
,
2684 SvxBoxItemLine::BOTTOM
, SvxBoxItemLine::RIGHT
2687 sal_uInt16 nDefaultMargin
[4] = {31681, 31681, 31681, 31681}; // outside of documented valid range
2688 // last column in each row defines the row default in TableRowDefaultBorders()
2689 if ( nBoxes
&& rTabBoxes
.size() == nBoxes
)
2691 const SvxBoxItem
& rBox
= rTabBoxes
[ nBoxes
-1 ]->GetFrameFormat()->GetBox();
2692 for ( int i
= 0; i
< 4; ++i
)
2693 nDefaultMargin
[i
] = rBox
.GetDistance( aBorders
[i
] );
2696 // Detect sequences of cells which have the same borders, and output
2697 // a border description for each such cell range.
2698 for ( unsigned n
= 0; n
<= nBoxes
; ++n
)
2700 const SvxBoxItem
* pBox
= (n
== nBoxes
) ? nullptr :
2701 &rTabBoxes
[n
]->GetFrameFormat()->GetBox();
2704 else if( !pBox
|| *pLastBox
!= *pBox
)
2706 // This cell has different borders than the previous cell,
2707 // so output the borders for the preceding cell range.
2708 m_rWW8Export
.Out_CellRangeBorders(pLastBox
, nSeqStart
, n
);
2710 // The last column is used as the row default for margins, so we can ignore these matching ones
2714 // Output cell margins.
2715 // One CSSA can define up to all four margins if they are the same size value.
2716 sal_uInt16 nMargin
[4];
2717 sal_uInt8 nSideBits
[4] = {0, 0, 0, 0}; // 0001:top, 0010:left, 0100:bottom, 1000:right
2718 for ( int i
= 0; i
< 4; ++i
) // sides: top, left, bottom, right
2720 nMargin
[i
] = std::min(sal_Int16(31680), pLastBox
->GetDistance( aBorders
[i
] ));
2721 if ( nMargin
[i
] == nDefaultMargin
[i
] )
2724 // join a previous side's definition if it shares the same value
2725 for ( int p
= 0; p
< 4; ++p
)
2727 if ( nMargin
[i
] == nMargin
[p
] )
2729 nSideBits
[p
] |= 1 << i
;
2735 // write out the cell margins definitions that were used
2736 for ( int i
= 0; i
< 4; ++i
)
2740 SwWW8Writer::InsUInt16( *m_rWW8Export
.m_pO
, NS_sprm::TCellPadding::val
);
2741 m_rWW8Export
.m_pO
->push_back( sal_uInt8(6) ); // 6 bytes
2742 m_rWW8Export
.m_pO
->push_back( sal_uInt8(nSeqStart
) ); // first cell: apply margin
2743 m_rWW8Export
.m_pO
->push_back( sal_uInt8(n
) ); // end cell: do not apply margin
2744 m_rWW8Export
.m_pO
->push_back( sal_uInt8(nSideBits
[i
]) );
2745 m_rWW8Export
.m_pO
->push_back( sal_uInt8(3) ); // FtsDxa: size in twips
2746 SwWW8Writer::InsUInt16( *m_rWW8Export
.m_pO
, nMargin
[i
] );
2756 void WW8AttributeOutput::TableBackgrounds( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2758 const SwTable
* pTab
= pTableTextNodeInfoInner
->getTable();
2759 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
2760 const SwTableLine
* pTabLine
= pTabBox
->GetUpper();
2761 const SwTableBoxes
& rTabBoxes
= pTabLine
->GetTabBoxes();
2763 sal_uInt8 nBoxes
= rTabBoxes
.size();
2764 m_rWW8Export
.InsUInt16( NS_sprm::TDefTableShd80::val
);
2765 m_rWW8Export
.m_pO
->push_back( static_cast<sal_uInt8
>(nBoxes
* 2) ); // Len
2767 Color aRowColor
= COL_AUTO
;
2768 const SvxBrushItem
*pTableColorProp
= pTab
->GetFrameFormat()->GetAttrSet().GetItem
<SvxBrushItem
>(RES_BACKGROUND
);
2769 if ( pTableColorProp
)
2770 aRowColor
= pTableColorProp
->GetColor();
2772 const SvxBrushItem
*pRowColorProp
= pTabLine
->GetFrameFormat()->GetAttrSet().GetItem
<SvxBrushItem
>(RES_BACKGROUND
);
2773 if ( pRowColorProp
&& pRowColorProp
->GetColor() != COL_AUTO
)
2774 aRowColor
= pRowColorProp
->GetColor();
2776 for ( sal_uInt8 n
= 0; n
< nBoxes
; n
++ )
2778 const SwTableBox
* pBox1
= rTabBoxes
[n
];
2779 const SwFrameFormat
* pFrameFormat
= pBox1
->GetFrameFormat();
2780 Color aColor
= aRowColor
;
2782 const SvxBrushItem
*pCellColorProp
= pFrameFormat
->GetAttrSet().GetItem
<SvxBrushItem
>(RES_BACKGROUND
);
2783 if ( pCellColorProp
&& pCellColorProp
->GetColor() != COL_AUTO
)
2784 aColor
= pCellColorProp
->GetColor();
2787 WW8Export::TransBrush( aColor
, aShd
);
2788 m_rWW8Export
.InsUInt16( aShd
.GetValue() );
2791 /*sprmTDefTableShdRaw:
2792 * A DefTableShdOperand value that specifies the ... shading for cells 1 up to 22 in the row,
2793 * ... Cells 23 to 44 are shaded by sprmTDefTableShdRaw2nd,
2794 * and cells 45 to 63 are shaded by sprmTDefTableShdRaw3rd.
2796 sal_uInt32
const aSprmIds
[] { NS_sprm::TDefTableShd::val
,
2797 NS_sprm::TDefTableShdRaw::val
,
2798 NS_sprm::TDefTableShdRaw::val
,
2799 NS_sprm::TDefTableShd2nd::val
,
2800 NS_sprm::TDefTableShdRaw2nd::val
,
2801 NS_sprm::TDefTableShd3rd::val
,
2802 NS_sprm::TDefTableShdRaw3rd::val
};
2803 for (sal_uInt32 m
: aSprmIds
)
2805 sal_uInt8 nStart
= 0;
2806 sal_uInt8 nStop
= rTabBoxes
.size();
2809 case NS_sprm::TDefTableShd::val
:
2810 case NS_sprm::TDefTableShdRaw::val
:
2814 case NS_sprm::TDefTableShd2nd::val
:
2815 case NS_sprm::TDefTableShdRaw2nd::val
:
2820 case NS_sprm::TDefTableShd3rd::val
:
2821 case NS_sprm::TDefTableShdRaw3rd::val
:
2827 if ( nStart
>= nStop
)
2830 m_rWW8Export
.InsUInt16( m
);
2831 m_rWW8Export
.m_pO
->push_back( static_cast<sal_uInt8
>((nStop
-nStart
) * 10) );
2833 for ( sal_uInt8 n
= nStart
; n
< nStop
; n
++ )
2835 const SwTableBox
* pBox1
= rTabBoxes
[n
];
2836 const SwFrameFormat
* pFrameFormat
= pBox1
->GetFrameFormat();
2837 Color aColor
= aRowColor
;
2839 const SvxBrushItem
*pCellColorProp
= pFrameFormat
->GetAttrSet().GetItem
<SvxBrushItem
>(RES_BACKGROUND
);
2840 if ( pCellColorProp
&& pCellColorProp
->GetColor() != COL_AUTO
)
2841 aColor
= pCellColorProp
->GetColor();
2844 aSHD
.setCvFore( 0xFF000000 );
2846 if ( aColor
== COL_AUTO
)
2847 aSHD
.setCvBack( 0xFF000000 );
2849 aSHD
.setCvBack( wwUtility::RGBToBGR( aColor
) );
2851 aSHD
.Write( m_rWW8Export
);
2856 void WW8Export::SectionBreaksAndFrames( const SwTextNode
& rNode
)
2858 // output page/section breaks
2859 OutputSectionBreaks( rNode
.GetpSwAttrSet(), rNode
);
2864 class TrackContentToExport
2868 SwNodeOffset m_nStart
, m_nEnd
;
2870 TrackContentToExport(SwPaM
*pCurPam
, SwNodeOffset nCurStart
, SwNodeOffset nCurEnd
)
2871 : m_pCurPam(pCurPam
)
2872 , m_nStart(nCurStart
)
2877 bool contentRemainsToExport(ww8::WW8TableInfo
*pTableInfo
)
2879 bool bSimpleContentRemains
= m_pCurPam
->GetPoint()->GetNode() < m_pCurPam
->GetMark()->GetNode() ||
2880 (m_pCurPam
->GetPoint()->GetNode() == m_pCurPam
->GetMark()->GetNode() &&
2881 m_pCurPam
->GetPoint()->GetContentIndex() <= m_pCurPam
->GetMark()->GetContentIndex());
2882 if (bSimpleContentRemains
)
2888 //An old-school table where one cell may points back to a previous node as the next cell
2889 //so if this node is the last node in the range, we may need to jump back to a previously
2890 //skipped cell to output it in a sane sequence. See ooo47778-3.sxw for one of these
2891 //horrors. So if we are at the end of the selection, but this end point is a table
2892 //cell whose next cell is in the selection allow jumping back to it
2893 const SwNode
* pCurrentNode
= &m_pCurPam
->GetPoint()->GetNode();
2894 const SwNode
* pNextNode
= pTableInfo
->getNextNode(pCurrentNode
);
2896 if (pNextNode
&& pCurrentNode
!= pNextNode
)
2898 return pNextNode
->GetIndex() >= m_nStart
&&
2899 pNextNode
->GetIndex() < m_nEnd
;
2908 void MSWordExportBase::WriteText()
2910 TrackContentToExport
aContentTracking(m_pCurPam
.get(), m_nCurStart
, m_nCurEnd
);
2911 while (aContentTracking
.contentRemainsToExport(m_pTableInfo
.get()))
2913 SwNode
& rNd
= m_pCurPam
->GetPointNode();
2915 // no section breaks exported for Endnotes
2916 if ( rNd
.IsTextNode() && m_nTextTyp
!= TXT_EDN
&& m_nTextTyp
!= TXT_FTN
)
2918 SwSoftPageBreakList breakList
;
2919 // if paragraph need to be split than handle section break somewhere
2921 if( !NeedTextNodeSplit( *rNd
.GetTextNode(), breakList
) )
2922 SectionBreaksAndFrames( *rNd
.GetTextNode() );
2926 // output the various types of nodes
2927 if ( rNd
.IsContentNode() )
2929 SwContentNode
* pCNd
= static_cast<SwContentNode
*>(&rNd
);
2931 const SwPageDesc
* pTemp
= rNd
.FindPageDesc();
2933 m_pCurrentPageDesc
= pTemp
;
2935 m_pCurPam
->GetPoint()->SetContent( 0 );
2936 OutputContentNode( *pCNd
);
2938 else if ( rNd
.IsTableNode() )
2940 m_pTableInfo
->processSwTable( &rNd
.GetTableNode()->GetTable() );
2942 else if ( rNd
.IsSectionNode() && TXT_MAINTEXT
== m_nTextTyp
)
2943 OutputSectionNode( *rNd
.GetSectionNode() );
2944 else if ( TXT_MAINTEXT
== m_nTextTyp
&& rNd
.IsEndNode() &&
2945 rNd
.StartOfSectionNode()->IsSectionNode() )
2947 const SwSection
& rSect
= rNd
.StartOfSectionNode()->GetSectionNode()
2949 if ( m_bStartTOX
&& SectionType::ToxContent
== rSect
.GetType() )
2950 m_bStartTOX
= false;
2952 SwNodeIndex
aIdx( rNd
, 1 );
2953 if ( aIdx
.GetNode().IsEndNode() && aIdx
.GetNode().StartOfSectionNode()->IsSectionNode() )
2955 else if ( aIdx
.GetNode().IsSectionNode() )
2957 else if ( !IsInTable() ) //No sections in table
2959 //#120140# Do not need to insert a page/section break after a section end. Check this case first
2960 bool bNeedExportBreakHere
= true;
2961 if ( rSect
.GetType() == SectionType::ToxContent
|| rSect
.GetType() == SectionType::ToxHeader
)
2962 bNeedExportBreakHere
= false;
2963 else if ( aIdx
.GetNode().IsTextNode() )
2965 SwTextNode
*pTempNext
= aIdx
.GetNode().GetTextNode();
2968 const SwFormatPageDesc
* pTempItem
= nullptr;
2969 if (pTempNext
->GetpSwAttrSet()
2970 && (pTempItem
= pTempNext
->GetpSwAttrSet()->GetItemIfSet(RES_PAGEDESC
, false))
2971 && pTempItem
->GetRegisteredIn())
2973 //Next node has a new page style which means this node is a section end. Do not insert another page/section break here
2974 bNeedExportBreakHere
= false;
2980 /* Do not export Section Break in case DOCX containing MultiColumn and
2981 * aIdx.GetNode().IsTextNode() is False i.e. Text node is NULL.
2983 const SwFrameFormat
* pPgFormat
= rSect
.GetFormat();
2984 const SwFormatCol
& rCol
= pPgFormat
->GetCol();
2985 sal_uInt16 nColumnCount
= rCol
.GetNumCols();
2986 const SwFormatNoBalancedColumns
& rNoBalanced
= pPgFormat
->GetBalancedColumns();
2987 // Prevent the additional section break only for non-balanced columns.
2988 if (nColumnCount
> 1 && rNoBalanced
.GetValue())
2990 bNeedExportBreakHere
= false;
2992 // No need to create a "fake" section if this is the end of the document,
2993 // except to emulate balanced columns.
2994 else if ( nColumnCount
< 2 && aIdx
== m_rDoc
.GetNodes().GetEndOfContent() )
2995 bNeedExportBreakHere
= false;
2998 if (bNeedExportBreakHere
) //#120140# End of check
3000 ReplaceCr( char(0xc) ); // indicator for Page/Section-Break
3002 const SwSectionFormat
* pParentFormat
= rSect
.GetFormat()->GetParent();
3003 if ( !pParentFormat
)
3004 pParentFormat
= reinterpret_cast<SwSectionFormat
*>(sal_IntPtr(-1));
3006 sal_uLong nRstLnNum
;
3007 if ( aIdx
.GetNode().IsContentNode() )
3008 nRstLnNum
= static_cast<SwContentNode
&>(aIdx
.GetNode()).GetSwAttrSet().
3009 GetLineNumber().GetStartValue();
3013 AppendSection( m_pCurrentPageDesc
, pParentFormat
, nRstLnNum
);
3017 OutputEndNode( *rNd
.GetEndNode() );
3021 else if ( rNd
.IsStartNode() )
3023 OutputStartNode( *rNd
.GetStartNode() );
3025 else if ( rNd
.IsEndNode() )
3027 OutputEndNode( *rNd
.GetEndNode() );
3030 if ( &rNd
== &rNd
.GetNodes().GetEndOfContent() )
3033 const SwNode
* pCurrentNode
= &m_pCurPam
->GetPoint()->GetNode();
3034 const SwNode
* pNextNode
= m_pTableInfo
->getNextNode(pCurrentNode
);
3036 if (pCurrentNode
== pNextNode
)
3038 SAL_WARN("sw.ww8", "loop in TableInfo");
3039 pNextNode
= nullptr;
3042 if (pNextNode
!= nullptr)
3043 m_pCurPam
->GetPoint()->Assign(*pNextNode
);
3045 m_pCurPam
->GetPoint()->Adjust(SwNodeOffset(1));
3047 SwNodeOffset nPos
= m_pCurPam
->GetPoint()->GetNodeIndex();
3048 ::SetProgressState( sal_Int32(nPos
), m_pCurPam
->GetDoc().GetDocShell() );
3051 SAL_INFO( "sw.ww8.level2", "</WriteText>" );
3054 void WW8Export::WriteMainText()
3056 SAL_INFO( "sw.ww8.level2", "<WriteMainText>" );
3058 m_pFib
->m_fcMin
= Strm().Tell();
3060 m_pCurPam
->GetPoint()->Assign(*m_rDoc
.GetNodes().GetEndOfContent().StartOfSectionNode());
3064 if( 0 == Strm().Tell() - m_pFib
->m_fcMin
) // no text ?
3065 WriteCR(); // then CR at the end ( otherwise WW will complain )
3067 m_pFib
->m_ccpText
= Fc2Cp( Strm().Tell() );
3068 m_pFieldMain
->Finish( m_pFib
->m_ccpText
, 0 );
3070 // ccpText includes Footnote and KF-text
3071 // therefore pFib->ccpText may get updated as well
3072 // save the StyleId of the last paragraph. Because WW97 take the style
3073 // from the last CR, that will be written after footer/Header/footnotes/
3075 const SwTextNode
* pLastNd
= m_pCurPam
->GetMark()->GetNode().GetTextNode();
3077 m_nLastFormatId
= GetId( static_cast<SwTextFormatColl
&>(pLastNd
->GetAnyFormatColl()) );
3079 SAL_INFO( "sw.ww8.level2", "</WriteMainText>" );
3082 bool MSWordExportBase::IsInTable() const
3084 bool bResult
= false;
3086 if (m_pCurPam
!= nullptr)
3088 SwNode
& rNode
= m_pCurPam
->GetPointNode();
3092 ww8::WW8TableNodeInfo::Pointer_t pTableNodeInfo
= m_pTableInfo
->getTableNodeInfo(&rNode
);
3094 if (pTableNodeInfo
&& pTableNodeInfo
->getDepth() > 0)
3104 typedef ww8::WW8Sttb
< ww8::WW8Struct
> WW8SttbAssoc
;
3106 void WW8Export::WriteFkpPlcUsw()
3108 // Graphics in the data stream
3109 m_pGrf
->Write(); // Graphics
3111 // output into WordDocument stream
3112 m_pChpPlc
->WriteFkps(); // Fkp.Chpx
3113 m_pPapPlc
->WriteFkps(); // Fkp.Papx
3114 m_pSepx
->WriteSepx( Strm() ); // Sepx
3116 // output into Table stream
3117 m_pStyles
->OutputStylesTable(); // for WW8 StyleTab
3118 m_pFootnote
->WritePlc( *this ); // Footnote-Ref & Text Plc
3119 m_pEdn
->WritePlc( *this ); // Endnote-Ref & Text Plc
3120 m_pTextBxs
->WritePlc( *this ); // Textbox Text Plc
3121 m_pHFTextBxs
->WritePlc( *this ); // Head/Foot-Textbox Text Plc
3122 m_pAtn
->WritePlc( *this ); // Annotation-Ref & Text Plc
3124 m_pSepx
->WritePlcSed( *this ); // Slcx.PlcSed
3125 m_pSepx
->WritePlcHdd( *this ); // Slcx.PlcHdd
3127 m_pChpPlc
->WritePlc(); // Plcx.Chpx
3128 m_pPapPlc
->WritePlc(); // Plcx.Papx
3130 if( m_pRedlAuthors
)
3131 m_pRedlAuthors
->Write( GetWriter() ); // sttbfRMark (RedlineAuthors)
3132 m_pFieldMain
->Write( *this ); // Fields ( Main Text )
3133 m_pFieldHdFt
->Write( *this ); // Fields ( Header/Footer )
3134 m_pFieldFootnote
->Write( *this ); // Fields ( FootNotes )
3135 m_pFieldEdn
->Write( *this ); // Fields ( EndNotes )
3136 m_pFieldAtn
->Write( *this ); // Fields ( Annotations )
3137 m_pFieldTextBxs
->Write( *this ); // Fields ( Textboxes )
3138 m_pFieldHFTextBxs
->Write( *this ); // Fields ( Head/Foot-Textboxes )
3140 if (m_pEscher
|| m_rDoc
.ContainsMSVBasic())
3143 Every time MS 2000 creates an escher stream there is always
3144 an ObjectPool dir (even if empty). It turns out that if a copy of
3145 MS 2000 is used to open a document that contains escher graphics
3146 exported from StarOffice without this empty dir then *if* that
3147 copy of MS Office has never been used to open a MSOffice document
3148 that has escher graphics (and an ObjectPool dir of course) and
3149 that copy of office has not been used to draw escher graphics then
3150 our exported graphics do not appear. Once you do open a ms
3151 document with escher graphics or draw an escher graphic with that
3152 copy of word, then all documents from staroffice that contain
3153 escher work from then on. Tricky to track down, some sort of late
3154 binding trickery in MS where solely for first time initialization
3155 the existence of an ObjectPool dir is necessary for triggering
3158 // avoid memory leak #i120098#, the unnamed obj will be released in destructor.
3159 m_xEscherStg
= GetWriter().GetStorage().OpenSotStorage(SL::aObjectPool
);
3162 // dggInfo - escher stream
3165 m_pSdrObjs
->WritePlc( *this );
3166 m_pHFSdrObjs
->WritePlc( *this );
3167 // spamom - office drawing table
3168 // spahdr - header office drawing table
3170 m_pBkmks
->Write( *this ); // Bookmarks - sttbfBkmk/
3171 // plcfBkmkf/plcfBkmkl
3172 m_pFactoids
->Write(*this);
3178 m_pMagicTable
->Write( *this );
3180 m_pPiece
->WritePc( *this ); // Piece-Table
3181 m_aFontHelper
.WriteFontTable(m_pTableStrm
, *m_pFib
); // FFNs
3183 //Convert OOo asian typography into MS typography structure
3184 ExportDopTypography(m_pDop
->doptypography
);
3186 WriteDop( *this ); // Document-Properties
3189 WW8SttbAssoc
* pSttbfAssoc
= dynamic_cast<WW8SttbAssoc
*>
3190 (m_rDoc
.getIDocumentExternalData().getExternalData(::sw::tExternalDataType::STTBF_ASSOC
).get());
3192 if ( pSttbfAssoc
) // #i106057#
3194 std::vector
<OUString
> aStrings(pSttbfAssoc
->getStrings());
3195 WriteAsStringTable(aStrings
, m_pFib
->m_fcSttbfAssoc
,
3196 m_pFib
->m_lcbSttbfAssoc
);
3201 // Reclaim stored FIB data from document.
3202 ::ww8::WW8FibData
* pFibData
= dynamic_cast<ww8::WW8FibData
*>
3203 (m_rDoc
.getIDocumentExternalData().getExternalData(::sw::tExternalDataType::FIB
).get());
3207 m_pFib
->m_fReadOnlyRecommended
=
3208 pFibData
->getReadOnlyRecommended();
3209 m_pFib
->m_fWriteReservation
=
3210 pFibData
->getWriteReservation();
3213 m_pFib
->Write( Strm() ); // FIB
3216 void WW8Export::StoreDoc1()
3218 bool bNeedsFinalPara
= false;
3219 // Start of Text ( overwrite )
3220 SwWW8Writer::FillUntil( Strm(), m_pFib
->m_fcMin
);
3222 WriteMainText(); // main text
3223 sal_uInt8 nSprmsLen
;
3224 sal_uInt8
*pLastSprms
= m_pPapPlc
->CopyLastSprms(nSprmsLen
);
3226 bNeedsFinalPara
|= m_pFootnote
->WriteText( *this ); // Footnote-Text
3227 bNeedsFinalPara
|= m_pSepx
->WriteKFText( *this ); // K/F-Text
3228 bNeedsFinalPara
|= m_pAtn
->WriteText( *this ); // Annotation-Text
3229 bNeedsFinalPara
|= m_pEdn
->WriteText( *this ); // EndNote-Text
3231 // create the escher streams
3234 bNeedsFinalPara
|= m_pTextBxs
->WriteText( *this ); //Textbox Text Plc
3235 bNeedsFinalPara
|= m_pHFTextBxs
->WriteText( *this );//Head/Foot-Textbox Text Plc
3237 if (bNeedsFinalPara
)
3240 m_pPapPlc
->AppendFkpEntry(Strm().Tell(), nSprmsLen
, pLastSprms
);
3242 delete[] pLastSprms
;
3244 m_pSepx
->Finish( Fc2Cp( Strm().Tell() ));// Text + Footnote + HdFt as section end
3245 m_pMagicTable
->Finish( Fc2Cp( Strm().Tell() ),0);
3247 m_pFib
->m_fcMac
= Strm().Tell(); // End of all texts
3249 WriteFkpPlcUsw(); // FKP, PLC, ...
3252 void MSWordExportBase::AddLinkTarget(std::u16string_view rURL
)
3254 if( rURL
.empty() || rURL
[0] != '#' )
3257 OUString
aURL( BookmarkToWriter( rURL
.substr( 1 ) ) );
3258 sal_Int32 nPos
= aURL
.lastIndexOf( cMarkSeparator
);
3263 OUString sCmp
= aURL
.copy(nPos
+1).replaceAll(" ", "");
3264 if( sCmp
.isEmpty() )
3267 sCmp
= sCmp
.toAsciiLowerCase();
3268 if( sCmp
== "outline" )
3270 SwPosition
aPos(*m_pCurPam
->GetPoint());
3271 OUString
aName(BookmarkToWriter(aURL
.subView(0, nPos
)));
3272 // If we can find the outline this bookmark refers to
3273 // save the name of the bookmark and the
3274 // node index number of where it points to
3275 if( m_rDoc
.GotoOutline( aPos
, aName
) )
3276 m_aImplicitBookmarks
.emplace_back(aURL
, aPos
.GetNodeIndex());
3278 else if( sCmp
== "graphic" )
3280 OUString
aName(BookmarkToWriter(aURL
.subView(0, nPos
)));
3281 if (const SwFlyFrameFormat
* pFormat
= m_rDoc
.FindFlyByName(aName
, SwNodeType::Grf
))
3282 if (const SwNodeIndex
* pIdx
= pFormat
->GetContent().GetContentIdx())
3283 m_aImplicitBookmarks
.emplace_back(aURL
, pIdx
->GetNext()->GetIndex());
3285 else if( sCmp
== "frame" )
3287 OUString
aName(BookmarkToWriter(aURL
.subView(0, nPos
)));
3288 if (const SwFlyFrameFormat
* pFormat
= m_rDoc
.FindFlyByName(aName
, SwNodeType::Text
))
3289 if (const SwNodeIndex
* pIdx
= pFormat
->GetContent().GetContentIdx())
3290 m_aImplicitBookmarks
.emplace_back(aURL
, pIdx
->GetIndex() + 1);
3292 else if( sCmp
== "ole" )
3294 OUString
aName(BookmarkToWriter(aURL
.subView(0, nPos
)));
3295 if (const SwFlyFrameFormat
* pFormat
= m_rDoc
.FindFlyByName(aName
, SwNodeType::Ole
))
3296 if (const SwNodeIndex
* pIdx
= pFormat
->GetContent().GetContentIdx())
3297 m_aImplicitBookmarks
.emplace_back(aURL
, pIdx
->GetNext()->GetIndex());
3299 else if( sCmp
== "region" )
3301 OUString
aName(BookmarkToWriter(aURL
.subView(0, nPos
)));
3302 for (const SwSectionFormat
* pFormat
: m_rDoc
.GetSections())
3304 if (aName
== pFormat
->GetSection()->GetSectionName())
3306 if (const SwNodeIndex
* pIdx
= pFormat
->GetContent().GetContentIdx())
3308 m_aImplicitBookmarks
.emplace_back(aURL
, pIdx
->GetIndex() + 1);
3314 else if( sCmp
== "table" )
3316 OUString
aName(BookmarkToWriter(aURL
.subView(0, nPos
)));
3317 if (const SwTable
* pTable
= SwTable::FindTable(m_rDoc
.FindTableFormatByName(aName
)))
3318 if (const SwTableNode
* pTableNode
= pTable
->GetTabSortBoxes()[1]->GetSttNd()->FindTableNode())
3319 m_aImplicitBookmarks
.emplace_back(aURL
, pTableNode
->GetIndex() + 2);
3321 else if (sCmp
== "toxmark")
3323 OUString
const name(aURL
.copy(0, nPos
));
3324 OUString
const nameDecoded(INetURLObject::decode(name
,
3325 INetURLObject::DecodeMechanism::WithCharset
));
3326 if (const auto tmp
= sw::PrepareJumpToTOXMark(m_rDoc
, nameDecoded
))
3328 SwTOXMark
const* pMark(&tmp
->first
);
3329 for (sal_Int32 i
= 0; i
< tmp
->second
; ++i
)
3331 pMark
= &m_rDoc
.GotoTOXMark(*pMark
, TOX_SAME_NXT
, true);
3333 if (pMark
!= &tmp
->first
)
3335 m_TOXMarkBookmarksByURL
.emplace(aURL
, name
);
3336 m_TOXMarkBookmarksByTOXMark
.emplace(pMark
, nameDecoded
);
3342 void MSWordExportBase::CollectOutlineBookmarks(const SwDoc
&rDoc
)
3344 for (const SfxPoolItem
* pItem
: rDoc
.GetAttrPool().GetItemSurrogates(RES_TXTATR_INETFMT
))
3346 auto pINetFormat
= dynamic_cast<const SwFormatINetFormat
*>(pItem
);
3350 const SwTextINetFormat
* pTextAttr
= pINetFormat
->GetTextINetFormat();
3354 const SwTextNode
* pTextNd
= pTextAttr
->GetpTextNode();
3358 if (!pTextNd
->GetNodes().IsDocNodes())
3361 AddLinkTarget( pINetFormat
->GetValue() );
3364 for (const SfxPoolItem
* pItem
: rDoc
.GetAttrPool().GetItemSurrogates(RES_URL
))
3366 auto pURL
= dynamic_cast<const SwFormatURL
*>(pItem
);
3370 AddLinkTarget(pURL
->GetURL());
3371 const ImageMap
*pIMap
= pURL
->GetMap();
3375 for (size_t i
=0; i
< pIMap
->GetIMapObjectCount(); ++i
)
3377 const IMapObject
* pObj
= pIMap
->GetIMapObject(i
);
3380 AddLinkTarget( pObj
->GetURL() );
3387 const sal_uInt64 WW_BLOCKSIZE
= 0x200;
3389 ErrCode
EncryptRC4(msfilter::MSCodec_Std97
& rCtx
, SvStream
&rIn
, SvStream
&rOut
)
3391 sal_uInt64 nLen
= rIn
.TellEnd();
3394 sal_uInt8 in
[WW_BLOCKSIZE
];
3395 for (std::size_t nI
= 0, nBlock
= 0; nI
< nLen
; nI
+= WW_BLOCKSIZE
, ++nBlock
)
3397 std::size_t nBS
= std::min(nLen
- nI
, WW_BLOCKSIZE
);
3398 nBS
= rIn
.ReadBytes(in
, nBS
);
3399 if (!rCtx
.InitCipher(nBlock
)) {
3400 return ERRCODE_IO_NOTSUPPORTED
;
3402 rCtx
.Encode(in
, nBS
, in
, nBS
);
3403 rOut
.WriteBytes(in
, nBS
);
3405 return ERRCODE_NONE
;
3409 ErrCode
MSWordExportBase::ExportDocument( bool bWriteAll
)
3411 m_nCharFormatStart
= DEFAULT_STYLES_COUNT
;
3412 m_nFormatCollStart
= m_nCharFormatStart
+ m_rDoc
.GetCharFormats()->size() - 1;
3414 m_bStyDef
= m_bBreakBefore
= m_bOutKF
=
3415 m_bOutFlyFrameAttrs
= m_bOutPageDescs
= m_bOutTable
= m_bOutFirstPage
=
3416 m_bOutGrf
= m_bInWriteEscher
= m_bStartTOX
=
3417 m_bInWriteTOX
= false;
3419 m_bFootnoteAtTextEnd
= m_bEndAtTextEnd
= true;
3421 m_pParentFrame
= nullptr;
3422 m_pFlyOffset
= nullptr;
3423 m_eNewAnchorType
= RndStdIds::FLY_AT_PAGE
;
3424 m_nTextTyp
= TXT_MAINTEXT
;
3425 m_nStyleBeforeFly
= m_nLastFormatId
= 0;
3426 m_pStyAttr
= nullptr;
3427 m_pCurrentStyle
= nullptr;
3428 m_pOutFormatNode
= nullptr;
3429 m_pEscher
= nullptr;
3430 m_pRedlAuthors
= nullptr;
3435 sal_uInt32 nSvxMSDffOLEConvFlags
= 0;
3436 const SvtFilterOptions
& rOpt
= SvtFilterOptions::Get();
3437 if ( rOpt
.IsMath2MathType() )
3438 nSvxMSDffOLEConvFlags
|= OLE_STARMATH_2_MATHTYPE
;
3439 if ( rOpt
.IsWriter2WinWord() )
3440 nSvxMSDffOLEConvFlags
|= OLE_STARWRITER_2_WINWORD
;
3441 if ( rOpt
.IsCalc2Excel() )
3442 nSvxMSDffOLEConvFlags
|= OLE_STARCALC_2_EXCEL
;
3443 if ( rOpt
.IsImpress2PowerPoint() )
3444 nSvxMSDffOLEConvFlags
|= OLE_STARIMPRESS_2_POWERPOINT
;
3446 m_oOLEExp
.emplace( nSvxMSDffOLEConvFlags
);
3449 if ( !m_pOCXExp
&& m_rDoc
.GetDocShell() )
3450 m_pOCXExp
.reset(new SwMSConvertControls(m_rDoc
.GetDocShell(), m_pCurPam
.get()));
3452 // #i81405# - Collect anchored objects before changing the redline mode.
3453 m_aFrames
= GetFrames( m_rDoc
, bWriteAll
? nullptr : m_pOrigPam
);
3455 m_nOrigRedlineFlags
= m_rDoc
.getIDocumentRedlineAccess().GetRedlineFlags();
3457 SwRootFrame
const*const pLayout(m_rDoc
.getIDocumentLayoutAccess().GetCurrentLayout());
3458 m_bOrigShowChanges
= pLayout
== nullptr || !pLayout
->IsHideRedlines();
3460 if ( !m_rDoc
.getIDocumentRedlineAccess().GetRedlineTable().empty() )
3462 //restored to original state by SwWriter::Write
3463 m_rDoc
.getIDocumentRedlineAccess().SetRedlineFlags(m_nOrigRedlineFlags
|
3464 RedlineFlags::ShowDelete
|
3465 RedlineFlags::ShowInsert
);
3468 // fix the SwPositions in m_aFrames after SetRedlineFlags
3469 UpdateFramePositions(m_aFrames
);
3471 m_aFontHelper
.InitFontTable(m_rDoc
);
3472 GatherChapterFields();
3474 CollectOutlineBookmarks(m_rDoc
);
3476 // make unique OrdNums (Z-Order) for all drawing-/fly Objects
3477 if ( m_rDoc
.getIDocumentDrawModelAccess().GetDrawModel() )
3478 m_rDoc
.getIDocumentDrawModelAccess().GetDrawModel()->GetPage( 0 )->RecalcObjOrdNums();
3480 ErrCode err
= ExportDocument_Impl();
3484 // park m_pCurPam in a "safe place" now that document is fully exported
3485 // before toggling redline mode to avoid ~SwContentIndexReg assert e.g. export
3486 // ooo103014-1.odt to .doc
3487 // park m_pOrigPam as well, as needed for exporting abi9915-1.odt to doc
3488 m_pOrigPam
->DeleteMark();
3489 m_pOrigPam
->GetPoint()->Assign(m_rDoc
.GetNodes().GetEndOfContent());
3490 static_cast<SwPaM
&>(*m_pCurPam
) = *m_pOrigPam
;
3492 m_rDoc
.getIDocumentRedlineAccess().SetRedlineFlags(m_nOrigRedlineFlags
);
3497 bool SwWW8Writer::InitStd97CodecUpdateMedium( ::msfilter::MSCodec_Std97
& rCodec
)
3499 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
3503 const SfxUnoAnyItem
* pEncryptionDataItem
= SfxItemSet::GetItem
<SfxUnoAnyItem
>(mpMedium
->GetItemSet(), SID_ENCRYPTIONDATA
, false);
3504 if ( pEncryptionDataItem
&& ( pEncryptionDataItem
->GetValue() >>= aEncryptionData
) && !rCodec
.InitCodec( aEncryptionData
) )
3506 OSL_ENSURE( false, "Unexpected EncryptionData!" );
3507 aEncryptionData
.realloc( 0 );
3510 if ( !aEncryptionData
.hasElements() )
3512 // try to generate the encryption data based on password
3513 const SfxStringItem
* pPasswordItem
= SfxItemSet::GetItem
<SfxStringItem
>(mpMedium
->GetItemSet(), SID_PASSWORD
, false);
3514 if ( pPasswordItem
&& !pPasswordItem
->GetValue().isEmpty() && pPasswordItem
->GetValue().getLength() <= 15 )
3516 // Generate random number with a seed of time as salt.
3517 rtlRandomPool aRandomPool
= rtl_random_createPool ();
3518 sal_uInt8 pDocId
[ 16 ];
3519 rtl_random_getBytes( aRandomPool
, pDocId
, 16 );
3521 rtl_random_destroyPool( aRandomPool
);
3523 sal_uInt16 aPassword
[16] = {};
3525 const OUString
& sPassword(pPasswordItem
->GetValue());
3526 for ( sal_Int32 nChar
= 0; nChar
< sPassword
.getLength(); ++nChar
)
3527 aPassword
[nChar
] = sPassword
[nChar
];
3529 rCodec
.InitKey( aPassword
, pDocId
);
3530 aEncryptionData
= rCodec
.GetEncryptionData();
3532 mpMedium
->GetItemSet()->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA
, uno::Any( aEncryptionData
) ) );
3536 if ( aEncryptionData
.hasElements() )
3537 mpMedium
->GetItemSet()->ClearItem( SID_PASSWORD
);
3540 // nonempty encryption data means here that the codec was successfully initialized
3541 return aEncryptionData
.hasElements();
3544 ErrCode
WW8Export::ExportDocument_Impl()
3548 m_pFib
.reset(new WW8Fib(8, m_bDot
));
3550 tools::SvRef
<SotStorageStream
> xWwStrm( GetWriter().GetStorage().OpenSotStream( m_aMainStg
) );
3551 tools::SvRef
<SotStorageStream
> xTableStrm( xWwStrm
), xDataStrm( xWwStrm
);
3552 xWwStrm
->SetBufferSize( 32768 );
3554 m_pFib
->m_fWhichTableStm
= true;
3555 xTableStrm
= GetWriter().GetStorage().OpenSotStream(SL::a1Table
, StreamMode::STD_WRITE
);
3556 xDataStrm
= GetWriter().GetStorage().OpenSotStream(SL::aData
, StreamMode::STD_WRITE
);
3558 xDataStrm
->SetBufferSize( 32768 ); // for graphics
3559 xTableStrm
->SetBufferSize( 16384 ); // for the Font-/Style-Table, etc.
3561 xTableStrm
->SetEndian( SvStreamEndian::LITTLE
);
3562 xDataStrm
->SetEndian( SvStreamEndian::LITTLE
);
3564 GetWriter().SetStream( xWwStrm
.get() );
3565 m_pTableStrm
= xTableStrm
.get();
3566 m_pDataStrm
= xDataStrm
.get();
3568 Strm().SetEndian( SvStreamEndian::LITTLE
);
3570 utl::TempFileFast aTempMain
;
3571 utl::TempFileFast aTempTable
;
3572 utl::TempFileFast aTempData
;
3574 msfilter::MSCodec_Std97 aCtx
;
3575 bool bEncrypt
= GetWriter().InitStd97CodecUpdateMedium(aCtx
);
3578 GetWriter().SetStream(
3579 aTempMain
.GetStream( StreamMode::READWRITE
| StreamMode::SHARE_DENYWRITE
) );
3581 m_pTableStrm
= aTempTable
.GetStream( StreamMode::READWRITE
| StreamMode::SHARE_DENYWRITE
);
3583 m_pDataStrm
= aTempData
.GetStream( StreamMode::READWRITE
| StreamMode::SHARE_DENYWRITE
);
3585 sal_uInt8
const aRC4EncryptionHeader
[ 52 ] = {0};
3586 m_pTableStrm
->WriteBytes(aRC4EncryptionHeader
, 52);
3589 // Default: "Standard"
3590 m_pSepx
.reset(new WW8_WrPlcSepx( *this )); // Sections/headers/footers
3592 m_pFootnote
.reset(new WW8_WrPlcFootnoteEdn( TXT_FTN
)); // Footnotes
3593 m_pEdn
.reset(new WW8_WrPlcFootnoteEdn( TXT_EDN
)); // Endnotes
3594 m_pAtn
.reset(new WW8_WrPlcAnnotations
); // PostIts
3595 m_pFactoids
.reset(new WW8_WrtFactoids
); // Smart tags.
3596 m_pTextBxs
.reset(new WW8_WrPlcTextBoxes( TXT_TXTBOX
));
3597 m_pHFTextBxs
.reset(new WW8_WrPlcTextBoxes( TXT_HFTXTBOX
));
3599 m_pSdrObjs
.reset(new MainTextPlcDrawObj
); // Draw-/Fly-Objects for main text
3600 m_pHFSdrObjs
.reset(new HdFtPlcDrawObj
); // Draw-/Fly-Objects for header/footer
3602 m_pBkmks
.reset(new WW8_WrtBookmarks
); // Bookmarks
3603 GetWriter().CreateBookmarkTable();
3605 m_pPapPlc
.reset(new WW8_WrPlcPn( *this, PAP
, m_pFib
->m_fcMin
));
3606 m_pChpPlc
.reset(new WW8_WrPlcPn( *this, CHP
, m_pFib
->m_fcMin
));
3607 m_pO
.reset(new ww::bytes
);
3608 m_pStyles
.reset(new MSWordStyles( *this ));
3609 m_pFieldMain
.reset(new WW8_WrPlcField( 2, TXT_MAINTEXT
));
3610 m_pFieldHdFt
.reset(new WW8_WrPlcField( 2, TXT_HDFT
));
3611 m_pFieldFootnote
.reset(new WW8_WrPlcField( 2, TXT_FTN
));
3612 m_pFieldEdn
.reset(new WW8_WrPlcField( 2, TXT_EDN
));
3613 m_pFieldAtn
.reset(new WW8_WrPlcField( 2, TXT_ATN
));
3614 m_pFieldTextBxs
.reset(new WW8_WrPlcField( 2, TXT_TXTBOX
));
3615 m_pFieldHFTextBxs
.reset(new WW8_WrPlcField( 2, TXT_HFTXTBOX
));
3617 m_pMagicTable
.reset(new WW8_WrMagicTable
);
3619 m_pGrf
.reset(new SwWW8WrGrf( *this ));
3620 m_pPiece
.reset(new WW8_WrPct( m_pFib
->m_fcMin
));
3621 m_pDop
.reset(new WW8Dop
);
3623 m_pDop
->fRevMarking
= bool( RedlineFlags::On
& m_nOrigRedlineFlags
);
3624 SwRootFrame
const*const pLayout(m_rDoc
.getIDocumentLayoutAccess().GetCurrentLayout());
3625 m_pDop
->fRMView
= pLayout
== nullptr || !pLayout
->IsHideRedlines();
3626 m_pDop
->fRMPrint
= m_pDop
->fRMView
;
3628 // set AutoHyphenation flag if found in default para style
3629 const SvxHyphenZoneItem
* pItem
;
3630 SwTextFormatColl
* pStdTextFormatColl
=
3631 m_rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD
, false);
3632 if (pStdTextFormatColl
&& (pItem
= pStdTextFormatColl
->GetItemIfSet(
3633 RES_PARATR_HYPHENZONE
, false)))
3635 m_pDop
->fAutoHyphen
= pItem
->IsHyphen();
3640 ErrCode err
= ERRCODE_NONE
;
3643 SvStream
*pStrmTemp
, *pTableStrmTemp
, *pDataStrmTemp
;
3644 pStrmTemp
= xWwStrm
.get();
3645 pTableStrmTemp
= xTableStrm
.get();
3646 pDataStrmTemp
= xDataStrm
.get();
3648 if ( pDataStrmTemp
&& pDataStrmTemp
!= pStrmTemp
) {
3649 err
= EncryptRC4(aCtx
, *m_pDataStrm
, *pDataStrmTemp
);
3650 if (err
!= ERRCODE_NONE
) {
3655 err
= EncryptRC4(aCtx
, *m_pTableStrm
, *pTableStrmTemp
);
3656 if (err
!= ERRCODE_NONE
) {
3660 // Write Unencrypted Header 52 bytes to the start of the table stream
3661 // EncryptionVersionInfo (4 bytes): A Version structure where Version.vMajor MUST be 0x0001, and Version.vMinor MUST be 0x0001.
3662 pTableStrmTemp
->Seek( 0 );
3663 pTableStrmTemp
->WriteUInt32( 0x10001 ); // nEncType
3665 sal_uInt8 pDocId
[16];
3666 aCtx
.GetDocId( pDocId
);
3668 sal_uInt8 pSaltData
[16];
3669 sal_uInt8 pSaltDigest
[16];
3670 aCtx
.GetEncryptKey( pDocId
, pSaltData
, pSaltDigest
);
3672 pTableStrmTemp
->WriteBytes(pDocId
, 16);
3673 pTableStrmTemp
->WriteBytes(pSaltData
, 16);
3674 pTableStrmTemp
->WriteBytes(pSaltDigest
, 16);
3676 err
= EncryptRC4(aCtx
, GetWriter().Strm(), *pStrmTemp
);
3677 if (err
!= ERRCODE_NONE
) {
3681 // Write Unencrypted Fib 68 bytes to the start of the workdocument stream
3682 m_pFib
->m_fEncrypted
= true; // fEncrypted indicates the document is encrypted.
3683 m_pFib
->m_fObfuscated
= false; // Must be 0 for RC4.
3684 m_pFib
->m_nHash
= 0x34; // encrypt header bytes count of table stream.
3685 m_pFib
->m_nKey
= 0; // lkey2 must be 0 for RC4.
3687 pStrmTemp
->Seek( 0 );
3688 m_pFib
->WriteHeader( *pStrmTemp
);
3693 m_pMagicTable
.reset();
3694 m_pFieldFootnote
.reset();
3695 m_pFieldTextBxs
.reset();
3696 m_pFieldHFTextBxs
.reset();
3697 m_pFieldAtn
.reset();
3698 m_pFieldEdn
.reset();
3699 m_pFieldHdFt
.reset();
3700 m_pFieldMain
.reset();
3707 m_pRedlAuthors
.reset();
3709 m_pHFSdrObjs
.reset();
3711 m_pHFTextBxs
.reset();
3714 m_pFootnote
.reset();
3719 GetWriter().SetStream( nullptr );
3721 xWwStrm
->SetBufferSize( 0 );
3722 xTableStrm
->SetBufferSize( 0 );
3723 xDataStrm
->SetBufferSize( 0 );
3724 if( 0 == m_pDataStrm
->Seek( STREAM_SEEK_TO_END
))
3727 m_pDataStrm
= nullptr;
3728 GetWriter().GetStorage().Remove(SL::aData
);
3734 void WW8Export::PrepareStorage()
3736 static const sal_uInt8 pData
[] =
3738 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
3739 0xFF, 0xFF, 0xFF, 0xFF, 0x06, 0x09, 0x02, 0x00,
3740 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,
3741 0x00, 0x00, 0x00, 0x46,
3743 0x18, 0x00, 0x00, 0x00,
3744 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f',
3745 't', ' ', 'W', 'o', 'r', 'd', '-', 'D',
3746 'o', 'k', 'u', 'm', 'e', 'n', 't', 0x0,
3748 0x0A, 0x00, 0x00, 0x00,
3749 'M', 'S', 'W', 'o', 'r', 'd', 'D', 'o',
3752 0x10, 0x00, 0x00, 0x00,
3753 'W', 'o', 'r', 'd', '.', 'D', 'o', 'c',
3754 'u', 'm', 'e', 'n', 't', '.', '8', 0x0,
3756 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00,
3757 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
3760 SvGlobalName
aGName(MSO_WW8_CLASSID
);
3761 GetWriter().GetStorage().SetClass(
3762 aGName
, SotClipboardFormatId::NONE
, "Microsoft Word-Document");
3763 tools::SvRef
<SotStorageStream
> xStor( GetWriter().GetStorage().OpenSotStream(sCompObj
) );
3764 xStor
->WriteBytes(pData
, sizeof(pData
));
3766 SwDocShell
* pDocShell
= m_rDoc
.GetDocShell ();
3767 OSL_ENSURE(pDocShell
, "no SwDocShell");
3769 if (!pDocShell
) return;
3771 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
3772 pDocShell
->GetModel(), uno::UNO_QUERY_THROW
);
3773 uno::Reference
<document::XDocumentProperties
> xDocProps(
3774 xDPS
->getDocumentProperties());
3775 OSL_ENSURE(xDocProps
.is(), "DocumentProperties is null");
3777 if (!xDocProps
.is())
3780 if ( SvtFilterOptions::Get().IsEnableWordPreview() )
3782 std::shared_ptr
<GDIMetaFile
> xMetaFile
=
3783 pDocShell
->GetPreviewMetaFile();
3784 uno::Sequence
<sal_Int8
> metaFile(
3785 sfx2::convertMetaFile(xMetaFile
.get()));
3786 sfx2::SaveOlePropertySet(xDocProps
, &GetWriter().GetStorage(), &metaFile
);
3789 sfx2::SaveOlePropertySet( xDocProps
, &GetWriter().GetStorage() );
3792 ErrCode
SwWW8Writer::WriteStorage()
3794 tools::SvRef
<SotStorage
> pOrigStg
;
3795 uno::Reference
< packages::XPackageEncryption
> xPackageEncryption
;
3796 std::shared_ptr
<SvStream
> pSotStorageStream
;
3797 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
3800 // Check for specific encryption requests
3801 const SfxUnoAnyItem
* pEncryptionDataItem
= SfxItemSet::GetItem
<SfxUnoAnyItem
>(mpMedium
->GetItemSet(), SID_ENCRYPTIONDATA
, false);
3802 if (pEncryptionDataItem
&& (pEncryptionDataItem
->GetValue() >>= aEncryptionData
))
3804 ::comphelper::SequenceAsHashMap
aHashData(aEncryptionData
);
3805 OUString sCryptoType
= aHashData
.getUnpackedValueOrDefault("CryptoType", OUString());
3807 if (sCryptoType
.getLength())
3809 uno::Reference
<uno::XComponentContext
> xComponentContext(comphelper::getProcessComponentContext());
3810 uno::Sequence
<uno::Any
> aArguments
{
3811 uno::Any(beans::NamedValue("Binary", uno::Any(true))) };
3812 xPackageEncryption
.set(
3813 xComponentContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
3814 "com.sun.star.comp.oox.crypto." + sCryptoType
, aArguments
, xComponentContext
), uno::UNO_QUERY
);
3816 if (xPackageEncryption
)
3818 // We have an encryptor
3819 // Create new temporary storage for content
3821 pSotStorageStream
= std::make_shared
<SvMemoryStream
>();
3822 m_pStg
= new SotStorage(*pSotStorageStream
);
3828 ErrCode nErrorCode
= WriteStorageImpl();
3830 if (xPackageEncryption
)
3832 assert(pSotStorageStream
&& m_pStg
&& "because always set if xPackageEncryption was set");
3835 pSotStorageStream
->Seek(0);
3837 // Encrypt data written into temporary storage
3838 xPackageEncryption
->setupEncryption(aEncryptionData
);
3840 uno::Reference
<io::XInputStream
> xInputStream(new utl::OSeekableInputStreamWrapper(pSotStorageStream
.get(), false));
3841 uno::Sequence
<beans::NamedValue
> aStreams
= xPackageEncryption
->encrypt(xInputStream
);
3844 for (const beans::NamedValue
& aStreamData
: std::as_const(aStreams
))
3846 // To avoid long paths split and open substorages recursively
3847 // Splitting paths manually, since comphelper::string::split is trimming special characters like \0x01, \0x09
3848 tools::SvRef
<SotStorage
> pStorage
= m_pStg
.get();
3851 while (pStorage
&& idx
>= 0)
3853 OUString sPathElem
= aStreamData
.Name
.getToken(0, L
'/', idx
);
3854 if (!sPathElem
.isEmpty())
3858 sFileName
= sPathElem
;
3862 pStorage
= pStorage
->OpenSotStorage(sPathElem
);
3871 nErrorCode
= ERRCODE_IO_GENERAL
;
3875 tools::SvRef
<SotStorageStream
> pStream
= pStorage
->OpenSotStream(sFileName
);
3878 nErrorCode
= ERRCODE_IO_GENERAL
;
3881 uno::Sequence
<sal_Int8
> aStreamContent
;
3882 aStreamData
.Value
>>= aStreamContent
;
3883 size_t nBytesWritten
= pStream
->WriteBytes(aStreamContent
.getArray(), aStreamContent
.getLength());
3884 if (nBytesWritten
!= static_cast<size_t>(aStreamContent
.getLength()))
3886 nErrorCode
= ERRCODE_IO_CANTWRITE
;
3894 ErrCode
SwWW8Writer::WriteStorageImpl()
3896 // #i34818# - update layout (if present), for SwWriteTable
3897 SwViewShell
* pViewShell
= m_pDoc
->getIDocumentLayoutAccess().GetCurrentViewShell();
3898 if( pViewShell
!= nullptr )
3899 pViewShell
->CalcLayout();
3901 SwNodeOffset nMaxNode
= m_pDoc
->GetNodes().Count();
3902 ::StartProgress( STR_STATSTR_W4WWRITE
, 0, sal_Int32(nMaxNode
), m_pDoc
->GetDocShell() );
3904 // Respect table at the beginning of the document
3906 SwTableNode
* pTNd
= m_pCurrentPam
->GetPointNode().FindTableNode();
3907 if( pTNd
&& m_bWriteAll
)
3908 // start with the table node !!
3909 m_pCurrentPam
->GetPoint()->Assign(*pTNd
);
3912 // Do the actual export
3913 ErrCode err
= ERRCODE_NONE
;
3915 bool bDot
= mpMedium
->GetFilter()->GetName().endsWith("Vorlage");
3916 WW8Export
aExport(this, *m_pDoc
, m_pCurrentPam
, m_pOrigPam
, bDot
);
3917 m_pExport
= &aExport
;
3918 err
= aExport
.ExportDocument( m_bWriteAll
);
3919 m_pExport
= nullptr;
3922 ::EndProgress( m_pDoc
->GetDocShell() );
3926 ErrCode
SwWW8Writer::WriteMedium( SfxMedium
& )
3928 return WriteStorage();
3931 ErrCode
SwWW8Writer::Write( SwPaM
& rPaM
, SfxMedium
& rMed
,
3932 const OUString
* pFileName
)
3935 ErrCode nRet
= StgWriter::Write( rPaM
, rMed
, pFileName
);
3940 MSWordExportBase::MSWordExportBase( SwDoc
& rDocument
, std::shared_ptr
<SwUnoCursor
> & pCurrentPam
, SwPaM
* pOriginalPam
)
3941 : m_aMainStg(sMainStream
)
3943 , m_pTopNodeOfHdFtPage(nullptr)
3944 , m_pTableInfo(std::make_shared
<ww8::WW8TableInfo
>())
3945 , m_nCharFormatStart(0)
3946 , m_nFormatCollStart(0)
3947 , m_nStyleBeforeFly(0)
3948 , m_nLastFormatId(0)
3951 , m_nOrigRedlineFlags(RedlineFlags::NONE
)
3952 , m_bOrigShowChanges(true)
3953 , m_pCurrentPageDesc(nullptr)
3954 , m_pPreviousSectionPageDesc(nullptr)
3955 , m_bFirstTOCNodeWithSection(false)
3956 , m_pChpIter(nullptr)
3957 , m_pParentFrame(nullptr)
3958 , m_pFlyOffset(nullptr)
3959 , m_eNewAnchorType(RndStdIds::FLY_AS_CHAR
)
3960 , m_pStyAttr(nullptr)
3961 , m_pOutFormatNode(nullptr)
3962 , m_pCurrentStyle(nullptr)
3963 , m_pEscher(nullptr)
3966 , m_bBreakBefore(false)
3968 , m_bOutFlyFrameAttrs(false)
3969 , m_bOutPageDescs(false)
3970 , m_bOutFirstPage(false)
3971 , m_bOutTable(false)
3973 , m_bInWriteEscher(false)
3974 , m_bStartTOX(false)
3975 , m_bInWriteTOX(false)
3976 , m_bFootnoteAtTextEnd(false)
3977 , m_bEndAtTextEnd(false)
3980 , m_bSubstituteBullets(true)
3981 , m_bTabInTOC(false)
3982 , m_bHideTabLeaderAndPageNumbers(false)
3983 , m_bExportModeRTF(false)
3984 , m_bFontSizeWritten(false)
3985 , m_bAddFootnoteTab(false)
3987 , m_nCurStart(pCurrentPam
->GetPoint()->GetNodeIndex())
3988 , m_nCurEnd(pCurrentPam
->GetMark()->GetNodeIndex())
3989 , m_pCurPam(pCurrentPam
)
3990 , m_pOrigPam(pOriginalPam
)
3994 MSWordExportBase::~MSWordExportBase()
3996 if (m_pUsedNumTable
) // all used NumRules
3998 // clear the part of the list array that was copied from the document
3999 // - it's an auto delete array, so the rest of the array which are
4000 // duplicated lists that were added during the export will be deleted.
4001 m_pUsedNumTable
->erase(m_pUsedNumTable
->begin(), m_pUsedNumTable
->begin() + m_pUsedNumTable
->size() - m_nUniqueList
);
4002 m_pUsedNumTable
.reset();
4008 WW8Export::WW8Export( SwWW8Writer
*pWriter
,
4009 SwDoc
& rDocument
, std::shared_ptr
<SwUnoCursor
> & pCurrentPam
, SwPaM
* pOriginalPam
,
4011 : MSWordExportBase( rDocument
, pCurrentPam
, pOriginalPam
)
4012 , m_pTableStrm(nullptr)
4013 , m_pDataStrm(nullptr)
4015 , m_pWriter(pWriter
)
4016 , m_pAttrOutput(new WW8AttributeOutput(*this))
4020 WW8Export::~WW8Export()
4024 AttributeOutputBase
& WW8Export::AttrOutput() const
4026 return *m_pAttrOutput
;
4029 MSWordSections
& WW8Export::Sections() const
4034 SwWW8Writer::SwWW8Writer(std::u16string_view rFltName
, const OUString
& rBaseURL
)
4035 : m_pExport( nullptr ),
4038 assert(rFltName
== FILTER_WW8
); // WW6/7 export was removed
4040 SetBaseURL( rBaseURL
);
4043 SwWW8Writer::~SwWW8Writer()
4047 extern "C" SAL_DLLPUBLIC_EXPORT sal_uInt32
SaveOrDelMSVBAStorage_ww8( SfxObjectShell
& rDoc
, SotStorage
& rStor
, sal_Bool bSaveInto
, const OUString
& rStorageName
)
4049 SvxImportMSVBasic
aTmp( rDoc
, rStor
);
4050 return sal_uInt32(aTmp
.SaveOrDelMSVBAStorage( bSaveInto
, rStorageName
));
4053 extern "C" SAL_DLLPUBLIC_EXPORT
void ExportDOC( std::u16string_view rFltName
, const OUString
& rBaseURL
, WriterRef
& xRet
)
4055 xRet
= new SwWW8Writer( rFltName
, rBaseURL
);
4058 extern "C" SAL_DLLPUBLIC_EXPORT sal_uInt32
GetSaveWarningOfMSVBAStorage_ww8( SfxObjectShell
&rDocS
)
4060 return sal_uInt32(SvxImportMSVBasic::GetSaveWarningOfMSVBAStorage( rDocS
));
4063 bool WW8_WrPlcFootnoteEdn::WriteText( WW8Export
& rWrt
)
4066 if (TXT_FTN
== m_nTyp
)
4068 bRet
= WriteGenericText( rWrt
, TXT_FTN
, rWrt
.m_pFib
->m_ccpFootnote
);
4069 rWrt
.m_pFieldFootnote
->Finish( rWrt
.Fc2Cp( rWrt
.Strm().Tell() ),
4070 rWrt
.m_pFib
->m_ccpText
);
4074 bRet
= WriteGenericText( rWrt
, TXT_EDN
, rWrt
.m_pFib
->m_ccpEdn
);
4075 rWrt
.m_pFieldEdn
->Finish( rWrt
.Fc2Cp( rWrt
.Strm().Tell() ),
4076 rWrt
.m_pFib
->m_ccpText
+ rWrt
.m_pFib
->m_ccpFootnote
4077 + rWrt
.m_pFib
->m_ccpHdr
+ rWrt
.m_pFib
->m_ccpAtn
);
4082 void WW8_WrPlcFootnoteEdn::WritePlc( WW8Export
& rWrt
) const
4084 if( TXT_FTN
== m_nTyp
)
4086 WriteGenericPlc( rWrt
, TXT_FTN
, rWrt
.m_pFib
->m_fcPlcffndText
,
4087 rWrt
.m_pFib
->m_lcbPlcffndText
, rWrt
.m_pFib
->m_fcPlcffndRef
,
4088 rWrt
.m_pFib
->m_lcbPlcffndRef
);
4092 WriteGenericPlc( rWrt
, TXT_EDN
, rWrt
.m_pFib
->m_fcPlcfendText
,
4093 rWrt
.m_pFib
->m_lcbPlcfendText
, rWrt
.m_pFib
->m_fcPlcfendRef
,
4094 rWrt
.m_pFib
->m_lcbPlcfendRef
);
4098 bool WW8_WrPlcAnnotations::WriteText( WW8Export
& rWrt
)
4100 bool bRet
= WriteGenericText( rWrt
, TXT_ATN
, rWrt
.m_pFib
->m_ccpAtn
);
4101 rWrt
.m_pFieldAtn
->Finish( rWrt
.Fc2Cp( rWrt
.Strm().Tell() ),
4102 rWrt
.m_pFib
->m_ccpText
+ rWrt
.m_pFib
->m_ccpFootnote
4103 + rWrt
.m_pFib
->m_ccpHdr
);
4107 void WW8_WrPlcAnnotations::WritePlc( WW8Export
& rWrt
) const
4109 WriteGenericPlc( rWrt
, TXT_ATN
, rWrt
.m_pFib
->m_fcPlcfandText
,
4110 rWrt
.m_pFib
->m_lcbPlcfandText
, rWrt
.m_pFib
->m_fcPlcfandRef
,
4111 rWrt
.m_pFib
->m_lcbPlcfandRef
);
4114 void WW8_WrPlcTextBoxes::WritePlc( WW8Export
& rWrt
) const
4116 if( TXT_TXTBOX
== m_nTyp
)
4118 WriteGenericPlc( rWrt
, m_nTyp
, rWrt
.m_pFib
->m_fcPlcftxbxBkd
,
4119 rWrt
.m_pFib
->m_lcbPlcftxbxBkd
, rWrt
.m_pFib
->m_fcPlcftxbxText
,
4120 rWrt
.m_pFib
->m_lcbPlcftxbxText
);
4124 WriteGenericPlc( rWrt
, m_nTyp
, rWrt
.m_pFib
->m_fcPlcfHdrtxbxBkd
,
4125 rWrt
.m_pFib
->m_lcbPlcfHdrtxbxBkd
, rWrt
.m_pFib
->m_fcPlcfHdrtxbxText
,
4126 rWrt
.m_pFib
->m_lcbPlcfHdrtxbxText
);
4130 void WW8Export::RestoreMacroCmds()
4132 m_pFib
->m_fcCmds
= m_pTableStrm
->Tell();
4134 uno::Reference
< embed::XStorage
> xSrcRoot(m_rDoc
.GetDocShell()->GetStorage());
4137 uno::Reference
< io::XStream
> xSrcStream
=
4138 xSrcRoot
->openStreamElement( SL::aMSMacroCmds
, embed::ElementModes::READ
);
4139 std::unique_ptr
<SvStream
> pStream
= ::utl::UcbStreamHelper::CreateStream( xSrcStream
);
4141 if ( pStream
&& ERRCODE_NONE
== pStream
->GetError())
4143 m_pFib
->m_lcbCmds
= pStream
->TellEnd();
4146 std::unique_ptr
<sal_uInt8
[]> pBuffer( new sal_uInt8
[m_pFib
->m_lcbCmds
] );
4147 bool bReadOk
= checkRead(*pStream
, pBuffer
.get(), m_pFib
->m_lcbCmds
);
4149 m_pTableStrm
->WriteBytes(pBuffer
.get(), m_pFib
->m_lcbCmds
);
4152 catch ( const uno::Exception
& )
4157 m_pFib
->m_lcbCmds
= m_pTableStrm
->Tell() - m_pFib
->m_fcCmds
;
4160 void WW8SHDLong::Write( WW8Export
& rExport
)
4162 rExport
.InsUInt32( m_cvFore
);
4163 rExport
.InsUInt32( m_cvBack
);
4164 rExport
.InsUInt16( 0 ); // ipat
4167 void WW8Export::WriteFormData( const ::sw::mark::IFieldmark
& rFieldmark
)
4169 const ::sw::mark::IFieldmark
* pFieldmark
= &rFieldmark
;
4170 const ::sw::mark::ICheckboxFieldmark
* pAsCheckbox
= dynamic_cast< const ::sw::mark::ICheckboxFieldmark
* >( pFieldmark
);
4172 if ( ! ( rFieldmark
.GetFieldname() == ODF_FORMTEXT
||
4173 rFieldmark
.GetFieldname() == ODF_FORMDROPDOWN
||
4174 rFieldmark
.GetFieldname() == ODF_FORMCHECKBOX
) )
4176 SAL_WARN( "sw.ww8", "unknown field type" );
4180 int type
= 0; // TextFieldmark
4183 if ( rFieldmark
.GetFieldname() == ODF_FORMDROPDOWN
)
4186 OUString ffname
= rFieldmark
.GetName();
4187 if (ffname
.getLength() > 20)
4188 ffname
= ffname
.copy(0, 20);
4190 sal_uInt64 nDataStt
= m_pDataStrm
->Tell();
4191 m_pChpPlc
->AppendFkpEntry(Strm().Tell());
4194 static sal_uInt8 aArr1
[] =
4196 0x03, 0x6a, 0,0,0,0, // sprmCPicLocation
4198 0x06, 0x08, 0x01, // sprmCFData
4199 0x55, 0x08, 0x01, // sprmCFSpec
4200 0x02, 0x08, 0x01 // sprmCFFieldVanish
4202 sal_uInt8
* pDataAdr
= aArr1
+ 2;
4203 Set_UInt32(pDataAdr
, nDataStt
);
4205 m_pChpPlc
->AppendFkpEntry( Strm().Tell(), sizeof( aArr1
), aArr1
);
4213 FFDataHeader() : version( 0xFFFFFFFF ), bits(0), cch(0), hps(0) {}
4216 FFDataHeader aFieldHeader
;
4217 aFieldHeader
.bits
|= (type
& 0x03);
4219 sal_Int32 ffres
= 0; // rFieldmark.GetFFRes();
4220 if ( pAsCheckbox
&& pAsCheckbox
->IsChecked() )
4222 else if ( type
== 2 )
4224 ::sw::mark::IFieldmark::parameter_map_t::const_iterator pResParameter
= rFieldmark
.GetParameters()->find(ODF_FORMDROPDOWN_RESULT
);
4225 if(pResParameter
!= rFieldmark
.GetParameters()->end())
4226 pResParameter
->second
>>= ffres
;
4230 aFieldHeader
.bits
|= ( (ffres
<<2) & 0x7C );
4234 OUString ffhelptext
= rFieldmark
.GetFieldHelptext();
4235 if ( ffhelptext
.getLength() > 255 )
4236 ffhelptext
= ffhelptext
.copy(0, 255);
4237 OUString ffstattext
;
4238 OUString ffentrymcr
;
4241 ::sw::mark::IFieldmark::parameter_map_t::const_iterator pParameter
4242 = rFieldmark
.GetParameters()->find("Type");
4243 if (type
== 0) // iTypeText
4245 sal_uInt16 nType
= 0;
4246 if ( pParameter
!= rFieldmark
.GetParameters()->end() )
4249 pParameter
->second
>>= aType
;
4250 if ( aType
== "number" ) nType
= 1;
4251 else if ( aType
== "date" ) nType
= 2;
4252 else if ( aType
== "currentTime" ) nType
= 3;
4253 else if ( aType
== "currentDate" ) nType
= 4;
4254 else if ( aType
== "calculated" ) nType
= 5;
4255 aFieldHeader
.bits
|= nType
<<11; // FFDataBits-F 00111000 00000000
4258 if ( nType
< 3 || nType
== 5 ) // not currentTime or currentDate
4260 pParameter
= rFieldmark
.GetParameters()->find("Content");
4261 if ( pParameter
!= rFieldmark
.GetParameters()->end() )
4263 OUString aDefaultText
;
4264 pParameter
->second
>>= aDefaultText
;
4265 const sal_Int32 nLen
= std::min( sal_Int32(255), aDefaultText
.getLength() );
4266 ffdeftext
= aDefaultText
.copy (0, nLen
);
4270 pParameter
= rFieldmark
.GetParameters()->find("MaxLength");
4271 if ( pParameter
!= rFieldmark
.GetParameters()->end() )
4273 sal_uInt16 nLength
= 0;
4274 pParameter
->second
>>= nLength
;
4275 nLength
= std::min( sal_uInt16(32767), nLength
);
4276 aFieldHeader
.cch
= nLength
;
4279 pParameter
= rFieldmark
.GetParameters()->find("Format");
4280 if ( pParameter
!= rFieldmark
.GetParameters()->end() )
4283 pParameter
->second
>>= aFormat
;
4284 const sal_Int32 nLen
= std::min( sal_Int32(64), aFormat
.getLength() );
4285 ffformat
= aFormat
.copy(0, nLen
);
4289 pParameter
= rFieldmark
.GetParameters()->find("Help"); //help
4290 if ( ffhelptext
.isEmpty() && pParameter
!= rFieldmark
.GetParameters()->end() )
4293 pParameter
->second
>>= aHelpText
;
4294 const sal_Int32 nLen
= std::min( sal_Int32(255), aHelpText
.getLength() );
4295 ffhelptext
= aHelpText
.copy (0, nLen
);
4297 if ( !ffhelptext
.isEmpty() )
4298 aFieldHeader
.bits
|= 0x1<<7;
4300 pParameter
= rFieldmark
.GetParameters()->find("Description"); // doc tooltip
4301 if ( pParameter
== rFieldmark
.GetParameters()->end() )
4302 pParameter
= rFieldmark
.GetParameters()->find("Hint"); //docx tooltip
4303 if ( pParameter
!= rFieldmark
.GetParameters()->end() )
4305 OUString aStatusText
;
4306 pParameter
->second
>>= aStatusText
;
4307 const sal_Int32 nLen
= std::min( sal_Int32(138), aStatusText
.getLength() );
4308 ffstattext
= aStatusText
.copy (0, nLen
);
4310 if ( !ffstattext
.isEmpty() )
4311 aFieldHeader
.bits
|= 0x1<<8;
4313 pParameter
= rFieldmark
.GetParameters()->find("EntryMacro");
4314 if ( pParameter
!= rFieldmark
.GetParameters()->end() )
4316 OUString aEntryMacro
;
4317 pParameter
->second
>>= aEntryMacro
;
4318 const sal_Int32 nLen
= std::min( sal_Int32(32), aEntryMacro
.getLength() );
4319 ffentrymcr
= aEntryMacro
.copy (0, nLen
);
4322 pParameter
= rFieldmark
.GetParameters()->find("ExitMacro");
4323 if ( pParameter
!= rFieldmark
.GetParameters()->end() )
4325 OUString aExitMacro
;
4326 pParameter
->second
>>= aExitMacro
;
4327 const sal_Int32 nLen
= std::min( sal_Int32(32), aExitMacro
.getLength() );
4328 ffexitmcr
= aExitMacro
.copy (0, nLen
);
4331 std::vector
< OUString
> aListItems
;
4334 aFieldHeader
.bits
|= 0x8000; // ffhaslistbox
4335 const ::sw::mark::IFieldmark::parameter_map_t
* const pParameters
= rFieldmark
.GetParameters();
4336 ::sw::mark::IFieldmark::parameter_map_t::const_iterator pListEntries
= pParameters
->find(ODF_FORMDROPDOWN_LISTENTRY
);
4337 if(pListEntries
!= pParameters
->end())
4339 uno::Sequence
< OUString
> vListEntries
;
4340 pListEntries
->second
>>= vListEntries
;
4341 aListItems
.reserve(vListEntries
.getLength());
4342 copy(std::cbegin(vListEntries
), std::cend(vListEntries
), back_inserter(aListItems
));
4346 const sal_uInt8 aFieldData
[] =
4348 0x44,0, // the start of "next" data
4349 0,0,0,0,0,0,0,0,0,0, // PIC-Structure! /10
4350 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | /16
4351 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | /16
4352 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | /16
4355 sal_uInt32 slen
= sizeof(sal_uInt32
)
4356 + sizeof(aFieldData
)
4357 + sizeof( aFieldHeader
.version
) + sizeof( aFieldHeader
.bits
) + sizeof( aFieldHeader
.cch
) + sizeof( aFieldHeader
.hps
)
4358 + 2*ffname
.getLength() + 4
4359 + 2*ffformat
.getLength() + 4
4360 + 2*ffhelptext
.getLength() + 4
4361 + 2*ffstattext
.getLength() + 4
4362 + 2*ffentrymcr
.getLength() + 4
4363 + 2*ffexitmcr
.getLength() + 4;
4367 slen
+= 2*ffdeftext
.getLength() + 4; //xstzTextDef
4369 slen
+= 2; // sttb ( fExtend )
4370 slen
+= 4; // for num of list items
4371 const int items
= aListItems
.size();
4372 for( int i
= 0; i
< items
; i
++ ) {
4373 OUString item
= aListItems
[i
];
4374 slen
+= 2 * item
.getLength() + 2;
4378 m_pDataStrm
->WriteUInt32( slen
);
4380 int len
= sizeof( aFieldData
);
4381 OSL_ENSURE( len
== 0x44-sizeof(sal_uInt32
), "SwWW8Writer::WriteFormData(..) - wrong aFieldData length" );
4382 m_pDataStrm
->WriteBytes( aFieldData
, len
);
4384 m_pDataStrm
->WriteUInt32( aFieldHeader
.version
).WriteUInt16( aFieldHeader
.bits
).WriteUInt16( aFieldHeader
.cch
).WriteUInt16( aFieldHeader
.hps
);
4386 SwWW8Writer::WriteString_xstz( *m_pDataStrm
, ffname
, true ); // Form field name
4389 SwWW8Writer::WriteString_xstz( *m_pDataStrm
, ffdeftext
, true );
4391 m_pDataStrm
->WriteUInt16( 0 );
4393 SwWW8Writer::WriteString_xstz( *m_pDataStrm
, ffformat
, true );
4394 SwWW8Writer::WriteString_xstz( *m_pDataStrm
, ffhelptext
, true );
4395 SwWW8Writer::WriteString_xstz( *m_pDataStrm
, ffstattext
, true );
4396 SwWW8Writer::WriteString_xstz( *m_pDataStrm
, ffentrymcr
, true );
4397 SwWW8Writer::WriteString_xstz( *m_pDataStrm
, ffexitmcr
, true );
4399 m_pDataStrm
->WriteUInt16( 0xFFFF );
4400 const int items
=aListItems
.size();
4401 m_pDataStrm
->WriteUInt32( items
);
4402 for(int i
=0;i
<items
;i
++) {
4403 OUString item
=aListItems
[i
];
4404 SwWW8Writer::WriteString_xstz( *m_pDataStrm
, item
, false );
4409 void WW8Export::WriteHyperlinkData( const sw::mark::IFieldmark
& /*rFieldmark*/ )
4411 //@TODO implement me !!!
4414 void WW8AttributeOutput::TableNodeInfoInner( ww8::WW8TableNodeInfoInner::Pointer_t pNodeInfoInner
)
4417 ShortToSVBT16( m_rWW8Export
.m_nStyleBeforeFly
, nStyle
);
4420 SAL_INFO( "sw.ww8", "<OutWW8_TableNodeInfoInner>" << pNodeInfoInner
->toString());
4423 m_rWW8Export
.m_pO
->clear();
4425 sal_uInt32 nShadowsBefore
= pNodeInfoInner
->getShadowsBefore();
4426 if (nShadowsBefore
> 0)
4428 ww8::WW8TableNodeInfoInner::Pointer_t
4429 pTmpNodeInfoInner
= std::make_shared
<ww8::WW8TableNodeInfoInner
>(nullptr);
4431 pTmpNodeInfoInner
->setDepth(pNodeInfoInner
->getDepth());
4432 pTmpNodeInfoInner
->setEndOfCell(true);
4434 for (sal_uInt32 n
= 0; n
< nShadowsBefore
; ++n
)
4436 m_rWW8Export
.WriteCR(pTmpNodeInfoInner
);
4438 m_rWW8Export
.m_pO
->insert( m_rWW8Export
.m_pO
->end(), nStyle
, nStyle
+2 ); // Style #
4439 TableInfoCell(pTmpNodeInfoInner
);
4440 m_rWW8Export
.m_pPapPlc
->AppendFkpEntry
4441 ( m_rWW8Export
.Strm().Tell(), m_rWW8Export
.m_pO
->size(), m_rWW8Export
.m_pO
->data() );
4443 m_rWW8Export
.m_pO
->clear();
4447 if (pNodeInfoInner
->isEndOfCell())
4449 SAL_INFO( "sw.ww8", "<endOfCell/>" );
4451 m_rWW8Export
.WriteCR(pNodeInfoInner
);
4453 m_rWW8Export
.m_pO
->insert( m_rWW8Export
.m_pO
->end(), nStyle
, nStyle
+2 ); // Style #
4454 TableInfoCell(pNodeInfoInner
);
4455 m_rWW8Export
.m_pPapPlc
->AppendFkpEntry( m_rWW8Export
.Strm().Tell(), m_rWW8Export
.m_pO
->size(), m_rWW8Export
.m_pO
->data() );
4457 m_rWW8Export
.m_pO
->clear();
4460 sal_uInt32 nShadowsAfter
= pNodeInfoInner
->getShadowsAfter();
4461 if (nShadowsAfter
> 0)
4463 ww8::WW8TableNodeInfoInner::Pointer_t
4464 pTmpNodeInfoInner
= std::make_shared
<ww8::WW8TableNodeInfoInner
>(nullptr);
4466 pTmpNodeInfoInner
->setDepth(pNodeInfoInner
->getDepth());
4467 pTmpNodeInfoInner
->setEndOfCell(true);
4469 for (sal_uInt32 n
= 0; n
< nShadowsAfter
; ++n
)
4471 m_rWW8Export
.WriteCR(pTmpNodeInfoInner
);
4473 m_rWW8Export
.m_pO
->insert( m_rWW8Export
.m_pO
->end(), nStyle
, nStyle
+2 ); // Style #
4474 TableInfoCell(pTmpNodeInfoInner
);
4475 m_rWW8Export
.m_pPapPlc
->AppendFkpEntry( m_rWW8Export
.Strm().Tell(), m_rWW8Export
.m_pO
->size(), m_rWW8Export
.m_pO
->data() );
4477 m_rWW8Export
.m_pO
->clear();
4481 if (pNodeInfoInner
->isEndOfLine())
4483 SAL_INFO( "sw.ww8", "<endOfLine/>" );
4485 TableRowEnd(pNodeInfoInner
->getDepth());
4487 ShortToSVBT16(0, nStyle
);
4488 m_rWW8Export
.m_pO
->insert( m_rWW8Export
.m_pO
->end(), nStyle
, nStyle
+2 ); // Style #
4489 TableInfoRow(pNodeInfoInner
);
4490 m_rWW8Export
.m_pPapPlc
->AppendFkpEntry( m_rWW8Export
.Strm().Tell(), m_rWW8Export
.m_pO
->size(), m_rWW8Export
.m_pO
->data() );
4492 m_rWW8Export
.m_pO
->clear();
4494 SAL_INFO( "sw.ww8", "</OutWW8_TableNodeInfoInner>" );
4497 void MSWordExportBase::OutputStartNode( const SwStartNode
& rNode
)
4500 ww8::WW8TableNodeInfo::Pointer_t pNodeInfo
=
4501 m_pTableInfo
->getTableNodeInfo( &rNode
);
4506 SAL_INFO( "sw.ww8", pNodeInfo
->toString());
4508 const ww8::WW8TableNodeInfo::Inners_t aInners
= pNodeInfo
->getInners();
4509 ww8::WW8TableNodeInfo::Inners_t::const_reverse_iterator
aIt(aInners
.rbegin());
4510 ww8::WW8TableNodeInfo::Inners_t::const_reverse_iterator
aEnd(aInners
.rend());
4513 ww8::WW8TableNodeInfoInner::Pointer_t pInner
= aIt
->second
;
4515 AttrOutput().TableNodeInfoInner(pInner
);
4519 SAL_INFO( "sw.ww8", "</OutWW8_SwStartNode>" );
4522 void MSWordExportBase::OutputEndNode( const SwEndNode
&rNode
)
4525 SAL_INFO( "sw.ww8", "<OutWW8_SwEndNode>" << dbg_out(&rNode
));
4528 ww8::WW8TableNodeInfo::Pointer_t pNodeInfo
= m_pTableInfo
->getTableNodeInfo( &rNode
);
4533 SAL_INFO( "sw.ww8", pNodeInfo
->toString());
4535 const ww8::WW8TableNodeInfo::Inners_t aInners
= pNodeInfo
->getInners();
4536 for (const auto& rEntry
: aInners
)
4538 ww8::WW8TableNodeInfoInner::Pointer_t pInner
= rEntry
.second
;
4539 AttrOutput().TableNodeInfoInner(pInner
);
4542 SAL_INFO( "sw.ww8", "</OutWW8_SwEndNode>" );
4545 const NfKeywordTable
& MSWordExportBase::GetNfKeywordTable()
4547 if (m_pKeyMap
== nullptr)
4549 m_pKeyMap
= std::make_shared
<NfKeywordTable
>();
4550 NfKeywordTable
& rKeywordTable
= *m_pKeyMap
;
4551 rKeywordTable
[NF_KEY_D
] = "d";
4552 rKeywordTable
[NF_KEY_DD
] = "dd";
4553 rKeywordTable
[NF_KEY_DDD
] = "ddd";
4554 rKeywordTable
[NF_KEY_DDDD
] = "dddd";
4555 rKeywordTable
[NF_KEY_M
] = "M";
4556 rKeywordTable
[NF_KEY_MM
] = "MM";
4557 rKeywordTable
[NF_KEY_MMM
] = "MMM";
4558 rKeywordTable
[NF_KEY_MMMM
] = "MMMM";
4559 rKeywordTable
[NF_KEY_NN
] = "ddd";
4560 rKeywordTable
[NF_KEY_NNN
] = "dddd";
4561 rKeywordTable
[NF_KEY_NNNN
] = "dddd";
4562 rKeywordTable
[NF_KEY_YY
] = "yy";
4563 rKeywordTable
[NF_KEY_YYYY
] = "yyyy";
4564 rKeywordTable
[NF_KEY_H
] = "H";
4565 rKeywordTable
[NF_KEY_HH
] = "HH";
4566 rKeywordTable
[NF_KEY_MI
] = "m";
4567 rKeywordTable
[NF_KEY_MMI
] = "mm";
4568 rKeywordTable
[NF_KEY_S
] = "s";
4569 rKeywordTable
[NF_KEY_SS
] = "ss";
4570 rKeywordTable
[NF_KEY_AMPM
] = "AM/PM";
4576 OUString
MSWordExportBase::BookmarkToWord(const OUString
& rBookmark
, bool* pIsMove
, bool* pIsFrom
)
4578 OUString sLookup
= rBookmark
;
4581 static constexpr OUStringLiteral MoveFrom_Bookmark_NamePrefix
= u
"__RefMoveFrom__";
4582 static constexpr OUStringLiteral MoveTo_Bookmark_NamePrefix
= u
"__RefMoveTo__";
4583 if (rBookmark
.startsWith(MoveFrom_Bookmark_NamePrefix
, &sLookup
))
4588 else if (rBookmark
.startsWith(MoveTo_Bookmark_NamePrefix
, &sLookup
))
4594 if (auto it
= m_aBookmarkToWord
.find(sLookup
); it
!= m_aBookmarkToWord
.end())
4598 = INetURLObject::encode(sLookup
.replace(' ', '_'), // Spaces are prohibited in bookmark name
4599 INetURLObject::PART_REL_SEGMENT_EXTRA
,
4600 INetURLObject::EncodeMechanism::All
, RTL_TEXTENCODING_ASCII_US
);
4601 // Unicode letters are allowed
4602 sRet
= INetURLObject::decode(sRet
, INetURLObject::DecodeMechanism::Unambiguous
,
4603 RTL_TEXTENCODING_UTF8
);
4606 // Word has 40 character limit for bookmarks: [MS-OE376] Part 4 Sect. 2.13.6.2, bookmarkStart
4607 if (sRet
.getLength() > 40)
4609 // Generate a unique bookmark name
4610 sRet
= sRet
.copy(0, 40);
4611 for (sal_uInt32 n
= 1; n
; ++n
)
4613 if (m_aWordBookmarks
.find(sRet
) == m_aWordBookmarks
.end())
4615 auto num
= OUString::number(n
, 36);
4616 sRet
= sRet
.subView(0, 40 - num
.length
) + num
;
4620 m_aBookmarkToWord
[sLookup
] = sRet
;
4621 m_aWordBookmarks
.insert(sRet
);
4625 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */