xref: /core/sw/source/filter/ww8/ww8par.cxx (revision 71ce1181)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <config_features.h>
21 
22 #include <sal/config.h>
23 #include <sal/log.hxx>
24 
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/packages/XPackageEncryption.hpp>
29 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
30 #include <com/sun/star/text/XTextFieldsSupplier.hpp>
31 
32 #include <i18nlangtag/languagetag.hxx>
33 
34 #include <comphelper/configuration.hxx>
35 #include <comphelper/string.hxx>
36 #include <unotools/ucbstreamhelper.hxx>
37 #include <unotools/streamwrap.hxx>
38 #include <rtl/random.h>
39 #include <rtl/ustring.hxx>
40 #include <rtl/ustrbuf.hxx>
41 
42 #include <sfx2/docinf.hxx>
43 #include <sfx2/frame.hxx>
44 #include <sfx2/zoomitem.hxx>
45 #include <tools/urlobj.hxx>
46 #include <unotools/tempfile.hxx>
47 
48 #include <comphelper/docpasswordrequest.hxx>
49 #include <comphelper/documentinfo.hxx>
50 #include <comphelper/propertysequence.hxx>
51 
52 #include <editeng/outlobj.hxx>
53 #include <editeng/brushitem.hxx>
54 #include <editeng/formatbreakitem.hxx>
55 #include <editeng/tstpitem.hxx>
56 #include <editeng/ulspitem.hxx>
57 #include <editeng/langitem.hxx>
58 #include <editeng/opaqitem.hxx>
59 #include <editeng/charhiddenitem.hxx>
60 #include <editeng/fontitem.hxx>
61 #include <editeng/editeng.hxx>
62 #include <svx/svdoole2.hxx>
63 #include <svx/svdoashp.hxx>
64 #include <svx/svxerr.hxx>
65 #include <filter/msfilter/mscodec.hxx>
66 #include <svx/svdmodel.hxx>
67 #include <svx/xflclit.hxx>
68 #include <svx/sdasitm.hxx>
69 #include <svx/sdtagitm.hxx>
70 #include <svx/sdtcfitm.hxx>
71 #include <svx/sdtditm.hxx>
72 #include <svx/sdtmfitm.hxx>
73 #include <fmtfld.hxx>
74 #include <fmturl.hxx>
75 #include <fmtinfmt.hxx>
76 #include <reffld.hxx>
77 #include <fmthdft.hxx>
78 #include <fmtcntnt.hxx>
79 #include <fmtcnct.hxx>
80 #include <fmtanchr.hxx>
81 #include <fmtpdsc.hxx>
82 #include <ftninfo.hxx>
83 #include <fmtftn.hxx>
84 #include <txtftn.hxx>
85 #include <ndtxt.hxx>
86 #include <pagedesc.hxx>
87 #include <paratr.hxx>
88 #include <poolfmt.hxx>
89 #include <fmtclbl.hxx>
90 #include <section.hxx>
91 #include <docsh.hxx>
92 #include <IDocumentFieldsAccess.hxx>
93 #include <IDocumentLayoutAccess.hxx>
94 #include <IDocumentMarkAccess.hxx>
95 #include <IDocumentStylePoolAccess.hxx>
96 #include <IDocumentExternalData.hxx>
97 #include <../../core/inc/DocumentRedlineManager.hxx>
98 #include <docufld.hxx>
99 #include <swfltopt.hxx>
100 #include <utility>
101 #include <viewsh.hxx>
102 #include <shellres.hxx>
103 #include <swerror.h>
104 #include <swtable.hxx>
105 #include <fchrfmt.hxx>
106 #include <charfmt.hxx>
107 #include <fmtautofmt.hxx>
108 #include <IDocumentSettingAccess.hxx>
109 #include "sprmids.hxx"
110 
111 #include "writerwordglue.hxx"
112 
113 #include <ndgrf.hxx>
114 #include <editeng/editids.hrc>
115 #include <fmtflcnt.hxx>
116 #include <txatbase.hxx>
117 
118 #include "ww8par2.hxx"
119 
120 #include <com/sun/star/beans/PropertyAttribute.hpp>
121 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
122 #include <com/sun/star/document/XViewDataSupplier.hpp>
123 
124 #include <svl/lngmisc.hxx>
125 #include <svl/itemiter.hxx>
126 #include <svl/whiter.hxx>
127 
128 #include <comphelper/indexedpropertyvalues.hxx>
129 #include <comphelper/processfactory.hxx>
130 #include <basic/basmgr.hxx>
131 
132 #include "ww8toolbar.hxx"
133 #include <o3tl/unit_conversion.hxx>
134 #include <o3tl/safeint.hxx>
135 #include <osl/file.hxx>
136 
137 #include <breakit.hxx>
138 
139 #include <sfx2/docfile.hxx>
140 #include <swdll.hxx>
141 #include "WW8Sttbf.hxx"
142 #include "WW8FibData.hxx"
143 #include <unordered_set>
144 #include <memory>
145 
146 #include <com/sun/star/i18n/XBreakIterator.hpp>
147 #include <com/sun/star/i18n/ScriptType.hpp>
148 #include <unotools/pathoptions.hxx>
149 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
150 
151 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
152 #include <comphelper/sequenceashashmap.hxx>
153 #include <oox/ole/vbaproject.hxx>
154 #include <oox/ole/olestorage.hxx>
155 #include <comphelper/storagehelper.hxx>
156 #include <sfx2/DocumentMetadataAccess.hxx>
157 #include <comphelper/diagnose_ex.hxx>
158 #include <officecfg/Office/Common.hxx>
159 
160 using namespace ::com::sun::star;
161 using namespace sw::util;
162 using namespace sw::types;
163 using namespace nsHdFtFlags;
164 
GetMacroInfo(SdrObject * pObj)165 static SwMacroInfo* GetMacroInfo( SdrObject* pObj )
166 {
167     if ( pObj )
168     {
169         sal_uInt16 nCount = pObj->GetUserDataCount();
170         for( sal_uInt16 i = 0; i < nCount; i++ )
171         {
172             SdrObjUserData* pData = pObj->GetUserData( i );
173             if( pData && pData->GetInventor() == SdrInventor::ScOrSwDraw
174                 && pData->GetId() == SW_UD_IMAPDATA)
175             {
176                 return dynamic_cast<SwMacroInfo*>(pData);
177             }
178         }
179         SwMacroInfo* pData = new SwMacroInfo;
180         pObj->AppendUserData(std::unique_ptr<SdrObjUserData>(pData));
181         return pData;
182     }
183 
184     return nullptr;
185 };
186 
lclGetAbsPath(OUString & rPath,sal_uInt16 nLevel,SwDocShell const * pDocShell)187 static void lclGetAbsPath(OUString& rPath, sal_uInt16 nLevel, SwDocShell const * pDocShell)
188 {
189     OUStringBuffer aTmpStr;
190     while( nLevel )
191     {
192         aTmpStr.append("../");
193         --nLevel;
194     }
195     if (!aTmpStr.isEmpty())
196         aTmpStr.append(rPath);
197     else
198         aTmpStr = rPath;
199 
200     if (!aTmpStr.isEmpty())
201     {
202         bool bWasAbs = false;
203         rPath = pDocShell->GetMedium()->GetURLObject().smartRel2Abs( aTmpStr.makeStringAndClear(), bWasAbs ).GetMainURL( INetURLObject::DecodeMechanism::NONE );
204         // full path as stored in SvxURLField must be encoded
205     }
206 }
207 
208 namespace
209 {
lclIgnoreUString32(SvStream & rStrm)210     void lclIgnoreUString32(SvStream& rStrm)
211     {
212         sal_uInt32 nChars(0);
213         rStrm.ReadUInt32(nChars);
214         nChars *= 2;
215         rStrm.SeekRel(nChars);
216     }
217 }
218 
ReadEmbeddedData(SvStream & rStrm,SwDocShell const * pDocShell,struct HyperLinksTable & hlStr)219 void SwWW8ImplReader::ReadEmbeddedData(SvStream& rStrm, SwDocShell const * pDocShell, struct HyperLinksTable& hlStr)
220 {
221     // (0x01B8) HLINK
222     // const sal_uInt16 WW8_ID_HLINK               = 0x01B8;
223     constexpr sal_uInt32 WW8_HLINK_BODY             = 0x00000001;   /// Contains file link or URL.
224     constexpr sal_uInt32 WW8_HLINK_ABS              = 0x00000002;   /// Absolute path.
225     constexpr sal_uInt32 WW8_HLINK_DESCR            = 0x00000014;   /// Description.
226     constexpr sal_uInt32 WW8_HLINK_MARK             = 0x00000008;   /// Text mark.
227     constexpr sal_uInt32 WW8_HLINK_FRAME            = 0x00000080;   /// Target frame.
228     constexpr sal_uInt32 WW8_HLINK_UNC              = 0x00000100;   /// UNC path.
229 
230     //sal_uInt8 maGuidStdLink[ 16 ] ={
231     //    0xD0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE, 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B };
232 
233     sal_uInt8 const aGuidUrlMoniker[ 16 ] = {
234         0xE0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE, 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B };
235 
236     sal_uInt8 const aGuidFileMoniker[ 16 ] = {
237         0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 };
238 
239     sal_uInt8 aGuid[16];
240     sal_uInt32 nFlags(0);
241 
242     rStrm.ReadBytes(aGuid, 16);
243     rStrm.SeekRel( 4 );
244     rStrm.ReadUInt32( nFlags );
245 
246     std::unique_ptr< OUString > xLongName;    // link / file name
247     std::unique_ptr< OUString > xShortName;   // 8.3-representation of file name
248     std::unique_ptr< OUString > xTextMark;    // text mark
249 
250     // description (ignore)
251     if( ::get_flag( nFlags, WW8_HLINK_DESCR ) )
252         lclIgnoreUString32( rStrm );
253 
254     // target frame
255     if( ::get_flag( nFlags, WW8_HLINK_FRAME ) )
256     {
257         hlStr.tarFrame = read_uInt32_lenPrefixed_uInt16s_ToOUString(rStrm);
258     }
259 
260         // UNC path
261     if( ::get_flag( nFlags, WW8_HLINK_UNC ) )
262     {
263         // MS-OSHARED: An unsigned integer that specifies the number of Unicode characters in the
264         // string field, including the null-terminating character.
265         sal_uInt32 nStrLen(0);
266         rStrm.ReadUInt32(nStrLen);
267         if (nStrLen)
268         {
269             xLongName.reset(new OUString(read_uInt16s_ToOUString(rStrm, nStrLen - 1)));
270             rStrm.SeekRel(sizeof(sal_Unicode)); // skip null-byte at end
271             lclGetAbsPath( *xLongName, 0 , pDocShell);
272         }
273     }
274     // file link or URL
275     else if( ::get_flag( nFlags, WW8_HLINK_BODY ) )
276     {
277         rStrm.ReadBytes(aGuid, 16);
278 
279         if( memcmp(aGuid, aGuidFileMoniker, 16) == 0 )
280         {
281             sal_uInt16 nLevel = 0;                  // counter for level to climb down in path
282             rStrm.ReadUInt16( nLevel );
283             // MS-OSHARED: An unsigned integer that specifies the number of
284             // ANSI characters in ansiPath, including the terminating NULL character
285             sal_uInt32 nUnits = 0;
286             rStrm.ReadUInt32(nUnits);
287             if (!nUnits)
288                 xShortName.reset(new OUString);
289             else
290             {
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()));
294             }
295             rStrm.SeekRel( 24 );
296 
297             sal_uInt32 nStrLen(0);
298             rStrm.ReadUInt32( nStrLen );
299             if( nStrLen )
300             {
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);
308             }
309             else
310                 lclGetAbsPath( *xShortName, nLevel, pDocShell);
311         }
312         else if( memcmp(aGuid, aGuidUrlMoniker, 16) == 0 )
313         {
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)
322                 xLongName.reset(new OUString);
323             else
324             {
325                 xLongName.reset(new OUString(read_uInt16s_ToOUString(rStrm, nStrLen - 1)));
326                 rStrm.SeekRel(sizeof(sal_Unicode)); // skip null-byte at end
327             }
328             if( !::get_flag( nFlags, WW8_HLINK_ABS ) )
329                 lclGetAbsPath( *xLongName, 0 ,pDocShell);
330         }
331         else
332         {
333             SAL_INFO("sw.ww8", "WW8Hyperlink::ReadEmbeddedData - unknown content GUID");
334         }
335     }
336 
337     // text mark
338     if( ::get_flag( nFlags, WW8_HLINK_MARK ) )
339     {
340         xTextMark.reset(new OUString(read_uInt32_lenPrefixed_uInt16s_ToOUString(rStrm)));
341     }
342 
343     if (!xLongName && xShortName)
344         xLongName.reset(new OUString(*xShortName));
345     else if (!xLongName && xTextMark)
346         xLongName.reset( new OUString );
347 
348     if (xLongName)
349     {
350         if (xTextMark)
351         {
352             if (xLongName->isEmpty())
353                 *xTextMark = xTextMark->replace('!', '.');
354             *xLongName += "#" + *xTextMark;
355         }
356         hlStr.hLinkAddr = *xLongName;
357     }
358 }
359 
360 namespace {
361 
362 class BasicProjImportHelper
363 {
364     SwDocShell& mrDocShell;
365     uno::Reference< uno::XComponentContext > mxCtx;
366 public:
BasicProjImportHelper(SwDocShell & rShell)367     explicit BasicProjImportHelper( SwDocShell& rShell ) : mrDocShell( rShell ),
368       mxCtx(comphelper::getProcessComponentContext())
369     {
370     }
371     bool import( const uno::Reference< io::XInputStream >& rxIn );
372     OUString getProjectName() const;
373 };
374 
375 }
376 
import(const uno::Reference<io::XInputStream> & rxIn)377 bool BasicProjImportHelper::import( const uno::Reference< io::XInputStream >& rxIn )
378 {
379     bool bRet = false;
380     try
381     {
382         oox::ole::OleStorage root( mxCtx, rxIn, false );
383         oox::StorageRef vbaStg = root.openSubStorage( u"Macros"_ustr , false );
384         if ( vbaStg )
385         {
386             oox::ole::VbaProject aVbaPrj( mxCtx, mrDocShell.GetModel(), u"Writer" );
387             bRet = aVbaPrj.importVbaProject( *vbaStg );
388         }
389     }
390     catch( const uno::Exception& )
391     {
392         bRet = false;
393     }
394     return bRet;
395 }
396 
getProjectName() const397 OUString BasicProjImportHelper::getProjectName() const
398 {
399     OUString sProjName( u"Standard"_ustr );
400     uno::Reference< beans::XPropertySet > xProps( mrDocShell.GetModel(), uno::UNO_QUERY );
401     if ( xProps.is() )
402     {
403         try
404         {
405             uno::Reference< script::vba::XVBACompatibility > xVBA( xProps->getPropertyValue( u"BasicLibraries"_ustr ), uno::UNO_QUERY_THROW  );
406             sProjName = xVBA->getProjectName();
407 
408         }
409         catch( const uno::Exception& )
410         {
411         }
412     }
413     return sProjName;
414 }
415 
416 namespace {
417 
418 class Sttb : public TBBase
419 {
420 struct SBBItem
421 {
422     sal_uInt16 cchData;
423     OUString data;
SBBItem__anonf22e66620311::Sttb::SBBItem424     SBBItem() : cchData(0){}
425 };
426     sal_uInt16 m_fExtend;
427     sal_uInt16 m_cData;
428     sal_uInt16 m_cbExtra;
429 
430     std::vector< SBBItem > m_dataItems;
431 
432     Sttb(Sttb const&) = delete;
433     Sttb& operator=(Sttb const&) = delete;
434 
435 public:
436     Sttb();
437 
438     bool Read(SvStream &rS) override;
439     OUString getStringAtIndex( sal_uInt32 );
440 };
441 
442 }
443 
Sttb()444 Sttb::Sttb()
445     : m_fExtend(0)
446     , m_cData(0)
447     , m_cbExtra(0)
448 {
449 }
450 
Read(SvStream & rS)451 bool Sttb::Read( SvStream& rS )
452 {
453     SAL_INFO("sw.ww8", "stream pos " << rS.Tell());
454     nOffSet = rS.Tell();
455     rS.ReadUInt16( m_fExtend ).ReadUInt16( m_cData ).ReadUInt16( m_cbExtra );
456     if ( m_cData )
457     {
458         //if they are all going to be empty strings, how many could there be
459         const size_t nMaxPossibleRecords = rS.remainingSize() / sizeof(sal_uInt16);
460         if (m_cData > nMaxPossibleRecords)
461             return false;
462         for ( sal_Int32 index = 0; index < m_cData; ++index )
463         {
464             SBBItem aItem;
465             rS.ReadUInt16( aItem.cchData );
466             aItem.data = read_uInt16s_ToOUString(rS, aItem.cchData);
467             m_dataItems.push_back( aItem );
468         }
469     }
470     return true;
471 }
472 
473 OUString
getStringAtIndex(sal_uInt32 index)474 Sttb::getStringAtIndex( sal_uInt32 index )
475 {
476     OUString aRet;
477     if ( index < m_dataItems.size() )
478         aRet = m_dataItems[ index ].data;
479     return aRet;
480 
481 }
482 
SwMSDffManager(SwWW8ImplReader & rRdr,bool bSkipImages)483 SwMSDffManager::SwMSDffManager( SwWW8ImplReader& rRdr, bool bSkipImages )
484     : SvxMSDffManager(*rRdr.m_pTableStream, rRdr.GetBaseURL(), rRdr.m_xWwFib->m_fcDggInfo,
485         rRdr.m_pDataStream, nullptr, 0, COL_WHITE, rRdr.m_pStrm, bSkipImages),
486     m_rReader(rRdr), m_pFallbackStream(nullptr)
487 {
488     SetSvxMSDffSettings( GetSvxMSDffSettings() );
489     nSvxMSDffOLEConvFlags = SwMSDffManager::GetFilterFlags();
490 }
491 
GetFilterFlags()492 sal_uInt32 SwMSDffManager::GetFilterFlags()
493 {
494     sal_uInt32 nFlags(0);
495     if (officecfg::Office::Common::Filter::Microsoft::Import::MathTypeToMath::get())
496         nFlags |= OLE_MATHTYPE_2_STARMATH;
497     if (officecfg::Office::Common::Filter::Microsoft::Import::ExcelToCalc::get())
498         nFlags |= OLE_EXCEL_2_STARCALC;
499     if (officecfg::Office::Common::Filter::Microsoft::Import::PowerPointToImpress::get())
500         nFlags |= OLE_POWERPOINT_2_STARIMPRESS;
501     if (officecfg::Office::Common::Filter::Microsoft::Import::WinWordToWriter::get())
502         nFlags |= OLE_WINWORD_2_STARWRITER;
503     return nFlags;
504 }
505 
506 /*
507  * I would like to override the default OLE importing to add a test
508  * and conversion of OCX controls from their native OLE type into our
509  * native nonOLE Form Control Objects.
510  */
511 // #i32596# - consider new parameter <_nCalledByGroup>
ImportOLE(sal_uInt32 nOLEId,const Graphic & rGrf,const tools::Rectangle & rBoundRect,const tools::Rectangle & rVisArea,const int _nCalledByGroup) const512 rtl::Reference<SdrObject> SwMSDffManager::ImportOLE( sal_uInt32 nOLEId,
513                                       const Graphic& rGrf,
514                                       const tools::Rectangle& rBoundRect,
515                                       const tools::Rectangle& rVisArea,
516                                       const int _nCalledByGroup ) const
517 {
518     // #i32596# - no import of OLE object, if it's inside a group.
519     // NOTE: This can be undone, if grouping of Writer fly frames is possible or
520     // if drawing OLE objects are allowed in Writer.
521     if ( _nCalledByGroup > 0 )
522     {
523         return nullptr;
524     }
525 
526     rtl::Reference<SdrObject> pRet;
527     OUString sStorageName;
528     rtl::Reference<SotStorage> xSrcStg;
529     uno::Reference < embed::XStorage > xDstStg;
530     if( GetOLEStorageName( nOLEId, sStorageName, xSrcStg, xDstStg ))
531     {
532         rtl::Reference<SotStorage> xSrc = xSrcStg->OpenSotStorage(sStorageName);
533         OSL_ENSURE(m_rReader.m_xFormImpl, "No Form Implementation!");
534         css::uno::Reference< css::drawing::XShape > xShape;
535         if ( (!(m_rReader.m_bIsHeader || m_rReader.m_bIsFooter)) &&
536             m_rReader.m_xFormImpl->ReadOCXStream(xSrc,&xShape,true))
537         {
538             pRet = SdrObject::getSdrObjectFromXShape(xShape);
539         }
540         else
541         {
542             ErrCode nError = ERRCODE_NONE;
543             pRet = CreateSdrOLEFromStorage(
544                 *pSdrModel,
545                 sStorageName,
546                 xSrcStg,
547                 xDstStg,
548                 rGrf,
549                 rBoundRect,
550                 rVisArea,
551                 pStData,
552                 nError,
553                 nSvxMSDffOLEConvFlags,
554                 css::embed::Aspects::MSOLE_CONTENT,
555                 m_rReader.GetBaseURL());
556         }
557     }
558     return pRet;
559 }
560 
DisableFallbackStream()561 void SwMSDffManager::DisableFallbackStream()
562 {
563     OSL_ENSURE(!m_pFallbackStream,
564         "if you're recursive, you're broken");
565     m_pFallbackStream = pStData2;
566     m_aOldEscherBlipCache = aEscherBlipCache;
567     aEscherBlipCache.clear();
568     pStData2 = nullptr;
569 }
570 
EnableFallbackStream()571 void SwMSDffManager::EnableFallbackStream()
572 {
573     pStData2 = m_pFallbackStream;
574     aEscherBlipCache = m_aOldEscherBlipCache;
575     m_aOldEscherBlipCache.clear();
576     m_pFallbackStream = nullptr;
577 }
578 
GetToggleAttrFlags() const579 sal_uInt16 SwWW8ImplReader::GetToggleAttrFlags() const
580 {
581     return m_xCtrlStck ? m_xCtrlStck->GetToggleAttrFlags() : 0;
582 }
583 
GetToggleBiDiAttrFlags() const584 sal_uInt16 SwWW8ImplReader::GetToggleBiDiAttrFlags() const
585 {
586     return m_xCtrlStck ? m_xCtrlStck->GetToggleBiDiAttrFlags() : 0;
587 }
588 
SetToggleAttrFlags(sal_uInt16 nFlags)589 void SwWW8ImplReader::SetToggleAttrFlags(sal_uInt16 nFlags)
590 {
591     if (m_xCtrlStck)
592         m_xCtrlStck->SetToggleAttrFlags(nFlags);
593 }
594 
SetToggleBiDiAttrFlags(sal_uInt16 nFlags)595 void SwWW8ImplReader::SetToggleBiDiAttrFlags(sal_uInt16 nFlags)
596 {
597     if (m_xCtrlStck)
598         m_xCtrlStck->SetToggleBiDiAttrFlags(nFlags);
599 }
600 
ProcessObj(SvStream & rSt,DffObjData & rObjData,SvxMSDffClientData & rData,tools::Rectangle & rTextRect,SdrObject * pObj1)601 rtl::Reference<SdrObject> SwMSDffManager::ProcessObj(SvStream& rSt,
602                                        DffObjData& rObjData,
603                                        SvxMSDffClientData& rData,
604                                        tools::Rectangle& rTextRect,
605                                        SdrObject* pObj1
606                                        )
607 {
608     rtl::Reference<SdrObject> pObj = pObj1;
609     if( !rTextRect.IsEmpty() )
610     {
611         SvxMSDffImportData& rImportData = static_cast<SvxMSDffImportData&>(rData);
612         std::unique_ptr<SvxMSDffImportRec> pImpRec(new SvxMSDffImportRec);
613 
614         // fill Import Record with data
615         pImpRec->nShapeId   = rObjData.nShapeId;
616         pImpRec->eShapeType = rObjData.eShapeType;
617 
618         rObjData.bClientAnchor = maShapeRecords.SeekToContent( rSt,
619                                             DFF_msofbtClientAnchor,
620                                             SEEK_FROM_CURRENT_AND_RESTART );
621         if( rObjData.bClientAnchor )
622             ProcessClientAnchor( rSt,
623                     maShapeRecords.Current()->nRecLen,
624                     pImpRec->pClientAnchorBuffer, pImpRec->nClientAnchorLen );
625 
626         rObjData.bClientData = maShapeRecords.SeekToContent( rSt,
627                                             DFF_msofbtClientData,
628                                             SEEK_FROM_CURRENT_AND_RESTART );
629         if( rObjData.bClientData )
630             ProcessClientData( rSt,
631                     maShapeRecords.Current()->nRecLen,
632                     pImpRec->pClientDataBuffer, pImpRec->nClientDataLen );
633 
634         pImpRec->nGroupShapeBooleanProperties = 0;
635 
636         if(    maShapeRecords.SeekToContent( rSt,
637                                              DFF_msofbtUDefProp,
638                                              SEEK_FROM_CURRENT_AND_RESTART )
639             && maShapeRecords.Current()->nRecLen )
640         {
641             sal_uInt32 nBytesLeft = maShapeRecords.Current()->nRecLen;
642             auto nAvailableBytes = rSt.remainingSize();
643             if (nBytesLeft > nAvailableBytes)
644             {
645                 SAL_WARN("sw.ww8", "Document claimed to have shape record of " << nBytesLeft << " bytes, but only " << nAvailableBytes << " available");
646                 nBytesLeft = nAvailableBytes;
647             }
648             while( 5 < nBytesLeft )
649             {
650                 sal_uInt16 nPID(0);
651                 rSt.ReadUInt16(nPID);
652                 sal_uInt32 nUDData(0);
653                 rSt.ReadUInt32(nUDData);
654                 if (!rSt.good())
655                     break;
656                 switch (nPID)
657                 {
658                     case 0x038F: pImpRec->nXAlign = nUDData; break;
659                     case 0x0390:
660                         pImpRec->nXRelTo = nUDData;
661                         break;
662                     case 0x0391: pImpRec->nYAlign = nUDData; break;
663                     case 0x0392:
664                         pImpRec->nYRelTo = nUDData;
665                         break;
666                     case 0x03BF: pImpRec->nGroupShapeBooleanProperties = nUDData; break;
667                     case 0x0393:
668                     // This seems to correspond to o:hrpct from .docx (even including
669                     // the difference that it's in 0.1% even though the .docx spec
670                     // says it's in 1%).
671                         pImpRec->relativeHorizontalWidth = nUDData;
672                         break;
673                     case 0x0394:
674                     // And this is really just a guess, but a mere presence of this
675                     // flag makes a horizontal rule be as wide as the page (unless
676                     // overridden by something), so it probably matches o:hr from .docx.
677                         pImpRec->isHorizontalRule = true;
678                         break;
679                 }
680                 nBytesLeft  -= 6;
681             }
682         }
683 
684         // Text Frame also Title or Outline
685         sal_uInt32 nTextId = GetPropertyValue( DFF_Prop_lTxid, 0 );
686         if( nTextId )
687         {
688             SfxItemSet aSet( pSdrModel->GetItemPool() );
689 
690             // Originally anything that as a mso_sptTextBox was created as a
691             // textbox, this was changed to be created as a simple
692             // rect to keep impress happy. For the rest of us we'd like to turn
693             // it back into a textbox again.
694             bool bIsSimpleDrawingTextBox = (pImpRec->eShapeType == mso_sptTextBox);
695             if (!bIsSimpleDrawingTextBox)
696             {
697                 // Either
698                 // a) it's a simple text object or
699                 // b) it's a rectangle with text and square wrapping.
700                 bIsSimpleDrawingTextBox =
701                 (
702                     (pImpRec->eShapeType == mso_sptTextSimple) ||
703                     (
704                         (pImpRec->eShapeType == mso_sptRectangle)
705                         && ShapeHasText(pImpRec->nShapeId, rObjData.rSpHd.GetRecBegFilePos() )
706                     )
707                 );
708             }
709 
710             // Distance of Textbox to its surrounding Autoshape
711             sal_Int32 nTextLeft = GetPropertyValue( DFF_Prop_dxTextLeft, 91440);
712             sal_Int32 nTextRight = GetPropertyValue( DFF_Prop_dxTextRight, 91440 );
713             sal_Int32 nTextTop = GetPropertyValue( DFF_Prop_dyTextTop, 45720 );
714             sal_Int32 nTextBottom = GetPropertyValue( DFF_Prop_dyTextBottom, 45720 );
715 
716             ScaleEmu( nTextLeft );
717             ScaleEmu( nTextRight );
718             ScaleEmu( nTextTop );
719             ScaleEmu( nTextBottom );
720 
721             Degree100 nTextRotationAngle;
722             bool bVerticalText = false;
723             if ( IsProperty( DFF_Prop_txflTextFlow ) )
724             {
725                 MSO_TextFlow eTextFlow = static_cast<MSO_TextFlow>(GetPropertyValue(
726                     DFF_Prop_txflTextFlow, 0) & 0xFFFF);
727                 switch( eTextFlow )
728                 {
729                     case mso_txflBtoT:
730                         nTextRotationAngle = 9000_deg100;
731                     break;
732                     case mso_txflVertN:
733                     case mso_txflTtoBN:
734                         nTextRotationAngle = 27000_deg100;
735                         break;
736                     case mso_txflTtoBA:
737                         bVerticalText = true;
738                     break;
739                     case mso_txflHorzA:
740                         bVerticalText = true;
741                         nTextRotationAngle = 9000_deg100;
742                     break;
743                     case mso_txflHorzN:
744                     default :
745                         break;
746                 }
747             }
748 
749             if (nTextRotationAngle)
750             {
751                 if (nTextRotationAngle == 9000_deg100)
752                 {
753                     tools::Long nWidth = rTextRect.GetWidth();
754                     rTextRect.SetRight( rTextRect.Left() + rTextRect.GetHeight() );
755                     rTextRect.SetBottom( rTextRect.Top() + nWidth );
756 
757                     sal_Int32 nOldTextLeft = nTextLeft;
758                     sal_Int32 nOldTextRight = nTextRight;
759                     sal_Int32 nOldTextTop = nTextTop;
760                     sal_Int32 nOldTextBottom = nTextBottom;
761 
762                     nTextLeft = nOldTextBottom;
763                     nTextRight = nOldTextTop;
764                     nTextTop = nOldTextLeft;
765                     nTextBottom = nOldTextRight;
766                 }
767                 else if (nTextRotationAngle == 27000_deg100)
768                 {
769                     tools::Long nWidth = rTextRect.GetWidth();
770                     rTextRect.SetRight( rTextRect.Left() + rTextRect.GetHeight() );
771                     rTextRect.SetBottom( rTextRect.Top() + nWidth );
772 
773                     sal_Int32 nOldTextLeft = nTextLeft;
774                     sal_Int32 nOldTextRight = nTextRight;
775                     sal_Int32 nOldTextTop = nTextTop;
776                     sal_Int32 nOldTextBottom = nTextBottom;
777 
778                     nTextLeft = nOldTextTop;
779                     nTextRight = nOldTextBottom;
780                     nTextTop = nOldTextRight;
781                     nTextBottom = nOldTextLeft;
782                 }
783             }
784 
785             if (bIsSimpleDrawingTextBox)
786             {
787                 pObj = new SdrRectObj(
788                     *pSdrModel,
789                     SdrObjKind::Text,
790                     rTextRect);
791             }
792 
793             // The vertical paragraph justification are contained within the
794             // BoundRect so calculate it here
795             tools::Rectangle aNewRect(rTextRect);
796             aNewRect.AdjustBottom( -(nTextTop + nTextBottom) );
797             aNewRect.AdjustRight( -(nTextLeft + nTextRight) );
798 
799             // Only if it's a simple Textbox, Writer can replace the Object
800             // with a Frame, else
801             if( bIsSimpleDrawingTextBox )
802             {
803                 std::shared_ptr<SvxMSDffShapeInfo> const xTmpRec =
804                         std::make_shared<SvxMSDffShapeInfo>(0, pImpRec->nShapeId);
805 
806                 SvxMSDffShapeInfos_ById::const_iterator const it =
807                     GetShapeInfos()->find(xTmpRec);
808                 if (it != GetShapeInfos()->end())
809                 {
810                     SvxMSDffShapeInfo& rInfo = **it;
811                     pImpRec->bReplaceByFly   = rInfo.bReplaceByFly;
812                 }
813 
814                 ApplyAttributes(rSt, aSet, rObjData);
815             }
816 
817             if (GetPropertyValue(DFF_Prop_FitTextToShape, 0) & 2)
818             {
819                 aSet.Put( makeSdrTextAutoGrowHeightItem( true ) );
820                 aSet.Put( makeSdrTextMinFrameHeightItem(
821                     aNewRect.Bottom() - aNewRect.Top() ) );
822                 aSet.Put( makeSdrTextMinFrameWidthItem(
823                     aNewRect.Right() - aNewRect.Left() ) );
824             }
825             else
826             {
827                 aSet.Put( makeSdrTextAutoGrowHeightItem( false ) );
828                 aSet.Put( makeSdrTextAutoGrowWidthItem( false ) );
829             }
830 
831             switch ( static_cast<MSO_WrapMode>(GetPropertyValue( DFF_Prop_WrapText, mso_wrapSquare )) )
832             {
833                 case mso_wrapNone :
834                     aSet.Put( makeSdrTextAutoGrowWidthItem( true ) );
835                     pImpRec->bAutoWidth = true;
836                 break;
837                 case mso_wrapByPoints :
838                     aSet.Put( makeSdrTextContourFrameItem( true ) );
839                 break;
840                 default:
841                     ;
842             }
843 
844             // Set distances on Textbox's margins
845             aSet.Put( makeSdrTextLeftDistItem( nTextLeft ) );
846             aSet.Put( makeSdrTextRightDistItem( nTextRight ) );
847             aSet.Put( makeSdrTextUpperDistItem( nTextTop ) );
848             aSet.Put( makeSdrTextLowerDistItem( nTextBottom ) );
849             pImpRec->nDxTextLeft    = nTextLeft;
850             pImpRec->nDyTextTop     = nTextTop;
851             pImpRec->nDxTextRight   = nTextRight;
852             pImpRec->nDyTextBottom  = nTextBottom;
853 
854             // Taking the correct default (which is mso_anchorTop)
855             sal_uInt32 eTextAnchor =
856                 GetPropertyValue( DFF_Prop_anchorText, mso_anchorTop );
857 
858             SdrTextVertAdjust eTVA = bVerticalText
859                                      ? SDRTEXTVERTADJUST_BLOCK
860                                      : SDRTEXTVERTADJUST_CENTER;
861             SdrTextHorzAdjust eTHA = bVerticalText
862                                      ? SDRTEXTHORZADJUST_CENTER
863                                      : SDRTEXTHORZADJUST_BLOCK;
864 
865             switch( eTextAnchor )
866             {
867                 case mso_anchorTop:
868                 {
869                     if ( bVerticalText )
870                         eTHA = SDRTEXTHORZADJUST_RIGHT;
871                     else
872                         eTVA = SDRTEXTVERTADJUST_TOP;
873                 }
874                 break;
875                 case mso_anchorTopCentered:
876                 {
877                     if ( bVerticalText )
878                         eTHA = SDRTEXTHORZADJUST_RIGHT;
879                     else
880                         eTVA = SDRTEXTVERTADJUST_TOP;
881                 }
882                 break;
883                 case mso_anchorMiddle:
884                 break;
885                 case mso_anchorMiddleCentered:
886                 break;
887                 case mso_anchorBottom:
888                 {
889                     if ( bVerticalText )
890                         eTHA = SDRTEXTHORZADJUST_LEFT;
891                     else
892                         eTVA = SDRTEXTVERTADJUST_BOTTOM;
893                 }
894                 break;
895                 case mso_anchorBottomCentered:
896                 {
897                     if ( bVerticalText )
898                         eTHA = SDRTEXTHORZADJUST_LEFT;
899                     else
900                         eTVA = SDRTEXTVERTADJUST_BOTTOM;
901                 }
902                 break;
903                 default:
904                     ;
905             }
906 
907             aSet.Put( SdrTextVertAdjustItem( eTVA ) );
908             aSet.Put( SdrTextHorzAdjustItem( eTHA ) );
909 
910             if (pObj != nullptr)
911             {
912                 pObj->SetMergedItemSet(aSet);
913 
914                 if (bVerticalText)
915                 {
916                     SdrTextObj *pTextObj = DynCastSdrTextObj(pObj.get());
917                     if (pTextObj)
918                         pTextObj->SetVerticalWriting(true);
919                 }
920 
921                 if ( bIsSimpleDrawingTextBox )
922                 {
923                     if ( nTextRotationAngle )
924                     {
925                         tools::Long nMinWH = rTextRect.GetWidth() < rTextRect.GetHeight() ?
926                             rTextRect.GetWidth() : rTextRect.GetHeight();
927                         nMinWH /= 2;
928                         Point aPivot(rTextRect.TopLeft());
929                         aPivot.AdjustX(nMinWH );
930                         aPivot.AdjustY(nMinWH );
931                         pObj->NbcRotate(aPivot, nTextRotationAngle);
932                     }
933                 }
934 
935                 if ( ( ( rObjData.nSpFlags & ShapeFlag::FlipV ) || mnFix16Angle || nTextRotationAngle ) && dynamic_cast< SdrObjCustomShape* >( pObj.get() ) )
936                 {
937                     SdrObjCustomShape* pCustomShape = dynamic_cast< SdrObjCustomShape* >( pObj.get() );
938                     if (pCustomShape)
939                     {
940                         double fExtraTextRotation = 0.0;
941                         if ( mnFix16Angle && !( GetPropertyValue( DFF_Prop_FitTextToShape, 0 ) & 4 ) )
942                         {   // text is already rotated, we have to take back the object rotation if DFF_Prop_RotateText is false
943                             fExtraTextRotation = -mnFix16Angle.get();
944                         }
945                         if ( rObjData.nSpFlags & ShapeFlag::FlipV )    // sj: in ppt the text is flipped, whereas in word the text
946                         {                                       // remains unchanged, so we have to take back the flipping here
947                             fExtraTextRotation += 18000.0;      // because our core will flip text if the shape is flipped.
948                         }
949                         fExtraTextRotation += nTextRotationAngle.get();
950                         if ( !::basegfx::fTools::equalZero( fExtraTextRotation ) )
951                         {
952                             fExtraTextRotation /= 100.0;
953                             SdrCustomShapeGeometryItem aGeometryItem( pCustomShape->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
954                             css::beans::PropertyValue aPropVal;
955                             aPropVal.Name = "TextRotateAngle";
956                             aPropVal.Value <<= fExtraTextRotation;
957                             aGeometryItem.SetPropertyValue( aPropVal );
958                             pCustomShape->SetMergedItem( aGeometryItem );
959                         }
960                     }
961                 }
962                 else if ( mnFix16Angle )
963                 {
964                     // rotate text with shape ?
965                     pObj->NbcRotate( rObjData.aBoundRect.Center(), mnFix16Angle );
966                 }
967             }
968         }
969         else if( !pObj )
970         {
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);
977 
978             SfxItemSet aSet( pSdrModel->GetItemPool() );
979             ApplyAttributes( rSt, aSet, rObjData );
980 
981             SfxItemState eState = aSet.GetItemState( XATTR_FILLCOLOR, false );
982             if( SfxItemState::DEFAULT == eState )
983                 aSet.Put( XFillColorItem( OUString(), mnDefaultColor ) );
984             pObj->SetMergedItemSet(aSet);
985         }
986 
987         // Means that fBehindDocument is set
988         if (GetPropertyValue(DFF_Prop_fPrint, 0) & 0x20)
989             pImpRec->bDrawHell = true;
990         else
991             pImpRec->bDrawHell = false;
992         if (GetPropertyValue(DFF_Prop_fPrint, 0) & 0x02)
993             pImpRec->bHidden = true;
994         pImpRec->nNextShapeId   = GetPropertyValue( DFF_Prop_hspNext, 0 );
995 
996         if ( nTextId )
997         {
998             pImpRec->aTextId.nTxBxS = o3tl::narrowing<sal_uInt16>( nTextId >> 16 );
999             pImpRec->aTextId.nSequence = o3tl::narrowing<sal_uInt16>(nTextId);
1000         }
1001 
1002         pImpRec->nDxWrapDistLeft = o3tl::convert(GetPropertyValue(DFF_Prop_dxWrapDistLeft, 114935),
1003                                                  o3tl::Length::emu, o3tl::Length::twip);
1004         pImpRec->nDyWrapDistTop = o3tl::convert(GetPropertyValue(DFF_Prop_dyWrapDistTop, 0),
1005                                                 o3tl::Length::emu, o3tl::Length::twip);
1006         pImpRec->nDxWrapDistRight
1007             = o3tl::convert(GetPropertyValue(DFF_Prop_dxWrapDistRight, 114935), o3tl::Length::emu,
1008                             o3tl::Length::twip);
1009         pImpRec->nDyWrapDistBottom = o3tl::convert(GetPropertyValue(DFF_Prop_dyWrapDistBottom, 0),
1010                                                    o3tl::Length::emu, o3tl::Length::twip);
1011         // 16.16 fraction times total image width or height, as appropriate.
1012 
1013         if (SeekToContent(DFF_Prop_pWrapPolygonVertices, rSt))
1014         {
1015             pImpRec->pWrapPolygon.reset();
1016 
1017             sal_uInt16 nNumElemVert(0), nNumElemMemVert(0), nElemSizeVert(0);
1018             rSt.ReadUInt16( nNumElemVert ).ReadUInt16( nNumElemMemVert ).ReadUInt16( nElemSizeVert );
1019             bool bOk = false;
1020             if (nNumElemVert && (nElemSizeVert == 8 || nElemSizeVert == 4))
1021             {
1022                 //check if there is enough data in the file to make the
1023                 //record sane
1024                 // coverity[tainted_data : FALSE] - nElemSizeVert is either 8 or 4 so it has been sanitized
1025                 bOk = rSt.remainingSize() / nElemSizeVert >= nNumElemVert;
1026             }
1027             if (bOk)
1028             {
1029                 pImpRec->pWrapPolygon = tools::Polygon(nNumElemVert);
1030                 for (sal_uInt16 i = 0; i < nNumElemVert; ++i)
1031                 {
1032                     sal_Int32 nX(0), nY(0);
1033                     if (nElemSizeVert == 8)
1034                         rSt.ReadInt32( nX ).ReadInt32( nY );
1035                     else
1036                     {
1037                         sal_Int16 nSmallX(0), nSmallY(0);
1038                         rSt.ReadInt16( nSmallX ).ReadInt16( nSmallY );
1039                         nX = nSmallX;
1040                         nY = nSmallY;
1041                     }
1042                     (*(pImpRec->pWrapPolygon))[i].setX( nX );
1043                     (*(pImpRec->pWrapPolygon))[i].setY( nY );
1044                 }
1045             }
1046         }
1047 
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 );
1056 
1057         sal_uInt32 nLineFlags = GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 );
1058 
1059         if ( !IsHardAttribute( DFF_Prop_fLine ) &&
1060              pImpRec->eShapeType == mso_sptPictureFrame )
1061         {
1062             nLineFlags &= ~0x08;
1063         }
1064 
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 ));
1072 
1073         pImpRec->nFlags = rObjData.nSpFlags;
1074 
1075         if( pImpRec->nShapeId )
1076         {
1077             auto nShapeId = pImpRec->nShapeId;
1078             auto nShapeOrder = (static_cast<sal_uLong>(pImpRec->aTextId.nTxBxS) << 16)
1079                                     + pImpRec->aTextId.nSequence;
1080             // Complement Import Record List
1081             pImpRec->pObj = pObj;
1082             rImportData.insert(std::move(pImpRec));
1083 
1084             // Complement entry in Z Order List with a pointer to this Object
1085             // Only store objects which are not deep inside the tree
1086             if( ( rObjData.nCalledByGroup == 0 )
1087                 ||
1088                 ( (rObjData.nSpFlags & ShapeFlag::Group)
1089                  && (rObjData.nCalledByGroup < 2) )
1090               )
1091             {
1092                 StoreShapeOrder(nShapeId, nShapeOrder, pObj.get());
1093             }
1094         }
1095         else
1096             pImpRec.reset();
1097     }
1098 
1099     sal_uInt32 nBufferSize = GetPropertyValue( DFF_Prop_pihlShape, 0 );
1100     if( (0 < nBufferSize) && (nBufferSize <= 0xFFFF) && SeekToContent( DFF_Prop_pihlShape, rSt ) )
1101     {
1102         SvMemoryStream aMemStream;
1103         struct HyperLinksTable hlStr;
1104         aMemStream.WriteUInt16( 0 ).WriteUInt16( nBufferSize );
1105 
1106         // copy from DFF stream to memory stream
1107         std::vector< sal_uInt8 > aBuffer( nBufferSize );
1108         if (rSt.ReadBytes(aBuffer.data(), nBufferSize) == nBufferSize)
1109         {
1110             aMemStream.WriteBytes(aBuffer.data(), nBufferSize);
1111             sal_uInt64 nStreamSize = aMemStream.TellEnd();
1112             aMemStream.Seek( STREAM_SEEK_TO_BEGIN );
1113             bool bRet = 4 <= nStreamSize;
1114             sal_uInt16 nRawRecId,nRawRecSize;
1115             if( bRet )
1116                 aMemStream.ReadUInt16( nRawRecId ).ReadUInt16( nRawRecSize );
1117             SwDocShell* pDocShell = m_rReader.m_pDocShell;
1118             if (pDocShell)
1119             {
1120                 m_rReader.ReadEmbeddedData(aMemStream, pDocShell, hlStr);
1121             }
1122         }
1123 
1124         if (pObj && !hlStr.hLinkAddr.isEmpty())
1125         {
1126             SwMacroInfo* pInfo = GetMacroInfo( pObj.get() );
1127             if( pInfo )
1128             {
1129                 pInfo->SetShapeId( rObjData.nShapeId );
1130                 pInfo->SetHlink( hlStr.hLinkAddr );
1131                 if (!hlStr.tarFrame.isEmpty())
1132                     pInfo->SetTarFrame( hlStr.tarFrame );
1133                 OUString aNameStr = GetPropertyString( DFF_Prop_wzName, rSt );
1134                 if (!aNameStr.isEmpty())
1135                     pInfo->SetName( aNameStr );
1136             }
1137         }
1138     }
1139 
1140     return pObj;
1141 }
1142 
1143 /**
1144  * Special FastSave - Attributes
1145  */
Read_StyleCode(sal_uInt16,const sal_uInt8 * pData,short nLen)1146 void SwWW8ImplReader::Read_StyleCode( sal_uInt16, const sal_uInt8* pData, short nLen )
1147 {
1148     if (nLen < 0)
1149     {
1150         m_bCpxStyle = false;
1151         return;
1152     }
1153     sal_uInt16 nColl = 0;
1154     if (m_xWwFib->GetFIBVersion() <= ww::eWW2)
1155         nColl = *pData;
1156     else
1157         nColl = SVBT16ToUInt16(pData);
1158     if (nColl < m_vColl.size())
1159     {
1160         SetTextFormatCollAndListLevel( *m_pPaM, m_vColl[nColl] );
1161         m_bCpxStyle = true;
1162     }
1163 }
1164 
1165 /**
1166  * Read_Majority is for Majority (103) and Majority50 (108)
1167  */
Read_Majority(sal_uInt16,const sal_uInt8 *,short)1168 void SwWW8ImplReader::Read_Majority( sal_uInt16, const sal_uInt8* , short )
1169 {
1170 }
1171 
1172 /**
1173  * Stack
1174  */
NewAttr(const SwPosition & rPos,const SfxPoolItem & rAttr)1175 void SwWW8FltControlStack::NewAttr(const SwPosition& rPos,
1176     const SfxPoolItem& rAttr)
1177 {
1178     OSL_ENSURE(RES_TXTATR_FIELD != rAttr.Which(), "probably don't want to put"
1179         "fields into the control stack");
1180     OSL_ENSURE(RES_TXTATR_INPUTFIELD != rAttr.Which(), "probably don't want to put"
1181         "input fields into the control stack");
1182     OSL_ENSURE(RES_TXTATR_ANNOTATION != rAttr.Which(), "probably don't want to put"
1183         "annotations into the control stack");
1184     OSL_ENSURE(RES_FLTR_REDLINE != rAttr.Which(), "probably don't want to put"
1185         "redlines into the control stack");
1186     SwFltControlStack::NewAttr(rPos, rAttr);
1187 }
1188 
SetAttr(const SwPosition & rPos,sal_uInt16 nAttrId,bool bTstEnd,tools::Long nHand,bool)1189 SwFltStackEntry* SwWW8FltControlStack::SetAttr(const SwPosition& rPos, sal_uInt16 nAttrId,
1190     bool bTstEnd, tools::Long nHand, bool )
1191 {
1192     SwFltStackEntry *pRet = nullptr;
1193     // Doing a textbox, and using the control stack only as a temporary
1194     // collection point for properties which will are not to be set into
1195     // the real document
1196     if (m_rReader.m_xPlcxMan && m_rReader.m_xPlcxMan->GetDoingDrawTextBox())
1197     {
1198         size_t nCnt = size();
1199         for (size_t i=0; i < nCnt; ++i)
1200         {
1201             SwFltStackEntry& rEntry = (*this)[i];
1202             if (nAttrId == rEntry.m_pAttr->Which())
1203             {
1204                 DeleteAndDestroy(i--);
1205                 --nCnt;
1206             }
1207         }
1208     }
1209     else // Normal case, set the attribute into the document
1210         pRet = SwFltControlStack::SetAttr(rPos, nAttrId, bTstEnd, nHand);
1211     return pRet;
1212 }
1213 
GetListFirstLineIndent(const SwNumFormat & rFormat)1214 tools::Long GetListFirstLineIndent(const SwNumFormat &rFormat)
1215 {
1216     OSL_ENSURE( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION,
1217             "<GetListFirstLineIndent> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION" );
1218 
1219     SvxAdjust eAdj = rFormat.GetNumAdjust();
1220     tools::Long nReverseListIndented;
1221     if (eAdj == SvxAdjust::Right)
1222         nReverseListIndented = -rFormat.GetCharTextDistance();
1223     else if (eAdj == SvxAdjust::Center)
1224         nReverseListIndented = rFormat.GetFirstLineOffset()/2;
1225     else
1226         nReverseListIndented = rFormat.GetFirstLineOffset();
1227     return nReverseListIndented;
1228 }
1229 
lcl_GetTrueMargin(SvxFirstLineIndentItem const & rFirstLine,SvxTextLeftMarginItem const & rLeftMargin,const SwNumFormat & rFormat,tools::Long & rFirstLinePos)1230 static tools::Long lcl_GetTrueMargin(SvxFirstLineIndentItem const& rFirstLine,
1231         SvxTextLeftMarginItem const& rLeftMargin, const SwNumFormat &rFormat,
1232     tools::Long &rFirstLinePos)
1233 {
1234     OSL_ENSURE( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION,
1235             "<lcl_GetTrueMargin> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION" );
1236 
1237     const tools::Long nBodyIndent = rLeftMargin.GetTextLeft();
1238     const tools::Long nFirstLineDiff = rFirstLine.GetTextFirstLineOffset();
1239     rFirstLinePos = nBodyIndent + nFirstLineDiff;
1240 
1241     const auto nPseudoListBodyIndent = rFormat.GetAbsLSpace();
1242     const tools::Long nReverseListIndented = GetListFirstLineIndent(rFormat);
1243     tools::Long nExtraListIndent = nPseudoListBodyIndent + nReverseListIndented;
1244 
1245     return std::max<tools::Long>(nExtraListIndent, 0);
1246 }
1247 
1248 // #i103711#
1249 // #i105414#
SyncIndentWithList(SvxFirstLineIndentItem & rFirstLine,SvxTextLeftMarginItem & rLeftMargin,const SwNumFormat & rFormat,const bool bFirstLineOfstSet,const bool bLeftIndentSet)1250 void SyncIndentWithList( SvxFirstLineIndentItem & rFirstLine,
1251                          SvxTextLeftMarginItem & rLeftMargin,
1252                          const SwNumFormat &rFormat,
1253                          const bool bFirstLineOfstSet,
1254                          const bool bLeftIndentSet )
1255 {
1256     if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
1257     {
1258         tools::Long nWantedFirstLinePos;
1259         tools::Long nExtraListIndent = lcl_GetTrueMargin(rFirstLine, rLeftMargin, rFormat, nWantedFirstLinePos);
1260         rLeftMargin.SetTextLeft(nWantedFirstLinePos - nExtraListIndent);
1261         rFirstLine.SetTextFirstLineOffset(0);
1262     }
1263     else if ( rFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
1264     {
1265         if ( !bFirstLineOfstSet && bLeftIndentSet &&
1266              rFormat.GetFirstLineIndent() != 0 )
1267         {
1268             rFirstLine.SetTextFirstLineOffset(rFormat.GetFirstLineIndent());
1269         }
1270         else if ( bFirstLineOfstSet && !bLeftIndentSet &&
1271                   rFormat.GetIndentAt() != 0 )
1272         {
1273             rLeftMargin.SetTextLeft(rFormat.GetIndentAt());
1274         }
1275         else if (!bFirstLineOfstSet && !bLeftIndentSet )
1276         {
1277             if ( rFormat.GetFirstLineIndent() != 0 )
1278             {
1279                 rFirstLine.SetTextFirstLineOffset(rFormat.GetFirstLineIndent());
1280             }
1281             if ( rFormat.GetIndentAt() != 0 )
1282             {
1283                 rLeftMargin.SetTextLeft(rFormat.GetIndentAt());
1284             }
1285         }
1286     }
1287 }
1288 
GetNumFormatFromStack(const SwPosition & rPos,const SwTextNode & rTextNode)1289 const SwNumFormat* SwWW8FltControlStack::GetNumFormatFromStack(const SwPosition &rPos,
1290     const SwTextNode &rTextNode)
1291 {
1292     const SwNumFormat *pRet = nullptr;
1293     const SfxPoolItem *pItem = GetStackAttr(rPos, RES_FLTR_NUMRULE);
1294     if (pItem && rTextNode.GetNumRule())
1295     {
1296         if (rTextNode.IsCountedInList())
1297         {
1298             OUString sName(static_cast<const SfxStringItem*>(pItem)->GetValue());
1299             const SwNumRule *pRule = m_rDoc.FindNumRulePtr(sName);
1300             if (pRule)
1301                 pRet = GetNumFormatFromSwNumRuleLevel(*pRule, rTextNode.GetActualListLevel());
1302         }
1303     }
1304     return pRet;
1305 }
1306 
SetAttrInDoc(const SwPosition & rTmpPos,SwFltStackEntry & rEntry)1307 void SwWW8ReferencedFltEndStack::SetAttrInDoc( const SwPosition& rTmpPos,
1308                                                SwFltStackEntry& rEntry )
1309 {
1310     switch( rEntry.m_pAttr->Which() )
1311     {
1312     case RES_FLTR_BOOKMARK:
1313         {
1314             // suppress insertion of bookmark, which is recognized as an internal bookmark used for table-of-content
1315             // and which is not referenced.
1316             bool bInsertBookmarkIntoDoc = true;
1317 
1318             SwFltBookmark* pFltBookmark = dynamic_cast<SwFltBookmark*>(rEntry.m_pAttr.get());
1319             if ( pFltBookmark != nullptr && pFltBookmark->IsTOCBookmark() )
1320             {
1321                 const OUString& rName = pFltBookmark->GetName();
1322                 std::set< OUString, SwWW8::ltstr >::const_iterator aResult = m_aReferencedTOCBookmarks.find(rName);
1323                 if ( aResult == m_aReferencedTOCBookmarks.end() )
1324                 {
1325                     bInsertBookmarkIntoDoc = false;
1326                 }
1327             }
1328             if ( bInsertBookmarkIntoDoc )
1329             {
1330                 SwFltEndStack::SetAttrInDoc( rTmpPos, rEntry );
1331             }
1332             break;
1333         }
1334     default:
1335         SwFltEndStack::SetAttrInDoc( rTmpPos, rEntry );
1336         break;
1337     }
1338 
1339 }
1340 
SetAttrInDoc(const SwPosition & rTmpPos,SwFltStackEntry & rEntry)1341 void SwWW8FltControlStack::SetAttrInDoc(const SwPosition& rTmpPos,
1342     SwFltStackEntry& rEntry)
1343 {
1344     switch (rEntry.m_pAttr->Which())
1345     {
1346         case RES_LR_SPACE:
1347             assert(false);
1348             break;
1349         case RES_MARGIN_FIRSTLINE:
1350         case RES_MARGIN_TEXTLEFT:
1351             {
1352                 /*
1353                  Loop over the affected nodes and
1354                  a) convert the word style absolute indent to indent relative
1355                     to any numbering indent active on the nodes
1356                  b) adjust the writer style tabstops relative to the old
1357                     paragraph indent to be relative to the new paragraph indent
1358                 */
1359                 SwPaM aRegion(rTmpPos);
1360                 if (rEntry.MakeRegion(aRegion, SwFltStackEntry::RegionMode::NoCheck))
1361                 {
1362                     SvxFirstLineIndentItem firstLineNew(RES_MARGIN_FIRSTLINE);
1363                     SvxTextLeftMarginItem leftMarginNew(RES_MARGIN_TEXTLEFT);
1364                     if (rEntry.m_pAttr->Which() == RES_MARGIN_FIRSTLINE)
1365                     {
1366                         SvxFirstLineIndentItem const firstLineEntry(*static_cast<SvxFirstLineIndentItem*>(rEntry.m_pAttr.get()));
1367                         firstLineNew.SetTextFirstLineOffset(firstLineEntry.GetTextFirstLineOffset(), firstLineEntry.GetPropTextFirstLineOffset());
1368                         firstLineNew.SetAutoFirst(firstLineEntry.IsAutoFirst());
1369                     }
1370                     else
1371                     {
1372                         SvxTextLeftMarginItem const leftMarginEntry(*static_cast<SvxTextLeftMarginItem*>(rEntry.m_pAttr.get()));
1373                         leftMarginNew.SetTextLeft(leftMarginEntry.GetTextLeft(), leftMarginEntry.GetPropLeft());
1374                     }
1375                     SwNodeOffset nStart = aRegion.Start()->GetNodeIndex();
1376                     SwNodeOffset nEnd   = aRegion.End()->GetNodeIndex();
1377                     for(; nStart <= nEnd; ++nStart)
1378                     {
1379                         SwNode* pNode = m_rDoc.GetNodes()[ nStart ];
1380                         if (!pNode || !pNode->IsTextNode())
1381                             continue;
1382 
1383                         SwContentNode* pNd = static_cast<SwContentNode*>(pNode);
1384                         SvxFirstLineIndentItem firstLineOld(pNd->GetAttr(RES_MARGIN_FIRSTLINE));
1385                         SvxTextLeftMarginItem leftMarginOld(pNd->GetAttr(RES_MARGIN_TEXTLEFT));
1386                         if (rEntry.m_pAttr->Which() == RES_MARGIN_FIRSTLINE)
1387                         {
1388                             leftMarginNew.SetTextLeft(leftMarginOld.GetTextLeft(), leftMarginOld.GetPropLeft());
1389                         }
1390                         else
1391                         {
1392                             firstLineNew.SetTextFirstLineOffset(firstLineOld.GetTextFirstLineOffset(), firstLineOld.GetPropTextFirstLineOffset());
1393                             firstLineNew.SetAutoFirst(firstLineOld.IsAutoFirst());
1394                         }
1395 
1396                         SwTextNode *pTextNode = static_cast<SwTextNode*>(pNode);
1397 
1398                         const SwNumFormat* pNum
1399                             = GetNumFormatFromStack(*aRegion.GetPoint(), *pTextNode);
1400                         if (!pNum)
1401                         {
1402                             pNum = GetNumFormatFromTextNode(*pTextNode);
1403                         }
1404 
1405                         if ( pNum )
1406                         {
1407                             // #i103711#
1408                             const bool bFirstLineIndentSet =
1409                                 ( m_rReader.m_aTextNodesHavingFirstLineOfstSet.end() !=
1410                                     m_rReader.m_aTextNodesHavingFirstLineOfstSet.find( pNode ) );
1411                             // #i105414#
1412                             const bool bLeftIndentSet =
1413                                 (  m_rReader.m_aTextNodesHavingLeftIndentSet.end() !=
1414                                     m_rReader.m_aTextNodesHavingLeftIndentSet.find( pNode ) );
1415                             SyncIndentWithList(firstLineNew, leftMarginNew, *pNum,
1416                                                 bFirstLineIndentSet,
1417                                                 bLeftIndentSet );
1418                         }
1419 
1420                         if (firstLineNew != firstLineOld)
1421                         {
1422                             if (nStart == aRegion.Start()->GetNodeIndex())
1423                             {
1424                                 pNd->SetAttr(firstLineNew);
1425                             }
1426                         }
1427                         if (leftMarginNew != leftMarginOld)
1428                         {
1429                             pNd->SetAttr(leftMarginNew);
1430                         }
1431                     }
1432                 }
1433             }
1434             break;
1435 
1436         case RES_TXTATR_FIELD:
1437             OSL_ENSURE(false, "What is a field doing in the control stack,"
1438                 "probably should have been in the endstack");
1439             break;
1440 
1441         case RES_TXTATR_ANNOTATION:
1442             OSL_ENSURE(false, "What is an annotation doing in the control stack,"
1443                 "probably should have been in the endstack");
1444             break;
1445 
1446         case RES_TXTATR_INPUTFIELD:
1447             OSL_ENSURE(false, "What is an input field doing in the control stack,"
1448                 "probably should have been in the endstack");
1449             break;
1450 
1451         case RES_TXTATR_INETFMT:
1452             {
1453                 SwPaM aRegion(rTmpPos);
1454                 if (rEntry.MakeRegion(aRegion, SwFltStackEntry::RegionMode::NoCheck))
1455                 {
1456                     SwFrameFormat *pFrame;
1457                     // If we have just one single inline graphic then
1458                     // don't insert a field for the single frame, set
1459                     // the frames hyperlink field attribute directly.
1460                     pFrame = SwWW8ImplReader::ContainsSingleInlineGraphic(aRegion);
1461                     if (nullptr != pFrame)
1462                     {
1463                         const SwFormatINetFormat *pAttr = static_cast<const SwFormatINetFormat *>(
1464                             rEntry.m_pAttr.get());
1465                         SwFormatURL aURL;
1466                         aURL.SetURL(pAttr->GetValue(), false);
1467                         aURL.SetTargetFrameName(pAttr->GetTargetFrame());
1468                         pFrame->SetFormatAttr(aURL);
1469                     }
1470                     else
1471                     {
1472                         m_rDoc.getIDocumentContentOperations().InsertPoolItem(aRegion, *rEntry.m_pAttr);
1473                     }
1474                 }
1475             }
1476             break;
1477         default:
1478             SwFltControlStack::SetAttrInDoc(rTmpPos, rEntry);
1479             break;
1480     }
1481 }
1482 
GetFormatAttr(const SwPosition & rPos,sal_uInt16 nWhich)1483 const SfxPoolItem* SwWW8FltControlStack::GetFormatAttr(const SwPosition& rPos,
1484     sal_uInt16 nWhich)
1485 {
1486     const SfxPoolItem *pItem = GetStackAttr(rPos, nWhich);
1487     if (!pItem)
1488     {
1489         SwContentNode const*const pNd = rPos.GetNode().GetContentNode();
1490         if (!pNd)
1491             pItem = &m_rDoc.GetAttrPool().GetUserOrPoolDefaultItem(nWhich);
1492         else
1493         {
1494             /*
1495             If we're hunting for the indent on a paragraph and need to use the
1496             parent style indent, then return the indent in msword format, and
1497             not writer format, because that's the style that the filter works
1498             in (naturally)
1499             */
1500             if (nWhich == RES_MARGIN_FIRSTLINE
1501                 || nWhich == RES_MARGIN_TEXTLEFT
1502                 || nWhich == RES_MARGIN_RIGHT)
1503             {
1504                 SfxItemState eState = SfxItemState::DEFAULT;
1505                 if (const SfxItemSet *pSet = pNd->GetpSwAttrSet())
1506                     eState = pSet->GetItemState(nWhich, false);
1507                 if (eState != SfxItemState::SET && m_rReader.m_nCurrentColl < m_rReader.m_vColl.size())
1508                 {
1509                     switch (nWhich)
1510                     {
1511                         case RES_MARGIN_FIRSTLINE:
1512                             pItem = m_rReader.m_vColl[m_rReader.m_nCurrentColl].m_pWordFirstLine.get();
1513                             break;
1514                         case RES_MARGIN_TEXTLEFT:
1515                             pItem = m_rReader.m_vColl[m_rReader.m_nCurrentColl].m_pWordLeftMargin.get();
1516                             break;
1517                         case RES_MARGIN_RIGHT:
1518                             pItem = m_rReader.m_vColl[m_rReader.m_nCurrentColl].m_pWordRightMargin.get();
1519                             break;
1520                     }
1521                 }
1522             }
1523 
1524             /*
1525             If we're hunting for a character property, try and exact position
1526             within the text node for lookup
1527             */
1528             if (pNd->IsTextNode())
1529             {
1530                 const sal_Int32 nPos = rPos.GetContentIndex();
1531                 m_xScratchSet.reset(new SfxItemSet(m_rDoc.GetAttrPool(), nWhich, nWhich));
1532                 if (pNd->GetTextNode()->GetParaAttr(*m_xScratchSet, nPos, nPos))
1533                     pItem = m_xScratchSet->GetItem(nWhich);
1534             }
1535 
1536             if (!pItem)
1537                 pItem = &pNd->GetAttr(nWhich);
1538         }
1539     }
1540     return pItem;
1541 }
1542 
GetStackAttr(const SwPosition & rPos,sal_uInt16 nWhich)1543 const SfxPoolItem* SwWW8FltControlStack::GetStackAttr(const SwPosition& rPos,
1544     sal_uInt16 nWhich)
1545 {
1546     SwFltPosition aFltPos(rPos);
1547 
1548     size_t nSize = size();
1549     while (nSize)
1550     {
1551         const SwFltStackEntry& rEntry = (*this)[ --nSize ];
1552         if (rEntry.m_pAttr->Which() == nWhich)
1553         {
1554             if ( (rEntry.m_bOpen) ||
1555                  (
1556                   (rEntry.m_aMkPos.m_nNode <= aFltPos.m_nNode) &&
1557                   (rEntry.m_aPtPos.m_nNode >= aFltPos.m_nNode) &&
1558                   (rEntry.m_aMkPos.m_nContent <= aFltPos.m_nContent) &&
1559                   (rEntry.m_aPtPos.m_nContent > aFltPos.m_nContent)
1560                  )
1561                )
1562                 /*
1563                  * e.g. half-open range [0-3) so asking for properties at 3
1564                  * means props that end at 3 are not included
1565                  */
1566             {
1567                 return rEntry.m_pAttr.get();
1568             }
1569         }
1570     }
1571     return nullptr;
1572 }
1573 
IsFootnoteEdnBkmField(const SwFormatField & rFormatField,sal_uInt16 & rBkmNo)1574 bool SwWW8FltRefStack::IsFootnoteEdnBkmField(
1575     const SwFormatField& rFormatField,
1576     sal_uInt16& rBkmNo)
1577 {
1578     const SwField* pField = rFormatField.GetField();
1579     sal_uInt16 nSubType;
1580     if(pField && (SwFieldIds::GetRef == pField->Which())
1581         && ((REF_FOOTNOTE == (nSubType = pField->GetSubType())) || (REF_ENDNOTE  == nSubType))
1582         && !static_cast<const SwGetRefField*>(pField)->GetSetRefName().isEmpty())
1583     {
1584         const IDocumentMarkAccess* const pMarkAccess = m_rDoc.getIDocumentMarkAccess();
1585         IDocumentMarkAccess::const_iterator_t ppBkmk =
1586             pMarkAccess->findMark( static_cast<const SwGetRefField*>(pField)->GetSetRefName() );
1587         if(ppBkmk != pMarkAccess->getAllMarksEnd())
1588         {
1589             // find Sequence No of corresponding Foot-/Endnote
1590             rBkmNo = ppBkmk - pMarkAccess->getAllMarksBegin();
1591             return true;
1592         }
1593     }
1594     return false;
1595 }
1596 
SetAttrInDoc(const SwPosition & rTmpPos,SwFltStackEntry & rEntry)1597 void SwWW8FltRefStack::SetAttrInDoc(const SwPosition& rTmpPos,
1598     SwFltStackEntry& rEntry)
1599 {
1600     switch (rEntry.m_pAttr->Which())
1601     {
1602         /*
1603         Look up these in our lists of bookmarks that were changed to
1604         variables, and replace the ref field with a var field, otherwise
1605         do normal (?) strange stuff
1606         */
1607         case RES_TXTATR_FIELD:
1608         case RES_TXTATR_ANNOTATION:
1609         case RES_TXTATR_INPUTFIELD:
1610         {
1611             SwPaM aPaM(rEntry.m_aMkPos.m_nNode.GetNode(), SwNodeOffset(1), rEntry.m_aMkPos.m_nContent);
1612 
1613             SwFormatField& rFormatField   = *static_cast<SwFormatField*>(rEntry.m_pAttr.get());
1614             SwField* pField = rFormatField.GetField();
1615 
1616             if (!RefToVar(pField, rEntry))
1617             {
1618                 sal_uInt16 nBkmNo;
1619                 if( IsFootnoteEdnBkmField(rFormatField, nBkmNo) )
1620                 {
1621                     ::sw::mark::IMark const * const pMark = m_rDoc.getIDocumentMarkAccess()->getAllMarksBegin()[nBkmNo];
1622 
1623                     const SwPosition& rBkMrkPos = pMark->GetMarkPos();
1624 
1625                     SwTextNode* pText = rBkMrkPos.GetNode().GetTextNode();
1626                     if( pText && rBkMrkPos.GetContentIndex() )
1627                     {
1628                         SwTextAttr* const pFootnote = pText->GetTextAttrForCharAt(
1629                             rBkMrkPos.GetContentIndex()-1, RES_TXTATR_FTN );
1630                         if( pFootnote )
1631                         {
1632                             sal_uInt16 nRefNo = static_cast<SwTextFootnote*>(pFootnote)->GetSeqRefNo();
1633 
1634                             static_cast<SwGetRefField*>(pField)->SetSeqNo( nRefNo );
1635 
1636                             if( pFootnote->GetFootnote().IsEndNote() )
1637                                 static_cast<SwGetRefField*>(pField)->SetSubType(REF_ENDNOTE);
1638                         }
1639                     }
1640                 }
1641             }
1642 
1643             m_rDoc.getIDocumentContentOperations().InsertPoolItem(aPaM, *rEntry.m_pAttr);
1644             MoveAttrs(*aPaM.GetPoint());
1645         }
1646         break;
1647         case RES_FLTR_TOX:
1648             SwFltEndStack::SetAttrInDoc(rTmpPos, rEntry);
1649             break;
1650         default:
1651         case RES_FLTR_BOOKMARK:
1652             OSL_ENSURE(false, "EndStck used with non field, not what we want");
1653             SwFltEndStack::SetAttrInDoc(rTmpPos, rEntry);
1654             break;
1655     }
1656 }
1657 
1658 /*
1659  For styles we will do our tabstop arithmetic in word style and adjust them to
1660  writer style after all the styles have been finished and the dust settles as
1661  to what affects what.
1662 
1663  For explicit attributes we turn the adjusted writer tabstops back into 0 based
1664  word indexes and we'll turn them back into writer indexes when setting them
1665  into the document. If explicit left indent exist which affects them, then this
1666  is handled when the explicit left indent is set into the document
1667 */
Read_Tab(sal_uInt16,const sal_uInt8 * pData,short nLen)1668 void SwWW8ImplReader::Read_Tab(sal_uInt16 , const sal_uInt8* pData, short nLen)
1669 {
1670     if (nLen < 0)
1671     {
1672         m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_PARATR_TABSTOP);
1673         return;
1674     }
1675 
1676     sal_uInt8 nDel = (nLen > 0) ? pData[0] : 0;
1677     const sal_uInt8* pDel = pData + 1;                   // Del - Array
1678 
1679     sal_uInt8 nIns = (nLen > nDel*2+1) ? pData[nDel*2+1] : 0;
1680     const sal_uInt8* pIns = pData + 2*nDel + 2;          // Ins - Array
1681 
1682     short nRequiredLength = 2 + 2*nDel + 2*nIns + 1*nIns;
1683     if (nRequiredLength > nLen)
1684     {
1685         // would require more data than available to describe!
1686         // discard invalid record
1687         nIns = 0;
1688         nDel = 0;
1689     }
1690 
1691     WW8_TBD const * pTyp = reinterpret_cast<WW8_TBD const *>(pData + 2*nDel + 2*nIns + 2); // Type Array
1692 
1693     std::shared_ptr<SvxTabStopItem> aAttr(std::make_shared<SvxTabStopItem>(0, 0, SvxTabAdjust::Default, RES_PARATR_TABSTOP));
1694 
1695     const SwFormat * pSty = nullptr;
1696     sal_uInt16 nTabBase;
1697     if (m_pCurrentColl && m_nCurrentColl < m_vColl.size()) // StyleDef
1698     {
1699         nTabBase = m_vColl[m_nCurrentColl].m_nBase;
1700         if (nTabBase < m_vColl.size())  // Based On
1701             pSty = m_vColl[nTabBase].m_pFormat;
1702     }
1703     else
1704     { // Text
1705         nTabBase = m_nCurrentColl;
1706         if (m_nCurrentColl < m_vColl.size())
1707             pSty = m_vColl[m_nCurrentColl].m_pFormat;
1708         //TODO: figure out else here
1709     }
1710 
1711     bool bFound = false;
1712     std::unordered_set<size_t> aLoopWatch;
1713     while (pSty && !bFound)
1714     {
1715         const SvxTabStopItem* pTabs;
1716         bFound = pSty->GetAttrSet().GetItemState(RES_PARATR_TABSTOP, false,
1717             &pTabs) == SfxItemState::SET;
1718         if( bFound )
1719         {
1720             aAttr.reset(pTabs->Clone());
1721         }
1722         else
1723         {
1724             sal_uInt16 nOldTabBase = nTabBase;
1725             // If based on another
1726             if (nTabBase < m_vColl.size())
1727                 nTabBase = m_vColl[nTabBase].m_nBase;
1728 
1729             if (
1730                     nTabBase < m_vColl.size() &&
1731                     nOldTabBase != nTabBase &&
1732                     nTabBase != ww::stiNil
1733                )
1734             {
1735                 // #i61789: Stop searching when next style is the same as the
1736                 // current one (prevent loop)
1737                 aLoopWatch.insert(reinterpret_cast<size_t>(pSty));
1738                 if (nTabBase < m_vColl.size())
1739                     pSty = m_vColl[nTabBase].m_pFormat;
1740                 //TODO figure out the else branch
1741 
1742                 if (aLoopWatch.find(reinterpret_cast<size_t>(pSty)) !=
1743                     aLoopWatch.end())
1744                     pSty = nullptr;
1745             }
1746             else
1747                 pSty = nullptr; // Give up on the search
1748         }
1749     }
1750 
1751     SvxTabStop aTabStop;
1752     for (short i=0; i < nDel; ++i)
1753     {
1754         sal_uInt16 nPos = aAttr->GetPos(SVBT16ToUInt16(pDel + i*2));
1755         if( nPos != SVX_TAB_NOTFOUND )
1756             aAttr->Remove( nPos );
1757     }
1758 
1759     for (short i=0; i < nIns; ++i)
1760     {
1761         short nPos = SVBT16ToUInt16(pIns + i*2);
1762         aTabStop.GetTabPos() = nPos;
1763         switch( pTyp[i].aBits1 & 0x7 ) // pTyp[i].jc
1764         {
1765             case 0:
1766                 aTabStop.GetAdjustment() = SvxTabAdjust::Left;
1767                 break;
1768             case 1:
1769                 aTabStop.GetAdjustment() = SvxTabAdjust::Center;
1770                 break;
1771             case 2:
1772                 aTabStop.GetAdjustment() = SvxTabAdjust::Right;
1773                 break;
1774             case 3:
1775                 aTabStop.GetAdjustment() = SvxTabAdjust::Decimal;
1776                 break;
1777             case 4:
1778                 continue; // Ignore Bar
1779         }
1780 
1781         switch( pTyp[i].aBits1 >> 3 & 0x7 )
1782         {
1783             case 0:
1784                 aTabStop.GetFill() = ' ';
1785                 break;
1786             case 1:
1787                 aTabStop.GetFill() = '.';
1788                 break;
1789             case 2:
1790                 aTabStop.GetFill() = '-';
1791                 break;
1792             case 3:
1793             case 4:
1794                 aTabStop.GetFill() = '_';
1795                 break;
1796         }
1797 
1798         sal_uInt16 nPos2 = aAttr->GetPos( nPos );
1799         if (nPos2 != SVX_TAB_NOTFOUND)
1800             aAttr->Remove(nPos2); // Or else Insert() refuses
1801         aAttr->Insert(aTabStop);
1802     }
1803 
1804     if (nIns || nDel)
1805         NewAttr(*aAttr);
1806     else
1807     {
1808         // Here we have a tab definition which inserts no extra tabs, or deletes
1809         // no existing tabs. An older version of writer is probably the creator
1810         // of the document  :-( . So if we are importing a style we can just
1811         // ignore it. But if we are importing into text we cannot as during
1812         // text SwWW8ImplReader::Read_Tab is called at the begin and end of
1813         // the range the attrib affects, and ignoring it would upset the
1814         // balance
1815         if (!m_pCurrentColl) // not importing into a style
1816         {
1817             SvxTabStopItem aOrig = pSty ?
1818                 pSty->GetFormatAttr(RES_PARATR_TABSTOP) :
1819                 m_rDoc.GetAttrPool().GetUserOrPoolDefaultItem(RES_PARATR_TABSTOP);
1820             NewAttr(aOrig);
1821         }
1822     }
1823 }
1824 
1825 /**
1826  * DOP
1827 */
ImportDop()1828 void SwWW8ImplReader::ImportDop()
1829 {
1830     // correct the LastPrinted date in DocumentProperties
1831     uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
1832         m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
1833     uno::Reference<document::XDocumentProperties> xDocuProps(
1834         xDPS->getDocumentProperties());
1835     OSL_ENSURE(xDocuProps.is(), "DocumentProperties is null");
1836     if (xDocuProps.is())
1837     {
1838         DateTime aLastPrinted(
1839             msfilter::util::DTTM2DateTime(m_xWDop->dttmLastPrint));
1840         ::util::DateTime uDT = aLastPrinted.GetUNODateTime();
1841         xDocuProps->setPrintDate(uDT);
1842     }
1843 
1844     // COMPATIBILITY FLAGS START
1845 
1846     // #i78951# - remember the unknown compatibility options
1847     // so as to export them out
1848     m_rDoc.getIDocumentSettingAccess().Setn32DummyCompatibilityOptions1(m_xWDop->GetCompatibilityOptions());
1849     m_rDoc.getIDocumentSettingAccess().Setn32DummyCompatibilityOptions2(m_xWDop->GetCompatibilityOptions2());
1850 
1851     // The distance between two paragraphs is the sum of the bottom distance of
1852     // the first paragraph and the top distance of the second one
1853     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::PARA_SPACE_MAX, m_xWDop->fDontUseHTMLAutoSpacing);
1854     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES, true );
1855     // move tabs on alignment
1856     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TAB_COMPAT, true);
1857     // #i24363# tab stops relative to indent
1858     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TABS_RELATIVE_TO_INDENT, false);
1859     // tdf#117923
1860     m_rDoc.getIDocumentSettingAccess().set(
1861         DocumentSettingId::APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING, true);
1862     m_rDoc.getIDocumentSettingAccess().set(
1863         DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS, true);
1864     // tdf#128195
1865     m_rDoc.getIDocumentSettingAccess().set(
1866         DocumentSettingId::HEADER_SPACING_BELOW_LAST_PARA, true);
1867     m_rDoc.getIDocumentSettingAccess().set(
1868         DocumentSettingId::FRAME_AUTOWIDTH_WITH_MORE_PARA, true);
1869     m_rDoc.getIDocumentSettingAccess().set(
1870         DocumentSettingId::FOOTNOTE_IN_COLUMN_TO_PAGEEND, true);
1871 
1872     // Import Default Tabs
1873     tools::Long nDefTabSiz = m_xWDop->dxaTab;
1874     if( nDefTabSiz < 56 )
1875         nDefTabSiz = 709;
1876 
1877     // We want exactly one DefaultTab
1878     SvxTabStopItem aNewTab( 1, sal_uInt16(nDefTabSiz), SvxTabAdjust::Default, RES_PARATR_TABSTOP );
1879     const_cast<SvxTabStop&>(aNewTab[0]).GetAdjustment() = SvxTabAdjust::Default;
1880 
1881     m_rDoc.GetAttrPool().SetUserDefaultItem( aNewTab );
1882 
1883     // Import zoom factor
1884     if (m_xWDop->wScaleSaved)
1885     {
1886         //Import zoom type
1887         sal_Int16 nZoomType;
1888         switch (m_xWDop->zkSaved) {
1889             case 1:  nZoomType = sal_Int16(SvxZoomType::WHOLEPAGE); break;
1890             case 2:  nZoomType = sal_Int16(SvxZoomType::PAGEWIDTH); break;
1891             case 3:  nZoomType = sal_Int16(SvxZoomType::OPTIMAL);   break;
1892             default: nZoomType = sal_Int16(SvxZoomType::PERCENT);   break;
1893         }
1894         uno::Sequence<beans::PropertyValue> aViewProps( comphelper::InitPropertySequence({
1895                 { "ZoomFactor", uno::Any(sal_Int16(m_xWDop->wScaleSaved)) },
1896                 { "VisibleBottom", uno::Any(sal_Int32(0)) },
1897                 { "ZoomType", uno::Any(nZoomType) }
1898             }));
1899 
1900         rtl::Reference< comphelper::IndexedPropertyValuesContainer > xBox = new comphelper::IndexedPropertyValuesContainer();
1901         xBox->insertByIndex(sal_Int32(0), uno::Any(aViewProps));
1902         uno::Reference<document::XViewDataSupplier> xViewDataSupplier(m_pDocShell->GetModel(), uno::UNO_QUERY);
1903         xViewDataSupplier->setViewData(xBox);
1904     }
1905 
1906     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::USE_VIRTUAL_DEVICE, !m_xWDop->fUsePrinterMetrics);
1907     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::USE_HIRES_VIRTUAL_DEVICE, true);
1908     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::ADD_FLY_OFFSETS, true );
1909 
1910     // No vertical offsets would lead to e.g. overlap of table and fly frames.
1911     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::ADD_VERTICAL_FLY_OFFSETS, true );
1912 
1913     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::ADD_EXT_LEADING, !m_xWDop->fNoLeading);
1914     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::OLD_NUMBERING, false);
1915     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING, false); // #i47448#
1916     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::NO_GAP_AFTER_NOTE_NUMBER, true); // tdf#159382
1917     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK, !m_xWDop->fExpShRtn); // #i49277#, #i56856#
1918     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::DO_NOT_RESET_PARA_ATTRS_FOR_NUM_FONT, false);  // #i53199#
1919     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::OLD_LINE_SPACING, false);
1920 
1921     // #i25901# - set new compatibility option
1922     //      'Add paragraph and table spacing at bottom of table cells'
1923     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS, true);
1924     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::ADD_PARA_LINE_SPACING_TO_TABLE_CELLS, true);
1925 
1926     // #i11860# - set new compatibility option
1927     //      'Use former object positioning' to <false>
1928     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::USE_FORMER_OBJECT_POS, false);
1929 
1930     // #i27767# - set new compatibility option
1931     //      'Consider Wrapping mode when positioning object' to <true>
1932     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION, true);
1933 
1934     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::USE_FORMER_TEXT_WRAPPING, false); // #i13832#, #i24135#
1935 
1936     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TABLE_ROW_KEEP, true); //SetTableRowKeep( true );
1937 
1938     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::IGNORE_TABS_AND_BLANKS_FOR_LINE_CALCULATION, true); // #i3952#
1939 
1940     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::INVERT_BORDER_SPACING, true);
1941     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::COLLAPSE_EMPTY_CELL_PARA, true);
1942     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::UNBREAKABLE_NUMBERINGS, true);
1943     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::CLIPPED_PICTURES, true);
1944     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TAB_OVER_MARGIN, true);
1945     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::SURROUND_TEXT_WRAP_SMALL, true);
1946     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::PROP_LINE_SPACING_SHRINKS_FIRST_LINE, true);
1947     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::CONTINUOUS_ENDNOTES, true);
1948     // rely on default for HYPHENATE_URLS=false
1949     // rely on default for APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH=true
1950 
1951     IDocumentSettingAccess& rIDSA = m_rDoc.getIDocumentSettingAccess();
1952     if (m_xWDop->fDontBreakWrappedTables)
1953     {
1954         rIDSA.set(DocumentSettingId::DO_NOT_BREAK_WRAPPED_TABLES, true);
1955     }
1956 
1957     // COMPATIBILITY FLAGS END
1958 
1959     // Import magic doptypography information, if it's there
1960     if (m_xWwFib->m_nFib > 105)
1961         ImportDopTypography(m_xWDop->doptypography);
1962 
1963     // disable form design mode to be able to use imported controls directly
1964     // #i31239# always disable form design mode, not only in protected docs
1965     uno::Reference<beans::XPropertySet> xDocProps(m_pDocShell->GetModel(), uno::UNO_QUERY);
1966     if (xDocProps.is())
1967     {
1968         uno::Reference<beans::XPropertySetInfo> xInfo = xDocProps->getPropertySetInfo();
1969         if (xInfo.is())
1970         {
1971             if (xInfo->hasPropertyByName(u"ApplyFormDesignMode"_ustr))
1972                 xDocProps->setPropertyValue(u"ApplyFormDesignMode"_ustr, css::uno::Any(false));
1973         }
1974 
1975         // for the benefit of DOCX - if this is ever saved in that format.
1976         comphelper::SequenceAsHashMap aGrabBag(xDocProps->getPropertyValue(u"InteropGrabBag"_ustr));
1977         uno::Sequence<beans::PropertyValue> aCompatSetting( comphelper::InitPropertySequence({
1978                 { "name", uno::Any(u"compatibilityMode"_ustr) },
1979                 { "uri", uno::Any(u"http://schemas.microsoft.com/office/word"_ustr) },
1980                 { "val", uno::Any(u"11"_ustr) }  //11: Use features specified in MS-DOC.
1981         }));
1982 
1983         uno::Sequence< beans::PropertyValue > aValue(comphelper::InitPropertySequence({
1984             { "compatSetting", uno::Any(aCompatSetting) }
1985         }));
1986 
1987         aGrabBag[u"CompatSettings"_ustr] <<= aValue;
1988         xDocProps->setPropertyValue(u"InteropGrabBag"_ustr, uno::Any(aGrabBag.getAsConstPropertyValueList()));
1989     }
1990 
1991     // The password can force read-only, comments-only, fill-in-form-only, or require track-changes.
1992     // Treat comments-only like read-only since Writer has no support for that.
1993     // Still allow editing of form fields, without requiring the password.
1994     // Still allow editing if track-changes is locked on. (Currently LockRev is ignored/lost on export anyway.)
1995     if (!m_xWDop->fProtEnabled && !m_xWDop->fLockRev)
1996         m_pDocShell->SetModifyPasswordHash(m_xWDop->lKeyProtDoc);
1997     else if ( xDocProps.is() )
1998     {
1999         comphelper::SequenceAsHashMap aGrabBag(xDocProps->getPropertyValue(u"InteropGrabBag"_ustr));
2000         aGrabBag[u"FormPasswordHash"_ustr] <<= m_xWDop->lKeyProtDoc;
2001         xDocProps->setPropertyValue(u"InteropGrabBag"_ustr, uno::Any(aGrabBag.getAsConstPropertyValueList()));
2002     }
2003 
2004     if (officecfg::Office::Common::Filter::Microsoft::Import::ImportWWFieldsAsEnhancedFields::get())
2005         m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::PROTECT_FORM, m_xWDop->fProtEnabled );
2006 
2007     if (m_xWDop->iGutterPos)
2008     {
2009         m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::GUTTER_AT_TOP, true);
2010     }
2011 }
2012 
ImportDopTypography(const WW8DopTypography & rTypo)2013 void SwWW8ImplReader::ImportDopTypography(const WW8DopTypography &rTypo)
2014 {
2015     switch (rTypo.m_iLevelOfKinsoku)
2016     {
2017         case 2: // custom
2018             {
2019                 i18n::ForbiddenCharacters aForbidden(OUString(+rTypo.m_rgxchFPunct),
2020                     OUString(+rTypo.m_rgxchLPunct));
2021                     // unary + makes sure not to accidentally call the deleted
2022                     // OUString(ConstCharArrayDetector<...>::TypeUtf16) ctor that takes the full
2023                     // m_rgxchFPunct, m_rgxchLPunct arrays with embedded NULs, instead of just the
2024                     // prefix leading up to the first NUL
2025                 m_rDoc.getIDocumentSettingAccess().setForbiddenCharacters(rTypo.GetConvertedLang(),
2026                         aForbidden);
2027                 // Obviously cannot set the standard level 1 for japanese, so
2028                 // bail out now while we can.
2029                 if (rTypo.GetConvertedLang() == LANGUAGE_JAPANESE)
2030                     return;
2031             }
2032             break;
2033         default:
2034             break;
2035     }
2036 
2037     /*
2038     This MS hack means that level 2 of japanese is not in operation, so we put
2039     in what we know are the MS defaults, there is a complementary reverse
2040     hack in the writer. Its our default as well, but we can set it anyway
2041     as a flag for later.
2042     */
2043     if (!rTypo.m_reserved2)
2044     {
2045         i18n::ForbiddenCharacters aForbidden(WW8DopTypography::JapanNotBeginLevel1,
2046             WW8DopTypography::JapanNotEndLevel1);
2047         m_rDoc.getIDocumentSettingAccess().setForbiddenCharacters(LANGUAGE_JAPANESE,aForbidden);
2048     }
2049 
2050     m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::KERN_ASIAN_PUNCTUATION, bool(rTypo.m_fKerningPunct));
2051     m_rDoc.getIDocumentSettingAccess().setCharacterCompressionType(static_cast<CharCompressType>(rTypo.m_iJustification));
2052 }
2053 
2054 /**
2055  * Footnotes and Endnotes
2056  */
WW8ReaderSave(SwWW8ImplReader * pRdr,WW8_CP nStartCp)2057 WW8ReaderSave::WW8ReaderSave(SwWW8ImplReader* pRdr ,WW8_CP nStartCp) :
2058     mxTmpPos(pRdr->m_rDoc.CreateUnoCursor(*pRdr->m_pPaM->GetPoint())),
2059     mxOldStck(std::move(pRdr->m_xCtrlStck)),
2060     mxOldAnchorStck(std::move(pRdr->m_xAnchorStck)),
2061     mxOldRedlines(std::move(pRdr->m_xRedlineStack)),
2062     mxOldPlcxMan(pRdr->m_xPlcxMan),
2063     mpWFlyPara(std::move(pRdr->m_xWFlyPara)),
2064     mpSFlyPara(std::move(pRdr->m_xSFlyPara)),
2065     mpPreviousNumPaM(pRdr->m_pPreviousNumPaM),
2066     mpPrevNumRule(pRdr->m_pPrevNumRule),
2067     mxTableDesc(std::move(pRdr->m_xTableDesc)),
2068     mnInTable(pRdr->m_nInTable),
2069     mnCurrentColl(pRdr->m_nCurrentColl),
2070     mcSymbol(pRdr->m_cSymbol),
2071     mbIgnoreText(pRdr->m_bIgnoreText),
2072     mbSymbol(pRdr->m_bSymbol),
2073     mbHdFtFootnoteEdn(pRdr->m_bHdFtFootnoteEdn),
2074     mbTxbxFlySection(pRdr->m_bTxbxFlySection),
2075     mbAnl(pRdr->m_bAnl),
2076     mbInHyperlink(pRdr->m_bInHyperlink),
2077     mbPgSecBreak(pRdr->m_bPgSecBreak),
2078     mbWasParaEnd(pRdr->m_bWasParaEnd),
2079     mbHasBorder(pRdr->m_bHasBorder),
2080     mbFirstPara(pRdr->m_bFirstPara)
2081 {
2082     pRdr->m_bSymbol = false;
2083     pRdr->m_bHdFtFootnoteEdn = true;
2084     pRdr->m_bTxbxFlySection = pRdr->m_bAnl = pRdr->m_bPgSecBreak = pRdr->m_bWasParaEnd
2085         = pRdr->m_bHasBorder = false;
2086     pRdr->m_bFirstPara = true;
2087     pRdr->m_nInTable = 0;
2088     pRdr->m_pPreviousNumPaM = nullptr;
2089     pRdr->m_pPrevNumRule = nullptr;
2090     pRdr->m_nCurrentColl = 0;
2091 
2092     pRdr->m_xCtrlStck.reset(new SwWW8FltControlStack(pRdr->m_rDoc, pRdr->m_nFieldFlags,
2093         *pRdr));
2094 
2095     pRdr->m_xRedlineStack.reset(new sw::util::RedlineStack(pRdr->m_rDoc));
2096 
2097     pRdr->m_xAnchorStck.reset(new SwWW8FltAnchorStack(pRdr->m_rDoc, pRdr->m_nFieldFlags));
2098 
2099     // Save the attribute manager: we need this as the newly created PLCFx Manager
2100     // access the same FKPs as the old one and their Start-End position changes.
2101     if (pRdr->m_xPlcxMan)
2102         pRdr->m_xPlcxMan->SaveAllPLCFx(maPLCFxSave);
2103 
2104     if (nStartCp != -1)
2105     {
2106         pRdr->m_xPlcxMan = std::make_shared<WW8PLCFMan>(pRdr->m_xSBase.get(),
2107             mxOldPlcxMan->GetManType(), nStartCp);
2108     }
2109 
2110     maOldApos.push_back(false);
2111     maOldApos.swap(pRdr->m_aApos);
2112     maOldFieldStack.swap(pRdr->m_aFieldStack);
2113 }
2114 
Restore(SwWW8ImplReader * pRdr)2115 void WW8ReaderSave::Restore( SwWW8ImplReader* pRdr )
2116 {
2117     pRdr->m_xWFlyPara = std::move(mpWFlyPara);
2118     pRdr->m_xSFlyPara = std::move(mpSFlyPara);
2119     pRdr->m_pPreviousNumPaM = mpPreviousNumPaM;
2120     pRdr->m_pPrevNumRule = mpPrevNumRule;
2121     pRdr->m_xTableDesc = std::move(mxTableDesc);
2122     pRdr->m_cSymbol = mcSymbol;
2123     pRdr->m_bSymbol = mbSymbol;
2124     pRdr->m_bIgnoreText = mbIgnoreText;
2125     pRdr->m_bHdFtFootnoteEdn = mbHdFtFootnoteEdn;
2126     pRdr->m_bTxbxFlySection = mbTxbxFlySection;
2127     pRdr->m_nInTable = mnInTable;
2128     pRdr->m_bAnl = mbAnl;
2129     pRdr->m_bInHyperlink = mbInHyperlink;
2130     pRdr->m_bWasParaEnd = mbWasParaEnd;
2131     pRdr->m_bPgSecBreak = mbPgSecBreak;
2132     pRdr->m_nCurrentColl = mnCurrentColl;
2133     pRdr->m_bHasBorder = mbHasBorder;
2134     pRdr->m_bFirstPara = mbFirstPara;
2135 
2136     // Close all attributes as attributes could be created that extend the Fly
2137     pRdr->DeleteCtrlStack();
2138     pRdr->m_xCtrlStck = std::move(mxOldStck);
2139 
2140     pRdr->m_xRedlineStack->closeall(*pRdr->m_pPaM->GetPoint());
2141 
2142     // ofz#37322 drop m_oLastAnchorPos during RedlineStack dtor and restore it afterwards to the same
2143     // place, or somewhere close if that place got destroyed
2144     std::shared_ptr<SwUnoCursor> xLastAnchorCursor(pRdr->m_oLastAnchorPos ? pRdr->m_rDoc.CreateUnoCursor(*pRdr->m_oLastAnchorPos) : nullptr);
2145     pRdr->m_oLastAnchorPos.reset();
2146 
2147     pRdr->m_xRedlineStack = std::move(mxOldRedlines);
2148 
2149     if (xLastAnchorCursor)
2150         pRdr->m_oLastAnchorPos.emplace(*xLastAnchorCursor->GetPoint());
2151 
2152     pRdr->DeleteAnchorStack();
2153     pRdr->m_xAnchorStck = std::move(mxOldAnchorStck);
2154 
2155     *pRdr->m_pPaM->GetPoint() = GetStartPos();
2156 
2157     if (mxOldPlcxMan != pRdr->m_xPlcxMan)
2158         pRdr->m_xPlcxMan = mxOldPlcxMan;
2159     if (pRdr->m_xPlcxMan)
2160         pRdr->m_xPlcxMan->RestoreAllPLCFx(maPLCFxSave);
2161     pRdr->m_aApos.swap(maOldApos);
2162     pRdr->m_aFieldStack.swap(maOldFieldStack);
2163 }
2164 
Read_HdFtFootnoteText(const SwNodeIndex * pSttIdx,WW8_CP nStartCp,WW8_CP nLen,ManTypes nType)2165 void SwWW8ImplReader::Read_HdFtFootnoteText( const SwNodeIndex* pSttIdx,
2166     WW8_CP nStartCp, WW8_CP nLen, ManTypes nType )
2167 {
2168     if (nStartCp < 0 || nLen < 0)
2169         return;
2170 
2171     // Saves Flags (amongst other things) and resets them
2172     WW8ReaderSave aSave( this );
2173 
2174     m_pPaM->GetPoint()->Assign( pSttIdx->GetIndex() + 1 );
2175 
2176     // Read Text for Header, Footer or Footnote
2177     ReadText( nStartCp, nLen, nType ); // Ignore Sepx when doing so
2178     aSave.Restore( this );
2179 }
2180 
2181 /**
2182  * Use authornames, if not available fall back to initials.
2183  */
Read_And(WW8PLCFManResult * pRes)2184 tools::Long SwWW8ImplReader::Read_And(WW8PLCFManResult* pRes)
2185 {
2186     WW8PLCFx_SubDoc* pSD = m_xPlcxMan->GetAtn();
2187     if (!pSD)
2188         return 0;
2189 
2190     const void* pData = pSD->GetData();
2191     if (!pData)
2192         return 0;
2193 
2194     OUString sAuthor;
2195     OUString sInitials;
2196     if( m_bVer67 )
2197     {
2198         const WW67_ATRD* pDescri = static_cast<const WW67_ATRD*>(pData);
2199         const OUString* pA = GetAnnotationAuthor(SVBT16ToUInt16(pDescri->ibst));
2200         if (pA)
2201             sAuthor = *pA;
2202         else
2203         {
2204             const sal_uInt8 nLen = std::min<sal_uInt8>(pDescri->xstUsrInitl[0],
2205                                                        SAL_N_ELEMENTS(pDescri->xstUsrInitl)-1);
2206             sAuthor = OUString(pDescri->xstUsrInitl + 1, nLen, RTL_TEXTENCODING_MS_1252);
2207         }
2208     }
2209     else
2210     {
2211         const WW8_ATRD* pDescri = static_cast<const WW8_ATRD*>(pData);
2212         {
2213             const sal_uInt16 nLen = std::min<sal_uInt16>(SVBT16ToUInt16(pDescri->xstUsrInitl[0]),
2214                                                          SAL_N_ELEMENTS(pDescri->xstUsrInitl)-1);
2215             OUStringBuffer aBuf;
2216             aBuf.setLength(nLen);
2217             for(sal_uInt16 nIdx = 1; nIdx <= nLen; ++nIdx)
2218                 aBuf[nIdx-1] = SVBT16ToUInt16(pDescri->xstUsrInitl[nIdx]);
2219             sInitials = aBuf.makeStringAndClear();
2220         }
2221 
2222         if (const OUString* pA = GetAnnotationAuthor(SVBT16ToUInt16(pDescri->ibst)))
2223             sAuthor = *pA;
2224         else
2225             sAuthor = sInitials;
2226     }
2227 
2228     sal_uInt32 nDateTime = 0;
2229 
2230     if (sal_uInt8 * pExtended = m_xPlcxMan->GetExtendedAtrds()) // Word < 2002 has no date data for comments
2231     {
2232         sal_uLong nIndex = pSD->GetIdx() & 0xFFFF; // Index is (stupidly) multiplexed for WW8PLCFx_SubDocs
2233         if (m_xWwFib->m_lcbAtrdExtra/18 > nIndex)
2234             nDateTime = SVBT32ToUInt32(*reinterpret_cast<SVBT32*>(pExtended+(nIndex*18)));
2235     }
2236 
2237     DateTime aDate = msfilter::util::DTTM2DateTime(nDateTime);
2238 
2239     OUString sText;
2240     std::optional<OutlinerParaObject> pOutliner = ImportAsOutliner( sText, pRes->nCp2OrIdx,
2241         pRes->nCp2OrIdx + pRes->nMemLen, MAN_AND );
2242 
2243     m_xFormatOfJustInsertedApo.reset();
2244     SwPostItField aPostIt(
2245         static_cast<SwPostItFieldType*>(m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Postit)), sAuthor,
2246         sText, sInitials, OUString(), aDate );
2247     aPostIt.SetTextObject(std::move(pOutliner));
2248 
2249     SwPaM aEnd(*m_pPaM->End(), *m_pPaM->End());
2250     m_xCtrlStck->NewAttr(*aEnd.GetPoint(), SvxCharHiddenItem(false, RES_CHRATR_HIDDEN));
2251     m_rDoc.getIDocumentContentOperations().InsertPoolItem(aEnd, SwFormatField(aPostIt));
2252     m_xCtrlStck->SetAttr(*aEnd.GetPoint(), RES_CHRATR_HIDDEN);
2253     // If this is a range, make sure that it ends after the just inserted character, not before it.
2254     m_xReffedStck->MoveAttrs(*aEnd.GetPoint(), SwFltControlStack::MoveAttrsMode::POSTIT_INSERTED);
2255 
2256     return 0;
2257 }
2258 
Read_HdFtTextAsHackedFrame(WW8_CP nStart,WW8_CP nLen,SwFrameFormat const & rHdFtFormat,sal_uInt16 nPageWidth)2259 void SwWW8ImplReader::Read_HdFtTextAsHackedFrame(WW8_CP nStart, WW8_CP nLen,
2260     SwFrameFormat const &rHdFtFormat, sal_uInt16 nPageWidth)
2261 {
2262     const SwNodeIndex* pSttIdx = rHdFtFormat.GetContent().GetContentIdx();
2263     OSL_ENSURE(pSttIdx, "impossible");
2264     if (!pSttIdx)
2265         return;
2266 
2267     SwPosition aTmpPos(*m_pPaM->GetPoint());
2268 
2269     m_pPaM->GetPoint()->Assign( pSttIdx->GetIndex() + 1 );
2270 
2271     // tdf#122425: Explicitly remove borders and spacing
2272     SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END - 1> aFlySet(m_rDoc.GetAttrPool());
2273     Reader::ResetFrameFormatAttrs(aFlySet);
2274 
2275     SwFlyFrameFormat* pFrame
2276         = m_rDoc.MakeFlySection(RndStdIds::FLY_AT_PARA, m_pPaM->GetPoint(), &aFlySet);
2277 
2278     SwFormatAnchor aAnch( pFrame->GetAnchor() );
2279     aAnch.SetType( RndStdIds::FLY_AT_PARA );
2280     pFrame->SetFormatAttr( aAnch );
2281     SwFormatFrameSize aSz(SwFrameSize::Minimum, nPageWidth, MINLAY);
2282     SwFrameSize eFrameSize = SwFrameSize::Minimum;
2283     if( eFrameSize != aSz.GetWidthSizeType() )
2284         aSz.SetWidthSizeType( eFrameSize );
2285     pFrame->SetFormatAttr(aSz);
2286     pFrame->SetFormatAttr(SwFormatSurround(css::text::WrapTextMode_THROUGH));
2287     pFrame->SetFormatAttr(SwFormatHoriOrient(0, text::HoriOrientation::LEFT)); //iFOO
2288 
2289     // #i43427# - send frame for header/footer into background.
2290     pFrame->SetFormatAttr( SvxOpaqueItem( RES_OPAQUE, false ) );
2291     SdrObject* pFrameObj = CreateContactObject( pFrame );
2292     OSL_ENSURE( pFrameObj,
2293             "<SwWW8ImplReader::Read_HdFtTextAsHackedFrame(..)> - missing SdrObject instance" );
2294     if ( pFrameObj )
2295     {
2296         pFrameObj->SetOrdNum( 0 );
2297     }
2298     MoveInsideFly(pFrame);
2299 
2300     const SwNodeIndex* pHackIdx = pFrame->GetContent().GetContentIdx();
2301 
2302     Read_HdFtFootnoteText(pHackIdx, nStart, nLen - 1, MAN_HDFT);
2303 
2304     MoveOutsideFly(pFrame, aTmpPos);
2305 }
2306 
Read_HdFtText(WW8_CP nStart,WW8_CP nLen,SwFrameFormat const * pHdFtFormat)2307 void SwWW8ImplReader::Read_HdFtText(WW8_CP nStart, WW8_CP nLen, SwFrameFormat const * pHdFtFormat)
2308 {
2309     const SwNodeIndex* pSttIdx = pHdFtFormat->GetContent().GetContentIdx();
2310     if (!pSttIdx)
2311         return;
2312 
2313     SwPosition aTmpPos( *m_pPaM->GetPoint() ); // Remember old cursor position
2314 
2315     Read_HdFtFootnoteText(pSttIdx, nStart, nLen - 1, MAN_HDFT);
2316 
2317     *m_pPaM->GetPoint() = std::move(aTmpPos);
2318 }
2319 
isValid_HdFt_CP(WW8_CP nHeaderCP) const2320 bool SwWW8ImplReader::isValid_HdFt_CP(WW8_CP nHeaderCP) const
2321 {
2322     // Each CP of Plcfhdd MUST be less than FibRgLw97.ccpHdd
2323     return (nHeaderCP < m_xWwFib->m_ccpHdr && nHeaderCP >= 0);
2324 }
2325 
HasOwnHeaderFooter(sal_uInt8 nWhichItems,sal_uInt8 grpfIhdt,int nSect)2326 bool SwWW8ImplReader::HasOwnHeaderFooter(sal_uInt8 nWhichItems, sal_uInt8 grpfIhdt,
2327     int nSect)
2328 {
2329     if (m_xHdFt)
2330     {
2331         WW8_CP nStart, nLen;
2332         sal_uInt8 nNumber = 5;
2333 
2334         for( sal_uInt8 nI = 0x20; nI; nI >>= 1, nNumber-- )
2335         {
2336             if (nI & nWhichItems)
2337             {
2338                 bool bOk = true;
2339                 if( m_bVer67 )
2340                     bOk = ( m_xHdFt->GetTextPos(grpfIhdt, nI, nStart, nLen ) && nStart >= 0 && nLen >= 2 );
2341                 else
2342                 {
2343                     m_xHdFt->GetTextPosExact( static_cast< short >(nNumber + (nSect+1)*6), nStart, nLen);
2344                     bOk = ( 2 <= nLen ) && isValid_HdFt_CP(nStart);
2345                 }
2346 
2347                 if (bOk)
2348                     return true;
2349             }
2350         }
2351     }
2352     return false;
2353 }
2354 
Read_HdFt(int nSect,const SwPageDesc * pPrev,const wwSection & rSection)2355 void SwWW8ImplReader::Read_HdFt(int nSect, const SwPageDesc *pPrev,
2356     const wwSection &rSection)
2357 {
2358     sal_uInt8 grpfIhdt = rSection.maSep.grpfIhdt;
2359     SwPageDesc *pPD = rSection.mpPage;
2360 
2361     if( !m_xHdFt )
2362         return;
2363 
2364     WW8_CP nStart, nLen;
2365     sal_uInt8 nNumber = 5;
2366 
2367     // This loops through the 6 flags WW8_{FOOTER,HEADER}_{ODD,EVEN,FIRST}
2368     // corresponding to bit fields in grpfIhdt indicating which
2369     // header/footer(s) are present in this section
2370     for( sal_uInt8 nI = 0x20; nI; nI >>= 1, nNumber-- )
2371     {
2372         if (nI & grpfIhdt)
2373         {
2374             bool bOk = true;
2375             if( m_bVer67 )
2376                 bOk = ( m_xHdFt->GetTextPos(grpfIhdt, nI, nStart, nLen ) && nLen >= 2 );
2377             else
2378             {
2379                 m_xHdFt->GetTextPosExact( static_cast< short >(nNumber + (nSect+1)*6), nStart, nLen);
2380                 bOk = ( 2 <= nLen ) && isValid_HdFt_CP(nStart);
2381             }
2382 
2383             bool bUseLeft
2384                 = (nI & ( WW8_HEADER_EVEN | WW8_FOOTER_EVEN )) != 0;
2385             bool bUseFirst
2386                 = (nI & ( WW8_HEADER_FIRST | WW8_FOOTER_FIRST )) != 0;
2387 
2388             // If we are loading a first-page header/footer which is not
2389             // actually enabled in this section (it still needs to be
2390             // loaded as it may be inherited by a later section)
2391             bool bDisabledFirst = bUseFirst && !rSection.HasTitlePage();
2392 
2393             bool bFooter
2394                 = (nI & ( WW8_FOOTER_EVEN | WW8_FOOTER_ODD | WW8_FOOTER_FIRST )) != 0;
2395 
2396             SwFrameFormat& rFormat = bUseLeft ? pPD->GetLeft()
2397                 : bUseFirst ? pPD->GetFirstMaster()
2398                 : pPD->GetMaster();
2399 
2400             SwFrameFormat* pHdFtFormat;
2401             // If we have empty first page header and footer.
2402             bool bNoFirst = !(grpfIhdt & WW8_HEADER_FIRST) && !(grpfIhdt & WW8_FOOTER_FIRST);
2403             if (bFooter)
2404             {
2405                 m_bIsFooter = true;
2406                 //#i17196# Cannot have left without right
2407                 if (!bDisabledFirst
2408                         && !pPD->GetMaster().GetFooter().GetFooterFormat())
2409                     pPD->GetMaster().SetFormatAttr(SwFormatFooter(true));
2410                 if (bUseLeft)
2411                     pPD->GetLeft().SetFormatAttr(SwFormatFooter(true));
2412                 if (bUseFirst || (rSection.maSep.fTitlePage && bNoFirst))
2413                     pPD->GetFirstMaster().SetFormatAttr(SwFormatFooter(true));
2414                 pHdFtFormat = const_cast<SwFrameFormat*>(rFormat.GetFooter().GetFooterFormat());
2415             }
2416             else
2417             {
2418                 m_bIsHeader = true;
2419                 //#i17196# Cannot have left without right
2420                 if (!bDisabledFirst
2421                         && !pPD->GetMaster().GetHeader().GetHeaderFormat())
2422                     pPD->GetMaster().SetFormatAttr(SwFormatHeader(true));
2423                 if (bUseLeft)
2424                     pPD->GetLeft().SetFormatAttr(SwFormatHeader(true));
2425                 if (bUseFirst || (rSection.maSep.fTitlePage && bNoFirst))
2426                     pPD->GetFirstMaster().SetFormatAttr(SwFormatHeader(true));
2427                 pHdFtFormat = const_cast<SwFrameFormat*>(rFormat.GetHeader().GetHeaderFormat());
2428             }
2429 
2430             if (bOk)
2431             {
2432                 bool bHackRequired = false;
2433                 if (m_bIsHeader && rSection.IsFixedHeightHeader())
2434                     bHackRequired = true;
2435                 else if (m_bIsFooter && rSection.IsFixedHeightFooter())
2436                     bHackRequired = true;
2437 
2438                 if (bHackRequired)
2439                 {
2440                     Read_HdFtTextAsHackedFrame(nStart, nLen, *pHdFtFormat,
2441                         static_cast< sal_uInt16 >(rSection.GetTextAreaWidth()) );
2442                 }
2443                 else
2444                     Read_HdFtText(nStart, nLen, pHdFtFormat);
2445             }
2446             else if (pPrev)
2447                 CopyPageDescHdFt(pPrev, pPD, nI);
2448 
2449             m_bIsHeader = m_bIsFooter = false;
2450         }
2451     }
2452 }
2453 
SectionIsProtected(const wwSection & rSection) const2454 bool wwSectionManager::SectionIsProtected(const wwSection &rSection) const
2455 {
2456     return ( mrReader.m_xWDop->fProtEnabled && !rSection.IsNotProtected() );
2457 }
2458 
SetHdFt(wwSection const & rSection,int nSect,const wwSection * pPrevious)2459 void wwSectionManager::SetHdFt(wwSection const &rSection, int nSect,
2460     const wwSection *pPrevious)
2461 {
2462     // Header/Footer not present
2463     if (!rSection.maSep.grpfIhdt)
2464         return;
2465 
2466     OSL_ENSURE(rSection.mpPage, "makes no sense to call with a main page");
2467     if (rSection.mpPage)
2468     {
2469         mrReader.Read_HdFt(nSect, pPrevious ? pPrevious->mpPage : nullptr,
2470                 rSection);
2471     }
2472 
2473     // Header/Footer - Update Index
2474     // So that the index is still valid later on
2475     if (mrReader.m_xHdFt)
2476         mrReader.m_xHdFt->UpdateIndex(rSection.maSep.grpfIhdt);
2477 
2478 }
2479 
FinalizeTextNode(SwPosition & rPos,bool bAddNew)2480 void SwWW8ImplReader::FinalizeTextNode(SwPosition& rPos, bool bAddNew)
2481 {
2482     SwTextNode* pText = m_pPaM->GetPointNode().GetTextNode();
2483 
2484     const SwNumRule* pRule = nullptr;
2485 
2486     if (pText != nullptr)
2487         pRule = sw::util::GetNumRuleFromTextNode(*pText);
2488 
2489     // tdf#64222 / tdf#150613 filter out the "paragraph marker" formatting and
2490     // set it as a separate paragraph property, just like we do for DOCX.
2491     // This is only being used for numbering currently, so limiting to that context.
2492     if (pRule)
2493     {
2494         SfxItemSetFixed<RES_CHRATR_BEGIN, RES_CHRATR_END - 1, RES_TXTATR_CHARFMT,
2495                         RES_TXTATR_CHARFMT, RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END - 1>
2496             items(m_pPaM->GetDoc().GetAttrPool());
2497 
2498         SfxWhichIter aIter(items);
2499         for (sal_uInt16 nWhich = aIter.FirstWhich(); nWhich; nWhich = aIter.NextWhich())
2500         {
2501             const SfxPoolItem* pItem = m_xCtrlStck->GetStackAttr(rPos, nWhich);
2502             if (pItem)
2503                 items.Put(*pItem);
2504         }
2505         SwFormatAutoFormat item(RES_PARATR_LIST_AUTOFMT);
2506         item.SetStyleHandle(std::make_shared<SfxItemSet>(items));
2507         pText->SetAttr(item);
2508     }
2509 
2510     if (
2511          pRule && !m_xWDop->fDontUseHTMLAutoSpacing &&
2512          (m_bParaAutoBefore || m_bParaAutoAfter)
2513        )
2514     {
2515         // If after spacing is set to auto, set the after space to 0
2516         if (m_bParaAutoAfter)
2517             SetLowerSpacing(*m_pPaM, 0);
2518 
2519         // If the previous textnode had numbering and
2520         // and before spacing is set to auto, set before space to 0
2521         if(m_pPrevNumRule && m_bParaAutoBefore)
2522             SetUpperSpacing(*m_pPaM, 0);
2523 
2524         // If the previous numbering rule was different we need
2525         // to insert a space after the previous paragraph
2526         if((pRule != m_pPrevNumRule) && m_pPreviousNumPaM)
2527             SetLowerSpacing(*m_pPreviousNumPaM, GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
2528 
2529         // cache current paragraph
2530         if(m_pPreviousNumPaM)
2531         {
2532             delete m_pPreviousNumPaM;
2533             m_pPreviousNumPaM = nullptr;
2534         }
2535 
2536         m_pPreviousNumPaM = new SwPaM(*m_pPaM, m_pPaM);
2537         m_pPrevNumRule = pRule;
2538     }
2539     else if(!pRule && m_pPreviousNumPaM)
2540     {
2541         // If the previous paragraph has numbering but the current one does not
2542         // we need to add a space after the previous paragraph
2543         SetLowerSpacing(*m_pPreviousNumPaM, GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
2544         delete m_pPreviousNumPaM;
2545         m_pPreviousNumPaM = nullptr;
2546         m_pPrevNumRule = nullptr;
2547     }
2548     else
2549     {
2550         // clear paragraph cache
2551         if(m_pPreviousNumPaM)
2552         {
2553             delete m_pPreviousNumPaM;
2554             m_pPreviousNumPaM = nullptr;
2555         }
2556         m_pPrevNumRule = pRule;
2557     }
2558 
2559     // If this is the first paragraph in the document and
2560     // Auto-spacing before paragraph is set,
2561     // set the upper spacing value to 0
2562     if(m_bParaAutoBefore && m_bFirstPara && !m_xWDop->fDontUseHTMLAutoSpacing)
2563         SetUpperSpacing(*m_pPaM, 0);
2564 
2565     m_bFirstPara = false;
2566 
2567     if (bAddNew)
2568         m_rDoc.getIDocumentContentOperations().AppendTextNode(rPos);
2569 
2570     // We can flush all anchored graphics at the end of a paragraph.
2571     m_xAnchorStck->Flush();
2572 }
2573 
SetSpacing(SwPaM & rMyPam,int nSpace,bool bIsUpper)2574 bool SwWW8ImplReader::SetSpacing(SwPaM &rMyPam, int nSpace, bool bIsUpper )
2575 {
2576         bool bRet = false;
2577         const SwPosition* pSpacingPos = rMyPam.GetPoint();
2578 
2579         const SvxULSpaceItem* pULSpaceItem = m_xCtrlStck->GetFormatAttr(*pSpacingPos, RES_UL_SPACE);
2580 
2581         if(pULSpaceItem != nullptr)
2582         {
2583             SvxULSpaceItem aUL(*pULSpaceItem);
2584 
2585             if(bIsUpper)
2586                 aUL.SetUpper( static_cast< sal_uInt16 >(nSpace) );
2587             else
2588                 aUL.SetLower( static_cast< sal_uInt16 >(nSpace) );
2589 
2590             const sal_Int32 nEnd = pSpacingPos->GetContentIndex();
2591             rMyPam.GetPoint()->SetContent(0);
2592             m_xCtrlStck->NewAttr(*pSpacingPos, aUL);
2593             rMyPam.GetPoint()->SetContent(nEnd);
2594             m_xCtrlStck->SetAttr(*pSpacingPos, RES_UL_SPACE);
2595             bRet = true;
2596         }
2597         return bRet;
2598 }
2599 
SetLowerSpacing(SwPaM & rMyPam,int nSpace)2600 bool SwWW8ImplReader::SetLowerSpacing(SwPaM &rMyPam, int nSpace)
2601 {
2602     return SetSpacing(rMyPam, nSpace, false);
2603 }
2604 
SetUpperSpacing(SwPaM & rMyPam,int nSpace)2605 bool SwWW8ImplReader::SetUpperSpacing(SwPaM &rMyPam, int nSpace)
2606 {
2607     return SetSpacing(rMyPam, nSpace, true);
2608 }
2609 
TabRowSprm(int nLevel) const2610 sal_uInt16 SwWW8ImplReader::TabRowSprm(int nLevel) const
2611 {
2612     if (m_bVer67)
2613         return NS_sprm::v6::sprmPTtp;
2614     return nLevel ? NS_sprm::PFInnerTtp::val : NS_sprm::PFTtp::val;
2615 }
2616 
EndSpecial()2617 void SwWW8ImplReader::EndSpecial()
2618 {
2619     // Frame/Table/Anl
2620     if (m_bAnl)
2621         StopAllAnl(); // -> bAnl = false
2622 
2623     while(m_aApos.size() > 1)
2624     {
2625         StopTable();
2626         m_aApos.pop_back();
2627         --m_nInTable;
2628         if (m_aApos[m_nInTable])
2629             StopApo();
2630     }
2631 
2632     if (m_aApos[0])
2633         StopApo();
2634 
2635     OSL_ENSURE(!m_nInTable, "unclosed table!");
2636 }
2637 
ProcessSpecial(bool & rbReSync,WW8_CP nStartCp)2638 bool SwWW8ImplReader::ProcessSpecial(bool &rbReSync, WW8_CP nStartCp)
2639 {
2640     // Frame/Table/Anl
2641     if (m_bInHyperlink)
2642         return false;
2643 
2644     rbReSync = false;
2645 
2646     OSL_ENSURE(m_nInTable >= 0,"nInTable < 0!");
2647 
2648     // TabRowEnd
2649     bool bTableRowEnd = (m_xPlcxMan->HasParaSprm(m_bVer67 ? 25 : 0x2417).pSprm != nullptr);
2650 
2651 // Unfortunately, for every paragraph we need to check first whether
2652 // they contain a sprm 29 (0x261B), which starts an APO.
2653 // All other sprms then refer to that APO and not to the normal text
2654 // surrounding it.
2655 // The same holds true for a Table (sprm 24 (0x2416)) and Anls (sprm 13).
2656 
2657 // WW: Table in APO is possible (Both Start-Ends occur at the same time)
2658 // WW: APO in Table not possible
2659 
2660 // This mean that of a Table is the content of an APO, the APO start needs
2661 // to be edited first, so that the Table remains in the APO and not the
2662 // other way around.
2663 // At the End, however, we need to edit the Table End first as the APO
2664 // must end after that Table (or else we never find the APO End).
2665 
2666 // The same holds true for Fly / Anl, Tab / Anl, Fly / Tab / Anl.
2667 
2668 // If the Table is within an APO the TabRowEnd Area misses the
2669 // APO settings.
2670 // To not end the APO there, we do not call ProcessApo
2671 
2672 // KHZ: When there is a table inside the Apo the Apo-flags are also
2673 //      missing for the 2nd, 3rd... paragraphs of each cell.
2674 
2675 //  1st look for in-table flag, for 2000+ there is a subtable flag to
2676 //  be considered, the sprm 6649 gives the level of the table
2677     sal_uInt8 nCellLevel = 0;
2678 
2679     if (m_bVer67)
2680         nCellLevel = int(nullptr != m_xPlcxMan->HasParaSprm(24).pSprm);
2681     else
2682     {
2683         nCellLevel = int(nullptr != m_xPlcxMan->HasParaSprm(0x2416).pSprm);
2684         if (!nCellLevel)
2685             nCellLevel = int(nullptr != m_xPlcxMan->HasParaSprm(0x244B).pSprm);
2686     }
2687     do
2688     {
2689         WW8_TablePos *pTabPos=nullptr;
2690         WW8_TablePos aTabPos;
2691         if(nCellLevel && !m_bVer67)
2692         {
2693             WW8PLCFxSave1 aSave;
2694             m_xPlcxMan->GetPap()->Save( aSave );
2695             rbReSync = true;
2696             WW8PLCFx_Cp_FKP* pPap = m_xPlcxMan->GetPapPLCF();
2697             WW8_CP nMyStartCp=nStartCp;
2698 
2699             SprmResult aLevel = m_xPlcxMan->HasParaSprm(0x6649);
2700             if (aLevel.pSprm && aLevel.nRemainingData >= 1)
2701                 nCellLevel = *aLevel.pSprm;
2702 
2703             bool bHasRowEnd = SearchRowEnd(pPap, nMyStartCp, (m_nInTable<nCellLevel?m_nInTable:nCellLevel-1));
2704 
2705             // Bad Table, remain unchanged in level, e.g. #i19667#
2706             if (!bHasRowEnd)
2707                 nCellLevel = static_cast< sal_uInt8 >(m_nInTable);
2708 
2709             if (bHasRowEnd && ParseTabPos(&aTabPos,pPap))
2710                 pTabPos = &aTabPos;
2711 
2712             m_xPlcxMan->GetPap()->Restore( aSave );
2713         }
2714 
2715         // Then look if we are in an Apo
2716 
2717         ApoTestResults aApo = TestApo(nCellLevel, bTableRowEnd, pTabPos);
2718 
2719         // Look to see if we are in a Table, but Table in foot/end note not allowed
2720         bool bStartTab = (m_nInTable < nCellLevel) && !m_bFootnoteEdn;
2721 
2722         bool bStopTab = m_bWasTabRowEnd && (m_nInTable > nCellLevel) && !m_bFootnoteEdn;
2723 
2724         m_bWasTabRowEnd = false;  // must be deactivated right here to prevent next
2725                                 // WW8TabDesc::TableCellEnd() from making nonsense
2726 
2727         if (m_nInTable && !bTableRowEnd && !bStopTab && (m_nInTable == nCellLevel && aApo.HasStartStop()))
2728             bStopTab = bStartTab = true; // Required to stop and start table
2729 
2730         //  Test for Anl (Numbering) and process all events in the right order
2731         if( m_bAnl && !bTableRowEnd )
2732         {
2733             SprmResult aSprm13 = m_xPlcxMan->HasParaSprm(13);
2734             const sal_uInt8* pSprm13 = aSprm13.pSprm;
2735             if (pSprm13 && aSprm13.nRemainingData >= 1)
2736             {   // Still Anl left?
2737                 sal_uInt8 nT = static_cast< sal_uInt8 >(GetNumType( *pSprm13 ));
2738                 if( ( nT != WW8_Pause && nT != m_nWwNumType ) // Anl change
2739                     || aApo.HasStartStop()                  // Forced Anl end
2740                     || bStopTab || bStartTab )
2741                 {
2742                     StopAnlToRestart(nT);  // Anl-Restart (= change) over sprms
2743                 }
2744                 else
2745                 {
2746                     NextAnlLine( pSprm13 ); // Next Anl Line
2747                 }
2748             }
2749             else
2750             {   // Regular Anl end
2751                 StopAllAnl(); // Actual end
2752             }
2753         }
2754         if (bStopTab)
2755         {
2756             StopTable();
2757             m_aApos.pop_back();
2758             --m_nInTable;
2759         }
2760         if (aApo.mbStopApo)
2761         {
2762             StopApo();
2763             m_aApos[m_nInTable] = false;
2764         }
2765 
2766         if (aApo.mbStartApo)
2767         {
2768             m_aApos[m_nInTable] = StartApo(aApo, pTabPos);
2769             // We need an ReSync after StartApo
2770             // (actually only if the Apo extends past a FKP border)
2771             rbReSync = true;
2772         }
2773         if (bStartTab)
2774         {
2775             WW8PLCFxSave1 aSave;
2776             m_xPlcxMan->GetPap()->Save( aSave );
2777 
2778             // Numbering for cell borders causes a crash -> no Anls in Tables
2779             if (m_bAnl)
2780                StopAllAnl();
2781 
2782             if(m_nInTable < nCellLevel)
2783             {
2784                 if (StartTable(nStartCp))
2785                     ++m_nInTable;
2786                 else
2787                     break;
2788                 m_aApos.push_back(false);
2789             }
2790 
2791             if(m_nInTable >= nCellLevel)
2792             {
2793                 // We need an ReSync after StartTable
2794                 // (actually only if the Apo extends past a FKP border)
2795                 rbReSync = true;
2796                 m_xPlcxMan->GetPap()->Restore( aSave );
2797             }
2798         }
2799     } while (!m_bFootnoteEdn && (m_nInTable < nCellLevel));
2800     return bTableRowEnd;
2801 }
2802 
GetCharSetFromLanguage()2803 rtl_TextEncoding SwWW8ImplReader::GetCharSetFromLanguage()
2804 {
2805     /*
2806      #i22206#/#i52786#
2807      The (default) character set used for a run of text is the default
2808      character set for the version of Word that last saved the document.
2809 
2810      This is a bit tentative, more might be required if the concept is correct.
2811      When later version of word write older 6/95 documents the charset is
2812      correctly set in the character runs involved, so it's hard to reproduce
2813      documents that require this to be sure of the process involved.
2814     */
2815     const SvxLanguageItem *pLang = GetFormatAttr(RES_CHRATR_LANGUAGE);
2816     LanguageType eLang = pLang ? pLang->GetLanguage() : LANGUAGE_SYSTEM;
2817     css::lang::Locale aLocale(LanguageTag::convertToLocale(eLang));
2818     return msfilter::util::getBestTextEncodingFromLocale(aLocale);
2819 }
2820 
GetCJKCharSetFromLanguage()2821 rtl_TextEncoding SwWW8ImplReader::GetCJKCharSetFromLanguage()
2822 {
2823     /*
2824      #i22206#/#i52786#
2825      The (default) character set used for a run of text is the default
2826      character set for the version of Word that last saved the document.
2827 
2828      This is a bit tentative, more might be required if the concept is correct.
2829      When later version of word write older 6/95 documents the charset is
2830      correctly set in the character runs involved, so it's hard to reproduce
2831      documents that require this to be sure of the process involved.
2832     */
2833     const SvxLanguageItem *pLang = GetFormatAttr(RES_CHRATR_CJK_LANGUAGE);
2834     LanguageType eLang = pLang ? pLang->GetLanguage() : LANGUAGE_SYSTEM;
2835     css::lang::Locale aLocale(LanguageTag::convertToLocale(eLang));
2836     return msfilter::util::getBestTextEncodingFromLocale(aLocale);
2837 }
2838 
GetCurrentCharSet()2839 rtl_TextEncoding SwWW8ImplReader::GetCurrentCharSet()
2840 {
2841     /*
2842     #i2015
2843     If the hard charset is set use it, if not see if there is an open
2844     character run that has set the charset, if not then fallback to the
2845     current underlying paragraph style.
2846     */
2847     rtl_TextEncoding eSrcCharSet = m_eHardCharSet;
2848     if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2849     {
2850         if (!m_bVer67)
2851             eSrcCharSet = GetCharSetFromLanguage();
2852         else if (!m_aFontSrcCharSets.empty())
2853             eSrcCharSet = m_aFontSrcCharSets.top();
2854         if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && m_nCharFormat >= 0 && o3tl::make_unsigned(m_nCharFormat) < m_vColl.size() )
2855             eSrcCharSet = m_vColl[m_nCharFormat].GetCharSet();
2856         if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && StyleExists(m_nCurrentColl) && m_nCurrentColl < m_vColl.size())
2857             eSrcCharSet = m_vColl[m_nCurrentColl].GetCharSet();
2858         if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2859             eSrcCharSet = GetCharSetFromLanguage();
2860     }
2861     return eSrcCharSet;
2862 }
2863 
2864 //Takashi Ono for CJK
GetCurrentCJKCharSet()2865 rtl_TextEncoding SwWW8ImplReader::GetCurrentCJKCharSet()
2866 {
2867     /*
2868     #i2015
2869     If the hard charset is set use it, if not see if there is an open
2870     character run that has set the charset, if not then fallback to the
2871     current underlying paragraph style.
2872     */
2873     rtl_TextEncoding eSrcCharSet = m_eHardCharSet;
2874     if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2875     {
2876         if (!m_aFontSrcCJKCharSets.empty())
2877             eSrcCharSet = m_aFontSrcCJKCharSets.top();
2878         if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && m_nCharFormat >= 0 && o3tl::make_unsigned(m_nCharFormat) < m_vColl.size() )
2879             eSrcCharSet = m_vColl[m_nCharFormat].GetCJKCharSet();
2880         if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW && StyleExists(m_nCurrentColl) && m_nCurrentColl < m_vColl.size())
2881             eSrcCharSet = m_vColl[m_nCurrentColl].GetCJKCharSet();
2882         if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2883             eSrcCharSet = GetCJKCharSetFromLanguage();
2884     }
2885     return eSrcCharSet;
2886 }
2887 
PostProcessAttrs()2888 void SwWW8ImplReader::PostProcessAttrs()
2889 {
2890     if (m_pPostProcessAttrsInfo == nullptr)
2891         return;
2892 
2893     SfxItemIter aIter(m_pPostProcessAttrsInfo->mItemSet);
2894 
2895     for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
2896     {
2897         m_xCtrlStck->NewAttr(*m_pPostProcessAttrsInfo->mPaM.GetPoint(),
2898                            *pItem);
2899         m_xCtrlStck->SetAttr(*m_pPostProcessAttrsInfo->mPaM.GetMark(),
2900                            pItem->Which());
2901     }
2902 
2903     m_pPostProcessAttrsInfo.reset();
2904 }
2905 
2906 /*
2907  #i9240#
2908  It appears that some documents that are in a baltic 8 bit encoding which has
2909  some undefined characters can have use made of those characters, in which
2910  case they default to CP1252. If not then it's perhaps that the font encoding
2911  is only in use for 6/7 and for 8+ if we are in 8bit mode then the encoding
2912  is always 1252.
2913 
2914  So an encoding converter that on an undefined character attempts to
2915  convert from 1252 on the undefined character
2916 */
Custom8BitToUnicode(rtl_TextToUnicodeConverter hConverter,char const * pIn,std::size_t nInLen,sal_Unicode * pOut,std::size_t nOutLen)2917 static std::size_t Custom8BitToUnicode(rtl_TextToUnicodeConverter hConverter,
2918     char const *pIn, std::size_t nInLen, sal_Unicode *pOut, std::size_t nOutLen)
2919 {
2920     const sal_uInt32 nFlags =
2921         RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
2922         RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
2923         RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE |
2924         RTL_TEXTTOUNICODE_FLAGS_FLUSH;
2925 
2926     const sal_uInt32 nFlags2 =
2927         RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE |
2928         RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_IGNORE |
2929         RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE |
2930         RTL_TEXTTOUNICODE_FLAGS_FLUSH;
2931 
2932     std::size_t nDestChars=0;
2933     std::size_t nConverted=0;
2934 
2935     do
2936     {
2937         sal_uInt32 nInfo = 0;
2938         sal_Size nThisConverted=0;
2939 
2940         nDestChars += rtl_convertTextToUnicode(hConverter, nullptr,
2941             pIn+nConverted, nInLen-nConverted,
2942             pOut+nDestChars, nOutLen-nDestChars,
2943             nFlags, &nInfo, &nThisConverted);
2944 
2945         OSL_ENSURE(nInfo == 0, "A character conversion failed!");
2946 
2947         nConverted += nThisConverted;
2948 
2949         if (
2950             nInfo & RTL_TEXTTOUNICODE_INFO_UNDEFINED ||
2951             nInfo & RTL_TEXTTOUNICODE_INFO_MBUNDEFINED
2952            )
2953         {
2954             sal_Size nOtherConverted;
2955             rtl_TextToUnicodeConverter hCP1252Converter =
2956                 rtl_createTextToUnicodeConverter(RTL_TEXTENCODING_MS_1252);
2957             nDestChars += rtl_convertTextToUnicode(hCP1252Converter, nullptr,
2958                 pIn+nConverted, 1,
2959                 pOut+nDestChars, nOutLen-nDestChars,
2960                 nFlags2, &nInfo, &nOtherConverted);
2961             rtl_destroyTextToUnicodeConverter(hCP1252Converter);
2962             nConverted+=1;
2963         }
2964     } while (nConverted < nInLen);
2965 
2966     return nDestChars;
2967 }
2968 
LangUsesHindiNumbers(LanguageType nLang)2969 bool SwWW8ImplReader::LangUsesHindiNumbers(LanguageType nLang)
2970 {
2971     bool bResult = false;
2972 
2973     switch (static_cast<sal_uInt16>(nLang))
2974     {
2975         case 0x1401: // Arabic(Algeria)
2976         case 0x3c01: // Arabic(Bahrain)
2977         case 0xc01: // Arabic(Egypt)
2978         case 0x801: // Arabic(Iraq)
2979         case 0x2c01: // Arabic (Jordan)
2980         case 0x3401: // Arabic(Kuwait)
2981         case 0x3001: // Arabic(Lebanon)
2982         case 0x1001: // Arabic(Libya)
2983         case 0x1801: // Arabic(Morocco)
2984         case 0x2001: // Arabic(Oman)
2985         case 0x4001: // Arabic(Qatar)
2986         case 0x401: // Arabic(Saudi Arabia)
2987         case 0x2801: // Arabic(Syria)
2988         case 0x1c01: // Arabic(Tunisia)
2989         case 0x3801: // Arabic(U.A.E)
2990         case 0x2401: // Arabic(Yemen)
2991             bResult = true;
2992             break;
2993         default:
2994             break;
2995     }
2996 
2997     return bResult;
2998 }
2999 
TranslateToHindiNumbers(sal_Unicode nChar)3000 sal_Unicode SwWW8ImplReader::TranslateToHindiNumbers(sal_Unicode nChar)
3001 {
3002     if (nChar >= 0x0030 && nChar <= 0x0039)
3003         return nChar + 0x0630;
3004 
3005     return nChar;
3006 }
3007 
3008 namespace
3009 {
makeOUString(rtl_uString * pStr,sal_Int32 nAllocLen)3010     OUString makeOUString(rtl_uString *pStr, sal_Int32 nAllocLen)
3011     {
3012         //if read len was in or around that of allocated len, just reuse pStr
3013         if (nAllocLen < pStr->length + 256)
3014             return OUString(pStr, SAL_NO_ACQUIRE);
3015         //otherwise copy the shorter used section to release extra mem
3016         OUString sRet(pStr->buffer, pStr->length);
3017         rtl_uString_release(pStr);
3018         return sRet;
3019     }
3020 }
3021 
3022 /**
3023  * Return value: true for non special chars
3024  */
ReadPlainChars(WW8_CP & rPos,sal_Int32 nEnd,sal_Int32 nCpOfs)3025 bool SwWW8ImplReader::ReadPlainChars(WW8_CP& rPos, sal_Int32 nEnd, sal_Int32 nCpOfs)
3026 {
3027     sal_Int32 nRequestedStrLen = nEnd - rPos;
3028 
3029     OSL_ENSURE(nRequestedStrLen, "String is 0");
3030     if (nRequestedStrLen <= 0)
3031         return true;
3032 
3033     WW8_CP nCp;
3034     const bool bFail = o3tl::checked_add(nCpOfs, rPos, nCp);
3035     if (bFail)
3036     {
3037         rPos+=nRequestedStrLen;
3038         return true;
3039     }
3040 
3041     sal_Int32 nRequestedPos = m_xSBase->WW8Cp2Fc(nCp, &m_bIsUnicode);
3042     bool bValidPos = checkSeek(*m_pStrm, nRequestedPos);
3043     OSL_ENSURE(bValidPos, "Document claimed to have more text than available");
3044     if (!bValidPos)
3045     {
3046         // Swallow missing range, e.g. #i95550#
3047         rPos+=nRequestedStrLen;
3048         return true;
3049     }
3050 
3051     std::size_t nAvailableStrLen = m_pStrm->remainingSize() / (m_bIsUnicode ? 2 : 1);
3052     OSL_ENSURE(nAvailableStrLen, "Document claimed to have more text than available");
3053     if (!nAvailableStrLen)
3054     {
3055         // Swallow missing range, e.g. #i95550#
3056         rPos+=nRequestedStrLen;
3057         return true;
3058     }
3059 
3060     sal_Int32 nValidStrLen = std::min<std::size_t>(nRequestedStrLen, nAvailableStrLen);
3061 
3062     // Reset Unicode flag and correct FilePos if needed.
3063     // Note: Seek is not expensive, as we're checking inline whether or not
3064     // the correct FilePos has already been reached.
3065     const sal_Int32 nStrLen = std::min(nValidStrLen, SAL_MAX_INT32-1);
3066 
3067     rtl_TextEncoding eSrcCharSet = m_bVer67 ? GetCurrentCharSet() :
3068         RTL_TEXTENCODING_MS_1252;
3069     if (m_bVer67 && eSrcCharSet == RTL_TEXTENCODING_MS_932)
3070     {
3071         /*
3072          fdo#82904
3073 
3074          Older documents exported as word 95 that use unicode aware fonts will
3075          have the charset of those fonts set to RTL_TEXTENCODING_MS_932 on
3076          export as the conversion from RTL_TEXTENCODING_UNICODE. This is a serious
3077          pain.
3078 
3079          We will try and use a fallback encoding if the conversion from
3080          RTL_TEXTENCODING_MS_932 fails, but you can get unlucky and get a document
3081          which isn't really in RTL_TEXTENCODING_MS_932 but parts of it form
3082          valid RTL_TEXTENCODING_MS_932 by chance :-(
3083 
3084          We're not the only ones that struggle with this: Here's the help from
3085          MSOffice 2003 on the topic:
3086 
3087          <<
3088           Earlier versions of Microsoft Word were sometimes used in conjunction with
3089           third-party language-processing add-in programs designed to support Chinese or
3090           Korean on English versions of Microsoft Windows. Use of these add-ins sometimes
3091           results in incorrect text display in more recent versions of Word.
3092 
3093           However, you can set options to convert these documents so that text is
3094           displayed correctly. On the Tools menu, click Options, and then click the
3095           General tab. In the English Word 6.0/95 documents list, select Contain Asian
3096           text (to have Word interpret the text as Asian code page data, regardless of
3097           its font) or Automatically detect Asian text (to have Word attempt to determine
3098           which parts of the text are meant to be Asian).
3099         >>
3100 
3101         What we can try here is to ignore a RTL_TEXTENCODING_MS_932 codepage if
3102         the language is not Japanese
3103         */
3104 
3105         const SvxLanguageItem * pItem = GetFormatAttr(RES_CHRATR_CJK_LANGUAGE);
3106         if (pItem != nullptr && LANGUAGE_JAPANESE != pItem->GetLanguage())
3107         {
3108             SAL_WARN("sw.ww8", "discarding word95 RTL_TEXTENCODING_MS_932 encoding");
3109             eSrcCharSet = GetCharSetFromLanguage();
3110         }
3111     }
3112     const rtl_TextEncoding eSrcCJKCharSet = m_bVer67 ? GetCurrentCJKCharSet() :
3113         RTL_TEXTENCODING_MS_1252;
3114 
3115     // allocate unicode string data
3116     auto l = [](rtl_uString* p){rtl_uString_release(p);};
3117     std::unique_ptr<rtl_uString, decltype(l)> xStr(rtl_uString_alloc(nStrLen), l);
3118     sal_Unicode* pBuffer = xStr->buffer;
3119     sal_Unicode* pWork = pBuffer;
3120 
3121     std::unique_ptr<char[]> p8Bits;
3122 
3123     rtl_TextToUnicodeConverter hConverter = nullptr;
3124     if (!m_bIsUnicode || m_bVer67)
3125         hConverter = rtl_createTextToUnicodeConverter(eSrcCharSet);
3126 
3127     if (!m_bIsUnicode)
3128         p8Bits.reset( new char[nStrLen] );
3129 
3130     // read the stream data
3131     sal_uInt8   nBCode = 0;
3132     sal_uInt16 nUCode;
3133 
3134     LanguageType nCTLLang = LANGUAGE_SYSTEM;
3135     const SvxLanguageItem * pItem = GetFormatAttr(RES_CHRATR_CTL_LANGUAGE);
3136     if (pItem != nullptr)
3137         nCTLLang = pItem->GetLanguage();
3138 
3139     sal_Int32 nL2;
3140     for (nL2 = 0; nL2 < nStrLen; ++nL2)
3141     {
3142         if (m_bIsUnicode)
3143             m_pStrm->ReadUInt16( nUCode ); // unicode  --> read 2 bytes
3144         else
3145         {
3146             m_pStrm->ReadUChar( nBCode ); // old code --> read 1 byte
3147             nUCode = nBCode;
3148         }
3149 
3150         if (!m_pStrm->good())
3151         {
3152             rPos = WW8_CP_MAX-10; // -> eof or other error
3153             return true;
3154         }
3155 
3156         if ((32 > nUCode) || (0xa0 == nUCode))
3157         {
3158             m_pStrm->SeekRel( m_bIsUnicode ? -2 : -1 );
3159             break; // Special character < 32, == 0xa0 found
3160         }
3161 
3162         if (m_bIsUnicode)
3163         {
3164             if (!m_bVer67)
3165                 *pWork++ = nUCode;
3166             else
3167             {
3168                 if (nUCode >= 0x3000) //0x8000 ?
3169                 {
3170                     char aTest[2];
3171                     aTest[0] = static_cast< char >((nUCode & 0xFF00) >> 8);
3172                     aTest[1] = static_cast< char >(nUCode & 0x00FF);
3173                     OUString aTemp(aTest, 2, eSrcCJKCharSet);
3174                     OSL_ENSURE(aTemp.getLength() == 1, "so much for that theory");
3175                     *pWork++ = aTemp[0];
3176                 }
3177                 else
3178                 {
3179                     char cTest = static_cast< char >(nUCode & 0x00FF);
3180                     pWork += Custom8BitToUnicode(hConverter, &cTest, 1, pWork, 1);
3181                 }
3182             }
3183         }
3184         else
3185             p8Bits[nL2] = nBCode;
3186     }
3187 
3188     if (nL2)
3189     {
3190         const sal_Int32 nEndUsed = !m_bIsUnicode
3191             ? Custom8BitToUnicode(hConverter, p8Bits.get(), nL2, pBuffer, nStrLen)
3192             : pWork - pBuffer;
3193 
3194         if (m_bRegardHindiDigits && m_bBidi && LangUsesHindiNumbers(nCTLLang))
3195         {
3196             for (sal_Int32 nI = 0; nI < nEndUsed; ++nI, ++pBuffer)
3197                 *pBuffer = TranslateToHindiNumbers(*pBuffer);
3198         }
3199 
3200         xStr->buffer[nEndUsed] = 0;
3201         xStr->length = nEndUsed;
3202 
3203         emulateMSWordAddTextToParagraph(makeOUString(xStr.release(), nStrLen));
3204         rPos += nL2;
3205         if (!m_aApos.back()) // a para end in apo doesn't count
3206             m_bWasParaEnd = false; // No CR
3207     }
3208 
3209     if (hConverter)
3210         rtl_destroyTextToUnicodeConverter(hConverter);
3211     return nL2 >= nStrLen;
3212 }
3213 
3214 #define MSASCII SAL_MAX_INT16
3215 
3216 namespace
3217 {
3218     // We want to force weak chars inside 0x0020 to 0x007F to LATIN
lcl_getScriptType(const uno::Reference<i18n::XBreakIterator> & rBI,const OUString & rString,sal_Int32 nPos)3219     sal_Int16 lcl_getScriptType(
3220         const uno::Reference<i18n::XBreakIterator>& rBI,
3221         const OUString &rString, sal_Int32 nPos)
3222     {
3223         sal_Int16 nScript = rBI->getScriptType(rString, nPos);
3224         if (nScript == i18n::ScriptType::WEAK && rString[nPos] >= 0x0020 && rString[nPos] <= 0x007F)
3225             nScript = MSASCII;
3226         return nScript;
3227     }
3228 
3229     // We want to know about WEAK segments, so endOfScript isn't
3230     // useful, and see lcl_getScriptType anyway
lcl_endOfScript(const uno::Reference<i18n::XBreakIterator> & rBI,const OUString & rString,sal_Int32 nPos,sal_Int16 nScript)3231     sal_Int32 lcl_endOfScript(
3232         const uno::Reference<i18n::XBreakIterator>& rBI,
3233         const OUString &rString, sal_Int32 nPos, sal_Int16 nScript)
3234     {
3235         while (nPos < rString.getLength())
3236         {
3237             sal_Int16 nNewScript = lcl_getScriptType(rBI, rString, nPos);
3238             if (nScript != nNewScript)
3239                 break;
3240             ++nPos;
3241         }
3242         return nPos;
3243     }
3244 
lcl_getWriterScriptType(const uno::Reference<i18n::XBreakIterator> & rBI,const OUString & rString,sal_Int32 nPos)3245     sal_Int32 lcl_getWriterScriptType(
3246         const uno::Reference<i18n::XBreakIterator>& rBI,
3247         const OUString &rString, sal_Int32 nPos)
3248     {
3249         sal_Int16 nScript = i18n::ScriptType::WEAK;
3250 
3251         if (rString.isEmpty())
3252             return nScript;
3253 
3254         while (nPos >= 0)
3255         {
3256             nScript = rBI->getScriptType(rString, nPos);
3257             if (nScript != i18n::ScriptType::WEAK)
3258                 break;
3259             --nPos;
3260         }
3261 
3262         return nScript;
3263     }
3264 
samePitchIgnoreUnknown(FontPitch eA,FontPitch eB)3265     bool samePitchIgnoreUnknown(FontPitch eA, FontPitch eB)
3266     {
3267         return (eA == eB || eA == PITCH_DONTKNOW || eB == PITCH_DONTKNOW);
3268     }
3269 
sameFontIgnoringIrrelevantFields(const SvxFontItem & rA,const SvxFontItem & rB)3270     bool sameFontIgnoringIrrelevantFields(const SvxFontItem &rA, const SvxFontItem &rB)
3271     {
3272         // Ignoring CharSet, and ignoring unknown pitch
3273         return rA.GetFamilyName() == rB.GetFamilyName() &&
3274             rA.GetStyleName() == rB.GetStyleName() &&
3275             rA.GetFamily() == rB.GetFamily() &&
3276             samePitchIgnoreUnknown(rA.GetPitch(), rB.GetPitch());
3277     }
3278 }
3279 
3280 // In writer we categorize text into CJK, CTL and "Western" for everything else.
3281 // Microsoft Word basically categorizes text into East Asian, Complex, ASCII,
3282 // NonEastAsian/HighAnsi, with some shared characters and some properties to
3283 // hint as to which way to bias those shared characters.
3284 
3285 // That's four categories, we however have three categories. Given that problem
3286 // here we would ideally find out "what would word do" to see what font/language
3287 // word would assign to characters based on the unicode range they fall into and
3288 // hack the word one onto the range we use. However it's unclear what word's
3289 // categorization is. So we don't do that here yet.
3290 
3291 // Additional to the categorization, when word encounters weak text for ambiguous
3292 // chars it uses idcthint to indicate which way to bias. We don't have an idcthint
3293 // feature in writer.
3294 
3295 // So what we currently do here then is to split our text into non-weak/weak
3296 // sections and uses word's idcthint to determine what font it would use and
3297 // force that on for the segment. Following what we *do* know about word's
3298 // categorization, we know that the range 0x0020 and 0x007F is sprmCRgFtc0 in
3299 // word, something we map to LATIN, so we consider all weak chars in that range
3300 // to auto-bias to LATIN.
3301 
3302 // See https://bugs.libreoffice.org/show_bug.cgi?id=34319 for an example
emulateMSWordAddTextToParagraph(const OUString & rAddString)3303 void SwWW8ImplReader::emulateMSWordAddTextToParagraph(const OUString& rAddString)
3304 {
3305     if (rAddString.isEmpty())
3306         return;
3307 
3308     if (m_bFuzzing)
3309     {
3310         simpleAddTextToParagraph(rAddString);
3311         return;
3312     }
3313 
3314     uno::Reference<i18n::XBreakIterator> xBI(g_pBreakIt->GetBreakIter());
3315     assert(xBI.is());
3316 
3317     sal_Int16 nScript = lcl_getScriptType(xBI, rAddString, 0);
3318     sal_Int32 nLen = rAddString.getLength();
3319 
3320     OUString sParagraphText;
3321     const SwContentNode *pCntNd = m_pPaM->GetPointContentNode();
3322     const SwTextNode* pNd = pCntNd ? pCntNd->GetTextNode() : nullptr;
3323     if (pNd)
3324         sParagraphText = pNd->GetText();
3325     sal_Int32 nParaOffset = sParagraphText.getLength();
3326     sParagraphText = sParagraphText + rAddString;
3327 
3328     sal_Int32 nPos = 0;
3329     while (nPos < nLen)
3330     {
3331         sal_Int32 nEnd = lcl_endOfScript(xBI, rAddString, nPos, nScript);
3332         if (nEnd < 0)
3333             break;
3334 
3335         OUString sChunk(rAddString.copy(nPos, nEnd-nPos));
3336         const TypedWhichId<SvxFontItem> aIds[] = {RES_CHRATR_FONT, RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_FONT};
3337         const SvxFontItem *pOverriddenItems[] = {nullptr, nullptr, nullptr};
3338         bool aForced[] = {false, false, false};
3339 
3340         int nLclIdctHint = 0xFF;
3341         if (nScript == i18n::ScriptType::WEAK)
3342         {
3343             const SfxInt16Item *pIdctHint = GetFormatAttr(RES_CHRATR_IDCTHINT);
3344             nLclIdctHint = pIdctHint->GetValue();
3345         }
3346         else if (nScript == MSASCII) // Force weak chars in ascii range to use LATIN font
3347             nLclIdctHint = 0;
3348 
3349         TypedWhichId<SvxFontItem> nForceFromFontId(0);
3350         if (nLclIdctHint != 0xFF)
3351         {
3352             switch (nLclIdctHint)
3353             {
3354                 case 0:
3355                     nForceFromFontId = RES_CHRATR_FONT;
3356                     break;
3357                 case 1:
3358                     nForceFromFontId = RES_CHRATR_CJK_FONT;
3359                     break;
3360                 case 2:
3361                     nForceFromFontId = RES_CHRATR_CTL_FONT;
3362                     break;
3363                 default:
3364                     break;
3365             }
3366         }
3367 
3368         if (sal_uInt16(nForceFromFontId) != 0)
3369         {
3370             // Now we know that word would use the nForceFromFontId font for this range
3371             // Try and determine what script writer would assign this range to
3372 
3373             sal_Int32 nWriterScript = lcl_getWriterScriptType(xBI, sParagraphText,
3374                 nPos + nParaOffset);
3375 
3376             bool bWriterWillUseSameFontAsWordAutomatically = false;
3377 
3378             if (nWriterScript != i18n::ScriptType::WEAK)
3379             {
3380                 if (
3381                      (nWriterScript == i18n::ScriptType::ASIAN && nForceFromFontId == RES_CHRATR_CJK_FONT) ||
3382                      (nWriterScript == i18n::ScriptType::COMPLEX && nForceFromFontId == RES_CHRATR_CTL_FONT) ||
3383                      (nWriterScript == i18n::ScriptType::LATIN && nForceFromFontId == RES_CHRATR_FONT)
3384                    )
3385                 {
3386                     bWriterWillUseSameFontAsWordAutomatically = true;
3387                 }
3388                 else
3389                 {
3390                     const SvxFontItem *pSourceFont = GetFormatAttr(nForceFromFontId);
3391                     TypedWhichId<SvxFontItem> nDestId = aIds[nWriterScript-1];
3392                     const SvxFontItem *pDestFont = GetFormatAttr(nDestId);
3393                     bWriterWillUseSameFontAsWordAutomatically = sameFontIgnoringIrrelevantFields(*pSourceFont, *pDestFont);
3394                 }
3395             }
3396 
3397             // Writer won't use the same font as word, so force the issue
3398             if (!bWriterWillUseSameFontAsWordAutomatically)
3399             {
3400                 const SvxFontItem *pSourceFont = GetFormatAttr(nForceFromFontId);
3401 
3402                 for (size_t i = 0; i < SAL_N_ELEMENTS(aIds); ++i)
3403                 {
3404                     const SvxFontItem *pDestFont = GetFormatAttr(aIds[i]);
3405                     aForced[i] = aIds[i] != nForceFromFontId && *pSourceFont != *pDestFont;
3406                     if (aForced[i])
3407                     {
3408                         pOverriddenItems[i] =
3409                             static_cast<const SvxFontItem*>(m_xCtrlStck->GetStackAttr(*m_pPaM->GetPoint(), aIds[i]));
3410 
3411                         SvxFontItem aForceFont(*pSourceFont);
3412                         aForceFont.SetWhich(aIds[i]);
3413                         m_xCtrlStck->NewAttr(*m_pPaM->GetPoint(), aForceFont);
3414                     }
3415                 }
3416             }
3417         }
3418 
3419         simpleAddTextToParagraph(sChunk);
3420 
3421         for (size_t i = 0; i < SAL_N_ELEMENTS(aIds); ++i)
3422         {
3423             if (aForced[i])
3424             {
3425                 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), aIds[i]);
3426                 if (pOverriddenItems[i])
3427                     m_xCtrlStck->NewAttr(*m_pPaM->GetPoint(), *(pOverriddenItems[i]));
3428             }
3429         }
3430 
3431         nPos = nEnd;
3432         if (nPos < nLen)
3433             nScript = lcl_getScriptType(xBI, rAddString, nPos);
3434     }
3435 }
3436 
3437 namespace sw {
3438 
FilterControlChars(std::u16string_view aString)3439 auto FilterControlChars(std::u16string_view aString) -> OUString
3440 {
3441     OUStringBuffer buf(aString.size());
3442     for (size_t i = 0; i < aString.size(); ++i)
3443     {
3444         sal_Unicode const ch(aString[i]);
3445         if (!linguistic::IsControlChar(ch) || ch == '\r' || ch == '\n' || ch == '\t')
3446         {
3447             buf.append(ch);
3448         }
3449         else
3450         {
3451             SAL_INFO("sw.ww8", "filtering control character");
3452         }
3453     }
3454     return buf.makeStringAndClear();
3455 }
3456 
3457 } // namespace sw
3458 
simpleAddTextToParagraph(std::u16string_view aAddString)3459 void SwWW8ImplReader::simpleAddTextToParagraph(std::u16string_view aAddString)
3460 {
3461     OUString const addString(sw::FilterControlChars(aAddString));
3462 
3463     if (addString.isEmpty())
3464         return;
3465 
3466     const SwContentNode *pCntNd = m_pPaM->GetPointContentNode();
3467     const SwTextNode* pNd = pCntNd ? pCntNd->GetTextNode() : nullptr;
3468 
3469     OSL_ENSURE(pNd, "What the hell, where's my text node");
3470 
3471     if (!pNd)
3472         return;
3473 
3474     const sal_Int32 nCharsLeft = SAL_MAX_INT32 - pNd->GetText().getLength();
3475     if (nCharsLeft > 0)
3476     {
3477         if (addString.getLength() <= nCharsLeft)
3478         {
3479             m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, addString);
3480         }
3481         else
3482         {
3483             m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, addString.copy(0, nCharsLeft));
3484             FinalizeTextNode(*m_pPaM->GetPoint());
3485             m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, addString.copy(nCharsLeft));
3486         }
3487     }
3488     else
3489     {
3490         FinalizeTextNode(*m_pPaM->GetPoint());
3491         m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, addString);
3492     }
3493 
3494     m_bReadTable = false;
3495 }
3496 
3497 /**
3498  * Return value: true for para end
3499  */
ReadChars(WW8_CP & rPos,WW8_CP nNextAttr,tools::Long nTextEnd,tools::Long nCpOfs)3500 bool SwWW8ImplReader::ReadChars(WW8_CP& rPos, WW8_CP nNextAttr, tools::Long nTextEnd,
3501     tools::Long nCpOfs)
3502 {
3503     tools::Long nEnd = ( nNextAttr < nTextEnd ) ? nNextAttr : nTextEnd;
3504 
3505     if (m_bSymbol || m_bIgnoreText)
3506     {
3507         WW8_CP nRequested = nEnd - rPos;
3508         if (m_bSymbol) // Insert special chars
3509         {
3510             sal_uInt64 nMaxPossible = m_pStrm->remainingSize();
3511             if (o3tl::make_unsigned(nRequested) > nMaxPossible)
3512             {
3513                 SAL_WARN("sw.ww8", "document claims to have more characters, " << nRequested << " than remaining, " << nMaxPossible);
3514                 nRequested = nMaxPossible;
3515             }
3516 
3517             if (!linguistic::IsControlChar(m_cSymbol)
3518                 || m_cSymbol == '\r' || m_cSymbol == '\n' || m_cSymbol == '\t')
3519             {
3520                 for (WW8_CP nCh = 0; nCh < nRequested; ++nCh)
3521                 {
3522                     m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, OUString(m_cSymbol));
3523                 }
3524                 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_CHRATR_FONT);
3525                 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_CHRATR_CJK_FONT);
3526                 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_CHRATR_CTL_FONT);
3527             }
3528         }
3529         m_pStrm->SeekRel(nRequested);
3530         rPos = nEnd; // Ignore until attribute end
3531         return false;
3532     }
3533 
3534     while (true)
3535     {
3536         if (ReadPlainChars(rPos, nEnd, nCpOfs))
3537             return false; // Done
3538 
3539         bool bStartLine = ReadChar(rPos, nCpOfs);
3540         rPos++;
3541         if (m_bPgSecBreak || bStartLine || rPos == nEnd) // CR or Done
3542         {
3543             return bStartLine;
3544         }
3545     }
3546 }
3547 
HandlePageBreakChar()3548 bool SwWW8ImplReader::HandlePageBreakChar()
3549 {
3550     bool bParaEndAdded = false;
3551     // #i1909# section/page breaks should not occur in tables, word
3552     // itself ignores them in this case.
3553     if (!m_nInTable)
3554     {
3555         bool IsTemp=true;
3556         SwTextNode* pTemp = m_pPaM->GetPointNode().GetTextNode();
3557         if (pTemp && pTemp->GetText().isEmpty()
3558                 && (m_bFirstPara || m_bFirstParaOfPage))
3559         {
3560             IsTemp = false;
3561             FinalizeTextNode(*m_pPaM->GetPoint());
3562             pTemp->SetAttr(*GetDfltAttr(RES_PARATR_NUMRULE));
3563         }
3564 
3565         m_bPgSecBreak = true;
3566         m_xCtrlStck->KillUnlockedAttrs(*m_pPaM->GetPoint());
3567         /*
3568         If it's a 0x0c without a paragraph end before it, act like a
3569         paragraph end, but nevertheless, numbering (and perhaps other
3570         similar constructs) do not exist on the para.
3571         */
3572         if (!m_bWasParaEnd && IsTemp)
3573         {
3574             bParaEndAdded = true;
3575             if (0 >= m_pPaM->GetPoint()->GetContentIndex())
3576             {
3577                 if (SwTextNode* pTextNode = m_pPaM->GetPointNode().GetTextNode())
3578                 {
3579                     pTextNode->SetAttr(
3580                         *GetDfltAttr(RES_PARATR_NUMRULE));
3581                 }
3582             }
3583         }
3584     }
3585     return bParaEndAdded;
3586 }
3587 
ReadChar(tools::Long nPosCp,tools::Long nCpOfs)3588 bool SwWW8ImplReader::ReadChar(tools::Long nPosCp, tools::Long nCpOfs)
3589 {
3590     bool bNewParaEnd = false;
3591     // Reset Unicode flag and correct FilePos if needed.
3592     // Note: Seek is not expensive, as we're checking inline whether or not
3593     // the correct FilePos has already been reached.
3594     std::size_t nRequestedPos = m_xSBase->WW8Cp2Fc(nCpOfs+nPosCp, &m_bIsUnicode);
3595     if (!checkSeek(*m_pStrm, nRequestedPos))
3596         return false;
3597 
3598     sal_uInt16 nWCharVal(0);
3599     if( m_bIsUnicode )
3600         m_pStrm->ReadUInt16( nWCharVal ); // unicode  --> read 2 bytes
3601     else
3602     {
3603         sal_uInt8 nBCode(0);
3604         m_pStrm -> ReadUChar( nBCode ); // old code --> read 1 byte
3605         nWCharVal = nBCode;
3606     }
3607 
3608     sal_Unicode cInsert = '\x0';
3609     bool bParaMark = false;
3610 
3611     if ( 0xc != nWCharVal )
3612         m_bFirstParaOfPage = false;
3613 
3614     switch (nWCharVal)
3615     {
3616         case 0:
3617             if (!m_bFuzzing)
3618             {
3619                 // Page number
3620                 SwPageNumberField aField(
3621                     static_cast<SwPageNumberFieldType*>(m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(
3622                     SwFieldIds::PageNumber )), PG_RANDOM, SVX_NUM_ARABIC);
3623                 m_rDoc.getIDocumentContentOperations().InsertPoolItem(*m_pPaM, SwFormatField(aField));
3624             }
3625             else
3626             {
3627                 // extremely slow, so skip for fuzzing, and insert a space instead
3628                 cInsert = ' ';
3629             }
3630             break;
3631         case 0xe:
3632             // if there is only one column word treats a column break like a pagebreak.
3633             if (m_aSectionManager.CurrentSectionColCount() < 2)
3634                 bParaMark = HandlePageBreakChar();
3635             else if (!m_nInTable)
3636             {
3637                 // Always insert a txtnode for a column break, e.g. ##
3638                 SwContentNode *pCntNd=m_pPaM->GetPointContentNode();
3639                 if (pCntNd!=nullptr && pCntNd->Len()>0) // if par is empty not break is needed
3640                     FinalizeTextNode(*m_pPaM->GetPoint());
3641                 m_rDoc.getIDocumentContentOperations().InsertPoolItem(*m_pPaM, SvxFormatBreakItem(SvxBreak::ColumnBefore, RES_BREAK));
3642             }
3643             break;
3644         case 0x7:
3645             {
3646                 bNewParaEnd = true;
3647                 WW8PLCFxDesc* pPap = m_xPlcxMan->GetPap();
3648                 //The last paragraph of each cell is terminated by a special
3649                 //paragraph mark called a cell mark. Following the cell mark
3650                 //that ends the last cell of a table row, the table row is
3651                 //terminated by a special paragraph mark called a row mark
3652                 //
3653                 //So the 0x7 should be right at the end of the previous
3654                 //range to be a real cell-end.
3655                 if (pPap->nOrigStartPos == nPosCp+1 ||
3656                     pPap->nOrigStartPos == WW8_CP_MAX)
3657                 {
3658                     TabCellEnd();       // Table cell/row end
3659                 }
3660                 else
3661                     bParaMark = true;
3662             }
3663             break;
3664         case 0xf:
3665             if( !m_bSpec )        // "Satellite"
3666                 cInsert = u'\x00a4';
3667             break;
3668         case 0x14:
3669             if( !m_bSpec )        // "Para End" char
3670                 cInsert = u'\x00b5';
3671                     //TODO: should this be U+00B6 PILCROW SIGN rather than
3672                     // U+00B5 MICRO SIGN?
3673             break;
3674         case 0x15:
3675             if( !m_bSpec )        // Juristenparagraph
3676             {
3677                 cp_set::iterator aItr = m_aTOXEndCps.find(static_cast<WW8_CP>(nPosCp));
3678                 if (aItr == m_aTOXEndCps.end())
3679                     cInsert = u'\x00a7';
3680                 else
3681                     m_aTOXEndCps.erase(aItr);
3682             }
3683             break;
3684         case 0x9:
3685             cInsert = '\x9';    // Tab
3686             break;
3687         case 0xb:
3688             cInsert = '\xa';    // Hard NewLine
3689             break;
3690         case 0xc:
3691             bParaMark = HandlePageBreakChar();
3692             break;
3693         case 0x1e:              // Non-breaking hyphen
3694             m_rDoc.getIDocumentContentOperations().InsertString( *m_pPaM, OUString(CHAR_HARDHYPHEN) );
3695             break;
3696         case 0x1f:              // Non-required hyphens
3697             m_rDoc.getIDocumentContentOperations().InsertString( *m_pPaM, OUString(CHAR_SOFTHYPHEN) );
3698             break;
3699         case 0xa0:              // Non-breaking spaces
3700             m_rDoc.getIDocumentContentOperations().InsertString( *m_pPaM, OUString(CHAR_HARDBLANK)  );
3701             break;
3702         case 0x1:
3703             /*
3704             Current thinking is that if bObj is set then we have a
3705             straightforward "traditional" ole object, otherwise we have a
3706             graphic preview of an associated ole2 object (or a simple
3707             graphic of course)
3708 
3709             normally in the canvas field, the code is 0x8 0x1.
3710             in a special case, the code is 0x1 0x1, which yields a simple picture
3711             */
3712             {
3713                 bool bReadObj = IsInlineEscherHack();
3714                 if( bReadObj )
3715                 {
3716                     sal_uInt64 nCurPos = m_pStrm->Tell();
3717                     sal_uInt16 nWordCode(0);
3718 
3719                     if( m_bIsUnicode )
3720                         m_pStrm->ReadUInt16( nWordCode );
3721                     else
3722                     {
3723                         sal_uInt8 nByteCode(0);
3724                         m_pStrm->ReadUChar( nByteCode );
3725                         nWordCode = nByteCode;
3726                     }
3727                     if( nWordCode == 0x1 )
3728                         bReadObj = false;
3729                     m_pStrm->Seek( nCurPos );
3730                 }
3731                 if( !bReadObj )
3732                 {
3733                     SwFrameFormat *pResult = nullptr;
3734                     if (m_bObj)
3735                         pResult = ImportOle();
3736                     else if (m_bSpec)
3737                     {
3738                         SwFrameFormat* pAsCharFlyFormat =
3739                             m_rDoc.MakeFrameFormat(OUString(), m_rDoc.GetDfltFrameFormat());
3740                         SwFormatAnchor aAnchor(RndStdIds::FLY_AS_CHAR);
3741                         pAsCharFlyFormat->SetFormatAttr(aAnchor);
3742                         pResult = ImportGraf(nullptr, pAsCharFlyFormat);
3743                         m_rDoc.DelFrameFormat(pAsCharFlyFormat);
3744                     }
3745 
3746 
3747                     // If we have a bad 0x1 insert a space instead.
3748                     if (!pResult)
3749                     {
3750                         cInsert = ' ';
3751                         OSL_ENSURE(!m_bObj && !m_bEmbeddObj && !m_nObjLocFc,
3752                             "WW8: Please report this document, it may have a "
3753                             "missing graphic");
3754                     }
3755                     else
3756                     {
3757                         // reset the flags.
3758                         m_bObj = m_bEmbeddObj = false;
3759                         m_nObjLocFc = 0;
3760                     }
3761                 }
3762             }
3763             break;
3764         case 0x8:
3765             if( !m_bObj )
3766                 Read_GrafLayer( nPosCp );
3767             break;
3768         case 0xd:
3769             bNewParaEnd = bParaMark = true;
3770             if (m_nInTable > 1)
3771             {
3772                 /*
3773                 #i9666#/#i23161#
3774                 Yes complex, if there is an entry in the undocumented PLCF
3775                 which I believe to be a record of cell and row boundaries
3776                 see if the magic bit which I believe to mean cell end is
3777                 set. I also think btw that the third byte of the 4 byte
3778                 value is the level of the cell
3779                 */
3780                 WW8PLCFspecial* pTest = m_xPlcxMan->GetMagicTables();
3781                 if (pTest && pTest->SeekPosExact(nPosCp+1+nCpOfs) &&
3782                     pTest->Where() == nPosCp+1+nCpOfs)
3783                 {
3784                     WW8_FC nPos;
3785                     void *pData;
3786                     sal_uInt32 nData = pTest->Get(nPos, pData) ? SVBT32ToUInt32(*static_cast<SVBT32*>(pData))
3787                                                                : 0;
3788                     if (nData & 0x2) // Might be how it works
3789                     {
3790                         TabCellEnd();
3791                         bParaMark = false;
3792                     }
3793                 }
3794                 // tdf#106799: We expect TTP marks to be also cell marks,
3795                 // but sometimes sprmPFInnerTtp comes without sprmPFInnerTableCell
3796                 else if (m_bWasTabCellEnd || m_bWasTabRowEnd)
3797                 {
3798                     TabCellEnd();
3799                     bParaMark = false;
3800                 }
3801             }
3802 
3803             m_bWasTabCellEnd = false;
3804 
3805             break;              // line end
3806         case 0x5:               // Annotation reference
3807         case 0x13:
3808             break;
3809         case 0x2:               // TODO: Auto-Footnote-Number, should be replaced by SwWW8ImplReader::End_Footnote later
3810             if (!m_aFootnoteStack.empty())
3811                 cInsert = '?';
3812             break;
3813         default:
3814             SAL_INFO( "sw.ww8.level2", "<unknownValue val=\"" << nWCharVal << "\">" );
3815             break;
3816     }
3817 
3818     if( '\x0' != cInsert )
3819     {
3820         OUString sInsert(cInsert);
3821         emulateMSWordAddTextToParagraph(sInsert);
3822     }
3823     if (!m_aApos.back()) // a para end in apo doesn't count
3824         m_bWasParaEnd = bNewParaEnd;
3825     return bParaMark;
3826 }
3827 
ProcessCurrentCollChange(WW8PLCFManResult & rRes,bool * pStartAttr,bool bCallProcessSpecial)3828 void SwWW8ImplReader::ProcessCurrentCollChange(WW8PLCFManResult& rRes,
3829     bool* pStartAttr, bool bCallProcessSpecial)
3830 {
3831     sal_uInt16 nOldColl = m_nCurrentColl;
3832     m_nCurrentColl = m_xPlcxMan->GetColl();
3833 
3834     // Invalid Style-Id
3835     if (m_nCurrentColl >= m_vColl.size() || !m_vColl[m_nCurrentColl].m_pFormat || !m_vColl[m_nCurrentColl].m_bColl)
3836     {
3837         m_nCurrentColl = 0;
3838         m_bParaAutoBefore = false;
3839         m_bParaAutoAfter = false;
3840     }
3841     else
3842     {
3843         m_bParaAutoBefore = m_vColl[m_nCurrentColl].m_bParaAutoBefore;
3844         m_bParaAutoAfter = m_vColl[m_nCurrentColl].m_bParaAutoAfter;
3845     }
3846 
3847     if (nOldColl >= m_vColl.size())
3848         nOldColl = 0; // guess! TODO make sure this is what we want
3849 
3850     bool bTabRowEnd = false;
3851     if( pStartAttr && bCallProcessSpecial && !m_bInHyperlink )
3852     {
3853         bool bReSync;
3854         // Frame/Table/Autonumbering List Level
3855         bTabRowEnd = ProcessSpecial(bReSync, rRes.nCurrentCp + m_xPlcxMan->GetCpOfs());
3856         if( bReSync )
3857             *pStartAttr = m_xPlcxMan->Get( &rRes ); // Get Attribute-Pos again
3858     }
3859 
3860     if (!bTabRowEnd && StyleExists(m_nCurrentColl))
3861     {
3862         SetTextFormatCollAndListLevel( *m_pPaM, m_vColl[ m_nCurrentColl ]);
3863         ChkToggleAttr(m_vColl[ nOldColl ].m_n81Flags, m_vColl[ m_nCurrentColl ].m_n81Flags);
3864         ChkToggleBiDiAttr(m_vColl[nOldColl].m_n81BiDiFlags,
3865             m_vColl[m_nCurrentColl].m_n81BiDiFlags);
3866     }
3867 }
3868 
ReadTextAttr(WW8_CP & rTextPos,tools::Long nTextEnd,bool & rbStartLine,int nDepthGuard)3869 tools::Long SwWW8ImplReader::ReadTextAttr(WW8_CP& rTextPos, tools::Long nTextEnd, bool& rbStartLine, int nDepthGuard)
3870 {
3871     tools::Long nSkipChars = 0;
3872     WW8PLCFManResult aRes;
3873 
3874     OSL_ENSURE(m_pPaM->GetPointNode().GetTextNode(), "Missing txtnode");
3875     bool bStartAttr = m_xPlcxMan->Get(&aRes); // Get Attribute position again
3876     aRes.nCurrentCp = rTextPos;                  // Current Cp position
3877 
3878     bool bNewSection = (aRes.nFlags & MAN_MASK_NEW_SEP) && !m_bIgnoreText;
3879     if ( bNewSection ) // New Section
3880     {
3881         OSL_ENSURE(m_pPaM->GetPointNode().GetTextNode(), "Missing txtnode");
3882         // Create PageDesc and fill it
3883         m_aSectionManager.CreateSep(rTextPos);
3884         // -> 0xc was a Sectionbreak, but not a Pagebreak;
3885         // Create PageDesc and fill it
3886         m_bPgSecBreak = false;
3887         OSL_ENSURE(m_pPaM->GetPointNode().GetTextNode(), "Missing txtnode");
3888     }
3889 
3890     // New paragraph over Plcx.Fkp.papx
3891     if ( (aRes.nFlags & MAN_MASK_NEW_PAP)|| rbStartLine )
3892     {
3893         ProcessCurrentCollChange( aRes, &bStartAttr,
3894             MAN_MASK_NEW_PAP == (aRes.nFlags & MAN_MASK_NEW_PAP) &&
3895             !m_bIgnoreText );
3896         rbStartLine = false;
3897     }
3898 
3899     // position of last CP that's to be ignored
3900     tools::Long nSkipPos = -1;
3901 
3902     if( 0 < aRes.nSprmId ) // Ignore empty Attrs
3903     {
3904         if( ( eFTN > aRes.nSprmId ) || ( 0x0800 <= aRes.nSprmId ) )
3905         {
3906             if( bStartAttr ) // WW attributes
3907             {
3908                 if( aRes.nMemLen >= 0 )
3909                     ImportSprm(aRes.pMemPos, aRes.nMemLen, aRes.nSprmId);
3910             }
3911             else
3912                 EndSprm( aRes.nSprmId ); // Switch off Attr
3913         }
3914         else if( aRes.nSprmId < 0x800 ) // Own helper attributes
3915         {
3916             if (bStartAttr)
3917             {
3918                 nSkipChars = ImportExtSprm(&aRes);
3919                 if (
3920                     (aRes.nSprmId == eFTN) || (aRes.nSprmId == eEDN) ||
3921                     (aRes.nSprmId == eFLD) || (aRes.nSprmId == eAND)
3922                    )
3923                 {
3924                     WW8_CP nMaxLegalSkip = nTextEnd - rTextPos;
3925                     // Skip Field/Footnote-/End-Note here
3926                     rTextPos += std::min<WW8_CP>(nSkipChars, nMaxLegalSkip);
3927                     nSkipPos = rTextPos-1;
3928                 }
3929             }
3930             else
3931                 EndExtSprm( aRes.nSprmId );
3932         }
3933     }
3934 
3935     sal_Int32 nRequestedPos = m_xSBase->WW8Cp2Fc(m_xPlcxMan->GetCpOfs() + rTextPos, &m_bIsUnicode);
3936     bool bValidPos = checkSeek(*m_pStrm, nRequestedPos);
3937     SAL_WARN_IF(!bValidPos, "sw.ww8", "Document claimed to have text at an invalid position, skip attributes for region");
3938 
3939     // Find next Attr position (and Skip attributes of field contents if needed)
3940     if (nSkipChars && !m_bIgnoreText)
3941         m_xCtrlStck->MarkAllAttrsOld();
3942     bool bOldIgnoreText = m_bIgnoreText;
3943     m_bIgnoreText = true;
3944     sal_uInt16 nOldColl = m_nCurrentColl;
3945     bool bDoPlcxManPlusPLus = true;
3946     tools::Long nNext;
3947     do
3948     {
3949         if( bDoPlcxManPlusPLus )
3950             m_xPlcxMan->advance();
3951         nNext = bValidPos ? m_xPlcxMan->Where() : nTextEnd;
3952 
3953         if (m_pPostProcessAttrsInfo &&
3954             m_pPostProcessAttrsInfo->mnCpStart == nNext)
3955         {
3956             m_pPostProcessAttrsInfo->mbCopy = true;
3957         }
3958 
3959         if( (0 <= nNext) && (nSkipPos >= nNext) )
3960         {
3961             if (nDepthGuard >= 1024)
3962             {
3963                 SAL_WARN("sw.ww8", "ReadTextAttr hit recursion limit");
3964                 nNext = nTextEnd;
3965             }
3966             else
3967                 nNext = ReadTextAttr(rTextPos, nTextEnd, rbStartLine, nDepthGuard + 1);
3968             bDoPlcxManPlusPLus = false;
3969             m_bIgnoreText = true;
3970         }
3971 
3972         if (m_pPostProcessAttrsInfo &&
3973             nNext > m_pPostProcessAttrsInfo->mnCpEnd)
3974         {
3975             m_pPostProcessAttrsInfo->mbCopy = false;
3976         }
3977     }
3978     while( nSkipPos >= nNext );
3979     m_bIgnoreText    = bOldIgnoreText;
3980     if( nSkipChars )
3981     {
3982         m_xCtrlStck->KillUnlockedAttrs( *m_pPaM->GetPoint() );
3983         if( nOldColl != m_xPlcxMan->GetColl() )
3984             ProcessCurrentCollChange(aRes, nullptr, false);
3985     }
3986 
3987     return nNext;
3988 }
3989 
ReadAttrs(WW8_CP & rTextPos,WW8_CP & rNext,tools::Long nTextEnd,bool & rbStartLine)3990 void SwWW8ImplReader::ReadAttrs(WW8_CP& rTextPos, WW8_CP& rNext, tools::Long nTextEnd, bool& rbStartLine)
3991 {
3992     // Do we have attributes?
3993     if( rTextPos >= rNext )
3994     {
3995         do
3996         {
3997             rNext = ReadTextAttr(rTextPos, nTextEnd, rbStartLine);
3998             if (rTextPos == rNext && rTextPos >= nTextEnd)
3999                 break;
4000         }
4001         while( rTextPos >= rNext );
4002 
4003     }
4004     else if ( rbStartLine )
4005     {
4006     /* No attributes, but still a new line.
4007      * If a line ends with a line break and paragraph attributes or paragraph templates
4008      * do NOT change the line end was not added to the Plcx.Fkp.papx i.e. (nFlags & MAN_MASK_NEW_PAP)
4009      * is false.
4010      * Due to this we need to set the template here as a kind of special treatment.
4011      */
4012         if (!m_bCpxStyle && m_nCurrentColl < m_vColl.size())
4013             SetTextFormatCollAndListLevel(*m_pPaM, m_vColl[m_nCurrentColl]);
4014         rbStartLine = false;
4015     }
4016 }
4017 
4018 /**
4019  * CloseAttrEnds to only read the attribute ends at the end of a text or a
4020  * text area (Header, Footnote, ...).
4021  * We ignore attribute starts and fields.
4022  */
CloseAttrEnds()4023 void SwWW8ImplReader::CloseAttrEnds()
4024 {
4025     // If there are any unclosed sprms then copy them to
4026     // another stack and close the ones that must be closed
4027     std::stack<sal_uInt16> aStack;
4028     m_xPlcxMan->TransferOpenSprms(aStack);
4029 
4030     while (!aStack.empty())
4031     {
4032         sal_uInt16 nSprmId = aStack.top();
4033         if ((0 < nSprmId) && (( eFTN > nSprmId) || (0x0800 <= nSprmId)))
4034             EndSprm(nSprmId);
4035         aStack.pop();
4036     }
4037 
4038     EndSpecial();
4039 }
4040 
ReadText(WW8_CP nStartCp,WW8_CP nTextLen,ManTypes nType)4041 bool SwWW8ImplReader::ReadText(WW8_CP nStartCp, WW8_CP nTextLen, ManTypes nType)
4042 {
4043     bool bJoined=false;
4044 
4045     bool bStartLine = true;
4046     short nCrCount = 0;
4047     short nDistance = 0;
4048 
4049     m_bWasParaEnd = false;
4050     m_nCurrentColl    =  0;
4051     m_xCurrentItemSet.reset();
4052     m_nCharFormat    = -1;
4053     m_bSpec = false;
4054     m_bPgSecBreak = false;
4055 
4056     m_xPlcxMan = std::make_shared<WW8PLCFMan>(m_xSBase.get(), nType, nStartCp);
4057     tools::Long nCpOfs = m_xPlcxMan->GetCpOfs(); // Offset for Header/Footer, Footnote
4058 
4059     WW8_CP nNext = m_xPlcxMan->Where();
4060     m_xPreviousNode.reset();
4061     sal_uInt8 nDropLines = 0;
4062     SwCharFormat* pNewSwCharFormat = nullptr;
4063     const SwCharFormat* pFormat = nullptr;
4064 
4065     bool bValidPos = checkSeek(*m_pStrm, m_xSBase->WW8Cp2Fc(nStartCp + nCpOfs, &m_bIsUnicode));
4066     if (!bValidPos)
4067         return false;
4068 
4069     WW8_CP l = nStartCp;
4070     const WW8_CP nMaxPossible = WW8_CP_MAX-nStartCp;
4071     if (nTextLen > nMaxPossible)
4072     {
4073         SAL_WARN_IF(nTextLen > nMaxPossible, "sw.ww8", "TextLen too long");
4074         nTextLen = nMaxPossible;
4075     }
4076     WW8_CP nTextEnd = nStartCp+nTextLen;
4077     while (l < nTextEnd)
4078     {
4079         ReadAttrs( l, nNext, nTextEnd, bStartLine );// Takes SectionBreaks into account, too
4080         OSL_ENSURE(m_pPaM->GetPointNode().GetTextNode(), "Missing txtnode");
4081 
4082         if (m_pPostProcessAttrsInfo != nullptr)
4083             PostProcessAttrs();
4084 
4085         if (l >= nTextEnd)
4086             break;
4087 
4088         bStartLine = ReadChars(l, nNext, nTextEnd, nCpOfs);
4089 
4090         // If the previous paragraph was a dropcap then do not
4091         // create a new txtnode and join the two paragraphs together
4092         if (bStartLine && !m_xPreviousNode) // Line end
4093         {
4094             bool bSplit = true;
4095             if (m_bCareFirstParaEndInToc)
4096             {
4097                 m_bCareFirstParaEndInToc = false;
4098                 if (m_pPaM->End() && m_pPaM->End()->GetNode().GetTextNode() &&  m_pPaM->End()->GetNode().GetTextNode()->Len() == 0)
4099                     bSplit = false;
4100             }
4101             if (m_bCareLastParaEndInToc)
4102             {
4103                 m_bCareLastParaEndInToc = false;
4104                 if (m_pPaM->End() && m_pPaM->End()->GetNode().GetTextNode() &&  m_pPaM->End()->GetNode().GetTextNode()->Len() == 0)
4105                     bSplit = false;
4106             }
4107             if (bSplit)
4108             {
4109                 FinalizeTextNode(*m_pPaM->GetPoint());
4110             }
4111         }
4112 
4113         if (SwTextNode* pPreviousNode = (bStartLine && m_xPreviousNode) ? m_xPreviousNode->GetTextNode() : nullptr)
4114         {
4115             SwTextNode* pEndNd = m_pPaM->GetPointNode().GetTextNode();
4116             SAL_WARN_IF(!pEndNd, "sw.ww8", "didn't find textnode for dropcap");
4117             if (pEndNd)
4118             {
4119                 const sal_Int32 nDropCapLen = pPreviousNode->GetText().getLength();
4120 
4121                 // Need to reset the font size and text position for the dropcap
4122                 {
4123                     SwPaM aTmp(*pEndNd, 0, *pEndNd, nDropCapLen+1);
4124                     m_xCtrlStck->Delete(aTmp);
4125                 }
4126 
4127                 // Get the default document dropcap which we can use as our template
4128                 const SwFormatDrop* defaultDrop = GetFormatAttr(RES_PARATR_DROP);
4129                 SwFormatDrop aDrop(*defaultDrop);
4130 
4131                 aDrop.GetLines() = nDropLines;
4132                 aDrop.GetDistance() = nDistance;
4133                 aDrop.GetChars() = writer_cast<sal_uInt8>(nDropCapLen);
4134                 // Word has no concept of a "whole word dropcap"
4135                 aDrop.GetWholeWord() = false;
4136 
4137                 if (pFormat)
4138                     aDrop.SetCharFormat(const_cast<SwCharFormat*>(pFormat));
4139                 else if(pNewSwCharFormat)
4140                     aDrop.SetCharFormat(pNewSwCharFormat);
4141 
4142                 SwPosition aStart(*pEndNd);
4143                 m_xCtrlStck->NewAttr(aStart, aDrop);
4144                 m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_PARATR_DROP);
4145             }
4146             m_xPreviousNode.reset();
4147         }
4148         else if (m_bDropCap)
4149         {
4150             // If we have found a dropcap store the textnode
4151             m_xPreviousNode.reset(new TextNodeListener(m_pPaM->GetPointNode().GetTextNode()));
4152 
4153             SprmResult aDCS;
4154             if (m_bVer67)
4155                 aDCS = m_xPlcxMan->GetPapPLCF()->HasSprm(46);
4156             else
4157                 aDCS = m_xPlcxMan->GetPapPLCF()->HasSprm(0x442C);
4158 
4159             if (aDCS.pSprm && aDCS.nRemainingData >= 1)
4160                 nDropLines = (*aDCS.pSprm) >> 3;
4161             else    // There is no Drop Cap Specifier hence no dropcap
4162                 m_xPreviousNode.reset();
4163 
4164             SprmResult aDistance = m_xPlcxMan->GetPapPLCF()->HasSprm(0x842F);
4165             if (aDistance.pSprm && aDistance.nRemainingData >= 2)
4166                 nDistance = SVBT16ToUInt16(aDistance.pSprm);
4167             else
4168                 nDistance = 0;
4169 
4170             const SwFormatCharFormat *pSwFormatCharFormat = nullptr;
4171 
4172             if (m_xCurrentItemSet)
4173                 pSwFormatCharFormat = &(m_xCurrentItemSet->Get(RES_TXTATR_CHARFMT));
4174 
4175             if (pSwFormatCharFormat)
4176                 pFormat = pSwFormatCharFormat->GetCharFormat();
4177 
4178             if (m_xCurrentItemSet && !pFormat)
4179             {
4180                 OUString sPrefix = "WW8Dropcap" + OUString::number(m_nDropCap++);
4181                 pNewSwCharFormat = m_rDoc.MakeCharFormat(sPrefix, m_rDoc.GetDfltCharFormat());
4182                 m_xCurrentItemSet->ClearItem(RES_CHRATR_ESCAPEMENT);
4183                 pNewSwCharFormat->SetFormatAttr(*m_xCurrentItemSet);
4184             }
4185 
4186             m_xCurrentItemSet.reset();
4187             m_bDropCap=false;
4188         }
4189 
4190         if (bStartLine || m_bWasTabRowEnd)
4191         {
4192             // Call all 64 CRs; not for Header and the like
4193             if ((nCrCount++ & 0x40) == 0 && nType == MAN_MAINTEXT && l <= nTextLen)
4194             {
4195                 if (nTextLen < WW8_CP_MAX/100)
4196                     m_nProgress = o3tl::narrowing<sal_uInt16>(l * 100 / nTextLen);
4197                 else
4198                     m_nProgress = o3tl::narrowing<sal_uInt16>(l / nTextLen * 100);
4199                 m_xProgress->Update(m_nProgress); // Update
4200             }
4201         }
4202 
4203         // If we have encountered a 0x0c which indicates either section of
4204         // pagebreak then look it up to see if it is a section break, and
4205         // if it is not then insert a page break. If it is a section break
4206         // it will be handled as such in the ReadAttrs of the next loop
4207         if (m_bPgSecBreak)
4208         {
4209             // We need only to see if a section is ending at this cp,
4210             // the plcf will already be sitting on the correct location
4211             // if it is there.
4212             WW8PLCFxDesc aTemp;
4213             aTemp.nStartPos = aTemp.nEndPos = WW8_CP_MAX;
4214             if (m_xPlcxMan->GetSepPLCF())
4215                 m_xPlcxMan->GetSepPLCF()->GetSprms(&aTemp);
4216             if ((aTemp.nStartPos != l) && (aTemp.nEndPos != l))
4217             {
4218                 // #i39251# - insert text node for page break, if no one inserted.
4219                 // #i43118# - refine condition: the anchor
4220                 // control stack has to have entries, otherwise it's not needed
4221                 // to insert a text node.
4222                 if (!bStartLine && !m_xAnchorStck->empty())
4223                 {
4224                     FinalizeTextNode(*m_pPaM->GetPoint());
4225                 }
4226                 m_rDoc.getIDocumentContentOperations().InsertPoolItem(*m_pPaM,
4227                     SvxFormatBreakItem(SvxBreak::PageBefore, RES_BREAK));
4228                 m_bFirstParaOfPage = true;
4229                 m_bPgSecBreak = false;
4230             }
4231         }
4232     }
4233 
4234     m_xPreviousNode.reset();
4235 
4236     if (m_pPaM->GetPoint()->GetContentIndex())
4237         FinalizeTextNode(*m_pPaM->GetPoint());
4238 
4239     if (!m_bInHyperlink)
4240         bJoined = JoinNode(*m_pPaM);
4241 
4242     CloseAttrEnds();
4243 
4244     m_xPlcxMan.reset();
4245     return bJoined;
4246 }
4247 
SwWW8ImplReader(sal_uInt8 nVersionPara,SotStorage * pStorage,SvStream * pSt,SwDoc & rD,OUString aBaseURL,bool bNewDoc,bool bSkipImages,SwPosition const & rPos)4248 SwWW8ImplReader::SwWW8ImplReader(sal_uInt8 nVersionPara, SotStorage* pStorage,
4249     SvStream* pSt, SwDoc& rD, OUString aBaseURL, bool bNewDoc, bool bSkipImages, SwPosition const &rPos)
4250     : m_pDocShell(rD.GetDocShell())
4251     , m_pStg(pStorage)
4252     , m_pStrm(pSt)
4253     , m_pTableStream(nullptr)
4254     , m_pDataStream(nullptr)
4255     , m_rDoc(rD)
4256     , m_pPaM(nullptr)
4257     , m_aSectionManager(*this)
4258     , m_aExtraneousParas(rD)
4259     , m_aInsertedTables(rD)
4260     , m_aSectionNameGenerator(rD, u"WW"_ustr)
4261     , m_aGrfNameGenerator(bNewDoc, OUString('G'))
4262     , m_aParaStyleMapper(rD)
4263     , m_aCharStyleMapper(rD)
4264     , m_pFlyFormatOfJustInsertedGraphic(nullptr)
4265     , m_pPreviousNumPaM(nullptr)
4266     , m_pPrevNumRule(nullptr)
4267     , m_pCurrentColl(nullptr)
4268     , m_pDfltTextFormatColl(nullptr)
4269     , m_pStandardFormatColl(nullptr)
4270     , m_pDrawModel(nullptr)
4271     , m_pDrawPg(nullptr)
4272     , m_pNumFieldType(nullptr)
4273     , m_sBaseURL(std::move(aBaseURL))
4274     , m_nIniFlags(0)
4275     , m_nIniFlags1(0)
4276     , m_nFieldFlags(0)
4277     , m_bRegardHindiDigits( false )
4278     , m_bDrawCpOValid( false )
4279     , m_nDrawCpO(0)
4280     , m_nPicLocFc(0)
4281     , m_nObjLocFc(0)
4282     , m_nIniFlyDx(0)
4283     , m_nIniFlyDy(0)
4284     , m_eTextCharSet(RTL_TEXTENCODING_ASCII_US)
4285     , m_eStructCharSet(RTL_TEXTENCODING_ASCII_US)
4286     , m_eHardCharSet(RTL_TEXTENCODING_DONTKNOW)
4287     , m_nProgress(0)
4288     , m_nCurrentColl(0)
4289     , m_nFieldNum(0)
4290     , m_nLFOPosition(USHRT_MAX)
4291     , m_nCharFormat(0)
4292     , m_nDrawXOfs(0)
4293     , m_nDrawYOfs(0)
4294     , m_nDrawXOfs2(0)
4295     , m_nDrawYOfs2(0)
4296     , m_cSymbol(0)
4297     , m_nWantedVersion(nVersionPara)
4298     , m_nSwNumLevel(0xff)
4299     , m_nWwNumType(0xff)
4300     , m_pChosenWW8OutlineStyle(nullptr)
4301     , m_nListLevel(MAXLEVEL)
4302     , m_bNewDoc(bNewDoc)
4303     , m_bSkipImages(bSkipImages)
4304     , m_bReadNoTable(false)
4305     , m_bPgSecBreak(false)
4306     , m_bSpec(false)
4307     , m_bObj(false)
4308     , m_bTxbxFlySection(false)
4309     , m_bHasBorder(false)
4310     , m_bSymbol(false)
4311     , m_bIgnoreText(false)
4312     , m_nInTable(0)
4313     , m_bWasTabRowEnd(false)
4314     , m_bWasTabCellEnd(false)
4315     , m_bAnl(false)
4316     , m_bHdFtFootnoteEdn(false)
4317     , m_bFootnoteEdn(false)
4318     , m_bIsHeader(false)
4319     , m_bIsFooter(false)
4320     , m_bIsUnicode(false)
4321     , m_bCpxStyle(false)
4322     , m_bStyNormal(false)
4323     , m_bWWBugNormal(false)
4324     , m_bNoAttrImport(false)
4325     , m_bInHyperlink(false)
4326     , m_bWasParaEnd(false)
4327     , m_bVer67(false)
4328     , m_bVer6(false)
4329     , m_bVer7(false)
4330     , m_bVer8(false)
4331     , m_bEmbeddObj(false)
4332     , m_bCurrentAND_fNumberAcross(false)
4333     , m_bNoLnNumYet(true)
4334     , m_bFirstPara(true)
4335     , m_bFirstParaOfPage(false)
4336     , m_bParaAutoBefore(false)
4337     , m_bParaAutoAfter(false)
4338     , m_bDropCap(false)
4339     , m_nDropCap(0)
4340     , m_bBidi(false)
4341     , m_bReadTable(false)
4342     , m_bLoadingTOXCache(false)
4343     , m_nEmbeddedTOXLevel(0)
4344     , m_bLoadingTOXHyperlink(false)
4345     , m_bCareFirstParaEndInToc(false)
4346     , m_bCareLastParaEndInToc(false)
4347     , m_bNotifyMacroEventRead(false)
4348     , m_bFuzzing(comphelper::IsFuzzing())
4349 {
4350     m_pStrm->SetEndian( SvStreamEndian::LITTLE );
4351     m_aApos.push_back(false);
4352 
4353     mpCursor = m_rDoc.CreateUnoCursor(rPos);
4354 }
4355 
~SwWW8ImplReader()4356 SwWW8ImplReader::~SwWW8ImplReader()
4357 {
4358 }
4359 
DeleteStack(std::unique_ptr<SwFltControlStack> pStck)4360 void SwWW8ImplReader::DeleteStack(std::unique_ptr<SwFltControlStack> pStck)
4361 {
4362     if( pStck )
4363     {
4364         pStck->SetAttr( *m_pPaM->GetPoint(), 0, false);
4365         pStck->SetAttr( *m_pPaM->GetPoint(), 0, false);
4366     }
4367     else
4368     {
4369         OSL_ENSURE( false, "WW stack already deleted" );
4370     }
4371 }
4372 
SetSegmentToPageDesc(const wwSection & rSection,bool bIgnoreCols)4373 void wwSectionManager::SetSegmentToPageDesc(const wwSection &rSection,
4374     bool bIgnoreCols)
4375 {
4376     SwPageDesc &rPage = *rSection.mpPage;
4377 
4378     SetNumberingType(rSection, rPage);
4379 
4380     SwFrameFormat &rFormat = rPage.GetMaster();
4381 
4382     if(mrReader.m_xWDop->fUseBackGroundInAllmodes) // #i56806# Make sure mrReader is initialized
4383         mrReader.GraphicCtor();
4384 
4385     if (mrReader.m_xWDop->fUseBackGroundInAllmodes && mrReader.m_xMSDffManager)
4386     {
4387         tools::Rectangle aRect(0, 0, 100, 100); // A dummy, we don't care about the size
4388         SvxMSDffImportData aData(aRect);
4389         rtl::Reference<SdrObject> pObject;
4390         if (mrReader.m_xMSDffManager->GetShape(0x401, pObject, aData) && !aData.empty())
4391         {
4392             // Only handle shape if it is a background shape
4393             if (aData.begin()->get()->nFlags & ShapeFlag::Background)
4394             {
4395                 SfxItemSetFixed<RES_BACKGROUND, RES_BACKGROUND,XATTR_START, XATTR_END>
4396                     aSet(rFormat.GetDoc()->GetAttrPool());
4397                 mrReader.MatchSdrItemsIntoFlySet(pObject.get(), aSet, mso_lineSimple,
4398                                                  mso_lineSolid, mso_sptRectangle, aRect);
4399                 if ( aSet.HasItem(RES_BACKGROUND) )
4400                     rFormat.SetFormatAttr(aSet.Get(RES_BACKGROUND));
4401                 else
4402                     rFormat.SetFormatAttr(aSet);
4403             }
4404         }
4405     }
4406     wwULSpaceData aULData;
4407     GetPageULData(rSection, aULData);
4408     SetPageULSpaceItems(rFormat, aULData, rSection);
4409 
4410     rPage.SetVerticalAdjustment( rSection.mnVerticalAdjustment );
4411 
4412     SetPage(rPage, rFormat, rSection, bIgnoreCols);
4413 
4414     if (!(rSection.maSep.pgbApplyTo & 1))
4415         SwWW8ImplReader::SetPageBorder(rFormat, rSection);
4416     if (!(rSection.maSep.pgbApplyTo & 2))
4417         SwWW8ImplReader::SetPageBorder(rPage.GetFirstMaster(), rSection);
4418 
4419     mrReader.SetDocumentGrid(rFormat, rSection);
4420 }
4421 
SetUseOn(wwSection & rSection)4422 void wwSectionManager::SetUseOn(wwSection &rSection)
4423 {
4424     bool bMirror = mrReader.m_xWDop->fMirrorMargins ||
4425         mrReader.m_xWDop->doptypography.m_f2on1;
4426 
4427     UseOnPage eUseBase = bMirror ? UseOnPage::Mirror : UseOnPage::All;
4428     UseOnPage eUse = eUseBase;
4429     if (!mrReader.m_xWDop->fFacingPages)
4430         eUse |= UseOnPage::HeaderShare | UseOnPage::FooterShare;
4431     if (!rSection.HasTitlePage())
4432         eUse |= UseOnPage::FirstShare;
4433 
4434     OSL_ENSURE(rSection.mpPage, "Makes no sense to call me with no pages to set");
4435     if (rSection.mpPage)
4436         rSection.mpPage->WriteUseOn(eUse);
4437 }
4438 
4439 /**
4440  * Set the page descriptor on this node, handle the different cases for a text
4441  * node or a table
4442  */
GiveNodePageDesc(SwNodeIndex const & rIdx,const SwFormatPageDesc & rPgDesc,SwDoc & rDoc)4443 static void GiveNodePageDesc(SwNodeIndex const &rIdx, const SwFormatPageDesc &rPgDesc,
4444     SwDoc &rDoc)
4445 {
4446     /*
4447     If it's a table here, apply the pagebreak to the table
4448     properties, otherwise we add it to the para at this
4449     position
4450     */
4451     if (rIdx.GetNode().IsTableNode())
4452     {
4453         SwTable& rTable =
4454             rIdx.GetNode().GetTableNode()->GetTable();
4455         SwFrameFormat* pApply = rTable.GetFrameFormat();
4456         OSL_ENSURE(pApply, "impossible");
4457         if (pApply)
4458             pApply->SetFormatAttr(rPgDesc);
4459     }
4460     else
4461     {
4462         SwPaM aPage(rIdx);
4463         rDoc.getIDocumentContentOperations().InsertPoolItem(aPage, rPgDesc);
4464     }
4465 }
4466 
4467 /**
4468  * Map a word section to a writer page descriptor
4469  */
SetSwFormatPageDesc(mySegIter const & rIter,mySegIter const & rStart,bool bIgnoreCols)4470 SwFormatPageDesc wwSectionManager::SetSwFormatPageDesc(mySegIter const &rIter,
4471     mySegIter const &rStart, bool bIgnoreCols)
4472 {
4473     if (mrReader.m_bNewDoc && rIter == rStart)
4474     {
4475         rIter->mpPage =
4476             mrReader.m_rDoc.getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD);
4477     }
4478     else
4479     {
4480         rIter->mpPage = mrReader.m_rDoc.MakePageDesc(
4481             SwViewShell::GetShellRes()->GetPageDescName(mnDesc, ShellResource::NORMAL_PAGE),
4482             nullptr, false);
4483     }
4484     OSL_ENSURE(rIter->mpPage, "no page!");
4485     if (!rIter->mpPage)
4486         return SwFormatPageDesc();
4487 
4488     // Set page before hd/ft
4489     const wwSection *pPrevious = nullptr;
4490     if (rIter != rStart)
4491         pPrevious = &(*(rIter-1));
4492     SetHdFt(*rIter, std::distance(rStart, rIter), pPrevious);
4493     SetUseOn(*rIter);
4494 
4495     // Set hd/ft after set page
4496     SetSegmentToPageDesc(*rIter, bIgnoreCols);
4497 
4498     SwFormatPageDesc aRet(rIter->mpPage);
4499 
4500     rIter->mpPage->SetFollow(rIter->mpPage);
4501 
4502     if (rIter->PageRestartNo())
4503         aRet.SetNumOffset(rIter->PageStartAt());
4504 
4505     ++mnDesc;
4506     return aRet;
4507 }
4508 
InsertSegments()4509 void wwSectionManager::InsertSegments()
4510 {
4511     mySegIter aEnd = maSegments.end();
4512     mySegIter aStart = maSegments.begin();
4513     for (mySegIter aIter = aStart; aIter != aEnd; ++aIter)
4514     {
4515         // If the section is of type "New column" (0x01), then simply insert a column break.
4516         // But only if there actually are columns on the page, otherwise a column break
4517         // seems to be handled like a page break by MSO.
4518         if ( aIter->maSep.bkc == 1 && aIter->maSep.ccolM1 > 0 )
4519         {
4520             SwPaM start( aIter->maStart );
4521             mrReader.m_rDoc.getIDocumentContentOperations().InsertPoolItem( start, SvxFormatBreakItem(SvxBreak::ColumnBefore, RES_BREAK));
4522             continue;
4523         }
4524 
4525         mySegIter aNext = aIter+1;
4526         mySegIter aPrev = (aIter == aStart) ? aIter : aIter-1;
4527 
4528         // If two following sections are different in following properties, Word will interpret a continuous
4529         // section break between them as if it was a section break next page.
4530         bool bThisAndPreviousAreCompatible = ((aIter->GetPageWidth() == aPrev->GetPageWidth()) &&
4531             (aIter->GetPageHeight() == aPrev->GetPageHeight()) && (aIter->IsLandScape() == aPrev->IsLandScape()));
4532 
4533         bool bInsertSection = (aIter != aStart) && aIter->IsContinuous() &&  bThisAndPreviousAreCompatible;
4534         bool bInsertPageDesc = !bInsertSection;
4535         bool bProtected = SectionIsProtected(*aIter); // do we really  need this ?? I guess I have a different logic in editshell which disables this...
4536 
4537         if (bInsertPageDesc)
4538         {
4539             /*
4540              If a cont section follows this section then we won't be
4541              creating a page desc with 2+ cols as we cannot host a one
4542              col section in a 2+ col pagedesc and make it look like
4543              word. But if the current section actually has columns then
4544              we are forced to insert a section here as well as a page
4545              descriptor.
4546             */
4547 
4548             bool bIgnoreCols = bInsertSection;
4549             bool bThisAndNextAreCompatible = (aNext == aEnd) ||
4550                 ((aIter->GetPageWidth() == aNext->GetPageWidth()) &&
4551                  (aIter->GetPageHeight() == aNext->GetPageHeight()) &&
4552                  (aIter->IsLandScape() == aNext->IsLandScape()));
4553 
4554             if ((aNext != aEnd && aNext->IsContinuous() && bThisAndNextAreCompatible) || bProtected)
4555             {
4556                 bIgnoreCols = true;
4557                 if ((aIter->NoCols() > 1) || bProtected)
4558                     bInsertSection = true;
4559             }
4560 
4561             SwFormatPageDesc aDesc(SetSwFormatPageDesc(aIter, aStart, bIgnoreCols));
4562             if (!aDesc.GetPageDesc())
4563                 continue;
4564 
4565             // special case handling for odd/even section break
4566             // a) as before create a new page style for the section break
4567             // b) set Layout of generated page style to right/left ( according
4568             //    to section break odd/even )
4569             // c) create a new style to follow the break page style
4570             if ( aIter->maSep.bkc == 3 || aIter->maSep.bkc == 4 )
4571             {
4572                 // SetSwFormatPageDesc calls some methods that could
4573                 // modify aIter (e.g. wwSection ).
4574                 // Since  we call SetSwFormatPageDesc below to generate the
4575                 // 'Following' style of the Break style, it is safer
4576                 // to take  a copy of the contents of aIter.
4577                 wwSection aTmpSection = *aIter;
4578                 // create a new following page style
4579                 SwFormatPageDesc aFollow(SetSwFormatPageDesc(aIter, aStart, bIgnoreCols));
4580                 // restore any contents of aIter trashed by SetSwFormatPageDesc
4581                 *aIter = std::move(aTmpSection);
4582 
4583                 // Handle the section break
4584                 UseOnPage eUseOnPage = UseOnPage::Left;
4585                 if ( aIter->maSep.bkc == 4 ) // Odd ( right ) Section break
4586                     eUseOnPage = UseOnPage::Right;
4587 
4588                 // Keep the share flags.
4589                 aDesc.GetPageDesc()->SetUseOn( eUseOnPage );
4590                 aDesc.GetPageDesc()->SetFollow( aFollow.GetPageDesc() );
4591             }
4592 
4593             // Avoid setting the page style at the very beginning since it is always the default style anyway,
4594             // unless it is needed to specify a page number.
4595             if (aIter != aStart || aDesc.GetNumOffset())
4596                 GiveNodePageDesc(aIter->maStart, aDesc, mrReader.m_rDoc);
4597         }
4598 
4599         SwTextNode* pTextNd = nullptr;
4600         if (bInsertSection)
4601         {
4602             // Start getting the bounds of this section
4603             SwPaM aSectPaM(*mrReader.m_pPaM, mrReader.m_pPaM);
4604             SwNodeIndex aAnchor(aSectPaM.GetPoint()->GetNode());
4605             if (aNext != aEnd)
4606             {
4607                 aAnchor = aNext->maStart;
4608                 aSectPaM.GetPoint()->Assign(aAnchor);
4609                 aSectPaM.Move(fnMoveBackward);
4610             }
4611 
4612             const SwPosition* pPos  = aSectPaM.GetPoint();
4613             SwTextNode const*const pSttNd = pPos->GetNode().GetTextNode();
4614             const SwTableNode* pTableNd = pSttNd ? pSttNd->FindTableNode() : nullptr;
4615             if (pTableNd)
4616             {
4617                 pTextNd =
4618                     mrReader.m_rDoc.GetNodes().MakeTextNode(aAnchor.GetNode(),
4619                     mrReader.m_rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TEXT ));
4620 
4621                 aSectPaM.GetPoint()->Assign(*pTextNd, 0);
4622             }
4623 
4624             aSectPaM.SetMark();
4625 
4626             aSectPaM.GetPoint()->Assign(aIter->maStart);
4627 
4628             bool bHasOwnHdFt = false;
4629             /*
4630              In this nightmare scenario the continuous section has its own
4631              headers and footers so we will try and find a hard page break
4632              between here and the end of the section and put the headers and
4633              footers there.
4634             */
4635             if (!bInsertPageDesc)
4636             {
4637                bHasOwnHdFt =
4638                 mrReader.HasOwnHeaderFooter(
4639                  aIter->maSep.grpfIhdt & ~(WW8_HEADER_FIRST | WW8_FOOTER_FIRST),
4640                  aIter->maSep.grpfIhdt, std::distance(aStart, aIter)
4641                 );
4642             }
4643             if (bHasOwnHdFt)
4644             {
4645                 // #i40766# Need to cache the page descriptor in case there is
4646                 // no page break in the section
4647                 SwPageDesc *pOrig = aIter->mpPage;
4648                 bool bFailed = true;
4649                 SwFormatPageDesc aDesc(SetSwFormatPageDesc(aIter, aStart, true));
4650                 if (aDesc.GetPageDesc())
4651                 {
4652                     SwNodeOffset nStart = aSectPaM.Start()->GetNodeIndex();
4653                     SwNodeOffset nEnd   = aSectPaM.End()->GetNodeIndex();
4654                     for(; nStart <= nEnd; ++nStart)
4655                     {
4656                         SwNode* pNode = mrReader.m_rDoc.GetNodes()[nStart];
4657                         if (!pNode)
4658                             continue;
4659                         if (sw::util::HasPageBreak(*pNode))
4660                         {
4661                             SwNodeIndex aIdx(*pNode);
4662                             GiveNodePageDesc(aIdx, aDesc, mrReader.m_rDoc);
4663                             bFailed = false;
4664                             break;
4665                         }
4666                     }
4667                 }
4668                 if(bFailed)
4669                 {
4670                     aIter->mpPage = pOrig;
4671                 }
4672             }
4673 
4674             // End getting the bounds of this section, quite a job eh?
4675             SwSectionFormat *pRet = InsertSection(aSectPaM, *aIter);
4676             // The last section if continuous is always unbalanced
4677             if (pRet)
4678             {
4679                 // Set the columns to be UnBalanced if that compatibility option is set
4680                 if (mrReader.m_xWDop->fNoColumnBalance)
4681                     pRet->SetFormatAttr(SwFormatNoBalancedColumns(true));
4682                 else
4683                 {
4684                     // Otherwise set to unbalanced if the following section is
4685                     // not continuous, (which also means that the last section
4686                     // is unbalanced)
4687                     if (aNext == aEnd || !aNext->IsContinuous())
4688                         pRet->SetFormatAttr(SwFormatNoBalancedColumns(true));
4689                 }
4690             }
4691         }
4692 
4693         if (pTextNd)
4694         {
4695             SwPaM aTest(*pTextNd);
4696             mrReader.m_rDoc.getIDocumentContentOperations().DelFullPara(aTest);
4697             pTextNd = nullptr;
4698         }
4699     }
4700 }
4701 
delete_all_from_doc()4702 void wwExtraneousParas::delete_all_from_doc()
4703 {
4704     auto aEnd = m_aTextNodes.rend();
4705     for (auto aI = m_aTextNodes.rbegin(); aI != aEnd; ++aI)
4706     {
4707         ExtraTextNodeListener& rListener = const_cast<ExtraTextNodeListener&>(*aI);
4708         SwTextNode* pTextNode = rListener.GetTextNode();
4709         rListener.StopListening(pTextNode);
4710 
4711         SwPaM aTest(*pTextNode);
4712         m_rDoc.getIDocumentContentOperations().DelFullPara(aTest);
4713     }
4714     m_aTextNodes.clear();
4715 }
4716 
insert(SwTextNode * pTextNode)4717 void wwExtraneousParas::insert(SwTextNode *pTextNode)
4718 {
4719     m_aTextNodes.emplace(pTextNode, this);
4720 }
4721 
remove_if_present(SwModify * pModify)4722 void wwExtraneousParas::remove_if_present(SwModify* pModify)
4723 {
4724     auto it = std::find_if(m_aTextNodes.begin(), m_aTextNodes.end(),
4725         [pModify](const ExtraTextNodeListener& rEntry) { return rEntry.GetTextNode() == pModify; });
4726     if (it == m_aTextNodes.end())
4727         return;
4728     SAL_WARN("sw.ww8", "It is unexpected to drop a para scheduled for removal");
4729     m_aTextNodes.erase(it);
4730 }
4731 
TextNodeListener(SwTextNode * pTextNode)4732 TextNodeListener::TextNodeListener(SwTextNode* pTextNode)
4733     : m_pTextNode(pTextNode)
4734 {
4735     m_pTextNode->Add(*this);
4736 }
4737 
~TextNodeListener()4738 TextNodeListener::~TextNodeListener()
4739 {
4740     if (!m_pTextNode)
4741         return;
4742     StopListening(m_pTextNode);
4743 }
4744 
SwClientNotify(const SwModify & rModify,const SfxHint & rHint)4745 void TextNodeListener::SwClientNotify(const SwModify& rModify, const SfxHint& rHint)
4746 {
4747     if (rHint.GetId() != SfxHintId::SwLegacyModify)
4748         return;
4749     auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
4750     // ofz#41398 drop a para scheduled for deletion if something else deletes it
4751     // before wwExtraneousParas gets its chance to do so. Not the usual scenario,
4752     // indicates an underlying bug.
4753     if (pLegacy->GetWhich() == RES_OBJECTDYING)
4754         removed(const_cast<SwModify*>(&rModify));
4755 }
4756 
StopListening(SwModify * pTextNode)4757 void TextNodeListener::StopListening(SwModify* pTextNode)
4758 {
4759     pTextNode->Remove(*this);
4760     m_pTextNode = nullptr;
4761 }
4762 
removed(SwModify * pTextNode)4763 void TextNodeListener::removed(SwModify* pTextNode)
4764 {
4765     StopListening(pTextNode);
4766 }
4767 
removed(SwModify * pTextNode)4768 void wwExtraneousParas::ExtraTextNodeListener::removed(SwModify* pTextNode)
4769 {
4770     m_pOwner->remove_if_present(pTextNode);
4771 }
4772 
StoreMacroCmds()4773 void SwWW8ImplReader::StoreMacroCmds()
4774 {
4775     if (!m_xWwFib->m_lcbCmds)
4776         return;
4777 
4778     bool bValidPos = checkSeek(*m_pTableStream, m_xWwFib->m_fcCmds);
4779     if (!bValidPos)
4780         return;
4781 
4782     uno::Reference < embed::XStorage > xRoot(m_pDocShell->GetStorage());
4783 
4784     if (!xRoot.is())
4785         return;
4786 
4787     try
4788     {
4789         uno::Reference < io::XStream > xStream =
4790                 xRoot->openStreamElement( SL::aMSMacroCmds, embed::ElementModes::READWRITE );
4791         std::unique_ptr<SvStream> xOutStream(::utl::UcbStreamHelper::CreateStream(xStream));
4792 
4793         sal_uInt32 lcbCmds = std::min<sal_uInt32>(m_xWwFib->m_lcbCmds, m_pTableStream->remainingSize());
4794         std::unique_ptr<sal_uInt8[]> xBuffer(new sal_uInt8[lcbCmds]);
4795         m_xWwFib->m_lcbCmds = m_pTableStream->ReadBytes(xBuffer.get(), lcbCmds);
4796         xOutStream->WriteBytes(xBuffer.get(), m_xWwFib->m_lcbCmds);
4797     }
4798     catch (...)
4799     {
4800     }
4801 }
4802 
ReadDocVars()4803 void SwWW8ImplReader::ReadDocVars()
4804 {
4805     std::vector<OUString> aDocVarStrings;
4806     std::vector<ww::bytes> aDocVarStringIds;
4807     std::vector<OUString> aDocValueStrings;
4808     WW8ReadSTTBF(!m_bVer67, *m_pTableStream, m_xWwFib->m_fcStwUser,
4809         m_xWwFib->m_lcbStwUser, m_bVer67 ? 2 : 0, m_eStructCharSet,
4810         aDocVarStrings, &aDocVarStringIds, &aDocValueStrings);
4811     if (m_bVer67)        return;
4812 
4813     uno::Reference< text::XTextFieldsSupplier > xFieldsSupplier(m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
4814     uno::Reference<css::lang::XMultiServiceFactory> xTextFactory(m_pDocShell->GetModel(), uno::UNO_QUERY);
4815     uno::Reference< container::XNameAccess > xFieldMasterAccess = xFieldsSupplier->getTextFieldMasters();
4816     for(size_t i = 0; i < aDocVarStrings.size(); i++)
4817     {
4818         const OUString &rName = aDocVarStrings[i];
4819         uno::Any aValue;
4820         if (aDocValueStrings.size() > i)
4821         {
4822             OUString value = aDocValueStrings[i];
4823             value = value.replaceAll("\r\n", "\n");
4824             value = value.replaceAll("\r", "\n");
4825             // fdo48097-1.doc is an example of a case needing sanitizeStringSurrogates
4826             aValue <<= comphelper::string::sanitizeStringSurrogates(value);
4827         }
4828 
4829         uno::Reference< beans::XPropertySet > xMaster;
4830         OUString sFieldMasterService("com.sun.star.text.FieldMaster.User." + rName);
4831 
4832         // Find or create Field Master
4833         if (xFieldMasterAccess->hasByName(sFieldMasterService))
4834         {
4835             xMaster.set(xFieldMasterAccess->getByName(sFieldMasterService), uno::UNO_QUERY_THROW);
4836         }
4837         else
4838         {
4839             xMaster.set(xTextFactory->createInstance(u"com.sun.star.text.FieldMaster.User"_ustr), uno::UNO_QUERY_THROW);
4840             xMaster->setPropertyValue(u"Name"_ustr, uno::Any(rName));
4841         }
4842         xMaster->setPropertyValue(u"Content"_ustr, aValue);
4843     }
4844 }
4845 
4846 /**
4847  * Document Info
4848  */
ReadDocInfo()4849 void SwWW8ImplReader::ReadDocInfo()
4850 {
4851     if( !m_pStg )
4852         return;
4853 
4854     uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
4855         m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
4856     uno::Reference<document::XDocumentProperties> xDocProps(
4857         xDPS->getDocumentProperties());
4858     OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
4859 
4860     if (!xDocProps.is())
4861         return;
4862 
4863     if ( m_xWwFib->m_fDot )
4864     {
4865         SfxMedium* pMedium = m_pDocShell->GetMedium();
4866         if ( pMedium )
4867         {
4868             const OUString& aName = pMedium->GetName();
4869             INetURLObject aURL( aName );
4870             OUString sTemplateURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri);
4871             if ( !sTemplateURL.isEmpty() )
4872                 xDocProps->setTemplateURL( sTemplateURL );
4873         }
4874     }
4875     else if (m_xWwFib->m_lcbSttbfAssoc) // not a template, and has a SttbfAssoc
4876     {
4877         auto nCur = m_pTableStream->Tell();
4878         Sttb aSttb;
4879         // point at tgc record
4880         if (!checkSeek(*m_pTableStream, m_xWwFib->m_fcSttbfAssoc) || !aSttb.Read(*m_pTableStream))
4881             SAL_WARN("sw.ww8", "** Read of SttbAssoc data failed!!!! ");
4882         m_pTableStream->Seek( nCur ); // return to previous position, is that necessary?
4883         OUString sPath = aSttb.getStringAtIndex( 0x1 );
4884         OUString aURL;
4885         // attempt to convert to url (won't work for obvious reasons on linux)
4886         if ( !sPath.isEmpty() )
4887             osl::FileBase::getFileURLFromSystemPath( sPath, aURL );
4888         if (aURL.isEmpty())
4889             xDocProps->setTemplateURL( aURL );
4890         else
4891             xDocProps->setTemplateURL( sPath );
4892 
4893     }
4894     sfx2::LoadOlePropertySet(xDocProps, m_pStg);
4895 }
4896 
lcl_createTemplateToProjectEntry(const uno::Reference<container::XNameContainer> & xPrjNameCache,const OUString & sTemplatePathOrURL,const OUString & sVBAProjName)4897 static void lcl_createTemplateToProjectEntry( const uno::Reference< container::XNameContainer >& xPrjNameCache, const OUString& sTemplatePathOrURL, const OUString& sVBAProjName )
4898 {
4899     if ( !xPrjNameCache.is() )
4900         return;
4901 
4902     INetURLObject aObj;
4903     aObj.SetURL( sTemplatePathOrURL );
4904     bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
4905     OUString aURL;
4906     if ( bIsURL )
4907         aURL = sTemplatePathOrURL;
4908     else
4909     {
4910         osl::FileBase::getFileURLFromSystemPath( sTemplatePathOrURL, aURL );
4911         aObj.SetURL( aURL );
4912     }
4913     try
4914     {
4915         OUString templateNameWithExt = aObj.GetLastName();
4916         sal_Int32 nIndex =  templateNameWithExt.lastIndexOf( '.' );
4917         if ( nIndex != -1 )
4918         {
4919             OUString templateName = templateNameWithExt.copy( 0, nIndex );
4920             xPrjNameCache->insertByName( templateName, uno::Any( sVBAProjName ) );
4921         }
4922     }
4923     catch( const uno::Exception& )
4924     {
4925     }
4926 }
4927 
4928 namespace {
4929 
4930 class WW8Customizations
4931 {
4932     SvStream* mpTableStream;
4933     WW8Fib mWw8Fib;
4934 public:
4935     WW8Customizations( SvStream*, WW8Fib const & );
4936     void  Import( SwDocShell* pShell );
4937 };
4938 
4939 }
4940 
WW8Customizations(SvStream * pTableStream,WW8Fib const & rFib)4941 WW8Customizations::WW8Customizations( SvStream* pTableStream, WW8Fib const & rFib ) : mpTableStream(pTableStream), mWw8Fib( rFib )
4942 {
4943 }
4944 
Import(SwDocShell * pShell)4945 void WW8Customizations::Import( SwDocShell* pShell )
4946 {
4947     if ( mWw8Fib.m_lcbCmds == 0 || !IsEightPlus(mWw8Fib.GetFIBVersion()) )
4948         return;
4949     try
4950     {
4951         Tcg aTCG;
4952         sal_uInt64 nCur = mpTableStream->Tell();
4953         if (!checkSeek(*mpTableStream, mWw8Fib.m_fcCmds)) // point at tgc record
4954         {
4955             SAL_WARN("sw.ww8", "** Seek to Customization data failed!!!! ");
4956             return;
4957         }
4958         bool bReadResult = aTCG.Read( *mpTableStream );
4959         mpTableStream->Seek( nCur ); // return to previous position, is that necessary?
4960         if ( !bReadResult )
4961         {
4962             SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! ");
4963             return;
4964         }
4965         aTCG.ImportCustomToolBar( *pShell );
4966     }
4967     catch(...)
4968     {
4969         SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! epically");
4970     }
4971 }
4972 
ReadGlobalTemplateSettings(std::u16string_view sCreatedFrom,const uno::Reference<container::XNameContainer> & xPrjNameCache)4973 void SwWW8ImplReader::ReadGlobalTemplateSettings( std::u16string_view sCreatedFrom, const uno::Reference< container::XNameContainer >& xPrjNameCache )
4974 {
4975     if (m_bFuzzing)
4976         return;
4977 
4978     SvtPathOptions aPathOpt;
4979     const OUString& aAddinPath = aPathOpt.GetAddinPath();
4980     uno::Sequence< OUString > sGlobalTemplates;
4981 
4982     // first get the autoload addins in the directory STARTUP
4983     uno::Reference<ucb::XSimpleFileAccess3> xSFA(ucb::SimpleFileAccess::create(::comphelper::getProcessComponentContext()));
4984 
4985     if( xSFA->isFolder( aAddinPath ) )
4986         sGlobalTemplates = xSFA->getFolderContents( aAddinPath, false );
4987 
4988     for (const auto& rGlobalTemplate : sGlobalTemplates)
4989     {
4990         INetURLObject aObj;
4991         aObj.SetURL( rGlobalTemplate );
4992         bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
4993         OUString aURL;
4994         if ( bIsURL )
4995                 aURL = rGlobalTemplate;
4996         else
4997                 osl::FileBase::getFileURLFromSystemPath( rGlobalTemplate, aURL );
4998         if ( !aURL.endsWithIgnoreAsciiCase( ".dot" ) || ( !sCreatedFrom.empty() && sCreatedFrom == aURL ) )
4999             continue; // don't try and read the same document as ourselves
5000 
5001         rtl::Reference<SotStorage> rRoot = new SotStorage(aURL, StreamMode::STD_READWRITE);
5002 
5003         BasicProjImportHelper aBasicImporter( *m_pDocShell );
5004         // Import vba via oox filter
5005         aBasicImporter.import( m_pDocShell->GetMedium()->GetInputStream() );
5006         lcl_createTemplateToProjectEntry( xPrjNameCache, aURL, aBasicImporter.getProjectName() );
5007         // Read toolbars & menus
5008         rtl::Reference<SotStorageStream> refMainStream = rRoot->OpenSotStream(u"WordDocument"_ustr);
5009         refMainStream->SetEndian(SvStreamEndian::LITTLE);
5010         WW8Fib aWwFib( *refMainStream, 8 );
5011         rtl::Reference<SotStorageStream> xTableStream =
5012                 rRoot->OpenSotStream(aWwFib.m_fWhichTableStm ? SL::a1Table : SL::a0Table, StreamMode::STD_READ);
5013 
5014         if (xTableStream.is() && ERRCODE_NONE == xTableStream->GetError())
5015         {
5016             xTableStream->SetEndian(SvStreamEndian::LITTLE);
5017             WW8Customizations aGblCustomisations( xTableStream.get(), aWwFib );
5018             aGblCustomisations.Import( m_pDocShell );
5019         }
5020     }
5021 }
5022 
CoreLoad(WW8Glossary const * pGloss)5023 ErrCode SwWW8ImplReader::CoreLoad(WW8Glossary const *pGloss)
5024 {
5025     m_rDoc.SetDocumentType( SwDoc::DOCTYPE_MSWORD );
5026     if (m_bNewDoc && m_pStg && !pGloss)
5027     {
5028         // Initialize RDF metadata, to be able to add statements during the import.
5029         try
5030         {
5031             uno::Reference<frame::XModel> const xModel(m_rDoc.GetDocShell()->GetBaseModel());
5032             uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, uno::UNO_QUERY_THROW);
5033             uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext());
5034             uno::Reference<embed::XStorage> xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
5035             const uno::Reference<rdf::XURI> xBaseURI(sfx2::createBaseURI(xComponentContext, xModel, m_sBaseURL));
5036             uno::Reference<task::XInteractionHandler> xHandler;
5037             xDocumentMetadataAccess->loadMetadataFromStorage(xStorage, xBaseURI, xHandler);
5038         }
5039         catch (const uno::Exception&)
5040         {
5041             TOOLS_WARN_EXCEPTION("sw.ww8", "failed to initialize RDF metadata");
5042         }
5043         ReadDocInfo();
5044     }
5045 
5046     auto pFibData = std::make_shared<::ww8::WW8FibData>();
5047 
5048     if (m_xWwFib->m_fReadOnlyRecommended)
5049         pFibData->setReadOnlyRecommended(true);
5050     else
5051         pFibData->setReadOnlyRecommended(false);
5052 
5053     if (m_xWwFib->m_fWriteReservation)
5054         pFibData->setWriteReservation(true);
5055     else
5056         pFibData->setWriteReservation(false);
5057 
5058     m_rDoc.getIDocumentExternalData().setExternalData(::sw::tExternalDataType::FIB, pFibData);
5059 
5060     ::sw::tExternalDataPointer pSttbfAsoc
5061           = std::make_shared<::ww8::WW8Sttb<ww8::WW8Struct>>(*m_pTableStream, m_xWwFib->m_fcSttbfAssoc, m_xWwFib->m_lcbSttbfAssoc);
5062 
5063     m_rDoc.getIDocumentExternalData().setExternalData(::sw::tExternalDataType::STTBF_ASSOC, pSttbfAsoc);
5064 
5065     if (m_xWwFib->m_fWriteReservation || m_xWwFib->m_fReadOnlyRecommended)
5066     {
5067         SwDocShell * pDocShell = m_rDoc.GetDocShell();
5068         if (pDocShell)
5069             pDocShell->SetReadOnlyUI();
5070     }
5071 
5072     m_pPaM = mpCursor.get();
5073 
5074     m_xCtrlStck.reset(new SwWW8FltControlStack(m_rDoc, m_nFieldFlags, *this));
5075 
5076     m_xRedlineStack.reset(new sw::util::RedlineStack(m_rDoc));
5077 
5078     /*
5079         RefFieldStck: Keeps track of bookmarks which may be inserted as
5080         variables instead.
5081     */
5082     m_xReffedStck.reset(new SwWW8ReferencedFltEndStack(m_rDoc, m_nFieldFlags));
5083     m_xReffingStck.reset(new SwWW8FltRefStack(m_rDoc, m_nFieldFlags));
5084 
5085     m_xAnchorStck.reset(new SwWW8FltAnchorStack(m_rDoc, m_nFieldFlags));
5086 
5087     size_t nPageDescOffset = m_rDoc.GetPageDescCnt();
5088 
5089     RedlineFlags eMode = RedlineFlags::ShowInsert | RedlineFlags::ShowDelete;
5090 
5091     m_oSprmParser.emplace(*m_xWwFib);
5092 
5093     // Set handy helper variables
5094     m_bVer6  = (6 == m_xWwFib->m_nVersion);
5095     m_bVer7  = (7 == m_xWwFib->m_nVersion);
5096     m_bVer67 = m_bVer6 || m_bVer7;
5097     m_bVer8  = (8 == m_xWwFib->m_nVersion);
5098 
5099     m_eTextCharSet = WW8Fib::GetFIBCharset(m_xWwFib->m_chse, m_xWwFib->m_lid);
5100     m_eStructCharSet = WW8Fib::GetFIBCharset(m_xWwFib->m_chseTables, m_xWwFib->m_lid);
5101 
5102     m_bWWBugNormal = m_xWwFib->m_nProduct == 0xc03d;
5103 
5104     m_xProgress.reset(new ImportProgress(m_pDocShell, 0, 100));
5105 
5106     // read Font Table
5107     m_xFonts.reset(new WW8Fonts(*m_pTableStream, *m_xWwFib));
5108 
5109     // Document Properties
5110     m_xWDop.reset(new WW8Dop(*m_pTableStream, m_xWwFib->m_nFib, m_xWwFib->m_fcDop,
5111         m_xWwFib->m_lcbDop));
5112 
5113     if (m_bNewDoc)
5114         ImportDop();
5115 
5116     /*
5117         Import revisioning data: author names
5118     */
5119     if( m_xWwFib->m_lcbSttbfRMark )
5120     {
5121         ReadRevMarkAuthorStrTabl(*m_pTableStream,
5122                                  m_xWwFib->m_fcSttbfRMark,
5123                                  m_xWwFib->m_lcbSttbfRMark, m_rDoc);
5124     }
5125 
5126     // Initialize our String/ID map for Linked Sections
5127     std::vector<OUString> aLinkStrings;
5128     std::vector<ww::bytes> aStringIds;
5129 
5130     WW8ReadSTTBF(!m_bVer67, *m_pTableStream, m_xWwFib->m_fcSttbFnm,
5131         m_xWwFib->m_lcbSttbFnm, m_bVer67 ? 2 : 0, m_eStructCharSet,
5132         aLinkStrings, &aStringIds);
5133 
5134     for (size_t i=0; i < aLinkStrings.size() && i < aStringIds.size(); ++i)
5135     {
5136         const ww::bytes& stringId = aStringIds[i];
5137         if (stringId.size() < sizeof(WW8_STRINGID))
5138         {
5139             SAL_WARN("sw.ww8", "SwWW8ImplReader::CoreLoad: WW8_STRINGID is too short");
5140             continue;
5141         }
5142         const WW8_STRINGID *stringIdStruct = reinterpret_cast<const WW8_STRINGID*>(stringId.data());
5143         m_aLinkStringMap[SVBT16ToUInt16(stringIdStruct->nStringId)] = aLinkStrings[i];
5144     }
5145 
5146     ReadDocVars(); // import document variables as meta information.
5147 
5148     m_xProgress->Update(m_nProgress);    // Update
5149 
5150     m_xLstManager.reset(new WW8ListManager(*m_pTableStream, *this));
5151 
5152     /*
5153         first (1) import all styles (see WW8PAR2.CXX)
5154             BEFORE the import of the lists !!
5155     */
5156     m_xProgress->Update(m_nProgress);    // Update
5157     m_xStyles.reset(new WW8RStyle(*m_xWwFib, this)); // Styles
5158     m_xStyles->Import();
5159 
5160     /*
5161         In the end: (also see WW8PAR3.CXX)
5162 
5163         Go through all Styles and attach respective List Format
5164         AFTER we imported the Styles and AFTER we imported the Lists!
5165     */
5166     m_xProgress->Update(m_nProgress); // Update
5167     m_xStyles->PostProcessStyles();
5168 
5169     if (!m_vColl.empty())
5170         SetOutlineStyles();
5171 
5172     m_xSBase.reset(new WW8ScannerBase(m_pStrm,m_pTableStream,m_pDataStream, m_xWwFib.get()));
5173 
5174     if (m_xSBase->AreThereFootnotes())
5175     {
5176         static const SwFootnoteNum eNumA[4] =
5177         {
5178             FTNNUM_DOC, FTNNUM_CHAPTER, FTNNUM_PAGE, FTNNUM_DOC
5179         };
5180 
5181         SwFootnoteInfo aInfo = m_rDoc.GetFootnoteInfo(); // Copy-Ctor private
5182 
5183         aInfo.m_ePos = FTNPOS_PAGE;
5184         aInfo.m_eNum = eNumA[m_xWDop->rncFootnote];
5185         sal_uInt16 nfcFootnoteRef = m_xWDop->nfcFootnoteRef;
5186         aInfo.m_aFormat.SetNumberingType(WW8ListManager::GetSvxNumTypeFromMSONFC(nfcFootnoteRef));
5187         if( m_xWDop->nFootnote )
5188             aInfo.m_nFootnoteOffset = m_xWDop->nFootnote - 1;
5189         m_rDoc.SetFootnoteInfo( aInfo );
5190     }
5191     if (m_xSBase->AreThereEndnotes())
5192     {
5193         SwEndNoteInfo aInfo = m_rDoc.GetEndNoteInfo(); // Same as for Footnote
5194         sal_uInt16 nfcEdnRef = m_xWDop->nfcEdnRef;
5195         aInfo.m_aFormat.SetNumberingType(WW8ListManager::GetSvxNumTypeFromMSONFC(nfcEdnRef));
5196         if( m_xWDop->nEdn )
5197             aInfo.m_nFootnoteOffset = m_xWDop->nEdn - 1;
5198         m_rDoc.SetEndNoteInfo( aInfo );
5199     }
5200 
5201     if (m_xWwFib->m_lcbPlcfhdd)
5202         m_xHdFt.reset(new WW8PLCF_HdFt(m_pTableStream, *m_xWwFib, *m_xWDop));
5203 
5204     if (!m_bNewDoc)
5205     {
5206         // inserting into an existing document:
5207         // As only complete paragraphs are inserted, the current one
5208         // needs to be split - once or even twice.
5209         const SwPosition* pPos = m_pPaM->GetPoint();
5210 
5211         // split current paragraph to get new paragraph for the insertion
5212         m_rDoc.getIDocumentContentOperations().SplitNode( *pPos, false );
5213 
5214         // another split, if insertion position was not at the end of the current paragraph.
5215         SwTextNode const*const pTextNd = pPos->GetNode().GetTextNode();
5216         if ( pTextNd->GetText().getLength() )
5217         {
5218             m_rDoc.getIDocumentContentOperations().SplitNode( *pPos, false );
5219             // move PaM back to the newly empty paragraph
5220             m_pPaM->Move( fnMoveBackward );
5221         }
5222 
5223         // suppress insertion of tables inside footnotes.
5224         const SwNodeOffset nNd = pPos->GetNodeIndex();
5225         m_bReadNoTable = ( nNd < m_rDoc.GetNodes().GetEndOfInserts().GetIndex() &&
5226                        m_rDoc.GetNodes().GetEndOfInserts().StartOfSectionIndex() < nNd );
5227     }
5228 
5229     m_xProgress->Update(m_nProgress); // Update
5230 
5231     // loop for each glossary entry and add dummy section node
5232     if (pGloss)
5233     {
5234         WW8PLCF aPlc(*m_pTableStream, m_xWwFib->m_fcPlcfglsy, m_xWwFib->m_lcbPlcfglsy, 0);
5235 
5236         WW8_CP nStart, nEnd;
5237         void* pDummy;
5238 
5239         for (int i = 0; i < pGloss->GetNoStrings(); ++i, aPlc.advance())
5240         {
5241             SwNodeIndex aIdx( m_rDoc.GetNodes().GetEndOfContent());
5242             SwTextFormatColl* pColl =
5243                 m_rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD,
5244                 false);
5245             SwStartNode *pNode =
5246                 m_rDoc.GetNodes().MakeTextSection(aIdx.GetNode(),
5247                 SwNormalStartNode,pColl);
5248             m_pPaM->GetPoint()->Assign( pNode->GetIndex()+1 );
5249             aPlc.Get( nStart, nEnd, pDummy );
5250             ReadText(nStart,nEnd-nStart-1,MAN_MAINTEXT);
5251         }
5252     }
5253     else // ordinary case
5254     {
5255         if (m_bNewDoc && m_pStg) /*meaningless for a glossary */
5256         {
5257             m_pDocShell->SetIsTemplate( m_xWwFib->m_fDot ); // point at tgc record
5258             uno::Reference<document::XDocumentPropertiesSupplier> const
5259                 xDocPropSupp(m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
5260             uno::Reference< document::XDocumentProperties > xDocProps( xDocPropSupp->getDocumentProperties(), uno::UNO_SET_THROW );
5261 
5262             OUString sCreatedFrom = xDocProps->getTemplateURL();
5263             uno::Reference< container::XNameContainer > xPrjNameCache;
5264             uno::Reference< lang::XMultiServiceFactory> xSF(m_pDocShell->GetModel(), uno::UNO_QUERY);
5265             if ( xSF.is() )
5266                 xPrjNameCache.set( xSF->createInstance( u"ooo.vba.VBAProjectNameProvider"_ustr ), uno::UNO_QUERY );
5267 
5268             // Read Global templates
5269             ReadGlobalTemplateSettings( sCreatedFrom, xPrjNameCache );
5270 
5271             // Create and insert Word vba Globals
5272             uno::Any aGlobs;
5273             uno::Sequence< uno::Any > aArgs{ uno::Any(m_pDocShell->GetModel()) };
5274             try
5275             {
5276                 aGlobs <<= ::comphelper::getProcessServiceFactory()->createInstanceWithArguments( u"ooo.vba.word.Globals"_ustr, aArgs );
5277             }
5278             catch (const uno::Exception&)
5279             {
5280                 SAL_WARN("sw.ww8", "SwWW8ImplReader::CoreLoad: ooo.vba.word.Globals is not available");
5281             }
5282 
5283 #if HAVE_FEATURE_SCRIPTING
5284             if (!m_bFuzzing)
5285             {
5286                 BasicManager *pBasicMan = m_pDocShell->GetBasicManager();
5287                 if (pBasicMan)
5288                     pBasicMan->SetGlobalUNOConstant( u"VBAGlobals"_ustr, aGlobs );
5289             }
5290 #endif
5291             BasicProjImportHelper aBasicImporter( *m_pDocShell );
5292             // Import vba via oox filter
5293             bool bRet = aBasicImporter.import( m_pDocShell->GetMedium()->GetInputStream() );
5294 
5295             lcl_createTemplateToProjectEntry( xPrjNameCache, sCreatedFrom, aBasicImporter.getProjectName() );
5296             WW8Customizations aCustomisations( m_pTableStream, *m_xWwFib );
5297             aCustomisations.Import( m_pDocShell );
5298 
5299             if( bRet )
5300                 m_rDoc.SetContainsMSVBasic(true);
5301 
5302             StoreMacroCmds();
5303         }
5304         ReadText(0, m_xWwFib->m_ccpText, MAN_MAINTEXT);
5305     }
5306 
5307     m_xProgress->Update(m_nProgress); // Update
5308 
5309     if (m_pDrawPg && m_xMSDffManager && m_xMSDffManager->GetShapeOrders())
5310     {
5311         // Helper array to chain the inserted frames (instead of SdrTextObj)
5312         SvxMSDffShapeTxBxSort aTxBxSort;
5313 
5314         // Ensure correct z-order of read Escher objects
5315         sal_uInt16 nShapeCount = m_xMSDffManager->GetShapeOrders()->size();
5316 
5317         for (sal_uInt16 nShapeNum=0; nShapeNum < nShapeCount; nShapeNum++)
5318         {
5319             SvxMSDffShapeOrder *pOrder =
5320                 (*m_xMSDffManager->GetShapeOrders())[nShapeNum].get();
5321             // Insert Pointer into new Sort array
5322             if (pOrder->nTxBxComp && pOrder->pFly)
5323                 aTxBxSort.insert(pOrder);
5324         }
5325         // Chain Frames
5326         if( !aTxBxSort.empty() )
5327         {
5328             SwFormatChain aChain;
5329             for( SvxMSDffShapeTxBxSort::iterator it = aTxBxSort.begin(); it != aTxBxSort.end(); ++it )
5330             {
5331                 SvxMSDffShapeOrder *pOrder = *it;
5332 
5333                 // Initialize FlyFrame Formats
5334                 SwFlyFrameFormat* pFlyFormat     = pOrder->pFly;
5335                 SwFlyFrameFormat* pNextFlyFormat = nullptr;
5336                 SwFlyFrameFormat* pPrevFlyFormat = nullptr;
5337 
5338                 // Determine successor, if we can
5339                 SvxMSDffShapeTxBxSort::iterator tmpIter1 = it;
5340                 ++tmpIter1;
5341                 if( tmpIter1 != aTxBxSort.end() )
5342                 {
5343                     SvxMSDffShapeOrder *pNextOrder = *tmpIter1;
5344                     if ((0xFFFF0000 & pOrder->nTxBxComp)
5345                            == (0xFFFF0000 & pNextOrder->nTxBxComp))
5346                         pNextFlyFormat = pNextOrder->pFly;
5347                 }
5348                 // Determine predecessor, if we can
5349                 if( it != aTxBxSort.begin() )
5350                 {
5351                     SvxMSDffShapeTxBxSort::iterator tmpIter2 = it;
5352                     --tmpIter2;
5353                     SvxMSDffShapeOrder *pPrevOrder = *tmpIter2;
5354                     if ((0xFFFF0000 & pOrder->nTxBxComp)
5355                            == (0xFFFF0000 & pPrevOrder->nTxBxComp))
5356                         pPrevFlyFormat = pPrevOrder->pFly;
5357                 }
5358                 // If successor or predecessor present, insert the
5359                 // chain at the FlyFrame Format
5360                 if (pNextFlyFormat || pPrevFlyFormat)
5361                 {
5362                     aChain.SetNext( pNextFlyFormat );
5363                     aChain.SetPrev( pPrevFlyFormat );
5364                     pFlyFormat->SetFormatAttr( aChain );
5365                 }
5366             }
5367         }
5368     }
5369 
5370     bool isHideRedlines(false);
5371 
5372     if (m_bNewDoc)
5373     {
5374         if( m_xWDop->fRevMarking )
5375             eMode |= RedlineFlags::On;
5376         isHideRedlines = !m_xWDop->fRMView;
5377     }
5378 
5379     m_aInsertedTables.DelAndMakeTableFrames();
5380     m_aSectionManager.InsertSegments();
5381 
5382     m_vColl.clear();
5383 
5384     m_xStyles.reset();
5385 
5386     m_xFormImpl.reset();
5387     GraphicDtor();
5388     m_xMSDffManager.reset();
5389     m_xHdFt.reset();
5390     m_xSBase.reset();
5391     m_xWDop.reset();
5392     m_xFonts.reset();
5393     m_xAtnNames.reset();
5394     m_oSprmParser.reset();
5395     m_xProgress.reset();
5396 
5397     m_pDataStream = nullptr;
5398     m_pTableStream = nullptr;
5399 
5400     DeleteCtrlStack();
5401     DeleteAnchorStack();
5402     DeleteRefStacks();
5403     m_oLastAnchorPos.reset();//ensure this is deleted before UpdatePageDescs
5404     // ofz#10994 remove any trailing fly paras before processing redlines
5405     m_xWFlyPara.reset();
5406     // ofz#12660 remove any trailing fly paras before deleting extra paras
5407     m_xSFlyPara.reset();
5408     // remove extra paragraphs after attribute ctrl
5409     // stacks etc. are destroyed, and before fields
5410     // are updated
5411     m_aExtraneousParas.delete_all_from_doc();
5412     m_xRedlineStack->closeall(*m_pPaM->GetPoint());
5413 
5414     // For i120928,achieve the graphics from the special bookmark with is for graphic bullet
5415     {
5416         std::vector<const SwGrfNode*> vecBulletGrf;
5417         std::vector<SwFrameFormat*> vecFrameFormat;
5418 
5419         IDocumentMarkAccess* const pMarkAccess = m_rDoc.getIDocumentMarkAccess();
5420         if ( pMarkAccess )
5421         {
5422             IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->findBookmark( u"_PictureBullets"_ustr );
5423             if ( ppBkmk != pMarkAccess->getBookmarksEnd() &&
5424                        IDocumentMarkAccess::GetType(**ppBkmk) == IDocumentMarkAccess::MarkType::BOOKMARK )
5425             {
5426                 SwTextNode* pTextNode = (*ppBkmk)->GetMarkStart().GetNode().GetTextNode();
5427 
5428                 if ( pTextNode )
5429                 {
5430                     const SwpHints* pHints = pTextNode->GetpSwpHints();
5431                     for( size_t nHintPos = 0; pHints && nHintPos < pHints->Count(); ++nHintPos)
5432                     {
5433                         const SwTextAttr *pHt = pHints->Get(nHintPos);
5434                         if (pHt->Which() != RES_TXTATR_FLYCNT)
5435                             continue;
5436                         const sal_Int32 st = pHt->GetStart();
5437                         if (st >= (*ppBkmk)->GetMarkStart().GetContentIndex())
5438                         {
5439                             SwFrameFormat* pFrameFormat = pHt->GetFlyCnt().GetFrameFormat();
5440                             vecFrameFormat.push_back(pFrameFormat);
5441                             const SwNodeIndex* pNdIdx = pFrameFormat->GetContent().GetContentIdx();
5442                             const SwNodes* pNodesArray = (pNdIdx != nullptr)
5443                                                          ? &(pNdIdx->GetNodes())
5444                                                          : nullptr;
5445                             const SwGrfNode *pGrf = (pNodesArray != nullptr)
5446                                                     ? (*pNodesArray)[pNdIdx->GetIndex() + 1]->GetGrfNode()
5447                                                     : nullptr;
5448                             vecBulletGrf.push_back(pGrf);
5449                         }
5450                     }
5451                     // update graphic bullet information
5452                     size_t nCount = m_xLstManager->GetWW8LSTInfoNum();
5453                     for (size_t i = 0; i < nCount; ++i)
5454                     {
5455                         SwNumRule* pRule = m_xLstManager->GetNumRule(i);
5456                         for (sal_uInt16 j = 0; j < MAXLEVEL; ++j)
5457                         {
5458                             SwNumFormat aNumFormat(pRule->Get(j));
5459                             const sal_Int16 nType = aNumFormat.GetNumberingType();
5460                             const sal_uInt16 nGrfBulletCP = aNumFormat.GetGrfBulletCP();
5461                             if ( nType == SVX_NUM_BITMAP
5462                                  && vecBulletGrf.size() > nGrfBulletCP
5463                                  && vecBulletGrf[nGrfBulletCP] != nullptr )
5464                             {
5465                                 Graphic aGraphic = vecBulletGrf[nGrfBulletCP]->GetGrf();
5466                                 SvxBrushItem aBrush(aGraphic, GPOS_AREA, SID_ATTR_BRUSH);
5467                                 const vcl::Font& aFont = numfunc::GetDefBulletFont();
5468                                 int nHeight = aFont.GetFontHeight() * 12;
5469                                 Size aPrefSize( aGraphic.GetPrefSize());
5470                                 if (aPrefSize.Height() * aPrefSize.Width() != 0 )
5471                                 {
5472                                     int nWidth = (nHeight * aPrefSize.Width()) / aPrefSize.Height();
5473                                     Size aSize(nWidth, nHeight);
5474                                     aNumFormat.SetGraphicBrush(&aBrush, &aSize);
5475                                 }
5476                                 else
5477                                 {
5478                                     aNumFormat.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
5479                                     aNumFormat.SetBulletChar(0x2190);
5480                                 }
5481                                 pRule->Set( j, aNumFormat );
5482                             }
5483                         }
5484                     }
5485                     // Remove additional pictures
5486                     for (SwFrameFormat* p : vecFrameFormat)
5487                     {
5488                         m_rDoc.getIDocumentLayoutAccess().DelLayoutFormat(p);
5489                     }
5490                 }
5491             }
5492         }
5493         m_xLstManager.reset();
5494     }
5495 
5496     m_oPosAfterTOC.reset();
5497     m_xRedlineStack.reset();
5498     mpCursor.reset();
5499     m_pPaM = nullptr;
5500 
5501     UpdateFields();
5502 
5503     // delete the pam before the call for hide all redlines (Bug 73683)
5504     if (m_bNewDoc)
5505       m_rDoc.getIDocumentRedlineAccess().SetRedlineFlags(eMode);
5506 
5507     UpdatePageDescs(m_rDoc, nPageDescOffset);
5508 
5509     // can't set it on the layout or view shell because it doesn't exist yet
5510     m_rDoc.GetDocumentRedlineManager().SetHideRedlines(isHideRedlines);
5511 
5512     return ERRCODE_NONE;
5513 }
5514 
SetSubStreams(rtl::Reference<SotStorageStream> & rTableStream,rtl::Reference<SotStorageStream> & rDataStream)5515 ErrCode SwWW8ImplReader::SetSubStreams(rtl::Reference<SotStorageStream>& rTableStream,
5516                                        rtl::Reference<SotStorageStream>& rDataStream)
5517 {
5518     ErrCode nErrRet = ERRCODE_NONE;
5519     // 6 stands for "6 OR 7", 7 stands for "ONLY 7"
5520     switch (m_xWwFib->m_nVersion)
5521     {
5522         case 6:
5523         case 7:
5524             m_pTableStream = m_pStrm;
5525             m_pDataStream = m_pStrm;
5526             break;
5527         case 8:
5528             if(!m_pStg)
5529             {
5530                 OSL_ENSURE( m_pStg, "Version 8 always needs to have a Storage!!" );
5531                 nErrRet = ERR_SWG_READ_ERROR;
5532                 break;
5533             }
5534 
5535             rTableStream = m_pStg->OpenSotStream(
5536                 m_xWwFib->m_fWhichTableStm ? SL::a1Table : SL::a0Table,
5537                 StreamMode::STD_READ);
5538 
5539             m_pTableStream = rTableStream.get();
5540             m_pTableStream->SetEndian( SvStreamEndian::LITTLE );
5541 
5542             rDataStream = m_pStg->OpenSotStream(SL::aData, StreamMode::STD_READ);
5543 
5544             if (rDataStream.is() && ERRCODE_NONE == rDataStream->GetError())
5545             {
5546                 m_pDataStream = rDataStream.get();
5547                 m_pDataStream->SetEndian(SvStreamEndian::LITTLE);
5548             }
5549             else
5550                 m_pDataStream = m_pStrm;
5551             break;
5552         default:
5553             // Program error!
5554             OSL_ENSURE( false, "We forgot to encode nVersion!" );
5555             nErrRet = ERR_SWG_READ_ERROR;
5556             break;
5557     }
5558     return nErrRet;
5559 }
5560 
5561 namespace
5562 {
MakeTemp(std::optional<utl::TempFileFast> & roTempFile)5563     SvStream* MakeTemp(std::optional<utl::TempFileFast>& roTempFile)
5564     {
5565         roTempFile.emplace();
5566         return roTempFile->GetStream(StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE);
5567     }
5568 
5569 #define WW_BLOCKSIZE 0x200
5570 
DecryptRC4(msfilter::MSCodec97 & rCtx,SvStream & rIn,SvStream & rOut)5571     void DecryptRC4(msfilter::MSCodec97& rCtx, SvStream &rIn, SvStream &rOut)
5572     {
5573         const std::size_t nLen = rIn.TellEnd();
5574         rIn.Seek(0);
5575 
5576         sal_uInt8 in[WW_BLOCKSIZE];
5577         for (std::size_t nI = 0, nBlock = 0; nI < nLen; nI += WW_BLOCKSIZE, ++nBlock)
5578         {
5579             std::size_t nBS = std::min<size_t>(nLen - nI, WW_BLOCKSIZE);
5580             nBS = rIn.ReadBytes(in, nBS);
5581             rCtx.InitCipher(nBlock);
5582             rCtx.Decode(in, nBS, in, nBS);
5583             rOut.WriteBytes(in, nBS);
5584         }
5585     }
5586 
DecryptXOR(msfilter::MSCodec_XorWord95 & rCtx,SvStream & rIn,SvStream & rOut)5587     void DecryptXOR(msfilter::MSCodec_XorWord95 &rCtx, SvStream &rIn, SvStream &rOut)
5588     {
5589         std::size_t nSt = rIn.Tell();
5590         std::size_t nLen = rIn.TellEnd();
5591 
5592         rCtx.InitCipher();
5593         rCtx.Skip(nSt);
5594 
5595         sal_uInt8 in[0x4096];
5596         for (std::size_t nI = nSt; nI < nLen; nI += 0x4096)
5597         {
5598             std::size_t nBS = std::min<size_t>(nLen - nI, 0x4096 );
5599             nBS = rIn.ReadBytes(in, nBS);
5600             rCtx.Decode(in, nBS);
5601             rOut.WriteBytes(in, nBS);
5602         }
5603     }
5604 
5605     // moan, copy and paste :-(
QueryPasswordForMedium(SfxMedium & rMedium)5606     OUString QueryPasswordForMedium(SfxMedium& rMedium)
5607     {
5608         OUString aPassw;
5609 
5610         if (const SfxStringItem* pPasswordItem = rMedium.GetItemSet().GetItemIfSet(SID_PASSWORD))
5611             aPassw = pPasswordItem->GetValue();
5612         else
5613         {
5614             try
5615             {
5616                 uno::Reference< task::XInteractionHandler > xHandler( rMedium.GetInteractionHandler() );
5617                 if( xHandler.is() )
5618                 {
5619                     rtl::Reference<::comphelper::DocPasswordRequest> pRequest = new ::comphelper::DocPasswordRequest(
5620                         ::comphelper::DocPasswordRequestType::MS, task::PasswordRequestMode_PASSWORD_ENTER,
5621                         INetURLObject(rMedium.GetOrigURL())
5622                             .GetLastName(INetURLObject::DecodeMechanism::WithCharset));
5623 
5624                     xHandler->handle( pRequest );
5625 
5626                     if( pRequest->isPassword() )
5627                         aPassw = pRequest->getPassword();
5628                 }
5629             }
5630             catch( const uno::Exception& )
5631             {
5632             }
5633         }
5634 
5635         return aPassw;
5636     }
5637 
InitXorWord95Codec(::msfilter::MSCodec_XorWord95 & rCodec,SfxMedium & rMedium,WW8Fib const * pWwFib)5638     uno::Sequence< beans::NamedValue > InitXorWord95Codec( ::msfilter::MSCodec_XorWord95& rCodec, SfxMedium& rMedium, WW8Fib const * pWwFib )
5639     {
5640         uno::Sequence< beans::NamedValue > aEncryptionData;
5641         const SfxUnoAnyItem* pEncryptionData = rMedium.GetItemSet().GetItem(SID_ENCRYPTIONDATA, false);
5642         if ( pEncryptionData && ( pEncryptionData->GetValue() >>= aEncryptionData ) && !rCodec.InitCodec( aEncryptionData ) )
5643             aEncryptionData.realloc( 0 );
5644 
5645         if ( !aEncryptionData.hasElements() )
5646         {
5647             OUString sUniPassword = QueryPasswordForMedium( rMedium );
5648 
5649             OString sPassword(OUStringToOString(sUniPassword,
5650                 WW8Fib::GetFIBCharset(pWwFib->m_chseTables, pWwFib->m_lid)));
5651 
5652             sal_Int32 nLen = sPassword.getLength();
5653             if( nLen <= 15 )
5654             {
5655                 sal_uInt8 pPassword[16];
5656                 memcpy(pPassword, sPassword.getStr(), nLen);
5657                 memset(pPassword+nLen, 0, sizeof(pPassword)-nLen);
5658 
5659                 rCodec.InitKey( pPassword );
5660                 aEncryptionData = rCodec.GetEncryptionData();
5661 
5662                 // the export supports RC4 algorithm only, so we have to
5663                 // generate the related EncryptionData as well, so that Save
5664                 // can export the document without asking for a password;
5665                 // as result there will be EncryptionData for both algorithms
5666                 // in the MediaDescriptor
5667                 ::msfilter::MSCodec_Std97 aCodec97;
5668 
5669                 sal_uInt8 pDocId[ 16 ];
5670                 if (rtl_random_getBytes(nullptr, pDocId, 16) != rtl_Random_E_None)
5671                 {
5672                     throw uno::RuntimeException(u"rtl_random_getBytes failed"_ustr);
5673                 }
5674 
5675                 sal_uInt16 pStd97Pass[16] = {};
5676                 for( sal_Int32 nChar = 0; nChar < nLen; ++nChar )
5677                     pStd97Pass[nChar] = sUniPassword[nChar];
5678 
5679                 aCodec97.InitKey( pStd97Pass, pDocId );
5680 
5681                 // merge the EncryptionData, there should be no conflicts
5682                 ::comphelper::SequenceAsHashMap aEncryptionHash( aEncryptionData );
5683                 aEncryptionHash.update( ::comphelper::SequenceAsHashMap( aCodec97.GetEncryptionData() ) );
5684                 aEncryptionHash >> aEncryptionData;
5685             }
5686         }
5687 
5688         return aEncryptionData;
5689     }
5690 
Init97Codec(msfilter::MSCodec97 & rCodec,sal_uInt8 const pDocId[16],SfxMedium & rMedium)5691     uno::Sequence< beans::NamedValue > Init97Codec(msfilter::MSCodec97& rCodec, sal_uInt8 const pDocId[16], SfxMedium& rMedium)
5692     {
5693         uno::Sequence< beans::NamedValue > aEncryptionData;
5694         const SfxUnoAnyItem* pEncryptionData = rMedium.GetItemSet().GetItem(SID_ENCRYPTIONDATA, false);
5695         if ( pEncryptionData && ( pEncryptionData->GetValue() >>= aEncryptionData ) && !rCodec.InitCodec( aEncryptionData ) )
5696             aEncryptionData.realloc( 0 );
5697 
5698         if ( !aEncryptionData.hasElements() )
5699         {
5700             OUString sUniPassword = QueryPasswordForMedium( rMedium );
5701 
5702             sal_Int32 nLen = sUniPassword.getLength();
5703             if ( nLen <= 15 )
5704             {
5705                 sal_uInt16 pPassword[16] = {};
5706                 for( sal_Int32 nChar = 0; nChar < nLen; ++nChar )
5707                     pPassword[nChar] = sUniPassword[nChar];
5708 
5709                 rCodec.InitKey( pPassword, pDocId );
5710                 aEncryptionData = rCodec.GetEncryptionData();
5711             }
5712         }
5713 
5714         return aEncryptionData;
5715     }
5716 }
5717 
5718 //TO-DO: merge this with lclReadFilepass8_Strong in sc which uses a different
5719 //stream thing
lclReadCryptoAPIHeader(msfilter::RC4EncryptionInfo & info,SvStream & rStream)5720 static bool lclReadCryptoAPIHeader(msfilter::RC4EncryptionInfo &info, SvStream &rStream)
5721 {
5722     //It is possible there are other variants in existence but these
5723     //are the defaults I get with Word 2013
5724 
5725     rStream.ReadUInt32(info.header.flags);
5726     if (oox::getFlag( info.header.flags, msfilter::ENCRYPTINFO_EXTERNAL))
5727         return false;
5728 
5729     sal_uInt32 nHeaderSize(0);
5730     rStream.ReadUInt32(nHeaderSize);
5731     sal_uInt32 actualHeaderSize = sizeof(info.header);
5732 
5733     if (nHeaderSize < actualHeaderSize)
5734         return false;
5735 
5736     rStream.ReadUInt32(info.header.flags);
5737     rStream.ReadUInt32(info.header.sizeExtra);
5738     rStream.ReadUInt32(info.header.algId);
5739     rStream.ReadUInt32(info.header.algIdHash);
5740     rStream.ReadUInt32(info.header.keyBits);
5741     rStream.ReadUInt32(info.header.providedType);
5742     rStream.ReadUInt32(info.header.reserved1);
5743     rStream.ReadUInt32(info.header.reserved2);
5744 
5745     rStream.SeekRel(nHeaderSize - actualHeaderSize);
5746 
5747     rStream.ReadUInt32(info.verifier.saltSize);
5748     if (info.verifier.saltSize != msfilter::SALT_LENGTH)
5749         return false;
5750     rStream.ReadBytes(&info.verifier.salt, sizeof(info.verifier.salt));
5751     rStream.ReadBytes(&info.verifier.encryptedVerifier, sizeof(info.verifier.encryptedVerifier));
5752 
5753     rStream.ReadUInt32(info.verifier.encryptedVerifierHashSize);
5754     if (info.verifier.encryptedVerifierHashSize != RTL_DIGEST_LENGTH_SHA1)
5755         return false;
5756     rStream.ReadBytes(&info.verifier.encryptedVerifierHash, info.verifier.encryptedVerifierHashSize);
5757 
5758     // check flags and algorithm IDs, required are AES128 and SHA-1
5759     if (!oox::getFlag(info.header.flags, msfilter::ENCRYPTINFO_CRYPTOAPI))
5760         return false;
5761 
5762     if (oox::getFlag(info.header.flags, msfilter::ENCRYPTINFO_AES))
5763         return false;
5764 
5765     if (info.header.algId != msfilter::ENCRYPT_ALGO_RC4)
5766         return false;
5767 
5768     // hash algorithm ID 0 defaults to SHA-1 too
5769     if (info.header.algIdHash != 0 && info.header.algIdHash != msfilter::ENCRYPT_HASH_SHA1)
5770         return false;
5771 
5772     return true;
5773 }
5774 
LoadThroughDecryption(WW8Glossary * pGloss)5775 ErrCode SwWW8ImplReader::LoadThroughDecryption(WW8Glossary *pGloss)
5776 {
5777     ErrCode nErrRet = ERRCODE_NONE;
5778     if (pGloss)
5779         m_xWwFib = pGloss->GetFib();
5780     else
5781         m_xWwFib = std::make_shared<WW8Fib>(*m_pStrm, m_nWantedVersion);
5782 
5783     if (m_xWwFib->m_nFibError)
5784         nErrRet = ERR_SWG_READ_ERROR;
5785 
5786     rtl::Reference<SotStorageStream> xTableStream, xDataStream;
5787 
5788     if (!nErrRet)
5789         nErrRet = SetSubStreams(xTableStream, xDataStream);
5790 
5791     std::optional<utl::TempFileFast> oTempMain;
5792     std::optional<utl::TempFileFast> oTempTable;
5793     std::optional<utl::TempFileFast> oTempData;
5794     SvStream* pDecryptMain = nullptr;
5795     SvStream* pDecryptTable = nullptr;
5796     SvStream* pDecryptData = nullptr;
5797 
5798     bool bDecrypt = false;
5799     enum {RC4CryptoAPI, RC4, XOR, Other} eAlgo = Other;
5800     if (m_xWwFib->m_fEncrypted && !nErrRet)
5801     {
5802         if (!pGloss)
5803         {
5804             bDecrypt = true;
5805             if (8 != m_xWwFib->m_nVersion)
5806                 eAlgo = XOR;
5807             else
5808             {
5809                 if (m_xWwFib->m_nKey != 0)
5810                     eAlgo = XOR;
5811                 else
5812                 {
5813                     m_pTableStream->Seek(0);
5814                     sal_uInt32 nEncType(0);
5815                     m_pTableStream->ReadUInt32(nEncType);
5816                     if (nEncType == msfilter::VERSION_INFO_1997_FORMAT)
5817                         eAlgo = RC4;
5818                     else if (nEncType == msfilter::VERSION_INFO_2007_FORMAT || nEncType == msfilter::VERSION_INFO_2007_FORMAT_SP2)
5819                         eAlgo = RC4CryptoAPI;
5820                 }
5821             }
5822         }
5823     }
5824 
5825     if (bDecrypt)
5826     {
5827         nErrRet = ERRCODE_SVX_WRONGPASS;
5828         SfxMedium* pMedium = m_pDocShell->GetMedium();
5829 
5830         if ( pMedium )
5831         {
5832             switch (eAlgo)
5833             {
5834                 default:
5835                     nErrRet = ERRCODE_SVX_READ_FILTER_CRYPT;
5836                     break;
5837                 case XOR:
5838                 {
5839                     msfilter::MSCodec_XorWord95 aCtx;
5840                     uno::Sequence< beans::NamedValue > aEncryptionData = InitXorWord95Codec(aCtx, *pMedium, m_xWwFib.get());
5841 
5842                     // if initialization has failed the EncryptionData should be empty
5843                     if (aEncryptionData.hasElements() && aCtx.VerifyKey(m_xWwFib->m_nKey, m_xWwFib->m_nHash))
5844                     {
5845                         nErrRet = ERRCODE_NONE;
5846                         pDecryptMain = MakeTemp(oTempMain);
5847 
5848                         m_pStrm->Seek(0);
5849                         size_t nUnencryptedHdr =
5850                             (8 == m_xWwFib->m_nVersion) ? 0x44 : 0x34;
5851                         std::unique_ptr<sal_uInt8[]> pIn(new sal_uInt8[nUnencryptedHdr]);
5852                         nUnencryptedHdr = m_pStrm->ReadBytes(pIn.get(), nUnencryptedHdr);
5853                         pDecryptMain->WriteBytes(pIn.get(), nUnencryptedHdr);
5854                         pIn.reset();
5855 
5856                         DecryptXOR(aCtx, *m_pStrm, *pDecryptMain);
5857 
5858                         if (!m_pTableStream || m_pTableStream == m_pStrm)
5859                             m_pTableStream = pDecryptMain;
5860                         else
5861                         {
5862                             pDecryptTable = MakeTemp(oTempTable);
5863                             DecryptXOR(aCtx, *m_pTableStream, *pDecryptTable);
5864                             m_pTableStream = pDecryptTable;
5865                         }
5866 
5867                         if (!m_pDataStream || m_pDataStream == m_pStrm)
5868                             m_pDataStream = pDecryptMain;
5869                         else
5870                         {
5871                             pDecryptData = MakeTemp(oTempData);
5872                             DecryptXOR(aCtx, *m_pDataStream, *pDecryptData);
5873                             m_pDataStream = pDecryptData;
5874                         }
5875 
5876                         pMedium->GetItemSet().ClearItem( SID_PASSWORD );
5877                         pMedium->GetItemSet().Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::Any( aEncryptionData ) ) );
5878                     }
5879                 }
5880                 break;
5881                 case RC4:
5882                 case RC4CryptoAPI:
5883                 {
5884                     std::unique_ptr<msfilter::MSCodec97> xCtx;
5885                     msfilter::RC4EncryptionInfo info;
5886                     bool bCouldReadHeaders;
5887 
5888                     if (eAlgo == RC4)
5889                     {
5890                         xCtx.reset(new msfilter::MSCodec_Std97);
5891                         assert(sizeof(info.verifier.encryptedVerifierHash) >= RTL_DIGEST_LENGTH_MD5);
5892                         bCouldReadHeaders =
5893                             checkRead(*m_pTableStream, info.verifier.salt, sizeof(info.verifier.salt)) &&
5894                             checkRead(*m_pTableStream, info.verifier.encryptedVerifier, sizeof(info.verifier.encryptedVerifier)) &&
5895                             checkRead(*m_pTableStream, info.verifier.encryptedVerifierHash, RTL_DIGEST_LENGTH_MD5);
5896                     }
5897                     else
5898                     {
5899                         xCtx.reset(new msfilter::MSCodec_CryptoAPI);
5900                         bCouldReadHeaders = lclReadCryptoAPIHeader(info, *m_pTableStream);
5901                     }
5902 
5903                     // if initialization has failed the EncryptionData should be empty
5904                     uno::Sequence< beans::NamedValue > aEncryptionData;
5905                     if (bCouldReadHeaders)
5906                         aEncryptionData = Init97Codec(*xCtx, info.verifier.salt, *pMedium);
5907                     else
5908                         nErrRet = ERRCODE_SVX_READ_FILTER_CRYPT;
5909                     if (aEncryptionData.hasElements() && xCtx->VerifyKey(info.verifier.encryptedVerifier,
5910                                                                        info.verifier.encryptedVerifierHash))
5911                     {
5912                         nErrRet = ERRCODE_NONE;
5913 
5914                         pDecryptMain = MakeTemp(oTempMain);
5915 
5916                         m_pStrm->Seek(0);
5917                         std::size_t nUnencryptedHdr = 0x44;
5918                         std::unique_ptr<sal_uInt8[]> pIn(new sal_uInt8[nUnencryptedHdr]);
5919                         nUnencryptedHdr = m_pStrm->ReadBytes(pIn.get(), nUnencryptedHdr);
5920 
5921                         DecryptRC4(*xCtx, *m_pStrm, *pDecryptMain);
5922 
5923                         pDecryptMain->Seek(0);
5924                         pDecryptMain->WriteBytes(pIn.get(), nUnencryptedHdr);
5925                         pIn.reset();
5926 
5927                         pDecryptTable = MakeTemp(oTempTable);
5928                         DecryptRC4(*xCtx, *m_pTableStream, *pDecryptTable);
5929                         m_pTableStream = pDecryptTable;
5930 
5931                         if (!m_pDataStream || m_pDataStream == m_pStrm)
5932                             m_pDataStream = pDecryptMain;
5933                         else
5934                         {
5935                             pDecryptData = MakeTemp(oTempData);
5936                             DecryptRC4(*xCtx, *m_pDataStream, *pDecryptData);
5937                             m_pDataStream = pDecryptData;
5938                         }
5939 
5940                         pMedium->GetItemSet().ClearItem( SID_PASSWORD );
5941                         pMedium->GetItemSet().Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::Any( aEncryptionData ) ) );
5942                     }
5943                 }
5944                 break;
5945             }
5946         }
5947 
5948         if (nErrRet == ERRCODE_NONE)
5949         {
5950             m_pStrm = pDecryptMain;
5951             assert(m_pStrm);
5952             m_xWwFib = std::make_shared<WW8Fib>(*m_pStrm, m_nWantedVersion);
5953             if (m_xWwFib->m_nFibError)
5954                 nErrRet = ERR_SWG_READ_ERROR;
5955         }
5956     }
5957 
5958     if (!nErrRet)
5959         nErrRet = CoreLoad(pGloss);
5960 
5961     oTempMain.reset();
5962     oTempTable.reset();
5963     oTempData.reset();
5964 
5965     m_xWwFib.reset();
5966     return nErrRet;
5967 }
5968 
SetOutlineStyles()5969 void SwWW8ImplReader::SetOutlineStyles()
5970 {
5971     // If we are inserted into a document then don't clobber existing outline
5972     // levels.
5973     sal_uInt16 nOutlineStyleListLevelWithAssignment = 0;
5974     if (!m_bNewDoc)
5975     {
5976         ww8::ParaStyles aOutLined(sw::util::GetParaStyles(m_rDoc));
5977         sw::util::SortByAssignedOutlineStyleListLevel(aOutLined);
5978         ww8::ParaStyles::reverse_iterator aEnd = aOutLined.rend();
5979         for ( ww8::ParaStyles::reverse_iterator aIter = aOutLined.rbegin(); aIter < aEnd; ++aIter)
5980         {
5981             if ((*aIter)->IsAssignedToListLevelOfOutlineStyle())
5982                 nOutlineStyleListLevelWithAssignment |= 1 << (*aIter)->GetAssignedOutlineStyleLevel();
5983             else
5984                 break;
5985         }
5986     }
5987 
5988     // Check applied WW8 list styles at WW8 Built-In Heading Styles
5989     // - Choose the list style which occurs most often as the one which provides
5990     //   the list level properties for the Outline Style.
5991     // - Populate temporary list of WW8 Built-In Heading Styles for further
5992     // iteration
5993     std::vector<SwWW8StyInf*> aWW8BuiltInHeadingStyles;
5994     {
5995         sal_uInt16 nStyle = 0;
5996         std::map<const SwNumRule*, int> aWW8ListStyleCounts;
5997         std::map<const SwNumRule*, bool> aPreventUseAsChapterNumbering;
5998         for (SwWW8StyInf& rSI : m_vColl)
5999         {
6000             // Copy inherited numbering info since LO drops inheritance after ChapterNumbering
6001             // and only applies listLevel via style with the selected ChapterNumbering LFO.
6002             bool bReRegister = false;
6003             if (rSI.m_nBase && rSI.m_nBase < m_vColl.size()
6004                 && m_vColl[rSI.m_nBase].HasWW8OutlineLevel())
6005             {
6006                 if (rSI.m_nLFOIndex == USHRT_MAX)
6007                 {
6008                     rSI.m_nLFOIndex = m_vColl[rSI.m_nBase].m_nLFOIndex;
6009 
6010                     // When ANYTHING is wrong or strange, prohibit eligibility for ChapterNumbering.
6011                     // A style never inherits numbering from Chapter Numbering.
6012                     if (rSI.m_nLFOIndex != USHRT_MAX)
6013                     {
6014                         const SwNumRule* pNumRule = m_vColl[rSI.m_nBase].m_pOutlineNumrule;
6015                         if (pNumRule)
6016                             aPreventUseAsChapterNumbering[pNumRule] = true;
6017                     }
6018                 }
6019                 if (rSI.m_nListLevel == MAXLEVEL)
6020                     rSI.m_nListLevel = m_vColl[rSI.m_nBase].m_nListLevel;
6021                 if (rSI.mnWW8OutlineLevel == MAXLEVEL)
6022                     rSI.mnWW8OutlineLevel = m_vColl[rSI.m_nBase].mnWW8OutlineLevel;
6023                 bReRegister = true;
6024             }
6025 
6026             // Undefined listLevel is treated as the first level with valid numbering rule.
6027             if (rSI.m_nLFOIndex < USHRT_MAX && rSI.m_nListLevel == MAXLEVEL)
6028             {
6029                 rSI.m_nListLevel = 0;
6030                 bReRegister = true;
6031             }
6032 
6033             if (bReRegister)
6034                 RegisterNumFormatOnStyle(nStyle);
6035 
6036             ++nStyle; // increment before the first "continue";
6037 
6038             if (!rSI.m_bColl || !rSI.IsWW8BuiltInHeadingStyle() || !rSI.HasWW8OutlineLevel())
6039             {
6040                 continue;
6041             }
6042 
6043             // When ANYTHING is wrong or strange, prohibit eligibility for ChapterNumbering.
6044             if (rSI.IsOutlineNumbered() && rSI.m_nListLevel != rSI.mnWW8OutlineLevel)
6045             {
6046                 aPreventUseAsChapterNumbering[rSI.m_pOutlineNumrule] = true;
6047             }
6048 
6049             aWW8BuiltInHeadingStyles.push_back(&rSI);
6050 
6051             const SwNumRule* pWW8ListStyle = rSI.GetOutlineNumrule();
6052             if (pWW8ListStyle != nullptr)
6053             {
6054                 std::map<const SwNumRule*, int>::iterator aCountIter
6055                     = aWW8ListStyleCounts.find(pWW8ListStyle);
6056                 if (aCountIter == aWW8ListStyleCounts.end())
6057                 {
6058                     aWW8ListStyleCounts[pWW8ListStyle] = 1;
6059                 }
6060                 else
6061                 {
6062                     ++(aCountIter->second);
6063                 }
6064             }
6065         }
6066 
6067         int nCurrentMaxCount = 0;
6068         for (const auto& rEntry : aWW8ListStyleCounts)
6069         {
6070             if (aPreventUseAsChapterNumbering[rEntry.first])
6071                 continue;
6072 
6073             if (rEntry.second > nCurrentMaxCount)
6074             {
6075                 nCurrentMaxCount = rEntry.second;
6076                 m_pChosenWW8OutlineStyle = rEntry.first;
6077             }
6078         }
6079     }
6080 
6081     // - set list level properties of Outline Style - ODF's list style applied
6082     // by default to headings
6083     // - assign corresponding Heading Paragraph Styles to the Outline Style
6084     // - If a heading Paragraph Styles is not applying the WW8 list style which
6085     // had been chosen as
6086     //   the one which provides the list level properties for the Outline Style,
6087     // its assignment to
6088     //   the Outline Style is removed. A potential applied WW8 list style is
6089     // assigned directly and
6090     //   its default outline level is applied.
6091     SwNumRule aOutlineRule(*m_rDoc.GetOutlineNumRule());
6092     if (m_pChosenWW8OutlineStyle)
6093     {
6094         for (int i = 0; i < WW8ListManager::nMaxLevel; ++i)
6095         {
6096             // Don't clobber existing outline levels.
6097             const sal_uInt16 nLevel = 1 << i;
6098             if (!(nOutlineStyleListLevelWithAssignment & nLevel))
6099                 aOutlineRule.Set(i, m_pChosenWW8OutlineStyle->Get(i));
6100         }
6101     }
6102 
6103     for (const SwWW8StyInf* pStyleInf : aWW8BuiltInHeadingStyles)
6104     {
6105         const sal_uInt16 nOutlineStyleListLevelOfWW8BuiltInHeadingStyle
6106             = 1 << pStyleInf->mnWW8OutlineLevel;
6107         if (nOutlineStyleListLevelOfWW8BuiltInHeadingStyle
6108             & nOutlineStyleListLevelWithAssignment)
6109         {
6110             continue;
6111         }
6112 
6113         // in case that there are more styles on this level ignore them
6114         nOutlineStyleListLevelWithAssignment
6115             |= nOutlineStyleListLevelOfWW8BuiltInHeadingStyle;
6116 
6117         SwTextFormatColl* pTextFormatColl = static_cast<SwTextFormatColl*>(pStyleInf->m_pFormat);
6118         if (pStyleInf->GetOutlineNumrule() != m_pChosenWW8OutlineStyle
6119             || (pStyleInf->m_nListLevel < WW8ListManager::nMaxLevel
6120                 && pStyleInf->mnWW8OutlineLevel != pStyleInf->m_nListLevel))
6121         {
6122             // WW8 Built-In Heading Style does not apply the chosen one.
6123             // --> delete assignment to OutlineStyle, but keep its current
6124             // outline level
6125             pTextFormatColl->DeleteAssignmentToListLevelOfOutlineStyle();
6126             // Apply existing WW8 list style a normal list style at the
6127             // Paragraph Style
6128             if (pStyleInf->GetOutlineNumrule() != nullptr)
6129             {
6130                 pTextFormatColl->SetFormatAttr(
6131                     SwNumRuleItem(pStyleInf->GetOutlineNumrule()->GetName()));
6132             }
6133             // apply default outline level of WW8 Built-in Heading Style
6134             const sal_uInt8 nOutlineLevel
6135                 = SwWW8StyInf::WW8OutlineLevelToOutlinelevel(
6136                     pStyleInf->mnWW8OutlineLevel);
6137             pTextFormatColl->SetFormatAttr(
6138                 SfxUInt16Item(RES_PARATR_OUTLINELEVEL, nOutlineLevel));
6139         }
6140         else
6141         {
6142             pTextFormatColl->AssignToListLevelOfOutlineStyle(
6143                 pStyleInf->mnWW8OutlineLevel);
6144         }
6145     }
6146 
6147     if (m_pChosenWW8OutlineStyle)
6148     {
6149         m_rDoc.SetOutlineNumRule(aOutlineRule);
6150     }
6151 }
6152 
GetAnnotationAuthor(sal_uInt16 nIdx)6153 const OUString* SwWW8ImplReader::GetAnnotationAuthor(sal_uInt16 nIdx)
6154 {
6155     if (!m_xAtnNames && m_xWwFib->m_lcbGrpStAtnOwners)
6156     {
6157         // Determine authors: can be found in the TableStream
6158         m_xAtnNames.emplace();
6159         SvStream& rStrm = *m_pTableStream;
6160 
6161         auto nOldPos = rStrm.Tell();
6162         bool bValidPos = checkSeek(rStrm, m_xWwFib->m_fcGrpStAtnOwners);
6163         if (bValidPos)
6164         {
6165             tools::Long nRead = 0, nCount = m_xWwFib->m_lcbGrpStAtnOwners;
6166             while (nRead < nCount && rStrm.good())
6167             {
6168                 if( m_bVer67 )
6169                 {
6170                     m_xAtnNames->push_back(read_uInt8_PascalString(rStrm,
6171                         RTL_TEXTENCODING_MS_1252));
6172                     nRead += m_xAtnNames->rbegin()->getLength() + 1; // Length + sal_uInt8 count
6173                 }
6174                 else
6175                 {
6176                     m_xAtnNames->push_back(read_uInt16_PascalString(rStrm));
6177                     // Unicode: double the length + sal_uInt16 count
6178                     nRead += (m_xAtnNames->rbegin()->getLength() + 1)*2;
6179                 }
6180             }
6181         }
6182         rStrm.Seek( nOldPos );
6183     }
6184 
6185     const OUString *pRet = nullptr;
6186     if (m_xAtnNames && nIdx < m_xAtnNames->size())
6187         pRet = &((*m_xAtnNames)[nIdx]);
6188     return pRet;
6189 }
6190 
GetSmartTagInfo(SwFltRDFMark & rMark)6191 void SwWW8ImplReader::GetSmartTagInfo(SwFltRDFMark& rMark)
6192 {
6193     if (!m_pSmartTagData && m_xWwFib->m_lcbFactoidData)
6194     {
6195         m_pSmartTagData.reset(new WW8SmartTagData);
6196         m_pSmartTagData->Read(*m_pTableStream, m_xWwFib->m_fcFactoidData, m_xWwFib->m_lcbFactoidData);
6197     }
6198 
6199     if (!m_pSmartTagData)
6200         return;
6201 
6202     // Check if the handle is a valid smart tag bookmark index.
6203     size_t nIndex = rMark.GetHandle();
6204     if (nIndex >= m_pSmartTagData->m_aPropBags.size())
6205         return;
6206 
6207     // Check if the smart tag bookmark refers to a valid factoid type.
6208     const MSOPropertyBag& rPropertyBag = m_pSmartTagData->m_aPropBags[rMark.GetHandle()];
6209     auto& rFactoidTypes = m_pSmartTagData->m_aPropBagStore.m_aFactoidTypes;
6210     auto itPropertyBag = std::find_if(rFactoidTypes.begin(), rFactoidTypes.end(),
6211         [&rPropertyBag](const MSOFactoidType& rType) { return rType.m_nId == rPropertyBag.m_nId; });
6212     if (itPropertyBag == rFactoidTypes.end())
6213         return;
6214 
6215     // Check if the factoid is an RDF one.
6216     const MSOFactoidType& rFactoidType = *itPropertyBag;
6217     if (rFactoidType.m_aUri != "http://www.w3.org/1999/02/22-rdf-syntax-ns#")
6218         return;
6219 
6220     // Finally put the relevant attributes to the mark.
6221     std::vector< std::pair<OUString, OUString> > aAttributes;
6222     for (const MSOProperty& rProperty : rPropertyBag.m_aProperties)
6223     {
6224         OUString aKey;
6225         OUString aValue;
6226         if (rProperty.m_nKey < m_pSmartTagData->m_aPropBagStore.m_aStringTable.size())
6227             aKey = m_pSmartTagData->m_aPropBagStore.m_aStringTable[rProperty.m_nKey];
6228         if (rProperty.m_nValue < m_pSmartTagData->m_aPropBagStore.m_aStringTable.size())
6229             aValue = m_pSmartTagData->m_aPropBagStore.m_aStringTable[rProperty.m_nValue];
6230         if (!aKey.isEmpty() && !aValue.isEmpty())
6231             aAttributes.emplace_back(aKey, aValue);
6232     }
6233     rMark.SetAttributes(std::move(aAttributes));
6234 }
6235 
LoadDoc(WW8Glossary * pGloss)6236 ErrCode SwWW8ImplReader::LoadDoc(WW8Glossary *pGloss)
6237 {
6238     ErrCode nErrRet = ERRCODE_NONE;
6239 
6240     {
6241         static constexpr OUString aNames[ 13 ] = {
6242             u"WinWord/WW"_ustr, u"WinWord/WW8"_ustr, u"WinWord/WWFT"_ustr,
6243             u"WinWord/WWFLX"_ustr, u"WinWord/WWFLY"_ustr,
6244             u"WinWord/WWF"_ustr,
6245             u"WinWord/WWFA0"_ustr, u"WinWord/WWFA1"_ustr, u"WinWord/WWFA2"_ustr,
6246             u"WinWord/WWFB0"_ustr, u"WinWord/WWFB1"_ustr, u"WinWord/WWFB2"_ustr,
6247             u"WinWord/RegardHindiDigits"_ustr
6248         };
6249         sal_uInt64 aVal[ 13 ];
6250 
6251         SwFilterOptions aOpt( 13, aNames, aVal );
6252 
6253         m_nIniFlags = aVal[ 0 ];
6254         m_nIniFlags1= aVal[ 1 ];
6255         // Moves Flys by x twips to the right or left
6256         m_nIniFlyDx = aVal[ 3 ];
6257         m_nIniFlyDy = aVal[ 4 ];
6258 
6259         m_nFieldFlags = aVal[ 5 ];
6260         m_nFieldTagAlways[0] = aVal[ 6 ];
6261         m_nFieldTagAlways[1] = aVal[ 7 ];
6262         m_nFieldTagAlways[2] = aVal[ 8 ];
6263         m_nFieldTagBad[0] = aVal[ 9 ];
6264         m_nFieldTagBad[1] = aVal[ 10 ];
6265         m_nFieldTagBad[2] = aVal[ 11 ];
6266         m_bRegardHindiDigits = aVal[ 12 ] > 0;
6267     }
6268 
6269     sal_uInt16 nMagic(0);
6270     m_pStrm->ReadUInt16( nMagic );
6271 
6272     // Remember: 6 means "6 OR 7", 7 means "JUST 7"
6273     switch (m_nWantedVersion)
6274     {
6275         case 6:
6276         case 7:
6277             if (
6278                  0xa59b != nMagic && 0xa59c != nMagic &&
6279                  0xa5dc != nMagic && 0xa5db != nMagic &&
6280                  (nMagic < 0xa697 || nMagic > 0xa699)
6281                )
6282             {
6283                 // Test for own 97 fake!
6284                 if (m_pStg && 0xa5ec == nMagic)
6285                 {
6286                     sal_uInt64 nCurPos = m_pStrm->Tell();
6287                     if (checkSeek(*m_pStrm, nCurPos + 2))
6288                     {
6289                         sal_uInt32 nfcMin(0);
6290                         m_pStrm->ReadUInt32( nfcMin );
6291                         if (0x300 != nfcMin)
6292                             nErrRet = ERR_WW6_NO_WW6_FILE_ERR;
6293                     }
6294                     m_pStrm->Seek( nCurPos );
6295                 }
6296                 else
6297                     nErrRet = ERR_WW6_NO_WW6_FILE_ERR;
6298             }
6299             break;
6300         case 8:
6301             if (0xa5ec != nMagic)
6302                 nErrRet = ERR_WW8_NO_WW8_FILE_ERR;
6303             break;
6304         default:
6305             nErrRet = ERR_WW8_NO_WW8_FILE_ERR;
6306             OSL_ENSURE( false, "We forgot to encode nVersion!" );
6307             break;
6308     }
6309 
6310     if (!nErrRet)
6311         nErrRet = LoadThroughDecryption(pGloss);
6312 
6313     m_rDoc.PropagateOutlineRule();
6314 
6315     return nErrRet;
6316 }
6317 
ImportDOC()6318 extern "C" SAL_DLLPUBLIC_EXPORT Reader* ImportDOC()
6319 {
6320     return new WW8Reader;
6321 }
6322 
6323 namespace
6324 {
6325     class FontCacheGuard
6326     {
6327     public:
~FontCacheGuard()6328         ~FontCacheGuard()
6329         {
6330             FlushFontCache();
6331         }
6332     };
6333 }
6334 
TestImportDOC(SvStream & rStream,const OUString & rFltName)6335 bool TestImportDOC(SvStream &rStream, const OUString &rFltName)
6336 {
6337     FontCacheGuard aFontCacheGuard;
6338     std::unique_ptr<Reader> xReader(ImportDOC());
6339 
6340     rtl::Reference<SotStorage> xStorage;
6341     xReader->m_pStream = &rStream;
6342     if (rFltName != "WW6")
6343     {
6344         try
6345         {
6346             xStorage.set(new SotStorage(rStream));
6347             if (xStorage->GetError())
6348                 return false;
6349         }
6350         catch (...)
6351         {
6352             return false;
6353         }
6354         xReader->m_pStorage = xStorage.get();
6355     }
6356     xReader->SetFltName(rFltName);
6357 
6358     SwGlobals::ensure();
6359 
6360     SfxObjectShellLock xDocSh(new SwDocShell(SfxObjectCreateMode::INTERNAL));
6361     xDocSh->DoInitNew();
6362     SwDoc *pD =  static_cast<SwDocShell*>((&xDocSh))->GetDoc();
6363 
6364     SwPaM aPaM(pD->GetNodes().GetEndOfContent(), SwNodeOffset(-1));
6365     pD->SetInReading(true);
6366     bool bRet = xReader->Read(*pD, OUString(), aPaM, OUString()) == ERRCODE_NONE;
6367     pD->SetInReading(false);
6368 
6369     return bRet;
6370 }
6371 
TestImportWW8(SvStream & rStream)6372 extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportWW8(SvStream &rStream)
6373 {
6374     return TestImportDOC(rStream, u"CWW8"_ustr);
6375 }
6376 
TestImportWW6(SvStream & rStream)6377 extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportWW6(SvStream &rStream)
6378 {
6379     return TestImportDOC(rStream, u"CWW6"_ustr);
6380 }
6381 
TestImportWW2(SvStream & rStream)6382 extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportWW2(SvStream &rStream)
6383 {
6384     return TestImportDOC(rStream, u"WW6"_ustr);
6385 }
6386 
OpenMainStream(rtl::Reference<SotStorageStream> & rRef,sal_uInt16 & rBuffSize)6387 ErrCode WW8Reader::OpenMainStream(rtl::Reference<SotStorageStream>& rRef, sal_uInt16& rBuffSize)
6388 {
6389     ErrCode nRet = ERR_SWG_READ_ERROR;
6390     OSL_ENSURE(m_pStorage, "Where is my Storage?");
6391     rRef = m_pStorage->OpenSotStream( u"WordDocument"_ustr, StreamMode::READ | StreamMode::SHARE_DENYALL);
6392 
6393     if( rRef.is() )
6394     {
6395         if( ERRCODE_NONE == rRef->GetError() )
6396         {
6397             sal_uInt16 nOld = rRef->GetBufferSize();
6398             rRef->SetBufferSize( rBuffSize );
6399             rBuffSize = nOld;
6400             nRet = ERRCODE_NONE;
6401         }
6402         else
6403             nRet = rRef->GetError();
6404     }
6405     return nRet;
6406 }
6407 
lcl_getListOfStreams(SotStorage * pStorage,comphelper::SequenceAsHashMap & aStreamsData,std::u16string_view sPrefix)6408 static void lcl_getListOfStreams(SotStorage * pStorage, comphelper::SequenceAsHashMap& aStreamsData, std::u16string_view sPrefix)
6409 {
6410     SvStorageInfoList aElements;
6411     pStorage->FillInfoList(&aElements);
6412     for (const auto & aElement : aElements)
6413     {
6414         OUString sStreamFullName = sPrefix.size() ? OUString::Concat(sPrefix) + "/" + aElement.GetName() : aElement.GetName();
6415         if (aElement.IsStorage())
6416         {
6417             rtl::Reference<SotStorage> xSubStorage = pStorage->OpenSotStorage(aElement.GetName(), StreamMode::STD_READ | StreamMode::SHARE_DENYALL);
6418             lcl_getListOfStreams(xSubStorage.get(), aStreamsData, sStreamFullName);
6419         }
6420         else
6421         {
6422             // Read stream
6423             rtl::Reference<SotStorageStream> rStream = pStorage->OpenSotStream(aElement.GetName(), StreamMode::READ | StreamMode::SHARE_DENYALL);
6424             if (rStream.is())
6425             {
6426                 sal_Int32 nStreamSize = rStream->GetSize();
6427                 css::uno::Sequence< sal_Int8 > oData;
6428                 oData.realloc(nStreamSize);
6429                 sal_Int32 nReadBytes = rStream->ReadBytes(oData.getArray(), nStreamSize);
6430                 if (nStreamSize == nReadBytes)
6431                     aStreamsData[sStreamFullName] <<= oData;
6432             }
6433         }
6434     }
6435 }
6436 
DecryptDRMPackage()6437 ErrCode WW8Reader::DecryptDRMPackage()
6438 {
6439     // We have DRM encrypted storage. We should try to decrypt it first, if we can
6440     uno::Sequence< uno::Any > aArguments;
6441     uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext());
6442     uno::Reference< packages::XPackageEncryption > xPackageEncryption(
6443         xComponentContext->getServiceManager()->createInstanceWithArgumentsAndContext(
6444             u"com.sun.star.comp.oox.crypto.DRMDataSpace"_ustr, aArguments, xComponentContext), uno::UNO_QUERY);
6445 
6446     if (!xPackageEncryption.is())
6447     {
6448         // We do not know how to decrypt this
6449         return ERRCODE_IO_ACCESSDENIED;
6450     }
6451 
6452     comphelper::SequenceAsHashMap aStreamsData;
6453     lcl_getListOfStreams(m_pStorage.get(), aStreamsData, u"");
6454 
6455     try {
6456         uno::Sequence<beans::NamedValue> aStreams = aStreamsData.getAsConstNamedValueList();
6457         if (!xPackageEncryption->readEncryptionInfo(aStreams))
6458         {
6459             // We failed with decryption
6460             return ERRCODE_IO_ACCESSDENIED;
6461         }
6462 
6463         rtl::Reference<SotStorageStream> rContentStream = m_pStorage->OpenSotStream(u"\011DRMContent"_ustr, StreamMode::READ | StreamMode::SHARE_DENYALL);
6464         if (!rContentStream.is())
6465         {
6466             return ERRCODE_IO_NOTEXISTS;
6467         }
6468 
6469         mDecodedStream = std::make_shared<SvMemoryStream>();
6470 
6471         uno::Reference<io::XInputStream > xInputStream(new utl::OSeekableInputStreamWrapper(rContentStream.get(), false));
6472         uno::Reference<io::XOutputStream > xDecryptedStream(new utl::OSeekableOutputStreamWrapper(*mDecodedStream));
6473 
6474         if (!xPackageEncryption->decrypt(xInputStream, xDecryptedStream))
6475         {
6476             // We failed with decryption
6477             return ERRCODE_IO_ACCESSDENIED;
6478         }
6479 
6480         mDecodedStream->Seek(0);
6481 
6482         // Further reading is done from new document
6483         m_pStorage = new SotStorage(*mDecodedStream);
6484 
6485         // Set the media descriptor data
6486         uno::Sequence<beans::NamedValue> aEncryptionData = xPackageEncryption->createEncryptionData(u""_ustr);
6487         m_pMedium->GetItemSet().Put(SfxUnoAnyItem(SID_ENCRYPTIONDATA, uno::Any(aEncryptionData)));
6488     }
6489     catch (const std::exception&)
6490     {
6491         return ERRCODE_IO_ACCESSDENIED;
6492     }
6493 
6494     return ERRCODE_NONE;
6495 }
6496 
Read(SwDoc & rDoc,const OUString & rBaseURL,SwPaM & rPaM,const OUString &)6497 ErrCodeMsg WW8Reader::Read(SwDoc &rDoc, const OUString& rBaseURL, SwPaM &rPaM, const OUString & /* FileName */)
6498 {
6499     sal_uInt16 nOldBuffSize = 32768;
6500     bool bNew = !m_bInsertMode; // New Doc (no inserting)
6501 
6502     rtl::Reference<SotStorageStream> refStrm; // So that no one else can steal the Stream
6503     SvStream* pIn = m_pStream;
6504 
6505     ErrCode nRet = ERRCODE_NONE;
6506     sal_uInt8 nVersion = 8;
6507 
6508     const OUString sFltName = GetFltName();
6509     if ( sFltName=="WW6" )
6510     {
6511         if (m_pStream)
6512             nVersion = 6;
6513         else
6514         {
6515             OSL_ENSURE(false, "WinWord 95 Reader-Read without Stream");
6516             nRet = ERR_SWG_READ_ERROR;
6517         }
6518     }
6519     else
6520     {
6521         if ( sFltName=="CWW6" )
6522             nVersion = 6;
6523         else if ( sFltName=="CWW7" )
6524             nVersion = 7;
6525 
6526         if( m_pStorage.is() )
6527         {
6528             // Check if we have special encrypted content
6529             rtl::Reference<SotStorageStream> rRef = m_pStorage->OpenSotStream(u"\006DataSpaces/DataSpaceInfo/\011DRMDataSpace"_ustr, StreamMode::READ | StreamMode::SHARE_DENYALL);
6530             if (rRef.is())
6531             {
6532                 nRet = DecryptDRMPackage();
6533             }
6534             nRet = OpenMainStream(refStrm, nOldBuffSize);
6535             pIn = refStrm.get();
6536         }
6537         else
6538         {
6539             OSL_ENSURE(false, "WinWord 95/97 Reader-Read without Storage");
6540             nRet = ERR_SWG_READ_ERROR;
6541         }
6542     }
6543 
6544     if( !nRet )
6545     {
6546         std::unique_ptr<SwWW8ImplReader> pRdr(new SwWW8ImplReader(nVersion, m_pStorage.get(), pIn, rDoc,
6547             rBaseURL, bNew, m_bSkipImages, *rPaM.GetPoint()));
6548         if (bNew)
6549         {
6550             rPaM.GetBound().nContent.Assign(nullptr, 0);
6551             rPaM.GetBound(false).nContent.Assign(nullptr, 0);
6552         }
6553         try
6554         {
6555             nRet = pRdr->LoadDoc();
6556         }
6557         catch( const std::exception& )
6558         {
6559             nRet = ERR_WW8_NO_WW8_FILE_ERR;
6560         }
6561 
6562         if( refStrm.is() )
6563         {
6564             refStrm->SetBufferSize( nOldBuffSize );
6565             refStrm.clear();
6566         }
6567         else
6568         {
6569             pIn->ResetError();
6570         }
6571 
6572     }
6573     return nRet;
6574 }
6575 
GetReaderType()6576 SwReaderType WW8Reader::GetReaderType()
6577 {
6578     return SwReaderType::Storage | SwReaderType::Stream;
6579 }
6580 
HasGlossaries() const6581 bool WW8Reader::HasGlossaries() const
6582 {
6583     return true;
6584 }
6585 
ReadGlossaries(SwTextBlocks & rBlocks,bool bSaveRelFiles) const6586 bool WW8Reader::ReadGlossaries(SwTextBlocks& rBlocks, bool bSaveRelFiles) const
6587 {
6588     bool bRet=false;
6589 
6590     WW8Reader *pThis = const_cast<WW8Reader *>(this);
6591 
6592     sal_uInt16 nOldBuffSize = 32768;
6593     rtl::Reference<SotStorageStream> refStrm;
6594     if (!pThis->OpenMainStream(refStrm, nOldBuffSize))
6595     {
6596         WW8Glossary aGloss( refStrm, 8, m_pStorage.get() );
6597         bRet = aGloss.Load( rBlocks, bSaveRelFiles );
6598     }
6599     return bRet;
6600 }
6601 
GetOLEStorageName(sal_uInt32 nOLEId,OUString & rStorageName,rtl::Reference<SotStorage> & rSrcStorage,uno::Reference<embed::XStorage> & rDestStorage) const6602 bool SwMSDffManager::GetOLEStorageName(sal_uInt32 nOLEId, OUString& rStorageName,
6603     rtl::Reference<SotStorage>& rSrcStorage, uno::Reference < embed::XStorage >& rDestStorage) const
6604 {
6605     bool bRet = false;
6606 
6607     sal_Int32 nPictureId = 0;
6608     if (m_rReader.m_pStg)
6609     {
6610         // Via the TextBox-PLCF we get the right char Start-End positions
6611         // We should then find the EmbeddedField and the corresponding Sprms
6612         // in that Area.
6613         // We only need the Sprm for the Picture Id.
6614         sal_uInt64 nOldPos = m_rReader.m_pStrm->Tell();
6615         {
6616             // #i32596# - consider return value of method
6617             // <rReader.GetTxbxTextSttEndCp(..)>. If it returns false, method
6618             // wasn't successful. Thus, continue in this case.
6619             // Note: Ask MM for initialization of <nStartCp> and <nEndCp>.
6620             // Note: Ask MM about assertions in method <rReader.GetTxbxTextSttEndCp(..)>.
6621             WW8_CP nStartCp, nEndCp;
6622             if ( m_rReader.m_bDrawCpOValid && m_rReader.GetTxbxTextSttEndCp(nStartCp, nEndCp,
6623                             o3tl::narrowing<sal_uInt16>((nOLEId >> 16) & 0xFFFF),
6624                             o3tl::narrowing<sal_uInt16>(nOLEId & 0xFFFF)) )
6625             {
6626                 WW8PLCFxSaveAll aSave;
6627                 m_rReader.m_xPlcxMan->SaveAllPLCFx( aSave );
6628 
6629                 nStartCp += m_rReader.m_nDrawCpO;
6630                 nEndCp   += m_rReader.m_nDrawCpO;
6631                 WW8PLCFx_Cp_FKP* pChp = m_rReader.m_xPlcxMan->GetChpPLCF();
6632                 wwSprmParser aSprmParser(*m_rReader.m_xWwFib);
6633                 while (nStartCp <= nEndCp && !nPictureId)
6634                 {
6635                     if (!pChp->SeekPos( nStartCp))
6636                         break;
6637                     WW8PLCFxDesc aDesc;
6638                     pChp->GetSprms( &aDesc );
6639 
6640                     if (aDesc.nSprmsLen && aDesc.pMemPos) // Attributes present
6641                     {
6642                         auto nLen = aDesc.nSprmsLen;
6643                         const sal_uInt8* pSprm = aDesc.pMemPos;
6644 
6645                         while (nLen >= 2 && !nPictureId)
6646                         {
6647                             sal_uInt16 nId = aSprmParser.GetSprmId(pSprm);
6648                             sal_Int32 nSL = aSprmParser.GetSprmSize(nId, pSprm, nLen);
6649 
6650                             if( nLen < nSL )
6651                                 break; // Not enough Bytes left
6652 
6653                             if (0x6A03 == nId)
6654                             {
6655                                 nPictureId = SVBT32ToUInt32(pSprm +
6656                                     aSprmParser.DistanceToData(nId));
6657                                 bRet = true;
6658                             }
6659                             pSprm += nSL;
6660                             nLen -= nSL;
6661                         }
6662                     }
6663                     nStartCp = aDesc.nEndPos;
6664                 }
6665 
6666                 m_rReader.m_xPlcxMan->RestoreAllPLCFx( aSave );
6667             }
6668         }
6669         m_rReader.m_pStrm->Seek( nOldPos );
6670     }
6671 
6672     if( bRet )
6673     {
6674         rStorageName = "_";
6675         rStorageName += OUString::number(nPictureId);
6676         rSrcStorage = m_rReader.m_pStg->OpenSotStorage(SL::aObjectPool);
6677         if (!m_rReader.m_pDocShell)
6678             bRet=false;
6679         else
6680             rDestStorage = m_rReader.m_pDocShell->GetStorage();
6681     }
6682     return bRet;
6683 }
6684 
6685 /**
6686  * When reading a single Box (which possibly is part of a group), we do
6687  * not yet have enough information to decide whether we need it as a TextField
6688  * or not.
6689  * So convert all of them as a precaution.
6690  * FIXME: Actually implement this!
6691  */
ShapeHasText(sal_uLong,sal_uLong) const6692 bool SwMSDffManager::ShapeHasText(sal_uLong, sal_uLong) const
6693 {
6694     return true;
6695 }
6696 
InEqualOrHigherApo(int nLvl) const6697 bool SwWW8ImplReader::InEqualOrHigherApo(int nLvl) const
6698 {
6699     if (nLvl)
6700         --nLvl;
6701     // #i60827# - check size of <maApos> to assure that <maApos.begin() + nLvl> can be performed.
6702     if ( sal::static_int_cast< sal_Int32>(nLvl) >= sal::static_int_cast< sal_Int32>(m_aApos.size()) )
6703     {
6704         return false;
6705     }
6706     auto aIter = std::find(m_aApos.begin() + nLvl, m_aApos.end(), true);
6707     return aIter != m_aApos.end();
6708 }
6709 
InEqualApo(int nLvl) const6710 bool SwWW8ImplReader::InEqualApo(int nLvl) const
6711 {
6712     // If we are in a table, see if an apo was inserted at the level below the table.
6713     if (nLvl)
6714         --nLvl;
6715     if (nLvl < 0 || o3tl::make_unsigned(nLvl) >= m_aApos.size())
6716         return false;
6717     return m_aApos[nLvl];
6718 }
6719 
6720 namespace sw::hack
6721 {
Position(const SwPosition & rPos)6722         Position::Position(const SwPosition &rPos)
6723             : maPtNode(rPos.GetNode()), mnPtContent(rPos.GetContentIndex())
6724         {
6725         }
6726 
operator SwPosition() const6727         Position::operator SwPosition() const
6728         {
6729             return SwPosition(maPtNode, maPtNode.GetNode().GetContentNode(), mnPtContent);
6730         }
6731 }
6732 
SwMacroInfo()6733 SwMacroInfo::SwMacroInfo()
6734     : SdrObjUserData( SdrInventor::ScOrSwDraw, SW_UD_IMAPDATA )
6735     , mnShapeId(-1)
6736 {
6737 }
6738 
~SwMacroInfo()6739 SwMacroInfo::~SwMacroInfo()
6740 {
6741 }
6742 
Clone(SdrObject *) const6743 std::unique_ptr<SdrObjUserData> SwMacroInfo::Clone( SdrObject* /*pObj*/ ) const
6744 {
6745    return std::unique_ptr<SdrObjUserData>(new SwMacroInfo( *this ));
6746 }
6747 
SetCurrentItemSet(std::unique_ptr<SfxItemSet> pItemSet)6748 std::unique_ptr<SfxItemSet> SwWW8ImplReader::SetCurrentItemSet(std::unique_ptr<SfxItemSet> pItemSet)
6749 {
6750     std::unique_ptr<SfxItemSet> xRet(std::move(m_xCurrentItemSet));
6751     m_xCurrentItemSet = std::move(pItemSet);
6752     return xRet;
6753 }
6754 
NotifyMacroEventRead()6755 void SwWW8ImplReader::NotifyMacroEventRead()
6756 {
6757     if (m_bNotifyMacroEventRead)
6758         return;
6759     uno::Reference<frame::XModel> const xModel(m_rDoc.GetDocShell()->GetBaseModel());
6760     comphelper::DocumentInfo::notifyMacroEventRead(xModel);
6761     m_bNotifyMacroEventRead = true;
6762 }
6763 
6764 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
6765