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