LibreOffice Module sw (master)  1
ww8par.cxx
Go to the documentation of this file.
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 
32 
33 #include <unotools/configmgr.hxx>
35 #include <unotools/streamwrap.hxx>
36 #include <rtl/random.h>
37 #include <rtl/ustring.hxx>
38 #include <rtl/ustrbuf.hxx>
39 
40 #include <sfx2/docinf.hxx>
41 #include <sfx2/frame.hxx>
42 #include <sfx2/zoomitem.hxx>
43 #include <tools/urlobj.hxx>
44 #include <unotools/tempfile.hxx>
45 
49 
50 #include <editeng/outlobj.hxx>
51 #include <editeng/brushitem.hxx>
53 #include <editeng/tstpitem.hxx>
54 #include <editeng/ulspitem.hxx>
55 #include <editeng/langitem.hxx>
56 #include <editeng/opaqitem.hxx>
58 #include <editeng/fontitem.hxx>
59 #include <editeng/editeng.hxx>
60 #include <svx/unoapi.hxx>
61 #include <svx/svdoole2.hxx>
62 #include <svx/svdoashp.hxx>
63 #include <svx/svxerr.hxx>
65 #include <svx/svdmodel.hxx>
66 #include <svx/xflclit.hxx>
67 #include <svx/sdasitm.hxx>
68 #include <svx/sdtagitm.hxx>
69 #include <svx/sdtcfitm.hxx>
70 #include <svx/sdtditm.hxx>
71 #include <svx/sdtmfitm.hxx>
72 #include <unotools/fltrcfg.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>
94 #include <IDocumentMarkAccess.hxx>
97 #include <../../core/inc/DocumentRedlineManager.hxx>
98 #include <docufld.hxx>
99 #include <swfltopt.hxx>
100 #include <viewsh.hxx>
101 #include <shellres.hxx>
102 #include <swerror.h>
103 #include <swtable.hxx>
104 #include <fchrfmt.hxx>
105 #include <charfmt.hxx>
107 #include "sprmids.hxx"
108 
109 #include "writerwordglue.hxx"
110 
111 #include <ndgrf.hxx>
112 #include <editeng/editids.hrc>
113 #include <fmtflcnt.hxx>
114 #include <txatbase.hxx>
115 
116 #include "ww8par2.hxx"
117 
118 #include <com/sun/star/beans/PropertyAttribute.hpp>
119 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
120 #include <com/sun/star/document/XViewDataSupplier.hpp>
121 #include <com/sun/star/document/IndexedPropertyValues.hpp>
122 
123 #include <svl/lngmisc.hxx>
124 #include <svl/itemiter.hxx>
125 
127 #include <basic/basmgr.hxx>
128 
129 #include "ww8toolbar.hxx"
130 #include <o3tl/unit_conversion.hxx>
131 #include <o3tl/safeint.hxx>
132 #include <osl/file.hxx>
133 
134 #include <breakit.hxx>
135 
136 #include <sfx2/docfile.hxx>
137 #include <swdll.hxx>
138 #include "WW8Sttbf.hxx"
139 #include "WW8FibData.hxx"
140 #include <unordered_set>
141 #include <memory>
142 
143 using namespace ::com::sun::star;
144 using namespace sw::util;
145 using namespace sw::types;
146 using namespace nsHdFtFlags;
147 
148 #include <com/sun/star/i18n/XBreakIterator.hpp>
149 #include <com/sun/star/i18n/ScriptType.hpp>
150 #include <unotools/pathoptions.hxx>
151 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
152 
153 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
155 #include <oox/ole/vbaproject.hxx>
156 #include <oox/ole/olestorage.hxx>
159 #include <tools/diagnose_ex.h>
160 
162 {
163  if ( pObj )
164  {
165  sal_uInt16 nCount = pObj->GetUserDataCount();
166  for( sal_uInt16 i = 0; i < nCount; i++ )
167  {
168  SdrObjUserData* pData = pObj->GetUserData( i );
169  if( pData && pData->GetInventor() == SdrInventor::ScOrSwDraw
170  && pData->GetId() == SW_UD_IMAPDATA)
171  {
172  return dynamic_cast<SwMacroInfo*>(pData);
173  }
174  }
176  pObj->AppendUserData(std::unique_ptr<SdrObjUserData>(pData));
177  return pData;
178  }
179 
180  return nullptr;
181 };
182 
183 static void lclGetAbsPath(OUString& rPath, sal_uInt16 nLevel, SwDocShell const * pDocShell)
184 {
185  OUStringBuffer aTmpStr;
186  while( nLevel )
187  {
188  aTmpStr.append("../");
189  --nLevel;
190  }
191  if (!aTmpStr.isEmpty())
192  aTmpStr.append(rPath);
193  else
194  aTmpStr = rPath;
195 
196  if (!aTmpStr.isEmpty())
197  {
198  bool bWasAbs = false;
199  rPath = pDocShell->GetMedium()->GetURLObject().smartRel2Abs( aTmpStr.makeStringAndClear(), bWasAbs ).GetMainURL( INetURLObject::DecodeMechanism::NONE );
200  // full path as stored in SvxURLField must be encoded
201  }
202 }
203 
204 namespace
205 {
206  void lclIgnoreUString32(SvStream& rStrm)
207  {
208  sal_uInt32 nChars(0);
209  rStrm.ReadUInt32(nChars);
210  nChars *= 2;
211  rStrm.SeekRel(nChars);
212  }
213 }
214 
215 void SwWW8ImplReader::ReadEmbeddedData(SvStream& rStrm, SwDocShell const * pDocShell, struct HyperLinksTable& hlStr)
216 {
217  // (0x01B8) HLINK
218  // const sal_uInt16 WW8_ID_HLINK = 0x01B8;
219  constexpr sal_uInt32 WW8_HLINK_BODY = 0x00000001;
220  constexpr sal_uInt32 WW8_HLINK_ABS = 0x00000002;
221  constexpr sal_uInt32 WW8_HLINK_DESCR = 0x00000014;
222  constexpr sal_uInt32 WW8_HLINK_MARK = 0x00000008;
223  constexpr sal_uInt32 WW8_HLINK_FRAME = 0x00000080;
224  constexpr sal_uInt32 WW8_HLINK_UNC = 0x00000100;
225 
226  //sal_uInt8 maGuidStdLink[ 16 ] ={
227  // 0xD0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE, 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B };
228 
229  sal_uInt8 const aGuidUrlMoniker[ 16 ] = {
230  0xE0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE, 0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B };
231 
232  sal_uInt8 const aGuidFileMoniker[ 16 ] = {
233  0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 };
234 
235  sal_uInt8 aGuid[16];
236  sal_uInt32 nFlags(0);
237 
238  rStrm.ReadBytes(aGuid, 16);
239  rStrm.SeekRel( 4 );
240  rStrm.ReadUInt32( nFlags );
241 
242  std::unique_ptr< OUString > xLongName; // link / file name
243  std::unique_ptr< OUString > xShortName; // 8.3-representation of file name
244  std::unique_ptr< OUString > xTextMark; // text mark
245 
246  // description (ignore)
247  if( ::get_flag( nFlags, WW8_HLINK_DESCR ) )
248  lclIgnoreUString32( rStrm );
249 
250  // target frame
251  if( ::get_flag( nFlags, WW8_HLINK_FRAME ) )
252  {
254  }
255 
256  // UNC path
257  if( ::get_flag( nFlags, WW8_HLINK_UNC ) )
258  {
259  // MS-OSHARED: An unsigned integer that specifies the number of Unicode characters in the
260  // string field, including the null-terminating character.
261  sal_uInt32 nStrLen(0);
262  rStrm.ReadUInt32(nStrLen);
263  if (nStrLen)
264  {
265  xLongName.reset(new OUString(read_uInt16s_ToOUString(rStrm, nStrLen - 1)));
266  rStrm.SeekRel(sizeof(sal_Unicode)); // skip null-byte at end
267  }
268  lclGetAbsPath( *xLongName, 0 , pDocShell);
269  }
270  // file link or URL
271  else if( ::get_flag( nFlags, WW8_HLINK_BODY ) )
272  {
273  rStrm.ReadBytes(aGuid, 16);
274 
275  if( memcmp(aGuid, aGuidFileMoniker, 16) == 0 )
276  {
277  sal_uInt16 nLevel = 0; // counter for level to climb down in path
278  rStrm.ReadUInt16( nLevel );
279  // MS-OSHARED: An unsigned integer that specifies the number of
280  // ANSI characters in ansiPath, including the terminating NULL character
281  sal_uInt32 nUnits = 0;
282  rStrm.ReadUInt32(nUnits);
283  if (nUnits)
284  {
285  OString sStr(read_uInt8s_ToOString(rStrm, nUnits - 1));
286  rStrm.SeekRel(sizeof(sal_uInt8)); // skip null-byte at end
287  xShortName.reset(new OUString(sStr.getStr(), sStr.getLength(), GetCharSetFromLanguage()));
288  }
289  rStrm.SeekRel( 24 );
290 
291  sal_uInt32 nStrLen(0);
292  rStrm.ReadUInt32( nStrLen );
293  if( nStrLen )
294  {
295  nStrLen = 0;
296  rStrm.ReadUInt32( nStrLen );
297  nStrLen /= 2;
298  rStrm.SeekRel( 2 );
299  // MS-OSHARED: This array MUST not include a terminating NULL character.
300  xLongName.reset(new OUString(read_uInt16s_ToOUString(rStrm, nStrLen)));
301  lclGetAbsPath( *xLongName, nLevel, pDocShell);
302  }
303  else
304  lclGetAbsPath( *xShortName, nLevel, pDocShell);
305  }
306  else if( memcmp(aGuid, aGuidUrlMoniker, 16) == 0 )
307  {
308  // MS-OSHARED: An unsigned integer that specifies the size of this
309  // structure in bytes, excluding the size of the length field. The
310  // value of this field MUST be ... the byte size of the url
311  // field (including the terminating NULL character)
312  sal_uInt32 nStrLen(0);
313  rStrm.ReadUInt32( nStrLen );
314  nStrLen /= 2;
315  if (nStrLen)
316  {
317  xLongName.reset(new OUString(read_uInt16s_ToOUString(rStrm, nStrLen - 1)));
318  rStrm.SeekRel(sizeof(sal_Unicode)); // skip null-byte at end
319  }
320  if( !::get_flag( nFlags, WW8_HLINK_ABS ) )
321  lclGetAbsPath( *xLongName, 0 ,pDocShell);
322  }
323  else
324  {
325  SAL_INFO("sw.ww8", "WW8Hyperlink::ReadEmbeddedData - unknown content GUID");
326  }
327  }
328 
329  // text mark
330  if( ::get_flag( nFlags, WW8_HLINK_MARK ) )
331  {
332  xTextMark.reset(new OUString(read_uInt32_lenPrefixed_uInt16s_ToOUString(rStrm)));
333  }
334 
335  if (!xLongName && xShortName)
336  {
337  xLongName.reset( new OUString );
338  *xLongName += *xShortName;
339  }
340  else if (!xLongName && xTextMark)
341  xLongName.reset( new OUString );
342 
343  if (xLongName)
344  {
345  if (xTextMark)
346  {
347  if (xLongName->isEmpty())
348  *xTextMark = xTextMark->replace('!', '.');
349  *xLongName += "#" + *xTextMark;
350  }
351  hlStr.hLinkAddr = *xLongName;
352  }
353 }
354 
355 namespace {
356 
357 class BasicProjImportHelper
358 {
359  SwDocShell& mrDocShell;
360  uno::Reference< uno::XComponentContext > mxCtx;
361 public:
362  explicit BasicProjImportHelper( SwDocShell& rShell ) : mrDocShell( rShell ),
364  {
365  }
366  bool import( const uno::Reference< io::XInputStream >& rxIn );
367  OUString getProjectName() const;
368 };
369 
370 }
371 
372 bool BasicProjImportHelper::import( const uno::Reference< io::XInputStream >& rxIn )
373 {
374  bool bRet = false;
375  try
376  {
377  oox::ole::OleStorage root( mxCtx, rxIn, false );
378  oox::StorageRef vbaStg = root.openSubStorage( "Macros" , false );
379  if ( vbaStg )
380  {
381  oox::ole::VbaProject aVbaPrj( mxCtx, mrDocShell.GetModel(), u"Writer" );
382  bRet = aVbaPrj.importVbaProject( *vbaStg );
383  }
384  }
385  catch( const uno::Exception& )
386  {
387  bRet = false;
388  }
389  return bRet;
390 }
391 
392 OUString BasicProjImportHelper::getProjectName() const
393 {
394  OUString sProjName( "Standard" );
395  uno::Reference< beans::XPropertySet > xProps( mrDocShell.GetModel(), uno::UNO_QUERY );
396  if ( xProps.is() )
397  {
398  try
399  {
400  uno::Reference< script::vba::XVBACompatibility > xVBA( xProps->getPropertyValue( "BasicLibraries" ), uno::UNO_QUERY_THROW );
401  sProjName = xVBA->getProjectName();
402 
403  }
404  catch( const uno::Exception& )
405  {
406  }
407  }
408  return sProjName;
409 }
410 
411 namespace {
412 
413 class Sttb : public TBBase
414 {
415 struct SBBItem
416 {
417  sal_uInt16 cchData;
418  OUString data;
419  SBBItem() : cchData(0){}
420 };
421  sal_uInt16 fExtend;
422  sal_uInt16 cData;
423  sal_uInt16 cbExtra;
424 
425  std::vector< SBBItem > dataItems;
426 
427  Sttb(Sttb const&) = delete;
428  Sttb& operator=(Sttb const&) = delete;
429 
430 public:
431  Sttb();
432 
433  bool Read(SvStream &rS) override;
434  OUString getStringAtIndex( sal_uInt32 );
435 };
436 
437 }
438 
439 Sttb::Sttb()
440  : fExtend(0)
441  , cData(0)
442  , cbExtra(0)
443 {
444 }
445 
446 bool Sttb::Read( SvStream& rS )
447 {
448  SAL_INFO("sw.ww8", "stream pos " << rS.Tell());
449  nOffSet = rS.Tell();
450  rS.ReadUInt16( fExtend ).ReadUInt16( cData ).ReadUInt16( cbExtra );
451  if ( cData )
452  {
453  //if they are all going to be empty strings, how many could there be
454  const size_t nMaxPossibleRecords = rS.remainingSize() / sizeof(sal_uInt16);
455  if (cData > nMaxPossibleRecords)
456  return false;
457  for ( sal_Int32 index = 0; index < cData; ++index )
458  {
459  SBBItem aItem;
460  rS.ReadUInt16( aItem.cchData );
461  aItem.data = read_uInt16s_ToOUString(rS, aItem.cchData);
462  dataItems.push_back( aItem );
463  }
464  }
465  return true;
466 }
467 
468 OUString
469 Sttb::getStringAtIndex( sal_uInt32 index )
470 {
471  OUString aRet;
472  if ( index < dataItems.size() )
473  aRet = dataItems[ index ].data;
474  return aRet;
475 
476 }
477 
479  : SvxMSDffManager(*rRdr.m_pTableStream, rRdr.GetBaseURL(), rRdr.m_xWwFib->m_fcDggInfo,
480  rRdr.m_pDataStream, nullptr, 0, COL_WHITE, rRdr.m_pStrm, bSkipImages),
481  rReader(rRdr), pFallbackStream(nullptr)
482 {
485 }
486 
488 {
489  sal_uInt32 nFlags(0);
490  const SvtFilterOptions& rOpt = SvtFilterOptions::Get();
491  if (rOpt.IsMathType2Math())
492  nFlags |= OLE_MATHTYPE_2_STARMATH;
493  if (rOpt.IsExcel2Calc())
494  nFlags |= OLE_EXCEL_2_STARCALC;
495  if (rOpt.IsPowerPoint2Impress())
497  if (rOpt.IsWinWord2Writer())
498  nFlags |= OLE_WINWORD_2_STARWRITER;
499  return nFlags;
500 }
501 
502 /*
503  * I would like to override the default OLE importing to add a test
504  * and conversion of OCX controls from their native OLE type into our
505  * native nonOLE Form Control Objects.
506  */
507 // #i32596# - consider new parameter <_nCalledByGroup>
509  const Graphic& rGrf,
510  const tools::Rectangle& rBoundRect,
511  const tools::Rectangle& rVisArea,
512  const int _nCalledByGroup ) const
513 {
514  // #i32596# - no import of OLE object, if it's inside a group.
515  // NOTE: This can be undone, if grouping of Writer fly frames is possible or
516  // if drawing OLE objects are allowed in Writer.
517  if ( _nCalledByGroup > 0 )
518  {
519  return nullptr;
520  }
521 
522  SdrObject* pRet = nullptr;
523  OUString sStorageName;
524  tools::SvRef<SotStorage> xSrcStg;
525  uno::Reference < embed::XStorage > xDstStg;
526  if( GetOLEStorageName( nOLEId, sStorageName, xSrcStg, xDstStg ))
527  {
528  tools::SvRef<SotStorage> xSrc = xSrcStg->OpenSotStorage( sStorageName );
529  OSL_ENSURE(rReader.m_xFormImpl, "No Form Implementation!");
530  css::uno::Reference< css::drawing::XShape > xShape;
531  if ( (!(rReader.m_bIsHeader || rReader.m_bIsFooter)) &&
532  rReader.m_xFormImpl->ReadOCXStream(xSrc,&xShape,true))
533  {
534  pRet = SdrObject::getSdrObjectFromXShape(xShape);
535  }
536  else
537  {
538  ErrCode nError = ERRCODE_NONE;
540  *pSdrModel,
541  sStorageName,
542  xSrcStg,
543  xDstStg,
544  rGrf,
545  rBoundRect,
546  rVisArea,
547  pStData,
548  nError,
550  css::embed::Aspects::MSOLE_CONTENT,
551  rReader.GetBaseURL());
552  }
553  }
554  return pRet;
555 }
556 
558 {
559  OSL_ENSURE(!pFallbackStream,
560  "if you're recursive, you're broken");
563  aEscherBlipCache.clear();
564  pStData2 = nullptr;
565 }
566 
568 {
571  aOldEscherBlipCache.clear();
572  pFallbackStream = nullptr;
573 }
574 
576 {
577  return m_xCtrlStck ? m_xCtrlStck->GetToggleAttrFlags() : 0;
578 }
579 
581 {
582  return m_xCtrlStck ? m_xCtrlStck->GetToggleBiDiAttrFlags() : 0;
583 }
584 
585 void SwWW8ImplReader::SetToggleAttrFlags(sal_uInt16 nFlags)
586 {
587  if (m_xCtrlStck)
588  m_xCtrlStck->SetToggleAttrFlags(nFlags);
589 }
590 
592 {
593  if (m_xCtrlStck)
594  m_xCtrlStck->SetToggleBiDiAttrFlags(nFlags);
595 }
596 
598  DffObjData& rObjData,
599  SvxMSDffClientData& rData,
600  tools::Rectangle& rTextRect,
601  SdrObject* pObj
602  )
603 {
604  if( !rTextRect.IsEmpty() )
605  {
606  SvxMSDffImportData& rImportData = static_cast<SvxMSDffImportData&>(rData);
607  std::unique_ptr<SvxMSDffImportRec> pImpRec(new SvxMSDffImportRec);
608 
609  // fill Import Record with data
610  pImpRec->nShapeId = rObjData.nShapeId;
611  pImpRec->eShapeType = rObjData.eShapeType;
612 
616  if( rObjData.bClientAnchor )
617  ProcessClientAnchor( rSt,
619  pImpRec->pClientAnchorBuffer, pImpRec->nClientAnchorLen );
620 
621  rObjData.bClientData = maShapeRecords.SeekToContent( rSt,
624  if( rObjData.bClientData )
625  ProcessClientData( rSt,
627  pImpRec->pClientDataBuffer, pImpRec->nClientDataLen );
628 
629  // process user (== Winword) defined parameters in 0xF122 record
630  // #i84783# - set special value to determine, if property is provided or not.
631  pImpRec->nLayoutInTableCell = 0xFFFFFFFF;
632 
633  if( maShapeRecords.SeekToContent( rSt,
637  {
638  sal_uInt32 nBytesLeft = maShapeRecords.Current()->nRecLen;
639  auto nAvailableBytes = rSt.remainingSize();
640  if (nBytesLeft > nAvailableBytes)
641  {
642  SAL_WARN("sw.ww8", "Document claimed to have shape record of " << nBytesLeft << " bytes, but only " << nAvailableBytes << " available");
643  nBytesLeft = nAvailableBytes;
644  }
645  while( 5 < nBytesLeft )
646  {
647  sal_uInt16 nPID(0);
648  rSt.ReadUInt16(nPID);
649  sal_uInt32 nUDData(0);
650  rSt.ReadUInt32(nUDData);
651  if (!rSt.good())
652  break;
653  switch (nPID)
654  {
655  case 0x038F: pImpRec->nXAlign = nUDData; break;
656  case 0x0390:
657  pImpRec->nXRelTo = nUDData;
658  break;
659  case 0x0391: pImpRec->nYAlign = nUDData; break;
660  case 0x0392:
661  pImpRec->nYRelTo = nUDData;
662  break;
663  case 0x03BF: pImpRec->nLayoutInTableCell = nUDData; break;
664  case 0x0393:
665  // This seems to correspond to o:hrpct from .docx (even including
666  // the difference that it's in 0.1% even though the .docx spec
667  // says it's in 1%).
668  pImpRec->relativeHorizontalWidth = nUDData;
669  break;
670  case 0x0394:
671  // And this is really just a guess, but a mere presence of this
672  // flag makes a horizontal rule be as wide as the page (unless
673  // overridden by something), so it probably matches o:hr from .docx.
674  pImpRec->isHorizontalRule = true;
675  break;
676  }
677  nBytesLeft -= 6;
678  }
679  }
680 
681  // Text Frame also Title or Outline
682  sal_uInt32 nTextId = GetPropertyValue( DFF_Prop_lTxid, 0 );
683  if( nTextId )
684  {
685  SfxItemSet aSet( pSdrModel->GetItemPool() );
686 
687  // Originally anything that as a mso_sptTextBox was created as a
688  // textbox, this was changed to be created as a simple
689  // rect to keep impress happy. For the rest of us we'd like to turn
690  // it back into a textbox again.
691  bool bIsSimpleDrawingTextBox = (pImpRec->eShapeType == mso_sptTextBox);
692  if (!bIsSimpleDrawingTextBox)
693  {
694  // Either
695  // a) it's a simple text object or
696  // b) it's a rectangle with text and square wrapping.
697  bIsSimpleDrawingTextBox =
698  (
699  (pImpRec->eShapeType == mso_sptTextSimple) ||
700  (
701  (pImpRec->eShapeType == mso_sptRectangle)
702  && ShapeHasText(pImpRec->nShapeId, rObjData.rSpHd.GetRecBegFilePos() )
703  )
704  );
705  }
706 
707  // Distance of Textbox to its surrounding Autoshape
708  sal_Int32 nTextLeft = GetPropertyValue( DFF_Prop_dxTextLeft, 91440);
709  sal_Int32 nTextRight = GetPropertyValue( DFF_Prop_dxTextRight, 91440 );
710  sal_Int32 nTextTop = GetPropertyValue( DFF_Prop_dyTextTop, 45720 );
711  sal_Int32 nTextBottom = GetPropertyValue( DFF_Prop_dyTextBottom, 45720 );
712 
713  ScaleEmu( nTextLeft );
714  ScaleEmu( nTextRight );
715  ScaleEmu( nTextTop );
716  ScaleEmu( nTextBottom );
717 
718  Degree100 nTextRotationAngle;
719  bool bVerticalText = false;
721  {
722  MSO_TextFlow eTextFlow = static_cast<MSO_TextFlow>(GetPropertyValue(
723  DFF_Prop_txflTextFlow, 0) & 0xFFFF);
724  switch( eTextFlow )
725  {
726  case mso_txflBtoT:
727  nTextRotationAngle = 9000_deg100;
728  break;
729  case mso_txflVertN:
730  case mso_txflTtoBN:
731  nTextRotationAngle = 27000_deg100;
732  break;
733  case mso_txflTtoBA:
734  bVerticalText = true;
735  break;
736  case mso_txflHorzA:
737  bVerticalText = true;
738  nTextRotationAngle = 9000_deg100;
739  break;
740  case mso_txflHorzN:
741  default :
742  break;
743  }
744  }
745 
746  if (nTextRotationAngle)
747  {
748  if (nTextRotationAngle == 9000_deg100)
749  {
750  tools::Long nWidth = rTextRect.GetWidth();
751  rTextRect.SetRight( rTextRect.Left() + rTextRect.GetHeight() );
752  rTextRect.SetBottom( rTextRect.Top() + nWidth );
753 
754  sal_Int32 nOldTextLeft = nTextLeft;
755  sal_Int32 nOldTextRight = nTextRight;
756  sal_Int32 nOldTextTop = nTextTop;
757  sal_Int32 nOldTextBottom = nTextBottom;
758 
759  nTextLeft = nOldTextBottom;
760  nTextRight = nOldTextTop;
761  nTextTop = nOldTextLeft;
762  nTextBottom = nOldTextRight;
763  }
764  else if (nTextRotationAngle == 27000_deg100)
765  {
766  tools::Long nWidth = rTextRect.GetWidth();
767  rTextRect.SetRight( rTextRect.Left() + rTextRect.GetHeight() );
768  rTextRect.SetBottom( rTextRect.Top() + nWidth );
769 
770  sal_Int32 nOldTextLeft = nTextLeft;
771  sal_Int32 nOldTextRight = nTextRight;
772  sal_Int32 nOldTextTop = nTextTop;
773  sal_Int32 nOldTextBottom = nTextBottom;
774 
775  nTextLeft = nOldTextTop;
776  nTextRight = nOldTextBottom;
777  nTextTop = nOldTextRight;
778  nTextBottom = nOldTextLeft;
779  }
780  }
781 
782  if (bIsSimpleDrawingTextBox)
783  {
784  SdrObject::Free( pObj );
785  pObj = new SdrRectObj(
786  *pSdrModel,
787  SdrObjKind::Text,
788  rTextRect);
789  }
790 
791  // The vertical paragraph justification are contained within the
792  // BoundRect so calculate it here
793  tools::Rectangle aNewRect(rTextRect);
794  aNewRect.AdjustBottom( -(nTextTop + nTextBottom) );
795  aNewRect.AdjustRight( -(nTextLeft + nTextRight) );
796 
797  // Only if it's a simple Textbox, Writer can replace the Object
798  // with a Frame, else
799  if( bIsSimpleDrawingTextBox )
800  {
801  std::shared_ptr<SvxMSDffShapeInfo> const xTmpRec =
802  std::make_shared<SvxMSDffShapeInfo>(0, pImpRec->nShapeId);
803 
804  SvxMSDffShapeInfos_ById::const_iterator const it =
805  GetShapeInfos()->find(xTmpRec);
806  if (it != GetShapeInfos()->end())
807  {
808  SvxMSDffShapeInfo& rInfo = **it;
809  pImpRec->bReplaceByFly = rInfo.bReplaceByFly;
810  }
811 
812  ApplyAttributes(rSt, aSet, rObjData);
813  }
814 
816  {
817  aSet.Put( makeSdrTextAutoGrowHeightItem( true ) );
819  aNewRect.Bottom() - aNewRect.Top() ) );
821  aNewRect.Right() - aNewRect.Left() ) );
822  }
823  else
824  {
825  aSet.Put( makeSdrTextAutoGrowHeightItem( false ) );
826  aSet.Put( makeSdrTextAutoGrowWidthItem( false ) );
827  }
828 
829  switch ( static_cast<MSO_WrapMode>(GetPropertyValue( DFF_Prop_WrapText, mso_wrapSquare )) )
830  {
831  case mso_wrapNone :
832  aSet.Put( makeSdrTextAutoGrowWidthItem( true ) );
833  pImpRec->bAutoWidth = true;
834  break;
835  case mso_wrapByPoints :
836  aSet.Put( makeSdrTextContourFrameItem( true ) );
837  break;
838  default:
839  ;
840  }
841 
842  // Set distances on Textbox's margins
843  aSet.Put( makeSdrTextLeftDistItem( nTextLeft ) );
844  aSet.Put( makeSdrTextRightDistItem( nTextRight ) );
845  aSet.Put( makeSdrTextUpperDistItem( nTextTop ) );
846  aSet.Put( makeSdrTextLowerDistItem( nTextBottom ) );
847  pImpRec->nDxTextLeft = nTextLeft;
848  pImpRec->nDyTextTop = nTextTop;
849  pImpRec->nDxTextRight = nTextRight;
850  pImpRec->nDyTextBottom = nTextBottom;
851 
852  // Taking the correct default (which is mso_anchorTop)
853  sal_uInt32 eTextAnchor =
855 
856  SdrTextVertAdjust eTVA = bVerticalText
859  SdrTextHorzAdjust eTHA = bVerticalText
862 
863  switch( eTextAnchor )
864  {
865  case mso_anchorTop:
866  {
867  if ( bVerticalText )
869  else
870  eTVA = SDRTEXTVERTADJUST_TOP;
871  }
872  break;
874  {
875  if ( bVerticalText )
877  else
878  eTVA = SDRTEXTVERTADJUST_TOP;
879  }
880  break;
881  case mso_anchorMiddle:
882  break;
884  break;
885  case mso_anchorBottom:
886  {
887  if ( bVerticalText )
888  eTHA = SDRTEXTHORZADJUST_LEFT;
889  else
891  }
892  break;
894  {
895  if ( bVerticalText )
896  eTHA = SDRTEXTHORZADJUST_LEFT;
897  else
899  }
900  break;
901  default:
902  ;
903  }
904 
905  aSet.Put( SdrTextVertAdjustItem( eTVA ) );
906  aSet.Put( SdrTextHorzAdjustItem( eTHA ) );
907 
908  if (pObj != nullptr)
909  {
910  pObj->SetMergedItemSet(aSet);
911 
912  if (bVerticalText)
913  {
914  SdrTextObj *pTextObj = dynamic_cast< SdrTextObj* >(pObj);
915  if (pTextObj)
916  pTextObj->SetVerticalWriting(true);
917  }
918 
919  if ( bIsSimpleDrawingTextBox )
920  {
921  if ( nTextRotationAngle )
922  {
923  tools::Long nMinWH = rTextRect.GetWidth() < rTextRect.GetHeight() ?
924  rTextRect.GetWidth() : rTextRect.GetHeight();
925  nMinWH /= 2;
926  Point aPivot(rTextRect.TopLeft());
927  aPivot.AdjustX(nMinWH );
928  aPivot.AdjustY(nMinWH );
929  pObj->NbcRotate(aPivot, nTextRotationAngle);
930  }
931  }
932 
933  if ( ( ( rObjData.nSpFlags & ShapeFlag::FlipV ) || mnFix16Angle || nTextRotationAngle ) && dynamic_cast< SdrObjCustomShape* >( pObj ) )
934  {
935  SdrObjCustomShape* pCustomShape = dynamic_cast< SdrObjCustomShape* >( pObj );
936  if (pCustomShape)
937  {
938  double fExtraTextRotation = 0.0;
939  if ( mnFix16Angle && !( GetPropertyValue( DFF_Prop_FitTextToShape, 0 ) & 4 ) )
940  { // text is already rotated, we have to take back the object rotation if DFF_Prop_RotateText is false
941  fExtraTextRotation = -mnFix16Angle.get();
942  }
943  if ( rObjData.nSpFlags & ShapeFlag::FlipV ) // sj: in ppt the text is flipped, whereas in word the text
944  { // remains unchanged, so we have to take back the flipping here
945  fExtraTextRotation += 18000.0; // because our core will flip text if the shape is flipped.
946  }
947  fExtraTextRotation += nTextRotationAngle.get();
948  if ( !::basegfx::fTools::equalZero( fExtraTextRotation ) )
949  {
950  fExtraTextRotation /= 100.0;
952  css::beans::PropertyValue aPropVal;
953  aPropVal.Name = "TextRotateAngle";
954  aPropVal.Value <<= fExtraTextRotation;
955  aGeometryItem.SetPropertyValue( aPropVal );
956  pCustomShape->SetMergedItem( aGeometryItem );
957  }
958  }
959  }
960  else if ( mnFix16Angle )
961  {
962  // rotate text with shape ?
963  pObj->NbcRotate( rObjData.aBoundRect.Center(), mnFix16Angle );
964  }
965  }
966  }
967  else if( !pObj )
968  {
969  // simple rectangular objects are ignored by ImportObj() :-(
970  // this is OK for Draw but not for Calc and Writer
971  // cause here these objects have a default border
972  pObj = new SdrRectObj(
973  *pSdrModel,
974  rTextRect);
975 
976  SfxItemSet aSet( pSdrModel->GetItemPool() );
977  ApplyAttributes( rSt, aSet, rObjData );
978 
979  const SfxPoolItem* pPoolItem=nullptr;
980  SfxItemState eState = aSet.GetItemState( XATTR_FILLCOLOR,
981  false, &pPoolItem );
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),
1004  pImpRec->nDyWrapDistTop = o3tl::convert(GetPropertyValue(DFF_Prop_dyWrapDistTop, 0),
1006  pImpRec->nDxWrapDistRight
1009  pImpRec->nDyWrapDistBottom = o3tl::convert(GetPropertyValue(DFF_Prop_dyWrapDistBottom, 0),
1011  // 16.16 fraction times total image width or height, as appropriate.
1012 
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(
1052  pImpRec->nCropFromLeft = GetPropertyValue(
1053  DFF_Prop_cropFromLeft, 0 );
1054  pImpRec->nCropFromRight = GetPropertyValue(
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(
1068  mso_lineSimple ))
1069  : MSO_LineStyle(USHRT_MAX);
1070  pImpRec->eLineDashing = static_cast<MSO_LineDashing>(GetPropertyValue(
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);
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 = rReader.m_pDocShell;
1118  if (pDocShell)
1119  {
1120  rReader.ReadEmbeddedData(aMemStream, pDocShell, hlStr);
1121  }
1122  }
1123 
1124  if (pObj && !hlStr.hLinkAddr.isEmpty())
1125  {
1126  SwMacroInfo* pInfo = GetMacroInfo( pObj );
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 
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  {
1161  m_bCpxStyle = true;
1162  }
1163 }
1164 
1168 void SwWW8ImplReader::Read_Majority( sal_uInt16, const sal_uInt8* , short )
1169 {
1170 }
1171 
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 
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 (rReader.m_xPlcxMan && 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 
1215 {
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 
1230 static tools::Long lcl_GetTrueMargin(const SvxLRSpaceItem &rLR, const SwNumFormat &rFormat,
1231  tools::Long &rFirstLinePos)
1232 {
1234  "<lcl_GetTrueMargin> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION" );
1235 
1236  const tools::Long nBodyIndent = rLR.GetTextLeft();
1237  const tools::Long nFirstLineDiff = rLR.GetTextFirstLineOffset();
1238  rFirstLinePos = nBodyIndent + nFirstLineDiff;
1239 
1240  const auto nPseudoListBodyIndent = rFormat.GetAbsLSpace();
1241  const tools::Long nReverseListIndented = GetListFirstLineIndent(rFormat);
1242  tools::Long nExtraListIndent = nPseudoListBodyIndent + nReverseListIndented;
1243 
1244  return std::max<tools::Long>(nExtraListIndent, 0);
1245 }
1246 
1247 // #i103711#
1248 // #i105414#
1250  const SwNumFormat &rFormat,
1251  const bool bFirstLineOfstSet,
1252  const bool bLeftIndentSet )
1253 {
1255  {
1256  tools::Long nWantedFirstLinePos;
1257  tools::Long nExtraListIndent = lcl_GetTrueMargin(rLR, rFormat, nWantedFirstLinePos);
1258  rLR.SetTextLeft(nWantedFirstLinePos - nExtraListIndent);
1259  rLR.SetTextFirstLineOffset(0);
1260  }
1262  {
1263  if ( !bFirstLineOfstSet && bLeftIndentSet &&
1264  rFormat.GetFirstLineIndent() != 0 )
1265  {
1266  rLR.SetTextFirstLineOffset( rFormat.GetFirstLineIndent() );
1267  }
1268  else if ( bFirstLineOfstSet && !bLeftIndentSet &&
1269  rFormat.GetIndentAt() != 0 )
1270  {
1271  rLR.SetTextLeft( rFormat.GetIndentAt() );
1272  }
1273  else if (!bFirstLineOfstSet && !bLeftIndentSet )
1274  {
1275  if ( rFormat.GetFirstLineIndent() != 0 )
1276  {
1277  rLR.SetTextFirstLineOffset( rFormat.GetFirstLineIndent() );
1278  }
1279  if ( rFormat.GetIndentAt() != 0 )
1280  {
1281  rLR.SetTextLeft( rFormat.GetIndentAt() );
1282  }
1283  }
1284  }
1285 }
1286 
1288  const SwTextNode &rTextNode)
1289 {
1290  const SwNumFormat *pRet = nullptr;
1291  const SfxPoolItem *pItem = GetStackAttr(rPos, RES_FLTR_NUMRULE);
1292  if (pItem && rTextNode.GetNumRule())
1293  {
1294  if (rTextNode.IsCountedInList())
1295  {
1296  OUString sName(static_cast<const SfxStringItem*>(pItem)->GetValue());
1297  const SwNumRule *pRule = m_rDoc.FindNumRulePtr(sName);
1298  if (pRule)
1299  pRet = GetNumFormatFromSwNumRuleLevel(*pRule, rTextNode.GetActualListLevel());
1300  }
1301  }
1302  return pRet;
1303 }
1304 
1306  SwFltStackEntry& rEntry )
1307 {
1308  switch( rEntry.m_pAttr->Which() )
1309  {
1310  case RES_FLTR_BOOKMARK:
1311  {
1312  // suppress insertion of bookmark, which is recognized as an internal bookmark used for table-of-content
1313  // and which is not referenced.
1314  bool bInsertBookmarkIntoDoc = true;
1315 
1316  SwFltBookmark* pFltBookmark = dynamic_cast<SwFltBookmark*>(rEntry.m_pAttr.get());
1317  if ( pFltBookmark != nullptr && pFltBookmark->IsTOCBookmark() )
1318  {
1319  const OUString& rName = pFltBookmark->GetName();
1320  std::set< OUString, SwWW8::ltstr >::const_iterator aResult = aReferencedTOCBookmarks.find(rName);
1321  if ( aResult == aReferencedTOCBookmarks.end() )
1322  {
1323  bInsertBookmarkIntoDoc = false;
1324  }
1325  }
1326  if ( bInsertBookmarkIntoDoc )
1327  {
1328  SwFltEndStack::SetAttrInDoc( rTmpPos, rEntry );
1329  }
1330  break;
1331  }
1332  default:
1333  SwFltEndStack::SetAttrInDoc( rTmpPos, rEntry );
1334  break;
1335  }
1336 
1337 }
1338 
1340  SwFltStackEntry& rEntry)
1341 {
1342  switch (rEntry.m_pAttr->Which())
1343  {
1344  case RES_LR_SPACE:
1345  {
1346  /*
1347  Loop over the affected nodes and
1348  a) convert the word style absolute indent to indent relative
1349  to any numbering indent active on the nodes
1350  b) adjust the writer style tabstops relative to the old
1351  paragraph indent to be relative to the new paragraph indent
1352  */
1353  SwPaM aRegion(rTmpPos);
1355  {
1356  SvxLRSpaceItem aNewLR( *static_cast<SvxLRSpaceItem*>(rEntry.m_pAttr.get()) );
1357  SwNodeOffset nStart = aRegion.Start()->nNode.GetIndex();
1358  SwNodeOffset nEnd = aRegion.End()->nNode.GetIndex();
1359  for(; nStart <= nEnd; ++nStart)
1360  {
1361  SwNode* pNode = m_rDoc.GetNodes()[ nStart ];
1362  if (!pNode || !pNode->IsTextNode())
1363  continue;
1364 
1365  SwContentNode* pNd = static_cast<SwContentNode*>(pNode);
1366  SvxLRSpaceItem aOldLR = static_cast<const SvxLRSpaceItem&>(pNd->GetAttr(RES_LR_SPACE));
1367 
1368  SwTextNode *pTextNode = static_cast<SwTextNode*>(pNode);
1369 
1370  const SwNumFormat* pNum
1371  = GetNumFormatFromStack(*aRegion.GetPoint(), *pTextNode);
1372  if (!pNum)
1373  {
1374  pNum = GetNumFormatFromTextNode(*pTextNode);
1375  }
1376 
1377  if ( pNum )
1378  {
1379  // #i103711#
1380  const bool bFirstLineIndentSet =
1383  // #i105414#
1384  const bool bLeftIndentSet =
1387  SyncIndentWithList( aNewLR, *pNum,
1388  bFirstLineIndentSet,
1389  bLeftIndentSet );
1390  }
1391 
1392  if (aNewLR == aOldLR)
1393  continue;
1394 
1395  pNd->SetAttr(aNewLR);
1396 
1397  }
1398  }
1399  }
1400  break;
1401 
1402  case RES_TXTATR_FIELD:
1403  OSL_ENSURE(false, "What is a field doing in the control stack,"
1404  "probably should have been in the endstack");
1405  break;
1406 
1407  case RES_TXTATR_ANNOTATION:
1408  OSL_ENSURE(false, "What is an annotation doing in the control stack,"
1409  "probably should have been in the endstack");
1410  break;
1411 
1412  case RES_TXTATR_INPUTFIELD:
1413  OSL_ENSURE(false, "What is an input field doing in the control stack,"
1414  "probably should have been in the endstack");
1415  break;
1416 
1417  case RES_TXTATR_INETFMT:
1418  {
1419  SwPaM aRegion(rTmpPos);
1421  {
1422  SwFrameFormat *pFrame;
1423  // If we have just one single inline graphic then
1424  // don't insert a field for the single frame, set
1425  // the frames hyperlink field attribute directly.
1427  if (nullptr != pFrame)
1428  {
1429  const SwFormatINetFormat *pAttr = static_cast<const SwFormatINetFormat *>(
1430  rEntry.m_pAttr.get());
1431  SwFormatURL aURL;
1432  aURL.SetURL(pAttr->GetValue(), false);
1433  aURL.SetTargetFrameName(pAttr->GetTargetFrame());
1434  pFrame->SetFormatAttr(aURL);
1435  }
1436  else
1437  {
1439  }
1440  }
1441  }
1442  break;
1443  default:
1444  SwFltControlStack::SetAttrInDoc(rTmpPos, rEntry);
1445  break;
1446  }
1447 }
1448 
1450  sal_uInt16 nWhich)
1451 {
1452  const SfxPoolItem *pItem = GetStackAttr(rPos, nWhich);
1453  if (!pItem)
1454  {
1455  SwContentNode const*const pNd = rPos.nNode.GetNode().GetContentNode();
1456  if (!pNd)
1457  pItem = &m_rDoc.GetAttrPool().GetDefaultItem(nWhich);
1458  else
1459  {
1460  /*
1461  If we're hunting for the indent on a paragraph and need to use the
1462  parent style indent, then return the indent in msword format, and
1463  not writer format, because that's the style that the filter works
1464  in (naturally)
1465  */
1466  if (nWhich == RES_LR_SPACE)
1467  {
1468  SfxItemState eState = SfxItemState::DEFAULT;
1469  if (const SfxItemSet *pSet = pNd->GetpSwAttrSet())
1470  eState = pSet->GetItemState(RES_LR_SPACE, false);
1471  if (eState != SfxItemState::SET && rReader.m_nCurrentColl < rReader.m_vColl.size())
1472  pItem = rReader.m_vColl[rReader.m_nCurrentColl].maWordLR.get();
1473  }
1474 
1475  /*
1476  If we're hunting for a character property, try and exact position
1477  within the text node for lookup
1478  */
1479  if (pNd->IsTextNode())
1480  {
1481  const sal_Int32 nPos = rPos.nContent.GetIndex();
1482  m_xScratchSet.reset(new SfxItemSet(m_rDoc.GetAttrPool(), nWhich, nWhich));
1483  if (pNd->GetTextNode()->GetParaAttr(*m_xScratchSet, nPos, nPos))
1484  pItem = m_xScratchSet->GetItem(nWhich);
1485  }
1486 
1487  if (!pItem)
1488  pItem = &pNd->GetAttr(nWhich);
1489  }
1490  }
1491  return pItem;
1492 }
1493 
1495  sal_uInt16 nWhich)
1496 {
1497  SwFltPosition aFltPos(rPos);
1498 
1499  size_t nSize = size();
1500  while (nSize)
1501  {
1502  const SwFltStackEntry& rEntry = (*this)[ --nSize ];
1503  if (rEntry.m_pAttr->Which() == nWhich)
1504  {
1505  if ( (rEntry.m_bOpen) ||
1506  (
1507  (rEntry.m_aMkPos.m_nNode <= aFltPos.m_nNode) &&
1508  (rEntry.m_aPtPos.m_nNode >= aFltPos.m_nNode) &&
1509  (rEntry.m_aMkPos.m_nContent <= aFltPos.m_nContent) &&
1510  (rEntry.m_aPtPos.m_nContent > aFltPos.m_nContent)
1511  )
1512  )
1513  /*
1514  * e.g. half-open range [0-3) so asking for properties at 3
1515  * means props that end at 3 are not included
1516  */
1517  {
1518  return rEntry.m_pAttr.get();
1519  }
1520  }
1521  }
1522  return nullptr;
1523 }
1524 
1526  const SwFormatField& rFormatField,
1527  sal_uInt16& rBkmNo)
1528 {
1529  const SwField* pField = rFormatField.GetField();
1530  sal_uInt16 nSubType;
1531  if(pField && (SwFieldIds::GetRef == pField->Which())
1532  && ((REF_FOOTNOTE == (nSubType = pField->GetSubType())) || (REF_ENDNOTE == nSubType))
1533  && !static_cast<const SwGetRefField*>(pField)->GetSetRefName().isEmpty())
1534  {
1535  const IDocumentMarkAccess* const pMarkAccess = m_rDoc.getIDocumentMarkAccess();
1537  pMarkAccess->findMark( static_cast<const SwGetRefField*>(pField)->GetSetRefName() );
1538  if(ppBkmk != pMarkAccess->getAllMarksEnd())
1539  {
1540  // find Sequence No of corresponding Foot-/Endnote
1541  rBkmNo = ppBkmk - pMarkAccess->getAllMarksBegin();
1542  return true;
1543  }
1544  }
1545  return false;
1546 }
1547 
1549  SwFltStackEntry& rEntry)
1550 {
1551  switch (rEntry.m_pAttr->Which())
1552  {
1553  /*
1554  Look up these in our lists of bookmarks that were changed to
1555  variables, and replace the ref field with a var field, otherwise
1556  do normal (?) strange stuff
1557  */
1558  case RES_TXTATR_FIELD:
1559  case RES_TXTATR_ANNOTATION:
1560  case RES_TXTATR_INPUTFIELD:
1561  {
1562  SwNodeIndex aIdx(rEntry.m_aMkPos.m_nNode, 1);
1563  SwPaM aPaM(aIdx, rEntry.m_aMkPos.m_nContent);
1564 
1565  SwFormatField& rFormatField = *static_cast<SwFormatField*>(rEntry.m_pAttr.get());
1566  SwField* pField = rFormatField.GetField();
1567 
1568  if (!RefToVar(pField, rEntry))
1569  {
1570  sal_uInt16 nBkmNo;
1571  if( IsFootnoteEdnBkmField(rFormatField, nBkmNo) )
1572  {
1573  ::sw::mark::IMark const * const pMark = m_rDoc.getIDocumentMarkAccess()->getAllMarksBegin()[nBkmNo];
1574 
1575  const SwPosition& rBkMrkPos = pMark->GetMarkPos();
1576 
1577  SwTextNode* pText = rBkMrkPos.nNode.GetNode().GetTextNode();
1578  if( pText && rBkMrkPos.nContent.GetIndex() )
1579  {
1580  SwTextAttr* const pFootnote = pText->GetTextAttrForCharAt(
1581  rBkMrkPos.nContent.GetIndex()-1, RES_TXTATR_FTN );
1582  if( pFootnote )
1583  {
1584  sal_uInt16 nRefNo = static_cast<SwTextFootnote*>(pFootnote)->GetSeqRefNo();
1585 
1586  static_cast<SwGetRefField*>(pField)->SetSeqNo( nRefNo );
1587 
1588  if( pFootnote->GetFootnote().IsEndNote() )
1589  static_cast<SwGetRefField*>(pField)->SetSubType(REF_ENDNOTE);
1590  }
1591  }
1592  }
1593  }
1594 
1596  MoveAttrs(*aPaM.GetPoint());
1597  }
1598  break;
1599  case RES_FLTR_TOX:
1600  SwFltEndStack::SetAttrInDoc(rTmpPos, rEntry);
1601  break;
1602  default:
1603  case RES_FLTR_BOOKMARK:
1604  OSL_ENSURE(false, "EndStck used with non field, not what we want");
1605  SwFltEndStack::SetAttrInDoc(rTmpPos, rEntry);
1606  break;
1607  }
1608 }
1609 
1610 /*
1611  For styles we will do our tabstop arithmetic in word style and adjust them to
1612  writer style after all the styles have been finished and the dust settles as
1613  to what affects what.
1614 
1615  For explicit attributes we turn the adjusted writer tabstops back into 0 based
1616  word indexes and we'll turn them back into writer indexes when setting them
1617  into the document. If explicit left indent exist which affects them, then this
1618  is handled when the explicit left indent is set into the document
1619 */
1620 void SwWW8ImplReader::Read_Tab(sal_uInt16 , const sal_uInt8* pData, short nLen)
1621 {
1622  if (nLen < 0)
1623  {
1625  return;
1626  }
1627 
1628  sal_uInt8 nDel = (nLen > 0) ? pData[0] : 0;
1629  const sal_uInt8* pDel = pData + 1; // Del - Array
1630 
1631  sal_uInt8 nIns = (nLen > nDel*2+1) ? pData[nDel*2+1] : 0;
1632  const sal_uInt8* pIns = pData + 2*nDel + 2; // Ins - Array
1633 
1634  short nRequiredLength = 2 + 2*nDel + 2*nIns + 1*nIns;
1635  if (nRequiredLength > nLen)
1636  {
1637  // would require more data than available to describe!
1638  // discard invalid record
1639  nIns = 0;
1640  nDel = 0;
1641  }
1642 
1643  WW8_TBD const * pTyp = reinterpret_cast<WW8_TBD const *>(pData + 2*nDel + 2*nIns + 2); // Type Array
1644 
1645  std::shared_ptr<SvxTabStopItem> aAttr(std::make_shared<SvxTabStopItem>(0, 0, SvxTabAdjust::Default, RES_PARATR_TABSTOP));
1646 
1647  const SwFormat * pSty = nullptr;
1648  sal_uInt16 nTabBase;
1649  if (m_pCurrentColl && m_nCurrentColl < m_vColl.size()) // StyleDef
1650  {
1651  nTabBase = m_vColl[m_nCurrentColl].m_nBase;
1652  if (nTabBase < m_vColl.size()) // Based On
1653  pSty = m_vColl[nTabBase].m_pFormat;
1654  }
1655  else
1656  { // Text
1657  nTabBase = m_nCurrentColl;
1658  if (m_nCurrentColl < m_vColl.size())
1659  pSty = m_vColl[m_nCurrentColl].m_pFormat;
1660  //TODO: figure out else here
1661  }
1662 
1663  bool bFound = false;
1664  std::unordered_set<size_t> aLoopWatch;
1665  while (pSty && !bFound)
1666  {
1667  const SfxPoolItem* pTabs;
1668  bFound = pSty->GetAttrSet().GetItemState(RES_PARATR_TABSTOP, false,
1669  &pTabs) == SfxItemState::SET;
1670  if( bFound )
1671  {
1672  aAttr.reset(static_cast<SvxTabStopItem*>(pTabs->Clone()));
1673  }
1674  else
1675  {
1676  sal_uInt16 nOldTabBase = nTabBase;
1677  // If based on another
1678  if (nTabBase < m_vColl.size())
1679  nTabBase = m_vColl[nTabBase].m_nBase;
1680 
1681  if (
1682  nTabBase < m_vColl.size() &&
1683  nOldTabBase != nTabBase &&
1684  nTabBase != ww::stiNil
1685  )
1686  {
1687  // #i61789: Stop searching when next style is the same as the
1688  // current one (prevent loop)
1689  aLoopWatch.insert(reinterpret_cast<size_t>(pSty));
1690  if (nTabBase < m_vColl.size())
1691  pSty = m_vColl[nTabBase].m_pFormat;
1692  //TODO figure out the else branch
1693 
1694  if (aLoopWatch.find(reinterpret_cast<size_t>(pSty)) !=
1695  aLoopWatch.end())
1696  pSty = nullptr;
1697  }
1698  else
1699  pSty = nullptr; // Give up on the search
1700  }
1701  }
1702 
1703  SvxTabStop aTabStop;
1704  for (short i=0; i < nDel; ++i)
1705  {
1706  sal_uInt16 nPos = aAttr->GetPos(SVBT16ToUInt16(pDel + i*2));
1707  if( nPos != SVX_TAB_NOTFOUND )
1708  aAttr->Remove( nPos );
1709  }
1710 
1711  for (short i=0; i < nIns; ++i)
1712  {
1713  short nPos = SVBT16ToUInt16(pIns + i*2);
1714  aTabStop.GetTabPos() = nPos;
1715  switch( pTyp[i].aBits1 & 0x7 ) // pTyp[i].jc
1716  {
1717  case 0:
1718  aTabStop.GetAdjustment() = SvxTabAdjust::Left;
1719  break;
1720  case 1:
1721  aTabStop.GetAdjustment() = SvxTabAdjust::Center;
1722  break;
1723  case 2:
1724  aTabStop.GetAdjustment() = SvxTabAdjust::Right;
1725  break;
1726  case 3:
1727  aTabStop.GetAdjustment() = SvxTabAdjust::Decimal;
1728  break;
1729  case 4:
1730  continue; // Ignore Bar
1731  }
1732 
1733  switch( pTyp[i].aBits1 >> 3 & 0x7 )
1734  {
1735  case 0:
1736  aTabStop.GetFill() = ' ';
1737  break;
1738  case 1:
1739  aTabStop.GetFill() = '.';
1740  break;
1741  case 2:
1742  aTabStop.GetFill() = '-';
1743  break;
1744  case 3:
1745  case 4:
1746  aTabStop.GetFill() = '_';
1747  break;
1748  }
1749 
1750  sal_uInt16 nPos2 = aAttr->GetPos( nPos );
1751  if (nPos2 != SVX_TAB_NOTFOUND)
1752  aAttr->Remove(nPos2); // Or else Insert() refuses
1753  aAttr->Insert(aTabStop);
1754  }
1755 
1756  if (nIns || nDel)
1757  NewAttr(*aAttr);
1758  else
1759  {
1760  // Here we have a tab definition which inserts no extra tabs, or deletes
1761  // no existing tabs. An older version of writer is probably the creator
1762  // of the document :-( . So if we are importing a style we can just
1763  // ignore it. But if we are importing into text we cannot as during
1764  // text SwWW8ImplReader::Read_Tab is called at the begin and end of
1765  // the range the attrib affects, and ignoring it would upset the
1766  // balance
1767  if (!m_pCurrentColl) // not importing into a style
1768  {
1769  SvxTabStopItem aOrig = pSty ?
1770  ItemGet<SvxTabStopItem>(*pSty, RES_PARATR_TABSTOP) :
1771  DefaultItemGet<SvxTabStopItem>(m_rDoc, RES_PARATR_TABSTOP);
1772  NewAttr(aOrig);
1773  }
1774  }
1775 }
1776 
1781 {
1782  // correct the LastPrinted date in DocumentProperties
1783  uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
1784  m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
1785  uno::Reference<document::XDocumentProperties> xDocuProps(
1786  xDPS->getDocumentProperties());
1787  OSL_ENSURE(xDocuProps.is(), "DocumentProperties is null");
1788  if (xDocuProps.is())
1789  {
1790  DateTime aLastPrinted(
1791  msfilter::util::DTTM2DateTime(m_xWDop->dttmLastPrint));
1792  ::util::DateTime uDT = aLastPrinted.GetUNODateTime();
1793  xDocuProps->setPrintDate(uDT);
1794  }
1795 
1796  // COMPATIBILITY FLAGS START
1797 
1798  // #i78951# - remember the unknown compatibility options
1799  // so as to export them out
1802 
1803  // The distance between two paragraphs is the sum of the bottom distance of
1804  // the first paragraph and the top distance of the second one
1807  // move tabs on alignment
1809  // #i24363# tab stops relative to indent
1811  // tdf#117923
1816  // tdf#128195
1823 
1824  // Import Default Tabs
1825  tools::Long nDefTabSiz = m_xWDop->dxaTab;
1826  if( nDefTabSiz < 56 )
1827  nDefTabSiz = 709;
1828 
1829  // We want exactly one DefaultTab
1830  SvxTabStopItem aNewTab( 1, sal_uInt16(nDefTabSiz), SvxTabAdjust::Default, RES_PARATR_TABSTOP );
1831  const_cast<SvxTabStop&>(aNewTab[0]).GetAdjustment() = SvxTabAdjust::Default;
1832 
1833  m_rDoc.GetAttrPool().SetPoolDefaultItem( aNewTab );
1834 
1835  // Import zoom factor
1836  if (m_xWDop->wScaleSaved)
1837  {
1838  //Import zoom type
1839  sal_Int16 nZoomType;
1840  switch (m_xWDop->zkSaved) {
1841  case 1: nZoomType = sal_Int16(SvxZoomType::WHOLEPAGE); break;
1842  case 2: nZoomType = sal_Int16(SvxZoomType::PAGEWIDTH); break;
1843  case 3: nZoomType = sal_Int16(SvxZoomType::OPTIMAL); break;
1844  default: nZoomType = sal_Int16(SvxZoomType::PERCENT); break;
1845  }
1846  uno::Sequence<beans::PropertyValue> aViewProps( comphelper::InitPropertySequence({
1847  { "ZoomFactor", uno::Any(sal_Int16(m_xWDop->wScaleSaved)) },
1848  { "VisibleBottom", uno::Any(sal_Int32(0)) },
1849  { "ZoomType", uno::Any(nZoomType) }
1850  }));
1851 
1852  uno::Reference< uno::XComponentContext > xComponentContext(comphelper::getProcessComponentContext());
1853  uno::Reference<container::XIndexContainer> xBox = document::IndexedPropertyValues::create(xComponentContext);
1854  xBox->insertByIndex(sal_Int32(0), uno::makeAny(aViewProps));
1855  uno::Reference<document::XViewDataSupplier> xViewDataSupplier(m_pDocShell->GetModel(), uno::UNO_QUERY);
1856  xViewDataSupplier->setViewData(xBox);
1857  }
1858 
1868 
1869  // #i25901# - set new compatibility option
1870  // 'Add paragraph and table spacing at bottom of table cells'
1873 
1874  // #i11860# - set new compatibility option
1875  // 'Use former object positioning' to <false>
1877 
1878  // #i27767# - set new compatibility option
1879  // 'Consider Wrapping mode when positioning object' to <true>
1881 
1883 
1884  m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TABLE_ROW_KEEP, true); //SetTableRowKeep( true );
1885 
1887 
1896 
1897  // COMPATIBILITY FLAGS END
1898 
1899  // Import magic doptypography information, if it's there
1900  if (m_xWwFib->m_nFib > 105)
1901  ImportDopTypography(m_xWDop->doptypography);
1902 
1903  // disable form design mode to be able to use imported controls directly
1904  // #i31239# always disable form design mode, not only in protected docs
1905  uno::Reference<beans::XPropertySet> xDocProps(m_pDocShell->GetModel(), uno::UNO_QUERY);
1906  if (xDocProps.is())
1907  {
1908  uno::Reference<beans::XPropertySetInfo> xInfo = xDocProps->getPropertySetInfo();
1909  if (xInfo.is())
1910  {
1911  if (xInfo->hasPropertyByName("ApplyFormDesignMode"))
1912  xDocProps->setPropertyValue("ApplyFormDesignMode", css::uno::makeAny(false));
1913  }
1914  }
1915 
1916  // The password can force read-only, comments-only, fill-in-form-only, or require track-changes.
1917  // Treat comments-only like read-only since Writer has no support for that.
1918  // Still allow editing of form fields, without requiring the password.
1919  // Still allow editing if track-changes is locked on. (Currently LockRev is ignored/lost on export anyway.)
1920  if (!m_xWDop->fProtEnabled && !m_xWDop->fLockRev)
1921  m_pDocShell->SetModifyPasswordHash(m_xWDop->lKeyProtDoc);
1922  else if ( xDocProps.is() )
1923  {
1924  comphelper::SequenceAsHashMap aGrabBag(xDocProps->getPropertyValue("InteropGrabBag"));
1925  aGrabBag["FormPasswordHash"] <<= m_xWDop->lKeyProtDoc;
1926  xDocProps->setPropertyValue("InteropGrabBag", uno::Any(aGrabBag.getAsConstPropertyValueList()));
1927  }
1928 
1929  const SvtFilterOptions& rOpt = SvtFilterOptions::Get();
1930  if (rOpt.IsUseEnhancedFields())
1932 
1933  if (m_xWDop->iGutterPos)
1934  {
1936  }
1937 }
1938 
1940 {
1941  switch (rTypo.m_iLevelOfKinsoku)
1942  {
1943  case 2: // custom
1944  {
1945  i18n::ForbiddenCharacters aForbidden(OUString(+rTypo.m_rgxchFPunct),
1946  OUString(+rTypo.m_rgxchLPunct));
1947  // unary + makes sure not to accidentally call the
1948  // OUString(ConstCharArrayDetector<...>::TypeUtf16) ctor that takes the full
1949  // m_rgxchFPunct, m_rgxchLPunct arrays with embedded NULs, instead of just the
1950  // prefix leading up to the first NUL
1952  aForbidden);
1953  // Obviously cannot set the standard level 1 for japanese, so
1954  // bail out now while we can.
1955  if (rTypo.GetConvertedLang() == LANGUAGE_JAPANESE)
1956  return;
1957  }
1958  break;
1959  default:
1960  break;
1961  }
1962 
1963  /*
1964  This MS hack means that level 2 of japanese is not in operation, so we put
1965  in what we know are the MS defaults, there is a complementary reverse
1966  hack in the writer. Its our default as well, but we can set it anyway
1967  as a flag for later.
1968  */
1969  if (!rTypo.m_reserved2)
1970  {
1971  i18n::ForbiddenCharacters aForbidden(WW8DopTypography::JapanNotBeginLevel1,
1974  }
1975 
1977  m_rDoc.getIDocumentSettingAccess().setCharacterCompressionType(static_cast<CharCompressType>(rTypo.m_iJustification));
1978 }
1979 
1984  mxTmpPos(pRdr->m_rDoc.CreateUnoCursor(*pRdr->m_pPaM->GetPoint())),
1985  mxOldStck(std::move(pRdr->m_xCtrlStck)),
1986  mxOldAnchorStck(std::move(pRdr->m_xAnchorStck)),
1987  mxOldRedlines(std::move(pRdr->m_xRedlineStack)),
1988  mxOldPlcxMan(pRdr->m_xPlcxMan),
1989  mpWFlyPara(std::move(pRdr->m_xWFlyPara)),
1990  mpSFlyPara(std::move(pRdr->m_xSFlyPara)),
1991  mpPreviousNumPaM(pRdr->m_pPreviousNumPaM),
1992  mpPrevNumRule(pRdr->m_pPrevNumRule),
1993  mxTableDesc(std::move(pRdr->m_xTableDesc)),
1994  mnInTable(pRdr->m_nInTable),
1995  mnCurrentColl(pRdr->m_nCurrentColl),
1996  mcSymbol(pRdr->m_cSymbol),
1997  mbIgnoreText(pRdr->m_bIgnoreText),
1998  mbSymbol(pRdr->m_bSymbol),
1999  mbHdFtFootnoteEdn(pRdr->m_bHdFtFootnoteEdn),
2000  mbTxbxFlySection(pRdr->m_bTxbxFlySection),
2001  mbAnl(pRdr->m_bAnl),
2002  mbInHyperlink(pRdr->m_bInHyperlink),
2003  mbPgSecBreak(pRdr->m_bPgSecBreak),
2004  mbWasParaEnd(pRdr->m_bWasParaEnd),
2005  mbHasBorder(pRdr->m_bHasBorder),
2006  mbFirstPara(pRdr->m_bFirstPara)
2007 {
2008  pRdr->m_bSymbol = false;
2009  pRdr->m_bHdFtFootnoteEdn = true;
2010  pRdr->m_bTxbxFlySection = pRdr->m_bAnl = pRdr->m_bPgSecBreak = pRdr->m_bWasParaEnd
2011  = pRdr->m_bHasBorder = false;
2012  pRdr->m_bFirstPara = true;
2013  pRdr->m_nInTable = 0;
2014  pRdr->m_pPreviousNumPaM = nullptr;
2015  pRdr->m_pPrevNumRule = nullptr;
2016  pRdr->m_nCurrentColl = 0;
2017 
2018  pRdr->m_xCtrlStck.reset(new SwWW8FltControlStack(pRdr->m_rDoc, pRdr->m_nFieldFlags,
2019  *pRdr));
2020 
2021  pRdr->m_xRedlineStack.reset(new sw::util::RedlineStack(pRdr->m_rDoc));
2022 
2023  pRdr->m_xAnchorStck.reset(new SwWW8FltAnchorStack(pRdr->m_rDoc, pRdr->m_nFieldFlags));
2024 
2025  // Save the attribute manager: we need this as the newly created PLCFx Manager
2026  // access the same FKPs as the old one and their Start-End position changes.
2027  if (pRdr->m_xPlcxMan)
2028  pRdr->m_xPlcxMan->SaveAllPLCFx(maPLCFxSave);
2029 
2030  if (nStartCp != -1)
2031  {
2032  pRdr->m_xPlcxMan = std::make_shared<WW8PLCFMan>(pRdr->m_xSBase.get(),
2033  mxOldPlcxMan->GetManType(), nStartCp);
2034  }
2035 
2036  maOldApos.push_back(false);
2037  maOldApos.swap(pRdr->m_aApos);
2038  maOldFieldStack.swap(pRdr->m_aFieldStack);
2039 }
2040 
2042 {
2043  pRdr->m_xWFlyPara = std::move(mpWFlyPara);
2044  pRdr->m_xSFlyPara = std::move(mpSFlyPara);
2046  pRdr->m_pPrevNumRule = mpPrevNumRule;
2047  pRdr->m_xTableDesc = std::move(mxTableDesc);
2048  pRdr->m_cSymbol = mcSymbol;
2049  pRdr->m_bSymbol = mbSymbol;
2050  pRdr->m_bIgnoreText = mbIgnoreText;
2053  pRdr->m_nInTable = mnInTable;
2054  pRdr->m_bAnl = mbAnl;
2055  pRdr->m_bInHyperlink = mbInHyperlink;
2056  pRdr->m_bWasParaEnd = mbWasParaEnd;
2057  pRdr->m_bPgSecBreak = mbPgSecBreak;
2058  pRdr->m_nCurrentColl = mnCurrentColl;
2059  pRdr->m_bHasBorder = mbHasBorder;
2060  pRdr->m_bFirstPara = mbFirstPara;
2061 
2062  // Close all attributes as attributes could be created that extend the Fly
2063  pRdr->DeleteCtrlStack();
2064  pRdr->m_xCtrlStck = std::move(mxOldStck);
2065 
2066  pRdr->m_xRedlineStack->closeall(*pRdr->m_pPaM->GetPoint());
2067 
2068  // ofz#37322 drop m_pLastAnchorPos during RedlineStack dtor and restore it afterwards to the same
2069  // place, or somewhere close if that place got destroyed
2070  std::shared_ptr<SwUnoCursor> xLastAnchorCursor(pRdr->m_pLastAnchorPos ? pRdr->m_rDoc.CreateUnoCursor(*pRdr->m_pLastAnchorPos) : nullptr);
2071  pRdr->m_pLastAnchorPos.reset();
2072 
2073  pRdr->m_xRedlineStack = std::move(mxOldRedlines);
2074 
2075  if (xLastAnchorCursor)
2076  pRdr->m_pLastAnchorPos.reset(new SwPosition(*xLastAnchorCursor->GetPoint()));
2077 
2078  pRdr->DeleteAnchorStack();
2079  pRdr->m_xAnchorStck = std::move(mxOldAnchorStck);
2080 
2081  *pRdr->m_pPaM->GetPoint() = GetStartPos();
2082 
2083  if (mxOldPlcxMan != pRdr->m_xPlcxMan)
2084  pRdr->m_xPlcxMan = mxOldPlcxMan;
2085  if (pRdr->m_xPlcxMan)
2086  pRdr->m_xPlcxMan->RestoreAllPLCFx(maPLCFxSave);
2087  pRdr->m_aApos.swap(maOldApos);
2088  pRdr->m_aFieldStack.swap(maOldFieldStack);
2089 }
2090 
2092  WW8_CP nStartCp, WW8_CP nLen, ManTypes nType )
2093 {
2094  if (nStartCp < 0 || nLen < 0)
2095  return;
2096 
2097  // Saves Flags (amongst other things) and resets them
2098  WW8ReaderSave aSave( this );
2099 
2100  m_pPaM->GetPoint()->nNode = pSttIdx->GetIndex() + 1;
2102 
2103  // Read Text for Header, Footer or Footnote
2104  ReadText( nStartCp, nLen, nType ); // Ignore Sepx when doing so
2105  aSave.Restore( this );
2106 }
2107 
2112 {
2113  WW8PLCFx_SubDoc* pSD = m_xPlcxMan->GetAtn();
2114  if (!pSD)
2115  return 0;
2116 
2117  const void* pData = pSD->GetData();
2118  if (!pData)
2119  return 0;
2120 
2121  OUString sAuthor;
2122  OUString sInitials;
2123  if( m_bVer67 )
2124  {
2125  const WW67_ATRD* pDescri = static_cast<const WW67_ATRD*>(pData);
2126  const OUString* pA = GetAnnotationAuthor(SVBT16ToUInt16(pDescri->ibst));
2127  if (pA)
2128  sAuthor = *pA;
2129  else
2130  {
2131  const sal_uInt8 nLen = std::min<sal_uInt8>(pDescri->xstUsrInitl[0],
2132  SAL_N_ELEMENTS(pDescri->xstUsrInitl)-1);
2133  sAuthor = OUString(pDescri->xstUsrInitl + 1, nLen, RTL_TEXTENCODING_MS_1252);
2134  }
2135  }
2136  else
2137  {
2138  const WW8_ATRD* pDescri = static_cast<const WW8_ATRD*>(pData);
2139  {
2140  const sal_uInt16 nLen = std::min<sal_uInt16>(SVBT16ToUInt16(pDescri->xstUsrInitl[0]),
2141  SAL_N_ELEMENTS(pDescri->xstUsrInitl)-1);
2142  OUStringBuffer aBuf;
2143  aBuf.setLength(nLen);
2144  for(sal_uInt16 nIdx = 1; nIdx <= nLen; ++nIdx)
2145  aBuf[nIdx-1] = SVBT16ToUInt16(pDescri->xstUsrInitl[nIdx]);
2146  sInitials = aBuf.makeStringAndClear();
2147  }
2148 
2149  if (const OUString* pA = GetAnnotationAuthor(SVBT16ToUInt16(pDescri->ibst)))
2150  sAuthor = *pA;
2151  else
2152  sAuthor = sInitials;
2153  }
2154 
2155  sal_uInt32 nDateTime = 0;
2156 
2157  if (sal_uInt8 * pExtended = m_xPlcxMan->GetExtendedAtrds()) // Word < 2002 has no date data for comments
2158  {
2159  sal_uLong nIndex = pSD->GetIdx() & 0xFFFF; // Index is (stupidly) multiplexed for WW8PLCFx_SubDocs
2160  if (m_xWwFib->m_lcbAtrdExtra/18 > nIndex)
2161  nDateTime = SVBT32ToUInt32(*reinterpret_cast<SVBT32*>(pExtended+(nIndex*18)));
2162  }
2163 
2164  DateTime aDate = msfilter::util::DTTM2DateTime(nDateTime);
2165 
2166  OUString sText;
2168  pRes->nCp2OrIdx + pRes->nMemLen, MAN_AND );
2169 
2171  SwPostItField aPostIt(
2172  static_cast<SwPostItFieldType*>(m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Postit)), sAuthor,
2173  sText, sInitials, OUString(), aDate );
2174  aPostIt.SetTextObject(std::move(pOutliner));
2175 
2176  SwPaM aEnd(*m_pPaM->End(), *m_pPaM->End());
2177  m_xCtrlStck->NewAttr(*aEnd.GetPoint(), SvxCharHiddenItem(false, RES_CHRATR_HIDDEN));
2179  m_xCtrlStck->SetAttr(*aEnd.GetPoint(), RES_CHRATR_HIDDEN);
2180  // If this is a range, make sure that it ends after the just inserted character, not before it.
2182 
2183  return 0;
2184 }
2185 
2187  SwFrameFormat const &rHdFtFormat, sal_uInt16 nPageWidth)
2188 {
2189  const SwNodeIndex* pSttIdx = rHdFtFormat.GetContent().GetContentIdx();
2190  OSL_ENSURE(pSttIdx, "impossible");
2191  if (!pSttIdx)
2192  return;
2193 
2194  SwPosition aTmpPos(*m_pPaM->GetPoint());
2195 
2196  m_pPaM->GetPoint()->nNode = pSttIdx->GetIndex() + 1;
2198 
2199  // tdf#122425: Explicitly remove borders and spacing
2202 
2203  SwFlyFrameFormat* pFrame
2204  = m_rDoc.MakeFlySection(RndStdIds::FLY_AT_PARA, m_pPaM->GetPoint(), &aFlySet);
2205 
2206  SwFormatAnchor aAnch( pFrame->GetAnchor() );
2207  aAnch.SetType( RndStdIds::FLY_AT_PARA );
2208  pFrame->SetFormatAttr( aAnch );
2209  SwFormatFrameSize aSz(SwFrameSize::Minimum, nPageWidth, MINLAY);
2210  SwFrameSize eFrameSize = SwFrameSize::Minimum;
2211  if( eFrameSize != aSz.GetWidthSizeType() )
2212  aSz.SetWidthSizeType( eFrameSize );
2213  pFrame->SetFormatAttr(aSz);
2214  pFrame->SetFormatAttr(SwFormatSurround(css::text::WrapTextMode_THROUGH));
2215  pFrame->SetFormatAttr(SwFormatHoriOrient(0, text::HoriOrientation::LEFT)); //iFOO
2216 
2217  // #i43427# - send frame for header/footer into background.
2218  pFrame->SetFormatAttr( SvxOpaqueItem( RES_OPAQUE, false ) );
2219  SdrObject* pFrameObj = CreateContactObject( pFrame );
2220  OSL_ENSURE( pFrameObj,
2221  "<SwWW8ImplReader::Read_HdFtTextAsHackedFrame(..)> - missing SdrObject instance" );
2222  if ( pFrameObj )
2223  {
2224  pFrameObj->SetOrdNum( 0 );
2225  }
2226  MoveInsideFly(pFrame);
2227 
2228  const SwNodeIndex* pHackIdx = pFrame->GetContent().GetContentIdx();
2229 
2230  Read_HdFtFootnoteText(pHackIdx, nStart, nLen - 1, MAN_HDFT);
2231 
2232  MoveOutsideFly(pFrame, aTmpPos);
2233 }
2234 
2235 void SwWW8ImplReader::Read_HdFtText(WW8_CP nStart, WW8_CP nLen, SwFrameFormat const * pHdFtFormat)
2236 {
2237  const SwNodeIndex* pSttIdx = pHdFtFormat->GetContent().GetContentIdx();
2238  if (!pSttIdx)
2239  return;
2240 
2241  SwPosition aTmpPos( *m_pPaM->GetPoint() ); // Remember old cursor position
2242 
2243  Read_HdFtFootnoteText(pSttIdx, nStart, nLen - 1, MAN_HDFT);
2244 
2245  *m_pPaM->GetPoint() = aTmpPos;
2246 }
2247 
2249 {
2250  // Each CP of Plcfhdd MUST be less than FibRgLw97.ccpHdd
2251  return (nHeaderCP < m_xWwFib->m_ccpHdr && nHeaderCP >= 0);
2252 }
2253 
2255  int nSect)
2256 {
2257  if (m_xHdFt)
2258  {
2259  WW8_CP nStart, nLen;
2260  sal_uInt8 nNumber = 5;
2261 
2262  for( sal_uInt8 nI = 0x20; nI; nI >>= 1, nNumber-- )
2263  {
2264  if (nI & nWhichItems)
2265  {
2266  bool bOk = true;
2267  if( m_bVer67 )
2268  bOk = ( m_xHdFt->GetTextPos(grpfIhdt, nI, nStart, nLen ) && nStart >= 0 && nLen >= 2 );
2269  else
2270  {
2271  m_xHdFt->GetTextPosExact( static_cast< short >(nNumber + (nSect+1)*6), nStart, nLen);
2272  bOk = ( 2 <= nLen ) && isValid_HdFt_CP(nStart);
2273  }
2274 
2275  if (bOk)
2276  return true;
2277  }
2278  }
2279  }
2280  return false;
2281 }
2282 
2283 void SwWW8ImplReader::Read_HdFt(int nSect, const SwPageDesc *pPrev,
2284  const wwSection &rSection)
2285 {
2286  sal_uInt8 grpfIhdt = rSection.maSep.grpfIhdt;
2287  SwPageDesc *pPD = rSection.mpPage;
2288 
2289  if( !m_xHdFt )
2290  return;
2291 
2292  WW8_CP nStart, nLen;
2293  sal_uInt8 nNumber = 5;
2294 
2295  // This loops through the 6 flags WW8_{FOOTER,HEADER}_{ODD,EVEN,FIRST}
2296  // corresponding to bit fields in grpfIhdt indicating which
2297  // header/footer(s) are present in this section
2298  for( sal_uInt8 nI = 0x20; nI; nI >>= 1, nNumber-- )
2299  {
2300  if (nI & grpfIhdt)
2301  {
2302  bool bOk = true;
2303  if( m_bVer67 )
2304  bOk = ( m_xHdFt->GetTextPos(grpfIhdt, nI, nStart, nLen ) && nLen >= 2 );
2305  else
2306  {
2307  m_xHdFt->GetTextPosExact( static_cast< short >(nNumber + (nSect+1)*6), nStart, nLen);
2308  bOk = ( 2 <= nLen ) && isValid_HdFt_CP(nStart);
2309  }
2310 
2311  bool bUseLeft
2312  = (nI & ( WW8_HEADER_EVEN | WW8_FOOTER_EVEN )) != 0;
2313  bool bUseFirst
2314  = (nI & ( WW8_HEADER_FIRST | WW8_FOOTER_FIRST )) != 0;
2315 
2316  // If we are loading a first-page header/footer which is not
2317  // actually enabled in this section (it still needs to be
2318  // loaded as it may be inherited by a later section)
2319  bool bDisabledFirst = bUseFirst && !rSection.HasTitlePage();
2320 
2321  bool bFooter
2322  = (nI & ( WW8_FOOTER_EVEN | WW8_FOOTER_ODD | WW8_FOOTER_FIRST )) != 0;
2323 
2324  SwFrameFormat& rFormat = bUseLeft ? pPD->GetLeft()
2325  : bUseFirst ? pPD->GetFirstMaster()
2326  : pPD->GetMaster();
2327 
2328  SwFrameFormat* pHdFtFormat;
2329  // If we have empty first page header and footer.
2330  bool bNoFirst = !(grpfIhdt & WW8_HEADER_FIRST) && !(grpfIhdt & WW8_FOOTER_FIRST);
2331  if (bFooter)
2332  {
2333  m_bIsFooter = true;
2334  //#i17196# Cannot have left without right
2335  if (!bDisabledFirst
2336  && !pPD->GetMaster().GetFooter().GetFooterFormat())
2337  pPD->GetMaster().SetFormatAttr(SwFormatFooter(true));
2338  if (bUseLeft)
2339  pPD->GetLeft().SetFormatAttr(SwFormatFooter(true));
2340  if (bUseFirst || (rSection.maSep.fTitlePage && bNoFirst))
2342  pHdFtFormat = const_cast<SwFrameFormat*>(rFormat.GetFooter().GetFooterFormat());
2343  }
2344  else
2345  {
2346  m_bIsHeader = true;
2347  //#i17196# Cannot have left without right
2348  if (!bDisabledFirst
2349  && !pPD->GetMaster().GetHeader().GetHeaderFormat())
2350  pPD->GetMaster().SetFormatAttr(SwFormatHeader(true));
2351  if (bUseLeft)
2352  pPD->GetLeft().SetFormatAttr(SwFormatHeader(true));
2353  if (bUseFirst || (rSection.maSep.fTitlePage && bNoFirst))
2355  pHdFtFormat = const_cast<SwFrameFormat*>(rFormat.GetHeader().GetHeaderFormat());
2356  }
2357 
2358  if (bOk)
2359  {
2360  bool bHackRequired = false;
2361  if (m_bIsHeader && rSection.IsFixedHeightHeader())
2362  bHackRequired = true;
2363  else if (m_bIsFooter && rSection.IsFixedHeightFooter())
2364  bHackRequired = true;
2365 
2366  if (bHackRequired)
2367  {
2368  Read_HdFtTextAsHackedFrame(nStart, nLen, *pHdFtFormat,
2369  static_cast< sal_uInt16 >(rSection.GetTextAreaWidth()) );
2370  }
2371  else
2372  Read_HdFtText(nStart, nLen, pHdFtFormat);
2373  }
2374  else if (pPrev)
2375  CopyPageDescHdFt(pPrev, pPD, nI);
2376 
2377  m_bIsHeader = m_bIsFooter = false;
2378  }
2379  }
2380 }
2381 
2383 {
2384  return ( mrReader.m_xWDop->fProtEnabled && !rSection.IsNotProtected() );
2385 }
2386 
2387 void wwSectionManager::SetHdFt(wwSection const &rSection, int nSect,
2388  const wwSection *pPrevious)
2389 {
2390  // Header/Footer not present
2391  if (!rSection.maSep.grpfIhdt)
2392  return;
2393 
2394  OSL_ENSURE(rSection.mpPage, "makes no sense to call with a main page");
2395  if (rSection.mpPage)
2396  {
2397  mrReader.Read_HdFt(nSect, pPrevious ? pPrevious->mpPage : nullptr,
2398  rSection);
2399  }
2400 
2401  // Header/Footer - Update Index
2402  // So that the index is still valid later on
2403  if (mrReader.m_xHdFt)
2404  mrReader.m_xHdFt->UpdateIndex(rSection.maSep.grpfIhdt);
2405 
2406 }
2407 
2409 {
2410  SwTextNode* pText = m_pPaM->GetNode().GetTextNode();
2411 
2412  const SwNumRule* pRule = nullptr;
2413 
2414  if (pText != nullptr)
2415  pRule = sw::util::GetNumRuleFromTextNode(*pText);
2416 
2417  if (
2418  pRule && !m_xWDop->fDontUseHTMLAutoSpacing &&
2420  )
2421  {
2422  // If after spacing is set to auto, set the after space to 0
2423  if (m_bParaAutoAfter)
2424  SetLowerSpacing(*m_pPaM, 0);
2425 
2426  // If the previous textnode had numbering and
2427  // and before spacing is set to auto, set before space to 0
2429  SetUpperSpacing(*m_pPaM, 0);
2430 
2431  // If the previous numbering rule was different we need
2432  // to insert a space after the previous paragraph
2433  if((pRule != m_pPrevNumRule) && m_pPreviousNumPaM)
2434  SetLowerSpacing(*m_pPreviousNumPaM, GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
2435 
2436  // cache current paragraph
2437  if(m_pPreviousNumPaM)
2438  {
2439  delete m_pPreviousNumPaM;
2440  m_pPreviousNumPaM = nullptr;
2441  }
2442 
2444  m_pPrevNumRule = pRule;
2445  }
2446  else if(!pRule && m_pPreviousNumPaM)
2447  {
2448  // If the previous paragraph has numbering but the current one does not
2449  // we need to add a space after the previous paragraph
2450  SetLowerSpacing(*m_pPreviousNumPaM, GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
2451  delete m_pPreviousNumPaM;
2452  m_pPreviousNumPaM = nullptr;
2453  m_pPrevNumRule = nullptr;
2454  }
2455  else
2456  {
2457  // clear paragraph cache
2458  if(m_pPreviousNumPaM)
2459  {
2460  delete m_pPreviousNumPaM;
2461  m_pPreviousNumPaM = nullptr;
2462  }
2463  m_pPrevNumRule = pRule;
2464  }
2465 
2466  // If this is the first paragraph in the document and
2467  // Auto-spacing before paragraph is set,
2468  // set the upper spacing value to 0
2469  if(m_bParaAutoBefore && m_bFirstPara && !m_xWDop->fDontUseHTMLAutoSpacing)
2470  SetUpperSpacing(*m_pPaM, 0);
2471 
2472  m_bFirstPara = false;
2473 
2475 
2476  // We can flush all anchored graphics at the end of a paragraph.
2477  m_xAnchorStck->Flush();
2478 }
2479 
2480 bool SwWW8ImplReader::SetSpacing(SwPaM &rMyPam, int nSpace, bool bIsUpper )
2481 {
2482  bool bRet = false;
2483  const SwPosition* pSpacingPos = rMyPam.GetPoint();
2484 
2485  const SvxULSpaceItem* pULSpaceItem = m_xCtrlStck->GetFormatAttr(*pSpacingPos, RES_UL_SPACE);
2486 
2487  if(pULSpaceItem != nullptr)
2488  {
2489  SvxULSpaceItem aUL(*pULSpaceItem);
2490 
2491  if(bIsUpper)
2492  aUL.SetUpper( static_cast< sal_uInt16 >(nSpace) );
2493  else
2494  aUL.SetLower( static_cast< sal_uInt16 >(nSpace) );
2495 
2496  const sal_Int32 nEnd = pSpacingPos->nContent.GetIndex();
2497  rMyPam.GetPoint()->nContent.Assign(rMyPam.GetContentNode(), 0);
2498  m_xCtrlStck->NewAttr(*pSpacingPos, aUL);
2499  rMyPam.GetPoint()->nContent.Assign(rMyPam.GetContentNode(), nEnd);
2500  m_xCtrlStck->SetAttr(*pSpacingPos, RES_UL_SPACE);
2501  bRet = true;
2502  }
2503  return bRet;
2504 }
2505 
2506 bool SwWW8ImplReader::SetLowerSpacing(SwPaM &rMyPam, int nSpace)
2507 {
2508  return SetSpacing(rMyPam, nSpace, false);
2509 }
2510 
2511 bool SwWW8ImplReader::SetUpperSpacing(SwPaM &rMyPam, int nSpace)
2512 {
2513  return SetSpacing(rMyPam, nSpace, true);
2514 }
2515 
2516 sal_uInt16 SwWW8ImplReader::TabRowSprm(int nLevel) const
2517 {
2518  if (m_bVer67)
2519  return NS_sprm::v6::sprmPTtp;
2521 }
2522 
2524 {
2525  // Frame/Table/Anl
2526  if (m_bAnl)
2527  StopAllAnl(); // -> bAnl = false
2528 
2529  while(m_aApos.size() > 1)
2530  {
2531  StopTable();
2532  m_aApos.pop_back();
2533  --m_nInTable;
2534  if (m_aApos[m_nInTable])
2535  StopApo();
2536  }
2537 
2538  if (m_aApos[0])
2539  StopApo();
2540 
2541  OSL_ENSURE(!m_nInTable, "unclosed table!");
2542 }
2543 
2545 {
2546  // This is ww8 version of the code deciding if the table needs to be
2547  // in a floating frame.
2548  // For OOXML code, see SectionPropertyMap::FloatingTableConversion in
2549  // writerfilter/source/dmapper/PropertyMap.cxx
2550  // The two should do ~same, so if you make changes here, please check
2551  // that the other is in sync.
2552 
2553  // Note that this is just a list of heuristics till sw core can have a
2554  // table that is floating and can span over multiple pages at the same
2555  // time.
2556 
2557  // If the floating table is in a header or footer, then it won't be a
2558  // multi-page one, so can always do the conversion.
2559  if (m_bIsHeader || m_bIsFooter)
2560  {
2561  return true;
2562  }
2563 
2564  bool bResult = true;
2565 
2567  if (nullptr != aRes.pSprm)
2568  {
2569  bResult = false;
2570  WW8TabBandDesc aDesc;
2571  aDesc.ReadDef(false, aRes.pSprm, aRes.nRemainingData);
2572  int nTextAreaWidth = m_aSectionManager.GetTextAreaWidth();
2573  int nTableWidth = aDesc.nCenter[aDesc.nWwCols] - aDesc.nCenter[0];
2574 
2575  // It seems Word has a limit here, so that in case the table width is quite
2576  // close to the text area width, then it won't perform a wrapping, even in
2577  // case the content (e.g. an empty paragraph) would fit. The magic constant
2578  // here represents this limit.
2579  const int nMagicNumber = 469;
2580 
2581  // If the table is wider than the text area, then don't create a fly
2582  // for the table: no wrapping will be performed anyway, but multi-page
2583  // tables will be broken.
2584  if ((nTableWidth + nMagicNumber) < nTextAreaWidth)
2585  bResult = true;
2586 
2587  // If there are columns, do create a fly, as the flow of the columns
2588  // would otherwise restrict the table.
2589  if (!bResult && (m_aSectionManager.CurrentSectionColCount() >= 2))
2590  bResult = true;
2591  }
2592 
2593  if (bResult)
2594  {
2595  WW8PLCFxSave1 aSave;
2596  pPap->Save(aSave);
2597  if (SearchTableEnd(pPap))
2598  {
2599  // Table is considered to be imported into a fly frame and we
2600  // know where the end of the table is.
2601  bool bIsUnicode;
2602  WW8_FC nFc = m_xSBase->WW8Cp2Fc(pPap->Where(), &bIsUnicode);
2603  sal_uInt64 nPos = m_pStrm->Tell();
2604  m_pStrm->Seek(nFc);
2605  sal_uInt16 nUChar = 0;
2606  if (bIsUnicode)
2607  m_pStrm->ReadUInt16(nUChar);
2608  else
2609  {
2610  sal_uInt8 nChar = 0;
2611  m_pStrm->ReadUChar(nChar);
2612  nUChar = nChar;
2613  }
2614  m_pStrm->Seek(nPos);
2615  if (nUChar == 0xc)
2616  // The pap after the table starts with a page break, so
2617  // there will be no wrapping around the float-table.
2618  // Request no fly in this case, so the table can properly
2619  // be a multi-page one if necessary.
2620  bResult = false;
2621  }
2622  pPap->Restore(aSave);
2623  }
2624 
2625  return bResult;
2626 }
2627 
2628 bool SwWW8ImplReader::ProcessSpecial(bool &rbReSync, WW8_CP nStartCp)
2629 {
2630  // Frame/Table/Anl
2631  if (m_bInHyperlink)
2632  return false;
2633 
2634  rbReSync = false;
2635 
2636  OSL_ENSURE(m_nInTable >= 0,"nInTable < 0!");
2637 
2638  // TabRowEnd
2639  bool bTableRowEnd = (m_xPlcxMan->HasParaSprm(m_bVer67 ? 25 : 0x2417).pSprm != nullptr);
2640 
2641 // Unfortunately, for every paragraph we need to check first whether
2642 // they contain a sprm 29 (0x261B), which starts an APO.
2643 // All other sprms then refer to that APO and not to the normal text
2644 // surrounding it.
2645 // The same holds true for a Table (sprm 24 (0x2416)) and Anls (sprm 13).
2646 
2647 // WW: Table in APO is possible (Both Start-Ends occur at the same time)
2648 // WW: APO in Table not possible
2649 
2650 // This mean that of a Table is the content of an APO, the APO start needs
2651 // to be edited first, so that the Table remains in the APO and not the
2652 // other way around.
2653 // At the End, however, we need to edit the Table End first as the APO
2654 // must end after that Table (or else we never find the APO End).
2655 
2656 // The same holds true for Fly / Anl, Tab / Anl, Fly / Tab / Anl.
2657 
2658 // If the Table is within an APO the TabRowEnd Area misses the
2659 // APO settings.
2660 // To not end the APO there, we do not call ProcessApo
2661 
2662 // KHZ: When there is a table inside the Apo the Apo-flags are also
2663 // missing for the 2nd, 3rd... paragraphs of each cell.
2664 
2665 // 1st look for in-table flag, for 2000+ there is a subtable flag to
2666 // be considered, the sprm 6649 gives the level of the table
2667  sal_uInt8 nCellLevel = 0;
2668 
2669  if (m_bVer67)
2670  nCellLevel = int(nullptr != m_xPlcxMan->HasParaSprm(24).pSprm);
2671  else
2672  {
2673  nCellLevel = int(nullptr != m_xPlcxMan->HasParaSprm(0x2416).pSprm);
2674  if (!nCellLevel)
2675  nCellLevel = int(nullptr != m_xPlcxMan->HasParaSprm(0x244B).pSprm);
2676  }
2677  do
2678  {
2679  WW8_TablePos *pTabPos=nullptr;
2680  WW8_TablePos aTabPos;
2681  if(nCellLevel && !m_bVer67)
2682  {
2683  WW8PLCFxSave1 aSave;
2684  m_xPlcxMan->GetPap()->Save( aSave );
2685  rbReSync = true;
2686  WW8PLCFx_Cp_FKP* pPap = m_xPlcxMan->GetPapPLCF();
2687  WW8_CP nMyStartCp=nStartCp;
2688 
2689  SprmResult aLevel = m_xPlcxMan->HasParaSprm(0x6649);
2690  if (aLevel.pSprm && aLevel.nRemainingData >= 1)
2691  nCellLevel = *aLevel.pSprm;
2692 
2693  bool bHasRowEnd = SearchRowEnd(pPap, nMyStartCp, (m_nInTable<nCellLevel?m_nInTable:nCellLevel-1));
2694 
2695  // Bad Table, remain unchanged in level, e.g. #i19667#
2696  if (!bHasRowEnd)
2697  nCellLevel = static_cast< sal_uInt8 >(m_nInTable);
2698 
2699  if (bHasRowEnd && ParseTabPos(&aTabPos,pPap))
2700  pTabPos = &aTabPos;
2701 
2702  m_xPlcxMan->GetPap()->Restore( aSave );
2703  }
2704 
2705  // Then look if we are in an Apo
2706 
2707  ApoTestResults aApo = TestApo(nCellLevel, bTableRowEnd, pTabPos);
2708 
2709  // Look to see if we are in a Table, but Table in foot/end note not allowed
2710  bool bStartTab = (m_nInTable < nCellLevel) && !m_bFootnoteEdn;
2711 
2712  bool bStopTab = m_bWasTabRowEnd && (m_nInTable > nCellLevel) && !m_bFootnoteEdn;
2713 
2714  m_bWasTabRowEnd = false; // must be deactivated right here to prevent next
2715  // WW8TabDesc::TableCellEnd() from making nonsense
2716 
2717  if (m_nInTable && !bTableRowEnd && !bStopTab && (m_nInTable == nCellLevel && aApo.HasStartStop()))
2718  bStopTab = bStartTab = true; // Required to stop and start table
2719 
2720  // Test for Anl (Numbering) and process all events in the right order
2721  if( m_bAnl && !bTableRowEnd )
2722  {
2723  SprmResult aSprm13 = m_xPlcxMan->HasParaSprm(13);
2724  const sal_uInt8* pSprm13 = aSprm13.pSprm;
2725  if (pSprm13 && aSprm13.nRemainingData >= 1)
2726  { // Still Anl left?
2727  sal_uInt8 nT = static_cast< sal_uInt8 >(GetNumType( *pSprm13 ));
2728  if( ( nT != WW8_Pause && nT != m_nWwNumType ) // Anl change
2729  || aApo.HasStartStop() // Forced Anl end
2730  || bStopTab || bStartTab )
2731  {
2732  StopAnlToRestart(nT); // Anl-Restart (= change) over sprms
2733  }
2734  else
2735  {
2736  NextAnlLine( pSprm13 ); // Next Anl Line
2737  }
2738  }
2739  else
2740  { // Regular Anl end
2741  StopAllAnl(); // Actual end
2742  }
2743  }
2744  if (bStopTab)
2745  {
2746  StopTable();
2747  m_aApos.pop_back();
2748  --m_nInTable;
2749  }
2750  if (aApo.mbStopApo)
2751  {
2752  StopApo();
2753  m_aApos[m_nInTable] = false;
2754  }
2755 
2756  if (aApo.mbStartApo)
2757  {
2758  m_aApos[m_nInTable] = StartApo(aApo, pTabPos);
2759  // We need an ReSync after StartApo
2760  // (actually only if the Apo extends past a FKP border)
2761  rbReSync = true;
2762  }
2763  if (bStartTab)
2764  {
2765  WW8PLCFxSave1 aSave;
2766  m_xPlcxMan->GetPap()->Save( aSave );
2767 
2768  // Numbering for cell borders causes a crash -> no Anls in Tables
2769  if (m_bAnl)
2770  StopAllAnl();
2771 
2772  if(m_nInTable < nCellLevel)
2773  {
2774  if (StartTable(nStartCp))
2775  ++m_nInTable;
2776  else
2777  break;
2778  m_aApos.push_back(false);
2779  }
2780 
2781  if(m_nInTable >= nCellLevel)
2782  {
2783  // We need an ReSync after StartTable
2784  // (actually only if the Apo extends past a FKP border)
2785  rbReSync = true;
2786  m_xPlcxMan->GetPap()->Restore( aSave );
2787  }
2788  }
2789  } while (!m_bFootnoteEdn && (m_nInTable < nCellLevel));
2790  return bTableRowEnd;
2791 }
2792 
2794 {
2795  /*
2796  #i22206#/#i52786#
2797  The (default) character set used for a run of text is the default
2798  character set for the version of Word that last saved the document.
2799 
2800  This is a bit tentative, more might be required if the concept is correct.
2801  When later version of word write older 6/95 documents the charset is
2802  correctly set in the character runs involved, so it's hard to reproduce
2803  documents that require this to be sure of the process involved.
2804  */
2805  const SvxLanguageItem *pLang = static_cast<const SvxLanguageItem*>(GetFormatAttr(RES_CHRATR_LANGUAGE));
2806  LanguageType eLang = pLang ? pLang->GetLanguage() : LANGUAGE_SYSTEM;
2807  css::lang::Locale aLocale(LanguageTag::convertToLocale(eLang));
2809 }
2810 
2812 {
2813  /*
2814  #i22206#/#i52786#
2815  The (default) character set used for a run of text is the default
2816  character set for the version of Word that last saved the document.
2817 
2818  This is a bit tentative, more might be required if the concept is correct.
2819  When later version of word write older 6/95 documents the charset is
2820  correctly set in the character runs involved, so it's hard to reproduce
2821  documents that require this to be sure of the process involved.
2822  */
2823  const SvxLanguageItem *pLang = static_cast<const SvxLanguageItem*>(GetFormatAttr(RES_CHRATR_CJK_LANGUAGE));
2824  LanguageType eLang = pLang ? pLang->GetLanguage() : LANGUAGE_SYSTEM;
2825  css::lang::Locale aLocale(LanguageTag::convertToLocale(eLang));
2827 }
2828 
2830 {
2831  /*
2832  #i2015
2833  If the hard charset is set use it, if not see if there is an open
2834  character run that has set the charset, if not then fallback to the
2835  current underlying paragraph style.
2836  */
2837  rtl_TextEncoding eSrcCharSet = m_eHardCharSet;
2838  if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2839  {
2840  if (!m_bVer67)
2841  eSrcCharSet = GetCharSetFromLanguage();
2842  else if (!m_aFontSrcCharSets.empty())
2843  eSrcCharSet = m_aFontSrcCharSets.top();
2844  if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && m_nCharFormat >= 0 && o3tl::make_unsigned(m_nCharFormat) < m_vColl.size() )
2845  eSrcCharSet = m_vColl[m_nCharFormat].GetCharSet();
2846  if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && StyleExists(m_nCurrentColl) && m_nCurrentColl < m_vColl.size())
2847  eSrcCharSet = m_vColl[m_nCurrentColl].GetCharSet();
2848  if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2849  eSrcCharSet = GetCharSetFromLanguage();
2850  }
2851  return eSrcCharSet;
2852 }
2853 
2854 //Takashi Ono for CJK
2856 {
2857  /*
2858  #i2015
2859  If the hard charset is set use it, if not see if there is an open
2860  character run that has set the charset, if not then fallback to the
2861  current underlying paragraph style.
2862  */
2863  rtl_TextEncoding eSrcCharSet = m_eHardCharSet;
2864  if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2865  {
2866  if (!m_aFontSrcCJKCharSets.empty())
2867  eSrcCharSet = m_aFontSrcCJKCharSets.top();
2868  if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && m_nCharFormat >= 0 && o3tl::make_unsigned(m_nCharFormat) < m_vColl.size() )
2869  eSrcCharSet = m_vColl[m_nCharFormat].GetCJKCharSet();
2870  if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW && StyleExists(m_nCurrentColl) && m_nCurrentColl < m_vColl.size())
2871  eSrcCharSet = m_vColl[m_nCurrentColl].GetCJKCharSet();
2872  if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2873  eSrcCharSet = GetCJKCharSetFromLanguage();
2874  }
2875  return eSrcCharSet;
2876 }
2877 
2879 {
2880  if (m_pPostProcessAttrsInfo == nullptr)
2881  return;
2882 
2883  SfxItemIter aIter(m_pPostProcessAttrsInfo->mItemSet);
2884 
2885  for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
2886  {
2887  m_xCtrlStck->NewAttr(*m_pPostProcessAttrsInfo->mPaM.GetPoint(),
2888  *pItem);
2889  m_xCtrlStck->SetAttr(*m_pPostProcessAttrsInfo->mPaM.GetMark(),
2890  pItem->Which());
2891  }
2892 
2893  m_pPostProcessAttrsInfo.reset();
2894 }
2895 
2896 /*
2897  #i9240#
2898  It appears that some documents that are in a baltic 8 bit encoding which has
2899  some undefined characters can have use made of those characters, in which
2900  case they default to CP1252. If not then it's perhaps that the font encoding
2901  is only in use for 6/7 and for 8+ if we are in 8bit mode then the encoding
2902  is always 1252.
2903 
2904  So an encoding converter that on an undefined character attempts to
2905  convert from 1252 on the undefined character
2906 */
2907 static std::size_t Custom8BitToUnicode(rtl_TextToUnicodeConverter hConverter,
2908  char const *pIn, std::size_t nInLen, sal_Unicode *pOut, std::size_t nOutLen)
2909 {
2910  const sal_uInt32 nFlags =
2911  RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
2912  RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
2913  RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE |
2914  RTL_TEXTTOUNICODE_FLAGS_FLUSH;
2915 
2916  const sal_uInt32 nFlags2 =
2917  RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE |
2918  RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_IGNORE |
2919  RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE |
2920  RTL_TEXTTOUNICODE_FLAGS_FLUSH;
2921 
2922  std::size_t nDestChars=0;
2923  std::size_t nConverted=0;
2924 
2925  do
2926  {
2927  sal_uInt32 nInfo = 0;
2928  sal_Size nThisConverted=0;
2929 
2930  nDestChars += rtl_convertTextToUnicode(hConverter, nullptr,
2931  pIn+nConverted, nInLen-nConverted,
2932  pOut+nDestChars, nOutLen-nDestChars,
2933  nFlags, &nInfo, &nThisConverted);
2934 
2935  OSL_ENSURE(nInfo == 0, "A character conversion failed!");
2936 
2937  nConverted += nThisConverted;
2938 
2939  if (
2940  nInfo & RTL_TEXTTOUNICODE_INFO_UNDEFINED ||
2941  nInfo & RTL_TEXTTOUNICODE_INFO_MBUNDEFINED
2942  )
2943  {
2944  sal_Size nOtherConverted;
2945  rtl_TextToUnicodeConverter hCP1252Converter =
2946  rtl_createTextToUnicodeConverter(RTL_TEXTENCODING_MS_1252);
2947  nDestChars += rtl_convertTextToUnicode(hCP1252Converter, nullptr,
2948  pIn+nConverted, 1,
2949  pOut+nDestChars, nOutLen-nDestChars,
2950  nFlags2, &nInfo, &nOtherConverted);
2951  rtl_destroyTextToUnicodeConverter(hCP1252Converter);
2952  nConverted+=1;
2953  }
2954  } while (nConverted < nInLen);
2955 
2956  return nDestChars;
2957 }
2958 
2960 {
2961  bool bResult = false;
2962 
2963  switch (static_cast<sal_uInt16>(nLang))
2964  {
2965  case 0x1401: // Arabic(Algeria)
2966  case 0x3c01: // Arabic(Bahrain)
2967  case 0xc01: // Arabic(Egypt)
2968  case 0x801: // Arabic(Iraq)
2969  case 0x2c01: // Arabic (Jordan)
2970  case 0x3401: // Arabic(Kuwait)
2971  case 0x3001: // Arabic(Lebanon)
2972  case 0x1001: // Arabic(Libya)
2973  case 0x1801: // Arabic(Morocco)
2974  case 0x2001: // Arabic(Oman)
2975  case 0x4001: // Arabic(Qatar)
2976  case 0x401: // Arabic(Saudi Arabia)
2977  case 0x2801: // Arabic(Syria)
2978  case 0x1c01: // Arabic(Tunisia)
2979  case 0x3801: // Arabic(U.A.E)
2980  case 0x2401: // Arabic(Yemen)
2981  bResult = true;
2982  break;
2983  default:
2984  break;
2985  }
2986 
2987  return bResult;
2988 }
2989 
2991 {
2992  if (nChar >= 0x0030 && nChar <= 0x0039)
2993  return nChar + 0x0630;
2994 
2995  return nChar;
2996 }
2997 
2998 namespace
2999 {
3000  OUString makeOUString(rtl_uString *pStr, sal_Int32 nAllocLen)
3001  {
3002  //if read len was in or around that of allocated len, just reuse pStr
3003  if (nAllocLen < pStr->length + 256)
3004  return OUString(pStr, SAL_NO_ACQUIRE);
3005  //otherwise copy the shorter used section to release extra mem
3006  OUString sRet(pStr->buffer, pStr->length);
3007  rtl_uString_release(pStr);
3008  return sRet;
3009  }
3010 }
3011 
3015 bool SwWW8ImplReader::ReadPlainChars(WW8_CP& rPos, sal_Int32 nEnd, sal_Int32 nCpOfs)
3016 {
3017  sal_Int32 nRequestedStrLen = nEnd - rPos;
3018 
3019  OSL_ENSURE(nRequestedStrLen, "String is 0");
3020  if (nRequestedStrLen <= 0)
3021  return true;
3022 
3023  sal_Int32 nRequestedPos = m_xSBase->WW8Cp2Fc(nCpOfs+rPos, &m_bIsUnicode);
3024  bool bValidPos = checkSeek(*m_pStrm, nRequestedPos);
3025  OSL_ENSURE(bValidPos, "Document claimed to have more text than available");
3026  if (!bValidPos)
3027  {
3028  // Swallow missing range, e.g. #i95550#
3029  rPos+=nRequestedStrLen;
3030  return true;
3031  }
3032 
3033  std::size_t nAvailableStrLen = m_pStrm->remainingSize() / (m_bIsUnicode ? 2 : 1);
3034  OSL_ENSURE(nAvailableStrLen, "Document claimed to have more text than available");
3035  if (!nAvailableStrLen)
3036  {
3037  // Swallow missing range, e.g. #i95550#
3038  rPos+=nRequestedStrLen;
3039  return true;
3040  }
3041 
3042  sal_Int32 nValidStrLen = std::min<std::size_t>(nRequestedStrLen, nAvailableStrLen);
3043 
3044  // Reset Unicode flag and correct FilePos if needed.
3045  // Note: Seek is not expensive, as we're checking inline whether or not
3046  // the correct FilePos has already been reached.
3047  const sal_Int32 nStrLen = std::min(nValidStrLen, SAL_MAX_INT32-1);
3048 
3049  rtl_TextEncoding eSrcCharSet = m_bVer67 ? GetCurrentCharSet() :
3050  RTL_TEXTENCODING_MS_1252;
3051  if (m_bVer67 && eSrcCharSet == RTL_TEXTENCODING_MS_932)
3052  {
3053  /*
3054  fdo#82904
3055 
3056  Older documents exported as word 95 that use unicode aware fonts will
3057  have the charset of those fonts set to RTL_TEXTENCODING_MS_932 on
3058  export as the conversion from RTL_TEXTENCODING_UNICODE. This is a serious
3059  pain.
3060 
3061  We will try and use a fallback encoding if the conversion from
3062  RTL_TEXTENCODING_MS_932 fails, but you can get unlucky and get a document
3063  which isn't really in RTL_TEXTENCODING_MS_932 but parts of it form
3064  valid RTL_TEXTENCODING_MS_932 by chance :-(
3065 
3066  We're not the only ones that struggle with this: Here's the help from
3067  MSOffice 2003 on the topic:
3068 
3069  <<
3070  Earlier versions of Microsoft Word were sometimes used in conjunction with
3071  third-party language-processing add-in programs designed to support Chinese or
3072  Korean on English versions of Microsoft Windows. Use of these add-ins sometimes
3073  results in incorrect text display in more recent versions of Word.
3074 
3075  However, you can set options to convert these documents so that text is
3076  displayed correctly. On the Tools menu, click Options, and then click the
3077  General tab. In the English Word 6.0/95 documents list, select Contain Asian
3078  text (to have Word interpret the text as Asian code page data, regardless of
3079  its font) or Automatically detect Asian text (to have Word attempt to determine
3080  which parts of the text are meant to be Asian).
3081  >>
3082 
3083  What we can try here is to ignore a RTL_TEXTENCODING_MS_932 codepage if
3084  the language is not Japanese
3085  */
3086 
3088  if (pItem != nullptr && LANGUAGE_JAPANESE != static_cast<const SvxLanguageItem *>(pItem)->GetLanguage())
3089  {
3090  SAL_WARN("sw.ww8", "discarding word95 RTL_TEXTENCODING_MS_932 encoding");
3091  eSrcCharSet = GetCharSetFromLanguage();
3092  }
3093  }
3094  const rtl_TextEncoding eSrcCJKCharSet = m_bVer67 ? GetCurrentCJKCharSet() :
3095  RTL_TEXTENCODING_MS_1252;
3096 
3097  // allocate unicode string data
3098  auto l = [](rtl_uString* p){rtl_uString_release(p);};
3099  std::unique_ptr<rtl_uString, decltype(l)> xStr(rtl_uString_alloc(nStrLen), l);
3100  sal_Unicode* pBuffer = xStr->buffer;
3101  sal_Unicode* pWork = pBuffer;
3102 
3103  std::unique_ptr<char[]> p8Bits;
3104 
3105  rtl_TextToUnicodeConverter hConverter = nullptr;
3106  if (!m_bIsUnicode || m_bVer67)
3107  hConverter = rtl_createTextToUnicodeConverter(eSrcCharSet);
3108 
3109  if (!m_bIsUnicode)
3110  p8Bits.reset( new char[nStrLen] );
3111 
3112  // read the stream data
3113  sal_uInt8 nBCode = 0;
3114  sal_uInt16 nUCode;
3115 
3116  LanguageType nCTLLang = LANGUAGE_SYSTEM;
3118  if (pItem != nullptr)
3119  nCTLLang = static_cast<const SvxLanguageItem *>(pItem)->GetLanguage();
3120 
3121  sal_Int32 nL2;
3122  for (nL2 = 0; nL2 < nStrLen; ++nL2)
3123  {
3124  if (m_bIsUnicode)
3125  m_pStrm->ReadUInt16( nUCode ); // unicode --> read 2 bytes
3126  else
3127  {
3128  m_pStrm->ReadUChar( nBCode ); // old code --> read 1 byte
3129  nUCode = nBCode;
3130  }
3131 
3132  if (!m_pStrm->good())
3133  {
3134  rPos = WW8_CP_MAX-10; // -> eof or other error
3135  return true;
3136  }
3137 
3138  if ((32 > nUCode) || (0xa0 == nUCode))
3139  {
3140  m_pStrm->SeekRel( m_bIsUnicode ? -2 : -1 );
3141  break; // Special character < 32, == 0xa0 found
3142  }
3143 
3144  if (m_bIsUnicode)
3145  {
3146  if (!m_bVer67)
3147  *pWork++ = nUCode;
3148  else
3149  {
3150  if (nUCode >= 0x3000) //0x8000 ?
3151  {
3152  char aTest[2];
3153  aTest[0] = static_cast< char >((nUCode & 0xFF00) >> 8);
3154  aTest[1] = static_cast< char >(nUCode & 0x00FF);
3155  OUString aTemp(aTest, 2, eSrcCJKCharSet);
3156  OSL_ENSURE(aTemp.getLength() == 1, "so much for that theory");
3157  *pWork++ = aTemp[0];
3158  }
3159  else
3160  {
3161  char cTest = static_cast< char >(nUCode & 0x00FF);
3162  pWork += Custom8BitToUnicode(hConverter, &cTest, 1, pWork, 1);
3163  }
3164  }
3165  }
3166  else
3167  p8Bits[nL2] = nBCode;
3168  }
3169 
3170  if (nL2)
3171  {
3172  const sal_Int32 nEndUsed = !m_bIsUnicode
3173  ? Custom8BitToUnicode(hConverter, p8Bits.get(), nL2, pBuffer, nStrLen)
3174  : pWork - pBuffer;
3175 
3177  {
3178  for (sal_Int32 nI = 0; nI < nEndUsed; ++nI, ++pBuffer)
3179  *pBuffer = TranslateToHindiNumbers(*pBuffer);
3180  }
3181 
3182  xStr->buffer[nEndUsed] = 0;
3183  xStr->length = nEndUsed;
3184 
3185  emulateMSWordAddTextToParagraph(makeOUString(xStr.release(), nStrLen));
3186  rPos += nL2;
3187  if (!m_aApos.back()) // a para end in apo doesn't count
3188  m_bWasParaEnd = false; // No CR
3189  }
3190 
3191  if (hConverter)
3192  rtl_destroyTextToUnicodeConverter(hConverter);
3193  return nL2 >= nStrLen;
3194 }
3195 
3196 #define MSASCII SAL_MAX_INT16
3197 
3198 namespace
3199 {
3200  // We want to force weak chars inside 0x0020 to 0x007F to LATIN
3201  sal_Int16 lcl_getScriptType(
3202  const uno::Reference<i18n::XBreakIterator>& rBI,
3203  const OUString &rString, sal_Int32 nPos)
3204  {
3205  sal_Int16 nScript = rBI->getScriptType(rString, nPos);
3206  if (nScript == i18n::ScriptType::WEAK && rString[nPos] >= 0x0020 && rString[nPos] <= 0x007F)
3207  nScript = MSASCII;
3208  return nScript;
3209  }
3210 
3211  // We want to know about WEAK segments, so endOfScript isn't
3212  // useful, and see lcl_getScriptType anyway
3213  sal_Int32 lcl_endOfScript(
3214  const uno::Reference<i18n::XBreakIterator>& rBI,
3215  const OUString &rString, sal_Int32 nPos, sal_Int16 nScript)
3216  {
3217  while (nPos < rString.getLength())
3218  {
3219  sal_Int16 nNewScript = lcl_getScriptType(rBI, rString, nPos);
3220  if (nScript != nNewScript)
3221  break;
3222  ++nPos;
3223  }
3224  return nPos;
3225  }
3226 
3227  sal_Int32 lcl_getWriterScriptType(
3228  const uno::Reference<i18n::XBreakIterator>& rBI,
3229  const OUString &rString, sal_Int32 nPos)
3230  {
3231  sal_Int16 nScript = i18n::ScriptType::WEAK;
3232 
3233  if (rString.isEmpty())
3234  return nScript;
3235 
3236  while (nPos >= 0)
3237  {
3238  nScript = rBI->getScriptType(rString, nPos);
3239  if (nScript != i18n::ScriptType::WEAK)
3240  break;
3241  --nPos;
3242  }
3243 
3244  return nScript;
3245  }
3246 
3247  bool samePitchIgnoreUnknown(FontPitch eA, FontPitch eB)
3248  {
3249  return (eA == eB || eA == PITCH_DONTKNOW || eB == PITCH_DONTKNOW);
3250  }
3251 
3252  bool sameFontIgnoringIrrelevantFields(const SvxFontItem &rA, const SvxFontItem &rB)
3253  {
3254  // Ignoring CharSet, and ignoring unknown pitch
3255  return rA.GetFamilyName() == rB.GetFamilyName() &&
3256  rA.GetStyleName() == rB.GetStyleName() &&
3257  rA.GetFamily() == rB.GetFamily() &&
3258  samePitchIgnoreUnknown(rA.GetPitch(), rB.GetPitch());
3259  }
3260 }
3261 
3262 // In writer we categorize text into CJK, CTL and "Western" for everything else.
3263 // Microsoft Word basically categorizes text into East Asian, Complex, ASCII,
3264 // NonEastAsian/HighAnsi, with some shared characters and some properties to
3265 // hint as to which way to bias those shared characters.
3266 
3267 // That's four categories, we however have three categories. Given that problem
3268 // here we would ideally find out "what would word do" to see what font/language
3269 // word would assign to characters based on the unicode range they fall into and
3270 // hack the word one onto the range we use. However it's unclear what word's
3271 // categorization is. So we don't do that here yet.
3272 
3273 // Additional to the categorization, when word encounters weak text for ambiguous
3274 // chars it uses idcthint to indicate which way to bias. We don't have an idcthint
3275 // feature in writer.
3276 
3277 // So what we currently do here then is to split our text into non-weak/weak
3278 // sections and uses word's idcthint to determine what font it would use and
3279 // force that on for the segment. Following what we *do* know about word's
3280 // categorization, we know that the range 0x0020 and 0x007F is sprmCRgFtc0 in
3281 // word, something we map to LATIN, so we consider all weak chars in that range
3282 // to auto-bias to LATIN.
3283 
3284 // See https://bugs.libreoffice.org/show_bug.cgi?id=34319 for an example
3286 {
3287  if (rAddString.isEmpty())
3288  return;
3289 
3290  if (m_bFuzzing)
3291  {
3292  simpleAddTextToParagraph(rAddString);
3293  return;
3294  }
3295 
3296  uno::Reference<i18n::XBreakIterator> xBI(g_pBreakIt->GetBreakIter());
3297  assert(xBI.is());
3298 
3299  sal_Int16 nScript = lcl_getScriptType(xBI, rAddString, 0);
3300  sal_Int32 nLen = rAddString.getLength();
3301 
3302  OUString sParagraphText;
3303  const SwContentNode *pCntNd = m_pPaM->GetContentNode();
3304  const SwTextNode* pNd = pCntNd ? pCntNd->GetTextNode() : nullptr;
3305  if (pNd)
3306  sParagraphText = pNd->GetText();
3307  sal_Int32 nParaOffset = sParagraphText.getLength();
3308  sParagraphText = sParagraphText + rAddString;
3309 
3310  sal_Int32 nPos = 0;
3311  while (nPos < nLen)
3312  {
3313  sal_Int32 nEnd = lcl_endOfScript(xBI, rAddString, nPos, nScript);
3314  if (nEnd < 0)
3315  break;
3316 
3317  OUString sChunk(rAddString.copy(nPos, nEnd-nPos));
3318  const sal_uInt16 aIds[] = {RES_CHRATR_FONT, RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_FONT};
3319  const SvxFontItem *pOverriddenItems[] = {nullptr, nullptr, nullptr};
3320  bool aForced[] = {false, false, false};
3321 
3322  int nLclIdctHint = 0xFF;
3323  if (nScript == i18n::ScriptType::WEAK)
3324  {
3325  const SfxInt16Item *pIdctHint = static_cast<const SfxInt16Item*>(GetFormatAttr(RES_CHRATR_IDCTHINT));
3326  nLclIdctHint = pIdctHint->GetValue();
3327  }
3328  else if (nScript == MSASCII) // Force weak chars in ascii range to use LATIN font
3329  nLclIdctHint = 0;
3330 
3331  sal_uInt16 nForceFromFontId = 0;
3332  if (nLclIdctHint != 0xFF)
3333  {
3334  switch (nLclIdctHint)
3335  {
3336  case 0:
3337  nForceFromFontId = RES_CHRATR_FONT;
3338  break;
3339  case 1:
3340  nForceFromFontId = RES_CHRATR_CJK_FONT;
3341  break;
3342  case 2:
3343  nForceFromFontId = RES_CHRATR_CTL_FONT;
3344  break;
3345  default:
3346  break;
3347  }
3348  }
3349 
3350  if (nForceFromFontId != 0)
3351  {
3352  // Now we know that word would use the nForceFromFontId font for this range
3353  // Try and determine what script writer would assign this range to
3354 
3355  sal_Int32 nWriterScript = lcl_getWriterScriptType(xBI, sParagraphText,
3356  nPos + nParaOffset);
3357 
3358  bool bWriterWillUseSameFontAsWordAutomatically = false;
3359 
3360  if (nWriterScript != i18n::ScriptType::WEAK)
3361  {
3362  if (
3363  (nWriterScript == i18n::ScriptType::ASIAN && nForceFromFontId == RES_CHRATR_CJK_FONT) ||
3364  (nWriterScript == i18n::ScriptType::COMPLEX && nForceFromFontId == RES_CHRATR_CTL_FONT) ||
3365  (nWriterScript == i18n::ScriptType::LATIN && nForceFromFontId == RES_CHRATR_FONT)
3366  )
3367  {
3368  bWriterWillUseSameFontAsWordAutomatically = true;
3369  }
3370  else
3371  {
3372  const SvxFontItem *pSourceFont = static_cast<const SvxFontItem*>(GetFormatAttr(nForceFromFontId));
3373  sal_uInt16 nDestId = aIds[nWriterScript-1];
3374  const SvxFontItem *pDestFont = static_cast<const SvxFontItem*>(GetFormatAttr(nDestId));
3375  bWriterWillUseSameFontAsWordAutomatically = sameFontIgnoringIrrelevantFields(*pSourceFont, *pDestFont);
3376  }
3377  }
3378 
3379  // Writer won't use the same font as word, so force the issue
3380  if (!bWriterWillUseSameFontAsWordAutomatically)
3381  {
3382  const SvxFontItem *pSourceFont = static_cast<const SvxFontItem*>(GetFormatAttr(nForceFromFontId));
3383 
3384  for (size_t i = 0; i < SAL_N_ELEMENTS(aIds); ++i)
3385  {
3386  const SvxFontItem *pDestFont = static_cast<const SvxFontItem*>(GetFormatAttr(aIds[i]));
3387  aForced[i] = aIds[i] != nForceFromFontId && *pSourceFont != *pDestFont;
3388  if (aForced[i])
3389  {
3390  pOverriddenItems[i] =
3391  static_cast<const SvxFontItem*>(m_xCtrlStck->GetStackAttr(*m_pPaM->GetPoint(), aIds[i]));
3392 
3393  SvxFontItem aForceFont(*pSourceFont);
3394  aForceFont.SetWhich(aIds[i]);
3395  m_xCtrlStck->NewAttr(*m_pPaM->GetPoint(), aForceFont);
3396  }
3397  }
3398  }
3399  }
3400 
3401  simpleAddTextToParagraph(sChunk);
3402 
3403  for (size_t i = 0; i < SAL_N_ELEMENTS(aIds); ++i)
3404  {
3405  if (aForced[i])
3406  {
3407  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), aIds[i]);
3408  if (pOverriddenItems[i])
3409  m_xCtrlStck->NewAttr(*m_pPaM->GetPoint(), *(pOverriddenItems[i]));
3410  }
3411  }
3412 
3413  nPos = nEnd;
3414  if (nPos < nLen)
3415  nScript = lcl_getScriptType(xBI, rAddString, nPos);
3416  }
3417 }
3418 
3419 namespace sw {
3420 
3421 auto FilterControlChars(OUString const& rString) -> OUString
3422 {
3423  OUStringBuffer buf(rString.getLength());
3424  for (sal_Int32 i = 0; i < rString.getLength(); ++i)
3425  {
3426  sal_Unicode const ch(rString[i]);
3427  if (!linguistic::IsControlChar(ch) || ch == '\r' || ch == '\n' || ch == '\t')
3428  {
3429  buf.append(ch);
3430  }
3431  else
3432  {
3433  SAL_INFO("sw.ww8", "filtering control character");
3434  }
3435  }
3436  return buf.makeStringAndClear();
3437 }
3438 
3439 } // namespace sw
3440 
3441 void SwWW8ImplReader::simpleAddTextToParagraph(const OUString& rAddString)
3442 {
3443  OUString const addString(sw::FilterControlChars(rAddString));
3444 
3445  if (addString.isEmpty())
3446  return;
3447 
3448  const SwContentNode *pCntNd = m_pPaM->GetContentNode();
3449  const SwTextNode* pNd = pCntNd ? pCntNd->GetTextNode() : nullptr;
3450 
3451  OSL_ENSURE(pNd, "What the hell, where's my text node");
3452 
3453  if (!pNd)
3454  return;
3455 
3456  const sal_Int32 nCharsLeft = SAL_MAX_INT32 - pNd->GetText().getLength();
3457  if (nCharsLeft > 0)
3458  {
3459  if (addString.getLength() <= nCharsLeft)
3460  {
3462  }
3463  else
3464  {
3465  m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, addString.copy(0, nCharsLeft));
3467  m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, addString.copy(nCharsLeft));
3468  }
3469  }
3470  else
3471  {
3474  }
3475 
3476  m_bReadTable = false;
3477 }
3478 
3482 bool SwWW8ImplReader::ReadChars(WW8_CP& rPos, WW8_CP nNextAttr, tools::Long nTextEnd,
3483  tools::Long nCpOfs)
3484 {
3485  tools::Long nEnd = ( nNextAttr < nTextEnd ) ? nNextAttr : nTextEnd;
3486 
3487  if (m_bSymbol || m_bIgnoreText)
3488  {
3489  WW8_CP nRequested = nEnd - rPos;
3490  if (m_bSymbol) // Insert special chars
3491  {
3492  sal_uInt64 nMaxPossible = m_pStrm->remainingSize();
3493  if (o3tl::make_unsigned(nRequested) > nMaxPossible)
3494  {
3495  SAL_WARN("sw.ww8", "document claims to have more characters, " << nRequested << " than remaining, " << nMaxPossible);
3496  nRequested = nMaxPossible;
3497  }
3498 
3500  || m_cSymbol == '\r' || m_cSymbol == '\n' || m_cSymbol == '\t')
3501  {
3502  for (WW8_CP nCh = 0; nCh < nRequested; ++nCh)
3503  {
3505  }
3506  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_CHRATR_FONT);
3509  }
3510  }
3511  m_pStrm->SeekRel(nRequested);
3512  rPos = nEnd; // Ignore until attribute end
3513  return false;
3514  }
3515 
3516  while (true)
3517  {
3518  if (ReadPlainChars(rPos, nEnd, nCpOfs))
3519  return false; // Done
3520 
3521  bool bStartLine = ReadChar(rPos, nCpOfs);
3522  rPos++;
3523  if (m_bPgSecBreak || bStartLine || rPos == nEnd) // CR or Done
3524  {
3525  return bStartLine;
3526  }
3527  }
3528 }
3529 
3531 {
3532  bool bParaEndAdded = false;
3533  // #i1909# section/page breaks should not occur in tables, word
3534  // itself ignores them in this case.
3535  if (!m_nInTable)
3536  {
3537  bool IsTemp=true;
3538  SwTextNode* pTemp = m_pPaM->GetNode().GetTextNode();
3539  if (pTemp && pTemp->GetText().isEmpty()
3541  {
3542  IsTemp = false;
3545  }
3546 
3547  m_bPgSecBreak = true;
3548  m_xCtrlStck->KillUnlockedAttrs(*m_pPaM->GetPoint());
3549  /*
3550  If it's a 0x0c without a paragraph end before it, act like a
3551  paragraph end, but nevertheless, numbering (and perhaps other
3552  similar constructs) do not exist on the para.
3553  */
3554  if (!m_bWasParaEnd && IsTemp)
3555  {
3556  bParaEndAdded = true;
3557  if (0 >= m_pPaM->GetPoint()->nContent.GetIndex())
3558  {
3559  if (SwTextNode* pTextNode = m_pPaM->GetNode().GetTextNode())
3560  {
3561  pTextNode->SetAttr(
3563  }
3564  }
3565  }
3566  }
3567  return bParaEndAdded;
3568 }
3569 
3571 {
3572  bool bNewParaEnd = false;
3573  // Reset Unicode flag and correct FilePos if needed.
3574  // Note: Seek is not expensive, as we're checking inline whether or not
3575  // the correct FilePos has already been reached.
3576  std::size_t nRequestedPos = m_xSBase->WW8Cp2Fc(nCpOfs+nPosCp, &m_bIsUnicode);
3577  if (!checkSeek(*m_pStrm, nRequestedPos))
3578  return false;
3579 
3580  sal_uInt16 nWCharVal(0);
3581  if( m_bIsUnicode )
3582  m_pStrm->ReadUInt16( nWCharVal ); // unicode --> read 2 bytes
3583  else
3584  {
3585  sal_uInt8 nBCode(0);
3586  m_pStrm -> ReadUChar( nBCode ); // old code --> read 1 byte
3587  nWCharVal = nBCode;
3588  }
3589 
3590  sal_Unicode cInsert = '\x0';
3591  bool bParaMark = false;
3592 
3593  if ( 0xc != nWCharVal )
3594  m_bFirstParaOfPage = false;
3595 
3596  switch (nWCharVal)
3597  {
3598  case 0:
3599  {
3600  // Page number
3601  SwPageNumberField aField(
3602  static_cast<SwPageNumberFieldType*>(m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(
3605  }
3606  break;
3607  case 0xe:
3608  // if there is only one column word treats a column break like a pagebreak.
3610  bParaMark = HandlePageBreakChar();
3611  else if (!m_nInTable)
3612  {
3613  // Always insert a txtnode for a column break, e.g. ##
3614  SwContentNode *pCntNd=m_pPaM->GetContentNode();
3615  if (pCntNd!=nullptr && pCntNd->Len()>0) // if par is empty not break is needed
3618  }
3619  break;
3620  case 0x7:
3621  {
3622  bNewParaEnd = true;
3623  WW8PLCFxDesc* pPap = m_xPlcxMan->GetPap();
3624  //The last paragraph of each cell is terminated by a special
3625  //paragraph mark called a cell mark. Following the cell mark
3626  //that ends the last cell of a table row, the table row is
3627  //terminated by a special paragraph mark called a row mark
3628  //
3629  //So the 0x7 should be right at the end of the previous
3630  //range to be a real cell-end.
3631  if (pPap->nOrigStartPos == nPosCp+1 ||
3632  pPap->nOrigStartPos == WW8_CP_MAX)
3633  {
3634  TabCellEnd(); // Table cell/row end
3635  }
3636  else
3637  bParaMark = true;
3638  }
3639  break;
3640  case 0xf:
3641  if( !m_bSpec ) // "Satellite"
3642  cInsert = u'\x00a4';
3643  break;
3644  case 0x14:
3645  if( !m_bSpec ) // "Para End" char
3646  cInsert = u'\x00b5';
3647  //TODO: should this be U+00B6 PILCROW SIGN rather than
3648  // U+00B5 MICRO SIGN?
3649  break;
3650  case 0x15:
3651  if( !m_bSpec ) // Juristenparagraph
3652  {
3653  cp_set::iterator aItr = m_aTOXEndCps.find(static_cast<WW8_CP>(nPosCp));
3654  if (aItr == m_aTOXEndCps.end())
3655  cInsert = u'\x00a7';
3656  else
3657  m_aTOXEndCps.erase(aItr);
3658  }
3659  break;
3660  case 0x9:
3661  cInsert = '\x9'; // Tab
3662  break;
3663  case 0xb:
3664  cInsert = '\xa'; // Hard NewLine
3665  break;
3666  case 0xc:
3667  bParaMark = HandlePageBreakChar();
3668  break;
3669  case 0x1e: // Non-breaking hyphen
3671  break;
3672  case 0x1f: // Non-required hyphens
3674  break;
3675  case 0xa0: // Non-breaking spaces
3677  break;
3678  case 0x1:
3679  /*
3680  Current thinking is that if bObj is set then we have a
3681  straightforward "traditional" ole object, otherwise we have a
3682  graphic preview of an associated ole2 object (or a simple
3683  graphic of course)
3684 
3685  normally in the canvas field, the code is 0x8 0x1.
3686  in a special case, the code is 0x1 0x1, which yields a simple picture
3687  */
3688  {
3689  bool bReadObj = IsInlineEscherHack();
3690  if( bReadObj )
3691  {
3692  sal_uInt64 nCurPos = m_pStrm->Tell();
3693  sal_uInt16 nWordCode(0);
3694 
3695  if( m_bIsUnicode )
3696  m_pStrm->ReadUInt16( nWordCode );
3697  else
3698  {
3699  sal_uInt8 nByteCode(0);
3700  m_pStrm->ReadUChar( nByteCode );
3701  nWordCode = nByteCode;
3702  }
3703  if( nWordCode == 0x1 )
3704  bReadObj = false;
3705  m_pStrm->Seek( nCurPos );
3706  }
3707  if( !bReadObj )
3708  {
3709  SwFrameFormat *pResult = nullptr;
3710  if (m_bObj)
3711  pResult = ImportOle();
3712  else if (m_bSpec)
3713  pResult = ImportGraf();
3714 
3715  // If we have a bad 0x1 insert a space instead.
3716  if (!pResult)
3717  {
3718  cInsert = ' ';
3719  OSL_ENSURE(!m_bObj && !m_bEmbeddObj && !m_nObjLocFc,
3720  "WW8: Please report this document, it may have a "
3721  "missing graphic");
3722  }
3723  else
3724  {
3725  // reset the flags.
3726  m_bObj = m_bEmbeddObj = false;
3727  m_nObjLocFc = 0;
3728  }
3729  }
3730  }
3731  break;
3732  case 0x8:
3733  if( !m_bObj )
3734  Read_GrafLayer( nPosCp );
3735  break;
3736  case 0xd:
3737  bNewParaEnd = bParaMark = true;
3738  if (m_nInTable > 1)
3739  {
3740  /*
3741  #i9666#/#i23161#
3742  Yes complex, if there is an entry in the undocumented PLCF
3743  which I believe to be a record of cell and row boundaries
3744  see if the magic bit which I believe to mean cell end is
3745  set. I also think btw that the third byte of the 4 byte
3746  value is the level of the cell
3747  */
3748  WW8PLCFspecial* pTest = m_xPlcxMan->GetMagicTables();
3749  if (pTest && pTest->SeekPosExact(nPosCp+1+nCpOfs) &&
3750  pTest->Where() == nPosCp+1+nCpOfs)
3751  {
3752  WW8_FC nPos;
3753  void *pData;
3754  sal_uInt32 nData = pTest->Get(nPos, pData) ? SVBT32ToUInt32(*static_cast<SVBT32*>(pData))
3755  : 0;
3756  if (nData & 0x2) // Might be how it works
3757  {
3758  TabCellEnd();
3759  bParaMark = false;
3760  }
3761  }
3762  // tdf#106799: We expect TTP marks to be also cell marks,
3763  // but sometimes sprmPFInnerTtp comes without sprmPFInnerTableCell
3764  else if (m_bWasTabCellEnd || m_bWasTabRowEnd)
3765  {
3766  TabCellEnd();
3767  bParaMark = false;
3768  }
3769  }
3770 
3771  m_bWasTabCellEnd = false;
3772 
3773  break; // line end
3774  case 0x5: // Annotation reference
3775  case 0x13:
3776  break;
3777  case 0x2: // TODO: Auto-Footnote-Number, should be replaced by SwWW8ImplReader::End_Footnote later
3778  if (!m_aFootnoteStack.empty())
3779  cInsert = '?';
3780  break;
3781  default:
3782  SAL_INFO( "sw.ww8.level2", "<unknownValue val=\"" << nWCharVal << "\">" );
3783  break;
3784  }
3785 
3786  if( '\x0' != cInsert )
3787  {
3788  OUString sInsert(cInsert);
3790  }
3791  if (!m_aApos.back()) // a para end in apo doesn't count
3792  m_bWasParaEnd = bNewParaEnd;
3793  return bParaMark;
3794 }
3795 
3797  bool* pStartAttr, bool bCallProcessSpecial)
3798 {
3799  sal_uInt16 nOldColl = m_nCurrentColl;
3800  m_nCurrentColl = m_xPlcxMan->GetColl();
3801 
3802  // Invalid Style-Id
3803  if (m_nCurrentColl >= m_vColl.size() || !m_vColl[m_nCurrentColl].m_pFormat || !m_vColl[m_nCurrentColl].m_bColl)
3804  {
3805  m_nCurrentColl = 0;
3806  m_bParaAutoBefore = false;
3807  m_bParaAutoAfter = false;
3808  }
3809  else
3810  {
3811  m_bParaAutoBefore = m_vColl[m_nCurrentColl].m_bParaAutoBefore;
3812  m_bParaAutoAfter = m_vColl[m_nCurrentColl].m_bParaAutoAfter;
3813  }
3814 
3815  if (nOldColl >= m_vColl.size())
3816  nOldColl = 0; // guess! TODO make sure this is what we want
3817 
3818  bool bTabRowEnd = false;
3819  if( pStartAttr && bCallProcessSpecial && !m_bInHyperlink )
3820  {
3821  bool bReSync;
3822  // Frame/Table/Autonumbering List Level
3823  bTabRowEnd = ProcessSpecial(bReSync, rRes.nCurrentCp + m_xPlcxMan->GetCpOfs());
3824  if( bReSync )
3825  *pStartAttr = m_xPlcxMan->Get( &rRes ); // Get Attribute-Pos again
3826  }
3827 
3828  if (!bTabRowEnd && StyleExists(m_nCurrentColl))
3829  {
3831  ChkToggleAttr(m_vColl[ nOldColl ].m_n81Flags, m_vColl[ m_nCurrentColl ].m_n81Flags);
3832  ChkToggleBiDiAttr(m_vColl[nOldColl].m_n81BiDiFlags,
3833  m_vColl[m_nCurrentColl].m_n81BiDiFlags);
3834  }
3835 }
3836 
3837 tools::Long SwWW8ImplReader::ReadTextAttr(WW8_CP& rTextPos, tools::Long nTextEnd, bool& rbStartLine, int nDepthGuard)
3838 {
3839  tools::Long nSkipChars = 0;
3840  WW8PLCFManResult aRes;
3841 
3842  OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode");
3843  bool bStartAttr = m_xPlcxMan->Get(&aRes); // Get Attribute position again
3844  aRes.nCurrentCp = rTextPos; // Current Cp position
3845 
3846  bool bNewSection = (aRes.nFlags & MAN_MASK_NEW_SEP) && !m_bIgnoreText;
3847  if ( bNewSection ) // New Section
3848  {
3849  OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode");
3850  // Create PageDesc and fill it
3851  m_aSectionManager.CreateSep(rTextPos);
3852  // -> 0xc was a Sectionbreak, but not a Pagebreak;
3853  // Create PageDesc and fill it
3854  m_bPgSecBreak = false;
3855  OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode");
3856  }
3857 
3858  // New paragraph over Plcx.Fkp.papx
3859  if ( (aRes.nFlags & MAN_MASK_NEW_PAP)|| rbStartLine )
3860  {
3861  ProcessCurrentCollChange( aRes, &bStartAttr,
3863  !m_bIgnoreText );
3864  rbStartLine = false;
3865  }
3866 
3867  // position of last CP that's to be ignored
3868  tools::Long nSkipPos = -1;
3869 
3870  if( 0 < aRes.nSprmId ) // Ignore empty Attrs
3871  {
3872  if( ( eFTN > aRes.nSprmId ) || ( 0x0800 <= aRes.nSprmId ) )
3873  {
3874  if( bStartAttr ) // WW attributes
3875  {
3876  if( aRes.nMemLen >= 0 )
3877  ImportSprm(aRes.pMemPos, aRes.nMemLen, aRes.nSprmId);
3878  }
3879  else
3880  EndSprm( aRes.nSprmId ); // Switch off Attr
3881  }
3882  else if( aRes.nSprmId < 0x800 ) // Own helper attributes
3883  {
3884  if (bStartAttr)
3885  {
3886  nSkipChars = ImportExtSprm(&aRes);
3887  if (
3888  (aRes.nSprmId == eFTN) || (aRes.nSprmId == eEDN) ||
3889  (aRes.nSprmId == eFLD) || (aRes.nSprmId == eAND)
3890  )
3891  {
3892  WW8_CP nMaxLegalSkip = nTextEnd - rTextPos;
3893  // Skip Field/Footnote-/End-Note here
3894  rTextPos += std::min<WW8_CP>(nSkipChars, nMaxLegalSkip);
3895  nSkipPos = rTextPos-1;
3896  }
3897  }
3898  else
3899  EndExtSprm( aRes.nSprmId );
3900  }
3901  }
3902 
3903  sal_Int32 nRequestedPos = m_xSBase->WW8Cp2Fc(m_xPlcxMan->GetCpOfs() + rTextPos, &m_bIsUnicode);
3904  bool bValidPos = checkSeek(*m_pStrm, nRequestedPos);
3905  SAL_WARN_IF(!bValidPos, "sw.ww8", "Document claimed to have text at an invalid position, skip attributes for region");
3906 
3907  // Find next Attr position (and Skip attributes of field contents if needed)
3908  if (nSkipChars && !m_bIgnoreText)
3909  m_xCtrlStck->MarkAllAttrsOld();
3910  bool bOldIgnoreText = m_bIgnoreText;
3911  m_bIgnoreText = true;
3912  sal_uInt16 nOldColl = m_nCurrentColl;
3913  bool bDoPlcxManPlusPLus = true;
3914  tools::Long nNext;
3915  do
3916  {
3917  if( bDoPlcxManPlusPLus )
3918  m_xPlcxMan->advance();
3919  nNext = bValidPos ? m_xPlcxMan->Where() : nTextEnd;
3920 
3922  m_pPostProcessAttrsInfo->mnCpStart == nNext)
3923  {
3924  m_pPostProcessAttrsInfo->mbCopy = true;
3925  }
3926 
3927  if( (0 <= nNext) && (nSkipPos >= nNext) )
3928  {
3929  if (nDepthGuard >= 1024)
3930  {
3931  SAL_WARN("sw.ww8", "ReadTextAttr hit recursion limit");
3932  nNext = nTextEnd;
3933  }
3934  else
3935  nNext = ReadTextAttr(rTextPos, nTextEnd, rbStartLine, nDepthGuard + 1);
3936  bDoPlcxManPlusPLus = false;
3937  m_bIgnoreText = true;
3938  }
3939 
3941  nNext > m_pPostProcessAttrsInfo->mnCpEnd)
3942  {
3943  m_pPostProcessAttrsInfo->mbCopy = false;
3944  }
3945  }
3946  while( nSkipPos >= nNext );
3947  m_bIgnoreText = bOldIgnoreText;
3948  if( nSkipChars )
3949  {
3950  m_xCtrlStck->KillUnlockedAttrs( *m_pPaM->GetPoint() );
3951  if( nOldColl != m_xPlcxMan->GetColl() )
3952  ProcessCurrentCollChange(aRes, nullptr, false);
3953  }
3954 
3955  return nNext;
3956 }
3957 
3958 void SwWW8ImplReader::ReadAttrs(WW8_CP& rTextPos, WW8_CP& rNext, tools::Long nTextEnd, bool& rbStartLine)
3959 {
3960  // Do we have attributes?
3961  if( rTextPos >= rNext )
3962  {
3963  do
3964  {
3965  rNext = ReadTextAttr(rTextPos, nTextEnd, rbStartLine);
3966  if (rTextPos == rNext && rTextPos >= nTextEnd)
3967  break;
3968  }
3969  while( rTextPos >= rNext );
3970 
3971  }
3972  else if ( rbStartLine )
3973  {
3974  /* No attributes, but still a new line.
3975  * If a line ends with a line break and paragraph attributes or paragraph templates
3976  * do NOT change the line end was not added to the Plcx.Fkp.papx i.e. (nFlags & MAN_MASK_NEW_PAP)
3977  * is false.
3978  * Due to this we need to set the template here as a kind of special treatment.
3979  */
3980  if (!m_bCpxStyle && m_nCurrentColl < m_vColl.size())
3982  rbStartLine = false;
3983  }
3984 }
3985 
3992 {
3993  // If there are any unclosed sprms then copy them to
3994  // another stack and close the ones that must be closed
3995  std::stack<sal_uInt16> aStack;
3996  m_xPlcxMan->TransferOpenSprms(aStack);
3997 
3998  while (!aStack.empty())
3999  {
4000  sal_uInt16 nSprmId = aStack.top();
4001  if ((0 < nSprmId) && (( eFTN > nSprmId) || (0x0800 <= nSprmId)))
4002  EndSprm(nSprmId);
4003  aStack.pop();
4004  }
4005 
4006  EndSpecial();
4007 }
4008 
4009 bool SwWW8ImplReader::ReadText(WW8_CP nStartCp, WW8_CP nTextLen, ManTypes nType)
4010 {
4011  bool bJoined=false;
4012 
4013  bool bStartLine = true;
4014  short nCrCount = 0;
4015  short nDistance = 0;
4016 
4017  m_bWasParaEnd = false;
4018  m_nCurrentColl = 0;
4019  m_xCurrentItemSet.reset();
4020  m_nCharFormat = -1;
4021  m_bSpec = false;
4022  m_bPgSecBreak = false;
4023 
4024  m_xPlcxMan = std::make_shared<WW8PLCFMan>(m_xSBase.get(), nType, nStartCp);
4025  tools::Long nCpOfs = m_xPlcxMan->GetCpOfs(); // Offset for Header/Footer, Footnote
4026 
4027  WW8_CP nNext = m_xPlcxMan->Where();
4028  m_xPreviousNode.reset();
4029  sal_uInt8 nDropLines = 0;
4030  SwCharFormat* pNewSwCharFormat = nullptr;
4031  const SwCharFormat* pFormat = nullptr;
4032 
4033  bool bValidPos = checkSeek(*m_pStrm, m_xSBase->WW8Cp2Fc(nStartCp + nCpOfs, &m_bIsUnicode));
4034  if (!bValidPos)
4035  return false;
4036 
4037  WW8_CP l = nStartCp;
4038  const WW8_CP nMaxPossible = WW8_CP_MAX-nStartCp;
4039  if (nTextLen > nMaxPossible)
4040  {
4041  SAL_WARN_IF(nTextLen > nMaxPossible, "sw.ww8", "TextLen too long");
4042  nTextLen = nMaxPossible;
4043  }
4044  WW8_CP nTextEnd = nStartCp+nTextLen;
4045  while (l < nTextEnd)
4046  {
4047  ReadAttrs( l, nNext, nTextEnd, bStartLine );// Takes SectionBreaks into account, too
4048  OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode");
4049 
4050  if (m_pPostProcessAttrsInfo != nullptr)
4051  PostProcessAttrs();
4052 
4053  if (l >= nTextEnd)
4054  break;
4055 
4056  bStartLine = ReadChars(l, nNext, nTextEnd, nCpOfs);
4057 
4058  // If the previous paragraph was a dropcap then do not
4059  // create a new txtnode and join the two paragraphs together
4060  if (bStartLine && !m_xPreviousNode) // Line end
4061  {
4062  bool bSplit = true;
4064  {
4065  m_bCareFirstParaEndInToc = false;
4066  if (m_pPaM->End() && m_pPaM->End()->nNode.GetNode().GetTextNode() && m_pPaM->End()->nNode.GetNode().GetTextNode()->Len() == 0)
4067  bSplit = false;
4068  }
4070  {
4071  m_bCareLastParaEndInToc = false;
4072  if (m_pPaM->End() && m_pPaM->End()->nNode.GetNode().GetTextNode() && m_pPaM->End()->nNode.GetNode().GetTextNode()->Len() == 0)
4073  bSplit = false;
4074  }
4075  if (bSplit)
4076  {
4078  }
4079  }
4080 
4081  if (SwTextNode* pPreviousNode = (bStartLine && m_xPreviousNode) ? m_xPreviousNode->GetTextNode() : nullptr)
4082  {
4083  SwTextNode* pEndNd = m_pPaM->GetNode().GetTextNode();
4084  const sal_Int32 nDropCapLen = pPreviousNode->GetText().getLength();
4085 
4086  // Need to reset the font size and text position for the dropcap
4087  {
4088  SwPaM aTmp(*pEndNd, 0, *pEndNd, nDropCapLen+1);
4089  m_xCtrlStck->Delete(aTmp);
4090  }
4091 
4092  // Get the default document dropcap which we can use as our template
4093  const SwFormatDrop* defaultDrop =
4094  static_cast<const SwFormatDrop*>( GetFormatAttr(RES_PARATR_DROP));
4095  SwFormatDrop aDrop(*defaultDrop);
4096 
4097  aDrop.GetLines() = nDropLines;
4098  aDrop.GetDistance() = nDistance;
4099  aDrop.GetChars() = writer_cast<sal_uInt8>(nDropCapLen);
4100  // Word has no concept of a "whole word dropcap"
4101  aDrop.GetWholeWord() = false;
4102 
4103  if (pFormat)
4104  aDrop.SetCharFormat(const_cast<SwCharFormat*>(pFormat));
4105  else if(pNewSwCharFormat)
4106  aDrop.SetCharFormat(pNewSwCharFormat);
4107 
4108  SwPosition aStart(*pEndNd);
4109  m_xCtrlStck->NewAttr(aStart, aDrop);
4110  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_PARATR_DROP);
4111  m_xPreviousNode.reset();
4112  }
4113  else if (m_bDropCap)
4114  {
4115  // If we have found a dropcap store the textnode
4117 
4118  SprmResult aDCS;
4119  if (m_bVer67)
4120  aDCS = m_xPlcxMan->GetPapPLCF()->HasSprm(46);
4121  else
4122  aDCS = m_xPlcxMan->GetPapPLCF()->HasSprm(0x442C);
4123 
4124  if (aDCS.pSprm && aDCS.nRemainingData >= 1)
4125  nDropLines = (*aDCS.pSprm) >> 3;
4126  else // There is no Drop Cap Specifier hence no dropcap
4127  m_xPreviousNode.reset();
4128 
4129  SprmResult aDistance = m_xPlcxMan->GetPapPLCF()->HasSprm(0x842F);
4130  if (aDistance.pSprm && aDistance.nRemainingData >= 2)
4131  nDistance = SVBT16ToUInt16(aDistance.pSprm);
4132  else
4133  nDistance = 0;
4134 
4135  const SwFormatCharFormat *pSwFormatCharFormat = nullptr;
4136 
4137  if (m_xCurrentItemSet)
4138  pSwFormatCharFormat = &(ItemGet<SwFormatCharFormat>(*m_xCurrentItemSet, RES_TXTATR_CHARFMT));
4139 
4140  if (pSwFormatCharFormat)
4141  pFormat = pSwFormatCharFormat->GetCharFormat();
4142 
4143  if (m_xCurrentItemSet && !pFormat)
4144  {
4145  OUString sPrefix = "WW8Dropcap" + OUString::number(m_nDropCap++);
4146  pNewSwCharFormat = m_rDoc.MakeCharFormat(sPrefix, m_rDoc.GetDfltCharFormat());
4147  m_xCurrentItemSet->ClearItem(RES_CHRATR_ESCAPEMENT);
4148  pNewSwCharFormat->SetFormatAttr(*m_xCurrentItemSet);
4149  }
4150 
4151  m_xCurrentItemSet.reset();
4152  m_bDropCap=false;
4153  }
4154 
4155  if (bStartLine || m_bWasTabRowEnd)
4156  {
4157  // Call all 64 CRs; not for Header and the like
4158  if ((nCrCount++ & 0x40) == 0 && nType == MAN_MAINTEXT && l <= nTextLen)
4159  {
4160  if (nTextLen < WW8_CP_MAX/100)
4161  m_nProgress = o3tl::narrowing<sal_uInt16>(l * 100 / nTextLen);
4162  else
4163  m_nProgress = o3tl::narrowing<sal_uInt16>(l / nTextLen * 100);
4164  m_xProgress->Update(m_nProgress); // Update
4165  }
4166  }
4167 
4168  // If we have encountered a 0x0c which indicates either section of
4169  // pagebreak then look it up to see if it is a section break, and
4170  // if it is not then insert a page break. If it is a section break
4171  // it will be handled as such in the ReadAttrs of the next loop
4172  if (m_bPgSecBreak)
4173  {
4174  // We need only to see if a section is ending at this cp,
4175  // the plcf will already be sitting on the correct location
4176  // if it is there.
4177  WW8PLCFxDesc aTemp;
4178  aTemp.nStartPos = aTemp.nEndPos = WW8_CP_MAX;
4179  if (m_xPlcxMan->GetSepPLCF())
4180  m_xPlcxMan->GetSepPLCF()->GetSprms(&aTemp);
4181  if ((aTemp.nStartPos != l) && (aTemp.nEndPos != l))
4182  {
4183  // #i39251# - insert text node for page break, if no one inserted.
4184  // #i43118# - refine condition: the anchor
4185  // control stack has to have entries, otherwise it's not needed
4186  // to insert a text node.
4187  if (!bStartLine && !m_xAnchorStck->empty())
4188  {
4190  }
4192  SvxFormatBreakItem(SvxBreak::PageBefore, RES_BREAK));
4193  m_bFirstParaOfPage = true;
4194  m_bPgSecBreak = false;
4195  }
4196  }
4197  }
4198 
4199  m_xPreviousNode.reset();
4200 
4201  if (m_pPaM->GetPoint()->nContent.GetIndex())
4203 
4204  if (!m_bInHyperlink)
4205  bJoined = JoinNode(*m_pPaM);
4206 
4207  CloseAttrEnds();
4208 
4209  m_xPlcxMan.reset();
4210  return bJoined;
4211 }
4212 
4214  SvStream* pSt, SwDoc& rD, const OUString& rBaseURL, bool bNewDoc, bool bSkipImages, SwPosition const &rPos)
4215  : m_pDocShell(rD.GetDocShell())
4216  , m_pStg(pStorage)
4217  , m_pStrm(pSt)
4218  , m_pTableStream(nullptr)
4219  , m_pDataStream(nullptr)
4220  , m_rDoc(rD)
4221  , m_pPaM(nullptr)
4222  , m_aSectionManager(*this)
4223  , m_aExtraneousParas(rD)
4224  , m_aInsertedTables(rD)
4225  , m_aSectionNameGenerator(rD, "WW")
4226  , m_aGrfNameGenerator(bNewDoc, OUString('G'))
4227  , m_aParaStyleMapper(rD)
4228  , m_aCharStyleMapper(rD)
4229  , m_pFlyFormatOfJustInsertedGraphic(nullptr)
4230  , m_pPreviousNumPaM(nullptr)
4231  , m_pPrevNumRule(nullptr)
4232  , m_pCurrentColl(nullptr)
4233  , m_pDfltTextFormatColl(nullptr)
4234  , m_pStandardFormatColl(nullptr)
4235  , m_pDrawModel(nullptr)
4236  , m_pDrawPg(nullptr)
4237  , m_pNumFieldType(nullptr)
4238  , m_sBaseURL(rBaseURL)
4239  , m_nIniFlags(0)
4240  , m_nIniFlags1(0)
4241  , m_nFieldFlags(0)
4242  , m_bRegardHindiDigits( false )
4243  , m_bDrawCpOValid( false )
4244  , m_nDrawCpO(0)
4245  , m_nPicLocFc(0)
4246  , m_nObjLocFc(0)
4247  , m_nIniFlyDx(0)
4248  , m_nIniFlyDy(0)
4249  , m_eTextCharSet(RTL_TEXTENCODING_ASCII_US)
4250  , m_eStructCharSet(RTL_TEXTENCODING_ASCII_US)
4251  , m_eHardCharSet(RTL_TEXTENCODING_DONTKNOW)
4252  , m_nProgress(0)
4253  , m_nCurrentColl(0)
4254  , m_nFieldNum(0)
4255  , m_nLFOPosition(USHRT_MAX)
4256  , m_nCharFormat(0)
4257  , m_nDrawXOfs(0)
4258  , m_nDrawYOfs(0)
4259  , m_nDrawXOfs2(0)
4260  , m_nDrawYOfs2(0)
4261  , m_cSymbol(0)
4262  , m_nWantedVersion(nVersionPara)
4263  , m_nSwNumLevel(0xff)
4264  , m_nWwNumType(0xff)
4265  , m_pChosenWW8OutlineStyle(nullptr)
4266  , m_nListLevel(MAXLEVEL)
4267  , m_bNewDoc(bNewDoc)
4268  , m_bSkipImages(bSkipImages)
4269  , m_bReadNoTable(false)
4270  , m_bPgSecBreak(false)
4271  , m_bSpec(false)
4272  , m_bObj(false)
4273  , m_bTxbxFlySection(false)
4274  , m_bHasBorder(false)
4275  , m_bSymbol(false)
4276  , m_bIgnoreText(false)
4277  , m_nInTable(0)
4278  , m_bWasTabRowEnd(false)
4279  , m_bWasTabCellEnd(false)
4280  , m_bAnl(false)
4281  , m_bHdFtFootnoteEdn(false)
4282  , m_bFootnoteEdn(false)
4283  , m_bIsHeader(false)
4284  , m_bIsFooter(false)
4285  , m_bIsUnicode(false)
4286  , m_bCpxStyle(false)
4287  , m_bStyNormal(false)
4288  , m_bWWBugNormal(false)
4289  , m_bNoAttrImport(false)
4290  , m_bInHyperlink(false)
4291  , m_bWasParaEnd(false)
4292  , m_bVer67(false)
4293  , m_bVer6(false)
4294  , m_bVer7(false)
4295  , m_bVer8(false)
4296  , m_bEmbeddObj(false)
4297  , m_bCurrentAND_fNumberAcross(false)
4298  , m_bNoLnNumYet(true)
4299  , m_bFirstPara(true)
4300  , m_bFirstParaOfPage(false)
4301  , m_bParaAutoBefore(false)
4302  , m_bParaAutoAfter(false)
4303  , m_bDropCap(false)
4304  , m_nDropCap(0)
4305  , m_bBidi(false)
4306  , m_bReadTable(false)
4307  , m_bLoadingTOXCache(false)
4308  , m_nEmbeddedTOXLevel(0)
4309  , m_bLoadingTOXHyperlink(false)
4310  , m_bCareFirstParaEndInToc(false)
4311  , m_bCareLastParaEndInToc(false)
4312  , m_bNotifyMacroEventRead(false)
4313  , m_bFuzzing(utl::ConfigManager::IsFuzzing())
4314 {
4315  m_pStrm->SetEndian( SvStreamEndian::LITTLE );
4316  m_aApos.push_back(false);
4317 
4319 }
4320 
4322 {
4323 }
4324 
4325 void SwWW8ImplReader::DeleteStack(std::unique_ptr<SwFltControlStack> pStck)
4326 {
4327  if( pStck )
4328  {
4329  pStck->SetAttr( *m_pPaM->GetPoint(), 0, false);
4330  pStck->SetAttr( *m_pPaM->GetPoint(), 0, false);
4331  }
4332  else
4333  {
4334  OSL_ENSURE( false, "WW stack already deleted" );
4335  }
4336 }
4337 
4339  bool bIgnoreCols)
4340 {
4341  SwPageDesc &rPage = *rSection.mpPage;
4342 
4343  SetNumberingType(rSection, rPage);
4344 
4345  SwFrameFormat &rFormat = rPage.GetMaster();
4346 
4347  if(mrReader.m_xWDop->fUseBackGroundInAllmodes) // #i56806# Make sure mrReader is initialized
4349 
4350  if (mrReader.m_xWDop->fUseBackGroundInAllmodes && mrReader.m_xMSDffManager)
4351  {
4352  tools::Rectangle aRect(0, 0, 100, 100); // A dummy, we don't care about the size
4353  SvxMSDffImportData aData(aRect);
4354  SdrObject* pObject = nullptr;
4355  if (mrReader.m_xMSDffManager->GetShape(0x401, pObject, aData) && !aData.empty())
4356  {
4357  // Only handle shape if it is a background shape
4358  if (aData.begin()->get()->nFlags & ShapeFlag::Background)
4359  {
4361  aSet(rFormat.GetDoc()->GetAttrPool());
4364  if ( aSet.HasItem(RES_BACKGROUND) )
4365  rFormat.SetFormatAttr(aSet.Get(RES_BACKGROUND));
4366  else
4367  rFormat.SetFormatAttr(aSet);
4368  }
4369  }
4370  SdrObject::Free(pObject);
4371  }
4372  wwULSpaceData aULData;
4373  GetPageULData(rSection, aULData);
4374  SetPageULSpaceItems(rFormat, aULData, rSection);
4375 
4376  rPage.SetVerticalAdjustment( rSection.mnVerticalAdjustment );
4377 
4378  SetPage(rPage, rFormat, rSection, bIgnoreCols);
4379 
4380  if (!(rSection.maSep.pgbApplyTo & 1))
4381  SwWW8ImplReader::SetPageBorder(rFormat, rSection);
4382  if (!(rSection.maSep.pgbApplyTo & 2))
4384 
4385  mrReader.SetDocumentGrid(rFormat, rSection);
4386 }
4387 
4389 {
4390  bool bMirror = mrReader.m_xWDop->fMirrorMargins ||
4391  mrReader.m_xWDop->doptypography.m_f2on1;
4392 
4393  UseOnPage eUseBase = bMirror ? UseOnPage::Mirror : UseOnPage::All;
4394  UseOnPage eUse = eUseBase;
4395  if (!mrReader.m_xWDop->fFacingPages)
4397  if (!rSection.HasTitlePage())
4398  eUse |= UseOnPage::FirstShare;
4399 
4400  OSL_ENSURE(rSection.mpPage, "Makes no sense to call me with no pages to set");
4401  if (rSection.mpPage)
4402  rSection.mpPage->WriteUseOn(eUse);
4403 }
4404 
4409 static void GiveNodePageDesc(SwNodeIndex const &rIdx, const SwFormatPageDesc &rPgDesc,
4410  SwDoc &rDoc)
4411 {
4412  /*
4413  If it's a table here, apply the pagebreak to the table
4414  properties, otherwise we add it to the para at this
4415  position
4416  */
4417  if (rIdx.GetNode().IsTableNode())
4418  {
4419  SwTable& rTable =
4420  rIdx.GetNode().GetTableNode()->GetTable();
4421  SwFrameFormat* pApply = rTable.GetFrameFormat();
4422  OSL_ENSURE(pApply, "impossible");
4423  if (pApply)
4424  pApply->SetFormatAttr(rPgDesc);
4425  }
4426  else
4427  {
4428  SwPosition aPamStart(rIdx);
4429  aPamStart.nContent.Assign(
4430  rIdx.GetNode().GetContentNode(), 0);
4431  SwPaM aPage(aPamStart);
4432 
4433  rDoc.getIDocumentContentOperations().InsertPoolItem(aPage, rPgDesc);
4434  }
4435 }
4436 
4441  mySegIter const &rStart, bool bIgnoreCols)
4442 {
4443  if (mrReader.m_bNewDoc && rIter == rStart)
4444  {
4445  rIter->mpPage =
4447  }
4448  else
4449  {
4450  rIter->mpPage = mrReader.m_rDoc.MakePageDesc(
4452  nullptr, false);
4453  }
4454  OSL_ENSURE(rIter->mpPage, "no page!");
4455  if (!rIter->mpPage)
4456  return SwFormatPageDesc();
4457 
4458  // Set page before hd/ft
4459  const wwSection *pPrevious = nullptr;
4460  if (rIter != rStart)
4461  pPrevious = &(*(rIter-1));
4462  SetHdFt(*rIter, std::distance(rStart, rIter), pPrevious);
4463  SetUseOn(*rIter);
4464 
4465  // Set hd/ft after set page
4466  SetSegmentToPageDesc(*rIter, bIgnoreCols);
4467 
4468  SwFormatPageDesc aRet(rIter->mpPage);
4469 
4470  rIter->mpPage->SetFollow(rIter->mpPage);
4471 
4472  if (rIter->PageRestartNo())
4473  aRet.SetNumOffset(rIter->PageStartAt());
4474 
4475  ++mnDesc;
4476  return aRet;
4477 }
4478 
4480 {
4481  mySegIter aEnd = maSegments.end();
4482  mySegIter aStart = maSegments.begin();
4483  for (mySegIter aIter = aStart; aIter != aEnd; ++aIter)
4484  {
4485  // If the section is of type "New column" (0x01), then simply insert a column break.
4486  // But only if there actually are columns on the page, otherwise a column break
4487  // seems to be handled like a page break by MSO.
4488  if ( aIter->maSep.bkc == 1 && aIter->maSep.ccolM1 > 0 )
4489  {
4490  SwPaM start( aIter->maStart );
4492  continue;
4493  }
4494 
4495  mySegIter aNext = aIter+1;
4496  mySegIter aPrev = (aIter == aStart) ? aIter : aIter-1;
4497 
4498  // If two following sections are different in following properties, Word will interpret a continuous
4499  // section break between them as if it was a section break next page.
4500  bool bThisAndPreviousAreCompatible = ((aIter->GetPageWidth() == aPrev->GetPageWidth()) &&
4501  (aIter->GetPageHeight() == aPrev->GetPageHeight()) && (aIter->IsLandScape() == aPrev->IsLandScape()));
4502 
4503  bool bInsertSection = (aIter != aStart) && aIter->IsContinuous() && bThisAndPreviousAreCompatible;
4504  bool bInsertPageDesc = !bInsertSection;
4505  // HACK Force new pagedesc if left/right margins change, otherwise e.g. floating tables may be anchored improperly.
4506  if( aIter->maSep.dxaLeft != aPrev->maSep.dxaLeft || aIter->maSep.dxaRight != aPrev->maSep.dxaRight )
4507  bInsertPageDesc = true;
4508  bool bProtected = SectionIsProtected(*aIter); // do we really need this ?? I guess I have a different logic in editshell which disables this...
4509 
4510  if (bInsertPageDesc)
4511  {
4512  /*
4513  If a cont section follows this section then we won't be
4514  creating a page desc with 2+ cols as we cannot host a one
4515  col section in a 2+ col pagedesc and make it look like
4516  word. But if the current section actually has columns then
4517  we are forced to insert a section here as well as a page
4518  descriptor.
4519  */
4520 
4521  bool bIgnoreCols = bInsertSection;
4522  bool bThisAndNextAreCompatible = (aNext == aEnd) ||
4523  ((aIter->GetPageWidth() == aNext->GetPageWidth()) &&
4524  (aIter->GetPageHeight() == aNext->GetPageHeight()) &&
4525  (aIter->IsLandScape() == aNext->IsLandScape()));
4526 
4527  if ((aNext != aEnd && aNext->IsContinuous() && bThisAndNextAreCompatible) || bProtected)
4528  {
4529  bIgnoreCols = true;
4530  if ((aIter->NoCols() > 1) || bProtected)
4531  bInsertSection = true;
4532  }
4533 
4534  SwFormatPageDesc aDesc(SetSwFormatPageDesc(aIter, aStart, bIgnoreCols));
4535  if (!aDesc.GetPageDesc())
4536  continue;
4537 
4538  // special case handling for odd/even section break
4539  // a) as before create a new page style for the section break
4540  // b) set Layout of generated page style to right/left ( according
4541  // to section break odd/even )
4542  // c) create a new style to follow the break page style
4543  if ( aIter->maSep.bkc == 3 || aIter->maSep.bkc == 4 )
4544  {
4545  // SetSwFormatPageDesc calls some methods that could
4546  // modify aIter (e.g. wwSection ).
4547  // Since we call SetSwFormatPageDesc below to generate the
4548  // 'Following' style of the Break style, it is safer
4549  // to take a copy of the contents of aIter.
4550  wwSection aTmpSection = *aIter;
4551  // create a new following page style
4552  SwFormatPageDesc aFollow(SetSwFormatPageDesc(aIter, aStart, bIgnoreCols));
4553  // restore any contents of aIter trashed by SetSwFormatPageDesc
4554  *aIter = aTmpSection;
4555 
4556  // Handle the section break
4557  UseOnPage eUseOnPage = UseOnPage::Left;
4558  if ( aIter->maSep.bkc == 4 ) // Odd ( right ) Section break
4559  eUseOnPage = UseOnPage::Right;
4560 
4561  // Keep the share flags.
4562  aDesc.GetPageDesc()->SetUseOn( eUseOnPage );
4563  aDesc.GetPageDesc()->SetFollow( aFollow.GetPageDesc() );
4564  }
4565 
4566  // Avoid setting the page style at the very beginning since it is always the default style anyway,
4567  // unless it is needed to specify a page number.
4568  if (aIter != aStart || aDesc.GetNumOffset())
4569  GiveNodePageDesc(aIter->maStart, aDesc, mrReader.m_rDoc);
4570  }
4571 
4572  SwTextNode* pTextNd = nullptr;
4573  if (bInsertSection)
4574  {
4575  // Start getting the bounds of this section
4576  SwPaM aSectPaM(*mrReader.m_pPaM, mrReader.m_pPaM);
4577  SwNodeIndex aAnchor(aSectPaM.GetPoint()->nNode);
4578  if (aNext != aEnd)
4579  {
4580  aAnchor = aNext->maStart;
4581  aSectPaM.GetPoint()->nNode = aAnchor;
4582  aSectPaM.GetPoint()->nContent.Assign(
4583  aNext->maStart.GetNode().GetContentNode(), 0);
4584  aSectPaM.Move(fnMoveBackward);
4585  }
4586 
4587  const SwPosition* pPos = aSectPaM.GetPoint();
4588  SwTextNode const*const pSttNd = pPos->nNode.GetNode().GetTextNode();
4589  const SwTableNode* pTableNd = pSttNd ? pSttNd->FindTableNode() : nullptr;
4590  if (pTableNd)
4591  {
4592  pTextNd =
4595 
4596  aSectPaM.GetPoint()->nNode.Assign(*pTextNd);
4597  aSectPaM.GetPoint()->nContent.Assign(
4598  aSectPaM.GetContentNode(), 0);
4599  }
4600 
4601  aSectPaM.SetMark();
4602 
4603  aSectPaM.GetPoint()->nNode = aIter->maStart;
4604  aSectPaM.GetPoint()->nContent.Assign(
4605  aSectPaM.GetContentNode(), 0);
4606 
4607  bool bHasOwnHdFt = false;
4608  /*
4609  In this nightmare scenario the continuous section has its own
4610  headers and footers so we will try and find a hard page break
4611  between here and the end of the section and put the headers and
4612  footers there.
4613  */
4614  if (!bInsertPageDesc)
4615  {
4616  bHasOwnHdFt =
4618  aIter->maSep.grpfIhdt & ~(WW8_HEADER_FIRST | WW8_FOOTER_FIRST),
4619  aIter->maSep.grpfIhdt, std::distance(aStart, aIter)
4620  );
4621  }
4622  if (bHasOwnHdFt)
4623  {
4624  // #i40766# Need to cache the page descriptor in case there is
4625  // no page break in the section
4626  SwPageDesc *pOrig = aIter->mpPage;
4627  bool bFailed = true;
4628  SwFormatPageDesc aDesc(SetSwFormatPageDesc(aIter, aStart, true));
4629  if (aDesc.GetPageDesc())
4630  {
4631  SwNodeOffset nStart = aSectPaM.Start()->nNode.GetIndex();
4632  SwNodeOffset nEnd = aSectPaM.End()->nNode.GetIndex();
4633  for(; nStart <= nEnd; ++nStart)
4634  {
4635  SwNode* pNode = mrReader.m_rDoc.GetNodes()[nStart];
4636  if (!pNode)
4637  continue;
4638  if (sw::util::HasPageBreak(*pNode))
4639  {
4640  SwNodeIndex aIdx(*pNode);
4641  GiveNodePageDesc(aIdx, aDesc, mrReader.m_rDoc);
4642  bFailed = false;
4643  break;
4644  }
4645  }
4646  }
4647  if(bFailed)
4648  {
4649  aIter->mpPage = pOrig;
4650  }
4651  }
4652 
4653  // End getting the bounds of this section, quite a job eh?
4654  SwSectionFormat *pRet = InsertSection(aSectPaM, *aIter);
4655  // The last section if continuous is always unbalanced
4656  if (pRet)
4657  {
4658  // Set the columns to be UnBalanced if that compatibility option is set
4659  if (mrReader.m_xWDop->fNoColumnBalance)
4661  else
4662  {
4663  // Otherwise set to unbalanced if the following section is
4664  // not continuous, (which also means that the last section
4665  // is unbalanced)
4666  if (aNext == aEnd || !aNext->IsContinuous())
4668  }
4669  }
4670  }
4671 
4672  if (pTextNd)
4673  {
4674  SwNodeIndex aIdx(*pTextNd);
4675  SwPaM aTest(aIdx);
4677  pTextNd = nullptr;
4678  }
4679  }
4680 }
4681 
4683 {
4684  auto aEnd = m_aTextNodes.rend();
4685  for (auto aI = m_aTextNodes.rbegin(); aI != aEnd; ++aI)
4686  {
4687  ExtraTextNodeListener& rListener = const_cast<ExtraTextNodeListener&>(*aI);
4688  SwTextNode* pTextNode = rListener.GetTextNode();
4689  rListener.StopListening(pTextNode);
4690 
4691  SwNodeIndex aIdx(*pTextNode);
4692  SwPaM aTest(aIdx);
4694  }
4695  m_aTextNodes.clear();
4696 }
4697 
4699 {
4700  m_aTextNodes.emplace(pTextNode, this);
4701 }
4702 
4704 {
4705  auto it = std::find_if(m_aTextNodes.begin(), m_aTextNodes.end(),
4706  [pModify](const ExtraTextNodeListener& rEntry) { return rEntry.GetTextNode() == pModify; });
4707  if (it == m_aTextNodes.end())
4708  return;
4709  SAL_WARN("sw.ww8", "It is unexpected to drop a para scheduled for removal");
4710  m_aTextNodes.erase(it);
4711 }
4712 
4714  : m_pTextNode(pTextNode)
4715 {
4716  m_pTextNode->Add(this);
4717 }
4718 
4720 {
4721  if (!m_pTextNode)
4722  return;
4724 }
4725 
4726 void TextNodeListener::SwClientNotify(const SwModify& rModify, const SfxHint& rHint)
4727 {
4728  if (rHint.GetId() != SfxHintId::SwLegacyModify)
4729  return;
4730  auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
4731  // ofz#41398 drop a para scheduled for deletion if something else deletes it
4732  // before wwExtraneousParas gets its chance to do so. Not the usual scenario,
4733  // indicates an underlying bug.
4734  if (pLegacy->GetWhich() == RES_OBJECTDYING)
4735  removed(const_cast<SwModify*>(&rModify));
4736 }
4737 
4739 {
4740  pTextNode->Remove(this);
4741  m_pTextNode = nullptr;
4742 }
4743 
4745 {
4746  StopListening(pTextNode);
4747 }
4748 
4750 {
4751  m_pOwner->remove_if_present(pTextNode);
4752 }
4753 
4755 {
4756  if (!m_xWwFib->m_lcbCmds)
4757  return;
4758 
4759  bool bValidPos = checkSeek(*m_pTableStream, m_xWwFib->m_fcCmds);
4760  if (!bValidPos)
4761  return;
4762 
4763  uno::Reference < embed::XStorage > xRoot(m_pDocShell->GetStorage());
4764 
4765  if (!xRoot.is())
4766  return;
4767 
4768  try
4769  {
4770  uno::Reference < io::XStream > xStream =
4771  xRoot->openStreamElement( SL::aMSMacroCmds, embed::ElementModes::READWRITE );
4772  std::unique_ptr<SvStream> xOutStream(::utl::UcbStreamHelper::CreateStream(xStream));
4773 
4774  sal_uInt32 lcbCmds = std::min<sal_uInt32>(m_xWwFib->m_lcbCmds, m_pTableStream->remainingSize());
4775  std::unique_ptr<sal_uInt8[]> xBuffer(new sal_uInt8[lcbCmds]);
4776  m_xWwFib->m_lcbCmds = m_pTableStream->ReadBytes(xBuffer.get(), lcbCmds);
4777  xOutStream->WriteBytes(xBuffer.get(), m_xWwFib->m_lcbCmds);
4778  }
4779  catch (...)
4780  {
4781  }
4782 }
4783 
4785 {
4786  std::vector<OUString> aDocVarStrings;
4787  std::vector<ww::bytes> aDocVarStringIds;
4788  std::vector<OUString> aDocValueStrings;
4789  WW8ReadSTTBF(!m_bVer67, *m_pTableStream, m_xWwFib->m_fcStwUser,
4790  m_xWwFib->m_lcbStwUser, m_bVer67 ? 2 : 0, m_eStructCharSet,
4791  aDocVarStrings, &aDocVarStringIds, &aDocValueStrings);
4792  if (m_bVer67) return;
4793 
4794  uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
4795  m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
4796  uno::Reference<document::XDocumentProperties> xDocProps(
4797  xDPS->getDocumentProperties());
4798  OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
4799  uno::Reference<beans::XPropertyContainer> xUserDefinedProps =
4800  xDocProps->getUserDefinedProperties();
4801  OSL_ENSURE(xUserDefinedProps.is(), "UserDefinedProperties is null");
4802 
4803  for(size_t i=0; i<aDocVarStrings.size(); i++)
4804  {
4805  const OUString &rName = aDocVarStrings[i];
4806  uno::Any aValue;
4807  aValue <<= rName;
4808  try {
4809  xUserDefinedProps->addProperty( rName,
4810  beans::PropertyAttribute::REMOVABLE,
4811  aValue );
4812  } catch (const uno::Exception &) {
4813  // ignore
4814  }
4815  }
4816 }
4817 
4822 {
4823  if( !m_pStg )
4824  return;
4825 
4826  uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
4827  m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
4828  uno::Reference<document::XDocumentProperties> xDocProps(
4829  xDPS->getDocumentProperties());
4830  OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
4831 
4832  if (!xDocProps.is())
4833  return;
4834 
4835  if ( m_xWwFib->m_fDot )
4836  {
4837  SfxMedium* pMedium = m_pDocShell->GetMedium();
4838  if ( pMedium )
4839  {
4840  const OUString& aName = pMedium->GetName();
4841  INetURLObject aURL( aName );
4842  OUString sTemplateURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri);
4843  if ( !sTemplateURL.isEmpty() )
4844  xDocProps->setTemplateURL( sTemplateURL );
4845  }
4846  }
4847  else if (m_xWwFib->m_lcbSttbfAssoc) // not a template, and has a SttbfAssoc
4848  {
4849  auto nCur = m_pTableStream->Tell();
4850  Sttb aSttb;
4851  // point at tgc record
4852  if (!checkSeek(*m_pTableStream, m_xWwFib->m_fcSttbfAssoc) || !aSttb.Read(*m_pTableStream))
4853  SAL_WARN("sw.ww8", "** Read of SttbAssoc data failed!!!! ");
4854  m_pTableStream->Seek( nCur ); // return to previous position, is that necessary?
4855  OUString sPath = aSttb.getStringAtIndex( 0x1 );
4856  OUString aURL;
4857  // attempt to convert to url (won't work for obvious reasons on linux)
4858  if ( !sPath.isEmpty() )
4859  osl::FileBase::getFileURLFromSystemPath( sPath, aURL );
4860  if (aURL.isEmpty())
4861  xDocProps->setTemplateURL( aURL );
4862  else
4863  xDocProps->setTemplateURL( sPath );
4864 
4865  }
4866  sfx2::LoadOlePropertySet(xDocProps, m_pStg);
4867 }
4868 
4869 static void lcl_createTemplateToProjectEntry( const uno::Reference< container::XNameContainer >& xPrjNameCache, const OUString& sTemplatePathOrURL, const OUString& sVBAProjName )
4870 {
4871  if ( !xPrjNameCache.is() )
4872  return;
4873 
4874  INetURLObject aObj;
4875  aObj.SetURL( sTemplatePathOrURL );
4876  bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
4877  OUString aURL;
4878  if ( bIsURL )
4879  aURL = sTemplatePathOrURL;
4880  else
4881  {
4882  osl::FileBase::getFileURLFromSystemPath( sTemplatePathOrURL, aURL );
4883  aObj.SetURL( aURL );
4884  }
4885  try
4886  {
4887  OUString templateNameWithExt = aObj.GetLastName();
4888  sal_Int32 nIndex = templateNameWithExt.lastIndexOf( '.' );
4889  if ( nIndex != -1 )
4890  {
4891  OUString templateName = templateNameWithExt.copy( 0, nIndex );
4892  xPrjNameCache->insertByName( templateName, uno::makeAny( sVBAProjName ) );
4893  }
4894  }
4895  catch( const uno::Exception& )
4896  {
4897  }
4898 }
4899 
4900 namespace {
4901 
4902 class WW8Customizations
4903 {
4904  SvStream* mpTableStream;
4905  WW8Fib mWw8Fib;
4906 public:
4907  WW8Customizations( SvStream*, WW8Fib const & );
4908  void Import( SwDocShell* pShell );
4909 };
4910 
4911 }
4912 
4913 WW8Customizations::WW8Customizations( SvStream* pTableStream, WW8Fib const & rFib ) : mpTableStream(pTableStream), mWw8Fib( rFib )
4914 {
4915 }
4916 
4917 void WW8Customizations::Import( SwDocShell* pShell )
4918 {
4919  if ( mWw8Fib.m_lcbCmds == 0 || !IsEightPlus(mWw8Fib.GetFIBVersion()) )
4920  return;
4921  try
4922  {
4923  Tcg aTCG;
4924  sal_uInt64 nCur = mpTableStream->Tell();
4925  if (!checkSeek(*mpTableStream, mWw8Fib.m_fcCmds)) // point at tgc record
4926  {
4927  SAL_WARN("sw.ww8", "** Seek to Customization data failed!!!! ");
4928  return;
4929  }
4930  bool bReadResult = aTCG.Read( *mpTableStream );
4931  mpTableStream->Seek( nCur ); // return to previous position, is that necessary?
4932  if ( !bReadResult )
4933  {
4934  SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! ");
4935  return;
4936  }
4937  aTCG.ImportCustomToolBar( *pShell );
4938  }
4939  catch(...)
4940  {
4941  SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! epically");
4942  }
4943 }
4944 
4945 void SwWW8ImplReader::ReadGlobalTemplateSettings( std::u16string_view sCreatedFrom, const uno::Reference< container::XNameContainer >& xPrjNameCache )
4946 {
4947  if (m_bFuzzing)
4948  return;
4949 
4950  SvtPathOptions aPathOpt;
4951  const OUString& aAddinPath = aPathOpt.GetAddinPath();
4952  uno::Sequence< OUString > sGlobalTemplates;
4953 
4954  // first get the autoload addins in the directory STARTUP
4955  uno::Reference<ucb::XSimpleFileAccess3> xSFA(ucb::SimpleFileAccess::create(::comphelper::getProcessComponentContext()));
4956 
4957  if( xSFA->isFolder( aAddinPath ) )
4958  sGlobalTemplates = xSFA->getFolderContents( aAddinPath, false );
4959 
4960  for ( const auto& rGlobalTemplate : std::as_const(sGlobalTemplates) )
4961  {
4962  INetURLObject aObj;
4963  aObj.SetURL( rGlobalTemplate );
4964  bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
4965  OUString aURL;
4966  if ( bIsURL )
4967  aURL = rGlobalTemplate;
4968  else
4969  osl::FileBase::getFileURLFromSystemPath( rGlobalTemplate, aURL );
4970  if ( !aURL.endsWithIgnoreAsciiCase( ".dot" ) || ( !sCreatedFrom.empty() && sCreatedFrom == aURL ) )
4971  continue; // don't try and read the same document as ourselves
4972 
4973  tools::SvRef<SotStorage> rRoot = new SotStorage( aURL, StreamMode::STD_READWRITE );
4974 
4975  BasicProjImportHelper aBasicImporter( *m_pDocShell );
4976  // Import vba via oox filter
4977  aBasicImporter.import( m_pDocShell->GetMedium()->GetInputStream() );
4978  lcl_createTemplateToProjectEntry( xPrjNameCache, aURL, aBasicImporter.getProjectName() );
4979  // Read toolbars & menus
4980  tools::SvRef<SotStorageStream> refMainStream = rRoot->OpenSotStream( "WordDocument");
4981  refMainStream->SetEndian(SvStreamEndian::LITTLE);
4982  WW8Fib aWwFib( *refMainStream, 8 );
4983  tools::SvRef<SotStorageStream> xTableStream =
4984  rRoot->OpenSotStream(aWwFib.m_fWhichTableStm ? OUString(SL::a1Table) : OUString(SL::a0Table), StreamMode::STD_READ);
4985 
4986  if (xTableStream.is() && ERRCODE_NONE == xTableStream->GetError())
4987  {
4988  xTableStream->SetEndian(SvStreamEndian::LITTLE);
4989  WW8Customizations aGblCustomisations( xTableStream.get(), aWwFib );
4990  aGblCustomisations.Import( m_pDocShell );
4991  }
4992  }
4993 }
4994 
4996 {
4998  if (m_bNewDoc && m_pStg && !pGloss)
4999  {
5000  // Initialize RDF metadata, to be able to add statements during the import.
5001  try
5002  {
5003  uno::Reference<frame::XModel> const xModel(m_rDoc.GetDocShell()->GetBaseModel());
5004  uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, uno::UNO_QUERY_THROW);
5005  uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext());
5006  uno::Reference<embed::XStorage> xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
5007  const uno::Reference<rdf::XURI> xBaseURI(sfx2::createBaseURI(xComponentContext, xModel, m_sBaseURL));
5008  uno::Reference<task::XInteractionHandler> xHandler;
5009  xDocumentMetadataAccess->loadMetadataFromStorage(xStorage, xBaseURI, xHandler);
5010  }
5011  catch (const uno::Exception&)
5012  {
5013  TOOLS_WARN_EXCEPTION("sw.ww8", "failed to initialize RDF metadata");
5014  }
5015  ReadDocInfo();
5016  }
5017 
5018  auto pFibData = std::make_shared<::ww8::WW8FibData>();
5019 
5020  if (m_xWwFib->m_fReadOnlyRecommended)
5021  pFibData->setReadOnlyRecommended(true);
5022  else
5023  pFibData->setReadOnlyRecommended(false);
5024 
5025  if (m_xWwFib->m_fWriteReservation)
5026  pFibData->setWriteReservation(true);
5027  else
5028  pFibData->setWriteReservation(false);
5029 
5031 
5032  ::sw::tExternalDataPointer pSttbfAsoc
5033  = std::make_shared<::ww8::WW8Sttb<ww8::WW8Struct>>(*m_pTableStream, m_xWwFib->m_fcSttbfAssoc, m_xWwFib->m_lcbSttbfAssoc);
5034 
5036 
5037  if (m_xWwFib->m_fWriteReservation || m_xWwFib->m_fReadOnlyRecommended)
5038  {
5039  SwDocShell * pDocShell = m_rDoc.GetDocShell();
5040  if (pDocShell)
5041  pDocShell->SetReadOnlyUI();
5042  }
5043 
5044  m_pPaM = mpCursor.get();
5045 
5047 
5049 
5050  /*
5051  RefFieldStck: Keeps track of bookmarks which may be inserted as
5052  variables instead.
5053  */
5056 
5058 
5059  size_t nPageDescOffset = m_rDoc.GetPageDescCnt();