bump product version to 4.1.6.2
[LibreOffice.git] / sw / source / filter / ww8 / wrtww8.cxx
blob639b25cd4c1859f8604f87a882a6b9f5e7cb7233
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
21 #include <iostream>
23 #include <com/sun/star/embed/ElementModes.hpp>
24 #include <com/sun/star/embed/XStorage.hpp>
25 #include <unotools/ucbstreamhelper.hxx>
27 #include <algorithm>
29 #include <hintids.hxx>
30 #include <string.h> // memcpy()
31 #include <osl/endian.h>
32 #include <docsh.hxx>
34 #include <unotools/fltrcfg.hxx>
35 #include <vcl/salbtype.hxx>
36 #include <sot/storage.hxx>
37 #include <svl/zformat.hxx>
38 #include <sfx2/docinf.hxx>
39 #include <editeng/tstpitem.hxx>
40 #include <svx/svdmodel.hxx>
41 #include <svx/svdpage.hxx>
42 #include <editeng/hyphenzoneitem.hxx>
43 #include <editeng/langitem.hxx>
44 #include <filter/msfilter/msoleexp.hxx>
45 #include <editeng/lrspitem.hxx>
46 #include <editeng/ulspitem.hxx>
47 #include <editeng/boxitem.hxx>
48 #include <editeng/brushitem.hxx>
49 #include <swtypes.hxx>
50 #include <swrect.hxx>
51 #include <swtblfmt.hxx>
52 #include <txatbase.hxx>
53 #include <fmtcntnt.hxx>
54 #include <fmtpdsc.hxx>
55 #include <fmtrowsplt.hxx>
56 #include <frmatr.hxx>
57 #include <doc.hxx>
58 #include <viewopt.hxx>
59 #include <docary.hxx>
60 #include <pam.hxx>
61 #include <ndtxt.hxx>
62 #include <shellio.hxx>
63 #include <docstat.hxx>
64 #include <pagedesc.hxx>
65 #include <IMark.hxx>
66 #include <swtable.hxx>
67 #include <wrtww8.hxx>
68 #include <ww8par.hxx>
69 #include <fltini.hxx>
70 #include <swmodule.hxx>
71 #include <section.hxx>
72 #include <swfltopt.hxx>
73 #include <fmtinfmt.hxx>
74 #include <txtinet.hxx>
75 #include <fmturl.hxx>
76 #include <fesh.hxx>
77 #include <svtools/imap.hxx>
78 #include <svtools/imapobj.hxx>
79 #include <tools/urlobj.hxx>
80 #include <mdiexp.hxx> // Progress
81 #include <statstr.hrc> // ResId for the status bar
82 #include <fmtline.hxx>
83 #include <fmtfsize.hxx>
84 #include <comphelper/extract.hxx>
85 #include <comphelper/stlunosequence.hxx>
86 #include <comphelper/string.hxx>
87 #include <doctok/sprmids.hxx>
89 #include "writerhelper.hxx"
90 #include "writerwordglue.hxx"
91 #include "ww8attributeoutput.hxx"
93 #include <IDocumentMarkAccess.hxx>
94 #include <xmloff/odffields.hxx>
96 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
97 #include <com/sun/star/document/XDocumentProperties.hpp>
99 #include "dbgoutsw.hxx"
101 #include <sfx2/docfile.hxx>
102 #include <sfx2/request.hxx>
103 #include <sfx2/frame.hxx>
104 #include <svl/stritem.hxx>
105 #include <unotools/tempfile.hxx>
106 #include <filter/msfilter/mscodec.hxx>
107 #include <filter/msfilter/svxmsbas.hxx>
108 #include <osl/time.h>
109 #include <rtl/random.h>
110 #include <vcl/svapp.hxx>
111 #include "WW8Sttbf.hxx"
112 #include <editeng/charrotateitem.hxx>
113 #include "WW8FibData.hxx"
114 #include "numrule.hxx"//For i120928
116 using namespace css;
117 using namespace sw::util;
118 using namespace sw::types;
120 /** FKP - Formatted disK Page
122 class WW8_WrFkp
124 sal_uInt8* pFkp; // Fkp total ( first and only FCs and Sprms )
125 sal_uInt8* pOfs; // pointer to the offset area, later copied to pFkp
126 ePLCFT ePlc;
127 short nStartGrp; // ab hier grpprls
128 short nOldStartGrp;
129 sal_uInt8 nItemSize;
130 sal_uInt8 nIMax; // number of entry pairs
131 sal_uInt8 nOldVarLen;
132 bool bCombined; // true : paste not allowed
134 sal_uInt8 SearchSameSprm( sal_uInt16 nVarLen, const sal_uInt8* pSprms );
135 public:
136 WW8_WrFkp(ePLCFT ePl, WW8_FC nStartFc, bool bWrtWW8);
137 ~WW8_WrFkp();
138 bool Append( WW8_FC nEndFc, sal_uInt16 nVarLen = 0, const sal_uInt8* pSprms = 0 );
139 bool Combine();
140 void Write( SvStream& rStrm, SwWW8WrGrf& rGrf );
142 bool IsEqualPos(WW8_FC nEndFc) const
143 { return !bCombined && nIMax && nEndFc == ((sal_Int32*)pFkp)[nIMax]; }
144 void MergeToNew( short& rVarLen, sal_uInt8 *& pNewSprms );
145 bool IsEmptySprm() const
146 { return !bCombined && nIMax && !nOldVarLen; }
147 void SetNewEnd( WW8_FC nEnd )
148 { ((sal_Int32*)pFkp)[nIMax] = nEnd; }
150 #ifdef __WW8_NEEDS_COPY
151 WW8_FC GetStartFc() const;
152 WW8_FC GetEndFc() const;
153 #else
154 WW8_FC GetStartFc() const { return ((sal_Int32*)pFkp)[0]; };
155 WW8_FC GetEndFc() const { return ((sal_Int32*)pFkp)[nIMax]; };
156 #endif // defined __WW8_NEEDS_COPY
158 sal_uInt8 *CopyLastSprms(sal_uInt8 &rLen, bool bVer8);
162 // class WW8_WrPc collects all piece entries for one piece
163 class WW8_WrPc
165 WW8_CP nStartCp; // Starting character position of the text
166 WW8_FC nStartFc; // Starting file position of the text
167 sal_uInt16 nStatus; // End of paragraph inside the piece?
169 public:
170 WW8_WrPc(WW8_FC nSFc, WW8_CP nSCp )
171 : nStartCp( nSCp ), nStartFc( nSFc ), nStatus( 0x0040 )
174 void SetStatus() { nStatus = 0x0050; }
175 sal_uInt16 GetStatus() const { return nStatus; }
176 WW8_CP GetStartCp() const { return nStartCp; }
177 WW8_FC GetStartFc() const { return nStartFc; }
180 class WW8_WrtBookmarks
182 private:
183 //! Holds information about a single bookmark.
184 struct BookmarkInfo {
185 sal_uLong startPos; //!< Starting character position.
186 sal_uLong endPos; //!< Ending character position.
187 bool isField; //!< True if the bookmark is in a field result.
188 String name; //!< Name of this bookmark.
189 inline BookmarkInfo(sal_uLong start, sal_uLong end, bool isFld, const String& bkName) : startPos(start), endPos(end), isField(isFld), name(bkName) {};
190 //! Operator < is defined purely for sorting.
191 inline bool operator<(const BookmarkInfo &other) const { return startPos < other.startPos; }
193 std::vector<BookmarkInfo> aBookmarks;
194 typedef std::vector<BookmarkInfo>::iterator BkmIter;
196 //! Return the position in aBookmarks where the string rNm can be found.
197 BkmIter GetPos( const String& rNm );
199 //No copying
200 WW8_WrtBookmarks(const WW8_WrtBookmarks&);
201 WW8_WrtBookmarks& operator=(const WW8_WrtBookmarks&);
202 public:
203 WW8_WrtBookmarks();
204 ~WW8_WrtBookmarks();
206 //! Add a new bookmark to the list OR add an end position to an existing bookmark.
207 void Append( WW8_CP nStartCp, const String& rNm, const ::sw::mark::IMark* pBkmk=NULL );
208 //! Write out bookmarks to file.
209 void Write( WW8Export& rWrt );
210 //! Move existing field marks from one position to another.
211 void MoveFieldMarks(sal_uLong nFrom,sal_uLong nTo);
215 #define ANZ_DEFAULT_STYLES 16
217 // Names of the storage streams
218 #define sMainStream OUString("WordDocument")
219 #define sCompObj OUString("\1CompObj")
221 static void WriteDop( WW8Export& rWrt )
223 WW8Dop& rDop = *rWrt.pDop;
225 // i#78951#, store the value of unknown compatability options
226 rDop.SetCompatabilityOptions( rWrt.pDoc->Getn32DummyCompatabilityOptions1());
227 rDop.SetCompatabilityOptions2( rWrt.pDoc->Getn32DummyCompatabilityOptions2());
229 rDop.fNoLeading = !rWrt.pDoc->get(IDocumentSettingAccess::ADD_EXT_LEADING);
230 rDop.fUsePrinterMetrics = !rWrt.pDoc->get(IDocumentSettingAccess::USE_VIRTUAL_DEVICE);
232 // write default TabStop
233 const SvxTabStopItem& rTabStop =
234 DefaultItemGet<SvxTabStopItem>(*rWrt.pDoc, RES_PARATR_TABSTOP);
235 rDop.dxaTab = (sal_uInt16)rTabStop[0].GetTabPos();
237 // Zoom factor
238 ViewShell *pViewShell(rWrt.pDoc->GetCurrentViewShell());
239 if (pViewShell && pViewShell->GetViewOptions()->GetZoomType() == SVX_ZOOM_PERCENT)
240 rDop.wScaleSaved = pViewShell->GetViewOptions()->GetZoom();
242 // Werte aus der DocStatistik (werden aufjedenfall fuer die
243 // DocStat-Felder benoetigt!)
244 rDop.fWCFtnEdn = true; // because they are included in StarWriter
246 const SwDocStat& rDStat = rWrt.pDoc->GetDocStat();
247 rDop.cWords = rDStat.nWord;
248 rDop.cCh = rDStat.nChar;
249 rDop.cPg = static_cast< sal_Int16 >(rDStat.nPage);
250 rDop.cParas = rDStat.nPara;
251 rDop.cLines = rDStat.nPara;
253 SwDocShell *pDocShell(rWrt.pDoc->GetDocShell());
254 OSL_ENSURE(pDocShell, "no SwDocShell");
255 uno::Reference<document::XDocumentProperties> xDocProps;
256 uno::Reference<beans::XPropertySet> xProps;
257 if (pDocShell) {
258 uno::Reference<lang::XComponent> xModelComp(pDocShell->GetModel(),
259 uno::UNO_QUERY);
260 xProps = uno::Reference<beans::XPropertySet>(xModelComp,
261 uno::UNO_QUERY);
262 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
263 xModelComp, uno::UNO_QUERY_THROW);
264 xDocProps = xDPS->getDocumentProperties();
265 OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
267 rDop.lKeyProtDoc = pDocShell->GetModifyPasswordHash();
270 if ((rWrt.pSepx && rWrt.pSepx->DocumentIsProtected()) ||
271 rDop.lKeyProtDoc != 0)
273 rDop.fProtEnabled = 1;
275 else
277 rDop.fProtEnabled = 0;
280 if (!xDocProps.is())
282 rDop.dttmCreated = rDop.dttmRevised = rDop.dttmLastPrint = 0x45FBAC69;
284 else
286 ::util::DateTime uDT = xDocProps->getCreationDate();
287 Date aD(uDT.Day, uDT.Month, uDT.Year);
288 Time aT(uDT.Hours, uDT.Minutes, uDT.Seconds, uDT.NanoSeconds);
289 rDop.dttmCreated = sw::ms::DateTime2DTTM(DateTime(aD,aT));
290 uDT = xDocProps->getModificationDate();
291 Date aD2(uDT.Day, uDT.Month, uDT.Year);
292 Time aT2(uDT.Hours, uDT.Minutes, uDT.Seconds, uDT.NanoSeconds);
293 rDop.dttmRevised = sw::ms::DateTime2DTTM(DateTime(aD2,aT2));
294 uDT = xDocProps->getPrintDate();
295 Date aD3(uDT.Day, uDT.Month, uDT.Year);
296 Time aT3(uDT.Hours, uDT.Minutes, uDT.Seconds, uDT.NanoSeconds);
297 rDop.dttmLastPrint = sw::ms::DateTime2DTTM(DateTime(aD3,aT3));
300 // Also, the DocStat fields in headers, footers are not calculated correctly.
301 // ( we do not have this fields! )
303 // and also for the Headers and Footers
304 rDop.cWordsFtnEnd = rDStat.nWord;
305 rDop.cChFtnEdn = rDStat.nChar;
306 rDop.cPgFtnEdn = (sal_Int16)rDStat.nPage;
307 rDop.cParasFtnEdn = rDStat.nPara;
308 rDop.cLinesFtnEdn = rDStat.nPara;
310 rDop.fDontUseHTMLAutoSpacing = (rWrt.pDoc->get(IDocumentSettingAccess::PARA_SPACE_MAX) != 0);
312 rDop.fExpShRtn = !rWrt.pDoc->get(IDocumentSettingAccess::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK); // #i56856#
314 rDop.Write( *rWrt.pTableStrm, *rWrt.pFib );
317 const sal_Unicode *WW8DopTypography::GetJapanNotBeginLevel1()
319 static const sal_Unicode aJapanNotBeginLevel1[nMaxFollowing] =
320 //Japanese Level 1
322 0x0021, 0x0025, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f,
323 0x005d, 0x007d, 0x00a2, 0x00b0, 0x2019, 0x201d, 0x2030, 0x2032,
324 0x2033, 0x2103, 0x3001, 0x3002, 0x3005, 0x3009, 0x300b, 0x300d,
325 0x300f, 0x3011, 0x3015, 0x309b, 0x309c, 0x309d, 0x309e, 0x30fb,
326 0x30fd, 0x30fe, 0xff01, 0xff05, 0xff09, 0xff0c, 0xff0e, 0xff1a,
327 0xff1b, 0xff1f, 0xff3d, 0xff5d, 0xff61, 0xff63, 0xff64, 0xff65,
328 0xff9e, 0xff9f, 0xffe0
330 return &aJapanNotBeginLevel1[0];
333 const sal_Unicode *WW8DopTypography::GetJapanNotEndLevel1()
335 static const sal_Unicode aJapanNotEndLevel1[nMaxLeading] =
336 //Japanese Level 1
338 0x0024, 0x0028, 0x005b, 0x005c, 0x007b, 0x00a3, 0x00a5, 0x2018,
339 0x201c, 0x3008, 0x300a, 0x300c, 0x300e, 0x3010, 0x3014, 0xff04,
340 0xff08, 0xff3b, 0xff5b, 0xff62, 0xffe1, 0xffe5
342 return &aJapanNotEndLevel1[0];
345 static int lcl_CmpBeginEndChars( const OUString& rSWStr,
346 const sal_Unicode* pMSStr, int nMSStrByteLen )
348 nMSStrByteLen /= sizeof( sal_Unicode );
349 if( nMSStrByteLen > rSWStr.getLength() )
350 nMSStrByteLen = rSWStr.getLength()+1;
351 nMSStrByteLen *= sizeof( sal_Unicode );
353 return memcmp( rSWStr.getStr(), pMSStr, nMSStrByteLen );
357 Converts the OOo Asian Typography into a best fit match for Microsoft
358 Asian typography. This structure is actually dumped to disk within the
359 Dop Writer. Assumption is that rTypo is cleared to 0 on entry
361 void WW8Export::ExportDopTypography(WW8DopTypography &rTypo)
363 static const sal_Unicode aLangNotBegin[4][WW8DopTypography::nMaxFollowing]=
365 //Japanese Level 1
367 0x0021, 0x0025, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f,
368 0x005d, 0x007d, 0x00a2, 0x00b0, 0x2019, 0x201d, 0x2030, 0x2032,
369 0x2033, 0x2103, 0x3001, 0x3002, 0x3005, 0x3009, 0x300b, 0x300d,
370 0x300f, 0x3011, 0x3015, 0x3041, 0x3043, 0x3045, 0x3047, 0x3049,
371 0x3063, 0x3083, 0x3085, 0x3087, 0x308e, 0x309b, 0x309c, 0x309d,
372 0x309e, 0x30a1, 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30c3, 0x30e3,
373 0x30e5, 0x30e7, 0x30ee, 0x30f5, 0x30f6, 0x30fb, 0x30fc, 0x30fd,
374 0x30fe, 0xff01, 0xff05, 0xff09, 0xff0c, 0xff0e, 0xff1a, 0xff1b,
375 0xff1f, 0xff3d, 0xff5d, 0xff61, 0xff63, 0xff64, 0xff65, 0xff67,
376 0xff68, 0xff69, 0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f,
377 0xff70, 0xff9e, 0xff9f, 0xffe0
379 //Simplified Chinese
381 0x0021, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f, 0x005d,
382 0x007d, 0x00a8, 0x00b7, 0x02c7, 0x02c9, 0x2015, 0x2016, 0x2019,
383 0x201d, 0x2026, 0x2236, 0x3001, 0x3002, 0x3003, 0x3005, 0x3009,
384 0x300b, 0x300d, 0x300f, 0x3011, 0x3015, 0x3017, 0xff01, 0xff02,
385 0xff07, 0xff09, 0xff0c, 0xff0e, 0xff1a, 0xff1b, 0xff1f, 0xff3d,
386 0xff40, 0xff5c, 0xff5d, 0xff5e, 0xffe0
388 //Korean
390 0x0021, 0x0025, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f,
391 0x005d, 0x007d, 0x00a2, 0x00b0, 0x2019, 0x201d, 0x2032, 0x2033,
392 0x2103, 0x3009, 0x300b, 0x300d, 0x300f, 0x3011, 0x3015, 0xff01,
393 0xff05, 0xff09, 0xff0c, 0xff0e, 0xff1a, 0xff1b, 0xff1f, 0xff3d,
394 0xff5d, 0xffe0
396 //Traditional Chinese
398 0x0021, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b, 0x003f, 0x005d,
399 0x007d, 0x00a2, 0x00b7, 0x2013, 0x2014, 0x2019, 0x201d, 0x2022,
400 0x2025, 0x2026, 0x2027, 0x2032, 0x2574, 0x3001, 0x3002, 0x3009,
401 0x300b, 0x300d, 0x300f, 0x3011, 0x3015, 0x301e, 0xfe30, 0xfe31,
402 0xfe33, 0xfe34, 0xfe36, 0xfe38, 0xfe3a, 0xfe3c, 0xfe3e, 0xfe40,
403 0xfe42, 0xfe44, 0xfe4f, 0xfe50, 0xfe51, 0xfe52, 0xfe54, 0xfe55,
404 0xfe56, 0xfe57, 0xfe5a, 0xfe5c, 0xfe5e, 0xff01, 0xff09, 0xff0c,
405 0xff0e, 0xff1a, 0xff1b, 0xff1f, 0xff5c, 0xff5d, 0xff64
409 static const sal_Unicode aLangNotEnd[4][WW8DopTypography::nMaxLeading] =
411 //Japanese Level 1
413 0x0024, 0x0028, 0x005b, 0x005c, 0x007b, 0x00a3, 0x00a5, 0x2018,
414 0x201c, 0x3008, 0x300a, 0x300c, 0x300e, 0x3010, 0x3014, 0xff04,
415 0xff08, 0xff3b, 0xff5b, 0xff62, 0xffe1, 0xffe5
417 //Simplified Chinese
419 0x0028, 0x005b, 0x007b, 0x00b7, 0x2018, 0x201c, 0x3008, 0x300a,
420 0x300c, 0x300e, 0x3010, 0x3014, 0x3016, 0xff08, 0xff0e, 0xff3b,
421 0xff5b, 0xffe1, 0xffe5
423 //Korean
425 0x0028, 0x005b, 0x005c, 0x007b, 0x00a3, 0x00a5, 0x2018, 0x201c,
426 0x3008, 0x300a, 0x300c, 0x300e, 0x3010, 0x3014, 0xff04, 0xff08,
427 0xff3b, 0xff5b, 0xffe6
429 //Traditional Chinese
431 0x0028, 0x005b, 0x007b, 0x00a3, 0x00a5, 0x2018, 0x201c, 0x2035,
432 0x3008, 0x300a, 0x300c, 0x300e, 0x3010, 0x3014, 0x301d, 0xfe35,
433 0xfe37, 0xfe39, 0xfe3b, 0xfe3d, 0xfe3f, 0xfe41, 0xfe43, 0xfe59,
434 0xfe5b, 0xfe5d, 0xff08, 0xff5b
438 const i18n::ForbiddenCharacters *pForbidden = 0;
439 const i18n::ForbiddenCharacters *pUseMe = 0;
440 sal_uInt8 nUseReserved=0;
441 int nNoNeeded=0;
443 Now we have some minor difficult issues, to wit...
444 a. MicroSoft Office can only store one set of begin and end characters in
445 a given document, not one per language.
446 b. StarOffice has only a concept of one set of begin and end characters for
447 a given language, i.e. not the two levels of kinsoku in japanese
449 What is unknown as yet is if our default begin and end chars for
450 japanese, chinese tradition, chinese simplified and korean are different
451 in Word and Writer. I already suspect that they are different between
452 different version of word itself.
454 So what have come up with is to simply see if any of the four languages
455 in OOo have been changed away from OUR defaults, and if one has then
456 export that. If more than one has in the future we may hack in something
457 which examines our document properties to see which language is used the
458 most and choose that, for now we choose the first and throw an ASSERT
461 /*Our default Japanese Level is 2, this is a special MS hack to set this*/
462 rTypo.reserved2 = 1;
464 for (rTypo.reserved1=8;rTypo.reserved1>0;rTypo.reserved1-=2)
466 if (0 != (pForbidden = pDoc->getForbiddenCharacters(rTypo.GetConvertedLang(),
467 false)))
469 int nIdx = (rTypo.reserved1-2)/2;
470 if( lcl_CmpBeginEndChars( pForbidden->endLine,
471 aLangNotEnd[ nIdx ], sizeof(aLangNotEnd[ nIdx ]) ) ||
472 lcl_CmpBeginEndChars( pForbidden->beginLine,
473 aLangNotBegin[ nIdx ], sizeof(aLangNotBegin[ nIdx ]) ) )
475 //One exception for Japanese, if it matches a level 1 we
476 //can use one extra flag for that, rather than use a custom
477 if (rTypo.GetConvertedLang() == LANGUAGE_JAPANESE)
479 if (
480 !lcl_CmpBeginEndChars
482 pForbidden->endLine,
483 rTypo.GetJapanNotEndLevel1(),
484 rTypo.nMaxLeading * sizeof(sal_Unicode)
487 !lcl_CmpBeginEndChars
489 pForbidden->beginLine,
490 rTypo.GetJapanNotBeginLevel1(),
491 rTypo.nMaxFollowing * sizeof(sal_Unicode)
495 rTypo.reserved2 = 0;
496 continue;
500 if (!pUseMe)
502 pUseMe = pForbidden;
503 nUseReserved = rTypo.reserved1;
504 rTypo.iLevelOfKinsoku = 2;
506 nNoNeeded++;
511 OSL_ENSURE( nNoNeeded<=1, "Example of unexportable forbidden chars" );
512 rTypo.reserved1=nUseReserved;
513 if (rTypo.iLevelOfKinsoku)
515 rTypo.cchFollowingPunct = msword_cast<sal_Int16>
516 (pUseMe->beginLine.getLength());
517 if (rTypo.cchFollowingPunct > WW8DopTypography::nMaxFollowing - 1)
518 rTypo.cchFollowingPunct = WW8DopTypography::nMaxFollowing - 1;
520 rTypo.cchLeadingPunct = msword_cast<sal_Int16>
521 (pUseMe->endLine.getLength());
522 if (rTypo.cchLeadingPunct > WW8DopTypography::nMaxLeading - 1)
523 rTypo.cchLeadingPunct = WW8DopTypography::nMaxLeading -1;
525 memcpy(rTypo.rgxchFPunct,pUseMe->beginLine.getStr(),
526 (rTypo.cchFollowingPunct+1)*2);
528 memcpy(rTypo.rgxchLPunct,pUseMe->endLine.getStr(),
529 (rTypo.cchLeadingPunct+1)*2);
532 const IDocumentSettingAccess* pIDocumentSettingAccess = GetWriter().getIDocumentSettingAccess();
534 rTypo.fKerningPunct = pIDocumentSettingAccess->get(IDocumentSettingAccess::KERN_ASIAN_PUNCTUATION);
535 rTypo.iJustification = pDoc->getCharacterCompressionType();
538 // It can only be found something with this method, if it is used within
539 // WW8_SwAttrIter::OutAttr() and WW8Export::OutputItemSet()
540 const SfxPoolItem* MSWordExportBase::HasItem( sal_uInt16 nWhich ) const
542 const SfxPoolItem* pItem=0;
543 if (pISet)
545 // if write a EditEngine text, then the WhichIds are greater as
546 // ourer own Ids. So the Id have to translate from our into the
547 // EditEngine Range
548 nWhich = sw::hack::GetSetWhichFromSwDocWhich(*pISet, *pDoc, nWhich);
549 if (nWhich && SFX_ITEM_SET != pISet->GetItemState(nWhich, true, &pItem))
550 pItem = 0;
552 else if( pChpIter )
553 pItem = pChpIter->HasTextItem( nWhich );
554 else
556 OSL_ENSURE( !this, "Where is my ItemSet / pChpIter ?" );
557 pItem = 0;
559 return pItem;
562 const SfxPoolItem& MSWordExportBase::GetItem(sal_uInt16 nWhich) const
564 const SfxPoolItem* pItem;
565 if (pISet)
567 // if write a EditEngine text, then the WhichIds are greater as
568 // ourer own Ids. So the Id have to translate from our into the
569 // EditEngine Range
570 nWhich = sw::hack::GetSetWhichFromSwDocWhich(*pISet, *pDoc, nWhich);
571 OSL_ENSURE(nWhich != 0, "All broken, Impossible");
572 pItem = &pISet->Get(nWhich, true);
574 else if( pChpIter )
575 pItem = &pChpIter->GetItem( nWhich );
576 else
578 OSL_ENSURE( !this, "Where is my ItemSet / pChpIter ?" );
579 pItem = 0;
581 return *pItem;
584 //------------------------------------------------------------------------------
586 WW8_WrPlc1::WW8_WrPlc1( sal_uInt16 nStructSz )
587 : nStructSiz( nStructSz )
589 nDataLen = 16 * nStructSz;
590 pData = new sal_uInt8[ nDataLen ];
593 WW8_WrPlc1::~WW8_WrPlc1()
595 delete[] pData;
598 WW8_CP WW8_WrPlc1::Prev() const
600 bool b = !aPos.empty();
601 OSL_ENSURE(b,"Prev called on empty list");
602 return b ? aPos.back() : 0;
605 void WW8_WrPlc1::Append( WW8_CP nCp, const void* pNewData )
607 sal_uLong nInsPos = aPos.size() * nStructSiz;
608 aPos.push_back( nCp );
609 if( nDataLen < nInsPos + nStructSiz )
611 sal_uInt8* pNew = new sal_uInt8[ 2 * nDataLen ];
612 memcpy( pNew, pData, nDataLen );
613 delete[] pData;
614 pData = pNew;
615 nDataLen *= 2;
617 memcpy( pData + nInsPos, pNewData, nStructSiz );
620 void WW8_WrPlc1::Finish( sal_uLong nLastCp, sal_uLong nSttCp )
622 if( !aPos.empty() )
624 aPos.push_back( nLastCp );
625 if( nSttCp )
626 for( sal_uInt32 n = 0; n < aPos.size(); ++n )
627 aPos[ n ] -= nSttCp;
632 void WW8_WrPlc1::Write( SvStream& rStrm )
634 sal_uInt32 i;
635 for( i = 0; i < aPos.size(); ++i )
636 SwWW8Writer::WriteLong( rStrm, aPos[i] );
637 if( i )
638 rStrm.Write( pData, (i-1) * nStructSiz );
642 // Class WW8_WrPlcFld for fields
644 bool WW8_WrPlcFld::Write( WW8Export& rWrt )
646 if( WW8_WrPlc1::Count() <= 1 )
647 return false;
649 WW8_FC *pfc;
650 sal_Int32 *plc;
651 switch (nTxtTyp)
653 case TXT_MAINTEXT:
654 pfc = &rWrt.pFib->fcPlcffldMom;
655 plc = &rWrt.pFib->lcbPlcffldMom;
656 break;
657 case TXT_HDFT:
658 pfc = &rWrt.pFib->fcPlcffldHdr;
659 plc = &rWrt.pFib->lcbPlcffldHdr;
660 break;
662 case TXT_FTN:
663 pfc = &rWrt.pFib->fcPlcffldFtn;
664 plc = &rWrt.pFib->lcbPlcffldFtn;
665 break;
667 case TXT_EDN:
668 pfc = &rWrt.pFib->fcPlcffldEdn;
669 plc = &rWrt.pFib->lcbPlcffldEdn;
670 break;
672 case TXT_ATN:
673 pfc = &rWrt.pFib->fcPlcffldAtn;
674 plc = &rWrt.pFib->lcbPlcffldAtn;
675 break;
677 case TXT_TXTBOX:
678 pfc = &rWrt.pFib->fcPlcffldTxbx;
679 plc = &rWrt.pFib->lcbPlcffldTxbx;
680 break;
682 case TXT_HFTXTBOX:
683 pfc = &rWrt.pFib->fcPlcffldHdrTxbx;
684 plc = &rWrt.pFib->lcbPlcffldHdrTxbx;
685 break;
687 default:
688 pfc = plc = 0;
689 break;
692 if( pfc && plc )
694 sal_uLong nFcStart = rWrt.pTableStrm->Tell();
695 WW8_WrPlc1::Write( *rWrt.pTableStrm );
696 *pfc = nFcStart;
697 *plc = rWrt.pTableStrm->Tell() - nFcStart;
699 return true;
702 bool WW8_WrMagicTable::Write( WW8Export& rWrt )
704 if( WW8_WrPlc1::Count() <= 1 )
705 return false;
706 sal_uLong nFcStart = rWrt.pTableStrm->Tell();
707 WW8_WrPlc1::Write( *rWrt.pTableStrm );
708 rWrt.pFib->fcPlcfTch = nFcStart;
709 rWrt.pFib->lcbPlcfTch = rWrt.pTableStrm->Tell() - nFcStart;
710 return true;
713 void WW8_WrMagicTable::Append( WW8_CP nCp, sal_uLong nData)
715 SVBT32 nLittle;
717 Tell the undocumented table hack that everything between here and the last
718 table position is nontable text, don't do it if the previous position is
719 the same as this one, as that would be a region of 0 length
721 if ((!Count()) || (Prev() != nCp))
723 UInt32ToSVBT32(nData,nLittle);
724 WW8_WrPlc1::Append(nCp, nLittle);
728 //--------------------------------------------------------------------------
730 void SwWW8Writer::FillCount( SvStream& rStrm, sal_uLong nCount )
732 static const sal_uInt32 aNulls[16] =
734 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 // 64 Byte
737 while (nCount > 64)
739 rStrm.Write( aNulls, 64 ); // in steps of 64-Byte
740 nCount -= 64;
742 rStrm.Write( aNulls, nCount ); // write the rest ( 0 .. 64 Bytes )
745 sal_uLong SwWW8Writer::FillUntil( SvStream& rStrm, sal_uLong nEndPos )
747 sal_uLong nCurPos = rStrm.Tell();
748 if( !nEndPos ) // nEndPos == 0 -> next Page
749 nEndPos = (nCurPos + 0x1ff) & ~0x1ffUL;
751 if( nEndPos > nCurPos )
752 SwWW8Writer::FillCount( rStrm, nEndPos - nCurPos );
753 #if OSL_DEBUG_LEVEL > 0
754 else
755 OSL_ENSURE( nEndPos == nCurPos, "Falsches FillUntil()" );
756 #endif
757 return rStrm.Tell();
761 //--------------------------------------------------------------------------
763 WW8_WrPlcPn::WW8_WrPlcPn( WW8Export& rWr, ePLCFT ePl, WW8_FC nStartFc )
764 : rWrt(rWr), nFkpStartPage(0), ePlc(ePl), nMark(0)
766 WW8_WrFkp* pF = new WW8_WrFkp( ePlc, nStartFc, rWrt.bWrtWW8 );
767 aFkps.push_back( pF );
770 WW8_WrPlcPn::~WW8_WrPlcPn()
774 sal_uInt8 *WW8_WrPlcPn::CopyLastSprms(sal_uInt8 &rLen)
776 WW8_WrFkp& rF = aFkps.back();
777 return rF.CopyLastSprms(rLen, rWrt.bWrtWW8);
780 void WW8_WrPlcPn::AppendFkpEntry(WW8_FC nEndFc,short nVarLen,const sal_uInt8* pSprms)
782 WW8_WrFkp* pF = &aFkps.back();
784 // big sprm? build the sprmPHugePapx
785 sal_uInt8* pNewSprms = (sal_uInt8*)pSprms;
786 sal_uInt8 aHugePapx[ 8 ];
787 if( rWrt.bWrtWW8 && PAP == ePlc && 488 < nVarLen )
789 sal_uInt8* p = aHugePapx;
790 *p++ = *pSprms++; // set style Id
791 *p++ = *pSprms++;
792 nVarLen -= 2;
794 long nDataPos = rWrt.pDataStrm->Tell();
795 SwWW8Writer::WriteShort( *rWrt.pDataStrm, nVarLen );
796 rWrt.pDataStrm->Write( pSprms, nVarLen );
798 Set_UInt16( p, 0x6646 ); // set SprmCode
799 Set_UInt32( p, nDataPos ); // set startpos (FC) in the datastream
800 nVarLen = static_cast< short >(p - aHugePapx);
801 pSprms = pNewSprms = aHugePapx;
803 // if append at the same FC-EndPos and there are sprms, then get the old
804 // sprms and erase it; they will append now with the new sprms
805 else if( nVarLen && pF->IsEqualPos( nEndFc ))
806 pF->MergeToNew( nVarLen, pNewSprms );
807 // has the prev EndFC an empty sprm and the current is empty too, then
808 // expand only the old EndFc to the new EndFc
809 else if( !nVarLen && pF->IsEmptySprm() )
811 pF->SetNewEnd( nEndFc );
812 return ;
815 bool bOk = pF->Append(nEndFc, nVarLen, pNewSprms);
816 if( !bOk )
818 pF->Combine();
819 pF = new WW8_WrFkp( ePlc, pF->GetEndFc(), rWrt.bWrtWW8 ); // Start new Fkp == end of old Fkp
821 aFkps.push_back( pF );
822 if( !pF->Append( nEndFc, nVarLen, pNewSprms ) )
824 OSL_ENSURE( !this, "Sprm liess sich nicht einfuegen" );
827 if( pNewSprms != pSprms ) //Merge to new has created a new block
828 delete[] pNewSprms;
831 void WW8_WrPlcPn::WriteFkps()
833 nFkpStartPage = (sal_uInt16) ( SwWW8Writer::FillUntil( rWrt.Strm() ) >> 9 );
835 for( sal_uInt16 i = 0; i < aFkps.size(); i++ )
836 aFkps[ i ].Write( rWrt.Strm(), *rWrt.pGrf );
838 if( CHP == ePlc )
840 rWrt.pFib->pnChpFirst = nFkpStartPage;
841 rWrt.pFib->cpnBteChp = aFkps.size();
843 else
845 rWrt.pFib->pnPapFirst = nFkpStartPage;
846 rWrt.pFib->cpnBtePap = aFkps.size();
850 void WW8_WrPlcPn::WritePlc()
852 sal_uLong nFcStart = rWrt.pTableStrm->Tell();
853 sal_uInt16 i;
855 for( i = 0; i < aFkps.size(); i++ )
856 SwWW8Writer::WriteLong( *rWrt.pTableStrm,
857 aFkps[ i ].GetStartFc() );
859 SwWW8Writer::WriteLong( *rWrt.pTableStrm,
860 aFkps[ i - 1 ].GetEndFc() );
862 // fuer jedes FKP die Page ausgeben
863 if( rWrt.bWrtWW8) // for WW97 Long output
864 for ( i = 0; i < aFkps.size(); i++)
865 SwWW8Writer::WriteLong( *rWrt.pTableStrm, i + nFkpStartPage );
866 else // for WW95 Short output
867 for ( i = 0; i < aFkps.size(); i++)
868 SwWW8Writer::WriteShort( *rWrt.pTableStrm, i + nFkpStartPage );
870 if( CHP == ePlc )
872 rWrt.pFib->fcPlcfbteChpx = nFcStart;
873 rWrt.pFib->lcbPlcfbteChpx = rWrt.pTableStrm->Tell() - nFcStart;
875 else
877 rWrt.pFib->fcPlcfbtePapx = nFcStart;
878 rWrt.pFib->lcbPlcfbtePapx = rWrt.pTableStrm->Tell() - nFcStart;
882 //--------------------------------------------------------------------------
884 WW8_WrFkp::WW8_WrFkp(ePLCFT ePl, WW8_FC nStartFc, bool bWrtWW8)
885 : ePlc(ePl), nStartGrp(511), nOldStartGrp(511),
886 nItemSize( ( CHP == ePl ) ? 1 : ( bWrtWW8 ? 13 : 7 )),
887 nIMax(0), nOldVarLen(0), bCombined(false)
889 pFkp = (sal_uInt8*)new sal_Int32[128]; // 512 Byte
890 pOfs = (sal_uInt8*)new sal_Int32[128]; // 512 Byte
891 memset( pFkp, 0, 4 * 128 );
892 memset( pOfs, 0, 4 * 128 );
893 ( (sal_Int32*)pFkp )[0] = nStartFc; // 0th entry FC at nStartFc
896 WW8_WrFkp::~WW8_WrFkp()
898 delete[] (sal_Int32 *)pFkp;
899 delete[] (sal_Int32 *)pOfs;
902 sal_uInt8 WW8_WrFkp::SearchSameSprm( sal_uInt16 nVarLen, const sal_uInt8* pSprms )
904 if( 3 < nVarLen )
906 // if the sprms contained picture-references then never equal!
907 for( sal_uInt8 n = static_cast< sal_uInt8 >(nVarLen - 1); 3 < n; --n )
908 if( pSprms[ n ] == GRF_MAGIC_3 &&
909 pSprms[ n-1 ] == GRF_MAGIC_2 &&
910 pSprms[ n-2 ] == GRF_MAGIC_1 )
911 return 0;
914 short i;
915 for( i = 0; i < nIMax; i++ )
917 sal_uInt8 nStart = pOfs[i * nItemSize];
918 if( nStart )
919 { // has Sprms
920 const sal_uInt8* p = pFkp + ( (sal_uInt16)nStart << 1 );
921 if( ( CHP == ePlc
922 ? (*p++ == nVarLen)
923 : (((sal_uInt16)*p++ << 1 ) == (( nVarLen+1) & 0xfffe)) )
924 && !memcmp( p, pSprms, nVarLen ) )
925 return nStart; // found it
928 return 0; // didn't found it
931 sal_uInt8 *WW8_WrFkp::CopyLastSprms(sal_uInt8 &rLen, bool bVer8)
933 rLen=0;
934 sal_uInt8 *pStart=0,*pRet=0;
936 if (!bCombined)
937 pStart = pOfs;
938 else
939 pStart = pFkp + ( nIMax + 1 ) * 4;
941 sal_uInt8 nStart = *(pStart + (nIMax-1) * nItemSize);
943 const sal_uInt8* p = pFkp + ( (sal_uInt16)nStart << 1 );
945 if (!*p && bVer8)
946 p++;
948 if (*p)
950 rLen = *p++;
951 if (PAP == ePlc)
952 rLen *= 2;
953 pRet = new sal_uInt8[rLen];
954 memcpy(pRet,p,rLen);
956 return pRet;
959 bool WW8_WrFkp::Append( WW8_FC nEndFc, sal_uInt16 nVarLen, const sal_uInt8* pSprms )
961 OSL_ENSURE( !nVarLen || pSprms, "Item pointer missing" );
962 OSL_ENSURE( nVarLen < ( ( ePlc == PAP ) ? 497U : 502U ), "Sprms too long !" );
964 if( bCombined )
966 OSL_ENSURE( !this, "Fkp::Append: Fkp is already combined" );
967 return false;
969 sal_Int32 n = ((sal_Int32*)pFkp)[nIMax]; // last entry
970 if( nEndFc <= n )
972 OSL_ENSURE( nEndFc >= n, "+Fkp: FC backwards" );
973 OSL_ENSURE( !nVarLen || !pSprms || nEndFc != n,
974 "+Fkp: selber FC mehrfach benutzt" );
975 // selber FC ohne Sprm wird ohne zu mosern ignoriert.
977 return true; // ignore (do not create a new Fkp)
980 sal_uInt8 nOldP = ( nVarLen ) ? SearchSameSprm( nVarLen, pSprms ) : 0;
981 // Combine equal entries
982 short nOffset=0, nPos = nStartGrp;
983 if (nVarLen && !nOldP)
985 nPos = PAP == ePlc
986 ? ( 13 == nItemSize // HACK: PAP and bWrtWW8 !!
987 ? (nStartGrp & 0xFFFE ) - nVarLen - 1
988 : (nStartGrp - (((nVarLen + 1) & 0xFFFE)+1)) & 0xFFFE )
989 : ((nStartGrp - nVarLen - 1) & 0xFFFE);
990 if( nPos < 0 )
991 return false; // doesn't fit at all
992 nOffset = nPos; // save offset (can also be uneven!)
993 nPos &= 0xFFFE; // Pos for Sprms ( gerade Pos )
996 if( (sal_uInt16)nPos <= ( nIMax + 2U ) * 4U + ( nIMax + 1U ) * nItemSize )
997 // does it fits behind the CPs and offsets?
998 return false; // no
1000 ((sal_Int32*)pFkp)[nIMax + 1] = nEndFc; // insert FC
1002 nOldVarLen = (sal_uInt8)nVarLen;
1003 if( nVarLen && !nOldP )
1004 { // insert it for real
1005 nOldStartGrp = nStartGrp;
1007 nStartGrp = nPos;
1008 pOfs[nIMax * nItemSize] = (sal_uInt8)( nStartGrp >> 1 );
1009 // ( DatenAnfg >> 1 ) insert
1010 sal_uInt8 nCnt = static_cast< sal_uInt8 >(CHP == ePlc
1011 ? ( nVarLen < 256 ) ? (sal_uInt8) nVarLen : 255
1012 : ( ( nVarLen + 1 ) >> 1 ));
1014 pFkp[ nOffset ] = nCnt; // Enter data length
1015 memcpy( pFkp + nOffset + 1, pSprms, nVarLen ); // store Sprms
1017 else
1019 // do not enter for real ( no Sprms or recurrence )
1020 // DatenAnfg 0 ( no data ) or recurrence
1021 pOfs[nIMax * nItemSize] = nOldP;
1023 nIMax++;
1024 return true;
1027 bool WW8_WrFkp::Combine()
1029 if( bCombined )
1030 return false;
1031 if( nIMax )
1032 memcpy( pFkp + ( nIMax + 1 ) * 4, pOfs, nIMax * nItemSize );
1033 delete[] pOfs;
1034 pOfs = 0;
1035 ((sal_uInt8*)pFkp)[511] = nIMax;
1036 bCombined = true;
1038 #if defined OSL_BIGENDIAN // only the FCs will be rotated here
1039 sal_uInt16 i; // the Sprms must be rotated elsewhere
1041 sal_uInt32* p;
1042 for( i = 0, p = (sal_uInt32*)pFkp; i <= nIMax; i++, p++ )
1043 *p = OSL_SWAPDWORD( *p );
1044 #endif // ifdef OSL_BIGENDIAN
1046 return true;
1049 void WW8_WrFkp::Write( SvStream& rStrm, SwWW8WrGrf& rGrf )
1051 Combine(); // If not already combined
1053 sal_uInt8* p; // Suche Magic fuer nPicLocFc
1054 sal_uInt8* pEnd = pFkp + nStartGrp;
1055 for( p = pFkp + 511 - 4; p >= pEnd; p-- )
1057 if( *p != GRF_MAGIC_1 ) // search for signature 0x12 0x34 0x56 0xXX
1058 continue;
1059 if( *(p+1) != GRF_MAGIC_2 )
1060 continue;
1061 if( *(p+2) != GRF_MAGIC_3 )
1062 continue;
1064 SVBT32 nPos; // signature found
1065 UInt32ToSVBT32( rGrf.GetFPos(), nPos ); // FilePos the graphics
1066 memcpy( p, nPos, 4 ); // patch FilePos over the signature
1068 rStrm.Write( pFkp, 512 );
1071 void WW8_WrFkp::MergeToNew( short& rVarLen, sal_uInt8 *& rpNewSprms )
1073 sal_uInt8 nStart = pOfs[ (nIMax-1) * nItemSize ];
1074 if( nStart )
1075 { // has Sprms
1076 sal_uInt8* p = pFkp + ( (sal_uInt16)nStart << 1 );
1078 // old and new equal? Then copy only one into the new sprms
1079 if( nOldVarLen == rVarLen && !memcmp( p+1, rpNewSprms, nOldVarLen ))
1081 sal_uInt8* pNew = new sal_uInt8[ nOldVarLen ];
1082 memcpy( pNew, p+1, nOldVarLen );
1083 rpNewSprms = pNew;
1085 else
1087 sal_uInt8* pNew = new sal_uInt8[ nOldVarLen + rVarLen ];
1088 memcpy( pNew, p+1, nOldVarLen );
1089 memcpy( pNew + nOldVarLen, rpNewSprms, rVarLen );
1091 rpNewSprms = pNew;
1092 rVarLen = rVarLen + nOldVarLen;
1094 --nIMax;
1095 // if this sprms dont used from others, remove it
1096 bool bFnd = false;
1097 for (sal_uInt16 n = 0; n < nIMax; ++n)
1099 if (nStart == pOfs[n * nItemSize])
1101 bFnd = true;
1102 break;
1105 if (!bFnd)
1107 nStartGrp = nOldStartGrp;
1108 memset( p, 0, nOldVarLen+1 );
1113 #ifdef __WW8_NEEDS_COPY
1115 WW8_FC WW8_WrFkp::GetStartFc() const
1117 // wenn bCombined, dann ist das Array ab pFkp schon Bytemaessig auf LittleEndian
1118 // umgedreht, d.h. zum Herausholen der Anfangs- und Endpositionen muss
1119 // zurueckgedreht werden.
1120 if( bCombined )
1121 return SVBT32ToUInt32( pFkp ); // 0. Element
1122 return ((sal_Int32*)pFkp)[0];
1125 WW8_FC WW8_WrFkp::GetEndFc() const
1127 if( bCombined )
1128 return SVBT32ToUInt32( &(pFkp[nIMax*4]) ); // nIMax-tes SVBT32-Element
1129 return ((sal_Int32*)pFkp)[nIMax];
1132 #endif // defined __WW8_NEEDS_COPY
1135 // Method for managing the piece table
1136 WW8_WrPct::WW8_WrPct(WW8_FC nfcMin, bool bSaveUniCode)
1137 : nOldFc(nfcMin), bIsUni(bSaveUniCode)
1139 AppendPc( nOldFc, bIsUni );
1142 WW8_WrPct::~WW8_WrPct()
1146 // Fill the piece and create a new one
1147 void WW8_WrPct::AppendPc(WW8_FC nStartFc, bool bIsUnicode)
1149 WW8_CP nStartCp = nStartFc - nOldFc; // substract the beginning of the text
1150 if ( !nStartCp )
1152 if ( !aPcts.empty() )
1154 OSL_ENSURE( 1 == aPcts.size(), "Leeres Piece !!");
1155 aPcts.pop_back( );
1159 nOldFc = nStartFc; // remember StartFc as old
1161 if( bIsUni )
1162 nStartCp >>= 1; // for Unicode: number of characters / 2
1165 if ( !bIsUnicode )
1167 nStartFc <<= 1; // Adress * 2
1168 nStartFc |= 0x40000000; // second last bit for non-Unicode
1171 if( !aPcts.empty() )
1172 nStartCp += aPcts.back().GetStartCp();
1174 WW8_WrPc* pPc = new WW8_WrPc( nStartFc, nStartCp );
1175 aPcts.push_back( pPc );
1177 bIsUni = bIsUnicode;
1181 void WW8_WrPct::WritePc( WW8Export& rWrt )
1183 sal_uLong nPctStart;
1184 sal_uLong nOldPos, nEndPos;
1185 boost::ptr_vector<WW8_WrPc>::iterator aIter;
1187 nPctStart = rWrt.pTableStrm->Tell(); // Start piece table
1188 *rWrt.pTableStrm << ( char )0x02; // Status byte PCT
1189 nOldPos = nPctStart + 1; // remember Position
1190 SwWW8Writer::WriteLong( *rWrt.pTableStrm, 0 ); // then the length
1192 for( aIter = aPcts.begin(); aIter != aPcts.end(); ++aIter ) // ranges
1193 SwWW8Writer::WriteLong( *rWrt.pTableStrm,
1194 aIter->GetStartCp() );
1197 // calculate the last Pos
1198 sal_uLong nStartCp = rWrt.pFib->fcMac - nOldFc;
1199 if( bIsUni )
1200 nStartCp >>= 1; // For Unicode: number of characters / 2
1201 nStartCp += aPcts.back().GetStartCp();
1202 SwWW8Writer::WriteLong( *rWrt.pTableStrm, nStartCp );
1204 // piece references
1205 for ( aIter = aPcts.begin(); aIter != aPcts.end(); ++aIter )
1207 SwWW8Writer::WriteShort( *rWrt.pTableStrm, aIter->GetStatus());
1208 SwWW8Writer::WriteLong( *rWrt.pTableStrm, aIter->GetStartFc());
1209 SwWW8Writer::WriteShort( *rWrt.pTableStrm, 0); // PRM=0
1212 // entries in the FIB
1213 rWrt.pFib->fcClx = nPctStart;
1214 nEndPos = rWrt.pTableStrm->Tell();
1215 rWrt.pFib->lcbClx = nEndPos - nPctStart;
1217 // and register the length as well
1218 SwWW8Writer::WriteLong( *rWrt.pTableStrm, nOldPos,
1219 nEndPos - nPctStart-5 );
1223 void WW8_WrPct::SetParaBreak()
1225 OSL_ENSURE( !aPcts.empty(),"SetParaBreak : aPcts.empty()" );
1226 aPcts.back().SetStatus();
1229 WW8_CP WW8_WrPct::Fc2Cp( sal_uLong nFc ) const
1231 OSL_ENSURE( nFc >= (sal_uLong)nOldFc, "FilePos lies in front of last piece" );
1232 OSL_ENSURE( ! aPcts.empty(), "Fc2Cp no piece available" );
1234 nFc -= nOldFc;
1235 if( bIsUni )
1236 nFc /= 2;
1237 return nFc + aPcts.back().GetStartCp();
1240 //--------------------------------------------------------------------------
1242 WW8_WrtBookmarks::WW8_WrtBookmarks()
1246 WW8_WrtBookmarks::~WW8_WrtBookmarks()
1250 void WW8_WrtBookmarks::Append( WW8_CP nStartCp, const String& rNm, const ::sw::mark::IMark* )
1252 BkmIter bkIter = GetPos( rNm );
1253 if( bkIter == aBookmarks.end() )
1255 // new bookmark -> insert with start==end
1256 aBookmarks.push_back( BookmarkInfo(nStartCp, nStartCp, false, rNm) );
1258 else
1260 // old bookmark -> this should be the end position
1261 OSL_ENSURE( bkIter->endPos == bkIter->startPos, "end position is valid" );
1263 //If this bookmark was around a field in writer, then we want to move
1264 //it to the field result in word. The end is therefore one cp
1265 //backwards from the 0x15 end mark that was inserted.
1266 if (bkIter->isField)
1267 --nStartCp;
1268 bkIter->endPos = nStartCp;
1273 void WW8_WrtBookmarks::Write( WW8Export& rWrt )
1275 if (!aBookmarks.empty())
1277 //Make sure the bookmarks are sorted in order of start position.
1278 std::sort(aBookmarks.begin(), aBookmarks.end());
1280 // First write the Bookmark Name Stringtable
1281 std::vector<OUString> aNames;
1282 aNames.reserve(aBookmarks.size());
1283 for (BkmIter bIt = aBookmarks.begin(); bIt < aBookmarks.end(); ++bIt)
1284 aNames.push_back(bIt->name);
1285 rWrt.WriteAsStringTable(aNames, rWrt.pFib->fcSttbfbkmk, rWrt.pFib->lcbSttbfbkmk);
1287 // Second write the Bookmark start positions as pcf of longs
1288 SvStream& rStrm = rWrt.bWrtWW8 ? *rWrt.pTableStrm : rWrt.Strm();
1289 rWrt.pFib->fcPlcfbkf = rStrm.Tell();
1290 for (BkmIter bIt = aBookmarks.begin(); bIt < aBookmarks.end(); ++bIt)
1291 SwWW8Writer::WriteLong( rStrm, bIt->startPos );
1292 SwWW8Writer::WriteLong(rStrm, rWrt.pFib->ccpText + rWrt.pFib->ccpTxbx);
1294 //Lastly, need to write out the end positions (sorted by end position). But
1295 //before that we need a lookup table (sorted by start position) to link
1296 //start and end positions.
1297 // Start by sorting the end positions.
1298 std::vector<sal_uLong> aEndSortTab;
1299 aEndSortTab.reserve(aBookmarks.size());
1300 for (BkmIter bIt = aBookmarks.begin(); bIt < aBookmarks.end(); ++bIt)
1301 aEndSortTab.push_back(bIt->endPos);
1302 std::sort(aEndSortTab.begin(), aEndSortTab.end());
1304 //Now write out the lookups.
1305 //Note that in most cases, the positions in both vectors will be very close.
1306 for( sal_uLong i = 0; i < aBookmarks.size(); ++i )
1308 sal_uLong nEndCP = aBookmarks[ i ].endPos;
1309 sal_uInt16 nPos = i;
1310 if( aEndSortTab[ nPos ] > nEndCP )
1312 while( aEndSortTab[ --nPos ] != nEndCP )
1315 else if( aEndSortTab[ nPos ] < nEndCP )
1316 while( aEndSortTab[ ++nPos ] != nEndCP )
1318 SwWW8Writer::WriteLong( rStrm, nPos );
1320 rWrt.pFib->lcbPlcfbkf = rStrm.Tell() - rWrt.pFib->fcPlcfbkf;
1322 // Finally, the actual Bookmark end positions.
1323 rWrt.pFib->fcPlcfbkl = rStrm.Tell();
1324 for(sal_uLong i = 0; i < aEndSortTab.size(); ++i )
1325 SwWW8Writer::WriteLong( rStrm, aEndSortTab[ i ] );
1326 SwWW8Writer::WriteLong(rStrm, rWrt.pFib->ccpText + rWrt.pFib->ccpTxbx);
1327 rWrt.pFib->lcbPlcfbkl = rStrm.Tell() - rWrt.pFib->fcPlcfbkl;
1331 WW8_WrtBookmarks::BkmIter WW8_WrtBookmarks::GetPos( const String& rNm )
1333 for (BkmIter bIt = aBookmarks.begin(); bIt < aBookmarks.end(); ++bIt) {
1334 if (rNm == bIt->name)
1335 return bIt;
1337 return aBookmarks.end();
1340 void WW8_WrtBookmarks::MoveFieldMarks(sal_uLong nFrom, sal_uLong nTo)
1342 for (BkmIter i = aBookmarks.begin(); i < aBookmarks.end(); ++i)
1344 if (i->startPos == nFrom)
1346 i->startPos = nTo;
1347 if (i->endPos == nFrom)
1349 i->isField = true;
1350 i->endPos = nTo;
1356 void WW8Export::AppendBookmarks( const SwTxtNode& rNd,
1357 xub_StrLen nAktPos, xub_StrLen nLen )
1359 std::vector< const ::sw::mark::IMark* > aArr;
1360 sal_uInt16 nCntnt;
1361 xub_StrLen nAktEnd = nAktPos + nLen;
1362 if( GetWriter().GetBookmarks( rNd, nAktPos, nAktEnd, aArr ))
1364 sal_uLong nNd = rNd.GetIndex(), nSttCP = Fc2Cp( Strm().Tell() );
1365 for( sal_uInt16 n = 0; n < aArr.size(); ++n )
1367 const ::sw::mark::IMark& rBkmk = *(aArr[ n ]);
1368 if(dynamic_cast< const ::sw::mark::IFieldmark *>(&rBkmk))
1369 continue;
1371 const SwPosition* pPos = &rBkmk.GetMarkPos();
1372 const SwPosition* pOPos = 0;
1373 if(rBkmk.IsExpanded())
1374 pOPos = &rBkmk.GetOtherMarkPos();
1375 if( pOPos && pOPos->nNode == pPos->nNode &&
1376 pOPos->nContent < pPos->nContent )
1378 pPos = pOPos;
1379 pOPos = &rBkmk.GetMarkPos();
1382 if( !pOPos || ( nNd == pPos->nNode.GetIndex() &&
1383 ( nCntnt = pPos->nContent.GetIndex() ) >= nAktPos &&
1384 nCntnt < nAktEnd ) )
1386 sal_uLong nCp = nSttCP + pPos->nContent.GetIndex() - nAktPos;
1387 pBkmks->Append(nCp, BookmarkToWord(rBkmk.GetName()), &rBkmk);
1389 if( pOPos && nNd == pOPos->nNode.GetIndex() &&
1390 ( nCntnt = pOPos->nContent.GetIndex() ) >= nAktPos &&
1391 nCntnt < nAktEnd )
1393 sal_uLong nCp = nSttCP + pOPos->nContent.GetIndex() - nAktPos;
1394 pBkmks->Append(nCp, BookmarkToWord(rBkmk.GetName()), &rBkmk);
1400 void WW8Export::MoveFieldMarks(sal_uLong nFrom, sal_uLong nTo)
1402 pBkmks->MoveFieldMarks(nFrom, nTo);
1405 void WW8Export::AppendBookmark( const OUString& rName, bool bSkip )
1407 sal_uLong nSttCP = Fc2Cp( Strm().Tell() ) + ( bSkip? 1: 0 );
1408 pBkmks->Append( nSttCP, rName );
1411 // #i120928 collect all the graphics of bullets applied to paragraphs
1412 int MSWordExportBase::CollectGrfsOfBullets()
1414 m_vecBulletPic.clear();
1416 if ( pDoc )
1418 int nCountRule = pDoc->GetNumRuleTbl().size();
1419 for (int n = 0; n < nCountRule; ++n)
1421 const SwNumRule &rRule = *( pDoc->GetNumRuleTbl().at(n) );
1422 sal_uInt16 nLevels = rRule.IsContinusNum() ? 1 : 9;
1423 for (sal_uInt16 nLvl = 0; nLvl < nLevels; ++nLvl)
1425 const SwNumFmt &rFmt = rRule.Get(nLvl);
1426 if (SVX_NUM_BITMAP != rFmt.GetNumberingType())
1428 continue;
1430 const Graphic *pGraf = rFmt.GetBrush()? rFmt.GetBrush()->GetGraphic():0;
1431 if ( pGraf )
1433 bool bHas = false;
1434 for (unsigned i = 0; i < m_vecBulletPic.size(); ++i)
1436 if (m_vecBulletPic[i]->GetChecksum() == pGraf->GetChecksum())
1438 bHas = true;
1439 break;
1442 if (!bHas)
1444 m_vecBulletPic.push_back(pGraf);
1451 return m_vecBulletPic.size();
1454 void MSWordExportBase::BulletDefinitions()
1456 for (size_t i = 0; i < m_vecBulletPic.size(); ++i)
1458 const MapMode aMapMode(MAP_TWIP);
1459 const Graphic& rGraphic = *m_vecBulletPic[i];
1460 Size aSize(rGraphic.GetPrefSize());
1461 if (MAP_PIXEL == rGraphic.GetPrefMapMode().GetMapUnit())
1462 aSize = Application::GetDefaultDevice()->PixelToLogic(aSize, aMapMode);
1463 else
1464 aSize = OutputDevice::LogicToLogic(aSize,rGraphic.GetPrefMapMode(), aMapMode);
1465 AttrOutput().BulletDefinition(i, rGraphic, aSize);
1469 //Export Graphic of Bullets
1470 void WW8Export::ExportGrfBullet(const SwTxtNode& rNd)
1472 int nCount = CollectGrfsOfBullets();
1473 if (nCount > 0)
1475 SwPosition aPos(rNd);
1476 OUString aPicBullets("_PictureBullets");
1477 AppendBookmark(aPicBullets);
1478 for (int i = 0; i < nCount; i++)
1480 sw::Frame aFrame(*(m_vecBulletPic[i]), aPos);
1481 OutGrfBullets(aFrame);
1483 AppendBookmark(aPicBullets);
1487 static sal_uInt8 nAttrMagicIdx = 0;
1488 void WW8Export::OutGrfBullets(const sw::Frame & rFrame)
1490 if ( !pGrf || !pChpPlc || !pO )
1491 return;
1493 pGrf->Insert(rFrame);
1494 pChpPlc->AppendFkpEntry( Strm().Tell(), pO->size(), pO->data() );
1495 pO->clear();
1496 //if links...
1497 WriteChar( (char)1 );
1499 sal_uInt8 aArr[ 22 ];
1500 sal_uInt8* pArr = aArr;
1502 // sprmCFSpec
1503 if( bWrtWW8 )
1504 Set_UInt16( pArr, 0x855 );
1505 else
1506 Set_UInt8( pArr, 117 );
1507 Set_UInt8( pArr, 1 );
1509 Set_UInt16( pArr, 0x083c );
1510 Set_UInt8( pArr, 0x81 );
1512 // sprmCPicLocation
1513 if( bWrtWW8 )
1514 Set_UInt16( pArr, 0x6a03 );
1515 else
1517 Set_UInt8( pArr, 68 );
1518 Set_UInt8( pArr, 4 );
1520 Set_UInt32( pArr, GRF_MAGIC_321 );
1522 //extern nAttrMagicIdx;
1523 --pArr;
1524 Set_UInt8( pArr, nAttrMagicIdx++ );
1525 pChpPlc->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr - aArr), aArr );
1528 int MSWordExportBase::GetGrfIndex(const SvxBrushItem& rBrush)
1530 int nIndex = -1;
1531 if ( rBrush.GetGraphic() )
1533 for (unsigned i = 0; i < m_vecBulletPic.size(); ++i)
1535 if (m_vecBulletPic[i]->GetChecksum() == rBrush.GetGraphic()->GetChecksum())
1537 nIndex = i;
1538 break;
1543 return nIndex;
1546 void MSWordExportBase::AppendWordBookmark( const String& rName )
1548 AppendBookmark( BookmarkToWord( rName ) );
1552 //--------------------------------------------------------------------------
1554 void WW8_WrtRedlineAuthor::Write( Writer& rWrt )
1556 WW8Export & rWW8Wrt = *(((SwWW8Writer&)rWrt).m_pExport);
1557 rWW8Wrt.WriteAsStringTable(maAuthors, rWW8Wrt.pFib->fcSttbfRMark,
1558 rWW8Wrt.pFib->lcbSttbfRMark, rWW8Wrt.bWrtWW8 ? 0 : 2);
1561 sal_uInt16 WW8Export::AddRedlineAuthor( sal_uInt16 nId )
1563 if( !pRedlAuthors )
1565 pRedlAuthors = new WW8_WrtRedlineAuthor;
1566 pRedlAuthors->AddName(OUString("Unknown"));
1568 return pRedlAuthors->AddName( SW_MOD()->GetRedlineAuthor( nId ) );
1571 //--------------------------------------------------------------------------
1573 void WW8Export::WriteAsStringTable(const std::vector<OUString>& rStrings,
1574 sal_Int32& rfcSttbf, sal_Int32& rlcbSttbf, sal_uInt16 nExtraLen)
1576 sal_uInt16 n, nCount = static_cast< sal_uInt16 >(rStrings.size());
1577 if( nCount )
1579 // we have some Redlines found in the document -> the
1580 // Author Name Stringtable
1581 SvStream& rStrm = bWrtWW8 ? *pTableStrm : Strm();
1582 rfcSttbf = rStrm.Tell();
1583 if( bWrtWW8 )
1585 SwWW8Writer::WriteShort( rStrm, -1 );
1586 SwWW8Writer::WriteLong( rStrm, nCount );
1587 for( n = 0; n < nCount; ++n )
1589 const String& rNm = rStrings[n];
1590 SwWW8Writer::WriteShort( rStrm, rNm.Len() );
1591 SwWW8Writer::WriteString16(rStrm, rNm, false);
1592 if( nExtraLen )
1593 SwWW8Writer::FillCount(rStrm, nExtraLen);
1596 else
1598 SwWW8Writer::WriteShort( rStrm, 0 );
1599 for( n = 0; n < nCount; ++n )
1601 const OUString &rString = rStrings[n];
1602 const String aNm(rString.copy(0, std::min<sal_Int32>(rString.getLength(), 255)));
1603 rStrm << (sal_uInt8)aNm.Len();
1604 SwWW8Writer::WriteString8(rStrm, aNm, false,
1605 RTL_TEXTENCODING_MS_1252);
1606 if (nExtraLen)
1607 SwWW8Writer::FillCount(rStrm, nExtraLen);
1610 rlcbSttbf = rStrm.Tell() - rfcSttbf;
1611 if( !bWrtWW8 )
1612 SwWW8Writer::WriteShort( rStrm, rfcSttbf, (sal_uInt16)rlcbSttbf );
1616 // WriteShort() traegt an FilePos nPos den Wert nVal ein und seekt auf die
1617 // alte FilePos zurueck. Benutzt zum Nachtragen von Laengen.
1618 void SwWW8Writer::WriteShort( SvStream& rStrm, sal_uLong nPos, sal_Int16 nVal )
1620 sal_uLong nOldPos = rStrm.Tell(); // remember Pos
1621 rStrm.Seek( nPos );
1622 SwWW8Writer::WriteShort( rStrm, nVal );
1623 rStrm.Seek( nOldPos );
1626 void SwWW8Writer::WriteLong( SvStream& rStrm, sal_uLong nPos, sal_Int32 nVal )
1628 sal_uLong nOldPos = rStrm.Tell(); // remember Pos
1629 rStrm.Seek( nPos );
1630 SwWW8Writer::WriteLong( rStrm, nVal );
1631 rStrm.Seek( nOldPos );
1634 void SwWW8Writer::InsUInt16(ww::bytes &rO, sal_uInt16 n)
1636 SVBT16 nL;
1637 ShortToSVBT16( n, nL );
1638 rO.push_back(nL[0]);
1639 rO.push_back(nL[1]);
1642 void SwWW8Writer::InsUInt32(ww::bytes &rO, sal_uInt32 n)
1644 SVBT32 nL;
1645 UInt32ToSVBT32( n, nL );
1646 rO.push_back(nL[0]);
1647 rO.push_back(nL[1]);
1648 rO.push_back(nL[2]);
1649 rO.push_back(nL[3]);
1652 void SwWW8Writer::InsAsString16(ww::bytes &rO, const String& rStr)
1654 const sal_Unicode* pStr = rStr.GetBuffer();
1655 for( xub_StrLen n = 0, nLen = rStr.Len(); n < nLen; ++n, ++pStr )
1656 SwWW8Writer::InsUInt16( rO, *pStr );
1659 void SwWW8Writer::InsAsString8(ww::bytes &rO, const String& rStr,
1660 rtl_TextEncoding eCodeSet)
1662 OString sTmp(OUStringToOString(rStr, eCodeSet));
1663 const sal_Char *pStart = sTmp.getStr();
1664 const sal_Char *pEnd = pStart + sTmp.getLength();
1665 rO.reserve(rO.size() + sTmp.getLength());
1667 std::copy(pStart, pEnd, std::inserter(rO, rO.end()));
1670 void SwWW8Writer::WriteString16(SvStream& rStrm, const String& rStr,
1671 bool bAddZero)
1673 ww::bytes aBytes;
1674 SwWW8Writer::InsAsString16(aBytes, rStr);
1675 if (bAddZero)
1676 SwWW8Writer::InsUInt16(aBytes, 0);
1677 //vectors are guaranteed to have contiguous memory, so we can do
1678 //this while migrating away from WW8Bytes. Meyers Effective STL, item 16
1679 if (!aBytes.empty())
1680 rStrm.Write(&aBytes[0], aBytes.size());
1683 void SwWW8Writer::WriteString_xstz(SvStream& rStrm, const String& rStr, bool bAddZero)
1685 ww::bytes aBytes;
1686 SwWW8Writer::InsUInt16(aBytes, rStr.Len());
1687 SwWW8Writer::InsAsString16(aBytes, rStr);
1688 if (bAddZero)
1689 SwWW8Writer::InsUInt16(aBytes, 0);
1690 rStrm.Write(&aBytes[0], aBytes.size());
1694 void SwWW8Writer::WriteString8(SvStream& rStrm, const String& rStr,
1695 bool bAddZero, rtl_TextEncoding eCodeSet)
1697 ww::bytes aBytes;
1698 SwWW8Writer::InsAsString8(aBytes, rStr, eCodeSet);
1699 if (bAddZero)
1700 aBytes.push_back(0);
1701 //vectors are guaranteed to have contiguous memory, so we can do
1702 ////this while migrating away from WW8Bytes. Meyers Effective STL, item 16
1703 if (!aBytes.empty())
1704 rStrm.Write(&aBytes[0], aBytes.size());
1707 void WW8Export::WriteStringAsPara( const String& rTxt, sal_uInt16 nStyleId )
1709 if( rTxt.Len() )
1710 OutSwString( rTxt, 0, rTxt.Len(), IsUnicode(), RTL_TEXTENCODING_MS_1252 );
1711 WriteCR(); // CR thereafter
1713 ww::bytes aArr;
1714 SwWW8Writer::InsUInt16( aArr, nStyleId );
1715 if( bOutTable )
1716 { // Tab-Attr
1717 // sprmPFInTable
1718 if( bWrtWW8 )
1719 SwWW8Writer::InsUInt16( aArr, NS_sprm::LN_PFInTable );
1720 else
1721 aArr.push_back( 24 );
1722 aArr.push_back( 1 );
1725 sal_uLong nPos = Strm().Tell();
1726 pPapPlc->AppendFkpEntry( nPos, aArr.size(), aArr.data() );
1727 pChpPlc->AppendFkpEntry( nPos );
1730 void MSWordExportBase::WriteSpecialText( sal_uLong nStart, sal_uLong nEnd, sal_uInt8 nTTyp )
1732 sal_uInt8 nOldTyp = nTxtTyp;
1733 nTxtTyp = nTTyp;
1734 SwPaM* pOldPam = pCurPam; //!! Simply shifting the PaM without restoring should do the job too
1735 SwPaM* pOldEnd = pOrigPam;
1736 bool bOldPageDescs = bOutPageDescs;
1737 bOutPageDescs = false;
1738 // bOutKF was setted / stored in WriteKF1
1739 pCurPam = Writer::NewSwPaM( *pDoc, nStart, nEnd );
1741 // Tabelle in Sonderbereichen erkennen
1742 if ( ( nStart != pCurPam->GetMark()->nNode.GetIndex() ) &&
1743 pDoc->GetNodes()[ nStart ]->IsTableNode() )
1745 pCurPam->GetMark()->nNode = nStart;
1748 pOrigPam = pCurPam;
1749 pCurPam->Exchange();
1751 WriteText();
1753 bOutPageDescs = bOldPageDescs;
1754 delete pCurPam; // delete Pam
1755 pCurPam = pOldPam;
1756 pOrigPam = pOldEnd;
1757 nTxtTyp = nOldTyp;
1760 void WW8Export::OutSwString(const String& rStr, xub_StrLen nStt,
1761 xub_StrLen nLen, bool bUnicode, rtl_TextEncoding eChrSet)
1764 SAL_INFO( "sw.ww8.level2", "<OutSwString>" );
1766 if( nLen )
1768 if ( bUnicode != pPiece->IsUnicode() )
1769 pPiece->AppendPc ( Strm().Tell(), bUnicode );
1771 if( nStt || nLen != rStr.Len() )
1773 String sOut( rStr.Copy( nStt, nLen ) );
1775 SAL_INFO( "sw.ww8.level2", sOut );
1777 if (bUnicode)
1778 SwWW8Writer::WriteString16(Strm(), sOut, false);
1779 else
1780 SwWW8Writer::WriteString8(Strm(), sOut, false, eChrSet);
1782 else
1784 SAL_INFO( "sw.ww8.level2", rStr );
1786 if (bUnicode)
1787 SwWW8Writer::WriteString16(Strm(), rStr, false);
1788 else
1789 SwWW8Writer::WriteString8(Strm(), rStr, false, eChrSet);
1793 SAL_INFO( "sw.ww8.level2", "</OutSwString>" );
1796 void WW8Export::WriteCR(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
1798 if (pTableTextNodeInfoInner.get() != NULL && pTableTextNodeInfoInner->getDepth() == 1 && pTableTextNodeInfoInner->isEndOfCell())
1799 WriteChar('\007');
1800 else
1801 WriteChar( '\015' );
1803 pPiece->SetParaBreak();
1806 void WW8Export::WriteChar( sal_Unicode c )
1808 if( pPiece->IsUnicode() )
1809 Strm() << c;
1810 else
1811 Strm() << (sal_uInt8)c;
1814 void MSWordExportBase::SaveData( sal_uLong nStt, sal_uLong nEnd )
1816 MSWordSaveData aData;
1818 // WW8Export only stuff - zeroed here not to issue warnings
1819 aData.pOOld = NULL;
1821 // Common stuff
1822 aData.pOldPam = pCurPam;
1823 aData.pOldEnd = pOrigPam;
1824 aData.pOldFlyFmt = mpParentFrame;
1825 aData.pOldPageDesc = pAktPageDesc;
1827 aData.pOldFlyOffset = pFlyOffset;
1828 aData.eOldAnchorType = eNewAnchorType;
1830 aData.bOldOutTable = bOutTable;
1831 aData.bOldFlyFrmAttrs = bOutFlyFrmAttrs;
1832 aData.bOldStartTOX = bStartTOX;
1833 aData.bOldInWriteTOX = bInWriteTOX;
1835 pCurPam = Writer::NewSwPaM( *pDoc, nStt, nEnd );
1837 // Recognize tables in special cases
1838 if ( nStt != pCurPam->GetMark()->nNode.GetIndex() &&
1839 pDoc->GetNodes()[ nStt ]->IsTableNode() )
1841 pCurPam->GetMark()->nNode = nStt;
1844 pOrigPam = pCurPam;
1845 pCurPam->Exchange();
1847 bOutTable = false;
1848 // Caution: bIsInTable should not be set here
1849 bOutFlyFrmAttrs = false;
1850 bStartTOX = false;
1851 bInWriteTOX = false;
1853 maSaveData.push( aData );
1856 void MSWordExportBase::RestoreData()
1858 MSWordSaveData &rData = maSaveData.top();
1860 delete pCurPam;
1861 pCurPam = rData.pOldPam;
1862 pOrigPam = rData.pOldEnd;
1864 bOutTable = rData.bOldOutTable;
1865 bOutFlyFrmAttrs = rData.bOldFlyFrmAttrs;
1866 bStartTOX = rData.bOldStartTOX;
1867 bInWriteTOX = rData.bOldInWriteTOX;
1869 mpParentFrame = rData.pOldFlyFmt;
1870 pAktPageDesc = rData.pOldPageDesc;
1872 eNewAnchorType = rData.eOldAnchorType;
1873 pFlyOffset = rData.pOldFlyOffset;
1875 maSaveData.pop();
1878 void WW8Export::SaveData( sal_uLong nStt, sal_uLong nEnd )
1880 MSWordExportBase::SaveData( nStt, nEnd );
1882 MSWordSaveData &rData = maSaveData.top();
1884 if ( !pO->empty() )
1886 rData.pOOld = pO;
1887 pO = new ww::bytes();
1889 else
1890 rData.pOOld = 0; // reuse pO
1892 rData.bOldWriteAll = GetWriter().bWriteAll;
1893 GetWriter().bWriteAll = true;
1896 void WW8Export::RestoreData()
1898 MSWordSaveData &rData = maSaveData.top();
1900 GetWriter().bWriteAll = rData.bOldWriteAll;
1902 OSL_ENSURE( pO->empty(), "pO is not empty in WW8Export::RestoreData()" );
1903 if ( rData.pOOld )
1905 delete pO;
1906 pO = rData.pOOld;
1909 MSWordExportBase::RestoreData();
1912 void WW8AttributeOutput::TableInfoCell( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
1914 sal_uInt32 nDepth = pTableTextNodeInfoInner->getDepth();
1916 if ( nDepth > 0 )
1918 /* Cell */
1919 m_rWW8Export.InsUInt16( NS_sprm::LN_PFInTable );
1920 m_rWW8Export.pO->push_back( (sal_uInt8)0x1 );
1921 m_rWW8Export.InsUInt16( NS_sprm::LN_PTableDepth );
1922 m_rWW8Export.InsUInt32( nDepth );
1924 if ( nDepth > 1 && pTableTextNodeInfoInner->isEndOfCell() )
1926 m_rWW8Export.InsUInt16( NS_sprm::LN_PCell );
1927 m_rWW8Export.pO->push_back( (sal_uInt8)0x1 );
1932 void WW8AttributeOutput::TableInfoRow( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
1934 sal_uInt32 nDepth = pTableTextNodeInfoInner->getDepth();
1936 if ( nDepth > 0 )
1938 /* Row */
1939 if ( pTableTextNodeInfoInner->isEndOfLine() )
1941 m_rWW8Export.InsUInt16( NS_sprm::LN_PFInTable );
1942 m_rWW8Export.pO->push_back( (sal_uInt8)0x1 );
1944 if ( nDepth == 1 )
1946 m_rWW8Export.InsUInt16( NS_sprm::LN_PFTtp );
1947 m_rWW8Export.pO->push_back( (sal_uInt8)0x1 );
1950 m_rWW8Export.InsUInt16( NS_sprm::LN_PTableDepth );
1951 m_rWW8Export.InsUInt32( nDepth );
1953 if ( nDepth > 1 )
1955 m_rWW8Export.InsUInt16( NS_sprm::LN_PCell );
1956 m_rWW8Export.pO->push_back( (sal_uInt8)0x1 );
1957 m_rWW8Export.InsUInt16( NS_sprm::LN_PRow );
1958 m_rWW8Export.pO->push_back( (sal_uInt8)0x1 );
1961 TableDefinition( pTableTextNodeInfoInner );
1962 TableHeight( pTableTextNodeInfoInner );
1963 TableBackgrounds( pTableTextNodeInfoInner );
1964 TableDefaultBorders( pTableTextNodeInfoInner );
1965 TableCanSplit( pTableTextNodeInfoInner );
1966 TableBidi( pTableTextNodeInfoInner );
1967 TableVerticalCell( pTableTextNodeInfoInner );
1968 TableOrientation( pTableTextNodeInfoInner );
1969 TableSpacing( pTableTextNodeInfoInner );
1974 static sal_uInt16 lcl_TCFlags(SwDoc &rDoc, const SwTableBox * pBox, sal_Int32 nRowSpan)
1976 sal_uInt16 nFlags = 0;
1978 if (nRowSpan > 1)
1979 nFlags |= (3 << 5);
1980 else if (nRowSpan < 0)
1981 nFlags |= (1 << 5);
1983 if (pBox != NULL)
1985 const SwFrmFmt * pFmt = pBox->GetFrmFmt();
1986 switch (pFmt->GetVertOrient().GetVertOrient())
1988 case text::VertOrientation::CENTER:
1989 nFlags |= (1 << 7);
1990 break;
1991 case text::VertOrientation::BOTTOM:
1992 nFlags |= (2 << 7);
1993 break;
1994 default:
1995 break;
1997 const SwStartNode * pSttNd = pBox->GetSttNd();
1998 if(pSttNd)
2000 SwNodeIndex aIdx( *pSttNd );
2001 const SwCntntNode * pCNd = pSttNd->GetNodes().GoNext( &aIdx );
2002 if( pCNd && pCNd->IsTxtNode())
2004 SfxItemSet aCoreSet(rDoc.GetAttrPool(), RES_CHRATR_ROTATE, RES_CHRATR_ROTATE);
2005 ((SwTxtNode*)pCNd)->GetAttr( aCoreSet, 0, ((SwTxtNode*)pCNd)->GetTxt().getLength());
2006 const SvxCharRotateItem * pRotate = NULL;
2007 const SfxPoolItem * pRotItem;
2008 if ( SFX_ITEM_SET == aCoreSet.GetItemState(RES_CHRATR_ROTATE, sal_True, &pRotItem))
2010 pRotate = (SvxCharRotateItem*)pRotItem;
2011 if(pRotate && pRotate->GetValue() == 900)
2013 nFlags = nFlags | 0x0004 | 0x0008;
2015 else if(pRotate && pRotate->GetValue() == 2700 )
2017 nFlags = nFlags | 0x0004 | 0x0010;
2024 return nFlags;
2027 void WW8AttributeOutput::TableVerticalCell( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2029 const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
2030 const SwTableLine * pTabLine = pTabBox->GetUpper();
2031 const SwTableBoxes & rTblBoxes = pTabLine->GetTabBoxes();
2033 sal_uInt8 nBoxes = rTblBoxes.size();
2034 for ( sal_uInt8 n = 0; n < nBoxes; n++ )
2036 const SwTableBox * pTabBox1 = rTblBoxes[n];
2037 const SwFrmFmt * pFrmFmt = pTabBox1->GetFrmFmt();
2039 if ( FRMDIR_VERT_TOP_RIGHT == m_rWW8Export.TrueFrameDirection( *pFrmFmt ) )
2041 m_rWW8Export.InsUInt16( NS_sprm::LN_TTextFlow );
2042 m_rWW8Export.pO->push_back( sal_uInt8(n) ); //start range
2043 m_rWW8Export.pO->push_back( sal_uInt8(n + 1) ); //end range
2044 m_rWW8Export.InsUInt16( 5 ); //Equals vertical writing
2049 void WW8AttributeOutput::TableCanSplit( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2051 const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
2052 const SwTableLine * pTabLine = pTabBox->GetUpper();
2053 const SwFrmFmt * pLineFmt = pTabLine->GetFrmFmt();
2056 By default the row can be split in word, and now in writer we have a
2057 feature equivalent to this, Word stores 1 for fCantSplit if the row
2058 cannot be split, we set true if we can split it. An example is #i4569#
2061 const SwFmtRowSplit& rSplittable = pLineFmt->GetRowSplit();
2062 sal_uInt8 nCantSplit = (!rSplittable.GetValue()) ? 1 : 0;
2063 if ( m_rWW8Export.bWrtWW8 )
2065 m_rWW8Export.InsUInt16( NS_sprm::LN_TFCantSplit );
2066 m_rWW8Export.pO->push_back( nCantSplit );
2067 m_rWW8Export.InsUInt16( NS_sprm::LN_TFCantSplit90 ); // also write fCantSplit90
2069 else
2071 m_rWW8Export.pO->push_back( 185 );
2073 m_rWW8Export.pO->push_back( nCantSplit );
2076 void WW8AttributeOutput::TableBidi( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2078 const SwTable * pTable = pTableTextNodeInfoInner->getTable();
2079 const SwFrmFmt * pFrmFmt = pTable->GetFrmFmt();
2081 if ( m_rWW8Export.bWrtWW8 )
2083 if ( m_rWW8Export.TrueFrameDirection(*pFrmFmt) == FRMDIR_HORI_RIGHT_TOP )
2085 m_rWW8Export.InsUInt16( NS_sprm::LN_TFBiDi );
2086 m_rWW8Export.InsUInt16( 1 );
2091 void WW8AttributeOutput::TableHeight( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2093 const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
2094 const SwTableLine * pTabLine = pTabBox->GetUpper();
2095 const SwFrmFmt * pLineFmt = pTabLine->GetFrmFmt();
2097 // Zeilenhoehe ausgeben sprmTDyaRowHeight
2098 long nHeight = 0;
2099 const SwFmtFrmSize& rLSz = pLineFmt->GetFrmSize();
2100 if ( ATT_VAR_SIZE != rLSz.GetHeightSizeType() && rLSz.GetHeight() )
2102 if ( ATT_MIN_SIZE == rLSz.GetHeightSizeType() )
2103 nHeight = rLSz.GetHeight();
2104 else
2105 nHeight = -rLSz.GetHeight();
2108 if ( nHeight )
2110 if ( m_rWW8Export.bWrtWW8 )
2111 m_rWW8Export.InsUInt16( NS_sprm::LN_TDyaRowHeight );
2112 else
2113 m_rWW8Export.pO->push_back( 189 );
2114 m_rWW8Export.InsUInt16( (sal_uInt16)nHeight );
2119 void WW8AttributeOutput::TableOrientation( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2121 const SwTable * pTable = pTableTextNodeInfoInner->getTable();
2123 const SwFrmFmt *pFmt = pTable->GetFrmFmt();
2124 OSL_ENSURE(pFmt,"Impossible");
2125 if (!pFmt)
2126 return;
2128 const SwFmtHoriOrient &rHori = pFmt->GetHoriOrient();
2129 const SwFmtVertOrient &rVert = pFmt->GetVertOrient();
2131 if (
2132 (text::RelOrientation::PRINT_AREA == rHori.GetRelationOrient() ||
2133 text::RelOrientation::FRAME == rHori.GetRelationOrient())
2135 (text::RelOrientation::PRINT_AREA == rVert.GetRelationOrient() ||
2136 text::RelOrientation::FRAME == rVert.GetRelationOrient())
2139 sal_Int16 eHOri = rHori.GetHoriOrient();
2140 switch (eHOri)
2142 case text::HoriOrientation::CENTER:
2143 case text::HoriOrientation::RIGHT:
2144 if ( m_rWW8Export.bWrtWW8 )
2145 m_rWW8Export.InsUInt16( NS_sprm::LN_TJc );
2146 else
2147 m_rWW8Export.pO->push_back( 182 );
2148 m_rWW8Export.InsUInt16( text::HoriOrientation::RIGHT == eHOri ? 2 : 1 );
2149 break;
2150 default:
2151 break;
2156 void WW8AttributeOutput::TableSpacing(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
2158 const SwTable * pTable = pTableTextNodeInfoInner->getTable();
2159 const SwTableFmt * pTableFmt = pTable->GetTableFmt();
2161 // Writing these SPRM's will make the table a floating one, so only write
2162 // them in case the table is already inside a frame.
2163 if (pTableFmt != NULL && pTable->GetTableNode()->GetFlyFmt())
2165 const SvxULSpaceItem & rUL = pTableFmt->GetULSpace();
2167 if (rUL.GetUpper() > 0)
2169 sal_uInt8 nPadding = 2;
2170 sal_uInt8 nPcVert = 0;
2171 sal_uInt8 nPcHorz = 0;
2173 sal_uInt8 nTPc = (nPadding << 4) | (nPcVert << 2) | nPcHorz;
2175 m_rWW8Export.InsUInt16(NS_sprm::LN_TPc);
2176 m_rWW8Export.pO->push_back( nTPc );
2178 m_rWW8Export.InsUInt16(NS_sprm::LN_TDyaAbs);
2179 m_rWW8Export.InsUInt16(rUL.GetUpper());
2181 m_rWW8Export.InsUInt16(NS_sprm::LN_TDyaFromText);
2182 m_rWW8Export.InsUInt16(rUL.GetUpper());
2185 if (rUL.GetLower() > 0)
2187 m_rWW8Export.InsUInt16(NS_sprm::LN_TDyaFromTextBottom);
2188 m_rWW8Export.InsUInt16(rUL.GetLower());
2193 void WW8AttributeOutput::TableDefinition( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2195 const SwTable * pTable = pTableTextNodeInfoInner->getTable();
2197 if ( pTable->GetRowsToRepeat() > pTableTextNodeInfoInner->getRow() )
2199 if( m_rWW8Export.bWrtWW8 )
2200 m_rWW8Export.InsUInt16( NS_sprm::LN_TTableHeader );
2201 else
2202 m_rWW8Export.pO->push_back( 186 );
2203 m_rWW8Export.pO->push_back( 1 );
2206 ww8::TableBoxVectorPtr pTableBoxes =
2207 pTableTextNodeInfoInner->getTableBoxesOfRow();
2208 // number of cell written
2209 sal_uInt32 nBoxes = pTableBoxes->size();
2210 if (nBoxes > ww8::MAXTABLECELLS)
2211 nBoxes = ww8::MAXTABLECELLS;
2213 // sprm header
2214 m_rWW8Export.InsUInt16( NS_sprm::LN_TDefTable );
2215 sal_uInt16 nSprmSize = 2 + (nBoxes + 1) * 2 + nBoxes * 20;
2216 m_rWW8Export.InsUInt16( nSprmSize ); // length
2218 // number of boxes
2219 m_rWW8Export.pO->push_back( static_cast<sal_uInt8>(nBoxes) );
2221 /* cellxs */
2223 ALWAYS relative when text::HoriOrientation::NONE (nPageSize + ( nPageSize / 10 )) < nTblSz,
2224 in that case the cell width's and table width's are not real. The table
2225 width is maxed and cells relative, so we need the frame (generally page)
2226 width that the table is in to work out the true widths.
2228 //const bool bNewTableModel = pTbl->IsNewModel();
2229 const SwFrmFmt *pFmt = pTable->GetFrmFmt();
2230 OSL_ENSURE(pFmt,"Impossible");
2231 if (!pFmt)
2232 return;
2234 const SwFmtHoriOrient &rHori = pFmt->GetHoriOrient();
2235 const SwFmtVertOrient &rVert = pFmt->GetVertOrient();
2237 sal_uInt16 nTblOffset = 0;
2239 if (
2240 (text::RelOrientation::PRINT_AREA == rHori.GetRelationOrient() ||
2241 text::RelOrientation::FRAME == rHori.GetRelationOrient())
2243 (text::RelOrientation::PRINT_AREA == rVert.GetRelationOrient() ||
2244 text::RelOrientation::FRAME == rVert.GetRelationOrient())
2247 sal_Int16 eHOri = rHori.GetHoriOrient();
2248 switch ( eHOri )
2250 case text::HoriOrientation::CENTER:
2251 case text::HoriOrientation::RIGHT:
2252 break;
2254 default:
2255 nTblOffset = rHori.GetPos();
2256 const SvxLRSpaceItem& rLRSp = pFmt->GetLRSpace();
2257 nTblOffset += rLRSp.GetLeft();
2258 break;
2262 m_rWW8Export.InsUInt16( nTblOffset );
2264 ww8::GridColsPtr pGridCols = GetGridCols( pTableTextNodeInfoInner );
2265 for ( ww8::GridCols::const_iterator it = pGridCols->begin(),
2266 end = pGridCols->end(); it != end; ++it )
2268 m_rWW8Export.InsUInt16( static_cast<sal_uInt16>( *it ) + nTblOffset );
2271 /* TCs */
2272 ww8::RowSpansPtr pRowSpans = pTableTextNodeInfoInner->getRowSpansOfRow();
2273 ww8::RowSpans::const_iterator aItRowSpans = pRowSpans->begin();
2274 ww8::TableBoxVector::const_iterator aIt;
2275 ww8::TableBoxVector::const_iterator aItEnd = pTableBoxes->end();
2277 #if OSL_DEBUG_LEVEL > 1
2278 size_t nRowSpans = pRowSpans->size();
2279 size_t nTableBoxes = pTableBoxes->size();
2280 (void) nRowSpans;
2281 (void) nTableBoxes;
2282 #endif
2284 for( aIt = pTableBoxes->begin(); aIt != aItEnd; ++aIt, ++aItRowSpans)
2286 sal_uInt16 npOCount = m_rWW8Export.pO->size();
2288 const SwTableBox * pTabBox1 = *aIt;
2289 const SwFrmFmt * pBoxFmt = NULL;
2290 if (pTabBox1 != NULL)
2291 pBoxFmt = pTabBox1->GetFrmFmt();
2293 if ( m_rWW8Export.bWrtWW8 )
2295 sal_uInt16 nFlags =
2296 lcl_TCFlags(*m_rWW8Export.pDoc, pTabBox1, *aItRowSpans);
2297 m_rWW8Export.InsUInt16( nFlags );
2300 static sal_uInt8 aNullBytes[] = { 0x0, 0x0 };
2302 m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), aNullBytes, aNullBytes+2 ); // dummy
2303 if (pBoxFmt != NULL)
2305 const SvxBoxItem & rBoxItem = pBoxFmt->GetBox();
2307 m_rWW8Export.Out_SwFmtTableBox( *m_rWW8Export.pO, &rBoxItem ); // 8/16 Byte
2309 else
2310 m_rWW8Export.Out_SwFmtTableBox( *m_rWW8Export.pO, NULL); // 8/16 Byte
2312 SAL_INFO( "sw.ww8.level2", "<tclength>" << ( m_rWW8Export.pO->size() - npOCount ) << "</tclength>" );
2316 ww8::GridColsPtr AttributeOutputBase::GetGridCols( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2318 return pTableTextNodeInfoInner->getGridColsOfRow(*this);
2321 void AttributeOutputBase::GetTablePageSize( ww8::WW8TableNodeInfoInner * pTableTextNodeInfoInner, sal_uInt32& rPageSize, bool& rRelBoxSize )
2323 sal_uInt32 nPageSize = 0;
2325 const SwNode *pTxtNd = pTableTextNodeInfoInner->getNode( );
2326 const SwTable *pTable = pTableTextNodeInfoInner->getTable( );
2328 const SwFrmFmt *pFmt = pTable->GetFrmFmt();
2329 OSL_ENSURE(pFmt,"Impossible");
2330 if (!pFmt)
2331 return;
2333 const SwFmtFrmSize &rSize = pFmt->GetFrmSize();
2334 int nWidthPercent = rSize.GetWidthPercent();
2335 bool bManualAligned = pFmt->GetHoriOrient().GetHoriOrient() == text::HoriOrientation::NONE;
2336 if ( (pFmt->GetHoriOrient().GetHoriOrient() == text::HoriOrientation::FULL) || bManualAligned )
2337 nWidthPercent = 100;
2338 bool bRelBoxSize = nWidthPercent != 0;
2339 unsigned long nTblSz = static_cast<unsigned long>(rSize.GetWidth());
2340 if (nTblSz > USHRT_MAX/2 && !bRelBoxSize)
2342 OSL_ENSURE(bRelBoxSize, "huge table width but not relative, suspicious");
2343 bRelBoxSize = true;
2346 if ( bRelBoxSize )
2348 Point aPt;
2349 SwRect aRect( pFmt->FindLayoutRect( false, &aPt ) );
2350 if ( aRect.IsEmpty() )
2352 // dann besorge mal die Seitenbreite ohne Raender !!
2353 const SwFrmFmt* pParentFmt =
2354 GetExport().mpParentFrame ?
2355 &(GetExport().mpParentFrame->GetFrmFmt()) :
2356 GetExport().pDoc->GetPageDesc(0).GetPageFmtOfNode(*pTxtNd, false);
2357 aRect = pParentFmt->FindLayoutRect(true);
2358 if ( 0 == ( nPageSize = aRect.Width() ) )
2360 const SvxLRSpaceItem& rLR = pParentFmt->GetLRSpace();
2361 nPageSize = pParentFmt->GetFrmSize().GetWidth() - rLR.GetLeft()
2362 - rLR.GetRight();
2365 else
2367 nPageSize = aRect.Width();
2368 if ( bManualAligned )
2370 // #i37571# For manually aligned tables
2371 const SvxLRSpaceItem &rLR = pFmt->GetLRSpace();
2372 nPageSize -= (rLR.GetLeft() + rLR.GetRight());
2377 OSL_ENSURE(nWidthPercent, "Impossible");
2378 if (nWidthPercent)
2380 nPageSize *= nWidthPercent;
2381 nPageSize /= 100;
2385 rPageSize = nPageSize;
2386 rRelBoxSize = bRelBoxSize;
2389 void WW8AttributeOutput::TableDefaultBorders( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2391 const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
2392 const SwFrmFmt * pFrmFmt = pTabBox->GetFrmFmt();
2394 //Set Default, just taken from the first cell of the first
2395 //row
2396 static sal_uInt16 aBorders[] =
2398 BOX_LINE_TOP, BOX_LINE_LEFT,
2399 BOX_LINE_BOTTOM, BOX_LINE_RIGHT
2402 for ( int i = 0; i < 4; ++i )
2404 SwWW8Writer::InsUInt16( *m_rWW8Export.pO, 0xD634 );
2405 m_rWW8Export.pO->push_back( sal_uInt8(6) );
2406 m_rWW8Export.pO->push_back( sal_uInt8(0) );
2407 m_rWW8Export.pO->push_back( sal_uInt8(1) );
2408 m_rWW8Export.pO->push_back( sal_uInt8(1 << i) );
2409 m_rWW8Export.pO->push_back( sal_uInt8(3) );
2411 SwWW8Writer::InsUInt16( *m_rWW8Export.pO,
2412 pFrmFmt->GetBox().GetDistance( aBorders[i] ) );
2416 void WW8AttributeOutput::TableBackgrounds( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2418 const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
2419 const SwTableLine * pTabLine = pTabBox->GetUpper();
2420 const SwTableBoxes & rTabBoxes = pTabLine->GetTabBoxes();
2422 sal_uInt8 nBoxes = rTabBoxes.size();
2423 if ( m_rWW8Export.bWrtWW8 )
2424 m_rWW8Export.InsUInt16( NS_sprm::LN_TDefTableShd );
2425 else
2426 m_rWW8Export.pO->push_back( (sal_uInt8)191 );
2427 m_rWW8Export.pO->push_back( (sal_uInt8)(nBoxes * 2) ); // Len
2429 for ( sal_uInt8 n = 0; n < nBoxes; n++ )
2431 const SwTableBox * pBox1 = rTabBoxes[n];
2432 const SwFrmFmt * pFrmFmt = pBox1->GetFrmFmt();
2433 const SfxPoolItem * pI = NULL;
2434 Color aColor;
2436 if ( SFX_ITEM_ON == pFrmFmt->GetAttrSet().GetItemState( RES_BACKGROUND, false, &pI ) )
2438 aColor = dynamic_cast<const SvxBrushItem *>(pI)->GetColor();
2440 else
2441 aColor = COL_AUTO;
2443 WW8_SHD aShd;
2444 m_rWW8Export.TransBrush( aColor, aShd );
2445 m_rWW8Export.InsUInt16( aShd.GetValue() );
2448 if ( m_rWW8Export.bWrtWW8 )
2450 sal_uInt32 aSprmIds[] = {NS_sprm::LN_TCellShd, NS_sprm::LN_TCellShadow};
2451 sal_uInt8 nBoxes0 = rTabBoxes.size();
2452 if (nBoxes0 > 21)
2453 nBoxes0 = 21;
2455 for (sal_uInt32 m = 0; m < 2; m++)
2457 m_rWW8Export.InsUInt16( aSprmIds[m] );
2458 m_rWW8Export.pO->push_back( static_cast<sal_uInt8>(nBoxes0 * 10) );
2460 for ( sal_uInt8 n = 0; n < nBoxes0; n++ )
2462 const SwTableBox * pBox1 = rTabBoxes[n];
2463 const SwFrmFmt * pFrmFmt = pBox1->GetFrmFmt();
2464 const SfxPoolItem * pI = NULL;
2465 Color aColor;
2467 if ( SFX_ITEM_ON ==
2468 pFrmFmt->GetAttrSet().
2469 GetItemState( RES_BACKGROUND, false, &pI ) )
2471 aColor = dynamic_cast<const SvxBrushItem *>(pI)->GetColor();
2473 else
2474 aColor = COL_AUTO;
2476 WW8SHDLong aSHD;
2477 aSHD.setCvFore( 0xFF000000 );
2479 sal_uInt32 nBgColor = aColor.GetColor();
2480 if ( nBgColor == COL_AUTO )
2481 aSHD.setCvBack( 0xFF000000 );
2482 else
2483 aSHD.setCvBack( wwUtility::RGBToBGR( nBgColor ) );
2485 aSHD.Write( m_rWW8Export );
2491 void WW8Export::SectionBreaksAndFrames( const SwTxtNode& rNode )
2493 // output page/section breaks
2494 OutputSectionBreaks( rNode.GetpSwAttrSet(), rNode );
2496 // all textframes anchored as character for the winword 7- format
2497 if ( !bWrtWW8 && !IsInTable() )
2498 OutWW6FlyFrmsInCntnt( rNode );
2501 void MSWordExportBase::WriteText()
2503 while( pCurPam->GetPoint()->nNode < pCurPam->GetMark()->nNode ||
2504 ( pCurPam->GetPoint()->nNode == pCurPam->GetMark()->nNode &&
2505 pCurPam->GetPoint()->nContent.GetIndex() <= pCurPam->GetMark()->nContent.GetIndex() ) )
2507 SwNode * pNd = pCurPam->GetNode();
2509 if ( pNd->IsTxtNode() )
2510 SectionBreaksAndFrames( *pNd->GetTxtNode() );
2512 // output the various types of nodes
2513 if ( pNd->IsCntntNode() )
2515 SwCntntNode* pCNd = (SwCntntNode*)pNd;
2517 const SwPageDesc* pTemp = pCNd->GetSwAttrSet().GetPageDesc().GetPageDesc();
2518 if ( pTemp )
2519 pAktPageDesc = pTemp;
2521 pCurPam->GetPoint()->nContent.Assign( pCNd, 0 );
2522 OutputContentNode( *pCNd );
2524 else if ( pNd->IsTableNode() )
2526 mpTableInfo->processSwTable( &pNd->GetTableNode()->GetTable() );
2528 else if ( pNd->IsSectionNode() && TXT_MAINTEXT == nTxtTyp )
2529 OutputSectionNode( *pNd->GetSectionNode() );
2530 else if ( TXT_MAINTEXT == nTxtTyp && pNd->IsEndNode() &&
2531 pNd->StartOfSectionNode()->IsSectionNode() )
2533 const SwSection& rSect = pNd->StartOfSectionNode()->GetSectionNode()
2534 ->GetSection();
2535 if ( bStartTOX && TOX_CONTENT_SECTION == rSect.GetType() )
2536 bStartTOX = false;
2538 SwNodeIndex aIdx( *pNd, 1 );
2539 if ( aIdx.GetNode().IsEndNode() && aIdx.GetNode().StartOfSectionNode()->IsSectionNode() )
2541 else if ( aIdx.GetNode().IsSectionNode() )
2543 else if ( !IsInTable() ) //No sections in table
2545 //#120140# Do not need to insert a page/section break after a section end. Check this case first
2546 sal_Bool bNeedExportBreakHere = sal_True;
2547 if ( aIdx.GetNode().IsTxtNode() )
2549 SwTxtNode *pTempNext = aIdx.GetNode().GetTxtNode();
2550 if ( pTempNext )
2552 const SfxPoolItem * pTempItem = NULL;
2553 if (pTempNext->GetpSwAttrSet() && SFX_ITEM_SET == pTempNext->GetpSwAttrSet()->GetItemState(RES_PAGEDESC, false, &pTempItem)
2554 && pTempItem && ((SwFmtPageDesc*)pTempItem)->GetRegisteredIn())
2556 //Next node has a new page style which means this node is a section end. Do not insert another page/section break here
2557 bNeedExportBreakHere = sal_False;
2561 if (bNeedExportBreakHere) //#120140# End of check
2563 ReplaceCr( (char)0xc ); // indicator for Page/Section-Break
2565 const SwSectionFmt* pParentFmt = rSect.GetFmt()->GetParent();
2566 if ( !pParentFmt )
2567 pParentFmt = (SwSectionFmt*)0xFFFFFFFF;
2569 sal_uLong nRstLnNum;
2570 if ( aIdx.GetNode().IsCntntNode() )
2571 nRstLnNum = ((SwCntntNode&)aIdx.GetNode()).GetSwAttrSet().
2572 GetLineNumber().GetStartValue();
2573 else
2574 nRstLnNum = 0;
2576 AppendSection( pAktPageDesc, pParentFmt, nRstLnNum );
2580 else if ( pNd->IsStartNode() )
2582 OutputStartNode( *pNd->GetStartNode() );
2584 else if ( pNd->IsEndNode() )
2586 OutputEndNode( *pNd->GetEndNode() );
2589 if ( pNd == &pNd->GetNodes().GetEndOfContent() )
2590 break;
2592 SwNode * pCurrentNode = &pCurPam->GetPoint()->nNode.GetNode();
2593 const SwNode * pNextNode = mpTableInfo->getNextNode(pCurrentNode);
2595 if (pNextNode != NULL)
2596 pCurPam->GetPoint()->nNode = SwNodeIndex(*pNextNode);
2597 else
2598 pCurPam->GetPoint()->nNode++;
2600 sal_uLong nPos = pCurPam->GetPoint()->nNode.GetIndex();
2601 ::SetProgressState( nPos, pCurPam->GetDoc()->GetDocShell() );
2604 SAL_INFO( "sw.ww8.level2", "</WriteText>" );
2607 void WW8Export::WriteMainText()
2609 SAL_INFO( "sw.ww8.level2", "<WriteMainText>" );
2611 pFib->fcMin = Strm().Tell();
2613 pCurPam->GetPoint()->nNode = pDoc->GetNodes().GetEndOfContent().StartOfSectionNode()->GetIndex();
2615 WriteText();
2617 if( 0 == Strm().Tell() - pFib->fcMin ) // no text ?
2618 WriteCR(); // then CR at the end ( otherwise WW will complain )
2620 pFib->ccpText = Fc2Cp( Strm().Tell() );
2621 pFldMain->Finish( pFib->ccpText, 0 );
2623 // ccpText includes Footnote and KF-text
2624 // therefore pFib->ccpText may get updated as well
2625 // save the StyleId of the last paragraph. Because WW97 take the style
2626 // from the last CR, that will be writen after footer/Header/footnotes/
2627 // annotation usw.
2628 const SwTxtNode* pLastNd = pCurPam->GetMark()->nNode.GetNode().GetTxtNode();
2629 if( pLastNd )
2630 nLastFmtId = GetId( (SwTxtFmtColl&)pLastNd->GetAnyFmtColl() );
2632 SAL_INFO( "sw.ww8.level2", "</WriteMainText>" );
2635 bool MSWordExportBase::IsInTable() const
2637 bool bResult = false;
2639 if (pCurPam != NULL)
2641 SwNode * pNode = pCurPam->GetNode();
2643 if (pNode != NULL && mpTableInfo.get() != NULL)
2645 ww8::WW8TableNodeInfo::Pointer_t pTableNodeInfo = mpTableInfo->getTableNodeInfo(pNode);
2647 if (pTableNodeInfo.get() != NULL && pTableNodeInfo->getDepth() > 0)
2649 bResult = true;
2654 return bResult;
2657 typedef ww8::WW8Sttb< ww8::WW8Struct > WW8SttbAssoc;
2659 void WW8Export::WriteFkpPlcUsw()
2661 if( !bWrtWW8 )
2663 static const sal_uInt8 aSpec[2] =
2665 117, 1
2668 pChpPlc->AppendFkpEntry( Strm().Tell() ); // Sepx with fSpecial
2669 pSepx->WriteSepx( Strm() ); // Slcx.Sepx
2670 pGrf->Write(); // Graphics
2671 pChpPlc->AppendFkpEntry( Strm().Tell(), sizeof( aSpec ), aSpec );
2673 pChpPlc->WriteFkps(); // Fkp.Chpx
2674 pPapPlc->WriteFkps(); // Fkp.Papx
2675 pStyles->OutputStylesTable(); // Styles
2676 pFtn->WritePlc( *this ); // Footnote-Ref & Text Plc
2677 pEdn->WritePlc( *this ); // Endnote-Ref & Text Plc
2678 pAtn->WritePlc( *this ); // Annotation-Ref & Text Plc
2679 pSepx->WritePlcSed( *this ); // Slcx.PlcSed
2680 pSepx->WritePlcHdd( *this ); // Slcx.PlcHdd
2681 pChpPlc->WritePlc(); // Plcx.Chpx
2682 pPapPlc->WritePlc(); // Plcx.Papx
2683 maFontHelper.WriteFontTable(pTableStrm, *pFib); // FFNs
2684 if( pRedlAuthors )
2685 pRedlAuthors->Write( GetWriter() ); // sttbfRMark (RedlineAuthors)
2686 pFldMain->Write( *this ); // Fields ( Main Text )
2687 pFldHdFt->Write( *this ); // Fields ( Header/Footer )
2688 pFldFtn->Write( *this ); // Fields ( FootNotes )
2689 pFldEdn->Write( *this ); // Fields ( EndNotes )
2690 pFldAtn->Write( *this ); // Fields ( Annotations )
2691 pBkmks->Write( *this ); // Bookmarks - sttbfBkmk/
2692 // plcfBkmkf/plcfBkmkl
2693 WriteDop( *this ); // Document-Properties
2696 else
2698 // Graphics in the data stream
2699 pGrf->Write(); // Graphics
2701 // Ausgabe in WordDocument-Stream
2702 pChpPlc->WriteFkps(); // Fkp.Chpx
2703 pPapPlc->WriteFkps(); // Fkp.Papx
2704 pSepx->WriteSepx( Strm() ); // Sepx
2706 // Ausagbe in Table-Stream
2707 pStyles->OutputStylesTable(); // for WW8 StyleTab
2708 pFtn->WritePlc( *this ); // Footnote-Ref & Text Plc
2709 pEdn->WritePlc( *this ); // Endnote-Ref & Text Plc
2710 pTxtBxs->WritePlc( *this ); // Textbox Text Plc
2711 pHFTxtBxs->WritePlc( *this ); // Head/Foot-Textbox Text Plc
2712 pAtn->WritePlc( *this ); // Annotation-Ref & Text Plc
2714 pSepx->WritePlcSed( *this ); // Slcx.PlcSed
2715 pSepx->WritePlcHdd( *this ); // Slcx.PlcHdd
2717 pChpPlc->WritePlc(); // Plcx.Chpx
2718 pPapPlc->WritePlc(); // Plcx.Papx
2720 if( pRedlAuthors )
2721 pRedlAuthors->Write( GetWriter() ); // sttbfRMark (RedlineAuthors)
2722 pFldMain->Write( *this ); // Fields ( Main Text )
2723 pFldHdFt->Write( *this ); // Fields ( Header/Footer )
2724 pFldFtn->Write( *this ); // Fields ( FootNotes )
2725 pFldEdn->Write( *this ); // Fields ( EndNotes )
2726 pFldAtn->Write( *this ); // Fields ( Annotations )
2727 pFldTxtBxs->Write( *this ); // Fields ( Textboxes )
2728 pFldHFTxtBxs->Write( *this ); // Fields ( Head/Foot-Textboxes )
2730 if (pEscher || pDoc->ContainsMSVBasic())
2733 Everytime MS 2000 creates an escher stream there is always
2734 an ObjectPool dir (even if empty). It turns out that if a copy of
2735 MS 2000 is used to open a document that contains escher graphics
2736 exported from StarOffice without this empty dir then *if* that
2737 copy of MS Office has never been used to open a MSOffice document
2738 that has escher graphics (and an ObjectPool dir of course) and
2739 that copy of office has not been used to draw escher graphics then
2740 our exported graphics do not appear. Once you do open a ms
2741 document with escher graphics or draw an escher graphic with that
2742 copy of word, then all documents from staroffice that contain
2743 escher work from then on. Tricky to track down, some sort of late
2744 binding trickery in MS where solely for first time initialization
2745 the existence of an ObjectPool dir is necessary for triggering
2746 some magic. cmc
2748 // avoid memory leak #i120098#, the unnamed obj will be released in destructor.
2749 xEscherStg = GetWriter().GetStorage().OpenSotStorage(OUString(SL::aObjectPool),
2750 STREAM_READWRITE | STREAM_SHARE_DENYALL);
2753 // dggInfo - escher stream
2754 WriteEscher();
2756 pSdrObjs->WritePlc( *this );
2757 pHFSdrObjs->WritePlc( *this );
2758 // spamom - office drawing table
2759 // spahdr - header office drawing table
2761 pBkmks->Write( *this ); // Bookmarks - sttbfBkmk/
2762 // plcfBkmkf/plcfBkmkl
2764 WriteNumbering();
2766 RestoreMacroCmds();
2768 pMagicTable->Write( *this );
2770 pPiece->WritePc( *this ); // Piece-Table
2771 maFontHelper.WriteFontTable(pTableStrm, *pFib); // FFNs
2773 //Convert OOo asian typography into MS typography structure
2774 ExportDopTypography(pDop->doptypography);
2776 WriteDop( *this ); // Document-Properties
2778 // Write SttbfAssoc
2779 WW8SttbAssoc * pSttbfAssoc = dynamic_cast<WW8SttbAssoc *>
2780 (pDoc->getExternalData(::sw::STTBF_ASSOC).get());
2782 if ( pSttbfAssoc ) // #i106057#
2784 ::std::vector<OUString> aStrings;
2786 ::ww8::StringVector_t & aSttbStrings = pSttbfAssoc->getStrings();
2787 ::ww8::StringVector_t::const_iterator aItEnd = aSttbStrings.end();
2788 for (::ww8::StringVector_t::const_iterator aIt = aSttbStrings.begin();
2789 aIt != aItEnd; ++aIt)
2791 aStrings.push_back(aIt->getStr());
2794 WriteAsStringTable(aStrings, pFib->fcSttbfAssoc,
2795 pFib->lcbSttbfAssoc);
2798 Strm().Seek( 0 );
2800 // Reclaim stored FIB data from document.
2801 ::ww8::WW8FibData * pFibData = dynamic_cast<ww8::WW8FibData *>
2802 (pDoc->getExternalData(::sw::FIB).get());
2804 if ( pFibData )
2806 pFib->fReadOnlyRecommended =
2807 pFibData->getReadOnlyRecommended() ? 1 : 0;
2808 pFib->fWriteReservation =
2809 pFibData->getWriteReservation() ? 1 : 0;
2812 pFib->Write( Strm() ); // FIB
2815 void WW8Export::StoreDoc1()
2817 bool bNeedsFinalPara = false;
2818 // Start of Text ( Mangel ueber )
2819 SwWW8Writer::FillUntil( Strm(), pFib->fcMin );
2821 WriteMainText(); // main text
2822 sal_uInt8 nSprmsLen;
2823 sal_uInt8 *pLastSprms = pPapPlc->CopyLastSprms(nSprmsLen);
2825 bNeedsFinalPara |= pFtn->WriteTxt( *this ); // Footnote-Text
2826 bNeedsFinalPara |= pSepx->WriteKFTxt( *this ); // K/F-Text
2827 bNeedsFinalPara |= pAtn->WriteTxt( *this ); // Annotation-Text
2828 bNeedsFinalPara |= pEdn->WriteTxt( *this ); // EndNote-Text
2830 // create the escher streams
2831 if( bWrtWW8 )
2832 CreateEscher();
2834 bNeedsFinalPara |= pTxtBxs->WriteTxt( *this ); //Textbox Text Plc
2835 bNeedsFinalPara |= pHFTxtBxs->WriteTxt( *this );//Head/Foot-Textbox Text Plc
2837 if (bNeedsFinalPara)
2839 WriteCR();
2840 pPapPlc->AppendFkpEntry(Strm().Tell(), nSprmsLen, pLastSprms);
2842 delete[] pLastSprms;
2844 pSepx->Finish( Fc2Cp( Strm().Tell() ));// Text + Ftn + HdFt als Section-Ende
2845 pMagicTable->Finish( Fc2Cp( Strm().Tell() ),0);
2847 pFib->fcMac = Strm().Tell(); // End of all texts
2849 WriteFkpPlcUsw(); // FKP, PLC, .....
2852 void MSWordExportBase::AddLinkTarget(const String& rURL)
2854 if( !rURL.Len() || rURL.GetChar(0) != INET_MARK_TOKEN )
2855 return;
2857 String aURL( BookmarkToWriter( rURL.Copy( 1 ) ) );
2858 xub_StrLen nPos = aURL.SearchBackward( cMarkSeparator );
2860 if( nPos < 2 )
2861 return;
2863 String sCmp(comphelper::string::remove(aURL.Copy(nPos+1), ' '));
2864 if( !sCmp.Len() )
2865 return;
2867 sCmp.ToLowerAscii();
2869 if( sCmp.EqualsAscii( pMarkToOutline ) )
2871 SwPosition aPos( *pCurPam->GetPoint() );
2872 String aOutline( BookmarkToWriter(aURL.Copy( 0, nPos )) );
2873 // If we can find the outline this bookmark refers to
2874 // save the name of the bookmark and the
2875 // node index number of where it points to
2876 if( pDoc->GotoOutline( aPos, aOutline ) )
2878 sal_uLong nIdx = aPos.nNode.GetIndex();
2879 aBookmarkPair aImplicitBookmark;
2880 aImplicitBookmark.first = aOutline;
2881 aImplicitBookmark.second = nIdx;
2882 maImplicitBookmarks.push_back(aImplicitBookmark);
2887 void MSWordExportBase::CollectOutlineBookmarks(const SwDoc &rDoc)
2889 const SwFmtINetFmt* pINetFmt;
2890 const SwTxtINetFmt* pTxtAttr;
2891 const SwTxtNode* pTxtNd;
2893 sal_uInt32 n, nMaxItems = rDoc.GetAttrPool().GetItemCount2( RES_TXTATR_INETFMT );
2894 for( n = 0; n < nMaxItems; ++n )
2896 if( 0 != (pINetFmt = (SwFmtINetFmt*)rDoc.GetAttrPool().GetItem2(
2897 RES_TXTATR_INETFMT, n ) ) &&
2898 0 != ( pTxtAttr = pINetFmt->GetTxtINetFmt()) &&
2899 0 != ( pTxtNd = pTxtAttr->GetpTxtNode() ) &&
2900 pTxtNd->GetNodes().IsDocNodes() )
2902 AddLinkTarget( pINetFmt->GetValue() );
2906 const SwFmtURL *pURL;
2907 nMaxItems = rDoc.GetAttrPool().GetItemCount2( RES_URL );
2908 for( n = 0; n < nMaxItems; ++n )
2910 if( 0 != (pURL = (SwFmtURL*)rDoc.GetAttrPool().GetItem2(
2911 RES_URL, n ) ) )
2913 AddLinkTarget( pURL->GetURL() );
2914 const ImageMap *pIMap = pURL->GetMap();
2915 if( pIMap )
2917 for( sal_uInt16 i=0; i<pIMap->GetIMapObjectCount(); i++ )
2919 const IMapObject* pObj = pIMap->GetIMapObject( i );
2920 if( pObj )
2922 AddLinkTarget( pObj->GetURL() );
2930 namespace
2932 const sal_uLong WW_BLOCKSIZE = 0x200;
2934 void EncryptRC4(msfilter::MSCodec_Std97& rCtx, SvStream &rIn, SvStream &rOut)
2936 rIn.Seek(STREAM_SEEK_TO_END);
2937 sal_uLong nLen = rIn.Tell();
2938 rIn.Seek(0);
2940 sal_uInt8 in[WW_BLOCKSIZE];
2941 for (sal_Size nI = 0, nBlock = 0; nI < nLen; nI += WW_BLOCKSIZE, ++nBlock)
2943 sal_Size nBS = (nLen - nI > WW_BLOCKSIZE) ? WW_BLOCKSIZE : nLen - nI;
2944 nBS = rIn.Read(in, nBS);
2945 rCtx.InitCipher(nBlock);
2946 rCtx.Encode(in, nBS, in, nBS);
2947 rOut.Write(in, nBS);
2952 void MSWordExportBase::ExportDocument( bool bWriteAll )
2954 nCharFmtStart = ANZ_DEFAULT_STYLES;
2955 nFmtCollStart = nCharFmtStart + pDoc->GetCharFmts()->size() - 1;
2957 bStyDef = bBreakBefore = bOutKF =
2958 bOutFlyFrmAttrs = bOutPageDescs = bOutTable = bOutFirstPage =
2959 bOutGrf = bInWriteEscher = bStartTOX =
2960 bInWriteTOX = false;
2962 bFtnAtTxtEnd = bEndAtTxtEnd = true;
2964 mpParentFrame = 0;
2965 pFlyOffset = 0;
2966 eNewAnchorType = FLY_AT_PAGE;
2967 nTxtTyp = TXT_MAINTEXT;
2968 nStyleBeforeFly = nLastFmtId = 0;
2969 pStyAttr = 0;
2970 pCurrentStyle = NULL;
2971 pOutFmtNode = 0;
2972 pEscher = 0;
2973 pRedlAuthors = 0;
2974 aTOXArr.clear();
2976 if ( !pOLEExp )
2978 sal_uInt32 nSvxMSDffOLEConvFlags = 0;
2979 const SvtFilterOptions& rOpt = SvtFilterOptions::Get();
2980 if ( rOpt.IsMath2MathType() )
2981 nSvxMSDffOLEConvFlags |= OLE_STARMATH_2_MATHTYPE;
2982 if ( rOpt.IsWriter2WinWord() )
2983 nSvxMSDffOLEConvFlags |= OLE_STARWRITER_2_WINWORD;
2984 if ( rOpt.IsCalc2Excel() )
2985 nSvxMSDffOLEConvFlags |= OLE_STARCALC_2_EXCEL;
2986 if ( rOpt.IsImpress2PowerPoint() )
2987 nSvxMSDffOLEConvFlags |= OLE_STARIMPRESS_2_POWERPOINT;
2989 pOLEExp = new SvxMSExportOLEObjects( nSvxMSDffOLEConvFlags );
2992 if ( !pOCXExp && pDoc->GetDocShell() )
2993 pOCXExp = new SwMSConvertControls( pDoc->GetDocShell(), pCurPam );
2995 // #i81405# - Collect anchored objects before changing the redline mode.
2996 maFrames = GetFrames( *pDoc, bWriteAll? NULL : pOrigPam );
2998 mnRedlineMode = pDoc->GetRedlineMode();
2999 if ( !pDoc->GetRedlineTbl().empty() )
3001 pDoc->SetRedlineMode( (RedlineMode_t)(mnRedlineMode | nsRedlineMode_t::REDLINE_SHOW_DELETE |
3002 nsRedlineMode_t::REDLINE_SHOW_INSERT) );
3005 maFontHelper.InitFontTable( SupportsUnicode(), *pDoc );
3006 GatherChapterFields();
3008 CollectOutlineBookmarks(*pDoc);
3010 // make unique OrdNums (Z-Order) for all drawing-/fly Objects
3011 if ( pDoc->GetDrawModel() )
3012 pDoc->GetDrawModel()->GetPage( 0 )->RecalcObjOrdNums();
3014 ExportDocument_Impl();
3016 if ( mnRedlineMode != pDoc->GetRedlineMode() )
3017 pDoc->SetRedlineMode( (RedlineMode_t)(mnRedlineMode) );
3020 bool SwWW8Writer::InitStd97CodecUpdateMedium( ::msfilter::MSCodec_Std97& rCodec )
3022 uno::Sequence< beans::NamedValue > aEncryptionData;
3024 if ( mpMedium )
3026 SFX_ITEMSET_ARG( mpMedium->GetItemSet(), pEncryptionDataItem, SfxUnoAnyItem, SID_ENCRYPTIONDATA, sal_False );
3027 if ( pEncryptionDataItem && ( pEncryptionDataItem->GetValue() >>= aEncryptionData ) && !rCodec.InitCodec( aEncryptionData ) )
3029 OSL_ENSURE( false, "Unexpected EncryptionData!" );
3030 aEncryptionData.realloc( 0 );
3033 if ( !aEncryptionData.getLength() )
3035 // try to generate the encryption data based on password
3036 SFX_ITEMSET_ARG( mpMedium->GetItemSet(), pPasswordItem, SfxStringItem, SID_PASSWORD, sal_False );
3037 if ( pPasswordItem && !pPasswordItem->GetValue().isEmpty() && pPasswordItem->GetValue().getLength() <= 15 )
3039 // Generate random number with a seed of time as salt.
3040 TimeValue aTime;
3041 osl_getSystemTime( &aTime );
3042 rtlRandomPool aRandomPool = rtl_random_createPool ();
3043 rtl_random_addBytes ( aRandomPool, &aTime, 8 );
3045 sal_uInt8 pDocId[ 16 ];
3046 rtl_random_getBytes( aRandomPool, pDocId, 16 );
3048 rtl_random_destroyPool( aRandomPool );
3050 sal_Unicode aPassword[16];
3051 memset( aPassword, 0, sizeof( aPassword ) );
3053 OUString sPassword(pPasswordItem->GetValue());
3054 for ( sal_Int32 nChar = 0; nChar < sPassword.getLength(); ++nChar )
3055 aPassword[nChar] = sPassword[nChar];
3057 rCodec.InitKey( aPassword, pDocId );
3058 aEncryptionData = rCodec.GetEncryptionData();
3060 mpMedium->GetItemSet()->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aEncryptionData ) ) );
3064 if ( aEncryptionData.getLength() )
3065 mpMedium->GetItemSet()->ClearItem( SID_PASSWORD );
3068 // nonempty encryption data means hier that the codec was successfully initialized
3069 return ( aEncryptionData.getLength() != 0 );
3072 void WW8Export::ExportDocument_Impl()
3074 PrepareStorage();
3076 pFib = new WW8Fib( bWrtWW8 ? 8 : 6 );
3078 SvStorageStreamRef xWwStrm( GetWriter().GetStorage().OpenSotStream( aMainStg ) );
3079 SvStorageStreamRef xTableStrm( xWwStrm ), xDataStrm( xWwStrm );
3080 xWwStrm->SetBufferSize( 32768 );
3082 if( bWrtWW8 )
3084 pFib->fWhichTblStm = 1;
3085 xTableStrm = GetWriter().GetStorage().OpenSotStream(OUString(SL::a1Table),
3086 STREAM_STD_WRITE );
3087 xDataStrm = GetWriter().GetStorage().OpenSotStream(OUString(SL::aData),
3088 STREAM_STD_WRITE );
3090 xDataStrm->SetBufferSize( 32768 ); // for graphics
3091 xTableStrm->SetBufferSize( 16384 ); // for the Font-/Style-Table, etc.
3093 xTableStrm->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
3094 xDataStrm->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
3097 GetWriter().SetStream( & *xWwStrm );
3098 pTableStrm = &xTableStrm;
3099 pDataStrm = &xDataStrm;
3101 Strm().SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
3103 utl::TempFile aTempMain;
3104 aTempMain.EnableKillingFile();
3105 utl::TempFile aTempTable;
3106 aTempTable.EnableKillingFile();
3107 utl::TempFile aTempData;
3108 aTempData.EnableKillingFile();
3110 msfilter::MSCodec_Std97 aCtx;
3111 bool bEncrypt = m_pWriter ? m_pWriter->InitStd97CodecUpdateMedium( aCtx ) : false;
3112 if ( bEncrypt )
3114 GetWriter().SetStream(
3115 aTempMain.GetStream( STREAM_READWRITE | STREAM_SHARE_DENYWRITE ) );
3117 pTableStrm = aTempTable.GetStream( STREAM_READWRITE | STREAM_SHARE_DENYWRITE );
3119 pDataStrm = aTempData.GetStream( STREAM_READWRITE | STREAM_SHARE_DENYWRITE );
3121 sal_uInt8 aRC4EncryptionHeader[ 52 ] = {0};
3122 pTableStrm->Write( aRC4EncryptionHeader, 52 );
3125 // Default: "Standard"
3126 pSepx = new WW8_WrPlcSepx( *this ); // Sections/headers/footers
3128 pFtn = new WW8_WrPlcFtnEdn( TXT_FTN ); // Footnotes
3129 pEdn = new WW8_WrPlcFtnEdn( TXT_EDN ); // Endnotes
3130 pAtn = new WW8_WrPlcAnnotations; // PostIts
3131 pTxtBxs = new WW8_WrPlcTxtBoxes( TXT_TXTBOX );
3132 pHFTxtBxs = new WW8_WrPlcTxtBoxes( TXT_HFTXTBOX );
3134 pSdrObjs = new MainTxtPlcDrawObj; // Draw-/Fly-Objects for main text
3135 pHFSdrObjs = new HdFtPlcDrawObj; // Draw-/Fly-Objects for header/footer
3137 pBkmks = new WW8_WrtBookmarks; // Bookmarks
3138 GetWriter().CreateBookmarkTbl();
3140 pPapPlc = new WW8_WrPlcPn( *this, PAP, pFib->fcMin );
3141 pChpPlc = new WW8_WrPlcPn( *this, CHP, pFib->fcMin );
3142 pO = new ww::bytes();
3143 pStyles = new MSWordStyles( *this );
3144 pFldMain = new WW8_WrPlcFld( 2, TXT_MAINTEXT );
3145 pFldHdFt = new WW8_WrPlcFld( 2, TXT_HDFT );
3146 pFldFtn = new WW8_WrPlcFld( 2, TXT_FTN );
3147 pFldEdn = new WW8_WrPlcFld( 2, TXT_EDN );
3148 pFldAtn = new WW8_WrPlcFld( 2, TXT_ATN );
3149 pFldTxtBxs = new WW8_WrPlcFld( 2, TXT_TXTBOX );
3150 pFldHFTxtBxs = new WW8_WrPlcFld( 2, TXT_HFTXTBOX );
3152 pMagicTable = new WW8_WrMagicTable;
3154 pGrf = new SwWW8WrGrf( *this );
3155 pPiece = new WW8_WrPct( pFib->fcMin, bWrtWW8 );
3156 pDop = new WW8Dop;
3159 pDop->fRevMarking = 0 != ( nsRedlineMode_t::REDLINE_ON & mnRedlineMode );
3160 pDop->fRMView = 0 != ( nsRedlineMode_t::REDLINE_SHOW_DELETE & mnRedlineMode );
3161 pDop->fRMPrint = pDop->fRMView;
3163 // set AutoHyphenation flag if found in default para style
3164 const SfxPoolItem* pItem;
3165 SwTxtFmtColl* pStdTxtFmtColl =
3166 pDoc->GetTxtCollFromPool(RES_POOLCOLL_STANDARD, false);
3167 if (pStdTxtFmtColl && SFX_ITEM_SET == pStdTxtFmtColl->GetItemState(
3168 RES_PARATR_HYPHENZONE, false, &pItem))
3170 pDop->fAutoHyphen = ((const SvxHyphenZoneItem*)pItem)->IsHyphen();
3173 StoreDoc1();
3175 if ( bEncrypt )
3177 SvStream *pStrmTemp, *pTableStrmTemp, *pDataStrmTemp;
3178 pStrmTemp = &xWwStrm;
3179 pTableStrmTemp = &xTableStrm;
3180 pDataStrmTemp = &xDataStrm;
3182 if ( pDataStrmTemp && pDataStrmTemp != pStrmTemp)
3183 EncryptRC4(aCtx, *pDataStrm, *pDataStrmTemp);
3185 EncryptRC4(aCtx, *pTableStrm, *pTableStrmTemp);
3187 // Write Unencrypted Header 52 bytes to the start of the table stream
3188 // EncryptionVersionInfo (4 bytes): A Version structure where Version.vMajor MUST be 0x0001, and Version.vMinor MUST be 0x0001.
3189 pTableStrmTemp->Seek( 0 );
3190 sal_uInt32 nEncType = 0x10001;
3191 *pTableStrmTemp << nEncType;
3193 sal_uInt8 pDocId[16];
3194 aCtx.GetDocId( pDocId );
3196 sal_uInt8 pSaltData[16];
3197 sal_uInt8 pSaltDigest[16];
3198 aCtx.GetEncryptKey( pDocId, pSaltData, pSaltDigest );
3200 pTableStrmTemp->Write( pDocId, 16 );
3201 pTableStrmTemp->Write( pSaltData, 16 );
3202 pTableStrmTemp->Write( pSaltDigest, 16 );
3204 EncryptRC4(aCtx, GetWriter().Strm(), *pStrmTemp);
3206 // Write Unencrypted Fib 68 bytes to the start of the workdocument stream
3207 pFib->fEncrypted = 1; // fEncrypted indicates the document is encrypted.
3208 pFib->fObfuscated = 0; // Must be 0 for RC4.
3209 pFib->nHash = 0x34; // encrypt header bytes count of table stream.
3210 pFib->nKey = 0; // lkey2 must be 0 for RC4.
3212 pStrmTemp->Seek( 0 );
3213 pFib->WriteHeader( *pStrmTemp );
3216 if (pUsedNumTbl) // all used NumRules
3218 // clear the part of the list array that was copied from the document
3219 // - it's an auto delete array, so the rest of the array which are
3220 // duplicated lists that were added during the export will be deleted.
3221 pUsedNumTbl->erase(pUsedNumTbl->begin(), pUsedNumTbl->begin() + pUsedNumTbl->size() - nUniqueList);
3222 delete pUsedNumTbl;
3225 DELETEZ( pGrf );
3226 DELETEZ( pMagicTable );
3227 DELETEZ( pFldFtn );
3228 DELETEZ( pFldTxtBxs );
3229 DELETEZ( pFldHFTxtBxs );
3230 DELETEZ( pFldAtn );
3231 DELETEZ( pFldEdn );
3232 DELETEZ( pFldHdFt );
3233 DELETEZ( pFldMain );
3234 DELETEZ( pStyles );
3235 DELETEZ( pO );
3236 DELETEZ( pChpPlc );
3237 DELETEZ( pPapPlc );
3238 DELETEZ( pSepx );
3240 delete pRedlAuthors;
3241 delete pSdrObjs;
3242 delete pHFSdrObjs;
3243 delete pTxtBxs;
3244 delete pHFTxtBxs;
3245 delete pAtn;
3246 delete pEdn;
3247 delete pFtn;
3248 delete pBkmks;
3249 delete pPiece;
3250 delete pDop;
3251 delete pFib;
3252 GetWriter().SetStream( 0 );
3255 xWwStrm->SetBufferSize( 0 );
3256 if( bWrtWW8 )
3258 xTableStrm->SetBufferSize( 0 );
3259 xDataStrm->SetBufferSize( 0 );
3260 if( 0 == pDataStrm->Seek( STREAM_SEEK_TO_END ))
3262 xDataStrm.Clear();
3263 pDataStrm = 0;
3264 GetWriter().GetStorage().Remove(OUString(SL::aData));
3270 void WW8Export::PrepareStorage()
3272 sal_uLong nLen;
3273 const sal_uInt8* pData;
3274 const char* pName;
3275 sal_uInt32 nId1;
3277 if (bWrtWW8)
3279 static const char aUserName[] = "Microsoft Word-Document";
3280 static const sal_uInt8 aCompObj[] =
3282 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
3283 0xFF, 0xFF, 0xFF, 0xFF, 0x06, 0x09, 0x02, 0x00,
3284 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,
3285 0x00, 0x00, 0x00, 0x46, 0x18, 0x00, 0x00, 0x00,
3286 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66,
3287 0x74, 0x20, 0x57, 0x6F, 0x72, 0x64, 0x2D, 0x44,
3288 0x6F, 0x6B, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x00,
3289 0x0A, 0x00, 0x00, 0x00, 0x4D, 0x53, 0x57, 0x6F,
3290 0x72, 0x64, 0x44, 0x6F, 0x63, 0x00, 0x10, 0x00,
3291 0x00, 0x00, 0x57, 0x6F, 0x72, 0x64, 0x2E, 0x44,
3292 0x6F, 0x63, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x2E,
3293 0x38, 0x00, 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00,
3294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3295 0x00, 0x00
3298 pName = aUserName;
3299 pData = aCompObj;
3300 nLen = sizeof( aCompObj );
3301 nId1 = 0x00020906L;
3303 else
3305 static const char aUserName[] = "Microsoft Word 6.0 Document";
3306 static const sal_uInt8 aCompObj[] =
3308 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
3309 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x09, 0x02, 0x00,
3310 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,
3311 0x00, 0x00, 0x00, 0x46, 0x1C, 0x00, 0x00, 0x00,
3312 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66,
3313 0x74, 0x20, 0x57, 0x6F, 0x72, 0x64, 0x20, 0x36,
3314 0x2E, 0x30, 0x2D, 0x44, 0x6F, 0x6B, 0x75, 0x6D,
3315 0x65, 0x6E, 0x74, 0x00, 0x0A, 0x00, 0x00, 0x00,
3316 0x4D, 0x53, 0x57, 0x6F, 0x72, 0x64, 0x44, 0x6F,
3317 0x63, 0x00, 0x10, 0x00, 0x00, 0x00, 0x57, 0x6F,
3318 0x72, 0x64, 0x2E, 0x44, 0x6F, 0x63, 0x75, 0x6D,
3319 0x65, 0x6E, 0x74, 0x2E, 0x36, 0x00, 0x00, 0x00,
3320 0x00, 0x00
3323 pName = aUserName;
3324 pData = aCompObj;
3325 nLen = sizeof( aCompObj );
3326 nId1 = 0x00020900L;
3329 SvGlobalName aGName( nId1, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00,
3330 0x00, 0x00, 0x00, 0x46 );
3331 GetWriter().GetStorage().SetClass( aGName, 0, OUString::createFromAscii( pName ));
3332 SvStorageStreamRef xStor( GetWriter().GetStorage().OpenSotStream(sCompObj) );
3333 xStor->Write( pData, nLen );
3335 SwDocShell* pDocShell = pDoc->GetDocShell ();
3336 OSL_ENSURE(pDocShell, "no SwDocShell");
3338 if (pDocShell) {
3339 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
3340 pDocShell->GetModel(), uno::UNO_QUERY_THROW);
3341 uno::Reference<document::XDocumentProperties> xDocProps(
3342 xDPS->getDocumentProperties());
3343 OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
3345 if (xDocProps.is())
3347 if ( SvtFilterOptions::Get().IsEnableWordPreview() )
3349 ::boost::shared_ptr<GDIMetaFile> pMetaFile =
3350 pDocShell->GetPreviewMetaFile (sal_False);
3351 uno::Sequence<sal_uInt8> metaFile(
3352 sfx2::convertMetaFile(pMetaFile.get()));
3353 sfx2::SaveOlePropertySet(xDocProps, &GetWriter().GetStorage(), &metaFile);
3355 else
3356 sfx2::SaveOlePropertySet( xDocProps, &GetWriter().GetStorage() );
3361 sal_uLong SwWW8Writer::WriteStorage()
3363 // #i34818# - update layout (if present), for SwWriteTable
3364 ViewShell* pViewShell = NULL;
3365 pDoc->GetEditShell( &pViewShell );
3366 if( pViewShell != NULL )
3367 pViewShell->CalcLayout();
3369 long nMaxNode = pDoc->GetNodes().Count();
3370 ::StartProgress( STR_STATSTR_W4WWRITE, 0, nMaxNode, pDoc->GetDocShell() );
3372 // Respect table at the beginning of the document
3374 SwTableNode * pTNd = pCurPam->GetNode()->FindTableNode();
3375 if( pTNd && bWriteAll )
3376 // start with the table node !!
3377 pCurPam->GetPoint()->nNode = *pTNd;
3380 // Do the actual export
3382 WW8Export aExport( this, pDoc, pCurPam, pOrigPam, m_bWrtWW8 );
3383 m_pExport = &aExport;
3384 aExport.ExportDocument( bWriteAll );
3385 m_pExport = NULL;
3388 ::EndProgress( pDoc->GetDocShell() );
3389 return 0;
3392 sal_uLong SwWW8Writer::WriteMedium( SfxMedium& )
3394 return WriteStorage();
3397 sal_uLong SwWW8Writer::Write( SwPaM& rPaM, SfxMedium& rMed,
3398 const String* pFileName )
3400 mpMedium = &rMed;
3401 sal_uLong nRet = StgWriter::Write( rPaM, rMed, pFileName );
3402 mpMedium = NULL;
3403 return nRet;
3406 MSWordExportBase::MSWordExportBase( SwDoc *pDocument, SwPaM *pCurrentPam, SwPaM *pOriginalPam )
3407 : aMainStg(sMainStream), pISet(0), pUsedNumTbl(0), mpTopNodeOfHdFtPage(0),
3408 pBmpPal(0), pOLEExp(0), pOCXExp(0),
3409 mpTableInfo(new ww8::WW8TableInfo()), nUniqueList(0),
3410 mnHdFtIndex(0), pAktPageDesc(0), pPapPlc(0), pChpPlc(0), pChpIter(0),
3411 pStyles( NULL ),
3412 bHasHdr(false), bHasFtr(false), bSubstituteBullets(true),
3413 mbExportModeRTF( false ),
3414 mbOutOutlineOnly( false ),
3415 pDoc( pDocument ),
3416 pCurPam( pCurrentPam ),
3417 pOrigPam( pOriginalPam )
3421 MSWordExportBase::~MSWordExportBase()
3423 delete pBmpPal;
3424 delete pOLEExp;
3425 delete pOCXExp;
3428 WW8Export::WW8Export( SwWW8Writer *pWriter,
3429 SwDoc *pDocument, SwPaM *pCurrentPam, SwPaM *pOriginalPam,
3430 bool bIsWW8 )
3431 : MSWordExportBase( pDocument, pCurrentPam, pOriginalPam ),
3432 pO( NULL ),
3433 pSepx( NULL ),
3434 bWrtWW8( bIsWW8 ),
3435 m_pWriter( pWriter ),
3436 m_pAttrOutput( new WW8AttributeOutput( *this ) )
3440 WW8Export::~WW8Export()
3442 delete m_pAttrOutput, m_pAttrOutput = NULL;
3445 AttributeOutputBase& WW8Export::AttrOutput() const
3447 return *m_pAttrOutput;
3450 MSWordSections& WW8Export::Sections() const
3452 return *pSepx;
3455 SwWW8Writer::SwWW8Writer(const String& rFltName, const String& rBaseURL)
3456 : StgWriter(),
3457 m_bWrtWW8( rFltName.EqualsAscii( FILTER_WW8 ) ),
3458 m_pExport( NULL ),
3459 mpMedium( 0 )
3461 SetBaseURL( rBaseURL );
3464 SwWW8Writer::~SwWW8Writer()
3468 extern "C" SAL_DLLPUBLIC_EXPORT sal_uLong SAL_CALL SaveOrDelMSVBAStorage_ww8( SfxObjectShell& rDoc, SotStorage& rStor, sal_Bool bSaveInto, const String& rStorageName )
3470 SvxImportMSVBasic aTmp( rDoc, rStor );
3471 return aTmp.SaveOrDelMSVBAStorage( bSaveInto, rStorageName );
3474 extern "C" SAL_DLLPUBLIC_EXPORT void SAL_CALL ExportDOC( const String& rFltName, const String& rBaseURL, WriterRef& xRet )
3476 xRet = new SwWW8Writer( rFltName, rBaseURL );
3480 extern "C" SAL_DLLPUBLIC_EXPORT sal_uLong SAL_CALL GetSaveWarningOfMSVBAStorage_ww8( SfxObjectShell &rDocS )
3482 return SvxImportMSVBasic::GetSaveWarningOfMSVBAStorage( rDocS );
3485 bool WW8_WrPlcFtnEdn::WriteTxt( WW8Export& rWrt )
3487 bool bRet = false;
3488 if (TXT_FTN == nTyp)
3490 bRet = WriteGenericTxt( rWrt, TXT_FTN, rWrt.pFib->ccpFtn );
3491 rWrt.pFldFtn->Finish( rWrt.Fc2Cp( rWrt.Strm().Tell() ),
3492 rWrt.pFib->ccpText );
3494 else
3496 bRet = WriteGenericTxt( rWrt, TXT_EDN, rWrt.pFib->ccpEdn );
3497 rWrt.pFldEdn->Finish( rWrt.Fc2Cp( rWrt.Strm().Tell() ),
3498 rWrt.pFib->ccpText + rWrt.pFib->ccpFtn
3499 + rWrt.pFib->ccpHdr + rWrt.pFib->ccpAtn );
3501 return bRet;
3504 void WW8_WrPlcFtnEdn::WritePlc( WW8Export& rWrt ) const
3506 if( TXT_FTN == nTyp )
3508 WriteGenericPlc( rWrt, TXT_FTN, rWrt.pFib->fcPlcffndTxt,
3509 rWrt.pFib->lcbPlcffndTxt, rWrt.pFib->fcPlcffndRef,
3510 rWrt.pFib->lcbPlcffndRef );
3512 else
3514 WriteGenericPlc( rWrt, TXT_EDN, rWrt.pFib->fcPlcfendTxt,
3515 rWrt.pFib->lcbPlcfendTxt, rWrt.pFib->fcPlcfendRef,
3516 rWrt.pFib->lcbPlcfendRef );
3521 bool WW8_WrPlcAnnotations::WriteTxt( WW8Export& rWrt )
3523 bool bRet = WriteGenericTxt( rWrt, TXT_ATN, rWrt.pFib->ccpAtn );
3524 rWrt.pFldAtn->Finish( rWrt.Fc2Cp( rWrt.Strm().Tell() ),
3525 rWrt.pFib->ccpText + rWrt.pFib->ccpFtn
3526 + rWrt.pFib->ccpHdr );
3527 return bRet;
3530 void WW8_WrPlcAnnotations::WritePlc( WW8Export& rWrt ) const
3532 WriteGenericPlc( rWrt, TXT_ATN, rWrt.pFib->fcPlcfandTxt,
3533 rWrt.pFib->lcbPlcfandTxt, rWrt.pFib->fcPlcfandRef,
3534 rWrt.pFib->lcbPlcfandRef );
3537 void WW8_WrPlcTxtBoxes::WritePlc( WW8Export& rWrt ) const
3539 if( TXT_TXTBOX == nTyp )
3541 WriteGenericPlc( rWrt, nTyp, rWrt.pFib->fcPlcftxbxBkd,
3542 rWrt.pFib->lcbPlcftxbxBkd, rWrt.pFib->fcPlcftxbxTxt,
3543 rWrt.pFib->lcbPlcftxbxTxt );
3545 else
3547 WriteGenericPlc( rWrt, nTyp, rWrt.pFib->fcPlcfHdrtxbxBkd,
3548 rWrt.pFib->lcbPlcfHdrtxbxBkd, rWrt.pFib->fcPlcfHdrtxbxTxt,
3549 rWrt.pFib->lcbPlcfHdrtxbxTxt );
3553 void WW8Export::RestoreMacroCmds()
3555 pFib->fcCmds = pTableStrm->Tell();
3557 uno::Reference < embed::XStorage > xSrcRoot(pDoc->GetDocShell()->GetStorage());
3560 uno::Reference < io::XStream > xSrcStream =
3561 xSrcRoot->openStreamElement( OUString(SL::aMSMacroCmds), embed::ElementModes::READ );
3562 SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( xSrcStream );
3564 if ( pStream && SVSTREAM_OK == pStream->GetError())
3566 pStream->Seek(STREAM_SEEK_TO_END);
3567 pFib->lcbCmds = pStream->Tell();
3568 pStream->Seek(0);
3570 sal_uInt8 *pBuffer = new sal_uInt8[pFib->lcbCmds];
3571 bool bReadOk = checkRead(*pStream, pBuffer, pFib->lcbCmds);
3572 if (bReadOk)
3573 pTableStrm->Write(pBuffer, pFib->lcbCmds);
3574 delete[] pBuffer;
3578 delete pStream;
3580 catch ( const uno::Exception& )
3584 // set len to FIB
3585 pFib->lcbCmds = pTableStrm->Tell() - pFib->fcCmds;
3588 void WW8SHDLong::Write( WW8Export& rExport )
3590 rExport.InsUInt32( m_cvFore );
3591 rExport.InsUInt32( m_cvBack );
3592 rExport.InsUInt16( m_ipat );
3595 void WW8Export::WriteFormData( const ::sw::mark::IFieldmark& rFieldmark )
3597 OSL_ENSURE( bWrtWW8, "No 95 export yet" );
3598 if ( !bWrtWW8 )
3599 return;
3601 const ::sw::mark::IFieldmark* pFieldmark = &rFieldmark;
3602 const ::sw::mark::ICheckboxFieldmark* pAsCheckbox = dynamic_cast< const ::sw::mark::ICheckboxFieldmark* >( pFieldmark );
3605 OSL_ENSURE(rFieldmark.GetFieldname() == ODF_FORMTEXT ||
3606 rFieldmark.GetFieldname() == ODF_FORMDROPDOWN ||
3607 rFieldmark.GetFieldname() == ODF_FORMCHECKBOX, "Unknown field type!!!");
3608 if ( ! ( rFieldmark.GetFieldname() == ODF_FORMTEXT ||
3609 rFieldmark.GetFieldname() == ODF_FORMDROPDOWN ||
3610 rFieldmark.GetFieldname() == ODF_FORMCHECKBOX ) )
3611 return;
3613 int type = 0; // TextFieldmark
3614 if ( pAsCheckbox )
3615 type = 1;
3616 if ( rFieldmark.GetFieldname() == ODF_FORMDROPDOWN )
3617 type=2;
3619 ::sw::mark::IFieldmark::parameter_map_t::const_iterator pNameParameter = rFieldmark.GetParameters()->find("name");
3620 OUString ffname;
3621 if(pNameParameter != rFieldmark.GetParameters()->end())
3622 pNameParameter->second >>= ffname;
3624 sal_uLong nDataStt = pDataStrm->Tell();
3625 pChpPlc->AppendFkpEntry(Strm().Tell());
3627 WriteChar(0x01);
3628 static sal_uInt8 aArr1[] =
3630 0x03, 0x6a, 0,0,0,0, // sprmCPicLocation
3632 0x06, 0x08, 0x01, // sprmCFData
3633 0x55, 0x08, 0x01, // sprmCFSpec
3634 0x02, 0x08, 0x01 // sprmCFFldVanish
3636 sal_uInt8* pDataAdr = aArr1 + 2;
3637 Set_UInt32(pDataAdr, nDataStt);
3639 pChpPlc->AppendFkpEntry( Strm().Tell(), sizeof( aArr1 ), aArr1 );
3641 struct FFDataHeader
3643 sal_uInt32 version;
3644 sal_uInt16 bits;
3645 sal_uInt16 cch;
3646 sal_uInt16 hps;
3647 FFDataHeader() : version( 0xFFFFFFFF ), bits(0), cch(0), hps(0) {}
3651 FFDataHeader aFldHeader;
3652 aFldHeader.bits |= (type & 0x03);
3654 sal_Int32 ffres = 0; // rFieldmark.GetFFRes();
3655 if ( pAsCheckbox && pAsCheckbox->IsChecked() )
3656 ffres = 1;
3657 else if ( type == 2 )
3659 ::sw::mark::IFieldmark::parameter_map_t::const_iterator pResParameter = rFieldmark.GetParameters()->find(ODF_FORMDROPDOWN_RESULT);
3660 if(pResParameter != rFieldmark.GetParameters()->end())
3661 pResParameter->second >>= ffres;
3662 else
3663 ffres = 0;
3665 aFldHeader.bits |= ( (ffres<<2) & 0x7C );
3667 std::vector< OUString > aListItems;
3668 if (type==2)
3670 aFldHeader.bits |= 0x8000; // ffhaslistbox
3671 const ::sw::mark::IFieldmark::parameter_map_t* const pParameters = rFieldmark.GetParameters();
3672 ::sw::mark::IFieldmark::parameter_map_t::const_iterator pListEntries = pParameters->find(ODF_FORMDROPDOWN_LISTENTRY);
3673 if(pListEntries != pParameters->end())
3675 uno::Sequence< OUString > vListEntries;
3676 pListEntries->second >>= vListEntries;
3677 copy(::comphelper::stl_begin(vListEntries), ::comphelper::stl_end(vListEntries), back_inserter(aListItems));
3681 const OUString ffdeftext;
3682 const OUString ffformat;
3683 const OUString ffhelptext;
3684 const OUString ffstattext;
3685 const OUString ffentrymcr;
3686 const OUString ffexitmcr;
3689 const sal_uInt8 aFldData[] =
3691 0x44,0, // the start of "next" data
3692 0,0,0,0,0,0,0,0,0,0, // PIC-Structure! /10
3693 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | /16
3694 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | /16
3695 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | /16
3696 0,0,0,0, // / /4
3698 sal_uInt32 slen = sizeof(sal_uInt32)
3699 + sizeof(aFldData)
3700 + sizeof( aFldHeader.version ) + sizeof( aFldHeader.bits ) + sizeof( aFldHeader.cch ) + sizeof( aFldHeader.hps )
3701 + 2*ffname.getLength() + 4
3702 + 2*ffformat.getLength() + 4
3703 + 2*ffhelptext.getLength() + 4
3704 + 2*ffstattext.getLength() + 4
3705 + 2*ffentrymcr.getLength() + 4
3706 + 2*ffexitmcr.getLength() + 4;
3707 if ( type )
3708 slen += 2; // wDef
3709 else
3710 slen += 2*ffdeftext.getLength() + 4; //xstzTextDef
3711 if ( type==2 ) {
3712 slen += 2; // sttb ( fExtend )
3713 slen += 4; // for num of list items
3714 const int items = aListItems.size();
3715 for( int i = 0; i < items; i++ ) {
3716 OUString item = aListItems[i];
3717 slen += 2 * item.getLength() + 2;
3721 *pDataStrm << slen;
3723 int len = sizeof( aFldData );
3724 OSL_ENSURE( len == 0x44-sizeof(sal_uInt32), "SwWW8Writer::WriteFormData(..) - wrong aFldData length" );
3725 pDataStrm->Write( aFldData, len );
3727 *pDataStrm << aFldHeader.version << aFldHeader.bits << aFldHeader.cch << aFldHeader.hps;
3729 SwWW8Writer::WriteString_xstz( *pDataStrm, ffname, true ); // Form field name
3731 if ( !type )
3732 SwWW8Writer::WriteString_xstz( *pDataStrm, ffdeftext, true );
3733 if ( type )
3734 *pDataStrm << sal_uInt16(0);
3737 SwWW8Writer::WriteString_xstz( *pDataStrm, String( ffformat ), true );
3738 SwWW8Writer::WriteString_xstz( *pDataStrm, String( ffhelptext ), true );
3739 SwWW8Writer::WriteString_xstz( *pDataStrm, String( ffstattext ), true );
3740 SwWW8Writer::WriteString_xstz( *pDataStrm, String( ffentrymcr ), true );
3741 SwWW8Writer::WriteString_xstz( *pDataStrm, String( ffexitmcr ), true );
3742 if (type==2) {
3743 *pDataStrm<<(sal_uInt16)0xFFFF;
3744 const int items=aListItems.size();
3745 *pDataStrm<<(sal_uInt32)items;
3746 for(int i=0;i<items;i++) {
3747 OUString item=aListItems[i];
3748 SwWW8Writer::WriteString_xstz( *pDataStrm, item, false );
3753 void WW8Export::WriteHyperlinkData( const sw::mark::IFieldmark& /*rFieldmark*/ )
3755 //@TODO implement me !!!
3758 void WW8AttributeOutput::TableNodeInfoInner( ww8::WW8TableNodeInfoInner::Pointer_t pNodeInfoInner )
3760 SVBT16 nStyle;
3761 ShortToSVBT16( m_rWW8Export.nStyleBeforeFly, nStyle );
3763 #ifdef DBG_UTIL
3764 SAL_INFO( "sw.ww8", "<OutWW8_TableNodeInfoInner>" << pNodeInfoInner->toString());
3765 #endif
3767 m_rWW8Export.pO->clear();
3769 sal_uInt32 nShadowsBefore = pNodeInfoInner->getShadowsBefore();
3770 if (nShadowsBefore > 0)
3772 ww8::WW8TableNodeInfoInner::Pointer_t
3773 pTmpNodeInfoInner(new ww8::WW8TableNodeInfoInner(NULL));
3775 pTmpNodeInfoInner->setDepth(pNodeInfoInner->getDepth());
3776 pTmpNodeInfoInner->setEndOfCell(true);
3778 for (sal_uInt32 n = 0; n < nShadowsBefore; ++n)
3780 m_rWW8Export.WriteCR(pTmpNodeInfoInner);
3782 m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), (sal_uInt8*)&nStyle, (sal_uInt8*)&nStyle+2 ); // Style #
3783 TableInfoCell(pTmpNodeInfoInner);
3784 m_rWW8Export.pPapPlc->AppendFkpEntry
3785 ( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->size(), m_rWW8Export.pO->data() );
3787 m_rWW8Export.pO->clear();
3791 if (pNodeInfoInner->isEndOfCell())
3793 SAL_INFO( "sw.ww8", "<endOfCell/>" );
3795 m_rWW8Export.WriteCR(pNodeInfoInner);
3797 m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), (sal_uInt8*)&nStyle, (sal_uInt8*)&nStyle+2 ); // Style #
3798 TableInfoCell(pNodeInfoInner);
3799 m_rWW8Export.pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->size(), m_rWW8Export.pO->data() );
3801 m_rWW8Export.pO->clear();
3804 sal_uInt32 nShadowsAfter = pNodeInfoInner->getShadowsAfter();
3805 if (nShadowsAfter > 0)
3807 ww8::WW8TableNodeInfoInner::Pointer_t
3808 pTmpNodeInfoInner(new ww8::WW8TableNodeInfoInner(NULL));
3810 pTmpNodeInfoInner->setDepth(pNodeInfoInner->getDepth());
3811 pTmpNodeInfoInner->setEndOfCell(true);
3813 for (sal_uInt32 n = 0; n < nShadowsAfter; ++n)
3815 m_rWW8Export.WriteCR(pTmpNodeInfoInner);
3817 m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), (sal_uInt8*)&nStyle, (sal_uInt8*)&nStyle+2 ); // Style #
3818 TableInfoCell(pTmpNodeInfoInner);
3819 m_rWW8Export.pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->size(), m_rWW8Export.pO->data() );
3821 m_rWW8Export.pO->clear();
3825 if (pNodeInfoInner->isEndOfLine())
3827 SAL_INFO( "sw.ww8", "<endOfLine/>" );
3829 TableRowEnd(pNodeInfoInner->getDepth());
3831 ShortToSVBT16(0, nStyle);
3832 m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), (sal_uInt8*)&nStyle, (sal_uInt8*)&nStyle+2 ); // Style #
3833 TableInfoRow(pNodeInfoInner);
3834 m_rWW8Export.pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->size(), m_rWW8Export.pO->data() );
3836 m_rWW8Export.pO->clear();
3838 SAL_INFO( "sw.ww8", "</OutWW8_TableNodeInfoInner>" );
3841 void MSWordExportBase::OutputStartNode( const SwStartNode & rNode)
3844 ww8::WW8TableNodeInfo::Pointer_t pNodeInfo =
3845 mpTableInfo->getTableNodeInfo( &rNode );
3847 if (pNodeInfo.get() != NULL)
3849 #ifdef DBG_UTIL
3850 SAL_INFO( "sw.ww8", pNodeInfo->toString());
3851 #endif
3852 const ww8::WW8TableNodeInfo::Inners_t aInners = pNodeInfo->getInners();
3853 ww8::WW8TableNodeInfo::Inners_t::const_reverse_iterator aIt(aInners.rbegin());
3854 ww8::WW8TableNodeInfo::Inners_t::const_reverse_iterator aEnd(aInners.rend());
3855 while (aIt != aEnd)
3857 ww8::WW8TableNodeInfoInner::Pointer_t pInner = aIt->second;
3859 AttrOutput().TableNodeInfoInner(pInner);
3860 ++aIt;
3863 SAL_INFO( "sw.ww8", "</OutWW8_SwStartNode>" );
3866 void MSWordExportBase::OutputEndNode( const SwEndNode &rNode )
3868 #ifdef DBG_UTIL
3869 SAL_INFO( "sw.ww8", "<OutWW8_SwEndNode>" << dbg_out(&rNode));
3870 #endif
3872 ww8::WW8TableNodeInfo::Pointer_t pNodeInfo = mpTableInfo->getTableNodeInfo( &rNode );
3874 if (pNodeInfo.get() != NULL)
3876 #ifdef DBG_UTIL
3877 SAL_INFO( "sw.ww8", pNodeInfo->toString());
3878 #endif
3880 const ww8::WW8TableNodeInfo::Inners_t aInners = pNodeInfo->getInners();
3881 ww8::WW8TableNodeInfo::Inners_t::const_iterator aIt(aInners.begin());
3882 ww8::WW8TableNodeInfo::Inners_t::const_iterator aEnd(aInners.end());
3883 while (aIt != aEnd)
3885 ww8::WW8TableNodeInfoInner::Pointer_t pInner = aIt->second;
3886 AttrOutput().TableNodeInfoInner(pInner);
3887 ++aIt;
3890 SAL_INFO( "sw.ww8", "</OutWW8_SwEndNode>" );
3893 const NfKeywordTable & MSWordExportBase::GetNfKeywordTable()
3895 if (pKeyMap.get() == NULL)
3897 pKeyMap.reset(new NfKeywordTable);
3898 NfKeywordTable & rKeywordTable = *pKeyMap;
3899 rKeywordTable[NF_KEY_D] = "d";
3900 rKeywordTable[NF_KEY_DD] = "dd";
3901 rKeywordTable[NF_KEY_DDD] = "ddd";
3902 rKeywordTable[NF_KEY_DDDD] = "dddd";
3903 rKeywordTable[NF_KEY_M] = "M";
3904 rKeywordTable[NF_KEY_MM] = "MM";
3905 rKeywordTable[NF_KEY_MMM] = "MMM";
3906 rKeywordTable[NF_KEY_MMMM] = "MMMM";
3907 rKeywordTable[NF_KEY_NN] = "ddd";
3908 rKeywordTable[NF_KEY_NNN] = "dddd";
3909 rKeywordTable[NF_KEY_NNNN] = "dddd";
3910 rKeywordTable[NF_KEY_YY] = "yy";
3911 rKeywordTable[NF_KEY_YYYY] = "yyyy";
3912 rKeywordTable[NF_KEY_H] = "H";
3913 rKeywordTable[NF_KEY_HH] = "HH";
3914 rKeywordTable[NF_KEY_MI] = "m";
3915 rKeywordTable[NF_KEY_MMI] = "mm";
3916 rKeywordTable[NF_KEY_S] = "s";
3917 rKeywordTable[NF_KEY_SS] = "ss";
3918 rKeywordTable[NF_KEY_AMPM] = "AM/PM";
3921 return *pKeyMap;
3924 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */