warn on load when a document binds an event to a macro
[LibreOffice.git] / sw / source / filter / ww8 / ww8par.cxx
blobc1ac48f408feda7b91a45a5db1842b14dcbdcab6
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 .
20 #include <config_features.h>
22 #include <sal/config.h>
23 #include <sal/log.hxx>
25 #include <com/sun/star/embed/Aspects.hpp>
26 #include <com/sun/star/embed/ElementModes.hpp>
27 #include <com/sun/star/frame/XModel.hpp>
28 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
30 #include <i18nlangtag/languagetag.hxx>
32 #include <unotools/configmgr.hxx>
33 #include <unotools/ucbstreamhelper.hxx>
34 #include <rtl/random.h>
35 #include <rtl/ustring.hxx>
36 #include <rtl/ustrbuf.hxx>
38 #include <sfx2/docinf.hxx>
39 #include <sfx2/request.hxx>
40 #include <sfx2/frame.hxx>
41 #include <tools/urlobj.hxx>
42 #include <unotools/tempfile.hxx>
44 #include <comphelper/docpasswordrequest.hxx>
45 #include <comphelper/documentinfo.hxx>
46 #include <comphelper/propertysequence.hxx>
48 #include <editeng/outlobj.hxx>
49 #include <editeng/brushitem.hxx>
50 #include <editeng/formatbreakitem.hxx>
51 #include <editeng/tstpitem.hxx>
52 #include <editeng/ulspitem.hxx>
53 #include <editeng/langitem.hxx>
54 #include <editeng/opaqitem.hxx>
55 #include <editeng/charhiddenitem.hxx>
56 #include <editeng/fontitem.hxx>
57 #include <editeng/editeng.hxx>
58 #include <svx/unoapi.hxx>
59 #include <svx/svdoole2.hxx>
60 #include <svx/svdoashp.hxx>
61 #include <svx/svxerr.hxx>
62 #include <filter/msfilter/mscodec.hxx>
63 #include <svx/svdmodel.hxx>
64 #include <svx/xflclit.hxx>
65 #include <svx/sdasitm.hxx>
66 #include <svx/sdtagitm.hxx>
67 #include <svx/sdtcfitm.hxx>
68 #include <svx/sdtditm.hxx>
69 #include <svx/sdtmfitm.hxx>
70 #include <unotools/fltrcfg.hxx>
71 #include <fmtfld.hxx>
72 #include <fmturl.hxx>
73 #include <fmtinfmt.hxx>
74 #include <reffld.hxx>
75 #include <fmthdft.hxx>
76 #include <fmtcntnt.hxx>
77 #include <fmtcnct.hxx>
78 #include <fmtanchr.hxx>
79 #include <fmtpdsc.hxx>
80 #include <ftninfo.hxx>
81 #include <fmtftn.hxx>
82 #include <txtftn.hxx>
83 #include <ndtxt.hxx>
84 #include <pagedesc.hxx>
85 #include <paratr.hxx>
86 #include <poolfmt.hxx>
87 #include <fmtclbl.hxx>
88 #include <section.hxx>
89 #include <docsh.hxx>
90 #include <IDocumentFieldsAccess.hxx>
91 #include <IDocumentLayoutAccess.hxx>
92 #include <IDocumentMarkAccess.hxx>
93 #include <IDocumentStylePoolAccess.hxx>
94 #include <IDocumentExternalData.hxx>
95 #include <../../core/inc/DocumentRedlineManager.hxx>
96 #include <docufld.hxx>
97 #include <swfltopt.hxx>
98 #include <viewsh.hxx>
99 #include <viewopt.hxx>
100 #include <shellres.hxx>
101 #include <mdiexp.hxx>
102 #include <swerror.h>
103 #include <swtable.hxx>
104 #include <fchrfmt.hxx>
105 #include <charfmt.hxx>
106 #include <unocrsr.hxx>
107 #include <IDocumentSettingAccess.hxx>
108 #include "sprmids.hxx"
110 #include <fltini.hxx>
112 #include "writerwordglue.hxx"
114 #include <ndgrf.hxx>
115 #include <editeng/editids.hrc>
116 #include <txtflcnt.hxx>
117 #include <fmtflcnt.hxx>
118 #include <txatbase.hxx>
120 #include "ww8par2.hxx"
122 #include <com/sun/star/beans/PropertyAttribute.hpp>
123 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
124 #include <com/sun/star/document/XViewDataSupplier.hpp>
125 #include <com/sun/star/document/IndexedPropertyValues.hpp>
126 #include <svl/itemiter.hxx>
128 #include <comphelper/processfactory.hxx>
129 #include <basic/basmgr.hxx>
131 #include "ww8toolbar.hxx"
132 #include <osl/file.hxx>
134 #include <breakit.hxx>
136 #if OSL_DEBUG_LEVEL > 1
137 #include <iostream>
138 #include <dbgoutsw.hxx>
139 #endif
141 #include <svx/hlnkitem.hxx>
142 #include <sfx2/docfile.hxx>
143 #include <swdll.hxx>
144 #include "WW8Sttbf.hxx"
145 #include "WW8FibData.hxx"
146 #include <unordered_set>
147 #include <memory>
149 using namespace ::com::sun::star;
150 using namespace sw::util;
151 using namespace sw::types;
152 using namespace nsHdFtFlags;
154 #include <com/sun/star/i18n/BreakIterator.hpp>
155 #include <com/sun/star/i18n/ScriptType.hpp>
156 #include <unotools/pathoptions.hxx>
157 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
159 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
160 #include <comphelper/sequenceashashmap.hxx>
161 #include <oox/ole/vbaproject.hxx>
162 #include <oox/ole/olestorage.hxx>
163 #include <comphelper/storagehelper.hxx>
164 #include <sfx2/DocumentMetadataAccess.hxx>
165 #include <tools/diagnose_ex.h>
167 static SwMacroInfo* GetMacroInfo( SdrObject* pObj )
169 if ( pObj )
171 sal_uInt16 nCount = pObj->GetUserDataCount();
172 for( sal_uInt16 i = 0; i < nCount; i++ )
174 SdrObjUserData* pData = pObj->GetUserData( i );
175 if( pData && pData->GetInventor() == SdrInventor::ScOrSwDraw
176 && pData->GetId() == SW_UD_IMAPDATA)
178 return dynamic_cast<SwMacroInfo*>(pData);
181 SwMacroInfo* pData = new SwMacroInfo;
182 pObj->AppendUserData(std::unique_ptr<SdrObjUserData>(pData));
183 return pData;
186 return nullptr;
189 static void lclGetAbsPath(OUString& rPath, sal_uInt16 nLevel, SwDocShell const * pDocShell)
191 OUStringBuffer aTmpStr;
192 while( nLevel )
194 aTmpStr.append("../");
195 --nLevel;
197 if (!aTmpStr.isEmpty())
198 aTmpStr.append(rPath);
199 else
200 aTmpStr = rPath;
202 if (!aTmpStr.isEmpty())
204 bool bWasAbs = false;
205 rPath = pDocShell->GetMedium()->GetURLObject().smartRel2Abs( aTmpStr.makeStringAndClear(), bWasAbs ).GetMainURL( INetURLObject::DecodeMechanism::NONE );
206 // full path as stored in SvxURLField must be encoded
210 namespace
212 void lclIgnoreUString32(SvStream& rStrm)
214 sal_uInt32 nChars(0);
215 rStrm.ReadUInt32(nChars);
216 nChars *= 2;
217 rStrm.SeekRel(nChars);
221 void SwWW8ImplReader::ReadEmbeddedData(SvStream& rStrm, SwDocShell const * pDocShell, struct HyperLinksTable& hlStr)
223 // (0x01B8) HLINK
224 // const sal_uInt16 WW8_ID_HLINK = 0x01B8;
225 const sal_uInt32 WW8_HLINK_BODY = 0x00000001; /// Contains file link or URL.
226 const sal_uInt32 WW8_HLINK_ABS = 0x00000002; /// Absolute path.
227 const sal_uInt32 WW8_HLINK_DESCR = 0x00000014; /// Description.
228 const sal_uInt32 WW8_HLINK_MARK = 0x00000008; /// Text mark.
229 const sal_uInt32 WW8_HLINK_FRAME = 0x00000080; /// Target frame.
230 const sal_uInt32 WW8_HLINK_UNC = 0x00000100; /// UNC path.
232 //sal_uInt8 maGuidStdLink[ 16 ] ={
233 // 0xD0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE, 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B };
235 sal_uInt8 const aGuidUrlMoniker[ 16 ] = {
236 0xE0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE, 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B };
238 sal_uInt8 const aGuidFileMoniker[ 16 ] = {
239 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 };
241 sal_uInt8 aGuid[16];
242 sal_uInt32 nFlags(0);
244 rStrm.ReadBytes(aGuid, 16);
245 rStrm.SeekRel( 4 );
246 rStrm.ReadUInt32( nFlags );
248 sal_uInt16 nLevel = 0; // counter for level to climb down in path
249 std::unique_ptr< OUString > xLongName; // link / file name
250 std::unique_ptr< OUString > xShortName; // 8.3-representation of file name
251 std::unique_ptr< OUString > xTextMark; // text mark
253 // description (ignore)
254 if( ::get_flag( nFlags, WW8_HLINK_DESCR ) )
255 lclIgnoreUString32( rStrm );
257 // target frame
258 if( ::get_flag( nFlags, WW8_HLINK_FRAME ) )
260 hlStr.tarFrame = read_uInt32_lenPrefixed_uInt16s_ToOUString(rStrm);
263 // UNC path
264 if( ::get_flag( nFlags, WW8_HLINK_UNC ) )
266 // MS-OSHARED: An unsigned integer that specifies the number of Unicode characters in the
267 // string field, including the null-terminating character.
268 sal_uInt32 nStrLen(0);
269 rStrm.ReadUInt32(nStrLen);
270 if (nStrLen)
272 xLongName.reset(new OUString(read_uInt16s_ToOUString(rStrm, nStrLen - 1)));
273 rStrm.SeekRel(sizeof(sal_Unicode)); // skip null-byte at end
275 lclGetAbsPath( *xLongName, 0 , pDocShell);
277 // file link or URL
278 else if( ::get_flag( nFlags, WW8_HLINK_BODY ) )
280 rStrm.ReadBytes(aGuid, 16);
282 if( memcmp(aGuid, aGuidFileMoniker, 16) == 0 )
284 rStrm.ReadUInt16( nLevel );
285 // MS-OSHARED: An unsigned integer that specifies the number of
286 // ANSI characters in ansiPath, including the terminating NULL character
287 sal_uInt32 nUnits = 0;
288 rStrm.ReadUInt32(nUnits);
289 if (nUnits)
291 OString sStr(read_uInt8s_ToOString(rStrm, nUnits - 1));
292 rStrm.SeekRel(sizeof(sal_uInt8)); // skip null-byte at end
293 xShortName.reset(new OUString(sStr.getStr(), sStr.getLength(), GetCharSetFromLanguage()));
295 rStrm.SeekRel( 24 );
297 sal_uInt32 nStrLen(0);
298 rStrm.ReadUInt32( nStrLen );
299 if( nStrLen )
301 nStrLen = 0;
302 rStrm.ReadUInt32( nStrLen );
303 nStrLen /= 2;
304 rStrm.SeekRel( 2 );
305 // MS-OSHARED: This array MUST not include a terminating NULL character.
306 xLongName.reset(new OUString(read_uInt16s_ToOUString(rStrm, nStrLen)));
307 lclGetAbsPath( *xLongName, nLevel, pDocShell);
309 else
310 lclGetAbsPath( *xShortName, nLevel, pDocShell);
312 else if( memcmp(aGuid, aGuidUrlMoniker, 16) == 0 )
314 // MS-OSHARED: An unsigned integer that specifies the size of this
315 // structure in bytes, excluding the size of the length field. The
316 // value of this field MUST be ... the byte size of the url
317 // field (including the terminating NULL character)
318 sal_uInt32 nStrLen(0);
319 rStrm.ReadUInt32( nStrLen );
320 nStrLen /= 2;
321 if (nStrLen)
323 xLongName.reset(new OUString(read_uInt16s_ToOUString(rStrm, nStrLen - 1)));
324 rStrm.SeekRel(sizeof(sal_Unicode)); // skip null-byte at end
326 if( !::get_flag( nFlags, WW8_HLINK_ABS ) )
327 lclGetAbsPath( *xLongName, 0 ,pDocShell);
329 else
331 SAL_INFO("sw.ww8", "WW8Hyperlink::ReadEmbeddedData - unknown content GUID");
335 // text mark
336 if( ::get_flag( nFlags, WW8_HLINK_MARK ) )
338 xTextMark.reset(new OUString(read_uInt32_lenPrefixed_uInt16s_ToOUString(rStrm)));
341 if (!xLongName && xShortName.get())
343 xLongName.reset( new OUString );
344 *xLongName += *xShortName;
346 else if (!xLongName && xTextMark.get())
347 xLongName.reset( new OUString );
349 if (xLongName)
351 if (xTextMark)
353 if (xLongName->isEmpty())
354 *xTextMark = xTextMark->replace('!', '.');
355 *xLongName += "#" + *xTextMark;
357 hlStr.hLinkAddr = *xLongName;
361 class BasicProjImportHelper
363 SwDocShell& mrDocShell;
364 uno::Reference< uno::XComponentContext > mxCtx;
365 public:
366 explicit BasicProjImportHelper( SwDocShell& rShell ) : mrDocShell( rShell )
368 mxCtx = comphelper::getProcessComponentContext();
370 bool import( const uno::Reference< io::XInputStream >& rxIn );
371 OUString getProjectName();
374 bool BasicProjImportHelper::import( const uno::Reference< io::XInputStream >& rxIn )
376 bool bRet = false;
379 oox::ole::OleStorage root( mxCtx, rxIn, false );
380 oox::StorageRef vbaStg = root.openSubStorage( "Macros" , false );
381 if ( vbaStg.get() )
383 oox::ole::VbaProject aVbaPrj( mxCtx, mrDocShell.GetModel(), "Writer" );
384 bRet = aVbaPrj.importVbaProject( *vbaStg );
387 catch( const uno::Exception& )
389 bRet = false;
391 return bRet;
394 OUString BasicProjImportHelper::getProjectName()
396 OUString sProjName( "Standard" );
397 uno::Reference< beans::XPropertySet > xProps( mrDocShell.GetModel(), uno::UNO_QUERY );
398 if ( xProps.is() )
402 uno::Reference< script::vba::XVBACompatibility > xVBA( xProps->getPropertyValue( "BasicLibraries" ), uno::UNO_QUERY_THROW );
403 sProjName = xVBA->getProjectName();
406 catch( const uno::Exception& )
410 return sProjName;
413 class Sttb : public TBBase
415 struct SBBItem
417 sal_uInt16 cchData;
418 OUString data;
419 SBBItem() : cchData(0){}
421 sal_uInt16 fExtend;
422 sal_uInt16 cData;
423 sal_uInt16 cbExtra;
425 std::vector< SBBItem > dataItems;
427 Sttb(Sttb const&) = delete;
428 Sttb& operator=(Sttb const&) = delete;
430 public:
431 Sttb();
433 bool Read(SvStream &rS) override;
434 OUString getStringAtIndex( sal_uInt32 );
437 Sttb::Sttb()
438 : fExtend(0)
439 , cData(0)
440 , cbExtra(0)
444 bool Sttb::Read( SvStream& rS )
446 SAL_INFO("sw.ww8", "stream pos " << rS.Tell());
447 nOffSet = rS.Tell();
448 rS.ReadUInt16( fExtend ).ReadUInt16( cData ).ReadUInt16( cbExtra );
449 if ( cData )
451 //if they are all going to be empty strings, how many could there be
452 const size_t nMaxPossibleRecords = rS.remainingSize() / sizeof(sal_uInt16);
453 if (cData > nMaxPossibleRecords)
454 return false;
455 for ( sal_Int32 index = 0; index < cData; ++index )
457 SBBItem aItem;
458 rS.ReadUInt16( aItem.cchData );
459 aItem.data = read_uInt16s_ToOUString(rS, aItem.cchData);
460 dataItems.push_back( aItem );
463 return true;
466 OUString
467 Sttb::getStringAtIndex( sal_uInt32 index )
469 OUString aRet;
470 if ( index < dataItems.size() )
471 aRet = dataItems[ index ].data;
472 return aRet;
476 SwMSDffManager::SwMSDffManager( SwWW8ImplReader& rRdr, bool bSkipImages )
477 : SvxMSDffManager(*rRdr.m_pTableStream, rRdr.GetBaseURL(), rRdr.m_xWwFib->m_fcDggInfo,
478 rRdr.m_pDataStream, nullptr, 0, COL_WHITE, rRdr.m_pStrm, bSkipImages),
479 rReader(rRdr), pFallbackStream(nullptr)
481 SetSvxMSDffSettings( GetSvxMSDffSettings() );
482 nSvxMSDffOLEConvFlags = SwMSDffManager::GetFilterFlags();
485 sal_uInt32 SwMSDffManager::GetFilterFlags()
487 sal_uInt32 nFlags(0);
488 const SvtFilterOptions& rOpt = SvtFilterOptions::Get();
489 if (rOpt.IsMathType2Math())
490 nFlags |= OLE_MATHTYPE_2_STARMATH;
491 if (rOpt.IsExcel2Calc())
492 nFlags |= OLE_EXCEL_2_STARCALC;
493 if (rOpt.IsPowerPoint2Impress())
494 nFlags |= OLE_POWERPOINT_2_STARIMPRESS;
495 if (rOpt.IsWinWord2Writer())
496 nFlags |= OLE_WINWORD_2_STARWRITER;
497 return nFlags;
501 * I would like to override the default OLE importing to add a test
502 * and conversion of OCX controls from their native OLE type into our
503 * native nonOLE Form Control Objects.
505 // #i32596# - consider new parameter <_nCalledByGroup>
506 SdrObject* SwMSDffManager::ImportOLE( sal_uInt32 nOLEId,
507 const Graphic& rGrf,
508 const tools::Rectangle& rBoundRect,
509 const tools::Rectangle& rVisArea,
510 const int _nCalledByGroup ) const
512 // #i32596# - no import of OLE object, if it's inside a group.
513 // NOTE: This can be undone, if grouping of Writer fly frames is possible or
514 // if drawing OLE objects are allowed in Writer.
515 if ( _nCalledByGroup > 0 )
517 return nullptr;
520 SdrObject* pRet = nullptr;
521 OUString sStorageName;
522 tools::SvRef<SotStorage> xSrcStg;
523 uno::Reference < embed::XStorage > xDstStg;
524 if( GetOLEStorageName( nOLEId, sStorageName, xSrcStg, xDstStg ))
526 tools::SvRef<SotStorage> xSrc = xSrcStg->OpenSotStorage( sStorageName );
527 OSL_ENSURE(rReader.m_xFormImpl, "No Form Implementation!");
528 css::uno::Reference< css::drawing::XShape > xShape;
529 if ( (!(rReader.m_bIsHeader || rReader.m_bIsFooter)) &&
530 rReader.m_xFormImpl->ReadOCXStream(xSrc,&xShape,true))
532 pRet = GetSdrObjectFromXShape(xShape);
534 else
536 ErrCode nError = ERRCODE_NONE;
537 pRet = CreateSdrOLEFromStorage(
538 *pSdrModel,
539 sStorageName,
540 xSrcStg,
541 xDstStg,
542 rGrf,
543 rBoundRect,
544 rVisArea,
545 pStData,
546 nError,
547 nSvxMSDffOLEConvFlags,
548 css::embed::Aspects::MSOLE_CONTENT,
549 rReader.GetBaseURL());
552 return pRet;
555 void SwMSDffManager::DisableFallbackStream()
557 OSL_ENSURE(!pFallbackStream,
558 "if you're recursive, you're broken");
559 pFallbackStream = pStData2;
560 aOldEscherBlipCache = aEscherBlipCache;
561 aEscherBlipCache.clear();
562 pStData2 = nullptr;
565 void SwMSDffManager::EnableFallbackStream()
567 pStData2 = pFallbackStream;
568 aEscherBlipCache = aOldEscherBlipCache;
569 aOldEscherBlipCache.clear();
570 pFallbackStream = nullptr;
573 sal_uInt16 SwWW8ImplReader::GetToggleAttrFlags() const
575 return m_xCtrlStck ? m_xCtrlStck->GetToggleAttrFlags() : 0;
578 sal_uInt16 SwWW8ImplReader::GetToggleBiDiAttrFlags() const
580 return m_xCtrlStck ? m_xCtrlStck->GetToggleBiDiAttrFlags() : 0;
583 void SwWW8ImplReader::SetToggleAttrFlags(sal_uInt16 nFlags)
585 if (m_xCtrlStck)
586 m_xCtrlStck->SetToggleAttrFlags(nFlags);
589 void SwWW8ImplReader::SetToggleBiDiAttrFlags(sal_uInt16 nFlags)
591 if (m_xCtrlStck)
592 m_xCtrlStck->SetToggleBiDiAttrFlags(nFlags);
595 SdrObject* SwMSDffManager::ProcessObj(SvStream& rSt,
596 DffObjData& rObjData,
597 SvxMSDffClientData& rData,
598 tools::Rectangle& rTextRect,
599 SdrObject* pObj
602 if( !rTextRect.IsEmpty() )
604 SvxMSDffImportData& rImportData = static_cast<SvxMSDffImportData&>(rData);
605 std::unique_ptr<SvxMSDffImportRec> pImpRec(new SvxMSDffImportRec);
607 // fill Import Record with data
608 pImpRec->nShapeId = rObjData.nShapeId;
609 pImpRec->eShapeType = rObjData.eShapeType;
611 rObjData.bClientAnchor = maShapeRecords.SeekToContent( rSt,
612 DFF_msofbtClientAnchor,
613 SEEK_FROM_CURRENT_AND_RESTART );
614 if( rObjData.bClientAnchor )
615 ProcessClientAnchor( rSt,
616 maShapeRecords.Current()->nRecLen,
617 pImpRec->pClientAnchorBuffer, pImpRec->nClientAnchorLen );
619 rObjData.bClientData = maShapeRecords.SeekToContent( rSt,
620 DFF_msofbtClientData,
621 SEEK_FROM_CURRENT_AND_RESTART );
622 if( rObjData.bClientData )
623 ProcessClientData( rSt,
624 maShapeRecords.Current()->nRecLen,
625 pImpRec->pClientDataBuffer, pImpRec->nClientDataLen );
627 // process user (== Winword) defined parameters in 0xF122 record
628 // #i84783# - set special value to determine, if property is provided or not.
629 pImpRec->nLayoutInTableCell = 0xFFFFFFFF;
631 if( maShapeRecords.SeekToContent( rSt,
632 DFF_msofbtUDefProp,
633 SEEK_FROM_CURRENT_AND_RESTART )
634 && maShapeRecords.Current()->nRecLen )
636 sal_uInt32 nBytesLeft = maShapeRecords.Current()->nRecLen;
637 auto nAvailableBytes = rSt.remainingSize();
638 if (nBytesLeft > nAvailableBytes)
640 SAL_WARN("sw.ww8", "Document claimed to have shape record of " << nBytesLeft << " bytes, but only " << nAvailableBytes << " available");
641 nBytesLeft = nAvailableBytes;
643 while( 5 < nBytesLeft )
645 sal_uInt16 nPID(0);
646 rSt.ReadUInt16(nPID);
647 sal_uInt32 nUDData(0);
648 rSt.ReadUInt32(nUDData);
649 if (!rSt.good())
650 break;
651 switch (nPID)
653 case 0x038F: pImpRec->nXAlign = nUDData; break;
654 case 0x0390:
655 pImpRec->nXRelTo = nUDData;
656 break;
657 case 0x0391: pImpRec->nYAlign = nUDData; break;
658 case 0x0392:
659 pImpRec->nYRelTo = nUDData;
660 break;
661 case 0x03BF: pImpRec->nLayoutInTableCell = nUDData; break;
662 case 0x0393:
663 // This seems to correspond to o:hrpct from .docx (even including
664 // the difference that it's in 0.1% even though the .docx spec
665 // says it's in 1%).
666 pImpRec->relativeHorizontalWidth = nUDData;
667 break;
668 case 0x0394:
669 // And this is really just a guess, but a mere presence of this
670 // flag makes a horizontal rule be as wide as the page (unless
671 // overridden by something), so it probably matches o:hr from .docx.
672 pImpRec->isHorizontalRule = true;
673 break;
675 nBytesLeft -= 6;
679 // Text Frame also Title or Outline
680 sal_uInt32 nTextId = GetPropertyValue( DFF_Prop_lTxid, 0 );
681 if( nTextId )
683 SfxItemSet aSet( pSdrModel->GetItemPool() );
685 // Originally anything that as a mso_sptTextBox was created as a
686 // textbox, this was changed to be created as a simple
687 // rect to keep impress happy. For the rest of us we'd like to turn
688 // it back into a textbox again.
689 bool bIsSimpleDrawingTextBox = (pImpRec->eShapeType == mso_sptTextBox);
690 if (!bIsSimpleDrawingTextBox)
692 // Either
693 // a) it's a simple text object or
694 // b) it's a rectangle with text and square wrapping.
695 bIsSimpleDrawingTextBox =
697 (pImpRec->eShapeType == mso_sptTextSimple) ||
699 (pImpRec->eShapeType == mso_sptRectangle)
700 && ShapeHasText(pImpRec->nShapeId, rObjData.rSpHd.GetRecBegFilePos() )
705 // Distance of Textbox to its surrounding Autoshape
706 sal_Int32 nTextLeft = GetPropertyValue( DFF_Prop_dxTextLeft, 91440);
707 sal_Int32 nTextRight = GetPropertyValue( DFF_Prop_dxTextRight, 91440 );
708 sal_Int32 nTextTop = GetPropertyValue( DFF_Prop_dyTextTop, 45720 );
709 sal_Int32 nTextBottom = GetPropertyValue( DFF_Prop_dyTextBottom, 45720 );
711 ScaleEmu( nTextLeft );
712 ScaleEmu( nTextRight );
713 ScaleEmu( nTextTop );
714 ScaleEmu( nTextBottom );
716 sal_Int32 nTextRotationAngle=0;
717 bool bVerticalText = false;
718 if ( IsProperty( DFF_Prop_txflTextFlow ) )
720 MSO_TextFlow eTextFlow = static_cast<MSO_TextFlow>(GetPropertyValue(
721 DFF_Prop_txflTextFlow, 0) & 0xFFFF);
722 switch( eTextFlow )
724 case mso_txflBtoT:
725 nTextRotationAngle = 9000;
726 break;
727 case mso_txflVertN:
728 case mso_txflTtoBN:
729 nTextRotationAngle = 27000;
730 break;
731 case mso_txflTtoBA:
732 bVerticalText = true;
733 break;
734 case mso_txflHorzA:
735 bVerticalText = true;
736 nTextRotationAngle = 9000;
737 break;
738 case mso_txflHorzN:
739 default :
740 break;
744 if (nTextRotationAngle)
746 if (nTextRotationAngle == 9000)
748 long nWidth = rTextRect.GetWidth();
749 rTextRect.SetRight( rTextRect.Left() + rTextRect.GetHeight() );
750 rTextRect.SetBottom( rTextRect.Top() + nWidth );
752 sal_Int32 nOldTextLeft = nTextLeft;
753 sal_Int32 nOldTextRight = nTextRight;
754 sal_Int32 nOldTextTop = nTextTop;
755 sal_Int32 nOldTextBottom = nTextBottom;
757 nTextLeft = nOldTextBottom;
758 nTextRight = nOldTextTop;
759 nTextTop = nOldTextLeft;
760 nTextBottom = nOldTextRight;
762 else if (nTextRotationAngle == 27000)
764 long nWidth = rTextRect.GetWidth();
765 rTextRect.SetRight( rTextRect.Left() + rTextRect.GetHeight() );
766 rTextRect.SetBottom( rTextRect.Top() + nWidth );
768 sal_Int32 nOldTextLeft = nTextLeft;
769 sal_Int32 nOldTextRight = nTextRight;
770 sal_Int32 nOldTextTop = nTextTop;
771 sal_Int32 nOldTextBottom = nTextBottom;
773 nTextLeft = nOldTextTop;
774 nTextRight = nOldTextBottom;
775 nTextTop = nOldTextRight;
776 nTextBottom = nOldTextLeft;
780 if (bIsSimpleDrawingTextBox)
782 SdrObject::Free( pObj );
783 pObj = new SdrRectObj(
784 *pSdrModel,
785 OBJ_TEXT,
786 rTextRect);
789 // The vertical paragraph justification are contained within the
790 // BoundRect so calculate it here
791 tools::Rectangle aNewRect(rTextRect);
792 aNewRect.AdjustBottom( -(nTextTop + nTextBottom) );
793 aNewRect.AdjustRight( -(nTextLeft + nTextRight) );
795 // Only if it's a simple Textbox, Writer can replace the Object
796 // with a Frame, else
797 if( bIsSimpleDrawingTextBox )
799 std::shared_ptr<SvxMSDffShapeInfo> const xTmpRec(
800 new SvxMSDffShapeInfo(0, pImpRec->nShapeId));
802 SvxMSDffShapeInfos_ById::const_iterator const it =
803 GetShapeInfos()->find(xTmpRec);
804 if (it != GetShapeInfos()->end())
806 SvxMSDffShapeInfo& rInfo = **it;
807 pImpRec->bReplaceByFly = rInfo.bReplaceByFly;
810 ApplyAttributes(rSt, aSet, rObjData);
813 if (GetPropertyValue(DFF_Prop_FitTextToShape, 0) & 2)
815 aSet.Put( makeSdrTextAutoGrowHeightItem( true ) );
816 aSet.Put( makeSdrTextMinFrameHeightItem(
817 aNewRect.Bottom() - aNewRect.Top() ) );
818 aSet.Put( makeSdrTextMinFrameWidthItem(
819 aNewRect.Right() - aNewRect.Left() ) );
821 else
823 aSet.Put( makeSdrTextAutoGrowHeightItem( false ) );
824 aSet.Put( makeSdrTextAutoGrowWidthItem( false ) );
827 switch ( static_cast<MSO_WrapMode>(GetPropertyValue( DFF_Prop_WrapText, mso_wrapSquare )) )
829 case mso_wrapNone :
830 aSet.Put( makeSdrTextAutoGrowWidthItem( true ) );
831 pImpRec->bAutoWidth = true;
832 break;
833 case mso_wrapByPoints :
834 aSet.Put( makeSdrTextContourFrameItem( true ) );
835 break;
836 default:
840 // Set distances on Textbox's margins
841 aSet.Put( makeSdrTextLeftDistItem( nTextLeft ) );
842 aSet.Put( makeSdrTextRightDistItem( nTextRight ) );
843 aSet.Put( makeSdrTextUpperDistItem( nTextTop ) );
844 aSet.Put( makeSdrTextLowerDistItem( nTextBottom ) );
845 pImpRec->nDxTextLeft = nTextLeft;
846 pImpRec->nDyTextTop = nTextTop;
847 pImpRec->nDxTextRight = nTextRight;
848 pImpRec->nDyTextBottom = nTextBottom;
850 // Taking the correct default (which is mso_anchorTop)
851 sal_uInt32 eTextAnchor =
852 GetPropertyValue( DFF_Prop_anchorText, mso_anchorTop );
854 SdrTextVertAdjust eTVA = bVerticalText
855 ? SDRTEXTVERTADJUST_BLOCK
856 : SDRTEXTVERTADJUST_CENTER;
857 SdrTextHorzAdjust eTHA = bVerticalText
858 ? SDRTEXTHORZADJUST_CENTER
859 : SDRTEXTHORZADJUST_BLOCK;
861 switch( eTextAnchor )
863 case mso_anchorTop:
865 if ( bVerticalText )
866 eTHA = SDRTEXTHORZADJUST_RIGHT;
867 else
868 eTVA = SDRTEXTVERTADJUST_TOP;
870 break;
871 case mso_anchorTopCentered:
873 if ( bVerticalText )
874 eTHA = SDRTEXTHORZADJUST_RIGHT;
875 else
876 eTVA = SDRTEXTVERTADJUST_TOP;
878 break;
879 case mso_anchorMiddle:
880 break;
881 case mso_anchorMiddleCentered:
882 break;
883 case mso_anchorBottom:
885 if ( bVerticalText )
886 eTHA = SDRTEXTHORZADJUST_LEFT;
887 else
888 eTVA = SDRTEXTVERTADJUST_BOTTOM;
890 break;
891 case mso_anchorBottomCentered:
893 if ( bVerticalText )
894 eTHA = SDRTEXTHORZADJUST_LEFT;
895 else
896 eTVA = SDRTEXTVERTADJUST_BOTTOM;
898 break;
899 default:
903 aSet.Put( SdrTextVertAdjustItem( eTVA ) );
904 aSet.Put( SdrTextHorzAdjustItem( eTHA ) );
906 if (pObj != nullptr)
908 pObj->SetMergedItemSet(aSet);
910 if (bVerticalText)
912 SdrTextObj *pTextObj = dynamic_cast< SdrTextObj* >(pObj);
913 if (pTextObj)
914 pTextObj->SetVerticalWriting(true);
917 if ( bIsSimpleDrawingTextBox )
919 if ( nTextRotationAngle )
921 long nMinWH = rTextRect.GetWidth() < rTextRect.GetHeight() ?
922 rTextRect.GetWidth() : rTextRect.GetHeight();
923 nMinWH /= 2;
924 Point aPivot(rTextRect.TopLeft());
925 aPivot.AdjustX(nMinWH );
926 aPivot.AdjustY(nMinWH );
927 double a = nTextRotationAngle * F_PI18000;
928 pObj->NbcRotate(aPivot, nTextRotationAngle, sin(a), cos(a));
932 if ( ( ( rObjData.nSpFlags & ShapeFlag::FlipV ) || mnFix16Angle || nTextRotationAngle ) && dynamic_cast< SdrObjCustomShape* >( pObj ) )
934 SdrObjCustomShape* pCustomShape = dynamic_cast< SdrObjCustomShape* >( pObj );
935 if (pCustomShape)
937 double fExtraTextRotation = 0.0;
938 if ( mnFix16Angle && !( GetPropertyValue( DFF_Prop_FitTextToShape, 0 ) & 4 ) )
939 { // text is already rotated, we have to take back the object rotation if DFF_Prop_RotateText is false
940 fExtraTextRotation = -mnFix16Angle;
942 if ( rObjData.nSpFlags & ShapeFlag::FlipV ) // sj: in ppt the text is flipped, whereas in word the text
943 { // remains unchanged, so we have to take back the flipping here
944 fExtraTextRotation += 18000.0; // because our core will flip text if the shape is flipped.
946 fExtraTextRotation += nTextRotationAngle;
947 if ( !::basegfx::fTools::equalZero( fExtraTextRotation ) )
949 fExtraTextRotation /= 100.0;
950 SdrCustomShapeGeometryItem aGeometryItem( pCustomShape->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
951 const OUString sTextRotateAngle( "TextRotateAngle" );
952 css::beans::PropertyValue aPropVal;
953 aPropVal.Name = sTextRotateAngle;
954 aPropVal.Value <<= fExtraTextRotation;
955 aGeometryItem.SetPropertyValue( aPropVal );
956 pCustomShape->SetMergedItem( aGeometryItem );
960 else if ( mnFix16Angle )
962 // rotate text with shape ?
963 double a = mnFix16Angle * F_PI18000;
964 pObj->NbcRotate( rObjData.aBoundRect.Center(), mnFix16Angle,
965 sin( a ), cos( a ) );
969 else if( !pObj )
971 // simple rectangular objects are ignored by ImportObj() :-(
972 // this is OK for Draw but not for Calc and Writer
973 // cause here these objects have a default border
974 pObj = new SdrRectObj(
975 *pSdrModel,
976 rTextRect);
978 SfxItemSet aSet( pSdrModel->GetItemPool() );
979 ApplyAttributes( rSt, aSet, rObjData );
981 const SfxPoolItem* pPoolItem=nullptr;
982 SfxItemState eState = aSet.GetItemState( XATTR_FILLCOLOR,
983 false, &pPoolItem );
984 if( SfxItemState::DEFAULT == eState )
985 aSet.Put( XFillColorItem( OUString(), mnDefaultColor ) );
986 pObj->SetMergedItemSet(aSet);
989 // Means that fBehindDocument is set
990 if (GetPropertyValue(DFF_Prop_fPrint, 0) & 0x20)
991 pImpRec->bDrawHell = true;
992 else
993 pImpRec->bDrawHell = false;
994 if (GetPropertyValue(DFF_Prop_fPrint, 0) & 0x02)
995 pImpRec->bHidden = true;
996 pImpRec->nNextShapeId = GetPropertyValue( DFF_Prop_hspNext, 0 );
998 if ( nTextId )
1000 pImpRec->aTextId.nTxBxS = static_cast<sal_uInt16>( nTextId >> 16 );
1001 pImpRec->aTextId.nSequence = static_cast<sal_uInt16>(nTextId);
1004 pImpRec->nDxWrapDistLeft = GetPropertyValue(
1005 DFF_Prop_dxWrapDistLeft, 114935 ) / 635;
1006 pImpRec->nDyWrapDistTop = GetPropertyValue(
1007 DFF_Prop_dyWrapDistTop, 0 ) / 635;
1008 pImpRec->nDxWrapDistRight = GetPropertyValue(
1009 DFF_Prop_dxWrapDistRight, 114935 ) / 635;
1010 pImpRec->nDyWrapDistBottom = GetPropertyValue(
1011 DFF_Prop_dyWrapDistBottom, 0 ) / 635;
1012 // 16.16 fraction times total image width or height, as appropriate.
1014 if (SeekToContent(DFF_Prop_pWrapPolygonVertices, rSt))
1016 pImpRec->pWrapPolygon.reset();
1018 sal_uInt16 nNumElemVert(0), nNumElemMemVert(0), nElemSizeVert(0);
1019 rSt.ReadUInt16( nNumElemVert ).ReadUInt16( nNumElemMemVert ).ReadUInt16( nElemSizeVert );
1020 bool bOk = false;
1021 if (nNumElemVert && ((nElemSizeVert == 8) || (nElemSizeVert == 4)))
1023 //check if there is enough data in the file to make the
1024 //record sane
1025 bOk = rSt.remainingSize() / nElemSizeVert >= nNumElemVert;
1027 if (bOk)
1029 pImpRec->pWrapPolygon.reset( new tools::Polygon(nNumElemVert) );
1030 for (sal_uInt16 i = 0; i < nNumElemVert; ++i)
1032 sal_Int32 nX(0), nY(0);
1033 if (nElemSizeVert == 8)
1034 rSt.ReadInt32( nX ).ReadInt32( nY );
1035 else
1037 sal_Int16 nSmallX(0), nSmallY(0);
1038 rSt.ReadInt16( nSmallX ).ReadInt16( nSmallY );
1039 nX = nSmallX;
1040 nY = nSmallY;
1042 (*(pImpRec->pWrapPolygon))[i].setX( nX );
1043 (*(pImpRec->pWrapPolygon))[i].setY( nY );
1048 pImpRec->nCropFromTop = GetPropertyValue(
1049 DFF_Prop_cropFromTop, 0 );
1050 pImpRec->nCropFromBottom = GetPropertyValue(
1051 DFF_Prop_cropFromBottom, 0 );
1052 pImpRec->nCropFromLeft = GetPropertyValue(
1053 DFF_Prop_cropFromLeft, 0 );
1054 pImpRec->nCropFromRight = GetPropertyValue(
1055 DFF_Prop_cropFromRight, 0 );
1057 sal_uInt32 nLineFlags = GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 );
1059 if ( !IsHardAttribute( DFF_Prop_fLine ) &&
1060 pImpRec->eShapeType == mso_sptPictureFrame )
1062 nLineFlags &= ~0x08;
1065 pImpRec->eLineStyle = (nLineFlags & 8)
1066 ? static_cast<MSO_LineStyle>(GetPropertyValue(
1067 DFF_Prop_lineStyle,
1068 mso_lineSimple ))
1069 : MSO_LineStyle(USHRT_MAX);
1070 pImpRec->eLineDashing = static_cast<MSO_LineDashing>(GetPropertyValue(
1071 DFF_Prop_lineDashing, mso_lineSolid ));
1073 pImpRec->nFlags = rObjData.nSpFlags;
1075 if( pImpRec->nShapeId )
1077 auto pImpRecTmp = pImpRec.get();
1078 // Complement Import Record List
1079 pImpRec->pObj = pObj;
1080 rImportData.insert(std::move(pImpRec));
1082 // Complement entry in Z Order List with a pointer to this Object
1083 // Only store objects which are not deep inside the tree
1084 if( ( rObjData.nCalledByGroup == 0 )
1086 ( (rObjData.nSpFlags & ShapeFlag::Group)
1087 && (rObjData.nCalledByGroup < 2) )
1089 StoreShapeOrder( pImpRecTmp->nShapeId,
1090 ( static_cast<sal_uLong>(pImpRecTmp->aTextId.nTxBxS) << 16 )
1091 + pImpRecTmp->aTextId.nSequence, pObj );
1093 else
1094 pImpRec.reset();
1097 sal_uInt32 nBufferSize = GetPropertyValue( DFF_Prop_pihlShape, 0 );
1098 if( (0 < nBufferSize) && (nBufferSize <= 0xFFFF) && SeekToContent( DFF_Prop_pihlShape, rSt ) )
1100 SvMemoryStream aMemStream;
1101 struct HyperLinksTable hlStr;
1102 sal_uInt16 nRawRecId,nRawRecSize;
1103 aMemStream.WriteUInt16( 0 ).WriteUInt16( nBufferSize );
1105 // copy from DFF stream to memory stream
1106 std::vector< sal_uInt8 > aBuffer( nBufferSize );
1107 if (rSt.ReadBytes(aBuffer.data(), nBufferSize) == nBufferSize)
1109 aMemStream.WriteBytes(aBuffer.data(), nBufferSize);
1110 sal_uInt8 nStreamSize = aMemStream.TellEnd();
1111 aMemStream.Seek( STREAM_SEEK_TO_BEGIN );
1112 bool bRet = 4 <= nStreamSize;
1113 if( bRet )
1114 aMemStream.ReadUInt16( nRawRecId ).ReadUInt16( nRawRecSize );
1115 SwDocShell* pDocShell = rReader.m_pDocShell;
1116 if (pDocShell)
1118 rReader.ReadEmbeddedData(aMemStream, pDocShell, hlStr);
1122 if (pObj && !hlStr.hLinkAddr.isEmpty())
1124 SwMacroInfo* pInfo = GetMacroInfo( pObj );
1125 if( pInfo )
1127 pInfo->SetShapeId( rObjData.nShapeId );
1128 pInfo->SetHlink( hlStr.hLinkAddr );
1129 if (!hlStr.tarFrame.isEmpty())
1130 pInfo->SetTarFrame( hlStr.tarFrame );
1131 OUString aNameStr = GetPropertyString( DFF_Prop_wzName, rSt );
1132 if (!aNameStr.isEmpty())
1133 pInfo->SetName( aNameStr );
1138 return pObj;
1142 * Special FastSave - Attributes
1144 void SwWW8ImplReader::Read_StyleCode( sal_uInt16, const sal_uInt8* pData, short nLen )
1146 if (nLen < 0)
1148 m_bCpxStyle = false;
1149 return;
1151 sal_uInt16 nColl = 0;
1152 if (m_xWwFib->GetFIBVersion() <= ww::eWW2)
1153 nColl = *pData;
1154 else
1155 nColl = SVBT16ToUInt16(pData);
1156 if (nColl < m_vColl.size())
1158 SetTextFormatCollAndListLevel( *m_pPaM, m_vColl[nColl] );
1159 m_bCpxStyle = true;
1164 * Read_Majority is for Majority (103) and Majority50 (108)
1166 void SwWW8ImplReader::Read_Majority( sal_uInt16, const sal_uInt8* , short )
1171 * Stack
1173 void SwWW8FltControlStack::NewAttr(const SwPosition& rPos,
1174 const SfxPoolItem& rAttr)
1176 OSL_ENSURE(RES_TXTATR_FIELD != rAttr.Which(), "probably don't want to put"
1177 "fields into the control stack");
1178 OSL_ENSURE(RES_TXTATR_INPUTFIELD != rAttr.Which(), "probably don't want to put"
1179 "input fields into the control stack");
1180 OSL_ENSURE(RES_TXTATR_ANNOTATION != rAttr.Which(), "probably don't want to put"
1181 "annotations into the control stack");
1182 OSL_ENSURE(RES_FLTR_REDLINE != rAttr.Which(), "probably don't want to put"
1183 "redlines into the control stack");
1184 SwFltControlStack::NewAttr(rPos, rAttr);
1187 SwFltStackEntry* SwWW8FltControlStack::SetAttr(const SwPosition& rPos, sal_uInt16 nAttrId,
1188 bool bTstEnde, long nHand, bool )
1190 SwFltStackEntry *pRet = nullptr;
1191 // Doing a textbox, and using the control stack only as a temporary
1192 // collection point for properties which will are not to be set into
1193 // the real document
1194 if (rReader.m_xPlcxMan && rReader.m_xPlcxMan->GetDoingDrawTextBox())
1196 size_t nCnt = size();
1197 for (size_t i=0; i < nCnt; ++i)
1199 SwFltStackEntry& rEntry = (*this)[i];
1200 if (nAttrId == rEntry.pAttr->Which())
1202 DeleteAndDestroy(i--);
1203 --nCnt;
1207 else // Normal case, set the attribute into the document
1208 pRet = SwFltControlStack::SetAttr(rPos, nAttrId, bTstEnde, nHand);
1209 return pRet;
1212 long GetListFirstLineIndent(const SwNumFormat &rFormat)
1214 OSL_ENSURE( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION,
1215 "<GetListFirstLineIndent> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION" );
1217 SvxAdjust eAdj = rFormat.GetNumAdjust();
1218 long nReverseListIndented;
1219 if (eAdj == SvxAdjust::Right)
1220 nReverseListIndented = -rFormat.GetCharTextDistance();
1221 else if (eAdj == SvxAdjust::Center)
1222 nReverseListIndented = rFormat.GetFirstLineOffset()/2;
1223 else
1224 nReverseListIndented = rFormat.GetFirstLineOffset();
1225 return nReverseListIndented;
1228 static long lcl_GetTrueMargin(const SvxLRSpaceItem &rLR, const SwNumFormat &rFormat,
1229 long &rFirstLinePos)
1231 OSL_ENSURE( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION,
1232 "<lcl_GetTrueMargin> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION" );
1234 const long nBodyIndent = rLR.GetTextLeft();
1235 const long nFirstLineDiff = rLR.GetTextFirstLineOfst();
1236 rFirstLinePos = nBodyIndent + nFirstLineDiff;
1238 const auto nPseudoListBodyIndent = rFormat.GetAbsLSpace();
1239 const long nReverseListIndented = GetListFirstLineIndent(rFormat);
1240 long nExtraListIndent = nPseudoListBodyIndent + nReverseListIndented;
1242 return std::max<long>(nExtraListIndent, 0);
1245 // #i103711#
1246 // #i105414#
1247 void SyncIndentWithList( SvxLRSpaceItem &rLR,
1248 const SwNumFormat &rFormat,
1249 const bool bFirstLineOfstSet,
1250 const bool bLeftIndentSet )
1252 if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
1254 long nWantedFirstLinePos;
1255 long nExtraListIndent = lcl_GetTrueMargin(rLR, rFormat, nWantedFirstLinePos);
1256 rLR.SetTextLeft(nWantedFirstLinePos - nExtraListIndent);
1257 rLR.SetTextFirstLineOfst(0);
1259 else if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
1261 if ( !bFirstLineOfstSet && bLeftIndentSet &&
1262 rFormat.GetFirstLineIndent() != 0 )
1264 rLR.SetTextFirstLineOfst( rFormat.GetFirstLineIndent() );
1266 else if ( bFirstLineOfstSet && !bLeftIndentSet &&
1267 rFormat.GetIndentAt() != 0 )
1269 rLR.SetTextLeft( rFormat.GetIndentAt() );
1271 else if (!bFirstLineOfstSet && !bLeftIndentSet )
1273 if ( rFormat.GetFirstLineIndent() != 0 )
1275 rLR.SetTextFirstLineOfst( rFormat.GetFirstLineIndent() );
1277 if ( rFormat.GetIndentAt() != 0 )
1279 rLR.SetTextLeft( rFormat.GetIndentAt() );
1285 const SwNumFormat* SwWW8FltControlStack::GetNumFormatFromStack(const SwPosition &rPos,
1286 const SwTextNode &rTextNode)
1288 const SwNumFormat *pRet = nullptr;
1289 const SfxPoolItem *pItem = GetStackAttr(rPos, RES_FLTR_NUMRULE);
1290 if (pItem && rTextNode.GetNumRule())
1292 if (rTextNode.IsCountedInList())
1294 OUString sName(static_cast<const SfxStringItem*>(pItem)->GetValue());
1295 const SwNumRule *pRule = pDoc->FindNumRulePtr(sName);
1296 if (pRule)
1297 pRet = GetNumFormatFromSwNumRuleLevel(*pRule, rTextNode.GetActualListLevel());
1300 return pRet;
1303 sal_Int32 SwWW8FltControlStack::GetCurrAttrCP() const
1305 return rReader.GetCurrAttrCP();
1308 bool SwWW8FltControlStack::IsParaEndInCPs(sal_Int32 nStart,sal_Int32 nEnd,bool bSdOD) const
1310 return rReader.IsParaEndInCPs(nStart,nEnd,bSdOD);
1314 * Clear the para end position recorded in reader intermittently
1315 * for the least impact on loading performance.
1317 void SwWW8FltControlStack::ClearParaEndPosition()
1319 if ( !empty() )
1320 return;
1322 rReader.ClearParaEndPosition();
1325 bool SwWW8FltControlStack::CheckSdOD(sal_Int32 nStart,sal_Int32 nEnd)
1327 return rReader.IsParaEndInCPs(nStart,nEnd);
1330 void SwWW8ReferencedFltEndStack::SetAttrInDoc( const SwPosition& rTmpPos,
1331 SwFltStackEntry& rEntry )
1333 switch( rEntry.pAttr->Which() )
1335 case RES_FLTR_BOOKMARK:
1337 // suppress insertion of bookmark, which is recognized as an internal bookmark used for table-of-content
1338 // and which is not referenced.
1339 bool bInsertBookmarkIntoDoc = true;
1341 SwFltBookmark* pFltBookmark = dynamic_cast<SwFltBookmark*>(rEntry.pAttr.get());
1342 if ( pFltBookmark != nullptr && pFltBookmark->IsTOCBookmark() )
1344 const OUString& rName = pFltBookmark->GetName();
1345 std::set< OUString, SwWW8::ltstr >::const_iterator aResult = aReferencedTOCBookmarks.find(rName);
1346 if ( aResult == aReferencedTOCBookmarks.end() )
1348 bInsertBookmarkIntoDoc = false;
1351 if ( bInsertBookmarkIntoDoc )
1353 SwFltEndStack::SetAttrInDoc( rTmpPos, rEntry );
1355 break;
1357 default:
1358 SwFltEndStack::SetAttrInDoc( rTmpPos, rEntry );
1359 break;
1364 void SwWW8FltControlStack::SetAttrInDoc(const SwPosition& rTmpPos,
1365 SwFltStackEntry& rEntry)
1367 switch (rEntry.pAttr->Which())
1369 case RES_LR_SPACE:
1372 Loop over the affected nodes and
1373 a) convert the word style absolute indent to indent relative
1374 to any numbering indent active on the nodes
1375 b) adjust the writer style tabstops relative to the old
1376 paragraph indent to be relative to the new paragraph indent
1378 SwPaM aRegion(rTmpPos);
1379 if (rEntry.MakeRegion(pDoc, aRegion, false))
1381 SvxLRSpaceItem aNewLR( *static_cast<SvxLRSpaceItem*>(rEntry.pAttr.get()) );
1382 sal_uLong nStart = aRegion.Start()->nNode.GetIndex();
1383 sal_uLong nEnd = aRegion.End()->nNode.GetIndex();
1384 for(; nStart <= nEnd; ++nStart)
1386 SwNode* pNode = pDoc->GetNodes()[ nStart ];
1387 if (!pNode || !pNode->IsTextNode())
1388 continue;
1390 SwContentNode* pNd = static_cast<SwContentNode*>(pNode);
1391 SvxLRSpaceItem aOldLR = static_cast<const SvxLRSpaceItem&>(pNd->GetAttr(RES_LR_SPACE));
1393 SwTextNode *pTextNode = static_cast<SwTextNode*>(pNode);
1395 const SwNumFormat* pNum
1396 = GetNumFormatFromStack(*aRegion.GetPoint(), *pTextNode);
1397 if (!pNum)
1399 pNum = GetNumFormatFromTextNode(*pTextNode);
1402 if ( pNum )
1404 // #i103711#
1405 const bool bFirstLineIndentSet =
1406 ( rReader.m_aTextNodesHavingFirstLineOfstSet.end() !=
1407 rReader.m_aTextNodesHavingFirstLineOfstSet.find( pNode ) );
1408 // #i105414#
1409 const bool bLeftIndentSet =
1410 ( rReader.m_aTextNodesHavingLeftIndentSet.end() !=
1411 rReader.m_aTextNodesHavingLeftIndentSet.find( pNode ) );
1412 SyncIndentWithList( aNewLR, *pNum,
1413 bFirstLineIndentSet,
1414 bLeftIndentSet );
1417 if (aNewLR == aOldLR)
1418 continue;
1420 pNd->SetAttr(aNewLR);
1425 break;
1427 case RES_TXTATR_FIELD:
1428 OSL_ENSURE(false, "What is a field doing in the control stack,"
1429 "probably should have been in the endstack");
1430 break;
1432 case RES_TXTATR_ANNOTATION:
1433 OSL_ENSURE(false, "What is an annotation doing in the control stack,"
1434 "probably should have been in the endstack");
1435 break;
1437 case RES_TXTATR_INPUTFIELD:
1438 OSL_ENSURE(false, "What is an input field doing in the control stack,"
1439 "probably should have been in the endstack");
1440 break;
1442 case RES_TXTATR_INETFMT:
1444 SwPaM aRegion(rTmpPos);
1445 if (rEntry.MakeRegion(pDoc, aRegion, false))
1447 SwFrameFormat *pFrame;
1448 // If we have just one single inline graphic then
1449 // don't insert a field for the single frame, set
1450 // the frames hyperlink field attribute directly.
1451 if (nullptr != (pFrame = SwWW8ImplReader::ContainsSingleInlineGraphic(aRegion)))
1453 const SwFormatINetFormat *pAttr = static_cast<const SwFormatINetFormat *>(
1454 rEntry.pAttr.get());
1455 SwFormatURL aURL;
1456 aURL.SetURL(pAttr->GetValue(), false);
1457 aURL.SetTargetFrameName(pAttr->GetTargetFrame());
1458 pFrame->SetFormatAttr(aURL);
1460 else
1462 pDoc->getIDocumentContentOperations().InsertPoolItem(aRegion, *rEntry.pAttr);
1466 break;
1467 default:
1468 SwFltControlStack::SetAttrInDoc(rTmpPos, rEntry);
1469 break;
1473 const SfxPoolItem* SwWW8FltControlStack::GetFormatAttr(const SwPosition& rPos,
1474 sal_uInt16 nWhich)
1476 const SfxPoolItem *pItem = GetStackAttr(rPos, nWhich);
1477 if (!pItem)
1479 SwContentNode const*const pNd = rPos.nNode.GetNode().GetContentNode();
1480 if (!pNd)
1481 pItem = &pDoc->GetAttrPool().GetDefaultItem(nWhich);
1482 else
1485 If we're hunting for the indent on a paragraph and need to use the
1486 parent style indent, then return the indent in msword format, and
1487 not writer format, because that's the style that the filter works
1488 in (naturally)
1490 if (nWhich == RES_LR_SPACE)
1492 SfxItemState eState = SfxItemState::DEFAULT;
1493 if (const SfxItemSet *pSet = pNd->GetpSwAttrSet())
1494 eState = pSet->GetItemState(RES_LR_SPACE, false);
1495 if (eState != SfxItemState::SET && rReader.m_nCurrentColl < rReader.m_vColl.size())
1496 pItem = rReader.m_vColl[rReader.m_nCurrentColl].maWordLR.get();
1500 If we're hunting for a character property, try and exact position
1501 within the text node for lookup
1503 if (pNd->IsTextNode())
1505 const sal_Int32 nPos = rPos.nContent.GetIndex();
1506 m_xScratchSet.reset(new SfxItemSet(pDoc->GetAttrPool(), {{nWhich, nWhich}}));
1507 if (pNd->GetTextNode()->GetParaAttr(*m_xScratchSet, nPos, nPos))
1508 pItem = m_xScratchSet->GetItem(nWhich);
1511 if (!pItem)
1512 pItem = &pNd->GetAttr(nWhich);
1515 return pItem;
1518 const SfxPoolItem* SwWW8FltControlStack::GetStackAttr(const SwPosition& rPos,
1519 sal_uInt16 nWhich)
1521 SwFltPosition aFltPos(rPos);
1523 size_t nSize = size();
1524 while (nSize)
1526 const SwFltStackEntry& rEntry = (*this)[ --nSize ];
1527 if (rEntry.pAttr->Which() == nWhich)
1529 if ( (rEntry.bOpen) ||
1531 (rEntry.m_aMkPos.m_nNode <= aFltPos.m_nNode) &&
1532 (rEntry.m_aPtPos.m_nNode >= aFltPos.m_nNode) &&
1533 (rEntry.m_aMkPos.m_nContent <= aFltPos.m_nContent) &&
1534 (rEntry.m_aPtPos.m_nContent > aFltPos.m_nContent)
1538 * e.g. half-open range [0-3) so asking for properties at 3
1539 * means props that end at 3 are not included
1542 return rEntry.pAttr.get();
1546 return nullptr;
1549 bool SwWW8FltRefStack::IsFootnoteEdnBkmField(
1550 const SwFormatField& rFormatField,
1551 sal_uInt16& rBkmNo)
1553 const SwField* pField = rFormatField.GetField();
1554 sal_uInt16 nSubType;
1555 if(pField && (SwFieldIds::GetRef == pField->Which())
1556 && ((REF_FOOTNOTE == (nSubType = pField->GetSubType())) || (REF_ENDNOTE == nSubType))
1557 && !static_cast<const SwGetRefField*>(pField)->GetSetRefName().isEmpty())
1559 const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1560 IDocumentMarkAccess::const_iterator_t ppBkmk =
1561 pMarkAccess->findMark( static_cast<const SwGetRefField*>(pField)->GetSetRefName() );
1562 if(ppBkmk != pMarkAccess->getAllMarksEnd())
1564 // find Sequence No of corresponding Foot-/Endnote
1565 rBkmNo = ppBkmk - pMarkAccess->getAllMarksBegin();
1566 return true;
1569 return false;
1572 void SwWW8FltRefStack::SetAttrInDoc(const SwPosition& rTmpPos,
1573 SwFltStackEntry& rEntry)
1575 switch (rEntry.pAttr->Which())
1578 Look up these in our lists of bookmarks that were changed to
1579 variables, and replace the ref field with a var field, otherwise
1580 do normal (?) strange stuff
1582 case RES_TXTATR_FIELD:
1583 case RES_TXTATR_ANNOTATION:
1584 case RES_TXTATR_INPUTFIELD:
1586 SwNodeIndex aIdx(rEntry.m_aMkPos.m_nNode, 1);
1587 SwPaM aPaM(aIdx, rEntry.m_aMkPos.m_nContent);
1589 SwFormatField& rFormatField = *static_cast<SwFormatField*>(rEntry.pAttr.get());
1590 SwField* pField = rFormatField.GetField();
1592 if (!RefToVar(pField, rEntry))
1594 sal_uInt16 nBkmNo;
1595 if( IsFootnoteEdnBkmField(rFormatField, nBkmNo) )
1597 ::sw::mark::IMark const * const pMark = pDoc->getIDocumentMarkAccess()->getAllMarksBegin()[nBkmNo];
1599 const SwPosition& rBkMrkPos = pMark->GetMarkPos();
1601 SwTextNode* pText = rBkMrkPos.nNode.GetNode().GetTextNode();
1602 if( pText && rBkMrkPos.nContent.GetIndex() )
1604 SwTextAttr* const pFootnote = pText->GetTextAttrForCharAt(
1605 rBkMrkPos.nContent.GetIndex()-1, RES_TXTATR_FTN );
1606 if( pFootnote )
1608 sal_uInt16 nRefNo = static_cast<SwTextFootnote*>(pFootnote)->GetSeqRefNo();
1610 static_cast<SwGetRefField*>(pField)->SetSeqNo( nRefNo );
1612 if( pFootnote->GetFootnote().IsEndNote() )
1613 static_cast<SwGetRefField*>(pField)->SetSubType(REF_ENDNOTE);
1619 pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, *rEntry.pAttr);
1620 MoveAttrs(*aPaM.GetPoint());
1622 break;
1623 case RES_FLTR_TOX:
1624 SwFltEndStack::SetAttrInDoc(rTmpPos, rEntry);
1625 break;
1626 default:
1627 case RES_FLTR_BOOKMARK:
1628 OSL_ENSURE(false, "EndStck used with non field, not what we want");
1629 SwFltEndStack::SetAttrInDoc(rTmpPos, rEntry);
1630 break;
1635 For styles we will do our tabstop arithmetic in word style and adjust them to
1636 writer style after all the styles have been finished and the dust settles as
1637 to what affects what.
1639 For explicit attributes we turn the adjusted writer tabstops back into 0 based
1640 word indexes and we'll turn them back into writer indexes when setting them
1641 into the document. If explicit left indent exist which affects them, then this
1642 is handled when the explicit left indent is set into the document
1644 void SwWW8ImplReader::Read_Tab(sal_uInt16 , const sal_uInt8* pData, short nLen)
1646 if (nLen < 0)
1648 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_PARATR_TABSTOP);
1649 return;
1652 sal_uInt8 nDel = (nLen > 0) ? pData[0] : 0;
1653 const sal_uInt8* pDel = pData + 1; // Del - Array
1655 sal_uInt8 nIns = (nLen > nDel*2+1) ? pData[nDel*2+1] : 0;
1656 const sal_uInt8* pIns = pData + 2*nDel + 2; // Ins - Array
1658 short nRequiredLength = 2 + 2*nDel + 2*nIns + 1*nIns;
1659 if (nRequiredLength > nLen)
1661 // would require more data than available to describe!
1662 // discard invalid record
1663 nIns = 0;
1664 nDel = 0;
1667 WW8_TBD const * pTyp = reinterpret_cast<WW8_TBD const *>(pData + 2*nDel + 2*nIns + 2); // Type Array
1669 std::shared_ptr<SvxTabStopItem> aAttr(std::make_shared<SvxTabStopItem>(0, 0, SvxTabAdjust::Default, RES_PARATR_TABSTOP));
1671 const SwFormat * pSty = nullptr;
1672 sal_uInt16 nTabBase;
1673 if (m_pCurrentColl && m_nCurrentColl < m_vColl.size()) // StyleDef
1675 nTabBase = m_vColl[m_nCurrentColl].m_nBase;
1676 if (nTabBase < m_vColl.size()) // Based On
1677 pSty = m_vColl[nTabBase].m_pFormat;
1679 else
1680 { // Text
1681 nTabBase = m_nCurrentColl;
1682 if (m_nCurrentColl < m_vColl.size())
1683 pSty = m_vColl[m_nCurrentColl].m_pFormat;
1684 //TODO: figure out else here
1687 bool bFound = false;
1688 std::unordered_set<size_t> aLoopWatch;
1689 while (pSty && !bFound)
1691 const SfxPoolItem* pTabs;
1692 bFound = pSty->GetAttrSet().GetItemState(RES_PARATR_TABSTOP, false,
1693 &pTabs) == SfxItemState::SET;
1694 if( bFound )
1696 aAttr.reset(static_cast<SvxTabStopItem*>(pTabs->Clone()));
1698 else
1700 sal_uInt16 nOldTabBase = nTabBase;
1701 // If based on another
1702 if (nTabBase < m_vColl.size())
1703 nTabBase = m_vColl[nTabBase].m_nBase;
1705 if (
1706 nTabBase < m_vColl.size() &&
1707 nOldTabBase != nTabBase &&
1708 nTabBase != ww::stiNil
1711 // #i61789: Stop searching when next style is the same as the
1712 // current one (prevent loop)
1713 aLoopWatch.insert(reinterpret_cast<size_t>(pSty));
1714 if (nTabBase < m_vColl.size())
1715 pSty = m_vColl[nTabBase].m_pFormat;
1716 //TODO figure out the else branch
1718 if (aLoopWatch.find(reinterpret_cast<size_t>(pSty)) !=
1719 aLoopWatch.end())
1720 pSty = nullptr;
1722 else
1723 pSty = nullptr; // Give up on the search
1727 SvxTabStop aTabStop;
1728 for (short i=0; i < nDel; ++i)
1730 sal_uInt16 nPos = aAttr->GetPos(SVBT16ToUInt16(pDel + i*2));
1731 if( nPos != SVX_TAB_NOTFOUND )
1732 aAttr->Remove( nPos );
1735 for (short i=0; i < nIns; ++i)
1737 short nPos = SVBT16ToUInt16(pIns + i*2);
1738 aTabStop.GetTabPos() = nPos;
1739 switch( pTyp[i].aBits1 & 0x7 ) // pTyp[i].jc
1741 case 0:
1742 aTabStop.GetAdjustment() = SvxTabAdjust::Left;
1743 break;
1744 case 1:
1745 aTabStop.GetAdjustment() = SvxTabAdjust::Center;
1746 break;
1747 case 2:
1748 aTabStop.GetAdjustment() = SvxTabAdjust::Right;
1749 break;
1750 case 3:
1751 aTabStop.GetAdjustment() = SvxTabAdjust::Decimal;
1752 break;
1753 case 4:
1754 continue; // Ignore Bar
1757 switch( pTyp[i].aBits1 >> 3 & 0x7 )
1759 case 0:
1760 aTabStop.GetFill() = ' ';
1761 break;
1762 case 1:
1763 aTabStop.GetFill() = '.';
1764 break;
1765 case 2:
1766 aTabStop.GetFill() = '-';
1767 break;
1768 case 3:
1769 case 4:
1770 aTabStop.GetFill() = '_';
1771 break;
1774 sal_uInt16 nPos2 = aAttr->GetPos( nPos );
1775 if (nPos2 != SVX_TAB_NOTFOUND)
1776 aAttr->Remove(nPos2); // Or else Insert() refuses
1777 aAttr->Insert(aTabStop);
1780 if (nIns || nDel)
1781 NewAttr(*aAttr);
1782 else
1784 // Here we have a tab definition which inserts no extra tabs, or deletes
1785 // no existing tabs. An older version of writer is probably the creator
1786 // of the document :-( . So if we are importing a style we can just
1787 // ignore it. But if we are importing into text we cannot as during
1788 // text SwWW8ImplReader::Read_Tab is called at the begin and end of
1789 // the range the attrib affects, and ignoring it would upset the
1790 // balance
1791 if (!m_pCurrentColl) // not importing into a style
1793 SvxTabStopItem aOrig = pSty ?
1794 ItemGet<SvxTabStopItem>(*pSty, RES_PARATR_TABSTOP) :
1795 DefaultItemGet<SvxTabStopItem>(m_rDoc, RES_PARATR_TABSTOP);
1796 NewAttr(aOrig);
1802 * DOP
1804 void SwWW8ImplReader::ImportDop()
1806 // correct the LastPrinted date in DocumentProperties
1807 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
1808 m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
1809 uno::Reference<document::XDocumentProperties> xDocuProps(
1810 xDPS->getDocumentProperties());
1811 OSL_ENSURE(xDocuProps.is(), "DocumentProperties is null");
1812 if (xDocuProps.is())
1814 DateTime aLastPrinted(
1815 msfilter::util::DTTM2DateTime(m_xWDop->dttmLastPrint));
1816 ::util::DateTime uDT = aLastPrinted.GetUNODateTime();
1817 xDocuProps->setPrintDate(uDT);
1820 // COMPATIBILITY FLAGS START
1822 // #i78951# - remember the unknown compatibility options
1823 // so as to export them out
1824 m_rDoc.getIDocumentSettingAccess().Setn32DummyCompatibilityOptions1(m_xWDop->GetCompatibilityOptions());
1825 m_rDoc.getIDocumentSettingAccess().Setn32DummyCompatibilityOptions2(m_xWDop->GetCompatibilityOptions2());
1827 // The distance between two paragraphs is the sum of the bottom distance of
1828 // the first paragraph and the top distance of the second one
1829 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::PARA_SPACE_MAX, m_xWDop->fDontUseHTMLAutoSpacing);
1830 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES, true );
1831 // move tabs on alignment
1832 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TAB_COMPAT, true);
1833 // #i24363# tab stops relative to indent
1834 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TABS_RELATIVE_TO_INDENT, false);
1835 // tdf#117923
1836 m_rDoc.getIDocumentSettingAccess().set(
1837 DocumentSettingId::APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING, true);
1839 // Import Default Tabs
1840 long nDefTabSiz = m_xWDop->dxaTab;
1841 if( nDefTabSiz < 56 )
1842 nDefTabSiz = 709;
1844 // We want exactly one DefaultTab
1845 SvxTabStopItem aNewTab( 1, sal_uInt16(nDefTabSiz), SvxTabAdjust::Default, RES_PARATR_TABSTOP );
1846 const_cast<SvxTabStop&>(aNewTab[0]).GetAdjustment() = SvxTabAdjust::Default;
1848 m_rDoc.GetAttrPool().SetPoolDefaultItem( aNewTab );
1850 // Import zoom factor
1851 if (m_xWDop->wScaleSaved)
1853 //Import zoom type
1854 sal_Int16 nZoomType;
1855 switch (m_xWDop->zkSaved) {
1856 case 1: nZoomType = sal_Int16(SvxZoomType::WHOLEPAGE); break;
1857 case 2: nZoomType = sal_Int16(SvxZoomType::PAGEWIDTH); break;
1858 case 3: nZoomType = sal_Int16(SvxZoomType::OPTIMAL); break;
1859 default: nZoomType = sal_Int16(SvxZoomType::PERCENT); break;
1861 uno::Sequence<beans::PropertyValue> aViewProps( comphelper::InitPropertySequence({
1862 { "ZoomFactor", uno::Any(sal_Int16(m_xWDop->wScaleSaved)) },
1863 { "VisibleBottom", uno::Any(sal_Int32(0)) },
1864 { "ZoomType", uno::Any(nZoomType) }
1865 }));
1867 uno::Reference< uno::XComponentContext > xComponentContext(comphelper::getProcessComponentContext());
1868 uno::Reference<container::XIndexContainer> xBox = document::IndexedPropertyValues::create(xComponentContext);
1869 xBox->insertByIndex(sal_Int32(0), uno::makeAny(aViewProps));
1870 uno::Reference<document::XViewDataSupplier> xViewDataSupplier(m_pDocShell->GetModel(), uno::UNO_QUERY);
1871 xViewDataSupplier->setViewData(xBox);
1874 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::USE_VIRTUAL_DEVICE, !m_xWDop->fUsePrinterMetrics);
1875 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::USE_HIRES_VIRTUAL_DEVICE, true);
1876 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::ADD_FLY_OFFSETS, true );
1877 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::ADD_EXT_LEADING, !m_xWDop->fNoLeading);
1878 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::OLD_NUMBERING, false);
1879 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING, false); // #i47448#
1880 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK, !m_xWDop->fExpShRtn); // #i49277#, #i56856#
1881 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::DO_NOT_RESET_PARA_ATTRS_FOR_NUM_FONT, false); // #i53199#
1882 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::OLD_LINE_SPACING, false);
1884 // #i25901# - set new compatibility option
1885 // 'Add paragraph and table spacing at bottom of table cells'
1886 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS, true);
1888 // #i11860# - set new compatibility option
1889 // 'Use former object positioning' to <false>
1890 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::USE_FORMER_OBJECT_POS, false);
1892 // #i27767# - set new compatibility option
1893 // 'Consider Wrapping mode when positioning object' to <true>
1894 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION, true);
1896 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::USE_FORMER_TEXT_WRAPPING, false); // #i13832#, #i24135#
1898 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TABLE_ROW_KEEP, true); //SetTableRowKeep( true );
1900 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::IGNORE_TABS_AND_BLANKS_FOR_LINE_CALCULATION, true); // #i3952#
1902 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::INVERT_BORDER_SPACING, true);
1903 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::COLLAPSE_EMPTY_CELL_PARA, true);
1904 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TAB_OVERFLOW, true);
1905 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::UNBREAKABLE_NUMBERINGS, true);
1906 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::CLIPPED_PICTURES, true);
1907 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TAB_OVER_MARGIN, true);
1908 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::SURROUND_TEXT_WRAP_SMALL, true);
1909 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::PROP_LINE_SPACING_SHRINKS_FIRST_LINE, true);
1911 // COMPATIBILITY FLAGS END
1913 // Import magic doptypography information, if its there
1914 if (m_xWwFib->m_nFib > 105)
1915 ImportDopTypography(m_xWDop->doptypography);
1917 // disable form design mode to be able to use imported controls directly
1918 // #i31239# always disable form design mode, not only in protected docs
1919 uno::Reference<beans::XPropertySet> xDocProps(m_pDocShell->GetModel(), uno::UNO_QUERY);
1920 if (xDocProps.is())
1922 uno::Reference<beans::XPropertySetInfo> xInfo = xDocProps->getPropertySetInfo();
1923 if (xInfo.is())
1925 if (xInfo->hasPropertyByName("ApplyFormDesignMode"))
1926 xDocProps->setPropertyValue("ApplyFormDesignMode", css::uno::makeAny(false));
1930 // Still allow editing of form fields.
1931 if (!m_xWDop->fProtEnabled)
1932 m_pDocShell->SetModifyPasswordHash(m_xWDop->lKeyProtDoc);
1933 else if ( xDocProps.is() )
1935 comphelper::SequenceAsHashMap aGrabBag(xDocProps->getPropertyValue("InteropGrabBag"));
1936 aGrabBag["FormPasswordHash"] <<= m_xWDop->lKeyProtDoc;
1937 xDocProps->setPropertyValue("InteropGrabBag", uno::Any(aGrabBag.getAsConstPropertyValueList()));
1940 const SvtFilterOptions& rOpt = SvtFilterOptions::Get();
1941 if (rOpt.IsUseEnhancedFields())
1942 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::PROTECT_FORM, m_xWDop->fProtEnabled );
1945 void SwWW8ImplReader::ImportDopTypography(const WW8DopTypography &rTypo)
1947 switch (rTypo.m_iLevelOfKinsoku)
1949 case 2: // custom
1951 i18n::ForbiddenCharacters aForbidden(rTypo.m_rgxchFPunct,
1952 rTypo.m_rgxchLPunct);
1953 m_rDoc.getIDocumentSettingAccess().setForbiddenCharacters(rTypo.GetConvertedLang(),
1954 aForbidden);
1955 // Obviously cannot set the standard level 1 for japanese, so
1956 // bail out now while we can.
1957 if (rTypo.GetConvertedLang() == LANGUAGE_JAPANESE)
1958 return;
1960 break;
1961 default:
1962 break;
1966 This MS hack means that level 2 of japanese is not in operation, so we put
1967 in what we know are the MS defaults, there is a complementary reverse
1968 hack in the writer. Its our default as well, but we can set it anyway
1969 as a flag for later.
1971 if (!rTypo.m_reserved2)
1973 i18n::ForbiddenCharacters aForbidden(WW8DopTypography::GetJapanNotBeginLevel1(),
1974 WW8DopTypography::GetJapanNotEndLevel1());
1975 m_rDoc.getIDocumentSettingAccess().setForbiddenCharacters(LANGUAGE_JAPANESE,aForbidden);
1978 m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::KERN_ASIAN_PUNCTUATION, bool(rTypo.m_fKerningPunct));
1979 m_rDoc.getIDocumentSettingAccess().setCharacterCompressionType(static_cast<CharCompressType>(rTypo.m_iJustification));
1983 * Footnotes and Endnotes
1985 WW8ReaderSave::WW8ReaderSave(SwWW8ImplReader* pRdr ,WW8_CP nStartCp) :
1986 maTmpPos(*pRdr->m_pPaM->GetPoint()),
1987 mxOldStck(std::move(pRdr->m_xCtrlStck)),
1988 mxOldAnchorStck(std::move(pRdr->m_xAnchorStck)),
1989 mxOldRedlines(std::move(pRdr->m_xRedlineStack)),
1990 mxOldPlcxMan(pRdr->m_xPlcxMan),
1991 mpWFlyPara(std::move(pRdr->m_xWFlyPara)),
1992 mpSFlyPara(std::move(pRdr->m_xSFlyPara)),
1993 mpPreviousNumPaM(pRdr->m_pPreviousNumPaM),
1994 mpPrevNumRule(pRdr->m_pPrevNumRule),
1995 mxTableDesc(std::move(pRdr->m_xTableDesc)),
1996 mnInTable(pRdr->m_nInTable),
1997 mnCurrentColl(pRdr->m_nCurrentColl),
1998 mcSymbol(pRdr->m_cSymbol),
1999 mbIgnoreText(pRdr->m_bIgnoreText),
2000 mbSymbol(pRdr->m_bSymbol),
2001 mbHdFtFootnoteEdn(pRdr->m_bHdFtFootnoteEdn),
2002 mbTxbxFlySection(pRdr->m_bTxbxFlySection),
2003 mbAnl(pRdr->m_bAnl),
2004 mbInHyperlink(pRdr->m_bInHyperlink),
2005 mbPgSecBreak(pRdr->m_bPgSecBreak),
2006 mbWasParaEnd(pRdr->m_bWasParaEnd),
2007 mbHasBorder(pRdr->m_bHasBorder),
2008 mbFirstPara(pRdr->m_bFirstPara)
2010 pRdr->m_bSymbol = false;
2011 pRdr->m_bHdFtFootnoteEdn = true;
2012 pRdr->m_bTxbxFlySection = pRdr->m_bAnl = pRdr->m_bPgSecBreak = pRdr->m_bWasParaEnd
2013 = pRdr->m_bHasBorder = false;
2014 pRdr->m_bFirstPara = true;
2015 pRdr->m_nInTable = 0;
2016 pRdr->m_pPreviousNumPaM = nullptr;
2017 pRdr->m_pPrevNumRule = nullptr;
2018 pRdr->m_nCurrentColl = 0;
2020 pRdr->m_xCtrlStck.reset(new SwWW8FltControlStack(&pRdr->m_rDoc, pRdr->m_nFieldFlags,
2021 *pRdr));
2023 pRdr->m_xRedlineStack.reset(new sw::util::RedlineStack(pRdr->m_rDoc));
2025 pRdr->m_xAnchorStck.reset(new SwWW8FltAnchorStack(&pRdr->m_rDoc, pRdr->m_nFieldFlags));
2027 // Save the attribute manager: we need this as the newly created PLCFx Manager
2028 // access the same FKPs as the old one and their Start-End position changes.
2029 if (pRdr->m_xPlcxMan)
2030 pRdr->m_xPlcxMan->SaveAllPLCFx(maPLCFxSave);
2032 if (nStartCp != -1)
2034 pRdr->m_xPlcxMan.reset(new WW8PLCFMan(pRdr->m_xSBase.get(),
2035 mxOldPlcxMan->GetManType(), nStartCp));
2038 maOldApos.push_back(false);
2039 maOldApos.swap(pRdr->m_aApos);
2040 maOldFieldStack.swap(pRdr->m_aFieldStack);
2043 void WW8ReaderSave::Restore( SwWW8ImplReader* pRdr )
2045 pRdr->m_xWFlyPara = std::move(mpWFlyPara);
2046 pRdr->m_xSFlyPara = std::move(mpSFlyPara);
2047 pRdr->m_pPreviousNumPaM = mpPreviousNumPaM;
2048 pRdr->m_pPrevNumRule = mpPrevNumRule;
2049 pRdr->m_xTableDesc = std::move(mxTableDesc);
2050 pRdr->m_cSymbol = mcSymbol;
2051 pRdr->m_bSymbol = mbSymbol;
2052 pRdr->m_bIgnoreText = mbIgnoreText;
2053 pRdr->m_bHdFtFootnoteEdn = mbHdFtFootnoteEdn;
2054 pRdr->m_bTxbxFlySection = mbTxbxFlySection;
2055 pRdr->m_nInTable = mnInTable;
2056 pRdr->m_bAnl = mbAnl;
2057 pRdr->m_bInHyperlink = mbInHyperlink;
2058 pRdr->m_bWasParaEnd = mbWasParaEnd;
2059 pRdr->m_bPgSecBreak = mbPgSecBreak;
2060 pRdr->m_nCurrentColl = mnCurrentColl;
2061 pRdr->m_bHasBorder = mbHasBorder;
2062 pRdr->m_bFirstPara = mbFirstPara;
2064 // Close all attributes as attributes could be created that extend the Fly
2065 pRdr->DeleteCtrlStack();
2066 pRdr->m_xCtrlStck = std::move(mxOldStck);
2068 pRdr->m_xRedlineStack->closeall(*pRdr->m_pPaM->GetPoint());
2069 pRdr->m_aFrameRedlines.emplace(std::move(pRdr->m_xRedlineStack));
2070 pRdr->m_xRedlineStack = std::move(mxOldRedlines);
2072 pRdr->DeleteAnchorStack();
2073 pRdr->m_xAnchorStck = std::move(mxOldAnchorStck);
2075 *pRdr->m_pPaM->GetPoint() = maTmpPos;
2077 if (mxOldPlcxMan != pRdr->m_xPlcxMan)
2078 pRdr->m_xPlcxMan = mxOldPlcxMan;
2079 if (pRdr->m_xPlcxMan)
2080 pRdr->m_xPlcxMan->RestoreAllPLCFx(maPLCFxSave);
2081 pRdr->m_aApos.swap(maOldApos);
2082 pRdr->m_aFieldStack.swap(maOldFieldStack);
2085 void SwWW8ImplReader::Read_HdFtFootnoteText( const SwNodeIndex* pSttIdx,
2086 WW8_CP nStartCp, WW8_CP nLen, ManTypes nType )
2088 if (nStartCp < 0 || nLen < 0)
2089 return;
2091 // Saves Flags (amongst other things) and resets them
2092 WW8ReaderSave aSave( this );
2094 m_pPaM->GetPoint()->nNode = pSttIdx->GetIndex() + 1;
2095 m_pPaM->GetPoint()->nContent.Assign( m_pPaM->GetContentNode(), 0 );
2097 // Read Text for Header, Footer or Footnote
2098 ReadText( nStartCp, nLen, nType ); // Ignore Sepx when doing so
2099 aSave.Restore( this );
2103 * Use authornames, if not available fall back to initials.
2105 long SwWW8ImplReader::Read_And(WW8PLCFManResult* pRes)
2107 WW8PLCFx_SubDoc* pSD = m_xPlcxMan->GetAtn();
2108 if (!pSD)
2109 return 0;
2111 const void* pData = pSD->GetData();
2112 if (!pData)
2113 return 0;
2115 OUString sAuthor;
2116 OUString sInitials;
2117 if( m_bVer67 )
2119 const WW67_ATRD* pDescri = static_cast<const WW67_ATRD*>(pData);
2120 const OUString* pA = GetAnnotationAuthor(SVBT16ToUInt16(pDescri->ibst));
2121 if (pA)
2122 sAuthor = *pA;
2123 else
2125 const sal_uInt8 nLen = std::min<sal_uInt8>(pDescri->xstUsrInitl[0],
2126 SAL_N_ELEMENTS(pDescri->xstUsrInitl)-1);
2127 sAuthor = OUString(pDescri->xstUsrInitl + 1, nLen, RTL_TEXTENCODING_MS_1252);
2130 else
2132 const WW8_ATRD* pDescri = static_cast<const WW8_ATRD*>(pData);
2134 const sal_uInt16 nLen = std::min<sal_uInt16>(SVBT16ToUInt16(pDescri->xstUsrInitl[0]),
2135 SAL_N_ELEMENTS(pDescri->xstUsrInitl)-1);
2136 OUStringBuffer aBuf;
2137 aBuf.setLength(nLen);
2138 for(sal_uInt16 nIdx = 1; nIdx <= nLen; ++nIdx)
2139 aBuf[nIdx-1] = SVBT16ToUInt16(pDescri->xstUsrInitl[nIdx]);
2140 sInitials = aBuf.makeStringAndClear();
2143 if (const OUString* pA = GetAnnotationAuthor(SVBT16ToUInt16(pDescri->ibst)))
2144 sAuthor = *pA;
2145 else
2146 sAuthor = sInitials;
2149 sal_uInt32 nDateTime = 0;
2151 if (sal_uInt8 * pExtended = m_xPlcxMan->GetExtendedAtrds()) // Word < 2002 has no date data for comments
2153 sal_uLong nIndex = pSD->GetIdx() & 0xFFFF; // Index is (stupidly) multiplexed for WW8PLCFx_SubDocs
2154 if (m_xWwFib->m_lcbAtrdExtra/18 > nIndex)
2155 nDateTime = SVBT32ToUInt32(*reinterpret_cast<SVBT32*>(pExtended+(nIndex*18)));
2158 DateTime aDate = msfilter::util::DTTM2DateTime(nDateTime);
2160 OUString sText;
2161 std::unique_ptr<OutlinerParaObject> pOutliner = ImportAsOutliner( sText, pRes->nCp2OrIdx,
2162 pRes->nCp2OrIdx + pRes->nMemLen, MAN_AND );
2164 m_pFormatOfJustInsertedApo = nullptr;
2165 SwPostItField aPostIt(
2166 static_cast<SwPostItFieldType*>(m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Postit)), sAuthor,
2167 sText, sInitials, OUString(), aDate );
2168 aPostIt.SetTextObject(std::move(pOutliner));
2170 SwPaM aEnd(*m_pPaM->End(), *m_pPaM->End());
2171 m_xCtrlStck->NewAttr(*aEnd.GetPoint(), SvxCharHiddenItem(false, RES_CHRATR_HIDDEN));
2172 m_rDoc.getIDocumentContentOperations().InsertPoolItem(aEnd, SwFormatField(aPostIt));
2173 m_xCtrlStck->SetAttr(*aEnd.GetPoint(), RES_CHRATR_HIDDEN);
2174 // If this is a range, make sure that it ends after the just inserted character, not before it.
2175 m_xReffedStck->MoveAttrs(*aEnd.GetPoint(), SwFltControlStack::MoveAttrsMode::POSTIT_INSERTED);
2177 return 0;
2180 void SwWW8ImplReader::Read_HdFtTextAsHackedFrame(WW8_CP nStart, WW8_CP nLen,
2181 SwFrameFormat const &rHdFtFormat, sal_uInt16 nPageWidth)
2183 const SwNodeIndex* pSttIdx = rHdFtFormat.GetContent().GetContentIdx();
2184 OSL_ENSURE(pSttIdx, "impossible");
2185 if (!pSttIdx)
2186 return;
2188 SwPosition aTmpPos(*m_pPaM->GetPoint());
2190 m_pPaM->GetPoint()->nNode = pSttIdx->GetIndex() + 1;
2191 m_pPaM->GetPoint()->nContent.Assign(m_pPaM->GetContentNode(), 0);
2193 // tdf#122425: Explicitly remove borders and spacing
2194 SfxItemSet aFlySet(m_rDoc.GetAttrPool(), svl::Items<RES_FRMATR_BEGIN, RES_FRMATR_END - 1>{});
2195 Reader::ResetFrameFormatAttrs(aFlySet);
2197 SwFlyFrameFormat* pFrame
2198 = m_rDoc.MakeFlySection(RndStdIds::FLY_AT_PARA, m_pPaM->GetPoint(), &aFlySet);
2200 SwFormatAnchor aAnch( pFrame->GetAnchor() );
2201 aAnch.SetType( RndStdIds::FLY_AT_PARA );
2202 pFrame->SetFormatAttr( aAnch );
2203 SwFormatFrameSize aSz(ATT_MIN_SIZE, nPageWidth, MINLAY);
2204 SwFrameSize eFrameSize = ATT_MIN_SIZE;
2205 if( eFrameSize != aSz.GetWidthSizeType() )
2206 aSz.SetWidthSizeType( eFrameSize );
2207 pFrame->SetFormatAttr(aSz);
2208 pFrame->SetFormatAttr(SwFormatSurround(css::text::WrapTextMode_THROUGH));
2209 pFrame->SetFormatAttr(SwFormatHoriOrient(0, text::HoriOrientation::LEFT)); //iFOO
2211 // #i43427# - send frame for header/footer into background.
2212 pFrame->SetFormatAttr( SvxOpaqueItem( RES_OPAQUE, false ) );
2213 SdrObject* pFrameObj = CreateContactObject( pFrame );
2214 OSL_ENSURE( pFrameObj,
2215 "<SwWW8ImplReader::Read_HdFtTextAsHackedFrame(..)> - missing SdrObject instance" );
2216 if ( pFrameObj )
2218 pFrameObj->SetOrdNum( 0 );
2220 MoveInsideFly(pFrame);
2222 const SwNodeIndex* pHackIdx = pFrame->GetContent().GetContentIdx();
2224 Read_HdFtFootnoteText(pHackIdx, nStart, nLen - 1, MAN_HDFT);
2226 MoveOutsideFly(pFrame, aTmpPos);
2229 void SwWW8ImplReader::Read_HdFtText(WW8_CP nStart, WW8_CP nLen, SwFrameFormat const * pHdFtFormat)
2231 const SwNodeIndex* pSttIdx = pHdFtFormat->GetContent().GetContentIdx();
2232 if (!pSttIdx)
2233 return;
2235 SwPosition aTmpPos( *m_pPaM->GetPoint() ); // Remember old cursor position
2237 Read_HdFtFootnoteText(pSttIdx, nStart, nLen - 1, MAN_HDFT);
2239 *m_pPaM->GetPoint() = aTmpPos;
2242 bool SwWW8ImplReader::isValid_HdFt_CP(WW8_CP nHeaderCP) const
2244 // Each CP of Plcfhdd MUST be less than FibRgLw97.ccpHdd
2245 return (nHeaderCP < m_xWwFib->m_ccpHdr && nHeaderCP >= 0);
2248 bool SwWW8ImplReader::HasOwnHeaderFooter(sal_uInt8 nWhichItems, sal_uInt8 grpfIhdt,
2249 int nSect)
2251 if (m_xHdFt)
2253 WW8_CP nStart, nLen;
2254 sal_uInt8 nNumber = 5;
2256 for( sal_uInt8 nI = 0x20; nI; nI >>= 1, nNumber-- )
2258 if (nI & nWhichItems)
2260 bool bOk = true;
2261 if( m_bVer67 )
2262 bOk = ( m_xHdFt->GetTextPos(grpfIhdt, nI, nStart, nLen ) && nStart >= 0 && nLen >= 2 );
2263 else
2265 m_xHdFt->GetTextPosExact( static_cast< short >(nNumber + (nSect+1)*6), nStart, nLen);
2266 bOk = ( 2 <= nLen ) && isValid_HdFt_CP(nStart);
2269 if (bOk)
2270 return true;
2274 return false;
2277 void SwWW8ImplReader::Read_HdFt(int nSect, const SwPageDesc *pPrev,
2278 const wwSection &rSection)
2280 sal_uInt8 grpfIhdt = rSection.maSep.grpfIhdt;
2281 SwPageDesc *pPD = rSection.mpPage;
2283 if( m_xHdFt )
2285 WW8_CP nStart, nLen;
2286 sal_uInt8 nNumber = 5;
2288 // This loops through the 6 flags WW8_{FOOTER,HEADER}_{ODD,EVEN,FIRST}
2289 // corresponding to bit fields in grpfIhdt indicating which
2290 // header/footer(s) are present in this section
2291 for( sal_uInt8 nI = 0x20; nI; nI >>= 1, nNumber-- )
2293 if (nI & grpfIhdt)
2295 bool bOk = true;
2296 if( m_bVer67 )
2297 bOk = ( m_xHdFt->GetTextPos(grpfIhdt, nI, nStart, nLen ) && nLen >= 2 );
2298 else
2300 m_xHdFt->GetTextPosExact( static_cast< short >(nNumber + (nSect+1)*6), nStart, nLen);
2301 bOk = ( 2 <= nLen ) && isValid_HdFt_CP(nStart);
2304 bool bUseLeft
2305 = (nI & ( WW8_HEADER_EVEN | WW8_FOOTER_EVEN )) != 0;
2306 bool bUseFirst
2307 = (nI & ( WW8_HEADER_FIRST | WW8_FOOTER_FIRST )) != 0;
2309 // If we are loading a first-page header/footer which is not
2310 // actually enabled in this section (it still needs to be
2311 // loaded as it may be inherited by a later section)
2312 bool bDisabledFirst = bUseFirst && !rSection.HasTitlePage();
2314 bool bFooter
2315 = (nI & ( WW8_FOOTER_EVEN | WW8_FOOTER_ODD | WW8_FOOTER_FIRST )) != 0;
2317 SwFrameFormat& rFormat = bUseLeft ? pPD->GetLeft()
2318 : bUseFirst ? pPD->GetFirstMaster()
2319 : pPD->GetMaster();
2321 SwFrameFormat* pHdFtFormat;
2322 // If we have empty first page header and footer.
2323 bool bNoFirst = !(grpfIhdt & WW8_HEADER_FIRST) && !(grpfIhdt & WW8_FOOTER_FIRST);
2324 if (bFooter)
2326 m_bIsFooter = true;
2327 //#i17196# Cannot have left without right
2328 if (!bDisabledFirst
2329 && !pPD->GetMaster().GetFooter().GetFooterFormat())
2330 pPD->GetMaster().SetFormatAttr(SwFormatFooter(true));
2331 if (bUseLeft)
2332 pPD->GetLeft().SetFormatAttr(SwFormatFooter(true));
2333 if (bUseFirst || (rSection.maSep.fTitlePage && bNoFirst))
2334 pPD->GetFirstMaster().SetFormatAttr(SwFormatFooter(true));
2335 pHdFtFormat = const_cast<SwFrameFormat*>(rFormat.GetFooter().GetFooterFormat());
2337 else
2339 m_bIsHeader = true;
2340 //#i17196# Cannot have left without right
2341 if (!bDisabledFirst
2342 && !pPD->GetMaster().GetHeader().GetHeaderFormat())
2343 pPD->GetMaster().SetFormatAttr(SwFormatHeader(true));
2344 if (bUseLeft)
2345 pPD->GetLeft().SetFormatAttr(SwFormatHeader(true));
2346 if (bUseFirst || (rSection.maSep.fTitlePage && bNoFirst))
2347 pPD->GetFirstMaster().SetFormatAttr(SwFormatHeader(true));
2348 pHdFtFormat = const_cast<SwFrameFormat*>(rFormat.GetHeader().GetHeaderFormat());
2351 if (bOk)
2353 bool bHackRequired = false;
2354 if (m_bIsHeader && rSection.IsFixedHeightHeader())
2355 bHackRequired = true;
2356 else if (m_bIsFooter && rSection.IsFixedHeightFooter())
2357 bHackRequired = true;
2359 if (bHackRequired)
2361 Read_HdFtTextAsHackedFrame(nStart, nLen, *pHdFtFormat,
2362 static_cast< sal_uInt16 >(rSection.GetTextAreaWidth()) );
2364 else
2365 Read_HdFtText(nStart, nLen, pHdFtFormat);
2367 else if (pPrev)
2368 CopyPageDescHdFt(pPrev, pPD, nI);
2370 m_bIsHeader = m_bIsFooter = false;
2376 bool wwSectionManager::SectionIsProtected(const wwSection &rSection) const
2378 return ( mrReader.m_xWDop->fProtEnabled && !rSection.IsNotProtected() );
2381 void wwSectionManager::SetHdFt(wwSection const &rSection, int nSect,
2382 const wwSection *pPrevious)
2384 // Header/Footer not present
2385 if (!rSection.maSep.grpfIhdt)
2386 return;
2388 OSL_ENSURE(rSection.mpPage, "makes no sense to call with a main page");
2389 if (rSection.mpPage)
2391 mrReader.Read_HdFt(nSect, pPrevious ? pPrevious->mpPage : nullptr,
2392 rSection);
2395 // Header/Footer - Update Index
2396 // So that the index is still valid later on
2397 if (mrReader.m_xHdFt)
2398 mrReader.m_xHdFt->UpdateIndex(rSection.maSep.grpfIhdt);
2402 void SwWW8ImplReader::AppendTextNode(SwPosition& rPos)
2404 SwTextNode* pText = m_pPaM->GetNode().GetTextNode();
2406 const SwNumRule* pRule = nullptr;
2408 if (pText != nullptr)
2409 pRule = sw::util::GetNumRuleFromTextNode(*pText);
2411 if (
2412 pRule && !m_xWDop->fDontUseHTMLAutoSpacing &&
2413 (m_bParaAutoBefore || m_bParaAutoAfter)
2416 // If after spacing is set to auto, set the after space to 0
2417 if (m_bParaAutoAfter)
2418 SetLowerSpacing(*m_pPaM, 0);
2420 // If the previous textnode had numbering and
2421 // and before spacing is set to auto, set before space to 0
2422 if(m_pPrevNumRule && m_bParaAutoBefore)
2423 SetUpperSpacing(*m_pPaM, 0);
2425 // If the previous numbering rule was different we need
2426 // to insert a space after the previous paragraph
2427 if((pRule != m_pPrevNumRule) && m_pPreviousNumPaM)
2428 SetLowerSpacing(*m_pPreviousNumPaM, GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
2430 // cache current paragraph
2431 if(m_pPreviousNumPaM)
2433 delete m_pPreviousNumPaM;
2434 m_pPreviousNumPaM = nullptr;
2437 m_pPreviousNumPaM = new SwPaM(*m_pPaM, m_pPaM);
2438 m_pPrevNumRule = pRule;
2440 else if(!pRule && m_pPreviousNumPaM)
2442 // If the previous paragraph has numbering but the current one does not
2443 // we need to add a space after the previous paragraph
2444 SetLowerSpacing(*m_pPreviousNumPaM, GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
2445 delete m_pPreviousNumPaM;
2446 m_pPreviousNumPaM = nullptr;
2447 m_pPrevNumRule = nullptr;
2449 else
2451 // clear paragraph cache
2452 if(m_pPreviousNumPaM)
2454 delete m_pPreviousNumPaM;
2455 m_pPreviousNumPaM = nullptr;
2457 m_pPrevNumRule = pRule;
2460 // If this is the first paragraph in the document and
2461 // Auto-spacing before paragraph is set,
2462 // set the upper spacing value to 0
2463 if(m_bParaAutoBefore && m_bFirstPara && !m_xWDop->fDontUseHTMLAutoSpacing)
2464 SetUpperSpacing(*m_pPaM, 0);
2466 m_bFirstPara = false;
2468 m_rDoc.getIDocumentContentOperations().AppendTextNode(rPos);
2470 // We can flush all anchored graphics at the end of a paragraph.
2471 m_xAnchorStck->Flush();
2474 bool SwWW8ImplReader::SetSpacing(SwPaM &rMyPam, int nSpace, bool bIsUpper )
2476 bool bRet = false;
2477 const SwPosition* pSpacingPos = rMyPam.GetPoint();
2479 const SvxULSpaceItem* pULSpaceItem = m_xCtrlStck->GetFormatAttr(*pSpacingPos, RES_UL_SPACE);
2481 if(pULSpaceItem != nullptr)
2483 SvxULSpaceItem aUL(*pULSpaceItem);
2485 if(bIsUpper)
2486 aUL.SetUpper( static_cast< sal_uInt16 >(nSpace) );
2487 else
2488 aUL.SetLower( static_cast< sal_uInt16 >(nSpace) );
2490 const sal_Int32 nEnd = pSpacingPos->nContent.GetIndex();
2491 rMyPam.GetPoint()->nContent.Assign(rMyPam.GetContentNode(), 0);
2492 m_xCtrlStck->NewAttr(*pSpacingPos, aUL);
2493 rMyPam.GetPoint()->nContent.Assign(rMyPam.GetContentNode(), nEnd);
2494 m_xCtrlStck->SetAttr(*pSpacingPos, RES_UL_SPACE);
2495 bRet = true;
2497 return bRet;
2500 bool SwWW8ImplReader::SetLowerSpacing(SwPaM &rMyPam, int nSpace)
2502 return SetSpacing(rMyPam, nSpace, false);
2505 bool SwWW8ImplReader::SetUpperSpacing(SwPaM &rMyPam, int nSpace)
2507 return SetSpacing(rMyPam, nSpace, true);
2510 sal_uInt16 SwWW8ImplReader::TabRowSprm(int nLevel) const
2512 if (m_bVer67)
2513 return 25;
2514 return nLevel ? 0x244C : 0x2417;
2517 void SwWW8ImplReader::EndSpecial()
2519 // Frame/Table/Anl
2520 if (m_bAnl)
2521 StopAllAnl(); // -> bAnl = false
2523 while(m_aApos.size() > 1)
2525 StopTable();
2526 m_aApos.pop_back();
2527 --m_nInTable;
2528 if (m_aApos[m_nInTable])
2529 StopApo();
2532 if (m_aApos[0])
2533 StopApo();
2535 OSL_ENSURE(!m_nInTable, "unclosed table!");
2538 bool SwWW8ImplReader::FloatingTableConversion(WW8PLCFx_Cp_FKP* pPap)
2540 // This is ww8 version of the code deciding if the table needs to be
2541 // in a floating frame.
2542 // For OOXML code, see SectionPropertyMap::FloatingTableConversion in
2543 // writerfilter/source/dmapper/PropertyMap.cxx
2544 // The two should do ~same, so if you make changes here, please check
2545 // that the other is in sync.
2547 // Note that this is just a list of heuristics till sw core can have a
2548 // table that is floating and can span over multiple pages at the same
2549 // time.
2551 bool bResult = true;
2553 SprmResult aRes = pPap->HasSprm(NS_sprm::sprmTDefTable);
2554 if (nullptr != aRes.pSprm)
2556 bResult = false;
2557 WW8TabBandDesc aDesc;
2558 aDesc.ReadDef(false, aRes.pSprm, aRes.nRemainingData);
2559 int nTextAreaWidth = m_aSectionManager.GetTextAreaWidth();
2560 int nTableWidth = aDesc.nCenter[aDesc.nWwCols] - aDesc.nCenter[0];
2562 // It seems Word has a limit here, so that in case the table width is quite
2563 // close to the text area width, then it won't perform a wrapping, even in
2564 // case the content (e.g. an empty paragraph) would fit. The magic constant
2565 // here represents this limit.
2566 const int nMagicNumber = 469;
2568 // If the table is wider than the text area, then don't create a fly
2569 // for the table: no wrapping will be performed anyway, but multi-page
2570 // tables will be broken.
2571 if ((nTableWidth + nMagicNumber) < nTextAreaWidth)
2572 bResult = true;
2574 // If there are columns, do create a fly, as the flow of the columns
2575 // would otherwise restrict the table.
2576 if (!bResult && (m_aSectionManager.CurrentSectionColCount() >= 2))
2577 bResult = true;
2580 if (bResult)
2582 WW8PLCFxSave1 aSave;
2583 pPap->Save(aSave);
2584 if (SearchTableEnd(pPap))
2586 // Table is considered to be imported into a fly frame and we
2587 // know where the end of the table is.
2588 bool bIsUnicode;
2589 WW8_FC nFc = m_xSBase->WW8Cp2Fc(pPap->Where(), &bIsUnicode);
2590 sal_uInt64 nPos = m_pStrm->Tell();
2591 m_pStrm->Seek(nFc);
2592 sal_uInt16 nUChar = 0;
2593 if (bIsUnicode)
2594 m_pStrm->ReadUInt16(nUChar);
2595 else
2597 sal_uInt8 nChar = 0;
2598 m_pStrm->ReadUChar(nChar);
2599 nUChar = nChar;
2601 m_pStrm->Seek(nPos);
2602 if (nUChar == 0xc)
2603 // The pap after the table starts with a page break, so
2604 // there will be no wrapping around the float-table.
2605 // Request no fly in this case, so the table can properly
2606 // be a multi-page one if necessary.
2607 bResult = false;
2609 pPap->Restore(aSave);
2612 return bResult;
2615 bool SwWW8ImplReader::ProcessSpecial(bool &rbReSync, WW8_CP nStartCp)
2617 // Frame/Table/Anl
2618 if (m_bInHyperlink)
2619 return false;
2621 rbReSync = false;
2623 OSL_ENSURE(m_nInTable >= 0,"nInTable < 0!");
2625 // TabRowEnd
2626 bool bTableRowEnd = (m_xPlcxMan->HasParaSprm(m_bVer67 ? 25 : 0x2417).pSprm != nullptr);
2628 // Unfortunately, for every paragraph we need to check first whether
2629 // they contain a sprm 29 (0x261B), which starts an APO.
2630 // All other sprms then refer to that APO and not to the normal text
2631 // surrounding it.
2632 // The same holds true for a Table (sprm 24 (0x2416)) and Anls (sprm 13).
2634 // WW: Table in APO is possible (Both Start-Ends occur at the same time)
2635 // WW: APO in Table not possible
2637 // This mean that of a Table is the content of an APO, the APO start needs
2638 // to be edited first, so that the Table remains in the APO and not the
2639 // other way around.
2640 // At the End, however, we need to edit the Table End first as the APO
2641 // must end after that Table (or else we never find the APO End).
2643 // The same holds true for Fly / Anl, Tab / Anl, Fly / Tab / Anl.
2645 // If the Table is within an APO the TabRowEnd Area misses the
2646 // APO settings.
2647 // To not end the APO there, we do not call ProcessApo
2649 // KHZ: When there is a table inside the Apo the Apo-flags are also
2650 // missing for the 2nd, 3rd... paragraphs of each cell.
2652 // 1st look for in-table flag, for 2000+ there is a subtable flag to
2653 // be considered, the sprm 6649 gives the level of the table
2654 sal_uInt8 nCellLevel = 0;
2656 if (m_bVer67)
2657 nCellLevel = int(nullptr != m_xPlcxMan->HasParaSprm(24).pSprm);
2658 else
2660 nCellLevel = int(nullptr != m_xPlcxMan->HasParaSprm(0x2416).pSprm);
2661 if (!nCellLevel)
2662 nCellLevel = int(nullptr != m_xPlcxMan->HasParaSprm(0x244B).pSprm);
2666 WW8_TablePos *pTabPos=nullptr;
2667 WW8_TablePos aTabPos;
2668 if(nCellLevel && !m_bVer67)
2670 WW8PLCFxSave1 aSave;
2671 m_xPlcxMan->GetPap()->Save( aSave );
2672 rbReSync = true;
2673 WW8PLCFx_Cp_FKP* pPap = m_xPlcxMan->GetPapPLCF();
2674 WW8_CP nMyStartCp=nStartCp;
2676 SprmResult aLevel = m_xPlcxMan->HasParaSprm(0x6649);
2677 if (aLevel.pSprm && aLevel.nRemainingData >= 1)
2678 nCellLevel = *aLevel.pSprm;
2680 bool bHasRowEnd = SearchRowEnd(pPap, nMyStartCp, (m_nInTable<nCellLevel?m_nInTable:nCellLevel-1));
2682 // Bad Table, remain unchanged in level, e.g. #i19667#
2683 if (!bHasRowEnd)
2684 nCellLevel = static_cast< sal_uInt8 >(m_nInTable);
2686 if (bHasRowEnd && ParseTabPos(&aTabPos,pPap))
2687 pTabPos = &aTabPos;
2689 m_xPlcxMan->GetPap()->Restore( aSave );
2692 // Then look if we are in an Apo
2694 ApoTestResults aApo = TestApo(nCellLevel, bTableRowEnd, pTabPos);
2696 // Look to see if we are in a Table, but Table in foot/end note not allowed
2697 bool bStartTab = (m_nInTable < nCellLevel) && !m_bFootnoteEdn;
2699 bool bStopTab = m_bWasTabRowEnd && (m_nInTable > nCellLevel) && !m_bFootnoteEdn;
2701 m_bWasTabRowEnd = false; // must be deactivated right here to prevent next
2702 // WW8TabDesc::TableCellEnd() from making nonsense
2704 if (m_nInTable && !bTableRowEnd && !bStopTab && (m_nInTable == nCellLevel && aApo.HasStartStop()))
2705 bStopTab = bStartTab = true; // Required to stop and start table
2707 // Test for Anl (Numbering) and process all events in the right order
2708 if( m_bAnl && !bTableRowEnd )
2710 SprmResult aSprm13 = m_xPlcxMan->HasParaSprm(13);
2711 const sal_uInt8* pSprm13 = aSprm13.pSprm;
2712 if (pSprm13 && aSprm13.nRemainingData >= 1)
2713 { // Still Anl left?
2714 sal_uInt8 nT = static_cast< sal_uInt8 >(GetNumType( *pSprm13 ));
2715 if( ( nT != WW8_Pause && nT != m_nWwNumType ) // Anl change
2716 || aApo.HasStartStop() // Forced Anl end
2717 || bStopTab || bStartTab )
2719 StopAnlToRestart(nT); // Anl-Restart (= change) over sprms
2721 else
2723 NextAnlLine( pSprm13 ); // Next Anl Line
2726 else
2727 { // Regular Anl end
2728 StopAllAnl(); // Actual end
2731 if (bStopTab)
2733 StopTable();
2734 m_aApos.pop_back();
2735 --m_nInTable;
2737 if (aApo.mbStopApo)
2739 StopApo();
2740 m_aApos[m_nInTable] = false;
2743 if (aApo.mbStartApo)
2745 m_aApos[m_nInTable] = StartApo(aApo, pTabPos);
2746 // We need an ReSync after StartApo
2747 // (actually only if the Apo extends past a FKP border)
2748 rbReSync = true;
2750 if (bStartTab)
2752 WW8PLCFxSave1 aSave;
2753 m_xPlcxMan->GetPap()->Save( aSave );
2755 // Numbering for cell borders causes a crash -> no Anls in Tables
2756 if (m_bAnl)
2757 StopAllAnl();
2759 if(m_nInTable < nCellLevel)
2761 if (StartTable(nStartCp))
2762 ++m_nInTable;
2763 else
2764 break;
2765 m_aApos.push_back(false);
2768 if(m_nInTable >= nCellLevel)
2770 // We need an ReSync after StartTable
2771 // (actually only if the Apo extends past a FKP border)
2772 rbReSync = true;
2773 m_xPlcxMan->GetPap()->Restore( aSave );
2776 } while (!m_bFootnoteEdn && (m_nInTable < nCellLevel));
2777 return bTableRowEnd;
2780 rtl_TextEncoding SwWW8ImplReader::GetCharSetFromLanguage()
2783 #i22206#/#i52786#
2784 The (default) character set used for a run of text is the default
2785 character set for the version of Word that last saved the document.
2787 This is a bit tentative, more might be required if the concept is correct.
2788 When later version of word write older 6/95 documents the charset is
2789 correctly set in the character runs involved, so it's hard to reproduce
2790 documents that require this to be sure of the process involved.
2792 const SvxLanguageItem *pLang = static_cast<const SvxLanguageItem*>(GetFormatAttr(RES_CHRATR_LANGUAGE));
2793 LanguageType eLang = pLang ? pLang->GetLanguage() : LANGUAGE_SYSTEM;
2794 css::lang::Locale aLocale(LanguageTag::convertToLocale(eLang));
2795 return msfilter::util::getBestTextEncodingFromLocale(aLocale);
2798 rtl_TextEncoding SwWW8ImplReader::GetCJKCharSetFromLanguage()
2801 #i22206#/#i52786#
2802 The (default) character set used for a run of text is the default
2803 character set for the version of Word that last saved the document.
2805 This is a bit tentative, more might be required if the concept is correct.
2806 When later version of word write older 6/95 documents the charset is
2807 correctly set in the character runs involved, so it's hard to reproduce
2808 documents that require this to be sure of the process involved.
2810 const SvxLanguageItem *pLang = static_cast<const SvxLanguageItem*>(GetFormatAttr(RES_CHRATR_CJK_LANGUAGE));
2811 LanguageType eLang = pLang ? pLang->GetLanguage() : LANGUAGE_SYSTEM;
2812 css::lang::Locale aLocale(LanguageTag::convertToLocale(eLang));
2813 return msfilter::util::getBestTextEncodingFromLocale(aLocale);
2816 rtl_TextEncoding SwWW8ImplReader::GetCurrentCharSet()
2819 #i2015
2820 If the hard charset is set use it, if not see if there is an open
2821 character run that has set the charset, if not then fallback to the
2822 current underlying paragraph style.
2824 rtl_TextEncoding eSrcCharSet = m_eHardCharSet;
2825 if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2827 if (!m_bVer67)
2828 eSrcCharSet = GetCharSetFromLanguage();
2829 else if (!m_aFontSrcCharSets.empty())
2830 eSrcCharSet = m_aFontSrcCharSets.top();
2831 if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && m_nCharFormat >= 0 && static_cast<size_t>(m_nCharFormat) < m_vColl.size() )
2832 eSrcCharSet = m_vColl[m_nCharFormat].GetCharSet();
2833 if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && StyleExists(m_nCurrentColl) && m_nCurrentColl < m_vColl.size())
2834 eSrcCharSet = m_vColl[m_nCurrentColl].GetCharSet();
2835 if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2836 eSrcCharSet = GetCharSetFromLanguage();
2838 return eSrcCharSet;
2841 //Takashi Ono for CJK
2842 rtl_TextEncoding SwWW8ImplReader::GetCurrentCJKCharSet()
2845 #i2015
2846 If the hard charset is set use it, if not see if there is an open
2847 character run that has set the charset, if not then fallback to the
2848 current underlying paragraph style.
2850 rtl_TextEncoding eSrcCharSet = m_eHardCharSet;
2851 if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2853 if (!m_aFontSrcCJKCharSets.empty())
2854 eSrcCharSet = m_aFontSrcCJKCharSets.top();
2855 if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && m_nCharFormat >= 0 && static_cast<size_t>(m_nCharFormat) < m_vColl.size() )
2856 eSrcCharSet = m_vColl[m_nCharFormat].GetCJKCharSet();
2857 if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW && StyleExists(m_nCurrentColl) && m_nCurrentColl < m_vColl.size())
2858 eSrcCharSet = m_vColl[m_nCurrentColl].GetCJKCharSet();
2859 if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2860 eSrcCharSet = GetCJKCharSetFromLanguage();
2862 return eSrcCharSet;
2865 void SwWW8ImplReader::PostProcessAttrs()
2867 if (m_pPostProcessAttrsInfo != nullptr)
2869 SfxItemIter aIter(m_pPostProcessAttrsInfo->mItemSet);
2871 const SfxPoolItem * pItem = aIter.GetCurItem();
2872 if (pItem != nullptr)
2876 m_xCtrlStck->NewAttr(*m_pPostProcessAttrsInfo->mPaM.GetPoint(),
2877 *pItem);
2878 m_xCtrlStck->SetAttr(*m_pPostProcessAttrsInfo->mPaM.GetMark(),
2879 pItem->Which());
2881 while (!aIter.IsAtEnd() && nullptr != (pItem = aIter.NextItem()));
2884 m_pPostProcessAttrsInfo.reset();
2889 #i9241#
2890 It appears that some documents that are in a baltic 8 bit encoding which has
2891 some undefined characters can have use made of those characters, in which
2892 case they default to CP1252. If not then it's perhaps that the font encoding
2893 is only in use for 6/7 and for 8+ if we are in 8bit mode then the encoding
2894 is always 1252.
2896 So an encoding converter that on an undefined character attempts to
2897 convert from 1252 on the undefined character
2899 static std::size_t Custom8BitToUnicode(rtl_TextToUnicodeConverter hConverter,
2900 sal_Char const *pIn, std::size_t nInLen, sal_Unicode *pOut, std::size_t nOutLen)
2902 const sal_uInt32 nFlags =
2903 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
2904 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
2905 RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE |
2906 RTL_TEXTTOUNICODE_FLAGS_FLUSH;
2908 const sal_uInt32 nFlags2 =
2909 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE |
2910 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_IGNORE |
2911 RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE |
2912 RTL_TEXTTOUNICODE_FLAGS_FLUSH;
2914 std::size_t nDestChars=0;
2915 std::size_t nConverted=0;
2919 sal_uInt32 nInfo = 0;
2920 sal_Size nThisConverted=0;
2922 nDestChars += rtl_convertTextToUnicode(hConverter, nullptr,
2923 pIn+nConverted, nInLen-nConverted,
2924 pOut+nDestChars, nOutLen-nDestChars,
2925 nFlags, &nInfo, &nThisConverted);
2927 OSL_ENSURE(nInfo == 0, "A character conversion failed!");
2929 nConverted += nThisConverted;
2931 if (
2932 nInfo & RTL_TEXTTOUNICODE_INFO_UNDEFINED ||
2933 nInfo & RTL_TEXTTOUNICODE_INFO_MBUNDEFINED
2936 sal_Size nOtherConverted;
2937 rtl_TextToUnicodeConverter hCP1252Converter =
2938 rtl_createTextToUnicodeConverter(RTL_TEXTENCODING_MS_1252);
2939 nDestChars += rtl_convertTextToUnicode(hCP1252Converter, nullptr,
2940 pIn+nConverted, 1,
2941 pOut+nDestChars, nOutLen-nDestChars,
2942 nFlags2, &nInfo, &nOtherConverted);
2943 rtl_destroyTextToUnicodeConverter(hCP1252Converter);
2944 nConverted+=1;
2946 } while (nConverted < nInLen);
2948 return nDestChars;
2951 bool SwWW8ImplReader::LangUsesHindiNumbers(LanguageType nLang)
2953 bool bResult = false;
2955 switch (static_cast<sal_uInt16>(nLang))
2957 case 0x1401: // Arabic(Algeria)
2958 case 0x3c01: // Arabic(Bahrain)
2959 case 0xc01: // Arabic(Egypt)
2960 case 0x801: // Arabic(Iraq)
2961 case 0x2c01: // Arabic (Jordan)
2962 case 0x3401: // Arabic(Kuwait)
2963 case 0x3001: // Arabic(Lebanon)
2964 case 0x1001: // Arabic(Libya)
2965 case 0x1801: // Arabic(Morocco)
2966 case 0x2001: // Arabic(Oman)
2967 case 0x4001: // Arabic(Qatar)
2968 case 0x401: // Arabic(Saudi Arabia)
2969 case 0x2801: // Arabic(Syria)
2970 case 0x1c01: // Arabic(Tunisia)
2971 case 0x3801: // Arabic(U.A.E)
2972 case 0x2401: // Arabic(Yemen)
2973 bResult = true;
2974 break;
2975 default:
2976 break;
2979 return bResult;
2982 sal_Unicode SwWW8ImplReader::TranslateToHindiNumbers(sal_Unicode nChar)
2984 if (nChar >= 0x0030 && nChar <= 0x0039)
2985 return nChar + 0x0630;
2987 return nChar;
2990 namespace
2992 OUString makeOUString(rtl_uString *pStr, sal_Int32 nAllocLen)
2994 //if read len was in or around that of allocated len, just reuse pStr
2995 if (nAllocLen < pStr->length + 256)
2996 return OUString(pStr, SAL_NO_ACQUIRE);
2997 //otherwise copy the shorter used section to release extra mem
2998 OUString sRet(pStr->buffer, pStr->length);
2999 rtl_uString_release(pStr);
3000 return sRet;
3005 * Return value: true for non special chars
3007 bool SwWW8ImplReader::ReadPlainChars(WW8_CP& rPos, sal_Int32 nEnd, sal_Int32 nCpOfs)
3009 sal_Int32 nRequestedStrLen = nEnd - rPos;
3011 OSL_ENSURE(nRequestedStrLen, "String is 0");
3012 if (nRequestedStrLen <= 0)
3013 return true;
3015 sal_Int32 nRequestedPos = m_xSBase->WW8Cp2Fc(nCpOfs+rPos, &m_bIsUnicode);
3016 bool bValidPos = checkSeek(*m_pStrm, nRequestedPos);
3017 OSL_ENSURE(bValidPos, "Document claimed to have more text than available");
3018 if (!bValidPos)
3020 // Swallow missing range, e.g. #i95550#
3021 rPos+=nRequestedStrLen;
3022 return true;
3025 std::size_t nAvailableStrLen = m_pStrm->remainingSize() / (m_bIsUnicode ? 2 : 1);
3026 OSL_ENSURE(nAvailableStrLen, "Document claimed to have more text than available");
3027 if (!nAvailableStrLen)
3029 // Swallow missing range, e.g. #i95550#
3030 rPos+=nRequestedStrLen;
3031 return true;
3034 sal_Int32 nValidStrLen = std::min<std::size_t>(nRequestedStrLen, nAvailableStrLen);
3036 // Reset Unicode flag and correct FilePos if needed.
3037 // Note: Seek is not expensive, as we're checking inline whether or not
3038 // the correct FilePos has already been reached.
3039 const sal_Int32 nStrLen = std::min(nValidStrLen, SAL_MAX_INT32-1);
3041 rtl_TextEncoding eSrcCharSet = m_bVer67 ? GetCurrentCharSet() :
3042 RTL_TEXTENCODING_MS_1252;
3043 if (m_bVer67 && eSrcCharSet == RTL_TEXTENCODING_MS_932)
3046 fdo#82904
3048 Older documents exported as word 95 that use unicode aware fonts will
3049 have the charset of those fonts set to RTL_TEXTENCODING_MS_932 on
3050 export as the conversion from RTL_TEXTENCODING_UNICODE. This is a serious
3051 pain.
3053 We will try and use a fallback encoding if the conversion from
3054 RTL_TEXTENCODING_MS_932 fails, but you can get unlucky and get a document
3055 which isn't really in RTL_TEXTENCODING_MS_932 but parts of it form
3056 valid RTL_TEXTENCODING_MS_932 by chance :-(
3058 We're not the only ones that struggle with this: Here's the help from
3059 MSOffice 2003 on the topic:
3062 Earlier versions of Microsoft Word were sometimes used in conjunction with
3063 third-party language-processing add-in programs designed to support Chinese or
3064 Korean on English versions of Microsoft Windows. Use of these add-ins sometimes
3065 results in incorrect text display in more recent versions of Word.
3067 However, you can set options to convert these documents so that text is
3068 displayed correctly. On the Tools menu, click Options, and then click the
3069 General tab. In the English Word 6.0/95 documents list, select Contain Asian
3070 text (to have Word interpret the text as Asian code page data, regardless of
3071 its font) or Automatically detect Asian text (to have Word attempt to determine
3072 which parts of the text are meant to be Asian).
3075 What we can try here is to ignore a RTL_TEXTENCODING_MS_932 codepage if
3076 the language is not Japanese
3079 const SfxPoolItem * pItem = GetFormatAttr(RES_CHRATR_CJK_LANGUAGE);
3080 if (pItem != nullptr && LANGUAGE_JAPANESE != static_cast<const SvxLanguageItem *>(pItem)->GetLanguage())
3082 SAL_WARN("sw.ww8", "discarding word95 RTL_TEXTENCODING_MS_932 encoding");
3083 eSrcCharSet = GetCharSetFromLanguage();
3086 const rtl_TextEncoding eSrcCJKCharSet = m_bVer67 ? GetCurrentCJKCharSet() :
3087 RTL_TEXTENCODING_MS_1252;
3089 // allocate unicode string data
3090 rtl_uString *pStr = rtl_uString_alloc(nStrLen);
3091 sal_Unicode* pBuffer = pStr->buffer;
3092 sal_Unicode* pWork = pBuffer;
3094 std::unique_ptr<sal_Char[]> p8Bits;
3096 rtl_TextToUnicodeConverter hConverter = nullptr;
3097 if (!m_bIsUnicode || m_bVer67)
3098 hConverter = rtl_createTextToUnicodeConverter(eSrcCharSet);
3100 if (!m_bIsUnicode)
3101 p8Bits.reset( new sal_Char[nStrLen] );
3103 // read the stream data
3104 sal_uInt8 nBCode = 0;
3105 sal_uInt16 nUCode;
3107 LanguageType nCTLLang = LANGUAGE_SYSTEM;
3108 const SfxPoolItem * pItem = GetFormatAttr(RES_CHRATR_CTL_LANGUAGE);
3109 if (pItem != nullptr)
3110 nCTLLang = static_cast<const SvxLanguageItem *>(pItem)->GetLanguage();
3112 sal_Int32 nL2;
3113 for (nL2 = 0; nL2 < nStrLen; ++nL2)
3115 if (m_bIsUnicode)
3116 m_pStrm->ReadUInt16( nUCode ); // unicode --> read 2 bytes
3117 else
3119 m_pStrm->ReadUChar( nBCode ); // old code --> read 1 byte
3120 nUCode = nBCode;
3123 if (m_pStrm->GetError())
3125 rPos = WW8_CP_MAX-10; // -> eof or other error
3126 std::free(pStr);
3127 return true;
3130 if ((32 > nUCode) || (0xa0 == nUCode))
3132 m_pStrm->SeekRel( m_bIsUnicode ? -2 : -1 );
3133 break; // Special character < 32, == 0xa0 found
3136 if (m_bIsUnicode)
3138 if (!m_bVer67)
3139 *pWork++ = nUCode;
3140 else
3142 if (nUCode >= 0x3000) //0x8000 ?
3144 sal_Char aTest[2];
3145 aTest[0] = static_cast< sal_Char >((nUCode & 0xFF00) >> 8);
3146 aTest[1] = static_cast< sal_Char >(nUCode & 0x00FF);
3147 OUString aTemp(aTest, 2, eSrcCJKCharSet);
3148 OSL_ENSURE(aTemp.getLength() == 1, "so much for that theory");
3149 *pWork++ = aTemp[0];
3151 else
3153 sal_Char cTest = static_cast< sal_Char >(nUCode & 0x00FF);
3154 pWork += Custom8BitToUnicode(hConverter, &cTest, 1, pWork, 1);
3158 else
3159 p8Bits[nL2] = nBCode;
3162 if (nL2)
3164 const sal_Int32 nEndUsed = !m_bIsUnicode
3165 ? Custom8BitToUnicode(hConverter, p8Bits.get(), nL2, pBuffer, nStrLen)
3166 : pWork - pBuffer;
3168 if (m_bRegardHindiDigits && m_bBidi && LangUsesHindiNumbers(nCTLLang))
3170 for (sal_Int32 nI = 0; nI < nEndUsed; ++nI, ++pBuffer)
3171 *pBuffer = TranslateToHindiNumbers(*pBuffer);
3174 pStr->buffer[nEndUsed] = 0;
3175 pStr->length = nEndUsed;
3177 emulateMSWordAddTextToParagraph(makeOUString(pStr, nStrLen));
3178 pStr = nullptr;
3179 rPos += nL2;
3180 if (!m_aApos.back()) // a para end in apo doesn't count
3181 m_bWasParaEnd = false; // No CR
3184 if (hConverter)
3185 rtl_destroyTextToUnicodeConverter(hConverter);
3186 if (pStr)
3187 rtl_uString_release(pStr);
3188 return nL2 >= nStrLen;
3191 #define MSASCII SAL_MAX_INT16
3193 namespace
3195 // We want to force weak chars inside 0x0020 to 0x007F to LATIN
3196 sal_Int16 lcl_getScriptType(
3197 const uno::Reference<i18n::XBreakIterator>& rBI,
3198 const OUString &rString, sal_Int32 nPos)
3200 sal_Int16 nScript = rBI->getScriptType(rString, nPos);
3201 if (nScript == i18n::ScriptType::WEAK && rString[nPos] >= 0x0020 && rString[nPos] <= 0x007F)
3202 nScript = MSASCII;
3203 return nScript;
3206 // We want to know about WEAK segments, so endOfScript isn't
3207 // useful, and see lcl_getScriptType anyway
3208 sal_Int32 lcl_endOfScript(
3209 const uno::Reference<i18n::XBreakIterator>& rBI,
3210 const OUString &rString, sal_Int32 nPos, sal_Int16 nScript)
3212 while (nPos < rString.getLength())
3214 sal_Int16 nNewScript = lcl_getScriptType(rBI, rString, nPos);
3215 if (nScript != nNewScript)
3216 break;
3217 ++nPos;
3219 return nPos;
3222 sal_Int32 lcl_getWriterScriptType(
3223 const uno::Reference<i18n::XBreakIterator>& rBI,
3224 const OUString &rString, sal_Int32 nPos)
3226 sal_Int16 nScript = i18n::ScriptType::WEAK;
3228 if (rString.isEmpty())
3229 return nScript;
3231 while (nPos >= 0)
3233 nScript = rBI->getScriptType(rString, nPos);
3234 if (nScript != i18n::ScriptType::WEAK)
3235 break;
3236 --nPos;
3239 return nScript;
3242 bool samePitchIgnoreUnknown(FontPitch eA, FontPitch eB)
3244 return (eA == eB || eA == PITCH_DONTKNOW || eB == PITCH_DONTKNOW);
3247 bool sameFontIgnoringIrrelevantFields(const SvxFontItem &rA, const SvxFontItem &rB)
3249 // Ignoring CharSet, and ignoring unknown pitch
3250 return rA.GetFamilyName() == rB.GetFamilyName() &&
3251 rA.GetStyleName() == rB.GetStyleName() &&
3252 rA.GetFamily() == rB.GetFamily() &&
3253 samePitchIgnoreUnknown(rA.GetPitch(), rB.GetPitch());
3257 // In writer we categorize text into CJK, CTL and "Western" for everything else.
3258 // Microsoft Word basically categorizes text into East Asian, Complex, ASCII,
3259 // NonEastAsian/HighAnsi, with some shared characters and some properties to
3260 // hint as to which way to bias those shared characters.
3262 // That's four categories, we however have three categories. Given that problem
3263 // here we would ideally find out "what would word do" to see what font/language
3264 // word would assign to characters based on the unicode range they fall into and
3265 // hack the word one onto the range we use. However it's unclear what word's
3266 // categorization is. So we don't do that here yet.
3268 // Additional to the categorization, when word encounters weak text for ambiguous
3269 // chars it uses idcthint to indicate which way to bias. We don't have an idcthint
3270 // feature in writer.
3272 // So what we currently do here then is to split our text into non-weak/weak
3273 // sections and uses word's idcthint to determine what font it would use and
3274 // force that on for the segment. Following what we *do* know about word's
3275 // categorization, we know that the range 0x0020 and 0x007F is sprmCRgFtc0 in
3276 // word, something we map to LATIN, so we consider all weak chars in that range
3277 // to auto-bias to LATIN.
3279 // See https://bugs.libreoffice.org/show_bug.cgi?id=34319 for an example
3280 void SwWW8ImplReader::emulateMSWordAddTextToParagraph(const OUString& rAddString)
3282 if (rAddString.isEmpty())
3283 return;
3285 uno::Reference<i18n::XBreakIterator> xBI(g_pBreakIt->GetBreakIter());
3286 assert(xBI.is());
3288 sal_Int16 nScript = lcl_getScriptType(xBI, rAddString, 0);
3289 sal_Int32 nLen = rAddString.getLength();
3291 OUString sParagraphText;
3292 const SwContentNode *pCntNd = m_pPaM->GetContentNode();
3293 const SwTextNode* pNd = pCntNd ? pCntNd->GetTextNode() : nullptr;
3294 if (pNd)
3295 sParagraphText = pNd->GetText();
3296 sal_Int32 nParaOffset = sParagraphText.getLength();
3297 sParagraphText = sParagraphText + rAddString;
3299 sal_Int32 nPos = 0;
3300 while (nPos < nLen)
3302 sal_Int32 nEnd = lcl_endOfScript(xBI, rAddString, nPos, nScript);
3303 if (nEnd < 0)
3304 break;
3306 OUString sChunk(rAddString.copy(nPos, nEnd-nPos));
3307 const sal_uInt16 aIds[] = {RES_CHRATR_FONT, RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_FONT};
3308 const SvxFontItem *pOverriddenItems[] = {nullptr, nullptr, nullptr};
3309 bool aForced[] = {false, false, false};
3311 int nLclIdctHint = 0xFF;
3312 if (nScript == i18n::ScriptType::WEAK)
3314 const SfxInt16Item *pIdctHint = static_cast<const SfxInt16Item*>(GetFormatAttr(RES_CHRATR_IDCTHINT));
3315 nLclIdctHint = pIdctHint->GetValue();
3317 else if (nScript == MSASCII) // Force weak chars in ascii range to use LATIN font
3318 nLclIdctHint = 0;
3320 sal_uInt16 nForceFromFontId = 0;
3321 if (nLclIdctHint != 0xFF)
3323 switch (nLclIdctHint)
3325 case 0:
3326 nForceFromFontId = RES_CHRATR_FONT;
3327 break;
3328 case 1:
3329 nForceFromFontId = RES_CHRATR_CJK_FONT;
3330 break;
3331 case 2:
3332 nForceFromFontId = RES_CHRATR_CTL_FONT;
3333 break;
3334 default:
3335 break;
3339 if (nForceFromFontId != 0)
3341 // Now we know that word would use the nForceFromFontId font for this range
3342 // Try and determine what script writer would assign this range to
3344 sal_Int32 nWriterScript = lcl_getWriterScriptType(xBI, sParagraphText,
3345 nPos + nParaOffset);
3347 bool bWriterWillUseSameFontAsWordAutomatically = false;
3349 if (nWriterScript != i18n::ScriptType::WEAK)
3351 if (
3352 (nWriterScript == i18n::ScriptType::ASIAN && nForceFromFontId == RES_CHRATR_CJK_FONT) ||
3353 (nWriterScript == i18n::ScriptType::COMPLEX && nForceFromFontId == RES_CHRATR_CTL_FONT) ||
3354 (nWriterScript == i18n::ScriptType::LATIN && nForceFromFontId == RES_CHRATR_FONT)
3357 bWriterWillUseSameFontAsWordAutomatically = true;
3359 else
3361 const SvxFontItem *pSourceFont = static_cast<const SvxFontItem*>(GetFormatAttr(nForceFromFontId));
3362 sal_uInt16 nDestId = aIds[nWriterScript-1];
3363 const SvxFontItem *pDestFont = static_cast<const SvxFontItem*>(GetFormatAttr(nDestId));
3364 bWriterWillUseSameFontAsWordAutomatically = sameFontIgnoringIrrelevantFields(*pSourceFont, *pDestFont);
3368 // Writer won't use the same font as word, so force the issue
3369 if (!bWriterWillUseSameFontAsWordAutomatically)
3371 const SvxFontItem *pSourceFont = static_cast<const SvxFontItem*>(GetFormatAttr(nForceFromFontId));
3373 for (size_t i = 0; i < SAL_N_ELEMENTS(aIds); ++i)
3375 const SvxFontItem *pDestFont = static_cast<const SvxFontItem*>(GetFormatAttr(aIds[i]));
3376 aForced[i] = aIds[i] != nForceFromFontId && *pSourceFont != *pDestFont;
3377 if (aForced[i])
3379 pOverriddenItems[i] =
3380 static_cast<const SvxFontItem*>(m_xCtrlStck->GetStackAttr(*m_pPaM->GetPoint(), aIds[i]));
3382 SvxFontItem aForceFont(*pSourceFont);
3383 aForceFont.SetWhich(aIds[i]);
3384 m_xCtrlStck->NewAttr(*m_pPaM->GetPoint(), aForceFont);
3390 simpleAddTextToParagraph(sChunk);
3392 for (size_t i = 0; i < SAL_N_ELEMENTS(aIds); ++i)
3394 if (aForced[i])
3396 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), aIds[i]);
3397 if (pOverriddenItems[i])
3398 m_xCtrlStck->NewAttr(*m_pPaM->GetPoint(), *(pOverriddenItems[i]));
3402 nPos = nEnd;
3403 if (nPos < nLen)
3404 nScript = lcl_getScriptType(xBI, rAddString, nPos);
3408 void SwWW8ImplReader::simpleAddTextToParagraph(const OUString& rAddString)
3410 if (rAddString.isEmpty())
3411 return;
3413 #if OSL_DEBUG_LEVEL > 1
3414 SAL_INFO("sw.ww8", "<addTextToParagraph>" << rAddString << "</addTextToParagraph>");
3415 #endif
3417 const SwContentNode *pCntNd = m_pPaM->GetContentNode();
3418 const SwTextNode* pNd = pCntNd ? pCntNd->GetTextNode() : nullptr;
3420 OSL_ENSURE(pNd, "What the hell, where's my text node");
3422 if (!pNd)
3423 return;
3425 const sal_Int32 nCharsLeft = SAL_MAX_INT32 - pNd->GetText().getLength();
3426 if (nCharsLeft > 0)
3428 if (rAddString.getLength() <= nCharsLeft)
3430 m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, rAddString);
3432 else
3434 m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, rAddString.copy(0, nCharsLeft));
3435 AppendTextNode(*m_pPaM->GetPoint());
3436 m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, rAddString.copy(nCharsLeft));
3439 else
3441 AppendTextNode(*m_pPaM->GetPoint());
3442 m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, rAddString);
3445 m_bReadTable = false;
3449 * Return value: true for para end
3451 bool SwWW8ImplReader::ReadChars(WW8_CP& rPos, WW8_CP nNextAttr, long nTextEnd,
3452 long nCpOfs)
3454 long nEnd = ( nNextAttr < nTextEnd ) ? nNextAttr : nTextEnd;
3456 if (m_bSymbol || m_bIgnoreText)
3458 WW8_CP nRequested = nEnd - rPos;
3459 if (m_bSymbol) // Insert special chars
3461 sal_uInt64 nMaxPossible = m_pStrm->remainingSize();
3462 if (static_cast<sal_uInt64>(nRequested) > nMaxPossible)
3464 SAL_WARN("sw.ww8", "document claims to have more characters, " << nRequested << " than remaining, " << nMaxPossible);
3465 nRequested = nMaxPossible;
3468 for (WW8_CP nCh = 0; nCh < nRequested; ++nCh)
3470 m_rDoc.getIDocumentContentOperations().InsertString( *m_pPaM, OUString(m_cSymbol) );
3472 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_FONT );
3473 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_CJK_FONT );
3474 m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_CTL_FONT );
3476 m_pStrm->SeekRel(nRequested);
3477 rPos = nEnd; // Ignore until attribute end
3478 return false;
3481 while (true)
3483 if (ReadPlainChars(rPos, nEnd, nCpOfs))
3484 return false; // Done
3486 bool bStartLine = ReadChar(rPos, nCpOfs);
3487 rPos++;
3488 if (m_bPgSecBreak || bStartLine || rPos == nEnd) // CR or Done
3490 return bStartLine;
3495 bool SwWW8ImplReader::HandlePageBreakChar()
3497 bool bParaEndAdded = false;
3498 // #i1909# section/page breaks should not occur in tables, word
3499 // itself ignores them in this case.
3500 if (!m_nInTable)
3502 bool IsTemp=true;
3503 SwTextNode* pTemp = m_pPaM->GetNode().GetTextNode();
3504 if (pTemp && pTemp->GetText().isEmpty()
3505 && (m_bFirstPara || m_bFirstParaOfPage))
3507 IsTemp = false;
3508 AppendTextNode(*m_pPaM->GetPoint());
3509 pTemp->SetAttr(*GetDfltAttr(RES_PARATR_NUMRULE));
3512 m_bPgSecBreak = true;
3513 m_xCtrlStck->KillUnlockedAttrs(*m_pPaM->GetPoint());
3515 If it's a 0x0c without a paragraph end before it, act like a
3516 paragraph end, but nevertheless, numbering (and perhaps other
3517 similar constructs) do not exist on the para.
3519 if (!m_bWasParaEnd && IsTemp)
3521 bParaEndAdded = true;
3522 if (0 >= m_pPaM->GetPoint()->nContent.GetIndex())
3524 if (SwTextNode* pTextNode = m_pPaM->GetNode().GetTextNode())
3526 pTextNode->SetAttr(
3527 *GetDfltAttr(RES_PARATR_NUMRULE));
3532 return bParaEndAdded;
3535 bool SwWW8ImplReader::ReadChar(long nPosCp, long nCpOfs)
3537 bool bNewParaEnd = false;
3538 // Reset Unicode flag and correct FilePos if needed.
3539 // Note: Seek is not expensive, as we're checking inline whether or not
3540 // the correct FilePos has already been reached.
3541 std::size_t nRequestedPos = m_xSBase->WW8Cp2Fc(nCpOfs+nPosCp, &m_bIsUnicode);
3542 if (!checkSeek(*m_pStrm, nRequestedPos))
3543 return false;
3545 sal_uInt8 nBCode(0);
3546 sal_uInt16 nWCharVal(0);
3547 if( m_bIsUnicode )
3548 m_pStrm->ReadUInt16( nWCharVal ); // unicode --> read 2 bytes
3549 else
3551 m_pStrm -> ReadUChar( nBCode ); // old code --> read 1 byte
3552 nWCharVal = nBCode;
3555 sal_Unicode cInsert = '\x0';
3556 bool bParaMark = false;
3558 if ( 0xc != nWCharVal )
3559 m_bFirstParaOfPage = false;
3561 switch (nWCharVal)
3563 case 0:
3565 // Page number
3566 SwPageNumberField aField(
3567 static_cast<SwPageNumberFieldType*>(m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(
3568 SwFieldIds::PageNumber )), PG_RANDOM, SVX_NUM_ARABIC);
3569 m_rDoc.getIDocumentContentOperations().InsertPoolItem(*m_pPaM, SwFormatField(aField));
3571 break;
3572 case 0xe:
3573 // if there is only one column word treats a column break like a pagebreak.
3574 if (m_aSectionManager.CurrentSectionColCount() < 2)
3575 bParaMark = HandlePageBreakChar();
3576 else if (!m_nInTable)
3578 // Always insert a txtnode for a column break, e.g. ##
3579 SwContentNode *pCntNd=m_pPaM->GetContentNode();
3580 if (pCntNd!=nullptr && pCntNd->Len()>0) // if par is empty not break is needed
3581 AppendTextNode(*m_pPaM->GetPoint());
3582 m_rDoc.getIDocumentContentOperations().InsertPoolItem(*m_pPaM, SvxFormatBreakItem(SvxBreak::ColumnBefore, RES_BREAK));
3584 break;
3585 case 0x7:
3587 bNewParaEnd = true;
3588 WW8PLCFxDesc* pPap = m_xPlcxMan->GetPap();
3589 //The last paragraph of each cell is terminated by a special
3590 //paragraph mark called a cell mark. Following the cell mark
3591 //that ends the last cell of a table row, the table row is
3592 //terminated by a special paragraph mark called a row mark
3594 //So the 0x7 should be right at the end of the previous
3595 //range to be a real cell-end.
3596 if (pPap->nOrigStartPos == nPosCp+1 ||
3597 pPap->nOrigStartPos == WW8_CP_MAX)
3599 TabCellEnd(); // Table cell/row end
3601 else
3602 bParaMark = true;
3604 break;
3605 case 0xf:
3606 if( !m_bSpec ) // "Satellite"
3607 cInsert = u'\x00a4';
3608 break;
3609 case 0x14:
3610 if( !m_bSpec ) // "Para End" char
3611 cInsert = u'\x00b5';
3612 //TODO: should this be U+00B6 PILCROW SIGN rather than
3613 // U+00B5 MICRO SIGN?
3614 break;
3615 case 0x15:
3616 if( !m_bSpec ) // Juristenparagraph
3618 cp_set::iterator aItr = m_aTOXEndCps.find(static_cast<WW8_CP>(nPosCp));
3619 if (aItr == m_aTOXEndCps.end())
3620 cInsert = u'\x00a7';
3621 else
3622 m_aTOXEndCps.erase(aItr);
3624 break;
3625 case 0x9:
3626 cInsert = '\x9'; // Tab
3627 break;
3628 case 0xb:
3629 cInsert = '\xa'; // Hard NewLine
3630 break;
3631 case 0xc:
3632 bParaMark = HandlePageBreakChar();
3633 break;
3634 case 0x1e: // Non-breaking hyphen
3635 m_rDoc.getIDocumentContentOperations().InsertString( *m_pPaM, OUString(CHAR_HARDHYPHEN) );
3636 break;
3637 case 0x1f: // Non-required hyphens
3638 m_rDoc.getIDocumentContentOperations().InsertString( *m_pPaM, OUString(CHAR_SOFTHYPHEN) );
3639 break;
3640 case 0xa0: // Non-breaking spaces
3641 m_rDoc.getIDocumentContentOperations().InsertString( *m_pPaM, OUString(CHAR_HARDBLANK) );
3642 break;
3643 case 0x1:
3645 Current thinking is that if bObj is set then we have a
3646 straightforward "traditional" ole object, otherwise we have a
3647 graphic preview of an associated ole2 object (or a simple
3648 graphic of course)
3650 normally in the canvas field, the code is 0x8 0x1.
3651 in a special case, the code is 0x1 0x1, which yields a simple picture
3654 bool bReadObj = IsInlineEscherHack();
3655 if( bReadObj )
3657 long nCurPos = m_pStrm->Tell();
3658 sal_uInt16 nWordCode(0);
3660 if( m_bIsUnicode )
3661 m_pStrm->ReadUInt16( nWordCode );
3662 else
3664 sal_uInt8 nByteCode(0);
3665 m_pStrm->ReadUChar( nByteCode );
3666 nWordCode = nByteCode;
3668 if( nWordCode == 0x1 )
3669 bReadObj = false;
3670 m_pStrm->Seek( nCurPos );
3672 if( !bReadObj )
3674 SwFrameFormat *pResult = nullptr;
3675 if (m_bObj)
3676 pResult = ImportOle();
3677 else if (m_bSpec)
3678 pResult = ImportGraf();
3680 // If we have a bad 0x1 insert a space instead.
3681 if (!pResult)
3683 cInsert = ' ';
3684 OSL_ENSURE(!m_bObj && !m_bEmbeddObj && !m_nObjLocFc,
3685 "WW8: Please report this document, it may have a "
3686 "missing graphic");
3688 else
3690 // reset the flags.
3691 m_bObj = m_bEmbeddObj = false;
3692 m_nObjLocFc = 0;
3696 break;
3697 case 0x8:
3698 if( !m_bObj )
3699 Read_GrafLayer( nPosCp );
3700 break;
3701 case 0xd:
3702 bNewParaEnd = bParaMark = true;
3703 if (m_nInTable > 1)
3706 #i9666#/#i23161#
3707 Yes complex, if there is an entry in the undocumented PLCF
3708 which I believe to be a record of cell and row boundaries
3709 see if the magic bit which I believe to mean cell end is
3710 set. I also think btw that the third byte of the 4 byte
3711 value is the level of the cell
3713 WW8PLCFspecial* pTest = m_xPlcxMan->GetMagicTables();
3714 if (pTest && pTest->SeekPosExact(nPosCp+1+nCpOfs) &&
3715 pTest->Where() == nPosCp+1+nCpOfs)
3717 WW8_FC nPos;
3718 void *pData;
3719 sal_uInt32 nData = pTest->Get(nPos, pData) ? SVBT32ToUInt32(*static_cast<SVBT32*>(pData))
3720 : 0;
3721 if (nData & 0x2) // Might be how it works
3723 TabCellEnd();
3724 bParaMark = false;
3727 // tdf#106799: We expect TTP marks to be also cell marks,
3728 // but sometimes sprmPFInnerTtp comes without sprmPFInnerTableCell
3729 else if (m_bWasTabCellEnd || m_bWasTabRowEnd)
3731 TabCellEnd();
3732 bParaMark = false;
3736 m_bWasTabCellEnd = false;
3738 break; // line end
3739 case 0x5: // Annotation reference
3740 case 0x13:
3741 break;
3742 case 0x2: // TODO: Auto-Footnote-Number, should be replaced by SwWW8ImplReader::End_Footnote later
3743 if (!m_aFootnoteStack.empty())
3744 cInsert = 0x2;
3745 break;
3746 default:
3747 SAL_INFO( "sw.ww8.level2", "<unknownValue val=\"" << nWCharVal << "\">" );
3748 break;
3751 if( '\x0' != cInsert )
3753 OUString sInsert(cInsert);
3754 emulateMSWordAddTextToParagraph(sInsert);
3756 if (!m_aApos.back()) // a para end in apo doesn't count
3757 m_bWasParaEnd = bNewParaEnd;
3758 return bParaMark;
3761 void SwWW8ImplReader::ProcessCurrentCollChange(WW8PLCFManResult& rRes,
3762 bool* pStartAttr, bool bCallProcessSpecial)
3764 sal_uInt16 nOldColl = m_nCurrentColl;
3765 m_nCurrentColl = m_xPlcxMan->GetColl();
3767 // Invalid Style-Id
3768 if (m_nCurrentColl >= m_vColl.size() || !m_vColl[m_nCurrentColl].m_pFormat || !m_vColl[m_nCurrentColl].m_bColl)
3770 m_nCurrentColl = 0;
3771 m_bParaAutoBefore = false;
3772 m_bParaAutoAfter = false;
3774 else
3776 m_bParaAutoBefore = m_vColl[m_nCurrentColl].m_bParaAutoBefore;
3777 m_bParaAutoAfter = m_vColl[m_nCurrentColl].m_bParaAutoAfter;
3780 if (nOldColl >= m_vColl.size())
3781 nOldColl = 0; // guess! TODO make sure this is what we want
3783 bool bTabRowEnd = false;
3784 if( pStartAttr && bCallProcessSpecial && !m_bInHyperlink )
3786 bool bReSync;
3787 // Frame/Table/Autonumbering List Level
3788 bTabRowEnd = ProcessSpecial(bReSync, rRes.nCurrentCp + m_xPlcxMan->GetCpOfs());
3789 if( bReSync )
3790 *pStartAttr = m_xPlcxMan->Get( &rRes ); // Get Attribut-Pos again
3793 if (!bTabRowEnd && StyleExists(m_nCurrentColl))
3795 SetTextFormatCollAndListLevel( *m_pPaM, m_vColl[ m_nCurrentColl ]);
3796 ChkToggleAttr(m_vColl[ nOldColl ].m_n81Flags, m_vColl[ m_nCurrentColl ].m_n81Flags);
3797 ChkToggleBiDiAttr(m_vColl[nOldColl].m_n81BiDiFlags,
3798 m_vColl[m_nCurrentColl].m_n81BiDiFlags);
3802 long SwWW8ImplReader::ReadTextAttr(WW8_CP& rTextPos, long nTextEnd, bool& rbStartLine, int nDepthGuard)
3804 long nSkipChars = 0;
3805 WW8PLCFManResult aRes;
3807 OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode");
3808 bool bStartAttr = m_xPlcxMan->Get(&aRes); // Get Attribute position again
3809 aRes.nCurrentCp = rTextPos; // Current Cp position
3811 bool bNewSection = (aRes.nFlags & MAN_MASK_NEW_SEP) && !m_bIgnoreText;
3812 if ( bNewSection ) // New Section
3814 OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode");
3815 // Create PageDesc and fill it
3816 m_aSectionManager.CreateSep(rTextPos);
3817 // -> 0xc was a Sectionbreak, but not a Pagebreak;
3818 // Create PageDesc and fill it
3819 m_bPgSecBreak = false;
3820 OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode");
3823 // New paragraph over Plcx.Fkp.papx
3824 if ( (aRes.nFlags & MAN_MASK_NEW_PAP)|| rbStartLine )
3826 ProcessCurrentCollChange( aRes, &bStartAttr,
3827 MAN_MASK_NEW_PAP == (aRes.nFlags & MAN_MASK_NEW_PAP) &&
3828 !m_bIgnoreText );
3829 rbStartLine = false;
3832 // position of last CP that's to be ignored
3833 long nSkipPos = -1;
3835 if( 0 < aRes.nSprmId ) // Ignore empty Attrs
3837 if( ( eFTN > aRes.nSprmId ) || ( 0x0800 <= aRes.nSprmId ) )
3839 if( bStartAttr ) // WW attributes
3841 if( aRes.nMemLen >= 0 )
3842 ImportSprm(aRes.pMemPos, aRes.nMemLen, aRes.nSprmId);
3844 else
3845 EndSprm( aRes.nSprmId ); // Switch off Attr
3847 else if( aRes.nSprmId < 0x800 ) // Own helper attributes
3849 if (bStartAttr)
3851 nSkipChars = ImportExtSprm(&aRes);
3852 if (
3853 (aRes.nSprmId == eFTN) || (aRes.nSprmId == eEDN) ||
3854 (aRes.nSprmId == eFLD) || (aRes.nSprmId == eAND)
3857 WW8_CP nMaxLegalSkip = nTextEnd - rTextPos;
3858 // Skip Field/Footnote-/End-Note here
3859 rTextPos += std::min<WW8_CP>(nSkipChars, nMaxLegalSkip);
3860 nSkipPos = rTextPos-1;
3863 else
3864 EndExtSprm( aRes.nSprmId );
3868 sal_Int32 nRequestedPos = m_xSBase->WW8Cp2Fc(m_xPlcxMan->GetCpOfs() + rTextPos, &m_bIsUnicode);
3869 bool bValidPos = checkSeek(*m_pStrm, nRequestedPos);
3870 SAL_WARN_IF(!bValidPos, "sw.ww8", "Document claimed to have text at an invalid position, skip attributes for region");
3872 // Find next Attr position (and Skip attributes of field contents if needed)
3873 if (nSkipChars && !m_bIgnoreText)
3874 m_xCtrlStck->MarkAllAttrsOld();
3875 bool bOldIgnoreText = m_bIgnoreText;
3876 m_bIgnoreText = true;
3877 sal_uInt16 nOldColl = m_nCurrentColl;
3878 bool bDoPlcxManPlusPLus = true;
3879 long nNext;
3882 if( bDoPlcxManPlusPLus )
3883 m_xPlcxMan->advance();
3884 nNext = bValidPos ? m_xPlcxMan->Where() : nTextEnd;
3886 if (m_pPostProcessAttrsInfo &&
3887 m_pPostProcessAttrsInfo->mnCpStart == nNext)
3889 m_pPostProcessAttrsInfo->mbCopy = true;
3892 if( (0 <= nNext) && (nSkipPos >= nNext) )
3894 if (nDepthGuard >= 1024)
3896 SAL_WARN("sw.ww8", "ReadTextAttr hit recursion limit");
3897 nNext = nTextEnd;
3899 else
3900 nNext = ReadTextAttr(rTextPos, nTextEnd, rbStartLine, nDepthGuard + 1);
3901 bDoPlcxManPlusPLus = false;
3902 m_bIgnoreText = true;
3905 if (m_pPostProcessAttrsInfo &&
3906 nNext > m_pPostProcessAttrsInfo->mnCpEnd)
3908 m_pPostProcessAttrsInfo->mbCopy = false;
3911 while( nSkipPos >= nNext );
3912 m_bIgnoreText = bOldIgnoreText;
3913 if( nSkipChars )
3915 m_xCtrlStck->KillUnlockedAttrs( *m_pPaM->GetPoint() );
3916 if( nOldColl != m_xPlcxMan->GetColl() )
3917 ProcessCurrentCollChange(aRes, nullptr, false);
3920 return nNext;
3923 //Revised 2012.8.16 for the complex attribute presentation of 0x0D in MS
3924 bool SwWW8ImplReader::IsParaEndInCPs(sal_Int32 nStart, sal_Int32 nEnd,bool bSdOD) const
3926 //Revised for performance consideration
3927 if (nStart == -1 || nEnd == -1 || nEnd < nStart )
3928 return false;
3930 return std::any_of(m_aEndParaPos.rbegin(), m_aEndParaPos.rend(),
3931 [=](const WW8_CP& rPos) {
3932 //Revised 2012.8.16,to the 0x0D,the attribute will have two situations
3933 //*********within***********exact******
3934 //*********but also sample with only left and the position of 0x0d is the edge of the right side***********
3935 return (bSdOD && ((nStart < rPos && nEnd > rPos) || (nStart == nEnd && rPos == nStart))) ||
3936 (!bSdOD && (nStart < rPos && nEnd >= rPos));
3941 //Clear the para end position recorded in reader intermittently for the least impact on loading performance
3942 void SwWW8ImplReader::ClearParaEndPosition()
3944 if ( !m_aEndParaPos.empty() )
3945 m_aEndParaPos.clear();
3948 void SwWW8ImplReader::ReadAttrs(WW8_CP& rTextPos, WW8_CP& rNext, long nTextEnd, bool& rbStartLine)
3950 // Do we have attributes?
3951 if( rTextPos >= rNext )
3955 m_aCurrAttrCP = rTextPos;
3956 rNext = ReadTextAttr(rTextPos, nTextEnd, rbStartLine);
3957 if (rTextPos == rNext && rTextPos >= nTextEnd)
3958 break;
3960 while( rTextPos >= rNext );
3963 else if ( rbStartLine )
3965 /* No attributes, but still a new line.
3966 * If a line ends with a line break and paragraph attributes or paragraph templates
3967 * do NOT change the line end was not added to the Plcx.Fkp.papx i.e. (nFlags & MAN_MASK_NEW_PAP)
3968 * is false.
3969 * Due to this we need to set the template here as a kind of special treatment.
3971 if (!m_bCpxStyle && m_nCurrentColl < m_vColl.size())
3972 SetTextFormatCollAndListLevel(*m_pPaM, m_vColl[m_nCurrentColl]);
3973 rbStartLine = false;
3978 * CloseAttrEnds to only read the attribute ends at the end of a text or a
3979 * text area (Header, Footnote, ...).
3980 * We ignore attribute starts and fields.
3982 void SwWW8ImplReader::CloseAttrEnds()
3984 // If there are any unclosed sprms then copy them to
3985 // another stack and close the ones that must be closed
3986 std::stack<sal_uInt16> aStack;
3987 m_xPlcxMan->TransferOpenSprms(aStack);
3989 while (!aStack.empty())
3991 sal_uInt16 nSprmId = aStack.top();
3992 if ((0 < nSprmId) && (( eFTN > nSprmId) || (0x0800 <= nSprmId)))
3993 EndSprm(nSprmId);
3994 aStack.pop();
3997 EndSpecial();
4000 bool SwWW8ImplReader::ReadText(WW8_CP nStartCp, WW8_CP nTextLen, ManTypes nType)
4002 bool bJoined=false;
4004 bool bStartLine = true;
4005 short nCrCount = 0;
4006 short nDistance = 0;
4008 m_bWasParaEnd = false;
4009 m_nCurrentColl = 0;
4010 m_xCurrentItemSet.reset();
4011 m_nCharFormat = -1;
4012 m_bSpec = false;
4013 m_bPgSecBreak = false;
4015 m_xPlcxMan.reset(new WW8PLCFMan(m_xSBase.get(), nType, nStartCp));
4016 long nCpOfs = m_xPlcxMan->GetCpOfs(); // Offset for Header/Footer, Footnote
4018 WW8_CP nNext = m_xPlcxMan->Where();
4019 m_pPreviousNode = nullptr;
4020 sal_uInt8 nDropLines = 0;
4021 SwCharFormat* pNewSwCharFormat = nullptr;
4022 const SwCharFormat* pFormat = nullptr;
4024 bool bValidPos = checkSeek(*m_pStrm, m_xSBase->WW8Cp2Fc(nStartCp + nCpOfs, &m_bIsUnicode));
4025 if (!bValidPos)
4026 return false;
4028 WW8_CP l = nStartCp;
4029 const WW8_CP nMaxPossible = WW8_CP_MAX-nStartCp;
4030 if (nTextLen > nMaxPossible)
4032 SAL_WARN_IF(nTextLen > nMaxPossible, "sw.ww8", "TextLen too long");
4033 nTextLen = nMaxPossible;
4035 WW8_CP nTextEnd = nStartCp+nTextLen;
4036 while (l < nTextEnd)
4038 ReadAttrs( l, nNext, nTextEnd, bStartLine );// Takes SectionBreaks into account, too
4039 OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode");
4041 if (m_pPostProcessAttrsInfo != nullptr)
4042 PostProcessAttrs();
4044 if (l >= nTextEnd)
4045 break;
4047 bStartLine = ReadChars(l, nNext, nTextEnd, nCpOfs);
4049 // If the previous paragraph was a dropcap then do not
4050 // create a new txtnode and join the two paragraphs together
4051 if (bStartLine && !m_pPreviousNode) // Line end
4053 bool bSplit = true;
4054 if (m_bCareFirstParaEndInToc)
4056 m_bCareFirstParaEndInToc = false;
4057 if (m_pPaM->End() && m_pPaM->End()->nNode.GetNode().GetTextNode() && m_pPaM->End()->nNode.GetNode().GetTextNode()->Len() == 0)
4058 bSplit = false;
4060 if (m_bCareLastParaEndInToc)
4062 m_bCareLastParaEndInToc = false;
4063 if (m_pPaM->End() && m_pPaM->End()->nNode.GetNode().GetTextNode() && m_pPaM->End()->nNode.GetNode().GetTextNode()->Len() == 0)
4064 bSplit = false;
4066 if (bSplit)
4068 // We will record the CP of a paragraph end ('0x0D'), if current loading contents is from main stream;
4069 if (m_bOnLoadingMain)
4070 m_aEndParaPos.push_back(l-1);
4071 AppendTextNode(*m_pPaM->GetPoint());
4075 if (m_pPreviousNode && bStartLine)
4077 SwTextNode* pEndNd = m_pPaM->GetNode().GetTextNode();
4078 const sal_Int32 nDropCapLen = m_pPreviousNode->GetText().getLength();
4080 // Need to reset the font size and text position for the dropcap
4082 SwPaM aTmp(*pEndNd, 0, *pEndNd, nDropCapLen+1);
4083 m_xCtrlStck->Delete(aTmp);
4086 // Get the default document dropcap which we can use as our template
4087 const SwFormatDrop* defaultDrop =
4088 static_cast<const SwFormatDrop*>( GetFormatAttr(RES_PARATR_DROP));
4089 SwFormatDrop aDrop(*defaultDrop);
4091 aDrop.GetLines() = nDropLines;
4092 aDrop.GetDistance() = nDistance;
4093 aDrop.GetChars() = writer_cast<sal_uInt8>(nDropCapLen);
4094 // Word has no concept of a "whole word dropcap"
4095 aDrop.GetWholeWord() = false;
4097 if (pFormat)
4098 aDrop.SetCharFormat(const_cast<SwCharFormat*>(pFormat));
4099 else if(pNewSwCharFormat)
4100 aDrop.SetCharFormat(pNewSwCharFormat);
4102 SwPosition aStart(*pEndNd);
4103 m_xCtrlStck->NewAttr(aStart, aDrop);
4104 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_PARATR_DROP);
4105 m_pPreviousNode = nullptr;
4107 else if (m_bDropCap)
4109 // If we have found a dropcap store the textnode
4110 m_pPreviousNode = m_pPaM->GetNode().GetTextNode();
4112 SprmResult aDCS;
4113 if (m_bVer67)
4114 aDCS = m_xPlcxMan->GetPapPLCF()->HasSprm(46);
4115 else
4116 aDCS = m_xPlcxMan->GetPapPLCF()->HasSprm(0x442C);
4118 if (aDCS.pSprm && aDCS.nRemainingData >= 1)
4119 nDropLines = (*aDCS.pSprm) >> 3;
4120 else // There is no Drop Cap Specifier hence no dropcap
4121 m_pPreviousNode = nullptr;
4123 SprmResult aDistance = m_xPlcxMan->GetPapPLCF()->HasSprm(0x842F);
4124 if (aDistance.pSprm && aDistance.nRemainingData >= 2)
4125 nDistance = SVBT16ToUInt16(aDistance.pSprm);
4126 else
4127 nDistance = 0;
4129 const SwFormatCharFormat *pSwFormatCharFormat = nullptr;
4131 if (m_xCurrentItemSet)
4132 pSwFormatCharFormat = &(ItemGet<SwFormatCharFormat>(*m_xCurrentItemSet, RES_TXTATR_CHARFMT));
4134 if (pSwFormatCharFormat)
4135 pFormat = pSwFormatCharFormat->GetCharFormat();
4137 if (m_xCurrentItemSet && !pFormat)
4139 OUString sPrefix = "WW8Dropcap" + OUString::number(m_nDropCap++);
4140 pNewSwCharFormat = m_rDoc.MakeCharFormat(sPrefix, m_rDoc.GetDfltCharFormat());
4141 m_xCurrentItemSet->ClearItem(RES_CHRATR_ESCAPEMENT);
4142 pNewSwCharFormat->SetFormatAttr(*m_xCurrentItemSet);
4145 m_xCurrentItemSet.reset();
4146 m_bDropCap=false;
4149 if (bStartLine || m_bWasTabRowEnd)
4151 // Call all 64 CRs; not for Header and the like
4152 if ((nCrCount++ & 0x40) == 0 && nType == MAN_MAINTEXT && l <= nTextLen)
4154 if (nTextLen < WW8_CP_MAX/100)
4155 m_nProgress = static_cast<sal_uInt16>(l * 100 / nTextLen);
4156 else
4157 m_nProgress = static_cast<sal_uInt16>(l / nTextLen * 100);
4158 m_xProgress->Update(m_nProgress); // Update
4162 // If we have encountered a 0x0c which indicates either section of
4163 // pagebreak then look it up to see if it is a section break, and
4164 // if it is not then insert a page break. If it is a section break
4165 // it will be handled as such in the ReadAttrs of the next loop
4166 if (m_bPgSecBreak)
4168 // We need only to see if a section is ending at this cp,
4169 // the plcf will already be sitting on the correct location
4170 // if it is there.
4171 WW8PLCFxDesc aTemp;
4172 aTemp.nStartPos = aTemp.nEndPos = WW8_CP_MAX;
4173 if (m_xPlcxMan->GetSepPLCF())
4174 m_xPlcxMan->GetSepPLCF()->GetSprms(&aTemp);
4175 if ((aTemp.nStartPos != l) && (aTemp.nEndPos != l))
4177 // #i39251# - insert text node for page break, if no one inserted.
4178 // #i43118# - refine condition: the anchor
4179 // control stack has to have entries, otherwise it's not needed
4180 // to insert a text node.
4181 if (!bStartLine && !m_xAnchorStck->empty())
4183 AppendTextNode(*m_pPaM->GetPoint());
4185 m_rDoc.getIDocumentContentOperations().InsertPoolItem(*m_pPaM,
4186 SvxFormatBreakItem(SvxBreak::PageBefore, RES_BREAK));
4187 m_bFirstParaOfPage = true;
4188 m_bPgSecBreak = false;
4193 m_pPreviousNode = nullptr;
4195 if (m_pPaM->GetPoint()->nContent.GetIndex())
4196 AppendTextNode(*m_pPaM->GetPoint());
4198 if (!m_bInHyperlink)
4199 bJoined = JoinNode(*m_pPaM);
4201 CloseAttrEnds();
4203 m_xPlcxMan.reset();
4204 return bJoined;
4207 SwWW8ImplReader::SwWW8ImplReader(sal_uInt8 nVersionPara, SotStorage* pStorage,
4208 SvStream* pSt, SwDoc& rD, const OUString& rBaseURL, bool bNewDoc, bool bSkipImages, SwPosition const &rPos)
4209 : m_pDocShell(rD.GetDocShell())
4210 , m_pStg(pStorage)
4211 , m_pStrm(pSt)
4212 , m_pTableStream(nullptr)
4213 , m_pDataStream(nullptr)
4214 , m_rDoc(rD)
4215 , m_pPaM(nullptr)
4216 , m_aSectionManager(*this)
4217 , m_aExtraneousParas(rD)
4218 , m_aInsertedTables(rD)
4219 , m_aSectionNameGenerator(rD, "WW")
4220 , m_aGrfNameGenerator(bNewDoc, OUString('G'))
4221 , m_aParaStyleMapper(rD)
4222 , m_aCharStyleMapper(rD)
4223 , m_pFlyFormatOfJustInsertedGraphic(nullptr)
4224 , m_pFormatOfJustInsertedApo(nullptr)
4225 , m_pPreviousNumPaM(nullptr)
4226 , m_pPrevNumRule(nullptr)
4227 , m_aTextNodesHavingFirstLineOfstSet()
4228 , m_aTextNodesHavingLeftIndentSet()
4229 , m_pCurrentColl(nullptr)
4230 , m_pDfltTextFormatColl(nullptr)
4231 , m_pStandardFormatColl(nullptr)
4232 , m_pDrawModel(nullptr)
4233 , m_pDrawPg(nullptr)
4234 , m_pNumFieldType(nullptr)
4235 , m_sBaseURL(rBaseURL)
4236 , m_nIniFlags(0)
4237 , m_nIniFlags1(0)
4238 , m_nFieldFlags(0)
4239 , m_bRegardHindiDigits( false )
4240 , m_bDrawCpOValid( false )
4241 , m_nDrawCpO(0)
4242 , m_nPicLocFc(0)
4243 , m_nObjLocFc(0)
4244 , m_nIniFlyDx(0)
4245 , m_nIniFlyDy(0)
4246 , m_eTextCharSet(RTL_TEXTENCODING_ASCII_US)
4247 , m_eStructCharSet(RTL_TEXTENCODING_ASCII_US)
4248 , m_eHardCharSet(RTL_TEXTENCODING_DONTKNOW)
4249 , m_nProgress(0)
4250 , m_nCurrentColl(0)
4251 , m_nFieldNum(0)
4252 , m_nLFOPosition(USHRT_MAX)
4253 , m_nCharFormat(0)
4254 , m_nDrawXOfs(0)
4255 , m_nDrawYOfs(0)
4256 , m_nDrawXOfs2(0)
4257 , m_nDrawYOfs2(0)
4258 , m_cSymbol(0)
4259 , m_nWantedVersion(nVersionPara)
4260 , m_nSwNumLevel(0xff)
4261 , m_nWwNumType(0xff)
4262 , m_nListLevel(WW8ListManager::nMaxLevel)
4263 , m_bNewDoc(bNewDoc)
4264 , m_bSkipImages(bSkipImages)
4265 , m_bReadNoTable(false)
4266 , m_bPgSecBreak(false)
4267 , m_bSpec(false)
4268 , m_bObj(false)
4269 , m_bTxbxFlySection(false)
4270 , m_bHasBorder(false)
4271 , m_bSymbol(false)
4272 , m_bIgnoreText(false)
4273 , m_nInTable(0)
4274 , m_bWasTabRowEnd(false)
4275 , m_bWasTabCellEnd(false)
4276 , m_bAnl(false)
4277 , m_bHdFtFootnoteEdn(false)
4278 , m_bFootnoteEdn(false)
4279 , m_bIsHeader(false)
4280 , m_bIsFooter(false)
4281 , m_bIsUnicode(false)
4282 , m_bCpxStyle(false)
4283 , m_bStyNormal(false)
4284 , m_bWWBugNormal(false)
4285 , m_bNoAttrImport(false)
4286 , m_bInHyperlink(false)
4287 , m_bWasParaEnd(false)
4288 , m_bVer67(false)
4289 , m_bVer6(false)
4290 , m_bVer7(false)
4291 , m_bVer8(false)
4292 , m_bEmbeddObj(false)
4293 , m_bCurrentAND_fNumberAcross(false)
4294 , m_bNoLnNumYet(true)
4295 , m_bFirstPara(true)
4296 , m_bFirstParaOfPage(false)
4297 , m_bParaAutoBefore(false)
4298 , m_bParaAutoAfter(false)
4299 , m_bDropCap(false)
4300 , m_nDropCap(0)
4301 , m_bBidi(false)
4302 , m_bReadTable(false)
4303 , m_bLoadingTOXCache(false)
4304 , m_nEmbeddedTOXLevel(0)
4305 , m_bLoadingTOXHyperlink(false)
4306 , m_pPreviousNode(nullptr)
4307 , m_bCareFirstParaEndInToc(false)
4308 , m_bCareLastParaEndInToc(false)
4309 , m_aTOXEndCps()
4310 , m_aCurrAttrCP(-1)
4311 , m_bOnLoadingMain(false)
4312 , m_bNotifyMacroEventRead(false)
4314 m_pStrm->SetEndian( SvStreamEndian::LITTLE );
4315 m_aApos.push_back(false);
4317 mpCursor = m_rDoc.CreateUnoCursor(rPos);
4320 SwWW8ImplReader::~SwWW8ImplReader()
4324 void SwWW8ImplReader::DeleteStack(std::unique_ptr<SwFltControlStack> pStck)
4326 if( pStck )
4328 pStck->SetAttr( *m_pPaM->GetPoint(), 0, false);
4329 pStck->SetAttr( *m_pPaM->GetPoint(), 0, false);
4331 else
4333 OSL_ENSURE( false, "WW stack already deleted" );
4337 void wwSectionManager::SetSegmentToPageDesc(const wwSection &rSection,
4338 bool bIgnoreCols)
4340 SwPageDesc &rPage = *rSection.mpPage;
4342 SetNumberingType(rSection, rPage);
4344 SwFrameFormat &rFormat = rPage.GetMaster();
4346 if(mrReader.m_xWDop->fUseBackGroundInAllmodes) // #i56806# Make sure mrReader is initialized
4347 mrReader.GrafikCtor();
4349 if (mrReader.m_xWDop->fUseBackGroundInAllmodes && mrReader.m_xMSDffManager)
4351 tools::Rectangle aRect(0, 0, 100, 100); // A dummy, we don't care about the size
4352 SvxMSDffImportData aData(aRect);
4353 SdrObject* pObject = nullptr;
4354 if (mrReader.m_xMSDffManager->GetShape(0x401, pObject, aData) && !aData.empty())
4356 // Only handle shape if it is a background shape
4357 if (aData.begin()->get()->nFlags & ShapeFlag::Background)
4359 SfxItemSet aSet(rFormat.GetAttrSet());
4360 mrReader.MatchSdrItemsIntoFlySet(pObject, aSet, mso_lineSimple,
4361 mso_lineSolid, mso_sptRectangle, aRect);
4362 rFormat.SetFormatAttr(aSet.Get(RES_BACKGROUND));
4365 SdrObject::Free(pObject);
4367 wwULSpaceData aULData;
4368 GetPageULData(rSection, aULData);
4369 SetPageULSpaceItems(rFormat, aULData, rSection);
4371 rPage.SetVerticalAdjustment( rSection.mnVerticalAdjustment );
4373 SetPage(rPage, rFormat, rSection, bIgnoreCols);
4375 if (!(rSection.maSep.pgbApplyTo & 1))
4376 SwWW8ImplReader::SetPageBorder(rFormat, rSection);
4377 if (!(rSection.maSep.pgbApplyTo & 2))
4378 SwWW8ImplReader::SetPageBorder(rPage.GetFirstMaster(), rSection);
4380 mrReader.SetDocumentGrid(rFormat, rSection);
4383 void wwSectionManager::SetUseOn(wwSection &rSection)
4385 bool bMirror = mrReader.m_xWDop->fMirrorMargins ||
4386 mrReader.m_xWDop->doptypography.m_f2on1;
4388 UseOnPage eUseBase = bMirror ? UseOnPage::Mirror : UseOnPage::All;
4389 UseOnPage eUse = eUseBase;
4390 if (!mrReader.m_xWDop->fFacingPages)
4391 eUse |= UseOnPage::HeaderShare | UseOnPage::FooterShare;
4392 if (!rSection.HasTitlePage())
4393 eUse |= UseOnPage::FirstShare;
4395 OSL_ENSURE(rSection.mpPage, "Makes no sense to call me with no pages to set");
4396 if (rSection.mpPage)
4397 rSection.mpPage->WriteUseOn(eUse);
4401 * Set the page descriptor on this node, handle the different cases for a text
4402 * node or a table
4404 static void GiveNodePageDesc(SwNodeIndex const &rIdx, const SwFormatPageDesc &rPgDesc,
4405 SwDoc &rDoc)
4408 If it's a table here, apply the pagebreak to the table
4409 properties, otherwise we add it to the para at this
4410 position
4412 if (rIdx.GetNode().IsTableNode())
4414 SwTable& rTable =
4415 rIdx.GetNode().GetTableNode()->GetTable();
4416 SwFrameFormat* pApply = rTable.GetFrameFormat();
4417 OSL_ENSURE(pApply, "impossible");
4418 if (pApply)
4419 pApply->SetFormatAttr(rPgDesc);
4421 else
4423 SwPosition aPamStart(rIdx);
4424 aPamStart.nContent.Assign(
4425 rIdx.GetNode().GetContentNode(), 0);
4426 SwPaM aPage(aPamStart);
4428 rDoc.getIDocumentContentOperations().InsertPoolItem(aPage, rPgDesc);
4433 * Map a word section to a writer page descriptor
4435 SwFormatPageDesc wwSectionManager::SetSwFormatPageDesc(mySegIter const &rIter,
4436 mySegIter const &rStart, bool bIgnoreCols)
4438 if (mrReader.m_bNewDoc && rIter == rStart)
4440 rIter->mpPage =
4441 mrReader.m_rDoc.getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD);
4443 else
4445 rIter->mpPage = mrReader.m_rDoc.MakePageDesc(
4446 SwViewShell::GetShellRes()->GetPageDescName(mnDesc, ShellResource::NORMAL_PAGE),
4447 nullptr, false);
4449 OSL_ENSURE(rIter->mpPage, "no page!");
4450 if (!rIter->mpPage)
4451 return SwFormatPageDesc();
4453 // Set page before hd/ft
4454 const wwSection *pPrevious = nullptr;
4455 if (rIter != rStart)
4456 pPrevious = &(*(rIter-1));
4457 SetHdFt(*rIter, std::distance(rStart, rIter), pPrevious);
4458 SetUseOn(*rIter);
4460 // Set hd/ft after set page
4461 SetSegmentToPageDesc(*rIter, bIgnoreCols);
4463 SwFormatPageDesc aRet(rIter->mpPage);
4465 rIter->mpPage->SetFollow(rIter->mpPage);
4467 if (rIter->PageRestartNo())
4468 aRet.SetNumOffset(rIter->PageStartAt());
4470 ++mnDesc;
4471 return aRet;
4474 void wwSectionManager::InsertSegments()
4476 mySegIter aEnd = maSegments.end();
4477 mySegIter aStart = maSegments.begin();
4478 for (mySegIter aIter = aStart; aIter != aEnd; ++aIter)
4480 // If the section is of type "New column" (0x01), then simply insert a column break.
4481 // But only if there actually are columns on the page, otherwise a column break
4482 // seems to be handled like a page break by MSO.
4483 if ( aIter->maSep.bkc == 1 && aIter->maSep.ccolM1 > 0 )
4485 SwPaM start( aIter->maStart );
4486 mrReader.m_rDoc.getIDocumentContentOperations().InsertPoolItem( start, SvxFormatBreakItem(SvxBreak::ColumnBefore, RES_BREAK));
4487 continue;
4490 mySegIter aNext = aIter+1;
4491 mySegIter aPrev = (aIter == aStart) ? aIter : aIter-1;
4493 // If two following sections are different in following properties, Word will interpret a continuous
4494 // section break between them as if it was a section break next page.
4495 bool bThisAndPreviousAreCompatible = ((aIter->GetPageWidth() == aPrev->GetPageWidth()) &&
4496 (aIter->GetPageHeight() == aPrev->GetPageHeight()) && (aIter->IsLandScape() == aPrev->IsLandScape()));
4498 bool bInsertSection = (aIter != aStart) && aIter->IsContinuous() && bThisAndPreviousAreCompatible;
4499 bool bInsertPageDesc = !bInsertSection;
4500 // HACK Force new pagedesc if margins change, otherwise e.g. floating tables may be anchored improperly.
4501 if( aIter->maSep.dyaTop != aPrev->maSep.dyaTop || aIter->maSep.dyaBottom != aPrev->maSep.dyaBottom
4502 || aIter->maSep.dxaLeft != aPrev->maSep.dxaLeft || aIter->maSep.dxaRight != aPrev->maSep.dxaRight )
4503 bInsertPageDesc = true;
4504 bool bProtected = SectionIsProtected(*aIter); // do we really need this ?? I guess I have a different logic in editshell which disables this...
4506 if (bInsertPageDesc)
4509 If a cont section follows this section then we won't be
4510 creating a page desc with 2+ cols as we cannot host a one
4511 col section in a 2+ col pagedesc and make it look like
4512 word. But if the current section actually has columns then
4513 we are forced to insert a section here as well as a page
4514 descriptor.
4517 bool bIgnoreCols = bInsertSection;
4518 bool bThisAndNextAreCompatible = (aNext == aEnd) ||
4519 ((aIter->GetPageWidth() == aNext->GetPageWidth()) &&
4520 (aIter->GetPageHeight() == aNext->GetPageHeight()) &&
4521 (aIter->IsLandScape() == aNext->IsLandScape()));
4523 if ((aNext != aEnd && aNext->IsContinuous() && bThisAndNextAreCompatible) || bProtected)
4525 bIgnoreCols = true;
4526 if ((aIter->NoCols() > 1) || bProtected)
4527 bInsertSection = true;
4530 SwFormatPageDesc aDesc(SetSwFormatPageDesc(aIter, aStart, bIgnoreCols));
4531 if (!aDesc.GetPageDesc())
4532 continue;
4534 // special case handling for odd/even section break
4535 // a) as before create a new page style for the section break
4536 // b) set Layout of generated page style to right/left ( according
4537 // to section break odd/even )
4538 // c) create a new style to follow the break page style
4539 if ( aIter->maSep.bkc == 3 || aIter->maSep.bkc == 4 )
4541 // SetSwFormatPageDesc calls some methods that could
4542 // modify aIter (e.g. wwSection ).
4543 // Since we call SetSwFormatPageDesc below to generate the
4544 // 'Following' style of the Break style, it is safer
4545 // to take a copy of the contents of aIter.
4546 wwSection aTmpSection = *aIter;
4547 // create a new following page style
4548 SwFormatPageDesc aFollow(SetSwFormatPageDesc(aIter, aStart, bIgnoreCols));
4549 // restore any contents of aIter trashed by SetSwFormatPageDesc
4550 *aIter = aTmpSection;
4552 // Handle the section break
4553 UseOnPage eUseOnPage = UseOnPage::Left;
4554 if ( aIter->maSep.bkc == 4 ) // Odd ( right ) Section break
4555 eUseOnPage = UseOnPage::Right;
4557 // Keep the share flags.
4558 aDesc.GetPageDesc()->SetUseOn( eUseOnPage );
4559 aDesc.GetPageDesc()->SetFollow( aFollow.GetPageDesc() );
4562 GiveNodePageDesc(aIter->maStart, aDesc, mrReader.m_rDoc);
4565 SwTextNode* pTextNd = nullptr;
4566 if (bInsertSection)
4568 // Start getting the bounds of this section
4569 SwPaM aSectPaM(*mrReader.m_pPaM, mrReader.m_pPaM);
4570 SwNodeIndex aAnchor(aSectPaM.GetPoint()->nNode);
4571 if (aNext != aEnd)
4573 aAnchor = aNext->maStart;
4574 aSectPaM.GetPoint()->nNode = aAnchor;
4575 aSectPaM.GetPoint()->nContent.Assign(
4576 aNext->maStart.GetNode().GetContentNode(), 0);
4577 aSectPaM.Move(fnMoveBackward);
4580 const SwPosition* pPos = aSectPaM.GetPoint();
4581 SwTextNode const*const pSttNd = pPos->nNode.GetNode().GetTextNode();
4582 const SwTableNode* pTableNd = pSttNd ? pSttNd->FindTableNode() : nullptr;
4583 if (pTableNd)
4585 pTextNd =
4586 mrReader.m_rDoc.GetNodes().MakeTextNode(aAnchor,
4587 mrReader.m_rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TEXT ));
4589 aSectPaM.GetPoint()->nNode.Assign(*pTextNd);
4590 aSectPaM.GetPoint()->nContent.Assign(
4591 aSectPaM.GetContentNode(), 0);
4594 aSectPaM.SetMark();
4596 aSectPaM.GetPoint()->nNode = aIter->maStart;
4597 aSectPaM.GetPoint()->nContent.Assign(
4598 aSectPaM.GetContentNode(), 0);
4600 bool bHasOwnHdFt = false;
4602 In this nightmare scenario the continuous section has its own
4603 headers and footers so we will try and find a hard page break
4604 between here and the end of the section and put the headers and
4605 footers there.
4607 if (!bInsertPageDesc)
4609 bHasOwnHdFt =
4610 mrReader.HasOwnHeaderFooter(
4611 aIter->maSep.grpfIhdt & ~(WW8_HEADER_FIRST | WW8_FOOTER_FIRST),
4612 aIter->maSep.grpfIhdt, std::distance(aStart, aIter)
4615 if (bHasOwnHdFt)
4617 // #i40766# Need to cache the page descriptor in case there is
4618 // no page break in the section
4619 SwPageDesc *pOrig = aIter->mpPage;
4620 bool bFailed = true;
4621 SwFormatPageDesc aDesc(SetSwFormatPageDesc(aIter, aStart, true));
4622 if (aDesc.GetPageDesc())
4624 sal_uLong nStart = aSectPaM.Start()->nNode.GetIndex();
4625 sal_uLong nEnd = aSectPaM.End()->nNode.GetIndex();
4626 for(; nStart <= nEnd; ++nStart)
4628 SwNode* pNode = mrReader.m_rDoc.GetNodes()[nStart];
4629 if (!pNode)
4630 continue;
4631 if (sw::util::HasPageBreak(*pNode))
4633 SwNodeIndex aIdx(*pNode);
4634 GiveNodePageDesc(aIdx, aDesc, mrReader.m_rDoc);
4635 bFailed = false;
4636 break;
4640 if(bFailed)
4642 aIter->mpPage = pOrig;
4646 // End getting the bounds of this section, quite a job eh?
4647 SwSectionFormat *pRet = InsertSection(aSectPaM, *aIter);
4648 // The last section if continuous is always unbalanced
4649 if (pRet)
4651 // Set the columns to be UnBalanced if that compatibility option is set
4652 if (mrReader.m_xWDop->fNoColumnBalance)
4653 pRet->SetFormatAttr(SwFormatNoBalancedColumns(true));
4654 else
4656 // Otherwise set to unbalanced if the following section is
4657 // not continuous, (which also means that the last section
4658 // is unbalanced)
4659 if (aNext == aEnd || !aNext->IsContinuous())
4660 pRet->SetFormatAttr(SwFormatNoBalancedColumns(true));
4665 if (pTextNd)
4667 SwNodeIndex aIdx(*pTextNd);
4668 SwPaM aTest(aIdx);
4669 mrReader.m_rDoc.getIDocumentContentOperations().DelFullPara(aTest);
4670 pTextNd = nullptr;
4675 void wwExtraneousParas::delete_all_from_doc()
4677 auto aEnd = m_aTextNodes.rend();
4678 for (auto aI = m_aTextNodes.rbegin(); aI != aEnd; ++aI)
4680 SwTextNode *pTextNode = *aI;
4681 SwNodeIndex aIdx(*pTextNode);
4682 SwPaM aTest(aIdx);
4683 m_rDoc.getIDocumentContentOperations().DelFullPara(aTest);
4685 m_aTextNodes.clear();
4688 void SwWW8ImplReader::StoreMacroCmds()
4690 if (m_xWwFib->m_lcbCmds)
4692 bool bValidPos = checkSeek(*m_pTableStream, m_xWwFib->m_fcCmds);
4693 if (!bValidPos)
4694 return;
4696 uno::Reference < embed::XStorage > xRoot(m_pDocShell->GetStorage());
4698 if (!xRoot.is())
4699 return;
4703 NotifyMacroEventRead();
4705 uno::Reference < io::XStream > xStream =
4706 xRoot->openStreamElement( SL::aMSMacroCmds, embed::ElementModes::READWRITE );
4707 std::unique_ptr<SvStream> xOutStream(::utl::UcbStreamHelper::CreateStream(xStream));
4709 sal_uInt32 lcbCmds = std::min<sal_uInt32>(m_xWwFib->m_lcbCmds, m_pTableStream->remainingSize());
4710 std::unique_ptr<sal_uInt8[]> xBuffer(new sal_uInt8[lcbCmds]);
4711 m_xWwFib->m_lcbCmds = m_pTableStream->ReadBytes(xBuffer.get(), lcbCmds);
4712 xOutStream->WriteBytes(xBuffer.get(), m_xWwFib->m_lcbCmds);
4714 catch (...)
4720 void SwWW8ImplReader::ReadDocVars()
4722 std::vector<OUString> aDocVarStrings;
4723 std::vector<ww::bytes> aDocVarStringIds;
4724 std::vector<OUString> aDocValueStrings;
4725 WW8ReadSTTBF(!m_bVer67, *m_pTableStream, m_xWwFib->m_fcStwUser,
4726 m_xWwFib->m_lcbStwUser, m_bVer67 ? 2 : 0, m_eStructCharSet,
4727 aDocVarStrings, &aDocVarStringIds, &aDocValueStrings);
4728 if (!m_bVer67) {
4729 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
4730 m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
4731 uno::Reference<document::XDocumentProperties> xDocProps(
4732 xDPS->getDocumentProperties());
4733 OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
4734 uno::Reference<beans::XPropertyContainer> xUserDefinedProps =
4735 xDocProps->getUserDefinedProperties();
4736 OSL_ENSURE(xUserDefinedProps.is(), "UserDefinedProperties is null");
4738 for(size_t i=0; i<aDocVarStrings.size(); i++)
4740 const OUString &rName = aDocVarStrings[i];
4741 uno::Any aValue;
4742 aValue <<= rName;
4743 try {
4744 xUserDefinedProps->addProperty( rName,
4745 beans::PropertyAttribute::REMOVABLE,
4746 aValue );
4747 } catch (const uno::Exception &) {
4748 // ignore
4755 * Document Info
4757 void SwWW8ImplReader::ReadDocInfo()
4759 if( m_pStg )
4761 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
4762 m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
4763 uno::Reference<document::XDocumentProperties> xDocProps(
4764 xDPS->getDocumentProperties());
4765 OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
4767 if (xDocProps.is())
4769 if ( m_xWwFib->m_fDot )
4771 OUString sTemplateURL;
4772 SfxMedium* pMedium = m_pDocShell->GetMedium();
4773 if ( pMedium )
4775 const OUString& aName = pMedium->GetName();
4776 INetURLObject aURL( aName );
4777 sTemplateURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri);
4778 if ( !sTemplateURL.isEmpty() )
4779 xDocProps->setTemplateURL( sTemplateURL );
4782 else if (m_xWwFib->m_lcbSttbfAssoc) // not a template, and has a SttbfAssoc
4784 auto nCur = m_pTableStream->Tell();
4785 Sttb aSttb;
4786 // point at tgc record
4787 if (!checkSeek(*m_pTableStream, m_xWwFib->m_fcSttbfAssoc) || !aSttb.Read(*m_pTableStream))
4788 SAL_WARN("sw.ww8", "** Read of SttbAssoc data failed!!!! ");
4789 m_pTableStream->Seek( nCur ); // return to previous position, is that necessary?
4790 OUString sPath = aSttb.getStringAtIndex( 0x1 );
4791 OUString aURL;
4792 // attempt to convert to url (won't work for obvious reasons on linux)
4793 if ( !sPath.isEmpty() )
4794 osl::FileBase::getFileURLFromSystemPath( sPath, aURL );
4795 if (aURL.isEmpty())
4796 xDocProps->setTemplateURL( aURL );
4797 else
4798 xDocProps->setTemplateURL( sPath );
4801 sfx2::LoadOlePropertySet(xDocProps, m_pStg);
4806 static void lcl_createTemplateToProjectEntry( const uno::Reference< container::XNameContainer >& xPrjNameCache, const OUString& sTemplatePathOrURL, const OUString& sVBAProjName )
4808 if ( xPrjNameCache.is() )
4810 INetURLObject aObj;
4811 aObj.SetURL( sTemplatePathOrURL );
4812 bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
4813 OUString aURL;
4814 if ( bIsURL )
4815 aURL = sTemplatePathOrURL;
4816 else
4818 osl::FileBase::getFileURLFromSystemPath( sTemplatePathOrURL, aURL );
4819 aObj.SetURL( aURL );
4823 OUString templateNameWithExt = aObj.GetLastName();
4824 OUString templateName;
4825 sal_Int32 nIndex = templateNameWithExt.lastIndexOf( '.' );
4826 if ( nIndex != -1 )
4828 templateName = templateNameWithExt.copy( 0, nIndex );
4829 xPrjNameCache->insertByName( templateName, uno::makeAny( sVBAProjName ) );
4832 catch( const uno::Exception& )
4838 class WW8Customizations
4840 SvStream* mpTableStream;
4841 WW8Fib mWw8Fib;
4842 public:
4843 WW8Customizations( SvStream*, WW8Fib const & );
4844 void Import( SwDocShell* pShell );
4847 WW8Customizations::WW8Customizations( SvStream* pTableStream, WW8Fib const & rFib ) : mpTableStream(pTableStream), mWw8Fib( rFib )
4851 void WW8Customizations::Import( SwDocShell* pShell )
4853 if ( mWw8Fib.m_lcbCmds == 0 || !IsEightPlus(mWw8Fib.GetFIBVersion()) )
4854 return;
4857 Tcg aTCG;
4858 long nCur = mpTableStream->Tell();
4859 if (!checkSeek(*mpTableStream, mWw8Fib.m_fcCmds)) // point at tgc record
4861 SAL_WARN("sw.ww8", "** Seek to Customization data failed!!!! ");
4862 return;
4864 bool bReadResult = aTCG.Read( *mpTableStream );
4865 mpTableStream->Seek( nCur ); // return to previous position, is that necessary?
4866 if ( !bReadResult )
4868 SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! ");
4869 return;
4871 aTCG.ImportCustomToolBar( *pShell );
4873 catch(...)
4875 SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! epically");
4879 void SwWW8ImplReader::ReadGlobalTemplateSettings( const OUString& sCreatedFrom, const uno::Reference< container::XNameContainer >& xPrjNameCache )
4881 if (utl::ConfigManager::IsFuzzing())
4882 return;
4884 SvtPathOptions aPathOpt;
4885 const OUString& aAddinPath = aPathOpt.GetAddinPath();
4886 uno::Sequence< OUString > sGlobalTemplates;
4888 // first get the autoload addins in the directory STARTUP
4889 uno::Reference<ucb::XSimpleFileAccess3> xSFA(ucb::SimpleFileAccess::create(::comphelper::getProcessComponentContext()));
4891 if( xSFA->isFolder( aAddinPath ) )
4892 sGlobalTemplates = xSFA->getFolderContents( aAddinPath, false );
4894 for ( const auto& rGlobalTemplate : sGlobalTemplates )
4896 INetURLObject aObj;
4897 aObj.SetURL( rGlobalTemplate );
4898 bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
4899 OUString aURL;
4900 if ( bIsURL )
4901 aURL = rGlobalTemplate;
4902 else
4903 osl::FileBase::getFileURLFromSystemPath( rGlobalTemplate, aURL );
4904 if ( !aURL.endsWithIgnoreAsciiCase( ".dot" ) || ( !sCreatedFrom.isEmpty() && sCreatedFrom == aURL ) )
4905 continue; // don't try and read the same document as ourselves
4907 tools::SvRef<SotStorage> rRoot = new SotStorage( aURL, StreamMode::STD_READWRITE );
4909 BasicProjImportHelper aBasicImporter( *m_pDocShell );
4910 // Import vba via oox filter
4911 aBasicImporter.import( m_pDocShell->GetMedium()->GetInputStream() );
4912 lcl_createTemplateToProjectEntry( xPrjNameCache, aURL, aBasicImporter.getProjectName() );
4913 // Read toolbars & menus
4914 tools::SvRef<SotStorageStream> refMainStream = rRoot->OpenSotStream( "WordDocument");
4915 refMainStream->SetEndian(SvStreamEndian::LITTLE);
4916 WW8Fib aWwFib( *refMainStream, 8 );
4917 tools::SvRef<SotStorageStream> xTableStream =
4918 rRoot->OpenSotStream(aWwFib.m_fWhichTableStm ? SL::a1Table : SL::a0Table, StreamMode::STD_READ);
4920 if (xTableStream.is() && ERRCODE_NONE == xTableStream->GetError())
4922 xTableStream->SetEndian(SvStreamEndian::LITTLE);
4923 WW8Customizations aGblCustomisations( xTableStream.get(), aWwFib );
4924 aGblCustomisations.Import( m_pDocShell );
4929 ErrCode SwWW8ImplReader::CoreLoad(WW8Glossary const *pGloss)
4931 m_rDoc.SetDocumentType( SwDoc::DOCTYPE_MSWORD );
4932 if (m_bNewDoc && m_pStg && !pGloss)
4934 // Initialize RDF metadata, to be able to add statements during the import.
4937 uno::Reference<frame::XModel> const xModel(m_rDoc.GetDocShell()->GetBaseModel());
4938 uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, uno::UNO_QUERY_THROW);
4939 uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext());
4940 uno::Reference<embed::XStorage> xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
4941 const uno::Reference<rdf::XURI> xBaseURI(sfx2::createBaseURI(xComponentContext, xModel, m_sBaseURL));
4942 uno::Reference<task::XInteractionHandler> xHandler;
4943 xDocumentMetadataAccess->loadMetadataFromStorage(xStorage, xBaseURI, xHandler);
4945 catch (const uno::Exception&)
4947 DBG_UNHANDLED_EXCEPTION("sw.ww8", "failed to initialize RDF metadata");
4949 ReadDocInfo();
4952 ::ww8::WW8FibData * pFibData = new ::ww8::WW8FibData();
4954 if (m_xWwFib->m_fReadOnlyRecommended)
4955 pFibData->setReadOnlyRecommended(true);
4956 else
4957 pFibData->setReadOnlyRecommended(false);
4959 if (m_xWwFib->m_fWriteReservation)
4960 pFibData->setWriteReservation(true);
4961 else
4962 pFibData->setWriteReservation(false);
4964 ::sw::tExternalDataPointer pExternalFibData(pFibData);
4966 m_rDoc.getIDocumentExternalData().setExternalData(::sw::tExternalDataType::FIB, pExternalFibData);
4968 ::sw::tExternalDataPointer pSttbfAsoc
4969 (new ::ww8::WW8Sttb<ww8::WW8Struct>(*m_pTableStream, m_xWwFib->m_fcSttbfAssoc, m_xWwFib->m_lcbSttbfAssoc));
4971 m_rDoc.getIDocumentExternalData().setExternalData(::sw::tExternalDataType::STTBF_ASSOC, pSttbfAsoc);
4973 if (m_xWwFib->m_fWriteReservation || m_xWwFib->m_fReadOnlyRecommended)
4975 SwDocShell * pDocShell = m_rDoc.GetDocShell();
4976 if (pDocShell)
4977 pDocShell->SetReadOnlyUI();
4980 m_pPaM = mpCursor.get();
4982 m_xCtrlStck.reset(new SwWW8FltControlStack(&m_rDoc, m_nFieldFlags, *this));
4984 m_xRedlineStack.reset(new sw::util::RedlineStack(m_rDoc));
4987 RefFieldStck: Keeps track of bookmarks which may be inserted as
4988 variables instead.
4990 m_xReffedStck.reset(new SwWW8ReferencedFltEndStack(&m_rDoc, m_nFieldFlags));
4991 m_xReffingStck.reset(new SwWW8FltRefStack(&m_rDoc, m_nFieldFlags));
4993 m_xAnchorStck.reset(new SwWW8FltAnchorStack(&m_rDoc, m_nFieldFlags));
4995 size_t nPageDescOffset = m_rDoc.GetPageDescCnt();
4997 SwNodeIndex aSttNdIdx( m_rDoc.GetNodes() );
4998 SwRelNumRuleSpaces aRelNumRule(m_rDoc, m_bNewDoc);
5000 RedlineFlags eMode = RedlineFlags::ShowInsert | RedlineFlags::ShowDelete;
5002 m_xSprmParser.reset(new wwSprmParser(*m_xWwFib));
5004 // Set handy helper variables
5005 m_bVer6 = (6 == m_xWwFib->m_nVersion);
5006 m_bVer7 = (7 == m_xWwFib->m_nVersion);
5007 m_bVer67 = m_bVer6 || m_bVer7;
5008 m_bVer8 = (8 == m_xWwFib->m_nVersion);
5010 m_eTextCharSet = WW8Fib::GetFIBCharset(m_xWwFib->m_chse, m_xWwFib->m_lid);
5011 m_eStructCharSet = WW8Fib::GetFIBCharset(m_xWwFib->m_chseTables, m_xWwFib->m_lid);
5013 m_bWWBugNormal = m_xWwFib->m_nProduct == 0xc03d;
5015 if (!m_bNewDoc)
5016 aSttNdIdx = m_pPaM->GetPoint()->nNode;
5018 m_xProgress.reset(new ImportProgress(m_pDocShell, 0, 100));
5020 // read Font Table
5021 m_xFonts.reset(new WW8Fonts(*m_pTableStream, *m_xWwFib));
5023 // Document Properties
5024 m_xWDop.reset(new WW8Dop(*m_pTableStream, m_xWwFib->m_nFib, m_xWwFib->m_fcDop,
5025 m_xWwFib->m_lcbDop));
5027 if (m_bNewDoc)
5028 ImportDop();
5031 Import revisioning data: author names
5033 if( m_xWwFib->m_lcbSttbfRMark )
5035 ReadRevMarkAuthorStrTabl(*m_pTableStream,
5036 m_xWwFib->m_fcSttbfRMark,
5037 m_xWwFib->m_lcbSttbfRMark, m_rDoc);
5040 // Initialize our String/ID map for Linked Sections
5041 std::vector<OUString> aLinkStrings;
5042 std::vector<ww::bytes> aStringIds;
5044 WW8ReadSTTBF(!m_bVer67, *m_pTableStream, m_xWwFib->m_fcSttbFnm,
5045 m_xWwFib->m_lcbSttbFnm, m_bVer67 ? 2 : 0, m_eStructCharSet,
5046 aLinkStrings, &aStringIds);
5048 for (size_t i=0; i < aLinkStrings.size() && i < aStringIds.size(); ++i)
5050 const ww::bytes& stringId = aStringIds[i];
5051 if (stringId.size() < sizeof(WW8_STRINGID))
5053 SAL_WARN("sw.ww8", "SwWW8ImplReader::CoreLoad: WW8_STRINGID is too short");
5054 continue;
5056 const WW8_STRINGID *stringIdStruct = reinterpret_cast<const WW8_STRINGID*>(stringId.data());
5057 m_aLinkStringMap[SVBT16ToUInt16(stringIdStruct->nStringId)] = aLinkStrings[i];
5060 ReadDocVars(); // import document variables as meta information.
5062 m_xProgress->Update(m_nProgress); // Update
5064 m_xLstManager.reset(new WW8ListManager(*m_pTableStream, *this));
5067 first (1) import all styles (see WW8PAR2.CXX)
5068 BEFORE the import of the lists !!
5070 m_xProgress->Update(m_nProgress); // Update
5071 m_xStyles.reset(new WW8RStyle(*m_xWwFib, this)); // Styles
5072 m_xStyles->Import();
5075 In the end: (also see WW8PAR3.CXX)
5077 Go through all Styles and attach respective List Format
5078 AFTER we imported the Styles and AFTER we imported the Lists!
5080 m_xProgress->Update(m_nProgress); // Update
5081 m_xStyles->PostProcessStyles();
5083 if (!m_vColl.empty())
5084 SetOutlineStyles();
5086 m_xSBase.reset(new WW8ScannerBase(m_pStrm,m_pTableStream,m_pDataStream, m_xWwFib.get()));
5088 static const SvxNumType eNumTA[16] =
5090 SVX_NUM_ARABIC, SVX_NUM_ROMAN_UPPER, SVX_NUM_ROMAN_LOWER,
5091 SVX_NUM_CHARS_UPPER_LETTER_N, SVX_NUM_CHARS_LOWER_LETTER_N,
5092 SVX_NUM_ARABIC, SVX_NUM_ARABIC, SVX_NUM_ARABIC,
5093 SVX_NUM_ARABIC, SVX_NUM_ARABIC, SVX_NUM_ARABIC,
5094 SVX_NUM_ARABIC, SVX_NUM_ARABIC, SVX_NUM_ARABIC,
5095 SVX_NUM_ARABIC, SVX_NUM_ARABIC
5098 if (m_xSBase->AreThereFootnotes())
5100 static const SwFootnoteNum eNumA[4] =
5102 FTNNUM_DOC, FTNNUM_CHAPTER, FTNNUM_PAGE, FTNNUM_DOC
5105 SwFootnoteInfo aInfo = m_rDoc.GetFootnoteInfo(); // Copy-Ctor private
5107 aInfo.ePos = FTNPOS_PAGE;
5108 aInfo.eNum = eNumA[m_xWDop->rncFootnote];
5109 sal_uInt16 nfcFootnoteRef = m_xWDop->nfcFootnoteRef & 0xF;
5110 aInfo.aFormat.SetNumberingType( eNumTA[nfcFootnoteRef] );
5111 if( m_xWDop->nFootnote )
5112 aInfo.nFootnoteOffset = m_xWDop->nFootnote - 1;
5113 m_rDoc.SetFootnoteInfo( aInfo );
5115 if (m_xSBase->AreThereEndnotes())
5117 SwEndNoteInfo aInfo = m_rDoc.GetEndNoteInfo(); // Same as for Footnote
5118 sal_uInt16 nfcEdnRef = m_xWDop->nfcEdnRef & 0xF;
5119 aInfo.aFormat.SetNumberingType( eNumTA[nfcEdnRef] );
5120 if( m_xWDop->nEdn )
5121 aInfo.nFootnoteOffset = m_xWDop->nEdn - 1;
5122 m_rDoc.SetEndNoteInfo( aInfo );
5125 if (m_xWwFib->m_lcbPlcfhdd)
5126 m_xHdFt.reset(new WW8PLCF_HdFt(m_pTableStream, *m_xWwFib, *m_xWDop));
5128 if (!m_bNewDoc)
5130 // inserting into an existing document:
5131 // As only complete paragraphs are inserted, the current one
5132 // needs to be split - once or even twice.
5133 const SwPosition* pPos = m_pPaM->GetPoint();
5135 // split current paragraph to get new paragraph for the insertion
5136 m_rDoc.getIDocumentContentOperations().SplitNode( *pPos, false );
5138 // another split, if insertion position was not at the end of the current paragraph.
5139 SwTextNode const*const pTextNd = pPos->nNode.GetNode().GetTextNode();
5140 if ( pTextNd->GetText().getLength() )
5142 m_rDoc.getIDocumentContentOperations().SplitNode( *pPos, false );
5143 // move PaM back to the newly empty paragraph
5144 m_pPaM->Move( fnMoveBackward );
5147 // suppress insertion of tables inside footnotes.
5148 const sal_uLong nNd = pPos->nNode.GetIndex();
5149 m_bReadNoTable = ( nNd < m_rDoc.GetNodes().GetEndOfInserts().GetIndex() &&
5150 m_rDoc.GetNodes().GetEndOfInserts().StartOfSectionIndex() < nNd );
5153 m_xProgress->Update(m_nProgress); // Update
5155 // loop for each glossary entry and add dummy section node
5156 if (pGloss)
5158 WW8PLCF aPlc(*m_pTableStream, m_xWwFib->m_fcPlcfglsy, m_xWwFib->m_lcbPlcfglsy, 0);
5160 WW8_CP nStart, nEnd;
5161 void* pDummy;
5163 for (int i = 0; i < pGloss->GetNoStrings(); ++i, aPlc.advance())
5165 SwNodeIndex aIdx( m_rDoc.GetNodes().GetEndOfContent());
5166 SwTextFormatColl* pColl =
5167 m_rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD,
5168 false);
5169 SwStartNode *pNode =
5170 m_rDoc.GetNodes().MakeTextSection(aIdx,
5171 SwNormalStartNode,pColl);
5172 m_pPaM->GetPoint()->nNode = pNode->GetIndex()+1;
5173 m_pPaM->GetPoint()->nContent.Assign(m_pPaM->GetContentNode(),0);
5174 aPlc.Get( nStart, nEnd, pDummy );
5175 ReadText(nStart,nEnd-nStart-1,MAN_MAINTEXT);
5178 else // ordinary case
5180 if (m_bNewDoc && m_pStg) /*meaningless for a glossary */
5182 m_pDocShell->SetIsTemplate( m_xWwFib->m_fDot ); // point at tgc record
5183 uno::Reference<document::XDocumentPropertiesSupplier> const
5184 xDocPropSupp(m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
5185 uno::Reference< document::XDocumentProperties > xDocProps( xDocPropSupp->getDocumentProperties(), uno::UNO_SET_THROW );
5187 OUString sCreatedFrom = xDocProps->getTemplateURL();
5188 uno::Reference< container::XNameContainer > xPrjNameCache;
5189 uno::Reference< lang::XMultiServiceFactory> xSF(m_pDocShell->GetModel(), uno::UNO_QUERY);
5190 if ( xSF.is() )
5191 xPrjNameCache.set( xSF->createInstance( "ooo.vba.VBAProjectNameProvider" ), uno::UNO_QUERY );
5193 // Read Global templates
5194 ReadGlobalTemplateSettings( sCreatedFrom, xPrjNameCache );
5196 // Create and insert Word vba Globals
5197 uno::Any aGlobs;
5198 uno::Sequence< uno::Any > aArgs(1);
5199 aArgs[ 0 ] <<= m_pDocShell->GetModel();
5202 aGlobs <<= ::comphelper::getProcessServiceFactory()->createInstanceWithArguments( "ooo.vba.word.Globals", aArgs );
5204 catch (const uno::Exception&)
5206 SAL_WARN("sw.ww8", "SwWW8ImplReader::CoreLoad: ooo.vba.word.Globals is not available");
5209 #if HAVE_FEATURE_SCRIPTING
5210 if (!utl::ConfigManager::IsFuzzing())
5212 BasicManager *pBasicMan = m_pDocShell->GetBasicManager();
5213 if (pBasicMan)
5214 pBasicMan->SetGlobalUNOConstant( "VBAGlobals", aGlobs );
5216 #endif
5217 BasicProjImportHelper aBasicImporter( *m_pDocShell );
5218 // Import vba via oox filter
5219 bool bRet = aBasicImporter.import( m_pDocShell->GetMedium()->GetInputStream() );
5221 lcl_createTemplateToProjectEntry( xPrjNameCache, sCreatedFrom, aBasicImporter.getProjectName() );
5222 WW8Customizations aCustomisations( m_pTableStream, *m_xWwFib );
5223 aCustomisations.Import( m_pDocShell );
5225 if( bRet )
5226 m_rDoc.SetContainsMSVBasic(true);
5228 StoreMacroCmds();
5230 m_bOnLoadingMain = true;
5231 ReadText(0, m_xWwFib->m_ccpText, MAN_MAINTEXT);
5232 m_bOnLoadingMain = false;
5235 m_xProgress->Update(m_nProgress); // Update
5237 if (m_pDrawPg && m_xMSDffManager && m_xMSDffManager->GetShapeOrders())
5239 // Helper array to chain the inserted frames (instead of SdrTextObj)
5240 SvxMSDffShapeTxBxSort aTxBxSort;
5242 // Ensure correct z-order of read Escher objects
5243 sal_uInt16 nShapeCount = m_xMSDffManager->GetShapeOrders()->size();
5245 for (sal_uInt16 nShapeNum=0; nShapeNum < nShapeCount; nShapeNum++)
5247 SvxMSDffShapeOrder *pOrder =
5248 (*m_xMSDffManager->GetShapeOrders())[nShapeNum].get();
5249 // Insert Pointer into new Sort array
5250 if (pOrder->nTxBxComp && pOrder->pFly)
5251 aTxBxSort.insert(pOrder);
5253 // Chain Frames
5254 if( !aTxBxSort.empty() )
5256 SwFormatChain aChain;
5257 for( SvxMSDffShapeTxBxSort::iterator it = aTxBxSort.begin(); it != aTxBxSort.end(); ++it )
5259 SvxMSDffShapeOrder *pOrder = *it;
5261 // Initialize FlyFrame Formats
5262 SwFlyFrameFormat* pFlyFormat = pOrder->pFly;
5263 SwFlyFrameFormat* pNextFlyFormat = nullptr;
5264 SwFlyFrameFormat* pPrevFlyFormat = nullptr;
5266 // Determine successor, if we can
5267 SvxMSDffShapeTxBxSort::iterator tmpIter1 = it;
5268 ++tmpIter1;
5269 if( tmpIter1 != aTxBxSort.end() )
5271 SvxMSDffShapeOrder *pNextOrder = *tmpIter1;
5272 if ((0xFFFF0000 & pOrder->nTxBxComp)
5273 == (0xFFFF0000 & pNextOrder->nTxBxComp))
5274 pNextFlyFormat = pNextOrder->pFly;
5276 // Determine predecessor, if we can
5277 if( it != aTxBxSort.begin() )
5279 SvxMSDffShapeTxBxSort::iterator tmpIter2 = it;
5280 --tmpIter2;
5281 SvxMSDffShapeOrder *pPrevOrder = *tmpIter2;
5282 if ((0xFFFF0000 & pOrder->nTxBxComp)
5283 == (0xFFFF0000 & pPrevOrder->nTxBxComp))
5284 pPrevFlyFormat = pPrevOrder->pFly;
5286 // If successor or predecessor present, insert the
5287 // chain at the FlyFrame Format
5288 if (pNextFlyFormat || pPrevFlyFormat)
5290 aChain.SetNext( pNextFlyFormat );
5291 aChain.SetPrev( pPrevFlyFormat );
5292 pFlyFormat->SetFormatAttr( aChain );
5298 bool isHideRedlines(false);
5300 if (m_bNewDoc)
5302 if( m_xWDop->fRevMarking )
5303 eMode |= RedlineFlags::On;
5304 isHideRedlines = !m_xWDop->fRMView;
5307 m_aInsertedTables.DelAndMakeTableFrames();
5308 m_aSectionManager.InsertSegments();
5310 m_vColl.clear();
5312 m_xStyles.reset();
5314 m_xFormImpl.reset();
5315 GrafikDtor();
5316 m_xMSDffManager.reset();
5317 m_xHdFt.reset();
5318 m_xSBase.reset();
5319 m_xWDop.reset();
5320 m_xFonts.reset();
5321 m_pAtnNames.reset();
5322 m_xSprmParser.reset();
5323 m_xProgress.reset();
5325 m_pDataStream = nullptr;
5326 m_pTableStream = nullptr;
5328 DeleteCtrlStack();
5329 DeleteAnchorStack();
5330 DeleteRefStacks();
5331 m_pLastAnchorPos.reset();//ensure this is deleted before UpdatePageDescs
5332 // ofz#10994 remove any trailing fly paras before processing redlines
5333 m_xWFlyPara.reset();
5334 // ofz#12660 remove any trailing fly paras before deleting extra paras
5335 m_xSFlyPara.reset();
5336 // remove extra paragraphs after attribute ctrl
5337 // stacks etc. are destroyed, and before fields
5338 // are updated
5339 m_aExtraneousParas.delete_all_from_doc();
5340 m_xRedlineStack->closeall(*m_pPaM->GetPoint());
5341 while (!m_aFrameRedlines.empty())
5342 m_aFrameRedlines.pop();
5343 m_xRedlineStack.reset();
5345 // For i120928,achieve the graphics from the special bookmark with is for graphic bullet
5347 std::vector<const SwGrfNode*> vecBulletGrf;
5348 std::vector<SwFrameFormat*> vecFrameFormat;
5350 IDocumentMarkAccess* const pMarkAccess = m_rDoc.getIDocumentMarkAccess();
5351 if ( pMarkAccess )
5353 IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->findBookmark( "_PictureBullets" );
5354 if ( ppBkmk != pMarkAccess->getBookmarksEnd() &&
5355 IDocumentMarkAccess::GetType(**ppBkmk) == IDocumentMarkAccess::MarkType::BOOKMARK )
5357 SwTextNode* pTextNode = (*ppBkmk)->GetMarkStart().nNode.GetNode().GetTextNode();
5359 if ( pTextNode )
5361 const SwpHints* pHints = pTextNode->GetpSwpHints();
5362 for( size_t nHintPos = 0; pHints && nHintPos < pHints->Count(); ++nHintPos)
5364 const SwTextAttr *pHt = pHints->Get(nHintPos);
5365 if (pHt->Which() != RES_TXTATR_FLYCNT)
5366 continue;
5367 const sal_Int32 st = pHt->GetStart();
5368 if (st >= (*ppBkmk)->GetMarkStart().nContent.GetIndex())
5370 SwFrameFormat* pFrameFormat = pHt->GetFlyCnt().GetFrameFormat();
5371 vecFrameFormat.push_back(pFrameFormat);
5372 const SwNodeIndex* pNdIdx = pFrameFormat->GetContent().GetContentIdx();
5373 const SwNodes* pNodesArray = (pNdIdx != nullptr)
5374 ? &(pNdIdx->GetNodes())
5375 : nullptr;
5376 const SwGrfNode *pGrf = (pNodesArray != nullptr)
5377 ? dynamic_cast<const SwGrfNode*>((*pNodesArray)[pNdIdx->GetIndex() + 1])
5378 : nullptr;
5379 vecBulletGrf.push_back(pGrf);
5382 // update graphic bullet information
5383 size_t nCount = m_xLstManager->GetWW8LSTInfoNum();
5384 for (size_t i = 0; i < nCount; ++i)
5386 SwNumRule* pRule = m_xLstManager->GetNumRule(i);
5387 for (sal_uInt16 j = 0; j < MAXLEVEL; ++j)
5389 SwNumFormat aNumFormat(pRule->Get(j));
5390 const sal_Int16 nType = aNumFormat.GetNumberingType();
5391 const sal_uInt16 nGrfBulletCP = aNumFormat.GetGrfBulletCP();
5392 if ( nType == SVX_NUM_BITMAP
5393 && vecBulletGrf.size() > nGrfBulletCP
5394 && vecBulletGrf[nGrfBulletCP] != nullptr )
5396 Graphic aGraphic = vecBulletGrf[nGrfBulletCP]->GetGrf();
5397 SvxBrushItem aBrush(aGraphic, GPOS_AREA, SID_ATTR_BRUSH);
5398 const vcl::Font& aFont = numfunc::GetDefBulletFont();
5399 int nHeight = aFont.GetFontHeight() * 12;
5400 Size aPrefSize( aGraphic.GetPrefSize());
5401 if (aPrefSize.Height() * aPrefSize.Width() != 0 )
5403 int nWidth = (nHeight * aPrefSize.Width()) / aPrefSize.Height();
5404 Size aSize(nWidth, nHeight);
5405 aNumFormat.SetGraphicBrush(&aBrush, &aSize);
5407 else
5409 aNumFormat.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
5410 aNumFormat.SetBulletChar(0x2190);
5412 pRule->Set( j, aNumFormat );
5416 // Remove additional pictures
5417 for (SwFrameFormat* p : vecFrameFormat)
5419 m_rDoc.getIDocumentLayoutAccess().DelLayoutFormat(p);
5424 m_xLstManager.reset();
5427 m_pPosAfterTOC.reset();
5428 mpCursor.reset();
5429 m_pPaM = nullptr;
5431 UpdateFields();
5433 // delete the pam before the call for hide all redlines (Bug 73683)
5434 if (m_bNewDoc)
5435 m_rDoc.getIDocumentRedlineAccess().SetRedlineFlags(eMode);
5437 UpdatePageDescs(m_rDoc, nPageDescOffset);
5439 // can't set it on the layout or view shell because it doesn't exist yet
5440 m_rDoc.GetDocumentRedlineManager().SetHideRedlines(isHideRedlines);
5442 return ERRCODE_NONE;
5445 ErrCode SwWW8ImplReader::SetSubStreams(tools::SvRef<SotStorageStream> &rTableStream,
5446 tools::SvRef<SotStorageStream> &rDataStream)
5448 ErrCode nErrRet = ERRCODE_NONE;
5449 // 6 stands for "6 OR 7", 7 stands for "ONLY 7"
5450 switch (m_xWwFib->m_nVersion)
5452 case 6:
5453 case 7:
5454 m_pTableStream = m_pStrm;
5455 m_pDataStream = m_pStrm;
5456 break;
5457 case 8:
5458 if(!m_pStg)
5460 OSL_ENSURE( m_pStg, "Version 8 always needs to have a Storage!!" );
5461 nErrRet = ERR_SWG_READ_ERROR;
5462 break;
5465 rTableStream = m_pStg->OpenSotStream(
5466 m_xWwFib->m_fWhichTableStm ? SL::a1Table : SL::a0Table,
5467 StreamMode::STD_READ);
5469 m_pTableStream = rTableStream.get();
5470 m_pTableStream->SetEndian( SvStreamEndian::LITTLE );
5472 rDataStream = m_pStg->OpenSotStream(SL::aData, StreamMode::STD_READ);
5474 if (rDataStream.is() && ERRCODE_NONE == rDataStream->GetError())
5476 m_pDataStream = rDataStream.get();
5477 m_pDataStream->SetEndian(SvStreamEndian::LITTLE);
5479 else
5480 m_pDataStream = m_pStrm;
5481 break;
5482 default:
5483 // Program error!
5484 OSL_ENSURE( false, "We forgot to encode nVersion!" );
5485 nErrRet = ERR_SWG_READ_ERROR;
5486 break;
5488 return nErrRet;
5491 namespace
5493 std::unique_ptr<utl::TempFile> MakeTemp(SvFileStream &rSt)
5495 std::unique_ptr<utl::TempFile> pT(new utl::TempFile);
5496 pT->EnableKillingFile();
5497 rSt.Open(pT->GetFileName(), StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE);
5498 return pT;
5501 #define WW_BLOCKSIZE 0x200
5503 void DecryptRC4(msfilter::MSCodec97& rCtx, SvStream &rIn, SvStream &rOut)
5505 const std::size_t nLen = rIn.TellEnd();
5506 rIn.Seek(0);
5508 sal_uInt8 in[WW_BLOCKSIZE];
5509 for (std::size_t nI = 0, nBlock = 0; nI < nLen; nI += WW_BLOCKSIZE, ++nBlock)
5511 std::size_t nBS = std::min<size_t>(nLen - nI, WW_BLOCKSIZE);
5512 nBS = rIn.ReadBytes(in, nBS);
5513 rCtx.InitCipher(nBlock);
5514 rCtx.Decode(in, nBS, in, nBS);
5515 rOut.WriteBytes(in, nBS);
5519 void DecryptXOR(msfilter::MSCodec_XorWord95 &rCtx, SvStream &rIn, SvStream &rOut)
5521 std::size_t nSt = rIn.Tell();
5522 std::size_t nLen = rIn.TellEnd();
5524 rCtx.InitCipher();
5525 rCtx.Skip(nSt);
5527 sal_uInt8 in[0x4096];
5528 for (std::size_t nI = nSt; nI < nLen; nI += 0x4096)
5530 std::size_t nBS = std::min<size_t>(nLen - nI, 0x4096 );
5531 nBS = rIn.ReadBytes(in, nBS);
5532 rCtx.Decode(in, nBS);
5533 rOut.WriteBytes(in, nBS);
5537 // moan, copy and paste :-(
5538 OUString QueryPasswordForMedium(SfxMedium& rMedium)
5540 OUString aPassw;
5542 const SfxItemSet* pSet = rMedium.GetItemSet();
5543 const SfxPoolItem *pPasswordItem;
5545 if(pSet && SfxItemState::SET == pSet->GetItemState(SID_PASSWORD, true, &pPasswordItem))
5546 aPassw = static_cast<const SfxStringItem *>(pPasswordItem)->GetValue();
5547 else
5551 uno::Reference< task::XInteractionHandler > xHandler( rMedium.GetInteractionHandler() );
5552 if( xHandler.is() )
5554 ::comphelper::DocPasswordRequest* pRequest = new ::comphelper::DocPasswordRequest(
5555 ::comphelper::DocPasswordRequestType::MS, task::PasswordRequestMode_PASSWORD_ENTER,
5556 INetURLObject(rMedium.GetOrigURL())
5557 .GetLastName(INetURLObject::DecodeMechanism::WithCharset));
5558 uno::Reference< task::XInteractionRequest > xRequest( pRequest );
5560 xHandler->handle( xRequest );
5562 if( pRequest->isPassword() )
5563 aPassw = pRequest->getPassword();
5566 catch( const uno::Exception& )
5571 return aPassw;
5574 uno::Sequence< beans::NamedValue > InitXorWord95Codec( ::msfilter::MSCodec_XorWord95& rCodec, SfxMedium& rMedium, WW8Fib const * pWwFib )
5576 uno::Sequence< beans::NamedValue > aEncryptionData;
5577 const SfxUnoAnyItem* pEncryptionData = SfxItemSet::GetItem<SfxUnoAnyItem>(rMedium.GetItemSet(), SID_ENCRYPTIONDATA, false);
5578 if ( pEncryptionData && ( pEncryptionData->GetValue() >>= aEncryptionData ) && !rCodec.InitCodec( aEncryptionData ) )
5579 aEncryptionData.realloc( 0 );
5581 if ( !aEncryptionData.hasElements() )
5583 OUString sUniPassword = QueryPasswordForMedium( rMedium );
5585 OString sPassword(OUStringToOString(sUniPassword,
5586 WW8Fib::GetFIBCharset(pWwFib->m_chseTables, pWwFib->m_lid)));
5588 sal_Int32 nLen = sPassword.getLength();
5589 if( nLen <= 15 )
5591 sal_uInt8 pPassword[16];
5592 memcpy(pPassword, sPassword.getStr(), nLen);
5593 memset(pPassword+nLen, 0, sizeof(pPassword)-nLen);
5595 rCodec.InitKey( pPassword );
5596 aEncryptionData = rCodec.GetEncryptionData();
5598 // the export supports RC4 algorithm only, so we have to
5599 // generate the related EncryptionData as well, so that Save
5600 // can export the document without asking for a password;
5601 // as result there will be EncryptionData for both algorithms
5602 // in the MediaDescriptor
5603 ::msfilter::MSCodec_Std97 aCodec97;
5605 rtlRandomPool aRandomPool = rtl_random_createPool();
5606 sal_uInt8 pDocId[ 16 ];
5607 rtl_random_getBytes( aRandomPool, pDocId, 16 );
5609 rtl_random_destroyPool( aRandomPool );
5611 sal_uInt16 pStd97Pass[16];
5612 memset( pStd97Pass, 0, sizeof( pStd97Pass ) );
5613 for( sal_Int32 nChar = 0; nChar < nLen; ++nChar )
5614 pStd97Pass[nChar] = sUniPassword[nChar];
5616 aCodec97.InitKey( pStd97Pass, pDocId );
5618 // merge the EncryptionData, there should be no conflicts
5619 ::comphelper::SequenceAsHashMap aEncryptionHash( aEncryptionData );
5620 aEncryptionHash.update( ::comphelper::SequenceAsHashMap( aCodec97.GetEncryptionData() ) );
5621 aEncryptionHash >> aEncryptionData;
5625 return aEncryptionData;
5628 uno::Sequence< beans::NamedValue > Init97Codec(msfilter::MSCodec97& rCodec, sal_uInt8 const pDocId[16], SfxMedium& rMedium)
5630 uno::Sequence< beans::NamedValue > aEncryptionData;
5631 const SfxUnoAnyItem* pEncryptionData = SfxItemSet::GetItem<SfxUnoAnyItem>(rMedium.GetItemSet(), SID_ENCRYPTIONDATA, false);
5632 if ( pEncryptionData && ( pEncryptionData->GetValue() >>= aEncryptionData ) && !rCodec.InitCodec( aEncryptionData ) )
5633 aEncryptionData.realloc( 0 );
5635 if ( !aEncryptionData.hasElements() )
5637 OUString sUniPassword = QueryPasswordForMedium( rMedium );
5639 sal_Int32 nLen = sUniPassword.getLength();
5640 if ( nLen <= 15 )
5642 sal_uInt16 pPassword[16];
5643 memset( pPassword, 0, sizeof( pPassword ) );
5644 for( sal_Int32 nChar = 0; nChar < nLen; ++nChar )
5645 pPassword[nChar] = sUniPassword[nChar];
5647 rCodec.InitKey( pPassword, pDocId );
5648 aEncryptionData = rCodec.GetEncryptionData();
5652 return aEncryptionData;
5656 //TO-DO: merge this with lclReadFilepass8_Strong in sc which uses a different
5657 //stream thing
5658 static bool lclReadCryptoAPIHeader(msfilter::RC4EncryptionInfo &info, SvStream &rStream)
5660 //It is possible there are other variants in existence but these
5661 //are the defaults I get with Word 2013
5663 rStream.ReadUInt32(info.header.flags);
5664 if (oox::getFlag( info.header.flags, msfilter::ENCRYPTINFO_EXTERNAL))
5665 return false;
5667 sal_uInt32 nHeaderSize(0);
5668 rStream.ReadUInt32(nHeaderSize);
5669 sal_uInt32 actualHeaderSize = sizeof(info.header);
5671 if (nHeaderSize < actualHeaderSize)
5672 return false;
5674 rStream.ReadUInt32(info.header.flags);
5675 rStream.ReadUInt32(info.header.sizeExtra);
5676 rStream.ReadUInt32(info.header.algId);
5677 rStream.ReadUInt32(info.header.algIdHash);
5678 rStream.ReadUInt32(info.header.keyBits);
5679 rStream.ReadUInt32(info.header.providedType);
5680 rStream.ReadUInt32(info.header.reserved1);
5681 rStream.ReadUInt32(info.header.reserved2);
5683 rStream.SeekRel(nHeaderSize - actualHeaderSize);
5685 rStream.ReadUInt32(info.verifier.saltSize);
5686 if (info.verifier.saltSize != msfilter::SALT_LENGTH)
5687 return false;
5688 rStream.ReadBytes(&info.verifier.salt, sizeof(info.verifier.salt));
5689 rStream.ReadBytes(&info.verifier.encryptedVerifier, sizeof(info.verifier.encryptedVerifier));
5691 rStream.ReadUInt32(info.verifier.encryptedVerifierHashSize);
5692 if (info.verifier.encryptedVerifierHashSize != RTL_DIGEST_LENGTH_SHA1)
5693 return false;
5694 rStream.ReadBytes(&info.verifier.encryptedVerifierHash, info.verifier.encryptedVerifierHashSize);
5696 // check flags and algorithm IDs, required are AES128 and SHA-1
5697 if (!oox::getFlag(info.header.flags, msfilter::ENCRYPTINFO_CRYPTOAPI))
5698 return false;
5700 if (oox::getFlag(info.header.flags, msfilter::ENCRYPTINFO_AES))
5701 return false;
5703 if (info.header.algId != msfilter::ENCRYPT_ALGO_RC4)
5704 return false;
5706 // hash algorithm ID 0 defaults to SHA-1 too
5707 if (info.header.algIdHash != 0 && info.header.algIdHash != msfilter::ENCRYPT_HASH_SHA1)
5708 return false;
5710 return true;
5713 ErrCode SwWW8ImplReader::LoadThroughDecryption(WW8Glossary *pGloss)
5715 ErrCode nErrRet = ERRCODE_NONE;
5716 if (pGloss)
5717 m_xWwFib = pGloss->GetFib();
5718 else
5719 m_xWwFib.reset(new WW8Fib(*m_pStrm, m_nWantedVersion));
5721 if (m_xWwFib->m_nFibError)
5722 nErrRet = ERR_SWG_READ_ERROR;
5724 tools::SvRef<SotStorageStream> xTableStream, xDataStream;
5726 if (!nErrRet)
5727 nErrRet = SetSubStreams(xTableStream, xDataStream);
5729 std::unique_ptr<utl::TempFile> pTempMain;
5730 std::unique_ptr<utl::TempFile> pTempTable;
5731 std::unique_ptr<utl::TempFile> pTempData;
5732 SvFileStream aDecryptMain;
5733 SvFileStream aDecryptTable;
5734 SvFileStream aDecryptData;
5736 bool bDecrypt = false;
5737 enum {RC4CryptoAPI, RC4, XOR, Other} eAlgo = Other;
5738 if (m_xWwFib->m_fEncrypted && !nErrRet)
5740 if (!pGloss)
5742 bDecrypt = true;
5743 if (8 != m_xWwFib->m_nVersion)
5744 eAlgo = XOR;
5745 else
5747 if (m_xWwFib->m_nKey != 0)
5748 eAlgo = XOR;
5749 else
5751 m_pTableStream->Seek(0);
5752 sal_uInt32 nEncType(0);
5753 m_pTableStream->ReadUInt32(nEncType);
5754 if (nEncType == msfilter::VERSION_INFO_1997_FORMAT)
5755 eAlgo = RC4;
5756 else if (nEncType == msfilter::VERSION_INFO_2007_FORMAT || nEncType == msfilter::VERSION_INFO_2007_FORMAT_SP2)
5757 eAlgo = RC4CryptoAPI;
5763 if (bDecrypt)
5765 nErrRet = ERRCODE_SVX_WRONGPASS;
5766 SfxMedium* pMedium = m_pDocShell->GetMedium();
5768 if ( pMedium )
5770 switch (eAlgo)
5772 default:
5773 nErrRet = ERRCODE_SVX_READ_FILTER_CRYPT;
5774 break;
5775 case XOR:
5777 msfilter::MSCodec_XorWord95 aCtx;
5778 uno::Sequence< beans::NamedValue > aEncryptionData = InitXorWord95Codec(aCtx, *pMedium, m_xWwFib.get());
5780 // if initialization has failed the EncryptionData should be empty
5781 if (aEncryptionData.hasElements() && aCtx.VerifyKey(m_xWwFib->m_nKey, m_xWwFib->m_nHash))
5783 nErrRet = ERRCODE_NONE;
5784 pTempMain = MakeTemp(aDecryptMain);
5786 m_pStrm->Seek(0);
5787 size_t nUnencryptedHdr =
5788 (8 == m_xWwFib->m_nVersion) ? 0x44 : 0x34;
5789 std::unique_ptr<sal_uInt8[]> pIn(new sal_uInt8[nUnencryptedHdr]);
5790 nUnencryptedHdr = m_pStrm->ReadBytes(pIn.get(), nUnencryptedHdr);
5791 aDecryptMain.WriteBytes(pIn.get(), nUnencryptedHdr);
5792 pIn.reset();
5794 DecryptXOR(aCtx, *m_pStrm, aDecryptMain);
5796 if (!m_pTableStream || m_pTableStream == m_pStrm)
5797 m_pTableStream = &aDecryptMain;
5798 else
5800 pTempTable = MakeTemp(aDecryptTable);
5801 DecryptXOR(aCtx, *m_pTableStream, aDecryptTable);
5802 m_pTableStream = &aDecryptTable;
5805 if (!m_pDataStream || m_pDataStream == m_pStrm)
5806 m_pDataStream = &aDecryptMain;
5807 else
5809 pTempData = MakeTemp(aDecryptData);
5810 DecryptXOR(aCtx, *m_pDataStream, aDecryptData);
5811 m_pDataStream = &aDecryptData;
5814 pMedium->GetItemSet()->ClearItem( SID_PASSWORD );
5815 pMedium->GetItemSet()->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aEncryptionData ) ) );
5818 break;
5819 case RC4:
5820 case RC4CryptoAPI:
5822 std::unique_ptr<msfilter::MSCodec97> xCtx;
5823 msfilter::RC4EncryptionInfo info;
5824 bool bCouldReadHeaders;
5826 if (eAlgo == RC4)
5828 xCtx.reset(new msfilter::MSCodec_Std97);
5829 assert(sizeof(info.verifier.encryptedVerifierHash) >= RTL_DIGEST_LENGTH_MD5);
5830 bCouldReadHeaders =
5831 checkRead(*m_pTableStream, info.verifier.salt, sizeof(info.verifier.salt)) &&
5832 checkRead(*m_pTableStream, info.verifier.encryptedVerifier, sizeof(info.verifier.encryptedVerifier)) &&
5833 checkRead(*m_pTableStream, info.verifier.encryptedVerifierHash, RTL_DIGEST_LENGTH_MD5);
5835 else
5837 xCtx.reset(new msfilter::MSCodec_CryptoAPI);
5838 bCouldReadHeaders = lclReadCryptoAPIHeader(info, *m_pTableStream);
5841 // if initialization has failed the EncryptionData should be empty
5842 uno::Sequence< beans::NamedValue > aEncryptionData;
5843 if (bCouldReadHeaders)
5844 aEncryptionData = Init97Codec(*xCtx, info.verifier.salt, *pMedium);
5845 else
5846 nErrRet = ERRCODE_SVX_READ_FILTER_CRYPT;
5847 if (aEncryptionData.hasElements() && xCtx->VerifyKey(info.verifier.encryptedVerifier,
5848 info.verifier.encryptedVerifierHash))
5850 nErrRet = ERRCODE_NONE;
5852 pTempMain = MakeTemp(aDecryptMain);
5854 m_pStrm->Seek(0);
5855 std::size_t nUnencryptedHdr = 0x44;
5856 std::unique_ptr<sal_uInt8[]> pIn(new sal_uInt8[nUnencryptedHdr]);
5857 nUnencryptedHdr = m_pStrm->ReadBytes(pIn.get(), nUnencryptedHdr);
5859 DecryptRC4(*xCtx, *m_pStrm, aDecryptMain);
5861 aDecryptMain.Seek(0);
5862 aDecryptMain.WriteBytes(pIn.get(), nUnencryptedHdr);
5863 pIn.reset();
5865 pTempTable = MakeTemp(aDecryptTable);
5866 DecryptRC4(*xCtx, *m_pTableStream, aDecryptTable);
5867 m_pTableStream = &aDecryptTable;
5869 if (!m_pDataStream || m_pDataStream == m_pStrm)
5870 m_pDataStream = &aDecryptMain;
5871 else
5873 pTempData = MakeTemp(aDecryptData);
5874 DecryptRC4(*xCtx, *m_pDataStream, aDecryptData);
5875 m_pDataStream = &aDecryptData;
5878 pMedium->GetItemSet()->ClearItem( SID_PASSWORD );
5879 pMedium->GetItemSet()->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aEncryptionData ) ) );
5882 break;
5886 if (nErrRet == ERRCODE_NONE)
5888 m_pStrm = &aDecryptMain;
5890 m_xWwFib.reset(new WW8Fib(*m_pStrm, m_nWantedVersion));
5891 if (m_xWwFib->m_nFibError)
5892 nErrRet = ERR_SWG_READ_ERROR;
5896 if (!nErrRet)
5897 nErrRet = CoreLoad(pGloss);
5899 pTempMain.reset();
5900 pTempTable.reset();
5901 pTempData.reset();
5903 m_xWwFib.reset();
5904 return nErrRet;
5907 void SwWW8ImplReader::SetOutlineStyles()
5909 // If we are inserted into a document then don't clobber existing outline
5910 // levels.
5911 sal_uInt16 nOutlineStyleListLevelWithAssignment = 0;
5912 if (!m_bNewDoc)
5914 ww8::ParaStyles aOutLined(sw::util::GetParaStyles(m_rDoc));
5915 sw::util::SortByAssignedOutlineStyleListLevel(aOutLined);
5916 ww8::ParaStyles::reverse_iterator aEnd = aOutLined.rend();
5917 for ( ww8::ParaStyles::reverse_iterator aIter = aOutLined.rbegin(); aIter < aEnd; ++aIter)
5919 if ((*aIter)->IsAssignedToListLevelOfOutlineStyle())
5920 nOutlineStyleListLevelWithAssignment |= 1 << (*aIter)->GetAssignedOutlineStyleLevel();
5921 else
5922 break;
5926 // Check applied WW8 list styles at WW8 Built-In Heading Styles
5927 // - Choose the list style which occurs most often as the one which provides
5928 // the list level properties for the Outline Style.
5929 // - Populate temporary list of WW8 Built-In Heading Styles for further
5930 // iteration
5931 std::vector<SwWW8StyInf*> aWW8BuiltInHeadingStyles;
5932 const SwNumRule* pChosenWW8ListStyle = nullptr;
5934 std::map<const SwNumRule*, int> aWW8ListStyleCounts;
5935 for (SwWW8StyInf & rSI : m_vColl)
5937 if (!rSI.IsWW8BuiltInHeadingStyle() || !rSI.HasWW8OutlineLevel())
5939 continue;
5942 aWW8BuiltInHeadingStyles.push_back(&rSI);
5944 const SwNumRule* pWW8ListStyle = rSI.GetOutlineNumrule();
5945 if (pWW8ListStyle != nullptr)
5947 std::map<const SwNumRule*, int>::iterator aCountIter
5948 = aWW8ListStyleCounts.find(pWW8ListStyle);
5949 if (aCountIter == aWW8ListStyleCounts.end())
5951 aWW8ListStyleCounts[pWW8ListStyle] = 1;
5953 else
5955 ++(aCountIter->second);
5960 int nCurrentMaxCount = 0;
5961 for (const auto& rEntry : aWW8ListStyleCounts)
5963 if (rEntry.second > nCurrentMaxCount)
5965 nCurrentMaxCount = rEntry.second;
5966 pChosenWW8ListStyle = rEntry.first;
5971 // - set list level properties of Outline Style - ODF's list style applied
5972 // by default to headings
5973 // - assign corresponding Heading Paragraph Styles to the Outline Style
5974 // - If a heading Paragraph Styles is not applying the WW8 list style which
5975 // had been chosen as
5976 // the one which provides the list level properties for the Outline Style,
5977 // its assignment to
5978 // the Outline Style is removed. A potential applied WW8 list style is
5979 // assigned directly and
5980 // its default outline level is applied.
5981 SwNumRule aOutlineRule(*m_rDoc.GetOutlineNumRule());
5982 bool bAppliedChangedOutlineStyle = false;
5983 for (const SwWW8StyInf* pStyleInf : aWW8BuiltInHeadingStyles)
5985 if (!pStyleInf->m_bColl) //Character Style
5986 continue;
5988 const sal_uInt16 nOutlineStyleListLevelOfWW8BuiltInHeadingStyle
5989 = 1 << pStyleInf->mnWW8OutlineLevel;
5990 if (nOutlineStyleListLevelOfWW8BuiltInHeadingStyle
5991 & nOutlineStyleListLevelWithAssignment)
5993 continue;
5996 if (pChosenWW8ListStyle != nullptr && pStyleInf->mnWW8OutlineLevel
5997 == pStyleInf->m_nListLevel)
5999 const SwNumFormat& rRule
6000 = pChosenWW8ListStyle->Get(pStyleInf->mnWW8OutlineLevel);
6001 aOutlineRule.Set(pStyleInf->mnWW8OutlineLevel, rRule);
6002 bAppliedChangedOutlineStyle = true;
6005 // in case that there are more styles on this level ignore them
6006 nOutlineStyleListLevelWithAssignment
6007 |= nOutlineStyleListLevelOfWW8BuiltInHeadingStyle;
6009 SwTextFormatColl* pTextFormatColl = static_cast<SwTextFormatColl*>(pStyleInf->m_pFormat);
6010 if (pStyleInf->GetOutlineNumrule() != pChosenWW8ListStyle
6011 || (pStyleInf->m_nListLevel < WW8ListManager::nMaxLevel
6012 && pStyleInf->mnWW8OutlineLevel != pStyleInf->m_nListLevel))
6014 // WW8 Built-In Heading Style does not apply the chosen one.
6015 // --> delete assignment to OutlineStyle, but keep its current
6016 // outline level
6017 pTextFormatColl->DeleteAssignmentToListLevelOfOutlineStyle();
6018 // Apply existing WW8 list style a normal list style at the
6019 // Paragraph Style
6020 if (pStyleInf->GetOutlineNumrule() != nullptr)
6022 pTextFormatColl->SetFormatAttr(
6023 SwNumRuleItem(pStyleInf->GetOutlineNumrule()->GetName()));
6025 // apply default outline level of WW8 Built-in Heading Style
6026 const sal_uInt8 nOutlineLevel
6027 = SwWW8StyInf::WW8OutlineLevelToOutlinelevel(
6028 pStyleInf->mnWW8OutlineLevel);
6029 pTextFormatColl->SetFormatAttr(
6030 SfxUInt16Item(RES_PARATR_OUTLINELEVEL, nOutlineLevel));
6032 else
6034 pTextFormatColl->AssignToListLevelOfOutlineStyle(
6035 pStyleInf->mnWW8OutlineLevel);
6039 if (bAppliedChangedOutlineStyle)
6041 m_rDoc.SetOutlineNumRule(aOutlineRule);
6045 const OUString* SwWW8ImplReader::GetAnnotationAuthor(sal_uInt16 nIdx)
6047 if (!m_pAtnNames && m_xWwFib->m_lcbGrpStAtnOwners)
6049 // Determine authors: can be found in the TableStream
6050 m_pAtnNames.reset(new std::vector<OUString>);
6051 SvStream& rStrm = *m_pTableStream;
6053 long nOldPos = rStrm.Tell();
6054 rStrm.Seek( m_xWwFib->m_fcGrpStAtnOwners );
6056 long nRead = 0, nCount = m_xWwFib->m_lcbGrpStAtnOwners;
6057 while (nRead < nCount && rStrm.good())
6059 if( m_bVer67 )
6061 m_pAtnNames->push_back(read_uInt8_PascalString(rStrm,
6062 RTL_TEXTENCODING_MS_1252));
6063 nRead += m_pAtnNames->rbegin()->getLength() + 1; // Length + sal_uInt8 count
6065 else
6067 m_pAtnNames->push_back(read_uInt16_PascalString(rStrm));
6068 // Unicode: double the length + sal_uInt16 count
6069 nRead += (m_pAtnNames->rbegin()->getLength() + 1)*2;
6072 rStrm.Seek( nOldPos );
6075 const OUString *pRet = nullptr;
6076 if (m_pAtnNames && nIdx < m_pAtnNames->size())
6077 pRet = &((*m_pAtnNames)[nIdx]);
6078 return pRet;
6081 void SwWW8ImplReader::GetSmartTagInfo(SwFltRDFMark& rMark)
6083 if (!m_pSmartTagData && m_xWwFib->m_lcbFactoidData)
6085 m_pSmartTagData.reset(new WW8SmartTagData);
6086 m_pSmartTagData->Read(*m_pTableStream, m_xWwFib->m_fcFactoidData, m_xWwFib->m_lcbFactoidData);
6089 if (!m_pSmartTagData)
6090 return;
6092 // Check if the handle is a valid smart tag bookmark index.
6093 size_t nIndex = rMark.GetHandle();
6094 if (nIndex >= m_pSmartTagData->m_aPropBags.size())
6095 return;
6097 // Check if the smart tag bookmark refers to a valid factoid type.
6098 const MSOPropertyBag& rPropertyBag = m_pSmartTagData->m_aPropBags[rMark.GetHandle()];
6099 auto& rFactoidTypes = m_pSmartTagData->m_aPropBagStore.m_aFactoidTypes;
6100 auto itPropertyBag = std::find_if(rFactoidTypes.begin(), rFactoidTypes.end(),
6101 [&rPropertyBag](const MSOFactoidType& rType) { return rType.m_nId == rPropertyBag.m_nId; });
6102 if (itPropertyBag == rFactoidTypes.end())
6103 return;
6105 // Check if the factoid is an RDF one.
6106 const MSOFactoidType& rFactoidType = *itPropertyBag;
6107 if (rFactoidType.m_aUri != "http://www.w3.org/1999/02/22-rdf-syntax-ns#")
6108 return;
6110 // Finally put the relevant attributes to the mark.
6111 std::vector< std::pair<OUString, OUString> > aAttributes;
6112 for (const MSOProperty& rProperty : rPropertyBag.m_aProperties)
6114 OUString aKey;
6115 OUString aValue;
6116 if (rProperty.m_nKey < m_pSmartTagData->m_aPropBagStore.m_aStringTable.size())
6117 aKey = m_pSmartTagData->m_aPropBagStore.m_aStringTable[rProperty.m_nKey];
6118 if (rProperty.m_nValue < m_pSmartTagData->m_aPropBagStore.m_aStringTable.size())
6119 aValue = m_pSmartTagData->m_aPropBagStore.m_aStringTable[rProperty.m_nValue];
6120 if (!aKey.isEmpty() && !aValue.isEmpty())
6121 aAttributes.emplace_back(aKey, aValue);
6123 rMark.SetAttributes(aAttributes);
6126 ErrCode SwWW8ImplReader::LoadDoc(WW8Glossary *pGloss)
6128 ErrCode nErrRet = ERRCODE_NONE;
6131 static const sal_Char* aNames[ 13 ] = {
6132 "WinWord/WW", "WinWord/WW8", "WinWord/WWFT",
6133 "WinWord/WWFLX", "WinWord/WWFLY",
6134 "WinWord/WWF",
6135 "WinWord/WWFA0", "WinWord/WWFA1", "WinWord/WWFA2",
6136 "WinWord/WWFB0", "WinWord/WWFB1", "WinWord/WWFB2",
6137 "WinWord/RegardHindiDigits"
6139 sal_uInt64 aVal[ 13 ];
6141 SwFilterOptions aOpt( 13, aNames, aVal );
6143 m_nIniFlags = aVal[ 0 ];
6144 m_nIniFlags1= aVal[ 1 ];
6145 // Moves Flys by x twips to the right or left
6146 m_nIniFlyDx = aVal[ 3 ];
6147 m_nIniFlyDy = aVal[ 4 ];
6149 m_nFieldFlags = aVal[ 5 ];
6150 m_nFieldTagAlways[0] = aVal[ 6 ];
6151 m_nFieldTagAlways[1] = aVal[ 7 ];
6152 m_nFieldTagAlways[2] = aVal[ 8 ];
6153 m_nFieldTagBad[0] = aVal[ 9 ];
6154 m_nFieldTagBad[1] = aVal[ 10 ];
6155 m_nFieldTagBad[2] = aVal[ 11 ];
6156 m_bRegardHindiDigits = aVal[ 12 ] > 0;
6159 sal_uInt16 nMagic(0);
6160 m_pStrm->ReadUInt16( nMagic );
6162 // Remember: 6 means "6 OR 7", 7 means "JUST 7"
6163 switch (m_nWantedVersion)
6165 case 6:
6166 case 7:
6167 if (
6168 0xa59b != nMagic && 0xa59c != nMagic &&
6169 0xa5dc != nMagic && 0xa5db != nMagic &&
6170 (nMagic < 0xa697 || nMagic > 0xa699)
6173 // Test for own 97 fake!
6174 if (m_pStg && 0xa5ec == nMagic)
6176 sal_uLong nCurPos = m_pStrm->Tell();
6177 if (m_pStrm->Seek(nCurPos + 22))
6179 sal_uInt32 nfcMin;
6180 m_pStrm->ReadUInt32( nfcMin );
6181 if (0x300 != nfcMin)
6182 nErrRet = ERR_WW6_NO_WW6_FILE_ERR;
6184 m_pStrm->Seek( nCurPos );
6186 else
6187 nErrRet = ERR_WW6_NO_WW6_FILE_ERR;
6189 break;
6190 case 8:
6191 if (0xa5ec != nMagic)
6192 nErrRet = ERR_WW8_NO_WW8_FILE_ERR;
6193 break;
6194 default:
6195 nErrRet = ERR_WW8_NO_WW8_FILE_ERR;
6196 OSL_ENSURE( false, "We forgot to encode nVersion!" );
6197 break;
6200 if (!nErrRet)
6201 nErrRet = LoadThroughDecryption(pGloss);
6203 m_rDoc.PropagateOutlineRule();
6205 return nErrRet;
6208 extern "C" SAL_DLLPUBLIC_EXPORT Reader* ImportDOC()
6210 return new WW8Reader;
6213 namespace
6215 class FontCacheGuard
6217 public:
6218 ~FontCacheGuard()
6220 FlushFontCache();
6225 bool TestImportDOC(SvStream &rStream, const OUString &rFltName)
6227 FontCacheGuard aFontCacheGuard;
6228 std::unique_ptr<Reader> xReader(ImportDOC());
6230 tools::SvRef<SotStorage> xStorage;
6231 xReader->m_pStream = &rStream;
6232 if (rFltName != "WW6")
6236 xStorage = tools::SvRef<SotStorage>(new SotStorage(rStream));
6237 if (xStorage->GetError())
6238 return false;
6240 catch (...)
6242 return false;
6244 xReader->m_pStorage = xStorage.get();
6246 xReader->SetFltName(rFltName);
6248 SwGlobals::ensure();
6250 SfxObjectShellLock xDocSh(new SwDocShell(SfxObjectCreateMode::INTERNAL));
6251 xDocSh->DoInitNew();
6252 SwDoc *pD = static_cast<SwDocShell*>((&xDocSh))->GetDoc();
6254 SwNodeIndex aIdx(pD->GetNodes().GetEndOfContent(), -1);
6255 SwPaM aPaM(aIdx);
6256 aPaM.GetPoint()->nContent.Assign(aIdx.GetNode().GetContentNode(), 0);
6257 pD->SetInReading(true);
6258 bool bRet = xReader->Read(*pD, OUString(), aPaM, OUString()) == ERRCODE_NONE;
6259 pD->SetInReading(false);
6261 return bRet;
6264 extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportWW8(SvStream &rStream)
6266 return TestImportDOC(rStream, "CWW8");
6269 extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportWW6(SvStream &rStream)
6271 return TestImportDOC(rStream, "CWW6");
6274 extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportWW2(SvStream &rStream)
6276 return TestImportDOC(rStream, "WW6");
6279 ErrCode WW8Reader::OpenMainStream( tools::SvRef<SotStorageStream>& rRef, sal_uInt16& rBuffSize )
6281 ErrCode nRet = ERR_SWG_READ_ERROR;
6282 OSL_ENSURE(m_pStorage, "Where is my Storage?");
6283 rRef = m_pStorage->OpenSotStream( "WordDocument", StreamMode::READ | StreamMode::SHARE_DENYALL);
6285 if( rRef.is() )
6287 if( ERRCODE_NONE == rRef->GetError() )
6289 sal_uInt16 nOld = rRef->GetBufferSize();
6290 rRef->SetBufferSize( rBuffSize );
6291 rBuffSize = nOld;
6292 nRet = ERRCODE_NONE;
6294 else
6295 nRet = rRef->GetError();
6297 return nRet;
6300 ErrCode WW8Reader::Read(SwDoc &rDoc, const OUString& rBaseURL, SwPaM &rPaM, const OUString & /* FileName */)
6302 sal_uInt16 nOldBuffSize = 32768;
6303 bool bNew = !m_bInsertMode; // New Doc (no inserting)
6305 tools::SvRef<SotStorageStream> refStrm; // So that no one else can steal the Stream
6306 SvStream* pIn = m_pStream;
6308 ErrCode nRet = ERRCODE_NONE;
6309 sal_uInt8 nVersion = 8;
6311 const OUString sFltName = GetFltName();
6312 if ( sFltName=="WW6" )
6314 if (m_pStream)
6315 nVersion = 6;
6316 else
6318 OSL_ENSURE(false, "WinWord 95 Reader-Read without Stream");
6319 nRet = ERR_SWG_READ_ERROR;
6322 else
6324 if ( sFltName=="CWW6" )
6325 nVersion = 6;
6326 else if ( sFltName=="CWW7" )
6327 nVersion = 7;
6329 if( m_pStorage.is() )
6331 nRet = OpenMainStream( refStrm, nOldBuffSize );
6332 pIn = refStrm.get();
6334 else
6336 OSL_ENSURE(false, "WinWord 95/97 Reader-Read without Storage");
6337 nRet = ERR_SWG_READ_ERROR;
6341 if( !nRet )
6343 std::unique_ptr<SwWW8ImplReader> pRdr(new SwWW8ImplReader(nVersion, m_pStorage.get(), pIn, rDoc,
6344 rBaseURL, bNew, m_bSkipImages, *rPaM.GetPoint()));
6345 if (bNew)
6347 rPaM.GetBound().nContent.Assign(nullptr, 0);
6348 rPaM.GetBound(false).nContent.Assign(nullptr, 0);
6352 nRet = pRdr->LoadDoc();
6354 catch( const std::exception& )
6356 nRet = ERR_WW8_NO_WW8_FILE_ERR;
6359 if( refStrm.is() )
6361 refStrm->SetBufferSize( nOldBuffSize );
6362 refStrm.clear();
6364 else
6366 pIn->ResetError();
6370 return nRet;
6373 SwReaderType WW8Reader::GetReaderType()
6375 return SwReaderType::Storage | SwReaderType::Stream;
6378 bool WW8Reader::HasGlossaries() const
6380 return true;
6383 bool WW8Reader::ReadGlossaries(SwTextBlocks& rBlocks, bool bSaveRelFiles) const
6385 bool bRet=false;
6387 WW8Reader *pThis = const_cast<WW8Reader *>(this);
6389 sal_uInt16 nOldBuffSize = 32768;
6390 tools::SvRef<SotStorageStream> refStrm;
6391 if (!pThis->OpenMainStream(refStrm, nOldBuffSize))
6393 WW8Glossary aGloss( refStrm, 8, m_pStorage.get() );
6394 bRet = aGloss.Load( rBlocks, bSaveRelFiles );
6396 return bRet;
6399 bool SwMSDffManager::GetOLEStorageName(sal_uInt32 nOLEId, OUString& rStorageName,
6400 tools::SvRef<SotStorage>& rSrcStorage, uno::Reference < embed::XStorage >& rDestStorage) const
6402 bool bRet = false;
6404 sal_Int32 nPictureId = 0;
6405 if (rReader.m_pStg)
6407 // Via the TextBox-PLCF we get the right char Start-End positions
6408 // We should then find the EmbeddedField and the corresponding Sprms
6409 // in that Area.
6410 // We only need the Sprm for the Picture Id.
6411 long nOldPos = rReader.m_pStrm->Tell();
6413 // #i32596# - consider return value of method
6414 // <rReader.GetTxbxTextSttEndCp(..)>. If it returns false, method
6415 // wasn't successful. Thus, continue in this case.
6416 // Note: Ask MM for initialization of <nStartCp> and <nEndCp>.
6417 // Note: Ask MM about assertions in method <rReader.GetTxbxTextSttEndCp(..)>.
6418 WW8_CP nStartCp, nEndCp;
6419 if ( rReader.m_bDrawCpOValid && rReader.GetTxbxTextSttEndCp(nStartCp, nEndCp,
6420 static_cast<sal_uInt16>((nOLEId >> 16) & 0xFFFF),
6421 static_cast<sal_uInt16>(nOLEId & 0xFFFF)) )
6423 WW8PLCFxSaveAll aSave;
6424 rReader.m_xPlcxMan->SaveAllPLCFx( aSave );
6426 nStartCp += rReader.m_nDrawCpO;
6427 nEndCp += rReader.m_nDrawCpO;
6428 WW8PLCFx_Cp_FKP* pChp = rReader.m_xPlcxMan->GetChpPLCF();
6429 wwSprmParser aSprmParser(*rReader.m_xWwFib);
6430 while (nStartCp <= nEndCp && !nPictureId)
6432 if (!pChp->SeekPos( nStartCp))
6433 break;
6434 WW8PLCFxDesc aDesc;
6435 pChp->GetSprms( &aDesc );
6437 if (aDesc.nSprmsLen && aDesc.pMemPos) // Attributes present
6439 long nLen = aDesc.nSprmsLen;
6440 const sal_uInt8* pSprm = aDesc.pMemPos;
6442 while (nLen >= 2 && !nPictureId)
6444 sal_uInt16 nId = aSprmParser.GetSprmId(pSprm);
6445 sal_uInt16 nSL = aSprmParser.GetSprmSize(nId, pSprm, nLen);
6447 if( nLen < nSL )
6448 break; // Not enough Bytes left
6450 if (0x6A03 == nId)
6452 nPictureId = SVBT32ToUInt32(pSprm +
6453 aSprmParser.DistanceToData(nId));
6454 bRet = true;
6456 pSprm += nSL;
6457 nLen -= nSL;
6460 nStartCp = aDesc.nEndPos;
6463 rReader.m_xPlcxMan->RestoreAllPLCFx( aSave );
6466 rReader.m_pStrm->Seek( nOldPos );
6469 if( bRet )
6471 rStorageName = "_";
6472 rStorageName += OUString::number(nPictureId);
6473 rSrcStorage = rReader.m_pStg->OpenSotStorage(SL::aObjectPool);
6474 if (!rReader.m_pDocShell)
6475 bRet=false;
6476 else
6477 rDestStorage = rReader.m_pDocShell->GetStorage();
6479 return bRet;
6483 * When reading a single Box (which possibly is part of a group), we do
6484 * not yet have enough information to decide whether we need it as a TextField
6485 * or not.
6486 * So convert all of them as a precaution.
6487 * FIXME: Actually implement this!
6489 bool SwMSDffManager::ShapeHasText(sal_uLong, sal_uLong) const
6491 return true;
6494 bool SwWW8ImplReader::InEqualOrHigherApo(int nLvl) const
6496 if (nLvl)
6497 --nLvl;
6498 // #i60827# - check size of <maApos> to assure that <maApos.begin() + nLvl> can be performed.
6499 if ( sal::static_int_cast< sal_Int32>(nLvl) >= sal::static_int_cast< sal_Int32>(m_aApos.size()) )
6501 return false;
6503 auto aIter = std::find(m_aApos.begin() + nLvl, m_aApos.end(), true);
6504 return aIter != m_aApos.end();
6507 bool SwWW8ImplReader::InEqualApo(int nLvl) const
6509 // If we are in a table, see if an apo was inserted at the level below the table.
6510 if (nLvl)
6511 --nLvl;
6512 if (nLvl < 0 || static_cast<size_t>(nLvl) >= m_aApos.size())
6513 return false;
6514 return m_aApos[nLvl];
6517 namespace sw
6519 namespace hack
6521 Position::Position(const SwPosition &rPos)
6522 : maPtNode(rPos.nNode), mnPtContent(rPos.nContent.GetIndex())
6526 Position::Position(const Position &rPos)
6527 : maPtNode(rPos.maPtNode), mnPtContent(rPos.mnPtContent)
6531 Position::operator SwPosition() const
6533 SwPosition aRet(maPtNode);
6534 aRet.nContent.Assign(maPtNode.GetNode().GetContentNode(), mnPtContent);
6535 return aRet;
6540 SwMacroInfo::SwMacroInfo()
6541 : SdrObjUserData( SdrInventor::ScOrSwDraw, SW_UD_IMAPDATA )
6542 , mnShapeId(-1)
6546 SwMacroInfo::~SwMacroInfo()
6550 std::unique_ptr<SdrObjUserData> SwMacroInfo::Clone( SdrObject* /*pObj*/ ) const
6552 return std::unique_ptr<SdrObjUserData>(new SwMacroInfo( *this ));
6555 std::unique_ptr<SfxItemSet> SwWW8ImplReader::SetCurrentItemSet(std::unique_ptr<SfxItemSet> pItemSet)
6557 std::unique_ptr<SfxItemSet> xRet(std::move(m_xCurrentItemSet));
6558 m_xCurrentItemSet = std::move(pItemSet);
6559 return xRet;
6562 void SwWW8ImplReader::NotifyMacroEventRead()
6564 if (m_bNotifyMacroEventRead)
6565 return;
6566 uno::Reference<frame::XModel> const xModel(m_rDoc.GetDocShell()->GetBaseModel());
6567 comphelper::DocumentInfo::notifyMacroEventRead(xModel);
6568 m_bNotifyMacroEventRead = true;
6571 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */