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 .
22 #include <com/sun/star/embed/ElementModes.hpp>
23 #include <com/sun/star/embed/XStorage.hpp>
24 #include <unotools/ucbstreamhelper.hxx>
28 #include <hintids.hxx>
30 #include <osl/endian.h>
31 #include <o3tl/make_unique.hxx>
33 #include <drawdoc.hxx>
35 #include <unotools/fltrcfg.hxx>
36 #include <vcl/salbtype.hxx>
37 #include <sot/storage.hxx>
38 #include <svl/zformat.hxx>
39 #include <sfx2/docinf.hxx>
40 #include <editeng/tstpitem.hxx>
41 #include <svx/svdmodel.hxx>
42 #include <svx/svdpage.hxx>
43 #include <editeng/hyphenzoneitem.hxx>
44 #include <editeng/langitem.hxx>
45 #include <filter/msfilter/classids.hxx>
46 #include <filter/msfilter/msoleexp.hxx>
47 #include <editeng/lrspitem.hxx>
48 #include <editeng/ulspitem.hxx>
49 #include <editeng/boxitem.hxx>
50 #include <editeng/brushitem.hxx>
51 #include <swtypes.hxx>
53 #include <swtblfmt.hxx>
54 #include <txatbase.hxx>
55 #include <fmtcntnt.hxx>
56 #include <fmtpdsc.hxx>
57 #include <fmtrowsplt.hxx>
60 #include <IDocumentSettingAccess.hxx>
61 #include <IDocumentDrawModelAccess.hxx>
62 #include <IDocumentStylePoolAccess.hxx>
63 #include <IDocumentStatistics.hxx>
64 #include <IDocumentLayoutAccess.hxx>
65 #include <IDocumentExternalData.hxx>
66 #include <viewopt.hxx>
70 #include <shellio.hxx>
71 #include <docstat.hxx>
72 #include <pagedesc.hxx>
74 #include <swtable.hxx>
78 #include <swmodule.hxx>
79 #include <section.hxx>
80 #include <swfltopt.hxx>
81 #include <fmtinfmt.hxx>
82 #include <txtinet.hxx>
85 #include <svtools/imap.hxx>
86 #include <svtools/imapobj.hxx>
87 #include <tools/urlobj.hxx>
89 #include <statstr.hrc>
90 #include <fmtline.hxx>
91 #include <fmtfsize.hxx>
92 #include <comphelper/extract.hxx>
93 #include <comphelper/string.hxx>
94 #include <sprmids.hxx>
96 #include "writerhelper.hxx"
97 #include "writerwordglue.hxx"
98 #include "ww8attributeoutput.hxx"
99 #include <IDocumentMarkAccess.hxx>
100 #include <xmloff/odffields.hxx>
101 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
102 #include <com/sun/star/document/XDocumentProperties.hpp>
103 #include "dbgoutsw.hxx"
104 #include <sfx2/docfile.hxx>
105 #include <sfx2/request.hxx>
106 #include <sfx2/frame.hxx>
107 #include <svl/stritem.hxx>
108 #include <unotools/tempfile.hxx>
109 #include <filter/msfilter/mscodec.hxx>
110 #include <filter/msfilter/svxmsbas.hxx>
111 #include <osl/time.h>
112 #include <rtl/random.h>
113 #include <vcl/svapp.hxx>
114 #include "WW8Sttbf.hxx"
115 #include <editeng/charrotateitem.hxx>
116 #include "WW8FibData.hxx"
117 #include "numrule.hxx"
118 #include "fmtclds.hxx"
119 #include "rdfhelper.hxx"
122 using namespace sw::util
;
123 using namespace sw::types
;
125 /** FKP - Formatted disK Page
129 sal_uInt8
* pFkp
; // Fkp total ( first and only FCs and Sprms )
130 sal_uInt8
* pOfs
; // pointer to the offset area, later copied to pFkp
132 short nStartGrp
; // ab hier grpprls
135 sal_uInt8 nIMax
; // number of entry pairs
136 sal_uInt8 nOldVarLen
;
137 bool bCombined
; // true : paste not allowed
139 sal_uInt8
SearchSameSprm( sal_uInt16 nVarLen
, const sal_uInt8
* pSprms
);
141 WW8_WrFkp(const WW8_WrFkp
&) = delete;
142 WW8_WrFkp
& operator=(const WW8_WrFkp
&) = delete;
145 WW8_WrFkp(ePLCFT ePl
, WW8_FC nStartFc
);
147 bool Append( WW8_FC nEndFc
, sal_uInt16 nVarLen
, const sal_uInt8
* pSprms
);
149 void Write( SvStream
& rStrm
, SwWW8WrGrf
& rGrf
);
151 bool IsEqualPos(WW8_FC nEndFc
) const
152 { return !bCombined
&& nIMax
&& nEndFc
== reinterpret_cast<sal_Int32
*>(pFkp
)[nIMax
]; }
153 void MergeToNew( short& rVarLen
, sal_uInt8
*& pNewSprms
);
154 bool IsEmptySprm() const
155 { return !bCombined
&& nIMax
&& !nOldVarLen
; }
156 void SetNewEnd( WW8_FC nEnd
)
157 { reinterpret_cast<sal_Int32
*>(pFkp
)[nIMax
] = nEnd
; }
159 WW8_FC
GetStartFc() const;
160 WW8_FC
GetEndFc() const;
162 sal_uInt8
*CopyLastSprms(sal_uInt8
&rLen
);
165 // class WW8_WrPc collects all piece entries for one piece
168 WW8_CP nStartCp
; // Starting character position of the text
169 WW8_FC nStartFc
; // Starting file position of the text
170 sal_uInt16 nStatus
; // End of paragraph inside the piece?
173 WW8_WrPc(WW8_FC nSFc
, WW8_CP nSCp
)
174 : nStartCp( nSCp
), nStartFc( nSFc
), nStatus( 0x0040 )
177 void SetStatus() { nStatus
= 0x0050; }
178 sal_uInt16
GetStatus() const { return nStatus
; }
179 WW8_CP
GetStartCp() const { return nStartCp
; }
180 WW8_FC
GetStartFc() const { return nStartFc
; }
183 typedef std::map
<OUString
,long> BKMKNames
;
184 typedef std::pair
<bool,OUString
> BKMK
;
185 typedef std::pair
<long,BKMK
> BKMKCP
;
186 typedef std::multimap
<long,BKMKCP
*> BKMKCPs
;
187 typedef BKMKCPs::iterator CPItr
;
189 class WW8_WrtBookmarks
192 BKMKCPs aSttCps
,aEndCps
;
193 BKMKNames maSwBkmkNms
;
195 WW8_WrtBookmarks(WW8_WrtBookmarks
const&) = delete;
196 WW8_WrtBookmarks
& operator=(WW8_WrtBookmarks
const&) = delete;
201 //! Add a new bookmark to the list OR add an end position to an existing bookmark.
202 void Append( WW8_CP nStartCp
, const OUString
& rNm
, const ::sw::mark::IMark
* pBkmk
=nullptr );
203 //! Write out bookmarks to file.
204 void Write( WW8Export
& rWrt
);
205 //! Move existing field marks from one position to another.
206 void MoveFieldMarks(WW8_CP nFrom
, WW8_CP nTo
);
209 WW8_WrtBookmarks::WW8_WrtBookmarks()
212 WW8_WrtBookmarks::~WW8_WrtBookmarks()
214 CPItr aEnd
= aSttCps
.end();
215 for (CPItr aItr
= aSttCps
.begin();aItr
!=aEnd
;++aItr
)
220 aItr
->second
= nullptr;
225 void WW8_WrtBookmarks::Append( WW8_CP nStartCp
, const OUString
& rNm
, const ::sw::mark::IMark
*)
227 std::pair
<BKMKNames::iterator
, bool> aResult
= maSwBkmkNms
.insert(std::pair
<OUString
,long>(rNm
,0L));
231 BKMKCP
* pBKCP
= new BKMKCP((long)nStartCp
,aBK
);
232 aSttCps
.insert(std::pair
<long,BKMKCP
*>(nStartCp
,pBKCP
));
233 aResult
.first
->second
= (long)nStartCp
;
237 std::pair
<CPItr
,CPItr
> aRange
= aSttCps
.equal_range(aResult
.first
->second
);
238 for (CPItr aItr
= aRange
.first
;aItr
!= aRange
.second
;++aItr
)
240 if (aItr
->second
&& aItr
->second
->second
.second
== rNm
)
242 if (aItr
->second
->second
.first
)
244 aItr
->second
->first
= (long)nStartCp
;
251 void WW8_WrtBookmarks::Write( WW8Export
& rWrt
)
257 std::vector
<OUString
> aNames
;
258 SvMemoryStream
aTempStrm1(65535,65535);
259 SvMemoryStream
aTempStrm2(65535,65535);
260 for (aItr
= aSttCps
.begin();aItr
!=aSttCps
.end();++aItr
)
264 aEndCps
.insert(std::pair
<long,BKMKCP
*>(aItr
->second
->first
,aItr
->second
));
265 aNames
.push_back(aItr
->second
->second
.second
);
266 SwWW8Writer::WriteLong( aTempStrm1
, aItr
->first
);
271 for (aItr
= aEndCps
.begin(), n
= 0;aItr
!= aEndCps
.end();++aItr
,++n
)
275 aItr
->second
->first
= n
;
276 SwWW8Writer::WriteLong( aTempStrm2
, aItr
->first
);
281 rWrt
.WriteAsStringTable(aNames
, rWrt
.pFib
->m_fcSttbfbkmk
,rWrt
.pFib
->m_lcbSttbfbkmk
);
282 SvStream
& rStrm
= *rWrt
.pTableStrm
;
283 rWrt
.pFib
->m_fcPlcfbkf
= rStrm
.Tell();
284 rStrm
.WriteStream( aTempStrm1
);
285 SwWW8Writer::WriteLong(rStrm
, rWrt
.pFib
->m_ccpText
+ rWrt
.pFib
->m_ccpTxbx
);
286 for (aItr
= aSttCps
.begin();aItr
!=aSttCps
.end();++aItr
)
290 SwWW8Writer::WriteLong(rStrm
, aItr
->second
->first
);
293 rWrt
.pFib
->m_lcbPlcfbkf
= rStrm
.Tell() - rWrt
.pFib
->m_fcPlcfbkf
;
294 rWrt
.pFib
->m_fcPlcfbkl
= rStrm
.Tell();
295 rStrm
.WriteStream( aTempStrm2
);
296 SwWW8Writer::WriteLong(rStrm
, rWrt
.pFib
->m_ccpText
+ rWrt
.pFib
->m_ccpTxbx
);
297 rWrt
.pFib
->m_lcbPlcfbkl
= rStrm
.Tell() - rWrt
.pFib
->m_fcPlcfbkl
;
300 void WW8_WrtBookmarks::MoveFieldMarks(WW8_CP nFrom
, WW8_CP nTo
)
302 std::pair
<CPItr
,CPItr
> aRange
= aSttCps
.equal_range(nFrom
);
303 CPItr aItr
= aRange
.first
;
304 while (aItr
!= aRange
.second
)
308 if (aItr
->second
->first
== (long)nFrom
)
310 aItr
->second
->second
.first
= true;
311 aItr
->second
->first
= nTo
;
313 aSttCps
.insert(std::pair
<long,BKMKCP
*>(nTo
,aItr
->second
));
314 aItr
->second
= nullptr;
315 aRange
= aSttCps
.equal_range(nFrom
);
323 /// Handles export of smart tags.
324 class WW8_WrtFactoids
326 std::vector
<WW8_CP
> m_aStartCPs
;
327 std::vector
<WW8_CP
> m_aEndCPs
;
328 std::vector
< std::map
<OUString
, OUString
> > m_aStatements
;
330 WW8_WrtFactoids(WW8_WrtFactoids
const&) = delete;
331 WW8_WrtFactoids
& operator=(WW8_WrtFactoids
const&) = delete;
336 void Append(WW8_CP nStartCp
, WW8_CP nEndCp
, const std::map
<OUString
, OUString
>& rStatements
);
337 void Write(WW8Export
& rWrt
);
340 WW8_WrtFactoids::WW8_WrtFactoids()
344 WW8_WrtFactoids::~WW8_WrtFactoids()
348 void WW8_WrtFactoids::Append(WW8_CP nStartCp
, WW8_CP nEndCp
, const std::map
<OUString
, OUString
>& rStatements
)
350 m_aStartCPs
.push_back(nStartCp
);
351 m_aEndCPs
.push_back(nEndCp
);
352 m_aStatements
.push_back(rStatements
);
355 void WW8_WrtFactoids::Write(WW8Export
& rExport
)
357 if (m_aStartCPs
.empty())
360 // Smart tags are otherwise removed by Word on saving.
361 rExport
.pDop
->fEmbedFactoids
= true;
363 SvStream
& rStream
= *rExport
.pTableStrm
;
365 rExport
.pFib
->m_fcSttbfBkmkFactoid
= rStream
.Tell();
366 // Write SttbfBkmkFactoid.
367 rStream
.WriteUInt16(0xffff); // fExtend
368 rStream
.WriteUInt16(m_aStartCPs
.size()); // cData
369 rStream
.WriteUInt16(0); // cbExtra
371 for (size_t i
= 0; i
< m_aStartCPs
.size(); ++i
)
373 rStream
.WriteUInt16(6); // cchData
374 // Write FACTOIDINFO.
375 rStream
.WriteUInt32(i
); // dwId
376 rStream
.WriteUInt16(0); // fSubEntry
377 rStream
.WriteUInt16(0); // fto
378 rStream
.WriteUInt32(0); // pfpb
380 rExport
.pFib
->m_lcbSttbfBkmkFactoid
= rStream
.Tell() - rExport
.pFib
->m_fcSttbfBkmkFactoid
;
382 rExport
.pFib
->m_fcPlcfBkfFactoid
= rStream
.Tell();
383 for (const WW8_CP
& rCP
: m_aStartCPs
)
384 rStream
.WriteInt32(rCP
);
385 rStream
.WriteInt32(rExport
.pFib
->m_ccpText
+ rExport
.pFib
->m_ccpTxbx
);
388 for (size_t i
= 0; i
< m_aStartCPs
.size(); ++i
)
390 rStream
.WriteInt16(i
); // ibkl
391 rStream
.WriteInt16(0); // bkc
392 rStream
.WriteInt16(1); // cDepth, 1 as start and end is the same.
395 rExport
.pFib
->m_lcbPlcfBkfFactoid
= rStream
.Tell() - rExport
.pFib
->m_fcPlcfBkfFactoid
;
397 rExport
.pFib
->m_fcPlcfBklFactoid
= rStream
.Tell();
398 for (const WW8_CP
& rCP
: m_aEndCPs
)
399 rStream
.WriteInt32(rCP
);
400 rStream
.WriteInt32(rExport
.pFib
->m_ccpText
+ rExport
.pFib
->m_ccpTxbx
);
403 for (size_t i
= 0; i
< m_aEndCPs
.size(); ++i
)
405 rStream
.WriteInt16(i
); // ibkf
406 rStream
.WriteInt16(0); // cDepth, 0 as does not overlap with any other smart tag.
408 rExport
.pFib
->m_lcbPlcfBklFactoid
= rStream
.Tell() - rExport
.pFib
->m_fcPlcfBklFactoid
;
410 rExport
.pFib
->m_fcFactoidData
= rStream
.Tell();
411 // Write SmartTagData.
412 MSOFactoidType aFactoidType
;
413 aFactoidType
.m_nId
= 1;
414 aFactoidType
.m_aUri
= "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
415 aFactoidType
.m_aTag
= "RDF";
416 WW8SmartTagData aSmartTagData
;
417 aSmartTagData
.m_aPropBagStore
.m_aFactoidTypes
.push_back(aFactoidType
);
419 std::set
<OUString
> aSet
;
420 for (const std::map
<OUString
, OUString
>& rStatements
: m_aStatements
)
422 // Statements for a single text node.
423 for (const auto& rPair
: rStatements
)
425 aSet
.insert(rPair
.first
);
426 aSet
.insert(rPair
.second
);
429 aSmartTagData
.m_aPropBagStore
.m_aStringTable
.assign(aSet
.begin(), aSet
.end());
430 for (const std::map
<OUString
, OUString
>& rStatements
: m_aStatements
)
432 MSOPropertyBag aPropertyBag
;
433 aPropertyBag
.m_nId
= 1;
434 for (const auto& rPair
: rStatements
)
436 MSOProperty aProperty
;
437 aProperty
.m_nKey
= std::distance(aSet
.begin(), aSet
.find(rPair
.first
));
438 aProperty
.m_nValue
= std::distance(aSet
.begin(), aSet
.find(rPair
.second
));
439 aPropertyBag
.m_aProperties
.push_back(aProperty
);
441 aSmartTagData
.m_aPropBags
.push_back(aPropertyBag
);
444 aSmartTagData
.Write(rExport
);
445 rExport
.pFib
->m_lcbFactoidData
= rStream
.Tell() - rExport
.pFib
->m_fcFactoidData
;
448 #define ANZ_DEFAULT_STYLES 16
450 // Names of the storage streams
451 #define sMainStream OUString("WordDocument")
452 #define sCompObj "\1CompObj"
454 static void WriteDop( WW8Export
& rWrt
)
456 WW8Dop
& rDop
= *rWrt
.pDop
;
458 // i#78951#, store the value of unknown compatibility options
459 rDop
.SetCompatibilityOptions( rWrt
.m_pDoc
->getIDocumentSettingAccess().Getn32DummyCompatibilityOptions1());
460 rDop
.SetCompatibilityOptions2( rWrt
.m_pDoc
->getIDocumentSettingAccess().Getn32DummyCompatibilityOptions2());
462 rDop
.fNoLeading
= !rWrt
.m_pDoc
->getIDocumentSettingAccess().get(DocumentSettingId::ADD_EXT_LEADING
);
463 rDop
.fUsePrinterMetrics
= !rWrt
.m_pDoc
->getIDocumentSettingAccess().get(DocumentSettingId::USE_VIRTUAL_DEVICE
);
465 // write default TabStop
466 const SvxTabStopItem
& rTabStop
=
467 DefaultItemGet
<SvxTabStopItem
>(*rWrt
.m_pDoc
, RES_PARATR_TABSTOP
);
468 rDop
.dxaTab
= (sal_uInt16
)rTabStop
[0].GetTabPos();
470 // Zoom factor and type
471 SwViewShell
*pViewShell(rWrt
.m_pDoc
->getIDocumentLayoutAccess().GetCurrentViewShell());
474 switch ( pViewShell
->GetViewOptions()->GetZoomType() )
476 case SvxZoomType::WHOLEPAGE
: rDop
.zkSaved
= 1; break;
477 case SvxZoomType::PAGEWIDTH
: rDop
.zkSaved
= 2; break;
478 case SvxZoomType::OPTIMAL
: rDop
.zkSaved
= 3; break;
479 default: rDop
.zkSaved
= 0;
480 rDop
.wScaleSaved
= pViewShell
->GetViewOptions()->GetZoom();
485 // Werte aus der DocStatistik (werden aufjedenfall fuer die
486 // DocStat-Felder benoetigt!)
487 rDop
.fWCFootnoteEdn
= true; // because they are included in StarWriter
489 const SwDocStat
& rDStat
= rWrt
.m_pDoc
->getIDocumentStatistics().GetDocStat();
490 rDop
.cWords
= rDStat
.nWord
;
491 rDop
.cCh
= rDStat
.nChar
;
492 rDop
.cPg
= static_cast< sal_Int16
>(rDStat
.nPage
);
493 rDop
.cParas
= rDStat
.nPara
;
494 rDop
.cLines
= rDStat
.nPara
;
496 SwDocShell
*pDocShell(rWrt
.m_pDoc
->GetDocShell());
497 OSL_ENSURE(pDocShell
, "no SwDocShell");
498 uno::Reference
<document::XDocumentProperties
> xDocProps
;
499 uno::Reference
<beans::XPropertySet
> xProps
;
501 uno::Reference
<lang::XComponent
> xModelComp(pDocShell
->GetModel(),
503 xProps
.set(xModelComp
, uno::UNO_QUERY
);
504 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
505 xModelComp
, uno::UNO_QUERY_THROW
);
506 xDocProps
= xDPS
->getDocumentProperties();
507 OSL_ENSURE(xDocProps
.is(), "DocumentProperties is null");
509 rDop
.lKeyProtDoc
= pDocShell
->GetModifyPasswordHash();
512 if ((rWrt
.pSepx
&& rWrt
.pSepx
->DocumentIsProtected()) ||
513 rDop
.lKeyProtDoc
!= 0)
515 rDop
.fProtEnabled
= true;
519 rDop
.fProtEnabled
= false;
524 rDop
.dttmCreated
= rDop
.dttmRevised
= rDop
.dttmLastPrint
= 0x45FBAC69;
528 ::util::DateTime uDT
= xDocProps
->getCreationDate();
529 rDop
.dttmCreated
= sw::ms::DateTime2DTTM(DateTime(uDT
));
530 uDT
= xDocProps
->getModificationDate();
531 rDop
.dttmRevised
= sw::ms::DateTime2DTTM(DateTime(uDT
));
532 uDT
= xDocProps
->getPrintDate();
533 rDop
.dttmLastPrint
= sw::ms::DateTime2DTTM(DateTime(uDT
));
536 // Also, the DocStat fields in headers, footers are not calculated correctly.
537 // ( we do not have this fields! )
539 // and also for the Headers and Footers
540 rDop
.cWordsFootnoteEnd
= rDStat
.nWord
;
541 rDop
.cChFootnoteEdn
= rDStat
.nChar
;
542 rDop
.cPgFootnoteEdn
= (sal_Int16
)rDStat
.nPage
;
543 rDop
.cParasFootnoteEdn
= rDStat
.nPara
;
544 rDop
.cLinesFootnoteEdn
= rDStat
.nPara
;
546 rDop
.fDontUseHTMLAutoSpacing
= rWrt
.m_pDoc
->getIDocumentSettingAccess().get(DocumentSettingId::PARA_SPACE_MAX
);
548 rDop
.fExpShRtn
= !rWrt
.m_pDoc
->getIDocumentSettingAccess().get(DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK
); // #i56856#
550 rDop
.Write( *rWrt
.pTableStrm
, *rWrt
.pFib
);
553 const sal_Unicode
*WW8DopTypography::GetJapanNotBeginLevel1()
555 static const sal_Unicode aJapanNotBeginLevel1
[nMaxFollowing
] =
558 0x0021, 0x0025, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f,
559 0x005d, 0x007d, 0x00a2, 0x00b0, 0x2019, 0x201d, 0x2030, 0x2032,
560 0x2033, 0x2103, 0x3001, 0x3002, 0x3005, 0x3009, 0x300b, 0x300d,
561 0x300f, 0x3011, 0x3015, 0x309b, 0x309c, 0x309d, 0x309e, 0x30fb,
562 0x30fd, 0x30fe, 0xff01, 0xff05, 0xff09, 0xff0c, 0xff0e, 0xff1a,
563 0xff1b, 0xff1f, 0xff3d, 0xff5d, 0xff61, 0xff63, 0xff64, 0xff65,
564 0xff9e, 0xff9f, 0xffe0
566 return &aJapanNotBeginLevel1
[0];
569 const sal_Unicode
*WW8DopTypography::GetJapanNotEndLevel1()
571 static const sal_Unicode aJapanNotEndLevel1
[nMaxLeading
] =
574 0x0024, 0x0028, 0x005b, 0x005c, 0x007b, 0x00a3, 0x00a5, 0x2018,
575 0x201c, 0x3008, 0x300a, 0x300c, 0x300e, 0x3010, 0x3014, 0xff04,
576 0xff08, 0xff3b, 0xff5b, 0xff62, 0xffe1, 0xffe5
578 return &aJapanNotEndLevel1
[0];
581 static int lcl_CmpBeginEndChars( const OUString
& rSWStr
,
582 const sal_Unicode
* pMSStr
, int nMSStrByteLen
)
584 nMSStrByteLen
/= sizeof( sal_Unicode
);
585 if( nMSStrByteLen
> rSWStr
.getLength() )
586 nMSStrByteLen
= rSWStr
.getLength()+1;
587 nMSStrByteLen
*= sizeof( sal_Unicode
);
589 return memcmp( rSWStr
.getStr(), pMSStr
, nMSStrByteLen
);
593 Converts the OOo Asian Typography into a best fit match for Microsoft
594 Asian typography. This structure is actually dumped to disk within the
595 Dop Writer. Assumption is that rTypo is cleared to 0 on entry
597 void WW8Export::ExportDopTypography(WW8DopTypography
&rTypo
)
599 static const sal_Unicode aLangNotBegin
[4][WW8DopTypography::nMaxFollowing
]=
603 0x0021, 0x0025, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f,
604 0x005d, 0x007d, 0x00a2, 0x00b0, 0x2019, 0x201d, 0x2030, 0x2032,
605 0x2033, 0x2103, 0x3001, 0x3002, 0x3005, 0x3009, 0x300b, 0x300d,
606 0x300f, 0x3011, 0x3015, 0x3041, 0x3043, 0x3045, 0x3047, 0x3049,
607 0x3063, 0x3083, 0x3085, 0x3087, 0x308e, 0x309b, 0x309c, 0x309d,
608 0x309e, 0x30a1, 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30c3, 0x30e3,
609 0x30e5, 0x30e7, 0x30ee, 0x30f5, 0x30f6, 0x30fb, 0x30fc, 0x30fd,
610 0x30fe, 0xff01, 0xff05, 0xff09, 0xff0c, 0xff0e, 0xff1a, 0xff1b,
611 0xff1f, 0xff3d, 0xff5d, 0xff61, 0xff63, 0xff64, 0xff65, 0xff67,
612 0xff68, 0xff69, 0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f,
613 0xff70, 0xff9e, 0xff9f, 0xffe0
617 0x0021, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f, 0x005d,
618 0x007d, 0x00a8, 0x00b7, 0x02c7, 0x02c9, 0x2015, 0x2016, 0x2019,
619 0x201d, 0x2026, 0x2236, 0x3001, 0x3002, 0x3003, 0x3005, 0x3009,
620 0x300b, 0x300d, 0x300f, 0x3011, 0x3015, 0x3017, 0xff01, 0xff02,
621 0xff07, 0xff09, 0xff0c, 0xff0e, 0xff1a, 0xff1b, 0xff1f, 0xff3d,
622 0xff40, 0xff5c, 0xff5d, 0xff5e, 0xffe0
626 0x0021, 0x0025, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f,
627 0x005d, 0x007d, 0x00a2, 0x00b0, 0x2019, 0x201d, 0x2032, 0x2033,
628 0x2103, 0x3009, 0x300b, 0x300d, 0x300f, 0x3011, 0x3015, 0xff01,
629 0xff05, 0xff09, 0xff0c, 0xff0e, 0xff1a, 0xff1b, 0xff1f, 0xff3d,
632 //Traditional Chinese
634 0x0021, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f, 0x005d,
635 0x007d, 0x00a2, 0x00b7, 0x2013, 0x2014, 0x2019, 0x201d, 0x2022,
636 0x2025, 0x2026, 0x2027, 0x2032, 0x2574, 0x3001, 0x3002, 0x3009,
637 0x300b, 0x300d, 0x300f, 0x3011, 0x3015, 0x301e, 0xfe30, 0xfe31,
638 0xfe33, 0xfe34, 0xfe36, 0xfe38, 0xfe3a, 0xfe3c, 0xfe3e, 0xfe40,
639 0xfe42, 0xfe44, 0xfe4f, 0xfe50, 0xfe51, 0xfe52, 0xfe54, 0xfe55,
640 0xfe56, 0xfe57, 0xfe5a, 0xfe5c, 0xfe5e, 0xff01, 0xff09, 0xff0c,
641 0xff0e, 0xff1a, 0xff1b, 0xff1f, 0xff5c, 0xff5d, 0xff64
645 static const sal_Unicode aLangNotEnd
[4][WW8DopTypography::nMaxLeading
] =
649 0x0024, 0x0028, 0x005b, 0x005c, 0x007b, 0x00a3, 0x00a5, 0x2018,
650 0x201c, 0x3008, 0x300a, 0x300c, 0x300e, 0x3010, 0x3014, 0xff04,
651 0xff08, 0xff3b, 0xff5b, 0xff62, 0xffe1, 0xffe5
655 0x0028, 0x005b, 0x007b, 0x00b7, 0x2018, 0x201c, 0x3008, 0x300a,
656 0x300c, 0x300e, 0x3010, 0x3014, 0x3016, 0xff08, 0xff0e, 0xff3b,
657 0xff5b, 0xffe1, 0xffe5
661 0x0028, 0x005b, 0x005c, 0x007b, 0x00a3, 0x00a5, 0x2018, 0x201c,
662 0x3008, 0x300a, 0x300c, 0x300e, 0x3010, 0x3014, 0xff04, 0xff08,
663 0xff3b, 0xff5b, 0xffe6
665 //Traditional Chinese
667 0x0028, 0x005b, 0x007b, 0x00a3, 0x00a5, 0x2018, 0x201c, 0x2035,
668 0x3008, 0x300a, 0x300c, 0x300e, 0x3010, 0x3014, 0x301d, 0xfe35,
669 0xfe37, 0xfe39, 0xfe3b, 0xfe3d, 0xfe3f, 0xfe41, 0xfe43, 0xfe59,
670 0xfe5b, 0xfe5d, 0xff08, 0xff5b
674 const i18n::ForbiddenCharacters
*pForbidden
= nullptr;
675 const i18n::ForbiddenCharacters
*pUseMe
= nullptr;
676 sal_uInt8 nUseReserved
=0;
679 Now we have some minor difficult issues, to wit...
680 a. MicroSoft Office can only store one set of begin and end characters in
681 a given document, not one per language.
682 b. StarOffice has only a concept of one set of begin and end characters for
683 a given language, i.e. not the two levels of kinsoku in japanese
685 What is unknown as yet is if our default begin and end chars for
686 japanese, chinese tradition, chinese simplified and korean are different
687 in Word and Writer. I already suspect that they are different between
688 different version of word itself.
690 So what have come up with is to simply see if any of the four languages
691 in OOo have been changed away from OUR defaults, and if one has then
692 export that. If more than one has in the future we may hack in something
693 which examines our document properties to see which language is used the
694 most and choose that, for now we choose the first and throw an ASSERT
697 /*Our default Japanese Level is 2, this is a special MS hack to set this*/
700 for (rTypo
.reserved1
=8;rTypo
.reserved1
>0;rTypo
.reserved1
-=2)
702 if (nullptr != (pForbidden
= m_pDoc
->getIDocumentSettingAccess().getForbiddenCharacters(rTypo
.GetConvertedLang(),
705 int nIdx
= (rTypo
.reserved1
-2)/2;
706 if( lcl_CmpBeginEndChars( pForbidden
->endLine
,
707 aLangNotEnd
[ nIdx
], sizeof(aLangNotEnd
[ nIdx
]) ) ||
708 lcl_CmpBeginEndChars( pForbidden
->beginLine
,
709 aLangNotBegin
[ nIdx
], sizeof(aLangNotBegin
[ nIdx
]) ) )
711 //One exception for Japanese, if it matches a level 1 we
712 //can use one extra flag for that, rather than use a custom
713 if (rTypo
.GetConvertedLang() == LANGUAGE_JAPANESE
)
716 !lcl_CmpBeginEndChars
719 WW8DopTypography::GetJapanNotEndLevel1(),
720 WW8DopTypography::nMaxLeading
* sizeof(sal_Unicode
)
723 !lcl_CmpBeginEndChars
725 pForbidden
->beginLine
,
726 WW8DopTypography::GetJapanNotBeginLevel1(),
727 WW8DopTypography::nMaxFollowing
* sizeof(sal_Unicode
)
739 nUseReserved
= rTypo
.reserved1
;
740 rTypo
.iLevelOfKinsoku
= 2;
747 OSL_ENSURE( nNoNeeded
<=1, "Example of unexportable forbidden chars" );
748 rTypo
.reserved1
=nUseReserved
;
749 if (rTypo
.iLevelOfKinsoku
&& pUseMe
)
751 rTypo
.cchFollowingPunct
= msword_cast
<sal_Int16
>
752 (pUseMe
->beginLine
.getLength());
753 if (rTypo
.cchFollowingPunct
> WW8DopTypography::nMaxFollowing
- 1)
754 rTypo
.cchFollowingPunct
= WW8DopTypography::nMaxFollowing
- 1;
756 rTypo
.cchLeadingPunct
= msword_cast
<sal_Int16
>
757 (pUseMe
->endLine
.getLength());
758 if (rTypo
.cchLeadingPunct
> WW8DopTypography::nMaxLeading
- 1)
759 rTypo
.cchLeadingPunct
= WW8DopTypography::nMaxLeading
-1;
761 memcpy(rTypo
.rgxchFPunct
,pUseMe
->beginLine
.getStr(),
762 (rTypo
.cchFollowingPunct
+1)*2);
764 memcpy(rTypo
.rgxchLPunct
,pUseMe
->endLine
.getStr(),
765 (rTypo
.cchLeadingPunct
+1)*2);
768 const IDocumentSettingAccess
& rIDocumentSettingAccess
= GetWriter().getIDocumentSettingAccess();
770 rTypo
.fKerningPunct
= sal_uInt16(rIDocumentSettingAccess
.get(DocumentSettingId::KERN_ASIAN_PUNCTUATION
));
771 rTypo
.iJustification
= m_pDoc
->getIDocumentSettingAccess().getCharacterCompressionType();
774 // It can only be found something with this method, if it is used within
775 // WW8_SwAttrIter::OutAttr() and WW8Export::OutputItemSet()
776 const SfxPoolItem
* MSWordExportBase::HasItem( sal_uInt16 nWhich
) const
778 const SfxPoolItem
* pItem
=nullptr;
781 // if write a EditEngine text, then the WhichIds are greater as
782 // ourer own Ids. So the Id have to translate from our into the
784 nWhich
= sw::hack::GetSetWhichFromSwDocWhich(*m_pISet
, *m_pDoc
, nWhich
);
785 if (nWhich
&& SfxItemState::SET
!= m_pISet
->GetItemState(nWhich
, true, &pItem
))
788 else if( m_pChpIter
)
789 pItem
= m_pChpIter
->HasTextItem( nWhich
);
792 OSL_ENSURE( false, "Where is my ItemSet / pChpIter ?" );
798 const SfxPoolItem
& MSWordExportBase::GetItem(sal_uInt16 nWhich
) const
800 assert((m_pISet
|| m_pChpIter
) && "Where is my ItemSet / pChpIter ?");
803 // if write a EditEngine text, then the WhichIds are greater as
804 // ourer own Ids. So the Id have to translate from our into the
806 nWhich
= sw::hack::GetSetWhichFromSwDocWhich(*m_pISet
, *m_pDoc
, nWhich
);
807 OSL_ENSURE(nWhich
!= 0, "All broken, Impossible");
808 return m_pISet
->Get(nWhich
);
810 return m_pChpIter
->GetItem( nWhich
);
813 WW8_WrPlc1::WW8_WrPlc1( sal_uInt16 nStructSz
)
814 : nStructSiz( nStructSz
)
816 nDataLen
= 16 * nStructSz
;
817 pData
.reset( new sal_uInt8
[ nDataLen
] );
820 WW8_WrPlc1::~WW8_WrPlc1()
824 WW8_CP
WW8_WrPlc1::Prev() const
826 bool b
= !aPos
.empty();
827 OSL_ENSURE(b
,"Prev called on empty list");
828 return b
? aPos
.back() : 0;
831 void WW8_WrPlc1::Append( WW8_CP nCp
, const void* pNewData
)
833 sal_uLong nInsPos
= aPos
.size() * nStructSiz
;
834 aPos
.push_back( nCp
);
835 if( nDataLen
< nInsPos
+ nStructSiz
)
837 sal_uInt8
* pNew
= new sal_uInt8
[ 2 * nDataLen
];
838 memcpy( pNew
, pData
.get(), nDataLen
);
842 memcpy( pData
.get() + nInsPos
, pNewData
, nStructSiz
);
845 void WW8_WrPlc1::Finish( sal_uLong nLastCp
, sal_uLong nSttCp
)
849 aPos
.push_back( nLastCp
);
851 for(WW8_CP
& rCp
: aPos
)
856 void WW8_WrPlc1::Write( SvStream
& rStrm
)
859 for( i
= 0; i
< aPos
.size(); ++i
)
860 SwWW8Writer::WriteLong( rStrm
, aPos
[i
] );
862 rStrm
.WriteBytes(pData
.get(), (i
-1) * nStructSiz
);
865 // Class WW8_WrPlcField for fields
867 void WW8_WrPlcField::Write( WW8Export
& rWrt
)
869 if( WW8_WrPlc1::Count() <= 1 )
877 pfc
= &rWrt
.pFib
->m_fcPlcffldMom
;
878 plc
= &rWrt
.pFib
->m_lcbPlcffldMom
;
881 pfc
= &rWrt
.pFib
->m_fcPlcffldHdr
;
882 plc
= &rWrt
.pFib
->m_lcbPlcffldHdr
;
886 pfc
= &rWrt
.pFib
->m_fcPlcffldFootnote
;
887 plc
= &rWrt
.pFib
->m_lcbPlcffldFootnote
;
891 pfc
= &rWrt
.pFib
->m_fcPlcffldEdn
;
892 plc
= &rWrt
.pFib
->m_lcbPlcffldEdn
;
896 pfc
= &rWrt
.pFib
->m_fcPlcffldAtn
;
897 plc
= &rWrt
.pFib
->m_lcbPlcffldAtn
;
901 pfc
= &rWrt
.pFib
->m_fcPlcffldTxbx
;
902 plc
= &rWrt
.pFib
->m_lcbPlcffldTxbx
;
906 pfc
= &rWrt
.pFib
->m_fcPlcffldHdrTxbx
;
907 plc
= &rWrt
.pFib
->m_lcbPlcffldHdrTxbx
;
917 sal_uLong nFcStart
= rWrt
.pTableStrm
->Tell();
918 WW8_WrPlc1::Write( *rWrt
.pTableStrm
);
920 *plc
= rWrt
.pTableStrm
->Tell() - nFcStart
;
924 void WW8_WrMagicTable::Write( WW8Export
& rWrt
)
926 if( WW8_WrPlc1::Count() <= 1 )
928 sal_uLong nFcStart
= rWrt
.pTableStrm
->Tell();
929 WW8_WrPlc1::Write( *rWrt
.pTableStrm
);
930 rWrt
.pFib
->m_fcPlcfTch
= nFcStart
;
931 rWrt
.pFib
->m_lcbPlcfTch
= rWrt
.pTableStrm
->Tell() - nFcStart
;
934 void WW8_WrMagicTable::Append( WW8_CP nCp
, sal_uLong nData
)
937 Tell the undocumented table hack that everything between here and the last
938 table position is nontable text, don't do it if the previous position is
939 the same as this one, as that would be a region of 0 length
941 if ((!Count()) || (Prev() != nCp
))
944 UInt32ToSVBT32(nData
,nLittle
);
945 WW8_WrPlc1::Append(nCp
, nLittle
);
949 void SwWW8Writer::FillCount( SvStream
& rStrm
, sal_uLong nCount
)
951 static const sal_uInt32 aNulls
[16] =
953 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 // 64 Byte
958 rStrm
.WriteBytes(aNulls
, 64); // in steps of 64-Byte
961 rStrm
.WriteBytes(aNulls
, nCount
); // write the rest (0 .. 64 Bytes)
964 sal_uLong
SwWW8Writer::FillUntil( SvStream
& rStrm
, sal_uLong nEndPos
)
966 sal_uLong nCurPos
= rStrm
.Tell();
967 if( !nEndPos
) // nEndPos == 0 -> next Page
968 nEndPos
= (nCurPos
+ 0x1ff) & ~0x1ffUL
;
970 if( nEndPos
> nCurPos
)
971 SwWW8Writer::FillCount( rStrm
, nEndPos
- nCurPos
);
972 #if OSL_DEBUG_LEVEL > 0
974 OSL_ENSURE( nEndPos
== nCurPos
, "Falsches FillUntil()" );
979 WW8_WrPlcPn::WW8_WrPlcPn(WW8Export
& rWr
, ePLCFT ePl
, WW8_FC nStartFc
)
984 m_Fkps
.push_back(o3tl::make_unique
<WW8_WrFkp
>(ePlc
, nStartFc
));
987 WW8_WrPlcPn::~WW8_WrPlcPn()
991 sal_uInt8
*WW8_WrPlcPn::CopyLastSprms(sal_uInt8
&rLen
)
993 WW8_WrFkp
& rF
= *m_Fkps
.back();
994 return rF
.CopyLastSprms(rLen
);
997 void WW8_WrPlcPn::AppendFkpEntry(WW8_FC nEndFc
,short nVarLen
,const sal_uInt8
* pSprms
)
999 WW8_WrFkp
* pF
= m_Fkps
.back().get();
1001 // big sprm? build the sprmPHugePapx
1002 sal_uInt8
* pNewSprms
= const_cast<sal_uInt8
*>(pSprms
);
1003 sal_uInt8 aHugePapx
[ 8 ];
1004 if (PAP
== ePlc
&& 488 < nVarLen
)
1006 sal_uInt8
* p
= aHugePapx
;
1007 *p
++ = *pSprms
++; // set style Id
1011 long nDataPos
= rWrt
.pDataStrm
->Tell();
1012 SwWW8Writer::WriteShort( *rWrt
.pDataStrm
, nVarLen
);
1013 rWrt
.pDataStrm
->WriteBytes(pSprms
, nVarLen
);
1015 Set_UInt16( p
, 0x6646 ); // set SprmCode
1016 Set_UInt32( p
, nDataPos
); // set startpos (FC) in the datastream
1017 nVarLen
= static_cast< short >(p
- aHugePapx
);
1018 pSprms
= pNewSprms
= aHugePapx
;
1020 // if append at the same FC-EndPos and there are sprms, then get the old
1021 // sprms and erase it; they will append now with the new sprms
1022 else if( nVarLen
&& pF
->IsEqualPos( nEndFc
))
1023 pF
->MergeToNew( nVarLen
, pNewSprms
);
1024 // has the prev EndFC an empty sprm and the current is empty too, then
1025 // expand only the old EndFc to the new EndFc
1026 else if( !nVarLen
&& pF
->IsEmptySprm() )
1028 pF
->SetNewEnd( nEndFc
);
1032 bool bOk
= pF
->Append(nEndFc
, nVarLen
, pNewSprms
);
1036 pF
= new WW8_WrFkp(ePlc
, pF
->GetEndFc()); // Start new Fkp == end of old Fkp
1038 m_Fkps
.push_back(std::unique_ptr
<WW8_WrFkp
>(pF
));
1039 if( !pF
->Append( nEndFc
, nVarLen
, pNewSprms
) )
1041 OSL_ENSURE( false, "Sprm liess sich nicht einfuegen" );
1044 if( pNewSprms
!= pSprms
) //Merge to new has created a new block
1048 void WW8_WrPlcPn::WriteFkps()
1050 nFkpStartPage
= (sal_uInt16
) ( SwWW8Writer::FillUntil( rWrt
.Strm() ) >> 9 );
1052 for(const std::unique_ptr
<WW8_WrFkp
> & rp
: m_Fkps
)
1054 rp
->Write( rWrt
.Strm(), *rWrt
.m_pGrf
);
1059 rWrt
.pFib
->m_pnChpFirst
= nFkpStartPage
;
1060 rWrt
.pFib
->m_cpnBteChp
= m_Fkps
.size();
1064 rWrt
.pFib
->m_pnPapFirst
= nFkpStartPage
;
1065 rWrt
.pFib
->m_cpnBtePap
= m_Fkps
.size();
1069 void WW8_WrPlcPn::WritePlc()
1071 sal_uLong nFcStart
= rWrt
.pTableStrm
->Tell();
1074 for (i
= 0; i
< m_Fkps
.size(); ++i
)
1076 SwWW8Writer::WriteLong( *rWrt
.pTableStrm
,
1077 m_Fkps
[ i
]->GetStartFc() );
1080 SwWW8Writer::WriteLong( *rWrt
.pTableStrm
,
1081 m_Fkps
[ i
- 1 ]->GetEndFc() );
1083 // fuer jedes FKP die Page ausgeben
1084 for (i
= 0; i
< m_Fkps
.size(); ++i
)
1086 SwWW8Writer::WriteLong( *rWrt
.pTableStrm
, i
+ nFkpStartPage
);
1091 rWrt
.pFib
->m_fcPlcfbteChpx
= nFcStart
;
1092 rWrt
.pFib
->m_lcbPlcfbteChpx
= rWrt
.pTableStrm
->Tell() - nFcStart
;
1096 rWrt
.pFib
->m_fcPlcfbtePapx
= nFcStart
;
1097 rWrt
.pFib
->m_lcbPlcfbtePapx
= rWrt
.pTableStrm
->Tell() - nFcStart
;
1101 WW8_WrFkp::WW8_WrFkp(ePLCFT ePl
, WW8_FC nStartFc
)
1102 : ePlc(ePl
), nStartGrp(511), nOldStartGrp(511),
1103 nItemSize( ( CHP
== ePl
) ? 1 : 13 ),
1104 nIMax(0), nOldVarLen(0), bCombined(false)
1106 pFkp
= reinterpret_cast<sal_uInt8
*>(new sal_Int32
[128]); // 512 Byte
1107 pOfs
= reinterpret_cast<sal_uInt8
*>(new sal_Int32
[128]); // 512 Byte
1108 memset( pFkp
, 0, 4 * 128 );
1109 memset( pOfs
, 0, 4 * 128 );
1110 reinterpret_cast<sal_Int32
*>(pFkp
)[0] = nStartFc
; // 0th entry FC at nStartFc
1113 WW8_WrFkp::~WW8_WrFkp()
1115 delete[] reinterpret_cast<sal_Int32
*>(pFkp
);
1116 delete[] reinterpret_cast<sal_Int32
*>(pOfs
);
1119 sal_uInt8
WW8_WrFkp::SearchSameSprm( sal_uInt16 nVarLen
, const sal_uInt8
* pSprms
)
1123 // if the sprms contained picture-references then never equal!
1124 for( sal_uInt8 n
= static_cast< sal_uInt8
>(nVarLen
- 1); 3 < n
; --n
)
1125 if( pSprms
[ n
] == GRF_MAGIC_3
&&
1126 pSprms
[ n
-1 ] == GRF_MAGIC_2
&&
1127 pSprms
[ n
-2 ] == GRF_MAGIC_1
)
1132 for( i
= 0; i
< nIMax
; i
++ )
1134 sal_uInt8 nStart
= pOfs
[i
* nItemSize
];
1137 const sal_uInt8
* p
= pFkp
+ ( (sal_uInt16
)nStart
<< 1 );
1140 : (((sal_uInt16
)*p
++ << 1 ) == (( nVarLen
+1) & 0xfffe)) )
1141 && !memcmp( p
, pSprms
, nVarLen
) )
1142 return nStart
; // found it
1145 return 0; // didn't found it
1148 sal_uInt8
*WW8_WrFkp::CopyLastSprms(sal_uInt8
&rLen
)
1151 sal_uInt8
*pStart
=nullptr,*pRet
=nullptr;
1156 pStart
= pFkp
+ ( nIMax
+ 1 ) * 4;
1158 sal_uInt8 nStart
= *(pStart
+ (nIMax
-1) * nItemSize
);
1160 const sal_uInt8
* p
= pFkp
+ ( (sal_uInt16
)nStart
<< 1 );
1170 pRet
= new sal_uInt8
[rLen
];
1171 memcpy(pRet
,p
,rLen
);
1176 bool WW8_WrFkp::Append( WW8_FC nEndFc
, sal_uInt16 nVarLen
, const sal_uInt8
* pSprms
)
1178 assert((!nVarLen
|| pSprms
) && "Item pointer missing");
1180 OSL_ENSURE( nVarLen
< ( ( ePlc
== PAP
) ? 497U : 502U ), "Sprms too long !" );
1184 OSL_ENSURE( false, "Fkp::Append: Fkp is already combined" );
1187 sal_Int32 n
= reinterpret_cast<sal_Int32
*>(pFkp
)[nIMax
]; // last entry
1190 OSL_ENSURE( nEndFc
>= n
, "+Fkp: FC backwards" );
1191 OSL_ENSURE( !nVarLen
|| !pSprms
|| nEndFc
!= n
,
1192 "+Fkp: selber FC mehrfach benutzt" );
1193 // selber FC ohne Sprm wird ohne zu mosern ignoriert.
1195 return true; // ignore (do not create a new Fkp)
1198 sal_uInt8 nOldP
= ( nVarLen
) ? SearchSameSprm( nVarLen
, pSprms
) : 0;
1199 // Combine equal entries
1200 short nOffset
=0, nPos
= nStartGrp
;
1201 if (nVarLen
&& !nOldP
)
1204 ? ( 13 == nItemSize
// HACK: PAP and bWrtWW8 !!
1205 ? (nStartGrp
& 0xFFFE ) - nVarLen
- 1
1206 : (nStartGrp
- (((nVarLen
+ 1) & 0xFFFE)+1)) & 0xFFFE )
1207 : ((nStartGrp
- nVarLen
- 1) & 0xFFFE);
1209 return false; // doesn't fit at all
1210 nOffset
= nPos
; // save offset (can also be uneven!)
1211 nPos
&= 0xFFFE; // Pos for Sprms ( gerade Pos )
1214 if( (sal_uInt16
)nPos
<= ( nIMax
+ 2U ) * 4U + ( nIMax
+ 1U ) * nItemSize
)
1215 // does it fits after the CPs and offsets?
1218 reinterpret_cast<sal_Int32
*>(pFkp
)[nIMax
+ 1] = nEndFc
; // insert FC
1220 nOldVarLen
= (sal_uInt8
)nVarLen
;
1221 if( nVarLen
&& !nOldP
)
1222 { // insert it for real
1223 nOldStartGrp
= nStartGrp
;
1226 pOfs
[nIMax
* nItemSize
] = (sal_uInt8
)( nStartGrp
>> 1 );
1227 // ( DatenAnfg >> 1 ) insert
1228 sal_uInt8 nCnt
= static_cast< sal_uInt8
>(CHP
== ePlc
1229 ? ( nVarLen
< 256 ) ? (sal_uInt8
) nVarLen
: 255
1230 : ( ( nVarLen
+ 1 ) >> 1 ));
1232 pFkp
[ nOffset
] = nCnt
; // Enter data length
1233 memcpy( pFkp
+ nOffset
+ 1, pSprms
, nVarLen
); // store Sprms
1237 // do not enter for real ( no Sprms or recurrence )
1238 // DatenAnfg 0 ( no data ) or recurrence
1239 pOfs
[nIMax
* nItemSize
] = nOldP
;
1245 void WW8_WrFkp::Combine()
1250 memcpy( pFkp
+ ( nIMax
+ 1 ) * 4, pOfs
, nIMax
* nItemSize
);
1256 #if defined OSL_BIGENDIAN // only the FCs will be rotated here
1257 sal_uInt16 i
; // the Sprms must be rotated elsewhere
1260 for( i
= 0, p
= (sal_uInt32
*)pFkp
; i
<= nIMax
; i
++, p
++ )
1261 *p
= OSL_SWAPDWORD( *p
);
1262 #endif // ifdef OSL_BIGENDIAN
1265 void WW8_WrFkp::Write( SvStream
& rStrm
, SwWW8WrGrf
& rGrf
)
1267 Combine(); // If not already combined
1269 sal_uInt8
* p
; // Suche Magic fuer nPicLocFc
1270 sal_uInt8
* pEnd
= pFkp
+ nStartGrp
;
1271 for( p
= pFkp
+ 511 - 4; p
>= pEnd
; p
-- )
1273 if( *p
!= GRF_MAGIC_1
) // search for signature 0x12 0x34 0x56 0xXX
1275 if( *(p
+1) != GRF_MAGIC_2
)
1277 if( *(p
+2) != GRF_MAGIC_3
)
1280 SVBT32 nPos
; // signature found
1281 UInt32ToSVBT32( rGrf
.GetFPos(), nPos
); // FilePos the graphics
1282 memcpy( p
, nPos
, 4 ); // patch FilePos over the signature
1284 rStrm
.WriteBytes(pFkp
, 512);
1287 void WW8_WrFkp::MergeToNew( short& rVarLen
, sal_uInt8
*& rpNewSprms
)
1289 sal_uInt8 nStart
= pOfs
[ (nIMax
-1) * nItemSize
];
1292 sal_uInt8
* p
= pFkp
+ ( (sal_uInt16
)nStart
<< 1 );
1294 // old and new equal? Then copy only one into the new sprms
1295 if( nOldVarLen
== rVarLen
&& !memcmp( p
+1, rpNewSprms
, nOldVarLen
))
1297 sal_uInt8
* pNew
= new sal_uInt8
[ nOldVarLen
];
1298 memcpy( pNew
, p
+1, nOldVarLen
);
1303 sal_uInt8
* pNew
= new sal_uInt8
[ nOldVarLen
+ rVarLen
];
1304 memcpy( pNew
, p
+1, nOldVarLen
);
1305 memcpy( pNew
+ nOldVarLen
, rpNewSprms
, rVarLen
);
1308 rVarLen
= rVarLen
+ nOldVarLen
;
1311 // if this sprms don't used from others, remove it
1313 for (sal_uInt16 n
= 0; n
< nIMax
; ++n
)
1315 if (nStart
== pOfs
[n
* nItemSize
])
1323 nStartGrp
= nOldStartGrp
;
1324 memset( p
, 0, nOldVarLen
+1 );
1329 WW8_FC
WW8_WrFkp::GetStartFc() const
1331 // wenn bCombined, dann ist das Array ab pFkp schon Bytemaessig auf LittleEndian
1332 // umgedreht, d.h. zum Herausholen der Anfangs- und Endpositionen muss
1333 // zurueckgedreht werden.
1335 return SVBT32ToUInt32( pFkp
); // 0. Element
1336 return reinterpret_cast<sal_Int32
*>(pFkp
)[0];
1339 WW8_FC
WW8_WrFkp::GetEndFc() const
1342 return SVBT32ToUInt32( &(pFkp
[nIMax
*4]) ); // nIMax-tes SVBT32-Element
1343 return reinterpret_cast<sal_Int32
*>(pFkp
)[nIMax
];
1346 // Method for managing the piece table
1347 WW8_WrPct::WW8_WrPct(WW8_FC nfcMin
)
1353 WW8_WrPct::~WW8_WrPct()
1357 // Fill the piece and create a new one
1358 void WW8_WrPct::AppendPc(WW8_FC nStartFc
)
1360 WW8_CP nStartCp
= nStartFc
- nOldFc
; // subtract the beginning of the text
1363 if (!m_Pcts
.empty())
1365 OSL_ENSURE(1 == m_Pcts
.size(), "empty Piece!");
1370 nOldFc
= nStartFc
; // remember StartFc as old
1372 nStartCp
>>= 1; // for Unicode: number of characters / 2
1374 if (!m_Pcts
.empty())
1376 nStartCp
+= m_Pcts
.back()->GetStartCp();
1379 m_Pcts
.push_back(o3tl::make_unique
<WW8_WrPc
>(nStartFc
, nStartCp
));
1382 void WW8_WrPct::WritePc( WW8Export
& rWrt
)
1384 sal_uLong nPctStart
;
1385 sal_uLong nOldPos
, nEndPos
;
1387 nPctStart
= rWrt
.pTableStrm
->Tell(); // Start piece table
1388 rWrt
.pTableStrm
->WriteChar( ( char )0x02 ); // Status byte PCT
1389 nOldPos
= nPctStart
+ 1; // remember Position
1390 SwWW8Writer::WriteLong( *rWrt
.pTableStrm
, 0 ); // then the length
1392 for (auto const& it
: m_Pcts
) // ranges
1394 SwWW8Writer::WriteLong( *rWrt
.pTableStrm
, it
->GetStartCp() );
1397 // calculate the last Pos
1398 sal_uLong nStartCp
= rWrt
.pFib
->m_fcMac
- nOldFc
;
1399 nStartCp
>>= 1; // For Unicode: number of characters / 2
1400 nStartCp
+= m_Pcts
.back()->GetStartCp();
1401 SwWW8Writer::WriteLong( *rWrt
.pTableStrm
, nStartCp
);
1404 for (auto const& it
: m_Pcts
)
1406 SwWW8Writer::WriteShort(*rWrt
.pTableStrm
, it
->GetStatus());
1407 SwWW8Writer::WriteLong(*rWrt
.pTableStrm
, it
->GetStartFc());
1408 SwWW8Writer::WriteShort( *rWrt
.pTableStrm
, 0); // PRM=0
1411 // entries in the FIB
1412 rWrt
.pFib
->m_fcClx
= nPctStart
;
1413 nEndPos
= rWrt
.pTableStrm
->Tell();
1414 rWrt
.pFib
->m_lcbClx
= nEndPos
- nPctStart
;
1416 // and register the length as well
1417 SwWW8Writer::WriteLong( *rWrt
.pTableStrm
, nOldPos
,
1418 nEndPos
- nPctStart
-5 );
1422 void WW8_WrPct::SetParaBreak()
1424 OSL_ENSURE( !m_Pcts
.empty(), "SetParaBreak : m_Pcts.empty()" );
1425 m_Pcts
.back()->SetStatus();
1428 WW8_CP
WW8_WrPct::Fc2Cp( sal_uLong nFc
) const
1430 OSL_ENSURE( nFc
>= (sal_uLong
)nOldFc
, "FilePos lies in front of last piece" );
1431 OSL_ENSURE( ! m_Pcts
.empty(), "Fc2Cp no piece available" );
1434 nFc
/= 2; // Unicode
1435 return nFc
+ m_Pcts
.back()->GetStartCp();
1438 void WW8Export::AppendBookmarks( const SwTextNode
& rNd
, sal_Int32 nAktPos
, sal_Int32 nLen
)
1440 std::vector
< const ::sw::mark::IMark
* > aArr
;
1441 sal_uInt16 nContent
;
1442 const sal_Int32 nAktEnd
= nAktPos
+ nLen
;
1443 if( GetWriter().GetBookmarks( rNd
, nAktPos
, nAktEnd
, aArr
))
1445 sal_uLong nNd
= rNd
.GetIndex(), nSttCP
= Fc2Cp( Strm().Tell() );
1446 for(const ::sw::mark::IMark
* p
: aArr
)
1448 const ::sw::mark::IMark
& rBkmk
= *p
;
1449 if(dynamic_cast< const ::sw::mark::IFieldmark
*>(&rBkmk
))
1452 const SwPosition
* pPos
= &rBkmk
.GetMarkPos();
1453 const SwPosition
* pOPos
= nullptr;
1454 if(rBkmk
.IsExpanded())
1455 pOPos
= &rBkmk
.GetOtherMarkPos();
1456 if( pOPos
&& pOPos
->nNode
== pPos
->nNode
&&
1457 pOPos
->nContent
< pPos
->nContent
)
1460 pOPos
= &rBkmk
.GetMarkPos();
1463 if( !pOPos
|| ( nNd
== pPos
->nNode
.GetIndex() &&
1464 ( nContent
= pPos
->nContent
.GetIndex() ) >= nAktPos
&&
1465 nContent
< nAktEnd
) )
1467 sal_uLong nCp
= nSttCP
+ pPos
->nContent
.GetIndex() - nAktPos
;
1468 m_pBkmks
->Append(nCp
, BookmarkToWord(rBkmk
.GetName()), &rBkmk
);
1470 if( pOPos
&& nNd
== pOPos
->nNode
.GetIndex() &&
1471 ( nContent
= pOPos
->nContent
.GetIndex() ) >= nAktPos
&&
1472 nContent
< nAktEnd
)
1474 sal_uLong nCp
= nSttCP
+ pOPos
->nContent
.GetIndex() - nAktPos
;
1475 m_pBkmks
->Append(nCp
, BookmarkToWord(rBkmk
.GetName()), &rBkmk
);
1481 void WW8Export::AppendAnnotationMarks(const SwTextNode
& rNode
, sal_Int32 nAktPos
, sal_Int32 nLen
)
1484 if (GetAnnotationMarks(rNode
, nAktPos
, nAktPos
+ nLen
, aMarks
))
1486 for (IMarkVector::const_iterator it
= aMarks
.begin(), end
= aMarks
.end(); it
!= end
; ++it
)
1488 sw::mark::IMark
* pMark
= (*it
);
1489 const sal_Int32 nStart
= pMark
->GetMarkStart().nContent
.GetIndex();
1490 if (nStart
== nAktPos
)
1492 m_pAtn
->AddRangeStartPosition(pMark
->GetName(), Fc2Cp(Strm().Tell()));
1498 void WW8Export::AppendSmartTags(const SwTextNode
& rTextNode
)
1500 std::map
<OUString
, OUString
> aStatements
= SwRDFHelper::getTextNodeStatements("urn:bails", rTextNode
);
1501 if (!aStatements
.empty())
1503 WW8_CP nCP
= Fc2Cp(Strm().Tell());
1504 m_pFactoids
->Append(nCP
, nCP
, aStatements
);
1508 void WW8Export::MoveFieldMarks(WW8_CP nFrom
, WW8_CP nTo
)
1510 m_pBkmks
->MoveFieldMarks(nFrom
, nTo
);
1513 void WW8Export::AppendBookmark( const OUString
& rName
)
1515 sal_uLong nSttCP
= Fc2Cp( Strm().Tell() );
1516 m_pBkmks
->Append( nSttCP
, rName
);
1519 boost::optional
<SvxBrushItem
> MSWordExportBase::getBackground()
1521 boost::optional
<SvxBrushItem
> oRet
;
1522 const SwFrameFormat
&rFormat
= m_pDoc
->GetPageDesc(0).GetMaster();
1523 SvxBrushItem
aBrush(RES_BACKGROUND
);
1524 SfxItemState eState
= rFormat
.GetBackgroundState(aBrush
);
1526 if (SfxItemState::SET
== eState
)
1528 // The 'color' is set for the first page style - take it and use it as the background color of the entire DOCX
1529 if (aBrush
.GetColor().GetColor() != COL_AUTO
)
1535 // #i120928 collect all the graphics of bullets applied to paragraphs
1536 int MSWordExportBase::CollectGrfsOfBullets()
1538 m_vecBulletPic
.clear();
1542 size_t nCountRule
= m_pDoc
->GetNumRuleTable().size();
1543 for (size_t n
= 0; n
< nCountRule
; ++n
)
1545 const SwNumRule
&rRule
= *( m_pDoc
->GetNumRuleTable().at(n
) );
1546 sal_uInt16 nLevels
= rRule
.IsContinusNum() ? 1 : 9;
1547 for (sal_uInt16 nLvl
= 0; nLvl
< nLevels
; ++nLvl
)
1549 const SwNumFormat
&rFormat
= rRule
.Get(nLvl
);
1550 if (SVX_NUM_BITMAP
!= rFormat
.GetNumberingType())
1554 const Graphic
*pGraf
= rFormat
.GetBrush()? rFormat
.GetBrush()->GetGraphic():nullptr;
1558 for (const Graphic
* p
: m_vecBulletPic
)
1560 if (p
->GetChecksum() == pGraf
->GetChecksum())
1568 Size
aSize(pGraf
->GetPrefSize());
1569 if (0 != aSize
.Height() && 0 != aSize
.Width())
1570 m_vecBulletPic
.push_back(pGraf
);
1577 return m_vecBulletPic
.size();
1580 void MSWordExportBase::BulletDefinitions()
1582 for (size_t i
= 0; i
< m_vecBulletPic
.size(); ++i
)
1584 const MapMode
aMapMode(MapUnit::MapTwip
);
1585 const Graphic
& rGraphic
= *m_vecBulletPic
[i
];
1586 Size
aSize(rGraphic
.GetPrefSize());
1587 if (MapUnit::MapPixel
== rGraphic
.GetPrefMapMode().GetMapUnit())
1588 aSize
= Application::GetDefaultDevice()->PixelToLogic(aSize
, aMapMode
);
1590 aSize
= OutputDevice::LogicToLogic(aSize
,rGraphic
.GetPrefMapMode(), aMapMode
);
1592 if (0 != aSize
.Height() && 0 != aSize
.Width())
1593 AttrOutput().BulletDefinition(i
, rGraphic
, aSize
);
1597 //Export Graphic of Bullets
1598 void WW8Export::ExportGrfBullet(const SwTextNode
& rNd
)
1600 int nCount
= CollectGrfsOfBullets();
1603 SwPosition
aPos(rNd
);
1604 OUString
aPicBullets("_PictureBullets");
1605 AppendBookmark(aPicBullets
);
1606 for (int i
= 0; i
< nCount
; i
++)
1608 ww8::Frame
aFrame(*(m_vecBulletPic
[i
]), aPos
);
1609 OutGrfBullets(aFrame
);
1611 AppendBookmark(aPicBullets
);
1615 static sal_uInt8 nAttrMagicIdx
= 0;
1616 void WW8Export::OutGrfBullets(const ww8::Frame
& rFrame
)
1618 if ( !m_pGrf
|| !m_pChpPlc
|| !pO
)
1621 m_pGrf
->Insert(rFrame
);
1622 m_pChpPlc
->AppendFkpEntry( Strm().Tell(), pO
->size(), pO
->data() );
1625 WriteChar( (char)1 );
1627 sal_uInt8 aArr
[ 22 ];
1628 sal_uInt8
* pArr
= aArr
;
1631 Set_UInt16( pArr
, 0x855 );
1632 Set_UInt8( pArr
, 1 );
1634 Set_UInt16( pArr
, 0x083c );
1635 Set_UInt8( pArr
, 0x81 );
1638 Set_UInt16( pArr
, 0x6a03 );
1639 Set_UInt32( pArr
, GRF_MAGIC_321
);
1641 //extern nAttrMagicIdx;
1643 Set_UInt8( pArr
, nAttrMagicIdx
++ );
1644 m_pChpPlc
->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr
- aArr
), aArr
);
1647 int MSWordExportBase::GetGrfIndex(const SvxBrushItem
& rBrush
)
1651 const Graphic
* pGraphic
= rBrush
.GetGraphic();
1654 for (size_t i
= 0; i
< m_vecBulletPic
.size(); ++i
)
1656 if (m_vecBulletPic
[i
]->GetChecksum() == pGraphic
->GetChecksum())
1667 void WW8_WrtRedlineAuthor::Write( Writer
& rWrt
)
1669 WW8Export
& rWW8Wrt
= *(static_cast<SwWW8Writer
&>(rWrt
).m_pExport
);
1670 rWW8Wrt
.WriteAsStringTable(maAuthors
, rWW8Wrt
.pFib
->m_fcSttbfRMark
,
1671 rWW8Wrt
.pFib
->m_lcbSttbfRMark
);
1674 sal_uInt16
WW8Export::AddRedlineAuthor( sal_uInt16 nId
)
1676 if( !m_pRedlAuthors
)
1678 m_pRedlAuthors
= new WW8_WrtRedlineAuthor
;
1679 m_pRedlAuthors
->AddName("Unknown");
1681 return m_pRedlAuthors
->AddName( SW_MOD()->GetRedlineAuthor( nId
) );
1684 void WW8Export::WriteAsStringTable(const std::vector
<OUString
>& rStrings
,
1685 sal_Int32
& rfcSttbf
, sal_Int32
& rlcbSttbf
)
1687 sal_uInt16 n
, nCount
= static_cast< sal_uInt16
>(rStrings
.size());
1690 // we have some Redlines found in the document -> the
1691 // Author Name Stringtable
1692 SvStream
& rStrm
= *pTableStrm
;
1693 rfcSttbf
= rStrm
.Tell();
1694 SwWW8Writer::WriteShort( rStrm
, -1 );
1695 SwWW8Writer::WriteLong( rStrm
, nCount
);
1696 for( n
= 0; n
< nCount
; ++n
)
1698 const OUString
& rNm
= rStrings
[n
];
1699 SwWW8Writer::WriteShort( rStrm
, rNm
.getLength() );
1700 SwWW8Writer::WriteString16(rStrm
, rNm
, false);
1702 rlcbSttbf
= rStrm
.Tell() - rfcSttbf
;
1706 // WriteShort() target an FilePos nPos den Wert nVal ein und seekt auf die
1707 // alte FilePos zurueck. Benutzt zum Nachtragen von Laengen.
1708 void SwWW8Writer::WriteShort( SvStream
& rStrm
, sal_uLong nPos
, sal_Int16 nVal
)
1710 sal_uLong nOldPos
= rStrm
.Tell(); // remember Pos
1712 SwWW8Writer::WriteShort( rStrm
, nVal
);
1713 rStrm
.Seek( nOldPos
);
1716 void SwWW8Writer::WriteLong( SvStream
& rStrm
, sal_uLong nPos
, sal_Int32 nVal
)
1718 sal_uLong nOldPos
= rStrm
.Tell(); // remember Pos
1720 SwWW8Writer::WriteLong( rStrm
, nVal
);
1721 rStrm
.Seek( nOldPos
);
1724 void SwWW8Writer::InsUInt16(ww::bytes
&rO
, sal_uInt16 n
)
1727 ShortToSVBT16( n
, nL
);
1728 rO
.push_back(nL
[0]);
1729 rO
.push_back(nL
[1]);
1732 void SwWW8Writer::InsUInt32(ww::bytes
&rO
, sal_uInt32 n
)
1735 UInt32ToSVBT32( n
, nL
);
1736 rO
.push_back(nL
[0]);
1737 rO
.push_back(nL
[1]);
1738 rO
.push_back(nL
[2]);
1739 rO
.push_back(nL
[3]);
1742 void SwWW8Writer::InsAsString16(ww::bytes
&rO
, const OUString
& rStr
)
1744 const sal_Unicode
* pStr
= rStr
.getStr();
1745 for (sal_Int32 n
= 0, nLen
= rStr
.getLength(); n
< nLen
; ++n
, ++pStr
)
1746 SwWW8Writer::InsUInt16( rO
, *pStr
);
1749 void SwWW8Writer::InsAsString8(ww::bytes
&rO
, const OUString
& rStr
,
1750 rtl_TextEncoding eCodeSet
)
1752 OString
sTmp(OUStringToOString(rStr
, eCodeSet
));
1753 const sal_Char
*pStart
= sTmp
.getStr();
1754 const sal_Char
*pEnd
= pStart
+ sTmp
.getLength();
1755 rO
.reserve(rO
.size() + sTmp
.getLength());
1757 std::copy(pStart
, pEnd
, std::inserter(rO
, rO
.end()));
1760 void SwWW8Writer::WriteString16(SvStream
& rStrm
, const OUString
& rStr
,
1764 SwWW8Writer::InsAsString16(aBytes
, rStr
);
1766 SwWW8Writer::InsUInt16(aBytes
, 0);
1767 //vectors are guaranteed to have contiguous memory, so we can do
1768 //this while migrating away from WW8Bytes. Meyers Effective STL, item 16
1769 if (!aBytes
.empty())
1770 rStrm
.WriteBytes(&aBytes
[0], aBytes
.size());
1773 void SwWW8Writer::WriteString_xstz(SvStream
& rStrm
, const OUString
& rStr
, bool bAddZero
)
1776 SwWW8Writer::InsUInt16(aBytes
, rStr
.getLength());
1777 SwWW8Writer::InsAsString16(aBytes
, rStr
);
1779 SwWW8Writer::InsUInt16(aBytes
, 0);
1780 rStrm
.WriteBytes(&aBytes
[0], aBytes
.size());
1783 void SwWW8Writer::WriteString8(SvStream
& rStrm
, const OUString
& rStr
,
1784 bool bAddZero
, rtl_TextEncoding eCodeSet
)
1787 SwWW8Writer::InsAsString8(aBytes
, rStr
, eCodeSet
);
1789 aBytes
.push_back(0);
1790 //vectors are guaranteed to have contiguous memory, so we can do
1791 ////this while migrating away from WW8Bytes. Meyers Effective STL, item 16
1792 if (!aBytes
.empty())
1793 rStrm
.WriteBytes(&aBytes
[0], aBytes
.size());
1796 void WW8Export::WriteStringAsPara( const OUString
& rText
)
1798 if( !rText
.isEmpty() )
1799 OutSwString(rText
, 0, rText
.getLength());
1800 WriteCR(); // CR thereafter
1803 SwWW8Writer::InsUInt16( aArr
, 0/*nStyleId*/ );
1807 SwWW8Writer::InsUInt16( aArr
, NS_sprm::LN_PFInTable
);
1808 aArr
.push_back( 1 );
1811 sal_uLong nPos
= Strm().Tell();
1812 m_pPapPlc
->AppendFkpEntry( nPos
, aArr
.size(), aArr
.data() );
1813 m_pChpPlc
->AppendFkpEntry( nPos
);
1816 void MSWordExportBase::WriteSpecialText( sal_uLong nStart
, sal_uLong nEnd
, sal_uInt8 nTTyp
)
1818 sal_uInt8 nOldTyp
= m_nTextTyp
;
1820 SwPaM
* pOldPam
= m_pCurPam
; //!! Simply shifting the PaM without restoring should do the job too
1821 sal_uLong nOldStart
= m_nCurStart
;
1822 sal_uLong nOldEnd
= m_nCurEnd
;
1823 SwPaM
* pOldEnd
= m_pOrigPam
;
1824 bool bOldPageDescs
= m_bOutPageDescs
;
1825 m_bOutPageDescs
= false;
1826 // bOutKF was setted / stored in WriteKF1
1827 SetCurPam(nStart
, nEnd
);
1829 // clear linked textboxes since old ones can't be linked to frames in this section
1830 m_aLinkedTextboxesHelper
.clear();
1832 // tdf#106261 Reset table infos, otherwise the depth of the cells will be
1833 // incorrect, in case the header/footer had table(s) and we try to export
1834 // the same table second time.
1835 ww8::WW8TableInfo::Pointer_t pOldTableInfo
= m_pTableInfo
;
1836 m_pTableInfo
= std::make_shared
<ww8::WW8TableInfo
>();
1840 m_pTableInfo
= pOldTableInfo
;
1842 m_bOutPageDescs
= bOldPageDescs
;
1843 delete m_pCurPam
; // delete Pam
1844 m_pCurPam
= pOldPam
;
1845 m_nCurStart
= nOldStart
;
1846 m_nCurEnd
= nOldEnd
;
1847 m_pOrigPam
= pOldEnd
;
1848 m_nTextTyp
= nOldTyp
;
1851 void WW8Export::OutSwString(const OUString
& rStr
, sal_Int32 nStt
,
1852 sal_Int32
const nLen
)
1855 SAL_INFO( "sw.ww8.level2", "<OutSwString>" );
1859 if( nStt
|| nLen
!= rStr
.getLength() )
1861 OUString
sOut( rStr
.copy( nStt
, nLen
) );
1863 SAL_INFO( "sw.ww8.level2", sOut
);
1865 SwWW8Writer::WriteString16(Strm(), sOut
, false);
1869 SAL_INFO( "sw.ww8.level2", rStr
);
1871 SwWW8Writer::WriteString16(Strm(), rStr
, false);
1875 SAL_INFO( "sw.ww8.level2", "</OutSwString>" );
1878 void WW8Export::WriteCR(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
1880 if (pTableTextNodeInfoInner
.get() != nullptr && pTableTextNodeInfoInner
->getDepth() == 1 && pTableTextNodeInfoInner
->isEndOfCell())
1883 WriteChar( '\015' );
1885 m_pPiece
->SetParaBreak();
1888 void WW8Export::WriteChar( sal_Unicode c
)
1890 Strm().WriteUInt16( c
);
1893 void MSWordExportBase::SetCurPam(sal_uLong nStt
, sal_uLong nEnd
)
1897 m_pCurPam
= Writer::NewSwPaM( *m_pDoc
, nStt
, nEnd
);
1899 // Recognize tables in special cases
1900 if ( nStt
!= m_pCurPam
->GetMark()->nNode
.GetIndex() &&
1901 m_pDoc
->GetNodes()[ nStt
]->IsTableNode() )
1903 m_pCurPam
->GetMark()->nNode
= nStt
;
1906 m_pOrigPam
= m_pCurPam
;
1907 m_pCurPam
->Exchange();
1910 void MSWordExportBase::SaveData( sal_uLong nStt
, sal_uLong nEnd
)
1912 MSWordSaveData aData
;
1914 // WW8Export only stuff - zeroed here not to issue warnings
1915 aData
.pOOld
= nullptr;
1918 aData
.pOldPam
= m_pCurPam
;
1919 aData
.pOldEnd
= m_pOrigPam
;
1920 aData
.pOldFlyFormat
= m_pParentFrame
;
1921 aData
.pOldPageDesc
= m_pAktPageDesc
;
1923 aData
.pOldFlyOffset
= m_pFlyOffset
;
1924 aData
.eOldAnchorType
= m_eNewAnchorType
;
1926 aData
.bOldOutTable
= m_bOutTable
;
1927 aData
.bOldFlyFrameAttrs
= m_bOutFlyFrameAttrs
;
1928 aData
.bOldStartTOX
= m_bStartTOX
;
1929 aData
.bOldInWriteTOX
= m_bInWriteTOX
;
1931 SetCurPam(nStt
, nEnd
);
1933 m_bOutTable
= false;
1934 // Caution: bIsInTable should not be set here
1935 m_bOutFlyFrameAttrs
= false;
1936 m_bStartTOX
= false;
1937 m_bInWriteTOX
= false;
1939 m_aSaveData
.push( aData
);
1942 void MSWordExportBase::RestoreData()
1944 MSWordSaveData
&rData
= m_aSaveData
.top();
1947 m_pCurPam
= rData
.pOldPam
;
1948 m_nCurStart
= rData
.nOldStart
;
1949 m_nCurEnd
= rData
.nOldEnd
;
1950 m_pOrigPam
= rData
.pOldEnd
;
1952 m_bOutTable
= rData
.bOldOutTable
;
1953 m_bOutFlyFrameAttrs
= rData
.bOldFlyFrameAttrs
;
1954 m_bStartTOX
= rData
.bOldStartTOX
;
1955 m_bInWriteTOX
= rData
.bOldInWriteTOX
;
1957 m_pParentFrame
= rData
.pOldFlyFormat
;
1958 m_pAktPageDesc
= rData
.pOldPageDesc
;
1960 m_eNewAnchorType
= rData
.eOldAnchorType
;
1961 m_pFlyOffset
= rData
.pOldFlyOffset
;
1966 void WW8Export::SaveData( sal_uLong nStt
, sal_uLong nEnd
)
1968 MSWordExportBase::SaveData( nStt
, nEnd
);
1970 MSWordSaveData
&rData
= m_aSaveData
.top();
1975 pO
= new ww::bytes();
1978 rData
.pOOld
= nullptr; // reuse pO
1980 rData
.bOldWriteAll
= GetWriter().bWriteAll
;
1981 GetWriter().bWriteAll
= true;
1984 void WW8Export::RestoreData()
1986 MSWordSaveData
&rData
= m_aSaveData
.top();
1988 GetWriter().bWriteAll
= rData
.bOldWriteAll
;
1990 OSL_ENSURE( pO
->empty(), "pO is not empty in WW8Export::RestoreData()" );
1997 MSWordExportBase::RestoreData();
2000 void WW8AttributeOutput::TableInfoCell( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2002 sal_uInt32 nDepth
= pTableTextNodeInfoInner
->getDepth();
2007 m_rWW8Export
.InsUInt16( NS_sprm::LN_PFInTable
);
2008 m_rWW8Export
.pO
->push_back( (sal_uInt8
)0x1 );
2009 m_rWW8Export
.InsUInt16( NS_sprm::LN_PTableDepth
);
2010 m_rWW8Export
.InsUInt32( nDepth
);
2012 if ( nDepth
> 1 && pTableTextNodeInfoInner
->isEndOfCell() )
2014 m_rWW8Export
.InsUInt16( NS_sprm::LN_PCell
);
2015 m_rWW8Export
.pO
->push_back( (sal_uInt8
)0x1 );
2020 void WW8AttributeOutput::TableInfoRow( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2022 sal_uInt32 nDepth
= pTableTextNodeInfoInner
->getDepth();
2027 if ( pTableTextNodeInfoInner
->isEndOfLine() )
2029 m_rWW8Export
.InsUInt16( NS_sprm::LN_PFInTable
);
2030 m_rWW8Export
.pO
->push_back( (sal_uInt8
)0x1 );
2034 m_rWW8Export
.InsUInt16( NS_sprm::LN_PFTtp
);
2035 m_rWW8Export
.pO
->push_back( (sal_uInt8
)0x1 );
2038 m_rWW8Export
.InsUInt16( NS_sprm::LN_PTableDepth
);
2039 m_rWW8Export
.InsUInt32( nDepth
);
2043 m_rWW8Export
.InsUInt16( NS_sprm::LN_PCell
);
2044 m_rWW8Export
.pO
->push_back( (sal_uInt8
)0x1 );
2045 m_rWW8Export
.InsUInt16( NS_sprm::LN_PRow
);
2046 m_rWW8Export
.pO
->push_back( (sal_uInt8
)0x1 );
2049 TableDefinition( pTableTextNodeInfoInner
);
2050 TableHeight( pTableTextNodeInfoInner
);
2051 TableBackgrounds( pTableTextNodeInfoInner
);
2052 TableDefaultBorders( pTableTextNodeInfoInner
);
2053 TableCanSplit( pTableTextNodeInfoInner
);
2054 TableBidi( pTableTextNodeInfoInner
);
2055 TableVerticalCell( pTableTextNodeInfoInner
);
2056 TableOrientation( pTableTextNodeInfoInner
);
2057 TableSpacing( pTableTextNodeInfoInner
);
2058 TableCellBorders( pTableTextNodeInfoInner
);
2063 static sal_uInt16
lcl_TCFlags(SwDoc
&rDoc
, const SwTableBox
* pBox
, sal_Int32 nRowSpan
)
2065 sal_uInt16 nFlags
= 0;
2069 else if (nRowSpan
< 0)
2072 if (pBox
!= nullptr)
2074 const SwFrameFormat
* pFormat
= pBox
->GetFrameFormat();
2075 switch (pFormat
->GetVertOrient().GetVertOrient())
2077 case text::VertOrientation::CENTER
:
2080 case text::VertOrientation::BOTTOM
:
2086 const SwStartNode
* pSttNd
= pBox
->GetSttNd();
2089 SwNodeIndex
aIdx( *pSttNd
);
2090 const SwContentNode
* pCNd
= pSttNd
->GetNodes().GoNext( &aIdx
);
2091 if( pCNd
&& pCNd
->IsTextNode())
2093 SfxItemSet
aCoreSet(rDoc
.GetAttrPool(), RES_CHRATR_ROTATE
, RES_CHRATR_ROTATE
);
2094 static_cast<const SwTextNode
*>(pCNd
)->GetAttr( aCoreSet
, 0, static_cast<const SwTextNode
*>(pCNd
)->GetText().getLength());
2095 const SfxPoolItem
* pRotItem
;
2096 if ( SfxItemState::SET
== aCoreSet
.GetItemState(RES_CHRATR_ROTATE
, true, &pRotItem
))
2098 const SvxCharRotateItem
* pRotate
= static_cast<const SvxCharRotateItem
*>(pRotItem
);
2099 if(pRotate
&& pRotate
->GetValue() == 900)
2101 nFlags
= nFlags
| 0x0004 | 0x0008;
2103 else if(pRotate
&& pRotate
->GetValue() == 2700 )
2105 nFlags
= nFlags
| 0x0004 | 0x0010;
2115 void WW8AttributeOutput::TableVerticalCell( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2117 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
2118 const SwTableLine
* pTabLine
= pTabBox
->GetUpper();
2119 const SwTableBoxes
& rTableBoxes
= pTabLine
->GetTabBoxes();
2121 sal_uInt8 nBoxes
= rTableBoxes
.size();
2122 for ( sal_uInt8 n
= 0; n
< nBoxes
; n
++ )
2124 const SwTableBox
* pTabBox1
= rTableBoxes
[n
];
2125 const SwFrameFormat
* pFrameFormat
= pTabBox1
->GetFrameFormat();
2127 if ( FRMDIR_VERT_TOP_RIGHT
== m_rWW8Export
.TrueFrameDirection( *pFrameFormat
) )
2129 m_rWW8Export
.InsUInt16( NS_sprm::LN_TTextFlow
);
2130 m_rWW8Export
.pO
->push_back( sal_uInt8(n
) ); //start range
2131 m_rWW8Export
.pO
->push_back( sal_uInt8(n
+ 1) ); //end range
2132 m_rWW8Export
.InsUInt16( 5 ); //Equals vertical writing
2137 void WW8AttributeOutput::TableCanSplit( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2139 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
2140 const SwTableLine
* pTabLine
= pTabBox
->GetUpper();
2141 const SwFrameFormat
* pLineFormat
= pTabLine
->GetFrameFormat();
2144 By default the row can be split in word, and now in writer we have a
2145 feature equivalent to this, Word stores 1 for fCantSplit if the row
2146 cannot be split, we set true if we can split it. An example is #i4569#
2149 const SwFormatRowSplit
& rSplittable
= pLineFormat
->GetRowSplit();
2150 sal_uInt8 nCantSplit
= (!rSplittable
.GetValue()) ? 1 : 0;
2151 m_rWW8Export
.InsUInt16( NS_sprm::LN_TFCantSplit
);
2152 m_rWW8Export
.pO
->push_back( nCantSplit
);
2153 m_rWW8Export
.InsUInt16( NS_sprm::LN_TFCantSplit90
); // also write fCantSplit90
2154 m_rWW8Export
.pO
->push_back( nCantSplit
);
2157 void WW8AttributeOutput::TableBidi( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2159 const SwTable
* pTable
= pTableTextNodeInfoInner
->getTable();
2160 const SwFrameFormat
* pFrameFormat
= pTable
->GetFrameFormat();
2162 if ( m_rWW8Export
.TrueFrameDirection(*pFrameFormat
) == FRMDIR_HORI_RIGHT_TOP
)
2164 m_rWW8Export
.InsUInt16( NS_sprm::LN_TFBiDi
);
2165 m_rWW8Export
.InsUInt16( 1 );
2169 void WW8AttributeOutput::TableRowRedline( ww8::WW8TableNodeInfoInner::Pointer_t
/*pTableTextNodeInfoInner*/ )
2173 void WW8AttributeOutput::TableCellRedline( ww8::WW8TableNodeInfoInner::Pointer_t
/*pTableTextNodeInfoInner*/ )
2177 void WW8AttributeOutput::TableHeight( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2179 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
2180 const SwTableLine
* pTabLine
= pTabBox
->GetUpper();
2181 const SwFrameFormat
* pLineFormat
= pTabLine
->GetFrameFormat();
2183 // Zeilenhoehe ausgeben sprmTDyaRowHeight
2185 const SwFormatFrameSize
& rLSz
= pLineFormat
->GetFrameSize();
2186 if ( ATT_VAR_SIZE
!= rLSz
.GetHeightSizeType() && rLSz
.GetHeight() )
2188 if ( ATT_MIN_SIZE
== rLSz
.GetHeightSizeType() )
2189 nHeight
= rLSz
.GetHeight();
2191 nHeight
= -rLSz
.GetHeight();
2196 m_rWW8Export
.InsUInt16( NS_sprm::LN_TDyaRowHeight
);
2197 m_rWW8Export
.InsUInt16( (sal_uInt16
)nHeight
);
2202 void WW8AttributeOutput::TableOrientation( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2204 const SwTable
* pTable
= pTableTextNodeInfoInner
->getTable();
2206 const SwFrameFormat
*pFormat
= pTable
->GetFrameFormat();
2209 SAL_WARN( "sw.ww8", "FrameFormat is nil" );
2213 const SwFormatHoriOrient
&rHori
= pFormat
->GetHoriOrient();
2214 const SwFormatVertOrient
&rVert
= pFormat
->GetVertOrient();
2217 (text::RelOrientation::PRINT_AREA
== rHori
.GetRelationOrient() ||
2218 text::RelOrientation::FRAME
== rHori
.GetRelationOrient())
2220 (text::RelOrientation::PRINT_AREA
== rVert
.GetRelationOrient() ||
2221 text::RelOrientation::FRAME
== rVert
.GetRelationOrient())
2224 sal_Int16 eHOri
= rHori
.GetHoriOrient();
2227 case text::HoriOrientation::CENTER
:
2228 case text::HoriOrientation::RIGHT
:
2229 m_rWW8Export
.InsUInt16( NS_sprm::LN_TJc90
);
2230 m_rWW8Export
.InsUInt16( text::HoriOrientation::RIGHT
== eHOri
? 2 : 1 );
2238 void WW8AttributeOutput::TableSpacing(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2240 const SwTable
* pTable
= pTableTextNodeInfoInner
->getTable();
2241 const SwTableFormat
* pTableFormat
= pTable
->GetFrameFormat();
2244 // Writing these SPRM's will make the table a floating one, so only write
2245 // them in case the table is already inside a frame.
2246 if (pTableFormat
!= nullptr && pTable
->GetTableNode()->GetFlyFormat())
2248 const SvxULSpaceItem
& rUL
= pTableFormat
->GetULSpace();
2250 if (rUL
.GetUpper() > 0)
2252 sal_uInt8 nPadding
= 2;
2253 sal_uInt8 nPcVert
= 0;
2254 sal_uInt8 nPcHorz
= 0;
2256 sal_uInt8 nTPc
= (nPadding
<< 4) | (nPcVert
<< 2) | nPcHorz
;
2258 m_rWW8Export
.InsUInt16(NS_sprm::LN_TPc
);
2259 m_rWW8Export
.pO
->push_back( nTPc
);
2261 m_rWW8Export
.InsUInt16(NS_sprm::LN_TDyaAbs
);
2262 m_rWW8Export
.InsUInt16(rUL
.GetUpper());
2264 m_rWW8Export
.InsUInt16(NS_sprm::LN_TDyaFromText
);
2265 m_rWW8Export
.InsUInt16(rUL
.GetUpper());
2268 if (rUL
.GetLower() > 0)
2270 m_rWW8Export
.InsUInt16(NS_sprm::LN_TDyaFromTextBottom
);
2271 m_rWW8Export
.InsUInt16(rUL
.GetLower());
2276 void WW8AttributeOutput::TableDefinition( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2278 const SwTable
* pTable
= pTableTextNodeInfoInner
->getTable();
2280 if ( pTable
->GetRowsToRepeat() > pTableTextNodeInfoInner
->getRow() )
2282 m_rWW8Export
.InsUInt16( NS_sprm::LN_TTableHeader
);
2283 m_rWW8Export
.pO
->push_back( 1 );
2286 ww8::TableBoxVectorPtr pTableBoxes
=
2287 pTableTextNodeInfoInner
->getTableBoxesOfRow();
2288 // number of cell written
2289 sal_uInt32 nBoxes
= pTableBoxes
->size();
2290 assert(nBoxes
<= ww8::MAXTABLECELLS
);
2293 m_rWW8Export
.InsUInt16( NS_sprm::LN_TDefTable
);
2294 sal_uInt16 nSprmSize
= 2 + (nBoxes
+ 1) * 2 + nBoxes
* 20;
2295 m_rWW8Export
.InsUInt16( nSprmSize
); // length
2298 m_rWW8Export
.pO
->push_back( static_cast<sal_uInt8
>(nBoxes
) );
2302 ALWAYS relative when text::HoriOrientation::NONE (nPageSize + ( nPageSize / 10 )) < nTableSz,
2303 in that case the cell width's and table width's are not real. The table
2304 width is maxed and cells relative, so we need the frame (generally page)
2305 width that the table is in to work out the true widths.
2307 //const bool bNewTableModel = pTable->IsNewModel();
2308 const SwFrameFormat
*pFormat
= pTable
->GetFrameFormat();
2311 SAL_WARN( "sw.ww8", "FrameFormat is nil" );
2315 const SwFormatHoriOrient
&rHori
= pFormat
->GetHoriOrient();
2316 const SwFormatVertOrient
&rVert
= pFormat
->GetVertOrient();
2318 sal_uInt16 nTableOffset
= 0;
2321 (text::RelOrientation::PRINT_AREA
== rHori
.GetRelationOrient() ||
2322 text::RelOrientation::FRAME
== rHori
.GetRelationOrient())
2324 (text::RelOrientation::PRINT_AREA
== rVert
.GetRelationOrient() ||
2325 text::RelOrientation::FRAME
== rVert
.GetRelationOrient())
2328 sal_Int16 eHOri
= rHori
.GetHoriOrient();
2331 case text::HoriOrientation::CENTER
:
2332 case text::HoriOrientation::RIGHT
:
2336 nTableOffset
= rHori
.GetPos();
2337 const SvxLRSpaceItem
& rLRSp
= pFormat
->GetLRSpace();
2338 nTableOffset
+= rLRSp
.GetLeft();
2343 m_rWW8Export
.InsUInt16( nTableOffset
);
2345 ww8::GridColsPtr pGridCols
= GetGridCols( pTableTextNodeInfoInner
);
2346 for ( ww8::GridCols::const_iterator it
= pGridCols
->begin(),
2347 end
= pGridCols
->end(); it
!= end
; ++it
)
2349 m_rWW8Export
.InsUInt16( static_cast<sal_uInt16
>( *it
) + nTableOffset
);
2353 ww8::RowSpansPtr pRowSpans
= pTableTextNodeInfoInner
->getRowSpansOfRow();
2354 ww8::RowSpans::const_iterator aItRowSpans
= pRowSpans
->begin();
2355 ww8::TableBoxVector::const_iterator aIt
;
2356 ww8::TableBoxVector::const_iterator aItEnd
= pTableBoxes
->end();
2358 for (aIt
= pTableBoxes
->begin(); aIt
!= aItEnd
; ++aIt
, ++aItRowSpans
)
2360 sal_uInt16 npOCount
= m_rWW8Export
.pO
->size();
2362 const SwTableBox
* pTabBox1
= *aIt
;
2363 const SwFrameFormat
* pBoxFormat
= nullptr;
2364 if (pTabBox1
!= nullptr)
2365 pBoxFormat
= pTabBox1
->GetFrameFormat();
2368 lcl_TCFlags(*m_rWW8Export
.m_pDoc
, pTabBox1
, *aItRowSpans
);
2369 m_rWW8Export
.InsUInt16( nFlags
);
2371 static sal_uInt8 aNullBytes
[] = { 0x0, 0x0 };
2373 m_rWW8Export
.pO
->insert( m_rWW8Export
.pO
->end(), aNullBytes
, aNullBytes
+2 ); // dummy
2374 if (pBoxFormat
!= nullptr)
2376 const SvxBoxItem
& rBoxItem
= pBoxFormat
->GetBox();
2378 WW8Export::Out_SwFormatTableBox( *m_rWW8Export
.pO
, &rBoxItem
); // 8/16 Byte
2381 WW8Export::Out_SwFormatTableBox( *m_rWW8Export
.pO
, nullptr); // 8/16 Byte
2383 SAL_INFO( "sw.ww8.level2", "<tclength>" << ( m_rWW8Export
.pO
->size() - npOCount
) << "</tclength>" );
2387 ww8::GridColsPtr
AttributeOutputBase::GetGridCols( ww8::WW8TableNodeInfoInner::Pointer_t
const & pTableTextNodeInfoInner
)
2389 return pTableTextNodeInfoInner
->getGridColsOfRow(*this);
2392 ww8::WidthsPtr
AttributeOutputBase::GetColumnWidths( ww8::WW8TableNodeInfoInner::Pointer_t
const & pTableTextNodeInfoInner
)
2394 // Get the column widths based on ALL the rows, not just the current row
2395 return pTableTextNodeInfoInner
->getGridColsOfRow(*this, true);
2398 void AttributeOutputBase::GetTablePageSize( ww8::WW8TableNodeInfoInner
* pTableTextNodeInfoInner
, long& rPageSize
, bool& rRelBoxSize
)
2402 const SwNode
*pTextNd
= pTableTextNodeInfoInner
->getNode( );
2403 const SwTable
*pTable
= pTableTextNodeInfoInner
->getTable( );
2405 const SwFrameFormat
*pFormat
= pTable
->GetFrameFormat();
2408 SAL_WARN( "sw.ww8", "FrameFormat is nil" );
2412 const SwFormatFrameSize
&rSize
= pFormat
->GetFrameSize();
2413 int nWidthPercent
= rSize
.GetWidthPercent();
2414 bool bManualAligned
= pFormat
->GetHoriOrient().GetHoriOrient() == text::HoriOrientation::NONE
;
2415 if ( (pFormat
->GetHoriOrient().GetHoriOrient() == text::HoriOrientation::FULL
) || bManualAligned
)
2416 nWidthPercent
= 100;
2417 bool bRelBoxSize
= nWidthPercent
!= 0;
2418 unsigned long nTableSz
= static_cast<unsigned long>(rSize
.GetWidth());
2419 if (nTableSz
> USHRT_MAX
/2 && !bRelBoxSize
)
2421 OSL_ENSURE(bRelBoxSize
, "huge table width but not relative, suspicious");
2428 SwRect
aRect( pFormat
->FindLayoutRect( false, &aPt
) );
2429 if ( aRect
.IsEmpty() )
2431 // dann besorge mal die Seitenbreite ohne Raender !!
2432 const SwFrameFormat
* pParentFormat
=
2433 GetExport().m_pParentFrame
?
2434 &(GetExport().m_pParentFrame
->GetFrameFormat()) :
2435 GetExport().m_pDoc
->GetPageDesc(0).GetPageFormatOfNode(*pTextNd
, false);
2436 aRect
= pParentFormat
->FindLayoutRect(true);
2437 if ( 0 == ( nPageSize
= aRect
.Width() ) )
2439 const SvxLRSpaceItem
& rLR
= pParentFormat
->GetLRSpace();
2440 nPageSize
= pParentFormat
->GetFrameSize().GetWidth() - rLR
.GetLeft()
2446 nPageSize
= aRect
.Width();
2447 if ( bManualAligned
)
2449 // #i37571# For manually aligned tables
2450 const SvxLRSpaceItem
&rLR
= pFormat
->GetLRSpace();
2451 nPageSize
-= (rLR
.GetLeft() + rLR
.GetRight());
2456 if ( nWidthPercent
)
2458 nPageSize
*= nWidthPercent
;
2462 SAL_WARN( "sw.ww8", "nWidthPercent is zero" );
2466 // As the table width is not relative, the TablePageSize equals its width
2467 nPageSize
= nTableSz
;
2470 rPageSize
= nPageSize
;
2471 rRelBoxSize
= bRelBoxSize
;
2474 void WW8AttributeOutput::TableDefaultBorders( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2476 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
2477 const SwFrameFormat
* pFrameFormat
= pTabBox
->GetFrameFormat();
2479 //Set Default, just taken from the first cell of the first
2481 static const SvxBoxItemLine aBorders
[] =
2483 SvxBoxItemLine::TOP
, SvxBoxItemLine::LEFT
,
2484 SvxBoxItemLine::BOTTOM
, SvxBoxItemLine::RIGHT
2487 for ( int i
= 0; i
< 4; ++i
)
2489 SwWW8Writer::InsUInt16( *m_rWW8Export
.pO
, 0xD634 );
2490 m_rWW8Export
.pO
->push_back( sal_uInt8(6) );
2491 m_rWW8Export
.pO
->push_back( sal_uInt8(0) );
2492 m_rWW8Export
.pO
->push_back( sal_uInt8(1) );
2493 m_rWW8Export
.pO
->push_back( sal_uInt8(1 << i
) );
2494 m_rWW8Export
.pO
->push_back( sal_uInt8(3) );
2496 SwWW8Writer::InsUInt16( *m_rWW8Export
.pO
,
2497 pFrameFormat
->GetBox().GetDistance( aBorders
[i
] ) );
2501 void WW8AttributeOutput::TableCellBorders(
2502 ww8::WW8TableNodeInfoInner::Pointer_t
const & pTableTextNodeInfoInner
)
2504 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
2505 const SwTableLine
* pTabLine
= pTabBox
->GetUpper();
2506 const SwTableBoxes
& rTabBoxes
= pTabLine
->GetTabBoxes();
2507 sal_uInt8 nBoxes
= std::min
<size_t>(rTabBoxes
.size(), 255);
2508 const SvxBoxItem
* pLastBox
= nullptr;
2509 sal_uInt8 nSeqStart
= 0; // start of sequence of cells with same borders
2511 // Detect sequences of cells which have the same borders, and output
2512 // a border description for each such cell range.
2513 for ( unsigned n
= 0; n
<= nBoxes
; ++n
)
2515 const SvxBoxItem
* pBox
= (n
== nBoxes
) ? nullptr :
2516 &rTabBoxes
[n
]->GetFrameFormat()->GetBox();
2519 else if( !pBox
|| *pLastBox
!= *pBox
)
2521 // This cell has different borders than the previous cell,
2522 // so output the borders for the preceding cell range.
2523 m_rWW8Export
.Out_CellRangeBorders(pLastBox
, nSeqStart
, n
);
2530 void WW8AttributeOutput::TableBackgrounds( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
2532 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
2533 const SwTableLine
* pTabLine
= pTabBox
->GetUpper();
2534 const SwTableBoxes
& rTabBoxes
= pTabLine
->GetTabBoxes();
2536 sal_uInt8 nBoxes
= rTabBoxes
.size();
2537 m_rWW8Export
.InsUInt16( NS_sprm::LN_TDefTableShd80
);
2538 m_rWW8Export
.pO
->push_back( (sal_uInt8
)(nBoxes
* 2) ); // Len
2540 for ( sal_uInt8 n
= 0; n
< nBoxes
; n
++ )
2542 const SwTableBox
* pBox1
= rTabBoxes
[n
];
2543 const SwFrameFormat
* pFrameFormat
= pBox1
->GetFrameFormat();
2544 const SfxPoolItem
* pI
= nullptr;
2547 if ( SfxItemState::SET
== pFrameFormat
->GetAttrSet().GetItemState( RES_BACKGROUND
, false, &pI
) )
2549 aColor
= dynamic_cast<const SvxBrushItem
*>(pI
)->GetColor();
2555 WW8Export::TransBrush( aColor
, aShd
);
2556 m_rWW8Export
.InsUInt16( aShd
.GetValue() );
2559 sal_uInt32 aSprmIds
[] = { NS_sprm::LN_TDefTableShd
,
2560 NS_sprm::LN_TDefTableShdRaw
};
2561 sal_uInt8 nBoxes0
= rTabBoxes
.size();
2565 for (sal_uInt32 m
: aSprmIds
)
2567 m_rWW8Export
.InsUInt16( m
);
2568 m_rWW8Export
.pO
->push_back( static_cast<sal_uInt8
>(nBoxes0
* 10) );
2570 for ( sal_uInt8 n
= 0; n
< nBoxes0
; n
++ )
2572 const SwTableBox
* pBox1
= rTabBoxes
[n
];
2573 const SwFrameFormat
* pFrameFormat
= pBox1
->GetFrameFormat();
2574 const SfxPoolItem
* pI
= nullptr;
2577 if ( SfxItemState::SET
==
2578 pFrameFormat
->GetAttrSet().
2579 GetItemState( RES_BACKGROUND
, false, &pI
) )
2581 aColor
= dynamic_cast<const SvxBrushItem
*>(pI
)->GetColor();
2587 aSHD
.setCvFore( 0xFF000000 );
2589 sal_uInt32 nBgColor
= aColor
.GetColor();
2590 if ( nBgColor
== COL_AUTO
)
2591 aSHD
.setCvBack( 0xFF000000 );
2593 aSHD
.setCvBack( wwUtility::RGBToBGR( nBgColor
) );
2595 aSHD
.Write( m_rWW8Export
);
2600 void WW8Export::SectionBreaksAndFrames( const SwTextNode
& rNode
)
2602 // output page/section breaks
2603 OutputSectionBreaks( rNode
.GetpSwAttrSet(), rNode
);
2606 class TrackContentToExport
2610 sal_uLong m_nStart
, m_nEnd
;
2612 TrackContentToExport(SwPaM
*pCurPam
, sal_uLong nCurStart
, sal_uLong nCurEnd
)
2613 : m_pCurPam(pCurPam
)
2614 , m_nStart(nCurStart
)
2619 bool contentRemainsToExport(ww8::WW8TableInfo
*pTableInfo
)
2621 bool bSimpleContentRemains
= m_pCurPam
->GetPoint()->nNode
< m_pCurPam
->GetMark()->nNode
||
2622 (m_pCurPam
->GetPoint()->nNode
== m_pCurPam
->GetMark()->nNode
&&
2623 m_pCurPam
->GetPoint()->nContent
.GetIndex() <= m_pCurPam
->GetMark()->nContent
.GetIndex());
2624 if (bSimpleContentRemains
)
2630 //An old-school table where one cell may points back to a previous node as the next cell
2631 //so if this node is the last node in the range, we may need to jump back to a previously
2632 //skipped cell to output it in a sane sequence. See ooo47778-3.sxw for one of these
2633 //horrors. So if we are at the end of the selection, but this end point is a table
2634 //cell whose next cell is in the selection allow jumping back to it
2635 const SwNode
* pCurrentNode
= &m_pCurPam
->GetPoint()->nNode
.GetNode();
2636 const SwNode
* pNextNode
= pTableInfo
->getNextNode(pCurrentNode
);
2638 if (pNextNode
&& pCurrentNode
!= pNextNode
)
2640 return pNextNode
->GetIndex() >= m_nStart
&&
2641 pNextNode
->GetIndex() < m_nEnd
;
2648 void MSWordExportBase::WriteText()
2650 TrackContentToExport
aContentTracking(m_pCurPam
, m_nCurStart
, m_nCurEnd
);
2651 while (aContentTracking
.contentRemainsToExport(m_pTableInfo
.get()))
2653 SwNode
& rNd
= m_pCurPam
->GetNode();
2655 if ( rNd
.IsTextNode() )
2656 SectionBreaksAndFrames( *rNd
.GetTextNode() );
2658 // output the various types of nodes
2659 if ( rNd
.IsContentNode() )
2661 SwContentNode
* pCNd
= static_cast<SwContentNode
*>(&rNd
);
2663 const SwPageDesc
* pTemp
= rNd
.FindPageDesc();
2665 m_pAktPageDesc
= pTemp
;
2667 m_pCurPam
->GetPoint()->nContent
.Assign( pCNd
, 0 );
2668 OutputContentNode( *pCNd
);
2670 else if ( rNd
.IsTableNode() )
2672 m_pTableInfo
->processSwTable( &rNd
.GetTableNode()->GetTable() );
2674 else if ( rNd
.IsSectionNode() && TXT_MAINTEXT
== m_nTextTyp
)
2675 OutputSectionNode( *rNd
.GetSectionNode() );
2676 else if ( TXT_MAINTEXT
== m_nTextTyp
&& rNd
.IsEndNode() &&
2677 rNd
.StartOfSectionNode()->IsSectionNode() )
2679 const SwSection
& rSect
= rNd
.StartOfSectionNode()->GetSectionNode()
2681 if ( m_bStartTOX
&& TOX_CONTENT_SECTION
== rSect
.GetType() )
2682 m_bStartTOX
= false;
2684 SwNodeIndex
aIdx( rNd
, 1 );
2685 if ( aIdx
.GetNode().IsEndNode() && aIdx
.GetNode().StartOfSectionNode()->IsSectionNode() )
2687 else if ( aIdx
.GetNode().IsSectionNode() )
2689 else if ( !IsInTable()
2690 && (rSect
.GetType() != TOX_CONTENT_SECTION
&& rSect
.GetType() != TOX_HEADER_SECTION
)) //No sections in table
2692 //#120140# Do not need to insert a page/section break after a section end. Check this case first
2693 bool bNeedExportBreakHere
= true;
2694 if ( aIdx
.GetNode().IsTextNode() )
2696 SwTextNode
*pTempNext
= aIdx
.GetNode().GetTextNode();
2699 const SfxPoolItem
* pTempItem
= nullptr;
2700 if (pTempNext
->GetpSwAttrSet() && SfxItemState::SET
== pTempNext
->GetpSwAttrSet()->GetItemState(RES_PAGEDESC
, false, &pTempItem
)
2701 && pTempItem
&& static_cast<const SwFormatPageDesc
*>(pTempItem
)->GetRegisteredIn())
2703 //Next node has a new page style which means this node is a section end. Do not insert another page/section break here
2704 bNeedExportBreakHere
= false;
2710 /* Do not export Section Break in case DOCX containing MultiColumn and
2711 * aIdx.GetNode().IsTextNode() is False i.e. Text node is NULL.
2713 const SwFrameFormat
* pPgFormat
= rSect
.GetFormat();
2714 const SwFormatCol
& rCol
= pPgFormat
->GetCol();
2715 sal_uInt16 nColumnCount
= rCol
.GetNumCols();
2716 if(nColumnCount
> 1)
2718 bNeedExportBreakHere
= false;
2722 if (bNeedExportBreakHere
) //#120140# End of check
2724 ReplaceCr( (char)0xc ); // indicator for Page/Section-Break
2726 const SwSectionFormat
* pParentFormat
= rSect
.GetFormat()->GetParent();
2727 if ( !pParentFormat
)
2728 pParentFormat
= reinterpret_cast<SwSectionFormat
*>(sal_IntPtr(-1));
2730 sal_uLong nRstLnNum
;
2731 if ( aIdx
.GetNode().IsContentNode() )
2732 nRstLnNum
= static_cast<SwContentNode
&>(aIdx
.GetNode()).GetSwAttrSet().
2733 GetLineNumber().GetStartValue();
2737 AppendSection( m_pAktPageDesc
, pParentFormat
, nRstLnNum
);
2741 OutputEndNode( *rNd
.GetEndNode() );
2745 else if ( rNd
.IsStartNode() )
2747 OutputStartNode( *rNd
.GetStartNode() );
2749 else if ( rNd
.IsEndNode() )
2751 OutputEndNode( *rNd
.GetEndNode() );
2754 if ( &rNd
== &rNd
.GetNodes().GetEndOfContent() )
2757 const SwNode
* pCurrentNode
= &m_pCurPam
->GetPoint()->nNode
.GetNode();
2758 const SwNode
* pNextNode
= m_pTableInfo
->getNextNode(pCurrentNode
);
2760 if (pCurrentNode
== pNextNode
)
2762 SAL_WARN("sw.ww8", "loop in TableInfo");
2763 pNextNode
= nullptr;
2766 if (pNextNode
!= nullptr)
2767 m_pCurPam
->GetPoint()->nNode
.Assign(*pNextNode
);
2769 ++m_pCurPam
->GetPoint()->nNode
;
2771 sal_uLong nPos
= m_pCurPam
->GetPoint()->nNode
.GetIndex();
2772 ::SetProgressState( nPos
, m_pCurPam
->GetDoc()->GetDocShell() );
2775 SAL_INFO( "sw.ww8.level2", "</WriteText>" );
2778 void WW8Export::WriteMainText()
2780 SAL_INFO( "sw.ww8.level2", "<WriteMainText>" );
2782 pFib
->m_fcMin
= Strm().Tell();
2784 m_pCurPam
->GetPoint()->nNode
= m_pDoc
->GetNodes().GetEndOfContent().StartOfSectionNode()->GetIndex();
2788 if( 0 == Strm().Tell() - pFib
->m_fcMin
) // no text ?
2789 WriteCR(); // then CR at the end ( otherwise WW will complain )
2791 pFib
->m_ccpText
= Fc2Cp( Strm().Tell() );
2792 m_pFieldMain
->Finish( pFib
->m_ccpText
, 0 );
2794 // ccpText includes Footnote and KF-text
2795 // therefore pFib->ccpText may get updated as well
2796 // save the StyleId of the last paragraph. Because WW97 take the style
2797 // from the last CR, that will be written after footer/Header/footnotes/
2799 const SwTextNode
* pLastNd
= m_pCurPam
->GetMark()->nNode
.GetNode().GetTextNode();
2801 m_nLastFormatId
= GetId( static_cast<SwTextFormatColl
&>(pLastNd
->GetAnyFormatColl()) );
2803 SAL_INFO( "sw.ww8.level2", "</WriteMainText>" );
2806 bool MSWordExportBase::IsInTable() const
2808 bool bResult
= false;
2810 if (m_pCurPam
!= nullptr)
2812 SwNode
& rNode
= m_pCurPam
->GetNode();
2814 if (m_pTableInfo
.get() != nullptr)
2816 ww8::WW8TableNodeInfo::Pointer_t pTableNodeInfo
= m_pTableInfo
->getTableNodeInfo(&rNode
);
2818 if (pTableNodeInfo
.get() != nullptr && pTableNodeInfo
->getDepth() > 0)
2828 typedef ww8::WW8Sttb
< ww8::WW8Struct
> WW8SttbAssoc
;
2830 void WW8Export::WriteFkpPlcUsw()
2832 // Graphics in the data stream
2833 m_pGrf
->Write(); // Graphics
2835 // Ausgabe in WordDocument-Stream
2836 m_pChpPlc
->WriteFkps(); // Fkp.Chpx
2837 m_pPapPlc
->WriteFkps(); // Fkp.Papx
2838 pSepx
->WriteSepx( Strm() ); // Sepx
2840 // Ausagbe in Table-Stream
2841 m_pStyles
->OutputStylesTable(); // for WW8 StyleTab
2842 pFootnote
->WritePlc( *this ); // Footnote-Ref & Text Plc
2843 pEdn
->WritePlc( *this ); // Endnote-Ref & Text Plc
2844 m_pTextBxs
->WritePlc( *this ); // Textbox Text Plc
2845 m_pHFTextBxs
->WritePlc( *this ); // Head/Foot-Textbox Text Plc
2846 m_pAtn
->WritePlc( *this ); // Annotation-Ref & Text Plc
2848 pSepx
->WritePlcSed( *this ); // Slcx.PlcSed
2849 pSepx
->WritePlcHdd( *this ); // Slcx.PlcHdd
2851 m_pChpPlc
->WritePlc(); // Plcx.Chpx
2852 m_pPapPlc
->WritePlc(); // Plcx.Papx
2854 if( m_pRedlAuthors
)
2855 m_pRedlAuthors
->Write( GetWriter() ); // sttbfRMark (RedlineAuthors)
2856 m_pFieldMain
->Write( *this ); // Fields ( Main Text )
2857 m_pFieldHdFt
->Write( *this ); // Fields ( Header/Footer )
2858 m_pFieldFootnote
->Write( *this ); // Fields ( FootNotes )
2859 m_pFieldEdn
->Write( *this ); // Fields ( EndNotes )
2860 m_pFieldAtn
->Write( *this ); // Fields ( Annotations )
2861 m_pFieldTextBxs
->Write( *this ); // Fields ( Textboxes )
2862 m_pFieldHFTextBxs
->Write( *this ); // Fields ( Head/Foot-Textboxes )
2864 if (m_pEscher
|| m_pDoc
->ContainsMSVBasic())
2867 Every time MS 2000 creates an escher stream there is always
2868 an ObjectPool dir (even if empty). It turns out that if a copy of
2869 MS 2000 is used to open a document that contains escher graphics
2870 exported from StarOffice without this empty dir then *if* that
2871 copy of MS Office has never been used to open a MSOffice document
2872 that has escher graphics (and an ObjectPool dir of course) and
2873 that copy of office has not been used to draw escher graphics then
2874 our exported graphics do not appear. Once you do open a ms
2875 document with escher graphics or draw an escher graphic with that
2876 copy of word, then all documents from staroffice that contain
2877 escher work from then on. Tricky to track down, some sort of late
2878 binding trickery in MS where solely for first time initialization
2879 the existence of an ObjectPool dir is necessary for triggering
2882 // avoid memory leak #i120098#, the unnamed obj will be released in destructor.
2883 xEscherStg
= GetWriter().GetStorage().OpenSotStorage(OUString(SL::aObjectPool
));
2886 // dggInfo - escher stream
2889 m_pSdrObjs
->WritePlc( *this );
2890 m_pHFSdrObjs
->WritePlc( *this );
2891 // spamom - office drawing table
2892 // spahdr - header office drawing table
2894 m_pBkmks
->Write( *this ); // Bookmarks - sttbfBkmk/
2895 // plcfBkmkf/plcfBkmkl
2896 m_pFactoids
->Write(*this);
2902 m_pMagicTable
->Write( *this );
2904 m_pPiece
->WritePc( *this ); // Piece-Table
2905 m_aFontHelper
.WriteFontTable(pTableStrm
, *pFib
); // FFNs
2907 //Convert OOo asian typography into MS typography structure
2908 ExportDopTypography(pDop
->doptypography
);
2910 WriteDop( *this ); // Document-Properties
2913 WW8SttbAssoc
* pSttbfAssoc
= dynamic_cast<WW8SttbAssoc
*>
2914 (m_pDoc
->getIDocumentExternalData().getExternalData(::sw::tExternalDataType::STTBF_ASSOC
).get());
2916 if ( pSttbfAssoc
) // #i106057#
2918 std::vector
<OUString
> aStrings(pSttbfAssoc
->getStrings());
2919 WriteAsStringTable(aStrings
, pFib
->m_fcSttbfAssoc
,
2920 pFib
->m_lcbSttbfAssoc
);
2925 // Reclaim stored FIB data from document.
2926 ::ww8::WW8FibData
* pFibData
= dynamic_cast<ww8::WW8FibData
*>
2927 (m_pDoc
->getIDocumentExternalData().getExternalData(::sw::tExternalDataType::FIB
).get());
2931 pFib
->m_fReadOnlyRecommended
=
2932 pFibData
->getReadOnlyRecommended();
2933 pFib
->m_fWriteReservation
=
2934 pFibData
->getWriteReservation();
2937 pFib
->Write( Strm() ); // FIB
2940 void WW8Export::StoreDoc1()
2942 bool bNeedsFinalPara
= false;
2943 // Start of Text ( Mangel ueber )
2944 SwWW8Writer::FillUntil( Strm(), pFib
->m_fcMin
);
2946 WriteMainText(); // main text
2947 sal_uInt8 nSprmsLen
;
2948 sal_uInt8
*pLastSprms
= m_pPapPlc
->CopyLastSprms(nSprmsLen
);
2950 bNeedsFinalPara
|= pFootnote
->WriteText( *this ); // Footnote-Text
2951 bNeedsFinalPara
|= pSepx
->WriteKFText( *this ); // K/F-Text
2952 bNeedsFinalPara
|= m_pAtn
->WriteText( *this ); // Annotation-Text
2953 bNeedsFinalPara
|= pEdn
->WriteText( *this ); // EndNote-Text
2955 // create the escher streams
2958 bNeedsFinalPara
|= m_pTextBxs
->WriteText( *this ); //Textbox Text Plc
2959 bNeedsFinalPara
|= m_pHFTextBxs
->WriteText( *this );//Head/Foot-Textbox Text Plc
2961 if (bNeedsFinalPara
)
2964 m_pPapPlc
->AppendFkpEntry(Strm().Tell(), nSprmsLen
, pLastSprms
);
2966 delete[] pLastSprms
;
2968 pSepx
->Finish( Fc2Cp( Strm().Tell() ));// Text + Footnote + HdFt als Section-Ende
2969 m_pMagicTable
->Finish( Fc2Cp( Strm().Tell() ),0);
2971 pFib
->m_fcMac
= Strm().Tell(); // End of all texts
2973 WriteFkpPlcUsw(); // FKP, PLC, .....
2976 void MSWordExportBase::AddLinkTarget(const OUString
& rURL
)
2978 if( rURL
.isEmpty() || rURL
[0] != '#' )
2981 OUString
aURL( BookmarkToWriter( rURL
.copy( 1 ) ) );
2982 sal_Int32 nPos
= aURL
.lastIndexOf( cMarkSeparator
);
2987 OUString sCmp
= aURL
.copy(nPos
+1).replaceAll(" ", "");
2988 if( sCmp
.isEmpty() )
2991 sCmp
= sCmp
.toAsciiLowerCase();
2993 if( sCmp
== "outline" )
2995 SwPosition
aPos( *m_pCurPam
->GetPoint() );
2996 OUString
aOutline( BookmarkToWriter(aURL
.copy( 0, nPos
)) );
2997 // If we can find the outline this bookmark refers to
2998 // save the name of the bookmark and the
2999 // node index number of where it points to
3000 if( m_pDoc
->GotoOutline( aPos
, aOutline
) )
3002 sal_uLong nIdx
= aPos
.nNode
.GetIndex();
3003 aBookmarkPair aImplicitBookmark
;
3004 aImplicitBookmark
.first
= aOutline
;
3005 aImplicitBookmark
.second
= nIdx
;
3006 m_aImplicitBookmarks
.push_back(aImplicitBookmark
);
3011 void MSWordExportBase::CollectOutlineBookmarks(const SwDoc
&rDoc
)
3013 sal_uInt32 nMaxItems
= rDoc
.GetAttrPool().GetItemCount2(RES_TXTATR_INETFMT
);
3014 for (sal_uInt32 n
= 0; n
< nMaxItems
; ++n
)
3016 const SwFormatINetFormat
* pINetFormat
= static_cast<const SwFormatINetFormat
*>(rDoc
.GetAttrPool().GetItem2(RES_TXTATR_INETFMT
, n
));
3020 const SwTextINetFormat
* pTextAttr
= pINetFormat
->GetTextINetFormat();
3024 const SwTextNode
* pTextNd
= pTextAttr
->GetpTextNode();
3028 if (!pTextNd
->GetNodes().IsDocNodes())
3031 AddLinkTarget( pINetFormat
->GetValue() );
3034 nMaxItems
= rDoc
.GetAttrPool().GetItemCount2( RES_URL
);
3035 for (sal_uInt32 n
= 0; n
< nMaxItems
; ++n
)
3037 const SwFormatURL
*pURL
= static_cast<const SwFormatURL
*>(rDoc
.GetAttrPool().GetItem2(RES_URL
, n
));
3041 AddLinkTarget(pURL
->GetURL());
3042 const ImageMap
*pIMap
= pURL
->GetMap();
3046 for (size_t i
=0; i
< pIMap
->GetIMapObjectCount(); ++i
)
3048 const IMapObject
* pObj
= pIMap
->GetIMapObject(i
);
3051 AddLinkTarget( pObj
->GetURL() );
3058 const sal_uLong WW_BLOCKSIZE
= 0x200;
3060 void EncryptRC4(msfilter::MSCodec_Std97
& rCtx
, SvStream
&rIn
, SvStream
&rOut
)
3062 rIn
.Seek(STREAM_SEEK_TO_END
);
3063 sal_uLong nLen
= rIn
.Tell();
3066 sal_uInt8 in
[WW_BLOCKSIZE
];
3067 for (std::size_t nI
= 0, nBlock
= 0; nI
< nLen
; nI
+= WW_BLOCKSIZE
, ++nBlock
)
3069 std::size_t nBS
= (nLen
- nI
> WW_BLOCKSIZE
) ? WW_BLOCKSIZE
: nLen
- nI
;
3070 nBS
= rIn
.ReadBytes(in
, nBS
);
3071 rCtx
.InitCipher(nBlock
);
3072 rCtx
.Encode(in
, nBS
, in
, nBS
);
3073 rOut
.WriteBytes(in
, nBS
);
3078 void MSWordExportBase::ExportDocument( bool bWriteAll
)
3080 m_nCharFormatStart
= ANZ_DEFAULT_STYLES
;
3081 m_nFormatCollStart
= m_nCharFormatStart
+ m_pDoc
->GetCharFormats()->size() - 1;
3083 m_bStyDef
= m_bBreakBefore
= m_bOutKF
=
3084 m_bOutFlyFrameAttrs
= m_bOutPageDescs
= m_bOutTable
= m_bOutFirstPage
=
3085 m_bOutGrf
= m_bInWriteEscher
= m_bStartTOX
=
3086 m_bInWriteTOX
= false;
3088 m_bFootnoteAtTextEnd
= m_bEndAtTextEnd
= true;
3090 m_pParentFrame
= nullptr;
3091 m_pFlyOffset
= nullptr;
3092 m_eNewAnchorType
= FLY_AT_PAGE
;
3093 m_nTextTyp
= TXT_MAINTEXT
;
3094 m_nStyleBeforeFly
= m_nLastFormatId
= 0;
3095 m_pStyAttr
= nullptr;
3096 m_pCurrentStyle
= nullptr;
3097 m_pOutFormatNode
= nullptr;
3098 m_pEscher
= nullptr;
3099 m_pRedlAuthors
= nullptr;
3104 sal_uInt32 nSvxMSDffOLEConvFlags
= 0;
3105 const SvtFilterOptions
& rOpt
= SvtFilterOptions::Get();
3106 if ( rOpt
.IsMath2MathType() )
3107 nSvxMSDffOLEConvFlags
|= OLE_STARMATH_2_MATHTYPE
;
3108 if ( rOpt
.IsWriter2WinWord() )
3109 nSvxMSDffOLEConvFlags
|= OLE_STARWRITER_2_WINWORD
;
3110 if ( rOpt
.IsCalc2Excel() )
3111 nSvxMSDffOLEConvFlags
|= OLE_STARCALC_2_EXCEL
;
3112 if ( rOpt
.IsImpress2PowerPoint() )
3113 nSvxMSDffOLEConvFlags
|= OLE_STARIMPRESS_2_POWERPOINT
;
3115 m_pOLEExp
= new SvxMSExportOLEObjects( nSvxMSDffOLEConvFlags
);
3118 if ( !m_pOCXExp
&& m_pDoc
->GetDocShell() )
3119 m_pOCXExp
= new SwMSConvertControls( m_pDoc
->GetDocShell(), m_pCurPam
);
3121 // #i81405# - Collect anchored objects before changing the redline mode.
3122 m_aFrames
= GetFrames( *m_pDoc
, bWriteAll
? nullptr : m_pOrigPam
);
3124 m_nOrigRedlineFlags
= m_pDoc
->getIDocumentRedlineAccess().GetRedlineFlags();
3125 if ( !m_pDoc
->getIDocumentRedlineAccess().GetRedlineTable().empty() )
3127 //restored to original state by SwWriter::Write
3128 m_pDoc
->getIDocumentRedlineAccess().SetRedlineFlags(m_nOrigRedlineFlags
|
3129 RedlineFlags::ShowDelete
|
3130 RedlineFlags::ShowInsert
);
3133 // fix the SwPositions in m_aFrames after SetRedlineFlags
3134 UpdateFramePositions(m_aFrames
);
3136 m_aFontHelper
.InitFontTable(*m_pDoc
);
3137 GatherChapterFields();
3139 CollectOutlineBookmarks(*m_pDoc
);
3141 // make unique OrdNums (Z-Order) for all drawing-/fly Objects
3142 if ( m_pDoc
->getIDocumentDrawModelAccess().GetDrawModel() )
3143 m_pDoc
->getIDocumentDrawModelAccess().GetDrawModel()->GetPage( 0 )->RecalcObjOrdNums();
3145 ExportDocument_Impl();
3149 // park m_pCurPam in a "safe place" now that document is fully exported
3150 // before toggling redline mode to avoid ~SwIndexReg assert e.g. export
3151 // ooo103014-1.odt to .doc
3152 // park m_pOrigPam as well, as needed for exporting abi9915-1.odt to doc
3153 m_pOrigPam
->DeleteMark();
3154 *m_pOrigPam
->GetPoint() = SwPosition(m_pDoc
->GetNodes().GetEndOfContent());
3155 *m_pCurPam
= *m_pOrigPam
;
3157 m_pDoc
->getIDocumentRedlineAccess().SetRedlineFlags(m_nOrigRedlineFlags
);
3160 bool SwWW8Writer::InitStd97CodecUpdateMedium( ::msfilter::MSCodec_Std97
& rCodec
)
3162 uno::Sequence
< beans::NamedValue
> aEncryptionData
;
3166 const SfxUnoAnyItem
* pEncryptionDataItem
= SfxItemSet::GetItem
<SfxUnoAnyItem
>(mpMedium
->GetItemSet(), SID_ENCRYPTIONDATA
, false);
3167 if ( pEncryptionDataItem
&& ( pEncryptionDataItem
->GetValue() >>= aEncryptionData
) && !rCodec
.InitCodec( aEncryptionData
) )
3169 OSL_ENSURE( false, "Unexpected EncryptionData!" );
3170 aEncryptionData
.realloc( 0 );
3173 if ( !aEncryptionData
.getLength() )
3175 // try to generate the encryption data based on password
3176 const SfxStringItem
* pPasswordItem
= SfxItemSet::GetItem
<SfxStringItem
>(mpMedium
->GetItemSet(), SID_PASSWORD
, false);
3177 if ( pPasswordItem
&& !pPasswordItem
->GetValue().isEmpty() && pPasswordItem
->GetValue().getLength() <= 15 )
3179 // Generate random number with a seed of time as salt.
3181 osl_getSystemTime( &aTime
);
3182 rtlRandomPool aRandomPool
= rtl_random_createPool ();
3183 rtl_random_addBytes ( aRandomPool
, &aTime
, 8 );
3185 sal_uInt8 pDocId
[ 16 ];
3186 rtl_random_getBytes( aRandomPool
, pDocId
, 16 );
3188 rtl_random_destroyPool( aRandomPool
);
3190 sal_uInt16 aPassword
[16];
3191 memset( aPassword
, 0, sizeof( aPassword
) );
3193 OUString
sPassword(pPasswordItem
->GetValue());
3194 for ( sal_Int32 nChar
= 0; nChar
< sPassword
.getLength(); ++nChar
)
3195 aPassword
[nChar
] = sPassword
[nChar
];
3197 rCodec
.InitKey( aPassword
, pDocId
);
3198 aEncryptionData
= rCodec
.GetEncryptionData();
3200 mpMedium
->GetItemSet()->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA
, uno::makeAny( aEncryptionData
) ) );
3204 if ( aEncryptionData
.getLength() )
3205 mpMedium
->GetItemSet()->ClearItem( SID_PASSWORD
);
3208 // nonempty encryption data means hier that the codec was successfully initialized
3209 return ( aEncryptionData
.getLength() != 0 );
3212 void WW8Export::ExportDocument_Impl()
3216 pFib
= new WW8Fib(8, m_bDot
);
3218 tools::SvRef
<SotStorageStream
> xWwStrm( GetWriter().GetStorage().OpenSotStream( m_aMainStg
) );
3219 tools::SvRef
<SotStorageStream
> xTableStrm( xWwStrm
), xDataStrm( xWwStrm
);
3220 xWwStrm
->SetBufferSize( 32768 );
3222 pFib
->m_fWhichTableStm
= true;
3223 xTableStrm
= GetWriter().GetStorage().OpenSotStream(OUString(SL::a1Table
),
3224 StreamMode::STD_WRITE
);
3225 xDataStrm
= GetWriter().GetStorage().OpenSotStream(OUString(SL::aData
),
3226 StreamMode::STD_WRITE
);
3228 xDataStrm
->SetBufferSize( 32768 ); // for graphics
3229 xTableStrm
->SetBufferSize( 16384 ); // for the Font-/Style-Table, etc.
3231 xTableStrm
->SetEndian( SvStreamEndian::LITTLE
);
3232 xDataStrm
->SetEndian( SvStreamEndian::LITTLE
);
3234 GetWriter().SetStream( xWwStrm
.get() );
3235 pTableStrm
= xTableStrm
.get();
3236 pDataStrm
= xDataStrm
.get();
3238 Strm().SetEndian( SvStreamEndian::LITTLE
);
3240 utl::TempFile aTempMain
;
3241 aTempMain
.EnableKillingFile();
3242 utl::TempFile aTempTable
;
3243 aTempTable
.EnableKillingFile();
3244 utl::TempFile aTempData
;
3245 aTempData
.EnableKillingFile();
3247 msfilter::MSCodec_Std97 aCtx
;
3248 bool bEncrypt
= GetWriter().InitStd97CodecUpdateMedium(aCtx
);
3251 GetWriter().SetStream(
3252 aTempMain
.GetStream( StreamMode::READWRITE
| StreamMode::SHARE_DENYWRITE
) );
3254 pTableStrm
= aTempTable
.GetStream( StreamMode::READWRITE
| StreamMode::SHARE_DENYWRITE
);
3256 pDataStrm
= aTempData
.GetStream( StreamMode::READWRITE
| StreamMode::SHARE_DENYWRITE
);
3258 sal_uInt8 aRC4EncryptionHeader
[ 52 ] = {0};
3259 pTableStrm
->WriteBytes(aRC4EncryptionHeader
, 52);
3262 // Default: "Standard"
3263 pSepx
= new WW8_WrPlcSepx( *this ); // Sections/headers/footers
3265 pFootnote
= new WW8_WrPlcFootnoteEdn( TXT_FTN
); // Footnotes
3266 pEdn
= new WW8_WrPlcFootnoteEdn( TXT_EDN
); // Endnotes
3267 m_pAtn
= new WW8_WrPlcAnnotations
; // PostIts
3268 m_pFactoids
.reset(new WW8_WrtFactoids
); // Smart tags.
3269 m_pTextBxs
= new WW8_WrPlcTextBoxes( TXT_TXTBOX
);
3270 m_pHFTextBxs
= new WW8_WrPlcTextBoxes( TXT_HFTXTBOX
);
3272 m_pSdrObjs
= new MainTextPlcDrawObj
; // Draw-/Fly-Objects for main text
3273 m_pHFSdrObjs
= new HdFtPlcDrawObj
; // Draw-/Fly-Objects for header/footer
3275 m_pBkmks
= new WW8_WrtBookmarks
; // Bookmarks
3276 GetWriter().CreateBookmarkTable();
3278 m_pPapPlc
= new WW8_WrPlcPn( *this, PAP
, pFib
->m_fcMin
);
3279 m_pChpPlc
= new WW8_WrPlcPn( *this, CHP
, pFib
->m_fcMin
);
3280 pO
= new ww::bytes();
3281 m_pStyles
= new MSWordStyles( *this );
3282 m_pFieldMain
= new WW8_WrPlcField( 2, TXT_MAINTEXT
);
3283 m_pFieldHdFt
= new WW8_WrPlcField( 2, TXT_HDFT
);
3284 m_pFieldFootnote
= new WW8_WrPlcField( 2, TXT_FTN
);
3285 m_pFieldEdn
= new WW8_WrPlcField( 2, TXT_EDN
);
3286 m_pFieldAtn
= new WW8_WrPlcField( 2, TXT_ATN
);
3287 m_pFieldTextBxs
= new WW8_WrPlcField( 2, TXT_TXTBOX
);
3288 m_pFieldHFTextBxs
= new WW8_WrPlcField( 2, TXT_HFTXTBOX
);
3290 m_pMagicTable
= new WW8_WrMagicTable
;
3292 m_pGrf
= new SwWW8WrGrf( *this );
3293 m_pPiece
= new WW8_WrPct( pFib
->m_fcMin
);
3296 pDop
->fRevMarking
= bool( RedlineFlags::On
& m_nOrigRedlineFlags
);
3297 pDop
->fRMView
= bool( RedlineFlags::ShowDelete
& m_nOrigRedlineFlags
);
3298 pDop
->fRMPrint
= pDop
->fRMView
;
3300 // set AutoHyphenation flag if found in default para style
3301 const SfxPoolItem
* pItem
;
3302 SwTextFormatColl
* pStdTextFormatColl
=
3303 m_pDoc
->getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD
, false);
3304 if (pStdTextFormatColl
&& SfxItemState::SET
== pStdTextFormatColl
->GetItemState(
3305 RES_PARATR_HYPHENZONE
, false, &pItem
))
3307 pDop
->fAutoHyphen
= static_cast<const SvxHyphenZoneItem
*>(pItem
)->IsHyphen();
3314 SvStream
*pStrmTemp
, *pTableStrmTemp
, *pDataStrmTemp
;
3315 pStrmTemp
= xWwStrm
.get();
3316 pTableStrmTemp
= xTableStrm
.get();
3317 pDataStrmTemp
= xDataStrm
.get();
3319 if ( pDataStrmTemp
&& pDataStrmTemp
!= pStrmTemp
)
3320 EncryptRC4(aCtx
, *pDataStrm
, *pDataStrmTemp
);
3322 EncryptRC4(aCtx
, *pTableStrm
, *pTableStrmTemp
);
3324 // Write Unencrypted Header 52 bytes to the start of the table stream
3325 // EncryptionVersionInfo (4 bytes): A Version structure where Version.vMajor MUST be 0x0001, and Version.vMinor MUST be 0x0001.
3326 pTableStrmTemp
->Seek( 0 );
3327 sal_uInt32 nEncType
= 0x10001;
3328 pTableStrmTemp
->WriteUInt32( nEncType
);
3330 sal_uInt8 pDocId
[16];
3331 aCtx
.GetDocId( pDocId
);
3333 sal_uInt8 pSaltData
[16];
3334 sal_uInt8 pSaltDigest
[16];
3335 aCtx
.GetEncryptKey( pDocId
, pSaltData
, pSaltDigest
);
3337 pTableStrmTemp
->WriteBytes(pDocId
, 16);
3338 pTableStrmTemp
->WriteBytes(pSaltData
, 16);
3339 pTableStrmTemp
->WriteBytes(pSaltDigest
, 16);
3341 EncryptRC4(aCtx
, GetWriter().Strm(), *pStrmTemp
);
3343 // Write Unencrypted Fib 68 bytes to the start of the workdocument stream
3344 pFib
->m_fEncrypted
= true; // fEncrypted indicates the document is encrypted.
3345 pFib
->m_fObfuscated
= false; // Must be 0 for RC4.
3346 pFib
->m_nHash
= 0x34; // encrypt header bytes count of table stream.
3347 pFib
->m_nKey
= 0; // lkey2 must be 0 for RC4.
3349 pStrmTemp
->Seek( 0 );
3350 pFib
->WriteHeader( *pStrmTemp
);
3354 DELETEZ( m_pMagicTable
);
3355 DELETEZ( m_pFieldFootnote
);
3356 DELETEZ( m_pFieldTextBxs
);
3357 DELETEZ( m_pFieldHFTextBxs
);
3358 DELETEZ( m_pFieldAtn
);
3359 DELETEZ( m_pFieldEdn
);
3360 DELETEZ( m_pFieldHdFt
);
3361 DELETEZ( m_pFieldMain
);
3362 DELETEZ( m_pStyles
);
3364 DELETEZ( m_pChpPlc
);
3365 DELETEZ( m_pPapPlc
);
3368 delete m_pRedlAuthors
;
3370 delete m_pHFSdrObjs
;
3372 delete m_pHFTextBxs
;
3380 GetWriter().SetStream( nullptr );
3382 xWwStrm
->SetBufferSize( 0 );
3383 xTableStrm
->SetBufferSize( 0 );
3384 xDataStrm
->SetBufferSize( 0 );
3385 if( 0 == pDataStrm
->Seek( STREAM_SEEK_TO_END
))
3388 pDataStrm
= nullptr;
3389 GetWriter().GetStorage().Remove(OUString(SL::aData
));
3393 void WW8Export::PrepareStorage()
3395 static const sal_uInt8 pData
[] =
3397 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
3398 0xFF, 0xFF, 0xFF, 0xFF, 0x06, 0x09, 0x02, 0x00,
3399 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,
3400 0x00, 0x00, 0x00, 0x46,
3402 0x18, 0x00, 0x00, 0x00,
3403 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f',
3404 't', ' ', 'W', 'o', 'r', 'd', '-', 'D',
3405 'o', 'k', 'u', 'm', 'e', 'n', 't', 0x0,
3407 0x0A, 0x00, 0x00, 0x00,
3408 'M', 'S', 'W', 'o', 'r', 'd', 'D', 'o',
3411 0x10, 0x00, 0x00, 0x00,
3412 'W', 'o', 'r', 'd', '.', 'D', 'o', 'c',
3413 'u', 'm', 'e', 'n', 't', '.', '8', 0x0,
3415 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00,
3416 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
3419 SvGlobalName
aGName(MSO_WW8_CLASSID
);
3420 GetWriter().GetStorage().SetClass(
3421 aGName
, SotClipboardFormatId::NONE
, "Microsoft Word-Document");
3422 tools::SvRef
<SotStorageStream
> xStor( GetWriter().GetStorage().OpenSotStream(sCompObj
) );
3423 xStor
->WriteBytes(pData
, sizeof(pData
));
3425 SwDocShell
* pDocShell
= m_pDoc
->GetDocShell ();
3426 OSL_ENSURE(pDocShell
, "no SwDocShell");
3429 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
3430 pDocShell
->GetModel(), uno::UNO_QUERY_THROW
);
3431 uno::Reference
<document::XDocumentProperties
> xDocProps(
3432 xDPS
->getDocumentProperties());
3433 OSL_ENSURE(xDocProps
.is(), "DocumentProperties is null");
3437 if ( SvtFilterOptions::Get().IsEnableWordPreview() )
3439 std::shared_ptr
<GDIMetaFile
> xMetaFile
=
3440 pDocShell
->GetPreviewMetaFile();
3441 uno::Sequence
<sal_Int8
> metaFile(
3442 sfx2::convertMetaFile(xMetaFile
.get()));
3443 sfx2::SaveOlePropertySet(xDocProps
, &GetWriter().GetStorage(), &metaFile
);
3446 sfx2::SaveOlePropertySet( xDocProps
, &GetWriter().GetStorage() );
3451 sal_uLong
SwWW8Writer::WriteStorage()
3453 // #i34818# - update layout (if present), for SwWriteTable
3454 SwViewShell
* pViewShell
= pDoc
->getIDocumentLayoutAccess().GetCurrentViewShell();
3455 if( pViewShell
!= nullptr )
3456 pViewShell
->CalcLayout();
3458 long nMaxNode
= pDoc
->GetNodes().Count();
3459 ::StartProgress( STR_STATSTR_W4WWRITE
, 0, nMaxNode
, pDoc
->GetDocShell() );
3461 // Respect table at the beginning of the document
3463 SwTableNode
* pTNd
= pCurPam
->GetNode().FindTableNode();
3464 if( pTNd
&& bWriteAll
)
3465 // start with the table node !!
3466 pCurPam
->GetPoint()->nNode
= *pTNd
;
3469 // Do the actual export
3471 bool bDot
= mpMedium
->GetFilter()->GetName().endsWith("Vorlage");
3472 WW8Export
aExport(this, pDoc
, pCurPam
, pOrigPam
, bDot
);
3473 m_pExport
= &aExport
;
3474 aExport
.ExportDocument( bWriteAll
);
3475 m_pExport
= nullptr;
3478 ::EndProgress( pDoc
->GetDocShell() );
3482 sal_uLong
SwWW8Writer::WriteMedium( SfxMedium
& )
3484 return WriteStorage();
3487 sal_uLong
SwWW8Writer::Write( SwPaM
& rPaM
, SfxMedium
& rMed
,
3488 const OUString
* pFileName
)
3491 sal_uLong nRet
= StgWriter::Write( rPaM
, rMed
, pFileName
);
3496 MSWordExportBase::MSWordExportBase( SwDoc
*pDocument
, SwPaM
*pCurrentPam
, SwPaM
*pOriginalPam
)
3497 : m_aMainStg(sMainStream
)
3500 , m_pUsedNumTable(nullptr)
3501 , m_pTopNodeOfHdFtPage(nullptr)
3503 , m_pRedlAuthors(nullptr)
3504 , m_pOLEExp(nullptr)
3505 , m_pOCXExp(nullptr)
3506 , m_pTableInfo(new ww8::WW8TableInfo())
3507 , m_nCharFormatStart(0)
3508 , m_nFormatCollStart(0)
3509 , m_nStyleBeforeFly(0)
3510 , m_nLastFormatId(0)
3513 , m_nOrigRedlineFlags(RedlineFlags::NONE
)
3514 , m_pAktPageDesc(nullptr)
3515 , m_bPrevTextNodeIsEmpty(false)
3516 , m_pPapPlc(nullptr)
3517 , m_pChpPlc(nullptr)
3518 , m_pChpIter(nullptr)
3519 , m_pStyles(nullptr)
3521 , m_pFactoids(nullptr)
3522 , m_pTextBxs(nullptr)
3523 , m_pHFTextBxs(nullptr)
3524 , m_pParentFrame(nullptr)
3525 , m_pFlyOffset(nullptr)
3526 , m_eNewAnchorType(FLY_AS_CHAR
)
3527 , m_pFieldMain(nullptr)
3528 , m_pFieldHdFt(nullptr)
3529 , m_pFieldFootnote(nullptr)
3530 , m_pFieldEdn(nullptr)
3531 , m_pFieldAtn(nullptr)
3532 , m_pFieldTextBxs(nullptr)
3533 , m_pFieldHFTextBxs(nullptr)
3534 , m_pMagicTable(nullptr)
3536 , m_pStyAttr(nullptr)
3537 , m_pOutFormatNode(nullptr)
3538 , m_pCurrentStyle(nullptr)
3539 , m_pSdrObjs(nullptr)
3540 , m_pHFSdrObjs(nullptr)
3541 , m_pEscher(nullptr)
3544 , m_bBreakBefore(false)
3546 , m_bOutFlyFrameAttrs(false)
3547 , m_bOutPageDescs(false)
3548 , m_bOutFirstPage(false)
3549 , m_bOutTable(false)
3551 , m_bInWriteEscher(false)
3552 , m_bStartTOX(false)
3553 , m_bInWriteTOX(false)
3554 , m_bFootnoteAtTextEnd(false)
3555 , m_bEndAtTextEnd(false)
3558 , m_bSubstituteBullets(true)
3559 , m_bTabInTOC(false)
3560 , m_bHideTabLeaderAndPageNumbers(false)
3561 , m_bExportModeRTF(false)
3562 , m_bFontSizeWritten(false)
3564 , m_nCurStart(pCurrentPam
->GetPoint()->nNode
.GetIndex())
3565 , m_nCurEnd(pCurrentPam
->GetMark()->nNode
.GetIndex())
3566 , m_pCurPam(pCurrentPam
)
3567 , m_pOrigPam(pOriginalPam
)
3571 MSWordExportBase::~MSWordExportBase()
3573 if (m_pUsedNumTable
) // all used NumRules
3575 // clear the part of the list array that was copied from the document
3576 // - it's an auto delete array, so the rest of the array which are
3577 // duplicated lists that were added during the export will be deleted.
3578 m_pUsedNumTable
->erase(m_pUsedNumTable
->begin(), m_pUsedNumTable
->begin() + m_pUsedNumTable
->size() - m_nUniqueList
);
3579 delete m_pUsedNumTable
;
3585 WW8Export::WW8Export( SwWW8Writer
*pWriter
,
3586 SwDoc
*pDocument
, SwPaM
*pCurrentPam
, SwPaM
*pOriginalPam
,
3588 : MSWordExportBase( pDocument
, pCurrentPam
, pOriginalPam
)
3590 , pTableStrm(nullptr)
3591 , pDataStrm(nullptr)
3594 , pFootnote(nullptr)
3598 , m_pWriter(pWriter
)
3599 , m_pAttrOutput(new WW8AttributeOutput(*this))
3603 WW8Export::~WW8Export()
3605 delete m_pAttrOutput
;
3606 m_pAttrOutput
= nullptr;
3609 AttributeOutputBase
& WW8Export::AttrOutput() const
3611 return *m_pAttrOutput
;
3614 MSWordSections
& WW8Export::Sections() const
3619 SwWW8Writer::SwWW8Writer(const OUString
& rFltName
, const OUString
& rBaseURL
)
3621 m_pExport( nullptr ),
3624 assert(rFltName
== FILTER_WW8
); // WW6/7 export was removed
3626 SetBaseURL( rBaseURL
);
3629 SwWW8Writer::~SwWW8Writer()
3633 extern "C" SAL_DLLPUBLIC_EXPORT sal_uLong SAL_CALL
SaveOrDelMSVBAStorage_ww8( SfxObjectShell
& rDoc
, SotStorage
& rStor
, sal_Bool bSaveInto
, const OUString
& rStorageName
)
3635 SvxImportMSVBasic
aTmp( rDoc
, rStor
);
3636 return aTmp
.SaveOrDelMSVBAStorage( bSaveInto
, rStorageName
);
3639 extern "C" SAL_DLLPUBLIC_EXPORT
void SAL_CALL
ExportDOC( const OUString
& rFltName
, const OUString
& rBaseURL
, WriterRef
& xRet
)
3641 xRet
= new SwWW8Writer( rFltName
, rBaseURL
);
3644 extern "C" SAL_DLLPUBLIC_EXPORT sal_uLong SAL_CALL
GetSaveWarningOfMSVBAStorage_ww8( SfxObjectShell
&rDocS
)
3646 return SvxImportMSVBasic::GetSaveWarningOfMSVBAStorage( rDocS
);
3649 bool WW8_WrPlcFootnoteEdn::WriteText( WW8Export
& rWrt
)
3652 if (TXT_FTN
== nTyp
)
3654 bRet
= WriteGenericText( rWrt
, TXT_FTN
, rWrt
.pFib
->m_ccpFootnote
);
3655 rWrt
.m_pFieldFootnote
->Finish( rWrt
.Fc2Cp( rWrt
.Strm().Tell() ),
3656 rWrt
.pFib
->m_ccpText
);
3660 bRet
= WriteGenericText( rWrt
, TXT_EDN
, rWrt
.pFib
->m_ccpEdn
);
3661 rWrt
.m_pFieldEdn
->Finish( rWrt
.Fc2Cp( rWrt
.Strm().Tell() ),
3662 rWrt
.pFib
->m_ccpText
+ rWrt
.pFib
->m_ccpFootnote
3663 + rWrt
.pFib
->m_ccpHdr
+ rWrt
.pFib
->m_ccpAtn
);
3668 void WW8_WrPlcFootnoteEdn::WritePlc( WW8Export
& rWrt
) const
3670 if( TXT_FTN
== nTyp
)
3672 WriteGenericPlc( rWrt
, TXT_FTN
, rWrt
.pFib
->m_fcPlcffndText
,
3673 rWrt
.pFib
->m_lcbPlcffndText
, rWrt
.pFib
->m_fcPlcffndRef
,
3674 rWrt
.pFib
->m_lcbPlcffndRef
);
3678 WriteGenericPlc( rWrt
, TXT_EDN
, rWrt
.pFib
->m_fcPlcfendText
,
3679 rWrt
.pFib
->m_lcbPlcfendText
, rWrt
.pFib
->m_fcPlcfendRef
,
3680 rWrt
.pFib
->m_lcbPlcfendRef
);
3684 bool WW8_WrPlcAnnotations::WriteText( WW8Export
& rWrt
)
3686 bool bRet
= WriteGenericText( rWrt
, TXT_ATN
, rWrt
.pFib
->m_ccpAtn
);
3687 rWrt
.m_pFieldAtn
->Finish( rWrt
.Fc2Cp( rWrt
.Strm().Tell() ),
3688 rWrt
.pFib
->m_ccpText
+ rWrt
.pFib
->m_ccpFootnote
3689 + rWrt
.pFib
->m_ccpHdr
);
3693 void WW8_WrPlcAnnotations::WritePlc( WW8Export
& rWrt
) const
3695 WriteGenericPlc( rWrt
, TXT_ATN
, rWrt
.pFib
->m_fcPlcfandText
,
3696 rWrt
.pFib
->m_lcbPlcfandText
, rWrt
.pFib
->m_fcPlcfandRef
,
3697 rWrt
.pFib
->m_lcbPlcfandRef
);
3700 void WW8_WrPlcTextBoxes::WritePlc( WW8Export
& rWrt
) const
3702 if( TXT_TXTBOX
== nTyp
)
3704 WriteGenericPlc( rWrt
, nTyp
, rWrt
.pFib
->m_fcPlcftxbxBkd
,
3705 rWrt
.pFib
->m_lcbPlcftxbxBkd
, rWrt
.pFib
->m_fcPlcftxbxText
,
3706 rWrt
.pFib
->m_lcbPlcftxbxText
);
3710 WriteGenericPlc( rWrt
, nTyp
, rWrt
.pFib
->m_fcPlcfHdrtxbxBkd
,
3711 rWrt
.pFib
->m_lcbPlcfHdrtxbxBkd
, rWrt
.pFib
->m_fcPlcfHdrtxbxText
,
3712 rWrt
.pFib
->m_lcbPlcfHdrtxbxText
);
3716 void WW8Export::RestoreMacroCmds()
3718 pFib
->m_fcCmds
= pTableStrm
->Tell();
3720 uno::Reference
< embed::XStorage
> xSrcRoot(m_pDoc
->GetDocShell()->GetStorage());
3723 uno::Reference
< io::XStream
> xSrcStream
=
3724 xSrcRoot
->openStreamElement( SL::aMSMacroCmds
, embed::ElementModes::READ
);
3725 SvStream
* pStream
= ::utl::UcbStreamHelper::CreateStream( xSrcStream
);
3727 if ( pStream
&& SVSTREAM_OK
== pStream
->GetError())
3729 pStream
->Seek(STREAM_SEEK_TO_END
);
3730 pFib
->m_lcbCmds
= pStream
->Tell();
3733 std::unique_ptr
<sal_uInt8
[]> pBuffer( new sal_uInt8
[pFib
->m_lcbCmds
] );
3734 bool bReadOk
= checkRead(*pStream
, pBuffer
.get(), pFib
->m_lcbCmds
);
3736 pTableStrm
->WriteBytes(pBuffer
.get(), pFib
->m_lcbCmds
);
3741 catch ( const uno::Exception
& )
3746 pFib
->m_lcbCmds
= pTableStrm
->Tell() - pFib
->m_fcCmds
;
3749 void WW8SHDLong::Write( WW8Export
& rExport
)
3751 rExport
.InsUInt32( m_cvFore
);
3752 rExport
.InsUInt32( m_cvBack
);
3753 rExport
.InsUInt16( 0 ); // ipat
3756 void WW8Export::WriteFormData( const ::sw::mark::IFieldmark
& rFieldmark
)
3758 const ::sw::mark::IFieldmark
* pFieldmark
= &rFieldmark
;
3759 const ::sw::mark::ICheckboxFieldmark
* pAsCheckbox
= dynamic_cast< const ::sw::mark::ICheckboxFieldmark
* >( pFieldmark
);
3761 if ( ! ( rFieldmark
.GetFieldname() == ODF_FORMTEXT
||
3762 rFieldmark
.GetFieldname() == ODF_FORMDROPDOWN
||
3763 rFieldmark
.GetFieldname() == ODF_FORMCHECKBOX
) )
3765 SAL_WARN( "sw.ww8", "unknown field type" );
3769 int type
= 0; // TextFieldmark
3772 if ( rFieldmark
.GetFieldname() == ODF_FORMDROPDOWN
)
3775 ::sw::mark::IFieldmark::parameter_map_t::const_iterator pNameParameter
= rFieldmark
.GetParameters()->find("name");
3777 if(pNameParameter
!= rFieldmark
.GetParameters()->end())
3778 pNameParameter
->second
>>= ffname
;
3780 sal_uLong nDataStt
= pDataStrm
->Tell();
3781 m_pChpPlc
->AppendFkpEntry(Strm().Tell());
3784 static sal_uInt8 aArr1
[] =
3786 0x03, 0x6a, 0,0,0,0, // sprmCPicLocation
3788 0x06, 0x08, 0x01, // sprmCFData
3789 0x55, 0x08, 0x01, // sprmCFSpec
3790 0x02, 0x08, 0x01 // sprmCFFieldVanish
3792 sal_uInt8
* pDataAdr
= aArr1
+ 2;
3793 Set_UInt32(pDataAdr
, nDataStt
);
3795 m_pChpPlc
->AppendFkpEntry( Strm().Tell(), sizeof( aArr1
), aArr1
);
3803 FFDataHeader() : version( 0xFFFFFFFF ), bits(0), cch(0), hps(0) {}
3806 FFDataHeader aFieldHeader
;
3807 aFieldHeader
.bits
|= (type
& 0x03);
3809 sal_Int32 ffres
= 0; // rFieldmark.GetFFRes();
3810 if ( pAsCheckbox
&& pAsCheckbox
->IsChecked() )
3812 else if ( type
== 2 )
3814 ::sw::mark::IFieldmark::parameter_map_t::const_iterator pResParameter
= rFieldmark
.GetParameters()->find(ODF_FORMDROPDOWN_RESULT
);
3815 if(pResParameter
!= rFieldmark
.GetParameters()->end())
3816 pResParameter
->second
>>= ffres
;
3820 aFieldHeader
.bits
|= ( (ffres
<<2) & 0x7C );
3821 if (type
== 0) // iTypeText
3823 sw::mark::IFieldmark::parameter_map_t::const_iterator pParameter
= rFieldmark
.GetParameters()->find("MaxLength");
3824 if (pParameter
!= rFieldmark
.GetParameters()->end())
3827 pParameter
->second
>>= aLength
;
3828 aFieldHeader
.cch
= aLength
.toUInt32();
3832 std::vector
< OUString
> aListItems
;
3835 aFieldHeader
.bits
|= 0x8000; // ffhaslistbox
3836 const ::sw::mark::IFieldmark::parameter_map_t
* const pParameters
= rFieldmark
.GetParameters();
3837 ::sw::mark::IFieldmark::parameter_map_t::const_iterator pListEntries
= pParameters
->find(ODF_FORMDROPDOWN_LISTENTRY
);
3838 if(pListEntries
!= pParameters
->end())
3840 uno::Sequence
< OUString
> vListEntries
;
3841 pListEntries
->second
>>= vListEntries
;
3842 copy(vListEntries
.begin(), vListEntries
.end(), back_inserter(aListItems
));
3846 const OUString ffdeftext
;
3847 const OUString ffformat
;
3848 const OUString ffhelptext
;
3849 const OUString ffstattext
;
3850 const OUString ffentrymcr
;
3851 const OUString ffexitmcr
;
3853 const sal_uInt8 aFieldData
[] =
3855 0x44,0, // the start of "next" data
3856 0,0,0,0,0,0,0,0,0,0, // PIC-Structure! /10
3857 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | /16
3858 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | /16
3859 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | /16
3862 sal_uInt32 slen
= sizeof(sal_uInt32
)
3863 + sizeof(aFieldData
)
3864 + sizeof( aFieldHeader
.version
) + sizeof( aFieldHeader
.bits
) + sizeof( aFieldHeader
.cch
) + sizeof( aFieldHeader
.hps
)
3865 + 2*ffname
.getLength() + 4
3866 + 2*ffformat
.getLength() + 4
3867 + 2*ffhelptext
.getLength() + 4
3868 + 2*ffstattext
.getLength() + 4
3869 + 2*ffentrymcr
.getLength() + 4
3870 + 2*ffexitmcr
.getLength() + 4;
3874 slen
+= 2*ffdeftext
.getLength() + 4; //xstzTextDef
3876 slen
+= 2; // sttb ( fExtend )
3877 slen
+= 4; // for num of list items
3878 const int items
= aListItems
.size();
3879 for( int i
= 0; i
< items
; i
++ ) {
3880 OUString item
= aListItems
[i
];
3881 slen
+= 2 * item
.getLength() + 2;
3885 pDataStrm
->WriteUInt32( slen
);
3887 int len
= sizeof( aFieldData
);
3888 OSL_ENSURE( len
== 0x44-sizeof(sal_uInt32
), "SwWW8Writer::WriteFormData(..) - wrong aFieldData length" );
3889 pDataStrm
->WriteBytes( aFieldData
, len
);
3891 pDataStrm
->WriteUInt32( aFieldHeader
.version
).WriteUInt16( aFieldHeader
.bits
).WriteUInt16( aFieldHeader
.cch
).WriteUInt16( aFieldHeader
.hps
);
3893 SwWW8Writer::WriteString_xstz( *pDataStrm
, ffname
, true ); // Form field name
3896 SwWW8Writer::WriteString_xstz( *pDataStrm
, ffdeftext
, true );
3898 pDataStrm
->WriteUInt16( 0 );
3900 SwWW8Writer::WriteString_xstz( *pDataStrm
, OUString( ffformat
), true );
3901 SwWW8Writer::WriteString_xstz( *pDataStrm
, OUString( ffhelptext
), true );
3902 SwWW8Writer::WriteString_xstz( *pDataStrm
, OUString( ffstattext
), true );
3903 SwWW8Writer::WriteString_xstz( *pDataStrm
, OUString( ffentrymcr
), true );
3904 SwWW8Writer::WriteString_xstz( *pDataStrm
, OUString( ffexitmcr
), true );
3906 pDataStrm
->WriteUInt16( 0xFFFF );
3907 const int items
=aListItems
.size();
3908 pDataStrm
->WriteUInt32( items
);
3909 for(int i
=0;i
<items
;i
++) {
3910 OUString item
=aListItems
[i
];
3911 SwWW8Writer::WriteString_xstz( *pDataStrm
, item
, false );
3916 void WW8Export::WriteHyperlinkData( const sw::mark::IFieldmark
& /*rFieldmark*/ )
3918 //@TODO implement me !!!
3921 void WW8AttributeOutput::TableNodeInfoInner( ww8::WW8TableNodeInfoInner::Pointer_t pNodeInfoInner
)
3924 ShortToSVBT16( m_rWW8Export
.m_nStyleBeforeFly
, nStyle
);
3927 SAL_INFO( "sw.ww8", "<OutWW8_TableNodeInfoInner>" << pNodeInfoInner
->toString());
3930 m_rWW8Export
.pO
->clear();
3932 sal_uInt32 nShadowsBefore
= pNodeInfoInner
->getShadowsBefore();
3933 if (nShadowsBefore
> 0)
3935 ww8::WW8TableNodeInfoInner::Pointer_t
3936 pTmpNodeInfoInner(new ww8::WW8TableNodeInfoInner(nullptr));
3938 pTmpNodeInfoInner
->setDepth(pNodeInfoInner
->getDepth());
3939 pTmpNodeInfoInner
->setEndOfCell(true);
3941 for (sal_uInt32 n
= 0; n
< nShadowsBefore
; ++n
)
3943 m_rWW8Export
.WriteCR(pTmpNodeInfoInner
);
3945 m_rWW8Export
.pO
->insert( m_rWW8Export
.pO
->end(), nStyle
, nStyle
+2 ); // Style #
3946 TableInfoCell(pTmpNodeInfoInner
);
3947 m_rWW8Export
.m_pPapPlc
->AppendFkpEntry
3948 ( m_rWW8Export
.Strm().Tell(), m_rWW8Export
.pO
->size(), m_rWW8Export
.pO
->data() );
3950 m_rWW8Export
.pO
->clear();
3954 if (pNodeInfoInner
->isEndOfCell())
3956 SAL_INFO( "sw.ww8", "<endOfCell/>" );
3958 m_rWW8Export
.WriteCR(pNodeInfoInner
);
3960 m_rWW8Export
.pO
->insert( m_rWW8Export
.pO
->end(), nStyle
, nStyle
+2 ); // Style #
3961 TableInfoCell(pNodeInfoInner
);
3962 m_rWW8Export
.m_pPapPlc
->AppendFkpEntry( m_rWW8Export
.Strm().Tell(), m_rWW8Export
.pO
->size(), m_rWW8Export
.pO
->data() );
3964 m_rWW8Export
.pO
->clear();
3967 sal_uInt32 nShadowsAfter
= pNodeInfoInner
->getShadowsAfter();
3968 if (nShadowsAfter
> 0)
3970 ww8::WW8TableNodeInfoInner::Pointer_t
3971 pTmpNodeInfoInner(new ww8::WW8TableNodeInfoInner(nullptr));
3973 pTmpNodeInfoInner
->setDepth(pNodeInfoInner
->getDepth());
3974 pTmpNodeInfoInner
->setEndOfCell(true);
3976 for (sal_uInt32 n
= 0; n
< nShadowsAfter
; ++n
)
3978 m_rWW8Export
.WriteCR(pTmpNodeInfoInner
);
3980 m_rWW8Export
.pO
->insert( m_rWW8Export
.pO
->end(), nStyle
, nStyle
+2 ); // Style #
3981 TableInfoCell(pTmpNodeInfoInner
);
3982 m_rWW8Export
.m_pPapPlc
->AppendFkpEntry( m_rWW8Export
.Strm().Tell(), m_rWW8Export
.pO
->size(), m_rWW8Export
.pO
->data() );
3984 m_rWW8Export
.pO
->clear();
3988 if (pNodeInfoInner
->isEndOfLine())
3990 SAL_INFO( "sw.ww8", "<endOfLine/>" );
3992 TableRowEnd(pNodeInfoInner
->getDepth());
3994 ShortToSVBT16(0, nStyle
);
3995 m_rWW8Export
.pO
->insert( m_rWW8Export
.pO
->end(), nStyle
, nStyle
+2 ); // Style #
3996 TableInfoRow(pNodeInfoInner
);
3997 m_rWW8Export
.m_pPapPlc
->AppendFkpEntry( m_rWW8Export
.Strm().Tell(), m_rWW8Export
.pO
->size(), m_rWW8Export
.pO
->data() );
3999 m_rWW8Export
.pO
->clear();
4001 SAL_INFO( "sw.ww8", "</OutWW8_TableNodeInfoInner>" );
4004 void MSWordExportBase::OutputStartNode( const SwStartNode
& rNode
)
4007 ww8::WW8TableNodeInfo::Pointer_t pNodeInfo
=
4008 m_pTableInfo
->getTableNodeInfo( &rNode
);
4010 if (pNodeInfo
.get() != nullptr)
4013 SAL_INFO( "sw.ww8", pNodeInfo
->toString());
4015 const ww8::WW8TableNodeInfo::Inners_t aInners
= pNodeInfo
->getInners();
4016 ww8::WW8TableNodeInfo::Inners_t::const_reverse_iterator
aIt(aInners
.rbegin());
4017 ww8::WW8TableNodeInfo::Inners_t::const_reverse_iterator
aEnd(aInners
.rend());
4020 ww8::WW8TableNodeInfoInner::Pointer_t pInner
= aIt
->second
;
4022 AttrOutput().TableNodeInfoInner(pInner
);
4026 SAL_INFO( "sw.ww8", "</OutWW8_SwStartNode>" );
4029 void MSWordExportBase::OutputEndNode( const SwEndNode
&rNode
)
4032 SAL_INFO( "sw.ww8", "<OutWW8_SwEndNode>" << dbg_out(&rNode
));
4035 ww8::WW8TableNodeInfo::Pointer_t pNodeInfo
= m_pTableInfo
->getTableNodeInfo( &rNode
);
4037 if (pNodeInfo
.get() != nullptr)
4040 SAL_INFO( "sw.ww8", pNodeInfo
->toString());
4043 const ww8::WW8TableNodeInfo::Inners_t aInners
= pNodeInfo
->getInners();
4044 ww8::WW8TableNodeInfo::Inners_t::const_iterator
aIt(aInners
.begin());
4045 ww8::WW8TableNodeInfo::Inners_t::const_iterator
aEnd(aInners
.end());
4048 ww8::WW8TableNodeInfoInner::Pointer_t pInner
= aIt
->second
;
4049 AttrOutput().TableNodeInfoInner(pInner
);
4053 SAL_INFO( "sw.ww8", "</OutWW8_SwEndNode>" );
4056 const NfKeywordTable
& MSWordExportBase::GetNfKeywordTable()
4058 if (m_pKeyMap
.get() == nullptr)
4060 m_pKeyMap
.reset(new NfKeywordTable
);
4061 NfKeywordTable
& rKeywordTable
= *m_pKeyMap
;
4062 rKeywordTable
[NF_KEY_D
] = "d";
4063 rKeywordTable
[NF_KEY_DD
] = "dd";
4064 rKeywordTable
[NF_KEY_DDD
] = "ddd";
4065 rKeywordTable
[NF_KEY_DDDD
] = "dddd";
4066 rKeywordTable
[NF_KEY_M
] = "M";
4067 rKeywordTable
[NF_KEY_MM
] = "MM";
4068 rKeywordTable
[NF_KEY_MMM
] = "MMM";
4069 rKeywordTable
[NF_KEY_MMMM
] = "MMMM";
4070 rKeywordTable
[NF_KEY_NN
] = "ddd";
4071 rKeywordTable
[NF_KEY_NNN
] = "dddd";
4072 rKeywordTable
[NF_KEY_NNNN
] = "dddd";
4073 rKeywordTable
[NF_KEY_YY
] = "yy";
4074 rKeywordTable
[NF_KEY_YYYY
] = "yyyy";
4075 rKeywordTable
[NF_KEY_H
] = "H";
4076 rKeywordTable
[NF_KEY_HH
] = "HH";
4077 rKeywordTable
[NF_KEY_MI
] = "m";
4078 rKeywordTable
[NF_KEY_MMI
] = "mm";
4079 rKeywordTable
[NF_KEY_S
] = "s";
4080 rKeywordTable
[NF_KEY_SS
] = "ss";
4081 rKeywordTable
[NF_KEY_AMPM
] = "AM/PM";
4087 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */