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