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