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