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