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