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