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