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 = o3tl::narrowing<sal_uInt16>( nTextId >> 16 );
1004  pImpRec->aTextId.nSequence = o3tl::narrowing<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 ))
1073  : MSO_LineStyle(USHRT_MAX);
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.m_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 = m_rDoc.FindNumRulePtr(sName);
1302  if (pRule)
1303  pRet = GetNumFormatFromSwNumRuleLevel(*pRule, rTextNode.GetActualListLevel());
1304  }
1305  }
1306  return pRet;
1307 }
1308 
1310  SwFltStackEntry& rEntry )
1311 {
1312  switch( rEntry.m_pAttr->Which() )
1313  {
1314  case RES_FLTR_BOOKMARK:
1315  {
1316  // suppress insertion of bookmark, which is recognized as an internal bookmark used for table-of-content
1317  // and which is not referenced.
1318  bool bInsertBookmarkIntoDoc = true;
1319 
1320  SwFltBookmark* pFltBookmark = dynamic_cast<SwFltBookmark*>(rEntry.m_pAttr.get());
1321  if ( pFltBookmark != nullptr && pFltBookmark->IsTOCBookmark() )
1322  {
1323  const OUString& rName = pFltBookmark->GetName();
1324  std::set< OUString, SwWW8::ltstr >::const_iterator aResult = aReferencedTOCBookmarks.find(rName);
1325  if ( aResult == aReferencedTOCBookmarks.end() )
1326  {
1327  bInsertBookmarkIntoDoc = false;
1328  }
1329  }
1330  if ( bInsertBookmarkIntoDoc )
1331  {
1332  SwFltEndStack::SetAttrInDoc( rTmpPos, rEntry );
1333  }
1334  break;
1335  }
1336  default:
1337  SwFltEndStack::SetAttrInDoc( rTmpPos, rEntry );
1338  break;
1339  }
1340 
1341 }
1342 
1344  SwFltStackEntry& rEntry)
1345 {
1346  switch (rEntry.m_pAttr->Which())
1347  {
1348  case RES_LR_SPACE:
1349  {
1350  /*
1351  Loop over the affected nodes and
1352  a) convert the word style absolute indent to indent relative
1353  to any numbering indent active on the nodes
1354  b) adjust the writer style tabstops relative to the old
1355  paragraph indent to be relative to the new paragraph indent
1356  */
1357  SwPaM aRegion(rTmpPos);
1359  {
1360  SvxLRSpaceItem aNewLR( *static_cast<SvxLRSpaceItem*>(rEntry.m_pAttr.get()) );
1361  sal_uLong nStart = aRegion.Start()->nNode.GetIndex();
1362  sal_uLong nEnd = aRegion.End()->nNode.GetIndex();
1363  for(; nStart <= nEnd; ++nStart)
1364  {
1365  SwNode* pNode = m_rDoc.GetNodes()[ nStart ];
1366  if (!pNode || !pNode->IsTextNode())
1367  continue;
1368 
1369  SwContentNode* pNd = static_cast<SwContentNode*>(pNode);
1370  SvxLRSpaceItem aOldLR = static_cast<const SvxLRSpaceItem&>(pNd->GetAttr(RES_LR_SPACE));
1371 
1372  SwTextNode *pTextNode = static_cast<SwTextNode*>(pNode);
1373 
1374  const SwNumFormat* pNum
1375  = GetNumFormatFromStack(*aRegion.GetPoint(), *pTextNode);
1376  if (!pNum)
1377  {
1378  pNum = GetNumFormatFromTextNode(*pTextNode);
1379  }
1380 
1381  if ( pNum )
1382  {
1383  // #i103711#
1384  const bool bFirstLineIndentSet =
1387  // #i105414#
1388  const bool bLeftIndentSet =
1391  SyncIndentWithList( aNewLR, *pNum,
1392  bFirstLineIndentSet,
1393  bLeftIndentSet );
1394  }
1395 
1396  if (aNewLR == aOldLR)
1397  continue;
1398 
1399  pNd->SetAttr(aNewLR);
1400 
1401  }
1402  }
1403  }
1404  break;
1405 
1406  case RES_TXTATR_FIELD:
1407  OSL_ENSURE(false, "What is a field doing in the control stack,"
1408  "probably should have been in the endstack");
1409  break;
1410 
1411  case RES_TXTATR_ANNOTATION:
1412  OSL_ENSURE(false, "What is an annotation doing in the control stack,"
1413  "probably should have been in the endstack");
1414  break;
1415 
1416  case RES_TXTATR_INPUTFIELD:
1417  OSL_ENSURE(false, "What is an input field doing in the control stack,"
1418  "probably should have been in the endstack");
1419  break;
1420 
1421  case RES_TXTATR_INETFMT:
1422  {
1423  SwPaM aRegion(rTmpPos);
1425  {
1426  SwFrameFormat *pFrame;
1427  // If we have just one single inline graphic then
1428  // don't insert a field for the single frame, set
1429  // the frames hyperlink field attribute directly.
1431  if (nullptr != pFrame)
1432  {
1433  const SwFormatINetFormat *pAttr = static_cast<const SwFormatINetFormat *>(
1434  rEntry.m_pAttr.get());
1435  SwFormatURL aURL;
1436  aURL.SetURL(pAttr->GetValue(), false);
1437  aURL.SetTargetFrameName(pAttr->GetTargetFrame());
1438  pFrame->SetFormatAttr(aURL);
1439  }
1440  else
1441  {
1443  }
1444  }
1445  }
1446  break;
1447  default:
1448  SwFltControlStack::SetAttrInDoc(rTmpPos, rEntry);
1449  break;
1450  }
1451 }
1452 
1454  sal_uInt16 nWhich)
1455 {
1456  const SfxPoolItem *pItem = GetStackAttr(rPos, nWhich);
1457  if (!pItem)
1458  {
1459  SwContentNode const*const pNd = rPos.nNode.GetNode().GetContentNode();
1460  if (!pNd)
1461  pItem = &m_rDoc.GetAttrPool().GetDefaultItem(nWhich);
1462  else
1463  {
1464  /*
1465  If we're hunting for the indent on a paragraph and need to use the
1466  parent style indent, then return the indent in msword format, and
1467  not writer format, because that's the style that the filter works
1468  in (naturally)
1469  */
1470  if (nWhich == RES_LR_SPACE)
1471  {
1472  SfxItemState eState = SfxItemState::DEFAULT;
1473  if (const SfxItemSet *pSet = pNd->GetpSwAttrSet())
1474  eState = pSet->GetItemState(RES_LR_SPACE, false);
1475  if (eState != SfxItemState::SET && rReader.m_nCurrentColl < rReader.m_vColl.size())
1476  pItem = rReader.m_vColl[rReader.m_nCurrentColl].maWordLR.get();
1477  }
1478 
1479  /*
1480  If we're hunting for a character property, try and exact position
1481  within the text node for lookup
1482  */
1483  if (pNd->IsTextNode())
1484  {
1485  const sal_Int32 nPos = rPos.nContent.GetIndex();
1486  m_xScratchSet.reset(new SfxItemSet(m_rDoc.GetAttrPool(), nWhich, nWhich));
1487  if (pNd->GetTextNode()->GetParaAttr(*m_xScratchSet, nPos, nPos))
1488  pItem = m_xScratchSet->GetItem(nWhich);
1489  }
1490 
1491  if (!pItem)
1492  pItem = &pNd->GetAttr(nWhich);
1493  }
1494  }
1495  return pItem;
1496 }
1497 
1499  sal_uInt16 nWhich)
1500 {
1501  SwFltPosition aFltPos(rPos);
1502 
1503  size_t nSize = size();
1504  while (nSize)
1505  {
1506  const SwFltStackEntry& rEntry = (*this)[ --nSize ];
1507  if (rEntry.m_pAttr->Which() == nWhich)
1508  {
1509  if ( (rEntry.m_bOpen) ||
1510  (
1511  (rEntry.m_aMkPos.m_nNode <= aFltPos.m_nNode) &&
1512  (rEntry.m_aPtPos.m_nNode >= aFltPos.m_nNode) &&
1513  (rEntry.m_aMkPos.m_nContent <= aFltPos.m_nContent) &&
1514  (rEntry.m_aPtPos.m_nContent > aFltPos.m_nContent)
1515  )
1516  )
1517  /*
1518  * e.g. half-open range [0-3) so asking for properties at 3
1519  * means props that end at 3 are not included
1520  */
1521  {
1522  return rEntry.m_pAttr.get();
1523  }
1524  }
1525  }
1526  return nullptr;
1527 }
1528 
1530  const SwFormatField& rFormatField,
1531  sal_uInt16& rBkmNo)
1532 {
1533  const SwField* pField = rFormatField.GetField();
1534  sal_uInt16 nSubType;
1535  if(pField && (SwFieldIds::GetRef == pField->Which())
1536  && ((REF_FOOTNOTE == (nSubType = pField->GetSubType())) || (REF_ENDNOTE == nSubType))
1537  && !static_cast<const SwGetRefField*>(pField)->GetSetRefName().isEmpty())
1538  {
1539  const IDocumentMarkAccess* const pMarkAccess = m_rDoc.getIDocumentMarkAccess();
1541  pMarkAccess->findMark( static_cast<const SwGetRefField*>(pField)->GetSetRefName() );
1542  if(ppBkmk != pMarkAccess->getAllMarksEnd())
1543  {
1544  // find Sequence No of corresponding Foot-/Endnote
1545  rBkmNo = ppBkmk - pMarkAccess->getAllMarksBegin();
1546  return true;
1547  }
1548  }
1549  return false;
1550 }
1551 
1553  SwFltStackEntry& rEntry)
1554 {
1555  switch (rEntry.m_pAttr->Which())
1556  {
1557  /*
1558  Look up these in our lists of bookmarks that were changed to
1559  variables, and replace the ref field with a var field, otherwise
1560  do normal (?) strange stuff
1561  */
1562  case RES_TXTATR_FIELD:
1563  case RES_TXTATR_ANNOTATION:
1564  case RES_TXTATR_INPUTFIELD:
1565  {
1566  SwNodeIndex aIdx(rEntry.m_aMkPos.m_nNode, 1);
1567  SwPaM aPaM(aIdx, rEntry.m_aMkPos.m_nContent);
1568 
1569  SwFormatField& rFormatField = *static_cast<SwFormatField*>(rEntry.m_pAttr.get());
1570  SwField* pField = rFormatField.GetField();
1571 
1572  if (!RefToVar(pField, rEntry))
1573  {
1574  sal_uInt16 nBkmNo;
1575  if( IsFootnoteEdnBkmField(rFormatField, nBkmNo) )
1576  {
1577  ::sw::mark::IMark const * const pMark = m_rDoc.getIDocumentMarkAccess()->getAllMarksBegin()[nBkmNo];
1578 
1579  const SwPosition& rBkMrkPos = pMark->GetMarkPos();
1580 
1581  SwTextNode* pText = rBkMrkPos.nNode.GetNode().GetTextNode();
1582  if( pText && rBkMrkPos.nContent.GetIndex() )
1583  {
1584  SwTextAttr* const pFootnote = pText->GetTextAttrForCharAt(
1585  rBkMrkPos.nContent.GetIndex()-1, RES_TXTATR_FTN );
1586  if( pFootnote )
1587  {
1588  sal_uInt16 nRefNo = static_cast<SwTextFootnote*>(pFootnote)->GetSeqRefNo();
1589 
1590  static_cast<SwGetRefField*>(pField)->SetSeqNo( nRefNo );
1591 
1592  if( pFootnote->GetFootnote().IsEndNote() )
1593  static_cast<SwGetRefField*>(pField)->SetSubType(REF_ENDNOTE);
1594  }
1595  }
1596  }
1597  }
1598 
1600  MoveAttrs(*aPaM.GetPoint());
1601  }
1602  break;
1603  case RES_FLTR_TOX:
1604  SwFltEndStack::SetAttrInDoc(rTmpPos, rEntry);
1605  break;
1606  default:
1607  case RES_FLTR_BOOKMARK:
1608  OSL_ENSURE(false, "EndStck used with non field, not what we want");
1609  SwFltEndStack::SetAttrInDoc(rTmpPos, rEntry);
1610  break;
1611  }
1612 }
1613 
1614 /*
1615  For styles we will do our tabstop arithmetic in word style and adjust them to
1616  writer style after all the styles have been finished and the dust settles as
1617  to what affects what.
1618 
1619  For explicit attributes we turn the adjusted writer tabstops back into 0 based
1620  word indexes and we'll turn them back into writer indexes when setting them
1621  into the document. If explicit left indent exist which affects them, then this
1622  is handled when the explicit left indent is set into the document
1623 */
1624 void SwWW8ImplReader::Read_Tab(sal_uInt16 , const sal_uInt8* pData, short nLen)
1625 {
1626  if (nLen < 0)
1627  {
1629  return;
1630  }
1631 
1632  sal_uInt8 nDel = (nLen > 0) ? pData[0] : 0;
1633  const sal_uInt8* pDel = pData + 1; // Del - Array
1634 
1635  sal_uInt8 nIns = (nLen > nDel*2+1) ? pData[nDel*2+1] : 0;
1636  const sal_uInt8* pIns = pData + 2*nDel + 2; // Ins - Array
1637 
1638  short nRequiredLength = 2 + 2*nDel + 2*nIns + 1*nIns;
1639  if (nRequiredLength > nLen)
1640  {
1641  // would require more data than available to describe!
1642  // discard invalid record
1643  nIns = 0;
1644  nDel = 0;
1645  }
1646 
1647  WW8_TBD const * pTyp = reinterpret_cast<WW8_TBD const *>(pData + 2*nDel + 2*nIns + 2); // Type Array
1648 
1649  std::shared_ptr<SvxTabStopItem> aAttr(std::make_shared<SvxTabStopItem>(0, 0, SvxTabAdjust::Default, RES_PARATR_TABSTOP));
1650 
1651  const SwFormat * pSty = nullptr;
1652  sal_uInt16 nTabBase;
1653  if (m_pCurrentColl && m_nCurrentColl < m_vColl.size()) // StyleDef
1654  {
1655  nTabBase = m_vColl[m_nCurrentColl].m_nBase;
1656  if (nTabBase < m_vColl.size()) // Based On
1657  pSty = m_vColl[nTabBase].m_pFormat;
1658  }
1659  else
1660  { // Text
1661  nTabBase = m_nCurrentColl;
1662  if (m_nCurrentColl < m_vColl.size())
1663  pSty = m_vColl[m_nCurrentColl].m_pFormat;
1664  //TODO: figure out else here
1665  }
1666 
1667  bool bFound = false;
1668  std::unordered_set<size_t> aLoopWatch;
1669  while (pSty && !bFound)
1670  {
1671  const SfxPoolItem* pTabs;
1672  bFound = pSty->GetAttrSet().GetItemState(RES_PARATR_TABSTOP, false,
1673  &pTabs) == SfxItemState::SET;
1674  if( bFound )
1675  {
1676  aAttr.reset(static_cast<SvxTabStopItem*>(pTabs->Clone()));
1677  }
1678  else
1679  {
1680  sal_uInt16 nOldTabBase = nTabBase;
1681  // If based on another
1682  if (nTabBase < m_vColl.size())
1683  nTabBase = m_vColl[nTabBase].m_nBase;
1684 
1685  if (
1686  nTabBase < m_vColl.size() &&
1687  nOldTabBase != nTabBase &&
1688  nTabBase != ww::stiNil
1689  )
1690  {
1691  // #i61789: Stop searching when next style is the same as the
1692  // current one (prevent loop)
1693  aLoopWatch.insert(reinterpret_cast<size_t>(pSty));
1694  if (nTabBase < m_vColl.size())
1695  pSty = m_vColl[nTabBase].m_pFormat;
1696  //TODO figure out the else branch
1697 
1698  if (aLoopWatch.find(reinterpret_cast<size_t>(pSty)) !=
1699  aLoopWatch.end())
1700  pSty = nullptr;
1701  }
1702  else
1703  pSty = nullptr; // Give up on the search
1704  }
1705  }
1706 
1707  SvxTabStop aTabStop;
1708  for (short i=0; i < nDel; ++i)
1709  {
1710  sal_uInt16 nPos = aAttr->GetPos(SVBT16ToUInt16(pDel + i*2));
1711  if( nPos != SVX_TAB_NOTFOUND )
1712  aAttr->Remove( nPos );
1713  }
1714 
1715  for (short i=0; i < nIns; ++i)
1716  {
1717  short nPos = SVBT16ToUInt16(pIns + i*2);
1718  aTabStop.GetTabPos() = nPos;
1719  switch( pTyp[i].aBits1 & 0x7 ) // pTyp[i].jc
1720  {
1721  case 0:
1722  aTabStop.GetAdjustment() = SvxTabAdjust::Left;
1723  break;
1724  case 1:
1725  aTabStop.GetAdjustment() = SvxTabAdjust::Center;
1726  break;
1727  case 2:
1728  aTabStop.GetAdjustment() = SvxTabAdjust::Right;
1729  break;
1730  case 3:
1731  aTabStop.GetAdjustment() = SvxTabAdjust::Decimal;
1732  break;
1733  case 4:
1734  continue; // Ignore Bar
1735  }
1736 
1737  switch( pTyp[i].aBits1 >> 3 & 0x7 )
1738  {
1739  case 0:
1740  aTabStop.GetFill() = ' ';
1741  break;
1742  case 1:
1743  aTabStop.GetFill() = '.';
1744  break;
1745  case 2:
1746  aTabStop.GetFill() = '-';
1747  break;
1748  case 3:
1749  case 4:
1750  aTabStop.GetFill() = '_';
1751  break;
1752  }
1753 
1754  sal_uInt16 nPos2 = aAttr->GetPos( nPos );
1755  if (nPos2 != SVX_TAB_NOTFOUND)
1756  aAttr->Remove(nPos2); // Or else Insert() refuses
1757  aAttr->Insert(aTabStop);
1758  }
1759 
1760  if (nIns || nDel)
1761  NewAttr(*aAttr);
1762  else
1763  {
1764  // Here we have a tab definition which inserts no extra tabs, or deletes
1765  // no existing tabs. An older version of writer is probably the creator
1766  // of the document :-( . So if we are importing a style we can just
1767  // ignore it. But if we are importing into text we cannot as during
1768  // text SwWW8ImplReader::Read_Tab is called at the begin and end of
1769  // the range the attrib affects, and ignoring it would upset the
1770  // balance
1771  if (!m_pCurrentColl) // not importing into a style
1772  {
1773  SvxTabStopItem aOrig = pSty ?
1774  ItemGet<SvxTabStopItem>(*pSty, RES_PARATR_TABSTOP) :
1775  DefaultItemGet<SvxTabStopItem>(m_rDoc, RES_PARATR_TABSTOP);
1776  NewAttr(aOrig);
1777  }
1778  }
1779 }
1780 
1785 {
1786  // correct the LastPrinted date in DocumentProperties
1787  uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
1788  m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
1789  uno::Reference<document::XDocumentProperties> xDocuProps(
1790  xDPS->getDocumentProperties());
1791  OSL_ENSURE(xDocuProps.is(), "DocumentProperties is null");
1792  if (xDocuProps.is())
1793  {
1794  DateTime aLastPrinted(
1795  msfilter::util::DTTM2DateTime(m_xWDop->dttmLastPrint));
1796  ::util::DateTime uDT = aLastPrinted.GetUNODateTime();
1797  xDocuProps->setPrintDate(uDT);
1798  }
1799 
1800  // COMPATIBILITY FLAGS START
1801 
1802  // #i78951# - remember the unknown compatibility options
1803  // so as to export them out
1806 
1807  // The distance between two paragraphs is the sum of the bottom distance of
1808  // the first paragraph and the top distance of the second one
1811  // move tabs on alignment
1813  // #i24363# tab stops relative to indent
1815  // tdf#117923
1820  // tdf#128195
1825 
1826  // Import Default Tabs
1827  tools::Long nDefTabSiz = m_xWDop->dxaTab;
1828  if( nDefTabSiz < 56 )
1829  nDefTabSiz = 709;
1830 
1831  // We want exactly one DefaultTab
1832  SvxTabStopItem aNewTab( 1, sal_uInt16(nDefTabSiz), SvxTabAdjust::Default, RES_PARATR_TABSTOP );
1833  const_cast<SvxTabStop&>(aNewTab[0]).GetAdjustment() = SvxTabAdjust::Default;
1834 
1835  m_rDoc.GetAttrPool().SetPoolDefaultItem( aNewTab );
1836 
1837  // Import zoom factor
1838  if (m_xWDop->wScaleSaved)
1839  {
1840  //Import zoom type
1841  sal_Int16 nZoomType;
1842  switch (m_xWDop->zkSaved) {
1843  case 1: nZoomType = sal_Int16(SvxZoomType::WHOLEPAGE); break;
1844  case 2: nZoomType = sal_Int16(SvxZoomType::PAGEWIDTH); break;
1845  case 3: nZoomType = sal_Int16(SvxZoomType::OPTIMAL); break;
1846  default: nZoomType = sal_Int16(SvxZoomType::PERCENT); break;
1847  }
1848  uno::Sequence<beans::PropertyValue> aViewProps( comphelper::InitPropertySequence({
1849  { "ZoomFactor", uno::Any(sal_Int16(m_xWDop->wScaleSaved)) },
1850  { "VisibleBottom", uno::Any(sal_Int32(0)) },
1851  { "ZoomType", uno::Any(nZoomType) }
1852  }));
1853 
1854  uno::Reference< uno::XComponentContext > xComponentContext(comphelper::getProcessComponentContext());
1855  uno::Reference<container::XIndexContainer> xBox = document::IndexedPropertyValues::create(xComponentContext);
1856  xBox->insertByIndex(sal_Int32(0), uno::makeAny(aViewProps));
1857  uno::Reference<document::XViewDataSupplier> xViewDataSupplier(m_pDocShell->GetModel(), uno::UNO_QUERY);
1858  xViewDataSupplier->setViewData(xBox);
1859  }
1860 
1870 
1871  // #i25901# - set new compatibility option
1872  // 'Add paragraph and table spacing at bottom of table cells'
1875 
1876  // #i11860# - set new compatibility option
1877  // 'Use former object positioning' to <false>
1879 
1880  // #i27767# - set new compatibility option
1881  // 'Consider Wrapping mode when positioning object' to <true>
1883 
1885 
1886  m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::TABLE_ROW_KEEP, true); //SetTableRowKeep( true );
1887 
1889 
1898 
1899  // COMPATIBILITY FLAGS END
1900 
1901  // Import magic doptypography information, if its there
1902  if (m_xWwFib->m_nFib > 105)
1903  ImportDopTypography(m_xWDop->doptypography);
1904 
1905  // disable form design mode to be able to use imported controls directly
1906  // #i31239# always disable form design mode, not only in protected docs
1907  uno::Reference<beans::XPropertySet> xDocProps(m_pDocShell->GetModel(), uno::UNO_QUERY);
1908  if (xDocProps.is())
1909  {
1910  uno::Reference<beans::XPropertySetInfo> xInfo = xDocProps->getPropertySetInfo();
1911  if (xInfo.is())
1912  {
1913  if (xInfo->hasPropertyByName("ApplyFormDesignMode"))
1914  xDocProps->setPropertyValue("ApplyFormDesignMode", css::uno::makeAny(false));
1915  }
1916  }
1917 
1918  // The password can force read-only, comments-only, fill-in-form-only, or require track-changes.
1919  // Treat comments-only like read-only since Writer has no support for that.
1920  // Still allow editing of form fields, without requiring the password.
1921  // Still allow editing if track-changes is locked on. (Currently LockRev is ignored/lost on export anyway.)
1922  if (!m_xWDop->fProtEnabled && !m_xWDop->fLockRev)
1923  m_pDocShell->SetModifyPasswordHash(m_xWDop->lKeyProtDoc);
1924  else if ( xDocProps.is() )
1925  {
1926  comphelper::SequenceAsHashMap aGrabBag(xDocProps->getPropertyValue("InteropGrabBag"));
1927  aGrabBag["FormPasswordHash"] <<= m_xWDop->lKeyProtDoc;
1928  xDocProps->setPropertyValue("InteropGrabBag", uno::Any(aGrabBag.getAsConstPropertyValueList()));
1929  }
1930 
1931  const SvtFilterOptions& rOpt = SvtFilterOptions::Get();
1932  if (rOpt.IsUseEnhancedFields())
1934 
1935  if (m_xWDop->iGutterPos)
1936  {
1938  }
1939 }
1940 
1942 {
1943  switch (rTypo.m_iLevelOfKinsoku)
1944  {
1945  case 2: // custom
1946  {
1947  i18n::ForbiddenCharacters aForbidden(OUString(+rTypo.m_rgxchFPunct),
1948  OUString(+rTypo.m_rgxchLPunct));
1949  // unary + makes sure not to accidentally call the
1950  // OUString(ConstCharArrayDetector<...>::TypeUtf16) ctor that takes the full
1951  // m_rgxchFPunct, m_rgxchLPunct arrays with embedded NULs, instead of just the
1952  // prefix leading up to the first NUL
1954  aForbidden);
1955  // Obviously cannot set the standard level 1 for japanese, so
1956  // bail out now while we can.
1957  if (rTypo.GetConvertedLang() == LANGUAGE_JAPANESE)
1958  return;
1959  }
1960  break;
1961  default:
1962  break;
1963  }
1964 
1965  /*
1966  This MS hack means that level 2 of japanese is not in operation, so we put
1967  in what we know are the MS defaults, there is a complementary reverse
1968  hack in the writer. Its our default as well, but we can set it anyway
1969  as a flag for later.
1970  */
1971  if (!rTypo.m_reserved2)
1972  {
1973  i18n::ForbiddenCharacters aForbidden(WW8DopTypography::JapanNotBeginLevel1,
1976  }
1977 
1979  m_rDoc.getIDocumentSettingAccess().setCharacterCompressionType(static_cast<CharCompressType>(rTypo.m_iJustification));
1980 }
1981 
1986  maTmpPos(*pRdr->m_pPaM->GetPoint()),
1987  mxOldStck(std::move(pRdr->m_xCtrlStck)),
1988  mxOldAnchorStck(std::move(pRdr->m_xAnchorStck)),
1989  mxOldRedlines(std::move(pRdr->m_xRedlineStack)),
1990  mxOldPlcxMan(pRdr->m_xPlcxMan),
1991  mpWFlyPara(std::move(pRdr->m_xWFlyPara)),
1992  mpSFlyPara(std::move(pRdr->m_xSFlyPara)),
1993  mpPreviousNumPaM(pRdr->m_pPreviousNumPaM),
1994  mpPrevNumRule(pRdr->m_pPrevNumRule),
1995  mxTableDesc(std::move(pRdr->m_xTableDesc)),
1996  mnInTable(pRdr->m_nInTable),
1997  mnCurrentColl(pRdr->m_nCurrentColl),
1998  mcSymbol(pRdr->m_cSymbol),
1999  mbIgnoreText(pRdr->m_bIgnoreText),
2000  mbSymbol(pRdr->m_bSymbol),
2001  mbHdFtFootnoteEdn(pRdr->m_bHdFtFootnoteEdn),
2002  mbTxbxFlySection(pRdr->m_bTxbxFlySection),
2003  mbAnl(pRdr->m_bAnl),
2004  mbInHyperlink(pRdr->m_bInHyperlink),
2005  mbPgSecBreak(pRdr->m_bPgSecBreak),
2006  mbWasParaEnd(pRdr->m_bWasParaEnd),
2007  mbHasBorder(pRdr->m_bHasBorder),
2008  mbFirstPara(pRdr->m_bFirstPara)
2009 {
2010  pRdr->m_bSymbol = false;
2011  pRdr->m_bHdFtFootnoteEdn = true;
2012  pRdr->m_bTxbxFlySection = pRdr->m_bAnl = pRdr->m_bPgSecBreak = pRdr->m_bWasParaEnd
2013  = pRdr->m_bHasBorder = false;
2014  pRdr->m_bFirstPara = true;
2015  pRdr->m_nInTable = 0;
2016  pRdr->m_pPreviousNumPaM = nullptr;
2017  pRdr->m_pPrevNumRule = nullptr;
2018  pRdr->m_nCurrentColl = 0;
2019 
2020  pRdr->m_xCtrlStck.reset(new SwWW8FltControlStack(pRdr->m_rDoc, pRdr->m_nFieldFlags,
2021  *pRdr));
2022 
2023  pRdr->m_xRedlineStack.reset(new sw::util::RedlineStack(pRdr->m_rDoc));
2024 
2025  pRdr->m_xAnchorStck.reset(new SwWW8FltAnchorStack(pRdr->m_rDoc, pRdr->m_nFieldFlags));
2026 
2027  // Save the attribute manager: we need this as the newly created PLCFx Manager
2028  // access the same FKPs as the old one and their Start-End position changes.
2029  if (pRdr->m_xPlcxMan)
2030  pRdr->m_xPlcxMan->SaveAllPLCFx(maPLCFxSave);
2031 
2032  if (nStartCp != -1)
2033  {
2034  pRdr->m_xPlcxMan = std::make_shared<WW8PLCFMan>(pRdr->m_xSBase.get(),
2035  mxOldPlcxMan->GetManType(), nStartCp);
2036  }
2037 
2038  maOldApos.push_back(false);
2039  maOldApos.swap(pRdr->m_aApos);
2040  maOldFieldStack.swap(pRdr->m_aFieldStack);
2041 }
2042 
2044 {
2045  pRdr->m_xWFlyPara = std::move(mpWFlyPara);
2046  pRdr->m_xSFlyPara = std::move(mpSFlyPara);
2048  pRdr->m_pPrevNumRule = mpPrevNumRule;
2049  pRdr->m_xTableDesc = std::move(mxTableDesc);
2050  pRdr->m_cSymbol = mcSymbol;
2051  pRdr->m_bSymbol = mbSymbol;
2052  pRdr->m_bIgnoreText = mbIgnoreText;
2055  pRdr->m_nInTable = mnInTable;
2056  pRdr->m_bAnl = mbAnl;
2057  pRdr->m_bInHyperlink = mbInHyperlink;
2058  pRdr->m_bWasParaEnd = mbWasParaEnd;
2059  pRdr->m_bPgSecBreak = mbPgSecBreak;
2060  pRdr->m_nCurrentColl = mnCurrentColl;
2061  pRdr->m_bHasBorder = mbHasBorder;
2062  pRdr->m_bFirstPara = mbFirstPara;
2063 
2064  // Close all attributes as attributes could be created that extend the Fly
2065  pRdr->DeleteCtrlStack();
2066  pRdr->m_xCtrlStck = std::move(mxOldStck);
2067 
2068  pRdr->m_xRedlineStack->closeall(*pRdr->m_pPaM->GetPoint());
2069  pRdr->m_aFrameRedlines.emplace(std::move(pRdr->m_xRedlineStack));
2070  pRdr->m_xRedlineStack = std::move(mxOldRedlines);
2071 
2072  pRdr->DeleteAnchorStack();
2073  pRdr->m_xAnchorStck = std::move(mxOldAnchorStck);
2074 
2075  *pRdr->m_pPaM->GetPoint() = maTmpPos;
2076 
2077  if (mxOldPlcxMan != pRdr->m_xPlcxMan)
2078  pRdr->m_xPlcxMan = mxOldPlcxMan;
2079  if (pRdr->m_xPlcxMan)
2080  pRdr->m_xPlcxMan->RestoreAllPLCFx(maPLCFxSave);
2081  pRdr->m_aApos.swap(maOldApos);
2082  pRdr->m_aFieldStack.swap(maOldFieldStack);
2083 }
2084 
2086  WW8_CP nStartCp, WW8_CP nLen, ManTypes nType )
2087 {
2088  if (nStartCp < 0 || nLen < 0)
2089  return;
2090 
2091  // Saves Flags (amongst other things) and resets them
2092  WW8ReaderSave aSave( this );
2093 
2094  m_pPaM->GetPoint()->nNode = pSttIdx->GetIndex() + 1;
2096 
2097  // Read Text for Header, Footer or Footnote
2098  ReadText( nStartCp, nLen, nType ); // Ignore Sepx when doing so
2099  aSave.Restore( this );
2100 }
2101 
2106 {
2107  WW8PLCFx_SubDoc* pSD = m_xPlcxMan->GetAtn();
2108  if (!pSD)
2109  return 0;
2110 
2111  const void* pData = pSD->GetData();
2112  if (!pData)
2113  return 0;
2114 
2115  OUString sAuthor;
2116  OUString sInitials;
2117  if( m_bVer67 )
2118  {
2119  const WW67_ATRD* pDescri = static_cast<const WW67_ATRD*>(pData);
2120  const OUString* pA = GetAnnotationAuthor(SVBT16ToUInt16(pDescri->ibst));
2121  if (pA)
2122  sAuthor = *pA;
2123  else
2124  {
2125  const sal_uInt8 nLen = std::min<sal_uInt8>(pDescri->xstUsrInitl[0],
2126  SAL_N_ELEMENTS(pDescri->xstUsrInitl)-1);
2127  sAuthor = OUString(pDescri->xstUsrInitl + 1, nLen, RTL_TEXTENCODING_MS_1252);
2128  }
2129  }
2130  else
2131  {
2132  const WW8_ATRD* pDescri = static_cast<const WW8_ATRD*>(pData);
2133  {
2134  const sal_uInt16 nLen = std::min<sal_uInt16>(SVBT16ToUInt16(pDescri->xstUsrInitl[0]),
2135  SAL_N_ELEMENTS(pDescri->xstUsrInitl)-1);
2136  OUStringBuffer aBuf;
2137  aBuf.setLength(nLen);
2138  for(sal_uInt16 nIdx = 1; nIdx <= nLen; ++nIdx)
2139  aBuf[nIdx-1] = SVBT16ToUInt16(pDescri->xstUsrInitl[nIdx]);
2140  sInitials = aBuf.makeStringAndClear();
2141  }
2142 
2143  if (const OUString* pA = GetAnnotationAuthor(SVBT16ToUInt16(pDescri->ibst)))
2144  sAuthor = *pA;
2145  else
2146  sAuthor = sInitials;
2147  }
2148 
2149  sal_uInt32 nDateTime = 0;
2150 
2151  if (sal_uInt8 * pExtended = m_xPlcxMan->GetExtendedAtrds()) // Word < 2002 has no date data for comments
2152  {
2153  sal_uLong nIndex = pSD->GetIdx() & 0xFFFF; // Index is (stupidly) multiplexed for WW8PLCFx_SubDocs
2154  if (m_xWwFib->m_lcbAtrdExtra/18 > nIndex)
2155  nDateTime = SVBT32ToUInt32(*reinterpret_cast<SVBT32*>(pExtended+(nIndex*18)));
2156  }
2157 
2158  DateTime aDate = msfilter::util::DTTM2DateTime(nDateTime);
2159 
2160  OUString sText;
2161  std::unique_ptr<OutlinerParaObject> pOutliner = ImportAsOutliner( sText, pRes->nCp2OrIdx,
2162  pRes->nCp2OrIdx + pRes->nMemLen, MAN_AND );
2163 
2165  SwPostItField aPostIt(
2166  static_cast<SwPostItFieldType*>(m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Postit)), sAuthor,
2167  sText, sInitials, OUString(), aDate );
2168  aPostIt.SetTextObject(std::move(pOutliner));
2169 
2170  SwPaM aEnd(*m_pPaM->End(), *m_pPaM->End());
2171  m_xCtrlStck->NewAttr(*aEnd.GetPoint(), SvxCharHiddenItem(false, RES_CHRATR_HIDDEN));
2173  m_xCtrlStck->SetAttr(*aEnd.GetPoint(), RES_CHRATR_HIDDEN);
2174  // If this is a range, make sure that it ends after the just inserted character, not before it.
2176 
2177  return 0;
2178 }
2179 
2181  SwFrameFormat const &rHdFtFormat, sal_uInt16 nPageWidth)
2182 {
2183  const SwNodeIndex* pSttIdx = rHdFtFormat.GetContent().GetContentIdx();
2184  OSL_ENSURE(pSttIdx, "impossible");
2185  if (!pSttIdx)
2186  return;
2187 
2188  SwPosition aTmpPos(*m_pPaM->GetPoint());
2189 
2190  m_pPaM->GetPoint()->nNode = pSttIdx->GetIndex() + 1;
2192 
2193  // tdf#122425: Explicitly remove borders and spacing
2196 
2197  SwFlyFrameFormat* pFrame
2198  = m_rDoc.MakeFlySection(RndStdIds::FLY_AT_PARA, m_pPaM->GetPoint(), &aFlySet);
2199 
2200  SwFormatAnchor aAnch( pFrame->GetAnchor() );
2201  aAnch.SetType( RndStdIds::FLY_AT_PARA );
2202  pFrame->SetFormatAttr( aAnch );
2203  SwFormatFrameSize aSz(SwFrameSize::Minimum, nPageWidth, MINLAY);
2204  SwFrameSize eFrameSize = SwFrameSize::Minimum;
2205  if( eFrameSize != aSz.GetWidthSizeType() )
2206  aSz.SetWidthSizeType( eFrameSize );
2207  pFrame->SetFormatAttr(aSz);
2208  pFrame->SetFormatAttr(SwFormatSurround(css::text::WrapTextMode_THROUGH));
2209  pFrame->SetFormatAttr(SwFormatHoriOrient(0, text::HoriOrientation::LEFT)); //iFOO
2210 
2211  // #i43427# - send frame for header/footer into background.
2212  pFrame->SetFormatAttr( SvxOpaqueItem( RES_OPAQUE, false ) );
2213  SdrObject* pFrameObj = CreateContactObject( pFrame );
2214  OSL_ENSURE( pFrameObj,
2215  "<SwWW8ImplReader::Read_HdFtTextAsHackedFrame(..)> - missing SdrObject instance" );
2216  if ( pFrameObj )
2217  {
2218  pFrameObj->SetOrdNum( 0 );
2219  }
2220  MoveInsideFly(pFrame);
2221 
2222  const SwNodeIndex* pHackIdx = pFrame->GetContent().GetContentIdx();
2223 
2224  Read_HdFtFootnoteText(pHackIdx, nStart, nLen - 1, MAN_HDFT);
2225 
2226  MoveOutsideFly(pFrame, aTmpPos);
2227 }
2228 
2229 void SwWW8ImplReader::Read_HdFtText(WW8_CP nStart, WW8_CP nLen, SwFrameFormat const * pHdFtFormat)
2230 {
2231  const SwNodeIndex* pSttIdx = pHdFtFormat->GetContent().GetContentIdx();
2232  if (!pSttIdx)
2233  return;
2234 
2235  SwPosition aTmpPos( *m_pPaM->GetPoint() ); // Remember old cursor position
2236 
2237  Read_HdFtFootnoteText(pSttIdx, nStart, nLen - 1, MAN_HDFT);
2238 
2239  *m_pPaM->GetPoint() = aTmpPos;
2240 }
2241 
2243 {
2244  // Each CP of Plcfhdd MUST be less than FibRgLw97.ccpHdd
2245  return (nHeaderCP < m_xWwFib->m_ccpHdr && nHeaderCP >= 0);
2246 }
2247 
2249  int nSect)
2250 {
2251  if (m_xHdFt)
2252  {
2253  WW8_CP nStart, nLen;
2254  sal_uInt8 nNumber = 5;
2255 
2256  for( sal_uInt8 nI = 0x20; nI; nI >>= 1, nNumber-- )
2257  {
2258  if (nI & nWhichItems)
2259  {
2260  bool bOk = true;
2261  if( m_bVer67 )
2262  bOk = ( m_xHdFt->GetTextPos(grpfIhdt, nI, nStart, nLen ) && nStart >= 0 && nLen >= 2 );
2263  else
2264  {
2265  m_xHdFt->GetTextPosExact( static_cast< short >(nNumber + (nSect+1)*6), nStart, nLen);
2266  bOk = ( 2 <= nLen ) && isValid_HdFt_CP(nStart);
2267  }
2268 
2269  if (bOk)
2270  return true;
2271  }
2272  }
2273  }
2274  return false;
2275 }
2276 
2277 void SwWW8ImplReader::Read_HdFt(int nSect, const SwPageDesc *pPrev,
2278  const wwSection &rSection)
2279 {
2280  sal_uInt8 grpfIhdt = rSection.maSep.grpfIhdt;
2281  SwPageDesc *pPD = rSection.mpPage;
2282 
2283  if( !m_xHdFt )
2284  return;
2285 
2286  WW8_CP nStart, nLen;
2287  sal_uInt8 nNumber = 5;
2288 
2289  // This loops through the 6 flags WW8_{FOOTER,HEADER}_{ODD,EVEN,FIRST}
2290  // corresponding to bit fields in grpfIhdt indicating which
2291  // header/footer(s) are present in this section
2292  for( sal_uInt8 nI = 0x20; nI; nI >>= 1, nNumber-- )
2293  {
2294  if (nI & grpfIhdt)
2295  {
2296  bool bOk = true;
2297  if( m_bVer67 )
2298  bOk = ( m_xHdFt->GetTextPos(grpfIhdt, nI, nStart, nLen ) && nLen >= 2 );
2299  else
2300  {
2301  m_xHdFt->GetTextPosExact( static_cast< short >(nNumber + (nSect+1)*6), nStart, nLen);
2302  bOk = ( 2 <= nLen ) && isValid_HdFt_CP(nStart);
2303  }
2304 
2305  bool bUseLeft
2306  = (nI & ( WW8_HEADER_EVEN | WW8_FOOTER_EVEN )) != 0;
2307  bool bUseFirst
2308  = (nI & ( WW8_HEADER_FIRST | WW8_FOOTER_FIRST )) != 0;
2309 
2310  // If we are loading a first-page header/footer which is not
2311  // actually enabled in this section (it still needs to be
2312  // loaded as it may be inherited by a later section)
2313  bool bDisabledFirst = bUseFirst && !rSection.HasTitlePage();
2314 
2315  bool bFooter
2316  = (nI & ( WW8_FOOTER_EVEN | WW8_FOOTER_ODD | WW8_FOOTER_FIRST )) != 0;
2317 
2318  SwFrameFormat& rFormat = bUseLeft ? pPD->GetLeft()
2319  : bUseFirst ? pPD->GetFirstMaster()
2320  : pPD->GetMaster();
2321 
2322  SwFrameFormat* pHdFtFormat;
2323  // If we have empty first page header and footer.
2324  bool bNoFirst = !(grpfIhdt & WW8_HEADER_FIRST) && !(grpfIhdt & WW8_FOOTER_FIRST);
2325  if (bFooter)
2326  {
2327  m_bIsFooter = true;
2328  //#i17196# Cannot have left without right
2329  if (!bDisabledFirst
2330  && !pPD->GetMaster().GetFooter().GetFooterFormat())
2331  pPD->GetMaster().SetFormatAttr(SwFormatFooter(true));
2332  if (bUseLeft)
2333  pPD->GetLeft().SetFormatAttr(SwFormatFooter(true));
2334  if (bUseFirst || (rSection.maSep.fTitlePage && bNoFirst))
2336  pHdFtFormat = const_cast<SwFrameFormat*>(rFormat.GetFooter().GetFooterFormat());
2337  }
2338  else
2339  {
2340  m_bIsHeader = true;
2341  //#i17196# Cannot have left without right
2342  if (!bDisabledFirst
2343  && !pPD->GetMaster().GetHeader().GetHeaderFormat())
2344  pPD->GetMaster().SetFormatAttr(SwFormatHeader(true));
2345  if (bUseLeft)
2346  pPD->GetLeft().SetFormatAttr(SwFormatHeader(true));
2347  if (bUseFirst || (rSection.maSep.fTitlePage && bNoFirst))
2349  pHdFtFormat = const_cast<SwFrameFormat*>(rFormat.GetHeader().GetHeaderFormat());
2350  }
2351 
2352  if (bOk)
2353  {
2354  bool bHackRequired = false;
2355  if (m_bIsHeader && rSection.IsFixedHeightHeader())
2356  bHackRequired = true;
2357  else if (m_bIsFooter && rSection.IsFixedHeightFooter())
2358  bHackRequired = true;
2359 
2360  if (bHackRequired)
2361  {
2362  Read_HdFtTextAsHackedFrame(nStart, nLen, *pHdFtFormat,
2363  static_cast< sal_uInt16 >(rSection.GetTextAreaWidth()) );
2364  }
2365  else
2366  Read_HdFtText(nStart, nLen, pHdFtFormat);
2367  }
2368  else if (pPrev)
2369  CopyPageDescHdFt(pPrev, pPD, nI);
2370 
2371  m_bIsHeader = m_bIsFooter = false;
2372  }
2373  }
2374 }
2375 
2377 {
2378  return ( mrReader.m_xWDop->fProtEnabled && !rSection.IsNotProtected() );
2379 }
2380 
2381 void wwSectionManager::SetHdFt(wwSection const &rSection, int nSect,
2382  const wwSection *pPrevious)
2383 {
2384  // Header/Footer not present
2385  if (!rSection.maSep.grpfIhdt)
2386  return;
2387 
2388  OSL_ENSURE(rSection.mpPage, "makes no sense to call with a main page");
2389  if (rSection.mpPage)
2390  {
2391  mrReader.Read_HdFt(nSect, pPrevious ? pPrevious->mpPage : nullptr,
2392  rSection);
2393  }
2394 
2395  // Header/Footer - Update Index
2396  // So that the index is still valid later on
2397  if (mrReader.m_xHdFt)
2398  mrReader.m_xHdFt->UpdateIndex(rSection.maSep.grpfIhdt);
2399 
2400 }
2401 
2403 {
2404  SwTextNode* pText = m_pPaM->GetNode().GetTextNode();
2405 
2406  const SwNumRule* pRule = nullptr;
2407 
2408  if (pText != nullptr)
2409  pRule = sw::util::GetNumRuleFromTextNode(*pText);
2410 
2411  if (
2412  pRule && !m_xWDop->fDontUseHTMLAutoSpacing &&
2414  )
2415  {
2416  // If after spacing is set to auto, set the after space to 0
2417  if (m_bParaAutoAfter)
2418  SetLowerSpacing(*m_pPaM, 0);
2419 
2420  // If the previous textnode had numbering and
2421  // and before spacing is set to auto, set before space to 0
2423  SetUpperSpacing(*m_pPaM, 0);
2424 
2425  // If the previous numbering rule was different we need
2426  // to insert a space after the previous paragraph
2427  if((pRule != m_pPrevNumRule) && m_pPreviousNumPaM)
2428  SetLowerSpacing(*m_pPreviousNumPaM, GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
2429 
2430  // cache current paragraph
2431  if(m_pPreviousNumPaM)
2432  {
2433  delete m_pPreviousNumPaM;
2434  m_pPreviousNumPaM = nullptr;
2435  }
2436 
2438  m_pPrevNumRule = pRule;
2439  }
2440  else if(!pRule && m_pPreviousNumPaM)
2441  {
2442  // If the previous paragraph has numbering but the current one does not
2443  // we need to add a space after the previous paragraph
2444  SetLowerSpacing(*m_pPreviousNumPaM, GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
2445  delete m_pPreviousNumPaM;
2446  m_pPreviousNumPaM = nullptr;
2447  m_pPrevNumRule = nullptr;
2448  }
2449  else
2450  {
2451  // clear paragraph cache
2452  if(m_pPreviousNumPaM)
2453  {
2454  delete m_pPreviousNumPaM;
2455  m_pPreviousNumPaM = nullptr;
2456  }
2457  m_pPrevNumRule = pRule;
2458  }
2459 
2460  // If this is the first paragraph in the document and
2461  // Auto-spacing before paragraph is set,
2462  // set the upper spacing value to 0
2463  if(m_bParaAutoBefore && m_bFirstPara && !m_xWDop->fDontUseHTMLAutoSpacing)
2464  SetUpperSpacing(*m_pPaM, 0);
2465 
2466  m_bFirstPara = false;
2467 
2469 
2470  // We can flush all anchored graphics at the end of a paragraph.
2471  m_xAnchorStck->Flush();
2472 }
2473 
2474 bool SwWW8ImplReader::SetSpacing(SwPaM &rMyPam, int nSpace, bool bIsUpper )
2475 {
2476  bool bRet = false;
2477  const SwPosition* pSpacingPos = rMyPam.GetPoint();
2478 
2479  const SvxULSpaceItem* pULSpaceItem = m_xCtrlStck->GetFormatAttr(*pSpacingPos, RES_UL_SPACE);
2480 
2481  if(pULSpaceItem != nullptr)
2482  {
2483  SvxULSpaceItem aUL(*pULSpaceItem);
2484 
2485  if(bIsUpper)
2486  aUL.SetUpper( static_cast< sal_uInt16 >(nSpace) );
2487  else
2488  aUL.SetLower( static_cast< sal_uInt16 >(nSpace) );
2489 
2490  const sal_Int32 nEnd = pSpacingPos->nContent.GetIndex();
2491  rMyPam.GetPoint()->nContent.Assign(rMyPam.GetContentNode(), 0);
2492  m_xCtrlStck->NewAttr(*pSpacingPos, aUL);
2493  rMyPam.GetPoint()->nContent.Assign(rMyPam.GetContentNode(), nEnd);
2494  m_xCtrlStck->SetAttr(*pSpacingPos, RES_UL_SPACE);
2495  bRet = true;
2496  }
2497  return bRet;
2498 }
2499 
2500 bool SwWW8ImplReader::SetLowerSpacing(SwPaM &rMyPam, int nSpace)
2501 {
2502  return SetSpacing(rMyPam, nSpace, false);
2503 }
2504 
2505 bool SwWW8ImplReader::SetUpperSpacing(SwPaM &rMyPam, int nSpace)
2506 {
2507  return SetSpacing(rMyPam, nSpace, true);
2508 }
2509 
2510 sal_uInt16 SwWW8ImplReader::TabRowSprm(int nLevel) const
2511 {
2512  if (m_bVer67)
2513  return NS_sprm::v6::sprmPTtp;
2515 }
2516 
2518 {
2519  // Frame/Table/Anl
2520  if (m_bAnl)
2521  StopAllAnl(); // -> bAnl = false
2522 
2523  while(m_aApos.size() > 1)
2524  {
2525  StopTable();
2526  m_aApos.pop_back();
2527  --m_nInTable;
2528  if (m_aApos[m_nInTable])
2529  StopApo();
2530  }
2531 
2532  if (m_aApos[0])
2533  StopApo();
2534 
2535  OSL_ENSURE(!m_nInTable, "unclosed table!");
2536 }
2537 
2539 {
2540  // This is ww8 version of the code deciding if the table needs to be
2541  // in a floating frame.
2542  // For OOXML code, see SectionPropertyMap::FloatingTableConversion in
2543  // writerfilter/source/dmapper/PropertyMap.cxx
2544  // The two should do ~same, so if you make changes here, please check
2545  // that the other is in sync.
2546 
2547  // Note that this is just a list of heuristics till sw core can have a
2548  // table that is floating and can span over multiple pages at the same
2549  // time.
2550 
2551  // If the floating table is in a header or footer, then it won't be a
2552  // multi-page one, so can always do the conversion.
2553  if (m_bIsHeader || m_bIsFooter)
2554  {
2555  return true;
2556  }
2557 
2558  bool bResult = true;
2559 
2561  if (nullptr != aRes.pSprm)
2562  {
2563  bResult = false;
2564  WW8TabBandDesc aDesc;
2565  aDesc.ReadDef(false, aRes.pSprm, aRes.nRemainingData);
2566  int nTextAreaWidth = m_aSectionManager.GetTextAreaWidth();
2567  int nTableWidth = aDesc.nCenter[aDesc.nWwCols] - aDesc.nCenter[0];
2568 
2569  // It seems Word has a limit here, so that in case the table width is quite
2570  // close to the text area width, then it won't perform a wrapping, even in
2571  // case the content (e.g. an empty paragraph) would fit. The magic constant
2572  // here represents this limit.
2573  const int nMagicNumber = 469;
2574 
2575  // If the table is wider than the text area, then don't create a fly
2576  // for the table: no wrapping will be performed anyway, but multi-page
2577  // tables will be broken.
2578  if ((nTableWidth + nMagicNumber) < nTextAreaWidth)
2579  bResult = true;
2580 
2581  // If there are columns, do create a fly, as the flow of the columns
2582  // would otherwise restrict the table.
2583  if (!bResult && (m_aSectionManager.CurrentSectionColCount() >= 2))
2584  bResult = true;
2585  }
2586 
2587  if (bResult)
2588  {
2589  WW8PLCFxSave1 aSave;
2590  pPap->Save(aSave);
2591  if (SearchTableEnd(pPap))
2592  {
2593  // Table is considered to be imported into a fly frame and we
2594  // know where the end of the table is.
2595  bool bIsUnicode;
2596  WW8_FC nFc = m_xSBase->WW8Cp2Fc(pPap->Where(), &bIsUnicode);
2597  sal_uInt64 nPos = m_pStrm->Tell();
2598  m_pStrm->Seek(nFc);
2599  sal_uInt16 nUChar = 0;
2600  if (bIsUnicode)
2601  m_pStrm->ReadUInt16(nUChar);
2602  else
2603  {
2604  sal_uInt8 nChar = 0;
2605  m_pStrm->ReadUChar(nChar);
2606  nUChar = nChar;
2607  }
2608  m_pStrm->Seek(nPos);
2609  if (nUChar == 0xc)
2610  // The pap after the table starts with a page break, so
2611  // there will be no wrapping around the float-table.
2612  // Request no fly in this case, so the table can properly
2613  // be a multi-page one if necessary.
2614  bResult = false;
2615  }
2616  pPap->Restore(aSave);
2617  }
2618 
2619  return bResult;
2620 }
2621 
2622 bool SwWW8ImplReader::ProcessSpecial(bool &rbReSync, WW8_CP nStartCp)
2623 {
2624  // Frame/Table/Anl
2625  if (m_bInHyperlink)
2626  return false;
2627 
2628  rbReSync = false;
2629 
2630  OSL_ENSURE(m_nInTable >= 0,"nInTable < 0!");
2631 
2632  // TabRowEnd
2633  bool bTableRowEnd = (m_xPlcxMan->HasParaSprm(m_bVer67 ? 25 : 0x2417).pSprm != nullptr);
2634 
2635 // Unfortunately, for every paragraph we need to check first whether
2636 // they contain a sprm 29 (0x261B), which starts an APO.
2637 // All other sprms then refer to that APO and not to the normal text
2638 // surrounding it.
2639 // The same holds true for a Table (sprm 24 (0x2416)) and Anls (sprm 13).
2640 
2641 // WW: Table in APO is possible (Both Start-Ends occur at the same time)
2642 // WW: APO in Table not possible
2643 
2644 // This mean that of a Table is the content of an APO, the APO start needs
2645 // to be edited first, so that the Table remains in the APO and not the
2646 // other way around.
2647 // At the End, however, we need to edit the Table End first as the APO
2648 // must end after that Table (or else we never find the APO End).
2649 
2650 // The same holds true for Fly / Anl, Tab / Anl, Fly / Tab / Anl.
2651 
2652 // If the Table is within an APO the TabRowEnd Area misses the
2653 // APO settings.
2654 // To not end the APO there, we do not call ProcessApo
2655 
2656 // KHZ: When there is a table inside the Apo the Apo-flags are also
2657 // missing for the 2nd, 3rd... paragraphs of each cell.
2658 
2659 // 1st look for in-table flag, for 2000+ there is a subtable flag to
2660 // be considered, the sprm 6649 gives the level of the table
2661  sal_uInt8 nCellLevel = 0;
2662 
2663  if (m_bVer67)
2664  nCellLevel = int(nullptr != m_xPlcxMan->HasParaSprm(24).pSprm);
2665  else
2666  {
2667  nCellLevel = int(nullptr != m_xPlcxMan->HasParaSprm(0x2416).pSprm);
2668  if (!nCellLevel)
2669  nCellLevel = int(nullptr != m_xPlcxMan->HasParaSprm(0x244B).pSprm);
2670  }
2671  do
2672  {
2673  WW8_TablePos *pTabPos=nullptr;
2674  WW8_TablePos aTabPos;
2675  if(nCellLevel && !m_bVer67)
2676  {
2677  WW8PLCFxSave1 aSave;
2678  m_xPlcxMan->GetPap()->Save( aSave );
2679  rbReSync = true;
2680  WW8PLCFx_Cp_FKP* pPap = m_xPlcxMan->GetPapPLCF();
2681  WW8_CP nMyStartCp=nStartCp;
2682 
2683  SprmResult aLevel = m_xPlcxMan->HasParaSprm(0x6649);
2684  if (aLevel.pSprm && aLevel.nRemainingData >= 1)
2685  nCellLevel = *aLevel.pSprm;
2686 
2687  bool bHasRowEnd = SearchRowEnd(pPap, nMyStartCp, (m_nInTable<nCellLevel?m_nInTable:nCellLevel-1));
2688 
2689  // Bad Table, remain unchanged in level, e.g. #i19667#
2690  if (!bHasRowEnd)
2691  nCellLevel = static_cast< sal_uInt8 >(m_nInTable);
2692 
2693  if (bHasRowEnd && ParseTabPos(&aTabPos,pPap))
2694  pTabPos = &aTabPos;
2695 
2696  m_xPlcxMan->GetPap()->Restore( aSave );
2697  }
2698 
2699  // Then look if we are in an Apo
2700 
2701  ApoTestResults aApo = TestApo(nCellLevel, bTableRowEnd, pTabPos);
2702 
2703  // Look to see if we are in a Table, but Table in foot/end note not allowed
2704  bool bStartTab = (m_nInTable < nCellLevel) && !m_bFootnoteEdn;
2705 
2706  bool bStopTab = m_bWasTabRowEnd && (m_nInTable > nCellLevel) && !m_bFootnoteEdn;
2707 
2708  m_bWasTabRowEnd = false; // must be deactivated right here to prevent next
2709  // WW8TabDesc::TableCellEnd() from making nonsense
2710 
2711  if (m_nInTable && !bTableRowEnd && !bStopTab && (m_nInTable == nCellLevel && aApo.HasStartStop()))
2712  bStopTab = bStartTab = true; // Required to stop and start table
2713 
2714  // Test for Anl (Numbering) and process all events in the right order
2715  if( m_bAnl && !bTableRowEnd )
2716  {
2717  SprmResult aSprm13 = m_xPlcxMan->HasParaSprm(13);
2718  const sal_uInt8* pSprm13 = aSprm13.pSprm;
2719  if (pSprm13 && aSprm13.nRemainingData >= 1)
2720  { // Still Anl left?
2721  sal_uInt8 nT = static_cast< sal_uInt8 >(GetNumType( *pSprm13 ));
2722  if( ( nT != WW8_Pause && nT != m_nWwNumType ) // Anl change
2723  || aApo.HasStartStop() // Forced Anl end
2724  || bStopTab || bStartTab )
2725  {
2726  StopAnlToRestart(nT); // Anl-Restart (= change) over sprms
2727  }
2728  else
2729  {
2730  NextAnlLine( pSprm13 ); // Next Anl Line
2731  }
2732  }
2733  else
2734  { // Regular Anl end
2735  StopAllAnl(); // Actual end
2736  }
2737  }
2738  if (bStopTab)
2739  {
2740  StopTable();
2741  m_aApos.pop_back();
2742  --m_nInTable;
2743  }
2744  if (aApo.mbStopApo)
2745  {
2746  StopApo();
2747  m_aApos[m_nInTable] = false;
2748  }
2749 
2750  if (aApo.mbStartApo)
2751  {
2752  m_aApos[m_nInTable] = StartApo(aApo, pTabPos);
2753  // We need an ReSync after StartApo
2754  // (actually only if the Apo extends past a FKP border)
2755  rbReSync = true;
2756  }
2757  if (bStartTab)
2758  {
2759  WW8PLCFxSave1 aSave;
2760  m_xPlcxMan->GetPap()->Save( aSave );
2761 
2762  // Numbering for cell borders causes a crash -> no Anls in Tables
2763  if (m_bAnl)
2764  StopAllAnl();
2765 
2766  if(m_nInTable < nCellLevel)
2767  {
2768  if (StartTable(nStartCp))
2769  ++m_nInTable;
2770  else
2771  break;
2772  m_aApos.push_back(false);
2773  }
2774 
2775  if(m_nInTable >= nCellLevel)
2776  {
2777  // We need an ReSync after StartTable
2778  // (actually only if the Apo extends past a FKP border)
2779  rbReSync = true;
2780  m_xPlcxMan->GetPap()->Restore( aSave );
2781  }
2782  }
2783  } while (!m_bFootnoteEdn && (m_nInTable < nCellLevel));
2784  return bTableRowEnd;
2785 }
2786 
2788 {
2789  /*
2790  #i22206#/#i52786#
2791  The (default) character set used for a run of text is the default
2792  character set for the version of Word that last saved the document.
2793 
2794  This is a bit tentative, more might be required if the concept is correct.
2795  When later version of word write older 6/95 documents the charset is
2796  correctly set in the character runs involved, so it's hard to reproduce
2797  documents that require this to be sure of the process involved.
2798  */
2799  const SvxLanguageItem *pLang = static_cast<const SvxLanguageItem*>(GetFormatAttr(RES_CHRATR_LANGUAGE));
2800  LanguageType eLang = pLang ? pLang->GetLanguage() : LANGUAGE_SYSTEM;
2801  css::lang::Locale aLocale(LanguageTag::convertToLocale(eLang));
2803 }
2804 
2806 {
2807  /*
2808  #i22206#/#i52786#
2809  The (default) character set used for a run of text is the default
2810  character set for the version of Word that last saved the document.
2811 
2812  This is a bit tentative, more might be required if the concept is correct.
2813  When later version of word write older 6/95 documents the charset is
2814  correctly set in the character runs involved, so it's hard to reproduce
2815  documents that require this to be sure of the process involved.
2816  */
2817  const SvxLanguageItem *pLang = static_cast<const SvxLanguageItem*>(GetFormatAttr(RES_CHRATR_CJK_LANGUAGE));
2818  LanguageType eLang = pLang ? pLang->GetLanguage() : LANGUAGE_SYSTEM;
2819  css::lang::Locale aLocale(LanguageTag::convertToLocale(eLang));
2821 }
2822 
2824 {
2825  /*
2826  #i2015
2827  If the hard charset is set use it, if not see if there is an open
2828  character run that has set the charset, if not then fallback to the
2829  current underlying paragraph style.
2830  */
2831  rtl_TextEncoding eSrcCharSet = m_eHardCharSet;
2832  if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2833  {
2834  if (!m_bVer67)
2835  eSrcCharSet = GetCharSetFromLanguage();
2836  else if (!m_aFontSrcCharSets.empty())
2837  eSrcCharSet = m_aFontSrcCharSets.top();
2838  if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && m_nCharFormat >= 0 && o3tl::make_unsigned(m_nCharFormat) < m_vColl.size() )
2839  eSrcCharSet = m_vColl[m_nCharFormat].GetCharSet();
2840  if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && StyleExists(m_nCurrentColl) && m_nCurrentColl < m_vColl.size())
2841  eSrcCharSet = m_vColl[m_nCurrentColl].GetCharSet();
2842  if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2843  eSrcCharSet = GetCharSetFromLanguage();
2844  }
2845  return eSrcCharSet;
2846 }
2847 
2848 //Takashi Ono for CJK
2850 {
2851  /*
2852  #i2015
2853  If the hard charset is set use it, if not see if there is an open
2854  character run that has set the charset, if not then fallback to the
2855  current underlying paragraph style.
2856  */
2857  rtl_TextEncoding eSrcCharSet = m_eHardCharSet;
2858  if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2859  {
2860  if (!m_aFontSrcCJKCharSets.empty())
2861  eSrcCharSet = m_aFontSrcCJKCharSets.top();
2862  if ((eSrcCharSet == RTL_TEXTENCODING_DONTKNOW) && m_nCharFormat >= 0 && o3tl::make_unsigned(m_nCharFormat) < m_vColl.size() )
2863  eSrcCharSet = m_vColl[m_nCharFormat].GetCJKCharSet();
2864  if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW && StyleExists(m_nCurrentColl) && m_nCurrentColl < m_vColl.size())
2865  eSrcCharSet = m_vColl[m_nCurrentColl].GetCJKCharSet();
2866  if (eSrcCharSet == RTL_TEXTENCODING_DONTKNOW)
2867  eSrcCharSet = GetCJKCharSetFromLanguage();
2868  }
2869  return eSrcCharSet;
2870 }
2871 
2873 {
2874  if (m_pPostProcessAttrsInfo == nullptr)
2875  return;
2876 
2877  SfxItemIter aIter(m_pPostProcessAttrsInfo->mItemSet);
2878 
2879  for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
2880  {
2881  m_xCtrlStck->NewAttr(*m_pPostProcessAttrsInfo->mPaM.GetPoint(),
2882  *pItem);
2883  m_xCtrlStck->SetAttr(*m_pPostProcessAttrsInfo->mPaM.GetMark(),
2884  pItem->Which());
2885  }
2886 
2887  m_pPostProcessAttrsInfo.reset();
2888 }
2889 
2890 /*
2891  #i9240#
2892  It appears that some documents that are in a baltic 8 bit encoding which has
2893  some undefined characters can have use made of those characters, in which
2894  case they default to CP1252. If not then it's perhaps that the font encoding
2895  is only in use for 6/7 and for 8+ if we are in 8bit mode then the encoding
2896  is always 1252.
2897 
2898  So an encoding converter that on an undefined character attempts to
2899  convert from 1252 on the undefined character
2900 */
2901 static std::size_t Custom8BitToUnicode(rtl_TextToUnicodeConverter hConverter,
2902  char const *pIn, std::size_t nInLen, sal_Unicode *pOut, std::size_t nOutLen)
2903 {
2904  const sal_uInt32 nFlags =
2905  RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
2906  RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
2907  RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE |
2908  RTL_TEXTTOUNICODE_FLAGS_FLUSH;
2909 
2910  const sal_uInt32 nFlags2 =
2911  RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE |
2912  RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_IGNORE |
2913  RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE |
2914  RTL_TEXTTOUNICODE_FLAGS_FLUSH;
2915 
2916  std::size_t nDestChars=0;
2917  std::size_t nConverted=0;
2918 
2919  do
2920  {
2921  sal_uInt32 nInfo = 0;
2922  sal_Size nThisConverted=0;
2923 
2924  nDestChars += rtl_convertTextToUnicode(hConverter, nullptr,
2925  pIn+nConverted, nInLen-nConverted,
2926  pOut+nDestChars, nOutLen-nDestChars,
2927  nFlags, &nInfo, &nThisConverted);
2928 
2929  OSL_ENSURE(nInfo == 0, "A character conversion failed!");
2930 
2931  nConverted += nThisConverted;
2932 
2933  if (
2934  nInfo & RTL_TEXTTOUNICODE_INFO_UNDEFINED ||
2935  nInfo & RTL_TEXTTOUNICODE_INFO_MBUNDEFINED
2936  )
2937  {
2938  sal_Size nOtherConverted;
2939  rtl_TextToUnicodeConverter hCP1252Converter =
2940  rtl_createTextToUnicodeConverter(RTL_TEXTENCODING_MS_1252);
2941  nDestChars += rtl_convertTextToUnicode(hCP1252Converter, nullptr,
2942  pIn+nConverted, 1,
2943  pOut+nDestChars, nOutLen-nDestChars,
2944  nFlags2, &nInfo, &nOtherConverted);
2945  rtl_destroyTextToUnicodeConverter(hCP1252Converter);
2946  nConverted+=1;
2947  }
2948  } while (nConverted < nInLen);
2949 
2950  return nDestChars;
2951 }
2952 
2954 {
2955  bool bResult = false;
2956 
2957  switch (static_cast<sal_uInt16>(nLang))
2958  {
2959  case 0x1401: // Arabic(Algeria)
2960  case 0x3c01: // Arabic(Bahrain)
2961  case 0xc01: // Arabic(Egypt)
2962  case 0x801: // Arabic(Iraq)
2963  case 0x2c01: // Arabic (Jordan)
2964  case 0x3401: // Arabic(Kuwait)
2965  case 0x3001: // Arabic(Lebanon)
2966  case 0x1001: // Arabic(Libya)
2967  case 0x1801: // Arabic(Morocco)
2968  case 0x2001: // Arabic(Oman)
2969  case 0x4001: // Arabic(Qatar)
2970  case 0x401: // Arabic(Saudi Arabia)
2971  case 0x2801: // Arabic(Syria)
2972  case 0x1c01: // Arabic(Tunisia)
2973  case 0x3801: // Arabic(U.A.E)
2974  case 0x2401: // Arabic(Yemen)
2975  bResult = true;
2976  break;
2977  default:
2978  break;
2979  }
2980 
2981  return bResult;
2982 }
2983 
2985 {
2986  if (nChar >= 0x0030 && nChar <= 0x0039)
2987  return nChar + 0x0630;
2988 
2989  return nChar;
2990 }
2991 
2992 namespace
2993 {
2994  OUString makeOUString(rtl_uString *pStr, sal_Int32 nAllocLen)
2995  {
2996  //if read len was in or around that of allocated len, just reuse pStr
2997  if (nAllocLen < pStr->length + 256)
2998  return OUString(pStr, SAL_NO_ACQUIRE);
2999  //otherwise copy the shorter used section to release extra mem
3000  OUString sRet(pStr->buffer, pStr->length);
3001  rtl_uString_release(pStr);
3002  return sRet;
3003  }
3004 }
3005 
3009 bool SwWW8ImplReader::ReadPlainChars(WW8_CP& rPos, sal_Int32 nEnd, sal_Int32 nCpOfs)
3010 {
3011  sal_Int32 nRequestedStrLen = nEnd - rPos;
3012 
3013  OSL_ENSURE(nRequestedStrLen, "String is 0");
3014  if (nRequestedStrLen <= 0)
3015  return true;
3016 
3017  sal_Int32 nRequestedPos = m_xSBase->WW8Cp2Fc(nCpOfs+rPos, &m_bIsUnicode);
3018  bool bValidPos = checkSeek(*m_pStrm, nRequestedPos);
3019  OSL_ENSURE(bValidPos, "Document claimed to have more text than available");
3020  if (!bValidPos)
3021  {
3022  // Swallow missing range, e.g. #i95550#
3023  rPos+=nRequestedStrLen;
3024  return true;
3025  }
3026 
3027  std::size_t nAvailableStrLen = m_pStrm->remainingSize() / (m_bIsUnicode ? 2 : 1);
3028  OSL_ENSURE(nAvailableStrLen, "Document claimed to have more text than available");
3029  if (!nAvailableStrLen)
3030  {
3031  // Swallow missing range, e.g. #i95550#
3032  rPos+=nRequestedStrLen;
3033  return true;
3034  }
3035 
3036  sal_Int32 nValidStrLen = std::min<std::size_t>(nRequestedStrLen, nAvailableStrLen);
3037 
3038  // Reset Unicode flag and correct FilePos if needed.
3039  // Note: Seek is not expensive, as we're checking inline whether or not
3040  // the correct FilePos has already been reached.
3041  const sal_Int32 nStrLen = std::min(nValidStrLen, SAL_MAX_INT32-1);
3042 
3043  rtl_TextEncoding eSrcCharSet = m_bVer67 ? GetCurrentCharSet() :
3044  RTL_TEXTENCODING_MS_1252;
3045  if (m_bVer67 && eSrcCharSet == RTL_TEXTENCODING_MS_932)
3046  {
3047  /*
3048  fdo#82904
3049 
3050  Older documents exported as word 95 that use unicode aware fonts will
3051  have the charset of those fonts set to RTL_TEXTENCODING_MS_932 on
3052  export as the conversion from RTL_TEXTENCODING_UNICODE. This is a serious
3053  pain.
3054 
3055  We will try and use a fallback encoding if the conversion from
3056  RTL_TEXTENCODING_MS_932 fails, but you can get unlucky and get a document
3057  which isn't really in RTL_TEXTENCODING_MS_932 but parts of it form
3058  valid RTL_TEXTENCODING_MS_932 by chance :-(
3059 
3060  We're not the only ones that struggle with this: Here's the help from
3061  MSOffice 2003 on the topic:
3062 
3063  <<
3064  Earlier versions of Microsoft Word were sometimes used in conjunction with
3065  third-party language-processing add-in programs designed to support Chinese or
3066  Korean on English versions of Microsoft Windows. Use of these add-ins sometimes
3067  results in incorrect text display in more recent versions of Word.
3068 
3069  However, you can set options to convert these documents so that text is
3070  displayed correctly. On the Tools menu, click Options, and then click the
3071  General tab. In the English Word 6.0/95 documents list, select Contain Asian
3072  text (to have Word interpret the text as Asian code page data, regardless of
3073  its font) or Automatically detect Asian text (to have Word attempt to determine
3074  which parts of the text are meant to be Asian).
3075  >>
3076 
3077  What we can try here is to ignore a RTL_TEXTENCODING_MS_932 codepage if
3078  the language is not Japanese
3079  */
3080 
3082  if (pItem != nullptr && LANGUAGE_JAPANESE != static_cast<const SvxLanguageItem *>(pItem)->GetLanguage())
3083  {
3084  SAL_WARN("sw.ww8", "discarding word95 RTL_TEXTENCODING_MS_932 encoding");
3085  eSrcCharSet = GetCharSetFromLanguage();
3086  }
3087  }
3088  const rtl_TextEncoding eSrcCJKCharSet = m_bVer67 ? GetCurrentCJKCharSet() :
3089  RTL_TEXTENCODING_MS_1252;
3090 
3091  // allocate unicode string data
3092  auto l = [](rtl_uString* p){rtl_uString_release(p);};
3093  std::unique_ptr<rtl_uString, decltype(l)> xStr(rtl_uString_alloc(nStrLen), l);
3094  sal_Unicode* pBuffer = xStr->buffer;
3095  sal_Unicode* pWork = pBuffer;
3096 
3097  std::unique_ptr<char[]> p8Bits;
3098 
3099  rtl_TextToUnicodeConverter hConverter = nullptr;
3100  if (!m_bIsUnicode || m_bVer67)
3101  hConverter = rtl_createTextToUnicodeConverter(eSrcCharSet);
3102 
3103  if (!m_bIsUnicode)
3104  p8Bits.reset( new char[nStrLen] );
3105 
3106  // read the stream data
3107  sal_uInt8 nBCode = 0;
3108  sal_uInt16 nUCode;
3109 
3110  LanguageType nCTLLang = LANGUAGE_SYSTEM;
3112  if (pItem != nullptr)
3113  nCTLLang = static_cast<const SvxLanguageItem *>(pItem)->GetLanguage();
3114 
3115  sal_Int32 nL2;
3116  for (nL2 = 0; nL2 < nStrLen; ++nL2)
3117  {
3118  if (m_bIsUnicode)
3119  m_pStrm->ReadUInt16( nUCode ); // unicode --> read 2 bytes
3120  else
3121  {
3122  m_pStrm->ReadUChar( nBCode ); // old code --> read 1 byte
3123  nUCode = nBCode;
3124  }
3125 
3126  if (m_pStrm->GetError())
3127  {
3128  rPos = WW8_CP_MAX-10; // -> eof or other error
3129  return true;
3130  }
3131 
3132  if ((32 > nUCode) || (0xa0 == nUCode))
3133  {
3134  m_pStrm->SeekRel( m_bIsUnicode ? -2 : -1 );
3135  break; // Special character < 32, == 0xa0 found
3136  }
3137 
3138  if (m_bIsUnicode)
3139  {
3140  if (!m_bVer67)
3141  *pWork++ = nUCode;
3142  else
3143  {
3144  if (nUCode >= 0x3000) //0x8000 ?
3145  {
3146  char aTest[2];
3147  aTest[0] = static_cast< char >((nUCode & 0xFF00) >> 8);
3148  aTest[1] = static_cast< char >(nUCode & 0x00FF);
3149  OUString aTemp(aTest, 2, eSrcCJKCharSet);
3150  OSL_ENSURE(aTemp.getLength() == 1, "so much for that theory");
3151  *pWork++ = aTemp[0];
3152  }
3153  else
3154  {
3155  char cTest = static_cast< char >(nUCode & 0x00FF);
3156  pWork += Custom8BitToUnicode(hConverter, &cTest, 1, pWork, 1);
3157  }
3158  }
3159  }
3160  else
3161  p8Bits[nL2] = nBCode;
3162  }
3163 
3164  if (nL2)
3165  {
3166  const sal_Int32 nEndUsed = !m_bIsUnicode
3167  ? Custom8BitToUnicode(hConverter, p8Bits.get(), nL2, pBuffer, nStrLen)
3168  : pWork - pBuffer;
3169 
3171  {
3172  for (sal_Int32 nI = 0; nI < nEndUsed; ++nI, ++pBuffer)
3173  *pBuffer = TranslateToHindiNumbers(*pBuffer);
3174  }
3175 
3176  xStr->buffer[nEndUsed] = 0;
3177  xStr->length = nEndUsed;
3178 
3179  emulateMSWordAddTextToParagraph(makeOUString(xStr.release(), nStrLen));
3180  rPos += nL2;
3181  if (!m_aApos.back()) // a para end in apo doesn't count
3182  m_bWasParaEnd = false; // No CR
3183  }
3184 
3185  if (hConverter)
3186  rtl_destroyTextToUnicodeConverter(hConverter);
3187  return nL2 >= nStrLen;
3188 }
3189 
3190 #define MSASCII SAL_MAX_INT16
3191 
3192 namespace
3193 {
3194  // We want to force weak chars inside 0x0020 to 0x007F to LATIN
3195  sal_Int16 lcl_getScriptType(
3196  const uno::Reference<i18n::XBreakIterator>& rBI,
3197  const OUString &rString, sal_Int32 nPos)
3198  {
3199  sal_Int16 nScript = rBI->getScriptType(rString, nPos);
3200  if (nScript == i18n::ScriptType::WEAK && rString[nPos] >= 0x0020 && rString[nPos] <= 0x007F)
3201  nScript = MSASCII;
3202  return nScript;
3203  }
3204 
3205  // We want to know about WEAK segments, so endOfScript isn't
3206  // useful, and see lcl_getScriptType anyway
3207  sal_Int32 lcl_endOfScript(
3208  const uno::Reference<i18n::XBreakIterator>& rBI,
3209  const OUString &rString, sal_Int32 nPos, sal_Int16 nScript)
3210  {
3211  while (nPos < rString.getLength())
3212  {
3213  sal_Int16 nNewScript = lcl_getScriptType(rBI, rString, nPos);
3214  if (nScript != nNewScript)
3215  break;
3216  ++nPos;
3217  }
3218  return nPos;
3219  }
3220 
3221  sal_Int32 lcl_getWriterScriptType(
3222  const uno::Reference<i18n::XBreakIterator>& rBI,
3223  const OUString &rString, sal_Int32 nPos)
3224  {
3225  sal_Int16 nScript = i18n::ScriptType::WEAK;
3226 
3227  if (rString.isEmpty())
3228  return nScript;
3229 
3230  while (nPos >= 0)
3231  {
3232  nScript = rBI->getScriptType(rString, nPos);
3233  if (nScript != i18n::ScriptType::WEAK)
3234  break;
3235  --nPos;
3236  }
3237 
3238  return nScript;
3239  }
3240 
3241  bool samePitchIgnoreUnknown(FontPitch eA, FontPitch eB)
3242  {
3243  return (eA == eB || eA == PITCH_DONTKNOW || eB == PITCH_DONTKNOW);
3244  }
3245 
3246  bool sameFontIgnoringIrrelevantFields(const SvxFontItem &rA, const SvxFontItem &rB)
3247  {
3248  // Ignoring CharSet, and ignoring unknown pitch
3249  return rA.GetFamilyName() == rB.GetFamilyName() &&
3250  rA.GetStyleName() == rB.GetStyleName() &&
3251  rA.GetFamily() == rB.GetFamily() &&
3252  samePitchIgnoreUnknown(rA.GetPitch(), rB.GetPitch());
3253  }
3254 }
3255 
3256 // In writer we categorize text into CJK, CTL and "Western" for everything else.
3257 // Microsoft Word basically categorizes text into East Asian, Complex, ASCII,
3258 // NonEastAsian/HighAnsi, with some shared characters and some properties to
3259 // hint as to which way to bias those shared characters.
3260 
3261 // That's four categories, we however have three categories. Given that problem
3262 // here we would ideally find out "what would word do" to see what font/language
3263 // word would assign to characters based on the unicode range they fall into and
3264 // hack the word one onto the range we use. However it's unclear what word's
3265 // categorization is. So we don't do that here yet.
3266 
3267 // Additional to the categorization, when word encounters weak text for ambiguous
3268 // chars it uses idcthint to indicate which way to bias. We don't have an idcthint
3269 // feature in writer.
3270 
3271 // So what we currently do here then is to split our text into non-weak/weak
3272 // sections and uses word's idcthint to determine what font it would use and
3273 // force that on for the segment. Following what we *do* know about word's
3274 // categorization, we know that the range 0x0020 and 0x007F is sprmCRgFtc0 in
3275 // word, something we map to LATIN, so we consider all weak chars in that range
3276 // to auto-bias to LATIN.
3277 
3278 // See https://bugs.libreoffice.org/show_bug.cgi?id=34319 for an example
3280 {
3281  if (rAddString.isEmpty())
3282  return;
3283 
3284  if (m_bFuzzing)
3285  {
3286  simpleAddTextToParagraph(rAddString);
3287  return;
3288  }
3289 
3290  uno::Reference<i18n::XBreakIterator> xBI(g_pBreakIt->GetBreakIter());
3291  assert(xBI.is());
3292 
3293  sal_Int16 nScript = lcl_getScriptType(xBI, rAddString, 0);
3294  sal_Int32 nLen = rAddString.getLength();
3295 
3296  OUString sParagraphText;
3297  const SwContentNode *pCntNd = m_pPaM->GetContentNode();
3298  const SwTextNode* pNd = pCntNd ? pCntNd->GetTextNode() : nullptr;
3299  if (pNd)
3300  sParagraphText = pNd->GetText();
3301  sal_Int32 nParaOffset = sParagraphText.getLength();
3302  sParagraphText = sParagraphText + rAddString;
3303 
3304  sal_Int32 nPos = 0;
3305  while (nPos < nLen)
3306  {
3307  sal_Int32 nEnd = lcl_endOfScript(xBI, rAddString, nPos, nScript);
3308  if (nEnd < 0)
3309  break;
3310 
3311  OUString sChunk(rAddString.copy(nPos, nEnd-nPos));
3312  const sal_uInt16 aIds[] = {RES_CHRATR_FONT, RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_FONT};
3313  const SvxFontItem *pOverriddenItems[] = {nullptr, nullptr, nullptr};
3314  bool aForced[] = {false, false, false};
3315 
3316  int nLclIdctHint = 0xFF;
3317  if (nScript == i18n::ScriptType::WEAK)
3318  {
3319  const SfxInt16Item *pIdctHint = static_cast<const SfxInt16Item*>(GetFormatAttr(RES_CHRATR_IDCTHINT));
3320  nLclIdctHint = pIdctHint->GetValue();
3321  }
3322  else if (nScript == MSASCII) // Force weak chars in ascii range to use LATIN font
3323  nLclIdctHint = 0;
3324 
3325  sal_uInt16 nForceFromFontId = 0;
3326  if (nLclIdctHint != 0xFF)
3327  {
3328  switch (nLclIdctHint)
3329  {
3330  case 0:
3331  nForceFromFontId = RES_CHRATR_FONT;
3332  break;
3333  case 1:
3334  nForceFromFontId = RES_CHRATR_CJK_FONT;
3335  break;
3336  case 2:
3337  nForceFromFontId = RES_CHRATR_CTL_FONT;
3338  break;
3339  default:
3340  break;
3341  }
3342  }
3343 
3344  if (nForceFromFontId != 0)
3345  {
3346  // Now we know that word would use the nForceFromFontId font for this range
3347  // Try and determine what script writer would assign this range to
3348 
3349  sal_Int32 nWriterScript = lcl_getWriterScriptType(xBI, sParagraphText,
3350  nPos + nParaOffset);
3351 
3352  bool bWriterWillUseSameFontAsWordAutomatically = false;
3353 
3354  if (nWriterScript != i18n::ScriptType::WEAK)
3355  {
3356  if (
3357  (nWriterScript == i18n::ScriptType::ASIAN && nForceFromFontId == RES_CHRATR_CJK_FONT) ||
3358  (nWriterScript == i18n::ScriptType::COMPLEX && nForceFromFontId == RES_CHRATR_CTL_FONT) ||
3359  (nWriterScript == i18n::ScriptType::LATIN && nForceFromFontId == RES_CHRATR_FONT)
3360  )
3361  {
3362  bWriterWillUseSameFontAsWordAutomatically = true;
3363  }
3364  else
3365  {
3366  const SvxFontItem *pSourceFont = static_cast<const SvxFontItem*>(GetFormatAttr(nForceFromFontId));
3367  sal_uInt16 nDestId = aIds[nWriterScript-1];
3368  const SvxFontItem *pDestFont = static_cast<const SvxFontItem*>(GetFormatAttr(nDestId));
3369  bWriterWillUseSameFontAsWordAutomatically = sameFontIgnoringIrrelevantFields(*pSourceFont, *pDestFont);
3370  }
3371  }
3372 
3373  // Writer won't use the same font as word, so force the issue
3374  if (!bWriterWillUseSameFontAsWordAutomatically)
3375  {
3376  const SvxFontItem *pSourceFont = static_cast<const SvxFontItem*>(GetFormatAttr(nForceFromFontId));
3377 
3378  for (size_t i = 0; i < SAL_N_ELEMENTS(aIds); ++i)
3379  {
3380  const SvxFontItem *pDestFont = static_cast<const SvxFontItem*>(GetFormatAttr(aIds[i]));
3381  aForced[i] = aIds[i] != nForceFromFontId && *pSourceFont != *pDestFont;
3382  if (aForced[i])
3383  {
3384  pOverriddenItems[i] =
3385  static_cast<const SvxFontItem*>(m_xCtrlStck->GetStackAttr(*m_pPaM->GetPoint(), aIds[i]));
3386 
3387  SvxFontItem aForceFont(*pSourceFont);
3388  aForceFont.SetWhich(aIds[i]);
3389  m_xCtrlStck->NewAttr(*m_pPaM->GetPoint(), aForceFont);
3390  }
3391  }
3392  }
3393  }
3394 
3395  simpleAddTextToParagraph(sChunk);
3396 
3397  for (size_t i = 0; i < SAL_N_ELEMENTS(aIds); ++i)
3398  {
3399  if (aForced[i])
3400  {
3401  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), aIds[i]);
3402  if (pOverriddenItems[i])
3403  m_xCtrlStck->NewAttr(*m_pPaM->GetPoint(), *(pOverriddenItems[i]));
3404  }
3405  }
3406 
3407  nPos = nEnd;
3408  if (nPos < nLen)
3409  nScript = lcl_getScriptType(xBI, rAddString, nPos);
3410  }
3411 }
3412 
3413 namespace sw {
3414 
3415 auto FilterControlChars(OUString const& rString) -> OUString
3416 {
3417  OUStringBuffer buf(rString.getLength());
3418  for (sal_Int32 i = 0; i < rString.getLength(); ++i)
3419  {
3420  sal_Unicode const ch(rString[i]);
3421  if (!linguistic::IsControlChar(ch) || ch == '\r' || ch == '\n' || ch == '\t')
3422  {
3423  buf.append(ch);
3424  }
3425  else
3426  {
3427  SAL_INFO("sw.ww8", "filtering control character");
3428  }
3429  }
3430  return buf.makeStringAndClear();
3431 }
3432 
3433 } // namespace sw
3434 
3435 void SwWW8ImplReader::simpleAddTextToParagraph(const OUString& rAddString)
3436 {
3437  OUString const addString(sw::FilterControlChars(rAddString));
3438 
3439  if (addString.isEmpty())
3440  return;
3441 
3442 #if OSL_DEBUG_LEVEL > 1
3443  SAL_INFO("sw.ww8", "<addTextToParagraph>" << addString << "</addTextToParagraph>");
3444 #endif
3445 
3446  const SwContentNode *pCntNd = m_pPaM->GetContentNode();
3447  const SwTextNode* pNd = pCntNd ? pCntNd->GetTextNode() : nullptr;
3448 
3449  OSL_ENSURE(pNd, "What the hell, where's my text node");
3450 
3451  if (!pNd)
3452  return;
3453 
3454  const sal_Int32 nCharsLeft = SAL_MAX_INT32 - pNd->GetText().getLength();
3455  if (nCharsLeft > 0)
3456  {
3457  if (addString.getLength() <= nCharsLeft)
3458  {
3460  }
3461  else
3462  {
3463  m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, addString.copy(0, nCharsLeft));
3465  m_rDoc.getIDocumentContentOperations().InsertString(*m_pPaM, addString.copy(nCharsLeft));
3466  }
3467  }
3468  else
3469  {
3472  }
3473 
3474  m_bReadTable = false;
3475 }
3476 
3480 bool SwWW8ImplReader::ReadChars(WW8_CP& rPos, WW8_CP nNextAttr, tools::Long nTextEnd,
3481  tools::Long nCpOfs)
3482 {
3483  tools::Long nEnd = ( nNextAttr < nTextEnd ) ? nNextAttr : nTextEnd;
3484 
3485  if (m_bSymbol || m_bIgnoreText)
3486  {
3487  WW8_CP nRequested = nEnd - rPos;
3488  if (m_bSymbol) // Insert special chars
3489  {
3490  sal_uInt64 nMaxPossible = m_pStrm->remainingSize();
3491  if (o3tl::make_unsigned(nRequested) > nMaxPossible)
3492  {
3493  SAL_WARN("sw.ww8", "document claims to have more characters, " << nRequested << " than remaining, " << nMaxPossible);
3494  nRequested = nMaxPossible;
3495  }
3496 
3498  || m_cSymbol == '\r' || m_cSymbol == '\n' || m_cSymbol == '\t')
3499  {
3500  for (WW8_CP nCh = 0; nCh < nRequested; ++nCh)
3501  {
3503  }
3504  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_CHRATR_FONT);
3507  }
3508  }
3509  m_pStrm->SeekRel(nRequested);
3510  rPos = nEnd; // Ignore until attribute end
3511  return false;
3512  }
3513 
3514  while (true)
3515  {
3516  if (ReadPlainChars(rPos, nEnd, nCpOfs))
3517  return false; // Done
3518 
3519  bool bStartLine = ReadChar(rPos, nCpOfs);
3520  rPos++;
3521  if (m_bPgSecBreak || bStartLine || rPos == nEnd) // CR or Done
3522  {
3523  return bStartLine;
3524  }
3525  }
3526 }
3527 
3529 {
3530  bool bParaEndAdded = false;
3531  // #i1909# section/page breaks should not occur in tables, word
3532  // itself ignores them in this case.
3533  if (!m_nInTable)
3534  {
3535  bool IsTemp=true;
3536  SwTextNode* pTemp = m_pPaM->GetNode().GetTextNode();
3537  if (pTemp && pTemp->GetText().isEmpty()
3539  {
3540  IsTemp = false;
3543  }
3544 
3545  m_bPgSecBreak = true;
3546  m_xCtrlStck->KillUnlockedAttrs(*m_pPaM->GetPoint());
3547  /*
3548  If it's a 0x0c without a paragraph end before it, act like a
3549  paragraph end, but nevertheless, numbering (and perhaps other
3550  similar constructs) do not exist on the para.
3551  */
3552  if (!m_bWasParaEnd && IsTemp)
3553  {
3554  bParaEndAdded = true;
3555  if (0 >= m_pPaM->GetPoint()->nContent.GetIndex())
3556  {
3557  if (SwTextNode* pTextNode = m_pPaM->GetNode().GetTextNode())
3558  {
3559  pTextNode->SetAttr(
3561  }
3562  }
3563  }
3564  }
3565  return bParaEndAdded;
3566 }
3567 
3569 {
3570  bool bNewParaEnd = false;
3571  // Reset Unicode flag and correct FilePos if needed.
3572  // Note: Seek is not expensive, as we're checking inline whether or not
3573  // the correct FilePos has already been reached.
3574  std::size_t nRequestedPos = m_xSBase->WW8Cp2Fc(nCpOfs+nPosCp, &m_bIsUnicode);
3575  if (!checkSeek(*m_pStrm, nRequestedPos))
3576  return false;
3577 
3578  sal_uInt16 nWCharVal(0);
3579  if( m_bIsUnicode )
3580  m_pStrm->ReadUInt16( nWCharVal ); // unicode --> read 2 bytes
3581  else
3582  {
3583  sal_uInt8 nBCode(0);
3584  m_pStrm -> ReadUChar( nBCode ); // old code --> read 1 byte
3585  nWCharVal = nBCode;
3586  }
3587 
3588  sal_Unicode cInsert = '\x0';
3589  bool bParaMark = false;
3590 
3591  if ( 0xc != nWCharVal )
3592  m_bFirstParaOfPage = false;
3593 
3594  switch (nWCharVal)
3595  {
3596  case 0:
3597  {
3598  // Page number
3599  SwPageNumberField aField(
3600  static_cast<SwPageNumberFieldType*>(m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(
3603  }
3604  break;
3605  case 0xe:
3606  // if there is only one column word treats a column break like a pagebreak.
3608  bParaMark = HandlePageBreakChar();
3609  else if (!m_nInTable)
3610  {
3611  // Always insert a txtnode for a column break, e.g. ##
3612  SwContentNode *pCntNd=m_pPaM->GetContentNode();
3613  if (pCntNd!=nullptr && pCntNd->Len()>0) // if par is empty not break is needed
3616  }
3617  break;
3618  case 0x7:
3619  {
3620  bNewParaEnd = true;
3621  WW8PLCFxDesc* pPap = m_xPlcxMan->GetPap();
3622  //The last paragraph of each cell is terminated by a special
3623  //paragraph mark called a cell mark. Following the cell mark
3624  //that ends the last cell of a table row, the table row is
3625  //terminated by a special paragraph mark called a row mark
3626  //
3627  //So the 0x7 should be right at the end of the previous
3628  //range to be a real cell-end.
3629  if (pPap->nOrigStartPos == nPosCp+1 ||
3630  pPap->nOrigStartPos == WW8_CP_MAX)
3631  {
3632  TabCellEnd(); // Table cell/row end
3633  }
3634  else
3635  bParaMark = true;
3636  }
3637  break;
3638  case 0xf:
3639  if( !m_bSpec ) // "Satellite"
3640  cInsert = u'\x00a4';
3641  break;
3642  case 0x14:
3643  if( !m_bSpec ) // "Para End" char
3644  cInsert = u'\x00b5';
3645  //TODO: should this be U+00B6 PILCROW SIGN rather than
3646  // U+00B5 MICRO SIGN?
3647  break;
3648  case 0x15:
3649  if( !m_bSpec ) // Juristenparagraph
3650  {
3651  cp_set::iterator aItr = m_aTOXEndCps.find(static_cast<WW8_CP>(nPosCp));
3652  if (aItr == m_aTOXEndCps.end())
3653  cInsert = u'\x00a7';
3654  else
3655  m_aTOXEndCps.erase(aItr);
3656  }
3657  break;
3658  case 0x9:
3659  cInsert = '\x9'; // Tab
3660  break;
3661  case 0xb:
3662  cInsert = '\xa'; // Hard NewLine
3663  break;
3664  case 0xc:
3665  bParaMark = HandlePageBreakChar();
3666  break;
3667  case 0x1e: // Non-breaking hyphen
3669  break;
3670  case 0x1f: // Non-required hyphens
3672  break;
3673  case 0xa0: // Non-breaking spaces
3675  break;
3676  case 0x1:
3677  /*
3678  Current thinking is that if bObj is set then we have a
3679  straightforward "traditional" ole object, otherwise we have a
3680  graphic preview of an associated ole2 object (or a simple
3681  graphic of course)
3682 
3683  normally in the canvas field, the code is 0x8 0x1.
3684  in a special case, the code is 0x1 0x1, which yields a simple picture
3685  */
3686  {
3687  bool bReadObj = IsInlineEscherHack();
3688  if( bReadObj )
3689  {
3690  tools::Long nCurPos = m_pStrm->Tell();
3691  sal_uInt16 nWordCode(0);
3692 
3693  if( m_bIsUnicode )
3694  m_pStrm->ReadUInt16( nWordCode );
3695  else
3696  {
3697  sal_uInt8 nByteCode(0);
3698  m_pStrm->ReadUChar( nByteCode );
3699  nWordCode = nByteCode;
3700  }
3701  if( nWordCode == 0x1 )
3702  bReadObj = false;
3703  m_pStrm->Seek( nCurPos );
3704  }
3705  if( !bReadObj )
3706  {
3707  SwFrameFormat *pResult = nullptr;
3708  if (m_bObj)
3709  pResult = ImportOle();
3710  else if (m_bSpec)
3711  pResult = ImportGraf();
3712 
3713  // If we have a bad 0x1 insert a space instead.
3714  if (!pResult)
3715  {
3716  cInsert = ' ';
3717  OSL_ENSURE(!m_bObj && !m_bEmbeddObj && !m_nObjLocFc,
3718  "WW8: Please report this document, it may have a "
3719  "missing graphic");
3720  }
3721  else
3722  {
3723  // reset the flags.
3724  m_bObj = m_bEmbeddObj = false;
3725  m_nObjLocFc = 0;
3726  }
3727  }
3728  }
3729  break;
3730  case 0x8:
3731  if( !m_bObj )
3732  Read_GrafLayer( nPosCp );
3733  break;
3734  case 0xd:
3735  bNewParaEnd = bParaMark = true;
3736  if (m_nInTable > 1)
3737  {
3738  /*
3739  #i9666#/#i23161#
3740  Yes complex, if there is an entry in the undocumented PLCF
3741  which I believe to be a record of cell and row boundaries
3742  see if the magic bit which I believe to mean cell end is
3743  set. I also think btw that the third byte of the 4 byte
3744  value is the level of the cell
3745  */
3746  WW8PLCFspecial* pTest = m_xPlcxMan->GetMagicTables();
3747  if (pTest && pTest->SeekPosExact(nPosCp+1+nCpOfs) &&
3748  pTest->Where() == nPosCp+1+nCpOfs)
3749  {
3750  WW8_FC nPos;
3751  void *pData;
3752  sal_uInt32 nData = pTest->Get(nPos, pData) ? SVBT32ToUInt32(*static_cast<SVBT32*>(pData))
3753  : 0;
3754  if (nData & 0x2) // Might be how it works
3755  {
3756  TabCellEnd();
3757  bParaMark = false;
3758  }
3759  }
3760  // tdf#106799: We expect TTP marks to be also cell marks,
3761  // but sometimes sprmPFInnerTtp comes without sprmPFInnerTableCell
3762  else if (m_bWasTabCellEnd || m_bWasTabRowEnd)
3763  {
3764  TabCellEnd();
3765  bParaMark = false;
3766  }
3767  }
3768 
3769  m_bWasTabCellEnd = false;
3770 
3771  break; // line end
3772  case 0x5: // Annotation reference
3773  case 0x13:
3774  break;
3775  case 0x2: // TODO: Auto-Footnote-Number, should be replaced by SwWW8ImplReader::End_Footnote later
3776  if (!m_aFootnoteStack.empty())
3777  cInsert = '?';
3778  break;
3779  default:
3780  SAL_INFO( "sw.ww8.level2", "<unknownValue val=\"" << nWCharVal << "\">" );
3781  break;
3782  }
3783 
3784  if( '\x0' != cInsert )
3785  {
3786  OUString sInsert(cInsert);
3788  }
3789  if (!m_aApos.back()) // a para end in apo doesn't count
3790  m_bWasParaEnd = bNewParaEnd;
3791  return bParaMark;
3792 }
3793 
3795  bool* pStartAttr, bool bCallProcessSpecial)
3796 {
3797  sal_uInt16 nOldColl = m_nCurrentColl;
3798  m_nCurrentColl = m_xPlcxMan->GetColl();
3799 
3800  // Invalid Style-Id
3801  if (m_nCurrentColl >= m_vColl.size() || !m_vColl[m_nCurrentColl].m_pFormat || !m_vColl[m_nCurrentColl].m_bColl)
3802  {
3803  m_nCurrentColl = 0;
3804  m_bParaAutoBefore = false;
3805  m_bParaAutoAfter = false;
3806  }
3807  else
3808  {
3809  m_bParaAutoBefore = m_vColl[m_nCurrentColl].m_bParaAutoBefore;
3810  m_bParaAutoAfter = m_vColl[m_nCurrentColl].m_bParaAutoAfter;
3811  }
3812 
3813  if (nOldColl >= m_vColl.size())
3814  nOldColl = 0; // guess! TODO make sure this is what we want
3815 
3816  bool bTabRowEnd = false;
3817  if( pStartAttr && bCallProcessSpecial && !m_bInHyperlink )
3818  {
3819  bool bReSync;
3820  // Frame/Table/Autonumbering List Level
3821  bTabRowEnd = ProcessSpecial(bReSync, rRes.nCurrentCp + m_xPlcxMan->GetCpOfs());
3822  if( bReSync )
3823  *pStartAttr = m_xPlcxMan->Get( &rRes ); // Get Attribute-Pos again
3824  }
3825 
3826  if (!bTabRowEnd && StyleExists(m_nCurrentColl))
3827  {
3829  ChkToggleAttr(m_vColl[ nOldColl ].m_n81Flags, m_vColl[ m_nCurrentColl ].m_n81Flags);
3830  ChkToggleBiDiAttr(m_vColl[nOldColl].m_n81BiDiFlags,
3831  m_vColl[m_nCurrentColl].m_n81BiDiFlags);
3832  }
3833 }
3834 
3835 tools::Long SwWW8ImplReader::ReadTextAttr(WW8_CP& rTextPos, tools::Long nTextEnd, bool& rbStartLine, int nDepthGuard)
3836 {
3837  tools::Long nSkipChars = 0;
3838  WW8PLCFManResult aRes;
3839 
3840  OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode");
3841  bool bStartAttr = m_xPlcxMan->Get(&aRes); // Get Attribute position again
3842  aRes.nCurrentCp = rTextPos; // Current Cp position
3843 
3844  bool bNewSection = (aRes.nFlags & MAN_MASK_NEW_SEP) && !m_bIgnoreText;
3845  if ( bNewSection ) // New Section
3846  {
3847  OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode");
3848  // Create PageDesc and fill it
3849  m_aSectionManager.CreateSep(rTextPos);
3850  // -> 0xc was a Sectionbreak, but not a Pagebreak;
3851  // Create PageDesc and fill it
3852  m_bPgSecBreak = false;
3853  OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode");
3854  }
3855 
3856  // New paragraph over Plcx.Fkp.papx
3857  if ( (aRes.nFlags & MAN_MASK_NEW_PAP)|| rbStartLine )
3858  {
3859  ProcessCurrentCollChange( aRes, &bStartAttr,
3861  !m_bIgnoreText );
3862  rbStartLine = false;
3863  }
3864 
3865  // position of last CP that's to be ignored
3866  tools::Long nSkipPos = -1;
3867 
3868  if( 0 < aRes.nSprmId ) // Ignore empty Attrs
3869  {
3870  if( ( eFTN > aRes.nSprmId ) || ( 0x0800 <= aRes.nSprmId ) )
3871  {
3872  if( bStartAttr ) // WW attributes
3873  {
3874  if( aRes.nMemLen >= 0 )
3875  ImportSprm(aRes.pMemPos, aRes.nMemLen, aRes.nSprmId);
3876  }
3877  else
3878  EndSprm( aRes.nSprmId ); // Switch off Attr
3879  }
3880  else if( aRes.nSprmId < 0x800 ) // Own helper attributes
3881  {
3882  if (bStartAttr)
3883  {
3884  nSkipChars = ImportExtSprm(&aRes);
3885  if (
3886  (aRes.nSprmId == eFTN) || (aRes.nSprmId == eEDN) ||
3887  (aRes.nSprmId == eFLD) || (aRes.nSprmId == eAND)
3888  )
3889  {
3890  WW8_CP nMaxLegalSkip = nTextEnd - rTextPos;
3891  // Skip Field/Footnote-/End-Note here
3892  rTextPos += std::min<WW8_CP>(nSkipChars, nMaxLegalSkip);
3893  nSkipPos = rTextPos-1;
3894  }
3895  }
3896  else
3897  EndExtSprm( aRes.nSprmId );
3898  }
3899  }
3900 
3901  sal_Int32 nRequestedPos = m_xSBase->WW8Cp2Fc(m_xPlcxMan->GetCpOfs() + rTextPos, &m_bIsUnicode);
3902  bool bValidPos = checkSeek(*m_pStrm, nRequestedPos);
3903  SAL_WARN_IF(!bValidPos, "sw.ww8", "Document claimed to have text at an invalid position, skip attributes for region");
3904 
3905  // Find next Attr position (and Skip attributes of field contents if needed)
3906  if (nSkipChars && !m_bIgnoreText)
3907  m_xCtrlStck->MarkAllAttrsOld();
3908  bool bOldIgnoreText = m_bIgnoreText;
3909  m_bIgnoreText = true;
3910  sal_uInt16 nOldColl = m_nCurrentColl;
3911  bool bDoPlcxManPlusPLus = true;
3912  tools::Long nNext;
3913  do
3914  {
3915  if( bDoPlcxManPlusPLus )
3916  m_xPlcxMan->advance();
3917  nNext = bValidPos ? m_xPlcxMan->Where() : nTextEnd;
3918 
3920  m_pPostProcessAttrsInfo->mnCpStart == nNext)
3921  {
3922  m_pPostProcessAttrsInfo->mbCopy = true;
3923  }
3924 
3925  if( (0 <= nNext) && (nSkipPos >= nNext) )
3926  {
3927  if (nDepthGuard >= 1024)
3928  {
3929  SAL_WARN("sw.ww8", "ReadTextAttr hit recursion limit");
3930  nNext = nTextEnd;
3931  }
3932  else
3933  nNext = ReadTextAttr(rTextPos, nTextEnd, rbStartLine, nDepthGuard + 1);
3934  bDoPlcxManPlusPLus = false;
3935  m_bIgnoreText = true;
3936  }
3937 
3939  nNext > m_pPostProcessAttrsInfo->mnCpEnd)
3940  {
3941  m_pPostProcessAttrsInfo->mbCopy = false;
3942  }
3943  }
3944  while( nSkipPos >= nNext );
3945  m_bIgnoreText = bOldIgnoreText;
3946  if( nSkipChars )
3947  {
3948  m_xCtrlStck->KillUnlockedAttrs( *m_pPaM->GetPoint() );
3949  if( nOldColl != m_xPlcxMan->GetColl() )
3950  ProcessCurrentCollChange(aRes, nullptr, false);
3951  }
3952 
3953  return nNext;
3954 }
3955 
3956 void SwWW8ImplReader::ReadAttrs(WW8_CP& rTextPos, WW8_CP& rNext, tools::Long nTextEnd, bool& rbStartLine)
3957 {
3958  // Do we have attributes?
3959  if( rTextPos >= rNext )
3960  {
3961  do
3962  {
3963  rNext = ReadTextAttr(rTextPos, nTextEnd, rbStartLine);
3964  if (rTextPos == rNext && rTextPos >= nTextEnd)
3965  break;
3966  }
3967  while( rTextPos >= rNext );
3968 
3969  }
3970  else if ( rbStartLine )
3971  {
3972  /* No attributes, but still a new line.
3973  * If a line ends with a line break and paragraph attributes or paragraph templates
3974  * do NOT change the line end was not added to the Plcx.Fkp.papx i.e. (nFlags & MAN_MASK_NEW_PAP)
3975  * is false.
3976  * Due to this we need to set the template here as a kind of special treatment.
3977  */
3978  if (!m_bCpxStyle && m_nCurrentColl < m_vColl.size())
3980  rbStartLine = false;
3981  }
3982 }
3983 
3990 {
3991  // If there are any unclosed sprms then copy them to
3992  // another stack and close the ones that must be closed
3993  std::stack<sal_uInt16> aStack;
3994  m_xPlcxMan->TransferOpenSprms(aStack);
3995 
3996  while (!aStack.empty())
3997  {
3998  sal_uInt16 nSprmId = aStack.top();
3999  if ((0 < nSprmId) && (( eFTN > nSprmId) || (0x0800 <= nSprmId)))
4000  EndSprm(nSprmId);
4001  aStack.pop();
4002  }
4003 
4004  EndSpecial();
4005 }
4006 
4007 bool SwWW8ImplReader::ReadText(WW8_CP nStartCp, WW8_CP nTextLen, ManTypes nType)
4008 {
4009  bool bJoined=false;
4010 
4011  bool bStartLine = true;
4012  short nCrCount = 0;
4013  short nDistance = 0;
4014 
4015  m_bWasParaEnd = false;
4016  m_nCurrentColl = 0;
4017  m_xCurrentItemSet.reset();
4018  m_nCharFormat = -1;
4019  m_bSpec = false;
4020  m_bPgSecBreak = false;
4021 
4022  m_xPlcxMan = std::make_shared<WW8PLCFMan>(m_xSBase.get(), nType, nStartCp);
4023  tools::Long nCpOfs = m_xPlcxMan->GetCpOfs(); // Offset for Header/Footer, Footnote
4024 
4025  WW8_CP nNext = m_xPlcxMan->Where();
4026  m_pPreviousNode = nullptr;
4027  sal_uInt8 nDropLines = 0;
4028  SwCharFormat* pNewSwCharFormat = nullptr;
4029  const SwCharFormat* pFormat = nullptr;
4030 
4031  bool bValidPos = checkSeek(*m_pStrm, m_xSBase->WW8Cp2Fc(nStartCp + nCpOfs, &m_bIsUnicode));
4032  if (!bValidPos)
4033  return false;
4034 
4035  WW8_CP l = nStartCp;
4036  const WW8_CP nMaxPossible = WW8_CP_MAX-nStartCp;
4037  if (nTextLen > nMaxPossible)
4038  {
4039  SAL_WARN_IF(nTextLen > nMaxPossible, "sw.ww8", "TextLen too long");
4040  nTextLen = nMaxPossible;
4041  }
4042  WW8_CP nTextEnd = nStartCp+nTextLen;
4043  while (l < nTextEnd)
4044  {
4045  ReadAttrs( l, nNext, nTextEnd, bStartLine );// Takes SectionBreaks into account, too
4046  OSL_ENSURE(m_pPaM->GetNode().GetTextNode(), "Missing txtnode");
4047 
4048  if (m_pPostProcessAttrsInfo != nullptr)
4049  PostProcessAttrs();
4050 
4051  if (l >= nTextEnd)
4052  break;
4053 
4054  bStartLine = ReadChars(l, nNext, nTextEnd, nCpOfs);
4055 
4056  // If the previous paragraph was a dropcap then do not
4057  // create a new txtnode and join the two paragraphs together
4058  if (bStartLine && !m_pPreviousNode) // Line end
4059  {
4060  bool bSplit = true;
4062  {
4063  m_bCareFirstParaEndInToc = false;
4064  if (m_pPaM->End() && m_pPaM->End()->nNode.GetNode().GetTextNode() && m_pPaM->End()->nNode.GetNode().GetTextNode()->Len() == 0)
4065  bSplit = false;
4066  }
4068  {
4069  m_bCareLastParaEndInToc = false;
4070  if (m_pPaM->End() && m_pPaM->End()->nNode.GetNode().GetTextNode() && m_pPaM->End()->nNode.GetNode().GetTextNode()->Len() == 0)
4071  bSplit = false;
4072  }
4073  if (bSplit)
4074  {
4076  }
4077  }
4078 
4079  if (m_pPreviousNode && bStartLine)
4080  {
4081  SwTextNode* pEndNd = m_pPaM->GetNode().GetTextNode();
4082  const sal_Int32 nDropCapLen = m_pPreviousNode->GetText().getLength();
4083 
4084  // Need to reset the font size and text position for the dropcap
4085  {
4086  SwPaM aTmp(*pEndNd, 0, *pEndNd, nDropCapLen+1);
4087  m_xCtrlStck->Delete(aTmp);
4088  }
4089 
4090  // Get the default document dropcap which we can use as our template
4091  const SwFormatDrop* defaultDrop =
4092  static_cast<const SwFormatDrop*>( GetFormatAttr(RES_PARATR_DROP));
4093  SwFormatDrop aDrop(*defaultDrop);
4094 
4095  aDrop.GetLines() = nDropLines;
4096  aDrop.GetDistance() = nDistance;
4097  aDrop.GetChars() = writer_cast<sal_uInt8>(nDropCapLen);
4098  // Word has no concept of a "whole word dropcap"
4099  aDrop.GetWholeWord() = false;
4100 
4101  if (pFormat)
4102  aDrop.SetCharFormat(const_cast<SwCharFormat*>(pFormat));
4103  else if(pNewSwCharFormat)
4104  aDrop.SetCharFormat(pNewSwCharFormat);
4105 
4106  SwPosition aStart(*pEndNd);
4107  m_xCtrlStck->NewAttr(aStart, aDrop);
4108  m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_PARATR_DROP);
4109  m_pPreviousNode = nullptr;
4110  }
4111  else if (m_bDropCap)
4112  {
4113  // If we have found a dropcap store the textnode
4115 
4116  SprmResult aDCS;
4117  if (m_bVer67)
4118  aDCS = m_xPlcxMan->GetPapPLCF()->HasSprm(46);
4119  else
4120  aDCS = m_xPlcxMan->GetPapPLCF()->HasSprm(0x442C);
4121 
4122  if (aDCS.pSprm && aDCS.nRemainingData >= 1)
4123  nDropLines = (*aDCS.pSprm) >> 3;
4124  else // There is no Drop Cap Specifier hence no dropcap
4125  m_pPreviousNode = nullptr;
4126 
4127  SprmResult aDistance = m_xPlcxMan->GetPapPLCF()->HasSprm(0x842F);
4128  if (aDistance.pSprm && aDistance.nRemainingData >= 2)
4129  nDistance = SVBT16ToUInt16(aDistance.pSprm);
4130  else
4131  nDistance = 0;
4132 
4133  const SwFormatCharFormat *pSwFormatCharFormat = nullptr;
4134 
4135  if (m_xCurrentItemSet)
4136  pSwFormatCharFormat = &(ItemGet<SwFormatCharFormat>(*m_xCurrentItemSet, RES_TXTATR_CHARFMT));
4137 
4138  if (pSwFormatCharFormat)
4139  pFormat = pSwFormatCharFormat->GetCharFormat();
4140 
4141  if (m_xCurrentItemSet && !pFormat)
4142  {
4143  OUString sPrefix = "WW8Dropcap" + OUString::number(m_nDropCap++);
4144  pNewSwCharFormat = m_rDoc.MakeCharFormat(sPrefix, m_rDoc.GetDfltCharFormat());
4145  m_xCurrentItemSet->ClearItem(RES_CHRATR_ESCAPEMENT);
4146  pNewSwCharFormat->SetFormatAttr(*m_xCurrentItemSet);
4147  }
4148 
4149  m_xCurrentItemSet.reset();
4150  m_bDropCap=false;
4151  }
4152 
4153  if (bStartLine || m_bWasTabRowEnd)
4154  {
4155  // Call all 64 CRs; not for Header and the like
4156  if ((nCrCount++ & 0x40) == 0 && nType == MAN_MAINTEXT && l <= nTextLen)
4157  {
4158  if (nTextLen < WW8_CP_MAX/100)
4159  m_nProgress = o3tl::narrowing<sal_uInt16>(l * 100 / nTextLen);
4160  else
4161  m_nProgress = o3tl::narrowing<sal_uInt16>(l / nTextLen * 100);
4162  m_xProgress->Update(m_nProgress); // Update
4163  }
4164  }
4165 
4166  // If we have encountered a 0x0c which indicates either section of
4167  // pagebreak then look it up to see if it is a section break, and
4168  // if it is not then insert a page break. If it is a section break
4169  // it will be handled as such in the ReadAttrs of the next loop
4170  if (m_bPgSecBreak)
4171  {
4172  // We need only to see if a section is ending at this cp,
4173  // the plcf will already be sitting on the correct location
4174  // if it is there.
4175  WW8PLCFxDesc aTemp;
4176  aTemp.nStartPos = aTemp.nEndPos = WW8_CP_MAX;
4177  if (m_xPlcxMan->GetSepPLCF())
4178  m_xPlcxMan->GetSepPLCF()->GetSprms(&aTemp);
4179  if ((aTemp.nStartPos != l) && (aTemp.nEndPos != l))
4180  {
4181  // #i39251# - insert text node for page break, if no one inserted.
4182  // #i43118# - refine condition: the anchor
4183  // control stack has to have entries, otherwise it's not needed
4184  // to insert a text node.
4185  if (!bStartLine && !m_xAnchorStck->empty())
4186  {
4188  }
4190  SvxFormatBreakItem(SvxBreak::PageBefore, RES_BREAK));
4191  m_bFirstParaOfPage = true;
4192  m_bPgSecBreak = false;
4193  }
4194  }
4195  }
4196 
4197  m_pPreviousNode = nullptr;
4198 
4199  if (m_pPaM->GetPoint()->nContent.GetIndex())
4201 
4202  if (!m_bInHyperlink)
4203  bJoined = JoinNode(*m_pPaM);
4204 
4205  CloseAttrEnds();
4206 
4207  m_xPlcxMan.reset();
4208  return bJoined;
4209 }
4210 
4212  SvStream* pSt, SwDoc& rD, const OUString& rBaseURL, bool bNewDoc, bool bSkipImages, SwPosition const &rPos)
4213  : m_pDocShell(rD.GetDocShell())
4214  , m_pStg(pStorage)
4215  , m_pStrm(pSt)
4216  , m_pTableStream(nullptr)
4217  , m_pDataStream(nullptr)
4218  , m_rDoc(rD)
4219  , m_pPaM(nullptr)
4220  , m_aSectionManager(*this)
4221  , m_aExtraneousParas(rD)
4222  , m_aInsertedTables(rD)
4223  , m_aSectionNameGenerator(rD, "WW")
4224  , m_aGrfNameGenerator(bNewDoc, OUString('G'))
4225  , m_aParaStyleMapper(rD)
4226  , m_aCharStyleMapper(rD)
4227  , m_pFlyFormatOfJustInsertedGraphic(nullptr)
4228  , m_pPreviousNumPaM(nullptr)
4229  , m_pPrevNumRule(nullptr)
4230  , m_aTextNodesHavingFirstLineOfstSet()
4231  , m_aTextNodesHavingLeftIndentSet()
4232  , m_pCurrentColl(nullptr)
4233  , m_pDfltTextFormatColl(nullptr)
4234  , m_pStandardFormatColl(nullptr)
4235  , m_pDrawModel(nullptr)
4236  , m_pDrawPg(nullptr)
4237  , m_pNumFieldType(nullptr)
4238  , m_sBaseURL(rBaseURL)
4239  , m_nIniFlags(0)
4240  , m_nIniFlags1(0)
4241  , m_nFieldFlags(0)
4242  , m_bRegardHindiDigits( false )
4243  , m_bDrawCpOValid( false )
4244  , m_nDrawCpO(0)
4245  , m_nPicLocFc(0)
4246  , m_nObjLocFc(0)
4247  , m_nIniFlyDx(0)
4248  , m_nIniFlyDy(0)
4249  , m_eTextCharSet(RTL_TEXTENCODING_ASCII_US)
4250  , m_eStructCharSet(RTL_TEXTENCODING_ASCII_US)
4251  , m_eHardCharSet(RTL_TEXTENCODING_DONTKNOW)
4252  , m_nProgress(0)
4253  , m_nCurrentColl(0)
4254  , m_nFieldNum(0)
4255  , m_nLFOPosition(USHRT_MAX)
4256  , m_nCharFormat(0)
4257  , m_nDrawXOfs(0)
4258  , m_nDrawYOfs(0)
4259  , m_nDrawXOfs2(0)
4260  , m_nDrawYOfs2(0)
4261  , m_cSymbol(0)
4262  , m_nWantedVersion(nVersionPara)
4263  , m_nSwNumLevel(0xff)
4264  , m_nWwNumType(0xff)
4265  , m_pChosenWW8OutlineStyle(nullptr)
4266  , m_nListLevel(MAXLEVEL)
4267  , m_bNewDoc(bNewDoc)
4268  , m_bSkipImages(bSkipImages)
4269  , m_bReadNoTable(false)
4270  , m_bPgSecBreak(false)
4271  , m_bSpec(false)
4272  , m_bObj(false)
4273  , m_bTxbxFlySection(false)
4274  , m_bHasBorder(false)
4275  , m_bSymbol(false)
4276  , m_bIgnoreText(false)
4277  , m_nInTable(0)
4278  , m_bWasTabRowEnd(false)
4279  , m_bWasTabCellEnd(false)
4280  , m_bAnl(false)
4281  , m_bHdFtFootnoteEdn(false)
4282  , m_bFootnoteEdn(false)
4283  , m_bIsHeader(false)
4284  , m_bIsFooter(false)
4285  , m_bIsUnicode(false)
4286  , m_bCpxStyle(false)
4287  , m_bStyNormal(false)
4288  , m_bWWBugNormal(false)
4289  , m_bNoAttrImport(false)
4290  , m_bInHyperlink(false)
4291  , m_bWasParaEnd(false)
4292  , m_bVer67(false)
4293  , m_bVer6(false)
4294  , m_bVer7(false)
4295  , m_bVer8(false)
4296  , m_bEmbeddObj(false)
4297  , m_bCurrentAND_fNumberAcross(false)
4298  , m_bNoLnNumYet(true)
4299  , m_bFirstPara(true)
4300  , m_bFirstParaOfPage(false)
4301  , m_bParaAutoBefore(false)
4302  , m_bParaAutoAfter(false)
4303  , m_bDropCap(false)
4304  , m_nDropCap(0)
4305  , m_bBidi(false)
4306  , m_bReadTable(false)
4307  , m_bLoadingTOXCache(false)
4308  , m_nEmbeddedTOXLevel(0)
4309  , m_bLoadingTOXHyperlink(false)
4310  , m_pPreviousNode(nullptr)
4311  , m_bCareFirstParaEndInToc(false)
4312  , m_bCareLastParaEndInToc(false)
4313  , m_aTOXEndCps()
4314  , m_bNotifyMacroEventRead(false)
4315  , m_bFuzzing(utl::ConfigManager::IsFuzzing())
4316 {
4317  m_pStrm->SetEndian( SvStreamEndian::LITTLE );
4318  m_aApos.push_back(false);
4319 
4321 }
4322 
4324 {
4325 }
4326 
4327 void SwWW8ImplReader::DeleteStack(std::unique_ptr<SwFltControlStack> pStck)
4328 {
4329  if( pStck )
4330  {
4331  pStck->SetAttr( *m_pPaM->GetPoint(), 0, false);
4332  pStck->SetAttr( *m_pPaM->GetPoint(), 0, false);
4333  }
4334  else
4335  {
4336  OSL_ENSURE( false, "WW stack already deleted" );
4337  }
4338 }
4339 
4341  bool bIgnoreCols)
4342 {
4343  SwPageDesc &rPage = *rSection.mpPage;
4344 
4345  SetNumberingType(rSection, rPage);
4346 
4347  SwFrameFormat &rFormat = rPage.GetMaster();
4348 
4349  if(mrReader.m_xWDop->fUseBackGroundInAllmodes) // #i56806# Make sure mrReader is initialized
4351 
4352  if (mrReader.m_xWDop->fUseBackGroundInAllmodes && mrReader.m_xMSDffManager)
4353  {
4354  tools::Rectangle aRect(0, 0, 100, 100); // A dummy, we don't care about the size
4355  SvxMSDffImportData aData(aRect);
4356  SdrObject* pObject = nullptr;
4357  if (mrReader.m_xMSDffManager->GetShape(0x401, pObject, aData) && !aData.empty())
4358  {
4359  // Only handle shape if it is a background shape
4360  if (aData.begin()->get()->nFlags & ShapeFlag::Background)
4361  {
4362  SfxItemSet aSet(rFormat.GetDoc()->GetAttrPool(),
4363  svl::Items<RES_BACKGROUND, RES_BACKGROUND,XATTR_START, XATTR_END>);
4366  if ( aSet.HasItem(RES_BACKGROUND) )
4367  rFormat.SetFormatAttr(aSet.Get(RES_BACKGROUND));
4368  else
4369  rFormat.SetFormatAttr(aSet);
4370  }
4371  }
4372  SdrObject::Free(pObject);
4373  }
4374  wwULSpaceData aULData;
4375  GetPageULData(rSection, aULData);
4376  SetPageULSpaceItems(rFormat, aULData, rSection);
4377 
4378  rPage.SetVerticalAdjustment( rSection.mnVerticalAdjustment );
4379 
4380  SetPage(rPage, rFormat, rSection, bIgnoreCols);
4381 
4382  if (!(rSection.maSep.pgbApplyTo & 1))
4383  SwWW8ImplReader::SetPageBorder(rFormat, rSection);
4384  if (!(rSection.maSep.pgbApplyTo & 2))
4386 
4387  mrReader.SetDocumentGrid(rFormat, rSection);
4388 }
4389 
4391 {
4392  bool bMirror = mrReader.m_xWDop->fMirrorMargins ||
4393  mrReader.m_xWDop->doptypography.m_f2on1;
4394 
4395  UseOnPage eUseBase = bMirror ? UseOnPage::Mirror : UseOnPage::All;
4396  UseOnPage eUse = eUseBase;
4397  if (!mrReader.m_xWDop->fFacingPages)
4399  if (!rSection.HasTitlePage())
4400  eUse |= UseOnPage::FirstShare;
4401 
4402  OSL_ENSURE(rSection.mpPage, "Makes no sense to call me with no pages to set");
4403  if (rSection.mpPage)
4404  rSection.mpPage->WriteUseOn(eUse);
4405 }
4406 
4411 static void GiveNodePageDesc(SwNodeIndex const &rIdx, const SwFormatPageDesc &rPgDesc,
4412  SwDoc &rDoc)
4413 {
4414  /*
4415  If it's a table here, apply the pagebreak to the table
4416  properties, otherwise we add it to the para at this
4417  position
4418  */
4419  if (rIdx.GetNode().IsTableNode())
4420  {
4421  SwTable& rTable =
4422  rIdx.GetNode().GetTableNode()->GetTable();
4423  SwFrameFormat* pApply = rTable.GetFrameFormat();
4424  OSL_ENSURE(pApply, "impossible");
4425  if (pApply)
4426  pApply->SetFormatAttr(rPgDesc);
4427  }
4428  else
4429  {
4430  SwPosition aPamStart(rIdx);
4431  aPamStart.nContent.Assign(
4432  rIdx.GetNode().GetContentNode(), 0);
4433  SwPaM aPage(aPamStart);
4434 
4435  rDoc.getIDocumentContentOperations().InsertPoolItem(aPage, rPgDesc);
4436  }
4437 }
4438 
4443  mySegIter const &rStart, bool bIgnoreCols)
4444 {
4445  if (mrReader.m_bNewDoc && rIter == rStart)
4446  {
4447  rIter->mpPage =
4449  }
4450  else
4451  {
4452  rIter->mpPage = mrReader.m_rDoc.MakePageDesc(
4454  nullptr, false);
4455  }
4456  OSL_ENSURE(rIter->mpPage, "no page!");
4457  if (!rIter->mpPage)
4458  return SwFormatPageDesc();
4459 
4460  // Set page before hd/ft
4461  const wwSection *pPrevious = nullptr;
4462  if (rIter != rStart)
4463  pPrevious = &(*(rIter-1));
4464  SetHdFt(*rIter, std::distance(rStart, rIter), pPrevious);
4465  SetUseOn(*rIter);
4466 
4467  // Set hd/ft after set page
4468  SetSegmentToPageDesc(*rIter, bIgnoreCols);
4469 
4470  SwFormatPageDesc aRet(rIter->mpPage);
4471 
4472  rIter->mpPage->SetFollow(rIter->mpPage);
4473 
4474  if (rIter->PageRestartNo())
4475  aRet.SetNumOffset(rIter->PageStartAt());
4476 
4477  ++mnDesc;
4478  return aRet;
4479 }
4480 
4482 {
4483  mySegIter aEnd = maSegments.end();
4484  mySegIter aStart = maSegments.begin();
4485  for (mySegIter aIter = aStart; aIter != aEnd; ++aIter)
4486  {
4487  // If the section is of type "New column" (0x01), then simply insert a column break.
4488  // But only if there actually are columns on the page, otherwise a column break
4489  // seems to be handled like a page break by MSO.
4490  if ( aIter->maSep.bkc == 1 && aIter->maSep.ccolM1 > 0 )
4491  {
4492  SwPaM start( aIter->maStart );
4494  continue;
4495  }
4496 
4497  mySegIter aNext = aIter+1;
4498  mySegIter aPrev = (aIter == aStart) ? aIter : aIter-1;
4499 
4500  // If two following sections are different in following properties, Word will interpret a continuous
4501  // section break between them as if it was a section break next page.
4502  bool bThisAndPreviousAreCompatible = ((aIter->GetPageWidth() == aPrev->GetPageWidth()) &&
4503  (aIter->GetPageHeight() == aPrev->GetPageHeight()) && (aIter->IsLandScape() == aPrev->IsLandScape()));
4504 
4505  bool bInsertSection = (aIter != aStart) && aIter->IsContinuous() && bThisAndPreviousAreCompatible;
4506  bool bInsertPageDesc = !bInsertSection;
4507  // HACK Force new pagedesc if left/right margins change, otherwise e.g. floating tables may be anchored improperly.
4508  if( aIter->maSep.dxaLeft != aPrev->maSep.dxaLeft || aIter->maSep.dxaRight != aPrev->maSep.dxaRight )
4509  bInsertPageDesc = true;
4510  bool bProtected = SectionIsProtected(*aIter); // do we really need this ?? I guess I have a different logic in editshell which disables this...
4511 
4512  if (bInsertPageDesc)
4513  {
4514  /*
4515  If a cont section follows this section then we won't be
4516  creating a page desc with 2+ cols as we cannot host a one
4517  col section in a 2+ col pagedesc and make it look like
4518  word. But if the current section actually has columns then
4519  we are forced to insert a section here as well as a page
4520  descriptor.
4521  */
4522 
4523  bool bIgnoreCols = bInsertSection;
4524  bool bThisAndNextAreCompatible = (aNext == aEnd) ||
4525  ((aIter->GetPageWidth() == aNext->GetPageWidth()) &&
4526  (aIter->GetPageHeight() == aNext->GetPageHeight()) &&
4527  (aIter->IsLandScape() == aNext->IsLandScape()));
4528 
4529  if ((aNext != aEnd && aNext->IsContinuous() && bThisAndNextAreCompatible) || bProtected)
4530  {
4531  bIgnoreCols = true;
4532  if ((aIter->NoCols() > 1) || bProtected)
4533  bInsertSection = true;
4534  }
4535 
4536  SwFormatPageDesc aDesc(SetSwFormatPageDesc(aIter, aStart, bIgnoreCols));
4537  if (!aDesc.GetPageDesc())
4538  continue;
4539 
4540  // special case handling for odd/even section break
4541  // a) as before create a new page style for the section break
4542  // b) set Layout of generated page style to right/left ( according
4543  // to section break odd/even )
4544  // c) create a new style to follow the break page style
4545  if ( aIter->maSep.bkc == 3 || aIter->maSep.bkc == 4 )
4546  {
4547  // SetSwFormatPageDesc calls some methods that could
4548  // modify aIter (e.g. wwSection ).
4549  // Since we call SetSwFormatPageDesc below to generate the
4550  // 'Following' style of the Break style, it is safer
4551  // to take a copy of the contents of aIter.
4552  wwSection aTmpSection = *aIter;
4553  // create a new following page style
4554  SwFormatPageDesc aFollow(SetSwFormatPageDesc(aIter, aStart, bIgnoreCols));
4555  // restore any contents of aIter trashed by SetSwFormatPageDesc
4556  *aIter = aTmpSection;
4557 
4558  // Handle the section break
4559  UseOnPage eUseOnPage = UseOnPage::Left;
4560  if ( aIter->maSep.bkc == 4 ) // Odd ( right ) Section break
4561  eUseOnPage = UseOnPage::Right;
4562 
4563  // Keep the share flags.
4564  aDesc.GetPageDesc()->SetUseOn( eUseOnPage );
4565  aDesc.GetPageDesc()->SetFollow( aFollow.GetPageDesc() );
4566  }
4567 
4568  // Avoid setting the page style at the very beginning since it is always the default style anyway,
4569  // unless it is needed to specify a page number.
4570  if (aIter != aStart || aDesc.GetNumOffset())
4571  GiveNodePageDesc(aIter->maStart, aDesc, mrReader.m_rDoc);
4572  }
4573 
4574  SwTextNode* pTextNd = nullptr;
4575  if (bInsertSection)
4576  {
4577  // Start getting the bounds of this section
4578  SwPaM aSectPaM(*mrReader.m_pPaM, mrReader.m_pPaM);
4579  SwNodeIndex aAnchor(aSectPaM.GetPoint()->nNode);
4580  if (aNext != aEnd)
4581  {
4582  aAnchor = aNext->maStart;
4583  aSectPaM.GetPoint()->nNode = aAnchor;
4584  aSectPaM.GetPoint()->nContent.Assign(
4585  aNext->maStart.GetNode().GetContentNode(), 0);
4586  aSectPaM.Move(fnMoveBackward);
4587  }
4588 
4589  const SwPosition* pPos = aSectPaM.GetPoint();
4590  SwTextNode const*const pSttNd = pPos->nNode.GetNode().GetTextNode();
4591  const SwTableNode* pTableNd = pSttNd ? pSttNd->FindTableNode() : nullptr;
4592  if (pTableNd)
4593  {
4594  pTextNd =
4597 
4598  aSectPaM.GetPoint()->nNode.Assign(*pTextNd);
4599  aSectPaM.GetPoint()->nContent.Assign(
4600  aSectPaM.GetContentNode(), 0);
4601  }
4602 
4603  aSectPaM.SetMark();
4604 
4605  aSectPaM.GetPoint()->nNode = aIter->maStart;
4606  aSectPaM.GetPoint()->nContent.Assign(
4607  aSectPaM.GetContentNode(), 0);
4608 
4609  bool bHasOwnHdFt = false;
4610  /*
4611  In this nightmare scenario the continuous section has its own
4612  headers and footers so we will try and find a hard page break
4613  between here and the end of the section and put the headers and
4614  footers there.
4615  */
4616  if (!bInsertPageDesc)
4617  {
4618  bHasOwnHdFt =
4620  aIter->maSep.grpfIhdt & ~(WW8_HEADER_FIRST | WW8_FOOTER_FIRST),
4621  aIter->maSep.grpfIhdt, std::distance(aStart, aIter)
4622  );
4623  }
4624  if (bHasOwnHdFt)
4625  {
4626  // #i40766# Need to cache the page descriptor in case there is
4627  // no page break in the section
4628  SwPageDesc *pOrig = aIter->mpPage;
4629  bool bFailed = true;
4630  SwFormatPageDesc aDesc(SetSwFormatPageDesc(aIter, aStart, true));
4631  if (aDesc.GetPageDesc())
4632  {
4633  sal_uLong nStart = aSectPaM.Start()->nNode.GetIndex();
4634  sal_uLong nEnd = aSectPaM.End()->nNode.GetIndex();
4635  for(; nStart <= nEnd; ++nStart)
4636  {
4637  SwNode* pNode = mrReader.m_rDoc.GetNodes()[nStart];
4638  if (!pNode)
4639  continue;
4640  if (sw::util::HasPageBreak(*pNode))
4641  {
4642  SwNodeIndex aIdx(*pNode);
4643  GiveNodePageDesc(aIdx, aDesc, mrReader.m_rDoc);
4644  bFailed = false;
4645  break;
4646  }
4647  }
4648  }
4649  if(bFailed)
4650  {
4651  aIter->mpPage = pOrig;
4652  }
4653  }
4654 
4655  // End getting the bounds of this section, quite a job eh?
4656  SwSectionFormat *pRet = InsertSection(aSectPaM, *aIter);
4657  // The last section if continuous is always unbalanced
4658  if (pRet)
4659  {
4660  // Set the columns to be UnBalanced if that compatibility option is set
4661  if (mrReader.m_xWDop->fNoColumnBalance)
4663  else
4664  {
4665  // Otherwise set to unbalanced if the following section is
4666  // not continuous, (which also means that the last section
4667  // is unbalanced)
4668  if (aNext == aEnd || !aNext->IsContinuous())
4670  }
4671  }
4672  }
4673 
4674  if (pTextNd)
4675  {
4676  SwNodeIndex aIdx(*pTextNd);
4677  SwPaM aTest(aIdx);
4679  pTextNd = nullptr;
4680  }
4681  }
4682 }
4683 
4685 {
4686  auto aEnd = m_aTextNodes.rend();
4687  for (auto aI = m_aTextNodes.rbegin(); aI != aEnd; ++aI)
4688  {
4689  SwTextNode *pTextNode = *aI;
4690  SwNodeIndex aIdx(*pTextNode);
4691  SwPaM aTest(aIdx);
4693  }
4694  m_aTextNodes.clear();
4695 }
4696 
4698 {
4699  if (!m_xWwFib->m_lcbCmds)
4700  return;
4701 
4702  bool bValidPos = checkSeek(*m_pTableStream, m_xWwFib->m_fcCmds);
4703  if (!bValidPos)
4704  return;
4705 
4706  uno::Reference < embed::XStorage > xRoot(m_pDocShell->GetStorage());
4707 
4708  if (!xRoot.is())
4709  return;
4710 
4711  try
4712  {
4713  uno::Reference < io::XStream > xStream =
4714  xRoot->openStreamElement( SL::aMSMacroCmds, embed::ElementModes::READWRITE );
4715  std::unique_ptr<SvStream> xOutStream(::utl::UcbStreamHelper::CreateStream(xStream));
4716 
4717  sal_uInt32 lcbCmds = std::min<sal_uInt32>(m_xWwFib->m_lcbCmds, m_pTableStream->remainingSize());
4718  std::unique_ptr<sal_uInt8[]> xBuffer(new sal_uInt8[lcbCmds]);
4719  m_xWwFib->m_lcbCmds = m_pTableStream->ReadBytes(xBuffer.get(), lcbCmds);
4720  xOutStream->WriteBytes(xBuffer.get(), m_xWwFib->m_lcbCmds);
4721  }
4722  catch (...)
4723  {
4724  }
4725 }
4726 
4728 {
4729  std::vector<OUString> aDocVarStrings;
4730  std::vector<ww::bytes> aDocVarStringIds;
4731  std::vector<OUString> aDocValueStrings;
4732  WW8ReadSTTBF(!m_bVer67, *m_pTableStream, m_xWwFib->m_fcStwUser,
4733  m_xWwFib->m_lcbStwUser, m_bVer67 ? 2 : 0, m_eStructCharSet,
4734  aDocVarStrings, &aDocVarStringIds, &aDocValueStrings);
4735  if (m_bVer67) return;
4736 
4737  uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
4738  m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
4739  uno::Reference<document::XDocumentProperties> xDocProps(
4740  xDPS->getDocumentProperties());
4741  OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
4742  uno::Reference<beans::XPropertyContainer> xUserDefinedProps =
4743  xDocProps->getUserDefinedProperties();
4744  OSL_ENSURE(xUserDefinedProps.is(), "UserDefinedProperties is null");
4745 
4746  for(size_t i=0; i<aDocVarStrings.size(); i++)
4747  {
4748  const OUString &rName = aDocVarStrings[i];
4749  uno::Any aValue;
4750  aValue <<= rName;
4751  try {
4752  xUserDefinedProps->addProperty( rName,
4753  beans::PropertyAttribute::REMOVABLE,
4754  aValue );
4755  } catch (const uno::Exception &) {
4756  // ignore
4757  }
4758  }
4759 }
4760 
4765 {
4766  if( !m_pStg )
4767  return;
4768 
4769  uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
4770  m_pDocShell->GetModel(), uno::UNO_QUERY_THROW);
4771  uno::Reference<document::XDocumentProperties> xDocProps(
4772  xDPS->getDocumentProperties());
4773  OSL_ENSURE(xDocProps.is(), "DocumentProperties is null");
4774 
4775  if (!xDocProps.is())
4776  return;
4777 
4778  if ( m_xWwFib->m_fDot )
4779  {
4780  SfxMedium* pMedium = m_pDocShell->GetMedium();
4781  if ( pMedium )
4782  {
4783  const OUString& aName = pMedium->GetName();
4784  INetURLObject aURL( aName );
4785  OUString sTemplateURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri);
4786  if ( !sTemplateURL.isEmpty() )
4787  xDocProps->setTemplateURL( sTemplateURL );
4788  }
4789  }
4790  else if (m_xWwFib->m_lcbSttbfAssoc) // not a template, and has a SttbfAssoc
4791  {
4792  auto nCur = m_pTableStream->Tell();
4793  Sttb aSttb;
4794  // point at tgc record
4795  if (!checkSeek(*m_pTableStream, m_xWwFib->m_fcSttbfAssoc) || !aSttb.Read(*m_pTableStream))
4796  SAL_WARN("sw.ww8", "** Read of SttbAssoc data failed!!!! ");
4797  m_pTableStream->Seek( nCur ); // return to previous position, is that necessary?
4798  OUString sPath = aSttb.getStringAtIndex( 0x1 );
4799  OUString aURL;
4800  // attempt to convert to url (won't work for obvious reasons on linux)
4801  if ( !sPath.isEmpty() )
4802  osl::FileBase::getFileURLFromSystemPath( sPath, aURL );
4803  if (aURL.isEmpty())
4804  xDocProps->setTemplateURL( aURL );
4805  else
4806  xDocProps->setTemplateURL( sPath );
4807 
4808  }
4809  sfx2::LoadOlePropertySet(xDocProps, m_pStg);
4810 }
4811 
4812 static void lcl_createTemplateToProjectEntry( const uno::Reference< container::XNameContainer >& xPrjNameCache, const OUString& sTemplatePathOrURL, const OUString& sVBAProjName )
4813 {
4814  if ( !xPrjNameCache.is() )
4815  return;
4816 
4817  INetURLObject aObj;
4818  aObj.SetURL( sTemplatePathOrURL );
4819  bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
4820  OUString aURL;
4821  if ( bIsURL )
4822  aURL = sTemplatePathOrURL;
4823  else
4824  {
4825  osl::FileBase::getFileURLFromSystemPath( sTemplatePathOrURL, aURL );
4826  aObj.SetURL( aURL );
4827  }
4828  try
4829  {
4830  OUString templateNameWithExt = aObj.GetLastName();
4831  sal_Int32 nIndex = templateNameWithExt.lastIndexOf( '.' );
4832  if ( nIndex != -1 )
4833  {
4834  OUString templateName = templateNameWithExt.copy( 0, nIndex );
4835  xPrjNameCache->insertByName( templateName, uno::makeAny( sVBAProjName ) );
4836  }
4837  }
4838  catch( const uno::Exception& )
4839  {
4840  }
4841 }
4842 
4843 namespace {
4844 
4845 class WW8Customizations
4846 {
4847  SvStream* mpTableStream;
4848  WW8Fib mWw8Fib;
4849 public:
4850  WW8Customizations( SvStream*, WW8Fib const & );
4851  void Import( SwDocShell* pShell );
4852 };
4853 
4854 }
4855 
4856 WW8Customizations::WW8Customizations( SvStream* pTableStream, WW8Fib const & rFib ) : mpTableStream(pTableStream), mWw8Fib( rFib )
4857 {
4858 }
4859 
4860 void WW8Customizations::Import( SwDocShell* pShell )
4861 {
4862  if ( mWw8Fib.m_lcbCmds == 0 || !IsEightPlus(mWw8Fib.GetFIBVersion()) )
4863  return;
4864  try
4865  {
4866  Tcg aTCG;
4867  tools::Long nCur = mpTableStream->Tell();
4868  if (!checkSeek(*mpTableStream, mWw8Fib.m_fcCmds)) // point at tgc record
4869  {
4870  SAL_WARN("sw.ww8", "** Seek to Customization data failed!!!! ");
4871  return;
4872  }
4873  bool bReadResult = aTCG.Read( *mpTableStream );
4874  mpTableStream->Seek( nCur ); // return to previous position, is that necessary?
4875  if ( !bReadResult )
4876  {
4877  SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! ");
4878  return;
4879  }
4880  aTCG.ImportCustomToolBar( *pShell );
4881  }
4882  catch(...)
4883  {
4884  SAL_WARN("sw.ww8", "** Read of Customization data failed!!!! epically");
4885  }
4886 }
4887 
4888 void SwWW8ImplReader::ReadGlobalTemplateSettings( std::u16string_view sCreatedFrom, const uno::Reference< container::XNameContainer >& xPrjNameCache )
4889 {
4890  if (m_bFuzzing)
4891  return;
4892 
4893  SvtPathOptions aPathOpt;
4894  const OUString& aAddinPath = aPathOpt.GetAddinPath();
4895  uno::Sequence< OUString > sGlobalTemplates;
4896 
4897  // first get the autoload addins in the directory STARTUP
4898  uno::Reference<ucb::XSimpleFileAccess3> xSFA(ucb::SimpleFileAccess::create(::comphelper::getProcessComponentContext()));
4899 
4900  if( xSFA->isFolder( aAddinPath ) )
4901  sGlobalTemplates = xSFA->getFolderContents( aAddinPath, false );
4902 
4903  for ( const auto& rGlobalTemplate : std::as_const(sGlobalTemplates) )
4904  {
4905  INetURLObject aObj;
4906  aObj.SetURL( rGlobalTemplate );
4907  bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
4908  OUString aURL;
4909  if ( bIsURL )
4910  aURL = rGlobalTemplate;
4911  else
4912  osl::FileBase::getFileURLFromSystemPath( rGlobalTemplate, aURL );
4913  if ( !aURL.endsWithIgnoreAsciiCase( ".dot" ) || ( !sCreatedFrom.empty() && sCreatedFrom == aURL ) )
4914  continue; // don't try and read the same document as ourselves
4915 
4916  tools::SvRef<SotStorage> rRoot = new SotStorage( aURL, StreamMode::STD_READWRITE );
4917 
4918  BasicProjImportHelper aBasicImporter( *m_pDocShell );
4919  // Import vba via oox filter
4920  aBasicImporter.import( m_pDocShell->GetMedium()->GetInputStream() );
4921  lcl_createTemplateToProjectEntry( xPrjNameCache, aURL, aBasicImporter.getProjectName() );
4922  // Read toolbars & menus
4923  tools::SvRef<SotStorageStream> refMainStream = rRoot->OpenSotStream( "WordDocument");
4924  refMainStream->SetEndian(SvStreamEndian::LITTLE);
4925  WW8Fib aWwFib( *refMainStream, 8 );
4926  tools::SvRef<SotStorageStream> xTableStream =
4927  rRoot->OpenSotStream(aWwFib.m_fWhichTableStm ? OUString(SL::a1Table) : OUString(SL::a0Table), StreamMode::STD_READ);
4928 
4929  if (xTableStream.is() && ERRCODE_NONE == xTableStream->GetError())
4930  {
4931  xTableStream->SetEndian(SvStreamEndian::LITTLE);
4932  WW8Customizations aGblCustomisations( xTableStream.get(), aWwFib );
4933  aGblCustomisations.Import( m_pDocShell );
4934  }
4935  }
4936 }
4937 
4939 {
4941  if (m_bNewDoc && m_pStg && !pGloss)
4942  {
4943  // Initialize RDF metadata, to be able to add statements during the import.
4944  try
4945  {
4946  uno::Reference<frame::XModel> const xModel(m_rDoc.GetDocShell()->GetBaseModel());
4947  uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, uno::UNO_QUERY_THROW);
4948  uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext());
4949  uno::Reference<embed::XStorage> xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
4950  const uno::Reference<rdf::XURI> xBaseURI(sfx2::createBaseURI(xComponentContext, xModel, m_sBaseURL));
4951  uno::Reference<task::XInteractionHandler> xHandler;
4952  xDocumentMetadataAccess->loadMetadataFromStorage(xStorage, xBaseURI, xHandler);
4953  }
4954  catch (const uno::Exception&)
4955  {
4956  TOOLS_WARN_EXCEPTION("sw.ww8", "failed to initialize RDF metadata");
4957  }
4958  ReadDocInfo();
4959  }
4960 
4961  auto pFibData = std::make_shared<::ww8::WW8FibData>();
4962 
4963  if (m_xWwFib->m_fReadOnlyRecommended)
4964  pFibData->setReadOnlyRecommended(true);
4965  else
4966  pFibData->setReadOnlyRecommended(false);
4967 
4968  if (m_xWwFib->m_fWriteReservation)
4969  pFibData->setWriteReservation(true);
4970  else
4971  pFibData->setWriteReservation(false);
4972 
4974 
4975  ::sw::tExternalDataPointer pSttbfAsoc
4976  = std::make_shared<::ww8::WW8Sttb<ww8::WW8Struct>>(*m_pTableStream, m_xWwFib->m_fcSttbfAssoc, m_xWwFib->m_lcbSttbfAssoc);
4977 
4979 
4980  if (m_xWwFib->m_fWriteReservation || m_xWwFib->m_fReadOnlyRecommended)
4981  {
4982  SwDocShell * pDocShell = m_rDoc.GetDocShell();
4983  if (pDocShell)
4984  pDocShell->SetReadOnlyUI();
4985  }
4986 
4987  m_pPaM = mpCursor.get();
4988 
4990 
4992 
4993  /*
4994  RefFieldStck: Keeps track of bookmarks which may be inserted as
4995  variables instead.
4996  */
4999 
5001 
5002  size_t nPageDescOffset = m_rDoc.GetPageDescCnt();
5003 
5004  SwNodeIndex aSttNdIdx( m_rDoc.GetNodes() );
5005 
5007 
5008  m_xSprmParser.reset(new wwSprmParser(*m_xWwFib));
5009 
5010  // Set handy helper variables
5011  m_bVer6 = (6 == m_xWwFib->m_nVersion);
5012  m_bVer7 = (7 == m_xWwFib->m_nVersion);
5013  m_bVer67 = m_bVer6 || m_bVer7;
5014  m_bVer8 = (8 == m_xWwFib->m_nVersion);
5015 
5017  m_eStructCharSet = WW8Fib::GetFIBCharset(m_xWwFib->m_chseTables, m_xWwFib->m_lid);
5018 
5019  m_bWWBugNormal = m_xWwFib->m_nProduct == 0xc03d;
5020 
5021  if (!m_bNewDoc)
5022  aSttNdIdx = m_pPaM->GetPoint()->nNode;
5023 
5024  m_xProgress.reset(new ImportProgress(m_pDocShell, 0, 100));
5025 
5026  // read Font Table
5027  m_xFonts.reset(new WW8Fonts(*m_pTableStream, *m_xWwFib));
5028 
5029  // Document Properties
5030  m_xWDop.reset(new WW8Dop(*m_pTableStream, m_xWwFib->m_nFib, m_xWwFib->m_fcDop,
5031  m_xWwFib->m_lcbDop));
5032 
5033  if (m_bNewDoc)
5034  ImportDop();
5035